Merge branch 'for-2.6.23' of master.kernel.org:/pub/scm/linux/kernel/git/arnd/cell-2.6

* 'for-2.6.23' of master.kernel.org:/pub/scm/linux/kernel/git/arnd/cell-2.6: (37 commits)
[CELL] spufs: rework list management and associated locking
[CELL] oprofile: add support to OProfile for profiling CELL BE SPUs
[CELL] oprofile: enable SPU switch notification to detect currently active SPU tasks
[CELL] spu_base: locking cleanup
[CELL] cell: indexing of SPUs based on firmware vicinity properties
[CELL] spufs: integration of SPE affinity with the scheduller
[CELL] cell: add placement computation for scheduling of affinity contexts
[CELL] spufs: extension of spu_create to support affinity definition
[CELL] cell: add hardcoded spu vicinity information for QS20
[CELL] cell: add vicinity information on spus
[CELL] cell: add per BE structure with info about its SPUs
[CELL] spufs: use find_first_bit() instead of sched_find_first_bit()
[CELL] spufs: remove unused file argument from spufs_run_spu()
[CELL] spufs: change decrementer restore timing
[CELL] spufs: dont halt decrementer at restore step 47
[CELL] spufs: limit saving MFC_CNTL bits
[CELL] spufs: fix read and write for decr_status file
[CELL] spufs: fix decr_status meanings
[CELL] spufs: remove needless context save/restore code
[CELL] spufs: fix array size of channel index
...

+4330 -941
+2 -1
arch/powerpc/configs/cell_defconfig
··· 1455 # Instrumentation Support 1456 # 1457 CONFIG_PROFILING=y 1458 - CONFIG_OPROFILE=y 1459 # CONFIG_KPROBES is not set 1460 1461 #
··· 1455 # Instrumentation Support 1456 # 1457 CONFIG_PROFILING=y 1458 + CONFIG_OPROFILE=m 1459 + CONFIG_OPROFILE_CELL=y 1460 # CONFIG_KPROBES is not set 1461 1462 #
+67
arch/powerpc/kernel/crash.c
··· 219 cpus_in_sr = CPU_MASK_NONE; 220 } 221 #endif 222 223 void default_machine_crash_shutdown(struct pt_regs *regs) 224 { ··· 320 crash_save_cpu(regs, crashing_cpu); 321 crash_kexec_prepare_cpus(crashing_cpu); 322 cpu_set(crashing_cpu, cpus_in_crash); 323 if (ppc_md.kexec_cpu_down) 324 ppc_md.kexec_cpu_down(1, 0); 325 }
··· 219 cpus_in_sr = CPU_MASK_NONE; 220 } 221 #endif 222 + #ifdef CONFIG_SPU_BASE 223 + 224 + #include <asm/spu.h> 225 + #include <asm/spu_priv1.h> 226 + 227 + struct crash_spu_info { 228 + struct spu *spu; 229 + u32 saved_spu_runcntl_RW; 230 + u32 saved_spu_status_R; 231 + u32 saved_spu_npc_RW; 232 + u64 saved_mfc_sr1_RW; 233 + u64 saved_mfc_dar; 234 + u64 saved_mfc_dsisr; 235 + }; 236 + 237 + #define CRASH_NUM_SPUS 16 /* Enough for current hardware */ 238 + static struct crash_spu_info crash_spu_info[CRASH_NUM_SPUS]; 239 + 240 + static void crash_kexec_stop_spus(void) 241 + { 242 + struct spu *spu; 243 + int i; 244 + u64 tmp; 245 + 246 + for (i = 0; i < CRASH_NUM_SPUS; i++) { 247 + if (!crash_spu_info[i].spu) 248 + continue; 249 + 250 + spu = crash_spu_info[i].spu; 251 + 252 + crash_spu_info[i].saved_spu_runcntl_RW = 253 + in_be32(&spu->problem->spu_runcntl_RW); 254 + crash_spu_info[i].saved_spu_status_R = 255 + in_be32(&spu->problem->spu_status_R); 256 + crash_spu_info[i].saved_spu_npc_RW = 257 + in_be32(&spu->problem->spu_npc_RW); 258 + 259 + crash_spu_info[i].saved_mfc_dar = spu_mfc_dar_get(spu); 260 + crash_spu_info[i].saved_mfc_dsisr = spu_mfc_dsisr_get(spu); 261 + tmp = spu_mfc_sr1_get(spu); 262 + crash_spu_info[i].saved_mfc_sr1_RW = tmp; 263 + 264 + tmp &= ~MFC_STATE1_MASTER_RUN_CONTROL_MASK; 265 + spu_mfc_sr1_set(spu, tmp); 266 + 267 + __delay(200); 268 + } 269 + } 270 + 271 + void crash_register_spus(struct list_head *list) 272 + { 273 + struct spu *spu; 274 + 275 + list_for_each_entry(spu, list, full_list) { 276 + if (WARN_ON(spu->number >= CRASH_NUM_SPUS)) 277 + continue; 278 + 279 + crash_spu_info[spu->number].spu = spu; 280 + } 281 + } 282 + 283 + #else 284 + static inline void crash_kexec_stop_spus(void) 285 + { 286 + } 287 + #endif /* CONFIG_SPU_BASE */ 288 289 void default_machine_crash_shutdown(struct pt_regs *regs) 290 { ··· 254 crash_save_cpu(regs, crashing_cpu); 255 crash_kexec_prepare_cpus(crashing_cpu); 256 cpu_set(crashing_cpu, cpus_in_crash); 257 + crash_kexec_stop_spus(); 258 if (ppc_md.kexec_cpu_down) 259 ppc_md.kexec_cpu_down(1, 0); 260 }
+1
arch/powerpc/kernel/time.c
··· 122 static long timezone_offset; 123 124 unsigned long ppc_proc_freq; 125 unsigned long ppc_tb_freq; 126 127 static u64 tb_last_jiffy __cacheline_aligned_in_smp;
··· 122 static long timezone_offset; 123 124 unsigned long ppc_proc_freq; 125 + EXPORT_SYMBOL(ppc_proc_freq); 126 unsigned long ppc_tb_freq; 127 128 static u64 tb_last_jiffy __cacheline_aligned_in_smp;
+7
arch/powerpc/oprofile/Kconfig
··· 15 16 If unsure, say N. 17
··· 15 16 If unsure, say N. 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 timer_int.o ) 12 13 oprofile-y := $(DRIVER_OBJS) common.o backtrace.o 14 - oprofile-$(CONFIG_PPC_CELL_NATIVE) += op_model_cell.o 15 oprofile-$(CONFIG_PPC64) += op_model_rs64.o op_model_power4.o op_model_pa6t.o 16 oprofile-$(CONFIG_FSL_BOOKE) += op_model_fsl_booke.o 17 oprofile-$(CONFIG_6xx) += op_model_7450.o
··· 11 timer_int.o ) 12 13 oprofile-y := $(DRIVER_OBJS) common.o backtrace.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 17 oprofile-$(CONFIG_PPC64) += op_model_rs64.o op_model_power4.o op_model_pa6t.o 18 oprofile-$(CONFIG_FSL_BOOKE) += op_model_fsl_booke.o 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 static struct op_counter_config ctr[OP_MAX_COUNTER]; 30 static struct op_system_config sys; 31 32 static void op_handle_interrupt(struct pt_regs *regs) 33 { 34 model->handle_interrupt(regs, ctr); ··· 38 39 static void op_powerpc_cpu_setup(void *dummy) 40 { 41 - model->cpu_setup(ctr); 42 } 43 44 static int op_powerpc_setup(void) 45 { 46 int err; 47 48 /* Grab the hardware */ 49 err = reserve_pmc_hardware(op_handle_interrupt); ··· 58 return err; 59 60 /* Pre-compute the values to stuff in the hardware registers. */ 61 - model->reg_setup(ctr, &sys, model->num_counters); 62 63 - /* Configure the registers on all cpus. */ 64 on_each_cpu(op_powerpc_cpu_setup, NULL, 0, 1); 65 66 - return 0; 67 } 68 69 static void op_powerpc_shutdown(void) ··· 82 83 static void op_powerpc_cpu_start(void *dummy) 84 { 85 - model->start(ctr); 86 } 87 88 static int op_powerpc_start(void) 89 { 90 if (model->global_start) 91 - model->global_start(ctr); 92 - if (model->start) 93 on_each_cpu(op_powerpc_cpu_start, NULL, 0, 1); 94 - return 0; 95 } 96 97 static inline void op_powerpc_cpu_stop(void *dummy) ··· 178 179 switch (cur_cpu_spec->oprofile_type) { 180 #ifdef CONFIG_PPC64 181 - #ifdef CONFIG_PPC_CELL_NATIVE 182 case PPC_OPROFILE_CELL: 183 if (firmware_has_feature(FW_FEATURE_LPAR)) 184 return -ENODEV; 185 model = &op_model_cell; 186 break; 187 #endif 188 case PPC_OPROFILE_RS64:
··· 29 static struct op_counter_config ctr[OP_MAX_COUNTER]; 30 static struct op_system_config sys; 31 32 + static int op_per_cpu_rc; 33 + 34 static void op_handle_interrupt(struct pt_regs *regs) 35 { 36 model->handle_interrupt(regs, ctr); ··· 36 37 static void op_powerpc_cpu_setup(void *dummy) 38 { 39 + int ret; 40 + 41 + ret = model->cpu_setup(ctr); 42 + 43 + if (ret != 0) 44 + op_per_cpu_rc = ret; 45 } 46 47 static int op_powerpc_setup(void) 48 { 49 int err; 50 + 51 + op_per_cpu_rc = 0; 52 53 /* Grab the hardware */ 54 err = reserve_pmc_hardware(op_handle_interrupt); ··· 49 return err; 50 51 /* Pre-compute the values to stuff in the hardware registers. */ 52 + op_per_cpu_rc = model->reg_setup(ctr, &sys, model->num_counters); 53 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 */ 59 on_each_cpu(op_powerpc_cpu_setup, NULL, 0, 1); 60 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 } 68 69 static void op_powerpc_shutdown(void) ··· 64 65 static void op_powerpc_cpu_start(void *dummy) 66 { 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; 76 } 77 78 static int op_powerpc_start(void) 79 { 80 + op_per_cpu_rc = 0; 81 + 82 if (model->global_start) 83 + return model->global_start(ctr); 84 + if (model->start) { 85 on_each_cpu(op_powerpc_cpu_start, NULL, 0, 1); 86 + return op_per_cpu_rc; 87 + } 88 + return -EIO; /* No start function is defined for this 89 + power architecture */ 90 } 91 92 static inline void op_powerpc_cpu_stop(void *dummy) ··· 147 148 switch (cur_cpu_spec->oprofile_type) { 149 #ifdef CONFIG_PPC64 150 + #ifdef CONFIG_OPROFILE_CELL 151 case PPC_OPROFILE_CELL: 152 if (firmware_has_feature(FW_FEATURE_LPAR)) 153 return -ENODEV; 154 model = &op_model_cell; 155 + ops->sync_start = model->sync_start; 156 + ops->sync_stop = model->sync_stop; 157 break; 158 #endif 159 case PPC_OPROFILE_RS64:
+10 -4
arch/powerpc/oprofile/op_model_7450.c
··· 81 82 /* Configures the counters on this CPU based on the global 83 * settings */ 84 - static void fsl7450_cpu_setup(struct op_counter_config *ctr) 85 { 86 /* freeze all counters */ 87 pmc_stop_ctrs(); ··· 89 mtspr(SPRN_MMCR0, mmcr0_val); 90 mtspr(SPRN_MMCR1, mmcr1_val); 91 mtspr(SPRN_MMCR2, mmcr2_val); 92 } 93 94 #define NUM_CTRS 6 95 96 /* Configures the global settings for the countes on all CPUs. */ 97 - static void fsl7450_reg_setup(struct op_counter_config *ctr, 98 struct op_system_config *sys, 99 int num_ctrs) 100 { ··· 128 | mmcr1_event6(ctr[5].event); 129 130 mmcr2_val = 0; 131 } 132 133 /* Sets the counters on this CPU to the chosen values, and starts them */ 134 - static void fsl7450_start(struct op_counter_config *ctr) 135 { 136 int i; 137 ··· 152 pmc_start_ctrs(); 153 154 oprofile_running = 1; 155 } 156 157 /* Stop the counters on this CPU */ ··· 199 /* The freeze bit was set by the interrupt. */ 200 /* Clear the freeze bit, and reenable the interrupt. 201 * The counters won't actually start until the rfi clears 202 - * the PMM bit */ 203 pmc_start_ctrs(); 204 } 205
··· 81 82 /* Configures the counters on this CPU based on the global 83 * settings */ 84 + static int fsl7450_cpu_setup(struct op_counter_config *ctr) 85 { 86 /* freeze all counters */ 87 pmc_stop_ctrs(); ··· 89 mtspr(SPRN_MMCR0, mmcr0_val); 90 mtspr(SPRN_MMCR1, mmcr1_val); 91 mtspr(SPRN_MMCR2, mmcr2_val); 92 + 93 + return 0; 94 } 95 96 #define NUM_CTRS 6 97 98 /* Configures the global settings for the countes on all CPUs. */ 99 + static int fsl7450_reg_setup(struct op_counter_config *ctr, 100 struct op_system_config *sys, 101 int num_ctrs) 102 { ··· 126 | mmcr1_event6(ctr[5].event); 127 128 mmcr2_val = 0; 129 + 130 + return 0; 131 } 132 133 /* Sets the counters on this CPU to the chosen values, and starts them */ 134 + static int fsl7450_start(struct op_counter_config *ctr) 135 { 136 int i; 137 ··· 148 pmc_start_ctrs(); 149 150 oprofile_running = 1; 151 + 152 + return 0; 153 } 154 155 /* Stop the counters on this CPU */ ··· 193 /* The freeze bit was set by the interrupt. */ 194 /* Clear the freeze bit, and reenable the interrupt. 195 * The counters won't actually start until the rfi clears 196 + * the PM/M bit */ 197 pmc_start_ctrs(); 198 } 199
+528 -81
arch/powerpc/oprofile/op_model_cell.c
··· 5 * 6 * Author: David Erb (djerb@us.ibm.com) 7 * Modifications: 8 - * Carl Love <carll@us.ibm.com> 9 - * Maynard Johnson <maynardj@us.ibm.com> 10 * 11 * This program is free software; you can redistribute it and/or 12 * modify it under the terms of the GNU General Public License ··· 38 39 #include "../platforms/cell/interrupt.h" 40 #include "../platforms/cell/cbe_regs.h" 41 42 #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 */ 47 48 #define NUM_THREADS 2 /* number of physical threads in 49 * physical processor ··· 64 #define NUM_TRACE_BUS_WORDS 4 65 #define NUM_INPUT_BUS_WORDS 2 66 67 68 struct pmc_cntrl_data { 69 unsigned long vcntr; ··· 76 /* 77 * ibm,cbe-perftools rtas parameters 78 */ 79 - 80 struct pm_signal { 81 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 */ 84 u8 bus_word; /* Enable/Disable on this Trace/Trigger/Event 85 * Bus Word(s) (bitmask) 86 */ ··· 125 126 static struct pmc_cntrl_data pmc_cntrl[NUM_THREADS][NR_PHYS_CTRS]; 127 128 - /* Interpetation of hdw_thread: 129 * 0 - even virtual cpus 0, 2, 4,... 130 * 1 - odd virtual cpus 1, 3, 5, ... 131 */ 132 static u32 hdw_thread; 133 134 static u32 virt_cntr_inter_mask; 135 static struct timer_list timer_virt_cntr; 136 137 - /* pm_signal needs to be global since it is initialized in 138 * cell_reg_setup at the time when the necessary information 139 * is available. 140 */ 141 static struct pm_signal pm_signal[NR_PHYS_CTRS]; 142 - static int pm_rtas_token; 143 144 static u32 reset_value[NR_PHYS_CTRS]; 145 static int num_counters; ··· 181 { 182 u64 paddr = __pa(address); 183 184 - return rtas_call(pm_rtas_token, 5, 1, NULL, subfunc, passthru, 185 - paddr >> 32, paddr & 0xffffffff, length); 186 } 187 188 static void pm_rtas_reset_signals(u32 node) ··· 190 int ret; 191 struct pm_signal pm_signal_local; 192 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. 199 */ 200 201 /* fw expects physical cpu #. */ ··· 210 &pm_signal_local, 211 sizeof(struct pm_signal)); 212 213 - if (ret) 214 printk(KERN_WARNING "%s: rtas returned: %d\n", 215 __FUNCTION__, ret); 216 } 217 218 - static void pm_rtas_activate_signals(u32 node, u32 count) 219 { 220 int ret; 221 int i, j; 222 struct pm_signal pm_signal_local[NR_PHYS_CTRS]; 223 224 - /* There is no debug setup required for the cycles event. 225 * Note that only events in the same group can be used. 226 * Otherwise, there will be conflicts in correctly routing 227 * the signals on the debug bus. It is the responsiblity ··· 254 pm_signal_local, 255 i * sizeof(struct pm_signal)); 256 257 - if (ret) 258 printk(KERN_WARNING "%s: rtas returned: %d\n", 259 __FUNCTION__, ret); 260 } 261 } 262 263 /* ··· 305 pm_regs.pm07_cntrl[ctr] |= PM07_CTR_POLARITY(polarity); 306 pm_regs.pm07_cntrl[ctr] |= PM07_CTR_INPUT_CONTROL(input_control); 307 308 - /* Some of the islands signal selection is based on 64 bit words. 309 * The debug bus words are 32 bits, the input words to the performance 310 * counters are defined as 32 bits. Need to convert the 64 bit island 311 * specification to the appropriate 32 input bit and bus word for the 312 - * performance counter event selection. See the CELL Performance 313 * monitoring signals manual and the Perf cntr hardware descriptions 314 * for the details. 315 */ ··· 344 input_bus[j] = i; 345 pm_regs.group_control |= 346 (i << (31 - i)); 347 break; 348 } 349 } ··· 356 357 static void write_pm_cntrl(int cpu) 358 { 359 - /* Oprofile will use 32 bit counters, set bits 7:10 to 0 360 * pmregs.pm_cntrl is a global 361 */ 362 ··· 374 if (pm_regs.pm_cntrl.freeze == 1) 375 val |= CBE_PM_FREEZE_ALL_CTRS; 376 377 - /* Routine set_count_mode must be called previously to set 378 * the count mode based on the user selection of user and kernel. 379 */ 380 val |= CBE_PM_COUNT_MODE_SET(pm_regs.pm_cntrl.count_mode); ··· 385 static inline void 386 set_count_mode(u32 kernel, u32 user) 387 { 388 - /* The user must specify user and kernel if they want them. If 389 * neither is specified, OProfile will count in hypervisor mode. 390 * pm_regs.pm_cntrl is a global 391 */ ··· 414 415 /* 416 * Oprofile is expected to collect data on all CPUs simultaneously. 417 - * However, there is one set of performance counters per node. There are 418 * two hardware threads or virtual CPUs on each node. Hence, OProfile must 419 * multiplex in time the performance counter collection on the two virtual 420 * CPUs. The multiplexing of the performance counters is done by this ··· 427 * pair of per-cpu arrays is used for storing the previous and next 428 * pmc values for a given node. 429 * NOTE: We use the per-cpu variable to improve cache performance. 430 */ 431 static void cell_virtual_cntr(unsigned long data) 432 { 433 - /* This routine will alternate loading the virtual counters for 434 - * virtual CPUs 435 - */ 436 int i, prev_hdw_thread, next_hdw_thread; 437 u32 cpu; 438 unsigned long flags; 439 440 - /* Make sure that the interrupt_hander and 441 - * the virt counter are not both playing with 442 - * the counters on the same node. 443 */ 444 445 spin_lock_irqsave(&virt_cntr_lock, flags); ··· 450 hdw_thread = 1 ^ hdw_thread; 451 next_hdw_thread = hdw_thread; 452 453 - for (i = 0; i < num_counters; i++) 454 - /* There are some per thread events. Must do the 455 * set event, for the thread that is being started 456 */ 457 set_pm_event(i, 458 pmc_cntrl[next_hdw_thread][i].evnts, 459 pmc_cntrl[next_hdw_thread][i].masks); 460 461 - /* The following is done only once per each node, but 462 * we need cpu #, not node #, to pass to the cbe_xxx functions. 463 */ 464 for_each_online_cpu(cpu) { 465 if (cbe_get_hw_thread_id(cpu)) 466 continue; 467 468 - /* stop counters, save counter values, restore counts 469 * for previous thread 470 */ 471 cbe_disable_pm(cpu); ··· 481 == 0xFFFFFFFF) 482 /* If the cntr value is 0xffffffff, we must 483 * reset that to 0xfffffff0 when the current 484 - * thread is restarted. This will generate a 485 * new interrupt and make sure that we never 486 * restore the counters to the max value. If 487 * the counters were restored to the max value, ··· 497 next_hdw_thread)[i]); 498 } 499 500 - /* Switch to the other thread. Change the interrupt 501 * and control regs to be scheduled on the CPU 502 * corresponding to the thread to execute. 503 */ 504 for (i = 0; i < num_counters; i++) { 505 if (pmc_cntrl[next_hdw_thread][i].enabled) { 506 - /* There are some per thread events. 507 * Must do the set event, enable_cntr 508 * for each cpu. 509 */ ··· 537 } 538 539 /* 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) 543 { 544 int i, j, cpu; 545 546 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", 549 __FUNCTION__); 550 - goto out; 551 } 552 553 num_counters = num_ctrs; ··· 600 per_cpu(pmc_values, j)[i] = 0; 601 } 602 603 - /* Setup the thread 1 events, map the thread 0 event to the 604 * equivalent thread 1 event. 605 */ 606 for (i = 0; i < num_ctrs; ++i) { ··· 625 for (i = 0; i < NUM_INPUT_BUS_WORDS; i++) 626 input_bus[i] = 0xff; 627 628 - /* Our counters count up, and "count" refers to 629 * how much before the next interrupt, and we interrupt 630 - * on overflow. So we calculate the starting value 631 * which will give us "count" until overflow. 632 * Then we set the events on the enabled counters. 633 */ ··· 651 for (i = 0; i < num_counters; ++i) { 652 per_cpu(pmc_values, cpu)[i] = reset_value[i]; 653 } 654 - out: 655 - ; 656 } 657 658 /* This function is called once for each cpu */ 659 - static void cell_cpu_setup(struct op_counter_config *cntr) 660 { 661 u32 cpu = smp_processor_id(); 662 u32 num_enabled = 0; 663 int i; 664 665 /* There is one performance monitor per processor chip (i.e. node), 666 * so we only need to perform this function once per node. 667 */ 668 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 - } 676 677 /* Stop all counters */ 678 cbe_disable_pm(cpu); ··· 690 } 691 } 692 693 - pm_rtas_activate_signals(cbe_cpu_to_node(cpu), num_enabled); 694 - out: 695 - ; 696 } 697 698 - static void cell_global_start(struct op_counter_config *ctr) 699 { 700 - u32 cpu; 701 u32 interrupt_mask = 0; 702 - u32 i; 703 704 /* This routine gets called once for the system. 705 * There is one performance monitor per node, so we ··· 1002 oprofile_running = 1; 1003 smp_wmb(); 1004 1005 - /* NOTE: start_virt_cntrs will result in cell_virtual_cntr() being 1006 - * executed which manipulates the PMU. We start the "virtual counter" 1007 * here so that we do not need to synchronize access to the PMU in 1008 * the above for-loop. 1009 */ 1010 start_virt_cntrs(); 1011 } 1012 1013 - static void cell_global_stop(void) 1014 { 1015 int cpu; 1016 1017 - /* This routine will be called once for the system. 1018 * There is one performance monitor per node, so we 1019 * only need to perform this function once per node. 1020 */ ··· 1098 } 1099 } 1100 1101 - static void 1102 - cell_handle_interrupt(struct pt_regs *regs, struct op_counter_config *ctr) 1103 { 1104 u32 cpu; 1105 u64 pc; ··· 1118 1119 cpu = smp_processor_id(); 1120 1121 - /* Need to make sure the interrupt handler and the virt counter 1122 * routine are not running at the same time. See the 1123 * cell_virtual_cntr() routine for additional comments. 1124 */ 1125 spin_lock_irqsave(&virt_cntr_lock, flags); 1126 1127 - /* Need to disable and reenable the performance counters 1128 * to get the desired behavior from the hardware. This 1129 * is hardware specific. 1130 */ ··· 1135 1136 interrupt_mask = cbe_get_and_clear_pm_interrupts(cpu); 1137 1138 - /* If the interrupt mask has been cleared, then the virt cntr 1139 * has cleared the interrupt. When the thread that generated 1140 * the interrupt is restored, the data count will be restored to 1141 * 0xffffff0 to cause the interrupt to be regenerated. ··· 1154 } 1155 } 1156 1157 - /* The counters were frozen by the interrupt. 1158 * Reenable the interrupt and restart the counters. 1159 * If there was a race between the interrupt handler and 1160 - * the virtual counter routine. The virutal counter 1161 * routine may have cleared the interrupts. Hence must 1162 * use the virt_cntr_inter_mask to re-enable the interrupts. 1163 */ 1164 cbe_enable_pm_interrupts(cpu, hdw_thread, 1165 virt_cntr_inter_mask); 1166 1167 - /* The writes to the various performance counters only writes 1168 - * to a latch. The new values (interrupt setting bits, reset 1169 * counter value etc.) are not copied to the actual registers 1170 * until the performance monitor is enabled. In order to get 1171 * this to work as desired, the permormance monitor needs to ··· 1179 spin_unlock_irqrestore(&virt_cntr_lock, flags); 1180 } 1181 1182 struct op_powerpc_model op_model_cell = { 1183 .reg_setup = cell_reg_setup, 1184 .cpu_setup = cell_cpu_setup, 1185 .global_start = cell_global_start, 1186 .global_stop = cell_global_stop, 1187 .handle_interrupt = cell_handle_interrupt, 1188 };
··· 5 * 6 * Author: David Erb (djerb@us.ibm.com) 7 * Modifications: 8 + * Carl Love <carll@us.ibm.com> 9 + * Maynard Johnson <maynardj@us.ibm.com> 10 * 11 * This program is free software; you can redistribute it and/or 12 * modify it under the terms of the GNU General Public License ··· 38 39 #include "../platforms/cell/interrupt.h" 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 */ 54 55 #define PPU_CYCLES_EVENT_NUM 1 /* event number for CYCLES */ 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 */ 60 61 #define NUM_THREADS 2 /* number of physical threads in 62 * physical processor ··· 51 #define NUM_TRACE_BUS_WORDS 4 52 #define NUM_INPUT_BUS_WORDS 2 53 54 + #define MAX_SPU_COUNT 0xFFFFFF /* maximum 24 bit LFSR value */ 55 56 struct pmc_cntrl_data { 57 unsigned long vcntr; ··· 62 /* 63 * ibm,cbe-perftools rtas parameters 64 */ 65 struct pm_signal { 66 u16 cpu; /* Processor to modify */ 67 + u16 sub_unit; /* hw subunit this applies to (if applicable)*/ 68 + short int signal_group; /* Signal Group to Enable/Disable */ 69 u8 bus_word; /* Enable/Disable on this Trace/Trigger/Event 70 * Bus Word(s) (bitmask) 71 */ ··· 112 113 static struct pmc_cntrl_data pmc_cntrl[NUM_THREADS][NR_PHYS_CTRS]; 114 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: 132 * 0 - even virtual cpus 0, 2, 4,... 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 137 */ 138 static u32 hdw_thread; 139 140 static u32 virt_cntr_inter_mask; 141 static struct timer_list timer_virt_cntr; 142 143 + /* 144 + * pm_signal needs to be global since it is initialized in 145 * cell_reg_setup at the time when the necessary information 146 * is available. 147 */ 148 static struct pm_signal pm_signal[NR_PHYS_CTRS]; 149 + static int pm_rtas_token; /* token for debug bus setup call */ 150 + static int spu_rtas_token; /* token for SPU cycle profiling */ 151 152 static u32 reset_value[NR_PHYS_CTRS]; 153 static int num_counters; ··· 147 { 148 u64 paddr = __pa(address); 149 150 + return rtas_call(pm_rtas_token, 5, 1, NULL, subfunc, 151 + passthru, paddr >> 32, paddr & 0xffffffff, length); 152 } 153 154 static void pm_rtas_reset_signals(u32 node) ··· 156 int ret; 157 struct pm_signal pm_signal_local; 158 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. 166 */ 167 168 /* fw expects physical cpu #. */ ··· 175 &pm_signal_local, 176 sizeof(struct pm_signal)); 177 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 + */ 184 printk(KERN_WARNING "%s: rtas returned: %d\n", 185 __FUNCTION__, ret); 186 } 187 188 + static int pm_rtas_activate_signals(u32 node, u32 count) 189 { 190 int ret; 191 int i, j; 192 struct pm_signal pm_signal_local[NR_PHYS_CTRS]; 193 194 + /* 195 + * There is no debug setup required for the cycles event. 196 * Note that only events in the same group can be used. 197 * Otherwise, there will be conflicts in correctly routing 198 * the signals on the debug bus. It is the responsiblity ··· 213 pm_signal_local, 214 i * sizeof(struct pm_signal)); 215 216 + if (unlikely(ret)) { 217 printk(KERN_WARNING "%s: rtas returned: %d\n", 218 __FUNCTION__, ret); 219 + return -EIO; 220 + } 221 } 222 + 223 + return 0; 224 } 225 226 /* ··· 260 pm_regs.pm07_cntrl[ctr] |= PM07_CTR_POLARITY(polarity); 261 pm_regs.pm07_cntrl[ctr] |= PM07_CTR_INPUT_CONTROL(input_control); 262 263 + /* 264 + * Some of the islands signal selection is based on 64 bit words. 265 * The debug bus words are 32 bits, the input words to the performance 266 * counters are defined as 32 bits. Need to convert the 64 bit island 267 * specification to the appropriate 32 input bit and bus word for the 268 + * performance counter event selection. See the CELL Performance 269 * monitoring signals manual and the Perf cntr hardware descriptions 270 * for the details. 271 */ ··· 298 input_bus[j] = i; 299 pm_regs.group_control |= 300 (i << (31 - i)); 301 + 302 break; 303 } 304 } ··· 309 310 static void write_pm_cntrl(int cpu) 311 { 312 + /* 313 + * Oprofile will use 32 bit counters, set bits 7:10 to 0 314 * pmregs.pm_cntrl is a global 315 */ 316 ··· 326 if (pm_regs.pm_cntrl.freeze == 1) 327 val |= CBE_PM_FREEZE_ALL_CTRS; 328 329 + /* 330 + * Routine set_count_mode must be called previously to set 331 * the count mode based on the user selection of user and kernel. 332 */ 333 val |= CBE_PM_COUNT_MODE_SET(pm_regs.pm_cntrl.count_mode); ··· 336 static inline void 337 set_count_mode(u32 kernel, u32 user) 338 { 339 + /* 340 + * The user must specify user and kernel if they want them. If 341 * neither is specified, OProfile will count in hypervisor mode. 342 * pm_regs.pm_cntrl is a global 343 */ ··· 364 365 /* 366 * Oprofile is expected to collect data on all CPUs simultaneously. 367 + * However, there is one set of performance counters per node. There are 368 * two hardware threads or virtual CPUs on each node. Hence, OProfile must 369 * multiplex in time the performance counter collection on the two virtual 370 * CPUs. The multiplexing of the performance counters is done by this ··· 377 * pair of per-cpu arrays is used for storing the previous and next 378 * pmc values for a given node. 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 383 */ 384 static void cell_virtual_cntr(unsigned long data) 385 { 386 int i, prev_hdw_thread, next_hdw_thread; 387 u32 cpu; 388 unsigned long flags; 389 390 + /* 391 + * Make sure that the interrupt_hander and the virt counter are 392 + * not both playing with the counters on the same node. 393 */ 394 395 spin_lock_irqsave(&virt_cntr_lock, flags); ··· 400 hdw_thread = 1 ^ hdw_thread; 401 next_hdw_thread = hdw_thread; 402 403 + /* 404 + * There are some per thread events. Must do the 405 * set event, for the thread that is being started 406 */ 407 + for (i = 0; i < num_counters; i++) 408 set_pm_event(i, 409 pmc_cntrl[next_hdw_thread][i].evnts, 410 pmc_cntrl[next_hdw_thread][i].masks); 411 412 + /* 413 + * The following is done only once per each node, but 414 * we need cpu #, not node #, to pass to the cbe_xxx functions. 415 */ 416 for_each_online_cpu(cpu) { 417 if (cbe_get_hw_thread_id(cpu)) 418 continue; 419 420 + /* 421 + * stop counters, save counter values, restore counts 422 * for previous thread 423 */ 424 cbe_disable_pm(cpu); ··· 428 == 0xFFFFFFFF) 429 /* If the cntr value is 0xffffffff, we must 430 * reset that to 0xfffffff0 when the current 431 + * thread is restarted. This will generate a 432 * new interrupt and make sure that we never 433 * restore the counters to the max value. If 434 * the counters were restored to the max value, ··· 444 next_hdw_thread)[i]); 445 } 446 447 + /* 448 + * Switch to the other thread. Change the interrupt 449 * and control regs to be scheduled on the CPU 450 * corresponding to the thread to execute. 451 */ 452 for (i = 0; i < num_counters; i++) { 453 if (pmc_cntrl[next_hdw_thread][i].enabled) { 454 + /* 455 + * There are some per thread events. 456 * Must do the set event, enable_cntr 457 * for each cpu. 458 */ ··· 482 } 483 484 /* This function is called once for all cpus combined */ 485 + static int cell_reg_setup(struct op_counter_config *ctr, 486 + struct op_system_config *sys, int num_ctrs) 487 { 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 + } 507 508 pm_rtas_token = rtas_token("ibm,cbe-perftools"); 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", 519 __FUNCTION__); 520 + return -EIO; 521 } 522 523 num_counters = num_ctrs; ··· 520 per_cpu(pmc_values, j)[i] = 0; 521 } 522 523 + /* 524 + * Setup the thread 1 events, map the thread 0 event to the 525 * equivalent thread 1 event. 526 */ 527 for (i = 0; i < num_ctrs; ++i) { ··· 544 for (i = 0; i < NUM_INPUT_BUS_WORDS; i++) 545 input_bus[i] = 0xff; 546 547 + /* 548 + * Our counters count up, and "count" refers to 549 * how much before the next interrupt, and we interrupt 550 + * on overflow. So we calculate the starting value 551 * which will give us "count" until overflow. 552 * Then we set the events on the enabled counters. 553 */ ··· 569 for (i = 0; i < num_counters; ++i) { 570 per_cpu(pmc_values, cpu)[i] = reset_value[i]; 571 } 572 + 573 + return 0; 574 } 575 576 + 577 + 578 /* This function is called once for each cpu */ 579 + static int cell_cpu_setup(struct op_counter_config *cntr) 580 { 581 u32 cpu = smp_processor_id(); 582 u32 num_enabled = 0; 583 int i; 584 585 + if (spu_cycle_reset) 586 + return 0; 587 + 588 /* There is one performance monitor per processor chip (i.e. node), 589 * so we only need to perform this function once per node. 590 */ 591 if (cbe_get_hw_thread_id(cpu)) 592 + return 0; 593 594 /* Stop all counters */ 595 cbe_disable_pm(cpu); ··· 609 } 610 } 611 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); 617 } 618 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) 722 { 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; 891 u32 interrupt_mask = 0; 892 893 /* This routine gets called once for the system. 894 * There is one performance monitor per node, so we ··· 651 oprofile_running = 1; 652 smp_wmb(); 653 654 + /* 655 + * NOTE: start_virt_cntrs will result in cell_virtual_cntr() being 656 + * executed which manipulates the PMU. We start the "virtual counter" 657 * here so that we do not need to synchronize access to the PMU in 658 * the above for-loop. 659 */ 660 start_virt_cntrs(); 661 + 662 + return 0; 663 } 664 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) 722 { 723 int cpu; 724 725 + /* 726 + * This routine will be called once for the system. 727 * There is one performance monitor per node, so we 728 * only need to perform this function once per node. 729 */ ··· 687 } 688 } 689 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) 700 { 701 u32 cpu; 702 u64 pc; ··· 699 700 cpu = smp_processor_id(); 701 702 + /* 703 + * Need to make sure the interrupt handler and the virt counter 704 * routine are not running at the same time. See the 705 * cell_virtual_cntr() routine for additional comments. 706 */ 707 spin_lock_irqsave(&virt_cntr_lock, flags); 708 709 + /* 710 + * Need to disable and reenable the performance counters 711 * to get the desired behavior from the hardware. This 712 * is hardware specific. 713 */ ··· 714 715 interrupt_mask = cbe_get_and_clear_pm_interrupts(cpu); 716 717 + /* 718 + * If the interrupt mask has been cleared, then the virt cntr 719 * has cleared the interrupt. When the thread that generated 720 * the interrupt is restored, the data count will be restored to 721 * 0xffffff0 to cause the interrupt to be regenerated. ··· 732 } 733 } 734 735 + /* 736 + * The counters were frozen by the interrupt. 737 * Reenable the interrupt and restart the counters. 738 * If there was a race between the interrupt handler and 739 + * the virtual counter routine. The virutal counter 740 * routine may have cleared the interrupts. Hence must 741 * use the virt_cntr_inter_mask to re-enable the interrupts. 742 */ 743 cbe_enable_pm_interrupts(cpu, hdw_thread, 744 virt_cntr_inter_mask); 745 746 + /* 747 + * The writes to the various performance counters only writes 748 + * to a latch. The new values (interrupt setting bits, reset 749 * counter value etc.) are not copied to the actual registers 750 * until the performance monitor is enabled. In order to get 751 * this to work as desired, the permormance monitor needs to ··· 755 spin_unlock_irqrestore(&virt_cntr_lock, flags); 756 } 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 + 779 struct op_powerpc_model op_model_cell = { 780 .reg_setup = cell_reg_setup, 781 .cpu_setup = cell_cpu_setup, 782 .global_start = cell_global_start, 783 .global_stop = cell_global_stop, 784 + .sync_start = cell_sync_start, 785 + .sync_stop = cell_sync_stop, 786 .handle_interrupt = cell_handle_interrupt, 787 };
+8 -3
arch/powerpc/oprofile/op_model_fsl_booke.c
··· 244 mfpmr(PMRN_PMLCA3), mfpmr(PMRN_PMLCB3)); 245 } 246 247 - static void fsl_booke_cpu_setup(struct op_counter_config *ctr) 248 { 249 int i; 250 ··· 258 259 set_pmc_user_kernel(i, ctr[i].user, ctr[i].kernel); 260 } 261 } 262 263 - static void fsl_booke_reg_setup(struct op_counter_config *ctr, 264 struct op_system_config *sys, 265 int num_ctrs) 266 { ··· 278 for (i = 0; i < num_counters; ++i) 279 reset_value[i] = 0x80000000UL - ctr[i].count; 280 281 } 282 283 - static void fsl_booke_start(struct op_counter_config *ctr) 284 { 285 int i; 286 ··· 311 312 pr_debug("start on cpu %d, pmgc0 %x\n", smp_processor_id(), 313 mfpmr(PMRN_PMGC0)); 314 } 315 316 static void fsl_booke_stop(void)
··· 244 mfpmr(PMRN_PMLCA3), mfpmr(PMRN_PMLCB3)); 245 } 246 247 + static int fsl_booke_cpu_setup(struct op_counter_config *ctr) 248 { 249 int i; 250 ··· 258 259 set_pmc_user_kernel(i, ctr[i].user, ctr[i].kernel); 260 } 261 + 262 + return 0; 263 } 264 265 + static int fsl_booke_reg_setup(struct op_counter_config *ctr, 266 struct op_system_config *sys, 267 int num_ctrs) 268 { ··· 276 for (i = 0; i < num_counters; ++i) 277 reset_value[i] = 0x80000000UL - ctr[i].count; 278 279 + return 0; 280 } 281 282 + static int fsl_booke_start(struct op_counter_config *ctr) 283 { 284 int i; 285 ··· 308 309 pr_debug("start on cpu %d, pmgc0 %x\n", smp_processor_id(), 310 mfpmr(PMRN_PMGC0)); 311 + 312 + return 0; 313 } 314 315 static void fsl_booke_stop(void)
+9 -3
arch/powerpc/oprofile/op_model_pa6t.c
··· 89 90 91 /* precompute the values to stuff in the hardware registers */ 92 - static void pa6t_reg_setup(struct op_counter_config *ctr, 93 struct op_system_config *sys, 94 int num_ctrs) 95 { ··· 135 pr_debug("reset_value for pmc%u inited to 0x%lx\n", 136 pmc, reset_value[pmc]); 137 } 138 } 139 140 /* configure registers on this cpu */ 141 - static void pa6t_cpu_setup(struct op_counter_config *ctr) 142 { 143 u64 mmcr0 = mmcr0_val; 144 u64 mmcr1 = mmcr1_val; ··· 156 mfspr(SPRN_PA6T_MMCR0)); 157 pr_debug("setup on cpu %d, mmcr1 %016lx\n", smp_processor_id(), 158 mfspr(SPRN_PA6T_MMCR1)); 159 } 160 161 - static void pa6t_start(struct op_counter_config *ctr) 162 { 163 int i; 164 ··· 178 oprofile_running = 1; 179 180 pr_debug("start on cpu %d, mmcr0 %lx\n", smp_processor_id(), mmcr0); 181 } 182 183 static void pa6t_stop(void)
··· 89 90 91 /* precompute the values to stuff in the hardware registers */ 92 + static int pa6t_reg_setup(struct op_counter_config *ctr, 93 struct op_system_config *sys, 94 int num_ctrs) 95 { ··· 135 pr_debug("reset_value for pmc%u inited to 0x%lx\n", 136 pmc, reset_value[pmc]); 137 } 138 + 139 + return 0; 140 } 141 142 /* configure registers on this cpu */ 143 + static int pa6t_cpu_setup(struct op_counter_config *ctr) 144 { 145 u64 mmcr0 = mmcr0_val; 146 u64 mmcr1 = mmcr1_val; ··· 154 mfspr(SPRN_PA6T_MMCR0)); 155 pr_debug("setup on cpu %d, mmcr1 %016lx\n", smp_processor_id(), 156 mfspr(SPRN_PA6T_MMCR1)); 157 + 158 + return 0; 159 } 160 161 + static int pa6t_start(struct op_counter_config *ctr) 162 { 163 int i; 164 ··· 174 oprofile_running = 1; 175 176 pr_debug("start on cpu %d, mmcr0 %lx\n", smp_processor_id(), mmcr0); 177 + 178 + return 0; 179 } 180 181 static void pa6t_stop(void)
+8 -3
arch/powerpc/oprofile/op_model_power4.c
··· 32 static u64 mmcr1_val; 33 static u64 mmcra_val; 34 35 - static void power4_reg_setup(struct op_counter_config *ctr, 36 struct op_system_config *sys, 37 int num_ctrs) 38 { ··· 60 mmcr0_val &= ~MMCR0_PROBLEM_DISABLE; 61 else 62 mmcr0_val |= MMCR0_PROBLEM_DISABLE; 63 } 64 65 extern void ppc64_enable_pmcs(void); ··· 86 return 0; 87 } 88 89 - static void power4_cpu_setup(struct op_counter_config *ctr) 90 { 91 unsigned int mmcr0 = mmcr0_val; 92 unsigned long mmcra = mmcra_val; ··· 113 mfspr(SPRN_MMCR1)); 114 dbg("setup on cpu %d, mmcra %lx\n", smp_processor_id(), 115 mfspr(SPRN_MMCRA)); 116 } 117 118 - static void power4_start(struct op_counter_config *ctr) 119 { 120 int i; 121 unsigned int mmcr0; ··· 152 oprofile_running = 1; 153 154 dbg("start on cpu %d, mmcr0 %x\n", smp_processor_id(), mmcr0); 155 } 156 157 static void power4_stop(void)
··· 32 static u64 mmcr1_val; 33 static u64 mmcra_val; 34 35 + static int power4_reg_setup(struct op_counter_config *ctr, 36 struct op_system_config *sys, 37 int num_ctrs) 38 { ··· 60 mmcr0_val &= ~MMCR0_PROBLEM_DISABLE; 61 else 62 mmcr0_val |= MMCR0_PROBLEM_DISABLE; 63 + 64 + return 0; 65 } 66 67 extern void ppc64_enable_pmcs(void); ··· 84 return 0; 85 } 86 87 + static int power4_cpu_setup(struct op_counter_config *ctr) 88 { 89 unsigned int mmcr0 = mmcr0_val; 90 unsigned long mmcra = mmcra_val; ··· 111 mfspr(SPRN_MMCR1)); 112 dbg("setup on cpu %d, mmcra %lx\n", smp_processor_id(), 113 mfspr(SPRN_MMCRA)); 114 + 115 + return 0; 116 } 117 118 + static int power4_start(struct op_counter_config *ctr) 119 { 120 int i; 121 unsigned int mmcr0; ··· 148 oprofile_running = 1; 149 150 dbg("start on cpu %d, mmcr0 %x\n", smp_processor_id(), mmcr0); 151 + return 0; 152 } 153 154 static void power4_stop(void)
+7 -3
arch/powerpc/oprofile/op_model_rs64.c
··· 88 89 static int num_counters; 90 91 - static void rs64_reg_setup(struct op_counter_config *ctr, 92 struct op_system_config *sys, 93 int num_ctrs) 94 { ··· 100 reset_value[i] = 0x80000000UL - ctr[i].count; 101 102 /* XXX setup user and kernel profiling */ 103 } 104 105 - static void rs64_cpu_setup(struct op_counter_config *ctr) 106 { 107 unsigned int mmcr0; 108 ··· 126 mfspr(SPRN_MMCR0)); 127 dbg("setup on cpu %d, mmcr1 %lx\n", smp_processor_id(), 128 mfspr(SPRN_MMCR1)); 129 } 130 131 - static void rs64_start(struct op_counter_config *ctr) 132 { 133 int i; 134 unsigned int mmcr0; ··· 158 mtspr(SPRN_MMCR0, mmcr0); 159 160 dbg("start on cpu %d, mmcr0 %x\n", smp_processor_id(), mmcr0); 161 } 162 163 static void rs64_stop(void)
··· 88 89 static int num_counters; 90 91 + static int rs64_reg_setup(struct op_counter_config *ctr, 92 struct op_system_config *sys, 93 int num_ctrs) 94 { ··· 100 reset_value[i] = 0x80000000UL - ctr[i].count; 101 102 /* XXX setup user and kernel profiling */ 103 + return 0; 104 } 105 106 + static int rs64_cpu_setup(struct op_counter_config *ctr) 107 { 108 unsigned int mmcr0; 109 ··· 125 mfspr(SPRN_MMCR0)); 126 dbg("setup on cpu %d, mmcr1 %lx\n", smp_processor_id(), 127 mfspr(SPRN_MMCR1)); 128 + 129 + return 0; 130 } 131 132 + static int rs64_start(struct op_counter_config *ctr) 133 { 134 int i; 135 unsigned int mmcr0; ··· 155 mtspr(SPRN_MMCR0, mmcr0); 156 157 dbg("start on cpu %d, mmcr0 %x\n", smp_processor_id(), mmcr0); 158 + return 0; 159 } 160 161 static void rs64_stop(void)
+10
arch/powerpc/platforms/Kconfig
··· 272 you wish to build a kernel for a machine with a CPM2 coprocessor 273 on it (826x, 827x, 8560). 274 275 endmenu
··· 272 you wish to build a kernel for a machine with a CPM2 coprocessor 273 on it (826x, 827x, 8560). 274 275 + config AXON_RAM 276 + tristate "Axon DDR2 memory device driver" 277 + depends on PPC_IBM_CELL_BLADE 278 + default m 279 + help 280 + It registers one block device per Axon's DDR2 memory bank found 281 + on a system. Block devices are called axonram?, their major and 282 + minor numbers are available in /proc/devices, /proc/partitions or 283 + in /sys/block/axonram?/dev. 284 + 285 endmenu
+10
arch/powerpc/platforms/cell/Kconfig
··· 73 For details, take a look at <file:Documentation/cpu-freq/>. 74 If you don't have such processor, say N 75 76 endmenu
··· 73 For details, take a look at <file:Documentation/cpu-freq/>. 74 If you don't have such processor, say N 75 76 + config CBE_CPUFREQ_PMI 77 + tristate "CBE frequency scaling using PMI interface" 78 + depends on CBE_CPUFREQ && PPC_PMI && EXPERIMENTAL 79 + default n 80 + help 81 + Select this, if you want to use the PMI interface 82 + to switch frequencies. Using PMI, the 83 + processor will not only be able to run at lower speed, 84 + but also at lower core voltage. 85 + 86 endmenu
+5 -1
arch/powerpc/platforms/cell/Makefile
··· 4 obj-$(CONFIG_CBE_RAS) += ras.o 5 6 obj-$(CONFIG_CBE_THERM) += cbe_thermal.o 7 - obj-$(CONFIG_CBE_CPUFREQ) += cbe_cpufreq.o 8 9 ifeq ($(CONFIG_SMP),y) 10 obj-$(CONFIG_PPC_CELL_NATIVE) += smp.o ··· 25 $(spu-priv1-y) \ 26 $(spu-manage-y) \ 27 spufs/
··· 4 obj-$(CONFIG_CBE_RAS) += ras.o 5 6 obj-$(CONFIG_CBE_THERM) += cbe_thermal.o 7 + obj-$(CONFIG_CBE_CPUFREQ_PMI) += cbe_cpufreq_pmi.o 8 + obj-$(CONFIG_CBE_CPUFREQ) += cbe-cpufreq.o 9 + cbe-cpufreq-y += cbe_cpufreq_pervasive.o cbe_cpufreq.o 10 11 ifeq ($(CONFIG_SMP),y) 12 obj-$(CONFIG_PPC_CELL_NATIVE) += smp.o ··· 23 $(spu-priv1-y) \ 24 $(spu-manage-y) \ 25 spufs/ 26 + 27 + obj-$(CONFIG_PCI_MSI) += axon_msi.o
+445
arch/powerpc/platforms/cell/axon_msi.c
···
··· 1 + /* 2 + * Copyright 2007, Michael Ellerman, IBM Corporation. 3 + * 4 + * This program is free software; you can redistribute it and/or 5 + * modify it under the terms of the GNU General Public License 6 + * as published by the Free Software Foundation; either version 7 + * 2 of the License, or (at your option) any later version. 8 + */ 9 + 10 + 11 + #include <linux/interrupt.h> 12 + #include <linux/irq.h> 13 + #include <linux/kernel.h> 14 + #include <linux/pci.h> 15 + #include <linux/msi.h> 16 + #include <linux/reboot.h> 17 + 18 + #include <asm/dcr.h> 19 + #include <asm/machdep.h> 20 + #include <asm/prom.h> 21 + 22 + 23 + /* 24 + * MSIC registers, specified as offsets from dcr_base 25 + */ 26 + #define MSIC_CTRL_REG 0x0 27 + 28 + /* Base Address registers specify FIFO location in BE memory */ 29 + #define MSIC_BASE_ADDR_HI_REG 0x3 30 + #define MSIC_BASE_ADDR_LO_REG 0x4 31 + 32 + /* Hold the read/write offsets into the FIFO */ 33 + #define MSIC_READ_OFFSET_REG 0x5 34 + #define MSIC_WRITE_OFFSET_REG 0x6 35 + 36 + 37 + /* MSIC control register flags */ 38 + #define MSIC_CTRL_ENABLE 0x0001 39 + #define MSIC_CTRL_FIFO_FULL_ENABLE 0x0002 40 + #define MSIC_CTRL_IRQ_ENABLE 0x0008 41 + #define MSIC_CTRL_FULL_STOP_ENABLE 0x0010 42 + 43 + /* 44 + * The MSIC can be configured to use a FIFO of 32KB, 64KB, 128KB or 256KB. 45 + * Currently we're using a 64KB FIFO size. 46 + */ 47 + #define MSIC_FIFO_SIZE_SHIFT 16 48 + #define MSIC_FIFO_SIZE_BYTES (1 << MSIC_FIFO_SIZE_SHIFT) 49 + 50 + /* 51 + * To configure the FIFO size as (1 << n) bytes, we write (n - 15) into bits 52 + * 8-9 of the MSIC control reg. 53 + */ 54 + #define MSIC_CTRL_FIFO_SIZE (((MSIC_FIFO_SIZE_SHIFT - 15) << 8) & 0x300) 55 + 56 + /* 57 + * We need to mask the read/write offsets to make sure they stay within 58 + * the bounds of the FIFO. Also they should always be 16-byte aligned. 59 + */ 60 + #define MSIC_FIFO_SIZE_MASK ((MSIC_FIFO_SIZE_BYTES - 1) & ~0xFu) 61 + 62 + /* Each entry in the FIFO is 16 bytes, the first 4 bytes hold the irq # */ 63 + #define MSIC_FIFO_ENTRY_SIZE 0x10 64 + 65 + 66 + struct axon_msic { 67 + struct device_node *dn; 68 + struct irq_host *irq_host; 69 + __le32 *fifo; 70 + dcr_host_t dcr_host; 71 + struct list_head list; 72 + u32 read_offset; 73 + u32 dcr_base; 74 + }; 75 + 76 + static LIST_HEAD(axon_msic_list); 77 + 78 + static void msic_dcr_write(struct axon_msic *msic, unsigned int dcr_n, u32 val) 79 + { 80 + pr_debug("axon_msi: dcr_write(0x%x, 0x%x)\n", val, dcr_n); 81 + 82 + dcr_write(msic->dcr_host, msic->dcr_base + dcr_n, val); 83 + } 84 + 85 + static u32 msic_dcr_read(struct axon_msic *msic, unsigned int dcr_n) 86 + { 87 + return dcr_read(msic->dcr_host, msic->dcr_base + dcr_n); 88 + } 89 + 90 + static void axon_msi_cascade(unsigned int irq, struct irq_desc *desc) 91 + { 92 + struct axon_msic *msic = get_irq_data(irq); 93 + u32 write_offset, msi; 94 + int idx; 95 + 96 + write_offset = msic_dcr_read(msic, MSIC_WRITE_OFFSET_REG); 97 + pr_debug("axon_msi: original write_offset 0x%x\n", write_offset); 98 + 99 + /* write_offset doesn't wrap properly, so we have to mask it */ 100 + write_offset &= MSIC_FIFO_SIZE_MASK; 101 + 102 + while (msic->read_offset != write_offset) { 103 + idx = msic->read_offset / sizeof(__le32); 104 + msi = le32_to_cpu(msic->fifo[idx]); 105 + msi &= 0xFFFF; 106 + 107 + pr_debug("axon_msi: woff %x roff %x msi %x\n", 108 + write_offset, msic->read_offset, msi); 109 + 110 + msic->read_offset += MSIC_FIFO_ENTRY_SIZE; 111 + msic->read_offset &= MSIC_FIFO_SIZE_MASK; 112 + 113 + if (msi < NR_IRQS && irq_map[msi].host == msic->irq_host) 114 + generic_handle_irq(msi); 115 + else 116 + pr_debug("axon_msi: invalid irq 0x%x!\n", msi); 117 + } 118 + 119 + desc->chip->eoi(irq); 120 + } 121 + 122 + static struct axon_msic *find_msi_translator(struct pci_dev *dev) 123 + { 124 + struct irq_host *irq_host; 125 + struct device_node *dn, *tmp; 126 + const phandle *ph; 127 + struct axon_msic *msic = NULL; 128 + 129 + dn = pci_device_to_OF_node(dev); 130 + if (!dn) { 131 + dev_dbg(&dev->dev, "axon_msi: no pci_dn found\n"); 132 + return NULL; 133 + } 134 + 135 + for (; dn; tmp = of_get_parent(dn), of_node_put(dn), dn = tmp) { 136 + ph = of_get_property(dn, "msi-translator", NULL); 137 + if (ph) 138 + break; 139 + } 140 + 141 + if (!ph) { 142 + dev_dbg(&dev->dev, 143 + "axon_msi: no msi-translator property found\n"); 144 + goto out_error; 145 + } 146 + 147 + tmp = dn; 148 + dn = of_find_node_by_phandle(*ph); 149 + if (!dn) { 150 + dev_dbg(&dev->dev, 151 + "axon_msi: msi-translator doesn't point to a node\n"); 152 + goto out_error; 153 + } 154 + 155 + irq_host = irq_find_host(dn); 156 + if (!irq_host) { 157 + dev_dbg(&dev->dev, "axon_msi: no irq_host found for node %s\n", 158 + dn->full_name); 159 + goto out_error; 160 + } 161 + 162 + msic = irq_host->host_data; 163 + 164 + out_error: 165 + of_node_put(dn); 166 + of_node_put(tmp); 167 + 168 + return msic; 169 + } 170 + 171 + static int axon_msi_check_device(struct pci_dev *dev, int nvec, int type) 172 + { 173 + if (!find_msi_translator(dev)) 174 + return -ENODEV; 175 + 176 + return 0; 177 + } 178 + 179 + static int setup_msi_msg_address(struct pci_dev *dev, struct msi_msg *msg) 180 + { 181 + struct device_node *dn, *tmp; 182 + struct msi_desc *entry; 183 + int len; 184 + const u32 *prop; 185 + 186 + dn = pci_device_to_OF_node(dev); 187 + if (!dn) { 188 + dev_dbg(&dev->dev, "axon_msi: no pci_dn found\n"); 189 + return -ENODEV; 190 + } 191 + 192 + entry = list_first_entry(&dev->msi_list, struct msi_desc, list); 193 + 194 + for (; dn; tmp = of_get_parent(dn), of_node_put(dn), dn = tmp) { 195 + if (entry->msi_attrib.is_64) { 196 + prop = of_get_property(dn, "msi-address-64", &len); 197 + if (prop) 198 + break; 199 + } 200 + 201 + prop = of_get_property(dn, "msi-address-32", &len); 202 + if (prop) 203 + break; 204 + } 205 + 206 + if (!prop) { 207 + dev_dbg(&dev->dev, 208 + "axon_msi: no msi-address-(32|64) properties found\n"); 209 + return -ENOENT; 210 + } 211 + 212 + switch (len) { 213 + case 8: 214 + msg->address_hi = prop[0]; 215 + msg->address_lo = prop[1]; 216 + break; 217 + case 4: 218 + msg->address_hi = 0; 219 + msg->address_lo = prop[0]; 220 + break; 221 + default: 222 + dev_dbg(&dev->dev, 223 + "axon_msi: malformed msi-address-(32|64) property\n"); 224 + of_node_put(dn); 225 + return -EINVAL; 226 + } 227 + 228 + of_node_put(dn); 229 + 230 + return 0; 231 + } 232 + 233 + static int axon_msi_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) 234 + { 235 + unsigned int virq, rc; 236 + struct msi_desc *entry; 237 + struct msi_msg msg; 238 + struct axon_msic *msic; 239 + 240 + msic = find_msi_translator(dev); 241 + if (!msic) 242 + return -ENODEV; 243 + 244 + rc = setup_msi_msg_address(dev, &msg); 245 + if (rc) 246 + return rc; 247 + 248 + /* We rely on being able to stash a virq in a u16 */ 249 + BUILD_BUG_ON(NR_IRQS > 65536); 250 + 251 + list_for_each_entry(entry, &dev->msi_list, list) { 252 + virq = irq_create_direct_mapping(msic->irq_host); 253 + if (virq == NO_IRQ) { 254 + dev_warn(&dev->dev, 255 + "axon_msi: virq allocation failed!\n"); 256 + return -1; 257 + } 258 + dev_dbg(&dev->dev, "axon_msi: allocated virq 0x%x\n", virq); 259 + 260 + set_irq_msi(virq, entry); 261 + msg.data = virq; 262 + write_msi_msg(virq, &msg); 263 + } 264 + 265 + return 0; 266 + } 267 + 268 + static void axon_msi_teardown_msi_irqs(struct pci_dev *dev) 269 + { 270 + struct msi_desc *entry; 271 + 272 + dev_dbg(&dev->dev, "axon_msi: tearing down msi irqs\n"); 273 + 274 + list_for_each_entry(entry, &dev->msi_list, list) { 275 + if (entry->irq == NO_IRQ) 276 + continue; 277 + 278 + set_irq_msi(entry->irq, NULL); 279 + irq_dispose_mapping(entry->irq); 280 + } 281 + } 282 + 283 + static struct irq_chip msic_irq_chip = { 284 + .mask = mask_msi_irq, 285 + .unmask = unmask_msi_irq, 286 + .shutdown = unmask_msi_irq, 287 + .typename = "AXON-MSI", 288 + }; 289 + 290 + static int msic_host_map(struct irq_host *h, unsigned int virq, 291 + irq_hw_number_t hw) 292 + { 293 + set_irq_chip_and_handler(virq, &msic_irq_chip, handle_simple_irq); 294 + 295 + return 0; 296 + } 297 + 298 + static int msic_host_match(struct irq_host *host, struct device_node *dn) 299 + { 300 + struct axon_msic *msic = host->host_data; 301 + 302 + return msic->dn == dn; 303 + } 304 + 305 + static struct irq_host_ops msic_host_ops = { 306 + .match = msic_host_match, 307 + .map = msic_host_map, 308 + }; 309 + 310 + static int axon_msi_notify_reboot(struct notifier_block *nb, 311 + unsigned long code, void *data) 312 + { 313 + struct axon_msic *msic; 314 + u32 tmp; 315 + 316 + list_for_each_entry(msic, &axon_msic_list, list) { 317 + pr_debug("axon_msi: disabling %s\n", msic->dn->full_name); 318 + tmp = msic_dcr_read(msic, MSIC_CTRL_REG); 319 + tmp &= ~MSIC_CTRL_ENABLE & ~MSIC_CTRL_IRQ_ENABLE; 320 + msic_dcr_write(msic, MSIC_CTRL_REG, tmp); 321 + } 322 + 323 + return 0; 324 + } 325 + 326 + static struct notifier_block axon_msi_reboot_notifier = { 327 + .notifier_call = axon_msi_notify_reboot 328 + }; 329 + 330 + static int axon_msi_setup_one(struct device_node *dn) 331 + { 332 + struct page *page; 333 + struct axon_msic *msic; 334 + unsigned int virq; 335 + int dcr_len; 336 + 337 + pr_debug("axon_msi: setting up dn %s\n", dn->full_name); 338 + 339 + msic = kzalloc(sizeof(struct axon_msic), GFP_KERNEL); 340 + if (!msic) { 341 + printk(KERN_ERR "axon_msi: couldn't allocate msic for %s\n", 342 + dn->full_name); 343 + goto out; 344 + } 345 + 346 + msic->dcr_base = dcr_resource_start(dn, 0); 347 + dcr_len = dcr_resource_len(dn, 0); 348 + 349 + if (msic->dcr_base == 0 || dcr_len == 0) { 350 + printk(KERN_ERR 351 + "axon_msi: couldn't parse dcr properties on %s\n", 352 + dn->full_name); 353 + goto out; 354 + } 355 + 356 + msic->dcr_host = dcr_map(dn, msic->dcr_base, dcr_len); 357 + if (!DCR_MAP_OK(msic->dcr_host)) { 358 + printk(KERN_ERR "axon_msi: dcr_map failed for %s\n", 359 + dn->full_name); 360 + goto out_free_msic; 361 + } 362 + 363 + page = alloc_pages_node(of_node_to_nid(dn), GFP_KERNEL, 364 + get_order(MSIC_FIFO_SIZE_BYTES)); 365 + if (!page) { 366 + printk(KERN_ERR "axon_msi: couldn't allocate fifo for %s\n", 367 + dn->full_name); 368 + goto out_free_msic; 369 + } 370 + 371 + msic->fifo = page_address(page); 372 + 373 + msic->irq_host = irq_alloc_host(IRQ_HOST_MAP_NOMAP, NR_IRQS, 374 + &msic_host_ops, 0); 375 + if (!msic->irq_host) { 376 + printk(KERN_ERR "axon_msi: couldn't allocate irq_host for %s\n", 377 + dn->full_name); 378 + goto out_free_fifo; 379 + } 380 + 381 + msic->irq_host->host_data = msic; 382 + 383 + virq = irq_of_parse_and_map(dn, 0); 384 + if (virq == NO_IRQ) { 385 + printk(KERN_ERR "axon_msi: irq parse and map failed for %s\n", 386 + dn->full_name); 387 + goto out_free_host; 388 + } 389 + 390 + msic->dn = of_node_get(dn); 391 + 392 + set_irq_data(virq, msic); 393 + set_irq_chained_handler(virq, axon_msi_cascade); 394 + pr_debug("axon_msi: irq 0x%x setup for axon_msi\n", virq); 395 + 396 + /* Enable the MSIC hardware */ 397 + msic_dcr_write(msic, MSIC_BASE_ADDR_HI_REG, (u64)msic->fifo >> 32); 398 + msic_dcr_write(msic, MSIC_BASE_ADDR_LO_REG, 399 + (u64)msic->fifo & 0xFFFFFFFF); 400 + msic_dcr_write(msic, MSIC_CTRL_REG, 401 + MSIC_CTRL_IRQ_ENABLE | MSIC_CTRL_ENABLE | 402 + MSIC_CTRL_FIFO_SIZE); 403 + 404 + list_add(&msic->list, &axon_msic_list); 405 + 406 + printk(KERN_DEBUG "axon_msi: setup MSIC on %s\n", dn->full_name); 407 + 408 + return 0; 409 + 410 + out_free_host: 411 + kfree(msic->irq_host); 412 + out_free_fifo: 413 + __free_pages(virt_to_page(msic->fifo), get_order(MSIC_FIFO_SIZE_BYTES)); 414 + out_free_msic: 415 + kfree(msic); 416 + out: 417 + 418 + return -1; 419 + } 420 + 421 + static int axon_msi_init(void) 422 + { 423 + struct device_node *dn; 424 + int found = 0; 425 + 426 + pr_debug("axon_msi: initialising ...\n"); 427 + 428 + for_each_compatible_node(dn, NULL, "ibm,axon-msic") { 429 + if (axon_msi_setup_one(dn) == 0) 430 + found++; 431 + } 432 + 433 + if (found) { 434 + ppc_md.setup_msi_irqs = axon_msi_setup_msi_irqs; 435 + ppc_md.teardown_msi_irqs = axon_msi_teardown_msi_irqs; 436 + ppc_md.msi_check_device = axon_msi_check_device; 437 + 438 + register_reboot_notifier(&axon_msi_reboot_notifier); 439 + 440 + pr_debug("axon_msi: registered callbacks!\n"); 441 + } 442 + 443 + return 0; 444 + } 445 + arch_initcall(axon_msi_init);
+36 -185
arch/powerpc/platforms/cell/cbe_cpufreq.c
··· 1 /* 2 * cpufreq driver for the cell processor 3 * 4 - * (C) Copyright IBM Deutschland Entwicklung GmbH 2005 5 * 6 * Author: Christian Krafft <krafft@de.ibm.com> 7 * ··· 21 */ 22 23 #include <linux/cpufreq.h> 24 - #include <linux/timer.h> 25 - 26 - #include <asm/hw_irq.h> 27 - #include <asm/io.h> 28 #include <asm/machdep.h> 29 - #include <asm/processor.h> 30 - #include <asm/prom.h> 31 - #include <asm/time.h> 32 - #include <asm/pmi.h> 33 #include <asm/of_platform.h> 34 - 35 #include "cbe_regs.h" 36 37 static DEFINE_MUTEX(cbe_switch_mutex); 38 ··· 43 {0, CPUFREQ_TABLE_END}, 44 }; 45 46 - /* to write to MIC register */ 47 - static u64 MIC_Slow_Fast_Timer_table[] = { 48 - [0 ... 7] = 0x007fc00000000000ull, 49 - }; 50 - 51 - /* more values for the MIC */ 52 - static u64 MIC_Slow_Next_Timer_table[] = { 53 - 0x0000240000000000ull, 54 - 0x0000268000000000ull, 55 - 0x000029C000000000ull, 56 - 0x00002D0000000000ull, 57 - 0x0000300000000000ull, 58 - 0x0000334000000000ull, 59 - 0x000039C000000000ull, 60 - 0x00003FC000000000ull, 61 - }; 62 - 63 - static unsigned int pmi_frequency_limit = 0; 64 /* 65 * hardware specific functions 66 */ 67 68 - static struct of_device *pmi_dev; 69 - 70 - #ifdef CONFIG_PPC_PMI 71 - static int set_pmode_pmi(int cpu, unsigned int pmode) 72 { 73 - int ret; 74 - pmi_message_t pmi_msg; 75 - #ifdef DEBUG 76 - u64 time; 77 - #endif 78 79 - pmi_msg.type = PMI_TYPE_FREQ_CHANGE; 80 - pmi_msg.data1 = cbe_cpu_to_node(cpu); 81 - pmi_msg.data2 = pmode; 82 - 83 - #ifdef DEBUG 84 - time = (u64) get_cycles(); 85 - #endif 86 - 87 - pmi_send_message(pmi_dev, pmi_msg); 88 - ret = pmi_msg.data2; 89 - 90 - pr_debug("PMI returned slow mode %d\n", ret); 91 - 92 - #ifdef DEBUG 93 - time = (u64) get_cycles() - time; /* actual cycles (not cpu cycles!) */ 94 - time = 1000000000 * time / CLOCK_TICK_RATE; /* time in ns (10^-9) */ 95 - pr_debug("had to wait %lu ns for a transition\n", time); 96 - #endif 97 - return ret; 98 - } 99 - #endif 100 - 101 - static int get_pmode(int cpu) 102 - { 103 - int ret; 104 - struct cbe_pmd_regs __iomem *pmd_regs; 105 - 106 - pmd_regs = cbe_get_cpu_pmd_regs(cpu); 107 - ret = in_be64(&pmd_regs->pmsr) & 0x07; 108 - 109 - return ret; 110 - } 111 - 112 - static int set_pmode_reg(int cpu, unsigned int pmode) 113 - { 114 - struct cbe_pmd_regs __iomem *pmd_regs; 115 - struct cbe_mic_tm_regs __iomem *mic_tm_regs; 116 - u64 flags; 117 - u64 value; 118 - 119 - local_irq_save(flags); 120 - 121 - mic_tm_regs = cbe_get_cpu_mic_tm_regs(cpu); 122 - pmd_regs = cbe_get_cpu_pmd_regs(cpu); 123 - 124 - pr_debug("pm register is mapped at %p\n", &pmd_regs->pmcr); 125 - pr_debug("mic register is mapped at %p\n", &mic_tm_regs->slow_fast_timer_0); 126 - 127 - out_be64(&mic_tm_regs->slow_fast_timer_0, MIC_Slow_Fast_Timer_table[pmode]); 128 - out_be64(&mic_tm_regs->slow_fast_timer_1, MIC_Slow_Fast_Timer_table[pmode]); 129 - 130 - out_be64(&mic_tm_regs->slow_next_timer_0, MIC_Slow_Next_Timer_table[pmode]); 131 - out_be64(&mic_tm_regs->slow_next_timer_1, MIC_Slow_Next_Timer_table[pmode]); 132 - 133 - value = in_be64(&pmd_regs->pmcr); 134 - /* set bits to zero */ 135 - value &= 0xFFFFFFFFFFFFFFF8ull; 136 - /* set bits to next pmode */ 137 - value |= pmode; 138 - 139 - out_be64(&pmd_regs->pmcr, value); 140 - 141 - /* wait until new pmode appears in status register */ 142 - value = in_be64(&pmd_regs->pmsr) & 0x07; 143 - while(value != pmode) { 144 - cpu_relax(); 145 - value = in_be64(&pmd_regs->pmsr) & 0x07; 146 - } 147 - 148 - local_irq_restore(flags); 149 - 150 - return 0; 151 - } 152 - 153 - static int set_pmode(int cpu, unsigned int slow_mode) { 154 - #ifdef CONFIG_PPC_PMI 155 - if (pmi_dev) 156 - return set_pmode_pmi(cpu, slow_mode); 157 else 158 - #endif 159 - return set_pmode_reg(cpu, slow_mode); 160 } 161 - 162 - static void cbe_cpufreq_handle_pmi(struct of_device *dev, pmi_message_t pmi_msg) 163 - { 164 - u8 cpu; 165 - u8 cbe_pmode_new; 166 - 167 - BUG_ON(pmi_msg.type != PMI_TYPE_FREQ_CHANGE); 168 - 169 - cpu = cbe_node_to_cpu(pmi_msg.data1); 170 - cbe_pmode_new = pmi_msg.data2; 171 - 172 - pmi_frequency_limit = cbe_freqs[cbe_pmode_new].frequency; 173 - 174 - pr_debug("cbe_handle_pmi: max freq=%d\n", pmi_frequency_limit); 175 - } 176 - 177 - static int pmi_notifier(struct notifier_block *nb, 178 - unsigned long event, void *data) 179 - { 180 - struct cpufreq_policy *policy = data; 181 - 182 - if (event != CPUFREQ_INCOMPATIBLE) 183 - return 0; 184 - 185 - cpufreq_verify_within_limits(policy, 0, pmi_frequency_limit); 186 - return 0; 187 - } 188 - 189 - static struct notifier_block pmi_notifier_block = { 190 - .notifier_call = pmi_notifier, 191 - }; 192 - 193 - static struct pmi_handler cbe_pmi_handler = { 194 - .type = PMI_TYPE_FREQ_CHANGE, 195 - .handle_pmi_message = cbe_cpufreq_handle_pmi, 196 - }; 197 - 198 199 /* 200 * cpufreq functions ··· 79 80 pr_debug("init cpufreq on CPU %d\n", policy->cpu); 81 82 max_freqp = of_get_property(cpu, "clock-frequency", NULL); 83 84 if (!max_freqp) 85 return -EINVAL; ··· 108 } 109 110 policy->governor = CPUFREQ_DEFAULT_GOVERNOR; 111 - /* if DEBUG is enabled set_pmode() measures the correct latency of a transition */ 112 policy->cpuinfo.transition_latency = 25000; 113 114 - cur_pmode = get_pmode(policy->cpu); 115 pr_debug("current pmode is at %d\n",cur_pmode); 116 117 policy->cur = cbe_freqs[cur_pmode].frequency; ··· 124 125 cpufreq_frequency_table_get_attr(cbe_freqs, policy->cpu); 126 127 - if (pmi_dev) { 128 - /* frequency might get limited later, initialize limit with max_freq */ 129 - pmi_frequency_limit = max_freq; 130 - cpufreq_register_notifier(&pmi_notifier_block, CPUFREQ_POLICY_NOTIFIER); 131 - } 132 - 133 - /* this ensures that policy->cpuinfo_min and policy->cpuinfo_max are set correctly */ 134 return cpufreq_frequency_table_cpuinfo(policy, cbe_freqs); 135 } 136 137 static int cbe_cpufreq_cpu_exit(struct cpufreq_policy *policy) 138 { 139 - if (pmi_dev) 140 - cpufreq_unregister_notifier(&pmi_notifier_block, CPUFREQ_POLICY_NOTIFIER); 141 - 142 cpufreq_frequency_table_put_attr(policy->cpu); 143 return 0; 144 } ··· 140 return cpufreq_frequency_table_verify(policy, cbe_freqs); 141 } 142 143 - 144 - static int cbe_cpufreq_target(struct cpufreq_policy *policy, unsigned int target_freq, 145 - unsigned int relation) 146 { 147 int rc; 148 struct cpufreq_freqs freqs; 149 - int cbe_pmode_new; 150 151 cpufreq_frequency_table_target(policy, 152 cbe_freqs, ··· 161 mutex_lock(&cbe_switch_mutex); 162 cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); 163 164 - pr_debug("setting frequency for cpu %d to %d kHz, 1/%d of max frequency\n", 165 policy->cpu, 166 cbe_freqs[cbe_pmode_new].frequency, 167 cbe_freqs[cbe_pmode_new].index); 168 169 rc = set_pmode(policy->cpu, cbe_pmode_new); 170 cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); 171 mutex_unlock(&cbe_switch_mutex); 172 ··· 191 192 static int __init cbe_cpufreq_init(void) 193 { 194 - #ifdef CONFIG_PPC_PMI 195 - struct device_node *np; 196 - #endif 197 if (!machine_is(cell)) 198 return -ENODEV; 199 - #ifdef CONFIG_PPC_PMI 200 - np = of_find_node_by_type(NULL, "ibm,pmi"); 201 202 - pmi_dev = of_find_device_by_node(np); 203 - 204 - if (pmi_dev) 205 - pmi_register_handler(pmi_dev, &cbe_pmi_handler); 206 - #endif 207 return cpufreq_register_driver(&cbe_cpufreq_driver); 208 } 209 210 static void __exit cbe_cpufreq_exit(void) 211 { 212 - #ifdef CONFIG_PPC_PMI 213 - if (pmi_dev) 214 - pmi_unregister_handler(pmi_dev, &cbe_pmi_handler); 215 - #endif 216 cpufreq_unregister_driver(&cbe_cpufreq_driver); 217 } 218
··· 1 /* 2 * cpufreq driver for the cell processor 3 * 4 + * (C) Copyright IBM Deutschland Entwicklung GmbH 2005-2007 5 * 6 * Author: Christian Krafft <krafft@de.ibm.com> 7 * ··· 21 */ 22 23 #include <linux/cpufreq.h> 24 #include <asm/machdep.h> 25 #include <asm/of_platform.h> 26 + #include <asm/prom.h> 27 #include "cbe_regs.h" 28 + #include "cbe_cpufreq.h" 29 30 static DEFINE_MUTEX(cbe_switch_mutex); 31 ··· 50 {0, CPUFREQ_TABLE_END}, 51 }; 52 53 /* 54 * hardware specific functions 55 */ 56 57 + static int set_pmode(unsigned int cpu, unsigned int slow_mode) 58 { 59 + int rc; 60 61 + if (cbe_cpufreq_has_pmi) 62 + rc = cbe_cpufreq_set_pmode_pmi(cpu, slow_mode); 63 else 64 + rc = cbe_cpufreq_set_pmode(cpu, slow_mode); 65 + 66 + pr_debug("register contains slow mode %d\n", cbe_cpufreq_get_pmode(cpu)); 67 + 68 + return rc; 69 } 70 71 /* 72 * cpufreq functions ··· 221 222 pr_debug("init cpufreq on CPU %d\n", policy->cpu); 223 224 + /* 225 + * Let's check we can actually get to the CELL regs 226 + */ 227 + if (!cbe_get_cpu_pmd_regs(policy->cpu) || 228 + !cbe_get_cpu_mic_tm_regs(policy->cpu)) { 229 + pr_info("invalid CBE regs pointers for cpufreq\n"); 230 + return -EINVAL; 231 + } 232 + 233 max_freqp = of_get_property(cpu, "clock-frequency", NULL); 234 + 235 + of_node_put(cpu); 236 237 if (!max_freqp) 238 return -EINVAL; ··· 239 } 240 241 policy->governor = CPUFREQ_DEFAULT_GOVERNOR; 242 + 243 + /* if DEBUG is enabled set_pmode() measures the latency 244 + * of a transition */ 245 policy->cpuinfo.transition_latency = 25000; 246 247 + cur_pmode = cbe_cpufreq_get_pmode(policy->cpu); 248 pr_debug("current pmode is at %d\n",cur_pmode); 249 250 policy->cur = cbe_freqs[cur_pmode].frequency; ··· 253 254 cpufreq_frequency_table_get_attr(cbe_freqs, policy->cpu); 255 256 + /* this ensures that policy->cpuinfo_min 257 + * and policy->cpuinfo_max are set correctly */ 258 return cpufreq_frequency_table_cpuinfo(policy, cbe_freqs); 259 } 260 261 static int cbe_cpufreq_cpu_exit(struct cpufreq_policy *policy) 262 { 263 cpufreq_frequency_table_put_attr(policy->cpu); 264 return 0; 265 } ··· 277 return cpufreq_frequency_table_verify(policy, cbe_freqs); 278 } 279 280 + static int cbe_cpufreq_target(struct cpufreq_policy *policy, 281 + unsigned int target_freq, 282 + unsigned int relation) 283 { 284 int rc; 285 struct cpufreq_freqs freqs; 286 + unsigned int cbe_pmode_new; 287 288 cpufreq_frequency_table_target(policy, 289 cbe_freqs, ··· 298 mutex_lock(&cbe_switch_mutex); 299 cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); 300 301 + pr_debug("setting frequency for cpu %d to %d kHz, " \ 302 + "1/%d of max frequency\n", 303 policy->cpu, 304 cbe_freqs[cbe_pmode_new].frequency, 305 cbe_freqs[cbe_pmode_new].index); 306 307 rc = set_pmode(policy->cpu, cbe_pmode_new); 308 + 309 cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); 310 mutex_unlock(&cbe_switch_mutex); 311 ··· 326 327 static int __init cbe_cpufreq_init(void) 328 { 329 if (!machine_is(cell)) 330 return -ENODEV; 331 332 return cpufreq_register_driver(&cbe_cpufreq_driver); 333 } 334 335 static void __exit cbe_cpufreq_exit(void) 336 { 337 cpufreq_unregister_driver(&cbe_cpufreq_driver); 338 } 339
+24
arch/powerpc/platforms/cell/cbe_cpufreq.h
···
··· 1 + /* 2 + * cbe_cpufreq.h 3 + * 4 + * This file contains the definitions used by the cbe_cpufreq driver. 5 + * 6 + * (C) Copyright IBM Deutschland Entwicklung GmbH 2005-2007 7 + * 8 + * Author: Christian Krafft <krafft@de.ibm.com> 9 + * 10 + */ 11 + 12 + #include <linux/cpufreq.h> 13 + #include <linux/types.h> 14 + 15 + int cbe_cpufreq_set_pmode(int cpu, unsigned int pmode); 16 + int cbe_cpufreq_get_pmode(int cpu); 17 + 18 + int cbe_cpufreq_set_pmode_pmi(int cpu, unsigned int pmode); 19 + 20 + #if defined(CONFIG_CBE_CPUFREQ_PMI) || defined(CONFIG_CBE_CPUFREQ_PMI_MODULE) 21 + extern bool cbe_cpufreq_has_pmi; 22 + #else 23 + #define cbe_cpufreq_has_pmi (0) 24 + #endif
+115
arch/powerpc/platforms/cell/cbe_cpufreq_pervasive.c
···
··· 1 + /* 2 + * pervasive backend for the cbe_cpufreq driver 3 + * 4 + * This driver makes use of the pervasive unit to 5 + * engage the desired frequency. 6 + * 7 + * (C) Copyright IBM Deutschland Entwicklung GmbH 2005-2007 8 + * 9 + * Author: Christian Krafft <krafft@de.ibm.com> 10 + * 11 + * This program is free software; you can redistribute it and/or modify 12 + * it under the terms of the GNU General Public License as published by 13 + * the Free Software Foundation; either version 2, or (at your option) 14 + * any later version. 15 + * 16 + * This program is distributed in the hope that it will be useful, 17 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 + * GNU General Public License for more details. 20 + * 21 + * You should have received a copy of the GNU General Public License 22 + * along with this program; if not, write to the Free Software 23 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 24 + */ 25 + 26 + #include <linux/io.h> 27 + #include <linux/kernel.h> 28 + #include <linux/time.h> 29 + #include <asm/machdep.h> 30 + #include <asm/hw_irq.h> 31 + 32 + #include "cbe_regs.h" 33 + #include "cbe_cpufreq.h" 34 + 35 + /* to write to MIC register */ 36 + static u64 MIC_Slow_Fast_Timer_table[] = { 37 + [0 ... 7] = 0x007fc00000000000ull, 38 + }; 39 + 40 + /* more values for the MIC */ 41 + static u64 MIC_Slow_Next_Timer_table[] = { 42 + 0x0000240000000000ull, 43 + 0x0000268000000000ull, 44 + 0x000029C000000000ull, 45 + 0x00002D0000000000ull, 46 + 0x0000300000000000ull, 47 + 0x0000334000000000ull, 48 + 0x000039C000000000ull, 49 + 0x00003FC000000000ull, 50 + }; 51 + 52 + 53 + int cbe_cpufreq_set_pmode(int cpu, unsigned int pmode) 54 + { 55 + struct cbe_pmd_regs __iomem *pmd_regs; 56 + struct cbe_mic_tm_regs __iomem *mic_tm_regs; 57 + u64 flags; 58 + u64 value; 59 + #ifdef DEBUG 60 + long time; 61 + #endif 62 + 63 + local_irq_save(flags); 64 + 65 + mic_tm_regs = cbe_get_cpu_mic_tm_regs(cpu); 66 + pmd_regs = cbe_get_cpu_pmd_regs(cpu); 67 + 68 + #ifdef DEBUG 69 + time = jiffies; 70 + #endif 71 + 72 + out_be64(&mic_tm_regs->slow_fast_timer_0, MIC_Slow_Fast_Timer_table[pmode]); 73 + out_be64(&mic_tm_regs->slow_fast_timer_1, MIC_Slow_Fast_Timer_table[pmode]); 74 + 75 + out_be64(&mic_tm_regs->slow_next_timer_0, MIC_Slow_Next_Timer_table[pmode]); 76 + out_be64(&mic_tm_regs->slow_next_timer_1, MIC_Slow_Next_Timer_table[pmode]); 77 + 78 + value = in_be64(&pmd_regs->pmcr); 79 + /* set bits to zero */ 80 + value &= 0xFFFFFFFFFFFFFFF8ull; 81 + /* set bits to next pmode */ 82 + value |= pmode; 83 + 84 + out_be64(&pmd_regs->pmcr, value); 85 + 86 + #ifdef DEBUG 87 + /* wait until new pmode appears in status register */ 88 + value = in_be64(&pmd_regs->pmsr) & 0x07; 89 + while (value != pmode) { 90 + cpu_relax(); 91 + value = in_be64(&pmd_regs->pmsr) & 0x07; 92 + } 93 + 94 + time = jiffies - time; 95 + time = jiffies_to_msecs(time); 96 + pr_debug("had to wait %lu ms for a transition using " \ 97 + "pervasive unit\n", time); 98 + #endif 99 + local_irq_restore(flags); 100 + 101 + return 0; 102 + } 103 + 104 + 105 + int cbe_cpufreq_get_pmode(int cpu) 106 + { 107 + int ret; 108 + struct cbe_pmd_regs __iomem *pmd_regs; 109 + 110 + pmd_regs = cbe_get_cpu_pmd_regs(cpu); 111 + ret = in_be64(&pmd_regs->pmsr) & 0x07; 112 + 113 + return ret; 114 + } 115 +
+148
arch/powerpc/platforms/cell/cbe_cpufreq_pmi.c
···
··· 1 + /* 2 + * pmi backend for the cbe_cpufreq driver 3 + * 4 + * (C) Copyright IBM Deutschland Entwicklung GmbH 2005-2007 5 + * 6 + * Author: Christian Krafft <krafft@de.ibm.com> 7 + * 8 + * This program is free software; you can redistribute it and/or modify 9 + * it under the terms of the GNU General Public License as published by 10 + * the Free Software Foundation; either version 2, or (at your option) 11 + * any later version. 12 + * 13 + * This program is distributed in the hope that it will be useful, 14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 + * GNU General Public License for more details. 17 + * 18 + * You should have received a copy of the GNU General Public License 19 + * along with this program; if not, write to the Free Software 20 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21 + */ 22 + 23 + #include <linux/kernel.h> 24 + #include <linux/types.h> 25 + #include <linux/timer.h> 26 + #include <asm/of_platform.h> 27 + #include <asm/processor.h> 28 + #include <asm/prom.h> 29 + #include <asm/pmi.h> 30 + 31 + #ifdef DEBUG 32 + #include <asm/time.h> 33 + #endif 34 + 35 + #include "cbe_regs.h" 36 + #include "cbe_cpufreq.h" 37 + 38 + static u8 pmi_slow_mode_limit[MAX_CBE]; 39 + 40 + bool cbe_cpufreq_has_pmi = false; 41 + EXPORT_SYMBOL_GPL(cbe_cpufreq_has_pmi); 42 + 43 + /* 44 + * hardware specific functions 45 + */ 46 + 47 + int cbe_cpufreq_set_pmode_pmi(int cpu, unsigned int pmode) 48 + { 49 + int ret; 50 + pmi_message_t pmi_msg; 51 + #ifdef DEBUG 52 + long time; 53 + #endif 54 + pmi_msg.type = PMI_TYPE_FREQ_CHANGE; 55 + pmi_msg.data1 = cbe_cpu_to_node(cpu); 56 + pmi_msg.data2 = pmode; 57 + 58 + #ifdef DEBUG 59 + time = jiffies; 60 + #endif 61 + pmi_send_message(pmi_msg); 62 + 63 + #ifdef DEBUG 64 + time = jiffies - time; 65 + time = jiffies_to_msecs(time); 66 + pr_debug("had to wait %lu ms for a transition using " \ 67 + "PMI\n", time); 68 + #endif 69 + ret = pmi_msg.data2; 70 + pr_debug("PMI returned slow mode %d\n", ret); 71 + 72 + return ret; 73 + } 74 + EXPORT_SYMBOL_GPL(cbe_cpufreq_set_pmode_pmi); 75 + 76 + 77 + static void cbe_cpufreq_handle_pmi(pmi_message_t pmi_msg) 78 + { 79 + u8 node, slow_mode; 80 + 81 + BUG_ON(pmi_msg.type != PMI_TYPE_FREQ_CHANGE); 82 + 83 + node = pmi_msg.data1; 84 + slow_mode = pmi_msg.data2; 85 + 86 + pmi_slow_mode_limit[node] = slow_mode; 87 + 88 + pr_debug("cbe_handle_pmi: node: %d max_freq: %d\n", node, slow_mode); 89 + } 90 + 91 + static int pmi_notifier(struct notifier_block *nb, 92 + unsigned long event, void *data) 93 + { 94 + struct cpufreq_policy *policy = data; 95 + struct cpufreq_frequency_table *cbe_freqs; 96 + u8 node; 97 + 98 + cbe_freqs = cpufreq_frequency_get_table(policy->cpu); 99 + node = cbe_cpu_to_node(policy->cpu); 100 + 101 + pr_debug("got notified, event=%lu, node=%u\n", event, node); 102 + 103 + if (pmi_slow_mode_limit[node] != 0) { 104 + pr_debug("limiting node %d to slow mode %d\n", 105 + node, pmi_slow_mode_limit[node]); 106 + 107 + cpufreq_verify_within_limits(policy, 0, 108 + 109 + cbe_freqs[pmi_slow_mode_limit[node]].frequency); 110 + } 111 + 112 + return 0; 113 + } 114 + 115 + static struct notifier_block pmi_notifier_block = { 116 + .notifier_call = pmi_notifier, 117 + }; 118 + 119 + static struct pmi_handler cbe_pmi_handler = { 120 + .type = PMI_TYPE_FREQ_CHANGE, 121 + .handle_pmi_message = cbe_cpufreq_handle_pmi, 122 + }; 123 + 124 + 125 + 126 + static int __init cbe_cpufreq_pmi_init(void) 127 + { 128 + cbe_cpufreq_has_pmi = pmi_register_handler(&cbe_pmi_handler) == 0; 129 + 130 + if (!cbe_cpufreq_has_pmi) 131 + return -ENODEV; 132 + 133 + cpufreq_register_notifier(&pmi_notifier_block, CPUFREQ_POLICY_NOTIFIER); 134 + 135 + return 0; 136 + } 137 + 138 + static void __exit cbe_cpufreq_pmi_exit(void) 139 + { 140 + cpufreq_unregister_notifier(&pmi_notifier_block, CPUFREQ_POLICY_NOTIFIER); 141 + pmi_unregister_handler(&cbe_pmi_handler); 142 + } 143 + 144 + module_init(cbe_cpufreq_pmi_init); 145 + module_exit(cbe_cpufreq_pmi_exit); 146 + 147 + MODULE_LICENSE("GPL"); 148 + MODULE_AUTHOR("Christian Krafft <krafft@de.ibm.com>");
+7
arch/powerpc/platforms/cell/cbe_regs.c
··· 174 175 cpu_handle = of_get_property(np, "cpus", &len); 176 177 for (i=0; i<len; i++) 178 if (of_find_node_by_phandle(cpu_handle[i]) == of_get_cpu_node(cpu_id, NULL)) 179 return np;
··· 174 175 cpu_handle = of_get_property(np, "cpus", &len); 176 177 + /* 178 + * the CAB SLOF tree is non compliant, so we just assume 179 + * there is only one node 180 + */ 181 + if (WARN_ON_ONCE(!cpu_handle)) 182 + return np; 183 + 184 for (i=0; i<len; i++) 185 if (of_find_node_by_phandle(cpu_handle[i]) == of_get_cpu_node(cpu_id, NULL)) 186 return np;
+20 -5
arch/powerpc/platforms/cell/cbe_thermal.c
··· 292 /* 293 * initialize throttling with default values 294 */ 295 - static void __init init_default_values(void) 296 { 297 int cpu; 298 struct cbe_pmd_regs __iomem *pmd_regs; ··· 339 for_each_possible_cpu (cpu) { 340 pr_debug("processing cpu %d\n", cpu); 341 sysdev = get_cpu_sysdev(cpu); 342 pmd_regs = cbe_get_cpu_pmd_regs(sysdev->id); 343 344 out_be64(&pmd_regs->tm_str2, str2); 345 out_be64(&pmd_regs->tm_str1.val, str1.val); ··· 358 out_be64(&pmd_regs->tm_cr1.val, cr1.val); 359 out_be64(&pmd_regs->tm_cr2, cr2); 360 } 361 } 362 363 364 static int __init thermal_init(void) 365 { 366 - init_default_values(); 367 368 - spu_add_sysdev_attr_group(&spu_attribute_group); 369 - cpu_add_sysdev_attr_group(&ppe_attribute_group); 370 371 - return 0; 372 } 373 module_init(thermal_init); 374
··· 292 /* 293 * initialize throttling with default values 294 */ 295 + static int __init init_default_values(void) 296 { 297 int cpu; 298 struct cbe_pmd_regs __iomem *pmd_regs; ··· 339 for_each_possible_cpu (cpu) { 340 pr_debug("processing cpu %d\n", cpu); 341 sysdev = get_cpu_sysdev(cpu); 342 + 343 + if (!sysdev) { 344 + pr_info("invalid sysdev pointer for cbe_thermal\n"); 345 + return -EINVAL; 346 + } 347 + 348 pmd_regs = cbe_get_cpu_pmd_regs(sysdev->id); 349 + 350 + if (!pmd_regs) { 351 + pr_info("invalid CBE regs pointer for cbe_thermal\n"); 352 + return -EINVAL; 353 + } 354 355 out_be64(&pmd_regs->tm_str2, str2); 356 out_be64(&pmd_regs->tm_str1.val, str1.val); ··· 347 out_be64(&pmd_regs->tm_cr1.val, cr1.val); 348 out_be64(&pmd_regs->tm_cr2, cr2); 349 } 350 + 351 + return 0; 352 } 353 354 355 static int __init thermal_init(void) 356 { 357 + int rc = init_default_values(); 358 359 + if (rc == 0) { 360 + spu_add_sysdev_attr_group(&spu_attribute_group); 361 + cpu_add_sysdev_attr_group(&ppe_attribute_group); 362 + } 363 364 + return rc; 365 } 366 module_init(thermal_init); 367
+219 -80
arch/powerpc/platforms/cell/spu_base.c
··· 35 #include <asm/spu.h> 36 #include <asm/spu_priv1.h> 37 #include <asm/xmon.h> 38 39 const struct spu_management_ops *spu_management_ops; 40 EXPORT_SYMBOL_GPL(spu_management_ops); 41 42 const struct spu_priv1_ops *spu_priv1_ops; 43 - 44 - static struct list_head spu_list[MAX_NUMNODES]; 45 - static LIST_HEAD(spu_full_list); 46 - static DEFINE_MUTEX(spu_mutex); 47 - static DEFINE_SPINLOCK(spu_list_lock); 48 - 49 EXPORT_SYMBOL_GPL(spu_priv1_ops); 50 51 void spu_invalidate_slbs(struct spu *spu) 52 { ··· 84 struct spu *spu; 85 unsigned long flags; 86 87 - spin_lock_irqsave(&spu_list_lock, flags); 88 list_for_each_entry(spu, &spu_full_list, full_list) { 89 if (spu->mm == mm) 90 spu_invalidate_slbs(spu); 91 } 92 - spin_unlock_irqrestore(&spu_list_lock, flags); 93 } 94 95 /* The hack below stinks... try to do something better one of ··· 107 { 108 unsigned long flags; 109 110 - spin_lock_irqsave(&spu_list_lock, flags); 111 spu->mm = mm; 112 - spin_unlock_irqrestore(&spu_list_lock, flags); 113 if (mm) 114 mm_needs_global_tlbie(mm); 115 } ··· 409 free_irq(spu->irqs[2], spu); 410 } 411 412 - static void spu_init_channels(struct spu *spu) 413 { 414 static const struct { 415 unsigned channel; ··· 442 out_be64(&priv2->spu_chnlcnt_RW, count_list[i].count); 443 } 444 } 445 - 446 - struct spu *spu_alloc_node(int node) 447 - { 448 - struct spu *spu = NULL; 449 - 450 - mutex_lock(&spu_mutex); 451 - if (!list_empty(&spu_list[node])) { 452 - spu = list_entry(spu_list[node].next, struct spu, list); 453 - list_del_init(&spu->list); 454 - pr_debug("Got SPU %d %d\n", spu->number, spu->node); 455 - } 456 - mutex_unlock(&spu_mutex); 457 - 458 - if (spu) 459 - spu_init_channels(spu); 460 - return spu; 461 - } 462 - EXPORT_SYMBOL_GPL(spu_alloc_node); 463 - 464 - struct spu *spu_alloc(void) 465 - { 466 - struct spu *spu = NULL; 467 - int node; 468 - 469 - for (node = 0; node < MAX_NUMNODES; node++) { 470 - spu = spu_alloc_node(node); 471 - if (spu) 472 - break; 473 - } 474 - 475 - return spu; 476 - } 477 - 478 - void spu_free(struct spu *spu) 479 - { 480 - mutex_lock(&spu_mutex); 481 - list_add_tail(&spu->list, &spu_list[spu->node]); 482 - mutex_unlock(&spu_mutex); 483 - } 484 - EXPORT_SYMBOL_GPL(spu_free); 485 486 static int spu_shutdown(struct sys_device *sysdev) 487 { ··· 461 int spu_add_sysdev_attr(struct sysdev_attribute *attr) 462 { 463 struct spu *spu; 464 - mutex_lock(&spu_mutex); 465 466 list_for_each_entry(spu, &spu_full_list, full_list) 467 sysdev_create_file(&spu->sysdev, attr); 468 469 - mutex_unlock(&spu_mutex); 470 return 0; 471 } 472 EXPORT_SYMBOL_GPL(spu_add_sysdev_attr); ··· 474 int spu_add_sysdev_attr_group(struct attribute_group *attrs) 475 { 476 struct spu *spu; 477 - mutex_lock(&spu_mutex); 478 479 list_for_each_entry(spu, &spu_full_list, full_list) 480 sysfs_create_group(&spu->sysdev.kobj, attrs); 481 482 - mutex_unlock(&spu_mutex); 483 return 0; 484 } 485 EXPORT_SYMBOL_GPL(spu_add_sysdev_attr_group); ··· 488 void spu_remove_sysdev_attr(struct sysdev_attribute *attr) 489 { 490 struct spu *spu; 491 - mutex_lock(&spu_mutex); 492 493 list_for_each_entry(spu, &spu_full_list, full_list) 494 sysdev_remove_file(&spu->sysdev, attr); 495 - 496 - mutex_unlock(&spu_mutex); 497 } 498 EXPORT_SYMBOL_GPL(spu_remove_sysdev_attr); 499 500 void spu_remove_sysdev_attr_group(struct attribute_group *attrs) 501 { 502 struct spu *spu; 503 - mutex_lock(&spu_mutex); 504 505 list_for_each_entry(spu, &spu_full_list, full_list) 506 sysfs_remove_group(&spu->sysdev.kobj, attrs); 507 - 508 - mutex_unlock(&spu_mutex); 509 } 510 EXPORT_SYMBOL_GPL(spu_remove_sysdev_attr_group); 511 ··· 531 int ret; 532 static int number; 533 unsigned long flags; 534 535 ret = -ENOMEM; 536 spu = kzalloc(sizeof (*spu), GFP_KERNEL); 537 if (!spu) 538 goto out; 539 540 spin_lock_init(&spu->register_lock); 541 - mutex_lock(&spu_mutex); 542 spu->number = number++; 543 - mutex_unlock(&spu_mutex); 544 545 ret = spu_create_spu(spu, data); 546 ··· 560 if (ret) 561 goto out_free_irqs; 562 563 - mutex_lock(&spu_mutex); 564 - spin_lock_irqsave(&spu_list_lock, flags); 565 - list_add(&spu->list, &spu_list[spu->node]); 566 - list_add(&spu->full_list, &spu_full_list); 567 - spin_unlock_irqrestore(&spu_list_lock, flags); 568 - mutex_unlock(&spu_mutex); 569 570 - spu->stats.utilization_state = SPU_UTIL_IDLE; 571 - spu->stats.tstamp = jiffies; 572 573 goto out; 574 ··· 596 static unsigned long long spu_acct_time(struct spu *spu, 597 enum spu_utilization_state state) 598 { 599 unsigned long long time = spu->stats.times[state]; 600 601 - if (spu->stats.utilization_state == state) 602 - time += jiffies - spu->stats.tstamp; 603 604 - return jiffies_to_msecs(time); 605 } 606 607 ··· 619 620 return sprintf(buf, "%s %llu %llu %llu %llu " 621 "%llu %llu %llu %llu %llu %llu %llu %llu\n", 622 - spu_state_names[spu->stats.utilization_state], 623 spu_acct_time(spu, SPU_UTIL_USER), 624 spu_acct_time(spu, SPU_UTIL_SYSTEM), 625 spu_acct_time(spu, SPU_UTIL_IOWAIT), 626 - spu_acct_time(spu, SPU_UTIL_IDLE), 627 spu->stats.vol_ctx_switch, 628 spu->stats.invol_ctx_switch, 629 spu->stats.slb_flt, ··· 636 637 static SYSDEV_ATTR(stat, 0644, spu_stat_show, NULL); 638 639 static int __init init_spu_base(void) 640 { 641 int i, ret = 0; 642 643 - for (i = 0; i < MAX_NUMNODES; i++) 644 - INIT_LIST_HEAD(&spu_list[i]); 645 646 if (!spu_management_ops) 647 goto out; ··· 805 fb_append_extra_logo(&logo_spe_clut224, ret); 806 } 807 808 xmon_register_spus(&spu_full_list); 809 - 810 spu_add_sysdev_attr(&attr_stat); 811 812 return 0; 813 814 out_unregister_sysdev_class: 815 sysdev_class_unregister(&spu_sysdev_class); 816 out: 817 - 818 return ret; 819 } 820 module_init(init_spu_base);
··· 35 #include <asm/spu.h> 36 #include <asm/spu_priv1.h> 37 #include <asm/xmon.h> 38 + #include <asm/prom.h> 39 + #include "spu_priv1_mmio.h" 40 41 const struct spu_management_ops *spu_management_ops; 42 EXPORT_SYMBOL_GPL(spu_management_ops); 43 44 const struct spu_priv1_ops *spu_priv1_ops; 45 EXPORT_SYMBOL_GPL(spu_priv1_ops); 46 + 47 + struct cbe_spu_info cbe_spu_info[MAX_NUMNODES]; 48 + EXPORT_SYMBOL_GPL(cbe_spu_info); 49 + 50 + /* 51 + * Protects cbe_spu_info and spu->number. 52 + */ 53 + static DEFINE_SPINLOCK(spu_lock); 54 + 55 + /* 56 + * List of all spus in the system. 57 + * 58 + * This list is iterated by callers from irq context and callers that 59 + * want to sleep. Thus modifications need to be done with both 60 + * spu_full_list_lock and spu_full_list_mutex held, while iterating 61 + * through it requires either of these locks. 62 + * 63 + * In addition spu_full_list_lock protects all assignmens to 64 + * spu->mm. 65 + */ 66 + static LIST_HEAD(spu_full_list); 67 + static DEFINE_SPINLOCK(spu_full_list_lock); 68 + static DEFINE_MUTEX(spu_full_list_mutex); 69 70 void spu_invalidate_slbs(struct spu *spu) 71 { ··· 65 struct spu *spu; 66 unsigned long flags; 67 68 + spin_lock_irqsave(&spu_full_list_lock, flags); 69 list_for_each_entry(spu, &spu_full_list, full_list) { 70 if (spu->mm == mm) 71 spu_invalidate_slbs(spu); 72 } 73 + spin_unlock_irqrestore(&spu_full_list_lock, flags); 74 } 75 76 /* The hack below stinks... try to do something better one of ··· 88 { 89 unsigned long flags; 90 91 + spin_lock_irqsave(&spu_full_list_lock, flags); 92 spu->mm = mm; 93 + spin_unlock_irqrestore(&spu_full_list_lock, flags); 94 if (mm) 95 mm_needs_global_tlbie(mm); 96 } ··· 390 free_irq(spu->irqs[2], spu); 391 } 392 393 + void spu_init_channels(struct spu *spu) 394 { 395 static const struct { 396 unsigned channel; ··· 423 out_be64(&priv2->spu_chnlcnt_RW, count_list[i].count); 424 } 425 } 426 + EXPORT_SYMBOL_GPL(spu_init_channels); 427 428 static int spu_shutdown(struct sys_device *sysdev) 429 { ··· 481 int spu_add_sysdev_attr(struct sysdev_attribute *attr) 482 { 483 struct spu *spu; 484 485 + mutex_lock(&spu_full_list_mutex); 486 list_for_each_entry(spu, &spu_full_list, full_list) 487 sysdev_create_file(&spu->sysdev, attr); 488 + mutex_unlock(&spu_full_list_mutex); 489 490 return 0; 491 } 492 EXPORT_SYMBOL_GPL(spu_add_sysdev_attr); ··· 494 int spu_add_sysdev_attr_group(struct attribute_group *attrs) 495 { 496 struct spu *spu; 497 498 + mutex_lock(&spu_full_list_mutex); 499 list_for_each_entry(spu, &spu_full_list, full_list) 500 sysfs_create_group(&spu->sysdev.kobj, attrs); 501 + mutex_unlock(&spu_full_list_mutex); 502 503 return 0; 504 } 505 EXPORT_SYMBOL_GPL(spu_add_sysdev_attr_group); ··· 508 void spu_remove_sysdev_attr(struct sysdev_attribute *attr) 509 { 510 struct spu *spu; 511 512 + mutex_lock(&spu_full_list_mutex); 513 list_for_each_entry(spu, &spu_full_list, full_list) 514 sysdev_remove_file(&spu->sysdev, attr); 515 + mutex_unlock(&spu_full_list_mutex); 516 } 517 EXPORT_SYMBOL_GPL(spu_remove_sysdev_attr); 518 519 void spu_remove_sysdev_attr_group(struct attribute_group *attrs) 520 { 521 struct spu *spu; 522 523 + mutex_lock(&spu_full_list_mutex); 524 list_for_each_entry(spu, &spu_full_list, full_list) 525 sysfs_remove_group(&spu->sysdev.kobj, attrs); 526 + mutex_unlock(&spu_full_list_mutex); 527 } 528 EXPORT_SYMBOL_GPL(spu_remove_sysdev_attr_group); 529 ··· 553 int ret; 554 static int number; 555 unsigned long flags; 556 + struct timespec ts; 557 558 ret = -ENOMEM; 559 spu = kzalloc(sizeof (*spu), GFP_KERNEL); 560 if (!spu) 561 goto out; 562 563 + spu->alloc_state = SPU_FREE; 564 + 565 spin_lock_init(&spu->register_lock); 566 + spin_lock(&spu_lock); 567 spu->number = number++; 568 + spin_unlock(&spu_lock); 569 570 ret = spu_create_spu(spu, data); 571 ··· 579 if (ret) 580 goto out_free_irqs; 581 582 + mutex_lock(&cbe_spu_info[spu->node].list_mutex); 583 + list_add(&spu->cbe_list, &cbe_spu_info[spu->node].spus); 584 + cbe_spu_info[spu->node].n_spus++; 585 + mutex_unlock(&cbe_spu_info[spu->node].list_mutex); 586 587 + mutex_lock(&spu_full_list_mutex); 588 + spin_lock_irqsave(&spu_full_list_lock, flags); 589 + list_add(&spu->full_list, &spu_full_list); 590 + spin_unlock_irqrestore(&spu_full_list_lock, flags); 591 + mutex_unlock(&spu_full_list_mutex); 592 + 593 + spu->stats.util_state = SPU_UTIL_IDLE_LOADED; 594 + ktime_get_ts(&ts); 595 + spu->stats.tstamp = timespec_to_ns(&ts); 596 + 597 + INIT_LIST_HEAD(&spu->aff_list); 598 599 goto out; 600 ··· 608 static unsigned long long spu_acct_time(struct spu *spu, 609 enum spu_utilization_state state) 610 { 611 + struct timespec ts; 612 unsigned long long time = spu->stats.times[state]; 613 614 + /* 615 + * If the spu is idle or the context is stopped, utilization 616 + * statistics are not updated. Apply the time delta from the 617 + * last recorded state of the spu. 618 + */ 619 + if (spu->stats.util_state == state) { 620 + ktime_get_ts(&ts); 621 + time += timespec_to_ns(&ts) - spu->stats.tstamp; 622 + } 623 624 + return time / NSEC_PER_MSEC; 625 } 626 627 ··· 623 624 return sprintf(buf, "%s %llu %llu %llu %llu " 625 "%llu %llu %llu %llu %llu %llu %llu %llu\n", 626 + spu_state_names[spu->stats.util_state], 627 spu_acct_time(spu, SPU_UTIL_USER), 628 spu_acct_time(spu, SPU_UTIL_SYSTEM), 629 spu_acct_time(spu, SPU_UTIL_IOWAIT), 630 + spu_acct_time(spu, SPU_UTIL_IDLE_LOADED), 631 spu->stats.vol_ctx_switch, 632 spu->stats.invol_ctx_switch, 633 spu->stats.slb_flt, ··· 640 641 static SYSDEV_ATTR(stat, 0644, spu_stat_show, NULL); 642 643 + /* Hardcoded affinity idxs for QS20 */ 644 + #define SPES_PER_BE 8 645 + static int QS20_reg_idxs[SPES_PER_BE] = { 0, 2, 4, 6, 7, 5, 3, 1 }; 646 + static int QS20_reg_memory[SPES_PER_BE] = { 1, 1, 0, 0, 0, 0, 0, 0 }; 647 + 648 + static struct spu *spu_lookup_reg(int node, u32 reg) 649 + { 650 + struct spu *spu; 651 + 652 + list_for_each_entry(spu, &cbe_spu_info[node].spus, cbe_list) { 653 + if (*(u32 *)get_property(spu_devnode(spu), "reg", NULL) == reg) 654 + return spu; 655 + } 656 + return NULL; 657 + } 658 + 659 + static void init_aff_QS20_harcoded(void) 660 + { 661 + int node, i; 662 + struct spu *last_spu, *spu; 663 + u32 reg; 664 + 665 + for (node = 0; node < MAX_NUMNODES; node++) { 666 + last_spu = NULL; 667 + for (i = 0; i < SPES_PER_BE; i++) { 668 + reg = QS20_reg_idxs[i]; 669 + spu = spu_lookup_reg(node, reg); 670 + if (!spu) 671 + continue; 672 + spu->has_mem_affinity = QS20_reg_memory[reg]; 673 + if (last_spu) 674 + list_add_tail(&spu->aff_list, 675 + &last_spu->aff_list); 676 + last_spu = spu; 677 + } 678 + } 679 + } 680 + 681 + static int of_has_vicinity(void) 682 + { 683 + struct spu* spu; 684 + 685 + spu = list_entry(cbe_spu_info[0].spus.next, struct spu, cbe_list); 686 + return of_find_property(spu_devnode(spu), "vicinity", NULL) != NULL; 687 + } 688 + 689 + static struct spu *aff_devnode_spu(int cbe, struct device_node *dn) 690 + { 691 + struct spu *spu; 692 + 693 + list_for_each_entry(spu, &cbe_spu_info[cbe].spus, cbe_list) 694 + if (spu_devnode(spu) == dn) 695 + return spu; 696 + return NULL; 697 + } 698 + 699 + static struct spu * 700 + aff_node_next_to(int cbe, struct device_node *target, struct device_node *avoid) 701 + { 702 + struct spu *spu; 703 + const phandle *vic_handles; 704 + int lenp, i; 705 + 706 + list_for_each_entry(spu, &cbe_spu_info[cbe].spus, cbe_list) { 707 + if (spu_devnode(spu) == avoid) 708 + continue; 709 + vic_handles = get_property(spu_devnode(spu), "vicinity", &lenp); 710 + for (i=0; i < (lenp / sizeof(phandle)); i++) { 711 + if (vic_handles[i] == target->linux_phandle) 712 + return spu; 713 + } 714 + } 715 + return NULL; 716 + } 717 + 718 + static void init_aff_fw_vicinity_node(int cbe) 719 + { 720 + struct spu *spu, *last_spu; 721 + struct device_node *vic_dn, *last_spu_dn; 722 + phandle avoid_ph; 723 + const phandle *vic_handles; 724 + const char *name; 725 + int lenp, i, added, mem_aff; 726 + 727 + last_spu = list_entry(cbe_spu_info[cbe].spus.next, struct spu, cbe_list); 728 + avoid_ph = 0; 729 + for (added = 1; added < cbe_spu_info[cbe].n_spus; added++) { 730 + last_spu_dn = spu_devnode(last_spu); 731 + vic_handles = get_property(last_spu_dn, "vicinity", &lenp); 732 + 733 + for (i = 0; i < (lenp / sizeof(phandle)); i++) { 734 + if (vic_handles[i] == avoid_ph) 735 + continue; 736 + 737 + vic_dn = of_find_node_by_phandle(vic_handles[i]); 738 + if (!vic_dn) 739 + continue; 740 + 741 + name = get_property(vic_dn, "name", NULL); 742 + if (strcmp(name, "spe") == 0) { 743 + spu = aff_devnode_spu(cbe, vic_dn); 744 + avoid_ph = last_spu_dn->linux_phandle; 745 + } 746 + else { 747 + mem_aff = strcmp(name, "mic-tm") == 0; 748 + spu = aff_node_next_to(cbe, vic_dn, last_spu_dn); 749 + if (!spu) 750 + continue; 751 + if (mem_aff) { 752 + last_spu->has_mem_affinity = 1; 753 + spu->has_mem_affinity = 1; 754 + } 755 + avoid_ph = vic_dn->linux_phandle; 756 + } 757 + list_add_tail(&spu->aff_list, &last_spu->aff_list); 758 + last_spu = spu; 759 + break; 760 + } 761 + } 762 + } 763 + 764 + static void init_aff_fw_vicinity(void) 765 + { 766 + int cbe; 767 + 768 + /* sets has_mem_affinity for each spu, as long as the 769 + * spu->aff_list list, linking each spu to its neighbors 770 + */ 771 + for (cbe = 0; cbe < MAX_NUMNODES; cbe++) 772 + init_aff_fw_vicinity_node(cbe); 773 + } 774 + 775 static int __init init_spu_base(void) 776 { 777 int i, ret = 0; 778 779 + for (i = 0; i < MAX_NUMNODES; i++) { 780 + mutex_init(&cbe_spu_info[i].list_mutex); 781 + INIT_LIST_HEAD(&cbe_spu_info[i].spus); 782 + } 783 784 if (!spu_management_ops) 785 goto out; ··· 675 fb_append_extra_logo(&logo_spe_clut224, ret); 676 } 677 678 + mutex_lock(&spu_full_list_mutex); 679 xmon_register_spus(&spu_full_list); 680 + crash_register_spus(&spu_full_list); 681 + mutex_unlock(&spu_full_list_mutex); 682 spu_add_sysdev_attr(&attr_stat); 683 + 684 + if (of_has_vicinity()) { 685 + init_aff_fw_vicinity(); 686 + } else { 687 + long root = of_get_flat_dt_root(); 688 + if (of_flat_dt_is_compatible(root, "IBM,CPBW-1.0")) 689 + init_aff_QS20_harcoded(); 690 + } 691 692 return 0; 693 694 out_unregister_sysdev_class: 695 sysdev_class_unregister(&spu_sysdev_class); 696 out: 697 return ret; 698 } 699 module_init(init_spu_base);
+15 -2
arch/powerpc/platforms/cell/spu_syscalls.c
··· 34 * this file is not used and the syscalls directly enter the fs code */ 35 36 asmlinkage long sys_spu_create(const char __user *name, 37 - unsigned int flags, mode_t mode) 38 { 39 long ret; 40 struct module *owner = spufs_calls.owner; 41 42 ret = -ENOSYS; 43 if (owner && try_module_get(owner)) { 44 - ret = spufs_calls.create_thread(name, flags, mode); 45 module_put(owner); 46 } 47 return ret;
··· 34 * this file is not used and the syscalls directly enter the fs code */ 35 36 asmlinkage long sys_spu_create(const char __user *name, 37 + unsigned int flags, mode_t mode, int neighbor_fd) 38 { 39 long ret; 40 struct module *owner = spufs_calls.owner; 41 + struct file *neighbor; 42 + int fput_needed; 43 44 ret = -ENOSYS; 45 if (owner && try_module_get(owner)) { 46 + if (flags & SPU_CREATE_AFFINITY_SPU) { 47 + neighbor = fget_light(neighbor_fd, &fput_needed); 48 + if (neighbor) { 49 + ret = spufs_calls.create_thread(name, flags, 50 + mode, neighbor); 51 + fput_light(neighbor, fput_needed); 52 + } 53 + } 54 + else { 55 + ret = spufs_calls.create_thread(name, flags, 56 + mode, NULL); 57 + } 58 module_put(owner); 59 } 60 return ret;
+39 -3
arch/powerpc/platforms/cell/spufs/context.c
··· 22 23 #include <linux/fs.h> 24 #include <linux/mm.h> 25 #include <linux/slab.h> 26 #include <asm/atomic.h> 27 #include <asm/spu.h> ··· 56 ctx->ops = &spu_backing_ops; 57 ctx->owner = get_task_mm(current); 58 INIT_LIST_HEAD(&ctx->rq); 59 if (gang) 60 spu_gang_add_ctx(gang, ctx); 61 ctx->cpus_allowed = current->cpus_allowed; 62 spu_set_timeslice(ctx); 63 - ctx->stats.execution_state = SPUCTX_UTIL_USER; 64 - ctx->stats.tstamp = jiffies; 65 66 atomic_inc(&nr_spu_contexts); 67 goto out; ··· 82 spu_fini_csa(&ctx->csa); 83 if (ctx->gang) 84 spu_gang_remove_ctx(ctx->gang, ctx); 85 BUG_ON(!list_empty(&ctx->rq)); 86 atomic_dec(&nr_spu_contexts); 87 kfree(ctx); ··· 169 void spu_acquire_saved(struct spu_context *ctx) 170 { 171 spu_acquire(ctx); 172 - if (ctx->state != SPU_STATE_SAVED) 173 spu_deactivate(ctx); 174 }
··· 22 23 #include <linux/fs.h> 24 #include <linux/mm.h> 25 + #include <linux/module.h> 26 #include <linux/slab.h> 27 #include <asm/atomic.h> 28 #include <asm/spu.h> ··· 55 ctx->ops = &spu_backing_ops; 56 ctx->owner = get_task_mm(current); 57 INIT_LIST_HEAD(&ctx->rq); 58 + INIT_LIST_HEAD(&ctx->aff_list); 59 if (gang) 60 spu_gang_add_ctx(gang, ctx); 61 ctx->cpus_allowed = current->cpus_allowed; 62 spu_set_timeslice(ctx); 63 + ctx->stats.util_state = SPU_UTIL_IDLE_LOADED; 64 65 atomic_inc(&nr_spu_contexts); 66 goto out; ··· 81 spu_fini_csa(&ctx->csa); 82 if (ctx->gang) 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); 86 BUG_ON(!list_empty(&ctx->rq)); 87 atomic_dec(&nr_spu_contexts); 88 kfree(ctx); ··· 166 void spu_acquire_saved(struct spu_context *ctx) 167 { 168 spu_acquire(ctx); 169 + if (ctx->state != SPU_STATE_SAVED) { 170 + set_bit(SPU_SCHED_WAS_ACTIVE, &ctx->sched_flags); 171 spu_deactivate(ctx); 172 + } 173 } 174 + 175 + /** 176 + * spu_release_saved - unlock spu context and return it to the runqueue 177 + * @ctx: context to unlock 178 + */ 179 + void spu_release_saved(struct spu_context *ctx) 180 + { 181 + BUG_ON(ctx->state != SPU_STATE_SAVED); 182 + 183 + if (test_and_clear_bit(SPU_SCHED_WAS_ACTIVE, &ctx->sched_flags)) 184 + spu_activate(ctx, 0); 185 + 186 + spu_release(ctx); 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 +
+1 -1
arch/powerpc/platforms/cell/spufs/coredump.c
··· 226 spu_acquire_saved(ctx_info->ctx); 227 for (j = 0; j < spufs_coredump_num_notes; j++) 228 spufs_arch_write_note(ctx_info, j, file); 229 - spu_release(ctx_info->ctx); 230 list_del(&ctx_info->list); 231 kfree(ctx_info); 232 }
··· 226 spu_acquire_saved(ctx_info->ctx); 227 for (j = 0; j < spufs_coredump_num_notes; j++) 228 spufs_arch_write_note(ctx_info, j, file); 229 + spu_release_saved(ctx_info->ctx); 230 list_del(&ctx_info->list); 231 kfree(ctx_info); 232 }
+3 -5
arch/powerpc/platforms/cell/spufs/fault.c
··· 179 if (!(dsisr & (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED))) 180 return 0; 181 182 - spuctx_switch_state(ctx, SPUCTX_UTIL_IOWAIT); 183 184 pr_debug("ctx %p: ea %016lx, dsisr %016lx state %d\n", ctx, ea, 185 dsisr, ctx->state); 186 187 ctx->stats.hash_flt++; 188 - if (ctx->state == SPU_STATE_RUNNABLE) { 189 ctx->spu->stats.hash_flt++; 190 - spu_switch_state(ctx->spu, SPU_UTIL_IOWAIT); 191 - } 192 193 /* we must not hold the lock when entering spu_handle_mm_fault */ 194 spu_release(ctx); ··· 224 } else 225 spufs_handle_dma_error(ctx, ea, SPE_EVENT_SPE_DATA_STORAGE); 226 227 - spuctx_switch_state(ctx, SPUCTX_UTIL_SYSTEM); 228 return ret; 229 } 230 EXPORT_SYMBOL_GPL(spufs_handle_class1);
··· 179 if (!(dsisr & (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED))) 180 return 0; 181 182 + spuctx_switch_state(ctx, SPU_UTIL_IOWAIT); 183 184 pr_debug("ctx %p: ea %016lx, dsisr %016lx state %d\n", ctx, ea, 185 dsisr, ctx->state); 186 187 ctx->stats.hash_flt++; 188 + if (ctx->state == SPU_STATE_RUNNABLE) 189 ctx->spu->stats.hash_flt++; 190 191 /* we must not hold the lock when entering spu_handle_mm_fault */ 192 spu_release(ctx); ··· 226 } else 227 spufs_handle_dma_error(ctx, ea, SPE_EVENT_SPE_DATA_STORAGE); 228 229 + spuctx_switch_state(ctx, SPU_UTIL_SYSTEM); 230 return ret; 231 } 232 EXPORT_SYMBOL_GPL(spufs_handle_class1);
+67 -37
arch/powerpc/platforms/cell/spufs/file.c
··· 370 371 spu_acquire_saved(ctx); 372 ret = __spufs_regs_read(ctx, buffer, size, pos); 373 - spu_release(ctx); 374 return ret; 375 } 376 ··· 392 ret = copy_from_user(lscsa->gprs + *pos - size, 393 buffer, size) ? -EFAULT : size; 394 395 - spu_release(ctx); 396 return ret; 397 } 398 ··· 421 422 spu_acquire_saved(ctx); 423 ret = __spufs_fpcr_read(ctx, buffer, size, pos); 424 - spu_release(ctx); 425 return ret; 426 } 427 ··· 443 ret = copy_from_user((char *)&lscsa->fpcr + *pos - size, 444 buffer, size) ? -EFAULT : size; 445 446 - spu_release(ctx); 447 return ret; 448 } 449 ··· 868 869 spu_acquire_saved(ctx); 870 ret = __spufs_signal1_read(ctx, buf, len, pos); 871 - spu_release(ctx); 872 873 return ret; 874 } ··· 934 .mmap = spufs_signal1_mmap, 935 }; 936 937 static int spufs_signal2_open(struct inode *inode, struct file *file) 938 { 939 struct spufs_inode_info *i = SPUFS_I(inode); ··· 999 1000 spu_acquire_saved(ctx); 1001 ret = __spufs_signal2_read(ctx, buf, len, pos); 1002 - spu_release(ctx); 1003 1004 return ret; 1005 } ··· 1065 .open = spufs_signal2_open, 1066 .release = spufs_signal2_release, 1067 .read = spufs_signal2_read, 1068 .write = spufs_signal2_write, 1069 .mmap = spufs_signal2_mmap, 1070 }; ··· 1626 struct spu_lscsa *lscsa = ctx->csa.lscsa; 1627 spu_acquire_saved(ctx); 1628 lscsa->decr.slot[0] = (u32) val; 1629 - spu_release(ctx); 1630 } 1631 1632 static u64 __spufs_decr_get(void *data) ··· 1642 u64 ret; 1643 spu_acquire_saved(ctx); 1644 ret = __spufs_decr_get(data); 1645 - spu_release(ctx); 1646 return ret; 1647 } 1648 DEFINE_SIMPLE_ATTRIBUTE(spufs_decr_ops, spufs_decr_get, spufs_decr_set, ··· 1651 static void spufs_decr_status_set(void *data, u64 val) 1652 { 1653 struct spu_context *ctx = data; 1654 - struct spu_lscsa *lscsa = ctx->csa.lscsa; 1655 spu_acquire_saved(ctx); 1656 - lscsa->decr_status.slot[0] = (u32) val; 1657 - spu_release(ctx); 1658 } 1659 1660 static u64 __spufs_decr_status_get(void *data) 1661 { 1662 struct spu_context *ctx = data; 1663 - struct spu_lscsa *lscsa = ctx->csa.lscsa; 1664 - return lscsa->decr_status.slot[0]; 1665 } 1666 1667 static u64 spufs_decr_status_get(void *data) ··· 1674 u64 ret; 1675 spu_acquire_saved(ctx); 1676 ret = __spufs_decr_status_get(data); 1677 - spu_release(ctx); 1678 return ret; 1679 } 1680 DEFINE_SIMPLE_ATTRIBUTE(spufs_decr_status_ops, spufs_decr_status_get, ··· 1686 struct spu_lscsa *lscsa = ctx->csa.lscsa; 1687 spu_acquire_saved(ctx); 1688 lscsa->event_mask.slot[0] = (u32) val; 1689 - spu_release(ctx); 1690 } 1691 1692 static u64 __spufs_event_mask_get(void *data) ··· 1702 u64 ret; 1703 spu_acquire_saved(ctx); 1704 ret = __spufs_event_mask_get(data); 1705 - spu_release(ctx); 1706 return ret; 1707 } 1708 DEFINE_SIMPLE_ATTRIBUTE(spufs_event_mask_ops, spufs_event_mask_get, ··· 1726 1727 spu_acquire_saved(ctx); 1728 ret = __spufs_event_status_get(data); 1729 - spu_release(ctx); 1730 return ret; 1731 } 1732 DEFINE_SIMPLE_ATTRIBUTE(spufs_event_status_ops, spufs_event_status_get, ··· 1738 struct spu_lscsa *lscsa = ctx->csa.lscsa; 1739 spu_acquire_saved(ctx); 1740 lscsa->srr0.slot[0] = (u32) val; 1741 - spu_release(ctx); 1742 } 1743 1744 static u64 spufs_srr0_get(void *data) ··· 1748 u64 ret; 1749 spu_acquire_saved(ctx); 1750 ret = lscsa->srr0.slot[0]; 1751 - spu_release(ctx); 1752 return ret; 1753 } 1754 DEFINE_SIMPLE_ATTRIBUTE(spufs_srr0_ops, spufs_srr0_get, spufs_srr0_set, ··· 1804 1805 spu_acquire_saved(ctx); 1806 ret = __spufs_lslr_get(data); 1807 - spu_release(ctx); 1808 1809 return ret; 1810 } ··· 1868 spin_lock(&ctx->csa.register_lock); 1869 ret = __spufs_mbox_info_read(ctx, buf, len, pos); 1870 spin_unlock(&ctx->csa.register_lock); 1871 - spu_release(ctx); 1872 1873 return ret; 1874 } ··· 1906 spin_lock(&ctx->csa.register_lock); 1907 ret = __spufs_ibox_info_read(ctx, buf, len, pos); 1908 spin_unlock(&ctx->csa.register_lock); 1909 - spu_release(ctx); 1910 1911 return ret; 1912 } ··· 1947 spin_lock(&ctx->csa.register_lock); 1948 ret = __spufs_wbox_info_read(ctx, buf, len, pos); 1949 spin_unlock(&ctx->csa.register_lock); 1950 - spu_release(ctx); 1951 1952 return ret; 1953 } ··· 1997 spin_lock(&ctx->csa.register_lock); 1998 ret = __spufs_dma_info_read(ctx, buf, len, pos); 1999 spin_unlock(&ctx->csa.register_lock); 2000 - spu_release(ctx); 2001 2002 return ret; 2003 } ··· 2048 spin_lock(&ctx->csa.register_lock); 2049 ret = __spufs_proxydma_info_read(ctx, buf, len, pos); 2050 spin_unlock(&ctx->csa.register_lock); 2051 - spu_release(ctx); 2052 2053 return ret; 2054 } ··· 2083 }; 2084 2085 static unsigned long long spufs_acct_time(struct spu_context *ctx, 2086 - enum spuctx_execution_state state) 2087 { 2088 - unsigned long time = ctx->stats.times[state]; 2089 2090 - if (ctx->stats.execution_state == state) 2091 - time += jiffies - ctx->stats.tstamp; 2092 2093 - return jiffies_to_msecs(time); 2094 } 2095 2096 static unsigned long long spufs_slb_flts(struct spu_context *ctx) ··· 2137 spu_acquire(ctx); 2138 seq_printf(s, "%s %llu %llu %llu %llu " 2139 "%llu %llu %llu %llu %llu %llu %llu %llu\n", 2140 - ctx_state_names[ctx->stats.execution_state], 2141 - spufs_acct_time(ctx, SPUCTX_UTIL_USER), 2142 - spufs_acct_time(ctx, SPUCTX_UTIL_SYSTEM), 2143 - spufs_acct_time(ctx, SPUCTX_UTIL_IOWAIT), 2144 - spufs_acct_time(ctx, SPUCTX_UTIL_LOADED), 2145 ctx->stats.vol_ctx_switch, 2146 ctx->stats.invol_ctx_switch, 2147 spufs_slb_flts(ctx), ··· 2214 { "mbox_stat", &spufs_mbox_stat_fops, 0444, }, 2215 { "ibox_stat", &spufs_ibox_stat_fops, 0444, }, 2216 { "wbox_stat", &spufs_wbox_stat_fops, 0444, }, 2217 - { "signal1", &spufs_signal1_fops, 0666, }, 2218 - { "signal2", &spufs_signal2_fops, 0666, }, 2219 { "signal1_type", &spufs_signal1_type, 0666, }, 2220 { "signal2_type", &spufs_signal2_type, 0666, }, 2221 { "mss", &spufs_mss_fops, 0666, },
··· 370 371 spu_acquire_saved(ctx); 372 ret = __spufs_regs_read(ctx, buffer, size, pos); 373 + spu_release_saved(ctx); 374 return ret; 375 } 376 ··· 392 ret = copy_from_user(lscsa->gprs + *pos - size, 393 buffer, size) ? -EFAULT : size; 394 395 + spu_release_saved(ctx); 396 return ret; 397 } 398 ··· 421 422 spu_acquire_saved(ctx); 423 ret = __spufs_fpcr_read(ctx, buffer, size, pos); 424 + spu_release_saved(ctx); 425 return ret; 426 } 427 ··· 443 ret = copy_from_user((char *)&lscsa->fpcr + *pos - size, 444 buffer, size) ? -EFAULT : size; 445 446 + spu_release_saved(ctx); 447 return ret; 448 } 449 ··· 868 869 spu_acquire_saved(ctx); 870 ret = __spufs_signal1_read(ctx, buf, len, pos); 871 + spu_release_saved(ctx); 872 873 return ret; 874 } ··· 934 .mmap = spufs_signal1_mmap, 935 }; 936 937 + static const struct file_operations spufs_signal1_nosched_fops = { 938 + .open = spufs_signal1_open, 939 + .release = spufs_signal1_release, 940 + .write = spufs_signal1_write, 941 + .mmap = spufs_signal1_mmap, 942 + }; 943 + 944 static int spufs_signal2_open(struct inode *inode, struct file *file) 945 { 946 struct spufs_inode_info *i = SPUFS_I(inode); ··· 992 993 spu_acquire_saved(ctx); 994 ret = __spufs_signal2_read(ctx, buf, len, pos); 995 + spu_release_saved(ctx); 996 997 return ret; 998 } ··· 1058 .open = spufs_signal2_open, 1059 .release = spufs_signal2_release, 1060 .read = spufs_signal2_read, 1061 + .write = spufs_signal2_write, 1062 + .mmap = spufs_signal2_mmap, 1063 + }; 1064 + 1065 + static const struct file_operations spufs_signal2_nosched_fops = { 1066 + .open = spufs_signal2_open, 1067 + .release = spufs_signal2_release, 1068 .write = spufs_signal2_write, 1069 .mmap = spufs_signal2_mmap, 1070 }; ··· 1612 struct spu_lscsa *lscsa = ctx->csa.lscsa; 1613 spu_acquire_saved(ctx); 1614 lscsa->decr.slot[0] = (u32) val; 1615 + spu_release_saved(ctx); 1616 } 1617 1618 static u64 __spufs_decr_get(void *data) ··· 1628 u64 ret; 1629 spu_acquire_saved(ctx); 1630 ret = __spufs_decr_get(data); 1631 + spu_release_saved(ctx); 1632 return ret; 1633 } 1634 DEFINE_SIMPLE_ATTRIBUTE(spufs_decr_ops, spufs_decr_get, spufs_decr_set, ··· 1637 static void spufs_decr_status_set(void *data, u64 val) 1638 { 1639 struct spu_context *ctx = data; 1640 spu_acquire_saved(ctx); 1641 + if (val) 1642 + ctx->csa.priv2.mfc_control_RW |= MFC_CNTL_DECREMENTER_RUNNING; 1643 + else 1644 + ctx->csa.priv2.mfc_control_RW &= ~MFC_CNTL_DECREMENTER_RUNNING; 1645 + spu_release_saved(ctx); 1646 } 1647 1648 static u64 __spufs_decr_status_get(void *data) 1649 { 1650 struct spu_context *ctx = data; 1651 + if (ctx->csa.priv2.mfc_control_RW & MFC_CNTL_DECREMENTER_RUNNING) 1652 + return SPU_DECR_STATUS_RUNNING; 1653 + else 1654 + return 0; 1655 } 1656 1657 static u64 spufs_decr_status_get(void *data) ··· 1656 u64 ret; 1657 spu_acquire_saved(ctx); 1658 ret = __spufs_decr_status_get(data); 1659 + spu_release_saved(ctx); 1660 return ret; 1661 } 1662 DEFINE_SIMPLE_ATTRIBUTE(spufs_decr_status_ops, spufs_decr_status_get, ··· 1668 struct spu_lscsa *lscsa = ctx->csa.lscsa; 1669 spu_acquire_saved(ctx); 1670 lscsa->event_mask.slot[0] = (u32) val; 1671 + spu_release_saved(ctx); 1672 } 1673 1674 static u64 __spufs_event_mask_get(void *data) ··· 1684 u64 ret; 1685 spu_acquire_saved(ctx); 1686 ret = __spufs_event_mask_get(data); 1687 + spu_release_saved(ctx); 1688 return ret; 1689 } 1690 DEFINE_SIMPLE_ATTRIBUTE(spufs_event_mask_ops, spufs_event_mask_get, ··· 1708 1709 spu_acquire_saved(ctx); 1710 ret = __spufs_event_status_get(data); 1711 + spu_release_saved(ctx); 1712 return ret; 1713 } 1714 DEFINE_SIMPLE_ATTRIBUTE(spufs_event_status_ops, spufs_event_status_get, ··· 1720 struct spu_lscsa *lscsa = ctx->csa.lscsa; 1721 spu_acquire_saved(ctx); 1722 lscsa->srr0.slot[0] = (u32) val; 1723 + spu_release_saved(ctx); 1724 } 1725 1726 static u64 spufs_srr0_get(void *data) ··· 1730 u64 ret; 1731 spu_acquire_saved(ctx); 1732 ret = lscsa->srr0.slot[0]; 1733 + spu_release_saved(ctx); 1734 return ret; 1735 } 1736 DEFINE_SIMPLE_ATTRIBUTE(spufs_srr0_ops, spufs_srr0_get, spufs_srr0_set, ··· 1786 1787 spu_acquire_saved(ctx); 1788 ret = __spufs_lslr_get(data); 1789 + spu_release_saved(ctx); 1790 1791 return ret; 1792 } ··· 1850 spin_lock(&ctx->csa.register_lock); 1851 ret = __spufs_mbox_info_read(ctx, buf, len, pos); 1852 spin_unlock(&ctx->csa.register_lock); 1853 + spu_release_saved(ctx); 1854 1855 return ret; 1856 } ··· 1888 spin_lock(&ctx->csa.register_lock); 1889 ret = __spufs_ibox_info_read(ctx, buf, len, pos); 1890 spin_unlock(&ctx->csa.register_lock); 1891 + spu_release_saved(ctx); 1892 1893 return ret; 1894 } ··· 1929 spin_lock(&ctx->csa.register_lock); 1930 ret = __spufs_wbox_info_read(ctx, buf, len, pos); 1931 spin_unlock(&ctx->csa.register_lock); 1932 + spu_release_saved(ctx); 1933 1934 return ret; 1935 } ··· 1979 spin_lock(&ctx->csa.register_lock); 1980 ret = __spufs_dma_info_read(ctx, buf, len, pos); 1981 spin_unlock(&ctx->csa.register_lock); 1982 + spu_release_saved(ctx); 1983 1984 return ret; 1985 } ··· 2030 spin_lock(&ctx->csa.register_lock); 2031 ret = __spufs_proxydma_info_read(ctx, buf, len, pos); 2032 spin_unlock(&ctx->csa.register_lock); 2033 + spu_release_saved(ctx); 2034 2035 return ret; 2036 } ··· 2065 }; 2066 2067 static unsigned long long spufs_acct_time(struct spu_context *ctx, 2068 + enum spu_utilization_state state) 2069 { 2070 + struct timespec ts; 2071 + unsigned long long time = ctx->stats.times[state]; 2072 2073 + /* 2074 + * In general, utilization statistics are updated by the controlling 2075 + * thread as the spu context moves through various well defined 2076 + * state transitions, but if the context is lazily loaded its 2077 + * utilization statistics are not updated as the controlling thread 2078 + * is not tightly coupled with the execution of the spu context. We 2079 + * calculate and apply the time delta from the last recorded state 2080 + * of the spu context. 2081 + */ 2082 + if (ctx->spu && ctx->stats.util_state == state) { 2083 + ktime_get_ts(&ts); 2084 + time += timespec_to_ns(&ts) - ctx->stats.tstamp; 2085 + } 2086 2087 + return time / NSEC_PER_MSEC; 2088 } 2089 2090 static unsigned long long spufs_slb_flts(struct spu_context *ctx) ··· 2107 spu_acquire(ctx); 2108 seq_printf(s, "%s %llu %llu %llu %llu " 2109 "%llu %llu %llu %llu %llu %llu %llu %llu\n", 2110 + ctx_state_names[ctx->stats.util_state], 2111 + spufs_acct_time(ctx, SPU_UTIL_USER), 2112 + spufs_acct_time(ctx, SPU_UTIL_SYSTEM), 2113 + spufs_acct_time(ctx, SPU_UTIL_IOWAIT), 2114 + spufs_acct_time(ctx, SPU_UTIL_IDLE_LOADED), 2115 ctx->stats.vol_ctx_switch, 2116 ctx->stats.invol_ctx_switch, 2117 spufs_slb_flts(ctx), ··· 2184 { "mbox_stat", &spufs_mbox_stat_fops, 0444, }, 2185 { "ibox_stat", &spufs_ibox_stat_fops, 0444, }, 2186 { "wbox_stat", &spufs_wbox_stat_fops, 0444, }, 2187 + { "signal1", &spufs_signal1_nosched_fops, 0222, }, 2188 + { "signal2", &spufs_signal2_nosched_fops, 0222, }, 2189 { "signal1_type", &spufs_signal1_type, 0666, }, 2190 { "signal2_type", &spufs_signal2_type, 0666, }, 2191 { "mss", &spufs_mss_fops, 0666, },
+6
arch/powerpc/platforms/cell/spufs/gang.c
··· 35 36 kref_init(&gang->kref); 37 mutex_init(&gang->mutex); 38 INIT_LIST_HEAD(&gang->list); 39 40 out: 41 return gang; ··· 75 { 76 mutex_lock(&gang->mutex); 77 WARN_ON(ctx->gang != gang); 78 list_del_init(&ctx->gang_list); 79 gang->contexts--; 80 mutex_unlock(&gang->mutex);
··· 35 36 kref_init(&gang->kref); 37 mutex_init(&gang->mutex); 38 + mutex_init(&gang->aff_mutex); 39 INIT_LIST_HEAD(&gang->list); 40 + INIT_LIST_HEAD(&gang->aff_list_head); 41 42 out: 43 return gang; ··· 73 { 74 mutex_lock(&gang->mutex); 75 WARN_ON(ctx->gang != gang); 76 + if (!list_empty(&ctx->aff_list)) { 77 + list_del_init(&ctx->aff_list); 78 + gang->aff_flags &= ~AFF_OFFSETS_SET; 79 + } 80 list_del_init(&ctx->gang_list); 81 gang->contexts--; 82 mutex_unlock(&gang->mutex);
+126 -6
arch/powerpc/platforms/cell/spufs/inode.c
··· 316 return ret; 317 } 318 319 - static int spufs_create_context(struct inode *inode, 320 - struct dentry *dentry, 321 - struct vfsmount *mnt, int flags, int mode) 322 { 323 int ret; 324 325 ret = -EPERM; 326 if ((flags & SPU_CREATE_NOSCHED) && ··· 432 if ((flags & SPU_CREATE_ISOLATE) && !isolated_loader) 433 goto out_unlock; 434 435 ret = spufs_mkdir(inode, dentry, flags, mode & S_IRWXUGO); 436 if (ret) 437 - goto out_unlock; 438 439 /* 440 * get references for dget and mntget, will be released ··· 468 goto out; 469 } 470 471 out_unlock: 472 mutex_unlock(&inode->i_mutex); 473 out: ··· 569 570 static struct file_system_type spufs_type; 571 572 - long spufs_create(struct nameidata *nd, unsigned int flags, mode_t mode) 573 { 574 struct dentry *dentry; 575 int ret; ··· 607 dentry, nd->mnt, mode); 608 else 609 return spufs_create_context(nd->dentry->d_inode, 610 - dentry, nd->mnt, flags, mode); 611 612 out_dput: 613 dput(dentry);
··· 316 return ret; 317 } 318 319 + static struct spu_context * 320 + spufs_assert_affinity(unsigned int flags, struct spu_gang *gang, 321 + struct file *filp) 322 + { 323 + struct spu_context *tmp, *neighbor; 324 + int count, node; 325 + int aff_supp; 326 + 327 + aff_supp = !list_empty(&(list_entry(cbe_spu_info[0].spus.next, 328 + struct spu, cbe_list))->aff_list); 329 + 330 + if (!aff_supp) 331 + return ERR_PTR(-EINVAL); 332 + 333 + if (flags & SPU_CREATE_GANG) 334 + return ERR_PTR(-EINVAL); 335 + 336 + if (flags & SPU_CREATE_AFFINITY_MEM && 337 + gang->aff_ref_ctx && 338 + gang->aff_ref_ctx->flags & SPU_CREATE_AFFINITY_MEM) 339 + return ERR_PTR(-EEXIST); 340 + 341 + if (gang->aff_flags & AFF_MERGED) 342 + return ERR_PTR(-EBUSY); 343 + 344 + neighbor = NULL; 345 + if (flags & SPU_CREATE_AFFINITY_SPU) { 346 + if (!filp || filp->f_op != &spufs_context_fops) 347 + return ERR_PTR(-EINVAL); 348 + 349 + neighbor = get_spu_context( 350 + SPUFS_I(filp->f_dentry->d_inode)->i_ctx); 351 + 352 + if (!list_empty(&neighbor->aff_list) && !(neighbor->aff_head) && 353 + !list_is_last(&neighbor->aff_list, &gang->aff_list_head) && 354 + !list_entry(neighbor->aff_list.next, struct spu_context, 355 + aff_list)->aff_head) 356 + return ERR_PTR(-EEXIST); 357 + 358 + if (gang != neighbor->gang) 359 + return ERR_PTR(-EINVAL); 360 + 361 + count = 1; 362 + list_for_each_entry(tmp, &gang->aff_list_head, aff_list) 363 + count++; 364 + if (list_empty(&neighbor->aff_list)) 365 + count++; 366 + 367 + for (node = 0; node < MAX_NUMNODES; node++) { 368 + if ((cbe_spu_info[node].n_spus - atomic_read( 369 + &cbe_spu_info[node].reserved_spus)) >= count) 370 + break; 371 + } 372 + 373 + if (node == MAX_NUMNODES) 374 + return ERR_PTR(-EEXIST); 375 + } 376 + 377 + return neighbor; 378 + } 379 + 380 + static void 381 + spufs_set_affinity(unsigned int flags, struct spu_context *ctx, 382 + struct spu_context *neighbor) 383 + { 384 + if (flags & SPU_CREATE_AFFINITY_MEM) 385 + ctx->gang->aff_ref_ctx = ctx; 386 + 387 + if (flags & SPU_CREATE_AFFINITY_SPU) { 388 + if (list_empty(&neighbor->aff_list)) { 389 + list_add_tail(&neighbor->aff_list, 390 + &ctx->gang->aff_list_head); 391 + neighbor->aff_head = 1; 392 + } 393 + 394 + if (list_is_last(&neighbor->aff_list, &ctx->gang->aff_list_head) 395 + || list_entry(neighbor->aff_list.next, struct spu_context, 396 + aff_list)->aff_head) { 397 + list_add(&ctx->aff_list, &neighbor->aff_list); 398 + } else { 399 + list_add_tail(&ctx->aff_list, &neighbor->aff_list); 400 + if (neighbor->aff_head) { 401 + neighbor->aff_head = 0; 402 + ctx->aff_head = 1; 403 + } 404 + } 405 + 406 + if (!ctx->gang->aff_ref_ctx) 407 + ctx->gang->aff_ref_ctx = ctx; 408 + } 409 + } 410 + 411 + static int 412 + spufs_create_context(struct inode *inode, struct dentry *dentry, 413 + struct vfsmount *mnt, int flags, int mode, 414 + struct file *aff_filp) 415 { 416 int ret; 417 + int affinity; 418 + struct spu_gang *gang; 419 + struct spu_context *neighbor; 420 421 ret = -EPERM; 422 if ((flags & SPU_CREATE_NOSCHED) && ··· 336 if ((flags & SPU_CREATE_ISOLATE) && !isolated_loader) 337 goto out_unlock; 338 339 + gang = NULL; 340 + neighbor = NULL; 341 + affinity = flags & (SPU_CREATE_AFFINITY_MEM | SPU_CREATE_AFFINITY_SPU); 342 + if (affinity) { 343 + gang = SPUFS_I(inode)->i_gang; 344 + ret = -EINVAL; 345 + if (!gang) 346 + goto out_unlock; 347 + mutex_lock(&gang->aff_mutex); 348 + neighbor = spufs_assert_affinity(flags, gang, aff_filp); 349 + if (IS_ERR(neighbor)) { 350 + ret = PTR_ERR(neighbor); 351 + goto out_aff_unlock; 352 + } 353 + } 354 + 355 ret = spufs_mkdir(inode, dentry, flags, mode & S_IRWXUGO); 356 if (ret) 357 + goto out_aff_unlock; 358 + 359 + if (affinity) 360 + spufs_set_affinity(flags, SPUFS_I(dentry->d_inode)->i_ctx, 361 + neighbor); 362 363 /* 364 * get references for dget and mntget, will be released ··· 352 goto out; 353 } 354 355 + out_aff_unlock: 356 + if (affinity) 357 + mutex_unlock(&gang->aff_mutex); 358 out_unlock: 359 mutex_unlock(&inode->i_mutex); 360 out: ··· 450 451 static struct file_system_type spufs_type; 452 453 + long spufs_create(struct nameidata *nd, unsigned int flags, mode_t mode, 454 + struct file *filp) 455 { 456 struct dentry *dentry; 457 int ret; ··· 487 dentry, nd->mnt, mode); 488 else 489 return spufs_create_context(nd->dentry->d_inode, 490 + dentry, nd->mnt, flags, mode, filp); 491 492 out_dput: 493 dput(dentry);
+28 -8
arch/powerpc/platforms/cell/spufs/run.c
··· 18 wake_up_all(&ctx->stop_wq); 19 } 20 21 - static inline int spu_stopped(struct spu_context *ctx, u32 * stat) 22 { 23 struct spu *spu; 24 u64 pte_fault; 25 26 *stat = ctx->ops->status_read(ctx); 27 - if (ctx->state != SPU_STATE_RUNNABLE) 28 - return 1; 29 spu = ctx->spu; 30 pte_fault = spu->dsisr & 31 (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED); 32 return (!(*stat & SPU_STATUS_RUNNING) || pte_fault || spu->class_0_pending) ? ··· 126 return ret; 127 } 128 129 - static int spu_run_init(struct spu_context *ctx, u32 * npc) 130 { 131 if (ctx->flags & SPU_CREATE_ISOLATE) { 132 unsigned long runcntl; 133 ··· 155 ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_RUNNABLE); 156 } 157 158 return 0; 159 } 160 161 - static int spu_run_fini(struct spu_context *ctx, u32 * npc, 162 - u32 * status) 163 { 164 int ret = 0; 165 166 *status = ctx->ops->status_read(ctx); 167 *npc = ctx->ops->npc_read(ctx); 168 spu_release(ctx); 169 170 if (signal_pending(current)) ··· 297 return ret; 298 } 299 300 - long spufs_run_spu(struct file *file, struct spu_context *ctx, 301 - u32 *npc, u32 *event) 302 { 303 int ret; 304 u32 status; 305 306 if (mutex_lock_interruptible(&ctx->run_mutex)) ··· 336 ret = spufs_wait(ctx->stop_wq, spu_stopped(ctx, &status)); 337 if (unlikely(ret)) 338 break; 339 if ((status & SPU_STATUS_STOPPED_BY_STOP) && 340 (status >> SPU_STOP_STATUS_SHIFT == 0x2104)) { 341 ret = spu_process_callback(ctx); ··· 374 (((status >> SPU_STOP_STATUS_SHIFT) & 0x3f00) == 0x2100) && 375 (ctx->state == SPU_STATE_RUNNABLE)) 376 ctx->stats.libassist++; 377 378 ctx->ops->master_stop(ctx); 379 ret = spu_run_fini(ctx, npc, &status);
··· 18 wake_up_all(&ctx->stop_wq); 19 } 20 21 + static inline int spu_stopped(struct spu_context *ctx, u32 *stat) 22 { 23 struct spu *spu; 24 u64 pte_fault; 25 26 *stat = ctx->ops->status_read(ctx); 27 + 28 spu = ctx->spu; 29 + if (ctx->state != SPU_STATE_RUNNABLE || 30 + test_bit(SPU_SCHED_NOTIFY_ACTIVE, &ctx->sched_flags)) 31 + return 1; 32 pte_fault = spu->dsisr & 33 (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED); 34 return (!(*stat & SPU_STATUS_RUNNING) || pte_fault || spu->class_0_pending) ? ··· 124 return ret; 125 } 126 127 + static int spu_run_init(struct spu_context *ctx, u32 *npc) 128 { 129 + spuctx_switch_state(ctx, SPU_UTIL_SYSTEM); 130 + 131 if (ctx->flags & SPU_CREATE_ISOLATE) { 132 unsigned long runcntl; 133 ··· 151 ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_RUNNABLE); 152 } 153 154 + spuctx_switch_state(ctx, SPU_UTIL_USER); 155 + 156 return 0; 157 } 158 159 + static int spu_run_fini(struct spu_context *ctx, u32 *npc, 160 + u32 *status) 161 { 162 int ret = 0; 163 164 *status = ctx->ops->status_read(ctx); 165 *npc = ctx->ops->npc_read(ctx); 166 + 167 + spuctx_switch_state(ctx, SPU_UTIL_IDLE_LOADED); 168 spu_release(ctx); 169 170 if (signal_pending(current)) ··· 289 return ret; 290 } 291 292 + long spufs_run_spu(struct spu_context *ctx, u32 *npc, u32 *event) 293 { 294 int ret; 295 + struct spu *spu; 296 u32 status; 297 298 if (mutex_lock_interruptible(&ctx->run_mutex)) ··· 328 ret = spufs_wait(ctx->stop_wq, spu_stopped(ctx, &status)); 329 if (unlikely(ret)) 330 break; 331 + spu = ctx->spu; 332 + if (unlikely(test_and_clear_bit(SPU_SCHED_NOTIFY_ACTIVE, 333 + &ctx->sched_flags))) { 334 + if (!(status & SPU_STATUS_STOPPED_BY_STOP)) { 335 + spu_switch_notify(spu, ctx); 336 + continue; 337 + } 338 + } 339 + 340 + spuctx_switch_state(ctx, SPU_UTIL_SYSTEM); 341 + 342 if ((status & SPU_STATUS_STOPPED_BY_STOP) && 343 (status >> SPU_STOP_STATUS_SHIFT == 0x2104)) { 344 ret = spu_process_callback(ctx); ··· 355 (((status >> SPU_STOP_STATUS_SHIFT) & 0x3f00) == 0x2100) && 356 (ctx->state == SPU_STATE_RUNNABLE)) 357 ctx->stats.libassist++; 358 + 359 360 ctx->ops->master_stop(ctx); 361 ret = spu_run_fini(ctx, npc, &status);
+277 -104
arch/powerpc/platforms/cell/spufs/sched.c
··· 51 DECLARE_BITMAP(bitmap, MAX_PRIO); 52 struct list_head runq[MAX_PRIO]; 53 spinlock_t runq_lock; 54 - struct list_head active_list[MAX_NUMNODES]; 55 - struct mutex active_mutex[MAX_NUMNODES]; 56 - int nr_active[MAX_NUMNODES]; 57 int nr_waiting; 58 }; 59 ··· 124 ctx->policy = current->policy; 125 126 /* 127 - * A lot of places that don't hold active_mutex poke into 128 * cpus_allowed, including grab_runnable_context which 129 * already holds the runq_lock. So abuse runq_lock 130 * to protect this field aswell. ··· 138 { 139 int node = ctx->spu->node; 140 141 - mutex_lock(&spu_prio->active_mutex[node]); 142 __spu_update_sched_info(ctx); 143 - mutex_unlock(&spu_prio->active_mutex[node]); 144 } 145 146 static int __node_allowed(struct spu_context *ctx, int node) ··· 166 return rval; 167 } 168 169 - /** 170 - * spu_add_to_active_list - add spu to active list 171 - * @spu: spu to add to the active list 172 - */ 173 - static void spu_add_to_active_list(struct spu *spu) 174 - { 175 - int node = spu->node; 176 - 177 - mutex_lock(&spu_prio->active_mutex[node]); 178 - spu_prio->nr_active[node]++; 179 - list_add_tail(&spu->list, &spu_prio->active_list[node]); 180 - mutex_unlock(&spu_prio->active_mutex[node]); 181 - } 182 - 183 - static void __spu_remove_from_active_list(struct spu *spu) 184 - { 185 - list_del_init(&spu->list); 186 - spu_prio->nr_active[spu->node]--; 187 - } 188 - 189 - /** 190 - * spu_remove_from_active_list - remove spu from active list 191 - * @spu: spu to remove from the active list 192 - */ 193 - static void spu_remove_from_active_list(struct spu *spu) 194 - { 195 - int node = spu->node; 196 - 197 - mutex_lock(&spu_prio->active_mutex[node]); 198 - __spu_remove_from_active_list(spu); 199 - mutex_unlock(&spu_prio->active_mutex[node]); 200 - } 201 - 202 static BLOCKING_NOTIFIER_HEAD(spu_switch_notifier); 203 204 - static void spu_switch_notify(struct spu *spu, struct spu_context *ctx) 205 { 206 blocking_notifier_call_chain(&spu_switch_notifier, 207 ctx ? ctx->object_id : 0, spu); 208 } 209 210 int spu_switch_event_register(struct notifier_block * n) 211 { 212 - return blocking_notifier_chain_register(&spu_switch_notifier, n); 213 } 214 215 int spu_switch_event_unregister(struct notifier_block * n) 216 { 217 return blocking_notifier_chain_unregister(&spu_switch_notifier, n); 218 } 219 220 /** 221 * spu_bind_context - bind spu context to physical spu ··· 226 { 227 pr_debug("%s: pid=%d SPU=%d NODE=%d\n", __FUNCTION__, current->pid, 228 spu->number, spu->node); 229 230 ctx->stats.slb_flt_base = spu->stats.slb_flt; 231 ctx->stats.class2_intr_base = spu->stats.class2_intr; ··· 241 ctx->spu = spu; 242 ctx->ops = &spu_hw_ops; 243 spu->pid = current->pid; 244 spu_associate_mm(spu, ctx->owner); 245 spu->ibox_callback = spufs_ibox_callback; 246 spu->wbox_callback = spufs_wbox_callback; ··· 255 spu_cpu_affinity_set(spu, raw_smp_processor_id()); 256 spu_switch_notify(spu, ctx); 257 ctx->state = SPU_STATE_RUNNABLE; 258 - spu_switch_state(spu, SPU_UTIL_SYSTEM); 259 } 260 261 /** ··· 413 { 414 pr_debug("%s: unbind pid=%d SPU=%d NODE=%d\n", __FUNCTION__, 415 spu->pid, spu->number, spu->node); 416 417 - spu_switch_state(spu, SPU_UTIL_IDLE); 418 - 419 spu_switch_notify(spu, NULL); 420 spu_unmap_mappings(ctx); 421 spu_save(&ctx->csa, spu); ··· 432 spu->dma_callback = NULL; 433 spu_associate_mm(spu, NULL); 434 spu->pid = 0; 435 ctx->ops = &spu_backing_ops; 436 - ctx->spu = NULL; 437 spu->flags = 0; 438 spu->ctx = NULL; 439 ··· 441 (spu->stats.slb_flt - ctx->stats.slb_flt_base); 442 ctx->stats.class2_intr += 443 (spu->stats.class2_intr - ctx->stats.class2_intr_base); 444 } 445 446 /** ··· 510 511 static struct spu *spu_get_idle(struct spu_context *ctx) 512 { 513 - struct spu *spu = NULL; 514 - int node = cpu_to_node(raw_smp_processor_id()); 515 - int n; 516 517 for (n = 0; n < MAX_NUMNODES; n++, node++) { 518 node = (node < MAX_NUMNODES) ? node : 0; 519 if (!node_allowed(ctx, node)) 520 continue; 521 - spu = spu_alloc_node(node); 522 - if (spu) 523 - break; 524 } 525 return spu; 526 } 527 ··· 574 if (!node_allowed(ctx, node)) 575 continue; 576 577 - mutex_lock(&spu_prio->active_mutex[node]); 578 - list_for_each_entry(spu, &spu_prio->active_list[node], list) { 579 struct spu_context *tmp = spu->ctx; 580 581 if (tmp->prio > ctx->prio && 582 (!victim || tmp->prio > victim->prio)) 583 victim = spu->ctx; 584 } 585 - mutex_unlock(&spu_prio->active_mutex[node]); 586 587 if (victim) { 588 /* ··· 607 victim = NULL; 608 goto restart; 609 } 610 - spu_remove_from_active_list(spu); 611 spu_unbind_context(spu, victim); 612 victim->stats.invol_ctx_switch++; 613 spu->stats.invol_ctx_switch++; ··· 640 */ 641 int spu_activate(struct spu_context *ctx, unsigned long flags) 642 { 643 - spuctx_switch_state(ctx, SPUCTX_UTIL_SYSTEM); 644 - 645 do { 646 struct spu *spu; 647 ··· 660 if (!spu && rt_prio(ctx->prio)) 661 spu = find_victim(ctx); 662 if (spu) { 663 spu_bind_context(spu, ctx); 664 - spu_add_to_active_list(spu); 665 return 0; 666 } 667 ··· 687 int best; 688 689 spin_lock(&spu_prio->runq_lock); 690 - best = sched_find_first_bit(spu_prio->bitmap); 691 while (best < prio) { 692 struct list_head *rq = &spu_prio->runq[best]; 693 ··· 714 if (spu) { 715 new = grab_runnable_context(max_prio, spu->node); 716 if (new || force) { 717 - spu_remove_from_active_list(spu); 718 spu_unbind_context(spu, ctx); 719 ctx->stats.vol_ctx_switch++; 720 spu->stats.vol_ctx_switch++; 721 - spu_free(spu); 722 if (new) 723 wake_up(&new->stop_wq); 724 } ··· 743 */ 744 void spu_deactivate(struct spu_context *ctx) 745 { 746 - /* 747 - * We must never reach this for a nosched context, 748 - * but handle the case gracefull instead of panicing. 749 - */ 750 - if (ctx->flags & SPU_CREATE_NOSCHED) { 751 - WARN_ON(1); 752 - return; 753 - } 754 - 755 __spu_deactivate(ctx, 1, MAX_PRIO); 756 - spuctx_switch_state(ctx, SPUCTX_UTIL_USER); 757 } 758 759 /** 760 - * spu_yield - yield a physical spu if others are waiting 761 * @ctx: spu context to yield 762 * 763 * Check if there is a higher priority context waiting and if yes ··· 758 { 759 if (!(ctx->flags & SPU_CREATE_NOSCHED)) { 760 mutex_lock(&ctx->state_mutex); 761 - if (__spu_deactivate(ctx, 0, MAX_PRIO)) 762 - spuctx_switch_state(ctx, SPUCTX_UTIL_USER); 763 - else { 764 - spuctx_switch_state(ctx, SPUCTX_UTIL_LOADED); 765 - spu_switch_state(ctx->spu, SPU_UTIL_USER); 766 - } 767 mutex_unlock(&ctx->state_mutex); 768 } 769 } 770 771 - static void spusched_tick(struct spu_context *ctx) 772 { 773 if (ctx->flags & SPU_CREATE_NOSCHED) 774 return; ··· 774 return; 775 776 /* 777 - * Unfortunately active_mutex ranks outside of state_mutex, so 778 * we have to trylock here. If we fail give the context another 779 * tick and try again. 780 */ ··· 784 785 new = grab_runnable_context(ctx->prio + 1, spu->node); 786 if (new) { 787 - 788 - __spu_remove_from_active_list(spu); 789 spu_unbind_context(spu, ctx); 790 ctx->stats.invol_ctx_switch++; 791 spu->stats.invol_ctx_switch++; 792 - spu_free(spu); 793 wake_up(&new->stop_wq); 794 /* 795 * We need to break out of the wait loop in ··· 809 * 810 * Return the number of tasks currently running or waiting to run. 811 * 812 - * Note that we don't take runq_lock / active_mutex here. Reading 813 * a single 32bit value is atomic on powerpc, and we don't care 814 * about memory ordering issues here. 815 */ ··· 818 int nr_active = 0, node; 819 820 for (node = 0; node < MAX_NUMNODES; node++) 821 - nr_active += spu_prio->nr_active[node]; 822 nr_active += spu_prio->nr_waiting; 823 824 return nr_active; ··· 858 859 static int spusched_thread(void *unused) 860 { 861 - struct spu *spu, *next; 862 int node; 863 864 while (!kthread_should_stop()) { 865 set_current_state(TASK_INTERRUPTIBLE); 866 schedule(); 867 for (node = 0; node < MAX_NUMNODES; node++) { 868 - mutex_lock(&spu_prio->active_mutex[node]); 869 - list_for_each_entry_safe(spu, next, 870 - &spu_prio->active_list[node], 871 - list) 872 - spusched_tick(spu->ctx); 873 - mutex_unlock(&spu_prio->active_mutex[node]); 874 } 875 } 876 ··· 927 INIT_LIST_HEAD(&spu_prio->runq[i]); 928 __clear_bit(i, spu_prio->bitmap); 929 } 930 - __set_bit(MAX_PRIO, spu_prio->bitmap); 931 for (i = 0; i < MAX_NUMNODES; i++) { 932 - mutex_init(&spu_prio->active_mutex[i]); 933 - INIT_LIST_HEAD(&spu_prio->active_list[i]); 934 } 935 spin_lock_init(&spu_prio->runq_lock); 936 ··· 958 return err; 959 } 960 961 - void __exit spu_sched_exit(void) 962 { 963 - struct spu *spu, *tmp; 964 int node; 965 966 remove_proc_entry("spu_loadavg", NULL); ··· 969 kthread_stop(spusched_task); 970 971 for (node = 0; node < MAX_NUMNODES; node++) { 972 - mutex_lock(&spu_prio->active_mutex[node]); 973 - list_for_each_entry_safe(spu, tmp, &spu_prio->active_list[node], 974 - list) { 975 - list_del_init(&spu->list); 976 - spu_free(spu); 977 - } 978 - mutex_unlock(&spu_prio->active_mutex[node]); 979 } 980 kfree(spu_prio); 981 }
··· 51 DECLARE_BITMAP(bitmap, MAX_PRIO); 52 struct list_head runq[MAX_PRIO]; 53 spinlock_t runq_lock; 54 int nr_waiting; 55 }; 56 ··· 127 ctx->policy = current->policy; 128 129 /* 130 + * A lot of places that don't hold list_mutex poke into 131 * cpus_allowed, including grab_runnable_context which 132 * already holds the runq_lock. So abuse runq_lock 133 * to protect this field aswell. ··· 141 { 142 int node = ctx->spu->node; 143 144 + mutex_lock(&cbe_spu_info[node].list_mutex); 145 __spu_update_sched_info(ctx); 146 + mutex_unlock(&cbe_spu_info[node].list_mutex); 147 } 148 149 static int __node_allowed(struct spu_context *ctx, int node) ··· 169 return rval; 170 } 171 172 static BLOCKING_NOTIFIER_HEAD(spu_switch_notifier); 173 174 + void spu_switch_notify(struct spu *spu, struct spu_context *ctx) 175 { 176 blocking_notifier_call_chain(&spu_switch_notifier, 177 ctx ? ctx->object_id : 0, spu); 178 } 179 180 + static void notify_spus_active(void) 181 + { 182 + int node; 183 + 184 + /* 185 + * Wake up the active spu_contexts. 186 + * 187 + * When the awakened processes see their "notify_active" flag is set, 188 + * they will call spu_switch_notify(); 189 + */ 190 + for_each_online_node(node) { 191 + struct spu *spu; 192 + 193 + mutex_lock(&cbe_spu_info[node].list_mutex); 194 + list_for_each_entry(spu, &cbe_spu_info[node].spus, cbe_list) { 195 + if (spu->alloc_state != SPU_FREE) { 196 + struct spu_context *ctx = spu->ctx; 197 + set_bit(SPU_SCHED_NOTIFY_ACTIVE, 198 + &ctx->sched_flags); 199 + mb(); 200 + wake_up_all(&ctx->stop_wq); 201 + } 202 + } 203 + mutex_unlock(&cbe_spu_info[node].list_mutex); 204 + } 205 + } 206 + 207 int spu_switch_event_register(struct notifier_block * n) 208 { 209 + int ret; 210 + ret = blocking_notifier_chain_register(&spu_switch_notifier, n); 211 + if (!ret) 212 + notify_spus_active(); 213 + return ret; 214 } 215 + EXPORT_SYMBOL_GPL(spu_switch_event_register); 216 217 int spu_switch_event_unregister(struct notifier_block * n) 218 { 219 return blocking_notifier_chain_unregister(&spu_switch_notifier, n); 220 } 221 + EXPORT_SYMBOL_GPL(spu_switch_event_unregister); 222 223 /** 224 * spu_bind_context - bind spu context to physical spu ··· 229 { 230 pr_debug("%s: pid=%d SPU=%d NODE=%d\n", __FUNCTION__, current->pid, 231 spu->number, spu->node); 232 + spuctx_switch_state(ctx, SPU_UTIL_SYSTEM); 233 + 234 + if (ctx->flags & SPU_CREATE_NOSCHED) 235 + atomic_inc(&cbe_spu_info[spu->node].reserved_spus); 236 + if (!list_empty(&ctx->aff_list)) 237 + atomic_inc(&ctx->gang->aff_sched_count); 238 239 ctx->stats.slb_flt_base = spu->stats.slb_flt; 240 ctx->stats.class2_intr_base = spu->stats.class2_intr; ··· 238 ctx->spu = spu; 239 ctx->ops = &spu_hw_ops; 240 spu->pid = current->pid; 241 + spu->tgid = current->tgid; 242 spu_associate_mm(spu, ctx->owner); 243 spu->ibox_callback = spufs_ibox_callback; 244 spu->wbox_callback = spufs_wbox_callback; ··· 251 spu_cpu_affinity_set(spu, raw_smp_processor_id()); 252 spu_switch_notify(spu, ctx); 253 ctx->state = SPU_STATE_RUNNABLE; 254 + 255 + spuctx_switch_state(ctx, SPU_UTIL_IDLE_LOADED); 256 + } 257 + 258 + /* 259 + * Must be used with the list_mutex held. 260 + */ 261 + static inline int sched_spu(struct spu *spu) 262 + { 263 + BUG_ON(!mutex_is_locked(&cbe_spu_info[spu->node].list_mutex)); 264 + 265 + return (!spu->ctx || !(spu->ctx->flags & SPU_CREATE_NOSCHED)); 266 + } 267 + 268 + static void aff_merge_remaining_ctxs(struct spu_gang *gang) 269 + { 270 + struct spu_context *ctx; 271 + 272 + list_for_each_entry(ctx, &gang->aff_list_head, aff_list) { 273 + if (list_empty(&ctx->aff_list)) 274 + list_add(&ctx->aff_list, &gang->aff_list_head); 275 + } 276 + gang->aff_flags |= AFF_MERGED; 277 + } 278 + 279 + static void aff_set_offsets(struct spu_gang *gang) 280 + { 281 + struct spu_context *ctx; 282 + int offset; 283 + 284 + offset = -1; 285 + list_for_each_entry_reverse(ctx, &gang->aff_ref_ctx->aff_list, 286 + aff_list) { 287 + if (&ctx->aff_list == &gang->aff_list_head) 288 + break; 289 + ctx->aff_offset = offset--; 290 + } 291 + 292 + offset = 0; 293 + list_for_each_entry(ctx, gang->aff_ref_ctx->aff_list.prev, aff_list) { 294 + if (&ctx->aff_list == &gang->aff_list_head) 295 + break; 296 + ctx->aff_offset = offset++; 297 + } 298 + 299 + gang->aff_flags |= AFF_OFFSETS_SET; 300 + } 301 + 302 + static struct spu *aff_ref_location(struct spu_context *ctx, int mem_aff, 303 + int group_size, int lowest_offset) 304 + { 305 + struct spu *spu; 306 + int node, n; 307 + 308 + /* 309 + * TODO: A better algorithm could be used to find a good spu to be 310 + * used as reference location for the ctxs chain. 311 + */ 312 + node = cpu_to_node(raw_smp_processor_id()); 313 + for (n = 0; n < MAX_NUMNODES; n++, node++) { 314 + node = (node < MAX_NUMNODES) ? node : 0; 315 + if (!node_allowed(ctx, node)) 316 + continue; 317 + mutex_lock(&cbe_spu_info[node].list_mutex); 318 + list_for_each_entry(spu, &cbe_spu_info[node].spus, cbe_list) { 319 + if ((!mem_aff || spu->has_mem_affinity) && 320 + sched_spu(spu)) { 321 + mutex_unlock(&cbe_spu_info[node].list_mutex); 322 + return spu; 323 + } 324 + } 325 + mutex_unlock(&cbe_spu_info[node].list_mutex); 326 + } 327 + return NULL; 328 + } 329 + 330 + static void aff_set_ref_point_location(struct spu_gang *gang) 331 + { 332 + int mem_aff, gs, lowest_offset; 333 + struct spu_context *ctx; 334 + struct spu *tmp; 335 + 336 + mem_aff = gang->aff_ref_ctx->flags & SPU_CREATE_AFFINITY_MEM; 337 + lowest_offset = 0; 338 + gs = 0; 339 + 340 + list_for_each_entry(tmp, &gang->aff_list_head, aff_list) 341 + gs++; 342 + 343 + list_for_each_entry_reverse(ctx, &gang->aff_ref_ctx->aff_list, 344 + aff_list) { 345 + if (&ctx->aff_list == &gang->aff_list_head) 346 + break; 347 + lowest_offset = ctx->aff_offset; 348 + } 349 + 350 + gang->aff_ref_spu = aff_ref_location(ctx, mem_aff, gs, lowest_offset); 351 + } 352 + 353 + static struct spu *ctx_location(struct spu *ref, int offset, int node) 354 + { 355 + struct spu *spu; 356 + 357 + spu = NULL; 358 + if (offset >= 0) { 359 + list_for_each_entry(spu, ref->aff_list.prev, aff_list) { 360 + BUG_ON(spu->node != node); 361 + if (offset == 0) 362 + break; 363 + if (sched_spu(spu)) 364 + offset--; 365 + } 366 + } else { 367 + list_for_each_entry_reverse(spu, ref->aff_list.next, aff_list) { 368 + BUG_ON(spu->node != node); 369 + if (offset == 0) 370 + break; 371 + if (sched_spu(spu)) 372 + offset++; 373 + } 374 + } 375 + 376 + return spu; 377 + } 378 + 379 + /* 380 + * affinity_check is called each time a context is going to be scheduled. 381 + * It returns the spu ptr on which the context must run. 382 + */ 383 + static int has_affinity(struct spu_context *ctx) 384 + { 385 + struct spu_gang *gang = ctx->gang; 386 + 387 + if (list_empty(&ctx->aff_list)) 388 + return 0; 389 + 390 + mutex_lock(&gang->aff_mutex); 391 + if (!gang->aff_ref_spu) { 392 + if (!(gang->aff_flags & AFF_MERGED)) 393 + aff_merge_remaining_ctxs(gang); 394 + if (!(gang->aff_flags & AFF_OFFSETS_SET)) 395 + aff_set_offsets(gang); 396 + aff_set_ref_point_location(gang); 397 + } 398 + mutex_unlock(&gang->aff_mutex); 399 + 400 + return gang->aff_ref_spu != NULL; 401 } 402 403 /** ··· 263 { 264 pr_debug("%s: unbind pid=%d SPU=%d NODE=%d\n", __FUNCTION__, 265 spu->pid, spu->number, spu->node); 266 + spuctx_switch_state(ctx, SPU_UTIL_SYSTEM); 267 268 + if (spu->ctx->flags & SPU_CREATE_NOSCHED) 269 + atomic_dec(&cbe_spu_info[spu->node].reserved_spus); 270 + if (!list_empty(&ctx->aff_list)) 271 + if (atomic_dec_and_test(&ctx->gang->aff_sched_count)) 272 + ctx->gang->aff_ref_spu = NULL; 273 spu_switch_notify(spu, NULL); 274 spu_unmap_mappings(ctx); 275 spu_save(&ctx->csa, spu); ··· 278 spu->dma_callback = NULL; 279 spu_associate_mm(spu, NULL); 280 spu->pid = 0; 281 + spu->tgid = 0; 282 ctx->ops = &spu_backing_ops; 283 spu->flags = 0; 284 spu->ctx = NULL; 285 ··· 287 (spu->stats.slb_flt - ctx->stats.slb_flt_base); 288 ctx->stats.class2_intr += 289 (spu->stats.class2_intr - ctx->stats.class2_intr_base); 290 + 291 + /* This maps the underlying spu state to idle */ 292 + spuctx_switch_state(ctx, SPU_UTIL_IDLE_LOADED); 293 + ctx->spu = NULL; 294 } 295 296 /** ··· 352 353 static struct spu *spu_get_idle(struct spu_context *ctx) 354 { 355 + struct spu *spu; 356 + int node, n; 357 358 + if (has_affinity(ctx)) { 359 + node = ctx->gang->aff_ref_spu->node; 360 + 361 + mutex_lock(&cbe_spu_info[node].list_mutex); 362 + spu = ctx_location(ctx->gang->aff_ref_spu, ctx->aff_offset, node); 363 + if (spu && spu->alloc_state == SPU_FREE) 364 + goto found; 365 + mutex_unlock(&cbe_spu_info[node].list_mutex); 366 + return NULL; 367 + } 368 + 369 + node = cpu_to_node(raw_smp_processor_id()); 370 for (n = 0; n < MAX_NUMNODES; n++, node++) { 371 node = (node < MAX_NUMNODES) ? node : 0; 372 if (!node_allowed(ctx, node)) 373 continue; 374 + 375 + mutex_lock(&cbe_spu_info[node].list_mutex); 376 + list_for_each_entry(spu, &cbe_spu_info[node].spus, cbe_list) { 377 + if (spu->alloc_state == SPU_FREE) 378 + goto found; 379 + } 380 + mutex_unlock(&cbe_spu_info[node].list_mutex); 381 } 382 + 383 + return NULL; 384 + 385 + found: 386 + spu->alloc_state = SPU_USED; 387 + mutex_unlock(&cbe_spu_info[node].list_mutex); 388 + pr_debug("Got SPU %d %d\n", spu->number, spu->node); 389 + spu_init_channels(spu); 390 return spu; 391 } 392 ··· 393 if (!node_allowed(ctx, node)) 394 continue; 395 396 + mutex_lock(&cbe_spu_info[node].list_mutex); 397 + list_for_each_entry(spu, &cbe_spu_info[node].spus, cbe_list) { 398 struct spu_context *tmp = spu->ctx; 399 400 if (tmp->prio > ctx->prio && 401 (!victim || tmp->prio > victim->prio)) 402 victim = spu->ctx; 403 } 404 + mutex_unlock(&cbe_spu_info[node].list_mutex); 405 406 if (victim) { 407 /* ··· 426 victim = NULL; 427 goto restart; 428 } 429 + 430 + mutex_lock(&cbe_spu_info[node].list_mutex); 431 + cbe_spu_info[node].nr_active--; 432 + mutex_unlock(&cbe_spu_info[node].list_mutex); 433 + 434 spu_unbind_context(spu, victim); 435 victim->stats.invol_ctx_switch++; 436 spu->stats.invol_ctx_switch++; ··· 455 */ 456 int spu_activate(struct spu_context *ctx, unsigned long flags) 457 { 458 do { 459 struct spu *spu; 460 ··· 477 if (!spu && rt_prio(ctx->prio)) 478 spu = find_victim(ctx); 479 if (spu) { 480 + int node = spu->node; 481 + 482 + mutex_lock(&cbe_spu_info[node].list_mutex); 483 spu_bind_context(spu, ctx); 484 + cbe_spu_info[node].nr_active++; 485 + mutex_unlock(&cbe_spu_info[node].list_mutex); 486 return 0; 487 } 488 ··· 500 int best; 501 502 spin_lock(&spu_prio->runq_lock); 503 + best = find_first_bit(spu_prio->bitmap, prio); 504 while (best < prio) { 505 struct list_head *rq = &spu_prio->runq[best]; 506 ··· 527 if (spu) { 528 new = grab_runnable_context(max_prio, spu->node); 529 if (new || force) { 530 + int node = spu->node; 531 + 532 + mutex_lock(&cbe_spu_info[node].list_mutex); 533 spu_unbind_context(spu, ctx); 534 + spu->alloc_state = SPU_FREE; 535 + cbe_spu_info[node].nr_active--; 536 + mutex_unlock(&cbe_spu_info[node].list_mutex); 537 + 538 ctx->stats.vol_ctx_switch++; 539 spu->stats.vol_ctx_switch++; 540 + 541 if (new) 542 wake_up(&new->stop_wq); 543 } ··· 550 */ 551 void spu_deactivate(struct spu_context *ctx) 552 { 553 __spu_deactivate(ctx, 1, MAX_PRIO); 554 } 555 556 /** 557 + * spu_yield - yield a physical spu if others are waiting 558 * @ctx: spu context to yield 559 * 560 * Check if there is a higher priority context waiting and if yes ··· 575 { 576 if (!(ctx->flags & SPU_CREATE_NOSCHED)) { 577 mutex_lock(&ctx->state_mutex); 578 + __spu_deactivate(ctx, 0, MAX_PRIO); 579 mutex_unlock(&ctx->state_mutex); 580 } 581 } 582 583 + static noinline void spusched_tick(struct spu_context *ctx) 584 { 585 if (ctx->flags & SPU_CREATE_NOSCHED) 586 return; ··· 596 return; 597 598 /* 599 + * Unfortunately list_mutex ranks outside of state_mutex, so 600 * we have to trylock here. If we fail give the context another 601 * tick and try again. 602 */ ··· 606 607 new = grab_runnable_context(ctx->prio + 1, spu->node); 608 if (new) { 609 spu_unbind_context(spu, ctx); 610 ctx->stats.invol_ctx_switch++; 611 spu->stats.invol_ctx_switch++; 612 + spu->alloc_state = SPU_FREE; 613 + cbe_spu_info[spu->node].nr_active--; 614 wake_up(&new->stop_wq); 615 /* 616 * We need to break out of the wait loop in ··· 632 * 633 * Return the number of tasks currently running or waiting to run. 634 * 635 + * Note that we don't take runq_lock / list_mutex here. Reading 636 * a single 32bit value is atomic on powerpc, and we don't care 637 * about memory ordering issues here. 638 */ ··· 641 int nr_active = 0, node; 642 643 for (node = 0; node < MAX_NUMNODES; node++) 644 + nr_active += cbe_spu_info[node].nr_active; 645 nr_active += spu_prio->nr_waiting; 646 647 return nr_active; ··· 681 682 static int spusched_thread(void *unused) 683 { 684 + struct spu *spu; 685 int node; 686 687 while (!kthread_should_stop()) { 688 set_current_state(TASK_INTERRUPTIBLE); 689 schedule(); 690 for (node = 0; node < MAX_NUMNODES; node++) { 691 + mutex_lock(&cbe_spu_info[node].list_mutex); 692 + list_for_each_entry(spu, &cbe_spu_info[node].spus, cbe_list) 693 + if (spu->ctx) 694 + spusched_tick(spu->ctx); 695 + mutex_unlock(&cbe_spu_info[node].list_mutex); 696 } 697 } 698 ··· 751 INIT_LIST_HEAD(&spu_prio->runq[i]); 752 __clear_bit(i, spu_prio->bitmap); 753 } 754 for (i = 0; i < MAX_NUMNODES; i++) { 755 + mutex_init(&cbe_spu_info[i].list_mutex); 756 + INIT_LIST_HEAD(&cbe_spu_info[i].spus); 757 } 758 spin_lock_init(&spu_prio->runq_lock); 759 ··· 783 return err; 784 } 785 786 + void spu_sched_exit(void) 787 { 788 + struct spu *spu; 789 int node; 790 791 remove_proc_entry("spu_loadavg", NULL); ··· 794 kthread_stop(spusched_task); 795 796 for (node = 0; node < MAX_NUMNODES; node++) { 797 + mutex_lock(&cbe_spu_info[node].list_mutex); 798 + list_for_each_entry(spu, &cbe_spu_info[node].spus, cbe_list) 799 + if (spu->alloc_state != SPU_FREE) 800 + spu->alloc_state = SPU_FREE; 801 + mutex_unlock(&cbe_spu_info[node].list_mutex); 802 } 803 kfree(spu_prio); 804 }
+3 -3
arch/powerpc/platforms/cell/spufs/spu_restore.c
··· 84 unsigned int decr_running; 85 unsigned int decr; 86 87 - /* Restore, Step 6: 88 * If the LSCSA "decrementer running" flag is set 89 * then write the SPU_WrDec channel with the 90 * decrementer value from LSCSA. 91 */ 92 offset = LSCSA_QW_OFFSET(decr_status); 93 - decr_running = regs_spill[offset].slot[0]; 94 if (decr_running) { 95 offset = LSCSA_QW_OFFSET(decr); 96 decr = regs_spill[offset].slot[0]; ··· 318 build_dma_list(lscsa_ea); /* Step 3. */ 319 restore_upper_240kb(lscsa_ea); /* Step 4. */ 320 /* Step 5: done by 'exit'. */ 321 - restore_decr(); /* Step 6. */ 322 enqueue_putllc(lscsa_ea); /* Step 7. */ 323 set_tag_update(); /* Step 8. */ 324 read_tag_status(); /* Step 9. */ 325 read_llar_status(); /* Step 10. */ 326 write_ppu_mb(); /* Step 11. */ 327 write_ppuint_mb(); /* Step 12. */
··· 84 unsigned int decr_running; 85 unsigned int decr; 86 87 + /* Restore, Step 6(moved): 88 * If the LSCSA "decrementer running" flag is set 89 * then write the SPU_WrDec channel with the 90 * decrementer value from LSCSA. 91 */ 92 offset = LSCSA_QW_OFFSET(decr_status); 93 + decr_running = regs_spill[offset].slot[0] & SPU_DECR_STATUS_RUNNING; 94 if (decr_running) { 95 offset = LSCSA_QW_OFFSET(decr); 96 decr = regs_spill[offset].slot[0]; ··· 318 build_dma_list(lscsa_ea); /* Step 3. */ 319 restore_upper_240kb(lscsa_ea); /* Step 4. */ 320 /* Step 5: done by 'exit'. */ 321 enqueue_putllc(lscsa_ea); /* Step 7. */ 322 set_tag_update(); /* Step 8. */ 323 read_tag_status(); /* Step 9. */ 324 + restore_decr(); /* moved Step 6. */ 325 read_llar_status(); /* Step 10. */ 326 write_ppu_mb(); /* Step 11. */ 327 write_ppuint_mb(); /* Step 12. */
+277 -245
arch/powerpc/platforms/cell/spufs/spu_restore_dump.h_shipped
··· 10 0x24fd8081, 11 0x1cd80081, 12 0x33001180, 13 - 0x42030003, 14 0x33800284, 15 0x1c010204, 16 0x40200000, ··· 24 0x23fffd84, 25 0x1c100183, 26 0x217ffa85, 27 - 0x3080a000, 28 - 0x3080a201, 29 - 0x3080a402, 30 - 0x3080a603, 31 - 0x3080a804, 32 - 0x3080aa05, 33 - 0x3080ac06, 34 - 0x3080ae07, 35 - 0x3080b008, 36 - 0x3080b209, 37 - 0x3080b40a, 38 - 0x3080b60b, 39 - 0x3080b80c, 40 - 0x3080ba0d, 41 - 0x3080bc0e, 42 - 0x3080be0f, 43 0x00003ffc, 44 0x00000000, 45 0x00000000, ··· 48 0x3ec00083, 49 0xb0a14103, 50 0x01a00204, 51 - 0x3ec10082, 52 - 0x4202800e, 53 - 0x04000703, 54 - 0xb0a14202, 55 - 0x21a00803, 56 - 0x3fbf028d, 57 - 0x3f20068d, 58 - 0x3fbe0682, 59 0x3fe30102, 60 0x21a00882, 61 - 0x3f82028f, 62 - 0x3fe3078f, 63 - 0x3fbf0784, 64 0x3f200204, 65 0x3fbe0204, 66 0x3fe30204, ··· 74 0x21a00083, 75 0x40800082, 76 0x21a00b02, 77 - 0x10002818, 78 - 0x42a00002, 79 - 0x32800007, 80 - 0x4207000c, 81 - 0x18008208, 82 - 0x40a0000b, 83 - 0x4080020a, 84 - 0x40800709, 85 - 0x00200000, 86 - 0x42070002, 87 - 0x3ac30384, 88 0x1cffc489, 89 - 0x00200000, 90 - 0x18008383, 91 - 0x38830382, 92 - 0x4cffc486, 93 - 0x3ac28185, 94 - 0xb0408584, 95 - 0x28830382, 96 - 0x1c020387, 97 - 0x38828182, 98 - 0xb0408405, 99 - 0x1802c408, 100 - 0x28828182, 101 - 0x217ff886, 102 - 0x04000583, 103 - 0x21a00803, 104 - 0x3fbe0682, 105 - 0x3fe30102, 106 - 0x04000106, 107 - 0x21a00886, 108 - 0x04000603, 109 - 0x21a00903, 110 - 0x40803c02, 111 - 0x21a00982, 112 - 0x40800003, 113 - 0x04000184, 114 - 0x21a00a04, 115 0x40802202, 116 0x21a00a82, 117 - 0x42028005, 118 - 0x34208702, 119 - 0x21002282, 120 - 0x21a00804, 121 - 0x21a00886, 122 - 0x3fbf0782, 123 0x3f200102, 124 0x3fbe0102, 125 0x3fe30102, 126 0x21a00902, 127 0x40804003, 128 0x21a00983, 129 - 0x21a00a04, 130 0x40805a02, 131 0x21a00a82, 132 0x40800083, 133 0x21a00b83, 134 0x01a00c02, 135 - 0x01a00d83, 136 - 0x3420c282, 137 0x21a00e02, 138 - 0x34210283, 139 - 0x21a00f03, 140 - 0x34200284, 141 - 0x77400200, 142 - 0x3421c282, 143 0x21a00702, 144 - 0x34218283, 145 - 0x21a00083, 146 - 0x34214282, 147 0x21a00b02, 148 - 0x4200480c, 149 - 0x00200000, 150 - 0x1c010286, 151 - 0x34220284, 152 - 0x34220302, 153 - 0x0f608203, 154 - 0x5c024204, 155 - 0x3b81810b, 156 - 0x42013c02, 157 - 0x00200000, 158 - 0x18008185, 159 - 0x38808183, 160 - 0x3b814182, 161 - 0x21004e84, 162 0x4020007f, 163 0x35000100, 164 - 0x000004e0, 165 - 0x000002a0, 166 - 0x000002e8, 167 - 0x00000428, 168 0x00000360, 169 - 0x000002e8, 170 - 0x000004a0, 171 - 0x00000468, 172 0x000003c8, 173 0x00000360, 174 - 0x409ffe02, 175 - 0x30801203, 176 - 0x40800204, 177 - 0x3ec40085, 178 - 0x10009c09, 179 - 0x3ac10606, 180 - 0xb060c105, 181 - 0x4020007f, 182 - 0x4020007f, 183 - 0x20801203, 184 - 0x38810602, 185 - 0xb0408586, 186 - 0x28810602, 187 - 0x32004180, 188 - 0x34204702, 189 - 0x21a00382, 190 - 0x4020007f, 191 - 0x327fdc80, 192 - 0x409ffe02, 193 - 0x30801203, 194 - 0x40800204, 195 - 0x3ec40087, 196 - 0x40800405, 197 0x00200000, 198 - 0x40800606, 199 - 0x3ac10608, 200 - 0x3ac14609, 201 - 0x3ac1860a, 202 - 0xb060c107, 203 0x20801203, 204 0x41004003, 205 - 0x38810602, 206 - 0x4020007f, 207 - 0xb0408188, 208 - 0x4020007f, 209 - 0x28810602, 210 - 0x41201002, 211 - 0x38814603, 212 - 0x10009c09, 213 - 0xb060c109, 214 - 0x4020007f, 215 - 0x28814603, 216 - 0x41193f83, 217 - 0x38818602, 218 - 0x60ffc003, 219 - 0xb040818a, 220 - 0x28818602, 221 - 0x32003080, 222 - 0x409ffe02, 223 - 0x30801203, 224 - 0x40800204, 225 - 0x3ec40087, 226 - 0x41201008, 227 - 0x10009c14, 228 - 0x40800405, 229 - 0x3ac10609, 230 - 0x40800606, 231 - 0x3ac1460a, 232 - 0xb060c107, 233 - 0x3ac1860b, 234 - 0x20801203, 235 - 0x38810602, 236 - 0xb0408409, 237 - 0x28810602, 238 - 0x38814603, 239 - 0xb060c40a, 240 - 0x4020007f, 241 - 0x28814603, 242 - 0x41193f83, 243 - 0x38818602, 244 - 0x60ffc003, 245 - 0xb040818b, 246 - 0x28818602, 247 - 0x32002380, 248 - 0x409ffe02, 249 - 0x30801204, 250 - 0x40800205, 251 - 0x3ec40083, 252 - 0x40800406, 253 - 0x3ac14607, 254 - 0x3ac18608, 255 - 0xb0810103, 256 - 0x41004002, 257 - 0x20801204, 258 - 0x4020007f, 259 - 0x38814603, 260 - 0x10009c0b, 261 - 0xb060c107, 262 - 0x4020007f, 263 - 0x4020007f, 264 - 0x28814603, 265 - 0x38818602, 266 - 0x4020007f, 267 - 0x4020007f, 268 - 0xb0408588, 269 - 0x28818602, 270 - 0x4020007f, 271 - 0x32001780, 272 - 0x409ffe02, 273 - 0x1000640e, 274 - 0x40800204, 275 - 0x30801203, 276 - 0x40800405, 277 - 0x3ec40087, 278 - 0x40800606, 279 - 0x3ac10608, 280 - 0x3ac14609, 281 - 0x3ac1860a, 282 - 0xb060c107, 283 - 0x20801203, 284 - 0x413d8003, 285 - 0x38810602, 286 - 0x4020007f, 287 - 0x327fd780, 288 - 0x409ffe02, 289 - 0x10007f0c, 290 - 0x40800205, 291 - 0x30801204, 292 - 0x40800406, 293 - 0x3ec40083, 294 - 0x3ac14607, 295 - 0x3ac18608, 296 - 0xb0810103, 297 - 0x413d8002, 298 - 0x20801204, 299 - 0x38814603, 300 - 0x4020007f, 301 - 0x327feb80, 302 - 0x409ffe02, 303 - 0x30801203, 304 - 0x40800204, 305 - 0x3ec40087, 306 - 0x40800405, 307 - 0x1000650a, 308 - 0x40800606, 309 - 0x3ac10608, 310 - 0x3ac14609, 311 - 0x3ac1860a, 312 - 0xb060c107, 313 - 0x20801203, 314 - 0x38810602, 315 - 0xb0408588, 316 - 0x4020007f, 317 - 0x327fc980, 318 0x00400000, 319 0x40800003, 320 - 0x4020007f, 321 0x35000000, 322 0x00000000, 323 0x00000000, 324 0x00000000, 325 0x00000000,
··· 10 0x24fd8081, 11 0x1cd80081, 12 0x33001180, 13 + 0x42034003, 14 0x33800284, 15 0x1c010204, 16 0x40200000, ··· 24 0x23fffd84, 25 0x1c100183, 26 0x217ffa85, 27 + 0x3080b000, 28 + 0x3080b201, 29 + 0x3080b402, 30 + 0x3080b603, 31 + 0x3080b804, 32 + 0x3080ba05, 33 + 0x3080bc06, 34 + 0x3080be07, 35 + 0x3080c008, 36 + 0x3080c209, 37 + 0x3080c40a, 38 + 0x3080c60b, 39 + 0x3080c80c, 40 + 0x3080ca0d, 41 + 0x3080cc0e, 42 + 0x3080ce0f, 43 0x00003ffc, 44 0x00000000, 45 0x00000000, ··· 48 0x3ec00083, 49 0xb0a14103, 50 0x01a00204, 51 + 0x3ec10083, 52 + 0x4202c002, 53 + 0xb0a14203, 54 + 0x21a00802, 55 + 0x3fbf028a, 56 + 0x3f20050a, 57 + 0x3fbe0502, 58 0x3fe30102, 59 0x21a00882, 60 + 0x3f82028b, 61 + 0x3fe3058b, 62 + 0x3fbf0584, 63 0x3f200204, 64 0x3fbe0204, 65 0x3fe30204, ··· 75 0x21a00083, 76 0x40800082, 77 0x21a00b02, 78 + 0x10002612, 79 + 0x42a00003, 80 + 0x42074006, 81 + 0x1800c204, 82 + 0x40a00008, 83 + 0x40800789, 84 + 0x1c010305, 85 + 0x34000302, 86 0x1cffc489, 87 + 0x3ec00303, 88 + 0x3ec00287, 89 + 0xb0408403, 90 + 0x24000302, 91 + 0x34000282, 92 + 0x1c020306, 93 + 0xb0408207, 94 + 0x18020204, 95 + 0x24000282, 96 + 0x217ffa09, 97 + 0x04000402, 98 + 0x21a00802, 99 + 0x3fbe0504, 100 + 0x3fe30204, 101 + 0x21a00884, 102 + 0x42074002, 103 + 0x21a00902, 104 + 0x40803c03, 105 + 0x21a00983, 106 + 0x04000485, 107 + 0x21a00a05, 108 0x40802202, 109 0x21a00a82, 110 + 0x21a00805, 111 + 0x21a00884, 112 + 0x3fbf0582, 113 0x3f200102, 114 0x3fbe0102, 115 0x3fe30102, 116 0x21a00902, 117 0x40804003, 118 0x21a00983, 119 + 0x21a00a05, 120 0x40805a02, 121 0x21a00a82, 122 0x40800083, 123 0x21a00b83, 124 0x01a00c02, 125 + 0x30809c03, 126 + 0x34000182, 127 + 0x14004102, 128 + 0x21002082, 129 + 0x01a00d82, 130 + 0x3080a003, 131 + 0x34000182, 132 0x21a00e02, 133 + 0x3080a203, 134 + 0x34000182, 135 + 0x21a00f02, 136 + 0x3080a403, 137 + 0x34000182, 138 + 0x77400100, 139 + 0x3080a603, 140 + 0x34000182, 141 0x21a00702, 142 + 0x3080a803, 143 + 0x34000182, 144 + 0x21a00082, 145 + 0x3080aa03, 146 + 0x34000182, 147 0x21a00b02, 148 + 0x4020007f, 149 + 0x3080ae02, 150 + 0x42004805, 151 + 0x3080ac04, 152 + 0x34000103, 153 + 0x34000202, 154 + 0x1cffc183, 155 + 0x3b810106, 156 + 0x0f608184, 157 + 0x42013802, 158 + 0x5c020183, 159 + 0x38810102, 160 + 0x3b810102, 161 + 0x21000e83, 162 0x4020007f, 163 0x35000100, 164 + 0x00000470, 165 + 0x000002f8, 166 + 0x00000430, 167 0x00000360, 168 + 0x000002f8, 169 0x000003c8, 170 + 0x000004a8, 171 + 0x00000298, 172 0x00000360, 173 0x00200000, 174 + 0x409ffe02, 175 + 0x30801203, 176 + 0x40800208, 177 + 0x3ec40084, 178 + 0x40800407, 179 + 0x3ac20289, 180 + 0xb060c104, 181 + 0x3ac1c284, 182 0x20801203, 183 + 0x38820282, 184 0x41004003, 185 + 0xb0408189, 186 + 0x28820282, 187 + 0x3881c282, 188 + 0xb0408304, 189 + 0x2881c282, 190 0x00400000, 191 0x40800003, 192 0x35000000, 193 + 0x30809e03, 194 + 0x34000182, 195 + 0x21a00382, 196 + 0x4020007f, 197 + 0x327fde00, 198 + 0x409ffe02, 199 + 0x30801203, 200 + 0x40800206, 201 + 0x3ec40084, 202 + 0x40800407, 203 + 0x40800608, 204 + 0x3ac1828a, 205 + 0x3ac20289, 206 + 0xb060c104, 207 + 0x3ac1c284, 208 + 0x20801203, 209 + 0x38818282, 210 + 0x41004003, 211 + 0xb040818a, 212 + 0x10005b0b, 213 + 0x41201003, 214 + 0x28818282, 215 + 0x3881c282, 216 + 0xb0408184, 217 + 0x41193f83, 218 + 0x60ffc003, 219 + 0x2881c282, 220 + 0x38820282, 221 + 0xb0408189, 222 + 0x28820282, 223 + 0x327fef80, 224 + 0x409ffe02, 225 + 0x30801203, 226 + 0x40800207, 227 + 0x3ec40086, 228 + 0x4120100b, 229 + 0x10005b14, 230 + 0x40800404, 231 + 0x3ac1c289, 232 + 0x40800608, 233 + 0xb060c106, 234 + 0x3ac10286, 235 + 0x3ac2028a, 236 + 0x20801203, 237 + 0x3881c282, 238 + 0x41193f83, 239 + 0x60ffc003, 240 + 0xb0408589, 241 + 0x2881c282, 242 + 0x38810282, 243 + 0xb0408586, 244 + 0x28810282, 245 + 0x38820282, 246 + 0xb040818a, 247 + 0x28820282, 248 + 0x4020007f, 249 + 0x327fe280, 250 + 0x409ffe02, 251 + 0x30801203, 252 + 0x40800207, 253 + 0x3ec40084, 254 + 0x40800408, 255 + 0x10005b14, 256 + 0x40800609, 257 + 0x3ac1c28a, 258 + 0x3ac2028b, 259 + 0xb060c104, 260 + 0x3ac24284, 261 + 0x20801203, 262 + 0x41201003, 263 + 0x3881c282, 264 + 0xb040830a, 265 + 0x2881c282, 266 + 0x38820282, 267 + 0xb040818b, 268 + 0x41193f83, 269 + 0x60ffc003, 270 + 0x28820282, 271 + 0x38824282, 272 + 0xb0408184, 273 + 0x28824282, 274 + 0x4020007f, 275 + 0x327fd580, 276 + 0x409ffe02, 277 + 0x1000658e, 278 + 0x40800206, 279 + 0x30801203, 280 + 0x40800407, 281 + 0x3ec40084, 282 + 0x40800608, 283 + 0x3ac1828a, 284 + 0x3ac20289, 285 + 0xb060c104, 286 + 0x3ac1c284, 287 + 0x20801203, 288 + 0x413d8003, 289 + 0x38818282, 290 + 0x4020007f, 291 + 0x327fd800, 292 + 0x409ffe03, 293 + 0x30801202, 294 + 0x40800207, 295 + 0x3ec40084, 296 + 0x10005b09, 297 + 0x3ac1c288, 298 + 0xb0408184, 299 + 0x4020007f, 300 + 0x4020007f, 301 + 0x20801202, 302 + 0x3881c282, 303 + 0xb0408308, 304 + 0x2881c282, 305 + 0x327fc680, 306 + 0x409ffe02, 307 + 0x1000588b, 308 + 0x40800208, 309 + 0x30801203, 310 + 0x40800407, 311 + 0x3ec40084, 312 + 0x3ac20289, 313 + 0xb060c104, 314 + 0x3ac1c284, 315 + 0x20801203, 316 + 0x413d8003, 317 + 0x38820282, 318 + 0x327fbd80, 319 + 0x00200000, 320 + 0x00000da0, 321 0x00000000, 322 + 0x00000000, 323 + 0x00000000, 324 + 0x00000d90, 325 + 0x00000000, 326 + 0x00000000, 327 + 0x00000000, 328 + 0x00000db0, 329 + 0x00000000, 330 + 0x00000000, 331 + 0x00000000, 332 + 0x00000dc0, 333 + 0x00000000, 334 + 0x00000000, 335 + 0x00000000, 336 + 0x00000d80, 337 + 0x00000000, 338 + 0x00000000, 339 + 0x00000000, 340 + 0x00000df0, 341 + 0x00000000, 342 + 0x00000000, 343 + 0x00000000, 344 + 0x00000de0, 345 + 0x00000000, 346 + 0x00000000, 347 + 0x00000000, 348 + 0x00000dd0, 349 + 0x00000000, 350 + 0x00000000, 351 + 0x00000000, 352 + 0x00000e04, 353 + 0x00000000, 354 + 0x00000000, 355 + 0x00000000, 356 + 0x00000e00, 357 0x00000000, 358 0x00000000, 359 0x00000000,
+59 -38
arch/powerpc/platforms/cell/spufs/spufs.h
··· 40 struct spu_context_ops; 41 struct spu_gang; 42 43 - /* 44 - * This is the state for spu utilization reporting to userspace. 45 - * Because this state is visible to userspace it must never change and needs 46 - * to be kept strictly separate from any internal state kept by the kernel. 47 - */ 48 - enum spuctx_execution_state { 49 - SPUCTX_UTIL_USER = 0, 50 - SPUCTX_UTIL_SYSTEM, 51 - SPUCTX_UTIL_IOWAIT, 52 - SPUCTX_UTIL_LOADED, 53 - SPUCTX_UTIL_MAX 54 }; 55 56 struct spu_context { ··· 85 86 struct list_head gang_list; 87 struct spu_gang *gang; 88 89 /* owner thread */ 90 pid_t tid; ··· 102 /* statistics */ 103 struct { 104 /* updates protected by ctx->state_mutex */ 105 - enum spuctx_execution_state execution_state; 106 - unsigned long tstamp; /* time of last ctx switch */ 107 - unsigned long times[SPUCTX_UTIL_MAX]; 108 unsigned long long vol_ctx_switch; 109 unsigned long long invol_ctx_switch; 110 unsigned long long min_flt; ··· 116 unsigned long long class2_intr_base; /* # at last ctx switch */ 117 unsigned long long libassist; 118 } stats; 119 }; 120 121 struct spu_gang { ··· 127 struct mutex mutex; 128 struct kref kref; 129 int contexts; 130 }; 131 132 struct mfc_dma_command { 133 int32_t pad; /* reserved */ ··· 203 extern struct tree_descr spufs_dir_nosched_contents[]; 204 205 /* system call implementation */ 206 - long spufs_run_spu(struct file *file, 207 - struct spu_context *ctx, u32 *npc, u32 *status); 208 - long spufs_create(struct nameidata *nd, 209 - unsigned int flags, mode_t mode); 210 extern const struct file_operations spufs_context_fops; 211 212 /* gang management */ ··· 217 218 /* fault handling */ 219 int spufs_handle_class1(struct spu_context *ctx); 220 221 /* context management */ 222 extern atomic_t nr_spu_contexts; ··· 242 void spu_forget(struct spu_context *ctx); 243 int spu_acquire_runnable(struct spu_context *ctx, unsigned long flags); 244 void spu_acquire_saved(struct spu_context *ctx); 245 246 int spu_activate(struct spu_context *ctx, unsigned long flags); 247 void spu_deactivate(struct spu_context *ctx); 248 void spu_yield(struct spu_context *ctx); 249 void spu_set_timeslice(struct spu_context *ctx); 250 void spu_update_sched_info(struct spu_context *ctx); 251 void __spu_update_sched_info(struct spu_context *ctx); 252 int __init spu_sched_init(void); 253 - void __exit spu_sched_exit(void); 254 255 extern char *isolated_loader; 256 ··· 310 * line. 311 */ 312 static inline void spuctx_switch_state(struct spu_context *ctx, 313 - enum spuctx_execution_state new_state) 314 { 315 WARN_ON(!mutex_is_locked(&ctx->state_mutex)); 316 317 - if (ctx->stats.execution_state != new_state) { 318 - unsigned long curtime = jiffies; 319 320 - ctx->stats.times[ctx->stats.execution_state] += 321 - curtime - ctx->stats.tstamp; 322 - ctx->stats.tstamp = curtime; 323 - ctx->stats.execution_state = new_state; 324 - } 325 - } 326 - 327 - static inline void spu_switch_state(struct spu *spu, 328 - enum spuctx_execution_state new_state) 329 - { 330 - if (spu->stats.utilization_state != new_state) { 331 - unsigned long curtime = jiffies; 332 - 333 - spu->stats.times[spu->stats.utilization_state] += 334 - curtime - spu->stats.tstamp; 335 spu->stats.tstamp = curtime; 336 - spu->stats.utilization_state = new_state; 337 } 338 } 339
··· 40 struct spu_context_ops; 41 struct spu_gang; 42 43 + enum { 44 + SPU_SCHED_WAS_ACTIVE, /* was active upon spu_acquire_saved() */ 45 + }; 46 + 47 + /* ctx->sched_flags */ 48 + enum { 49 + SPU_SCHED_NOTIFY_ACTIVE, 50 }; 51 52 struct spu_context { ··· 89 90 struct list_head gang_list; 91 struct spu_gang *gang; 92 + struct kref *prof_priv_kref; 93 + void ( * prof_priv_release) (struct kref *kref); 94 95 /* owner thread */ 96 pid_t tid; ··· 104 /* statistics */ 105 struct { 106 /* updates protected by ctx->state_mutex */ 107 + enum spu_utilization_state util_state; 108 + unsigned long long tstamp; /* time of last state switch */ 109 + unsigned long long times[SPU_UTIL_MAX]; 110 unsigned long long vol_ctx_switch; 111 unsigned long long invol_ctx_switch; 112 unsigned long long min_flt; ··· 118 unsigned long long class2_intr_base; /* # at last ctx switch */ 119 unsigned long long libassist; 120 } stats; 121 + 122 + struct list_head aff_list; 123 + int aff_head; 124 + int aff_offset; 125 }; 126 127 struct spu_gang { ··· 125 struct mutex mutex; 126 struct kref kref; 127 int contexts; 128 + 129 + struct spu_context *aff_ref_ctx; 130 + struct list_head aff_list_head; 131 + struct mutex aff_mutex; 132 + int aff_flags; 133 + struct spu *aff_ref_spu; 134 + atomic_t aff_sched_count; 135 }; 136 + 137 + /* Flag bits for spu_gang aff_flags */ 138 + #define AFF_OFFSETS_SET 1 139 + #define AFF_MERGED 2 140 141 struct mfc_dma_command { 142 int32_t pad; /* reserved */ ··· 190 extern struct tree_descr spufs_dir_nosched_contents[]; 191 192 /* system call implementation */ 193 + long spufs_run_spu(struct spu_context *ctx, u32 *npc, u32 *status); 194 + long spufs_create(struct nameidata *nd, unsigned int flags, 195 + mode_t mode, struct file *filp); 196 extern const struct file_operations spufs_context_fops; 197 198 /* gang management */ ··· 205 206 /* fault handling */ 207 int spufs_handle_class1(struct spu_context *ctx); 208 + 209 + /* affinity */ 210 + struct spu *affinity_check(struct spu_context *ctx); 211 212 /* context management */ 213 extern atomic_t nr_spu_contexts; ··· 227 void spu_forget(struct spu_context *ctx); 228 int spu_acquire_runnable(struct spu_context *ctx, unsigned long flags); 229 void spu_acquire_saved(struct spu_context *ctx); 230 + void spu_release_saved(struct spu_context *ctx); 231 232 int spu_activate(struct spu_context *ctx, unsigned long flags); 233 void spu_deactivate(struct spu_context *ctx); 234 void spu_yield(struct spu_context *ctx); 235 + void spu_switch_notify(struct spu *spu, struct spu_context *ctx); 236 void spu_set_timeslice(struct spu_context *ctx); 237 void spu_update_sched_info(struct spu_context *ctx); 238 void __spu_update_sched_info(struct spu_context *ctx); 239 int __init spu_sched_init(void); 240 + void spu_sched_exit(void); 241 242 extern char *isolated_loader; 243 ··· 293 * line. 294 */ 295 static inline void spuctx_switch_state(struct spu_context *ctx, 296 + enum spu_utilization_state new_state) 297 { 298 + unsigned long long curtime; 299 + signed long long delta; 300 + struct timespec ts; 301 + struct spu *spu; 302 + enum spu_utilization_state old_state; 303 + 304 + ktime_get_ts(&ts); 305 + curtime = timespec_to_ns(&ts); 306 + delta = curtime - ctx->stats.tstamp; 307 + 308 WARN_ON(!mutex_is_locked(&ctx->state_mutex)); 309 + WARN_ON(delta < 0); 310 311 + spu = ctx->spu; 312 + old_state = ctx->stats.util_state; 313 + ctx->stats.util_state = new_state; 314 + ctx->stats.tstamp = curtime; 315 316 + /* 317 + * Update the physical SPU utilization statistics. 318 + */ 319 + if (spu) { 320 + ctx->stats.times[old_state] += delta; 321 + spu->stats.times[old_state] += delta; 322 + spu->stats.util_state = new_state; 323 spu->stats.tstamp = curtime; 324 } 325 } 326
+39 -33
arch/powerpc/platforms/cell/spufs/switch.c
··· 180 case MFC_CNTL_SUSPEND_COMPLETE: 181 if (csa) { 182 csa->priv2.mfc_control_RW = 183 - in_be64(&priv2->mfc_control_RW) | 184 MFC_CNTL_SUSPEND_DMA_QUEUE; 185 } 186 break; ··· 190 MFC_CNTL_SUSPEND_DMA_STATUS_MASK) == 191 MFC_CNTL_SUSPEND_COMPLETE); 192 if (csa) { 193 - csa->priv2.mfc_control_RW = 194 - in_be64(&priv2->mfc_control_RW) & 195 - ~MFC_CNTL_SUSPEND_DMA_QUEUE; 196 } 197 break; 198 } ··· 249 * Read MFC_CNTL[Ds]. Update saved copy of 250 * CSA.MFC_CNTL[Ds]. 251 */ 252 - if (in_be64(&priv2->mfc_control_RW) & MFC_CNTL_DECREMENTER_RUNNING) { 253 - csa->priv2.mfc_control_RW |= MFC_CNTL_DECREMENTER_RUNNING; 254 - csa->suspend_time = get_cycles(); 255 - out_be64(&priv2->spu_chnlcntptr_RW, 7ULL); 256 - eieio(); 257 - csa->spu_chnldata_RW[7] = in_be64(&priv2->spu_chnldata_RW); 258 - eieio(); 259 - } else { 260 - csa->priv2.mfc_control_RW &= ~MFC_CNTL_DECREMENTER_RUNNING; 261 - } 262 } 263 264 static inline void halt_mfc_decr(struct spu_state *csa, struct spu *spu) ··· 261 * Write MFC_CNTL[Dh] set to a '1' to halt 262 * the decrementer. 263 */ 264 - out_be64(&priv2->mfc_control_RW, MFC_CNTL_DECREMENTER_HALTED); 265 eieio(); 266 } 267 ··· 606 static inline void save_ch_part1(struct spu_state *csa, struct spu *spu) 607 { 608 struct spu_priv2 __iomem *priv2 = spu->priv2; 609 - u64 idx, ch_indices[7] = { 0UL, 3UL, 4UL, 24UL, 25UL, 27UL }; 610 int i; 611 612 /* Save, Step 42: ··· 617 csa->spu_chnldata_RW[1] = in_be64(&priv2->spu_chnldata_RW); 618 619 /* Save the following CH: [0,3,4,24,25,27] */ 620 - for (i = 0; i < 7; i++) { 621 idx = ch_indices[i]; 622 out_be64(&priv2->spu_chnlcntptr_RW, idx); 623 eieio(); ··· 974 */ 975 } 976 977 - static inline void suspend_mfc(struct spu_state *csa, struct spu *spu) 978 { 979 struct spu_priv2 __iomem *priv2 = spu->priv2; 980 981 /* Restore, Step 7: 982 - * Restore, Step 47. 983 - * Write MFC_Cntl[Dh,Sc]='1','1' to suspend 984 * the queue and halt the decrementer. 985 */ 986 out_be64(&priv2->mfc_control_RW, MFC_CNTL_SUSPEND_DMA_QUEUE | ··· 1081 static inline void reset_ch_part1(struct spu_state *csa, struct spu *spu) 1082 { 1083 struct spu_priv2 __iomem *priv2 = spu->priv2; 1084 - u64 ch_indices[7] = { 0UL, 3UL, 4UL, 24UL, 25UL, 27UL }; 1085 u64 idx; 1086 int i; 1087 ··· 1093 out_be64(&priv2->spu_chnldata_RW, 0UL); 1094 1095 /* Reset the following CH: [0,3,4,24,25,27] */ 1096 - for (i = 0; i < 7; i++) { 1097 idx = ch_indices[i]; 1098 out_be64(&priv2->spu_chnlcntptr_RW, idx); 1099 eieio(); ··· 1280 cycles_t resume_time = get_cycles(); 1281 cycles_t delta_time = resume_time - csa->suspend_time; 1282 1283 csa->lscsa->decr.slot[0] -= delta_time; 1284 } 1285 } 1286 ··· 1395 * 16kb of local storage from CSA. 1396 */ 1397 send_mfc_dma(spu, addr, ls_offset, size, tag, rclass, cmd); 1398 } 1399 1400 static inline void clear_interrupts(struct spu_state *csa, struct spu *spu) ··· 1559 * "wrapped" flag is set, OR in a '1' to 1560 * CSA.SPU_Event_Status[Tm]. 1561 */ 1562 - if (csa->lscsa->decr_status.slot[0] == 1) { 1563 csa->spu_chnldata_RW[0] |= 0x20; 1564 } 1565 - if ((csa->lscsa->decr_status.slot[0] == 1) && 1566 (csa->spu_chnlcnt_RW[0] == 0 && 1567 ((csa->spu_chnldata_RW[2] & 0x20) == 0x0) && 1568 ((csa->spu_chnldata_RW[0] & 0x20) != 0x1))) { ··· 1573 static inline void restore_ch_part1(struct spu_state *csa, struct spu *spu) 1574 { 1575 struct spu_priv2 __iomem *priv2 = spu->priv2; 1576 - u64 idx, ch_indices[7] = { 0UL, 3UL, 4UL, 24UL, 25UL, 27UL }; 1577 int i; 1578 1579 /* Restore, Step 59: 1580 */ 1581 - 1582 - /* Restore CH 1 without count */ 1583 - out_be64(&priv2->spu_chnlcntptr_RW, 1); 1584 - out_be64(&priv2->spu_chnldata_RW, csa->spu_chnldata_RW[1]); 1585 - 1586 - /* Restore the following CH: [0,3,4,24,25,27] */ 1587 - for (i = 0; i < 7; i++) { 1588 idx = ch_indices[i]; 1589 out_be64(&priv2->spu_chnlcntptr_RW, idx); 1590 eieio(); ··· 1938 set_switch_pending(prev, spu); /* Step 5. */ 1939 stop_spu_isolate(spu); /* NEW. */ 1940 remove_other_spu_access(prev, spu); /* Step 6. */ 1941 - suspend_mfc(prev, spu); /* Step 7. */ 1942 wait_suspend_mfc_complete(prev, spu); /* Step 8. */ 1943 if (!suspend_spe(prev, spu)) /* Step 9. */ 1944 clear_spu_status(prev, spu); /* Step 10. */
··· 180 case MFC_CNTL_SUSPEND_COMPLETE: 181 if (csa) { 182 csa->priv2.mfc_control_RW = 183 + MFC_CNTL_SUSPEND_MASK | 184 MFC_CNTL_SUSPEND_DMA_QUEUE; 185 } 186 break; ··· 190 MFC_CNTL_SUSPEND_DMA_STATUS_MASK) == 191 MFC_CNTL_SUSPEND_COMPLETE); 192 if (csa) { 193 + csa->priv2.mfc_control_RW = 0; 194 } 195 break; 196 } ··· 251 * Read MFC_CNTL[Ds]. Update saved copy of 252 * CSA.MFC_CNTL[Ds]. 253 */ 254 + csa->priv2.mfc_control_RW |= 255 + in_be64(&priv2->mfc_control_RW) & MFC_CNTL_DECREMENTER_RUNNING; 256 } 257 258 static inline void halt_mfc_decr(struct spu_state *csa, struct spu *spu) ··· 271 * Write MFC_CNTL[Dh] set to a '1' to halt 272 * the decrementer. 273 */ 274 + out_be64(&priv2->mfc_control_RW, 275 + MFC_CNTL_DECREMENTER_HALTED | MFC_CNTL_SUSPEND_MASK); 276 eieio(); 277 } 278 ··· 615 static inline void save_ch_part1(struct spu_state *csa, struct spu *spu) 616 { 617 struct spu_priv2 __iomem *priv2 = spu->priv2; 618 + u64 idx, ch_indices[] = { 0UL, 3UL, 4UL, 24UL, 25UL, 27UL }; 619 int i; 620 621 /* Save, Step 42: ··· 626 csa->spu_chnldata_RW[1] = in_be64(&priv2->spu_chnldata_RW); 627 628 /* Save the following CH: [0,3,4,24,25,27] */ 629 + for (i = 0; i < ARRAY_SIZE(ch_indices); i++) { 630 idx = ch_indices[i]; 631 out_be64(&priv2->spu_chnlcntptr_RW, idx); 632 eieio(); ··· 983 */ 984 } 985 986 + static inline void suspend_mfc_and_halt_decr(struct spu_state *csa, 987 + struct spu *spu) 988 { 989 struct spu_priv2 __iomem *priv2 = spu->priv2; 990 991 /* Restore, Step 7: 992 + * Write MFC_Cntl[Dh,Sc,Sm]='1','1','0' to suspend 993 * the queue and halt the decrementer. 994 */ 995 out_be64(&priv2->mfc_control_RW, MFC_CNTL_SUSPEND_DMA_QUEUE | ··· 1090 static inline void reset_ch_part1(struct spu_state *csa, struct spu *spu) 1091 { 1092 struct spu_priv2 __iomem *priv2 = spu->priv2; 1093 + u64 ch_indices[] = { 0UL, 3UL, 4UL, 24UL, 25UL, 27UL }; 1094 u64 idx; 1095 int i; 1096 ··· 1102 out_be64(&priv2->spu_chnldata_RW, 0UL); 1103 1104 /* Reset the following CH: [0,3,4,24,25,27] */ 1105 + for (i = 0; i < ARRAY_SIZE(ch_indices); i++) { 1106 idx = ch_indices[i]; 1107 out_be64(&priv2->spu_chnlcntptr_RW, idx); 1108 eieio(); ··· 1289 cycles_t resume_time = get_cycles(); 1290 cycles_t delta_time = resume_time - csa->suspend_time; 1291 1292 + csa->lscsa->decr_status.slot[0] = SPU_DECR_STATUS_RUNNING; 1293 + if (csa->lscsa->decr.slot[0] < delta_time) { 1294 + csa->lscsa->decr_status.slot[0] |= 1295 + SPU_DECR_STATUS_WRAPPED; 1296 + } 1297 + 1298 csa->lscsa->decr.slot[0] -= delta_time; 1299 + } else { 1300 + csa->lscsa->decr_status.slot[0] = 0; 1301 } 1302 } 1303 ··· 1396 * 16kb of local storage from CSA. 1397 */ 1398 send_mfc_dma(spu, addr, ls_offset, size, tag, rclass, cmd); 1399 + } 1400 + 1401 + static inline void suspend_mfc(struct spu_state *csa, struct spu *spu) 1402 + { 1403 + struct spu_priv2 __iomem *priv2 = spu->priv2; 1404 + 1405 + /* Restore, Step 47. 1406 + * Write MFC_Cntl[Sc,Sm]='1','0' to suspend 1407 + * the queue. 1408 + */ 1409 + out_be64(&priv2->mfc_control_RW, MFC_CNTL_SUSPEND_DMA_QUEUE); 1410 + eieio(); 1411 } 1412 1413 static inline void clear_interrupts(struct spu_state *csa, struct spu *spu) ··· 1548 * "wrapped" flag is set, OR in a '1' to 1549 * CSA.SPU_Event_Status[Tm]. 1550 */ 1551 + if (csa->lscsa->decr_status.slot[0] & SPU_DECR_STATUS_WRAPPED) { 1552 csa->spu_chnldata_RW[0] |= 0x20; 1553 } 1554 + if ((csa->lscsa->decr_status.slot[0] & SPU_DECR_STATUS_WRAPPED) && 1555 (csa->spu_chnlcnt_RW[0] == 0 && 1556 ((csa->spu_chnldata_RW[2] & 0x20) == 0x0) && 1557 ((csa->spu_chnldata_RW[0] & 0x20) != 0x1))) { ··· 1562 static inline void restore_ch_part1(struct spu_state *csa, struct spu *spu) 1563 { 1564 struct spu_priv2 __iomem *priv2 = spu->priv2; 1565 + u64 idx, ch_indices[] = { 0UL, 3UL, 4UL, 24UL, 25UL, 27UL }; 1566 int i; 1567 1568 /* Restore, Step 59: 1569 + * Restore the following CH: [0,3,4,24,25,27] 1570 */ 1571 + for (i = 0; i < ARRAY_SIZE(ch_indices); i++) { 1572 idx = ch_indices[i]; 1573 out_be64(&priv2->spu_chnlcntptr_RW, idx); 1574 eieio(); ··· 1932 set_switch_pending(prev, spu); /* Step 5. */ 1933 stop_spu_isolate(spu); /* NEW. */ 1934 remove_other_spu_access(prev, spu); /* Step 6. */ 1935 + suspend_mfc_and_halt_decr(prev, spu); /* Step 7. */ 1936 wait_suspend_mfc_complete(prev, spu); /* Step 8. */ 1937 if (!suspend_spe(prev, spu)) /* Step 9. */ 1938 clear_spu_status(prev, spu); /* Step 10. */
+29 -5
arch/powerpc/platforms/cell/spufs/syscalls.c
··· 47 goto out; 48 49 i = SPUFS_I(filp->f_path.dentry->d_inode); 50 - ret = spufs_run_spu(filp, i->i_ctx, &npc, &status); 51 52 if (put_user(npc, unpc)) 53 ret = -EFAULT; ··· 76 } 77 #endif 78 79 - asmlinkage long sys_spu_create(const char __user *pathname, 80 - unsigned int flags, mode_t mode) 81 { 82 char *tmp; 83 int ret; ··· 90 ret = path_lookup(tmp, LOOKUP_PARENT| 91 LOOKUP_OPEN|LOOKUP_CREATE, &nd); 92 if (!ret) { 93 - ret = spufs_create(&nd, flags, mode); 94 path_release(&nd); 95 } 96 putname(tmp); ··· 99 return ret; 100 } 101 102 struct spufs_calls spufs_calls = { 103 - .create_thread = sys_spu_create, 104 .spu_run = do_spu_run, 105 .owner = THIS_MODULE, 106 };
··· 47 goto out; 48 49 i = SPUFS_I(filp->f_path.dentry->d_inode); 50 + ret = spufs_run_spu(i->i_ctx, &npc, &status); 51 52 if (put_user(npc, unpc)) 53 ret = -EFAULT; ··· 76 } 77 #endif 78 79 + asmlinkage long do_spu_create(const char __user *pathname, unsigned int flags, 80 + mode_t mode, struct file *neighbor) 81 { 82 char *tmp; 83 int ret; ··· 90 ret = path_lookup(tmp, LOOKUP_PARENT| 91 LOOKUP_OPEN|LOOKUP_CREATE, &nd); 92 if (!ret) { 93 + ret = spufs_create(&nd, flags, mode, neighbor); 94 path_release(&nd); 95 } 96 putname(tmp); ··· 99 return ret; 100 } 101 102 + #ifndef MODULE 103 + asmlinkage long sys_spu_create(const char __user *pathname, unsigned int flags, 104 + mode_t mode, int neighbor_fd) 105 + { 106 + int fput_needed; 107 + struct file *neighbor; 108 + long ret; 109 + 110 + if (flags & SPU_CREATE_AFFINITY_SPU) { 111 + ret = -EBADF; 112 + neighbor = fget_light(neighbor_fd, &fput_needed); 113 + if (neighbor) { 114 + ret = do_spu_create(pathname, flags, mode, neighbor); 115 + fput_light(neighbor, fput_needed); 116 + } 117 + } 118 + else { 119 + ret = do_spu_create(pathname, flags, mode, NULL); 120 + } 121 + 122 + return ret; 123 + } 124 + #endif 125 + 126 struct spufs_calls spufs_calls = { 127 + .create_thread = do_spu_create, 128 .spu_run = do_spu_run, 129 .owner = THIS_MODULE, 130 };
+1
arch/powerpc/sysdev/Makefile
··· 17 mv64x60-$(CONFIG_PCI) += mv64x60_pci.o 18 obj-$(CONFIG_MV64X60) += $(mv64x60-y) mv64x60_pic.o mv64x60_dev.o 19 obj-$(CONFIG_RTC_DRV_CMOS) += rtc_cmos_setup.o 20 21 # contains only the suspend handler for time 22 ifeq ($(CONFIG_RTC_CLASS),)
··· 17 mv64x60-$(CONFIG_PCI) += mv64x60_pci.o 18 obj-$(CONFIG_MV64X60) += $(mv64x60-y) mv64x60_pic.o mv64x60_dev.o 19 obj-$(CONFIG_RTC_DRV_CMOS) += rtc_cmos_setup.o 20 + obj-$(CONFIG_AXON_RAM) += axonram.o 21 22 # contains only the suspend handler for time 23 ifeq ($(CONFIG_RTC_CLASS),)
+381
arch/powerpc/sysdev/axonram.c
···
··· 1 + /* 2 + * (C) Copyright IBM Deutschland Entwicklung GmbH 2006 3 + * 4 + * Author: Maxim Shchetynin <maxim@de.ibm.com> 5 + * 6 + * Axon DDR2 device driver. 7 + * It registers one block device per Axon's DDR2 memory bank found on a system. 8 + * Block devices are called axonram?, their major and minor numbers are 9 + * available in /proc/devices, /proc/partitions or in /sys/block/axonram?/dev. 10 + * 11 + * This program is free software; you can redistribute it and/or modify 12 + * it under the terms of the GNU General Public License as published by 13 + * the Free Software Foundation; either version 2, or (at your option) 14 + * any later version. 15 + * 16 + * This program is distributed in the hope that it will be useful, 17 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 + * GNU General Public License for more details. 20 + * 21 + * You should have received a copy of the GNU General Public License 22 + * along with this program; if not, write to the Free Software 23 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 24 + */ 25 + 26 + #include <linux/bio.h> 27 + #include <linux/blkdev.h> 28 + #include <linux/buffer_head.h> 29 + #include <linux/device.h> 30 + #include <linux/errno.h> 31 + #include <linux/fs.h> 32 + #include <linux/genhd.h> 33 + #include <linux/interrupt.h> 34 + #include <linux/io.h> 35 + #include <linux/ioport.h> 36 + #include <linux/irq.h> 37 + #include <linux/irqreturn.h> 38 + #include <linux/kernel.h> 39 + #include <linux/mm.h> 40 + #include <linux/mod_devicetable.h> 41 + #include <linux/module.h> 42 + #include <linux/slab.h> 43 + #include <linux/string.h> 44 + #include <linux/types.h> 45 + #include <asm/of_device.h> 46 + #include <asm/of_platform.h> 47 + #include <asm/page.h> 48 + #include <asm/prom.h> 49 + 50 + #define AXON_RAM_MODULE_NAME "axonram" 51 + #define AXON_RAM_DEVICE_NAME "axonram" 52 + #define AXON_RAM_MINORS_PER_DISK 16 53 + #define AXON_RAM_BLOCK_SHIFT PAGE_SHIFT 54 + #define AXON_RAM_BLOCK_SIZE 1 << AXON_RAM_BLOCK_SHIFT 55 + #define AXON_RAM_SECTOR_SHIFT 9 56 + #define AXON_RAM_SECTOR_SIZE 1 << AXON_RAM_SECTOR_SHIFT 57 + #define AXON_RAM_IRQ_FLAGS IRQF_SHARED | IRQF_TRIGGER_RISING 58 + 59 + struct axon_ram_bank { 60 + struct of_device *device; 61 + struct gendisk *disk; 62 + unsigned int irq_correctable; 63 + unsigned int irq_uncorrectable; 64 + unsigned long ph_addr; 65 + unsigned long io_addr; 66 + unsigned long size; 67 + unsigned long ecc_counter; 68 + }; 69 + 70 + static ssize_t 71 + axon_ram_sysfs_ecc(struct device *dev, struct device_attribute *attr, char *buf) 72 + { 73 + struct of_device *device = to_of_device(dev); 74 + struct axon_ram_bank *bank = device->dev.platform_data; 75 + 76 + BUG_ON(!bank); 77 + 78 + return sprintf(buf, "%ld\n", bank->ecc_counter); 79 + } 80 + 81 + static DEVICE_ATTR(ecc, S_IRUGO, axon_ram_sysfs_ecc, NULL); 82 + 83 + /** 84 + * axon_ram_irq_handler - interrupt handler for Axon RAM ECC 85 + * @irq: interrupt ID 86 + * @dev: pointer to of_device 87 + */ 88 + static irqreturn_t 89 + axon_ram_irq_handler(int irq, void *dev) 90 + { 91 + struct of_device *device = dev; 92 + struct axon_ram_bank *bank = device->dev.platform_data; 93 + 94 + BUG_ON(!bank); 95 + 96 + if (irq == bank->irq_correctable) { 97 + dev_err(&device->dev, "Correctable memory error occured\n"); 98 + bank->ecc_counter++; 99 + return IRQ_HANDLED; 100 + } else if (irq == bank->irq_uncorrectable) { 101 + dev_err(&device->dev, "Uncorrectable memory error occured\n"); 102 + panic("Critical ECC error on %s", device->node->full_name); 103 + } 104 + 105 + return IRQ_NONE; 106 + } 107 + 108 + /** 109 + * axon_ram_make_request - make_request() method for block device 110 + * @queue, @bio: see blk_queue_make_request() 111 + */ 112 + static int 113 + axon_ram_make_request(struct request_queue *queue, struct bio *bio) 114 + { 115 + struct axon_ram_bank *bank = bio->bi_bdev->bd_disk->private_data; 116 + unsigned long phys_mem, phys_end; 117 + void *user_mem; 118 + struct bio_vec *vec; 119 + unsigned int transfered; 120 + unsigned short idx; 121 + int rc = 0; 122 + 123 + phys_mem = bank->io_addr + (bio->bi_sector << AXON_RAM_SECTOR_SHIFT); 124 + phys_end = bank->io_addr + bank->size; 125 + transfered = 0; 126 + bio_for_each_segment(vec, bio, idx) { 127 + if (unlikely(phys_mem + vec->bv_len > phys_end)) { 128 + bio_io_error(bio, bio->bi_size); 129 + rc = -ERANGE; 130 + break; 131 + } 132 + 133 + user_mem = page_address(vec->bv_page) + vec->bv_offset; 134 + if (bio_data_dir(bio) == READ) 135 + memcpy(user_mem, (void *) phys_mem, vec->bv_len); 136 + else 137 + memcpy((void *) phys_mem, user_mem, vec->bv_len); 138 + 139 + phys_mem += vec->bv_len; 140 + transfered += vec->bv_len; 141 + } 142 + bio_endio(bio, transfered, 0); 143 + 144 + return rc; 145 + } 146 + 147 + /** 148 + * axon_ram_direct_access - direct_access() method for block device 149 + * @device, @sector, @data: see block_device_operations method 150 + */ 151 + static int 152 + axon_ram_direct_access(struct block_device *device, sector_t sector, 153 + unsigned long *data) 154 + { 155 + struct axon_ram_bank *bank = device->bd_disk->private_data; 156 + loff_t offset; 157 + 158 + offset = sector << AXON_RAM_SECTOR_SHIFT; 159 + if (offset >= bank->size) { 160 + dev_err(&bank->device->dev, "Access outside of address space\n"); 161 + return -ERANGE; 162 + } 163 + 164 + *data = bank->ph_addr + offset; 165 + 166 + return 0; 167 + } 168 + 169 + static struct block_device_operations axon_ram_devops = { 170 + .owner = THIS_MODULE, 171 + .direct_access = axon_ram_direct_access 172 + }; 173 + 174 + /** 175 + * axon_ram_probe - probe() method for platform driver 176 + * @device, @device_id: see of_platform_driver method 177 + */ 178 + static int 179 + axon_ram_probe(struct of_device *device, const struct of_device_id *device_id) 180 + { 181 + static int axon_ram_bank_id = -1; 182 + struct axon_ram_bank *bank; 183 + struct resource resource; 184 + int rc = 0; 185 + 186 + axon_ram_bank_id++; 187 + 188 + dev_info(&device->dev, "Found memory controller on %s\n", 189 + device->node->full_name); 190 + 191 + bank = kzalloc(sizeof(struct axon_ram_bank), GFP_KERNEL); 192 + if (bank == NULL) { 193 + dev_err(&device->dev, "Out of memory\n"); 194 + rc = -ENOMEM; 195 + goto failed; 196 + } 197 + 198 + device->dev.platform_data = bank; 199 + 200 + bank->device = device; 201 + 202 + if (of_address_to_resource(device->node, 0, &resource) != 0) { 203 + dev_err(&device->dev, "Cannot access device tree\n"); 204 + rc = -EFAULT; 205 + goto failed; 206 + } 207 + 208 + bank->size = resource.end - resource.start + 1; 209 + 210 + if (bank->size == 0) { 211 + dev_err(&device->dev, "No DDR2 memory found for %s%d\n", 212 + AXON_RAM_DEVICE_NAME, axon_ram_bank_id); 213 + rc = -ENODEV; 214 + goto failed; 215 + } 216 + 217 + dev_info(&device->dev, "Register DDR2 memory device %s%d with %luMB\n", 218 + AXON_RAM_DEVICE_NAME, axon_ram_bank_id, bank->size >> 20); 219 + 220 + bank->ph_addr = resource.start; 221 + bank->io_addr = (unsigned long) ioremap_flags( 222 + bank->ph_addr, bank->size, _PAGE_NO_CACHE); 223 + if (bank->io_addr == 0) { 224 + dev_err(&device->dev, "ioremap() failed\n"); 225 + rc = -EFAULT; 226 + goto failed; 227 + } 228 + 229 + bank->disk = alloc_disk(AXON_RAM_MINORS_PER_DISK); 230 + if (bank->disk == NULL) { 231 + dev_err(&device->dev, "Cannot register disk\n"); 232 + rc = -EFAULT; 233 + goto failed; 234 + } 235 + 236 + bank->disk->first_minor = 0; 237 + bank->disk->fops = &axon_ram_devops; 238 + bank->disk->private_data = bank; 239 + bank->disk->driverfs_dev = &device->dev; 240 + 241 + sprintf(bank->disk->disk_name, "%s%d", 242 + AXON_RAM_DEVICE_NAME, axon_ram_bank_id); 243 + bank->disk->major = register_blkdev(0, bank->disk->disk_name); 244 + if (bank->disk->major < 0) { 245 + dev_err(&device->dev, "Cannot register block device\n"); 246 + rc = -EFAULT; 247 + goto failed; 248 + } 249 + 250 + bank->disk->queue = blk_alloc_queue(GFP_KERNEL); 251 + if (bank->disk->queue == NULL) { 252 + dev_err(&device->dev, "Cannot register disk queue\n"); 253 + rc = -EFAULT; 254 + goto failed; 255 + } 256 + 257 + set_capacity(bank->disk, bank->size >> AXON_RAM_SECTOR_SHIFT); 258 + blk_queue_make_request(bank->disk->queue, axon_ram_make_request); 259 + blk_queue_hardsect_size(bank->disk->queue, AXON_RAM_SECTOR_SIZE); 260 + add_disk(bank->disk); 261 + 262 + bank->irq_correctable = irq_of_parse_and_map(device->node, 0); 263 + bank->irq_uncorrectable = irq_of_parse_and_map(device->node, 1); 264 + if ((bank->irq_correctable <= 0) || (bank->irq_uncorrectable <= 0)) { 265 + dev_err(&device->dev, "Cannot access ECC interrupt ID\n"); 266 + rc = -EFAULT; 267 + goto failed; 268 + } 269 + 270 + rc = request_irq(bank->irq_correctable, axon_ram_irq_handler, 271 + AXON_RAM_IRQ_FLAGS, bank->disk->disk_name, device); 272 + if (rc != 0) { 273 + dev_err(&device->dev, "Cannot register ECC interrupt handler\n"); 274 + bank->irq_correctable = bank->irq_uncorrectable = 0; 275 + rc = -EFAULT; 276 + goto failed; 277 + } 278 + 279 + rc = request_irq(bank->irq_uncorrectable, axon_ram_irq_handler, 280 + AXON_RAM_IRQ_FLAGS, bank->disk->disk_name, device); 281 + if (rc != 0) { 282 + dev_err(&device->dev, "Cannot register ECC interrupt handler\n"); 283 + bank->irq_uncorrectable = 0; 284 + rc = -EFAULT; 285 + goto failed; 286 + } 287 + 288 + rc = device_create_file(&device->dev, &dev_attr_ecc); 289 + if (rc != 0) { 290 + dev_err(&device->dev, "Cannot create sysfs file\n"); 291 + rc = -EFAULT; 292 + goto failed; 293 + } 294 + 295 + return 0; 296 + 297 + failed: 298 + if (bank != NULL) { 299 + if (bank->irq_uncorrectable > 0) 300 + free_irq(bank->irq_uncorrectable, device); 301 + if (bank->irq_correctable > 0) 302 + free_irq(bank->irq_correctable, device); 303 + if (bank->disk != NULL) { 304 + if (bank->disk->queue != NULL) 305 + blk_cleanup_queue(bank->disk->queue); 306 + if (bank->disk->major > 0) 307 + unregister_blkdev(bank->disk->major, 308 + bank->disk->disk_name); 309 + del_gendisk(bank->disk); 310 + } 311 + device->dev.platform_data = NULL; 312 + if (bank->io_addr != 0) 313 + iounmap((void __iomem *) bank->io_addr); 314 + kfree(bank); 315 + } 316 + 317 + return rc; 318 + } 319 + 320 + /** 321 + * axon_ram_remove - remove() method for platform driver 322 + * @device: see of_platform_driver method 323 + */ 324 + static int 325 + axon_ram_remove(struct of_device *device) 326 + { 327 + struct axon_ram_bank *bank = device->dev.platform_data; 328 + 329 + BUG_ON(!bank || !bank->disk); 330 + 331 + device_remove_file(&device->dev, &dev_attr_ecc); 332 + free_irq(bank->irq_uncorrectable, device); 333 + free_irq(bank->irq_correctable, device); 334 + blk_cleanup_queue(bank->disk->queue); 335 + unregister_blkdev(bank->disk->major, bank->disk->disk_name); 336 + del_gendisk(bank->disk); 337 + iounmap((void __iomem *) bank->io_addr); 338 + kfree(bank); 339 + 340 + return 0; 341 + } 342 + 343 + static struct of_device_id axon_ram_device_id[] = { 344 + { 345 + .type = "dma-memory" 346 + }, 347 + {} 348 + }; 349 + 350 + static struct of_platform_driver axon_ram_driver = { 351 + .owner = THIS_MODULE, 352 + .name = AXON_RAM_MODULE_NAME, 353 + .match_table = axon_ram_device_id, 354 + .probe = axon_ram_probe, 355 + .remove = axon_ram_remove 356 + }; 357 + 358 + /** 359 + * axon_ram_init 360 + */ 361 + static int __init 362 + axon_ram_init(void) 363 + { 364 + return of_register_platform_driver(&axon_ram_driver); 365 + } 366 + 367 + /** 368 + * axon_ram_exit 369 + */ 370 + static void __exit 371 + axon_ram_exit(void) 372 + { 373 + of_unregister_platform_driver(&axon_ram_driver); 374 + } 375 + 376 + module_init(axon_ram_init); 377 + module_exit(axon_ram_exit); 378 + 379 + MODULE_LICENSE("GPL"); 380 + MODULE_AUTHOR("Maxim Shchetynin <maxim@de.ibm.com>"); 381 + MODULE_DESCRIPTION("Axon DDR2 RAM device driver for IBM Cell BE");
+22 -29
arch/powerpc/sysdev/pmi.c
··· 48 struct work_struct work; 49 }; 50 51 52 static int pmi_irq_handler(int irq, void *dev_id) 53 { 54 - struct pmi_data *data; 55 u8 type; 56 int rc; 57 - 58 - data = dev_id; 59 60 spin_lock(&data->pmi_spinlock); 61 ··· 109 110 static void pmi_notify_handlers(struct work_struct *work) 111 { 112 - struct pmi_data *data; 113 struct pmi_handler *handler; 114 - 115 - data = container_of(work, struct pmi_data, work); 116 117 spin_lock(&data->handler_spinlock); 118 list_for_each_entry(handler, &data->handler, node) { 119 pr_debug(KERN_INFO "pmi: notifying handler %p\n", handler); 120 if (handler->type == data->msg.type) 121 - handler->handle_pmi_message(data->dev, data->msg); 122 } 123 spin_unlock(&data->handler_spinlock); 124 } ··· 124 const struct of_device_id *match) 125 { 126 struct device_node *np = dev->node; 127 - struct pmi_data *data; 128 int rc; 129 130 data = kzalloc(sizeof(struct pmi_data), GFP_KERNEL); 131 if (!data) { ··· 154 155 INIT_WORK(&data->work, pmi_notify_handlers); 156 157 - dev->dev.driver_data = data; 158 data->dev = dev; 159 160 data->irq = irq_of_parse_and_map(np, 0); ··· 163 goto error_cleanup_iomap; 164 } 165 166 - rc = request_irq(data->irq, pmi_irq_handler, 0, "pmi", data); 167 if (rc) { 168 printk(KERN_ERR "pmi: can't request IRQ %d: returned %d\n", 169 data->irq, rc); ··· 186 187 static int pmi_of_remove(struct of_device *dev) 188 { 189 - struct pmi_data *data; 190 struct pmi_handler *handler, *tmp; 191 192 - data = dev->dev.driver_data; 193 - 194 - free_irq(data->irq, data); 195 iounmap(data->pmi_reg); 196 197 spin_lock(&data->handler_spinlock); ··· 198 199 spin_unlock(&data->handler_spinlock); 200 201 - kfree(dev->dev.driver_data); 202 203 return 0; 204 } ··· 223 } 224 module_exit(pmi_module_exit); 225 226 - void pmi_send_message(struct of_device *device, pmi_message_t msg) 227 { 228 - struct pmi_data *data; 229 unsigned long flags; 230 DECLARE_COMPLETION_ONSTACK(completion); 231 232 - data = device->dev.driver_data; 233 234 mutex_lock(&data->msg_mutex); 235 ··· 253 data->completion = NULL; 254 255 mutex_unlock(&data->msg_mutex); 256 } 257 EXPORT_SYMBOL_GPL(pmi_send_message); 258 259 - void pmi_register_handler(struct of_device *device, 260 - struct pmi_handler *handler) 261 { 262 - struct pmi_data *data; 263 - data = device->dev.driver_data; 264 - 265 if (!data) 266 - return; 267 268 spin_lock(&data->handler_spinlock); 269 list_add_tail(&handler->node, &data->handler); 270 spin_unlock(&data->handler_spinlock); 271 } 272 EXPORT_SYMBOL_GPL(pmi_register_handler); 273 274 - void pmi_unregister_handler(struct of_device *device, 275 - struct pmi_handler *handler) 276 { 277 - struct pmi_data *data; 278 - data = device->dev.driver_data; 279 - 280 if (!data) 281 return; 282
··· 48 struct work_struct work; 49 }; 50 51 + static struct pmi_data *data; 52 53 static int pmi_irq_handler(int irq, void *dev_id) 54 { 55 u8 type; 56 int rc; 57 58 spin_lock(&data->pmi_spinlock); 59 ··· 111 112 static void pmi_notify_handlers(struct work_struct *work) 113 { 114 struct pmi_handler *handler; 115 116 spin_lock(&data->handler_spinlock); 117 list_for_each_entry(handler, &data->handler, node) { 118 pr_debug(KERN_INFO "pmi: notifying handler %p\n", handler); 119 if (handler->type == data->msg.type) 120 + handler->handle_pmi_message(data->msg); 121 } 122 spin_unlock(&data->handler_spinlock); 123 } ··· 129 const struct of_device_id *match) 130 { 131 struct device_node *np = dev->node; 132 int rc; 133 + 134 + if (data) { 135 + printk(KERN_ERR "pmi: driver has already been initialized.\n"); 136 + rc = -EBUSY; 137 + goto out; 138 + } 139 140 data = kzalloc(sizeof(struct pmi_data), GFP_KERNEL); 141 if (!data) { ··· 154 155 INIT_WORK(&data->work, pmi_notify_handlers); 156 157 data->dev = dev; 158 159 data->irq = irq_of_parse_and_map(np, 0); ··· 164 goto error_cleanup_iomap; 165 } 166 167 + rc = request_irq(data->irq, pmi_irq_handler, 0, "pmi", NULL); 168 if (rc) { 169 printk(KERN_ERR "pmi: can't request IRQ %d: returned %d\n", 170 data->irq, rc); ··· 187 188 static int pmi_of_remove(struct of_device *dev) 189 { 190 struct pmi_handler *handler, *tmp; 191 192 + free_irq(data->irq, NULL); 193 iounmap(data->pmi_reg); 194 195 spin_lock(&data->handler_spinlock); ··· 202 203 spin_unlock(&data->handler_spinlock); 204 205 + kfree(data); 206 + data = NULL; 207 208 return 0; 209 } ··· 226 } 227 module_exit(pmi_module_exit); 228 229 + int pmi_send_message(pmi_message_t msg) 230 { 231 unsigned long flags; 232 DECLARE_COMPLETION_ONSTACK(completion); 233 234 + if (!data) 235 + return -ENODEV; 236 237 mutex_lock(&data->msg_mutex); 238 ··· 256 data->completion = NULL; 257 258 mutex_unlock(&data->msg_mutex); 259 + 260 + return 0; 261 } 262 EXPORT_SYMBOL_GPL(pmi_send_message); 263 264 + int pmi_register_handler(struct pmi_handler *handler) 265 { 266 if (!data) 267 + return -ENODEV; 268 269 spin_lock(&data->handler_spinlock); 270 list_add_tail(&handler->node, &data->handler); 271 spin_unlock(&data->handler_spinlock); 272 + 273 + return 0; 274 } 275 EXPORT_SYMBOL_GPL(pmi_register_handler); 276 277 + void pmi_unregister_handler(struct pmi_handler *handler) 278 { 279 if (!data) 280 return; 281
+2 -1
drivers/oprofile/buffer_sync.c
··· 26 #include <linux/profile.h> 27 #include <linux/module.h> 28 #include <linux/fs.h> 29 #include <linux/sched.h> 30 - 31 #include "oprofile_stats.h" 32 #include "event_buffer.h" 33 #include "cpu_buffer.h"
··· 26 #include <linux/profile.h> 27 #include <linux/module.h> 28 #include <linux/fs.h> 29 + #include <linux/oprofile.h> 30 #include <linux/sched.h> 31 + 32 #include "oprofile_stats.h" 33 #include "event_buffer.h" 34 #include "cpu_buffer.h"
+1 -19
drivers/oprofile/event_buffer.h
··· 19 20 /* wake up the process sleeping on the event file */ 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 - 38 #define INVALID_COOKIE ~0UL 39 #define NO_COOKIE 0UL 40 41 - /* add data to the event buffer */ 42 - void add_event_entry(unsigned long data); 43 - 44 extern const struct file_operations event_buffer_fops; 45 46 /* mutex between sync_cpu_buffers() and the
··· 19 20 /* wake up the process sleeping on the event file */ 21 void wake_up_buffer_waiter(void); 22 + 23 #define INVALID_COOKIE ~0UL 24 #define NO_COOKIE 0UL 25 26 extern const struct file_operations event_buffer_fops; 27 28 /* mutex between sync_cpu_buffers() and the
+28
drivers/oprofile/oprof.c
··· 53 * us missing task deaths and eventually oopsing 54 * when trying to process the event buffer. 55 */ 56 if ((err = sync_start())) 57 goto out3; 58 59 is_setup = 1; 60 mutex_unlock(&start_mutex); 61 return 0; ··· 133 void oprofile_shutdown(void) 134 { 135 mutex_lock(&start_mutex); 136 sync_stop(); 137 if (oprofile_ops.shutdown) 138 oprofile_ops.shutdown(); 139 is_setup = 0;
··· 53 * us missing task deaths and eventually oopsing 54 * when trying to process the event buffer. 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: 70 if ((err = sync_start())) 71 goto out3; 72 73 + post_sync: 74 is_setup = 1; 75 mutex_unlock(&start_mutex); 76 return 0; ··· 118 void oprofile_shutdown(void) 119 { 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: 133 sync_stop(); 134 + post_sync: 135 if (oprofile_ops.shutdown) 136 oprofile_ops.shutdown(); 137 is_setup = 0;
+6 -4
include/asm-powerpc/oprofile_impl.h
··· 39 40 /* Per-arch configuration */ 41 struct op_powerpc_model { 42 - void (*reg_setup) (struct op_counter_config *, 43 struct op_system_config *, 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 *); 48 void (*stop) (void); 49 void (*global_stop) (void); 50 void (*handle_interrupt) (struct pt_regs *, 51 struct op_counter_config *); 52 int num_counters;
··· 39 40 /* Per-arch configuration */ 41 struct op_powerpc_model { 42 + int (*reg_setup) (struct op_counter_config *, 43 struct op_system_config *, 44 int num_counters); 45 + int (*cpu_setup) (struct op_counter_config *); 46 + int (*start) (struct op_counter_config *); 47 + int (*global_start) (struct op_counter_config *); 48 void (*stop) (void); 49 void (*global_stop) (void); 50 + int (*sync_start)(void); 51 + int (*sync_stop)(void); 52 void (*handle_interrupt) (struct pt_regs *, 53 struct op_counter_config *); 54 int num_counters;
+4 -4
include/asm-powerpc/pmi.h
··· 55 struct pmi_handler { 56 struct list_head node; 57 u8 type; 58 - void (*handle_pmi_message) (struct of_device *, pmi_message_t); 59 }; 60 61 - void pmi_register_handler(struct of_device *, struct pmi_handler *); 62 - void pmi_unregister_handler(struct of_device *, struct pmi_handler *); 63 64 - void pmi_send_message(struct of_device *, pmi_message_t); 65 66 #endif /* __KERNEL__ */ 67 #endif /* _POWERPC_PMI_H */
··· 55 struct pmi_handler { 56 struct list_head node; 57 u8 type; 58 + void (*handle_pmi_message) (pmi_message_t); 59 }; 60 61 + int pmi_register_handler(struct pmi_handler *); 62 + void pmi_unregister_handler(struct pmi_handler *); 63 64 + int pmi_send_message(pmi_message_t); 65 66 #endif /* __KERNEL__ */ 67 #endif /* _POWERPC_PMI_H */
+50 -12
include/asm-powerpc/spu.h
··· 107 struct device_node; 108 109 enum spu_utilization_state { 110 - SPU_UTIL_SYSTEM, 111 SPU_UTIL_USER, 112 SPU_UTIL_IOWAIT, 113 - SPU_UTIL_IDLE, 114 SPU_UTIL_MAX 115 }; 116 ··· 121 unsigned long problem_phys; 122 struct spu_problem __iomem *problem; 123 struct spu_priv2 __iomem *priv2; 124 - struct list_head list; 125 - struct list_head sched_list; 126 struct list_head full_list; 127 int number; 128 unsigned int irqs[3]; 129 u32 node; ··· 137 struct spu_runqueue *rq; 138 unsigned long long timestamp; 139 pid_t pid; 140 int class_0_pending; 141 spinlock_t register_lock; 142 ··· 166 167 struct sys_device sysdev; 168 169 struct { 170 /* protected by interrupt reentrancy */ 171 - enum spu_utilization_state utilization_state; 172 - unsigned long tstamp; /* time of last ctx switch */ 173 - unsigned long times[SPU_UTIL_MAX]; 174 unsigned long long vol_ctx_switch; 175 unsigned long long invol_ctx_switch; 176 unsigned long long min_flt; ··· 185 } stats; 186 }; 187 188 - struct spu *spu_alloc(void); 189 - struct spu *spu_alloc_node(int node); 190 - void spu_free(struct spu *spu); 191 int spu_irq_class_0_bottom(struct spu *spu); 192 int spu_irq_class_1_bottom(struct spu *spu); 193 void spu_irq_setaffinity(struct spu *spu, int cpu); 194 195 extern void spu_invalidate_slbs(struct spu *spu); 196 extern void spu_associate_mm(struct spu *spu, struct mm_struct *mm); ··· 214 /* Calls from the memory management to the SPU */ 215 struct mm_struct; 216 extern void spu_flush_all_slbs(struct mm_struct *mm); 217 218 /* system callbacks from the SPU */ 219 struct spu_syscall_block { ··· 240 struct file; 241 extern struct spufs_calls { 242 asmlinkage long (*create_thread)(const char __user *name, 243 - unsigned int flags, mode_t mode); 244 asmlinkage long (*spu_run)(struct file *filp, __u32 __user *unpc, 245 __u32 __user *ustatus); 246 struct module *owner; ··· 268 #define SPU_CREATE_GANG 0x0002 269 #define SPU_CREATE_NOSCHED 0x0004 270 #define SPU_CREATE_ISOLATE 0x0008 271 272 - #define SPU_CREATE_FLAG_ALL 0x000f /* mask of all valid flags */ 273 274 275 #ifdef CONFIG_SPU_FS_MODULE ··· 440 #define MFC_CNTL_RESUME_DMA_QUEUE (0ull << 0) 441 #define MFC_CNTL_SUSPEND_DMA_QUEUE (1ull << 0) 442 #define MFC_CNTL_SUSPEND_DMA_QUEUE_MASK (1ull << 0) 443 #define MFC_CNTL_NORMAL_DMA_QUEUE_OPERATION (0ull << 8) 444 #define MFC_CNTL_SUSPEND_IN_PROGRESS (1ull << 8) 445 #define MFC_CNTL_SUSPEND_COMPLETE (3ull << 8)
··· 107 struct device_node; 108 109 enum spu_utilization_state { 110 SPU_UTIL_USER, 111 + SPU_UTIL_SYSTEM, 112 SPU_UTIL_IOWAIT, 113 + SPU_UTIL_IDLE_LOADED, 114 SPU_UTIL_MAX 115 }; 116 ··· 121 unsigned long problem_phys; 122 struct spu_problem __iomem *problem; 123 struct spu_priv2 __iomem *priv2; 124 + struct list_head cbe_list; 125 struct list_head full_list; 126 + enum { SPU_FREE, SPU_USED } alloc_state; 127 int number; 128 unsigned int irqs[3]; 129 u32 node; ··· 137 struct spu_runqueue *rq; 138 unsigned long long timestamp; 139 pid_t pid; 140 + pid_t tgid; 141 int class_0_pending; 142 spinlock_t register_lock; 143 ··· 165 166 struct sys_device sysdev; 167 168 + int has_mem_affinity; 169 + struct list_head aff_list; 170 + 171 struct { 172 /* protected by interrupt reentrancy */ 173 + enum spu_utilization_state util_state; 174 + unsigned long long tstamp; 175 + unsigned long long times[SPU_UTIL_MAX]; 176 unsigned long long vol_ctx_switch; 177 unsigned long long invol_ctx_switch; 178 unsigned long long min_flt; ··· 181 } stats; 182 }; 183 184 + struct cbe_spu_info { 185 + struct mutex list_mutex; 186 + struct list_head spus; 187 + int n_spus; 188 + int nr_active; 189 + atomic_t reserved_spus; 190 + }; 191 + 192 + extern struct cbe_spu_info cbe_spu_info[]; 193 + 194 + void spu_init_channels(struct spu *spu); 195 int spu_irq_class_0_bottom(struct spu *spu); 196 int spu_irq_class_1_bottom(struct spu *spu); 197 void spu_irq_setaffinity(struct spu *spu, int cpu); 198 + 199 + #ifdef CONFIG_KEXEC 200 + void crash_register_spus(struct list_head *list); 201 + #else 202 + static inline void crash_register_spus(struct list_head *list) 203 + { 204 + } 205 + #endif 206 207 extern void spu_invalidate_slbs(struct spu *spu); 208 extern void spu_associate_mm(struct spu *spu, struct mm_struct *mm); ··· 194 /* Calls from the memory management to the SPU */ 195 struct mm_struct; 196 extern void spu_flush_all_slbs(struct mm_struct *mm); 197 + 198 + /* This interface allows a profiler (e.g., OProfile) to store a ref 199 + * to spu context information that it creates. This caching technique 200 + * avoids the need to recreate this information after a save/restore operation. 201 + * 202 + * Assumes the caller has already incremented the ref count to 203 + * profile_info; then spu_context_destroy must call kref_put 204 + * on prof_info_kref. 205 + */ 206 + void spu_set_profile_private_kref(struct spu_context *ctx, 207 + struct kref *prof_info_kref, 208 + void ( * prof_info_release) (struct kref *kref)); 209 + 210 + void *spu_get_profile_private_kref(struct spu_context *ctx); 211 212 /* system callbacks from the SPU */ 213 struct spu_syscall_block { ··· 206 struct file; 207 extern struct spufs_calls { 208 asmlinkage long (*create_thread)(const char __user *name, 209 + unsigned int flags, mode_t mode, 210 + struct file *neighbor); 211 asmlinkage long (*spu_run)(struct file *filp, __u32 __user *unpc, 212 __u32 __user *ustatus); 213 struct module *owner; ··· 233 #define SPU_CREATE_GANG 0x0002 234 #define SPU_CREATE_NOSCHED 0x0004 235 #define SPU_CREATE_ISOLATE 0x0008 236 + #define SPU_CREATE_AFFINITY_SPU 0x0010 237 + #define SPU_CREATE_AFFINITY_MEM 0x0020 238 239 + #define SPU_CREATE_FLAG_ALL 0x003f /* mask of all valid flags */ 240 241 242 #ifdef CONFIG_SPU_FS_MODULE ··· 403 #define MFC_CNTL_RESUME_DMA_QUEUE (0ull << 0) 404 #define MFC_CNTL_SUSPEND_DMA_QUEUE (1ull << 0) 405 #define MFC_CNTL_SUSPEND_DMA_QUEUE_MASK (1ull << 0) 406 + #define MFC_CNTL_SUSPEND_MASK (1ull << 4) 407 #define MFC_CNTL_NORMAL_DMA_QUEUE_OPERATION (0ull << 8) 408 #define MFC_CNTL_SUSPEND_IN_PROGRESS (1ull << 8) 409 #define MFC_CNTL_SUSPEND_COMPLETE (3ull << 8)
+7 -1
include/asm-powerpc/spu_csa.h
··· 50 #define SPU_STOPPED_STATUS_P_I 8 51 #define SPU_STOPPED_STATUS_R 9 52 53 #ifndef __ASSEMBLY__ 54 /** 55 * spu_reg128 - generic 128-bit register definition. ··· 69 * @gprs: Array of saved registers. 70 * @fpcr: Saved floating point status control register. 71 * @decr: Saved decrementer value. 72 - * @decr_status: Indicates decrementer run status. 73 * @ppu_mb: Saved PPU mailbox data. 74 * @ppuint_mb: Saved PPU interrupting mailbox data. 75 * @tag_mask: Saved tag group mask.
··· 50 #define SPU_STOPPED_STATUS_P_I 8 51 #define SPU_STOPPED_STATUS_R 9 52 53 + /* 54 + * Definitions for software decrementer status flag. 55 + */ 56 + #define SPU_DECR_STATUS_RUNNING 0x1 57 + #define SPU_DECR_STATUS_WRAPPED 0x2 58 + 59 #ifndef __ASSEMBLY__ 60 /** 61 * spu_reg128 - generic 128-bit register definition. ··· 63 * @gprs: Array of saved registers. 64 * @fpcr: Saved floating point status control register. 65 * @decr: Saved decrementer value. 66 + * @decr_status: Indicates software decrementer status flags. 67 * @ppu_mb: Saved PPU mailbox data. 68 * @ppuint_mb: Saved PPU interrupting mailbox data. 69 * @tag_mask: Saved tag group mask.
+1
include/linux/dcookies.h
··· 12 13 #ifdef CONFIG_PROFILING 14 15 #include <linux/types.h> 16 17 struct dcookie_user;
··· 12 13 #ifdef CONFIG_PROFILING 14 15 + #include <linux/dcache.h> 16 #include <linux/types.h> 17 18 struct dcookie_user;
+2 -1
include/linux/elf-em.h
··· 20 #define EM_PARISC 15 /* HPPA */ 21 #define EM_SPARC32PLUS 18 /* Sun's "v8plus" */ 22 #define EM_PPC 20 /* PowerPC */ 23 - #define EM_PPC64 21 /* PowerPC64 */ 24 #define EM_SH 42 /* SuperH */ 25 #define EM_SPARCV9 43 /* SPARC v9 64-bit */ 26 #define EM_IA_64 50 /* HP/Intel IA-64 */
··· 20 #define EM_PARISC 15 /* HPPA */ 21 #define EM_SPARC32PLUS 18 /* Sun's "v8plus" */ 22 #define EM_PPC 20 /* PowerPC */ 23 + #define EM_PPC64 21 /* PowerPC64 */ 24 + #define EM_SPU 23 /* Cell BE SPU */ 25 #define EM_SH 42 /* SuperH */ 26 #define EM_SPARCV9 43 /* SPARC v9 64-bit */ 27 #define EM_IA_64 50 /* HP/Intel IA-64 */
+35
include/linux/oprofile.h
··· 17 #include <linux/spinlock.h> 18 #include <asm/atomic.h> 19 20 struct super_block; 21 struct dentry; 22 struct file_operations; ··· 55 int (*start)(void); 56 /* Stop delivering interrupts. */ 57 void (*stop)(void); 58 /* Initiate a stack backtrace. Optional. */ 59 void (*backtrace)(struct pt_regs * const regs, unsigned int depth); 60 /* CPU identification string. */ ··· 82 * One-time exit/cleanup for the arch. 83 */ 84 void oprofile_arch_exit(void); 85 86 /** 87 * Add a sample. This may be called from any context. Pass
··· 17 #include <linux/spinlock.h> 18 #include <asm/atomic.h> 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 + 40 struct super_block; 41 struct dentry; 42 struct file_operations; ··· 35 int (*start)(void); 36 /* Stop delivering interrupts. */ 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 + 46 /* Initiate a stack backtrace. Optional. */ 47 void (*backtrace)(struct pt_regs * const regs, unsigned int depth); 48 /* CPU identification string. */ ··· 54 * One-time exit/cleanup for the arch. 55 */ 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); 64 65 /** 66 * Add a sample. This may be called from any context. Pass
+1 -1
include/linux/syscalls.h
··· 549 asmlinkage long sys_spu_run(int fd, __u32 __user *unpc, 550 __u32 __user *ustatus); 551 asmlinkage long sys_spu_create(const char __user *name, 552 - unsigned int flags, mode_t mode); 553 554 asmlinkage long sys_mknodat(int dfd, const char __user * filename, int mode, 555 unsigned dev);
··· 549 asmlinkage long sys_spu_run(int fd, __u32 __user *unpc, 550 __u32 __user *ustatus); 551 asmlinkage long sys_spu_create(const char __user *name, 552 + unsigned int flags, mode_t mode, int fd); 553 554 asmlinkage long sys_mknodat(int dfd, const char __user * filename, int mode, 555 unsigned dev);