summaryrefslogtreecommitdiffstats
path: root/arch/mips/sgi-ip27/ip27-timer.c
diff options
context:
space:
mode:
authorSean Christopherson <seanjc@google.com>2026-09-23 09:37:21 -0700
committerPaolo Bonzini <pbonzini@redhat.com>2026-09-26 00:39:55 -0400
commit93de2a6a4b91b72607136dd656edf03fb399d27f (patch)
tree9220c76eb23cb39a146fac9692ee69afa4aa3135 /arch/mips/sgi-ip27/ip27-timer.c
downloadlinux-stable-93de2a6a4b91b72607136dd656edf03fb399d27f.tar.gz
linux-stable-93de2a6a4b91b72607136dd656edf03fb399d27f.zip
KVM: SEV: Do cache maintenance on the source VM during intra-host migrationgrafted
Manually perform cache maintenance on the source VM during intra-host migration to ensure no stale data is left in CPU caches after the VM is destroyed. Because the source VM is "converted" to a non-SEV VM, KVM's memory reclaim flows won't trigger cache maintenance, e.g. when all guest memory is reclaimed in response to detaching from the mmu_notifier. Note, relying on the destination VM to do cache maintenance isn't an option as KVM doesn't require identical guest memory configurations, i.e. the source VM may have access to memory that the destination VM does not. Enforcing equivalent memory configurations is infeasible, as it would require a *deep* comparison of memslots, e.g. to verify that not only are the memslot identical, but what the memslots point at is also identical. Fixes: b56639318bb2 ("KVM: SEV: Add support for SEV intra host migration") Cc: stable@vger.kernel.org Reported-by: Stefan Teodorescu <fane@google.com> Signed-off-by: Sean Christopherson <seanjc@google.com> Message-ID: <20260923163721.1584779-3-seanjc@google.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'arch/mips/sgi-ip27/ip27-timer.c')
-rw-r--r--arch/mips/sgi-ip27/ip27-timer.c154
1 files changed, 154 insertions, 0 deletions
diff --git a/arch/mips/sgi-ip27/ip27-timer.c b/arch/mips/sgi-ip27/ip27-timer.c
new file mode 100644
index 000000000..5f4da05cb
--- /dev/null
+++ b/arch/mips/sgi-ip27/ip27-timer.c
@@ -0,0 +1,154 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 1999, 2000, 05, 06 Ralf Baechle (ralf@linux-mips.org)
+ * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
+ */
+#include <linux/bcd.h>
+#include <linux/clockchips.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/sched_clock.h>
+#include <linux/interrupt.h>
+#include <linux/kernel_stat.h>
+#include <linux/param.h>
+#include <linux/smp.h>
+#include <linux/time.h>
+#include <linux/timex.h>
+#include <linux/mm.h>
+#include <linux/platform_device.h>
+
+#include <asm/time.h>
+#include <asm/sgialib.h>
+#include <asm/sn/klconfig.h>
+#include <asm/sn/arch.h>
+#include <asm/sn/addrs.h>
+#include <asm/sn/agent.h>
+
+#include "ip27-common.h"
+
+static int rt_next_event(unsigned long delta, struct clock_event_device *evt)
+{
+ unsigned int cpu = smp_processor_id();
+ int slice = cputoslice(cpu);
+ unsigned long cnt;
+
+ cnt = LOCAL_HUB_L(PI_RT_COUNT);
+ cnt += delta;
+ LOCAL_HUB_S(PI_RT_COMPARE_A + PI_COUNT_OFFSET * slice, cnt);
+
+ return LOCAL_HUB_L(PI_RT_COUNT) >= cnt ? -ETIME : 0;
+}
+
+static DEFINE_PER_CPU(struct clock_event_device, hub_rt_clockevent);
+static DEFINE_PER_CPU(char [11], hub_rt_name);
+
+static irqreturn_t hub_rt_counter_handler(int irq, void *dev_id)
+{
+ unsigned int cpu = smp_processor_id();
+ struct clock_event_device *cd = &per_cpu(hub_rt_clockevent, cpu);
+ int slice = cputoslice(cpu);
+
+ /*
+ * Ack
+ */
+ LOCAL_HUB_S(PI_RT_PEND_A + PI_COUNT_OFFSET * slice, 0);
+ cd->event_handler(cd);
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * This is a hack; we really need to figure these values out dynamically
+ *
+ * Since 800 ns works very well with various HUB frequencies, such as
+ * 360, 380, 390 and 400 MHZ, we use 800 ns rtc cycle time.
+ *
+ * Ralf: which clock rate is used to feed the counter?
+ */
+#define NSEC_PER_CYCLE 800
+#define CYCLES_PER_SEC (NSEC_PER_SEC / NSEC_PER_CYCLE)
+
+void hub_rt_clock_event_init(void)
+{
+ unsigned int cpu = smp_processor_id();
+ struct clock_event_device *cd = &per_cpu(hub_rt_clockevent, cpu);
+ unsigned char *name = per_cpu(hub_rt_name, cpu);
+
+ sprintf(name, "hub-rt %d", cpu);
+ cd->name = name;
+ cd->features = CLOCK_EVT_FEAT_ONESHOT;
+ clockevent_set_clock(cd, CYCLES_PER_SEC);
+ cd->max_delta_ns = clockevent_delta2ns(0xfffffffffffff, cd);
+ cd->max_delta_ticks = 0xfffffffffffff;
+ cd->min_delta_ns = clockevent_delta2ns(0x300, cd);
+ cd->min_delta_ticks = 0x300;
+ cd->rating = 200;
+ cd->irq = IP27_RT_TIMER_IRQ;
+ cd->cpumask = cpumask_of(cpu);
+ cd->set_next_event = rt_next_event;
+ clockevents_register_device(cd);
+
+ enable_percpu_irq(IP27_RT_TIMER_IRQ, IRQ_TYPE_NONE);
+}
+
+static void __init hub_rt_clock_event_global_init(void)
+{
+ irq_set_handler(IP27_RT_TIMER_IRQ, handle_percpu_devid_irq);
+ irq_set_percpu_devid(IP27_RT_TIMER_IRQ);
+ WARN_ON(request_percpu_irq(IP27_RT_TIMER_IRQ, hub_rt_counter_handler,
+ "hub-rt", &hub_rt_clockevent));
+}
+
+static u64 hub_rt_read(struct clocksource *cs)
+{
+ return REMOTE_HUB_L(cputonasid(0), PI_RT_COUNT);
+}
+
+struct clocksource hub_rt_clocksource = {
+ .name = "HUB-RT",
+ .rating = 200,
+ .read = hub_rt_read,
+ .mask = CLOCKSOURCE_MASK(52),
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+static u64 notrace hub_rt_read_sched_clock(void)
+{
+ return REMOTE_HUB_L(cputonasid(0), PI_RT_COUNT);
+}
+
+static void __init hub_rt_clocksource_init(void)
+{
+ struct clocksource *cs = &hub_rt_clocksource;
+
+ clocksource_register_hz(cs, CYCLES_PER_SEC);
+
+ sched_clock_register(hub_rt_read_sched_clock, 52, CYCLES_PER_SEC);
+}
+
+void __init plat_time_init(void)
+{
+ hub_rt_clocksource_init();
+ hub_rt_clock_event_global_init();
+ hub_rt_clock_event_init();
+}
+
+void hub_rtc_init(nasid_t nasid)
+{
+
+ /*
+ * We only need to initialize the current node.
+ * If this is not the current node then it is a cpuless
+ * node and timeouts will not happen there.
+ */
+ if (get_nasid() == nasid) {
+ LOCAL_HUB_S(PI_RT_EN_A, 1);
+ LOCAL_HUB_S(PI_RT_EN_B, 1);
+ LOCAL_HUB_S(PI_PROF_EN_A, 0);
+ LOCAL_HUB_S(PI_PROF_EN_B, 0);
+ LOCAL_HUB_S(PI_RT_COUNT, 0);
+ LOCAL_HUB_S(PI_RT_PEND_A, 0);
+ LOCAL_HUB_S(PI_RT_PEND_B, 0);
+ }
+}