linux/arch/powerpc/platforms/ps3/smp.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 *  PS3 SMP routines.
   4 *
   5 *  Copyright (C) 2006 Sony Computer Entertainment Inc.
   6 *  Copyright 2006 Sony Corp.
   7 */
   8
   9#include <linux/kernel.h>
  10#include <linux/smp.h>
  11
  12#include <asm/machdep.h>
  13#include <asm/udbg.h>
  14
  15#include "platform.h"
  16
  17#if defined(DEBUG)
  18#define DBG udbg_printf
  19#else
  20#define DBG pr_debug
  21#endif
  22
  23/**
  24  * ps3_ipi_virqs - a per cpu array of virqs for ipi use
  25  */
  26
  27#define MSG_COUNT 4
  28static DEFINE_PER_CPU(unsigned int [MSG_COUNT], ps3_ipi_virqs);
  29
  30static void ps3_smp_message_pass(int cpu, int msg)
  31{
  32        int result;
  33        unsigned int virq;
  34
  35        if (msg >= MSG_COUNT) {
  36                DBG("%s:%d: bad msg: %d\n", __func__, __LINE__, msg);
  37                return;
  38        }
  39
  40        virq = per_cpu(ps3_ipi_virqs, cpu)[msg];
  41        result = ps3_send_event_locally(virq);
  42
  43        if (result)
  44                DBG("%s:%d: ps3_send_event_locally(%d, %d) failed"
  45                        " (%d)\n", __func__, __LINE__, cpu, msg, result);
  46}
  47
  48static void __init ps3_smp_probe(void)
  49{
  50        int cpu;
  51
  52        for (cpu = 0; cpu < 2; cpu++) {
  53                int result;
  54                unsigned int *virqs = per_cpu(ps3_ipi_virqs, cpu);
  55                int i;
  56
  57                DBG(" -> %s:%d: (%d)\n", __func__, __LINE__, cpu);
  58
  59                /*
  60                * Check assumptions on ps3_ipi_virqs[] indexing. If this
  61                * check fails, then a different mapping of PPC_MSG_
  62                * to index needs to be setup.
  63                */
  64
  65                BUILD_BUG_ON(PPC_MSG_CALL_FUNCTION    != 0);
  66                BUILD_BUG_ON(PPC_MSG_RESCHEDULE       != 1);
  67                BUILD_BUG_ON(PPC_MSG_TICK_BROADCAST   != 2);
  68                BUILD_BUG_ON(PPC_MSG_NMI_IPI          != 3);
  69
  70                for (i = 0; i < MSG_COUNT; i++) {
  71                        result = ps3_event_receive_port_setup(cpu, &virqs[i]);
  72
  73                        if (result)
  74                                continue;
  75
  76                        DBG("%s:%d: (%d, %d) => virq %u\n",
  77                                __func__, __LINE__, cpu, i, virqs[i]);
  78
  79                        result = smp_request_message_ipi(virqs[i], i);
  80
  81                        if (result)
  82                                virqs[i] = 0;
  83                        else
  84                                ps3_register_ipi_irq(cpu, virqs[i]);
  85                }
  86
  87                ps3_register_ipi_debug_brk(cpu, virqs[PPC_MSG_NMI_IPI]);
  88
  89                DBG(" <- %s:%d: (%d)\n", __func__, __LINE__, cpu);
  90        }
  91}
  92
  93void ps3_smp_cleanup_cpu(int cpu)
  94{
  95        unsigned int *virqs = per_cpu(ps3_ipi_virqs, cpu);
  96        int i;
  97
  98        DBG(" -> %s:%d: (%d)\n", __func__, __LINE__, cpu);
  99
 100        for (i = 0; i < MSG_COUNT; i++) {
 101                /* Can't call free_irq from interrupt context. */
 102                ps3_event_receive_port_destroy(virqs[i]);
 103                virqs[i] = 0;
 104        }
 105
 106        DBG(" <- %s:%d: (%d)\n", __func__, __LINE__, cpu);
 107}
 108
 109static struct smp_ops_t ps3_smp_ops = {
 110        .probe          = ps3_smp_probe,
 111        .message_pass   = ps3_smp_message_pass,
 112        .kick_cpu       = smp_generic_kick_cpu,
 113};
 114
 115void smp_init_ps3(void)
 116{
 117        DBG(" -> %s\n", __func__);
 118        smp_ops = &ps3_smp_ops;
 119        DBG(" <- %s\n", __func__);
 120}
 121