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

1 // SPDX-License-Identifier: GPL-2.0
12 #include <linux/firmware/xlnx-event-manager.h>
13 #include <linux/firmware/xlnx-zynqmp.h>
16 #include <linux/irq.h>
26 static int event_manager_availability = -EACCES;
31 /* 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
104 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
117 if (eve_data->key == key) { in xlnx_add_cb_for_notify_event()
127 return -ENOMEM; in xlnx_add_cb_for_notify_event()
128 eve_data->key = key; in xlnx_add_cb_for_notify_event()
129 eve_data->cb_type = PM_NOTIFY_CB; in xlnx_add_cb_for_notify_event()
130 eve_data->wake = wake; in xlnx_add_cb_for_notify_event()
131 INIT_LIST_HEAD(&eve_data->cb_list_head); in xlnx_add_cb_for_notify_event()
136 return -ENOMEM; in xlnx_add_cb_for_notify_event()
138 cb_data->eve_cb = cb_fun; in xlnx_add_cb_for_notify_event()
139 cb_data->agent_data = data; in xlnx_add_cb_for_notify_event()
142 list_add(&cb_data->list, &eve_data->cb_list_head); in xlnx_add_cb_for_notify_event()
145 hash_add(reg_driver_map, &eve_data->hentry, key); in xlnx_add_cb_for_notify_event()
148 list_for_each_entry_safe(cb_pos, cb_next, &eve_data->cb_list_head, list) { in xlnx_add_cb_for_notify_event()
149 if (cb_pos->eve_cb == cb_fun && in xlnx_add_cb_for_notify_event()
150 cb_pos->agent_data == data) { in xlnx_add_cb_for_notify_event()
158 return -ENOMEM; in xlnx_add_cb_for_notify_event()
159 cb_data->eve_cb = cb_fun; in xlnx_add_cb_for_notify_event()
160 cb_data->agent_data = data; in xlnx_add_cb_for_notify_event()
162 list_add(&cb_data->list, &eve_data->cb_list_head); in xlnx_add_cb_for_notify_event()
175 if (eve_data->cb_type == PM_INIT_SUSPEND_CB) { in xlnx_add_cb_for_suspend()
177 return -EINVAL; in xlnx_add_cb_for_suspend()
184 return -ENOMEM; in xlnx_add_cb_for_suspend()
186 eve_data->key = 0; in xlnx_add_cb_for_suspend()
187 eve_data->cb_type = PM_INIT_SUSPEND_CB; in xlnx_add_cb_for_suspend()
188 INIT_LIST_HEAD(&eve_data->cb_list_head); in xlnx_add_cb_for_suspend()
192 return -ENOMEM; in xlnx_add_cb_for_suspend()
193 cb_data->eve_cb = cb_fun; in xlnx_add_cb_for_suspend()
194 cb_data->agent_data = data; in xlnx_add_cb_for_suspend()
197 list_add(&cb_data->list, &eve_data->cb_list_head); in xlnx_add_cb_for_suspend()
199 hash_add(reg_driver_map, &eve_data->hentry, PM_INIT_SUSPEND_CB); in xlnx_add_cb_for_suspend()
216 if (eve_data->cb_type == PM_INIT_SUSPEND_CB) { in xlnx_remove_cb_for_suspend()
218 list_for_each_entry_safe(cb_pos, cb_next, &eve_data->cb_list_head, list) { in xlnx_remove_cb_for_suspend()
219 if (cb_pos->eve_cb == cb_fun) { in xlnx_remove_cb_for_suspend()
221 list_del_init(&cb_pos->list); in xlnx_remove_cb_for_suspend()
226 hash_del(&eve_data->hentry); in xlnx_remove_cb_for_suspend()
233 return -EINVAL; in xlnx_remove_cb_for_suspend()
253 if (eve_data->key == key) { in xlnx_remove_cb_for_notify_event()
255 list_for_each_entry_safe(cb_pos, cb_next, &eve_data->cb_list_head, list) { in xlnx_remove_cb_for_notify_event()
256 if (cb_pos->eve_cb == cb_fun && in xlnx_remove_cb_for_notify_event()
257 cb_pos->agent_data == data) { in xlnx_remove_cb_for_notify_event()
259 list_del_init(&cb_pos->list); in xlnx_remove_cb_for_notify_event()
265 if (list_empty(&eve_data->cb_list_head)) { in xlnx_remove_cb_for_notify_event()
267 hash_del(&eve_data->hentry); in xlnx_remove_cb_for_notify_event()
276 return -EINVAL; in xlnx_remove_cb_for_notify_event()
283 * xlnx_register_event() - Register for the event.
285 * PM_NOTIFY_CB - for Error Events,
286 * PM_INIT_SUSPEND_CB - for suspend callback.
287 * @node_id: Node-Id related to event.
289 * @wake: Flag specifying whether the subsystem should be woken upon
297 const bool wake, event_cb_func_t cb_fun, void *data) in xlnx_register_event() argument
308 return -EINVAL; in xlnx_register_event()
312 return -EFAULT; in xlnx_register_event()
318 /* Add entry for Node-Id/Event in hash table */ in xlnx_register_event()
319 ret = xlnx_add_cb_for_notify_event(node_id, event, wake, cb_fun, data); in xlnx_register_event()
327 /* Add entry for Node-Id/Eve in hash table */ in xlnx_register_event()
328 ret = xlnx_add_cb_for_notify_event(node_id, eve, wake, cb_fun, in xlnx_register_event()
336 pos--; in xlnx_register_event()
338 for ( ; pos >= 0; pos--) { in xlnx_register_event()
353 /* Register for Node-Id/Event combination in firmware */ in xlnx_register_event()
354 ret = zynqmp_pm_register_notifier(node_id, event, wake, true); in xlnx_register_event()
378 * xlnx_unregister_event() - Unregister for the event.
380 * PM_NOTIFY_CB - for Error Events,
381 * PM_INIT_SUSPEND_CB - for suspend callback.
382 * @node_id: Node-Id related to event.
402 return -EINVAL; in xlnx_unregister_event()
406 return -EFAULT; in xlnx_unregister_event()
411 /* Remove Node-Id/Event from hash table */ in xlnx_unregister_event()
424 /* Un-register if list is empty */ in xlnx_unregister_event()
426 /* Un-register for Node-Id/Event combination */ in xlnx_unregister_event()
450 if (eve_data->cb_type == cb_type) { in xlnx_call_suspend_cb_handler()
451 list_for_each_entry_safe(cb_pos, cb_next, &eve_data->cb_list_head, list) { in xlnx_call_suspend_cb_handler()
452 cb_pos->eve_cb(&payload[0], cb_pos->agent_data); in xlnx_call_suspend_cb_handler()
472 if (eve_data->key == key) { in xlnx_call_notify_cb_handler()
473 list_for_each_entry_safe(cb_pos, cb_next, &eve_data->cb_list_head, list) { in xlnx_call_notify_cb_handler()
474 cb_pos->eve_cb(&payload[0], cb_pos->agent_data); in xlnx_call_notify_cb_handler()
480 eve_data->wake, true); in xlnx_call_notify_cb_handler()
484 list_for_each_entry_safe(cb_pos, cb_next, &eve_data->cb_list_head, in xlnx_call_notify_cb_handler()
488 cb_pos->eve_cb, in xlnx_call_notify_cb_handler()
489 cb_pos->agent_data); in xlnx_call_notify_cb_handler()
504 static irqreturn_t xlnx_event_handler(int irq, void *dev_id) in xlnx_event_handler() argument
524 * We can get multiple error events as in one call back through error in xlnx_event_handler()
525 * mask. So payload[2] may can contain multiple error events. in xlnx_event_handler()
527 * node_id-error combination. in xlnx_event_handler()
574 * IRQ related structures are used for the following: in xlnx_event_init_sgi()
575 * for each SGI interrupt ensure its mapped by GIC IRQ domain in xlnx_event_init_sgi()
576 * and that each corresponding linux IRQ for the HW IRQ has in xlnx_event_init_sgi()
583 struct device *parent = pdev->dev.parent; in xlnx_event_init_sgi()
586 interrupt_parent = of_irq_find_parent(parent->of_node); in xlnx_event_init_sgi()
588 dev_err(&pdev->dev, "Failed to find property for Interrupt parent\n"); in xlnx_event_init_sgi()
589 return -EINVAL; in xlnx_event_init_sgi()
592 /* Each SGI needs to be associated with GIC's IRQ domain. */ in xlnx_event_init_sgi()
596 /* Each mapping needs GIC domain when finding IRQ mapping. */ in xlnx_event_init_sgi()
597 sgi_fwspec.fwnode = domain->fwnode; in xlnx_event_init_sgi()
600 * When irq domain looks at mapping each arg is as follows: in xlnx_event_init_sgi()
641 dev_err(&pdev->dev, "Feature check failed with %d\n", ret); in xlnx_event_manager_probe()
647 dev_err(&pdev->dev, "Register notifier version error. Expected Firmware: v%d - Found: v%d\n", in xlnx_event_manager_probe()
650 return -EOPNOTSUPP; in xlnx_event_manager_probe()
656 dev_err(&pdev->dev, "SGI Init has been failed with %d\n", ret); in xlnx_event_manager_probe()
660 /* Setup function for the CPU hot-plug cases */ in xlnx_event_manager_probe()
666 if (ret == -EOPNOTSUPP) in xlnx_event_manager_probe()
667 dev_err(&pdev->dev, "SGI registration not supported by TF-A or Xen\n"); in xlnx_event_manager_probe()
669 dev_err(&pdev->dev, "SGI %d registration failed, err %d\n", sgi_num, ret); in xlnx_event_manager_probe()
677 dev_info(&pdev->dev, "SGI %d Registered over TF-A\n", sgi_num); in xlnx_event_manager_probe()
678 dev_info(&pdev->dev, "Xilinx Event Management driver probed\n"); in xlnx_event_manager_probe()
693 list_for_each_entry_safe(cb_pos, cb_next, &eve_data->cb_list_head, list) { in xlnx_event_manager_remove()
694 list_del_init(&cb_pos->list); in xlnx_event_manager_remove()
697 hash_del(&eve_data->hentry); in xlnx_event_manager_remove()
703 dev_err(&pdev->dev, "SGI unregistration over TF-A failed with %d\n", ret); in xlnx_event_manager_remove()
707 event_manager_availability = -EACCES; in xlnx_event_manager_remove()