123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162 |
- /*
- * 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)
- #define DBG udbg_printf
- #else
- #define DBG pr_debug
- #endif
- static irqreturn_t ipi_function_handler(int irq, void *msg)
- {
- smp_message_recv((int)(long)msg);
- return IRQ_HANDLED;
- }
- /**
- * ps3_ipi_virqs - a per cpu array of virqs for ipi use
- */
- #define MSG_COUNT 4
- static DEFINE_PER_CPU(unsigned int, ps3_ipi_virqs[MSG_COUNT]);
- static const char *names[MSG_COUNT] = {
- "ipi call",
- "ipi reschedule",
- "ipi migrate",
- "ipi debug brk"
- };
- static void do_message_pass(int target, int msg)
- {
- int result;
- unsigned int virq;
- if (msg >= MSG_COUNT) {
- DBG("%s:%d: bad msg: %d\n", __func__, __LINE__, msg);
- return;
- }
- virq = per_cpu(ps3_ipi_virqs, target)[msg];
- result = ps3_send_event_locally(virq);
- if (result)
- DBG("%s:%d: ps3_send_event_locally(%d, %d) failed"
- " (%d)\n", __func__, __LINE__, target, msg, result);
- }
- static void ps3_smp_message_pass(int target, int msg)
- {
- int cpu;
- if (target < NR_CPUS)
- do_message_pass(target, msg);
- else if (target == MSG_ALL_BUT_SELF) {
- for_each_online_cpu(cpu)
- if (cpu != smp_processor_id())
- do_message_pass(cpu, msg);
- } else {
- for_each_online_cpu(cpu)
- do_message_pass(cpu, msg);
- }
- }
- static int ps3_smp_probe(void)
- {
- return 2;
- }
- static void __init ps3_smp_setup_cpu(int cpu)
- {
- int result;
- unsigned int *virqs = per_cpu(ps3_ipi_virqs, cpu);
- int i;
- DBG(" -> %s:%d: (%d)\n", __func__, __LINE__, cpu);
- /*
- * Check assumptions on ps3_ipi_virqs[] indexing. If this
- * check fails, then a different mapping of PPC_MSG_
- * to index needs to be setup.
- */
- 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);
- for (i = 0; i < MSG_COUNT; i++) {
- result = ps3_event_receive_port_setup(cpu, &virqs[i]);
- if (result)
- continue;
- DBG("%s:%d: (%d, %d) => virq %u\n",
- __func__, __LINE__, cpu, i, virqs[i]);
- result = request_irq(virqs[i], ipi_function_handler,
- IRQF_DISABLED, names[i], (void*)(long)i);
- if (result)
- virqs[i] = NO_IRQ;
- }
- ps3_register_ipi_debug_brk(cpu, virqs[PPC_MSG_DEBUGGER_BREAK]);
- DBG(" <- %s:%d: (%d)\n", __func__, __LINE__, cpu);
- }
- void ps3_smp_cleanup_cpu(int cpu)
- {
- unsigned int *virqs = per_cpu(ps3_ipi_virqs, cpu);
- int i;
- DBG(" -> %s:%d: (%d)\n", __func__, __LINE__, cpu);
- for (i = 0; i < MSG_COUNT; i++) {
- /* Can't call free_irq from interrupt context. */
- ps3_event_receive_port_destroy(virqs[i]);
- virqs[i] = NO_IRQ;
- }
- 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,
- .setup_cpu = ps3_smp_setup_cpu,
- };
- void smp_init_ps3(void)
- {
- DBG(" -> %s\n", __func__);
- smp_ops = &ps3_smp_ops;
- DBG(" <- %s\n", __func__);
- }
|