blob: 97d1f5dc17a81329ae9afefbd3563e2348762cd1 [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 {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700197 DOWN,
198 UP,
199};
200
201static void init_routing_table(void)
202{
203 int i;
204 for (i = 0; i < RT_HASH_SIZE; i++)
205 INIT_LIST_HEAD(&routing_table[i]);
206}
207
208static struct msm_ipc_routing_table_entry *alloc_routing_table_entry(
209 uint32_t node_id)
210{
211 int i;
212 struct msm_ipc_routing_table_entry *rt_entry;
213
214 rt_entry = kmalloc(sizeof(struct msm_ipc_routing_table_entry),
215 GFP_KERNEL);
216 if (!rt_entry) {
217 pr_err("%s: rt_entry allocation failed for %d\n",
218 __func__, node_id);
219 return NULL;
220 }
221
222 for (i = 0; i < RP_HASH_SIZE; i++)
223 INIT_LIST_HEAD(&rt_entry->remote_port_list[i]);
224
225 mutex_init(&rt_entry->lock);
226 rt_entry->node_id = node_id;
227 rt_entry->xprt_info = NULL;
228 return rt_entry;
229}
230
231/*Please take routing_table_lock before calling this function*/
232static int add_routing_table_entry(
233 struct msm_ipc_routing_table_entry *rt_entry)
234{
235 uint32_t key;
236
237 if (!rt_entry)
238 return -EINVAL;
239
240 key = (rt_entry->node_id % RT_HASH_SIZE);
241 list_add_tail(&rt_entry->list, &routing_table[key]);
242 return 0;
243}
244
245/*Please take routing_table_lock before calling this function*/
246static struct msm_ipc_routing_table_entry *lookup_routing_table(
247 uint32_t node_id)
248{
249 uint32_t key = (node_id % RT_HASH_SIZE);
250 struct msm_ipc_routing_table_entry *rt_entry;
251
252 list_for_each_entry(rt_entry, &routing_table[key], list) {
253 if (rt_entry->node_id == node_id)
254 return rt_entry;
255 }
256 return NULL;
257}
258
259struct rr_packet *rr_read(struct msm_ipc_router_xprt_info *xprt_info)
260{
261 struct rr_packet *temp_pkt;
262
263 if (!xprt_info)
264 return NULL;
265
266 mutex_lock(&xprt_info->rx_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600267 if (xprt_info->abort_data_read) {
268 mutex_unlock(&xprt_info->rx_lock);
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -0600269 pr_err("%s detected SSR & exiting now\n",
270 xprt_info->xprt->name);
271 return NULL;
272 }
273
274 if (list_empty(&xprt_info->pkt_list)) {
275 mutex_unlock(&xprt_info->rx_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600276 return NULL;
277 }
278
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700279 temp_pkt = list_first_entry(&xprt_info->pkt_list,
280 struct rr_packet, list);
281 list_del(&temp_pkt->list);
282 if (list_empty(&xprt_info->pkt_list))
283 wake_unlock(&xprt_info->wakelock);
284 mutex_unlock(&xprt_info->rx_lock);
285 return temp_pkt;
286}
287
288struct rr_packet *clone_pkt(struct rr_packet *pkt)
289{
290 struct rr_packet *cloned_pkt;
291 struct sk_buff *temp_skb, *cloned_skb;
292 struct sk_buff_head *pkt_fragment_q;
293
294 cloned_pkt = kzalloc(sizeof(struct rr_packet), GFP_KERNEL);
295 if (!cloned_pkt) {
296 pr_err("%s: failure\n", __func__);
297 return NULL;
298 }
299
300 pkt_fragment_q = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
301 if (!pkt_fragment_q) {
302 pr_err("%s: pkt_frag_q alloc failure\n", __func__);
303 kfree(cloned_pkt);
304 return NULL;
305 }
306 skb_queue_head_init(pkt_fragment_q);
307
308 skb_queue_walk(pkt->pkt_fragment_q, temp_skb) {
309 cloned_skb = skb_clone(temp_skb, GFP_KERNEL);
310 if (!cloned_skb)
311 goto fail_clone;
312 skb_queue_tail(pkt_fragment_q, cloned_skb);
313 }
314 cloned_pkt->pkt_fragment_q = pkt_fragment_q;
315 cloned_pkt->length = pkt->length;
316 return cloned_pkt;
317
318fail_clone:
319 while (!skb_queue_empty(pkt_fragment_q)) {
320 temp_skb = skb_dequeue(pkt_fragment_q);
321 kfree_skb(temp_skb);
322 }
323 kfree(pkt_fragment_q);
324 kfree(cloned_pkt);
325 return NULL;
326}
327
328struct rr_packet *create_pkt(struct sk_buff_head *data)
329{
330 struct rr_packet *pkt;
331 struct sk_buff *temp_skb;
332
333 pkt = kzalloc(sizeof(struct rr_packet), GFP_KERNEL);
334 if (!pkt) {
335 pr_err("%s: failure\n", __func__);
336 return NULL;
337 }
338
339 pkt->pkt_fragment_q = data;
340 skb_queue_walk(pkt->pkt_fragment_q, temp_skb)
341 pkt->length += temp_skb->len;
342 return pkt;
343}
344
345void release_pkt(struct rr_packet *pkt)
346{
347 struct sk_buff *temp_skb;
348
349 if (!pkt)
350 return;
351
352 if (!pkt->pkt_fragment_q) {
353 kfree(pkt);
354 return;
355 }
356
357 while (!skb_queue_empty(pkt->pkt_fragment_q)) {
358 temp_skb = skb_dequeue(pkt->pkt_fragment_q);
359 kfree_skb(temp_skb);
360 }
361 kfree(pkt->pkt_fragment_q);
362 kfree(pkt);
363 return;
364}
365
366static int post_control_ports(struct rr_packet *pkt)
367{
368 struct msm_ipc_port *port_ptr;
369 struct rr_packet *cloned_pkt;
370
371 if (!pkt)
372 return -EINVAL;
373
374 mutex_lock(&control_ports_lock);
375 list_for_each_entry(port_ptr, &control_ports, list) {
376 mutex_lock(&port_ptr->port_rx_q_lock);
377 cloned_pkt = clone_pkt(pkt);
378 wake_lock(&port_ptr->port_rx_wake_lock);
379 list_add_tail(&cloned_pkt->list, &port_ptr->port_rx_q);
380 wake_up(&port_ptr->port_rx_wait_q);
381 mutex_unlock(&port_ptr->port_rx_q_lock);
382 }
383 mutex_unlock(&control_ports_lock);
384 return 0;
385}
386
387static uint32_t allocate_port_id(void)
388{
389 uint32_t port_id = 0, prev_port_id, key;
390 struct msm_ipc_port *port_ptr;
391
392 mutex_lock(&next_port_id_lock);
393 prev_port_id = next_port_id;
394 mutex_lock(&local_ports_lock);
395 do {
396 next_port_id++;
397 if ((next_port_id & 0xFFFFFFFE) == 0xFFFFFFFE)
398 next_port_id = 1;
399
400 key = (next_port_id & (LP_HASH_SIZE - 1));
401 if (list_empty(&local_ports[key])) {
402 port_id = next_port_id;
403 break;
404 }
405 list_for_each_entry(port_ptr, &local_ports[key], list) {
406 if (port_ptr->this_port.port_id == next_port_id) {
407 port_id = next_port_id;
408 break;
409 }
410 }
411 if (!port_id) {
412 port_id = next_port_id;
413 break;
414 }
415 port_id = 0;
416 } while (next_port_id != prev_port_id);
417 mutex_unlock(&local_ports_lock);
418 mutex_unlock(&next_port_id_lock);
419
420 return port_id;
421}
422
423void msm_ipc_router_add_local_port(struct msm_ipc_port *port_ptr)
424{
425 uint32_t key;
426
427 if (!port_ptr)
428 return;
429
430 key = (port_ptr->this_port.port_id & (LP_HASH_SIZE - 1));
431 mutex_lock(&local_ports_lock);
432 list_add_tail(&port_ptr->list, &local_ports[key]);
433 mutex_unlock(&local_ports_lock);
434}
435
436struct msm_ipc_port *msm_ipc_router_create_raw_port(void *endpoint,
437 void (*notify)(unsigned event, void *data,
438 void *addr, void *priv),
439 void *priv)
440{
441 struct msm_ipc_port *port_ptr;
442
443 port_ptr = kzalloc(sizeof(struct msm_ipc_port), GFP_KERNEL);
444 if (!port_ptr)
445 return NULL;
446
447 port_ptr->this_port.node_id = IPC_ROUTER_NID_LOCAL;
448 port_ptr->this_port.port_id = allocate_port_id();
449 if (!port_ptr->this_port.port_id) {
450 pr_err("%s: All port ids are in use\n", __func__);
451 kfree(port_ptr);
452 return NULL;
453 }
454
455 spin_lock_init(&port_ptr->port_lock);
456 INIT_LIST_HEAD(&port_ptr->incomplete);
457 mutex_init(&port_ptr->incomplete_lock);
458 INIT_LIST_HEAD(&port_ptr->port_rx_q);
459 mutex_init(&port_ptr->port_rx_q_lock);
460 init_waitqueue_head(&port_ptr->port_rx_wait_q);
Karthikeyan Ramasubramanianb4aeeb92012-03-13 12:31:43 -0600461 snprintf(port_ptr->rx_wakelock_name, MAX_WAKELOCK_NAME_SZ,
462 "msm_ipc_read%08x:%08x",
463 port_ptr->this_port.node_id,
464 port_ptr->this_port.port_id);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700465 wake_lock_init(&port_ptr->port_rx_wake_lock,
Karthikeyan Ramasubramanianb4aeeb92012-03-13 12:31:43 -0600466 WAKE_LOCK_SUSPEND, port_ptr->rx_wakelock_name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700467
468 port_ptr->endpoint = endpoint;
469 port_ptr->notify = notify;
470 port_ptr->priv = priv;
471
472 msm_ipc_router_add_local_port(port_ptr);
473 return port_ptr;
474}
475
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -0600476/*
477 * Should be called with local_ports_lock locked
478 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700479static struct msm_ipc_port *msm_ipc_router_lookup_local_port(uint32_t port_id)
480{
481 int key = (port_id & (LP_HASH_SIZE - 1));
482 struct msm_ipc_port *port_ptr;
483
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700484 list_for_each_entry(port_ptr, &local_ports[key], list) {
485 if (port_ptr->this_port.port_id == port_id) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700486 return port_ptr;
487 }
488 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700489 return NULL;
490}
491
492static struct msm_ipc_router_remote_port *msm_ipc_router_lookup_remote_port(
493 uint32_t node_id,
494 uint32_t port_id)
495{
496 struct msm_ipc_router_remote_port *rport_ptr;
497 struct msm_ipc_routing_table_entry *rt_entry;
498 int key = (port_id & (RP_HASH_SIZE - 1));
499
500 mutex_lock(&routing_table_lock);
501 rt_entry = lookup_routing_table(node_id);
502 if (!rt_entry) {
503 mutex_unlock(&routing_table_lock);
504 pr_err("%s: Node is not up\n", __func__);
505 return NULL;
506 }
507
508 mutex_lock(&rt_entry->lock);
509 list_for_each_entry(rport_ptr,
510 &rt_entry->remote_port_list[key], list) {
511 if (rport_ptr->port_id == port_id) {
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600512 if (rport_ptr->restart_state != RESTART_NORMAL)
513 rport_ptr = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700514 mutex_unlock(&rt_entry->lock);
515 mutex_unlock(&routing_table_lock);
516 return rport_ptr;
517 }
518 }
519 mutex_unlock(&rt_entry->lock);
520 mutex_unlock(&routing_table_lock);
521 return NULL;
522}
523
524static struct msm_ipc_router_remote_port *msm_ipc_router_create_remote_port(
525 uint32_t node_id,
526 uint32_t port_id)
527{
528 struct msm_ipc_router_remote_port *rport_ptr;
529 struct msm_ipc_routing_table_entry *rt_entry;
530 int key = (port_id & (RP_HASH_SIZE - 1));
531
532 mutex_lock(&routing_table_lock);
533 rt_entry = lookup_routing_table(node_id);
534 if (!rt_entry) {
535 mutex_unlock(&routing_table_lock);
536 pr_err("%s: Node is not up\n", __func__);
537 return NULL;
538 }
539
540 mutex_lock(&rt_entry->lock);
541 rport_ptr = kmalloc(sizeof(struct msm_ipc_router_remote_port),
542 GFP_KERNEL);
543 if (!rport_ptr) {
544 mutex_unlock(&rt_entry->lock);
545 mutex_unlock(&routing_table_lock);
546 pr_err("%s: Remote port alloc failed\n", __func__);
547 return NULL;
548 }
549 rport_ptr->port_id = port_id;
550 rport_ptr->node_id = node_id;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600551 rport_ptr->restart_state = RESTART_NORMAL;
Karthikeyan Ramasubramanian1668cc62012-09-23 22:23:36 -0600552 rport_ptr->sec_rule = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700553 rport_ptr->tx_quota_cnt = 0;
554 init_waitqueue_head(&rport_ptr->quota_wait);
555 mutex_init(&rport_ptr->quota_lock);
556 list_add_tail(&rport_ptr->list,
557 &rt_entry->remote_port_list[key]);
558 mutex_unlock(&rt_entry->lock);
559 mutex_unlock(&routing_table_lock);
560 return rport_ptr;
561}
562
563static void msm_ipc_router_destroy_remote_port(
564 struct msm_ipc_router_remote_port *rport_ptr)
565{
566 uint32_t node_id;
567 struct msm_ipc_routing_table_entry *rt_entry;
568
569 if (!rport_ptr)
570 return;
571
572 node_id = rport_ptr->node_id;
573 mutex_lock(&routing_table_lock);
574 rt_entry = lookup_routing_table(node_id);
575 if (!rt_entry) {
576 mutex_unlock(&routing_table_lock);
577 pr_err("%s: Node %d is not up\n", __func__, node_id);
578 return;
579 }
580
581 mutex_lock(&rt_entry->lock);
582 list_del(&rport_ptr->list);
583 kfree(rport_ptr);
584 mutex_unlock(&rt_entry->lock);
585 mutex_unlock(&routing_table_lock);
586 return;
587}
588
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -0600589/**
590 * msm_ipc_router_lookup_server() - Lookup server information
591 * @service: Service ID of the server info to be looked up.
592 * @instance: Instance ID of the server info to be looked up.
593 * @node_id: Node/Processor ID in which the server is hosted.
594 * @port_id: Port ID within the node in which the server is hosted.
595 *
596 * @return: If found Pointer to server structure, else NULL.
597 *
598 * Note1: Lock the server_list_lock before accessing this function.
599 * Note2: If the <node_id:port_id> are <0:0>, then the lookup is restricted
600 * to <service:instance>. Used only when a client wants to send a
601 * message to any QMI server.
602 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700603static struct msm_ipc_server *msm_ipc_router_lookup_server(
604 uint32_t service,
605 uint32_t instance,
606 uint32_t node_id,
607 uint32_t port_id)
608{
609 struct msm_ipc_server *server;
610 struct msm_ipc_server_port *server_port;
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -0600611 int key = (service & (SRV_HASH_SIZE - 1));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700612
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700613 list_for_each_entry(server, &server_list[key], list) {
614 if ((server->name.service != service) ||
615 (server->name.instance != instance))
616 continue;
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -0600617 if ((node_id == 0) && (port_id == 0))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700618 return server;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700619 list_for_each_entry(server_port, &server->server_port_list,
620 list) {
621 if ((server_port->server_addr.node_id == node_id) &&
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -0600622 (server_port->server_addr.port_id == port_id))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700623 return server;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700624 }
625 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700626 return NULL;
627}
628
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -0600629/**
630 * msm_ipc_router_create_server() - Add server info to hash table
631 * @service: Service ID of the server info to be created.
632 * @instance: Instance ID of the server info to be created.
633 * @node_id: Node/Processor ID in which the server is hosted.
634 * @port_id: Port ID within the node in which the server is hosted.
635 * @xprt_info: XPRT through which the node hosting the server is reached.
636 *
637 * @return: Pointer to server structure on success, else NULL.
638 *
639 * This function adds the server info to the hash table. If the same
640 * server(i.e. <service_id:instance_id>) is hosted in different nodes,
641 * they are maintained as list of "server_port" under "server" structure.
642 * Note: Lock the server_list_lock before accessing this function.
643 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700644static struct msm_ipc_server *msm_ipc_router_create_server(
645 uint32_t service,
646 uint32_t instance,
647 uint32_t node_id,
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600648 uint32_t port_id,
649 struct msm_ipc_router_xprt_info *xprt_info)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700650{
651 struct msm_ipc_server *server = NULL;
652 struct msm_ipc_server_port *server_port;
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -0600653 int key = (service & (SRV_HASH_SIZE - 1));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700654
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700655 list_for_each_entry(server, &server_list[key], list) {
656 if ((server->name.service == service) &&
657 (server->name.instance == instance))
658 goto create_srv_port;
659 }
660
661 server = kmalloc(sizeof(struct msm_ipc_server), GFP_KERNEL);
662 if (!server) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700663 pr_err("%s: Server allocation failed\n", __func__);
664 return NULL;
665 }
666 server->name.service = service;
667 server->name.instance = instance;
Karthikeyan Ramasubramanian1668cc62012-09-23 22:23:36 -0600668 server->synced_sec_rule = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700669 INIT_LIST_HEAD(&server->server_port_list);
670 list_add_tail(&server->list, &server_list[key]);
671
672create_srv_port:
673 server_port = kmalloc(sizeof(struct msm_ipc_server_port), GFP_KERNEL);
674 if (!server_port) {
675 if (list_empty(&server->server_port_list)) {
676 list_del(&server->list);
677 kfree(server);
678 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700679 pr_err("%s: Server Port allocation failed\n", __func__);
680 return NULL;
681 }
682 server_port->server_addr.node_id = node_id;
683 server_port->server_addr.port_id = port_id;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600684 server_port->xprt_info = xprt_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700685 list_add_tail(&server_port->list, &server->server_port_list);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700686
687 return server;
688}
689
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -0600690/**
691 * msm_ipc_router_destroy_server() - Remove server info from hash table
692 * @server: Server info to be removed.
693 * @node_id: Node/Processor ID in which the server is hosted.
694 * @port_id: Port ID within the node in which the server is hosted.
695 *
696 * This function removes the server_port identified using <node_id:port_id>
697 * from the server structure. If the server_port list under server structure
698 * is empty after removal, then remove the server structure from the server
699 * hash table.
700 * Note: Lock the server_list_lock before accessing this function.
701 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700702static void msm_ipc_router_destroy_server(struct msm_ipc_server *server,
703 uint32_t node_id, uint32_t port_id)
704{
705 struct msm_ipc_server_port *server_port;
706
707 if (!server)
708 return;
709
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700710 list_for_each_entry(server_port, &server->server_port_list, list) {
711 if ((server_port->server_addr.node_id == node_id) &&
712 (server_port->server_addr.port_id == port_id))
713 break;
714 }
715 if (server_port) {
716 list_del(&server_port->list);
717 kfree(server_port);
718 }
719 if (list_empty(&server->server_port_list)) {
720 list_del(&server->list);
721 kfree(server);
722 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700723 return;
724}
725
726static int msm_ipc_router_send_control_msg(
727 struct msm_ipc_router_xprt_info *xprt_info,
728 union rr_control_msg *msg)
729{
730 struct rr_packet *pkt;
731 struct sk_buff *ipc_rtr_pkt;
732 struct rr_header *hdr;
733 int pkt_size;
734 void *data;
735 struct sk_buff_head *pkt_fragment_q;
736 int ret;
737
738 if (!xprt_info || ((msg->cmd != IPC_ROUTER_CTRL_CMD_HELLO) &&
739 !xprt_info->initialized)) {
740 pr_err("%s: xprt_info not initialized\n", __func__);
741 return -EINVAL;
742 }
743
744 if (xprt_info->remote_node_id == IPC_ROUTER_NID_LOCAL)
745 return 0;
746
747 pkt = kzalloc(sizeof(struct rr_packet), GFP_KERNEL);
748 if (!pkt) {
749 pr_err("%s: pkt alloc failed\n", __func__);
750 return -ENOMEM;
751 }
752
753 pkt_fragment_q = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
754 if (!pkt_fragment_q) {
755 pr_err("%s: pkt_fragment_q alloc failed\n", __func__);
756 kfree(pkt);
757 return -ENOMEM;
758 }
759 skb_queue_head_init(pkt_fragment_q);
760
761 pkt_size = IPC_ROUTER_HDR_SIZE + sizeof(*msg);
762 ipc_rtr_pkt = alloc_skb(pkt_size, GFP_KERNEL);
763 if (!ipc_rtr_pkt) {
764 pr_err("%s: ipc_rtr_pkt alloc failed\n", __func__);
765 kfree(pkt_fragment_q);
766 kfree(pkt);
767 return -ENOMEM;
768 }
769
770 skb_reserve(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
771 data = skb_put(ipc_rtr_pkt, sizeof(*msg));
772 memcpy(data, msg, sizeof(*msg));
773 hdr = (struct rr_header *)skb_push(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
774 if (!hdr) {
775 pr_err("%s: skb_push failed\n", __func__);
776 kfree_skb(ipc_rtr_pkt);
777 kfree(pkt_fragment_q);
778 kfree(pkt);
779 return -ENOMEM;
780 }
781
782 hdr->version = IPC_ROUTER_VERSION;
783 hdr->type = msg->cmd;
784 hdr->src_node_id = IPC_ROUTER_NID_LOCAL;
785 hdr->src_port_id = IPC_ROUTER_ADDRESS;
786 hdr->confirm_rx = 0;
787 hdr->size = sizeof(*msg);
788 hdr->dst_node_id = xprt_info->remote_node_id;
789 hdr->dst_port_id = IPC_ROUTER_ADDRESS;
790 skb_queue_tail(pkt_fragment_q, ipc_rtr_pkt);
791 pkt->pkt_fragment_q = pkt_fragment_q;
792 pkt->length = pkt_size;
793
794 mutex_lock(&xprt_info->tx_lock);
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700795 ret = xprt_info->xprt->write(pkt, pkt_size, xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700796 mutex_unlock(&xprt_info->tx_lock);
797
798 release_pkt(pkt);
799 return ret;
800}
801
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -0600802static int msm_ipc_router_send_server_list(uint32_t node_id,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700803 struct msm_ipc_router_xprt_info *xprt_info)
804{
805 union rr_control_msg ctl;
806 struct msm_ipc_server *server;
807 struct msm_ipc_server_port *server_port;
808 int i;
809
810 if (!xprt_info || !xprt_info->initialized) {
811 pr_err("%s: Xprt info not initialized\n", __func__);
812 return -EINVAL;
813 }
814
815 ctl.cmd = IPC_ROUTER_CTRL_CMD_NEW_SERVER;
816
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700817 for (i = 0; i < SRV_HASH_SIZE; i++) {
818 list_for_each_entry(server, &server_list[i], list) {
819 ctl.srv.service = server->name.service;
820 ctl.srv.instance = server->name.instance;
821 list_for_each_entry(server_port,
822 &server->server_port_list, list) {
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -0600823 if (server_port->server_addr.node_id !=
824 node_id)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700825 continue;
826
827 ctl.srv.node_id =
828 server_port->server_addr.node_id;
829 ctl.srv.port_id =
830 server_port->server_addr.port_id;
831 msm_ipc_router_send_control_msg(xprt_info,
832 &ctl);
833 }
834 }
835 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700836
837 return 0;
838}
839
840#if defined(DEBUG)
841static char *type_to_str(int i)
842{
843 switch (i) {
844 case IPC_ROUTER_CTRL_CMD_DATA:
845 return "data ";
846 case IPC_ROUTER_CTRL_CMD_HELLO:
847 return "hello ";
848 case IPC_ROUTER_CTRL_CMD_BYE:
849 return "bye ";
850 case IPC_ROUTER_CTRL_CMD_NEW_SERVER:
851 return "new_srvr";
852 case IPC_ROUTER_CTRL_CMD_REMOVE_SERVER:
853 return "rmv_srvr";
854 case IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT:
855 return "rmv_clnt";
856 case IPC_ROUTER_CTRL_CMD_RESUME_TX:
857 return "resum_tx";
858 case IPC_ROUTER_CTRL_CMD_EXIT:
859 return "cmd_exit";
860 default:
861 return "invalid";
862 }
863}
864#endif
865
866static int broadcast_ctl_msg_locally(union rr_control_msg *msg)
867{
868 struct rr_packet *pkt;
869 struct sk_buff *ipc_rtr_pkt;
870 struct rr_header *hdr;
871 int pkt_size;
872 void *data;
873 struct sk_buff_head *pkt_fragment_q;
874 int ret;
875
876 pkt = kzalloc(sizeof(struct rr_packet), GFP_KERNEL);
877 if (!pkt) {
878 pr_err("%s: pkt alloc failed\n", __func__);
879 return -ENOMEM;
880 }
881
882 pkt_fragment_q = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
883 if (!pkt_fragment_q) {
884 pr_err("%s: pkt_fragment_q alloc failed\n", __func__);
885 kfree(pkt);
886 return -ENOMEM;
887 }
888 skb_queue_head_init(pkt_fragment_q);
889
890 pkt_size = IPC_ROUTER_HDR_SIZE + sizeof(*msg);
891 ipc_rtr_pkt = alloc_skb(pkt_size, GFP_KERNEL);
892 if (!ipc_rtr_pkt) {
893 pr_err("%s: ipc_rtr_pkt alloc failed\n", __func__);
894 kfree(pkt_fragment_q);
895 kfree(pkt);
896 return -ENOMEM;
897 }
898
899 skb_reserve(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
900 data = skb_put(ipc_rtr_pkt, sizeof(*msg));
901 memcpy(data, msg, sizeof(*msg));
902 hdr = (struct rr_header *)skb_push(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
903 if (!hdr) {
904 pr_err("%s: skb_push failed\n", __func__);
905 kfree_skb(ipc_rtr_pkt);
906 kfree(pkt_fragment_q);
907 kfree(pkt);
908 return -ENOMEM;
909 }
910 hdr->version = IPC_ROUTER_VERSION;
911 hdr->type = msg->cmd;
912 hdr->src_node_id = IPC_ROUTER_NID_LOCAL;
913 hdr->src_port_id = IPC_ROUTER_ADDRESS;
914 hdr->confirm_rx = 0;
915 hdr->size = sizeof(*msg);
916 hdr->dst_node_id = IPC_ROUTER_NID_LOCAL;
917 hdr->dst_port_id = IPC_ROUTER_ADDRESS;
918 skb_queue_tail(pkt_fragment_q, ipc_rtr_pkt);
919 pkt->pkt_fragment_q = pkt_fragment_q;
920 pkt->length = pkt_size;
921
922 ret = post_control_ports(pkt);
923 release_pkt(pkt);
924 return ret;
925}
926
927static int broadcast_ctl_msg(union rr_control_msg *ctl)
928{
929 struct msm_ipc_router_xprt_info *xprt_info;
930
931 mutex_lock(&xprt_info_list_lock);
932 list_for_each_entry(xprt_info, &xprt_info_list, list) {
933 msm_ipc_router_send_control_msg(xprt_info, ctl);
934 }
935 mutex_unlock(&xprt_info_list_lock);
936
937 return 0;
938}
939
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600940static int relay_ctl_msg(struct msm_ipc_router_xprt_info *xprt_info,
941 union rr_control_msg *ctl)
942{
943 struct msm_ipc_router_xprt_info *fwd_xprt_info;
944
945 if (!xprt_info || !ctl)
946 return -EINVAL;
947
948 mutex_lock(&xprt_info_list_lock);
949 list_for_each_entry(fwd_xprt_info, &xprt_info_list, list) {
950 if (xprt_info->xprt->link_id != fwd_xprt_info->xprt->link_id)
951 msm_ipc_router_send_control_msg(fwd_xprt_info, ctl);
952 }
953 mutex_unlock(&xprt_info_list_lock);
954
955 return 0;
956}
957
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700958static int relay_msg(struct msm_ipc_router_xprt_info *xprt_info,
959 struct rr_packet *pkt)
960{
961 struct msm_ipc_router_xprt_info *fwd_xprt_info;
962
963 if (!xprt_info || !pkt)
964 return -EINVAL;
965
966 mutex_lock(&xprt_info_list_lock);
967 list_for_each_entry(fwd_xprt_info, &xprt_info_list, list) {
968 mutex_lock(&fwd_xprt_info->tx_lock);
969 if (xprt_info->xprt->link_id != fwd_xprt_info->xprt->link_id)
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700970 fwd_xprt_info->xprt->write(pkt, pkt->length,
971 fwd_xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700972 mutex_unlock(&fwd_xprt_info->tx_lock);
973 }
974 mutex_unlock(&xprt_info_list_lock);
975 return 0;
976}
977
978static int forward_msg(struct msm_ipc_router_xprt_info *xprt_info,
979 struct rr_packet *pkt)
980{
981 uint32_t dst_node_id;
982 struct sk_buff *head_pkt;
983 struct rr_header *hdr;
984 struct msm_ipc_router_xprt_info *fwd_xprt_info;
985 struct msm_ipc_routing_table_entry *rt_entry;
986
987 if (!xprt_info || !pkt)
988 return -EINVAL;
989
990 head_pkt = skb_peek(pkt->pkt_fragment_q);
991 if (!head_pkt)
992 return -EINVAL;
993
994 hdr = (struct rr_header *)head_pkt->data;
995 dst_node_id = hdr->dst_node_id;
996 mutex_lock(&routing_table_lock);
997 rt_entry = lookup_routing_table(dst_node_id);
998 if (!(rt_entry) || !(rt_entry->xprt_info)) {
999 mutex_unlock(&routing_table_lock);
1000 pr_err("%s: Routing table not initialized\n", __func__);
1001 return -ENODEV;
1002 }
1003
1004 mutex_lock(&rt_entry->lock);
1005 fwd_xprt_info = rt_entry->xprt_info;
1006 mutex_lock(&fwd_xprt_info->tx_lock);
1007 if (xprt_info->remote_node_id == fwd_xprt_info->remote_node_id) {
1008 mutex_unlock(&fwd_xprt_info->tx_lock);
1009 mutex_unlock(&rt_entry->lock);
1010 mutex_unlock(&routing_table_lock);
1011 pr_err("%s: Discarding Command to route back\n", __func__);
1012 return -EINVAL;
1013 }
1014
1015 if (xprt_info->xprt->link_id == fwd_xprt_info->xprt->link_id) {
1016 mutex_unlock(&fwd_xprt_info->tx_lock);
1017 mutex_unlock(&rt_entry->lock);
1018 mutex_unlock(&routing_table_lock);
1019 pr_err("%s: DST in the same cluster\n", __func__);
1020 return 0;
1021 }
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -07001022 fwd_xprt_info->xprt->write(pkt, pkt->length, fwd_xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001023 mutex_unlock(&fwd_xprt_info->tx_lock);
1024 mutex_unlock(&rt_entry->lock);
1025 mutex_unlock(&routing_table_lock);
1026
1027 return 0;
1028}
1029
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001030static void reset_remote_port_info(uint32_t node_id, uint32_t port_id)
1031{
1032 struct msm_ipc_router_remote_port *rport_ptr;
1033
1034 rport_ptr = msm_ipc_router_lookup_remote_port(node_id, port_id);
1035 if (!rport_ptr) {
1036 pr_err("%s: No such remote port %08x:%08x\n",
1037 __func__, node_id, port_id);
1038 return;
1039 }
1040 mutex_lock(&rport_ptr->quota_lock);
1041 rport_ptr->restart_state = RESTART_PEND;
1042 wake_up(&rport_ptr->quota_wait);
1043 mutex_unlock(&rport_ptr->quota_lock);
1044 return;
1045}
1046
1047static void msm_ipc_cleanup_remote_server_info(
1048 struct msm_ipc_router_xprt_info *xprt_info)
1049{
1050 struct msm_ipc_server *svr, *tmp_svr;
1051 struct msm_ipc_server_port *svr_port, *tmp_svr_port;
1052 int i;
1053 union rr_control_msg ctl;
1054
1055 if (!xprt_info) {
1056 pr_err("%s: Invalid xprt_info\n", __func__);
1057 return;
1058 }
1059
1060 ctl.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_SERVER;
1061 mutex_lock(&server_list_lock);
1062 for (i = 0; i < SRV_HASH_SIZE; i++) {
1063 list_for_each_entry_safe(svr, tmp_svr, &server_list[i], list) {
1064 ctl.srv.service = svr->name.service;
1065 ctl.srv.instance = svr->name.instance;
1066 list_for_each_entry_safe(svr_port, tmp_svr_port,
1067 &svr->server_port_list, list) {
1068 if (svr_port->xprt_info != xprt_info)
1069 continue;
1070 D("Remove server %08x:%08x - %08x:%08x",
1071 ctl.srv.service, ctl.srv.instance,
1072 svr_port->server_addr.node_id,
1073 svr_port->server_addr.port_id);
1074 reset_remote_port_info(
1075 svr_port->server_addr.node_id,
1076 svr_port->server_addr.port_id);
1077 ctl.srv.node_id = svr_port->server_addr.node_id;
1078 ctl.srv.port_id = svr_port->server_addr.port_id;
1079 relay_ctl_msg(xprt_info, &ctl);
1080 broadcast_ctl_msg_locally(&ctl);
1081 list_del(&svr_port->list);
1082 kfree(svr_port);
1083 }
1084 if (list_empty(&svr->server_port_list)) {
1085 list_del(&svr->list);
1086 kfree(svr);
1087 }
1088 }
1089 }
1090 mutex_unlock(&server_list_lock);
1091}
1092
1093static void msm_ipc_cleanup_remote_client_info(
1094 struct msm_ipc_router_xprt_info *xprt_info)
1095{
1096 struct msm_ipc_routing_table_entry *rt_entry;
1097 struct msm_ipc_router_remote_port *rport_ptr;
1098 int i, j;
1099 union rr_control_msg ctl;
1100
1101 if (!xprt_info) {
1102 pr_err("%s: Invalid xprt_info\n", __func__);
1103 return;
1104 }
1105
1106 ctl.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT;
1107 mutex_lock(&routing_table_lock);
1108 for (i = 0; i < RT_HASH_SIZE; i++) {
1109 list_for_each_entry(rt_entry, &routing_table[i], list) {
1110 mutex_lock(&rt_entry->lock);
1111 if (rt_entry->xprt_info != xprt_info) {
1112 mutex_unlock(&rt_entry->lock);
1113 continue;
1114 }
1115 for (j = 0; j < RP_HASH_SIZE; j++) {
1116 list_for_each_entry(rport_ptr,
1117 &rt_entry->remote_port_list[j], list) {
1118 if (rport_ptr->restart_state ==
1119 RESTART_PEND)
1120 continue;
1121 mutex_lock(&rport_ptr->quota_lock);
1122 rport_ptr->restart_state = RESTART_PEND;
1123 wake_up(&rport_ptr->quota_wait);
1124 mutex_unlock(&rport_ptr->quota_lock);
1125 ctl.cli.node_id = rport_ptr->node_id;
1126 ctl.cli.port_id = rport_ptr->port_id;
1127 broadcast_ctl_msg_locally(&ctl);
1128 }
1129 }
1130 mutex_unlock(&rt_entry->lock);
1131 }
1132 }
1133 mutex_unlock(&routing_table_lock);
1134}
1135
1136static void msm_ipc_cleanup_remote_port_info(uint32_t node_id)
1137{
1138 struct msm_ipc_routing_table_entry *rt_entry, *tmp_rt_entry;
1139 struct msm_ipc_router_remote_port *rport_ptr, *tmp_rport_ptr;
1140 int i, j;
1141
1142 mutex_lock(&routing_table_lock);
1143 for (i = 0; i < RT_HASH_SIZE; i++) {
1144 list_for_each_entry_safe(rt_entry, tmp_rt_entry,
1145 &routing_table[i], list) {
1146 mutex_lock(&rt_entry->lock);
1147 if (rt_entry->neighbor_node_id != node_id) {
1148 mutex_unlock(&rt_entry->lock);
1149 continue;
1150 }
1151 for (j = 0; j < RP_HASH_SIZE; j++) {
1152 list_for_each_entry_safe(rport_ptr,
1153 tmp_rport_ptr,
1154 &rt_entry->remote_port_list[j], list) {
1155 list_del(&rport_ptr->list);
1156 kfree(rport_ptr);
1157 }
1158 }
1159 mutex_unlock(&rt_entry->lock);
1160 }
1161 }
1162 mutex_unlock(&routing_table_lock);
1163}
1164
1165static void msm_ipc_cleanup_routing_table(
1166 struct msm_ipc_router_xprt_info *xprt_info)
1167{
1168 int i;
1169 struct msm_ipc_routing_table_entry *rt_entry;
1170
1171 if (!xprt_info) {
1172 pr_err("%s: Invalid xprt_info\n", __func__);
1173 return;
1174 }
1175
1176 mutex_lock(&routing_table_lock);
1177 for (i = 0; i < RT_HASH_SIZE; i++) {
1178 list_for_each_entry(rt_entry, &routing_table[i], list) {
1179 mutex_lock(&rt_entry->lock);
1180 if (rt_entry->xprt_info == xprt_info)
1181 rt_entry->xprt_info = NULL;
1182 mutex_unlock(&rt_entry->lock);
1183 }
1184 }
1185 mutex_unlock(&routing_table_lock);
1186}
1187
1188static void modem_reset_cleanup(struct msm_ipc_router_xprt_info *xprt_info)
1189{
1190
1191 if (!xprt_info) {
1192 pr_err("%s: Invalid xprt_info\n", __func__);
1193 return;
1194 }
1195
1196 msm_ipc_cleanup_remote_server_info(xprt_info);
1197 msm_ipc_cleanup_remote_client_info(xprt_info);
1198 msm_ipc_cleanup_routing_table(xprt_info);
1199}
1200
Karthikeyan Ramasubramanian1668cc62012-09-23 22:23:36 -06001201/**
1202 * sync_sec_rule() - Synchrnoize the security rule into the server structure
1203 * @server: Server structure where the rule has to be synchronized.
1204 * @rule: Security tule to be synchronized.
1205 *
1206 * This function is used to update the server structure with the security
1207 * rule configured for the <service:instance> corresponding to that server.
1208 */
1209static void sync_sec_rule(struct msm_ipc_server *server, void *rule)
1210{
1211 struct msm_ipc_server_port *server_port;
1212 struct msm_ipc_router_remote_port *rport_ptr = NULL;
1213
1214 list_for_each_entry(server_port, &server->server_port_list, list) {
1215 rport_ptr = msm_ipc_router_lookup_remote_port(
1216 server_port->server_addr.node_id,
1217 server_port->server_addr.port_id);
1218 if (!rport_ptr)
1219 continue;
1220 rport_ptr->sec_rule = rule;
1221 }
1222 server->synced_sec_rule = 1;
1223}
1224
1225/**
1226 * msm_ipc_sync_sec_rule() - Sync the security rule to the service
1227 * @service: Service for which the rule has to be synchronized.
1228 * @instance: Instance for which the rule has to be synchronized.
1229 * @rule: Security rule to be synchronized.
1230 *
1231 * This function is used to syncrhonize the security rule with the server
1232 * hash table, if the user-space script configures the rule after the service
1233 * has come up. This function is used to synchronize the security rule to a
1234 * specific service and optionally a specific instance.
1235 */
1236void msm_ipc_sync_sec_rule(uint32_t service, uint32_t instance, void *rule)
1237{
1238 int key = (service & (SRV_HASH_SIZE - 1));
1239 struct msm_ipc_server *server;
1240
1241 mutex_lock(&server_list_lock);
1242 list_for_each_entry(server, &server_list[key], list) {
1243 if (server->name.service != service)
1244 continue;
1245
1246 if (server->name.instance != instance &&
1247 instance != ALL_INSTANCE)
1248 continue;
1249
1250 /*
1251 * If the rule applies to all instances and if the specific
1252 * instance of a service has a rule synchronized already,
1253 * do not apply the rule for that specific instance.
1254 */
1255 if (instance == ALL_INSTANCE && server->synced_sec_rule)
1256 continue;
1257
1258 sync_sec_rule(server, rule);
1259 }
1260 mutex_unlock(&server_list_lock);
1261}
1262
1263/**
1264 * msm_ipc_sync_default_sec_rule() - Default security rule to all services
1265 * @rule: Security rule to be synchronized.
1266 *
1267 * This function is used to syncrhonize the security rule with the server
1268 * hash table, if the user-space script configures the rule after the service
1269 * has come up. This function is used to synchronize the security rule that
1270 * applies to all services, if the concerned service do not have any rule
1271 * defined.
1272 */
1273void msm_ipc_sync_default_sec_rule(void *rule)
1274{
1275 int key;
1276 struct msm_ipc_server *server;
1277
1278 mutex_lock(&server_list_lock);
1279 for (key = 0; key < SRV_HASH_SIZE; key++) {
1280 list_for_each_entry(server, &server_list[key], list) {
1281 if (server->synced_sec_rule)
1282 continue;
1283
1284 sync_sec_rule(server, rule);
1285 }
1286 }
1287 mutex_unlock(&server_list_lock);
1288}
1289
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001290static int process_hello_msg(struct msm_ipc_router_xprt_info *xprt_info,
1291 struct rr_header *hdr)
1292{
1293 int i, rc = 0;
1294 union rr_control_msg ctl;
1295 struct msm_ipc_routing_table_entry *rt_entry;
1296
1297 if (!hdr)
1298 return -EINVAL;
1299
1300 RR("o HELLO NID %d\n", hdr->src_node_id);
1301
1302 xprt_info->remote_node_id = hdr->src_node_id;
1303 /*
1304 * Find the entry from Routing Table corresponding to Node ID.
1305 * Under SSR, an entry will be found. When the system boots up
1306 * for the 1st time, an entry will not be found and hence allocate
1307 * an entry. Update the entry with the Node ID that it corresponds
1308 * to and the XPRT through which it can be reached.
1309 */
1310 mutex_lock(&routing_table_lock);
1311 rt_entry = lookup_routing_table(hdr->src_node_id);
1312 if (!rt_entry) {
1313 rt_entry = alloc_routing_table_entry(hdr->src_node_id);
1314 if (!rt_entry) {
1315 mutex_unlock(&routing_table_lock);
1316 pr_err("%s: rt_entry allocation failed\n", __func__);
1317 return -ENOMEM;
1318 }
1319 add_routing_table_entry(rt_entry);
1320 }
1321 mutex_lock(&rt_entry->lock);
1322 rt_entry->neighbor_node_id = xprt_info->remote_node_id;
1323 rt_entry->xprt_info = xprt_info;
1324 mutex_unlock(&rt_entry->lock);
1325 mutex_unlock(&routing_table_lock);
1326
1327 /* Cleanup any remote ports, if the node is coming out of reset */
1328 msm_ipc_cleanup_remote_port_info(xprt_info->remote_node_id);
1329
1330 /* Send a reply HELLO message */
1331 memset(&ctl, 0, sizeof(ctl));
1332 ctl.cmd = IPC_ROUTER_CTRL_CMD_HELLO;
1333 rc = msm_ipc_router_send_control_msg(xprt_info, &ctl);
1334 if (rc < 0) {
1335 pr_err("%s: Error sending reply HELLO message\n", __func__);
1336 return rc;
1337 }
1338 xprt_info->initialized = 1;
1339
1340 /*
1341 * Send list of servers from the local node and from nodes
1342 * outside the mesh network in which this XPRT is part of.
1343 */
Karthikeyan Ramasubramaniane8ad5352012-10-31 15:12:08 -06001344 mutex_lock(&server_list_lock);
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001345 mutex_lock(&routing_table_lock);
1346 for (i = 0; i < RT_HASH_SIZE; i++) {
1347 list_for_each_entry(rt_entry, &routing_table[i], list) {
1348 if ((rt_entry->node_id != IPC_ROUTER_NID_LOCAL) &&
Karthikeyan Ramasubramanian72ad5792013-01-30 14:17:57 -07001349 (!rt_entry->xprt_info ||
1350 (rt_entry->xprt_info->xprt->link_id ==
1351 xprt_info->xprt->link_id)))
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001352 continue;
1353 rc = msm_ipc_router_send_server_list(rt_entry->node_id,
1354 xprt_info);
1355 if (rc < 0) {
1356 mutex_unlock(&routing_table_lock);
Karthikeyan Ramasubramaniane8ad5352012-10-31 15:12:08 -06001357 mutex_unlock(&server_list_lock);
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001358 return rc;
1359 }
1360 }
1361 }
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 RR("HELLO message processed\n");
1365 return rc;
1366}
1367
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001368static int process_control_msg(struct msm_ipc_router_xprt_info *xprt_info,
1369 struct rr_packet *pkt)
1370{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001371 union rr_control_msg *msg;
1372 struct msm_ipc_router_remote_port *rport_ptr;
1373 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001374 struct sk_buff *temp_ptr;
1375 struct rr_header *hdr;
1376 struct msm_ipc_server *server;
1377 struct msm_ipc_routing_table_entry *rt_entry;
1378
1379 if (pkt->length != (IPC_ROUTER_HDR_SIZE + sizeof(*msg))) {
1380 pr_err("%s: r2r msg size %d != %d\n", __func__, pkt->length,
1381 (IPC_ROUTER_HDR_SIZE + sizeof(*msg)));
1382 return -EINVAL;
1383 }
1384
1385 temp_ptr = skb_peek(pkt->pkt_fragment_q);
Karthikeyan Ramasubramanian9024dd82011-12-19 18:44:19 -07001386 if (!temp_ptr) {
1387 pr_err("%s: pkt_fragment_q is empty\n", __func__);
1388 return -EINVAL;
1389 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001390 hdr = (struct rr_header *)temp_ptr->data;
Karthikeyan Ramasubramanian9024dd82011-12-19 18:44:19 -07001391 if (!hdr) {
1392 pr_err("%s: No data inside the skb\n", __func__);
1393 return -EINVAL;
1394 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001395 msg = (union rr_control_msg *)((char *)hdr + IPC_ROUTER_HDR_SIZE);
1396
1397 switch (msg->cmd) {
1398 case IPC_ROUTER_CTRL_CMD_HELLO:
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001399 rc = process_hello_msg(xprt_info, hdr);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001400 break;
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001401
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001402 case IPC_ROUTER_CTRL_CMD_RESUME_TX:
1403 RR("o RESUME_TX id=%d:%08x\n",
1404 msg->cli.node_id, msg->cli.port_id);
1405
1406 rport_ptr = msm_ipc_router_lookup_remote_port(msg->cli.node_id,
1407 msg->cli.port_id);
1408 if (!rport_ptr) {
1409 pr_err("%s: Unable to resume client\n", __func__);
1410 break;
1411 }
1412 mutex_lock(&rport_ptr->quota_lock);
1413 rport_ptr->tx_quota_cnt = 0;
1414 mutex_unlock(&rport_ptr->quota_lock);
1415 wake_up(&rport_ptr->quota_wait);
1416 break;
1417
1418 case IPC_ROUTER_CTRL_CMD_NEW_SERVER:
1419 if (msg->srv.instance == 0) {
1420 pr_err(
1421 "rpcrouter: Server create rejected, version = 0, "
1422 "service = %08x\n", msg->srv.service);
1423 break;
1424 }
1425
1426 RR("o NEW_SERVER id=%d:%08x service=%08x:%08x\n",
1427 msg->srv.node_id, msg->srv.port_id,
1428 msg->srv.service, msg->srv.instance);
1429
1430 mutex_lock(&routing_table_lock);
1431 rt_entry = lookup_routing_table(msg->srv.node_id);
1432 if (!rt_entry) {
1433 rt_entry = alloc_routing_table_entry(msg->srv.node_id);
1434 if (!rt_entry) {
1435 mutex_unlock(&routing_table_lock);
1436 pr_err("%s: rt_entry allocation failed\n",
1437 __func__);
1438 return -ENOMEM;
1439 }
1440 mutex_lock(&rt_entry->lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001441 rt_entry->neighbor_node_id = xprt_info->remote_node_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001442 rt_entry->xprt_info = xprt_info;
1443 mutex_unlock(&rt_entry->lock);
1444 add_routing_table_entry(rt_entry);
1445 }
1446 mutex_unlock(&routing_table_lock);
1447
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001448 mutex_lock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001449 server = msm_ipc_router_lookup_server(msg->srv.service,
1450 msg->srv.instance,
1451 msg->srv.node_id,
1452 msg->srv.port_id);
1453 if (!server) {
1454 server = msm_ipc_router_create_server(
1455 msg->srv.service, msg->srv.instance,
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001456 msg->srv.node_id, msg->srv.port_id, xprt_info);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001457 if (!server) {
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001458 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001459 pr_err("%s: Server Create failed\n", __func__);
1460 return -ENOMEM;
1461 }
1462
1463 if (!msm_ipc_router_lookup_remote_port(
1464 msg->srv.node_id, msg->srv.port_id)) {
1465 rport_ptr = msm_ipc_router_create_remote_port(
1466 msg->srv.node_id, msg->srv.port_id);
1467 if (!rport_ptr)
1468 pr_err("%s: Remote port create "
1469 "failed\n", __func__);
Brent Hronik0e83d3b2013-05-01 16:25:00 -06001470 else
1471 rport_ptr->sec_rule =
1472 msm_ipc_get_security_rule(
1473 msg->srv.service,
1474 msg->srv.instance);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001475 }
1476 wake_up(&newserver_wait);
1477 }
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001478 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001479
1480 relay_msg(xprt_info, pkt);
1481 post_control_ports(pkt);
1482 break;
1483 case IPC_ROUTER_CTRL_CMD_REMOVE_SERVER:
1484 RR("o REMOVE_SERVER service=%08x:%d\n",
1485 msg->srv.service, msg->srv.instance);
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001486 mutex_lock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001487 server = msm_ipc_router_lookup_server(msg->srv.service,
1488 msg->srv.instance,
1489 msg->srv.node_id,
1490 msg->srv.port_id);
1491 if (server) {
1492 msm_ipc_router_destroy_server(server,
1493 msg->srv.node_id,
1494 msg->srv.port_id);
1495 relay_msg(xprt_info, pkt);
1496 post_control_ports(pkt);
1497 }
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001498 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001499 break;
1500 case IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT:
1501 RR("o REMOVE_CLIENT id=%d:%08x\n",
1502 msg->cli.node_id, msg->cli.port_id);
1503 rport_ptr = msm_ipc_router_lookup_remote_port(msg->cli.node_id,
1504 msg->cli.port_id);
1505 if (rport_ptr)
1506 msm_ipc_router_destroy_remote_port(rport_ptr);
1507
1508 relay_msg(xprt_info, pkt);
1509 post_control_ports(pkt);
1510 break;
1511 case IPC_ROUTER_CTRL_CMD_PING:
1512 /* No action needed for ping messages received */
1513 RR("o PING\n");
1514 break;
1515 default:
1516 RR("o UNKNOWN(%08x)\n", msg->cmd);
1517 rc = -ENOSYS;
1518 }
1519
1520 return rc;
1521}
1522
1523static void do_read_data(struct work_struct *work)
1524{
1525 struct rr_header *hdr;
1526 struct rr_packet *pkt = NULL;
1527 struct msm_ipc_port *port_ptr;
1528 struct sk_buff *head_skb;
1529 struct msm_ipc_port_addr *src_addr;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001530 struct msm_ipc_router_remote_port *rport_ptr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001531 uint32_t resume_tx, resume_tx_node_id, resume_tx_port_id;
1532
1533 struct msm_ipc_router_xprt_info *xprt_info =
1534 container_of(work,
1535 struct msm_ipc_router_xprt_info,
1536 read_data);
1537
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001538 while ((pkt = rr_read(xprt_info)) != NULL) {
1539 if (pkt->length < IPC_ROUTER_HDR_SIZE ||
1540 pkt->length > MAX_IPC_PKT_SIZE) {
1541 pr_err("%s: Invalid pkt length %d\n",
1542 __func__, pkt->length);
1543 goto fail_data;
1544 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001545
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001546 head_skb = skb_peek(pkt->pkt_fragment_q);
1547 if (!head_skb) {
1548 pr_err("%s: head_skb is invalid\n", __func__);
1549 goto fail_data;
1550 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001551
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001552 hdr = (struct rr_header *)(head_skb->data);
1553 RR("- ver=%d type=%d src=%d:%08x crx=%d siz=%d dst=%d:%08x\n",
1554 hdr->version, hdr->type, hdr->src_node_id, hdr->src_port_id,
1555 hdr->confirm_rx, hdr->size, hdr->dst_node_id,
1556 hdr->dst_port_id);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001557
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001558 if (hdr->version != IPC_ROUTER_VERSION) {
1559 pr_err("version %d != %d\n",
1560 hdr->version, IPC_ROUTER_VERSION);
1561 goto fail_data;
1562 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001563
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001564 if ((hdr->dst_node_id != IPC_ROUTER_NID_LOCAL) &&
1565 ((hdr->type == IPC_ROUTER_CTRL_CMD_RESUME_TX) ||
1566 (hdr->type == IPC_ROUTER_CTRL_CMD_DATA))) {
1567 forward_msg(xprt_info, pkt);
1568 release_pkt(pkt);
1569 continue;
1570 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001571
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001572 if ((hdr->dst_port_id == IPC_ROUTER_ADDRESS) ||
1573 (hdr->type == IPC_ROUTER_CTRL_CMD_HELLO)) {
1574 process_control_msg(xprt_info, pkt);
1575 release_pkt(pkt);
1576 continue;
1577 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001578#if defined(CONFIG_MSM_SMD_LOGGING)
1579#if defined(DEBUG)
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001580 if (msm_ipc_router_debug_mask & SMEM_LOG) {
1581 smem_log_event((SMEM_LOG_PROC_ID_APPS |
1582 SMEM_LOG_RPC_ROUTER_EVENT_BASE |
1583 IPC_ROUTER_LOG_EVENT_RX),
1584 (hdr->src_node_id << 24) |
1585 (hdr->src_port_id & 0xffffff),
1586 (hdr->dst_node_id << 24) |
1587 (hdr->dst_port_id & 0xffffff),
1588 (hdr->type << 24) | (hdr->confirm_rx << 16) |
1589 (hdr->size & 0xffff));
1590 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001591#endif
1592#endif
1593
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001594 resume_tx = hdr->confirm_rx;
1595 resume_tx_node_id = hdr->dst_node_id;
1596 resume_tx_port_id = hdr->dst_port_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001597
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001598 rport_ptr = msm_ipc_router_lookup_remote_port(hdr->src_node_id,
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06001599 hdr->src_port_id);
1600
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001601 mutex_lock(&local_ports_lock);
1602 port_ptr = msm_ipc_router_lookup_local_port(hdr->dst_port_id);
1603 if (!port_ptr) {
1604 pr_err("%s: No local port id %08x\n", __func__,
1605 hdr->dst_port_id);
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06001606 mutex_unlock(&local_ports_lock);
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001607 release_pkt(pkt);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001608 goto process_done;
1609 }
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001610
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001611 if (!rport_ptr) {
1612 rport_ptr = msm_ipc_router_create_remote_port(
1613 hdr->src_node_id,
1614 hdr->src_port_id);
1615 if (!rport_ptr) {
1616 pr_err("%s: Rmt Prt %08x:%08x create failed\n",
1617 __func__, hdr->src_node_id,
1618 hdr->src_port_id);
1619 mutex_unlock(&local_ports_lock);
1620 goto process_done;
1621 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001622 }
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001623
1624 if (!port_ptr->notify) {
1625 mutex_lock(&port_ptr->port_rx_q_lock);
1626 wake_lock(&port_ptr->port_rx_wake_lock);
1627 list_add_tail(&pkt->list, &port_ptr->port_rx_q);
1628 wake_up(&port_ptr->port_rx_wait_q);
1629 mutex_unlock(&port_ptr->port_rx_q_lock);
1630 mutex_unlock(&local_ports_lock);
1631 } else {
1632 mutex_lock(&port_ptr->port_rx_q_lock);
1633 src_addr = kmalloc(sizeof(struct msm_ipc_port_addr),
1634 GFP_KERNEL);
1635 if (src_addr) {
1636 src_addr->node_id = hdr->src_node_id;
1637 src_addr->port_id = hdr->src_port_id;
1638 }
1639 skb_pull(head_skb, IPC_ROUTER_HDR_SIZE);
1640 mutex_unlock(&local_ports_lock);
1641 port_ptr->notify(MSM_IPC_ROUTER_READ_CB,
1642 pkt->pkt_fragment_q, src_addr, port_ptr->priv);
1643 mutex_unlock(&port_ptr->port_rx_q_lock);
1644 pkt->pkt_fragment_q = NULL;
1645 src_addr = NULL;
1646 release_pkt(pkt);
1647 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001648
1649process_done:
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001650 if (resume_tx) {
1651 union rr_control_msg msg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001652
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001653 msg.cmd = IPC_ROUTER_CTRL_CMD_RESUME_TX;
1654 msg.cli.node_id = resume_tx_node_id;
1655 msg.cli.port_id = resume_tx_port_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001656
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001657 RR("x RESUME_TX id=%d:%08x\n",
1658 msg.cli.node_id, msg.cli.port_id);
1659 msm_ipc_router_send_control_msg(xprt_info, &msg);
1660 }
1661
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001662 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001663 return;
1664
1665fail_data:
1666 release_pkt(pkt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001667 pr_err("ipc_router has died\n");
1668}
1669
1670int msm_ipc_router_register_server(struct msm_ipc_port *port_ptr,
1671 struct msm_ipc_addr *name)
1672{
1673 struct msm_ipc_server *server;
1674 unsigned long flags;
1675 union rr_control_msg ctl;
1676
1677 if (!port_ptr || !name)
1678 return -EINVAL;
1679
1680 if (name->addrtype != MSM_IPC_ADDR_NAME)
1681 return -EINVAL;
1682
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001683 mutex_lock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001684 server = msm_ipc_router_lookup_server(name->addr.port_name.service,
1685 name->addr.port_name.instance,
1686 IPC_ROUTER_NID_LOCAL,
1687 port_ptr->this_port.port_id);
1688 if (server) {
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001689 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001690 pr_err("%s: Server already present\n", __func__);
1691 return -EINVAL;
1692 }
1693
1694 server = msm_ipc_router_create_server(name->addr.port_name.service,
1695 name->addr.port_name.instance,
1696 IPC_ROUTER_NID_LOCAL,
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001697 port_ptr->this_port.port_id,
1698 NULL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001699 if (!server) {
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001700 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001701 pr_err("%s: Server Creation failed\n", __func__);
1702 return -EINVAL;
1703 }
1704
1705 ctl.cmd = IPC_ROUTER_CTRL_CMD_NEW_SERVER;
1706 ctl.srv.service = server->name.service;
1707 ctl.srv.instance = server->name.instance;
1708 ctl.srv.node_id = IPC_ROUTER_NID_LOCAL;
1709 ctl.srv.port_id = port_ptr->this_port.port_id;
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001710 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001711 broadcast_ctl_msg(&ctl);
1712 spin_lock_irqsave(&port_ptr->port_lock, flags);
1713 port_ptr->type = SERVER_PORT;
1714 port_ptr->port_name.service = server->name.service;
1715 port_ptr->port_name.instance = server->name.instance;
1716 spin_unlock_irqrestore(&port_ptr->port_lock, flags);
1717 return 0;
1718}
1719
1720int msm_ipc_router_unregister_server(struct msm_ipc_port *port_ptr)
1721{
1722 struct msm_ipc_server *server;
1723 unsigned long flags;
1724 union rr_control_msg ctl;
1725
1726 if (!port_ptr)
1727 return -EINVAL;
1728
1729 if (port_ptr->type != SERVER_PORT) {
1730 pr_err("%s: Trying to unregister a non-server port\n",
1731 __func__);
1732 return -EINVAL;
1733 }
1734
1735 if (port_ptr->this_port.node_id != IPC_ROUTER_NID_LOCAL) {
1736 pr_err("%s: Trying to unregister a remote server locally\n",
1737 __func__);
1738 return -EINVAL;
1739 }
1740
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001741 mutex_lock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001742 server = msm_ipc_router_lookup_server(port_ptr->port_name.service,
1743 port_ptr->port_name.instance,
1744 port_ptr->this_port.node_id,
1745 port_ptr->this_port.port_id);
1746 if (!server) {
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001747 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001748 pr_err("%s: Server lookup failed\n", __func__);
1749 return -ENODEV;
1750 }
1751
1752 ctl.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_SERVER;
1753 ctl.srv.service = server->name.service;
1754 ctl.srv.instance = server->name.instance;
1755 ctl.srv.node_id = IPC_ROUTER_NID_LOCAL;
1756 ctl.srv.port_id = port_ptr->this_port.port_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001757 msm_ipc_router_destroy_server(server, port_ptr->this_port.node_id,
1758 port_ptr->this_port.port_id);
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001759 mutex_unlock(&server_list_lock);
1760 broadcast_ctl_msg(&ctl);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001761 spin_lock_irqsave(&port_ptr->port_lock, flags);
1762 port_ptr->type = CLIENT_PORT;
1763 spin_unlock_irqrestore(&port_ptr->port_lock, flags);
1764 return 0;
1765}
1766
1767static int loopback_data(struct msm_ipc_port *src,
1768 uint32_t port_id,
1769 struct sk_buff_head *data)
1770{
1771 struct sk_buff *head_skb;
1772 struct rr_header *hdr;
1773 struct msm_ipc_port *port_ptr;
1774 struct rr_packet *pkt;
Karthikeyan Ramasubramanian0a801c12013-02-08 13:07:42 -07001775 int ret_len;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001776
1777 if (!data) {
1778 pr_err("%s: Invalid pkt pointer\n", __func__);
1779 return -EINVAL;
1780 }
1781
1782 pkt = create_pkt(data);
1783 if (!pkt) {
1784 pr_err("%s: New pkt create failed\n", __func__);
1785 return -ENOMEM;
1786 }
1787
1788 head_skb = skb_peek(pkt->pkt_fragment_q);
Karthikeyan Ramasubramanian9024dd82011-12-19 18:44:19 -07001789 if (!head_skb) {
1790 pr_err("%s: pkt_fragment_q is empty\n", __func__);
Brent Hronik0e83d3b2013-05-01 16:25:00 -06001791 release_pkt(pkt);
Karthikeyan Ramasubramanian9024dd82011-12-19 18:44:19 -07001792 return -EINVAL;
1793 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001794 hdr = (struct rr_header *)skb_push(head_skb, IPC_ROUTER_HDR_SIZE);
1795 if (!hdr) {
1796 pr_err("%s: Prepend Header failed\n", __func__);
1797 release_pkt(pkt);
1798 return -ENOMEM;
1799 }
1800 hdr->version = IPC_ROUTER_VERSION;
1801 hdr->type = IPC_ROUTER_CTRL_CMD_DATA;
1802 hdr->src_node_id = src->this_port.node_id;
1803 hdr->src_port_id = src->this_port.port_id;
1804 hdr->size = pkt->length;
1805 hdr->confirm_rx = 0;
1806 hdr->dst_node_id = IPC_ROUTER_NID_LOCAL;
1807 hdr->dst_port_id = port_id;
1808 pkt->length += IPC_ROUTER_HDR_SIZE;
1809
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06001810 mutex_lock(&local_ports_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001811 port_ptr = msm_ipc_router_lookup_local_port(port_id);
1812 if (!port_ptr) {
1813 pr_err("%s: Local port %d not present\n", __func__, port_id);
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06001814 mutex_unlock(&local_ports_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001815 release_pkt(pkt);
1816 return -ENODEV;
1817 }
1818
1819 mutex_lock(&port_ptr->port_rx_q_lock);
1820 wake_lock(&port_ptr->port_rx_wake_lock);
1821 list_add_tail(&pkt->list, &port_ptr->port_rx_q);
Karthikeyan Ramasubramanian0a801c12013-02-08 13:07:42 -07001822 ret_len = pkt->length;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001823 wake_up(&port_ptr->port_rx_wait_q);
1824 mutex_unlock(&port_ptr->port_rx_q_lock);
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06001825 mutex_unlock(&local_ports_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001826
Karthikeyan Ramasubramanian0a801c12013-02-08 13:07:42 -07001827 return ret_len;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001828}
1829
1830static int msm_ipc_router_write_pkt(struct msm_ipc_port *src,
1831 struct msm_ipc_router_remote_port *rport_ptr,
1832 struct rr_packet *pkt)
1833{
1834 struct sk_buff *head_skb;
1835 struct rr_header *hdr;
1836 struct msm_ipc_router_xprt_info *xprt_info;
1837 struct msm_ipc_routing_table_entry *rt_entry;
1838 int ret;
1839 DEFINE_WAIT(__wait);
1840
1841 if (!rport_ptr || !src || !pkt)
1842 return -EINVAL;
1843
1844 head_skb = skb_peek(pkt->pkt_fragment_q);
Karthikeyan Ramasubramanian9024dd82011-12-19 18:44:19 -07001845 if (!head_skb) {
1846 pr_err("%s: pkt_fragment_q is empty\n", __func__);
1847 return -EINVAL;
1848 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001849 hdr = (struct rr_header *)skb_push(head_skb, IPC_ROUTER_HDR_SIZE);
1850 if (!hdr) {
1851 pr_err("%s: Prepend Header failed\n", __func__);
1852 return -ENOMEM;
1853 }
1854 hdr->version = IPC_ROUTER_VERSION;
1855 hdr->type = IPC_ROUTER_CTRL_CMD_DATA;
1856 hdr->src_node_id = src->this_port.node_id;
1857 hdr->src_port_id = src->this_port.port_id;
1858 hdr->size = pkt->length;
1859 hdr->confirm_rx = 0;
1860 hdr->dst_node_id = rport_ptr->node_id;
1861 hdr->dst_port_id = rport_ptr->port_id;
1862 pkt->length += IPC_ROUTER_HDR_SIZE;
1863
1864 for (;;) {
1865 prepare_to_wait(&rport_ptr->quota_wait, &__wait,
1866 TASK_INTERRUPTIBLE);
1867 mutex_lock(&rport_ptr->quota_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001868 if (rport_ptr->restart_state != RESTART_NORMAL)
1869 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001870 if (rport_ptr->tx_quota_cnt <
1871 IPC_ROUTER_DEFAULT_RX_QUOTA)
1872 break;
1873 if (signal_pending(current))
1874 break;
1875 mutex_unlock(&rport_ptr->quota_lock);
1876 schedule();
1877 }
1878 finish_wait(&rport_ptr->quota_wait, &__wait);
1879
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001880 if (rport_ptr->restart_state != RESTART_NORMAL) {
1881 mutex_unlock(&rport_ptr->quota_lock);
1882 return -ENETRESET;
1883 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001884 if (signal_pending(current)) {
1885 mutex_unlock(&rport_ptr->quota_lock);
1886 return -ERESTARTSYS;
1887 }
1888 rport_ptr->tx_quota_cnt++;
1889 if (rport_ptr->tx_quota_cnt == IPC_ROUTER_DEFAULT_RX_QUOTA)
1890 hdr->confirm_rx = 1;
1891 mutex_unlock(&rport_ptr->quota_lock);
1892
1893 mutex_lock(&routing_table_lock);
1894 rt_entry = lookup_routing_table(hdr->dst_node_id);
1895 if (!rt_entry || !rt_entry->xprt_info) {
1896 mutex_unlock(&routing_table_lock);
1897 pr_err("%s: Remote node %d not up\n",
1898 __func__, hdr->dst_node_id);
1899 return -ENODEV;
1900 }
1901 mutex_lock(&rt_entry->lock);
1902 xprt_info = rt_entry->xprt_info;
1903 mutex_lock(&xprt_info->tx_lock);
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -07001904 ret = xprt_info->xprt->write(pkt, pkt->length, xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001905 mutex_unlock(&xprt_info->tx_lock);
1906 mutex_unlock(&rt_entry->lock);
1907 mutex_unlock(&routing_table_lock);
1908
1909 if (ret < 0) {
1910 pr_err("%s: Write on XPRT failed\n", __func__);
1911 return ret;
1912 }
1913
1914 RAW_HDR("[w rr_h] "
1915 "ver=%i,type=%s,src_nid=%08x,src_port_id=%08x,"
1916 "confirm_rx=%i,size=%3i,dst_pid=%08x,dst_cid=%08x\n",
1917 hdr->version, type_to_str(hdr->type),
1918 hdr->src_node_id, hdr->src_port_id,
1919 hdr->confirm_rx, hdr->size,
1920 hdr->dst_node_id, hdr->dst_port_id);
1921
1922#if defined(CONFIG_MSM_SMD_LOGGING)
1923#if defined(DEBUG)
1924 if (msm_ipc_router_debug_mask & SMEM_LOG) {
1925 smem_log_event((SMEM_LOG_PROC_ID_APPS |
1926 SMEM_LOG_RPC_ROUTER_EVENT_BASE |
1927 IPC_ROUTER_LOG_EVENT_TX),
1928 (hdr->src_node_id << 24) |
1929 (hdr->src_port_id & 0xffffff),
1930 (hdr->dst_node_id << 24) |
1931 (hdr->dst_port_id & 0xffffff),
1932 (hdr->type << 24) | (hdr->confirm_rx << 16) |
1933 (hdr->size & 0xffff));
1934 }
1935#endif
1936#endif
1937
1938 return pkt->length;
1939}
1940
1941int msm_ipc_router_send_to(struct msm_ipc_port *src,
1942 struct sk_buff_head *data,
1943 struct msm_ipc_addr *dest)
1944{
1945 uint32_t dst_node_id = 0, dst_port_id = 0;
1946 struct msm_ipc_server *server;
1947 struct msm_ipc_server_port *server_port;
1948 struct msm_ipc_router_remote_port *rport_ptr = NULL;
1949 struct rr_packet *pkt;
1950 int ret;
1951
1952 if (!src || !data || !dest) {
1953 pr_err("%s: Invalid Parameters\n", __func__);
1954 return -EINVAL;
1955 }
1956
1957 /* Resolve Address*/
1958 if (dest->addrtype == MSM_IPC_ADDR_ID) {
1959 dst_node_id = dest->addr.port_addr.node_id;
1960 dst_port_id = dest->addr.port_addr.port_id;
1961 } else if (dest->addrtype == MSM_IPC_ADDR_NAME) {
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001962 mutex_lock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001963 server = msm_ipc_router_lookup_server(
1964 dest->addr.port_name.service,
1965 dest->addr.port_name.instance,
1966 0, 0);
1967 if (!server) {
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001968 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001969 pr_err("%s: Destination not reachable\n", __func__);
1970 return -ENODEV;
1971 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001972 server_port = list_first_entry(&server->server_port_list,
1973 struct msm_ipc_server_port,
1974 list);
1975 dst_node_id = server_port->server_addr.node_id;
1976 dst_port_id = server_port->server_addr.port_id;
1977 mutex_unlock(&server_list_lock);
1978 }
1979 if (dst_node_id == IPC_ROUTER_NID_LOCAL) {
1980 ret = loopback_data(src, dst_port_id, data);
1981 return ret;
1982 }
1983
1984 /* Achieve Flow control */
1985 rport_ptr = msm_ipc_router_lookup_remote_port(dst_node_id,
1986 dst_port_id);
1987 if (!rport_ptr) {
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001988 pr_err("%s: Could not create remote port\n", __func__);
1989 return -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001990 }
1991
Karthikeyan Ramasubramanian1668cc62012-09-23 22:23:36 -06001992 if (src->check_send_permissions) {
1993 ret = src->check_send_permissions(rport_ptr->sec_rule);
1994 if (ret <= 0) {
1995 pr_err("%s: permission failure for %s\n",
1996 __func__, current->comm);
1997 return -EPERM;
1998 }
1999 }
2000
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002001 pkt = create_pkt(data);
2002 if (!pkt) {
2003 pr_err("%s: Pkt creation failed\n", __func__);
2004 return -ENOMEM;
2005 }
2006
2007 ret = msm_ipc_router_write_pkt(src, rport_ptr, pkt);
2008 release_pkt(pkt);
2009
2010 return ret;
2011}
2012
2013int msm_ipc_router_read(struct msm_ipc_port *port_ptr,
2014 struct sk_buff_head **data,
2015 size_t buf_len)
2016{
2017 struct rr_packet *pkt;
2018 int ret;
2019
2020 if (!port_ptr || !data)
2021 return -EINVAL;
2022
2023 mutex_lock(&port_ptr->port_rx_q_lock);
2024 if (list_empty(&port_ptr->port_rx_q)) {
2025 mutex_unlock(&port_ptr->port_rx_q_lock);
2026 return -EAGAIN;
2027 }
2028
2029 pkt = list_first_entry(&port_ptr->port_rx_q, struct rr_packet, list);
2030 if ((buf_len) && ((pkt->length - IPC_ROUTER_HDR_SIZE) > buf_len)) {
2031 mutex_unlock(&port_ptr->port_rx_q_lock);
2032 return -ETOOSMALL;
2033 }
2034 list_del(&pkt->list);
2035 if (list_empty(&port_ptr->port_rx_q))
2036 wake_unlock(&port_ptr->port_rx_wake_lock);
2037 *data = pkt->pkt_fragment_q;
2038 ret = pkt->length;
2039 kfree(pkt);
2040 mutex_unlock(&port_ptr->port_rx_q_lock);
2041
2042 return ret;
2043}
2044
2045int msm_ipc_router_recv_from(struct msm_ipc_port *port_ptr,
2046 struct sk_buff_head **data,
2047 struct msm_ipc_addr *src,
2048 unsigned long timeout)
2049{
2050 int ret, data_len, align_size;
2051 struct sk_buff *temp_skb;
2052 struct rr_header *hdr = NULL;
2053
2054 if (!port_ptr || !data) {
2055 pr_err("%s: Invalid pointers being passed\n", __func__);
2056 return -EINVAL;
2057 }
2058
2059 *data = NULL;
2060 mutex_lock(&port_ptr->port_rx_q_lock);
2061 while (list_empty(&port_ptr->port_rx_q)) {
2062 mutex_unlock(&port_ptr->port_rx_q_lock);
2063 if (timeout < 0) {
2064 ret = wait_event_interruptible(
2065 port_ptr->port_rx_wait_q,
2066 !list_empty(&port_ptr->port_rx_q));
2067 if (ret)
2068 return ret;
2069 } else if (timeout > 0) {
2070 timeout = wait_event_interruptible_timeout(
2071 port_ptr->port_rx_wait_q,
2072 !list_empty(&port_ptr->port_rx_q),
2073 timeout);
2074 if (timeout < 0)
2075 return -EFAULT;
2076 }
2077 if (timeout == 0)
2078 return -ETIMEDOUT;
2079 mutex_lock(&port_ptr->port_rx_q_lock);
2080 }
2081 mutex_unlock(&port_ptr->port_rx_q_lock);
2082
2083 ret = msm_ipc_router_read(port_ptr, data, 0);
2084 if (ret <= 0 || !(*data))
2085 return ret;
2086
2087 temp_skb = skb_peek(*data);
2088 hdr = (struct rr_header *)(temp_skb->data);
2089 if (src) {
2090 src->addrtype = MSM_IPC_ADDR_ID;
2091 src->addr.port_addr.node_id = hdr->src_node_id;
2092 src->addr.port_addr.port_id = hdr->src_port_id;
2093 }
2094
2095 data_len = hdr->size;
2096 skb_pull(temp_skb, IPC_ROUTER_HDR_SIZE);
2097 align_size = ALIGN_SIZE(data_len);
2098 if (align_size) {
2099 temp_skb = skb_peek_tail(*data);
2100 skb_trim(temp_skb, (temp_skb->len - align_size));
2101 }
2102 return data_len;
2103}
2104
2105struct msm_ipc_port *msm_ipc_router_create_port(
2106 void (*notify)(unsigned event, void *data, void *addr, void *priv),
2107 void *priv)
2108{
2109 struct msm_ipc_port *port_ptr;
2110
2111 port_ptr = msm_ipc_router_create_raw_port(NULL, notify, priv);
2112 if (!port_ptr)
2113 pr_err("%s: port_ptr alloc failed\n", __func__);
2114
2115 return port_ptr;
2116}
2117
2118int msm_ipc_router_close_port(struct msm_ipc_port *port_ptr)
2119{
2120 union rr_control_msg msg;
2121 struct rr_packet *pkt, *temp_pkt;
2122 struct msm_ipc_server *server;
2123
2124 if (!port_ptr)
2125 return -EINVAL;
2126
2127 if (port_ptr->type == SERVER_PORT || port_ptr->type == CLIENT_PORT) {
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06002128 mutex_lock(&local_ports_lock);
2129 list_del(&port_ptr->list);
2130 mutex_unlock(&local_ports_lock);
2131
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002132 if (port_ptr->type == SERVER_PORT) {
2133 msg.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_SERVER;
2134 msg.srv.service = port_ptr->port_name.service;
2135 msg.srv.instance = port_ptr->port_name.instance;
2136 msg.srv.node_id = port_ptr->this_port.node_id;
2137 msg.srv.port_id = port_ptr->this_port.port_id;
2138 RR("x REMOVE_SERVER Name=%d:%08x Id=%d:%08x\n",
2139 msg.srv.service, msg.srv.instance,
2140 msg.srv.node_id, msg.srv.port_id);
Karthikeyan Ramasubramanian25e91872013-01-10 17:09:13 -07002141 broadcast_ctl_msg(&msg);
2142 broadcast_ctl_msg_locally(&msg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002143 }
Karthikeyan Ramasubramanian25e91872013-01-10 17:09:13 -07002144
2145 /*
2146 * Server port could have been a client port earlier.
2147 * Send REMOVE_CLIENT message in either case.
2148 */
2149 msg.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT;
2150 msg.cli.node_id = port_ptr->this_port.node_id;
2151 msg.cli.port_id = port_ptr->this_port.port_id;
2152 RR("x REMOVE_CLIENT id=%d:%08x\n",
2153 msg.cli.node_id, msg.cli.port_id);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002154 broadcast_ctl_msg(&msg);
2155 broadcast_ctl_msg_locally(&msg);
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06002156 } else if (port_ptr->type == CONTROL_PORT) {
2157 mutex_lock(&control_ports_lock);
2158 list_del(&port_ptr->list);
2159 mutex_unlock(&control_ports_lock);
Karthikeyan Ramasubramaniand6dbfae2013-01-16 09:00:28 -07002160 } else if (port_ptr->type == IRSC_PORT) {
2161 mutex_lock(&local_ports_lock);
2162 list_del(&port_ptr->list);
2163 mutex_unlock(&local_ports_lock);
2164 signal_irsc_completion();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002165 }
2166
2167 mutex_lock(&port_ptr->port_rx_q_lock);
2168 list_for_each_entry_safe(pkt, temp_pkt, &port_ptr->port_rx_q, list) {
2169 list_del(&pkt->list);
2170 release_pkt(pkt);
2171 }
2172 mutex_unlock(&port_ptr->port_rx_q_lock);
2173
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002174 if (port_ptr->type == SERVER_PORT) {
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002175 mutex_lock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002176 server = msm_ipc_router_lookup_server(
2177 port_ptr->port_name.service,
2178 port_ptr->port_name.instance,
2179 port_ptr->this_port.node_id,
2180 port_ptr->this_port.port_id);
2181 if (server)
2182 msm_ipc_router_destroy_server(server,
2183 port_ptr->this_port.node_id,
2184 port_ptr->this_port.port_id);
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002185 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002186 }
2187
Karthikeyan Ramasubramaniandd8c3b52011-11-30 16:26:12 -07002188 wake_lock_destroy(&port_ptr->port_rx_wake_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002189 kfree(port_ptr);
2190 return 0;
2191}
2192
2193int msm_ipc_router_get_curr_pkt_size(struct msm_ipc_port *port_ptr)
2194{
2195 struct rr_packet *pkt;
2196 int rc = 0;
2197
2198 if (!port_ptr)
2199 return -EINVAL;
2200
2201 mutex_lock(&port_ptr->port_rx_q_lock);
2202 if (!list_empty(&port_ptr->port_rx_q)) {
2203 pkt = list_first_entry(&port_ptr->port_rx_q,
2204 struct rr_packet, list);
2205 rc = pkt->length;
2206 }
2207 mutex_unlock(&port_ptr->port_rx_q_lock);
2208
2209 return rc;
2210}
2211
2212int msm_ipc_router_bind_control_port(struct msm_ipc_port *port_ptr)
2213{
2214 if (!port_ptr)
2215 return -EINVAL;
2216
2217 mutex_lock(&local_ports_lock);
2218 list_del(&port_ptr->list);
2219 mutex_unlock(&local_ports_lock);
2220 port_ptr->type = CONTROL_PORT;
2221 mutex_lock(&control_ports_lock);
2222 list_add_tail(&port_ptr->list, &control_ports);
2223 mutex_unlock(&control_ports_lock);
2224
2225 return 0;
2226}
2227
2228int msm_ipc_router_lookup_server_name(struct msm_ipc_port_name *srv_name,
Flemmard122bb162013-05-22 20:33:47 -07002229#ifdef CONFIG_MACH_HTC
2230 struct msm_ipc_port_addr *srv_info,
2231#else
Karthikeyan Ramasubramaniandfde01b2012-06-12 14:25:13 -06002232 struct msm_ipc_server_info *srv_info,
Flemmard122bb162013-05-22 20:33:47 -07002233#endif
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002234 int num_entries_in_array,
2235 uint32_t lookup_mask)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002236{
2237 struct msm_ipc_server *server;
2238 struct msm_ipc_server_port *server_port;
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002239 int key, i = 0; /*num_entries_found*/
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002240
2241 if (!srv_name) {
2242 pr_err("%s: Invalid srv_name\n", __func__);
2243 return -EINVAL;
2244 }
2245
Karthikeyan Ramasubramaniandfde01b2012-06-12 14:25:13 -06002246 if (num_entries_in_array && !srv_info) {
2247 pr_err("%s: srv_info NULL\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002248 return -EINVAL;
2249 }
2250
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002251 mutex_lock(&server_list_lock);
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002252 if (!lookup_mask)
2253 lookup_mask = 0xFFFFFFFF;
Flemmard122bb162013-05-22 20:33:47 -07002254#ifdef CONFIG_MACH_HTC
2255 for (key = 0; key < SRV_HASH_SIZE; key++)
2256#else
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002257 key = (srv_name->service & (SRV_HASH_SIZE - 1));
Flemmard122bb162013-05-22 20:33:47 -07002258#endif
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002259 list_for_each_entry(server, &server_list[key], list) {
2260 if ((server->name.service != srv_name->service) ||
2261 ((server->name.instance & lookup_mask) !=
2262 srv_name->instance))
2263 continue;
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002264
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002265 list_for_each_entry(server_port,
2266 &server->server_port_list, list) {
2267 if (i < num_entries_in_array) {
2268 srv_info[i].node_id =
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002269 server_port->server_addr.node_id;
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002270 srv_info[i].port_id =
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002271 server_port->server_addr.port_id;
Flemmard122bb162013-05-22 20:33:47 -07002272#ifndef CONFIG_MACH_HTC
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002273 srv_info[i].service = server->name.service;
2274 srv_info[i].instance = server->name.instance;
Flemmard122bb162013-05-22 20:33:47 -07002275#endif
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002276 }
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002277 i++;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002278 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002279 }
2280 mutex_unlock(&server_list_lock);
2281
2282 return i;
2283}
2284
2285int msm_ipc_router_close(void)
2286{
2287 struct msm_ipc_router_xprt_info *xprt_info, *tmp_xprt_info;
2288
2289 mutex_lock(&xprt_info_list_lock);
2290 list_for_each_entry_safe(xprt_info, tmp_xprt_info,
2291 &xprt_info_list, list) {
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -07002292 xprt_info->xprt->close(xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002293 list_del(&xprt_info->list);
2294 kfree(xprt_info);
2295 }
2296 mutex_unlock(&xprt_info_list_lock);
2297 return 0;
2298}
2299
2300#if defined(CONFIG_DEBUG_FS)
2301static int dump_routing_table(char *buf, int max)
2302{
2303 int i = 0, j;
2304 struct msm_ipc_routing_table_entry *rt_entry;
2305
2306 for (j = 0; j < RT_HASH_SIZE; j++) {
2307 mutex_lock(&routing_table_lock);
2308 list_for_each_entry(rt_entry, &routing_table[j], list) {
2309 mutex_lock(&rt_entry->lock);
2310 i += scnprintf(buf + i, max - i,
2311 "Node Id: 0x%08x\n", rt_entry->node_id);
Karthikeyan Ramasubramanianc1a4e3a2012-09-10 16:10:24 -06002312 if (rt_entry->node_id == IPC_ROUTER_NID_LOCAL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002313 i += scnprintf(buf + i, max - i,
2314 "XPRT Name: Loopback\n");
2315 i += scnprintf(buf + i, max - i,
2316 "Next Hop: %d\n", rt_entry->node_id);
2317 } else {
2318 i += scnprintf(buf + i, max - i,
2319 "XPRT Name: %s\n",
2320 rt_entry->xprt_info->xprt->name);
2321 i += scnprintf(buf + i, max - i,
2322 "Next Hop: 0x%08x\n",
2323 rt_entry->xprt_info->remote_node_id);
2324 }
2325 i += scnprintf(buf + i, max - i, "\n");
2326 mutex_unlock(&rt_entry->lock);
2327 }
2328 mutex_unlock(&routing_table_lock);
2329 }
2330
2331 return i;
2332}
2333
2334static int dump_xprt_info(char *buf, int max)
2335{
2336 int i = 0;
2337 struct msm_ipc_router_xprt_info *xprt_info;
2338
2339 mutex_lock(&xprt_info_list_lock);
2340 list_for_each_entry(xprt_info, &xprt_info_list, list) {
2341 i += scnprintf(buf + i, max - i, "XPRT Name: %s\n",
2342 xprt_info->xprt->name);
2343 i += scnprintf(buf + i, max - i, "Link Id: %d\n",
2344 xprt_info->xprt->link_id);
2345 i += scnprintf(buf + i, max - i, "Initialized: %s\n",
2346 (xprt_info->initialized ? "Y" : "N"));
2347 i += scnprintf(buf + i, max - i, "Remote Node Id: 0x%08x\n",
2348 xprt_info->remote_node_id);
2349 i += scnprintf(buf + i, max - i, "\n");
2350 }
2351 mutex_unlock(&xprt_info_list_lock);
2352
2353 return i;
2354}
2355
2356static int dump_servers(char *buf, int max)
2357{
2358 int i = 0, j;
2359 struct msm_ipc_server *server;
2360 struct msm_ipc_server_port *server_port;
2361
2362 mutex_lock(&server_list_lock);
2363 for (j = 0; j < SRV_HASH_SIZE; j++) {
2364 list_for_each_entry(server, &server_list[j], list) {
2365 list_for_each_entry(server_port,
2366 &server->server_port_list,
2367 list) {
2368 i += scnprintf(buf + i, max - i, "Service: "
2369 "0x%08x\n", server->name.service);
2370 i += scnprintf(buf + i, max - i, "Instance: "
2371 "0x%08x\n", server->name.instance);
2372 i += scnprintf(buf + i, max - i,
2373 "Node_id: 0x%08x\n",
2374 server_port->server_addr.node_id);
2375 i += scnprintf(buf + i, max - i,
2376 "Port_id: 0x%08x\n",
2377 server_port->server_addr.port_id);
2378 i += scnprintf(buf + i, max - i, "\n");
2379 }
2380 }
2381 }
2382 mutex_unlock(&server_list_lock);
2383
2384 return i;
2385}
2386
2387static int dump_remote_ports(char *buf, int max)
2388{
2389 int i = 0, j, k;
2390 struct msm_ipc_router_remote_port *rport_ptr;
2391 struct msm_ipc_routing_table_entry *rt_entry;
2392
2393 for (j = 0; j < RT_HASH_SIZE; j++) {
2394 mutex_lock(&routing_table_lock);
2395 list_for_each_entry(rt_entry, &routing_table[j], list) {
2396 mutex_lock(&rt_entry->lock);
2397 for (k = 0; k < RP_HASH_SIZE; k++) {
2398 list_for_each_entry(rport_ptr,
2399 &rt_entry->remote_port_list[k],
2400 list) {
2401 i += scnprintf(buf + i, max - i,
2402 "Node_id: 0x%08x\n",
2403 rport_ptr->node_id);
2404 i += scnprintf(buf + i, max - i,
2405 "Port_id: 0x%08x\n",
2406 rport_ptr->port_id);
2407 i += scnprintf(buf + i, max - i,
2408 "Quota_cnt: %d\n",
2409 rport_ptr->tx_quota_cnt);
2410 i += scnprintf(buf + i, max - i, "\n");
2411 }
2412 }
2413 mutex_unlock(&rt_entry->lock);
2414 }
2415 mutex_unlock(&routing_table_lock);
2416 }
2417
2418 return i;
2419}
2420
2421static int dump_control_ports(char *buf, int max)
2422{
2423 int i = 0;
2424 struct msm_ipc_port *port_ptr;
2425
2426 mutex_lock(&control_ports_lock);
2427 list_for_each_entry(port_ptr, &control_ports, list) {
2428 i += scnprintf(buf + i, max - i, "Node_id: 0x%08x\n",
2429 port_ptr->this_port.node_id);
2430 i += scnprintf(buf + i, max - i, "Port_id: 0x%08x\n",
2431 port_ptr->this_port.port_id);
2432 i += scnprintf(buf + i, max - i, "\n");
2433 }
2434 mutex_unlock(&control_ports_lock);
2435
2436 return i;
2437}
2438
2439static int dump_local_ports(char *buf, int max)
2440{
2441 int i = 0, j;
2442 unsigned long flags;
2443 struct msm_ipc_port *port_ptr;
2444
2445 mutex_lock(&local_ports_lock);
2446 for (j = 0; j < LP_HASH_SIZE; j++) {
2447 list_for_each_entry(port_ptr, &local_ports[j], list) {
2448 spin_lock_irqsave(&port_ptr->port_lock, flags);
2449 i += scnprintf(buf + i, max - i, "Node_id: 0x%08x\n",
2450 port_ptr->this_port.node_id);
2451 i += scnprintf(buf + i, max - i, "Port_id: 0x%08x\n",
2452 port_ptr->this_port.port_id);
2453 i += scnprintf(buf + i, max - i, "# pkts tx'd %d\n",
2454 port_ptr->num_tx);
2455 i += scnprintf(buf + i, max - i, "# pkts rx'd %d\n",
2456 port_ptr->num_rx);
2457 i += scnprintf(buf + i, max - i, "# bytes tx'd %ld\n",
2458 port_ptr->num_tx_bytes);
2459 i += scnprintf(buf + i, max - i, "# bytes rx'd %ld\n",
2460 port_ptr->num_rx_bytes);
2461 spin_unlock_irqrestore(&port_ptr->port_lock, flags);
2462 i += scnprintf(buf + i, max - i, "\n");
2463 }
2464 }
2465 mutex_unlock(&local_ports_lock);
2466
2467 return i;
2468}
2469
2470#define DEBUG_BUFMAX 4096
2471static char debug_buffer[DEBUG_BUFMAX];
2472
2473static ssize_t debug_read(struct file *file, char __user *buf,
2474 size_t count, loff_t *ppos)
2475{
2476 int (*fill)(char *buf, int max) = file->private_data;
2477 int bsize = fill(debug_buffer, DEBUG_BUFMAX);
2478 return simple_read_from_buffer(buf, count, ppos, debug_buffer, bsize);
2479}
2480
2481static int debug_open(struct inode *inode, struct file *file)
2482{
2483 file->private_data = inode->i_private;
2484 return 0;
2485}
2486
2487static const struct file_operations debug_ops = {
2488 .read = debug_read,
2489 .open = debug_open,
2490};
2491
2492static void debug_create(const char *name, mode_t mode,
2493 struct dentry *dent,
2494 int (*fill)(char *buf, int max))
2495{
2496 debugfs_create_file(name, mode, dent, fill, &debug_ops);
2497}
2498
2499static void debugfs_init(void)
2500{
2501 struct dentry *dent;
2502
2503 dent = debugfs_create_dir("msm_ipc_router", 0);
2504 if (IS_ERR(dent))
2505 return;
2506
2507 debug_create("dump_local_ports", 0444, dent,
2508 dump_local_ports);
2509 debug_create("dump_remote_ports", 0444, dent,
2510 dump_remote_ports);
2511 debug_create("dump_control_ports", 0444, dent,
2512 dump_control_ports);
2513 debug_create("dump_servers", 0444, dent,
2514 dump_servers);
2515 debug_create("dump_xprt_info", 0444, dent,
2516 dump_xprt_info);
2517 debug_create("dump_routing_table", 0444, dent,
2518 dump_routing_table);
2519}
2520
2521#else
2522static void debugfs_init(void) {}
2523#endif
2524
2525static int msm_ipc_router_add_xprt(struct msm_ipc_router_xprt *xprt)
2526{
2527 struct msm_ipc_router_xprt_info *xprt_info;
2528 struct msm_ipc_routing_table_entry *rt_entry;
2529
2530 xprt_info = kmalloc(sizeof(struct msm_ipc_router_xprt_info),
2531 GFP_KERNEL);
2532 if (!xprt_info)
2533 return -ENOMEM;
2534
2535 xprt_info->xprt = xprt;
2536 xprt_info->initialized = 0;
2537 xprt_info->remote_node_id = -1;
2538 INIT_LIST_HEAD(&xprt_info->pkt_list);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002539 mutex_init(&xprt_info->rx_lock);
2540 mutex_init(&xprt_info->tx_lock);
2541 wake_lock_init(&xprt_info->wakelock,
2542 WAKE_LOCK_SUSPEND, xprt->name);
2543 xprt_info->need_len = 0;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002544 xprt_info->abort_data_read = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002545 INIT_WORK(&xprt_info->read_data, do_read_data);
2546 INIT_LIST_HEAD(&xprt_info->list);
2547
2548 xprt_info->workqueue = create_singlethread_workqueue(xprt->name);
2549 if (!xprt_info->workqueue) {
2550 kfree(xprt_info);
2551 return -ENOMEM;
2552 }
2553
2554 if (!strcmp(xprt->name, "msm_ipc_router_loopback_xprt")) {
2555 xprt_info->remote_node_id = IPC_ROUTER_NID_LOCAL;
2556 xprt_info->initialized = 1;
2557 }
2558
2559 mutex_lock(&xprt_info_list_lock);
2560 list_add_tail(&xprt_info->list, &xprt_info_list);
2561 mutex_unlock(&xprt_info_list_lock);
2562
2563 mutex_lock(&routing_table_lock);
2564 if (!routing_table_inited) {
2565 init_routing_table();
2566 rt_entry = alloc_routing_table_entry(IPC_ROUTER_NID_LOCAL);
2567 add_routing_table_entry(rt_entry);
2568 routing_table_inited = 1;
2569 }
2570 mutex_unlock(&routing_table_lock);
2571
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002572 xprt->priv = xprt_info;
2573
2574 return 0;
2575}
2576
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002577static void msm_ipc_router_remove_xprt(struct msm_ipc_router_xprt *xprt)
2578{
2579 struct msm_ipc_router_xprt_info *xprt_info;
2580
2581 if (xprt && xprt->priv) {
2582 xprt_info = xprt->priv;
2583
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06002584 mutex_lock(&xprt_info->rx_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002585 xprt_info->abort_data_read = 1;
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06002586 mutex_unlock(&xprt_info->rx_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002587
2588 mutex_lock(&xprt_info_list_lock);
2589 list_del(&xprt_info->list);
2590 mutex_unlock(&xprt_info_list_lock);
2591
2592 flush_workqueue(xprt_info->workqueue);
2593 destroy_workqueue(xprt_info->workqueue);
2594 wake_lock_destroy(&xprt_info->wakelock);
2595
2596 xprt->priv = 0;
2597 kfree(xprt_info);
2598 }
2599}
2600
2601
2602struct msm_ipc_router_xprt_work {
2603 struct msm_ipc_router_xprt *xprt;
2604 struct work_struct work;
2605};
2606
2607static void xprt_open_worker(struct work_struct *work)
2608{
2609 struct msm_ipc_router_xprt_work *xprt_work =
2610 container_of(work, struct msm_ipc_router_xprt_work, work);
2611
2612 msm_ipc_router_add_xprt(xprt_work->xprt);
2613 kfree(xprt_work);
2614}
2615
2616static void xprt_close_worker(struct work_struct *work)
2617{
2618 struct msm_ipc_router_xprt_work *xprt_work =
2619 container_of(work, struct msm_ipc_router_xprt_work, work);
2620
2621 modem_reset_cleanup(xprt_work->xprt->priv);
2622 msm_ipc_router_remove_xprt(xprt_work->xprt);
2623
2624 if (atomic_dec_return(&pending_close_count) == 0)
2625 wake_up(&subsystem_restart_wait);
2626
2627 kfree(xprt_work);
2628}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002629
2630void msm_ipc_router_xprt_notify(struct msm_ipc_router_xprt *xprt,
2631 unsigned event,
2632 void *data)
2633{
2634 struct msm_ipc_router_xprt_info *xprt_info = xprt->priv;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002635 struct msm_ipc_router_xprt_work *xprt_work;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002636 struct rr_packet *pkt;
Karthikeyan Ramasubramanian4af9f7c2011-09-30 15:55:18 -06002637 unsigned long ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002638
Karthikeyan Ramasubramanian4af9f7c2011-09-30 15:55:18 -06002639 if (!msm_ipc_router_workqueue) {
2640 ret = wait_for_completion_timeout(&msm_ipc_local_router_up,
2641 IPC_ROUTER_INIT_TIMEOUT);
2642 if (!ret || !msm_ipc_router_workqueue) {
2643 pr_err("%s: IPC Router not initialized\n", __func__);
2644 return;
2645 }
2646 }
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002647
2648 switch (event) {
2649 case IPC_ROUTER_XPRT_EVENT_OPEN:
2650 D("open event for '%s'\n", xprt->name);
2651 xprt_work = kmalloc(sizeof(struct msm_ipc_router_xprt_work),
2652 GFP_ATOMIC);
2653 xprt_work->xprt = xprt;
2654 INIT_WORK(&xprt_work->work, xprt_open_worker);
2655 queue_work(msm_ipc_router_workqueue, &xprt_work->work);
2656 break;
2657
2658 case IPC_ROUTER_XPRT_EVENT_CLOSE:
2659 D("close event for '%s'\n", xprt->name);
2660 atomic_inc(&pending_close_count);
2661 xprt_work = kmalloc(sizeof(struct msm_ipc_router_xprt_work),
2662 GFP_ATOMIC);
2663 xprt_work->xprt = xprt;
2664 INIT_WORK(&xprt_work->work, xprt_close_worker);
2665 queue_work(msm_ipc_router_workqueue, &xprt_work->work);
2666 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002667 }
2668
2669 if (!data)
2670 return;
2671
2672 while (!xprt_info) {
2673 msleep(100);
2674 xprt_info = xprt->priv;
2675 }
2676
2677 pkt = clone_pkt((struct rr_packet *)data);
2678 if (!pkt)
2679 return;
2680
2681 mutex_lock(&xprt_info->rx_lock);
2682 list_add_tail(&pkt->list, &xprt_info->pkt_list);
2683 wake_lock(&xprt_info->wakelock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002684 mutex_unlock(&xprt_info->rx_lock);
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06002685 queue_work(xprt_info->workqueue, &xprt_info->read_data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002686}
2687
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002688static int modem_restart_notifier_cb(struct notifier_block *this,
2689 unsigned long code,
2690 void *data);
2691static struct notifier_block msm_ipc_router_nb = {
2692 .notifier_call = modem_restart_notifier_cb,
2693};
2694
2695static int modem_restart_notifier_cb(struct notifier_block *this,
2696 unsigned long code,
2697 void *data)
2698{
2699 switch (code) {
2700 case SUBSYS_BEFORE_SHUTDOWN:
2701 D("%s: SUBSYS_BEFORE_SHUTDOWN\n", __func__);
2702 break;
2703
2704 case SUBSYS_BEFORE_POWERUP:
2705 D("%s: waiting for RPC restart to complete\n", __func__);
2706 wait_event(subsystem_restart_wait,
2707 atomic_read(&pending_close_count) == 0);
2708 D("%s: finished restart wait\n", __func__);
2709 break;
2710
2711 default:
2712 break;
2713 }
2714
2715 return NOTIFY_DONE;
2716}
2717
2718static void *restart_notifier_handle;
2719static __init int msm_ipc_router_modem_restart_late_init(void)
2720{
2721 restart_notifier_handle = subsys_notif_register_notifier("modem",
2722 &msm_ipc_router_nb);
2723 return 0;
2724}
2725late_initcall(msm_ipc_router_modem_restart_late_init);
2726
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002727static int __init msm_ipc_router_init(void)
2728{
2729 int i, ret;
2730 struct msm_ipc_routing_table_entry *rt_entry;
2731
2732 msm_ipc_router_debug_mask |= SMEM_LOG;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002733 msm_ipc_router_workqueue =
2734 create_singlethread_workqueue("msm_ipc_router");
2735 if (!msm_ipc_router_workqueue)
2736 return -ENOMEM;
2737
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002738 debugfs_init();
2739
2740 for (i = 0; i < SRV_HASH_SIZE; i++)
2741 INIT_LIST_HEAD(&server_list[i]);
2742
2743 for (i = 0; i < LP_HASH_SIZE; i++)
2744 INIT_LIST_HEAD(&local_ports[i]);
2745
2746 mutex_lock(&routing_table_lock);
2747 if (!routing_table_inited) {
2748 init_routing_table();
2749 rt_entry = alloc_routing_table_entry(IPC_ROUTER_NID_LOCAL);
2750 add_routing_table_entry(rt_entry);
2751 routing_table_inited = 1;
2752 }
2753 mutex_unlock(&routing_table_lock);
2754
2755 init_waitqueue_head(&newserver_wait);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002756 init_waitqueue_head(&subsystem_restart_wait);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002757 ret = msm_ipc_router_init_sockets();
2758 if (ret < 0)
2759 pr_err("%s: Init sockets failed\n", __func__);
2760
Karthikeyan Ramasubramanian1668cc62012-09-23 22:23:36 -06002761 ret = msm_ipc_router_security_init();
2762 if (ret < 0)
2763 pr_err("%s: Security Init failed\n", __func__);
2764
Karthikeyan Ramasubramanian4af9f7c2011-09-30 15:55:18 -06002765 complete_all(&msm_ipc_local_router_up);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002766 return ret;
2767}
2768
2769module_init(msm_ipc_router_init);
2770MODULE_DESCRIPTION("MSM IPC Router");
2771MODULE_LICENSE("GPL v2");