xref: /openbmc/linux/arch/mips/kernel/vpe.c (revision 07cc0c9e)
1e01402b1SRalf Baechle /*
2e01402b1SRalf Baechle  * Copyright (C) 2004, 2005 MIPS Technologies, Inc.  All rights reserved.
3e01402b1SRalf Baechle  *
4e01402b1SRalf Baechle  *  This program is free software; you can distribute it and/or modify it
5e01402b1SRalf Baechle  *  under the terms of the GNU General Public License (Version 2) as
6e01402b1SRalf Baechle  *  published by the Free Software Foundation.
7e01402b1SRalf Baechle  *
8e01402b1SRalf Baechle  *  This program is distributed in the hope it will be useful, but WITHOUT
9e01402b1SRalf Baechle  *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10e01402b1SRalf Baechle  *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
11e01402b1SRalf Baechle  *  for more details.
12e01402b1SRalf Baechle  *
13e01402b1SRalf Baechle  *  You should have received a copy of the GNU General Public License along
14e01402b1SRalf Baechle  *  with this program; if not, write to the Free Software Foundation, Inc.,
15e01402b1SRalf Baechle  *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
16e01402b1SRalf Baechle  */
17e01402b1SRalf Baechle 
18e01402b1SRalf Baechle /*
19e01402b1SRalf Baechle  * VPE support module
20e01402b1SRalf Baechle  *
21e01402b1SRalf Baechle  * Provides support for loading a MIPS SP program on VPE1.
22e01402b1SRalf Baechle  * The SP enviroment is rather simple, no tlb's.  It needs to be relocatable
23e01402b1SRalf Baechle  * (or partially linked). You should initialise your stack in the startup
24e01402b1SRalf Baechle  * code. This loader looks for the symbol __start and sets up
25e01402b1SRalf Baechle  * execution to resume from there. The MIPS SDE kit contains suitable examples.
26e01402b1SRalf Baechle  *
27e01402b1SRalf Baechle  * To load and run, simply cat a SP 'program file' to /dev/vpe1.
28e01402b1SRalf Baechle  * i.e cat spapp >/dev/vpe1.
29e01402b1SRalf Baechle  */
30e01402b1SRalf Baechle #include <linux/kernel.h>
3127a3bbafSRalf Baechle #include <linux/device.h>
32e01402b1SRalf Baechle #include <linux/module.h>
33e01402b1SRalf Baechle #include <linux/fs.h>
34e01402b1SRalf Baechle #include <linux/init.h>
35e01402b1SRalf Baechle #include <asm/uaccess.h>
36e01402b1SRalf Baechle #include <linux/slab.h>
37e01402b1SRalf Baechle #include <linux/list.h>
38e01402b1SRalf Baechle #include <linux/vmalloc.h>
39e01402b1SRalf Baechle #include <linux/elf.h>
40e01402b1SRalf Baechle #include <linux/seq_file.h>
41e01402b1SRalf Baechle #include <linux/syscalls.h>
42e01402b1SRalf Baechle #include <linux/moduleloader.h>
43e01402b1SRalf Baechle #include <linux/interrupt.h>
44e01402b1SRalf Baechle #include <linux/poll.h>
45e01402b1SRalf Baechle #include <linux/bootmem.h>
46e01402b1SRalf Baechle #include <asm/mipsregs.h>
47340ee4b9SRalf Baechle #include <asm/mipsmtregs.h>
48e01402b1SRalf Baechle #include <asm/cacheflush.h>
49e01402b1SRalf Baechle #include <asm/atomic.h>
50e01402b1SRalf Baechle #include <asm/cpu.h>
5127a3bbafSRalf Baechle #include <asm/mips_mt.h>
52e01402b1SRalf Baechle #include <asm/processor.h>
53e01402b1SRalf Baechle #include <asm/system.h>
542600990eSRalf Baechle #include <asm/vpe.h>
552600990eSRalf Baechle #include <asm/kspd.h>
5607cc0c9eSRalf Baechle #include <asm/mips_mt.h>
57e01402b1SRalf Baechle 
58e01402b1SRalf Baechle typedef void *vpe_handle;
59e01402b1SRalf Baechle 
60e01402b1SRalf Baechle #ifndef ARCH_SHF_SMALL
61e01402b1SRalf Baechle #define ARCH_SHF_SMALL 0
62e01402b1SRalf Baechle #endif
63e01402b1SRalf Baechle 
64e01402b1SRalf Baechle /* If this is set, the section belongs in the init part of the module */
65e01402b1SRalf Baechle #define INIT_OFFSET_MASK (1UL << (BITS_PER_LONG-1))
66e01402b1SRalf Baechle 
67e01402b1SRalf Baechle static char module_name[] = "vpe";
68307bd284SRalf Baechle static int major;
6927a3bbafSRalf Baechle static const int minor = 1;	/* fixed for now  */
70e01402b1SRalf Baechle 
712600990eSRalf Baechle #ifdef CONFIG_MIPS_APSP_KSPD
722600990eSRalf Baechle  static struct kspd_notifications kspd_events;
732600990eSRalf Baechle static int kspd_events_reqd = 0;
742600990eSRalf Baechle #endif
752600990eSRalf Baechle 
76e01402b1SRalf Baechle /* grab the likely amount of memory we will need. */
77e01402b1SRalf Baechle #ifdef CONFIG_MIPS_VPE_LOADER_TOM
78e01402b1SRalf Baechle #define P_SIZE (2 * 1024 * 1024)
79e01402b1SRalf Baechle #else
80e01402b1SRalf Baechle /* add an overhead to the max kmalloc size for non-striped symbols/etc */
81e01402b1SRalf Baechle #define P_SIZE (256 * 1024)
82e01402b1SRalf Baechle #endif
83e01402b1SRalf Baechle 
842600990eSRalf Baechle extern unsigned long physical_memsize;
852600990eSRalf Baechle 
86e01402b1SRalf Baechle #define MAX_VPES 16
872600990eSRalf Baechle #define VPE_PATH_MAX 256
88e01402b1SRalf Baechle 
89e01402b1SRalf Baechle enum vpe_state {
90e01402b1SRalf Baechle 	VPE_STATE_UNUSED = 0,
91e01402b1SRalf Baechle 	VPE_STATE_INUSE,
92e01402b1SRalf Baechle 	VPE_STATE_RUNNING
93e01402b1SRalf Baechle };
94e01402b1SRalf Baechle 
95e01402b1SRalf Baechle enum tc_state {
96e01402b1SRalf Baechle 	TC_STATE_UNUSED = 0,
97e01402b1SRalf Baechle 	TC_STATE_INUSE,
98e01402b1SRalf Baechle 	TC_STATE_RUNNING,
99e01402b1SRalf Baechle 	TC_STATE_DYNAMIC
100e01402b1SRalf Baechle };
101e01402b1SRalf Baechle 
102307bd284SRalf Baechle struct vpe {
103e01402b1SRalf Baechle 	enum vpe_state state;
104e01402b1SRalf Baechle 
105e01402b1SRalf Baechle 	/* (device) minor associated with this vpe */
106e01402b1SRalf Baechle 	int minor;
107e01402b1SRalf Baechle 
108e01402b1SRalf Baechle 	/* elfloader stuff */
109e01402b1SRalf Baechle 	void *load_addr;
110571e0bedSRalf Baechle 	unsigned long len;
111e01402b1SRalf Baechle 	char *pbuffer;
112571e0bedSRalf Baechle 	unsigned long plen;
1132600990eSRalf Baechle 	unsigned int uid, gid;
1142600990eSRalf Baechle 	char cwd[VPE_PATH_MAX];
115e01402b1SRalf Baechle 
116e01402b1SRalf Baechle 	unsigned long __start;
117e01402b1SRalf Baechle 
118e01402b1SRalf Baechle 	/* tc's associated with this vpe */
119e01402b1SRalf Baechle 	struct list_head tc;
120e01402b1SRalf Baechle 
121e01402b1SRalf Baechle 	/* The list of vpe's */
122e01402b1SRalf Baechle 	struct list_head list;
123e01402b1SRalf Baechle 
124e01402b1SRalf Baechle 	/* shared symbol address */
125e01402b1SRalf Baechle 	void *shared_ptr;
1262600990eSRalf Baechle 
1272600990eSRalf Baechle 	/* the list of who wants to know when something major happens */
1282600990eSRalf Baechle 	struct list_head notify;
129307bd284SRalf Baechle };
130307bd284SRalf Baechle 
131307bd284SRalf Baechle struct tc {
132307bd284SRalf Baechle 	enum tc_state state;
133307bd284SRalf Baechle 	int index;
134307bd284SRalf Baechle 
13507cc0c9eSRalf Baechle 	struct vpe *pvpe;	/* parent VPE */
13607cc0c9eSRalf Baechle 	struct list_head tc;	/* The list of TC's with this VPE */
13707cc0c9eSRalf Baechle 	struct list_head list;	/* The global list of tc's */
138307bd284SRalf Baechle };
139e01402b1SRalf Baechle 
1409cfdf6f1SRalf Baechle struct {
141e01402b1SRalf Baechle 	/* Virtual processing elements */
142e01402b1SRalf Baechle 	struct list_head vpe_list;
143e01402b1SRalf Baechle 
144e01402b1SRalf Baechle 	/* Thread contexts */
145e01402b1SRalf Baechle 	struct list_head tc_list;
1469cfdf6f1SRalf Baechle } vpecontrol = {
1479cfdf6f1SRalf Baechle 	.vpe_list = LIST_HEAD_INIT(vpecontrol.vpe_list),
1489cfdf6f1SRalf Baechle 	.tc_list = LIST_HEAD_INIT(vpecontrol.tc_list)
1499cfdf6f1SRalf Baechle };
150e01402b1SRalf Baechle 
151e01402b1SRalf Baechle static void release_progmem(void *ptr);
152e01402b1SRalf Baechle extern void save_gp_address(unsigned int secbase, unsigned int rel);
153e01402b1SRalf Baechle 
154e01402b1SRalf Baechle /* get the vpe associated with this minor */
155e01402b1SRalf Baechle struct vpe *get_vpe(int minor)
156e01402b1SRalf Baechle {
157e01402b1SRalf Baechle 	struct vpe *v;
158e01402b1SRalf Baechle 
1592600990eSRalf Baechle 	if (!cpu_has_mipsmt)
1602600990eSRalf Baechle 		return NULL;
1612600990eSRalf Baechle 
162e01402b1SRalf Baechle 	list_for_each_entry(v, &vpecontrol.vpe_list, list) {
163e01402b1SRalf Baechle 		if (v->minor == minor)
164e01402b1SRalf Baechle 			return v;
165e01402b1SRalf Baechle 	}
166e01402b1SRalf Baechle 
167e01402b1SRalf Baechle 	return NULL;
168e01402b1SRalf Baechle }
169e01402b1SRalf Baechle 
170e01402b1SRalf Baechle /* get the vpe associated with this minor */
171e01402b1SRalf Baechle struct tc *get_tc(int index)
172e01402b1SRalf Baechle {
173e01402b1SRalf Baechle 	struct tc *t;
174e01402b1SRalf Baechle 
175e01402b1SRalf Baechle 	list_for_each_entry(t, &vpecontrol.tc_list, list) {
176e01402b1SRalf Baechle 		if (t->index == index)
177e01402b1SRalf Baechle 			return t;
178e01402b1SRalf Baechle 	}
179e01402b1SRalf Baechle 
180e01402b1SRalf Baechle 	return NULL;
181e01402b1SRalf Baechle }
182e01402b1SRalf Baechle 
183e01402b1SRalf Baechle struct tc *get_tc_unused(void)
184e01402b1SRalf Baechle {
185e01402b1SRalf Baechle 	struct tc *t;
186e01402b1SRalf Baechle 
187e01402b1SRalf Baechle 	list_for_each_entry(t, &vpecontrol.tc_list, list) {
188e01402b1SRalf Baechle 		if (t->state == TC_STATE_UNUSED)
189e01402b1SRalf Baechle 			return t;
190e01402b1SRalf Baechle 	}
191e01402b1SRalf Baechle 
192e01402b1SRalf Baechle 	return NULL;
193e01402b1SRalf Baechle }
194e01402b1SRalf Baechle 
195e01402b1SRalf Baechle /* allocate a vpe and associate it with this minor (or index) */
196e01402b1SRalf Baechle struct vpe *alloc_vpe(int minor)
197e01402b1SRalf Baechle {
198e01402b1SRalf Baechle 	struct vpe *v;
199e01402b1SRalf Baechle 
200307bd284SRalf Baechle 	if ((v = kzalloc(sizeof(struct vpe), GFP_KERNEL)) == NULL) {
201e01402b1SRalf Baechle 		return NULL;
202e01402b1SRalf Baechle 	}
203e01402b1SRalf Baechle 
204e01402b1SRalf Baechle 	INIT_LIST_HEAD(&v->tc);
205e01402b1SRalf Baechle 	list_add_tail(&v->list, &vpecontrol.vpe_list);
206e01402b1SRalf Baechle 
2072600990eSRalf Baechle 	INIT_LIST_HEAD(&v->notify);
208e01402b1SRalf Baechle 	v->minor = minor;
209e01402b1SRalf Baechle 	return v;
210e01402b1SRalf Baechle }
211e01402b1SRalf Baechle 
212e01402b1SRalf Baechle /* allocate a tc. At startup only tc0 is running, all other can be halted. */
213e01402b1SRalf Baechle struct tc *alloc_tc(int index)
214e01402b1SRalf Baechle {
21507cc0c9eSRalf Baechle 	struct tc *tc;
216e01402b1SRalf Baechle 
21707cc0c9eSRalf Baechle 	if ((tc = kzalloc(sizeof(struct tc), GFP_KERNEL)) == NULL)
21807cc0c9eSRalf Baechle 		goto out;
219e01402b1SRalf Baechle 
22007cc0c9eSRalf Baechle 	INIT_LIST_HEAD(&tc->tc);
22107cc0c9eSRalf Baechle 	tc->index = index;
22207cc0c9eSRalf Baechle 	list_add_tail(&tc->list, &vpecontrol.tc_list);
223e01402b1SRalf Baechle 
22407cc0c9eSRalf Baechle out:
22507cc0c9eSRalf Baechle 	return tc;
226e01402b1SRalf Baechle }
227e01402b1SRalf Baechle 
228e01402b1SRalf Baechle /* clean up and free everything */
229e01402b1SRalf Baechle void release_vpe(struct vpe *v)
230e01402b1SRalf Baechle {
231e01402b1SRalf Baechle 	list_del(&v->list);
232e01402b1SRalf Baechle 	if (v->load_addr)
233e01402b1SRalf Baechle 		release_progmem(v);
234e01402b1SRalf Baechle 	kfree(v);
235e01402b1SRalf Baechle }
236e01402b1SRalf Baechle 
237e01402b1SRalf Baechle void dump_mtregs(void)
238e01402b1SRalf Baechle {
239e01402b1SRalf Baechle 	unsigned long val;
240e01402b1SRalf Baechle 
241e01402b1SRalf Baechle 	val = read_c0_config3();
242e01402b1SRalf Baechle 	printk("config3 0x%lx MT %ld\n", val,
243e01402b1SRalf Baechle 	       (val & CONFIG3_MT) >> CONFIG3_MT_SHIFT);
244e01402b1SRalf Baechle 
245e01402b1SRalf Baechle 	val = read_c0_mvpcontrol();
246e01402b1SRalf Baechle 	printk("MVPControl 0x%lx, STLB %ld VPC %ld EVP %ld\n", val,
247e01402b1SRalf Baechle 	       (val & MVPCONTROL_STLB) >> MVPCONTROL_STLB_SHIFT,
248e01402b1SRalf Baechle 	       (val & MVPCONTROL_VPC) >> MVPCONTROL_VPC_SHIFT,
249e01402b1SRalf Baechle 	       (val & MVPCONTROL_EVP));
250e01402b1SRalf Baechle 
2512600990eSRalf Baechle 	val = read_c0_mvpconf0();
2522600990eSRalf Baechle 	printk("mvpconf0 0x%lx, PVPE %ld PTC %ld M %ld\n", val,
2532600990eSRalf Baechle 	       (val & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT,
2542600990eSRalf Baechle 	       val & MVPCONF0_PTC, (val & MVPCONF0_M) >> MVPCONF0_M_SHIFT);
255e01402b1SRalf Baechle }
256e01402b1SRalf Baechle 
257e01402b1SRalf Baechle /* Find some VPE program space  */
258571e0bedSRalf Baechle static void *alloc_progmem(unsigned long len)
259e01402b1SRalf Baechle {
260e01402b1SRalf Baechle #ifdef CONFIG_MIPS_VPE_LOADER_TOM
261e01402b1SRalf Baechle 	/* this means you must tell linux to use less memory than you physically have */
262571e0bedSRalf Baechle 	return pfn_to_kaddr(max_pfn);
263e01402b1SRalf Baechle #else
264e01402b1SRalf Baechle 	// simple grab some mem for now
265e01402b1SRalf Baechle 	return kmalloc(len, GFP_KERNEL);
266e01402b1SRalf Baechle #endif
267e01402b1SRalf Baechle }
268e01402b1SRalf Baechle 
269e01402b1SRalf Baechle static void release_progmem(void *ptr)
270e01402b1SRalf Baechle {
271e01402b1SRalf Baechle #ifndef CONFIG_MIPS_VPE_LOADER_TOM
272e01402b1SRalf Baechle 	kfree(ptr);
273e01402b1SRalf Baechle #endif
274e01402b1SRalf Baechle }
275e01402b1SRalf Baechle 
276e01402b1SRalf Baechle /* Update size with this section: return offset. */
277e01402b1SRalf Baechle static long get_offset(unsigned long *size, Elf_Shdr * sechdr)
278e01402b1SRalf Baechle {
279e01402b1SRalf Baechle 	long ret;
280e01402b1SRalf Baechle 
281e01402b1SRalf Baechle 	ret = ALIGN(*size, sechdr->sh_addralign ? : 1);
282e01402b1SRalf Baechle 	*size = ret + sechdr->sh_size;
283e01402b1SRalf Baechle 	return ret;
284e01402b1SRalf Baechle }
285e01402b1SRalf Baechle 
286e01402b1SRalf Baechle /* Lay out the SHF_ALLOC sections in a way not dissimilar to how ld
287e01402b1SRalf Baechle    might -- code, read-only data, read-write data, small data.  Tally
288e01402b1SRalf Baechle    sizes, and place the offsets into sh_entsize fields: high bit means it
289e01402b1SRalf Baechle    belongs in init. */
290e01402b1SRalf Baechle static void layout_sections(struct module *mod, const Elf_Ehdr * hdr,
291e01402b1SRalf Baechle 			    Elf_Shdr * sechdrs, const char *secstrings)
292e01402b1SRalf Baechle {
293e01402b1SRalf Baechle 	static unsigned long const masks[][2] = {
294e01402b1SRalf Baechle 		/* NOTE: all executable code must be the first section
295e01402b1SRalf Baechle 		 * in this array; otherwise modify the text_size
296e01402b1SRalf Baechle 		 * finder in the two loops below */
297e01402b1SRalf Baechle 		{SHF_EXECINSTR | SHF_ALLOC, ARCH_SHF_SMALL},
298e01402b1SRalf Baechle 		{SHF_ALLOC, SHF_WRITE | ARCH_SHF_SMALL},
299e01402b1SRalf Baechle 		{SHF_WRITE | SHF_ALLOC, ARCH_SHF_SMALL},
300e01402b1SRalf Baechle 		{ARCH_SHF_SMALL | SHF_ALLOC, 0}
301e01402b1SRalf Baechle 	};
302e01402b1SRalf Baechle 	unsigned int m, i;
303e01402b1SRalf Baechle 
304e01402b1SRalf Baechle 	for (i = 0; i < hdr->e_shnum; i++)
305e01402b1SRalf Baechle 		sechdrs[i].sh_entsize = ~0UL;
306e01402b1SRalf Baechle 
307e01402b1SRalf Baechle 	for (m = 0; m < ARRAY_SIZE(masks); ++m) {
308e01402b1SRalf Baechle 		for (i = 0; i < hdr->e_shnum; ++i) {
309e01402b1SRalf Baechle 			Elf_Shdr *s = &sechdrs[i];
310e01402b1SRalf Baechle 
311e01402b1SRalf Baechle 			//  || strncmp(secstrings + s->sh_name, ".init", 5) == 0)
312e01402b1SRalf Baechle 			if ((s->sh_flags & masks[m][0]) != masks[m][0]
313e01402b1SRalf Baechle 			    || (s->sh_flags & masks[m][1])
314e01402b1SRalf Baechle 			    || s->sh_entsize != ~0UL)
315e01402b1SRalf Baechle 				continue;
316e01402b1SRalf Baechle 			s->sh_entsize = get_offset(&mod->core_size, s);
317e01402b1SRalf Baechle 		}
318e01402b1SRalf Baechle 
319e01402b1SRalf Baechle 		if (m == 0)
320e01402b1SRalf Baechle 			mod->core_text_size = mod->core_size;
321e01402b1SRalf Baechle 
322e01402b1SRalf Baechle 	}
323e01402b1SRalf Baechle }
324e01402b1SRalf Baechle 
325e01402b1SRalf Baechle 
326e01402b1SRalf Baechle /* from module-elf32.c, but subverted a little */
327e01402b1SRalf Baechle 
328e01402b1SRalf Baechle struct mips_hi16 {
329e01402b1SRalf Baechle 	struct mips_hi16 *next;
330e01402b1SRalf Baechle 	Elf32_Addr *addr;
331e01402b1SRalf Baechle 	Elf32_Addr value;
332e01402b1SRalf Baechle };
333e01402b1SRalf Baechle 
334e01402b1SRalf Baechle static struct mips_hi16 *mips_hi16_list;
335e01402b1SRalf Baechle static unsigned int gp_offs, gp_addr;
336e01402b1SRalf Baechle 
337e01402b1SRalf Baechle static int apply_r_mips_none(struct module *me, uint32_t *location,
338e01402b1SRalf Baechle 			     Elf32_Addr v)
339e01402b1SRalf Baechle {
340e01402b1SRalf Baechle 	return 0;
341e01402b1SRalf Baechle }
342e01402b1SRalf Baechle 
343e01402b1SRalf Baechle static int apply_r_mips_gprel16(struct module *me, uint32_t *location,
344e01402b1SRalf Baechle 				Elf32_Addr v)
345e01402b1SRalf Baechle {
346e01402b1SRalf Baechle 	int rel;
347e01402b1SRalf Baechle 
348e01402b1SRalf Baechle 	if( !(*location & 0xffff) ) {
349e01402b1SRalf Baechle 		rel = (int)v - gp_addr;
350e01402b1SRalf Baechle 	}
351e01402b1SRalf Baechle 	else {
352e01402b1SRalf Baechle 		/* .sbss + gp(relative) + offset */
353e01402b1SRalf Baechle 		/* kludge! */
354e01402b1SRalf Baechle 		rel =  (int)(short)((int)v + gp_offs +
355e01402b1SRalf Baechle 				    (int)(short)(*location & 0xffff) - gp_addr);
356e01402b1SRalf Baechle 	}
357e01402b1SRalf Baechle 
358e01402b1SRalf Baechle 	if( (rel > 32768) || (rel < -32768) ) {
3592600990eSRalf Baechle 		printk(KERN_DEBUG "VPE loader: apply_r_mips_gprel16: "
3602600990eSRalf Baechle 		       "relative address 0x%x out of range of gp register\n",
3612600990eSRalf Baechle 		       rel);
362e01402b1SRalf Baechle 		return -ENOEXEC;
363e01402b1SRalf Baechle 	}
364e01402b1SRalf Baechle 
365e01402b1SRalf Baechle 	*location = (*location & 0xffff0000) | (rel & 0xffff);
366e01402b1SRalf Baechle 
367e01402b1SRalf Baechle 	return 0;
368e01402b1SRalf Baechle }
369e01402b1SRalf Baechle 
370e01402b1SRalf Baechle static int apply_r_mips_pc16(struct module *me, uint32_t *location,
371e01402b1SRalf Baechle 			     Elf32_Addr v)
372e01402b1SRalf Baechle {
373e01402b1SRalf Baechle 	int rel;
374e01402b1SRalf Baechle 	rel = (((unsigned int)v - (unsigned int)location));
375e01402b1SRalf Baechle 	rel >>= 2;		// because the offset is in _instructions_ not bytes.
376e01402b1SRalf Baechle 	rel -= 1;		// and one instruction less due to the branch delay slot.
377e01402b1SRalf Baechle 
378e01402b1SRalf Baechle 	if( (rel > 32768) || (rel < -32768) ) {
3792600990eSRalf Baechle 		printk(KERN_DEBUG "VPE loader: "
380e01402b1SRalf Baechle  		       "apply_r_mips_pc16: relative address out of range 0x%x\n", rel);
381e01402b1SRalf Baechle 		return -ENOEXEC;
382e01402b1SRalf Baechle 	}
383e01402b1SRalf Baechle 
384e01402b1SRalf Baechle 	*location = (*location & 0xffff0000) | (rel & 0xffff);
385e01402b1SRalf Baechle 
386e01402b1SRalf Baechle 	return 0;
387e01402b1SRalf Baechle }
388e01402b1SRalf Baechle 
389e01402b1SRalf Baechle static int apply_r_mips_32(struct module *me, uint32_t *location,
390e01402b1SRalf Baechle 			   Elf32_Addr v)
391e01402b1SRalf Baechle {
392e01402b1SRalf Baechle 	*location += v;
393e01402b1SRalf Baechle 
394e01402b1SRalf Baechle 	return 0;
395e01402b1SRalf Baechle }
396e01402b1SRalf Baechle 
397e01402b1SRalf Baechle static int apply_r_mips_26(struct module *me, uint32_t *location,
398e01402b1SRalf Baechle 			   Elf32_Addr v)
399e01402b1SRalf Baechle {
400e01402b1SRalf Baechle 	if (v % 4) {
4012600990eSRalf Baechle 		printk(KERN_DEBUG "VPE loader: apply_r_mips_26 "
4022600990eSRalf Baechle 		       " unaligned relocation\n");
403e01402b1SRalf Baechle 		return -ENOEXEC;
404e01402b1SRalf Baechle 	}
405e01402b1SRalf Baechle 
406307bd284SRalf Baechle /*
407307bd284SRalf Baechle  * Not desperately convinced this is a good check of an overflow condition
408307bd284SRalf Baechle  * anyway. But it gets in the way of handling undefined weak symbols which
409307bd284SRalf Baechle  * we want to set to zero.
410307bd284SRalf Baechle  * if ((v & 0xf0000000) != (((unsigned long)location + 4) & 0xf0000000)) {
411307bd284SRalf Baechle  * printk(KERN_ERR
412307bd284SRalf Baechle  * "module %s: relocation overflow\n",
413307bd284SRalf Baechle  * me->name);
414307bd284SRalf Baechle  * return -ENOEXEC;
415307bd284SRalf Baechle  * }
416e01402b1SRalf Baechle  */
417e01402b1SRalf Baechle 
418e01402b1SRalf Baechle 	*location = (*location & ~0x03ffffff) |
419e01402b1SRalf Baechle 		((*location + (v >> 2)) & 0x03ffffff);
420e01402b1SRalf Baechle 	return 0;
421e01402b1SRalf Baechle }
422e01402b1SRalf Baechle 
423e01402b1SRalf Baechle static int apply_r_mips_hi16(struct module *me, uint32_t *location,
424e01402b1SRalf Baechle 			     Elf32_Addr v)
425e01402b1SRalf Baechle {
426e01402b1SRalf Baechle 	struct mips_hi16 *n;
427e01402b1SRalf Baechle 
428e01402b1SRalf Baechle 	/*
429e01402b1SRalf Baechle 	 * We cannot relocate this one now because we don't know the value of
430e01402b1SRalf Baechle 	 * the carry we need to add.  Save the information, and let LO16 do the
431e01402b1SRalf Baechle 	 * actual relocation.
432e01402b1SRalf Baechle 	 */
433e01402b1SRalf Baechle 	n = kmalloc(sizeof *n, GFP_KERNEL);
434e01402b1SRalf Baechle 	if (!n)
435e01402b1SRalf Baechle 		return -ENOMEM;
436e01402b1SRalf Baechle 
437e01402b1SRalf Baechle 	n->addr = location;
438e01402b1SRalf Baechle 	n->value = v;
439e01402b1SRalf Baechle 	n->next = mips_hi16_list;
440e01402b1SRalf Baechle 	mips_hi16_list = n;
441e01402b1SRalf Baechle 
442e01402b1SRalf Baechle 	return 0;
443e01402b1SRalf Baechle }
444e01402b1SRalf Baechle 
445e01402b1SRalf Baechle static int apply_r_mips_lo16(struct module *me, uint32_t *location,
446e01402b1SRalf Baechle 			     Elf32_Addr v)
447e01402b1SRalf Baechle {
448e01402b1SRalf Baechle 	unsigned long insnlo = *location;
449e01402b1SRalf Baechle 	Elf32_Addr val, vallo;
450e01402b1SRalf Baechle 
451e01402b1SRalf Baechle 	/* Sign extend the addend we extract from the lo insn.  */
452e01402b1SRalf Baechle 	vallo = ((insnlo & 0xffff) ^ 0x8000) - 0x8000;
453e01402b1SRalf Baechle 
454e01402b1SRalf Baechle 	if (mips_hi16_list != NULL) {
455e01402b1SRalf Baechle 		struct mips_hi16 *l;
456e01402b1SRalf Baechle 
457e01402b1SRalf Baechle 		l = mips_hi16_list;
458e01402b1SRalf Baechle 		while (l != NULL) {
459e01402b1SRalf Baechle 			struct mips_hi16 *next;
460e01402b1SRalf Baechle 			unsigned long insn;
461e01402b1SRalf Baechle 
462e01402b1SRalf Baechle 			/*
463e01402b1SRalf Baechle 			 * The value for the HI16 had best be the same.
464e01402b1SRalf Baechle 			 */
465e01402b1SRalf Baechle  			if (v != l->value) {
4662600990eSRalf Baechle 				printk(KERN_DEBUG "VPE loader: "
4672600990eSRalf Baechle 				       "apply_r_mips_lo16/hi16: 	"
4682600990eSRalf Baechle 				       "inconsistent value information\n");
4692600990eSRalf Baechle 				return -ENOEXEC;
470e01402b1SRalf Baechle 			}
471e01402b1SRalf Baechle 
472e01402b1SRalf Baechle 			/*
473e01402b1SRalf Baechle 			 * Do the HI16 relocation.  Note that we actually don't
474e01402b1SRalf Baechle 			 * need to know anything about the LO16 itself, except
475e01402b1SRalf Baechle 			 * where to find the low 16 bits of the addend needed
476e01402b1SRalf Baechle 			 * by the LO16.
477e01402b1SRalf Baechle 			 */
478e01402b1SRalf Baechle 			insn = *l->addr;
479e01402b1SRalf Baechle 			val = ((insn & 0xffff) << 16) + vallo;
480e01402b1SRalf Baechle 			val += v;
481e01402b1SRalf Baechle 
482e01402b1SRalf Baechle 			/*
483e01402b1SRalf Baechle 			 * Account for the sign extension that will happen in
484e01402b1SRalf Baechle 			 * the low bits.
485e01402b1SRalf Baechle 			 */
486e01402b1SRalf Baechle 			val = ((val >> 16) + ((val & 0x8000) != 0)) & 0xffff;
487e01402b1SRalf Baechle 
488e01402b1SRalf Baechle 			insn = (insn & ~0xffff) | val;
489e01402b1SRalf Baechle 			*l->addr = insn;
490e01402b1SRalf Baechle 
491e01402b1SRalf Baechle 			next = l->next;
492e01402b1SRalf Baechle 			kfree(l);
493e01402b1SRalf Baechle 			l = next;
494e01402b1SRalf Baechle 		}
495e01402b1SRalf Baechle 
496e01402b1SRalf Baechle 		mips_hi16_list = NULL;
497e01402b1SRalf Baechle 	}
498e01402b1SRalf Baechle 
499e01402b1SRalf Baechle 	/*
500e01402b1SRalf Baechle 	 * Ok, we're done with the HI16 relocs.  Now deal with the LO16.
501e01402b1SRalf Baechle 	 */
502e01402b1SRalf Baechle 	val = v + vallo;
503e01402b1SRalf Baechle 	insnlo = (insnlo & ~0xffff) | (val & 0xffff);
504e01402b1SRalf Baechle 	*location = insnlo;
505e01402b1SRalf Baechle 
506e01402b1SRalf Baechle 	return 0;
507e01402b1SRalf Baechle }
508e01402b1SRalf Baechle 
509e01402b1SRalf Baechle static int (*reloc_handlers[]) (struct module *me, uint32_t *location,
510e01402b1SRalf Baechle 				Elf32_Addr v) = {
511e01402b1SRalf Baechle 	[R_MIPS_NONE]	= apply_r_mips_none,
512e01402b1SRalf Baechle 	[R_MIPS_32]	= apply_r_mips_32,
513e01402b1SRalf Baechle 	[R_MIPS_26]	= apply_r_mips_26,
514e01402b1SRalf Baechle 	[R_MIPS_HI16]	= apply_r_mips_hi16,
515e01402b1SRalf Baechle 	[R_MIPS_LO16]	= apply_r_mips_lo16,
516e01402b1SRalf Baechle 	[R_MIPS_GPREL16] = apply_r_mips_gprel16,
517e01402b1SRalf Baechle 	[R_MIPS_PC16] = apply_r_mips_pc16
518e01402b1SRalf Baechle };
519e01402b1SRalf Baechle 
5202600990eSRalf Baechle static char *rstrs[] = {
5212600990eSRalf Baechle 	[R_MIPS_NONE]	= "MIPS_NONE",
5222600990eSRalf Baechle 	[R_MIPS_32]	= "MIPS_32",
5232600990eSRalf Baechle 	[R_MIPS_26]	= "MIPS_26",
5242600990eSRalf Baechle 	[R_MIPS_HI16]	= "MIPS_HI16",
5252600990eSRalf Baechle 	[R_MIPS_LO16]	= "MIPS_LO16",
5262600990eSRalf Baechle 	[R_MIPS_GPREL16] = "MIPS_GPREL16",
5272600990eSRalf Baechle 	[R_MIPS_PC16] = "MIPS_PC16"
5282600990eSRalf Baechle };
529e01402b1SRalf Baechle 
530e01402b1SRalf Baechle int apply_relocations(Elf32_Shdr *sechdrs,
531e01402b1SRalf Baechle 		      const char *strtab,
532e01402b1SRalf Baechle 		      unsigned int symindex,
533e01402b1SRalf Baechle 		      unsigned int relsec,
534e01402b1SRalf Baechle 		      struct module *me)
535e01402b1SRalf Baechle {
536e01402b1SRalf Baechle 	Elf32_Rel *rel = (void *) sechdrs[relsec].sh_addr;
537e01402b1SRalf Baechle 	Elf32_Sym *sym;
538e01402b1SRalf Baechle 	uint32_t *location;
539e01402b1SRalf Baechle 	unsigned int i;
540e01402b1SRalf Baechle 	Elf32_Addr v;
541e01402b1SRalf Baechle 	int res;
542e01402b1SRalf Baechle 
543e01402b1SRalf Baechle 	for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
544e01402b1SRalf Baechle 		Elf32_Word r_info = rel[i].r_info;
545e01402b1SRalf Baechle 
546e01402b1SRalf Baechle 		/* This is where to make the change */
547e01402b1SRalf Baechle 		location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
548e01402b1SRalf Baechle 			+ rel[i].r_offset;
549e01402b1SRalf Baechle 		/* This is the symbol it is referring to */
550e01402b1SRalf Baechle 		sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
551e01402b1SRalf Baechle 			+ ELF32_R_SYM(r_info);
552e01402b1SRalf Baechle 
553e01402b1SRalf Baechle 		if (!sym->st_value) {
554e01402b1SRalf Baechle 			printk(KERN_DEBUG "%s: undefined weak symbol %s\n",
555e01402b1SRalf Baechle 			       me->name, strtab + sym->st_name);
556e01402b1SRalf Baechle 			/* just print the warning, dont barf */
557e01402b1SRalf Baechle 		}
558e01402b1SRalf Baechle 
559e01402b1SRalf Baechle 		v = sym->st_value;
560e01402b1SRalf Baechle 
561e01402b1SRalf Baechle 		res = reloc_handlers[ELF32_R_TYPE(r_info)](me, location, v);
562e01402b1SRalf Baechle 		if( res ) {
5632600990eSRalf Baechle 			char *r = rstrs[ELF32_R_TYPE(r_info)];
5642600990eSRalf Baechle 		    	printk(KERN_WARNING "VPE loader: .text+0x%x "
5652600990eSRalf Baechle 			       "relocation type %s for symbol \"%s\" failed\n",
5662600990eSRalf Baechle 			       rel[i].r_offset, r ? r : "UNKNOWN",
5672600990eSRalf Baechle 			       strtab + sym->st_name);
568e01402b1SRalf Baechle 			return res;
569e01402b1SRalf Baechle 		}
5702600990eSRalf Baechle 	}
571e01402b1SRalf Baechle 
572e01402b1SRalf Baechle 	return 0;
573e01402b1SRalf Baechle }
574e01402b1SRalf Baechle 
575e01402b1SRalf Baechle void save_gp_address(unsigned int secbase, unsigned int rel)
576e01402b1SRalf Baechle {
577e01402b1SRalf Baechle 	gp_addr = secbase + rel;
578e01402b1SRalf Baechle 	gp_offs = gp_addr - (secbase & 0xffff0000);
579e01402b1SRalf Baechle }
580e01402b1SRalf Baechle /* end module-elf32.c */
581e01402b1SRalf Baechle 
582e01402b1SRalf Baechle 
583e01402b1SRalf Baechle 
584e01402b1SRalf Baechle /* Change all symbols so that sh_value encodes the pointer directly. */
5852600990eSRalf Baechle static void simplify_symbols(Elf_Shdr * sechdrs,
586e01402b1SRalf Baechle 			    unsigned int symindex,
587e01402b1SRalf Baechle 			    const char *strtab,
588e01402b1SRalf Baechle 			    const char *secstrings,
589e01402b1SRalf Baechle 			    unsigned int nsecs, struct module *mod)
590e01402b1SRalf Baechle {
591e01402b1SRalf Baechle 	Elf_Sym *sym = (void *)sechdrs[symindex].sh_addr;
592e01402b1SRalf Baechle 	unsigned long secbase, bssbase = 0;
593e01402b1SRalf Baechle 	unsigned int i, n = sechdrs[symindex].sh_size / sizeof(Elf_Sym);
5942600990eSRalf Baechle 	int size;
595e01402b1SRalf Baechle 
596e01402b1SRalf Baechle 	/* find the .bss section for COMMON symbols */
597e01402b1SRalf Baechle 	for (i = 0; i < nsecs; i++) {
5982600990eSRalf Baechle 		if (strncmp(secstrings + sechdrs[i].sh_name, ".bss", 4) == 0) {
599e01402b1SRalf Baechle 			bssbase = sechdrs[i].sh_addr;
6002600990eSRalf Baechle 			break;
6012600990eSRalf Baechle 		}
602e01402b1SRalf Baechle 	}
603e01402b1SRalf Baechle 
604e01402b1SRalf Baechle 	for (i = 1; i < n; i++) {
605e01402b1SRalf Baechle 		switch (sym[i].st_shndx) {
606e01402b1SRalf Baechle 		case SHN_COMMON:
6072600990eSRalf Baechle 			/* Allocate space for the symbol in the .bss section.
6082600990eSRalf Baechle 			   st_value is currently size.
609e01402b1SRalf Baechle 			   We want it to have the address of the symbol. */
610e01402b1SRalf Baechle 
611e01402b1SRalf Baechle 			size = sym[i].st_value;
612e01402b1SRalf Baechle 			sym[i].st_value = bssbase;
613e01402b1SRalf Baechle 
614e01402b1SRalf Baechle 			bssbase += size;
615e01402b1SRalf Baechle 			break;
616e01402b1SRalf Baechle 
617e01402b1SRalf Baechle 		case SHN_ABS:
618e01402b1SRalf Baechle 			/* Don't need to do anything */
619e01402b1SRalf Baechle 			break;
620e01402b1SRalf Baechle 
621e01402b1SRalf Baechle 		case SHN_UNDEF:
622e01402b1SRalf Baechle 			/* ret = -ENOENT; */
623e01402b1SRalf Baechle 			break;
624e01402b1SRalf Baechle 
625e01402b1SRalf Baechle 		case SHN_MIPS_SCOMMON:
6262600990eSRalf Baechle 			printk(KERN_DEBUG "simplify_symbols: ignoring SHN_MIPS_SCOMMON"
6272600990eSRalf Baechle 			       "symbol <%s> st_shndx %d\n", strtab + sym[i].st_name,
6282600990eSRalf Baechle 			       sym[i].st_shndx);
629e01402b1SRalf Baechle 			// .sbss section
630e01402b1SRalf Baechle 			break;
631e01402b1SRalf Baechle 
632e01402b1SRalf Baechle 		default:
633e01402b1SRalf Baechle 			secbase = sechdrs[sym[i].st_shndx].sh_addr;
634e01402b1SRalf Baechle 
635e01402b1SRalf Baechle 			if (strncmp(strtab + sym[i].st_name, "_gp", 3) == 0) {
636e01402b1SRalf Baechle 				save_gp_address(secbase, sym[i].st_value);
637e01402b1SRalf Baechle 			}
638e01402b1SRalf Baechle 
639e01402b1SRalf Baechle 			sym[i].st_value += secbase;
640e01402b1SRalf Baechle 			break;
641e01402b1SRalf Baechle 		}
642e01402b1SRalf Baechle 	}
643e01402b1SRalf Baechle }
644e01402b1SRalf Baechle 
645e01402b1SRalf Baechle #ifdef DEBUG_ELFLOADER
646e01402b1SRalf Baechle static void dump_elfsymbols(Elf_Shdr * sechdrs, unsigned int symindex,
647e01402b1SRalf Baechle 			    const char *strtab, struct module *mod)
648e01402b1SRalf Baechle {
649e01402b1SRalf Baechle 	Elf_Sym *sym = (void *)sechdrs[symindex].sh_addr;
650e01402b1SRalf Baechle 	unsigned int i, n = sechdrs[symindex].sh_size / sizeof(Elf_Sym);
651e01402b1SRalf Baechle 
652e01402b1SRalf Baechle 	printk(KERN_DEBUG "dump_elfsymbols: n %d\n", n);
653e01402b1SRalf Baechle 	for (i = 1; i < n; i++) {
654e01402b1SRalf Baechle 		printk(KERN_DEBUG " i %d name <%s> 0x%x\n", i,
655e01402b1SRalf Baechle 		       strtab + sym[i].st_name, sym[i].st_value);
656e01402b1SRalf Baechle 	}
657e01402b1SRalf Baechle }
658e01402b1SRalf Baechle #endif
659e01402b1SRalf Baechle 
660e01402b1SRalf Baechle /* We are prepared so configure and start the VPE... */
661be6e1437SRalf Baechle static int vpe_run(struct vpe * v)
662e01402b1SRalf Baechle {
66307cc0c9eSRalf Baechle 	unsigned long flags, val, dmt_flag;
6642600990eSRalf Baechle 	struct vpe_notifications *n;
66507cc0c9eSRalf Baechle 	unsigned int vpeflags;
666e01402b1SRalf Baechle 	struct tc *t;
667e01402b1SRalf Baechle 
668e01402b1SRalf Baechle 	/* check we are the Master VPE */
66907cc0c9eSRalf Baechle 	local_irq_save(flags);
670e01402b1SRalf Baechle 	val = read_c0_vpeconf0();
671e01402b1SRalf Baechle 	if (!(val & VPECONF0_MVP)) {
672e01402b1SRalf Baechle 		printk(KERN_WARNING
6732600990eSRalf Baechle 		       "VPE loader: only Master VPE's are allowed to configure MT\n");
67407cc0c9eSRalf Baechle 		local_irq_restore(flags);
67507cc0c9eSRalf Baechle 
676e01402b1SRalf Baechle 		return -1;
677e01402b1SRalf Baechle 	}
678e01402b1SRalf Baechle 
67907cc0c9eSRalf Baechle 	dmt_flag = dmt();
68007cc0c9eSRalf Baechle 	vpeflags = dvpe();
681e01402b1SRalf Baechle 
682e01402b1SRalf Baechle 	if (!list_empty(&v->tc)) {
683e01402b1SRalf Baechle 		if ((t = list_entry(v->tc.next, struct tc, tc)) == NULL) {
68407cc0c9eSRalf Baechle 			evpe(vpeflags);
68507cc0c9eSRalf Baechle 			emt(dmt_flag);
68607cc0c9eSRalf Baechle 			local_irq_restore(flags);
68707cc0c9eSRalf Baechle 
68807cc0c9eSRalf Baechle 			printk(KERN_WARNING
68907cc0c9eSRalf Baechle 			       "VPE loader: TC %d is already in use.\n",
690e01402b1SRalf Baechle                                t->index);
691e01402b1SRalf Baechle 			return -ENOEXEC;
692e01402b1SRalf Baechle 		}
693e01402b1SRalf Baechle 	} else {
69407cc0c9eSRalf Baechle 		evpe(vpeflags);
69507cc0c9eSRalf Baechle 		emt(dmt_flag);
69607cc0c9eSRalf Baechle 		local_irq_restore(flags);
69707cc0c9eSRalf Baechle 
69807cc0c9eSRalf Baechle 		printk(KERN_WARNING
69907cc0c9eSRalf Baechle 		       "VPE loader: No TC's associated with VPE %d\n",
700e01402b1SRalf Baechle 		       v->minor);
70107cc0c9eSRalf Baechle 
702e01402b1SRalf Baechle 		return -ENOEXEC;
703e01402b1SRalf Baechle 	}
704e01402b1SRalf Baechle 
7052600990eSRalf Baechle 	/* Put MVPE's into 'configuration state' */
7062600990eSRalf Baechle 	set_c0_mvpcontrol(MVPCONTROL_VPC);
707e01402b1SRalf Baechle 
7082600990eSRalf Baechle 	settc(t->index);
709e01402b1SRalf Baechle 
710e01402b1SRalf Baechle 	/* should check it is halted, and not activated */
711e01402b1SRalf Baechle 	if ((read_tc_c0_tcstatus() & TCSTATUS_A) || !(read_tc_c0_tchalt() & TCHALT_H)) {
71207cc0c9eSRalf Baechle 		evpe(vpeflags);
71307cc0c9eSRalf Baechle 		emt(dmt_flag);
71407cc0c9eSRalf Baechle 		local_irq_restore(flags);
71507cc0c9eSRalf Baechle 
71607cc0c9eSRalf Baechle 		printk(KERN_WARNING "VPE loader: TC %d is already active!\n",
717e01402b1SRalf Baechle 		       t->index);
71807cc0c9eSRalf Baechle 
719e01402b1SRalf Baechle 		return -ENOEXEC;
720e01402b1SRalf Baechle 	}
721e01402b1SRalf Baechle 
722e01402b1SRalf Baechle 	/* Write the address we want it to start running from in the TCPC register. */
723e01402b1SRalf Baechle 	write_tc_c0_tcrestart((unsigned long)v->__start);
724e01402b1SRalf Baechle 	write_tc_c0_tccontext((unsigned long)0);
72507cc0c9eSRalf Baechle 
7262600990eSRalf Baechle 	/*
7272600990eSRalf Baechle 	 * Mark the TC as activated, not interrupt exempt and not dynamically
7282600990eSRalf Baechle 	 * allocatable
7292600990eSRalf Baechle 	 */
730e01402b1SRalf Baechle 	val = read_tc_c0_tcstatus();
731e01402b1SRalf Baechle 	val = (val & ~(TCSTATUS_DA | TCSTATUS_IXMT)) | TCSTATUS_A;
732e01402b1SRalf Baechle 	write_tc_c0_tcstatus(val);
733e01402b1SRalf Baechle 
734e01402b1SRalf Baechle 	write_tc_c0_tchalt(read_tc_c0_tchalt() & ~TCHALT_H);
735e01402b1SRalf Baechle 
736e01402b1SRalf Baechle 	/*
737e01402b1SRalf Baechle 	 * The sde-kit passes 'memsize' to __start in $a3, so set something
7382600990eSRalf Baechle 	 * here...  Or set $a3 to zero and define DFLT_STACK_SIZE and
739e01402b1SRalf Baechle 	 * DFLT_HEAP_SIZE when you compile your program
740e01402b1SRalf Baechle 	 */
7412600990eSRalf Baechle 	mttgpr(7, physical_memsize);
742e01402b1SRalf Baechle 
7432600990eSRalf Baechle 	/* set up VPE1 */
7442600990eSRalf Baechle 	/*
7452600990eSRalf Baechle 	 * bind the TC to VPE 1 as late as possible so we only have the final
7462600990eSRalf Baechle 	 * VPE registers to set up, and so an EJTAG probe can trigger on it
7472600990eSRalf Baechle 	 */
74807cc0c9eSRalf Baechle 	write_tc_c0_tcbind((read_tc_c0_tcbind() & ~TCBIND_CURVPE) | 1);
7492600990eSRalf Baechle 
750a94d7020SElizabeth Oldham 	write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() & ~(VPECONF0_VPA));
751a94d7020SElizabeth Oldham 
752a94d7020SElizabeth Oldham 	back_to_back_c0_hazard();
753a94d7020SElizabeth Oldham 
7542600990eSRalf Baechle 	/* Set up the XTC bit in vpeconf0 to point at our tc */
7552600990eSRalf Baechle 	write_vpe_c0_vpeconf0( (read_vpe_c0_vpeconf0() & ~(VPECONF0_XTC))
7562600990eSRalf Baechle 	                      | (t->index << VPECONF0_XTC_SHIFT));
7572600990eSRalf Baechle 
758a94d7020SElizabeth Oldham 	back_to_back_c0_hazard();
759a94d7020SElizabeth Oldham 
7602600990eSRalf Baechle 	/* enable this VPE */
7612600990eSRalf Baechle 	write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() | VPECONF0_VPA);
762e01402b1SRalf Baechle 
763e01402b1SRalf Baechle 	/* clear out any left overs from a previous program */
7642600990eSRalf Baechle 	write_vpe_c0_status(0);
765e01402b1SRalf Baechle 	write_vpe_c0_cause(0);
766e01402b1SRalf Baechle 
767e01402b1SRalf Baechle 	/* take system out of configuration state */
768340ee4b9SRalf Baechle 	clear_c0_mvpcontrol(MVPCONTROL_VPC);
769e01402b1SRalf Baechle 
77007cc0c9eSRalf Baechle #ifdef CONFIG_SMP
771e01402b1SRalf Baechle 	evpe(EVPE_ENABLE);
77207cc0c9eSRalf Baechle #else
77307cc0c9eSRalf Baechle 	evpe(vpeflags);
77407cc0c9eSRalf Baechle #endif
77507cc0c9eSRalf Baechle 	emt(dmt_flag);
77607cc0c9eSRalf Baechle 	local_irq_restore(flags);
777e01402b1SRalf Baechle 
77807cc0c9eSRalf Baechle 	list_for_each_entry(n, &v->notify, list)
77907cc0c9eSRalf Baechle 		n->start(minor);
7802600990eSRalf Baechle 
781e01402b1SRalf Baechle 	return 0;
782e01402b1SRalf Baechle }
783e01402b1SRalf Baechle 
7842600990eSRalf Baechle static int find_vpe_symbols(struct vpe * v, Elf_Shdr * sechdrs,
785e01402b1SRalf Baechle 				      unsigned int symindex, const char *strtab,
786e01402b1SRalf Baechle 				      struct module *mod)
787e01402b1SRalf Baechle {
788e01402b1SRalf Baechle 	Elf_Sym *sym = (void *)sechdrs[symindex].sh_addr;
789e01402b1SRalf Baechle 	unsigned int i, n = sechdrs[symindex].sh_size / sizeof(Elf_Sym);
790e01402b1SRalf Baechle 
791e01402b1SRalf Baechle 	for (i = 1; i < n; i++) {
792e01402b1SRalf Baechle 		if (strcmp(strtab + sym[i].st_name, "__start") == 0) {
793e01402b1SRalf Baechle 			v->__start = sym[i].st_value;
794e01402b1SRalf Baechle 		}
795e01402b1SRalf Baechle 
796e01402b1SRalf Baechle 		if (strcmp(strtab + sym[i].st_name, "vpe_shared") == 0) {
797e01402b1SRalf Baechle 			v->shared_ptr = (void *)sym[i].st_value;
798e01402b1SRalf Baechle 		}
799e01402b1SRalf Baechle 	}
800e01402b1SRalf Baechle 
8012600990eSRalf Baechle 	if ( (v->__start == 0) || (v->shared_ptr == NULL))
8022600990eSRalf Baechle 		return -1;
8032600990eSRalf Baechle 
804e01402b1SRalf Baechle 	return 0;
805e01402b1SRalf Baechle }
806e01402b1SRalf Baechle 
807307bd284SRalf Baechle /*
8082600990eSRalf Baechle  * Allocates a VPE with some program code space(the load address), copies the
8092600990eSRalf Baechle  * contents of the program (p)buffer performing relocatations/etc, free's it
8102600990eSRalf Baechle  * when finished.
811e01402b1SRalf Baechle  */
812be6e1437SRalf Baechle static int vpe_elfload(struct vpe * v)
813e01402b1SRalf Baechle {
814e01402b1SRalf Baechle 	Elf_Ehdr *hdr;
815e01402b1SRalf Baechle 	Elf_Shdr *sechdrs;
816e01402b1SRalf Baechle 	long err = 0;
817e01402b1SRalf Baechle 	char *secstrings, *strtab = NULL;
8182600990eSRalf Baechle 	unsigned int len, i, symindex = 0, strindex = 0, relocate = 0;
819e01402b1SRalf Baechle 	struct module mod;	// so we can re-use the relocations code
820e01402b1SRalf Baechle 
821e01402b1SRalf Baechle 	memset(&mod, 0, sizeof(struct module));
8222600990eSRalf Baechle 	strcpy(mod.name, "VPE loader");
823e01402b1SRalf Baechle 
824e01402b1SRalf Baechle 	hdr = (Elf_Ehdr *) v->pbuffer;
825e01402b1SRalf Baechle 	len = v->plen;
826e01402b1SRalf Baechle 
827e01402b1SRalf Baechle 	/* Sanity checks against insmoding binaries or wrong arch,
828e01402b1SRalf Baechle 	   weird elf version */
829e01402b1SRalf Baechle 	if (memcmp(hdr->e_ident, ELFMAG, 4) != 0
8302600990eSRalf Baechle 	    || (hdr->e_type != ET_REL && hdr->e_type != ET_EXEC)
8312600990eSRalf Baechle 	    || !elf_check_arch(hdr)
832e01402b1SRalf Baechle 	    || hdr->e_shentsize != sizeof(*sechdrs)) {
833e01402b1SRalf Baechle 		printk(KERN_WARNING
8342600990eSRalf Baechle 		       "VPE loader: program wrong arch or weird elf version\n");
835e01402b1SRalf Baechle 
836e01402b1SRalf Baechle 		return -ENOEXEC;
837e01402b1SRalf Baechle 	}
838e01402b1SRalf Baechle 
8392600990eSRalf Baechle 	if (hdr->e_type == ET_REL)
8402600990eSRalf Baechle 		relocate = 1;
8412600990eSRalf Baechle 
842e01402b1SRalf Baechle 	if (len < hdr->e_shoff + hdr->e_shnum * sizeof(Elf_Shdr)) {
8432600990eSRalf Baechle 		printk(KERN_ERR "VPE loader: program length %u truncated\n",
8442600990eSRalf Baechle 		       len);
8452600990eSRalf Baechle 
846e01402b1SRalf Baechle 		return -ENOEXEC;
847e01402b1SRalf Baechle 	}
848e01402b1SRalf Baechle 
849e01402b1SRalf Baechle 	/* Convenience variables */
850e01402b1SRalf Baechle 	sechdrs = (void *)hdr + hdr->e_shoff;
851e01402b1SRalf Baechle 	secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
852e01402b1SRalf Baechle 	sechdrs[0].sh_addr = 0;
853e01402b1SRalf Baechle 
854e01402b1SRalf Baechle 	/* And these should exist, but gcc whinges if we don't init them */
855e01402b1SRalf Baechle 	symindex = strindex = 0;
856e01402b1SRalf Baechle 
8572600990eSRalf Baechle 	if (relocate) {
858e01402b1SRalf Baechle 		for (i = 1; i < hdr->e_shnum; i++) {
859e01402b1SRalf Baechle 			if (sechdrs[i].sh_type != SHT_NOBITS
860e01402b1SRalf Baechle 			    && len < sechdrs[i].sh_offset + sechdrs[i].sh_size) {
861e01402b1SRalf Baechle 				printk(KERN_ERR "VPE program length %u truncated\n",
862e01402b1SRalf Baechle 				       len);
863e01402b1SRalf Baechle 				return -ENOEXEC;
864e01402b1SRalf Baechle 			}
865e01402b1SRalf Baechle 
866e01402b1SRalf Baechle 			/* Mark all sections sh_addr with their address in the
867e01402b1SRalf Baechle 			   temporary image. */
868e01402b1SRalf Baechle 			sechdrs[i].sh_addr = (size_t) hdr + sechdrs[i].sh_offset;
869e01402b1SRalf Baechle 
870e01402b1SRalf Baechle 			/* Internal symbols and strings. */
871e01402b1SRalf Baechle 			if (sechdrs[i].sh_type == SHT_SYMTAB) {
872e01402b1SRalf Baechle 				symindex = i;
873e01402b1SRalf Baechle 				strindex = sechdrs[i].sh_link;
874e01402b1SRalf Baechle 				strtab = (char *)hdr + sechdrs[strindex].sh_offset;
875e01402b1SRalf Baechle 			}
876e01402b1SRalf Baechle 		}
877e01402b1SRalf Baechle 		layout_sections(&mod, hdr, sechdrs, secstrings);
8782600990eSRalf Baechle 	}
879e01402b1SRalf Baechle 
880e01402b1SRalf Baechle 	v->load_addr = alloc_progmem(mod.core_size);
881e01402b1SRalf Baechle 	memset(v->load_addr, 0, mod.core_size);
882e01402b1SRalf Baechle 
8832600990eSRalf Baechle 	printk("VPE loader: loading to %p\n", v->load_addr);
884e01402b1SRalf Baechle 
8852600990eSRalf Baechle 	if (relocate) {
886e01402b1SRalf Baechle 		for (i = 0; i < hdr->e_shnum; i++) {
887e01402b1SRalf Baechle 			void *dest;
888e01402b1SRalf Baechle 
889e01402b1SRalf Baechle 			if (!(sechdrs[i].sh_flags & SHF_ALLOC))
890e01402b1SRalf Baechle 				continue;
891e01402b1SRalf Baechle 
892e01402b1SRalf Baechle 			dest = v->load_addr + sechdrs[i].sh_entsize;
893e01402b1SRalf Baechle 
894e01402b1SRalf Baechle 			if (sechdrs[i].sh_type != SHT_NOBITS)
895e01402b1SRalf Baechle 				memcpy(dest, (void *)sechdrs[i].sh_addr,
896e01402b1SRalf Baechle 				       sechdrs[i].sh_size);
897e01402b1SRalf Baechle 			/* Update sh_addr to point to copy in image. */
898e01402b1SRalf Baechle 			sechdrs[i].sh_addr = (unsigned long)dest;
8992600990eSRalf Baechle 
9002600990eSRalf Baechle 			printk(KERN_DEBUG " section sh_name %s sh_addr 0x%x\n",
9012600990eSRalf Baechle 			       secstrings + sechdrs[i].sh_name, sechdrs[i].sh_addr);
902e01402b1SRalf Baechle 		}
903e01402b1SRalf Baechle 
904e01402b1SRalf Baechle  		/* Fix up syms, so that st_value is a pointer to location. */
905e01402b1SRalf Baechle  		simplify_symbols(sechdrs, symindex, strtab, secstrings,
906e01402b1SRalf Baechle  				 hdr->e_shnum, &mod);
907e01402b1SRalf Baechle 
908e01402b1SRalf Baechle  		/* Now do relocations. */
909e01402b1SRalf Baechle  		for (i = 1; i < hdr->e_shnum; i++) {
910e01402b1SRalf Baechle  			const char *strtab = (char *)sechdrs[strindex].sh_addr;
911e01402b1SRalf Baechle  			unsigned int info = sechdrs[i].sh_info;
912e01402b1SRalf Baechle 
913e01402b1SRalf Baechle  			/* Not a valid relocation section? */
914e01402b1SRalf Baechle  			if (info >= hdr->e_shnum)
915e01402b1SRalf Baechle  				continue;
916e01402b1SRalf Baechle 
917e01402b1SRalf Baechle  			/* Don't bother with non-allocated sections */
918e01402b1SRalf Baechle  			if (!(sechdrs[info].sh_flags & SHF_ALLOC))
919e01402b1SRalf Baechle  				continue;
920e01402b1SRalf Baechle 
921e01402b1SRalf Baechle  			if (sechdrs[i].sh_type == SHT_REL)
9222600990eSRalf Baechle  				err = apply_relocations(sechdrs, strtab, symindex, i,
9232600990eSRalf Baechle  							&mod);
924e01402b1SRalf Baechle  			else if (sechdrs[i].sh_type == SHT_RELA)
925e01402b1SRalf Baechle  				err = apply_relocate_add(sechdrs, strtab, symindex, i,
926e01402b1SRalf Baechle  							 &mod);
9272600990eSRalf Baechle  			if (err < 0)
9282600990eSRalf Baechle  				return err;
9292600990eSRalf Baechle 
9302600990eSRalf Baechle   		}
9312600990eSRalf Baechle   	} else {
9322600990eSRalf Baechle   		for (i = 0; i < hdr->e_shnum; i++) {
9332600990eSRalf Baechle 
9342600990eSRalf Baechle  			/* Internal symbols and strings. */
9352600990eSRalf Baechle  			if (sechdrs[i].sh_type == SHT_SYMTAB) {
9362600990eSRalf Baechle  				symindex = i;
9372600990eSRalf Baechle  				strindex = sechdrs[i].sh_link;
9382600990eSRalf Baechle  				strtab = (char *)hdr + sechdrs[strindex].sh_offset;
9392600990eSRalf Baechle 
9402600990eSRalf Baechle  				/* mark the symtab's address for when we try to find the
9412600990eSRalf Baechle  				   magic symbols */
9422600990eSRalf Baechle  				sechdrs[i].sh_addr = (size_t) hdr + sechdrs[i].sh_offset;
9432600990eSRalf Baechle  			}
9442600990eSRalf Baechle 
9452600990eSRalf Baechle  			/* filter sections we dont want in the final image */
9462600990eSRalf Baechle  			if (!(sechdrs[i].sh_flags & SHF_ALLOC) ||
9472600990eSRalf Baechle  			    (sechdrs[i].sh_type == SHT_MIPS_REGINFO)) {
9482600990eSRalf Baechle  				printk( KERN_DEBUG " ignoring section, "
9492600990eSRalf Baechle  					"name %s type %x address 0x%x \n",
9502600990eSRalf Baechle  					secstrings + sechdrs[i].sh_name,
9512600990eSRalf Baechle  					sechdrs[i].sh_type, sechdrs[i].sh_addr);
9522600990eSRalf Baechle  				continue;
9532600990eSRalf Baechle  			}
9542600990eSRalf Baechle 
9552600990eSRalf Baechle   			if (sechdrs[i].sh_addr < (unsigned int)v->load_addr) {
9562600990eSRalf Baechle  				printk( KERN_WARNING "VPE loader: "
9572600990eSRalf Baechle  					"fully linked image has invalid section, "
9582600990eSRalf Baechle  					"name %s type %x address 0x%x, before load "
9592600990eSRalf Baechle  					"address of 0x%x\n",
9602600990eSRalf Baechle  					secstrings + sechdrs[i].sh_name,
9612600990eSRalf Baechle  					sechdrs[i].sh_type, sechdrs[i].sh_addr,
9622600990eSRalf Baechle  					(unsigned int)v->load_addr);
9632600990eSRalf Baechle   				return -ENOEXEC;
9642600990eSRalf Baechle   			}
9652600990eSRalf Baechle 
9662600990eSRalf Baechle  			printk(KERN_DEBUG " copying section sh_name %s, sh_addr 0x%x "
9672600990eSRalf Baechle 			       "size 0x%x0 from x%p\n",
9682600990eSRalf Baechle 			       secstrings + sechdrs[i].sh_name, sechdrs[i].sh_addr,
9692600990eSRalf Baechle 			       sechdrs[i].sh_size, hdr + sechdrs[i].sh_offset);
9702600990eSRalf Baechle 
9712600990eSRalf Baechle   			if (sechdrs[i].sh_type != SHT_NOBITS)
9722600990eSRalf Baechle 				memcpy((void *)sechdrs[i].sh_addr,
9732600990eSRalf Baechle 				       (char *)hdr + sechdrs[i].sh_offset,
9742600990eSRalf Baechle  				       sechdrs[i].sh_size);
9752600990eSRalf Baechle 			else
9762600990eSRalf Baechle 				memset((void *)sechdrs[i].sh_addr, 0, sechdrs[i].sh_size);
977e01402b1SRalf Baechle 		}
978e01402b1SRalf Baechle 	}
979e01402b1SRalf Baechle 
980e01402b1SRalf Baechle 	/* make sure it's physically written out */
981e01402b1SRalf Baechle 	flush_icache_range((unsigned long)v->load_addr,
982e01402b1SRalf Baechle 			   (unsigned long)v->load_addr + v->len);
983e01402b1SRalf Baechle 
984e01402b1SRalf Baechle 	if ((find_vpe_symbols(v, sechdrs, symindex, strtab, &mod)) < 0) {
9852600990eSRalf Baechle 		if (v->__start == 0) {
9862600990eSRalf Baechle 			printk(KERN_WARNING "VPE loader: program does not contain "
9872600990eSRalf Baechle 			       "a __start symbol\n");
9882600990eSRalf Baechle 			return -ENOEXEC;
9892600990eSRalf Baechle 		}
990e01402b1SRalf Baechle 
9912600990eSRalf Baechle 		if (v->shared_ptr == NULL)
9922600990eSRalf Baechle 			printk(KERN_WARNING "VPE loader: "
9932600990eSRalf Baechle 			       "program does not contain vpe_shared symbol.\n"
9942600990eSRalf Baechle 			       " Unable to use AMVP (AP/SP) facilities.\n");
995e01402b1SRalf Baechle 	}
996e01402b1SRalf Baechle 
997e01402b1SRalf Baechle 	printk(" elf loaded\n");
9982600990eSRalf Baechle 	return 0;
999e01402b1SRalf Baechle }
1000e01402b1SRalf Baechle 
10012600990eSRalf Baechle static void cleanup_tc(struct tc *tc)
1002e01402b1SRalf Baechle {
100307cc0c9eSRalf Baechle 	unsigned long flags;
100407cc0c9eSRalf Baechle 	unsigned int mtflags, vpflags;
10052600990eSRalf Baechle 	int tmp;
1006e01402b1SRalf Baechle 
100707cc0c9eSRalf Baechle 	local_irq_save(flags);
100807cc0c9eSRalf Baechle 	mtflags = dmt();
100907cc0c9eSRalf Baechle 	vpflags = dvpe();
10102600990eSRalf Baechle 	/* Put MVPE's into 'configuration state' */
10112600990eSRalf Baechle 	set_c0_mvpcontrol(MVPCONTROL_VPC);
1012e01402b1SRalf Baechle 
10132600990eSRalf Baechle 	settc(tc->index);
1014e01402b1SRalf Baechle 	tmp = read_tc_c0_tcstatus();
1015e01402b1SRalf Baechle 
1016e01402b1SRalf Baechle 	/* mark not allocated and not dynamically allocatable */
1017e01402b1SRalf Baechle 	tmp &= ~(TCSTATUS_A | TCSTATUS_DA);
1018e01402b1SRalf Baechle 	tmp |= TCSTATUS_IXMT;	/* interrupt exempt */
1019e01402b1SRalf Baechle 	write_tc_c0_tcstatus(tmp);
1020e01402b1SRalf Baechle 
1021e01402b1SRalf Baechle 	write_tc_c0_tchalt(TCHALT_H);
1022e01402b1SRalf Baechle 
10232600990eSRalf Baechle 	/* bind it to anything other than VPE1 */
102407cc0c9eSRalf Baechle //	write_tc_c0_tcbind(read_tc_c0_tcbind() & ~TCBIND_CURVPE); // | TCBIND_CURVPE
10252600990eSRalf Baechle 
10262600990eSRalf Baechle 	clear_c0_mvpcontrol(MVPCONTROL_VPC);
102707cc0c9eSRalf Baechle 	evpe(vpflags);
102807cc0c9eSRalf Baechle 	emt(mtflags);
102907cc0c9eSRalf Baechle 	local_irq_restore(flags);
10302600990eSRalf Baechle }
10312600990eSRalf Baechle 
10322600990eSRalf Baechle static int getcwd(char *buff, int size)
10332600990eSRalf Baechle {
10342600990eSRalf Baechle 	mm_segment_t old_fs;
10352600990eSRalf Baechle 	int ret;
10362600990eSRalf Baechle 
10372600990eSRalf Baechle 	old_fs = get_fs();
10382600990eSRalf Baechle 	set_fs(KERNEL_DS);
10392600990eSRalf Baechle 
10402600990eSRalf Baechle 	ret = sys_getcwd(buff,size);
10412600990eSRalf Baechle 
10422600990eSRalf Baechle 	set_fs(old_fs);
10432600990eSRalf Baechle 
10442600990eSRalf Baechle 	return ret;
10452600990eSRalf Baechle }
10462600990eSRalf Baechle 
10472600990eSRalf Baechle /* checks VPE is unused and gets ready to load program  */
10482600990eSRalf Baechle static int vpe_open(struct inode *inode, struct file *filp)
10492600990eSRalf Baechle {
1050c4c4018bSRalf Baechle 	enum vpe_state state;
10512600990eSRalf Baechle 	struct vpe_notifications *not;
105207cc0c9eSRalf Baechle 	struct vpe *v;
105307cc0c9eSRalf Baechle 	int ret;
10542600990eSRalf Baechle 
105507cc0c9eSRalf Baechle 	if (minor != iminor(inode)) {
105607cc0c9eSRalf Baechle 		/* assume only 1 device at the moment. */
10572600990eSRalf Baechle 		printk(KERN_WARNING "VPE loader: only vpe1 is supported\n");
10582600990eSRalf Baechle 		return -ENODEV;
10592600990eSRalf Baechle 	}
10602600990eSRalf Baechle 
106107cc0c9eSRalf Baechle 	if ((v = get_vpe(tclimit)) == NULL) {
10622600990eSRalf Baechle 		printk(KERN_WARNING "VPE loader: unable to get vpe\n");
10632600990eSRalf Baechle 		return -ENODEV;
10642600990eSRalf Baechle 	}
10652600990eSRalf Baechle 
1066c4c4018bSRalf Baechle 	state = xchg(&v->state, VPE_STATE_INUSE);
1067c4c4018bSRalf Baechle 	if (state != VPE_STATE_UNUSED) {
10682600990eSRalf Baechle 		printk(KERN_DEBUG "VPE loader: tc in use dumping regs\n");
10692600990eSRalf Baechle 
10702600990eSRalf Baechle 		list_for_each_entry(not, &v->notify, list) {
107107cc0c9eSRalf Baechle 			not->stop(tclimit);
10722600990eSRalf Baechle 		}
10732600990eSRalf Baechle 
10742600990eSRalf Baechle 		release_progmem(v->load_addr);
107507cc0c9eSRalf Baechle 		cleanup_tc(get_tc(tclimit));
1076e01402b1SRalf Baechle 	}
1077e01402b1SRalf Baechle 
1078e01402b1SRalf Baechle 	/* this of-course trashes what was there before... */
1079e01402b1SRalf Baechle 	v->pbuffer = vmalloc(P_SIZE);
1080e01402b1SRalf Baechle 	v->plen = P_SIZE;
1081e01402b1SRalf Baechle 	v->load_addr = NULL;
1082e01402b1SRalf Baechle 	v->len = 0;
1083e01402b1SRalf Baechle 
10842600990eSRalf Baechle 	v->uid = filp->f_uid;
10852600990eSRalf Baechle 	v->gid = filp->f_gid;
10862600990eSRalf Baechle 
10872600990eSRalf Baechle #ifdef CONFIG_MIPS_APSP_KSPD
10882600990eSRalf Baechle 	/* get kspd to tell us when a syscall_exit happens */
10892600990eSRalf Baechle 	if (!kspd_events_reqd) {
10902600990eSRalf Baechle 		kspd_notify(&kspd_events);
10912600990eSRalf Baechle 		kspd_events_reqd++;
10922600990eSRalf Baechle 	}
10932600990eSRalf Baechle #endif
10942600990eSRalf Baechle 
10952600990eSRalf Baechle 	v->cwd[0] = 0;
10962600990eSRalf Baechle 	ret = getcwd(v->cwd, VPE_PATH_MAX);
10972600990eSRalf Baechle 	if (ret < 0)
10982600990eSRalf Baechle 		printk(KERN_WARNING "VPE loader: open, getcwd returned %d\n", ret);
10992600990eSRalf Baechle 
11002600990eSRalf Baechle 	v->shared_ptr = NULL;
11012600990eSRalf Baechle 	v->__start = 0;
110207cc0c9eSRalf Baechle 
1103e01402b1SRalf Baechle 	return 0;
1104e01402b1SRalf Baechle }
1105e01402b1SRalf Baechle 
1106e01402b1SRalf Baechle static int vpe_release(struct inode *inode, struct file *filp)
1107e01402b1SRalf Baechle {
1108307bd284SRalf Baechle 	struct vpe *v;
1109e01402b1SRalf Baechle 	Elf_Ehdr *hdr;
111007cc0c9eSRalf Baechle 	int ret = 0;
1111e01402b1SRalf Baechle 
111207cc0c9eSRalf Baechle 	v = get_vpe(tclimit);
111307cc0c9eSRalf Baechle 	if (v == NULL)
1114e01402b1SRalf Baechle 		return -ENODEV;
1115e01402b1SRalf Baechle 
1116e01402b1SRalf Baechle 	hdr = (Elf_Ehdr *) v->pbuffer;
1117e01402b1SRalf Baechle 	if (memcmp(hdr->e_ident, ELFMAG, 4) == 0) {
111807cc0c9eSRalf Baechle 		if (vpe_elfload(v) >= 0) {
1119e01402b1SRalf Baechle 			vpe_run(v);
112007cc0c9eSRalf Baechle 		} else {
11212600990eSRalf Baechle  			printk(KERN_WARNING "VPE loader: ELF load failed.\n");
1122e01402b1SRalf Baechle 			ret = -ENOEXEC;
1123e01402b1SRalf Baechle 		}
1124e01402b1SRalf Baechle 	} else {
11252600990eSRalf Baechle  		printk(KERN_WARNING "VPE loader: only elf files are supported\n");
1126e01402b1SRalf Baechle 		ret = -ENOEXEC;
1127e01402b1SRalf Baechle 	}
1128e01402b1SRalf Baechle 
11292600990eSRalf Baechle 	/* It's good to be able to run the SP and if it chokes have a look at
11302600990eSRalf Baechle 	   the /dev/rt?. But if we reset the pointer to the shared struct we
11312600990eSRalf Baechle 	   loose what has happened. So perhaps if garbage is sent to the vpe
11322600990eSRalf Baechle 	   device, use it as a trigger for the reset. Hopefully a nice
11332600990eSRalf Baechle 	   executable will be along shortly. */
11342600990eSRalf Baechle 	if (ret < 0)
11352600990eSRalf Baechle 		v->shared_ptr = NULL;
11362600990eSRalf Baechle 
1137e01402b1SRalf Baechle 	// cleanup any temp buffers
1138e01402b1SRalf Baechle 	if (v->pbuffer)
1139e01402b1SRalf Baechle 		vfree(v->pbuffer);
1140e01402b1SRalf Baechle 	v->plen = 0;
1141e01402b1SRalf Baechle 	return ret;
1142e01402b1SRalf Baechle }
1143e01402b1SRalf Baechle 
1144e01402b1SRalf Baechle static ssize_t vpe_write(struct file *file, const char __user * buffer,
1145e01402b1SRalf Baechle 			 size_t count, loff_t * ppos)
1146e01402b1SRalf Baechle {
1147e01402b1SRalf Baechle 	size_t ret = count;
1148307bd284SRalf Baechle 	struct vpe *v;
1149e01402b1SRalf Baechle 
115007cc0c9eSRalf Baechle 	if (iminor(file->f_path.dentry->d_inode) != minor)
115107cc0c9eSRalf Baechle 		return -ENODEV;
115207cc0c9eSRalf Baechle 
115307cc0c9eSRalf Baechle 	v = get_vpe(tclimit);
115407cc0c9eSRalf Baechle 	if (v == NULL)
1155e01402b1SRalf Baechle 		return -ENODEV;
1156e01402b1SRalf Baechle 
1157e01402b1SRalf Baechle 	if (v->pbuffer == NULL) {
11582600990eSRalf Baechle 		printk(KERN_ERR "VPE loader: no buffer for program\n");
1159e01402b1SRalf Baechle 		return -ENOMEM;
1160e01402b1SRalf Baechle 	}
1161e01402b1SRalf Baechle 
1162e01402b1SRalf Baechle 	if ((count + v->len) > v->plen) {
1163e01402b1SRalf Baechle 		printk(KERN_WARNING
11642600990eSRalf Baechle 		       "VPE loader: elf size too big. Perhaps strip uneeded symbols\n");
1165e01402b1SRalf Baechle 		return -ENOMEM;
1166e01402b1SRalf Baechle 	}
1167e01402b1SRalf Baechle 
1168e01402b1SRalf Baechle 	count -= copy_from_user(v->pbuffer + v->len, buffer, count);
11692600990eSRalf Baechle 	if (!count)
1170e01402b1SRalf Baechle 		return -EFAULT;
1171e01402b1SRalf Baechle 
1172e01402b1SRalf Baechle 	v->len += count;
1173e01402b1SRalf Baechle 	return ret;
1174e01402b1SRalf Baechle }
1175e01402b1SRalf Baechle 
11765dfe4c96SArjan van de Ven static const struct file_operations vpe_fops = {
1177e01402b1SRalf Baechle 	.owner = THIS_MODULE,
1178e01402b1SRalf Baechle 	.open = vpe_open,
1179e01402b1SRalf Baechle 	.release = vpe_release,
1180e01402b1SRalf Baechle 	.write = vpe_write
1181e01402b1SRalf Baechle };
1182e01402b1SRalf Baechle 
1183e01402b1SRalf Baechle /* module wrapper entry points */
1184e01402b1SRalf Baechle /* give me a vpe */
1185e01402b1SRalf Baechle vpe_handle vpe_alloc(void)
1186e01402b1SRalf Baechle {
1187e01402b1SRalf Baechle 	int i;
1188e01402b1SRalf Baechle 	struct vpe *v;
1189e01402b1SRalf Baechle 
1190e01402b1SRalf Baechle 	/* find a vpe */
1191e01402b1SRalf Baechle 	for (i = 1; i < MAX_VPES; i++) {
1192e01402b1SRalf Baechle 		if ((v = get_vpe(i)) != NULL) {
1193e01402b1SRalf Baechle 			v->state = VPE_STATE_INUSE;
1194e01402b1SRalf Baechle 			return v;
1195e01402b1SRalf Baechle 		}
1196e01402b1SRalf Baechle 	}
1197e01402b1SRalf Baechle 	return NULL;
1198e01402b1SRalf Baechle }
1199e01402b1SRalf Baechle 
1200e01402b1SRalf Baechle EXPORT_SYMBOL(vpe_alloc);
1201e01402b1SRalf Baechle 
1202e01402b1SRalf Baechle /* start running from here */
1203e01402b1SRalf Baechle int vpe_start(vpe_handle vpe, unsigned long start)
1204e01402b1SRalf Baechle {
1205e01402b1SRalf Baechle 	struct vpe *v = vpe;
1206e01402b1SRalf Baechle 
1207e01402b1SRalf Baechle 	v->__start = start;
1208e01402b1SRalf Baechle 	return vpe_run(v);
1209e01402b1SRalf Baechle }
1210e01402b1SRalf Baechle 
1211e01402b1SRalf Baechle EXPORT_SYMBOL(vpe_start);
1212e01402b1SRalf Baechle 
1213e01402b1SRalf Baechle /* halt it for now */
1214e01402b1SRalf Baechle int vpe_stop(vpe_handle vpe)
1215e01402b1SRalf Baechle {
1216e01402b1SRalf Baechle 	struct vpe *v = vpe;
1217e01402b1SRalf Baechle 	struct tc *t;
1218e01402b1SRalf Baechle 	unsigned int evpe_flags;
1219e01402b1SRalf Baechle 
1220e01402b1SRalf Baechle 	evpe_flags = dvpe();
1221e01402b1SRalf Baechle 
1222e01402b1SRalf Baechle 	if ((t = list_entry(v->tc.next, struct tc, tc)) != NULL) {
1223e01402b1SRalf Baechle 
1224e01402b1SRalf Baechle 		settc(t->index);
1225e01402b1SRalf Baechle 		write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() & ~VPECONF0_VPA);
1226e01402b1SRalf Baechle 	}
1227e01402b1SRalf Baechle 
1228e01402b1SRalf Baechle 	evpe(evpe_flags);
1229e01402b1SRalf Baechle 
1230e01402b1SRalf Baechle 	return 0;
1231e01402b1SRalf Baechle }
1232e01402b1SRalf Baechle 
1233e01402b1SRalf Baechle EXPORT_SYMBOL(vpe_stop);
1234e01402b1SRalf Baechle 
1235e01402b1SRalf Baechle /* I've done with it thank you */
1236e01402b1SRalf Baechle int vpe_free(vpe_handle vpe)
1237e01402b1SRalf Baechle {
1238e01402b1SRalf Baechle 	struct vpe *v = vpe;
1239e01402b1SRalf Baechle 	struct tc *t;
1240e01402b1SRalf Baechle 	unsigned int evpe_flags;
1241e01402b1SRalf Baechle 
1242e01402b1SRalf Baechle 	if ((t = list_entry(v->tc.next, struct tc, tc)) == NULL) {
1243e01402b1SRalf Baechle 		return -ENOEXEC;
1244e01402b1SRalf Baechle 	}
1245e01402b1SRalf Baechle 
1246e01402b1SRalf Baechle 	evpe_flags = dvpe();
1247e01402b1SRalf Baechle 
1248e01402b1SRalf Baechle 	/* Put MVPE's into 'configuration state' */
1249340ee4b9SRalf Baechle 	set_c0_mvpcontrol(MVPCONTROL_VPC);
1250e01402b1SRalf Baechle 
1251e01402b1SRalf Baechle 	settc(t->index);
1252e01402b1SRalf Baechle 	write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() & ~VPECONF0_VPA);
1253e01402b1SRalf Baechle 
1254e01402b1SRalf Baechle 	/* mark the TC unallocated and halt'ed */
1255e01402b1SRalf Baechle 	write_tc_c0_tcstatus(read_tc_c0_tcstatus() & ~TCSTATUS_A);
1256e01402b1SRalf Baechle 	write_tc_c0_tchalt(TCHALT_H);
1257e01402b1SRalf Baechle 
1258e01402b1SRalf Baechle 	v->state = VPE_STATE_UNUSED;
1259e01402b1SRalf Baechle 
1260340ee4b9SRalf Baechle 	clear_c0_mvpcontrol(MVPCONTROL_VPC);
1261e01402b1SRalf Baechle 	evpe(evpe_flags);
1262e01402b1SRalf Baechle 
1263e01402b1SRalf Baechle 	return 0;
1264e01402b1SRalf Baechle }
1265e01402b1SRalf Baechle 
1266e01402b1SRalf Baechle EXPORT_SYMBOL(vpe_free);
1267e01402b1SRalf Baechle 
1268e01402b1SRalf Baechle void *vpe_get_shared(int index)
1269e01402b1SRalf Baechle {
1270e01402b1SRalf Baechle 	struct vpe *v;
1271e01402b1SRalf Baechle 
12722600990eSRalf Baechle 	if ((v = get_vpe(index)) == NULL)
1273e01402b1SRalf Baechle 		return NULL;
1274e01402b1SRalf Baechle 
1275e01402b1SRalf Baechle 	return v->shared_ptr;
1276e01402b1SRalf Baechle }
1277e01402b1SRalf Baechle 
1278e01402b1SRalf Baechle EXPORT_SYMBOL(vpe_get_shared);
1279e01402b1SRalf Baechle 
12802600990eSRalf Baechle int vpe_getuid(int index)
12812600990eSRalf Baechle {
12822600990eSRalf Baechle 	struct vpe *v;
12832600990eSRalf Baechle 
12842600990eSRalf Baechle 	if ((v = get_vpe(index)) == NULL)
12852600990eSRalf Baechle 		return -1;
12862600990eSRalf Baechle 
12872600990eSRalf Baechle 	return v->uid;
12882600990eSRalf Baechle }
12892600990eSRalf Baechle 
12902600990eSRalf Baechle EXPORT_SYMBOL(vpe_getuid);
12912600990eSRalf Baechle 
12922600990eSRalf Baechle int vpe_getgid(int index)
12932600990eSRalf Baechle {
12942600990eSRalf Baechle 	struct vpe *v;
12952600990eSRalf Baechle 
12962600990eSRalf Baechle 	if ((v = get_vpe(index)) == NULL)
12972600990eSRalf Baechle 		return -1;
12982600990eSRalf Baechle 
12992600990eSRalf Baechle 	return v->gid;
13002600990eSRalf Baechle }
13012600990eSRalf Baechle 
13022600990eSRalf Baechle EXPORT_SYMBOL(vpe_getgid);
13032600990eSRalf Baechle 
13042600990eSRalf Baechle int vpe_notify(int index, struct vpe_notifications *notify)
13052600990eSRalf Baechle {
13062600990eSRalf Baechle 	struct vpe *v;
13072600990eSRalf Baechle 
13082600990eSRalf Baechle 	if ((v = get_vpe(index)) == NULL)
13092600990eSRalf Baechle 		return -1;
13102600990eSRalf Baechle 
13112600990eSRalf Baechle 	list_add(&notify->list, &v->notify);
13122600990eSRalf Baechle 	return 0;
13132600990eSRalf Baechle }
13142600990eSRalf Baechle 
13152600990eSRalf Baechle EXPORT_SYMBOL(vpe_notify);
13162600990eSRalf Baechle 
13172600990eSRalf Baechle char *vpe_getcwd(int index)
13182600990eSRalf Baechle {
13192600990eSRalf Baechle 	struct vpe *v;
13202600990eSRalf Baechle 
13212600990eSRalf Baechle 	if ((v = get_vpe(index)) == NULL)
13222600990eSRalf Baechle 		return NULL;
13232600990eSRalf Baechle 
13242600990eSRalf Baechle 	return v->cwd;
13252600990eSRalf Baechle }
13262600990eSRalf Baechle 
13272600990eSRalf Baechle EXPORT_SYMBOL(vpe_getcwd);
13282600990eSRalf Baechle 
13292600990eSRalf Baechle #ifdef CONFIG_MIPS_APSP_KSPD
13302600990eSRalf Baechle static void kspd_sp_exit( int sp_id)
13312600990eSRalf Baechle {
13322600990eSRalf Baechle 	cleanup_tc(get_tc(sp_id));
13332600990eSRalf Baechle }
13342600990eSRalf Baechle #endif
13352600990eSRalf Baechle 
133627a3bbafSRalf Baechle static struct device *vpe_dev;
133727a3bbafSRalf Baechle 
1338e01402b1SRalf Baechle static int __init vpe_module_init(void)
1339e01402b1SRalf Baechle {
134007cc0c9eSRalf Baechle 	unsigned int mtflags, vpflags;
134107cc0c9eSRalf Baechle 	int hw_tcs, hw_vpes, tc, err = 0;
134207cc0c9eSRalf Baechle 	unsigned long flags, val;
1343e01402b1SRalf Baechle 	struct vpe *v = NULL;
134427a3bbafSRalf Baechle 	struct device *dev;
1345e01402b1SRalf Baechle 	struct tc *t;
1346e01402b1SRalf Baechle 
1347e01402b1SRalf Baechle 	if (!cpu_has_mipsmt) {
1348e01402b1SRalf Baechle 		printk("VPE loader: not a MIPS MT capable processor\n");
1349e01402b1SRalf Baechle 		return -ENODEV;
1350e01402b1SRalf Baechle 	}
1351e01402b1SRalf Baechle 
135207cc0c9eSRalf Baechle 	if (vpelimit == 0) {
135307cc0c9eSRalf Baechle 		printk(KERN_WARNING "No VPEs reserved for AP/SP, not "
135407cc0c9eSRalf Baechle 		       "initializing VPE loader.\nPass maxvpes=<n> argument as "
135507cc0c9eSRalf Baechle 		       "kernel argument\n");
135607cc0c9eSRalf Baechle 
135707cc0c9eSRalf Baechle 		return -ENODEV;
135807cc0c9eSRalf Baechle 	}
135907cc0c9eSRalf Baechle 
136007cc0c9eSRalf Baechle 	if (tclimit == 0) {
136107cc0c9eSRalf Baechle 		printk(KERN_WARNING "No TCs reserved for AP/SP, not "
136207cc0c9eSRalf Baechle 		       "initializing VPE loader.\nPass maxtcs=<n> argument as "
136307cc0c9eSRalf Baechle 		       "kernel argument\n");
136407cc0c9eSRalf Baechle 
136507cc0c9eSRalf Baechle 		return -ENODEV;
136607cc0c9eSRalf Baechle 	}
136707cc0c9eSRalf Baechle 
1368682e852eSAlexey Dobriyan 	major = register_chrdev(0, module_name, &vpe_fops);
1369682e852eSAlexey Dobriyan 	if (major < 0) {
1370e01402b1SRalf Baechle 		printk("VPE loader: unable to register character device\n");
1371307bd284SRalf Baechle 		return major;
1372e01402b1SRalf Baechle 	}
1373e01402b1SRalf Baechle 
137427a3bbafSRalf Baechle 	dev = device_create(mt_class, NULL, MKDEV(major, minor),
137507cc0c9eSRalf Baechle 	                    "vpe%d", minor);
137627a3bbafSRalf Baechle 	if (IS_ERR(dev)) {
137727a3bbafSRalf Baechle 		err = PTR_ERR(dev);
137827a3bbafSRalf Baechle 		goto out_chrdev;
137927a3bbafSRalf Baechle 	}
138027a3bbafSRalf Baechle 	vpe_dev = dev;
138127a3bbafSRalf Baechle 
138207cc0c9eSRalf Baechle 	local_irq_save(flags);
138307cc0c9eSRalf Baechle 	mtflags = dmt();
138407cc0c9eSRalf Baechle 	vpflags = dvpe();
1385e01402b1SRalf Baechle 
1386e01402b1SRalf Baechle 	/* Put MVPE's into 'configuration state' */
1387340ee4b9SRalf Baechle 	set_c0_mvpcontrol(MVPCONTROL_VPC);
1388e01402b1SRalf Baechle 
1389e01402b1SRalf Baechle 	/* dump_mtregs(); */
1390e01402b1SRalf Baechle 
1391e01402b1SRalf Baechle 	val = read_c0_mvpconf0();
139207cc0c9eSRalf Baechle 	hw_tcs = (val & MVPCONF0_PTC) + 1;
139307cc0c9eSRalf Baechle 	hw_vpes = ((val & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT) + 1;
139407cc0c9eSRalf Baechle 
139507cc0c9eSRalf Baechle 	for (tc = tclimit; tc < hw_tcs; tc++) {
139607cc0c9eSRalf Baechle 		/*
139707cc0c9eSRalf Baechle 		 * Must re-enable multithreading temporarily or in case we
139807cc0c9eSRalf Baechle 		 * reschedule send IPIs or similar we might hang.
139907cc0c9eSRalf Baechle 		 */
140007cc0c9eSRalf Baechle 		clear_c0_mvpcontrol(MVPCONTROL_VPC);
140107cc0c9eSRalf Baechle 		evpe(vpflags);
140207cc0c9eSRalf Baechle 		emt(mtflags);
140307cc0c9eSRalf Baechle 		local_irq_restore(flags);
140407cc0c9eSRalf Baechle 		t = alloc_tc(tc);
140507cc0c9eSRalf Baechle 		if (!t) {
140607cc0c9eSRalf Baechle 			err = -ENOMEM;
140707cc0c9eSRalf Baechle 			goto out;
140807cc0c9eSRalf Baechle 		}
140907cc0c9eSRalf Baechle 
141007cc0c9eSRalf Baechle 		local_irq_save(flags);
141107cc0c9eSRalf Baechle 		mtflags = dmt();
141207cc0c9eSRalf Baechle 		vpflags = dvpe();
141307cc0c9eSRalf Baechle 		set_c0_mvpcontrol(MVPCONTROL_VPC);
1414e01402b1SRalf Baechle 
1415e01402b1SRalf Baechle 		/* VPE's */
141607cc0c9eSRalf Baechle 		if (tc < hw_tcs) {
141707cc0c9eSRalf Baechle 			settc(tc);
1418e01402b1SRalf Baechle 
141907cc0c9eSRalf Baechle 			if ((v = alloc_vpe(tc)) == NULL) {
1420e01402b1SRalf Baechle 				printk(KERN_WARNING "VPE: unable to allocate VPE\n");
142107cc0c9eSRalf Baechle 
142207cc0c9eSRalf Baechle 				goto out_reenable;
1423e01402b1SRalf Baechle 			}
1424e01402b1SRalf Baechle 
14252600990eSRalf Baechle 			/* add the tc to the list of this vpe's tc's. */
14262600990eSRalf Baechle 			list_add(&t->tc, &v->tc);
1427e01402b1SRalf Baechle 
1428e01402b1SRalf Baechle 			/* deactivate all but vpe0 */
142907cc0c9eSRalf Baechle 			if (tc >= tclimit) {
1430e01402b1SRalf Baechle 				unsigned long tmp = read_vpe_c0_vpeconf0();
1431e01402b1SRalf Baechle 
1432e01402b1SRalf Baechle 				tmp &= ~VPECONF0_VPA;
1433e01402b1SRalf Baechle 
1434e01402b1SRalf Baechle 				/* master VPE */
1435e01402b1SRalf Baechle 				tmp |= VPECONF0_MVP;
1436e01402b1SRalf Baechle 				write_vpe_c0_vpeconf0(tmp);
1437e01402b1SRalf Baechle 			}
1438e01402b1SRalf Baechle 
1439e01402b1SRalf Baechle 			/* disable multi-threading with TC's */
1440e01402b1SRalf Baechle 			write_vpe_c0_vpecontrol(read_vpe_c0_vpecontrol() & ~VPECONTROL_TE);
1441e01402b1SRalf Baechle 
144207cc0c9eSRalf Baechle 			if (tc >= vpelimit) {
14432600990eSRalf Baechle 				/*
14442600990eSRalf Baechle 				 * Set config to be the same as vpe0,
14452600990eSRalf Baechle 				 * particularly kseg0 coherency alg
14462600990eSRalf Baechle 				 */
1447e01402b1SRalf Baechle 				write_vpe_c0_config(read_c0_config());
1448e01402b1SRalf Baechle 			}
1449e01402b1SRalf Baechle 		}
1450e01402b1SRalf Baechle 
1451e01402b1SRalf Baechle 		/* TC's */
1452e01402b1SRalf Baechle 		t->pvpe = v;	/* set the parent vpe */
1453e01402b1SRalf Baechle 
145407cc0c9eSRalf Baechle 		if (tc >= tclimit) {
1455e01402b1SRalf Baechle 			unsigned long tmp;
1456e01402b1SRalf Baechle 
145707cc0c9eSRalf Baechle 			settc(tc);
1458e01402b1SRalf Baechle 
14592600990eSRalf Baechle 			/* Any TC that is bound to VPE0 gets left as is - in case
14602600990eSRalf Baechle 			   we are running SMTC on VPE0. A TC that is bound to any
14612600990eSRalf Baechle 			   other VPE gets bound to VPE0, ideally I'd like to make
14622600990eSRalf Baechle 			   it homeless but it doesn't appear to let me bind a TC
14632600990eSRalf Baechle 			   to a non-existent VPE. Which is perfectly reasonable.
14642600990eSRalf Baechle 
14652600990eSRalf Baechle 			   The (un)bound state is visible to an EJTAG probe so may
14662600990eSRalf Baechle 			   notify GDB...
14672600990eSRalf Baechle 			*/
14682600990eSRalf Baechle 
14692600990eSRalf Baechle 			if (((tmp = read_tc_c0_tcbind()) & TCBIND_CURVPE)) {
14702600990eSRalf Baechle 				/* tc is bound >vpe0 */
14712600990eSRalf Baechle 				write_tc_c0_tcbind(tmp & ~TCBIND_CURVPE);
14722600990eSRalf Baechle 
14732600990eSRalf Baechle 				t->pvpe = get_vpe(0);	/* set the parent vpe */
14742600990eSRalf Baechle 			}
1475e01402b1SRalf Baechle 
1476e01402b1SRalf Baechle 			tmp = read_tc_c0_tcstatus();
1477e01402b1SRalf Baechle 
14782600990eSRalf Baechle 			/* mark not activated and not dynamically allocatable */
1479e01402b1SRalf Baechle 			tmp &= ~(TCSTATUS_A | TCSTATUS_DA);
1480e01402b1SRalf Baechle 			tmp |= TCSTATUS_IXMT;	/* interrupt exempt */
1481e01402b1SRalf Baechle 			write_tc_c0_tcstatus(tmp);
1482e01402b1SRalf Baechle 
1483e01402b1SRalf Baechle 			write_tc_c0_tchalt(TCHALT_H);
1484e01402b1SRalf Baechle 		}
1485e01402b1SRalf Baechle 	}
1486e01402b1SRalf Baechle 
148707cc0c9eSRalf Baechle out_reenable:
1488e01402b1SRalf Baechle 	/* release config state */
1489340ee4b9SRalf Baechle 	clear_c0_mvpcontrol(MVPCONTROL_VPC);
1490e01402b1SRalf Baechle 
149107cc0c9eSRalf Baechle 	evpe(vpflags);
149207cc0c9eSRalf Baechle 	emt(mtflags);
149307cc0c9eSRalf Baechle 	local_irq_restore(flags);
149407cc0c9eSRalf Baechle 
14952600990eSRalf Baechle #ifdef CONFIG_MIPS_APSP_KSPD
14962600990eSRalf Baechle 	kspd_events.kspd_sp_exit = kspd_sp_exit;
14972600990eSRalf Baechle #endif
1498e01402b1SRalf Baechle 	return 0;
149927a3bbafSRalf Baechle 
150027a3bbafSRalf Baechle out_chrdev:
150127a3bbafSRalf Baechle 	unregister_chrdev(major, module_name);
150227a3bbafSRalf Baechle 
150307cc0c9eSRalf Baechle out:
150427a3bbafSRalf Baechle 	return err;
1505e01402b1SRalf Baechle }
1506e01402b1SRalf Baechle 
1507e01402b1SRalf Baechle static void __exit vpe_module_exit(void)
1508e01402b1SRalf Baechle {
1509e01402b1SRalf Baechle 	struct vpe *v, *n;
1510e01402b1SRalf Baechle 
1511e01402b1SRalf Baechle 	list_for_each_entry_safe(v, n, &vpecontrol.vpe_list, list) {
1512e01402b1SRalf Baechle 		if (v->state != VPE_STATE_UNUSED) {
1513e01402b1SRalf Baechle 			release_vpe(v);
1514e01402b1SRalf Baechle 		}
1515e01402b1SRalf Baechle 	}
1516e01402b1SRalf Baechle 
151727a3bbafSRalf Baechle 	device_destroy(mt_class, MKDEV(major, minor));
1518e01402b1SRalf Baechle 	unregister_chrdev(major, module_name);
1519e01402b1SRalf Baechle }
1520e01402b1SRalf Baechle 
1521e01402b1SRalf Baechle module_init(vpe_module_init);
1522e01402b1SRalf Baechle module_exit(vpe_module_exit);
1523e01402b1SRalf Baechle MODULE_DESCRIPTION("MIPS VPE Loader");
15242600990eSRalf Baechle MODULE_AUTHOR("Elizabeth Oldham, MIPS Technologies, Inc.");
1525e01402b1SRalf Baechle MODULE_LICENSE("GPL");
1526