blob: e7271a9a2c0af236360e67c400690e13d84bb560 [file] [log] [blame]
Duy Truong790f06d2013-02-13 16:38:12 -08001/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
Naveen Ramarajbdf4dfe2012-04-23 14:09:50 -07002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#include <mach/ocmem_priv.h>
14#include <linux/hardirq.h>
15
16static unsigned notifier_threshold;
17
18/* Protect the notifier structure below */
19DEFINE_MUTEX(nc_lock);
20
21struct ocmem_notifier {
22 int owner;
23 struct atomic_notifier_head nc;
24 unsigned listeners;
25} notifiers[OCMEM_CLIENT_MAX];
26
Naveen Ramarajbdf4dfe2012-04-23 14:09:50 -070027int check_notifier(int id)
28{
29 int ret = 0;
30
31 if (!check_id(id))
32 return 0;
33
34 mutex_lock(&nc_lock);
35 ret = notifiers[id].listeners;
36 mutex_unlock(&nc_lock);
37 return ret;
38}
39
40int ocmem_notifier_init(void)
41{
42 int id;
43 /* Maximum notifiers for each subsystem */
44 notifier_threshold = 1;
45 mutex_lock(&nc_lock);
46 for (id = 0; id < OCMEM_CLIENT_MAX; id++) {
47 notifiers[id].owner = id;
48 ATOMIC_INIT_NOTIFIER_HEAD(&notifiers[id].nc);
49 notifiers[id].listeners = 0;
50 }
51 mutex_unlock(&nc_lock);
52 return 0;
53}
54
55/* Broadcast a notification to listeners */
56int dispatch_notification(int id, enum ocmem_notif_type notif,
57 struct ocmem_buf *buf)
58{
59 int ret = 0;
60 struct ocmem_notifier *nc_hndl = NULL;
61 mutex_lock(&nc_lock);
62 nc_hndl = &notifiers[id];
63 if (nc_hndl->listeners == 0) {
64 /* Send an error so that the scheduler can clean up */
65 mutex_unlock(&nc_lock);
66 return -EINVAL;
67 }
68 ret = atomic_notifier_call_chain(&notifiers[id].nc, notif, buf);
69 mutex_unlock(&nc_lock);
70 return ret;
71}
72
Naveen Ramaraj6b882652012-06-28 16:07:09 -070073struct ocmem_notifier *ocmem_notifier_register(int client_id,
74 struct notifier_block *nb)
Naveen Ramarajbdf4dfe2012-04-23 14:09:50 -070075{
76
77 int ret = 0;
78 struct ocmem_notifier *nc_hndl = NULL;
79
80 if (!check_id(client_id)) {
81 pr_err("ocmem: Invalid Client id\n");
82 return NULL;
83 }
84
Naveen Ramaraj4d5e3542012-08-12 21:55:49 -070085 if (!zone_active(client_id)) {
86 pr_err("ocmem: Client %s (id: %d) not allowed to use OCMEM\n",
87 get_name(client_id), client_id);
88 return NULL;
89 }
90
Naveen Ramarajbdf4dfe2012-04-23 14:09:50 -070091 if (!nb) {
92 pr_err("ocmem: Invalid Notifier Block\n");
93 return NULL;
94 }
95
96 mutex_lock(&nc_lock);
97
98 nc_hndl = &notifiers[client_id];
99
100 if (nc_hndl->listeners >= notifier_threshold) {
101 pr_err("ocmem: Max notifiers already registered\n");
102 mutex_unlock(&nc_lock);
103 return NULL;
104 }
105
106 ret = atomic_notifier_chain_register(&nc_hndl->nc, nb);
107
108 if (ret < 0) {
109 mutex_unlock(&nc_lock);
110 return NULL;
111 }
112
113 nc_hndl->listeners++;
114 pr_info("ocmem: Notifier registered for %d\n", client_id);
115 mutex_unlock(&nc_lock);
116 return nc_hndl;
117}
118EXPORT_SYMBOL(ocmem_notifier_register);
119
Naveen Ramaraj6b882652012-06-28 16:07:09 -0700120int ocmem_notifier_unregister(struct ocmem_notifier *nc_hndl,
121 struct notifier_block *nb)
Naveen Ramarajbdf4dfe2012-04-23 14:09:50 -0700122{
123
124 int ret = 0;
125
Naveen Ramarajbdf4dfe2012-04-23 14:09:50 -0700126 if (!nc_hndl) {
127 pr_err("ocmem: Invalid notification handle\n");
128 return -EINVAL;
129 }
130
131 mutex_lock(&nc_lock);
132 ret = atomic_notifier_chain_unregister(&nc_hndl->nc, nb);
133 nc_hndl->listeners--;
134 mutex_unlock(&nc_lock);
135
136 return ret;
137}
138EXPORT_SYMBOL(ocmem_notifier_unregister);