1c7fdb240SAbhyuday Godhasara // SPDX-License-Identifier: GPL-2.0
2c7fdb240SAbhyuday Godhasara /*
3c7fdb240SAbhyuday Godhasara * Xilinx Event Management Driver
4c7fdb240SAbhyuday Godhasara *
5c7fdb240SAbhyuday Godhasara * Copyright (C) 2021 Xilinx, Inc.
6a96e60a6SJay Buddhabhatti * Copyright (C) 2024 Advanced Micro Devices, Inc.
7c7fdb240SAbhyuday Godhasara *
8c7fdb240SAbhyuday Godhasara * Abhyuday Godhasara <abhyuday.godhasara@xilinx.com>
9c7fdb240SAbhyuday Godhasara */
10c7fdb240SAbhyuday Godhasara
11c7fdb240SAbhyuday Godhasara #include <linux/cpuhotplug.h>
12c7fdb240SAbhyuday Godhasara #include <linux/firmware/xlnx-event-manager.h>
13c7fdb240SAbhyuday Godhasara #include <linux/firmware/xlnx-zynqmp.h>
14c7fdb240SAbhyuday Godhasara #include <linux/hashtable.h>
15c7fdb240SAbhyuday Godhasara #include <linux/interrupt.h>
16c7fdb240SAbhyuday Godhasara #include <linux/irq.h>
17c7fdb240SAbhyuday Godhasara #include <linux/irqdomain.h>
18c7fdb240SAbhyuday Godhasara #include <linux/module.h>
19c7fdb240SAbhyuday Godhasara #include <linux/of_irq.h>
20c7fdb240SAbhyuday Godhasara #include <linux/platform_device.h>
21c7fdb240SAbhyuday Godhasara #include <linux/slab.h>
22c7fdb240SAbhyuday Godhasara
23a96e60a6SJay Buddhabhatti static DEFINE_PER_CPU_READ_MOSTLY(int, dummy_cpu_number);
24c7fdb240SAbhyuday Godhasara
25c7fdb240SAbhyuday Godhasara static int virq_sgi;
26c7fdb240SAbhyuday Godhasara static int event_manager_availability = -EACCES;
27c7fdb240SAbhyuday Godhasara
28c7fdb240SAbhyuday Godhasara /* SGI number used for Event management driver */
29c7fdb240SAbhyuday Godhasara #define XLNX_EVENT_SGI_NUM (15)
30c7fdb240SAbhyuday Godhasara
31c7fdb240SAbhyuday Godhasara /* Max number of driver can register for same event */
32c7fdb240SAbhyuday Godhasara #define MAX_DRIVER_PER_EVENT (10U)
33c7fdb240SAbhyuday Godhasara
34c7fdb240SAbhyuday Godhasara /* Max HashMap Order for PM API feature check (1<<7 = 128) */
35c7fdb240SAbhyuday Godhasara #define REGISTERED_DRIVER_MAX_ORDER (7)
36c7fdb240SAbhyuday Godhasara
37c7fdb240SAbhyuday Godhasara #define MAX_BITS (32U) /* Number of bits available for error mask */
38c7fdb240SAbhyuday Godhasara
39c7fdb240SAbhyuday Godhasara #define FIRMWARE_VERSION_MASK (0xFFFFU)
40c7fdb240SAbhyuday Godhasara #define REGISTER_NOTIFIER_FIRMWARE_VERSION (2U)
41c7fdb240SAbhyuday Godhasara
42c7fdb240SAbhyuday Godhasara static DEFINE_HASHTABLE(reg_driver_map, REGISTERED_DRIVER_MAX_ORDER);
43c7fdb240SAbhyuday Godhasara static int sgi_num = XLNX_EVENT_SGI_NUM;
44c7fdb240SAbhyuday Godhasara
45e6d3c99aSAbhyuday Godhasara static bool is_need_to_unregister;
46e6d3c99aSAbhyuday Godhasara
47c7fdb240SAbhyuday Godhasara /**
4805e5ba40SAbhyuday Godhasara * struct agent_cb - Registered callback function and private data.
4905e5ba40SAbhyuday Godhasara * @agent_data: Data passed back to handler function.
5005e5ba40SAbhyuday Godhasara * @eve_cb: Function pointer to store the callback function.
5105e5ba40SAbhyuday Godhasara * @list: member to create list.
5205e5ba40SAbhyuday Godhasara */
5305e5ba40SAbhyuday Godhasara struct agent_cb {
5405e5ba40SAbhyuday Godhasara void *agent_data;
5505e5ba40SAbhyuday Godhasara event_cb_func_t eve_cb;
5605e5ba40SAbhyuday Godhasara struct list_head list;
5705e5ba40SAbhyuday Godhasara };
5805e5ba40SAbhyuday Godhasara
5905e5ba40SAbhyuday Godhasara /**
60c7fdb240SAbhyuday Godhasara * struct registered_event_data - Registered Event Data.
61c7fdb240SAbhyuday Godhasara * @key: key is the combine id(Node-Id | Event-Id) of type u64
62c7fdb240SAbhyuday Godhasara * where upper u32 for Node-Id and lower u32 for Event-Id,
63c7fdb240SAbhyuday Godhasara * And this used as key to index into hashmap.
64c7fdb240SAbhyuday Godhasara * @cb_type: Type of Api callback, like PM_NOTIFY_CB, etc.
65c7fdb240SAbhyuday Godhasara * @wake: If this flag set, firmware will wake up processor if is
66c7fdb240SAbhyuday Godhasara * in sleep or power down state.
6705e5ba40SAbhyuday Godhasara * @cb_list_head: Head of call back data list which contain the information
6805e5ba40SAbhyuday Godhasara * about registered handler and private data.
69c7fdb240SAbhyuday Godhasara * @hentry: hlist_node that hooks this entry into hashtable.
70c7fdb240SAbhyuday Godhasara */
71c7fdb240SAbhyuday Godhasara struct registered_event_data {
72c7fdb240SAbhyuday Godhasara u64 key;
73c7fdb240SAbhyuday Godhasara enum pm_api_cb_id cb_type;
74c7fdb240SAbhyuday Godhasara bool wake;
7505e5ba40SAbhyuday Godhasara struct list_head cb_list_head;
76c7fdb240SAbhyuday Godhasara struct hlist_node hentry;
77c7fdb240SAbhyuday Godhasara };
78c7fdb240SAbhyuday Godhasara
xlnx_is_error_event(const u32 node_id)79c7fdb240SAbhyuday Godhasara static bool xlnx_is_error_event(const u32 node_id)
80c7fdb240SAbhyuday Godhasara {
81c7fdb240SAbhyuday Godhasara if (node_id == EVENT_ERROR_PMC_ERR1 ||
82c7fdb240SAbhyuday Godhasara node_id == EVENT_ERROR_PMC_ERR2 ||
83c7fdb240SAbhyuday Godhasara node_id == EVENT_ERROR_PSM_ERR1 ||
84c7fdb240SAbhyuday Godhasara node_id == EVENT_ERROR_PSM_ERR2)
85c7fdb240SAbhyuday Godhasara return true;
86c7fdb240SAbhyuday Godhasara
87c7fdb240SAbhyuday Godhasara return false;
88c7fdb240SAbhyuday Godhasara }
89c7fdb240SAbhyuday Godhasara
xlnx_add_cb_for_notify_event(const u32 node_id,const u32 event,const bool wake,event_cb_func_t cb_fun,void * data)90c7fdb240SAbhyuday Godhasara static int xlnx_add_cb_for_notify_event(const u32 node_id, const u32 event, const bool wake,
91c7fdb240SAbhyuday Godhasara event_cb_func_t cb_fun, void *data)
92c7fdb240SAbhyuday Godhasara {
93c7fdb240SAbhyuday Godhasara u64 key = 0;
9405e5ba40SAbhyuday Godhasara bool present_in_hash = false;
95c7fdb240SAbhyuday Godhasara struct registered_event_data *eve_data;
9605e5ba40SAbhyuday Godhasara struct agent_cb *cb_data;
9705e5ba40SAbhyuday Godhasara struct agent_cb *cb_pos;
9805e5ba40SAbhyuday Godhasara struct agent_cb *cb_next;
99c7fdb240SAbhyuday Godhasara
100c7fdb240SAbhyuday Godhasara key = ((u64)node_id << 32U) | (u64)event;
101c7fdb240SAbhyuday Godhasara /* Check for existing entry in hash table for given key id */
102c7fdb240SAbhyuday Godhasara hash_for_each_possible(reg_driver_map, eve_data, hentry, key) {
103c7fdb240SAbhyuday Godhasara if (eve_data->key == key) {
10405e5ba40SAbhyuday Godhasara present_in_hash = true;
10505e5ba40SAbhyuday Godhasara break;
106c7fdb240SAbhyuday Godhasara }
107c7fdb240SAbhyuday Godhasara }
108c7fdb240SAbhyuday Godhasara
10905e5ba40SAbhyuday Godhasara if (!present_in_hash) {
11005e5ba40SAbhyuday Godhasara /* Add new entry if not present in HASH table */
111c7fdb240SAbhyuday Godhasara eve_data = kmalloc(sizeof(*eve_data), GFP_KERNEL);
112c7fdb240SAbhyuday Godhasara if (!eve_data)
113c7fdb240SAbhyuday Godhasara return -ENOMEM;
114c7fdb240SAbhyuday Godhasara eve_data->key = key;
115c7fdb240SAbhyuday Godhasara eve_data->cb_type = PM_NOTIFY_CB;
116c7fdb240SAbhyuday Godhasara eve_data->wake = wake;
11705e5ba40SAbhyuday Godhasara INIT_LIST_HEAD(&eve_data->cb_list_head);
118c7fdb240SAbhyuday Godhasara
11905e5ba40SAbhyuday Godhasara cb_data = kmalloc(sizeof(*cb_data), GFP_KERNEL);
1201bea5349SGaosheng Cui if (!cb_data) {
1211bea5349SGaosheng Cui kfree(eve_data);
12205e5ba40SAbhyuday Godhasara return -ENOMEM;
1231bea5349SGaosheng Cui }
12405e5ba40SAbhyuday Godhasara cb_data->eve_cb = cb_fun;
12505e5ba40SAbhyuday Godhasara cb_data->agent_data = data;
12605e5ba40SAbhyuday Godhasara
12705e5ba40SAbhyuday Godhasara /* Add into callback list */
12805e5ba40SAbhyuday Godhasara list_add(&cb_data->list, &eve_data->cb_list_head);
12905e5ba40SAbhyuday Godhasara
13005e5ba40SAbhyuday Godhasara /* Add into HASH table */
131c7fdb240SAbhyuday Godhasara hash_add(reg_driver_map, &eve_data->hentry, key);
13205e5ba40SAbhyuday Godhasara } else {
13305e5ba40SAbhyuday Godhasara /* Search for callback function and private data in list */
13405e5ba40SAbhyuday Godhasara list_for_each_entry_safe(cb_pos, cb_next, &eve_data->cb_list_head, list) {
13505e5ba40SAbhyuday Godhasara if (cb_pos->eve_cb == cb_fun &&
13605e5ba40SAbhyuday Godhasara cb_pos->agent_data == data) {
13705e5ba40SAbhyuday Godhasara return 0;
13805e5ba40SAbhyuday Godhasara }
13905e5ba40SAbhyuday Godhasara }
14005e5ba40SAbhyuday Godhasara
14105e5ba40SAbhyuday Godhasara /* Add multiple handler and private data in list */
14205e5ba40SAbhyuday Godhasara cb_data = kmalloc(sizeof(*cb_data), GFP_KERNEL);
14305e5ba40SAbhyuday Godhasara if (!cb_data)
14405e5ba40SAbhyuday Godhasara return -ENOMEM;
14505e5ba40SAbhyuday Godhasara cb_data->eve_cb = cb_fun;
14605e5ba40SAbhyuday Godhasara cb_data->agent_data = data;
14705e5ba40SAbhyuday Godhasara
14805e5ba40SAbhyuday Godhasara list_add(&cb_data->list, &eve_data->cb_list_head);
14905e5ba40SAbhyuday Godhasara }
150c7fdb240SAbhyuday Godhasara
151c7fdb240SAbhyuday Godhasara return 0;
152c7fdb240SAbhyuday Godhasara }
153c7fdb240SAbhyuday Godhasara
xlnx_add_cb_for_suspend(event_cb_func_t cb_fun,void * data)154c7fdb240SAbhyuday Godhasara static int xlnx_add_cb_for_suspend(event_cb_func_t cb_fun, void *data)
155c7fdb240SAbhyuday Godhasara {
156c7fdb240SAbhyuday Godhasara struct registered_event_data *eve_data;
15705e5ba40SAbhyuday Godhasara struct agent_cb *cb_data;
158c7fdb240SAbhyuday Godhasara
159c7fdb240SAbhyuday Godhasara /* Check for existing entry in hash table for given cb_type */
160c7fdb240SAbhyuday Godhasara hash_for_each_possible(reg_driver_map, eve_data, hentry, PM_INIT_SUSPEND_CB) {
161c7fdb240SAbhyuday Godhasara if (eve_data->cb_type == PM_INIT_SUSPEND_CB) {
162c7fdb240SAbhyuday Godhasara pr_err("Found as already registered\n");
163c7fdb240SAbhyuday Godhasara return -EINVAL;
164c7fdb240SAbhyuday Godhasara }
165c7fdb240SAbhyuday Godhasara }
166c7fdb240SAbhyuday Godhasara
167c7fdb240SAbhyuday Godhasara /* Add new entry if not present */
168c7fdb240SAbhyuday Godhasara eve_data = kmalloc(sizeof(*eve_data), GFP_KERNEL);
169c7fdb240SAbhyuday Godhasara if (!eve_data)
170c7fdb240SAbhyuday Godhasara return -ENOMEM;
171c7fdb240SAbhyuday Godhasara
172c7fdb240SAbhyuday Godhasara eve_data->key = 0;
173c7fdb240SAbhyuday Godhasara eve_data->cb_type = PM_INIT_SUSPEND_CB;
17405e5ba40SAbhyuday Godhasara INIT_LIST_HEAD(&eve_data->cb_list_head);
17505e5ba40SAbhyuday Godhasara
17605e5ba40SAbhyuday Godhasara cb_data = kmalloc(sizeof(*cb_data), GFP_KERNEL);
177*882d7afaSGaosheng Cui if (!cb_data) {
178*882d7afaSGaosheng Cui kfree(eve_data);
17905e5ba40SAbhyuday Godhasara return -ENOMEM;
180*882d7afaSGaosheng Cui }
18105e5ba40SAbhyuday Godhasara cb_data->eve_cb = cb_fun;
18205e5ba40SAbhyuday Godhasara cb_data->agent_data = data;
18305e5ba40SAbhyuday Godhasara
18405e5ba40SAbhyuday Godhasara /* Add into callback list */
18505e5ba40SAbhyuday Godhasara list_add(&cb_data->list, &eve_data->cb_list_head);
186c7fdb240SAbhyuday Godhasara
187c7fdb240SAbhyuday Godhasara hash_add(reg_driver_map, &eve_data->hentry, PM_INIT_SUSPEND_CB);
188c7fdb240SAbhyuday Godhasara
189c7fdb240SAbhyuday Godhasara return 0;
190c7fdb240SAbhyuday Godhasara }
191c7fdb240SAbhyuday Godhasara
xlnx_remove_cb_for_suspend(event_cb_func_t cb_fun)192c7fdb240SAbhyuday Godhasara static int xlnx_remove_cb_for_suspend(event_cb_func_t cb_fun)
193c7fdb240SAbhyuday Godhasara {
194c7fdb240SAbhyuday Godhasara bool is_callback_found = false;
195c7fdb240SAbhyuday Godhasara struct registered_event_data *eve_data;
19605e5ba40SAbhyuday Godhasara struct agent_cb *cb_pos;
19705e5ba40SAbhyuday Godhasara struct agent_cb *cb_next;
198c58da0baSDan Carpenter struct hlist_node *tmp;
199c7fdb240SAbhyuday Godhasara
200e6d3c99aSAbhyuday Godhasara is_need_to_unregister = false;
201e6d3c99aSAbhyuday Godhasara
202c7fdb240SAbhyuday Godhasara /* Check for existing entry in hash table for given cb_type */
203c58da0baSDan Carpenter hash_for_each_possible_safe(reg_driver_map, eve_data, tmp, hentry, PM_INIT_SUSPEND_CB) {
20405e5ba40SAbhyuday Godhasara if (eve_data->cb_type == PM_INIT_SUSPEND_CB) {
20505e5ba40SAbhyuday Godhasara /* Delete the list of callback */
20605e5ba40SAbhyuday Godhasara list_for_each_entry_safe(cb_pos, cb_next, &eve_data->cb_list_head, list) {
20705e5ba40SAbhyuday Godhasara if (cb_pos->eve_cb == cb_fun) {
208c7fdb240SAbhyuday Godhasara is_callback_found = true;
20905e5ba40SAbhyuday Godhasara list_del_init(&cb_pos->list);
21005e5ba40SAbhyuday Godhasara kfree(cb_pos);
21105e5ba40SAbhyuday Godhasara }
21205e5ba40SAbhyuday Godhasara }
213c7fdb240SAbhyuday Godhasara /* remove an object from a hashtable */
214c7fdb240SAbhyuday Godhasara hash_del(&eve_data->hentry);
215c7fdb240SAbhyuday Godhasara kfree(eve_data);
216e6d3c99aSAbhyuday Godhasara is_need_to_unregister = true;
217c7fdb240SAbhyuday Godhasara }
218c7fdb240SAbhyuday Godhasara }
219c7fdb240SAbhyuday Godhasara if (!is_callback_found) {
220c7fdb240SAbhyuday Godhasara pr_warn("Didn't find any registered callback for suspend event\n");
221c7fdb240SAbhyuday Godhasara return -EINVAL;
222c7fdb240SAbhyuday Godhasara }
223c7fdb240SAbhyuday Godhasara
224c7fdb240SAbhyuday Godhasara return 0;
225c7fdb240SAbhyuday Godhasara }
226c7fdb240SAbhyuday Godhasara
xlnx_remove_cb_for_notify_event(const u32 node_id,const u32 event,event_cb_func_t cb_fun,void * data)227c7fdb240SAbhyuday Godhasara static int xlnx_remove_cb_for_notify_event(const u32 node_id, const u32 event,
228e6d3c99aSAbhyuday Godhasara event_cb_func_t cb_fun, void *data)
229c7fdb240SAbhyuday Godhasara {
230c7fdb240SAbhyuday Godhasara bool is_callback_found = false;
231c7fdb240SAbhyuday Godhasara struct registered_event_data *eve_data;
232c7fdb240SAbhyuday Godhasara u64 key = ((u64)node_id << 32U) | (u64)event;
23305e5ba40SAbhyuday Godhasara struct agent_cb *cb_pos;
23405e5ba40SAbhyuday Godhasara struct agent_cb *cb_next;
235c58da0baSDan Carpenter struct hlist_node *tmp;
236c7fdb240SAbhyuday Godhasara
237e6d3c99aSAbhyuday Godhasara is_need_to_unregister = false;
238e6d3c99aSAbhyuday Godhasara
239c7fdb240SAbhyuday Godhasara /* Check for existing entry in hash table for given key id */
240c58da0baSDan Carpenter hash_for_each_possible_safe(reg_driver_map, eve_data, tmp, hentry, key) {
24105e5ba40SAbhyuday Godhasara if (eve_data->key == key) {
24205e5ba40SAbhyuday Godhasara /* Delete the list of callback */
24305e5ba40SAbhyuday Godhasara list_for_each_entry_safe(cb_pos, cb_next, &eve_data->cb_list_head, list) {
244e6d3c99aSAbhyuday Godhasara if (cb_pos->eve_cb == cb_fun &&
245e6d3c99aSAbhyuday Godhasara cb_pos->agent_data == data) {
246c7fdb240SAbhyuday Godhasara is_callback_found = true;
24705e5ba40SAbhyuday Godhasara list_del_init(&cb_pos->list);
24805e5ba40SAbhyuday Godhasara kfree(cb_pos);
24905e5ba40SAbhyuday Godhasara }
25005e5ba40SAbhyuday Godhasara }
251e6d3c99aSAbhyuday Godhasara
252e6d3c99aSAbhyuday Godhasara /* Remove HASH table if callback list is empty */
253e6d3c99aSAbhyuday Godhasara if (list_empty(&eve_data->cb_list_head)) {
25405e5ba40SAbhyuday Godhasara /* remove an object from a HASH table */
255c7fdb240SAbhyuday Godhasara hash_del(&eve_data->hentry);
256c7fdb240SAbhyuday Godhasara kfree(eve_data);
257e6d3c99aSAbhyuday Godhasara is_need_to_unregister = true;
258e6d3c99aSAbhyuday Godhasara }
259c7fdb240SAbhyuday Godhasara }
260c7fdb240SAbhyuday Godhasara }
261c7fdb240SAbhyuday Godhasara if (!is_callback_found) {
262c7fdb240SAbhyuday Godhasara pr_warn("Didn't find any registered callback for 0x%x 0x%x\n",
263c7fdb240SAbhyuday Godhasara node_id, event);
264c7fdb240SAbhyuday Godhasara return -EINVAL;
265c7fdb240SAbhyuday Godhasara }
266c7fdb240SAbhyuday Godhasara
267c7fdb240SAbhyuday Godhasara return 0;
268c7fdb240SAbhyuday Godhasara }
269c7fdb240SAbhyuday Godhasara
270c7fdb240SAbhyuday Godhasara /**
271c7fdb240SAbhyuday Godhasara * xlnx_register_event() - Register for the event.
272c7fdb240SAbhyuday Godhasara * @cb_type: Type of callback from pm_api_cb_id,
273c7fdb240SAbhyuday Godhasara * PM_NOTIFY_CB - for Error Events,
274c7fdb240SAbhyuday Godhasara * PM_INIT_SUSPEND_CB - for suspend callback.
275c7fdb240SAbhyuday Godhasara * @node_id: Node-Id related to event.
276c7fdb240SAbhyuday Godhasara * @event: Event Mask for the Error Event.
277c7fdb240SAbhyuday Godhasara * @wake: Flag specifying whether the subsystem should be woken upon
278c7fdb240SAbhyuday Godhasara * event notification.
279c7fdb240SAbhyuday Godhasara * @cb_fun: Function pointer to store the callback function.
280c7fdb240SAbhyuday Godhasara * @data: Pointer for the driver instance.
281c7fdb240SAbhyuday Godhasara *
282c7fdb240SAbhyuday Godhasara * Return: Returns 0 on successful registration else error code.
283c7fdb240SAbhyuday Godhasara */
xlnx_register_event(const enum pm_api_cb_id cb_type,const u32 node_id,const u32 event,const bool wake,event_cb_func_t cb_fun,void * data)284c7fdb240SAbhyuday Godhasara int xlnx_register_event(const enum pm_api_cb_id cb_type, const u32 node_id, const u32 event,
285c7fdb240SAbhyuday Godhasara const bool wake, event_cb_func_t cb_fun, void *data)
286c7fdb240SAbhyuday Godhasara {
287c7fdb240SAbhyuday Godhasara int ret = 0;
288c7fdb240SAbhyuday Godhasara u32 eve;
289c7fdb240SAbhyuday Godhasara int pos;
290c7fdb240SAbhyuday Godhasara
291c7fdb240SAbhyuday Godhasara if (event_manager_availability)
292c7fdb240SAbhyuday Godhasara return event_manager_availability;
293c7fdb240SAbhyuday Godhasara
294c7fdb240SAbhyuday Godhasara if (cb_type != PM_NOTIFY_CB && cb_type != PM_INIT_SUSPEND_CB) {
295c7fdb240SAbhyuday Godhasara pr_err("%s() Unsupported Callback 0x%x\n", __func__, cb_type);
296c7fdb240SAbhyuday Godhasara return -EINVAL;
297c7fdb240SAbhyuday Godhasara }
298c7fdb240SAbhyuday Godhasara
299c7fdb240SAbhyuday Godhasara if (!cb_fun)
300c7fdb240SAbhyuday Godhasara return -EFAULT;
301c7fdb240SAbhyuday Godhasara
302c7fdb240SAbhyuday Godhasara if (cb_type == PM_INIT_SUSPEND_CB) {
303c7fdb240SAbhyuday Godhasara ret = xlnx_add_cb_for_suspend(cb_fun, data);
304c7fdb240SAbhyuday Godhasara } else {
305c7fdb240SAbhyuday Godhasara if (!xlnx_is_error_event(node_id)) {
306c7fdb240SAbhyuday Godhasara /* Add entry for Node-Id/Event in hash table */
307c7fdb240SAbhyuday Godhasara ret = xlnx_add_cb_for_notify_event(node_id, event, wake, cb_fun, data);
308c7fdb240SAbhyuday Godhasara } else {
309c7fdb240SAbhyuday Godhasara /* Add into Hash table */
310c7fdb240SAbhyuday Godhasara for (pos = 0; pos < MAX_BITS; pos++) {
311c7fdb240SAbhyuday Godhasara eve = event & (1 << pos);
312c7fdb240SAbhyuday Godhasara if (!eve)
313c7fdb240SAbhyuday Godhasara continue;
314c7fdb240SAbhyuday Godhasara
315c7fdb240SAbhyuday Godhasara /* Add entry for Node-Id/Eve in hash table */
316c7fdb240SAbhyuday Godhasara ret = xlnx_add_cb_for_notify_event(node_id, eve, wake, cb_fun,
317c7fdb240SAbhyuday Godhasara data);
318c7fdb240SAbhyuday Godhasara /* Break the loop if got error */
319c7fdb240SAbhyuday Godhasara if (ret)
320c7fdb240SAbhyuday Godhasara break;
321c7fdb240SAbhyuday Godhasara }
322c7fdb240SAbhyuday Godhasara if (ret) {
323c7fdb240SAbhyuday Godhasara /* Skip the Event for which got the error */
324c7fdb240SAbhyuday Godhasara pos--;
325c7fdb240SAbhyuday Godhasara /* Remove registered(during this call) event from hash table */
326c7fdb240SAbhyuday Godhasara for ( ; pos >= 0; pos--) {
327c7fdb240SAbhyuday Godhasara eve = event & (1 << pos);
328c7fdb240SAbhyuday Godhasara if (!eve)
329c7fdb240SAbhyuday Godhasara continue;
330e6d3c99aSAbhyuday Godhasara xlnx_remove_cb_for_notify_event(node_id, eve, cb_fun, data);
331c7fdb240SAbhyuday Godhasara }
332c7fdb240SAbhyuday Godhasara }
333c7fdb240SAbhyuday Godhasara }
334c7fdb240SAbhyuday Godhasara
335c7fdb240SAbhyuday Godhasara if (ret) {
336c7fdb240SAbhyuday Godhasara pr_err("%s() failed for 0x%x and 0x%x: %d\r\n", __func__, node_id,
337c7fdb240SAbhyuday Godhasara event, ret);
338c7fdb240SAbhyuday Godhasara return ret;
339c7fdb240SAbhyuday Godhasara }
340c7fdb240SAbhyuday Godhasara
341c7fdb240SAbhyuday Godhasara /* Register for Node-Id/Event combination in firmware */
342c7fdb240SAbhyuday Godhasara ret = zynqmp_pm_register_notifier(node_id, event, wake, true);
343c7fdb240SAbhyuday Godhasara if (ret) {
344c7fdb240SAbhyuday Godhasara pr_err("%s() failed for 0x%x and 0x%x: %d\r\n", __func__, node_id,
345c7fdb240SAbhyuday Godhasara event, ret);
346c7fdb240SAbhyuday Godhasara /* Remove already registered event from hash table */
347c7fdb240SAbhyuday Godhasara if (xlnx_is_error_event(node_id)) {
348c7fdb240SAbhyuday Godhasara for (pos = 0; pos < MAX_BITS; pos++) {
349c7fdb240SAbhyuday Godhasara eve = event & (1 << pos);
350c7fdb240SAbhyuday Godhasara if (!eve)
351c7fdb240SAbhyuday Godhasara continue;
352e6d3c99aSAbhyuday Godhasara xlnx_remove_cb_for_notify_event(node_id, eve, cb_fun, data);
353c7fdb240SAbhyuday Godhasara }
354c7fdb240SAbhyuday Godhasara } else {
355e6d3c99aSAbhyuday Godhasara xlnx_remove_cb_for_notify_event(node_id, event, cb_fun, data);
356c7fdb240SAbhyuday Godhasara }
357c7fdb240SAbhyuday Godhasara return ret;
358c7fdb240SAbhyuday Godhasara }
359c7fdb240SAbhyuday Godhasara }
360c7fdb240SAbhyuday Godhasara
361c7fdb240SAbhyuday Godhasara return ret;
362c7fdb240SAbhyuday Godhasara }
363c7fdb240SAbhyuday Godhasara EXPORT_SYMBOL_GPL(xlnx_register_event);
364c7fdb240SAbhyuday Godhasara
365c7fdb240SAbhyuday Godhasara /**
366c7fdb240SAbhyuday Godhasara * xlnx_unregister_event() - Unregister for the event.
367c7fdb240SAbhyuday Godhasara * @cb_type: Type of callback from pm_api_cb_id,
368c7fdb240SAbhyuday Godhasara * PM_NOTIFY_CB - for Error Events,
369c7fdb240SAbhyuday Godhasara * PM_INIT_SUSPEND_CB - for suspend callback.
370c7fdb240SAbhyuday Godhasara * @node_id: Node-Id related to event.
371c7fdb240SAbhyuday Godhasara * @event: Event Mask for the Error Event.
372c7fdb240SAbhyuday Godhasara * @cb_fun: Function pointer of callback function.
373e6d3c99aSAbhyuday Godhasara * @data: Pointer of agent's private data.
374c7fdb240SAbhyuday Godhasara *
375c7fdb240SAbhyuday Godhasara * Return: Returns 0 on successful unregistration else error code.
376c7fdb240SAbhyuday Godhasara */
xlnx_unregister_event(const enum pm_api_cb_id cb_type,const u32 node_id,const u32 event,event_cb_func_t cb_fun,void * data)377c7fdb240SAbhyuday Godhasara int xlnx_unregister_event(const enum pm_api_cb_id cb_type, const u32 node_id, const u32 event,
378e6d3c99aSAbhyuday Godhasara event_cb_func_t cb_fun, void *data)
379c7fdb240SAbhyuday Godhasara {
380e6d3c99aSAbhyuday Godhasara int ret = 0;
381c7fdb240SAbhyuday Godhasara u32 eve, pos;
382c7fdb240SAbhyuday Godhasara
383e6d3c99aSAbhyuday Godhasara is_need_to_unregister = false;
384e6d3c99aSAbhyuday Godhasara
385c7fdb240SAbhyuday Godhasara if (event_manager_availability)
386c7fdb240SAbhyuday Godhasara return event_manager_availability;
387c7fdb240SAbhyuday Godhasara
388c7fdb240SAbhyuday Godhasara if (cb_type != PM_NOTIFY_CB && cb_type != PM_INIT_SUSPEND_CB) {
389c7fdb240SAbhyuday Godhasara pr_err("%s() Unsupported Callback 0x%x\n", __func__, cb_type);
390c7fdb240SAbhyuday Godhasara return -EINVAL;
391c7fdb240SAbhyuday Godhasara }
392c7fdb240SAbhyuday Godhasara
393c7fdb240SAbhyuday Godhasara if (!cb_fun)
394c7fdb240SAbhyuday Godhasara return -EFAULT;
395c7fdb240SAbhyuday Godhasara
396c7fdb240SAbhyuday Godhasara if (cb_type == PM_INIT_SUSPEND_CB) {
397c7fdb240SAbhyuday Godhasara ret = xlnx_remove_cb_for_suspend(cb_fun);
398c7fdb240SAbhyuday Godhasara } else {
399c7fdb240SAbhyuday Godhasara /* Remove Node-Id/Event from hash table */
400c7fdb240SAbhyuday Godhasara if (!xlnx_is_error_event(node_id)) {
401e6d3c99aSAbhyuday Godhasara xlnx_remove_cb_for_notify_event(node_id, event, cb_fun, data);
402c7fdb240SAbhyuday Godhasara } else {
403c7fdb240SAbhyuday Godhasara for (pos = 0; pos < MAX_BITS; pos++) {
404c7fdb240SAbhyuday Godhasara eve = event & (1 << pos);
405c7fdb240SAbhyuday Godhasara if (!eve)
406c7fdb240SAbhyuday Godhasara continue;
407c7fdb240SAbhyuday Godhasara
408e6d3c99aSAbhyuday Godhasara xlnx_remove_cb_for_notify_event(node_id, eve, cb_fun, data);
409c7fdb240SAbhyuday Godhasara }
410c7fdb240SAbhyuday Godhasara }
411c7fdb240SAbhyuday Godhasara
412e6d3c99aSAbhyuday Godhasara /* Un-register if list is empty */
413e6d3c99aSAbhyuday Godhasara if (is_need_to_unregister) {
414c7fdb240SAbhyuday Godhasara /* Un-register for Node-Id/Event combination */
415c7fdb240SAbhyuday Godhasara ret = zynqmp_pm_register_notifier(node_id, event, false, false);
416c7fdb240SAbhyuday Godhasara if (ret) {
417c7fdb240SAbhyuday Godhasara pr_err("%s() failed for 0x%x and 0x%x: %d\n",
418c7fdb240SAbhyuday Godhasara __func__, node_id, event, ret);
419c7fdb240SAbhyuday Godhasara return ret;
420c7fdb240SAbhyuday Godhasara }
421c7fdb240SAbhyuday Godhasara }
422e6d3c99aSAbhyuday Godhasara }
423c7fdb240SAbhyuday Godhasara
424c7fdb240SAbhyuday Godhasara return ret;
425c7fdb240SAbhyuday Godhasara }
426c7fdb240SAbhyuday Godhasara EXPORT_SYMBOL_GPL(xlnx_unregister_event);
427c7fdb240SAbhyuday Godhasara
xlnx_call_suspend_cb_handler(const u32 * payload)428c7fdb240SAbhyuday Godhasara static void xlnx_call_suspend_cb_handler(const u32 *payload)
429c7fdb240SAbhyuday Godhasara {
430c7fdb240SAbhyuday Godhasara bool is_callback_found = false;
431c7fdb240SAbhyuday Godhasara struct registered_event_data *eve_data;
432c7fdb240SAbhyuday Godhasara u32 cb_type = payload[0];
43305e5ba40SAbhyuday Godhasara struct agent_cb *cb_pos;
43405e5ba40SAbhyuday Godhasara struct agent_cb *cb_next;
435c7fdb240SAbhyuday Godhasara
436c7fdb240SAbhyuday Godhasara /* Check for existing entry in hash table for given cb_type */
437c7fdb240SAbhyuday Godhasara hash_for_each_possible(reg_driver_map, eve_data, hentry, cb_type) {
438c7fdb240SAbhyuday Godhasara if (eve_data->cb_type == cb_type) {
43905e5ba40SAbhyuday Godhasara list_for_each_entry_safe(cb_pos, cb_next, &eve_data->cb_list_head, list) {
44005e5ba40SAbhyuday Godhasara cb_pos->eve_cb(&payload[0], cb_pos->agent_data);
441c7fdb240SAbhyuday Godhasara is_callback_found = true;
442c7fdb240SAbhyuday Godhasara }
443c7fdb240SAbhyuday Godhasara }
44405e5ba40SAbhyuday Godhasara }
445c7fdb240SAbhyuday Godhasara if (!is_callback_found)
446c7fdb240SAbhyuday Godhasara pr_warn("Didn't find any registered callback for suspend event\n");
447c7fdb240SAbhyuday Godhasara }
448c7fdb240SAbhyuday Godhasara
xlnx_call_notify_cb_handler(const u32 * payload)449c7fdb240SAbhyuday Godhasara static void xlnx_call_notify_cb_handler(const u32 *payload)
450c7fdb240SAbhyuday Godhasara {
451c7fdb240SAbhyuday Godhasara bool is_callback_found = false;
452c7fdb240SAbhyuday Godhasara struct registered_event_data *eve_data;
453c7fdb240SAbhyuday Godhasara u64 key = ((u64)payload[1] << 32U) | (u64)payload[2];
454c7fdb240SAbhyuday Godhasara int ret;
45505e5ba40SAbhyuday Godhasara struct agent_cb *cb_pos;
45605e5ba40SAbhyuday Godhasara struct agent_cb *cb_next;
457c7fdb240SAbhyuday Godhasara
458c7fdb240SAbhyuday Godhasara /* Check for existing entry in hash table for given key id */
459c7fdb240SAbhyuday Godhasara hash_for_each_possible(reg_driver_map, eve_data, hentry, key) {
460c7fdb240SAbhyuday Godhasara if (eve_data->key == key) {
46105e5ba40SAbhyuday Godhasara list_for_each_entry_safe(cb_pos, cb_next, &eve_data->cb_list_head, list) {
46205e5ba40SAbhyuday Godhasara cb_pos->eve_cb(&payload[0], cb_pos->agent_data);
463c7fdb240SAbhyuday Godhasara is_callback_found = true;
46405e5ba40SAbhyuday Godhasara }
465c7fdb240SAbhyuday Godhasara
466c7fdb240SAbhyuday Godhasara /* re register with firmware to get future events */
467c7fdb240SAbhyuday Godhasara ret = zynqmp_pm_register_notifier(payload[1], payload[2],
468c7fdb240SAbhyuday Godhasara eve_data->wake, true);
469c7fdb240SAbhyuday Godhasara if (ret) {
470c7fdb240SAbhyuday Godhasara pr_err("%s() failed for 0x%x and 0x%x: %d\r\n", __func__,
471c7fdb240SAbhyuday Godhasara payload[1], payload[2], ret);
47205e5ba40SAbhyuday Godhasara list_for_each_entry_safe(cb_pos, cb_next, &eve_data->cb_list_head,
47305e5ba40SAbhyuday Godhasara list) {
474c7fdb240SAbhyuday Godhasara /* Remove already registered event from hash table */
475c7fdb240SAbhyuday Godhasara xlnx_remove_cb_for_notify_event(payload[1], payload[2],
476e6d3c99aSAbhyuday Godhasara cb_pos->eve_cb,
477e6d3c99aSAbhyuday Godhasara cb_pos->agent_data);
47805e5ba40SAbhyuday Godhasara }
479c7fdb240SAbhyuday Godhasara }
480c7fdb240SAbhyuday Godhasara }
481c7fdb240SAbhyuday Godhasara }
482c7fdb240SAbhyuday Godhasara if (!is_callback_found)
48361cc78beSTanmay Shah pr_warn("Unhandled SGI node 0x%x event 0x%x. Expected with Xen hypervisor\n",
484c7fdb240SAbhyuday Godhasara payload[1], payload[2]);
485c7fdb240SAbhyuday Godhasara }
486c7fdb240SAbhyuday Godhasara
xlnx_get_event_callback_data(u32 * buf)487c7fdb240SAbhyuday Godhasara static void xlnx_get_event_callback_data(u32 *buf)
488c7fdb240SAbhyuday Godhasara {
489c7fdb240SAbhyuday Godhasara zynqmp_pm_invoke_fn(GET_CALLBACK_DATA, 0, 0, 0, 0, buf);
490c7fdb240SAbhyuday Godhasara }
491c7fdb240SAbhyuday Godhasara
xlnx_event_handler(int irq,void * dev_id)492c7fdb240SAbhyuday Godhasara static irqreturn_t xlnx_event_handler(int irq, void *dev_id)
493c7fdb240SAbhyuday Godhasara {
494c7fdb240SAbhyuday Godhasara u32 cb_type, node_id, event, pos;
495c7fdb240SAbhyuday Godhasara u32 payload[CB_MAX_PAYLOAD_SIZE] = {0};
496c7fdb240SAbhyuday Godhasara u32 event_data[CB_MAX_PAYLOAD_SIZE] = {0};
497c7fdb240SAbhyuday Godhasara
498c7fdb240SAbhyuday Godhasara /* Get event data */
499c7fdb240SAbhyuday Godhasara xlnx_get_event_callback_data(payload);
500c7fdb240SAbhyuday Godhasara
501c7fdb240SAbhyuday Godhasara /* First element is callback type, others are callback arguments */
502c7fdb240SAbhyuday Godhasara cb_type = payload[0];
503c7fdb240SAbhyuday Godhasara
504c7fdb240SAbhyuday Godhasara if (cb_type == PM_NOTIFY_CB) {
505c7fdb240SAbhyuday Godhasara node_id = payload[1];
506c7fdb240SAbhyuday Godhasara event = payload[2];
507c7fdb240SAbhyuday Godhasara if (!xlnx_is_error_event(node_id)) {
508c7fdb240SAbhyuday Godhasara xlnx_call_notify_cb_handler(payload);
509c7fdb240SAbhyuday Godhasara } else {
510c7fdb240SAbhyuday Godhasara /*
511c7fdb240SAbhyuday Godhasara * Each call back function expecting payload as an input arguments.
512c7fdb240SAbhyuday Godhasara * We can get multiple error events as in one call back through error
513c7fdb240SAbhyuday Godhasara * mask. So payload[2] may can contain multiple error events.
514c7fdb240SAbhyuday Godhasara * In reg_driver_map database we store data in the combination of single
515c7fdb240SAbhyuday Godhasara * node_id-error combination.
516c7fdb240SAbhyuday Godhasara * So coping the payload message into event_data and update the
517c7fdb240SAbhyuday Godhasara * event_data[2] with Error Mask for single error event and use
518c7fdb240SAbhyuday Godhasara * event_data as input argument for registered call back function.
519c7fdb240SAbhyuday Godhasara *
520c7fdb240SAbhyuday Godhasara */
521c7fdb240SAbhyuday Godhasara memcpy(event_data, payload, (4 * CB_MAX_PAYLOAD_SIZE));
522c7fdb240SAbhyuday Godhasara /* Support Multiple Error Event */
523c7fdb240SAbhyuday Godhasara for (pos = 0; pos < MAX_BITS; pos++) {
524c7fdb240SAbhyuday Godhasara if ((0 == (event & (1 << pos))))
525c7fdb240SAbhyuday Godhasara continue;
526c7fdb240SAbhyuday Godhasara event_data[2] = (event & (1 << pos));
527c7fdb240SAbhyuday Godhasara xlnx_call_notify_cb_handler(event_data);
528c7fdb240SAbhyuday Godhasara }
529c7fdb240SAbhyuday Godhasara }
530c7fdb240SAbhyuday Godhasara } else if (cb_type == PM_INIT_SUSPEND_CB) {
531c7fdb240SAbhyuday Godhasara xlnx_call_suspend_cb_handler(payload);
532c7fdb240SAbhyuday Godhasara } else {
533c7fdb240SAbhyuday Godhasara pr_err("%s() Unsupported Callback %d\n", __func__, cb_type);
534c7fdb240SAbhyuday Godhasara }
535c7fdb240SAbhyuday Godhasara
536c7fdb240SAbhyuday Godhasara return IRQ_HANDLED;
537c7fdb240SAbhyuday Godhasara }
538c7fdb240SAbhyuday Godhasara
xlnx_event_cpuhp_start(unsigned int cpu)539c7fdb240SAbhyuday Godhasara static int xlnx_event_cpuhp_start(unsigned int cpu)
540c7fdb240SAbhyuday Godhasara {
541c7fdb240SAbhyuday Godhasara enable_percpu_irq(virq_sgi, IRQ_TYPE_NONE);
542c7fdb240SAbhyuday Godhasara
543c7fdb240SAbhyuday Godhasara return 0;
544c7fdb240SAbhyuday Godhasara }
545c7fdb240SAbhyuday Godhasara
xlnx_event_cpuhp_down(unsigned int cpu)546c7fdb240SAbhyuday Godhasara static int xlnx_event_cpuhp_down(unsigned int cpu)
547c7fdb240SAbhyuday Godhasara {
548c7fdb240SAbhyuday Godhasara disable_percpu_irq(virq_sgi);
549c7fdb240SAbhyuday Godhasara
550c7fdb240SAbhyuday Godhasara return 0;
551c7fdb240SAbhyuday Godhasara }
552c7fdb240SAbhyuday Godhasara
xlnx_disable_percpu_irq(void * data)553c7fdb240SAbhyuday Godhasara static void xlnx_disable_percpu_irq(void *data)
554c7fdb240SAbhyuday Godhasara {
555c7fdb240SAbhyuday Godhasara disable_percpu_irq(virq_sgi);
556c7fdb240SAbhyuday Godhasara }
557c7fdb240SAbhyuday Godhasara
xlnx_event_init_sgi(struct platform_device * pdev)558c7fdb240SAbhyuday Godhasara static int xlnx_event_init_sgi(struct platform_device *pdev)
559c7fdb240SAbhyuday Godhasara {
560c7fdb240SAbhyuday Godhasara int ret = 0;
561c7fdb240SAbhyuday Godhasara /*
562c7fdb240SAbhyuday Godhasara * IRQ related structures are used for the following:
563c7fdb240SAbhyuday Godhasara * for each SGI interrupt ensure its mapped by GIC IRQ domain
564c7fdb240SAbhyuday Godhasara * and that each corresponding linux IRQ for the HW IRQ has
565c7fdb240SAbhyuday Godhasara * a handler for when receiving an interrupt from the remote
566c7fdb240SAbhyuday Godhasara * processor.
567c7fdb240SAbhyuday Godhasara */
568c7fdb240SAbhyuday Godhasara struct irq_domain *domain;
569c7fdb240SAbhyuday Godhasara struct irq_fwspec sgi_fwspec;
570c7fdb240SAbhyuday Godhasara struct device_node *interrupt_parent = NULL;
571c7fdb240SAbhyuday Godhasara struct device *parent = pdev->dev.parent;
572c7fdb240SAbhyuday Godhasara
573c7fdb240SAbhyuday Godhasara /* Find GIC controller to map SGIs. */
574c7fdb240SAbhyuday Godhasara interrupt_parent = of_irq_find_parent(parent->of_node);
575c7fdb240SAbhyuday Godhasara if (!interrupt_parent) {
576c7fdb240SAbhyuday Godhasara dev_err(&pdev->dev, "Failed to find property for Interrupt parent\n");
577c7fdb240SAbhyuday Godhasara return -EINVAL;
578c7fdb240SAbhyuday Godhasara }
579c7fdb240SAbhyuday Godhasara
580c7fdb240SAbhyuday Godhasara /* Each SGI needs to be associated with GIC's IRQ domain. */
581c7fdb240SAbhyuday Godhasara domain = irq_find_host(interrupt_parent);
582c7fdb240SAbhyuday Godhasara of_node_put(interrupt_parent);
583c7fdb240SAbhyuday Godhasara
584c7fdb240SAbhyuday Godhasara /* Each mapping needs GIC domain when finding IRQ mapping. */
585c7fdb240SAbhyuday Godhasara sgi_fwspec.fwnode = domain->fwnode;
586c7fdb240SAbhyuday Godhasara
587c7fdb240SAbhyuday Godhasara /*
588c7fdb240SAbhyuday Godhasara * When irq domain looks at mapping each arg is as follows:
589c7fdb240SAbhyuday Godhasara * 3 args for: interrupt type (SGI), interrupt # (set later), type
590c7fdb240SAbhyuday Godhasara */
591c7fdb240SAbhyuday Godhasara sgi_fwspec.param_count = 1;
592c7fdb240SAbhyuday Godhasara
593c7fdb240SAbhyuday Godhasara /* Set SGI's hwirq */
594c7fdb240SAbhyuday Godhasara sgi_fwspec.param[0] = sgi_num;
595c7fdb240SAbhyuday Godhasara virq_sgi = irq_create_fwspec_mapping(&sgi_fwspec);
596c7fdb240SAbhyuday Godhasara
597c7fdb240SAbhyuday Godhasara ret = request_percpu_irq(virq_sgi, xlnx_event_handler, "xlnx_event_mgmt",
598a96e60a6SJay Buddhabhatti &dummy_cpu_number);
5994722924eSHariBabu Gattem
600c7fdb240SAbhyuday Godhasara WARN_ON(ret);
601c7fdb240SAbhyuday Godhasara if (ret) {
602c7fdb240SAbhyuday Godhasara irq_dispose_mapping(virq_sgi);
603c7fdb240SAbhyuday Godhasara return ret;
604c7fdb240SAbhyuday Godhasara }
605c7fdb240SAbhyuday Godhasara
606c7fdb240SAbhyuday Godhasara irq_to_desc(virq_sgi);
607c7fdb240SAbhyuday Godhasara irq_set_status_flags(virq_sgi, IRQ_PER_CPU);
608c7fdb240SAbhyuday Godhasara
609c7fdb240SAbhyuday Godhasara return ret;
610c7fdb240SAbhyuday Godhasara }
611c7fdb240SAbhyuday Godhasara
xlnx_event_cleanup_sgi(struct platform_device * pdev)612c7fdb240SAbhyuday Godhasara static void xlnx_event_cleanup_sgi(struct platform_device *pdev)
613c7fdb240SAbhyuday Godhasara {
614c7fdb240SAbhyuday Godhasara cpuhp_remove_state(CPUHP_AP_ONLINE_DYN);
615c7fdb240SAbhyuday Godhasara
616c7fdb240SAbhyuday Godhasara on_each_cpu(xlnx_disable_percpu_irq, NULL, 1);
617c7fdb240SAbhyuday Godhasara
618c7fdb240SAbhyuday Godhasara irq_clear_status_flags(virq_sgi, IRQ_PER_CPU);
619a96e60a6SJay Buddhabhatti free_percpu_irq(virq_sgi, &dummy_cpu_number);
620c7fdb240SAbhyuday Godhasara irq_dispose_mapping(virq_sgi);
621c7fdb240SAbhyuday Godhasara }
622c7fdb240SAbhyuday Godhasara
xlnx_event_manager_probe(struct platform_device * pdev)623c7fdb240SAbhyuday Godhasara static int xlnx_event_manager_probe(struct platform_device *pdev)
624c7fdb240SAbhyuday Godhasara {
625c7fdb240SAbhyuday Godhasara int ret;
626c7fdb240SAbhyuday Godhasara
627c7fdb240SAbhyuday Godhasara ret = zynqmp_pm_feature(PM_REGISTER_NOTIFIER);
628c7fdb240SAbhyuday Godhasara if (ret < 0) {
629c7fdb240SAbhyuday Godhasara dev_err(&pdev->dev, "Feature check failed with %d\n", ret);
630c7fdb240SAbhyuday Godhasara return ret;
631c7fdb240SAbhyuday Godhasara }
632c7fdb240SAbhyuday Godhasara
633c7fdb240SAbhyuday Godhasara if ((ret & FIRMWARE_VERSION_MASK) <
634c7fdb240SAbhyuday Godhasara REGISTER_NOTIFIER_FIRMWARE_VERSION) {
635c7fdb240SAbhyuday Godhasara dev_err(&pdev->dev, "Register notifier version error. Expected Firmware: v%d - Found: v%d\n",
636c7fdb240SAbhyuday Godhasara REGISTER_NOTIFIER_FIRMWARE_VERSION,
637c7fdb240SAbhyuday Godhasara ret & FIRMWARE_VERSION_MASK);
638c7fdb240SAbhyuday Godhasara return -EOPNOTSUPP;
639c7fdb240SAbhyuday Godhasara }
640c7fdb240SAbhyuday Godhasara
641c7fdb240SAbhyuday Godhasara /* Initialize the SGI */
642c7fdb240SAbhyuday Godhasara ret = xlnx_event_init_sgi(pdev);
643c7fdb240SAbhyuday Godhasara if (ret) {
644c7fdb240SAbhyuday Godhasara dev_err(&pdev->dev, "SGI Init has been failed with %d\n", ret);
645c7fdb240SAbhyuday Godhasara return ret;
646c7fdb240SAbhyuday Godhasara }
647c7fdb240SAbhyuday Godhasara
648c7fdb240SAbhyuday Godhasara /* Setup function for the CPU hot-plug cases */
649c7fdb240SAbhyuday Godhasara cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "soc/event:starting",
650c7fdb240SAbhyuday Godhasara xlnx_event_cpuhp_start, xlnx_event_cpuhp_down);
651c7fdb240SAbhyuday Godhasara
652acd6510dSTanmay Shah ret = zynqmp_pm_register_sgi(sgi_num, 0);
653c7fdb240SAbhyuday Godhasara if (ret) {
654c7fdb240SAbhyuday Godhasara dev_err(&pdev->dev, "SGI %d Registration over TF-A failed with %d\n", sgi_num, ret);
655c7fdb240SAbhyuday Godhasara xlnx_event_cleanup_sgi(pdev);
656c7fdb240SAbhyuday Godhasara return ret;
657c7fdb240SAbhyuday Godhasara }
658c7fdb240SAbhyuday Godhasara
659c7fdb240SAbhyuday Godhasara event_manager_availability = 0;
660c7fdb240SAbhyuday Godhasara
661c7fdb240SAbhyuday Godhasara dev_info(&pdev->dev, "SGI %d Registered over TF-A\n", sgi_num);
662c7fdb240SAbhyuday Godhasara dev_info(&pdev->dev, "Xilinx Event Management driver probed\n");
663c7fdb240SAbhyuday Godhasara
664c7fdb240SAbhyuday Godhasara return ret;
665c7fdb240SAbhyuday Godhasara }
666c7fdb240SAbhyuday Godhasara
xlnx_event_manager_remove(struct platform_device * pdev)667e8864065SUwe Kleine-König static void xlnx_event_manager_remove(struct platform_device *pdev)
668c7fdb240SAbhyuday Godhasara {
669c7fdb240SAbhyuday Godhasara int i;
670c7fdb240SAbhyuday Godhasara struct registered_event_data *eve_data;
671c7fdb240SAbhyuday Godhasara struct hlist_node *tmp;
672c7fdb240SAbhyuday Godhasara int ret;
67305e5ba40SAbhyuday Godhasara struct agent_cb *cb_pos;
67405e5ba40SAbhyuday Godhasara struct agent_cb *cb_next;
675c7fdb240SAbhyuday Godhasara
676c7fdb240SAbhyuday Godhasara hash_for_each_safe(reg_driver_map, i, tmp, eve_data, hentry) {
67705e5ba40SAbhyuday Godhasara list_for_each_entry_safe(cb_pos, cb_next, &eve_data->cb_list_head, list) {
67805e5ba40SAbhyuday Godhasara list_del_init(&cb_pos->list);
67905e5ba40SAbhyuday Godhasara kfree(cb_pos);
68005e5ba40SAbhyuday Godhasara }
681c7fdb240SAbhyuday Godhasara hash_del(&eve_data->hentry);
682c7fdb240SAbhyuday Godhasara kfree(eve_data);
683c7fdb240SAbhyuday Godhasara }
684c7fdb240SAbhyuday Godhasara
685acd6510dSTanmay Shah ret = zynqmp_pm_register_sgi(0, 1);
686c7fdb240SAbhyuday Godhasara if (ret)
687c7fdb240SAbhyuday Godhasara dev_err(&pdev->dev, "SGI unregistration over TF-A failed with %d\n", ret);
688c7fdb240SAbhyuday Godhasara
689c7fdb240SAbhyuday Godhasara xlnx_event_cleanup_sgi(pdev);
690c7fdb240SAbhyuday Godhasara
691c7fdb240SAbhyuday Godhasara event_manager_availability = -EACCES;
692c7fdb240SAbhyuday Godhasara }
693c7fdb240SAbhyuday Godhasara
694c7fdb240SAbhyuday Godhasara static struct platform_driver xlnx_event_manager_driver = {
695c7fdb240SAbhyuday Godhasara .probe = xlnx_event_manager_probe,
696e8864065SUwe Kleine-König .remove_new = xlnx_event_manager_remove,
697c7fdb240SAbhyuday Godhasara .driver = {
698c7fdb240SAbhyuday Godhasara .name = "xlnx_event_manager",
699c7fdb240SAbhyuday Godhasara },
700c7fdb240SAbhyuday Godhasara };
701c7fdb240SAbhyuday Godhasara module_param(sgi_num, uint, 0);
702c7fdb240SAbhyuday Godhasara module_platform_driver(xlnx_event_manager_driver);
703