blob: ea9d24608b20b660a8be382c81a1d7f51ade047b [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* Copyright (c) 2011, 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#define DEBUG
14
15#include <linux/slab.h>
16#include <linux/module.h>
17#include <linux/kernel.h>
18#include <linux/string.h>
19#include <linux/errno.h>
20#include <linux/init.h>
21#include <linux/types.h>
22#include <linux/delay.h>
23#include <linux/err.h>
24#include <linux/sched.h>
25#include <linux/poll.h>
26#include <linux/wakelock.h>
27#include <linux/platform_device.h>
28#include <linux/uaccess.h>
29#include <linux/debugfs.h>
30
31#include <asm/uaccess.h>
32#include <asm/byteorder.h>
33
34#include <mach/smem_log.h>
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -060035#include <mach/subsystem_notif.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070036
37#include "ipc_router.h"
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -060038#include "modem_notifier.h"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070039
40enum {
41 SMEM_LOG = 1U << 0,
42 RTR_DBG = 1U << 1,
43 R2R_MSG = 1U << 2,
44 R2R_RAW = 1U << 3,
45 NTFY_MSG = 1U << 4,
46 R2R_RAW_HDR = 1U << 5,
47};
48
49static int msm_ipc_router_debug_mask;
50module_param_named(debug_mask, msm_ipc_router_debug_mask,
51 int, S_IRUGO | S_IWUSR | S_IWGRP);
52
53#define DIAG(x...) pr_info("[RR] ERROR " x)
54
55#if defined(DEBUG)
56#define D(x...) do { \
57if (msm_ipc_router_debug_mask & RTR_DBG) \
58 pr_info(x); \
59} while (0)
60
61#define RR(x...) do { \
62if (msm_ipc_router_debug_mask & R2R_MSG) \
63 pr_info("[RR] "x); \
64} while (0)
65
66#define RAW(x...) do { \
67if (msm_ipc_router_debug_mask & R2R_RAW) \
68 pr_info("[RAW] "x); \
69} while (0)
70
71#define NTFY(x...) do { \
72if (msm_ipc_router_debug_mask & NTFY_MSG) \
73 pr_info("[NOTIFY] "x); \
74} while (0)
75
76#define RAW_HDR(x...) do { \
77if (msm_ipc_router_debug_mask & R2R_RAW_HDR) \
78 pr_info("[HDR] "x); \
79} while (0)
80#else
81#define D(x...) do { } while (0)
82#define RR(x...) do { } while (0)
83#define RAW(x...) do { } while (0)
84#define RAW_HDR(x...) do { } while (0)
85#define NTFY(x...) do { } while (0)
86#endif
87
88#define IPC_ROUTER_LOG_EVENT_ERROR 0x10
89#define IPC_ROUTER_LOG_EVENT_TX 0x11
90#define IPC_ROUTER_LOG_EVENT_RX 0x12
91
92static LIST_HEAD(control_ports);
93static DEFINE_MUTEX(control_ports_lock);
94
95#define LP_HASH_SIZE 32
96static struct list_head local_ports[LP_HASH_SIZE];
97static DEFINE_MUTEX(local_ports_lock);
98
99#define SRV_HASH_SIZE 32
100static struct list_head server_list[SRV_HASH_SIZE];
101static DEFINE_MUTEX(server_list_lock);
102static wait_queue_head_t newserver_wait;
103
104struct msm_ipc_server {
105 struct list_head list;
106 struct msm_ipc_port_name name;
107 struct list_head server_port_list;
108};
109
110struct msm_ipc_server_port {
111 struct list_head list;
112 struct msm_ipc_port_addr server_addr;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600113 struct msm_ipc_router_xprt_info *xprt_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700114};
115
116#define RP_HASH_SIZE 32
117struct msm_ipc_router_remote_port {
118 struct list_head list;
119 uint32_t node_id;
120 uint32_t port_id;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600121 uint32_t restart_state;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700122 wait_queue_head_t quota_wait;
123 uint32_t tx_quota_cnt;
124 struct mutex quota_lock;
125};
126
127struct msm_ipc_router_xprt_info {
128 struct list_head list;
129 struct msm_ipc_router_xprt *xprt;
130 uint32_t remote_node_id;
131 uint32_t initialized;
132 struct list_head pkt_list;
133 wait_queue_head_t read_wait;
134 struct wake_lock wakelock;
135 struct mutex rx_lock;
136 struct mutex tx_lock;
137 uint32_t need_len;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600138 uint32_t abort_data_read;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700139 struct work_struct read_data;
140 struct workqueue_struct *workqueue;
141};
142
143#define RT_HASH_SIZE 4
144struct msm_ipc_routing_table_entry {
145 struct list_head list;
146 uint32_t node_id;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600147 uint32_t neighbor_node_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700148 struct list_head remote_port_list[RP_HASH_SIZE];
149 struct msm_ipc_router_xprt_info *xprt_info;
150 struct mutex lock;
151 unsigned long num_tx_bytes;
152 unsigned long num_rx_bytes;
153};
154
155static struct list_head routing_table[RT_HASH_SIZE];
156static DEFINE_MUTEX(routing_table_lock);
157static int routing_table_inited;
158
159static LIST_HEAD(msm_ipc_board_dev_list);
160static DEFINE_MUTEX(msm_ipc_board_dev_list_lock);
161
162static void do_read_data(struct work_struct *work);
163
164#define RR_STATE_IDLE 0
165#define RR_STATE_HEADER 1
166#define RR_STATE_BODY 2
167#define RR_STATE_ERROR 3
168
169#define RESTART_NORMAL 0
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600170#define RESTART_PEND 1
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700171
172/* State for remote ep following restart */
173#define RESTART_QUOTA_ABORT 1
174
175static LIST_HEAD(xprt_info_list);
176static DEFINE_MUTEX(xprt_info_list_lock);
177
178DECLARE_COMPLETION(msm_ipc_remote_router_up);
179
180static uint32_t next_port_id;
181static DEFINE_MUTEX(next_port_id_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600182static atomic_t pending_close_count = ATOMIC_INIT(0);
183static wait_queue_head_t subsystem_restart_wait;
184static struct workqueue_struct *msm_ipc_router_workqueue;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700185
186enum {
187 CLIENT_PORT,
188 SERVER_PORT,
189 CONTROL_PORT,
190};
191
192enum {
193 DOWN,
194 UP,
195};
196
197static void init_routing_table(void)
198{
199 int i;
200 for (i = 0; i < RT_HASH_SIZE; i++)
201 INIT_LIST_HEAD(&routing_table[i]);
202}
203
204static struct msm_ipc_routing_table_entry *alloc_routing_table_entry(
205 uint32_t node_id)
206{
207 int i;
208 struct msm_ipc_routing_table_entry *rt_entry;
209
210 rt_entry = kmalloc(sizeof(struct msm_ipc_routing_table_entry),
211 GFP_KERNEL);
212 if (!rt_entry) {
213 pr_err("%s: rt_entry allocation failed for %d\n",
214 __func__, node_id);
215 return NULL;
216 }
217
218 for (i = 0; i < RP_HASH_SIZE; i++)
219 INIT_LIST_HEAD(&rt_entry->remote_port_list[i]);
220
221 mutex_init(&rt_entry->lock);
222 rt_entry->node_id = node_id;
223 rt_entry->xprt_info = NULL;
224 return rt_entry;
225}
226
227/*Please take routing_table_lock before calling this function*/
228static int add_routing_table_entry(
229 struct msm_ipc_routing_table_entry *rt_entry)
230{
231 uint32_t key;
232
233 if (!rt_entry)
234 return -EINVAL;
235
236 key = (rt_entry->node_id % RT_HASH_SIZE);
237 list_add_tail(&rt_entry->list, &routing_table[key]);
238 return 0;
239}
240
241/*Please take routing_table_lock before calling this function*/
242static struct msm_ipc_routing_table_entry *lookup_routing_table(
243 uint32_t node_id)
244{
245 uint32_t key = (node_id % RT_HASH_SIZE);
246 struct msm_ipc_routing_table_entry *rt_entry;
247
248 list_for_each_entry(rt_entry, &routing_table[key], list) {
249 if (rt_entry->node_id == node_id)
250 return rt_entry;
251 }
252 return NULL;
253}
254
255struct rr_packet *rr_read(struct msm_ipc_router_xprt_info *xprt_info)
256{
257 struct rr_packet *temp_pkt;
258
259 if (!xprt_info)
260 return NULL;
261
262 mutex_lock(&xprt_info->rx_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600263 while (!(xprt_info->abort_data_read) &&
264 list_empty(&xprt_info->pkt_list)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700265 mutex_unlock(&xprt_info->rx_lock);
266 wait_event(xprt_info->read_wait,
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600267 ((xprt_info->abort_data_read) ||
268 !list_empty(&xprt_info->pkt_list)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700269 mutex_lock(&xprt_info->rx_lock);
270 }
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600271 if (xprt_info->abort_data_read) {
272 mutex_unlock(&xprt_info->rx_lock);
273 return NULL;
274 }
275
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700276 temp_pkt = list_first_entry(&xprt_info->pkt_list,
277 struct rr_packet, list);
278 list_del(&temp_pkt->list);
279 if (list_empty(&xprt_info->pkt_list))
280 wake_unlock(&xprt_info->wakelock);
281 mutex_unlock(&xprt_info->rx_lock);
282 return temp_pkt;
283}
284
285struct rr_packet *clone_pkt(struct rr_packet *pkt)
286{
287 struct rr_packet *cloned_pkt;
288 struct sk_buff *temp_skb, *cloned_skb;
289 struct sk_buff_head *pkt_fragment_q;
290
291 cloned_pkt = kzalloc(sizeof(struct rr_packet), GFP_KERNEL);
292 if (!cloned_pkt) {
293 pr_err("%s: failure\n", __func__);
294 return NULL;
295 }
296
297 pkt_fragment_q = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
298 if (!pkt_fragment_q) {
299 pr_err("%s: pkt_frag_q alloc failure\n", __func__);
300 kfree(cloned_pkt);
301 return NULL;
302 }
303 skb_queue_head_init(pkt_fragment_q);
304
305 skb_queue_walk(pkt->pkt_fragment_q, temp_skb) {
306 cloned_skb = skb_clone(temp_skb, GFP_KERNEL);
307 if (!cloned_skb)
308 goto fail_clone;
309 skb_queue_tail(pkt_fragment_q, cloned_skb);
310 }
311 cloned_pkt->pkt_fragment_q = pkt_fragment_q;
312 cloned_pkt->length = pkt->length;
313 return cloned_pkt;
314
315fail_clone:
316 while (!skb_queue_empty(pkt_fragment_q)) {
317 temp_skb = skb_dequeue(pkt_fragment_q);
318 kfree_skb(temp_skb);
319 }
320 kfree(pkt_fragment_q);
321 kfree(cloned_pkt);
322 return NULL;
323}
324
325struct rr_packet *create_pkt(struct sk_buff_head *data)
326{
327 struct rr_packet *pkt;
328 struct sk_buff *temp_skb;
329
330 pkt = kzalloc(sizeof(struct rr_packet), GFP_KERNEL);
331 if (!pkt) {
332 pr_err("%s: failure\n", __func__);
333 return NULL;
334 }
335
336 pkt->pkt_fragment_q = data;
337 skb_queue_walk(pkt->pkt_fragment_q, temp_skb)
338 pkt->length += temp_skb->len;
339 return pkt;
340}
341
342void release_pkt(struct rr_packet *pkt)
343{
344 struct sk_buff *temp_skb;
345
346 if (!pkt)
347 return;
348
349 if (!pkt->pkt_fragment_q) {
350 kfree(pkt);
351 return;
352 }
353
354 while (!skb_queue_empty(pkt->pkt_fragment_q)) {
355 temp_skb = skb_dequeue(pkt->pkt_fragment_q);
356 kfree_skb(temp_skb);
357 }
358 kfree(pkt->pkt_fragment_q);
359 kfree(pkt);
360 return;
361}
362
363static int post_control_ports(struct rr_packet *pkt)
364{
365 struct msm_ipc_port *port_ptr;
366 struct rr_packet *cloned_pkt;
367
368 if (!pkt)
369 return -EINVAL;
370
371 mutex_lock(&control_ports_lock);
372 list_for_each_entry(port_ptr, &control_ports, list) {
373 mutex_lock(&port_ptr->port_rx_q_lock);
374 cloned_pkt = clone_pkt(pkt);
375 wake_lock(&port_ptr->port_rx_wake_lock);
376 list_add_tail(&cloned_pkt->list, &port_ptr->port_rx_q);
377 wake_up(&port_ptr->port_rx_wait_q);
378 mutex_unlock(&port_ptr->port_rx_q_lock);
379 }
380 mutex_unlock(&control_ports_lock);
381 return 0;
382}
383
384static uint32_t allocate_port_id(void)
385{
386 uint32_t port_id = 0, prev_port_id, key;
387 struct msm_ipc_port *port_ptr;
388
389 mutex_lock(&next_port_id_lock);
390 prev_port_id = next_port_id;
391 mutex_lock(&local_ports_lock);
392 do {
393 next_port_id++;
394 if ((next_port_id & 0xFFFFFFFE) == 0xFFFFFFFE)
395 next_port_id = 1;
396
397 key = (next_port_id & (LP_HASH_SIZE - 1));
398 if (list_empty(&local_ports[key])) {
399 port_id = next_port_id;
400 break;
401 }
402 list_for_each_entry(port_ptr, &local_ports[key], list) {
403 if (port_ptr->this_port.port_id == next_port_id) {
404 port_id = next_port_id;
405 break;
406 }
407 }
408 if (!port_id) {
409 port_id = next_port_id;
410 break;
411 }
412 port_id = 0;
413 } while (next_port_id != prev_port_id);
414 mutex_unlock(&local_ports_lock);
415 mutex_unlock(&next_port_id_lock);
416
417 return port_id;
418}
419
420void msm_ipc_router_add_local_port(struct msm_ipc_port *port_ptr)
421{
422 uint32_t key;
423
424 if (!port_ptr)
425 return;
426
427 key = (port_ptr->this_port.port_id & (LP_HASH_SIZE - 1));
428 mutex_lock(&local_ports_lock);
429 list_add_tail(&port_ptr->list, &local_ports[key]);
430 mutex_unlock(&local_ports_lock);
431}
432
433struct msm_ipc_port *msm_ipc_router_create_raw_port(void *endpoint,
434 void (*notify)(unsigned event, void *data,
435 void *addr, void *priv),
436 void *priv)
437{
438 struct msm_ipc_port *port_ptr;
439
440 port_ptr = kzalloc(sizeof(struct msm_ipc_port), GFP_KERNEL);
441 if (!port_ptr)
442 return NULL;
443
444 port_ptr->this_port.node_id = IPC_ROUTER_NID_LOCAL;
445 port_ptr->this_port.port_id = allocate_port_id();
446 if (!port_ptr->this_port.port_id) {
447 pr_err("%s: All port ids are in use\n", __func__);
448 kfree(port_ptr);
449 return NULL;
450 }
451
452 spin_lock_init(&port_ptr->port_lock);
453 INIT_LIST_HEAD(&port_ptr->incomplete);
454 mutex_init(&port_ptr->incomplete_lock);
455 INIT_LIST_HEAD(&port_ptr->port_rx_q);
456 mutex_init(&port_ptr->port_rx_q_lock);
457 init_waitqueue_head(&port_ptr->port_rx_wait_q);
458 wake_lock_init(&port_ptr->port_rx_wake_lock,
459 WAKE_LOCK_SUSPEND, "msm_ipc_read");
460
461 port_ptr->endpoint = endpoint;
462 port_ptr->notify = notify;
463 port_ptr->priv = priv;
464
465 msm_ipc_router_add_local_port(port_ptr);
466 return port_ptr;
467}
468
469static struct msm_ipc_port *msm_ipc_router_lookup_local_port(uint32_t port_id)
470{
471 int key = (port_id & (LP_HASH_SIZE - 1));
472 struct msm_ipc_port *port_ptr;
473
474 mutex_lock(&local_ports_lock);
475 list_for_each_entry(port_ptr, &local_ports[key], list) {
476 if (port_ptr->this_port.port_id == port_id) {
477 mutex_unlock(&local_ports_lock);
478 return port_ptr;
479 }
480 }
481 mutex_unlock(&local_ports_lock);
482 return NULL;
483}
484
485static struct msm_ipc_router_remote_port *msm_ipc_router_lookup_remote_port(
486 uint32_t node_id,
487 uint32_t port_id)
488{
489 struct msm_ipc_router_remote_port *rport_ptr;
490 struct msm_ipc_routing_table_entry *rt_entry;
491 int key = (port_id & (RP_HASH_SIZE - 1));
492
493 mutex_lock(&routing_table_lock);
494 rt_entry = lookup_routing_table(node_id);
495 if (!rt_entry) {
496 mutex_unlock(&routing_table_lock);
497 pr_err("%s: Node is not up\n", __func__);
498 return NULL;
499 }
500
501 mutex_lock(&rt_entry->lock);
502 list_for_each_entry(rport_ptr,
503 &rt_entry->remote_port_list[key], list) {
504 if (rport_ptr->port_id == port_id) {
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600505 if (rport_ptr->restart_state != RESTART_NORMAL)
506 rport_ptr = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700507 mutex_unlock(&rt_entry->lock);
508 mutex_unlock(&routing_table_lock);
509 return rport_ptr;
510 }
511 }
512 mutex_unlock(&rt_entry->lock);
513 mutex_unlock(&routing_table_lock);
514 return NULL;
515}
516
517static struct msm_ipc_router_remote_port *msm_ipc_router_create_remote_port(
518 uint32_t node_id,
519 uint32_t port_id)
520{
521 struct msm_ipc_router_remote_port *rport_ptr;
522 struct msm_ipc_routing_table_entry *rt_entry;
523 int key = (port_id & (RP_HASH_SIZE - 1));
524
525 mutex_lock(&routing_table_lock);
526 rt_entry = lookup_routing_table(node_id);
527 if (!rt_entry) {
528 mutex_unlock(&routing_table_lock);
529 pr_err("%s: Node is not up\n", __func__);
530 return NULL;
531 }
532
533 mutex_lock(&rt_entry->lock);
534 rport_ptr = kmalloc(sizeof(struct msm_ipc_router_remote_port),
535 GFP_KERNEL);
536 if (!rport_ptr) {
537 mutex_unlock(&rt_entry->lock);
538 mutex_unlock(&routing_table_lock);
539 pr_err("%s: Remote port alloc failed\n", __func__);
540 return NULL;
541 }
542 rport_ptr->port_id = port_id;
543 rport_ptr->node_id = node_id;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600544 rport_ptr->restart_state = RESTART_NORMAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700545 rport_ptr->tx_quota_cnt = 0;
546 init_waitqueue_head(&rport_ptr->quota_wait);
547 mutex_init(&rport_ptr->quota_lock);
548 list_add_tail(&rport_ptr->list,
549 &rt_entry->remote_port_list[key]);
550 mutex_unlock(&rt_entry->lock);
551 mutex_unlock(&routing_table_lock);
552 return rport_ptr;
553}
554
555static void msm_ipc_router_destroy_remote_port(
556 struct msm_ipc_router_remote_port *rport_ptr)
557{
558 uint32_t node_id;
559 struct msm_ipc_routing_table_entry *rt_entry;
560
561 if (!rport_ptr)
562 return;
563
564 node_id = rport_ptr->node_id;
565 mutex_lock(&routing_table_lock);
566 rt_entry = lookup_routing_table(node_id);
567 if (!rt_entry) {
568 mutex_unlock(&routing_table_lock);
569 pr_err("%s: Node %d is not up\n", __func__, node_id);
570 return;
571 }
572
573 mutex_lock(&rt_entry->lock);
574 list_del(&rport_ptr->list);
575 kfree(rport_ptr);
576 mutex_unlock(&rt_entry->lock);
577 mutex_unlock(&routing_table_lock);
578 return;
579}
580
581static struct msm_ipc_server *msm_ipc_router_lookup_server(
582 uint32_t service,
583 uint32_t instance,
584 uint32_t node_id,
585 uint32_t port_id)
586{
587 struct msm_ipc_server *server;
588 struct msm_ipc_server_port *server_port;
589 int key = (instance & (SRV_HASH_SIZE - 1));
590
591 mutex_lock(&server_list_lock);
592 list_for_each_entry(server, &server_list[key], list) {
593 if ((server->name.service != service) ||
594 (server->name.instance != instance))
595 continue;
596 if ((node_id == 0) && (port_id == 0)) {
597 mutex_unlock(&server_list_lock);
598 return server;
599 }
600 list_for_each_entry(server_port, &server->server_port_list,
601 list) {
602 if ((server_port->server_addr.node_id == node_id) &&
603 (server_port->server_addr.port_id == port_id)) {
604 mutex_unlock(&server_list_lock);
605 return server;
606 }
607 }
608 }
609 mutex_unlock(&server_list_lock);
610 return NULL;
611}
612
613static struct msm_ipc_server *msm_ipc_router_create_server(
614 uint32_t service,
615 uint32_t instance,
616 uint32_t node_id,
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600617 uint32_t port_id,
618 struct msm_ipc_router_xprt_info *xprt_info)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700619{
620 struct msm_ipc_server *server = NULL;
621 struct msm_ipc_server_port *server_port;
622 int key = (instance & (SRV_HASH_SIZE - 1));
623
624 mutex_lock(&server_list_lock);
625 list_for_each_entry(server, &server_list[key], list) {
626 if ((server->name.service == service) &&
627 (server->name.instance == instance))
628 goto create_srv_port;
629 }
630
631 server = kmalloc(sizeof(struct msm_ipc_server), GFP_KERNEL);
632 if (!server) {
633 mutex_unlock(&server_list_lock);
634 pr_err("%s: Server allocation failed\n", __func__);
635 return NULL;
636 }
637 server->name.service = service;
638 server->name.instance = instance;
639 INIT_LIST_HEAD(&server->server_port_list);
640 list_add_tail(&server->list, &server_list[key]);
641
642create_srv_port:
643 server_port = kmalloc(sizeof(struct msm_ipc_server_port), GFP_KERNEL);
644 if (!server_port) {
645 if (list_empty(&server->server_port_list)) {
646 list_del(&server->list);
647 kfree(server);
648 }
649 mutex_unlock(&server_list_lock);
650 pr_err("%s: Server Port allocation failed\n", __func__);
651 return NULL;
652 }
653 server_port->server_addr.node_id = node_id;
654 server_port->server_addr.port_id = port_id;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600655 server_port->xprt_info = xprt_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700656 list_add_tail(&server_port->list, &server->server_port_list);
657 mutex_unlock(&server_list_lock);
658
659 return server;
660}
661
662static void msm_ipc_router_destroy_server(struct msm_ipc_server *server,
663 uint32_t node_id, uint32_t port_id)
664{
665 struct msm_ipc_server_port *server_port;
666
667 if (!server)
668 return;
669
670 mutex_lock(&server_list_lock);
671 list_for_each_entry(server_port, &server->server_port_list, list) {
672 if ((server_port->server_addr.node_id == node_id) &&
673 (server_port->server_addr.port_id == port_id))
674 break;
675 }
676 if (server_port) {
677 list_del(&server_port->list);
678 kfree(server_port);
679 }
680 if (list_empty(&server->server_port_list)) {
681 list_del(&server->list);
682 kfree(server);
683 }
684 mutex_unlock(&server_list_lock);
685 return;
686}
687
688static int msm_ipc_router_send_control_msg(
689 struct msm_ipc_router_xprt_info *xprt_info,
690 union rr_control_msg *msg)
691{
692 struct rr_packet *pkt;
693 struct sk_buff *ipc_rtr_pkt;
694 struct rr_header *hdr;
695 int pkt_size;
696 void *data;
697 struct sk_buff_head *pkt_fragment_q;
698 int ret;
699
700 if (!xprt_info || ((msg->cmd != IPC_ROUTER_CTRL_CMD_HELLO) &&
701 !xprt_info->initialized)) {
702 pr_err("%s: xprt_info not initialized\n", __func__);
703 return -EINVAL;
704 }
705
706 if (xprt_info->remote_node_id == IPC_ROUTER_NID_LOCAL)
707 return 0;
708
709 pkt = kzalloc(sizeof(struct rr_packet), GFP_KERNEL);
710 if (!pkt) {
711 pr_err("%s: pkt alloc failed\n", __func__);
712 return -ENOMEM;
713 }
714
715 pkt_fragment_q = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
716 if (!pkt_fragment_q) {
717 pr_err("%s: pkt_fragment_q alloc failed\n", __func__);
718 kfree(pkt);
719 return -ENOMEM;
720 }
721 skb_queue_head_init(pkt_fragment_q);
722
723 pkt_size = IPC_ROUTER_HDR_SIZE + sizeof(*msg);
724 ipc_rtr_pkt = alloc_skb(pkt_size, GFP_KERNEL);
725 if (!ipc_rtr_pkt) {
726 pr_err("%s: ipc_rtr_pkt alloc failed\n", __func__);
727 kfree(pkt_fragment_q);
728 kfree(pkt);
729 return -ENOMEM;
730 }
731
732 skb_reserve(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
733 data = skb_put(ipc_rtr_pkt, sizeof(*msg));
734 memcpy(data, msg, sizeof(*msg));
735 hdr = (struct rr_header *)skb_push(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
736 if (!hdr) {
737 pr_err("%s: skb_push failed\n", __func__);
738 kfree_skb(ipc_rtr_pkt);
739 kfree(pkt_fragment_q);
740 kfree(pkt);
741 return -ENOMEM;
742 }
743
744 hdr->version = IPC_ROUTER_VERSION;
745 hdr->type = msg->cmd;
746 hdr->src_node_id = IPC_ROUTER_NID_LOCAL;
747 hdr->src_port_id = IPC_ROUTER_ADDRESS;
748 hdr->confirm_rx = 0;
749 hdr->size = sizeof(*msg);
750 hdr->dst_node_id = xprt_info->remote_node_id;
751 hdr->dst_port_id = IPC_ROUTER_ADDRESS;
752 skb_queue_tail(pkt_fragment_q, ipc_rtr_pkt);
753 pkt->pkt_fragment_q = pkt_fragment_q;
754 pkt->length = pkt_size;
755
756 mutex_lock(&xprt_info->tx_lock);
757 ret = xprt_info->xprt->write(pkt, pkt_size, 0);
758 mutex_unlock(&xprt_info->tx_lock);
759
760 release_pkt(pkt);
761 return ret;
762}
763
764static int msm_ipc_router_send_server_list(
765 struct msm_ipc_router_xprt_info *xprt_info)
766{
767 union rr_control_msg ctl;
768 struct msm_ipc_server *server;
769 struct msm_ipc_server_port *server_port;
770 int i;
771
772 if (!xprt_info || !xprt_info->initialized) {
773 pr_err("%s: Xprt info not initialized\n", __func__);
774 return -EINVAL;
775 }
776
777 ctl.cmd = IPC_ROUTER_CTRL_CMD_NEW_SERVER;
778
779 mutex_lock(&server_list_lock);
780 for (i = 0; i < SRV_HASH_SIZE; i++) {
781 list_for_each_entry(server, &server_list[i], list) {
782 ctl.srv.service = server->name.service;
783 ctl.srv.instance = server->name.instance;
784 list_for_each_entry(server_port,
785 &server->server_port_list, list) {
786 if (server_port->server_addr.node_id ==
787 xprt_info->remote_node_id)
788 continue;
789
790 ctl.srv.node_id =
791 server_port->server_addr.node_id;
792 ctl.srv.port_id =
793 server_port->server_addr.port_id;
794 msm_ipc_router_send_control_msg(xprt_info,
795 &ctl);
796 }
797 }
798 }
799 mutex_unlock(&server_list_lock);
800
801 return 0;
802}
803
804#if defined(DEBUG)
805static char *type_to_str(int i)
806{
807 switch (i) {
808 case IPC_ROUTER_CTRL_CMD_DATA:
809 return "data ";
810 case IPC_ROUTER_CTRL_CMD_HELLO:
811 return "hello ";
812 case IPC_ROUTER_CTRL_CMD_BYE:
813 return "bye ";
814 case IPC_ROUTER_CTRL_CMD_NEW_SERVER:
815 return "new_srvr";
816 case IPC_ROUTER_CTRL_CMD_REMOVE_SERVER:
817 return "rmv_srvr";
818 case IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT:
819 return "rmv_clnt";
820 case IPC_ROUTER_CTRL_CMD_RESUME_TX:
821 return "resum_tx";
822 case IPC_ROUTER_CTRL_CMD_EXIT:
823 return "cmd_exit";
824 default:
825 return "invalid";
826 }
827}
828#endif
829
830static int broadcast_ctl_msg_locally(union rr_control_msg *msg)
831{
832 struct rr_packet *pkt;
833 struct sk_buff *ipc_rtr_pkt;
834 struct rr_header *hdr;
835 int pkt_size;
836 void *data;
837 struct sk_buff_head *pkt_fragment_q;
838 int ret;
839
840 pkt = kzalloc(sizeof(struct rr_packet), GFP_KERNEL);
841 if (!pkt) {
842 pr_err("%s: pkt alloc failed\n", __func__);
843 return -ENOMEM;
844 }
845
846 pkt_fragment_q = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
847 if (!pkt_fragment_q) {
848 pr_err("%s: pkt_fragment_q alloc failed\n", __func__);
849 kfree(pkt);
850 return -ENOMEM;
851 }
852 skb_queue_head_init(pkt_fragment_q);
853
854 pkt_size = IPC_ROUTER_HDR_SIZE + sizeof(*msg);
855 ipc_rtr_pkt = alloc_skb(pkt_size, GFP_KERNEL);
856 if (!ipc_rtr_pkt) {
857 pr_err("%s: ipc_rtr_pkt alloc failed\n", __func__);
858 kfree(pkt_fragment_q);
859 kfree(pkt);
860 return -ENOMEM;
861 }
862
863 skb_reserve(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
864 data = skb_put(ipc_rtr_pkt, sizeof(*msg));
865 memcpy(data, msg, sizeof(*msg));
866 hdr = (struct rr_header *)skb_push(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
867 if (!hdr) {
868 pr_err("%s: skb_push failed\n", __func__);
869 kfree_skb(ipc_rtr_pkt);
870 kfree(pkt_fragment_q);
871 kfree(pkt);
872 return -ENOMEM;
873 }
874 hdr->version = IPC_ROUTER_VERSION;
875 hdr->type = msg->cmd;
876 hdr->src_node_id = IPC_ROUTER_NID_LOCAL;
877 hdr->src_port_id = IPC_ROUTER_ADDRESS;
878 hdr->confirm_rx = 0;
879 hdr->size = sizeof(*msg);
880 hdr->dst_node_id = IPC_ROUTER_NID_LOCAL;
881 hdr->dst_port_id = IPC_ROUTER_ADDRESS;
882 skb_queue_tail(pkt_fragment_q, ipc_rtr_pkt);
883 pkt->pkt_fragment_q = pkt_fragment_q;
884 pkt->length = pkt_size;
885
886 ret = post_control_ports(pkt);
887 release_pkt(pkt);
888 return ret;
889}
890
891static int broadcast_ctl_msg(union rr_control_msg *ctl)
892{
893 struct msm_ipc_router_xprt_info *xprt_info;
894
895 mutex_lock(&xprt_info_list_lock);
896 list_for_each_entry(xprt_info, &xprt_info_list, list) {
897 msm_ipc_router_send_control_msg(xprt_info, ctl);
898 }
899 mutex_unlock(&xprt_info_list_lock);
900
901 return 0;
902}
903
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600904static int relay_ctl_msg(struct msm_ipc_router_xprt_info *xprt_info,
905 union rr_control_msg *ctl)
906{
907 struct msm_ipc_router_xprt_info *fwd_xprt_info;
908
909 if (!xprt_info || !ctl)
910 return -EINVAL;
911
912 mutex_lock(&xprt_info_list_lock);
913 list_for_each_entry(fwd_xprt_info, &xprt_info_list, list) {
914 if (xprt_info->xprt->link_id != fwd_xprt_info->xprt->link_id)
915 msm_ipc_router_send_control_msg(fwd_xprt_info, ctl);
916 }
917 mutex_unlock(&xprt_info_list_lock);
918
919 return 0;
920}
921
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700922static int relay_msg(struct msm_ipc_router_xprt_info *xprt_info,
923 struct rr_packet *pkt)
924{
925 struct msm_ipc_router_xprt_info *fwd_xprt_info;
926
927 if (!xprt_info || !pkt)
928 return -EINVAL;
929
930 mutex_lock(&xprt_info_list_lock);
931 list_for_each_entry(fwd_xprt_info, &xprt_info_list, list) {
932 mutex_lock(&fwd_xprt_info->tx_lock);
933 if (xprt_info->xprt->link_id != fwd_xprt_info->xprt->link_id)
934 fwd_xprt_info->xprt->write(pkt, pkt->length, 0);
935 mutex_unlock(&fwd_xprt_info->tx_lock);
936 }
937 mutex_unlock(&xprt_info_list_lock);
938 return 0;
939}
940
941static int forward_msg(struct msm_ipc_router_xprt_info *xprt_info,
942 struct rr_packet *pkt)
943{
944 uint32_t dst_node_id;
945 struct sk_buff *head_pkt;
946 struct rr_header *hdr;
947 struct msm_ipc_router_xprt_info *fwd_xprt_info;
948 struct msm_ipc_routing_table_entry *rt_entry;
949
950 if (!xprt_info || !pkt)
951 return -EINVAL;
952
953 head_pkt = skb_peek(pkt->pkt_fragment_q);
954 if (!head_pkt)
955 return -EINVAL;
956
957 hdr = (struct rr_header *)head_pkt->data;
958 dst_node_id = hdr->dst_node_id;
959 mutex_lock(&routing_table_lock);
960 rt_entry = lookup_routing_table(dst_node_id);
961 if (!(rt_entry) || !(rt_entry->xprt_info)) {
962 mutex_unlock(&routing_table_lock);
963 pr_err("%s: Routing table not initialized\n", __func__);
964 return -ENODEV;
965 }
966
967 mutex_lock(&rt_entry->lock);
968 fwd_xprt_info = rt_entry->xprt_info;
969 mutex_lock(&fwd_xprt_info->tx_lock);
970 if (xprt_info->remote_node_id == fwd_xprt_info->remote_node_id) {
971 mutex_unlock(&fwd_xprt_info->tx_lock);
972 mutex_unlock(&rt_entry->lock);
973 mutex_unlock(&routing_table_lock);
974 pr_err("%s: Discarding Command to route back\n", __func__);
975 return -EINVAL;
976 }
977
978 if (xprt_info->xprt->link_id == fwd_xprt_info->xprt->link_id) {
979 mutex_unlock(&fwd_xprt_info->tx_lock);
980 mutex_unlock(&rt_entry->lock);
981 mutex_unlock(&routing_table_lock);
982 pr_err("%s: DST in the same cluster\n", __func__);
983 return 0;
984 }
985 fwd_xprt_info->xprt->write(pkt, pkt->length, 0);
986 mutex_unlock(&fwd_xprt_info->tx_lock);
987 mutex_unlock(&rt_entry->lock);
988 mutex_unlock(&routing_table_lock);
989
990 return 0;
991}
992
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600993static void reset_remote_port_info(uint32_t node_id, uint32_t port_id)
994{
995 struct msm_ipc_router_remote_port *rport_ptr;
996
997 rport_ptr = msm_ipc_router_lookup_remote_port(node_id, port_id);
998 if (!rport_ptr) {
999 pr_err("%s: No such remote port %08x:%08x\n",
1000 __func__, node_id, port_id);
1001 return;
1002 }
1003 mutex_lock(&rport_ptr->quota_lock);
1004 rport_ptr->restart_state = RESTART_PEND;
1005 wake_up(&rport_ptr->quota_wait);
1006 mutex_unlock(&rport_ptr->quota_lock);
1007 return;
1008}
1009
1010static void msm_ipc_cleanup_remote_server_info(
1011 struct msm_ipc_router_xprt_info *xprt_info)
1012{
1013 struct msm_ipc_server *svr, *tmp_svr;
1014 struct msm_ipc_server_port *svr_port, *tmp_svr_port;
1015 int i;
1016 union rr_control_msg ctl;
1017
1018 if (!xprt_info) {
1019 pr_err("%s: Invalid xprt_info\n", __func__);
1020 return;
1021 }
1022
1023 ctl.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_SERVER;
1024 mutex_lock(&server_list_lock);
1025 for (i = 0; i < SRV_HASH_SIZE; i++) {
1026 list_for_each_entry_safe(svr, tmp_svr, &server_list[i], list) {
1027 ctl.srv.service = svr->name.service;
1028 ctl.srv.instance = svr->name.instance;
1029 list_for_each_entry_safe(svr_port, tmp_svr_port,
1030 &svr->server_port_list, list) {
1031 if (svr_port->xprt_info != xprt_info)
1032 continue;
1033 D("Remove server %08x:%08x - %08x:%08x",
1034 ctl.srv.service, ctl.srv.instance,
1035 svr_port->server_addr.node_id,
1036 svr_port->server_addr.port_id);
1037 reset_remote_port_info(
1038 svr_port->server_addr.node_id,
1039 svr_port->server_addr.port_id);
1040 ctl.srv.node_id = svr_port->server_addr.node_id;
1041 ctl.srv.port_id = svr_port->server_addr.port_id;
1042 relay_ctl_msg(xprt_info, &ctl);
1043 broadcast_ctl_msg_locally(&ctl);
1044 list_del(&svr_port->list);
1045 kfree(svr_port);
1046 }
1047 if (list_empty(&svr->server_port_list)) {
1048 list_del(&svr->list);
1049 kfree(svr);
1050 }
1051 }
1052 }
1053 mutex_unlock(&server_list_lock);
1054}
1055
1056static void msm_ipc_cleanup_remote_client_info(
1057 struct msm_ipc_router_xprt_info *xprt_info)
1058{
1059 struct msm_ipc_routing_table_entry *rt_entry;
1060 struct msm_ipc_router_remote_port *rport_ptr;
1061 int i, j;
1062 union rr_control_msg ctl;
1063
1064 if (!xprt_info) {
1065 pr_err("%s: Invalid xprt_info\n", __func__);
1066 return;
1067 }
1068
1069 ctl.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT;
1070 mutex_lock(&routing_table_lock);
1071 for (i = 0; i < RT_HASH_SIZE; i++) {
1072 list_for_each_entry(rt_entry, &routing_table[i], list) {
1073 mutex_lock(&rt_entry->lock);
1074 if (rt_entry->xprt_info != xprt_info) {
1075 mutex_unlock(&rt_entry->lock);
1076 continue;
1077 }
1078 for (j = 0; j < RP_HASH_SIZE; j++) {
1079 list_for_each_entry(rport_ptr,
1080 &rt_entry->remote_port_list[j], list) {
1081 if (rport_ptr->restart_state ==
1082 RESTART_PEND)
1083 continue;
1084 mutex_lock(&rport_ptr->quota_lock);
1085 rport_ptr->restart_state = RESTART_PEND;
1086 wake_up(&rport_ptr->quota_wait);
1087 mutex_unlock(&rport_ptr->quota_lock);
1088 ctl.cli.node_id = rport_ptr->node_id;
1089 ctl.cli.port_id = rport_ptr->port_id;
1090 broadcast_ctl_msg_locally(&ctl);
1091 }
1092 }
1093 mutex_unlock(&rt_entry->lock);
1094 }
1095 }
1096 mutex_unlock(&routing_table_lock);
1097}
1098
1099static void msm_ipc_cleanup_remote_port_info(uint32_t node_id)
1100{
1101 struct msm_ipc_routing_table_entry *rt_entry, *tmp_rt_entry;
1102 struct msm_ipc_router_remote_port *rport_ptr, *tmp_rport_ptr;
1103 int i, j;
1104
1105 mutex_lock(&routing_table_lock);
1106 for (i = 0; i < RT_HASH_SIZE; i++) {
1107 list_for_each_entry_safe(rt_entry, tmp_rt_entry,
1108 &routing_table[i], list) {
1109 mutex_lock(&rt_entry->lock);
1110 if (rt_entry->neighbor_node_id != node_id) {
1111 mutex_unlock(&rt_entry->lock);
1112 continue;
1113 }
1114 for (j = 0; j < RP_HASH_SIZE; j++) {
1115 list_for_each_entry_safe(rport_ptr,
1116 tmp_rport_ptr,
1117 &rt_entry->remote_port_list[j], list) {
1118 list_del(&rport_ptr->list);
1119 kfree(rport_ptr);
1120 }
1121 }
1122 mutex_unlock(&rt_entry->lock);
1123 }
1124 }
1125 mutex_unlock(&routing_table_lock);
1126}
1127
1128static void msm_ipc_cleanup_routing_table(
1129 struct msm_ipc_router_xprt_info *xprt_info)
1130{
1131 int i;
1132 struct msm_ipc_routing_table_entry *rt_entry;
1133
1134 if (!xprt_info) {
1135 pr_err("%s: Invalid xprt_info\n", __func__);
1136 return;
1137 }
1138
1139 mutex_lock(&routing_table_lock);
1140 for (i = 0; i < RT_HASH_SIZE; i++) {
1141 list_for_each_entry(rt_entry, &routing_table[i], list) {
1142 mutex_lock(&rt_entry->lock);
1143 if (rt_entry->xprt_info == xprt_info)
1144 rt_entry->xprt_info = NULL;
1145 mutex_unlock(&rt_entry->lock);
1146 }
1147 }
1148 mutex_unlock(&routing_table_lock);
1149}
1150
1151static void modem_reset_cleanup(struct msm_ipc_router_xprt_info *xprt_info)
1152{
1153
1154 if (!xprt_info) {
1155 pr_err("%s: Invalid xprt_info\n", __func__);
1156 return;
1157 }
1158
1159 msm_ipc_cleanup_remote_server_info(xprt_info);
1160 msm_ipc_cleanup_remote_client_info(xprt_info);
1161 msm_ipc_cleanup_routing_table(xprt_info);
1162}
1163
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001164static int process_control_msg(struct msm_ipc_router_xprt_info *xprt_info,
1165 struct rr_packet *pkt)
1166{
1167 union rr_control_msg ctl;
1168 union rr_control_msg *msg;
1169 struct msm_ipc_router_remote_port *rport_ptr;
1170 int rc = 0;
1171 static uint32_t first = 1;
1172 struct sk_buff *temp_ptr;
1173 struct rr_header *hdr;
1174 struct msm_ipc_server *server;
1175 struct msm_ipc_routing_table_entry *rt_entry;
1176
1177 if (pkt->length != (IPC_ROUTER_HDR_SIZE + sizeof(*msg))) {
1178 pr_err("%s: r2r msg size %d != %d\n", __func__, pkt->length,
1179 (IPC_ROUTER_HDR_SIZE + sizeof(*msg)));
1180 return -EINVAL;
1181 }
1182
1183 temp_ptr = skb_peek(pkt->pkt_fragment_q);
1184 hdr = (struct rr_header *)temp_ptr->data;
1185 msg = (union rr_control_msg *)((char *)hdr + IPC_ROUTER_HDR_SIZE);
1186
1187 switch (msg->cmd) {
1188 case IPC_ROUTER_CTRL_CMD_HELLO:
1189 RR("o HELLO NID %d\n", hdr->src_node_id);
1190 xprt_info->remote_node_id = hdr->src_node_id;
1191
1192 mutex_lock(&routing_table_lock);
1193 rt_entry = lookup_routing_table(hdr->src_node_id);
1194 if (!rt_entry) {
1195 rt_entry = alloc_routing_table_entry(hdr->src_node_id);
1196 if (!rt_entry) {
1197 mutex_unlock(&routing_table_lock);
1198 pr_err("%s: rt_entry allocation failed\n",
1199 __func__);
1200 return -ENOMEM;
1201 }
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001202 add_routing_table_entry(rt_entry);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001203 }
1204 mutex_lock(&rt_entry->lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001205 rt_entry->neighbor_node_id = xprt_info->remote_node_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001206 rt_entry->xprt_info = xprt_info;
1207 mutex_unlock(&rt_entry->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001208 mutex_unlock(&routing_table_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001209 msm_ipc_cleanup_remote_port_info(xprt_info->remote_node_id);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001210
1211 memset(&ctl, 0, sizeof(ctl));
1212 ctl.cmd = IPC_ROUTER_CTRL_CMD_HELLO;
1213 msm_ipc_router_send_control_msg(xprt_info, &ctl);
1214
1215 xprt_info->initialized = 1;
1216
1217 /* Send list of servers one at a time */
1218 msm_ipc_router_send_server_list(xprt_info);
1219
1220 if (first) {
1221 first = 0;
1222 complete_all(&msm_ipc_remote_router_up);
1223 }
1224 RR("HELLO message processed\n");
1225 break;
1226 case IPC_ROUTER_CTRL_CMD_RESUME_TX:
1227 RR("o RESUME_TX id=%d:%08x\n",
1228 msg->cli.node_id, msg->cli.port_id);
1229
1230 rport_ptr = msm_ipc_router_lookup_remote_port(msg->cli.node_id,
1231 msg->cli.port_id);
1232 if (!rport_ptr) {
1233 pr_err("%s: Unable to resume client\n", __func__);
1234 break;
1235 }
1236 mutex_lock(&rport_ptr->quota_lock);
1237 rport_ptr->tx_quota_cnt = 0;
1238 mutex_unlock(&rport_ptr->quota_lock);
1239 wake_up(&rport_ptr->quota_wait);
1240 break;
1241
1242 case IPC_ROUTER_CTRL_CMD_NEW_SERVER:
1243 if (msg->srv.instance == 0) {
1244 pr_err(
1245 "rpcrouter: Server create rejected, version = 0, "
1246 "service = %08x\n", msg->srv.service);
1247 break;
1248 }
1249
1250 RR("o NEW_SERVER id=%d:%08x service=%08x:%08x\n",
1251 msg->srv.node_id, msg->srv.port_id,
1252 msg->srv.service, msg->srv.instance);
1253
1254 mutex_lock(&routing_table_lock);
1255 rt_entry = lookup_routing_table(msg->srv.node_id);
1256 if (!rt_entry) {
1257 rt_entry = alloc_routing_table_entry(msg->srv.node_id);
1258 if (!rt_entry) {
1259 mutex_unlock(&routing_table_lock);
1260 pr_err("%s: rt_entry allocation failed\n",
1261 __func__);
1262 return -ENOMEM;
1263 }
1264 mutex_lock(&rt_entry->lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001265 rt_entry->neighbor_node_id = xprt_info->remote_node_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001266 rt_entry->xprt_info = xprt_info;
1267 mutex_unlock(&rt_entry->lock);
1268 add_routing_table_entry(rt_entry);
1269 }
1270 mutex_unlock(&routing_table_lock);
1271
1272 server = msm_ipc_router_lookup_server(msg->srv.service,
1273 msg->srv.instance,
1274 msg->srv.node_id,
1275 msg->srv.port_id);
1276 if (!server) {
1277 server = msm_ipc_router_create_server(
1278 msg->srv.service, msg->srv.instance,
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001279 msg->srv.node_id, msg->srv.port_id, xprt_info);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001280 if (!server) {
1281 pr_err("%s: Server Create failed\n", __func__);
1282 return -ENOMEM;
1283 }
1284
1285 if (!msm_ipc_router_lookup_remote_port(
1286 msg->srv.node_id, msg->srv.port_id)) {
1287 rport_ptr = msm_ipc_router_create_remote_port(
1288 msg->srv.node_id, msg->srv.port_id);
1289 if (!rport_ptr)
1290 pr_err("%s: Remote port create "
1291 "failed\n", __func__);
1292 }
1293 wake_up(&newserver_wait);
1294 }
1295
1296 relay_msg(xprt_info, pkt);
1297 post_control_ports(pkt);
1298 break;
1299 case IPC_ROUTER_CTRL_CMD_REMOVE_SERVER:
1300 RR("o REMOVE_SERVER service=%08x:%d\n",
1301 msg->srv.service, msg->srv.instance);
1302 server = msm_ipc_router_lookup_server(msg->srv.service,
1303 msg->srv.instance,
1304 msg->srv.node_id,
1305 msg->srv.port_id);
1306 if (server) {
1307 msm_ipc_router_destroy_server(server,
1308 msg->srv.node_id,
1309 msg->srv.port_id);
1310 relay_msg(xprt_info, pkt);
1311 post_control_ports(pkt);
1312 }
1313 break;
1314 case IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT:
1315 RR("o REMOVE_CLIENT id=%d:%08x\n",
1316 msg->cli.node_id, msg->cli.port_id);
1317 rport_ptr = msm_ipc_router_lookup_remote_port(msg->cli.node_id,
1318 msg->cli.port_id);
1319 if (rport_ptr)
1320 msm_ipc_router_destroy_remote_port(rport_ptr);
1321
1322 relay_msg(xprt_info, pkt);
1323 post_control_ports(pkt);
1324 break;
1325 case IPC_ROUTER_CTRL_CMD_PING:
1326 /* No action needed for ping messages received */
1327 RR("o PING\n");
1328 break;
1329 default:
1330 RR("o UNKNOWN(%08x)\n", msg->cmd);
1331 rc = -ENOSYS;
1332 }
1333
1334 return rc;
1335}
1336
1337static void do_read_data(struct work_struct *work)
1338{
1339 struct rr_header *hdr;
1340 struct rr_packet *pkt = NULL;
1341 struct msm_ipc_port *port_ptr;
1342 struct sk_buff *head_skb;
1343 struct msm_ipc_port_addr *src_addr;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001344 struct msm_ipc_router_remote_port *rport_ptr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001345 uint32_t resume_tx, resume_tx_node_id, resume_tx_port_id;
1346
1347 struct msm_ipc_router_xprt_info *xprt_info =
1348 container_of(work,
1349 struct msm_ipc_router_xprt_info,
1350 read_data);
1351
1352 pkt = rr_read(xprt_info);
1353 if (!pkt) {
1354 pr_err("%s: rr_read failed\n", __func__);
1355 goto fail_io;
1356 }
1357
1358 if (pkt->length < IPC_ROUTER_HDR_SIZE ||
1359 pkt->length > MAX_IPC_PKT_SIZE) {
1360 pr_err("%s: Invalid pkt length %d\n", __func__, pkt->length);
1361 goto fail_data;
1362 }
1363
1364 head_skb = skb_peek(pkt->pkt_fragment_q);
1365 if (!head_skb) {
1366 pr_err("%s: head_skb is invalid\n", __func__);
1367 goto fail_data;
1368 }
1369
1370 hdr = (struct rr_header *)(head_skb->data);
1371 RR("- ver=%d type=%d src=%d:%08x crx=%d siz=%d dst=%d:%08x\n",
1372 hdr->version, hdr->type, hdr->src_node_id, hdr->src_port_id,
1373 hdr->confirm_rx, hdr->size, hdr->dst_node_id, hdr->dst_port_id);
1374 RAW_HDR("[r rr_h] "
1375 "ver=%i,type=%s,src_node_id=%08x,src_port_id=%08x,"
1376 "confirm_rx=%i,size=%3i,dst_node_id=%08x,dst_port_id=%08x\n",
1377 hdr->version, type_to_str(hdr->type), hdr->src_node_id,
1378 hdr->src_port_id, hdr->confirm_rx, hdr->size, hdr->dst_node_id,
1379 hdr->dst_port_id);
1380
1381 if (hdr->version != IPC_ROUTER_VERSION) {
1382 pr_err("version %d != %d\n", hdr->version, IPC_ROUTER_VERSION);
1383 goto fail_data;
1384 }
1385
1386 if ((hdr->dst_node_id != IPC_ROUTER_NID_LOCAL) &&
1387 ((hdr->type == IPC_ROUTER_CTRL_CMD_RESUME_TX) ||
1388 (hdr->type == IPC_ROUTER_CTRL_CMD_DATA))) {
1389 forward_msg(xprt_info, pkt);
1390 release_pkt(pkt);
1391 goto done;
1392 }
1393
1394 if ((hdr->dst_port_id == IPC_ROUTER_ADDRESS) ||
1395 (hdr->type == IPC_ROUTER_CTRL_CMD_HELLO)) {
1396 process_control_msg(xprt_info, pkt);
1397 release_pkt(pkt);
1398 goto done;
1399 }
1400#if defined(CONFIG_MSM_SMD_LOGGING)
1401#if defined(DEBUG)
1402 if (msm_ipc_router_debug_mask & SMEM_LOG) {
1403 smem_log_event((SMEM_LOG_PROC_ID_APPS |
1404 SMEM_LOG_RPC_ROUTER_EVENT_BASE |
1405 IPC_ROUTER_LOG_EVENT_RX),
1406 (hdr->src_node_id << 24) |
1407 (hdr->src_port_id & 0xffffff),
1408 (hdr->dst_node_id << 24) |
1409 (hdr->dst_port_id & 0xffffff),
1410 (hdr->type << 24) | (hdr->confirm_rx << 16) |
1411 (hdr->size & 0xffff));
1412 }
1413#endif
1414#endif
1415
1416 resume_tx = hdr->confirm_rx;
1417 resume_tx_node_id = hdr->dst_node_id;
1418 resume_tx_port_id = hdr->dst_port_id;
1419
1420 port_ptr = msm_ipc_router_lookup_local_port(hdr->dst_port_id);
1421 if (!port_ptr) {
1422 pr_err("%s: No local port id %08x\n", __func__,
1423 hdr->dst_port_id);
1424 release_pkt(pkt);
1425 goto process_done;
1426 }
1427
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001428 rport_ptr = msm_ipc_router_lookup_remote_port(hdr->src_node_id,
1429 hdr->src_port_id);
1430 if (!rport_ptr) {
1431 rport_ptr = msm_ipc_router_create_remote_port(
1432 hdr->src_node_id,
1433 hdr->src_port_id);
1434 if (!rport_ptr) {
1435 pr_err("%s: Remote port %08x:%08x creation failed\n",
1436 __func__, hdr->src_node_id, hdr->src_port_id);
1437 goto process_done;
1438 }
1439 }
1440
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001441 if (!port_ptr->notify) {
1442 mutex_lock(&port_ptr->port_rx_q_lock);
1443 wake_lock(&port_ptr->port_rx_wake_lock);
1444 list_add_tail(&pkt->list, &port_ptr->port_rx_q);
1445 wake_up(&port_ptr->port_rx_wait_q);
1446 mutex_unlock(&port_ptr->port_rx_q_lock);
1447 } else {
1448 src_addr = kmalloc(sizeof(struct msm_ipc_port_addr),
1449 GFP_KERNEL);
1450 if (src_addr) {
1451 src_addr->node_id = hdr->src_node_id;
1452 src_addr->port_id = hdr->src_port_id;
1453 }
1454 skb_pull(head_skb, IPC_ROUTER_HDR_SIZE);
1455 port_ptr->notify(MSM_IPC_ROUTER_READ_CB, pkt->pkt_fragment_q,
1456 src_addr, port_ptr->priv);
1457 pkt->pkt_fragment_q = NULL;
1458 src_addr = NULL;
1459 release_pkt(pkt);
1460 }
1461
1462process_done:
1463 if (resume_tx) {
1464 union rr_control_msg msg;
1465
1466 msg.cmd = IPC_ROUTER_CTRL_CMD_RESUME_TX;
1467 msg.cli.node_id = resume_tx_node_id;
1468 msg.cli.port_id = resume_tx_port_id;
1469
1470 RR("x RESUME_TX id=%d:%08x\n",
1471 msg.cli.node_id, msg.cli.port_id);
1472 msm_ipc_router_send_control_msg(xprt_info, &msg);
1473 }
1474
1475done:
1476 queue_work(xprt_info->workqueue, &xprt_info->read_data);
1477 return;
1478
1479fail_data:
1480 release_pkt(pkt);
1481fail_io:
1482 pr_err("ipc_router has died\n");
1483}
1484
1485int msm_ipc_router_register_server(struct msm_ipc_port *port_ptr,
1486 struct msm_ipc_addr *name)
1487{
1488 struct msm_ipc_server *server;
1489 unsigned long flags;
1490 union rr_control_msg ctl;
1491
1492 if (!port_ptr || !name)
1493 return -EINVAL;
1494
1495 if (name->addrtype != MSM_IPC_ADDR_NAME)
1496 return -EINVAL;
1497
1498 server = msm_ipc_router_lookup_server(name->addr.port_name.service,
1499 name->addr.port_name.instance,
1500 IPC_ROUTER_NID_LOCAL,
1501 port_ptr->this_port.port_id);
1502 if (server) {
1503 pr_err("%s: Server already present\n", __func__);
1504 return -EINVAL;
1505 }
1506
1507 server = msm_ipc_router_create_server(name->addr.port_name.service,
1508 name->addr.port_name.instance,
1509 IPC_ROUTER_NID_LOCAL,
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001510 port_ptr->this_port.port_id,
1511 NULL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001512 if (!server) {
1513 pr_err("%s: Server Creation failed\n", __func__);
1514 return -EINVAL;
1515 }
1516
1517 ctl.cmd = IPC_ROUTER_CTRL_CMD_NEW_SERVER;
1518 ctl.srv.service = server->name.service;
1519 ctl.srv.instance = server->name.instance;
1520 ctl.srv.node_id = IPC_ROUTER_NID_LOCAL;
1521 ctl.srv.port_id = port_ptr->this_port.port_id;
1522 broadcast_ctl_msg(&ctl);
1523 spin_lock_irqsave(&port_ptr->port_lock, flags);
1524 port_ptr->type = SERVER_PORT;
1525 port_ptr->port_name.service = server->name.service;
1526 port_ptr->port_name.instance = server->name.instance;
1527 spin_unlock_irqrestore(&port_ptr->port_lock, flags);
1528 return 0;
1529}
1530
1531int msm_ipc_router_unregister_server(struct msm_ipc_port *port_ptr)
1532{
1533 struct msm_ipc_server *server;
1534 unsigned long flags;
1535 union rr_control_msg ctl;
1536
1537 if (!port_ptr)
1538 return -EINVAL;
1539
1540 if (port_ptr->type != SERVER_PORT) {
1541 pr_err("%s: Trying to unregister a non-server port\n",
1542 __func__);
1543 return -EINVAL;
1544 }
1545
1546 if (port_ptr->this_port.node_id != IPC_ROUTER_NID_LOCAL) {
1547 pr_err("%s: Trying to unregister a remote server locally\n",
1548 __func__);
1549 return -EINVAL;
1550 }
1551
1552 server = msm_ipc_router_lookup_server(port_ptr->port_name.service,
1553 port_ptr->port_name.instance,
1554 port_ptr->this_port.node_id,
1555 port_ptr->this_port.port_id);
1556 if (!server) {
1557 pr_err("%s: Server lookup failed\n", __func__);
1558 return -ENODEV;
1559 }
1560
1561 ctl.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_SERVER;
1562 ctl.srv.service = server->name.service;
1563 ctl.srv.instance = server->name.instance;
1564 ctl.srv.node_id = IPC_ROUTER_NID_LOCAL;
1565 ctl.srv.port_id = port_ptr->this_port.port_id;
1566 broadcast_ctl_msg(&ctl);
1567 msm_ipc_router_destroy_server(server, port_ptr->this_port.node_id,
1568 port_ptr->this_port.port_id);
1569 spin_lock_irqsave(&port_ptr->port_lock, flags);
1570 port_ptr->type = CLIENT_PORT;
1571 spin_unlock_irqrestore(&port_ptr->port_lock, flags);
1572 return 0;
1573}
1574
1575static int loopback_data(struct msm_ipc_port *src,
1576 uint32_t port_id,
1577 struct sk_buff_head *data)
1578{
1579 struct sk_buff *head_skb;
1580 struct rr_header *hdr;
1581 struct msm_ipc_port *port_ptr;
1582 struct rr_packet *pkt;
1583
1584 if (!data) {
1585 pr_err("%s: Invalid pkt pointer\n", __func__);
1586 return -EINVAL;
1587 }
1588
1589 pkt = create_pkt(data);
1590 if (!pkt) {
1591 pr_err("%s: New pkt create failed\n", __func__);
1592 return -ENOMEM;
1593 }
1594
1595 head_skb = skb_peek(pkt->pkt_fragment_q);
1596 hdr = (struct rr_header *)skb_push(head_skb, IPC_ROUTER_HDR_SIZE);
1597 if (!hdr) {
1598 pr_err("%s: Prepend Header failed\n", __func__);
1599 release_pkt(pkt);
1600 return -ENOMEM;
1601 }
1602 hdr->version = IPC_ROUTER_VERSION;
1603 hdr->type = IPC_ROUTER_CTRL_CMD_DATA;
1604 hdr->src_node_id = src->this_port.node_id;
1605 hdr->src_port_id = src->this_port.port_id;
1606 hdr->size = pkt->length;
1607 hdr->confirm_rx = 0;
1608 hdr->dst_node_id = IPC_ROUTER_NID_LOCAL;
1609 hdr->dst_port_id = port_id;
1610 pkt->length += IPC_ROUTER_HDR_SIZE;
1611
1612 port_ptr = msm_ipc_router_lookup_local_port(port_id);
1613 if (!port_ptr) {
1614 pr_err("%s: Local port %d not present\n", __func__, port_id);
1615 release_pkt(pkt);
1616 return -ENODEV;
1617 }
1618
1619 mutex_lock(&port_ptr->port_rx_q_lock);
1620 wake_lock(&port_ptr->port_rx_wake_lock);
1621 list_add_tail(&pkt->list, &port_ptr->port_rx_q);
1622 wake_up(&port_ptr->port_rx_wait_q);
1623 mutex_unlock(&port_ptr->port_rx_q_lock);
1624
1625 return pkt->length;
1626}
1627
1628static int msm_ipc_router_write_pkt(struct msm_ipc_port *src,
1629 struct msm_ipc_router_remote_port *rport_ptr,
1630 struct rr_packet *pkt)
1631{
1632 struct sk_buff *head_skb;
1633 struct rr_header *hdr;
1634 struct msm_ipc_router_xprt_info *xprt_info;
1635 struct msm_ipc_routing_table_entry *rt_entry;
1636 int ret;
1637 DEFINE_WAIT(__wait);
1638
1639 if (!rport_ptr || !src || !pkt)
1640 return -EINVAL;
1641
1642 head_skb = skb_peek(pkt->pkt_fragment_q);
1643 hdr = (struct rr_header *)skb_push(head_skb, IPC_ROUTER_HDR_SIZE);
1644 if (!hdr) {
1645 pr_err("%s: Prepend Header failed\n", __func__);
1646 return -ENOMEM;
1647 }
1648 hdr->version = IPC_ROUTER_VERSION;
1649 hdr->type = IPC_ROUTER_CTRL_CMD_DATA;
1650 hdr->src_node_id = src->this_port.node_id;
1651 hdr->src_port_id = src->this_port.port_id;
1652 hdr->size = pkt->length;
1653 hdr->confirm_rx = 0;
1654 hdr->dst_node_id = rport_ptr->node_id;
1655 hdr->dst_port_id = rport_ptr->port_id;
1656 pkt->length += IPC_ROUTER_HDR_SIZE;
1657
1658 for (;;) {
1659 prepare_to_wait(&rport_ptr->quota_wait, &__wait,
1660 TASK_INTERRUPTIBLE);
1661 mutex_lock(&rport_ptr->quota_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001662 if (rport_ptr->restart_state != RESTART_NORMAL)
1663 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001664 if (rport_ptr->tx_quota_cnt <
1665 IPC_ROUTER_DEFAULT_RX_QUOTA)
1666 break;
1667 if (signal_pending(current))
1668 break;
1669 mutex_unlock(&rport_ptr->quota_lock);
1670 schedule();
1671 }
1672 finish_wait(&rport_ptr->quota_wait, &__wait);
1673
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001674 if (rport_ptr->restart_state != RESTART_NORMAL) {
1675 mutex_unlock(&rport_ptr->quota_lock);
1676 return -ENETRESET;
1677 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001678 if (signal_pending(current)) {
1679 mutex_unlock(&rport_ptr->quota_lock);
1680 return -ERESTARTSYS;
1681 }
1682 rport_ptr->tx_quota_cnt++;
1683 if (rport_ptr->tx_quota_cnt == IPC_ROUTER_DEFAULT_RX_QUOTA)
1684 hdr->confirm_rx = 1;
1685 mutex_unlock(&rport_ptr->quota_lock);
1686
1687 mutex_lock(&routing_table_lock);
1688 rt_entry = lookup_routing_table(hdr->dst_node_id);
1689 if (!rt_entry || !rt_entry->xprt_info) {
1690 mutex_unlock(&routing_table_lock);
1691 pr_err("%s: Remote node %d not up\n",
1692 __func__, hdr->dst_node_id);
1693 return -ENODEV;
1694 }
1695 mutex_lock(&rt_entry->lock);
1696 xprt_info = rt_entry->xprt_info;
1697 mutex_lock(&xprt_info->tx_lock);
1698 ret = xprt_info->xprt->write(pkt, pkt->length, 0);
1699 mutex_unlock(&xprt_info->tx_lock);
1700 mutex_unlock(&rt_entry->lock);
1701 mutex_unlock(&routing_table_lock);
1702
1703 if (ret < 0) {
1704 pr_err("%s: Write on XPRT failed\n", __func__);
1705 return ret;
1706 }
1707
1708 RAW_HDR("[w rr_h] "
1709 "ver=%i,type=%s,src_nid=%08x,src_port_id=%08x,"
1710 "confirm_rx=%i,size=%3i,dst_pid=%08x,dst_cid=%08x\n",
1711 hdr->version, type_to_str(hdr->type),
1712 hdr->src_node_id, hdr->src_port_id,
1713 hdr->confirm_rx, hdr->size,
1714 hdr->dst_node_id, hdr->dst_port_id);
1715
1716#if defined(CONFIG_MSM_SMD_LOGGING)
1717#if defined(DEBUG)
1718 if (msm_ipc_router_debug_mask & SMEM_LOG) {
1719 smem_log_event((SMEM_LOG_PROC_ID_APPS |
1720 SMEM_LOG_RPC_ROUTER_EVENT_BASE |
1721 IPC_ROUTER_LOG_EVENT_TX),
1722 (hdr->src_node_id << 24) |
1723 (hdr->src_port_id & 0xffffff),
1724 (hdr->dst_node_id << 24) |
1725 (hdr->dst_port_id & 0xffffff),
1726 (hdr->type << 24) | (hdr->confirm_rx << 16) |
1727 (hdr->size & 0xffff));
1728 }
1729#endif
1730#endif
1731
1732 return pkt->length;
1733}
1734
1735int msm_ipc_router_send_to(struct msm_ipc_port *src,
1736 struct sk_buff_head *data,
1737 struct msm_ipc_addr *dest)
1738{
1739 uint32_t dst_node_id = 0, dst_port_id = 0;
1740 struct msm_ipc_server *server;
1741 struct msm_ipc_server_port *server_port;
1742 struct msm_ipc_router_remote_port *rport_ptr = NULL;
1743 struct rr_packet *pkt;
1744 int ret;
1745
1746 if (!src || !data || !dest) {
1747 pr_err("%s: Invalid Parameters\n", __func__);
1748 return -EINVAL;
1749 }
1750
1751 /* Resolve Address*/
1752 if (dest->addrtype == MSM_IPC_ADDR_ID) {
1753 dst_node_id = dest->addr.port_addr.node_id;
1754 dst_port_id = dest->addr.port_addr.port_id;
1755 } else if (dest->addrtype == MSM_IPC_ADDR_NAME) {
1756 server = msm_ipc_router_lookup_server(
1757 dest->addr.port_name.service,
1758 dest->addr.port_name.instance,
1759 0, 0);
1760 if (!server) {
1761 pr_err("%s: Destination not reachable\n", __func__);
1762 return -ENODEV;
1763 }
1764 mutex_lock(&server_list_lock);
1765 server_port = list_first_entry(&server->server_port_list,
1766 struct msm_ipc_server_port,
1767 list);
1768 dst_node_id = server_port->server_addr.node_id;
1769 dst_port_id = server_port->server_addr.port_id;
1770 mutex_unlock(&server_list_lock);
1771 }
1772 if (dst_node_id == IPC_ROUTER_NID_LOCAL) {
1773 ret = loopback_data(src, dst_port_id, data);
1774 return ret;
1775 }
1776
1777 /* Achieve Flow control */
1778 rport_ptr = msm_ipc_router_lookup_remote_port(dst_node_id,
1779 dst_port_id);
1780 if (!rport_ptr) {
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001781 pr_err("%s: Could not create remote port\n", __func__);
1782 return -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001783 }
1784
1785 pkt = create_pkt(data);
1786 if (!pkt) {
1787 pr_err("%s: Pkt creation failed\n", __func__);
1788 return -ENOMEM;
1789 }
1790
1791 ret = msm_ipc_router_write_pkt(src, rport_ptr, pkt);
1792 release_pkt(pkt);
1793
1794 return ret;
1795}
1796
1797int msm_ipc_router_read(struct msm_ipc_port *port_ptr,
1798 struct sk_buff_head **data,
1799 size_t buf_len)
1800{
1801 struct rr_packet *pkt;
1802 int ret;
1803
1804 if (!port_ptr || !data)
1805 return -EINVAL;
1806
1807 mutex_lock(&port_ptr->port_rx_q_lock);
1808 if (list_empty(&port_ptr->port_rx_q)) {
1809 mutex_unlock(&port_ptr->port_rx_q_lock);
1810 return -EAGAIN;
1811 }
1812
1813 pkt = list_first_entry(&port_ptr->port_rx_q, struct rr_packet, list);
1814 if ((buf_len) && ((pkt->length - IPC_ROUTER_HDR_SIZE) > buf_len)) {
1815 mutex_unlock(&port_ptr->port_rx_q_lock);
1816 return -ETOOSMALL;
1817 }
1818 list_del(&pkt->list);
1819 if (list_empty(&port_ptr->port_rx_q))
1820 wake_unlock(&port_ptr->port_rx_wake_lock);
1821 *data = pkt->pkt_fragment_q;
1822 ret = pkt->length;
1823 kfree(pkt);
1824 mutex_unlock(&port_ptr->port_rx_q_lock);
1825
1826 return ret;
1827}
1828
1829int msm_ipc_router_recv_from(struct msm_ipc_port *port_ptr,
1830 struct sk_buff_head **data,
1831 struct msm_ipc_addr *src,
1832 unsigned long timeout)
1833{
1834 int ret, data_len, align_size;
1835 struct sk_buff *temp_skb;
1836 struct rr_header *hdr = NULL;
1837
1838 if (!port_ptr || !data) {
1839 pr_err("%s: Invalid pointers being passed\n", __func__);
1840 return -EINVAL;
1841 }
1842
1843 *data = NULL;
1844 mutex_lock(&port_ptr->port_rx_q_lock);
1845 while (list_empty(&port_ptr->port_rx_q)) {
1846 mutex_unlock(&port_ptr->port_rx_q_lock);
1847 if (timeout < 0) {
1848 ret = wait_event_interruptible(
1849 port_ptr->port_rx_wait_q,
1850 !list_empty(&port_ptr->port_rx_q));
1851 if (ret)
1852 return ret;
1853 } else if (timeout > 0) {
1854 timeout = wait_event_interruptible_timeout(
1855 port_ptr->port_rx_wait_q,
1856 !list_empty(&port_ptr->port_rx_q),
1857 timeout);
1858 if (timeout < 0)
1859 return -EFAULT;
1860 }
1861 if (timeout == 0)
1862 return -ETIMEDOUT;
1863 mutex_lock(&port_ptr->port_rx_q_lock);
1864 }
1865 mutex_unlock(&port_ptr->port_rx_q_lock);
1866
1867 ret = msm_ipc_router_read(port_ptr, data, 0);
1868 if (ret <= 0 || !(*data))
1869 return ret;
1870
1871 temp_skb = skb_peek(*data);
1872 hdr = (struct rr_header *)(temp_skb->data);
1873 if (src) {
1874 src->addrtype = MSM_IPC_ADDR_ID;
1875 src->addr.port_addr.node_id = hdr->src_node_id;
1876 src->addr.port_addr.port_id = hdr->src_port_id;
1877 }
1878
1879 data_len = hdr->size;
1880 skb_pull(temp_skb, IPC_ROUTER_HDR_SIZE);
1881 align_size = ALIGN_SIZE(data_len);
1882 if (align_size) {
1883 temp_skb = skb_peek_tail(*data);
1884 skb_trim(temp_skb, (temp_skb->len - align_size));
1885 }
1886 return data_len;
1887}
1888
1889struct msm_ipc_port *msm_ipc_router_create_port(
1890 void (*notify)(unsigned event, void *data, void *addr, void *priv),
1891 void *priv)
1892{
1893 struct msm_ipc_port *port_ptr;
1894
1895 port_ptr = msm_ipc_router_create_raw_port(NULL, notify, priv);
1896 if (!port_ptr)
1897 pr_err("%s: port_ptr alloc failed\n", __func__);
1898
1899 return port_ptr;
1900}
1901
1902int msm_ipc_router_close_port(struct msm_ipc_port *port_ptr)
1903{
1904 union rr_control_msg msg;
1905 struct rr_packet *pkt, *temp_pkt;
1906 struct msm_ipc_server *server;
1907
1908 if (!port_ptr)
1909 return -EINVAL;
1910
1911 if (port_ptr->type == SERVER_PORT || port_ptr->type == CLIENT_PORT) {
1912 if (port_ptr->type == SERVER_PORT) {
1913 msg.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_SERVER;
1914 msg.srv.service = port_ptr->port_name.service;
1915 msg.srv.instance = port_ptr->port_name.instance;
1916 msg.srv.node_id = port_ptr->this_port.node_id;
1917 msg.srv.port_id = port_ptr->this_port.port_id;
1918 RR("x REMOVE_SERVER Name=%d:%08x Id=%d:%08x\n",
1919 msg.srv.service, msg.srv.instance,
1920 msg.srv.node_id, msg.srv.port_id);
1921 } else if (port_ptr->type == CLIENT_PORT) {
1922 msg.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT;
1923 msg.cli.node_id = port_ptr->this_port.node_id;
1924 msg.cli.port_id = port_ptr->this_port.port_id;
1925 RR("x REMOVE_CLIENT id=%d:%08x\n",
1926 msg.cli.node_id, msg.cli.port_id);
1927 }
1928 broadcast_ctl_msg(&msg);
1929 broadcast_ctl_msg_locally(&msg);
1930 }
1931
1932 mutex_lock(&port_ptr->port_rx_q_lock);
1933 list_for_each_entry_safe(pkt, temp_pkt, &port_ptr->port_rx_q, list) {
1934 list_del(&pkt->list);
1935 release_pkt(pkt);
1936 }
1937 mutex_unlock(&port_ptr->port_rx_q_lock);
1938
1939 wake_lock_destroy(&port_ptr->port_rx_wake_lock);
1940 if (port_ptr->type == SERVER_PORT) {
1941 server = msm_ipc_router_lookup_server(
1942 port_ptr->port_name.service,
1943 port_ptr->port_name.instance,
1944 port_ptr->this_port.node_id,
1945 port_ptr->this_port.port_id);
1946 if (server)
1947 msm_ipc_router_destroy_server(server,
1948 port_ptr->this_port.node_id,
1949 port_ptr->this_port.port_id);
1950 mutex_lock(&local_ports_lock);
1951 list_del(&port_ptr->list);
1952 mutex_unlock(&local_ports_lock);
1953 } else if (port_ptr->type == CLIENT_PORT) {
1954 mutex_lock(&local_ports_lock);
1955 list_del(&port_ptr->list);
1956 mutex_unlock(&local_ports_lock);
1957 } else if (port_ptr->type == CONTROL_PORT) {
1958 mutex_lock(&control_ports_lock);
1959 list_del(&port_ptr->list);
1960 mutex_unlock(&control_ports_lock);
1961 }
1962
1963 kfree(port_ptr);
1964 return 0;
1965}
1966
1967int msm_ipc_router_get_curr_pkt_size(struct msm_ipc_port *port_ptr)
1968{
1969 struct rr_packet *pkt;
1970 int rc = 0;
1971
1972 if (!port_ptr)
1973 return -EINVAL;
1974
1975 mutex_lock(&port_ptr->port_rx_q_lock);
1976 if (!list_empty(&port_ptr->port_rx_q)) {
1977 pkt = list_first_entry(&port_ptr->port_rx_q,
1978 struct rr_packet, list);
1979 rc = pkt->length;
1980 }
1981 mutex_unlock(&port_ptr->port_rx_q_lock);
1982
1983 return rc;
1984}
1985
1986int msm_ipc_router_bind_control_port(struct msm_ipc_port *port_ptr)
1987{
1988 if (!port_ptr)
1989 return -EINVAL;
1990
1991 mutex_lock(&local_ports_lock);
1992 list_del(&port_ptr->list);
1993 mutex_unlock(&local_ports_lock);
1994 port_ptr->type = CONTROL_PORT;
1995 mutex_lock(&control_ports_lock);
1996 list_add_tail(&port_ptr->list, &control_ports);
1997 mutex_unlock(&control_ports_lock);
1998
1999 return 0;
2000}
2001
2002int msm_ipc_router_lookup_server_name(struct msm_ipc_port_name *srv_name,
2003 struct msm_ipc_port_addr *srv_addr,
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002004 int num_entries_in_array,
2005 uint32_t lookup_mask)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002006{
2007 struct msm_ipc_server *server;
2008 struct msm_ipc_server_port *server_port;
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002009 int key, i = 0; /*num_entries_found*/
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002010
2011 if (!srv_name) {
2012 pr_err("%s: Invalid srv_name\n", __func__);
2013 return -EINVAL;
2014 }
2015
2016 if (num_entries_in_array && !srv_addr) {
2017 pr_err("%s: srv_addr NULL\n", __func__);
2018 return -EINVAL;
2019 }
2020
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002021 mutex_lock(&server_list_lock);
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002022 if (!lookup_mask)
2023 lookup_mask = 0xFFFFFFFF;
2024 for (key = 0; key < SRV_HASH_SIZE; key++) {
2025 list_for_each_entry(server, &server_list[key], list) {
2026 if ((server->name.service != srv_name->service) ||
2027 ((server->name.instance & lookup_mask) !=
2028 srv_name->instance))
2029 continue;
2030
2031 list_for_each_entry(server_port,
2032 &server->server_port_list, list) {
2033 if (i < num_entries_in_array) {
2034 srv_addr[i].node_id =
2035 server_port->server_addr.node_id;
2036 srv_addr[i].port_id =
2037 server_port->server_addr.port_id;
2038 }
2039 i++;
2040 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002041 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002042 }
2043 mutex_unlock(&server_list_lock);
2044
2045 return i;
2046}
2047
2048int msm_ipc_router_close(void)
2049{
2050 struct msm_ipc_router_xprt_info *xprt_info, *tmp_xprt_info;
2051
2052 mutex_lock(&xprt_info_list_lock);
2053 list_for_each_entry_safe(xprt_info, tmp_xprt_info,
2054 &xprt_info_list, list) {
2055 xprt_info->xprt->close();
2056 list_del(&xprt_info->list);
2057 kfree(xprt_info);
2058 }
2059 mutex_unlock(&xprt_info_list_lock);
2060 return 0;
2061}
2062
2063#if defined(CONFIG_DEBUG_FS)
2064static int dump_routing_table(char *buf, int max)
2065{
2066 int i = 0, j;
2067 struct msm_ipc_routing_table_entry *rt_entry;
2068
2069 for (j = 0; j < RT_HASH_SIZE; j++) {
2070 mutex_lock(&routing_table_lock);
2071 list_for_each_entry(rt_entry, &routing_table[j], list) {
2072 mutex_lock(&rt_entry->lock);
2073 i += scnprintf(buf + i, max - i,
2074 "Node Id: 0x%08x\n", rt_entry->node_id);
2075 if (j == IPC_ROUTER_NID_LOCAL) {
2076 i += scnprintf(buf + i, max - i,
2077 "XPRT Name: Loopback\n");
2078 i += scnprintf(buf + i, max - i,
2079 "Next Hop: %d\n", rt_entry->node_id);
2080 } else {
2081 i += scnprintf(buf + i, max - i,
2082 "XPRT Name: %s\n",
2083 rt_entry->xprt_info->xprt->name);
2084 i += scnprintf(buf + i, max - i,
2085 "Next Hop: 0x%08x\n",
2086 rt_entry->xprt_info->remote_node_id);
2087 }
2088 i += scnprintf(buf + i, max - i, "\n");
2089 mutex_unlock(&rt_entry->lock);
2090 }
2091 mutex_unlock(&routing_table_lock);
2092 }
2093
2094 return i;
2095}
2096
2097static int dump_xprt_info(char *buf, int max)
2098{
2099 int i = 0;
2100 struct msm_ipc_router_xprt_info *xprt_info;
2101
2102 mutex_lock(&xprt_info_list_lock);
2103 list_for_each_entry(xprt_info, &xprt_info_list, list) {
2104 i += scnprintf(buf + i, max - i, "XPRT Name: %s\n",
2105 xprt_info->xprt->name);
2106 i += scnprintf(buf + i, max - i, "Link Id: %d\n",
2107 xprt_info->xprt->link_id);
2108 i += scnprintf(buf + i, max - i, "Initialized: %s\n",
2109 (xprt_info->initialized ? "Y" : "N"));
2110 i += scnprintf(buf + i, max - i, "Remote Node Id: 0x%08x\n",
2111 xprt_info->remote_node_id);
2112 i += scnprintf(buf + i, max - i, "\n");
2113 }
2114 mutex_unlock(&xprt_info_list_lock);
2115
2116 return i;
2117}
2118
2119static int dump_servers(char *buf, int max)
2120{
2121 int i = 0, j;
2122 struct msm_ipc_server *server;
2123 struct msm_ipc_server_port *server_port;
2124
2125 mutex_lock(&server_list_lock);
2126 for (j = 0; j < SRV_HASH_SIZE; j++) {
2127 list_for_each_entry(server, &server_list[j], list) {
2128 list_for_each_entry(server_port,
2129 &server->server_port_list,
2130 list) {
2131 i += scnprintf(buf + i, max - i, "Service: "
2132 "0x%08x\n", server->name.service);
2133 i += scnprintf(buf + i, max - i, "Instance: "
2134 "0x%08x\n", server->name.instance);
2135 i += scnprintf(buf + i, max - i,
2136 "Node_id: 0x%08x\n",
2137 server_port->server_addr.node_id);
2138 i += scnprintf(buf + i, max - i,
2139 "Port_id: 0x%08x\n",
2140 server_port->server_addr.port_id);
2141 i += scnprintf(buf + i, max - i, "\n");
2142 }
2143 }
2144 }
2145 mutex_unlock(&server_list_lock);
2146
2147 return i;
2148}
2149
2150static int dump_remote_ports(char *buf, int max)
2151{
2152 int i = 0, j, k;
2153 struct msm_ipc_router_remote_port *rport_ptr;
2154 struct msm_ipc_routing_table_entry *rt_entry;
2155
2156 for (j = 0; j < RT_HASH_SIZE; j++) {
2157 mutex_lock(&routing_table_lock);
2158 list_for_each_entry(rt_entry, &routing_table[j], list) {
2159 mutex_lock(&rt_entry->lock);
2160 for (k = 0; k < RP_HASH_SIZE; k++) {
2161 list_for_each_entry(rport_ptr,
2162 &rt_entry->remote_port_list[k],
2163 list) {
2164 i += scnprintf(buf + i, max - i,
2165 "Node_id: 0x%08x\n",
2166 rport_ptr->node_id);
2167 i += scnprintf(buf + i, max - i,
2168 "Port_id: 0x%08x\n",
2169 rport_ptr->port_id);
2170 i += scnprintf(buf + i, max - i,
2171 "Quota_cnt: %d\n",
2172 rport_ptr->tx_quota_cnt);
2173 i += scnprintf(buf + i, max - i, "\n");
2174 }
2175 }
2176 mutex_unlock(&rt_entry->lock);
2177 }
2178 mutex_unlock(&routing_table_lock);
2179 }
2180
2181 return i;
2182}
2183
2184static int dump_control_ports(char *buf, int max)
2185{
2186 int i = 0;
2187 struct msm_ipc_port *port_ptr;
2188
2189 mutex_lock(&control_ports_lock);
2190 list_for_each_entry(port_ptr, &control_ports, list) {
2191 i += scnprintf(buf + i, max - i, "Node_id: 0x%08x\n",
2192 port_ptr->this_port.node_id);
2193 i += scnprintf(buf + i, max - i, "Port_id: 0x%08x\n",
2194 port_ptr->this_port.port_id);
2195 i += scnprintf(buf + i, max - i, "\n");
2196 }
2197 mutex_unlock(&control_ports_lock);
2198
2199 return i;
2200}
2201
2202static int dump_local_ports(char *buf, int max)
2203{
2204 int i = 0, j;
2205 unsigned long flags;
2206 struct msm_ipc_port *port_ptr;
2207
2208 mutex_lock(&local_ports_lock);
2209 for (j = 0; j < LP_HASH_SIZE; j++) {
2210 list_for_each_entry(port_ptr, &local_ports[j], list) {
2211 spin_lock_irqsave(&port_ptr->port_lock, flags);
2212 i += scnprintf(buf + i, max - i, "Node_id: 0x%08x\n",
2213 port_ptr->this_port.node_id);
2214 i += scnprintf(buf + i, max - i, "Port_id: 0x%08x\n",
2215 port_ptr->this_port.port_id);
2216 i += scnprintf(buf + i, max - i, "# pkts tx'd %d\n",
2217 port_ptr->num_tx);
2218 i += scnprintf(buf + i, max - i, "# pkts rx'd %d\n",
2219 port_ptr->num_rx);
2220 i += scnprintf(buf + i, max - i, "# bytes tx'd %ld\n",
2221 port_ptr->num_tx_bytes);
2222 i += scnprintf(buf + i, max - i, "# bytes rx'd %ld\n",
2223 port_ptr->num_rx_bytes);
2224 spin_unlock_irqrestore(&port_ptr->port_lock, flags);
2225 i += scnprintf(buf + i, max - i, "\n");
2226 }
2227 }
2228 mutex_unlock(&local_ports_lock);
2229
2230 return i;
2231}
2232
2233#define DEBUG_BUFMAX 4096
2234static char debug_buffer[DEBUG_BUFMAX];
2235
2236static ssize_t debug_read(struct file *file, char __user *buf,
2237 size_t count, loff_t *ppos)
2238{
2239 int (*fill)(char *buf, int max) = file->private_data;
2240 int bsize = fill(debug_buffer, DEBUG_BUFMAX);
2241 return simple_read_from_buffer(buf, count, ppos, debug_buffer, bsize);
2242}
2243
2244static int debug_open(struct inode *inode, struct file *file)
2245{
2246 file->private_data = inode->i_private;
2247 return 0;
2248}
2249
2250static const struct file_operations debug_ops = {
2251 .read = debug_read,
2252 .open = debug_open,
2253};
2254
2255static void debug_create(const char *name, mode_t mode,
2256 struct dentry *dent,
2257 int (*fill)(char *buf, int max))
2258{
2259 debugfs_create_file(name, mode, dent, fill, &debug_ops);
2260}
2261
2262static void debugfs_init(void)
2263{
2264 struct dentry *dent;
2265
2266 dent = debugfs_create_dir("msm_ipc_router", 0);
2267 if (IS_ERR(dent))
2268 return;
2269
2270 debug_create("dump_local_ports", 0444, dent,
2271 dump_local_ports);
2272 debug_create("dump_remote_ports", 0444, dent,
2273 dump_remote_ports);
2274 debug_create("dump_control_ports", 0444, dent,
2275 dump_control_ports);
2276 debug_create("dump_servers", 0444, dent,
2277 dump_servers);
2278 debug_create("dump_xprt_info", 0444, dent,
2279 dump_xprt_info);
2280 debug_create("dump_routing_table", 0444, dent,
2281 dump_routing_table);
2282}
2283
2284#else
2285static void debugfs_init(void) {}
2286#endif
2287
2288static int msm_ipc_router_add_xprt(struct msm_ipc_router_xprt *xprt)
2289{
2290 struct msm_ipc_router_xprt_info *xprt_info;
2291 struct msm_ipc_routing_table_entry *rt_entry;
2292
2293 xprt_info = kmalloc(sizeof(struct msm_ipc_router_xprt_info),
2294 GFP_KERNEL);
2295 if (!xprt_info)
2296 return -ENOMEM;
2297
2298 xprt_info->xprt = xprt;
2299 xprt_info->initialized = 0;
2300 xprt_info->remote_node_id = -1;
2301 INIT_LIST_HEAD(&xprt_info->pkt_list);
2302 init_waitqueue_head(&xprt_info->read_wait);
2303 mutex_init(&xprt_info->rx_lock);
2304 mutex_init(&xprt_info->tx_lock);
2305 wake_lock_init(&xprt_info->wakelock,
2306 WAKE_LOCK_SUSPEND, xprt->name);
2307 xprt_info->need_len = 0;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002308 xprt_info->abort_data_read = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002309 INIT_WORK(&xprt_info->read_data, do_read_data);
2310 INIT_LIST_HEAD(&xprt_info->list);
2311
2312 xprt_info->workqueue = create_singlethread_workqueue(xprt->name);
2313 if (!xprt_info->workqueue) {
2314 kfree(xprt_info);
2315 return -ENOMEM;
2316 }
2317
2318 if (!strcmp(xprt->name, "msm_ipc_router_loopback_xprt")) {
2319 xprt_info->remote_node_id = IPC_ROUTER_NID_LOCAL;
2320 xprt_info->initialized = 1;
2321 }
2322
2323 mutex_lock(&xprt_info_list_lock);
2324 list_add_tail(&xprt_info->list, &xprt_info_list);
2325 mutex_unlock(&xprt_info_list_lock);
2326
2327 mutex_lock(&routing_table_lock);
2328 if (!routing_table_inited) {
2329 init_routing_table();
2330 rt_entry = alloc_routing_table_entry(IPC_ROUTER_NID_LOCAL);
2331 add_routing_table_entry(rt_entry);
2332 routing_table_inited = 1;
2333 }
2334 mutex_unlock(&routing_table_lock);
2335
2336 queue_work(xprt_info->workqueue, &xprt_info->read_data);
2337
2338 xprt->priv = xprt_info;
2339
2340 return 0;
2341}
2342
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002343static void msm_ipc_router_remove_xprt(struct msm_ipc_router_xprt *xprt)
2344{
2345 struct msm_ipc_router_xprt_info *xprt_info;
2346
2347 if (xprt && xprt->priv) {
2348 xprt_info = xprt->priv;
2349
2350 xprt_info->abort_data_read = 1;
2351 wake_up(&xprt_info->read_wait);
2352
2353 mutex_lock(&xprt_info_list_lock);
2354 list_del(&xprt_info->list);
2355 mutex_unlock(&xprt_info_list_lock);
2356
2357 flush_workqueue(xprt_info->workqueue);
2358 destroy_workqueue(xprt_info->workqueue);
2359 wake_lock_destroy(&xprt_info->wakelock);
2360
2361 xprt->priv = 0;
2362 kfree(xprt_info);
2363 }
2364}
2365
2366
2367struct msm_ipc_router_xprt_work {
2368 struct msm_ipc_router_xprt *xprt;
2369 struct work_struct work;
2370};
2371
2372static void xprt_open_worker(struct work_struct *work)
2373{
2374 struct msm_ipc_router_xprt_work *xprt_work =
2375 container_of(work, struct msm_ipc_router_xprt_work, work);
2376
2377 msm_ipc_router_add_xprt(xprt_work->xprt);
2378 kfree(xprt_work);
2379}
2380
2381static void xprt_close_worker(struct work_struct *work)
2382{
2383 struct msm_ipc_router_xprt_work *xprt_work =
2384 container_of(work, struct msm_ipc_router_xprt_work, work);
2385
2386 modem_reset_cleanup(xprt_work->xprt->priv);
2387 msm_ipc_router_remove_xprt(xprt_work->xprt);
2388
2389 if (atomic_dec_return(&pending_close_count) == 0)
2390 wake_up(&subsystem_restart_wait);
2391
2392 kfree(xprt_work);
2393}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002394
2395void msm_ipc_router_xprt_notify(struct msm_ipc_router_xprt *xprt,
2396 unsigned event,
2397 void *data)
2398{
2399 struct msm_ipc_router_xprt_info *xprt_info = xprt->priv;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002400 struct msm_ipc_router_xprt_work *xprt_work;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002401 struct rr_packet *pkt;
2402
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002403 BUG_ON(!msm_ipc_router_workqueue);
2404
2405 switch (event) {
2406 case IPC_ROUTER_XPRT_EVENT_OPEN:
2407 D("open event for '%s'\n", xprt->name);
2408 xprt_work = kmalloc(sizeof(struct msm_ipc_router_xprt_work),
2409 GFP_ATOMIC);
2410 xprt_work->xprt = xprt;
2411 INIT_WORK(&xprt_work->work, xprt_open_worker);
2412 queue_work(msm_ipc_router_workqueue, &xprt_work->work);
2413 break;
2414
2415 case IPC_ROUTER_XPRT_EVENT_CLOSE:
2416 D("close event for '%s'\n", xprt->name);
2417 atomic_inc(&pending_close_count);
2418 xprt_work = kmalloc(sizeof(struct msm_ipc_router_xprt_work),
2419 GFP_ATOMIC);
2420 xprt_work->xprt = xprt;
2421 INIT_WORK(&xprt_work->work, xprt_close_worker);
2422 queue_work(msm_ipc_router_workqueue, &xprt_work->work);
2423 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002424 }
2425
2426 if (!data)
2427 return;
2428
2429 while (!xprt_info) {
2430 msleep(100);
2431 xprt_info = xprt->priv;
2432 }
2433
2434 pkt = clone_pkt((struct rr_packet *)data);
2435 if (!pkt)
2436 return;
2437
2438 mutex_lock(&xprt_info->rx_lock);
2439 list_add_tail(&pkt->list, &xprt_info->pkt_list);
2440 wake_lock(&xprt_info->wakelock);
2441 wake_up(&xprt_info->read_wait);
2442 mutex_unlock(&xprt_info->rx_lock);
2443}
2444
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002445static int modem_restart_notifier_cb(struct notifier_block *this,
2446 unsigned long code,
2447 void *data);
2448static struct notifier_block msm_ipc_router_nb = {
2449 .notifier_call = modem_restart_notifier_cb,
2450};
2451
2452static int modem_restart_notifier_cb(struct notifier_block *this,
2453 unsigned long code,
2454 void *data)
2455{
2456 switch (code) {
2457 case SUBSYS_BEFORE_SHUTDOWN:
2458 D("%s: SUBSYS_BEFORE_SHUTDOWN\n", __func__);
2459 break;
2460
2461 case SUBSYS_BEFORE_POWERUP:
2462 D("%s: waiting for RPC restart to complete\n", __func__);
2463 wait_event(subsystem_restart_wait,
2464 atomic_read(&pending_close_count) == 0);
2465 D("%s: finished restart wait\n", __func__);
2466 break;
2467
2468 default:
2469 break;
2470 }
2471
2472 return NOTIFY_DONE;
2473}
2474
2475static void *restart_notifier_handle;
2476static __init int msm_ipc_router_modem_restart_late_init(void)
2477{
2478 restart_notifier_handle = subsys_notif_register_notifier("modem",
2479 &msm_ipc_router_nb);
2480 return 0;
2481}
2482late_initcall(msm_ipc_router_modem_restart_late_init);
2483
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002484static int __init msm_ipc_router_init(void)
2485{
2486 int i, ret;
2487 struct msm_ipc_routing_table_entry *rt_entry;
2488
2489 msm_ipc_router_debug_mask |= SMEM_LOG;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002490 msm_ipc_router_workqueue =
2491 create_singlethread_workqueue("msm_ipc_router");
2492 if (!msm_ipc_router_workqueue)
2493 return -ENOMEM;
2494
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002495 debugfs_init();
2496
2497 for (i = 0; i < SRV_HASH_SIZE; i++)
2498 INIT_LIST_HEAD(&server_list[i]);
2499
2500 for (i = 0; i < LP_HASH_SIZE; i++)
2501 INIT_LIST_HEAD(&local_ports[i]);
2502
2503 mutex_lock(&routing_table_lock);
2504 if (!routing_table_inited) {
2505 init_routing_table();
2506 rt_entry = alloc_routing_table_entry(IPC_ROUTER_NID_LOCAL);
2507 add_routing_table_entry(rt_entry);
2508 routing_table_inited = 1;
2509 }
2510 mutex_unlock(&routing_table_lock);
2511
2512 init_waitqueue_head(&newserver_wait);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002513 init_waitqueue_head(&subsystem_restart_wait);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002514 ret = msm_ipc_router_init_sockets();
2515 if (ret < 0)
2516 pr_err("%s: Init sockets failed\n", __func__);
2517
2518 return ret;
2519}
2520
2521module_init(msm_ipc_router_init);
2522MODULE_DESCRIPTION("MSM IPC Router");
2523MODULE_LICENSE("GPL v2");