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 <quic_penyan@quicinc.com>
This commit is contained in:
Peng Yang 2022-07-02 08:43:08 -07:00 committed by Gerrit - the friendly Code Review server
parent ffd10e3562
commit 381ac781d4
3 changed files with 170 additions and 0 deletions

View File

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

View File

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

View File

@ -0,0 +1,157 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
*
*/
#include <linux/gunyah/gh_mem_notifier.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/notifier.h>
#include <linux/slab.h>
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");