Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[MIPS] MT: Enable coexistence of AP/SP with VSMP and SMTC.

Signed-off-by: Ralf Baechle <ralf@linux-mips.org>

+203 -169
+12 -12
arch/mips/Kconfig
··· 1377 1377 This is a kernel model which is known a SMTC or lately has been 1378 1378 marketesed into SMVP. 1379 1379 1380 - config MIPS_VPE_LOADER 1381 - bool "VPE loader support." 1382 - depends on SYS_SUPPORTS_MULTITHREADING 1383 - select CPU_MIPSR2_IRQ_VI 1384 - select CPU_MIPSR2_IRQ_EI 1385 - select CPU_MIPSR2_SRS 1386 - select MIPS_MT 1387 - help 1388 - Includes a loader for loading an elf relocatable object 1389 - onto another VPE and running it. 1390 - 1391 1380 endchoice 1392 1381 1393 1382 config MIPS_MT ··· 1387 1398 1388 1399 config MIPS_MT_FPAFF 1389 1400 bool "Dynamic FPU affinity for FP-intensive threads" 1390 - depends on MIPS_MT 1391 1401 default y 1402 + depends on MIPS_MT_SMP || MIPS_MT_SMTC 1403 + 1404 + config MIPS_VPE_LOADER 1405 + bool "VPE loader support." 1406 + depends on SYS_SUPPORTS_MULTITHREADING 1407 + select CPU_MIPSR2_IRQ_VI 1408 + select CPU_MIPSR2_IRQ_EI 1409 + select CPU_MIPSR2_SRS 1410 + select MIPS_MT 1411 + help 1412 + Includes a loader for loading an elf relocatable object 1413 + onto another VPE and running it. 1392 1414 1393 1415 config MIPS_MT_SMTC_INSTANT_REPLAY 1394 1416 bool "Low-latency Dispatch of Deferred SMTC IPIs"
+9 -10
arch/mips/kernel/kspd.c
··· 89 89 #define MTSP_O_EXCL 0x0800 90 90 #define MTSP_O_BINARY 0x8000 91 91 92 - #define SP_VPE 1 92 + extern int tclimit; 93 93 94 94 struct apsp_table { 95 95 int sp; ··· 225 225 /* Run the syscall at the priviledge of the user who loaded the 226 226 SP program */ 227 227 228 - if (vpe_getuid(SP_VPE)) 229 - sp_setfsuidgid( vpe_getuid(SP_VPE), vpe_getgid(SP_VPE)); 228 + if (vpe_getuid(tclimit)) 229 + sp_setfsuidgid(vpe_getuid(tclimit), vpe_getgid(tclimit)); 230 230 231 231 switch (sc.cmd) { 232 232 /* needs the flags argument translating from SDE kit to ··· 245 245 246 246 case MTSP_SYSCALL_EXIT: 247 247 list_for_each_entry(n, &kspd_notifylist, list) 248 - n->kspd_sp_exit(SP_VPE); 248 + n->kspd_sp_exit(tclimit); 249 249 sp_stopping = 1; 250 250 251 251 printk(KERN_DEBUG "KSPD got exit syscall from SP exitcode %d\n", ··· 255 255 case MTSP_SYSCALL_OPEN: 256 256 generic.arg1 = translate_open_flags(generic.arg1); 257 257 258 - vcwd = vpe_getcwd(SP_VPE); 258 + vcwd = vpe_getcwd(tclimit); 259 259 260 260 /* change to the cwd of the process that loaded the SP program */ 261 261 old_fs = get_fs(); ··· 283 283 break; 284 284 } /* switch */ 285 285 286 - if (vpe_getuid(SP_VPE)) 286 + if (vpe_getuid(tclimit)) 287 287 sp_setfsuidgid( 0, 0); 288 288 289 289 old_fs = get_fs(); ··· 364 364 } 365 365 366 366 INIT_WORK(&work, sp_work); 367 - queue_work(workqueue, &work); 368 - } else 369 - queue_work(workqueue, &work); 367 + } 370 368 369 + queue_work(workqueue, &work); 371 370 } 372 371 373 372 static void stopwork(int vpe) ··· 388 389 389 390 notify.start = startwork; 390 391 notify.stop = stopwork; 391 - vpe_notify(SP_VPE, &notify); 392 + vpe_notify(tclimit, &notify); 392 393 393 394 return 0; 394 395 }
+22
arch/mips/kernel/mips-mt.c
··· 21 21 #include <asm/r4kcache.h> 22 22 #include <asm/cacheflush.h> 23 23 24 + int vpelimit; 25 + 26 + static int __init maxvpes(char *str) 27 + { 28 + get_option(&str, &vpelimit); 29 + 30 + return 1; 31 + } 32 + 33 + __setup("maxvpes=", maxvpes); 34 + 35 + int tclimit; 36 + 37 + static int __init maxtcs(char *str) 38 + { 39 + get_option(&str, &tclimit); 40 + 41 + return 1; 42 + } 43 + 44 + __setup("maxtcs=", maxtcs); 45 + 24 46 /* 25 47 * Dump new MIPS MT state for the core. Does not leave TCs halted. 26 48 * Takes an argument which taken to be a pre-call MVPControl value.
+17 -5
arch/mips/kernel/rtlx.c
··· 40 40 #include <asm/atomic.h> 41 41 #include <asm/cpu.h> 42 42 #include <asm/processor.h> 43 + #include <asm/mips_mt.h> 43 44 #include <asm/system.h> 44 45 #include <asm/vpe.h> 45 46 #include <asm/rtlx.h> 46 - 47 - #define RTLX_TARG_VPE 1 48 47 49 48 static struct rtlx_info *rtlx; 50 49 static int major; ··· 164 165 } 165 166 166 167 if (rtlx == NULL) { 167 - if( (p = vpe_get_shared(RTLX_TARG_VPE)) == NULL) { 168 + if( (p = vpe_get_shared(tclimit)) == NULL) { 168 169 if (can_sleep) { 169 170 __wait_event_interruptible(channel_wqs[index].lx_queue, 170 - (p = vpe_get_shared(RTLX_TARG_VPE)), 171 + (p = vpe_get_shared(tclimit)), 171 172 ret); 172 173 if (ret) 173 174 goto out_fail; ··· 476 477 struct device *dev; 477 478 int i, err; 478 479 480 + if (!cpu_has_mipsmt) { 481 + printk("VPE loader: not a MIPS MT capable processor\n"); 482 + return -ENODEV; 483 + } 484 + 485 + if (tclimit == 0) { 486 + printk(KERN_WARNING "No TCs reserved for AP/SP, not " 487 + "initializing RTLX.\nPass maxtcs=<n> argument as kernel " 488 + "argument\n"); 489 + 490 + return -ENODEV; 491 + } 492 + 479 493 major = register_chrdev(0, module_name, &rtlx_fops); 480 494 if (major < 0) { 481 495 printk(register_chrdev_failed); ··· 513 501 /* set up notifiers */ 514 502 notify.start = starting; 515 503 notify.stop = stopping; 516 - vpe_notify(RTLX_TARG_VPE, &notify); 504 + vpe_notify(tclimit, &notify); 517 505 518 506 if (cpu_has_vint) 519 507 set_vi_handler(MIPS_CPU_RTLX_IRQ, rtlx_dispatch);
-16
arch/mips/kernel/smtc.c
··· 86 86 87 87 /* Boot command line configuration overrides */ 88 88 89 - static int vpelimit = 0; 90 - static int tclimit = 0; 91 89 static int ipibuffers = 0; 92 90 static int nostlb = 0; 93 91 static int asidmask = 0; 94 92 unsigned long smtc_asid_mask = 0xff; 95 - 96 - static int __init maxvpes(char *str) 97 - { 98 - get_option(&str, &vpelimit); 99 - return 1; 100 - } 101 - 102 - static int __init maxtcs(char *str) 103 - { 104 - get_option(&str, &tclimit); 105 - return 1; 106 - } 107 93 108 94 static int __init ipibufs(char *str) 109 95 { ··· 123 137 return 1; 124 138 } 125 139 126 - __setup("maxvpes=", maxvpes); 127 - __setup("maxtcs=", maxtcs); 128 140 __setup("ipibufs=", ipibufs); 129 141 __setup("nostlb", stlb_disable); 130 142 __setup("asidmask=", asidmask_set);
+137 -126
arch/mips/kernel/vpe.c
··· 27 27 * To load and run, simply cat a SP 'program file' to /dev/vpe1. 28 28 * i.e cat spapp >/dev/vpe1. 29 29 */ 30 - 31 30 #include <linux/kernel.h> 32 31 #include <linux/device.h> 33 32 #include <linux/module.h> ··· 53 54 #include <asm/system.h> 54 55 #include <asm/vpe.h> 55 56 #include <asm/kspd.h> 57 + #include <asm/mips_mt.h> 56 58 57 59 typedef void *vpe_handle; 58 60 ··· 132 132 enum tc_state state; 133 133 int index; 134 134 135 - /* parent VPE */ 136 - struct vpe *pvpe; 137 - 138 - /* The list of TC's with this VPE */ 139 - struct list_head tc; 140 - 141 - /* The global list of tc's */ 142 - struct list_head list; 135 + struct vpe *pvpe; /* parent VPE */ 136 + struct list_head tc; /* The list of TC's with this VPE */ 137 + struct list_head list; /* The global list of tc's */ 143 138 }; 144 139 145 140 struct { ··· 212 217 /* allocate a tc. At startup only tc0 is running, all other can be halted. */ 213 218 struct tc *alloc_tc(int index) 214 219 { 215 - struct tc *t; 220 + struct tc *tc; 216 221 217 - if ((t = kzalloc(sizeof(struct tc), GFP_KERNEL)) == NULL) { 218 - return NULL; 219 - } 222 + if ((tc = kzalloc(sizeof(struct tc), GFP_KERNEL)) == NULL) 223 + goto out; 220 224 221 - INIT_LIST_HEAD(&t->tc); 222 - list_add_tail(&t->list, &vpecontrol.tc_list); 225 + INIT_LIST_HEAD(&tc->tc); 226 + tc->index = index; 227 + list_add_tail(&tc->list, &vpecontrol.tc_list); 223 228 224 - t->index = index; 225 - 226 - return t; 229 + out: 230 + return tc; 227 231 } 228 232 229 233 /* clean up and free everything */ ··· 657 663 } 658 664 #endif 659 665 660 - static void dump_tc(struct tc *t) 661 - { 662 - unsigned long val; 663 - 664 - settc(t->index); 665 - printk(KERN_DEBUG "VPE loader: TC index %d targtc %ld " 666 - "TCStatus 0x%lx halt 0x%lx\n", 667 - t->index, read_c0_vpecontrol() & VPECONTROL_TARGTC, 668 - read_tc_c0_tcstatus(), read_tc_c0_tchalt()); 669 - 670 - printk(KERN_DEBUG " tcrestart 0x%lx\n", read_tc_c0_tcrestart()); 671 - printk(KERN_DEBUG " tcbind 0x%lx\n", read_tc_c0_tcbind()); 672 - 673 - val = read_c0_vpeconf0(); 674 - printk(KERN_DEBUG " VPEConf0 0x%lx MVP %ld\n", val, 675 - (val & VPECONF0_MVP) >> VPECONF0_MVP_SHIFT); 676 - 677 - printk(KERN_DEBUG " c0 status 0x%lx\n", read_vpe_c0_status()); 678 - printk(KERN_DEBUG " c0 cause 0x%lx\n", read_vpe_c0_cause()); 679 - 680 - printk(KERN_DEBUG " c0 badvaddr 0x%lx\n", read_vpe_c0_badvaddr()); 681 - printk(KERN_DEBUG " c0 epc 0x%lx\n", read_vpe_c0_epc()); 682 - } 683 - 684 - static void dump_tclist(void) 685 - { 686 - struct tc *t; 687 - 688 - list_for_each_entry(t, &vpecontrol.tc_list, list) { 689 - dump_tc(t); 690 - } 691 - } 692 - 693 666 /* We are prepared so configure and start the VPE... */ 694 667 static int vpe_run(struct vpe * v) 695 668 { 669 + unsigned long flags, val, dmt_flag; 696 670 struct vpe_notifications *n; 697 - unsigned long val, dmt_flag; 671 + unsigned int vpeflags; 698 672 struct tc *t; 699 673 700 674 /* check we are the Master VPE */ 675 + local_irq_save(flags); 701 676 val = read_c0_vpeconf0(); 702 677 if (!(val & VPECONF0_MVP)) { 703 678 printk(KERN_WARNING 704 679 "VPE loader: only Master VPE's are allowed to configure MT\n"); 680 + local_irq_restore(flags); 681 + 705 682 return -1; 706 683 } 707 684 708 - /* disable MT (using dvpe) */ 709 - dvpe(); 685 + dmt_flag = dmt(); 686 + vpeflags = dvpe(); 710 687 711 688 if (!list_empty(&v->tc)) { 712 689 if ((t = list_entry(v->tc.next, struct tc, tc)) == NULL) { 713 - printk(KERN_WARNING "VPE loader: TC %d is already in use.\n", 714 - t->index); 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); 715 697 return -ENOEXEC; 716 698 } 717 699 } else { 718 - printk(KERN_WARNING "VPE loader: No TC's associated with VPE %d\n", 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", 719 706 v->minor); 707 + 720 708 return -ENOEXEC; 721 709 } 722 710 ··· 709 733 710 734 /* should check it is halted, and not activated */ 711 735 if ((read_tc_c0_tcstatus() & TCSTATUS_A) || !(read_tc_c0_tchalt() & TCHALT_H)) { 712 - printk(KERN_WARNING "VPE loader: TC %d is already doing something!\n", 736 + evpe(vpeflags); 737 + emt(dmt_flag); 738 + local_irq_restore(flags); 739 + 740 + printk(KERN_WARNING "VPE loader: TC %d is already active!\n", 713 741 t->index); 714 - dump_tclist(); 742 + 715 743 return -ENOEXEC; 716 744 } 717 - 718 - /* 719 - * Disable multi-threaded execution whilst we activate, clear the 720 - * halt bit and bound the tc to the other VPE... 721 - */ 722 - dmt_flag = dmt(); 723 745 724 746 /* Write the address we want it to start running from in the TCPC register. */ 725 747 write_tc_c0_tcrestart((unsigned long)v->__start); 726 748 write_tc_c0_tccontext((unsigned long)0); 749 + 727 750 /* 728 751 * Mark the TC as activated, not interrupt exempt and not dynamically 729 752 * allocatable ··· 738 763 * here... Or set $a3 to zero and define DFLT_STACK_SIZE and 739 764 * DFLT_HEAP_SIZE when you compile your program 740 765 */ 741 - mttgpr(7, physical_memsize); 742 - 766 + mttgpr(7, physical_memsize); 743 767 744 768 /* set up VPE1 */ 745 769 /* 746 770 * bind the TC to VPE 1 as late as possible so we only have the final 747 771 * VPE registers to set up, and so an EJTAG probe can trigger on it 748 772 */ 749 - write_tc_c0_tcbind((read_tc_c0_tcbind() & ~TCBIND_CURVPE) | v->minor); 773 + write_tc_c0_tcbind((read_tc_c0_tcbind() & ~TCBIND_CURVPE) | 1); 750 774 751 775 write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() & ~(VPECONF0_VPA)); 752 776 ··· 767 793 /* take system out of configuration state */ 768 794 clear_c0_mvpcontrol(MVPCONTROL_VPC); 769 795 770 - /* now safe to re-enable multi-threading */ 771 - emt(dmt_flag); 772 - 773 - /* set it running */ 796 + #ifdef CONFIG_SMP 774 797 evpe(EVPE_ENABLE); 798 + #else 799 + evpe(vpeflags); 800 + #endif 801 + emt(dmt_flag); 802 + local_irq_restore(flags); 775 803 776 - list_for_each_entry(n, &v->notify, list) { 777 - n->start(v->minor); 778 - } 804 + list_for_each_entry(n, &v->notify, list) 805 + n->start(minor); 779 806 780 807 return 0; 781 808 } ··· 998 1023 return 0; 999 1024 } 1000 1025 1001 - void __used dump_vpe(struct vpe * v) 1002 - { 1003 - struct tc *t; 1004 - 1005 - settc(v->minor); 1006 - 1007 - printk(KERN_DEBUG "VPEControl 0x%lx\n", read_vpe_c0_vpecontrol()); 1008 - printk(KERN_DEBUG "VPEConf0 0x%lx\n", read_vpe_c0_vpeconf0()); 1009 - 1010 - list_for_each_entry(t, &vpecontrol.tc_list, list) 1011 - dump_tc(t); 1012 - } 1013 - 1014 1026 static void cleanup_tc(struct tc *tc) 1015 1027 { 1028 + unsigned long flags; 1029 + unsigned int mtflags, vpflags; 1016 1030 int tmp; 1017 1031 1032 + local_irq_save(flags); 1033 + mtflags = dmt(); 1034 + vpflags = dvpe(); 1018 1035 /* Put MVPE's into 'configuration state' */ 1019 1036 set_c0_mvpcontrol(MVPCONTROL_VPC); 1020 1037 ··· 1021 1054 write_tc_c0_tchalt(TCHALT_H); 1022 1055 1023 1056 /* bind it to anything other than VPE1 */ 1024 - write_tc_c0_tcbind(read_tc_c0_tcbind() & ~TCBIND_CURVPE); // | TCBIND_CURVPE 1057 + // write_tc_c0_tcbind(read_tc_c0_tcbind() & ~TCBIND_CURVPE); // | TCBIND_CURVPE 1025 1058 1026 1059 clear_c0_mvpcontrol(MVPCONTROL_VPC); 1060 + evpe(vpflags); 1061 + emt(mtflags); 1062 + local_irq_restore(flags); 1027 1063 } 1028 1064 1029 1065 static int getcwd(char *buff, int size) ··· 1047 1077 /* checks VPE is unused and gets ready to load program */ 1048 1078 static int vpe_open(struct inode *inode, struct file *filp) 1049 1079 { 1050 - int minor, ret; 1051 1080 enum vpe_state state; 1052 - struct vpe *v; 1053 1081 struct vpe_notifications *not; 1082 + struct vpe *v; 1083 + int ret; 1054 1084 1055 - /* assume only 1 device at the mo. */ 1056 - if ((minor = iminor(inode)) != 1) { 1085 + if (minor != iminor(inode)) { 1086 + /* assume only 1 device at the moment. */ 1057 1087 printk(KERN_WARNING "VPE loader: only vpe1 is supported\n"); 1058 1088 return -ENODEV; 1059 1089 } 1060 1090 1061 - if ((v = get_vpe(minor)) == NULL) { 1091 + if ((v = get_vpe(tclimit)) == NULL) { 1062 1092 printk(KERN_WARNING "VPE loader: unable to get vpe\n"); 1063 1093 return -ENODEV; 1064 1094 } 1065 1095 1066 1096 state = xchg(&v->state, VPE_STATE_INUSE); 1067 1097 if (state != VPE_STATE_UNUSED) { 1068 - dvpe(); 1069 - 1070 1098 printk(KERN_DEBUG "VPE loader: tc in use dumping regs\n"); 1071 1099 1072 - dump_tc(get_tc(minor)); 1073 - 1074 1100 list_for_each_entry(not, &v->notify, list) { 1075 - not->stop(minor); 1101 + not->stop(tclimit); 1076 1102 } 1077 1103 1078 1104 release_progmem(v->load_addr); 1079 - cleanup_tc(get_tc(minor)); 1105 + cleanup_tc(get_tc(tclimit)); 1080 1106 } 1081 1107 1082 1108 /* this of-course trashes what was there before... */ ··· 1099 1133 1100 1134 v->shared_ptr = NULL; 1101 1135 v->__start = 0; 1136 + 1102 1137 return 0; 1103 1138 } 1104 1139 1105 1140 static int vpe_release(struct inode *inode, struct file *filp) 1106 1141 { 1107 - int minor, ret = 0; 1108 1142 struct vpe *v; 1109 1143 Elf_Ehdr *hdr; 1144 + int ret = 0; 1110 1145 1111 - minor = iminor(inode); 1112 - if ((v = get_vpe(minor)) == NULL) 1146 + v = get_vpe(tclimit); 1147 + if (v == NULL) 1113 1148 return -ENODEV; 1114 - 1115 - // simple case of fire and forget, so tell the VPE to run... 1116 1149 1117 1150 hdr = (Elf_Ehdr *) v->pbuffer; 1118 1151 if (memcmp(hdr->e_ident, ELFMAG, 4) == 0) { 1119 - if (vpe_elfload(v) >= 0) 1152 + if (vpe_elfload(v) >= 0) { 1120 1153 vpe_run(v); 1121 - else { 1154 + } else { 1122 1155 printk(KERN_WARNING "VPE loader: ELF load failed.\n"); 1123 1156 ret = -ENOEXEC; 1124 1157 } ··· 1144 1179 static ssize_t vpe_write(struct file *file, const char __user * buffer, 1145 1180 size_t count, loff_t * ppos) 1146 1181 { 1147 - int minor; 1148 1182 size_t ret = count; 1149 1183 struct vpe *v; 1150 1184 1151 - minor = iminor(file->f_path.dentry->d_inode); 1152 - if ((v = get_vpe(minor)) == NULL) 1185 + if (iminor(file->f_path.dentry->d_inode) != minor) 1186 + return -ENODEV; 1187 + 1188 + v = get_vpe(tclimit); 1189 + if (v == NULL) 1153 1190 return -ENODEV; 1154 1191 1155 1192 if (v->pbuffer == NULL) { ··· 1337 1370 1338 1371 static int __init vpe_module_init(void) 1339 1372 { 1373 + unsigned int mtflags, vpflags; 1374 + int hw_tcs, hw_vpes, tc, err = 0; 1375 + unsigned long flags, val; 1340 1376 struct vpe *v = NULL; 1341 1377 struct device *dev; 1342 1378 struct tc *t; 1343 - unsigned long val; 1344 - int i, err; 1345 1379 1346 1380 if (!cpu_has_mipsmt) { 1347 1381 printk("VPE loader: not a MIPS MT capable processor\n"); 1382 + return -ENODEV; 1383 + } 1384 + 1385 + if (vpelimit == 0) { 1386 + printk(KERN_WARNING "No VPEs reserved for AP/SP, not " 1387 + "initializing VPE loader.\nPass maxvpes=<n> argument as " 1388 + "kernel argument\n"); 1389 + 1390 + return -ENODEV; 1391 + } 1392 + 1393 + if (tclimit == 0) { 1394 + printk(KERN_WARNING "No TCs reserved for AP/SP, not " 1395 + "initializing VPE loader.\nPass maxtcs=<n> argument as " 1396 + "kernel argument\n"); 1397 + 1348 1398 return -ENODEV; 1349 1399 } 1350 1400 ··· 1372 1388 } 1373 1389 1374 1390 dev = device_create(mt_class, NULL, MKDEV(major, minor), 1375 - "tc%d", minor); 1391 + "vpe%d", minor); 1376 1392 if (IS_ERR(dev)) { 1377 1393 err = PTR_ERR(dev); 1378 1394 goto out_chrdev; 1379 1395 } 1380 1396 vpe_dev = dev; 1381 1397 1382 - dmt(); 1383 - dvpe(); 1398 + local_irq_save(flags); 1399 + mtflags = dmt(); 1400 + vpflags = dvpe(); 1384 1401 1385 1402 /* Put MVPE's into 'configuration state' */ 1386 1403 set_c0_mvpcontrol(MVPCONTROL_VPC); 1387 1404 1388 1405 /* dump_mtregs(); */ 1389 1406 1390 - 1391 1407 val = read_c0_mvpconf0(); 1392 - for (i = 0; i < ((val & MVPCONF0_PTC) + 1); i++) { 1393 - t = alloc_tc(i); 1408 + hw_tcs = (val & MVPCONF0_PTC) + 1; 1409 + hw_vpes = ((val & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT) + 1; 1410 + 1411 + for (tc = tclimit; tc < hw_tcs; tc++) { 1412 + /* 1413 + * Must re-enable multithreading temporarily or in case we 1414 + * reschedule send IPIs or similar we might hang. 1415 + */ 1416 + clear_c0_mvpcontrol(MVPCONTROL_VPC); 1417 + evpe(vpflags); 1418 + emt(mtflags); 1419 + local_irq_restore(flags); 1420 + t = alloc_tc(tc); 1421 + if (!t) { 1422 + err = -ENOMEM; 1423 + goto out; 1424 + } 1425 + 1426 + local_irq_save(flags); 1427 + mtflags = dmt(); 1428 + vpflags = dvpe(); 1429 + set_c0_mvpcontrol(MVPCONTROL_VPC); 1394 1430 1395 1431 /* VPE's */ 1396 - if (i < ((val & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT) + 1) { 1397 - settc(i); 1432 + if (tc < hw_tcs) { 1433 + settc(tc); 1398 1434 1399 - if ((v = alloc_vpe(i)) == NULL) { 1435 + if ((v = alloc_vpe(tc)) == NULL) { 1400 1436 printk(KERN_WARNING "VPE: unable to allocate VPE\n"); 1401 - return -ENODEV; 1437 + 1438 + goto out_reenable; 1402 1439 } 1403 1440 1404 1441 /* add the tc to the list of this vpe's tc's. */ 1405 1442 list_add(&t->tc, &v->tc); 1406 1443 1407 1444 /* deactivate all but vpe0 */ 1408 - if (i != 0) { 1445 + if (tc >= tclimit) { 1409 1446 unsigned long tmp = read_vpe_c0_vpeconf0(); 1410 1447 1411 1448 tmp &= ~VPECONF0_VPA; ··· 1439 1434 /* disable multi-threading with TC's */ 1440 1435 write_vpe_c0_vpecontrol(read_vpe_c0_vpecontrol() & ~VPECONTROL_TE); 1441 1436 1442 - if (i != 0) { 1437 + if (tc >= vpelimit) { 1443 1438 /* 1444 1439 * Set config to be the same as vpe0, 1445 1440 * particularly kseg0 coherency alg ··· 1451 1446 /* TC's */ 1452 1447 t->pvpe = v; /* set the parent vpe */ 1453 1448 1454 - if (i != 0) { 1449 + if (tc >= tclimit) { 1455 1450 unsigned long tmp; 1456 1451 1457 - settc(i); 1452 + settc(tc); 1458 1453 1459 1454 /* Any TC that is bound to VPE0 gets left as is - in case 1460 1455 we are running SMTC on VPE0. A TC that is bound to any ··· 1484 1479 } 1485 1480 } 1486 1481 1482 + out_reenable: 1487 1483 /* release config state */ 1488 1484 clear_c0_mvpcontrol(MVPCONTROL_VPC); 1485 + 1486 + evpe(vpflags); 1487 + emt(mtflags); 1488 + local_irq_restore(flags); 1489 1489 1490 1490 #ifdef CONFIG_MIPS_APSP_KSPD 1491 1491 kspd_events.kspd_sp_exit = kspd_sp_exit; ··· 1500 1490 out_chrdev: 1501 1491 unregister_chrdev(major, module_name); 1502 1492 1493 + out: 1503 1494 return err; 1504 1495 } 1505 1496
+6
include/asm-mips/mips_mt.h
··· 8 8 9 9 #include <linux/cpumask.h> 10 10 11 + /* 12 + * How many VPEs and TCs is Linux allowed to use? 0 means no limit. 13 + */ 14 + extern int tclimit; 15 + extern int vpelimit; 16 + 11 17 extern cpumask_t mt_fpu_cpumask; 12 18 extern unsigned long mt_fpemul_threshold; 13 19