vpe.c (e23c34bb41da65f354fb7eee04300c56ee48f60c) | vpe.c (1a2a6d7e8816ed2b2679a0c4f7ba4019cd31dd62) |
---|---|
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 --- 37 unchanged lines hidden (view full) --- 46#include <asm/mipsmtregs.h> 47#include <asm/cacheflush.h> 48#include <linux/atomic.h> 49#include <asm/cpu.h> 50#include <asm/mips_mt.h> 51#include <asm/processor.h> 52#include <asm/vpe.h> 53 | 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 --- 37 unchanged lines hidden (view full) --- 46#include <asm/mipsmtregs.h> 47#include <asm/cacheflush.h> 48#include <linux/atomic.h> 49#include <asm/cpu.h> 50#include <asm/mips_mt.h> 51#include <asm/processor.h> 52#include <asm/vpe.h> 53 |
54typedef void *vpe_handle; 55 | |
56#ifndef ARCH_SHF_SMALL 57#define ARCH_SHF_SMALL 0 58#endif 59 60/* If this is set, the section belongs in the init part of the module */ 61#define INIT_OFFSET_MASK (1UL << (BITS_PER_LONG-1)) 62 | 54#ifndef ARCH_SHF_SMALL 55#define ARCH_SHF_SMALL 0 56#endif 57 58/* If this is set, the section belongs in the init part of the module */ 59#define INIT_OFFSET_MASK (1UL << (BITS_PER_LONG-1)) 60 |
63/* 64 * The number of TCs and VPEs physically available on the core 65 */ 66static int hw_tcs, hw_vpes; 67static char module_name[] = "vpe"; 68static int major; 69static const int minor = 1; /* fixed for now */ 70 71/* grab the likely amount of memory we will need. */ 72#ifdef CONFIG_MIPS_VPE_LOADER_TOM 73#define P_SIZE (2 * 1024 * 1024) 74#else 75/* add an overhead to the max kmalloc size for non-striped symbols/etc */ 76#define P_SIZE (256 * 1024) 77#endif 78 79extern unsigned long physical_memsize; 80 81#define MAX_VPES 16 82#define VPE_PATH_MAX 256 83 84enum vpe_state { 85 VPE_STATE_UNUSED = 0, 86 VPE_STATE_INUSE, 87 VPE_STATE_RUNNING 88}; 89 90enum tc_state { 91 TC_STATE_UNUSED = 0, 92 TC_STATE_INUSE, 93 TC_STATE_RUNNING, 94 TC_STATE_DYNAMIC 95}; 96 97struct vpe { 98 enum vpe_state state; 99 100 /* (device) minor associated with this vpe */ 101 int minor; 102 103 /* elfloader stuff */ 104 void *load_addr; 105 unsigned long len; 106 char *pbuffer; 107 unsigned long plen; 108 unsigned int uid, gid; 109 char cwd[VPE_PATH_MAX]; 110 111 unsigned long __start; 112 113 /* tc's associated with this vpe */ 114 struct list_head tc; 115 116 /* The list of vpe's */ 117 struct list_head list; 118 119 /* shared symbol address */ 120 void *shared_ptr; 121 122 /* the list of who wants to know when something major happens */ 123 struct list_head notify; 124 125 unsigned int ntcs; 126}; 127 128struct tc { 129 enum tc_state state; 130 int index; 131 132 struct vpe *pvpe; /* parent VPE */ 133 struct list_head tc; /* The list of TC's with this VPE */ 134 struct list_head list; /* The global list of tc's */ 135}; 136 137struct { 138 spinlock_t vpe_list_lock; 139 struct list_head vpe_list; /* Virtual processing elements */ 140 spinlock_t tc_list_lock; 141 struct list_head tc_list; /* Thread contexts */ 142} vpecontrol = { | 61struct vpe_control vpecontrol = { |
143 .vpe_list_lock = __SPIN_LOCK_UNLOCKED(vpe_list_lock), 144 .vpe_list = LIST_HEAD_INIT(vpecontrol.vpe_list), 145 .tc_list_lock = __SPIN_LOCK_UNLOCKED(tc_list_lock), 146 .tc_list = LIST_HEAD_INIT(vpecontrol.tc_list) 147}; 148 | 62 .vpe_list_lock = __SPIN_LOCK_UNLOCKED(vpe_list_lock), 63 .vpe_list = LIST_HEAD_INIT(vpecontrol.vpe_list), 64 .tc_list_lock = __SPIN_LOCK_UNLOCKED(tc_list_lock), 65 .tc_list = LIST_HEAD_INIT(vpecontrol.tc_list) 66}; 67 |
149static void release_progmem(void *ptr); 150 | |
151/* get the vpe associated with this minor */ | 68/* get the vpe associated with this minor */ |
152static struct vpe *get_vpe(int minor) | 69struct vpe *get_vpe(int minor) |
153{ 154 struct vpe *res, *v; 155 156 if (!cpu_has_mipsmt) 157 return NULL; 158 159 res = NULL; 160 spin_lock(&vpecontrol.vpe_list_lock); 161 list_for_each_entry(v, &vpecontrol.vpe_list, list) { | 70{ 71 struct vpe *res, *v; 72 73 if (!cpu_has_mipsmt) 74 return NULL; 75 76 res = NULL; 77 spin_lock(&vpecontrol.vpe_list_lock); 78 list_for_each_entry(v, &vpecontrol.vpe_list, list) { |
162 if (v->minor == minor) { | 79 if (v->minor == VPE_MODULE_MINOR) { |
163 res = v; 164 break; 165 } 166 } 167 spin_unlock(&vpecontrol.vpe_list_lock); 168 169 return res; 170} 171 172/* get the vpe associated with this minor */ | 80 res = v; 81 break; 82 } 83 } 84 spin_unlock(&vpecontrol.vpe_list_lock); 85 86 return res; 87} 88 89/* get the vpe associated with this minor */ |
173static struct tc *get_tc(int index) | 90struct tc *get_tc(int index) |
174{ 175 struct tc *res, *t; 176 177 res = NULL; 178 spin_lock(&vpecontrol.tc_list_lock); 179 list_for_each_entry(t, &vpecontrol.tc_list, list) { 180 if (t->index == index) { 181 res = t; 182 break; 183 } 184 } 185 spin_unlock(&vpecontrol.tc_list_lock); 186 187 return res; 188} 189 190/* allocate a vpe and associate it with this minor (or index) */ | 91{ 92 struct tc *res, *t; 93 94 res = NULL; 95 spin_lock(&vpecontrol.tc_list_lock); 96 list_for_each_entry(t, &vpecontrol.tc_list, list) { 97 if (t->index == index) { 98 res = t; 99 break; 100 } 101 } 102 spin_unlock(&vpecontrol.tc_list_lock); 103 104 return res; 105} 106 107/* allocate a vpe and associate it with this minor (or index) */ |
191static struct vpe *alloc_vpe(int minor) | 108struct vpe *alloc_vpe(int minor) |
192{ 193 struct vpe *v; 194 195 if ((v = kzalloc(sizeof(struct vpe), GFP_KERNEL)) == NULL) 196 return NULL; 197 198 INIT_LIST_HEAD(&v->tc); 199 spin_lock(&vpecontrol.vpe_list_lock); 200 list_add_tail(&v->list, &vpecontrol.vpe_list); 201 spin_unlock(&vpecontrol.vpe_list_lock); 202 203 INIT_LIST_HEAD(&v->notify); | 109{ 110 struct vpe *v; 111 112 if ((v = kzalloc(sizeof(struct vpe), GFP_KERNEL)) == NULL) 113 return NULL; 114 115 INIT_LIST_HEAD(&v->tc); 116 spin_lock(&vpecontrol.vpe_list_lock); 117 list_add_tail(&v->list, &vpecontrol.vpe_list); 118 spin_unlock(&vpecontrol.vpe_list_lock); 119 120 INIT_LIST_HEAD(&v->notify); |
204 v->minor = minor; | 121 v->minor = VPE_MODULE_MINOR; |
205 206 return v; 207} 208 209/* allocate a tc. At startup only tc0 is running, all other can be halted. */ | 122 123 return v; 124} 125 126/* allocate a tc. At startup only tc0 is running, all other can be halted. */ |
210static struct tc *alloc_tc(int index) | 127struct tc *alloc_tc(int index) |
211{ 212 struct tc *tc; 213 214 if ((tc = kzalloc(sizeof(struct tc), GFP_KERNEL)) == NULL) 215 goto out; 216 217 INIT_LIST_HEAD(&tc->tc); 218 tc->index = index; 219 220 spin_lock(&vpecontrol.tc_list_lock); 221 list_add_tail(&tc->list, &vpecontrol.tc_list); 222 spin_unlock(&vpecontrol.tc_list_lock); 223 224out: 225 return tc; 226} 227 228/* clean up and free everything */ | 128{ 129 struct tc *tc; 130 131 if ((tc = kzalloc(sizeof(struct tc), GFP_KERNEL)) == NULL) 132 goto out; 133 134 INIT_LIST_HEAD(&tc->tc); 135 tc->index = index; 136 137 spin_lock(&vpecontrol.tc_list_lock); 138 list_add_tail(&tc->list, &vpecontrol.tc_list); 139 spin_unlock(&vpecontrol.tc_list_lock); 140 141out: 142 return tc; 143} 144 145/* clean up and free everything */ |
229static void release_vpe(struct vpe *v) | 146void release_vpe(struct vpe *v) |
230{ 231 list_del(&v->list); 232 if (v->load_addr) 233 release_progmem(v); 234 kfree(v); 235} 236 | 147{ 148 list_del(&v->list); 149 if (v->load_addr) 150 release_progmem(v); 151 kfree(v); 152} 153 |
237static void __maybe_unused dump_mtregs(void) 238{ 239 unsigned long val; 240 241 val = read_c0_config3(); 242 printk("config3 0x%lx MT %ld\n", val, 243 (val & CONFIG3_MT) >> CONFIG3_MT_SHIFT); 244 245 val = read_c0_mvpcontrol(); 246 printk("MVPControl 0x%lx, STLB %ld VPC %ld EVP %ld\n", val, 247 (val & MVPCONTROL_STLB) >> MVPCONTROL_STLB_SHIFT, 248 (val & MVPCONTROL_VPC) >> MVPCONTROL_VPC_SHIFT, 249 (val & MVPCONTROL_EVP)); 250 251 val = read_c0_mvpconf0(); 252 printk("mvpconf0 0x%lx, PVPE %ld PTC %ld M %ld\n", val, 253 (val & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT, 254 val & MVPCONF0_PTC, (val & MVPCONF0_M) >> MVPCONF0_M_SHIFT); 255} 256 | |
257/* Find some VPE program space */ | 154/* Find some VPE program space */ |
258static void *alloc_progmem(unsigned long len) | 155void *alloc_progmem(unsigned long len) |
259{ 260 void *addr; 261 262#ifdef CONFIG_MIPS_VPE_LOADER_TOM 263 /* 264 * This means you must tell Linux to use less memory than you 265 * physically have, for example by passing a mem= boot argument. 266 */ 267 addr = pfn_to_kaddr(max_low_pfn); 268 memset(addr, 0, len); 269#else 270 /* simple grab some mem for now */ 271 addr = kzalloc(len, GFP_KERNEL); 272#endif 273 274 return addr; 275} 276 | 156{ 157 void *addr; 158 159#ifdef CONFIG_MIPS_VPE_LOADER_TOM 160 /* 161 * This means you must tell Linux to use less memory than you 162 * physically have, for example by passing a mem= boot argument. 163 */ 164 addr = pfn_to_kaddr(max_low_pfn); 165 memset(addr, 0, len); 166#else 167 /* simple grab some mem for now */ 168 addr = kzalloc(len, GFP_KERNEL); 169#endif 170 171 return addr; 172} 173 |
277static void release_progmem(void *ptr) | 174void release_progmem(void *ptr) |
278{ 279#ifndef CONFIG_MIPS_VPE_LOADER_TOM 280 kfree(ptr); 281#endif 282} 283 284/* Update size with this section: return offset. */ 285static long get_offset(unsigned long *size, Elf_Shdr * sechdr) --- 384 unchanged lines hidden (view full) --- 670 printk(KERN_DEBUG "dump_elfsymbols: n %d\n", n); 671 for (i = 1; i < n; i++) { 672 printk(KERN_DEBUG " i %d name <%s> 0x%x\n", i, 673 strtab + sym[i].st_name, sym[i].st_value); 674 } 675} 676#endif 677 | 175{ 176#ifndef CONFIG_MIPS_VPE_LOADER_TOM 177 kfree(ptr); 178#endif 179} 180 181/* Update size with this section: return offset. */ 182static long get_offset(unsigned long *size, Elf_Shdr * sechdr) --- 384 unchanged lines hidden (view full) --- 567 printk(KERN_DEBUG "dump_elfsymbols: n %d\n", n); 568 for (i = 1; i < n; i++) { 569 printk(KERN_DEBUG " i %d name <%s> 0x%x\n", i, 570 strtab + sym[i].st_name, sym[i].st_value); 571 } 572} 573#endif 574 |
678/* We are prepared so configure and start the VPE... */ 679static int vpe_run(struct vpe * v) 680{ 681 unsigned long flags, val, dmt_flag; 682 struct vpe_notifications *n; 683 unsigned int vpeflags; 684 struct tc *t; 685 686 /* check we are the Master VPE */ 687 local_irq_save(flags); 688 val = read_c0_vpeconf0(); 689 if (!(val & VPECONF0_MVP)) { 690 printk(KERN_WARNING 691 "VPE loader: only Master VPE's are allowed to configure MT\n"); 692 local_irq_restore(flags); 693 694 return -1; 695 } 696 697 dmt_flag = dmt(); 698 vpeflags = dvpe(); 699 700 if (list_empty(&v->tc)) { 701 evpe(vpeflags); 702 emt(dmt_flag); 703 local_irq_restore(flags); 704 705 printk(KERN_WARNING 706 "VPE loader: No TC's associated with VPE %d\n", 707 v->minor); 708 709 return -ENOEXEC; 710 } 711 712 t = list_first_entry(&v->tc, struct tc, tc); 713 714 /* Put MVPE's into 'configuration state' */ 715 set_c0_mvpcontrol(MVPCONTROL_VPC); 716 717 settc(t->index); 718 719 /* should check it is halted, and not activated */ 720 if ((read_tc_c0_tcstatus() & TCSTATUS_A) || !(read_tc_c0_tchalt() & TCHALT_H)) { 721 evpe(vpeflags); 722 emt(dmt_flag); 723 local_irq_restore(flags); 724 725 printk(KERN_WARNING "VPE loader: TC %d is already active!\n", 726 t->index); 727 728 return -ENOEXEC; 729 } 730 731 /* Write the address we want it to start running from in the TCPC register. */ 732 write_tc_c0_tcrestart((unsigned long)v->__start); 733 write_tc_c0_tccontext((unsigned long)0); 734 735 /* 736 * Mark the TC as activated, not interrupt exempt and not dynamically 737 * allocatable 738 */ 739 val = read_tc_c0_tcstatus(); 740 val = (val & ~(TCSTATUS_DA | TCSTATUS_IXMT)) | TCSTATUS_A; 741 write_tc_c0_tcstatus(val); 742 743 write_tc_c0_tchalt(read_tc_c0_tchalt() & ~TCHALT_H); 744 745 /* 746 * The sde-kit passes 'memsize' to __start in $a3, so set something 747 * here... Or set $a3 to zero and define DFLT_STACK_SIZE and 748 * DFLT_HEAP_SIZE when you compile your program 749 */ 750 mttgpr(6, v->ntcs); 751 mttgpr(7, physical_memsize); 752 753 /* set up VPE1 */ 754 /* 755 * bind the TC to VPE 1 as late as possible so we only have the final 756 * VPE registers to set up, and so an EJTAG probe can trigger on it 757 */ 758 write_tc_c0_tcbind((read_tc_c0_tcbind() & ~TCBIND_CURVPE) | 1); 759 760 write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() & ~(VPECONF0_VPA)); 761 762 back_to_back_c0_hazard(); 763 764 /* Set up the XTC bit in vpeconf0 to point at our tc */ 765 write_vpe_c0_vpeconf0( (read_vpe_c0_vpeconf0() & ~(VPECONF0_XTC)) 766 | (t->index << VPECONF0_XTC_SHIFT)); 767 768 back_to_back_c0_hazard(); 769 770 /* enable this VPE */ 771 write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() | VPECONF0_VPA); 772 773 /* clear out any left overs from a previous program */ 774 write_vpe_c0_status(0); 775 write_vpe_c0_cause(0); 776 777 /* take system out of configuration state */ 778 clear_c0_mvpcontrol(MVPCONTROL_VPC); 779 780 /* 781 * SMTC/SMVP kernels manage VPE enable independently, 782 * but uniprocessor kernels need to turn it on, even 783 * if that wasn't the pre-dvpe() state. 784 */ 785#ifdef CONFIG_SMP 786 evpe(vpeflags); 787#else 788 evpe(EVPE_ENABLE); 789#endif 790 emt(dmt_flag); 791 local_irq_restore(flags); 792 793 list_for_each_entry(n, &v->notify, list) 794 n->start(minor); 795 796 return 0; 797} 798 | |
799static int find_vpe_symbols(struct vpe * v, Elf_Shdr * sechdrs, 800 unsigned int symindex, const char *strtab, 801 struct module *mod) 802{ 803 Elf_Sym *sym = (void *)sechdrs[symindex].sh_addr; 804 unsigned int i, n = sechdrs[symindex].sh_size / sizeof(Elf_Sym); 805 806 for (i = 1; i < n; i++) { --- 181 unchanged lines hidden (view full) --- 988 "program does not contain vpe_shared symbol.\n" 989 " Unable to use AMVP (AP/SP) facilities.\n"); 990 } 991 992 printk(" elf loaded\n"); 993 return 0; 994} 995 | 575static int find_vpe_symbols(struct vpe * v, Elf_Shdr * sechdrs, 576 unsigned int symindex, const char *strtab, 577 struct module *mod) 578{ 579 Elf_Sym *sym = (void *)sechdrs[symindex].sh_addr; 580 unsigned int i, n = sechdrs[symindex].sh_size / sizeof(Elf_Sym); 581 582 for (i = 1; i < n; i++) { --- 181 unchanged lines hidden (view full) --- 764 "program does not contain vpe_shared symbol.\n" 765 " Unable to use AMVP (AP/SP) facilities.\n"); 766 } 767 768 printk(" elf loaded\n"); 769 return 0; 770} 771 |
996static void cleanup_tc(struct tc *tc) 997{ 998 unsigned long flags; 999 unsigned int mtflags, vpflags; 1000 int tmp; 1001 1002 local_irq_save(flags); 1003 mtflags = dmt(); 1004 vpflags = dvpe(); 1005 /* Put MVPE's into 'configuration state' */ 1006 set_c0_mvpcontrol(MVPCONTROL_VPC); 1007 1008 settc(tc->index); 1009 tmp = read_tc_c0_tcstatus(); 1010 1011 /* mark not allocated and not dynamically allocatable */ 1012 tmp &= ~(TCSTATUS_A | TCSTATUS_DA); 1013 tmp |= TCSTATUS_IXMT; /* interrupt exempt */ 1014 write_tc_c0_tcstatus(tmp); 1015 1016 write_tc_c0_tchalt(TCHALT_H); 1017 mips_ihb(); 1018 1019 /* bind it to anything other than VPE1 */ 1020// write_tc_c0_tcbind(read_tc_c0_tcbind() & ~TCBIND_CURVPE); // | TCBIND_CURVPE 1021 1022 clear_c0_mvpcontrol(MVPCONTROL_VPC); 1023 evpe(vpflags); 1024 emt(mtflags); 1025 local_irq_restore(flags); 1026} 1027 | |
1028static int getcwd(char *buff, int size) 1029{ 1030 mm_segment_t old_fs; 1031 int ret; 1032 1033 old_fs = get_fs(); 1034 set_fs(KERNEL_DS); 1035 --- 7 unchanged lines hidden (view full) --- 1043/* checks VPE is unused and gets ready to load program */ 1044static int vpe_open(struct inode *inode, struct file *filp) 1045{ 1046 enum vpe_state state; 1047 struct vpe_notifications *not; 1048 struct vpe *v; 1049 int ret; 1050 | 772static int getcwd(char *buff, int size) 773{ 774 mm_segment_t old_fs; 775 int ret; 776 777 old_fs = get_fs(); 778 set_fs(KERNEL_DS); 779 --- 7 unchanged lines hidden (view full) --- 787/* checks VPE is unused and gets ready to load program */ 788static int vpe_open(struct inode *inode, struct file *filp) 789{ 790 enum vpe_state state; 791 struct vpe_notifications *not; 792 struct vpe *v; 793 int ret; 794 |
1051 if (minor != iminor(inode)) { | 795 if (VPE_MODULE_MINOR != iminor(inode)) { |
1052 /* assume only 1 device at the moment. */ 1053 pr_warning("VPE loader: only vpe1 is supported\n"); 1054 1055 return -ENODEV; 1056 } 1057 | 796 /* assume only 1 device at the moment. */ 797 pr_warning("VPE loader: only vpe1 is supported\n"); 798 799 return -ENODEV; 800 } 801 |
1058 if ((v = get_vpe(tclimit)) == NULL) { | 802 if ((v = get_vpe(aprp_cpu_index())) == NULL) { |
1059 pr_warning("VPE loader: unable to get vpe\n"); 1060 1061 return -ENODEV; 1062 } 1063 1064 state = xchg(&v->state, VPE_STATE_INUSE); 1065 if (state != VPE_STATE_UNUSED) { 1066 printk(KERN_DEBUG "VPE loader: tc in use dumping regs\n"); 1067 1068 list_for_each_entry(not, &v->notify, list) { | 803 pr_warning("VPE loader: unable to get vpe\n"); 804 805 return -ENODEV; 806 } 807 808 state = xchg(&v->state, VPE_STATE_INUSE); 809 if (state != VPE_STATE_UNUSED) { 810 printk(KERN_DEBUG "VPE loader: tc in use dumping regs\n"); 811 812 list_for_each_entry(not, &v->notify, list) { |
1069 not->stop(tclimit); | 813 not->stop(aprp_cpu_index()); |
1070 } 1071 1072 release_progmem(v->load_addr); | 814 } 815 816 release_progmem(v->load_addr); |
1073 cleanup_tc(get_tc(tclimit)); | 817 cleanup_tc(get_tc(aprp_cpu_index())); |
1074 } 1075 1076 /* this of-course trashes what was there before... */ 1077 v->pbuffer = vmalloc(P_SIZE); 1078 if (!v->pbuffer) { 1079 pr_warning("VPE loader: unable to allocate memory\n"); 1080 return -ENOMEM; 1081 } --- 16 unchanged lines hidden (view full) --- 1098} 1099 1100static int vpe_release(struct inode *inode, struct file *filp) 1101{ 1102 struct vpe *v; 1103 Elf_Ehdr *hdr; 1104 int ret = 0; 1105 | 818 } 819 820 /* this of-course trashes what was there before... */ 821 v->pbuffer = vmalloc(P_SIZE); 822 if (!v->pbuffer) { 823 pr_warning("VPE loader: unable to allocate memory\n"); 824 return -ENOMEM; 825 } --- 16 unchanged lines hidden (view full) --- 842} 843 844static int vpe_release(struct inode *inode, struct file *filp) 845{ 846 struct vpe *v; 847 Elf_Ehdr *hdr; 848 int ret = 0; 849 |
1106 v = get_vpe(tclimit); | 850 v = get_vpe(aprp_cpu_index()); |
1107 if (v == NULL) 1108 return -ENODEV; 1109 1110 hdr = (Elf_Ehdr *) v->pbuffer; 1111 if (memcmp(hdr->e_ident, ELFMAG, SELFMAG) == 0) { | 851 if (v == NULL) 852 return -ENODEV; 853 854 hdr = (Elf_Ehdr *) v->pbuffer; 855 if (memcmp(hdr->e_ident, ELFMAG, SELFMAG) == 0) { |
1112 if (vpe_elfload(v) >= 0) { | 856 if ((vpe_elfload(v) >= 0) && vpe_run) { |
1113 vpe_run(v); 1114 } else { 1115 printk(KERN_WARNING "VPE loader: ELF load failed.\n"); 1116 ret = -ENOEXEC; 1117 } 1118 } else { 1119 printk(KERN_WARNING "VPE loader: only elf files are supported\n"); 1120 ret = -ENOEXEC; --- 14 unchanged lines hidden (view full) --- 1135} 1136 1137static ssize_t vpe_write(struct file *file, const char __user * buffer, 1138 size_t count, loff_t * ppos) 1139{ 1140 size_t ret = count; 1141 struct vpe *v; 1142 | 857 vpe_run(v); 858 } else { 859 printk(KERN_WARNING "VPE loader: ELF load failed.\n"); 860 ret = -ENOEXEC; 861 } 862 } else { 863 printk(KERN_WARNING "VPE loader: only elf files are supported\n"); 864 ret = -ENOEXEC; --- 14 unchanged lines hidden (view full) --- 879} 880 881static ssize_t vpe_write(struct file *file, const char __user * buffer, 882 size_t count, loff_t * ppos) 883{ 884 size_t ret = count; 885 struct vpe *v; 886 |
1143 if (iminor(file_inode(file)) != minor) | 887 if (iminor(file_inode(file)) != VPE_MODULE_MINOR) |
1144 return -ENODEV; 1145 | 888 return -ENODEV; 889 |
1146 v = get_vpe(tclimit); | 890 v = get_vpe(aprp_cpu_index()); |
1147 if (v == NULL) 1148 return -ENODEV; 1149 1150 if ((count + v->len) > v->plen) { 1151 printk(KERN_WARNING 1152 "VPE loader: elf size too big. Perhaps strip uneeded symbols\n"); 1153 return -ENOMEM; 1154 } 1155 1156 count -= copy_from_user(v->pbuffer + v->len, buffer, count); 1157 if (!count) 1158 return -EFAULT; 1159 1160 v->len += count; 1161 return ret; 1162} 1163 | 891 if (v == NULL) 892 return -ENODEV; 893 894 if ((count + v->len) > v->plen) { 895 printk(KERN_WARNING 896 "VPE loader: elf size too big. Perhaps strip uneeded symbols\n"); 897 return -ENOMEM; 898 } 899 900 count -= copy_from_user(v->pbuffer + v->len, buffer, count); 901 if (!count) 902 return -EFAULT; 903 904 v->len += count; 905 return ret; 906} 907 |
1164static const struct file_operations vpe_fops = { | 908const struct file_operations vpe_fops = { |
1165 .owner = THIS_MODULE, 1166 .open = vpe_open, 1167 .release = vpe_release, 1168 .write = vpe_write, 1169 .llseek = noop_llseek, 1170}; 1171 | 909 .owner = THIS_MODULE, 910 .open = vpe_open, 911 .release = vpe_release, 912 .write = vpe_write, 913 .llseek = noop_llseek, 914}; 915 |
1172/* module wrapper entry points */ 1173/* give me a vpe */ 1174vpe_handle vpe_alloc(void) 1175{ 1176 int i; 1177 struct vpe *v; 1178 1179 /* find a vpe */ 1180 for (i = 1; i < MAX_VPES; i++) { 1181 if ((v = get_vpe(i)) != NULL) { 1182 v->state = VPE_STATE_INUSE; 1183 return v; 1184 } 1185 } 1186 return NULL; 1187} 1188 1189EXPORT_SYMBOL(vpe_alloc); 1190 1191/* start running from here */ 1192int vpe_start(vpe_handle vpe, unsigned long start) 1193{ 1194 struct vpe *v = vpe; 1195 1196 v->__start = start; 1197 return vpe_run(v); 1198} 1199 1200EXPORT_SYMBOL(vpe_start); 1201 1202/* halt it for now */ 1203int vpe_stop(vpe_handle vpe) 1204{ 1205 struct vpe *v = vpe; 1206 struct tc *t; 1207 unsigned int evpe_flags; 1208 1209 evpe_flags = dvpe(); 1210 1211 if ((t = list_entry(v->tc.next, struct tc, tc)) != NULL) { 1212 1213 settc(t->index); 1214 write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() & ~VPECONF0_VPA); 1215 } 1216 1217 evpe(evpe_flags); 1218 1219 return 0; 1220} 1221 1222EXPORT_SYMBOL(vpe_stop); 1223 1224/* I've done with it thank you */ 1225int vpe_free(vpe_handle vpe) 1226{ 1227 struct vpe *v = vpe; 1228 struct tc *t; 1229 unsigned int evpe_flags; 1230 1231 if ((t = list_entry(v->tc.next, struct tc, tc)) == NULL) { 1232 return -ENOEXEC; 1233 } 1234 1235 evpe_flags = dvpe(); 1236 1237 /* Put MVPE's into 'configuration state' */ 1238 set_c0_mvpcontrol(MVPCONTROL_VPC); 1239 1240 settc(t->index); 1241 write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() & ~VPECONF0_VPA); 1242 1243 /* halt the TC */ 1244 write_tc_c0_tchalt(TCHALT_H); 1245 mips_ihb(); 1246 1247 /* mark the TC unallocated */ 1248 write_tc_c0_tcstatus(read_tc_c0_tcstatus() & ~TCSTATUS_A); 1249 1250 v->state = VPE_STATE_UNUSED; 1251 1252 clear_c0_mvpcontrol(MVPCONTROL_VPC); 1253 evpe(evpe_flags); 1254 1255 return 0; 1256} 1257 1258EXPORT_SYMBOL(vpe_free); 1259 | |
1260void *vpe_get_shared(int index) 1261{ 1262 struct vpe *v; 1263 1264 if ((v = get_vpe(index)) == NULL) 1265 return NULL; 1266 1267 return v->shared_ptr; --- 45 unchanged lines hidden (view full) --- 1313 if ((v = get_vpe(index)) == NULL) 1314 return NULL; 1315 1316 return v->cwd; 1317} 1318 1319EXPORT_SYMBOL(vpe_getcwd); 1320 | 916void *vpe_get_shared(int index) 917{ 918 struct vpe *v; 919 920 if ((v = get_vpe(index)) == NULL) 921 return NULL; 922 923 return v->shared_ptr; --- 45 unchanged lines hidden (view full) --- 969 if ((v = get_vpe(index)) == NULL) 970 return NULL; 971 972 return v->cwd; 973} 974 975EXPORT_SYMBOL(vpe_getcwd); 976 |
1321static ssize_t store_kill(struct device *dev, struct device_attribute *attr, 1322 const char *buf, size_t len) 1323{ 1324 struct vpe *vpe = get_vpe(tclimit); 1325 struct vpe_notifications *not; 1326 1327 list_for_each_entry(not, &vpe->notify, list) { 1328 not->stop(tclimit); 1329 } 1330 1331 release_progmem(vpe->load_addr); 1332 cleanup_tc(get_tc(tclimit)); 1333 vpe_stop(vpe); 1334 vpe_free(vpe); 1335 1336 return len; 1337} 1338static DEVICE_ATTR(kill, S_IWUSR, NULL, store_kill); 1339 1340static ssize_t ntcs_show(struct device *cd, struct device_attribute *attr, 1341 char *buf) 1342{ 1343 struct vpe *vpe = get_vpe(tclimit); 1344 1345 return sprintf(buf, "%d\n", vpe->ntcs); 1346} 1347 1348static ssize_t ntcs_store(struct device *dev, struct device_attribute *attr, 1349 const char *buf, size_t len) 1350{ 1351 struct vpe *vpe = get_vpe(tclimit); 1352 unsigned long new; 1353 char *endp; 1354 1355 new = simple_strtoul(buf, &endp, 0); 1356 if (endp == buf) 1357 goto out_einval; 1358 1359 if (new == 0 || new > (hw_tcs - tclimit)) 1360 goto out_einval; 1361 1362 vpe->ntcs = new; 1363 1364 return len; 1365 1366out_einval: 1367 return -EINVAL; 1368} 1369static DEVICE_ATTR_RW(ntcs); 1370 1371static struct attribute *vpe_attrs[] = { 1372 &dev_attr_kill.attr, 1373 &dev_attr_ntcs.attr, 1374 NULL, 1375}; 1376ATTRIBUTE_GROUPS(vpe); 1377 1378static void vpe_device_release(struct device *cd) 1379{ 1380 kfree(cd); 1381} 1382 1383struct class vpe_class = { 1384 .name = "vpe", 1385 .owner = THIS_MODULE, 1386 .dev_release = vpe_device_release, 1387 .dev_groups = vpe_groups, 1388}; 1389 1390struct device vpe_device; 1391 1392static int __init vpe_module_init(void) 1393{ 1394 unsigned int mtflags, vpflags; 1395 unsigned long flags, val; 1396 struct vpe *v = NULL; 1397 struct tc *t; 1398 int tc, err; 1399 1400 if (!cpu_has_mipsmt) { 1401 printk("VPE loader: not a MIPS MT capable processor\n"); 1402 return -ENODEV; 1403 } 1404 1405 if (vpelimit == 0) { 1406 printk(KERN_WARNING "No VPEs reserved for AP/SP, not " 1407 "initializing VPE loader.\nPass maxvpes=<n> argument as " 1408 "kernel argument\n"); 1409 1410 return -ENODEV; 1411 } 1412 1413 if (tclimit == 0) { 1414 printk(KERN_WARNING "No TCs reserved for AP/SP, not " 1415 "initializing VPE loader.\nPass maxtcs=<n> argument as " 1416 "kernel argument\n"); 1417 1418 return -ENODEV; 1419 } 1420 1421 major = register_chrdev(0, module_name, &vpe_fops); 1422 if (major < 0) { 1423 printk("VPE loader: unable to register character device\n"); 1424 return major; 1425 } 1426 1427 err = class_register(&vpe_class); 1428 if (err) { 1429 printk(KERN_ERR "vpe_class registration failed\n"); 1430 goto out_chrdev; 1431 } 1432 1433 device_initialize(&vpe_device); 1434 vpe_device.class = &vpe_class, 1435 vpe_device.parent = NULL, 1436 dev_set_name(&vpe_device, "vpe1"); 1437 vpe_device.devt = MKDEV(major, minor); 1438 err = device_add(&vpe_device); 1439 if (err) { 1440 printk(KERN_ERR "Adding vpe_device failed\n"); 1441 goto out_class; 1442 } 1443 1444 local_irq_save(flags); 1445 mtflags = dmt(); 1446 vpflags = dvpe(); 1447 1448 /* Put MVPE's into 'configuration state' */ 1449 set_c0_mvpcontrol(MVPCONTROL_VPC); 1450 1451 /* dump_mtregs(); */ 1452 1453 val = read_c0_mvpconf0(); 1454 hw_tcs = (val & MVPCONF0_PTC) + 1; 1455 hw_vpes = ((val & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT) + 1; 1456 1457 for (tc = tclimit; tc < hw_tcs; tc++) { 1458 /* 1459 * Must re-enable multithreading temporarily or in case we 1460 * reschedule send IPIs or similar we might hang. 1461 */ 1462 clear_c0_mvpcontrol(MVPCONTROL_VPC); 1463 evpe(vpflags); 1464 emt(mtflags); 1465 local_irq_restore(flags); 1466 t = alloc_tc(tc); 1467 if (!t) { 1468 err = -ENOMEM; 1469 goto out; 1470 } 1471 1472 local_irq_save(flags); 1473 mtflags = dmt(); 1474 vpflags = dvpe(); 1475 set_c0_mvpcontrol(MVPCONTROL_VPC); 1476 1477 /* VPE's */ 1478 if (tc < hw_tcs) { 1479 settc(tc); 1480 1481 if ((v = alloc_vpe(tc)) == NULL) { 1482 printk(KERN_WARNING "VPE: unable to allocate VPE\n"); 1483 1484 goto out_reenable; 1485 } 1486 1487 v->ntcs = hw_tcs - tclimit; 1488 1489 /* add the tc to the list of this vpe's tc's. */ 1490 list_add(&t->tc, &v->tc); 1491 1492 /* deactivate all but vpe0 */ 1493 if (tc >= tclimit) { 1494 unsigned long tmp = read_vpe_c0_vpeconf0(); 1495 1496 tmp &= ~VPECONF0_VPA; 1497 1498 /* master VPE */ 1499 tmp |= VPECONF0_MVP; 1500 write_vpe_c0_vpeconf0(tmp); 1501 } 1502 1503 /* disable multi-threading with TC's */ 1504 write_vpe_c0_vpecontrol(read_vpe_c0_vpecontrol() & ~VPECONTROL_TE); 1505 1506 if (tc >= vpelimit) { 1507 /* 1508 * Set config to be the same as vpe0, 1509 * particularly kseg0 coherency alg 1510 */ 1511 write_vpe_c0_config(read_c0_config()); 1512 } 1513 } 1514 1515 /* TC's */ 1516 t->pvpe = v; /* set the parent vpe */ 1517 1518 if (tc >= tclimit) { 1519 unsigned long tmp; 1520 1521 settc(tc); 1522 1523 /* Any TC that is bound to VPE0 gets left as is - in case 1524 we are running SMTC on VPE0. A TC that is bound to any 1525 other VPE gets bound to VPE0, ideally I'd like to make 1526 it homeless but it doesn't appear to let me bind a TC 1527 to a non-existent VPE. Which is perfectly reasonable. 1528 1529 The (un)bound state is visible to an EJTAG probe so may 1530 notify GDB... 1531 */ 1532 1533 if (((tmp = read_tc_c0_tcbind()) & TCBIND_CURVPE)) { 1534 /* tc is bound >vpe0 */ 1535 write_tc_c0_tcbind(tmp & ~TCBIND_CURVPE); 1536 1537 t->pvpe = get_vpe(0); /* set the parent vpe */ 1538 } 1539 1540 /* halt the TC */ 1541 write_tc_c0_tchalt(TCHALT_H); 1542 mips_ihb(); 1543 1544 tmp = read_tc_c0_tcstatus(); 1545 1546 /* mark not activated and not dynamically allocatable */ 1547 tmp &= ~(TCSTATUS_A | TCSTATUS_DA); 1548 tmp |= TCSTATUS_IXMT; /* interrupt exempt */ 1549 write_tc_c0_tcstatus(tmp); 1550 } 1551 } 1552 1553out_reenable: 1554 /* release config state */ 1555 clear_c0_mvpcontrol(MVPCONTROL_VPC); 1556 1557 evpe(vpflags); 1558 emt(mtflags); 1559 local_irq_restore(flags); 1560 1561 return 0; 1562 1563out_class: 1564 class_unregister(&vpe_class); 1565out_chrdev: 1566 unregister_chrdev(major, module_name); 1567 1568out: 1569 return err; 1570} 1571 1572static void __exit vpe_module_exit(void) 1573{ 1574 struct vpe *v, *n; 1575 1576 device_del(&vpe_device); 1577 unregister_chrdev(major, module_name); 1578 1579 /* No locking needed here */ 1580 list_for_each_entry_safe(v, n, &vpecontrol.vpe_list, list) { 1581 if (v->state != VPE_STATE_UNUSED) 1582 release_vpe(v); 1583 } 1584} 1585 | |
1586module_init(vpe_module_init); 1587module_exit(vpe_module_exit); 1588MODULE_DESCRIPTION("MIPS VPE Loader"); 1589MODULE_AUTHOR("Elizabeth Oldham, MIPS Technologies, Inc."); 1590MODULE_LICENSE("GPL"); | 977module_init(vpe_module_init); 978module_exit(vpe_module_exit); 979MODULE_DESCRIPTION("MIPS VPE Loader"); 980MODULE_AUTHOR("Elizabeth Oldham, MIPS Technologies, Inc."); 981MODULE_LICENSE("GPL"); |