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 <mnalajal@codeaurora.org>
This commit is contained in:
Murali Nalajala 2020-04-21 22:30:42 -07:00 • committed by Elliot Berman
commit cfa1320d7f
4 changed files with 90 additions and 46 deletions

View file

@ -10,7 +10,6 @@
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/haven/hh_common.h>
#include <linux/haven/hh_rm_drv.h>
#include <soc/qcom/subsystem_notif.h>
@ -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:

View file

@ -23,6 +23,7 @@
#include <linux/haven/hh_msgq.h>
#include <linux/haven/hh_errno.h>
#include <linux/haven/hh_common.h>
#include <linux/haven/hh_rm_drv.h>
#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)
{

View file

@ -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;

View file

@ -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)
{