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()
193 return -ENOMEM; in xlnx_add_cb_for_suspend()
195 cb_data->eve_cb = cb_fun; in xlnx_add_cb_for_suspend()
196 cb_data->agent_data = data; in xlnx_add_cb_for_suspend()
199 list_add(&cb_data->list, &eve_data->cb_list_head); in xlnx_add_cb_for_suspend()
201 hash_add(reg_driver_map, &eve_data->hentry, PM_INIT_SUSPEND_CB); in xlnx_add_cb_for_suspend()
218 if (eve_data->cb_type == PM_INIT_SUSPEND_CB) { in xlnx_remove_cb_for_suspend()
220 list_for_each_entry_safe(cb_pos, cb_next, &eve_data->cb_list_head, list) { in xlnx_remove_cb_for_suspend()
221 if (cb_pos->eve_cb == cb_fun) { in xlnx_remove_cb_for_suspend()
223 list_del_init(&cb_pos->list); in xlnx_remove_cb_for_suspend()
228 hash_del(&eve_data->hentry); in xlnx_remove_cb_for_suspend()
235 return -EINVAL; in xlnx_remove_cb_for_suspend()
255 if (eve_data->key == key) { in xlnx_remove_cb_for_notify_event()
257 list_for_each_entry_safe(cb_pos, cb_next, &eve_data->cb_list_head, list) { in xlnx_remove_cb_for_notify_event()
258 if (cb_pos->eve_cb == cb_fun && in xlnx_remove_cb_for_notify_event()
259 cb_pos->agent_data == data) { in xlnx_remove_cb_for_notify_event()
261 list_del_init(&cb_pos->list); in xlnx_remove_cb_for_notify_event()
267 if (list_empty(&eve_data->cb_list_head)) { in xlnx_remove_cb_for_notify_event()
269 hash_del(&eve_data->hentry); in xlnx_remove_cb_for_notify_event()
278 return -EINVAL; in xlnx_remove_cb_for_notify_event()
285 * xlnx_register_event() - Register for the event.
287 * PM_NOTIFY_CB - for Error Events,
288 * PM_INIT_SUSPEND_CB - for suspend callback.
289 * @node_id: Node-Id related to event.
291 * @wake: Flag specifying whether the subsystem should be woken upon
299 const bool wake, event_cb_func_t cb_fun, void *data) in xlnx_register_event() argument
310 return -EINVAL; in xlnx_register_event()
314 return -EFAULT; in xlnx_register_event()
320 /* Add entry for Node-Id/Event in hash table */ in xlnx_register_event()
321 ret = xlnx_add_cb_for_notify_event(node_id, event, wake, cb_fun, data); in xlnx_register_event()
329 /* Add entry for Node-Id/Eve in hash table */ in xlnx_register_event()
330 ret = xlnx_add_cb_for_notify_event(node_id, eve, wake, cb_fun, in xlnx_register_event()
338 pos--; in xlnx_register_event()
340 for ( ; pos >= 0; pos--) { in xlnx_register_event()
355 /* Register for Node-Id/Event combination in firmware */ in xlnx_register_event()
356 ret = zynqmp_pm_register_notifier(node_id, event, wake, true); in xlnx_register_event()
380 * xlnx_unregister_event() - Unregister for the event.
382 * PM_NOTIFY_CB - for Error Events,
383 * PM_INIT_SUSPEND_CB - for suspend callback.
384 * @node_id: Node-Id related to event.
404 return -EINVAL; in xlnx_unregister_event()
408 return -EFAULT; in xlnx_unregister_event()
413 /* Remove Node-Id/Event from hash table */ in xlnx_unregister_event()
426 /* Un-register if list is empty */ in xlnx_unregister_event()
428 /* Un-register for Node-Id/Event combination */ in xlnx_unregister_event()
452 if (eve_data->cb_type == cb_type) { in xlnx_call_suspend_cb_handler()
453 list_for_each_entry_safe(cb_pos, cb_next, &eve_data->cb_list_head, list) { in xlnx_call_suspend_cb_handler()
454 cb_pos->eve_cb(&payload[0], cb_pos->agent_data); in xlnx_call_suspend_cb_handler()
474 if (eve_data->key == key) { in xlnx_call_notify_cb_handler()
475 list_for_each_entry_safe(cb_pos, cb_next, &eve_data->cb_list_head, list) { in xlnx_call_notify_cb_handler()
476 cb_pos->eve_cb(&payload[0], cb_pos->agent_data); in xlnx_call_notify_cb_handler()
482 eve_data->wake, true); in xlnx_call_notify_cb_handler()
486 list_for_each_entry_safe(cb_pos, cb_next, &eve_data->cb_list_head, in xlnx_call_notify_cb_handler()
490 cb_pos->eve_cb, in xlnx_call_notify_cb_handler()
491 cb_pos->agent_data); in xlnx_call_notify_cb_handler()
506 static irqreturn_t xlnx_event_handler(int irq, void *dev_id) in xlnx_event_handler() argument
526 * We can get multiple error events as in one call back through error in xlnx_event_handler()
527 * mask. So payload[2] may can contain multiple error events. in xlnx_event_handler()
529 * node_id-error combination. in xlnx_event_handler()
576 * IRQ related structures are used for the following: in xlnx_event_init_sgi()
577 * for each SGI interrupt ensure its mapped by GIC IRQ domain in xlnx_event_init_sgi()
578 * and that each corresponding linux IRQ for the HW IRQ has in xlnx_event_init_sgi()
585 struct device *parent = pdev->dev.parent; in xlnx_event_init_sgi()
588 interrupt_parent = of_irq_find_parent(parent->of_node); in xlnx_event_init_sgi()
590 dev_err(&pdev->dev, "Failed to find property for Interrupt parent\n"); in xlnx_event_init_sgi()
591 return -EINVAL; in xlnx_event_init_sgi()
594 /* Each SGI needs to be associated with GIC's IRQ domain. */ in xlnx_event_init_sgi()
598 /* Each mapping needs GIC domain when finding IRQ mapping. */ in xlnx_event_init_sgi()
599 sgi_fwspec.fwnode = domain->fwnode; in xlnx_event_init_sgi()
602 * When irq domain looks at mapping each arg is as follows: in xlnx_event_init_sgi()
643 dev_err(&pdev->dev, "Feature check failed with %d\n", ret); in xlnx_event_manager_probe()
649 dev_err(&pdev->dev, "Register notifier version error. Expected Firmware: v%d - Found: v%d\n", in xlnx_event_manager_probe()
652 return -EOPNOTSUPP; in xlnx_event_manager_probe()
658 dev_err(&pdev->dev, "SGI Init has been failed with %d\n", ret); in xlnx_event_manager_probe()
662 /* Setup function for the CPU hot-plug cases */ in xlnx_event_manager_probe()
668 if (ret == -EOPNOTSUPP) in xlnx_event_manager_probe()
669 dev_err(&pdev->dev, "SGI registration not supported by TF-A or Xen\n"); in xlnx_event_manager_probe()
671 dev_err(&pdev->dev, "SGI %d registration failed, err %d\n", sgi_num, ret); in xlnx_event_manager_probe()
679 dev_info(&pdev->dev, "SGI %d Registered over TF-A\n", sgi_num); in xlnx_event_manager_probe()
680 dev_info(&pdev->dev, "Xilinx Event Management driver probed\n"); in xlnx_event_manager_probe()
695 list_for_each_entry_safe(cb_pos, cb_next, &eve_data->cb_list_head, list) { in xlnx_event_manager_remove()
696 list_del_init(&cb_pos->list); in xlnx_event_manager_remove()
699 hash_del(&eve_data->hentry); in xlnx_event_manager_remove()
705 dev_err(&pdev->dev, "SGI unregistration over TF-A failed with %d\n", ret); in xlnx_event_manager_remove()
709 event_manager_availability = -EACCES; in xlnx_event_manager_remove()