blob: 538dbbec058121857d2835e57a269f88523ef32f [file] [log] [blame]
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -07001/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002 *
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);
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700759 ret = xprt_info->xprt->write(pkt, pkt_size, xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700760 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)
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700936 fwd_xprt_info->xprt->write(pkt, pkt->length,
937 fwd_xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700938 mutex_unlock(&fwd_xprt_info->tx_lock);
939 }
940 mutex_unlock(&xprt_info_list_lock);
941 return 0;
942}
943
944static int forward_msg(struct msm_ipc_router_xprt_info *xprt_info,
945 struct rr_packet *pkt)
946{
947 uint32_t dst_node_id;
948 struct sk_buff *head_pkt;
949 struct rr_header *hdr;
950 struct msm_ipc_router_xprt_info *fwd_xprt_info;
951 struct msm_ipc_routing_table_entry *rt_entry;
952
953 if (!xprt_info || !pkt)
954 return -EINVAL;
955
956 head_pkt = skb_peek(pkt->pkt_fragment_q);
957 if (!head_pkt)
958 return -EINVAL;
959
960 hdr = (struct rr_header *)head_pkt->data;
961 dst_node_id = hdr->dst_node_id;
962 mutex_lock(&routing_table_lock);
963 rt_entry = lookup_routing_table(dst_node_id);
964 if (!(rt_entry) || !(rt_entry->xprt_info)) {
965 mutex_unlock(&routing_table_lock);
966 pr_err("%s: Routing table not initialized\n", __func__);
967 return -ENODEV;
968 }
969
970 mutex_lock(&rt_entry->lock);
971 fwd_xprt_info = rt_entry->xprt_info;
972 mutex_lock(&fwd_xprt_info->tx_lock);
973 if (xprt_info->remote_node_id == fwd_xprt_info->remote_node_id) {
974 mutex_unlock(&fwd_xprt_info->tx_lock);
975 mutex_unlock(&rt_entry->lock);
976 mutex_unlock(&routing_table_lock);
977 pr_err("%s: Discarding Command to route back\n", __func__);
978 return -EINVAL;
979 }
980
981 if (xprt_info->xprt->link_id == fwd_xprt_info->xprt->link_id) {
982 mutex_unlock(&fwd_xprt_info->tx_lock);
983 mutex_unlock(&rt_entry->lock);
984 mutex_unlock(&routing_table_lock);
985 pr_err("%s: DST in the same cluster\n", __func__);
986 return 0;
987 }
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700988 fwd_xprt_info->xprt->write(pkt, pkt->length, fwd_xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700989 mutex_unlock(&fwd_xprt_info->tx_lock);
990 mutex_unlock(&rt_entry->lock);
991 mutex_unlock(&routing_table_lock);
992
993 return 0;
994}
995
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600996static void reset_remote_port_info(uint32_t node_id, uint32_t port_id)
997{
998 struct msm_ipc_router_remote_port *rport_ptr;
999
1000 rport_ptr = msm_ipc_router_lookup_remote_port(node_id, port_id);
1001 if (!rport_ptr) {
1002 pr_err("%s: No such remote port %08x:%08x\n",
1003 __func__, node_id, port_id);
1004 return;
1005 }
1006 mutex_lock(&rport_ptr->quota_lock);
1007 rport_ptr->restart_state = RESTART_PEND;
1008 wake_up(&rport_ptr->quota_wait);
1009 mutex_unlock(&rport_ptr->quota_lock);
1010 return;
1011}
1012
1013static void msm_ipc_cleanup_remote_server_info(
1014 struct msm_ipc_router_xprt_info *xprt_info)
1015{
1016 struct msm_ipc_server *svr, *tmp_svr;
1017 struct msm_ipc_server_port *svr_port, *tmp_svr_port;
1018 int i;
1019 union rr_control_msg ctl;
1020
1021 if (!xprt_info) {
1022 pr_err("%s: Invalid xprt_info\n", __func__);
1023 return;
1024 }
1025
1026 ctl.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_SERVER;
1027 mutex_lock(&server_list_lock);
1028 for (i = 0; i < SRV_HASH_SIZE; i++) {
1029 list_for_each_entry_safe(svr, tmp_svr, &server_list[i], list) {
1030 ctl.srv.service = svr->name.service;
1031 ctl.srv.instance = svr->name.instance;
1032 list_for_each_entry_safe(svr_port, tmp_svr_port,
1033 &svr->server_port_list, list) {
1034 if (svr_port->xprt_info != xprt_info)
1035 continue;
1036 D("Remove server %08x:%08x - %08x:%08x",
1037 ctl.srv.service, ctl.srv.instance,
1038 svr_port->server_addr.node_id,
1039 svr_port->server_addr.port_id);
1040 reset_remote_port_info(
1041 svr_port->server_addr.node_id,
1042 svr_port->server_addr.port_id);
1043 ctl.srv.node_id = svr_port->server_addr.node_id;
1044 ctl.srv.port_id = svr_port->server_addr.port_id;
1045 relay_ctl_msg(xprt_info, &ctl);
1046 broadcast_ctl_msg_locally(&ctl);
1047 list_del(&svr_port->list);
1048 kfree(svr_port);
1049 }
1050 if (list_empty(&svr->server_port_list)) {
1051 list_del(&svr->list);
1052 kfree(svr);
1053 }
1054 }
1055 }
1056 mutex_unlock(&server_list_lock);
1057}
1058
1059static void msm_ipc_cleanup_remote_client_info(
1060 struct msm_ipc_router_xprt_info *xprt_info)
1061{
1062 struct msm_ipc_routing_table_entry *rt_entry;
1063 struct msm_ipc_router_remote_port *rport_ptr;
1064 int i, j;
1065 union rr_control_msg ctl;
1066
1067 if (!xprt_info) {
1068 pr_err("%s: Invalid xprt_info\n", __func__);
1069 return;
1070 }
1071
1072 ctl.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT;
1073 mutex_lock(&routing_table_lock);
1074 for (i = 0; i < RT_HASH_SIZE; i++) {
1075 list_for_each_entry(rt_entry, &routing_table[i], list) {
1076 mutex_lock(&rt_entry->lock);
1077 if (rt_entry->xprt_info != xprt_info) {
1078 mutex_unlock(&rt_entry->lock);
1079 continue;
1080 }
1081 for (j = 0; j < RP_HASH_SIZE; j++) {
1082 list_for_each_entry(rport_ptr,
1083 &rt_entry->remote_port_list[j], list) {
1084 if (rport_ptr->restart_state ==
1085 RESTART_PEND)
1086 continue;
1087 mutex_lock(&rport_ptr->quota_lock);
1088 rport_ptr->restart_state = RESTART_PEND;
1089 wake_up(&rport_ptr->quota_wait);
1090 mutex_unlock(&rport_ptr->quota_lock);
1091 ctl.cli.node_id = rport_ptr->node_id;
1092 ctl.cli.port_id = rport_ptr->port_id;
1093 broadcast_ctl_msg_locally(&ctl);
1094 }
1095 }
1096 mutex_unlock(&rt_entry->lock);
1097 }
1098 }
1099 mutex_unlock(&routing_table_lock);
1100}
1101
1102static void msm_ipc_cleanup_remote_port_info(uint32_t node_id)
1103{
1104 struct msm_ipc_routing_table_entry *rt_entry, *tmp_rt_entry;
1105 struct msm_ipc_router_remote_port *rport_ptr, *tmp_rport_ptr;
1106 int i, j;
1107
1108 mutex_lock(&routing_table_lock);
1109 for (i = 0; i < RT_HASH_SIZE; i++) {
1110 list_for_each_entry_safe(rt_entry, tmp_rt_entry,
1111 &routing_table[i], list) {
1112 mutex_lock(&rt_entry->lock);
1113 if (rt_entry->neighbor_node_id != node_id) {
1114 mutex_unlock(&rt_entry->lock);
1115 continue;
1116 }
1117 for (j = 0; j < RP_HASH_SIZE; j++) {
1118 list_for_each_entry_safe(rport_ptr,
1119 tmp_rport_ptr,
1120 &rt_entry->remote_port_list[j], list) {
1121 list_del(&rport_ptr->list);
1122 kfree(rport_ptr);
1123 }
1124 }
1125 mutex_unlock(&rt_entry->lock);
1126 }
1127 }
1128 mutex_unlock(&routing_table_lock);
1129}
1130
1131static void msm_ipc_cleanup_routing_table(
1132 struct msm_ipc_router_xprt_info *xprt_info)
1133{
1134 int i;
1135 struct msm_ipc_routing_table_entry *rt_entry;
1136
1137 if (!xprt_info) {
1138 pr_err("%s: Invalid xprt_info\n", __func__);
1139 return;
1140 }
1141
1142 mutex_lock(&routing_table_lock);
1143 for (i = 0; i < RT_HASH_SIZE; i++) {
1144 list_for_each_entry(rt_entry, &routing_table[i], list) {
1145 mutex_lock(&rt_entry->lock);
1146 if (rt_entry->xprt_info == xprt_info)
1147 rt_entry->xprt_info = NULL;
1148 mutex_unlock(&rt_entry->lock);
1149 }
1150 }
1151 mutex_unlock(&routing_table_lock);
1152}
1153
1154static void modem_reset_cleanup(struct msm_ipc_router_xprt_info *xprt_info)
1155{
1156
1157 if (!xprt_info) {
1158 pr_err("%s: Invalid xprt_info\n", __func__);
1159 return;
1160 }
1161
1162 msm_ipc_cleanup_remote_server_info(xprt_info);
1163 msm_ipc_cleanup_remote_client_info(xprt_info);
1164 msm_ipc_cleanup_routing_table(xprt_info);
1165}
1166
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001167static int process_control_msg(struct msm_ipc_router_xprt_info *xprt_info,
1168 struct rr_packet *pkt)
1169{
1170 union rr_control_msg ctl;
1171 union rr_control_msg *msg;
1172 struct msm_ipc_router_remote_port *rport_ptr;
1173 int rc = 0;
1174 static uint32_t first = 1;
1175 struct sk_buff *temp_ptr;
1176 struct rr_header *hdr;
1177 struct msm_ipc_server *server;
1178 struct msm_ipc_routing_table_entry *rt_entry;
1179
1180 if (pkt->length != (IPC_ROUTER_HDR_SIZE + sizeof(*msg))) {
1181 pr_err("%s: r2r msg size %d != %d\n", __func__, pkt->length,
1182 (IPC_ROUTER_HDR_SIZE + sizeof(*msg)));
1183 return -EINVAL;
1184 }
1185
1186 temp_ptr = skb_peek(pkt->pkt_fragment_q);
Karthikeyan Ramasubramanian9024dd82011-12-19 18:44:19 -07001187 if (!temp_ptr) {
1188 pr_err("%s: pkt_fragment_q is empty\n", __func__);
1189 return -EINVAL;
1190 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001191 hdr = (struct rr_header *)temp_ptr->data;
Karthikeyan Ramasubramanian9024dd82011-12-19 18:44:19 -07001192 if (!hdr) {
1193 pr_err("%s: No data inside the skb\n", __func__);
1194 return -EINVAL;
1195 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001196 msg = (union rr_control_msg *)((char *)hdr + IPC_ROUTER_HDR_SIZE);
1197
1198 switch (msg->cmd) {
1199 case IPC_ROUTER_CTRL_CMD_HELLO:
1200 RR("o HELLO NID %d\n", hdr->src_node_id);
1201 xprt_info->remote_node_id = hdr->src_node_id;
1202
1203 mutex_lock(&routing_table_lock);
1204 rt_entry = lookup_routing_table(hdr->src_node_id);
1205 if (!rt_entry) {
1206 rt_entry = alloc_routing_table_entry(hdr->src_node_id);
1207 if (!rt_entry) {
1208 mutex_unlock(&routing_table_lock);
1209 pr_err("%s: rt_entry allocation failed\n",
1210 __func__);
1211 return -ENOMEM;
1212 }
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001213 add_routing_table_entry(rt_entry);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001214 }
1215 mutex_lock(&rt_entry->lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001216 rt_entry->neighbor_node_id = xprt_info->remote_node_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001217 rt_entry->xprt_info = xprt_info;
1218 mutex_unlock(&rt_entry->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001219 mutex_unlock(&routing_table_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001220 msm_ipc_cleanup_remote_port_info(xprt_info->remote_node_id);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001221
1222 memset(&ctl, 0, sizeof(ctl));
1223 ctl.cmd = IPC_ROUTER_CTRL_CMD_HELLO;
1224 msm_ipc_router_send_control_msg(xprt_info, &ctl);
1225
1226 xprt_info->initialized = 1;
1227
1228 /* Send list of servers one at a time */
1229 msm_ipc_router_send_server_list(xprt_info);
1230
1231 if (first) {
1232 first = 0;
1233 complete_all(&msm_ipc_remote_router_up);
1234 }
1235 RR("HELLO message processed\n");
1236 break;
1237 case IPC_ROUTER_CTRL_CMD_RESUME_TX:
1238 RR("o RESUME_TX id=%d:%08x\n",
1239 msg->cli.node_id, msg->cli.port_id);
1240
1241 rport_ptr = msm_ipc_router_lookup_remote_port(msg->cli.node_id,
1242 msg->cli.port_id);
1243 if (!rport_ptr) {
1244 pr_err("%s: Unable to resume client\n", __func__);
1245 break;
1246 }
1247 mutex_lock(&rport_ptr->quota_lock);
1248 rport_ptr->tx_quota_cnt = 0;
1249 mutex_unlock(&rport_ptr->quota_lock);
1250 wake_up(&rport_ptr->quota_wait);
1251 break;
1252
1253 case IPC_ROUTER_CTRL_CMD_NEW_SERVER:
1254 if (msg->srv.instance == 0) {
1255 pr_err(
1256 "rpcrouter: Server create rejected, version = 0, "
1257 "service = %08x\n", msg->srv.service);
1258 break;
1259 }
1260
1261 RR("o NEW_SERVER id=%d:%08x service=%08x:%08x\n",
1262 msg->srv.node_id, msg->srv.port_id,
1263 msg->srv.service, msg->srv.instance);
1264
1265 mutex_lock(&routing_table_lock);
1266 rt_entry = lookup_routing_table(msg->srv.node_id);
1267 if (!rt_entry) {
1268 rt_entry = alloc_routing_table_entry(msg->srv.node_id);
1269 if (!rt_entry) {
1270 mutex_unlock(&routing_table_lock);
1271 pr_err("%s: rt_entry allocation failed\n",
1272 __func__);
1273 return -ENOMEM;
1274 }
1275 mutex_lock(&rt_entry->lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001276 rt_entry->neighbor_node_id = xprt_info->remote_node_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001277 rt_entry->xprt_info = xprt_info;
1278 mutex_unlock(&rt_entry->lock);
1279 add_routing_table_entry(rt_entry);
1280 }
1281 mutex_unlock(&routing_table_lock);
1282
1283 server = msm_ipc_router_lookup_server(msg->srv.service,
1284 msg->srv.instance,
1285 msg->srv.node_id,
1286 msg->srv.port_id);
1287 if (!server) {
1288 server = msm_ipc_router_create_server(
1289 msg->srv.service, msg->srv.instance,
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001290 msg->srv.node_id, msg->srv.port_id, xprt_info);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001291 if (!server) {
1292 pr_err("%s: Server Create failed\n", __func__);
1293 return -ENOMEM;
1294 }
1295
1296 if (!msm_ipc_router_lookup_remote_port(
1297 msg->srv.node_id, msg->srv.port_id)) {
1298 rport_ptr = msm_ipc_router_create_remote_port(
1299 msg->srv.node_id, msg->srv.port_id);
1300 if (!rport_ptr)
1301 pr_err("%s: Remote port create "
1302 "failed\n", __func__);
1303 }
1304 wake_up(&newserver_wait);
1305 }
1306
1307 relay_msg(xprt_info, pkt);
1308 post_control_ports(pkt);
1309 break;
1310 case IPC_ROUTER_CTRL_CMD_REMOVE_SERVER:
1311 RR("o REMOVE_SERVER service=%08x:%d\n",
1312 msg->srv.service, msg->srv.instance);
1313 server = msm_ipc_router_lookup_server(msg->srv.service,
1314 msg->srv.instance,
1315 msg->srv.node_id,
1316 msg->srv.port_id);
1317 if (server) {
1318 msm_ipc_router_destroy_server(server,
1319 msg->srv.node_id,
1320 msg->srv.port_id);
1321 relay_msg(xprt_info, pkt);
1322 post_control_ports(pkt);
1323 }
1324 break;
1325 case IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT:
1326 RR("o REMOVE_CLIENT id=%d:%08x\n",
1327 msg->cli.node_id, msg->cli.port_id);
1328 rport_ptr = msm_ipc_router_lookup_remote_port(msg->cli.node_id,
1329 msg->cli.port_id);
1330 if (rport_ptr)
1331 msm_ipc_router_destroy_remote_port(rport_ptr);
1332
1333 relay_msg(xprt_info, pkt);
1334 post_control_ports(pkt);
1335 break;
1336 case IPC_ROUTER_CTRL_CMD_PING:
1337 /* No action needed for ping messages received */
1338 RR("o PING\n");
1339 break;
1340 default:
1341 RR("o UNKNOWN(%08x)\n", msg->cmd);
1342 rc = -ENOSYS;
1343 }
1344
1345 return rc;
1346}
1347
1348static void do_read_data(struct work_struct *work)
1349{
1350 struct rr_header *hdr;
1351 struct rr_packet *pkt = NULL;
1352 struct msm_ipc_port *port_ptr;
1353 struct sk_buff *head_skb;
1354 struct msm_ipc_port_addr *src_addr;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001355 struct msm_ipc_router_remote_port *rport_ptr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001356 uint32_t resume_tx, resume_tx_node_id, resume_tx_port_id;
1357
1358 struct msm_ipc_router_xprt_info *xprt_info =
1359 container_of(work,
1360 struct msm_ipc_router_xprt_info,
1361 read_data);
1362
1363 pkt = rr_read(xprt_info);
1364 if (!pkt) {
1365 pr_err("%s: rr_read failed\n", __func__);
1366 goto fail_io;
1367 }
1368
1369 if (pkt->length < IPC_ROUTER_HDR_SIZE ||
1370 pkt->length > MAX_IPC_PKT_SIZE) {
1371 pr_err("%s: Invalid pkt length %d\n", __func__, pkt->length);
1372 goto fail_data;
1373 }
1374
1375 head_skb = skb_peek(pkt->pkt_fragment_q);
1376 if (!head_skb) {
1377 pr_err("%s: head_skb is invalid\n", __func__);
1378 goto fail_data;
1379 }
1380
1381 hdr = (struct rr_header *)(head_skb->data);
1382 RR("- ver=%d type=%d src=%d:%08x crx=%d siz=%d dst=%d:%08x\n",
1383 hdr->version, hdr->type, hdr->src_node_id, hdr->src_port_id,
1384 hdr->confirm_rx, hdr->size, hdr->dst_node_id, hdr->dst_port_id);
1385 RAW_HDR("[r rr_h] "
1386 "ver=%i,type=%s,src_node_id=%08x,src_port_id=%08x,"
1387 "confirm_rx=%i,size=%3i,dst_node_id=%08x,dst_port_id=%08x\n",
1388 hdr->version, type_to_str(hdr->type), hdr->src_node_id,
1389 hdr->src_port_id, hdr->confirm_rx, hdr->size, hdr->dst_node_id,
1390 hdr->dst_port_id);
1391
1392 if (hdr->version != IPC_ROUTER_VERSION) {
1393 pr_err("version %d != %d\n", hdr->version, IPC_ROUTER_VERSION);
1394 goto fail_data;
1395 }
1396
1397 if ((hdr->dst_node_id != IPC_ROUTER_NID_LOCAL) &&
1398 ((hdr->type == IPC_ROUTER_CTRL_CMD_RESUME_TX) ||
1399 (hdr->type == IPC_ROUTER_CTRL_CMD_DATA))) {
1400 forward_msg(xprt_info, pkt);
1401 release_pkt(pkt);
1402 goto done;
1403 }
1404
1405 if ((hdr->dst_port_id == IPC_ROUTER_ADDRESS) ||
1406 (hdr->type == IPC_ROUTER_CTRL_CMD_HELLO)) {
1407 process_control_msg(xprt_info, pkt);
1408 release_pkt(pkt);
1409 goto done;
1410 }
1411#if defined(CONFIG_MSM_SMD_LOGGING)
1412#if defined(DEBUG)
1413 if (msm_ipc_router_debug_mask & SMEM_LOG) {
1414 smem_log_event((SMEM_LOG_PROC_ID_APPS |
1415 SMEM_LOG_RPC_ROUTER_EVENT_BASE |
1416 IPC_ROUTER_LOG_EVENT_RX),
1417 (hdr->src_node_id << 24) |
1418 (hdr->src_port_id & 0xffffff),
1419 (hdr->dst_node_id << 24) |
1420 (hdr->dst_port_id & 0xffffff),
1421 (hdr->type << 24) | (hdr->confirm_rx << 16) |
1422 (hdr->size & 0xffff));
1423 }
1424#endif
1425#endif
1426
1427 resume_tx = hdr->confirm_rx;
1428 resume_tx_node_id = hdr->dst_node_id;
1429 resume_tx_port_id = hdr->dst_port_id;
1430
1431 port_ptr = msm_ipc_router_lookup_local_port(hdr->dst_port_id);
1432 if (!port_ptr) {
1433 pr_err("%s: No local port id %08x\n", __func__,
1434 hdr->dst_port_id);
1435 release_pkt(pkt);
1436 goto process_done;
1437 }
1438
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001439 rport_ptr = msm_ipc_router_lookup_remote_port(hdr->src_node_id,
1440 hdr->src_port_id);
1441 if (!rport_ptr) {
1442 rport_ptr = msm_ipc_router_create_remote_port(
1443 hdr->src_node_id,
1444 hdr->src_port_id);
1445 if (!rport_ptr) {
1446 pr_err("%s: Remote port %08x:%08x creation failed\n",
1447 __func__, hdr->src_node_id, hdr->src_port_id);
1448 goto process_done;
1449 }
1450 }
1451
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001452 if (!port_ptr->notify) {
1453 mutex_lock(&port_ptr->port_rx_q_lock);
1454 wake_lock(&port_ptr->port_rx_wake_lock);
1455 list_add_tail(&pkt->list, &port_ptr->port_rx_q);
1456 wake_up(&port_ptr->port_rx_wait_q);
1457 mutex_unlock(&port_ptr->port_rx_q_lock);
1458 } else {
1459 src_addr = kmalloc(sizeof(struct msm_ipc_port_addr),
1460 GFP_KERNEL);
1461 if (src_addr) {
1462 src_addr->node_id = hdr->src_node_id;
1463 src_addr->port_id = hdr->src_port_id;
1464 }
1465 skb_pull(head_skb, IPC_ROUTER_HDR_SIZE);
1466 port_ptr->notify(MSM_IPC_ROUTER_READ_CB, pkt->pkt_fragment_q,
1467 src_addr, port_ptr->priv);
1468 pkt->pkt_fragment_q = NULL;
1469 src_addr = NULL;
1470 release_pkt(pkt);
1471 }
1472
1473process_done:
1474 if (resume_tx) {
1475 union rr_control_msg msg;
1476
1477 msg.cmd = IPC_ROUTER_CTRL_CMD_RESUME_TX;
1478 msg.cli.node_id = resume_tx_node_id;
1479 msg.cli.port_id = resume_tx_port_id;
1480
1481 RR("x RESUME_TX id=%d:%08x\n",
1482 msg.cli.node_id, msg.cli.port_id);
1483 msm_ipc_router_send_control_msg(xprt_info, &msg);
1484 }
1485
1486done:
1487 queue_work(xprt_info->workqueue, &xprt_info->read_data);
1488 return;
1489
1490fail_data:
1491 release_pkt(pkt);
1492fail_io:
1493 pr_err("ipc_router has died\n");
1494}
1495
1496int msm_ipc_router_register_server(struct msm_ipc_port *port_ptr,
1497 struct msm_ipc_addr *name)
1498{
1499 struct msm_ipc_server *server;
1500 unsigned long flags;
1501 union rr_control_msg ctl;
1502
1503 if (!port_ptr || !name)
1504 return -EINVAL;
1505
1506 if (name->addrtype != MSM_IPC_ADDR_NAME)
1507 return -EINVAL;
1508
1509 server = msm_ipc_router_lookup_server(name->addr.port_name.service,
1510 name->addr.port_name.instance,
1511 IPC_ROUTER_NID_LOCAL,
1512 port_ptr->this_port.port_id);
1513 if (server) {
1514 pr_err("%s: Server already present\n", __func__);
1515 return -EINVAL;
1516 }
1517
1518 server = msm_ipc_router_create_server(name->addr.port_name.service,
1519 name->addr.port_name.instance,
1520 IPC_ROUTER_NID_LOCAL,
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001521 port_ptr->this_port.port_id,
1522 NULL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001523 if (!server) {
1524 pr_err("%s: Server Creation failed\n", __func__);
1525 return -EINVAL;
1526 }
1527
1528 ctl.cmd = IPC_ROUTER_CTRL_CMD_NEW_SERVER;
1529 ctl.srv.service = server->name.service;
1530 ctl.srv.instance = server->name.instance;
1531 ctl.srv.node_id = IPC_ROUTER_NID_LOCAL;
1532 ctl.srv.port_id = port_ptr->this_port.port_id;
1533 broadcast_ctl_msg(&ctl);
1534 spin_lock_irqsave(&port_ptr->port_lock, flags);
1535 port_ptr->type = SERVER_PORT;
1536 port_ptr->port_name.service = server->name.service;
1537 port_ptr->port_name.instance = server->name.instance;
1538 spin_unlock_irqrestore(&port_ptr->port_lock, flags);
1539 return 0;
1540}
1541
1542int msm_ipc_router_unregister_server(struct msm_ipc_port *port_ptr)
1543{
1544 struct msm_ipc_server *server;
1545 unsigned long flags;
1546 union rr_control_msg ctl;
1547
1548 if (!port_ptr)
1549 return -EINVAL;
1550
1551 if (port_ptr->type != SERVER_PORT) {
1552 pr_err("%s: Trying to unregister a non-server port\n",
1553 __func__);
1554 return -EINVAL;
1555 }
1556
1557 if (port_ptr->this_port.node_id != IPC_ROUTER_NID_LOCAL) {
1558 pr_err("%s: Trying to unregister a remote server locally\n",
1559 __func__);
1560 return -EINVAL;
1561 }
1562
1563 server = msm_ipc_router_lookup_server(port_ptr->port_name.service,
1564 port_ptr->port_name.instance,
1565 port_ptr->this_port.node_id,
1566 port_ptr->this_port.port_id);
1567 if (!server) {
1568 pr_err("%s: Server lookup failed\n", __func__);
1569 return -ENODEV;
1570 }
1571
1572 ctl.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_SERVER;
1573 ctl.srv.service = server->name.service;
1574 ctl.srv.instance = server->name.instance;
1575 ctl.srv.node_id = IPC_ROUTER_NID_LOCAL;
1576 ctl.srv.port_id = port_ptr->this_port.port_id;
1577 broadcast_ctl_msg(&ctl);
1578 msm_ipc_router_destroy_server(server, port_ptr->this_port.node_id,
1579 port_ptr->this_port.port_id);
1580 spin_lock_irqsave(&port_ptr->port_lock, flags);
1581 port_ptr->type = CLIENT_PORT;
1582 spin_unlock_irqrestore(&port_ptr->port_lock, flags);
1583 return 0;
1584}
1585
1586static int loopback_data(struct msm_ipc_port *src,
1587 uint32_t port_id,
1588 struct sk_buff_head *data)
1589{
1590 struct sk_buff *head_skb;
1591 struct rr_header *hdr;
1592 struct msm_ipc_port *port_ptr;
1593 struct rr_packet *pkt;
1594
1595 if (!data) {
1596 pr_err("%s: Invalid pkt pointer\n", __func__);
1597 return -EINVAL;
1598 }
1599
1600 pkt = create_pkt(data);
1601 if (!pkt) {
1602 pr_err("%s: New pkt create failed\n", __func__);
1603 return -ENOMEM;
1604 }
1605
1606 head_skb = skb_peek(pkt->pkt_fragment_q);
Karthikeyan Ramasubramanian9024dd82011-12-19 18:44:19 -07001607 if (!head_skb) {
1608 pr_err("%s: pkt_fragment_q is empty\n", __func__);
1609 return -EINVAL;
1610 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001611 hdr = (struct rr_header *)skb_push(head_skb, IPC_ROUTER_HDR_SIZE);
1612 if (!hdr) {
1613 pr_err("%s: Prepend Header failed\n", __func__);
1614 release_pkt(pkt);
1615 return -ENOMEM;
1616 }
1617 hdr->version = IPC_ROUTER_VERSION;
1618 hdr->type = IPC_ROUTER_CTRL_CMD_DATA;
1619 hdr->src_node_id = src->this_port.node_id;
1620 hdr->src_port_id = src->this_port.port_id;
1621 hdr->size = pkt->length;
1622 hdr->confirm_rx = 0;
1623 hdr->dst_node_id = IPC_ROUTER_NID_LOCAL;
1624 hdr->dst_port_id = port_id;
1625 pkt->length += IPC_ROUTER_HDR_SIZE;
1626
1627 port_ptr = msm_ipc_router_lookup_local_port(port_id);
1628 if (!port_ptr) {
1629 pr_err("%s: Local port %d not present\n", __func__, port_id);
1630 release_pkt(pkt);
1631 return -ENODEV;
1632 }
1633
1634 mutex_lock(&port_ptr->port_rx_q_lock);
1635 wake_lock(&port_ptr->port_rx_wake_lock);
1636 list_add_tail(&pkt->list, &port_ptr->port_rx_q);
1637 wake_up(&port_ptr->port_rx_wait_q);
1638 mutex_unlock(&port_ptr->port_rx_q_lock);
1639
1640 return pkt->length;
1641}
1642
1643static int msm_ipc_router_write_pkt(struct msm_ipc_port *src,
1644 struct msm_ipc_router_remote_port *rport_ptr,
1645 struct rr_packet *pkt)
1646{
1647 struct sk_buff *head_skb;
1648 struct rr_header *hdr;
1649 struct msm_ipc_router_xprt_info *xprt_info;
1650 struct msm_ipc_routing_table_entry *rt_entry;
1651 int ret;
1652 DEFINE_WAIT(__wait);
1653
1654 if (!rport_ptr || !src || !pkt)
1655 return -EINVAL;
1656
1657 head_skb = skb_peek(pkt->pkt_fragment_q);
Karthikeyan Ramasubramanian9024dd82011-12-19 18:44:19 -07001658 if (!head_skb) {
1659 pr_err("%s: pkt_fragment_q is empty\n", __func__);
1660 return -EINVAL;
1661 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001662 hdr = (struct rr_header *)skb_push(head_skb, IPC_ROUTER_HDR_SIZE);
1663 if (!hdr) {
1664 pr_err("%s: Prepend Header failed\n", __func__);
1665 return -ENOMEM;
1666 }
1667 hdr->version = IPC_ROUTER_VERSION;
1668 hdr->type = IPC_ROUTER_CTRL_CMD_DATA;
1669 hdr->src_node_id = src->this_port.node_id;
1670 hdr->src_port_id = src->this_port.port_id;
1671 hdr->size = pkt->length;
1672 hdr->confirm_rx = 0;
1673 hdr->dst_node_id = rport_ptr->node_id;
1674 hdr->dst_port_id = rport_ptr->port_id;
1675 pkt->length += IPC_ROUTER_HDR_SIZE;
1676
1677 for (;;) {
1678 prepare_to_wait(&rport_ptr->quota_wait, &__wait,
1679 TASK_INTERRUPTIBLE);
1680 mutex_lock(&rport_ptr->quota_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001681 if (rport_ptr->restart_state != RESTART_NORMAL)
1682 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001683 if (rport_ptr->tx_quota_cnt <
1684 IPC_ROUTER_DEFAULT_RX_QUOTA)
1685 break;
1686 if (signal_pending(current))
1687 break;
1688 mutex_unlock(&rport_ptr->quota_lock);
1689 schedule();
1690 }
1691 finish_wait(&rport_ptr->quota_wait, &__wait);
1692
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001693 if (rport_ptr->restart_state != RESTART_NORMAL) {
1694 mutex_unlock(&rport_ptr->quota_lock);
1695 return -ENETRESET;
1696 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001697 if (signal_pending(current)) {
1698 mutex_unlock(&rport_ptr->quota_lock);
1699 return -ERESTARTSYS;
1700 }
1701 rport_ptr->tx_quota_cnt++;
1702 if (rport_ptr->tx_quota_cnt == IPC_ROUTER_DEFAULT_RX_QUOTA)
1703 hdr->confirm_rx = 1;
1704 mutex_unlock(&rport_ptr->quota_lock);
1705
1706 mutex_lock(&routing_table_lock);
1707 rt_entry = lookup_routing_table(hdr->dst_node_id);
1708 if (!rt_entry || !rt_entry->xprt_info) {
1709 mutex_unlock(&routing_table_lock);
1710 pr_err("%s: Remote node %d not up\n",
1711 __func__, hdr->dst_node_id);
1712 return -ENODEV;
1713 }
1714 mutex_lock(&rt_entry->lock);
1715 xprt_info = rt_entry->xprt_info;
1716 mutex_lock(&xprt_info->tx_lock);
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -07001717 ret = xprt_info->xprt->write(pkt, pkt->length, xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001718 mutex_unlock(&xprt_info->tx_lock);
1719 mutex_unlock(&rt_entry->lock);
1720 mutex_unlock(&routing_table_lock);
1721
1722 if (ret < 0) {
1723 pr_err("%s: Write on XPRT failed\n", __func__);
1724 return ret;
1725 }
1726
1727 RAW_HDR("[w rr_h] "
1728 "ver=%i,type=%s,src_nid=%08x,src_port_id=%08x,"
1729 "confirm_rx=%i,size=%3i,dst_pid=%08x,dst_cid=%08x\n",
1730 hdr->version, type_to_str(hdr->type),
1731 hdr->src_node_id, hdr->src_port_id,
1732 hdr->confirm_rx, hdr->size,
1733 hdr->dst_node_id, hdr->dst_port_id);
1734
1735#if defined(CONFIG_MSM_SMD_LOGGING)
1736#if defined(DEBUG)
1737 if (msm_ipc_router_debug_mask & SMEM_LOG) {
1738 smem_log_event((SMEM_LOG_PROC_ID_APPS |
1739 SMEM_LOG_RPC_ROUTER_EVENT_BASE |
1740 IPC_ROUTER_LOG_EVENT_TX),
1741 (hdr->src_node_id << 24) |
1742 (hdr->src_port_id & 0xffffff),
1743 (hdr->dst_node_id << 24) |
1744 (hdr->dst_port_id & 0xffffff),
1745 (hdr->type << 24) | (hdr->confirm_rx << 16) |
1746 (hdr->size & 0xffff));
1747 }
1748#endif
1749#endif
1750
1751 return pkt->length;
1752}
1753
1754int msm_ipc_router_send_to(struct msm_ipc_port *src,
1755 struct sk_buff_head *data,
1756 struct msm_ipc_addr *dest)
1757{
1758 uint32_t dst_node_id = 0, dst_port_id = 0;
1759 struct msm_ipc_server *server;
1760 struct msm_ipc_server_port *server_port;
1761 struct msm_ipc_router_remote_port *rport_ptr = NULL;
1762 struct rr_packet *pkt;
1763 int ret;
1764
1765 if (!src || !data || !dest) {
1766 pr_err("%s: Invalid Parameters\n", __func__);
1767 return -EINVAL;
1768 }
1769
1770 /* Resolve Address*/
1771 if (dest->addrtype == MSM_IPC_ADDR_ID) {
1772 dst_node_id = dest->addr.port_addr.node_id;
1773 dst_port_id = dest->addr.port_addr.port_id;
1774 } else if (dest->addrtype == MSM_IPC_ADDR_NAME) {
1775 server = msm_ipc_router_lookup_server(
1776 dest->addr.port_name.service,
1777 dest->addr.port_name.instance,
1778 0, 0);
1779 if (!server) {
1780 pr_err("%s: Destination not reachable\n", __func__);
1781 return -ENODEV;
1782 }
1783 mutex_lock(&server_list_lock);
1784 server_port = list_first_entry(&server->server_port_list,
1785 struct msm_ipc_server_port,
1786 list);
1787 dst_node_id = server_port->server_addr.node_id;
1788 dst_port_id = server_port->server_addr.port_id;
1789 mutex_unlock(&server_list_lock);
1790 }
1791 if (dst_node_id == IPC_ROUTER_NID_LOCAL) {
1792 ret = loopback_data(src, dst_port_id, data);
1793 return ret;
1794 }
1795
1796 /* Achieve Flow control */
1797 rport_ptr = msm_ipc_router_lookup_remote_port(dst_node_id,
1798 dst_port_id);
1799 if (!rport_ptr) {
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001800 pr_err("%s: Could not create remote port\n", __func__);
1801 return -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001802 }
1803
1804 pkt = create_pkt(data);
1805 if (!pkt) {
1806 pr_err("%s: Pkt creation failed\n", __func__);
1807 return -ENOMEM;
1808 }
1809
1810 ret = msm_ipc_router_write_pkt(src, rport_ptr, pkt);
1811 release_pkt(pkt);
1812
1813 return ret;
1814}
1815
1816int msm_ipc_router_read(struct msm_ipc_port *port_ptr,
1817 struct sk_buff_head **data,
1818 size_t buf_len)
1819{
1820 struct rr_packet *pkt;
1821 int ret;
1822
1823 if (!port_ptr || !data)
1824 return -EINVAL;
1825
1826 mutex_lock(&port_ptr->port_rx_q_lock);
1827 if (list_empty(&port_ptr->port_rx_q)) {
1828 mutex_unlock(&port_ptr->port_rx_q_lock);
1829 return -EAGAIN;
1830 }
1831
1832 pkt = list_first_entry(&port_ptr->port_rx_q, struct rr_packet, list);
1833 if ((buf_len) && ((pkt->length - IPC_ROUTER_HDR_SIZE) > buf_len)) {
1834 mutex_unlock(&port_ptr->port_rx_q_lock);
1835 return -ETOOSMALL;
1836 }
1837 list_del(&pkt->list);
1838 if (list_empty(&port_ptr->port_rx_q))
1839 wake_unlock(&port_ptr->port_rx_wake_lock);
1840 *data = pkt->pkt_fragment_q;
1841 ret = pkt->length;
1842 kfree(pkt);
1843 mutex_unlock(&port_ptr->port_rx_q_lock);
1844
1845 return ret;
1846}
1847
1848int msm_ipc_router_recv_from(struct msm_ipc_port *port_ptr,
1849 struct sk_buff_head **data,
1850 struct msm_ipc_addr *src,
1851 unsigned long timeout)
1852{
1853 int ret, data_len, align_size;
1854 struct sk_buff *temp_skb;
1855 struct rr_header *hdr = NULL;
1856
1857 if (!port_ptr || !data) {
1858 pr_err("%s: Invalid pointers being passed\n", __func__);
1859 return -EINVAL;
1860 }
1861
1862 *data = NULL;
1863 mutex_lock(&port_ptr->port_rx_q_lock);
1864 while (list_empty(&port_ptr->port_rx_q)) {
1865 mutex_unlock(&port_ptr->port_rx_q_lock);
1866 if (timeout < 0) {
1867 ret = wait_event_interruptible(
1868 port_ptr->port_rx_wait_q,
1869 !list_empty(&port_ptr->port_rx_q));
1870 if (ret)
1871 return ret;
1872 } else if (timeout > 0) {
1873 timeout = wait_event_interruptible_timeout(
1874 port_ptr->port_rx_wait_q,
1875 !list_empty(&port_ptr->port_rx_q),
1876 timeout);
1877 if (timeout < 0)
1878 return -EFAULT;
1879 }
1880 if (timeout == 0)
1881 return -ETIMEDOUT;
1882 mutex_lock(&port_ptr->port_rx_q_lock);
1883 }
1884 mutex_unlock(&port_ptr->port_rx_q_lock);
1885
1886 ret = msm_ipc_router_read(port_ptr, data, 0);
1887 if (ret <= 0 || !(*data))
1888 return ret;
1889
1890 temp_skb = skb_peek(*data);
1891 hdr = (struct rr_header *)(temp_skb->data);
1892 if (src) {
1893 src->addrtype = MSM_IPC_ADDR_ID;
1894 src->addr.port_addr.node_id = hdr->src_node_id;
1895 src->addr.port_addr.port_id = hdr->src_port_id;
1896 }
1897
1898 data_len = hdr->size;
1899 skb_pull(temp_skb, IPC_ROUTER_HDR_SIZE);
1900 align_size = ALIGN_SIZE(data_len);
1901 if (align_size) {
1902 temp_skb = skb_peek_tail(*data);
1903 skb_trim(temp_skb, (temp_skb->len - align_size));
1904 }
1905 return data_len;
1906}
1907
1908struct msm_ipc_port *msm_ipc_router_create_port(
1909 void (*notify)(unsigned event, void *data, void *addr, void *priv),
1910 void *priv)
1911{
1912 struct msm_ipc_port *port_ptr;
1913
1914 port_ptr = msm_ipc_router_create_raw_port(NULL, notify, priv);
1915 if (!port_ptr)
1916 pr_err("%s: port_ptr alloc failed\n", __func__);
1917
1918 return port_ptr;
1919}
1920
1921int msm_ipc_router_close_port(struct msm_ipc_port *port_ptr)
1922{
1923 union rr_control_msg msg;
1924 struct rr_packet *pkt, *temp_pkt;
1925 struct msm_ipc_server *server;
1926
1927 if (!port_ptr)
1928 return -EINVAL;
1929
1930 if (port_ptr->type == SERVER_PORT || port_ptr->type == CLIENT_PORT) {
1931 if (port_ptr->type == SERVER_PORT) {
1932 msg.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_SERVER;
1933 msg.srv.service = port_ptr->port_name.service;
1934 msg.srv.instance = port_ptr->port_name.instance;
1935 msg.srv.node_id = port_ptr->this_port.node_id;
1936 msg.srv.port_id = port_ptr->this_port.port_id;
1937 RR("x REMOVE_SERVER Name=%d:%08x Id=%d:%08x\n",
1938 msg.srv.service, msg.srv.instance,
1939 msg.srv.node_id, msg.srv.port_id);
1940 } else if (port_ptr->type == CLIENT_PORT) {
1941 msg.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT;
1942 msg.cli.node_id = port_ptr->this_port.node_id;
1943 msg.cli.port_id = port_ptr->this_port.port_id;
1944 RR("x REMOVE_CLIENT id=%d:%08x\n",
1945 msg.cli.node_id, msg.cli.port_id);
1946 }
1947 broadcast_ctl_msg(&msg);
1948 broadcast_ctl_msg_locally(&msg);
1949 }
1950
1951 mutex_lock(&port_ptr->port_rx_q_lock);
1952 list_for_each_entry_safe(pkt, temp_pkt, &port_ptr->port_rx_q, list) {
1953 list_del(&pkt->list);
1954 release_pkt(pkt);
1955 }
1956 mutex_unlock(&port_ptr->port_rx_q_lock);
1957
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001958 if (port_ptr->type == SERVER_PORT) {
1959 server = msm_ipc_router_lookup_server(
1960 port_ptr->port_name.service,
1961 port_ptr->port_name.instance,
1962 port_ptr->this_port.node_id,
1963 port_ptr->this_port.port_id);
1964 if (server)
1965 msm_ipc_router_destroy_server(server,
1966 port_ptr->this_port.node_id,
1967 port_ptr->this_port.port_id);
1968 mutex_lock(&local_ports_lock);
1969 list_del(&port_ptr->list);
1970 mutex_unlock(&local_ports_lock);
1971 } else if (port_ptr->type == CLIENT_PORT) {
1972 mutex_lock(&local_ports_lock);
1973 list_del(&port_ptr->list);
1974 mutex_unlock(&local_ports_lock);
1975 } else if (port_ptr->type == CONTROL_PORT) {
1976 mutex_lock(&control_ports_lock);
1977 list_del(&port_ptr->list);
1978 mutex_unlock(&control_ports_lock);
1979 }
1980
Karthikeyan Ramasubramaniandd8c3b52011-11-30 16:26:12 -07001981 wake_lock_destroy(&port_ptr->port_rx_wake_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001982 kfree(port_ptr);
1983 return 0;
1984}
1985
1986int msm_ipc_router_get_curr_pkt_size(struct msm_ipc_port *port_ptr)
1987{
1988 struct rr_packet *pkt;
1989 int rc = 0;
1990
1991 if (!port_ptr)
1992 return -EINVAL;
1993
1994 mutex_lock(&port_ptr->port_rx_q_lock);
1995 if (!list_empty(&port_ptr->port_rx_q)) {
1996 pkt = list_first_entry(&port_ptr->port_rx_q,
1997 struct rr_packet, list);
1998 rc = pkt->length;
1999 }
2000 mutex_unlock(&port_ptr->port_rx_q_lock);
2001
2002 return rc;
2003}
2004
2005int msm_ipc_router_bind_control_port(struct msm_ipc_port *port_ptr)
2006{
2007 if (!port_ptr)
2008 return -EINVAL;
2009
2010 mutex_lock(&local_ports_lock);
2011 list_del(&port_ptr->list);
2012 mutex_unlock(&local_ports_lock);
2013 port_ptr->type = CONTROL_PORT;
2014 mutex_lock(&control_ports_lock);
2015 list_add_tail(&port_ptr->list, &control_ports);
2016 mutex_unlock(&control_ports_lock);
2017
2018 return 0;
2019}
2020
2021int msm_ipc_router_lookup_server_name(struct msm_ipc_port_name *srv_name,
2022 struct msm_ipc_port_addr *srv_addr,
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002023 int num_entries_in_array,
2024 uint32_t lookup_mask)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002025{
2026 struct msm_ipc_server *server;
2027 struct msm_ipc_server_port *server_port;
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002028 int key, i = 0; /*num_entries_found*/
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002029
2030 if (!srv_name) {
2031 pr_err("%s: Invalid srv_name\n", __func__);
2032 return -EINVAL;
2033 }
2034
2035 if (num_entries_in_array && !srv_addr) {
2036 pr_err("%s: srv_addr NULL\n", __func__);
2037 return -EINVAL;
2038 }
2039
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002040 mutex_lock(&server_list_lock);
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002041 if (!lookup_mask)
2042 lookup_mask = 0xFFFFFFFF;
2043 for (key = 0; key < SRV_HASH_SIZE; key++) {
2044 list_for_each_entry(server, &server_list[key], list) {
2045 if ((server->name.service != srv_name->service) ||
2046 ((server->name.instance & lookup_mask) !=
2047 srv_name->instance))
2048 continue;
2049
2050 list_for_each_entry(server_port,
2051 &server->server_port_list, list) {
2052 if (i < num_entries_in_array) {
2053 srv_addr[i].node_id =
2054 server_port->server_addr.node_id;
2055 srv_addr[i].port_id =
2056 server_port->server_addr.port_id;
2057 }
2058 i++;
2059 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002060 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002061 }
2062 mutex_unlock(&server_list_lock);
2063
2064 return i;
2065}
2066
2067int msm_ipc_router_close(void)
2068{
2069 struct msm_ipc_router_xprt_info *xprt_info, *tmp_xprt_info;
2070
2071 mutex_lock(&xprt_info_list_lock);
2072 list_for_each_entry_safe(xprt_info, tmp_xprt_info,
2073 &xprt_info_list, list) {
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -07002074 xprt_info->xprt->close(xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002075 list_del(&xprt_info->list);
2076 kfree(xprt_info);
2077 }
2078 mutex_unlock(&xprt_info_list_lock);
2079 return 0;
2080}
2081
2082#if defined(CONFIG_DEBUG_FS)
2083static int dump_routing_table(char *buf, int max)
2084{
2085 int i = 0, j;
2086 struct msm_ipc_routing_table_entry *rt_entry;
2087
2088 for (j = 0; j < RT_HASH_SIZE; j++) {
2089 mutex_lock(&routing_table_lock);
2090 list_for_each_entry(rt_entry, &routing_table[j], list) {
2091 mutex_lock(&rt_entry->lock);
2092 i += scnprintf(buf + i, max - i,
2093 "Node Id: 0x%08x\n", rt_entry->node_id);
2094 if (j == IPC_ROUTER_NID_LOCAL) {
2095 i += scnprintf(buf + i, max - i,
2096 "XPRT Name: Loopback\n");
2097 i += scnprintf(buf + i, max - i,
2098 "Next Hop: %d\n", rt_entry->node_id);
2099 } else {
2100 i += scnprintf(buf + i, max - i,
2101 "XPRT Name: %s\n",
2102 rt_entry->xprt_info->xprt->name);
2103 i += scnprintf(buf + i, max - i,
2104 "Next Hop: 0x%08x\n",
2105 rt_entry->xprt_info->remote_node_id);
2106 }
2107 i += scnprintf(buf + i, max - i, "\n");
2108 mutex_unlock(&rt_entry->lock);
2109 }
2110 mutex_unlock(&routing_table_lock);
2111 }
2112
2113 return i;
2114}
2115
2116static int dump_xprt_info(char *buf, int max)
2117{
2118 int i = 0;
2119 struct msm_ipc_router_xprt_info *xprt_info;
2120
2121 mutex_lock(&xprt_info_list_lock);
2122 list_for_each_entry(xprt_info, &xprt_info_list, list) {
2123 i += scnprintf(buf + i, max - i, "XPRT Name: %s\n",
2124 xprt_info->xprt->name);
2125 i += scnprintf(buf + i, max - i, "Link Id: %d\n",
2126 xprt_info->xprt->link_id);
2127 i += scnprintf(buf + i, max - i, "Initialized: %s\n",
2128 (xprt_info->initialized ? "Y" : "N"));
2129 i += scnprintf(buf + i, max - i, "Remote Node Id: 0x%08x\n",
2130 xprt_info->remote_node_id);
2131 i += scnprintf(buf + i, max - i, "\n");
2132 }
2133 mutex_unlock(&xprt_info_list_lock);
2134
2135 return i;
2136}
2137
2138static int dump_servers(char *buf, int max)
2139{
2140 int i = 0, j;
2141 struct msm_ipc_server *server;
2142 struct msm_ipc_server_port *server_port;
2143
2144 mutex_lock(&server_list_lock);
2145 for (j = 0; j < SRV_HASH_SIZE; j++) {
2146 list_for_each_entry(server, &server_list[j], list) {
2147 list_for_each_entry(server_port,
2148 &server->server_port_list,
2149 list) {
2150 i += scnprintf(buf + i, max - i, "Service: "
2151 "0x%08x\n", server->name.service);
2152 i += scnprintf(buf + i, max - i, "Instance: "
2153 "0x%08x\n", server->name.instance);
2154 i += scnprintf(buf + i, max - i,
2155 "Node_id: 0x%08x\n",
2156 server_port->server_addr.node_id);
2157 i += scnprintf(buf + i, max - i,
2158 "Port_id: 0x%08x\n",
2159 server_port->server_addr.port_id);
2160 i += scnprintf(buf + i, max - i, "\n");
2161 }
2162 }
2163 }
2164 mutex_unlock(&server_list_lock);
2165
2166 return i;
2167}
2168
2169static int dump_remote_ports(char *buf, int max)
2170{
2171 int i = 0, j, k;
2172 struct msm_ipc_router_remote_port *rport_ptr;
2173 struct msm_ipc_routing_table_entry *rt_entry;
2174
2175 for (j = 0; j < RT_HASH_SIZE; j++) {
2176 mutex_lock(&routing_table_lock);
2177 list_for_each_entry(rt_entry, &routing_table[j], list) {
2178 mutex_lock(&rt_entry->lock);
2179 for (k = 0; k < RP_HASH_SIZE; k++) {
2180 list_for_each_entry(rport_ptr,
2181 &rt_entry->remote_port_list[k],
2182 list) {
2183 i += scnprintf(buf + i, max - i,
2184 "Node_id: 0x%08x\n",
2185 rport_ptr->node_id);
2186 i += scnprintf(buf + i, max - i,
2187 "Port_id: 0x%08x\n",
2188 rport_ptr->port_id);
2189 i += scnprintf(buf + i, max - i,
2190 "Quota_cnt: %d\n",
2191 rport_ptr->tx_quota_cnt);
2192 i += scnprintf(buf + i, max - i, "\n");
2193 }
2194 }
2195 mutex_unlock(&rt_entry->lock);
2196 }
2197 mutex_unlock(&routing_table_lock);
2198 }
2199
2200 return i;
2201}
2202
2203static int dump_control_ports(char *buf, int max)
2204{
2205 int i = 0;
2206 struct msm_ipc_port *port_ptr;
2207
2208 mutex_lock(&control_ports_lock);
2209 list_for_each_entry(port_ptr, &control_ports, list) {
2210 i += scnprintf(buf + i, max - i, "Node_id: 0x%08x\n",
2211 port_ptr->this_port.node_id);
2212 i += scnprintf(buf + i, max - i, "Port_id: 0x%08x\n",
2213 port_ptr->this_port.port_id);
2214 i += scnprintf(buf + i, max - i, "\n");
2215 }
2216 mutex_unlock(&control_ports_lock);
2217
2218 return i;
2219}
2220
2221static int dump_local_ports(char *buf, int max)
2222{
2223 int i = 0, j;
2224 unsigned long flags;
2225 struct msm_ipc_port *port_ptr;
2226
2227 mutex_lock(&local_ports_lock);
2228 for (j = 0; j < LP_HASH_SIZE; j++) {
2229 list_for_each_entry(port_ptr, &local_ports[j], list) {
2230 spin_lock_irqsave(&port_ptr->port_lock, flags);
2231 i += scnprintf(buf + i, max - i, "Node_id: 0x%08x\n",
2232 port_ptr->this_port.node_id);
2233 i += scnprintf(buf + i, max - i, "Port_id: 0x%08x\n",
2234 port_ptr->this_port.port_id);
2235 i += scnprintf(buf + i, max - i, "# pkts tx'd %d\n",
2236 port_ptr->num_tx);
2237 i += scnprintf(buf + i, max - i, "# pkts rx'd %d\n",
2238 port_ptr->num_rx);
2239 i += scnprintf(buf + i, max - i, "# bytes tx'd %ld\n",
2240 port_ptr->num_tx_bytes);
2241 i += scnprintf(buf + i, max - i, "# bytes rx'd %ld\n",
2242 port_ptr->num_rx_bytes);
2243 spin_unlock_irqrestore(&port_ptr->port_lock, flags);
2244 i += scnprintf(buf + i, max - i, "\n");
2245 }
2246 }
2247 mutex_unlock(&local_ports_lock);
2248
2249 return i;
2250}
2251
2252#define DEBUG_BUFMAX 4096
2253static char debug_buffer[DEBUG_BUFMAX];
2254
2255static ssize_t debug_read(struct file *file, char __user *buf,
2256 size_t count, loff_t *ppos)
2257{
2258 int (*fill)(char *buf, int max) = file->private_data;
2259 int bsize = fill(debug_buffer, DEBUG_BUFMAX);
2260 return simple_read_from_buffer(buf, count, ppos, debug_buffer, bsize);
2261}
2262
2263static int debug_open(struct inode *inode, struct file *file)
2264{
2265 file->private_data = inode->i_private;
2266 return 0;
2267}
2268
2269static const struct file_operations debug_ops = {
2270 .read = debug_read,
2271 .open = debug_open,
2272};
2273
2274static void debug_create(const char *name, mode_t mode,
2275 struct dentry *dent,
2276 int (*fill)(char *buf, int max))
2277{
2278 debugfs_create_file(name, mode, dent, fill, &debug_ops);
2279}
2280
2281static void debugfs_init(void)
2282{
2283 struct dentry *dent;
2284
2285 dent = debugfs_create_dir("msm_ipc_router", 0);
2286 if (IS_ERR(dent))
2287 return;
2288
2289 debug_create("dump_local_ports", 0444, dent,
2290 dump_local_ports);
2291 debug_create("dump_remote_ports", 0444, dent,
2292 dump_remote_ports);
2293 debug_create("dump_control_ports", 0444, dent,
2294 dump_control_ports);
2295 debug_create("dump_servers", 0444, dent,
2296 dump_servers);
2297 debug_create("dump_xprt_info", 0444, dent,
2298 dump_xprt_info);
2299 debug_create("dump_routing_table", 0444, dent,
2300 dump_routing_table);
2301}
2302
2303#else
2304static void debugfs_init(void) {}
2305#endif
2306
2307static int msm_ipc_router_add_xprt(struct msm_ipc_router_xprt *xprt)
2308{
2309 struct msm_ipc_router_xprt_info *xprt_info;
2310 struct msm_ipc_routing_table_entry *rt_entry;
2311
2312 xprt_info = kmalloc(sizeof(struct msm_ipc_router_xprt_info),
2313 GFP_KERNEL);
2314 if (!xprt_info)
2315 return -ENOMEM;
2316
2317 xprt_info->xprt = xprt;
2318 xprt_info->initialized = 0;
2319 xprt_info->remote_node_id = -1;
2320 INIT_LIST_HEAD(&xprt_info->pkt_list);
2321 init_waitqueue_head(&xprt_info->read_wait);
2322 mutex_init(&xprt_info->rx_lock);
2323 mutex_init(&xprt_info->tx_lock);
2324 wake_lock_init(&xprt_info->wakelock,
2325 WAKE_LOCK_SUSPEND, xprt->name);
2326 xprt_info->need_len = 0;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002327 xprt_info->abort_data_read = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002328 INIT_WORK(&xprt_info->read_data, do_read_data);
2329 INIT_LIST_HEAD(&xprt_info->list);
2330
2331 xprt_info->workqueue = create_singlethread_workqueue(xprt->name);
2332 if (!xprt_info->workqueue) {
2333 kfree(xprt_info);
2334 return -ENOMEM;
2335 }
2336
2337 if (!strcmp(xprt->name, "msm_ipc_router_loopback_xprt")) {
2338 xprt_info->remote_node_id = IPC_ROUTER_NID_LOCAL;
2339 xprt_info->initialized = 1;
2340 }
2341
2342 mutex_lock(&xprt_info_list_lock);
2343 list_add_tail(&xprt_info->list, &xprt_info_list);
2344 mutex_unlock(&xprt_info_list_lock);
2345
2346 mutex_lock(&routing_table_lock);
2347 if (!routing_table_inited) {
2348 init_routing_table();
2349 rt_entry = alloc_routing_table_entry(IPC_ROUTER_NID_LOCAL);
2350 add_routing_table_entry(rt_entry);
2351 routing_table_inited = 1;
2352 }
2353 mutex_unlock(&routing_table_lock);
2354
2355 queue_work(xprt_info->workqueue, &xprt_info->read_data);
2356
2357 xprt->priv = xprt_info;
2358
2359 return 0;
2360}
2361
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002362static void msm_ipc_router_remove_xprt(struct msm_ipc_router_xprt *xprt)
2363{
2364 struct msm_ipc_router_xprt_info *xprt_info;
2365
2366 if (xprt && xprt->priv) {
2367 xprt_info = xprt->priv;
2368
2369 xprt_info->abort_data_read = 1;
2370 wake_up(&xprt_info->read_wait);
2371
2372 mutex_lock(&xprt_info_list_lock);
2373 list_del(&xprt_info->list);
2374 mutex_unlock(&xprt_info_list_lock);
2375
2376 flush_workqueue(xprt_info->workqueue);
2377 destroy_workqueue(xprt_info->workqueue);
2378 wake_lock_destroy(&xprt_info->wakelock);
2379
2380 xprt->priv = 0;
2381 kfree(xprt_info);
2382 }
2383}
2384
2385
2386struct msm_ipc_router_xprt_work {
2387 struct msm_ipc_router_xprt *xprt;
2388 struct work_struct work;
2389};
2390
2391static void xprt_open_worker(struct work_struct *work)
2392{
2393 struct msm_ipc_router_xprt_work *xprt_work =
2394 container_of(work, struct msm_ipc_router_xprt_work, work);
2395
2396 msm_ipc_router_add_xprt(xprt_work->xprt);
2397 kfree(xprt_work);
2398}
2399
2400static void xprt_close_worker(struct work_struct *work)
2401{
2402 struct msm_ipc_router_xprt_work *xprt_work =
2403 container_of(work, struct msm_ipc_router_xprt_work, work);
2404
2405 modem_reset_cleanup(xprt_work->xprt->priv);
2406 msm_ipc_router_remove_xprt(xprt_work->xprt);
2407
2408 if (atomic_dec_return(&pending_close_count) == 0)
2409 wake_up(&subsystem_restart_wait);
2410
2411 kfree(xprt_work);
2412}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002413
2414void msm_ipc_router_xprt_notify(struct msm_ipc_router_xprt *xprt,
2415 unsigned event,
2416 void *data)
2417{
2418 struct msm_ipc_router_xprt_info *xprt_info = xprt->priv;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002419 struct msm_ipc_router_xprt_work *xprt_work;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002420 struct rr_packet *pkt;
Karthikeyan Ramasubramanian4af9f7c2011-09-30 15:55:18 -06002421 unsigned long ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002422
Karthikeyan Ramasubramanian4af9f7c2011-09-30 15:55:18 -06002423 if (!msm_ipc_router_workqueue) {
2424 ret = wait_for_completion_timeout(&msm_ipc_local_router_up,
2425 IPC_ROUTER_INIT_TIMEOUT);
2426 if (!ret || !msm_ipc_router_workqueue) {
2427 pr_err("%s: IPC Router not initialized\n", __func__);
2428 return;
2429 }
2430 }
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002431
2432 switch (event) {
2433 case IPC_ROUTER_XPRT_EVENT_OPEN:
2434 D("open event for '%s'\n", xprt->name);
2435 xprt_work = kmalloc(sizeof(struct msm_ipc_router_xprt_work),
2436 GFP_ATOMIC);
2437 xprt_work->xprt = xprt;
2438 INIT_WORK(&xprt_work->work, xprt_open_worker);
2439 queue_work(msm_ipc_router_workqueue, &xprt_work->work);
2440 break;
2441
2442 case IPC_ROUTER_XPRT_EVENT_CLOSE:
2443 D("close event for '%s'\n", xprt->name);
2444 atomic_inc(&pending_close_count);
2445 xprt_work = kmalloc(sizeof(struct msm_ipc_router_xprt_work),
2446 GFP_ATOMIC);
2447 xprt_work->xprt = xprt;
2448 INIT_WORK(&xprt_work->work, xprt_close_worker);
2449 queue_work(msm_ipc_router_workqueue, &xprt_work->work);
2450 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002451 }
2452
2453 if (!data)
2454 return;
2455
2456 while (!xprt_info) {
2457 msleep(100);
2458 xprt_info = xprt->priv;
2459 }
2460
2461 pkt = clone_pkt((struct rr_packet *)data);
2462 if (!pkt)
2463 return;
2464
2465 mutex_lock(&xprt_info->rx_lock);
2466 list_add_tail(&pkt->list, &xprt_info->pkt_list);
2467 wake_lock(&xprt_info->wakelock);
2468 wake_up(&xprt_info->read_wait);
2469 mutex_unlock(&xprt_info->rx_lock);
2470}
2471
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002472static int modem_restart_notifier_cb(struct notifier_block *this,
2473 unsigned long code,
2474 void *data);
2475static struct notifier_block msm_ipc_router_nb = {
2476 .notifier_call = modem_restart_notifier_cb,
2477};
2478
2479static int modem_restart_notifier_cb(struct notifier_block *this,
2480 unsigned long code,
2481 void *data)
2482{
2483 switch (code) {
2484 case SUBSYS_BEFORE_SHUTDOWN:
2485 D("%s: SUBSYS_BEFORE_SHUTDOWN\n", __func__);
2486 break;
2487
2488 case SUBSYS_BEFORE_POWERUP:
2489 D("%s: waiting for RPC restart to complete\n", __func__);
2490 wait_event(subsystem_restart_wait,
2491 atomic_read(&pending_close_count) == 0);
2492 D("%s: finished restart wait\n", __func__);
2493 break;
2494
2495 default:
2496 break;
2497 }
2498
2499 return NOTIFY_DONE;
2500}
2501
2502static void *restart_notifier_handle;
2503static __init int msm_ipc_router_modem_restart_late_init(void)
2504{
2505 restart_notifier_handle = subsys_notif_register_notifier("modem",
2506 &msm_ipc_router_nb);
2507 return 0;
2508}
2509late_initcall(msm_ipc_router_modem_restart_late_init);
2510
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002511static int __init msm_ipc_router_init(void)
2512{
2513 int i, ret;
2514 struct msm_ipc_routing_table_entry *rt_entry;
2515
2516 msm_ipc_router_debug_mask |= SMEM_LOG;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002517 msm_ipc_router_workqueue =
2518 create_singlethread_workqueue("msm_ipc_router");
2519 if (!msm_ipc_router_workqueue)
2520 return -ENOMEM;
2521
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002522 debugfs_init();
2523
2524 for (i = 0; i < SRV_HASH_SIZE; i++)
2525 INIT_LIST_HEAD(&server_list[i]);
2526
2527 for (i = 0; i < LP_HASH_SIZE; i++)
2528 INIT_LIST_HEAD(&local_ports[i]);
2529
2530 mutex_lock(&routing_table_lock);
2531 if (!routing_table_inited) {
2532 init_routing_table();
2533 rt_entry = alloc_routing_table_entry(IPC_ROUTER_NID_LOCAL);
2534 add_routing_table_entry(rt_entry);
2535 routing_table_inited = 1;
2536 }
2537 mutex_unlock(&routing_table_lock);
2538
2539 init_waitqueue_head(&newserver_wait);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002540 init_waitqueue_head(&subsystem_restart_wait);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002541 ret = msm_ipc_router_init_sockets();
2542 if (ret < 0)
2543 pr_err("%s: Init sockets failed\n", __func__);
2544
Karthikeyan Ramasubramanian4af9f7c2011-09-30 15:55:18 -06002545 complete_all(&msm_ipc_local_router_up);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002546 return ret;
2547}
2548
2549module_init(msm_ipc_router_init);
2550MODULE_DESCRIPTION("MSM IPC Router");
2551MODULE_LICENSE("GPL v2");