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