aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/kernel/vpe.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2007-07-27 14:31:10 -0400
committerRalf Baechle <ralf@linux-mips.org>2007-07-31 16:35:24 -0400
commit07cc0c9e65d3e262f871ea357dd77b41950b1ca5 (patch)
treefa797fa236da6e03c7b778cdc364ac1c3e03b52f /arch/mips/kernel/vpe.c
parentc3a005f4b6a7752608e75d016ef8d07c55285e48 (diff)
[MIPS] MT: Enable coexistence of AP/SP with VSMP and SMTC.
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips/kernel/vpe.c')
-rw-r--r--arch/mips/kernel/vpe.c263
1 files changed, 137 insertions, 126 deletions
diff --git a/arch/mips/kernel/vpe.c b/arch/mips/kernel/vpe.c
index a2bee10f04cf..c726c47cd2c3 100644
--- a/arch/mips/kernel/vpe.c
+++ b/arch/mips/kernel/vpe.c
@@ -27,7 +27,6 @@
27 * To load and run, simply cat a SP 'program file' to /dev/vpe1. 27 * To load and run, simply cat a SP 'program file' to /dev/vpe1.
28 * i.e cat spapp >/dev/vpe1. 28 * i.e cat spapp >/dev/vpe1.
29 */ 29 */
30
31#include <linux/kernel.h> 30#include <linux/kernel.h>
32#include <linux/device.h> 31#include <linux/device.h>
33#include <linux/module.h> 32#include <linux/module.h>
@@ -54,6 +53,7 @@
54#include <asm/system.h> 53#include <asm/system.h>
55#include <asm/vpe.h> 54#include <asm/vpe.h>
56#include <asm/kspd.h> 55#include <asm/kspd.h>
56#include <asm/mips_mt.h>
57 57
58typedef void *vpe_handle; 58typedef void *vpe_handle;
59 59
@@ -132,14 +132,9 @@ struct tc {
132 enum tc_state state; 132 enum tc_state state;
133 int index; 133 int index;
134 134
135 /* parent VPE */ 135 struct vpe *pvpe; /* parent VPE */
136 struct vpe *pvpe; 136 struct list_head tc; /* The list of TC's with this VPE */
137 137 struct list_head list; /* The global list of tc's */
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;
143}; 138};
144 139
145struct { 140struct {
@@ -217,18 +212,17 @@ struct vpe *alloc_vpe(int minor)
217/* allocate a tc. At startup only tc0 is running, all other can be halted. */ 212/* allocate a tc. At startup only tc0 is running, all other can be halted. */
218struct tc *alloc_tc(int index) 213struct tc *alloc_tc(int index)
219{ 214{
220 struct tc *t; 215 struct tc *tc;
221
222 if ((t = kzalloc(sizeof(struct tc), GFP_KERNEL)) == NULL) {
223 return NULL;
224 }
225 216
226 INIT_LIST_HEAD(&t->tc); 217 if ((tc = kzalloc(sizeof(struct tc), GFP_KERNEL)) == NULL)
227 list_add_tail(&t->list, &vpecontrol.tc_list); 218 goto out;
228 219
229 t->index = index; 220 INIT_LIST_HEAD(&tc->tc);
221 tc->index = index;
222 list_add_tail(&tc->list, &vpecontrol.tc_list);
230 223
231 return t; 224out:
225 return tc;
232} 226}
233 227
234/* clean up and free everything */ 228/* clean up and free everything */
@@ -663,66 +657,48 @@ static void dump_elfsymbols(Elf_Shdr * sechdrs, unsigned int symindex,
663} 657}
664#endif 658#endif
665 659
666static void dump_tc(struct tc *t)
667{
668 unsigned long val;
669
670 settc(t->index);
671 printk(KERN_DEBUG "VPE loader: TC index %d targtc %ld "
672 "TCStatus 0x%lx halt 0x%lx\n",
673 t->index, read_c0_vpecontrol() & VPECONTROL_TARGTC,
674 read_tc_c0_tcstatus(), read_tc_c0_tchalt());
675
676 printk(KERN_DEBUG " tcrestart 0x%lx\n", read_tc_c0_tcrestart());
677 printk(KERN_DEBUG " tcbind 0x%lx\n", read_tc_c0_tcbind());
678
679 val = read_c0_vpeconf0();
680 printk(KERN_DEBUG " VPEConf0 0x%lx MVP %ld\n", val,
681 (val & VPECONF0_MVP) >> VPECONF0_MVP_SHIFT);
682
683 printk(KERN_DEBUG " c0 status 0x%lx\n", read_vpe_c0_status());
684 printk(KERN_DEBUG " c0 cause 0x%lx\n", read_vpe_c0_cause());
685
686 printk(KERN_DEBUG " c0 badvaddr 0x%lx\n", read_vpe_c0_badvaddr());
687 printk(KERN_DEBUG " c0 epc 0x%lx\n", read_vpe_c0_epc());
688}
689
690static void dump_tclist(void)
691{
692 struct tc *t;
693
694 list_for_each_entry(t, &vpecontrol.tc_list, list) {
695 dump_tc(t);
696 }
697}
698
699/* We are prepared so configure and start the VPE... */ 660/* We are prepared so configure and start the VPE... */
700static int vpe_run(struct vpe * v) 661static int vpe_run(struct vpe * v)
701{ 662{
663 unsigned long flags, val, dmt_flag;
702 struct vpe_notifications *n; 664 struct vpe_notifications *n;
703 unsigned long val, dmt_flag; 665 unsigned int vpeflags;
704 struct tc *t; 666 struct tc *t;
705 667
706 /* check we are the Master VPE */ 668 /* check we are the Master VPE */
669 local_irq_save(flags);
707 val = read_c0_vpeconf0(); 670 val = read_c0_vpeconf0();
708 if (!(val & VPECONF0_MVP)) { 671 if (!(val & VPECONF0_MVP)) {
709 printk(KERN_WARNING 672 printk(KERN_WARNING
710 "VPE loader: only Master VPE's are allowed to configure MT\n"); 673 "VPE loader: only Master VPE's are allowed to configure MT\n");
674 local_irq_restore(flags);
675
711 return -1; 676 return -1;
712 } 677 }
713 678
714 /* disable MT (using dvpe) */ 679 dmt_flag = dmt();
715 dvpe(); 680 vpeflags = dvpe();
716 681
717 if (!list_empty(&v->tc)) { 682 if (!list_empty(&v->tc)) {
718 if ((t = list_entry(v->tc.next, struct tc, tc)) == NULL) { 683 if ((t = list_entry(v->tc.next, struct tc, tc)) == NULL) {
719 printk(KERN_WARNING "VPE loader: TC %d is already in use.\n", 684 evpe(vpeflags);
720 t->index); 685 emt(dmt_flag);
686 local_irq_restore(flags);
687
688 printk(KERN_WARNING
689 "VPE loader: TC %d is already in use.\n",
690 t->index);
721 return -ENOEXEC; 691 return -ENOEXEC;
722 } 692 }
723 } else { 693 } else {
724 printk(KERN_WARNING "VPE loader: No TC's associated with VPE %d\n", 694 evpe(vpeflags);
695 emt(dmt_flag);
696 local_irq_restore(flags);
697
698 printk(KERN_WARNING
699 "VPE loader: No TC's associated with VPE %d\n",
725 v->minor); 700 v->minor);
701
726 return -ENOEXEC; 702 return -ENOEXEC;
727 } 703 }
728 704
@@ -733,21 +709,20 @@ static int vpe_run(struct vpe * v)
733 709
734 /* should check it is halted, and not activated */ 710 /* should check it is halted, and not activated */
735 if ((read_tc_c0_tcstatus() & TCSTATUS_A) || !(read_tc_c0_tchalt() & TCHALT_H)) { 711 if ((read_tc_c0_tcstatus() & TCSTATUS_A) || !(read_tc_c0_tchalt() & TCHALT_H)) {
736 printk(KERN_WARNING "VPE loader: TC %d is already doing something!\n", 712 evpe(vpeflags);
713 emt(dmt_flag);
714 local_irq_restore(flags);
715
716 printk(KERN_WARNING "VPE loader: TC %d is already active!\n",
737 t->index); 717 t->index);
738 dump_tclist(); 718
739 return -ENOEXEC; 719 return -ENOEXEC;
740 } 720 }
741 721
742 /*
743 * Disable multi-threaded execution whilst we activate, clear the
744 * halt bit and bound the tc to the other VPE...
745 */
746 dmt_flag = dmt();
747
748 /* Write the address we want it to start running from in the TCPC register. */ 722 /* Write the address we want it to start running from in the TCPC register. */
749 write_tc_c0_tcrestart((unsigned long)v->__start); 723 write_tc_c0_tcrestart((unsigned long)v->__start);
750 write_tc_c0_tccontext((unsigned long)0); 724 write_tc_c0_tccontext((unsigned long)0);
725
751 /* 726 /*
752 * Mark the TC as activated, not interrupt exempt and not dynamically 727 * Mark the TC as activated, not interrupt exempt and not dynamically
753 * allocatable 728 * allocatable
@@ -763,15 +738,14 @@ static int vpe_run(struct vpe * v)
763 * here... Or set $a3 to zero and define DFLT_STACK_SIZE and 738 * here... Or set $a3 to zero and define DFLT_STACK_SIZE and
764 * DFLT_HEAP_SIZE when you compile your program 739 * DFLT_HEAP_SIZE when you compile your program
765 */ 740 */
766 mttgpr(7, physical_memsize); 741 mttgpr(7, physical_memsize);
767
768 742
769 /* set up VPE1 */ 743 /* set up VPE1 */
770 /* 744 /*
771 * bind the TC to VPE 1 as late as possible so we only have the final 745 * bind the TC to VPE 1 as late as possible so we only have the final
772 * VPE registers to set up, and so an EJTAG probe can trigger on it 746 * VPE registers to set up, and so an EJTAG probe can trigger on it
773 */ 747 */
774 write_tc_c0_tcbind((read_tc_c0_tcbind() & ~TCBIND_CURVPE) | v->minor); 748 write_tc_c0_tcbind((read_tc_c0_tcbind() & ~TCBIND_CURVPE) | 1);
775 749
776 write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() & ~(VPECONF0_VPA)); 750 write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() & ~(VPECONF0_VPA));
777 751
@@ -793,15 +767,16 @@ static int vpe_run(struct vpe * v)
793 /* take system out of configuration state */ 767 /* take system out of configuration state */
794 clear_c0_mvpcontrol(MVPCONTROL_VPC); 768 clear_c0_mvpcontrol(MVPCONTROL_VPC);
795 769
796 /* now safe to re-enable multi-threading */ 770#ifdef CONFIG_SMP
797 emt(dmt_flag);
798
799 /* set it running */
800 evpe(EVPE_ENABLE); 771 evpe(EVPE_ENABLE);
772#else
773 evpe(vpeflags);
774#endif
775 emt(dmt_flag);
776 local_irq_restore(flags);
801 777
802 list_for_each_entry(n, &v->notify, list) { 778 list_for_each_entry(n, &v->notify, list)
803 n->start(v->minor); 779 n->start(minor);
804 }
805 780
806 return 0; 781 return 0;
807} 782}
@@ -1023,23 +998,15 @@ static int vpe_elfload(struct vpe * v)
1023 return 0; 998 return 0;
1024} 999}
1025 1000
1026void __used dump_vpe(struct vpe * v)
1027{
1028 struct tc *t;
1029
1030 settc(v->minor);
1031
1032 printk(KERN_DEBUG "VPEControl 0x%lx\n", read_vpe_c0_vpecontrol());
1033 printk(KERN_DEBUG "VPEConf0 0x%lx\n", read_vpe_c0_vpeconf0());
1034
1035 list_for_each_entry(t, &vpecontrol.tc_list, list)
1036 dump_tc(t);
1037}
1038
1039static void cleanup_tc(struct tc *tc) 1001static void cleanup_tc(struct tc *tc)
1040{ 1002{
1003 unsigned long flags;
1004 unsigned int mtflags, vpflags;
1041 int tmp; 1005 int tmp;
1042 1006
1007 local_irq_save(flags);
1008 mtflags = dmt();
1009 vpflags = dvpe();
1043 /* Put MVPE's into 'configuration state' */ 1010 /* Put MVPE's into 'configuration state' */
1044 set_c0_mvpcontrol(MVPCONTROL_VPC); 1011 set_c0_mvpcontrol(MVPCONTROL_VPC);
1045 1012
@@ -1054,9 +1021,12 @@ static void cleanup_tc(struct tc *tc)
1054 write_tc_c0_tchalt(TCHALT_H); 1021 write_tc_c0_tchalt(TCHALT_H);
1055 1022
1056 /* bind it to anything other than VPE1 */ 1023 /* bind it to anything other than VPE1 */
1057 write_tc_c0_tcbind(read_tc_c0_tcbind() & ~TCBIND_CURVPE); // | TCBIND_CURVPE 1024// write_tc_c0_tcbind(read_tc_c0_tcbind() & ~TCBIND_CURVPE); // | TCBIND_CURVPE
1058 1025
1059 clear_c0_mvpcontrol(MVPCONTROL_VPC); 1026 clear_c0_mvpcontrol(MVPCONTROL_VPC);
1027 evpe(vpflags);
1028 emt(mtflags);
1029 local_irq_restore(flags);
1060} 1030}
1061 1031
1062static int getcwd(char *buff, int size) 1032static int getcwd(char *buff, int size)
@@ -1077,36 +1047,32 @@ static int getcwd(char *buff, int size)
1077/* checks VPE is unused and gets ready to load program */ 1047/* checks VPE is unused and gets ready to load program */
1078static int vpe_open(struct inode *inode, struct file *filp) 1048static int vpe_open(struct inode *inode, struct file *filp)
1079{ 1049{
1080 int minor, ret;
1081 enum vpe_state state; 1050 enum vpe_state state;
1082 struct vpe *v;
1083 struct vpe_notifications *not; 1051 struct vpe_notifications *not;
1052 struct vpe *v;
1053 int ret;
1084 1054
1085 /* assume only 1 device at the mo. */ 1055 if (minor != iminor(inode)) {
1086 if ((minor = iminor(inode)) != 1) { 1056 /* assume only 1 device at the moment. */
1087 printk(KERN_WARNING "VPE loader: only vpe1 is supported\n"); 1057 printk(KERN_WARNING "VPE loader: only vpe1 is supported\n");
1088 return -ENODEV; 1058 return -ENODEV;
1089 } 1059 }
1090 1060
1091 if ((v = get_vpe(minor)) == NULL) { 1061 if ((v = get_vpe(tclimit)) == NULL) {
1092 printk(KERN_WARNING "VPE loader: unable to get vpe\n"); 1062 printk(KERN_WARNING "VPE loader: unable to get vpe\n");
1093 return -ENODEV; 1063 return -ENODEV;
1094 } 1064 }
1095 1065
1096 state = xchg(&v->state, VPE_STATE_INUSE); 1066 state = xchg(&v->state, VPE_STATE_INUSE);
1097 if (state != VPE_STATE_UNUSED) { 1067 if (state != VPE_STATE_UNUSED) {
1098 dvpe();
1099
1100 printk(KERN_DEBUG "VPE loader: tc in use dumping regs\n"); 1068 printk(KERN_DEBUG "VPE loader: tc in use dumping regs\n");
1101 1069
1102 dump_tc(get_tc(minor));
1103
1104 list_for_each_entry(not, &v->notify, list) { 1070 list_for_each_entry(not, &v->notify, list) {
1105 not->stop(minor); 1071 not->stop(tclimit);
1106 } 1072 }
1107 1073
1108 release_progmem(v->load_addr); 1074 release_progmem(v->load_addr);
1109 cleanup_tc(get_tc(minor)); 1075 cleanup_tc(get_tc(tclimit));
1110 } 1076 }
1111 1077
1112 /* this of-course trashes what was there before... */ 1078 /* this of-course trashes what was there before... */
@@ -1133,26 +1099,25 @@ static int vpe_open(struct inode *inode, struct file *filp)
1133 1099
1134 v->shared_ptr = NULL; 1100 v->shared_ptr = NULL;
1135 v->__start = 0; 1101 v->__start = 0;
1102
1136 return 0; 1103 return 0;
1137} 1104}
1138 1105
1139static int vpe_release(struct inode *inode, struct file *filp) 1106static int vpe_release(struct inode *inode, struct file *filp)
1140{ 1107{
1141 int minor, ret = 0;
1142 struct vpe *v; 1108 struct vpe *v;
1143 Elf_Ehdr *hdr; 1109 Elf_Ehdr *hdr;
1110 int ret = 0;
1144 1111
1145 minor = iminor(inode); 1112 v = get_vpe(tclimit);
1146 if ((v = get_vpe(minor)) == NULL) 1113 if (v == NULL)
1147 return -ENODEV; 1114 return -ENODEV;
1148 1115
1149 // simple case of fire and forget, so tell the VPE to run...
1150
1151 hdr = (Elf_Ehdr *) v->pbuffer; 1116 hdr = (Elf_Ehdr *) v->pbuffer;
1152 if (memcmp(hdr->e_ident, ELFMAG, 4) == 0) { 1117 if (memcmp(hdr->e_ident, ELFMAG, 4) == 0) {
1153 if (vpe_elfload(v) >= 0) 1118 if (vpe_elfload(v) >= 0) {
1154 vpe_run(v); 1119 vpe_run(v);
1155 else { 1120 } else {
1156 printk(KERN_WARNING "VPE loader: ELF load failed.\n"); 1121 printk(KERN_WARNING "VPE loader: ELF load failed.\n");
1157 ret = -ENOEXEC; 1122 ret = -ENOEXEC;
1158 } 1123 }
@@ -1179,12 +1144,14 @@ static int vpe_release(struct inode *inode, struct file *filp)
1179static ssize_t vpe_write(struct file *file, const char __user * buffer, 1144static ssize_t vpe_write(struct file *file, const char __user * buffer,
1180 size_t count, loff_t * ppos) 1145 size_t count, loff_t * ppos)
1181{ 1146{
1182 int minor;
1183 size_t ret = count; 1147 size_t ret = count;
1184 struct vpe *v; 1148 struct vpe *v;
1185 1149
1186 minor = iminor(file->f_path.dentry->d_inode); 1150 if (iminor(file->f_path.dentry->d_inode) != minor)
1187 if ((v = get_vpe(minor)) == NULL) 1151 return -ENODEV;
1152
1153 v = get_vpe(tclimit);
1154 if (v == NULL)
1188 return -ENODEV; 1155 return -ENODEV;
1189 1156
1190 if (v->pbuffer == NULL) { 1157 if (v->pbuffer == NULL) {
@@ -1370,17 +1337,34 @@ static struct device *vpe_dev;
1370 1337
1371static int __init vpe_module_init(void) 1338static int __init vpe_module_init(void)
1372{ 1339{
1340 unsigned int mtflags, vpflags;
1341 int hw_tcs, hw_vpes, tc, err = 0;
1342 unsigned long flags, val;
1373 struct vpe *v = NULL; 1343 struct vpe *v = NULL;
1374 struct device *dev; 1344 struct device *dev;
1375 struct tc *t; 1345 struct tc *t;
1376 unsigned long val;
1377 int i, err;
1378 1346
1379 if (!cpu_has_mipsmt) { 1347 if (!cpu_has_mipsmt) {
1380 printk("VPE loader: not a MIPS MT capable processor\n"); 1348 printk("VPE loader: not a MIPS MT capable processor\n");
1381 return -ENODEV; 1349 return -ENODEV;
1382 } 1350 }
1383 1351
1352 if (vpelimit == 0) {
1353 printk(KERN_WARNING "No VPEs reserved for AP/SP, not "
1354 "initializing VPE loader.\nPass maxvpes=<n> argument as "
1355 "kernel argument\n");
1356
1357 return -ENODEV;
1358 }
1359
1360 if (tclimit == 0) {
1361 printk(KERN_WARNING "No TCs reserved for AP/SP, not "
1362 "initializing VPE loader.\nPass maxtcs=<n> argument as "
1363 "kernel argument\n");
1364
1365 return -ENODEV;
1366 }
1367
1384 major = register_chrdev(0, module_name, &vpe_fops); 1368 major = register_chrdev(0, module_name, &vpe_fops);
1385 if (major < 0) { 1369 if (major < 0) {
1386 printk("VPE loader: unable to register character device\n"); 1370 printk("VPE loader: unable to register character device\n");
@@ -1388,40 +1372,61 @@ static int __init vpe_module_init(void)
1388 } 1372 }
1389 1373
1390 dev = device_create(mt_class, NULL, MKDEV(major, minor), 1374 dev = device_create(mt_class, NULL, MKDEV(major, minor),
1391 "tc%d", minor); 1375 "vpe%d", minor);
1392 if (IS_ERR(dev)) { 1376 if (IS_ERR(dev)) {
1393 err = PTR_ERR(dev); 1377 err = PTR_ERR(dev);
1394 goto out_chrdev; 1378 goto out_chrdev;
1395 } 1379 }
1396 vpe_dev = dev; 1380 vpe_dev = dev;
1397 1381
1398 dmt(); 1382 local_irq_save(flags);
1399 dvpe(); 1383 mtflags = dmt();
1384 vpflags = dvpe();
1400 1385
1401 /* Put MVPE's into 'configuration state' */ 1386 /* Put MVPE's into 'configuration state' */
1402 set_c0_mvpcontrol(MVPCONTROL_VPC); 1387 set_c0_mvpcontrol(MVPCONTROL_VPC);
1403 1388
1404 /* dump_mtregs(); */ 1389 /* dump_mtregs(); */
1405 1390
1406
1407 val = read_c0_mvpconf0(); 1391 val = read_c0_mvpconf0();
1408 for (i = 0; i < ((val & MVPCONF0_PTC) + 1); i++) { 1392 hw_tcs = (val & MVPCONF0_PTC) + 1;
1409 t = alloc_tc(i); 1393 hw_vpes = ((val & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT) + 1;
1394
1395 for (tc = tclimit; tc < hw_tcs; tc++) {
1396 /*
1397 * Must re-enable multithreading temporarily or in case we
1398 * reschedule send IPIs or similar we might hang.
1399 */
1400 clear_c0_mvpcontrol(MVPCONTROL_VPC);
1401 evpe(vpflags);
1402 emt(mtflags);
1403 local_irq_restore(flags);
1404 t = alloc_tc(tc);
1405 if (!t) {
1406 err = -ENOMEM;
1407 goto out;
1408 }
1409
1410 local_irq_save(flags);
1411 mtflags = dmt();
1412 vpflags = dvpe();
1413 set_c0_mvpcontrol(MVPCONTROL_VPC);
1410 1414
1411 /* VPE's */ 1415 /* VPE's */
1412 if (i < ((val & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT) + 1) { 1416 if (tc < hw_tcs) {
1413 settc(i); 1417 settc(tc);
1414 1418
1415 if ((v = alloc_vpe(i)) == NULL) { 1419 if ((v = alloc_vpe(tc)) == NULL) {
1416 printk(KERN_WARNING "VPE: unable to allocate VPE\n"); 1420 printk(KERN_WARNING "VPE: unable to allocate VPE\n");
1417 return -ENODEV; 1421
1422 goto out_reenable;
1418 } 1423 }
1419 1424
1420 /* add the tc to the list of this vpe's tc's. */ 1425 /* add the tc to the list of this vpe's tc's. */
1421 list_add(&t->tc, &v->tc); 1426 list_add(&t->tc, &v->tc);
1422 1427
1423 /* deactivate all but vpe0 */ 1428 /* deactivate all but vpe0 */
1424 if (i != 0) { 1429 if (tc >= tclimit) {
1425 unsigned long tmp = read_vpe_c0_vpeconf0(); 1430 unsigned long tmp = read_vpe_c0_vpeconf0();
1426 1431
1427 tmp &= ~VPECONF0_VPA; 1432 tmp &= ~VPECONF0_VPA;
@@ -1434,7 +1439,7 @@ static int __init vpe_module_init(void)
1434 /* disable multi-threading with TC's */ 1439 /* disable multi-threading with TC's */
1435 write_vpe_c0_vpecontrol(read_vpe_c0_vpecontrol() & ~VPECONTROL_TE); 1440 write_vpe_c0_vpecontrol(read_vpe_c0_vpecontrol() & ~VPECONTROL_TE);
1436 1441
1437 if (i != 0) { 1442 if (tc >= vpelimit) {
1438 /* 1443 /*
1439 * Set config to be the same as vpe0, 1444 * Set config to be the same as vpe0,
1440 * particularly kseg0 coherency alg 1445 * particularly kseg0 coherency alg
@@ -1446,10 +1451,10 @@ static int __init vpe_module_init(void)
1446 /* TC's */ 1451 /* TC's */
1447 t->pvpe = v; /* set the parent vpe */ 1452 t->pvpe = v; /* set the parent vpe */
1448 1453
1449 if (i != 0) { 1454 if (tc >= tclimit) {
1450 unsigned long tmp; 1455 unsigned long tmp;
1451 1456
1452 settc(i); 1457 settc(tc);
1453 1458
1454 /* Any TC that is bound to VPE0 gets left as is - in case 1459 /* Any TC that is bound to VPE0 gets left as is - in case
1455 we are running SMTC on VPE0. A TC that is bound to any 1460 we are running SMTC on VPE0. A TC that is bound to any
@@ -1479,9 +1484,14 @@ static int __init vpe_module_init(void)
1479 } 1484 }
1480 } 1485 }
1481 1486
1487out_reenable:
1482 /* release config state */ 1488 /* release config state */
1483 clear_c0_mvpcontrol(MVPCONTROL_VPC); 1489 clear_c0_mvpcontrol(MVPCONTROL_VPC);
1484 1490
1491 evpe(vpflags);
1492 emt(mtflags);
1493 local_irq_restore(flags);
1494
1485#ifdef CONFIG_MIPS_APSP_KSPD 1495#ifdef CONFIG_MIPS_APSP_KSPD
1486 kspd_events.kspd_sp_exit = kspd_sp_exit; 1496 kspd_events.kspd_sp_exit = kspd_sp_exit;
1487#endif 1497#endif
@@ -1490,6 +1500,7 @@ static int __init vpe_module_init(void)
1490out_chrdev: 1500out_chrdev:
1491 unregister_chrdev(major, module_name); 1501 unregister_chrdev(major, module_name);
1492 1502
1503out:
1493 return err; 1504 return err;
1494} 1505}
1495 1506