OpenCores
URL https://opencores.org/ocsvn/or1k_soc_on_altera_embedded_dev_kit/or1k_soc_on_altera_embedded_dev_kit/trunk

Subversion Repositories or1k_soc_on_altera_embedded_dev_kit

[/] [or1k_soc_on_altera_embedded_dev_kit/] [trunk/] [linux-2.6/] [linux-2.6.24/] [arch/] [mips/] [kernel/] [vpe.c] - Blame information for rev 3

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.