blob: 58ad3d95f6ff0fb2897ff3e4361b2177df0a914f [file] [log] [blame]
Naveen Ramarajbdf4dfe2012-04-23 14:09:50 -07001/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
2 *
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
27static int check_id(int id)
28{
29 return (id < OCMEM_CLIENT_MAX && id >= OCMEM_GRAPHICS);
30}
31
32int check_notifier(int id)
33{
34 int ret = 0;
35
36 if (!check_id(id))
37 return 0;
38
39 mutex_lock(&nc_lock);
40 ret = notifiers[id].listeners;
41 mutex_unlock(&nc_lock);
42 return ret;
43}
44
45int ocmem_notifier_init(void)
46{
47 int id;
48 /* Maximum notifiers for each subsystem */
49 notifier_threshold = 1;
50 mutex_lock(&nc_lock);
51 for (id = 0; id < OCMEM_CLIENT_MAX; id++) {
52 notifiers[id].owner = id;
53 ATOMIC_INIT_NOTIFIER_HEAD(&notifiers[id].nc);
54 notifiers[id].listeners = 0;
55 }
56 mutex_unlock(&nc_lock);
57 return 0;
58}
59
60/* Broadcast a notification to listeners */
61int dispatch_notification(int id, enum ocmem_notif_type notif,
62 struct ocmem_buf *buf)
63{
64 int ret = 0;
65 struct ocmem_notifier *nc_hndl = NULL;
66 mutex_lock(&nc_lock);
67 nc_hndl = &notifiers[id];
68 if (nc_hndl->listeners == 0) {
69 /* Send an error so that the scheduler can clean up */
70 mutex_unlock(&nc_lock);
71 return -EINVAL;
72 }
73 ret = atomic_notifier_call_chain(&notifiers[id].nc, notif, buf);
74 mutex_unlock(&nc_lock);
75 return ret;
76}
77
78void *ocmem_notifier_register(int client_id, struct notifier_block *nb)
79{
80
81 int ret = 0;
82 struct ocmem_notifier *nc_hndl = NULL;
83
84 if (!check_id(client_id)) {
85 pr_err("ocmem: Invalid Client id\n");
86 return NULL;
87 }
88
89 if (!nb) {
90 pr_err("ocmem: Invalid Notifier Block\n");
91 return NULL;
92 }
93
94 mutex_lock(&nc_lock);
95
96 nc_hndl = &notifiers[client_id];
97
98 if (nc_hndl->listeners >= notifier_threshold) {
99 pr_err("ocmem: Max notifiers already registered\n");
100 mutex_unlock(&nc_lock);
101 return NULL;
102 }
103
104 ret = atomic_notifier_chain_register(&nc_hndl->nc, nb);
105
106 if (ret < 0) {
107 mutex_unlock(&nc_lock);
108 return NULL;
109 }
110
111 nc_hndl->listeners++;
112 pr_info("ocmem: Notifier registered for %d\n", client_id);
113 mutex_unlock(&nc_lock);
114 return nc_hndl;
115}
116EXPORT_SYMBOL(ocmem_notifier_register);
117
118int ocmem_notifier_unregister(void *hndl, struct notifier_block *nb)
119{
120
121 int ret = 0;
122
123 struct ocmem_notifier *nc_hndl = (struct ocmem_notifier *) hndl;
124
125 if (!nc_hndl) {
126 pr_err("ocmem: Invalid notification handle\n");
127 return -EINVAL;
128 }
129
130 mutex_lock(&nc_lock);
131 ret = atomic_notifier_chain_unregister(&nc_hndl->nc, nb);
132 nc_hndl->listeners--;
133 mutex_unlock(&nc_lock);
134
135 return ret;
136}
137EXPORT_SYMBOL(ocmem_notifier_unregister);