summaryrefslogtreecommitdiffstats
path: root/sound/drivers/pcsp/pcsp.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 /sound/drivers/pcsp/pcsp.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 'sound/drivers/pcsp/pcsp.c')
-rw-r--r--sound/drivers/pcsp/pcsp.c216
1 files changed, 216 insertions, 0 deletions
diff --git a/sound/drivers/pcsp/pcsp.c b/sound/drivers/pcsp/pcsp.c
new file mode 100644
index 000000000..ff6bb375c
--- /dev/null
+++ b/sound/drivers/pcsp/pcsp.c
@@ -0,0 +1,216 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * PC-Speaker driver for Linux
+ *
+ * Copyright (C) 1997-2001 David Woodhouse
+ * Copyright (C) 2001-2008 Stas Sergeev
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <linux/input.h>
+#include <linux/delay.h>
+#include <linux/bitops.h>
+#include <linux/mm.h>
+#include "pcsp_input.h"
+#include "pcsp.h"
+
+MODULE_AUTHOR("Stas Sergeev <stsp@users.sourceforge.net>");
+MODULE_DESCRIPTION("PC-Speaker driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pcspkr");
+
+static int index = SNDRV_DEFAULT_IDX1; /* Index 0-MAX */
+static char *id = SNDRV_DEFAULT_STR1; /* ID for this card */
+static bool enable = SNDRV_DEFAULT_ENABLE1; /* Enable this card */
+static bool nopcm; /* Disable PCM capability of the driver */
+
+module_param(index, int, 0444);
+MODULE_PARM_DESC(index, "Index value for pcsp soundcard.");
+module_param(id, charp, 0444);
+MODULE_PARM_DESC(id, "ID string for pcsp soundcard.");
+module_param(enable, bool, 0444);
+MODULE_PARM_DESC(enable, "Enable PC-Speaker sound.");
+module_param(nopcm, bool, 0444);
+MODULE_PARM_DESC(nopcm, "Disable PC-Speaker PCM sound. Only beeps remain.");
+
+struct snd_pcsp pcsp_chip;
+
+static int snd_pcsp_create(struct snd_card *card)
+{
+ unsigned int resolution = hrtimer_resolution;
+ int div, min_div, order;
+
+ if (!nopcm) {
+ if (resolution > PCSP_MAX_PERIOD_NS) {
+ dev_err(card->dev,
+ "PCSP: Timer resolution is not sufficient (%unS)\n",
+ resolution);
+ dev_err(card->dev,
+ "PCSP: Make sure you have HPET and ACPI enabled.\n");
+ dev_err(card->dev, "PCSP: Turned into nopcm mode.\n");
+ nopcm = 1;
+ }
+ }
+
+ if (loops_per_jiffy >= PCSP_MIN_LPJ && resolution <= PCSP_MIN_PERIOD_NS)
+ min_div = MIN_DIV;
+ else
+ min_div = MAX_DIV;
+#if PCSP_DEBUG
+ dev_dbg(card->dev, "PCSP: lpj=%li, min_div=%i, res=%u\n",
+ loops_per_jiffy, min_div, resolution);
+#endif
+
+ div = MAX_DIV / min_div;
+ order = fls(div) - 1;
+
+ pcsp_chip.max_treble = min(order, PCSP_MAX_TREBLE);
+ pcsp_chip.treble = min(pcsp_chip.max_treble, PCSP_DEFAULT_TREBLE);
+ pcsp_chip.playback_ptr = 0;
+ pcsp_chip.period_ptr = 0;
+ atomic_set(&pcsp_chip.timer_active, 0);
+ pcsp_chip.enable = 1;
+ pcsp_chip.pcspkr = 1;
+
+ spin_lock_init(&pcsp_chip.substream_lock);
+
+ pcsp_chip.card = card;
+ pcsp_chip.port = 0x61;
+ pcsp_chip.irq = -1;
+ pcsp_chip.dma = -1;
+ card->private_data = &pcsp_chip;
+
+ return 0;
+}
+
+static void pcsp_stop_beep(struct snd_pcsp *chip);
+
+static void alsa_card_pcsp_free(struct snd_card *card)
+{
+ pcsp_stop_beep(card->private_data);
+}
+
+static int snd_card_pcsp_probe(int devnum, struct device *dev)
+{
+ struct snd_card *card;
+ int err;
+
+ if (devnum != 0)
+ return -EINVAL;
+
+ hrtimer_setup(&pcsp_chip.timer, pcsp_do_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+
+ err = snd_devm_card_new(dev, index, id, THIS_MODULE, 0, &card);
+ if (err < 0)
+ return err;
+
+ err = snd_pcsp_create(card);
+ if (err < 0)
+ return err;
+
+ if (!nopcm) {
+ err = snd_pcsp_new_pcm(&pcsp_chip);
+ if (err < 0)
+ return err;
+ }
+ err = snd_pcsp_new_mixer(&pcsp_chip, nopcm);
+ if (err < 0)
+ return err;
+
+ strscpy(card->driver, "PC-Speaker");
+ strscpy(card->shortname, "pcsp");
+ sprintf(card->longname, "Internal PC-Speaker at port 0x%x",
+ pcsp_chip.port);
+
+ err = snd_card_register(card);
+ if (err < 0)
+ return err;
+ card->private_free = alsa_card_pcsp_free;
+
+ return 0;
+}
+
+static int alsa_card_pcsp_init(struct device *dev)
+{
+ int err;
+
+ err = snd_card_pcsp_probe(0, dev);
+ if (err) {
+ dev_err(dev, "PC-Speaker initialization failed.\n");
+ return err;
+ }
+
+ /* Well, CONFIG_DEBUG_PAGEALLOC makes the sound horrible. Lets alert */
+ if (debug_pagealloc_enabled()) {
+ dev_warn(dev,
+ "PCSP: CONFIG_DEBUG_PAGEALLOC is enabled, which may make the sound noisy.\n");
+ }
+
+ return 0;
+}
+
+static int pcsp_probe(struct platform_device *dev)
+{
+ int err;
+
+ err = pcspkr_input_init(&pcsp_chip.input_dev, &dev->dev);
+ if (err < 0)
+ return err;
+
+ err = alsa_card_pcsp_init(&dev->dev);
+ if (err < 0)
+ return err;
+
+ platform_set_drvdata(dev, &pcsp_chip);
+ return 0;
+}
+
+static void pcsp_stop_beep(struct snd_pcsp *chip)
+{
+ pcsp_sync_stop(chip);
+ pcspkr_stop_sound();
+}
+
+static int pcsp_suspend(struct device *dev)
+{
+ struct snd_pcsp *chip = dev_get_drvdata(dev);
+ pcsp_stop_beep(chip);
+ return 0;
+}
+
+static DEFINE_SIMPLE_DEV_PM_OPS(pcsp_pm, pcsp_suspend, NULL);
+
+static void pcsp_shutdown(struct platform_device *dev)
+{
+ struct snd_pcsp *chip = platform_get_drvdata(dev);
+ pcsp_stop_beep(chip);
+}
+
+static struct platform_driver pcsp_platform_driver = {
+ .driver = {
+ .name = "pcspkr",
+ .pm = &pcsp_pm,
+ },
+ .probe = pcsp_probe,
+ .shutdown = pcsp_shutdown,
+};
+
+static int __init pcsp_init(void)
+{
+ if (!enable)
+ return -ENODEV;
+ return platform_driver_register(&pcsp_platform_driver);
+}
+
+static void __exit pcsp_exit(void)
+{
+ platform_driver_unregister(&pcsp_platform_driver);
+}
+
+module_init(pcsp_init);
+module_exit(pcsp_exit);