xref: /OK3568_Linux_fs/kernel/arch/powerpc/oprofile/cell/spu_task_sync.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Cell Broadband Engine OProfile Support
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * (C) Copyright IBM Corporation 2006
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * Author: Maynard Johnson <maynardj@us.ibm.com>
8*4882a593Smuzhiyun  */
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun /* The purpose of this file is to handle SPU event task switching
11*4882a593Smuzhiyun  * and to record SPU context information into the OProfile
12*4882a593Smuzhiyun  * event buffer.
13*4882a593Smuzhiyun  *
14*4882a593Smuzhiyun  * Additionally, the spu_sync_buffer function is provided as a helper
15*4882a593Smuzhiyun  * for recoding actual SPU program counter samples to the event buffer.
16*4882a593Smuzhiyun  */
17*4882a593Smuzhiyun #include <linux/dcookies.h>
18*4882a593Smuzhiyun #include <linux/kref.h>
19*4882a593Smuzhiyun #include <linux/mm.h>
20*4882a593Smuzhiyun #include <linux/fs.h>
21*4882a593Smuzhiyun #include <linux/file.h>
22*4882a593Smuzhiyun #include <linux/module.h>
23*4882a593Smuzhiyun #include <linux/notifier.h>
24*4882a593Smuzhiyun #include <linux/numa.h>
25*4882a593Smuzhiyun #include <linux/oprofile.h>
26*4882a593Smuzhiyun #include <linux/slab.h>
27*4882a593Smuzhiyun #include <linux/spinlock.h>
28*4882a593Smuzhiyun #include "pr_util.h"
29*4882a593Smuzhiyun 
30*4882a593Smuzhiyun #define RELEASE_ALL 9999
31*4882a593Smuzhiyun 
32*4882a593Smuzhiyun static DEFINE_SPINLOCK(buffer_lock);
33*4882a593Smuzhiyun static DEFINE_SPINLOCK(cache_lock);
34*4882a593Smuzhiyun static int num_spu_nodes;
35*4882a593Smuzhiyun static int spu_prof_num_nodes;
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun struct spu_buffer spu_buff[MAX_NUMNODES * SPUS_PER_NODE];
38*4882a593Smuzhiyun struct delayed_work spu_work;
39*4882a593Smuzhiyun static unsigned max_spu_buff;
40*4882a593Smuzhiyun 
spu_buff_add(unsigned long int value,int spu)41*4882a593Smuzhiyun static void spu_buff_add(unsigned long int value, int spu)
42*4882a593Smuzhiyun {
43*4882a593Smuzhiyun 	/* spu buff is a circular buffer.  Add entries to the
44*4882a593Smuzhiyun 	 * head.  Head is the index to store the next value.
45*4882a593Smuzhiyun 	 * The buffer is full when there is one available entry
46*4882a593Smuzhiyun 	 * in the queue, i.e. head and tail can't be equal.
47*4882a593Smuzhiyun 	 * That way we can tell the difference between the
48*4882a593Smuzhiyun 	 * buffer being full versus empty.
49*4882a593Smuzhiyun 	 *
50*4882a593Smuzhiyun 	 *  ASSUMPTION: the buffer_lock is held when this function
51*4882a593Smuzhiyun 	 *             is called to lock the buffer, head and tail.
52*4882a593Smuzhiyun 	 */
53*4882a593Smuzhiyun 	int full = 1;
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun 	if (spu_buff[spu].head >= spu_buff[spu].tail) {
56*4882a593Smuzhiyun 		if ((spu_buff[spu].head - spu_buff[spu].tail)
57*4882a593Smuzhiyun 		    <  (max_spu_buff - 1))
58*4882a593Smuzhiyun 			full = 0;
59*4882a593Smuzhiyun 
60*4882a593Smuzhiyun 	} else if (spu_buff[spu].tail > spu_buff[spu].head) {
61*4882a593Smuzhiyun 		if ((spu_buff[spu].tail - spu_buff[spu].head)
62*4882a593Smuzhiyun 		    > 1)
63*4882a593Smuzhiyun 			full = 0;
64*4882a593Smuzhiyun 	}
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun 	if (!full) {
67*4882a593Smuzhiyun 		spu_buff[spu].buff[spu_buff[spu].head] = value;
68*4882a593Smuzhiyun 		spu_buff[spu].head++;
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun 		if (spu_buff[spu].head >= max_spu_buff)
71*4882a593Smuzhiyun 			spu_buff[spu].head = 0;
72*4882a593Smuzhiyun 	} else {
73*4882a593Smuzhiyun 		/* From the user's perspective make the SPU buffer
74*4882a593Smuzhiyun 		 * size management/overflow look like we are using
75*4882a593Smuzhiyun 		 * per cpu buffers.  The user uses the same
76*4882a593Smuzhiyun 		 * per cpu parameter to adjust the SPU buffer size.
77*4882a593Smuzhiyun 		 * Increment the sample_lost_overflow to inform
78*4882a593Smuzhiyun 		 * the user the buffer size needs to be increased.
79*4882a593Smuzhiyun 		 */
80*4882a593Smuzhiyun 		oprofile_cpu_buffer_inc_smpl_lost();
81*4882a593Smuzhiyun 	}
82*4882a593Smuzhiyun }
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun /* This function copies the per SPU buffers to the
85*4882a593Smuzhiyun  * OProfile kernel buffer.
86*4882a593Smuzhiyun  */
sync_spu_buff(void)87*4882a593Smuzhiyun static void sync_spu_buff(void)
88*4882a593Smuzhiyun {
89*4882a593Smuzhiyun 	int spu;
90*4882a593Smuzhiyun 	unsigned long flags;
91*4882a593Smuzhiyun 	int curr_head;
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun 	for (spu = 0; spu < num_spu_nodes; spu++) {
94*4882a593Smuzhiyun 		/* In case there was an issue and the buffer didn't
95*4882a593Smuzhiyun 		 * get created skip it.
96*4882a593Smuzhiyun 		 */
97*4882a593Smuzhiyun 		if (spu_buff[spu].buff == NULL)
98*4882a593Smuzhiyun 			continue;
99*4882a593Smuzhiyun 
100*4882a593Smuzhiyun 		/* Hold the lock to make sure the head/tail
101*4882a593Smuzhiyun 		 * doesn't change while spu_buff_add() is
102*4882a593Smuzhiyun 		 * deciding if the buffer is full or not.
103*4882a593Smuzhiyun 		 * Being a little paranoid.
104*4882a593Smuzhiyun 		 */
105*4882a593Smuzhiyun 		spin_lock_irqsave(&buffer_lock, flags);
106*4882a593Smuzhiyun 		curr_head = spu_buff[spu].head;
107*4882a593Smuzhiyun 		spin_unlock_irqrestore(&buffer_lock, flags);
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun 		/* Transfer the current contents to the kernel buffer.
110*4882a593Smuzhiyun 		 * data can still be added to the head of the buffer.
111*4882a593Smuzhiyun 		 */
112*4882a593Smuzhiyun 		oprofile_put_buff(spu_buff[spu].buff,
113*4882a593Smuzhiyun 				  spu_buff[spu].tail,
114*4882a593Smuzhiyun 				  curr_head, max_spu_buff);
115*4882a593Smuzhiyun 
116*4882a593Smuzhiyun 		spin_lock_irqsave(&buffer_lock, flags);
117*4882a593Smuzhiyun 		spu_buff[spu].tail = curr_head;
118*4882a593Smuzhiyun 		spin_unlock_irqrestore(&buffer_lock, flags);
119*4882a593Smuzhiyun 	}
120*4882a593Smuzhiyun 
121*4882a593Smuzhiyun }
122*4882a593Smuzhiyun 
wq_sync_spu_buff(struct work_struct * work)123*4882a593Smuzhiyun static void wq_sync_spu_buff(struct work_struct *work)
124*4882a593Smuzhiyun {
125*4882a593Smuzhiyun 	/* move data from spu buffers to kernel buffer */
126*4882a593Smuzhiyun 	sync_spu_buff();
127*4882a593Smuzhiyun 
128*4882a593Smuzhiyun 	/* only reschedule if profiling is not done */
129*4882a593Smuzhiyun 	if (spu_prof_running)
130*4882a593Smuzhiyun 		schedule_delayed_work(&spu_work, DEFAULT_TIMER_EXPIRE);
131*4882a593Smuzhiyun }
132*4882a593Smuzhiyun 
133*4882a593Smuzhiyun /* Container for caching information about an active SPU task. */
134*4882a593Smuzhiyun struct cached_info {
135*4882a593Smuzhiyun 	struct vma_to_fileoffset_map *map;
136*4882a593Smuzhiyun 	struct spu *the_spu;	/* needed to access pointer to local_store */
137*4882a593Smuzhiyun 	struct kref cache_ref;
138*4882a593Smuzhiyun };
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun static struct cached_info *spu_info[MAX_NUMNODES * 8];
141*4882a593Smuzhiyun 
destroy_cached_info(struct kref * kref)142*4882a593Smuzhiyun static void destroy_cached_info(struct kref *kref)
143*4882a593Smuzhiyun {
144*4882a593Smuzhiyun 	struct cached_info *info;
145*4882a593Smuzhiyun 
146*4882a593Smuzhiyun 	info = container_of(kref, struct cached_info, cache_ref);
147*4882a593Smuzhiyun 	vma_map_free(info->map);
148*4882a593Smuzhiyun 	kfree(info);
149*4882a593Smuzhiyun 	module_put(THIS_MODULE);
150*4882a593Smuzhiyun }
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun /* Return the cached_info for the passed SPU number.
153*4882a593Smuzhiyun  * ATTENTION:  Callers are responsible for obtaining the
154*4882a593Smuzhiyun  *	       cache_lock if needed prior to invoking this function.
155*4882a593Smuzhiyun  */
get_cached_info(struct spu * the_spu,int spu_num)156*4882a593Smuzhiyun static struct cached_info *get_cached_info(struct spu *the_spu, int spu_num)
157*4882a593Smuzhiyun {
158*4882a593Smuzhiyun 	struct kref *ref;
159*4882a593Smuzhiyun 	struct cached_info *ret_info;
160*4882a593Smuzhiyun 
161*4882a593Smuzhiyun 	if (spu_num >= num_spu_nodes) {
162*4882a593Smuzhiyun 		printk(KERN_ERR "SPU_PROF: "
163*4882a593Smuzhiyun 		       "%s, line %d: Invalid index %d into spu info cache\n",
164*4882a593Smuzhiyun 		       __func__, __LINE__, spu_num);
165*4882a593Smuzhiyun 		ret_info = NULL;
166*4882a593Smuzhiyun 		goto out;
167*4882a593Smuzhiyun 	}
168*4882a593Smuzhiyun 	if (!spu_info[spu_num] && the_spu) {
169*4882a593Smuzhiyun 		ref = spu_get_profile_private_kref(the_spu->ctx);
170*4882a593Smuzhiyun 		if (ref) {
171*4882a593Smuzhiyun 			spu_info[spu_num] = container_of(ref, struct cached_info, cache_ref);
172*4882a593Smuzhiyun 			kref_get(&spu_info[spu_num]->cache_ref);
173*4882a593Smuzhiyun 		}
174*4882a593Smuzhiyun 	}
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun 	ret_info = spu_info[spu_num];
177*4882a593Smuzhiyun  out:
178*4882a593Smuzhiyun 	return ret_info;
179*4882a593Smuzhiyun }
180*4882a593Smuzhiyun 
181*4882a593Smuzhiyun 
182*4882a593Smuzhiyun /* Looks for cached info for the passed spu.  If not found, the
183*4882a593Smuzhiyun  * cached info is created for the passed spu.
184*4882a593Smuzhiyun  * Returns 0 for success; otherwise, -1 for error.
185*4882a593Smuzhiyun  */
186*4882a593Smuzhiyun static int
prepare_cached_spu_info(struct spu * spu,unsigned long objectId)187*4882a593Smuzhiyun prepare_cached_spu_info(struct spu *spu, unsigned long objectId)
188*4882a593Smuzhiyun {
189*4882a593Smuzhiyun 	unsigned long flags;
190*4882a593Smuzhiyun 	struct vma_to_fileoffset_map *new_map;
191*4882a593Smuzhiyun 	int retval = 0;
192*4882a593Smuzhiyun 	struct cached_info *info;
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun 	/* We won't bother getting cache_lock here since
195*4882a593Smuzhiyun 	 * don't do anything with the cached_info that's returned.
196*4882a593Smuzhiyun 	 */
197*4882a593Smuzhiyun 	info = get_cached_info(spu, spu->number);
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun 	if (info) {
200*4882a593Smuzhiyun 		pr_debug("Found cached SPU info.\n");
201*4882a593Smuzhiyun 		goto out;
202*4882a593Smuzhiyun 	}
203*4882a593Smuzhiyun 
204*4882a593Smuzhiyun 	/* Create cached_info and set spu_info[spu->number] to point to it.
205*4882a593Smuzhiyun 	 * spu->number is a system-wide value, not a per-node value.
206*4882a593Smuzhiyun 	 */
207*4882a593Smuzhiyun 	info = kzalloc(sizeof(*info), GFP_KERNEL);
208*4882a593Smuzhiyun 	if (!info) {
209*4882a593Smuzhiyun 		printk(KERN_ERR "SPU_PROF: "
210*4882a593Smuzhiyun 		       "%s, line %d: create vma_map failed\n",
211*4882a593Smuzhiyun 		       __func__, __LINE__);
212*4882a593Smuzhiyun 		retval = -ENOMEM;
213*4882a593Smuzhiyun 		goto err_alloc;
214*4882a593Smuzhiyun 	}
215*4882a593Smuzhiyun 	new_map = create_vma_map(spu, objectId);
216*4882a593Smuzhiyun 	if (!new_map) {
217*4882a593Smuzhiyun 		printk(KERN_ERR "SPU_PROF: "
218*4882a593Smuzhiyun 		       "%s, line %d: create vma_map failed\n",
219*4882a593Smuzhiyun 		       __func__, __LINE__);
220*4882a593Smuzhiyun 		retval = -ENOMEM;
221*4882a593Smuzhiyun 		goto err_alloc;
222*4882a593Smuzhiyun 	}
223*4882a593Smuzhiyun 
224*4882a593Smuzhiyun 	pr_debug("Created vma_map\n");
225*4882a593Smuzhiyun 	info->map = new_map;
226*4882a593Smuzhiyun 	info->the_spu = spu;
227*4882a593Smuzhiyun 	kref_init(&info->cache_ref);
228*4882a593Smuzhiyun 	spin_lock_irqsave(&cache_lock, flags);
229*4882a593Smuzhiyun 	spu_info[spu->number] = info;
230*4882a593Smuzhiyun 	/* Increment count before passing off ref to SPUFS. */
231*4882a593Smuzhiyun 	kref_get(&info->cache_ref);
232*4882a593Smuzhiyun 
233*4882a593Smuzhiyun 	/* We increment the module refcount here since SPUFS is
234*4882a593Smuzhiyun 	 * responsible for the final destruction of the cached_info,
235*4882a593Smuzhiyun 	 * and it must be able to access the destroy_cached_info()
236*4882a593Smuzhiyun 	 * function defined in the OProfile module.  We decrement
237*4882a593Smuzhiyun 	 * the module refcount in destroy_cached_info.
238*4882a593Smuzhiyun 	 */
239*4882a593Smuzhiyun 	try_module_get(THIS_MODULE);
240*4882a593Smuzhiyun 	spu_set_profile_private_kref(spu->ctx, &info->cache_ref,
241*4882a593Smuzhiyun 				destroy_cached_info);
242*4882a593Smuzhiyun 	spin_unlock_irqrestore(&cache_lock, flags);
243*4882a593Smuzhiyun 	goto out;
244*4882a593Smuzhiyun 
245*4882a593Smuzhiyun err_alloc:
246*4882a593Smuzhiyun 	kfree(info);
247*4882a593Smuzhiyun out:
248*4882a593Smuzhiyun 	return retval;
249*4882a593Smuzhiyun }
250*4882a593Smuzhiyun 
251*4882a593Smuzhiyun /*
252*4882a593Smuzhiyun  * NOTE:  The caller is responsible for locking the
253*4882a593Smuzhiyun  *	  cache_lock prior to calling this function.
254*4882a593Smuzhiyun  */
release_cached_info(int spu_index)255*4882a593Smuzhiyun static int release_cached_info(int spu_index)
256*4882a593Smuzhiyun {
257*4882a593Smuzhiyun 	int index, end;
258*4882a593Smuzhiyun 
259*4882a593Smuzhiyun 	if (spu_index == RELEASE_ALL) {
260*4882a593Smuzhiyun 		end = num_spu_nodes;
261*4882a593Smuzhiyun 		index = 0;
262*4882a593Smuzhiyun 	} else {
263*4882a593Smuzhiyun 		if (spu_index >= num_spu_nodes) {
264*4882a593Smuzhiyun 			printk(KERN_ERR "SPU_PROF: "
265*4882a593Smuzhiyun 				"%s, line %d: "
266*4882a593Smuzhiyun 				"Invalid index %d into spu info cache\n",
267*4882a593Smuzhiyun 				__func__, __LINE__, spu_index);
268*4882a593Smuzhiyun 			goto out;
269*4882a593Smuzhiyun 		}
270*4882a593Smuzhiyun 		end = spu_index + 1;
271*4882a593Smuzhiyun 		index = spu_index;
272*4882a593Smuzhiyun 	}
273*4882a593Smuzhiyun 	for (; index < end; index++) {
274*4882a593Smuzhiyun 		if (spu_info[index]) {
275*4882a593Smuzhiyun 			kref_put(&spu_info[index]->cache_ref,
276*4882a593Smuzhiyun 				 destroy_cached_info);
277*4882a593Smuzhiyun 			spu_info[index] = NULL;
278*4882a593Smuzhiyun 		}
279*4882a593Smuzhiyun 	}
280*4882a593Smuzhiyun 
281*4882a593Smuzhiyun out:
282*4882a593Smuzhiyun 	return 0;
283*4882a593Smuzhiyun }
284*4882a593Smuzhiyun 
285*4882a593Smuzhiyun /* The source code for fast_get_dcookie was "borrowed"
286*4882a593Smuzhiyun  * from drivers/oprofile/buffer_sync.c.
287*4882a593Smuzhiyun  */
288*4882a593Smuzhiyun 
289*4882a593Smuzhiyun /* Optimisation. We can manage without taking the dcookie sem
290*4882a593Smuzhiyun  * because we cannot reach this code without at least one
291*4882a593Smuzhiyun  * dcookie user still being registered (namely, the reader
292*4882a593Smuzhiyun  * of the event buffer).
293*4882a593Smuzhiyun  */
fast_get_dcookie(const struct path * path)294*4882a593Smuzhiyun static inline unsigned long fast_get_dcookie(const struct path *path)
295*4882a593Smuzhiyun {
296*4882a593Smuzhiyun 	unsigned long cookie;
297*4882a593Smuzhiyun 
298*4882a593Smuzhiyun 	if (path->dentry->d_flags & DCACHE_COOKIE)
299*4882a593Smuzhiyun 		return (unsigned long)path->dentry;
300*4882a593Smuzhiyun 	get_dcookie(path, &cookie);
301*4882a593Smuzhiyun 	return cookie;
302*4882a593Smuzhiyun }
303*4882a593Smuzhiyun 
304*4882a593Smuzhiyun /* Look up the dcookie for the task's mm->exe_file,
305*4882a593Smuzhiyun  * which corresponds loosely to "application name". Also, determine
306*4882a593Smuzhiyun  * the offset for the SPU ELF object.  If computed offset is
307*4882a593Smuzhiyun  * non-zero, it implies an embedded SPU object; otherwise, it's a
308*4882a593Smuzhiyun  * separate SPU binary, in which case we retrieve it's dcookie.
309*4882a593Smuzhiyun  * For the embedded case, we must determine if SPU ELF is embedded
310*4882a593Smuzhiyun  * in the executable application or another file (i.e., shared lib).
311*4882a593Smuzhiyun  * If embedded in a shared lib, we must get the dcookie and return
312*4882a593Smuzhiyun  * that to the caller.
313*4882a593Smuzhiyun  */
314*4882a593Smuzhiyun static unsigned long
get_exec_dcookie_and_offset(struct spu * spu,unsigned int * offsetp,unsigned long * spu_bin_dcookie,unsigned long spu_ref)315*4882a593Smuzhiyun get_exec_dcookie_and_offset(struct spu *spu, unsigned int *offsetp,
316*4882a593Smuzhiyun 			    unsigned long *spu_bin_dcookie,
317*4882a593Smuzhiyun 			    unsigned long spu_ref)
318*4882a593Smuzhiyun {
319*4882a593Smuzhiyun 	unsigned long app_cookie = 0;
320*4882a593Smuzhiyun 	unsigned int my_offset = 0;
321*4882a593Smuzhiyun 	struct vm_area_struct *vma;
322*4882a593Smuzhiyun 	struct file *exe_file;
323*4882a593Smuzhiyun 	struct mm_struct *mm = spu->mm;
324*4882a593Smuzhiyun 
325*4882a593Smuzhiyun 	if (!mm)
326*4882a593Smuzhiyun 		goto out;
327*4882a593Smuzhiyun 
328*4882a593Smuzhiyun 	exe_file = get_mm_exe_file(mm);
329*4882a593Smuzhiyun 	if (exe_file) {
330*4882a593Smuzhiyun 		app_cookie = fast_get_dcookie(&exe_file->f_path);
331*4882a593Smuzhiyun 		pr_debug("got dcookie for %pD\n", exe_file);
332*4882a593Smuzhiyun 		fput(exe_file);
333*4882a593Smuzhiyun 	}
334*4882a593Smuzhiyun 
335*4882a593Smuzhiyun 	mmap_read_lock(mm);
336*4882a593Smuzhiyun 	for (vma = mm->mmap; vma; vma = vma->vm_next) {
337*4882a593Smuzhiyun 		if (vma->vm_start > spu_ref || vma->vm_end <= spu_ref)
338*4882a593Smuzhiyun 			continue;
339*4882a593Smuzhiyun 		my_offset = spu_ref - vma->vm_start;
340*4882a593Smuzhiyun 		if (!vma->vm_file)
341*4882a593Smuzhiyun 			goto fail_no_image_cookie;
342*4882a593Smuzhiyun 
343*4882a593Smuzhiyun 		pr_debug("Found spu ELF at %X(object-id:%lx) for file %pD\n",
344*4882a593Smuzhiyun 			 my_offset, spu_ref, vma->vm_file);
345*4882a593Smuzhiyun 		*offsetp = my_offset;
346*4882a593Smuzhiyun 		break;
347*4882a593Smuzhiyun 	}
348*4882a593Smuzhiyun 
349*4882a593Smuzhiyun 	*spu_bin_dcookie = fast_get_dcookie(&vma->vm_file->f_path);
350*4882a593Smuzhiyun 	pr_debug("got dcookie for %pD\n", vma->vm_file);
351*4882a593Smuzhiyun 
352*4882a593Smuzhiyun 	mmap_read_unlock(mm);
353*4882a593Smuzhiyun 
354*4882a593Smuzhiyun out:
355*4882a593Smuzhiyun 	return app_cookie;
356*4882a593Smuzhiyun 
357*4882a593Smuzhiyun fail_no_image_cookie:
358*4882a593Smuzhiyun 	mmap_read_unlock(mm);
359*4882a593Smuzhiyun 
360*4882a593Smuzhiyun 	printk(KERN_ERR "SPU_PROF: "
361*4882a593Smuzhiyun 		"%s, line %d: Cannot find dcookie for SPU binary\n",
362*4882a593Smuzhiyun 		__func__, __LINE__);
363*4882a593Smuzhiyun 	goto out;
364*4882a593Smuzhiyun }
365*4882a593Smuzhiyun 
366*4882a593Smuzhiyun 
367*4882a593Smuzhiyun 
368*4882a593Smuzhiyun /* This function finds or creates cached context information for the
369*4882a593Smuzhiyun  * passed SPU and records SPU context information into the OProfile
370*4882a593Smuzhiyun  * event buffer.
371*4882a593Smuzhiyun  */
process_context_switch(struct spu * spu,unsigned long objectId)372*4882a593Smuzhiyun static int process_context_switch(struct spu *spu, unsigned long objectId)
373*4882a593Smuzhiyun {
374*4882a593Smuzhiyun 	unsigned long flags;
375*4882a593Smuzhiyun 	int retval;
376*4882a593Smuzhiyun 	unsigned int offset = 0;
377*4882a593Smuzhiyun 	unsigned long spu_cookie = 0, app_dcookie;
378*4882a593Smuzhiyun 
379*4882a593Smuzhiyun 	retval = prepare_cached_spu_info(spu, objectId);
380*4882a593Smuzhiyun 	if (retval)
381*4882a593Smuzhiyun 		goto out;
382*4882a593Smuzhiyun 
383*4882a593Smuzhiyun 	/* Get dcookie first because a mutex_lock is taken in that
384*4882a593Smuzhiyun 	 * code path, so interrupts must not be disabled.
385*4882a593Smuzhiyun 	 */
386*4882a593Smuzhiyun 	app_dcookie = get_exec_dcookie_and_offset(spu, &offset, &spu_cookie, objectId);
387*4882a593Smuzhiyun 	if (!app_dcookie || !spu_cookie) {
388*4882a593Smuzhiyun 		retval  = -ENOENT;
389*4882a593Smuzhiyun 		goto out;
390*4882a593Smuzhiyun 	}
391*4882a593Smuzhiyun 
392*4882a593Smuzhiyun 	/* Record context info in event buffer */
393*4882a593Smuzhiyun 	spin_lock_irqsave(&buffer_lock, flags);
394*4882a593Smuzhiyun 	spu_buff_add(ESCAPE_CODE, spu->number);
395*4882a593Smuzhiyun 	spu_buff_add(SPU_CTX_SWITCH_CODE, spu->number);
396*4882a593Smuzhiyun 	spu_buff_add(spu->number, spu->number);
397*4882a593Smuzhiyun 	spu_buff_add(spu->pid, spu->number);
398*4882a593Smuzhiyun 	spu_buff_add(spu->tgid, spu->number);
399*4882a593Smuzhiyun 	spu_buff_add(app_dcookie, spu->number);
400*4882a593Smuzhiyun 	spu_buff_add(spu_cookie, spu->number);
401*4882a593Smuzhiyun 	spu_buff_add(offset, spu->number);
402*4882a593Smuzhiyun 
403*4882a593Smuzhiyun 	/* Set flag to indicate SPU PC data can now be written out.  If
404*4882a593Smuzhiyun 	 * the SPU program counter data is seen before an SPU context
405*4882a593Smuzhiyun 	 * record is seen, the postprocessing will fail.
406*4882a593Smuzhiyun 	 */
407*4882a593Smuzhiyun 	spu_buff[spu->number].ctx_sw_seen = 1;
408*4882a593Smuzhiyun 
409*4882a593Smuzhiyun 	spin_unlock_irqrestore(&buffer_lock, flags);
410*4882a593Smuzhiyun 	smp_wmb();	/* insure spu event buffer updates are written */
411*4882a593Smuzhiyun 			/* don't want entries intermingled... */
412*4882a593Smuzhiyun out:
413*4882a593Smuzhiyun 	return retval;
414*4882a593Smuzhiyun }
415*4882a593Smuzhiyun 
416*4882a593Smuzhiyun /*
417*4882a593Smuzhiyun  * This function is invoked on either a bind_context or unbind_context.
418*4882a593Smuzhiyun  * If called for an unbind_context, the val arg is 0; otherwise,
419*4882a593Smuzhiyun  * it is the object-id value for the spu context.
420*4882a593Smuzhiyun  * The data arg is of type 'struct spu *'.
421*4882a593Smuzhiyun  */
spu_active_notify(struct notifier_block * self,unsigned long val,void * data)422*4882a593Smuzhiyun static int spu_active_notify(struct notifier_block *self, unsigned long val,
423*4882a593Smuzhiyun 				void *data)
424*4882a593Smuzhiyun {
425*4882a593Smuzhiyun 	int retval;
426*4882a593Smuzhiyun 	unsigned long flags;
427*4882a593Smuzhiyun 	struct spu *the_spu = data;
428*4882a593Smuzhiyun 
429*4882a593Smuzhiyun 	pr_debug("SPU event notification arrived\n");
430*4882a593Smuzhiyun 	if (!val) {
431*4882a593Smuzhiyun 		spin_lock_irqsave(&cache_lock, flags);
432*4882a593Smuzhiyun 		retval = release_cached_info(the_spu->number);
433*4882a593Smuzhiyun 		spin_unlock_irqrestore(&cache_lock, flags);
434*4882a593Smuzhiyun 	} else {
435*4882a593Smuzhiyun 		retval = process_context_switch(the_spu, val);
436*4882a593Smuzhiyun 	}
437*4882a593Smuzhiyun 	return retval;
438*4882a593Smuzhiyun }
439*4882a593Smuzhiyun 
440*4882a593Smuzhiyun static struct notifier_block spu_active = {
441*4882a593Smuzhiyun 	.notifier_call = spu_active_notify,
442*4882a593Smuzhiyun };
443*4882a593Smuzhiyun 
number_of_online_nodes(void)444*4882a593Smuzhiyun static int number_of_online_nodes(void)
445*4882a593Smuzhiyun {
446*4882a593Smuzhiyun         u32 cpu; u32 tmp;
447*4882a593Smuzhiyun         int nodes = 0;
448*4882a593Smuzhiyun         for_each_online_cpu(cpu) {
449*4882a593Smuzhiyun                 tmp = cbe_cpu_to_node(cpu) + 1;
450*4882a593Smuzhiyun                 if (tmp > nodes)
451*4882a593Smuzhiyun                         nodes++;
452*4882a593Smuzhiyun         }
453*4882a593Smuzhiyun         return nodes;
454*4882a593Smuzhiyun }
455*4882a593Smuzhiyun 
oprofile_spu_buff_create(void)456*4882a593Smuzhiyun static int oprofile_spu_buff_create(void)
457*4882a593Smuzhiyun {
458*4882a593Smuzhiyun 	int spu;
459*4882a593Smuzhiyun 
460*4882a593Smuzhiyun 	max_spu_buff = oprofile_get_cpu_buffer_size();
461*4882a593Smuzhiyun 
462*4882a593Smuzhiyun 	for (spu = 0; spu < num_spu_nodes; spu++) {
463*4882a593Smuzhiyun 		/* create circular buffers to store the data in.
464*4882a593Smuzhiyun 		 * use locks to manage accessing the buffers
465*4882a593Smuzhiyun 		 */
466*4882a593Smuzhiyun 		spu_buff[spu].head = 0;
467*4882a593Smuzhiyun 		spu_buff[spu].tail = 0;
468*4882a593Smuzhiyun 
469*4882a593Smuzhiyun 		/*
470*4882a593Smuzhiyun 		 * Create a buffer for each SPU.  Can't reliably
471*4882a593Smuzhiyun 		 * create a single buffer for all spus due to not
472*4882a593Smuzhiyun 		 * enough contiguous kernel memory.
473*4882a593Smuzhiyun 		 */
474*4882a593Smuzhiyun 
475*4882a593Smuzhiyun 		spu_buff[spu].buff = kzalloc((max_spu_buff
476*4882a593Smuzhiyun 					      * sizeof(unsigned long)),
477*4882a593Smuzhiyun 					     GFP_KERNEL);
478*4882a593Smuzhiyun 
479*4882a593Smuzhiyun 		if (!spu_buff[spu].buff) {
480*4882a593Smuzhiyun 			printk(KERN_ERR "SPU_PROF: "
481*4882a593Smuzhiyun 			       "%s, line %d:  oprofile_spu_buff_create "
482*4882a593Smuzhiyun 		       "failed to allocate spu buffer %d.\n",
483*4882a593Smuzhiyun 			       __func__, __LINE__, spu);
484*4882a593Smuzhiyun 
485*4882a593Smuzhiyun 			/* release the spu buffers that have been allocated */
486*4882a593Smuzhiyun 			while (spu >= 0) {
487*4882a593Smuzhiyun 				kfree(spu_buff[spu].buff);
488*4882a593Smuzhiyun 				spu_buff[spu].buff = 0;
489*4882a593Smuzhiyun 				spu--;
490*4882a593Smuzhiyun 			}
491*4882a593Smuzhiyun 			return -ENOMEM;
492*4882a593Smuzhiyun 		}
493*4882a593Smuzhiyun 	}
494*4882a593Smuzhiyun 	return 0;
495*4882a593Smuzhiyun }
496*4882a593Smuzhiyun 
497*4882a593Smuzhiyun /* The main purpose of this function is to synchronize
498*4882a593Smuzhiyun  * OProfile with SPUFS by registering to be notified of
499*4882a593Smuzhiyun  * SPU task switches.
500*4882a593Smuzhiyun  *
501*4882a593Smuzhiyun  * NOTE: When profiling SPUs, we must ensure that only
502*4882a593Smuzhiyun  * spu_sync_start is invoked and not the generic sync_start
503*4882a593Smuzhiyun  * in drivers/oprofile/oprof.c.	 A return value of
504*4882a593Smuzhiyun  * SKIP_GENERIC_SYNC or SYNC_START_ERROR will
505*4882a593Smuzhiyun  * accomplish this.
506*4882a593Smuzhiyun  */
spu_sync_start(void)507*4882a593Smuzhiyun int spu_sync_start(void)
508*4882a593Smuzhiyun {
509*4882a593Smuzhiyun 	int spu;
510*4882a593Smuzhiyun 	int ret = SKIP_GENERIC_SYNC;
511*4882a593Smuzhiyun 	int register_ret;
512*4882a593Smuzhiyun 	unsigned long flags = 0;
513*4882a593Smuzhiyun 
514*4882a593Smuzhiyun 	spu_prof_num_nodes = number_of_online_nodes();
515*4882a593Smuzhiyun 	num_spu_nodes = spu_prof_num_nodes * 8;
516*4882a593Smuzhiyun 	INIT_DELAYED_WORK(&spu_work, wq_sync_spu_buff);
517*4882a593Smuzhiyun 
518*4882a593Smuzhiyun 	/* create buffer for storing the SPU data to put in
519*4882a593Smuzhiyun 	 * the kernel buffer.
520*4882a593Smuzhiyun 	 */
521*4882a593Smuzhiyun 	ret = oprofile_spu_buff_create();
522*4882a593Smuzhiyun 	if (ret)
523*4882a593Smuzhiyun 		goto out;
524*4882a593Smuzhiyun 
525*4882a593Smuzhiyun 	spin_lock_irqsave(&buffer_lock, flags);
526*4882a593Smuzhiyun 	for (spu = 0; spu < num_spu_nodes; spu++) {
527*4882a593Smuzhiyun 		spu_buff_add(ESCAPE_CODE, spu);
528*4882a593Smuzhiyun 		spu_buff_add(SPU_PROFILING_CODE, spu);
529*4882a593Smuzhiyun 		spu_buff_add(num_spu_nodes, spu);
530*4882a593Smuzhiyun 	}
531*4882a593Smuzhiyun 	spin_unlock_irqrestore(&buffer_lock, flags);
532*4882a593Smuzhiyun 
533*4882a593Smuzhiyun 	for (spu = 0; spu < num_spu_nodes; spu++) {
534*4882a593Smuzhiyun 		spu_buff[spu].ctx_sw_seen = 0;
535*4882a593Smuzhiyun 		spu_buff[spu].last_guard_val = 0;
536*4882a593Smuzhiyun 	}
537*4882a593Smuzhiyun 
538*4882a593Smuzhiyun 	/* Register for SPU events  */
539*4882a593Smuzhiyun 	register_ret = spu_switch_event_register(&spu_active);
540*4882a593Smuzhiyun 	if (register_ret) {
541*4882a593Smuzhiyun 		ret = SYNC_START_ERROR;
542*4882a593Smuzhiyun 		goto out;
543*4882a593Smuzhiyun 	}
544*4882a593Smuzhiyun 
545*4882a593Smuzhiyun 	pr_debug("spu_sync_start -- running.\n");
546*4882a593Smuzhiyun out:
547*4882a593Smuzhiyun 	return ret;
548*4882a593Smuzhiyun }
549*4882a593Smuzhiyun 
550*4882a593Smuzhiyun /* Record SPU program counter samples to the oprofile event buffer. */
spu_sync_buffer(int spu_num,unsigned int * samples,int num_samples)551*4882a593Smuzhiyun void spu_sync_buffer(int spu_num, unsigned int *samples,
552*4882a593Smuzhiyun 		     int num_samples)
553*4882a593Smuzhiyun {
554*4882a593Smuzhiyun 	unsigned long long file_offset;
555*4882a593Smuzhiyun 	unsigned long flags;
556*4882a593Smuzhiyun 	int i;
557*4882a593Smuzhiyun 	struct vma_to_fileoffset_map *map;
558*4882a593Smuzhiyun 	struct spu *the_spu;
559*4882a593Smuzhiyun 	unsigned long long spu_num_ll = spu_num;
560*4882a593Smuzhiyun 	unsigned long long spu_num_shifted = spu_num_ll << 32;
561*4882a593Smuzhiyun 	struct cached_info *c_info;
562*4882a593Smuzhiyun 
563*4882a593Smuzhiyun 	/* We need to obtain the cache_lock here because it's
564*4882a593Smuzhiyun 	 * possible that after getting the cached_info, the SPU job
565*4882a593Smuzhiyun 	 * corresponding to this cached_info may end, thus resulting
566*4882a593Smuzhiyun 	 * in the destruction of the cached_info.
567*4882a593Smuzhiyun 	 */
568*4882a593Smuzhiyun 	spin_lock_irqsave(&cache_lock, flags);
569*4882a593Smuzhiyun 	c_info = get_cached_info(NULL, spu_num);
570*4882a593Smuzhiyun 	if (!c_info) {
571*4882a593Smuzhiyun 		/* This legitimately happens when the SPU task ends before all
572*4882a593Smuzhiyun 		 * samples are recorded.
573*4882a593Smuzhiyun 		 * No big deal -- so we just drop a few samples.
574*4882a593Smuzhiyun 		 */
575*4882a593Smuzhiyun 		pr_debug("SPU_PROF: No cached SPU context "
576*4882a593Smuzhiyun 			  "for SPU #%d. Dropping samples.\n", spu_num);
577*4882a593Smuzhiyun 		goto out;
578*4882a593Smuzhiyun 	}
579*4882a593Smuzhiyun 
580*4882a593Smuzhiyun 	map = c_info->map;
581*4882a593Smuzhiyun 	the_spu = c_info->the_spu;
582*4882a593Smuzhiyun 	spin_lock(&buffer_lock);
583*4882a593Smuzhiyun 	for (i = 0; i < num_samples; i++) {
584*4882a593Smuzhiyun 		unsigned int sample = *(samples+i);
585*4882a593Smuzhiyun 		int grd_val = 0;
586*4882a593Smuzhiyun 		file_offset = 0;
587*4882a593Smuzhiyun 		if (sample == 0)
588*4882a593Smuzhiyun 			continue;
589*4882a593Smuzhiyun 		file_offset = vma_map_lookup( map, sample, the_spu, &grd_val);
590*4882a593Smuzhiyun 
591*4882a593Smuzhiyun 		/* If overlays are used by this SPU application, the guard
592*4882a593Smuzhiyun 		 * value is non-zero, indicating which overlay section is in
593*4882a593Smuzhiyun 		 * use.	 We need to discard samples taken during the time
594*4882a593Smuzhiyun 		 * period which an overlay occurs (i.e., guard value changes).
595*4882a593Smuzhiyun 		 */
596*4882a593Smuzhiyun 		if (grd_val && grd_val != spu_buff[spu_num].last_guard_val) {
597*4882a593Smuzhiyun 			spu_buff[spu_num].last_guard_val = grd_val;
598*4882a593Smuzhiyun 			/* Drop the rest of the samples. */
599*4882a593Smuzhiyun 			break;
600*4882a593Smuzhiyun 		}
601*4882a593Smuzhiyun 
602*4882a593Smuzhiyun 		/* We must ensure that the SPU context switch has been written
603*4882a593Smuzhiyun 		 * out before samples for the SPU.  Otherwise, the SPU context
604*4882a593Smuzhiyun 		 * information is not available and the postprocessing of the
605*4882a593Smuzhiyun 		 * SPU PC will fail with no available anonymous map information.
606*4882a593Smuzhiyun 		 */
607*4882a593Smuzhiyun 		if (spu_buff[spu_num].ctx_sw_seen)
608*4882a593Smuzhiyun 			spu_buff_add((file_offset | spu_num_shifted),
609*4882a593Smuzhiyun 					 spu_num);
610*4882a593Smuzhiyun 	}
611*4882a593Smuzhiyun 	spin_unlock(&buffer_lock);
612*4882a593Smuzhiyun out:
613*4882a593Smuzhiyun 	spin_unlock_irqrestore(&cache_lock, flags);
614*4882a593Smuzhiyun }
615*4882a593Smuzhiyun 
616*4882a593Smuzhiyun 
spu_sync_stop(void)617*4882a593Smuzhiyun int spu_sync_stop(void)
618*4882a593Smuzhiyun {
619*4882a593Smuzhiyun 	unsigned long flags = 0;
620*4882a593Smuzhiyun 	int ret;
621*4882a593Smuzhiyun 	int k;
622*4882a593Smuzhiyun 
623*4882a593Smuzhiyun 	ret = spu_switch_event_unregister(&spu_active);
624*4882a593Smuzhiyun 
625*4882a593Smuzhiyun 	if (ret)
626*4882a593Smuzhiyun 		printk(KERN_ERR "SPU_PROF: "
627*4882a593Smuzhiyun 		       "%s, line %d: spu_switch_event_unregister "	\
628*4882a593Smuzhiyun 		       "returned %d\n",
629*4882a593Smuzhiyun 		       __func__, __LINE__, ret);
630*4882a593Smuzhiyun 
631*4882a593Smuzhiyun 	/* flush any remaining data in the per SPU buffers */
632*4882a593Smuzhiyun 	sync_spu_buff();
633*4882a593Smuzhiyun 
634*4882a593Smuzhiyun 	spin_lock_irqsave(&cache_lock, flags);
635*4882a593Smuzhiyun 	ret = release_cached_info(RELEASE_ALL);
636*4882a593Smuzhiyun 	spin_unlock_irqrestore(&cache_lock, flags);
637*4882a593Smuzhiyun 
638*4882a593Smuzhiyun 	/* remove scheduled work queue item rather then waiting
639*4882a593Smuzhiyun 	 * for every queued entry to execute.  Then flush pending
640*4882a593Smuzhiyun 	 * system wide buffer to event buffer.
641*4882a593Smuzhiyun 	 */
642*4882a593Smuzhiyun 	cancel_delayed_work(&spu_work);
643*4882a593Smuzhiyun 
644*4882a593Smuzhiyun 	for (k = 0; k < num_spu_nodes; k++) {
645*4882a593Smuzhiyun 		spu_buff[k].ctx_sw_seen = 0;
646*4882a593Smuzhiyun 
647*4882a593Smuzhiyun 		/*
648*4882a593Smuzhiyun 		 * spu_sys_buff will be null if there was a problem
649*4882a593Smuzhiyun 		 * allocating the buffer.  Only delete if it exists.
650*4882a593Smuzhiyun 		 */
651*4882a593Smuzhiyun 		kfree(spu_buff[k].buff);
652*4882a593Smuzhiyun 		spu_buff[k].buff = 0;
653*4882a593Smuzhiyun 	}
654*4882a593Smuzhiyun 	pr_debug("spu_sync_stop -- done.\n");
655*4882a593Smuzhiyun 	return ret;
656*4882a593Smuzhiyun }
657*4882a593Smuzhiyun 
658