| 
									
										
										
										
											2006-11-23 00:46:51 +01:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  *  PS3 SMP routines. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *  Copyright (C) 2006 Sony Computer Entertainment Inc. | 
					
						
							|  |  |  |  *  Copyright 2006 Sony Corp. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *  This program is free software; you can redistribute it and/or modify | 
					
						
							|  |  |  |  *  it under the terms of the GNU General Public License as published by | 
					
						
							|  |  |  |  *  the Free Software Foundation; version 2 of the License. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *  This program is distributed in the hope that it will be useful, | 
					
						
							|  |  |  |  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  |  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
					
						
							|  |  |  |  *  GNU General Public License for more details. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *  You should have received a copy of the GNU General Public License | 
					
						
							|  |  |  |  *  along with this program; if not, write to the Free Software | 
					
						
							|  |  |  |  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <linux/kernel.h>
 | 
					
						
							|  |  |  | #include <linux/smp.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <asm/machdep.h>
 | 
					
						
							|  |  |  | #include <asm/udbg.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "platform.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #if defined(DEBUG)
 | 
					
						
							| 
									
										
										
										
											2007-06-16 07:19:23 +10:00
										 |  |  | #define DBG udbg_printf
 | 
					
						
							| 
									
										
										
										
											2006-11-23 00:46:51 +01:00
										 |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2007-06-16 07:19:23 +10:00
										 |  |  | #define DBG pr_debug
 | 
					
						
							| 
									
										
										
										
											2006-11-23 00:46:51 +01:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							| 
									
										
										
										
											2007-06-16 07:17:42 +10:00
										 |  |  |   * ps3_ipi_virqs - a per cpu array of virqs for ipi use | 
					
						
							| 
									
										
										
										
											2006-11-23 00:46:51 +01:00
										 |  |  |   */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define MSG_COUNT 4
 | 
					
						
							| 
									
										
										
										
											2009-06-24 15:13:45 +09:00
										 |  |  | static DEFINE_PER_CPU(unsigned int [MSG_COUNT], ps3_ipi_virqs); | 
					
						
							| 
									
										
										
										
											2006-11-23 00:46:51 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-05-10 19:29:10 +00:00
										 |  |  | static void ps3_smp_message_pass(int cpu, int msg) | 
					
						
							| 
									
										
										
										
											2006-11-23 00:46:51 +01:00
										 |  |  | { | 
					
						
							|  |  |  | 	int result; | 
					
						
							|  |  |  | 	unsigned int virq; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (msg >= MSG_COUNT) { | 
					
						
							|  |  |  | 		DBG("%s:%d: bad msg: %d\n", __func__, __LINE__, msg); | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-05-10 19:29:10 +00:00
										 |  |  | 	virq = per_cpu(ps3_ipi_virqs, cpu)[msg]; | 
					
						
							| 
									
										
										
										
											2006-11-23 00:46:51 +01:00
										 |  |  | 	result = ps3_send_event_locally(virq); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (result) | 
					
						
							|  |  |  | 		DBG("%s:%d: ps3_send_event_locally(%d, %d) failed" | 
					
						
							| 
									
										
										
										
											2011-05-10 19:29:10 +00:00
										 |  |  | 			" (%d)\n", __func__, __LINE__, cpu, msg, result); | 
					
						
							| 
									
										
										
										
											2006-11-23 00:46:51 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-11-29 15:38:50 +00:00
										 |  |  | static int __init ps3_smp_probe(void) | 
					
						
							| 
									
										
										
										
											2006-11-23 00:46:51 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-11-08 12:38:21 +00:00
										 |  |  | 	int cpu; | 
					
						
							| 
									
										
										
										
											2006-11-23 00:46:51 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-11-08 12:38:21 +00:00
										 |  |  | 	for (cpu = 0; cpu < 2; cpu++) { | 
					
						
							|  |  |  | 		int result; | 
					
						
							|  |  |  | 		unsigned int *virqs = per_cpu(ps3_ipi_virqs, cpu); | 
					
						
							|  |  |  | 		int i; | 
					
						
							| 
									
										
										
										
											2006-11-23 00:46:51 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-11-08 12:38:21 +00:00
										 |  |  | 		DBG(" -> %s:%d: (%d)\n", __func__, __LINE__, cpu); | 
					
						
							| 
									
										
										
										
											2006-11-23 00:46:51 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-11-08 12:38:21 +00:00
										 |  |  | 		/*
 | 
					
						
							|  |  |  | 		* Check assumptions on ps3_ipi_virqs[] indexing. If this | 
					
						
							|  |  |  | 		* check fails, then a different mapping of PPC_MSG_ | 
					
						
							|  |  |  | 		* to index needs to be setup. | 
					
						
							|  |  |  | 		*/ | 
					
						
							| 
									
										
										
										
											2006-11-23 00:46:51 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-11-08 12:38:21 +00:00
										 |  |  | 		BUILD_BUG_ON(PPC_MSG_CALL_FUNCTION    != 0); | 
					
						
							|  |  |  | 		BUILD_BUG_ON(PPC_MSG_RESCHEDULE       != 1); | 
					
						
							|  |  |  | 		BUILD_BUG_ON(PPC_MSG_CALL_FUNC_SINGLE != 2); | 
					
						
							|  |  |  | 		BUILD_BUG_ON(PPC_MSG_DEBUGGER_BREAK   != 3); | 
					
						
							| 
									
										
										
										
											2006-11-23 00:46:51 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-11-08 12:38:21 +00:00
										 |  |  | 		for (i = 0; i < MSG_COUNT; i++) { | 
					
						
							|  |  |  | 			result = ps3_event_receive_port_setup(cpu, &virqs[i]); | 
					
						
							| 
									
										
										
										
											2006-11-23 00:46:51 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-11-08 12:38:21 +00:00
										 |  |  | 			if (result) | 
					
						
							|  |  |  | 				continue; | 
					
						
							| 
									
										
										
										
											2006-11-23 00:46:51 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-11-08 12:38:21 +00:00
										 |  |  | 			DBG("%s:%d: (%d, %d) => virq %u\n", | 
					
						
							|  |  |  | 				__func__, __LINE__, cpu, i, virqs[i]); | 
					
						
							| 
									
										
										
										
											2006-11-23 00:46:51 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-11-08 12:38:21 +00:00
										 |  |  | 			result = smp_request_message_ipi(virqs[i], i); | 
					
						
							| 
									
										
										
										
											2006-11-23 00:46:51 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-11-08 12:38:21 +00:00
										 |  |  | 			if (result) | 
					
						
							|  |  |  | 				virqs[i] = NO_IRQ; | 
					
						
							|  |  |  | 			else | 
					
						
							|  |  |  | 				ps3_register_ipi_irq(cpu, virqs[i]); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2006-11-23 00:46:51 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-11-08 12:38:21 +00:00
										 |  |  | 		ps3_register_ipi_debug_brk(cpu, virqs[PPC_MSG_DEBUGGER_BREAK]); | 
					
						
							| 
									
										
										
										
											2006-11-23 00:46:51 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-11-08 12:38:21 +00:00
										 |  |  | 		DBG(" <- %s:%d: (%d)\n", __func__, __LINE__, cpu); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 2; | 
					
						
							| 
									
										
										
										
											2006-11-23 00:46:51 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ps3_smp_cleanup_cpu(int cpu) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2007-06-16 07:17:42 +10:00
										 |  |  | 	unsigned int *virqs = per_cpu(ps3_ipi_virqs, cpu); | 
					
						
							| 
									
										
										
										
											2006-11-23 00:46:51 +01:00
										 |  |  | 	int i; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	DBG(" -> %s:%d: (%d)\n", __func__, __LINE__, cpu); | 
					
						
							| 
									
										
										
										
											2007-05-01 07:01:01 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-11-23 00:46:51 +01:00
										 |  |  | 	for (i = 0; i < MSG_COUNT; i++) { | 
					
						
							| 
									
										
										
										
											2007-06-16 07:19:32 +10:00
										 |  |  | 		/* Can't call free_irq from interrupt context. */ | 
					
						
							| 
									
										
										
										
											2007-05-01 07:01:01 +10:00
										 |  |  | 		ps3_event_receive_port_destroy(virqs[i]); | 
					
						
							| 
									
										
										
										
											2006-11-23 00:46:51 +01:00
										 |  |  | 		virqs[i] = NO_IRQ; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2007-05-01 07:01:01 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-11-23 00:46:51 +01:00
										 |  |  | 	DBG(" <- %s:%d: (%d)\n", __func__, __LINE__, cpu); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct smp_ops_t ps3_smp_ops = { | 
					
						
							|  |  |  | 	.probe		= ps3_smp_probe, | 
					
						
							|  |  |  | 	.message_pass	= ps3_smp_message_pass, | 
					
						
							|  |  |  | 	.kick_cpu	= smp_generic_kick_cpu, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void smp_init_ps3(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	DBG(" -> %s\n", __func__); | 
					
						
							|  |  |  | 	smp_ops = &ps3_smp_ops; | 
					
						
							|  |  |  | 	DBG(" <- %s\n", __func__); | 
					
						
							|  |  |  | } |