/* Add into callback list */
list_add(&cb_data->list, &eve_data->cb_list_head);
/* Add into HASH table */
hash_add(reg_driver_map, &eve_data->hentry, key);
} else { /* Search for callback function and private data in list */
list_for_each_entry_safe(cb_pos, cb_next, &eve_data->cb_list_head, list) { if (cb_pos->eve_cb == cb_fun &&
cb_pos->agent_data == data) { return0;
}
}
/* Add multiple handler and private data in list */
cb_data = kmalloc(sizeof(*cb_data), GFP_KERNEL); if (!cb_data) return -ENOMEM;
cb_data->eve_cb = cb_fun;
cb_data->agent_data = data;
/* 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) { if (eve_data->cb_type == PM_INIT_SUSPEND_CB) {
pr_err("Found as already registered\n"); return -EINVAL;
}
}
/* Add new entry if not present */
eve_data = kmalloc(sizeof(*eve_data), GFP_KERNEL); if (!eve_data) return -ENOMEM;
/* Check for existing entry in hash table for given key id */
hash_for_each_possible_safe(reg_driver_map, eve_data, tmp, hentry, key) { if (eve_data->key == key) { /* Delete the list of callback */
list_for_each_entry_safe(cb_pos, cb_next, &eve_data->cb_list_head, list) { if (cb_pos->eve_cb == cb_fun &&
cb_pos->agent_data == data) {
is_callback_found = true;
list_del_init(&cb_pos->list);
kfree(cb_pos);
}
}
/* Remove HASH table if callback list is empty */ 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) {
pr_warn("Didn't find any registered callback for 0x%x 0x%x\n",
node_id, event); return -EINVAL;
}
return0;
}
/** *xlnx_register_event()-Registerfortheevent. *@cb_type:Typeofcallbackfrompm_api_cb_id, *PM_NOTIFY_CB-forErrorEvents, *PM_INIT_SUSPEND_CB-forsuspendcallback. *@node_id:Node-Idrelatedtoevent. *@event:EventMaskfortheErrorEvent. *@wake:Flagspecifyingwhetherthesubsystemshouldbewokenupon *eventnotification. *@cb_fun:Functionpointertostorethecallbackfunction. *@data:Pointerforthedriverinstance. * *Return:Returns0onsuccessfulregistrationelseerrorcode.
*/ int xlnx_register_event(constenum pm_api_cb_id cb_type, const u32 node_id, const u32 event, constbool wake, event_cb_func_t cb_fun, void *data)
{ int ret = 0;
u32 eve; int pos;
if (event_manager_availability) return event_manager_availability;
if (cb_type == PM_INIT_SUSPEND_CB) {
ret = xlnx_add_cb_for_suspend(cb_fun, data);
} else { if (!xlnx_is_error_event(node_id)) { /* Add entry for Node-Id/Event in hash table */
ret = xlnx_add_cb_for_notify_event(node_id, event, wake, cb_fun, data);
} else { /* Add into Hash table */ for (pos = 0; pos < MAX_BITS; pos++) {
eve = event & (1 << pos); if (!eve) continue;
/* Add entry for Node-Id/Eve in hash table */
ret = xlnx_add_cb_for_notify_event(node_id, eve, wake, cb_fun,
data); /* Break the loop if got error */ if (ret) break;
} if (ret) { /* Skip the Event for which got the error */
pos--; /* Remove registered(during this call) event from hash table */ for ( ; pos >= 0; pos--) {
eve = event & (1 << pos); if (!eve) continue;
xlnx_remove_cb_for_notify_event(node_id, eve, cb_fun, data);
}
}
}
if (ret) {
pr_err("%s() failed for 0x%x and 0x%x: %d\r\n", __func__, node_id,
event, ret); return ret;
}
/* Register for Node-Id/Event combination in firmware */
ret = zynqmp_pm_register_notifier(node_id, event, wake, true); if (ret) {
pr_err("%s() failed for 0x%x and 0x%x: %d\r\n", __func__, node_id,
event, ret); /* Remove already registered event from hash table */ if (xlnx_is_error_event(node_id)) { for (pos = 0; pos < MAX_BITS; pos++) {
eve = event & (1 << pos); if (!eve) continue;
xlnx_remove_cb_for_notify_event(node_id, eve, cb_fun, data);
}
} else {
xlnx_remove_cb_for_notify_event(node_id, event, cb_fun, data);
} return ret;
}
}
/* Un-register if list is empty */ if (is_need_to_unregister) { /* Un-register for Node-Id/Event combination */
ret = zynqmp_pm_register_notifier(node_id, event, false, false); if (ret) {
pr_err("%s() failed for 0x%x and 0x%x: %d\n",
__func__, node_id, event, ret); return ret;
}
}
}
staticint xlnx_event_manager_probe(struct platform_device *pdev)
{ int ret;
ret = zynqmp_pm_feature(PM_REGISTER_NOTIFIER); if (ret < 0) {
dev_err(&pdev->dev, "Feature check failed with %d\n", ret); return ret;
}
if ((ret & FIRMWARE_VERSION_MASK) <
REGISTER_NOTIFIER_FIRMWARE_VERSION) {
dev_err(&pdev->dev, "Register notifier version error. Expected Firmware: v%d - Found: v%d\n",
REGISTER_NOTIFIER_FIRMWARE_VERSION,
ret & FIRMWARE_VERSION_MASK); return -EOPNOTSUPP;
}
/* Initialize the SGI */
ret = xlnx_event_init_sgi(pdev); if (ret) {
dev_err(&pdev->dev, "SGI Init has been failed with %d\n", ret); return ret;
}
/* Setup function for the CPU hot-plug cases */
cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "soc/event:starting",
xlnx_event_cpuhp_start, xlnx_event_cpuhp_down);
ret = zynqmp_pm_register_sgi(sgi_num, 0); if (ret) { if (ret == -EOPNOTSUPP)
dev_err(&pdev->dev, "SGI registration not supported by TF-A or Xen\n"); else
dev_err(&pdev->dev, "SGI %d registration failed, err %d\n", sgi_num, ret);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.