Commit 107c5500 authored by Nicholas Piggin's avatar Nicholas Piggin Committed by Michael Ellerman

powerpc/pseries: Add KVM guest doorbell restrictions

KVM guests have certain restrictions and performance quirks when using
doorbells. This patch moves the EPAPR KVM guest test so it can be shared
with PSERIES, and uses that in doorbell setup code to apply the KVM
guest quirks and  improves IPI performance for two cases:

 - PowerVM guests may now use doorbells even if they are secure.

 - KVM guests no longer use doorbells if XIVE is available.

There is a valid complaint that "KVM guest" is not a very reasonable
thing to test for, it's preferable for the hypervisor to advertise
particular behaviours to the guest so they could change if the
hypervisor implementation or configuration changes. However in this case
we were already assuming a KVM guest worst case, so this patch is about
containing those quirks. If KVM later advertises fast doorbells, we
should test for that and override the quirks.
Signed-off-by: default avatarNicholas Piggin <npiggin@gmail.com>
Tested-by: default avatarCédric Le Goater <clg@kaod.org>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/20200726035155.1424103-4-npiggin@gmail.com
parent 5b06d167
...@@ -132,6 +132,12 @@ extern int ibm_nmi_interlock_token; ...@@ -132,6 +132,12 @@ extern int ibm_nmi_interlock_token;
extern unsigned int __start___fw_ftr_fixup, __stop___fw_ftr_fixup; extern unsigned int __start___fw_ftr_fixup, __stop___fw_ftr_fixup;
#if defined(CONFIG_PPC_PSERIES) || defined(CONFIG_KVM_GUEST)
bool is_kvm_guest(void);
#else
static inline bool is_kvm_guest(void) { return false; }
#endif
#ifdef CONFIG_PPC_PSERIES #ifdef CONFIG_PPC_PSERIES
void pseries_probe_fw_features(void); void pseries_probe_fw_features(void);
#else #else
......
...@@ -8,35 +8,15 @@ ...@@ -8,35 +8,15 @@
#ifndef __POWERPC_KVM_PARA_H__ #ifndef __POWERPC_KVM_PARA_H__
#define __POWERPC_KVM_PARA_H__ #define __POWERPC_KVM_PARA_H__
#include <uapi/asm/kvm_para.h> #include <asm/firmware.h>
#ifdef CONFIG_KVM_GUEST
#include <linux/of.h>
static inline int kvm_para_available(void)
{
struct device_node *hyper_node;
hyper_node = of_find_node_by_path("/hypervisor");
if (!hyper_node)
return 0;
if (!of_device_is_compatible(hyper_node, "linux,kvm")) #include <uapi/asm/kvm_para.h>
return 0;
return 1;
}
#else
static inline int kvm_para_available(void) static inline int kvm_para_available(void)
{ {
return 0; return IS_ENABLED(CONFIG_KVM_GUEST) && is_kvm_guest();
} }
#endif
static inline unsigned int kvm_arch_para_features(void) static inline unsigned int kvm_arch_para_features(void)
{ {
unsigned long r; unsigned long r;
......
...@@ -45,11 +45,10 @@ obj-y := cputable.o syscalls.o \ ...@@ -45,11 +45,10 @@ obj-y := cputable.o syscalls.o \
signal.o sysfs.o cacheinfo.o time.o \ signal.o sysfs.o cacheinfo.o time.o \
prom.o traps.o setup-common.o \ prom.o traps.o setup-common.o \
udbg.o misc.o io.o misc_$(BITS).o \ udbg.o misc.o io.o misc_$(BITS).o \
of_platform.o prom_parse.o of_platform.o prom_parse.o firmware.o
obj-y += ptrace/ obj-y += ptrace/
obj-$(CONFIG_PPC64) += setup_64.o \ obj-$(CONFIG_PPC64) += setup_64.o \
paca.o nvram_64.o firmware.o note.o \ paca.o nvram_64.o note.o syscall_64.o
syscall_64.o
obj-$(CONFIG_COMPAT) += sys_ppc32.o signal_32.o obj-$(CONFIG_COMPAT) += sys_ppc32.o signal_32.o
obj-$(CONFIG_VDSO32) += vdso32/ obj-$(CONFIG_VDSO32) += vdso32/
obj-$(CONFIG_PPC_WATCHDOG) += watchdog.o obj-$(CONFIG_PPC_WATCHDOG) += watchdog.o
......
...@@ -11,8 +11,27 @@ ...@@ -11,8 +11,27 @@
#include <linux/export.h> #include <linux/export.h>
#include <linux/cache.h> #include <linux/cache.h>
#include <linux/of.h>
#include <asm/firmware.h> #include <asm/firmware.h>
#ifdef CONFIG_PPC64
unsigned long powerpc_firmware_features __read_mostly; unsigned long powerpc_firmware_features __read_mostly;
EXPORT_SYMBOL_GPL(powerpc_firmware_features); EXPORT_SYMBOL_GPL(powerpc_firmware_features);
#endif
#if defined(CONFIG_PPC_PSERIES) || defined(CONFIG_KVM_GUEST)
bool is_kvm_guest(void)
{
struct device_node *hyper_node;
hyper_node = of_find_node_by_path("/hypervisor");
if (!hyper_node)
return 0;
if (!of_device_is_compatible(hyper_node, "linux,kvm"))
return 0;
return 1;
}
#endif
...@@ -210,24 +210,32 @@ static __init void pSeries_smp_probe(void) ...@@ -210,24 +210,32 @@ static __init void pSeries_smp_probe(void)
if (!cpu_has_feature(CPU_FTR_SMT)) if (!cpu_has_feature(CPU_FTR_SMT))
return; return;
if (is_kvm_guest()) {
/* /*
* KVM emulates doorbells by disabling FSCR[MSGP] so msgsndp faults * KVM emulates doorbells by disabling FSCR[MSGP] so msgsndp
* to the hypervisor which then reads the instruction from guest * faults to the hypervisor which then reads the instruction
* memory. This can't be done if the guest is secure, so don't use * from guest memory, which tends to be slower than using XIVE.
* doorbells in secure guests. */
* if (xive_enabled())
* Under PowerVM, FSCR[MSGP] is enabled so doorbells could be used return;
* by secure guests if we distinguished this from KVM.
/*
* XICS hcalls aren't as fast, so we can use msgsndp (which
* also helps exercise KVM emulation), however KVM can't
* emulate secure guests because it can't read the instruction
* out of their memory.
*/ */
if (is_secure_guest()) if (is_secure_guest())
return; return;
}
/* /*
* The guest can use doobells for SMT sibling IPIs, which stay in * Under PowerVM, FSCR[MSGP] is enabled as guest vCPU siblings are
* the core rather than going to the interrupt controller. This * gang scheduled on the same physical core, so doorbells are always
* tends to be slower under KVM where doorbells are emulated, but * faster than the interrupt controller, and they can be used by
* faster for PowerVM where they're enabled. * secure guests.
*/ */
ic_cause_ipi = smp_ops->cause_ipi; ic_cause_ipi = smp_ops->cause_ipi;
smp_ops->cause_ipi = dbell_or_ic_cause_ipi; smp_ops->cause_ipi = dbell_or_ic_cause_ipi;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment