• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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