1 /*
2 * Copyright (C) 2021 HiSilicon (Shanghai) Technologies CO., LIMITED.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 */
18
19 #include <linux/notifier.h>
20 #include <linux/slab.h>
21 #include <linux/reboot.h>
22 #include <linux/module.h>
23 #include "securec.h"
24 #include "hi_osal.h"
25
26 OSAL_LIST_HEAD(nb_list);
27
28 struct nb_node {
29 struct osal_notifier_block *osal_nb;
30 struct notifier_block *nb;
31 struct osal_list_head node;
32 };
33
osal_find_ob(struct notifier_block * nb)34 static struct osal_notifier_block *osal_find_ob(struct notifier_block *nb)
35 {
36 struct osal_list_head *this = NULL;
37 if (osal_list_empty(&nb_list)) {
38 osal_trace("find nb failed! nb_list is empty!\n");
39 return NULL;
40 }
41 osal_list_for_each(this, &nb_list) {
42 struct nb_node *ns = osal_list_entry(this, struct nb_node, node);
43 if (ns->nb == nb) {
44 return ns->osal_nb;
45 }
46 }
47 osal_trace("find ob failed!\n");
48 return NULL;
49 }
50
osal_del_nb(struct osal_notifier_block * nb)51 static int osal_del_nb(struct osal_notifier_block *nb)
52 {
53 struct osal_list_head *this = NULL;
54 struct osal_list_head *next = NULL;
55 if (osal_list_empty(&nb_list)) {
56 osal_trace("find nb failed! nb_list is empty!\n");
57 return -1;
58 }
59 osal_list_for_each_safe(this, next, &nb_list) {
60 struct nb_node *ns = osal_list_entry(this, struct nb_node, node);
61 if (ns->osal_nb == nb) {
62 osal_list_del(this);
63 kfree(ns);
64 return 0;
65 }
66 }
67 osal_trace("del nb failed!\n");
68 return -1;
69 }
70
osal_notifier(struct notifier_block * nb,unsigned long action,void * data)71 static int osal_notifier(struct notifier_block *nb, unsigned long action, void *data)
72 {
73 struct osal_notifier_block *ob = osal_find_ob(nb);
74 if ((ob != NULL) && (ob->notifier_call != NULL)) {
75 return ob->notifier_call(ob, action, data);
76 }
77 return 0;
78 }
79
osal_register_reboot_notifier(struct osal_notifier_block * ob)80 int osal_register_reboot_notifier(struct osal_notifier_block *ob)
81 {
82 struct notifier_block *nb = NULL;
83 struct nb_node *node = NULL;
84
85 nb = kmalloc(sizeof(struct notifier_block), GFP_KERNEL);
86 if (nb == NULL) {
87 osal_trace("osal_register_reboot_notifier malloc nb failed!\n");
88 return -1;
89 }
90 (void)memset_s(nb, sizeof(struct notifier_block), 0, sizeof(struct notifier_block));
91
92 node = kmalloc(sizeof(struct nb_node), GFP_KERNEL);
93 if (node == NULL) {
94 osal_trace("osal_register_reboot_notifier kmalloc nb_node failed!\n");
95 kfree(nb);
96 return -1;
97 }
98 (void)memset_s(node, sizeof(struct nb_node), 0, sizeof(struct nb_node));
99
100 nb->notifier_call = osal_notifier;
101 register_reboot_notifier(nb);
102 ob->notifier_block = nb;
103 node->osal_nb = ob;
104 node->nb = nb;
105 osal_list_add(&(node->node), &nb_list);
106 return 0;
107 }
108 EXPORT_SYMBOL(osal_register_reboot_notifier);
109
osal_unregister_reboot_notifier(struct osal_notifier_block * nb)110 int osal_unregister_reboot_notifier(struct osal_notifier_block *nb)
111 {
112 if (nb != NULL) {
113 osal_del_nb(nb);
114 unregister_reboot_notifier((struct notifier_block *)nb->notifier_block);
115 kfree((struct notifier_block *)nb->notifier_block);
116 }
117 return 0;
118 }
119 EXPORT_SYMBOL(osal_unregister_reboot_notifier);
120