blob: 45ca5e4c1cb1bc2aa8a73acb1b65abad79d2bb0d [file] [log] [blame]
Karthikeyan Ramasubramanian5c568fb2013-01-10 17:09:13 -07001/* Copyright (c) 2011-2013, 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>
Karthikeyan Ramasubramanianefc493b2012-07-12 10:25:49 -060036#include <mach/msm_ipc_router.h>
Karthikeyan Ramasubramanian2bfe8ec2013-03-22 10:47:20 -060037#include <mach/msm_ipc_logging.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070038
39#include "ipc_router.h"
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -060040#include "modem_notifier.h"
Karthikeyan Ramasubramanian5b502d3642012-09-23 22:23:36 -060041#include "msm_ipc_router_security.h"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070042
43enum {
44 SMEM_LOG = 1U << 0,
45 RTR_DBG = 1U << 1,
46 R2R_MSG = 1U << 2,
47 R2R_RAW = 1U << 3,
48 NTFY_MSG = 1U << 4,
49 R2R_RAW_HDR = 1U << 5,
50};
51
52static int msm_ipc_router_debug_mask;
53module_param_named(debug_mask, msm_ipc_router_debug_mask,
54 int, S_IRUGO | S_IWUSR | S_IWGRP);
55
Karthikeyan Ramasubramanian2bfe8ec2013-03-22 10:47:20 -060056static void *ipc_rtr_log_ctxt;
57#define IPC_RTR_LOG_PAGES 5
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070058#define DIAG(x...) pr_info("[RR] ERROR " x)
59
60#if defined(DEBUG)
61#define D(x...) do { \
Karthikeyan Ramasubramanian2bfe8ec2013-03-22 10:47:20 -060062if (ipc_rtr_log_ctxt) \
63 ipc_log_string(ipc_rtr_log_ctxt, x); \
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070064if (msm_ipc_router_debug_mask & RTR_DBG) \
65 pr_info(x); \
66} while (0)
67
68#define RR(x...) do { \
Karthikeyan Ramasubramanian2bfe8ec2013-03-22 10:47:20 -060069if (ipc_rtr_log_ctxt) \
70 ipc_log_string(ipc_rtr_log_ctxt, x); \
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070071if (msm_ipc_router_debug_mask & R2R_MSG) \
72 pr_info("[RR] "x); \
73} while (0)
74
75#define RAW(x...) do { \
76if (msm_ipc_router_debug_mask & R2R_RAW) \
77 pr_info("[RAW] "x); \
78} while (0)
79
80#define NTFY(x...) do { \
81if (msm_ipc_router_debug_mask & NTFY_MSG) \
82 pr_info("[NOTIFY] "x); \
83} while (0)
84
85#define RAW_HDR(x...) do { \
86if (msm_ipc_router_debug_mask & R2R_RAW_HDR) \
87 pr_info("[HDR] "x); \
88} while (0)
89#else
90#define D(x...) do { } while (0)
91#define RR(x...) do { } while (0)
92#define RAW(x...) do { } while (0)
93#define RAW_HDR(x...) do { } while (0)
94#define NTFY(x...) do { } while (0)
95#endif
96
97#define IPC_ROUTER_LOG_EVENT_ERROR 0x10
98#define IPC_ROUTER_LOG_EVENT_TX 0x11
99#define IPC_ROUTER_LOG_EVENT_RX 0x12
100
101static LIST_HEAD(control_ports);
102static DEFINE_MUTEX(control_ports_lock);
103
104#define LP_HASH_SIZE 32
105static struct list_head local_ports[LP_HASH_SIZE];
106static DEFINE_MUTEX(local_ports_lock);
107
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -0600108/*
109 * Server info is organized as a hash table. The server's service ID is
110 * used to index into the hash table. The instance ID of most of the servers
111 * are 1 or 2. The service IDs are well distributed compared to the instance
112 * IDs and hence choosing service ID to index into this hash table optimizes
113 * the hash table operations like add, lookup, destroy.
114 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700115#define SRV_HASH_SIZE 32
116static struct list_head server_list[SRV_HASH_SIZE];
117static DEFINE_MUTEX(server_list_lock);
118static wait_queue_head_t newserver_wait;
119
120struct msm_ipc_server {
121 struct list_head list;
122 struct msm_ipc_port_name name;
Karthikeyan Ramasubramanianefc493b2012-07-12 10:25:49 -0600123 char pdev_name[32];
124 int next_pdev_id;
Karthikeyan Ramasubramanian5b502d3642012-09-23 22:23:36 -0600125 int synced_sec_rule;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700126 struct list_head server_port_list;
127};
128
129struct msm_ipc_server_port {
130 struct list_head list;
Karthikeyan Ramasubramanianefc493b2012-07-12 10:25:49 -0600131 struct platform_device pdev;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700132 struct msm_ipc_port_addr server_addr;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600133 struct msm_ipc_router_xprt_info *xprt_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700134};
135
Zaheerulla Meere3f6c3a2013-04-17 01:16:47 +0530136struct msm_ipc_resume_tx_port {
137 struct list_head list;
138 uint32_t port_id;
139 uint32_t node_id;
140};
141
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700142#define RP_HASH_SIZE 32
143struct msm_ipc_router_remote_port {
144 struct list_head list;
145 uint32_t node_id;
146 uint32_t port_id;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600147 uint32_t restart_state;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700148 uint32_t tx_quota_cnt;
149 struct mutex quota_lock;
Zaheerulla Meere3f6c3a2013-04-17 01:16:47 +0530150 struct list_head resume_tx_port_list;
Karthikeyan Ramasubramanian5b502d3642012-09-23 22:23:36 -0600151 void *sec_rule;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700152};
153
154struct msm_ipc_router_xprt_info {
155 struct list_head list;
156 struct msm_ipc_router_xprt *xprt;
157 uint32_t remote_node_id;
158 uint32_t initialized;
159 struct list_head pkt_list;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700160 struct wake_lock wakelock;
161 struct mutex rx_lock;
162 struct mutex tx_lock;
163 uint32_t need_len;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600164 uint32_t abort_data_read;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700165 struct work_struct read_data;
166 struct workqueue_struct *workqueue;
167};
168
169#define RT_HASH_SIZE 4
170struct msm_ipc_routing_table_entry {
171 struct list_head list;
172 uint32_t node_id;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600173 uint32_t neighbor_node_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700174 struct list_head remote_port_list[RP_HASH_SIZE];
175 struct msm_ipc_router_xprt_info *xprt_info;
176 struct mutex lock;
177 unsigned long num_tx_bytes;
178 unsigned long num_rx_bytes;
179};
180
181static struct list_head routing_table[RT_HASH_SIZE];
182static DEFINE_MUTEX(routing_table_lock);
183static int routing_table_inited;
184
185static LIST_HEAD(msm_ipc_board_dev_list);
186static DEFINE_MUTEX(msm_ipc_board_dev_list_lock);
187
188static void do_read_data(struct work_struct *work);
189
190#define RR_STATE_IDLE 0
191#define RR_STATE_HEADER 1
192#define RR_STATE_BODY 2
193#define RR_STATE_ERROR 3
194
195#define RESTART_NORMAL 0
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600196#define RESTART_PEND 1
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700197
198/* State for remote ep following restart */
199#define RESTART_QUOTA_ABORT 1
200
201static LIST_HEAD(xprt_info_list);
202static DEFINE_MUTEX(xprt_info_list_lock);
203
Karthikeyan Ramasubramanian4af9f7c2011-09-30 15:55:18 -0600204static DECLARE_COMPLETION(msm_ipc_local_router_up);
205#define IPC_ROUTER_INIT_TIMEOUT (10 * HZ)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700206
207static uint32_t next_port_id;
208static DEFINE_MUTEX(next_port_id_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600209static atomic_t pending_close_count = ATOMIC_INIT(0);
210static wait_queue_head_t subsystem_restart_wait;
211static struct workqueue_struct *msm_ipc_router_workqueue;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700212
213enum {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700214 DOWN,
215 UP,
216};
217
218static void init_routing_table(void)
219{
220 int i;
221 for (i = 0; i < RT_HASH_SIZE; i++)
222 INIT_LIST_HEAD(&routing_table[i]);
223}
224
225static struct msm_ipc_routing_table_entry *alloc_routing_table_entry(
226 uint32_t node_id)
227{
228 int i;
229 struct msm_ipc_routing_table_entry *rt_entry;
230
231 rt_entry = kmalloc(sizeof(struct msm_ipc_routing_table_entry),
232 GFP_KERNEL);
233 if (!rt_entry) {
234 pr_err("%s: rt_entry allocation failed for %d\n",
235 __func__, node_id);
236 return NULL;
237 }
238
239 for (i = 0; i < RP_HASH_SIZE; i++)
240 INIT_LIST_HEAD(&rt_entry->remote_port_list[i]);
241
242 mutex_init(&rt_entry->lock);
243 rt_entry->node_id = node_id;
244 rt_entry->xprt_info = NULL;
245 return rt_entry;
246}
247
248/*Please take routing_table_lock before calling this function*/
249static int add_routing_table_entry(
250 struct msm_ipc_routing_table_entry *rt_entry)
251{
252 uint32_t key;
253
254 if (!rt_entry)
255 return -EINVAL;
256
257 key = (rt_entry->node_id % RT_HASH_SIZE);
258 list_add_tail(&rt_entry->list, &routing_table[key]);
259 return 0;
260}
261
262/*Please take routing_table_lock before calling this function*/
263static struct msm_ipc_routing_table_entry *lookup_routing_table(
264 uint32_t node_id)
265{
266 uint32_t key = (node_id % RT_HASH_SIZE);
267 struct msm_ipc_routing_table_entry *rt_entry;
268
269 list_for_each_entry(rt_entry, &routing_table[key], list) {
270 if (rt_entry->node_id == node_id)
271 return rt_entry;
272 }
273 return NULL;
274}
275
276struct rr_packet *rr_read(struct msm_ipc_router_xprt_info *xprt_info)
277{
278 struct rr_packet *temp_pkt;
279
280 if (!xprt_info)
281 return NULL;
282
283 mutex_lock(&xprt_info->rx_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600284 if (xprt_info->abort_data_read) {
285 mutex_unlock(&xprt_info->rx_lock);
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -0600286 pr_err("%s detected SSR & exiting now\n",
287 xprt_info->xprt->name);
288 return NULL;
289 }
290
291 if (list_empty(&xprt_info->pkt_list)) {
292 mutex_unlock(&xprt_info->rx_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600293 return NULL;
294 }
295
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700296 temp_pkt = list_first_entry(&xprt_info->pkt_list,
297 struct rr_packet, list);
298 list_del(&temp_pkt->list);
299 if (list_empty(&xprt_info->pkt_list))
300 wake_unlock(&xprt_info->wakelock);
301 mutex_unlock(&xprt_info->rx_lock);
302 return temp_pkt;
303}
304
305struct rr_packet *clone_pkt(struct rr_packet *pkt)
306{
307 struct rr_packet *cloned_pkt;
308 struct sk_buff *temp_skb, *cloned_skb;
309 struct sk_buff_head *pkt_fragment_q;
310
311 cloned_pkt = kzalloc(sizeof(struct rr_packet), GFP_KERNEL);
312 if (!cloned_pkt) {
313 pr_err("%s: failure\n", __func__);
314 return NULL;
315 }
316
317 pkt_fragment_q = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
318 if (!pkt_fragment_q) {
319 pr_err("%s: pkt_frag_q alloc failure\n", __func__);
320 kfree(cloned_pkt);
321 return NULL;
322 }
323 skb_queue_head_init(pkt_fragment_q);
324
325 skb_queue_walk(pkt->pkt_fragment_q, temp_skb) {
326 cloned_skb = skb_clone(temp_skb, GFP_KERNEL);
327 if (!cloned_skb)
328 goto fail_clone;
329 skb_queue_tail(pkt_fragment_q, cloned_skb);
330 }
331 cloned_pkt->pkt_fragment_q = pkt_fragment_q;
332 cloned_pkt->length = pkt->length;
333 return cloned_pkt;
334
335fail_clone:
336 while (!skb_queue_empty(pkt_fragment_q)) {
337 temp_skb = skb_dequeue(pkt_fragment_q);
338 kfree_skb(temp_skb);
339 }
340 kfree(pkt_fragment_q);
341 kfree(cloned_pkt);
342 return NULL;
343}
344
345struct rr_packet *create_pkt(struct sk_buff_head *data)
346{
347 struct rr_packet *pkt;
348 struct sk_buff *temp_skb;
349
350 pkt = kzalloc(sizeof(struct rr_packet), GFP_KERNEL);
351 if (!pkt) {
352 pr_err("%s: failure\n", __func__);
353 return NULL;
354 }
355
356 pkt->pkt_fragment_q = data;
357 skb_queue_walk(pkt->pkt_fragment_q, temp_skb)
358 pkt->length += temp_skb->len;
359 return pkt;
360}
361
362void release_pkt(struct rr_packet *pkt)
363{
364 struct sk_buff *temp_skb;
365
366 if (!pkt)
367 return;
368
369 if (!pkt->pkt_fragment_q) {
370 kfree(pkt);
371 return;
372 }
373
374 while (!skb_queue_empty(pkt->pkt_fragment_q)) {
375 temp_skb = skb_dequeue(pkt->pkt_fragment_q);
376 kfree_skb(temp_skb);
377 }
378 kfree(pkt->pkt_fragment_q);
379 kfree(pkt);
380 return;
381}
382
Karthikeyan Ramasubramanianefc493b2012-07-12 10:25:49 -0600383static struct sk_buff_head *msm_ipc_router_buf_to_skb(void *buf,
384 unsigned int buf_len)
385{
386 struct sk_buff_head *skb_head;
387 struct sk_buff *skb;
388 int first = 1, offset = 0;
389 int skb_size, data_size;
390 void *data;
391
392 skb_head = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
393 if (!skb_head) {
394 pr_err("%s: Couldnot allocate skb_head\n", __func__);
395 return NULL;
396 }
397 skb_queue_head_init(skb_head);
398
399 data_size = buf_len;
400 while (offset != buf_len) {
401 skb_size = data_size;
402 if (first)
403 skb_size += IPC_ROUTER_HDR_SIZE;
404
405 skb = alloc_skb(skb_size, GFP_KERNEL);
406 if (!skb) {
407 if (skb_size <= (PAGE_SIZE/2)) {
408 pr_err("%s: cannot allocate skb\n", __func__);
409 goto buf_to_skb_error;
410 }
411 data_size = data_size / 2;
412 continue;
413 }
414
415 if (first) {
416 skb_reserve(skb, IPC_ROUTER_HDR_SIZE);
417 first = 0;
418 }
419
420 data = skb_put(skb, data_size);
421 memcpy(skb->data, buf + offset, data_size);
422 skb_queue_tail(skb_head, skb);
423 offset += data_size;
424 data_size = buf_len - offset;
425 }
426 return skb_head;
427
428buf_to_skb_error:
429 while (!skb_queue_empty(skb_head)) {
430 skb = skb_dequeue(skb_head);
431 kfree_skb(skb);
432 }
433 kfree(skb_head);
434 return NULL;
435}
436
437static void *msm_ipc_router_skb_to_buf(struct sk_buff_head *skb_head,
438 unsigned int len)
439{
440 struct sk_buff *temp;
441 int offset = 0, buf_len = 0, copy_len;
442 void *buf;
443
444 if (!skb_head) {
445 pr_err("%s: NULL skb_head\n", __func__);
446 return NULL;
447 }
448
449 temp = skb_peek(skb_head);
450 buf_len = len;
451 buf = kmalloc(buf_len, GFP_KERNEL);
452 if (!buf) {
453 pr_err("%s: cannot allocate buf\n", __func__);
454 return NULL;
455 }
456 skb_queue_walk(skb_head, temp) {
457 copy_len = buf_len < temp->len ? buf_len : temp->len;
458 memcpy(buf + offset, temp->data, copy_len);
459 offset += copy_len;
460 buf_len -= copy_len;
461 }
462 return buf;
463}
464
465static void msm_ipc_router_free_skb(struct sk_buff_head *skb_head)
466{
467 struct sk_buff *temp_skb;
468
469 if (!skb_head)
470 return;
471
472 while (!skb_queue_empty(skb_head)) {
473 temp_skb = skb_dequeue(skb_head);
474 kfree_skb(temp_skb);
475 }
476 kfree(skb_head);
477}
478
Karthikeyan Ramasubramanian6dbb00f2013-05-17 15:19:56 -0600479static int post_pkt_to_port(struct msm_ipc_port *port_ptr,
480 struct rr_packet *pkt, int clone)
481{
482 struct rr_packet *temp_pkt = pkt;
483
484 if (unlikely(!port_ptr || !pkt))
485 return -EINVAL;
486
487 if (clone) {
488 temp_pkt = clone_pkt(pkt);
489 if (!temp_pkt) {
490 pr_err("%s: Error cloning packet for port %08x:%08x\n",
491 __func__, port_ptr->this_port.node_id,
492 port_ptr->this_port.port_id);
493 return -ENOMEM;
494 }
495 }
496
497 mutex_lock(&port_ptr->port_rx_q_lock);
498 wake_lock(&port_ptr->port_rx_wake_lock);
499 list_add_tail(&temp_pkt->list, &port_ptr->port_rx_q);
500 wake_up(&port_ptr->port_rx_wait_q);
501 if (port_ptr->notify)
502 port_ptr->notify(MSM_IPC_ROUTER_READ_CB, port_ptr->priv);
503 mutex_unlock(&port_ptr->port_rx_q_lock);
504 return 0;
505}
506
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700507static int post_control_ports(struct rr_packet *pkt)
508{
509 struct msm_ipc_port *port_ptr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700510
511 if (!pkt)
512 return -EINVAL;
513
514 mutex_lock(&control_ports_lock);
Karthikeyan Ramasubramanian6dbb00f2013-05-17 15:19:56 -0600515 list_for_each_entry(port_ptr, &control_ports, list)
516 post_pkt_to_port(port_ptr, pkt, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700517 mutex_unlock(&control_ports_lock);
518 return 0;
519}
520
521static uint32_t allocate_port_id(void)
522{
523 uint32_t port_id = 0, prev_port_id, key;
524 struct msm_ipc_port *port_ptr;
525
526 mutex_lock(&next_port_id_lock);
527 prev_port_id = next_port_id;
528 mutex_lock(&local_ports_lock);
529 do {
530 next_port_id++;
531 if ((next_port_id & 0xFFFFFFFE) == 0xFFFFFFFE)
532 next_port_id = 1;
533
534 key = (next_port_id & (LP_HASH_SIZE - 1));
535 if (list_empty(&local_ports[key])) {
536 port_id = next_port_id;
537 break;
538 }
539 list_for_each_entry(port_ptr, &local_ports[key], list) {
540 if (port_ptr->this_port.port_id == next_port_id) {
541 port_id = next_port_id;
542 break;
543 }
544 }
545 if (!port_id) {
546 port_id = next_port_id;
547 break;
548 }
549 port_id = 0;
550 } while (next_port_id != prev_port_id);
551 mutex_unlock(&local_ports_lock);
552 mutex_unlock(&next_port_id_lock);
553
554 return port_id;
555}
556
557void msm_ipc_router_add_local_port(struct msm_ipc_port *port_ptr)
558{
559 uint32_t key;
560
561 if (!port_ptr)
562 return;
563
564 key = (port_ptr->this_port.port_id & (LP_HASH_SIZE - 1));
565 mutex_lock(&local_ports_lock);
566 list_add_tail(&port_ptr->list, &local_ports[key]);
567 mutex_unlock(&local_ports_lock);
568}
569
570struct msm_ipc_port *msm_ipc_router_create_raw_port(void *endpoint,
Karthikeyan Ramasubramanianefc493b2012-07-12 10:25:49 -0600571 void (*notify)(unsigned event, void *priv),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700572 void *priv)
573{
574 struct msm_ipc_port *port_ptr;
575
576 port_ptr = kzalloc(sizeof(struct msm_ipc_port), GFP_KERNEL);
577 if (!port_ptr)
578 return NULL;
579
580 port_ptr->this_port.node_id = IPC_ROUTER_NID_LOCAL;
581 port_ptr->this_port.port_id = allocate_port_id();
582 if (!port_ptr->this_port.port_id) {
583 pr_err("%s: All port ids are in use\n", __func__);
584 kfree(port_ptr);
585 return NULL;
586 }
587
588 spin_lock_init(&port_ptr->port_lock);
589 INIT_LIST_HEAD(&port_ptr->incomplete);
590 mutex_init(&port_ptr->incomplete_lock);
591 INIT_LIST_HEAD(&port_ptr->port_rx_q);
592 mutex_init(&port_ptr->port_rx_q_lock);
593 init_waitqueue_head(&port_ptr->port_rx_wait_q);
Karthikeyan Ramasubramanianb4aeeb92012-03-13 12:31:43 -0600594 snprintf(port_ptr->rx_wakelock_name, MAX_WAKELOCK_NAME_SZ,
Karthikeyan Ramasubramanian6396bdd2013-02-14 13:53:20 -0700595 "ipc%08x_%s",
596 port_ptr->this_port.port_id,
597 current->comm);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700598 wake_lock_init(&port_ptr->port_rx_wake_lock,
Karthikeyan Ramasubramanianb4aeeb92012-03-13 12:31:43 -0600599 WAKE_LOCK_SUSPEND, port_ptr->rx_wakelock_name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700600
601 port_ptr->endpoint = endpoint;
602 port_ptr->notify = notify;
603 port_ptr->priv = priv;
604
605 msm_ipc_router_add_local_port(port_ptr);
606 return port_ptr;
607}
608
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -0600609/*
610 * Should be called with local_ports_lock locked
611 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700612static struct msm_ipc_port *msm_ipc_router_lookup_local_port(uint32_t port_id)
613{
614 int key = (port_id & (LP_HASH_SIZE - 1));
615 struct msm_ipc_port *port_ptr;
616
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700617 list_for_each_entry(port_ptr, &local_ports[key], list) {
618 if (port_ptr->this_port.port_id == port_id) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700619 return port_ptr;
620 }
621 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700622 return NULL;
623}
624
625static struct msm_ipc_router_remote_port *msm_ipc_router_lookup_remote_port(
626 uint32_t node_id,
627 uint32_t port_id)
628{
629 struct msm_ipc_router_remote_port *rport_ptr;
630 struct msm_ipc_routing_table_entry *rt_entry;
631 int key = (port_id & (RP_HASH_SIZE - 1));
632
633 mutex_lock(&routing_table_lock);
634 rt_entry = lookup_routing_table(node_id);
635 if (!rt_entry) {
636 mutex_unlock(&routing_table_lock);
637 pr_err("%s: Node is not up\n", __func__);
638 return NULL;
639 }
640
641 mutex_lock(&rt_entry->lock);
642 list_for_each_entry(rport_ptr,
643 &rt_entry->remote_port_list[key], list) {
644 if (rport_ptr->port_id == port_id) {
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600645 if (rport_ptr->restart_state != RESTART_NORMAL)
646 rport_ptr = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700647 mutex_unlock(&rt_entry->lock);
648 mutex_unlock(&routing_table_lock);
649 return rport_ptr;
650 }
651 }
652 mutex_unlock(&rt_entry->lock);
653 mutex_unlock(&routing_table_lock);
654 return NULL;
655}
656
657static struct msm_ipc_router_remote_port *msm_ipc_router_create_remote_port(
658 uint32_t node_id,
659 uint32_t port_id)
660{
661 struct msm_ipc_router_remote_port *rport_ptr;
662 struct msm_ipc_routing_table_entry *rt_entry;
663 int key = (port_id & (RP_HASH_SIZE - 1));
664
665 mutex_lock(&routing_table_lock);
666 rt_entry = lookup_routing_table(node_id);
667 if (!rt_entry) {
668 mutex_unlock(&routing_table_lock);
669 pr_err("%s: Node is not up\n", __func__);
670 return NULL;
671 }
672
673 mutex_lock(&rt_entry->lock);
674 rport_ptr = kmalloc(sizeof(struct msm_ipc_router_remote_port),
675 GFP_KERNEL);
676 if (!rport_ptr) {
677 mutex_unlock(&rt_entry->lock);
678 mutex_unlock(&routing_table_lock);
679 pr_err("%s: Remote port alloc failed\n", __func__);
680 return NULL;
681 }
682 rport_ptr->port_id = port_id;
683 rport_ptr->node_id = node_id;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600684 rport_ptr->restart_state = RESTART_NORMAL;
Karthikeyan Ramasubramanian5b502d3642012-09-23 22:23:36 -0600685 rport_ptr->sec_rule = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700686 rport_ptr->tx_quota_cnt = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700687 mutex_init(&rport_ptr->quota_lock);
Zaheerulla Meere3f6c3a2013-04-17 01:16:47 +0530688 INIT_LIST_HEAD(&rport_ptr->resume_tx_port_list);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700689 list_add_tail(&rport_ptr->list,
690 &rt_entry->remote_port_list[key]);
691 mutex_unlock(&rt_entry->lock);
692 mutex_unlock(&routing_table_lock);
693 return rport_ptr;
694}
695
Zaheerulla Meere3f6c3a2013-04-17 01:16:47 +0530696/**
697 * msm_ipc_router_free_resume_tx_port() - Free the resume_tx ports
698 * @rport_ptr: Pointer to the remote port.
699 *
700 * This function deletes all the resume_tx ports associated with a remote port
701 * and frees the memory allocated to each resume_tx port.
702 *
703 * Must be called with rport_ptr->quota_lock locked.
704 */
705static void msm_ipc_router_free_resume_tx_port(
706 struct msm_ipc_router_remote_port *rport_ptr)
707{
708 struct msm_ipc_resume_tx_port *rtx_port, *tmp_rtx_port;
709
710 list_for_each_entry_safe(rtx_port, tmp_rtx_port,
711 &rport_ptr->resume_tx_port_list, list) {
712 list_del(&rtx_port->list);
713 kfree(rtx_port);
714 }
715}
716
717/**
718 * msm_ipc_router_lookup_resume_tx_port() - Lookup resume_tx port list
719 * @rport_ptr: Remote port whose resume_tx port list needs to be looked.
720 * @port_id: Port ID which needs to be looked from the list.
721 *
722 * return 1 if the port_id is found in the list, else 0.
723 *
724 * This function is used to lookup the existence of a local port in
725 * remote port's resume_tx list. This function is used to ensure that
726 * the same port is not added to the remote_port's resume_tx list repeatedly.
727 *
728 * Must be called with rport_ptr->quota_lock locked.
729 */
730static int msm_ipc_router_lookup_resume_tx_port(
731 struct msm_ipc_router_remote_port *rport_ptr, uint32_t port_id)
732{
733 struct msm_ipc_resume_tx_port *rtx_port;
734
735 list_for_each_entry(rtx_port, &rport_ptr->resume_tx_port_list, list) {
736 if (port_id == rtx_port->port_id)
737 return 1;
738 }
739 return 0;
740}
741
742/**
743 * post_resume_tx() - Post the resume_tx event
744 * @rport_ptr: Pointer to the remote port
745 * @pkt : The data packet that is received on a resume_tx event
746 *
747 * This function informs about the reception of the resume_tx message from a
748 * remote port pointed by rport_ptr to all the local ports that are in the
749 * resume_tx_ports_list of this remote port. On posting the information, this
750 * function sequentially deletes each entry in the resume_tx_port_list of the
751 * remote port.
752 *
753 * Must be called with rport_ptr->quota_lock locked.
754 */
755static void post_resume_tx(struct msm_ipc_router_remote_port *rport_ptr,
756 struct rr_packet *pkt)
757{
758 struct msm_ipc_resume_tx_port *rtx_port, *tmp_rtx_port;
759 struct msm_ipc_port *local_port;
Zaheerulla Meere3f6c3a2013-04-17 01:16:47 +0530760
761 list_for_each_entry_safe(rtx_port, tmp_rtx_port,
762 &rport_ptr->resume_tx_port_list, list) {
763 mutex_lock(&local_ports_lock);
764 local_port =
765 msm_ipc_router_lookup_local_port(rtx_port->port_id);
Karthikeyan Ramasubramanian6dbb00f2013-05-17 15:19:56 -0600766 if (local_port)
767 post_pkt_to_port(local_port, pkt, 1);
Zaheerulla Meere3f6c3a2013-04-17 01:16:47 +0530768 mutex_unlock(&local_ports_lock);
769 list_del(&rtx_port->list);
770 kfree(rtx_port);
771 }
772}
773
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700774static void msm_ipc_router_destroy_remote_port(
775 struct msm_ipc_router_remote_port *rport_ptr)
776{
777 uint32_t node_id;
778 struct msm_ipc_routing_table_entry *rt_entry;
779
780 if (!rport_ptr)
781 return;
782
783 node_id = rport_ptr->node_id;
784 mutex_lock(&routing_table_lock);
785 rt_entry = lookup_routing_table(node_id);
786 if (!rt_entry) {
787 mutex_unlock(&routing_table_lock);
788 pr_err("%s: Node %d is not up\n", __func__, node_id);
789 return;
790 }
Zaheerulla Meere3f6c3a2013-04-17 01:16:47 +0530791 mutex_lock(&rport_ptr->quota_lock);
792 msm_ipc_router_free_resume_tx_port(rport_ptr);
793 mutex_unlock(&rport_ptr->quota_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700794 mutex_lock(&rt_entry->lock);
795 list_del(&rport_ptr->list);
796 kfree(rport_ptr);
797 mutex_unlock(&rt_entry->lock);
798 mutex_unlock(&routing_table_lock);
799 return;
800}
801
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -0600802/**
803 * msm_ipc_router_lookup_server() - Lookup server information
804 * @service: Service ID of the server info to be looked up.
805 * @instance: Instance ID of the server info to be looked up.
806 * @node_id: Node/Processor ID in which the server is hosted.
807 * @port_id: Port ID within the node in which the server is hosted.
808 *
809 * @return: If found Pointer to server structure, else NULL.
810 *
811 * Note1: Lock the server_list_lock before accessing this function.
812 * Note2: If the <node_id:port_id> are <0:0>, then the lookup is restricted
813 * to <service:instance>. Used only when a client wants to send a
814 * message to any QMI server.
815 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700816static struct msm_ipc_server *msm_ipc_router_lookup_server(
817 uint32_t service,
818 uint32_t instance,
819 uint32_t node_id,
820 uint32_t port_id)
821{
822 struct msm_ipc_server *server;
823 struct msm_ipc_server_port *server_port;
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -0600824 int key = (service & (SRV_HASH_SIZE - 1));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700825
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700826 list_for_each_entry(server, &server_list[key], list) {
827 if ((server->name.service != service) ||
828 (server->name.instance != instance))
829 continue;
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -0600830 if ((node_id == 0) && (port_id == 0))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700831 return server;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700832 list_for_each_entry(server_port, &server->server_port_list,
833 list) {
834 if ((server_port->server_addr.node_id == node_id) &&
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -0600835 (server_port->server_addr.port_id == port_id))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700836 return server;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700837 }
838 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700839 return NULL;
840}
841
Karthikeyan Ramasubramanianefc493b2012-07-12 10:25:49 -0600842static void dummy_release(struct device *dev)
843{
844}
845
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -0600846/**
847 * msm_ipc_router_create_server() - Add server info to hash table
848 * @service: Service ID of the server info to be created.
849 * @instance: Instance ID of the server info to be created.
850 * @node_id: Node/Processor ID in which the server is hosted.
851 * @port_id: Port ID within the node in which the server is hosted.
852 * @xprt_info: XPRT through which the node hosting the server is reached.
853 *
854 * @return: Pointer to server structure on success, else NULL.
855 *
856 * This function adds the server info to the hash table. If the same
857 * server(i.e. <service_id:instance_id>) is hosted in different nodes,
858 * they are maintained as list of "server_port" under "server" structure.
859 * Note: Lock the server_list_lock before accessing this function.
860 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700861static struct msm_ipc_server *msm_ipc_router_create_server(
862 uint32_t service,
863 uint32_t instance,
864 uint32_t node_id,
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600865 uint32_t port_id,
866 struct msm_ipc_router_xprt_info *xprt_info)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700867{
868 struct msm_ipc_server *server = NULL;
869 struct msm_ipc_server_port *server_port;
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -0600870 int key = (service & (SRV_HASH_SIZE - 1));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700871
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700872 list_for_each_entry(server, &server_list[key], list) {
873 if ((server->name.service == service) &&
874 (server->name.instance == instance))
875 goto create_srv_port;
876 }
877
Karthikeyan Ramasubramanianefc493b2012-07-12 10:25:49 -0600878 server = kzalloc(sizeof(struct msm_ipc_server), GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700879 if (!server) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700880 pr_err("%s: Server allocation failed\n", __func__);
881 return NULL;
882 }
883 server->name.service = service;
884 server->name.instance = instance;
Karthikeyan Ramasubramanian5b502d3642012-09-23 22:23:36 -0600885 server->synced_sec_rule = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700886 INIT_LIST_HEAD(&server->server_port_list);
887 list_add_tail(&server->list, &server_list[key]);
Karthikeyan Ramasubramanianefc493b2012-07-12 10:25:49 -0600888 scnprintf(server->pdev_name, sizeof(server->pdev_name),
889 "QMI%08x:%08x", service, instance);
890 server->next_pdev_id = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700891
892create_srv_port:
Karthikeyan Ramasubramanianefc493b2012-07-12 10:25:49 -0600893 server_port = kzalloc(sizeof(struct msm_ipc_server_port), GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700894 if (!server_port) {
895 if (list_empty(&server->server_port_list)) {
896 list_del(&server->list);
897 kfree(server);
898 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700899 pr_err("%s: Server Port allocation failed\n", __func__);
900 return NULL;
901 }
902 server_port->server_addr.node_id = node_id;
903 server_port->server_addr.port_id = port_id;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600904 server_port->xprt_info = xprt_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700905 list_add_tail(&server_port->list, &server->server_port_list);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700906
Karthikeyan Ramasubramanianefc493b2012-07-12 10:25:49 -0600907 server_port->pdev.name = server->pdev_name;
908 server_port->pdev.id = server->next_pdev_id++;
909 server_port->pdev.dev.release = dummy_release;
910 platform_device_register(&server_port->pdev);
911
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700912 return server;
913}
914
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -0600915/**
916 * msm_ipc_router_destroy_server() - Remove server info from hash table
917 * @server: Server info to be removed.
918 * @node_id: Node/Processor ID in which the server is hosted.
919 * @port_id: Port ID within the node in which the server is hosted.
920 *
921 * This function removes the server_port identified using <node_id:port_id>
922 * from the server structure. If the server_port list under server structure
923 * is empty after removal, then remove the server structure from the server
924 * hash table.
925 * Note: Lock the server_list_lock before accessing this function.
926 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700927static void msm_ipc_router_destroy_server(struct msm_ipc_server *server,
928 uint32_t node_id, uint32_t port_id)
929{
930 struct msm_ipc_server_port *server_port;
931
932 if (!server)
933 return;
934
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700935 list_for_each_entry(server_port, &server->server_port_list, list) {
936 if ((server_port->server_addr.node_id == node_id) &&
937 (server_port->server_addr.port_id == port_id))
938 break;
939 }
940 if (server_port) {
Karthikeyan Ramasubramanianefc493b2012-07-12 10:25:49 -0600941 platform_device_unregister(&server_port->pdev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700942 list_del(&server_port->list);
943 kfree(server_port);
944 }
945 if (list_empty(&server->server_port_list)) {
946 list_del(&server->list);
947 kfree(server);
948 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700949 return;
950}
951
952static int msm_ipc_router_send_control_msg(
953 struct msm_ipc_router_xprt_info *xprt_info,
954 union rr_control_msg *msg)
955{
956 struct rr_packet *pkt;
957 struct sk_buff *ipc_rtr_pkt;
958 struct rr_header *hdr;
959 int pkt_size;
960 void *data;
961 struct sk_buff_head *pkt_fragment_q;
962 int ret;
963
964 if (!xprt_info || ((msg->cmd != IPC_ROUTER_CTRL_CMD_HELLO) &&
965 !xprt_info->initialized)) {
966 pr_err("%s: xprt_info not initialized\n", __func__);
967 return -EINVAL;
968 }
969
970 if (xprt_info->remote_node_id == IPC_ROUTER_NID_LOCAL)
971 return 0;
972
973 pkt = kzalloc(sizeof(struct rr_packet), GFP_KERNEL);
974 if (!pkt) {
975 pr_err("%s: pkt alloc failed\n", __func__);
976 return -ENOMEM;
977 }
978
979 pkt_fragment_q = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
980 if (!pkt_fragment_q) {
981 pr_err("%s: pkt_fragment_q alloc failed\n", __func__);
982 kfree(pkt);
983 return -ENOMEM;
984 }
985 skb_queue_head_init(pkt_fragment_q);
986
987 pkt_size = IPC_ROUTER_HDR_SIZE + sizeof(*msg);
988 ipc_rtr_pkt = alloc_skb(pkt_size, GFP_KERNEL);
989 if (!ipc_rtr_pkt) {
990 pr_err("%s: ipc_rtr_pkt alloc failed\n", __func__);
991 kfree(pkt_fragment_q);
992 kfree(pkt);
993 return -ENOMEM;
994 }
995
996 skb_reserve(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
997 data = skb_put(ipc_rtr_pkt, sizeof(*msg));
998 memcpy(data, msg, sizeof(*msg));
999 hdr = (struct rr_header *)skb_push(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
1000 if (!hdr) {
1001 pr_err("%s: skb_push failed\n", __func__);
1002 kfree_skb(ipc_rtr_pkt);
1003 kfree(pkt_fragment_q);
1004 kfree(pkt);
1005 return -ENOMEM;
1006 }
1007
1008 hdr->version = IPC_ROUTER_VERSION;
1009 hdr->type = msg->cmd;
1010 hdr->src_node_id = IPC_ROUTER_NID_LOCAL;
1011 hdr->src_port_id = IPC_ROUTER_ADDRESS;
1012 hdr->confirm_rx = 0;
1013 hdr->size = sizeof(*msg);
1014 hdr->dst_node_id = xprt_info->remote_node_id;
1015 hdr->dst_port_id = IPC_ROUTER_ADDRESS;
1016 skb_queue_tail(pkt_fragment_q, ipc_rtr_pkt);
1017 pkt->pkt_fragment_q = pkt_fragment_q;
1018 pkt->length = pkt_size;
1019
1020 mutex_lock(&xprt_info->tx_lock);
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -07001021 ret = xprt_info->xprt->write(pkt, pkt_size, xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001022 mutex_unlock(&xprt_info->tx_lock);
1023
1024 release_pkt(pkt);
1025 return ret;
1026}
1027
Karthikeyan Ramasubramaniana2b7fdb2012-10-23 13:12:44 -06001028static int msm_ipc_router_send_server_list(uint32_t node_id,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001029 struct msm_ipc_router_xprt_info *xprt_info)
1030{
1031 union rr_control_msg ctl;
1032 struct msm_ipc_server *server;
1033 struct msm_ipc_server_port *server_port;
1034 int i;
1035
1036 if (!xprt_info || !xprt_info->initialized) {
1037 pr_err("%s: Xprt info not initialized\n", __func__);
1038 return -EINVAL;
1039 }
1040
1041 ctl.cmd = IPC_ROUTER_CTRL_CMD_NEW_SERVER;
1042
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001043 for (i = 0; i < SRV_HASH_SIZE; i++) {
1044 list_for_each_entry(server, &server_list[i], list) {
1045 ctl.srv.service = server->name.service;
1046 ctl.srv.instance = server->name.instance;
1047 list_for_each_entry(server_port,
1048 &server->server_port_list, list) {
Karthikeyan Ramasubramaniana2b7fdb2012-10-23 13:12:44 -06001049 if (server_port->server_addr.node_id !=
1050 node_id)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001051 continue;
1052
1053 ctl.srv.node_id =
1054 server_port->server_addr.node_id;
1055 ctl.srv.port_id =
1056 server_port->server_addr.port_id;
1057 msm_ipc_router_send_control_msg(xprt_info,
1058 &ctl);
1059 }
1060 }
1061 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001062
1063 return 0;
1064}
1065
1066#if defined(DEBUG)
1067static char *type_to_str(int i)
1068{
1069 switch (i) {
1070 case IPC_ROUTER_CTRL_CMD_DATA:
1071 return "data ";
1072 case IPC_ROUTER_CTRL_CMD_HELLO:
1073 return "hello ";
1074 case IPC_ROUTER_CTRL_CMD_BYE:
1075 return "bye ";
1076 case IPC_ROUTER_CTRL_CMD_NEW_SERVER:
1077 return "new_srvr";
1078 case IPC_ROUTER_CTRL_CMD_REMOVE_SERVER:
1079 return "rmv_srvr";
1080 case IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT:
1081 return "rmv_clnt";
1082 case IPC_ROUTER_CTRL_CMD_RESUME_TX:
1083 return "resum_tx";
1084 case IPC_ROUTER_CTRL_CMD_EXIT:
1085 return "cmd_exit";
1086 default:
1087 return "invalid";
1088 }
1089}
1090#endif
1091
1092static int broadcast_ctl_msg_locally(union rr_control_msg *msg)
1093{
1094 struct rr_packet *pkt;
1095 struct sk_buff *ipc_rtr_pkt;
1096 struct rr_header *hdr;
1097 int pkt_size;
1098 void *data;
1099 struct sk_buff_head *pkt_fragment_q;
1100 int ret;
1101
1102 pkt = kzalloc(sizeof(struct rr_packet), GFP_KERNEL);
1103 if (!pkt) {
1104 pr_err("%s: pkt alloc failed\n", __func__);
1105 return -ENOMEM;
1106 }
1107
1108 pkt_fragment_q = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
1109 if (!pkt_fragment_q) {
1110 pr_err("%s: pkt_fragment_q alloc failed\n", __func__);
1111 kfree(pkt);
1112 return -ENOMEM;
1113 }
1114 skb_queue_head_init(pkt_fragment_q);
1115
1116 pkt_size = IPC_ROUTER_HDR_SIZE + sizeof(*msg);
1117 ipc_rtr_pkt = alloc_skb(pkt_size, GFP_KERNEL);
1118 if (!ipc_rtr_pkt) {
1119 pr_err("%s: ipc_rtr_pkt alloc failed\n", __func__);
1120 kfree(pkt_fragment_q);
1121 kfree(pkt);
1122 return -ENOMEM;
1123 }
1124
1125 skb_reserve(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
1126 data = skb_put(ipc_rtr_pkt, sizeof(*msg));
1127 memcpy(data, msg, sizeof(*msg));
1128 hdr = (struct rr_header *)skb_push(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
1129 if (!hdr) {
1130 pr_err("%s: skb_push failed\n", __func__);
1131 kfree_skb(ipc_rtr_pkt);
1132 kfree(pkt_fragment_q);
1133 kfree(pkt);
1134 return -ENOMEM;
1135 }
1136 hdr->version = IPC_ROUTER_VERSION;
1137 hdr->type = msg->cmd;
1138 hdr->src_node_id = IPC_ROUTER_NID_LOCAL;
1139 hdr->src_port_id = IPC_ROUTER_ADDRESS;
1140 hdr->confirm_rx = 0;
1141 hdr->size = sizeof(*msg);
1142 hdr->dst_node_id = IPC_ROUTER_NID_LOCAL;
1143 hdr->dst_port_id = IPC_ROUTER_ADDRESS;
1144 skb_queue_tail(pkt_fragment_q, ipc_rtr_pkt);
1145 pkt->pkt_fragment_q = pkt_fragment_q;
1146 pkt->length = pkt_size;
1147
1148 ret = post_control_ports(pkt);
1149 release_pkt(pkt);
1150 return ret;
1151}
1152
1153static int broadcast_ctl_msg(union rr_control_msg *ctl)
1154{
1155 struct msm_ipc_router_xprt_info *xprt_info;
1156
1157 mutex_lock(&xprt_info_list_lock);
1158 list_for_each_entry(xprt_info, &xprt_info_list, list) {
1159 msm_ipc_router_send_control_msg(xprt_info, ctl);
1160 }
1161 mutex_unlock(&xprt_info_list_lock);
1162
1163 return 0;
1164}
1165
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001166static int relay_ctl_msg(struct msm_ipc_router_xprt_info *xprt_info,
1167 union rr_control_msg *ctl)
1168{
1169 struct msm_ipc_router_xprt_info *fwd_xprt_info;
1170
1171 if (!xprt_info || !ctl)
1172 return -EINVAL;
1173
1174 mutex_lock(&xprt_info_list_lock);
1175 list_for_each_entry(fwd_xprt_info, &xprt_info_list, list) {
1176 if (xprt_info->xprt->link_id != fwd_xprt_info->xprt->link_id)
1177 msm_ipc_router_send_control_msg(fwd_xprt_info, ctl);
1178 }
1179 mutex_unlock(&xprt_info_list_lock);
1180
1181 return 0;
1182}
1183
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001184static int relay_msg(struct msm_ipc_router_xprt_info *xprt_info,
1185 struct rr_packet *pkt)
1186{
1187 struct msm_ipc_router_xprt_info *fwd_xprt_info;
1188
1189 if (!xprt_info || !pkt)
1190 return -EINVAL;
1191
1192 mutex_lock(&xprt_info_list_lock);
1193 list_for_each_entry(fwd_xprt_info, &xprt_info_list, list) {
1194 mutex_lock(&fwd_xprt_info->tx_lock);
1195 if (xprt_info->xprt->link_id != fwd_xprt_info->xprt->link_id)
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -07001196 fwd_xprt_info->xprt->write(pkt, pkt->length,
1197 fwd_xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001198 mutex_unlock(&fwd_xprt_info->tx_lock);
1199 }
1200 mutex_unlock(&xprt_info_list_lock);
1201 return 0;
1202}
1203
1204static int forward_msg(struct msm_ipc_router_xprt_info *xprt_info,
1205 struct rr_packet *pkt)
1206{
1207 uint32_t dst_node_id;
1208 struct sk_buff *head_pkt;
1209 struct rr_header *hdr;
1210 struct msm_ipc_router_xprt_info *fwd_xprt_info;
1211 struct msm_ipc_routing_table_entry *rt_entry;
1212
1213 if (!xprt_info || !pkt)
1214 return -EINVAL;
1215
1216 head_pkt = skb_peek(pkt->pkt_fragment_q);
1217 if (!head_pkt)
1218 return -EINVAL;
1219
1220 hdr = (struct rr_header *)head_pkt->data;
1221 dst_node_id = hdr->dst_node_id;
1222 mutex_lock(&routing_table_lock);
1223 rt_entry = lookup_routing_table(dst_node_id);
1224 if (!(rt_entry) || !(rt_entry->xprt_info)) {
1225 mutex_unlock(&routing_table_lock);
1226 pr_err("%s: Routing table not initialized\n", __func__);
1227 return -ENODEV;
1228 }
1229
1230 mutex_lock(&rt_entry->lock);
1231 fwd_xprt_info = rt_entry->xprt_info;
1232 mutex_lock(&fwd_xprt_info->tx_lock);
1233 if (xprt_info->remote_node_id == fwd_xprt_info->remote_node_id) {
1234 mutex_unlock(&fwd_xprt_info->tx_lock);
1235 mutex_unlock(&rt_entry->lock);
1236 mutex_unlock(&routing_table_lock);
1237 pr_err("%s: Discarding Command to route back\n", __func__);
1238 return -EINVAL;
1239 }
1240
1241 if (xprt_info->xprt->link_id == fwd_xprt_info->xprt->link_id) {
1242 mutex_unlock(&fwd_xprt_info->tx_lock);
1243 mutex_unlock(&rt_entry->lock);
1244 mutex_unlock(&routing_table_lock);
1245 pr_err("%s: DST in the same cluster\n", __func__);
1246 return 0;
1247 }
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -07001248 fwd_xprt_info->xprt->write(pkt, pkt->length, fwd_xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001249 mutex_unlock(&fwd_xprt_info->tx_lock);
1250 mutex_unlock(&rt_entry->lock);
1251 mutex_unlock(&routing_table_lock);
1252
1253 return 0;
1254}
1255
Karthikeyan Ramasubramanian96cced72013-05-02 17:25:54 -06001256static int msm_ipc_router_send_remove_client(struct comm_mode_info *mode_info,
1257 uint32_t node_id, uint32_t port_id)
1258{
1259 union rr_control_msg msg;
1260 struct msm_ipc_router_xprt_info *tmp_xprt_info;
1261 int mode;
1262 void *xprt_info;
1263 int rc = 0;
1264
1265 if (!mode_info) {
1266 pr_err("%s: NULL mode_info\n", __func__);
1267 return -EINVAL;
1268 }
1269 mode = mode_info->mode;
1270 xprt_info = mode_info->xprt_info;
1271
1272 msg.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT;
1273 msg.cli.node_id = node_id;
1274 msg.cli.port_id = port_id;
1275
1276 if ((mode == SINGLE_LINK_MODE) && xprt_info) {
1277 mutex_lock(&xprt_info_list_lock);
1278 list_for_each_entry(tmp_xprt_info, &xprt_info_list, list) {
1279 if (tmp_xprt_info != xprt_info)
1280 continue;
1281 msm_ipc_router_send_control_msg(tmp_xprt_info, &msg);
1282 break;
1283 }
1284 mutex_unlock(&xprt_info_list_lock);
1285 } else if ((mode == SINGLE_LINK_MODE) && !xprt_info) {
1286 broadcast_ctl_msg_locally(&msg);
1287 } else if (mode == MULTI_LINK_MODE) {
1288 broadcast_ctl_msg(&msg);
1289 broadcast_ctl_msg_locally(&msg);
1290 } else if (mode != NULL_MODE) {
1291 pr_err("%s: Invalid mode(%d) + xprt_inf(%p) for %08x:%08x\n",
1292 __func__, mode, xprt_info, node_id, port_id);
1293 rc = -EINVAL;
1294 }
1295 return rc;
1296}
1297
1298static void update_comm_mode_info(struct comm_mode_info *mode_info,
1299 struct msm_ipc_router_xprt_info *xprt_info)
1300{
1301 if (!mode_info) {
1302 pr_err("%s: NULL mode_info\n", __func__);
1303 return;
1304 }
1305
1306 if (mode_info->mode == NULL_MODE) {
1307 mode_info->xprt_info = xprt_info;
1308 mode_info->mode = SINGLE_LINK_MODE;
1309 } else if (mode_info->mode == SINGLE_LINK_MODE &&
1310 mode_info->xprt_info != xprt_info) {
1311 mode_info->mode = MULTI_LINK_MODE;
1312 }
1313
1314 return;
1315}
1316
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001317static void reset_remote_port_info(uint32_t node_id, uint32_t port_id)
1318{
1319 struct msm_ipc_router_remote_port *rport_ptr;
1320
1321 rport_ptr = msm_ipc_router_lookup_remote_port(node_id, port_id);
1322 if (!rport_ptr) {
1323 pr_err("%s: No such remote port %08x:%08x\n",
1324 __func__, node_id, port_id);
1325 return;
1326 }
1327 mutex_lock(&rport_ptr->quota_lock);
1328 rport_ptr->restart_state = RESTART_PEND;
Zaheerulla Meere3f6c3a2013-04-17 01:16:47 +05301329 msm_ipc_router_free_resume_tx_port(rport_ptr);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001330 mutex_unlock(&rport_ptr->quota_lock);
1331 return;
1332}
1333
1334static void msm_ipc_cleanup_remote_server_info(
1335 struct msm_ipc_router_xprt_info *xprt_info)
1336{
1337 struct msm_ipc_server *svr, *tmp_svr;
1338 struct msm_ipc_server_port *svr_port, *tmp_svr_port;
1339 int i;
1340 union rr_control_msg ctl;
1341
1342 if (!xprt_info) {
1343 pr_err("%s: Invalid xprt_info\n", __func__);
1344 return;
1345 }
1346
1347 ctl.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_SERVER;
1348 mutex_lock(&server_list_lock);
1349 for (i = 0; i < SRV_HASH_SIZE; i++) {
1350 list_for_each_entry_safe(svr, tmp_svr, &server_list[i], list) {
1351 ctl.srv.service = svr->name.service;
1352 ctl.srv.instance = svr->name.instance;
1353 list_for_each_entry_safe(svr_port, tmp_svr_port,
1354 &svr->server_port_list, list) {
1355 if (svr_port->xprt_info != xprt_info)
1356 continue;
1357 D("Remove server %08x:%08x - %08x:%08x",
1358 ctl.srv.service, ctl.srv.instance,
1359 svr_port->server_addr.node_id,
1360 svr_port->server_addr.port_id);
1361 reset_remote_port_info(
1362 svr_port->server_addr.node_id,
1363 svr_port->server_addr.port_id);
1364 ctl.srv.node_id = svr_port->server_addr.node_id;
1365 ctl.srv.port_id = svr_port->server_addr.port_id;
1366 relay_ctl_msg(xprt_info, &ctl);
1367 broadcast_ctl_msg_locally(&ctl);
Karthikeyan Ramasubramanianefc493b2012-07-12 10:25:49 -06001368 platform_device_unregister(&svr_port->pdev);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001369 list_del(&svr_port->list);
1370 kfree(svr_port);
1371 }
1372 if (list_empty(&svr->server_port_list)) {
1373 list_del(&svr->list);
1374 kfree(svr);
1375 }
1376 }
1377 }
1378 mutex_unlock(&server_list_lock);
1379}
1380
1381static void msm_ipc_cleanup_remote_client_info(
1382 struct msm_ipc_router_xprt_info *xprt_info)
1383{
1384 struct msm_ipc_routing_table_entry *rt_entry;
1385 struct msm_ipc_router_remote_port *rport_ptr;
1386 int i, j;
1387 union rr_control_msg ctl;
1388
1389 if (!xprt_info) {
1390 pr_err("%s: Invalid xprt_info\n", __func__);
1391 return;
1392 }
1393
1394 ctl.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT;
1395 mutex_lock(&routing_table_lock);
1396 for (i = 0; i < RT_HASH_SIZE; i++) {
1397 list_for_each_entry(rt_entry, &routing_table[i], list) {
1398 mutex_lock(&rt_entry->lock);
1399 if (rt_entry->xprt_info != xprt_info) {
1400 mutex_unlock(&rt_entry->lock);
1401 continue;
1402 }
1403 for (j = 0; j < RP_HASH_SIZE; j++) {
1404 list_for_each_entry(rport_ptr,
1405 &rt_entry->remote_port_list[j], list) {
1406 if (rport_ptr->restart_state ==
1407 RESTART_PEND)
1408 continue;
1409 mutex_lock(&rport_ptr->quota_lock);
1410 rport_ptr->restart_state = RESTART_PEND;
Zaheerulla Meere3f6c3a2013-04-17 01:16:47 +05301411 msm_ipc_router_free_resume_tx_port(
1412 rport_ptr);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001413 mutex_unlock(&rport_ptr->quota_lock);
1414 ctl.cli.node_id = rport_ptr->node_id;
1415 ctl.cli.port_id = rport_ptr->port_id;
1416 broadcast_ctl_msg_locally(&ctl);
1417 }
1418 }
1419 mutex_unlock(&rt_entry->lock);
1420 }
1421 }
1422 mutex_unlock(&routing_table_lock);
1423}
1424
1425static void msm_ipc_cleanup_remote_port_info(uint32_t node_id)
1426{
1427 struct msm_ipc_routing_table_entry *rt_entry, *tmp_rt_entry;
1428 struct msm_ipc_router_remote_port *rport_ptr, *tmp_rport_ptr;
1429 int i, j;
1430
1431 mutex_lock(&routing_table_lock);
1432 for (i = 0; i < RT_HASH_SIZE; i++) {
1433 list_for_each_entry_safe(rt_entry, tmp_rt_entry,
1434 &routing_table[i], list) {
1435 mutex_lock(&rt_entry->lock);
1436 if (rt_entry->neighbor_node_id != node_id) {
1437 mutex_unlock(&rt_entry->lock);
1438 continue;
1439 }
1440 for (j = 0; j < RP_HASH_SIZE; j++) {
1441 list_for_each_entry_safe(rport_ptr,
1442 tmp_rport_ptr,
1443 &rt_entry->remote_port_list[j], list) {
1444 list_del(&rport_ptr->list);
1445 kfree(rport_ptr);
1446 }
1447 }
1448 mutex_unlock(&rt_entry->lock);
1449 }
1450 }
1451 mutex_unlock(&routing_table_lock);
1452}
1453
1454static void msm_ipc_cleanup_routing_table(
1455 struct msm_ipc_router_xprt_info *xprt_info)
1456{
1457 int i;
1458 struct msm_ipc_routing_table_entry *rt_entry;
1459
1460 if (!xprt_info) {
1461 pr_err("%s: Invalid xprt_info\n", __func__);
1462 return;
1463 }
1464
1465 mutex_lock(&routing_table_lock);
1466 for (i = 0; i < RT_HASH_SIZE; i++) {
1467 list_for_each_entry(rt_entry, &routing_table[i], list) {
1468 mutex_lock(&rt_entry->lock);
1469 if (rt_entry->xprt_info == xprt_info)
1470 rt_entry->xprt_info = NULL;
1471 mutex_unlock(&rt_entry->lock);
1472 }
1473 }
1474 mutex_unlock(&routing_table_lock);
1475}
1476
1477static void modem_reset_cleanup(struct msm_ipc_router_xprt_info *xprt_info)
1478{
1479
1480 if (!xprt_info) {
1481 pr_err("%s: Invalid xprt_info\n", __func__);
1482 return;
1483 }
1484
1485 msm_ipc_cleanup_remote_server_info(xprt_info);
1486 msm_ipc_cleanup_remote_client_info(xprt_info);
1487 msm_ipc_cleanup_routing_table(xprt_info);
1488}
1489
Karthikeyan Ramasubramanian5b502d3642012-09-23 22:23:36 -06001490/**
1491 * sync_sec_rule() - Synchrnoize the security rule into the server structure
1492 * @server: Server structure where the rule has to be synchronized.
1493 * @rule: Security tule to be synchronized.
1494 *
1495 * This function is used to update the server structure with the security
1496 * rule configured for the <service:instance> corresponding to that server.
1497 */
1498static void sync_sec_rule(struct msm_ipc_server *server, void *rule)
1499{
1500 struct msm_ipc_server_port *server_port;
1501 struct msm_ipc_router_remote_port *rport_ptr = NULL;
1502
1503 list_for_each_entry(server_port, &server->server_port_list, list) {
1504 rport_ptr = msm_ipc_router_lookup_remote_port(
1505 server_port->server_addr.node_id,
1506 server_port->server_addr.port_id);
1507 if (!rport_ptr)
1508 continue;
1509 rport_ptr->sec_rule = rule;
1510 }
1511 server->synced_sec_rule = 1;
1512}
1513
1514/**
1515 * msm_ipc_sync_sec_rule() - Sync the security rule to the service
1516 * @service: Service for which the rule has to be synchronized.
1517 * @instance: Instance for which the rule has to be synchronized.
1518 * @rule: Security rule to be synchronized.
1519 *
1520 * This function is used to syncrhonize the security rule with the server
1521 * hash table, if the user-space script configures the rule after the service
1522 * has come up. This function is used to synchronize the security rule to a
1523 * specific service and optionally a specific instance.
1524 */
1525void msm_ipc_sync_sec_rule(uint32_t service, uint32_t instance, void *rule)
1526{
1527 int key = (service & (SRV_HASH_SIZE - 1));
1528 struct msm_ipc_server *server;
1529
1530 mutex_lock(&server_list_lock);
1531 list_for_each_entry(server, &server_list[key], list) {
1532 if (server->name.service != service)
1533 continue;
1534
1535 if (server->name.instance != instance &&
1536 instance != ALL_INSTANCE)
1537 continue;
1538
1539 /*
1540 * If the rule applies to all instances and if the specific
1541 * instance of a service has a rule synchronized already,
1542 * do not apply the rule for that specific instance.
1543 */
1544 if (instance == ALL_INSTANCE && server->synced_sec_rule)
1545 continue;
1546
1547 sync_sec_rule(server, rule);
1548 }
1549 mutex_unlock(&server_list_lock);
1550}
1551
1552/**
1553 * msm_ipc_sync_default_sec_rule() - Default security rule to all services
1554 * @rule: Security rule to be synchronized.
1555 *
1556 * This function is used to syncrhonize the security rule with the server
1557 * hash table, if the user-space script configures the rule after the service
1558 * has come up. This function is used to synchronize the security rule that
1559 * applies to all services, if the concerned service do not have any rule
1560 * defined.
1561 */
1562void msm_ipc_sync_default_sec_rule(void *rule)
1563{
1564 int key;
1565 struct msm_ipc_server *server;
1566
1567 mutex_lock(&server_list_lock);
1568 for (key = 0; key < SRV_HASH_SIZE; key++) {
1569 list_for_each_entry(server, &server_list[key], list) {
1570 if (server->synced_sec_rule)
1571 continue;
1572
1573 sync_sec_rule(server, rule);
1574 }
1575 }
1576 mutex_unlock(&server_list_lock);
1577}
1578
Karthikeyan Ramasubramaniana2b7fdb2012-10-23 13:12:44 -06001579static int process_hello_msg(struct msm_ipc_router_xprt_info *xprt_info,
1580 struct rr_header *hdr)
1581{
1582 int i, rc = 0;
1583 union rr_control_msg ctl;
1584 struct msm_ipc_routing_table_entry *rt_entry;
1585
1586 if (!hdr)
1587 return -EINVAL;
1588
1589 RR("o HELLO NID %d\n", hdr->src_node_id);
1590
1591 xprt_info->remote_node_id = hdr->src_node_id;
1592 /*
1593 * Find the entry from Routing Table corresponding to Node ID.
1594 * Under SSR, an entry will be found. When the system boots up
1595 * for the 1st time, an entry will not be found and hence allocate
1596 * an entry. Update the entry with the Node ID that it corresponds
1597 * to and the XPRT through which it can be reached.
1598 */
1599 mutex_lock(&routing_table_lock);
1600 rt_entry = lookup_routing_table(hdr->src_node_id);
1601 if (!rt_entry) {
1602 rt_entry = alloc_routing_table_entry(hdr->src_node_id);
1603 if (!rt_entry) {
1604 mutex_unlock(&routing_table_lock);
1605 pr_err("%s: rt_entry allocation failed\n", __func__);
1606 return -ENOMEM;
1607 }
1608 add_routing_table_entry(rt_entry);
1609 }
1610 mutex_lock(&rt_entry->lock);
1611 rt_entry->neighbor_node_id = xprt_info->remote_node_id;
1612 rt_entry->xprt_info = xprt_info;
1613 mutex_unlock(&rt_entry->lock);
1614 mutex_unlock(&routing_table_lock);
1615
1616 /* Cleanup any remote ports, if the node is coming out of reset */
1617 msm_ipc_cleanup_remote_port_info(xprt_info->remote_node_id);
1618
1619 /* Send a reply HELLO message */
1620 memset(&ctl, 0, sizeof(ctl));
1621 ctl.cmd = IPC_ROUTER_CTRL_CMD_HELLO;
1622 rc = msm_ipc_router_send_control_msg(xprt_info, &ctl);
1623 if (rc < 0) {
1624 pr_err("%s: Error sending reply HELLO message\n", __func__);
1625 return rc;
1626 }
1627 xprt_info->initialized = 1;
1628
1629 /*
1630 * Send list of servers from the local node and from nodes
1631 * outside the mesh network in which this XPRT is part of.
1632 */
Karthikeyan Ramasubramanian05066a82012-10-31 15:12:08 -06001633 mutex_lock(&server_list_lock);
Karthikeyan Ramasubramaniana2b7fdb2012-10-23 13:12:44 -06001634 mutex_lock(&routing_table_lock);
1635 for (i = 0; i < RT_HASH_SIZE; i++) {
1636 list_for_each_entry(rt_entry, &routing_table[i], list) {
1637 if ((rt_entry->node_id != IPC_ROUTER_NID_LOCAL) &&
Karthikeyan Ramasubramanianc4c0aaa2013-01-30 14:17:57 -07001638 (!rt_entry->xprt_info ||
1639 (rt_entry->xprt_info->xprt->link_id ==
1640 xprt_info->xprt->link_id)))
Karthikeyan Ramasubramaniana2b7fdb2012-10-23 13:12:44 -06001641 continue;
1642 rc = msm_ipc_router_send_server_list(rt_entry->node_id,
1643 xprt_info);
1644 if (rc < 0) {
1645 mutex_unlock(&routing_table_lock);
Karthikeyan Ramasubramanian05066a82012-10-31 15:12:08 -06001646 mutex_unlock(&server_list_lock);
Karthikeyan Ramasubramaniana2b7fdb2012-10-23 13:12:44 -06001647 return rc;
1648 }
1649 }
1650 }
1651 mutex_unlock(&routing_table_lock);
Karthikeyan Ramasubramanian05066a82012-10-31 15:12:08 -06001652 mutex_unlock(&server_list_lock);
Karthikeyan Ramasubramaniana2b7fdb2012-10-23 13:12:44 -06001653 RR("HELLO message processed\n");
1654 return rc;
1655}
1656
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001657static int process_control_msg(struct msm_ipc_router_xprt_info *xprt_info,
1658 struct rr_packet *pkt)
1659{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001660 union rr_control_msg *msg;
1661 struct msm_ipc_router_remote_port *rport_ptr;
1662 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001663 struct sk_buff *temp_ptr;
1664 struct rr_header *hdr;
1665 struct msm_ipc_server *server;
1666 struct msm_ipc_routing_table_entry *rt_entry;
1667
1668 if (pkt->length != (IPC_ROUTER_HDR_SIZE + sizeof(*msg))) {
1669 pr_err("%s: r2r msg size %d != %d\n", __func__, pkt->length,
1670 (IPC_ROUTER_HDR_SIZE + sizeof(*msg)));
1671 return -EINVAL;
1672 }
1673
1674 temp_ptr = skb_peek(pkt->pkt_fragment_q);
Karthikeyan Ramasubramanian9024dd82011-12-19 18:44:19 -07001675 if (!temp_ptr) {
1676 pr_err("%s: pkt_fragment_q is empty\n", __func__);
1677 return -EINVAL;
1678 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001679 hdr = (struct rr_header *)temp_ptr->data;
Karthikeyan Ramasubramanian9024dd82011-12-19 18:44:19 -07001680 if (!hdr) {
1681 pr_err("%s: No data inside the skb\n", __func__);
1682 return -EINVAL;
1683 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001684 msg = (union rr_control_msg *)((char *)hdr + IPC_ROUTER_HDR_SIZE);
1685
1686 switch (msg->cmd) {
1687 case IPC_ROUTER_CTRL_CMD_HELLO:
Karthikeyan Ramasubramaniana2b7fdb2012-10-23 13:12:44 -06001688 rc = process_hello_msg(xprt_info, hdr);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001689 break;
Karthikeyan Ramasubramaniana2b7fdb2012-10-23 13:12:44 -06001690
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001691 case IPC_ROUTER_CTRL_CMD_RESUME_TX:
1692 RR("o RESUME_TX id=%d:%08x\n",
1693 msg->cli.node_id, msg->cli.port_id);
1694
1695 rport_ptr = msm_ipc_router_lookup_remote_port(msg->cli.node_id,
1696 msg->cli.port_id);
1697 if (!rport_ptr) {
1698 pr_err("%s: Unable to resume client\n", __func__);
1699 break;
1700 }
1701 mutex_lock(&rport_ptr->quota_lock);
1702 rport_ptr->tx_quota_cnt = 0;
Zaheerulla Meere3f6c3a2013-04-17 01:16:47 +05301703 post_resume_tx(rport_ptr, pkt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001704 mutex_unlock(&rport_ptr->quota_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001705 break;
1706
1707 case IPC_ROUTER_CTRL_CMD_NEW_SERVER:
1708 if (msg->srv.instance == 0) {
1709 pr_err(
1710 "rpcrouter: Server create rejected, version = 0, "
1711 "service = %08x\n", msg->srv.service);
1712 break;
1713 }
1714
1715 RR("o NEW_SERVER id=%d:%08x service=%08x:%08x\n",
1716 msg->srv.node_id, msg->srv.port_id,
1717 msg->srv.service, msg->srv.instance);
1718
1719 mutex_lock(&routing_table_lock);
1720 rt_entry = lookup_routing_table(msg->srv.node_id);
1721 if (!rt_entry) {
1722 rt_entry = alloc_routing_table_entry(msg->srv.node_id);
1723 if (!rt_entry) {
1724 mutex_unlock(&routing_table_lock);
1725 pr_err("%s: rt_entry allocation failed\n",
1726 __func__);
1727 return -ENOMEM;
1728 }
1729 mutex_lock(&rt_entry->lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001730 rt_entry->neighbor_node_id = xprt_info->remote_node_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001731 rt_entry->xprt_info = xprt_info;
1732 mutex_unlock(&rt_entry->lock);
1733 add_routing_table_entry(rt_entry);
1734 }
1735 mutex_unlock(&routing_table_lock);
1736
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -06001737 mutex_lock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001738 server = msm_ipc_router_lookup_server(msg->srv.service,
1739 msg->srv.instance,
1740 msg->srv.node_id,
1741 msg->srv.port_id);
1742 if (!server) {
1743 server = msm_ipc_router_create_server(
1744 msg->srv.service, msg->srv.instance,
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001745 msg->srv.node_id, msg->srv.port_id, xprt_info);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001746 if (!server) {
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -06001747 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001748 pr_err("%s: Server Create failed\n", __func__);
1749 return -ENOMEM;
1750 }
1751
1752 if (!msm_ipc_router_lookup_remote_port(
1753 msg->srv.node_id, msg->srv.port_id)) {
1754 rport_ptr = msm_ipc_router_create_remote_port(
1755 msg->srv.node_id, msg->srv.port_id);
1756 if (!rport_ptr)
1757 pr_err("%s: Remote port create "
1758 "failed\n", __func__);
Brent Hronik1c9a3d42013-04-17 15:10:40 -06001759 else
1760 rport_ptr->sec_rule =
1761 msm_ipc_get_security_rule(
1762 msg->srv.service,
1763 msg->srv.instance);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001764 }
1765 wake_up(&newserver_wait);
1766 }
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -06001767 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001768
1769 relay_msg(xprt_info, pkt);
1770 post_control_ports(pkt);
1771 break;
1772 case IPC_ROUTER_CTRL_CMD_REMOVE_SERVER:
1773 RR("o REMOVE_SERVER service=%08x:%d\n",
1774 msg->srv.service, msg->srv.instance);
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -06001775 mutex_lock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001776 server = msm_ipc_router_lookup_server(msg->srv.service,
1777 msg->srv.instance,
1778 msg->srv.node_id,
1779 msg->srv.port_id);
1780 if (server) {
1781 msm_ipc_router_destroy_server(server,
1782 msg->srv.node_id,
1783 msg->srv.port_id);
1784 relay_msg(xprt_info, pkt);
1785 post_control_ports(pkt);
1786 }
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -06001787 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001788 break;
1789 case IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT:
1790 RR("o REMOVE_CLIENT id=%d:%08x\n",
1791 msg->cli.node_id, msg->cli.port_id);
1792 rport_ptr = msm_ipc_router_lookup_remote_port(msg->cli.node_id,
1793 msg->cli.port_id);
1794 if (rport_ptr)
1795 msm_ipc_router_destroy_remote_port(rport_ptr);
1796
1797 relay_msg(xprt_info, pkt);
1798 post_control_ports(pkt);
1799 break;
1800 case IPC_ROUTER_CTRL_CMD_PING:
1801 /* No action needed for ping messages received */
1802 RR("o PING\n");
1803 break;
1804 default:
1805 RR("o UNKNOWN(%08x)\n", msg->cmd);
1806 rc = -ENOSYS;
1807 }
1808
1809 return rc;
1810}
1811
1812static void do_read_data(struct work_struct *work)
1813{
1814 struct rr_header *hdr;
1815 struct rr_packet *pkt = NULL;
1816 struct msm_ipc_port *port_ptr;
1817 struct sk_buff *head_skb;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001818 struct msm_ipc_router_remote_port *rport_ptr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001819 uint32_t resume_tx, resume_tx_node_id, resume_tx_port_id;
1820
1821 struct msm_ipc_router_xprt_info *xprt_info =
1822 container_of(work,
1823 struct msm_ipc_router_xprt_info,
1824 read_data);
1825
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001826 while ((pkt = rr_read(xprt_info)) != NULL) {
1827 if (pkt->length < IPC_ROUTER_HDR_SIZE ||
1828 pkt->length > MAX_IPC_PKT_SIZE) {
1829 pr_err("%s: Invalid pkt length %d\n",
1830 __func__, pkt->length);
1831 goto fail_data;
1832 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001833
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001834 head_skb = skb_peek(pkt->pkt_fragment_q);
1835 if (!head_skb) {
1836 pr_err("%s: head_skb is invalid\n", __func__);
1837 goto fail_data;
1838 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001839
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001840 hdr = (struct rr_header *)(head_skb->data);
Karthikeyan Ramasubramanian2bfe8ec2013-03-22 10:47:20 -06001841 RAW("ver=%d type=%d src=%d:%08x crx=%d siz=%d dst=%d:%08x\n",
1842 hdr->version, hdr->type, hdr->src_node_id,
1843 hdr->src_port_id, hdr->confirm_rx, hdr->size,
1844 hdr->dst_node_id, hdr->dst_port_id);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001845
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001846 if (hdr->version != IPC_ROUTER_VERSION) {
1847 pr_err("version %d != %d\n",
1848 hdr->version, IPC_ROUTER_VERSION);
1849 goto fail_data;
1850 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001851
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001852 if ((hdr->dst_node_id != IPC_ROUTER_NID_LOCAL) &&
1853 ((hdr->type == IPC_ROUTER_CTRL_CMD_RESUME_TX) ||
1854 (hdr->type == IPC_ROUTER_CTRL_CMD_DATA))) {
1855 forward_msg(xprt_info, pkt);
1856 release_pkt(pkt);
1857 continue;
1858 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001859
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001860 if ((hdr->dst_port_id == IPC_ROUTER_ADDRESS) ||
1861 (hdr->type == IPC_ROUTER_CTRL_CMD_HELLO)) {
1862 process_control_msg(xprt_info, pkt);
1863 release_pkt(pkt);
1864 continue;
1865 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001866#if defined(CONFIG_MSM_SMD_LOGGING)
1867#if defined(DEBUG)
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001868 if (msm_ipc_router_debug_mask & SMEM_LOG) {
1869 smem_log_event((SMEM_LOG_PROC_ID_APPS |
1870 SMEM_LOG_RPC_ROUTER_EVENT_BASE |
1871 IPC_ROUTER_LOG_EVENT_RX),
1872 (hdr->src_node_id << 24) |
1873 (hdr->src_port_id & 0xffffff),
1874 (hdr->dst_node_id << 24) |
1875 (hdr->dst_port_id & 0xffffff),
1876 (hdr->type << 24) | (hdr->confirm_rx << 16) |
1877 (hdr->size & 0xffff));
1878 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001879#endif
1880#endif
1881
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001882 resume_tx = hdr->confirm_rx;
1883 resume_tx_node_id = hdr->dst_node_id;
1884 resume_tx_port_id = hdr->dst_port_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001885
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001886 rport_ptr = msm_ipc_router_lookup_remote_port(hdr->src_node_id,
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06001887 hdr->src_port_id);
1888
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001889 mutex_lock(&local_ports_lock);
1890 port_ptr = msm_ipc_router_lookup_local_port(hdr->dst_port_id);
1891 if (!port_ptr) {
1892 pr_err("%s: No local port id %08x\n", __func__,
1893 hdr->dst_port_id);
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06001894 mutex_unlock(&local_ports_lock);
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001895 release_pkt(pkt);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001896 goto process_done;
1897 }
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001898
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001899 if (!rport_ptr) {
1900 rport_ptr = msm_ipc_router_create_remote_port(
1901 hdr->src_node_id,
1902 hdr->src_port_id);
1903 if (!rport_ptr) {
1904 pr_err("%s: Rmt Prt %08x:%08x create failed\n",
1905 __func__, hdr->src_node_id,
1906 hdr->src_port_id);
1907 mutex_unlock(&local_ports_lock);
1908 goto process_done;
1909 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001910 }
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001911
Karthikeyan Ramasubramanian6dbb00f2013-05-17 15:19:56 -06001912 post_pkt_to_port(port_ptr, pkt, 0);
Karthikeyan Ramasubramanianefc493b2012-07-12 10:25:49 -06001913 mutex_unlock(&local_ports_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001914
1915process_done:
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001916 if (resume_tx) {
1917 union rr_control_msg msg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001918
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001919 msg.cmd = IPC_ROUTER_CTRL_CMD_RESUME_TX;
1920 msg.cli.node_id = resume_tx_node_id;
1921 msg.cli.port_id = resume_tx_port_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001922
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001923 RR("x RESUME_TX id=%d:%08x\n",
1924 msg.cli.node_id, msg.cli.port_id);
1925 msm_ipc_router_send_control_msg(xprt_info, &msg);
1926 }
1927
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001928 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001929 return;
1930
1931fail_data:
1932 release_pkt(pkt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001933 pr_err("ipc_router has died\n");
1934}
1935
1936int msm_ipc_router_register_server(struct msm_ipc_port *port_ptr,
1937 struct msm_ipc_addr *name)
1938{
1939 struct msm_ipc_server *server;
1940 unsigned long flags;
1941 union rr_control_msg ctl;
1942
1943 if (!port_ptr || !name)
1944 return -EINVAL;
1945
1946 if (name->addrtype != MSM_IPC_ADDR_NAME)
1947 return -EINVAL;
1948
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -06001949 mutex_lock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001950 server = msm_ipc_router_lookup_server(name->addr.port_name.service,
1951 name->addr.port_name.instance,
1952 IPC_ROUTER_NID_LOCAL,
1953 port_ptr->this_port.port_id);
1954 if (server) {
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -06001955 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001956 pr_err("%s: Server already present\n", __func__);
1957 return -EINVAL;
1958 }
1959
1960 server = msm_ipc_router_create_server(name->addr.port_name.service,
1961 name->addr.port_name.instance,
1962 IPC_ROUTER_NID_LOCAL,
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001963 port_ptr->this_port.port_id,
1964 NULL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001965 if (!server) {
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -06001966 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001967 pr_err("%s: Server Creation failed\n", __func__);
1968 return -EINVAL;
1969 }
1970
1971 ctl.cmd = IPC_ROUTER_CTRL_CMD_NEW_SERVER;
1972 ctl.srv.service = server->name.service;
1973 ctl.srv.instance = server->name.instance;
1974 ctl.srv.node_id = IPC_ROUTER_NID_LOCAL;
1975 ctl.srv.port_id = port_ptr->this_port.port_id;
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -06001976 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001977 broadcast_ctl_msg(&ctl);
1978 spin_lock_irqsave(&port_ptr->port_lock, flags);
1979 port_ptr->type = SERVER_PORT;
Karthikeyan Ramasubramanian96cced72013-05-02 17:25:54 -06001980 port_ptr->mode_info.mode = MULTI_LINK_MODE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001981 port_ptr->port_name.service = server->name.service;
1982 port_ptr->port_name.instance = server->name.instance;
1983 spin_unlock_irqrestore(&port_ptr->port_lock, flags);
1984 return 0;
1985}
1986
1987int msm_ipc_router_unregister_server(struct msm_ipc_port *port_ptr)
1988{
1989 struct msm_ipc_server *server;
1990 unsigned long flags;
1991 union rr_control_msg ctl;
1992
1993 if (!port_ptr)
1994 return -EINVAL;
1995
1996 if (port_ptr->type != SERVER_PORT) {
1997 pr_err("%s: Trying to unregister a non-server port\n",
1998 __func__);
1999 return -EINVAL;
2000 }
2001
2002 if (port_ptr->this_port.node_id != IPC_ROUTER_NID_LOCAL) {
2003 pr_err("%s: Trying to unregister a remote server locally\n",
2004 __func__);
2005 return -EINVAL;
2006 }
2007
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -06002008 mutex_lock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002009 server = msm_ipc_router_lookup_server(port_ptr->port_name.service,
2010 port_ptr->port_name.instance,
2011 port_ptr->this_port.node_id,
2012 port_ptr->this_port.port_id);
2013 if (!server) {
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -06002014 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002015 pr_err("%s: Server lookup failed\n", __func__);
2016 return -ENODEV;
2017 }
2018
2019 ctl.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_SERVER;
2020 ctl.srv.service = server->name.service;
2021 ctl.srv.instance = server->name.instance;
2022 ctl.srv.node_id = IPC_ROUTER_NID_LOCAL;
2023 ctl.srv.port_id = port_ptr->this_port.port_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002024 msm_ipc_router_destroy_server(server, port_ptr->this_port.node_id,
2025 port_ptr->this_port.port_id);
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -06002026 mutex_unlock(&server_list_lock);
2027 broadcast_ctl_msg(&ctl);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002028 spin_lock_irqsave(&port_ptr->port_lock, flags);
2029 port_ptr->type = CLIENT_PORT;
2030 spin_unlock_irqrestore(&port_ptr->port_lock, flags);
2031 return 0;
2032}
2033
2034static int loopback_data(struct msm_ipc_port *src,
2035 uint32_t port_id,
2036 struct sk_buff_head *data)
2037{
2038 struct sk_buff *head_skb;
2039 struct rr_header *hdr;
2040 struct msm_ipc_port *port_ptr;
2041 struct rr_packet *pkt;
Karthikeyan Ramasubramanianb0e23c52013-02-08 13:07:42 -07002042 int ret_len;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002043
2044 if (!data) {
2045 pr_err("%s: Invalid pkt pointer\n", __func__);
2046 return -EINVAL;
2047 }
2048
2049 pkt = create_pkt(data);
2050 if (!pkt) {
2051 pr_err("%s: New pkt create failed\n", __func__);
2052 return -ENOMEM;
2053 }
2054
2055 head_skb = skb_peek(pkt->pkt_fragment_q);
Karthikeyan Ramasubramanian9024dd82011-12-19 18:44:19 -07002056 if (!head_skb) {
2057 pr_err("%s: pkt_fragment_q is empty\n", __func__);
Brent Hronik1c9a3d42013-04-17 15:10:40 -06002058 release_pkt(pkt);
Karthikeyan Ramasubramanian9024dd82011-12-19 18:44:19 -07002059 return -EINVAL;
2060 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002061 hdr = (struct rr_header *)skb_push(head_skb, IPC_ROUTER_HDR_SIZE);
2062 if (!hdr) {
2063 pr_err("%s: Prepend Header failed\n", __func__);
2064 release_pkt(pkt);
2065 return -ENOMEM;
2066 }
2067 hdr->version = IPC_ROUTER_VERSION;
2068 hdr->type = IPC_ROUTER_CTRL_CMD_DATA;
2069 hdr->src_node_id = src->this_port.node_id;
2070 hdr->src_port_id = src->this_port.port_id;
2071 hdr->size = pkt->length;
2072 hdr->confirm_rx = 0;
2073 hdr->dst_node_id = IPC_ROUTER_NID_LOCAL;
2074 hdr->dst_port_id = port_id;
2075 pkt->length += IPC_ROUTER_HDR_SIZE;
2076
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06002077 mutex_lock(&local_ports_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002078 port_ptr = msm_ipc_router_lookup_local_port(port_id);
2079 if (!port_ptr) {
2080 pr_err("%s: Local port %d not present\n", __func__, port_id);
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06002081 mutex_unlock(&local_ports_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002082 release_pkt(pkt);
2083 return -ENODEV;
2084 }
2085
Karthikeyan Ramasubramanianb0e23c52013-02-08 13:07:42 -07002086 ret_len = pkt->length;
Karthikeyan Ramasubramanian6dbb00f2013-05-17 15:19:56 -06002087 post_pkt_to_port(port_ptr, pkt, 0);
Karthikeyan Ramasubramanian96cced72013-05-02 17:25:54 -06002088 update_comm_mode_info(&src->mode_info, NULL);
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06002089 mutex_unlock(&local_ports_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002090
Karthikeyan Ramasubramanianb0e23c52013-02-08 13:07:42 -07002091 return ret_len;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002092}
2093
2094static int msm_ipc_router_write_pkt(struct msm_ipc_port *src,
2095 struct msm_ipc_router_remote_port *rport_ptr,
2096 struct rr_packet *pkt)
2097{
2098 struct sk_buff *head_skb;
2099 struct rr_header *hdr;
2100 struct msm_ipc_router_xprt_info *xprt_info;
2101 struct msm_ipc_routing_table_entry *rt_entry;
Zaheerulla Meere3f6c3a2013-04-17 01:16:47 +05302102 struct msm_ipc_resume_tx_port *resume_tx_port;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002103 int ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002104
2105 if (!rport_ptr || !src || !pkt)
2106 return -EINVAL;
2107
2108 head_skb = skb_peek(pkt->pkt_fragment_q);
Karthikeyan Ramasubramanian9024dd82011-12-19 18:44:19 -07002109 if (!head_skb) {
2110 pr_err("%s: pkt_fragment_q is empty\n", __func__);
2111 return -EINVAL;
2112 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002113 hdr = (struct rr_header *)skb_push(head_skb, IPC_ROUTER_HDR_SIZE);
2114 if (!hdr) {
2115 pr_err("%s: Prepend Header failed\n", __func__);
2116 return -ENOMEM;
2117 }
2118 hdr->version = IPC_ROUTER_VERSION;
2119 hdr->type = IPC_ROUTER_CTRL_CMD_DATA;
2120 hdr->src_node_id = src->this_port.node_id;
2121 hdr->src_port_id = src->this_port.port_id;
2122 hdr->size = pkt->length;
2123 hdr->confirm_rx = 0;
2124 hdr->dst_node_id = rport_ptr->node_id;
2125 hdr->dst_port_id = rport_ptr->port_id;
2126 pkt->length += IPC_ROUTER_HDR_SIZE;
2127
Zaheerulla Meere3f6c3a2013-04-17 01:16:47 +05302128 mutex_lock(&rport_ptr->quota_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002129 if (rport_ptr->restart_state != RESTART_NORMAL) {
2130 mutex_unlock(&rport_ptr->quota_lock);
2131 return -ENETRESET;
2132 }
Zaheerulla Meere3f6c3a2013-04-17 01:16:47 +05302133 if (rport_ptr->tx_quota_cnt == IPC_ROUTER_DEFAULT_RX_QUOTA) {
2134 if (msm_ipc_router_lookup_resume_tx_port(
2135 rport_ptr, src->this_port.port_id)) {
2136 mutex_unlock(&rport_ptr->quota_lock);
2137 return -EAGAIN;
2138 }
2139 resume_tx_port =
2140 kzalloc(sizeof(struct msm_ipc_resume_tx_port),
2141 GFP_KERNEL);
2142 if (!resume_tx_port) {
2143 pr_err("%s: Resume_Tx port allocation failed\n",
2144 __func__);
2145 mutex_unlock(&rport_ptr->quota_lock);
2146 return -ENOMEM;
2147 }
2148 INIT_LIST_HEAD(&resume_tx_port->list);
2149 resume_tx_port->port_id = src->this_port.port_id;
2150 resume_tx_port->node_id = src->this_port.node_id;
2151 list_add_tail(&resume_tx_port->list,
2152 &rport_ptr->resume_tx_port_list);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002153 mutex_unlock(&rport_ptr->quota_lock);
Zaheerulla Meere3f6c3a2013-04-17 01:16:47 +05302154 return -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002155 }
2156 rport_ptr->tx_quota_cnt++;
2157 if (rport_ptr->tx_quota_cnt == IPC_ROUTER_DEFAULT_RX_QUOTA)
2158 hdr->confirm_rx = 1;
2159 mutex_unlock(&rport_ptr->quota_lock);
2160
2161 mutex_lock(&routing_table_lock);
2162 rt_entry = lookup_routing_table(hdr->dst_node_id);
2163 if (!rt_entry || !rt_entry->xprt_info) {
2164 mutex_unlock(&routing_table_lock);
2165 pr_err("%s: Remote node %d not up\n",
2166 __func__, hdr->dst_node_id);
2167 return -ENODEV;
2168 }
2169 mutex_lock(&rt_entry->lock);
2170 xprt_info = rt_entry->xprt_info;
2171 mutex_lock(&xprt_info->tx_lock);
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -07002172 ret = xprt_info->xprt->write(pkt, pkt->length, xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002173 mutex_unlock(&xprt_info->tx_lock);
2174 mutex_unlock(&rt_entry->lock);
2175 mutex_unlock(&routing_table_lock);
2176
2177 if (ret < 0) {
2178 pr_err("%s: Write on XPRT failed\n", __func__);
2179 return ret;
2180 }
Karthikeyan Ramasubramanian96cced72013-05-02 17:25:54 -06002181 update_comm_mode_info(&src->mode_info, xprt_info);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002182
2183 RAW_HDR("[w rr_h] "
2184 "ver=%i,type=%s,src_nid=%08x,src_port_id=%08x,"
2185 "confirm_rx=%i,size=%3i,dst_pid=%08x,dst_cid=%08x\n",
2186 hdr->version, type_to_str(hdr->type),
2187 hdr->src_node_id, hdr->src_port_id,
2188 hdr->confirm_rx, hdr->size,
2189 hdr->dst_node_id, hdr->dst_port_id);
2190
2191#if defined(CONFIG_MSM_SMD_LOGGING)
2192#if defined(DEBUG)
2193 if (msm_ipc_router_debug_mask & SMEM_LOG) {
2194 smem_log_event((SMEM_LOG_PROC_ID_APPS |
2195 SMEM_LOG_RPC_ROUTER_EVENT_BASE |
2196 IPC_ROUTER_LOG_EVENT_TX),
2197 (hdr->src_node_id << 24) |
2198 (hdr->src_port_id & 0xffffff),
2199 (hdr->dst_node_id << 24) |
2200 (hdr->dst_port_id & 0xffffff),
2201 (hdr->type << 24) | (hdr->confirm_rx << 16) |
2202 (hdr->size & 0xffff));
2203 }
2204#endif
2205#endif
2206
2207 return pkt->length;
2208}
2209
2210int msm_ipc_router_send_to(struct msm_ipc_port *src,
2211 struct sk_buff_head *data,
2212 struct msm_ipc_addr *dest)
2213{
2214 uint32_t dst_node_id = 0, dst_port_id = 0;
2215 struct msm_ipc_server *server;
2216 struct msm_ipc_server_port *server_port;
2217 struct msm_ipc_router_remote_port *rport_ptr = NULL;
2218 struct rr_packet *pkt;
2219 int ret;
2220
2221 if (!src || !data || !dest) {
2222 pr_err("%s: Invalid Parameters\n", __func__);
2223 return -EINVAL;
2224 }
2225
2226 /* Resolve Address*/
2227 if (dest->addrtype == MSM_IPC_ADDR_ID) {
2228 dst_node_id = dest->addr.port_addr.node_id;
2229 dst_port_id = dest->addr.port_addr.port_id;
2230 } else if (dest->addrtype == MSM_IPC_ADDR_NAME) {
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -06002231 mutex_lock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002232 server = msm_ipc_router_lookup_server(
2233 dest->addr.port_name.service,
2234 dest->addr.port_name.instance,
2235 0, 0);
2236 if (!server) {
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -06002237 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002238 pr_err("%s: Destination not reachable\n", __func__);
2239 return -ENODEV;
2240 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002241 server_port = list_first_entry(&server->server_port_list,
2242 struct msm_ipc_server_port,
2243 list);
2244 dst_node_id = server_port->server_addr.node_id;
2245 dst_port_id = server_port->server_addr.port_id;
2246 mutex_unlock(&server_list_lock);
2247 }
2248 if (dst_node_id == IPC_ROUTER_NID_LOCAL) {
2249 ret = loopback_data(src, dst_port_id, data);
2250 return ret;
2251 }
2252
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002253 rport_ptr = msm_ipc_router_lookup_remote_port(dst_node_id,
2254 dst_port_id);
2255 if (!rport_ptr) {
Zaheerulla Meer3d8b0a02013-05-10 15:51:28 +05302256 pr_err("%s: Remote port not found\n", __func__);
2257 return -ENODEV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002258 }
2259
Karthikeyan Ramasubramanian5b502d3642012-09-23 22:23:36 -06002260 if (src->check_send_permissions) {
2261 ret = src->check_send_permissions(rport_ptr->sec_rule);
2262 if (ret <= 0) {
2263 pr_err("%s: permission failure for %s\n",
2264 __func__, current->comm);
2265 return -EPERM;
2266 }
2267 }
2268
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002269 pkt = create_pkt(data);
2270 if (!pkt) {
2271 pr_err("%s: Pkt creation failed\n", __func__);
2272 return -ENOMEM;
2273 }
2274
2275 ret = msm_ipc_router_write_pkt(src, rport_ptr, pkt);
2276 release_pkt(pkt);
2277
2278 return ret;
2279}
2280
Karthikeyan Ramasubramanianefc493b2012-07-12 10:25:49 -06002281int msm_ipc_router_send_msg(struct msm_ipc_port *src,
2282 struct msm_ipc_addr *dest,
2283 void *data, unsigned int data_len)
2284{
2285 struct sk_buff_head *out_skb_head;
2286 int ret;
2287
2288 out_skb_head = msm_ipc_router_buf_to_skb(data, data_len);
2289 if (!out_skb_head) {
2290 pr_err("%s: SKB conversion failed\n", __func__);
2291 return -EFAULT;
2292 }
2293
2294 ret = msm_ipc_router_send_to(src, out_skb_head, dest);
2295 if (ret < 0) {
2296 pr_err("%s: msm_ipc_router_send_to failed - ret: %d\n",
2297 __func__, ret);
2298 msm_ipc_router_free_skb(out_skb_head);
2299 }
2300 return 0;
2301}
2302
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002303int msm_ipc_router_read(struct msm_ipc_port *port_ptr,
2304 struct sk_buff_head **data,
2305 size_t buf_len)
2306{
2307 struct rr_packet *pkt;
2308 int ret;
2309
2310 if (!port_ptr || !data)
2311 return -EINVAL;
2312
2313 mutex_lock(&port_ptr->port_rx_q_lock);
2314 if (list_empty(&port_ptr->port_rx_q)) {
2315 mutex_unlock(&port_ptr->port_rx_q_lock);
2316 return -EAGAIN;
2317 }
2318
2319 pkt = list_first_entry(&port_ptr->port_rx_q, struct rr_packet, list);
2320 if ((buf_len) && ((pkt->length - IPC_ROUTER_HDR_SIZE) > buf_len)) {
2321 mutex_unlock(&port_ptr->port_rx_q_lock);
2322 return -ETOOSMALL;
2323 }
2324 list_del(&pkt->list);
2325 if (list_empty(&port_ptr->port_rx_q))
2326 wake_unlock(&port_ptr->port_rx_wake_lock);
2327 *data = pkt->pkt_fragment_q;
2328 ret = pkt->length;
2329 kfree(pkt);
2330 mutex_unlock(&port_ptr->port_rx_q_lock);
2331
2332 return ret;
2333}
2334
2335int msm_ipc_router_recv_from(struct msm_ipc_port *port_ptr,
2336 struct sk_buff_head **data,
2337 struct msm_ipc_addr *src,
Karthikeyan Ramasubramanianefc493b2012-07-12 10:25:49 -06002338 long timeout)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002339{
2340 int ret, data_len, align_size;
2341 struct sk_buff *temp_skb;
2342 struct rr_header *hdr = NULL;
2343
2344 if (!port_ptr || !data) {
2345 pr_err("%s: Invalid pointers being passed\n", __func__);
2346 return -EINVAL;
2347 }
2348
2349 *data = NULL;
2350 mutex_lock(&port_ptr->port_rx_q_lock);
2351 while (list_empty(&port_ptr->port_rx_q)) {
2352 mutex_unlock(&port_ptr->port_rx_q_lock);
2353 if (timeout < 0) {
2354 ret = wait_event_interruptible(
2355 port_ptr->port_rx_wait_q,
2356 !list_empty(&port_ptr->port_rx_q));
2357 if (ret)
2358 return ret;
2359 } else if (timeout > 0) {
2360 timeout = wait_event_interruptible_timeout(
2361 port_ptr->port_rx_wait_q,
2362 !list_empty(&port_ptr->port_rx_q),
2363 timeout);
2364 if (timeout < 0)
2365 return -EFAULT;
2366 }
2367 if (timeout == 0)
2368 return -ETIMEDOUT;
2369 mutex_lock(&port_ptr->port_rx_q_lock);
2370 }
2371 mutex_unlock(&port_ptr->port_rx_q_lock);
2372
2373 ret = msm_ipc_router_read(port_ptr, data, 0);
2374 if (ret <= 0 || !(*data))
2375 return ret;
2376
2377 temp_skb = skb_peek(*data);
2378 hdr = (struct rr_header *)(temp_skb->data);
2379 if (src) {
2380 src->addrtype = MSM_IPC_ADDR_ID;
2381 src->addr.port_addr.node_id = hdr->src_node_id;
2382 src->addr.port_addr.port_id = hdr->src_port_id;
2383 }
2384
2385 data_len = hdr->size;
2386 skb_pull(temp_skb, IPC_ROUTER_HDR_SIZE);
2387 align_size = ALIGN_SIZE(data_len);
2388 if (align_size) {
2389 temp_skb = skb_peek_tail(*data);
2390 skb_trim(temp_skb, (temp_skb->len - align_size));
2391 }
2392 return data_len;
2393}
2394
Karthikeyan Ramasubramanianefc493b2012-07-12 10:25:49 -06002395int msm_ipc_router_read_msg(struct msm_ipc_port *port_ptr,
2396 struct msm_ipc_addr *src,
2397 unsigned char **data,
2398 unsigned int *len)
2399{
2400 struct sk_buff_head *in_skb_head;
2401 int ret;
2402
2403 ret = msm_ipc_router_recv_from(port_ptr, &in_skb_head, src, -1);
2404 if (ret < 0) {
2405 pr_err("%s: msm_ipc_router_recv_from failed - ret: %d\n",
2406 __func__, ret);
2407 return ret;
2408 }
2409
2410 *data = msm_ipc_router_skb_to_buf(in_skb_head, ret);
2411 if (!(*data))
2412 pr_err("%s: Buf conversion failed\n", __func__);
2413
2414 *len = ret;
2415 msm_ipc_router_free_skb(in_skb_head);
2416 return 0;
2417}
2418
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002419struct msm_ipc_port *msm_ipc_router_create_port(
Karthikeyan Ramasubramanianefc493b2012-07-12 10:25:49 -06002420 void (*notify)(unsigned event, void *priv),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002421 void *priv)
2422{
2423 struct msm_ipc_port *port_ptr;
Karthikeyan Ramasubramanianefc493b2012-07-12 10:25:49 -06002424 int ret;
2425
2426 ret = wait_for_completion_interruptible(&msm_ipc_local_router_up);
2427 if (ret < 0) {
2428 pr_err("%s: Error waiting for local router\n", __func__);
2429 return NULL;
2430 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002431
2432 port_ptr = msm_ipc_router_create_raw_port(NULL, notify, priv);
2433 if (!port_ptr)
2434 pr_err("%s: port_ptr alloc failed\n", __func__);
2435
2436 return port_ptr;
2437}
2438
2439int msm_ipc_router_close_port(struct msm_ipc_port *port_ptr)
2440{
2441 union rr_control_msg msg;
2442 struct rr_packet *pkt, *temp_pkt;
2443 struct msm_ipc_server *server;
2444
2445 if (!port_ptr)
2446 return -EINVAL;
2447
2448 if (port_ptr->type == SERVER_PORT || port_ptr->type == CLIENT_PORT) {
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06002449 mutex_lock(&local_ports_lock);
2450 list_del(&port_ptr->list);
2451 mutex_unlock(&local_ports_lock);
2452
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002453 if (port_ptr->type == SERVER_PORT) {
2454 msg.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_SERVER;
2455 msg.srv.service = port_ptr->port_name.service;
2456 msg.srv.instance = port_ptr->port_name.instance;
2457 msg.srv.node_id = port_ptr->this_port.node_id;
2458 msg.srv.port_id = port_ptr->this_port.port_id;
2459 RR("x REMOVE_SERVER Name=%d:%08x Id=%d:%08x\n",
2460 msg.srv.service, msg.srv.instance,
2461 msg.srv.node_id, msg.srv.port_id);
Karthikeyan Ramasubramanian5c568fb2013-01-10 17:09:13 -07002462 broadcast_ctl_msg(&msg);
2463 broadcast_ctl_msg_locally(&msg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002464 }
Karthikeyan Ramasubramanian5c568fb2013-01-10 17:09:13 -07002465
2466 /*
2467 * Server port could have been a client port earlier.
2468 * Send REMOVE_CLIENT message in either case.
2469 */
Karthikeyan Ramasubramanian5c568fb2013-01-10 17:09:13 -07002470 RR("x REMOVE_CLIENT id=%d:%08x\n",
Karthikeyan Ramasubramanian96cced72013-05-02 17:25:54 -06002471 port_ptr->this_port.node_id, port_ptr->this_port.port_id);
2472 msm_ipc_router_send_remove_client(&port_ptr->mode_info,
2473 port_ptr->this_port.node_id,
2474 port_ptr->this_port.port_id);
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06002475 } else if (port_ptr->type == CONTROL_PORT) {
2476 mutex_lock(&control_ports_lock);
2477 list_del(&port_ptr->list);
2478 mutex_unlock(&control_ports_lock);
Karthikeyan Ramasubramanianf7a4b6e2013-01-16 09:00:28 -07002479 } else if (port_ptr->type == IRSC_PORT) {
2480 mutex_lock(&local_ports_lock);
2481 list_del(&port_ptr->list);
2482 mutex_unlock(&local_ports_lock);
2483 signal_irsc_completion();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002484 }
2485
2486 mutex_lock(&port_ptr->port_rx_q_lock);
2487 list_for_each_entry_safe(pkt, temp_pkt, &port_ptr->port_rx_q, list) {
2488 list_del(&pkt->list);
2489 release_pkt(pkt);
2490 }
2491 mutex_unlock(&port_ptr->port_rx_q_lock);
2492
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002493 if (port_ptr->type == SERVER_PORT) {
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -06002494 mutex_lock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002495 server = msm_ipc_router_lookup_server(
2496 port_ptr->port_name.service,
2497 port_ptr->port_name.instance,
2498 port_ptr->this_port.node_id,
2499 port_ptr->this_port.port_id);
2500 if (server)
2501 msm_ipc_router_destroy_server(server,
2502 port_ptr->this_port.node_id,
2503 port_ptr->this_port.port_id);
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -06002504 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002505 }
2506
Karthikeyan Ramasubramaniandd8c3b52011-11-30 16:26:12 -07002507 wake_lock_destroy(&port_ptr->port_rx_wake_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002508 kfree(port_ptr);
2509 return 0;
2510}
2511
2512int msm_ipc_router_get_curr_pkt_size(struct msm_ipc_port *port_ptr)
2513{
2514 struct rr_packet *pkt;
2515 int rc = 0;
2516
2517 if (!port_ptr)
2518 return -EINVAL;
2519
2520 mutex_lock(&port_ptr->port_rx_q_lock);
2521 if (!list_empty(&port_ptr->port_rx_q)) {
2522 pkt = list_first_entry(&port_ptr->port_rx_q,
2523 struct rr_packet, list);
2524 rc = pkt->length;
2525 }
2526 mutex_unlock(&port_ptr->port_rx_q_lock);
2527
2528 return rc;
2529}
2530
2531int msm_ipc_router_bind_control_port(struct msm_ipc_port *port_ptr)
2532{
2533 if (!port_ptr)
2534 return -EINVAL;
2535
2536 mutex_lock(&local_ports_lock);
2537 list_del(&port_ptr->list);
2538 mutex_unlock(&local_ports_lock);
2539 port_ptr->type = CONTROL_PORT;
2540 mutex_lock(&control_ports_lock);
2541 list_add_tail(&port_ptr->list, &control_ports);
2542 mutex_unlock(&control_ports_lock);
2543
2544 return 0;
2545}
2546
2547int msm_ipc_router_lookup_server_name(struct msm_ipc_port_name *srv_name,
Karthikeyan Ramasubramaniandfde01b2012-06-12 14:25:13 -06002548 struct msm_ipc_server_info *srv_info,
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002549 int num_entries_in_array,
2550 uint32_t lookup_mask)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002551{
2552 struct msm_ipc_server *server;
2553 struct msm_ipc_server_port *server_port;
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002554 int key, i = 0; /*num_entries_found*/
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002555
2556 if (!srv_name) {
2557 pr_err("%s: Invalid srv_name\n", __func__);
2558 return -EINVAL;
2559 }
2560
Karthikeyan Ramasubramaniandfde01b2012-06-12 14:25:13 -06002561 if (num_entries_in_array && !srv_info) {
2562 pr_err("%s: srv_info NULL\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002563 return -EINVAL;
2564 }
2565
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002566 mutex_lock(&server_list_lock);
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002567 if (!lookup_mask)
2568 lookup_mask = 0xFFFFFFFF;
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -06002569 key = (srv_name->service & (SRV_HASH_SIZE - 1));
2570 list_for_each_entry(server, &server_list[key], list) {
2571 if ((server->name.service != srv_name->service) ||
2572 ((server->name.instance & lookup_mask) !=
2573 srv_name->instance))
2574 continue;
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002575
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -06002576 list_for_each_entry(server_port,
2577 &server->server_port_list, list) {
2578 if (i < num_entries_in_array) {
2579 srv_info[i].node_id =
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002580 server_port->server_addr.node_id;
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -06002581 srv_info[i].port_id =
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002582 server_port->server_addr.port_id;
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -06002583 srv_info[i].service = server->name.service;
2584 srv_info[i].instance = server->name.instance;
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002585 }
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -06002586 i++;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002587 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002588 }
2589 mutex_unlock(&server_list_lock);
2590
2591 return i;
2592}
2593
2594int msm_ipc_router_close(void)
2595{
2596 struct msm_ipc_router_xprt_info *xprt_info, *tmp_xprt_info;
2597
2598 mutex_lock(&xprt_info_list_lock);
2599 list_for_each_entry_safe(xprt_info, tmp_xprt_info,
2600 &xprt_info_list, list) {
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -07002601 xprt_info->xprt->close(xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002602 list_del(&xprt_info->list);
2603 kfree(xprt_info);
2604 }
2605 mutex_unlock(&xprt_info_list_lock);
2606 return 0;
2607}
2608
2609#if defined(CONFIG_DEBUG_FS)
2610static int dump_routing_table(char *buf, int max)
2611{
2612 int i = 0, j;
2613 struct msm_ipc_routing_table_entry *rt_entry;
2614
2615 for (j = 0; j < RT_HASH_SIZE; j++) {
2616 mutex_lock(&routing_table_lock);
2617 list_for_each_entry(rt_entry, &routing_table[j], list) {
2618 mutex_lock(&rt_entry->lock);
2619 i += scnprintf(buf + i, max - i,
2620 "Node Id: 0x%08x\n", rt_entry->node_id);
Karthikeyan Ramasubramanianbddeec72012-09-10 16:10:24 -06002621 if (rt_entry->node_id == IPC_ROUTER_NID_LOCAL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002622 i += scnprintf(buf + i, max - i,
2623 "XPRT Name: Loopback\n");
2624 i += scnprintf(buf + i, max - i,
2625 "Next Hop: %d\n", rt_entry->node_id);
2626 } else {
2627 i += scnprintf(buf + i, max - i,
2628 "XPRT Name: %s\n",
2629 rt_entry->xprt_info->xprt->name);
2630 i += scnprintf(buf + i, max - i,
2631 "Next Hop: 0x%08x\n",
2632 rt_entry->xprt_info->remote_node_id);
2633 }
2634 i += scnprintf(buf + i, max - i, "\n");
2635 mutex_unlock(&rt_entry->lock);
2636 }
2637 mutex_unlock(&routing_table_lock);
2638 }
2639
2640 return i;
2641}
2642
2643static int dump_xprt_info(char *buf, int max)
2644{
2645 int i = 0;
2646 struct msm_ipc_router_xprt_info *xprt_info;
2647
2648 mutex_lock(&xprt_info_list_lock);
2649 list_for_each_entry(xprt_info, &xprt_info_list, list) {
2650 i += scnprintf(buf + i, max - i, "XPRT Name: %s\n",
2651 xprt_info->xprt->name);
2652 i += scnprintf(buf + i, max - i, "Link Id: %d\n",
2653 xprt_info->xprt->link_id);
2654 i += scnprintf(buf + i, max - i, "Initialized: %s\n",
2655 (xprt_info->initialized ? "Y" : "N"));
2656 i += scnprintf(buf + i, max - i, "Remote Node Id: 0x%08x\n",
2657 xprt_info->remote_node_id);
2658 i += scnprintf(buf + i, max - i, "\n");
2659 }
2660 mutex_unlock(&xprt_info_list_lock);
2661
2662 return i;
2663}
2664
2665static int dump_servers(char *buf, int max)
2666{
2667 int i = 0, j;
2668 struct msm_ipc_server *server;
2669 struct msm_ipc_server_port *server_port;
2670
2671 mutex_lock(&server_list_lock);
2672 for (j = 0; j < SRV_HASH_SIZE; j++) {
2673 list_for_each_entry(server, &server_list[j], list) {
2674 list_for_each_entry(server_port,
2675 &server->server_port_list,
2676 list) {
2677 i += scnprintf(buf + i, max - i, "Service: "
2678 "0x%08x\n", server->name.service);
2679 i += scnprintf(buf + i, max - i, "Instance: "
2680 "0x%08x\n", server->name.instance);
2681 i += scnprintf(buf + i, max - i,
2682 "Node_id: 0x%08x\n",
2683 server_port->server_addr.node_id);
2684 i += scnprintf(buf + i, max - i,
2685 "Port_id: 0x%08x\n",
2686 server_port->server_addr.port_id);
2687 i += scnprintf(buf + i, max - i, "\n");
2688 }
2689 }
2690 }
2691 mutex_unlock(&server_list_lock);
2692
2693 return i;
2694}
2695
2696static int dump_remote_ports(char *buf, int max)
2697{
2698 int i = 0, j, k;
2699 struct msm_ipc_router_remote_port *rport_ptr;
2700 struct msm_ipc_routing_table_entry *rt_entry;
2701
2702 for (j = 0; j < RT_HASH_SIZE; j++) {
2703 mutex_lock(&routing_table_lock);
2704 list_for_each_entry(rt_entry, &routing_table[j], list) {
2705 mutex_lock(&rt_entry->lock);
2706 for (k = 0; k < RP_HASH_SIZE; k++) {
2707 list_for_each_entry(rport_ptr,
2708 &rt_entry->remote_port_list[k],
2709 list) {
2710 i += scnprintf(buf + i, max - i,
2711 "Node_id: 0x%08x\n",
2712 rport_ptr->node_id);
2713 i += scnprintf(buf + i, max - i,
2714 "Port_id: 0x%08x\n",
2715 rport_ptr->port_id);
2716 i += scnprintf(buf + i, max - i,
2717 "Quota_cnt: %d\n",
2718 rport_ptr->tx_quota_cnt);
2719 i += scnprintf(buf + i, max - i, "\n");
2720 }
2721 }
2722 mutex_unlock(&rt_entry->lock);
2723 }
2724 mutex_unlock(&routing_table_lock);
2725 }
2726
2727 return i;
2728}
2729
2730static int dump_control_ports(char *buf, int max)
2731{
2732 int i = 0;
2733 struct msm_ipc_port *port_ptr;
2734
2735 mutex_lock(&control_ports_lock);
2736 list_for_each_entry(port_ptr, &control_ports, list) {
2737 i += scnprintf(buf + i, max - i, "Node_id: 0x%08x\n",
2738 port_ptr->this_port.node_id);
2739 i += scnprintf(buf + i, max - i, "Port_id: 0x%08x\n",
2740 port_ptr->this_port.port_id);
2741 i += scnprintf(buf + i, max - i, "\n");
2742 }
2743 mutex_unlock(&control_ports_lock);
2744
2745 return i;
2746}
2747
2748static int dump_local_ports(char *buf, int max)
2749{
2750 int i = 0, j;
2751 unsigned long flags;
2752 struct msm_ipc_port *port_ptr;
2753
2754 mutex_lock(&local_ports_lock);
2755 for (j = 0; j < LP_HASH_SIZE; j++) {
2756 list_for_each_entry(port_ptr, &local_ports[j], list) {
2757 spin_lock_irqsave(&port_ptr->port_lock, flags);
2758 i += scnprintf(buf + i, max - i, "Node_id: 0x%08x\n",
2759 port_ptr->this_port.node_id);
2760 i += scnprintf(buf + i, max - i, "Port_id: 0x%08x\n",
2761 port_ptr->this_port.port_id);
2762 i += scnprintf(buf + i, max - i, "# pkts tx'd %d\n",
2763 port_ptr->num_tx);
2764 i += scnprintf(buf + i, max - i, "# pkts rx'd %d\n",
2765 port_ptr->num_rx);
2766 i += scnprintf(buf + i, max - i, "# bytes tx'd %ld\n",
2767 port_ptr->num_tx_bytes);
2768 i += scnprintf(buf + i, max - i, "# bytes rx'd %ld\n",
2769 port_ptr->num_rx_bytes);
2770 spin_unlock_irqrestore(&port_ptr->port_lock, flags);
2771 i += scnprintf(buf + i, max - i, "\n");
2772 }
2773 }
2774 mutex_unlock(&local_ports_lock);
2775
2776 return i;
2777}
2778
2779#define DEBUG_BUFMAX 4096
2780static char debug_buffer[DEBUG_BUFMAX];
2781
2782static ssize_t debug_read(struct file *file, char __user *buf,
2783 size_t count, loff_t *ppos)
2784{
2785 int (*fill)(char *buf, int max) = file->private_data;
2786 int bsize = fill(debug_buffer, DEBUG_BUFMAX);
2787 return simple_read_from_buffer(buf, count, ppos, debug_buffer, bsize);
2788}
2789
2790static int debug_open(struct inode *inode, struct file *file)
2791{
2792 file->private_data = inode->i_private;
2793 return 0;
2794}
2795
2796static const struct file_operations debug_ops = {
2797 .read = debug_read,
2798 .open = debug_open,
2799};
2800
2801static void debug_create(const char *name, mode_t mode,
2802 struct dentry *dent,
2803 int (*fill)(char *buf, int max))
2804{
2805 debugfs_create_file(name, mode, dent, fill, &debug_ops);
2806}
2807
2808static void debugfs_init(void)
2809{
2810 struct dentry *dent;
2811
2812 dent = debugfs_create_dir("msm_ipc_router", 0);
2813 if (IS_ERR(dent))
2814 return;
2815
2816 debug_create("dump_local_ports", 0444, dent,
2817 dump_local_ports);
2818 debug_create("dump_remote_ports", 0444, dent,
2819 dump_remote_ports);
2820 debug_create("dump_control_ports", 0444, dent,
2821 dump_control_ports);
2822 debug_create("dump_servers", 0444, dent,
2823 dump_servers);
2824 debug_create("dump_xprt_info", 0444, dent,
2825 dump_xprt_info);
2826 debug_create("dump_routing_table", 0444, dent,
2827 dump_routing_table);
2828}
2829
2830#else
2831static void debugfs_init(void) {}
2832#endif
2833
2834static int msm_ipc_router_add_xprt(struct msm_ipc_router_xprt *xprt)
2835{
2836 struct msm_ipc_router_xprt_info *xprt_info;
2837 struct msm_ipc_routing_table_entry *rt_entry;
2838
2839 xprt_info = kmalloc(sizeof(struct msm_ipc_router_xprt_info),
2840 GFP_KERNEL);
2841 if (!xprt_info)
2842 return -ENOMEM;
2843
2844 xprt_info->xprt = xprt;
2845 xprt_info->initialized = 0;
2846 xprt_info->remote_node_id = -1;
2847 INIT_LIST_HEAD(&xprt_info->pkt_list);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002848 mutex_init(&xprt_info->rx_lock);
2849 mutex_init(&xprt_info->tx_lock);
2850 wake_lock_init(&xprt_info->wakelock,
2851 WAKE_LOCK_SUSPEND, xprt->name);
2852 xprt_info->need_len = 0;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002853 xprt_info->abort_data_read = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002854 INIT_WORK(&xprt_info->read_data, do_read_data);
2855 INIT_LIST_HEAD(&xprt_info->list);
2856
2857 xprt_info->workqueue = create_singlethread_workqueue(xprt->name);
2858 if (!xprt_info->workqueue) {
2859 kfree(xprt_info);
2860 return -ENOMEM;
2861 }
2862
2863 if (!strcmp(xprt->name, "msm_ipc_router_loopback_xprt")) {
2864 xprt_info->remote_node_id = IPC_ROUTER_NID_LOCAL;
2865 xprt_info->initialized = 1;
2866 }
2867
2868 mutex_lock(&xprt_info_list_lock);
2869 list_add_tail(&xprt_info->list, &xprt_info_list);
2870 mutex_unlock(&xprt_info_list_lock);
2871
2872 mutex_lock(&routing_table_lock);
2873 if (!routing_table_inited) {
2874 init_routing_table();
2875 rt_entry = alloc_routing_table_entry(IPC_ROUTER_NID_LOCAL);
2876 add_routing_table_entry(rt_entry);
2877 routing_table_inited = 1;
2878 }
2879 mutex_unlock(&routing_table_lock);
2880
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002881 xprt->priv = xprt_info;
2882
2883 return 0;
2884}
2885
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002886static void msm_ipc_router_remove_xprt(struct msm_ipc_router_xprt *xprt)
2887{
2888 struct msm_ipc_router_xprt_info *xprt_info;
2889
2890 if (xprt && xprt->priv) {
2891 xprt_info = xprt->priv;
2892
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06002893 mutex_lock(&xprt_info->rx_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002894 xprt_info->abort_data_read = 1;
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06002895 mutex_unlock(&xprt_info->rx_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002896
2897 mutex_lock(&xprt_info_list_lock);
2898 list_del(&xprt_info->list);
2899 mutex_unlock(&xprt_info_list_lock);
2900
2901 flush_workqueue(xprt_info->workqueue);
2902 destroy_workqueue(xprt_info->workqueue);
2903 wake_lock_destroy(&xprt_info->wakelock);
2904
2905 xprt->priv = 0;
2906 kfree(xprt_info);
2907 }
2908}
2909
2910
2911struct msm_ipc_router_xprt_work {
2912 struct msm_ipc_router_xprt *xprt;
2913 struct work_struct work;
2914};
2915
2916static void xprt_open_worker(struct work_struct *work)
2917{
2918 struct msm_ipc_router_xprt_work *xprt_work =
2919 container_of(work, struct msm_ipc_router_xprt_work, work);
2920
2921 msm_ipc_router_add_xprt(xprt_work->xprt);
2922 kfree(xprt_work);
2923}
2924
2925static void xprt_close_worker(struct work_struct *work)
2926{
2927 struct msm_ipc_router_xprt_work *xprt_work =
2928 container_of(work, struct msm_ipc_router_xprt_work, work);
2929
2930 modem_reset_cleanup(xprt_work->xprt->priv);
2931 msm_ipc_router_remove_xprt(xprt_work->xprt);
2932
2933 if (atomic_dec_return(&pending_close_count) == 0)
2934 wake_up(&subsystem_restart_wait);
2935
2936 kfree(xprt_work);
2937}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002938
2939void msm_ipc_router_xprt_notify(struct msm_ipc_router_xprt *xprt,
2940 unsigned event,
2941 void *data)
2942{
2943 struct msm_ipc_router_xprt_info *xprt_info = xprt->priv;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002944 struct msm_ipc_router_xprt_work *xprt_work;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002945 struct rr_packet *pkt;
Karthikeyan Ramasubramanian4af9f7c2011-09-30 15:55:18 -06002946 unsigned long ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002947
Karthikeyan Ramasubramanian4af9f7c2011-09-30 15:55:18 -06002948 if (!msm_ipc_router_workqueue) {
2949 ret = wait_for_completion_timeout(&msm_ipc_local_router_up,
2950 IPC_ROUTER_INIT_TIMEOUT);
2951 if (!ret || !msm_ipc_router_workqueue) {
2952 pr_err("%s: IPC Router not initialized\n", __func__);
2953 return;
2954 }
2955 }
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002956
2957 switch (event) {
2958 case IPC_ROUTER_XPRT_EVENT_OPEN:
2959 D("open event for '%s'\n", xprt->name);
2960 xprt_work = kmalloc(sizeof(struct msm_ipc_router_xprt_work),
2961 GFP_ATOMIC);
Karthikeyan Ramasubramanian840bed12013-05-16 15:51:29 -06002962 if (xprt_work) {
2963 xprt_work->xprt = xprt;
2964 INIT_WORK(&xprt_work->work, xprt_open_worker);
2965 queue_work(msm_ipc_router_workqueue, &xprt_work->work);
2966 } else {
2967 pr_err("%s: malloc failure - Couldn't notify OPEN event",
2968 __func__);
2969 }
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002970 break;
2971
2972 case IPC_ROUTER_XPRT_EVENT_CLOSE:
2973 D("close event for '%s'\n", xprt->name);
2974 atomic_inc(&pending_close_count);
2975 xprt_work = kmalloc(sizeof(struct msm_ipc_router_xprt_work),
2976 GFP_ATOMIC);
Karthikeyan Ramasubramanian840bed12013-05-16 15:51:29 -06002977 if (xprt_work) {
2978 xprt_work->xprt = xprt;
2979 INIT_WORK(&xprt_work->work, xprt_close_worker);
2980 queue_work(msm_ipc_router_workqueue, &xprt_work->work);
2981 } else {
2982 pr_err("%s: malloc failure - Couldn't notify CLOSE event",
2983 __func__);
2984 }
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002985 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002986 }
2987
2988 if (!data)
2989 return;
2990
2991 while (!xprt_info) {
2992 msleep(100);
2993 xprt_info = xprt->priv;
2994 }
2995
2996 pkt = clone_pkt((struct rr_packet *)data);
2997 if (!pkt)
2998 return;
2999
3000 mutex_lock(&xprt_info->rx_lock);
3001 list_add_tail(&pkt->list, &xprt_info->pkt_list);
3002 wake_lock(&xprt_info->wakelock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003003 mutex_unlock(&xprt_info->rx_lock);
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06003004 queue_work(xprt_info->workqueue, &xprt_info->read_data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003005}
3006
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06003007static int modem_restart_notifier_cb(struct notifier_block *this,
3008 unsigned long code,
3009 void *data);
3010static struct notifier_block msm_ipc_router_nb = {
3011 .notifier_call = modem_restart_notifier_cb,
3012};
3013
3014static int modem_restart_notifier_cb(struct notifier_block *this,
3015 unsigned long code,
3016 void *data)
3017{
3018 switch (code) {
3019 case SUBSYS_BEFORE_SHUTDOWN:
3020 D("%s: SUBSYS_BEFORE_SHUTDOWN\n", __func__);
3021 break;
3022
3023 case SUBSYS_BEFORE_POWERUP:
3024 D("%s: waiting for RPC restart to complete\n", __func__);
3025 wait_event(subsystem_restart_wait,
3026 atomic_read(&pending_close_count) == 0);
3027 D("%s: finished restart wait\n", __func__);
3028 break;
3029
3030 default:
3031 break;
3032 }
3033
3034 return NOTIFY_DONE;
3035}
3036
3037static void *restart_notifier_handle;
3038static __init int msm_ipc_router_modem_restart_late_init(void)
3039{
3040 restart_notifier_handle = subsys_notif_register_notifier("modem",
3041 &msm_ipc_router_nb);
3042 return 0;
3043}
3044late_initcall(msm_ipc_router_modem_restart_late_init);
3045
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003046static int __init msm_ipc_router_init(void)
3047{
3048 int i, ret;
3049 struct msm_ipc_routing_table_entry *rt_entry;
3050
3051 msm_ipc_router_debug_mask |= SMEM_LOG;
Karthikeyan Ramasubramanian2bfe8ec2013-03-22 10:47:20 -06003052 ipc_rtr_log_ctxt = ipc_log_context_create(IPC_RTR_LOG_PAGES,
3053 "ipc_router");
3054 if (!ipc_rtr_log_ctxt)
3055 pr_err("%s: Unable to create IPC logging for IPC RTR",
3056 __func__);
3057
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06003058 msm_ipc_router_workqueue =
3059 create_singlethread_workqueue("msm_ipc_router");
3060 if (!msm_ipc_router_workqueue)
3061 return -ENOMEM;
3062
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003063 debugfs_init();
3064
3065 for (i = 0; i < SRV_HASH_SIZE; i++)
3066 INIT_LIST_HEAD(&server_list[i]);
3067
3068 for (i = 0; i < LP_HASH_SIZE; i++)
3069 INIT_LIST_HEAD(&local_ports[i]);
3070
3071 mutex_lock(&routing_table_lock);
3072 if (!routing_table_inited) {
3073 init_routing_table();
3074 rt_entry = alloc_routing_table_entry(IPC_ROUTER_NID_LOCAL);
3075 add_routing_table_entry(rt_entry);
3076 routing_table_inited = 1;
3077 }
3078 mutex_unlock(&routing_table_lock);
3079
3080 init_waitqueue_head(&newserver_wait);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06003081 init_waitqueue_head(&subsystem_restart_wait);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003082 ret = msm_ipc_router_init_sockets();
3083 if (ret < 0)
3084 pr_err("%s: Init sockets failed\n", __func__);
3085
Karthikeyan Ramasubramanian5b502d3642012-09-23 22:23:36 -06003086 ret = msm_ipc_router_security_init();
3087 if (ret < 0)
3088 pr_err("%s: Security Init failed\n", __func__);
3089
Karthikeyan Ramasubramanian4af9f7c2011-09-30 15:55:18 -06003090 complete_all(&msm_ipc_local_router_up);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003091 return ret;
3092}
3093
3094module_init(msm_ipc_router_init);
3095MODULE_DESCRIPTION("MSM IPC Router");
3096MODULE_LICENSE("GPL v2");