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 void __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_TICK_BROADCAST   != 2);
  80                BUILD_BUG_ON(PPC_MSG_NMI_IPI          != 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] = 0;
  95                        else
  96                                ps3_register_ipi_irq(cpu, virqs[i]);
  97                }
  98
  99                ps3_register_ipi_debug_brk(cpu, virqs[PPC_MSG_NMI_IPI]);
 100
 101                DBG(" <- %s:%d: (%d)\n", __func__, __LINE__, cpu);
 102        }
 103}
 104
 105void ps3_smp_cleanup_cpu(int cpu)
 106{
 107        unsigned int *virqs = per_cpu(ps3_ipi_virqs, cpu);
 108        int i;
 109
 110        DBG(" -> %s:%d: (%d)\n", __func__, __LINE__, cpu);
 111
 112        for (i = 0; i < MSG_COUNT; i++) {
 113                /* Can't call free_irq from interrupt context. */
 114                ps3_event_receive_port_destroy(virqs[i]);
 115                virqs[i] = 0;
 116        }
 117
 118        DBG(" <- %s:%d: (%d)\n", __func__, __LINE__, cpu);
 119}
 120
 121static struct smp_ops_t ps3_smp_ops = {
 122        .probe          = ps3_smp_probe,
 123        .message_pass   = ps3_smp_message_pass,
 124        .kick_cpu       = smp_generic_kick_cpu,
 125};
 126
 127void smp_init_ps3(void)
 128{
 129        DBG(" -> %s\n", __func__);
 130        smp_ops = &ps3_smp_ops;
 131        DBG(" <- %s\n", __func__);
 132}
 133