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