linux/arch/powerpc/platforms/ps3/smp.c
<<
>>
Prefs
   1/*
   2 *  PS3 SMP routines.
   3 *
   4 *  Copyright (C) 2006 Sony Computer Entertainment Inc.
   5 *  Copyright 2006 Sony Corp.
   6 *
   7 *  This program is free software; you can redistribute it and/or modify
   8 *  it under the terms of the GNU General Public License as published by
   9 *  the Free Software Foundation; version 2 of the License.
  10 *
  11 *  This program is distributed in the hope that it will be useful,
  12 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14 *  GNU General Public License for more details.
  15 *
  16 *  You should have received a copy of the GNU General Public License
  17 *  along with this program; if not, write to the Free Software
  18 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  19 */
  20
  21#include <linux/kernel.h>
  22#include <linux/smp.h>
  23
  24#include <asm/machdep.h>
  25#include <asm/udbg.h>
  26
  27#include "platform.h"
  28
  29#if defined(DEBUG)
  30#define DBG udbg_printf
  31#else
  32#define DBG pr_debug
  33#endif
  34
  35/**
  36  * ps3_ipi_virqs - a per cpu array of virqs for ipi use
  37  */
  38
  39#define MSG_COUNT 4
  40static DEFINE_PER_CPU(unsigned int [MSG_COUNT], ps3_ipi_virqs);
  41
  42static void ps3_smp_message_pass(int cpu, int msg)
  43{
  44        int result;
  45        unsigned int virq;
  46
  47        if (msg >= MSG_COUNT) {
  48                DBG("%s:%d: bad msg: %d\n", __func__, __LINE__, msg);
  49                return;
  50        }
  51
  52        virq = per_cpu(ps3_ipi_virqs, cpu)[msg];
  53        result = ps3_send_event_locally(virq);
  54
  55        if (result)
  56                DBG("%s:%d: ps3_send_event_locally(%d, %d) failed"
  57                        " (%d)\n", __func__, __LINE__, cpu, msg, result);
  58}
  59
  60static int __init ps3_smp_probe(void)
  61{
  62        int cpu;
  63
  64        for (cpu = 0; cpu < 2; cpu++) {
  65                int result;
  66                unsigned int *virqs = per_cpu(ps3_ipi_virqs, cpu);
  67                int i;
  68
  69                DBG(" -> %s:%d: (%d)\n", __func__, __LINE__, cpu);
  70
  71                /*
  72                * Check assumptions on ps3_ipi_virqs[] indexing. If this
  73                * check fails, then a different mapping of PPC_MSG_
  74                * to index needs to be setup.
  75                */
  76
  77                BUILD_BUG_ON(PPC_MSG_CALL_FUNCTION    != 0);
  78                BUILD_BUG_ON(PPC_MSG_RESCHEDULE       != 1);
  79                BUILD_BUG_ON(PPC_MSG_CALL_FUNC_SINGLE != 2);
  80                BUILD_BUG_ON(PPC_MSG_DEBUGGER_BREAK   != 3);
  81
  82                for (i = 0; i < MSG_COUNT; i++) {
  83                        result = ps3_event_receive_port_setup(cpu, &virqs[i]);
  84
  85                        if (result)
  86                                continue;
  87
  88                        DBG("%s:%d: (%d, %d) => virq %u\n",
  89                                __func__, __LINE__, cpu, i, virqs[i]);
  90
  91                        result = smp_request_message_ipi(virqs[i], i);
  92
  93                        if (result)
  94                                virqs[i] = NO_IRQ;
  95                        else
  96                                ps3_register_ipi_irq(cpu, virqs[i]);
  97                }
  98
  99                ps3_register_ipi_debug_brk(cpu, virqs[PPC_MSG_DEBUGGER_BREAK]);
 100
 101                DBG(" <- %s:%d: (%d)\n", __func__, __LINE__, cpu);
 102        }
 103
 104        return 2;
 105}
 106
 107void ps3_smp_cleanup_cpu(int cpu)
 108{
 109        unsigned int *virqs = per_cpu(ps3_ipi_virqs, cpu);
 110        int i;
 111
 112        DBG(" -> %s:%d: (%d)\n", __func__, __LINE__, cpu);
 113
 114        for (i = 0; i < MSG_COUNT; i++) {
 115                /* Can't call free_irq from interrupt context. */
 116                ps3_event_receive_port_destroy(virqs[i]);
 117                virqs[i] = NO_IRQ;
 118        }
 119
 120        DBG(" <- %s:%d: (%d)\n", __func__, __LINE__, cpu);
 121}
 122
 123static struct smp_ops_t ps3_smp_ops = {
 124        .probe          = ps3_smp_probe,
 125        .message_pass   = ps3_smp_message_pass,
 126        .kick_cpu       = smp_generic_kick_cpu,
 127};
 128
 129void smp_init_ps3(void)
 130{
 131        DBG(" -> %s\n", __func__);
 132        smp_ops = &ps3_smp_ops;
 133        DBG(" <- %s\n", __func__);
 134}
 135