Commit 36aaccc1 authored by Bob Nelson's avatar Bob Nelson Committed by Arnd Bergmann

[CELL] oprofile: enable SPU switch notification to detect currently active SPU tasks

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

This patch adds to the capability of spu_switch_event_register so that
the caller is also notified of currently active SPU tasks.
Exports spu_switch_event_register and spu_switch_event_unregister so
that OProfile can get access to the notifications provided.
Signed-off-by: default avatarMaynard Johnson <mpjohn@us.ibm.com>
Signed-off-by: default avatarCarl Love <carll@us.ibm.com>
Signed-off-by: default avatarBob Nelson <rrnelson@us.ibm.com>
Signed-off-by: default avatarArnd Bergmann <arnd.bergmann@de.ibm.com>
Acked-by: default avatarPaul Mackerras <paulus@samba.org>
parent 24140594
...@@ -18,15 +18,17 @@ void spufs_stop_callback(struct spu *spu) ...@@ -18,15 +18,17 @@ void spufs_stop_callback(struct spu *spu)
wake_up_all(&ctx->stop_wq); wake_up_all(&ctx->stop_wq);
} }
static inline int spu_stopped(struct spu_context *ctx, u32 * stat) static inline int spu_stopped(struct spu_context *ctx, u32 *stat)
{ {
struct spu *spu; struct spu *spu;
u64 pte_fault; u64 pte_fault;
*stat = ctx->ops->status_read(ctx); *stat = ctx->ops->status_read(ctx);
if (ctx->state != SPU_STATE_RUNNABLE)
return 1;
spu = ctx->spu; spu = ctx->spu;
if (ctx->state != SPU_STATE_RUNNABLE ||
test_bit(SPU_SCHED_NOTIFY_ACTIVE, &ctx->sched_flags))
return 1;
pte_fault = spu->dsisr & pte_fault = spu->dsisr &
(MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED); (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED);
return (!(*stat & SPU_STATUS_RUNNING) || pte_fault || spu->class_0_pending) ? return (!(*stat & SPU_STATUS_RUNNING) || pte_fault || spu->class_0_pending) ?
...@@ -124,7 +126,7 @@ static int spu_setup_isolated(struct spu_context *ctx) ...@@ -124,7 +126,7 @@ static int spu_setup_isolated(struct spu_context *ctx)
return ret; return ret;
} }
static int spu_run_init(struct spu_context *ctx, u32 * npc) static int spu_run_init(struct spu_context *ctx, u32 *npc)
{ {
spuctx_switch_state(ctx, SPU_UTIL_SYSTEM); spuctx_switch_state(ctx, SPU_UTIL_SYSTEM);
...@@ -158,8 +160,8 @@ static int spu_run_init(struct spu_context *ctx, u32 * npc) ...@@ -158,8 +160,8 @@ static int spu_run_init(struct spu_context *ctx, u32 * npc)
return 0; return 0;
} }
static int spu_run_fini(struct spu_context *ctx, u32 * npc, static int spu_run_fini(struct spu_context *ctx, u32 *npc,
u32 * status) u32 *status)
{ {
int ret = 0; int ret = 0;
...@@ -298,6 +300,7 @@ static inline int spu_process_events(struct spu_context *ctx) ...@@ -298,6 +300,7 @@ static inline int spu_process_events(struct spu_context *ctx)
long spufs_run_spu(struct spu_context *ctx, u32 *npc, u32 *event) long spufs_run_spu(struct spu_context *ctx, u32 *npc, u32 *event)
{ {
int ret; int ret;
struct spu *spu;
u32 status; u32 status;
if (mutex_lock_interruptible(&ctx->run_mutex)) if (mutex_lock_interruptible(&ctx->run_mutex))
...@@ -333,6 +336,14 @@ long spufs_run_spu(struct spu_context *ctx, u32 *npc, u32 *event) ...@@ -333,6 +336,14 @@ long spufs_run_spu(struct spu_context *ctx, u32 *npc, u32 *event)
ret = spufs_wait(ctx->stop_wq, spu_stopped(ctx, &status)); ret = spufs_wait(ctx->stop_wq, spu_stopped(ctx, &status));
if (unlikely(ret)) if (unlikely(ret))
break; break;
spu = ctx->spu;
if (unlikely(test_and_clear_bit(SPU_SCHED_NOTIFY_ACTIVE,
&ctx->sched_flags))) {
if (!(status & SPU_STATUS_STOPPED_BY_STOP)) {
spu_switch_notify(spu, ctx);
continue;
}
}
spuctx_switch_state(ctx, SPU_UTIL_SYSTEM); spuctx_switch_state(ctx, SPU_UTIL_SYSTEM);
......
...@@ -204,21 +204,51 @@ static void spu_remove_from_active_list(struct spu *spu) ...@@ -204,21 +204,51 @@ static void spu_remove_from_active_list(struct spu *spu)
static BLOCKING_NOTIFIER_HEAD(spu_switch_notifier); static BLOCKING_NOTIFIER_HEAD(spu_switch_notifier);
static void spu_switch_notify(struct spu *spu, struct spu_context *ctx) void spu_switch_notify(struct spu *spu, struct spu_context *ctx)
{ {
blocking_notifier_call_chain(&spu_switch_notifier, blocking_notifier_call_chain(&spu_switch_notifier,
ctx ? ctx->object_id : 0, spu); ctx ? ctx->object_id : 0, spu);
} }
static void notify_spus_active(void)
{
int node;
/*
* Wake up the active spu_contexts.
*
* When the awakened processes see their "notify_active" flag is set,
* they will call spu_switch_notify();
*/
for_each_online_node(node) {
struct spu *spu;
mutex_lock(&spu_prio->active_mutex[node]);
list_for_each_entry(spu, &spu_prio->active_list[node], list) {
struct spu_context *ctx = spu->ctx;
set_bit(SPU_SCHED_NOTIFY_ACTIVE, &ctx->sched_flags);
mb(); /* make sure any tasks woken up below */
/* can see the bit(s) set above */
wake_up_all(&ctx->stop_wq);
}
mutex_unlock(&spu_prio->active_mutex[node]);
}
}
int spu_switch_event_register(struct notifier_block * n) int spu_switch_event_register(struct notifier_block * n)
{ {
return blocking_notifier_chain_register(&spu_switch_notifier, n); int ret;
ret = blocking_notifier_chain_register(&spu_switch_notifier, n);
if (!ret)
notify_spus_active();
return ret;
} }
EXPORT_SYMBOL_GPL(spu_switch_event_register);
int spu_switch_event_unregister(struct notifier_block * n) int spu_switch_event_unregister(struct notifier_block * n)
{ {
return blocking_notifier_chain_unregister(&spu_switch_notifier, n); return blocking_notifier_chain_unregister(&spu_switch_notifier, n);
} }
EXPORT_SYMBOL_GPL(spu_switch_event_unregister);
/** /**
* spu_bind_context - bind spu context to physical spu * spu_bind_context - bind spu context to physical spu
......
...@@ -44,6 +44,11 @@ enum { ...@@ -44,6 +44,11 @@ enum {
SPU_SCHED_WAS_ACTIVE, /* was active upon spu_acquire_saved() */ SPU_SCHED_WAS_ACTIVE, /* was active upon spu_acquire_saved() */
}; };
/* ctx->sched_flags */
enum {
SPU_SCHED_NOTIFY_ACTIVE,
};
struct spu_context { struct spu_context {
struct spu *spu; /* pointer to a physical SPU */ struct spu *spu; /* pointer to a physical SPU */
struct spu_state csa; /* SPU context save area. */ struct spu_state csa; /* SPU context save area. */
...@@ -240,6 +245,7 @@ void spu_release_saved(struct spu_context *ctx); ...@@ -240,6 +245,7 @@ void spu_release_saved(struct spu_context *ctx);
int spu_activate(struct spu_context *ctx, unsigned long flags); int spu_activate(struct spu_context *ctx, unsigned long flags);
void spu_deactivate(struct spu_context *ctx); void spu_deactivate(struct spu_context *ctx);
void spu_yield(struct spu_context *ctx); void spu_yield(struct spu_context *ctx);
void spu_switch_notify(struct spu *spu, struct spu_context *ctx);
void spu_set_timeslice(struct spu_context *ctx); void spu_set_timeslice(struct spu_context *ctx);
void spu_update_sched_info(struct spu_context *ctx); void spu_update_sched_info(struct spu_context *ctx);
void __spu_update_sched_info(struct spu_context *ctx); void __spu_update_sched_info(struct spu_context *ctx);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment