blob: a86ed4c4d25f1ff24f866517187e51b449261327 [file] [log] [blame]
Karthikeyan Ramasubramanian25e91872013-01-10 17:09:13 -07001/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#define DEBUG
14
15#include <linux/slab.h>
16#include <linux/module.h>
17#include <linux/kernel.h>
18#include <linux/string.h>
19#include <linux/errno.h>
20#include <linux/init.h>
21#include <linux/types.h>
22#include <linux/delay.h>
23#include <linux/err.h>
24#include <linux/sched.h>
25#include <linux/poll.h>
26#include <linux/wakelock.h>
27#include <linux/platform_device.h>
28#include <linux/uaccess.h>
29#include <linux/debugfs.h>
30
31#include <asm/uaccess.h>
32#include <asm/byteorder.h>
33
34#include <mach/smem_log.h>
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -060035#include <mach/subsystem_notif.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070036
37#include "ipc_router.h"
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -060038#include "modem_notifier.h"
Karthikeyan Ramasubramanian1668cc62012-09-23 22:23:36 -060039#include "msm_ipc_router_security.h"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070040
41enum {
42 SMEM_LOG = 1U << 0,
43 RTR_DBG = 1U << 1,
44 R2R_MSG = 1U << 2,
45 R2R_RAW = 1U << 3,
46 NTFY_MSG = 1U << 4,
47 R2R_RAW_HDR = 1U << 5,
48};
49
50static int msm_ipc_router_debug_mask;
51module_param_named(debug_mask, msm_ipc_router_debug_mask,
52 int, S_IRUGO | S_IWUSR | S_IWGRP);
53
54#define DIAG(x...) pr_info("[RR] ERROR " x)
55
56#if defined(DEBUG)
57#define D(x...) do { \
58if (msm_ipc_router_debug_mask & RTR_DBG) \
59 pr_info(x); \
60} while (0)
61
62#define RR(x...) do { \
63if (msm_ipc_router_debug_mask & R2R_MSG) \
64 pr_info("[RR] "x); \
65} while (0)
66
67#define RAW(x...) do { \
68if (msm_ipc_router_debug_mask & R2R_RAW) \
69 pr_info("[RAW] "x); \
70} while (0)
71
72#define NTFY(x...) do { \
73if (msm_ipc_router_debug_mask & NTFY_MSG) \
74 pr_info("[NOTIFY] "x); \
75} while (0)
76
77#define RAW_HDR(x...) do { \
78if (msm_ipc_router_debug_mask & R2R_RAW_HDR) \
79 pr_info("[HDR] "x); \
80} while (0)
81#else
82#define D(x...) do { } while (0)
83#define RR(x...) do { } while (0)
84#define RAW(x...) do { } while (0)
85#define RAW_HDR(x...) do { } while (0)
86#define NTFY(x...) do { } while (0)
87#endif
88
89#define IPC_ROUTER_LOG_EVENT_ERROR 0x10
90#define IPC_ROUTER_LOG_EVENT_TX 0x11
91#define IPC_ROUTER_LOG_EVENT_RX 0x12
92
93static LIST_HEAD(control_ports);
94static DEFINE_MUTEX(control_ports_lock);
95
96#define LP_HASH_SIZE 32
97static struct list_head local_ports[LP_HASH_SIZE];
98static DEFINE_MUTEX(local_ports_lock);
99
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -0600100/*
101 * Server info is organized as a hash table. The server's service ID is
102 * used to index into the hash table. The instance ID of most of the servers
103 * are 1 or 2. The service IDs are well distributed compared to the instance
104 * IDs and hence choosing service ID to index into this hash table optimizes
105 * the hash table operations like add, lookup, destroy.
106 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700107#define SRV_HASH_SIZE 32
108static struct list_head server_list[SRV_HASH_SIZE];
109static DEFINE_MUTEX(server_list_lock);
110static wait_queue_head_t newserver_wait;
111
112struct msm_ipc_server {
113 struct list_head list;
114 struct msm_ipc_port_name name;
Karthikeyan Ramasubramanian1668cc62012-09-23 22:23:36 -0600115 int synced_sec_rule;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700116 struct list_head server_port_list;
117};
118
119struct msm_ipc_server_port {
120 struct list_head list;
121 struct msm_ipc_port_addr server_addr;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600122 struct msm_ipc_router_xprt_info *xprt_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700123};
124
125#define RP_HASH_SIZE 32
126struct msm_ipc_router_remote_port {
127 struct list_head list;
128 uint32_t node_id;
129 uint32_t port_id;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600130 uint32_t restart_state;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700131 wait_queue_head_t quota_wait;
132 uint32_t tx_quota_cnt;
133 struct mutex quota_lock;
Karthikeyan Ramasubramanian1668cc62012-09-23 22:23:36 -0600134 void *sec_rule;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700135};
136
137struct msm_ipc_router_xprt_info {
138 struct list_head list;
139 struct msm_ipc_router_xprt *xprt;
140 uint32_t remote_node_id;
141 uint32_t initialized;
142 struct list_head pkt_list;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700143 struct wake_lock wakelock;
144 struct mutex rx_lock;
145 struct mutex tx_lock;
146 uint32_t need_len;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600147 uint32_t abort_data_read;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700148 struct work_struct read_data;
149 struct workqueue_struct *workqueue;
150};
151
152#define RT_HASH_SIZE 4
153struct msm_ipc_routing_table_entry {
154 struct list_head list;
155 uint32_t node_id;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600156 uint32_t neighbor_node_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700157 struct list_head remote_port_list[RP_HASH_SIZE];
158 struct msm_ipc_router_xprt_info *xprt_info;
159 struct mutex lock;
160 unsigned long num_tx_bytes;
161 unsigned long num_rx_bytes;
162};
163
164static struct list_head routing_table[RT_HASH_SIZE];
165static DEFINE_MUTEX(routing_table_lock);
166static int routing_table_inited;
167
168static LIST_HEAD(msm_ipc_board_dev_list);
169static DEFINE_MUTEX(msm_ipc_board_dev_list_lock);
170
171static void do_read_data(struct work_struct *work);
172
173#define RR_STATE_IDLE 0
174#define RR_STATE_HEADER 1
175#define RR_STATE_BODY 2
176#define RR_STATE_ERROR 3
177
178#define RESTART_NORMAL 0
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600179#define RESTART_PEND 1
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700180
181/* State for remote ep following restart */
182#define RESTART_QUOTA_ABORT 1
183
184static LIST_HEAD(xprt_info_list);
185static DEFINE_MUTEX(xprt_info_list_lock);
186
Karthikeyan Ramasubramanian4af9f7c2011-09-30 15:55:18 -0600187static DECLARE_COMPLETION(msm_ipc_local_router_up);
188#define IPC_ROUTER_INIT_TIMEOUT (10 * HZ)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700189
190static uint32_t next_port_id;
191static DEFINE_MUTEX(next_port_id_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600192static struct workqueue_struct *msm_ipc_router_workqueue;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700193
194enum {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700195 DOWN,
196 UP,
197};
198
199static void init_routing_table(void)
200{
201 int i;
202 for (i = 0; i < RT_HASH_SIZE; i++)
203 INIT_LIST_HEAD(&routing_table[i]);
204}
205
206static struct msm_ipc_routing_table_entry *alloc_routing_table_entry(
207 uint32_t node_id)
208{
209 int i;
210 struct msm_ipc_routing_table_entry *rt_entry;
211
212 rt_entry = kmalloc(sizeof(struct msm_ipc_routing_table_entry),
213 GFP_KERNEL);
214 if (!rt_entry) {
215 pr_err("%s: rt_entry allocation failed for %d\n",
216 __func__, node_id);
217 return NULL;
218 }
219
220 for (i = 0; i < RP_HASH_SIZE; i++)
221 INIT_LIST_HEAD(&rt_entry->remote_port_list[i]);
222
223 mutex_init(&rt_entry->lock);
224 rt_entry->node_id = node_id;
225 rt_entry->xprt_info = NULL;
226 return rt_entry;
227}
228
229/*Please take routing_table_lock before calling this function*/
230static int add_routing_table_entry(
231 struct msm_ipc_routing_table_entry *rt_entry)
232{
233 uint32_t key;
234
235 if (!rt_entry)
236 return -EINVAL;
237
238 key = (rt_entry->node_id % RT_HASH_SIZE);
239 list_add_tail(&rt_entry->list, &routing_table[key]);
240 return 0;
241}
242
243/*Please take routing_table_lock before calling this function*/
244static struct msm_ipc_routing_table_entry *lookup_routing_table(
245 uint32_t node_id)
246{
247 uint32_t key = (node_id % RT_HASH_SIZE);
248 struct msm_ipc_routing_table_entry *rt_entry;
249
250 list_for_each_entry(rt_entry, &routing_table[key], list) {
251 if (rt_entry->node_id == node_id)
252 return rt_entry;
253 }
254 return NULL;
255}
256
257struct rr_packet *rr_read(struct msm_ipc_router_xprt_info *xprt_info)
258{
259 struct rr_packet *temp_pkt;
260
261 if (!xprt_info)
262 return NULL;
263
264 mutex_lock(&xprt_info->rx_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600265 if (xprt_info->abort_data_read) {
266 mutex_unlock(&xprt_info->rx_lock);
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -0600267 pr_err("%s detected SSR & exiting now\n",
268 xprt_info->xprt->name);
269 return NULL;
270 }
271
272 if (list_empty(&xprt_info->pkt_list)) {
273 mutex_unlock(&xprt_info->rx_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600274 return NULL;
275 }
276
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700277 temp_pkt = list_first_entry(&xprt_info->pkt_list,
278 struct rr_packet, list);
279 list_del(&temp_pkt->list);
280 if (list_empty(&xprt_info->pkt_list))
281 wake_unlock(&xprt_info->wakelock);
282 mutex_unlock(&xprt_info->rx_lock);
283 return temp_pkt;
284}
285
286struct rr_packet *clone_pkt(struct rr_packet *pkt)
287{
288 struct rr_packet *cloned_pkt;
289 struct sk_buff *temp_skb, *cloned_skb;
290 struct sk_buff_head *pkt_fragment_q;
291
292 cloned_pkt = kzalloc(sizeof(struct rr_packet), GFP_KERNEL);
293 if (!cloned_pkt) {
294 pr_err("%s: failure\n", __func__);
295 return NULL;
296 }
297
298 pkt_fragment_q = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
299 if (!pkt_fragment_q) {
300 pr_err("%s: pkt_frag_q alloc failure\n", __func__);
301 kfree(cloned_pkt);
302 return NULL;
303 }
304 skb_queue_head_init(pkt_fragment_q);
305
306 skb_queue_walk(pkt->pkt_fragment_q, temp_skb) {
307 cloned_skb = skb_clone(temp_skb, GFP_KERNEL);
308 if (!cloned_skb)
309 goto fail_clone;
310 skb_queue_tail(pkt_fragment_q, cloned_skb);
311 }
312 cloned_pkt->pkt_fragment_q = pkt_fragment_q;
313 cloned_pkt->length = pkt->length;
314 return cloned_pkt;
315
316fail_clone:
317 while (!skb_queue_empty(pkt_fragment_q)) {
318 temp_skb = skb_dequeue(pkt_fragment_q);
319 kfree_skb(temp_skb);
320 }
321 kfree(pkt_fragment_q);
322 kfree(cloned_pkt);
323 return NULL;
324}
325
326struct rr_packet *create_pkt(struct sk_buff_head *data)
327{
328 struct rr_packet *pkt;
329 struct sk_buff *temp_skb;
330
331 pkt = kzalloc(sizeof(struct rr_packet), GFP_KERNEL);
332 if (!pkt) {
333 pr_err("%s: failure\n", __func__);
334 return NULL;
335 }
336
337 pkt->pkt_fragment_q = data;
338 skb_queue_walk(pkt->pkt_fragment_q, temp_skb)
339 pkt->length += temp_skb->len;
340 return pkt;
341}
342
343void release_pkt(struct rr_packet *pkt)
344{
345 struct sk_buff *temp_skb;
346
347 if (!pkt)
348 return;
349
350 if (!pkt->pkt_fragment_q) {
351 kfree(pkt);
352 return;
353 }
354
355 while (!skb_queue_empty(pkt->pkt_fragment_q)) {
356 temp_skb = skb_dequeue(pkt->pkt_fragment_q);
357 kfree_skb(temp_skb);
358 }
359 kfree(pkt->pkt_fragment_q);
360 kfree(pkt);
361 return;
362}
363
364static int post_control_ports(struct rr_packet *pkt)
365{
366 struct msm_ipc_port *port_ptr;
367 struct rr_packet *cloned_pkt;
368
369 if (!pkt)
370 return -EINVAL;
371
372 mutex_lock(&control_ports_lock);
373 list_for_each_entry(port_ptr, &control_ports, list) {
374 mutex_lock(&port_ptr->port_rx_q_lock);
375 cloned_pkt = clone_pkt(pkt);
376 wake_lock(&port_ptr->port_rx_wake_lock);
377 list_add_tail(&cloned_pkt->list, &port_ptr->port_rx_q);
378 wake_up(&port_ptr->port_rx_wait_q);
379 mutex_unlock(&port_ptr->port_rx_q_lock);
380 }
381 mutex_unlock(&control_ports_lock);
382 return 0;
383}
384
385static uint32_t allocate_port_id(void)
386{
387 uint32_t port_id = 0, prev_port_id, key;
388 struct msm_ipc_port *port_ptr;
389
390 mutex_lock(&next_port_id_lock);
391 prev_port_id = next_port_id;
392 mutex_lock(&local_ports_lock);
393 do {
394 next_port_id++;
395 if ((next_port_id & 0xFFFFFFFE) == 0xFFFFFFFE)
396 next_port_id = 1;
397
398 key = (next_port_id & (LP_HASH_SIZE - 1));
399 if (list_empty(&local_ports[key])) {
400 port_id = next_port_id;
401 break;
402 }
403 list_for_each_entry(port_ptr, &local_ports[key], list) {
404 if (port_ptr->this_port.port_id == next_port_id) {
405 port_id = next_port_id;
406 break;
407 }
408 }
409 if (!port_id) {
410 port_id = next_port_id;
411 break;
412 }
413 port_id = 0;
414 } while (next_port_id != prev_port_id);
415 mutex_unlock(&local_ports_lock);
416 mutex_unlock(&next_port_id_lock);
417
418 return port_id;
419}
420
421void msm_ipc_router_add_local_port(struct msm_ipc_port *port_ptr)
422{
423 uint32_t key;
424
425 if (!port_ptr)
426 return;
427
428 key = (port_ptr->this_port.port_id & (LP_HASH_SIZE - 1));
429 mutex_lock(&local_ports_lock);
430 list_add_tail(&port_ptr->list, &local_ports[key]);
431 mutex_unlock(&local_ports_lock);
432}
433
434struct msm_ipc_port *msm_ipc_router_create_raw_port(void *endpoint,
435 void (*notify)(unsigned event, void *data,
436 void *addr, void *priv),
437 void *priv)
438{
439 struct msm_ipc_port *port_ptr;
440
441 port_ptr = kzalloc(sizeof(struct msm_ipc_port), GFP_KERNEL);
442 if (!port_ptr)
443 return NULL;
444
445 port_ptr->this_port.node_id = IPC_ROUTER_NID_LOCAL;
446 port_ptr->this_port.port_id = allocate_port_id();
447 if (!port_ptr->this_port.port_id) {
448 pr_err("%s: All port ids are in use\n", __func__);
449 kfree(port_ptr);
450 return NULL;
451 }
452
453 spin_lock_init(&port_ptr->port_lock);
454 INIT_LIST_HEAD(&port_ptr->incomplete);
455 mutex_init(&port_ptr->incomplete_lock);
456 INIT_LIST_HEAD(&port_ptr->port_rx_q);
457 mutex_init(&port_ptr->port_rx_q_lock);
458 init_waitqueue_head(&port_ptr->port_rx_wait_q);
Karthikeyan Ramasubramanianb4aeeb92012-03-13 12:31:43 -0600459 snprintf(port_ptr->rx_wakelock_name, MAX_WAKELOCK_NAME_SZ,
460 "msm_ipc_read%08x:%08x",
461 port_ptr->this_port.node_id,
462 port_ptr->this_port.port_id);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700463 wake_lock_init(&port_ptr->port_rx_wake_lock,
Karthikeyan Ramasubramanianb4aeeb92012-03-13 12:31:43 -0600464 WAKE_LOCK_SUSPEND, port_ptr->rx_wakelock_name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700465
466 port_ptr->endpoint = endpoint;
467 port_ptr->notify = notify;
468 port_ptr->priv = priv;
469
470 msm_ipc_router_add_local_port(port_ptr);
471 return port_ptr;
472}
473
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -0600474/*
475 * Should be called with local_ports_lock locked
476 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700477static struct msm_ipc_port *msm_ipc_router_lookup_local_port(uint32_t port_id)
478{
479 int key = (port_id & (LP_HASH_SIZE - 1));
480 struct msm_ipc_port *port_ptr;
481
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700482 list_for_each_entry(port_ptr, &local_ports[key], list) {
483 if (port_ptr->this_port.port_id == port_id) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700484 return port_ptr;
485 }
486 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700487 return NULL;
488}
489
490static struct msm_ipc_router_remote_port *msm_ipc_router_lookup_remote_port(
491 uint32_t node_id,
492 uint32_t port_id)
493{
494 struct msm_ipc_router_remote_port *rport_ptr;
495 struct msm_ipc_routing_table_entry *rt_entry;
496 int key = (port_id & (RP_HASH_SIZE - 1));
497
498 mutex_lock(&routing_table_lock);
499 rt_entry = lookup_routing_table(node_id);
500 if (!rt_entry) {
501 mutex_unlock(&routing_table_lock);
502 pr_err("%s: Node is not up\n", __func__);
503 return NULL;
504 }
505
506 mutex_lock(&rt_entry->lock);
507 list_for_each_entry(rport_ptr,
508 &rt_entry->remote_port_list[key], list) {
509 if (rport_ptr->port_id == port_id) {
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600510 if (rport_ptr->restart_state != RESTART_NORMAL)
511 rport_ptr = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700512 mutex_unlock(&rt_entry->lock);
513 mutex_unlock(&routing_table_lock);
514 return rport_ptr;
515 }
516 }
517 mutex_unlock(&rt_entry->lock);
518 mutex_unlock(&routing_table_lock);
519 return NULL;
520}
521
522static struct msm_ipc_router_remote_port *msm_ipc_router_create_remote_port(
523 uint32_t node_id,
524 uint32_t port_id)
525{
526 struct msm_ipc_router_remote_port *rport_ptr;
527 struct msm_ipc_routing_table_entry *rt_entry;
528 int key = (port_id & (RP_HASH_SIZE - 1));
529
530 mutex_lock(&routing_table_lock);
531 rt_entry = lookup_routing_table(node_id);
532 if (!rt_entry) {
533 mutex_unlock(&routing_table_lock);
534 pr_err("%s: Node is not up\n", __func__);
535 return NULL;
536 }
537
538 mutex_lock(&rt_entry->lock);
539 rport_ptr = kmalloc(sizeof(struct msm_ipc_router_remote_port),
540 GFP_KERNEL);
541 if (!rport_ptr) {
542 mutex_unlock(&rt_entry->lock);
543 mutex_unlock(&routing_table_lock);
544 pr_err("%s: Remote port alloc failed\n", __func__);
545 return NULL;
546 }
547 rport_ptr->port_id = port_id;
548 rport_ptr->node_id = node_id;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600549 rport_ptr->restart_state = RESTART_NORMAL;
Karthikeyan Ramasubramanian1668cc62012-09-23 22:23:36 -0600550 rport_ptr->sec_rule = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700551 rport_ptr->tx_quota_cnt = 0;
552 init_waitqueue_head(&rport_ptr->quota_wait);
553 mutex_init(&rport_ptr->quota_lock);
554 list_add_tail(&rport_ptr->list,
555 &rt_entry->remote_port_list[key]);
556 mutex_unlock(&rt_entry->lock);
557 mutex_unlock(&routing_table_lock);
558 return rport_ptr;
559}
560
561static void msm_ipc_router_destroy_remote_port(
562 struct msm_ipc_router_remote_port *rport_ptr)
563{
564 uint32_t node_id;
565 struct msm_ipc_routing_table_entry *rt_entry;
566
567 if (!rport_ptr)
568 return;
569
570 node_id = rport_ptr->node_id;
571 mutex_lock(&routing_table_lock);
572 rt_entry = lookup_routing_table(node_id);
573 if (!rt_entry) {
574 mutex_unlock(&routing_table_lock);
575 pr_err("%s: Node %d is not up\n", __func__, node_id);
576 return;
577 }
578
579 mutex_lock(&rt_entry->lock);
580 list_del(&rport_ptr->list);
581 kfree(rport_ptr);
582 mutex_unlock(&rt_entry->lock);
583 mutex_unlock(&routing_table_lock);
584 return;
585}
586
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -0600587/**
588 * msm_ipc_router_lookup_server() - Lookup server information
589 * @service: Service ID of the server info to be looked up.
590 * @instance: Instance ID of the server info to be looked up.
591 * @node_id: Node/Processor ID in which the server is hosted.
592 * @port_id: Port ID within the node in which the server is hosted.
593 *
594 * @return: If found Pointer to server structure, else NULL.
595 *
596 * Note1: Lock the server_list_lock before accessing this function.
597 * Note2: If the <node_id:port_id> are <0:0>, then the lookup is restricted
598 * to <service:instance>. Used only when a client wants to send a
599 * message to any QMI server.
600 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700601static struct msm_ipc_server *msm_ipc_router_lookup_server(
602 uint32_t service,
603 uint32_t instance,
604 uint32_t node_id,
605 uint32_t port_id)
606{
607 struct msm_ipc_server *server;
608 struct msm_ipc_server_port *server_port;
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -0600609 int key = (service & (SRV_HASH_SIZE - 1));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700610
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700611 list_for_each_entry(server, &server_list[key], list) {
612 if ((server->name.service != service) ||
613 (server->name.instance != instance))
614 continue;
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -0600615 if ((node_id == 0) && (port_id == 0))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700616 return server;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700617 list_for_each_entry(server_port, &server->server_port_list,
618 list) {
619 if ((server_port->server_addr.node_id == node_id) &&
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -0600620 (server_port->server_addr.port_id == port_id))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700621 return server;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700622 }
623 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700624 return NULL;
625}
626
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -0600627/**
628 * msm_ipc_router_create_server() - Add server info to hash table
629 * @service: Service ID of the server info to be created.
630 * @instance: Instance ID of the server info to be created.
631 * @node_id: Node/Processor ID in which the server is hosted.
632 * @port_id: Port ID within the node in which the server is hosted.
633 * @xprt_info: XPRT through which the node hosting the server is reached.
634 *
635 * @return: Pointer to server structure on success, else NULL.
636 *
637 * This function adds the server info to the hash table. If the same
638 * server(i.e. <service_id:instance_id>) is hosted in different nodes,
639 * they are maintained as list of "server_port" under "server" structure.
640 * Note: Lock the server_list_lock before accessing this function.
641 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700642static struct msm_ipc_server *msm_ipc_router_create_server(
643 uint32_t service,
644 uint32_t instance,
645 uint32_t node_id,
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600646 uint32_t port_id,
647 struct msm_ipc_router_xprt_info *xprt_info)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700648{
649 struct msm_ipc_server *server = NULL;
650 struct msm_ipc_server_port *server_port;
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -0600651 int key = (service & (SRV_HASH_SIZE - 1));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700652
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700653 list_for_each_entry(server, &server_list[key], list) {
654 if ((server->name.service == service) &&
655 (server->name.instance == instance))
656 goto create_srv_port;
657 }
658
659 server = kmalloc(sizeof(struct msm_ipc_server), GFP_KERNEL);
660 if (!server) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700661 pr_err("%s: Server allocation failed\n", __func__);
662 return NULL;
663 }
664 server->name.service = service;
665 server->name.instance = instance;
Karthikeyan Ramasubramanian1668cc62012-09-23 22:23:36 -0600666 server->synced_sec_rule = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700667 INIT_LIST_HEAD(&server->server_port_list);
668 list_add_tail(&server->list, &server_list[key]);
669
670create_srv_port:
671 server_port = kmalloc(sizeof(struct msm_ipc_server_port), GFP_KERNEL);
672 if (!server_port) {
673 if (list_empty(&server->server_port_list)) {
674 list_del(&server->list);
675 kfree(server);
676 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700677 pr_err("%s: Server Port allocation failed\n", __func__);
678 return NULL;
679 }
680 server_port->server_addr.node_id = node_id;
681 server_port->server_addr.port_id = port_id;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600682 server_port->xprt_info = xprt_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700683 list_add_tail(&server_port->list, &server->server_port_list);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700684
685 return server;
686}
687
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -0600688/**
689 * msm_ipc_router_destroy_server() - Remove server info from hash table
690 * @server: Server info to be removed.
691 * @node_id: Node/Processor ID in which the server is hosted.
692 * @port_id: Port ID within the node in which the server is hosted.
693 *
694 * This function removes the server_port identified using <node_id:port_id>
695 * from the server structure. If the server_port list under server structure
696 * is empty after removal, then remove the server structure from the server
697 * hash table.
698 * Note: Lock the server_list_lock before accessing this function.
699 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700700static void msm_ipc_router_destroy_server(struct msm_ipc_server *server,
701 uint32_t node_id, uint32_t port_id)
702{
703 struct msm_ipc_server_port *server_port;
704
705 if (!server)
706 return;
707
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700708 list_for_each_entry(server_port, &server->server_port_list, list) {
709 if ((server_port->server_addr.node_id == node_id) &&
710 (server_port->server_addr.port_id == port_id))
711 break;
712 }
713 if (server_port) {
714 list_del(&server_port->list);
715 kfree(server_port);
716 }
717 if (list_empty(&server->server_port_list)) {
718 list_del(&server->list);
719 kfree(server);
720 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700721 return;
722}
723
724static int msm_ipc_router_send_control_msg(
725 struct msm_ipc_router_xprt_info *xprt_info,
726 union rr_control_msg *msg)
727{
728 struct rr_packet *pkt;
729 struct sk_buff *ipc_rtr_pkt;
730 struct rr_header *hdr;
731 int pkt_size;
732 void *data;
733 struct sk_buff_head *pkt_fragment_q;
734 int ret;
735
736 if (!xprt_info || ((msg->cmd != IPC_ROUTER_CTRL_CMD_HELLO) &&
737 !xprt_info->initialized)) {
738 pr_err("%s: xprt_info not initialized\n", __func__);
739 return -EINVAL;
740 }
741
742 if (xprt_info->remote_node_id == IPC_ROUTER_NID_LOCAL)
743 return 0;
744
745 pkt = kzalloc(sizeof(struct rr_packet), GFP_KERNEL);
746 if (!pkt) {
747 pr_err("%s: pkt alloc failed\n", __func__);
748 return -ENOMEM;
749 }
750
751 pkt_fragment_q = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
752 if (!pkt_fragment_q) {
753 pr_err("%s: pkt_fragment_q alloc failed\n", __func__);
754 kfree(pkt);
755 return -ENOMEM;
756 }
757 skb_queue_head_init(pkt_fragment_q);
758
759 pkt_size = IPC_ROUTER_HDR_SIZE + sizeof(*msg);
760 ipc_rtr_pkt = alloc_skb(pkt_size, GFP_KERNEL);
761 if (!ipc_rtr_pkt) {
762 pr_err("%s: ipc_rtr_pkt alloc failed\n", __func__);
763 kfree(pkt_fragment_q);
764 kfree(pkt);
765 return -ENOMEM;
766 }
767
768 skb_reserve(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
769 data = skb_put(ipc_rtr_pkt, sizeof(*msg));
770 memcpy(data, msg, sizeof(*msg));
771 hdr = (struct rr_header *)skb_push(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
772 if (!hdr) {
773 pr_err("%s: skb_push failed\n", __func__);
774 kfree_skb(ipc_rtr_pkt);
775 kfree(pkt_fragment_q);
776 kfree(pkt);
777 return -ENOMEM;
778 }
779
780 hdr->version = IPC_ROUTER_VERSION;
781 hdr->type = msg->cmd;
782 hdr->src_node_id = IPC_ROUTER_NID_LOCAL;
783 hdr->src_port_id = IPC_ROUTER_ADDRESS;
784 hdr->confirm_rx = 0;
785 hdr->size = sizeof(*msg);
786 hdr->dst_node_id = xprt_info->remote_node_id;
787 hdr->dst_port_id = IPC_ROUTER_ADDRESS;
788 skb_queue_tail(pkt_fragment_q, ipc_rtr_pkt);
789 pkt->pkt_fragment_q = pkt_fragment_q;
790 pkt->length = pkt_size;
791
792 mutex_lock(&xprt_info->tx_lock);
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700793 ret = xprt_info->xprt->write(pkt, pkt_size, xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700794 mutex_unlock(&xprt_info->tx_lock);
795
796 release_pkt(pkt);
797 return ret;
798}
799
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -0600800static int msm_ipc_router_send_server_list(uint32_t node_id,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700801 struct msm_ipc_router_xprt_info *xprt_info)
802{
803 union rr_control_msg ctl;
804 struct msm_ipc_server *server;
805 struct msm_ipc_server_port *server_port;
806 int i;
807
808 if (!xprt_info || !xprt_info->initialized) {
809 pr_err("%s: Xprt info not initialized\n", __func__);
810 return -EINVAL;
811 }
812
813 ctl.cmd = IPC_ROUTER_CTRL_CMD_NEW_SERVER;
814
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700815 for (i = 0; i < SRV_HASH_SIZE; i++) {
816 list_for_each_entry(server, &server_list[i], list) {
817 ctl.srv.service = server->name.service;
818 ctl.srv.instance = server->name.instance;
819 list_for_each_entry(server_port,
820 &server->server_port_list, list) {
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -0600821 if (server_port->server_addr.node_id !=
822 node_id)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700823 continue;
824
825 ctl.srv.node_id =
826 server_port->server_addr.node_id;
827 ctl.srv.port_id =
828 server_port->server_addr.port_id;
829 msm_ipc_router_send_control_msg(xprt_info,
830 &ctl);
831 }
832 }
833 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700834
835 return 0;
836}
837
838#if defined(DEBUG)
839static char *type_to_str(int i)
840{
841 switch (i) {
842 case IPC_ROUTER_CTRL_CMD_DATA:
843 return "data ";
844 case IPC_ROUTER_CTRL_CMD_HELLO:
845 return "hello ";
846 case IPC_ROUTER_CTRL_CMD_BYE:
847 return "bye ";
848 case IPC_ROUTER_CTRL_CMD_NEW_SERVER:
849 return "new_srvr";
850 case IPC_ROUTER_CTRL_CMD_REMOVE_SERVER:
851 return "rmv_srvr";
852 case IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT:
853 return "rmv_clnt";
854 case IPC_ROUTER_CTRL_CMD_RESUME_TX:
855 return "resum_tx";
856 case IPC_ROUTER_CTRL_CMD_EXIT:
857 return "cmd_exit";
858 default:
859 return "invalid";
860 }
861}
862#endif
863
864static int broadcast_ctl_msg_locally(union rr_control_msg *msg)
865{
866 struct rr_packet *pkt;
867 struct sk_buff *ipc_rtr_pkt;
868 struct rr_header *hdr;
869 int pkt_size;
870 void *data;
871 struct sk_buff_head *pkt_fragment_q;
872 int ret;
873
874 pkt = kzalloc(sizeof(struct rr_packet), GFP_KERNEL);
875 if (!pkt) {
876 pr_err("%s: pkt alloc failed\n", __func__);
877 return -ENOMEM;
878 }
879
880 pkt_fragment_q = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
881 if (!pkt_fragment_q) {
882 pr_err("%s: pkt_fragment_q alloc failed\n", __func__);
883 kfree(pkt);
884 return -ENOMEM;
885 }
886 skb_queue_head_init(pkt_fragment_q);
887
888 pkt_size = IPC_ROUTER_HDR_SIZE + sizeof(*msg);
889 ipc_rtr_pkt = alloc_skb(pkt_size, GFP_KERNEL);
890 if (!ipc_rtr_pkt) {
891 pr_err("%s: ipc_rtr_pkt alloc failed\n", __func__);
892 kfree(pkt_fragment_q);
893 kfree(pkt);
894 return -ENOMEM;
895 }
896
897 skb_reserve(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
898 data = skb_put(ipc_rtr_pkt, sizeof(*msg));
899 memcpy(data, msg, sizeof(*msg));
900 hdr = (struct rr_header *)skb_push(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
901 if (!hdr) {
902 pr_err("%s: skb_push failed\n", __func__);
903 kfree_skb(ipc_rtr_pkt);
904 kfree(pkt_fragment_q);
905 kfree(pkt);
906 return -ENOMEM;
907 }
908 hdr->version = IPC_ROUTER_VERSION;
909 hdr->type = msg->cmd;
910 hdr->src_node_id = IPC_ROUTER_NID_LOCAL;
911 hdr->src_port_id = IPC_ROUTER_ADDRESS;
912 hdr->confirm_rx = 0;
913 hdr->size = sizeof(*msg);
914 hdr->dst_node_id = IPC_ROUTER_NID_LOCAL;
915 hdr->dst_port_id = IPC_ROUTER_ADDRESS;
916 skb_queue_tail(pkt_fragment_q, ipc_rtr_pkt);
917 pkt->pkt_fragment_q = pkt_fragment_q;
918 pkt->length = pkt_size;
919
920 ret = post_control_ports(pkt);
921 release_pkt(pkt);
922 return ret;
923}
924
925static int broadcast_ctl_msg(union rr_control_msg *ctl)
926{
927 struct msm_ipc_router_xprt_info *xprt_info;
928
929 mutex_lock(&xprt_info_list_lock);
930 list_for_each_entry(xprt_info, &xprt_info_list, list) {
931 msm_ipc_router_send_control_msg(xprt_info, ctl);
932 }
933 mutex_unlock(&xprt_info_list_lock);
934
935 return 0;
936}
937
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600938static int relay_ctl_msg(struct msm_ipc_router_xprt_info *xprt_info,
939 union rr_control_msg *ctl)
940{
941 struct msm_ipc_router_xprt_info *fwd_xprt_info;
942
943 if (!xprt_info || !ctl)
944 return -EINVAL;
945
946 mutex_lock(&xprt_info_list_lock);
947 list_for_each_entry(fwd_xprt_info, &xprt_info_list, list) {
948 if (xprt_info->xprt->link_id != fwd_xprt_info->xprt->link_id)
949 msm_ipc_router_send_control_msg(fwd_xprt_info, ctl);
950 }
951 mutex_unlock(&xprt_info_list_lock);
952
953 return 0;
954}
955
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700956static int relay_msg(struct msm_ipc_router_xprt_info *xprt_info,
957 struct rr_packet *pkt)
958{
959 struct msm_ipc_router_xprt_info *fwd_xprt_info;
960
961 if (!xprt_info || !pkt)
962 return -EINVAL;
963
964 mutex_lock(&xprt_info_list_lock);
965 list_for_each_entry(fwd_xprt_info, &xprt_info_list, list) {
966 mutex_lock(&fwd_xprt_info->tx_lock);
967 if (xprt_info->xprt->link_id != fwd_xprt_info->xprt->link_id)
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700968 fwd_xprt_info->xprt->write(pkt, pkt->length,
969 fwd_xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700970 mutex_unlock(&fwd_xprt_info->tx_lock);
971 }
972 mutex_unlock(&xprt_info_list_lock);
973 return 0;
974}
975
976static int forward_msg(struct msm_ipc_router_xprt_info *xprt_info,
977 struct rr_packet *pkt)
978{
979 uint32_t dst_node_id;
980 struct sk_buff *head_pkt;
981 struct rr_header *hdr;
982 struct msm_ipc_router_xprt_info *fwd_xprt_info;
983 struct msm_ipc_routing_table_entry *rt_entry;
984
985 if (!xprt_info || !pkt)
986 return -EINVAL;
987
988 head_pkt = skb_peek(pkt->pkt_fragment_q);
989 if (!head_pkt)
990 return -EINVAL;
991
992 hdr = (struct rr_header *)head_pkt->data;
993 dst_node_id = hdr->dst_node_id;
994 mutex_lock(&routing_table_lock);
995 rt_entry = lookup_routing_table(dst_node_id);
996 if (!(rt_entry) || !(rt_entry->xprt_info)) {
997 mutex_unlock(&routing_table_lock);
998 pr_err("%s: Routing table not initialized\n", __func__);
999 return -ENODEV;
1000 }
1001
1002 mutex_lock(&rt_entry->lock);
1003 fwd_xprt_info = rt_entry->xprt_info;
1004 mutex_lock(&fwd_xprt_info->tx_lock);
1005 if (xprt_info->remote_node_id == fwd_xprt_info->remote_node_id) {
1006 mutex_unlock(&fwd_xprt_info->tx_lock);
1007 mutex_unlock(&rt_entry->lock);
1008 mutex_unlock(&routing_table_lock);
1009 pr_err("%s: Discarding Command to route back\n", __func__);
1010 return -EINVAL;
1011 }
1012
1013 if (xprt_info->xprt->link_id == fwd_xprt_info->xprt->link_id) {
1014 mutex_unlock(&fwd_xprt_info->tx_lock);
1015 mutex_unlock(&rt_entry->lock);
1016 mutex_unlock(&routing_table_lock);
1017 pr_err("%s: DST in the same cluster\n", __func__);
1018 return 0;
1019 }
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -07001020 fwd_xprt_info->xprt->write(pkt, pkt->length, fwd_xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001021 mutex_unlock(&fwd_xprt_info->tx_lock);
1022 mutex_unlock(&rt_entry->lock);
1023 mutex_unlock(&routing_table_lock);
1024
1025 return 0;
1026}
1027
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001028static void reset_remote_port_info(uint32_t node_id, uint32_t port_id)
1029{
1030 struct msm_ipc_router_remote_port *rport_ptr;
1031
1032 rport_ptr = msm_ipc_router_lookup_remote_port(node_id, port_id);
1033 if (!rport_ptr) {
1034 pr_err("%s: No such remote port %08x:%08x\n",
1035 __func__, node_id, port_id);
1036 return;
1037 }
1038 mutex_lock(&rport_ptr->quota_lock);
1039 rport_ptr->restart_state = RESTART_PEND;
1040 wake_up(&rport_ptr->quota_wait);
1041 mutex_unlock(&rport_ptr->quota_lock);
1042 return;
1043}
1044
1045static void msm_ipc_cleanup_remote_server_info(
1046 struct msm_ipc_router_xprt_info *xprt_info)
1047{
1048 struct msm_ipc_server *svr, *tmp_svr;
1049 struct msm_ipc_server_port *svr_port, *tmp_svr_port;
1050 int i;
1051 union rr_control_msg ctl;
1052
1053 if (!xprt_info) {
1054 pr_err("%s: Invalid xprt_info\n", __func__);
1055 return;
1056 }
1057
1058 ctl.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_SERVER;
1059 mutex_lock(&server_list_lock);
1060 for (i = 0; i < SRV_HASH_SIZE; i++) {
1061 list_for_each_entry_safe(svr, tmp_svr, &server_list[i], list) {
1062 ctl.srv.service = svr->name.service;
1063 ctl.srv.instance = svr->name.instance;
1064 list_for_each_entry_safe(svr_port, tmp_svr_port,
1065 &svr->server_port_list, list) {
1066 if (svr_port->xprt_info != xprt_info)
1067 continue;
1068 D("Remove server %08x:%08x - %08x:%08x",
1069 ctl.srv.service, ctl.srv.instance,
1070 svr_port->server_addr.node_id,
1071 svr_port->server_addr.port_id);
1072 reset_remote_port_info(
1073 svr_port->server_addr.node_id,
1074 svr_port->server_addr.port_id);
1075 ctl.srv.node_id = svr_port->server_addr.node_id;
1076 ctl.srv.port_id = svr_port->server_addr.port_id;
1077 relay_ctl_msg(xprt_info, &ctl);
1078 broadcast_ctl_msg_locally(&ctl);
1079 list_del(&svr_port->list);
1080 kfree(svr_port);
1081 }
1082 if (list_empty(&svr->server_port_list)) {
1083 list_del(&svr->list);
1084 kfree(svr);
1085 }
1086 }
1087 }
1088 mutex_unlock(&server_list_lock);
1089}
1090
1091static void msm_ipc_cleanup_remote_client_info(
1092 struct msm_ipc_router_xprt_info *xprt_info)
1093{
1094 struct msm_ipc_routing_table_entry *rt_entry;
1095 struct msm_ipc_router_remote_port *rport_ptr;
1096 int i, j;
1097 union rr_control_msg ctl;
1098
1099 if (!xprt_info) {
1100 pr_err("%s: Invalid xprt_info\n", __func__);
1101 return;
1102 }
1103
1104 ctl.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT;
1105 mutex_lock(&routing_table_lock);
1106 for (i = 0; i < RT_HASH_SIZE; i++) {
1107 list_for_each_entry(rt_entry, &routing_table[i], list) {
1108 mutex_lock(&rt_entry->lock);
1109 if (rt_entry->xprt_info != xprt_info) {
1110 mutex_unlock(&rt_entry->lock);
1111 continue;
1112 }
1113 for (j = 0; j < RP_HASH_SIZE; j++) {
1114 list_for_each_entry(rport_ptr,
1115 &rt_entry->remote_port_list[j], list) {
1116 if (rport_ptr->restart_state ==
1117 RESTART_PEND)
1118 continue;
1119 mutex_lock(&rport_ptr->quota_lock);
1120 rport_ptr->restart_state = RESTART_PEND;
1121 wake_up(&rport_ptr->quota_wait);
1122 mutex_unlock(&rport_ptr->quota_lock);
1123 ctl.cli.node_id = rport_ptr->node_id;
1124 ctl.cli.port_id = rport_ptr->port_id;
1125 broadcast_ctl_msg_locally(&ctl);
1126 }
1127 }
1128 mutex_unlock(&rt_entry->lock);
1129 }
1130 }
1131 mutex_unlock(&routing_table_lock);
1132}
1133
1134static void msm_ipc_cleanup_remote_port_info(uint32_t node_id)
1135{
1136 struct msm_ipc_routing_table_entry *rt_entry, *tmp_rt_entry;
1137 struct msm_ipc_router_remote_port *rport_ptr, *tmp_rport_ptr;
1138 int i, j;
1139
1140 mutex_lock(&routing_table_lock);
1141 for (i = 0; i < RT_HASH_SIZE; i++) {
1142 list_for_each_entry_safe(rt_entry, tmp_rt_entry,
1143 &routing_table[i], list) {
1144 mutex_lock(&rt_entry->lock);
1145 if (rt_entry->neighbor_node_id != node_id) {
1146 mutex_unlock(&rt_entry->lock);
1147 continue;
1148 }
1149 for (j = 0; j < RP_HASH_SIZE; j++) {
1150 list_for_each_entry_safe(rport_ptr,
1151 tmp_rport_ptr,
1152 &rt_entry->remote_port_list[j], list) {
1153 list_del(&rport_ptr->list);
1154 kfree(rport_ptr);
1155 }
1156 }
1157 mutex_unlock(&rt_entry->lock);
1158 }
1159 }
1160 mutex_unlock(&routing_table_lock);
1161}
1162
1163static void msm_ipc_cleanup_routing_table(
1164 struct msm_ipc_router_xprt_info *xprt_info)
1165{
1166 int i;
1167 struct msm_ipc_routing_table_entry *rt_entry;
1168
1169 if (!xprt_info) {
1170 pr_err("%s: Invalid xprt_info\n", __func__);
1171 return;
1172 }
1173
1174 mutex_lock(&routing_table_lock);
1175 for (i = 0; i < RT_HASH_SIZE; i++) {
1176 list_for_each_entry(rt_entry, &routing_table[i], list) {
1177 mutex_lock(&rt_entry->lock);
1178 if (rt_entry->xprt_info == xprt_info)
1179 rt_entry->xprt_info = NULL;
1180 mutex_unlock(&rt_entry->lock);
1181 }
1182 }
1183 mutex_unlock(&routing_table_lock);
1184}
1185
1186static void modem_reset_cleanup(struct msm_ipc_router_xprt_info *xprt_info)
1187{
1188
1189 if (!xprt_info) {
1190 pr_err("%s: Invalid xprt_info\n", __func__);
1191 return;
1192 }
1193
1194 msm_ipc_cleanup_remote_server_info(xprt_info);
1195 msm_ipc_cleanup_remote_client_info(xprt_info);
1196 msm_ipc_cleanup_routing_table(xprt_info);
1197}
1198
Karthikeyan Ramasubramanian1668cc62012-09-23 22:23:36 -06001199/**
1200 * sync_sec_rule() - Synchrnoize the security rule into the server structure
1201 * @server: Server structure where the rule has to be synchronized.
1202 * @rule: Security tule to be synchronized.
1203 *
1204 * This function is used to update the server structure with the security
1205 * rule configured for the <service:instance> corresponding to that server.
1206 */
1207static void sync_sec_rule(struct msm_ipc_server *server, void *rule)
1208{
1209 struct msm_ipc_server_port *server_port;
1210 struct msm_ipc_router_remote_port *rport_ptr = NULL;
1211
1212 list_for_each_entry(server_port, &server->server_port_list, list) {
1213 rport_ptr = msm_ipc_router_lookup_remote_port(
1214 server_port->server_addr.node_id,
1215 server_port->server_addr.port_id);
1216 if (!rport_ptr)
1217 continue;
1218 rport_ptr->sec_rule = rule;
1219 }
1220 server->synced_sec_rule = 1;
1221}
1222
1223/**
1224 * msm_ipc_sync_sec_rule() - Sync the security rule to the service
1225 * @service: Service for which the rule has to be synchronized.
1226 * @instance: Instance for which the rule has to be synchronized.
1227 * @rule: Security rule to be synchronized.
1228 *
1229 * This function is used to syncrhonize the security rule with the server
1230 * hash table, if the user-space script configures the rule after the service
1231 * has come up. This function is used to synchronize the security rule to a
1232 * specific service and optionally a specific instance.
1233 */
1234void msm_ipc_sync_sec_rule(uint32_t service, uint32_t instance, void *rule)
1235{
1236 int key = (service & (SRV_HASH_SIZE - 1));
1237 struct msm_ipc_server *server;
1238
1239 mutex_lock(&server_list_lock);
1240 list_for_each_entry(server, &server_list[key], list) {
1241 if (server->name.service != service)
1242 continue;
1243
1244 if (server->name.instance != instance &&
1245 instance != ALL_INSTANCE)
1246 continue;
1247
1248 /*
1249 * If the rule applies to all instances and if the specific
1250 * instance of a service has a rule synchronized already,
1251 * do not apply the rule for that specific instance.
1252 */
1253 if (instance == ALL_INSTANCE && server->synced_sec_rule)
1254 continue;
1255
1256 sync_sec_rule(server, rule);
1257 }
1258 mutex_unlock(&server_list_lock);
1259}
1260
1261/**
1262 * msm_ipc_sync_default_sec_rule() - Default security rule to all services
1263 * @rule: Security rule to be synchronized.
1264 *
1265 * This function is used to syncrhonize the security rule with the server
1266 * hash table, if the user-space script configures the rule after the service
1267 * has come up. This function is used to synchronize the security rule that
1268 * applies to all services, if the concerned service do not have any rule
1269 * defined.
1270 */
1271void msm_ipc_sync_default_sec_rule(void *rule)
1272{
1273 int key;
1274 struct msm_ipc_server *server;
1275
1276 mutex_lock(&server_list_lock);
1277 for (key = 0; key < SRV_HASH_SIZE; key++) {
1278 list_for_each_entry(server, &server_list[key], list) {
1279 if (server->synced_sec_rule)
1280 continue;
1281
1282 sync_sec_rule(server, rule);
1283 }
1284 }
1285 mutex_unlock(&server_list_lock);
1286}
1287
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001288static int process_hello_msg(struct msm_ipc_router_xprt_info *xprt_info,
1289 struct rr_header *hdr)
1290{
1291 int i, rc = 0;
1292 union rr_control_msg ctl;
1293 struct msm_ipc_routing_table_entry *rt_entry;
1294
1295 if (!hdr)
1296 return -EINVAL;
1297
1298 RR("o HELLO NID %d\n", hdr->src_node_id);
1299
1300 xprt_info->remote_node_id = hdr->src_node_id;
1301 /*
1302 * Find the entry from Routing Table corresponding to Node ID.
1303 * Under SSR, an entry will be found. When the system boots up
1304 * for the 1st time, an entry will not be found and hence allocate
1305 * an entry. Update the entry with the Node ID that it corresponds
1306 * to and the XPRT through which it can be reached.
1307 */
1308 mutex_lock(&routing_table_lock);
1309 rt_entry = lookup_routing_table(hdr->src_node_id);
1310 if (!rt_entry) {
1311 rt_entry = alloc_routing_table_entry(hdr->src_node_id);
1312 if (!rt_entry) {
1313 mutex_unlock(&routing_table_lock);
1314 pr_err("%s: rt_entry allocation failed\n", __func__);
1315 return -ENOMEM;
1316 }
1317 add_routing_table_entry(rt_entry);
1318 }
1319 mutex_lock(&rt_entry->lock);
1320 rt_entry->neighbor_node_id = xprt_info->remote_node_id;
1321 rt_entry->xprt_info = xprt_info;
1322 mutex_unlock(&rt_entry->lock);
1323 mutex_unlock(&routing_table_lock);
1324
1325 /* Cleanup any remote ports, if the node is coming out of reset */
1326 msm_ipc_cleanup_remote_port_info(xprt_info->remote_node_id);
1327
1328 /* Send a reply HELLO message */
1329 memset(&ctl, 0, sizeof(ctl));
1330 ctl.cmd = IPC_ROUTER_CTRL_CMD_HELLO;
1331 rc = msm_ipc_router_send_control_msg(xprt_info, &ctl);
1332 if (rc < 0) {
1333 pr_err("%s: Error sending reply HELLO message\n", __func__);
1334 return rc;
1335 }
1336 xprt_info->initialized = 1;
1337
1338 /*
1339 * Send list of servers from the local node and from nodes
1340 * outside the mesh network in which this XPRT is part of.
1341 */
Karthikeyan Ramasubramaniane8ad5352012-10-31 15:12:08 -06001342 mutex_lock(&server_list_lock);
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001343 mutex_lock(&routing_table_lock);
1344 for (i = 0; i < RT_HASH_SIZE; i++) {
1345 list_for_each_entry(rt_entry, &routing_table[i], list) {
1346 if ((rt_entry->node_id != IPC_ROUTER_NID_LOCAL) &&
Karthikeyan Ramasubramanian72ad5792013-01-30 14:17:57 -07001347 (!rt_entry->xprt_info ||
1348 (rt_entry->xprt_info->xprt->link_id ==
1349 xprt_info->xprt->link_id)))
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001350 continue;
1351 rc = msm_ipc_router_send_server_list(rt_entry->node_id,
1352 xprt_info);
1353 if (rc < 0) {
1354 mutex_unlock(&routing_table_lock);
Karthikeyan Ramasubramaniane8ad5352012-10-31 15:12:08 -06001355 mutex_unlock(&server_list_lock);
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001356 return rc;
1357 }
1358 }
1359 }
1360 mutex_unlock(&routing_table_lock);
Karthikeyan Ramasubramaniane8ad5352012-10-31 15:12:08 -06001361 mutex_unlock(&server_list_lock);
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001362 RR("HELLO message processed\n");
1363 return rc;
1364}
1365
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001366static int process_control_msg(struct msm_ipc_router_xprt_info *xprt_info,
1367 struct rr_packet *pkt)
1368{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001369 union rr_control_msg *msg;
1370 struct msm_ipc_router_remote_port *rport_ptr;
1371 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001372 struct sk_buff *temp_ptr;
1373 struct rr_header *hdr;
1374 struct msm_ipc_server *server;
1375 struct msm_ipc_routing_table_entry *rt_entry;
1376
1377 if (pkt->length != (IPC_ROUTER_HDR_SIZE + sizeof(*msg))) {
1378 pr_err("%s: r2r msg size %d != %d\n", __func__, pkt->length,
1379 (IPC_ROUTER_HDR_SIZE + sizeof(*msg)));
1380 return -EINVAL;
1381 }
1382
1383 temp_ptr = skb_peek(pkt->pkt_fragment_q);
Karthikeyan Ramasubramanian9024dd82011-12-19 18:44:19 -07001384 if (!temp_ptr) {
1385 pr_err("%s: pkt_fragment_q is empty\n", __func__);
1386 return -EINVAL;
1387 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001388 hdr = (struct rr_header *)temp_ptr->data;
Karthikeyan Ramasubramanian9024dd82011-12-19 18:44:19 -07001389 if (!hdr) {
1390 pr_err("%s: No data inside the skb\n", __func__);
1391 return -EINVAL;
1392 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001393 msg = (union rr_control_msg *)((char *)hdr + IPC_ROUTER_HDR_SIZE);
1394
1395 switch (msg->cmd) {
1396 case IPC_ROUTER_CTRL_CMD_HELLO:
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001397 rc = process_hello_msg(xprt_info, hdr);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001398 break;
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001399
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001400 case IPC_ROUTER_CTRL_CMD_RESUME_TX:
1401 RR("o RESUME_TX id=%d:%08x\n",
1402 msg->cli.node_id, msg->cli.port_id);
1403
1404 rport_ptr = msm_ipc_router_lookup_remote_port(msg->cli.node_id,
1405 msg->cli.port_id);
1406 if (!rport_ptr) {
1407 pr_err("%s: Unable to resume client\n", __func__);
1408 break;
1409 }
1410 mutex_lock(&rport_ptr->quota_lock);
1411 rport_ptr->tx_quota_cnt = 0;
1412 mutex_unlock(&rport_ptr->quota_lock);
1413 wake_up(&rport_ptr->quota_wait);
1414 break;
1415
1416 case IPC_ROUTER_CTRL_CMD_NEW_SERVER:
1417 if (msg->srv.instance == 0) {
1418 pr_err(
1419 "rpcrouter: Server create rejected, version = 0, "
1420 "service = %08x\n", msg->srv.service);
1421 break;
1422 }
1423
1424 RR("o NEW_SERVER id=%d:%08x service=%08x:%08x\n",
1425 msg->srv.node_id, msg->srv.port_id,
1426 msg->srv.service, msg->srv.instance);
1427
1428 mutex_lock(&routing_table_lock);
1429 rt_entry = lookup_routing_table(msg->srv.node_id);
1430 if (!rt_entry) {
1431 rt_entry = alloc_routing_table_entry(msg->srv.node_id);
1432 if (!rt_entry) {
1433 mutex_unlock(&routing_table_lock);
1434 pr_err("%s: rt_entry allocation failed\n",
1435 __func__);
1436 return -ENOMEM;
1437 }
1438 mutex_lock(&rt_entry->lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001439 rt_entry->neighbor_node_id = xprt_info->remote_node_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001440 rt_entry->xprt_info = xprt_info;
1441 mutex_unlock(&rt_entry->lock);
1442 add_routing_table_entry(rt_entry);
1443 }
1444 mutex_unlock(&routing_table_lock);
1445
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001446 mutex_lock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001447 server = msm_ipc_router_lookup_server(msg->srv.service,
1448 msg->srv.instance,
1449 msg->srv.node_id,
1450 msg->srv.port_id);
1451 if (!server) {
1452 server = msm_ipc_router_create_server(
1453 msg->srv.service, msg->srv.instance,
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001454 msg->srv.node_id, msg->srv.port_id, xprt_info);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001455 if (!server) {
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001456 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001457 pr_err("%s: Server Create failed\n", __func__);
1458 return -ENOMEM;
1459 }
1460
1461 if (!msm_ipc_router_lookup_remote_port(
1462 msg->srv.node_id, msg->srv.port_id)) {
1463 rport_ptr = msm_ipc_router_create_remote_port(
1464 msg->srv.node_id, msg->srv.port_id);
1465 if (!rport_ptr)
1466 pr_err("%s: Remote port create "
1467 "failed\n", __func__);
Brent Hronik0e83d3b2013-05-01 16:25:00 -06001468 else
1469 rport_ptr->sec_rule =
1470 msm_ipc_get_security_rule(
1471 msg->srv.service,
1472 msg->srv.instance);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001473 }
1474 wake_up(&newserver_wait);
1475 }
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001476 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001477
1478 relay_msg(xprt_info, pkt);
1479 post_control_ports(pkt);
1480 break;
1481 case IPC_ROUTER_CTRL_CMD_REMOVE_SERVER:
1482 RR("o REMOVE_SERVER service=%08x:%d\n",
1483 msg->srv.service, msg->srv.instance);
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001484 mutex_lock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001485 server = msm_ipc_router_lookup_server(msg->srv.service,
1486 msg->srv.instance,
1487 msg->srv.node_id,
1488 msg->srv.port_id);
1489 if (server) {
1490 msm_ipc_router_destroy_server(server,
1491 msg->srv.node_id,
1492 msg->srv.port_id);
1493 relay_msg(xprt_info, pkt);
1494 post_control_ports(pkt);
1495 }
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001496 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001497 break;
1498 case IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT:
1499 RR("o REMOVE_CLIENT id=%d:%08x\n",
1500 msg->cli.node_id, msg->cli.port_id);
1501 rport_ptr = msm_ipc_router_lookup_remote_port(msg->cli.node_id,
1502 msg->cli.port_id);
1503 if (rport_ptr)
1504 msm_ipc_router_destroy_remote_port(rport_ptr);
1505
1506 relay_msg(xprt_info, pkt);
1507 post_control_ports(pkt);
1508 break;
1509 case IPC_ROUTER_CTRL_CMD_PING:
1510 /* No action needed for ping messages received */
1511 RR("o PING\n");
1512 break;
1513 default:
1514 RR("o UNKNOWN(%08x)\n", msg->cmd);
1515 rc = -ENOSYS;
1516 }
1517
1518 return rc;
1519}
1520
1521static void do_read_data(struct work_struct *work)
1522{
1523 struct rr_header *hdr;
1524 struct rr_packet *pkt = NULL;
1525 struct msm_ipc_port *port_ptr;
1526 struct sk_buff *head_skb;
1527 struct msm_ipc_port_addr *src_addr;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001528 struct msm_ipc_router_remote_port *rport_ptr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001529 uint32_t resume_tx, resume_tx_node_id, resume_tx_port_id;
1530
1531 struct msm_ipc_router_xprt_info *xprt_info =
1532 container_of(work,
1533 struct msm_ipc_router_xprt_info,
1534 read_data);
1535
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001536 while ((pkt = rr_read(xprt_info)) != NULL) {
1537 if (pkt->length < IPC_ROUTER_HDR_SIZE ||
1538 pkt->length > MAX_IPC_PKT_SIZE) {
1539 pr_err("%s: Invalid pkt length %d\n",
1540 __func__, pkt->length);
1541 goto fail_data;
1542 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001543
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001544 head_skb = skb_peek(pkt->pkt_fragment_q);
1545 if (!head_skb) {
1546 pr_err("%s: head_skb is invalid\n", __func__);
1547 goto fail_data;
1548 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001549
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001550 hdr = (struct rr_header *)(head_skb->data);
1551 RR("- ver=%d type=%d src=%d:%08x crx=%d siz=%d dst=%d:%08x\n",
1552 hdr->version, hdr->type, hdr->src_node_id, hdr->src_port_id,
1553 hdr->confirm_rx, hdr->size, hdr->dst_node_id,
1554 hdr->dst_port_id);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001555
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001556 if (hdr->version != IPC_ROUTER_VERSION) {
1557 pr_err("version %d != %d\n",
1558 hdr->version, IPC_ROUTER_VERSION);
1559 goto fail_data;
1560 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001561
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001562 if ((hdr->dst_node_id != IPC_ROUTER_NID_LOCAL) &&
1563 ((hdr->type == IPC_ROUTER_CTRL_CMD_RESUME_TX) ||
1564 (hdr->type == IPC_ROUTER_CTRL_CMD_DATA))) {
1565 forward_msg(xprt_info, pkt);
1566 release_pkt(pkt);
1567 continue;
1568 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001569
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001570 if ((hdr->dst_port_id == IPC_ROUTER_ADDRESS) ||
1571 (hdr->type == IPC_ROUTER_CTRL_CMD_HELLO)) {
1572 process_control_msg(xprt_info, pkt);
1573 release_pkt(pkt);
1574 continue;
1575 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001576#if defined(CONFIG_MSM_SMD_LOGGING)
1577#if defined(DEBUG)
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001578 if (msm_ipc_router_debug_mask & SMEM_LOG) {
1579 smem_log_event((SMEM_LOG_PROC_ID_APPS |
1580 SMEM_LOG_RPC_ROUTER_EVENT_BASE |
1581 IPC_ROUTER_LOG_EVENT_RX),
1582 (hdr->src_node_id << 24) |
1583 (hdr->src_port_id & 0xffffff),
1584 (hdr->dst_node_id << 24) |
1585 (hdr->dst_port_id & 0xffffff),
1586 (hdr->type << 24) | (hdr->confirm_rx << 16) |
1587 (hdr->size & 0xffff));
1588 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001589#endif
1590#endif
1591
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001592 resume_tx = hdr->confirm_rx;
1593 resume_tx_node_id = hdr->dst_node_id;
1594 resume_tx_port_id = hdr->dst_port_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001595
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001596 rport_ptr = msm_ipc_router_lookup_remote_port(hdr->src_node_id,
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06001597 hdr->src_port_id);
1598
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001599 mutex_lock(&local_ports_lock);
1600 port_ptr = msm_ipc_router_lookup_local_port(hdr->dst_port_id);
1601 if (!port_ptr) {
1602 pr_err("%s: No local port id %08x\n", __func__,
1603 hdr->dst_port_id);
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06001604 mutex_unlock(&local_ports_lock);
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001605 release_pkt(pkt);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001606 goto process_done;
1607 }
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001608
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001609 if (!rport_ptr) {
1610 rport_ptr = msm_ipc_router_create_remote_port(
1611 hdr->src_node_id,
1612 hdr->src_port_id);
1613 if (!rport_ptr) {
1614 pr_err("%s: Rmt Prt %08x:%08x create failed\n",
1615 __func__, hdr->src_node_id,
1616 hdr->src_port_id);
1617 mutex_unlock(&local_ports_lock);
1618 goto process_done;
1619 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001620 }
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001621
1622 if (!port_ptr->notify) {
1623 mutex_lock(&port_ptr->port_rx_q_lock);
1624 wake_lock(&port_ptr->port_rx_wake_lock);
1625 list_add_tail(&pkt->list, &port_ptr->port_rx_q);
1626 wake_up(&port_ptr->port_rx_wait_q);
1627 mutex_unlock(&port_ptr->port_rx_q_lock);
1628 mutex_unlock(&local_ports_lock);
1629 } else {
1630 mutex_lock(&port_ptr->port_rx_q_lock);
1631 src_addr = kmalloc(sizeof(struct msm_ipc_port_addr),
1632 GFP_KERNEL);
1633 if (src_addr) {
1634 src_addr->node_id = hdr->src_node_id;
1635 src_addr->port_id = hdr->src_port_id;
1636 }
1637 skb_pull(head_skb, IPC_ROUTER_HDR_SIZE);
1638 mutex_unlock(&local_ports_lock);
1639 port_ptr->notify(MSM_IPC_ROUTER_READ_CB,
1640 pkt->pkt_fragment_q, src_addr, port_ptr->priv);
1641 mutex_unlock(&port_ptr->port_rx_q_lock);
1642 pkt->pkt_fragment_q = NULL;
1643 src_addr = NULL;
1644 release_pkt(pkt);
1645 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001646
1647process_done:
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001648 if (resume_tx) {
1649 union rr_control_msg msg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001650
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001651 msg.cmd = IPC_ROUTER_CTRL_CMD_RESUME_TX;
1652 msg.cli.node_id = resume_tx_node_id;
1653 msg.cli.port_id = resume_tx_port_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001654
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001655 RR("x RESUME_TX id=%d:%08x\n",
1656 msg.cli.node_id, msg.cli.port_id);
1657 msm_ipc_router_send_control_msg(xprt_info, &msg);
1658 }
1659
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001660 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001661 return;
1662
1663fail_data:
1664 release_pkt(pkt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001665 pr_err("ipc_router has died\n");
1666}
1667
1668int msm_ipc_router_register_server(struct msm_ipc_port *port_ptr,
1669 struct msm_ipc_addr *name)
1670{
1671 struct msm_ipc_server *server;
1672 unsigned long flags;
1673 union rr_control_msg ctl;
1674
1675 if (!port_ptr || !name)
1676 return -EINVAL;
1677
1678 if (name->addrtype != MSM_IPC_ADDR_NAME)
1679 return -EINVAL;
1680
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001681 mutex_lock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001682 server = msm_ipc_router_lookup_server(name->addr.port_name.service,
1683 name->addr.port_name.instance,
1684 IPC_ROUTER_NID_LOCAL,
1685 port_ptr->this_port.port_id);
1686 if (server) {
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001687 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001688 pr_err("%s: Server already present\n", __func__);
1689 return -EINVAL;
1690 }
1691
1692 server = msm_ipc_router_create_server(name->addr.port_name.service,
1693 name->addr.port_name.instance,
1694 IPC_ROUTER_NID_LOCAL,
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001695 port_ptr->this_port.port_id,
1696 NULL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001697 if (!server) {
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001698 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001699 pr_err("%s: Server Creation failed\n", __func__);
1700 return -EINVAL;
1701 }
1702
1703 ctl.cmd = IPC_ROUTER_CTRL_CMD_NEW_SERVER;
1704 ctl.srv.service = server->name.service;
1705 ctl.srv.instance = server->name.instance;
1706 ctl.srv.node_id = IPC_ROUTER_NID_LOCAL;
1707 ctl.srv.port_id = port_ptr->this_port.port_id;
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001708 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001709 broadcast_ctl_msg(&ctl);
1710 spin_lock_irqsave(&port_ptr->port_lock, flags);
1711 port_ptr->type = SERVER_PORT;
1712 port_ptr->port_name.service = server->name.service;
1713 port_ptr->port_name.instance = server->name.instance;
1714 spin_unlock_irqrestore(&port_ptr->port_lock, flags);
1715 return 0;
1716}
1717
1718int msm_ipc_router_unregister_server(struct msm_ipc_port *port_ptr)
1719{
1720 struct msm_ipc_server *server;
1721 unsigned long flags;
1722 union rr_control_msg ctl;
1723
1724 if (!port_ptr)
1725 return -EINVAL;
1726
1727 if (port_ptr->type != SERVER_PORT) {
1728 pr_err("%s: Trying to unregister a non-server port\n",
1729 __func__);
1730 return -EINVAL;
1731 }
1732
1733 if (port_ptr->this_port.node_id != IPC_ROUTER_NID_LOCAL) {
1734 pr_err("%s: Trying to unregister a remote server locally\n",
1735 __func__);
1736 return -EINVAL;
1737 }
1738
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001739 mutex_lock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001740 server = msm_ipc_router_lookup_server(port_ptr->port_name.service,
1741 port_ptr->port_name.instance,
1742 port_ptr->this_port.node_id,
1743 port_ptr->this_port.port_id);
1744 if (!server) {
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001745 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001746 pr_err("%s: Server lookup failed\n", __func__);
1747 return -ENODEV;
1748 }
1749
1750 ctl.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_SERVER;
1751 ctl.srv.service = server->name.service;
1752 ctl.srv.instance = server->name.instance;
1753 ctl.srv.node_id = IPC_ROUTER_NID_LOCAL;
1754 ctl.srv.port_id = port_ptr->this_port.port_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001755 msm_ipc_router_destroy_server(server, port_ptr->this_port.node_id,
1756 port_ptr->this_port.port_id);
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001757 mutex_unlock(&server_list_lock);
1758 broadcast_ctl_msg(&ctl);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001759 spin_lock_irqsave(&port_ptr->port_lock, flags);
1760 port_ptr->type = CLIENT_PORT;
1761 spin_unlock_irqrestore(&port_ptr->port_lock, flags);
1762 return 0;
1763}
1764
1765static int loopback_data(struct msm_ipc_port *src,
1766 uint32_t port_id,
1767 struct sk_buff_head *data)
1768{
1769 struct sk_buff *head_skb;
1770 struct rr_header *hdr;
1771 struct msm_ipc_port *port_ptr;
1772 struct rr_packet *pkt;
Karthikeyan Ramasubramanian0a801c12013-02-08 13:07:42 -07001773 int ret_len;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001774
1775 if (!data) {
1776 pr_err("%s: Invalid pkt pointer\n", __func__);
1777 return -EINVAL;
1778 }
1779
1780 pkt = create_pkt(data);
1781 if (!pkt) {
1782 pr_err("%s: New pkt create failed\n", __func__);
1783 return -ENOMEM;
1784 }
1785
1786 head_skb = skb_peek(pkt->pkt_fragment_q);
Karthikeyan Ramasubramanian9024dd82011-12-19 18:44:19 -07001787 if (!head_skb) {
1788 pr_err("%s: pkt_fragment_q is empty\n", __func__);
Brent Hronik0e83d3b2013-05-01 16:25:00 -06001789 release_pkt(pkt);
Karthikeyan Ramasubramanian9024dd82011-12-19 18:44:19 -07001790 return -EINVAL;
1791 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001792 hdr = (struct rr_header *)skb_push(head_skb, IPC_ROUTER_HDR_SIZE);
1793 if (!hdr) {
1794 pr_err("%s: Prepend Header failed\n", __func__);
1795 release_pkt(pkt);
1796 return -ENOMEM;
1797 }
1798 hdr->version = IPC_ROUTER_VERSION;
1799 hdr->type = IPC_ROUTER_CTRL_CMD_DATA;
1800 hdr->src_node_id = src->this_port.node_id;
1801 hdr->src_port_id = src->this_port.port_id;
1802 hdr->size = pkt->length;
1803 hdr->confirm_rx = 0;
1804 hdr->dst_node_id = IPC_ROUTER_NID_LOCAL;
1805 hdr->dst_port_id = port_id;
1806 pkt->length += IPC_ROUTER_HDR_SIZE;
1807
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06001808 mutex_lock(&local_ports_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001809 port_ptr = msm_ipc_router_lookup_local_port(port_id);
1810 if (!port_ptr) {
1811 pr_err("%s: Local port %d not present\n", __func__, port_id);
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06001812 mutex_unlock(&local_ports_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001813 release_pkt(pkt);
1814 return -ENODEV;
1815 }
1816
1817 mutex_lock(&port_ptr->port_rx_q_lock);
1818 wake_lock(&port_ptr->port_rx_wake_lock);
1819 list_add_tail(&pkt->list, &port_ptr->port_rx_q);
Karthikeyan Ramasubramanian0a801c12013-02-08 13:07:42 -07001820 ret_len = pkt->length;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001821 wake_up(&port_ptr->port_rx_wait_q);
1822 mutex_unlock(&port_ptr->port_rx_q_lock);
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06001823 mutex_unlock(&local_ports_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001824
Karthikeyan Ramasubramanian0a801c12013-02-08 13:07:42 -07001825 return ret_len;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001826}
1827
1828static int msm_ipc_router_write_pkt(struct msm_ipc_port *src,
1829 struct msm_ipc_router_remote_port *rport_ptr,
1830 struct rr_packet *pkt)
1831{
1832 struct sk_buff *head_skb;
1833 struct rr_header *hdr;
1834 struct msm_ipc_router_xprt_info *xprt_info;
1835 struct msm_ipc_routing_table_entry *rt_entry;
1836 int ret;
1837 DEFINE_WAIT(__wait);
1838
1839 if (!rport_ptr || !src || !pkt)
1840 return -EINVAL;
1841
1842 head_skb = skb_peek(pkt->pkt_fragment_q);
Karthikeyan Ramasubramanian9024dd82011-12-19 18:44:19 -07001843 if (!head_skb) {
1844 pr_err("%s: pkt_fragment_q is empty\n", __func__);
1845 return -EINVAL;
1846 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001847 hdr = (struct rr_header *)skb_push(head_skb, IPC_ROUTER_HDR_SIZE);
1848 if (!hdr) {
1849 pr_err("%s: Prepend Header failed\n", __func__);
1850 return -ENOMEM;
1851 }
1852 hdr->version = IPC_ROUTER_VERSION;
1853 hdr->type = IPC_ROUTER_CTRL_CMD_DATA;
1854 hdr->src_node_id = src->this_port.node_id;
1855 hdr->src_port_id = src->this_port.port_id;
1856 hdr->size = pkt->length;
1857 hdr->confirm_rx = 0;
1858 hdr->dst_node_id = rport_ptr->node_id;
1859 hdr->dst_port_id = rport_ptr->port_id;
1860 pkt->length += IPC_ROUTER_HDR_SIZE;
1861
1862 for (;;) {
1863 prepare_to_wait(&rport_ptr->quota_wait, &__wait,
1864 TASK_INTERRUPTIBLE);
1865 mutex_lock(&rport_ptr->quota_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001866 if (rport_ptr->restart_state != RESTART_NORMAL)
1867 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001868 if (rport_ptr->tx_quota_cnt <
1869 IPC_ROUTER_DEFAULT_RX_QUOTA)
1870 break;
1871 if (signal_pending(current))
1872 break;
1873 mutex_unlock(&rport_ptr->quota_lock);
1874 schedule();
1875 }
1876 finish_wait(&rport_ptr->quota_wait, &__wait);
1877
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001878 if (rport_ptr->restart_state != RESTART_NORMAL) {
1879 mutex_unlock(&rport_ptr->quota_lock);
1880 return -ENETRESET;
1881 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001882 if (signal_pending(current)) {
1883 mutex_unlock(&rport_ptr->quota_lock);
1884 return -ERESTARTSYS;
1885 }
1886 rport_ptr->tx_quota_cnt++;
1887 if (rport_ptr->tx_quota_cnt == IPC_ROUTER_DEFAULT_RX_QUOTA)
1888 hdr->confirm_rx = 1;
1889 mutex_unlock(&rport_ptr->quota_lock);
1890
1891 mutex_lock(&routing_table_lock);
1892 rt_entry = lookup_routing_table(hdr->dst_node_id);
1893 if (!rt_entry || !rt_entry->xprt_info) {
1894 mutex_unlock(&routing_table_lock);
1895 pr_err("%s: Remote node %d not up\n",
1896 __func__, hdr->dst_node_id);
1897 return -ENODEV;
1898 }
1899 mutex_lock(&rt_entry->lock);
1900 xprt_info = rt_entry->xprt_info;
1901 mutex_lock(&xprt_info->tx_lock);
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -07001902 ret = xprt_info->xprt->write(pkt, pkt->length, xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001903 mutex_unlock(&xprt_info->tx_lock);
1904 mutex_unlock(&rt_entry->lock);
1905 mutex_unlock(&routing_table_lock);
1906
1907 if (ret < 0) {
1908 pr_err("%s: Write on XPRT failed\n", __func__);
1909 return ret;
1910 }
1911
1912 RAW_HDR("[w rr_h] "
1913 "ver=%i,type=%s,src_nid=%08x,src_port_id=%08x,"
1914 "confirm_rx=%i,size=%3i,dst_pid=%08x,dst_cid=%08x\n",
1915 hdr->version, type_to_str(hdr->type),
1916 hdr->src_node_id, hdr->src_port_id,
1917 hdr->confirm_rx, hdr->size,
1918 hdr->dst_node_id, hdr->dst_port_id);
1919
1920#if defined(CONFIG_MSM_SMD_LOGGING)
1921#if defined(DEBUG)
1922 if (msm_ipc_router_debug_mask & SMEM_LOG) {
1923 smem_log_event((SMEM_LOG_PROC_ID_APPS |
1924 SMEM_LOG_RPC_ROUTER_EVENT_BASE |
1925 IPC_ROUTER_LOG_EVENT_TX),
1926 (hdr->src_node_id << 24) |
1927 (hdr->src_port_id & 0xffffff),
1928 (hdr->dst_node_id << 24) |
1929 (hdr->dst_port_id & 0xffffff),
1930 (hdr->type << 24) | (hdr->confirm_rx << 16) |
1931 (hdr->size & 0xffff));
1932 }
1933#endif
1934#endif
1935
1936 return pkt->length;
1937}
1938
1939int msm_ipc_router_send_to(struct msm_ipc_port *src,
1940 struct sk_buff_head *data,
1941 struct msm_ipc_addr *dest)
1942{
1943 uint32_t dst_node_id = 0, dst_port_id = 0;
1944 struct msm_ipc_server *server;
1945 struct msm_ipc_server_port *server_port;
1946 struct msm_ipc_router_remote_port *rport_ptr = NULL;
1947 struct rr_packet *pkt;
1948 int ret;
1949
1950 if (!src || !data || !dest) {
1951 pr_err("%s: Invalid Parameters\n", __func__);
1952 return -EINVAL;
1953 }
1954
1955 /* Resolve Address*/
1956 if (dest->addrtype == MSM_IPC_ADDR_ID) {
1957 dst_node_id = dest->addr.port_addr.node_id;
1958 dst_port_id = dest->addr.port_addr.port_id;
1959 } else if (dest->addrtype == MSM_IPC_ADDR_NAME) {
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001960 mutex_lock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001961 server = msm_ipc_router_lookup_server(
1962 dest->addr.port_name.service,
1963 dest->addr.port_name.instance,
1964 0, 0);
1965 if (!server) {
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001966 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001967 pr_err("%s: Destination not reachable\n", __func__);
1968 return -ENODEV;
1969 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001970 server_port = list_first_entry(&server->server_port_list,
1971 struct msm_ipc_server_port,
1972 list);
1973 dst_node_id = server_port->server_addr.node_id;
1974 dst_port_id = server_port->server_addr.port_id;
1975 mutex_unlock(&server_list_lock);
1976 }
1977 if (dst_node_id == IPC_ROUTER_NID_LOCAL) {
1978 ret = loopback_data(src, dst_port_id, data);
1979 return ret;
1980 }
1981
1982 /* Achieve Flow control */
1983 rport_ptr = msm_ipc_router_lookup_remote_port(dst_node_id,
1984 dst_port_id);
1985 if (!rport_ptr) {
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001986 pr_err("%s: Could not create remote port\n", __func__);
1987 return -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001988 }
1989
Karthikeyan Ramasubramanian1668cc62012-09-23 22:23:36 -06001990 if (src->check_send_permissions) {
1991 ret = src->check_send_permissions(rport_ptr->sec_rule);
1992 if (ret <= 0) {
1993 pr_err("%s: permission failure for %s\n",
1994 __func__, current->comm);
1995 return -EPERM;
1996 }
1997 }
1998
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001999 pkt = create_pkt(data);
2000 if (!pkt) {
2001 pr_err("%s: Pkt creation failed\n", __func__);
2002 return -ENOMEM;
2003 }
2004
2005 ret = msm_ipc_router_write_pkt(src, rport_ptr, pkt);
2006 release_pkt(pkt);
2007
2008 return ret;
2009}
2010
2011int msm_ipc_router_read(struct msm_ipc_port *port_ptr,
2012 struct sk_buff_head **data,
2013 size_t buf_len)
2014{
2015 struct rr_packet *pkt;
2016 int ret;
2017
2018 if (!port_ptr || !data)
2019 return -EINVAL;
2020
2021 mutex_lock(&port_ptr->port_rx_q_lock);
2022 if (list_empty(&port_ptr->port_rx_q)) {
2023 mutex_unlock(&port_ptr->port_rx_q_lock);
2024 return -EAGAIN;
2025 }
2026
2027 pkt = list_first_entry(&port_ptr->port_rx_q, struct rr_packet, list);
2028 if ((buf_len) && ((pkt->length - IPC_ROUTER_HDR_SIZE) > buf_len)) {
2029 mutex_unlock(&port_ptr->port_rx_q_lock);
2030 return -ETOOSMALL;
2031 }
2032 list_del(&pkt->list);
2033 if (list_empty(&port_ptr->port_rx_q))
2034 wake_unlock(&port_ptr->port_rx_wake_lock);
2035 *data = pkt->pkt_fragment_q;
2036 ret = pkt->length;
2037 kfree(pkt);
2038 mutex_unlock(&port_ptr->port_rx_q_lock);
2039
2040 return ret;
2041}
2042
2043int msm_ipc_router_recv_from(struct msm_ipc_port *port_ptr,
2044 struct sk_buff_head **data,
2045 struct msm_ipc_addr *src,
2046 unsigned long timeout)
2047{
2048 int ret, data_len, align_size;
2049 struct sk_buff *temp_skb;
2050 struct rr_header *hdr = NULL;
2051
2052 if (!port_ptr || !data) {
2053 pr_err("%s: Invalid pointers being passed\n", __func__);
2054 return -EINVAL;
2055 }
2056
2057 *data = NULL;
2058 mutex_lock(&port_ptr->port_rx_q_lock);
2059 while (list_empty(&port_ptr->port_rx_q)) {
2060 mutex_unlock(&port_ptr->port_rx_q_lock);
2061 if (timeout < 0) {
2062 ret = wait_event_interruptible(
2063 port_ptr->port_rx_wait_q,
2064 !list_empty(&port_ptr->port_rx_q));
2065 if (ret)
2066 return ret;
2067 } else if (timeout > 0) {
2068 timeout = wait_event_interruptible_timeout(
2069 port_ptr->port_rx_wait_q,
2070 !list_empty(&port_ptr->port_rx_q),
2071 timeout);
2072 if (timeout < 0)
2073 return -EFAULT;
2074 }
2075 if (timeout == 0)
2076 return -ETIMEDOUT;
2077 mutex_lock(&port_ptr->port_rx_q_lock);
2078 }
2079 mutex_unlock(&port_ptr->port_rx_q_lock);
2080
2081 ret = msm_ipc_router_read(port_ptr, data, 0);
2082 if (ret <= 0 || !(*data))
2083 return ret;
2084
2085 temp_skb = skb_peek(*data);
2086 hdr = (struct rr_header *)(temp_skb->data);
2087 if (src) {
2088 src->addrtype = MSM_IPC_ADDR_ID;
2089 src->addr.port_addr.node_id = hdr->src_node_id;
2090 src->addr.port_addr.port_id = hdr->src_port_id;
2091 }
2092
2093 data_len = hdr->size;
2094 skb_pull(temp_skb, IPC_ROUTER_HDR_SIZE);
2095 align_size = ALIGN_SIZE(data_len);
2096 if (align_size) {
2097 temp_skb = skb_peek_tail(*data);
2098 skb_trim(temp_skb, (temp_skb->len - align_size));
2099 }
2100 return data_len;
2101}
2102
2103struct msm_ipc_port *msm_ipc_router_create_port(
2104 void (*notify)(unsigned event, void *data, void *addr, void *priv),
2105 void *priv)
2106{
2107 struct msm_ipc_port *port_ptr;
2108
2109 port_ptr = msm_ipc_router_create_raw_port(NULL, notify, priv);
2110 if (!port_ptr)
2111 pr_err("%s: port_ptr alloc failed\n", __func__);
2112
2113 return port_ptr;
2114}
2115
2116int msm_ipc_router_close_port(struct msm_ipc_port *port_ptr)
2117{
2118 union rr_control_msg msg;
2119 struct rr_packet *pkt, *temp_pkt;
2120 struct msm_ipc_server *server;
2121
2122 if (!port_ptr)
2123 return -EINVAL;
2124
2125 if (port_ptr->type == SERVER_PORT || port_ptr->type == CLIENT_PORT) {
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06002126 mutex_lock(&local_ports_lock);
2127 list_del(&port_ptr->list);
2128 mutex_unlock(&local_ports_lock);
2129
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002130 if (port_ptr->type == SERVER_PORT) {
2131 msg.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_SERVER;
2132 msg.srv.service = port_ptr->port_name.service;
2133 msg.srv.instance = port_ptr->port_name.instance;
2134 msg.srv.node_id = port_ptr->this_port.node_id;
2135 msg.srv.port_id = port_ptr->this_port.port_id;
2136 RR("x REMOVE_SERVER Name=%d:%08x Id=%d:%08x\n",
2137 msg.srv.service, msg.srv.instance,
2138 msg.srv.node_id, msg.srv.port_id);
Karthikeyan Ramasubramanian25e91872013-01-10 17:09:13 -07002139 broadcast_ctl_msg(&msg);
2140 broadcast_ctl_msg_locally(&msg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002141 }
Karthikeyan Ramasubramanian25e91872013-01-10 17:09:13 -07002142
2143 /*
2144 * Server port could have been a client port earlier.
2145 * Send REMOVE_CLIENT message in either case.
2146 */
2147 msg.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT;
2148 msg.cli.node_id = port_ptr->this_port.node_id;
2149 msg.cli.port_id = port_ptr->this_port.port_id;
2150 RR("x REMOVE_CLIENT id=%d:%08x\n",
2151 msg.cli.node_id, msg.cli.port_id);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002152 broadcast_ctl_msg(&msg);
2153 broadcast_ctl_msg_locally(&msg);
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06002154 } else if (port_ptr->type == CONTROL_PORT) {
2155 mutex_lock(&control_ports_lock);
2156 list_del(&port_ptr->list);
2157 mutex_unlock(&control_ports_lock);
Karthikeyan Ramasubramaniand6dbfae2013-01-16 09:00:28 -07002158 } else if (port_ptr->type == IRSC_PORT) {
2159 mutex_lock(&local_ports_lock);
2160 list_del(&port_ptr->list);
2161 mutex_unlock(&local_ports_lock);
2162 signal_irsc_completion();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002163 }
2164
2165 mutex_lock(&port_ptr->port_rx_q_lock);
2166 list_for_each_entry_safe(pkt, temp_pkt, &port_ptr->port_rx_q, list) {
2167 list_del(&pkt->list);
2168 release_pkt(pkt);
2169 }
2170 mutex_unlock(&port_ptr->port_rx_q_lock);
2171
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002172 if (port_ptr->type == SERVER_PORT) {
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002173 mutex_lock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002174 server = msm_ipc_router_lookup_server(
2175 port_ptr->port_name.service,
2176 port_ptr->port_name.instance,
2177 port_ptr->this_port.node_id,
2178 port_ptr->this_port.port_id);
2179 if (server)
2180 msm_ipc_router_destroy_server(server,
2181 port_ptr->this_port.node_id,
2182 port_ptr->this_port.port_id);
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002183 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002184 }
2185
Karthikeyan Ramasubramaniandd8c3b52011-11-30 16:26:12 -07002186 wake_lock_destroy(&port_ptr->port_rx_wake_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002187 kfree(port_ptr);
2188 return 0;
2189}
2190
2191int msm_ipc_router_get_curr_pkt_size(struct msm_ipc_port *port_ptr)
2192{
2193 struct rr_packet *pkt;
2194 int rc = 0;
2195
2196 if (!port_ptr)
2197 return -EINVAL;
2198
2199 mutex_lock(&port_ptr->port_rx_q_lock);
2200 if (!list_empty(&port_ptr->port_rx_q)) {
2201 pkt = list_first_entry(&port_ptr->port_rx_q,
2202 struct rr_packet, list);
2203 rc = pkt->length;
2204 }
2205 mutex_unlock(&port_ptr->port_rx_q_lock);
2206
2207 return rc;
2208}
2209
2210int msm_ipc_router_bind_control_port(struct msm_ipc_port *port_ptr)
2211{
2212 if (!port_ptr)
2213 return -EINVAL;
2214
2215 mutex_lock(&local_ports_lock);
2216 list_del(&port_ptr->list);
2217 mutex_unlock(&local_ports_lock);
2218 port_ptr->type = CONTROL_PORT;
2219 mutex_lock(&control_ports_lock);
2220 list_add_tail(&port_ptr->list, &control_ports);
2221 mutex_unlock(&control_ports_lock);
2222
2223 return 0;
2224}
2225
2226int msm_ipc_router_lookup_server_name(struct msm_ipc_port_name *srv_name,
Karthikeyan Ramasubramaniandfde01b2012-06-12 14:25:13 -06002227 struct msm_ipc_server_info *srv_info,
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002228 int num_entries_in_array,
2229 uint32_t lookup_mask)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002230{
2231 struct msm_ipc_server *server;
2232 struct msm_ipc_server_port *server_port;
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002233 int key, i = 0; /*num_entries_found*/
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002234
2235 if (!srv_name) {
2236 pr_err("%s: Invalid srv_name\n", __func__);
2237 return -EINVAL;
2238 }
2239
Karthikeyan Ramasubramaniandfde01b2012-06-12 14:25:13 -06002240 if (num_entries_in_array && !srv_info) {
2241 pr_err("%s: srv_info NULL\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002242 return -EINVAL;
2243 }
2244
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002245 mutex_lock(&server_list_lock);
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002246 if (!lookup_mask)
2247 lookup_mask = 0xFFFFFFFF;
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002248 key = (srv_name->service & (SRV_HASH_SIZE - 1));
2249 list_for_each_entry(server, &server_list[key], list) {
2250 if ((server->name.service != srv_name->service) ||
2251 ((server->name.instance & lookup_mask) !=
2252 srv_name->instance))
2253 continue;
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002254
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002255 list_for_each_entry(server_port,
2256 &server->server_port_list, list) {
2257 if (i < num_entries_in_array) {
2258 srv_info[i].node_id =
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002259 server_port->server_addr.node_id;
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002260 srv_info[i].port_id =
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002261 server_port->server_addr.port_id;
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002262 srv_info[i].service = server->name.service;
2263 srv_info[i].instance = server->name.instance;
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002264 }
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002265 i++;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002266 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002267 }
2268 mutex_unlock(&server_list_lock);
2269
2270 return i;
2271}
2272
2273int msm_ipc_router_close(void)
2274{
2275 struct msm_ipc_router_xprt_info *xprt_info, *tmp_xprt_info;
2276
2277 mutex_lock(&xprt_info_list_lock);
2278 list_for_each_entry_safe(xprt_info, tmp_xprt_info,
2279 &xprt_info_list, list) {
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -07002280 xprt_info->xprt->close(xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002281 list_del(&xprt_info->list);
2282 kfree(xprt_info);
2283 }
2284 mutex_unlock(&xprt_info_list_lock);
2285 return 0;
2286}
2287
2288#if defined(CONFIG_DEBUG_FS)
2289static int dump_routing_table(char *buf, int max)
2290{
2291 int i = 0, j;
2292 struct msm_ipc_routing_table_entry *rt_entry;
2293
2294 for (j = 0; j < RT_HASH_SIZE; j++) {
2295 mutex_lock(&routing_table_lock);
2296 list_for_each_entry(rt_entry, &routing_table[j], list) {
2297 mutex_lock(&rt_entry->lock);
2298 i += scnprintf(buf + i, max - i,
2299 "Node Id: 0x%08x\n", rt_entry->node_id);
Karthikeyan Ramasubramanianc1a4e3a2012-09-10 16:10:24 -06002300 if (rt_entry->node_id == IPC_ROUTER_NID_LOCAL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002301 i += scnprintf(buf + i, max - i,
2302 "XPRT Name: Loopback\n");
2303 i += scnprintf(buf + i, max - i,
2304 "Next Hop: %d\n", rt_entry->node_id);
2305 } else {
2306 i += scnprintf(buf + i, max - i,
2307 "XPRT Name: %s\n",
2308 rt_entry->xprt_info->xprt->name);
2309 i += scnprintf(buf + i, max - i,
2310 "Next Hop: 0x%08x\n",
2311 rt_entry->xprt_info->remote_node_id);
2312 }
2313 i += scnprintf(buf + i, max - i, "\n");
2314 mutex_unlock(&rt_entry->lock);
2315 }
2316 mutex_unlock(&routing_table_lock);
2317 }
2318
2319 return i;
2320}
2321
2322static int dump_xprt_info(char *buf, int max)
2323{
2324 int i = 0;
2325 struct msm_ipc_router_xprt_info *xprt_info;
2326
2327 mutex_lock(&xprt_info_list_lock);
2328 list_for_each_entry(xprt_info, &xprt_info_list, list) {
2329 i += scnprintf(buf + i, max - i, "XPRT Name: %s\n",
2330 xprt_info->xprt->name);
2331 i += scnprintf(buf + i, max - i, "Link Id: %d\n",
2332 xprt_info->xprt->link_id);
2333 i += scnprintf(buf + i, max - i, "Initialized: %s\n",
2334 (xprt_info->initialized ? "Y" : "N"));
2335 i += scnprintf(buf + i, max - i, "Remote Node Id: 0x%08x\n",
2336 xprt_info->remote_node_id);
2337 i += scnprintf(buf + i, max - i, "\n");
2338 }
2339 mutex_unlock(&xprt_info_list_lock);
2340
2341 return i;
2342}
2343
2344static int dump_servers(char *buf, int max)
2345{
2346 int i = 0, j;
2347 struct msm_ipc_server *server;
2348 struct msm_ipc_server_port *server_port;
2349
2350 mutex_lock(&server_list_lock);
2351 for (j = 0; j < SRV_HASH_SIZE; j++) {
2352 list_for_each_entry(server, &server_list[j], list) {
2353 list_for_each_entry(server_port,
2354 &server->server_port_list,
2355 list) {
2356 i += scnprintf(buf + i, max - i, "Service: "
2357 "0x%08x\n", server->name.service);
2358 i += scnprintf(buf + i, max - i, "Instance: "
2359 "0x%08x\n", server->name.instance);
2360 i += scnprintf(buf + i, max - i,
2361 "Node_id: 0x%08x\n",
2362 server_port->server_addr.node_id);
2363 i += scnprintf(buf + i, max - i,
2364 "Port_id: 0x%08x\n",
2365 server_port->server_addr.port_id);
2366 i += scnprintf(buf + i, max - i, "\n");
2367 }
2368 }
2369 }
2370 mutex_unlock(&server_list_lock);
2371
2372 return i;
2373}
2374
2375static int dump_remote_ports(char *buf, int max)
2376{
2377 int i = 0, j, k;
2378 struct msm_ipc_router_remote_port *rport_ptr;
2379 struct msm_ipc_routing_table_entry *rt_entry;
2380
2381 for (j = 0; j < RT_HASH_SIZE; j++) {
2382 mutex_lock(&routing_table_lock);
2383 list_for_each_entry(rt_entry, &routing_table[j], list) {
2384 mutex_lock(&rt_entry->lock);
2385 for (k = 0; k < RP_HASH_SIZE; k++) {
2386 list_for_each_entry(rport_ptr,
2387 &rt_entry->remote_port_list[k],
2388 list) {
2389 i += scnprintf(buf + i, max - i,
2390 "Node_id: 0x%08x\n",
2391 rport_ptr->node_id);
2392 i += scnprintf(buf + i, max - i,
2393 "Port_id: 0x%08x\n",
2394 rport_ptr->port_id);
2395 i += scnprintf(buf + i, max - i,
2396 "Quota_cnt: %d\n",
2397 rport_ptr->tx_quota_cnt);
2398 i += scnprintf(buf + i, max - i, "\n");
2399 }
2400 }
2401 mutex_unlock(&rt_entry->lock);
2402 }
2403 mutex_unlock(&routing_table_lock);
2404 }
2405
2406 return i;
2407}
2408
2409static int dump_control_ports(char *buf, int max)
2410{
2411 int i = 0;
2412 struct msm_ipc_port *port_ptr;
2413
2414 mutex_lock(&control_ports_lock);
2415 list_for_each_entry(port_ptr, &control_ports, list) {
2416 i += scnprintf(buf + i, max - i, "Node_id: 0x%08x\n",
2417 port_ptr->this_port.node_id);
2418 i += scnprintf(buf + i, max - i, "Port_id: 0x%08x\n",
2419 port_ptr->this_port.port_id);
2420 i += scnprintf(buf + i, max - i, "\n");
2421 }
2422 mutex_unlock(&control_ports_lock);
2423
2424 return i;
2425}
2426
2427static int dump_local_ports(char *buf, int max)
2428{
2429 int i = 0, j;
2430 unsigned long flags;
2431 struct msm_ipc_port *port_ptr;
2432
2433 mutex_lock(&local_ports_lock);
2434 for (j = 0; j < LP_HASH_SIZE; j++) {
2435 list_for_each_entry(port_ptr, &local_ports[j], list) {
2436 spin_lock_irqsave(&port_ptr->port_lock, flags);
2437 i += scnprintf(buf + i, max - i, "Node_id: 0x%08x\n",
2438 port_ptr->this_port.node_id);
2439 i += scnprintf(buf + i, max - i, "Port_id: 0x%08x\n",
2440 port_ptr->this_port.port_id);
2441 i += scnprintf(buf + i, max - i, "# pkts tx'd %d\n",
2442 port_ptr->num_tx);
2443 i += scnprintf(buf + i, max - i, "# pkts rx'd %d\n",
2444 port_ptr->num_rx);
2445 i += scnprintf(buf + i, max - i, "# bytes tx'd %ld\n",
2446 port_ptr->num_tx_bytes);
2447 i += scnprintf(buf + i, max - i, "# bytes rx'd %ld\n",
2448 port_ptr->num_rx_bytes);
2449 spin_unlock_irqrestore(&port_ptr->port_lock, flags);
2450 i += scnprintf(buf + i, max - i, "\n");
2451 }
2452 }
2453 mutex_unlock(&local_ports_lock);
2454
2455 return i;
2456}
2457
2458#define DEBUG_BUFMAX 4096
2459static char debug_buffer[DEBUG_BUFMAX];
2460
2461static ssize_t debug_read(struct file *file, char __user *buf,
2462 size_t count, loff_t *ppos)
2463{
2464 int (*fill)(char *buf, int max) = file->private_data;
2465 int bsize = fill(debug_buffer, DEBUG_BUFMAX);
2466 return simple_read_from_buffer(buf, count, ppos, debug_buffer, bsize);
2467}
2468
2469static int debug_open(struct inode *inode, struct file *file)
2470{
2471 file->private_data = inode->i_private;
2472 return 0;
2473}
2474
2475static const struct file_operations debug_ops = {
2476 .read = debug_read,
2477 .open = debug_open,
2478};
2479
2480static void debug_create(const char *name, mode_t mode,
2481 struct dentry *dent,
2482 int (*fill)(char *buf, int max))
2483{
2484 debugfs_create_file(name, mode, dent, fill, &debug_ops);
2485}
2486
2487static void debugfs_init(void)
2488{
2489 struct dentry *dent;
2490
2491 dent = debugfs_create_dir("msm_ipc_router", 0);
2492 if (IS_ERR(dent))
2493 return;
2494
2495 debug_create("dump_local_ports", 0444, dent,
2496 dump_local_ports);
2497 debug_create("dump_remote_ports", 0444, dent,
2498 dump_remote_ports);
2499 debug_create("dump_control_ports", 0444, dent,
2500 dump_control_ports);
2501 debug_create("dump_servers", 0444, dent,
2502 dump_servers);
2503 debug_create("dump_xprt_info", 0444, dent,
2504 dump_xprt_info);
2505 debug_create("dump_routing_table", 0444, dent,
2506 dump_routing_table);
2507}
2508
2509#else
2510static void debugfs_init(void) {}
2511#endif
2512
2513static int msm_ipc_router_add_xprt(struct msm_ipc_router_xprt *xprt)
2514{
2515 struct msm_ipc_router_xprt_info *xprt_info;
2516 struct msm_ipc_routing_table_entry *rt_entry;
2517
2518 xprt_info = kmalloc(sizeof(struct msm_ipc_router_xprt_info),
2519 GFP_KERNEL);
2520 if (!xprt_info)
2521 return -ENOMEM;
2522
2523 xprt_info->xprt = xprt;
2524 xprt_info->initialized = 0;
2525 xprt_info->remote_node_id = -1;
2526 INIT_LIST_HEAD(&xprt_info->pkt_list);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002527 mutex_init(&xprt_info->rx_lock);
2528 mutex_init(&xprt_info->tx_lock);
2529 wake_lock_init(&xprt_info->wakelock,
2530 WAKE_LOCK_SUSPEND, xprt->name);
2531 xprt_info->need_len = 0;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002532 xprt_info->abort_data_read = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002533 INIT_WORK(&xprt_info->read_data, do_read_data);
2534 INIT_LIST_HEAD(&xprt_info->list);
2535
2536 xprt_info->workqueue = create_singlethread_workqueue(xprt->name);
2537 if (!xprt_info->workqueue) {
2538 kfree(xprt_info);
2539 return -ENOMEM;
2540 }
2541
2542 if (!strcmp(xprt->name, "msm_ipc_router_loopback_xprt")) {
2543 xprt_info->remote_node_id = IPC_ROUTER_NID_LOCAL;
2544 xprt_info->initialized = 1;
2545 }
2546
2547 mutex_lock(&xprt_info_list_lock);
2548 list_add_tail(&xprt_info->list, &xprt_info_list);
2549 mutex_unlock(&xprt_info_list_lock);
2550
2551 mutex_lock(&routing_table_lock);
2552 if (!routing_table_inited) {
2553 init_routing_table();
2554 rt_entry = alloc_routing_table_entry(IPC_ROUTER_NID_LOCAL);
2555 add_routing_table_entry(rt_entry);
2556 routing_table_inited = 1;
2557 }
2558 mutex_unlock(&routing_table_lock);
2559
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002560 xprt->priv = xprt_info;
2561
2562 return 0;
2563}
2564
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002565static void msm_ipc_router_remove_xprt(struct msm_ipc_router_xprt *xprt)
2566{
2567 struct msm_ipc_router_xprt_info *xprt_info;
2568
2569 if (xprt && xprt->priv) {
2570 xprt_info = xprt->priv;
2571
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06002572 mutex_lock(&xprt_info->rx_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002573 xprt_info->abort_data_read = 1;
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06002574 mutex_unlock(&xprt_info->rx_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002575
2576 mutex_lock(&xprt_info_list_lock);
2577 list_del(&xprt_info->list);
2578 mutex_unlock(&xprt_info_list_lock);
2579
2580 flush_workqueue(xprt_info->workqueue);
2581 destroy_workqueue(xprt_info->workqueue);
2582 wake_lock_destroy(&xprt_info->wakelock);
2583
2584 xprt->priv = 0;
2585 kfree(xprt_info);
2586 }
2587}
2588
2589
2590struct msm_ipc_router_xprt_work {
2591 struct msm_ipc_router_xprt *xprt;
2592 struct work_struct work;
2593};
2594
2595static void xprt_open_worker(struct work_struct *work)
2596{
2597 struct msm_ipc_router_xprt_work *xprt_work =
2598 container_of(work, struct msm_ipc_router_xprt_work, work);
2599
2600 msm_ipc_router_add_xprt(xprt_work->xprt);
2601 kfree(xprt_work);
2602}
2603
2604static void xprt_close_worker(struct work_struct *work)
2605{
2606 struct msm_ipc_router_xprt_work *xprt_work =
2607 container_of(work, struct msm_ipc_router_xprt_work, work);
2608
2609 modem_reset_cleanup(xprt_work->xprt->priv);
2610 msm_ipc_router_remove_xprt(xprt_work->xprt);
Zaheerulla Meer35893a62013-06-19 16:54:44 +05302611 xprt_work->xprt->sft_close_done(xprt_work->xprt);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002612 kfree(xprt_work);
2613}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002614
2615void msm_ipc_router_xprt_notify(struct msm_ipc_router_xprt *xprt,
2616 unsigned event,
2617 void *data)
2618{
2619 struct msm_ipc_router_xprt_info *xprt_info = xprt->priv;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002620 struct msm_ipc_router_xprt_work *xprt_work;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002621 struct rr_packet *pkt;
Karthikeyan Ramasubramanian4af9f7c2011-09-30 15:55:18 -06002622 unsigned long ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002623
Karthikeyan Ramasubramanian4af9f7c2011-09-30 15:55:18 -06002624 if (!msm_ipc_router_workqueue) {
2625 ret = wait_for_completion_timeout(&msm_ipc_local_router_up,
2626 IPC_ROUTER_INIT_TIMEOUT);
2627 if (!ret || !msm_ipc_router_workqueue) {
2628 pr_err("%s: IPC Router not initialized\n", __func__);
2629 return;
2630 }
2631 }
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002632
2633 switch (event) {
2634 case IPC_ROUTER_XPRT_EVENT_OPEN:
2635 D("open event for '%s'\n", xprt->name);
2636 xprt_work = kmalloc(sizeof(struct msm_ipc_router_xprt_work),
2637 GFP_ATOMIC);
2638 xprt_work->xprt = xprt;
2639 INIT_WORK(&xprt_work->work, xprt_open_worker);
2640 queue_work(msm_ipc_router_workqueue, &xprt_work->work);
2641 break;
2642
2643 case IPC_ROUTER_XPRT_EVENT_CLOSE:
2644 D("close event for '%s'\n", xprt->name);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002645 xprt_work = kmalloc(sizeof(struct msm_ipc_router_xprt_work),
2646 GFP_ATOMIC);
2647 xprt_work->xprt = xprt;
2648 INIT_WORK(&xprt_work->work, xprt_close_worker);
2649 queue_work(msm_ipc_router_workqueue, &xprt_work->work);
2650 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002651 }
2652
2653 if (!data)
2654 return;
2655
2656 while (!xprt_info) {
2657 msleep(100);
2658 xprt_info = xprt->priv;
2659 }
2660
2661 pkt = clone_pkt((struct rr_packet *)data);
2662 if (!pkt)
2663 return;
2664
2665 mutex_lock(&xprt_info->rx_lock);
2666 list_add_tail(&pkt->list, &xprt_info->pkt_list);
2667 wake_lock(&xprt_info->wakelock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002668 mutex_unlock(&xprt_info->rx_lock);
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06002669 queue_work(xprt_info->workqueue, &xprt_info->read_data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002670}
2671
2672static int __init msm_ipc_router_init(void)
2673{
2674 int i, ret;
2675 struct msm_ipc_routing_table_entry *rt_entry;
2676
2677 msm_ipc_router_debug_mask |= SMEM_LOG;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002678 msm_ipc_router_workqueue =
2679 create_singlethread_workqueue("msm_ipc_router");
2680 if (!msm_ipc_router_workqueue)
2681 return -ENOMEM;
2682
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002683 debugfs_init();
2684
2685 for (i = 0; i < SRV_HASH_SIZE; i++)
2686 INIT_LIST_HEAD(&server_list[i]);
2687
2688 for (i = 0; i < LP_HASH_SIZE; i++)
2689 INIT_LIST_HEAD(&local_ports[i]);
2690
2691 mutex_lock(&routing_table_lock);
2692 if (!routing_table_inited) {
2693 init_routing_table();
2694 rt_entry = alloc_routing_table_entry(IPC_ROUTER_NID_LOCAL);
2695 add_routing_table_entry(rt_entry);
2696 routing_table_inited = 1;
2697 }
2698 mutex_unlock(&routing_table_lock);
2699
2700 init_waitqueue_head(&newserver_wait);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002701 ret = msm_ipc_router_init_sockets();
2702 if (ret < 0)
2703 pr_err("%s: Init sockets failed\n", __func__);
2704
Karthikeyan Ramasubramanian1668cc62012-09-23 22:23:36 -06002705 ret = msm_ipc_router_security_init();
2706 if (ret < 0)
2707 pr_err("%s: Security Init failed\n", __func__);
2708
Karthikeyan Ramasubramanian4af9f7c2011-09-30 15:55:18 -06002709 complete_all(&msm_ipc_local_router_up);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002710 return ret;
2711}
2712
2713module_init(msm_ipc_router_init);
2714MODULE_DESCRIPTION("MSM IPC Router");
2715MODULE_LICENSE("GPL v2");