1 #include <linux/wait.h>
2 #include <linux/ptrace.h>
3 
4 #include <asm/spu.h>
5 
6 #include "spufs.h"
7 
8 /* interrupt-level stop callback function. */
9 void spufs_stop_callback(struct spu *spu)
10 {
11 	struct spu_context *ctx = spu->ctx;
12 
13 	wake_up_all(&ctx->stop_wq);
14 }
15 
16 static inline int spu_stopped(struct spu_context *ctx, u32 * stat)
17 {
18 	struct spu *spu;
19 	u64 pte_fault;
20 
21 	*stat = ctx->ops->status_read(ctx);
22 	if (ctx->state != SPU_STATE_RUNNABLE)
23 		return 1;
24 	spu = ctx->spu;
25 	pte_fault = spu->dsisr &
26 	    (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED);
27 	return (!(*stat & 0x1) || pte_fault || spu->class_0_pending) ? 1 : 0;
28 }
29 
30 static inline int spu_run_init(struct spu_context *ctx, u32 * npc,
31 			       u32 * status)
32 {
33 	int ret;
34 
35 	if ((ret = spu_acquire_runnable(ctx)) != 0)
36 		return ret;
37 	ctx->ops->npc_write(ctx, *npc);
38 	ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_RUNNABLE);
39 	return 0;
40 }
41 
42 static inline int spu_run_fini(struct spu_context *ctx, u32 * npc,
43 			       u32 * status)
44 {
45 	int ret = 0;
46 
47 	*status = ctx->ops->status_read(ctx);
48 	*npc = ctx->ops->npc_read(ctx);
49 	spu_release(ctx);
50 
51 	if (signal_pending(current))
52 		ret = -ERESTARTSYS;
53 	if (unlikely(current->ptrace & PT_PTRACED)) {
54 		if ((*status & SPU_STATUS_STOPPED_BY_STOP)
55 		    && (*status >> SPU_STOP_STATUS_SHIFT) == 0x3fff) {
56 			force_sig(SIGTRAP, current);
57 			ret = -ERESTARTSYS;
58 		}
59 	}
60 	return ret;
61 }
62 
63 static inline int spu_reacquire_runnable(struct spu_context *ctx, u32 *npc,
64 				         u32 *status)
65 {
66 	int ret;
67 
68 	if ((ret = spu_run_fini(ctx, npc, status)) != 0)
69 		return ret;
70 	if (*status & (SPU_STATUS_STOPPED_BY_STOP |
71 		       SPU_STATUS_STOPPED_BY_HALT)) {
72 		return *status;
73 	}
74 	if ((ret = spu_run_init(ctx, npc, status)) != 0)
75 		return ret;
76 	return 0;
77 }
78 
79 static inline int spu_process_events(struct spu_context *ctx)
80 {
81 	struct spu *spu = ctx->spu;
82 	u64 pte_fault = MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED;
83 	int ret = 0;
84 
85 	if (spu->dsisr & pte_fault)
86 		ret = spu_irq_class_1_bottom(spu);
87 	if (spu->class_0_pending)
88 		ret = spu_irq_class_0_bottom(spu);
89 	if (!ret && signal_pending(current))
90 		ret = -ERESTARTSYS;
91 	return ret;
92 }
93 
94 long spufs_run_spu(struct file *file, struct spu_context *ctx,
95 		   u32 * npc, u32 * status)
96 {
97 	int ret;
98 
99 	if (down_interruptible(&ctx->run_sema))
100 		return -ERESTARTSYS;
101 
102 	ret = spu_run_init(ctx, npc, status);
103 	if (ret)
104 		goto out;
105 
106 	do {
107 		ret = spufs_wait(ctx->stop_wq, spu_stopped(ctx, status));
108 		if (unlikely(ret))
109 			break;
110 		if (unlikely(ctx->state != SPU_STATE_RUNNABLE)) {
111 			ret = spu_reacquire_runnable(ctx, npc, status);
112 			if (ret)
113 				goto out;
114 			continue;
115 		}
116 		ret = spu_process_events(ctx);
117 
118 	} while (!ret && !(*status & (SPU_STATUS_STOPPED_BY_STOP |
119 				      SPU_STATUS_STOPPED_BY_HALT)));
120 
121 	ctx->ops->runcntl_stop(ctx);
122 	ret = spu_run_fini(ctx, npc, status);
123 	if (!ret)
124 		ret = *status;
125 	spu_yield(ctx);
126 
127 out:
128 	up(&ctx->run_sema);
129 	return ret;
130 }
131 
132