18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public
38c2ecf20Sopenharmony_ci * License.  See the file "COPYING" in the main directory of this archive
48c2ecf20Sopenharmony_ci * for more details.
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Copyright (C) 2007 MIPS Technologies, Inc.  All rights reserved.
78c2ecf20Sopenharmony_ci * Copyright (C) 2013 Imagination Technologies Ltd.
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * Arbitrary Monitor Interface
108c2ecf20Sopenharmony_ci */
118c2ecf20Sopenharmony_ci#include <linux/kernel.h>
128c2ecf20Sopenharmony_ci#include <linux/smp.h>
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#include <asm/addrspace.h>
158c2ecf20Sopenharmony_ci#include <asm/mipsmtregs.h>
168c2ecf20Sopenharmony_ci#include <asm/mips-boards/launch.h>
178c2ecf20Sopenharmony_ci#include <asm/vpe.h>
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ciint amon_cpu_avail(int cpu)
208c2ecf20Sopenharmony_ci{
218c2ecf20Sopenharmony_ci	struct cpulaunch *launch = (struct cpulaunch *)CKSEG0ADDR(CPULAUNCH);
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci	if (cpu < 0 || cpu >= NCPULAUNCH) {
248c2ecf20Sopenharmony_ci		pr_debug("avail: cpu%d is out of range\n", cpu);
258c2ecf20Sopenharmony_ci		return 0;
268c2ecf20Sopenharmony_ci	}
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci	launch += cpu;
298c2ecf20Sopenharmony_ci	if (!(launch->flags & LAUNCH_FREADY)) {
308c2ecf20Sopenharmony_ci		pr_debug("avail: cpu%d is not ready\n", cpu);
318c2ecf20Sopenharmony_ci		return 0;
328c2ecf20Sopenharmony_ci	}
338c2ecf20Sopenharmony_ci	if (launch->flags & (LAUNCH_FGO|LAUNCH_FGONE)) {
348c2ecf20Sopenharmony_ci		pr_debug("avail: too late.. cpu%d is already gone\n", cpu);
358c2ecf20Sopenharmony_ci		return 0;
368c2ecf20Sopenharmony_ci	}
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci	return 1;
398c2ecf20Sopenharmony_ci}
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ciint amon_cpu_start(int cpu,
428c2ecf20Sopenharmony_ci		    unsigned long pc, unsigned long sp,
438c2ecf20Sopenharmony_ci		    unsigned long gp, unsigned long a0)
448c2ecf20Sopenharmony_ci{
458c2ecf20Sopenharmony_ci	volatile struct cpulaunch *launch =
468c2ecf20Sopenharmony_ci		(struct cpulaunch  *)CKSEG0ADDR(CPULAUNCH);
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci	if (!amon_cpu_avail(cpu))
498c2ecf20Sopenharmony_ci		return -1;
508c2ecf20Sopenharmony_ci	if (cpu == smp_processor_id()) {
518c2ecf20Sopenharmony_ci		pr_debug("launch: I am cpu%d!\n", cpu);
528c2ecf20Sopenharmony_ci		return -1;
538c2ecf20Sopenharmony_ci	}
548c2ecf20Sopenharmony_ci	launch += cpu;
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	pr_debug("launch: starting cpu%d\n", cpu);
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	launch->pc = pc;
598c2ecf20Sopenharmony_ci	launch->gp = gp;
608c2ecf20Sopenharmony_ci	launch->sp = sp;
618c2ecf20Sopenharmony_ci	launch->a0 = a0;
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	smp_wmb();		/* Target must see parameters before go */
648c2ecf20Sopenharmony_ci	launch->flags |= LAUNCH_FGO;
658c2ecf20Sopenharmony_ci	smp_wmb();		/* Target must see go before we poll  */
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci	while ((launch->flags & LAUNCH_FGONE) == 0)
688c2ecf20Sopenharmony_ci		;
698c2ecf20Sopenharmony_ci	smp_rmb();	/* Target will be updating flags soon */
708c2ecf20Sopenharmony_ci	pr_debug("launch: cpu%d gone!\n", cpu);
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	return 0;
738c2ecf20Sopenharmony_ci}
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci#ifdef CONFIG_MIPS_VPE_LOADER_CMP
768c2ecf20Sopenharmony_ciint vpe_run(struct vpe *v)
778c2ecf20Sopenharmony_ci{
788c2ecf20Sopenharmony_ci	struct vpe_notifications *n;
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci	if (amon_cpu_start(aprp_cpu_index(), v->__start, 0, 0, 0) < 0)
818c2ecf20Sopenharmony_ci		return -1;
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	list_for_each_entry(n, &v->notify, list)
848c2ecf20Sopenharmony_ci		n->start(VPE_MODULE_MINOR);
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	return 0;
878c2ecf20Sopenharmony_ci}
888c2ecf20Sopenharmony_ci#endif
89