llseek: automatically add .llseek fop
[linux-2.6-block.git] / arch / mips / kernel / vpe.c
CommitLineData
e01402b1
RB
1/*
2 * Copyright (C) 2004, 2005 MIPS Technologies, Inc. All rights reserved.
3 *
4 * This program is free software; you can distribute it and/or modify it
5 * under the terms of the GNU General Public License (Version 2) as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
11 * for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
e01402b1
RB
16 */
17
18/*
19 * VPE support module
20 *
21 * Provides support for loading a MIPS SP program on VPE1.
22 * The SP enviroment is rather simple, no tlb's. It needs to be relocatable
23 * (or partially linked). You should initialise your stack in the startup
24 * code. This loader looks for the symbol __start and sets up
25 * execution to resume from there. The MIPS SDE kit contains suitable examples.
26 *
27 * To load and run, simply cat a SP 'program file' to /dev/vpe1.
28 * i.e cat spapp >/dev/vpe1.
e01402b1 29 */
e01402b1 30#include <linux/kernel.h>
27a3bbaf 31#include <linux/device.h>
e01402b1
RB
32#include <linux/module.h>
33#include <linux/fs.h>
34#include <linux/init.h>
35#include <asm/uaccess.h>
36#include <linux/slab.h>
37#include <linux/list.h>
38#include <linux/vmalloc.h>
39#include <linux/elf.h>
40#include <linux/seq_file.h>
41#include <linux/syscalls.h>
42#include <linux/moduleloader.h>
43#include <linux/interrupt.h>
44#include <linux/poll.h>
45#include <linux/bootmem.h>
46#include <asm/mipsregs.h>
340ee4b9 47#include <asm/mipsmtregs.h>
e01402b1
RB
48#include <asm/cacheflush.h>
49#include <asm/atomic.h>
50#include <asm/cpu.h>
27a3bbaf 51#include <asm/mips_mt.h>
e01402b1
RB
52#include <asm/processor.h>
53#include <asm/system.h>
2600990e
RB
54#include <asm/vpe.h>
55#include <asm/kspd.h>
e01402b1
RB
56
57typedef void *vpe_handle;
58
e01402b1
RB
59#ifndef ARCH_SHF_SMALL
60#define ARCH_SHF_SMALL 0
61#endif
62
63/* If this is set, the section belongs in the init part of the module */
64#define INIT_OFFSET_MASK (1UL << (BITS_PER_LONG-1))
65
41790e04
RB
66/*
67 * The number of TCs and VPEs physically available on the core
68 */
69static int hw_tcs, hw_vpes;
e01402b1 70static char module_name[] = "vpe";
307bd284 71static int major;
27a3bbaf 72static const int minor = 1; /* fixed for now */
e01402b1 73
2600990e 74#ifdef CONFIG_MIPS_APSP_KSPD
349c4229 75static struct kspd_notifications kspd_events;
982f6ffe 76static int kspd_events_reqd;
2600990e
RB
77#endif
78
e01402b1
RB
79/* grab the likely amount of memory we will need. */
80#ifdef CONFIG_MIPS_VPE_LOADER_TOM
81#define P_SIZE (2 * 1024 * 1024)
82#else
83/* add an overhead to the max kmalloc size for non-striped symbols/etc */
84#define P_SIZE (256 * 1024)
85#endif
86
2600990e
RB
87extern unsigned long physical_memsize;
88
e01402b1 89#define MAX_VPES 16
2600990e 90#define VPE_PATH_MAX 256
e01402b1
RB
91
92enum vpe_state {
93 VPE_STATE_UNUSED = 0,
94 VPE_STATE_INUSE,
95 VPE_STATE_RUNNING
96};
97
98enum tc_state {
99 TC_STATE_UNUSED = 0,
100 TC_STATE_INUSE,
101 TC_STATE_RUNNING,
102 TC_STATE_DYNAMIC
103};
104
307bd284 105struct vpe {
e01402b1
RB
106 enum vpe_state state;
107
108 /* (device) minor associated with this vpe */
109 int minor;
110
111 /* elfloader stuff */
112 void *load_addr;
571e0bed 113 unsigned long len;
e01402b1 114 char *pbuffer;
571e0bed 115 unsigned long plen;
2600990e
RB
116 unsigned int uid, gid;
117 char cwd[VPE_PATH_MAX];
e01402b1
RB
118
119 unsigned long __start;
120
121 /* tc's associated with this vpe */
122 struct list_head tc;
123
124 /* The list of vpe's */
125 struct list_head list;
126
127 /* shared symbol address */
128 void *shared_ptr;
2600990e
RB
129
130 /* the list of who wants to know when something major happens */
131 struct list_head notify;
41790e04
RB
132
133 unsigned int ntcs;
307bd284
RB
134};
135
136struct tc {
137 enum tc_state state;
138 int index;
139
07cc0c9e
RB
140 struct vpe *pvpe; /* parent VPE */
141 struct list_head tc; /* The list of TC's with this VPE */
142 struct list_head list; /* The global list of tc's */
307bd284 143};
e01402b1 144
9cfdf6f1 145struct {
1bbfc20d
RB
146 spinlock_t vpe_list_lock;
147 struct list_head vpe_list; /* Virtual processing elements */
148 spinlock_t tc_list_lock;
149 struct list_head tc_list; /* Thread contexts */
9cfdf6f1 150} vpecontrol = {
1bbfc20d
RB
151 .vpe_list_lock = SPIN_LOCK_UNLOCKED,
152 .vpe_list = LIST_HEAD_INIT(vpecontrol.vpe_list),
153 .tc_list_lock = SPIN_LOCK_UNLOCKED,
154 .tc_list = LIST_HEAD_INIT(vpecontrol.tc_list)
9cfdf6f1 155};
e01402b1
RB
156
157static void release_progmem(void *ptr);
e01402b1
RB
158
159/* get the vpe associated with this minor */
f18b51cc 160static struct vpe *get_vpe(int minor)
e01402b1 161{
1bbfc20d 162 struct vpe *res, *v;
e01402b1 163
2600990e
RB
164 if (!cpu_has_mipsmt)
165 return NULL;
166
1bbfc20d
RB
167 res = NULL;
168 spin_lock(&vpecontrol.vpe_list_lock);
e01402b1 169 list_for_each_entry(v, &vpecontrol.vpe_list, list) {
1bbfc20d
RB
170 if (v->minor == minor) {
171 res = v;
172 break;
173 }
e01402b1 174 }
1bbfc20d 175 spin_unlock(&vpecontrol.vpe_list_lock);
e01402b1 176
1bbfc20d 177 return res;
e01402b1
RB
178}
179
180/* get the vpe associated with this minor */
f18b51cc 181static struct tc *get_tc(int index)
e01402b1 182{
1bbfc20d 183 struct tc *res, *t;
e01402b1 184
1bbfc20d
RB
185 res = NULL;
186 spin_lock(&vpecontrol.tc_list_lock);
e01402b1 187 list_for_each_entry(t, &vpecontrol.tc_list, list) {
1bbfc20d
RB
188 if (t->index == index) {
189 res = t;
190 break;
191 }
e01402b1 192 }
1bbfc20d 193 spin_unlock(&vpecontrol.tc_list_lock);
e01402b1 194
e01402b1
RB
195 return NULL;
196}
197
e01402b1 198/* allocate a vpe and associate it with this minor (or index) */
f18b51cc 199static struct vpe *alloc_vpe(int minor)
e01402b1
RB
200{
201 struct vpe *v;
202
1bbfc20d 203 if ((v = kzalloc(sizeof(struct vpe), GFP_KERNEL)) == NULL)
e01402b1 204 return NULL;
e01402b1 205
e01402b1 206 INIT_LIST_HEAD(&v->tc);
1bbfc20d 207 spin_lock(&vpecontrol.vpe_list_lock);
e01402b1 208 list_add_tail(&v->list, &vpecontrol.vpe_list);
1bbfc20d 209 spin_unlock(&vpecontrol.vpe_list_lock);
e01402b1 210
2600990e 211 INIT_LIST_HEAD(&v->notify);
e01402b1 212 v->minor = minor;
1bbfc20d 213
e01402b1
RB
214 return v;
215}
216
217/* allocate a tc. At startup only tc0 is running, all other can be halted. */
f18b51cc 218static struct tc *alloc_tc(int index)
e01402b1 219{
07cc0c9e 220 struct tc *tc;
e01402b1 221
07cc0c9e
RB
222 if ((tc = kzalloc(sizeof(struct tc), GFP_KERNEL)) == NULL)
223 goto out;
e01402b1 224
07cc0c9e
RB
225 INIT_LIST_HEAD(&tc->tc);
226 tc->index = index;
1bbfc20d
RB
227
228 spin_lock(&vpecontrol.tc_list_lock);
07cc0c9e 229 list_add_tail(&tc->list, &vpecontrol.tc_list);
1bbfc20d 230 spin_unlock(&vpecontrol.tc_list_lock);
e01402b1 231
07cc0c9e
RB
232out:
233 return tc;
e01402b1
RB
234}
235
236/* clean up and free everything */
f18b51cc 237static void release_vpe(struct vpe *v)
e01402b1
RB
238{
239 list_del(&v->list);
240 if (v->load_addr)
241 release_progmem(v);
242 kfree(v);
243}
244
1bbfc20d 245static void __maybe_unused dump_mtregs(void)
e01402b1
RB
246{
247 unsigned long val;
248
249 val = read_c0_config3();
250 printk("config3 0x%lx MT %ld\n", val,
251 (val & CONFIG3_MT) >> CONFIG3_MT_SHIFT);
252
e01402b1
RB
253 val = read_c0_mvpcontrol();
254 printk("MVPControl 0x%lx, STLB %ld VPC %ld EVP %ld\n", val,
255 (val & MVPCONTROL_STLB) >> MVPCONTROL_STLB_SHIFT,
256 (val & MVPCONTROL_VPC) >> MVPCONTROL_VPC_SHIFT,
257 (val & MVPCONTROL_EVP));
258
2600990e
RB
259 val = read_c0_mvpconf0();
260 printk("mvpconf0 0x%lx, PVPE %ld PTC %ld M %ld\n", val,
261 (val & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT,
262 val & MVPCONF0_PTC, (val & MVPCONF0_M) >> MVPCONF0_M_SHIFT);
e01402b1
RB
263}
264
265/* Find some VPE program space */
571e0bed 266static void *alloc_progmem(unsigned long len)
e01402b1 267{
5408c490
RB
268 void *addr;
269
e01402b1 270#ifdef CONFIG_MIPS_VPE_LOADER_TOM
5408c490
RB
271 /*
272 * This means you must tell Linux to use less memory than you
273 * physically have, for example by passing a mem= boot argument.
274 */
9f2546ad 275 addr = pfn_to_kaddr(max_low_pfn);
5408c490 276 memset(addr, 0, len);
e01402b1 277#else
5408c490
RB
278 /* simple grab some mem for now */
279 addr = kzalloc(len, GFP_KERNEL);
e01402b1 280#endif
5408c490
RB
281
282 return addr;
e01402b1
RB
283}
284
285static void release_progmem(void *ptr)
286{
287#ifndef CONFIG_MIPS_VPE_LOADER_TOM
288 kfree(ptr);
289#endif
290}
291
292/* Update size with this section: return offset. */
293static long get_offset(unsigned long *size, Elf_Shdr * sechdr)
294{
295 long ret;
296
297 ret = ALIGN(*size, sechdr->sh_addralign ? : 1);
298 *size = ret + sechdr->sh_size;
299 return ret;
300}
301
302/* Lay out the SHF_ALLOC sections in a way not dissimilar to how ld
303 might -- code, read-only data, read-write data, small data. Tally
304 sizes, and place the offsets into sh_entsize fields: high bit means it
305 belongs in init. */
306static void layout_sections(struct module *mod, const Elf_Ehdr * hdr,
307 Elf_Shdr * sechdrs, const char *secstrings)
308{
309 static unsigned long const masks[][2] = {
310 /* NOTE: all executable code must be the first section
311 * in this array; otherwise modify the text_size
312 * finder in the two loops below */
313 {SHF_EXECINSTR | SHF_ALLOC, ARCH_SHF_SMALL},
314 {SHF_ALLOC, SHF_WRITE | ARCH_SHF_SMALL},
315 {SHF_WRITE | SHF_ALLOC, ARCH_SHF_SMALL},
316 {ARCH_SHF_SMALL | SHF_ALLOC, 0}
317 };
318 unsigned int m, i;
319
320 for (i = 0; i < hdr->e_shnum; i++)
321 sechdrs[i].sh_entsize = ~0UL;
322
323 for (m = 0; m < ARRAY_SIZE(masks); ++m) {
324 for (i = 0; i < hdr->e_shnum; ++i) {
325 Elf_Shdr *s = &sechdrs[i];
326
327 // || strncmp(secstrings + s->sh_name, ".init", 5) == 0)
328 if ((s->sh_flags & masks[m][0]) != masks[m][0]
329 || (s->sh_flags & masks[m][1])
330 || s->sh_entsize != ~0UL)
331 continue;
e2a9cf96
RG
332 s->sh_entsize =
333 get_offset((unsigned long *)&mod->core_size, s);
e01402b1
RB
334 }
335
336 if (m == 0)
337 mod->core_text_size = mod->core_size;
338
339 }
340}
341
342
343/* from module-elf32.c, but subverted a little */
344
345struct mips_hi16 {
346 struct mips_hi16 *next;
347 Elf32_Addr *addr;
348 Elf32_Addr value;
349};
350
351static struct mips_hi16 *mips_hi16_list;
352static unsigned int gp_offs, gp_addr;
353
354static int apply_r_mips_none(struct module *me, uint32_t *location,
355 Elf32_Addr v)
356{
357 return 0;
358}
359
360static int apply_r_mips_gprel16(struct module *me, uint32_t *location,
361 Elf32_Addr v)
362{
363 int rel;
364
365 if( !(*location & 0xffff) ) {
366 rel = (int)v - gp_addr;
367 }
368 else {
369 /* .sbss + gp(relative) + offset */
370 /* kludge! */
371 rel = (int)(short)((int)v + gp_offs +
372 (int)(short)(*location & 0xffff) - gp_addr);
373 }
374
375 if( (rel > 32768) || (rel < -32768) ) {
2600990e
RB
376 printk(KERN_DEBUG "VPE loader: apply_r_mips_gprel16: "
377 "relative address 0x%x out of range of gp register\n",
378 rel);
e01402b1
RB
379 return -ENOEXEC;
380 }
381
382 *location = (*location & 0xffff0000) | (rel & 0xffff);
383
384 return 0;
385}
386
387static int apply_r_mips_pc16(struct module *me, uint32_t *location,
388 Elf32_Addr v)
389{
390 int rel;
391 rel = (((unsigned int)v - (unsigned int)location));
392 rel >>= 2; // because the offset is in _instructions_ not bytes.
393 rel -= 1; // and one instruction less due to the branch delay slot.
394
395 if( (rel > 32768) || (rel < -32768) ) {
2600990e
RB
396 printk(KERN_DEBUG "VPE loader: "
397 "apply_r_mips_pc16: relative address out of range 0x%x\n", rel);
e01402b1
RB
398 return -ENOEXEC;
399 }
400
401 *location = (*location & 0xffff0000) | (rel & 0xffff);
402
403 return 0;
404}
405
406static int apply_r_mips_32(struct module *me, uint32_t *location,
407 Elf32_Addr v)
408{
409 *location += v;
410
411 return 0;
412}
413
414static int apply_r_mips_26(struct module *me, uint32_t *location,
415 Elf32_Addr v)
416{
417 if (v % 4) {
2600990e
RB
418 printk(KERN_DEBUG "VPE loader: apply_r_mips_26 "
419 " unaligned relocation\n");
e01402b1
RB
420 return -ENOEXEC;
421 }
422
307bd284
RB
423/*
424 * Not desperately convinced this is a good check of an overflow condition
425 * anyway. But it gets in the way of handling undefined weak symbols which
426 * we want to set to zero.
427 * if ((v & 0xf0000000) != (((unsigned long)location + 4) & 0xf0000000)) {
428 * printk(KERN_ERR
429 * "module %s: relocation overflow\n",
430 * me->name);
431 * return -ENOEXEC;
432 * }
433 */
e01402b1
RB
434
435 *location = (*location & ~0x03ffffff) |
436 ((*location + (v >> 2)) & 0x03ffffff);
437 return 0;
438}
439
440static int apply_r_mips_hi16(struct module *me, uint32_t *location,
441 Elf32_Addr v)
442{
443 struct mips_hi16 *n;
444
445 /*
446 * We cannot relocate this one now because we don't know the value of
447 * the carry we need to add. Save the information, and let LO16 do the
448 * actual relocation.
449 */
450 n = kmalloc(sizeof *n, GFP_KERNEL);
451 if (!n)
452 return -ENOMEM;
453
454 n->addr = location;
455 n->value = v;
456 n->next = mips_hi16_list;
457 mips_hi16_list = n;
458
459 return 0;
460}
461
462static int apply_r_mips_lo16(struct module *me, uint32_t *location,
463 Elf32_Addr v)
464{
465 unsigned long insnlo = *location;
466 Elf32_Addr val, vallo;
477c4b07 467 struct mips_hi16 *l, *next;
e01402b1
RB
468
469 /* Sign extend the addend we extract from the lo insn. */
470 vallo = ((insnlo & 0xffff) ^ 0x8000) - 0x8000;
471
472 if (mips_hi16_list != NULL) {
e01402b1
RB
473
474 l = mips_hi16_list;
475 while (l != NULL) {
e01402b1
RB
476 unsigned long insn;
477
478 /*
479 * The value for the HI16 had best be the same.
480 */
2600990e
RB
481 if (v != l->value) {
482 printk(KERN_DEBUG "VPE loader: "
b1e3afa0 483 "apply_r_mips_lo16/hi16: \t"
2600990e 484 "inconsistent value information\n");
477c4b07 485 goto out_free;
e01402b1
RB
486 }
487
e01402b1
RB
488 /*
489 * Do the HI16 relocation. Note that we actually don't
490 * need to know anything about the LO16 itself, except
491 * where to find the low 16 bits of the addend needed
492 * by the LO16.
493 */
494 insn = *l->addr;
495 val = ((insn & 0xffff) << 16) + vallo;
496 val += v;
497
498 /*
499 * Account for the sign extension that will happen in
500 * the low bits.
501 */
502 val = ((val >> 16) + ((val & 0x8000) != 0)) & 0xffff;
503
504 insn = (insn & ~0xffff) | val;
505 *l->addr = insn;
506
507 next = l->next;
508 kfree(l);
509 l = next;
510 }
511
512 mips_hi16_list = NULL;
513 }
514
515 /*
516 * Ok, we're done with the HI16 relocs. Now deal with the LO16.
517 */
518 val = v + vallo;
519 insnlo = (insnlo & ~0xffff) | (val & 0xffff);
520 *location = insnlo;
521
522 return 0;
477c4b07
RB
523
524out_free:
525 while (l != NULL) {
526 next = l->next;
527 kfree(l);
528 l = next;
529 }
530 mips_hi16_list = NULL;
531
532 return -ENOEXEC;
e01402b1
RB
533}
534
535static int (*reloc_handlers[]) (struct module *me, uint32_t *location,
536 Elf32_Addr v) = {
537 [R_MIPS_NONE] = apply_r_mips_none,
538 [R_MIPS_32] = apply_r_mips_32,
539 [R_MIPS_26] = apply_r_mips_26,
540 [R_MIPS_HI16] = apply_r_mips_hi16,
541 [R_MIPS_LO16] = apply_r_mips_lo16,
542 [R_MIPS_GPREL16] = apply_r_mips_gprel16,
543 [R_MIPS_PC16] = apply_r_mips_pc16
544};
545
2600990e 546static char *rstrs[] = {
e0daad44 547 [R_MIPS_NONE] = "MIPS_NONE",
2600990e
RB
548 [R_MIPS_32] = "MIPS_32",
549 [R_MIPS_26] = "MIPS_26",
550 [R_MIPS_HI16] = "MIPS_HI16",
551 [R_MIPS_LO16] = "MIPS_LO16",
552 [R_MIPS_GPREL16] = "MIPS_GPREL16",
553 [R_MIPS_PC16] = "MIPS_PC16"
554};
e01402b1 555
f18b51cc 556static int apply_relocations(Elf32_Shdr *sechdrs,
e01402b1
RB
557 const char *strtab,
558 unsigned int symindex,
559 unsigned int relsec,
560 struct module *me)
561{
562 Elf32_Rel *rel = (void *) sechdrs[relsec].sh_addr;
563 Elf32_Sym *sym;
564 uint32_t *location;
565 unsigned int i;
566 Elf32_Addr v;
567 int res;
568
569 for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
570 Elf32_Word r_info = rel[i].r_info;
571
572 /* This is where to make the change */
573 location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
574 + rel[i].r_offset;
575 /* This is the symbol it is referring to */
576 sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
577 + ELF32_R_SYM(r_info);
578
579 if (!sym->st_value) {
580 printk(KERN_DEBUG "%s: undefined weak symbol %s\n",
581 me->name, strtab + sym->st_name);
582 /* just print the warning, dont barf */
583 }
584
585 v = sym->st_value;
586
587 res = reloc_handlers[ELF32_R_TYPE(r_info)](me, location, v);
588 if( res ) {
2600990e
RB
589 char *r = rstrs[ELF32_R_TYPE(r_info)];
590 printk(KERN_WARNING "VPE loader: .text+0x%x "
591 "relocation type %s for symbol \"%s\" failed\n",
592 rel[i].r_offset, r ? r : "UNKNOWN",
593 strtab + sym->st_name);
e01402b1 594 return res;
2600990e 595 }
e01402b1
RB
596 }
597
598 return 0;
599}
600
f18b51cc 601static inline void save_gp_address(unsigned int secbase, unsigned int rel)
e01402b1
RB
602{
603 gp_addr = secbase + rel;
604 gp_offs = gp_addr - (secbase & 0xffff0000);
605}
606/* end module-elf32.c */
607
608
609
610/* Change all symbols so that sh_value encodes the pointer directly. */
2600990e 611static void simplify_symbols(Elf_Shdr * sechdrs,
e01402b1
RB
612 unsigned int symindex,
613 const char *strtab,
614 const char *secstrings,
615 unsigned int nsecs, struct module *mod)
616{
617 Elf_Sym *sym = (void *)sechdrs[symindex].sh_addr;
618 unsigned long secbase, bssbase = 0;
619 unsigned int i, n = sechdrs[symindex].sh_size / sizeof(Elf_Sym);
2600990e 620 int size;
e01402b1
RB
621
622 /* find the .bss section for COMMON symbols */
623 for (i = 0; i < nsecs; i++) {
2600990e 624 if (strncmp(secstrings + sechdrs[i].sh_name, ".bss", 4) == 0) {
e01402b1 625 bssbase = sechdrs[i].sh_addr;
2600990e
RB
626 break;
627 }
e01402b1
RB
628 }
629
630 for (i = 1; i < n; i++) {
631 switch (sym[i].st_shndx) {
632 case SHN_COMMON:
2600990e
RB
633 /* Allocate space for the symbol in the .bss section.
634 st_value is currently size.
e01402b1
RB
635 We want it to have the address of the symbol. */
636
637 size = sym[i].st_value;
638 sym[i].st_value = bssbase;
639
640 bssbase += size;
641 break;
642
643 case SHN_ABS:
644 /* Don't need to do anything */
645 break;
646
647 case SHN_UNDEF:
648 /* ret = -ENOENT; */
649 break;
650
651 case SHN_MIPS_SCOMMON:
b1e3afa0 652 printk(KERN_DEBUG "simplify_symbols: ignoring SHN_MIPS_SCOMMON "
2600990e
RB
653 "symbol <%s> st_shndx %d\n", strtab + sym[i].st_name,
654 sym[i].st_shndx);
e01402b1
RB
655 // .sbss section
656 break;
657
658 default:
659 secbase = sechdrs[sym[i].st_shndx].sh_addr;
660
661 if (strncmp(strtab + sym[i].st_name, "_gp", 3) == 0) {
662 save_gp_address(secbase, sym[i].st_value);
663 }
664
665 sym[i].st_value += secbase;
666 break;
667 }
e01402b1 668 }
e01402b1
RB
669}
670
671#ifdef DEBUG_ELFLOADER
672static void dump_elfsymbols(Elf_Shdr * sechdrs, unsigned int symindex,
673 const char *strtab, struct module *mod)
674{
675 Elf_Sym *sym = (void *)sechdrs[symindex].sh_addr;
676 unsigned int i, n = sechdrs[symindex].sh_size / sizeof(Elf_Sym);
677
678 printk(KERN_DEBUG "dump_elfsymbols: n %d\n", n);
679 for (i = 1; i < n; i++) {
680 printk(KERN_DEBUG " i %d name <%s> 0x%x\n", i,
681 strtab + sym[i].st_name, sym[i].st_value);
682 }
683}
684#endif
685
e01402b1 686/* We are prepared so configure and start the VPE... */
be6e1437 687static int vpe_run(struct vpe * v)
e01402b1 688{
07cc0c9e 689 unsigned long flags, val, dmt_flag;
2600990e 690 struct vpe_notifications *n;
07cc0c9e 691 unsigned int vpeflags;
e01402b1
RB
692 struct tc *t;
693
694 /* check we are the Master VPE */
07cc0c9e 695 local_irq_save(flags);
e01402b1
RB
696 val = read_c0_vpeconf0();
697 if (!(val & VPECONF0_MVP)) {
698 printk(KERN_WARNING
2600990e 699 "VPE loader: only Master VPE's are allowed to configure MT\n");
07cc0c9e
RB
700 local_irq_restore(flags);
701
e01402b1
RB
702 return -1;
703 }
704
07cc0c9e
RB
705 dmt_flag = dmt();
706 vpeflags = dvpe();
e01402b1 707
2600990e 708 if (!list_empty(&v->tc)) {
e0daad44 709 if ((t = list_entry(v->tc.next, struct tc, tc)) == NULL) {
07cc0c9e
RB
710 evpe(vpeflags);
711 emt(dmt_flag);
712 local_irq_restore(flags);
713
714 printk(KERN_WARNING
715 "VPE loader: TC %d is already in use.\n",
716 t->index);
e0daad44
RB
717 return -ENOEXEC;
718 }
719 } else {
07cc0c9e
RB
720 evpe(vpeflags);
721 emt(dmt_flag);
722 local_irq_restore(flags);
723
724 printk(KERN_WARNING
725 "VPE loader: No TC's associated with VPE %d\n",
e0daad44 726 v->minor);
07cc0c9e 727
e0daad44
RB
728 return -ENOEXEC;
729 }
2600990e 730
e01402b1 731 /* Put MVPE's into 'configuration state' */
340ee4b9 732 set_c0_mvpcontrol(MVPCONTROL_VPC);
e01402b1 733
e01402b1
RB
734 settc(t->index);
735
e01402b1
RB
736 /* should check it is halted, and not activated */
737 if ((read_tc_c0_tcstatus() & TCSTATUS_A) || !(read_tc_c0_tchalt() & TCHALT_H)) {
07cc0c9e
RB
738 evpe(vpeflags);
739 emt(dmt_flag);
740 local_irq_restore(flags);
741
742 printk(KERN_WARNING "VPE loader: TC %d is already active!\n",
e01402b1 743 t->index);
07cc0c9e 744
e01402b1
RB
745 return -ENOEXEC;
746 }
747
748 /* Write the address we want it to start running from in the TCPC register. */
749 write_tc_c0_tcrestart((unsigned long)v->__start);
e01402b1 750 write_tc_c0_tccontext((unsigned long)0);
07cc0c9e 751
2600990e
RB
752 /*
753 * Mark the TC as activated, not interrupt exempt and not dynamically
754 * allocatable
755 */
e01402b1
RB
756 val = read_tc_c0_tcstatus();
757 val = (val & ~(TCSTATUS_DA | TCSTATUS_IXMT)) | TCSTATUS_A;
758 write_tc_c0_tcstatus(val);
759
760 write_tc_c0_tchalt(read_tc_c0_tchalt() & ~TCHALT_H);
761
e01402b1
RB
762 /*
763 * The sde-kit passes 'memsize' to __start in $a3, so set something
2600990e 764 * here... Or set $a3 to zero and define DFLT_STACK_SIZE and
e01402b1
RB
765 * DFLT_HEAP_SIZE when you compile your program
766 */
41790e04 767 mttgpr(6, v->ntcs);
07cc0c9e 768 mttgpr(7, physical_memsize);
2600990e
RB
769
770 /* set up VPE1 */
771 /*
772 * bind the TC to VPE 1 as late as possible so we only have the final
773 * VPE registers to set up, and so an EJTAG probe can trigger on it
774 */
07cc0c9e 775 write_tc_c0_tcbind((read_tc_c0_tcbind() & ~TCBIND_CURVPE) | 1);
e01402b1 776
a94d7020
EO
777 write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() & ~(VPECONF0_VPA));
778
779 back_to_back_c0_hazard();
780
e0daad44
RB
781 /* Set up the XTC bit in vpeconf0 to point at our tc */
782 write_vpe_c0_vpeconf0( (read_vpe_c0_vpeconf0() & ~(VPECONF0_XTC))
783 | (t->index << VPECONF0_XTC_SHIFT));
e01402b1 784
a94d7020
EO
785 back_to_back_c0_hazard();
786
e0daad44
RB
787 /* enable this VPE */
788 write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() | VPECONF0_VPA);
e01402b1
RB
789
790 /* clear out any left overs from a previous program */
2600990e 791 write_vpe_c0_status(0);
e01402b1
RB
792 write_vpe_c0_cause(0);
793
794 /* take system out of configuration state */
340ee4b9 795 clear_c0_mvpcontrol(MVPCONTROL_VPC);
e01402b1 796
b618336a
KK
797 /*
798 * SMTC/SMVP kernels manage VPE enable independently,
799 * but uniprocessor kernels need to turn it on, even
800 * if that wasn't the pre-dvpe() state.
801 */
07cc0c9e 802#ifdef CONFIG_SMP
07cc0c9e 803 evpe(vpeflags);
b618336a
KK
804#else
805 evpe(EVPE_ENABLE);
07cc0c9e
RB
806#endif
807 emt(dmt_flag);
808 local_irq_restore(flags);
e01402b1 809
07cc0c9e
RB
810 list_for_each_entry(n, &v->notify, list)
811 n->start(minor);
2600990e 812
e01402b1
RB
813 return 0;
814}
815
2600990e 816static int find_vpe_symbols(struct vpe * v, Elf_Shdr * sechdrs,
e01402b1
RB
817 unsigned int symindex, const char *strtab,
818 struct module *mod)
819{
820 Elf_Sym *sym = (void *)sechdrs[symindex].sh_addr;
821 unsigned int i, n = sechdrs[symindex].sh_size / sizeof(Elf_Sym);
822
823 for (i = 1; i < n; i++) {
824 if (strcmp(strtab + sym[i].st_name, "__start") == 0) {
825 v->__start = sym[i].st_value;
826 }
827
828 if (strcmp(strtab + sym[i].st_name, "vpe_shared") == 0) {
829 v->shared_ptr = (void *)sym[i].st_value;
830 }
831 }
832
2600990e
RB
833 if ( (v->__start == 0) || (v->shared_ptr == NULL))
834 return -1;
835
e01402b1
RB
836 return 0;
837}
838
307bd284 839/*
2600990e
RB
840 * Allocates a VPE with some program code space(the load address), copies the
841 * contents of the program (p)buffer performing relocatations/etc, free's it
842 * when finished.
843 */
be6e1437 844static int vpe_elfload(struct vpe * v)
e01402b1
RB
845{
846 Elf_Ehdr *hdr;
847 Elf_Shdr *sechdrs;
848 long err = 0;
849 char *secstrings, *strtab = NULL;
2600990e 850 unsigned int len, i, symindex = 0, strindex = 0, relocate = 0;
e01402b1
RB
851 struct module mod; // so we can re-use the relocations code
852
853 memset(&mod, 0, sizeof(struct module));
2600990e 854 strcpy(mod.name, "VPE loader");
e01402b1
RB
855
856 hdr = (Elf_Ehdr *) v->pbuffer;
857 len = v->plen;
858
859 /* Sanity checks against insmoding binaries or wrong arch,
860 weird elf version */
d303f4a1 861 if (memcmp(hdr->e_ident, ELFMAG, SELFMAG) != 0
2600990e
RB
862 || (hdr->e_type != ET_REL && hdr->e_type != ET_EXEC)
863 || !elf_check_arch(hdr)
e01402b1
RB
864 || hdr->e_shentsize != sizeof(*sechdrs)) {
865 printk(KERN_WARNING
2600990e 866 "VPE loader: program wrong arch or weird elf version\n");
e01402b1
RB
867
868 return -ENOEXEC;
869 }
870
2600990e
RB
871 if (hdr->e_type == ET_REL)
872 relocate = 1;
873
e01402b1 874 if (len < hdr->e_shoff + hdr->e_shnum * sizeof(Elf_Shdr)) {
2600990e
RB
875 printk(KERN_ERR "VPE loader: program length %u truncated\n",
876 len);
877
e01402b1
RB
878 return -ENOEXEC;
879 }
880
881 /* Convenience variables */
882 sechdrs = (void *)hdr + hdr->e_shoff;
883 secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
884 sechdrs[0].sh_addr = 0;
885
886 /* And these should exist, but gcc whinges if we don't init them */
887 symindex = strindex = 0;
888
2600990e
RB
889 if (relocate) {
890 for (i = 1; i < hdr->e_shnum; i++) {
891 if (sechdrs[i].sh_type != SHT_NOBITS
892 && len < sechdrs[i].sh_offset + sechdrs[i].sh_size) {
893 printk(KERN_ERR "VPE program length %u truncated\n",
894 len);
895 return -ENOEXEC;
896 }
e01402b1 897
2600990e
RB
898 /* Mark all sections sh_addr with their address in the
899 temporary image. */
900 sechdrs[i].sh_addr = (size_t) hdr + sechdrs[i].sh_offset;
e01402b1 901
2600990e
RB
902 /* Internal symbols and strings. */
903 if (sechdrs[i].sh_type == SHT_SYMTAB) {
904 symindex = i;
905 strindex = sechdrs[i].sh_link;
906 strtab = (char *)hdr + sechdrs[strindex].sh_offset;
907 }
e01402b1 908 }
2600990e 909 layout_sections(&mod, hdr, sechdrs, secstrings);
e01402b1
RB
910 }
911
e01402b1 912 v->load_addr = alloc_progmem(mod.core_size);
5408c490
RB
913 if (!v->load_addr)
914 return -ENOMEM;
e01402b1 915
5408c490 916 pr_info("VPE loader: loading to %p\n", v->load_addr);
e01402b1 917
2600990e
RB
918 if (relocate) {
919 for (i = 0; i < hdr->e_shnum; i++) {
920 void *dest;
e01402b1 921
2600990e
RB
922 if (!(sechdrs[i].sh_flags & SHF_ALLOC))
923 continue;
e01402b1 924
2600990e 925 dest = v->load_addr + sechdrs[i].sh_entsize;
e01402b1 926
2600990e
RB
927 if (sechdrs[i].sh_type != SHT_NOBITS)
928 memcpy(dest, (void *)sechdrs[i].sh_addr,
929 sechdrs[i].sh_size);
930 /* Update sh_addr to point to copy in image. */
931 sechdrs[i].sh_addr = (unsigned long)dest;
e01402b1 932
2600990e
RB
933 printk(KERN_DEBUG " section sh_name %s sh_addr 0x%x\n",
934 secstrings + sechdrs[i].sh_name, sechdrs[i].sh_addr);
935 }
e01402b1 936
2600990e
RB
937 /* Fix up syms, so that st_value is a pointer to location. */
938 simplify_symbols(sechdrs, symindex, strtab, secstrings,
939 hdr->e_shnum, &mod);
940
941 /* Now do relocations. */
942 for (i = 1; i < hdr->e_shnum; i++) {
943 const char *strtab = (char *)sechdrs[strindex].sh_addr;
944 unsigned int info = sechdrs[i].sh_info;
945
946 /* Not a valid relocation section? */
947 if (info >= hdr->e_shnum)
948 continue;
949
950 /* Don't bother with non-allocated sections */
951 if (!(sechdrs[info].sh_flags & SHF_ALLOC))
952 continue;
953
954 if (sechdrs[i].sh_type == SHT_REL)
955 err = apply_relocations(sechdrs, strtab, symindex, i,
956 &mod);
957 else if (sechdrs[i].sh_type == SHT_RELA)
958 err = apply_relocate_add(sechdrs, strtab, symindex, i,
959 &mod);
960 if (err < 0)
961 return err;
962
963 }
964 } else {
bdf5d42c 965 struct elf_phdr *phdr = (struct elf_phdr *) ((char *)hdr + hdr->e_phoff);
2600990e 966
bdf5d42c 967 for (i = 0; i < hdr->e_phnum; i++) {
b618336a
KK
968 if (phdr->p_type == PT_LOAD) {
969 memcpy((void *)phdr->p_paddr,
970 (char *)hdr + phdr->p_offset,
971 phdr->p_filesz);
972 memset((void *)phdr->p_paddr + phdr->p_filesz,
973 0, phdr->p_memsz - phdr->p_filesz);
974 }
975 phdr++;
bdf5d42c
RB
976 }
977
978 for (i = 0; i < hdr->e_shnum; i++) {
2600990e
RB
979 /* Internal symbols and strings. */
980 if (sechdrs[i].sh_type == SHT_SYMTAB) {
981 symindex = i;
982 strindex = sechdrs[i].sh_link;
983 strtab = (char *)hdr + sechdrs[strindex].sh_offset;
984
985 /* mark the symtab's address for when we try to find the
986 magic symbols */
987 sechdrs[i].sh_addr = (size_t) hdr + sechdrs[i].sh_offset;
988 }
e01402b1
RB
989 }
990 }
991
992 /* make sure it's physically written out */
993 flush_icache_range((unsigned long)v->load_addr,
994 (unsigned long)v->load_addr + v->len);
995
996 if ((find_vpe_symbols(v, sechdrs, symindex, strtab, &mod)) < 0) {
2600990e
RB
997 if (v->__start == 0) {
998 printk(KERN_WARNING "VPE loader: program does not contain "
999 "a __start symbol\n");
1000 return -ENOEXEC;
1001 }
e01402b1 1002
2600990e
RB
1003 if (v->shared_ptr == NULL)
1004 printk(KERN_WARNING "VPE loader: "
1005 "program does not contain vpe_shared symbol.\n"
1006 " Unable to use AMVP (AP/SP) facilities.\n");
e01402b1
RB
1007 }
1008
1009 printk(" elf loaded\n");
2600990e 1010 return 0;
e01402b1
RB
1011}
1012
2600990e
RB
1013static void cleanup_tc(struct tc *tc)
1014{
07cc0c9e
RB
1015 unsigned long flags;
1016 unsigned int mtflags, vpflags;
2600990e
RB
1017 int tmp;
1018
07cc0c9e
RB
1019 local_irq_save(flags);
1020 mtflags = dmt();
1021 vpflags = dvpe();
2600990e
RB
1022 /* Put MVPE's into 'configuration state' */
1023 set_c0_mvpcontrol(MVPCONTROL_VPC);
1024
1025 settc(tc->index);
1026 tmp = read_tc_c0_tcstatus();
1027
1028 /* mark not allocated and not dynamically allocatable */
1029 tmp &= ~(TCSTATUS_A | TCSTATUS_DA);
1030 tmp |= TCSTATUS_IXMT; /* interrupt exempt */
1031 write_tc_c0_tcstatus(tmp);
1032
1033 write_tc_c0_tchalt(TCHALT_H);
7c3a622d 1034 mips_ihb();
2600990e
RB
1035
1036 /* bind it to anything other than VPE1 */
07cc0c9e 1037// write_tc_c0_tcbind(read_tc_c0_tcbind() & ~TCBIND_CURVPE); // | TCBIND_CURVPE
2600990e
RB
1038
1039 clear_c0_mvpcontrol(MVPCONTROL_VPC);
07cc0c9e
RB
1040 evpe(vpflags);
1041 emt(mtflags);
1042 local_irq_restore(flags);
2600990e
RB
1043}
1044
1045static int getcwd(char *buff, int size)
1046{
1047 mm_segment_t old_fs;
1048 int ret;
1049
1050 old_fs = get_fs();
1051 set_fs(KERNEL_DS);
1052
21a151d8 1053 ret = sys_getcwd(buff, size);
2600990e
RB
1054
1055 set_fs(old_fs);
1056
1057 return ret;
1058}
1059
1060/* checks VPE is unused and gets ready to load program */
e01402b1
RB
1061static int vpe_open(struct inode *inode, struct file *filp)
1062{
c4c4018b 1063 enum vpe_state state;
2600990e 1064 struct vpe_notifications *not;
07cc0c9e 1065 struct vpe *v;
1bbfc20d 1066 int ret;
e01402b1 1067
07cc0c9e
RB
1068 if (minor != iminor(inode)) {
1069 /* assume only 1 device at the moment. */
1bbfc20d
RB
1070 pr_warning("VPE loader: only vpe1 is supported\n");
1071
1072 return -ENODEV;
e01402b1
RB
1073 }
1074
07cc0c9e 1075 if ((v = get_vpe(tclimit)) == NULL) {
1bbfc20d
RB
1076 pr_warning("VPE loader: unable to get vpe\n");
1077
1078 return -ENODEV;
e01402b1
RB
1079 }
1080
c4c4018b
RB
1081 state = xchg(&v->state, VPE_STATE_INUSE);
1082 if (state != VPE_STATE_UNUSED) {
2600990e 1083 printk(KERN_DEBUG "VPE loader: tc in use dumping regs\n");
e01402b1 1084
2600990e 1085 list_for_each_entry(not, &v->notify, list) {
07cc0c9e 1086 not->stop(tclimit);
2600990e 1087 }
e01402b1 1088
2600990e 1089 release_progmem(v->load_addr);
07cc0c9e 1090 cleanup_tc(get_tc(tclimit));
e01402b1
RB
1091 }
1092
e01402b1
RB
1093 /* this of-course trashes what was there before... */
1094 v->pbuffer = vmalloc(P_SIZE);
1095 v->plen = P_SIZE;
1096 v->load_addr = NULL;
1097 v->len = 0;
1098
d76b0d9b
DH
1099 v->uid = filp->f_cred->fsuid;
1100 v->gid = filp->f_cred->fsgid;
2600990e
RB
1101
1102#ifdef CONFIG_MIPS_APSP_KSPD
1103 /* get kspd to tell us when a syscall_exit happens */
1104 if (!kspd_events_reqd) {
1105 kspd_notify(&kspd_events);
1106 kspd_events_reqd++;
1107 }
1108#endif
1109
1110 v->cwd[0] = 0;
1111 ret = getcwd(v->cwd, VPE_PATH_MAX);
1112 if (ret < 0)
1113 printk(KERN_WARNING "VPE loader: open, getcwd returned %d\n", ret);
1114
1115 v->shared_ptr = NULL;
1116 v->__start = 0;
07cc0c9e 1117
e01402b1
RB
1118 return 0;
1119}
1120
1121static int vpe_release(struct inode *inode, struct file *filp)
1122{
307bd284 1123 struct vpe *v;
e01402b1 1124 Elf_Ehdr *hdr;
07cc0c9e 1125 int ret = 0;
e01402b1 1126
07cc0c9e
RB
1127 v = get_vpe(tclimit);
1128 if (v == NULL)
e01402b1
RB
1129 return -ENODEV;
1130
e01402b1 1131 hdr = (Elf_Ehdr *) v->pbuffer;
d303f4a1 1132 if (memcmp(hdr->e_ident, ELFMAG, SELFMAG) == 0) {
07cc0c9e 1133 if (vpe_elfload(v) >= 0) {
e01402b1 1134 vpe_run(v);
07cc0c9e 1135 } else {
2600990e 1136 printk(KERN_WARNING "VPE loader: ELF load failed.\n");
e01402b1
RB
1137 ret = -ENOEXEC;
1138 }
1139 } else {
2600990e 1140 printk(KERN_WARNING "VPE loader: only elf files are supported\n");
e01402b1
RB
1141 ret = -ENOEXEC;
1142 }
1143
2600990e
RB
1144 /* It's good to be able to run the SP and if it chokes have a look at
1145 the /dev/rt?. But if we reset the pointer to the shared struct we
8ebcfc8b 1146 lose what has happened. So perhaps if garbage is sent to the vpe
2600990e
RB
1147 device, use it as a trigger for the reset. Hopefully a nice
1148 executable will be along shortly. */
1149 if (ret < 0)
1150 v->shared_ptr = NULL;
1151
e01402b1
RB
1152 // cleanup any temp buffers
1153 if (v->pbuffer)
1154 vfree(v->pbuffer);
1155 v->plen = 0;
1156 return ret;
1157}
1158
1159static ssize_t vpe_write(struct file *file, const char __user * buffer,
1160 size_t count, loff_t * ppos)
1161{
e01402b1 1162 size_t ret = count;
307bd284 1163 struct vpe *v;
e01402b1 1164
07cc0c9e
RB
1165 if (iminor(file->f_path.dentry->d_inode) != minor)
1166 return -ENODEV;
1167
1168 v = get_vpe(tclimit);
1169 if (v == NULL)
e01402b1
RB
1170 return -ENODEV;
1171
1172 if (v->pbuffer == NULL) {
2600990e 1173 printk(KERN_ERR "VPE loader: no buffer for program\n");
e01402b1
RB
1174 return -ENOMEM;
1175 }
1176
1177 if ((count + v->len) > v->plen) {
1178 printk(KERN_WARNING
2600990e 1179 "VPE loader: elf size too big. Perhaps strip uneeded symbols\n");
e01402b1
RB
1180 return -ENOMEM;
1181 }
1182
1183 count -= copy_from_user(v->pbuffer + v->len, buffer, count);
2600990e 1184 if (!count)
e01402b1 1185 return -EFAULT;
e01402b1
RB
1186
1187 v->len += count;
1188 return ret;
1189}
1190
5dfe4c96 1191static const struct file_operations vpe_fops = {
e01402b1
RB
1192 .owner = THIS_MODULE,
1193 .open = vpe_open,
1194 .release = vpe_release,
6038f373
AB
1195 .write = vpe_write,
1196 .llseek = noop_llseek,
e01402b1
RB
1197};
1198
1199/* module wrapper entry points */
1200/* give me a vpe */
1201vpe_handle vpe_alloc(void)
1202{
1203 int i;
1204 struct vpe *v;
1205
1206 /* find a vpe */
1207 for (i = 1; i < MAX_VPES; i++) {
1208 if ((v = get_vpe(i)) != NULL) {
1209 v->state = VPE_STATE_INUSE;
1210 return v;
1211 }
1212 }
1213 return NULL;
1214}
1215
1216EXPORT_SYMBOL(vpe_alloc);
1217
1218/* start running from here */
1219int vpe_start(vpe_handle vpe, unsigned long start)
1220{
1221 struct vpe *v = vpe;
1222
1223 v->__start = start;
1224 return vpe_run(v);
1225}
1226
1227EXPORT_SYMBOL(vpe_start);
1228
1229/* halt it for now */
1230int vpe_stop(vpe_handle vpe)
1231{
1232 struct vpe *v = vpe;
1233 struct tc *t;
1234 unsigned int evpe_flags;
1235
1236 evpe_flags = dvpe();
1237
1238 if ((t = list_entry(v->tc.next, struct tc, tc)) != NULL) {
1239
1240 settc(t->index);
1241 write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() & ~VPECONF0_VPA);
1242 }
1243
1244 evpe(evpe_flags);
1245
1246 return 0;
1247}
1248
1249EXPORT_SYMBOL(vpe_stop);
1250
1251/* I've done with it thank you */
1252int vpe_free(vpe_handle vpe)
1253{
1254 struct vpe *v = vpe;
1255 struct tc *t;
1256 unsigned int evpe_flags;
1257
1258 if ((t = list_entry(v->tc.next, struct tc, tc)) == NULL) {
1259 return -ENOEXEC;
1260 }
1261
1262 evpe_flags = dvpe();
1263
1264 /* Put MVPE's into 'configuration state' */
340ee4b9 1265 set_c0_mvpcontrol(MVPCONTROL_VPC);
e01402b1
RB
1266
1267 settc(t->index);
1268 write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() & ~VPECONF0_VPA);
1269
7c3a622d 1270 /* halt the TC */
e01402b1 1271 write_tc_c0_tchalt(TCHALT_H);
7c3a622d
NS
1272 mips_ihb();
1273
1274 /* mark the TC unallocated */
1275 write_tc_c0_tcstatus(read_tc_c0_tcstatus() & ~TCSTATUS_A);
e01402b1
RB
1276
1277 v->state = VPE_STATE_UNUSED;
1278
340ee4b9 1279 clear_c0_mvpcontrol(MVPCONTROL_VPC);
e01402b1
RB
1280 evpe(evpe_flags);
1281
1282 return 0;
1283}
1284
1285EXPORT_SYMBOL(vpe_free);
1286
1287void *vpe_get_shared(int index)
1288{
1289 struct vpe *v;
1290
2600990e 1291 if ((v = get_vpe(index)) == NULL)
e01402b1 1292 return NULL;
e01402b1
RB
1293
1294 return v->shared_ptr;
1295}
1296
1297EXPORT_SYMBOL(vpe_get_shared);
1298
2600990e
RB
1299int vpe_getuid(int index)
1300{
1301 struct vpe *v;
1302
1303 if ((v = get_vpe(index)) == NULL)
1304 return -1;
1305
1306 return v->uid;
1307}
1308
1309EXPORT_SYMBOL(vpe_getuid);
1310
1311int vpe_getgid(int index)
1312{
1313 struct vpe *v;
1314
1315 if ((v = get_vpe(index)) == NULL)
1316 return -1;
1317
1318 return v->gid;
1319}
1320
1321EXPORT_SYMBOL(vpe_getgid);
1322
1323int vpe_notify(int index, struct vpe_notifications *notify)
1324{
1325 struct vpe *v;
1326
1327 if ((v = get_vpe(index)) == NULL)
1328 return -1;
1329
1330 list_add(&notify->list, &v->notify);
1331 return 0;
1332}
1333
1334EXPORT_SYMBOL(vpe_notify);
1335
1336char *vpe_getcwd(int index)
1337{
1338 struct vpe *v;
1339
1340 if ((v = get_vpe(index)) == NULL)
1341 return NULL;
1342
1343 return v->cwd;
1344}
1345
1346EXPORT_SYMBOL(vpe_getcwd);
1347
1348#ifdef CONFIG_MIPS_APSP_KSPD
1349static void kspd_sp_exit( int sp_id)
1350{
1351 cleanup_tc(get_tc(sp_id));
1352}
1353#endif
1354
736fad17
KS
1355static ssize_t store_kill(struct device *dev, struct device_attribute *attr,
1356 const char *buf, size_t len)
0f5d0df3
RB
1357{
1358 struct vpe *vpe = get_vpe(tclimit);
1359 struct vpe_notifications *not;
1360
1361 list_for_each_entry(not, &vpe->notify, list) {
1362 not->stop(tclimit);
1363 }
1364
1365 release_progmem(vpe->load_addr);
1366 cleanup_tc(get_tc(tclimit));
1367 vpe_stop(vpe);
1368 vpe_free(vpe);
1369
1370 return len;
1371}
1372
736fad17
KS
1373static ssize_t show_ntcs(struct device *cd, struct device_attribute *attr,
1374 char *buf)
41790e04
RB
1375{
1376 struct vpe *vpe = get_vpe(tclimit);
1377
1378 return sprintf(buf, "%d\n", vpe->ntcs);
1379}
1380
736fad17
KS
1381static ssize_t store_ntcs(struct device *dev, struct device_attribute *attr,
1382 const char *buf, size_t len)
41790e04
RB
1383{
1384 struct vpe *vpe = get_vpe(tclimit);
1385 unsigned long new;
1386 char *endp;
1387
1388 new = simple_strtoul(buf, &endp, 0);
1389 if (endp == buf)
1390 goto out_einval;
1391
1392 if (new == 0 || new > (hw_tcs - tclimit))
1393 goto out_einval;
1394
1395 vpe->ntcs = new;
1396
1397 return len;
1398
1399out_einval:
52a7a27c 1400 return -EINVAL;
41790e04
RB
1401}
1402
736fad17 1403static struct device_attribute vpe_class_attributes[] = {
0f5d0df3 1404 __ATTR(kill, S_IWUSR, NULL, store_kill),
41790e04
RB
1405 __ATTR(ntcs, S_IRUGO | S_IWUSR, show_ntcs, store_ntcs),
1406 {}
1407};
1408
736fad17 1409static void vpe_device_release(struct device *cd)
41790e04
RB
1410{
1411 kfree(cd);
1412}
1413
1414struct class vpe_class = {
1415 .name = "vpe",
1416 .owner = THIS_MODULE,
736fad17
KS
1417 .dev_release = vpe_device_release,
1418 .dev_attrs = vpe_class_attributes,
41790e04
RB
1419};
1420
736fad17 1421struct device vpe_device;
27a3bbaf 1422
e01402b1
RB
1423static int __init vpe_module_init(void)
1424{
07cc0c9e 1425 unsigned int mtflags, vpflags;
07cc0c9e 1426 unsigned long flags, val;
e01402b1
RB
1427 struct vpe *v = NULL;
1428 struct tc *t;
41790e04 1429 int tc, err;
e01402b1
RB
1430
1431 if (!cpu_has_mipsmt) {
1432 printk("VPE loader: not a MIPS MT capable processor\n");
1433 return -ENODEV;
1434 }
1435
07cc0c9e
RB
1436 if (vpelimit == 0) {
1437 printk(KERN_WARNING "No VPEs reserved for AP/SP, not "
1438 "initializing VPE loader.\nPass maxvpes=<n> argument as "
1439 "kernel argument\n");
1440
1441 return -ENODEV;
1442 }
1443
1444 if (tclimit == 0) {
1445 printk(KERN_WARNING "No TCs reserved for AP/SP, not "
1446 "initializing VPE loader.\nPass maxtcs=<n> argument as "
1447 "kernel argument\n");
1448
1449 return -ENODEV;
1450 }
1451
682e852e
AD
1452 major = register_chrdev(0, module_name, &vpe_fops);
1453 if (major < 0) {
e01402b1 1454 printk("VPE loader: unable to register character device\n");
307bd284 1455 return major;
e01402b1
RB
1456 }
1457
41790e04
RB
1458 err = class_register(&vpe_class);
1459 if (err) {
1460 printk(KERN_ERR "vpe_class registration failed\n");
27a3bbaf
RB
1461 goto out_chrdev;
1462 }
41790e04 1463
736fad17 1464 device_initialize(&vpe_device);
41790e04
RB
1465 vpe_device.class = &vpe_class,
1466 vpe_device.parent = NULL,
1bb5beb4 1467 dev_set_name(&vpe_device, "vpe1");
41790e04 1468 vpe_device.devt = MKDEV(major, minor);
736fad17 1469 err = device_add(&vpe_device);
41790e04
RB
1470 if (err) {
1471 printk(KERN_ERR "Adding vpe_device failed\n");
1472 goto out_class;
1473 }
27a3bbaf 1474
07cc0c9e
RB
1475 local_irq_save(flags);
1476 mtflags = dmt();
1477 vpflags = dvpe();
e01402b1
RB
1478
1479 /* Put MVPE's into 'configuration state' */
340ee4b9 1480 set_c0_mvpcontrol(MVPCONTROL_VPC);
e01402b1
RB
1481
1482 /* dump_mtregs(); */
1483
e01402b1 1484 val = read_c0_mvpconf0();
07cc0c9e
RB
1485 hw_tcs = (val & MVPCONF0_PTC) + 1;
1486 hw_vpes = ((val & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT) + 1;
1487
1488 for (tc = tclimit; tc < hw_tcs; tc++) {
1489 /*
1490 * Must re-enable multithreading temporarily or in case we
1491 * reschedule send IPIs or similar we might hang.
1492 */
1493 clear_c0_mvpcontrol(MVPCONTROL_VPC);
1494 evpe(vpflags);
1495 emt(mtflags);
1496 local_irq_restore(flags);
1497 t = alloc_tc(tc);
1498 if (!t) {
1499 err = -ENOMEM;
1500 goto out;
1501 }
1502
1503 local_irq_save(flags);
1504 mtflags = dmt();
1505 vpflags = dvpe();
1506 set_c0_mvpcontrol(MVPCONTROL_VPC);
e01402b1
RB
1507
1508 /* VPE's */
07cc0c9e
RB
1509 if (tc < hw_tcs) {
1510 settc(tc);
e01402b1 1511
07cc0c9e 1512 if ((v = alloc_vpe(tc)) == NULL) {
e01402b1 1513 printk(KERN_WARNING "VPE: unable to allocate VPE\n");
07cc0c9e
RB
1514
1515 goto out_reenable;
e01402b1
RB
1516 }
1517
41790e04
RB
1518 v->ntcs = hw_tcs - tclimit;
1519
2600990e
RB
1520 /* add the tc to the list of this vpe's tc's. */
1521 list_add(&t->tc, &v->tc);
e01402b1
RB
1522
1523 /* deactivate all but vpe0 */
07cc0c9e 1524 if (tc >= tclimit) {
e01402b1
RB
1525 unsigned long tmp = read_vpe_c0_vpeconf0();
1526
1527 tmp &= ~VPECONF0_VPA;
1528
1529 /* master VPE */
1530 tmp |= VPECONF0_MVP;
1531 write_vpe_c0_vpeconf0(tmp);
1532 }
1533
1534 /* disable multi-threading with TC's */
1535 write_vpe_c0_vpecontrol(read_vpe_c0_vpecontrol() & ~VPECONTROL_TE);
1536
07cc0c9e 1537 if (tc >= vpelimit) {
2600990e
RB
1538 /*
1539 * Set config to be the same as vpe0,
1540 * particularly kseg0 coherency alg
1541 */
e01402b1
RB
1542 write_vpe_c0_config(read_c0_config());
1543 }
e01402b1
RB
1544 }
1545
1546 /* TC's */
1547 t->pvpe = v; /* set the parent vpe */
1548
07cc0c9e 1549 if (tc >= tclimit) {
e01402b1
RB
1550 unsigned long tmp;
1551
07cc0c9e 1552 settc(tc);
e01402b1 1553
2600990e
RB
1554 /* Any TC that is bound to VPE0 gets left as is - in case
1555 we are running SMTC on VPE0. A TC that is bound to any
1556 other VPE gets bound to VPE0, ideally I'd like to make
1557 it homeless but it doesn't appear to let me bind a TC
1558 to a non-existent VPE. Which is perfectly reasonable.
1559
1560 The (un)bound state is visible to an EJTAG probe so may
1561 notify GDB...
1562 */
1563
1564 if (((tmp = read_tc_c0_tcbind()) & TCBIND_CURVPE)) {
1565 /* tc is bound >vpe0 */
1566 write_tc_c0_tcbind(tmp & ~TCBIND_CURVPE);
1567
1568 t->pvpe = get_vpe(0); /* set the parent vpe */
1569 }
e01402b1 1570
7c3a622d
NS
1571 /* halt the TC */
1572 write_tc_c0_tchalt(TCHALT_H);
1573 mips_ihb();
1574
e01402b1
RB
1575 tmp = read_tc_c0_tcstatus();
1576
2600990e 1577 /* mark not activated and not dynamically allocatable */
e01402b1
RB
1578 tmp &= ~(TCSTATUS_A | TCSTATUS_DA);
1579 tmp |= TCSTATUS_IXMT; /* interrupt exempt */
1580 write_tc_c0_tcstatus(tmp);
e01402b1
RB
1581 }
1582 }
1583
07cc0c9e 1584out_reenable:
e01402b1 1585 /* release config state */
340ee4b9 1586 clear_c0_mvpcontrol(MVPCONTROL_VPC);
e01402b1 1587
07cc0c9e
RB
1588 evpe(vpflags);
1589 emt(mtflags);
1590 local_irq_restore(flags);
1591
2600990e
RB
1592#ifdef CONFIG_MIPS_APSP_KSPD
1593 kspd_events.kspd_sp_exit = kspd_sp_exit;
1594#endif
e01402b1 1595 return 0;
27a3bbaf 1596
41790e04
RB
1597out_class:
1598 class_unregister(&vpe_class);
27a3bbaf
RB
1599out_chrdev:
1600 unregister_chrdev(major, module_name);
1601
07cc0c9e 1602out:
27a3bbaf 1603 return err;
e01402b1
RB
1604}
1605
1606static void __exit vpe_module_exit(void)
1607{
1608 struct vpe *v, *n;
1609
1bbfc20d
RB
1610 device_del(&vpe_device);
1611 unregister_chrdev(major, module_name);
1612
1613 /* No locking needed here */
e01402b1 1614 list_for_each_entry_safe(v, n, &vpecontrol.vpe_list, list) {
1bbfc20d 1615 if (v->state != VPE_STATE_UNUSED)
e01402b1 1616 release_vpe(v);
e01402b1 1617 }
e01402b1
RB
1618}
1619
1620module_init(vpe_module_init);
1621module_exit(vpe_module_exit);
1622MODULE_DESCRIPTION("MIPS VPE Loader");
2600990e 1623MODULE_AUTHOR("Elizabeth Oldham, MIPS Technologies, Inc.");
e01402b1 1624MODULE_LICENSE("GPL");