162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  PS3 SMP routines.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *  Copyright (C) 2006 Sony Computer Entertainment Inc.
662306a36Sopenharmony_ci *  Copyright 2006 Sony Corp.
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/kernel.h>
1062306a36Sopenharmony_ci#include <linux/smp.h>
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include <asm/machdep.h>
1362306a36Sopenharmony_ci#include <asm/udbg.h>
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#include "platform.h"
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#if defined(DEBUG)
1862306a36Sopenharmony_ci#define DBG udbg_printf
1962306a36Sopenharmony_ci#else
2062306a36Sopenharmony_ci#define DBG pr_debug
2162306a36Sopenharmony_ci#endif
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci/**
2462306a36Sopenharmony_ci  * ps3_ipi_virqs - a per cpu array of virqs for ipi use
2562306a36Sopenharmony_ci  */
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci#define MSG_COUNT 4
2862306a36Sopenharmony_cistatic DEFINE_PER_CPU(unsigned int [MSG_COUNT], ps3_ipi_virqs);
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_cistatic void ps3_smp_message_pass(int cpu, int msg)
3162306a36Sopenharmony_ci{
3262306a36Sopenharmony_ci	int result;
3362306a36Sopenharmony_ci	unsigned int virq;
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci	if (msg >= MSG_COUNT) {
3662306a36Sopenharmony_ci		DBG("%s:%d: bad msg: %d\n", __func__, __LINE__, msg);
3762306a36Sopenharmony_ci		return;
3862306a36Sopenharmony_ci	}
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	virq = per_cpu(ps3_ipi_virqs, cpu)[msg];
4162306a36Sopenharmony_ci	result = ps3_send_event_locally(virq);
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	if (result)
4462306a36Sopenharmony_ci		DBG("%s:%d: ps3_send_event_locally(%d, %d) failed"
4562306a36Sopenharmony_ci			" (%d)\n", __func__, __LINE__, cpu, msg, result);
4662306a36Sopenharmony_ci}
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_cistatic void __init ps3_smp_probe(void)
4962306a36Sopenharmony_ci{
5062306a36Sopenharmony_ci	int cpu;
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	for (cpu = 0; cpu < 2; cpu++) {
5362306a36Sopenharmony_ci		int result;
5462306a36Sopenharmony_ci		unsigned int *virqs = per_cpu(ps3_ipi_virqs, cpu);
5562306a36Sopenharmony_ci		int i;
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci		DBG(" -> %s:%d: (%d)\n", __func__, __LINE__, cpu);
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci		/*
6062306a36Sopenharmony_ci		* Check assumptions on ps3_ipi_virqs[] indexing. If this
6162306a36Sopenharmony_ci		* check fails, then a different mapping of PPC_MSG_
6262306a36Sopenharmony_ci		* to index needs to be setup.
6362306a36Sopenharmony_ci		*/
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci		BUILD_BUG_ON(PPC_MSG_CALL_FUNCTION    != 0);
6662306a36Sopenharmony_ci		BUILD_BUG_ON(PPC_MSG_RESCHEDULE       != 1);
6762306a36Sopenharmony_ci		BUILD_BUG_ON(PPC_MSG_TICK_BROADCAST   != 2);
6862306a36Sopenharmony_ci		BUILD_BUG_ON(PPC_MSG_NMI_IPI          != 3);
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci		for (i = 0; i < MSG_COUNT; i++) {
7162306a36Sopenharmony_ci			result = ps3_event_receive_port_setup(cpu, &virqs[i]);
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci			if (result)
7462306a36Sopenharmony_ci				continue;
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci			DBG("%s:%d: (%d, %d) => virq %u\n",
7762306a36Sopenharmony_ci				__func__, __LINE__, cpu, i, virqs[i]);
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci			result = smp_request_message_ipi(virqs[i], i);
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci			if (result)
8262306a36Sopenharmony_ci				virqs[i] = 0;
8362306a36Sopenharmony_ci			else
8462306a36Sopenharmony_ci				ps3_register_ipi_irq(cpu, virqs[i]);
8562306a36Sopenharmony_ci		}
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci		ps3_register_ipi_debug_brk(cpu, virqs[PPC_MSG_NMI_IPI]);
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci		DBG(" <- %s:%d: (%d)\n", __func__, __LINE__, cpu);
9062306a36Sopenharmony_ci	}
9162306a36Sopenharmony_ci}
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_civoid ps3_smp_cleanup_cpu(int cpu)
9462306a36Sopenharmony_ci{
9562306a36Sopenharmony_ci	unsigned int *virqs = per_cpu(ps3_ipi_virqs, cpu);
9662306a36Sopenharmony_ci	int i;
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	DBG(" -> %s:%d: (%d)\n", __func__, __LINE__, cpu);
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	for (i = 0; i < MSG_COUNT; i++) {
10162306a36Sopenharmony_ci		/* Can't call free_irq from interrupt context. */
10262306a36Sopenharmony_ci		ps3_event_receive_port_destroy(virqs[i]);
10362306a36Sopenharmony_ci		virqs[i] = 0;
10462306a36Sopenharmony_ci	}
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	DBG(" <- %s:%d: (%d)\n", __func__, __LINE__, cpu);
10762306a36Sopenharmony_ci}
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_cistatic struct smp_ops_t ps3_smp_ops = {
11062306a36Sopenharmony_ci	.probe		= ps3_smp_probe,
11162306a36Sopenharmony_ci	.message_pass	= ps3_smp_message_pass,
11262306a36Sopenharmony_ci	.kick_cpu	= smp_generic_kick_cpu,
11362306a36Sopenharmony_ci};
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_civoid __init smp_init_ps3(void)
11662306a36Sopenharmony_ci{
11762306a36Sopenharmony_ci	DBG(" -> %s\n", __func__);
11862306a36Sopenharmony_ci	smp_ops = &ps3_smp_ops;
11962306a36Sopenharmony_ci	DBG(" <- %s\n", __func__);
12062306a36Sopenharmony_ci}
121