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