diff options
-rw-r--r-- | arch/powerpc/platforms/cell/Makefile | 1 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/spu_coredump.c | 81 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/spufs/Makefile | 2 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/spufs/coredump.c | 238 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/spufs/file.c | 327 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/spufs/inode.c | 7 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/spufs/spufs.h | 11 | ||||
-rw-r--r-- | fs/binfmt_elf.c | 8 | ||||
-rw-r--r-- | include/asm-powerpc/elf.h | 13 | ||||
-rw-r--r-- | include/asm-powerpc/spu.h | 10 | ||||
-rw-r--r-- | include/linux/elf.h | 7 |
11 files changed, 618 insertions, 87 deletions
diff --git a/arch/powerpc/platforms/cell/Makefile b/arch/powerpc/platforms/cell/Makefile index 62c011e80929..f90e8337796c 100644 --- a/arch/powerpc/platforms/cell/Makefile +++ b/arch/powerpc/platforms/cell/Makefile | |||
@@ -15,5 +15,6 @@ spufs-modular-$(CONFIG_SPU_FS) += spu_syscalls.o | |||
15 | spu-priv1-$(CONFIG_PPC_CELL_NATIVE) += spu_priv1_mmio.o | 15 | spu-priv1-$(CONFIG_PPC_CELL_NATIVE) += spu_priv1_mmio.o |
16 | 16 | ||
17 | obj-$(CONFIG_SPU_BASE) += spu_callbacks.o spu_base.o \ | 17 | obj-$(CONFIG_SPU_BASE) += spu_callbacks.o spu_base.o \ |
18 | spu_coredump.o \ | ||
18 | $(spufs-modular-m) \ | 19 | $(spufs-modular-m) \ |
19 | $(spu-priv1-y) spufs/ | 20 | $(spu-priv1-y) spufs/ |
diff --git a/arch/powerpc/platforms/cell/spu_coredump.c b/arch/powerpc/platforms/cell/spu_coredump.c new file mode 100644 index 000000000000..6915b418ee73 --- /dev/null +++ b/arch/powerpc/platforms/cell/spu_coredump.c | |||
@@ -0,0 +1,81 @@ | |||
1 | /* | ||
2 | * SPU core dump code | ||
3 | * | ||
4 | * (C) Copyright 2006 IBM Corp. | ||
5 | * | ||
6 | * Author: Dwayne Grant McConnell <decimal@us.ibm.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2, or (at your option) | ||
11 | * any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | */ | ||
22 | |||
23 | #include <linux/file.h> | ||
24 | #include <linux/module.h> | ||
25 | #include <linux/syscalls.h> | ||
26 | |||
27 | #include <asm/spu.h> | ||
28 | |||
29 | static struct spu_coredump_calls spu_coredump_calls; | ||
30 | static DEFINE_MUTEX(spu_coredump_mutex); | ||
31 | |||
32 | int arch_notes_size(void) | ||
33 | { | ||
34 | long ret; | ||
35 | struct module *owner = spu_coredump_calls.owner; | ||
36 | |||
37 | ret = -ENOSYS; | ||
38 | mutex_lock(&spu_coredump_mutex); | ||
39 | if (owner && try_module_get(owner)) { | ||
40 | ret = spu_coredump_calls.arch_notes_size(); | ||
41 | module_put(owner); | ||
42 | } | ||
43 | mutex_unlock(&spu_coredump_mutex); | ||
44 | return ret; | ||
45 | } | ||
46 | |||
47 | void arch_write_notes(struct file *file) | ||
48 | { | ||
49 | struct module *owner = spu_coredump_calls.owner; | ||
50 | |||
51 | mutex_lock(&spu_coredump_mutex); | ||
52 | if (owner && try_module_get(owner)) { | ||
53 | spu_coredump_calls.arch_write_notes(file); | ||
54 | module_put(owner); | ||
55 | } | ||
56 | mutex_unlock(&spu_coredump_mutex); | ||
57 | } | ||
58 | |||
59 | int register_arch_coredump_calls(struct spu_coredump_calls *calls) | ||
60 | { | ||
61 | if (spu_coredump_calls.owner) | ||
62 | return -EBUSY; | ||
63 | |||
64 | mutex_lock(&spu_coredump_mutex); | ||
65 | spu_coredump_calls.arch_notes_size = calls->arch_notes_size; | ||
66 | spu_coredump_calls.arch_write_notes = calls->arch_write_notes; | ||
67 | spu_coredump_calls.owner = calls->owner; | ||
68 | mutex_unlock(&spu_coredump_mutex); | ||
69 | return 0; | ||
70 | } | ||
71 | EXPORT_SYMBOL_GPL(register_arch_coredump_calls); | ||
72 | |||
73 | void unregister_arch_coredump_calls(struct spu_coredump_calls *calls) | ||
74 | { | ||
75 | BUG_ON(spu_coredump_calls.owner != calls->owner); | ||
76 | |||
77 | mutex_lock(&spu_coredump_mutex); | ||
78 | spu_coredump_calls.owner = NULL; | ||
79 | mutex_unlock(&spu_coredump_mutex); | ||
80 | } | ||
81 | EXPORT_SYMBOL_GPL(unregister_arch_coredump_calls); | ||
diff --git a/arch/powerpc/platforms/cell/spufs/Makefile b/arch/powerpc/platforms/cell/spufs/Makefile index ecdfbb35f82e..472217d19faf 100644 --- a/arch/powerpc/platforms/cell/spufs/Makefile +++ b/arch/powerpc/platforms/cell/spufs/Makefile | |||
@@ -1,7 +1,7 @@ | |||
1 | obj-y += switch.o | 1 | obj-y += switch.o |
2 | 2 | ||
3 | obj-$(CONFIG_SPU_FS) += spufs.o | 3 | obj-$(CONFIG_SPU_FS) += spufs.o |
4 | spufs-y += inode.o file.o context.o syscalls.o | 4 | spufs-y += inode.o file.o context.o syscalls.o coredump.o |
5 | spufs-y += sched.o backing_ops.o hw_ops.o run.o gang.o | 5 | spufs-y += sched.o backing_ops.o hw_ops.o run.o gang.o |
6 | 6 | ||
7 | # Rules to build switch.o with the help of SPU tool chain | 7 | # Rules to build switch.o with the help of SPU tool chain |
diff --git a/arch/powerpc/platforms/cell/spufs/coredump.c b/arch/powerpc/platforms/cell/spufs/coredump.c new file mode 100644 index 000000000000..26945c491f6b --- /dev/null +++ b/arch/powerpc/platforms/cell/spufs/coredump.c | |||
@@ -0,0 +1,238 @@ | |||
1 | /* | ||
2 | * SPU core dump code | ||
3 | * | ||
4 | * (C) Copyright 2006 IBM Corp. | ||
5 | * | ||
6 | * Author: Dwayne Grant McConnell <decimal@us.ibm.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2, or (at your option) | ||
11 | * any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | */ | ||
22 | |||
23 | #include <linux/elf.h> | ||
24 | #include <linux/file.h> | ||
25 | #include <linux/fs.h> | ||
26 | #include <linux/list.h> | ||
27 | #include <linux/module.h> | ||
28 | #include <linux/syscalls.h> | ||
29 | |||
30 | #include <asm/uaccess.h> | ||
31 | |||
32 | #include "spufs.h" | ||
33 | |||
34 | struct spufs_ctx_info { | ||
35 | struct list_head list; | ||
36 | int dfd; | ||
37 | int memsize; /* in bytes */ | ||
38 | struct spu_context *ctx; | ||
39 | }; | ||
40 | |||
41 | static LIST_HEAD(ctx_info_list); | ||
42 | |||
43 | static ssize_t do_coredump_read(int num, struct spu_context *ctx, void __user *buffer, | ||
44 | size_t size, loff_t *off) | ||
45 | { | ||
46 | u64 data; | ||
47 | int ret; | ||
48 | |||
49 | if (spufs_coredump_read[num].read) | ||
50 | return spufs_coredump_read[num].read(ctx, buffer, size, off); | ||
51 | |||
52 | data = spufs_coredump_read[num].get(ctx); | ||
53 | ret = copy_to_user(buffer, &data, 8); | ||
54 | return ret ? -EFAULT : 8; | ||
55 | } | ||
56 | |||
57 | /* | ||
58 | * These are the only things you should do on a core-file: use only these | ||
59 | * functions to write out all the necessary info. | ||
60 | */ | ||
61 | static int spufs_dump_write(struct file *file, const void *addr, int nr) | ||
62 | { | ||
63 | return file->f_op->write(file, addr, nr, &file->f_pos) == nr; | ||
64 | } | ||
65 | |||
66 | static int spufs_dump_seek(struct file *file, loff_t off) | ||
67 | { | ||
68 | if (file->f_op->llseek) { | ||
69 | if (file->f_op->llseek(file, off, 0) != off) | ||
70 | return 0; | ||
71 | } else | ||
72 | file->f_pos = off; | ||
73 | return 1; | ||
74 | } | ||
75 | |||
76 | static void spufs_fill_memsize(struct spufs_ctx_info *ctx_info) | ||
77 | { | ||
78 | struct spu_context *ctx; | ||
79 | unsigned long long lslr; | ||
80 | |||
81 | ctx = ctx_info->ctx; | ||
82 | lslr = ctx->csa.priv2.spu_lslr_RW; | ||
83 | ctx_info->memsize = lslr + 1; | ||
84 | } | ||
85 | |||
86 | static int spufs_ctx_note_size(struct spufs_ctx_info *ctx_info) | ||
87 | { | ||
88 | int dfd, memsize, i, sz, total = 0; | ||
89 | char *name; | ||
90 | char fullname[80]; | ||
91 | |||
92 | dfd = ctx_info->dfd; | ||
93 | memsize = ctx_info->memsize; | ||
94 | |||
95 | for (i = 0; spufs_coredump_read[i].name; i++) { | ||
96 | name = spufs_coredump_read[i].name; | ||
97 | sz = spufs_coredump_read[i].size; | ||
98 | |||
99 | sprintf(fullname, "SPU/%d/%s", dfd, name); | ||
100 | |||
101 | total += sizeof(struct elf_note); | ||
102 | total += roundup(strlen(fullname) + 1, 4); | ||
103 | if (!strcmp(name, "mem")) | ||
104 | total += roundup(memsize, 4); | ||
105 | else | ||
106 | total += roundup(sz, 4); | ||
107 | } | ||
108 | |||
109 | return total; | ||
110 | } | ||
111 | |||
112 | static int spufs_add_one_context(struct file *file, int dfd) | ||
113 | { | ||
114 | struct spu_context *ctx; | ||
115 | struct spufs_ctx_info *ctx_info; | ||
116 | int size; | ||
117 | |||
118 | ctx = SPUFS_I(file->f_dentry->d_inode)->i_ctx; | ||
119 | if (ctx->flags & SPU_CREATE_NOSCHED) | ||
120 | return 0; | ||
121 | |||
122 | ctx_info = kzalloc(sizeof(*ctx_info), GFP_KERNEL); | ||
123 | if (unlikely(!ctx_info)) | ||
124 | return -ENOMEM; | ||
125 | |||
126 | ctx_info->dfd = dfd; | ||
127 | ctx_info->ctx = ctx; | ||
128 | |||
129 | spufs_fill_memsize(ctx_info); | ||
130 | |||
131 | size = spufs_ctx_note_size(ctx_info); | ||
132 | list_add(&ctx_info->list, &ctx_info_list); | ||
133 | return size; | ||
134 | } | ||
135 | |||
136 | /* | ||
137 | * The additional architecture-specific notes for Cell are various | ||
138 | * context files in the spu context. | ||
139 | * | ||
140 | * This function iterates over all open file descriptors and sees | ||
141 | * if they are a directory in spufs. In that case we use spufs | ||
142 | * internal functionality to dump them without needing to actually | ||
143 | * open the files. | ||
144 | */ | ||
145 | static int spufs_arch_notes_size(void) | ||
146 | { | ||
147 | struct fdtable *fdt = files_fdtable(current->files); | ||
148 | int size = 0, fd; | ||
149 | |||
150 | for (fd = 0; fd < fdt->max_fdset && fd < fdt->max_fds; fd++) { | ||
151 | if (FD_ISSET(fd, fdt->open_fds)) { | ||
152 | struct file *file = fcheck(fd); | ||
153 | |||
154 | if (file && file->f_op == &spufs_context_fops) { | ||
155 | int rval = spufs_add_one_context(file, fd); | ||
156 | if (rval < 0) | ||
157 | break; | ||
158 | size += rval; | ||
159 | } | ||
160 | } | ||
161 | } | ||
162 | |||
163 | return size; | ||
164 | } | ||
165 | |||
166 | static void spufs_arch_write_note(struct spufs_ctx_info *ctx_info, int i, | ||
167 | struct file *file) | ||
168 | { | ||
169 | struct spu_context *ctx; | ||
170 | loff_t pos = 0; | ||
171 | int sz, dfd, rc, total = 0; | ||
172 | const int bufsz = 4096; | ||
173 | char *name; | ||
174 | char fullname[80], *buf; | ||
175 | struct elf_note en; | ||
176 | |||
177 | buf = kmalloc(bufsz, GFP_KERNEL); | ||
178 | if (!buf) | ||
179 | return; | ||
180 | |||
181 | dfd = ctx_info->dfd; | ||
182 | name = spufs_coredump_read[i].name; | ||
183 | |||
184 | if (!strcmp(name, "mem")) | ||
185 | sz = ctx_info->memsize; | ||
186 | else | ||
187 | sz = spufs_coredump_read[i].size; | ||
188 | |||
189 | ctx = ctx_info->ctx; | ||
190 | if (!ctx) { | ||
191 | return; | ||
192 | } | ||
193 | |||
194 | sprintf(fullname, "SPU/%d/%s", dfd, name); | ||
195 | en.n_namesz = strlen(fullname) + 1; | ||
196 | en.n_descsz = sz; | ||
197 | en.n_type = NT_SPU; | ||
198 | |||
199 | if (!spufs_dump_write(file, &en, sizeof(en))) | ||
200 | return; | ||
201 | if (!spufs_dump_write(file, fullname, en.n_namesz)) | ||
202 | return; | ||
203 | if (!spufs_dump_seek(file, roundup((unsigned long)file->f_pos, 4))) | ||
204 | return; | ||
205 | |||
206 | do { | ||
207 | rc = do_coredump_read(i, ctx, buf, bufsz, &pos); | ||
208 | if (rc > 0) { | ||
209 | if (!spufs_dump_write(file, buf, rc)) | ||
210 | return; | ||
211 | total += rc; | ||
212 | } | ||
213 | } while (rc == bufsz && total < sz); | ||
214 | |||
215 | spufs_dump_seek(file, roundup((unsigned long)file->f_pos | ||
216 | - total + sz, 4)); | ||
217 | } | ||
218 | |||
219 | static void spufs_arch_write_notes(struct file *file) | ||
220 | { | ||
221 | int j; | ||
222 | struct spufs_ctx_info *ctx_info, *next; | ||
223 | |||
224 | list_for_each_entry_safe(ctx_info, next, &ctx_info_list, list) { | ||
225 | spu_acquire_saved(ctx_info->ctx); | ||
226 | for (j = 0; j < spufs_coredump_num_notes; j++) | ||
227 | spufs_arch_write_note(ctx_info, j, file); | ||
228 | spu_release(ctx_info->ctx); | ||
229 | list_del(&ctx_info->list); | ||
230 | kfree(ctx_info); | ||
231 | } | ||
232 | } | ||
233 | |||
234 | struct spu_coredump_calls spufs_coredump_calls = { | ||
235 | .arch_notes_size = spufs_arch_notes_size, | ||
236 | .arch_write_notes = spufs_arch_write_notes, | ||
237 | .owner = THIS_MODULE, | ||
238 | }; | ||
diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c index 50e0afc46ad2..347eff56fcbd 100644 --- a/arch/powerpc/platforms/cell/spufs/file.c +++ b/arch/powerpc/platforms/cell/spufs/file.c | |||
@@ -39,7 +39,6 @@ | |||
39 | 39 | ||
40 | #define SPUFS_MMAP_4K (PAGE_SIZE == 0x1000) | 40 | #define SPUFS_MMAP_4K (PAGE_SIZE == 0x1000) |
41 | 41 | ||
42 | |||
43 | static int | 42 | static int |
44 | spufs_mem_open(struct inode *inode, struct file *file) | 43 | spufs_mem_open(struct inode *inode, struct file *file) |
45 | { | 44 | { |
@@ -52,18 +51,23 @@ spufs_mem_open(struct inode *inode, struct file *file) | |||
52 | } | 51 | } |
53 | 52 | ||
54 | static ssize_t | 53 | static ssize_t |
54 | __spufs_mem_read(struct spu_context *ctx, char __user *buffer, | ||
55 | size_t size, loff_t *pos) | ||
56 | { | ||
57 | char *local_store = ctx->ops->get_ls(ctx); | ||
58 | return simple_read_from_buffer(buffer, size, pos, local_store, | ||
59 | LS_SIZE); | ||
60 | } | ||
61 | |||
62 | static ssize_t | ||
55 | spufs_mem_read(struct file *file, char __user *buffer, | 63 | spufs_mem_read(struct file *file, char __user *buffer, |
56 | size_t size, loff_t *pos) | 64 | size_t size, loff_t *pos) |
57 | { | 65 | { |
58 | struct spu_context *ctx = file->private_data; | ||
59 | char *local_store; | ||
60 | int ret; | 66 | int ret; |
67 | struct spu_context *ctx = file->private_data; | ||
61 | 68 | ||
62 | spu_acquire(ctx); | 69 | spu_acquire(ctx); |
63 | 70 | ret = __spufs_mem_read(ctx, buffer, size, pos); | |
64 | local_store = ctx->ops->get_ls(ctx); | ||
65 | ret = simple_read_from_buffer(buffer, size, pos, local_store, LS_SIZE); | ||
66 | |||
67 | spu_release(ctx); | 71 | spu_release(ctx); |
68 | return ret; | 72 | return ret; |
69 | } | 73 | } |
@@ -262,18 +266,23 @@ spufs_regs_open(struct inode *inode, struct file *file) | |||
262 | } | 266 | } |
263 | 267 | ||
264 | static ssize_t | 268 | static ssize_t |
269 | __spufs_regs_read(struct spu_context *ctx, char __user *buffer, | ||
270 | size_t size, loff_t *pos) | ||
271 | { | ||
272 | struct spu_lscsa *lscsa = ctx->csa.lscsa; | ||
273 | return simple_read_from_buffer(buffer, size, pos, | ||
274 | lscsa->gprs, sizeof lscsa->gprs); | ||
275 | } | ||
276 | |||
277 | static ssize_t | ||
265 | spufs_regs_read(struct file *file, char __user *buffer, | 278 | spufs_regs_read(struct file *file, char __user *buffer, |
266 | size_t size, loff_t *pos) | 279 | size_t size, loff_t *pos) |
267 | { | 280 | { |
268 | struct spu_context *ctx = file->private_data; | ||
269 | struct spu_lscsa *lscsa = ctx->csa.lscsa; | ||
270 | int ret; | 281 | int ret; |
282 | struct spu_context *ctx = file->private_data; | ||
271 | 283 | ||
272 | spu_acquire_saved(ctx); | 284 | spu_acquire_saved(ctx); |
273 | 285 | ret = __spufs_regs_read(ctx, buffer, size, pos); | |
274 | ret = simple_read_from_buffer(buffer, size, pos, | ||
275 | lscsa->gprs, sizeof lscsa->gprs); | ||
276 | |||
277 | spu_release(ctx); | 286 | spu_release(ctx); |
278 | return ret; | 287 | return ret; |
279 | } | 288 | } |
@@ -308,18 +317,23 @@ static struct file_operations spufs_regs_fops = { | |||
308 | }; | 317 | }; |
309 | 318 | ||
310 | static ssize_t | 319 | static ssize_t |
320 | __spufs_fpcr_read(struct spu_context *ctx, char __user * buffer, | ||
321 | size_t size, loff_t * pos) | ||
322 | { | ||
323 | struct spu_lscsa *lscsa = ctx->csa.lscsa; | ||
324 | return simple_read_from_buffer(buffer, size, pos, | ||
325 | &lscsa->fpcr, sizeof(lscsa->fpcr)); | ||
326 | } | ||
327 | |||
328 | static ssize_t | ||
311 | spufs_fpcr_read(struct file *file, char __user * buffer, | 329 | spufs_fpcr_read(struct file *file, char __user * buffer, |
312 | size_t size, loff_t * pos) | 330 | size_t size, loff_t * pos) |
313 | { | 331 | { |
314 | struct spu_context *ctx = file->private_data; | ||
315 | struct spu_lscsa *lscsa = ctx->csa.lscsa; | ||
316 | int ret; | 332 | int ret; |
333 | struct spu_context *ctx = file->private_data; | ||
317 | 334 | ||
318 | spu_acquire_saved(ctx); | 335 | spu_acquire_saved(ctx); |
319 | 336 | ret = __spufs_fpcr_read(ctx, buffer, size, pos); | |
320 | ret = simple_read_from_buffer(buffer, size, pos, | ||
321 | &lscsa->fpcr, sizeof(lscsa->fpcr)); | ||
322 | |||
323 | spu_release(ctx); | 337 | spu_release(ctx); |
324 | return ret; | 338 | return ret; |
325 | } | 339 | } |
@@ -719,22 +733,19 @@ static int spufs_signal1_open(struct inode *inode, struct file *file) | |||
719 | return nonseekable_open(inode, file); | 733 | return nonseekable_open(inode, file); |
720 | } | 734 | } |
721 | 735 | ||
722 | static ssize_t spufs_signal1_read(struct file *file, char __user *buf, | 736 | static ssize_t __spufs_signal1_read(struct spu_context *ctx, char __user *buf, |
723 | size_t len, loff_t *pos) | 737 | size_t len, loff_t *pos) |
724 | { | 738 | { |
725 | struct spu_context *ctx = file->private_data; | ||
726 | int ret = 0; | 739 | int ret = 0; |
727 | u32 data; | 740 | u32 data; |
728 | 741 | ||
729 | if (len < 4) | 742 | if (len < 4) |
730 | return -EINVAL; | 743 | return -EINVAL; |
731 | 744 | ||
732 | spu_acquire_saved(ctx); | ||
733 | if (ctx->csa.spu_chnlcnt_RW[3]) { | 745 | if (ctx->csa.spu_chnlcnt_RW[3]) { |
734 | data = ctx->csa.spu_chnldata_RW[3]; | 746 | data = ctx->csa.spu_chnldata_RW[3]; |
735 | ret = 4; | 747 | ret = 4; |
736 | } | 748 | } |
737 | spu_release(ctx); | ||
738 | 749 | ||
739 | if (!ret) | 750 | if (!ret) |
740 | goto out; | 751 | goto out; |
@@ -746,6 +757,19 @@ out: | |||
746 | return ret; | 757 | return ret; |
747 | } | 758 | } |
748 | 759 | ||
760 | static ssize_t spufs_signal1_read(struct file *file, char __user *buf, | ||
761 | size_t len, loff_t *pos) | ||
762 | { | ||
763 | int ret; | ||
764 | struct spu_context *ctx = file->private_data; | ||
765 | |||
766 | spu_acquire_saved(ctx); | ||
767 | ret = __spufs_signal1_read(ctx, buf, len, pos); | ||
768 | spu_release(ctx); | ||
769 | |||
770 | return ret; | ||
771 | } | ||
772 | |||
749 | static ssize_t spufs_signal1_write(struct file *file, const char __user *buf, | 773 | static ssize_t spufs_signal1_write(struct file *file, const char __user *buf, |
750 | size_t len, loff_t *pos) | 774 | size_t len, loff_t *pos) |
751 | { | 775 | { |
@@ -816,22 +840,19 @@ static int spufs_signal2_open(struct inode *inode, struct file *file) | |||
816 | return nonseekable_open(inode, file); | 840 | return nonseekable_open(inode, file); |
817 | } | 841 | } |
818 | 842 | ||
819 | static ssize_t spufs_signal2_read(struct file *file, char __user *buf, | 843 | static ssize_t __spufs_signal2_read(struct spu_context *ctx, char __user *buf, |
820 | size_t len, loff_t *pos) | 844 | size_t len, loff_t *pos) |
821 | { | 845 | { |
822 | struct spu_context *ctx = file->private_data; | ||
823 | int ret = 0; | 846 | int ret = 0; |
824 | u32 data; | 847 | u32 data; |
825 | 848 | ||
826 | if (len < 4) | 849 | if (len < 4) |
827 | return -EINVAL; | 850 | return -EINVAL; |
828 | 851 | ||
829 | spu_acquire_saved(ctx); | ||
830 | if (ctx->csa.spu_chnlcnt_RW[4]) { | 852 | if (ctx->csa.spu_chnlcnt_RW[4]) { |
831 | data = ctx->csa.spu_chnldata_RW[4]; | 853 | data = ctx->csa.spu_chnldata_RW[4]; |
832 | ret = 4; | 854 | ret = 4; |
833 | } | 855 | } |
834 | spu_release(ctx); | ||
835 | 856 | ||
836 | if (!ret) | 857 | if (!ret) |
837 | goto out; | 858 | goto out; |
@@ -840,7 +861,20 @@ static ssize_t spufs_signal2_read(struct file *file, char __user *buf, | |||
840 | return -EFAULT; | 861 | return -EFAULT; |
841 | 862 | ||
842 | out: | 863 | out: |
843 | return 4; | 864 | return ret; |
865 | } | ||
866 | |||
867 | static ssize_t spufs_signal2_read(struct file *file, char __user *buf, | ||
868 | size_t len, loff_t *pos) | ||
869 | { | ||
870 | struct spu_context *ctx = file->private_data; | ||
871 | int ret; | ||
872 | |||
873 | spu_acquire_saved(ctx); | ||
874 | ret = __spufs_signal2_read(ctx, buf, len, pos); | ||
875 | spu_release(ctx); | ||
876 | |||
877 | return ret; | ||
844 | } | 878 | } |
845 | 879 | ||
846 | static ssize_t spufs_signal2_write(struct file *file, const char __user *buf, | 880 | static ssize_t spufs_signal2_write(struct file *file, const char __user *buf, |
@@ -916,13 +950,19 @@ static void spufs_signal1_type_set(void *data, u64 val) | |||
916 | spu_release(ctx); | 950 | spu_release(ctx); |
917 | } | 951 | } |
918 | 952 | ||
953 | static u64 __spufs_signal1_type_get(void *data) | ||
954 | { | ||
955 | struct spu_context *ctx = data; | ||
956 | return ctx->ops->signal1_type_get(ctx); | ||
957 | } | ||
958 | |||
919 | static u64 spufs_signal1_type_get(void *data) | 959 | static u64 spufs_signal1_type_get(void *data) |
920 | { | 960 | { |
921 | struct spu_context *ctx = data; | 961 | struct spu_context *ctx = data; |
922 | u64 ret; | 962 | u64 ret; |
923 | 963 | ||
924 | spu_acquire(ctx); | 964 | spu_acquire(ctx); |
925 | ret = ctx->ops->signal1_type_get(ctx); | 965 | ret = __spufs_signal1_type_get(data); |
926 | spu_release(ctx); | 966 | spu_release(ctx); |
927 | 967 | ||
928 | return ret; | 968 | return ret; |
@@ -939,13 +979,19 @@ static void spufs_signal2_type_set(void *data, u64 val) | |||
939 | spu_release(ctx); | 979 | spu_release(ctx); |
940 | } | 980 | } |
941 | 981 | ||
982 | static u64 __spufs_signal2_type_get(void *data) | ||
983 | { | ||
984 | struct spu_context *ctx = data; | ||
985 | return ctx->ops->signal2_type_get(ctx); | ||
986 | } | ||
987 | |||
942 | static u64 spufs_signal2_type_get(void *data) | 988 | static u64 spufs_signal2_type_get(void *data) |
943 | { | 989 | { |
944 | struct spu_context *ctx = data; | 990 | struct spu_context *ctx = data; |
945 | u64 ret; | 991 | u64 ret; |
946 | 992 | ||
947 | spu_acquire(ctx); | 993 | spu_acquire(ctx); |
948 | ret = ctx->ops->signal2_type_get(ctx); | 994 | ret = __spufs_signal2_type_get(data); |
949 | spu_release(ctx); | 995 | spu_release(ctx); |
950 | 996 | ||
951 | return ret; | 997 | return ret; |
@@ -1387,13 +1433,19 @@ static void spufs_decr_set(void *data, u64 val) | |||
1387 | spu_release(ctx); | 1433 | spu_release(ctx); |
1388 | } | 1434 | } |
1389 | 1435 | ||
1390 | static u64 spufs_decr_get(void *data) | 1436 | static u64 __spufs_decr_get(void *data) |
1391 | { | 1437 | { |
1392 | struct spu_context *ctx = data; | 1438 | struct spu_context *ctx = data; |
1393 | struct spu_lscsa *lscsa = ctx->csa.lscsa; | 1439 | struct spu_lscsa *lscsa = ctx->csa.lscsa; |
1440 | return lscsa->decr.slot[0]; | ||
1441 | } | ||
1442 | |||
1443 | static u64 spufs_decr_get(void *data) | ||
1444 | { | ||
1445 | struct spu_context *ctx = data; | ||
1394 | u64 ret; | 1446 | u64 ret; |
1395 | spu_acquire_saved(ctx); | 1447 | spu_acquire_saved(ctx); |
1396 | ret = lscsa->decr.slot[0]; | 1448 | ret = __spufs_decr_get(data); |
1397 | spu_release(ctx); | 1449 | spu_release(ctx); |
1398 | return ret; | 1450 | return ret; |
1399 | } | 1451 | } |
@@ -1409,13 +1461,19 @@ static void spufs_decr_status_set(void *data, u64 val) | |||
1409 | spu_release(ctx); | 1461 | spu_release(ctx); |
1410 | } | 1462 | } |
1411 | 1463 | ||
1412 | static u64 spufs_decr_status_get(void *data) | 1464 | static u64 __spufs_decr_status_get(void *data) |
1413 | { | 1465 | { |
1414 | struct spu_context *ctx = data; | 1466 | struct spu_context *ctx = data; |
1415 | struct spu_lscsa *lscsa = ctx->csa.lscsa; | 1467 | struct spu_lscsa *lscsa = ctx->csa.lscsa; |
1468 | return lscsa->decr_status.slot[0]; | ||
1469 | } | ||
1470 | |||
1471 | static u64 spufs_decr_status_get(void *data) | ||
1472 | { | ||
1473 | struct spu_context *ctx = data; | ||
1416 | u64 ret; | 1474 | u64 ret; |
1417 | spu_acquire_saved(ctx); | 1475 | spu_acquire_saved(ctx); |
1418 | ret = lscsa->decr_status.slot[0]; | 1476 | ret = __spufs_decr_status_get(data); |
1419 | spu_release(ctx); | 1477 | spu_release(ctx); |
1420 | return ret; | 1478 | return ret; |
1421 | } | 1479 | } |
@@ -1431,30 +1489,43 @@ static void spufs_event_mask_set(void *data, u64 val) | |||
1431 | spu_release(ctx); | 1489 | spu_release(ctx); |
1432 | } | 1490 | } |
1433 | 1491 | ||
1434 | static u64 spufs_event_mask_get(void *data) | 1492 | static u64 __spufs_event_mask_get(void *data) |
1435 | { | 1493 | { |
1436 | struct spu_context *ctx = data; | 1494 | struct spu_context *ctx = data; |
1437 | struct spu_lscsa *lscsa = ctx->csa.lscsa; | 1495 | struct spu_lscsa *lscsa = ctx->csa.lscsa; |
1496 | return lscsa->event_mask.slot[0]; | ||
1497 | } | ||
1498 | |||
1499 | static u64 spufs_event_mask_get(void *data) | ||
1500 | { | ||
1501 | struct spu_context *ctx = data; | ||
1438 | u64 ret; | 1502 | u64 ret; |
1439 | spu_acquire_saved(ctx); | 1503 | spu_acquire_saved(ctx); |
1440 | ret = lscsa->event_mask.slot[0]; | 1504 | ret = __spufs_event_mask_get(data); |
1441 | spu_release(ctx); | 1505 | spu_release(ctx); |
1442 | return ret; | 1506 | return ret; |
1443 | } | 1507 | } |
1444 | DEFINE_SIMPLE_ATTRIBUTE(spufs_event_mask_ops, spufs_event_mask_get, | 1508 | DEFINE_SIMPLE_ATTRIBUTE(spufs_event_mask_ops, spufs_event_mask_get, |
1445 | spufs_event_mask_set, "0x%llx\n") | 1509 | spufs_event_mask_set, "0x%llx\n") |
1446 | 1510 | ||
1447 | static u64 spufs_event_status_get(void *data) | 1511 | static u64 __spufs_event_status_get(void *data) |
1448 | { | 1512 | { |
1449 | struct spu_context *ctx = data; | 1513 | struct spu_context *ctx = data; |
1450 | struct spu_state *state = &ctx->csa; | 1514 | struct spu_state *state = &ctx->csa; |
1451 | u64 ret = 0; | ||
1452 | u64 stat; | 1515 | u64 stat; |
1453 | |||
1454 | spu_acquire_saved(ctx); | ||
1455 | stat = state->spu_chnlcnt_RW[0]; | 1516 | stat = state->spu_chnlcnt_RW[0]; |
1456 | if (stat) | 1517 | if (stat) |
1457 | ret = state->spu_chnldata_RW[0]; | 1518 | return state->spu_chnldata_RW[0]; |
1519 | return 0; | ||
1520 | } | ||
1521 | |||
1522 | static u64 spufs_event_status_get(void *data) | ||
1523 | { | ||
1524 | struct spu_context *ctx = data; | ||
1525 | u64 ret = 0; | ||
1526 | |||
1527 | spu_acquire_saved(ctx); | ||
1528 | ret = __spufs_event_status_get(data); | ||
1458 | spu_release(ctx); | 1529 | spu_release(ctx); |
1459 | return ret; | 1530 | return ret; |
1460 | } | 1531 | } |
@@ -1499,12 +1570,18 @@ static u64 spufs_id_get(void *data) | |||
1499 | } | 1570 | } |
1500 | DEFINE_SIMPLE_ATTRIBUTE(spufs_id_ops, spufs_id_get, NULL, "0x%llx\n") | 1571 | DEFINE_SIMPLE_ATTRIBUTE(spufs_id_ops, spufs_id_get, NULL, "0x%llx\n") |
1501 | 1572 | ||
1502 | static u64 spufs_object_id_get(void *data) | 1573 | static u64 __spufs_object_id_get(void *data) |
1503 | { | 1574 | { |
1504 | struct spu_context *ctx = data; | 1575 | struct spu_context *ctx = data; |
1505 | return ctx->object_id; | 1576 | return ctx->object_id; |
1506 | } | 1577 | } |
1507 | 1578 | ||
1579 | static u64 spufs_object_id_get(void *data) | ||
1580 | { | ||
1581 | /* FIXME: Should there really be no locking here? */ | ||
1582 | return __spufs_object_id_get(data); | ||
1583 | } | ||
1584 | |||
1508 | static void spufs_object_id_set(void *data, u64 id) | 1585 | static void spufs_object_id_set(void *data, u64 id) |
1509 | { | 1586 | { |
1510 | struct spu_context *ctx = data; | 1587 | struct spu_context *ctx = data; |
@@ -1514,13 +1591,19 @@ static void spufs_object_id_set(void *data, u64 id) | |||
1514 | DEFINE_SIMPLE_ATTRIBUTE(spufs_object_id_ops, spufs_object_id_get, | 1591 | DEFINE_SIMPLE_ATTRIBUTE(spufs_object_id_ops, spufs_object_id_get, |
1515 | spufs_object_id_set, "0x%llx\n"); | 1592 | spufs_object_id_set, "0x%llx\n"); |
1516 | 1593 | ||
1594 | static u64 __spufs_lslr_get(void *data) | ||
1595 | { | ||
1596 | struct spu_context *ctx = data; | ||
1597 | return ctx->csa.priv2.spu_lslr_RW; | ||
1598 | } | ||
1599 | |||
1517 | static u64 spufs_lslr_get(void *data) | 1600 | static u64 spufs_lslr_get(void *data) |
1518 | { | 1601 | { |
1519 | struct spu_context *ctx = data; | 1602 | struct spu_context *ctx = data; |
1520 | u64 ret; | 1603 | u64 ret; |
1521 | 1604 | ||
1522 | spu_acquire_saved(ctx); | 1605 | spu_acquire_saved(ctx); |
1523 | ret = ctx->csa.priv2.spu_lslr_RW; | 1606 | ret = __spufs_lslr_get(data); |
1524 | spu_release(ctx); | 1607 | spu_release(ctx); |
1525 | 1608 | ||
1526 | return ret; | 1609 | return ret; |
@@ -1535,26 +1618,36 @@ static int spufs_info_open(struct inode *inode, struct file *file) | |||
1535 | return 0; | 1618 | return 0; |
1536 | } | 1619 | } |
1537 | 1620 | ||
1621 | static ssize_t __spufs_mbox_info_read(struct spu_context *ctx, | ||
1622 | char __user *buf, size_t len, loff_t *pos) | ||
1623 | { | ||
1624 | u32 mbox_stat; | ||
1625 | u32 data; | ||
1626 | |||
1627 | mbox_stat = ctx->csa.prob.mb_stat_R; | ||
1628 | if (mbox_stat & 0x0000ff) { | ||
1629 | data = ctx->csa.prob.pu_mb_R; | ||
1630 | } | ||
1631 | |||
1632 | return simple_read_from_buffer(buf, len, pos, &data, sizeof data); | ||
1633 | } | ||
1634 | |||
1538 | static ssize_t spufs_mbox_info_read(struct file *file, char __user *buf, | 1635 | static ssize_t spufs_mbox_info_read(struct file *file, char __user *buf, |
1539 | size_t len, loff_t *pos) | 1636 | size_t len, loff_t *pos) |
1540 | { | 1637 | { |
1638 | int ret; | ||
1541 | struct spu_context *ctx = file->private_data; | 1639 | struct spu_context *ctx = file->private_data; |
1542 | u32 mbox_stat; | ||
1543 | u32 data; | ||
1544 | 1640 | ||
1545 | if (!access_ok(VERIFY_WRITE, buf, len)) | 1641 | if (!access_ok(VERIFY_WRITE, buf, len)) |
1546 | return -EFAULT; | 1642 | return -EFAULT; |
1547 | 1643 | ||
1548 | spu_acquire_saved(ctx); | 1644 | spu_acquire_saved(ctx); |
1549 | spin_lock(&ctx->csa.register_lock); | 1645 | spin_lock(&ctx->csa.register_lock); |
1550 | mbox_stat = ctx->csa.prob.mb_stat_R; | 1646 | ret = __spufs_mbox_info_read(ctx, buf, len, pos); |
1551 | if (mbox_stat & 0x0000ff) { | ||
1552 | data = ctx->csa.prob.pu_mb_R; | ||
1553 | } | ||
1554 | spin_unlock(&ctx->csa.register_lock); | 1647 | spin_unlock(&ctx->csa.register_lock); |
1555 | spu_release(ctx); | 1648 | spu_release(ctx); |
1556 | 1649 | ||
1557 | return simple_read_from_buffer(buf, len, pos, &data, sizeof data); | 1650 | return ret; |
1558 | } | 1651 | } |
1559 | 1652 | ||
1560 | static struct file_operations spufs_mbox_info_fops = { | 1653 | static struct file_operations spufs_mbox_info_fops = { |
@@ -1563,26 +1656,36 @@ static struct file_operations spufs_mbox_info_fops = { | |||
1563 | .llseek = generic_file_llseek, | 1656 | .llseek = generic_file_llseek, |
1564 | }; | 1657 | }; |
1565 | 1658 | ||
1659 | static ssize_t __spufs_ibox_info_read(struct spu_context *ctx, | ||
1660 | char __user *buf, size_t len, loff_t *pos) | ||
1661 | { | ||
1662 | u32 ibox_stat; | ||
1663 | u32 data; | ||
1664 | |||
1665 | ibox_stat = ctx->csa.prob.mb_stat_R; | ||
1666 | if (ibox_stat & 0xff0000) { | ||
1667 | data = ctx->csa.priv2.puint_mb_R; | ||
1668 | } | ||
1669 | |||
1670 | return simple_read_from_buffer(buf, len, pos, &data, sizeof data); | ||
1671 | } | ||
1672 | |||
1566 | static ssize_t spufs_ibox_info_read(struct file *file, char __user *buf, | 1673 | static ssize_t spufs_ibox_info_read(struct file *file, char __user *buf, |
1567 | size_t len, loff_t *pos) | 1674 | size_t len, loff_t *pos) |
1568 | { | 1675 | { |
1569 | struct spu_context *ctx = file->private_data; | 1676 | struct spu_context *ctx = file->private_data; |
1570 | u32 ibox_stat; | 1677 | int ret; |
1571 | u32 data; | ||
1572 | 1678 | ||
1573 | if (!access_ok(VERIFY_WRITE, buf, len)) | 1679 | if (!access_ok(VERIFY_WRITE, buf, len)) |
1574 | return -EFAULT; | 1680 | return -EFAULT; |
1575 | 1681 | ||
1576 | spu_acquire_saved(ctx); | 1682 | spu_acquire_saved(ctx); |
1577 | spin_lock(&ctx->csa.register_lock); | 1683 | spin_lock(&ctx->csa.register_lock); |
1578 | ibox_stat = ctx->csa.prob.mb_stat_R; | 1684 | ret = __spufs_ibox_info_read(ctx, buf, len, pos); |
1579 | if (ibox_stat & 0xff0000) { | ||
1580 | data = ctx->csa.priv2.puint_mb_R; | ||
1581 | } | ||
1582 | spin_unlock(&ctx->csa.register_lock); | 1685 | spin_unlock(&ctx->csa.register_lock); |
1583 | spu_release(ctx); | 1686 | spu_release(ctx); |
1584 | 1687 | ||
1585 | return simple_read_from_buffer(buf, len, pos, &data, sizeof data); | 1688 | return ret; |
1586 | } | 1689 | } |
1587 | 1690 | ||
1588 | static struct file_operations spufs_ibox_info_fops = { | 1691 | static struct file_operations spufs_ibox_info_fops = { |
@@ -1591,29 +1694,39 @@ static struct file_operations spufs_ibox_info_fops = { | |||
1591 | .llseek = generic_file_llseek, | 1694 | .llseek = generic_file_llseek, |
1592 | }; | 1695 | }; |
1593 | 1696 | ||
1594 | static ssize_t spufs_wbox_info_read(struct file *file, char __user *buf, | 1697 | static ssize_t __spufs_wbox_info_read(struct spu_context *ctx, |
1595 | size_t len, loff_t *pos) | 1698 | char __user *buf, size_t len, loff_t *pos) |
1596 | { | 1699 | { |
1597 | struct spu_context *ctx = file->private_data; | ||
1598 | int i, cnt; | 1700 | int i, cnt; |
1599 | u32 data[4]; | 1701 | u32 data[4]; |
1600 | u32 wbox_stat; | 1702 | u32 wbox_stat; |
1601 | 1703 | ||
1704 | wbox_stat = ctx->csa.prob.mb_stat_R; | ||
1705 | cnt = 4 - ((wbox_stat & 0x00ff00) >> 8); | ||
1706 | for (i = 0; i < cnt; i++) { | ||
1707 | data[i] = ctx->csa.spu_mailbox_data[i]; | ||
1708 | } | ||
1709 | |||
1710 | return simple_read_from_buffer(buf, len, pos, &data, | ||
1711 | cnt * sizeof(u32)); | ||
1712 | } | ||
1713 | |||
1714 | static ssize_t spufs_wbox_info_read(struct file *file, char __user *buf, | ||
1715 | size_t len, loff_t *pos) | ||
1716 | { | ||
1717 | struct spu_context *ctx = file->private_data; | ||
1718 | int ret; | ||
1719 | |||
1602 | if (!access_ok(VERIFY_WRITE, buf, len)) | 1720 | if (!access_ok(VERIFY_WRITE, buf, len)) |
1603 | return -EFAULT; | 1721 | return -EFAULT; |
1604 | 1722 | ||
1605 | spu_acquire_saved(ctx); | 1723 | spu_acquire_saved(ctx); |
1606 | spin_lock(&ctx->csa.register_lock); | 1724 | spin_lock(&ctx->csa.register_lock); |
1607 | wbox_stat = ctx->csa.prob.mb_stat_R; | 1725 | ret = __spufs_wbox_info_read(ctx, buf, len, pos); |
1608 | cnt = (wbox_stat & 0x00ff00) >> 8; | ||
1609 | for (i = 0; i < cnt; i++) { | ||
1610 | data[i] = ctx->csa.spu_mailbox_data[i]; | ||
1611 | } | ||
1612 | spin_unlock(&ctx->csa.register_lock); | 1726 | spin_unlock(&ctx->csa.register_lock); |
1613 | spu_release(ctx); | 1727 | spu_release(ctx); |
1614 | 1728 | ||
1615 | return simple_read_from_buffer(buf, len, pos, &data, | 1729 | return ret; |
1616 | cnt * sizeof(u32)); | ||
1617 | } | 1730 | } |
1618 | 1731 | ||
1619 | static struct file_operations spufs_wbox_info_fops = { | 1732 | static struct file_operations spufs_wbox_info_fops = { |
@@ -1622,19 +1735,13 @@ static struct file_operations spufs_wbox_info_fops = { | |||
1622 | .llseek = generic_file_llseek, | 1735 | .llseek = generic_file_llseek, |
1623 | }; | 1736 | }; |
1624 | 1737 | ||
1625 | static ssize_t spufs_dma_info_read(struct file *file, char __user *buf, | 1738 | static ssize_t __spufs_dma_info_read(struct spu_context *ctx, |
1626 | size_t len, loff_t *pos) | 1739 | char __user *buf, size_t len, loff_t *pos) |
1627 | { | 1740 | { |
1628 | struct spu_context *ctx = file->private_data; | ||
1629 | struct spu_dma_info info; | 1741 | struct spu_dma_info info; |
1630 | struct mfc_cq_sr *qp, *spuqp; | 1742 | struct mfc_cq_sr *qp, *spuqp; |
1631 | int i; | 1743 | int i; |
1632 | 1744 | ||
1633 | if (!access_ok(VERIFY_WRITE, buf, len)) | ||
1634 | return -EFAULT; | ||
1635 | |||
1636 | spu_acquire_saved(ctx); | ||
1637 | spin_lock(&ctx->csa.register_lock); | ||
1638 | info.dma_info_type = ctx->csa.priv2.spu_tag_status_query_RW; | 1745 | info.dma_info_type = ctx->csa.priv2.spu_tag_status_query_RW; |
1639 | info.dma_info_mask = ctx->csa.lscsa->tag_mask.slot[0]; | 1746 | info.dma_info_mask = ctx->csa.lscsa->tag_mask.slot[0]; |
1640 | info.dma_info_status = ctx->csa.spu_chnldata_RW[24]; | 1747 | info.dma_info_status = ctx->csa.spu_chnldata_RW[24]; |
@@ -1649,25 +1756,40 @@ static ssize_t spufs_dma_info_read(struct file *file, char __user *buf, | |||
1649 | qp->mfc_cq_data2_RW = spuqp->mfc_cq_data2_RW; | 1756 | qp->mfc_cq_data2_RW = spuqp->mfc_cq_data2_RW; |
1650 | qp->mfc_cq_data3_RW = spuqp->mfc_cq_data3_RW; | 1757 | qp->mfc_cq_data3_RW = spuqp->mfc_cq_data3_RW; |
1651 | } | 1758 | } |
1652 | spin_unlock(&ctx->csa.register_lock); | ||
1653 | spu_release(ctx); | ||
1654 | 1759 | ||
1655 | return simple_read_from_buffer(buf, len, pos, &info, | 1760 | return simple_read_from_buffer(buf, len, pos, &info, |
1656 | sizeof info); | 1761 | sizeof info); |
1657 | } | 1762 | } |
1658 | 1763 | ||
1764 | static ssize_t spufs_dma_info_read(struct file *file, char __user *buf, | ||
1765 | size_t len, loff_t *pos) | ||
1766 | { | ||
1767 | struct spu_context *ctx = file->private_data; | ||
1768 | int ret; | ||
1769 | |||
1770 | if (!access_ok(VERIFY_WRITE, buf, len)) | ||
1771 | return -EFAULT; | ||
1772 | |||
1773 | spu_acquire_saved(ctx); | ||
1774 | spin_lock(&ctx->csa.register_lock); | ||
1775 | ret = __spufs_dma_info_read(ctx, buf, len, pos); | ||
1776 | spin_unlock(&ctx->csa.register_lock); | ||
1777 | spu_release(ctx); | ||
1778 | |||
1779 | return ret; | ||
1780 | } | ||
1781 | |||
1659 | static struct file_operations spufs_dma_info_fops = { | 1782 | static struct file_operations spufs_dma_info_fops = { |
1660 | .open = spufs_info_open, | 1783 | .open = spufs_info_open, |
1661 | .read = spufs_dma_info_read, | 1784 | .read = spufs_dma_info_read, |
1662 | }; | 1785 | }; |
1663 | 1786 | ||
1664 | static ssize_t spufs_proxydma_info_read(struct file *file, char __user *buf, | 1787 | static ssize_t __spufs_proxydma_info_read(struct spu_context *ctx, |
1665 | size_t len, loff_t *pos) | 1788 | char __user *buf, size_t len, loff_t *pos) |
1666 | { | 1789 | { |
1667 | struct spu_context *ctx = file->private_data; | ||
1668 | struct spu_proxydma_info info; | 1790 | struct spu_proxydma_info info; |
1669 | int ret = sizeof info; | ||
1670 | struct mfc_cq_sr *qp, *puqp; | 1791 | struct mfc_cq_sr *qp, *puqp; |
1792 | int ret = sizeof info; | ||
1671 | int i; | 1793 | int i; |
1672 | 1794 | ||
1673 | if (len < ret) | 1795 | if (len < ret) |
@@ -1676,8 +1798,6 @@ static ssize_t spufs_proxydma_info_read(struct file *file, char __user *buf, | |||
1676 | if (!access_ok(VERIFY_WRITE, buf, len)) | 1798 | if (!access_ok(VERIFY_WRITE, buf, len)) |
1677 | return -EFAULT; | 1799 | return -EFAULT; |
1678 | 1800 | ||
1679 | spu_acquire_saved(ctx); | ||
1680 | spin_lock(&ctx->csa.register_lock); | ||
1681 | info.proxydma_info_type = ctx->csa.prob.dma_querytype_RW; | 1801 | info.proxydma_info_type = ctx->csa.prob.dma_querytype_RW; |
1682 | info.proxydma_info_mask = ctx->csa.prob.dma_querymask_RW; | 1802 | info.proxydma_info_mask = ctx->csa.prob.dma_querymask_RW; |
1683 | info.proxydma_info_status = ctx->csa.prob.dma_tagstatus_R; | 1803 | info.proxydma_info_status = ctx->csa.prob.dma_tagstatus_R; |
@@ -1690,12 +1810,23 @@ static ssize_t spufs_proxydma_info_read(struct file *file, char __user *buf, | |||
1690 | qp->mfc_cq_data2_RW = puqp->mfc_cq_data2_RW; | 1810 | qp->mfc_cq_data2_RW = puqp->mfc_cq_data2_RW; |
1691 | qp->mfc_cq_data3_RW = puqp->mfc_cq_data3_RW; | 1811 | qp->mfc_cq_data3_RW = puqp->mfc_cq_data3_RW; |
1692 | } | 1812 | } |
1813 | |||
1814 | return simple_read_from_buffer(buf, len, pos, &info, | ||
1815 | sizeof info); | ||
1816 | } | ||
1817 | |||
1818 | static ssize_t spufs_proxydma_info_read(struct file *file, char __user *buf, | ||
1819 | size_t len, loff_t *pos) | ||
1820 | { | ||
1821 | struct spu_context *ctx = file->private_data; | ||
1822 | int ret; | ||
1823 | |||
1824 | spu_acquire_saved(ctx); | ||
1825 | spin_lock(&ctx->csa.register_lock); | ||
1826 | ret = __spufs_proxydma_info_read(ctx, buf, len, pos); | ||
1693 | spin_unlock(&ctx->csa.register_lock); | 1827 | spin_unlock(&ctx->csa.register_lock); |
1694 | spu_release(ctx); | 1828 | spu_release(ctx); |
1695 | 1829 | ||
1696 | if (copy_to_user(buf, &info, sizeof info)) | ||
1697 | ret = -EFAULT; | ||
1698 | |||
1699 | return ret; | 1830 | return ret; |
1700 | } | 1831 | } |
1701 | 1832 | ||
@@ -1760,3 +1891,27 @@ struct tree_descr spufs_dir_nosched_contents[] = { | |||
1760 | { "object-id", &spufs_object_id_ops, 0666, }, | 1891 | { "object-id", &spufs_object_id_ops, 0666, }, |
1761 | {}, | 1892 | {}, |
1762 | }; | 1893 | }; |
1894 | |||
1895 | struct spufs_coredump_reader spufs_coredump_read[] = { | ||
1896 | { "regs", __spufs_regs_read, NULL, 128 * 16 }, | ||
1897 | { "fpcr", __spufs_fpcr_read, NULL, 16 }, | ||
1898 | { "lslr", NULL, __spufs_lslr_get, 11 }, | ||
1899 | { "decr", NULL, __spufs_decr_get, 11 }, | ||
1900 | { "decr_status", NULL, __spufs_decr_status_get, 11 }, | ||
1901 | { "mem", __spufs_mem_read, NULL, 256 * 1024, }, | ||
1902 | { "signal1", __spufs_signal1_read, NULL, 4 }, | ||
1903 | { "signal1_type", NULL, __spufs_signal1_type_get, 2 }, | ||
1904 | { "signal2", __spufs_signal2_read, NULL, 4 }, | ||
1905 | { "signal2_type", NULL, __spufs_signal2_type_get, 2 }, | ||
1906 | { "event_mask", NULL, __spufs_event_mask_get, 8 }, | ||
1907 | { "event_status", NULL, __spufs_event_status_get, 8 }, | ||
1908 | { "mbox_info", __spufs_mbox_info_read, NULL, 4 }, | ||
1909 | { "ibox_info", __spufs_ibox_info_read, NULL, 4 }, | ||
1910 | { "wbox_info", __spufs_wbox_info_read, NULL, 16 }, | ||
1911 | { "dma_info", __spufs_dma_info_read, NULL, 69 * 8 }, | ||
1912 | { "proxydma_info", __spufs_proxydma_info_read, NULL, 35 * 8 }, | ||
1913 | { "object-id", NULL, __spufs_object_id_get, 19 }, | ||
1914 | { }, | ||
1915 | }; | ||
1916 | int spufs_coredump_num_notes = ARRAY_SIZE(spufs_coredump_read) - 1; | ||
1917 | |||
diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c index d5f0a21a19d8..a3ca06bd0ca1 100644 --- a/arch/powerpc/platforms/cell/spufs/inode.c +++ b/arch/powerpc/platforms/cell/spufs/inode.c | |||
@@ -232,6 +232,7 @@ struct file_operations spufs_context_fops = { | |||
232 | .readdir = dcache_readdir, | 232 | .readdir = dcache_readdir, |
233 | .fsync = simple_sync_file, | 233 | .fsync = simple_sync_file, |
234 | }; | 234 | }; |
235 | EXPORT_SYMBOL_GPL(spufs_context_fops); | ||
235 | 236 | ||
236 | static int | 237 | static int |
237 | spufs_mkdir(struct inode *dir, struct dentry *dentry, unsigned int flags, | 238 | spufs_mkdir(struct inode *dir, struct dentry *dentry, unsigned int flags, |
@@ -647,6 +648,7 @@ static struct file_system_type spufs_type = { | |||
647 | static int __init spufs_init(void) | 648 | static int __init spufs_init(void) |
648 | { | 649 | { |
649 | int ret; | 650 | int ret; |
651 | |||
650 | ret = -ENOMEM; | 652 | ret = -ENOMEM; |
651 | spufs_inode_cache = kmem_cache_create("spufs_inode_cache", | 653 | spufs_inode_cache = kmem_cache_create("spufs_inode_cache", |
652 | sizeof(struct spufs_inode_info), 0, | 654 | sizeof(struct spufs_inode_info), 0, |
@@ -664,8 +666,12 @@ static int __init spufs_init(void) | |||
664 | ret = register_spu_syscalls(&spufs_calls); | 666 | ret = register_spu_syscalls(&spufs_calls); |
665 | if (ret) | 667 | if (ret) |
666 | goto out_fs; | 668 | goto out_fs; |
669 | ret = register_arch_coredump_calls(&spufs_coredump_calls); | ||
670 | if (ret) | ||
671 | goto out_fs; | ||
667 | 672 | ||
668 | spufs_init_isolated_loader(); | 673 | spufs_init_isolated_loader(); |
674 | |||
669 | return 0; | 675 | return 0; |
670 | out_fs: | 676 | out_fs: |
671 | unregister_filesystem(&spufs_type); | 677 | unregister_filesystem(&spufs_type); |
@@ -679,6 +685,7 @@ module_init(spufs_init); | |||
679 | static void __exit spufs_exit(void) | 685 | static void __exit spufs_exit(void) |
680 | { | 686 | { |
681 | spu_sched_exit(); | 687 | spu_sched_exit(); |
688 | unregister_arch_coredump_calls(&spufs_coredump_calls); | ||
682 | unregister_spu_syscalls(&spufs_calls); | 689 | unregister_spu_syscalls(&spufs_calls); |
683 | unregister_filesystem(&spufs_type); | 690 | unregister_filesystem(&spufs_type); |
684 | kmem_cache_destroy(spufs_inode_cache); | 691 | kmem_cache_destroy(spufs_inode_cache); |
diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h index 23d20f380560..70fb13395c04 100644 --- a/arch/powerpc/platforms/cell/spufs/spufs.h +++ b/arch/powerpc/platforms/cell/spufs/spufs.h | |||
@@ -223,4 +223,15 @@ void spufs_stop_callback(struct spu *spu); | |||
223 | void spufs_mfc_callback(struct spu *spu); | 223 | void spufs_mfc_callback(struct spu *spu); |
224 | void spufs_dma_callback(struct spu *spu, int type); | 224 | void spufs_dma_callback(struct spu *spu, int type); |
225 | 225 | ||
226 | extern struct spu_coredump_calls spufs_coredump_calls; | ||
227 | struct spufs_coredump_reader { | ||
228 | char *name; | ||
229 | ssize_t (*read)(struct spu_context *ctx, | ||
230 | char __user *buffer, size_t size, loff_t *pos); | ||
231 | u64 (*get)(void *data); | ||
232 | size_t size; | ||
233 | }; | ||
234 | extern struct spufs_coredump_reader spufs_coredump_read[]; | ||
235 | extern int spufs_coredump_num_notes; | ||
236 | |||
226 | #endif | 237 | #endif |
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 79b05a1a4365..cc72bb43061d 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c | |||
@@ -1582,6 +1582,10 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file) | |||
1582 | 1582 | ||
1583 | sz += thread_status_size; | 1583 | sz += thread_status_size; |
1584 | 1584 | ||
1585 | #ifdef ELF_CORE_WRITE_EXTRA_NOTES | ||
1586 | sz += ELF_CORE_EXTRA_NOTES_SIZE; | ||
1587 | #endif | ||
1588 | |||
1585 | fill_elf_note_phdr(&phdr, sz, offset); | 1589 | fill_elf_note_phdr(&phdr, sz, offset); |
1586 | offset += sz; | 1590 | offset += sz; |
1587 | DUMP_WRITE(&phdr, sizeof(phdr)); | 1591 | DUMP_WRITE(&phdr, sizeof(phdr)); |
@@ -1622,6 +1626,10 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file) | |||
1622 | if (!writenote(notes + i, file, &foffset)) | 1626 | if (!writenote(notes + i, file, &foffset)) |
1623 | goto end_coredump; | 1627 | goto end_coredump; |
1624 | 1628 | ||
1629 | #ifdef ELF_CORE_WRITE_EXTRA_NOTES | ||
1630 | ELF_CORE_WRITE_EXTRA_NOTES; | ||
1631 | #endif | ||
1632 | |||
1625 | /* write out the thread status notes section */ | 1633 | /* write out the thread status notes section */ |
1626 | list_for_each(t, &thread_list) { | 1634 | list_for_each(t, &thread_list) { |
1627 | struct elf_thread_status *tmp = | 1635 | struct elf_thread_status *tmp = |
diff --git a/include/asm-powerpc/elf.h b/include/asm-powerpc/elf.h index 9a83a987d396..4545aa682509 100644 --- a/include/asm-powerpc/elf.h +++ b/include/asm-powerpc/elf.h | |||
@@ -411,4 +411,17 @@ do { \ | |||
411 | /* Keep this the last entry. */ | 411 | /* Keep this the last entry. */ |
412 | #define R_PPC64_NUM 107 | 412 | #define R_PPC64_NUM 107 |
413 | 413 | ||
414 | #ifdef CONFIG_PPC_CELL | ||
415 | /* Notes used in ET_CORE. Note name is "SPU/<fd>/<filename>". */ | ||
416 | #define NT_SPU 1 | ||
417 | |||
418 | extern int arch_notes_size(void); | ||
419 | extern void arch_write_notes(struct file *file); | ||
420 | |||
421 | #define ELF_CORE_EXTRA_NOTES_SIZE arch_notes_size() | ||
422 | #define ELF_CORE_WRITE_EXTRA_NOTES arch_write_notes(file) | ||
423 | |||
424 | #define ARCH_HAVE_EXTRA_ELF_NOTES | ||
425 | #endif /* CONFIG_PPC_CELL */ | ||
426 | |||
414 | #endif /* _ASM_POWERPC_ELF_H */ | 427 | #endif /* _ASM_POWERPC_ELF_H */ |
diff --git a/include/asm-powerpc/spu.h b/include/asm-powerpc/spu.h index ffa4df083609..f968f8697538 100644 --- a/include/asm-powerpc/spu.h +++ b/include/asm-powerpc/spu.h | |||
@@ -172,6 +172,13 @@ extern struct spufs_calls { | |||
172 | struct module *owner; | 172 | struct module *owner; |
173 | } spufs_calls; | 173 | } spufs_calls; |
174 | 174 | ||
175 | /* coredump calls implemented in spufs */ | ||
176 | struct spu_coredump_calls { | ||
177 | asmlinkage int (*arch_notes_size)(void); | ||
178 | asmlinkage void (*arch_write_notes)(struct file *file); | ||
179 | struct module *owner; | ||
180 | }; | ||
181 | |||
175 | /* return status from spu_run, same as in libspe */ | 182 | /* return status from spu_run, same as in libspe */ |
176 | #define SPE_EVENT_DMA_ALIGNMENT 0x0008 /*A DMA alignment error */ | 183 | #define SPE_EVENT_DMA_ALIGNMENT 0x0008 /*A DMA alignment error */ |
177 | #define SPE_EVENT_SPE_ERROR 0x0010 /*An illegal instruction error*/ | 184 | #define SPE_EVENT_SPE_ERROR 0x0010 /*An illegal instruction error*/ |
@@ -203,6 +210,9 @@ static inline void unregister_spu_syscalls(struct spufs_calls *calls) | |||
203 | } | 210 | } |
204 | #endif /* MODULE */ | 211 | #endif /* MODULE */ |
205 | 212 | ||
213 | int register_arch_coredump_calls(struct spu_coredump_calls *calls); | ||
214 | void unregister_arch_coredump_calls(struct spu_coredump_calls *calls); | ||
215 | |||
206 | int spu_add_sysdev_attr(struct sysdev_attribute *attr); | 216 | int spu_add_sysdev_attr(struct sysdev_attribute *attr); |
207 | void spu_remove_sysdev_attr(struct sysdev_attribute *attr); | 217 | void spu_remove_sysdev_attr(struct sysdev_attribute *attr); |
208 | 218 | ||
diff --git a/include/linux/elf.h b/include/linux/elf.h index b70d1d2c8d28..743d5c8e6d36 100644 --- a/include/linux/elf.h +++ b/include/linux/elf.h | |||
@@ -368,5 +368,12 @@ extern Elf64_Dyn _DYNAMIC []; | |||
368 | 368 | ||
369 | #endif | 369 | #endif |
370 | 370 | ||
371 | #ifndef ARCH_HAVE_EXTRA_ELF_NOTES | ||
372 | static inline int arch_notes_size(void) { return 0; } | ||
373 | static inline void arch_write_notes(struct file *file) { } | ||
374 | |||
375 | #define ELF_CORE_EXTRA_NOTES_SIZE arch_notes_size() | ||
376 | #define ELF_CORE_WRITE_EXTRA_NOTES arch_write_notes(file) | ||
377 | #endif /* ARCH_HAVE_EXTRA_ELF_NOTES */ | ||
371 | 378 | ||
372 | #endif /* _LINUX_ELF_H */ | 379 | #endif /* _LINUX_ELF_H */ |