Lines Matching +full:irq +full:- +full:can +full:- +full:wake

1 // SPDX-License-Identifier: GPL-2.0
11 #include <linux/firmware/xlnx-event-manager.h>
12 #include <linux/firmware/xlnx-zynqmp.h>
15 #include <linux/irq.h>
25 static int event_manager_availability = -EACCES;
30 /* Max number of driver can register for same event */
47 * struct agent_cb - Registered callback function and private data.
59 * struct registered_event_data - Registered Event Data.
60 * @key: key is the combine id(Node-Id | Event-Id) of type u64
61 * where upper u32 for Node-Id and lower u32 for Event-Id,
64 * @wake: If this flag set, firmware will wake up processor if is
73 bool wake; member
89 static int xlnx_add_cb_for_notify_event(const u32 node_id, const u32 event, const bool wake, in xlnx_add_cb_for_notify_event() argument
102 if (eve_data->key == key) { in xlnx_add_cb_for_notify_event()
112 return -ENOMEM; in xlnx_add_cb_for_notify_event()
113 eve_data->key = key; in xlnx_add_cb_for_notify_event()
114 eve_data->cb_type = PM_NOTIFY_CB; in xlnx_add_cb_for_notify_event()
115 eve_data->wake = wake; in xlnx_add_cb_for_notify_event()
116 INIT_LIST_HEAD(&eve_data->cb_list_head); in xlnx_add_cb_for_notify_event()
120 return -ENOMEM; in xlnx_add_cb_for_notify_event()
121 cb_data->eve_cb = cb_fun; in xlnx_add_cb_for_notify_event()
122 cb_data->agent_data = data; in xlnx_add_cb_for_notify_event()
125 list_add(&cb_data->list, &eve_data->cb_list_head); in xlnx_add_cb_for_notify_event()
128 hash_add(reg_driver_map, &eve_data->hentry, key); in xlnx_add_cb_for_notify_event()
131 list_for_each_entry_safe(cb_pos, cb_next, &eve_data->cb_list_head, list) { in xlnx_add_cb_for_notify_event()
132 if (cb_pos->eve_cb == cb_fun && in xlnx_add_cb_for_notify_event()
133 cb_pos->agent_data == data) { in xlnx_add_cb_for_notify_event()
141 return -ENOMEM; in xlnx_add_cb_for_notify_event()
142 cb_data->eve_cb = cb_fun; in xlnx_add_cb_for_notify_event()
143 cb_data->agent_data = data; in xlnx_add_cb_for_notify_event()
145 list_add(&cb_data->list, &eve_data->cb_list_head); in xlnx_add_cb_for_notify_event()
158 if (eve_data->cb_type == PM_INIT_SUSPEND_CB) { in xlnx_add_cb_for_suspend()
160 return -EINVAL; in xlnx_add_cb_for_suspend()
167 return -ENOMEM; in xlnx_add_cb_for_suspend()
169 eve_data->key = 0; in xlnx_add_cb_for_suspend()
170 eve_data->cb_type = PM_INIT_SUSPEND_CB; in xlnx_add_cb_for_suspend()
171 INIT_LIST_HEAD(&eve_data->cb_list_head); in xlnx_add_cb_for_suspend()
175 return -ENOMEM; in xlnx_add_cb_for_suspend()
176 cb_data->eve_cb = cb_fun; in xlnx_add_cb_for_suspend()
177 cb_data->agent_data = data; in xlnx_add_cb_for_suspend()
180 list_add(&cb_data->list, &eve_data->cb_list_head); in xlnx_add_cb_for_suspend()
182 hash_add(reg_driver_map, &eve_data->hentry, PM_INIT_SUSPEND_CB); in xlnx_add_cb_for_suspend()
198 if (eve_data->cb_type == PM_INIT_SUSPEND_CB) { in xlnx_remove_cb_for_suspend()
200 list_for_each_entry_safe(cb_pos, cb_next, &eve_data->cb_list_head, list) { in xlnx_remove_cb_for_suspend()
201 if (cb_pos->eve_cb == cb_fun) { in xlnx_remove_cb_for_suspend()
203 list_del_init(&cb_pos->list); in xlnx_remove_cb_for_suspend()
208 hash_del(&eve_data->hentry); in xlnx_remove_cb_for_suspend()
215 return -EINVAL; in xlnx_remove_cb_for_suspend()
234 if (eve_data->key == key) { in xlnx_remove_cb_for_notify_event()
236 list_for_each_entry_safe(cb_pos, cb_next, &eve_data->cb_list_head, list) { in xlnx_remove_cb_for_notify_event()
237 if (cb_pos->eve_cb == cb_fun && in xlnx_remove_cb_for_notify_event()
238 cb_pos->agent_data == data) { in xlnx_remove_cb_for_notify_event()
240 list_del_init(&cb_pos->list); in xlnx_remove_cb_for_notify_event()
246 if (list_empty(&eve_data->cb_list_head)) { in xlnx_remove_cb_for_notify_event()
248 hash_del(&eve_data->hentry); in xlnx_remove_cb_for_notify_event()
257 return -EINVAL; in xlnx_remove_cb_for_notify_event()
264 * xlnx_register_event() - Register for the event.
266 * PM_NOTIFY_CB - for Error Events,
267 * PM_INIT_SUSPEND_CB - for suspend callback.
268 * @node_id: Node-Id related to event.
270 * @wake: Flag specifying whether the subsystem should be woken upon
278 const bool wake, event_cb_func_t cb_fun, void *data) in xlnx_register_event() argument
289 return -EINVAL; in xlnx_register_event()
293 return -EFAULT; in xlnx_register_event()
299 /* Add entry for Node-Id/Event in hash table */ in xlnx_register_event()
300 ret = xlnx_add_cb_for_notify_event(node_id, event, wake, cb_fun, data); in xlnx_register_event()
308 /* Add entry for Node-Id/Eve in hash table */ in xlnx_register_event()
309 ret = xlnx_add_cb_for_notify_event(node_id, eve, wake, cb_fun, in xlnx_register_event()
317 pos--; in xlnx_register_event()
319 for ( ; pos >= 0; pos--) { in xlnx_register_event()
334 /* Register for Node-Id/Event combination in firmware */ in xlnx_register_event()
335 ret = zynqmp_pm_register_notifier(node_id, event, wake, true); in xlnx_register_event()
359 * xlnx_unregister_event() - Unregister for the event.
361 * PM_NOTIFY_CB - for Error Events,
362 * PM_INIT_SUSPEND_CB - for suspend callback.
363 * @node_id: Node-Id related to event.
383 return -EINVAL; in xlnx_unregister_event()
387 return -EFAULT; in xlnx_unregister_event()
392 /* Remove Node-Id/Event from hash table */ in xlnx_unregister_event()
405 /* Un-register if list is empty */ in xlnx_unregister_event()
407 /* Un-register for Node-Id/Event combination */ in xlnx_unregister_event()
431 if (eve_data->cb_type == cb_type) { in xlnx_call_suspend_cb_handler()
432 list_for_each_entry_safe(cb_pos, cb_next, &eve_data->cb_list_head, list) { in xlnx_call_suspend_cb_handler()
433 cb_pos->eve_cb(&payload[0], cb_pos->agent_data); in xlnx_call_suspend_cb_handler()
453 if (eve_data->key == key) { in xlnx_call_notify_cb_handler()
454 list_for_each_entry_safe(cb_pos, cb_next, &eve_data->cb_list_head, list) { in xlnx_call_notify_cb_handler()
455 cb_pos->eve_cb(&payload[0], cb_pos->agent_data); in xlnx_call_notify_cb_handler()
461 eve_data->wake, true); in xlnx_call_notify_cb_handler()
465 list_for_each_entry_safe(cb_pos, cb_next, &eve_data->cb_list_head, in xlnx_call_notify_cb_handler()
469 cb_pos->eve_cb, in xlnx_call_notify_cb_handler()
470 cb_pos->agent_data); in xlnx_call_notify_cb_handler()
485 static irqreturn_t xlnx_event_handler(int irq, void *dev_id) in xlnx_event_handler() argument
505 * We can get multiple error events as in one call back through error in xlnx_event_handler()
506 * mask. So payload[2] may can contain multiple error events. in xlnx_event_handler()
508 * node_id-error combination. in xlnx_event_handler()
556 * IRQ related structures are used for the following: in xlnx_event_init_sgi()
557 * for each SGI interrupt ensure its mapped by GIC IRQ domain in xlnx_event_init_sgi()
558 * and that each corresponding linux IRQ for the HW IRQ has in xlnx_event_init_sgi()
565 struct device *parent = pdev->dev.parent; in xlnx_event_init_sgi()
568 interrupt_parent = of_irq_find_parent(parent->of_node); in xlnx_event_init_sgi()
570 dev_err(&pdev->dev, "Failed to find property for Interrupt parent\n"); in xlnx_event_init_sgi()
571 return -EINVAL; in xlnx_event_init_sgi()
574 /* Each SGI needs to be associated with GIC's IRQ domain. */ in xlnx_event_init_sgi()
578 /* Each mapping needs GIC domain when finding IRQ mapping. */ in xlnx_event_init_sgi()
579 sgi_fwspec.fwnode = domain->fwnode; in xlnx_event_init_sgi()
582 * When irq domain looks at mapping each arg is as follows: in xlnx_event_init_sgi()
627 dev_err(&pdev->dev, "Feature check failed with %d\n", ret); in xlnx_event_manager_probe()
633 dev_err(&pdev->dev, "Register notifier version error. Expected Firmware: v%d - Found: v%d\n", in xlnx_event_manager_probe()
636 return -EOPNOTSUPP; in xlnx_event_manager_probe()
642 dev_err(&pdev->dev, "SGI Init has been failed with %d\n", ret); in xlnx_event_manager_probe()
646 /* Setup function for the CPU hot-plug cases */ in xlnx_event_manager_probe()
652 dev_err(&pdev->dev, "SGI %d Registration over TF-A failed with %d\n", sgi_num, ret); in xlnx_event_manager_probe()
659 dev_info(&pdev->dev, "SGI %d Registered over TF-A\n", sgi_num); in xlnx_event_manager_probe()
660 dev_info(&pdev->dev, "Xilinx Event Management driver probed\n"); in xlnx_event_manager_probe()
675 list_for_each_entry_safe(cb_pos, cb_next, &eve_data->cb_list_head, list) { in xlnx_event_manager_remove()
676 list_del_init(&cb_pos->list); in xlnx_event_manager_remove()
679 hash_del(&eve_data->hentry); in xlnx_event_manager_remove()
685 dev_err(&pdev->dev, "SGI unregistration over TF-A failed with %d\n", ret); in xlnx_event_manager_remove()
689 event_manager_availability = -EACCES; in xlnx_event_manager_remove()