• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/arch/mips/kernel/
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.
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.
29 */
30#include <linux/kernel.h>
31#include <linux/device.h>
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>
47#include <asm/mipsmtregs.h>
48#include <asm/cacheflush.h>
49#include <asm/atomic.h>
50#include <asm/cpu.h>
51#include <asm/mips_mt.h>
52#include <asm/processor.h>
53#include <asm/system.h>
54#include <asm/vpe.h>
55#include <asm/kspd.h>
56
57typedef void *vpe_handle;
58
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
66/*
67 * The number of TCs and VPEs physically available on the core
68 */
69static int hw_tcs, hw_vpes;
70static char module_name[] = "vpe";
71static int major;
72static const int minor = 1;	/* fixed for now  */
73
74#ifdef CONFIG_MIPS_APSP_KSPD
75static struct kspd_notifications kspd_events;
76static int kspd_events_reqd;
77#endif
78/*
79 * Size of private kernel buffer for ELF headers and sections
80 */
81#define P_SIZE (256 * 1024)
82
83/*
84 * Size of private kernel buffer for ELF headers and sections
85 */
86#define MAX_VPES 16
87#define VPE_PATH_MAX 256
88
89enum vpe_state {
90	VPE_STATE_UNUSED = 0,
91	VPE_STATE_INUSE,
92	VPE_STATE_RUNNING
93};
94
95enum tc_state {
96	TC_STATE_UNUSED = 0,
97	TC_STATE_INUSE,
98	TC_STATE_RUNNING,
99	TC_STATE_DYNAMIC
100};
101
102enum load_state {
103	LOAD_STATE_EHDR,
104	LOAD_STATE_PHDR,
105	LOAD_STATE_SHDR,
106	LOAD_STATE_PIMAGE,
107	LOAD_STATE_TRAILER,
108	LOAD_STATE_DONE,
109	LOAD_STATE_ERROR
110};
111
112struct vpe {
113	enum vpe_state state;
114
115	/* (device) minor associated with this vpe */
116	int minor;
117
118	/* elfloader stuff */
119	unsigned long offset; /* File offset into input stream */
120	void *load_addr;
121	unsigned long copied;
122	char *pbuffer;
123	unsigned long pbsize;
124	/* Program loading state */
125	enum load_state l_state;
126	Elf_Ehdr *l_ehdr;
127	struct elf_phdr *l_phdr;
128	unsigned int l_phlen;
129	Elf_Shdr *l_shdr;
130	unsigned int l_shlen;
131	int *l_phsort;  /* Sorted index list of program headers */
132	int l_segoff;   /* Offset into current program segment */
133	int l_cur_seg;  /* Indirect index of segment currently being loaded */
134	unsigned int l_progminad;
135	unsigned int l_progmaxad;
136	unsigned int l_trailer;
137
138	unsigned int uid, gid;
139	char cwd[VPE_PATH_MAX];
140
141	unsigned long __start;
142
143	/* tc's associated with this vpe */
144	struct list_head tc;
145
146	/* The list of vpe's */
147	struct list_head list;
148
149	/* legacy shared symbol address */
150	void *shared_ptr;
151
152	 /* shared area descriptor array address */
153	struct vpe_shared_area *shared_areas;
154
155	/* the list of who wants to know when something major happens */
156	struct list_head notify;
157
158	unsigned int ntcs;
159};
160
161struct tc {
162	enum tc_state state;
163	int index;
164
165	struct vpe *pvpe;	/* parent VPE */
166	struct list_head tc;	/* The list of TC's with this VPE */
167	struct list_head list;	/* The global list of tc's */
168};
169
170struct {
171	spinlock_t vpe_list_lock;
172	struct list_head vpe_list;	/* Virtual processing elements */
173	spinlock_t tc_list_lock;
174	struct list_head tc_list;	/* Thread contexts */
175} vpecontrol = {
176	.vpe_list_lock	= SPIN_LOCK_UNLOCKED,
177	.vpe_list	= LIST_HEAD_INIT(vpecontrol.vpe_list),
178	.tc_list_lock	= SPIN_LOCK_UNLOCKED,
179	.tc_list	= LIST_HEAD_INIT(vpecontrol.tc_list)
180};
181
182static void release_progmem(void *ptr);
183/*
184 * Values and state associated with publishing shared memory areas
185 */
186
187#define N_PUB_AREAS 4
188
189static struct vpe_shared_area published_vpe_area[N_PUB_AREAS] = {
190	{VPE_SHARED_RESERVED, 0},
191	{VPE_SHARED_RESERVED, 0},
192	{VPE_SHARED_RESERVED, 0},
193	{VPE_SHARED_RESERVED, 0} };
194
195/* get the vpe associated with this minor */
196static struct vpe *get_vpe(int minor)
197{
198	struct vpe *res, *v;
199
200	if (!cpu_has_mipsmt)
201		return NULL;
202
203	res = NULL;
204	spin_lock(&vpecontrol.vpe_list_lock);
205	list_for_each_entry(v, &vpecontrol.vpe_list, list) {
206		if (v->minor == minor) {
207			res = v;
208			break;
209		}
210	}
211	spin_unlock(&vpecontrol.vpe_list_lock);
212
213	return res;
214}
215
216/* get the tc associated with this minor */
217static struct tc *get_tc(int index)
218{
219	struct tc *res, *t;
220
221	res = NULL;
222	spin_lock(&vpecontrol.tc_list_lock);
223	list_for_each_entry(t, &vpecontrol.tc_list, list) {
224		if (t->index == index) {
225			res = t;
226			break;
227		}
228	}
229	spin_unlock(&vpecontrol.tc_list_lock);
230
231	return res;
232}
233
234
235/* allocate a vpe and associate it with this minor (or index) */
236static struct vpe *alloc_vpe(int minor)
237{
238	struct vpe *v;
239
240	if ((v = kzalloc(sizeof(struct vpe), GFP_KERNEL)) == NULL)
241		return NULL;
242	printk(KERN_DEBUG "Used kzalloc to allocate %d bytes at %x\n",
243		sizeof(struct vpe), (unsigned int)v);
244	INIT_LIST_HEAD(&v->tc);
245	spin_lock(&vpecontrol.vpe_list_lock);
246	list_add_tail(&v->list, &vpecontrol.vpe_list);
247	spin_unlock(&vpecontrol.vpe_list_lock);
248
249	INIT_LIST_HEAD(&v->notify);
250	v->minor = minor;
251
252	return v;
253}
254
255/* allocate a tc. At startup only tc0 is running, all other can be halted. */
256static struct tc *alloc_tc(int index)
257{
258	struct tc *tc;
259
260	if ((tc = kzalloc(sizeof(struct tc), GFP_KERNEL)) == NULL)
261		goto out;
262	printk(KERN_DEBUG "Used kzalloc to allocate %d bytes at %x\n",
263		sizeof(struct tc), (unsigned int)tc);
264	INIT_LIST_HEAD(&tc->tc);
265	tc->index = index;
266
267	spin_lock(&vpecontrol.tc_list_lock);
268	list_add_tail(&tc->list, &vpecontrol.tc_list);
269	spin_unlock(&vpecontrol.tc_list_lock);
270
271out:
272	return tc;
273}
274
275/* clean up and free everything */
276static void release_vpe(struct vpe *v)
277{
278	list_del(&v->list);
279	if (v->load_addr)
280		release_progmem(v);
281	printk(KERN_DEBUG "Used kfree to free memory at %x\n",
282		(unsigned int)v->l_phsort);
283	kfree(v->l_phsort);
284	printk(KERN_DEBUG "Used kfree to free memory at %x\n",
285		(unsigned int)v);
286	kfree(v);
287}
288
289static void __maybe_unused dump_mtregs(void)
290{
291	unsigned long val;
292
293	val = read_c0_config3();
294	printk("config3 0x%lx MT %ld\n", val,
295	       (val & CONFIG3_MT) >> CONFIG3_MT_SHIFT);
296
297	val = read_c0_mvpcontrol();
298	printk("MVPControl 0x%lx, STLB %ld VPC %ld EVP %ld\n", val,
299	       (val & MVPCONTROL_STLB) >> MVPCONTROL_STLB_SHIFT,
300	       (val & MVPCONTROL_VPC) >> MVPCONTROL_VPC_SHIFT,
301	       (val & MVPCONTROL_EVP));
302
303	val = read_c0_mvpconf0();
304	printk("mvpconf0 0x%lx, PVPE %ld PTC %ld M %ld\n", val,
305	       (val & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT,
306	       val & MVPCONF0_PTC, (val & MVPCONF0_M) >> MVPCONF0_M_SHIFT);
307}
308
309/*
310 * The original APRP prototype assumed a single, unshared IRQ for
311 * cross-VPE interrupts, used by the RTLX code.  But M3P networking
312 * and other future functions may need to share an IRQ, particularly
313 * in 34K/Malta configurations without an external interrupt controller.
314 * All cross-VPE insterrupt users need to coordinate through shared
315 * functions here.
316 */
317
318/*
319 * It would be nice if I could just have this initialized to zero,
320 * but the patchcheck police won't hear of it...
321 */
322
323static int xvpe_vector_set;
324
325#define XVPE_INTR_OFFSET 0
326
327static int xvpe_irq = MIPS_CPU_IRQ_BASE + XVPE_INTR_OFFSET;
328
329static void xvpe_dispatch(void)
330{
331	do_IRQ(xvpe_irq);
332}
333
334/* Name here is generic, as m3pnet.c could in principle be used by non-MIPS */
335int arch_get_xcpu_irq()
336{
337	/*
338	 * Some of this will ultimately become platform code,
339	 * but for now, we're only targeting 34K/FPGA/Malta,
340	 * and there's only one generic mechanism.
341	 */
342	if (!xvpe_vector_set) {
343		/*
344		 * A more elaborate shared variable shouldn't be needed.
345		 * Two initializations back-to-back should be harmless.
346		 */
347		if (cpu_has_vint) {
348			set_vi_handler(XVPE_INTR_OFFSET, xvpe_dispatch);
349			xvpe_vector_set = 1;
350		} else {
351			printk(KERN_ERR "APRP requires vectored interrupts\n");
352			return -1;
353		}
354	}
355
356	return xvpe_irq;
357}
358EXPORT_SYMBOL(arch_get_xcpu_irq);
359
360int vpe_send_interrupt(int vpe, int inter)
361{
362	unsigned long flags;
363	unsigned int vpeflags;
364
365	local_irq_save(flags);
366	vpeflags = dvpe();
367
368	/*
369	 * Initial version makes same simple-minded assumption
370	 * as is implicit elsewhere in this module, that the
371	 * only RP of interest is using the first non-Linux TC.
372	 * We ignore the parameters provided by the caller!
373	 */
374	settc(tclimit);
375	/*
376	 * In 34K/Malta, the only cross-VPE interrupts possible
377	 * are done by setting SWINT bits in Cause, of which there
378	 * are two.  SMTC uses SW1 for a multiplexed class of IPIs,
379	 * and this mechanism should be generalized to APRP and use
380	 * the same protocol.  Until that's implemented, send only
381	 * SW0 here, regardless of requested type.
382	 */
383	write_vpe_c0_cause(read_vpe_c0_cause() | C_SW0);
384	evpe(vpeflags);
385	local_irq_restore(flags);
386	return 1;
387}
388EXPORT_SYMBOL(vpe_send_interrupt);
389/* Find some VPE program space  */
390static void *alloc_progmem(void *requested, unsigned long len)
391{
392	void *addr;
393
394#ifdef CONFIG_MIPS_VPE_LOADER_TOM
395	/*
396	 * This means you must tell Linux to use less memory than you
397	 * physically have, for example by passing a mem= boot argument.
398	 */
399	addr = pfn_to_kaddr(max_low_pfn);
400	if (requested != 0) {
401		if (requested >= addr)
402			addr = requested;
403		else
404			addr = 0;
405	}
406	if (addr != 0)
407		memset(addr, 0, len);
408	printk(KERN_DEBUG "pfn_to_kaddr returns %lu bytes of memory at %x\n",
409	       len, (unsigned int)addr);
410#else
411	if (requested != 0) {
412		/* If we have a target in mind, grab a 2x slice and hope... */
413		addr = kzalloc(len*2, GFP_KERNEL);
414		if ((requested >= addr) && (requested < (addr + len)))
415			addr = requested;
416		else
417			addr = 0;
418	} else {
419		/* simply grab some mem for now */
420		addr = kzalloc(len, GFP_KERNEL);
421	}
422#endif
423
424	return addr;
425}
426
427static void release_progmem(void *ptr)
428{
429#ifndef CONFIG_MIPS_VPE_LOADER_TOM
430	kfree(ptr);
431#endif
432}
433
434/* Update size with this section: return offset. */
435static long get_offset(unsigned long *size, Elf_Shdr * sechdr)
436{
437	long ret;
438
439	ret = ALIGN(*size, sechdr->sh_addralign ? : 1);
440	*size = ret + sechdr->sh_size;
441	return ret;
442}
443
444/* Lay out the SHF_ALLOC sections in a way not dissimilar to how ld
445   might -- code, read-only data, read-write data, small data.  Tally
446   sizes, and place the offsets into sh_entsize fields: high bit means it
447   belongs in init. */
448static void layout_sections(struct module *mod, const Elf_Ehdr * hdr,
449			    Elf_Shdr * sechdrs, const char *secstrings)
450{
451	static unsigned long const masks[][2] = {
452		/* NOTE: all executable code must be the first section
453		 * in this array; otherwise modify the text_size
454		 * finder in the two loops below */
455		{SHF_EXECINSTR | SHF_ALLOC, ARCH_SHF_SMALL},
456		{SHF_ALLOC, SHF_WRITE | ARCH_SHF_SMALL},
457		{SHF_WRITE | SHF_ALLOC, ARCH_SHF_SMALL},
458		{ARCH_SHF_SMALL | SHF_ALLOC, 0}
459	};
460	unsigned int m, i;
461
462	for (i = 0; i < hdr->e_shnum; i++)
463		sechdrs[i].sh_entsize = ~0UL;
464
465	for (m = 0; m < ARRAY_SIZE(masks); ++m) {
466		for (i = 0; i < hdr->e_shnum; ++i) {
467			Elf_Shdr *s = &sechdrs[i];
468
469			//  || strncmp(secstrings + s->sh_name, ".init", 5) == 0)
470			if ((s->sh_flags & masks[m][0]) != masks[m][0]
471			    || (s->sh_flags & masks[m][1])
472			    || s->sh_entsize != ~0UL)
473				continue;
474			s->sh_entsize =
475				get_offset((unsigned long *)&mod->core_size, s);
476		}
477
478		if (m == 0)
479			mod->core_text_size = mod->core_size;
480
481	}
482}
483
484
485/* from module-elf32.c, but subverted a little */
486
487struct mips_hi16 {
488	struct mips_hi16 *next;
489	Elf32_Addr *addr;
490	Elf32_Addr value;
491};
492
493static struct mips_hi16 *mips_hi16_list;
494static unsigned int gp_offs, gp_addr;
495
496static int apply_r_mips_none(struct module *me, uint32_t *location,
497			     Elf32_Addr v)
498{
499	return 0;
500}
501
502static int apply_r_mips_gprel16(struct module *me, uint32_t *location,
503				Elf32_Addr v)
504{
505	int rel;
506
507	if( !(*location & 0xffff) ) {
508		rel = (int)v - gp_addr;
509	}
510	else {
511		/* .sbss + gp(relative) + offset */
512		/* kludge! */
513		rel =  (int)(short)((int)v + gp_offs +
514				    (int)(short)(*location & 0xffff) - gp_addr);
515	}
516
517	if( (rel > 32768) || (rel < -32768) ) {
518		printk(KERN_DEBUG "VPE loader: apply_r_mips_gprel16: "
519		       "relative address 0x%x out of range of gp register\n",
520		       rel);
521		return -ENOEXEC;
522	}
523
524	*location = (*location & 0xffff0000) | (rel & 0xffff);
525
526	return 0;
527}
528
529static int apply_r_mips_pc16(struct module *me, uint32_t *location,
530			     Elf32_Addr v)
531{
532	int rel;
533	rel = (((unsigned int)v - (unsigned int)location));
534	rel >>= 2;		// because the offset is in _instructions_ not bytes.
535	rel -= 1;		// and one instruction less due to the branch delay slot.
536
537	if( (rel > 32768) || (rel < -32768) ) {
538		printk(KERN_DEBUG "VPE loader: "
539 		       "apply_r_mips_pc16: relative address out of range 0x%x\n", rel);
540		return -ENOEXEC;
541	}
542
543	*location = (*location & 0xffff0000) | (rel & 0xffff);
544
545	return 0;
546}
547
548static int apply_r_mips_32(struct module *me, uint32_t *location,
549			   Elf32_Addr v)
550{
551	*location += v;
552
553	return 0;
554}
555
556static int apply_r_mips_26(struct module *me, uint32_t *location,
557			   Elf32_Addr v)
558{
559	if (v % 4) {
560		printk(KERN_DEBUG "VPE loader: apply_r_mips_26 "
561		       " unaligned relocation\n");
562		return -ENOEXEC;
563	}
564
565/*
566 * Not desperately convinced this is a good check of an overflow condition
567 * anyway. But it gets in the way of handling undefined weak symbols which
568 * we want to set to zero.
569 * if ((v & 0xf0000000) != (((unsigned long)location + 4) & 0xf0000000)) {
570 * printk(KERN_ERR
571 * "module %s: relocation overflow\n",
572 * me->name);
573 * return -ENOEXEC;
574 * }
575 */
576
577	*location = (*location & ~0x03ffffff) |
578		((*location + (v >> 2)) & 0x03ffffff);
579	return 0;
580}
581
582static int apply_r_mips_hi16(struct module *me, uint32_t *location,
583			     Elf32_Addr v)
584{
585	struct mips_hi16 *n;
586
587	/*
588	 * We cannot relocate this one now because we don't know the value of
589	 * the carry we need to add.  Save the information, and let LO16 do the
590	 * actual relocation.
591	 */
592	n = kmalloc(sizeof *n, GFP_KERNEL);
593	printk(KERN_DEBUG "Used kmalloc to allocate %d bytes at %x\n",
594	       sizeof(struct mips_hi16), (unsigned int)n);
595	if (!n)
596		return -ENOMEM;
597
598	n->addr = location;
599	n->value = v;
600	n->next = mips_hi16_list;
601	mips_hi16_list = n;
602
603	return 0;
604}
605
606static int apply_r_mips_lo16(struct module *me, uint32_t *location,
607			     Elf32_Addr v)
608{
609	unsigned long insnlo = *location;
610	Elf32_Addr val, vallo;
611	struct mips_hi16 *l, *next;
612
613	/* Sign extend the addend we extract from the lo insn.  */
614	vallo = ((insnlo & 0xffff) ^ 0x8000) - 0x8000;
615
616	if (mips_hi16_list != NULL) {
617
618		l = mips_hi16_list;
619		while (l != NULL) {
620			unsigned long insn;
621
622			/*
623			 * The value for the HI16 had best be the same.
624			 */
625 			if (v != l->value) {
626				printk(KERN_DEBUG "VPE loader: "
627				       "apply_r_mips_lo16/hi16: \t"
628				       "inconsistent value information\n");
629				goto out_free;
630			}
631
632			/*
633			 * Do the HI16 relocation.  Note that we actually don't
634			 * need to know anything about the LO16 itself, except
635			 * where to find the low 16 bits of the addend needed
636			 * by the LO16.
637			 */
638			insn = *l->addr;
639			val = ((insn & 0xffff) << 16) + vallo;
640			val += v;
641
642			/*
643			 * Account for the sign extension that will happen in
644			 * the low bits.
645			 */
646			val = ((val >> 16) + ((val & 0x8000) != 0)) & 0xffff;
647
648			insn = (insn & ~0xffff) | val;
649			*l->addr = insn;
650
651			next = l->next;
652			printk(KERN_DEBUG "Used kfree to free memory at %x\n",
653			       (unsigned int)l);
654			kfree(l);
655			l = next;
656		}
657
658		mips_hi16_list = NULL;
659	}
660
661	/*
662	 * Ok, we're done with the HI16 relocs.  Now deal with the LO16.
663	 */
664	val = v + vallo;
665	insnlo = (insnlo & ~0xffff) | (val & 0xffff);
666	*location = insnlo;
667
668	return 0;
669
670out_free:
671	while (l != NULL) {
672		next = l->next;
673		kfree(l);
674		l = next;
675	}
676	mips_hi16_list = NULL;
677
678	return -ENOEXEC;
679}
680
681static int (*reloc_handlers[]) (struct module *me, uint32_t *location,
682				Elf32_Addr v) = {
683	[R_MIPS_NONE]	= apply_r_mips_none,
684	[R_MIPS_32]	= apply_r_mips_32,
685	[R_MIPS_26]	= apply_r_mips_26,
686	[R_MIPS_HI16]	= apply_r_mips_hi16,
687	[R_MIPS_LO16]	= apply_r_mips_lo16,
688	[R_MIPS_GPREL16] = apply_r_mips_gprel16,
689	[R_MIPS_PC16] = apply_r_mips_pc16
690};
691
692static char *rstrs[] = {
693	[R_MIPS_NONE]	= "MIPS_NONE",
694	[R_MIPS_32]	= "MIPS_32",
695	[R_MIPS_26]	= "MIPS_26",
696	[R_MIPS_HI16]	= "MIPS_HI16",
697	[R_MIPS_LO16]	= "MIPS_LO16",
698	[R_MIPS_GPREL16] = "MIPS_GPREL16",
699	[R_MIPS_PC16] = "MIPS_PC16"
700};
701
702static int apply_relocations(Elf32_Shdr *sechdrs,
703		      const char *strtab,
704		      unsigned int symindex,
705		      unsigned int relsec,
706		      struct module *me)
707{
708	Elf32_Rel *rel = (void *) sechdrs[relsec].sh_addr;
709	Elf32_Sym *sym;
710	uint32_t *location;
711	unsigned int i;
712	Elf32_Addr v;
713	int res;
714
715	for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
716		Elf32_Word r_info = rel[i].r_info;
717
718		/* This is where to make the change */
719		location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
720			+ rel[i].r_offset;
721		/* This is the symbol it is referring to */
722		sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
723			+ ELF32_R_SYM(r_info);
724
725		if (!sym->st_value) {
726			printk(KERN_DEBUG "%s: undefined weak symbol %s\n",
727			       me->name, strtab + sym->st_name);
728			/* just print the warning, dont barf */
729		}
730
731		v = sym->st_value;
732
733		res = reloc_handlers[ELF32_R_TYPE(r_info)](me, location, v);
734		if( res ) {
735			char *r = rstrs[ELF32_R_TYPE(r_info)];
736		    	printk(KERN_WARNING "VPE loader: .text+0x%x "
737			       "relocation type %s for symbol \"%s\" failed\n",
738			       rel[i].r_offset, r ? r : "UNKNOWN",
739			       strtab + sym->st_name);
740			return res;
741		}
742	}
743
744	return 0;
745}
746
747void save_gp_address(unsigned int secbase, unsigned int rel)
748{
749	gp_addr = secbase + rel;
750	gp_offs = gp_addr - (secbase & 0xffff0000);
751}
752/* end module-elf32.c */
753
754
755
756/* Change all symbols so that sh_value encodes the pointer directly. */
757static void simplify_symbols(Elf_Shdr * sechdrs,
758			    unsigned int symindex,
759			    const char *strtab,
760			    const char *secstrings,
761			    unsigned int nsecs, struct module *mod)
762{
763	Elf_Sym *sym = (void *)sechdrs[symindex].sh_addr;
764	unsigned long secbase, bssbase = 0;
765	unsigned int i, n = sechdrs[symindex].sh_size / sizeof(Elf_Sym);
766	int size;
767
768	/* find the .bss section for COMMON symbols */
769	for (i = 0; i < nsecs; i++) {
770		if (strncmp(secstrings + sechdrs[i].sh_name, ".bss", 4) == 0) {
771			bssbase = sechdrs[i].sh_addr;
772			break;
773		}
774	}
775
776	for (i = 1; i < n; i++) {
777		switch (sym[i].st_shndx) {
778		case SHN_COMMON:
779			/* Allocate space for the symbol in the .bss section.
780			   st_value is currently size.
781			   We want it to have the address of the symbol. */
782
783			size = sym[i].st_value;
784			sym[i].st_value = bssbase;
785
786			bssbase += size;
787			break;
788
789		case SHN_ABS:
790			/* Don't need to do anything */
791			break;
792
793		case SHN_UNDEF:
794			/* ret = -ENOENT; */
795			break;
796
797		case SHN_MIPS_SCOMMON:
798			printk(KERN_DEBUG "simplify_symbols: ignoring SHN_MIPS_SCOMMON "
799			       "symbol <%s> st_shndx %d\n", strtab + sym[i].st_name,
800			       sym[i].st_shndx);
801			// .sbss section
802			break;
803
804		default:
805			secbase = sechdrs[sym[i].st_shndx].sh_addr;
806
807			if (strncmp(strtab + sym[i].st_name, "_gp", 3) == 0) {
808				save_gp_address(secbase, sym[i].st_value);
809			}
810
811			sym[i].st_value += secbase;
812			break;
813		}
814	}
815}
816
817#ifdef DEBUG_ELFLOADER
818static void dump_elfsymbols(Elf_Shdr * sechdrs, unsigned int symindex,
819			    const char *strtab, struct module *mod)
820{
821	Elf_Sym *sym = (void *)sechdrs[symindex].sh_addr;
822	unsigned int i, n = sechdrs[symindex].sh_size / sizeof(Elf_Sym);
823
824	printk(KERN_DEBUG "dump_elfsymbols: n %d\n", n);
825	for (i = 1; i < n; i++) {
826		printk(KERN_DEBUG " i %d name <%s> 0x%x\n", i,
827		       strtab + sym[i].st_name, sym[i].st_value);
828	}
829}
830#endif
831
832/* We are prepared so configure and start the VPE... */
833static int vpe_run(struct vpe * v)
834{
835	unsigned long flags, val, dmt_flag;
836	struct vpe_notifications *n;
837	unsigned int vpeflags;
838	struct tc *t;
839
840	/* check we are the Master VPE */
841	local_irq_save(flags);
842	val = read_c0_vpeconf0();
843	if (!(val & VPECONF0_MVP)) {
844		printk(KERN_WARNING
845		       "VPE loader: only Master VPE's are allowed to configure MT\n");
846		local_irq_restore(flags);
847
848		return -1;
849	}
850
851	dmt_flag = dmt();
852	vpeflags = dvpe();
853
854	if (!list_empty(&v->tc)) {
855		if ((t = list_entry(v->tc.next, struct tc, tc)) == NULL) {
856			evpe(vpeflags);
857			emt(dmt_flag);
858			local_irq_restore(flags);
859
860			printk(KERN_WARNING
861			       "VPE loader: TC %d is already in use.\n",
862                               t->index);
863			return -ENOEXEC;
864		}
865	} else {
866		evpe(vpeflags);
867		emt(dmt_flag);
868		local_irq_restore(flags);
869
870		printk(KERN_WARNING
871		       "VPE loader: No TC's associated with VPE %d\n",
872		       v->minor);
873
874		return -ENOEXEC;
875	}
876
877	/* Put MVPE's into 'configuration state' */
878	set_c0_mvpcontrol(MVPCONTROL_VPC);
879
880	settc(t->index);
881
882	/* should check it is halted, and not activated */
883	if ((read_tc_c0_tcstatus() & TCSTATUS_A) || !(read_tc_c0_tchalt() & TCHALT_H)) {
884		evpe(vpeflags);
885		emt(dmt_flag);
886		local_irq_restore(flags);
887
888		printk(KERN_WARNING "VPE loader: TC %d is already active!\n",
889		       t->index);
890
891		return -ENOEXEC;
892	}
893
894	/* Write the address we want it to start running from in the TCPC register. */
895	write_tc_c0_tcrestart((unsigned long)v->__start);
896	write_tc_c0_tccontext((unsigned long)0);
897
898	/*
899	 * Mark the TC as activated, not interrupt exempt and not dynamically
900	 * allocatable
901	 */
902	val = read_tc_c0_tcstatus();
903	val = (val & ~(TCSTATUS_DA | TCSTATUS_IXMT)) | TCSTATUS_A;
904	write_tc_c0_tcstatus(val);
905
906	write_tc_c0_tchalt(read_tc_c0_tchalt() & ~TCHALT_H);
907
908	/*
909	 * The sde-kit passes 'memsize' to __start in $a3, so set something
910	 * here...  Or set $a3 to zero and define DFLT_STACK_SIZE and
911	 * DFLT_HEAP_SIZE when you compile your program
912	 */
913	mttgpr(6, v->ntcs);
914	mttgpr(7, physical_memsize);
915
916	/* set up VPE1 */
917	/*
918	 * bind the TC to VPE 1 as late as possible so we only have the final
919	 * VPE registers to set up, and so an EJTAG probe can trigger on it
920	 */
921	write_tc_c0_tcbind((read_tc_c0_tcbind() & ~TCBIND_CURVPE) | 1);
922
923	write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() & ~(VPECONF0_VPA));
924
925	back_to_back_c0_hazard();
926
927	/* Set up the XTC bit in vpeconf0 to point at our tc */
928	write_vpe_c0_vpeconf0( (read_vpe_c0_vpeconf0() & ~(VPECONF0_XTC))
929	                      | (t->index << VPECONF0_XTC_SHIFT));
930
931	back_to_back_c0_hazard();
932
933	/* enable this VPE */
934	write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() | VPECONF0_VPA);
935
936	/* clear out any left overs from a previous program */
937	write_vpe_c0_status(0);
938	write_vpe_c0_cause(0);
939
940	/* take system out of configuration state */
941	clear_c0_mvpcontrol(MVPCONTROL_VPC);
942
943	/*
944	 * SMTC/SMVP kernels manage VPE enable independently,
945	 * but uniprocessor kernels need to turn it on, even
946	 * if that wasn't the pre-dvpe() state.
947	 */
948#ifdef CONFIG_SMP
949	evpe(vpeflags);
950#else
951	evpe(EVPE_ENABLE);
952#endif
953	emt(dmt_flag);
954	local_irq_restore(flags);
955
956	list_for_each_entry(n, &v->notify, list)
957		n->start(minor);
958
959	return 0;
960}
961
962static int find_vpe_symbols(struct vpe * v, Elf_Shdr * sechdrs,
963				      unsigned int symindex, const char *strtab,
964				      struct module *mod)
965{
966	Elf_Sym *sym = (void *)sechdrs[symindex].sh_addr;
967	unsigned int i, j, n = sechdrs[symindex].sh_size / sizeof(Elf_Sym);
968
969	for (i = 1; i < n; i++) {
970	    if (strcmp(strtab + sym[i].st_name, "__start") == 0)
971		v->__start = sym[i].st_value;
972
973	    if (strcmp(strtab + sym[i].st_name, "vpe_shared") == 0)
974		v->shared_ptr = (void *)sym[i].st_value;
975
976	    if (strcmp(strtab + sym[i].st_name, "_vpe_shared_areas") == 0) {
977		struct vpe_shared_area *psa
978		    = (struct vpe_shared_area *)sym[i].st_value;
979		struct vpe_shared_area *tpsa;
980		v->shared_areas = psa;
981		printk(KERN_INFO"_vpe_shared_areas found, 0x%x\n",
982		    (unsigned int)v->shared_areas);
983		/*
984		 * Copy any "published" areas to the descriptor
985		 */
986		for (j = 0; j < N_PUB_AREAS; j++) {
987		    if (published_vpe_area[j].type != VPE_SHARED_RESERVED) {
988			tpsa = psa;
989			while (tpsa->type != VPE_SHARED_NULL) {
990			    if ((tpsa->type == VPE_SHARED_RESERVED)
991			    || (tpsa->type == published_vpe_area[j].type)) {
992				tpsa->type = published_vpe_area[j].type;
993				tpsa->addr = published_vpe_area[j].addr;
994				break;
995			    }
996			    tpsa++;
997			}
998		    }
999		}
1000	    }
1001
1002	}
1003
1004	if ( (v->__start == 0) || (v->shared_ptr == NULL))
1005		return -1;
1006
1007	return 0;
1008}
1009
1010/*
1011 * Allocates a VPE with some program code space(the load address), copies the
1012 * contents of the program (p)buffer performing relocatations/etc, free's it
1013 * when finished.
1014 */
1015static int vpe_elfload(struct vpe * v)
1016{
1017	Elf_Ehdr *hdr;
1018	Elf_Shdr *sechdrs;
1019	long err = 0;
1020	char *secstrings, *strtab = NULL;
1021	unsigned int len, i, symindex = 0, strindex = 0, relocate = 0;
1022	struct module mod;	// so we can re-use the relocations code
1023
1024	memset(&mod, 0, sizeof(struct module));
1025	strcpy(mod.name, "VPE loader");
1026	hdr = v->l_ehdr;
1027	len = v->pbsize;
1028
1029	/* Sanity checks against insmoding binaries or wrong arch,
1030	   weird elf version */
1031	if ((hdr->e_type != ET_REL && hdr->e_type != ET_EXEC)
1032	    || !elf_check_arch(hdr)
1033	    || hdr->e_shentsize != sizeof(*sechdrs)) {
1034		printk(KERN_WARNING
1035		       "VPE loader: program wrong arch or weird elf version\n");
1036
1037		return -ENOEXEC;
1038	}
1039
1040	if (hdr->e_type == ET_REL)
1041		relocate = 1;
1042
1043	if (len < v->l_phlen + v->l_shlen) {
1044		printk(KERN_ERR "VPE loader: Headers exceed %u bytes\n", len);
1045
1046		return -ENOEXEC;
1047	}
1048
1049	/* Convenience variables */
1050	sechdrs = (void *)hdr + hdr->e_shoff;
1051	secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
1052	sechdrs[0].sh_addr = 0;
1053
1054	/* And these should exist, but gcc whinges if we don't init them */
1055	symindex = strindex = 0;
1056
1057	if (relocate) {
1058		for (i = 1; i < hdr->e_shnum; i++) {
1059			if (sechdrs[i].sh_type != SHT_NOBITS
1060			    && len < sechdrs[i].sh_offset + sechdrs[i].sh_size) {
1061				printk(KERN_ERR "VPE program length %u truncated\n",
1062				       len);
1063				return -ENOEXEC;
1064			}
1065
1066			/* Mark all sections sh_addr with their address in the
1067			   temporary image. */
1068			sechdrs[i].sh_addr = (size_t) hdr + sechdrs[i].sh_offset;
1069
1070			/* Internal symbols and strings. */
1071			if (sechdrs[i].sh_type == SHT_SYMTAB) {
1072				symindex = i;
1073				strindex = sechdrs[i].sh_link;
1074				strtab = (char *)hdr + sechdrs[strindex].sh_offset;
1075			}
1076		}
1077		layout_sections(&mod, hdr, sechdrs, secstrings);
1078		/*
1079		 * Non-relocatable loads should have already done their
1080		 * allocates, based on program header table.
1081		 */
1082	}
1083
1084	memset(v->load_addr, 0, mod.core_size);
1085	if (!v->load_addr)
1086		return -ENOMEM;
1087
1088	pr_info("VPE loader: loading to %p\n", v->load_addr);
1089
1090	if (relocate) {
1091		for (i = 0; i < hdr->e_shnum; i++) {
1092			void *dest;
1093
1094			if (!(sechdrs[i].sh_flags & SHF_ALLOC))
1095				continue;
1096
1097			dest = v->load_addr + sechdrs[i].sh_entsize;
1098
1099			if (sechdrs[i].sh_type != SHT_NOBITS)
1100				memcpy(dest, (void *)sechdrs[i].sh_addr,
1101				       sechdrs[i].sh_size);
1102			/* Update sh_addr to point to copy in image. */
1103			sechdrs[i].sh_addr = (unsigned long)dest;
1104
1105			printk(KERN_DEBUG " section sh_name %s sh_addr 0x%x\n",
1106			       secstrings + sechdrs[i].sh_name, sechdrs[i].sh_addr);
1107		}
1108
1109 		/* Fix up syms, so that st_value is a pointer to location. */
1110 		simplify_symbols(sechdrs, symindex, strtab, secstrings,
1111 				 hdr->e_shnum, &mod);
1112
1113 		/* Now do relocations. */
1114 		for (i = 1; i < hdr->e_shnum; i++) {
1115 			const char *strtab = (char *)sechdrs[strindex].sh_addr;
1116 			unsigned int info = sechdrs[i].sh_info;
1117
1118 			/* Not a valid relocation section? */
1119 			if (info >= hdr->e_shnum)
1120 				continue;
1121
1122 			/* Don't bother with non-allocated sections */
1123 			if (!(sechdrs[info].sh_flags & SHF_ALLOC))
1124 				continue;
1125
1126 			if (sechdrs[i].sh_type == SHT_REL)
1127 				err = apply_relocations(sechdrs, strtab, symindex, i,
1128 							&mod);
1129 			else if (sechdrs[i].sh_type == SHT_RELA)
1130 				err = apply_relocate_add(sechdrs, strtab, symindex, i,
1131 							 &mod);
1132 			if (err < 0)
1133 				return err;
1134
1135  		}
1136  	} else {
1137
1138		/*
1139		 * Program image is already in memory.
1140		 */
1141		for (i = 0; i < hdr->e_shnum; i++) {
1142 			/* Internal symbols and strings. */
1143 			if (sechdrs[i].sh_type == SHT_SYMTAB) {
1144 				symindex = i;
1145 				strindex = sechdrs[i].sh_link;
1146 				strtab = (char *)hdr + sechdrs[strindex].sh_offset;
1147
1148 				/* mark the symtab's address for when we try to find the
1149 				   magic symbols */
1150 				sechdrs[i].sh_addr = (size_t) hdr + sechdrs[i].sh_offset;
1151 			}
1152		}
1153	}
1154
1155	/* make sure it's physically written out */
1156	flush_icache_range((unsigned long)v->load_addr,
1157			   (unsigned long)v->load_addr + v->copied);
1158
1159	if ((find_vpe_symbols(v, sechdrs, symindex, strtab, &mod)) < 0) {
1160		if (v->__start == 0) {
1161			printk(KERN_WARNING "VPE loader: program does not contain "
1162			       "a __start symbol\n");
1163			return -ENOEXEC;
1164		}
1165
1166		if (v->shared_ptr == NULL)
1167			printk(KERN_WARNING "VPE loader: "
1168			       "program does not contain vpe_shared symbol.\n"
1169			       " Unable to use AMVP (AP/SP) facilities.\n");
1170	}
1171	pr_info("APRP VPE loader: elf loaded\n");
1172
1173	return 0;
1174}
1175
1176static void cleanup_tc(struct tc *tc)
1177{
1178	unsigned long flags;
1179	unsigned int mtflags, vpflags;
1180	int tmp;
1181
1182	local_irq_save(flags);
1183	mtflags = dmt();
1184	vpflags = dvpe();
1185	/* Put MVPE's into 'configuration state' */
1186	set_c0_mvpcontrol(MVPCONTROL_VPC);
1187
1188	settc(tc->index);
1189	tmp = read_tc_c0_tcstatus();
1190
1191	/* mark not allocated and not dynamically allocatable */
1192	tmp &= ~(TCSTATUS_A | TCSTATUS_DA);
1193	tmp |= TCSTATUS_IXMT;	/* interrupt exempt */
1194	write_tc_c0_tcstatus(tmp);
1195
1196	write_tc_c0_tchalt(TCHALT_H);
1197	mips_ihb();
1198
1199	/* bind it to anything other than VPE1 */
1200//	write_tc_c0_tcbind(read_tc_c0_tcbind() & ~TCBIND_CURVPE); // | TCBIND_CURVPE
1201
1202	clear_c0_mvpcontrol(MVPCONTROL_VPC);
1203	evpe(vpflags);
1204	emt(mtflags);
1205	local_irq_restore(flags);
1206}
1207
1208static int getcwd(char *buff, int size)
1209{
1210	mm_segment_t old_fs;
1211	int ret;
1212
1213	old_fs = get_fs();
1214	set_fs(KERNEL_DS);
1215
1216	ret = sys_getcwd(buff, size);
1217
1218	set_fs(old_fs);
1219
1220	return ret;
1221}
1222
1223/* checks VPE is unused and gets ready to load program  */
1224static int vpe_open(struct inode *inode, struct file *filp)
1225{
1226	enum vpe_state state;
1227	struct vpe_notifications *not;
1228	struct vpe *v;
1229	int ret;
1230
1231	if (minor != iminor(inode)) {
1232		/* assume only 1 device at the moment. */
1233		pr_warning("VPE loader: only vpe1 is supported\n");
1234
1235		return -ENODEV;
1236	}
1237	/*
1238	 * This treats the tclimit command line configuration input
1239	 * as a minor device indication, which is probably unwholesome.
1240	 */
1241
1242	if ((v = get_vpe(tclimit)) == NULL) {
1243		pr_warning("VPE loader: unable to get vpe\n");
1244
1245		return -ENODEV;
1246	}
1247
1248	state = xchg(&v->state, VPE_STATE_INUSE);
1249	if (state != VPE_STATE_UNUSED) {
1250		printk(KERN_DEBUG "VPE loader: tc in use dumping regs\n");
1251
1252		list_for_each_entry(not, &v->notify, list) {
1253			not->stop(tclimit);
1254		}
1255
1256		release_progmem(v->load_addr);
1257		kfree(v->l_phsort);
1258		cleanup_tc(get_tc(tclimit));
1259	}
1260
1261	/* this of-course trashes what was there before... */
1262	v->pbuffer = vmalloc(P_SIZE);
1263	v->load_addr = NULL;
1264	v->copied = 0;
1265	v->offset = 0;
1266	v->l_state = LOAD_STATE_EHDR;
1267	v->l_ehdr = NULL;
1268	v->l_phdr = NULL;
1269	v->l_phsort = NULL;
1270	v->l_shdr = NULL;
1271
1272	v->uid = filp->f_cred->fsuid;
1273	v->gid = filp->f_cred->fsgid;
1274
1275#ifdef CONFIG_MIPS_APSP_KSPD
1276	/* get kspd to tell us when a syscall_exit happens */
1277	if (!kspd_events_reqd) {
1278		kspd_notify(&kspd_events);
1279		kspd_events_reqd++;
1280	}
1281#endif
1282
1283	v->cwd[0] = 0;
1284	ret = getcwd(v->cwd, VPE_PATH_MAX);
1285	if (ret < 0)
1286		printk(KERN_WARNING "VPE loader: open, getcwd returned %d\n", ret);
1287
1288	v->shared_ptr = NULL;
1289	v->shared_areas = NULL;
1290	v->__start = 0;
1291
1292	return 0;
1293}
1294
1295static int vpe_release(struct inode *inode, struct file *filp)
1296{
1297	struct vpe *v;
1298	int ret = 0;
1299
1300	v = get_vpe(tclimit);
1301	if (v == NULL)
1302		return -ENODEV;
1303	/*
1304	 * If image load had no errors, massage program/section tables
1305	 * to reflect movement of program/section data into VPE program
1306	 * memory.
1307	 */
1308	if (v->l_state != LOAD_STATE_DONE) {
1309		printk(KERN_WARNING "VPE Release after incomplete load\n");
1310		printk(KERN_DEBUG "Used vfree to free memory at "
1311				  "%x after failed load attempt\n",
1312		       (unsigned int)v->pbuffer);
1313		if (v->pbuffer != NULL)
1314			vfree(v->pbuffer);
1315		return -ENOEXEC;
1316	}
1317
1318	if (vpe_elfload(v) >= 0) {
1319		vpe_run(v);
1320	} else {
1321		printk(KERN_WARNING "VPE loader: ELF load failed.\n");
1322		printk(KERN_DEBUG "Used vfree to free memory at "
1323				  "%x after failed load attempt\n",
1324		       (unsigned int)v->pbuffer);
1325		if (v->pbuffer != NULL)
1326			vfree(v->pbuffer);
1327		ret = -ENOEXEC;
1328	}
1329
1330
1331	/* It's good to be able to run the SP and if it chokes have a look at
1332	   the /dev/rt?. But if we reset the pointer to the shared struct we
1333	   lose what has happened. So perhaps if garbage is sent to the vpe
1334	   device, use it as a trigger for the reset. Hopefully a nice
1335	   executable will be along shortly. */
1336	if (ret < 0)
1337		v->shared_ptr = NULL;
1338
1339	// cleanup any temp buffers
1340	if (v->pbuffer) {
1341		printk(KERN_DEBUG "Used vfree to free memory at %x\n",
1342		       (unsigned int)v->pbuffer);
1343		vfree(v->pbuffer);
1344	}
1345	v->pbsize = 0;
1346	return ret;
1347}
1348
1349/*
1350 * A sort of insertion sort to generate list of program header indices
1351 * in order of their file offsets.
1352 */
1353
1354static void indexort(struct elf_phdr *phdr, int nph, int *index)
1355{
1356	int i, j, t;
1357	unsigned int toff;
1358
1359	/* Create initial mapping */
1360	for (i = 0; i < nph; i++)
1361		index[i] = i;
1362	/* Do the indexed insert sort */
1363	for (i = 1; i < nph; i++) {
1364		j = i;
1365		t = index[j];
1366		toff = phdr[t].p_offset;
1367		while ((j > 0) && (phdr[index[j-1]].p_offset > toff)) {
1368			index[j] = index[j-1];
1369			j--;
1370		}
1371		index[j] = t;
1372	}
1373}
1374
1375
1376/*
1377 * This function has to convert the ELF file image being sequentially
1378 * streamed to the pseudo-device into the binary image, symbol, and
1379 * string information, which the ELF format allows to be in some degree
1380 * of disorder.
1381 *
1382 * The ELF header and, if present, program header table, are copied into
1383 * a temporary buffer.  Loadable program segments, if present, are copied
1384 * into the RP program memory at the addresses specified by the program
1385 * header table.
1386 *
1387 * Sections not specified by the program header table are loaded into
1388 * memory following the program segments if they are "allocated", or
1389 * into the temporary buffer if they are not. The section header
1390 * table is loaded into the temporary buffer.???
1391 */
1392#define CURPHDR (v->l_phdr[v->l_phsort[v->l_cur_seg]])
1393static ssize_t vpe_write(struct file *file, const char __user * buffer,
1394			 size_t count, loff_t * ppos)
1395{
1396	size_t ret = count;
1397	struct vpe *v;
1398	int tocopy, uncopied;
1399	int i;
1400	unsigned int progmemlen;
1401
1402	if (iminor(file->f_path.dentry->d_inode) != minor)
1403		return -ENODEV;
1404
1405	v = get_vpe(tclimit);
1406	if (v == NULL)
1407		return -ENODEV;
1408
1409	if (v->pbuffer == NULL) {
1410		printk(KERN_ERR "VPE loader: no buffer for program\n");
1411		return -ENOMEM;
1412	}
1413
1414	while (count) {
1415		switch (v->l_state) {
1416		case LOAD_STATE_EHDR:
1417			/* Loading ELF Header into scratch buffer */
1418			tocopy = min((unsigned long)count,
1419				     sizeof(Elf_Ehdr) - v->offset);
1420			uncopied = copy_from_user(v->pbuffer + v->copied,
1421						  buffer, tocopy);
1422			count -= tocopy - uncopied;
1423			v->copied += tocopy - uncopied;
1424			v->offset += tocopy - uncopied;
1425			buffer += tocopy - uncopied;
1426			if (v->copied == sizeof(Elf_Ehdr)) {
1427			    v->l_ehdr = (Elf_Ehdr *)v->pbuffer;
1428			    if (memcmp(v->l_ehdr->e_ident, ELFMAG, 4) != 0) {
1429				printk(KERN_WARNING "VPE loader: %s\n",
1430					"non-ELF file image");
1431				ret = -ENOEXEC;
1432				v->l_state = LOAD_STATE_ERROR;
1433				break;
1434			    }
1435			    if (v->l_ehdr->e_phoff != 0) {
1436				v->l_phdr = (struct elf_phdr *)
1437					(v->pbuffer + v->l_ehdr->e_phoff);
1438				v->l_phlen = v->l_ehdr->e_phentsize
1439					* v->l_ehdr->e_phnum;
1440				/* Check against buffer overflow */
1441				if ((v->copied + v->l_phlen) > v->pbsize) {
1442					printk(KERN_WARNING
1443		       "VPE loader: elf program header table size too big\n");
1444					v->l_state = LOAD_STATE_ERROR;
1445					return -ENOMEM;
1446				}
1447				v->l_state = LOAD_STATE_PHDR;
1448				/*
1449				 * Program headers generally indicate
1450				 * linked executable with possibly
1451				 * valid entry point.
1452				 */
1453				v->__start = v->l_ehdr->e_entry;
1454			    } else  if (v->l_ehdr->e_shoff != 0) {
1455				/*
1456				 * No program headers, but a section
1457				 * header table.  A relocatable binary.
1458				 * We need to load the works into the
1459				 * kernel temp buffer to compute the
1460				 * RP program image.  That limits our
1461				 * binary size, but at least we're no
1462				 * worse off than the original APRP
1463				 * prototype.
1464				 */
1465				v->l_shlen = v->l_ehdr->e_shentsize
1466					* v->l_ehdr->e_shnum;
1467				if ((v->l_ehdr->e_shoff + v->l_shlen
1468				     - v->offset) > v->pbsize) {
1469					printk(KERN_WARNING
1470			 "VPE loader: elf sections/section table too big.\n");
1471					v->l_state = LOAD_STATE_ERROR;
1472					return -ENOMEM;
1473				}
1474				v->l_state = LOAD_STATE_SHDR;
1475			    } else {
1476				/*
1477				 * If neither program nor section tables,
1478				 * we don't know what to do.
1479				 */
1480				v->l_state = LOAD_STATE_ERROR;
1481				return -ENOEXEC;
1482			    }
1483			}
1484			break;
1485		case LOAD_STATE_PHDR:
1486			/* Loading Program Headers into scratch */
1487			tocopy = min((unsigned long)count,
1488			    v->l_ehdr->e_phoff + v->l_phlen - v->copied);
1489			uncopied = copy_from_user(v->pbuffer + v->copied,
1490			    buffer, tocopy);
1491			count -= tocopy - uncopied;
1492			v->copied += tocopy - uncopied;
1493			v->offset += tocopy - uncopied;
1494			buffer += tocopy - uncopied;
1495
1496			if (v->copied == v->l_ehdr->e_phoff + v->l_phlen) {
1497			    /*
1498			     * It's legal for the program headers to be
1499			     * out of order with respect to the file layout.
1500			     * Generate a list of indices, sorted by file
1501			     * offset.
1502			     */
1503			    v->l_phsort = kmalloc(v->l_ehdr->e_phnum
1504				* sizeof(int), GFP_KERNEL);
1505			    printk(KERN_DEBUG
1506		   "Used kmalloc to allocate %d bytes of memory at %x\n",
1507				   v->l_ehdr->e_phnum*sizeof(int),
1508				   (unsigned int)v->l_phsort);
1509			    if (!v->l_phsort)
1510				    return -ENOMEM; /* Preposterous, but... */
1511			    indexort(v->l_phdr, v->l_ehdr->e_phnum,
1512				     v->l_phsort);
1513
1514			    v->l_progminad = (unsigned int)-1;
1515			    v->l_progmaxad = 0;
1516			    progmemlen = 0;
1517			    for (i = 0; i < v->l_ehdr->e_phnum; i++) {
1518				if (v->l_phdr[v->l_phsort[i]].p_type
1519				    == PT_LOAD) {
1520				    /* Unstripped .reginfo sections are bad */
1521				    if (v->l_phdr[v->l_phsort[i]].p_vaddr
1522					< __UA_LIMIT) {
1523					printk(KERN_WARNING "%s%s%s\n",
1524					    "VPE loader: ",
1525					    "User-mode p_vaddr, ",
1526					    "skipping program segment,");
1527					printk(KERN_WARNING "%s%s%s\n",
1528					    "VPE loader: ",
1529					    "strip .reginfo from binary ",
1530					    "if necessary.");
1531					continue;
1532				    }
1533				    if (v->l_phdr[v->l_phsort[i]].p_vaddr
1534					< v->l_progminad)
1535					    v->l_progminad =
1536					      v->l_phdr[v->l_phsort[i]].p_vaddr;
1537				    if ((v->l_phdr[v->l_phsort[i]].p_vaddr
1538					+ v->l_phdr[v->l_phsort[i]].p_memsz)
1539					> v->l_progmaxad)
1540					    v->l_progmaxad =
1541					     v->l_phdr[v->l_phsort[i]].p_vaddr +
1542					     v->l_phdr[v->l_phsort[i]].p_memsz;
1543				}
1544			    }
1545			    printk(KERN_INFO "APRP RP program 0x%x to 0x%x\n",
1546				v->l_progminad, v->l_progmaxad);
1547			    /*
1548			     * Do a simple sanity check of the memory being
1549			     * allocated. Abort if greater than an arbitrary
1550			     * value of 32MB
1551			     */
1552			    if (v->l_progmaxad - v->l_progminad >
1553				32*1024*1024) {
1554				printk(KERN_WARNING
1555	      "RP program failed to allocate %d kbytes - limit is 32,768 KB\n",
1556				       (v->l_progmaxad - v->l_progminad)/1024);
1557				return -ENOMEM;
1558			      }
1559
1560			    v->load_addr = alloc_progmem((void *)v->l_progminad,
1561				v->l_progmaxad - v->l_progminad);
1562			    if (!v->load_addr)
1563				return -ENOMEM;
1564			    if ((unsigned int)v->load_addr
1565				> v->l_progminad) {
1566				release_progmem(v->load_addr);
1567				return -ENOMEM;
1568			    }
1569			    /* Find first segment with loadable content */
1570			    for (i = 0; i < v->l_ehdr->e_phnum; i++) {
1571				if (v->l_phdr[v->l_phsort[i]].p_type
1572				    == PT_LOAD) {
1573				    if (v->l_phdr[v->l_phsort[i]].p_vaddr
1574					< __UA_LIMIT) {
1575					/* Skip userspace segments */
1576					continue;
1577				    }
1578				    v->l_cur_seg = i;
1579				    break;
1580				}
1581			    }
1582			    if (i == v->l_ehdr->e_phnum) {
1583				/* No loadable program segment?  Bogus file. */
1584				printk(KERN_WARNING "Bad ELF file for APRP\n");
1585				return -ENOEXEC;
1586			    }
1587			    v->l_segoff = 0;
1588			    v->l_state = LOAD_STATE_PIMAGE;
1589			}
1590			break;
1591		case LOAD_STATE_PIMAGE:
1592			/*
1593			 * Skip through input stream until
1594			 * first program segment. Would be
1595			 * better to have loaded up to here
1596			 * into the temp buffer, but for now
1597			 * we simply rule out "interesting"
1598			 * sections prior to the last program
1599			 * segment in an executable file.
1600			 */
1601			if (v->offset < CURPHDR.p_offset) {
1602			    uncopied = CURPHDR.p_offset - v->offset;
1603			    if (uncopied > count)
1604				uncopied = count;
1605			    count -= uncopied;
1606			    buffer += uncopied;
1607			    v->offset += uncopied;
1608			    /* Go back through the "while" */
1609			    break;
1610			}
1611			/*
1612			 * Having dispensed with any unlikely fluff,
1613			 * copy from user I/O buffer to program segment.
1614			 */
1615			tocopy = min(count, CURPHDR.p_filesz - v->l_segoff);
1616
1617			/* Loading image into RP memory */
1618			uncopied = copy_from_user((char *)CURPHDR.p_vaddr
1619			    + v->l_segoff, buffer, tocopy);
1620			count -= tocopy - uncopied;
1621			v->offset += tocopy - uncopied;
1622			v->l_segoff += tocopy - uncopied;
1623			buffer += tocopy - uncopied;
1624			if (v->l_segoff >= CURPHDR.p_filesz) {
1625			    /* Finished current segment load */
1626			    /* Zero out non-file-sourced image */
1627			    uncopied = CURPHDR.p_memsz - CURPHDR.p_filesz;
1628			    if (uncopied > 0)
1629				memset((char *)CURPHDR.p_vaddr + v->l_segoff,
1630				    0, uncopied);
1631			    /* Advance to next segment */
1632			    for (i = v->l_cur_seg + 1;
1633				i < v->l_ehdr->e_phnum; i++) {
1634				if (v->l_phdr[v->l_phsort[i]].p_type
1635				    == PT_LOAD) {
1636				    if (v->l_phdr[v->l_phsort[i]].p_vaddr
1637					< __UA_LIMIT) {
1638					/* Skip userspace segments */
1639					continue;
1640				    }
1641				    v->l_cur_seg = i;
1642				    break;
1643				}
1644			    }
1645			    /* If none left, prepare to load section headers */
1646			    if (i == v->l_ehdr->e_phnum) {
1647				if (v->l_ehdr->e_shoff != 0) {
1648				/* Copy to where we left off in temp buffer */
1649				    v->l_shlen = v->l_ehdr->e_shentsize
1650					* v->l_ehdr->e_shnum;
1651				    if ((v->l_ehdr->e_shoff + v->l_shlen
1652					- v->offset) > v->pbsize) {
1653					printk(KERN_WARNING
1654			   "VPE loader: elf sections/section table too big\n");
1655					v->l_state = LOAD_STATE_ERROR;
1656					return -ENOMEM;
1657				    }
1658				    v->l_state = LOAD_STATE_SHDR;
1659				    break;
1660				}
1661			    } else {
1662				/* reset offset for new program segment */
1663				v->l_segoff = 0;
1664			    }
1665			}
1666			break;
1667		case LOAD_STATE_SHDR:
1668			/*
1669			 * Read stream into private buffer up
1670			 * through and including the section header
1671			 * table.
1672			 */
1673
1674			tocopy = min((unsigned long)count,
1675			    v->l_ehdr->e_shoff + v->l_shlen - v->offset);
1676			if (tocopy) {
1677			    uncopied = copy_from_user(v->pbuffer + v->copied,
1678			    buffer, tocopy);
1679			    count -= tocopy - uncopied;
1680			    v->copied += tocopy - uncopied;
1681			    v->offset += tocopy - uncopied;
1682			    buffer += tocopy - uncopied;
1683			}
1684			/* Finished? */
1685			if (v->offset == v->l_ehdr->e_shoff + v->l_shlen) {
1686			    unsigned int offset_delta = v->offset - v->copied;
1687
1688			    v->l_shdr = (Elf_Shdr *)(v->pbuffer
1689				+ v->l_ehdr->e_shoff - offset_delta);
1690			    /*
1691			     * Check for sections after the section table,
1692			     * which for gcc MIPS binaries includes
1693			     * the symbol table. Do any other processing
1694			     * that requires value within stream, and
1695			     * normalize offsets to be relative to
1696			     * the header-only layout of temp buffer.
1697			     */
1698
1699			    /* Assume no trailer until we detect one */
1700			    v->l_trailer = 0;
1701			    v->l_state = LOAD_STATE_DONE;
1702			    for (i = 0; i < v->l_ehdr->e_shnum; i++) {
1703				   if (v->l_shdr[i].sh_offset
1704					> v->l_ehdr->e_shoff) {
1705					v->l_state = LOAD_STATE_TRAILER;
1706					/* Track trailing data length */
1707					if (v->l_trailer
1708					    < (v->l_shdr[i].sh_offset
1709					    + v->l_shdr[i].sh_size)
1710					    - (v->l_ehdr->e_shoff
1711					    + v->l_shlen))
1712						v->l_trailer =
1713						    (v->l_shdr[i].sh_offset
1714						    + v->l_shdr[i].sh_size)
1715						    - (v->l_ehdr->e_shoff
1716						    + v->l_shlen);
1717				    }
1718				    /* Adjust section offset if necessary */
1719				    v->l_shdr[i].sh_offset -= offset_delta;
1720			    }
1721			    if ((v->copied + v->l_trailer) > v->pbsize) {
1722				printk(KERN_WARNING
1723	      "VPE loader: elf size too big. Perhaps strip uneeded symbols\n");
1724				v->l_state = LOAD_STATE_ERROR;
1725				return -ENOMEM;
1726			    }
1727
1728			    /* Fix up offsets in ELF header */
1729			    v->l_ehdr->e_shoff = (unsigned int)v->l_shdr
1730				- (unsigned int)v->pbuffer;
1731			}
1732			break;
1733		case LOAD_STATE_TRAILER:
1734			/*
1735			 * Symbol and string tables follow section headers
1736			 * in gcc binaries for MIPS. Copy into temp buffer.
1737			 */
1738			if (v->l_trailer) {
1739			    tocopy = min(count, v->l_trailer);
1740			    uncopied = copy_from_user(v->pbuffer + v->copied,
1741			    buffer, tocopy);
1742			    count -= tocopy - uncopied;
1743			    v->l_trailer -= tocopy - uncopied;
1744			    v->copied += tocopy - uncopied;
1745			    v->offset += tocopy - uncopied;
1746			    buffer += tocopy - uncopied;
1747			}
1748			if (!v->l_trailer)
1749			    v->l_state = LOAD_STATE_DONE;
1750			break;
1751		case LOAD_STATE_DONE:
1752			if (count)
1753				count = 0;
1754			break;
1755		case LOAD_STATE_ERROR:
1756		default:
1757			return -EINVAL;
1758		}
1759	}
1760	return ret;
1761}
1762
1763static const struct file_operations vpe_fops = {
1764	.owner = THIS_MODULE,
1765	.open = vpe_open,
1766	.release = vpe_release,
1767	.write = vpe_write
1768};
1769
1770/* module wrapper entry points */
1771/* give me a vpe */
1772vpe_handle vpe_alloc(void)
1773{
1774	int i;
1775	struct vpe *v;
1776
1777	/* find a vpe */
1778	for (i = 1; i < MAX_VPES; i++) {
1779		if ((v = get_vpe(i)) != NULL) {
1780			v->state = VPE_STATE_INUSE;
1781			return v;
1782		}
1783	}
1784	return NULL;
1785}
1786
1787EXPORT_SYMBOL(vpe_alloc);
1788
1789/* start running from here */
1790int vpe_start(vpe_handle vpe, unsigned long start)
1791{
1792	struct vpe *v = vpe;
1793
1794	/* Null start address means use value from ELF file */
1795	if (start)
1796		v->__start = start;
1797	return vpe_run(v);
1798}
1799
1800EXPORT_SYMBOL(vpe_start);
1801
1802/* halt it for now */
1803int vpe_stop(vpe_handle vpe)
1804{
1805	struct vpe *v = vpe;
1806	struct tc *t;
1807	unsigned int evpe_flags;
1808
1809	evpe_flags = dvpe();
1810
1811	if ((t = list_entry(v->tc.next, struct tc, tc)) != NULL) {
1812
1813		settc(t->index);
1814		write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() & ~VPECONF0_VPA);
1815	}
1816
1817	evpe(evpe_flags);
1818
1819	return 0;
1820}
1821
1822EXPORT_SYMBOL(vpe_stop);
1823
1824/* I've done with it thank you */
1825int vpe_free(vpe_handle vpe)
1826{
1827	struct vpe *v = vpe;
1828	struct tc *t;
1829	unsigned int evpe_flags;
1830
1831	if ((t = list_entry(v->tc.next, struct tc, tc)) == NULL) {
1832		return -ENOEXEC;
1833	}
1834
1835	evpe_flags = dvpe();
1836
1837	/* Put MVPE's into 'configuration state' */
1838	set_c0_mvpcontrol(MVPCONTROL_VPC);
1839
1840	settc(t->index);
1841	write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() & ~VPECONF0_VPA);
1842
1843	/* halt the TC */
1844	write_tc_c0_tchalt(TCHALT_H);
1845	mips_ihb();
1846
1847	/* mark the TC unallocated */
1848	write_tc_c0_tcstatus(read_tc_c0_tcstatus() & ~TCSTATUS_A);
1849
1850	v->state = VPE_STATE_UNUSED;
1851
1852	clear_c0_mvpcontrol(MVPCONTROL_VPC);
1853	evpe(evpe_flags);
1854
1855	return 0;
1856}
1857
1858EXPORT_SYMBOL(vpe_free);
1859
1860void *vpe_get_shared(int index)
1861{
1862	struct vpe *v;
1863
1864	if ((v = get_vpe(index)) == NULL)
1865		return NULL;
1866
1867	return v->shared_ptr;
1868}
1869
1870EXPORT_SYMBOL(vpe_get_shared);
1871
1872int vpe_getuid(int index)
1873{
1874	struct vpe *v;
1875
1876	if ((v = get_vpe(index)) == NULL)
1877		return -1;
1878
1879	return v->uid;
1880}
1881
1882EXPORT_SYMBOL(vpe_getuid);
1883
1884int vpe_getgid(int index)
1885{
1886	struct vpe *v;
1887
1888	if ((v = get_vpe(index)) == NULL)
1889		return -1;
1890
1891	return v->gid;
1892}
1893
1894EXPORT_SYMBOL(vpe_getgid);
1895
1896int vpe_notify(int index, struct vpe_notifications *notify)
1897{
1898	struct vpe *v;
1899
1900	if ((v = get_vpe(index)) == NULL)
1901		return -1;
1902
1903	list_add(&notify->list, &v->notify);
1904	return 0;
1905}
1906
1907EXPORT_SYMBOL(vpe_notify);
1908
1909char *vpe_getcwd(int index)
1910{
1911	struct vpe *v;
1912
1913	if ((v = get_vpe(index)) == NULL)
1914		return NULL;
1915
1916	return v->cwd;
1917}
1918
1919EXPORT_SYMBOL(vpe_getcwd);
1920
1921/*
1922 * RP applications may contain a _vpe_shared_area descriptor
1923 * array to allow for data sharing with Linux kernel functions
1924 * that's slightly more abstracted and extensible than the
1925 * fixed binding used by the rtlx support.  Indeed, the rtlx
1926 * support should ideally be converted to use the generic
1927 * shared area descriptor scheme at some point.
1928 *
1929 * mips_get_vpe_shared_area() can be used by AP kernel
1930 * modules to get an area pointer of a given type, if
1931 * it exists.
1932 *
1933 * mips_publish_vpe_area() is used by AP kernel modules
1934 * to share kseg0 kernel memory with the RP.  It maintains
1935 * a private table, so that publishing can be done before
1936 * the RP program is launched.  Making this table dynamically
1937 * allocated and extensible would be good scalable OS design.
1938 * however, until there's more than one user of the mechanism,
1939 * it should be an acceptable simplification to allow a static
1940 * maximum of 4 published areas.
1941 */
1942
1943void *mips_get_vpe_shared_area(int index, int type)
1944{
1945	struct vpe *v;
1946	struct vpe_shared_area *vsa;
1947
1948	v = get_vpe(index);
1949	if (v == NULL)
1950		return NULL;
1951
1952	if (v->shared_areas == NULL)
1953		return NULL;
1954
1955	vsa = v->shared_areas;
1956
1957	while (vsa->type != VPE_SHARED_NULL) {
1958		if (vsa->type == type)
1959			return vsa->addr;
1960		else
1961			vsa++;
1962	}
1963	/* Fell through without finding type */
1964
1965	return NULL;
1966}
1967EXPORT_SYMBOL(mips_get_vpe_shared_area);
1968
1969int  mips_publish_vpe_area(int type, void *ptr)
1970{
1971	int i;
1972	int retval = 0;
1973	struct vpe *v;
1974	unsigned long flags;
1975	unsigned int vpflags;
1976
1977	printk(KERN_INFO "mips_publish_vpe_area(0x%x, 0x%x)\n", type, (int)ptr);
1978	if ((unsigned int)ptr >= KSEG2) {
1979	    printk(KERN_ERR "VPE area pubish of invalid address 0x%x\n",
1980		(int)ptr);
1981	    return 0;
1982	}
1983	for (i = 0; i < N_PUB_AREAS; i++) {
1984	    if (published_vpe_area[i].type == VPE_SHARED_RESERVED) {
1985		published_vpe_area[i].type = type;
1986		published_vpe_area[i].addr = ptr;
1987		retval = type;
1988		break;
1989	    }
1990	}
1991	/*
1992	 * If we've already got a VPE up and running, try to
1993	 * update the shared descriptor with the new data.
1994	 */
1995	list_for_each_entry(v, &vpecontrol.vpe_list, list) {
1996	    if (v->shared_areas != NULL) {
1997		local_irq_save(flags);
1998		vpflags = dvpe();
1999		for (i = 0; v->shared_areas[i].type != VPE_SHARED_NULL; i++) {
2000		    if ((v->shared_areas[i].type == type)
2001		    || (v->shared_areas[i].type == VPE_SHARED_RESERVED)) {
2002			v->shared_areas[i].type = type;
2003			v->shared_areas[i].addr = ptr;
2004		    }
2005		}
2006		evpe(vpflags);
2007		local_irq_restore(flags);
2008	    }
2009	}
2010	return retval;
2011}
2012EXPORT_SYMBOL(mips_publish_vpe_area);
2013
2014#ifdef CONFIG_MIPS_APSP_KSPD
2015static void kspd_sp_exit( int sp_id)
2016{
2017	cleanup_tc(get_tc(sp_id));
2018}
2019#endif
2020
2021static ssize_t store_kill(struct device *dev, struct device_attribute *attr,
2022			  const char *buf, size_t len)
2023{
2024	struct vpe *vpe = get_vpe(tclimit);
2025	struct vpe_notifications *not;
2026
2027	list_for_each_entry(not, &vpe->notify, list) {
2028		not->stop(tclimit);
2029	}
2030
2031	release_progmem(vpe->load_addr);
2032	kfree(vpe->l_phsort);
2033	cleanup_tc(get_tc(tclimit));
2034	vpe_stop(vpe);
2035	vpe_free(vpe);
2036
2037	return len;
2038}
2039
2040static ssize_t show_ntcs(struct device *cd, struct device_attribute *attr,
2041			 char *buf)
2042{
2043	struct vpe *vpe = get_vpe(tclimit);
2044
2045	return sprintf(buf, "%d\n", vpe->ntcs);
2046}
2047
2048static ssize_t store_ntcs(struct device *dev, struct device_attribute *attr,
2049			  const char *buf, size_t len)
2050{
2051	struct vpe *vpe = get_vpe(tclimit);
2052	unsigned long new;
2053	char *endp;
2054
2055	new = simple_strtoul(buf, &endp, 0);
2056	if (endp == buf)
2057		goto out_einval;
2058
2059	if (new == 0 || new > (hw_tcs - tclimit))
2060		goto out_einval;
2061
2062	vpe->ntcs = new;
2063
2064	return len;
2065
2066out_einval:
2067	return -EINVAL;
2068}
2069
2070static struct device_attribute vpe_class_attributes[] = {
2071	__ATTR(kill, S_IWUSR, NULL, store_kill),
2072	__ATTR(ntcs, S_IRUGO | S_IWUSR, show_ntcs, store_ntcs),
2073	{}
2074};
2075
2076static void vpe_device_release(struct device *cd)
2077{
2078	printk(KERN_DEBUG "Using kfree to free vpe class device at %x\n",
2079	       (unsigned int)cd);
2080	kfree(cd);
2081}
2082
2083struct class vpe_class = {
2084	.name = "vpe",
2085	.owner = THIS_MODULE,
2086	.dev_release = vpe_device_release,
2087	.dev_attrs = vpe_class_attributes,
2088};
2089
2090struct device vpe_device;
2091
2092static int __init vpe_module_init(void)
2093{
2094	unsigned int mtflags, vpflags;
2095	unsigned long flags, val;
2096	struct vpe *v = NULL;
2097	struct tc *t;
2098	int tc, err;
2099
2100	if (!cpu_has_mipsmt) {
2101		printk("VPE loader: not a MIPS MT capable processor\n");
2102		return -ENODEV;
2103	}
2104
2105	if (vpelimit == 0) {
2106#if defined(CONFIG_MIPS_MT_SMTC) || defined(MIPS_MT_SMP)
2107		printk(KERN_WARNING "No VPEs reserved for VPE loader.\n"
2108			"Pass maxvpes=<n> argument as kernel argument\n");
2109		return -ENODEV;
2110#else
2111		vpelimit = 1;
2112#endif
2113	}
2114
2115	if (tclimit == 0) {
2116#if defined(CONFIG_MIPS_MT_SMTC) || defined(MIPS_MT_SMP)
2117		printk(KERN_WARNING "No TCs reserved for AP/SP, not "
2118		       "initializing VPE loader.\nPass maxtcs=<n> argument as "
2119		       "kernel argument\n");
2120		return -ENODEV;
2121#else
2122		tclimit = 1;
2123#endif
2124	}
2125
2126	major = register_chrdev(0, module_name, &vpe_fops);
2127	if (major < 0) {
2128		printk("VPE loader: unable to register character device\n");
2129		return major;
2130	}
2131
2132	err = class_register(&vpe_class);
2133	if (err) {
2134		printk(KERN_ERR "vpe_class registration failed\n");
2135		goto out_chrdev;
2136	}
2137	xvpe_vector_set = 0;
2138	device_initialize(&vpe_device);
2139	vpe_device.class	= &vpe_class,
2140	vpe_device.parent	= NULL,
2141	dev_set_name(&vpe_device, "vpe1");
2142	vpe_device.devt = MKDEV(major, minor);
2143	err = device_add(&vpe_device);
2144	if (err) {
2145		printk(KERN_ERR "Adding vpe_device failed\n");
2146		goto out_class;
2147	}
2148
2149	local_irq_save(flags);
2150	mtflags = dmt();
2151	vpflags = dvpe();
2152
2153	/* Put MVPE's into 'configuration state' */
2154	set_c0_mvpcontrol(MVPCONTROL_VPC);
2155
2156	/* dump_mtregs(); */
2157
2158	val = read_c0_mvpconf0();
2159	hw_tcs = (val & MVPCONF0_PTC) + 1;
2160	hw_vpes = ((val & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT) + 1;
2161
2162	for (tc = tclimit; tc < hw_tcs; tc++) {
2163		/*
2164		 * Must re-enable multithreading temporarily or in case we
2165		 * reschedule send IPIs or similar we might hang.
2166		 */
2167		clear_c0_mvpcontrol(MVPCONTROL_VPC);
2168		evpe(vpflags);
2169		emt(mtflags);
2170		local_irq_restore(flags);
2171		t = alloc_tc(tc);
2172		if (!t) {
2173			err = -ENOMEM;
2174			goto out;
2175		}
2176
2177		local_irq_save(flags);
2178		mtflags = dmt();
2179		vpflags = dvpe();
2180		set_c0_mvpcontrol(MVPCONTROL_VPC);
2181
2182		/* VPE's */
2183		if (tc < hw_tcs) {
2184			settc(tc);
2185
2186			if ((v = alloc_vpe(tc)) == NULL) {
2187				printk(KERN_WARNING "VPE: unable to allocate VPE\n");
2188
2189				goto out_reenable;
2190			}
2191
2192			v->ntcs = hw_tcs - tclimit;
2193
2194			/* add the tc to the list of this vpe's tc's. */
2195			list_add(&t->tc, &v->tc);
2196
2197			/* deactivate all but vpe0 */
2198			if (tc >= tclimit) {
2199				unsigned long tmp = read_vpe_c0_vpeconf0();
2200
2201				tmp &= ~VPECONF0_VPA;
2202
2203				/* master VPE */
2204				tmp |= VPECONF0_MVP;
2205				write_vpe_c0_vpeconf0(tmp);
2206			}
2207
2208			/* disable multi-threading with TC's */
2209			write_vpe_c0_vpecontrol(read_vpe_c0_vpecontrol() & ~VPECONTROL_TE);
2210
2211			if (tc >= vpelimit) {
2212				/*
2213				 * Set config to be the same as vpe0,
2214				 * particularly kseg0 coherency alg
2215				 */
2216				write_vpe_c0_config(read_c0_config());
2217			}
2218		}
2219
2220		/* TC's */
2221		t->pvpe = v;	/* set the parent vpe */
2222
2223		if (tc >= tclimit) {
2224			unsigned long tmp;
2225
2226			settc(tc);
2227
2228			/* Any TC that is bound to VPE0 gets left as is - in case
2229			   we are running SMTC on VPE0. A TC that is bound to any
2230			   other VPE gets bound to VPE0, ideally I'd like to make
2231			   it homeless but it doesn't appear to let me bind a TC
2232			   to a non-existent VPE. Which is perfectly reasonable.
2233
2234			   The (un)bound state is visible to an EJTAG probe so may
2235			   notify GDB...
2236			*/
2237
2238			if (((tmp = read_tc_c0_tcbind()) & TCBIND_CURVPE)) {
2239				/* tc is bound >vpe0 */
2240				write_tc_c0_tcbind(tmp & ~TCBIND_CURVPE);
2241
2242				t->pvpe = get_vpe(0);	/* set the parent vpe */
2243			}
2244
2245			/* halt the TC */
2246			write_tc_c0_tchalt(TCHALT_H);
2247			mips_ihb();
2248
2249			tmp = read_tc_c0_tcstatus();
2250
2251			/* mark not activated and not dynamically allocatable */
2252			tmp &= ~(TCSTATUS_A | TCSTATUS_DA);
2253			tmp |= TCSTATUS_IXMT;	/* interrupt exempt */
2254			write_tc_c0_tcstatus(tmp);
2255		}
2256	}
2257
2258out_reenable:
2259	/* release config state */
2260	clear_c0_mvpcontrol(MVPCONTROL_VPC);
2261
2262	evpe(vpflags);
2263	emt(mtflags);
2264	local_irq_restore(flags);
2265
2266#ifdef CONFIG_MIPS_APSP_KSPD
2267	kspd_events.kspd_sp_exit = kspd_sp_exit;
2268#endif
2269	return 0;
2270
2271out_class:
2272	class_unregister(&vpe_class);
2273out_chrdev:
2274	unregister_chrdev(major, module_name);
2275
2276out:
2277	return err;
2278}
2279
2280static void __exit vpe_module_exit(void)
2281{
2282	struct vpe *v, *n;
2283
2284	device_del(&vpe_device);
2285	unregister_chrdev(major, module_name);
2286
2287	/* No locking needed here */
2288	list_for_each_entry_safe(v, n, &vpecontrol.vpe_list, list) {
2289		if (v->state != VPE_STATE_UNUSED)
2290			release_vpe(v);
2291	}
2292}
2293
2294module_init(vpe_module_init);
2295module_exit(vpe_module_exit);
2296MODULE_DESCRIPTION("MIPS VPE Loader");
2297MODULE_AUTHOR("Elizabeth Oldham, MIPS Technologies, Inc.");
2298MODULE_LICENSE("GPL");
2299