Merge branch 'tizen_2.4' into tizen_2.4_dev
[platform/kernel/swap-modules.git] / parser / swap_msg_parser.c
1 /**
2  * parser/swap_msg_parser.c
3  * @author Vyacheslav Cherkashin
4  * @author Vitaliy Cherepanov
5  *
6  * @section LICENSE
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21  *
22  * @section COPYRIGHT
23  *
24  * Copyright (C) Samsung Electronics, 2013
25  *
26  * @section DESCRIPTION
27  *
28  * Parser module interface implementation.
29  */
30
31
32 #include <linux/module.h>
33 #include <linux/vmalloc.h>
34 #include <linux/cpumask.h>
35 #include <linux/uaccess.h>
36
37 #include "parser_defs.h"
38 #include "us_inst.h"
39 #include "msg_buf.h"
40 #include "msg_cmd.h"
41 #include "cpu_ctrl.h"
42
43 #include <driver/driver_to_msg.h>
44 #include <driver/swap_ioctl.h>
45 #include <master/swap_initializer.h>
46
47 /**
48  * @enum MSG_ID
49  * @brief Message IDs.
50  */
51 enum MSG_ID {
52         MSG_KEEP_ALIVE          = 0x0001,       /**< Keep alive message. */
53         MSG_START               = 0x0002,       /**< Start message. */
54         MSG_STOP                = 0x0003,       /**< Stop message. */
55         MSG_CONFIG              = 0x0004,       /**< Config message. */
56         MSG_SWAP_INST_ADD       = 0x0008,       /**< Swap inst add message. */
57         MSG_SWAP_INST_REMOVE    = 0x0009,       /**< Swap inst remove message. */
58         MSG_WRT_LAUNCHER_PORT   = 0x8001        /**< WRT launcher port. */
59 };
60
61 /**
62  * @struct basic_msg_fmt
63  * @brief Basic part of each message.
64  */
65 struct basic_msg_fmt {
66         u32 msg_id;                         /**< Message ID. */
67         u32 len;                            /**< Message length. */
68 } __packed;
69
70 static int msg_handler(void __user *msg)
71 {
72         int ret;
73         u32 size;
74         enum MSG_ID msg_id;
75         struct msg_buf mb;
76         void __user *payload;
77         struct basic_msg_fmt bmf;
78         enum { size_max = 128 * 1024 * 1024 };
79
80         ret = copy_from_user(&bmf, (void *)msg, sizeof(bmf));
81         if (ret)
82                 return ret;
83
84         size = bmf.len;
85         if (size >= size_max) {
86                 printk(KERN_INFO "%s: too large message, size=%u\n",
87                        __func__, size);
88                 return -ENOMEM;
89         }
90
91         ret = init_mb(&mb, size);
92         if (ret)
93                 return ret;
94
95         payload = msg + sizeof(bmf);
96         if (size) {
97                 ret = copy_from_user(mb.begin, (void *)payload, size);
98                 if (ret)
99                         goto uninit;
100         }
101
102         msg_id = bmf.msg_id;
103         switch (msg_id) {
104         case MSG_KEEP_ALIVE:
105                 print_parse_debug("MSG_KEEP_ALIVE. size=%d\n", size);
106                 ret = msg_keep_alive(&mb);
107                 break;
108         case MSG_START:
109                 print_parse_debug("MSG_START. size=%d\n", size);
110                 ret = msg_start(&mb);
111                 break;
112         case MSG_STOP: {
113                 struct cpumask mask;
114
115                 print_parse_debug("MSG_STOP. size=%d\n", size);
116
117                 swap_disable_nonboot_cpus_lock(&mask);
118                 ret = msg_stop(&mb);
119                 swap_enable_nonboot_cpus_unlock(&mask);
120
121                 break;
122         }
123         case MSG_CONFIG:
124                 print_parse_debug("MSG_CONFIG. size=%d\n", size);
125                 ret = msg_config(&mb);
126                 break;
127         case MSG_SWAP_INST_ADD:
128                 print_parse_debug("MSG_SWAP_INST_ADD. size=%d\n", size);
129                 ret = msg_swap_inst_add(&mb);
130                 break;
131         case MSG_SWAP_INST_REMOVE:
132                 print_parse_debug("MSG_SWAP_INST_REMOVE. size=%d\n", size);
133                 ret = msg_swap_inst_remove(&mb);
134                 break;
135         case MSG_WRT_LAUNCHER_PORT: {
136                 /* TODO: discuss wrt-launcher port transfer */
137                 int port;
138                 print_parse_debug("MSG_WRT_LAUNCHER_PORT. size=%d\n", size);
139                 port = get_wrt_launcher_port();
140                 if (copy_to_user(payload, &port, sizeof(port))) {
141                         ret = -EIO;
142                         break;
143                 }
144                 ret = port ? 0 : -EINVAL;
145                 break;
146         }
147         default:
148                 print_err("incorrect message ID [%u]. size=%d\n", msg_id, size);
149                 ret = -EINVAL;
150                 break;
151         }
152
153 uninit:
154         uninit_mb(&mb);
155         return ret;
156 }
157
158 static int reg_msg_handler(void)
159 {
160         set_msg_handler(msg_handler);
161         return 0;
162 }
163
164 static void unreg_msg_handler(void)
165 {
166         set_msg_handler(NULL);
167         pfg_put_all();
168 }
169
170 static int once(void)
171 {
172         int ret;
173
174         ret = once_cmd();
175         if (ret)
176                 return ret;
177
178         ret = init_cpu_deps();
179
180         return ret;
181 }
182
183 SWAP_LIGHT_INIT_MODULE(once, reg_msg_handler, unreg_msg_handler, NULL, NULL);
184
185 MODULE_LICENSE("GPL");