tizen 2.4 release
[profile/mobile/platform/kernel/linux-3.10-sc7730.git] / kernel / swap / wsp / wsp_res.c
1 /*
2  * This program is free software; you can redistribute it and/or modify
3  * it under the terms of the GNU General Public License as published by
4  * the Free Software Foundation; either version 2 of the License, or
5  * (at your option) any later version.
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  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software
14  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15  *
16  * Copyright (C) Samsung Electronics, 2016
17  *
18  * 2015         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
19  *
20  */
21
22
23 #include <linux/slab.h>
24 #include <linux/atomic.h>
25 #include <kprobe/swap_kprobes_deps.h>
26 #include "wsp_res.h"
27
28 static atomic_t wsp_res_count;
29
30 static int wsp_tdata_get_id(void)
31 {
32         return atomic_inc_return(&wsp_res_count);
33 }
34
35 static struct wsp_tdata *g_tdata;
36
37 /* FIXME: get_tdata() need receive for each processes */
38 static struct wsp_tdata *get_tdata(void)
39 {
40         return g_tdata;
41 }
42
43
44
45
46
47 /* ============================================================================
48  * =                                  wsp_tdata                               =
49  * ============================================================================
50  */
51 struct wsp_tdata {
52         struct list_head res_list;
53         spinlock_t lock;
54
55         enum tdata_stat stat;
56 };
57
58 static struct wsp_res *wsp_tdata_new_res(struct wsp_tdata *d, void *ptr,
59                                          enum wsp_res_t type)
60 {
61         struct wsp_res *res;
62
63         res = kmalloc(sizeof(*res), GFP_ATOMIC);
64         if (res) {
65                 INIT_LIST_HEAD(&res->list);
66                 res->ptr = ptr;
67                 res->id = wsp_tdata_get_id();
68                 res->type = type;
69                 res->stat = WRS_NEW;
70
71                 /* add to list */
72                 spin_lock(&d->lock);
73                 list_add(&res->list, &d->res_list);
74                 spin_unlock(&d->lock);
75         }
76
77         return res;
78 }
79
80 static void wsp_tdata_del_res(struct wsp_res *res)
81 {
82         list_del(&res->list);
83         kfree(res);
84 }
85
86 static struct wsp_tdata *wsp_tdata_create(void)
87 {
88         struct wsp_tdata *d;
89
90         d = kmalloc(sizeof(*d), GFP_ATOMIC);
91         if (d) {
92                 INIT_LIST_HEAD(&d->res_list);
93                 spin_lock_init(&d->lock);
94                 d->stat = TDS_NEW;
95         }
96
97         return d;
98 }
99
100 static void wsp_tdata_destroy(struct wsp_tdata *d)
101 {
102         struct wsp_res *res, *n;
103
104         spin_lock(&d->lock);
105         list_for_each_entry_safe(res, n, &d->res_list, list)
106                 wsp_tdata_del_res(res);
107         spin_unlock(&d->lock);
108
109         kfree(d);
110 }
111
112 static struct wsp_res *wsp_tdata_last_res(struct wsp_tdata *d)
113 {
114         struct wsp_res *res;
115
116         spin_lock(&d->lock);
117         res = list_first_entry_or_null(&d->res_list, struct wsp_res, list);
118         spin_unlock(&d->lock);
119
120         return res;
121 }
122
123 struct wsp_res *wsp_tdata_find_res(struct wsp_tdata *data, void *ptr,
124                                    enum wsp_res_t type)
125 {
126         struct wsp_res *res;
127
128         list_for_each_entry(res, &data->res_list, list) {
129                 if (res->type != type)
130                         continue;
131
132                 if (res->ptr == ptr) {
133                         if (res->stat == WRS_ERR) {
134                                 pr_err("ERR: something went wrong\n");
135                                 return NULL;
136                         }
137
138                         return res;
139                 }
140         }
141
142         return NULL;
143 }
144
145
146
147
148
149 /* ============================================================================
150  * =                          wsp_current_[get/set]_stat()                    =
151  * ============================================================================
152  */
153 enum tdata_stat wsp_current_get_stat(void)
154 {
155         struct wsp_tdata *d;
156
157         d = get_tdata();
158         if (d)
159                 return d->stat;
160         else
161                 pr_err("ERR: no current tdata\n");
162
163         return TDS_ERR;
164 }
165
166 void wsp_current_set_stat(enum tdata_stat stat)
167 {
168         struct wsp_tdata *d;
169
170         d = get_tdata();
171         if (d)
172                 d->stat = stat;
173         else
174                 pr_err("ERR: no current tdata\n");
175 }
176
177
178
179
180
181 /* ============================================================================
182  * =                                   wsp_res                                =
183  * ============================================================================
184  */
185 struct wsp_res *wsp_res_new(void *ptr, enum wsp_res_t type)
186 {
187         struct wsp_tdata *data;
188
189         data = get_tdata();
190         if (data == NULL) {
191                 pr_err("ERR: no current tdata\n");
192                 return NULL;
193         }
194
195
196         return wsp_tdata_new_res(data, ptr, type);
197 }
198
199 void wsp_res_del(struct wsp_res *res)
200 {
201         wsp_tdata_del_res(res);
202 }
203
204 struct wsp_res *wsp_res_find(void *ptr, enum wsp_res_t type)
205 {
206         struct wsp_tdata *data;
207
208         data = get_tdata();
209         if (data == NULL) {
210                 pr_err("ERR: no current tdata\n");
211                 return NULL;
212         }
213
214         return wsp_tdata_find_res(data, ptr, type);
215 }
216
217 struct wsp_res *wsp_res_last(void)
218 {
219         struct wsp_tdata *d;
220
221         d = get_tdata();
222         if (d == NULL) {
223                 pr_err("ERR: no current tdata\n");
224                 return NULL;
225         }
226
227         return wsp_tdata_last_res(d);
228 }
229
230 int wsp_res_stat_set_next(struct wsp_res *res, enum wsp_res_stat stat)
231 {
232         switch (res->stat) {
233         case WRS_NEW:
234                 if (stat == WRS_WILL_REQ) {
235                         res->stat = stat;
236                         return 0;
237                 }
238                 break;
239
240         case WRS_WILL_REQ:
241                 if (stat == WRS_SOUP_REQ) {
242                         res->stat = stat;
243                         return 0;
244                 }
245                 break;
246
247         case WRS_SOUP_REQ:
248         case WRS_ADD_DATA:
249                 if (stat == WRS_ADD_DATA || stat == WRS_FINISH) {
250                         res->stat = stat;
251                         return 0;
252                 }
253                 break;
254
255         default:
256                 break;
257         }
258
259         pr_err("ERR: set_next_stat from %d to %d [id=%d]\n",
260                res->stat, stat, res->id);
261
262         res->stat = WRS_ERR;
263
264         return -1;
265 }
266
267
268
269
270
271 /* ============================================================================
272  * =                                init/exit()                               =
273  * ============================================================================
274  */
275 int wsp_res_init(void)
276 {
277         g_tdata = wsp_tdata_create();
278         if (g_tdata == NULL)
279                 return -ENOMEM;
280
281         atomic_set(&wsp_res_count, 0);
282
283         return 0;
284 }
285
286 void wsp_res_exit(void)
287 {
288         wsp_tdata_destroy(g_tdata);
289         g_tdata = NULL;
290 }