linux/arch/powerpc/include/asm/dbell.h
<<
>>
Prefs
   1/* SPDX-License-Identifier: GPL-2.0-or-later */
   2/*
   3 * Copyright 2009 Freescale Semiconductor, Inc.
   4 *
   5 * provides masks and opcode images for use by code generation, emulation
   6 * and for instructions that older assemblers might not know about
   7 */
   8#ifndef _ASM_POWERPC_DBELL_H
   9#define _ASM_POWERPC_DBELL_H
  10
  11#include <linux/smp.h>
  12#include <linux/threads.h>
  13
  14#include <asm/cputhreads.h>
  15#include <asm/ppc-opcode.h>
  16#include <asm/feature-fixups.h>
  17#include <asm/kvm_ppc.h>
  18
  19#define PPC_DBELL_MSG_BRDCAST   (0x04000000)
  20#define PPC_DBELL_TYPE(x)       (((x) & 0xf) << (63-36))
  21#define PPC_DBELL_TYPE_MASK     PPC_DBELL_TYPE(0xf)
  22#define PPC_DBELL_LPID(x)       ((x) << (63 - 49))
  23#define PPC_DBELL_PIR_MASK      0x3fff
  24enum ppc_dbell {
  25        PPC_DBELL = 0,          /* doorbell */
  26        PPC_DBELL_CRIT = 1,     /* critical doorbell */
  27        PPC_G_DBELL = 2,        /* guest doorbell */
  28        PPC_G_DBELL_CRIT = 3,   /* guest critical doorbell */
  29        PPC_G_DBELL_MC = 4,     /* guest mcheck doorbell */
  30        PPC_DBELL_SERVER = 5,   /* doorbell on server */
  31};
  32
  33#ifdef CONFIG_PPC_BOOK3S
  34
  35#define PPC_DBELL_MSGTYPE               PPC_DBELL_SERVER
  36
  37static inline void _ppc_msgsnd(u32 msg)
  38{
  39        __asm__ __volatile__ (ASM_FTR_IFSET(PPC_MSGSND(%1), PPC_MSGSNDP(%1), %0)
  40                                : : "i" (CPU_FTR_HVMODE), "r" (msg));
  41}
  42
  43/* sync before sending message */
  44static inline void ppc_msgsnd_sync(void)
  45{
  46        __asm__ __volatile__ ("sync" : : : "memory");
  47}
  48
  49/* sync after taking message interrupt */
  50static inline void ppc_msgsync(void)
  51{
  52        /* sync is not required when taking messages from the same core */
  53        __asm__ __volatile__ (ASM_FTR_IFSET(PPC_MSGSYNC " ; lwsync", "", %0)
  54                                : : "i" (CPU_FTR_HVMODE|CPU_FTR_ARCH_300));
  55}
  56
  57static inline void _ppc_msgclr(u32 msg)
  58{
  59        __asm__ __volatile__ (ASM_FTR_IFSET(PPC_MSGCLR(%1), PPC_MSGCLRP(%1), %0)
  60                                : : "i" (CPU_FTR_HVMODE), "r" (msg));
  61}
  62
  63static inline void ppc_msgclr(enum ppc_dbell type)
  64{
  65        u32 msg = PPC_DBELL_TYPE(type);
  66
  67        _ppc_msgclr(msg);
  68}
  69
  70#else /* CONFIG_PPC_BOOK3S */
  71
  72#define PPC_DBELL_MSGTYPE               PPC_DBELL
  73
  74static inline void _ppc_msgsnd(u32 msg)
  75{
  76        __asm__ __volatile__ (PPC_MSGSND(%0) : : "r" (msg));
  77}
  78
  79/* sync before sending message */
  80static inline void ppc_msgsnd_sync(void)
  81{
  82        __asm__ __volatile__ ("sync" : : : "memory");
  83}
  84
  85/* sync after taking message interrupt */
  86static inline void ppc_msgsync(void)
  87{
  88}
  89
  90#endif /* CONFIG_PPC_BOOK3S */
  91
  92extern void doorbell_exception(struct pt_regs *regs);
  93
  94static inline void ppc_msgsnd(enum ppc_dbell type, u32 flags, u32 tag)
  95{
  96        u32 msg = PPC_DBELL_TYPE(type) | (flags & PPC_DBELL_MSG_BRDCAST) |
  97                        (tag & 0x07ffffff);
  98
  99        _ppc_msgsnd(msg);
 100}
 101
 102#ifdef CONFIG_SMP
 103
 104/*
 105 * Doorbells must only be used if CPU_FTR_DBELL is available.
 106 * msgsnd is used in HV, and msgsndp is used in !HV.
 107 *
 108 * These should be used by platform code that is aware of restrictions.
 109 * Other arch code should use ->cause_ipi.
 110 *
 111 * doorbell_global_ipi() sends a dbell to any target CPU.
 112 * Must be used only by architectures that address msgsnd target
 113 * by PIR/get_hard_smp_processor_id.
 114 */
 115static inline void doorbell_global_ipi(int cpu)
 116{
 117        u32 tag = get_hard_smp_processor_id(cpu);
 118
 119        kvmppc_set_host_ipi(cpu);
 120        /* Order previous accesses vs. msgsnd, which is treated as a store */
 121        ppc_msgsnd_sync();
 122        ppc_msgsnd(PPC_DBELL_MSGTYPE, 0, tag);
 123}
 124
 125/*
 126 * doorbell_core_ipi() sends a dbell to a target CPU in the same core.
 127 * Must be used only by architectures that address msgsnd target
 128 * by TIR/cpu_thread_in_core.
 129 */
 130static inline void doorbell_core_ipi(int cpu)
 131{
 132        u32 tag = cpu_thread_in_core(cpu);
 133
 134        kvmppc_set_host_ipi(cpu);
 135        /* Order previous accesses vs. msgsnd, which is treated as a store */
 136        ppc_msgsnd_sync();
 137        ppc_msgsnd(PPC_DBELL_MSGTYPE, 0, tag);
 138}
 139
 140/*
 141 * Attempt to cause a core doorbell if destination is on the same core.
 142 * Returns 1 on success, 0 on failure.
 143 */
 144static inline int doorbell_try_core_ipi(int cpu)
 145{
 146        int this_cpu = get_cpu();
 147        int ret = 0;
 148
 149        if (cpumask_test_cpu(cpu, cpu_sibling_mask(this_cpu))) {
 150                doorbell_core_ipi(cpu);
 151                ret = 1;
 152        }
 153
 154        put_cpu();
 155
 156        return ret;
 157}
 158
 159#endif /* CONFIG_SMP */
 160
 161#endif /* _ASM_POWERPC_DBELL_H */
 162