]>
Commit | Line | Data |
---|---|---|
de6cc651 | 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ |
67207b96 AB |
2 | /* |
3 | * SPU file system | |
4 | * | |
5 | * (C) Copyright IBM Deutschland Entwicklung GmbH 2005 | |
6 | * | |
7 | * Author: Arnd Bergmann <arndb@de.ibm.com> | |
67207b96 AB |
8 | */ |
9 | #ifndef SPUFS_H | |
10 | #define SPUFS_H | |
11 | ||
12 | #include <linux/kref.h> | |
650f8b02 | 13 | #include <linux/mutex.h> |
67207b96 AB |
14 | #include <linux/spinlock.h> |
15 | #include <linux/fs.h> | |
ea1ae594 | 16 | #include <linux/cpumask.h> |
174cd4b1 | 17 | #include <linux/sched/signal.h> |
67207b96 AB |
18 | |
19 | #include <asm/spu.h> | |
5473af04 | 20 | #include <asm/spu_csa.h> |
b9e3bd77 | 21 | #include <asm/spu_info.h> |
67207b96 | 22 | |
87ff6090 JK |
23 | #define SPUFS_PS_MAP_SIZE 0x20000 |
24 | #define SPUFS_MFC_MAP_SIZE 0x1000 | |
25 | #define SPUFS_CNTL_MAP_SIZE 0x1000 | |
87ff6090 JK |
26 | #define SPUFS_SIGNAL_MAP_SIZE PAGE_SIZE |
27 | #define SPUFS_MSS_MAP_SIZE 0x1000 | |
28 | ||
67207b96 AB |
29 | /* The magic number for our file system */ |
30 | enum { | |
31 | SPUFS_MAGIC = 0x23c9b64e, | |
32 | }; | |
33 | ||
8b3d6663 | 34 | struct spu_context_ops; |
6263203e AB |
35 | struct spu_gang; |
36 | ||
36aaccc1 BN |
37 | /* ctx->sched_flags */ |
38 | enum { | |
39 | SPU_SCHED_NOTIFY_ACTIVE, | |
b2c863bd | 40 | SPU_SCHED_WAS_ACTIVE, /* was active upon spu_acquire_saved() */ |
ce7c191b | 41 | SPU_SCHED_SPU_RUN, /* context is within spu_run */ |
36aaccc1 BN |
42 | }; |
43 | ||
5158e9b5 CH |
44 | enum { |
45 | SWITCH_LOG_BUFSIZE = 4096, | |
46 | }; | |
47 | ||
48 | enum { | |
49 | SWITCH_LOG_START, | |
50 | SWITCH_LOG_STOP, | |
51 | SWITCH_LOG_EXIT, | |
52 | }; | |
53 | ||
54 | struct switch_log { | |
5158e9b5 CH |
55 | wait_queue_head_t wait; |
56 | unsigned long head; | |
57 | unsigned long tail; | |
58 | struct switch_log_entry { | |
cef37ac1 | 59 | struct timespec64 tstamp; |
5158e9b5 CH |
60 | s32 spu_id; |
61 | u32 type; | |
62 | u32 val; | |
63 | u64 timebase; | |
64 | } log[]; | |
65 | }; | |
66 | ||
67207b96 AB |
67 | struct spu_context { |
68 | struct spu *spu; /* pointer to a physical SPU */ | |
5473af04 | 69 | struct spu_state csa; /* SPU context save area. */ |
67207b96 | 70 | spinlock_t mmio_lock; /* protects mmio access */ |
6df10a82 MN |
71 | struct address_space *local_store; /* local store mapping. */ |
72 | struct address_space *mfc; /* 'mfc' area mappings. */ | |
43c2bbd9 CH |
73 | struct address_space *cntl; /* 'control' area mappings. */ |
74 | struct address_space *signal1; /* 'signal1' area mappings. */ | |
75 | struct address_space *signal2; /* 'signal2' area mappings. */ | |
76 | struct address_space *mss; /* 'mss' area mappings. */ | |
77 | struct address_space *psmap; /* 'psmap' area mappings. */ | |
47d3a5fa | 78 | struct mutex mapping_lock; |
86767277 | 79 | u64 object_id; /* user space pointer for oprofile */ |
8b3d6663 AB |
80 | |
81 | enum { SPU_STATE_RUNNABLE, SPU_STATE_SAVED } state; | |
650f8b02 | 82 | struct mutex state_mutex; |
e45d48a3 | 83 | struct mutex run_mutex; |
8b3d6663 AB |
84 | |
85 | struct mm_struct *owner; | |
67207b96 AB |
86 | |
87 | struct kref kref; | |
8b3d6663 AB |
88 | wait_queue_head_t ibox_wq; |
89 | wait_queue_head_t wbox_wq; | |
5110459f | 90 | wait_queue_head_t stop_wq; |
a33a7d73 | 91 | wait_queue_head_t mfc_wq; |
33bfd7a7 | 92 | wait_queue_head_t run_wq; |
a33a7d73 | 93 | u32 tagwait; |
8b3d6663 | 94 | struct spu_context_ops *ops; |
2a911f0b | 95 | struct work_struct reap_work; |
9add11da AB |
96 | unsigned long flags; |
97 | unsigned long event_return; | |
6263203e AB |
98 | |
99 | struct list_head gang_list; | |
100 | struct spu_gang *gang; | |
1474855d BN |
101 | struct kref *prof_priv_kref; |
102 | void ( * prof_priv_release) (struct kref *kref); | |
8389998a | 103 | |
476273ad CH |
104 | /* owner thread */ |
105 | pid_t tid; | |
106 | ||
8389998a | 107 | /* scheduler fields */ |
7022543e | 108 | struct list_head rq; |
37901802 | 109 | unsigned int time_slice; |
26bec673 | 110 | unsigned long sched_flags; |
ea1ae594 | 111 | cpumask_t cpus_allowed; |
2eb1b120 | 112 | int policy; |
8389998a | 113 | int prio; |
7a214200 | 114 | int last_ran; |
e9f8a0b6 CH |
115 | |
116 | /* statistics */ | |
117 | struct { | |
118 | /* updates protected by ctx->state_mutex */ | |
27ec41d3 AD |
119 | enum spu_utilization_state util_state; |
120 | unsigned long long tstamp; /* time of last state switch */ | |
121 | unsigned long long times[SPU_UTIL_MAX]; | |
e9f8a0b6 CH |
122 | unsigned long long vol_ctx_switch; |
123 | unsigned long long invol_ctx_switch; | |
124 | unsigned long long min_flt; | |
125 | unsigned long long maj_flt; | |
126 | unsigned long long hash_flt; | |
127 | unsigned long long slb_flt; | |
128 | unsigned long long slb_flt_base; /* # at last ctx switch */ | |
129 | unsigned long long class2_intr; | |
130 | unsigned long long class2_intr_base; /* # at last ctx switch */ | |
131 | unsigned long long libassist; | |
132 | } stats; | |
8e68e2f2 | 133 | |
5158e9b5 CH |
134 | /* context switch log */ |
135 | struct switch_log *switch_log; | |
136 | ||
8e68e2f2 AB |
137 | struct list_head aff_list; |
138 | int aff_head; | |
c5fc8d2a | 139 | int aff_offset; |
6263203e AB |
140 | }; |
141 | ||
142 | struct spu_gang { | |
143 | struct list_head list; | |
144 | struct mutex mutex; | |
145 | struct kref kref; | |
146 | int contexts; | |
8e68e2f2 AB |
147 | |
148 | struct spu_context *aff_ref_ctx; | |
149 | struct list_head aff_list_head; | |
150 | struct mutex aff_mutex; | |
151 | int aff_flags; | |
c5fc8d2a AB |
152 | struct spu *aff_ref_spu; |
153 | atomic_t aff_sched_count; | |
8b3d6663 AB |
154 | }; |
155 | ||
8e68e2f2 AB |
156 | /* Flag bits for spu_gang aff_flags */ |
157 | #define AFF_OFFSETS_SET 1 | |
158 | #define AFF_MERGED 2 | |
159 | ||
a33a7d73 AB |
160 | struct mfc_dma_command { |
161 | int32_t pad; /* reserved */ | |
162 | uint32_t lsa; /* local storage address */ | |
163 | uint64_t ea; /* effective address */ | |
164 | uint16_t size; /* transfer size */ | |
165 | uint16_t tag; /* command tag */ | |
166 | uint16_t class; /* class ID */ | |
167 | uint16_t cmd; /* command opcode */ | |
168 | }; | |
169 | ||
170 | ||
8b3d6663 AB |
171 | /* SPU context query/set operations. */ |
172 | struct spu_context_ops { | |
173 | int (*mbox_read) (struct spu_context * ctx, u32 * data); | |
174 | u32(*mbox_stat_read) (struct spu_context * ctx); | |
8153a5ea | 175 | __poll_t (*mbox_stat_poll)(struct spu_context *ctx, __poll_t events); |
8b3d6663 AB |
176 | int (*ibox_read) (struct spu_context * ctx, u32 * data); |
177 | int (*wbox_write) (struct spu_context * ctx, u32 data); | |
178 | u32(*signal1_read) (struct spu_context * ctx); | |
179 | void (*signal1_write) (struct spu_context * ctx, u32 data); | |
180 | u32(*signal2_read) (struct spu_context * ctx); | |
181 | void (*signal2_write) (struct spu_context * ctx, u32 data); | |
182 | void (*signal1_type_set) (struct spu_context * ctx, u64 val); | |
183 | u64(*signal1_type_get) (struct spu_context * ctx); | |
184 | void (*signal2_type_set) (struct spu_context * ctx, u64 val); | |
185 | u64(*signal2_type_get) (struct spu_context * ctx); | |
186 | u32(*npc_read) (struct spu_context * ctx); | |
187 | void (*npc_write) (struct spu_context * ctx, u32 data); | |
188 | u32(*status_read) (struct spu_context * ctx); | |
189 | char*(*get_ls) (struct spu_context * ctx); | |
cc210b3e | 190 | void (*privcntl_write) (struct spu_context *ctx, u64 data); |
3960c260 | 191 | u32 (*runcntl_read) (struct spu_context * ctx); |
5110459f | 192 | void (*runcntl_write) (struct spu_context * ctx, u32 data); |
c25620d7 | 193 | void (*runcntl_stop) (struct spu_context * ctx); |
ee2d7340 AB |
194 | void (*master_start) (struct spu_context * ctx); |
195 | void (*master_stop) (struct spu_context * ctx); | |
a33a7d73 AB |
196 | int (*set_mfc_query)(struct spu_context * ctx, u32 mask, u32 mode); |
197 | u32 (*read_mfc_tagstatus)(struct spu_context * ctx); | |
198 | u32 (*get_mfc_free_elements)(struct spu_context *ctx); | |
b9e3bd77 DGM |
199 | int (*send_mfc_command)(struct spu_context * ctx, |
200 | struct mfc_dma_command * cmd); | |
201 | void (*dma_info_read) (struct spu_context * ctx, | |
202 | struct spu_dma_info * info); | |
203 | void (*proxydma_info_read) (struct spu_context * ctx, | |
204 | struct spu_proxydma_info * info); | |
57dace23 | 205 | void (*restart_dma)(struct spu_context *ctx); |
67207b96 AB |
206 | }; |
207 | ||
8b3d6663 AB |
208 | extern struct spu_context_ops spu_hw_ops; |
209 | extern struct spu_context_ops spu_backing_ops; | |
210 | ||
67207b96 AB |
211 | struct spufs_inode_info { |
212 | struct spu_context *i_ctx; | |
6263203e | 213 | struct spu_gang *i_gang; |
67207b96 | 214 | struct inode vfs_inode; |
43c2bbd9 | 215 | int i_openers; |
67207b96 AB |
216 | }; |
217 | #define SPUFS_I(inode) \ | |
218 | container_of(inode, struct spufs_inode_info, vfs_inode) | |
219 | ||
23d893f5 JK |
220 | struct spufs_tree_descr { |
221 | const char *name; | |
222 | const struct file_operations *ops; | |
c6684b26 | 223 | umode_t mode; |
23d893f5 JK |
224 | size_t size; |
225 | }; | |
226 | ||
74254647 JK |
227 | extern const struct spufs_tree_descr spufs_dir_contents[]; |
228 | extern const struct spufs_tree_descr spufs_dir_nosched_contents[]; | |
229 | extern const struct spufs_tree_descr spufs_dir_debug_contents[]; | |
67207b96 AB |
230 | |
231 | /* system call implementation */ | |
98f06978 | 232 | extern struct spufs_calls spufs_calls; |
cdc3d562 | 233 | struct coredump_params; |
50af32a9 | 234 | long spufs_run_spu(struct spu_context *ctx, u32 *npc, u32 *status); |
1ba10681 | 235 | long spufs_create(struct path *nd, struct dentry *dentry, unsigned int flags, |
c6684b26 | 236 | umode_t mode, struct file *filp); |
48cad41f ME |
237 | /* ELF coredump callbacks for writing SPU ELF notes */ |
238 | extern int spufs_coredump_extra_notes_size(void); | |
cdc3d562 | 239 | extern int spufs_coredump_extra_notes_write(struct coredump_params *cprm); |
48cad41f | 240 | |
9c2e08c5 | 241 | extern const struct file_operations spufs_context_fops; |
67207b96 | 242 | |
6263203e AB |
243 | /* gang management */ |
244 | struct spu_gang *alloc_spu_gang(void); | |
245 | struct spu_gang *get_spu_gang(struct spu_gang *gang); | |
246 | int put_spu_gang(struct spu_gang *gang); | |
247 | void spu_gang_remove_ctx(struct spu_gang *gang, struct spu_context *ctx); | |
248 | void spu_gang_add_ctx(struct spu_gang *gang, struct spu_context *ctx); | |
249 | ||
57dace23 AB |
250 | /* fault handling */ |
251 | int spufs_handle_class1(struct spu_context *ctx); | |
d6ad39bc | 252 | int spufs_handle_class0(struct spu_context *ctx); |
57dace23 | 253 | |
c5fc8d2a AB |
254 | /* affinity */ |
255 | struct spu *affinity_check(struct spu_context *ctx); | |
256 | ||
67207b96 | 257 | /* context management */ |
65de66f0 | 258 | extern atomic_t nr_spu_contexts; |
c9101bdb | 259 | static inline int __must_check spu_acquire(struct spu_context *ctx) |
6a0641e5 | 260 | { |
c9101bdb | 261 | return mutex_lock_interruptible(&ctx->state_mutex); |
6a0641e5 CH |
262 | } |
263 | ||
264 | static inline void spu_release(struct spu_context *ctx) | |
265 | { | |
266 | mutex_unlock(&ctx->state_mutex); | |
267 | } | |
268 | ||
6263203e | 269 | struct spu_context * alloc_spu_context(struct spu_gang *gang); |
67207b96 AB |
270 | void destroy_spu_context(struct kref *kref); |
271 | struct spu_context * get_spu_context(struct spu_context *ctx); | |
272 | int put_spu_context(struct spu_context *ctx); | |
5110459f | 273 | void spu_unmap_mappings(struct spu_context *ctx); |
67207b96 | 274 | |
8b3d6663 | 275 | void spu_forget(struct spu_context *ctx); |
c9101bdb | 276 | int __must_check spu_acquire_saved(struct spu_context *ctx); |
27b1ea09 | 277 | void spu_release_saved(struct spu_context *ctx); |
50b520d4 | 278 | |
e65c2f6f LB |
279 | int spu_stopped(struct spu_context *ctx, u32 * stat); |
280 | void spu_del_from_rq(struct spu_context *ctx); | |
26bec673 | 281 | int spu_activate(struct spu_context *ctx, unsigned long flags); |
8b3d6663 AB |
282 | void spu_deactivate(struct spu_context *ctx); |
283 | void spu_yield(struct spu_context *ctx); | |
36aaccc1 | 284 | void spu_switch_notify(struct spu *spu, struct spu_context *ctx); |
5158e9b5 CH |
285 | void spu_switch_log_notify(struct spu *spu, struct spu_context *ctx, |
286 | u32 type, u32 val); | |
fe443ef2 | 287 | void spu_set_timeslice(struct spu_context *ctx); |
2cf2b3b4 CH |
288 | void spu_update_sched_info(struct spu_context *ctx); |
289 | void __spu_update_sched_info(struct spu_context *ctx); | |
8b3d6663 | 290 | int __init spu_sched_init(void); |
d1450317 | 291 | void spu_sched_exit(void); |
8b3d6663 | 292 | |
c6730ed4 JK |
293 | extern char *isolated_loader; |
294 | ||
ce8ab854 AB |
295 | /* |
296 | * spufs_wait | |
7022543e | 297 | * Same as wait_event_interruptible(), except that here |
ce8ab854 AB |
298 | * we need to call spu_release(ctx) before sleeping, and |
299 | * then spu_acquire(ctx) when awoken. | |
eebead5b | 300 | * |
73ac36ea | 301 | * Returns with state_mutex re-acquired when successful or |
eebead5b | 302 | * with -ERESTARTSYS and the state_mutex dropped when interrupted. |
ce8ab854 AB |
303 | */ |
304 | ||
305 | #define spufs_wait(wq, condition) \ | |
306 | ({ \ | |
307 | int __ret = 0; \ | |
308 | DEFINE_WAIT(__wait); \ | |
309 | for (;;) { \ | |
310 | prepare_to_wait(&(wq), &__wait, TASK_INTERRUPTIBLE); \ | |
311 | if (condition) \ | |
312 | break; \ | |
eebead5b | 313 | spu_release(ctx); \ |
d3764397 JK |
314 | if (signal_pending(current)) { \ |
315 | __ret = -ERESTARTSYS; \ | |
316 | break; \ | |
ce8ab854 | 317 | } \ |
d3764397 | 318 | schedule(); \ |
c9101bdb CH |
319 | __ret = spu_acquire(ctx); \ |
320 | if (__ret) \ | |
321 | break; \ | |
ce8ab854 AB |
322 | } \ |
323 | finish_wait(&(wq), &__wait); \ | |
324 | __ret; \ | |
325 | }) | |
326 | ||
8b3d6663 AB |
327 | size_t spu_wbox_write(struct spu_context *ctx, u32 data); |
328 | size_t spu_ibox_read(struct spu_context *ctx, u32 *data); | |
329 | ||
330 | /* irq callback funcs. */ | |
331 | void spufs_ibox_callback(struct spu *spu); | |
332 | void spufs_wbox_callback(struct spu *spu); | |
f3d69e05 | 333 | void spufs_stop_callback(struct spu *spu, int irq); |
a33a7d73 | 334 | void spufs_mfc_callback(struct spu *spu); |
9add11da | 335 | void spufs_dma_callback(struct spu *spu, int type); |
8b3d6663 | 336 | |
bf1ab978 DGM |
337 | extern struct spu_coredump_calls spufs_coredump_calls; |
338 | struct spufs_coredump_reader { | |
339 | char *name; | |
340 | ssize_t (*read)(struct spu_context *ctx, | |
341 | char __user *buffer, size_t size, loff_t *pos); | |
74de08bc | 342 | u64 (*get)(struct spu_context *ctx); |
bf1ab978 DGM |
343 | size_t size; |
344 | }; | |
74254647 | 345 | extern const struct spufs_coredump_reader spufs_coredump_read[]; |
bf1ab978 DGM |
346 | extern int spufs_coredump_num_notes; |
347 | ||
7cd58e43 JK |
348 | extern int spu_init_csa(struct spu_state *csa); |
349 | extern void spu_fini_csa(struct spu_state *csa); | |
350 | extern int spu_save(struct spu_state *prev, struct spu *spu); | |
351 | extern int spu_restore(struct spu_state *new, struct spu *spu); | |
352 | extern int spu_switch(struct spu_state *prev, struct spu_state *new, | |
353 | struct spu *spu); | |
354 | extern int spu_alloc_lscsa(struct spu_state *csa); | |
355 | extern void spu_free_lscsa(struct spu_state *csa); | |
356 | ||
357 | extern void spuctx_switch_state(struct spu_context *ctx, | |
358 | enum spu_utilization_state new_state); | |
fe2f896d | 359 | |
67207b96 | 360 | #endif |