···13771377 This is a kernel model which is known a SMTC or lately has been13781378 marketesed into SMVP.1379137913801380-config MIPS_VPE_LOADER13811381- bool "VPE loader support."13821382- depends on SYS_SUPPORTS_MULTITHREADING13831383- select CPU_MIPSR2_IRQ_VI13841384- select CPU_MIPSR2_IRQ_EI13851385- select CPU_MIPSR2_SRS13861386- select MIPS_MT13871387- help13881388- Includes a loader for loading an elf relocatable object13891389- onto another VPE and running it.13901390-13911380endchoice1392138113931382config MIPS_MT···1387139813881399config MIPS_MT_FPAFF13891400 bool "Dynamic FPU affinity for FP-intensive threads"13901390- depends on MIPS_MT13911401 default y14021402+ depends on MIPS_MT_SMP || MIPS_MT_SMTC14031403+14041404+config MIPS_VPE_LOADER14051405+ bool "VPE loader support."14061406+ depends on SYS_SUPPORTS_MULTITHREADING14071407+ select CPU_MIPSR2_IRQ_VI14081408+ select CPU_MIPSR2_IRQ_EI14091409+ select CPU_MIPSR2_SRS14101410+ select MIPS_MT14111411+ help14121412+ Includes a loader for loading an elf relocatable object14131413+ onto another VPE and running it.1392141413931415config MIPS_MT_SMTC_INSTANT_REPLAY13941416 bool "Low-latency Dispatch of Deferred SMTC IPIs"
+9-10
arch/mips/kernel/kspd.c
···8989#define MTSP_O_EXCL 0x08009090#define MTSP_O_BINARY 0x800091919292-#define SP_VPE 19292+extern int tclimit;93939494struct apsp_table {9595 int sp;···225225 /* Run the syscall at the priviledge of the user who loaded the226226 SP program */227227228228- if (vpe_getuid(SP_VPE))229229- sp_setfsuidgid( vpe_getuid(SP_VPE), vpe_getgid(SP_VPE));228228+ if (vpe_getuid(tclimit))229229+ sp_setfsuidgid(vpe_getuid(tclimit), vpe_getgid(tclimit));230230231231 switch (sc.cmd) {232232 /* needs the flags argument translating from SDE kit to···245245246246 case MTSP_SYSCALL_EXIT:247247 list_for_each_entry(n, &kspd_notifylist, list)248248- n->kspd_sp_exit(SP_VPE);248248+ n->kspd_sp_exit(tclimit);249249 sp_stopping = 1;250250251251 printk(KERN_DEBUG "KSPD got exit syscall from SP exitcode %d\n",···255255 case MTSP_SYSCALL_OPEN:256256 generic.arg1 = translate_open_flags(generic.arg1);257257258258- vcwd = vpe_getcwd(SP_VPE);258258+ vcwd = vpe_getcwd(tclimit);259259260260 /* change to the cwd of the process that loaded the SP program */261261 old_fs = get_fs();···283283 break;284284 } /* switch */285285286286- if (vpe_getuid(SP_VPE))286286+ if (vpe_getuid(tclimit))287287 sp_setfsuidgid( 0, 0);288288289289 old_fs = get_fs();···364364 }365365366366 INIT_WORK(&work, sp_work);367367- queue_work(workqueue, &work);368368- } else369369- queue_work(workqueue, &work);367367+ }370368369369+ queue_work(workqueue, &work);371370}372371373372static void stopwork(int vpe)···388389389390 notify.start = startwork;390391 notify.stop = stopwork;391391- vpe_notify(SP_VPE, ¬ify);392392+ vpe_notify(tclimit, ¬ify);392393393394 return 0;394395}
+22
arch/mips/kernel/mips-mt.c
···2121#include <asm/r4kcache.h>2222#include <asm/cacheflush.h>23232424+int vpelimit;2525+2626+static int __init maxvpes(char *str)2727+{2828+ get_option(&str, &vpelimit);2929+3030+ return 1;3131+}3232+3333+__setup("maxvpes=", maxvpes);3434+3535+int tclimit;3636+3737+static int __init maxtcs(char *str)3838+{3939+ get_option(&str, &tclimit);4040+4141+ return 1;4242+}4343+4444+__setup("maxtcs=", maxtcs);4545+2446/*2547 * Dump new MIPS MT state for the core. Does not leave TCs halted.2648 * Takes an argument which taken to be a pre-call MVPControl value.
+17-5
arch/mips/kernel/rtlx.c
···4040#include <asm/atomic.h>4141#include <asm/cpu.h>4242#include <asm/processor.h>4343+#include <asm/mips_mt.h>4344#include <asm/system.h>4445#include <asm/vpe.h>4546#include <asm/rtlx.h>4646-4747-#define RTLX_TARG_VPE 148474948static struct rtlx_info *rtlx;5049static int major;···164165 }165166166167 if (rtlx == NULL) {167167- if( (p = vpe_get_shared(RTLX_TARG_VPE)) == NULL) {168168+ if( (p = vpe_get_shared(tclimit)) == NULL) {168169 if (can_sleep) {169170 __wait_event_interruptible(channel_wqs[index].lx_queue,170170- (p = vpe_get_shared(RTLX_TARG_VPE)),171171+ (p = vpe_get_shared(tclimit)),171172 ret);172173 if (ret)173174 goto out_fail;···476477 struct device *dev;477478 int i, err;478479480480+ if (!cpu_has_mipsmt) {481481+ printk("VPE loader: not a MIPS MT capable processor\n");482482+ return -ENODEV;483483+ }484484+485485+ if (tclimit == 0) {486486+ printk(KERN_WARNING "No TCs reserved for AP/SP, not "487487+ "initializing RTLX.\nPass maxtcs=<n> argument as kernel "488488+ "argument\n");489489+490490+ return -ENODEV;491491+ }492492+479493 major = register_chrdev(0, module_name, &rtlx_fops);480494 if (major < 0) {481495 printk(register_chrdev_failed);···513501 /* set up notifiers */514502 notify.start = starting;515503 notify.stop = stopping;516516- vpe_notify(RTLX_TARG_VPE, ¬ify);504504+ vpe_notify(tclimit, ¬ify);517505518506 if (cpu_has_vint)519507 set_vi_handler(MIPS_CPU_RTLX_IRQ, rtlx_dispatch);
-16
arch/mips/kernel/smtc.c
···86868787/* Boot command line configuration overrides */88888989-static int vpelimit = 0;9090-static int tclimit = 0;9189static int ipibuffers = 0;9290static int nostlb = 0;9391static int asidmask = 0;9492unsigned long smtc_asid_mask = 0xff;9595-9696-static int __init maxvpes(char *str)9797-{9898- get_option(&str, &vpelimit);9999- return 1;100100-}101101-102102-static int __init maxtcs(char *str)103103-{104104- get_option(&str, &tclimit);105105- return 1;106106-}1079310894static int __init ipibufs(char *str)10995{···123137 return 1;124138}125139126126-__setup("maxvpes=", maxvpes);127127-__setup("maxtcs=", maxtcs);128140__setup("ipibufs=", ipibufs);129141__setup("nostlb", stlb_disable);130142__setup("asidmask=", asidmask_set);
+137-126
arch/mips/kernel/vpe.c
···2727 * To load and run, simply cat a SP 'program file' to /dev/vpe1.2828 * i.e cat spapp >/dev/vpe1.2929 */3030-3130#include <linux/kernel.h>3231#include <linux/device.h>3332#include <linux/module.h>···5354#include <asm/system.h>5455#include <asm/vpe.h>5556#include <asm/kspd.h>5757+#include <asm/mips_mt.h>56585759typedef void *vpe_handle;5860···132132 enum tc_state state;133133 int index;134134135135- /* parent VPE */136136- struct vpe *pvpe;137137-138138- /* The list of TC's with this VPE */139139- struct list_head tc;140140-141141- /* The global list of tc's */142142- struct list_head list;135135+ struct vpe *pvpe; /* parent VPE */136136+ struct list_head tc; /* The list of TC's with this VPE */137137+ struct list_head list; /* The global list of tc's */143138};144139145140struct {···212217/* allocate a tc. At startup only tc0 is running, all other can be halted. */213218struct tc *alloc_tc(int index)214219{215215- struct tc *t;220220+ struct tc *tc;216221217217- if ((t = kzalloc(sizeof(struct tc), GFP_KERNEL)) == NULL) {218218- return NULL;219219- }222222+ if ((tc = kzalloc(sizeof(struct tc), GFP_KERNEL)) == NULL)223223+ goto out;220224221221- INIT_LIST_HEAD(&t->tc);222222- list_add_tail(&t->list, &vpecontrol.tc_list);225225+ INIT_LIST_HEAD(&tc->tc);226226+ tc->index = index;227227+ list_add_tail(&tc->list, &vpecontrol.tc_list);223228224224- t->index = index;225225-226226- return t;229229+out:230230+ return tc;227231}228232229233/* clean up and free everything */···657663}658664#endif659665660660-static void dump_tc(struct tc *t)661661-{662662- unsigned long val;663663-664664- settc(t->index);665665- printk(KERN_DEBUG "VPE loader: TC index %d targtc %ld "666666- "TCStatus 0x%lx halt 0x%lx\n",667667- t->index, read_c0_vpecontrol() & VPECONTROL_TARGTC,668668- read_tc_c0_tcstatus(), read_tc_c0_tchalt());669669-670670- printk(KERN_DEBUG " tcrestart 0x%lx\n", read_tc_c0_tcrestart());671671- printk(KERN_DEBUG " tcbind 0x%lx\n", read_tc_c0_tcbind());672672-673673- val = read_c0_vpeconf0();674674- printk(KERN_DEBUG " VPEConf0 0x%lx MVP %ld\n", val,675675- (val & VPECONF0_MVP) >> VPECONF0_MVP_SHIFT);676676-677677- printk(KERN_DEBUG " c0 status 0x%lx\n", read_vpe_c0_status());678678- printk(KERN_DEBUG " c0 cause 0x%lx\n", read_vpe_c0_cause());679679-680680- printk(KERN_DEBUG " c0 badvaddr 0x%lx\n", read_vpe_c0_badvaddr());681681- printk(KERN_DEBUG " c0 epc 0x%lx\n", read_vpe_c0_epc());682682-}683683-684684-static void dump_tclist(void)685685-{686686- struct tc *t;687687-688688- list_for_each_entry(t, &vpecontrol.tc_list, list) {689689- dump_tc(t);690690- }691691-}692692-693666/* We are prepared so configure and start the VPE... */694667static int vpe_run(struct vpe * v)695668{669669+ unsigned long flags, val, dmt_flag;696670 struct vpe_notifications *n;697697- unsigned long val, dmt_flag;671671+ unsigned int vpeflags;698672 struct tc *t;699673700674 /* check we are the Master VPE */675675+ local_irq_save(flags);701676 val = read_c0_vpeconf0();702677 if (!(val & VPECONF0_MVP)) {703678 printk(KERN_WARNING704679 "VPE loader: only Master VPE's are allowed to configure MT\n");680680+ local_irq_restore(flags);681681+705682 return -1;706683 }707684708708- /* disable MT (using dvpe) */709709- dvpe();685685+ dmt_flag = dmt();686686+ vpeflags = dvpe();710687711688 if (!list_empty(&v->tc)) {712689 if ((t = list_entry(v->tc.next, struct tc, tc)) == NULL) {713713- printk(KERN_WARNING "VPE loader: TC %d is already in use.\n",714714- t->index);690690+ evpe(vpeflags);691691+ emt(dmt_flag);692692+ local_irq_restore(flags);693693+694694+ printk(KERN_WARNING695695+ "VPE loader: TC %d is already in use.\n",696696+ t->index);715697 return -ENOEXEC;716698 }717699 } else {718718- printk(KERN_WARNING "VPE loader: No TC's associated with VPE %d\n",700700+ evpe(vpeflags);701701+ emt(dmt_flag);702702+ local_irq_restore(flags);703703+704704+ printk(KERN_WARNING705705+ "VPE loader: No TC's associated with VPE %d\n",719706 v->minor);707707+720708 return -ENOEXEC;721709 }722710···709733710734 /* should check it is halted, and not activated */711735 if ((read_tc_c0_tcstatus() & TCSTATUS_A) || !(read_tc_c0_tchalt() & TCHALT_H)) {712712- printk(KERN_WARNING "VPE loader: TC %d is already doing something!\n",736736+ evpe(vpeflags);737737+ emt(dmt_flag);738738+ local_irq_restore(flags);739739+740740+ printk(KERN_WARNING "VPE loader: TC %d is already active!\n",713741 t->index);714714- dump_tclist();742742+715743 return -ENOEXEC;716744 }717717-718718- /*719719- * Disable multi-threaded execution whilst we activate, clear the720720- * halt bit and bound the tc to the other VPE...721721- */722722- dmt_flag = dmt();723745724746 /* Write the address we want it to start running from in the TCPC register. */725747 write_tc_c0_tcrestart((unsigned long)v->__start);726748 write_tc_c0_tccontext((unsigned long)0);749749+727750 /*728751 * Mark the TC as activated, not interrupt exempt and not dynamically729752 * allocatable···738763 * here... Or set $a3 to zero and define DFLT_STACK_SIZE and739764 * DFLT_HEAP_SIZE when you compile your program740765 */741741- mttgpr(7, physical_memsize);742742-766766+ mttgpr(7, physical_memsize);743767744768 /* set up VPE1 */745769 /*746770 * bind the TC to VPE 1 as late as possible so we only have the final747771 * VPE registers to set up, and so an EJTAG probe can trigger on it748772 */749749- write_tc_c0_tcbind((read_tc_c0_tcbind() & ~TCBIND_CURVPE) | v->minor);773773+ write_tc_c0_tcbind((read_tc_c0_tcbind() & ~TCBIND_CURVPE) | 1);750774751775 write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() & ~(VPECONF0_VPA));752776···767793 /* take system out of configuration state */768794 clear_c0_mvpcontrol(MVPCONTROL_VPC);769795770770- /* now safe to re-enable multi-threading */771771- emt(dmt_flag);772772-773773- /* set it running */796796+#ifdef CONFIG_SMP774797 evpe(EVPE_ENABLE);798798+#else799799+ evpe(vpeflags);800800+#endif801801+ emt(dmt_flag);802802+ local_irq_restore(flags);775803776776- list_for_each_entry(n, &v->notify, list) {777777- n->start(v->minor);778778- }804804+ list_for_each_entry(n, &v->notify, list)805805+ n->start(minor);779806780807 return 0;781808}···9981023 return 0;9991024}1000102510011001-void __used dump_vpe(struct vpe * v)10021002-{10031003- struct tc *t;10041004-10051005- settc(v->minor);10061006-10071007- printk(KERN_DEBUG "VPEControl 0x%lx\n", read_vpe_c0_vpecontrol());10081008- printk(KERN_DEBUG "VPEConf0 0x%lx\n", read_vpe_c0_vpeconf0());10091009-10101010- list_for_each_entry(t, &vpecontrol.tc_list, list)10111011- dump_tc(t);10121012-}10131013-10141026static void cleanup_tc(struct tc *tc)10151027{10281028+ unsigned long flags;10291029+ unsigned int mtflags, vpflags;10161030 int tmp;1017103110321032+ local_irq_save(flags);10331033+ mtflags = dmt();10341034+ vpflags = dvpe();10181035 /* Put MVPE's into 'configuration state' */10191036 set_c0_mvpcontrol(MVPCONTROL_VPC);10201037···10211054 write_tc_c0_tchalt(TCHALT_H);1022105510231056 /* bind it to anything other than VPE1 */10241024- write_tc_c0_tcbind(read_tc_c0_tcbind() & ~TCBIND_CURVPE); // | TCBIND_CURVPE10571057+// write_tc_c0_tcbind(read_tc_c0_tcbind() & ~TCBIND_CURVPE); // | TCBIND_CURVPE1025105810261059 clear_c0_mvpcontrol(MVPCONTROL_VPC);10601060+ evpe(vpflags);10611061+ emt(mtflags);10621062+ local_irq_restore(flags);10271063}1028106410291065static int getcwd(char *buff, int size)···10471077/* checks VPE is unused and gets ready to load program */10481078static int vpe_open(struct inode *inode, struct file *filp)10491079{10501050- int minor, ret;10511080 enum vpe_state state;10521052- struct vpe *v;10531081 struct vpe_notifications *not;10821082+ struct vpe *v;10831083+ int ret;1054108410551055- /* assume only 1 device at the mo. */10561056- if ((minor = iminor(inode)) != 1) {10851085+ if (minor != iminor(inode)) {10861086+ /* assume only 1 device at the moment. */10571087 printk(KERN_WARNING "VPE loader: only vpe1 is supported\n");10581088 return -ENODEV;10591089 }1060109010611061- if ((v = get_vpe(minor)) == NULL) {10911091+ if ((v = get_vpe(tclimit)) == NULL) {10621092 printk(KERN_WARNING "VPE loader: unable to get vpe\n");10631093 return -ENODEV;10641094 }1065109510661096 state = xchg(&v->state, VPE_STATE_INUSE);10671097 if (state != VPE_STATE_UNUSED) {10681068- dvpe();10691069-10701098 printk(KERN_DEBUG "VPE loader: tc in use dumping regs\n");1071109910721072- dump_tc(get_tc(minor));10731073-10741100 list_for_each_entry(not, &v->notify, list) {10751075- not->stop(minor);11011101+ not->stop(tclimit);10761102 }1077110310781104 release_progmem(v->load_addr);10791079- cleanup_tc(get_tc(minor));11051105+ cleanup_tc(get_tc(tclimit));10801106 }1081110710821108 /* this of-course trashes what was there before... */···1099113311001134 v->shared_ptr = NULL;11011135 v->__start = 0;11361136+11021137 return 0;11031138}1104113911051140static int vpe_release(struct inode *inode, struct file *filp)11061141{11071107- int minor, ret = 0;11081142 struct vpe *v;11091143 Elf_Ehdr *hdr;11441144+ int ret = 0;1110114511111111- minor = iminor(inode);11121112- if ((v = get_vpe(minor)) == NULL)11461146+ v = get_vpe(tclimit);11471147+ if (v == NULL)11131148 return -ENODEV;11141114-11151115- // simple case of fire and forget, so tell the VPE to run...1116114911171150 hdr = (Elf_Ehdr *) v->pbuffer;11181151 if (memcmp(hdr->e_ident, ELFMAG, 4) == 0) {11191119- if (vpe_elfload(v) >= 0)11521152+ if (vpe_elfload(v) >= 0) {11201153 vpe_run(v);11211121- else {11541154+ } else {11221155 printk(KERN_WARNING "VPE loader: ELF load failed.\n");11231156 ret = -ENOEXEC;11241157 }···11441179static ssize_t vpe_write(struct file *file, const char __user * buffer,11451180 size_t count, loff_t * ppos)11461181{11471147- int minor;11481182 size_t ret = count;11491183 struct vpe *v;1150118411511151- minor = iminor(file->f_path.dentry->d_inode);11521152- if ((v = get_vpe(minor)) == NULL)11851185+ if (iminor(file->f_path.dentry->d_inode) != minor)11861186+ return -ENODEV;11871187+11881188+ v = get_vpe(tclimit);11891189+ if (v == NULL)11531190 return -ENODEV;1154119111551192 if (v->pbuffer == NULL) {···1337137013381371static int __init vpe_module_init(void)13391372{13731373+ unsigned int mtflags, vpflags;13741374+ int hw_tcs, hw_vpes, tc, err = 0;13751375+ unsigned long flags, val;13401376 struct vpe *v = NULL;13411377 struct device *dev;13421378 struct tc *t;13431343- unsigned long val;13441344- int i, err;1345137913461380 if (!cpu_has_mipsmt) {13471381 printk("VPE loader: not a MIPS MT capable processor\n");13821382+ return -ENODEV;13831383+ }13841384+13851385+ if (vpelimit == 0) {13861386+ printk(KERN_WARNING "No VPEs reserved for AP/SP, not "13871387+ "initializing VPE loader.\nPass maxvpes=<n> argument as "13881388+ "kernel argument\n");13891389+13901390+ return -ENODEV;13911391+ }13921392+13931393+ if (tclimit == 0) {13941394+ printk(KERN_WARNING "No TCs reserved for AP/SP, not "13951395+ "initializing VPE loader.\nPass maxtcs=<n> argument as "13961396+ "kernel argument\n");13971397+13481398 return -ENODEV;13491399 }13501400···13721388 }1373138913741390 dev = device_create(mt_class, NULL, MKDEV(major, minor),13751375- "tc%d", minor);13911391+ "vpe%d", minor);13761392 if (IS_ERR(dev)) {13771393 err = PTR_ERR(dev);13781394 goto out_chrdev;13791395 }13801396 vpe_dev = dev;1381139713821382- dmt();13831383- dvpe();13981398+ local_irq_save(flags);13991399+ mtflags = dmt();14001400+ vpflags = dvpe();1384140113851402 /* Put MVPE's into 'configuration state' */13861403 set_c0_mvpcontrol(MVPCONTROL_VPC);1387140413881405 /* dump_mtregs(); */1389140613901390-13911407 val = read_c0_mvpconf0();13921392- for (i = 0; i < ((val & MVPCONF0_PTC) + 1); i++) {13931393- t = alloc_tc(i);14081408+ hw_tcs = (val & MVPCONF0_PTC) + 1;14091409+ hw_vpes = ((val & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT) + 1;14101410+14111411+ for (tc = tclimit; tc < hw_tcs; tc++) {14121412+ /*14131413+ * Must re-enable multithreading temporarily or in case we14141414+ * reschedule send IPIs or similar we might hang.14151415+ */14161416+ clear_c0_mvpcontrol(MVPCONTROL_VPC);14171417+ evpe(vpflags);14181418+ emt(mtflags);14191419+ local_irq_restore(flags);14201420+ t = alloc_tc(tc);14211421+ if (!t) {14221422+ err = -ENOMEM;14231423+ goto out;14241424+ }14251425+14261426+ local_irq_save(flags);14271427+ mtflags = dmt();14281428+ vpflags = dvpe();14291429+ set_c0_mvpcontrol(MVPCONTROL_VPC);1394143013951431 /* VPE's */13961396- if (i < ((val & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT) + 1) {13971397- settc(i);14321432+ if (tc < hw_tcs) {14331433+ settc(tc);1398143413991399- if ((v = alloc_vpe(i)) == NULL) {14351435+ if ((v = alloc_vpe(tc)) == NULL) {14001436 printk(KERN_WARNING "VPE: unable to allocate VPE\n");14011401- return -ENODEV;14371437+14381438+ goto out_reenable;14021439 }1403144014041441 /* add the tc to the list of this vpe's tc's. */14051442 list_add(&t->tc, &v->tc);1406144314071444 /* deactivate all but vpe0 */14081408- if (i != 0) {14451445+ if (tc >= tclimit) {14091446 unsigned long tmp = read_vpe_c0_vpeconf0();1410144714111448 tmp &= ~VPECONF0_VPA;···14391434 /* disable multi-threading with TC's */14401435 write_vpe_c0_vpecontrol(read_vpe_c0_vpecontrol() & ~VPECONTROL_TE);1441143614421442- if (i != 0) {14371437+ if (tc >= vpelimit) {14431438 /*14441439 * Set config to be the same as vpe0,14451440 * particularly kseg0 coherency alg···14511446 /* TC's */14521447 t->pvpe = v; /* set the parent vpe */1453144814541454- if (i != 0) {14491449+ if (tc >= tclimit) {14551450 unsigned long tmp;1456145114571457- settc(i);14521452+ settc(tc);1458145314591454 /* Any TC that is bound to VPE0 gets left as is - in case14601455 we are running SMTC on VPE0. A TC that is bound to any···14841479 }14851480 }1486148114821482+out_reenable:14871483 /* release config state */14881484 clear_c0_mvpcontrol(MVPCONTROL_VPC);14851485+14861486+ evpe(vpflags);14871487+ emt(mtflags);14881488+ local_irq_restore(flags);1489148914901490#ifdef CONFIG_MIPS_APSP_KSPD14911491 kspd_events.kspd_sp_exit = kspd_sp_exit;···15001490out_chrdev:15011491 unregister_chrdev(major, module_name);1502149214931493+out:15031494 return err;15041495}15051496
+6
include/asm-mips/mips_mt.h
···8899#include <linux/cpumask.h>10101111+/*1212+ * How many VPEs and TCs is Linux allowed to use? 0 means no limit.1313+ */1414+extern int tclimit;1515+extern int vpelimit;1616+1117extern cpumask_t mt_fpu_cpumask;1218extern unsigned long mt_fpemul_threshold;1319