driver: soc: xilinx: Update function prototype for xlnx_unregister_event
As per the current implementation only single callback data gets saved per event, driver is throwing an error if try to register multiple callback for same event. So at time of unregistration of any event required things are event details and callback handler as parameter of xlnx_unregister_event(). As part of adding support of multiple callbacks for same event also require change in prototype of xlnx_unregister_event(). During unregistration of any events, now required things are event details, callback handler and agent's private data as parameter of xlnx_unregister_event(). Also modify the usage of xlnx_unregister_event() in xilinx/zynqmp_power.c driver as per new implementation. Signed-off-by: Abhyuday Godhasara <abhyuday.godhasara@xilinx.com> Link: https://lore.kernel.org/r/20220427074803.19009-3-abhyuday.godhasara@xilinx.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
05e5ba40ea
commit
e6d3c99adf
|
@ -41,6 +41,8 @@ static int event_manager_availability = -EACCES;
|
||||||
static DEFINE_HASHTABLE(reg_driver_map, REGISTERED_DRIVER_MAX_ORDER);
|
static DEFINE_HASHTABLE(reg_driver_map, REGISTERED_DRIVER_MAX_ORDER);
|
||||||
static int sgi_num = XLNX_EVENT_SGI_NUM;
|
static int sgi_num = XLNX_EVENT_SGI_NUM;
|
||||||
|
|
||||||
|
static bool is_need_to_unregister;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct agent_cb - Registered callback function and private data.
|
* struct agent_cb - Registered callback function and private data.
|
||||||
* @agent_data: Data passed back to handler function.
|
* @agent_data: Data passed back to handler function.
|
||||||
|
@ -189,6 +191,8 @@ static int xlnx_remove_cb_for_suspend(event_cb_func_t cb_fun)
|
||||||
struct agent_cb *cb_pos;
|
struct agent_cb *cb_pos;
|
||||||
struct agent_cb *cb_next;
|
struct agent_cb *cb_next;
|
||||||
|
|
||||||
|
is_need_to_unregister = false;
|
||||||
|
|
||||||
/* Check for existing entry in hash table for given cb_type */
|
/* Check for existing entry in hash table for given cb_type */
|
||||||
hash_for_each_possible(reg_driver_map, eve_data, hentry, PM_INIT_SUSPEND_CB) {
|
hash_for_each_possible(reg_driver_map, eve_data, hentry, PM_INIT_SUSPEND_CB) {
|
||||||
if (eve_data->cb_type == PM_INIT_SUSPEND_CB) {
|
if (eve_data->cb_type == PM_INIT_SUSPEND_CB) {
|
||||||
|
@ -203,6 +207,7 @@ static int xlnx_remove_cb_for_suspend(event_cb_func_t cb_fun)
|
||||||
/* remove an object from a hashtable */
|
/* remove an object from a hashtable */
|
||||||
hash_del(&eve_data->hentry);
|
hash_del(&eve_data->hentry);
|
||||||
kfree(eve_data);
|
kfree(eve_data);
|
||||||
|
is_need_to_unregister = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!is_callback_found) {
|
if (!is_callback_found) {
|
||||||
|
@ -214,7 +219,7 @@ static int xlnx_remove_cb_for_suspend(event_cb_func_t cb_fun)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int xlnx_remove_cb_for_notify_event(const u32 node_id, const u32 event,
|
static int xlnx_remove_cb_for_notify_event(const u32 node_id, const u32 event,
|
||||||
event_cb_func_t cb_fun)
|
event_cb_func_t cb_fun, void *data)
|
||||||
{
|
{
|
||||||
bool is_callback_found = false;
|
bool is_callback_found = false;
|
||||||
struct registered_event_data *eve_data;
|
struct registered_event_data *eve_data;
|
||||||
|
@ -222,20 +227,28 @@ static int xlnx_remove_cb_for_notify_event(const u32 node_id, const u32 event,
|
||||||
struct agent_cb *cb_pos;
|
struct agent_cb *cb_pos;
|
||||||
struct agent_cb *cb_next;
|
struct agent_cb *cb_next;
|
||||||
|
|
||||||
|
is_need_to_unregister = false;
|
||||||
|
|
||||||
/* Check for existing entry in hash table for given key id */
|
/* Check for existing entry in hash table for given key id */
|
||||||
hash_for_each_possible(reg_driver_map, eve_data, hentry, key) {
|
hash_for_each_possible(reg_driver_map, eve_data, hentry, key) {
|
||||||
if (eve_data->key == key) {
|
if (eve_data->key == key) {
|
||||||
/* Delete the list of callback */
|
/* Delete the list of callback */
|
||||||
list_for_each_entry_safe(cb_pos, cb_next, &eve_data->cb_list_head, list) {
|
list_for_each_entry_safe(cb_pos, cb_next, &eve_data->cb_list_head, list) {
|
||||||
if (cb_pos->eve_cb == cb_fun) {
|
if (cb_pos->eve_cb == cb_fun &&
|
||||||
|
cb_pos->agent_data == data) {
|
||||||
is_callback_found = true;
|
is_callback_found = true;
|
||||||
list_del_init(&cb_pos->list);
|
list_del_init(&cb_pos->list);
|
||||||
kfree(cb_pos);
|
kfree(cb_pos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* remove an object from a HASH table */
|
|
||||||
hash_del(&eve_data->hentry);
|
/* Remove HASH table if callback list is empty */
|
||||||
kfree(eve_data);
|
if (list_empty(&eve_data->cb_list_head)) {
|
||||||
|
/* remove an object from a HASH table */
|
||||||
|
hash_del(&eve_data->hentry);
|
||||||
|
kfree(eve_data);
|
||||||
|
is_need_to_unregister = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!is_callback_found) {
|
if (!is_callback_found) {
|
||||||
|
@ -307,7 +320,7 @@ int xlnx_register_event(const enum pm_api_cb_id cb_type, const u32 node_id, cons
|
||||||
eve = event & (1 << pos);
|
eve = event & (1 << pos);
|
||||||
if (!eve)
|
if (!eve)
|
||||||
continue;
|
continue;
|
||||||
xlnx_remove_cb_for_notify_event(node_id, eve, cb_fun);
|
xlnx_remove_cb_for_notify_event(node_id, eve, cb_fun, data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -329,10 +342,10 @@ int xlnx_register_event(const enum pm_api_cb_id cb_type, const u32 node_id, cons
|
||||||
eve = event & (1 << pos);
|
eve = event & (1 << pos);
|
||||||
if (!eve)
|
if (!eve)
|
||||||
continue;
|
continue;
|
||||||
xlnx_remove_cb_for_notify_event(node_id, eve, cb_fun);
|
xlnx_remove_cb_for_notify_event(node_id, eve, cb_fun, data);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
xlnx_remove_cb_for_notify_event(node_id, event, cb_fun);
|
xlnx_remove_cb_for_notify_event(node_id, event, cb_fun, data);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -350,15 +363,18 @@ EXPORT_SYMBOL_GPL(xlnx_register_event);
|
||||||
* @node_id: Node-Id related to event.
|
* @node_id: Node-Id related to event.
|
||||||
* @event: Event Mask for the Error Event.
|
* @event: Event Mask for the Error Event.
|
||||||
* @cb_fun: Function pointer of callback function.
|
* @cb_fun: Function pointer of callback function.
|
||||||
|
* @data: Pointer of agent's private data.
|
||||||
*
|
*
|
||||||
* Return: Returns 0 on successful unregistration else error code.
|
* Return: Returns 0 on successful unregistration else error code.
|
||||||
*/
|
*/
|
||||||
int xlnx_unregister_event(const enum pm_api_cb_id cb_type, const u32 node_id, const u32 event,
|
int xlnx_unregister_event(const enum pm_api_cb_id cb_type, const u32 node_id, const u32 event,
|
||||||
event_cb_func_t cb_fun)
|
event_cb_func_t cb_fun, void *data)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret = 0;
|
||||||
u32 eve, pos;
|
u32 eve, pos;
|
||||||
|
|
||||||
|
is_need_to_unregister = false;
|
||||||
|
|
||||||
if (event_manager_availability)
|
if (event_manager_availability)
|
||||||
return event_manager_availability;
|
return event_manager_availability;
|
||||||
|
|
||||||
|
@ -375,23 +391,26 @@ int xlnx_unregister_event(const enum pm_api_cb_id cb_type, const u32 node_id, co
|
||||||
} else {
|
} else {
|
||||||
/* Remove Node-Id/Event from hash table */
|
/* Remove Node-Id/Event from hash table */
|
||||||
if (!xlnx_is_error_event(node_id)) {
|
if (!xlnx_is_error_event(node_id)) {
|
||||||
xlnx_remove_cb_for_notify_event(node_id, event, cb_fun);
|
xlnx_remove_cb_for_notify_event(node_id, event, cb_fun, data);
|
||||||
} else {
|
} else {
|
||||||
for (pos = 0; pos < MAX_BITS; pos++) {
|
for (pos = 0; pos < MAX_BITS; pos++) {
|
||||||
eve = event & (1 << pos);
|
eve = event & (1 << pos);
|
||||||
if (!eve)
|
if (!eve)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
xlnx_remove_cb_for_notify_event(node_id, eve, cb_fun);
|
xlnx_remove_cb_for_notify_event(node_id, eve, cb_fun, data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Un-register for Node-Id/Event combination */
|
/* Un-register if list is empty */
|
||||||
ret = zynqmp_pm_register_notifier(node_id, event, false, false);
|
if (is_need_to_unregister) {
|
||||||
if (ret) {
|
/* Un-register for Node-Id/Event combination */
|
||||||
pr_err("%s() failed for 0x%x and 0x%x: %d\n",
|
ret = zynqmp_pm_register_notifier(node_id, event, false, false);
|
||||||
__func__, node_id, event, ret);
|
if (ret) {
|
||||||
return ret;
|
pr_err("%s() failed for 0x%x and 0x%x: %d\n",
|
||||||
|
__func__, node_id, event, ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -447,7 +466,8 @@ static void xlnx_call_notify_cb_handler(const u32 *payload)
|
||||||
list) {
|
list) {
|
||||||
/* Remove already registered event from hash table */
|
/* Remove already registered event from hash table */
|
||||||
xlnx_remove_cb_for_notify_event(payload[1], payload[2],
|
xlnx_remove_cb_for_notify_event(payload[1], payload[2],
|
||||||
cb_pos->eve_cb);
|
cb_pos->eve_cb,
|
||||||
|
cb_pos->agent_data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -208,7 +208,7 @@ static int zynqmp_pm_probe(struct platform_device *pdev)
|
||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
if (!zynqmp_pm_init_suspend_work) {
|
if (!zynqmp_pm_init_suspend_work) {
|
||||||
xlnx_unregister_event(PM_INIT_SUSPEND_CB, 0, 0,
|
xlnx_unregister_event(PM_INIT_SUSPEND_CB, 0, 0,
|
||||||
suspend_event_callback);
|
suspend_event_callback, NULL);
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
event_registered = true;
|
event_registered = true;
|
||||||
|
@ -263,7 +263,8 @@ static int zynqmp_pm_probe(struct platform_device *pdev)
|
||||||
ret = sysfs_create_file(&pdev->dev.kobj, &dev_attr_suspend_mode.attr);
|
ret = sysfs_create_file(&pdev->dev.kobj, &dev_attr_suspend_mode.attr);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
if (event_registered) {
|
if (event_registered) {
|
||||||
xlnx_unregister_event(PM_INIT_SUSPEND_CB, 0, 0, suspend_event_callback);
|
xlnx_unregister_event(PM_INIT_SUSPEND_CB, 0, 0, suspend_event_callback,
|
||||||
|
NULL);
|
||||||
event_registered = false;
|
event_registered = false;
|
||||||
}
|
}
|
||||||
dev_err(&pdev->dev, "unable to create sysfs interface\n");
|
dev_err(&pdev->dev, "unable to create sysfs interface\n");
|
||||||
|
@ -277,7 +278,7 @@ static int zynqmp_pm_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
sysfs_remove_file(&pdev->dev.kobj, &dev_attr_suspend_mode.attr);
|
sysfs_remove_file(&pdev->dev.kobj, &dev_attr_suspend_mode.attr);
|
||||||
if (event_registered)
|
if (event_registered)
|
||||||
xlnx_unregister_event(PM_INIT_SUSPEND_CB, 0, 0, suspend_event_callback);
|
xlnx_unregister_event(PM_INIT_SUSPEND_CB, 0, 0, suspend_event_callback, NULL);
|
||||||
|
|
||||||
if (!rx_chan)
|
if (!rx_chan)
|
||||||
mbox_free_channel(rx_chan);
|
mbox_free_channel(rx_chan);
|
||||||
|
|
|
@ -17,7 +17,7 @@ int xlnx_register_event(const enum pm_api_cb_id cb_type, const u32 node_id,
|
||||||
event_cb_func_t cb_fun, void *data);
|
event_cb_func_t cb_fun, void *data);
|
||||||
|
|
||||||
int xlnx_unregister_event(const enum pm_api_cb_id cb_type, const u32 node_id,
|
int xlnx_unregister_event(const enum pm_api_cb_id cb_type, const u32 node_id,
|
||||||
const u32 event, event_cb_func_t cb_fun);
|
const u32 event, event_cb_func_t cb_fun, void *data);
|
||||||
#else
|
#else
|
||||||
static inline int xlnx_register_event(const enum pm_api_cb_id cb_type, const u32 node_id,
|
static inline int xlnx_register_event(const enum pm_api_cb_id cb_type, const u32 node_id,
|
||||||
const u32 event, const bool wake,
|
const u32 event, const bool wake,
|
||||||
|
@ -27,7 +27,7 @@ static inline int xlnx_register_event(const enum pm_api_cb_id cb_type, const u32
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int xlnx_unregister_event(const enum pm_api_cb_id cb_type, const u32 node_id,
|
static inline int xlnx_unregister_event(const enum pm_api_cb_id cb_type, const u32 node_id,
|
||||||
const u32 event, event_cb_func_t cb_fun)
|
const u32 event, event_cb_func_t cb_fun, void *data)
|
||||||
{
|
{
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue