blob: d6f844e634ba7da9d03fc53467ee569ce29f8011 [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"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070039
40enum {
41 SMEM_LOG = 1U << 0,
42 RTR_DBG = 1U << 1,
43 R2R_MSG = 1U << 2,
44 R2R_RAW = 1U << 3,
45 NTFY_MSG = 1U << 4,
46 R2R_RAW_HDR = 1U << 5,
47};
48
49static int msm_ipc_router_debug_mask;
50module_param_named(debug_mask, msm_ipc_router_debug_mask,
51 int, S_IRUGO | S_IWUSR | S_IWGRP);
52
53#define DIAG(x...) pr_info("[RR] ERROR " x)
54
55#if defined(DEBUG)
56#define D(x...) do { \
57if (msm_ipc_router_debug_mask & RTR_DBG) \
58 pr_info(x); \
59} while (0)
60
61#define RR(x...) do { \
62if (msm_ipc_router_debug_mask & R2R_MSG) \
63 pr_info("[RR] "x); \
64} while (0)
65
66#define RAW(x...) do { \
67if (msm_ipc_router_debug_mask & R2R_RAW) \
68 pr_info("[RAW] "x); \
69} while (0)
70
71#define NTFY(x...) do { \
72if (msm_ipc_router_debug_mask & NTFY_MSG) \
73 pr_info("[NOTIFY] "x); \
74} while (0)
75
76#define RAW_HDR(x...) do { \
77if (msm_ipc_router_debug_mask & R2R_RAW_HDR) \
78 pr_info("[HDR] "x); \
79} while (0)
80#else
81#define D(x...) do { } while (0)
82#define RR(x...) do { } while (0)
83#define RAW(x...) do { } while (0)
84#define RAW_HDR(x...) do { } while (0)
85#define NTFY(x...) do { } while (0)
86#endif
87
88#define IPC_ROUTER_LOG_EVENT_ERROR 0x10
89#define IPC_ROUTER_LOG_EVENT_TX 0x11
90#define IPC_ROUTER_LOG_EVENT_RX 0x12
91
92static LIST_HEAD(control_ports);
93static DEFINE_MUTEX(control_ports_lock);
94
95#define LP_HASH_SIZE 32
96static struct list_head local_ports[LP_HASH_SIZE];
97static DEFINE_MUTEX(local_ports_lock);
98
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -060099/*
100 * Server info is organized as a hash table. The server's service ID is
101 * used to index into the hash table. The instance ID of most of the servers
102 * are 1 or 2. The service IDs are well distributed compared to the instance
103 * IDs and hence choosing service ID to index into this hash table optimizes
104 * the hash table operations like add, lookup, destroy.
105 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700106#define SRV_HASH_SIZE 32
107static struct list_head server_list[SRV_HASH_SIZE];
108static DEFINE_MUTEX(server_list_lock);
109static wait_queue_head_t newserver_wait;
110
111struct msm_ipc_server {
112 struct list_head list;
113 struct msm_ipc_port_name name;
114 struct list_head server_port_list;
115};
116
117struct msm_ipc_server_port {
118 struct list_head list;
119 struct msm_ipc_port_addr server_addr;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600120 struct msm_ipc_router_xprt_info *xprt_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700121};
122
123#define RP_HASH_SIZE 32
124struct msm_ipc_router_remote_port {
125 struct list_head list;
126 uint32_t node_id;
127 uint32_t port_id;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600128 uint32_t restart_state;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700129 wait_queue_head_t quota_wait;
130 uint32_t tx_quota_cnt;
131 struct mutex quota_lock;
132};
133
134struct msm_ipc_router_xprt_info {
135 struct list_head list;
136 struct msm_ipc_router_xprt *xprt;
137 uint32_t remote_node_id;
138 uint32_t initialized;
139 struct list_head pkt_list;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700140 struct wake_lock wakelock;
141 struct mutex rx_lock;
142 struct mutex tx_lock;
143 uint32_t need_len;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600144 uint32_t abort_data_read;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700145 struct work_struct read_data;
146 struct workqueue_struct *workqueue;
147};
148
149#define RT_HASH_SIZE 4
150struct msm_ipc_routing_table_entry {
151 struct list_head list;
152 uint32_t node_id;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600153 uint32_t neighbor_node_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700154 struct list_head remote_port_list[RP_HASH_SIZE];
155 struct msm_ipc_router_xprt_info *xprt_info;
156 struct mutex lock;
157 unsigned long num_tx_bytes;
158 unsigned long num_rx_bytes;
159};
160
161static struct list_head routing_table[RT_HASH_SIZE];
162static DEFINE_MUTEX(routing_table_lock);
163static int routing_table_inited;
164
165static LIST_HEAD(msm_ipc_board_dev_list);
166static DEFINE_MUTEX(msm_ipc_board_dev_list_lock);
167
168static void do_read_data(struct work_struct *work);
169
170#define RR_STATE_IDLE 0
171#define RR_STATE_HEADER 1
172#define RR_STATE_BODY 2
173#define RR_STATE_ERROR 3
174
175#define RESTART_NORMAL 0
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600176#define RESTART_PEND 1
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700177
178/* State for remote ep following restart */
179#define RESTART_QUOTA_ABORT 1
180
181static LIST_HEAD(xprt_info_list);
182static DEFINE_MUTEX(xprt_info_list_lock);
183
Karthikeyan Ramasubramanian4af9f7c2011-09-30 15:55:18 -0600184static DECLARE_COMPLETION(msm_ipc_local_router_up);
185#define IPC_ROUTER_INIT_TIMEOUT (10 * HZ)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700186
187static uint32_t next_port_id;
188static DEFINE_MUTEX(next_port_id_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600189static atomic_t pending_close_count = ATOMIC_INIT(0);
190static wait_queue_head_t subsystem_restart_wait;
191static struct workqueue_struct *msm_ipc_router_workqueue;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700192
193enum {
194 CLIENT_PORT,
195 SERVER_PORT,
196 CONTROL_PORT,
197};
198
199enum {
200 DOWN,
201 UP,
202};
203
204static void init_routing_table(void)
205{
206 int i;
207 for (i = 0; i < RT_HASH_SIZE; i++)
208 INIT_LIST_HEAD(&routing_table[i]);
209}
210
211static struct msm_ipc_routing_table_entry *alloc_routing_table_entry(
212 uint32_t node_id)
213{
214 int i;
215 struct msm_ipc_routing_table_entry *rt_entry;
216
217 rt_entry = kmalloc(sizeof(struct msm_ipc_routing_table_entry),
218 GFP_KERNEL);
219 if (!rt_entry) {
220 pr_err("%s: rt_entry allocation failed for %d\n",
221 __func__, node_id);
222 return NULL;
223 }
224
225 for (i = 0; i < RP_HASH_SIZE; i++)
226 INIT_LIST_HEAD(&rt_entry->remote_port_list[i]);
227
228 mutex_init(&rt_entry->lock);
229 rt_entry->node_id = node_id;
230 rt_entry->xprt_info = NULL;
231 return rt_entry;
232}
233
234/*Please take routing_table_lock before calling this function*/
235static int add_routing_table_entry(
236 struct msm_ipc_routing_table_entry *rt_entry)
237{
238 uint32_t key;
239
240 if (!rt_entry)
241 return -EINVAL;
242
243 key = (rt_entry->node_id % RT_HASH_SIZE);
244 list_add_tail(&rt_entry->list, &routing_table[key]);
245 return 0;
246}
247
248/*Please take routing_table_lock before calling this function*/
249static struct msm_ipc_routing_table_entry *lookup_routing_table(
250 uint32_t node_id)
251{
252 uint32_t key = (node_id % RT_HASH_SIZE);
253 struct msm_ipc_routing_table_entry *rt_entry;
254
255 list_for_each_entry(rt_entry, &routing_table[key], list) {
256 if (rt_entry->node_id == node_id)
257 return rt_entry;
258 }
259 return NULL;
260}
261
262struct rr_packet *rr_read(struct msm_ipc_router_xprt_info *xprt_info)
263{
264 struct rr_packet *temp_pkt;
265
266 if (!xprt_info)
267 return NULL;
268
269 mutex_lock(&xprt_info->rx_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600270 if (xprt_info->abort_data_read) {
271 mutex_unlock(&xprt_info->rx_lock);
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -0600272 pr_err("%s detected SSR & exiting now\n",
273 xprt_info->xprt->name);
274 return NULL;
275 }
276
277 if (list_empty(&xprt_info->pkt_list)) {
278 mutex_unlock(&xprt_info->rx_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600279 return NULL;
280 }
281
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700282 temp_pkt = list_first_entry(&xprt_info->pkt_list,
283 struct rr_packet, list);
284 list_del(&temp_pkt->list);
285 if (list_empty(&xprt_info->pkt_list))
286 wake_unlock(&xprt_info->wakelock);
287 mutex_unlock(&xprt_info->rx_lock);
288 return temp_pkt;
289}
290
291struct rr_packet *clone_pkt(struct rr_packet *pkt)
292{
293 struct rr_packet *cloned_pkt;
294 struct sk_buff *temp_skb, *cloned_skb;
295 struct sk_buff_head *pkt_fragment_q;
296
297 cloned_pkt = kzalloc(sizeof(struct rr_packet), GFP_KERNEL);
298 if (!cloned_pkt) {
299 pr_err("%s: failure\n", __func__);
300 return NULL;
301 }
302
303 pkt_fragment_q = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
304 if (!pkt_fragment_q) {
305 pr_err("%s: pkt_frag_q alloc failure\n", __func__);
306 kfree(cloned_pkt);
307 return NULL;
308 }
309 skb_queue_head_init(pkt_fragment_q);
310
311 skb_queue_walk(pkt->pkt_fragment_q, temp_skb) {
312 cloned_skb = skb_clone(temp_skb, GFP_KERNEL);
313 if (!cloned_skb)
314 goto fail_clone;
315 skb_queue_tail(pkt_fragment_q, cloned_skb);
316 }
317 cloned_pkt->pkt_fragment_q = pkt_fragment_q;
318 cloned_pkt->length = pkt->length;
319 return cloned_pkt;
320
321fail_clone:
322 while (!skb_queue_empty(pkt_fragment_q)) {
323 temp_skb = skb_dequeue(pkt_fragment_q);
324 kfree_skb(temp_skb);
325 }
326 kfree(pkt_fragment_q);
327 kfree(cloned_pkt);
328 return NULL;
329}
330
331struct rr_packet *create_pkt(struct sk_buff_head *data)
332{
333 struct rr_packet *pkt;
334 struct sk_buff *temp_skb;
335
336 pkt = kzalloc(sizeof(struct rr_packet), GFP_KERNEL);
337 if (!pkt) {
338 pr_err("%s: failure\n", __func__);
339 return NULL;
340 }
341
342 pkt->pkt_fragment_q = data;
343 skb_queue_walk(pkt->pkt_fragment_q, temp_skb)
344 pkt->length += temp_skb->len;
345 return pkt;
346}
347
348void release_pkt(struct rr_packet *pkt)
349{
350 struct sk_buff *temp_skb;
351
352 if (!pkt)
353 return;
354
355 if (!pkt->pkt_fragment_q) {
356 kfree(pkt);
357 return;
358 }
359
360 while (!skb_queue_empty(pkt->pkt_fragment_q)) {
361 temp_skb = skb_dequeue(pkt->pkt_fragment_q);
362 kfree_skb(temp_skb);
363 }
364 kfree(pkt->pkt_fragment_q);
365 kfree(pkt);
366 return;
367}
368
369static int post_control_ports(struct rr_packet *pkt)
370{
371 struct msm_ipc_port *port_ptr;
372 struct rr_packet *cloned_pkt;
373
374 if (!pkt)
375 return -EINVAL;
376
377 mutex_lock(&control_ports_lock);
378 list_for_each_entry(port_ptr, &control_ports, list) {
379 mutex_lock(&port_ptr->port_rx_q_lock);
380 cloned_pkt = clone_pkt(pkt);
381 wake_lock(&port_ptr->port_rx_wake_lock);
382 list_add_tail(&cloned_pkt->list, &port_ptr->port_rx_q);
383 wake_up(&port_ptr->port_rx_wait_q);
384 mutex_unlock(&port_ptr->port_rx_q_lock);
385 }
386 mutex_unlock(&control_ports_lock);
387 return 0;
388}
389
390static uint32_t allocate_port_id(void)
391{
392 uint32_t port_id = 0, prev_port_id, key;
393 struct msm_ipc_port *port_ptr;
394
395 mutex_lock(&next_port_id_lock);
396 prev_port_id = next_port_id;
397 mutex_lock(&local_ports_lock);
398 do {
399 next_port_id++;
400 if ((next_port_id & 0xFFFFFFFE) == 0xFFFFFFFE)
401 next_port_id = 1;
402
403 key = (next_port_id & (LP_HASH_SIZE - 1));
404 if (list_empty(&local_ports[key])) {
405 port_id = next_port_id;
406 break;
407 }
408 list_for_each_entry(port_ptr, &local_ports[key], list) {
409 if (port_ptr->this_port.port_id == next_port_id) {
410 port_id = next_port_id;
411 break;
412 }
413 }
414 if (!port_id) {
415 port_id = next_port_id;
416 break;
417 }
418 port_id = 0;
419 } while (next_port_id != prev_port_id);
420 mutex_unlock(&local_ports_lock);
421 mutex_unlock(&next_port_id_lock);
422
423 return port_id;
424}
425
426void msm_ipc_router_add_local_port(struct msm_ipc_port *port_ptr)
427{
428 uint32_t key;
429
430 if (!port_ptr)
431 return;
432
433 key = (port_ptr->this_port.port_id & (LP_HASH_SIZE - 1));
434 mutex_lock(&local_ports_lock);
435 list_add_tail(&port_ptr->list, &local_ports[key]);
436 mutex_unlock(&local_ports_lock);
437}
438
439struct msm_ipc_port *msm_ipc_router_create_raw_port(void *endpoint,
440 void (*notify)(unsigned event, void *data,
441 void *addr, void *priv),
442 void *priv)
443{
444 struct msm_ipc_port *port_ptr;
445
446 port_ptr = kzalloc(sizeof(struct msm_ipc_port), GFP_KERNEL);
447 if (!port_ptr)
448 return NULL;
449
450 port_ptr->this_port.node_id = IPC_ROUTER_NID_LOCAL;
451 port_ptr->this_port.port_id = allocate_port_id();
452 if (!port_ptr->this_port.port_id) {
453 pr_err("%s: All port ids are in use\n", __func__);
454 kfree(port_ptr);
455 return NULL;
456 }
457
458 spin_lock_init(&port_ptr->port_lock);
459 INIT_LIST_HEAD(&port_ptr->incomplete);
460 mutex_init(&port_ptr->incomplete_lock);
461 INIT_LIST_HEAD(&port_ptr->port_rx_q);
462 mutex_init(&port_ptr->port_rx_q_lock);
463 init_waitqueue_head(&port_ptr->port_rx_wait_q);
Karthikeyan Ramasubramanianb4aeeb92012-03-13 12:31:43 -0600464 snprintf(port_ptr->rx_wakelock_name, MAX_WAKELOCK_NAME_SZ,
465 "msm_ipc_read%08x:%08x",
466 port_ptr->this_port.node_id,
467 port_ptr->this_port.port_id);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700468 wake_lock_init(&port_ptr->port_rx_wake_lock,
Karthikeyan Ramasubramanianb4aeeb92012-03-13 12:31:43 -0600469 WAKE_LOCK_SUSPEND, port_ptr->rx_wakelock_name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700470
471 port_ptr->endpoint = endpoint;
472 port_ptr->notify = notify;
473 port_ptr->priv = priv;
474
475 msm_ipc_router_add_local_port(port_ptr);
476 return port_ptr;
477}
478
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -0600479/*
480 * Should be called with local_ports_lock locked
481 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700482static struct msm_ipc_port *msm_ipc_router_lookup_local_port(uint32_t port_id)
483{
484 int key = (port_id & (LP_HASH_SIZE - 1));
485 struct msm_ipc_port *port_ptr;
486
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700487 list_for_each_entry(port_ptr, &local_ports[key], list) {
488 if (port_ptr->this_port.port_id == port_id) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700489 return port_ptr;
490 }
491 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700492 return NULL;
493}
494
495static struct msm_ipc_router_remote_port *msm_ipc_router_lookup_remote_port(
496 uint32_t node_id,
497 uint32_t port_id)
498{
499 struct msm_ipc_router_remote_port *rport_ptr;
500 struct msm_ipc_routing_table_entry *rt_entry;
501 int key = (port_id & (RP_HASH_SIZE - 1));
502
503 mutex_lock(&routing_table_lock);
504 rt_entry = lookup_routing_table(node_id);
505 if (!rt_entry) {
506 mutex_unlock(&routing_table_lock);
507 pr_err("%s: Node is not up\n", __func__);
508 return NULL;
509 }
510
511 mutex_lock(&rt_entry->lock);
512 list_for_each_entry(rport_ptr,
513 &rt_entry->remote_port_list[key], list) {
514 if (rport_ptr->port_id == port_id) {
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600515 if (rport_ptr->restart_state != RESTART_NORMAL)
516 rport_ptr = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700517 mutex_unlock(&rt_entry->lock);
518 mutex_unlock(&routing_table_lock);
519 return rport_ptr;
520 }
521 }
522 mutex_unlock(&rt_entry->lock);
523 mutex_unlock(&routing_table_lock);
524 return NULL;
525}
526
527static struct msm_ipc_router_remote_port *msm_ipc_router_create_remote_port(
528 uint32_t node_id,
529 uint32_t port_id)
530{
531 struct msm_ipc_router_remote_port *rport_ptr;
532 struct msm_ipc_routing_table_entry *rt_entry;
533 int key = (port_id & (RP_HASH_SIZE - 1));
534
535 mutex_lock(&routing_table_lock);
536 rt_entry = lookup_routing_table(node_id);
537 if (!rt_entry) {
538 mutex_unlock(&routing_table_lock);
539 pr_err("%s: Node is not up\n", __func__);
540 return NULL;
541 }
542
543 mutex_lock(&rt_entry->lock);
544 rport_ptr = kmalloc(sizeof(struct msm_ipc_router_remote_port),
545 GFP_KERNEL);
546 if (!rport_ptr) {
547 mutex_unlock(&rt_entry->lock);
548 mutex_unlock(&routing_table_lock);
549 pr_err("%s: Remote port alloc failed\n", __func__);
550 return NULL;
551 }
552 rport_ptr->port_id = port_id;
553 rport_ptr->node_id = node_id;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600554 rport_ptr->restart_state = RESTART_NORMAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700555 rport_ptr->tx_quota_cnt = 0;
556 init_waitqueue_head(&rport_ptr->quota_wait);
557 mutex_init(&rport_ptr->quota_lock);
558 list_add_tail(&rport_ptr->list,
559 &rt_entry->remote_port_list[key]);
560 mutex_unlock(&rt_entry->lock);
561 mutex_unlock(&routing_table_lock);
562 return rport_ptr;
563}
564
565static void msm_ipc_router_destroy_remote_port(
566 struct msm_ipc_router_remote_port *rport_ptr)
567{
568 uint32_t node_id;
569 struct msm_ipc_routing_table_entry *rt_entry;
570
571 if (!rport_ptr)
572 return;
573
574 node_id = rport_ptr->node_id;
575 mutex_lock(&routing_table_lock);
576 rt_entry = lookup_routing_table(node_id);
577 if (!rt_entry) {
578 mutex_unlock(&routing_table_lock);
579 pr_err("%s: Node %d is not up\n", __func__, node_id);
580 return;
581 }
582
583 mutex_lock(&rt_entry->lock);
584 list_del(&rport_ptr->list);
585 kfree(rport_ptr);
586 mutex_unlock(&rt_entry->lock);
587 mutex_unlock(&routing_table_lock);
588 return;
589}
590
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -0600591/**
592 * msm_ipc_router_lookup_server() - Lookup server information
593 * @service: Service ID of the server info to be looked up.
594 * @instance: Instance ID of the server info to be looked up.
595 * @node_id: Node/Processor ID in which the server is hosted.
596 * @port_id: Port ID within the node in which the server is hosted.
597 *
598 * @return: If found Pointer to server structure, else NULL.
599 *
600 * Note1: Lock the server_list_lock before accessing this function.
601 * Note2: If the <node_id:port_id> are <0:0>, then the lookup is restricted
602 * to <service:instance>. Used only when a client wants to send a
603 * message to any QMI server.
604 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700605static struct msm_ipc_server *msm_ipc_router_lookup_server(
606 uint32_t service,
607 uint32_t instance,
608 uint32_t node_id,
609 uint32_t port_id)
610{
611 struct msm_ipc_server *server;
612 struct msm_ipc_server_port *server_port;
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -0600613 int key = (service & (SRV_HASH_SIZE - 1));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700614
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700615 list_for_each_entry(server, &server_list[key], list) {
616 if ((server->name.service != service) ||
617 (server->name.instance != instance))
618 continue;
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -0600619 if ((node_id == 0) && (port_id == 0))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700620 return server;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700621 list_for_each_entry(server_port, &server->server_port_list,
622 list) {
623 if ((server_port->server_addr.node_id == node_id) &&
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -0600624 (server_port->server_addr.port_id == port_id))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700625 return server;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700626 }
627 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700628 return NULL;
629}
630
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -0600631/**
632 * msm_ipc_router_create_server() - Add server info to hash table
633 * @service: Service ID of the server info to be created.
634 * @instance: Instance ID of the server info to be created.
635 * @node_id: Node/Processor ID in which the server is hosted.
636 * @port_id: Port ID within the node in which the server is hosted.
637 * @xprt_info: XPRT through which the node hosting the server is reached.
638 *
639 * @return: Pointer to server structure on success, else NULL.
640 *
641 * This function adds the server info to the hash table. If the same
642 * server(i.e. <service_id:instance_id>) is hosted in different nodes,
643 * they are maintained as list of "server_port" under "server" structure.
644 * Note: Lock the server_list_lock before accessing this function.
645 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700646static struct msm_ipc_server *msm_ipc_router_create_server(
647 uint32_t service,
648 uint32_t instance,
649 uint32_t node_id,
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600650 uint32_t port_id,
651 struct msm_ipc_router_xprt_info *xprt_info)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700652{
653 struct msm_ipc_server *server = NULL;
654 struct msm_ipc_server_port *server_port;
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -0600655 int key = (service & (SRV_HASH_SIZE - 1));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700656
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700657 list_for_each_entry(server, &server_list[key], list) {
658 if ((server->name.service == service) &&
659 (server->name.instance == instance))
660 goto create_srv_port;
661 }
662
663 server = kmalloc(sizeof(struct msm_ipc_server), GFP_KERNEL);
664 if (!server) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700665 pr_err("%s: Server allocation failed\n", __func__);
666 return NULL;
667 }
668 server->name.service = service;
669 server->name.instance = instance;
670 INIT_LIST_HEAD(&server->server_port_list);
671 list_add_tail(&server->list, &server_list[key]);
672
673create_srv_port:
674 server_port = kmalloc(sizeof(struct msm_ipc_server_port), GFP_KERNEL);
675 if (!server_port) {
676 if (list_empty(&server->server_port_list)) {
677 list_del(&server->list);
678 kfree(server);
679 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700680 pr_err("%s: Server Port allocation failed\n", __func__);
681 return NULL;
682 }
683 server_port->server_addr.node_id = node_id;
684 server_port->server_addr.port_id = port_id;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600685 server_port->xprt_info = xprt_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700686 list_add_tail(&server_port->list, &server->server_port_list);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700687
688 return server;
689}
690
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -0600691/**
692 * msm_ipc_router_destroy_server() - Remove server info from hash table
693 * @server: Server info to be removed.
694 * @node_id: Node/Processor ID in which the server is hosted.
695 * @port_id: Port ID within the node in which the server is hosted.
696 *
697 * This function removes the server_port identified using <node_id:port_id>
698 * from the server structure. If the server_port list under server structure
699 * is empty after removal, then remove the server structure from the server
700 * hash table.
701 * Note: Lock the server_list_lock before accessing this function.
702 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700703static void msm_ipc_router_destroy_server(struct msm_ipc_server *server,
704 uint32_t node_id, uint32_t port_id)
705{
706 struct msm_ipc_server_port *server_port;
707
708 if (!server)
709 return;
710
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700711 list_for_each_entry(server_port, &server->server_port_list, list) {
712 if ((server_port->server_addr.node_id == node_id) &&
713 (server_port->server_addr.port_id == port_id))
714 break;
715 }
716 if (server_port) {
717 list_del(&server_port->list);
718 kfree(server_port);
719 }
720 if (list_empty(&server->server_port_list)) {
721 list_del(&server->list);
722 kfree(server);
723 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700724 return;
725}
726
727static int msm_ipc_router_send_control_msg(
728 struct msm_ipc_router_xprt_info *xprt_info,
729 union rr_control_msg *msg)
730{
731 struct rr_packet *pkt;
732 struct sk_buff *ipc_rtr_pkt;
733 struct rr_header *hdr;
734 int pkt_size;
735 void *data;
736 struct sk_buff_head *pkt_fragment_q;
737 int ret;
738
739 if (!xprt_info || ((msg->cmd != IPC_ROUTER_CTRL_CMD_HELLO) &&
740 !xprt_info->initialized)) {
741 pr_err("%s: xprt_info not initialized\n", __func__);
742 return -EINVAL;
743 }
744
745 if (xprt_info->remote_node_id == IPC_ROUTER_NID_LOCAL)
746 return 0;
747
748 pkt = kzalloc(sizeof(struct rr_packet), GFP_KERNEL);
749 if (!pkt) {
750 pr_err("%s: pkt alloc failed\n", __func__);
751 return -ENOMEM;
752 }
753
754 pkt_fragment_q = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
755 if (!pkt_fragment_q) {
756 pr_err("%s: pkt_fragment_q alloc failed\n", __func__);
757 kfree(pkt);
758 return -ENOMEM;
759 }
760 skb_queue_head_init(pkt_fragment_q);
761
762 pkt_size = IPC_ROUTER_HDR_SIZE + sizeof(*msg);
763 ipc_rtr_pkt = alloc_skb(pkt_size, GFP_KERNEL);
764 if (!ipc_rtr_pkt) {
765 pr_err("%s: ipc_rtr_pkt alloc failed\n", __func__);
766 kfree(pkt_fragment_q);
767 kfree(pkt);
768 return -ENOMEM;
769 }
770
771 skb_reserve(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
772 data = skb_put(ipc_rtr_pkt, sizeof(*msg));
773 memcpy(data, msg, sizeof(*msg));
774 hdr = (struct rr_header *)skb_push(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
775 if (!hdr) {
776 pr_err("%s: skb_push failed\n", __func__);
777 kfree_skb(ipc_rtr_pkt);
778 kfree(pkt_fragment_q);
779 kfree(pkt);
780 return -ENOMEM;
781 }
782
783 hdr->version = IPC_ROUTER_VERSION;
784 hdr->type = msg->cmd;
785 hdr->src_node_id = IPC_ROUTER_NID_LOCAL;
786 hdr->src_port_id = IPC_ROUTER_ADDRESS;
787 hdr->confirm_rx = 0;
788 hdr->size = sizeof(*msg);
789 hdr->dst_node_id = xprt_info->remote_node_id;
790 hdr->dst_port_id = IPC_ROUTER_ADDRESS;
791 skb_queue_tail(pkt_fragment_q, ipc_rtr_pkt);
792 pkt->pkt_fragment_q = pkt_fragment_q;
793 pkt->length = pkt_size;
794
795 mutex_lock(&xprt_info->tx_lock);
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700796 ret = xprt_info->xprt->write(pkt, pkt_size, xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700797 mutex_unlock(&xprt_info->tx_lock);
798
799 release_pkt(pkt);
800 return ret;
801}
802
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -0600803static int msm_ipc_router_send_server_list(uint32_t node_id,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700804 struct msm_ipc_router_xprt_info *xprt_info)
805{
806 union rr_control_msg ctl;
807 struct msm_ipc_server *server;
808 struct msm_ipc_server_port *server_port;
809 int i;
810
811 if (!xprt_info || !xprt_info->initialized) {
812 pr_err("%s: Xprt info not initialized\n", __func__);
813 return -EINVAL;
814 }
815
816 ctl.cmd = IPC_ROUTER_CTRL_CMD_NEW_SERVER;
817
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700818 for (i = 0; i < SRV_HASH_SIZE; i++) {
819 list_for_each_entry(server, &server_list[i], list) {
820 ctl.srv.service = server->name.service;
821 ctl.srv.instance = server->name.instance;
822 list_for_each_entry(server_port,
823 &server->server_port_list, list) {
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -0600824 if (server_port->server_addr.node_id !=
825 node_id)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700826 continue;
827
828 ctl.srv.node_id =
829 server_port->server_addr.node_id;
830 ctl.srv.port_id =
831 server_port->server_addr.port_id;
832 msm_ipc_router_send_control_msg(xprt_info,
833 &ctl);
834 }
835 }
836 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700837
838 return 0;
839}
840
841#if defined(DEBUG)
842static char *type_to_str(int i)
843{
844 switch (i) {
845 case IPC_ROUTER_CTRL_CMD_DATA:
846 return "data ";
847 case IPC_ROUTER_CTRL_CMD_HELLO:
848 return "hello ";
849 case IPC_ROUTER_CTRL_CMD_BYE:
850 return "bye ";
851 case IPC_ROUTER_CTRL_CMD_NEW_SERVER:
852 return "new_srvr";
853 case IPC_ROUTER_CTRL_CMD_REMOVE_SERVER:
854 return "rmv_srvr";
855 case IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT:
856 return "rmv_clnt";
857 case IPC_ROUTER_CTRL_CMD_RESUME_TX:
858 return "resum_tx";
859 case IPC_ROUTER_CTRL_CMD_EXIT:
860 return "cmd_exit";
861 default:
862 return "invalid";
863 }
864}
865#endif
866
867static int broadcast_ctl_msg_locally(union rr_control_msg *msg)
868{
869 struct rr_packet *pkt;
870 struct sk_buff *ipc_rtr_pkt;
871 struct rr_header *hdr;
872 int pkt_size;
873 void *data;
874 struct sk_buff_head *pkt_fragment_q;
875 int ret;
876
877 pkt = kzalloc(sizeof(struct rr_packet), GFP_KERNEL);
878 if (!pkt) {
879 pr_err("%s: pkt alloc failed\n", __func__);
880 return -ENOMEM;
881 }
882
883 pkt_fragment_q = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
884 if (!pkt_fragment_q) {
885 pr_err("%s: pkt_fragment_q alloc failed\n", __func__);
886 kfree(pkt);
887 return -ENOMEM;
888 }
889 skb_queue_head_init(pkt_fragment_q);
890
891 pkt_size = IPC_ROUTER_HDR_SIZE + sizeof(*msg);
892 ipc_rtr_pkt = alloc_skb(pkt_size, GFP_KERNEL);
893 if (!ipc_rtr_pkt) {
894 pr_err("%s: ipc_rtr_pkt alloc failed\n", __func__);
895 kfree(pkt_fragment_q);
896 kfree(pkt);
897 return -ENOMEM;
898 }
899
900 skb_reserve(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
901 data = skb_put(ipc_rtr_pkt, sizeof(*msg));
902 memcpy(data, msg, sizeof(*msg));
903 hdr = (struct rr_header *)skb_push(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
904 if (!hdr) {
905 pr_err("%s: skb_push failed\n", __func__);
906 kfree_skb(ipc_rtr_pkt);
907 kfree(pkt_fragment_q);
908 kfree(pkt);
909 return -ENOMEM;
910 }
911 hdr->version = IPC_ROUTER_VERSION;
912 hdr->type = msg->cmd;
913 hdr->src_node_id = IPC_ROUTER_NID_LOCAL;
914 hdr->src_port_id = IPC_ROUTER_ADDRESS;
915 hdr->confirm_rx = 0;
916 hdr->size = sizeof(*msg);
917 hdr->dst_node_id = IPC_ROUTER_NID_LOCAL;
918 hdr->dst_port_id = IPC_ROUTER_ADDRESS;
919 skb_queue_tail(pkt_fragment_q, ipc_rtr_pkt);
920 pkt->pkt_fragment_q = pkt_fragment_q;
921 pkt->length = pkt_size;
922
923 ret = post_control_ports(pkt);
924 release_pkt(pkt);
925 return ret;
926}
927
928static int broadcast_ctl_msg(union rr_control_msg *ctl)
929{
930 struct msm_ipc_router_xprt_info *xprt_info;
931
932 mutex_lock(&xprt_info_list_lock);
933 list_for_each_entry(xprt_info, &xprt_info_list, list) {
934 msm_ipc_router_send_control_msg(xprt_info, ctl);
935 }
936 mutex_unlock(&xprt_info_list_lock);
937
938 return 0;
939}
940
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600941static int relay_ctl_msg(struct msm_ipc_router_xprt_info *xprt_info,
942 union rr_control_msg *ctl)
943{
944 struct msm_ipc_router_xprt_info *fwd_xprt_info;
945
946 if (!xprt_info || !ctl)
947 return -EINVAL;
948
949 mutex_lock(&xprt_info_list_lock);
950 list_for_each_entry(fwd_xprt_info, &xprt_info_list, list) {
951 if (xprt_info->xprt->link_id != fwd_xprt_info->xprt->link_id)
952 msm_ipc_router_send_control_msg(fwd_xprt_info, ctl);
953 }
954 mutex_unlock(&xprt_info_list_lock);
955
956 return 0;
957}
958
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700959static int relay_msg(struct msm_ipc_router_xprt_info *xprt_info,
960 struct rr_packet *pkt)
961{
962 struct msm_ipc_router_xprt_info *fwd_xprt_info;
963
964 if (!xprt_info || !pkt)
965 return -EINVAL;
966
967 mutex_lock(&xprt_info_list_lock);
968 list_for_each_entry(fwd_xprt_info, &xprt_info_list, list) {
969 mutex_lock(&fwd_xprt_info->tx_lock);
970 if (xprt_info->xprt->link_id != fwd_xprt_info->xprt->link_id)
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700971 fwd_xprt_info->xprt->write(pkt, pkt->length,
972 fwd_xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700973 mutex_unlock(&fwd_xprt_info->tx_lock);
974 }
975 mutex_unlock(&xprt_info_list_lock);
976 return 0;
977}
978
979static int forward_msg(struct msm_ipc_router_xprt_info *xprt_info,
980 struct rr_packet *pkt)
981{
982 uint32_t dst_node_id;
983 struct sk_buff *head_pkt;
984 struct rr_header *hdr;
985 struct msm_ipc_router_xprt_info *fwd_xprt_info;
986 struct msm_ipc_routing_table_entry *rt_entry;
987
988 if (!xprt_info || !pkt)
989 return -EINVAL;
990
991 head_pkt = skb_peek(pkt->pkt_fragment_q);
992 if (!head_pkt)
993 return -EINVAL;
994
995 hdr = (struct rr_header *)head_pkt->data;
996 dst_node_id = hdr->dst_node_id;
997 mutex_lock(&routing_table_lock);
998 rt_entry = lookup_routing_table(dst_node_id);
999 if (!(rt_entry) || !(rt_entry->xprt_info)) {
1000 mutex_unlock(&routing_table_lock);
1001 pr_err("%s: Routing table not initialized\n", __func__);
1002 return -ENODEV;
1003 }
1004
1005 mutex_lock(&rt_entry->lock);
1006 fwd_xprt_info = rt_entry->xprt_info;
1007 mutex_lock(&fwd_xprt_info->tx_lock);
1008 if (xprt_info->remote_node_id == fwd_xprt_info->remote_node_id) {
1009 mutex_unlock(&fwd_xprt_info->tx_lock);
1010 mutex_unlock(&rt_entry->lock);
1011 mutex_unlock(&routing_table_lock);
1012 pr_err("%s: Discarding Command to route back\n", __func__);
1013 return -EINVAL;
1014 }
1015
1016 if (xprt_info->xprt->link_id == fwd_xprt_info->xprt->link_id) {
1017 mutex_unlock(&fwd_xprt_info->tx_lock);
1018 mutex_unlock(&rt_entry->lock);
1019 mutex_unlock(&routing_table_lock);
1020 pr_err("%s: DST in the same cluster\n", __func__);
1021 return 0;
1022 }
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -07001023 fwd_xprt_info->xprt->write(pkt, pkt->length, fwd_xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001024 mutex_unlock(&fwd_xprt_info->tx_lock);
1025 mutex_unlock(&rt_entry->lock);
1026 mutex_unlock(&routing_table_lock);
1027
1028 return 0;
1029}
1030
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001031static void reset_remote_port_info(uint32_t node_id, uint32_t port_id)
1032{
1033 struct msm_ipc_router_remote_port *rport_ptr;
1034
1035 rport_ptr = msm_ipc_router_lookup_remote_port(node_id, port_id);
1036 if (!rport_ptr) {
1037 pr_err("%s: No such remote port %08x:%08x\n",
1038 __func__, node_id, port_id);
1039 return;
1040 }
1041 mutex_lock(&rport_ptr->quota_lock);
1042 rport_ptr->restart_state = RESTART_PEND;
1043 wake_up(&rport_ptr->quota_wait);
1044 mutex_unlock(&rport_ptr->quota_lock);
1045 return;
1046}
1047
1048static void msm_ipc_cleanup_remote_server_info(
1049 struct msm_ipc_router_xprt_info *xprt_info)
1050{
1051 struct msm_ipc_server *svr, *tmp_svr;
1052 struct msm_ipc_server_port *svr_port, *tmp_svr_port;
1053 int i;
1054 union rr_control_msg ctl;
1055
1056 if (!xprt_info) {
1057 pr_err("%s: Invalid xprt_info\n", __func__);
1058 return;
1059 }
1060
1061 ctl.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_SERVER;
1062 mutex_lock(&server_list_lock);
1063 for (i = 0; i < SRV_HASH_SIZE; i++) {
1064 list_for_each_entry_safe(svr, tmp_svr, &server_list[i], list) {
1065 ctl.srv.service = svr->name.service;
1066 ctl.srv.instance = svr->name.instance;
1067 list_for_each_entry_safe(svr_port, tmp_svr_port,
1068 &svr->server_port_list, list) {
1069 if (svr_port->xprt_info != xprt_info)
1070 continue;
1071 D("Remove server %08x:%08x - %08x:%08x",
1072 ctl.srv.service, ctl.srv.instance,
1073 svr_port->server_addr.node_id,
1074 svr_port->server_addr.port_id);
1075 reset_remote_port_info(
1076 svr_port->server_addr.node_id,
1077 svr_port->server_addr.port_id);
1078 ctl.srv.node_id = svr_port->server_addr.node_id;
1079 ctl.srv.port_id = svr_port->server_addr.port_id;
1080 relay_ctl_msg(xprt_info, &ctl);
1081 broadcast_ctl_msg_locally(&ctl);
1082 list_del(&svr_port->list);
1083 kfree(svr_port);
1084 }
1085 if (list_empty(&svr->server_port_list)) {
1086 list_del(&svr->list);
1087 kfree(svr);
1088 }
1089 }
1090 }
1091 mutex_unlock(&server_list_lock);
1092}
1093
1094static void msm_ipc_cleanup_remote_client_info(
1095 struct msm_ipc_router_xprt_info *xprt_info)
1096{
1097 struct msm_ipc_routing_table_entry *rt_entry;
1098 struct msm_ipc_router_remote_port *rport_ptr;
1099 int i, j;
1100 union rr_control_msg ctl;
1101
1102 if (!xprt_info) {
1103 pr_err("%s: Invalid xprt_info\n", __func__);
1104 return;
1105 }
1106
1107 ctl.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT;
1108 mutex_lock(&routing_table_lock);
1109 for (i = 0; i < RT_HASH_SIZE; i++) {
1110 list_for_each_entry(rt_entry, &routing_table[i], list) {
1111 mutex_lock(&rt_entry->lock);
1112 if (rt_entry->xprt_info != xprt_info) {
1113 mutex_unlock(&rt_entry->lock);
1114 continue;
1115 }
1116 for (j = 0; j < RP_HASH_SIZE; j++) {
1117 list_for_each_entry(rport_ptr,
1118 &rt_entry->remote_port_list[j], list) {
1119 if (rport_ptr->restart_state ==
1120 RESTART_PEND)
1121 continue;
1122 mutex_lock(&rport_ptr->quota_lock);
1123 rport_ptr->restart_state = RESTART_PEND;
1124 wake_up(&rport_ptr->quota_wait);
1125 mutex_unlock(&rport_ptr->quota_lock);
1126 ctl.cli.node_id = rport_ptr->node_id;
1127 ctl.cli.port_id = rport_ptr->port_id;
1128 broadcast_ctl_msg_locally(&ctl);
1129 }
1130 }
1131 mutex_unlock(&rt_entry->lock);
1132 }
1133 }
1134 mutex_unlock(&routing_table_lock);
1135}
1136
1137static void msm_ipc_cleanup_remote_port_info(uint32_t node_id)
1138{
1139 struct msm_ipc_routing_table_entry *rt_entry, *tmp_rt_entry;
1140 struct msm_ipc_router_remote_port *rport_ptr, *tmp_rport_ptr;
1141 int i, j;
1142
1143 mutex_lock(&routing_table_lock);
1144 for (i = 0; i < RT_HASH_SIZE; i++) {
1145 list_for_each_entry_safe(rt_entry, tmp_rt_entry,
1146 &routing_table[i], list) {
1147 mutex_lock(&rt_entry->lock);
1148 if (rt_entry->neighbor_node_id != node_id) {
1149 mutex_unlock(&rt_entry->lock);
1150 continue;
1151 }
1152 for (j = 0; j < RP_HASH_SIZE; j++) {
1153 list_for_each_entry_safe(rport_ptr,
1154 tmp_rport_ptr,
1155 &rt_entry->remote_port_list[j], list) {
1156 list_del(&rport_ptr->list);
1157 kfree(rport_ptr);
1158 }
1159 }
1160 mutex_unlock(&rt_entry->lock);
1161 }
1162 }
1163 mutex_unlock(&routing_table_lock);
1164}
1165
1166static void msm_ipc_cleanup_routing_table(
1167 struct msm_ipc_router_xprt_info *xprt_info)
1168{
1169 int i;
1170 struct msm_ipc_routing_table_entry *rt_entry;
1171
1172 if (!xprt_info) {
1173 pr_err("%s: Invalid xprt_info\n", __func__);
1174 return;
1175 }
1176
1177 mutex_lock(&routing_table_lock);
1178 for (i = 0; i < RT_HASH_SIZE; i++) {
1179 list_for_each_entry(rt_entry, &routing_table[i], list) {
1180 mutex_lock(&rt_entry->lock);
1181 if (rt_entry->xprt_info == xprt_info)
1182 rt_entry->xprt_info = NULL;
1183 mutex_unlock(&rt_entry->lock);
1184 }
1185 }
1186 mutex_unlock(&routing_table_lock);
1187}
1188
1189static void modem_reset_cleanup(struct msm_ipc_router_xprt_info *xprt_info)
1190{
1191
1192 if (!xprt_info) {
1193 pr_err("%s: Invalid xprt_info\n", __func__);
1194 return;
1195 }
1196
1197 msm_ipc_cleanup_remote_server_info(xprt_info);
1198 msm_ipc_cleanup_remote_client_info(xprt_info);
1199 msm_ipc_cleanup_routing_table(xprt_info);
1200}
1201
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001202static int process_hello_msg(struct msm_ipc_router_xprt_info *xprt_info,
1203 struct rr_header *hdr)
1204{
1205 int i, rc = 0;
1206 union rr_control_msg ctl;
1207 struct msm_ipc_routing_table_entry *rt_entry;
1208
1209 if (!hdr)
1210 return -EINVAL;
1211
1212 RR("o HELLO NID %d\n", hdr->src_node_id);
1213
1214 xprt_info->remote_node_id = hdr->src_node_id;
1215 /*
1216 * Find the entry from Routing Table corresponding to Node ID.
1217 * Under SSR, an entry will be found. When the system boots up
1218 * for the 1st time, an entry will not be found and hence allocate
1219 * an entry. Update the entry with the Node ID that it corresponds
1220 * to and the XPRT through which it can be reached.
1221 */
1222 mutex_lock(&routing_table_lock);
1223 rt_entry = lookup_routing_table(hdr->src_node_id);
1224 if (!rt_entry) {
1225 rt_entry = alloc_routing_table_entry(hdr->src_node_id);
1226 if (!rt_entry) {
1227 mutex_unlock(&routing_table_lock);
1228 pr_err("%s: rt_entry allocation failed\n", __func__);
1229 return -ENOMEM;
1230 }
1231 add_routing_table_entry(rt_entry);
1232 }
1233 mutex_lock(&rt_entry->lock);
1234 rt_entry->neighbor_node_id = xprt_info->remote_node_id;
1235 rt_entry->xprt_info = xprt_info;
1236 mutex_unlock(&rt_entry->lock);
1237 mutex_unlock(&routing_table_lock);
1238
1239 /* Cleanup any remote ports, if the node is coming out of reset */
1240 msm_ipc_cleanup_remote_port_info(xprt_info->remote_node_id);
1241
1242 /* Send a reply HELLO message */
1243 memset(&ctl, 0, sizeof(ctl));
1244 ctl.cmd = IPC_ROUTER_CTRL_CMD_HELLO;
1245 rc = msm_ipc_router_send_control_msg(xprt_info, &ctl);
1246 if (rc < 0) {
1247 pr_err("%s: Error sending reply HELLO message\n", __func__);
1248 return rc;
1249 }
1250 xprt_info->initialized = 1;
1251
1252 /*
1253 * Send list of servers from the local node and from nodes
1254 * outside the mesh network in which this XPRT is part of.
1255 */
Karthikeyan Ramasubramaniane8ad5352012-10-31 15:12:08 -06001256 mutex_lock(&server_list_lock);
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001257 mutex_lock(&routing_table_lock);
1258 for (i = 0; i < RT_HASH_SIZE; i++) {
1259 list_for_each_entry(rt_entry, &routing_table[i], list) {
1260 if ((rt_entry->node_id != IPC_ROUTER_NID_LOCAL) &&
Karthikeyan Ramasubramanian72ad5792013-01-30 14:17:57 -07001261 (!rt_entry->xprt_info ||
1262 (rt_entry->xprt_info->xprt->link_id ==
1263 xprt_info->xprt->link_id)))
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001264 continue;
1265 rc = msm_ipc_router_send_server_list(rt_entry->node_id,
1266 xprt_info);
1267 if (rc < 0) {
1268 mutex_unlock(&routing_table_lock);
Karthikeyan Ramasubramaniane8ad5352012-10-31 15:12:08 -06001269 mutex_unlock(&server_list_lock);
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001270 return rc;
1271 }
1272 }
1273 }
1274 mutex_unlock(&routing_table_lock);
Karthikeyan Ramasubramaniane8ad5352012-10-31 15:12:08 -06001275 mutex_unlock(&server_list_lock);
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001276 RR("HELLO message processed\n");
1277 return rc;
1278}
1279
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001280static int process_control_msg(struct msm_ipc_router_xprt_info *xprt_info,
1281 struct rr_packet *pkt)
1282{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001283 union rr_control_msg *msg;
1284 struct msm_ipc_router_remote_port *rport_ptr;
1285 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001286 struct sk_buff *temp_ptr;
1287 struct rr_header *hdr;
1288 struct msm_ipc_server *server;
1289 struct msm_ipc_routing_table_entry *rt_entry;
1290
1291 if (pkt->length != (IPC_ROUTER_HDR_SIZE + sizeof(*msg))) {
1292 pr_err("%s: r2r msg size %d != %d\n", __func__, pkt->length,
1293 (IPC_ROUTER_HDR_SIZE + sizeof(*msg)));
1294 return -EINVAL;
1295 }
1296
1297 temp_ptr = skb_peek(pkt->pkt_fragment_q);
Karthikeyan Ramasubramanian9024dd82011-12-19 18:44:19 -07001298 if (!temp_ptr) {
1299 pr_err("%s: pkt_fragment_q is empty\n", __func__);
1300 return -EINVAL;
1301 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001302 hdr = (struct rr_header *)temp_ptr->data;
Karthikeyan Ramasubramanian9024dd82011-12-19 18:44:19 -07001303 if (!hdr) {
1304 pr_err("%s: No data inside the skb\n", __func__);
1305 return -EINVAL;
1306 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001307 msg = (union rr_control_msg *)((char *)hdr + IPC_ROUTER_HDR_SIZE);
1308
1309 switch (msg->cmd) {
1310 case IPC_ROUTER_CTRL_CMD_HELLO:
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001311 rc = process_hello_msg(xprt_info, hdr);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001312 break;
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001313
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001314 case IPC_ROUTER_CTRL_CMD_RESUME_TX:
1315 RR("o RESUME_TX id=%d:%08x\n",
1316 msg->cli.node_id, msg->cli.port_id);
1317
1318 rport_ptr = msm_ipc_router_lookup_remote_port(msg->cli.node_id,
1319 msg->cli.port_id);
1320 if (!rport_ptr) {
1321 pr_err("%s: Unable to resume client\n", __func__);
1322 break;
1323 }
1324 mutex_lock(&rport_ptr->quota_lock);
1325 rport_ptr->tx_quota_cnt = 0;
1326 mutex_unlock(&rport_ptr->quota_lock);
1327 wake_up(&rport_ptr->quota_wait);
1328 break;
1329
1330 case IPC_ROUTER_CTRL_CMD_NEW_SERVER:
1331 if (msg->srv.instance == 0) {
1332 pr_err(
1333 "rpcrouter: Server create rejected, version = 0, "
1334 "service = %08x\n", msg->srv.service);
1335 break;
1336 }
1337
1338 RR("o NEW_SERVER id=%d:%08x service=%08x:%08x\n",
1339 msg->srv.node_id, msg->srv.port_id,
1340 msg->srv.service, msg->srv.instance);
1341
1342 mutex_lock(&routing_table_lock);
1343 rt_entry = lookup_routing_table(msg->srv.node_id);
1344 if (!rt_entry) {
1345 rt_entry = alloc_routing_table_entry(msg->srv.node_id);
1346 if (!rt_entry) {
1347 mutex_unlock(&routing_table_lock);
1348 pr_err("%s: rt_entry allocation failed\n",
1349 __func__);
1350 return -ENOMEM;
1351 }
1352 mutex_lock(&rt_entry->lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001353 rt_entry->neighbor_node_id = xprt_info->remote_node_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001354 rt_entry->xprt_info = xprt_info;
1355 mutex_unlock(&rt_entry->lock);
1356 add_routing_table_entry(rt_entry);
1357 }
1358 mutex_unlock(&routing_table_lock);
1359
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001360 mutex_lock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001361 server = msm_ipc_router_lookup_server(msg->srv.service,
1362 msg->srv.instance,
1363 msg->srv.node_id,
1364 msg->srv.port_id);
1365 if (!server) {
1366 server = msm_ipc_router_create_server(
1367 msg->srv.service, msg->srv.instance,
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001368 msg->srv.node_id, msg->srv.port_id, xprt_info);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001369 if (!server) {
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001370 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001371 pr_err("%s: Server Create failed\n", __func__);
1372 return -ENOMEM;
1373 }
1374
1375 if (!msm_ipc_router_lookup_remote_port(
1376 msg->srv.node_id, msg->srv.port_id)) {
1377 rport_ptr = msm_ipc_router_create_remote_port(
1378 msg->srv.node_id, msg->srv.port_id);
1379 if (!rport_ptr)
1380 pr_err("%s: Remote port create "
1381 "failed\n", __func__);
1382 }
1383 wake_up(&newserver_wait);
1384 }
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001385 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001386
1387 relay_msg(xprt_info, pkt);
1388 post_control_ports(pkt);
1389 break;
1390 case IPC_ROUTER_CTRL_CMD_REMOVE_SERVER:
1391 RR("o REMOVE_SERVER service=%08x:%d\n",
1392 msg->srv.service, msg->srv.instance);
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001393 mutex_lock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001394 server = msm_ipc_router_lookup_server(msg->srv.service,
1395 msg->srv.instance,
1396 msg->srv.node_id,
1397 msg->srv.port_id);
1398 if (server) {
1399 msm_ipc_router_destroy_server(server,
1400 msg->srv.node_id,
1401 msg->srv.port_id);
1402 relay_msg(xprt_info, pkt);
1403 post_control_ports(pkt);
1404 }
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001405 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001406 break;
1407 case IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT:
1408 RR("o REMOVE_CLIENT id=%d:%08x\n",
1409 msg->cli.node_id, msg->cli.port_id);
1410 rport_ptr = msm_ipc_router_lookup_remote_port(msg->cli.node_id,
1411 msg->cli.port_id);
1412 if (rport_ptr)
1413 msm_ipc_router_destroy_remote_port(rport_ptr);
1414
1415 relay_msg(xprt_info, pkt);
1416 post_control_ports(pkt);
1417 break;
1418 case IPC_ROUTER_CTRL_CMD_PING:
1419 /* No action needed for ping messages received */
1420 RR("o PING\n");
1421 break;
1422 default:
1423 RR("o UNKNOWN(%08x)\n", msg->cmd);
1424 rc = -ENOSYS;
1425 }
1426
1427 return rc;
1428}
1429
1430static void do_read_data(struct work_struct *work)
1431{
1432 struct rr_header *hdr;
1433 struct rr_packet *pkt = NULL;
1434 struct msm_ipc_port *port_ptr;
1435 struct sk_buff *head_skb;
1436 struct msm_ipc_port_addr *src_addr;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001437 struct msm_ipc_router_remote_port *rport_ptr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001438 uint32_t resume_tx, resume_tx_node_id, resume_tx_port_id;
1439
1440 struct msm_ipc_router_xprt_info *xprt_info =
1441 container_of(work,
1442 struct msm_ipc_router_xprt_info,
1443 read_data);
1444
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001445 while ((pkt = rr_read(xprt_info)) != NULL) {
1446 if (pkt->length < IPC_ROUTER_HDR_SIZE ||
1447 pkt->length > MAX_IPC_PKT_SIZE) {
1448 pr_err("%s: Invalid pkt length %d\n",
1449 __func__, pkt->length);
1450 goto fail_data;
1451 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001452
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001453 head_skb = skb_peek(pkt->pkt_fragment_q);
1454 if (!head_skb) {
1455 pr_err("%s: head_skb is invalid\n", __func__);
1456 goto fail_data;
1457 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001458
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001459 hdr = (struct rr_header *)(head_skb->data);
1460 RR("- ver=%d type=%d src=%d:%08x crx=%d siz=%d dst=%d:%08x\n",
1461 hdr->version, hdr->type, hdr->src_node_id, hdr->src_port_id,
1462 hdr->confirm_rx, hdr->size, hdr->dst_node_id,
1463 hdr->dst_port_id);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001464
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001465 if (hdr->version != IPC_ROUTER_VERSION) {
1466 pr_err("version %d != %d\n",
1467 hdr->version, IPC_ROUTER_VERSION);
1468 goto fail_data;
1469 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001470
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001471 if ((hdr->dst_node_id != IPC_ROUTER_NID_LOCAL) &&
1472 ((hdr->type == IPC_ROUTER_CTRL_CMD_RESUME_TX) ||
1473 (hdr->type == IPC_ROUTER_CTRL_CMD_DATA))) {
1474 forward_msg(xprt_info, pkt);
1475 release_pkt(pkt);
1476 continue;
1477 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001478
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001479 if ((hdr->dst_port_id == IPC_ROUTER_ADDRESS) ||
1480 (hdr->type == IPC_ROUTER_CTRL_CMD_HELLO)) {
1481 process_control_msg(xprt_info, pkt);
1482 release_pkt(pkt);
1483 continue;
1484 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001485#if defined(CONFIG_MSM_SMD_LOGGING)
1486#if defined(DEBUG)
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001487 if (msm_ipc_router_debug_mask & SMEM_LOG) {
1488 smem_log_event((SMEM_LOG_PROC_ID_APPS |
1489 SMEM_LOG_RPC_ROUTER_EVENT_BASE |
1490 IPC_ROUTER_LOG_EVENT_RX),
1491 (hdr->src_node_id << 24) |
1492 (hdr->src_port_id & 0xffffff),
1493 (hdr->dst_node_id << 24) |
1494 (hdr->dst_port_id & 0xffffff),
1495 (hdr->type << 24) | (hdr->confirm_rx << 16) |
1496 (hdr->size & 0xffff));
1497 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001498#endif
1499#endif
1500
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001501 resume_tx = hdr->confirm_rx;
1502 resume_tx_node_id = hdr->dst_node_id;
1503 resume_tx_port_id = hdr->dst_port_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001504
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001505 rport_ptr = msm_ipc_router_lookup_remote_port(hdr->src_node_id,
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06001506 hdr->src_port_id);
1507
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001508 mutex_lock(&local_ports_lock);
1509 port_ptr = msm_ipc_router_lookup_local_port(hdr->dst_port_id);
1510 if (!port_ptr) {
1511 pr_err("%s: No local port id %08x\n", __func__,
1512 hdr->dst_port_id);
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06001513 mutex_unlock(&local_ports_lock);
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001514 release_pkt(pkt);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001515 goto process_done;
1516 }
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001517
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001518 if (!rport_ptr) {
1519 rport_ptr = msm_ipc_router_create_remote_port(
1520 hdr->src_node_id,
1521 hdr->src_port_id);
1522 if (!rport_ptr) {
1523 pr_err("%s: Rmt Prt %08x:%08x create failed\n",
1524 __func__, hdr->src_node_id,
1525 hdr->src_port_id);
1526 mutex_unlock(&local_ports_lock);
1527 goto process_done;
1528 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001529 }
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001530
1531 if (!port_ptr->notify) {
1532 mutex_lock(&port_ptr->port_rx_q_lock);
1533 wake_lock(&port_ptr->port_rx_wake_lock);
1534 list_add_tail(&pkt->list, &port_ptr->port_rx_q);
1535 wake_up(&port_ptr->port_rx_wait_q);
1536 mutex_unlock(&port_ptr->port_rx_q_lock);
1537 mutex_unlock(&local_ports_lock);
1538 } else {
1539 mutex_lock(&port_ptr->port_rx_q_lock);
1540 src_addr = kmalloc(sizeof(struct msm_ipc_port_addr),
1541 GFP_KERNEL);
1542 if (src_addr) {
1543 src_addr->node_id = hdr->src_node_id;
1544 src_addr->port_id = hdr->src_port_id;
1545 }
1546 skb_pull(head_skb, IPC_ROUTER_HDR_SIZE);
1547 mutex_unlock(&local_ports_lock);
1548 port_ptr->notify(MSM_IPC_ROUTER_READ_CB,
1549 pkt->pkt_fragment_q, src_addr, port_ptr->priv);
1550 mutex_unlock(&port_ptr->port_rx_q_lock);
1551 pkt->pkt_fragment_q = NULL;
1552 src_addr = NULL;
1553 release_pkt(pkt);
1554 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001555
1556process_done:
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001557 if (resume_tx) {
1558 union rr_control_msg msg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001559
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001560 msg.cmd = IPC_ROUTER_CTRL_CMD_RESUME_TX;
1561 msg.cli.node_id = resume_tx_node_id;
1562 msg.cli.port_id = resume_tx_port_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001563
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001564 RR("x RESUME_TX id=%d:%08x\n",
1565 msg.cli.node_id, msg.cli.port_id);
1566 msm_ipc_router_send_control_msg(xprt_info, &msg);
1567 }
1568
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001569 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001570 return;
1571
1572fail_data:
1573 release_pkt(pkt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001574 pr_err("ipc_router has died\n");
1575}
1576
1577int msm_ipc_router_register_server(struct msm_ipc_port *port_ptr,
1578 struct msm_ipc_addr *name)
1579{
1580 struct msm_ipc_server *server;
1581 unsigned long flags;
1582 union rr_control_msg ctl;
1583
1584 if (!port_ptr || !name)
1585 return -EINVAL;
1586
1587 if (name->addrtype != MSM_IPC_ADDR_NAME)
1588 return -EINVAL;
1589
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001590 mutex_lock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001591 server = msm_ipc_router_lookup_server(name->addr.port_name.service,
1592 name->addr.port_name.instance,
1593 IPC_ROUTER_NID_LOCAL,
1594 port_ptr->this_port.port_id);
1595 if (server) {
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001596 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001597 pr_err("%s: Server already present\n", __func__);
1598 return -EINVAL;
1599 }
1600
1601 server = msm_ipc_router_create_server(name->addr.port_name.service,
1602 name->addr.port_name.instance,
1603 IPC_ROUTER_NID_LOCAL,
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001604 port_ptr->this_port.port_id,
1605 NULL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001606 if (!server) {
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001607 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001608 pr_err("%s: Server Creation failed\n", __func__);
1609 return -EINVAL;
1610 }
1611
1612 ctl.cmd = IPC_ROUTER_CTRL_CMD_NEW_SERVER;
1613 ctl.srv.service = server->name.service;
1614 ctl.srv.instance = server->name.instance;
1615 ctl.srv.node_id = IPC_ROUTER_NID_LOCAL;
1616 ctl.srv.port_id = port_ptr->this_port.port_id;
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001617 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001618 broadcast_ctl_msg(&ctl);
1619 spin_lock_irqsave(&port_ptr->port_lock, flags);
1620 port_ptr->type = SERVER_PORT;
1621 port_ptr->port_name.service = server->name.service;
1622 port_ptr->port_name.instance = server->name.instance;
1623 spin_unlock_irqrestore(&port_ptr->port_lock, flags);
1624 return 0;
1625}
1626
1627int msm_ipc_router_unregister_server(struct msm_ipc_port *port_ptr)
1628{
1629 struct msm_ipc_server *server;
1630 unsigned long flags;
1631 union rr_control_msg ctl;
1632
1633 if (!port_ptr)
1634 return -EINVAL;
1635
1636 if (port_ptr->type != SERVER_PORT) {
1637 pr_err("%s: Trying to unregister a non-server port\n",
1638 __func__);
1639 return -EINVAL;
1640 }
1641
1642 if (port_ptr->this_port.node_id != IPC_ROUTER_NID_LOCAL) {
1643 pr_err("%s: Trying to unregister a remote server locally\n",
1644 __func__);
1645 return -EINVAL;
1646 }
1647
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001648 mutex_lock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001649 server = msm_ipc_router_lookup_server(port_ptr->port_name.service,
1650 port_ptr->port_name.instance,
1651 port_ptr->this_port.node_id,
1652 port_ptr->this_port.port_id);
1653 if (!server) {
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001654 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001655 pr_err("%s: Server lookup failed\n", __func__);
1656 return -ENODEV;
1657 }
1658
1659 ctl.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_SERVER;
1660 ctl.srv.service = server->name.service;
1661 ctl.srv.instance = server->name.instance;
1662 ctl.srv.node_id = IPC_ROUTER_NID_LOCAL;
1663 ctl.srv.port_id = port_ptr->this_port.port_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001664 msm_ipc_router_destroy_server(server, port_ptr->this_port.node_id,
1665 port_ptr->this_port.port_id);
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001666 mutex_unlock(&server_list_lock);
1667 broadcast_ctl_msg(&ctl);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001668 spin_lock_irqsave(&port_ptr->port_lock, flags);
1669 port_ptr->type = CLIENT_PORT;
1670 spin_unlock_irqrestore(&port_ptr->port_lock, flags);
1671 return 0;
1672}
1673
1674static int loopback_data(struct msm_ipc_port *src,
1675 uint32_t port_id,
1676 struct sk_buff_head *data)
1677{
1678 struct sk_buff *head_skb;
1679 struct rr_header *hdr;
1680 struct msm_ipc_port *port_ptr;
1681 struct rr_packet *pkt;
Karthikeyan Ramasubramanian0a801c12013-02-08 13:07:42 -07001682 int ret_len;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001683
1684 if (!data) {
1685 pr_err("%s: Invalid pkt pointer\n", __func__);
1686 return -EINVAL;
1687 }
1688
1689 pkt = create_pkt(data);
1690 if (!pkt) {
1691 pr_err("%s: New pkt create failed\n", __func__);
1692 return -ENOMEM;
1693 }
1694
1695 head_skb = skb_peek(pkt->pkt_fragment_q);
Karthikeyan Ramasubramanian9024dd82011-12-19 18:44:19 -07001696 if (!head_skb) {
1697 pr_err("%s: pkt_fragment_q is empty\n", __func__);
1698 return -EINVAL;
1699 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001700 hdr = (struct rr_header *)skb_push(head_skb, IPC_ROUTER_HDR_SIZE);
1701 if (!hdr) {
1702 pr_err("%s: Prepend Header failed\n", __func__);
1703 release_pkt(pkt);
1704 return -ENOMEM;
1705 }
1706 hdr->version = IPC_ROUTER_VERSION;
1707 hdr->type = IPC_ROUTER_CTRL_CMD_DATA;
1708 hdr->src_node_id = src->this_port.node_id;
1709 hdr->src_port_id = src->this_port.port_id;
1710 hdr->size = pkt->length;
1711 hdr->confirm_rx = 0;
1712 hdr->dst_node_id = IPC_ROUTER_NID_LOCAL;
1713 hdr->dst_port_id = port_id;
1714 pkt->length += IPC_ROUTER_HDR_SIZE;
1715
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06001716 mutex_lock(&local_ports_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001717 port_ptr = msm_ipc_router_lookup_local_port(port_id);
1718 if (!port_ptr) {
1719 pr_err("%s: Local port %d not present\n", __func__, port_id);
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06001720 mutex_unlock(&local_ports_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001721 release_pkt(pkt);
1722 return -ENODEV;
1723 }
1724
1725 mutex_lock(&port_ptr->port_rx_q_lock);
1726 wake_lock(&port_ptr->port_rx_wake_lock);
1727 list_add_tail(&pkt->list, &port_ptr->port_rx_q);
Karthikeyan Ramasubramanian0a801c12013-02-08 13:07:42 -07001728 ret_len = pkt->length;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001729 wake_up(&port_ptr->port_rx_wait_q);
1730 mutex_unlock(&port_ptr->port_rx_q_lock);
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06001731 mutex_unlock(&local_ports_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001732
Karthikeyan Ramasubramanian0a801c12013-02-08 13:07:42 -07001733 return ret_len;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001734}
1735
1736static int msm_ipc_router_write_pkt(struct msm_ipc_port *src,
1737 struct msm_ipc_router_remote_port *rport_ptr,
1738 struct rr_packet *pkt)
1739{
1740 struct sk_buff *head_skb;
1741 struct rr_header *hdr;
1742 struct msm_ipc_router_xprt_info *xprt_info;
1743 struct msm_ipc_routing_table_entry *rt_entry;
1744 int ret;
1745 DEFINE_WAIT(__wait);
1746
1747 if (!rport_ptr || !src || !pkt)
1748 return -EINVAL;
1749
1750 head_skb = skb_peek(pkt->pkt_fragment_q);
Karthikeyan Ramasubramanian9024dd82011-12-19 18:44:19 -07001751 if (!head_skb) {
1752 pr_err("%s: pkt_fragment_q is empty\n", __func__);
1753 return -EINVAL;
1754 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001755 hdr = (struct rr_header *)skb_push(head_skb, IPC_ROUTER_HDR_SIZE);
1756 if (!hdr) {
1757 pr_err("%s: Prepend Header failed\n", __func__);
1758 return -ENOMEM;
1759 }
1760 hdr->version = IPC_ROUTER_VERSION;
1761 hdr->type = IPC_ROUTER_CTRL_CMD_DATA;
1762 hdr->src_node_id = src->this_port.node_id;
1763 hdr->src_port_id = src->this_port.port_id;
1764 hdr->size = pkt->length;
1765 hdr->confirm_rx = 0;
1766 hdr->dst_node_id = rport_ptr->node_id;
1767 hdr->dst_port_id = rport_ptr->port_id;
1768 pkt->length += IPC_ROUTER_HDR_SIZE;
1769
1770 for (;;) {
1771 prepare_to_wait(&rport_ptr->quota_wait, &__wait,
1772 TASK_INTERRUPTIBLE);
1773 mutex_lock(&rport_ptr->quota_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001774 if (rport_ptr->restart_state != RESTART_NORMAL)
1775 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001776 if (rport_ptr->tx_quota_cnt <
1777 IPC_ROUTER_DEFAULT_RX_QUOTA)
1778 break;
1779 if (signal_pending(current))
1780 break;
1781 mutex_unlock(&rport_ptr->quota_lock);
1782 schedule();
1783 }
1784 finish_wait(&rport_ptr->quota_wait, &__wait);
1785
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001786 if (rport_ptr->restart_state != RESTART_NORMAL) {
1787 mutex_unlock(&rport_ptr->quota_lock);
1788 return -ENETRESET;
1789 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001790 if (signal_pending(current)) {
1791 mutex_unlock(&rport_ptr->quota_lock);
1792 return -ERESTARTSYS;
1793 }
1794 rport_ptr->tx_quota_cnt++;
1795 if (rport_ptr->tx_quota_cnt == IPC_ROUTER_DEFAULT_RX_QUOTA)
1796 hdr->confirm_rx = 1;
1797 mutex_unlock(&rport_ptr->quota_lock);
1798
1799 mutex_lock(&routing_table_lock);
1800 rt_entry = lookup_routing_table(hdr->dst_node_id);
1801 if (!rt_entry || !rt_entry->xprt_info) {
1802 mutex_unlock(&routing_table_lock);
1803 pr_err("%s: Remote node %d not up\n",
1804 __func__, hdr->dst_node_id);
1805 return -ENODEV;
1806 }
1807 mutex_lock(&rt_entry->lock);
1808 xprt_info = rt_entry->xprt_info;
1809 mutex_lock(&xprt_info->tx_lock);
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -07001810 ret = xprt_info->xprt->write(pkt, pkt->length, xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001811 mutex_unlock(&xprt_info->tx_lock);
1812 mutex_unlock(&rt_entry->lock);
1813 mutex_unlock(&routing_table_lock);
1814
1815 if (ret < 0) {
1816 pr_err("%s: Write on XPRT failed\n", __func__);
1817 return ret;
1818 }
1819
1820 RAW_HDR("[w rr_h] "
1821 "ver=%i,type=%s,src_nid=%08x,src_port_id=%08x,"
1822 "confirm_rx=%i,size=%3i,dst_pid=%08x,dst_cid=%08x\n",
1823 hdr->version, type_to_str(hdr->type),
1824 hdr->src_node_id, hdr->src_port_id,
1825 hdr->confirm_rx, hdr->size,
1826 hdr->dst_node_id, hdr->dst_port_id);
1827
1828#if defined(CONFIG_MSM_SMD_LOGGING)
1829#if defined(DEBUG)
1830 if (msm_ipc_router_debug_mask & SMEM_LOG) {
1831 smem_log_event((SMEM_LOG_PROC_ID_APPS |
1832 SMEM_LOG_RPC_ROUTER_EVENT_BASE |
1833 IPC_ROUTER_LOG_EVENT_TX),
1834 (hdr->src_node_id << 24) |
1835 (hdr->src_port_id & 0xffffff),
1836 (hdr->dst_node_id << 24) |
1837 (hdr->dst_port_id & 0xffffff),
1838 (hdr->type << 24) | (hdr->confirm_rx << 16) |
1839 (hdr->size & 0xffff));
1840 }
1841#endif
1842#endif
1843
1844 return pkt->length;
1845}
1846
1847int msm_ipc_router_send_to(struct msm_ipc_port *src,
1848 struct sk_buff_head *data,
1849 struct msm_ipc_addr *dest)
1850{
1851 uint32_t dst_node_id = 0, dst_port_id = 0;
1852 struct msm_ipc_server *server;
1853 struct msm_ipc_server_port *server_port;
1854 struct msm_ipc_router_remote_port *rport_ptr = NULL;
1855 struct rr_packet *pkt;
1856 int ret;
1857
1858 if (!src || !data || !dest) {
1859 pr_err("%s: Invalid Parameters\n", __func__);
1860 return -EINVAL;
1861 }
1862
1863 /* Resolve Address*/
1864 if (dest->addrtype == MSM_IPC_ADDR_ID) {
1865 dst_node_id = dest->addr.port_addr.node_id;
1866 dst_port_id = dest->addr.port_addr.port_id;
1867 } else if (dest->addrtype == MSM_IPC_ADDR_NAME) {
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001868 mutex_lock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001869 server = msm_ipc_router_lookup_server(
1870 dest->addr.port_name.service,
1871 dest->addr.port_name.instance,
1872 0, 0);
1873 if (!server) {
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001874 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001875 pr_err("%s: Destination not reachable\n", __func__);
1876 return -ENODEV;
1877 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001878 server_port = list_first_entry(&server->server_port_list,
1879 struct msm_ipc_server_port,
1880 list);
1881 dst_node_id = server_port->server_addr.node_id;
1882 dst_port_id = server_port->server_addr.port_id;
1883 mutex_unlock(&server_list_lock);
1884 }
1885 if (dst_node_id == IPC_ROUTER_NID_LOCAL) {
1886 ret = loopback_data(src, dst_port_id, data);
1887 return ret;
1888 }
1889
1890 /* Achieve Flow control */
1891 rport_ptr = msm_ipc_router_lookup_remote_port(dst_node_id,
1892 dst_port_id);
1893 if (!rport_ptr) {
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001894 pr_err("%s: Could not create remote port\n", __func__);
1895 return -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001896 }
1897
1898 pkt = create_pkt(data);
1899 if (!pkt) {
1900 pr_err("%s: Pkt creation failed\n", __func__);
1901 return -ENOMEM;
1902 }
1903
1904 ret = msm_ipc_router_write_pkt(src, rport_ptr, pkt);
1905 release_pkt(pkt);
1906
1907 return ret;
1908}
1909
1910int msm_ipc_router_read(struct msm_ipc_port *port_ptr,
1911 struct sk_buff_head **data,
1912 size_t buf_len)
1913{
1914 struct rr_packet *pkt;
1915 int ret;
1916
1917 if (!port_ptr || !data)
1918 return -EINVAL;
1919
1920 mutex_lock(&port_ptr->port_rx_q_lock);
1921 if (list_empty(&port_ptr->port_rx_q)) {
1922 mutex_unlock(&port_ptr->port_rx_q_lock);
1923 return -EAGAIN;
1924 }
1925
1926 pkt = list_first_entry(&port_ptr->port_rx_q, struct rr_packet, list);
1927 if ((buf_len) && ((pkt->length - IPC_ROUTER_HDR_SIZE) > buf_len)) {
1928 mutex_unlock(&port_ptr->port_rx_q_lock);
1929 return -ETOOSMALL;
1930 }
1931 list_del(&pkt->list);
1932 if (list_empty(&port_ptr->port_rx_q))
1933 wake_unlock(&port_ptr->port_rx_wake_lock);
1934 *data = pkt->pkt_fragment_q;
1935 ret = pkt->length;
1936 kfree(pkt);
1937 mutex_unlock(&port_ptr->port_rx_q_lock);
1938
1939 return ret;
1940}
1941
1942int msm_ipc_router_recv_from(struct msm_ipc_port *port_ptr,
1943 struct sk_buff_head **data,
1944 struct msm_ipc_addr *src,
1945 unsigned long timeout)
1946{
1947 int ret, data_len, align_size;
1948 struct sk_buff *temp_skb;
1949 struct rr_header *hdr = NULL;
1950
1951 if (!port_ptr || !data) {
1952 pr_err("%s: Invalid pointers being passed\n", __func__);
1953 return -EINVAL;
1954 }
1955
1956 *data = NULL;
1957 mutex_lock(&port_ptr->port_rx_q_lock);
1958 while (list_empty(&port_ptr->port_rx_q)) {
1959 mutex_unlock(&port_ptr->port_rx_q_lock);
1960 if (timeout < 0) {
1961 ret = wait_event_interruptible(
1962 port_ptr->port_rx_wait_q,
1963 !list_empty(&port_ptr->port_rx_q));
1964 if (ret)
1965 return ret;
1966 } else if (timeout > 0) {
1967 timeout = wait_event_interruptible_timeout(
1968 port_ptr->port_rx_wait_q,
1969 !list_empty(&port_ptr->port_rx_q),
1970 timeout);
1971 if (timeout < 0)
1972 return -EFAULT;
1973 }
1974 if (timeout == 0)
1975 return -ETIMEDOUT;
1976 mutex_lock(&port_ptr->port_rx_q_lock);
1977 }
1978 mutex_unlock(&port_ptr->port_rx_q_lock);
1979
1980 ret = msm_ipc_router_read(port_ptr, data, 0);
1981 if (ret <= 0 || !(*data))
1982 return ret;
1983
1984 temp_skb = skb_peek(*data);
1985 hdr = (struct rr_header *)(temp_skb->data);
1986 if (src) {
1987 src->addrtype = MSM_IPC_ADDR_ID;
1988 src->addr.port_addr.node_id = hdr->src_node_id;
1989 src->addr.port_addr.port_id = hdr->src_port_id;
1990 }
1991
1992 data_len = hdr->size;
1993 skb_pull(temp_skb, IPC_ROUTER_HDR_SIZE);
1994 align_size = ALIGN_SIZE(data_len);
1995 if (align_size) {
1996 temp_skb = skb_peek_tail(*data);
1997 skb_trim(temp_skb, (temp_skb->len - align_size));
1998 }
1999 return data_len;
2000}
2001
2002struct msm_ipc_port *msm_ipc_router_create_port(
2003 void (*notify)(unsigned event, void *data, void *addr, void *priv),
2004 void *priv)
2005{
2006 struct msm_ipc_port *port_ptr;
2007
2008 port_ptr = msm_ipc_router_create_raw_port(NULL, notify, priv);
2009 if (!port_ptr)
2010 pr_err("%s: port_ptr alloc failed\n", __func__);
2011
2012 return port_ptr;
2013}
2014
2015int msm_ipc_router_close_port(struct msm_ipc_port *port_ptr)
2016{
2017 union rr_control_msg msg;
2018 struct rr_packet *pkt, *temp_pkt;
2019 struct msm_ipc_server *server;
2020
2021 if (!port_ptr)
2022 return -EINVAL;
2023
2024 if (port_ptr->type == SERVER_PORT || port_ptr->type == CLIENT_PORT) {
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06002025 mutex_lock(&local_ports_lock);
2026 list_del(&port_ptr->list);
2027 mutex_unlock(&local_ports_lock);
2028
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002029 if (port_ptr->type == SERVER_PORT) {
2030 msg.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_SERVER;
2031 msg.srv.service = port_ptr->port_name.service;
2032 msg.srv.instance = port_ptr->port_name.instance;
2033 msg.srv.node_id = port_ptr->this_port.node_id;
2034 msg.srv.port_id = port_ptr->this_port.port_id;
2035 RR("x REMOVE_SERVER Name=%d:%08x Id=%d:%08x\n",
2036 msg.srv.service, msg.srv.instance,
2037 msg.srv.node_id, msg.srv.port_id);
Karthikeyan Ramasubramanian25e91872013-01-10 17:09:13 -07002038 broadcast_ctl_msg(&msg);
2039 broadcast_ctl_msg_locally(&msg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002040 }
Karthikeyan Ramasubramanian25e91872013-01-10 17:09:13 -07002041
2042 /*
2043 * Server port could have been a client port earlier.
2044 * Send REMOVE_CLIENT message in either case.
2045 */
2046 msg.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT;
2047 msg.cli.node_id = port_ptr->this_port.node_id;
2048 msg.cli.port_id = port_ptr->this_port.port_id;
2049 RR("x REMOVE_CLIENT id=%d:%08x\n",
2050 msg.cli.node_id, msg.cli.port_id);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002051 broadcast_ctl_msg(&msg);
2052 broadcast_ctl_msg_locally(&msg);
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06002053 } else if (port_ptr->type == CONTROL_PORT) {
2054 mutex_lock(&control_ports_lock);
2055 list_del(&port_ptr->list);
2056 mutex_unlock(&control_ports_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002057 }
2058
2059 mutex_lock(&port_ptr->port_rx_q_lock);
2060 list_for_each_entry_safe(pkt, temp_pkt, &port_ptr->port_rx_q, list) {
2061 list_del(&pkt->list);
2062 release_pkt(pkt);
2063 }
2064 mutex_unlock(&port_ptr->port_rx_q_lock);
2065
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002066 if (port_ptr->type == SERVER_PORT) {
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002067 mutex_lock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002068 server = msm_ipc_router_lookup_server(
2069 port_ptr->port_name.service,
2070 port_ptr->port_name.instance,
2071 port_ptr->this_port.node_id,
2072 port_ptr->this_port.port_id);
2073 if (server)
2074 msm_ipc_router_destroy_server(server,
2075 port_ptr->this_port.node_id,
2076 port_ptr->this_port.port_id);
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002077 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002078 }
2079
Karthikeyan Ramasubramaniandd8c3b52011-11-30 16:26:12 -07002080 wake_lock_destroy(&port_ptr->port_rx_wake_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002081 kfree(port_ptr);
2082 return 0;
2083}
2084
2085int msm_ipc_router_get_curr_pkt_size(struct msm_ipc_port *port_ptr)
2086{
2087 struct rr_packet *pkt;
2088 int rc = 0;
2089
2090 if (!port_ptr)
2091 return -EINVAL;
2092
2093 mutex_lock(&port_ptr->port_rx_q_lock);
2094 if (!list_empty(&port_ptr->port_rx_q)) {
2095 pkt = list_first_entry(&port_ptr->port_rx_q,
2096 struct rr_packet, list);
2097 rc = pkt->length;
2098 }
2099 mutex_unlock(&port_ptr->port_rx_q_lock);
2100
2101 return rc;
2102}
2103
2104int msm_ipc_router_bind_control_port(struct msm_ipc_port *port_ptr)
2105{
2106 if (!port_ptr)
2107 return -EINVAL;
2108
2109 mutex_lock(&local_ports_lock);
2110 list_del(&port_ptr->list);
2111 mutex_unlock(&local_ports_lock);
2112 port_ptr->type = CONTROL_PORT;
2113 mutex_lock(&control_ports_lock);
2114 list_add_tail(&port_ptr->list, &control_ports);
2115 mutex_unlock(&control_ports_lock);
2116
2117 return 0;
2118}
2119
2120int msm_ipc_router_lookup_server_name(struct msm_ipc_port_name *srv_name,
Karthikeyan Ramasubramaniandfde01b2012-06-12 14:25:13 -06002121 struct msm_ipc_server_info *srv_info,
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002122 int num_entries_in_array,
2123 uint32_t lookup_mask)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002124{
2125 struct msm_ipc_server *server;
2126 struct msm_ipc_server_port *server_port;
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002127 int key, i = 0; /*num_entries_found*/
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002128
2129 if (!srv_name) {
2130 pr_err("%s: Invalid srv_name\n", __func__);
2131 return -EINVAL;
2132 }
2133
Karthikeyan Ramasubramaniandfde01b2012-06-12 14:25:13 -06002134 if (num_entries_in_array && !srv_info) {
2135 pr_err("%s: srv_info NULL\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002136 return -EINVAL;
2137 }
2138
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002139 mutex_lock(&server_list_lock);
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002140 if (!lookup_mask)
2141 lookup_mask = 0xFFFFFFFF;
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002142 key = (srv_name->service & (SRV_HASH_SIZE - 1));
2143 list_for_each_entry(server, &server_list[key], list) {
2144 if ((server->name.service != srv_name->service) ||
2145 ((server->name.instance & lookup_mask) !=
2146 srv_name->instance))
2147 continue;
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002148
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002149 list_for_each_entry(server_port,
2150 &server->server_port_list, list) {
2151 if (i < num_entries_in_array) {
2152 srv_info[i].node_id =
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002153 server_port->server_addr.node_id;
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002154 srv_info[i].port_id =
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002155 server_port->server_addr.port_id;
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002156 srv_info[i].service = server->name.service;
2157 srv_info[i].instance = server->name.instance;
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002158 }
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002159 i++;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002160 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002161 }
2162 mutex_unlock(&server_list_lock);
2163
2164 return i;
2165}
2166
2167int msm_ipc_router_close(void)
2168{
2169 struct msm_ipc_router_xprt_info *xprt_info, *tmp_xprt_info;
2170
2171 mutex_lock(&xprt_info_list_lock);
2172 list_for_each_entry_safe(xprt_info, tmp_xprt_info,
2173 &xprt_info_list, list) {
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -07002174 xprt_info->xprt->close(xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002175 list_del(&xprt_info->list);
2176 kfree(xprt_info);
2177 }
2178 mutex_unlock(&xprt_info_list_lock);
2179 return 0;
2180}
2181
2182#if defined(CONFIG_DEBUG_FS)
2183static int dump_routing_table(char *buf, int max)
2184{
2185 int i = 0, j;
2186 struct msm_ipc_routing_table_entry *rt_entry;
2187
2188 for (j = 0; j < RT_HASH_SIZE; j++) {
2189 mutex_lock(&routing_table_lock);
2190 list_for_each_entry(rt_entry, &routing_table[j], list) {
2191 mutex_lock(&rt_entry->lock);
2192 i += scnprintf(buf + i, max - i,
2193 "Node Id: 0x%08x\n", rt_entry->node_id);
Karthikeyan Ramasubramanianc1a4e3a2012-09-10 16:10:24 -06002194 if (rt_entry->node_id == IPC_ROUTER_NID_LOCAL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002195 i += scnprintf(buf + i, max - i,
2196 "XPRT Name: Loopback\n");
2197 i += scnprintf(buf + i, max - i,
2198 "Next Hop: %d\n", rt_entry->node_id);
2199 } else {
2200 i += scnprintf(buf + i, max - i,
2201 "XPRT Name: %s\n",
2202 rt_entry->xprt_info->xprt->name);
2203 i += scnprintf(buf + i, max - i,
2204 "Next Hop: 0x%08x\n",
2205 rt_entry->xprt_info->remote_node_id);
2206 }
2207 i += scnprintf(buf + i, max - i, "\n");
2208 mutex_unlock(&rt_entry->lock);
2209 }
2210 mutex_unlock(&routing_table_lock);
2211 }
2212
2213 return i;
2214}
2215
2216static int dump_xprt_info(char *buf, int max)
2217{
2218 int i = 0;
2219 struct msm_ipc_router_xprt_info *xprt_info;
2220
2221 mutex_lock(&xprt_info_list_lock);
2222 list_for_each_entry(xprt_info, &xprt_info_list, list) {
2223 i += scnprintf(buf + i, max - i, "XPRT Name: %s\n",
2224 xprt_info->xprt->name);
2225 i += scnprintf(buf + i, max - i, "Link Id: %d\n",
2226 xprt_info->xprt->link_id);
2227 i += scnprintf(buf + i, max - i, "Initialized: %s\n",
2228 (xprt_info->initialized ? "Y" : "N"));
2229 i += scnprintf(buf + i, max - i, "Remote Node Id: 0x%08x\n",
2230 xprt_info->remote_node_id);
2231 i += scnprintf(buf + i, max - i, "\n");
2232 }
2233 mutex_unlock(&xprt_info_list_lock);
2234
2235 return i;
2236}
2237
2238static int dump_servers(char *buf, int max)
2239{
2240 int i = 0, j;
2241 struct msm_ipc_server *server;
2242 struct msm_ipc_server_port *server_port;
2243
2244 mutex_lock(&server_list_lock);
2245 for (j = 0; j < SRV_HASH_SIZE; j++) {
2246 list_for_each_entry(server, &server_list[j], list) {
2247 list_for_each_entry(server_port,
2248 &server->server_port_list,
2249 list) {
2250 i += scnprintf(buf + i, max - i, "Service: "
2251 "0x%08x\n", server->name.service);
2252 i += scnprintf(buf + i, max - i, "Instance: "
2253 "0x%08x\n", server->name.instance);
2254 i += scnprintf(buf + i, max - i,
2255 "Node_id: 0x%08x\n",
2256 server_port->server_addr.node_id);
2257 i += scnprintf(buf + i, max - i,
2258 "Port_id: 0x%08x\n",
2259 server_port->server_addr.port_id);
2260 i += scnprintf(buf + i, max - i, "\n");
2261 }
2262 }
2263 }
2264 mutex_unlock(&server_list_lock);
2265
2266 return i;
2267}
2268
2269static int dump_remote_ports(char *buf, int max)
2270{
2271 int i = 0, j, k;
2272 struct msm_ipc_router_remote_port *rport_ptr;
2273 struct msm_ipc_routing_table_entry *rt_entry;
2274
2275 for (j = 0; j < RT_HASH_SIZE; j++) {
2276 mutex_lock(&routing_table_lock);
2277 list_for_each_entry(rt_entry, &routing_table[j], list) {
2278 mutex_lock(&rt_entry->lock);
2279 for (k = 0; k < RP_HASH_SIZE; k++) {
2280 list_for_each_entry(rport_ptr,
2281 &rt_entry->remote_port_list[k],
2282 list) {
2283 i += scnprintf(buf + i, max - i,
2284 "Node_id: 0x%08x\n",
2285 rport_ptr->node_id);
2286 i += scnprintf(buf + i, max - i,
2287 "Port_id: 0x%08x\n",
2288 rport_ptr->port_id);
2289 i += scnprintf(buf + i, max - i,
2290 "Quota_cnt: %d\n",
2291 rport_ptr->tx_quota_cnt);
2292 i += scnprintf(buf + i, max - i, "\n");
2293 }
2294 }
2295 mutex_unlock(&rt_entry->lock);
2296 }
2297 mutex_unlock(&routing_table_lock);
2298 }
2299
2300 return i;
2301}
2302
2303static int dump_control_ports(char *buf, int max)
2304{
2305 int i = 0;
2306 struct msm_ipc_port *port_ptr;
2307
2308 mutex_lock(&control_ports_lock);
2309 list_for_each_entry(port_ptr, &control_ports, list) {
2310 i += scnprintf(buf + i, max - i, "Node_id: 0x%08x\n",
2311 port_ptr->this_port.node_id);
2312 i += scnprintf(buf + i, max - i, "Port_id: 0x%08x\n",
2313 port_ptr->this_port.port_id);
2314 i += scnprintf(buf + i, max - i, "\n");
2315 }
2316 mutex_unlock(&control_ports_lock);
2317
2318 return i;
2319}
2320
2321static int dump_local_ports(char *buf, int max)
2322{
2323 int i = 0, j;
2324 unsigned long flags;
2325 struct msm_ipc_port *port_ptr;
2326
2327 mutex_lock(&local_ports_lock);
2328 for (j = 0; j < LP_HASH_SIZE; j++) {
2329 list_for_each_entry(port_ptr, &local_ports[j], list) {
2330 spin_lock_irqsave(&port_ptr->port_lock, flags);
2331 i += scnprintf(buf + i, max - i, "Node_id: 0x%08x\n",
2332 port_ptr->this_port.node_id);
2333 i += scnprintf(buf + i, max - i, "Port_id: 0x%08x\n",
2334 port_ptr->this_port.port_id);
2335 i += scnprintf(buf + i, max - i, "# pkts tx'd %d\n",
2336 port_ptr->num_tx);
2337 i += scnprintf(buf + i, max - i, "# pkts rx'd %d\n",
2338 port_ptr->num_rx);
2339 i += scnprintf(buf + i, max - i, "# bytes tx'd %ld\n",
2340 port_ptr->num_tx_bytes);
2341 i += scnprintf(buf + i, max - i, "# bytes rx'd %ld\n",
2342 port_ptr->num_rx_bytes);
2343 spin_unlock_irqrestore(&port_ptr->port_lock, flags);
2344 i += scnprintf(buf + i, max - i, "\n");
2345 }
2346 }
2347 mutex_unlock(&local_ports_lock);
2348
2349 return i;
2350}
2351
2352#define DEBUG_BUFMAX 4096
2353static char debug_buffer[DEBUG_BUFMAX];
2354
2355static ssize_t debug_read(struct file *file, char __user *buf,
2356 size_t count, loff_t *ppos)
2357{
2358 int (*fill)(char *buf, int max) = file->private_data;
2359 int bsize = fill(debug_buffer, DEBUG_BUFMAX);
2360 return simple_read_from_buffer(buf, count, ppos, debug_buffer, bsize);
2361}
2362
2363static int debug_open(struct inode *inode, struct file *file)
2364{
2365 file->private_data = inode->i_private;
2366 return 0;
2367}
2368
2369static const struct file_operations debug_ops = {
2370 .read = debug_read,
2371 .open = debug_open,
2372};
2373
2374static void debug_create(const char *name, mode_t mode,
2375 struct dentry *dent,
2376 int (*fill)(char *buf, int max))
2377{
2378 debugfs_create_file(name, mode, dent, fill, &debug_ops);
2379}
2380
2381static void debugfs_init(void)
2382{
2383 struct dentry *dent;
2384
2385 dent = debugfs_create_dir("msm_ipc_router", 0);
2386 if (IS_ERR(dent))
2387 return;
2388
2389 debug_create("dump_local_ports", 0444, dent,
2390 dump_local_ports);
2391 debug_create("dump_remote_ports", 0444, dent,
2392 dump_remote_ports);
2393 debug_create("dump_control_ports", 0444, dent,
2394 dump_control_ports);
2395 debug_create("dump_servers", 0444, dent,
2396 dump_servers);
2397 debug_create("dump_xprt_info", 0444, dent,
2398 dump_xprt_info);
2399 debug_create("dump_routing_table", 0444, dent,
2400 dump_routing_table);
2401}
2402
2403#else
2404static void debugfs_init(void) {}
2405#endif
2406
2407static int msm_ipc_router_add_xprt(struct msm_ipc_router_xprt *xprt)
2408{
2409 struct msm_ipc_router_xprt_info *xprt_info;
2410 struct msm_ipc_routing_table_entry *rt_entry;
2411
2412 xprt_info = kmalloc(sizeof(struct msm_ipc_router_xprt_info),
2413 GFP_KERNEL);
2414 if (!xprt_info)
2415 return -ENOMEM;
2416
2417 xprt_info->xprt = xprt;
2418 xprt_info->initialized = 0;
2419 xprt_info->remote_node_id = -1;
2420 INIT_LIST_HEAD(&xprt_info->pkt_list);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002421 mutex_init(&xprt_info->rx_lock);
2422 mutex_init(&xprt_info->tx_lock);
2423 wake_lock_init(&xprt_info->wakelock,
2424 WAKE_LOCK_SUSPEND, xprt->name);
2425 xprt_info->need_len = 0;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002426 xprt_info->abort_data_read = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002427 INIT_WORK(&xprt_info->read_data, do_read_data);
2428 INIT_LIST_HEAD(&xprt_info->list);
2429
2430 xprt_info->workqueue = create_singlethread_workqueue(xprt->name);
2431 if (!xprt_info->workqueue) {
2432 kfree(xprt_info);
2433 return -ENOMEM;
2434 }
2435
2436 if (!strcmp(xprt->name, "msm_ipc_router_loopback_xprt")) {
2437 xprt_info->remote_node_id = IPC_ROUTER_NID_LOCAL;
2438 xprt_info->initialized = 1;
2439 }
2440
2441 mutex_lock(&xprt_info_list_lock);
2442 list_add_tail(&xprt_info->list, &xprt_info_list);
2443 mutex_unlock(&xprt_info_list_lock);
2444
2445 mutex_lock(&routing_table_lock);
2446 if (!routing_table_inited) {
2447 init_routing_table();
2448 rt_entry = alloc_routing_table_entry(IPC_ROUTER_NID_LOCAL);
2449 add_routing_table_entry(rt_entry);
2450 routing_table_inited = 1;
2451 }
2452 mutex_unlock(&routing_table_lock);
2453
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002454 xprt->priv = xprt_info;
2455
2456 return 0;
2457}
2458
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002459static void msm_ipc_router_remove_xprt(struct msm_ipc_router_xprt *xprt)
2460{
2461 struct msm_ipc_router_xprt_info *xprt_info;
2462
2463 if (xprt && xprt->priv) {
2464 xprt_info = xprt->priv;
2465
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06002466 mutex_lock(&xprt_info->rx_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002467 xprt_info->abort_data_read = 1;
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06002468 mutex_unlock(&xprt_info->rx_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002469
2470 mutex_lock(&xprt_info_list_lock);
2471 list_del(&xprt_info->list);
2472 mutex_unlock(&xprt_info_list_lock);
2473
2474 flush_workqueue(xprt_info->workqueue);
2475 destroy_workqueue(xprt_info->workqueue);
2476 wake_lock_destroy(&xprt_info->wakelock);
2477
2478 xprt->priv = 0;
2479 kfree(xprt_info);
2480 }
2481}
2482
2483
2484struct msm_ipc_router_xprt_work {
2485 struct msm_ipc_router_xprt *xprt;
2486 struct work_struct work;
2487};
2488
2489static void xprt_open_worker(struct work_struct *work)
2490{
2491 struct msm_ipc_router_xprt_work *xprt_work =
2492 container_of(work, struct msm_ipc_router_xprt_work, work);
2493
2494 msm_ipc_router_add_xprt(xprt_work->xprt);
2495 kfree(xprt_work);
2496}
2497
2498static void xprt_close_worker(struct work_struct *work)
2499{
2500 struct msm_ipc_router_xprt_work *xprt_work =
2501 container_of(work, struct msm_ipc_router_xprt_work, work);
2502
2503 modem_reset_cleanup(xprt_work->xprt->priv);
2504 msm_ipc_router_remove_xprt(xprt_work->xprt);
2505
2506 if (atomic_dec_return(&pending_close_count) == 0)
2507 wake_up(&subsystem_restart_wait);
2508
2509 kfree(xprt_work);
2510}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002511
2512void msm_ipc_router_xprt_notify(struct msm_ipc_router_xprt *xprt,
2513 unsigned event,
2514 void *data)
2515{
2516 struct msm_ipc_router_xprt_info *xprt_info = xprt->priv;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002517 struct msm_ipc_router_xprt_work *xprt_work;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002518 struct rr_packet *pkt;
Karthikeyan Ramasubramanian4af9f7c2011-09-30 15:55:18 -06002519 unsigned long ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002520
Karthikeyan Ramasubramanian4af9f7c2011-09-30 15:55:18 -06002521 if (!msm_ipc_router_workqueue) {
2522 ret = wait_for_completion_timeout(&msm_ipc_local_router_up,
2523 IPC_ROUTER_INIT_TIMEOUT);
2524 if (!ret || !msm_ipc_router_workqueue) {
2525 pr_err("%s: IPC Router not initialized\n", __func__);
2526 return;
2527 }
2528 }
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002529
2530 switch (event) {
2531 case IPC_ROUTER_XPRT_EVENT_OPEN:
2532 D("open event for '%s'\n", xprt->name);
2533 xprt_work = kmalloc(sizeof(struct msm_ipc_router_xprt_work),
2534 GFP_ATOMIC);
2535 xprt_work->xprt = xprt;
2536 INIT_WORK(&xprt_work->work, xprt_open_worker);
2537 queue_work(msm_ipc_router_workqueue, &xprt_work->work);
2538 break;
2539
2540 case IPC_ROUTER_XPRT_EVENT_CLOSE:
2541 D("close event for '%s'\n", xprt->name);
2542 atomic_inc(&pending_close_count);
2543 xprt_work = kmalloc(sizeof(struct msm_ipc_router_xprt_work),
2544 GFP_ATOMIC);
2545 xprt_work->xprt = xprt;
2546 INIT_WORK(&xprt_work->work, xprt_close_worker);
2547 queue_work(msm_ipc_router_workqueue, &xprt_work->work);
2548 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002549 }
2550
2551 if (!data)
2552 return;
2553
2554 while (!xprt_info) {
2555 msleep(100);
2556 xprt_info = xprt->priv;
2557 }
2558
2559 pkt = clone_pkt((struct rr_packet *)data);
2560 if (!pkt)
2561 return;
2562
2563 mutex_lock(&xprt_info->rx_lock);
2564 list_add_tail(&pkt->list, &xprt_info->pkt_list);
2565 wake_lock(&xprt_info->wakelock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002566 mutex_unlock(&xprt_info->rx_lock);
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06002567 queue_work(xprt_info->workqueue, &xprt_info->read_data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002568}
2569
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002570static int modem_restart_notifier_cb(struct notifier_block *this,
2571 unsigned long code,
2572 void *data);
2573static struct notifier_block msm_ipc_router_nb = {
2574 .notifier_call = modem_restart_notifier_cb,
2575};
2576
2577static int modem_restart_notifier_cb(struct notifier_block *this,
2578 unsigned long code,
2579 void *data)
2580{
2581 switch (code) {
2582 case SUBSYS_BEFORE_SHUTDOWN:
2583 D("%s: SUBSYS_BEFORE_SHUTDOWN\n", __func__);
2584 break;
2585
2586 case SUBSYS_BEFORE_POWERUP:
2587 D("%s: waiting for RPC restart to complete\n", __func__);
2588 wait_event(subsystem_restart_wait,
2589 atomic_read(&pending_close_count) == 0);
2590 D("%s: finished restart wait\n", __func__);
2591 break;
2592
2593 default:
2594 break;
2595 }
2596
2597 return NOTIFY_DONE;
2598}
2599
2600static void *restart_notifier_handle;
2601static __init int msm_ipc_router_modem_restart_late_init(void)
2602{
2603 restart_notifier_handle = subsys_notif_register_notifier("modem",
2604 &msm_ipc_router_nb);
2605 return 0;
2606}
2607late_initcall(msm_ipc_router_modem_restart_late_init);
2608
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002609static int __init msm_ipc_router_init(void)
2610{
2611 int i, ret;
2612 struct msm_ipc_routing_table_entry *rt_entry;
2613
2614 msm_ipc_router_debug_mask |= SMEM_LOG;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002615 msm_ipc_router_workqueue =
2616 create_singlethread_workqueue("msm_ipc_router");
2617 if (!msm_ipc_router_workqueue)
2618 return -ENOMEM;
2619
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002620 debugfs_init();
2621
2622 for (i = 0; i < SRV_HASH_SIZE; i++)
2623 INIT_LIST_HEAD(&server_list[i]);
2624
2625 for (i = 0; i < LP_HASH_SIZE; i++)
2626 INIT_LIST_HEAD(&local_ports[i]);
2627
2628 mutex_lock(&routing_table_lock);
2629 if (!routing_table_inited) {
2630 init_routing_table();
2631 rt_entry = alloc_routing_table_entry(IPC_ROUTER_NID_LOCAL);
2632 add_routing_table_entry(rt_entry);
2633 routing_table_inited = 1;
2634 }
2635 mutex_unlock(&routing_table_lock);
2636
2637 init_waitqueue_head(&newserver_wait);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002638 init_waitqueue_head(&subsystem_restart_wait);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002639 ret = msm_ipc_router_init_sockets();
2640 if (ret < 0)
2641 pr_err("%s: Init sockets failed\n", __func__);
2642
Karthikeyan Ramasubramanian4af9f7c2011-09-30 15:55:18 -06002643 complete_all(&msm_ipc_local_router_up);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002644 return ret;
2645}
2646
2647module_init(msm_ipc_router_init);
2648MODULE_DESCRIPTION("MSM IPC Router");
2649MODULE_LICENSE("GPL v2");