0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include <linux/kernel.h>
0012 #include <linux/smp.h>
0013
0014 #include <asm/addrspace.h>
0015 #include <asm/mipsmtregs.h>
0016 #include <asm/mips-boards/launch.h>
0017 #include <asm/vpe.h>
0018
0019 int amon_cpu_avail(int cpu)
0020 {
0021 struct cpulaunch *launch = (struct cpulaunch *)CKSEG0ADDR(CPULAUNCH);
0022
0023 if (cpu < 0 || cpu >= NCPULAUNCH) {
0024 pr_debug("avail: cpu%d is out of range\n", cpu);
0025 return 0;
0026 }
0027
0028 launch += cpu;
0029 if (!(launch->flags & LAUNCH_FREADY)) {
0030 pr_debug("avail: cpu%d is not ready\n", cpu);
0031 return 0;
0032 }
0033 if (launch->flags & (LAUNCH_FGO|LAUNCH_FGONE)) {
0034 pr_debug("avail: too late.. cpu%d is already gone\n", cpu);
0035 return 0;
0036 }
0037
0038 return 1;
0039 }
0040
0041 int amon_cpu_start(int cpu,
0042 unsigned long pc, unsigned long sp,
0043 unsigned long gp, unsigned long a0)
0044 {
0045 volatile struct cpulaunch *launch =
0046 (struct cpulaunch *)CKSEG0ADDR(CPULAUNCH);
0047
0048 if (!amon_cpu_avail(cpu))
0049 return -1;
0050 if (cpu == smp_processor_id()) {
0051 pr_debug("launch: I am cpu%d!\n", cpu);
0052 return -1;
0053 }
0054 launch += cpu;
0055
0056 pr_debug("launch: starting cpu%d\n", cpu);
0057
0058 launch->pc = pc;
0059 launch->gp = gp;
0060 launch->sp = sp;
0061 launch->a0 = a0;
0062
0063 smp_wmb();
0064 launch->flags |= LAUNCH_FGO;
0065 smp_wmb();
0066
0067 while ((launch->flags & LAUNCH_FGONE) == 0)
0068 ;
0069 smp_rmb();
0070 pr_debug("launch: cpu%d gone!\n", cpu);
0071
0072 return 0;
0073 }
0074
0075 #ifdef CONFIG_MIPS_VPE_LOADER_CMP
0076 int vpe_run(struct vpe *v)
0077 {
0078 struct vpe_notifications *n;
0079
0080 if (amon_cpu_start(aprp_cpu_index(), v->__start, 0, 0, 0) < 0)
0081 return -1;
0082
0083 list_for_each_entry(n, &v->notify, list)
0084 n->start(VPE_MODULE_MINOR);
0085
0086 return 0;
0087 }
0088 #endif