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:
Prakruthi Deepak Heragu
2025-02-24 14:51:00 -08:00
committed by Todd Kjos
parent ca44b02c02
commit b582c89569
5 changed files with 133 additions and 2 deletions
+56 -1
View File
@@ -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;
+9 -1
View File
@@ -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 */
}
+15
View File
@@ -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
+5
View File
@@ -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);
};
+48
View File
@@ -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