blob: 7b51beb9436346a1ab0c7ca6600be3465381dc24 [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* arch/arm/mach-msm/smd_rpcrouter_device.c
2 *
3 * Copyright (C) 2007 Google, Inc.
Stephen Boyd77db8bb2012-06-27 15:15:16 -07004 * Copyright (c) 2007-2012, Code Aurora Forum. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005 * Author: San Mehat <san@android.com>
6 *
7 * This software is licensed under the terms of the GNU General Public
8 * License version 2, as published by the Free Software Foundation, and
9 * may be copied, distributed, and modified under those terms.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 */
17#include <linux/slab.h>
18#include <linux/module.h>
19#include <linux/kernel.h>
20#include <linux/string.h>
21#include <linux/errno.h>
22#include <linux/cdev.h>
23#include <linux/init.h>
24#include <linux/device.h>
25#include <linux/types.h>
26#include <linux/delay.h>
27#include <linux/fs.h>
28#include <linux/err.h>
29#include <linux/sched.h>
30#include <linux/poll.h>
31#include <linux/platform_device.h>
32#include <linux/msm_rpcrouter.h>
33
34#include <asm/uaccess.h>
35#include <asm/byteorder.h>
36
Stephen Boyd77db8bb2012-06-27 15:15:16 -070037#include <mach/subsystem_restart.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070038#include "smd_rpcrouter.h"
39
40/* Support 64KB of data plus some space for headers */
41#define SAFETY_MEM_SIZE (65536 + sizeof(struct rpc_request_hdr))
42
43/* modem load timeout */
44#define MODEM_LOAD_TIMEOUT (10 * HZ)
45
46/* Next minor # available for a remote server */
47static int next_minor = 1;
48static DEFINE_SPINLOCK(server_cdev_lock);
49
50struct class *msm_rpcrouter_class;
51dev_t msm_rpcrouter_devno;
52
53static struct cdev rpcrouter_cdev;
54static struct device *rpcrouter_device;
55
56struct rpcrouter_file_info {
57 struct msm_rpc_endpoint *ept;
58 void *modem_pil;
59};
60
61static void msm_rpcrouter_unload_modem(void *pil)
62{
63 if (pil)
Stephen Boyd77db8bb2012-06-27 15:15:16 -070064 subsystem_put(pil);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070065}
66
67static void *msm_rpcrouter_load_modem(void)
68{
69 void *pil;
70 int rc;
71
Stephen Boyd77db8bb2012-06-27 15:15:16 -070072 pil = subsystem_get("modem");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070073 if (IS_ERR(pil))
74 pr_err("%s: modem load failed\n", __func__);
75 else {
76 rc = wait_for_completion_interruptible_timeout(
77 &rpc_remote_router_up,
78 MODEM_LOAD_TIMEOUT);
79 if (!rc)
80 rc = -ETIMEDOUT;
81 if (rc < 0) {
82 pr_err("%s: wait for remote router failed %d\n",
83 __func__, rc);
84 msm_rpcrouter_unload_modem(pil);
85 pil = ERR_PTR(rc);
86 }
87 }
88
89 return pil;
90}
91
92static int rpcrouter_open(struct inode *inode, struct file *filp)
93{
94 int rc;
95 void *pil;
96 struct msm_rpc_endpoint *ept;
97 struct rpcrouter_file_info *file_info;
98
99 rc = nonseekable_open(inode, filp);
100 if (rc < 0)
101 return rc;
102
103 file_info = kzalloc(sizeof(*file_info), GFP_KERNEL);
104 if (!file_info)
105 return -ENOMEM;
106
107 ept = msm_rpcrouter_create_local_endpoint(inode->i_rdev);
108 if (!ept) {
109 kfree(file_info);
110 return -ENOMEM;
111 }
112 file_info->ept = ept;
113
114 /* if router device, load the modem */
115 if (inode->i_rdev == msm_rpcrouter_devno) {
116 pil = msm_rpcrouter_load_modem();
117 if (IS_ERR(pil)) {
118 kfree(file_info);
119 msm_rpcrouter_destroy_local_endpoint(ept);
120 return PTR_ERR(pil);
121 }
122 file_info->modem_pil = pil;
123 }
124
125 filp->private_data = file_info;
126 return 0;
127}
128
129static int rpcrouter_release(struct inode *inode, struct file *filp)
130{
131 struct rpcrouter_file_info *file_info = filp->private_data;
132 struct msm_rpc_endpoint *ept;
133 static unsigned int rpcrouter_release_cnt;
134
135 ept = (struct msm_rpc_endpoint *) file_info->ept;
136
137 /* A user program with many files open when ends abruptly,
138 * will cause a flood of REMOVE_CLIENT messages to the
139 * remote processor. This will cause remote processors
140 * internal queue to overflow. Inserting a sleep here
141 * regularly is the effecient option.
142 */
143 if (rpcrouter_release_cnt++ % 2)
144 msleep(1);
145
146 /* if router device, unload the modem */
147 if (inode->i_rdev == msm_rpcrouter_devno)
148 msm_rpcrouter_unload_modem(file_info->modem_pil);
149
150 kfree(file_info);
151 return msm_rpcrouter_destroy_local_endpoint(ept);
152}
153
154static ssize_t rpcrouter_read(struct file *filp, char __user *buf,
155 size_t count, loff_t *ppos)
156{
157 struct rpcrouter_file_info *file_info = filp->private_data;
158 struct msm_rpc_endpoint *ept;
159 struct rr_fragment *frag, *next;
160 int rc;
161
162 ept = (struct msm_rpc_endpoint *) file_info->ept;
163
164 rc = __msm_rpc_read(ept, &frag, count, -1);
165 if (rc < 0)
166 return rc;
167
168 count = rc;
169
170 while (frag != NULL) {
171 if (copy_to_user(buf, frag->data, frag->length)) {
172 printk(KERN_ERR
173 "rpcrouter: could not copy all read data to user!\n");
174 rc = -EFAULT;
175 }
176 buf += frag->length;
177 next = frag->next;
178 kfree(frag);
179 frag = next;
180 }
181
182 return rc;
183}
184
185static ssize_t rpcrouter_write(struct file *filp, const char __user *buf,
186 size_t count, loff_t *ppos)
187{
188 struct rpcrouter_file_info *file_info = filp->private_data;
189 struct msm_rpc_endpoint *ept;
190 int rc = 0;
191 void *k_buffer;
192
193 ept = (struct msm_rpc_endpoint *) file_info->ept;
194
195 /* A check for safety, this seems non-standard */
196 if (count > SAFETY_MEM_SIZE)
197 return -EINVAL;
198
199 k_buffer = kmalloc(count, GFP_KERNEL);
200 if (!k_buffer)
201 return -ENOMEM;
202
203 if (copy_from_user(k_buffer, buf, count)) {
204 rc = -EFAULT;
205 goto write_out_free;
206 }
207
208 rc = msm_rpc_write(ept, k_buffer, count);
209 if (rc < 0)
210 goto write_out_free;
211
212 rc = count;
213write_out_free:
214 kfree(k_buffer);
215 return rc;
216}
217
218/* RPC VFS Poll Implementation
219 *
220 * POLLRDHUP - restart in progress
221 * POLLOUT - writes accepted (without blocking)
222 * POLLIN - data ready to read
223 *
224 * The restart state consists of several different phases including a client
225 * notification and a server restart. If the server has been restarted, then
226 * reads and writes can be performed and the POLLOUT bit will be set. If a
227 * restart is in progress, but the server hasn't been restarted, then only the
228 * POLLRDHUP is active and reads and writes will block. See the table
229 * below for a summary. POLLRDHUP is cleared once a call to msm_rpc_write_pkt
230 * or msm_rpc_read_pkt returns ENETRESET.
231 *
232 * POLLOUT POLLRDHUP
233 * 1 0 Normal operation
234 * 0 1 Restart in progress and server hasn't restarted yet
235 * 1 1 Server has been restarted, but client has
236 * not been notified of a restart by a return code
237 * of ENETRESET from msm_rpc_write_pkt or
238 * msm_rpc_read_pkt.
239 */
240static unsigned int rpcrouter_poll(struct file *filp,
241 struct poll_table_struct *wait)
242{
243 struct rpcrouter_file_info *file_info = filp->private_data;
244 struct msm_rpc_endpoint *ept;
245 unsigned mask = 0;
246
247 ept = (struct msm_rpc_endpoint *) file_info->ept;
248
249 poll_wait(filp, &ept->wait_q, wait);
250 poll_wait(filp, &ept->restart_wait, wait);
251
252 if (!list_empty(&ept->read_q))
253 mask |= POLLIN;
254 if (!(ept->restart_state & RESTART_PEND_SVR))
255 mask |= POLLOUT;
256 if (ept->restart_state != 0)
257 mask |= POLLRDHUP;
258
259 return mask;
260}
261
262static long rpcrouter_ioctl(struct file *filp, unsigned int cmd,
263 unsigned long arg)
264{
265 struct rpcrouter_file_info *file_info = filp->private_data;
266 struct msm_rpc_endpoint *ept;
267 struct rpcrouter_ioctl_server_args server_args;
268 int rc = 0;
269 uint32_t n;
270
271 ept = (struct msm_rpc_endpoint *) file_info->ept;
272 switch (cmd) {
273
274 case RPC_ROUTER_IOCTL_GET_VERSION:
275 n = RPC_ROUTER_VERSION_V1;
276 rc = put_user(n, (unsigned int *) arg);
277 break;
278
279 case RPC_ROUTER_IOCTL_GET_MTU:
280 /* the pacmark word reduces the actual payload
281 * possible per message
282 */
283 n = RPCROUTER_MSGSIZE_MAX - sizeof(uint32_t);
284 rc = put_user(n, (unsigned int *) arg);
285 break;
286
287 case RPC_ROUTER_IOCTL_REGISTER_SERVER:
288 rc = copy_from_user(&server_args, (void *) arg,
289 sizeof(server_args));
290 if (rc < 0)
291 break;
292 msm_rpc_register_server(ept,
293 server_args.prog,
294 server_args.vers);
295 break;
296
297 case RPC_ROUTER_IOCTL_UNREGISTER_SERVER:
298 rc = copy_from_user(&server_args, (void *) arg,
299 sizeof(server_args));
300 if (rc < 0)
301 break;
302
303 msm_rpc_unregister_server(ept,
304 server_args.prog,
305 server_args.vers);
306 break;
307
308 case RPC_ROUTER_IOCTL_CLEAR_NETRESET:
309 msm_rpc_clear_netreset(ept);
310 break;
311
312 case RPC_ROUTER_IOCTL_GET_CURR_PKT_SIZE:
313 rc = msm_rpc_get_curr_pkt_size(ept);
314 break;
315
316 default:
317 rc = -EINVAL;
318 break;
319 }
320
321 return rc;
322}
323
324static struct file_operations rpcrouter_server_fops = {
325 .owner = THIS_MODULE,
326 .open = rpcrouter_open,
327 .release = rpcrouter_release,
328 .read = rpcrouter_read,
329 .write = rpcrouter_write,
330 .poll = rpcrouter_poll,
331 .unlocked_ioctl = rpcrouter_ioctl,
332};
333
334static struct file_operations rpcrouter_router_fops = {
335 .owner = THIS_MODULE,
336 .open = rpcrouter_open,
337 .release = rpcrouter_release,
338 .read = rpcrouter_read,
339 .write = rpcrouter_write,
340 .poll = rpcrouter_poll,
341 .unlocked_ioctl = rpcrouter_ioctl,
342};
343
344int msm_rpcrouter_create_server_cdev(struct rr_server *server)
345{
346 int rc;
347 uint32_t dev_vers;
348 unsigned long flags;
349
350 spin_lock_irqsave(&server_cdev_lock, flags);
351 if (next_minor == RPCROUTER_MAX_REMOTE_SERVERS) {
352 spin_unlock_irqrestore(&server_cdev_lock, flags);
353 printk(KERN_ERR
354 "rpcrouter: Minor numbers exhausted - Increase "
355 "RPCROUTER_MAX_REMOTE_SERVERS\n");
356 return -ENOBUFS;
357 }
358
359 /* Servers with bit 31 set are remote msm servers with hashkey version.
360 * Servers with bit 31 not set are remote msm servers with
361 * backwards compatible version type in which case the minor number
362 * (lower 16 bits) is set to zero.
363 *
364 */
365 if ((server->vers & 0x80000000))
366 dev_vers = server->vers;
367 else
368 dev_vers = server->vers & 0xffff0000;
369
370 server->device_number =
371 MKDEV(MAJOR(msm_rpcrouter_devno), next_minor++);
372 spin_unlock_irqrestore(&server_cdev_lock, flags);
373
374 server->device =
375 device_create(msm_rpcrouter_class, rpcrouter_device,
376 server->device_number, NULL, "%.8x:%.8x",
377 server->prog, dev_vers);
378 if (IS_ERR(server->device)) {
379 printk(KERN_ERR
380 "rpcrouter: Unable to create device (%ld)\n",
381 PTR_ERR(server->device));
382 return PTR_ERR(server->device);;
383 }
384
385 cdev_init(&server->cdev, &rpcrouter_server_fops);
386 server->cdev.owner = THIS_MODULE;
387
388 rc = cdev_add(&server->cdev, server->device_number, 1);
389 if (rc < 0) {
390 printk(KERN_ERR
391 "rpcrouter: Unable to add chrdev (%d)\n", rc);
392 device_destroy(msm_rpcrouter_class, server->device_number);
393 return rc;
394 }
395 return 0;
396}
397
398/* for backward compatible version type (31st bit cleared)
399 * clearing minor number (lower 16 bits) in device name
400 * is neccessary for driver binding
401 */
402int msm_rpcrouter_create_server_pdev(struct rr_server *server)
403{
404 server->p_device.base.id = (server->vers & RPC_VERSION_MODE_MASK) ?
405 server->vers :
406 (server->vers & RPC_VERSION_MAJOR_MASK);
407 server->p_device.base.name = server->pdev_name;
408
409 server->p_device.prog = server->prog;
410 server->p_device.vers = server->vers;
411
412 platform_device_register(&server->p_device.base);
413 return 0;
414}
415
416int msm_rpcrouter_init_devices(void)
417{
418 int rc;
419 int major;
420
421 /* Create the device nodes */
422 msm_rpcrouter_class = class_create(THIS_MODULE, "oncrpc");
423 if (IS_ERR(msm_rpcrouter_class)) {
424 rc = -ENOMEM;
425 printk(KERN_ERR
426 "rpcrouter: failed to create oncrpc class\n");
427 goto fail;
428 }
429
430 rc = alloc_chrdev_region(&msm_rpcrouter_devno, 0,
431 RPCROUTER_MAX_REMOTE_SERVERS + 1,
432 "oncrpc");
433 if (rc < 0) {
434 printk(KERN_ERR
435 "rpcrouter: Failed to alloc chardev region (%d)\n", rc);
436 goto fail_destroy_class;
437 }
438
439 major = MAJOR(msm_rpcrouter_devno);
440 rpcrouter_device = device_create(msm_rpcrouter_class, NULL,
441 msm_rpcrouter_devno, NULL, "%.8x:%d",
442 0, 0);
443 if (IS_ERR(rpcrouter_device)) {
444 rc = -ENOMEM;
445 goto fail_unregister_cdev_region;
446 }
447
448 cdev_init(&rpcrouter_cdev, &rpcrouter_router_fops);
449 rpcrouter_cdev.owner = THIS_MODULE;
450
451 rc = cdev_add(&rpcrouter_cdev, msm_rpcrouter_devno, 1);
452 if (rc < 0)
453 goto fail_destroy_device;
454
455 return 0;
456
457fail_destroy_device:
458 device_destroy(msm_rpcrouter_class, msm_rpcrouter_devno);
459fail_unregister_cdev_region:
460 unregister_chrdev_region(msm_rpcrouter_devno,
461 RPCROUTER_MAX_REMOTE_SERVERS + 1);
462fail_destroy_class:
463 class_destroy(msm_rpcrouter_class);
464fail:
465 return rc;
466}
467
468void msm_rpcrouter_exit_devices(void)
469{
470 cdev_del(&rpcrouter_cdev);
471 device_destroy(msm_rpcrouter_class, msm_rpcrouter_devno);
472 unregister_chrdev_region(msm_rpcrouter_devno,
473 RPCROUTER_MAX_REMOTE_SERVERS + 1);
474 class_destroy(msm_rpcrouter_class);
475}
476