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