smp: add APU support [1/2]

PD#SWPL-119162

Problem:
APU should not be seen except audio

Solution:
add APU support

Verify:
t5m

Change-Id: I03828c60962a16cdf801c8ddabeb7e05b4a4f232
Signed-off-by: Hanjie Lin <hanjie.lin@amlogic.com>
diff --git a/arch/arm64/kernel/cpuinfo.c b/arch/arm64/kernel/cpuinfo.c
index e1e7278..0db2edf 100644
--- a/arch/arm64/kernel/cpuinfo.c
+++ b/arch/arm64/kernel/cpuinfo.c
@@ -162,6 +162,10 @@ static int c_show(struct seq_file *m, void *v)
 		struct cpuinfo_arm64 *cpuinfo = &per_cpu(cpu_data, i);
 		u32 midr = cpuinfo->reg_midr;
 
+#ifdef CONFIG_AMLOGIC_APU
+		if (apu_enable && i == apu_id)
+			continue;
+#endif
 		/*
 		 * glibc reads /proc/cpuinfo to determine the number of
 		 * online processors, looking for lines beginning with
@@ -361,6 +365,9 @@ static void cpuinfo_detect_icache_policy(struct cpuinfo_arm64 *info)
 		break;
 	}
 
+#ifdef CONFIG_AMLOGIC_APU
+	if (!(apu_enable && cpu == apu_id))
+#endif
 	pr_info("Detected %s I-cache on CPU%d\n", icache_policy_str(l1ip), cpu);
 }
 
diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c
index d3b23e6..3110294 100644
--- a/arch/arm64/kernel/smp.c
+++ b/arch/arm64/kernel/smp.c
@@ -268,6 +268,9 @@ asmlinkage notrace void secondary_start_kernel(void)
 	 * the CPU migration code to notice that the CPU is online
 	 * before we continue.
 	 */
+#ifdef CONFIG_AMLOGIC_APU
+	if (!(apu_enable && cpu == apu_id))
+#endif
 	pr_info("CPU%u: Booted secondary processor 0x%010lx [0x%08x]\n",
 					 cpu, (unsigned long)mpidr,
 					 read_cpuid_id());
@@ -453,7 +456,15 @@ static void __init hyp_mode_check(void)
 
 void __init smp_cpus_done(unsigned int max_cpus)
 {
+#ifdef CONFIG_AMLOGIC_APU
+	int num = num_online_cpus();
+
+	if (apu_id != -1)
+		num -= 1;
+	pr_info("SMP: Total of %d processors activated.\n", num);
+#else
 	pr_info("SMP: Total of %d processors activated.\n", num_online_cpus());
+#endif
 	setup_cpu_features();
 	hyp_mode_check();
 	apply_alternatives_all();
@@ -675,10 +686,33 @@ static void __init acpi_parse_and_init_cpus(void)
 static void __init of_parse_and_init_cpus(void)
 {
 	struct device_node *dn;
+#ifdef CONFIG_AMLOGIC_APU
+	struct device_node *cpus;
+	int ret = 0;
+
+	cpus = of_find_node_by_path("/cpus");
+	ret |= of_property_read_u32(cpus, "apu_id", &apu_id);
+	ret |= of_property_read_u32(cpus, "apu_hwid", &apu_hwid);
+
+	if (ret) {
+		apu_id = -1;
+		apu_hwid = -1;
+		pr_info("no apu_id or apu_hwid\n");
+	}
+#endif
 
 	for_each_of_cpu_node(dn) {
 		u64 hwid = of_get_cpu_mpidr(dn);
 
+#ifdef CONFIG_AMLOGIC_APU
+		if (cpu_count == apu_id && hwid != apu_hwid) {
+			set_cpu_logical_map(cpu_count, apu_hwid);
+			early_map_cpu_to_node(cpu_count, 0);
+			cpu_count++;
+			pr_info("apu_enable:%d apu_id:%x apu_hwid:%x active\n",
+				apu_enable, apu_id, apu_hwid);
+		}
+#endif
 		if (hwid == INVALID_HWID)
 			goto next;
 
@@ -723,6 +757,16 @@ static void __init of_parse_and_init_cpus(void)
 next:
 		cpu_count++;
 	}
+
+#ifdef CONFIG_AMLOGIC_APU
+	if (cpu_count == apu_id) {
+		set_cpu_logical_map(cpu_count, apu_hwid);
+		early_map_cpu_to_node(cpu_count, 0);
+		cpu_count++;
+		pr_info("apu_enable:%d apu_id:%x apu_hwid:%x active\n",
+			apu_enable, apu_id, apu_hwid);
+	}
+#endif
 }
 
 /*
diff --git a/drivers/of/base.c b/drivers/of/base.c
index e46a075..66abf4b 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -389,6 +389,16 @@ struct device_node *of_get_cpu_node(int cpu, unsigned int *thread)
 		if (arch_find_n_match_cpu_physical_id(cpun, cpu, thread))
 			return cpun;
 	}
+
+#ifdef CONFIG_AMLOGIC_APU
+	if (cpu == apu_id)
+		cpu -= 1;
+
+	for_each_of_cpu_node(cpun) {
+		if (arch_find_n_match_cpu_physical_id(cpun, cpu, thread))
+			return cpun;
+	}
+#endif
 	return NULL;
 }
 EXPORT_SYMBOL(of_get_cpu_node);
diff --git a/fs/proc/base.c b/fs/proc/base.c
index f7eda33..8e999b3 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -3508,6 +3508,13 @@ int proc_pid_readdir(struct file *file, struct dir_context *ctx)
 		char name[10 + 1];
 		unsigned int len;
 
+#ifdef CONFIG_AMLOGIC_APU
+		if (apu_enable && apu_id != -1 &&
+		    iter.task->nr_cpus_allowed == 1 &&
+		    cpumask_test_cpu(apu_id, &iter.task->cpus_mask))
+			continue;
+#endif
+
 		cond_resched();
 		if (!has_pid_permissions(fs_info, iter.task, HIDEPID_INVISIBLE))
 			continue;
@@ -3854,6 +3861,13 @@ static int proc_task_readdir(struct file *file, struct dir_context *ctx)
 		unsigned int len;
 		tid = task_pid_nr_ns(task, ns);
 		len = snprintf(name, sizeof(name), "%u", tid);
+
+#ifdef CONFIG_AMLOGIC_APU
+		if (apu_enable && apu_id != -1 &&
+		    task->nr_cpus_allowed == 1 &&
+		    cpumask_test_cpu(apu_id, &task->cpus_mask))
+			continue;
+#endif
 		if (!proc_fill_cache(file, ctx, name, len,
 				proc_task_instantiate, task, NULL)) {
 			/* returning this tgid failed, save it as the first
diff --git a/fs/proc/stat.c b/fs/proc/stat.c
index 4fb8729..8af4299 100644
--- a/fs/proc/stat.c
+++ b/fs/proc/stat.c
@@ -126,6 +126,10 @@ static int show_stat(struct seq_file *p, void *v)
 		struct kernel_cpustat kcpustat;
 		u64 *cpustat = kcpustat.cpustat;
 
+#ifdef CONFIG_AMLOGIC_APU
+		if (apu_enable && i == apu_id)
+			continue;
+#endif
 		kcpustat_cpu_fetch(&kcpustat, i);
 
 		user		+= cpustat[CPUTIME_USER];
@@ -166,6 +170,10 @@ static int show_stat(struct seq_file *p, void *v)
 		struct kernel_cpustat kcpustat;
 		u64 *cpustat = kcpustat.cpustat;
 
+#ifdef CONFIG_AMLOGIC_APU
+		if (apu_enable && i == apu_id)
+			continue;
+#endif
 		kcpustat_cpu_fetch(&kcpustat, i);
 
 		/* Copy values here to work around gcc-2.95.3, gcc-2.96 */
diff --git a/include/linux/smp.h b/include/linux/smp.h
index 510519e..88bbeef 100644
--- a/include/linux/smp.h
+++ b/include/linux/smp.h
@@ -287,4 +287,10 @@ int smpcfd_prepare_cpu(unsigned int cpu);
 int smpcfd_dead_cpu(unsigned int cpu);
 int smpcfd_dying_cpu(unsigned int cpu);
 
+#ifdef CONFIG_AMLOGIC_APU
+extern int apu_id;
+extern int apu_hwid;
+extern int apu_enable;
+#endif
+
 #endif /* __LINUX_SMP_H */
diff --git a/kernel/smp.c b/kernel/smp.c
index 8282534..d950c59 100644
--- a/kernel/smp.c
+++ b/kernel/smp.c
@@ -1093,6 +1093,10 @@ void __init smp_init(void)
 
 	num_nodes = num_online_nodes();
 	num_cpus  = num_online_cpus();
+#ifdef CONFIG_AMLOGIC_APU
+	if (apu_enable && apu_id != -1)
+		num_cpus -= 1;
+#endif
 	pr_info("Brought up %d node%s, %d CPU%s\n",
 		num_nodes, (num_nodes > 1 ? "s" : ""),
 		num_cpus,  (num_cpus  > 1 ? "s" : ""));
@@ -1237,3 +1241,18 @@ int smp_call_on_cpu(unsigned int cpu, int (*func)(void *), void *par, bool phys)
 	return sscs.ret;
 }
 EXPORT_SYMBOL_GPL(smp_call_on_cpu);
+
+#ifdef CONFIG_AMLOGIC_APU
+int apu_id = -1;
+int apu_hwid = -1;
+int apu_enable = 1;
+
+static int __init setup_apu_enable(char *str)
+{
+	get_option(&str, &apu_enable);
+	pr_debug("set apu_enable=%d\n", apu_enable);
+	return 0;
+}
+
+early_param("apu_enable", setup_apu_enable);
+#endif
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 10f6079..8046d05 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -5196,6 +5196,11 @@ int tracing_set_cpumask(struct trace_array *tr,
 	if (!tr)
 		return -EINVAL;
 
+#ifdef CONFIG_AMLOGIC_APU
+	if (apu_enable && apu_id != -1)
+		cpumask_clear_cpu(apu_id, tracing_cpumask_new);
+#endif
+
 	local_irq_disable();
 	arch_spin_lock(&tr->max_lock);
 	for_each_tracing_cpu(cpu) {
@@ -8775,6 +8780,21 @@ tracing_init_tracefs_percpu(struct trace_array *tr, long cpu)
 	trace_create_cpu_file("snapshot_raw", TRACE_MODE_READ, d_cpu,
 				tr, cpu, &snapshot_raw_fops);
 #endif
+#ifdef CONFIG_AMLOGIC_APU
+	if (!apu_enable || apu_id != cpu)
+		return;
+
+	if (!cpumask_test_cpu(cpu, tr->tracing_cpumask))
+		return;
+
+	local_irq_disable();
+	arch_spin_lock(&tr->max_lock);
+	atomic_inc(&per_cpu_ptr(tr->array_buffer.data, apu_id)->disabled);
+	ring_buffer_record_disable_cpu(tr->array_buffer.buffer, apu_id);
+	arch_spin_unlock(&tr->max_lock);
+	local_irq_enable();
+	cpumask_clear_cpu(apu_id, tr->tracing_cpumask);
+#endif
 }
 
 #ifdef CONFIG_FTRACE_SELFTEST