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