aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/kernel/vpe.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/kernel/vpe.c')
-rw-r--r--arch/mips/kernel/vpe.c359
1 files changed, 226 insertions, 133 deletions
diff --git a/arch/mips/kernel/vpe.c b/arch/mips/kernel/vpe.c
index a2bee10f04cf..3c09b9785f4c 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
@@ -64,6 +64,10 @@ typedef void *vpe_handle;
64/* If this is set, the section belongs in the init part of the module */ 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)) 65#define INIT_OFFSET_MASK (1UL << (BITS_PER_LONG-1))
66 66
67/*
68 * The number of TCs and VPEs physically available on the core
69 */
70static int hw_tcs, hw_vpes;
67static char module_name[] = "vpe"; 71static char module_name[] = "vpe";
68static int major; 72static int major;
69static const int minor = 1; /* fixed for now */ 73static const int minor = 1; /* fixed for now */
@@ -126,20 +130,17 @@ struct vpe {
126 130
127 /* the list of who wants to know when something major happens */ 131 /* the list of who wants to know when something major happens */
128 struct list_head notify; 132 struct list_head notify;
133
134 unsigned int ntcs;
129}; 135};
130 136
131struct tc { 137struct tc {
132 enum tc_state state; 138 enum tc_state state;
133 int index; 139 int index;
134 140
135 /* parent VPE */ 141 struct vpe *pvpe; /* parent VPE */
136 struct vpe *pvpe; 142 struct list_head tc; /* The list of TC's with this VPE */
137 143 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}; 144};
144 145
145struct { 146struct {
@@ -217,18 +218,17 @@ struct vpe *alloc_vpe(int minor)
217/* allocate a tc. At startup only tc0 is running, all other can be halted. */ 218/* allocate a tc. At startup only tc0 is running, all other can be halted. */
218struct tc *alloc_tc(int index) 219struct tc *alloc_tc(int index)
219{ 220{
220 struct tc *t; 221 struct tc *tc;
221 222
222 if ((t = kzalloc(sizeof(struct tc), GFP_KERNEL)) == NULL) { 223 if ((tc = kzalloc(sizeof(struct tc), GFP_KERNEL)) == NULL)
223 return NULL; 224 goto out;
224 }
225
226 INIT_LIST_HEAD(&t->tc);
227 list_add_tail(&t->list, &vpecontrol.tc_list);
228 225
229 t->index = index; 226 INIT_LIST_HEAD(&tc->tc);
227 tc->index = index;
228 list_add_tail(&tc->list, &vpecontrol.tc_list);
230 229
231 return t; 230out:
231 return tc;
232} 232}
233 233
234/* clean up and free everything */ 234/* clean up and free everything */
@@ -663,66 +663,48 @@ static void dump_elfsymbols(Elf_Shdr * sechdrs, unsigned int symindex,
663} 663}
664#endif 664#endif
665 665
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... */ 666/* We are prepared so configure and start the VPE... */
700static int vpe_run(struct vpe * v) 667static int vpe_run(struct vpe * v)
701{ 668{
669 unsigned long flags, val, dmt_flag;
702 struct vpe_notifications *n; 670 struct vpe_notifications *n;
703 unsigned long val, dmt_flag; 671 unsigned int vpeflags;
704 struct tc *t; 672 struct tc *t;
705 673
706 /* check we are the Master VPE */ 674 /* check we are the Master VPE */
675 local_irq_save(flags);
707 val = read_c0_vpeconf0(); 676 val = read_c0_vpeconf0();
708 if (!(val & VPECONF0_MVP)) { 677 if (!(val & VPECONF0_MVP)) {
709 printk(KERN_WARNING 678 printk(KERN_WARNING
710 "VPE loader: only Master VPE's are allowed to configure MT\n"); 679 "VPE loader: only Master VPE's are allowed to configure MT\n");
680 local_irq_restore(flags);
681
711 return -1; 682 return -1;
712 } 683 }
713 684
714 /* disable MT (using dvpe) */ 685 dmt_flag = dmt();
715 dvpe(); 686 vpeflags = dvpe();
716 687
717 if (!list_empty(&v->tc)) { 688 if (!list_empty(&v->tc)) {
718 if ((t = list_entry(v->tc.next, struct tc, tc)) == NULL) { 689 if ((t = list_entry(v->tc.next, struct tc, tc)) == NULL) {
719 printk(KERN_WARNING "VPE loader: TC %d is already in use.\n", 690 evpe(vpeflags);
720 t->index); 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);
721 return -ENOEXEC; 697 return -ENOEXEC;
722 } 698 }
723 } else { 699 } else {
724 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",
725 v->minor); 706 v->minor);
707
726 return -ENOEXEC; 708 return -ENOEXEC;
727 } 709 }
728 710
@@ -733,21 +715,20 @@ static int vpe_run(struct vpe * v)
733 715
734 /* should check it is halted, and not activated */ 716 /* should check it is halted, and not activated */
735 if ((read_tc_c0_tcstatus() & TCSTATUS_A) || !(read_tc_c0_tchalt() & TCHALT_H)) { 717 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", 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",
737 t->index); 723 t->index);
738 dump_tclist(); 724
739 return -ENOEXEC; 725 return -ENOEXEC;
740 } 726 }
741 727
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. */ 728 /* Write the address we want it to start running from in the TCPC register. */
749 write_tc_c0_tcrestart((unsigned long)v->__start); 729 write_tc_c0_tcrestart((unsigned long)v->__start);
750 write_tc_c0_tccontext((unsigned long)0); 730 write_tc_c0_tccontext((unsigned long)0);
731
751 /* 732 /*
752 * Mark the TC as activated, not interrupt exempt and not dynamically 733 * Mark the TC as activated, not interrupt exempt and not dynamically
753 * allocatable 734 * allocatable
@@ -763,15 +744,15 @@ static int vpe_run(struct vpe * v)
763 * here... Or set $a3 to zero and define DFLT_STACK_SIZE and 744 * here... Or set $a3 to zero and define DFLT_STACK_SIZE and
764 * DFLT_HEAP_SIZE when you compile your program 745 * DFLT_HEAP_SIZE when you compile your program
765 */ 746 */
766 mttgpr(7, physical_memsize); 747 mttgpr(6, v->ntcs);
767 748 mttgpr(7, physical_memsize);
768 749
769 /* set up VPE1 */ 750 /* set up VPE1 */
770 /* 751 /*
771 * bind the TC to VPE 1 as late as possible so we only have the final 752 * 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 753 * VPE registers to set up, and so an EJTAG probe can trigger on it
773 */ 754 */
774 write_tc_c0_tcbind((read_tc_c0_tcbind() & ~TCBIND_CURVPE) | v->minor); 755 write_tc_c0_tcbind((read_tc_c0_tcbind() & ~TCBIND_CURVPE) | 1);
775 756
776 write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() & ~(VPECONF0_VPA)); 757 write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() & ~(VPECONF0_VPA));
777 758
@@ -793,15 +774,16 @@ static int vpe_run(struct vpe * v)
793 /* take system out of configuration state */ 774 /* take system out of configuration state */
794 clear_c0_mvpcontrol(MVPCONTROL_VPC); 775 clear_c0_mvpcontrol(MVPCONTROL_VPC);
795 776
796 /* now safe to re-enable multi-threading */ 777#ifdef CONFIG_SMP
797 emt(dmt_flag);
798
799 /* set it running */
800 evpe(EVPE_ENABLE); 778 evpe(EVPE_ENABLE);
779#else
780 evpe(vpeflags);
781#endif
782 emt(dmt_flag);
783 local_irq_restore(flags);
801 784
802 list_for_each_entry(n, &v->notify, list) { 785 list_for_each_entry(n, &v->notify, list)
803 n->start(v->minor); 786 n->start(minor);
804 }
805 787
806 return 0; 788 return 0;
807} 789}
@@ -1023,23 +1005,15 @@ static int vpe_elfload(struct vpe * v)
1023 return 0; 1005 return 0;
1024} 1006}
1025 1007
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) 1008static void cleanup_tc(struct tc *tc)
1040{ 1009{
1010 unsigned long flags;
1011 unsigned int mtflags, vpflags;
1041 int tmp; 1012 int tmp;
1042 1013
1014 local_irq_save(flags);
1015 mtflags = dmt();
1016 vpflags = dvpe();
1043 /* Put MVPE's into 'configuration state' */ 1017 /* Put MVPE's into 'configuration state' */
1044 set_c0_mvpcontrol(MVPCONTROL_VPC); 1018 set_c0_mvpcontrol(MVPCONTROL_VPC);
1045 1019
@@ -1054,9 +1028,12 @@ static void cleanup_tc(struct tc *tc)
1054 write_tc_c0_tchalt(TCHALT_H); 1028 write_tc_c0_tchalt(TCHALT_H);
1055 1029
1056 /* bind it to anything other than VPE1 */ 1030 /* bind it to anything other than VPE1 */
1057 write_tc_c0_tcbind(read_tc_c0_tcbind() & ~TCBIND_CURVPE); // | TCBIND_CURVPE 1031// write_tc_c0_tcbind(read_tc_c0_tcbind() & ~TCBIND_CURVPE); // | TCBIND_CURVPE
1058 1032
1059 clear_c0_mvpcontrol(MVPCONTROL_VPC); 1033 clear_c0_mvpcontrol(MVPCONTROL_VPC);
1034 evpe(vpflags);
1035 emt(mtflags);
1036 local_irq_restore(flags);
1060} 1037}
1061 1038
1062static int getcwd(char *buff, int size) 1039static int getcwd(char *buff, int size)
@@ -1077,36 +1054,32 @@ static int getcwd(char *buff, int size)
1077/* checks VPE is unused and gets ready to load program */ 1054/* checks VPE is unused and gets ready to load program */
1078static int vpe_open(struct inode *inode, struct file *filp) 1055static int vpe_open(struct inode *inode, struct file *filp)
1079{ 1056{
1080 int minor, ret;
1081 enum vpe_state state; 1057 enum vpe_state state;
1082 struct vpe *v;
1083 struct vpe_notifications *not; 1058 struct vpe_notifications *not;
1059 struct vpe *v;
1060 int ret;
1084 1061
1085 /* assume only 1 device at the mo. */ 1062 if (minor != iminor(inode)) {
1086 if ((minor = iminor(inode)) != 1) { 1063 /* assume only 1 device at the moment. */
1087 printk(KERN_WARNING "VPE loader: only vpe1 is supported\n"); 1064 printk(KERN_WARNING "VPE loader: only vpe1 is supported\n");
1088 return -ENODEV; 1065 return -ENODEV;
1089 } 1066 }
1090 1067
1091 if ((v = get_vpe(minor)) == NULL) { 1068 if ((v = get_vpe(tclimit)) == NULL) {
1092 printk(KERN_WARNING "VPE loader: unable to get vpe\n"); 1069 printk(KERN_WARNING "VPE loader: unable to get vpe\n");
1093 return -ENODEV; 1070 return -ENODEV;
1094 } 1071 }
1095 1072
1096 state = xchg(&v->state, VPE_STATE_INUSE); 1073 state = xchg(&v->state, VPE_STATE_INUSE);
1097 if (state != VPE_STATE_UNUSED) { 1074 if (state != VPE_STATE_UNUSED) {
1098 dvpe();
1099
1100 printk(KERN_DEBUG "VPE loader: tc in use dumping regs\n"); 1075 printk(KERN_DEBUG "VPE loader: tc in use dumping regs\n");
1101 1076
1102 dump_tc(get_tc(minor));
1103
1104 list_for_each_entry(not, &v->notify, list) { 1077 list_for_each_entry(not, &v->notify, list) {
1105 not->stop(minor); 1078 not->stop(tclimit);
1106 } 1079 }
1107 1080
1108 release_progmem(v->load_addr); 1081 release_progmem(v->load_addr);
1109 cleanup_tc(get_tc(minor)); 1082 cleanup_tc(get_tc(tclimit));
1110 } 1083 }
1111 1084
1112 /* this of-course trashes what was there before... */ 1085 /* this of-course trashes what was there before... */
@@ -1133,26 +1106,25 @@ static int vpe_open(struct inode *inode, struct file *filp)
1133 1106
1134 v->shared_ptr = NULL; 1107 v->shared_ptr = NULL;
1135 v->__start = 0; 1108 v->__start = 0;
1109
1136 return 0; 1110 return 0;
1137} 1111}
1138 1112
1139static int vpe_release(struct inode *inode, struct file *filp) 1113static int vpe_release(struct inode *inode, struct file *filp)
1140{ 1114{
1141 int minor, ret = 0;
1142 struct vpe *v; 1115 struct vpe *v;
1143 Elf_Ehdr *hdr; 1116 Elf_Ehdr *hdr;
1117 int ret = 0;
1144 1118
1145 minor = iminor(inode); 1119 v = get_vpe(tclimit);
1146 if ((v = get_vpe(minor)) == NULL) 1120 if (v == NULL)
1147 return -ENODEV; 1121 return -ENODEV;
1148 1122
1149 // simple case of fire and forget, so tell the VPE to run...
1150
1151 hdr = (Elf_Ehdr *) v->pbuffer; 1123 hdr = (Elf_Ehdr *) v->pbuffer;
1152 if (memcmp(hdr->e_ident, ELFMAG, 4) == 0) { 1124 if (memcmp(hdr->e_ident, ELFMAG, 4) == 0) {
1153 if (vpe_elfload(v) >= 0) 1125 if (vpe_elfload(v) >= 0) {
1154 vpe_run(v); 1126 vpe_run(v);
1155 else { 1127 } else {
1156 printk(KERN_WARNING "VPE loader: ELF load failed.\n"); 1128 printk(KERN_WARNING "VPE loader: ELF load failed.\n");
1157 ret = -ENOEXEC; 1129 ret = -ENOEXEC;
1158 } 1130 }
@@ -1179,12 +1151,14 @@ static int vpe_release(struct inode *inode, struct file *filp)
1179static ssize_t vpe_write(struct file *file, const char __user * buffer, 1151static ssize_t vpe_write(struct file *file, const char __user * buffer,
1180 size_t count, loff_t * ppos) 1152 size_t count, loff_t * ppos)
1181{ 1153{
1182 int minor;
1183 size_t ret = count; 1154 size_t ret = count;
1184 struct vpe *v; 1155 struct vpe *v;
1185 1156
1186 minor = iminor(file->f_path.dentry->d_inode); 1157 if (iminor(file->f_path.dentry->d_inode) != minor)
1187 if ((v = get_vpe(minor)) == NULL) 1158 return -ENODEV;
1159
1160 v = get_vpe(tclimit);
1161 if (v == NULL)
1188 return -ENODEV; 1162 return -ENODEV;
1189 1163
1190 if (v->pbuffer == NULL) { 1164 if (v->pbuffer == NULL) {
@@ -1366,62 +1340,173 @@ static void kspd_sp_exit( int sp_id)
1366} 1340}
1367#endif 1341#endif
1368 1342
1369static struct device *vpe_dev; 1343static ssize_t store_kill(struct class_device *dev, 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
1360static ssize_t show_ntcs(struct class_device *cd, char *buf)
1361{
1362 struct vpe *vpe = get_vpe(tclimit);
1363
1364 return sprintf(buf, "%d\n", vpe->ntcs);
1365}
1366
1367static ssize_t store_ntcs(struct class_device *dev, const char *buf, size_t len)
1368{
1369 struct vpe *vpe = get_vpe(tclimit);
1370 unsigned long new;
1371 char *endp;
1372
1373 new = simple_strtoul(buf, &endp, 0);
1374 if (endp == buf)
1375 goto out_einval;
1376
1377 if (new == 0 || new > (hw_tcs - tclimit))
1378 goto out_einval;
1379
1380 vpe->ntcs = new;
1381
1382 return len;
1383
1384out_einval:
1385 return -EINVAL;;
1386}
1387
1388static struct class_device_attribute vpe_class_attributes[] = {
1389 __ATTR(kill, S_IWUSR, NULL, store_kill),
1390 __ATTR(ntcs, S_IRUGO | S_IWUSR, show_ntcs, store_ntcs),
1391 {}
1392};
1393
1394static void vpe_class_device_release(struct class_device *cd)
1395{
1396 kfree(cd);
1397}
1398
1399struct class vpe_class = {
1400 .name = "vpe",
1401 .owner = THIS_MODULE,
1402 .release = vpe_class_device_release,
1403 .class_dev_attrs = vpe_class_attributes,
1404};
1405
1406struct class_device vpe_device;
1370 1407
1371static int __init vpe_module_init(void) 1408static int __init vpe_module_init(void)
1372{ 1409{
1410 unsigned int mtflags, vpflags;
1411 unsigned long flags, val;
1373 struct vpe *v = NULL; 1412 struct vpe *v = NULL;
1374 struct device *dev;
1375 struct tc *t; 1413 struct tc *t;
1376 unsigned long val; 1414 int tc, err;
1377 int i, err;
1378 1415
1379 if (!cpu_has_mipsmt) { 1416 if (!cpu_has_mipsmt) {
1380 printk("VPE loader: not a MIPS MT capable processor\n"); 1417 printk("VPE loader: not a MIPS MT capable processor\n");
1381 return -ENODEV; 1418 return -ENODEV;
1382 } 1419 }
1383 1420
1421 if (vpelimit == 0) {
1422 printk(KERN_WARNING "No VPEs reserved for AP/SP, not "
1423 "initializing VPE loader.\nPass maxvpes=<n> argument as "
1424 "kernel argument\n");
1425
1426 return -ENODEV;
1427 }
1428
1429 if (tclimit == 0) {
1430 printk(KERN_WARNING "No TCs reserved for AP/SP, not "
1431 "initializing VPE loader.\nPass maxtcs=<n> argument as "
1432 "kernel argument\n");
1433
1434 return -ENODEV;
1435 }
1436
1384 major = register_chrdev(0, module_name, &vpe_fops); 1437 major = register_chrdev(0, module_name, &vpe_fops);
1385 if (major < 0) { 1438 if (major < 0) {
1386 printk("VPE loader: unable to register character device\n"); 1439 printk("VPE loader: unable to register character device\n");
1387 return major; 1440 return major;
1388 } 1441 }
1389 1442
1390 dev = device_create(mt_class, NULL, MKDEV(major, minor), 1443 err = class_register(&vpe_class);
1391 "tc%d", minor); 1444 if (err) {
1392 if (IS_ERR(dev)) { 1445 printk(KERN_ERR "vpe_class registration failed\n");
1393 err = PTR_ERR(dev);
1394 goto out_chrdev; 1446 goto out_chrdev;
1395 } 1447 }
1396 vpe_dev = dev;
1397 1448
1398 dmt(); 1449 class_device_initialize(&vpe_device);
1399 dvpe(); 1450 vpe_device.class = &vpe_class,
1451 vpe_device.parent = NULL,
1452 strlcpy(vpe_device.class_id, "vpe1", BUS_ID_SIZE);
1453 vpe_device.devt = MKDEV(major, minor);
1454 err = class_device_add(&vpe_device);
1455 if (err) {
1456 printk(KERN_ERR "Adding vpe_device failed\n");
1457 goto out_class;
1458 }
1459
1460 local_irq_save(flags);
1461 mtflags = dmt();
1462 vpflags = dvpe();
1400 1463
1401 /* Put MVPE's into 'configuration state' */ 1464 /* Put MVPE's into 'configuration state' */
1402 set_c0_mvpcontrol(MVPCONTROL_VPC); 1465 set_c0_mvpcontrol(MVPCONTROL_VPC);
1403 1466
1404 /* dump_mtregs(); */ 1467 /* dump_mtregs(); */
1405 1468
1406
1407 val = read_c0_mvpconf0(); 1469 val = read_c0_mvpconf0();
1408 for (i = 0; i < ((val & MVPCONF0_PTC) + 1); i++) { 1470 hw_tcs = (val & MVPCONF0_PTC) + 1;
1409 t = alloc_tc(i); 1471 hw_vpes = ((val & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT) + 1;
1472
1473 for (tc = tclimit; tc < hw_tcs; tc++) {
1474 /*
1475 * Must re-enable multithreading temporarily or in case we
1476 * reschedule send IPIs or similar we might hang.
1477 */
1478 clear_c0_mvpcontrol(MVPCONTROL_VPC);
1479 evpe(vpflags);
1480 emt(mtflags);
1481 local_irq_restore(flags);
1482 t = alloc_tc(tc);
1483 if (!t) {
1484 err = -ENOMEM;
1485 goto out;
1486 }
1487
1488 local_irq_save(flags);
1489 mtflags = dmt();
1490 vpflags = dvpe();
1491 set_c0_mvpcontrol(MVPCONTROL_VPC);
1410 1492
1411 /* VPE's */ 1493 /* VPE's */
1412 if (i < ((val & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT) + 1) { 1494 if (tc < hw_tcs) {
1413 settc(i); 1495 settc(tc);
1414 1496
1415 if ((v = alloc_vpe(i)) == NULL) { 1497 if ((v = alloc_vpe(tc)) == NULL) {
1416 printk(KERN_WARNING "VPE: unable to allocate VPE\n"); 1498 printk(KERN_WARNING "VPE: unable to allocate VPE\n");
1417 return -ENODEV; 1499
1500 goto out_reenable;
1418 } 1501 }
1419 1502
1503 v->ntcs = hw_tcs - tclimit;
1504
1420 /* add the tc to the list of this vpe's tc's. */ 1505 /* add the tc to the list of this vpe's tc's. */
1421 list_add(&t->tc, &v->tc); 1506 list_add(&t->tc, &v->tc);
1422 1507
1423 /* deactivate all but vpe0 */ 1508 /* deactivate all but vpe0 */
1424 if (i != 0) { 1509 if (tc >= tclimit) {
1425 unsigned long tmp = read_vpe_c0_vpeconf0(); 1510 unsigned long tmp = read_vpe_c0_vpeconf0();
1426 1511
1427 tmp &= ~VPECONF0_VPA; 1512 tmp &= ~VPECONF0_VPA;
@@ -1434,7 +1519,7 @@ static int __init vpe_module_init(void)
1434 /* disable multi-threading with TC's */ 1519 /* disable multi-threading with TC's */
1435 write_vpe_c0_vpecontrol(read_vpe_c0_vpecontrol() & ~VPECONTROL_TE); 1520 write_vpe_c0_vpecontrol(read_vpe_c0_vpecontrol() & ~VPECONTROL_TE);
1436 1521
1437 if (i != 0) { 1522 if (tc >= vpelimit) {
1438 /* 1523 /*
1439 * Set config to be the same as vpe0, 1524 * Set config to be the same as vpe0,
1440 * particularly kseg0 coherency alg 1525 * particularly kseg0 coherency alg
@@ -1446,10 +1531,10 @@ static int __init vpe_module_init(void)
1446 /* TC's */ 1531 /* TC's */
1447 t->pvpe = v; /* set the parent vpe */ 1532 t->pvpe = v; /* set the parent vpe */
1448 1533
1449 if (i != 0) { 1534 if (tc >= tclimit) {
1450 unsigned long tmp; 1535 unsigned long tmp;
1451 1536
1452 settc(i); 1537 settc(tc);
1453 1538
1454 /* Any TC that is bound to VPE0 gets left as is - in case 1539 /* 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 1540 we are running SMTC on VPE0. A TC that is bound to any
@@ -1479,17 +1564,25 @@ static int __init vpe_module_init(void)
1479 } 1564 }
1480 } 1565 }
1481 1566
1567out_reenable:
1482 /* release config state */ 1568 /* release config state */
1483 clear_c0_mvpcontrol(MVPCONTROL_VPC); 1569 clear_c0_mvpcontrol(MVPCONTROL_VPC);
1484 1570
1571 evpe(vpflags);
1572 emt(mtflags);
1573 local_irq_restore(flags);
1574
1485#ifdef CONFIG_MIPS_APSP_KSPD 1575#ifdef CONFIG_MIPS_APSP_KSPD
1486 kspd_events.kspd_sp_exit = kspd_sp_exit; 1576 kspd_events.kspd_sp_exit = kspd_sp_exit;
1487#endif 1577#endif
1488 return 0; 1578 return 0;
1489 1579
1580out_class:
1581 class_unregister(&vpe_class);
1490out_chrdev: 1582out_chrdev:
1491 unregister_chrdev(major, module_name); 1583 unregister_chrdev(major, module_name);
1492 1584
1585out:
1493 return err; 1586 return err;
1494} 1587}
1495 1588
@@ -1503,7 +1596,7 @@ static void __exit vpe_module_exit(void)
1503 } 1596 }
1504 } 1597 }
1505 1598
1506 device_destroy(mt_class, MKDEV(major, minor)); 1599 class_device_del(&vpe_device);
1507 unregister_chrdev(major, module_name); 1600 unregister_chrdev(major, module_name);
1508} 1601}
1509 1602