blob: d5096ae969b34c3e4936420518ffe68156995112 [file] [log] [blame]
Karthikeyan Ramasubramanian25e91872013-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 Ramasubramanian70444192012-07-12 10:25:49 -060036#include <mach/msm_ipc_router.h>
Karthikeyan Ramasubramanian682ebcc2013-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 Ramasubramanian1668cc62012-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 Ramasubramanian682ebcc2013-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 Ramasubramanian682ebcc2013-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 Ramasubramanian682ebcc2013-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 Ramasubramaniana85d09f2012-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 Ramasubramanian1668cc62012-09-23 22:23:36 -0600123 int synced_sec_rule;
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -0600124 char pdev_name[32];
125 int next_pdev_id;
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 Ramasubramanian70444192012-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 Meera34fc662013-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 Meera34fc662013-04-17 01:16:47 +0530150 struct list_head resume_tx_port_list;
Karthikeyan Ramasubramanian1668cc62012-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 struct workqueue_struct *msm_ipc_router_workqueue;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700210
211enum {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700212 DOWN,
213 UP,
214};
215
216static void init_routing_table(void)
217{
218 int i;
219 for (i = 0; i < RT_HASH_SIZE; i++)
220 INIT_LIST_HEAD(&routing_table[i]);
221}
222
223static struct msm_ipc_routing_table_entry *alloc_routing_table_entry(
224 uint32_t node_id)
225{
226 int i;
227 struct msm_ipc_routing_table_entry *rt_entry;
228
229 rt_entry = kmalloc(sizeof(struct msm_ipc_routing_table_entry),
230 GFP_KERNEL);
231 if (!rt_entry) {
232 pr_err("%s: rt_entry allocation failed for %d\n",
233 __func__, node_id);
234 return NULL;
235 }
236
237 for (i = 0; i < RP_HASH_SIZE; i++)
238 INIT_LIST_HEAD(&rt_entry->remote_port_list[i]);
239
240 mutex_init(&rt_entry->lock);
241 rt_entry->node_id = node_id;
242 rt_entry->xprt_info = NULL;
243 return rt_entry;
244}
245
246/*Please take routing_table_lock before calling this function*/
247static int add_routing_table_entry(
248 struct msm_ipc_routing_table_entry *rt_entry)
249{
250 uint32_t key;
251
252 if (!rt_entry)
253 return -EINVAL;
254
255 key = (rt_entry->node_id % RT_HASH_SIZE);
256 list_add_tail(&rt_entry->list, &routing_table[key]);
257 return 0;
258}
259
260/*Please take routing_table_lock before calling this function*/
261static struct msm_ipc_routing_table_entry *lookup_routing_table(
262 uint32_t node_id)
263{
264 uint32_t key = (node_id % RT_HASH_SIZE);
265 struct msm_ipc_routing_table_entry *rt_entry;
266
267 list_for_each_entry(rt_entry, &routing_table[key], list) {
268 if (rt_entry->node_id == node_id)
269 return rt_entry;
270 }
271 return NULL;
272}
273
274struct rr_packet *rr_read(struct msm_ipc_router_xprt_info *xprt_info)
275{
276 struct rr_packet *temp_pkt;
277
278 if (!xprt_info)
279 return NULL;
280
281 mutex_lock(&xprt_info->rx_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600282 if (xprt_info->abort_data_read) {
283 mutex_unlock(&xprt_info->rx_lock);
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -0600284 pr_err("%s detected SSR & exiting now\n",
285 xprt_info->xprt->name);
286 return NULL;
287 }
288
289 if (list_empty(&xprt_info->pkt_list)) {
290 mutex_unlock(&xprt_info->rx_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600291 return NULL;
292 }
293
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700294 temp_pkt = list_first_entry(&xprt_info->pkt_list,
295 struct rr_packet, list);
296 list_del(&temp_pkt->list);
297 if (list_empty(&xprt_info->pkt_list))
298 wake_unlock(&xprt_info->wakelock);
299 mutex_unlock(&xprt_info->rx_lock);
300 return temp_pkt;
301}
302
303struct rr_packet *clone_pkt(struct rr_packet *pkt)
304{
305 struct rr_packet *cloned_pkt;
306 struct sk_buff *temp_skb, *cloned_skb;
307 struct sk_buff_head *pkt_fragment_q;
308
309 cloned_pkt = kzalloc(sizeof(struct rr_packet), GFP_KERNEL);
310 if (!cloned_pkt) {
311 pr_err("%s: failure\n", __func__);
312 return NULL;
313 }
314
315 pkt_fragment_q = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
316 if (!pkt_fragment_q) {
317 pr_err("%s: pkt_frag_q alloc failure\n", __func__);
318 kfree(cloned_pkt);
319 return NULL;
320 }
321 skb_queue_head_init(pkt_fragment_q);
322
323 skb_queue_walk(pkt->pkt_fragment_q, temp_skb) {
324 cloned_skb = skb_clone(temp_skb, GFP_KERNEL);
325 if (!cloned_skb)
326 goto fail_clone;
327 skb_queue_tail(pkt_fragment_q, cloned_skb);
328 }
329 cloned_pkt->pkt_fragment_q = pkt_fragment_q;
330 cloned_pkt->length = pkt->length;
331 return cloned_pkt;
332
333fail_clone:
334 while (!skb_queue_empty(pkt_fragment_q)) {
335 temp_skb = skb_dequeue(pkt_fragment_q);
336 kfree_skb(temp_skb);
337 }
338 kfree(pkt_fragment_q);
339 kfree(cloned_pkt);
340 return NULL;
341}
342
343struct rr_packet *create_pkt(struct sk_buff_head *data)
344{
345 struct rr_packet *pkt;
346 struct sk_buff *temp_skb;
347
348 pkt = kzalloc(sizeof(struct rr_packet), GFP_KERNEL);
349 if (!pkt) {
350 pr_err("%s: failure\n", __func__);
351 return NULL;
352 }
353
354 pkt->pkt_fragment_q = data;
355 skb_queue_walk(pkt->pkt_fragment_q, temp_skb)
356 pkt->length += temp_skb->len;
357 return pkt;
358}
359
360void release_pkt(struct rr_packet *pkt)
361{
362 struct sk_buff *temp_skb;
363
364 if (!pkt)
365 return;
366
367 if (!pkt->pkt_fragment_q) {
368 kfree(pkt);
369 return;
370 }
371
372 while (!skb_queue_empty(pkt->pkt_fragment_q)) {
373 temp_skb = skb_dequeue(pkt->pkt_fragment_q);
374 kfree_skb(temp_skb);
375 }
376 kfree(pkt->pkt_fragment_q);
377 kfree(pkt);
378 return;
379}
380
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -0600381static struct sk_buff_head *msm_ipc_router_buf_to_skb(void *buf,
382 unsigned int buf_len)
383{
384 struct sk_buff_head *skb_head;
385 struct sk_buff *skb;
386 int first = 1, offset = 0;
387 int skb_size, data_size;
388 void *data;
389
390 skb_head = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
391 if (!skb_head) {
392 pr_err("%s: Couldnot allocate skb_head\n", __func__);
393 return NULL;
394 }
395 skb_queue_head_init(skb_head);
396
397 data_size = buf_len;
398 while (offset != buf_len) {
399 skb_size = data_size;
400 if (first)
401 skb_size += IPC_ROUTER_HDR_SIZE;
402
403 skb = alloc_skb(skb_size, GFP_KERNEL);
404 if (!skb) {
405 if (skb_size <= (PAGE_SIZE/2)) {
406 pr_err("%s: cannot allocate skb\n", __func__);
407 goto buf_to_skb_error;
408 }
409 data_size = data_size / 2;
410 continue;
411 }
412
413 if (first) {
414 skb_reserve(skb, IPC_ROUTER_HDR_SIZE);
415 first = 0;
416 }
417
418 data = skb_put(skb, data_size);
419 memcpy(skb->data, buf + offset, data_size);
420 skb_queue_tail(skb_head, skb);
421 offset += data_size;
422 data_size = buf_len - offset;
423 }
424 return skb_head;
425
426buf_to_skb_error:
427 while (!skb_queue_empty(skb_head)) {
428 skb = skb_dequeue(skb_head);
429 kfree_skb(skb);
430 }
431 kfree(skb_head);
432 return NULL;
433}
434
435static void *msm_ipc_router_skb_to_buf(struct sk_buff_head *skb_head,
436 unsigned int len)
437{
438 struct sk_buff *temp;
439 int offset = 0, buf_len = 0, copy_len;
440 void *buf;
441
442 if (!skb_head) {
443 pr_err("%s: NULL skb_head\n", __func__);
444 return NULL;
445 }
446
447 temp = skb_peek(skb_head);
448 buf_len = len;
449 buf = kmalloc(buf_len, GFP_KERNEL);
450 if (!buf) {
451 pr_err("%s: cannot allocate buf\n", __func__);
452 return NULL;
453 }
454 skb_queue_walk(skb_head, temp) {
455 copy_len = buf_len < temp->len ? buf_len : temp->len;
456 memcpy(buf + offset, temp->data, copy_len);
457 offset += copy_len;
458 buf_len -= copy_len;
459 }
460 return buf;
461}
462
463static void msm_ipc_router_free_skb(struct sk_buff_head *skb_head)
464{
465 struct sk_buff *temp_skb;
466
467 if (!skb_head)
468 return;
469
470 while (!skb_queue_empty(skb_head)) {
471 temp_skb = skb_dequeue(skb_head);
472 kfree_skb(temp_skb);
473 }
474 kfree(skb_head);
475}
476
Karthikeyan Ramasubramaniand1af6252013-05-17 15:19:56 -0600477static int post_pkt_to_port(struct msm_ipc_port *port_ptr,
478 struct rr_packet *pkt, int clone)
479{
480 struct rr_packet *temp_pkt = pkt;
481
482 if (unlikely(!port_ptr || !pkt))
483 return -EINVAL;
484
485 if (clone) {
486 temp_pkt = clone_pkt(pkt);
487 if (!temp_pkt) {
488 pr_err("%s: Error cloning packet for port %08x:%08x\n",
489 __func__, port_ptr->this_port.node_id,
490 port_ptr->this_port.port_id);
491 return -ENOMEM;
492 }
493 }
494
495 mutex_lock(&port_ptr->port_rx_q_lock);
496 wake_lock(&port_ptr->port_rx_wake_lock);
497 list_add_tail(&temp_pkt->list, &port_ptr->port_rx_q);
498 wake_up(&port_ptr->port_rx_wait_q);
499 if (port_ptr->notify)
500 port_ptr->notify(MSM_IPC_ROUTER_READ_CB, port_ptr->priv);
501 mutex_unlock(&port_ptr->port_rx_q_lock);
502 return 0;
503}
504
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700505static int post_control_ports(struct rr_packet *pkt)
506{
507 struct msm_ipc_port *port_ptr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700508
509 if (!pkt)
510 return -EINVAL;
511
512 mutex_lock(&control_ports_lock);
Karthikeyan Ramasubramaniand1af6252013-05-17 15:19:56 -0600513 list_for_each_entry(port_ptr, &control_ports, list)
514 post_pkt_to_port(port_ptr, pkt, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700515 mutex_unlock(&control_ports_lock);
516 return 0;
517}
518
519static uint32_t allocate_port_id(void)
520{
521 uint32_t port_id = 0, prev_port_id, key;
522 struct msm_ipc_port *port_ptr;
523
524 mutex_lock(&next_port_id_lock);
525 prev_port_id = next_port_id;
526 mutex_lock(&local_ports_lock);
527 do {
528 next_port_id++;
529 if ((next_port_id & 0xFFFFFFFE) == 0xFFFFFFFE)
530 next_port_id = 1;
531
532 key = (next_port_id & (LP_HASH_SIZE - 1));
533 if (list_empty(&local_ports[key])) {
534 port_id = next_port_id;
535 break;
536 }
537 list_for_each_entry(port_ptr, &local_ports[key], list) {
538 if (port_ptr->this_port.port_id == next_port_id) {
539 port_id = next_port_id;
540 break;
541 }
542 }
543 if (!port_id) {
544 port_id = next_port_id;
545 break;
546 }
547 port_id = 0;
548 } while (next_port_id != prev_port_id);
549 mutex_unlock(&local_ports_lock);
550 mutex_unlock(&next_port_id_lock);
551
552 return port_id;
553}
554
555void msm_ipc_router_add_local_port(struct msm_ipc_port *port_ptr)
556{
557 uint32_t key;
558
559 if (!port_ptr)
560 return;
561
562 key = (port_ptr->this_port.port_id & (LP_HASH_SIZE - 1));
563 mutex_lock(&local_ports_lock);
564 list_add_tail(&port_ptr->list, &local_ports[key]);
565 mutex_unlock(&local_ports_lock);
566}
567
568struct msm_ipc_port *msm_ipc_router_create_raw_port(void *endpoint,
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -0600569 void (*notify)(unsigned event, void *priv),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700570 void *priv)
571{
572 struct msm_ipc_port *port_ptr;
573
574 port_ptr = kzalloc(sizeof(struct msm_ipc_port), GFP_KERNEL);
575 if (!port_ptr)
576 return NULL;
577
578 port_ptr->this_port.node_id = IPC_ROUTER_NID_LOCAL;
579 port_ptr->this_port.port_id = allocate_port_id();
580 if (!port_ptr->this_port.port_id) {
581 pr_err("%s: All port ids are in use\n", __func__);
582 kfree(port_ptr);
583 return NULL;
584 }
585
586 spin_lock_init(&port_ptr->port_lock);
587 INIT_LIST_HEAD(&port_ptr->incomplete);
588 mutex_init(&port_ptr->incomplete_lock);
589 INIT_LIST_HEAD(&port_ptr->port_rx_q);
590 mutex_init(&port_ptr->port_rx_q_lock);
591 init_waitqueue_head(&port_ptr->port_rx_wait_q);
Karthikeyan Ramasubramanianb4aeeb92012-03-13 12:31:43 -0600592 snprintf(port_ptr->rx_wakelock_name, MAX_WAKELOCK_NAME_SZ,
Karthikeyan Ramasubramanian090486e2013-02-14 13:53:20 -0700593 "ipc%08x_%s",
594 port_ptr->this_port.port_id,
595 current->comm);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700596 wake_lock_init(&port_ptr->port_rx_wake_lock,
Karthikeyan Ramasubramanianb4aeeb92012-03-13 12:31:43 -0600597 WAKE_LOCK_SUSPEND, port_ptr->rx_wakelock_name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700598
599 port_ptr->endpoint = endpoint;
600 port_ptr->notify = notify;
601 port_ptr->priv = priv;
602
603 msm_ipc_router_add_local_port(port_ptr);
604 return port_ptr;
605}
606
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -0600607/*
608 * Should be called with local_ports_lock locked
609 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700610static struct msm_ipc_port *msm_ipc_router_lookup_local_port(uint32_t port_id)
611{
612 int key = (port_id & (LP_HASH_SIZE - 1));
613 struct msm_ipc_port *port_ptr;
614
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700615 list_for_each_entry(port_ptr, &local_ports[key], list) {
616 if (port_ptr->this_port.port_id == port_id) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700617 return port_ptr;
618 }
619 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700620 return NULL;
621}
622
623static struct msm_ipc_router_remote_port *msm_ipc_router_lookup_remote_port(
624 uint32_t node_id,
625 uint32_t port_id)
626{
627 struct msm_ipc_router_remote_port *rport_ptr;
628 struct msm_ipc_routing_table_entry *rt_entry;
629 int key = (port_id & (RP_HASH_SIZE - 1));
630
631 mutex_lock(&routing_table_lock);
632 rt_entry = lookup_routing_table(node_id);
633 if (!rt_entry) {
634 mutex_unlock(&routing_table_lock);
635 pr_err("%s: Node is not up\n", __func__);
636 return NULL;
637 }
638
639 mutex_lock(&rt_entry->lock);
640 list_for_each_entry(rport_ptr,
641 &rt_entry->remote_port_list[key], list) {
642 if (rport_ptr->port_id == port_id) {
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600643 if (rport_ptr->restart_state != RESTART_NORMAL)
644 rport_ptr = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700645 mutex_unlock(&rt_entry->lock);
646 mutex_unlock(&routing_table_lock);
647 return rport_ptr;
648 }
649 }
650 mutex_unlock(&rt_entry->lock);
651 mutex_unlock(&routing_table_lock);
652 return NULL;
653}
654
655static struct msm_ipc_router_remote_port *msm_ipc_router_create_remote_port(
656 uint32_t node_id,
657 uint32_t port_id)
658{
659 struct msm_ipc_router_remote_port *rport_ptr;
660 struct msm_ipc_routing_table_entry *rt_entry;
661 int key = (port_id & (RP_HASH_SIZE - 1));
662
663 mutex_lock(&routing_table_lock);
664 rt_entry = lookup_routing_table(node_id);
665 if (!rt_entry) {
666 mutex_unlock(&routing_table_lock);
667 pr_err("%s: Node is not up\n", __func__);
668 return NULL;
669 }
670
671 mutex_lock(&rt_entry->lock);
672 rport_ptr = kmalloc(sizeof(struct msm_ipc_router_remote_port),
673 GFP_KERNEL);
674 if (!rport_ptr) {
675 mutex_unlock(&rt_entry->lock);
676 mutex_unlock(&routing_table_lock);
677 pr_err("%s: Remote port alloc failed\n", __func__);
678 return NULL;
679 }
680 rport_ptr->port_id = port_id;
681 rport_ptr->node_id = node_id;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600682 rport_ptr->restart_state = RESTART_NORMAL;
Karthikeyan Ramasubramanian1668cc62012-09-23 22:23:36 -0600683 rport_ptr->sec_rule = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700684 rport_ptr->tx_quota_cnt = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700685 mutex_init(&rport_ptr->quota_lock);
Zaheerulla Meera34fc662013-04-17 01:16:47 +0530686 INIT_LIST_HEAD(&rport_ptr->resume_tx_port_list);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700687 list_add_tail(&rport_ptr->list,
688 &rt_entry->remote_port_list[key]);
689 mutex_unlock(&rt_entry->lock);
690 mutex_unlock(&routing_table_lock);
691 return rport_ptr;
692}
693
Zaheerulla Meera34fc662013-04-17 01:16:47 +0530694/**
695 * msm_ipc_router_free_resume_tx_port() - Free the resume_tx ports
696 * @rport_ptr: Pointer to the remote port.
697 *
698 * This function deletes all the resume_tx ports associated with a remote port
699 * and frees the memory allocated to each resume_tx port.
700 *
701 * Must be called with rport_ptr->quota_lock locked.
702 */
703static void msm_ipc_router_free_resume_tx_port(
704 struct msm_ipc_router_remote_port *rport_ptr)
705{
706 struct msm_ipc_resume_tx_port *rtx_port, *tmp_rtx_port;
707
708 list_for_each_entry_safe(rtx_port, tmp_rtx_port,
709 &rport_ptr->resume_tx_port_list, list) {
710 list_del(&rtx_port->list);
711 kfree(rtx_port);
712 }
713}
714
715/**
716 * msm_ipc_router_lookup_resume_tx_port() - Lookup resume_tx port list
717 * @rport_ptr: Remote port whose resume_tx port list needs to be looked.
718 * @port_id: Port ID which needs to be looked from the list.
719 *
720 * return 1 if the port_id is found in the list, else 0.
721 *
722 * This function is used to lookup the existence of a local port in
723 * remote port's resume_tx list. This function is used to ensure that
724 * the same port is not added to the remote_port's resume_tx list repeatedly.
725 *
726 * Must be called with rport_ptr->quota_lock locked.
727 */
728static int msm_ipc_router_lookup_resume_tx_port(
729 struct msm_ipc_router_remote_port *rport_ptr, uint32_t port_id)
730{
731 struct msm_ipc_resume_tx_port *rtx_port;
732
733 list_for_each_entry(rtx_port, &rport_ptr->resume_tx_port_list, list) {
734 if (port_id == rtx_port->port_id)
735 return 1;
736 }
737 return 0;
738}
739
740/**
741 * post_resume_tx() - Post the resume_tx event
742 * @rport_ptr: Pointer to the remote port
743 * @pkt : The data packet that is received on a resume_tx event
744 *
745 * This function informs about the reception of the resume_tx message from a
746 * remote port pointed by rport_ptr to all the local ports that are in the
747 * resume_tx_ports_list of this remote port. On posting the information, this
748 * function sequentially deletes each entry in the resume_tx_port_list of the
749 * remote port.
750 *
751 * Must be called with rport_ptr->quota_lock locked.
752 */
753static void post_resume_tx(struct msm_ipc_router_remote_port *rport_ptr,
754 struct rr_packet *pkt)
755{
756 struct msm_ipc_resume_tx_port *rtx_port, *tmp_rtx_port;
757 struct msm_ipc_port *local_port;
Zaheerulla Meera34fc662013-04-17 01:16:47 +0530758
759 list_for_each_entry_safe(rtx_port, tmp_rtx_port,
760 &rport_ptr->resume_tx_port_list, list) {
761 mutex_lock(&local_ports_lock);
762 local_port =
763 msm_ipc_router_lookup_local_port(rtx_port->port_id);
Karthikeyan Ramasubramaniand1af6252013-05-17 15:19:56 -0600764 if (local_port)
765 post_pkt_to_port(local_port, pkt, 1);
Zaheerulla Meera34fc662013-04-17 01:16:47 +0530766 mutex_unlock(&local_ports_lock);
767 list_del(&rtx_port->list);
768 kfree(rtx_port);
769 }
770}
771
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700772static void msm_ipc_router_destroy_remote_port(
773 struct msm_ipc_router_remote_port *rport_ptr)
774{
775 uint32_t node_id;
776 struct msm_ipc_routing_table_entry *rt_entry;
777
778 if (!rport_ptr)
779 return;
780
781 node_id = rport_ptr->node_id;
782 mutex_lock(&routing_table_lock);
783 rt_entry = lookup_routing_table(node_id);
784 if (!rt_entry) {
785 mutex_unlock(&routing_table_lock);
786 pr_err("%s: Node %d is not up\n", __func__, node_id);
787 return;
788 }
Zaheerulla Meera34fc662013-04-17 01:16:47 +0530789 mutex_lock(&rport_ptr->quota_lock);
790 msm_ipc_router_free_resume_tx_port(rport_ptr);
791 mutex_unlock(&rport_ptr->quota_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700792 mutex_lock(&rt_entry->lock);
793 list_del(&rport_ptr->list);
794 kfree(rport_ptr);
795 mutex_unlock(&rt_entry->lock);
796 mutex_unlock(&routing_table_lock);
797 return;
798}
799
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -0600800/**
801 * msm_ipc_router_lookup_server() - Lookup server information
802 * @service: Service ID of the server info to be looked up.
803 * @instance: Instance ID of the server info to be looked up.
804 * @node_id: Node/Processor ID in which the server is hosted.
805 * @port_id: Port ID within the node in which the server is hosted.
806 *
807 * @return: If found Pointer to server structure, else NULL.
808 *
809 * Note1: Lock the server_list_lock before accessing this function.
810 * Note2: If the <node_id:port_id> are <0:0>, then the lookup is restricted
811 * to <service:instance>. Used only when a client wants to send a
812 * message to any QMI server.
813 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700814static struct msm_ipc_server *msm_ipc_router_lookup_server(
815 uint32_t service,
816 uint32_t instance,
817 uint32_t node_id,
818 uint32_t port_id)
819{
820 struct msm_ipc_server *server;
821 struct msm_ipc_server_port *server_port;
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -0600822 int key = (service & (SRV_HASH_SIZE - 1));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700823
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700824 list_for_each_entry(server, &server_list[key], list) {
825 if ((server->name.service != service) ||
826 (server->name.instance != instance))
827 continue;
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -0600828 if ((node_id == 0) && (port_id == 0))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700829 return server;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700830 list_for_each_entry(server_port, &server->server_port_list,
831 list) {
832 if ((server_port->server_addr.node_id == node_id) &&
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -0600833 (server_port->server_addr.port_id == port_id))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700834 return server;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700835 }
836 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700837 return NULL;
838}
839
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -0600840static void dummy_release(struct device *dev)
841{
842}
843
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -0600844/**
845 * msm_ipc_router_create_server() - Add server info to hash table
846 * @service: Service ID of the server info to be created.
847 * @instance: Instance ID of the server info to be created.
848 * @node_id: Node/Processor ID in which the server is hosted.
849 * @port_id: Port ID within the node in which the server is hosted.
850 * @xprt_info: XPRT through which the node hosting the server is reached.
851 *
852 * @return: Pointer to server structure on success, else NULL.
853 *
854 * This function adds the server info to the hash table. If the same
855 * server(i.e. <service_id:instance_id>) is hosted in different nodes,
856 * they are maintained as list of "server_port" under "server" structure.
857 * Note: Lock the server_list_lock before accessing this function.
858 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700859static struct msm_ipc_server *msm_ipc_router_create_server(
860 uint32_t service,
861 uint32_t instance,
862 uint32_t node_id,
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600863 uint32_t port_id,
864 struct msm_ipc_router_xprt_info *xprt_info)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700865{
866 struct msm_ipc_server *server = NULL;
867 struct msm_ipc_server_port *server_port;
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -0600868 int key = (service & (SRV_HASH_SIZE - 1));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700869
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700870 list_for_each_entry(server, &server_list[key], list) {
871 if ((server->name.service == service) &&
872 (server->name.instance == instance))
873 goto create_srv_port;
874 }
875
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -0600876 server = kzalloc(sizeof(struct msm_ipc_server), GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700877 if (!server) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700878 pr_err("%s: Server allocation failed\n", __func__);
879 return NULL;
880 }
881 server->name.service = service;
882 server->name.instance = instance;
Karthikeyan Ramasubramanian1668cc62012-09-23 22:23:36 -0600883 server->synced_sec_rule = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700884 INIT_LIST_HEAD(&server->server_port_list);
885 list_add_tail(&server->list, &server_list[key]);
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -0600886 scnprintf(server->pdev_name, sizeof(server->pdev_name),
887 "QMI%08x:%08x", service, instance);
888 server->next_pdev_id = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700889
890create_srv_port:
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -0600891 server_port = kzalloc(sizeof(struct msm_ipc_server_port), GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700892 if (!server_port) {
893 if (list_empty(&server->server_port_list)) {
894 list_del(&server->list);
895 kfree(server);
896 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700897 pr_err("%s: Server Port allocation failed\n", __func__);
898 return NULL;
899 }
900 server_port->server_addr.node_id = node_id;
901 server_port->server_addr.port_id = port_id;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600902 server_port->xprt_info = xprt_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700903 list_add_tail(&server_port->list, &server->server_port_list);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700904
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -0600905 server_port->pdev.name = server->pdev_name;
906 server_port->pdev.id = server->next_pdev_id++;
907 server_port->pdev.dev.release = dummy_release;
908 platform_device_register(&server_port->pdev);
909
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700910 return server;
911}
912
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -0600913/**
914 * msm_ipc_router_destroy_server() - Remove server info from hash table
915 * @server: Server info to be removed.
916 * @node_id: Node/Processor ID in which the server is hosted.
917 * @port_id: Port ID within the node in which the server is hosted.
918 *
919 * This function removes the server_port identified using <node_id:port_id>
920 * from the server structure. If the server_port list under server structure
921 * is empty after removal, then remove the server structure from the server
922 * hash table.
923 * Note: Lock the server_list_lock before accessing this function.
924 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700925static void msm_ipc_router_destroy_server(struct msm_ipc_server *server,
926 uint32_t node_id, uint32_t port_id)
927{
928 struct msm_ipc_server_port *server_port;
929
930 if (!server)
931 return;
932
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700933 list_for_each_entry(server_port, &server->server_port_list, list) {
934 if ((server_port->server_addr.node_id == node_id) &&
935 (server_port->server_addr.port_id == port_id))
936 break;
937 }
938 if (server_port) {
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -0600939 platform_device_unregister(&server_port->pdev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700940 list_del(&server_port->list);
941 kfree(server_port);
942 }
943 if (list_empty(&server->server_port_list)) {
944 list_del(&server->list);
945 kfree(server);
946 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700947 return;
948}
949
950static int msm_ipc_router_send_control_msg(
951 struct msm_ipc_router_xprt_info *xprt_info,
952 union rr_control_msg *msg)
953{
954 struct rr_packet *pkt;
955 struct sk_buff *ipc_rtr_pkt;
956 struct rr_header *hdr;
957 int pkt_size;
958 void *data;
959 struct sk_buff_head *pkt_fragment_q;
960 int ret;
961
962 if (!xprt_info || ((msg->cmd != IPC_ROUTER_CTRL_CMD_HELLO) &&
963 !xprt_info->initialized)) {
964 pr_err("%s: xprt_info not initialized\n", __func__);
965 return -EINVAL;
966 }
967
968 if (xprt_info->remote_node_id == IPC_ROUTER_NID_LOCAL)
969 return 0;
970
971 pkt = kzalloc(sizeof(struct rr_packet), GFP_KERNEL);
972 if (!pkt) {
973 pr_err("%s: pkt alloc failed\n", __func__);
974 return -ENOMEM;
975 }
976
977 pkt_fragment_q = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
978 if (!pkt_fragment_q) {
979 pr_err("%s: pkt_fragment_q alloc failed\n", __func__);
980 kfree(pkt);
981 return -ENOMEM;
982 }
983 skb_queue_head_init(pkt_fragment_q);
984
985 pkt_size = IPC_ROUTER_HDR_SIZE + sizeof(*msg);
986 ipc_rtr_pkt = alloc_skb(pkt_size, GFP_KERNEL);
987 if (!ipc_rtr_pkt) {
988 pr_err("%s: ipc_rtr_pkt alloc failed\n", __func__);
989 kfree(pkt_fragment_q);
990 kfree(pkt);
991 return -ENOMEM;
992 }
993
994 skb_reserve(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
995 data = skb_put(ipc_rtr_pkt, sizeof(*msg));
996 memcpy(data, msg, sizeof(*msg));
997 hdr = (struct rr_header *)skb_push(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
998 if (!hdr) {
999 pr_err("%s: skb_push failed\n", __func__);
1000 kfree_skb(ipc_rtr_pkt);
1001 kfree(pkt_fragment_q);
1002 kfree(pkt);
1003 return -ENOMEM;
1004 }
1005
1006 hdr->version = IPC_ROUTER_VERSION;
1007 hdr->type = msg->cmd;
1008 hdr->src_node_id = IPC_ROUTER_NID_LOCAL;
1009 hdr->src_port_id = IPC_ROUTER_ADDRESS;
1010 hdr->confirm_rx = 0;
1011 hdr->size = sizeof(*msg);
1012 hdr->dst_node_id = xprt_info->remote_node_id;
1013 hdr->dst_port_id = IPC_ROUTER_ADDRESS;
1014 skb_queue_tail(pkt_fragment_q, ipc_rtr_pkt);
1015 pkt->pkt_fragment_q = pkt_fragment_q;
1016 pkt->length = pkt_size;
1017
1018 mutex_lock(&xprt_info->tx_lock);
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -07001019 ret = xprt_info->xprt->write(pkt, pkt_size, xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001020 mutex_unlock(&xprt_info->tx_lock);
1021
1022 release_pkt(pkt);
1023 return ret;
1024}
1025
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001026static int msm_ipc_router_send_server_list(uint32_t node_id,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001027 struct msm_ipc_router_xprt_info *xprt_info)
1028{
1029 union rr_control_msg ctl;
1030 struct msm_ipc_server *server;
1031 struct msm_ipc_server_port *server_port;
1032 int i;
1033
1034 if (!xprt_info || !xprt_info->initialized) {
1035 pr_err("%s: Xprt info not initialized\n", __func__);
1036 return -EINVAL;
1037 }
1038
1039 ctl.cmd = IPC_ROUTER_CTRL_CMD_NEW_SERVER;
1040
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001041 for (i = 0; i < SRV_HASH_SIZE; i++) {
1042 list_for_each_entry(server, &server_list[i], list) {
1043 ctl.srv.service = server->name.service;
1044 ctl.srv.instance = server->name.instance;
1045 list_for_each_entry(server_port,
1046 &server->server_port_list, list) {
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001047 if (server_port->server_addr.node_id !=
1048 node_id)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001049 continue;
1050
1051 ctl.srv.node_id =
1052 server_port->server_addr.node_id;
1053 ctl.srv.port_id =
1054 server_port->server_addr.port_id;
1055 msm_ipc_router_send_control_msg(xprt_info,
1056 &ctl);
1057 }
1058 }
1059 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001060
1061 return 0;
1062}
1063
1064#if defined(DEBUG)
1065static char *type_to_str(int i)
1066{
1067 switch (i) {
1068 case IPC_ROUTER_CTRL_CMD_DATA:
1069 return "data ";
1070 case IPC_ROUTER_CTRL_CMD_HELLO:
1071 return "hello ";
1072 case IPC_ROUTER_CTRL_CMD_BYE:
1073 return "bye ";
1074 case IPC_ROUTER_CTRL_CMD_NEW_SERVER:
1075 return "new_srvr";
1076 case IPC_ROUTER_CTRL_CMD_REMOVE_SERVER:
1077 return "rmv_srvr";
1078 case IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT:
1079 return "rmv_clnt";
1080 case IPC_ROUTER_CTRL_CMD_RESUME_TX:
1081 return "resum_tx";
1082 case IPC_ROUTER_CTRL_CMD_EXIT:
1083 return "cmd_exit";
1084 default:
1085 return "invalid";
1086 }
1087}
1088#endif
1089
1090static int broadcast_ctl_msg_locally(union rr_control_msg *msg)
1091{
1092 struct rr_packet *pkt;
1093 struct sk_buff *ipc_rtr_pkt;
1094 struct rr_header *hdr;
1095 int pkt_size;
1096 void *data;
1097 struct sk_buff_head *pkt_fragment_q;
1098 int ret;
1099
1100 pkt = kzalloc(sizeof(struct rr_packet), GFP_KERNEL);
1101 if (!pkt) {
1102 pr_err("%s: pkt alloc failed\n", __func__);
1103 return -ENOMEM;
1104 }
1105
1106 pkt_fragment_q = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
1107 if (!pkt_fragment_q) {
1108 pr_err("%s: pkt_fragment_q alloc failed\n", __func__);
1109 kfree(pkt);
1110 return -ENOMEM;
1111 }
1112 skb_queue_head_init(pkt_fragment_q);
1113
1114 pkt_size = IPC_ROUTER_HDR_SIZE + sizeof(*msg);
1115 ipc_rtr_pkt = alloc_skb(pkt_size, GFP_KERNEL);
1116 if (!ipc_rtr_pkt) {
1117 pr_err("%s: ipc_rtr_pkt alloc failed\n", __func__);
1118 kfree(pkt_fragment_q);
1119 kfree(pkt);
1120 return -ENOMEM;
1121 }
1122
1123 skb_reserve(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
1124 data = skb_put(ipc_rtr_pkt, sizeof(*msg));
1125 memcpy(data, msg, sizeof(*msg));
1126 hdr = (struct rr_header *)skb_push(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
1127 if (!hdr) {
1128 pr_err("%s: skb_push failed\n", __func__);
1129 kfree_skb(ipc_rtr_pkt);
1130 kfree(pkt_fragment_q);
1131 kfree(pkt);
1132 return -ENOMEM;
1133 }
1134 hdr->version = IPC_ROUTER_VERSION;
1135 hdr->type = msg->cmd;
1136 hdr->src_node_id = IPC_ROUTER_NID_LOCAL;
1137 hdr->src_port_id = IPC_ROUTER_ADDRESS;
1138 hdr->confirm_rx = 0;
1139 hdr->size = sizeof(*msg);
1140 hdr->dst_node_id = IPC_ROUTER_NID_LOCAL;
1141 hdr->dst_port_id = IPC_ROUTER_ADDRESS;
1142 skb_queue_tail(pkt_fragment_q, ipc_rtr_pkt);
1143 pkt->pkt_fragment_q = pkt_fragment_q;
1144 pkt->length = pkt_size;
1145
1146 ret = post_control_ports(pkt);
1147 release_pkt(pkt);
1148 return ret;
1149}
1150
1151static int broadcast_ctl_msg(union rr_control_msg *ctl)
1152{
1153 struct msm_ipc_router_xprt_info *xprt_info;
1154
1155 mutex_lock(&xprt_info_list_lock);
1156 list_for_each_entry(xprt_info, &xprt_info_list, list) {
1157 msm_ipc_router_send_control_msg(xprt_info, ctl);
1158 }
1159 mutex_unlock(&xprt_info_list_lock);
1160
1161 return 0;
1162}
1163
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001164static int relay_ctl_msg(struct msm_ipc_router_xprt_info *xprt_info,
1165 union rr_control_msg *ctl)
1166{
1167 struct msm_ipc_router_xprt_info *fwd_xprt_info;
1168
1169 if (!xprt_info || !ctl)
1170 return -EINVAL;
1171
1172 mutex_lock(&xprt_info_list_lock);
1173 list_for_each_entry(fwd_xprt_info, &xprt_info_list, list) {
1174 if (xprt_info->xprt->link_id != fwd_xprt_info->xprt->link_id)
1175 msm_ipc_router_send_control_msg(fwd_xprt_info, ctl);
1176 }
1177 mutex_unlock(&xprt_info_list_lock);
1178
1179 return 0;
1180}
1181
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001182static int relay_msg(struct msm_ipc_router_xprt_info *xprt_info,
1183 struct rr_packet *pkt)
1184{
1185 struct msm_ipc_router_xprt_info *fwd_xprt_info;
1186
1187 if (!xprt_info || !pkt)
1188 return -EINVAL;
1189
1190 mutex_lock(&xprt_info_list_lock);
1191 list_for_each_entry(fwd_xprt_info, &xprt_info_list, list) {
1192 mutex_lock(&fwd_xprt_info->tx_lock);
1193 if (xprt_info->xprt->link_id != fwd_xprt_info->xprt->link_id)
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -07001194 fwd_xprt_info->xprt->write(pkt, pkt->length,
1195 fwd_xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001196 mutex_unlock(&fwd_xprt_info->tx_lock);
1197 }
1198 mutex_unlock(&xprt_info_list_lock);
1199 return 0;
1200}
1201
1202static int forward_msg(struct msm_ipc_router_xprt_info *xprt_info,
1203 struct rr_packet *pkt)
1204{
1205 uint32_t dst_node_id;
1206 struct sk_buff *head_pkt;
1207 struct rr_header *hdr;
1208 struct msm_ipc_router_xprt_info *fwd_xprt_info;
1209 struct msm_ipc_routing_table_entry *rt_entry;
1210
1211 if (!xprt_info || !pkt)
1212 return -EINVAL;
1213
1214 head_pkt = skb_peek(pkt->pkt_fragment_q);
1215 if (!head_pkt)
1216 return -EINVAL;
1217
1218 hdr = (struct rr_header *)head_pkt->data;
1219 dst_node_id = hdr->dst_node_id;
1220 mutex_lock(&routing_table_lock);
1221 rt_entry = lookup_routing_table(dst_node_id);
1222 if (!(rt_entry) || !(rt_entry->xprt_info)) {
1223 mutex_unlock(&routing_table_lock);
1224 pr_err("%s: Routing table not initialized\n", __func__);
1225 return -ENODEV;
1226 }
1227
1228 mutex_lock(&rt_entry->lock);
1229 fwd_xprt_info = rt_entry->xprt_info;
1230 mutex_lock(&fwd_xprt_info->tx_lock);
1231 if (xprt_info->remote_node_id == fwd_xprt_info->remote_node_id) {
1232 mutex_unlock(&fwd_xprt_info->tx_lock);
1233 mutex_unlock(&rt_entry->lock);
1234 mutex_unlock(&routing_table_lock);
1235 pr_err("%s: Discarding Command to route back\n", __func__);
1236 return -EINVAL;
1237 }
1238
1239 if (xprt_info->xprt->link_id == fwd_xprt_info->xprt->link_id) {
1240 mutex_unlock(&fwd_xprt_info->tx_lock);
1241 mutex_unlock(&rt_entry->lock);
1242 mutex_unlock(&routing_table_lock);
1243 pr_err("%s: DST in the same cluster\n", __func__);
1244 return 0;
1245 }
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -07001246 fwd_xprt_info->xprt->write(pkt, pkt->length, fwd_xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001247 mutex_unlock(&fwd_xprt_info->tx_lock);
1248 mutex_unlock(&rt_entry->lock);
1249 mutex_unlock(&routing_table_lock);
1250
1251 return 0;
1252}
1253
Karthikeyan Ramasubramaniandc9c4442013-05-02 17:25:54 -06001254static int msm_ipc_router_send_remove_client(struct comm_mode_info *mode_info,
1255 uint32_t node_id, uint32_t port_id)
1256{
1257 union rr_control_msg msg;
1258 struct msm_ipc_router_xprt_info *tmp_xprt_info;
1259 int mode;
1260 void *xprt_info;
1261 int rc = 0;
1262
1263 if (!mode_info) {
1264 pr_err("%s: NULL mode_info\n", __func__);
1265 return -EINVAL;
1266 }
1267 mode = mode_info->mode;
1268 xprt_info = mode_info->xprt_info;
1269
1270 msg.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT;
1271 msg.cli.node_id = node_id;
1272 msg.cli.port_id = port_id;
1273
1274 if ((mode == SINGLE_LINK_MODE) && xprt_info) {
1275 mutex_lock(&xprt_info_list_lock);
1276 list_for_each_entry(tmp_xprt_info, &xprt_info_list, list) {
1277 if (tmp_xprt_info != xprt_info)
1278 continue;
1279 msm_ipc_router_send_control_msg(tmp_xprt_info, &msg);
1280 break;
1281 }
1282 mutex_unlock(&xprt_info_list_lock);
1283 } else if ((mode == SINGLE_LINK_MODE) && !xprt_info) {
1284 broadcast_ctl_msg_locally(&msg);
1285 } else if (mode == MULTI_LINK_MODE) {
1286 broadcast_ctl_msg(&msg);
1287 broadcast_ctl_msg_locally(&msg);
1288 } else if (mode != NULL_MODE) {
1289 pr_err("%s: Invalid mode(%d) + xprt_inf(%p) for %08x:%08x\n",
1290 __func__, mode, xprt_info, node_id, port_id);
1291 rc = -EINVAL;
1292 }
1293 return rc;
1294}
1295
1296static void update_comm_mode_info(struct comm_mode_info *mode_info,
1297 struct msm_ipc_router_xprt_info *xprt_info)
1298{
1299 if (!mode_info) {
1300 pr_err("%s: NULL mode_info\n", __func__);
1301 return;
1302 }
1303
1304 if (mode_info->mode == NULL_MODE) {
1305 mode_info->xprt_info = xprt_info;
1306 mode_info->mode = SINGLE_LINK_MODE;
1307 } else if (mode_info->mode == SINGLE_LINK_MODE &&
1308 mode_info->xprt_info != xprt_info) {
1309 mode_info->mode = MULTI_LINK_MODE;
1310 }
1311
1312 return;
1313}
1314
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001315static void reset_remote_port_info(uint32_t node_id, uint32_t port_id)
1316{
1317 struct msm_ipc_router_remote_port *rport_ptr;
1318
1319 rport_ptr = msm_ipc_router_lookup_remote_port(node_id, port_id);
1320 if (!rport_ptr) {
1321 pr_err("%s: No such remote port %08x:%08x\n",
1322 __func__, node_id, port_id);
1323 return;
1324 }
1325 mutex_lock(&rport_ptr->quota_lock);
1326 rport_ptr->restart_state = RESTART_PEND;
Zaheerulla Meera34fc662013-04-17 01:16:47 +05301327 msm_ipc_router_free_resume_tx_port(rport_ptr);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001328 mutex_unlock(&rport_ptr->quota_lock);
1329 return;
1330}
1331
1332static void msm_ipc_cleanup_remote_server_info(
1333 struct msm_ipc_router_xprt_info *xprt_info)
1334{
1335 struct msm_ipc_server *svr, *tmp_svr;
1336 struct msm_ipc_server_port *svr_port, *tmp_svr_port;
1337 int i;
1338 union rr_control_msg ctl;
1339
1340 if (!xprt_info) {
1341 pr_err("%s: Invalid xprt_info\n", __func__);
1342 return;
1343 }
1344
1345 ctl.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_SERVER;
1346 mutex_lock(&server_list_lock);
1347 for (i = 0; i < SRV_HASH_SIZE; i++) {
1348 list_for_each_entry_safe(svr, tmp_svr, &server_list[i], list) {
1349 ctl.srv.service = svr->name.service;
1350 ctl.srv.instance = svr->name.instance;
1351 list_for_each_entry_safe(svr_port, tmp_svr_port,
1352 &svr->server_port_list, list) {
1353 if (svr_port->xprt_info != xprt_info)
1354 continue;
1355 D("Remove server %08x:%08x - %08x:%08x",
1356 ctl.srv.service, ctl.srv.instance,
1357 svr_port->server_addr.node_id,
1358 svr_port->server_addr.port_id);
1359 reset_remote_port_info(
1360 svr_port->server_addr.node_id,
1361 svr_port->server_addr.port_id);
1362 ctl.srv.node_id = svr_port->server_addr.node_id;
1363 ctl.srv.port_id = svr_port->server_addr.port_id;
1364 relay_ctl_msg(xprt_info, &ctl);
1365 broadcast_ctl_msg_locally(&ctl);
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -06001366 platform_device_unregister(&svr_port->pdev);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001367 list_del(&svr_port->list);
1368 kfree(svr_port);
1369 }
1370 if (list_empty(&svr->server_port_list)) {
1371 list_del(&svr->list);
1372 kfree(svr);
1373 }
1374 }
1375 }
1376 mutex_unlock(&server_list_lock);
1377}
1378
1379static void msm_ipc_cleanup_remote_client_info(
1380 struct msm_ipc_router_xprt_info *xprt_info)
1381{
1382 struct msm_ipc_routing_table_entry *rt_entry;
1383 struct msm_ipc_router_remote_port *rport_ptr;
1384 int i, j;
1385 union rr_control_msg ctl;
1386
1387 if (!xprt_info) {
1388 pr_err("%s: Invalid xprt_info\n", __func__);
1389 return;
1390 }
1391
1392 ctl.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT;
1393 mutex_lock(&routing_table_lock);
1394 for (i = 0; i < RT_HASH_SIZE; i++) {
1395 list_for_each_entry(rt_entry, &routing_table[i], list) {
1396 mutex_lock(&rt_entry->lock);
1397 if (rt_entry->xprt_info != xprt_info) {
1398 mutex_unlock(&rt_entry->lock);
1399 continue;
1400 }
1401 for (j = 0; j < RP_HASH_SIZE; j++) {
1402 list_for_each_entry(rport_ptr,
1403 &rt_entry->remote_port_list[j], list) {
1404 if (rport_ptr->restart_state ==
1405 RESTART_PEND)
1406 continue;
1407 mutex_lock(&rport_ptr->quota_lock);
1408 rport_ptr->restart_state = RESTART_PEND;
Zaheerulla Meera34fc662013-04-17 01:16:47 +05301409 msm_ipc_router_free_resume_tx_port(
1410 rport_ptr);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001411 mutex_unlock(&rport_ptr->quota_lock);
1412 ctl.cli.node_id = rport_ptr->node_id;
1413 ctl.cli.port_id = rport_ptr->port_id;
1414 broadcast_ctl_msg_locally(&ctl);
1415 }
1416 }
1417 mutex_unlock(&rt_entry->lock);
1418 }
1419 }
1420 mutex_unlock(&routing_table_lock);
1421}
1422
1423static void msm_ipc_cleanup_remote_port_info(uint32_t node_id)
1424{
1425 struct msm_ipc_routing_table_entry *rt_entry, *tmp_rt_entry;
1426 struct msm_ipc_router_remote_port *rport_ptr, *tmp_rport_ptr;
1427 int i, j;
1428
1429 mutex_lock(&routing_table_lock);
1430 for (i = 0; i < RT_HASH_SIZE; i++) {
1431 list_for_each_entry_safe(rt_entry, tmp_rt_entry,
1432 &routing_table[i], list) {
1433 mutex_lock(&rt_entry->lock);
1434 if (rt_entry->neighbor_node_id != node_id) {
1435 mutex_unlock(&rt_entry->lock);
1436 continue;
1437 }
1438 for (j = 0; j < RP_HASH_SIZE; j++) {
1439 list_for_each_entry_safe(rport_ptr,
1440 tmp_rport_ptr,
1441 &rt_entry->remote_port_list[j], list) {
1442 list_del(&rport_ptr->list);
1443 kfree(rport_ptr);
1444 }
1445 }
1446 mutex_unlock(&rt_entry->lock);
1447 }
1448 }
1449 mutex_unlock(&routing_table_lock);
1450}
1451
1452static void msm_ipc_cleanup_routing_table(
1453 struct msm_ipc_router_xprt_info *xprt_info)
1454{
1455 int i;
1456 struct msm_ipc_routing_table_entry *rt_entry;
1457
1458 if (!xprt_info) {
1459 pr_err("%s: Invalid xprt_info\n", __func__);
1460 return;
1461 }
1462
1463 mutex_lock(&routing_table_lock);
1464 for (i = 0; i < RT_HASH_SIZE; i++) {
1465 list_for_each_entry(rt_entry, &routing_table[i], list) {
1466 mutex_lock(&rt_entry->lock);
1467 if (rt_entry->xprt_info == xprt_info)
1468 rt_entry->xprt_info = NULL;
1469 mutex_unlock(&rt_entry->lock);
1470 }
1471 }
1472 mutex_unlock(&routing_table_lock);
1473}
1474
1475static void modem_reset_cleanup(struct msm_ipc_router_xprt_info *xprt_info)
1476{
1477
1478 if (!xprt_info) {
1479 pr_err("%s: Invalid xprt_info\n", __func__);
1480 return;
1481 }
1482
1483 msm_ipc_cleanup_remote_server_info(xprt_info);
1484 msm_ipc_cleanup_remote_client_info(xprt_info);
1485 msm_ipc_cleanup_routing_table(xprt_info);
1486}
1487
Karthikeyan Ramasubramanian1668cc62012-09-23 22:23:36 -06001488/**
1489 * sync_sec_rule() - Synchrnoize the security rule into the server structure
1490 * @server: Server structure where the rule has to be synchronized.
1491 * @rule: Security tule to be synchronized.
1492 *
1493 * This function is used to update the server structure with the security
1494 * rule configured for the <service:instance> corresponding to that server.
1495 */
1496static void sync_sec_rule(struct msm_ipc_server *server, void *rule)
1497{
1498 struct msm_ipc_server_port *server_port;
1499 struct msm_ipc_router_remote_port *rport_ptr = NULL;
1500
1501 list_for_each_entry(server_port, &server->server_port_list, list) {
1502 rport_ptr = msm_ipc_router_lookup_remote_port(
1503 server_port->server_addr.node_id,
1504 server_port->server_addr.port_id);
1505 if (!rport_ptr)
1506 continue;
1507 rport_ptr->sec_rule = rule;
1508 }
1509 server->synced_sec_rule = 1;
1510}
1511
1512/**
1513 * msm_ipc_sync_sec_rule() - Sync the security rule to the service
1514 * @service: Service for which the rule has to be synchronized.
1515 * @instance: Instance for which the rule has to be synchronized.
1516 * @rule: Security rule to be synchronized.
1517 *
1518 * This function is used to syncrhonize the security rule with the server
1519 * hash table, if the user-space script configures the rule after the service
1520 * has come up. This function is used to synchronize the security rule to a
1521 * specific service and optionally a specific instance.
1522 */
1523void msm_ipc_sync_sec_rule(uint32_t service, uint32_t instance, void *rule)
1524{
1525 int key = (service & (SRV_HASH_SIZE - 1));
1526 struct msm_ipc_server *server;
1527
1528 mutex_lock(&server_list_lock);
1529 list_for_each_entry(server, &server_list[key], list) {
1530 if (server->name.service != service)
1531 continue;
1532
1533 if (server->name.instance != instance &&
1534 instance != ALL_INSTANCE)
1535 continue;
1536
1537 /*
1538 * If the rule applies to all instances and if the specific
1539 * instance of a service has a rule synchronized already,
1540 * do not apply the rule for that specific instance.
1541 */
1542 if (instance == ALL_INSTANCE && server->synced_sec_rule)
1543 continue;
1544
1545 sync_sec_rule(server, rule);
1546 }
1547 mutex_unlock(&server_list_lock);
1548}
1549
1550/**
1551 * msm_ipc_sync_default_sec_rule() - Default security rule to all services
1552 * @rule: Security rule to be synchronized.
1553 *
1554 * This function is used to syncrhonize the security rule with the server
1555 * hash table, if the user-space script configures the rule after the service
1556 * has come up. This function is used to synchronize the security rule that
1557 * applies to all services, if the concerned service do not have any rule
1558 * defined.
1559 */
1560void msm_ipc_sync_default_sec_rule(void *rule)
1561{
1562 int key;
1563 struct msm_ipc_server *server;
1564
1565 mutex_lock(&server_list_lock);
1566 for (key = 0; key < SRV_HASH_SIZE; key++) {
1567 list_for_each_entry(server, &server_list[key], list) {
1568 if (server->synced_sec_rule)
1569 continue;
1570
1571 sync_sec_rule(server, rule);
1572 }
1573 }
1574 mutex_unlock(&server_list_lock);
1575}
1576
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001577static int process_hello_msg(struct msm_ipc_router_xprt_info *xprt_info,
1578 struct rr_header *hdr)
1579{
1580 int i, rc = 0;
1581 union rr_control_msg ctl;
1582 struct msm_ipc_routing_table_entry *rt_entry;
1583
1584 if (!hdr)
1585 return -EINVAL;
1586
1587 RR("o HELLO NID %d\n", hdr->src_node_id);
1588
1589 xprt_info->remote_node_id = hdr->src_node_id;
1590 /*
1591 * Find the entry from Routing Table corresponding to Node ID.
1592 * Under SSR, an entry will be found. When the system boots up
1593 * for the 1st time, an entry will not be found and hence allocate
1594 * an entry. Update the entry with the Node ID that it corresponds
1595 * to and the XPRT through which it can be reached.
1596 */
1597 mutex_lock(&routing_table_lock);
1598 rt_entry = lookup_routing_table(hdr->src_node_id);
1599 if (!rt_entry) {
1600 rt_entry = alloc_routing_table_entry(hdr->src_node_id);
1601 if (!rt_entry) {
1602 mutex_unlock(&routing_table_lock);
1603 pr_err("%s: rt_entry allocation failed\n", __func__);
1604 return -ENOMEM;
1605 }
1606 add_routing_table_entry(rt_entry);
1607 }
1608 mutex_lock(&rt_entry->lock);
1609 rt_entry->neighbor_node_id = xprt_info->remote_node_id;
1610 rt_entry->xprt_info = xprt_info;
1611 mutex_unlock(&rt_entry->lock);
1612 mutex_unlock(&routing_table_lock);
1613
1614 /* Cleanup any remote ports, if the node is coming out of reset */
1615 msm_ipc_cleanup_remote_port_info(xprt_info->remote_node_id);
1616
1617 /* Send a reply HELLO message */
1618 memset(&ctl, 0, sizeof(ctl));
1619 ctl.cmd = IPC_ROUTER_CTRL_CMD_HELLO;
1620 rc = msm_ipc_router_send_control_msg(xprt_info, &ctl);
1621 if (rc < 0) {
1622 pr_err("%s: Error sending reply HELLO message\n", __func__);
1623 return rc;
1624 }
1625 xprt_info->initialized = 1;
1626
1627 /*
1628 * Send list of servers from the local node and from nodes
1629 * outside the mesh network in which this XPRT is part of.
1630 */
Karthikeyan Ramasubramaniane8ad5352012-10-31 15:12:08 -06001631 mutex_lock(&server_list_lock);
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001632 mutex_lock(&routing_table_lock);
1633 for (i = 0; i < RT_HASH_SIZE; i++) {
1634 list_for_each_entry(rt_entry, &routing_table[i], list) {
1635 if ((rt_entry->node_id != IPC_ROUTER_NID_LOCAL) &&
Karthikeyan Ramasubramanian72ad5792013-01-30 14:17:57 -07001636 (!rt_entry->xprt_info ||
1637 (rt_entry->xprt_info->xprt->link_id ==
1638 xprt_info->xprt->link_id)))
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001639 continue;
1640 rc = msm_ipc_router_send_server_list(rt_entry->node_id,
1641 xprt_info);
1642 if (rc < 0) {
1643 mutex_unlock(&routing_table_lock);
Karthikeyan Ramasubramaniane8ad5352012-10-31 15:12:08 -06001644 mutex_unlock(&server_list_lock);
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001645 return rc;
1646 }
1647 }
1648 }
1649 mutex_unlock(&routing_table_lock);
Karthikeyan Ramasubramaniane8ad5352012-10-31 15:12:08 -06001650 mutex_unlock(&server_list_lock);
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001651 RR("HELLO message processed\n");
1652 return rc;
1653}
1654
Karthikeyan Ramasubramanian4b4120e2013-05-17 18:18:20 -06001655static int process_resume_tx_msg(union rr_control_msg *msg,
1656 struct rr_packet *pkt)
1657{
1658 struct msm_ipc_router_remote_port *rport_ptr;
1659
1660 RR("o RESUME_TX id=%d:%08x\n", msg->cli.node_id, msg->cli.port_id);
1661
1662 rport_ptr = msm_ipc_router_lookup_remote_port(msg->cli.node_id,
1663 msg->cli.port_id);
1664 if (!rport_ptr) {
1665 pr_err("%s: Unable to resume client\n", __func__);
1666 return -ENODEV;
1667 }
1668 mutex_lock(&rport_ptr->quota_lock);
1669 rport_ptr->tx_quota_cnt = 0;
1670 post_resume_tx(rport_ptr, pkt);
1671 mutex_unlock(&rport_ptr->quota_lock);
1672 return 0;
1673}
1674
1675static int process_new_server_msg(struct msm_ipc_router_xprt_info *xprt_info,
1676 union rr_control_msg *msg, struct rr_packet *pkt)
1677{
1678 struct msm_ipc_routing_table_entry *rt_entry;
1679 struct msm_ipc_server *server;
1680 struct msm_ipc_router_remote_port *rport_ptr;
1681
1682 if (msg->srv.instance == 0) {
1683 pr_err("%s: Server %08x create rejected, version = 0\n",
1684 __func__, msg->srv.service);
1685 return -EINVAL;
1686 }
1687
1688 RR("o NEW_SERVER id=%d:%08x service=%08x:%08x\n", msg->srv.node_id,
1689 msg->srv.port_id, msg->srv.service, msg->srv.instance);
1690 /*
1691 * Find the entry from Routing Table corresponding to Node ID.
1692 * Under SSR, an entry will be found. When the subsystem hosting
1693 * service is not adjacent, an entry will not be found and hence
1694 * allocate an entry. Update the entry with the Node ID that it
1695 * corresponds to and the XPRT through which it can be reached.
1696 */
1697 mutex_lock(&routing_table_lock);
1698 rt_entry = lookup_routing_table(msg->srv.node_id);
1699 if (!rt_entry) {
1700 rt_entry = alloc_routing_table_entry(msg->srv.node_id);
1701 if (!rt_entry) {
1702 mutex_unlock(&routing_table_lock);
1703 pr_err("%s: rt_entry allocation failed\n", __func__);
1704 return -ENOMEM;
1705 }
1706 mutex_lock(&rt_entry->lock);
1707 rt_entry->neighbor_node_id = xprt_info->remote_node_id;
1708 rt_entry->xprt_info = xprt_info;
1709 mutex_unlock(&rt_entry->lock);
1710 add_routing_table_entry(rt_entry);
1711 }
1712 mutex_unlock(&routing_table_lock);
1713
1714 /*
1715 * If the service does not exist already in the database, create and
1716 * store the service info. Create a remote port structure in which
1717 * the service is hosted and cache the security rule for the service
1718 * in that remote port structure.
1719 */
1720 mutex_lock(&server_list_lock);
1721 server = msm_ipc_router_lookup_server(msg->srv.service,
1722 msg->srv.instance, msg->srv.node_id, msg->srv.port_id);
1723 if (!server) {
1724 server = msm_ipc_router_create_server(
1725 msg->srv.service, msg->srv.instance,
1726 msg->srv.node_id, msg->srv.port_id, xprt_info);
1727 if (!server) {
1728 mutex_unlock(&server_list_lock);
1729 pr_err("%s: Server Create failed\n", __func__);
1730 return -ENOMEM;
1731 }
1732
1733 if (!msm_ipc_router_lookup_remote_port(
1734 msg->srv.node_id, msg->srv.port_id)) {
1735 rport_ptr = msm_ipc_router_create_remote_port(
1736 msg->srv.node_id, msg->srv.port_id);
1737 if (!rport_ptr) {
1738 mutex_unlock(&server_list_lock);
1739 return -ENOMEM;
1740 }
1741 rport_ptr->sec_rule = msm_ipc_get_security_rule(
1742 msg->srv.service,
1743 msg->srv.instance);
1744 }
1745 }
1746 mutex_unlock(&server_list_lock);
1747
1748 /*
1749 * Relay the new server message to other subsystems that do not belong
1750 * to the cluster from which this message is received. Notify the
1751 * local clients waiting for this service.
1752 */
1753 relay_msg(xprt_info, pkt);
1754 post_control_ports(pkt);
1755 return 0;
1756}
1757
1758static int process_rmv_server_msg(struct msm_ipc_router_xprt_info *xprt_info,
1759 union rr_control_msg *msg, struct rr_packet *pkt)
1760{
1761 struct msm_ipc_server *server;
1762
1763 RR("o REMOVE_SERVER service=%08x:%d\n",
1764 msg->srv.service, msg->srv.instance);
1765 mutex_lock(&server_list_lock);
1766 server = msm_ipc_router_lookup_server(msg->srv.service,
1767 msg->srv.instance, msg->srv.node_id, msg->srv.port_id);
1768 if (server) {
1769 msm_ipc_router_destroy_server(server, msg->srv.node_id,
1770 msg->srv.port_id);
1771 /*
1772 * Relay the new server message to other subsystems that do not
1773 * belong to the cluster from which this message is received.
1774 * Notify the local clients communicating with the service.
1775 */
1776 relay_msg(xprt_info, pkt);
1777 post_control_ports(pkt);
1778 }
1779 mutex_unlock(&server_list_lock);
1780 return 0;
1781}
1782
1783static int process_rmv_client_msg(struct msm_ipc_router_xprt_info *xprt_info,
1784 union rr_control_msg *msg, struct rr_packet *pkt)
1785{
1786 struct msm_ipc_router_remote_port *rport_ptr;
1787
1788 RR("o REMOVE_CLIENT id=%d:%08x\n", msg->cli.node_id, msg->cli.port_id);
1789 rport_ptr = msm_ipc_router_lookup_remote_port(msg->cli.node_id,
1790 msg->cli.port_id);
1791 if (rport_ptr)
1792 msm_ipc_router_destroy_remote_port(rport_ptr);
1793
1794 relay_msg(xprt_info, pkt);
1795 post_control_ports(pkt);
1796 return 0;
1797}
1798
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001799static int process_control_msg(struct msm_ipc_router_xprt_info *xprt_info,
1800 struct rr_packet *pkt)
1801{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001802 union rr_control_msg *msg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001803 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001804 struct sk_buff *temp_ptr;
1805 struct rr_header *hdr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001806
1807 if (pkt->length != (IPC_ROUTER_HDR_SIZE + sizeof(*msg))) {
1808 pr_err("%s: r2r msg size %d != %d\n", __func__, pkt->length,
1809 (IPC_ROUTER_HDR_SIZE + sizeof(*msg)));
1810 return -EINVAL;
1811 }
1812
1813 temp_ptr = skb_peek(pkt->pkt_fragment_q);
Karthikeyan Ramasubramanian9024dd82011-12-19 18:44:19 -07001814 if (!temp_ptr) {
1815 pr_err("%s: pkt_fragment_q is empty\n", __func__);
1816 return -EINVAL;
1817 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001818 hdr = (struct rr_header *)temp_ptr->data;
Karthikeyan Ramasubramanian9024dd82011-12-19 18:44:19 -07001819 if (!hdr) {
1820 pr_err("%s: No data inside the skb\n", __func__);
1821 return -EINVAL;
1822 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001823 msg = (union rr_control_msg *)((char *)hdr + IPC_ROUTER_HDR_SIZE);
1824
1825 switch (msg->cmd) {
1826 case IPC_ROUTER_CTRL_CMD_HELLO:
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001827 rc = process_hello_msg(xprt_info, hdr);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001828 break;
1829 case IPC_ROUTER_CTRL_CMD_RESUME_TX:
Karthikeyan Ramasubramanian4b4120e2013-05-17 18:18:20 -06001830 rc = process_resume_tx_msg(msg, pkt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001831 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001832 case IPC_ROUTER_CTRL_CMD_NEW_SERVER:
Karthikeyan Ramasubramanian4b4120e2013-05-17 18:18:20 -06001833 rc = process_new_server_msg(xprt_info, msg, pkt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001834 break;
1835 case IPC_ROUTER_CTRL_CMD_REMOVE_SERVER:
Karthikeyan Ramasubramanian4b4120e2013-05-17 18:18:20 -06001836 rc = process_rmv_server_msg(xprt_info, msg, pkt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001837 break;
1838 case IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT:
Karthikeyan Ramasubramanian4b4120e2013-05-17 18:18:20 -06001839 rc = process_rmv_client_msg(xprt_info, msg, pkt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001840 break;
1841 case IPC_ROUTER_CTRL_CMD_PING:
1842 /* No action needed for ping messages received */
1843 RR("o PING\n");
1844 break;
1845 default:
1846 RR("o UNKNOWN(%08x)\n", msg->cmd);
1847 rc = -ENOSYS;
1848 }
1849
1850 return rc;
1851}
1852
1853static void do_read_data(struct work_struct *work)
1854{
1855 struct rr_header *hdr;
1856 struct rr_packet *pkt = NULL;
1857 struct msm_ipc_port *port_ptr;
1858 struct sk_buff *head_skb;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001859 struct msm_ipc_router_remote_port *rport_ptr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001860 uint32_t resume_tx, resume_tx_node_id, resume_tx_port_id;
1861
1862 struct msm_ipc_router_xprt_info *xprt_info =
1863 container_of(work,
1864 struct msm_ipc_router_xprt_info,
1865 read_data);
1866
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001867 while ((pkt = rr_read(xprt_info)) != NULL) {
1868 if (pkt->length < IPC_ROUTER_HDR_SIZE ||
1869 pkt->length > MAX_IPC_PKT_SIZE) {
1870 pr_err("%s: Invalid pkt length %d\n",
1871 __func__, pkt->length);
1872 goto fail_data;
1873 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001874
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001875 head_skb = skb_peek(pkt->pkt_fragment_q);
1876 if (!head_skb) {
1877 pr_err("%s: head_skb is invalid\n", __func__);
1878 goto fail_data;
1879 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001880
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001881 hdr = (struct rr_header *)(head_skb->data);
Karthikeyan Ramasubramanian682ebcc2013-03-22 10:47:20 -06001882 RAW("ver=%d type=%d src=%d:%08x crx=%d siz=%d dst=%d:%08x\n",
1883 hdr->version, hdr->type, hdr->src_node_id,
1884 hdr->src_port_id, hdr->confirm_rx, hdr->size,
1885 hdr->dst_node_id, hdr->dst_port_id);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001886
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001887 if (hdr->version != IPC_ROUTER_VERSION) {
1888 pr_err("version %d != %d\n",
1889 hdr->version, IPC_ROUTER_VERSION);
1890 goto fail_data;
1891 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001892
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001893 if ((hdr->dst_node_id != IPC_ROUTER_NID_LOCAL) &&
1894 ((hdr->type == IPC_ROUTER_CTRL_CMD_RESUME_TX) ||
1895 (hdr->type == IPC_ROUTER_CTRL_CMD_DATA))) {
1896 forward_msg(xprt_info, pkt);
1897 release_pkt(pkt);
1898 continue;
1899 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001900
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001901 if ((hdr->dst_port_id == IPC_ROUTER_ADDRESS) ||
1902 (hdr->type == IPC_ROUTER_CTRL_CMD_HELLO)) {
1903 process_control_msg(xprt_info, pkt);
1904 release_pkt(pkt);
1905 continue;
1906 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001907#if defined(CONFIG_MSM_SMD_LOGGING)
1908#if defined(DEBUG)
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001909 if (msm_ipc_router_debug_mask & SMEM_LOG) {
1910 smem_log_event((SMEM_LOG_PROC_ID_APPS |
1911 SMEM_LOG_RPC_ROUTER_EVENT_BASE |
1912 IPC_ROUTER_LOG_EVENT_RX),
1913 (hdr->src_node_id << 24) |
1914 (hdr->src_port_id & 0xffffff),
1915 (hdr->dst_node_id << 24) |
1916 (hdr->dst_port_id & 0xffffff),
1917 (hdr->type << 24) | (hdr->confirm_rx << 16) |
1918 (hdr->size & 0xffff));
1919 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001920#endif
1921#endif
1922
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001923 resume_tx = hdr->confirm_rx;
1924 resume_tx_node_id = hdr->dst_node_id;
1925 resume_tx_port_id = hdr->dst_port_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001926
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001927 rport_ptr = msm_ipc_router_lookup_remote_port(hdr->src_node_id,
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06001928 hdr->src_port_id);
1929
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001930 mutex_lock(&local_ports_lock);
1931 port_ptr = msm_ipc_router_lookup_local_port(hdr->dst_port_id);
1932 if (!port_ptr) {
1933 pr_err("%s: No local port id %08x\n", __func__,
1934 hdr->dst_port_id);
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06001935 mutex_unlock(&local_ports_lock);
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001936 release_pkt(pkt);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001937 goto process_done;
1938 }
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001939
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001940 if (!rport_ptr) {
1941 rport_ptr = msm_ipc_router_create_remote_port(
1942 hdr->src_node_id,
1943 hdr->src_port_id);
1944 if (!rport_ptr) {
1945 pr_err("%s: Rmt Prt %08x:%08x create failed\n",
1946 __func__, hdr->src_node_id,
1947 hdr->src_port_id);
1948 mutex_unlock(&local_ports_lock);
1949 goto process_done;
1950 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001951 }
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001952
Karthikeyan Ramasubramaniand1af6252013-05-17 15:19:56 -06001953 post_pkt_to_port(port_ptr, pkt, 0);
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -06001954 mutex_unlock(&local_ports_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001955
1956process_done:
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001957 if (resume_tx) {
1958 union rr_control_msg msg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001959
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001960 msg.cmd = IPC_ROUTER_CTRL_CMD_RESUME_TX;
1961 msg.cli.node_id = resume_tx_node_id;
1962 msg.cli.port_id = resume_tx_port_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001963
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001964 RR("x RESUME_TX id=%d:%08x\n",
1965 msg.cli.node_id, msg.cli.port_id);
1966 msm_ipc_router_send_control_msg(xprt_info, &msg);
1967 }
1968
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001969 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001970 return;
1971
1972fail_data:
1973 release_pkt(pkt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001974 pr_err("ipc_router has died\n");
1975}
1976
1977int msm_ipc_router_register_server(struct msm_ipc_port *port_ptr,
1978 struct msm_ipc_addr *name)
1979{
1980 struct msm_ipc_server *server;
1981 unsigned long flags;
1982 union rr_control_msg ctl;
1983
1984 if (!port_ptr || !name)
1985 return -EINVAL;
1986
1987 if (name->addrtype != MSM_IPC_ADDR_NAME)
1988 return -EINVAL;
1989
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001990 mutex_lock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001991 server = msm_ipc_router_lookup_server(name->addr.port_name.service,
1992 name->addr.port_name.instance,
1993 IPC_ROUTER_NID_LOCAL,
1994 port_ptr->this_port.port_id);
1995 if (server) {
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001996 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001997 pr_err("%s: Server already present\n", __func__);
1998 return -EINVAL;
1999 }
2000
2001 server = msm_ipc_router_create_server(name->addr.port_name.service,
2002 name->addr.port_name.instance,
2003 IPC_ROUTER_NID_LOCAL,
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002004 port_ptr->this_port.port_id,
2005 NULL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002006 if (!server) {
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002007 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002008 pr_err("%s: Server Creation failed\n", __func__);
2009 return -EINVAL;
2010 }
2011
2012 ctl.cmd = IPC_ROUTER_CTRL_CMD_NEW_SERVER;
2013 ctl.srv.service = server->name.service;
2014 ctl.srv.instance = server->name.instance;
2015 ctl.srv.node_id = IPC_ROUTER_NID_LOCAL;
2016 ctl.srv.port_id = port_ptr->this_port.port_id;
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002017 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002018 broadcast_ctl_msg(&ctl);
2019 spin_lock_irqsave(&port_ptr->port_lock, flags);
2020 port_ptr->type = SERVER_PORT;
Karthikeyan Ramasubramaniandc9c4442013-05-02 17:25:54 -06002021 port_ptr->mode_info.mode = MULTI_LINK_MODE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002022 port_ptr->port_name.service = server->name.service;
2023 port_ptr->port_name.instance = server->name.instance;
2024 spin_unlock_irqrestore(&port_ptr->port_lock, flags);
2025 return 0;
2026}
2027
2028int msm_ipc_router_unregister_server(struct msm_ipc_port *port_ptr)
2029{
2030 struct msm_ipc_server *server;
2031 unsigned long flags;
2032 union rr_control_msg ctl;
2033
2034 if (!port_ptr)
2035 return -EINVAL;
2036
2037 if (port_ptr->type != SERVER_PORT) {
2038 pr_err("%s: Trying to unregister a non-server port\n",
2039 __func__);
2040 return -EINVAL;
2041 }
2042
2043 if (port_ptr->this_port.node_id != IPC_ROUTER_NID_LOCAL) {
2044 pr_err("%s: Trying to unregister a remote server locally\n",
2045 __func__);
2046 return -EINVAL;
2047 }
2048
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002049 mutex_lock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002050 server = msm_ipc_router_lookup_server(port_ptr->port_name.service,
2051 port_ptr->port_name.instance,
2052 port_ptr->this_port.node_id,
2053 port_ptr->this_port.port_id);
2054 if (!server) {
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002055 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002056 pr_err("%s: Server lookup failed\n", __func__);
2057 return -ENODEV;
2058 }
2059
2060 ctl.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_SERVER;
2061 ctl.srv.service = server->name.service;
2062 ctl.srv.instance = server->name.instance;
2063 ctl.srv.node_id = IPC_ROUTER_NID_LOCAL;
2064 ctl.srv.port_id = port_ptr->this_port.port_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002065 msm_ipc_router_destroy_server(server, port_ptr->this_port.node_id,
2066 port_ptr->this_port.port_id);
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002067 mutex_unlock(&server_list_lock);
2068 broadcast_ctl_msg(&ctl);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002069 spin_lock_irqsave(&port_ptr->port_lock, flags);
2070 port_ptr->type = CLIENT_PORT;
2071 spin_unlock_irqrestore(&port_ptr->port_lock, flags);
2072 return 0;
2073}
2074
2075static int loopback_data(struct msm_ipc_port *src,
2076 uint32_t port_id,
2077 struct sk_buff_head *data)
2078{
2079 struct sk_buff *head_skb;
2080 struct rr_header *hdr;
2081 struct msm_ipc_port *port_ptr;
2082 struct rr_packet *pkt;
Karthikeyan Ramasubramanian0a801c12013-02-08 13:07:42 -07002083 int ret_len;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002084
2085 if (!data) {
2086 pr_err("%s: Invalid pkt pointer\n", __func__);
2087 return -EINVAL;
2088 }
2089
2090 pkt = create_pkt(data);
2091 if (!pkt) {
2092 pr_err("%s: New pkt create failed\n", __func__);
2093 return -ENOMEM;
2094 }
2095
2096 head_skb = skb_peek(pkt->pkt_fragment_q);
Karthikeyan Ramasubramanian9024dd82011-12-19 18:44:19 -07002097 if (!head_skb) {
2098 pr_err("%s: pkt_fragment_q is empty\n", __func__);
Brent Hronik0e83d3b2013-05-01 16:25:00 -06002099 release_pkt(pkt);
Karthikeyan Ramasubramanian9024dd82011-12-19 18:44:19 -07002100 return -EINVAL;
2101 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002102 hdr = (struct rr_header *)skb_push(head_skb, IPC_ROUTER_HDR_SIZE);
2103 if (!hdr) {
2104 pr_err("%s: Prepend Header failed\n", __func__);
2105 release_pkt(pkt);
2106 return -ENOMEM;
2107 }
2108 hdr->version = IPC_ROUTER_VERSION;
2109 hdr->type = IPC_ROUTER_CTRL_CMD_DATA;
2110 hdr->src_node_id = src->this_port.node_id;
2111 hdr->src_port_id = src->this_port.port_id;
2112 hdr->size = pkt->length;
2113 hdr->confirm_rx = 0;
2114 hdr->dst_node_id = IPC_ROUTER_NID_LOCAL;
2115 hdr->dst_port_id = port_id;
2116 pkt->length += IPC_ROUTER_HDR_SIZE;
2117
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06002118 mutex_lock(&local_ports_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002119 port_ptr = msm_ipc_router_lookup_local_port(port_id);
2120 if (!port_ptr) {
2121 pr_err("%s: Local port %d not present\n", __func__, port_id);
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06002122 mutex_unlock(&local_ports_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002123 release_pkt(pkt);
2124 return -ENODEV;
2125 }
2126
Karthikeyan Ramasubramanian0a801c12013-02-08 13:07:42 -07002127 ret_len = pkt->length;
Karthikeyan Ramasubramaniand1af6252013-05-17 15:19:56 -06002128 post_pkt_to_port(port_ptr, pkt, 0);
Karthikeyan Ramasubramaniandc9c4442013-05-02 17:25:54 -06002129 update_comm_mode_info(&src->mode_info, NULL);
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06002130 mutex_unlock(&local_ports_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002131
Karthikeyan Ramasubramanian0a801c12013-02-08 13:07:42 -07002132 return ret_len;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002133}
2134
2135static int msm_ipc_router_write_pkt(struct msm_ipc_port *src,
2136 struct msm_ipc_router_remote_port *rport_ptr,
2137 struct rr_packet *pkt)
2138{
2139 struct sk_buff *head_skb;
2140 struct rr_header *hdr;
2141 struct msm_ipc_router_xprt_info *xprt_info;
2142 struct msm_ipc_routing_table_entry *rt_entry;
Zaheerulla Meera34fc662013-04-17 01:16:47 +05302143 struct msm_ipc_resume_tx_port *resume_tx_port;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002144 int ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002145
2146 if (!rport_ptr || !src || !pkt)
2147 return -EINVAL;
2148
2149 head_skb = skb_peek(pkt->pkt_fragment_q);
Karthikeyan Ramasubramanian9024dd82011-12-19 18:44:19 -07002150 if (!head_skb) {
2151 pr_err("%s: pkt_fragment_q is empty\n", __func__);
2152 return -EINVAL;
2153 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002154 hdr = (struct rr_header *)skb_push(head_skb, IPC_ROUTER_HDR_SIZE);
2155 if (!hdr) {
2156 pr_err("%s: Prepend Header failed\n", __func__);
2157 return -ENOMEM;
2158 }
2159 hdr->version = IPC_ROUTER_VERSION;
2160 hdr->type = IPC_ROUTER_CTRL_CMD_DATA;
2161 hdr->src_node_id = src->this_port.node_id;
2162 hdr->src_port_id = src->this_port.port_id;
2163 hdr->size = pkt->length;
2164 hdr->confirm_rx = 0;
2165 hdr->dst_node_id = rport_ptr->node_id;
2166 hdr->dst_port_id = rport_ptr->port_id;
2167 pkt->length += IPC_ROUTER_HDR_SIZE;
2168
Zaheerulla Meera34fc662013-04-17 01:16:47 +05302169 mutex_lock(&rport_ptr->quota_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002170 if (rport_ptr->restart_state != RESTART_NORMAL) {
2171 mutex_unlock(&rport_ptr->quota_lock);
2172 return -ENETRESET;
2173 }
Zaheerulla Meera34fc662013-04-17 01:16:47 +05302174 if (rport_ptr->tx_quota_cnt == IPC_ROUTER_DEFAULT_RX_QUOTA) {
2175 if (msm_ipc_router_lookup_resume_tx_port(
2176 rport_ptr, src->this_port.port_id)) {
2177 mutex_unlock(&rport_ptr->quota_lock);
2178 return -EAGAIN;
2179 }
2180 resume_tx_port =
2181 kzalloc(sizeof(struct msm_ipc_resume_tx_port),
2182 GFP_KERNEL);
2183 if (!resume_tx_port) {
2184 pr_err("%s: Resume_Tx port allocation failed\n",
2185 __func__);
2186 mutex_unlock(&rport_ptr->quota_lock);
2187 return -ENOMEM;
2188 }
2189 INIT_LIST_HEAD(&resume_tx_port->list);
2190 resume_tx_port->port_id = src->this_port.port_id;
2191 resume_tx_port->node_id = src->this_port.node_id;
2192 list_add_tail(&resume_tx_port->list,
2193 &rport_ptr->resume_tx_port_list);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002194 mutex_unlock(&rport_ptr->quota_lock);
Zaheerulla Meera34fc662013-04-17 01:16:47 +05302195 return -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002196 }
2197 rport_ptr->tx_quota_cnt++;
2198 if (rport_ptr->tx_quota_cnt == IPC_ROUTER_DEFAULT_RX_QUOTA)
2199 hdr->confirm_rx = 1;
2200 mutex_unlock(&rport_ptr->quota_lock);
2201
2202 mutex_lock(&routing_table_lock);
2203 rt_entry = lookup_routing_table(hdr->dst_node_id);
2204 if (!rt_entry || !rt_entry->xprt_info) {
2205 mutex_unlock(&routing_table_lock);
2206 pr_err("%s: Remote node %d not up\n",
2207 __func__, hdr->dst_node_id);
2208 return -ENODEV;
2209 }
2210 mutex_lock(&rt_entry->lock);
2211 xprt_info = rt_entry->xprt_info;
2212 mutex_lock(&xprt_info->tx_lock);
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -07002213 ret = xprt_info->xprt->write(pkt, pkt->length, xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002214 mutex_unlock(&xprt_info->tx_lock);
2215 mutex_unlock(&rt_entry->lock);
2216 mutex_unlock(&routing_table_lock);
2217
2218 if (ret < 0) {
2219 pr_err("%s: Write on XPRT failed\n", __func__);
2220 return ret;
2221 }
Karthikeyan Ramasubramaniandc9c4442013-05-02 17:25:54 -06002222 update_comm_mode_info(&src->mode_info, xprt_info);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002223
2224 RAW_HDR("[w rr_h] "
2225 "ver=%i,type=%s,src_nid=%08x,src_port_id=%08x,"
2226 "confirm_rx=%i,size=%3i,dst_pid=%08x,dst_cid=%08x\n",
2227 hdr->version, type_to_str(hdr->type),
2228 hdr->src_node_id, hdr->src_port_id,
2229 hdr->confirm_rx, hdr->size,
2230 hdr->dst_node_id, hdr->dst_port_id);
2231
2232#if defined(CONFIG_MSM_SMD_LOGGING)
2233#if defined(DEBUG)
2234 if (msm_ipc_router_debug_mask & SMEM_LOG) {
2235 smem_log_event((SMEM_LOG_PROC_ID_APPS |
2236 SMEM_LOG_RPC_ROUTER_EVENT_BASE |
2237 IPC_ROUTER_LOG_EVENT_TX),
2238 (hdr->src_node_id << 24) |
2239 (hdr->src_port_id & 0xffffff),
2240 (hdr->dst_node_id << 24) |
2241 (hdr->dst_port_id & 0xffffff),
2242 (hdr->type << 24) | (hdr->confirm_rx << 16) |
2243 (hdr->size & 0xffff));
2244 }
2245#endif
2246#endif
2247
2248 return pkt->length;
2249}
2250
2251int msm_ipc_router_send_to(struct msm_ipc_port *src,
2252 struct sk_buff_head *data,
2253 struct msm_ipc_addr *dest)
2254{
2255 uint32_t dst_node_id = 0, dst_port_id = 0;
2256 struct msm_ipc_server *server;
2257 struct msm_ipc_server_port *server_port;
2258 struct msm_ipc_router_remote_port *rport_ptr = NULL;
2259 struct rr_packet *pkt;
2260 int ret;
2261
2262 if (!src || !data || !dest) {
2263 pr_err("%s: Invalid Parameters\n", __func__);
2264 return -EINVAL;
2265 }
2266
2267 /* Resolve Address*/
2268 if (dest->addrtype == MSM_IPC_ADDR_ID) {
2269 dst_node_id = dest->addr.port_addr.node_id;
2270 dst_port_id = dest->addr.port_addr.port_id;
2271 } else if (dest->addrtype == MSM_IPC_ADDR_NAME) {
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002272 mutex_lock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002273 server = msm_ipc_router_lookup_server(
2274 dest->addr.port_name.service,
2275 dest->addr.port_name.instance,
2276 0, 0);
2277 if (!server) {
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002278 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002279 pr_err("%s: Destination not reachable\n", __func__);
2280 return -ENODEV;
2281 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002282 server_port = list_first_entry(&server->server_port_list,
2283 struct msm_ipc_server_port,
2284 list);
2285 dst_node_id = server_port->server_addr.node_id;
2286 dst_port_id = server_port->server_addr.port_id;
2287 mutex_unlock(&server_list_lock);
2288 }
2289 if (dst_node_id == IPC_ROUTER_NID_LOCAL) {
2290 ret = loopback_data(src, dst_port_id, data);
2291 return ret;
2292 }
2293
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002294 rport_ptr = msm_ipc_router_lookup_remote_port(dst_node_id,
2295 dst_port_id);
2296 if (!rport_ptr) {
Zaheerulla Meer2c515312013-05-10 15:51:28 +05302297 pr_err("%s: Remote port not found\n", __func__);
2298 return -ENODEV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002299 }
2300
Karthikeyan Ramasubramanian1668cc62012-09-23 22:23:36 -06002301 if (src->check_send_permissions) {
2302 ret = src->check_send_permissions(rport_ptr->sec_rule);
2303 if (ret <= 0) {
2304 pr_err("%s: permission failure for %s\n",
2305 __func__, current->comm);
2306 return -EPERM;
2307 }
2308 }
2309
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002310 pkt = create_pkt(data);
2311 if (!pkt) {
2312 pr_err("%s: Pkt creation failed\n", __func__);
2313 return -ENOMEM;
2314 }
2315
2316 ret = msm_ipc_router_write_pkt(src, rport_ptr, pkt);
2317 release_pkt(pkt);
2318
2319 return ret;
2320}
2321
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -06002322int msm_ipc_router_send_msg(struct msm_ipc_port *src,
2323 struct msm_ipc_addr *dest,
2324 void *data, unsigned int data_len)
2325{
2326 struct sk_buff_head *out_skb_head;
2327 int ret;
2328
2329 out_skb_head = msm_ipc_router_buf_to_skb(data, data_len);
2330 if (!out_skb_head) {
2331 pr_err("%s: SKB conversion failed\n", __func__);
2332 return -EFAULT;
2333 }
2334
2335 ret = msm_ipc_router_send_to(src, out_skb_head, dest);
2336 if (ret < 0) {
2337 pr_err("%s: msm_ipc_router_send_to failed - ret: %d\n",
2338 __func__, ret);
2339 msm_ipc_router_free_skb(out_skb_head);
2340 }
2341 return 0;
2342}
2343
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002344int msm_ipc_router_read(struct msm_ipc_port *port_ptr,
2345 struct sk_buff_head **data,
2346 size_t buf_len)
2347{
2348 struct rr_packet *pkt;
2349 int ret;
2350
2351 if (!port_ptr || !data)
2352 return -EINVAL;
2353
2354 mutex_lock(&port_ptr->port_rx_q_lock);
2355 if (list_empty(&port_ptr->port_rx_q)) {
2356 mutex_unlock(&port_ptr->port_rx_q_lock);
2357 return -EAGAIN;
2358 }
2359
2360 pkt = list_first_entry(&port_ptr->port_rx_q, struct rr_packet, list);
2361 if ((buf_len) && ((pkt->length - IPC_ROUTER_HDR_SIZE) > buf_len)) {
2362 mutex_unlock(&port_ptr->port_rx_q_lock);
2363 return -ETOOSMALL;
2364 }
2365 list_del(&pkt->list);
2366 if (list_empty(&port_ptr->port_rx_q))
2367 wake_unlock(&port_ptr->port_rx_wake_lock);
2368 *data = pkt->pkt_fragment_q;
2369 ret = pkt->length;
2370 kfree(pkt);
2371 mutex_unlock(&port_ptr->port_rx_q_lock);
2372
2373 return ret;
2374}
2375
2376int msm_ipc_router_recv_from(struct msm_ipc_port *port_ptr,
2377 struct sk_buff_head **data,
2378 struct msm_ipc_addr *src,
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -06002379 long timeout)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002380{
2381 int ret, data_len, align_size;
2382 struct sk_buff *temp_skb;
2383 struct rr_header *hdr = NULL;
2384
2385 if (!port_ptr || !data) {
2386 pr_err("%s: Invalid pointers being passed\n", __func__);
2387 return -EINVAL;
2388 }
2389
2390 *data = NULL;
2391 mutex_lock(&port_ptr->port_rx_q_lock);
2392 while (list_empty(&port_ptr->port_rx_q)) {
2393 mutex_unlock(&port_ptr->port_rx_q_lock);
2394 if (timeout < 0) {
2395 ret = wait_event_interruptible(
2396 port_ptr->port_rx_wait_q,
2397 !list_empty(&port_ptr->port_rx_q));
2398 if (ret)
2399 return ret;
2400 } else if (timeout > 0) {
2401 timeout = wait_event_interruptible_timeout(
2402 port_ptr->port_rx_wait_q,
2403 !list_empty(&port_ptr->port_rx_q),
2404 timeout);
2405 if (timeout < 0)
2406 return -EFAULT;
2407 }
2408 if (timeout == 0)
2409 return -ETIMEDOUT;
2410 mutex_lock(&port_ptr->port_rx_q_lock);
2411 }
2412 mutex_unlock(&port_ptr->port_rx_q_lock);
2413
2414 ret = msm_ipc_router_read(port_ptr, data, 0);
2415 if (ret <= 0 || !(*data))
2416 return ret;
2417
2418 temp_skb = skb_peek(*data);
2419 hdr = (struct rr_header *)(temp_skb->data);
2420 if (src) {
2421 src->addrtype = MSM_IPC_ADDR_ID;
2422 src->addr.port_addr.node_id = hdr->src_node_id;
2423 src->addr.port_addr.port_id = hdr->src_port_id;
2424 }
2425
2426 data_len = hdr->size;
2427 skb_pull(temp_skb, IPC_ROUTER_HDR_SIZE);
2428 align_size = ALIGN_SIZE(data_len);
2429 if (align_size) {
2430 temp_skb = skb_peek_tail(*data);
2431 skb_trim(temp_skb, (temp_skb->len - align_size));
2432 }
2433 return data_len;
2434}
2435
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -06002436int msm_ipc_router_read_msg(struct msm_ipc_port *port_ptr,
2437 struct msm_ipc_addr *src,
2438 unsigned char **data,
2439 unsigned int *len)
2440{
2441 struct sk_buff_head *in_skb_head;
2442 int ret;
2443
2444 ret = msm_ipc_router_recv_from(port_ptr, &in_skb_head, src, -1);
2445 if (ret < 0) {
2446 pr_err("%s: msm_ipc_router_recv_from failed - ret: %d\n",
2447 __func__, ret);
2448 return ret;
2449 }
2450
2451 *data = msm_ipc_router_skb_to_buf(in_skb_head, ret);
2452 if (!(*data))
2453 pr_err("%s: Buf conversion failed\n", __func__);
2454
2455 *len = ret;
2456 msm_ipc_router_free_skb(in_skb_head);
2457 return 0;
2458}
2459
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002460struct msm_ipc_port *msm_ipc_router_create_port(
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -06002461 void (*notify)(unsigned event, void *priv),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002462 void *priv)
2463{
2464 struct msm_ipc_port *port_ptr;
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -06002465 int ret;
2466
2467 ret = wait_for_completion_interruptible(&msm_ipc_local_router_up);
2468 if (ret < 0) {
2469 pr_err("%s: Error waiting for local router\n", __func__);
2470 return NULL;
2471 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002472
2473 port_ptr = msm_ipc_router_create_raw_port(NULL, notify, priv);
2474 if (!port_ptr)
2475 pr_err("%s: port_ptr alloc failed\n", __func__);
2476
2477 return port_ptr;
2478}
2479
2480int msm_ipc_router_close_port(struct msm_ipc_port *port_ptr)
2481{
2482 union rr_control_msg msg;
2483 struct rr_packet *pkt, *temp_pkt;
2484 struct msm_ipc_server *server;
2485
2486 if (!port_ptr)
2487 return -EINVAL;
2488
2489 if (port_ptr->type == SERVER_PORT || port_ptr->type == CLIENT_PORT) {
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06002490 mutex_lock(&local_ports_lock);
2491 list_del(&port_ptr->list);
2492 mutex_unlock(&local_ports_lock);
2493
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002494 if (port_ptr->type == SERVER_PORT) {
2495 msg.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_SERVER;
2496 msg.srv.service = port_ptr->port_name.service;
2497 msg.srv.instance = port_ptr->port_name.instance;
2498 msg.srv.node_id = port_ptr->this_port.node_id;
2499 msg.srv.port_id = port_ptr->this_port.port_id;
2500 RR("x REMOVE_SERVER Name=%d:%08x Id=%d:%08x\n",
2501 msg.srv.service, msg.srv.instance,
2502 msg.srv.node_id, msg.srv.port_id);
Karthikeyan Ramasubramanian25e91872013-01-10 17:09:13 -07002503 broadcast_ctl_msg(&msg);
2504 broadcast_ctl_msg_locally(&msg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002505 }
Karthikeyan Ramasubramanian25e91872013-01-10 17:09:13 -07002506
2507 /*
2508 * Server port could have been a client port earlier.
2509 * Send REMOVE_CLIENT message in either case.
2510 */
Karthikeyan Ramasubramanian25e91872013-01-10 17:09:13 -07002511 RR("x REMOVE_CLIENT id=%d:%08x\n",
Karthikeyan Ramasubramaniandc9c4442013-05-02 17:25:54 -06002512 port_ptr->this_port.node_id, port_ptr->this_port.port_id);
2513 msm_ipc_router_send_remove_client(&port_ptr->mode_info,
2514 port_ptr->this_port.node_id,
2515 port_ptr->this_port.port_id);
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06002516 } else if (port_ptr->type == CONTROL_PORT) {
2517 mutex_lock(&control_ports_lock);
2518 list_del(&port_ptr->list);
2519 mutex_unlock(&control_ports_lock);
Karthikeyan Ramasubramaniand6dbfae2013-01-16 09:00:28 -07002520 } else if (port_ptr->type == IRSC_PORT) {
2521 mutex_lock(&local_ports_lock);
2522 list_del(&port_ptr->list);
2523 mutex_unlock(&local_ports_lock);
2524 signal_irsc_completion();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002525 }
2526
2527 mutex_lock(&port_ptr->port_rx_q_lock);
2528 list_for_each_entry_safe(pkt, temp_pkt, &port_ptr->port_rx_q, list) {
2529 list_del(&pkt->list);
2530 release_pkt(pkt);
2531 }
2532 mutex_unlock(&port_ptr->port_rx_q_lock);
2533
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002534 if (port_ptr->type == SERVER_PORT) {
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002535 mutex_lock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002536 server = msm_ipc_router_lookup_server(
2537 port_ptr->port_name.service,
2538 port_ptr->port_name.instance,
2539 port_ptr->this_port.node_id,
2540 port_ptr->this_port.port_id);
2541 if (server)
2542 msm_ipc_router_destroy_server(server,
2543 port_ptr->this_port.node_id,
2544 port_ptr->this_port.port_id);
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002545 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002546 }
2547
Karthikeyan Ramasubramaniandd8c3b52011-11-30 16:26:12 -07002548 wake_lock_destroy(&port_ptr->port_rx_wake_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002549 kfree(port_ptr);
2550 return 0;
2551}
2552
2553int msm_ipc_router_get_curr_pkt_size(struct msm_ipc_port *port_ptr)
2554{
2555 struct rr_packet *pkt;
2556 int rc = 0;
2557
2558 if (!port_ptr)
2559 return -EINVAL;
2560
2561 mutex_lock(&port_ptr->port_rx_q_lock);
2562 if (!list_empty(&port_ptr->port_rx_q)) {
2563 pkt = list_first_entry(&port_ptr->port_rx_q,
2564 struct rr_packet, list);
2565 rc = pkt->length;
2566 }
2567 mutex_unlock(&port_ptr->port_rx_q_lock);
2568
2569 return rc;
2570}
2571
2572int msm_ipc_router_bind_control_port(struct msm_ipc_port *port_ptr)
2573{
2574 if (!port_ptr)
2575 return -EINVAL;
2576
2577 mutex_lock(&local_ports_lock);
2578 list_del(&port_ptr->list);
2579 mutex_unlock(&local_ports_lock);
2580 port_ptr->type = CONTROL_PORT;
2581 mutex_lock(&control_ports_lock);
2582 list_add_tail(&port_ptr->list, &control_ports);
2583 mutex_unlock(&control_ports_lock);
2584
2585 return 0;
2586}
2587
2588int msm_ipc_router_lookup_server_name(struct msm_ipc_port_name *srv_name,
Karthikeyan Ramasubramaniandfde01b2012-06-12 14:25:13 -06002589 struct msm_ipc_server_info *srv_info,
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002590 int num_entries_in_array,
2591 uint32_t lookup_mask)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002592{
2593 struct msm_ipc_server *server;
2594 struct msm_ipc_server_port *server_port;
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002595 int key, i = 0; /*num_entries_found*/
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002596
2597 if (!srv_name) {
2598 pr_err("%s: Invalid srv_name\n", __func__);
2599 return -EINVAL;
2600 }
2601
Karthikeyan Ramasubramaniandfde01b2012-06-12 14:25:13 -06002602 if (num_entries_in_array && !srv_info) {
2603 pr_err("%s: srv_info NULL\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002604 return -EINVAL;
2605 }
2606
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002607 mutex_lock(&server_list_lock);
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002608 if (!lookup_mask)
2609 lookup_mask = 0xFFFFFFFF;
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002610 key = (srv_name->service & (SRV_HASH_SIZE - 1));
2611 list_for_each_entry(server, &server_list[key], list) {
2612 if ((server->name.service != srv_name->service) ||
2613 ((server->name.instance & lookup_mask) !=
2614 srv_name->instance))
2615 continue;
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002616
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002617 list_for_each_entry(server_port,
2618 &server->server_port_list, list) {
2619 if (i < num_entries_in_array) {
2620 srv_info[i].node_id =
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002621 server_port->server_addr.node_id;
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002622 srv_info[i].port_id =
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002623 server_port->server_addr.port_id;
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002624 srv_info[i].service = server->name.service;
2625 srv_info[i].instance = server->name.instance;
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002626 }
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002627 i++;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002628 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002629 }
2630 mutex_unlock(&server_list_lock);
2631
2632 return i;
2633}
2634
2635int msm_ipc_router_close(void)
2636{
2637 struct msm_ipc_router_xprt_info *xprt_info, *tmp_xprt_info;
2638
2639 mutex_lock(&xprt_info_list_lock);
2640 list_for_each_entry_safe(xprt_info, tmp_xprt_info,
2641 &xprt_info_list, list) {
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -07002642 xprt_info->xprt->close(xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002643 list_del(&xprt_info->list);
2644 kfree(xprt_info);
2645 }
2646 mutex_unlock(&xprt_info_list_lock);
2647 return 0;
2648}
2649
2650#if defined(CONFIG_DEBUG_FS)
2651static int dump_routing_table(char *buf, int max)
2652{
2653 int i = 0, j;
2654 struct msm_ipc_routing_table_entry *rt_entry;
2655
2656 for (j = 0; j < RT_HASH_SIZE; j++) {
2657 mutex_lock(&routing_table_lock);
2658 list_for_each_entry(rt_entry, &routing_table[j], list) {
2659 mutex_lock(&rt_entry->lock);
2660 i += scnprintf(buf + i, max - i,
2661 "Node Id: 0x%08x\n", rt_entry->node_id);
Karthikeyan Ramasubramanianc1a4e3a2012-09-10 16:10:24 -06002662 if (rt_entry->node_id == IPC_ROUTER_NID_LOCAL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002663 i += scnprintf(buf + i, max - i,
2664 "XPRT Name: Loopback\n");
2665 i += scnprintf(buf + i, max - i,
2666 "Next Hop: %d\n", rt_entry->node_id);
2667 } else {
2668 i += scnprintf(buf + i, max - i,
2669 "XPRT Name: %s\n",
2670 rt_entry->xprt_info->xprt->name);
2671 i += scnprintf(buf + i, max - i,
2672 "Next Hop: 0x%08x\n",
2673 rt_entry->xprt_info->remote_node_id);
2674 }
2675 i += scnprintf(buf + i, max - i, "\n");
2676 mutex_unlock(&rt_entry->lock);
2677 }
2678 mutex_unlock(&routing_table_lock);
2679 }
2680
2681 return i;
2682}
2683
2684static int dump_xprt_info(char *buf, int max)
2685{
2686 int i = 0;
2687 struct msm_ipc_router_xprt_info *xprt_info;
2688
2689 mutex_lock(&xprt_info_list_lock);
2690 list_for_each_entry(xprt_info, &xprt_info_list, list) {
2691 i += scnprintf(buf + i, max - i, "XPRT Name: %s\n",
2692 xprt_info->xprt->name);
2693 i += scnprintf(buf + i, max - i, "Link Id: %d\n",
2694 xprt_info->xprt->link_id);
2695 i += scnprintf(buf + i, max - i, "Initialized: %s\n",
2696 (xprt_info->initialized ? "Y" : "N"));
2697 i += scnprintf(buf + i, max - i, "Remote Node Id: 0x%08x\n",
2698 xprt_info->remote_node_id);
2699 i += scnprintf(buf + i, max - i, "\n");
2700 }
2701 mutex_unlock(&xprt_info_list_lock);
2702
2703 return i;
2704}
2705
2706static int dump_servers(char *buf, int max)
2707{
2708 int i = 0, j;
2709 struct msm_ipc_server *server;
2710 struct msm_ipc_server_port *server_port;
2711
2712 mutex_lock(&server_list_lock);
2713 for (j = 0; j < SRV_HASH_SIZE; j++) {
2714 list_for_each_entry(server, &server_list[j], list) {
2715 list_for_each_entry(server_port,
2716 &server->server_port_list,
2717 list) {
2718 i += scnprintf(buf + i, max - i, "Service: "
2719 "0x%08x\n", server->name.service);
2720 i += scnprintf(buf + i, max - i, "Instance: "
2721 "0x%08x\n", server->name.instance);
2722 i += scnprintf(buf + i, max - i,
2723 "Node_id: 0x%08x\n",
2724 server_port->server_addr.node_id);
2725 i += scnprintf(buf + i, max - i,
2726 "Port_id: 0x%08x\n",
2727 server_port->server_addr.port_id);
2728 i += scnprintf(buf + i, max - i, "\n");
2729 }
2730 }
2731 }
2732 mutex_unlock(&server_list_lock);
2733
2734 return i;
2735}
2736
2737static int dump_remote_ports(char *buf, int max)
2738{
2739 int i = 0, j, k;
2740 struct msm_ipc_router_remote_port *rport_ptr;
2741 struct msm_ipc_routing_table_entry *rt_entry;
2742
2743 for (j = 0; j < RT_HASH_SIZE; j++) {
2744 mutex_lock(&routing_table_lock);
2745 list_for_each_entry(rt_entry, &routing_table[j], list) {
2746 mutex_lock(&rt_entry->lock);
2747 for (k = 0; k < RP_HASH_SIZE; k++) {
2748 list_for_each_entry(rport_ptr,
2749 &rt_entry->remote_port_list[k],
2750 list) {
2751 i += scnprintf(buf + i, max - i,
2752 "Node_id: 0x%08x\n",
2753 rport_ptr->node_id);
2754 i += scnprintf(buf + i, max - i,
2755 "Port_id: 0x%08x\n",
2756 rport_ptr->port_id);
2757 i += scnprintf(buf + i, max - i,
2758 "Quota_cnt: %d\n",
2759 rport_ptr->tx_quota_cnt);
2760 i += scnprintf(buf + i, max - i, "\n");
2761 }
2762 }
2763 mutex_unlock(&rt_entry->lock);
2764 }
2765 mutex_unlock(&routing_table_lock);
2766 }
2767
2768 return i;
2769}
2770
2771static int dump_control_ports(char *buf, int max)
2772{
2773 int i = 0;
2774 struct msm_ipc_port *port_ptr;
2775
2776 mutex_lock(&control_ports_lock);
2777 list_for_each_entry(port_ptr, &control_ports, list) {
2778 i += scnprintf(buf + i, max - i, "Node_id: 0x%08x\n",
2779 port_ptr->this_port.node_id);
2780 i += scnprintf(buf + i, max - i, "Port_id: 0x%08x\n",
2781 port_ptr->this_port.port_id);
2782 i += scnprintf(buf + i, max - i, "\n");
2783 }
2784 mutex_unlock(&control_ports_lock);
2785
2786 return i;
2787}
2788
2789static int dump_local_ports(char *buf, int max)
2790{
2791 int i = 0, j;
2792 unsigned long flags;
2793 struct msm_ipc_port *port_ptr;
2794
2795 mutex_lock(&local_ports_lock);
2796 for (j = 0; j < LP_HASH_SIZE; j++) {
2797 list_for_each_entry(port_ptr, &local_ports[j], list) {
2798 spin_lock_irqsave(&port_ptr->port_lock, flags);
2799 i += scnprintf(buf + i, max - i, "Node_id: 0x%08x\n",
2800 port_ptr->this_port.node_id);
2801 i += scnprintf(buf + i, max - i, "Port_id: 0x%08x\n",
2802 port_ptr->this_port.port_id);
2803 i += scnprintf(buf + i, max - i, "# pkts tx'd %d\n",
2804 port_ptr->num_tx);
2805 i += scnprintf(buf + i, max - i, "# pkts rx'd %d\n",
2806 port_ptr->num_rx);
2807 i += scnprintf(buf + i, max - i, "# bytes tx'd %ld\n",
2808 port_ptr->num_tx_bytes);
2809 i += scnprintf(buf + i, max - i, "# bytes rx'd %ld\n",
2810 port_ptr->num_rx_bytes);
2811 spin_unlock_irqrestore(&port_ptr->port_lock, flags);
2812 i += scnprintf(buf + i, max - i, "\n");
2813 }
2814 }
2815 mutex_unlock(&local_ports_lock);
2816
2817 return i;
2818}
2819
2820#define DEBUG_BUFMAX 4096
2821static char debug_buffer[DEBUG_BUFMAX];
2822
2823static ssize_t debug_read(struct file *file, char __user *buf,
2824 size_t count, loff_t *ppos)
2825{
2826 int (*fill)(char *buf, int max) = file->private_data;
2827 int bsize = fill(debug_buffer, DEBUG_BUFMAX);
2828 return simple_read_from_buffer(buf, count, ppos, debug_buffer, bsize);
2829}
2830
2831static int debug_open(struct inode *inode, struct file *file)
2832{
2833 file->private_data = inode->i_private;
2834 return 0;
2835}
2836
2837static const struct file_operations debug_ops = {
2838 .read = debug_read,
2839 .open = debug_open,
2840};
2841
2842static void debug_create(const char *name, mode_t mode,
2843 struct dentry *dent,
2844 int (*fill)(char *buf, int max))
2845{
2846 debugfs_create_file(name, mode, dent, fill, &debug_ops);
2847}
2848
2849static void debugfs_init(void)
2850{
2851 struct dentry *dent;
2852
2853 dent = debugfs_create_dir("msm_ipc_router", 0);
2854 if (IS_ERR(dent))
2855 return;
2856
2857 debug_create("dump_local_ports", 0444, dent,
2858 dump_local_ports);
2859 debug_create("dump_remote_ports", 0444, dent,
2860 dump_remote_ports);
2861 debug_create("dump_control_ports", 0444, dent,
2862 dump_control_ports);
2863 debug_create("dump_servers", 0444, dent,
2864 dump_servers);
2865 debug_create("dump_xprt_info", 0444, dent,
2866 dump_xprt_info);
2867 debug_create("dump_routing_table", 0444, dent,
2868 dump_routing_table);
2869}
2870
2871#else
2872static void debugfs_init(void) {}
2873#endif
2874
2875static int msm_ipc_router_add_xprt(struct msm_ipc_router_xprt *xprt)
2876{
2877 struct msm_ipc_router_xprt_info *xprt_info;
2878 struct msm_ipc_routing_table_entry *rt_entry;
2879
2880 xprt_info = kmalloc(sizeof(struct msm_ipc_router_xprt_info),
2881 GFP_KERNEL);
2882 if (!xprt_info)
2883 return -ENOMEM;
2884
2885 xprt_info->xprt = xprt;
2886 xprt_info->initialized = 0;
2887 xprt_info->remote_node_id = -1;
2888 INIT_LIST_HEAD(&xprt_info->pkt_list);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002889 mutex_init(&xprt_info->rx_lock);
2890 mutex_init(&xprt_info->tx_lock);
2891 wake_lock_init(&xprt_info->wakelock,
2892 WAKE_LOCK_SUSPEND, xprt->name);
2893 xprt_info->need_len = 0;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002894 xprt_info->abort_data_read = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002895 INIT_WORK(&xprt_info->read_data, do_read_data);
2896 INIT_LIST_HEAD(&xprt_info->list);
2897
2898 xprt_info->workqueue = create_singlethread_workqueue(xprt->name);
2899 if (!xprt_info->workqueue) {
2900 kfree(xprt_info);
2901 return -ENOMEM;
2902 }
2903
2904 if (!strcmp(xprt->name, "msm_ipc_router_loopback_xprt")) {
2905 xprt_info->remote_node_id = IPC_ROUTER_NID_LOCAL;
2906 xprt_info->initialized = 1;
2907 }
2908
2909 mutex_lock(&xprt_info_list_lock);
2910 list_add_tail(&xprt_info->list, &xprt_info_list);
2911 mutex_unlock(&xprt_info_list_lock);
2912
2913 mutex_lock(&routing_table_lock);
2914 if (!routing_table_inited) {
2915 init_routing_table();
2916 rt_entry = alloc_routing_table_entry(IPC_ROUTER_NID_LOCAL);
2917 add_routing_table_entry(rt_entry);
2918 routing_table_inited = 1;
2919 }
2920 mutex_unlock(&routing_table_lock);
2921
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002922 xprt->priv = xprt_info;
2923
2924 return 0;
2925}
2926
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002927static void msm_ipc_router_remove_xprt(struct msm_ipc_router_xprt *xprt)
2928{
2929 struct msm_ipc_router_xprt_info *xprt_info;
2930
2931 if (xprt && xprt->priv) {
2932 xprt_info = xprt->priv;
2933
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06002934 mutex_lock(&xprt_info->rx_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002935 xprt_info->abort_data_read = 1;
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06002936 mutex_unlock(&xprt_info->rx_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002937
2938 mutex_lock(&xprt_info_list_lock);
2939 list_del(&xprt_info->list);
2940 mutex_unlock(&xprt_info_list_lock);
2941
2942 flush_workqueue(xprt_info->workqueue);
2943 destroy_workqueue(xprt_info->workqueue);
2944 wake_lock_destroy(&xprt_info->wakelock);
2945
2946 xprt->priv = 0;
2947 kfree(xprt_info);
2948 }
2949}
2950
2951
2952struct msm_ipc_router_xprt_work {
2953 struct msm_ipc_router_xprt *xprt;
2954 struct work_struct work;
2955};
2956
2957static void xprt_open_worker(struct work_struct *work)
2958{
2959 struct msm_ipc_router_xprt_work *xprt_work =
2960 container_of(work, struct msm_ipc_router_xprt_work, work);
2961
2962 msm_ipc_router_add_xprt(xprt_work->xprt);
2963 kfree(xprt_work);
2964}
2965
2966static void xprt_close_worker(struct work_struct *work)
2967{
2968 struct msm_ipc_router_xprt_work *xprt_work =
2969 container_of(work, struct msm_ipc_router_xprt_work, work);
2970
2971 modem_reset_cleanup(xprt_work->xprt->priv);
2972 msm_ipc_router_remove_xprt(xprt_work->xprt);
Zaheerulla Meer35893a62013-06-19 16:54:44 +05302973 xprt_work->xprt->sft_close_done(xprt_work->xprt);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002974 kfree(xprt_work);
2975}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002976
2977void msm_ipc_router_xprt_notify(struct msm_ipc_router_xprt *xprt,
2978 unsigned event,
2979 void *data)
2980{
2981 struct msm_ipc_router_xprt_info *xprt_info = xprt->priv;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002982 struct msm_ipc_router_xprt_work *xprt_work;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002983 struct rr_packet *pkt;
Karthikeyan Ramasubramanian4af9f7c2011-09-30 15:55:18 -06002984 unsigned long ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002985
Karthikeyan Ramasubramanian4af9f7c2011-09-30 15:55:18 -06002986 if (!msm_ipc_router_workqueue) {
2987 ret = wait_for_completion_timeout(&msm_ipc_local_router_up,
2988 IPC_ROUTER_INIT_TIMEOUT);
2989 if (!ret || !msm_ipc_router_workqueue) {
2990 pr_err("%s: IPC Router not initialized\n", __func__);
2991 return;
2992 }
2993 }
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002994
2995 switch (event) {
2996 case IPC_ROUTER_XPRT_EVENT_OPEN:
2997 D("open event for '%s'\n", xprt->name);
2998 xprt_work = kmalloc(sizeof(struct msm_ipc_router_xprt_work),
2999 GFP_ATOMIC);
Karthikeyan Ramasubramanianc51456c2013-05-16 15:51:29 -06003000 if (xprt_work) {
3001 xprt_work->xprt = xprt;
3002 INIT_WORK(&xprt_work->work, xprt_open_worker);
3003 queue_work(msm_ipc_router_workqueue, &xprt_work->work);
3004 } else {
3005 pr_err("%s: malloc failure - Couldn't notify OPEN event",
3006 __func__);
3007 }
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06003008 break;
3009
3010 case IPC_ROUTER_XPRT_EVENT_CLOSE:
3011 D("close event for '%s'\n", xprt->name);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06003012 xprt_work = kmalloc(sizeof(struct msm_ipc_router_xprt_work),
3013 GFP_ATOMIC);
Karthikeyan Ramasubramanianc51456c2013-05-16 15:51:29 -06003014 if (xprt_work) {
3015 xprt_work->xprt = xprt;
3016 INIT_WORK(&xprt_work->work, xprt_close_worker);
3017 queue_work(msm_ipc_router_workqueue, &xprt_work->work);
3018 } else {
3019 pr_err("%s: malloc failure - Couldn't notify CLOSE event",
3020 __func__);
3021 }
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06003022 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003023 }
3024
3025 if (!data)
3026 return;
3027
3028 while (!xprt_info) {
3029 msleep(100);
3030 xprt_info = xprt->priv;
3031 }
3032
3033 pkt = clone_pkt((struct rr_packet *)data);
3034 if (!pkt)
3035 return;
3036
3037 mutex_lock(&xprt_info->rx_lock);
3038 list_add_tail(&pkt->list, &xprt_info->pkt_list);
3039 wake_lock(&xprt_info->wakelock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003040 mutex_unlock(&xprt_info->rx_lock);
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06003041 queue_work(xprt_info->workqueue, &xprt_info->read_data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003042}
3043
3044static int __init msm_ipc_router_init(void)
3045{
3046 int i, ret;
3047 struct msm_ipc_routing_table_entry *rt_entry;
3048
3049 msm_ipc_router_debug_mask |= SMEM_LOG;
Karthikeyan Ramasubramanian682ebcc2013-03-22 10:47:20 -06003050 ipc_rtr_log_ctxt = ipc_log_context_create(IPC_RTR_LOG_PAGES,
3051 "ipc_router");
3052 if (!ipc_rtr_log_ctxt)
3053 pr_err("%s: Unable to create IPC logging for IPC RTR",
3054 __func__);
3055
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06003056 msm_ipc_router_workqueue =
3057 create_singlethread_workqueue("msm_ipc_router");
3058 if (!msm_ipc_router_workqueue)
3059 return -ENOMEM;
3060
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003061 debugfs_init();
3062
3063 for (i = 0; i < SRV_HASH_SIZE; i++)
3064 INIT_LIST_HEAD(&server_list[i]);
3065
3066 for (i = 0; i < LP_HASH_SIZE; i++)
3067 INIT_LIST_HEAD(&local_ports[i]);
3068
3069 mutex_lock(&routing_table_lock);
3070 if (!routing_table_inited) {
3071 init_routing_table();
3072 rt_entry = alloc_routing_table_entry(IPC_ROUTER_NID_LOCAL);
3073 add_routing_table_entry(rt_entry);
3074 routing_table_inited = 1;
3075 }
3076 mutex_unlock(&routing_table_lock);
3077
3078 init_waitqueue_head(&newserver_wait);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003079 ret = msm_ipc_router_init_sockets();
3080 if (ret < 0)
3081 pr_err("%s: Init sockets failed\n", __func__);
3082
Karthikeyan Ramasubramanian1668cc62012-09-23 22:23:36 -06003083 ret = msm_ipc_router_security_init();
3084 if (ret < 0)
3085 pr_err("%s: Security Init failed\n", __func__);
3086
Karthikeyan Ramasubramanian4af9f7c2011-09-30 15:55:18 -06003087 complete_all(&msm_ipc_local_router_up);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003088 return ret;
3089}
3090
3091module_init(msm_ipc_router_init);
3092MODULE_DESCRIPTION("MSM IPC Router");
3093MODULE_LICENSE("GPL v2");