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