From cfa1320d7f2f18068817b4b671c7ce29db736226 Mon Sep 17 00:00:00 2001 From: Murali Nalajala Date: Tue, 21 Apr 2020 22:30:42 -0700 Subject: [PATCH] soc: qcom: guestvm loader enhancements RM-VM(Resource Manager) send various vm status notifications(INIT/READY/ RUNNING etc) back to primary VM while PIL loader is loading the VM images. Listern to these notifications and make a call to get the hypervisor resources to configure doorbell and message queues. Change-Id: Ia378a1df82ef960e2c11bf715100e38de82b670c Signed-off-by: Murali Nalajala --- drivers/soc/qcom/guestvm_loader.c | 78 ++++++++++++++++++++++++------- drivers/virt/haven/hh_rm_core.c | 30 ++++-------- drivers/virt/haven/hh_rm_iface.c | 4 +- include/linux/haven/hh_rm_drv.h | 22 +++++++-- 4 files changed, 89 insertions(+), 45 deletions(-) diff --git a/drivers/soc/qcom/guestvm_loader.c b/drivers/soc/qcom/guestvm_loader.c index 201d0f33bec5..7eb0e0e10b47 100644 --- a/drivers/soc/qcom/guestvm_loader.c +++ b/drivers/soc/qcom/guestvm_loader.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include @@ -31,12 +30,13 @@ static struct kobj_type guestvm_kobj_type = { }; struct guestvm_loader_private { - struct work_struct vm_loader_work; + struct notifier_block guestvm_nb; struct kobject vm_loader_kobj; struct device *dev; char vm_name[MAX_LEN]; void *vm_loaded; int vmid; + u8 vm_status; }; static inline enum hh_vm_names get_hh_vm_name(const char *str) @@ -50,24 +50,50 @@ static inline enum hh_vm_names get_hh_vm_name(const char *str) return HH_VM_MAX; } -static void guestvm_loader_rm_notifier(struct work_struct *vm_loader_work) +static int guestvm_loader_nb_handler(struct notifier_block *this, + unsigned long cmd, void *data) { struct guestvm_loader_private *priv; - int ret = 0; + struct hh_rm_notif_vm_status_payload *vm_status_payload = data; + u8 vm_status = vm_status_payload->vm_status; + int ret; - priv = container_of(vm_loader_work, struct guestvm_loader_private, - vm_loader_work); - priv->vmid = hh_rm_vm_alloc_vmid(get_hh_vm_name(priv->vm_name)); - if (priv->vmid == HH_VM_MAX) { - dev_err(priv->dev, "Couldn't get vmid.\n"); - return; + priv = container_of(this, struct guestvm_loader_private, guestvm_nb); + + if (cmd != HH_RM_NOTIF_VM_STATUS) + return NOTIFY_DONE; + + if (priv->vmid != vm_status_payload->vmid) + dev_warn(priv->dev, "Expected a notification from vmid = %d, but received one from vmid = %d\n", + priv->vmid, vm_status_payload->vmid); + + /* + * Listen to STATUS_READY or STATUS_RUNNING notifications from RM. + * These notifications come from RM after PIL loading the VM images. + * Query GET_HYP_RESOURCES to populate other entities such as MessageQ + * and DBL. + */ + switch (vm_status) { + case HH_RM_VM_STATUS_READY: + priv->vm_status = HH_RM_VM_STATUS_READY; + ret = hh_rm_populate_hyp_res(vm_status_payload->vmid); + if (ret < 0) { + dev_err(priv->dev, "Failed to get hyp resources for vmid = %d ret = %d\n", + vm_status_payload->vmid, ret); + return NOTIFY_DONE; + } + break; + case HH_RM_VM_STATUS_RUNNING: + break; + default: + dev_err(priv->dev, "Unknown notification receieved for vmid = %d vm_status = %d\n", + vm_status_payload->vmid, vm_status); } - ret = hh_rm_vm_start(priv->vmid); - if (ret) - dev_err(priv->dev, "VM start has failed with %d.\n", ret); + + return NOTIFY_DONE; } -static ssize_t guestvm_load_start(struct kobject *kobj, +static ssize_t guestvm_loader_start(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) @@ -88,6 +114,13 @@ static ssize_t guestvm_load_start(struct kobject *kobj, } if (boot) { + priv->vm_status = HH_RM_VM_STATUS_INIT; + priv->vmid = hh_rm_vm_alloc_vmid(get_hh_vm_name(priv->vm_name)); + if (priv->vmid < 0) { + dev_err(priv->dev, "Couldn't allocate VMID.\n"); + return count; + } + priv->vm_loaded = subsystem_get(priv->vm_name); if (IS_ERR(priv->vm_loaded)) { ret = (int)(PTR_ERR(priv->vm_loaded)); @@ -96,13 +129,18 @@ static ssize_t guestvm_load_start(struct kobject *kobj, priv->vm_loaded = NULL; return ret; } - schedule_work(&priv->vm_loader_work); + + priv->vm_status = HH_RM_VM_STATUS_RUNNING; + ret = hh_rm_vm_start(priv->vmid); + if (ret) + dev_err(priv->dev, "VM start has failed for vmid = %d ret = %d\n", + priv->vmid, ret); } return count; } static struct kobj_attribute guestvm_loader_attribute = -__ATTR(boot_guestvm, 0220, NULL, guestvm_load_start); +__ATTR(boot_guestvm, 0220, NULL, guestvm_loader_start); static struct attribute *attrs[] = { &guestvm_loader_attribute.attr, @@ -132,8 +170,6 @@ static int guestvm_loader_probe(struct platform_device *pdev) return -EINVAL; strlcpy(priv->vm_name, sub_sys, sizeof(priv->vm_name)); - INIT_WORK(&priv->vm_loader_work, guestvm_loader_rm_notifier); - ret = kobject_init_and_add(&priv->vm_loader_kobj, &guestvm_kobj_type, kernel_kobj, "load_guestvm"); if (ret) { @@ -148,6 +184,12 @@ static int guestvm_loader_probe(struct platform_device *pdev) goto error_return; } + priv->guestvm_nb.notifier_call = guestvm_loader_nb_handler; + ret = hh_rm_register_notifier(&priv->guestvm_nb); + if (ret) + return ret; + + priv->vm_status = HH_RM_VM_STATUS_NO_STATE; return 0; error_return: diff --git a/drivers/virt/haven/hh_rm_core.c b/drivers/virt/haven/hh_rm_core.c index 501745b52c93..80252355bf8b 100644 --- a/drivers/virt/haven/hh_rm_core.c +++ b/drivers/virt/haven/hh_rm_core.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "hh_rm_drv_private.h" @@ -66,8 +67,6 @@ SRCU_NOTIFIER_HEAD_STATIC(hh_rm_notifier); static void hh_rm_get_svm_res_work_fn(struct work_struct *work); static DECLARE_WORK(hh_rm_get_svm_res_work, hh_rm_get_svm_res_work_fn); -static int hh_rm_populate_hyp_res(hh_vmid_t vmid); - static struct hh_rm_connection *hh_rm_alloc_connection(u32 msg_id) { struct hh_rm_connection *connection; @@ -124,21 +123,6 @@ int hh_rm_unregister_notifier(struct notifier_block *nb) } EXPORT_SYMBOL(hh_rm_unregister_notifier); -static int hh_rm_process_notif_vm_status(void *recv_buff, size_t recv_buff_size) -{ - struct hh_rm_notif_vm_status_payload *vm_status_payload; - - vm_status_payload = recv_buff + sizeof(struct hh_rm_rpc_hdr); - - /* The VM is now booting. Collect it's info and - * populate to other entities such as MessageQ and DBL - */ - if (vm_status_payload->vm_status == HH_RM_OS_STATUS_BOOT) - return hh_rm_populate_hyp_res(vm_status_payload->vmid); - - return 0; -} - static struct hh_rm_connection * hh_rm_wait_for_notif_fragments(void *recv_buff, size_t recv_buff_size) { @@ -214,8 +198,6 @@ static int hh_rm_process_notif(void *recv_buff, size_t recv_buff_size) ret = -EINVAL; goto err; } - - ret = hh_rm_process_notif_vm_status(recv_buff, recv_buff_size); break; case HH_RM_NOTIF_VM_IRQ_LENT: if (recv_buff_size != sizeof(*hdr) + @@ -698,7 +680,14 @@ err: return ret; } -static int hh_rm_populate_hyp_res(hh_vmid_t vmid) +/** + * hh_rm_populate_hyp_res: Query Resource Manager VM to get hyp resources. + * @vmid: The vmid of resources to be queried. + * + * The function encodes the error codes via ERR_PTR. Hence, the caller is + * responsible to check it with IS_ERR_OR_NULL(). + */ +int hh_rm_populate_hyp_res(hh_vmid_t vmid) { struct hh_vm_get_hyp_res_resp_entry *res_entries = NULL; int linux_irq, ret = 0; @@ -768,6 +757,7 @@ out: kfree(res_entries); return ret; } +EXPORT_SYMBOL(hh_rm_populate_hyp_res); static void hh_rm_get_svm_res_work_fn(struct work_struct *work) { diff --git a/drivers/virt/haven/hh_rm_iface.c b/drivers/virt/haven/hh_rm_iface.c index 5abfea564f50..bc95b508ee7c 100644 --- a/drivers/virt/haven/hh_rm_iface.c +++ b/drivers/virt/haven/hh_rm_iface.c @@ -506,13 +506,13 @@ int hh_rm_vm_start(int vmid) &resp_payload_size, &reply_err_code); if (reply_err_code || IS_ERR_OR_NULL(resp_payload)) { err = PTR_ERR(resp_payload); - pr_err("%s: VM_ALLOCATE failed with err: %d\n", + pr_err("%s: VM_START failed with err: %d\n", __func__, err); return err; } if (resp_payload_size != sizeof(*resp_payload)) { - pr_err("%s: Invalid size received for VM_IRQ_ACCEPT: %u\n", + pr_err("%s: Invalid size received for VM_START: %u\n", __func__, resp_payload_size); kfree(resp_payload); return -EINVAL; diff --git a/include/linux/haven/hh_rm_drv.h b/include/linux/haven/hh_rm_drv.h index 37386ca41ed2..d8ac6e00e60e 100644 --- a/include/linux/haven/hh_rm_drv.h +++ b/include/linux/haven/hh_rm_drv.h @@ -130,11 +130,14 @@ struct hh_notify_vmid_desc { #define HH_RM_NOTIF_VM_IRQ_RELEASED 0x56100012 #define HH_RM_VM_STATUS_NO_STATE 0 -#define HH_RM_VM_STATUS_RUNNING 1 -#define HH_RM_VM_STATUS_PAUSED 2 -#define HH_RM_VM_STATUS_SHUTDOWN 3 -#define HH_RM_VM_STATUS_SHUTOFF 4 -#define HH_RM_VM_STATUS_CRASHED 5 +#define HH_RM_VM_STATUS_INIT 1 +#define HH_RM_VM_STATUS_READY 2 +#define HH_RM_VM_STATUS_RUNNING 3 +#define HH_RM_VM_STATUS_PAUSED 4 +#define HH_RM_VM_STATUS_SHUTDOWN 5 +#define HH_RM_VM_STATUS_SHUTOFF 6 +#define HH_RM_VM_STATUS_CRASHED 7 +#define HH_RM_VM_STATUS_INIT_FAILED 8 #define HH_RM_OS_STATUS_NONE 0 #define HH_RM_OS_STATUS_EARLY_BOOT 1 @@ -190,6 +193,9 @@ int hh_rm_get_vmid(enum hh_vm_names vm_name, hh_vmid_t *vmid); int hh_rm_get_vm_name(hh_vmid_t vmid, enum hh_vm_names *vm_name); int hh_rm_vm_start(int vmid); +/* Client APIs for VM query */ +int hh_rm_populate_hyp_res(hh_vmid_t vmid); + /* Client APIs for VM Services */ int hh_rm_console_open(hh_vmid_t vmid); int hh_rm_console_close(hh_vmid_t vmid); @@ -273,6 +279,12 @@ static inline int hh_rm_vm_start(int vmid) return -EINVAL; } +/* Client APIs for VM query */ +static inline int hh_rm_populate_hyp_res(hh_vmid_t vmid) +{ + return -EINVAL; +} + /* Client APIs for VM Services */ static inline int hh_rm_console_open(hh_vmid_t vmid) {