From 381ac781d4f855426b1b7e36e19be1258b5566ad Mon Sep 17 00:00:00 2001 From: Peng Yang Date: Sat, 2 Jul 2022 08:43:08 -0700 Subject: [PATCH] gunyah: rm: Porting gunyah memory resource notifier driver Add gunyah memory resource notifier drivers for pineapple. This is just snapshot of kalama's memory resource notifier driver 'commit 5beb98404269 ("Merge "i3c: i3c-master-msm-geni: Fix IBI for invalid device OR handler"")'from msm-5.15 branch. Change-Id: I4ccdc0876031ec95f0c9e23246912b31b334df93 Signed-off-by: Peng Yang --- drivers/virt/gunyah/Kconfig | 12 ++ drivers/virt/gunyah/Makefile | 1 + drivers/virt/gunyah/gh_mem_notifier.c | 157 ++++++++++++++++++++++++++ 3 files changed, 170 insertions(+) create mode 100644 drivers/virt/gunyah/gh_mem_notifier.c diff --git a/drivers/virt/gunyah/Kconfig b/drivers/virt/gunyah/Kconfig index b5646586fb33..9d0cbb336e46 100644 --- a/drivers/virt/gunyah/Kconfig +++ b/drivers/virt/gunyah/Kconfig @@ -66,4 +66,16 @@ config GH_IRQ_LEND supports sharing these interrupts. The follows RM recommended protocol. +config GH_MEM_NOTIFIER + tristate "Gunyah Memory Resource Notification Framework" + depends on GH_RM_DRV + help + The Gunyah Resource Manager allows for different memory resources + to be transferred across virtual machines with different notification + labels assigned to each resource to aid in distinguishing them. + Enabling the Gunyah Memory Resource Notification Framework provides an + interface for clients to transmit memory resources between virtual + machines, and register callbacks that get invoked only when + notifications pertaining to their memory resources arrive. + endif diff --git a/drivers/virt/gunyah/Makefile b/drivers/virt/gunyah/Makefile index 783158d60119..f68c17fad10f 100644 --- a/drivers/virt/gunyah/Makefile +++ b/drivers/virt/gunyah/Makefile @@ -5,3 +5,4 @@ obj-$(CONFIG_GH_MSGQ) += gh_msgq.o obj-$(CONFIG_GH_RM_DRV) += gh_rm_drv.o gh_rm_drv-y += gh_rm_core.o gh_rm_iface.o obj-$(CONFIG_GH_IRQ_LEND) += gh_irq_lend.o +obj-$(CONFIG_GH_MEM_NOTIFIER) += gh_mem_notifier.o diff --git a/drivers/virt/gunyah/gh_mem_notifier.c b/drivers/virt/gunyah/gh_mem_notifier.c new file mode 100644 index 000000000000..d2a96199101e --- /dev/null +++ b/drivers/virt/gunyah/gh_mem_notifier.c @@ -0,0 +1,157 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * + */ + +#include +#include +#include +#include +#include +#include + +struct mem_notifier_entry { + gh_mem_notifier_handler handler; + void *data; +}; + +static DEFINE_MUTEX(mem_notifier_entries_lock); +static struct mem_notifier_entry mem_notifier_entries[GH_MEM_NOTIFIER_TAG_MAX]; + +static bool gh_mem_notifier_tag_valid(enum gh_mem_notifier_tag tag) +{ + return tag >= 0 && tag < GH_MEM_NOTIFIER_TAG_MAX; +} + +/** + * gh_mem_notifier_register: Bind a callback and arbitrary data to a particular + * notification tag. The callback will be invoked when + * the Gunyah MEM_SHARED and MEM_RELEASED notifications + * involving the tag that was registered with arrive + * at the VM. + * @tag: The tag for which the caller would like to receive MEM_SHARED and + * MEM_RELEASED notifications for + * @handler: The handler that will be invoked when a MEM_SHARED or MEM_RELEASED + * notification pertaining to @tag arrives at the VM. The handler will + * also be invoked with a pointer to caller specific data, as well as + * the original MEM_SHARED/MEM_RELEASED payload from the resource + * manager. + * @data: The data that should be passed to @handler when it is invoked + * + * On success, the function will return a cookie. Otherwise, the function will + * return an error, and thus, callers should use IS_ERR() to check for any + * errors. The cookie must be used when unregistering the handler from the + * tag. + */ +void *gh_mem_notifier_register(enum gh_mem_notifier_tag tag, + gh_mem_notifier_handler handler, void *data) +{ + struct mem_notifier_entry *entry; + + if (!gh_mem_notifier_tag_valid(tag) || !handler) + return ERR_PTR(-EINVAL); + + mutex_lock(&mem_notifier_entries_lock); + entry = &mem_notifier_entries[tag]; + if (entry->handler) { + mutex_unlock(&mem_notifier_entries_lock); + return ERR_PTR(-EEXIST); + } + entry->handler = handler; + entry->data = data; + mutex_unlock(&mem_notifier_entries_lock); + + return entry; +} +EXPORT_SYMBOL(gh_mem_notifier_register); + +/** + * gh_mem_notifier_unregister: Unregister for memory notifier notifications + * with respect to a particular tag. + * @cookie: The cookie returned by gh_mem_notifier_register + * + * On success, the function will unbind the handler specified in + * gh_mem_notifier_register from the tag, preventing the handler from being + * invoked when subsequent MEM_SHARED/MEM_RELEASED notifications pertaining + * to the tag arrive. + */ +void gh_mem_notifier_unregister(void *cookie) +{ + struct mem_notifier_entry *entry = cookie; + + if (!cookie) + return; + + mutex_lock(&mem_notifier_entries_lock); + entry->handler = NULL; + entry->data = NULL; + mutex_unlock(&mem_notifier_entries_lock); +} +EXPORT_SYMBOL(gh_mem_notifier_unregister); + +static enum gh_mem_notifier_tag gh_mem_notifier_get_tag(unsigned long action, + void *msg) +{ + if (action == GH_RM_NOTIF_MEM_SHARED) + return + ((struct gh_rm_notif_mem_shared_payload *)msg)->mem_info_tag; + else if (action == GH_RM_NOTIF_MEM_RELEASED) + return + ((struct gh_rm_notif_mem_released_payload *)msg)->mem_info_tag; + + return ((struct gh_rm_notif_mem_accepted_payload *)msg)->mem_info_tag; +} + +static int gh_mem_notifier_call(struct notifier_block *nb, unsigned long action, + void *msg) +{ + struct mem_notifier_entry *entry; + enum gh_mem_notifier_tag tag; + gh_mem_notifier_handler handler = NULL; + void *data; + + if ((action != GH_RM_NOTIF_MEM_SHARED) && + (action != GH_RM_NOTIF_MEM_RELEASED) && + (action != GH_RM_NOTIF_MEM_ACCEPTED)) + return NOTIFY_DONE; + + tag = gh_mem_notifier_get_tag(action, msg); + if (!gh_mem_notifier_tag_valid(tag)) + return NOTIFY_DONE; + + mutex_lock(&mem_notifier_entries_lock); + entry = &mem_notifier_entries[tag]; + handler = entry->handler; + data = entry->data; + mutex_unlock(&mem_notifier_entries_lock); + + if (handler) + handler(tag, action, data, msg); + + return NOTIFY_OK; +} + +static struct notifier_block gh_mem_notifier_blk = { + .notifier_call = gh_mem_notifier_call, +}; + +static int __init gh_mem_notifier_init(void) +{ + int ret = gh_rm_register_notifier(&gh_mem_notifier_blk); + + if (ret) + pr_err("%s: registration with RM notifier failed rc: %d\n", + __func__, ret); + return ret; +} +module_init(gh_mem_notifier_init); + +static void __exit gh_mem_notifier_exit(void) +{ + gh_rm_unregister_notifier(&gh_mem_notifier_blk); +} +module_exit(gh_mem_notifier_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Qualcomm Technologies, Inc. Gunyah Memory Notifier");