mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-06 02:50:49 +09:00
ANDROID: gunyah: Sync with latest "gunyah: vm_mgr: Add framework for VM Functions"
Align Gunyah VM Functions with Gunyah v13 patches: https://lore.kernel.org/all/20230509204801.2824351-18-quic_eberman@quicinc.com/ Bug: 279506910 Change-Id: Id8e043191539d41e4b54cb579ba2a84db76e0f70 Signed-off-by: Elliot Berman <quic_eberman@quicinc.com>
This commit is contained in:
committed by
Carlos Llamas
parent
fea63fe1f1
commit
5e0785329a
@@ -111,7 +111,20 @@ static void gh_ioevent_unbind(struct gh_vm_function_instance *f)
|
||||
kfree(iofd);
|
||||
}
|
||||
|
||||
DECLARE_GH_VM_FUNCTION_INIT(ioeventfd, GH_FN_IOEVENTFD,
|
||||
gh_ioeventfd_bind, gh_ioevent_unbind);
|
||||
static bool gh_ioevent_compare(const struct gh_vm_function_instance *f,
|
||||
const void *arg, size_t size)
|
||||
{
|
||||
const struct gh_fn_ioeventfd_arg *instance = f->argp,
|
||||
*other = arg;
|
||||
|
||||
if (sizeof(*other) != size)
|
||||
return false;
|
||||
|
||||
return instance->addr == other->addr;
|
||||
}
|
||||
|
||||
DECLARE_GH_VM_FUNCTION_INIT(ioeventfd, GH_FN_IOEVENTFD, 3,
|
||||
gh_ioeventfd_bind, gh_ioevent_unbind,
|
||||
gh_ioevent_compare);
|
||||
MODULE_DESCRIPTION("Gunyah ioeventfds");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
@@ -159,6 +159,19 @@ static void gh_irqfd_unbind(struct gh_vm_function_instance *f)
|
||||
kfree(irqfd);
|
||||
}
|
||||
|
||||
DECLARE_GH_VM_FUNCTION_INIT(irqfd, GH_FN_IRQFD, gh_irqfd_bind, gh_irqfd_unbind);
|
||||
static bool gh_irqfd_compare(const struct gh_vm_function_instance *f,
|
||||
const void *arg, size_t size)
|
||||
{
|
||||
const struct gh_fn_irqfd_arg *instance = f->argp,
|
||||
*other = arg;
|
||||
|
||||
if (sizeof(*other) != size)
|
||||
return false;
|
||||
|
||||
return instance->label == other->label;
|
||||
}
|
||||
|
||||
DECLARE_GH_VM_FUNCTION_INIT(irqfd, GH_FN_IRQFD, 2, gh_irqfd_bind, gh_irqfd_unbind,
|
||||
gh_irqfd_compare);
|
||||
MODULE_DESCRIPTION("Gunyah irqfds");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
@@ -457,6 +457,18 @@ static void gh_vcpu_unbind(struct gh_vm_function_instance *f)
|
||||
kref_put(&vcpu->kref, vcpu_release);
|
||||
}
|
||||
|
||||
DECLARE_GH_VM_FUNCTION_INIT(vcpu, GH_FN_VCPU, gh_vcpu_bind, gh_vcpu_unbind);
|
||||
static bool gh_vcpu_compare(const struct gh_vm_function_instance *f,
|
||||
const void *arg, size_t size)
|
||||
{
|
||||
const struct gh_fn_vcpu_arg *instance = f->argp,
|
||||
*other = arg;
|
||||
|
||||
if (sizeof(*other) != size)
|
||||
return false;
|
||||
|
||||
return instance->id == other->id;
|
||||
}
|
||||
|
||||
DECLARE_GH_VM_FUNCTION_INIT(vcpu, GH_FN_VCPU, 1, gh_vcpu_bind, gh_vcpu_unbind, gh_vcpu_compare);
|
||||
MODULE_DESCRIPTION("Gunyah vCPU Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
@@ -19,47 +19,27 @@
|
||||
|
||||
#include "vm_mgr.h"
|
||||
|
||||
static DEFINE_XARRAY(functions);
|
||||
static void gh_vm_free(struct work_struct *work);
|
||||
|
||||
int gh_vm_function_register(struct gh_vm_function *fn)
|
||||
static DEFINE_XARRAY(gh_vm_functions);
|
||||
|
||||
static void gh_vm_put_function(struct gh_vm_function *fn)
|
||||
{
|
||||
if (!fn->bind || !fn->unbind)
|
||||
return -EINVAL;
|
||||
|
||||
return xa_err(xa_store(&functions, fn->type, fn, GFP_KERNEL));
|
||||
module_put(fn->mod);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gh_vm_function_register);
|
||||
|
||||
static void gh_vm_remove_function_instance(struct gh_vm_function_instance *inst)
|
||||
__must_hold(&inst->ghvm->fn_lock)
|
||||
{
|
||||
inst->fn->unbind(inst);
|
||||
list_del(&inst->vm_list);
|
||||
module_put(inst->fn->mod);
|
||||
kfree(inst->argp);
|
||||
kfree(inst);
|
||||
}
|
||||
|
||||
void gh_vm_function_unregister(struct gh_vm_function *fn)
|
||||
{
|
||||
/* Expecting unregister to only come when unloading a module */
|
||||
WARN_ON(fn->mod && module_refcount(fn->mod));
|
||||
xa_erase(&functions, fn->type);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gh_vm_function_unregister);
|
||||
|
||||
static struct gh_vm_function *gh_vm_get_function(u32 type)
|
||||
{
|
||||
struct gh_vm_function *fn;
|
||||
int r;
|
||||
|
||||
fn = xa_load(&functions, type);
|
||||
fn = xa_load(&gh_vm_functions, type);
|
||||
if (!fn) {
|
||||
r = request_module("ghfunc:%d", type);
|
||||
if (r)
|
||||
return ERR_PTR(r);
|
||||
return ERR_PTR(r > 0 ? -r : r);
|
||||
|
||||
fn = xa_load(&functions, type);
|
||||
fn = xa_load(&gh_vm_functions, type);
|
||||
}
|
||||
|
||||
if (!fn || !try_module_get(fn->mod))
|
||||
@@ -68,14 +48,36 @@ static struct gh_vm_function *gh_vm_get_function(u32 type)
|
||||
return fn;
|
||||
}
|
||||
|
||||
static long gh_vm_add_function(struct gh_vm *ghvm, struct gh_fn_desc *f)
|
||||
static void gh_vm_remove_function_instance(struct gh_vm_function_instance *inst)
|
||||
__must_hold(&inst->ghvm->fn_lock)
|
||||
{
|
||||
inst->fn->unbind(inst);
|
||||
list_del(&inst->vm_list);
|
||||
gh_vm_put_function(inst->fn);
|
||||
kfree(inst->argp);
|
||||
kfree(inst);
|
||||
}
|
||||
|
||||
static void gh_vm_remove_functions(struct gh_vm *ghvm)
|
||||
{
|
||||
struct gh_vm_function_instance *inst, *iiter;
|
||||
|
||||
mutex_lock(&ghvm->fn_lock);
|
||||
list_for_each_entry_safe(inst, iiter, &ghvm->functions, vm_list) {
|
||||
gh_vm_remove_function_instance(inst);
|
||||
}
|
||||
mutex_unlock(&ghvm->fn_lock);
|
||||
}
|
||||
|
||||
static long gh_vm_add_function_instance(struct gh_vm *ghvm, struct gh_fn_desc *f)
|
||||
{
|
||||
struct gh_vm_function_instance *inst;
|
||||
void __user *argp;
|
||||
long r = 0;
|
||||
|
||||
if (f->arg_size > GH_FN_MAX_ARG_SIZE) {
|
||||
dev_err(ghvm->parent, "%s: arg_size > %d\n", __func__, GH_FN_MAX_ARG_SIZE);
|
||||
dev_err_ratelimited(ghvm->parent, "%s: arg_size > %d\n",
|
||||
__func__, GH_FN_MAX_ARG_SIZE);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -110,7 +112,8 @@ static long gh_vm_add_function(struct gh_vm *ghvm, struct gh_fn_desc *f)
|
||||
mutex_lock(&ghvm->fn_lock);
|
||||
r = inst->fn->bind(inst);
|
||||
if (r < 0) {
|
||||
module_put(inst->fn->mod);
|
||||
mutex_unlock(&ghvm->fn_lock);
|
||||
gh_vm_put_function(inst->fn);
|
||||
goto free_arg;
|
||||
}
|
||||
|
||||
@@ -125,7 +128,7 @@ free:
|
||||
return r;
|
||||
}
|
||||
|
||||
static long gh_vm_rm_function(struct gh_vm *ghvm, struct gh_fn_desc *f)
|
||||
static long gh_vm_rm_function_instance(struct gh_vm *ghvm, struct gh_fn_desc *f)
|
||||
{
|
||||
struct gh_vm_function_instance *inst, *iter;
|
||||
void __user *user_argp;
|
||||
@@ -150,11 +153,13 @@ static long gh_vm_rm_function(struct gh_vm *ghvm, struct gh_fn_desc *f)
|
||||
goto out;
|
||||
}
|
||||
|
||||
r = -ENOENT;
|
||||
list_for_each_entry_safe(inst, iter, &ghvm->functions, vm_list) {
|
||||
if (inst->fn->type == f->type &&
|
||||
f->arg_size == inst->arg_size &&
|
||||
!memcmp(argp, inst->argp, f->arg_size))
|
||||
inst->fn->compare(inst, argp, f->arg_size)) {
|
||||
gh_vm_remove_function_instance(inst);
|
||||
r = 0;
|
||||
}
|
||||
}
|
||||
|
||||
kfree(argp);
|
||||
@@ -165,6 +170,23 @@ out:
|
||||
return r;
|
||||
}
|
||||
|
||||
int gh_vm_function_register(struct gh_vm_function *fn)
|
||||
{
|
||||
if (!fn->bind || !fn->unbind)
|
||||
return -EINVAL;
|
||||
|
||||
return xa_err(xa_store(&gh_vm_functions, fn->type, fn, GFP_KERNEL));
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gh_vm_function_register);
|
||||
|
||||
void gh_vm_function_unregister(struct gh_vm_function *fn)
|
||||
{
|
||||
/* Expecting unregister to only come when unloading a module */
|
||||
WARN_ON(fn->mod && module_refcount(fn->mod));
|
||||
xa_erase(&gh_vm_functions, fn->type);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gh_vm_function_unregister);
|
||||
|
||||
int gh_vm_add_resource_ticket(struct gh_vm *ghvm, struct gh_vm_resource_ticket *ticket)
|
||||
{
|
||||
struct gh_vm_resource_ticket *iter;
|
||||
@@ -189,7 +211,7 @@ int gh_vm_add_resource_ticket(struct gh_vm *ghvm, struct gh_vm_resource_ticket *
|
||||
|
||||
list_for_each_entry(ghrsc, &ghvm->resources, list) {
|
||||
if (ghrsc->type == ticket->resource_type && ghrsc->rm_label == ticket->label) {
|
||||
if (!ticket->populate(ticket, ghrsc))
|
||||
if (ticket->populate(ticket, ghrsc))
|
||||
list_move(&ghrsc->list, &ticket->resources);
|
||||
}
|
||||
}
|
||||
@@ -395,7 +417,6 @@ static void gh_vm_stop(struct gh_vm *ghvm)
|
||||
static void gh_vm_free(struct work_struct *work)
|
||||
{
|
||||
struct gh_vm *ghvm = container_of(work, struct gh_vm, free_work);
|
||||
struct gh_vm_function_instance *inst, *iiter;
|
||||
struct gh_vm_resource_ticket *ticket, *titer;
|
||||
struct gh_resource *ghrsc, *riter;
|
||||
struct gh_vm_mem *mapping, *tmp;
|
||||
@@ -407,11 +428,7 @@ static void gh_vm_free(struct work_struct *work)
|
||||
fallthrough;
|
||||
case GH_RM_VM_STATUS_INIT_FAILED:
|
||||
case GH_RM_VM_STATUS_EXITED:
|
||||
mutex_lock(&ghvm->fn_lock);
|
||||
list_for_each_entry_safe(inst, iiter, &ghvm->functions, vm_list) {
|
||||
gh_vm_remove_function_instance(inst);
|
||||
}
|
||||
mutex_unlock(&ghvm->fn_lock);
|
||||
gh_vm_remove_functions(ghvm);
|
||||
|
||||
mutex_lock(&ghvm->resources_lock);
|
||||
if (!list_empty(&ghvm->resource_tickets)) {
|
||||
@@ -728,21 +745,16 @@ static long gh_vm_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
if (copy_from_user(&f, argp, sizeof(f)))
|
||||
return -EFAULT;
|
||||
|
||||
r = gh_vm_add_function(ghvm, &f);
|
||||
r = gh_vm_add_function_instance(ghvm, &f);
|
||||
break;
|
||||
}
|
||||
case GH_VM_REMOVE_FUNCTION: {
|
||||
struct gh_fn_desc *f;
|
||||
struct gh_fn_desc f;
|
||||
|
||||
f = kzalloc(sizeof(*f), GFP_KERNEL);
|
||||
if (!f)
|
||||
return -ENOMEM;
|
||||
|
||||
if (copy_from_user(f, argp, sizeof(*f)))
|
||||
if (copy_from_user(&f, argp, sizeof(f)))
|
||||
return -EFAULT;
|
||||
|
||||
r = gh_vm_rm_function(ghvm, f);
|
||||
kfree(f);
|
||||
r = gh_vm_rm_function_instance(ghvm, &f);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
||||
@@ -27,6 +27,7 @@ struct gh_vm_function {
|
||||
struct module *mod;
|
||||
long (*bind)(struct gh_vm_function_instance *f);
|
||||
void (*unbind)(struct gh_vm_function_instance *f);
|
||||
bool (*compare)(const struct gh_vm_function_instance *f, const void *arg, size_t size);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -53,22 +54,35 @@ struct gh_vm_function_instance {
|
||||
int gh_vm_function_register(struct gh_vm_function *f);
|
||||
void gh_vm_function_unregister(struct gh_vm_function *f);
|
||||
|
||||
#define DECLARE_GH_VM_FUNCTION(_name, _type, _bind, _unbind) \
|
||||
static struct gh_vm_function _name = { \
|
||||
/* Since the function identifiers were setup in a uapi header as an
|
||||
* enum and we do no want to change that, the user must supply the expanded
|
||||
* constant as well and the compiler checks they are the same.
|
||||
* See also MODULE_ALIAS_RDMA_NETLINK.
|
||||
*/
|
||||
#define MODULE_ALIAS_GH_VM_FUNCTION(_type, _idx) \
|
||||
static inline void __maybe_unused __chk##_idx(void) \
|
||||
{ \
|
||||
BUILD_BUG_ON(_type != _idx); \
|
||||
} \
|
||||
MODULE_ALIAS("ghfunc:" __stringify(_idx))
|
||||
|
||||
#define DECLARE_GH_VM_FUNCTION(_name, _type, _bind, _unbind, _compare) \
|
||||
static struct gh_vm_function _name = { \
|
||||
.type = _type, \
|
||||
.name = __stringify(_name), \
|
||||
.mod = THIS_MODULE, \
|
||||
.bind = _bind, \
|
||||
.unbind = _unbind, \
|
||||
}; \
|
||||
MODULE_ALIAS("ghfunc:"__stringify(_type))
|
||||
.compare = _compare, \
|
||||
}
|
||||
|
||||
#define module_gh_vm_function(__gf) \
|
||||
module_driver(__gf, gh_vm_function_register, gh_vm_function_unregister)
|
||||
|
||||
#define DECLARE_GH_VM_FUNCTION_INIT(_name, _type, _bind, _unbind) \
|
||||
DECLARE_GH_VM_FUNCTION(_name, _type, _bind, _unbind); \
|
||||
module_gh_vm_function(_name)
|
||||
#define DECLARE_GH_VM_FUNCTION_INIT(_name, _type, _idx, _bind, _unbind, _compare) \
|
||||
DECLARE_GH_VM_FUNCTION(_name, _type, _bind, _unbind, _compare); \
|
||||
module_gh_vm_function(_name); \
|
||||
MODULE_ALIAS_GH_VM_FUNCTION(_type, _idx)
|
||||
|
||||
struct gh_vm_resource_ticket {
|
||||
struct list_head list; /* for gh_vm's resources list */
|
||||
|
||||
Reference in New Issue
Block a user