xref: /openbmc/linux/arch/powerpc/platforms/cell/spufs/sched.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
1de6cc651SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
28b3d6663SArnd Bergmann /* sched.c - SPU scheduler.
38b3d6663SArnd Bergmann  *
48b3d6663SArnd Bergmann  * Copyright (C) IBM 2005
58b3d6663SArnd Bergmann  * Author: Mark Nutter <mnutter@us.ibm.com>
68b3d6663SArnd Bergmann  *
7a68cf983SMark Nutter  * 2006-03-31	NUMA domains added.
88b3d6663SArnd Bergmann  */
98b3d6663SArnd Bergmann 
103b3d22cbSArnd Bergmann #undef DEBUG
113b3d22cbSArnd Bergmann 
128b3d6663SArnd Bergmann #include <linux/errno.h>
13174cd4b1SIngo Molnar #include <linux/sched/signal.h>
144f17722cSIngo Molnar #include <linux/sched/loadavg.h>
15993db4b4SIngo Molnar #include <linux/sched/rt.h>
168b3d6663SArnd Bergmann #include <linux/kernel.h>
178b3d6663SArnd Bergmann #include <linux/mm.h>
185a0e3ad6STejun Heo #include <linux/slab.h>
198b3d6663SArnd Bergmann #include <linux/completion.h>
208b3d6663SArnd Bergmann #include <linux/vmalloc.h>
218b3d6663SArnd Bergmann #include <linux/smp.h>
228b3d6663SArnd Bergmann #include <linux/stddef.h>
238b3d6663SArnd Bergmann #include <linux/unistd.h>
24a68cf983SMark Nutter #include <linux/numa.h>
25a68cf983SMark Nutter #include <linux/mutex.h>
2686767277SArnd Bergmann #include <linux/notifier.h>
2737901802SChristoph Hellwig #include <linux/kthread.h>
2865de66f0SChristoph Hellwig #include <linux/pid_namespace.h>
2965de66f0SChristoph Hellwig #include <linux/proc_fs.h>
3065de66f0SChristoph Hellwig #include <linux/seq_file.h>
318b3d6663SArnd Bergmann 
328b3d6663SArnd Bergmann #include <asm/io.h>
338b3d6663SArnd Bergmann #include <asm/mmu_context.h>
348b3d6663SArnd Bergmann #include <asm/spu.h>
358b3d6663SArnd Bergmann #include <asm/spu_csa.h>
36a91942aeSGeoff Levand #include <asm/spu_priv1.h>
378b3d6663SArnd Bergmann #include "spufs.h"
38ae142e0cSChristoph Hellwig #define CREATE_TRACE_POINTS
39ae142e0cSChristoph Hellwig #include "sputrace.h"
408b3d6663SArnd Bergmann 
418b3d6663SArnd Bergmann struct spu_prio_array {
4272cb3608SChristoph Hellwig 	DECLARE_BITMAP(bitmap, MAX_PRIO);
43079cdb61SChristoph Hellwig 	struct list_head runq[MAX_PRIO];
44079cdb61SChristoph Hellwig 	spinlock_t runq_lock;
4565de66f0SChristoph Hellwig 	int nr_waiting;
468b3d6663SArnd Bergmann };
478b3d6663SArnd Bergmann 
4865de66f0SChristoph Hellwig static unsigned long spu_avenrun[3];
49a68cf983SMark Nutter static struct spu_prio_array *spu_prio;
5037901802SChristoph Hellwig static struct task_struct *spusched_task;
5137901802SChristoph Hellwig static struct timer_list spusched_timer;
5290608a29SAegis Lin static struct timer_list spuloadavg_timer;
538b3d6663SArnd Bergmann 
54fe443ef2SChristoph Hellwig /*
55fe443ef2SChristoph Hellwig  * Priority of a normal, non-rt, non-niced'd process (aka nice level 0).
56fe443ef2SChristoph Hellwig  */
57fe443ef2SChristoph Hellwig #define NORMAL_PRIO		120
58fe443ef2SChristoph Hellwig 
59fe443ef2SChristoph Hellwig /*
60fe443ef2SChristoph Hellwig  * Frequency of the spu scheduler tick.  By default we do one SPU scheduler
61fe443ef2SChristoph Hellwig  * tick for every 10 CPU scheduler ticks.
62fe443ef2SChristoph Hellwig  */
63fe443ef2SChristoph Hellwig #define SPUSCHED_TICK		(10)
64fe443ef2SChristoph Hellwig 
65fe443ef2SChristoph Hellwig /*
66fe443ef2SChristoph Hellwig  * These are the 'tuning knobs' of the scheduler:
67fe443ef2SChristoph Hellwig  *
6860e24239SJeremy Kerr  * Minimum timeslice is 5 msecs (or 1 spu scheduler tick, whichever is
6960e24239SJeremy Kerr  * larger), default timeslice is 100 msecs, maximum timeslice is 800 msecs.
70fe443ef2SChristoph Hellwig  */
7160e24239SJeremy Kerr #define MIN_SPU_TIMESLICE	max(5 * HZ / (1000 * SPUSCHED_TICK), 1)
7260e24239SJeremy Kerr #define DEF_SPU_TIMESLICE	(100 * HZ / (1000 * SPUSCHED_TICK))
73fe443ef2SChristoph Hellwig 
74fe443ef2SChristoph Hellwig #define SCALE_PRIO(x, prio) \
759d061ba6SDietmar Eggemann 	max(x * (MAX_PRIO - prio) / (NICE_WIDTH / 2), MIN_SPU_TIMESLICE)
76fe443ef2SChristoph Hellwig 
77fe443ef2SChristoph Hellwig /*
78fe443ef2SChristoph Hellwig  * scale user-nice values [ -20 ... 0 ... 19 ] to time slice values:
79fe443ef2SChristoph Hellwig  * [800ms ... 100ms ... 5ms]
80fe443ef2SChristoph Hellwig  *
81fe443ef2SChristoph Hellwig  * The higher a thread's priority, the bigger timeslices
82fe443ef2SChristoph Hellwig  * it gets during one round of execution. But even the lowest
83fe443ef2SChristoph Hellwig  * priority thread gets MIN_TIMESLICE worth of execution time.
84fe443ef2SChristoph Hellwig  */
spu_set_timeslice(struct spu_context * ctx)85fe443ef2SChristoph Hellwig void spu_set_timeslice(struct spu_context *ctx)
86fe443ef2SChristoph Hellwig {
87fe443ef2SChristoph Hellwig 	if (ctx->prio < NORMAL_PRIO)
88fe443ef2SChristoph Hellwig 		ctx->time_slice = SCALE_PRIO(DEF_SPU_TIMESLICE * 4, ctx->prio);
89fe443ef2SChristoph Hellwig 	else
90fe443ef2SChristoph Hellwig 		ctx->time_slice = SCALE_PRIO(DEF_SPU_TIMESLICE, ctx->prio);
91fe443ef2SChristoph Hellwig }
92fe443ef2SChristoph Hellwig 
932cf2b3b4SChristoph Hellwig /*
942cf2b3b4SChristoph Hellwig  * Update scheduling information from the owning thread.
952cf2b3b4SChristoph Hellwig  */
__spu_update_sched_info(struct spu_context * ctx)962cf2b3b4SChristoph Hellwig void __spu_update_sched_info(struct spu_context *ctx)
972cf2b3b4SChristoph Hellwig {
982cf2b3b4SChristoph Hellwig 	/*
9991569531SLuke Browning 	 * assert that the context is not on the runqueue, so it is safe
10091569531SLuke Browning 	 * to change its scheduling parameters.
10191569531SLuke Browning 	 */
10291569531SLuke Browning 	BUG_ON(!list_empty(&ctx->rq));
10391569531SLuke Browning 
10491569531SLuke Browning 	/*
1059b1d21f8SJulio M. Merino Vidal 	 * 32-Bit assignments are atomic on powerpc, and we don't care about
1069b1d21f8SJulio M. Merino Vidal 	 * memory ordering here because retrieving the controlling thread is
1079b1d21f8SJulio M. Merino Vidal 	 * per definition racy.
108476273adSChristoph Hellwig 	 */
109476273adSChristoph Hellwig 	ctx->tid = current->pid;
110476273adSChristoph Hellwig 
111476273adSChristoph Hellwig 	/*
1122cf2b3b4SChristoph Hellwig 	 * We do our own priority calculations, so we normally want
1139b1d21f8SJulio M. Merino Vidal 	 * ->static_prio to start with. Unfortunately this field
1142cf2b3b4SChristoph Hellwig 	 * contains junk for threads with a realtime scheduling
1152cf2b3b4SChristoph Hellwig 	 * policy so we have to look at ->prio in this case.
1162cf2b3b4SChristoph Hellwig 	 */
1172cf2b3b4SChristoph Hellwig 	if (rt_prio(current->prio))
1182cf2b3b4SChristoph Hellwig 		ctx->prio = current->prio;
1192cf2b3b4SChristoph Hellwig 	else
1202cf2b3b4SChristoph Hellwig 		ctx->prio = current->static_prio;
1212cf2b3b4SChristoph Hellwig 	ctx->policy = current->policy;
122ea1ae594SChristoph Hellwig 
123ea1ae594SChristoph Hellwig 	/*
12491569531SLuke Browning 	 * TO DO: the context may be loaded, so we may need to activate
12591569531SLuke Browning 	 * it again on a different node. But it shouldn't hurt anything
12691569531SLuke Browning 	 * to update its parameters, because we know that the scheduler
12791569531SLuke Browning 	 * is not actively looking at this field, since it is not on the
12891569531SLuke Browning 	 * runqueue. The context will be rescheduled on the proper node
12991569531SLuke Browning 	 * if it is timesliced or preempted.
130ea1ae594SChristoph Hellwig 	 */
1313bd37062SSebastian Andrzej Siewior 	cpumask_copy(&ctx->cpus_allowed, current->cpus_ptr);
1327a214200SLuke Browning 
1337a214200SLuke Browning 	/* Save the current cpu id for spu interrupt routing. */
1347a214200SLuke Browning 	ctx->last_ran = raw_smp_processor_id();
1352cf2b3b4SChristoph Hellwig }
1362cf2b3b4SChristoph Hellwig 
spu_update_sched_info(struct spu_context * ctx)1372cf2b3b4SChristoph Hellwig void spu_update_sched_info(struct spu_context *ctx)
1382cf2b3b4SChristoph Hellwig {
13991569531SLuke Browning 	int node;
1402cf2b3b4SChristoph Hellwig 
14191569531SLuke Browning 	if (ctx->state == SPU_STATE_RUNNABLE) {
14291569531SLuke Browning 		node = ctx->spu->node;
143e65c2f6fSLuke Browning 
144e65c2f6fSLuke Browning 		/*
145e65c2f6fSLuke Browning 		 * Take list_mutex to sync with find_victim().
146e65c2f6fSLuke Browning 		 */
147486acd48SChristoph Hellwig 		mutex_lock(&cbe_spu_info[node].list_mutex);
1482cf2b3b4SChristoph Hellwig 		__spu_update_sched_info(ctx);
149486acd48SChristoph Hellwig 		mutex_unlock(&cbe_spu_info[node].list_mutex);
15091569531SLuke Browning 	} else {
15191569531SLuke Browning 		__spu_update_sched_info(ctx);
15291569531SLuke Browning 	}
1532cf2b3b4SChristoph Hellwig }
1542cf2b3b4SChristoph Hellwig 
__node_allowed(struct spu_context * ctx,int node)155ea1ae594SChristoph Hellwig static int __node_allowed(struct spu_context *ctx, int node)
1568b3d6663SArnd Bergmann {
157ea1ae594SChristoph Hellwig 	if (nr_cpus_node(node)) {
15886c6f274SRusty Russell 		const struct cpumask *mask = cpumask_of_node(node);
1598b3d6663SArnd Bergmann 
16086c6f274SRusty Russell 		if (cpumask_intersects(mask, &ctx->cpus_allowed))
161a68cf983SMark Nutter 			return 1;
1628b3d6663SArnd Bergmann 	}
1638b3d6663SArnd Bergmann 
164ea1ae594SChristoph Hellwig 	return 0;
165ea1ae594SChristoph Hellwig }
166ea1ae594SChristoph Hellwig 
node_allowed(struct spu_context * ctx,int node)167ea1ae594SChristoph Hellwig static int node_allowed(struct spu_context *ctx, int node)
168ea1ae594SChristoph Hellwig {
169ea1ae594SChristoph Hellwig 	int rval;
170ea1ae594SChristoph Hellwig 
171ea1ae594SChristoph Hellwig 	spin_lock(&spu_prio->runq_lock);
172ea1ae594SChristoph Hellwig 	rval = __node_allowed(ctx, node);
173ea1ae594SChristoph Hellwig 	spin_unlock(&spu_prio->runq_lock);
174ea1ae594SChristoph Hellwig 
175ea1ae594SChristoph Hellwig 	return rval;
176ea1ae594SChristoph Hellwig }
177ea1ae594SChristoph Hellwig 
do_notify_spus_active(void)178aed3a8c9SBob Nelson void do_notify_spus_active(void)
17936aaccc1SBob Nelson {
18036aaccc1SBob Nelson 	int node;
18136aaccc1SBob Nelson 
18236aaccc1SBob Nelson 	/*
18336aaccc1SBob Nelson 	 * Wake up the active spu_contexts.
18436aaccc1SBob Nelson 	 */
18536aaccc1SBob Nelson 	for_each_online_node(node) {
18636aaccc1SBob Nelson 		struct spu *spu;
187486acd48SChristoph Hellwig 
188486acd48SChristoph Hellwig 		mutex_lock(&cbe_spu_info[node].list_mutex);
189486acd48SChristoph Hellwig 		list_for_each_entry(spu, &cbe_spu_info[node].spus, cbe_list) {
190486acd48SChristoph Hellwig 			if (spu->alloc_state != SPU_FREE) {
19136aaccc1SBob Nelson 				struct spu_context *ctx = spu->ctx;
192486acd48SChristoph Hellwig 				set_bit(SPU_SCHED_NOTIFY_ACTIVE,
193486acd48SChristoph Hellwig 					&ctx->sched_flags);
194486acd48SChristoph Hellwig 				mb();
19536aaccc1SBob Nelson 				wake_up_all(&ctx->stop_wq);
19636aaccc1SBob Nelson 			}
197486acd48SChristoph Hellwig 		}
198486acd48SChristoph Hellwig 		mutex_unlock(&cbe_spu_info[node].list_mutex);
19936aaccc1SBob Nelson 	}
20036aaccc1SBob Nelson }
20136aaccc1SBob Nelson 
202202557d2SChristoph Hellwig /**
203202557d2SChristoph Hellwig  * spu_bind_context - bind spu context to physical spu
204202557d2SChristoph Hellwig  * @spu:	physical spu to bind to
205202557d2SChristoph Hellwig  * @ctx:	context to bind
206202557d2SChristoph Hellwig  */
spu_bind_context(struct spu * spu,struct spu_context * ctx)207202557d2SChristoph Hellwig static void spu_bind_context(struct spu *spu, struct spu_context *ctx)
2088b3d6663SArnd Bergmann {
209038200cfSChristoph Hellwig 	spu_context_trace(spu_bind_context__enter, ctx, spu);
210038200cfSChristoph Hellwig 
21127ec41d3SAndre Detsch 	spuctx_switch_state(ctx, SPU_UTIL_SYSTEM);
212e9f8a0b6SChristoph Hellwig 
213aa6d5b20SArnd Bergmann 	if (ctx->flags & SPU_CREATE_NOSCHED)
214aa6d5b20SArnd Bergmann 		atomic_inc(&cbe_spu_info[spu->node].reserved_spus);
215aa6d5b20SArnd Bergmann 
216e9f8a0b6SChristoph Hellwig 	ctx->stats.slb_flt_base = spu->stats.slb_flt;
217e9f8a0b6SChristoph Hellwig 	ctx->stats.class2_intr_base = spu->stats.class2_intr;
218e9f8a0b6SChristoph Hellwig 
2192c911a14SLuke Browning 	spu_associate_mm(spu, ctx->owner);
2202c911a14SLuke Browning 
2212c911a14SLuke Browning 	spin_lock_irq(&spu->register_lock);
2228b3d6663SArnd Bergmann 	spu->ctx = ctx;
2238b3d6663SArnd Bergmann 	spu->flags = 0;
2248b3d6663SArnd Bergmann 	ctx->spu = spu;
2258b3d6663SArnd Bergmann 	ctx->ops = &spu_hw_ops;
2268b3d6663SArnd Bergmann 	spu->pid = current->pid;
2271474855dSBob Nelson 	spu->tgid = current->tgid;
2288b3d6663SArnd Bergmann 	spu->ibox_callback = spufs_ibox_callback;
2298b3d6663SArnd Bergmann 	spu->wbox_callback = spufs_wbox_callback;
2305110459fSArnd Bergmann 	spu->stop_callback = spufs_stop_callback;
231a33a7d73SArnd Bergmann 	spu->mfc_callback = spufs_mfc_callback;
2322c911a14SLuke Browning 	spin_unlock_irq(&spu->register_lock);
2332c911a14SLuke Browning 
2345110459fSArnd Bergmann 	spu_unmap_mappings(ctx);
2352c911a14SLuke Browning 
2365158e9b5SChristoph Hellwig 	spu_switch_log_notify(spu, ctx, SWITCH_LOG_START, 0);
2378b3d6663SArnd Bergmann 	spu_restore(&ctx->csa, spu);
2382a911f0bSArnd Bergmann 	spu->timestamp = jiffies;
23981998bafSChristoph Hellwig 	ctx->state = SPU_STATE_RUNNABLE;
24027ec41d3SAndre Detsch 
2412a58aa33SAndre Detsch 	spuctx_switch_state(ctx, SPU_UTIL_USER);
2428b3d6663SArnd Bergmann }
2438b3d6663SArnd Bergmann 
244c5fc8d2aSArnd Bergmann /*
245486acd48SChristoph Hellwig  * Must be used with the list_mutex held.
246c5fc8d2aSArnd Bergmann  */
sched_spu(struct spu * spu)247c5fc8d2aSArnd Bergmann static inline int sched_spu(struct spu *spu)
248c5fc8d2aSArnd Bergmann {
249486acd48SChristoph Hellwig 	BUG_ON(!mutex_is_locked(&cbe_spu_info[spu->node].list_mutex));
250486acd48SChristoph Hellwig 
251c5fc8d2aSArnd Bergmann 	return (!spu->ctx || !(spu->ctx->flags & SPU_CREATE_NOSCHED));
252c5fc8d2aSArnd Bergmann }
253c5fc8d2aSArnd Bergmann 
aff_merge_remaining_ctxs(struct spu_gang * gang)254c5fc8d2aSArnd Bergmann static void aff_merge_remaining_ctxs(struct spu_gang *gang)
255c5fc8d2aSArnd Bergmann {
256c5fc8d2aSArnd Bergmann 	struct spu_context *ctx;
257c5fc8d2aSArnd Bergmann 
258c5fc8d2aSArnd Bergmann 	list_for_each_entry(ctx, &gang->aff_list_head, aff_list) {
259c5fc8d2aSArnd Bergmann 		if (list_empty(&ctx->aff_list))
260c5fc8d2aSArnd Bergmann 			list_add(&ctx->aff_list, &gang->aff_list_head);
261c5fc8d2aSArnd Bergmann 	}
262c5fc8d2aSArnd Bergmann 	gang->aff_flags |= AFF_MERGED;
263c5fc8d2aSArnd Bergmann }
264c5fc8d2aSArnd Bergmann 
aff_set_offsets(struct spu_gang * gang)265c5fc8d2aSArnd Bergmann static void aff_set_offsets(struct spu_gang *gang)
266c5fc8d2aSArnd Bergmann {
267c5fc8d2aSArnd Bergmann 	struct spu_context *ctx;
268c5fc8d2aSArnd Bergmann 	int offset;
269c5fc8d2aSArnd Bergmann 
270c5fc8d2aSArnd Bergmann 	offset = -1;
271c5fc8d2aSArnd Bergmann 	list_for_each_entry_reverse(ctx, &gang->aff_ref_ctx->aff_list,
272c5fc8d2aSArnd Bergmann 								aff_list) {
273c5fc8d2aSArnd Bergmann 		if (&ctx->aff_list == &gang->aff_list_head)
274c5fc8d2aSArnd Bergmann 			break;
275c5fc8d2aSArnd Bergmann 		ctx->aff_offset = offset--;
276c5fc8d2aSArnd Bergmann 	}
277c5fc8d2aSArnd Bergmann 
278c5fc8d2aSArnd Bergmann 	offset = 0;
279c5fc8d2aSArnd Bergmann 	list_for_each_entry(ctx, gang->aff_ref_ctx->aff_list.prev, aff_list) {
280c5fc8d2aSArnd Bergmann 		if (&ctx->aff_list == &gang->aff_list_head)
281c5fc8d2aSArnd Bergmann 			break;
282c5fc8d2aSArnd Bergmann 		ctx->aff_offset = offset++;
283c5fc8d2aSArnd Bergmann 	}
284c5fc8d2aSArnd Bergmann 
285c5fc8d2aSArnd Bergmann 	gang->aff_flags |= AFF_OFFSETS_SET;
286c5fc8d2aSArnd Bergmann }
287c5fc8d2aSArnd Bergmann 
aff_ref_location(struct spu_context * ctx,int mem_aff,int group_size,int lowest_offset)288c5fc8d2aSArnd Bergmann static struct spu *aff_ref_location(struct spu_context *ctx, int mem_aff,
289c5fc8d2aSArnd Bergmann 		 int group_size, int lowest_offset)
290c5fc8d2aSArnd Bergmann {
291c5fc8d2aSArnd Bergmann 	struct spu *spu;
292c5fc8d2aSArnd Bergmann 	int node, n;
293c5fc8d2aSArnd Bergmann 
294c5fc8d2aSArnd Bergmann 	/*
295c5fc8d2aSArnd Bergmann 	 * TODO: A better algorithm could be used to find a good spu to be
296c5fc8d2aSArnd Bergmann 	 *       used as reference location for the ctxs chain.
297c5fc8d2aSArnd Bergmann 	 */
298c5fc8d2aSArnd Bergmann 	node = cpu_to_node(raw_smp_processor_id());
299c5fc8d2aSArnd Bergmann 	for (n = 0; n < MAX_NUMNODES; n++, node++) {
30010baa26cSAndre Detsch 		/*
30110baa26cSAndre Detsch 		 * "available_spus" counts how many spus are not potentially
30210baa26cSAndre Detsch 		 * going to be used by other affinity gangs whose reference
30310baa26cSAndre Detsch 		 * context is already in place. Although this code seeks to
30410baa26cSAndre Detsch 		 * avoid having affinity gangs with a summed amount of
30510baa26cSAndre Detsch 		 * contexts bigger than the amount of spus in the node,
30610baa26cSAndre Detsch 		 * this may happen sporadically. In this case, available_spus
30710baa26cSAndre Detsch 		 * becomes negative, which is harmless.
30810baa26cSAndre Detsch 		 */
309ad1ede12SAndre Detsch 		int available_spus;
310ad1ede12SAndre Detsch 
311c5fc8d2aSArnd Bergmann 		node = (node < MAX_NUMNODES) ? node : 0;
312c5fc8d2aSArnd Bergmann 		if (!node_allowed(ctx, node))
313c5fc8d2aSArnd Bergmann 			continue;
314ad1ede12SAndre Detsch 
315ad1ede12SAndre Detsch 		available_spus = 0;
316486acd48SChristoph Hellwig 		mutex_lock(&cbe_spu_info[node].list_mutex);
317c5fc8d2aSArnd Bergmann 		list_for_each_entry(spu, &cbe_spu_info[node].spus, cbe_list) {
31810baa26cSAndre Detsch 			if (spu->ctx && spu->ctx->gang && !spu->ctx->aff_offset
31910baa26cSAndre Detsch 					&& spu->ctx->gang->aff_ref_spu)
32010baa26cSAndre Detsch 				available_spus -= spu->ctx->gang->contexts;
321ad1ede12SAndre Detsch 			available_spus++;
322ad1ede12SAndre Detsch 		}
323ad1ede12SAndre Detsch 		if (available_spus < ctx->gang->contexts) {
324ad1ede12SAndre Detsch 			mutex_unlock(&cbe_spu_info[node].list_mutex);
325ad1ede12SAndre Detsch 			continue;
326ad1ede12SAndre Detsch 		}
327ad1ede12SAndre Detsch 
328ad1ede12SAndre Detsch 		list_for_each_entry(spu, &cbe_spu_info[node].spus, cbe_list) {
329c5fc8d2aSArnd Bergmann 			if ((!mem_aff || spu->has_mem_affinity) &&
330486acd48SChristoph Hellwig 							sched_spu(spu)) {
331486acd48SChristoph Hellwig 				mutex_unlock(&cbe_spu_info[node].list_mutex);
332c5fc8d2aSArnd Bergmann 				return spu;
333c5fc8d2aSArnd Bergmann 			}
334c5fc8d2aSArnd Bergmann 		}
335486acd48SChristoph Hellwig 		mutex_unlock(&cbe_spu_info[node].list_mutex);
336486acd48SChristoph Hellwig 	}
337c5fc8d2aSArnd Bergmann 	return NULL;
338c5fc8d2aSArnd Bergmann }
339c5fc8d2aSArnd Bergmann 
aff_set_ref_point_location(struct spu_gang * gang)340c5fc8d2aSArnd Bergmann static void aff_set_ref_point_location(struct spu_gang *gang)
341c5fc8d2aSArnd Bergmann {
342c5fc8d2aSArnd Bergmann 	int mem_aff, gs, lowest_offset;
343925f76c5SJulia Lawall 	struct spu_context *tmp, *ctx;
344c5fc8d2aSArnd Bergmann 
345c5fc8d2aSArnd Bergmann 	mem_aff = gang->aff_ref_ctx->flags & SPU_CREATE_AFFINITY_MEM;
346c5fc8d2aSArnd Bergmann 	lowest_offset = 0;
347c5fc8d2aSArnd Bergmann 	gs = 0;
348c5fc8d2aSArnd Bergmann 
349c5fc8d2aSArnd Bergmann 	list_for_each_entry(tmp, &gang->aff_list_head, aff_list)
350c5fc8d2aSArnd Bergmann 		gs++;
351c5fc8d2aSArnd Bergmann 
352c5fc8d2aSArnd Bergmann 	list_for_each_entry_reverse(ctx, &gang->aff_ref_ctx->aff_list,
353c5fc8d2aSArnd Bergmann 								aff_list) {
354c5fc8d2aSArnd Bergmann 		if (&ctx->aff_list == &gang->aff_list_head)
355c5fc8d2aSArnd Bergmann 			break;
356c5fc8d2aSArnd Bergmann 		lowest_offset = ctx->aff_offset;
357c5fc8d2aSArnd Bergmann 	}
358c5fc8d2aSArnd Bergmann 
359683e3ab2SAndre Detsch 	gang->aff_ref_spu = aff_ref_location(gang->aff_ref_ctx, mem_aff, gs,
360683e3ab2SAndre Detsch 							lowest_offset);
361c5fc8d2aSArnd Bergmann }
362c5fc8d2aSArnd Bergmann 
ctx_location(struct spu * ref,int offset,int node)363486acd48SChristoph Hellwig static struct spu *ctx_location(struct spu *ref, int offset, int node)
364c5fc8d2aSArnd Bergmann {
365c5fc8d2aSArnd Bergmann 	struct spu *spu;
366c5fc8d2aSArnd Bergmann 
367c5fc8d2aSArnd Bergmann 	spu = NULL;
368c5fc8d2aSArnd Bergmann 	if (offset >= 0) {
369c5fc8d2aSArnd Bergmann 		list_for_each_entry(spu, ref->aff_list.prev, aff_list) {
370486acd48SChristoph Hellwig 			BUG_ON(spu->node != node);
371c5fc8d2aSArnd Bergmann 			if (offset == 0)
372c5fc8d2aSArnd Bergmann 				break;
373c5fc8d2aSArnd Bergmann 			if (sched_spu(spu))
374c5fc8d2aSArnd Bergmann 				offset--;
375c5fc8d2aSArnd Bergmann 		}
376c5fc8d2aSArnd Bergmann 	} else {
377c5fc8d2aSArnd Bergmann 		list_for_each_entry_reverse(spu, ref->aff_list.next, aff_list) {
378486acd48SChristoph Hellwig 			BUG_ON(spu->node != node);
379c5fc8d2aSArnd Bergmann 			if (offset == 0)
380c5fc8d2aSArnd Bergmann 				break;
381c5fc8d2aSArnd Bergmann 			if (sched_spu(spu))
382c5fc8d2aSArnd Bergmann 				offset++;
383c5fc8d2aSArnd Bergmann 		}
384c5fc8d2aSArnd Bergmann 	}
385486acd48SChristoph Hellwig 
386c5fc8d2aSArnd Bergmann 	return spu;
387c5fc8d2aSArnd Bergmann }
388c5fc8d2aSArnd Bergmann 
389c5fc8d2aSArnd Bergmann /*
390c5fc8d2aSArnd Bergmann  * affinity_check is called each time a context is going to be scheduled.
391c5fc8d2aSArnd Bergmann  * It returns the spu ptr on which the context must run.
392c5fc8d2aSArnd Bergmann  */
has_affinity(struct spu_context * ctx)393486acd48SChristoph Hellwig static int has_affinity(struct spu_context *ctx)
394c5fc8d2aSArnd Bergmann {
395486acd48SChristoph Hellwig 	struct spu_gang *gang = ctx->gang;
396c5fc8d2aSArnd Bergmann 
397c5fc8d2aSArnd Bergmann 	if (list_empty(&ctx->aff_list))
398486acd48SChristoph Hellwig 		return 0;
399486acd48SChristoph Hellwig 
4000855b543SAndre Detsch 	if (atomic_read(&ctx->gang->aff_sched_count) == 0)
4010855b543SAndre Detsch 		ctx->gang->aff_ref_spu = NULL;
4020855b543SAndre Detsch 
403c5fc8d2aSArnd Bergmann 	if (!gang->aff_ref_spu) {
404c5fc8d2aSArnd Bergmann 		if (!(gang->aff_flags & AFF_MERGED))
405c5fc8d2aSArnd Bergmann 			aff_merge_remaining_ctxs(gang);
406c5fc8d2aSArnd Bergmann 		if (!(gang->aff_flags & AFF_OFFSETS_SET))
407c5fc8d2aSArnd Bergmann 			aff_set_offsets(gang);
408c5fc8d2aSArnd Bergmann 		aff_set_ref_point_location(gang);
409c5fc8d2aSArnd Bergmann 	}
410486acd48SChristoph Hellwig 
411486acd48SChristoph Hellwig 	return gang->aff_ref_spu != NULL;
412c5fc8d2aSArnd Bergmann }
413c5fc8d2aSArnd Bergmann 
414202557d2SChristoph Hellwig /**
415202557d2SChristoph Hellwig  * spu_unbind_context - unbind spu context from physical spu
416202557d2SChristoph Hellwig  * @spu:	physical spu to unbind from
417202557d2SChristoph Hellwig  * @ctx:	context to unbind
418202557d2SChristoph Hellwig  */
spu_unbind_context(struct spu * spu,struct spu_context * ctx)419678b2ff1SChristoph Hellwig static void spu_unbind_context(struct spu *spu, struct spu_context *ctx)
4208b3d6663SArnd Bergmann {
421028fda0aSLuke Browning 	u32 status;
422028fda0aSLuke Browning 
423038200cfSChristoph Hellwig 	spu_context_trace(spu_unbind_context__enter, ctx, spu);
424038200cfSChristoph Hellwig 
42527ec41d3SAndre Detsch 	spuctx_switch_state(ctx, SPU_UTIL_SYSTEM);
426fe2f896dSChristoph Hellwig 
427aa6d5b20SArnd Bergmann  	if (spu->ctx->flags & SPU_CREATE_NOSCHED)
428aa6d5b20SArnd Bergmann 		atomic_dec(&cbe_spu_info[spu->node].reserved_spus);
42936ddbb13SAndre Detsch 
4300855b543SAndre Detsch 	if (ctx->gang)
43134318c25SAndre Detsch 		/*
43234318c25SAndre Detsch 		 * If ctx->gang->aff_sched_count is positive, SPU affinity is
43334318c25SAndre Detsch 		 * being considered in this gang. Using atomic_dec_if_positive
43434318c25SAndre Detsch 		 * allow us to skip an explicit check for affinity in this gang
43534318c25SAndre Detsch 		 */
4360855b543SAndre Detsch 		atomic_dec_if_positive(&ctx->gang->aff_sched_count);
43736ddbb13SAndre Detsch 
4385110459fSArnd Bergmann 	spu_unmap_mappings(ctx);
4398b3d6663SArnd Bergmann 	spu_save(&ctx->csa, spu);
4405158e9b5SChristoph Hellwig 	spu_switch_log_notify(spu, ctx, SWITCH_LOG_STOP, 0);
4412c911a14SLuke Browning 
4422c911a14SLuke Browning 	spin_lock_irq(&spu->register_lock);
4432a911f0bSArnd Bergmann 	spu->timestamp = jiffies;
4448b3d6663SArnd Bergmann 	ctx->state = SPU_STATE_SAVED;
4458b3d6663SArnd Bergmann 	spu->ibox_callback = NULL;
4468b3d6663SArnd Bergmann 	spu->wbox_callback = NULL;
4475110459fSArnd Bergmann 	spu->stop_callback = NULL;
448a33a7d73SArnd Bergmann 	spu->mfc_callback = NULL;
4498b3d6663SArnd Bergmann 	spu->pid = 0;
4501474855dSBob Nelson 	spu->tgid = 0;
4518b3d6663SArnd Bergmann 	ctx->ops = &spu_backing_ops;
4522a911f0bSArnd Bergmann 	spu->flags = 0;
4538b3d6663SArnd Bergmann 	spu->ctx = NULL;
4542c911a14SLuke Browning 	spin_unlock_irq(&spu->register_lock);
4552c911a14SLuke Browning 
4562c911a14SLuke Browning 	spu_associate_mm(spu, NULL);
457e9f8a0b6SChristoph Hellwig 
458e9f8a0b6SChristoph Hellwig 	ctx->stats.slb_flt +=
459e9f8a0b6SChristoph Hellwig 		(spu->stats.slb_flt - ctx->stats.slb_flt_base);
460e9f8a0b6SChristoph Hellwig 	ctx->stats.class2_intr +=
461e9f8a0b6SChristoph Hellwig 		(spu->stats.class2_intr - ctx->stats.class2_intr_base);
46227ec41d3SAndre Detsch 
46327ec41d3SAndre Detsch 	/* This maps the underlying spu state to idle */
46427ec41d3SAndre Detsch 	spuctx_switch_state(ctx, SPU_UTIL_IDLE_LOADED);
46527ec41d3SAndre Detsch 	ctx->spu = NULL;
466028fda0aSLuke Browning 
467028fda0aSLuke Browning 	if (spu_stopped(ctx, &status))
468028fda0aSLuke Browning 		wake_up_all(&ctx->stop_wq);
4698b3d6663SArnd Bergmann }
4708b3d6663SArnd Bergmann 
471079cdb61SChristoph Hellwig /**
472079cdb61SChristoph Hellwig  * spu_add_to_rq - add a context to the runqueue
473079cdb61SChristoph Hellwig  * @ctx:       context to add
474079cdb61SChristoph Hellwig  */
__spu_add_to_rq(struct spu_context * ctx)4754e0f4ed0SLuke Browning static void __spu_add_to_rq(struct spu_context *ctx)
4762a911f0bSArnd Bergmann {
47727449971SChristoph Hellwig 	/*
47827449971SChristoph Hellwig 	 * Unfortunately this code path can be called from multiple threads
47927449971SChristoph Hellwig 	 * on behalf of a single context due to the way the problem state
48027449971SChristoph Hellwig 	 * mmap support works.
48127449971SChristoph Hellwig 	 *
48227449971SChristoph Hellwig 	 * Fortunately we need to wake up all these threads at the same time
48327449971SChristoph Hellwig 	 * and can simply skip the runqueue addition for every but the first
48427449971SChristoph Hellwig 	 * thread getting into this codepath.
48527449971SChristoph Hellwig 	 *
48627449971SChristoph Hellwig 	 * It's still quite hacky, and long-term we should proxy all other
48727449971SChristoph Hellwig 	 * threads through the owner thread so that spu_run is in control
48827449971SChristoph Hellwig 	 * of all the scheduling activity for a given context.
48927449971SChristoph Hellwig 	 */
49027449971SChristoph Hellwig 	if (list_empty(&ctx->rq)) {
49127449971SChristoph Hellwig 		list_add_tail(&ctx->rq, &spu_prio->runq[ctx->prio]);
49227449971SChristoph Hellwig 		set_bit(ctx->prio, spu_prio->bitmap);
493c77239b8SChristoph Hellwig 		if (!spu_prio->nr_waiting++)
49474019224SIngo Molnar 			mod_timer(&spusched_timer, jiffies + SPUSCHED_TICK);
495a68cf983SMark Nutter 	}
49627449971SChristoph Hellwig }
4972a911f0bSArnd Bergmann 
spu_add_to_rq(struct spu_context * ctx)498e65c2f6fSLuke Browning static void spu_add_to_rq(struct spu_context *ctx)
499e65c2f6fSLuke Browning {
500e65c2f6fSLuke Browning 	spin_lock(&spu_prio->runq_lock);
501e65c2f6fSLuke Browning 	__spu_add_to_rq(ctx);
502e65c2f6fSLuke Browning 	spin_unlock(&spu_prio->runq_lock);
503e65c2f6fSLuke Browning }
504e65c2f6fSLuke Browning 
__spu_del_from_rq(struct spu_context * ctx)5054e0f4ed0SLuke Browning static void __spu_del_from_rq(struct spu_context *ctx)
506a475c2f4SChristoph Hellwig {
5074e0f4ed0SLuke Browning 	int prio = ctx->prio;
5084e0f4ed0SLuke Browning 
50965de66f0SChristoph Hellwig 	if (!list_empty(&ctx->rq)) {
510c77239b8SChristoph Hellwig 		if (!--spu_prio->nr_waiting)
511c77239b8SChristoph Hellwig 			del_timer(&spusched_timer);
512a475c2f4SChristoph Hellwig 		list_del_init(&ctx->rq);
513c77239b8SChristoph Hellwig 
514a475c2f4SChristoph Hellwig 		if (list_empty(&spu_prio->runq[prio]))
5154e0f4ed0SLuke Browning 			clear_bit(prio, spu_prio->bitmap);
5162a911f0bSArnd Bergmann 	}
517c77239b8SChristoph Hellwig }
518a68cf983SMark Nutter 
spu_del_from_rq(struct spu_context * ctx)519e65c2f6fSLuke Browning void spu_del_from_rq(struct spu_context *ctx)
520e65c2f6fSLuke Browning {
521e65c2f6fSLuke Browning 	spin_lock(&spu_prio->runq_lock);
522e65c2f6fSLuke Browning 	__spu_del_from_rq(ctx);
523e65c2f6fSLuke Browning 	spin_unlock(&spu_prio->runq_lock);
524e65c2f6fSLuke Browning }
525e65c2f6fSLuke Browning 
spu_prio_wait(struct spu_context * ctx)526079cdb61SChristoph Hellwig static void spu_prio_wait(struct spu_context *ctx)
527079cdb61SChristoph Hellwig {
528a68cf983SMark Nutter 	DEFINE_WAIT(wait);
529a68cf983SMark Nutter 
530e65c2f6fSLuke Browning 	/*
531e65c2f6fSLuke Browning 	 * The caller must explicitly wait for a context to be loaded
532e65c2f6fSLuke Browning 	 * if the nosched flag is set.  If NOSCHED is not set, the caller
533e65c2f6fSLuke Browning 	 * queues the context and waits for an spu event or error.
534e65c2f6fSLuke Browning 	 */
535e65c2f6fSLuke Browning 	BUG_ON(!(ctx->flags & SPU_CREATE_NOSCHED));
536e65c2f6fSLuke Browning 
5374e0f4ed0SLuke Browning 	spin_lock(&spu_prio->runq_lock);
538079cdb61SChristoph Hellwig 	prepare_to_wait_exclusive(&ctx->stop_wq, &wait, TASK_INTERRUPTIBLE);
539a68cf983SMark Nutter 	if (!signal_pending(current)) {
5404e0f4ed0SLuke Browning 		__spu_add_to_rq(ctx);
5414e0f4ed0SLuke Browning 		spin_unlock(&spu_prio->runq_lock);
542650f8b02SChristoph Hellwig 		mutex_unlock(&ctx->state_mutex);
543a68cf983SMark Nutter 		schedule();
544650f8b02SChristoph Hellwig 		mutex_lock(&ctx->state_mutex);
5454e0f4ed0SLuke Browning 		spin_lock(&spu_prio->runq_lock);
5464e0f4ed0SLuke Browning 		__spu_del_from_rq(ctx);
5472a911f0bSArnd Bergmann 	}
5484e0f4ed0SLuke Browning 	spin_unlock(&spu_prio->runq_lock);
549079cdb61SChristoph Hellwig 	__set_current_state(TASK_RUNNING);
550079cdb61SChristoph Hellwig 	remove_wait_queue(&ctx->stop_wq, &wait);
551a68cf983SMark Nutter }
552a68cf983SMark Nutter 
spu_get_idle(struct spu_context * ctx)553079cdb61SChristoph Hellwig static struct spu *spu_get_idle(struct spu_context *ctx)
554a68cf983SMark Nutter {
55536ddbb13SAndre Detsch 	struct spu *spu, *aff_ref_spu;
556486acd48SChristoph Hellwig 	int node, n;
557a68cf983SMark Nutter 
558038200cfSChristoph Hellwig 	spu_context_nospu_trace(spu_get_idle__enter, ctx);
559038200cfSChristoph Hellwig 
56036ddbb13SAndre Detsch 	if (ctx->gang) {
56136ddbb13SAndre Detsch 		mutex_lock(&ctx->gang->aff_mutex);
562486acd48SChristoph Hellwig 		if (has_affinity(ctx)) {
56336ddbb13SAndre Detsch 			aff_ref_spu = ctx->gang->aff_ref_spu;
56436ddbb13SAndre Detsch 			atomic_inc(&ctx->gang->aff_sched_count);
56536ddbb13SAndre Detsch 			mutex_unlock(&ctx->gang->aff_mutex);
56636ddbb13SAndre Detsch 			node = aff_ref_spu->node;
567cbc23d3eSArnd Bergmann 
568486acd48SChristoph Hellwig 			mutex_lock(&cbe_spu_info[node].list_mutex);
56936ddbb13SAndre Detsch 			spu = ctx_location(aff_ref_spu, ctx->aff_offset, node);
570486acd48SChristoph Hellwig 			if (spu && spu->alloc_state == SPU_FREE)
571486acd48SChristoph Hellwig 				goto found;
572486acd48SChristoph Hellwig 			mutex_unlock(&cbe_spu_info[node].list_mutex);
57336ddbb13SAndre Detsch 
5740855b543SAndre Detsch 			atomic_dec(&ctx->gang->aff_sched_count);
575038200cfSChristoph Hellwig 			goto not_found;
576486acd48SChristoph Hellwig 		}
57736ddbb13SAndre Detsch 		mutex_unlock(&ctx->gang->aff_mutex);
57836ddbb13SAndre Detsch 	}
579486acd48SChristoph Hellwig 	node = cpu_to_node(raw_smp_processor_id());
580a68cf983SMark Nutter 	for (n = 0; n < MAX_NUMNODES; n++, node++) {
581a68cf983SMark Nutter 		node = (node < MAX_NUMNODES) ? node : 0;
582ea1ae594SChristoph Hellwig 		if (!node_allowed(ctx, node))
583a68cf983SMark Nutter 			continue;
584486acd48SChristoph Hellwig 
585486acd48SChristoph Hellwig 		mutex_lock(&cbe_spu_info[node].list_mutex);
586486acd48SChristoph Hellwig 		list_for_each_entry(spu, &cbe_spu_info[node].spus, cbe_list) {
587486acd48SChristoph Hellwig 			if (spu->alloc_state == SPU_FREE)
588486acd48SChristoph Hellwig 				goto found;
589a68cf983SMark Nutter 		}
590486acd48SChristoph Hellwig 		mutex_unlock(&cbe_spu_info[node].list_mutex);
591486acd48SChristoph Hellwig 	}
592486acd48SChristoph Hellwig 
593038200cfSChristoph Hellwig  not_found:
594038200cfSChristoph Hellwig 	spu_context_nospu_trace(spu_get_idle__not_found, ctx);
595486acd48SChristoph Hellwig 	return NULL;
596486acd48SChristoph Hellwig 
597486acd48SChristoph Hellwig  found:
598486acd48SChristoph Hellwig 	spu->alloc_state = SPU_USED;
599486acd48SChristoph Hellwig 	mutex_unlock(&cbe_spu_info[node].list_mutex);
600038200cfSChristoph Hellwig 	spu_context_trace(spu_get_idle__found, ctx, spu);
601486acd48SChristoph Hellwig 	spu_init_channels(spu);
602a68cf983SMark Nutter 	return spu;
603a68cf983SMark Nutter }
604a68cf983SMark Nutter 
605079cdb61SChristoph Hellwig /**
60652f04fcfSChristoph Hellwig  * find_victim - find a lower priority context to preempt
607027dfac6SMichael Ellerman  * @ctx:	candidate context for running
60852f04fcfSChristoph Hellwig  *
60952f04fcfSChristoph Hellwig  * Returns the freed physical spu to run the new context on.
61052f04fcfSChristoph Hellwig  */
find_victim(struct spu_context * ctx)61152f04fcfSChristoph Hellwig static struct spu *find_victim(struct spu_context *ctx)
61252f04fcfSChristoph Hellwig {
61352f04fcfSChristoph Hellwig 	struct spu_context *victim = NULL;
61452f04fcfSChristoph Hellwig 	struct spu *spu;
61552f04fcfSChristoph Hellwig 	int node, n;
61652f04fcfSChristoph Hellwig 
6178a476d49SJulio M. Merino Vidal 	spu_context_nospu_trace(spu_find_victim__enter, ctx);
618038200cfSChristoph Hellwig 
61952f04fcfSChristoph Hellwig 	/*
62052f04fcfSChristoph Hellwig 	 * Look for a possible preemption candidate on the local node first.
62152f04fcfSChristoph Hellwig 	 * If there is no candidate look at the other nodes.  This isn't
6229b1d21f8SJulio M. Merino Vidal 	 * exactly fair, but so far the whole spu scheduler tries to keep
62352f04fcfSChristoph Hellwig 	 * a strong node affinity.  We might want to fine-tune this in
62452f04fcfSChristoph Hellwig 	 * the future.
62552f04fcfSChristoph Hellwig 	 */
62652f04fcfSChristoph Hellwig  restart:
62752f04fcfSChristoph Hellwig 	node = cpu_to_node(raw_smp_processor_id());
62852f04fcfSChristoph Hellwig 	for (n = 0; n < MAX_NUMNODES; n++, node++) {
62952f04fcfSChristoph Hellwig 		node = (node < MAX_NUMNODES) ? node : 0;
630ea1ae594SChristoph Hellwig 		if (!node_allowed(ctx, node))
63152f04fcfSChristoph Hellwig 			continue;
63252f04fcfSChristoph Hellwig 
633486acd48SChristoph Hellwig 		mutex_lock(&cbe_spu_info[node].list_mutex);
634486acd48SChristoph Hellwig 		list_for_each_entry(spu, &cbe_spu_info[node].spus, cbe_list) {
63552f04fcfSChristoph Hellwig 			struct spu_context *tmp = spu->ctx;
63652f04fcfSChristoph Hellwig 
637c0e7b4aaSChristoph Hellwig 			if (tmp && tmp->prio > ctx->prio &&
638e65c2f6fSLuke Browning 			    !(tmp->flags & SPU_CREATE_NOSCHED) &&
6398d5636fbSJeremy Kerr 			    (!victim || tmp->prio > victim->prio)) {
64052f04fcfSChristoph Hellwig 				victim = spu->ctx;
6419f43e391SJeremy Kerr 			}
6429f43e391SJeremy Kerr 		}
6439f43e391SJeremy Kerr 		if (victim)
6448d5636fbSJeremy Kerr 			get_spu_context(victim);
645486acd48SChristoph Hellwig 		mutex_unlock(&cbe_spu_info[node].list_mutex);
64652f04fcfSChristoph Hellwig 
64752f04fcfSChristoph Hellwig 		if (victim) {
64852f04fcfSChristoph Hellwig 			/*
64952f04fcfSChristoph Hellwig 			 * This nests ctx->state_mutex, but we always lock
65052f04fcfSChristoph Hellwig 			 * higher priority contexts before lower priority
65152f04fcfSChristoph Hellwig 			 * ones, so this is safe until we introduce
65252f04fcfSChristoph Hellwig 			 * priority inheritance schemes.
65391569531SLuke Browning 			 *
65491569531SLuke Browning 			 * XXX if the highest priority context is locked,
65591569531SLuke Browning 			 * this can loop a long time.  Might be better to
65691569531SLuke Browning 			 * look at another context or give up after X retries.
65752f04fcfSChristoph Hellwig 			 */
65852f04fcfSChristoph Hellwig 			if (!mutex_trylock(&victim->state_mutex)) {
6598d5636fbSJeremy Kerr 				put_spu_context(victim);
66052f04fcfSChristoph Hellwig 				victim = NULL;
66152f04fcfSChristoph Hellwig 				goto restart;
66252f04fcfSChristoph Hellwig 			}
66352f04fcfSChristoph Hellwig 
66452f04fcfSChristoph Hellwig 			spu = victim->spu;
665b192541bSLuke Browning 			if (!spu || victim->prio <= ctx->prio) {
66652f04fcfSChristoph Hellwig 				/*
66752f04fcfSChristoph Hellwig 				 * This race can happen because we've dropped
668b192541bSLuke Browning 				 * the active list mutex.  Not a problem, just
66952f04fcfSChristoph Hellwig 				 * restart the search.
67052f04fcfSChristoph Hellwig 				 */
67152f04fcfSChristoph Hellwig 				mutex_unlock(&victim->state_mutex);
6728d5636fbSJeremy Kerr 				put_spu_context(victim);
67352f04fcfSChristoph Hellwig 				victim = NULL;
67452f04fcfSChristoph Hellwig 				goto restart;
67552f04fcfSChristoph Hellwig 			}
676486acd48SChristoph Hellwig 
677038200cfSChristoph Hellwig 			spu_context_trace(__spu_deactivate__unload, ctx, spu);
678038200cfSChristoph Hellwig 
679486acd48SChristoph Hellwig 			mutex_lock(&cbe_spu_info[node].list_mutex);
680486acd48SChristoph Hellwig 			cbe_spu_info[node].nr_active--;
681c0e7b4aaSChristoph Hellwig 			spu_unbind_context(spu, victim);
682486acd48SChristoph Hellwig 			mutex_unlock(&cbe_spu_info[node].list_mutex);
683486acd48SChristoph Hellwig 
684e9f8a0b6SChristoph Hellwig 			victim->stats.invol_ctx_switch++;
685fe2f896dSChristoph Hellwig 			spu->stats.invol_ctx_switch++;
68608fcf1d6SLuke Browning 			if (test_bit(SPU_SCHED_SPU_RUN, &victim->sched_flags))
687e65c2f6fSLuke Browning 				spu_add_to_rq(victim);
688e65c2f6fSLuke Browning 
68952f04fcfSChristoph Hellwig 			mutex_unlock(&victim->state_mutex);
6908d5636fbSJeremy Kerr 			put_spu_context(victim);
691e65c2f6fSLuke Browning 
69252f04fcfSChristoph Hellwig 			return spu;
69352f04fcfSChristoph Hellwig 		}
69452f04fcfSChristoph Hellwig 	}
69552f04fcfSChristoph Hellwig 
69652f04fcfSChristoph Hellwig 	return NULL;
69752f04fcfSChristoph Hellwig }
69852f04fcfSChristoph Hellwig 
__spu_schedule(struct spu * spu,struct spu_context * ctx)699e65c2f6fSLuke Browning static void __spu_schedule(struct spu *spu, struct spu_context *ctx)
700e65c2f6fSLuke Browning {
701e65c2f6fSLuke Browning 	int node = spu->node;
702e65c2f6fSLuke Browning 	int success = 0;
703e65c2f6fSLuke Browning 
704e65c2f6fSLuke Browning 	spu_set_timeslice(ctx);
705e65c2f6fSLuke Browning 
706e65c2f6fSLuke Browning 	mutex_lock(&cbe_spu_info[node].list_mutex);
707e65c2f6fSLuke Browning 	if (spu->ctx == NULL) {
708e65c2f6fSLuke Browning 		spu_bind_context(spu, ctx);
709e65c2f6fSLuke Browning 		cbe_spu_info[node].nr_active++;
710e65c2f6fSLuke Browning 		spu->alloc_state = SPU_USED;
711e65c2f6fSLuke Browning 		success = 1;
712e65c2f6fSLuke Browning 	}
713e65c2f6fSLuke Browning 	mutex_unlock(&cbe_spu_info[node].list_mutex);
714e65c2f6fSLuke Browning 
715e65c2f6fSLuke Browning 	if (success)
716e65c2f6fSLuke Browning 		wake_up_all(&ctx->run_wq);
717e65c2f6fSLuke Browning 	else
718e65c2f6fSLuke Browning 		spu_add_to_rq(ctx);
719e65c2f6fSLuke Browning }
720e65c2f6fSLuke Browning 
spu_schedule(struct spu * spu,struct spu_context * ctx)721e65c2f6fSLuke Browning static void spu_schedule(struct spu *spu, struct spu_context *ctx)
722e65c2f6fSLuke Browning {
723c9101bdbSChristoph Hellwig 	/* not a candidate for interruptible because it's called either
724c9101bdbSChristoph Hellwig 	   from the scheduler thread or from spu_deactivate */
725c9101bdbSChristoph Hellwig 	mutex_lock(&ctx->state_mutex);
726b2e601d1SAndre Detsch 	if (ctx->state == SPU_STATE_SAVED)
727e65c2f6fSLuke Browning 		__spu_schedule(spu, ctx);
728e65c2f6fSLuke Browning 	spu_release(ctx);
729e65c2f6fSLuke Browning }
730e65c2f6fSLuke Browning 
731b65fe035SJeremy Kerr /**
732b65fe035SJeremy Kerr  * spu_unschedule - remove a context from a spu, and possibly release it.
733b65fe035SJeremy Kerr  * @spu:	The SPU to unschedule from
734b65fe035SJeremy Kerr  * @ctx:	The context currently scheduled on the SPU
735b65fe035SJeremy Kerr  * @free_spu	Whether to free the SPU for other contexts
736b65fe035SJeremy Kerr  *
737b65fe035SJeremy Kerr  * Unbinds the context @ctx from the SPU @spu. If @free_spu is non-zero, the
738b65fe035SJeremy Kerr  * SPU is made available for other contexts (ie, may be returned by
739b65fe035SJeremy Kerr  * spu_get_idle). If this is zero, the caller is expected to schedule another
740b65fe035SJeremy Kerr  * context to this spu.
741b65fe035SJeremy Kerr  *
742b65fe035SJeremy Kerr  * Should be called with ctx->state_mutex held.
743b65fe035SJeremy Kerr  */
spu_unschedule(struct spu * spu,struct spu_context * ctx,int free_spu)744b65fe035SJeremy Kerr static void spu_unschedule(struct spu *spu, struct spu_context *ctx,
745b65fe035SJeremy Kerr 		int free_spu)
746e65c2f6fSLuke Browning {
747e65c2f6fSLuke Browning 	int node = spu->node;
748e65c2f6fSLuke Browning 
749e65c2f6fSLuke Browning 	mutex_lock(&cbe_spu_info[node].list_mutex);
750e65c2f6fSLuke Browning 	cbe_spu_info[node].nr_active--;
751b65fe035SJeremy Kerr 	if (free_spu)
752e65c2f6fSLuke Browning 		spu->alloc_state = SPU_FREE;
753e65c2f6fSLuke Browning 	spu_unbind_context(spu, ctx);
754e65c2f6fSLuke Browning 	ctx->stats.invol_ctx_switch++;
755e65c2f6fSLuke Browning 	spu->stats.invol_ctx_switch++;
756e65c2f6fSLuke Browning 	mutex_unlock(&cbe_spu_info[node].list_mutex);
757e65c2f6fSLuke Browning }
758e65c2f6fSLuke Browning 
75952f04fcfSChristoph Hellwig /**
760079cdb61SChristoph Hellwig  * spu_activate - find a free spu for a context and execute it
761079cdb61SChristoph Hellwig  * @ctx:	spu context to schedule
762079cdb61SChristoph Hellwig  * @flags:	flags (currently ignored)
763079cdb61SChristoph Hellwig  *
76408873095SChristoph Hellwig  * Tries to find a free spu to run @ctx.  If no free spu is available
765079cdb61SChristoph Hellwig  * add the context to the runqueue so it gets woken up once an spu
766079cdb61SChristoph Hellwig  * is available.
767079cdb61SChristoph Hellwig  */
spu_activate(struct spu_context * ctx,unsigned long flags)76826bec673SChristoph Hellwig int spu_activate(struct spu_context *ctx, unsigned long flags)
7698b3d6663SArnd Bergmann {
770079cdb61SChristoph Hellwig 	struct spu *spu;
771079cdb61SChristoph Hellwig 
77227449971SChristoph Hellwig 	/*
77327449971SChristoph Hellwig 	 * If there are multiple threads waiting for a single context
77427449971SChristoph Hellwig 	 * only one actually binds the context while the others will
77527449971SChristoph Hellwig 	 * only be able to acquire the state_mutex once the context
77627449971SChristoph Hellwig 	 * already is in runnable state.
77727449971SChristoph Hellwig 	 */
77827449971SChristoph Hellwig 	if (ctx->spu)
77927449971SChristoph Hellwig 		return 0;
78027449971SChristoph Hellwig 
781e65c2f6fSLuke Browning spu_activate_top:
782e65c2f6fSLuke Browning 	if (signal_pending(current))
783e65c2f6fSLuke Browning 		return -ERESTARTSYS;
784e65c2f6fSLuke Browning 
785079cdb61SChristoph Hellwig 	spu = spu_get_idle(ctx);
78652f04fcfSChristoph Hellwig 	/*
78752f04fcfSChristoph Hellwig 	 * If this is a realtime thread we try to get it running by
78852f04fcfSChristoph Hellwig 	 * preempting a lower priority thread.
78952f04fcfSChristoph Hellwig 	 */
790fe443ef2SChristoph Hellwig 	if (!spu && rt_prio(ctx->prio))
79152f04fcfSChristoph Hellwig 		spu = find_victim(ctx);
792079cdb61SChristoph Hellwig 	if (spu) {
793e65c2f6fSLuke Browning 		unsigned long runcntl;
794486acd48SChristoph Hellwig 
795e65c2f6fSLuke Browning 		runcntl = ctx->ops->runcntl_read(ctx);
796e65c2f6fSLuke Browning 		__spu_schedule(spu, ctx);
797e65c2f6fSLuke Browning 		if (runcntl & SPU_RUNCNTL_RUNNABLE)
798e65c2f6fSLuke Browning 			spuctx_switch_state(ctx, SPU_UTIL_USER);
799e65c2f6fSLuke Browning 
800079cdb61SChristoph Hellwig 		return 0;
801a68cf983SMark Nutter 	}
802079cdb61SChristoph Hellwig 
803e65c2f6fSLuke Browning 	if (ctx->flags & SPU_CREATE_NOSCHED) {
804079cdb61SChristoph Hellwig 		spu_prio_wait(ctx);
805e65c2f6fSLuke Browning 		goto spu_activate_top;
806e65c2f6fSLuke Browning 	}
807079cdb61SChristoph Hellwig 
808e65c2f6fSLuke Browning 	spu_add_to_rq(ctx);
809e65c2f6fSLuke Browning 
810e65c2f6fSLuke Browning 	return 0;
8118b3d6663SArnd Bergmann }
8128b3d6663SArnd Bergmann 
813678b2ff1SChristoph Hellwig /**
814bb5db29aSChristoph Hellwig  * grab_runnable_context - try to find a runnable context
815bb5db29aSChristoph Hellwig  *
816bb5db29aSChristoph Hellwig  * Remove the highest priority context on the runqueue and return it
817bb5db29aSChristoph Hellwig  * to the caller.  Returns %NULL if no runnable context was found.
818bb5db29aSChristoph Hellwig  */
grab_runnable_context(int prio,int node)819ea1ae594SChristoph Hellwig static struct spu_context *grab_runnable_context(int prio, int node)
820bb5db29aSChristoph Hellwig {
821ea1ae594SChristoph Hellwig 	struct spu_context *ctx;
822bb5db29aSChristoph Hellwig 	int best;
823bb5db29aSChristoph Hellwig 
824bb5db29aSChristoph Hellwig 	spin_lock(&spu_prio->runq_lock);
8257e90b749SMasato Noguchi 	best = find_first_bit(spu_prio->bitmap, prio);
826ea1ae594SChristoph Hellwig 	while (best < prio) {
827bb5db29aSChristoph Hellwig 		struct list_head *rq = &spu_prio->runq[best];
828bb5db29aSChristoph Hellwig 
829ea1ae594SChristoph Hellwig 		list_for_each_entry(ctx, rq, rq) {
830ea1ae594SChristoph Hellwig 			/* XXX(hch): check for affinity here as well */
831ea1ae594SChristoph Hellwig 			if (__node_allowed(ctx, node)) {
832bb5db29aSChristoph Hellwig 				__spu_del_from_rq(ctx);
833ea1ae594SChristoph Hellwig 				goto found;
834bb5db29aSChristoph Hellwig 			}
835ea1ae594SChristoph Hellwig 		}
836ea1ae594SChristoph Hellwig 		best++;
837ea1ae594SChristoph Hellwig 	}
838ea1ae594SChristoph Hellwig 	ctx = NULL;
839ea1ae594SChristoph Hellwig  found:
840bb5db29aSChristoph Hellwig 	spin_unlock(&spu_prio->runq_lock);
841bb5db29aSChristoph Hellwig 	return ctx;
842bb5db29aSChristoph Hellwig }
843bb5db29aSChristoph Hellwig 
__spu_deactivate(struct spu_context * ctx,int force,int max_prio)844bb5db29aSChristoph Hellwig static int __spu_deactivate(struct spu_context *ctx, int force, int max_prio)
845bb5db29aSChristoph Hellwig {
846bb5db29aSChristoph Hellwig 	struct spu *spu = ctx->spu;
847bb5db29aSChristoph Hellwig 	struct spu_context *new = NULL;
848bb5db29aSChristoph Hellwig 
849bb5db29aSChristoph Hellwig 	if (spu) {
850ea1ae594SChristoph Hellwig 		new = grab_runnable_context(max_prio, spu->node);
851bb5db29aSChristoph Hellwig 		if (new || force) {
852b65fe035SJeremy Kerr 			spu_unschedule(spu, ctx, new == NULL);
853e65c2f6fSLuke Browning 			if (new) {
854e65c2f6fSLuke Browning 				if (new->flags & SPU_CREATE_NOSCHED)
855bb5db29aSChristoph Hellwig 					wake_up(&new->stop_wq);
856e65c2f6fSLuke Browning 				else {
857e65c2f6fSLuke Browning 					spu_release(ctx);
858e65c2f6fSLuke Browning 					spu_schedule(spu, new);
859c9101bdbSChristoph Hellwig 					/* this one can't easily be made
860c9101bdbSChristoph Hellwig 					   interruptible */
861c9101bdbSChristoph Hellwig 					mutex_lock(&ctx->state_mutex);
862bb5db29aSChristoph Hellwig 				}
863e65c2f6fSLuke Browning 			}
864e65c2f6fSLuke Browning 		}
865bb5db29aSChristoph Hellwig 	}
866bb5db29aSChristoph Hellwig 
867bb5db29aSChristoph Hellwig 	return new != NULL;
868bb5db29aSChristoph Hellwig }
869bb5db29aSChristoph Hellwig 
870bb5db29aSChristoph Hellwig /**
871678b2ff1SChristoph Hellwig  * spu_deactivate - unbind a context from it's physical spu
872678b2ff1SChristoph Hellwig  * @ctx:	spu context to unbind
873678b2ff1SChristoph Hellwig  *
874678b2ff1SChristoph Hellwig  * Unbind @ctx from the physical spu it is running on and schedule
875678b2ff1SChristoph Hellwig  * the highest priority context to run on the freed physical spu.
876678b2ff1SChristoph Hellwig  */
spu_deactivate(struct spu_context * ctx)8778b3d6663SArnd Bergmann void spu_deactivate(struct spu_context *ctx)
8788b3d6663SArnd Bergmann {
879038200cfSChristoph Hellwig 	spu_context_nospu_trace(spu_deactivate__enter, ctx);
880bb5db29aSChristoph Hellwig 	__spu_deactivate(ctx, 1, MAX_PRIO);
881678b2ff1SChristoph Hellwig }
8828b3d6663SArnd Bergmann 
883ae7b4c52SChristoph Hellwig /**
884ae7b4c52SChristoph Hellwig  * spu_yield -	yield a physical spu if others are waiting
885ae7b4c52SChristoph Hellwig  * @ctx:	spu context to yield
886ae7b4c52SChristoph Hellwig  *
887ae7b4c52SChristoph Hellwig  * Check if there is a higher priority context waiting and if yes
888ae7b4c52SChristoph Hellwig  * unbind @ctx from the physical spu and schedule the highest
889ae7b4c52SChristoph Hellwig  * priority context to run on the freed physical spu instead.
890ae7b4c52SChristoph Hellwig  */
spu_yield(struct spu_context * ctx)8918b3d6663SArnd Bergmann void spu_yield(struct spu_context *ctx)
8928b3d6663SArnd Bergmann {
893038200cfSChristoph Hellwig 	spu_context_nospu_trace(spu_yield__enter, ctx);
894e5c0b9ecSChristoph Hellwig 	if (!(ctx->flags & SPU_CREATE_NOSCHED)) {
895bb5db29aSChristoph Hellwig 		mutex_lock(&ctx->state_mutex);
89627ec41d3SAndre Detsch 		__spu_deactivate(ctx, 0, MAX_PRIO);
897650f8b02SChristoph Hellwig 		mutex_unlock(&ctx->state_mutex);
898a68cf983SMark Nutter 	}
899e5c0b9ecSChristoph Hellwig }
900bb5db29aSChristoph Hellwig 
spusched_tick(struct spu_context * ctx)901486acd48SChristoph Hellwig static noinline void spusched_tick(struct spu_context *ctx)
902bb5db29aSChristoph Hellwig {
903e65c2f6fSLuke Browning 	struct spu_context *new = NULL;
904e65c2f6fSLuke Browning 	struct spu *spu = NULL;
905e65c2f6fSLuke Browning 
906c9101bdbSChristoph Hellwig 	if (spu_acquire(ctx))
907c9101bdbSChristoph Hellwig 		BUG();	/* a kernel thread never has signals pending */
908e65c2f6fSLuke Browning 
909e65c2f6fSLuke Browning 	if (ctx->state != SPU_STATE_RUNNABLE)
910e65c2f6fSLuke Browning 		goto out;
911df09cf3eSChristoph Hellwig 	if (ctx->flags & SPU_CREATE_NOSCHED)
912e65c2f6fSLuke Browning 		goto out;
913df09cf3eSChristoph Hellwig 	if (ctx->policy == SCHED_FIFO)
914e65c2f6fSLuke Browning 		goto out;
915df09cf3eSChristoph Hellwig 
916ce7c191bSJeremy Kerr 	if (--ctx->time_slice && test_bit(SPU_SCHED_SPU_RUN, &ctx->sched_flags))
917e65c2f6fSLuke Browning 		goto out;
918bb5db29aSChristoph Hellwig 
919e65c2f6fSLuke Browning 	spu = ctx->spu;
920038200cfSChristoph Hellwig 
921038200cfSChristoph Hellwig 	spu_context_trace(spusched_tick__preempt, ctx, spu);
922038200cfSChristoph Hellwig 
923ea1ae594SChristoph Hellwig 	new = grab_runnable_context(ctx->prio + 1, spu->node);
924ea1ae594SChristoph Hellwig 	if (new) {
925b65fe035SJeremy Kerr 		spu_unschedule(spu, ctx, 0);
926ce7c191bSJeremy Kerr 		if (test_bit(SPU_SCHED_SPU_RUN, &ctx->sched_flags))
927e65c2f6fSLuke Browning 			spu_add_to_rq(ctx);
92837901802SChristoph Hellwig 	} else {
929038200cfSChristoph Hellwig 		spu_context_nospu_trace(spusched_tick__newslice, ctx);
9302442a8baSLuke Browning 		if (!ctx->time_slice)
93137901802SChristoph Hellwig 			ctx->time_slice++;
93237901802SChristoph Hellwig 	}
933e65c2f6fSLuke Browning out:
934e65c2f6fSLuke Browning 	spu_release(ctx);
935e65c2f6fSLuke Browning 
936e65c2f6fSLuke Browning 	if (new)
937e65c2f6fSLuke Browning 		spu_schedule(spu, new);
93837901802SChristoph Hellwig }
93937901802SChristoph Hellwig 
94065de66f0SChristoph Hellwig /**
94165de66f0SChristoph Hellwig  * count_active_contexts - count nr of active tasks
94265de66f0SChristoph Hellwig  *
94365de66f0SChristoph Hellwig  * Return the number of tasks currently running or waiting to run.
94465de66f0SChristoph Hellwig  *
945486acd48SChristoph Hellwig  * Note that we don't take runq_lock / list_mutex here.  Reading
94665de66f0SChristoph Hellwig  * a single 32bit value is atomic on powerpc, and we don't care
94765de66f0SChristoph Hellwig  * about memory ordering issues here.
94865de66f0SChristoph Hellwig  */
count_active_contexts(void)94965de66f0SChristoph Hellwig static unsigned long count_active_contexts(void)
95065de66f0SChristoph Hellwig {
95165de66f0SChristoph Hellwig 	int nr_active = 0, node;
95265de66f0SChristoph Hellwig 
95365de66f0SChristoph Hellwig 	for (node = 0; node < MAX_NUMNODES; node++)
954486acd48SChristoph Hellwig 		nr_active += cbe_spu_info[node].nr_active;
95565de66f0SChristoph Hellwig 	nr_active += spu_prio->nr_waiting;
95665de66f0SChristoph Hellwig 
95765de66f0SChristoph Hellwig 	return nr_active;
95865de66f0SChristoph Hellwig }
95965de66f0SChristoph Hellwig 
96065de66f0SChristoph Hellwig /**
96190608a29SAegis Lin  * spu_calc_load - update the avenrun load estimates.
96265de66f0SChristoph Hellwig  *
96365de66f0SChristoph Hellwig  * No locking against reading these values from userspace, as for
96465de66f0SChristoph Hellwig  * the CPU loadavg code.
96565de66f0SChristoph Hellwig  */
spu_calc_load(void)96690608a29SAegis Lin static void spu_calc_load(void)
96765de66f0SChristoph Hellwig {
96865de66f0SChristoph Hellwig 	unsigned long active_tasks; /* fixed-point */
96965de66f0SChristoph Hellwig 
97065de66f0SChristoph Hellwig 	active_tasks = count_active_contexts() * FIXED_1;
9718508cf3fSJohannes Weiner 	spu_avenrun[0] = calc_load(spu_avenrun[0], EXP_1, active_tasks);
9728508cf3fSJohannes Weiner 	spu_avenrun[1] = calc_load(spu_avenrun[1], EXP_5, active_tasks);
9738508cf3fSJohannes Weiner 	spu_avenrun[2] = calc_load(spu_avenrun[2], EXP_15, active_tasks);
97465de66f0SChristoph Hellwig }
97565de66f0SChristoph Hellwig 
spusched_wake(struct timer_list * unused)976e99e88a9SKees Cook static void spusched_wake(struct timer_list *unused)
97737901802SChristoph Hellwig {
97837901802SChristoph Hellwig 	mod_timer(&spusched_timer, jiffies + SPUSCHED_TICK);
97937901802SChristoph Hellwig 	wake_up_process(spusched_task);
98090608a29SAegis Lin }
98190608a29SAegis Lin 
spuloadavg_wake(struct timer_list * unused)982e99e88a9SKees Cook static void spuloadavg_wake(struct timer_list *unused)
98390608a29SAegis Lin {
98490608a29SAegis Lin 	mod_timer(&spuloadavg_timer, jiffies + LOAD_FREQ);
98590608a29SAegis Lin 	spu_calc_load();
98637901802SChristoph Hellwig }
98737901802SChristoph Hellwig 
spusched_thread(void * unused)98837901802SChristoph Hellwig static int spusched_thread(void *unused)
98937901802SChristoph Hellwig {
990486acd48SChristoph Hellwig 	struct spu *spu;
99137901802SChristoph Hellwig 	int node;
99237901802SChristoph Hellwig 
99337901802SChristoph Hellwig 	while (!kthread_should_stop()) {
99437901802SChristoph Hellwig 		set_current_state(TASK_INTERRUPTIBLE);
99537901802SChristoph Hellwig 		schedule();
99637901802SChristoph Hellwig 		for (node = 0; node < MAX_NUMNODES; node++) {
997e65c2f6fSLuke Browning 			struct mutex *mtx = &cbe_spu_info[node].list_mutex;
998e65c2f6fSLuke Browning 
999e65c2f6fSLuke Browning 			mutex_lock(mtx);
1000e65c2f6fSLuke Browning 			list_for_each_entry(spu, &cbe_spu_info[node].spus,
1001e65c2f6fSLuke Browning 					cbe_list) {
1002e65c2f6fSLuke Browning 				struct spu_context *ctx = spu->ctx;
1003e65c2f6fSLuke Browning 
1004e65c2f6fSLuke Browning 				if (ctx) {
10058d5636fbSJeremy Kerr 					get_spu_context(ctx);
1006e65c2f6fSLuke Browning 					mutex_unlock(mtx);
1007e65c2f6fSLuke Browning 					spusched_tick(ctx);
1008e65c2f6fSLuke Browning 					mutex_lock(mtx);
10098d5636fbSJeremy Kerr 					put_spu_context(ctx);
1010e65c2f6fSLuke Browning 				}
1011e65c2f6fSLuke Browning 			}
1012e65c2f6fSLuke Browning 			mutex_unlock(mtx);
101337901802SChristoph Hellwig 		}
101437901802SChristoph Hellwig 	}
101537901802SChristoph Hellwig 
101637901802SChristoph Hellwig 	return 0;
10178b3d6663SArnd Bergmann }
10188b3d6663SArnd Bergmann 
spuctx_switch_state(struct spu_context * ctx,enum spu_utilization_state new_state)10197cd58e43SJeremy Kerr void spuctx_switch_state(struct spu_context *ctx,
10207cd58e43SJeremy Kerr 		enum spu_utilization_state new_state)
10217cd58e43SJeremy Kerr {
10227cd58e43SJeremy Kerr 	unsigned long long curtime;
10237cd58e43SJeremy Kerr 	signed long long delta;
10247cd58e43SJeremy Kerr 	struct spu *spu;
10257cd58e43SJeremy Kerr 	enum spu_utilization_state old_state;
1026fabb6570SMaxim Shchetynin 	int node;
10277cd58e43SJeremy Kerr 
1028f2dec1eaSThomas Gleixner 	curtime = ktime_get_ns();
10297cd58e43SJeremy Kerr 	delta = curtime - ctx->stats.tstamp;
10307cd58e43SJeremy Kerr 
10317cd58e43SJeremy Kerr 	WARN_ON(!mutex_is_locked(&ctx->state_mutex));
10327cd58e43SJeremy Kerr 	WARN_ON(delta < 0);
10337cd58e43SJeremy Kerr 
10347cd58e43SJeremy Kerr 	spu = ctx->spu;
10357cd58e43SJeremy Kerr 	old_state = ctx->stats.util_state;
10367cd58e43SJeremy Kerr 	ctx->stats.util_state = new_state;
10377cd58e43SJeremy Kerr 	ctx->stats.tstamp = curtime;
10387cd58e43SJeremy Kerr 
10397cd58e43SJeremy Kerr 	/*
10407cd58e43SJeremy Kerr 	 * Update the physical SPU utilization statistics.
10417cd58e43SJeremy Kerr 	 */
10427cd58e43SJeremy Kerr 	if (spu) {
10437cd58e43SJeremy Kerr 		ctx->stats.times[old_state] += delta;
10447cd58e43SJeremy Kerr 		spu->stats.times[old_state] += delta;
10457cd58e43SJeremy Kerr 		spu->stats.util_state = new_state;
10467cd58e43SJeremy Kerr 		spu->stats.tstamp = curtime;
1047fabb6570SMaxim Shchetynin 		node = spu->node;
1048fabb6570SMaxim Shchetynin 		if (old_state == SPU_UTIL_USER)
1049fabb6570SMaxim Shchetynin 			atomic_dec(&cbe_spu_info[node].busy_spus);
1050cb9808d3SIlpo Järvinen 		if (new_state == SPU_UTIL_USER)
1051fabb6570SMaxim Shchetynin 			atomic_inc(&cbe_spu_info[node].busy_spus);
10527cd58e43SJeremy Kerr 	}
10537cd58e43SJeremy Kerr }
10547cd58e43SJeremy Kerr 
1055*5986f6b6SYueHaibing #ifdef CONFIG_PROC_FS
show_spu_loadavg(struct seq_file * s,void * private)105665de66f0SChristoph Hellwig static int show_spu_loadavg(struct seq_file *s, void *private)
105765de66f0SChristoph Hellwig {
105865de66f0SChristoph Hellwig 	int a, b, c;
105965de66f0SChristoph Hellwig 
106065de66f0SChristoph Hellwig 	a = spu_avenrun[0] + (FIXED_1/200);
106165de66f0SChristoph Hellwig 	b = spu_avenrun[1] + (FIXED_1/200);
106265de66f0SChristoph Hellwig 	c = spu_avenrun[2] + (FIXED_1/200);
106365de66f0SChristoph Hellwig 
106465de66f0SChristoph Hellwig 	/*
106565de66f0SChristoph Hellwig 	 * Note that last_pid doesn't really make much sense for the
10669b1d21f8SJulio M. Merino Vidal 	 * SPU loadavg (it even seems very odd on the CPU side...),
106765de66f0SChristoph Hellwig 	 * but we include it here to have a 100% compatible interface.
106865de66f0SChristoph Hellwig 	 */
106965de66f0SChristoph Hellwig 	seq_printf(s, "%d.%02d %d.%02d %d.%02d %ld/%d %d\n",
107065de66f0SChristoph Hellwig 		LOAD_INT(a), LOAD_FRAC(a),
107165de66f0SChristoph Hellwig 		LOAD_INT(b), LOAD_FRAC(b),
107265de66f0SChristoph Hellwig 		LOAD_INT(c), LOAD_FRAC(c),
107365de66f0SChristoph Hellwig 		count_active_contexts(),
107465de66f0SChristoph Hellwig 		atomic_read(&nr_spu_contexts),
10759a1015b3SAlexey Dobriyan 		idr_get_cursor(&task_active_pid_ns(current)->idr) - 1);
107665de66f0SChristoph Hellwig 	return 0;
1077*5986f6b6SYueHaibing }
1078*5986f6b6SYueHaibing #endif
107965de66f0SChristoph Hellwig 
spu_sched_init(void)10808b3d6663SArnd Bergmann int __init spu_sched_init(void)
10818b3d6663SArnd Bergmann {
108265de66f0SChristoph Hellwig 	struct proc_dir_entry *entry;
108365de66f0SChristoph Hellwig 	int err = -ENOMEM, i;
10848b3d6663SArnd Bergmann 
1085a68cf983SMark Nutter 	spu_prio = kzalloc(sizeof(struct spu_prio_array), GFP_KERNEL);
108637901802SChristoph Hellwig 	if (!spu_prio)
108765de66f0SChristoph Hellwig 		goto out;
108837901802SChristoph Hellwig 
10898b3d6663SArnd Bergmann 	for (i = 0; i < MAX_PRIO; i++) {
1090079cdb61SChristoph Hellwig 		INIT_LIST_HEAD(&spu_prio->runq[i]);
1091a68cf983SMark Nutter 		__clear_bit(i, spu_prio->bitmap);
10928b3d6663SArnd Bergmann 	}
1093079cdb61SChristoph Hellwig 	spin_lock_init(&spu_prio->runq_lock);
109437901802SChristoph Hellwig 
1095e99e88a9SKees Cook 	timer_setup(&spusched_timer, spusched_wake, 0);
1096e99e88a9SKees Cook 	timer_setup(&spuloadavg_timer, spuloadavg_wake, 0);
1097c77239b8SChristoph Hellwig 
109837901802SChristoph Hellwig 	spusched_task = kthread_run(spusched_thread, NULL, "spusched");
109937901802SChristoph Hellwig 	if (IS_ERR(spusched_task)) {
110065de66f0SChristoph Hellwig 		err = PTR_ERR(spusched_task);
110165de66f0SChristoph Hellwig 		goto out_free_spu_prio;
110237901802SChristoph Hellwig 	}
1103f3f59becSJeremy Kerr 
110490608a29SAegis Lin 	mod_timer(&spuloadavg_timer, 0);
110590608a29SAegis Lin 
11063f3942acSChristoph Hellwig 	entry = proc_create_single("spu_loadavg", 0, NULL, show_spu_loadavg);
110765de66f0SChristoph Hellwig 	if (!entry)
110865de66f0SChristoph Hellwig 		goto out_stop_kthread;
110965de66f0SChristoph Hellwig 
1110f3f59becSJeremy Kerr 	pr_debug("spusched: tick: %d, min ticks: %d, default ticks: %d\n",
1111f3f59becSJeremy Kerr 			SPUSCHED_TICK, MIN_SPU_TIMESLICE, DEF_SPU_TIMESLICE);
11128b3d6663SArnd Bergmann 	return 0;
111337901802SChristoph Hellwig 
111465de66f0SChristoph Hellwig  out_stop_kthread:
111565de66f0SChristoph Hellwig 	kthread_stop(spusched_task);
111665de66f0SChristoph Hellwig  out_free_spu_prio:
111765de66f0SChristoph Hellwig 	kfree(spu_prio);
111865de66f0SChristoph Hellwig  out:
111965de66f0SChristoph Hellwig 	return err;
11208b3d6663SArnd Bergmann }
11218b3d6663SArnd Bergmann 
spu_sched_exit(void)1122d1450317SSebastian Siewior void spu_sched_exit(void)
11238b3d6663SArnd Bergmann {
1124486acd48SChristoph Hellwig 	struct spu *spu;
1125a68cf983SMark Nutter 	int node;
11268b3d6663SArnd Bergmann 
112765de66f0SChristoph Hellwig 	remove_proc_entry("spu_loadavg", NULL);
112865de66f0SChristoph Hellwig 
1129c77239b8SChristoph Hellwig 	del_timer_sync(&spusched_timer);
113090608a29SAegis Lin 	del_timer_sync(&spuloadavg_timer);
113137901802SChristoph Hellwig 	kthread_stop(spusched_task);
113237901802SChristoph Hellwig 
1133a68cf983SMark Nutter 	for (node = 0; node < MAX_NUMNODES; node++) {
1134486acd48SChristoph Hellwig 		mutex_lock(&cbe_spu_info[node].list_mutex);
1135486acd48SChristoph Hellwig 		list_for_each_entry(spu, &cbe_spu_info[node].spus, cbe_list)
1136486acd48SChristoph Hellwig 			if (spu->alloc_state != SPU_FREE)
1137486acd48SChristoph Hellwig 				spu->alloc_state = SPU_FREE;
1138486acd48SChristoph Hellwig 		mutex_unlock(&cbe_spu_info[node].list_mutex);
1139a68cf983SMark Nutter 	}
1140a68cf983SMark Nutter 	kfree(spu_prio);
11418b3d6663SArnd Bergmann }
1142