From 56a1e8a1fe723d9c07f5c972d4b4b0a1f048e0cb Mon Sep 17 00:00:00 2001 From: Murali Nalajala Date: Fri, 20 Nov 2020 15:32:49 -0800 Subject: [PATCH] guestvm_loader: isolate cpus when VM is starting Do initial CPU reservation before starting VM, to avoid any resource contention, while booting guest VM. Remove the reservation after a configured timeout, which defaults to 8 seconds. Change-Id: Id49b07edd3e558dee074eafb729423ad8f8ff98d Signed-off-by: Murali Nalajala --- drivers/soc/qcom/guestvm_loader.c | 90 ++++++++++++++++++++++++++++++- 1 file changed, 89 insertions(+), 1 deletion(-) diff --git a/drivers/soc/qcom/guestvm_loader.c b/drivers/soc/qcom/guestvm_loader.c index 11255a005c84..91e8060256b9 100644 --- a/drivers/soc/qcom/guestvm_loader.c +++ b/drivers/soc/qcom/guestvm_loader.c @@ -11,12 +11,17 @@ #include #include #include +#include +#include +#include #include #include #include #define MAX_LEN 256 +#define DEFAULT_UNISO_TIMEOUT_MS 8000 +#define NUM_RESERVED_CPUS 2 const static struct { enum hh_vm_names val; @@ -41,6 +46,63 @@ struct guestvm_loader_private { u8 vm_status; }; +static struct timer_list guestvm_cpu_isolate_timer; +static struct completion isolation_done; +static struct work_struct unisolation_work; +static cpumask_t guestvm_isolated_cpus; +static cpumask_t guestvm_reserve_cpus; +static u32 guestvm_unisolate_timeout; + +static void guestvm_isolate_cpu(void) +{ + int cpu, ret; + + for_each_cpu_and(cpu, &guestvm_reserve_cpus, cpu_online_mask) { + ret = sched_isolate_cpu(cpu); + if (ret < 0) { + pr_err("fail to isolate CPU%d. ret=%d\n", cpu, ret); + continue; + } + cpumask_set_cpu(cpu, &guestvm_isolated_cpus); + } + + pr_info("%s: reserved_cpus=%*pbl isolated=%*pbl\n", __func__, + cpumask_pr_args(&guestvm_isolated_cpus), + cpumask_pr_args(cpu_isolated_mask)); +} + +static void guestvm_unisolate_cpu(void) +{ + int i, ret; + + for_each_cpu(i, &guestvm_isolated_cpus) { + ret = sched_unisolate_cpu(i); + if (ret < 0) { + pr_err("fail to un-isolate CPU%d. ret=%d\n", i, ret); + continue; + } + + cpumask_clear_cpu(i, &guestvm_isolated_cpus); + } + + pr_info("%s: isolated mask=%*pbl\n", __func__, + cpumask_pr_args(cpu_isolated_mask)); + del_timer(&guestvm_cpu_isolate_timer); +} + +static void guestvm_unisolate_work(struct work_struct *work) +{ + if (wait_for_completion_interruptible(&isolation_done)) + pr_err("%s: CPU unisolation is interrupted\n", __func__); + + guestvm_unisolate_cpu(); +} + +static void guestvm_timer_callback(struct timer_list *t) +{ + complete(&isolation_done); +} + static inline enum hh_vm_names get_hh_vm_name(const char *str) { int vmid; @@ -137,6 +199,11 @@ static ssize_t guestvm_loader_start(struct kobject *kobj, dev_err(priv->dev, "VM start completion interrupted\n"); priv->vm_status = HH_RM_VM_STATUS_RUNNING; + INIT_WORK(&unisolation_work, guestvm_unisolate_work); + schedule_work(&unisolation_work); + guestvm_isolate_cpu(); + mod_timer(&guestvm_cpu_isolate_timer, + jiffies + msecs_to_jiffies(guestvm_unisolate_timeout)); ret = hh_rm_vm_start(priv->vmid); if (ret) dev_err(priv->dev, "VM start failed for vmid = %d ret = %d\n", @@ -161,7 +228,8 @@ static int guestvm_loader_probe(struct platform_device *pdev) { struct guestvm_loader_private *priv = NULL; const char *sub_sys; - int ret = 0; + int ret = 0, i, reserve_cpus_len; + u32 reserve_cpus[NUM_RESERVED_CPUS] = {0}; priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); if (!priv) @@ -191,11 +259,31 @@ static int guestvm_loader_probe(struct platform_device *pdev) } init_completion(&priv->vm_start); + init_completion(&isolation_done); priv->guestvm_nb.notifier_call = guestvm_loader_nb_handler; ret = hh_rm_register_notifier(&priv->guestvm_nb); if (ret) return ret; + reserve_cpus_len = of_property_read_variable_u32_array( + pdev->dev.of_node, + "qcom,reserved-cpus", + reserve_cpus, 0, NUM_RESERVED_CPUS); + for (i = 0; i < reserve_cpus_len; i++) + if (reserve_cpus[i] < num_possible_cpus()) + cpumask_set_cpu(reserve_cpus[i], &guestvm_reserve_cpus); + + /* Default to (4,5) as reserve cpus */ + if (reserve_cpus_len <= 0) { + cpumask_set_cpu(4, &guestvm_reserve_cpus); + cpumask_set_cpu(5, &guestvm_reserve_cpus); + } + + ret = of_property_read_u32(pdev->dev.of_node, "qcom,unisolate-timeout-ms", + &guestvm_unisolate_timeout); + if (ret) + guestvm_unisolate_timeout = DEFAULT_UNISO_TIMEOUT_MS; + timer_setup(&guestvm_cpu_isolate_timer, guestvm_timer_callback, 0); priv->vm_status = HH_RM_VM_STATUS_NO_STATE; return 0;