From 93de2a6a4b91b72607136dd656edf03fb399d27f Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 23 Sep 2026 09:37:21 -0700 Subject: KVM: SEV: Do cache maintenance on the source VM during intra-host migration 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 Signed-off-by: Sean Christopherson Message-ID: <20260923163721.1584779-3-seanjc@google.com> Signed-off-by: Paolo Bonzini --- sound/soc/codecs/wcd-common.c | 144 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 sound/soc/codecs/wcd-common.c (limited to 'sound/soc/codecs/wcd-common.c') diff --git a/sound/soc/codecs/wcd-common.c b/sound/soc/codecs/wcd-common.c new file mode 100644 index 000000000..9016e9745 --- /dev/null +++ b/sound/soc/codecs/wcd-common.c @@ -0,0 +1,144 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (c) 2025, Qualcomm Technologies, Inc. and/or its subsidiaries. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wcd-common.h" + +#define WCD_MIN_MICBIAS_MV 1000 +#define WCD_DEF_MICBIAS_MV 1800 +#define WCD_MAX_MICBIAS_MV 2850 + +#define SWRS_SCP_HOST_CLK_DIV2_CTL_BANK(m) (0xE0 + 0x10 * (m)) + +int wcd_get_micb_vout_ctl_val(struct device *dev, u32 micb_mv) +{ + /* min micbias voltage is 1V and maximum is 2.85V */ + if (micb_mv < WCD_MIN_MICBIAS_MV || micb_mv > WCD_MAX_MICBIAS_MV) { + dev_err(dev, "Unsupported micbias voltage (%u mV)\n", micb_mv); + return -EINVAL; + } + + return (micb_mv - WCD_MIN_MICBIAS_MV) / 50; +} +EXPORT_SYMBOL_GPL(wcd_get_micb_vout_ctl_val); + +static int wcd_get_micbias_val(struct device *dev, int micb_num, u32 *micb_mv) +{ + char micbias[64]; + int mv; + + sprintf(micbias, "qcom,micbias%d-microvolt", micb_num); + + if (of_property_read_u32(dev->of_node, micbias, &mv)) { + dev_err(dev, "%s value not found, using default\n", micbias); + mv = WCD_DEF_MICBIAS_MV; + } else { + /* convert it to milli volts */ + mv = mv/1000; + } + if (micb_mv) + *micb_mv = mv; + + mv = wcd_get_micb_vout_ctl_val(dev, mv); + if (mv < 0) { + dev_err(dev, "Unsupported %s voltage (%d mV), falling back to default (%d mV)\n", + micbias, mv, WCD_DEF_MICBIAS_MV); + return wcd_get_micb_vout_ctl_val(dev, WCD_DEF_MICBIAS_MV); + } + + return mv; +} + +int wcd_dt_parse_micbias_info(struct wcd_common *common) +{ + int ret, i; + + for (i = 0; i < common->max_bias; i++) { + ret = wcd_get_micbias_val(common->dev, i + 1, &common->micb_mv[i]); + if (ret < 0) + return ret; + common->micb_vout[i] = ret; + } + + return 0; +} +EXPORT_SYMBOL_GPL(wcd_dt_parse_micbias_info); + +static int wcd_sdw_component_bind(struct device *dev, struct device *master, void *data) +{ + pm_runtime_set_autosuspend_delay(dev, 3000); + pm_runtime_use_autosuspend(dev); + pm_runtime_mark_last_busy(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + + return 0; +} + +static void wcd_sdw_component_unbind(struct device *dev, struct device *master, void *data) +{ + pm_runtime_disable(dev); + pm_runtime_set_suspended(dev); + pm_runtime_dont_use_autosuspend(dev); +} + +const struct component_ops wcd_sdw_component_ops = { + .bind = wcd_sdw_component_bind, + .unbind = wcd_sdw_component_unbind, +}; +EXPORT_SYMBOL_GPL(wcd_sdw_component_ops); + +int wcd_update_status(struct sdw_slave *slave, enum sdw_slave_status status) +{ + struct regmap *regmap = dev_get_regmap(&slave->dev, NULL); + + if (regmap && status == SDW_SLAVE_ATTACHED) { + /* Write out any cached changes that happened between probe and attach */ + regcache_cache_only(regmap, false); + return regcache_sync(regmap); + } + + return 0; +} +EXPORT_SYMBOL_GPL(wcd_update_status); + +int wcd_bus_config(struct sdw_slave *slave, struct sdw_bus_params *params) +{ + sdw_write(slave, SWRS_SCP_HOST_CLK_DIV2_CTL_BANK(params->next_bank), 0x01); + + return 0; +} +EXPORT_SYMBOL_GPL(wcd_bus_config); + +int wcd_interrupt_callback(struct sdw_slave *slave, struct irq_domain *slave_irq, + unsigned int wcd_intr_status0, unsigned int wcd_intr_status1, + unsigned int wcd_intr_status2) +{ + struct regmap *regmap = dev_get_regmap(&slave->dev, NULL); + u32 sts1, sts2, sts3; + + do { + handle_nested_irq(irq_find_mapping(slave_irq, 0)); + regmap_read(regmap, wcd_intr_status0, &sts1); + regmap_read(regmap, wcd_intr_status1, &sts2); + regmap_read(regmap, wcd_intr_status2, &sts3); + + } while (sts1 || sts2 || sts3); + + return IRQ_HANDLED; +} +EXPORT_SYMBOL_GPL(wcd_interrupt_callback); + +MODULE_DESCRIPTION("Common Qualcomm WCD Codec helpers driver"); +MODULE_LICENSE("GPL"); -- cgit v1.3.1