ANDROID: gunyah: qtvm: Add status notifier chain for QTVMs
QTVMs' Gunyah resources are handled partially by the VMM. The remaining resources are handled by the kernel clients. By providing this notifier, we allow the client drivers to add their operations for setting up the resources they own. Bug: 399219478 Change-Id: I2a5377358aa669dcebd6307ba5bc78ac117886f0 Signed-off-by: Prakruthi Deepak Heragu <quic_pheragu@quicinc.com>
This commit is contained in:
committed by
Todd Kjos
parent
ca44b02c02
commit
b582c89569
@@ -4,13 +4,14 @@
|
||||
*/
|
||||
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/gunyah_qtvm.h>
|
||||
#include "vm_mgr.h"
|
||||
|
||||
#define PAS_VM_METADATA_SZ 8192
|
||||
|
||||
static DEFINE_MUTEX(gunyah_qtvm_lock);
|
||||
static LIST_HEAD(gunyah_qtvm_list);
|
||||
SRCU_NOTIFIER_HEAD_STATIC(gunyah_vm_notifier);
|
||||
SRCU_NOTIFIER_HEAD_STATIC(gunyah_qtvm_notifier);
|
||||
|
||||
struct gunyah_qtvm {
|
||||
struct gunyah_vm *ghvm;
|
||||
@@ -22,6 +23,24 @@ struct gunyah_qtvm {
|
||||
u16 vmid;
|
||||
};
|
||||
|
||||
int gunyah_qtvm_register_notifier(struct notifier_block *nb)
|
||||
{
|
||||
return srcu_notifier_chain_register(&gunyah_qtvm_notifier, nb);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gunyah_qtvm_register_notifier);
|
||||
|
||||
int gunyah_qtvm_unregister_notifier(struct notifier_block *nb)
|
||||
{
|
||||
return srcu_notifier_chain_unregister(&gunyah_qtvm_notifier, nb);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gunyah_qtvm_unregister_notifier);
|
||||
|
||||
static void gunyah_notify_clients(struct gunyah_qtvm *vm,
|
||||
enum gunyah_qtvm_state state)
|
||||
{
|
||||
srcu_notifier_call_chain(&gunyah_qtvm_notifier, state, &vm->vmid);
|
||||
}
|
||||
|
||||
static u16 gunyah_qtvm_pre_alloc_vmid(struct gunyah_vm *ghvm)
|
||||
{
|
||||
struct gunyah_qtvm *vm = ghvm->auth_vm_mgr_data;
|
||||
@@ -109,10 +128,45 @@ static int gunyah_qtvm_authenticate(struct gunyah_vm *ghvm)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gunyah_qtvm_pre_vm_start(struct gunyah_vm *ghvm)
|
||||
{
|
||||
struct gunyah_qtvm *vm = ghvm->auth_vm_mgr_data;
|
||||
|
||||
gunyah_notify_clients(vm, GUNYAH_QTVM_BEFORE_POWERUP);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void gunyah_qtvm_vm_start_fail(struct gunyah_vm *ghvm)
|
||||
{
|
||||
struct gunyah_qtvm *vm = ghvm->auth_vm_mgr_data;
|
||||
|
||||
gunyah_notify_clients(vm, GUNYAH_QTVM_POWERUP_FAIL);
|
||||
}
|
||||
|
||||
static int gunyah_qtvm_pre_vm_reset(struct gunyah_vm *ghvm)
|
||||
{
|
||||
struct gunyah_qtvm *vm = ghvm->auth_vm_mgr_data;
|
||||
|
||||
gunyah_notify_clients(vm, GUNYAH_QTVM_EXITED);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gunyah_qtvm_post_vm_reset(struct gunyah_vm *ghvm)
|
||||
{
|
||||
struct gunyah_qtvm *vm = ghvm->auth_vm_mgr_data;
|
||||
|
||||
gunyah_notify_clients(vm, GUNYAH_QTVM_EARLY_POWEROFF);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct gunyah_auth_vm_mgr_ops vm_ops = {
|
||||
.pre_alloc_vmid = gunyah_qtvm_pre_alloc_vmid,
|
||||
.pre_vm_configure = gunyah_qtvm_pre_vm_configure,
|
||||
.vm_authenticate = gunyah_qtvm_authenticate,
|
||||
.pre_vm_start = gunyah_qtvm_pre_vm_start,
|
||||
.vm_start_fail = gunyah_qtvm_vm_start_fail,
|
||||
.pre_vm_reset = gunyah_qtvm_pre_vm_reset,
|
||||
.post_vm_reset = gunyah_qtvm_post_vm_reset,
|
||||
};
|
||||
|
||||
static long gunyah_qtvm_attach(struct gunyah_vm *ghvm, struct gunyah_auth_desc *desc)
|
||||
@@ -161,6 +215,7 @@ static void gunyah_qtvm_detach(struct gunyah_vm *ghvm)
|
||||
struct gunyah_qtvm *vm = ghvm->auth_vm_mgr_data;
|
||||
|
||||
kfree(vm->parcel_list);
|
||||
gunyah_notify_clients(vm, GUNYAH_QTVM_POWEROFF);
|
||||
list_del(&vm->list);
|
||||
kfree(vm);
|
||||
ghvm->auth_vm_mgr_ops = NULL;
|
||||
|
||||
@@ -1127,6 +1127,10 @@ static void _gunyah_vm_put(struct kref *kref)
|
||||
gunyah_vm_remove_resource_ticket(ghvm, &ghvm->guest_private_extent_ticket);
|
||||
/* clang-format on */
|
||||
|
||||
ret = gunyah_vm_pre_vm_reset(ghvm);
|
||||
if (ret)
|
||||
dev_err(ghvm->parent, "Failed pre reset the vm: %d\n", ret);
|
||||
|
||||
gunyah_vm_clean_resources(ghvm);
|
||||
|
||||
if (ghvm->vm_status == GUNYAH_RM_VM_STATUS_EXITED ||
|
||||
@@ -1138,7 +1142,11 @@ static void _gunyah_vm_put(struct kref *kref)
|
||||
wait_event(ghvm->vm_status_wait,
|
||||
ghvm->vm_status == GUNYAH_RM_VM_STATUS_RESET);
|
||||
else
|
||||
dev_err(ghvm->parent, "Failed to reset the vm: %d\n",ret);
|
||||
dev_err(ghvm->parent, "Failed to reset the vm: %d\n", ret);
|
||||
|
||||
ret = gunyah_vm_post_vm_reset(ghvm);
|
||||
if (ret)
|
||||
dev_err(ghvm->parent, "Failed post reset the vm: %d\n", ret);
|
||||
/* clang-format on */
|
||||
}
|
||||
|
||||
|
||||
@@ -329,4 +329,19 @@ static inline void gunyah_vm_start_fail(struct gunyah_vm *ghvm)
|
||||
return ghvm->auth_vm_mgr_ops->vm_start_fail(ghvm);
|
||||
}
|
||||
|
||||
static inline int gunyah_vm_pre_vm_reset(struct gunyah_vm *ghvm)
|
||||
{
|
||||
if (ghvm->auth_vm_mgr_ops->pre_vm_reset)
|
||||
return ghvm->auth_vm_mgr_ops->pre_vm_reset(ghvm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int gunyah_vm_post_vm_reset(struct gunyah_vm *ghvm)
|
||||
{
|
||||
if (ghvm->auth_vm_mgr_ops->post_vm_reset)
|
||||
return ghvm->auth_vm_mgr_ops->post_vm_reset(ghvm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -37,6 +37,9 @@ void gunyah_vm_put(struct gunyah_vm *ghvm);
|
||||
* choose to setup if you want demand paged VM or not. (Optional)
|
||||
* @pre_vm_start: Callback for any setup before VM start where client
|
||||
* drivers can share/lend memory. (Optional)
|
||||
* @pre_vm_reset: Callback for any cleanup before VM reset. All resources
|
||||
* tracked by RM will be cleaned at this stage (Optional)
|
||||
* @post_vm_reset: Callback for any cleanup after VM reset (Optional)
|
||||
* @start_fail: Needed when roll back is needed before auth_mgr can
|
||||
* clean up at a later stage.
|
||||
**/
|
||||
@@ -46,6 +49,8 @@ struct gunyah_auth_vm_mgr_ops {
|
||||
int (*vm_authenticate)(struct gunyah_vm *ghvm);
|
||||
int (*pre_vm_init)(struct gunyah_vm *ghvm);
|
||||
int (*pre_vm_start)(struct gunyah_vm *ghvm);
|
||||
int (*pre_vm_reset)(struct gunyah_vm *ghvm);
|
||||
int (*post_vm_reset)(struct gunyah_vm *ghvm);
|
||||
void (*vm_start_fail)(struct gunyah_vm *ghvm);
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_GUNYAH_QTVM_H
|
||||
#define _LINUX_GUNYAH_QTVM_H
|
||||
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/gunyah.h>
|
||||
|
||||
enum gunyah_qtvm_state {
|
||||
GUNYAH_QTVM_BEFORE_POWERUP = 1,
|
||||
GUNYAH_QTVM_POWERUP_FAIL = 2,
|
||||
GUNYAH_QTVM_EARLY_POWEROFF = 3,
|
||||
GUNYAH_QTVM_POWEROFF = 4,
|
||||
GUNYAH_QTVM_EXITED = 5,
|
||||
GUNYAH_QTVM_CRASH = 6,
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_GUNYAH_QCOM_TRUSTED_VM)
|
||||
int gunyah_qtvm_register_notifier(struct notifier_block *nb);
|
||||
int gunyah_qtvm_unregister_notifier(struct notifier_block *nb);
|
||||
int gunyah_qtvm_register_resource_ticket(struct gunyah_vm_resource_ticket *t,
|
||||
u16 vmid);
|
||||
void gunyah_qtvm_unregister_resource_ticket(struct gunyah_vm_resource_ticket *t,
|
||||
u16 vmid);
|
||||
#else
|
||||
static inline int gunyah_qtvm_register_notifier(struct notifier_block *nb)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline int gunyah_qtvm_unregister_notifier(struct notifier_block *nb)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline int gunyah_qtvm_register_resource_ticket(
|
||||
struct gunyah_vm_resource_ticket *t, u16 vmid)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline void gunyah_qtvm_unregister_resource_ticket(
|
||||
struct gunyah_vm_resource_ticket *t, u16 vmid)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user