|
@@ -12,6 +12,7 @@
|
|
|
#include <linux/slab.h>
|
|
|
#include <linux/module.h>
|
|
|
#include <linux/fs.h>
|
|
|
+#include <linux/reboot.h>
|
|
|
#include <linux/platform_device.h>
|
|
|
#include <linux/debugfs.h>
|
|
|
#include <linux/cdev.h>
|
|
@@ -379,6 +380,7 @@ struct qseecom_control {
|
|
|
|
|
|
struct list_head unload_app_pending_list_head;
|
|
|
struct task_struct *unload_app_kthread_task;
|
|
|
+ struct notifier_block reboot_nb;
|
|
|
wait_queue_head_t unload_app_kthread_wq;
|
|
|
atomic_t unload_app_kthread_state;
|
|
|
bool no_user_contig_mem_support;
|
|
@@ -9270,6 +9272,47 @@ static void qseecom_release_ce_data(void)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+static int qseecom_reboot_worker(struct notifier_block *nb, unsigned long val, void *data)
|
|
|
+{
|
|
|
+ struct qseecom_registered_listener_list *entry;
|
|
|
+
|
|
|
+ /* Mark all the listener as abort since system is going
|
|
|
+ * for a reboot so every pending listener request should
|
|
|
+ * be aborted.
|
|
|
+ */
|
|
|
+ list_for_each_entry(entry,
|
|
|
+ &qseecom.registered_listener_list_head, list) {
|
|
|
+ entry->abort = 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* stop CA thread waiting for listener response */
|
|
|
+ wake_up_interruptible_all(&qseecom.send_resp_wq);
|
|
|
+
|
|
|
+ /* Assumption is system going in reboot
|
|
|
+ * every registered listener from userspace waiting
|
|
|
+ * on event interruptible will receive interrupt as
|
|
|
+ * TASK_INTERRUPTIBLE flag will be set for them
|
|
|
+ */
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+static int qseecom_register_reboot_notifier(void)
|
|
|
+{
|
|
|
+ int rc = 0;
|
|
|
+
|
|
|
+ /* Registering reboot notifier for resource cleanup at reboot.
|
|
|
+ * Current implementation is for listener use case,
|
|
|
+ * it can be extended to App also in case of any corner
|
|
|
+ * case issue found.
|
|
|
+ */
|
|
|
+
|
|
|
+ qseecom.reboot_nb.notifier_call = qseecom_reboot_worker;
|
|
|
+ rc = register_reboot_notifier(&(qseecom.reboot_nb));
|
|
|
+ if (rc)
|
|
|
+ pr_err("failed to register reboot notifier\n");
|
|
|
+ return rc;
|
|
|
+}
|
|
|
+
|
|
|
static int qseecom_init_dev(struct platform_device *pdev)
|
|
|
{
|
|
|
int rc = 0;
|
|
@@ -9324,6 +9367,19 @@ static int qseecom_init_dev(struct platform_device *pdev)
|
|
|
pr_err("Failed to initialize reserved mem, ret %d\n", rc);
|
|
|
goto exit_del_cdev;
|
|
|
}
|
|
|
+
|
|
|
+ rc = qseecom_register_reboot_notifier();
|
|
|
+ if (rc) {
|
|
|
+ pr_err("failed in registering reboot notifier %d\n", rc);
|
|
|
+ /* exit even if notifier registration fail.
|
|
|
+ * Although, thats not a functional failure from qseecom
|
|
|
+ * driver prespective but this registration
|
|
|
+ * failure will cause more complex issue at the
|
|
|
+ * time of reboot or possibly halt the reboot.
|
|
|
+ */
|
|
|
+ goto exit_del_cdev;
|
|
|
+ }
|
|
|
+
|
|
|
return 0;
|
|
|
|
|
|
exit_del_cdev:
|
|
@@ -9342,6 +9398,7 @@ static void qseecom_deinit_dev(void)
|
|
|
{
|
|
|
kfree(qseecom.dev->dma_parms);
|
|
|
qseecom.dev->dma_parms = NULL;
|
|
|
+ unregister_reboot_notifier(&(qseecom.reboot_nb));
|
|
|
cdev_del(&qseecom.cdev);
|
|
|
device_destroy(qseecom.driver_class, qseecom.qseecom_device_no);
|
|
|
class_destroy(qseecom.driver_class);
|