blob: fde43b026c55dfcc30a6dc785dcdc105630d323e [file] [log] [blame]
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -07001/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#define DEBUG
14
15#include <linux/slab.h>
16#include <linux/module.h>
17#include <linux/kernel.h>
18#include <linux/string.h>
19#include <linux/errno.h>
20#include <linux/init.h>
21#include <linux/types.h>
22#include <linux/delay.h>
23#include <linux/err.h>
24#include <linux/sched.h>
25#include <linux/poll.h>
26#include <linux/wakelock.h>
27#include <linux/platform_device.h>
28#include <linux/uaccess.h>
29#include <linux/debugfs.h>
30
31#include <asm/uaccess.h>
32#include <asm/byteorder.h>
33
34#include <mach/smem_log.h>
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -060035#include <mach/subsystem_notif.h>
Karthikeyan Ramasubramanianefc493b2012-07-12 10:25:49 -060036#include <mach/msm_ipc_router.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070037
38#include "ipc_router.h"
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -060039#include "modem_notifier.h"
Karthikeyan Ramasubramanian5b502d3642012-09-23 22:23:36 -060040#include "msm_ipc_router_security.h"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070041
42enum {
43 SMEM_LOG = 1U << 0,
44 RTR_DBG = 1U << 1,
45 R2R_MSG = 1U << 2,
46 R2R_RAW = 1U << 3,
47 NTFY_MSG = 1U << 4,
48 R2R_RAW_HDR = 1U << 5,
49};
50
51static int msm_ipc_router_debug_mask;
52module_param_named(debug_mask, msm_ipc_router_debug_mask,
53 int, S_IRUGO | S_IWUSR | S_IWGRP);
54
55#define DIAG(x...) pr_info("[RR] ERROR " x)
56
57#if defined(DEBUG)
58#define D(x...) do { \
59if (msm_ipc_router_debug_mask & RTR_DBG) \
60 pr_info(x); \
61} while (0)
62
63#define RR(x...) do { \
64if (msm_ipc_router_debug_mask & R2R_MSG) \
65 pr_info("[RR] "x); \
66} while (0)
67
68#define RAW(x...) do { \
69if (msm_ipc_router_debug_mask & R2R_RAW) \
70 pr_info("[RAW] "x); \
71} while (0)
72
73#define NTFY(x...) do { \
74if (msm_ipc_router_debug_mask & NTFY_MSG) \
75 pr_info("[NOTIFY] "x); \
76} while (0)
77
78#define RAW_HDR(x...) do { \
79if (msm_ipc_router_debug_mask & R2R_RAW_HDR) \
80 pr_info("[HDR] "x); \
81} while (0)
82#else
83#define D(x...) do { } while (0)
84#define RR(x...) do { } while (0)
85#define RAW(x...) do { } while (0)
86#define RAW_HDR(x...) do { } while (0)
87#define NTFY(x...) do { } while (0)
88#endif
89
90#define IPC_ROUTER_LOG_EVENT_ERROR 0x10
91#define IPC_ROUTER_LOG_EVENT_TX 0x11
92#define IPC_ROUTER_LOG_EVENT_RX 0x12
93
94static LIST_HEAD(control_ports);
95static DEFINE_MUTEX(control_ports_lock);
96
97#define LP_HASH_SIZE 32
98static struct list_head local_ports[LP_HASH_SIZE];
99static DEFINE_MUTEX(local_ports_lock);
100
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -0600101/*
102 * Server info is organized as a hash table. The server's service ID is
103 * used to index into the hash table. The instance ID of most of the servers
104 * are 1 or 2. The service IDs are well distributed compared to the instance
105 * IDs and hence choosing service ID to index into this hash table optimizes
106 * the hash table operations like add, lookup, destroy.
107 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700108#define SRV_HASH_SIZE 32
109static struct list_head server_list[SRV_HASH_SIZE];
110static DEFINE_MUTEX(server_list_lock);
111static wait_queue_head_t newserver_wait;
112
113struct msm_ipc_server {
114 struct list_head list;
115 struct msm_ipc_port_name name;
Karthikeyan Ramasubramanianefc493b2012-07-12 10:25:49 -0600116 char pdev_name[32];
117 int next_pdev_id;
Karthikeyan Ramasubramanian5b502d3642012-09-23 22:23:36 -0600118 int synced_sec_rule;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700119 struct list_head server_port_list;
120};
121
122struct msm_ipc_server_port {
123 struct list_head list;
Karthikeyan Ramasubramanianefc493b2012-07-12 10:25:49 -0600124 struct platform_device pdev;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700125 struct msm_ipc_port_addr server_addr;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600126 struct msm_ipc_router_xprt_info *xprt_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700127};
128
129#define RP_HASH_SIZE 32
130struct msm_ipc_router_remote_port {
131 struct list_head list;
132 uint32_t node_id;
133 uint32_t port_id;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600134 uint32_t restart_state;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700135 wait_queue_head_t quota_wait;
136 uint32_t tx_quota_cnt;
137 struct mutex quota_lock;
Karthikeyan Ramasubramanian5b502d3642012-09-23 22:23:36 -0600138 void *sec_rule;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700139};
140
141struct msm_ipc_router_xprt_info {
142 struct list_head list;
143 struct msm_ipc_router_xprt *xprt;
144 uint32_t remote_node_id;
145 uint32_t initialized;
146 struct list_head pkt_list;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700147 struct wake_lock wakelock;
148 struct mutex rx_lock;
149 struct mutex tx_lock;
150 uint32_t need_len;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600151 uint32_t abort_data_read;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700152 struct work_struct read_data;
153 struct workqueue_struct *workqueue;
154};
155
156#define RT_HASH_SIZE 4
157struct msm_ipc_routing_table_entry {
158 struct list_head list;
159 uint32_t node_id;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600160 uint32_t neighbor_node_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700161 struct list_head remote_port_list[RP_HASH_SIZE];
162 struct msm_ipc_router_xprt_info *xprt_info;
163 struct mutex lock;
164 unsigned long num_tx_bytes;
165 unsigned long num_rx_bytes;
166};
167
168static struct list_head routing_table[RT_HASH_SIZE];
169static DEFINE_MUTEX(routing_table_lock);
170static int routing_table_inited;
171
172static LIST_HEAD(msm_ipc_board_dev_list);
173static DEFINE_MUTEX(msm_ipc_board_dev_list_lock);
174
175static void do_read_data(struct work_struct *work);
176
177#define RR_STATE_IDLE 0
178#define RR_STATE_HEADER 1
179#define RR_STATE_BODY 2
180#define RR_STATE_ERROR 3
181
182#define RESTART_NORMAL 0
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600183#define RESTART_PEND 1
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700184
185/* State for remote ep following restart */
186#define RESTART_QUOTA_ABORT 1
187
188static LIST_HEAD(xprt_info_list);
189static DEFINE_MUTEX(xprt_info_list_lock);
190
Karthikeyan Ramasubramanian4af9f7c2011-09-30 15:55:18 -0600191static DECLARE_COMPLETION(msm_ipc_local_router_up);
192#define IPC_ROUTER_INIT_TIMEOUT (10 * HZ)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700193
194static uint32_t next_port_id;
195static DEFINE_MUTEX(next_port_id_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600196static atomic_t pending_close_count = ATOMIC_INIT(0);
197static wait_queue_head_t subsystem_restart_wait;
198static struct workqueue_struct *msm_ipc_router_workqueue;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700199
200enum {
201 CLIENT_PORT,
202 SERVER_PORT,
203 CONTROL_PORT,
204};
205
206enum {
207 DOWN,
208 UP,
209};
210
211static void init_routing_table(void)
212{
213 int i;
214 for (i = 0; i < RT_HASH_SIZE; i++)
215 INIT_LIST_HEAD(&routing_table[i]);
216}
217
218static struct msm_ipc_routing_table_entry *alloc_routing_table_entry(
219 uint32_t node_id)
220{
221 int i;
222 struct msm_ipc_routing_table_entry *rt_entry;
223
224 rt_entry = kmalloc(sizeof(struct msm_ipc_routing_table_entry),
225 GFP_KERNEL);
226 if (!rt_entry) {
227 pr_err("%s: rt_entry allocation failed for %d\n",
228 __func__, node_id);
229 return NULL;
230 }
231
232 for (i = 0; i < RP_HASH_SIZE; i++)
233 INIT_LIST_HEAD(&rt_entry->remote_port_list[i]);
234
235 mutex_init(&rt_entry->lock);
236 rt_entry->node_id = node_id;
237 rt_entry->xprt_info = NULL;
238 return rt_entry;
239}
240
241/*Please take routing_table_lock before calling this function*/
242static int add_routing_table_entry(
243 struct msm_ipc_routing_table_entry *rt_entry)
244{
245 uint32_t key;
246
247 if (!rt_entry)
248 return -EINVAL;
249
250 key = (rt_entry->node_id % RT_HASH_SIZE);
251 list_add_tail(&rt_entry->list, &routing_table[key]);
252 return 0;
253}
254
255/*Please take routing_table_lock before calling this function*/
256static struct msm_ipc_routing_table_entry *lookup_routing_table(
257 uint32_t node_id)
258{
259 uint32_t key = (node_id % RT_HASH_SIZE);
260 struct msm_ipc_routing_table_entry *rt_entry;
261
262 list_for_each_entry(rt_entry, &routing_table[key], list) {
263 if (rt_entry->node_id == node_id)
264 return rt_entry;
265 }
266 return NULL;
267}
268
269struct rr_packet *rr_read(struct msm_ipc_router_xprt_info *xprt_info)
270{
271 struct rr_packet *temp_pkt;
272
273 if (!xprt_info)
274 return NULL;
275
276 mutex_lock(&xprt_info->rx_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600277 if (xprt_info->abort_data_read) {
278 mutex_unlock(&xprt_info->rx_lock);
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -0600279 pr_err("%s detected SSR & exiting now\n",
280 xprt_info->xprt->name);
281 return NULL;
282 }
283
284 if (list_empty(&xprt_info->pkt_list)) {
285 mutex_unlock(&xprt_info->rx_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600286 return NULL;
287 }
288
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700289 temp_pkt = list_first_entry(&xprt_info->pkt_list,
290 struct rr_packet, list);
291 list_del(&temp_pkt->list);
292 if (list_empty(&xprt_info->pkt_list))
293 wake_unlock(&xprt_info->wakelock);
294 mutex_unlock(&xprt_info->rx_lock);
295 return temp_pkt;
296}
297
298struct rr_packet *clone_pkt(struct rr_packet *pkt)
299{
300 struct rr_packet *cloned_pkt;
301 struct sk_buff *temp_skb, *cloned_skb;
302 struct sk_buff_head *pkt_fragment_q;
303
304 cloned_pkt = kzalloc(sizeof(struct rr_packet), GFP_KERNEL);
305 if (!cloned_pkt) {
306 pr_err("%s: failure\n", __func__);
307 return NULL;
308 }
309
310 pkt_fragment_q = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
311 if (!pkt_fragment_q) {
312 pr_err("%s: pkt_frag_q alloc failure\n", __func__);
313 kfree(cloned_pkt);
314 return NULL;
315 }
316 skb_queue_head_init(pkt_fragment_q);
317
318 skb_queue_walk(pkt->pkt_fragment_q, temp_skb) {
319 cloned_skb = skb_clone(temp_skb, GFP_KERNEL);
320 if (!cloned_skb)
321 goto fail_clone;
322 skb_queue_tail(pkt_fragment_q, cloned_skb);
323 }
324 cloned_pkt->pkt_fragment_q = pkt_fragment_q;
325 cloned_pkt->length = pkt->length;
326 return cloned_pkt;
327
328fail_clone:
329 while (!skb_queue_empty(pkt_fragment_q)) {
330 temp_skb = skb_dequeue(pkt_fragment_q);
331 kfree_skb(temp_skb);
332 }
333 kfree(pkt_fragment_q);
334 kfree(cloned_pkt);
335 return NULL;
336}
337
338struct rr_packet *create_pkt(struct sk_buff_head *data)
339{
340 struct rr_packet *pkt;
341 struct sk_buff *temp_skb;
342
343 pkt = kzalloc(sizeof(struct rr_packet), GFP_KERNEL);
344 if (!pkt) {
345 pr_err("%s: failure\n", __func__);
346 return NULL;
347 }
348
349 pkt->pkt_fragment_q = data;
350 skb_queue_walk(pkt->pkt_fragment_q, temp_skb)
351 pkt->length += temp_skb->len;
352 return pkt;
353}
354
355void release_pkt(struct rr_packet *pkt)
356{
357 struct sk_buff *temp_skb;
358
359 if (!pkt)
360 return;
361
362 if (!pkt->pkt_fragment_q) {
363 kfree(pkt);
364 return;
365 }
366
367 while (!skb_queue_empty(pkt->pkt_fragment_q)) {
368 temp_skb = skb_dequeue(pkt->pkt_fragment_q);
369 kfree_skb(temp_skb);
370 }
371 kfree(pkt->pkt_fragment_q);
372 kfree(pkt);
373 return;
374}
375
Karthikeyan Ramasubramanianefc493b2012-07-12 10:25:49 -0600376static struct sk_buff_head *msm_ipc_router_buf_to_skb(void *buf,
377 unsigned int buf_len)
378{
379 struct sk_buff_head *skb_head;
380 struct sk_buff *skb;
381 int first = 1, offset = 0;
382 int skb_size, data_size;
383 void *data;
384
385 skb_head = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
386 if (!skb_head) {
387 pr_err("%s: Couldnot allocate skb_head\n", __func__);
388 return NULL;
389 }
390 skb_queue_head_init(skb_head);
391
392 data_size = buf_len;
393 while (offset != buf_len) {
394 skb_size = data_size;
395 if (first)
396 skb_size += IPC_ROUTER_HDR_SIZE;
397
398 skb = alloc_skb(skb_size, GFP_KERNEL);
399 if (!skb) {
400 if (skb_size <= (PAGE_SIZE/2)) {
401 pr_err("%s: cannot allocate skb\n", __func__);
402 goto buf_to_skb_error;
403 }
404 data_size = data_size / 2;
405 continue;
406 }
407
408 if (first) {
409 skb_reserve(skb, IPC_ROUTER_HDR_SIZE);
410 first = 0;
411 }
412
413 data = skb_put(skb, data_size);
414 memcpy(skb->data, buf + offset, data_size);
415 skb_queue_tail(skb_head, skb);
416 offset += data_size;
417 data_size = buf_len - offset;
418 }
419 return skb_head;
420
421buf_to_skb_error:
422 while (!skb_queue_empty(skb_head)) {
423 skb = skb_dequeue(skb_head);
424 kfree_skb(skb);
425 }
426 kfree(skb_head);
427 return NULL;
428}
429
430static void *msm_ipc_router_skb_to_buf(struct sk_buff_head *skb_head,
431 unsigned int len)
432{
433 struct sk_buff *temp;
434 int offset = 0, buf_len = 0, copy_len;
435 void *buf;
436
437 if (!skb_head) {
438 pr_err("%s: NULL skb_head\n", __func__);
439 return NULL;
440 }
441
442 temp = skb_peek(skb_head);
443 buf_len = len;
444 buf = kmalloc(buf_len, GFP_KERNEL);
445 if (!buf) {
446 pr_err("%s: cannot allocate buf\n", __func__);
447 return NULL;
448 }
449 skb_queue_walk(skb_head, temp) {
450 copy_len = buf_len < temp->len ? buf_len : temp->len;
451 memcpy(buf + offset, temp->data, copy_len);
452 offset += copy_len;
453 buf_len -= copy_len;
454 }
455 return buf;
456}
457
458static void msm_ipc_router_free_skb(struct sk_buff_head *skb_head)
459{
460 struct sk_buff *temp_skb;
461
462 if (!skb_head)
463 return;
464
465 while (!skb_queue_empty(skb_head)) {
466 temp_skb = skb_dequeue(skb_head);
467 kfree_skb(temp_skb);
468 }
469 kfree(skb_head);
470}
471
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700472static int post_control_ports(struct rr_packet *pkt)
473{
474 struct msm_ipc_port *port_ptr;
475 struct rr_packet *cloned_pkt;
476
477 if (!pkt)
478 return -EINVAL;
479
480 mutex_lock(&control_ports_lock);
481 list_for_each_entry(port_ptr, &control_ports, list) {
482 mutex_lock(&port_ptr->port_rx_q_lock);
483 cloned_pkt = clone_pkt(pkt);
484 wake_lock(&port_ptr->port_rx_wake_lock);
485 list_add_tail(&cloned_pkt->list, &port_ptr->port_rx_q);
486 wake_up(&port_ptr->port_rx_wait_q);
487 mutex_unlock(&port_ptr->port_rx_q_lock);
488 }
489 mutex_unlock(&control_ports_lock);
490 return 0;
491}
492
493static uint32_t allocate_port_id(void)
494{
495 uint32_t port_id = 0, prev_port_id, key;
496 struct msm_ipc_port *port_ptr;
497
498 mutex_lock(&next_port_id_lock);
499 prev_port_id = next_port_id;
500 mutex_lock(&local_ports_lock);
501 do {
502 next_port_id++;
503 if ((next_port_id & 0xFFFFFFFE) == 0xFFFFFFFE)
504 next_port_id = 1;
505
506 key = (next_port_id & (LP_HASH_SIZE - 1));
507 if (list_empty(&local_ports[key])) {
508 port_id = next_port_id;
509 break;
510 }
511 list_for_each_entry(port_ptr, &local_ports[key], list) {
512 if (port_ptr->this_port.port_id == next_port_id) {
513 port_id = next_port_id;
514 break;
515 }
516 }
517 if (!port_id) {
518 port_id = next_port_id;
519 break;
520 }
521 port_id = 0;
522 } while (next_port_id != prev_port_id);
523 mutex_unlock(&local_ports_lock);
524 mutex_unlock(&next_port_id_lock);
525
526 return port_id;
527}
528
529void msm_ipc_router_add_local_port(struct msm_ipc_port *port_ptr)
530{
531 uint32_t key;
532
533 if (!port_ptr)
534 return;
535
536 key = (port_ptr->this_port.port_id & (LP_HASH_SIZE - 1));
537 mutex_lock(&local_ports_lock);
538 list_add_tail(&port_ptr->list, &local_ports[key]);
539 mutex_unlock(&local_ports_lock);
540}
541
542struct msm_ipc_port *msm_ipc_router_create_raw_port(void *endpoint,
Karthikeyan Ramasubramanianefc493b2012-07-12 10:25:49 -0600543 void (*notify)(unsigned event, void *priv),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700544 void *priv)
545{
546 struct msm_ipc_port *port_ptr;
547
548 port_ptr = kzalloc(sizeof(struct msm_ipc_port), GFP_KERNEL);
549 if (!port_ptr)
550 return NULL;
551
552 port_ptr->this_port.node_id = IPC_ROUTER_NID_LOCAL;
553 port_ptr->this_port.port_id = allocate_port_id();
554 if (!port_ptr->this_port.port_id) {
555 pr_err("%s: All port ids are in use\n", __func__);
556 kfree(port_ptr);
557 return NULL;
558 }
559
560 spin_lock_init(&port_ptr->port_lock);
561 INIT_LIST_HEAD(&port_ptr->incomplete);
562 mutex_init(&port_ptr->incomplete_lock);
563 INIT_LIST_HEAD(&port_ptr->port_rx_q);
564 mutex_init(&port_ptr->port_rx_q_lock);
565 init_waitqueue_head(&port_ptr->port_rx_wait_q);
Karthikeyan Ramasubramanianb4aeeb92012-03-13 12:31:43 -0600566 snprintf(port_ptr->rx_wakelock_name, MAX_WAKELOCK_NAME_SZ,
567 "msm_ipc_read%08x:%08x",
568 port_ptr->this_port.node_id,
569 port_ptr->this_port.port_id);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700570 wake_lock_init(&port_ptr->port_rx_wake_lock,
Karthikeyan Ramasubramanianb4aeeb92012-03-13 12:31:43 -0600571 WAKE_LOCK_SUSPEND, port_ptr->rx_wakelock_name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700572
573 port_ptr->endpoint = endpoint;
574 port_ptr->notify = notify;
575 port_ptr->priv = priv;
576
577 msm_ipc_router_add_local_port(port_ptr);
578 return port_ptr;
579}
580
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -0600581/*
582 * Should be called with local_ports_lock locked
583 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700584static struct msm_ipc_port *msm_ipc_router_lookup_local_port(uint32_t port_id)
585{
586 int key = (port_id & (LP_HASH_SIZE - 1));
587 struct msm_ipc_port *port_ptr;
588
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700589 list_for_each_entry(port_ptr, &local_ports[key], list) {
590 if (port_ptr->this_port.port_id == port_id) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700591 return port_ptr;
592 }
593 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700594 return NULL;
595}
596
597static struct msm_ipc_router_remote_port *msm_ipc_router_lookup_remote_port(
598 uint32_t node_id,
599 uint32_t port_id)
600{
601 struct msm_ipc_router_remote_port *rport_ptr;
602 struct msm_ipc_routing_table_entry *rt_entry;
603 int key = (port_id & (RP_HASH_SIZE - 1));
604
605 mutex_lock(&routing_table_lock);
606 rt_entry = lookup_routing_table(node_id);
607 if (!rt_entry) {
608 mutex_unlock(&routing_table_lock);
609 pr_err("%s: Node is not up\n", __func__);
610 return NULL;
611 }
612
613 mutex_lock(&rt_entry->lock);
614 list_for_each_entry(rport_ptr,
615 &rt_entry->remote_port_list[key], list) {
616 if (rport_ptr->port_id == port_id) {
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600617 if (rport_ptr->restart_state != RESTART_NORMAL)
618 rport_ptr = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700619 mutex_unlock(&rt_entry->lock);
620 mutex_unlock(&routing_table_lock);
621 return rport_ptr;
622 }
623 }
624 mutex_unlock(&rt_entry->lock);
625 mutex_unlock(&routing_table_lock);
626 return NULL;
627}
628
629static struct msm_ipc_router_remote_port *msm_ipc_router_create_remote_port(
630 uint32_t node_id,
631 uint32_t port_id)
632{
633 struct msm_ipc_router_remote_port *rport_ptr;
634 struct msm_ipc_routing_table_entry *rt_entry;
635 int key = (port_id & (RP_HASH_SIZE - 1));
636
637 mutex_lock(&routing_table_lock);
638 rt_entry = lookup_routing_table(node_id);
639 if (!rt_entry) {
640 mutex_unlock(&routing_table_lock);
641 pr_err("%s: Node is not up\n", __func__);
642 return NULL;
643 }
644
645 mutex_lock(&rt_entry->lock);
646 rport_ptr = kmalloc(sizeof(struct msm_ipc_router_remote_port),
647 GFP_KERNEL);
648 if (!rport_ptr) {
649 mutex_unlock(&rt_entry->lock);
650 mutex_unlock(&routing_table_lock);
651 pr_err("%s: Remote port alloc failed\n", __func__);
652 return NULL;
653 }
654 rport_ptr->port_id = port_id;
655 rport_ptr->node_id = node_id;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600656 rport_ptr->restart_state = RESTART_NORMAL;
Karthikeyan Ramasubramanian5b502d3642012-09-23 22:23:36 -0600657 rport_ptr->sec_rule = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700658 rport_ptr->tx_quota_cnt = 0;
659 init_waitqueue_head(&rport_ptr->quota_wait);
660 mutex_init(&rport_ptr->quota_lock);
661 list_add_tail(&rport_ptr->list,
662 &rt_entry->remote_port_list[key]);
663 mutex_unlock(&rt_entry->lock);
664 mutex_unlock(&routing_table_lock);
665 return rport_ptr;
666}
667
668static void msm_ipc_router_destroy_remote_port(
669 struct msm_ipc_router_remote_port *rport_ptr)
670{
671 uint32_t node_id;
672 struct msm_ipc_routing_table_entry *rt_entry;
673
674 if (!rport_ptr)
675 return;
676
677 node_id = rport_ptr->node_id;
678 mutex_lock(&routing_table_lock);
679 rt_entry = lookup_routing_table(node_id);
680 if (!rt_entry) {
681 mutex_unlock(&routing_table_lock);
682 pr_err("%s: Node %d is not up\n", __func__, node_id);
683 return;
684 }
685
686 mutex_lock(&rt_entry->lock);
687 list_del(&rport_ptr->list);
688 kfree(rport_ptr);
689 mutex_unlock(&rt_entry->lock);
690 mutex_unlock(&routing_table_lock);
691 return;
692}
693
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -0600694/**
695 * msm_ipc_router_lookup_server() - Lookup server information
696 * @service: Service ID of the server info to be looked up.
697 * @instance: Instance ID of the server info to be looked up.
698 * @node_id: Node/Processor ID in which the server is hosted.
699 * @port_id: Port ID within the node in which the server is hosted.
700 *
701 * @return: If found Pointer to server structure, else NULL.
702 *
703 * Note1: Lock the server_list_lock before accessing this function.
704 * Note2: If the <node_id:port_id> are <0:0>, then the lookup is restricted
705 * to <service:instance>. Used only when a client wants to send a
706 * message to any QMI server.
707 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700708static struct msm_ipc_server *msm_ipc_router_lookup_server(
709 uint32_t service,
710 uint32_t instance,
711 uint32_t node_id,
712 uint32_t port_id)
713{
714 struct msm_ipc_server *server;
715 struct msm_ipc_server_port *server_port;
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -0600716 int key = (service & (SRV_HASH_SIZE - 1));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700717
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700718 list_for_each_entry(server, &server_list[key], list) {
719 if ((server->name.service != service) ||
720 (server->name.instance != instance))
721 continue;
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -0600722 if ((node_id == 0) && (port_id == 0))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700723 return server;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700724 list_for_each_entry(server_port, &server->server_port_list,
725 list) {
726 if ((server_port->server_addr.node_id == node_id) &&
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -0600727 (server_port->server_addr.port_id == port_id))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700728 return server;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700729 }
730 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700731 return NULL;
732}
733
Karthikeyan Ramasubramanianefc493b2012-07-12 10:25:49 -0600734static void dummy_release(struct device *dev)
735{
736}
737
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -0600738/**
739 * msm_ipc_router_create_server() - Add server info to hash table
740 * @service: Service ID of the server info to be created.
741 * @instance: Instance ID of the server info to be created.
742 * @node_id: Node/Processor ID in which the server is hosted.
743 * @port_id: Port ID within the node in which the server is hosted.
744 * @xprt_info: XPRT through which the node hosting the server is reached.
745 *
746 * @return: Pointer to server structure on success, else NULL.
747 *
748 * This function adds the server info to the hash table. If the same
749 * server(i.e. <service_id:instance_id>) is hosted in different nodes,
750 * they are maintained as list of "server_port" under "server" structure.
751 * Note: Lock the server_list_lock before accessing this function.
752 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700753static struct msm_ipc_server *msm_ipc_router_create_server(
754 uint32_t service,
755 uint32_t instance,
756 uint32_t node_id,
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600757 uint32_t port_id,
758 struct msm_ipc_router_xprt_info *xprt_info)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700759{
760 struct msm_ipc_server *server = NULL;
761 struct msm_ipc_server_port *server_port;
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -0600762 int key = (service & (SRV_HASH_SIZE - 1));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700763
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700764 list_for_each_entry(server, &server_list[key], list) {
765 if ((server->name.service == service) &&
766 (server->name.instance == instance))
767 goto create_srv_port;
768 }
769
Karthikeyan Ramasubramanianefc493b2012-07-12 10:25:49 -0600770 server = kzalloc(sizeof(struct msm_ipc_server), GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700771 if (!server) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700772 pr_err("%s: Server allocation failed\n", __func__);
773 return NULL;
774 }
775 server->name.service = service;
776 server->name.instance = instance;
Karthikeyan Ramasubramanian5b502d3642012-09-23 22:23:36 -0600777 server->synced_sec_rule = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700778 INIT_LIST_HEAD(&server->server_port_list);
779 list_add_tail(&server->list, &server_list[key]);
Karthikeyan Ramasubramanianefc493b2012-07-12 10:25:49 -0600780 scnprintf(server->pdev_name, sizeof(server->pdev_name),
781 "QMI%08x:%08x", service, instance);
782 server->next_pdev_id = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700783
784create_srv_port:
Karthikeyan Ramasubramanianefc493b2012-07-12 10:25:49 -0600785 server_port = kzalloc(sizeof(struct msm_ipc_server_port), GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700786 if (!server_port) {
787 if (list_empty(&server->server_port_list)) {
788 list_del(&server->list);
789 kfree(server);
790 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700791 pr_err("%s: Server Port allocation failed\n", __func__);
792 return NULL;
793 }
794 server_port->server_addr.node_id = node_id;
795 server_port->server_addr.port_id = port_id;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600796 server_port->xprt_info = xprt_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700797 list_add_tail(&server_port->list, &server->server_port_list);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700798
Karthikeyan Ramasubramanianefc493b2012-07-12 10:25:49 -0600799 server_port->pdev.name = server->pdev_name;
800 server_port->pdev.id = server->next_pdev_id++;
801 server_port->pdev.dev.release = dummy_release;
802 platform_device_register(&server_port->pdev);
803
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700804 return server;
805}
806
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -0600807/**
808 * msm_ipc_router_destroy_server() - Remove server info from hash table
809 * @server: Server info to be removed.
810 * @node_id: Node/Processor ID in which the server is hosted.
811 * @port_id: Port ID within the node in which the server is hosted.
812 *
813 * This function removes the server_port identified using <node_id:port_id>
814 * from the server structure. If the server_port list under server structure
815 * is empty after removal, then remove the server structure from the server
816 * hash table.
817 * Note: Lock the server_list_lock before accessing this function.
818 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700819static void msm_ipc_router_destroy_server(struct msm_ipc_server *server,
820 uint32_t node_id, uint32_t port_id)
821{
822 struct msm_ipc_server_port *server_port;
823
824 if (!server)
825 return;
826
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700827 list_for_each_entry(server_port, &server->server_port_list, list) {
828 if ((server_port->server_addr.node_id == node_id) &&
829 (server_port->server_addr.port_id == port_id))
830 break;
831 }
832 if (server_port) {
Karthikeyan Ramasubramanianefc493b2012-07-12 10:25:49 -0600833 platform_device_unregister(&server_port->pdev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700834 list_del(&server_port->list);
835 kfree(server_port);
836 }
837 if (list_empty(&server->server_port_list)) {
838 list_del(&server->list);
839 kfree(server);
840 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700841 return;
842}
843
844static int msm_ipc_router_send_control_msg(
845 struct msm_ipc_router_xprt_info *xprt_info,
846 union rr_control_msg *msg)
847{
848 struct rr_packet *pkt;
849 struct sk_buff *ipc_rtr_pkt;
850 struct rr_header *hdr;
851 int pkt_size;
852 void *data;
853 struct sk_buff_head *pkt_fragment_q;
854 int ret;
855
856 if (!xprt_info || ((msg->cmd != IPC_ROUTER_CTRL_CMD_HELLO) &&
857 !xprt_info->initialized)) {
858 pr_err("%s: xprt_info not initialized\n", __func__);
859 return -EINVAL;
860 }
861
862 if (xprt_info->remote_node_id == IPC_ROUTER_NID_LOCAL)
863 return 0;
864
865 pkt = kzalloc(sizeof(struct rr_packet), GFP_KERNEL);
866 if (!pkt) {
867 pr_err("%s: pkt alloc failed\n", __func__);
868 return -ENOMEM;
869 }
870
871 pkt_fragment_q = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
872 if (!pkt_fragment_q) {
873 pr_err("%s: pkt_fragment_q alloc failed\n", __func__);
874 kfree(pkt);
875 return -ENOMEM;
876 }
877 skb_queue_head_init(pkt_fragment_q);
878
879 pkt_size = IPC_ROUTER_HDR_SIZE + sizeof(*msg);
880 ipc_rtr_pkt = alloc_skb(pkt_size, GFP_KERNEL);
881 if (!ipc_rtr_pkt) {
882 pr_err("%s: ipc_rtr_pkt alloc failed\n", __func__);
883 kfree(pkt_fragment_q);
884 kfree(pkt);
885 return -ENOMEM;
886 }
887
888 skb_reserve(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
889 data = skb_put(ipc_rtr_pkt, sizeof(*msg));
890 memcpy(data, msg, sizeof(*msg));
891 hdr = (struct rr_header *)skb_push(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
892 if (!hdr) {
893 pr_err("%s: skb_push failed\n", __func__);
894 kfree_skb(ipc_rtr_pkt);
895 kfree(pkt_fragment_q);
896 kfree(pkt);
897 return -ENOMEM;
898 }
899
900 hdr->version = IPC_ROUTER_VERSION;
901 hdr->type = msg->cmd;
902 hdr->src_node_id = IPC_ROUTER_NID_LOCAL;
903 hdr->src_port_id = IPC_ROUTER_ADDRESS;
904 hdr->confirm_rx = 0;
905 hdr->size = sizeof(*msg);
906 hdr->dst_node_id = xprt_info->remote_node_id;
907 hdr->dst_port_id = IPC_ROUTER_ADDRESS;
908 skb_queue_tail(pkt_fragment_q, ipc_rtr_pkt);
909 pkt->pkt_fragment_q = pkt_fragment_q;
910 pkt->length = pkt_size;
911
912 mutex_lock(&xprt_info->tx_lock);
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700913 ret = xprt_info->xprt->write(pkt, pkt_size, xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700914 mutex_unlock(&xprt_info->tx_lock);
915
916 release_pkt(pkt);
917 return ret;
918}
919
Karthikeyan Ramasubramaniana2b7fdb2012-10-23 13:12:44 -0600920static int msm_ipc_router_send_server_list(uint32_t node_id,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700921 struct msm_ipc_router_xprt_info *xprt_info)
922{
923 union rr_control_msg ctl;
924 struct msm_ipc_server *server;
925 struct msm_ipc_server_port *server_port;
926 int i;
927
928 if (!xprt_info || !xprt_info->initialized) {
929 pr_err("%s: Xprt info not initialized\n", __func__);
930 return -EINVAL;
931 }
932
933 ctl.cmd = IPC_ROUTER_CTRL_CMD_NEW_SERVER;
934
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700935 for (i = 0; i < SRV_HASH_SIZE; i++) {
936 list_for_each_entry(server, &server_list[i], list) {
937 ctl.srv.service = server->name.service;
938 ctl.srv.instance = server->name.instance;
939 list_for_each_entry(server_port,
940 &server->server_port_list, list) {
Karthikeyan Ramasubramaniana2b7fdb2012-10-23 13:12:44 -0600941 if (server_port->server_addr.node_id !=
942 node_id)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700943 continue;
944
945 ctl.srv.node_id =
946 server_port->server_addr.node_id;
947 ctl.srv.port_id =
948 server_port->server_addr.port_id;
949 msm_ipc_router_send_control_msg(xprt_info,
950 &ctl);
951 }
952 }
953 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700954
955 return 0;
956}
957
958#if defined(DEBUG)
959static char *type_to_str(int i)
960{
961 switch (i) {
962 case IPC_ROUTER_CTRL_CMD_DATA:
963 return "data ";
964 case IPC_ROUTER_CTRL_CMD_HELLO:
965 return "hello ";
966 case IPC_ROUTER_CTRL_CMD_BYE:
967 return "bye ";
968 case IPC_ROUTER_CTRL_CMD_NEW_SERVER:
969 return "new_srvr";
970 case IPC_ROUTER_CTRL_CMD_REMOVE_SERVER:
971 return "rmv_srvr";
972 case IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT:
973 return "rmv_clnt";
974 case IPC_ROUTER_CTRL_CMD_RESUME_TX:
975 return "resum_tx";
976 case IPC_ROUTER_CTRL_CMD_EXIT:
977 return "cmd_exit";
978 default:
979 return "invalid";
980 }
981}
982#endif
983
984static int broadcast_ctl_msg_locally(union rr_control_msg *msg)
985{
986 struct rr_packet *pkt;
987 struct sk_buff *ipc_rtr_pkt;
988 struct rr_header *hdr;
989 int pkt_size;
990 void *data;
991 struct sk_buff_head *pkt_fragment_q;
992 int ret;
993
994 pkt = kzalloc(sizeof(struct rr_packet), GFP_KERNEL);
995 if (!pkt) {
996 pr_err("%s: pkt alloc failed\n", __func__);
997 return -ENOMEM;
998 }
999
1000 pkt_fragment_q = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
1001 if (!pkt_fragment_q) {
1002 pr_err("%s: pkt_fragment_q alloc failed\n", __func__);
1003 kfree(pkt);
1004 return -ENOMEM;
1005 }
1006 skb_queue_head_init(pkt_fragment_q);
1007
1008 pkt_size = IPC_ROUTER_HDR_SIZE + sizeof(*msg);
1009 ipc_rtr_pkt = alloc_skb(pkt_size, GFP_KERNEL);
1010 if (!ipc_rtr_pkt) {
1011 pr_err("%s: ipc_rtr_pkt alloc failed\n", __func__);
1012 kfree(pkt_fragment_q);
1013 kfree(pkt);
1014 return -ENOMEM;
1015 }
1016
1017 skb_reserve(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
1018 data = skb_put(ipc_rtr_pkt, sizeof(*msg));
1019 memcpy(data, msg, sizeof(*msg));
1020 hdr = (struct rr_header *)skb_push(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
1021 if (!hdr) {
1022 pr_err("%s: skb_push failed\n", __func__);
1023 kfree_skb(ipc_rtr_pkt);
1024 kfree(pkt_fragment_q);
1025 kfree(pkt);
1026 return -ENOMEM;
1027 }
1028 hdr->version = IPC_ROUTER_VERSION;
1029 hdr->type = msg->cmd;
1030 hdr->src_node_id = IPC_ROUTER_NID_LOCAL;
1031 hdr->src_port_id = IPC_ROUTER_ADDRESS;
1032 hdr->confirm_rx = 0;
1033 hdr->size = sizeof(*msg);
1034 hdr->dst_node_id = IPC_ROUTER_NID_LOCAL;
1035 hdr->dst_port_id = IPC_ROUTER_ADDRESS;
1036 skb_queue_tail(pkt_fragment_q, ipc_rtr_pkt);
1037 pkt->pkt_fragment_q = pkt_fragment_q;
1038 pkt->length = pkt_size;
1039
1040 ret = post_control_ports(pkt);
1041 release_pkt(pkt);
1042 return ret;
1043}
1044
1045static int broadcast_ctl_msg(union rr_control_msg *ctl)
1046{
1047 struct msm_ipc_router_xprt_info *xprt_info;
1048
1049 mutex_lock(&xprt_info_list_lock);
1050 list_for_each_entry(xprt_info, &xprt_info_list, list) {
1051 msm_ipc_router_send_control_msg(xprt_info, ctl);
1052 }
1053 mutex_unlock(&xprt_info_list_lock);
1054
1055 return 0;
1056}
1057
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001058static int relay_ctl_msg(struct msm_ipc_router_xprt_info *xprt_info,
1059 union rr_control_msg *ctl)
1060{
1061 struct msm_ipc_router_xprt_info *fwd_xprt_info;
1062
1063 if (!xprt_info || !ctl)
1064 return -EINVAL;
1065
1066 mutex_lock(&xprt_info_list_lock);
1067 list_for_each_entry(fwd_xprt_info, &xprt_info_list, list) {
1068 if (xprt_info->xprt->link_id != fwd_xprt_info->xprt->link_id)
1069 msm_ipc_router_send_control_msg(fwd_xprt_info, ctl);
1070 }
1071 mutex_unlock(&xprt_info_list_lock);
1072
1073 return 0;
1074}
1075
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001076static int relay_msg(struct msm_ipc_router_xprt_info *xprt_info,
1077 struct rr_packet *pkt)
1078{
1079 struct msm_ipc_router_xprt_info *fwd_xprt_info;
1080
1081 if (!xprt_info || !pkt)
1082 return -EINVAL;
1083
1084 mutex_lock(&xprt_info_list_lock);
1085 list_for_each_entry(fwd_xprt_info, &xprt_info_list, list) {
1086 mutex_lock(&fwd_xprt_info->tx_lock);
1087 if (xprt_info->xprt->link_id != fwd_xprt_info->xprt->link_id)
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -07001088 fwd_xprt_info->xprt->write(pkt, pkt->length,
1089 fwd_xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001090 mutex_unlock(&fwd_xprt_info->tx_lock);
1091 }
1092 mutex_unlock(&xprt_info_list_lock);
1093 return 0;
1094}
1095
1096static int forward_msg(struct msm_ipc_router_xprt_info *xprt_info,
1097 struct rr_packet *pkt)
1098{
1099 uint32_t dst_node_id;
1100 struct sk_buff *head_pkt;
1101 struct rr_header *hdr;
1102 struct msm_ipc_router_xprt_info *fwd_xprt_info;
1103 struct msm_ipc_routing_table_entry *rt_entry;
1104
1105 if (!xprt_info || !pkt)
1106 return -EINVAL;
1107
1108 head_pkt = skb_peek(pkt->pkt_fragment_q);
1109 if (!head_pkt)
1110 return -EINVAL;
1111
1112 hdr = (struct rr_header *)head_pkt->data;
1113 dst_node_id = hdr->dst_node_id;
1114 mutex_lock(&routing_table_lock);
1115 rt_entry = lookup_routing_table(dst_node_id);
1116 if (!(rt_entry) || !(rt_entry->xprt_info)) {
1117 mutex_unlock(&routing_table_lock);
1118 pr_err("%s: Routing table not initialized\n", __func__);
1119 return -ENODEV;
1120 }
1121
1122 mutex_lock(&rt_entry->lock);
1123 fwd_xprt_info = rt_entry->xprt_info;
1124 mutex_lock(&fwd_xprt_info->tx_lock);
1125 if (xprt_info->remote_node_id == fwd_xprt_info->remote_node_id) {
1126 mutex_unlock(&fwd_xprt_info->tx_lock);
1127 mutex_unlock(&rt_entry->lock);
1128 mutex_unlock(&routing_table_lock);
1129 pr_err("%s: Discarding Command to route back\n", __func__);
1130 return -EINVAL;
1131 }
1132
1133 if (xprt_info->xprt->link_id == fwd_xprt_info->xprt->link_id) {
1134 mutex_unlock(&fwd_xprt_info->tx_lock);
1135 mutex_unlock(&rt_entry->lock);
1136 mutex_unlock(&routing_table_lock);
1137 pr_err("%s: DST in the same cluster\n", __func__);
1138 return 0;
1139 }
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -07001140 fwd_xprt_info->xprt->write(pkt, pkt->length, fwd_xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001141 mutex_unlock(&fwd_xprt_info->tx_lock);
1142 mutex_unlock(&rt_entry->lock);
1143 mutex_unlock(&routing_table_lock);
1144
1145 return 0;
1146}
1147
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001148static void reset_remote_port_info(uint32_t node_id, uint32_t port_id)
1149{
1150 struct msm_ipc_router_remote_port *rport_ptr;
1151
1152 rport_ptr = msm_ipc_router_lookup_remote_port(node_id, port_id);
1153 if (!rport_ptr) {
1154 pr_err("%s: No such remote port %08x:%08x\n",
1155 __func__, node_id, port_id);
1156 return;
1157 }
1158 mutex_lock(&rport_ptr->quota_lock);
1159 rport_ptr->restart_state = RESTART_PEND;
1160 wake_up(&rport_ptr->quota_wait);
1161 mutex_unlock(&rport_ptr->quota_lock);
1162 return;
1163}
1164
1165static void msm_ipc_cleanup_remote_server_info(
1166 struct msm_ipc_router_xprt_info *xprt_info)
1167{
1168 struct msm_ipc_server *svr, *tmp_svr;
1169 struct msm_ipc_server_port *svr_port, *tmp_svr_port;
1170 int i;
1171 union rr_control_msg ctl;
1172
1173 if (!xprt_info) {
1174 pr_err("%s: Invalid xprt_info\n", __func__);
1175 return;
1176 }
1177
1178 ctl.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_SERVER;
1179 mutex_lock(&server_list_lock);
1180 for (i = 0; i < SRV_HASH_SIZE; i++) {
1181 list_for_each_entry_safe(svr, tmp_svr, &server_list[i], list) {
1182 ctl.srv.service = svr->name.service;
1183 ctl.srv.instance = svr->name.instance;
1184 list_for_each_entry_safe(svr_port, tmp_svr_port,
1185 &svr->server_port_list, list) {
1186 if (svr_port->xprt_info != xprt_info)
1187 continue;
1188 D("Remove server %08x:%08x - %08x:%08x",
1189 ctl.srv.service, ctl.srv.instance,
1190 svr_port->server_addr.node_id,
1191 svr_port->server_addr.port_id);
1192 reset_remote_port_info(
1193 svr_port->server_addr.node_id,
1194 svr_port->server_addr.port_id);
1195 ctl.srv.node_id = svr_port->server_addr.node_id;
1196 ctl.srv.port_id = svr_port->server_addr.port_id;
1197 relay_ctl_msg(xprt_info, &ctl);
1198 broadcast_ctl_msg_locally(&ctl);
Karthikeyan Ramasubramanianefc493b2012-07-12 10:25:49 -06001199 platform_device_unregister(&svr_port->pdev);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001200 list_del(&svr_port->list);
1201 kfree(svr_port);
1202 }
1203 if (list_empty(&svr->server_port_list)) {
1204 list_del(&svr->list);
1205 kfree(svr);
1206 }
1207 }
1208 }
1209 mutex_unlock(&server_list_lock);
1210}
1211
1212static void msm_ipc_cleanup_remote_client_info(
1213 struct msm_ipc_router_xprt_info *xprt_info)
1214{
1215 struct msm_ipc_routing_table_entry *rt_entry;
1216 struct msm_ipc_router_remote_port *rport_ptr;
1217 int i, j;
1218 union rr_control_msg ctl;
1219
1220 if (!xprt_info) {
1221 pr_err("%s: Invalid xprt_info\n", __func__);
1222 return;
1223 }
1224
1225 ctl.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT;
1226 mutex_lock(&routing_table_lock);
1227 for (i = 0; i < RT_HASH_SIZE; i++) {
1228 list_for_each_entry(rt_entry, &routing_table[i], list) {
1229 mutex_lock(&rt_entry->lock);
1230 if (rt_entry->xprt_info != xprt_info) {
1231 mutex_unlock(&rt_entry->lock);
1232 continue;
1233 }
1234 for (j = 0; j < RP_HASH_SIZE; j++) {
1235 list_for_each_entry(rport_ptr,
1236 &rt_entry->remote_port_list[j], list) {
1237 if (rport_ptr->restart_state ==
1238 RESTART_PEND)
1239 continue;
1240 mutex_lock(&rport_ptr->quota_lock);
1241 rport_ptr->restart_state = RESTART_PEND;
1242 wake_up(&rport_ptr->quota_wait);
1243 mutex_unlock(&rport_ptr->quota_lock);
1244 ctl.cli.node_id = rport_ptr->node_id;
1245 ctl.cli.port_id = rport_ptr->port_id;
1246 broadcast_ctl_msg_locally(&ctl);
1247 }
1248 }
1249 mutex_unlock(&rt_entry->lock);
1250 }
1251 }
1252 mutex_unlock(&routing_table_lock);
1253}
1254
1255static void msm_ipc_cleanup_remote_port_info(uint32_t node_id)
1256{
1257 struct msm_ipc_routing_table_entry *rt_entry, *tmp_rt_entry;
1258 struct msm_ipc_router_remote_port *rport_ptr, *tmp_rport_ptr;
1259 int i, j;
1260
1261 mutex_lock(&routing_table_lock);
1262 for (i = 0; i < RT_HASH_SIZE; i++) {
1263 list_for_each_entry_safe(rt_entry, tmp_rt_entry,
1264 &routing_table[i], list) {
1265 mutex_lock(&rt_entry->lock);
1266 if (rt_entry->neighbor_node_id != node_id) {
1267 mutex_unlock(&rt_entry->lock);
1268 continue;
1269 }
1270 for (j = 0; j < RP_HASH_SIZE; j++) {
1271 list_for_each_entry_safe(rport_ptr,
1272 tmp_rport_ptr,
1273 &rt_entry->remote_port_list[j], list) {
1274 list_del(&rport_ptr->list);
1275 kfree(rport_ptr);
1276 }
1277 }
1278 mutex_unlock(&rt_entry->lock);
1279 }
1280 }
1281 mutex_unlock(&routing_table_lock);
1282}
1283
1284static void msm_ipc_cleanup_routing_table(
1285 struct msm_ipc_router_xprt_info *xprt_info)
1286{
1287 int i;
1288 struct msm_ipc_routing_table_entry *rt_entry;
1289
1290 if (!xprt_info) {
1291 pr_err("%s: Invalid xprt_info\n", __func__);
1292 return;
1293 }
1294
1295 mutex_lock(&routing_table_lock);
1296 for (i = 0; i < RT_HASH_SIZE; i++) {
1297 list_for_each_entry(rt_entry, &routing_table[i], list) {
1298 mutex_lock(&rt_entry->lock);
1299 if (rt_entry->xprt_info == xprt_info)
1300 rt_entry->xprt_info = NULL;
1301 mutex_unlock(&rt_entry->lock);
1302 }
1303 }
1304 mutex_unlock(&routing_table_lock);
1305}
1306
1307static void modem_reset_cleanup(struct msm_ipc_router_xprt_info *xprt_info)
1308{
1309
1310 if (!xprt_info) {
1311 pr_err("%s: Invalid xprt_info\n", __func__);
1312 return;
1313 }
1314
1315 msm_ipc_cleanup_remote_server_info(xprt_info);
1316 msm_ipc_cleanup_remote_client_info(xprt_info);
1317 msm_ipc_cleanup_routing_table(xprt_info);
1318}
1319
Karthikeyan Ramasubramanian5b502d3642012-09-23 22:23:36 -06001320/**
1321 * sync_sec_rule() - Synchrnoize the security rule into the server structure
1322 * @server: Server structure where the rule has to be synchronized.
1323 * @rule: Security tule to be synchronized.
1324 *
1325 * This function is used to update the server structure with the security
1326 * rule configured for the <service:instance> corresponding to that server.
1327 */
1328static void sync_sec_rule(struct msm_ipc_server *server, void *rule)
1329{
1330 struct msm_ipc_server_port *server_port;
1331 struct msm_ipc_router_remote_port *rport_ptr = NULL;
1332
1333 list_for_each_entry(server_port, &server->server_port_list, list) {
1334 rport_ptr = msm_ipc_router_lookup_remote_port(
1335 server_port->server_addr.node_id,
1336 server_port->server_addr.port_id);
1337 if (!rport_ptr)
1338 continue;
1339 rport_ptr->sec_rule = rule;
1340 }
1341 server->synced_sec_rule = 1;
1342}
1343
1344/**
1345 * msm_ipc_sync_sec_rule() - Sync the security rule to the service
1346 * @service: Service for which the rule has to be synchronized.
1347 * @instance: Instance for which the rule has to be synchronized.
1348 * @rule: Security rule to be synchronized.
1349 *
1350 * This function is used to syncrhonize the security rule with the server
1351 * hash table, if the user-space script configures the rule after the service
1352 * has come up. This function is used to synchronize the security rule to a
1353 * specific service and optionally a specific instance.
1354 */
1355void msm_ipc_sync_sec_rule(uint32_t service, uint32_t instance, void *rule)
1356{
1357 int key = (service & (SRV_HASH_SIZE - 1));
1358 struct msm_ipc_server *server;
1359
1360 mutex_lock(&server_list_lock);
1361 list_for_each_entry(server, &server_list[key], list) {
1362 if (server->name.service != service)
1363 continue;
1364
1365 if (server->name.instance != instance &&
1366 instance != ALL_INSTANCE)
1367 continue;
1368
1369 /*
1370 * If the rule applies to all instances and if the specific
1371 * instance of a service has a rule synchronized already,
1372 * do not apply the rule for that specific instance.
1373 */
1374 if (instance == ALL_INSTANCE && server->synced_sec_rule)
1375 continue;
1376
1377 sync_sec_rule(server, rule);
1378 }
1379 mutex_unlock(&server_list_lock);
1380}
1381
1382/**
1383 * msm_ipc_sync_default_sec_rule() - Default security rule to all services
1384 * @rule: Security rule to be synchronized.
1385 *
1386 * This function is used to syncrhonize the security rule with the server
1387 * hash table, if the user-space script configures the rule after the service
1388 * has come up. This function is used to synchronize the security rule that
1389 * applies to all services, if the concerned service do not have any rule
1390 * defined.
1391 */
1392void msm_ipc_sync_default_sec_rule(void *rule)
1393{
1394 int key;
1395 struct msm_ipc_server *server;
1396
1397 mutex_lock(&server_list_lock);
1398 for (key = 0; key < SRV_HASH_SIZE; key++) {
1399 list_for_each_entry(server, &server_list[key], list) {
1400 if (server->synced_sec_rule)
1401 continue;
1402
1403 sync_sec_rule(server, rule);
1404 }
1405 }
1406 mutex_unlock(&server_list_lock);
1407}
1408
Karthikeyan Ramasubramaniana2b7fdb2012-10-23 13:12:44 -06001409static int process_hello_msg(struct msm_ipc_router_xprt_info *xprt_info,
1410 struct rr_header *hdr)
1411{
1412 int i, rc = 0;
1413 union rr_control_msg ctl;
1414 struct msm_ipc_routing_table_entry *rt_entry;
1415
1416 if (!hdr)
1417 return -EINVAL;
1418
1419 RR("o HELLO NID %d\n", hdr->src_node_id);
1420
1421 xprt_info->remote_node_id = hdr->src_node_id;
1422 /*
1423 * Find the entry from Routing Table corresponding to Node ID.
1424 * Under SSR, an entry will be found. When the system boots up
1425 * for the 1st time, an entry will not be found and hence allocate
1426 * an entry. Update the entry with the Node ID that it corresponds
1427 * to and the XPRT through which it can be reached.
1428 */
1429 mutex_lock(&routing_table_lock);
1430 rt_entry = lookup_routing_table(hdr->src_node_id);
1431 if (!rt_entry) {
1432 rt_entry = alloc_routing_table_entry(hdr->src_node_id);
1433 if (!rt_entry) {
1434 mutex_unlock(&routing_table_lock);
1435 pr_err("%s: rt_entry allocation failed\n", __func__);
1436 return -ENOMEM;
1437 }
1438 add_routing_table_entry(rt_entry);
1439 }
1440 mutex_lock(&rt_entry->lock);
1441 rt_entry->neighbor_node_id = xprt_info->remote_node_id;
1442 rt_entry->xprt_info = xprt_info;
1443 mutex_unlock(&rt_entry->lock);
1444 mutex_unlock(&routing_table_lock);
1445
1446 /* Cleanup any remote ports, if the node is coming out of reset */
1447 msm_ipc_cleanup_remote_port_info(xprt_info->remote_node_id);
1448
1449 /* Send a reply HELLO message */
1450 memset(&ctl, 0, sizeof(ctl));
1451 ctl.cmd = IPC_ROUTER_CTRL_CMD_HELLO;
1452 rc = msm_ipc_router_send_control_msg(xprt_info, &ctl);
1453 if (rc < 0) {
1454 pr_err("%s: Error sending reply HELLO message\n", __func__);
1455 return rc;
1456 }
1457 xprt_info->initialized = 1;
1458
1459 /*
1460 * Send list of servers from the local node and from nodes
1461 * outside the mesh network in which this XPRT is part of.
1462 */
Karthikeyan Ramasubramanian05066a82012-10-31 15:12:08 -06001463 mutex_lock(&server_list_lock);
Karthikeyan Ramasubramaniana2b7fdb2012-10-23 13:12:44 -06001464 mutex_lock(&routing_table_lock);
1465 for (i = 0; i < RT_HASH_SIZE; i++) {
1466 list_for_each_entry(rt_entry, &routing_table[i], list) {
1467 if ((rt_entry->node_id != IPC_ROUTER_NID_LOCAL) &&
1468 (rt_entry->xprt_info->xprt->link_id ==
1469 xprt_info->xprt->link_id))
1470 continue;
1471 rc = msm_ipc_router_send_server_list(rt_entry->node_id,
1472 xprt_info);
1473 if (rc < 0) {
1474 mutex_unlock(&routing_table_lock);
Karthikeyan Ramasubramanian05066a82012-10-31 15:12:08 -06001475 mutex_unlock(&server_list_lock);
Karthikeyan Ramasubramaniana2b7fdb2012-10-23 13:12:44 -06001476 return rc;
1477 }
1478 }
1479 }
1480 mutex_unlock(&routing_table_lock);
Karthikeyan Ramasubramanian05066a82012-10-31 15:12:08 -06001481 mutex_unlock(&server_list_lock);
Karthikeyan Ramasubramaniana2b7fdb2012-10-23 13:12:44 -06001482 RR("HELLO message processed\n");
1483 return rc;
1484}
1485
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001486static int process_control_msg(struct msm_ipc_router_xprt_info *xprt_info,
1487 struct rr_packet *pkt)
1488{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001489 union rr_control_msg *msg;
1490 struct msm_ipc_router_remote_port *rport_ptr;
1491 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001492 struct sk_buff *temp_ptr;
1493 struct rr_header *hdr;
1494 struct msm_ipc_server *server;
1495 struct msm_ipc_routing_table_entry *rt_entry;
1496
1497 if (pkt->length != (IPC_ROUTER_HDR_SIZE + sizeof(*msg))) {
1498 pr_err("%s: r2r msg size %d != %d\n", __func__, pkt->length,
1499 (IPC_ROUTER_HDR_SIZE + sizeof(*msg)));
1500 return -EINVAL;
1501 }
1502
1503 temp_ptr = skb_peek(pkt->pkt_fragment_q);
Karthikeyan Ramasubramanian9024dd82011-12-19 18:44:19 -07001504 if (!temp_ptr) {
1505 pr_err("%s: pkt_fragment_q is empty\n", __func__);
1506 return -EINVAL;
1507 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001508 hdr = (struct rr_header *)temp_ptr->data;
Karthikeyan Ramasubramanian9024dd82011-12-19 18:44:19 -07001509 if (!hdr) {
1510 pr_err("%s: No data inside the skb\n", __func__);
1511 return -EINVAL;
1512 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001513 msg = (union rr_control_msg *)((char *)hdr + IPC_ROUTER_HDR_SIZE);
1514
1515 switch (msg->cmd) {
1516 case IPC_ROUTER_CTRL_CMD_HELLO:
Karthikeyan Ramasubramaniana2b7fdb2012-10-23 13:12:44 -06001517 rc = process_hello_msg(xprt_info, hdr);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001518 break;
Karthikeyan Ramasubramaniana2b7fdb2012-10-23 13:12:44 -06001519
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001520 case IPC_ROUTER_CTRL_CMD_RESUME_TX:
1521 RR("o RESUME_TX id=%d:%08x\n",
1522 msg->cli.node_id, msg->cli.port_id);
1523
1524 rport_ptr = msm_ipc_router_lookup_remote_port(msg->cli.node_id,
1525 msg->cli.port_id);
1526 if (!rport_ptr) {
1527 pr_err("%s: Unable to resume client\n", __func__);
1528 break;
1529 }
1530 mutex_lock(&rport_ptr->quota_lock);
1531 rport_ptr->tx_quota_cnt = 0;
1532 mutex_unlock(&rport_ptr->quota_lock);
1533 wake_up(&rport_ptr->quota_wait);
1534 break;
1535
1536 case IPC_ROUTER_CTRL_CMD_NEW_SERVER:
1537 if (msg->srv.instance == 0) {
1538 pr_err(
1539 "rpcrouter: Server create rejected, version = 0, "
1540 "service = %08x\n", msg->srv.service);
1541 break;
1542 }
1543
1544 RR("o NEW_SERVER id=%d:%08x service=%08x:%08x\n",
1545 msg->srv.node_id, msg->srv.port_id,
1546 msg->srv.service, msg->srv.instance);
1547
1548 mutex_lock(&routing_table_lock);
1549 rt_entry = lookup_routing_table(msg->srv.node_id);
1550 if (!rt_entry) {
1551 rt_entry = alloc_routing_table_entry(msg->srv.node_id);
1552 if (!rt_entry) {
1553 mutex_unlock(&routing_table_lock);
1554 pr_err("%s: rt_entry allocation failed\n",
1555 __func__);
1556 return -ENOMEM;
1557 }
1558 mutex_lock(&rt_entry->lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001559 rt_entry->neighbor_node_id = xprt_info->remote_node_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001560 rt_entry->xprt_info = xprt_info;
1561 mutex_unlock(&rt_entry->lock);
1562 add_routing_table_entry(rt_entry);
1563 }
1564 mutex_unlock(&routing_table_lock);
1565
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -06001566 mutex_lock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001567 server = msm_ipc_router_lookup_server(msg->srv.service,
1568 msg->srv.instance,
1569 msg->srv.node_id,
1570 msg->srv.port_id);
1571 if (!server) {
1572 server = msm_ipc_router_create_server(
1573 msg->srv.service, msg->srv.instance,
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001574 msg->srv.node_id, msg->srv.port_id, xprt_info);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001575 if (!server) {
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -06001576 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001577 pr_err("%s: Server Create failed\n", __func__);
1578 return -ENOMEM;
1579 }
1580
1581 if (!msm_ipc_router_lookup_remote_port(
1582 msg->srv.node_id, msg->srv.port_id)) {
1583 rport_ptr = msm_ipc_router_create_remote_port(
1584 msg->srv.node_id, msg->srv.port_id);
1585 if (!rport_ptr)
1586 pr_err("%s: Remote port create "
1587 "failed\n", __func__);
Karthikeyan Ramasubramanian5b502d3642012-09-23 22:23:36 -06001588 rport_ptr->sec_rule =
1589 msm_ipc_get_security_rule(
1590 msg->srv.service, msg->srv.instance);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001591 }
1592 wake_up(&newserver_wait);
1593 }
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -06001594 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001595
1596 relay_msg(xprt_info, pkt);
1597 post_control_ports(pkt);
1598 break;
1599 case IPC_ROUTER_CTRL_CMD_REMOVE_SERVER:
1600 RR("o REMOVE_SERVER service=%08x:%d\n",
1601 msg->srv.service, msg->srv.instance);
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -06001602 mutex_lock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001603 server = msm_ipc_router_lookup_server(msg->srv.service,
1604 msg->srv.instance,
1605 msg->srv.node_id,
1606 msg->srv.port_id);
1607 if (server) {
1608 msm_ipc_router_destroy_server(server,
1609 msg->srv.node_id,
1610 msg->srv.port_id);
1611 relay_msg(xprt_info, pkt);
1612 post_control_ports(pkt);
1613 }
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -06001614 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001615 break;
1616 case IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT:
1617 RR("o REMOVE_CLIENT id=%d:%08x\n",
1618 msg->cli.node_id, msg->cli.port_id);
1619 rport_ptr = msm_ipc_router_lookup_remote_port(msg->cli.node_id,
1620 msg->cli.port_id);
1621 if (rport_ptr)
1622 msm_ipc_router_destroy_remote_port(rport_ptr);
1623
1624 relay_msg(xprt_info, pkt);
1625 post_control_ports(pkt);
1626 break;
1627 case IPC_ROUTER_CTRL_CMD_PING:
1628 /* No action needed for ping messages received */
1629 RR("o PING\n");
1630 break;
1631 default:
1632 RR("o UNKNOWN(%08x)\n", msg->cmd);
1633 rc = -ENOSYS;
1634 }
1635
1636 return rc;
1637}
1638
1639static void do_read_data(struct work_struct *work)
1640{
1641 struct rr_header *hdr;
1642 struct rr_packet *pkt = NULL;
1643 struct msm_ipc_port *port_ptr;
1644 struct sk_buff *head_skb;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001645 struct msm_ipc_router_remote_port *rport_ptr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001646 uint32_t resume_tx, resume_tx_node_id, resume_tx_port_id;
1647
1648 struct msm_ipc_router_xprt_info *xprt_info =
1649 container_of(work,
1650 struct msm_ipc_router_xprt_info,
1651 read_data);
1652
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001653 while ((pkt = rr_read(xprt_info)) != NULL) {
1654 if (pkt->length < IPC_ROUTER_HDR_SIZE ||
1655 pkt->length > MAX_IPC_PKT_SIZE) {
1656 pr_err("%s: Invalid pkt length %d\n",
1657 __func__, pkt->length);
1658 goto fail_data;
1659 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001660
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001661 head_skb = skb_peek(pkt->pkt_fragment_q);
1662 if (!head_skb) {
1663 pr_err("%s: head_skb is invalid\n", __func__);
1664 goto fail_data;
1665 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001666
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001667 hdr = (struct rr_header *)(head_skb->data);
1668 RR("- ver=%d type=%d src=%d:%08x crx=%d siz=%d dst=%d:%08x\n",
1669 hdr->version, hdr->type, hdr->src_node_id, hdr->src_port_id,
1670 hdr->confirm_rx, hdr->size, hdr->dst_node_id,
1671 hdr->dst_port_id);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001672
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001673 if (hdr->version != IPC_ROUTER_VERSION) {
1674 pr_err("version %d != %d\n",
1675 hdr->version, IPC_ROUTER_VERSION);
1676 goto fail_data;
1677 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001678
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001679 if ((hdr->dst_node_id != IPC_ROUTER_NID_LOCAL) &&
1680 ((hdr->type == IPC_ROUTER_CTRL_CMD_RESUME_TX) ||
1681 (hdr->type == IPC_ROUTER_CTRL_CMD_DATA))) {
1682 forward_msg(xprt_info, pkt);
1683 release_pkt(pkt);
1684 continue;
1685 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001686
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001687 if ((hdr->dst_port_id == IPC_ROUTER_ADDRESS) ||
1688 (hdr->type == IPC_ROUTER_CTRL_CMD_HELLO)) {
1689 process_control_msg(xprt_info, pkt);
1690 release_pkt(pkt);
1691 continue;
1692 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001693#if defined(CONFIG_MSM_SMD_LOGGING)
1694#if defined(DEBUG)
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001695 if (msm_ipc_router_debug_mask & SMEM_LOG) {
1696 smem_log_event((SMEM_LOG_PROC_ID_APPS |
1697 SMEM_LOG_RPC_ROUTER_EVENT_BASE |
1698 IPC_ROUTER_LOG_EVENT_RX),
1699 (hdr->src_node_id << 24) |
1700 (hdr->src_port_id & 0xffffff),
1701 (hdr->dst_node_id << 24) |
1702 (hdr->dst_port_id & 0xffffff),
1703 (hdr->type << 24) | (hdr->confirm_rx << 16) |
1704 (hdr->size & 0xffff));
1705 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001706#endif
1707#endif
1708
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001709 resume_tx = hdr->confirm_rx;
1710 resume_tx_node_id = hdr->dst_node_id;
1711 resume_tx_port_id = hdr->dst_port_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001712
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001713 rport_ptr = msm_ipc_router_lookup_remote_port(hdr->src_node_id,
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06001714 hdr->src_port_id);
1715
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001716 mutex_lock(&local_ports_lock);
1717 port_ptr = msm_ipc_router_lookup_local_port(hdr->dst_port_id);
1718 if (!port_ptr) {
1719 pr_err("%s: No local port id %08x\n", __func__,
1720 hdr->dst_port_id);
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06001721 mutex_unlock(&local_ports_lock);
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001722 release_pkt(pkt);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001723 goto process_done;
1724 }
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001725
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001726 if (!rport_ptr) {
1727 rport_ptr = msm_ipc_router_create_remote_port(
1728 hdr->src_node_id,
1729 hdr->src_port_id);
1730 if (!rport_ptr) {
1731 pr_err("%s: Rmt Prt %08x:%08x create failed\n",
1732 __func__, hdr->src_node_id,
1733 hdr->src_port_id);
1734 mutex_unlock(&local_ports_lock);
1735 goto process_done;
1736 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001737 }
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001738
Karthikeyan Ramasubramanianefc493b2012-07-12 10:25:49 -06001739 mutex_lock(&port_ptr->port_rx_q_lock);
1740 wake_lock(&port_ptr->port_rx_wake_lock);
1741 list_add_tail(&pkt->list, &port_ptr->port_rx_q);
1742 wake_up(&port_ptr->port_rx_wait_q);
1743 if (port_ptr->notify)
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001744 port_ptr->notify(MSM_IPC_ROUTER_READ_CB,
Karthikeyan Ramasubramanianefc493b2012-07-12 10:25:49 -06001745 port_ptr->priv);
1746 mutex_unlock(&port_ptr->port_rx_q_lock);
1747 mutex_unlock(&local_ports_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001748
1749process_done:
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001750 if (resume_tx) {
1751 union rr_control_msg msg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001752
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001753 msg.cmd = IPC_ROUTER_CTRL_CMD_RESUME_TX;
1754 msg.cli.node_id = resume_tx_node_id;
1755 msg.cli.port_id = resume_tx_port_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001756
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001757 RR("x RESUME_TX id=%d:%08x\n",
1758 msg.cli.node_id, msg.cli.port_id);
1759 msm_ipc_router_send_control_msg(xprt_info, &msg);
1760 }
1761
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001762 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001763 return;
1764
1765fail_data:
1766 release_pkt(pkt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001767 pr_err("ipc_router has died\n");
1768}
1769
1770int msm_ipc_router_register_server(struct msm_ipc_port *port_ptr,
1771 struct msm_ipc_addr *name)
1772{
1773 struct msm_ipc_server *server;
1774 unsigned long flags;
1775 union rr_control_msg ctl;
1776
1777 if (!port_ptr || !name)
1778 return -EINVAL;
1779
1780 if (name->addrtype != MSM_IPC_ADDR_NAME)
1781 return -EINVAL;
1782
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -06001783 mutex_lock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001784 server = msm_ipc_router_lookup_server(name->addr.port_name.service,
1785 name->addr.port_name.instance,
1786 IPC_ROUTER_NID_LOCAL,
1787 port_ptr->this_port.port_id);
1788 if (server) {
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -06001789 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001790 pr_err("%s: Server already present\n", __func__);
1791 return -EINVAL;
1792 }
1793
1794 server = msm_ipc_router_create_server(name->addr.port_name.service,
1795 name->addr.port_name.instance,
1796 IPC_ROUTER_NID_LOCAL,
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001797 port_ptr->this_port.port_id,
1798 NULL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001799 if (!server) {
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -06001800 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001801 pr_err("%s: Server Creation failed\n", __func__);
1802 return -EINVAL;
1803 }
1804
1805 ctl.cmd = IPC_ROUTER_CTRL_CMD_NEW_SERVER;
1806 ctl.srv.service = server->name.service;
1807 ctl.srv.instance = server->name.instance;
1808 ctl.srv.node_id = IPC_ROUTER_NID_LOCAL;
1809 ctl.srv.port_id = port_ptr->this_port.port_id;
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -06001810 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001811 broadcast_ctl_msg(&ctl);
1812 spin_lock_irqsave(&port_ptr->port_lock, flags);
1813 port_ptr->type = SERVER_PORT;
1814 port_ptr->port_name.service = server->name.service;
1815 port_ptr->port_name.instance = server->name.instance;
1816 spin_unlock_irqrestore(&port_ptr->port_lock, flags);
1817 return 0;
1818}
1819
1820int msm_ipc_router_unregister_server(struct msm_ipc_port *port_ptr)
1821{
1822 struct msm_ipc_server *server;
1823 unsigned long flags;
1824 union rr_control_msg ctl;
1825
1826 if (!port_ptr)
1827 return -EINVAL;
1828
1829 if (port_ptr->type != SERVER_PORT) {
1830 pr_err("%s: Trying to unregister a non-server port\n",
1831 __func__);
1832 return -EINVAL;
1833 }
1834
1835 if (port_ptr->this_port.node_id != IPC_ROUTER_NID_LOCAL) {
1836 pr_err("%s: Trying to unregister a remote server locally\n",
1837 __func__);
1838 return -EINVAL;
1839 }
1840
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -06001841 mutex_lock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001842 server = msm_ipc_router_lookup_server(port_ptr->port_name.service,
1843 port_ptr->port_name.instance,
1844 port_ptr->this_port.node_id,
1845 port_ptr->this_port.port_id);
1846 if (!server) {
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -06001847 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001848 pr_err("%s: Server lookup failed\n", __func__);
1849 return -ENODEV;
1850 }
1851
1852 ctl.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_SERVER;
1853 ctl.srv.service = server->name.service;
1854 ctl.srv.instance = server->name.instance;
1855 ctl.srv.node_id = IPC_ROUTER_NID_LOCAL;
1856 ctl.srv.port_id = port_ptr->this_port.port_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001857 msm_ipc_router_destroy_server(server, port_ptr->this_port.node_id,
1858 port_ptr->this_port.port_id);
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -06001859 mutex_unlock(&server_list_lock);
1860 broadcast_ctl_msg(&ctl);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001861 spin_lock_irqsave(&port_ptr->port_lock, flags);
1862 port_ptr->type = CLIENT_PORT;
1863 spin_unlock_irqrestore(&port_ptr->port_lock, flags);
1864 return 0;
1865}
1866
1867static int loopback_data(struct msm_ipc_port *src,
1868 uint32_t port_id,
1869 struct sk_buff_head *data)
1870{
1871 struct sk_buff *head_skb;
1872 struct rr_header *hdr;
1873 struct msm_ipc_port *port_ptr;
1874 struct rr_packet *pkt;
1875
1876 if (!data) {
1877 pr_err("%s: Invalid pkt pointer\n", __func__);
1878 return -EINVAL;
1879 }
1880
1881 pkt = create_pkt(data);
1882 if (!pkt) {
1883 pr_err("%s: New pkt create failed\n", __func__);
1884 return -ENOMEM;
1885 }
1886
1887 head_skb = skb_peek(pkt->pkt_fragment_q);
Karthikeyan Ramasubramanian9024dd82011-12-19 18:44:19 -07001888 if (!head_skb) {
1889 pr_err("%s: pkt_fragment_q is empty\n", __func__);
1890 return -EINVAL;
1891 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001892 hdr = (struct rr_header *)skb_push(head_skb, IPC_ROUTER_HDR_SIZE);
1893 if (!hdr) {
1894 pr_err("%s: Prepend Header failed\n", __func__);
1895 release_pkt(pkt);
1896 return -ENOMEM;
1897 }
1898 hdr->version = IPC_ROUTER_VERSION;
1899 hdr->type = IPC_ROUTER_CTRL_CMD_DATA;
1900 hdr->src_node_id = src->this_port.node_id;
1901 hdr->src_port_id = src->this_port.port_id;
1902 hdr->size = pkt->length;
1903 hdr->confirm_rx = 0;
1904 hdr->dst_node_id = IPC_ROUTER_NID_LOCAL;
1905 hdr->dst_port_id = port_id;
1906 pkt->length += IPC_ROUTER_HDR_SIZE;
1907
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06001908 mutex_lock(&local_ports_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001909 port_ptr = msm_ipc_router_lookup_local_port(port_id);
1910 if (!port_ptr) {
1911 pr_err("%s: Local port %d not present\n", __func__, port_id);
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06001912 mutex_unlock(&local_ports_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001913 release_pkt(pkt);
1914 return -ENODEV;
1915 }
1916
1917 mutex_lock(&port_ptr->port_rx_q_lock);
1918 wake_lock(&port_ptr->port_rx_wake_lock);
1919 list_add_tail(&pkt->list, &port_ptr->port_rx_q);
1920 wake_up(&port_ptr->port_rx_wait_q);
1921 mutex_unlock(&port_ptr->port_rx_q_lock);
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06001922 mutex_unlock(&local_ports_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001923
1924 return pkt->length;
1925}
1926
1927static int msm_ipc_router_write_pkt(struct msm_ipc_port *src,
1928 struct msm_ipc_router_remote_port *rport_ptr,
1929 struct rr_packet *pkt)
1930{
1931 struct sk_buff *head_skb;
1932 struct rr_header *hdr;
1933 struct msm_ipc_router_xprt_info *xprt_info;
1934 struct msm_ipc_routing_table_entry *rt_entry;
1935 int ret;
1936 DEFINE_WAIT(__wait);
1937
1938 if (!rport_ptr || !src || !pkt)
1939 return -EINVAL;
1940
1941 head_skb = skb_peek(pkt->pkt_fragment_q);
Karthikeyan Ramasubramanian9024dd82011-12-19 18:44:19 -07001942 if (!head_skb) {
1943 pr_err("%s: pkt_fragment_q is empty\n", __func__);
1944 return -EINVAL;
1945 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001946 hdr = (struct rr_header *)skb_push(head_skb, IPC_ROUTER_HDR_SIZE);
1947 if (!hdr) {
1948 pr_err("%s: Prepend Header failed\n", __func__);
1949 return -ENOMEM;
1950 }
1951 hdr->version = IPC_ROUTER_VERSION;
1952 hdr->type = IPC_ROUTER_CTRL_CMD_DATA;
1953 hdr->src_node_id = src->this_port.node_id;
1954 hdr->src_port_id = src->this_port.port_id;
1955 hdr->size = pkt->length;
1956 hdr->confirm_rx = 0;
1957 hdr->dst_node_id = rport_ptr->node_id;
1958 hdr->dst_port_id = rport_ptr->port_id;
1959 pkt->length += IPC_ROUTER_HDR_SIZE;
1960
1961 for (;;) {
1962 prepare_to_wait(&rport_ptr->quota_wait, &__wait,
1963 TASK_INTERRUPTIBLE);
1964 mutex_lock(&rport_ptr->quota_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001965 if (rport_ptr->restart_state != RESTART_NORMAL)
1966 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001967 if (rport_ptr->tx_quota_cnt <
1968 IPC_ROUTER_DEFAULT_RX_QUOTA)
1969 break;
1970 if (signal_pending(current))
1971 break;
1972 mutex_unlock(&rport_ptr->quota_lock);
1973 schedule();
1974 }
1975 finish_wait(&rport_ptr->quota_wait, &__wait);
1976
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001977 if (rport_ptr->restart_state != RESTART_NORMAL) {
1978 mutex_unlock(&rport_ptr->quota_lock);
1979 return -ENETRESET;
1980 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001981 if (signal_pending(current)) {
1982 mutex_unlock(&rport_ptr->quota_lock);
1983 return -ERESTARTSYS;
1984 }
1985 rport_ptr->tx_quota_cnt++;
1986 if (rport_ptr->tx_quota_cnt == IPC_ROUTER_DEFAULT_RX_QUOTA)
1987 hdr->confirm_rx = 1;
1988 mutex_unlock(&rport_ptr->quota_lock);
1989
1990 mutex_lock(&routing_table_lock);
1991 rt_entry = lookup_routing_table(hdr->dst_node_id);
1992 if (!rt_entry || !rt_entry->xprt_info) {
1993 mutex_unlock(&routing_table_lock);
1994 pr_err("%s: Remote node %d not up\n",
1995 __func__, hdr->dst_node_id);
1996 return -ENODEV;
1997 }
1998 mutex_lock(&rt_entry->lock);
1999 xprt_info = rt_entry->xprt_info;
2000 mutex_lock(&xprt_info->tx_lock);
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -07002001 ret = xprt_info->xprt->write(pkt, pkt->length, xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002002 mutex_unlock(&xprt_info->tx_lock);
2003 mutex_unlock(&rt_entry->lock);
2004 mutex_unlock(&routing_table_lock);
2005
2006 if (ret < 0) {
2007 pr_err("%s: Write on XPRT failed\n", __func__);
2008 return ret;
2009 }
2010
2011 RAW_HDR("[w rr_h] "
2012 "ver=%i,type=%s,src_nid=%08x,src_port_id=%08x,"
2013 "confirm_rx=%i,size=%3i,dst_pid=%08x,dst_cid=%08x\n",
2014 hdr->version, type_to_str(hdr->type),
2015 hdr->src_node_id, hdr->src_port_id,
2016 hdr->confirm_rx, hdr->size,
2017 hdr->dst_node_id, hdr->dst_port_id);
2018
2019#if defined(CONFIG_MSM_SMD_LOGGING)
2020#if defined(DEBUG)
2021 if (msm_ipc_router_debug_mask & SMEM_LOG) {
2022 smem_log_event((SMEM_LOG_PROC_ID_APPS |
2023 SMEM_LOG_RPC_ROUTER_EVENT_BASE |
2024 IPC_ROUTER_LOG_EVENT_TX),
2025 (hdr->src_node_id << 24) |
2026 (hdr->src_port_id & 0xffffff),
2027 (hdr->dst_node_id << 24) |
2028 (hdr->dst_port_id & 0xffffff),
2029 (hdr->type << 24) | (hdr->confirm_rx << 16) |
2030 (hdr->size & 0xffff));
2031 }
2032#endif
2033#endif
2034
2035 return pkt->length;
2036}
2037
2038int msm_ipc_router_send_to(struct msm_ipc_port *src,
2039 struct sk_buff_head *data,
2040 struct msm_ipc_addr *dest)
2041{
2042 uint32_t dst_node_id = 0, dst_port_id = 0;
2043 struct msm_ipc_server *server;
2044 struct msm_ipc_server_port *server_port;
2045 struct msm_ipc_router_remote_port *rport_ptr = NULL;
2046 struct rr_packet *pkt;
2047 int ret;
2048
2049 if (!src || !data || !dest) {
2050 pr_err("%s: Invalid Parameters\n", __func__);
2051 return -EINVAL;
2052 }
2053
2054 /* Resolve Address*/
2055 if (dest->addrtype == MSM_IPC_ADDR_ID) {
2056 dst_node_id = dest->addr.port_addr.node_id;
2057 dst_port_id = dest->addr.port_addr.port_id;
2058 } else if (dest->addrtype == MSM_IPC_ADDR_NAME) {
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -06002059 mutex_lock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002060 server = msm_ipc_router_lookup_server(
2061 dest->addr.port_name.service,
2062 dest->addr.port_name.instance,
2063 0, 0);
2064 if (!server) {
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -06002065 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002066 pr_err("%s: Destination not reachable\n", __func__);
2067 return -ENODEV;
2068 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002069 server_port = list_first_entry(&server->server_port_list,
2070 struct msm_ipc_server_port,
2071 list);
2072 dst_node_id = server_port->server_addr.node_id;
2073 dst_port_id = server_port->server_addr.port_id;
2074 mutex_unlock(&server_list_lock);
2075 }
2076 if (dst_node_id == IPC_ROUTER_NID_LOCAL) {
2077 ret = loopback_data(src, dst_port_id, data);
2078 return ret;
2079 }
2080
2081 /* Achieve Flow control */
2082 rport_ptr = msm_ipc_router_lookup_remote_port(dst_node_id,
2083 dst_port_id);
2084 if (!rport_ptr) {
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002085 pr_err("%s: Could not create remote port\n", __func__);
2086 return -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002087 }
2088
Karthikeyan Ramasubramanian5b502d3642012-09-23 22:23:36 -06002089 if (src->check_send_permissions) {
2090 ret = src->check_send_permissions(rport_ptr->sec_rule);
2091 if (ret <= 0) {
2092 pr_err("%s: permission failure for %s\n",
2093 __func__, current->comm);
2094 return -EPERM;
2095 }
2096 }
2097
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002098 pkt = create_pkt(data);
2099 if (!pkt) {
2100 pr_err("%s: Pkt creation failed\n", __func__);
2101 return -ENOMEM;
2102 }
2103
2104 ret = msm_ipc_router_write_pkt(src, rport_ptr, pkt);
2105 release_pkt(pkt);
2106
2107 return ret;
2108}
2109
Karthikeyan Ramasubramanianefc493b2012-07-12 10:25:49 -06002110int msm_ipc_router_send_msg(struct msm_ipc_port *src,
2111 struct msm_ipc_addr *dest,
2112 void *data, unsigned int data_len)
2113{
2114 struct sk_buff_head *out_skb_head;
2115 int ret;
2116
2117 out_skb_head = msm_ipc_router_buf_to_skb(data, data_len);
2118 if (!out_skb_head) {
2119 pr_err("%s: SKB conversion failed\n", __func__);
2120 return -EFAULT;
2121 }
2122
2123 ret = msm_ipc_router_send_to(src, out_skb_head, dest);
2124 if (ret < 0) {
2125 pr_err("%s: msm_ipc_router_send_to failed - ret: %d\n",
2126 __func__, ret);
2127 msm_ipc_router_free_skb(out_skb_head);
2128 }
2129 return 0;
2130}
2131
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002132int msm_ipc_router_read(struct msm_ipc_port *port_ptr,
2133 struct sk_buff_head **data,
2134 size_t buf_len)
2135{
2136 struct rr_packet *pkt;
2137 int ret;
2138
2139 if (!port_ptr || !data)
2140 return -EINVAL;
2141
2142 mutex_lock(&port_ptr->port_rx_q_lock);
2143 if (list_empty(&port_ptr->port_rx_q)) {
2144 mutex_unlock(&port_ptr->port_rx_q_lock);
2145 return -EAGAIN;
2146 }
2147
2148 pkt = list_first_entry(&port_ptr->port_rx_q, struct rr_packet, list);
2149 if ((buf_len) && ((pkt->length - IPC_ROUTER_HDR_SIZE) > buf_len)) {
2150 mutex_unlock(&port_ptr->port_rx_q_lock);
2151 return -ETOOSMALL;
2152 }
2153 list_del(&pkt->list);
2154 if (list_empty(&port_ptr->port_rx_q))
2155 wake_unlock(&port_ptr->port_rx_wake_lock);
2156 *data = pkt->pkt_fragment_q;
2157 ret = pkt->length;
2158 kfree(pkt);
2159 mutex_unlock(&port_ptr->port_rx_q_lock);
2160
2161 return ret;
2162}
2163
2164int msm_ipc_router_recv_from(struct msm_ipc_port *port_ptr,
2165 struct sk_buff_head **data,
2166 struct msm_ipc_addr *src,
Karthikeyan Ramasubramanianefc493b2012-07-12 10:25:49 -06002167 long timeout)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002168{
2169 int ret, data_len, align_size;
2170 struct sk_buff *temp_skb;
2171 struct rr_header *hdr = NULL;
2172
2173 if (!port_ptr || !data) {
2174 pr_err("%s: Invalid pointers being passed\n", __func__);
2175 return -EINVAL;
2176 }
2177
2178 *data = NULL;
2179 mutex_lock(&port_ptr->port_rx_q_lock);
2180 while (list_empty(&port_ptr->port_rx_q)) {
2181 mutex_unlock(&port_ptr->port_rx_q_lock);
2182 if (timeout < 0) {
2183 ret = wait_event_interruptible(
2184 port_ptr->port_rx_wait_q,
2185 !list_empty(&port_ptr->port_rx_q));
2186 if (ret)
2187 return ret;
2188 } else if (timeout > 0) {
2189 timeout = wait_event_interruptible_timeout(
2190 port_ptr->port_rx_wait_q,
2191 !list_empty(&port_ptr->port_rx_q),
2192 timeout);
2193 if (timeout < 0)
2194 return -EFAULT;
2195 }
2196 if (timeout == 0)
2197 return -ETIMEDOUT;
2198 mutex_lock(&port_ptr->port_rx_q_lock);
2199 }
2200 mutex_unlock(&port_ptr->port_rx_q_lock);
2201
2202 ret = msm_ipc_router_read(port_ptr, data, 0);
2203 if (ret <= 0 || !(*data))
2204 return ret;
2205
2206 temp_skb = skb_peek(*data);
2207 hdr = (struct rr_header *)(temp_skb->data);
2208 if (src) {
2209 src->addrtype = MSM_IPC_ADDR_ID;
2210 src->addr.port_addr.node_id = hdr->src_node_id;
2211 src->addr.port_addr.port_id = hdr->src_port_id;
2212 }
2213
2214 data_len = hdr->size;
2215 skb_pull(temp_skb, IPC_ROUTER_HDR_SIZE);
2216 align_size = ALIGN_SIZE(data_len);
2217 if (align_size) {
2218 temp_skb = skb_peek_tail(*data);
2219 skb_trim(temp_skb, (temp_skb->len - align_size));
2220 }
2221 return data_len;
2222}
2223
Karthikeyan Ramasubramanianefc493b2012-07-12 10:25:49 -06002224int msm_ipc_router_read_msg(struct msm_ipc_port *port_ptr,
2225 struct msm_ipc_addr *src,
2226 unsigned char **data,
2227 unsigned int *len)
2228{
2229 struct sk_buff_head *in_skb_head;
2230 int ret;
2231
2232 ret = msm_ipc_router_recv_from(port_ptr, &in_skb_head, src, -1);
2233 if (ret < 0) {
2234 pr_err("%s: msm_ipc_router_recv_from failed - ret: %d\n",
2235 __func__, ret);
2236 return ret;
2237 }
2238
2239 *data = msm_ipc_router_skb_to_buf(in_skb_head, ret);
2240 if (!(*data))
2241 pr_err("%s: Buf conversion failed\n", __func__);
2242
2243 *len = ret;
2244 msm_ipc_router_free_skb(in_skb_head);
2245 return 0;
2246}
2247
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002248struct msm_ipc_port *msm_ipc_router_create_port(
Karthikeyan Ramasubramanianefc493b2012-07-12 10:25:49 -06002249 void (*notify)(unsigned event, void *priv),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002250 void *priv)
2251{
2252 struct msm_ipc_port *port_ptr;
Karthikeyan Ramasubramanianefc493b2012-07-12 10:25:49 -06002253 int ret;
2254
2255 ret = wait_for_completion_interruptible(&msm_ipc_local_router_up);
2256 if (ret < 0) {
2257 pr_err("%s: Error waiting for local router\n", __func__);
2258 return NULL;
2259 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002260
2261 port_ptr = msm_ipc_router_create_raw_port(NULL, notify, priv);
2262 if (!port_ptr)
2263 pr_err("%s: port_ptr alloc failed\n", __func__);
2264
2265 return port_ptr;
2266}
2267
2268int msm_ipc_router_close_port(struct msm_ipc_port *port_ptr)
2269{
2270 union rr_control_msg msg;
2271 struct rr_packet *pkt, *temp_pkt;
2272 struct msm_ipc_server *server;
2273
2274 if (!port_ptr)
2275 return -EINVAL;
2276
2277 if (port_ptr->type == SERVER_PORT || port_ptr->type == CLIENT_PORT) {
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06002278 mutex_lock(&local_ports_lock);
2279 list_del(&port_ptr->list);
2280 mutex_unlock(&local_ports_lock);
2281
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002282 if (port_ptr->type == SERVER_PORT) {
2283 msg.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_SERVER;
2284 msg.srv.service = port_ptr->port_name.service;
2285 msg.srv.instance = port_ptr->port_name.instance;
2286 msg.srv.node_id = port_ptr->this_port.node_id;
2287 msg.srv.port_id = port_ptr->this_port.port_id;
2288 RR("x REMOVE_SERVER Name=%d:%08x Id=%d:%08x\n",
2289 msg.srv.service, msg.srv.instance,
2290 msg.srv.node_id, msg.srv.port_id);
2291 } else if (port_ptr->type == CLIENT_PORT) {
2292 msg.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT;
2293 msg.cli.node_id = port_ptr->this_port.node_id;
2294 msg.cli.port_id = port_ptr->this_port.port_id;
2295 RR("x REMOVE_CLIENT id=%d:%08x\n",
2296 msg.cli.node_id, msg.cli.port_id);
2297 }
2298 broadcast_ctl_msg(&msg);
2299 broadcast_ctl_msg_locally(&msg);
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06002300 } else if (port_ptr->type == CONTROL_PORT) {
2301 mutex_lock(&control_ports_lock);
2302 list_del(&port_ptr->list);
2303 mutex_unlock(&control_ports_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002304 }
2305
2306 mutex_lock(&port_ptr->port_rx_q_lock);
2307 list_for_each_entry_safe(pkt, temp_pkt, &port_ptr->port_rx_q, list) {
2308 list_del(&pkt->list);
2309 release_pkt(pkt);
2310 }
2311 mutex_unlock(&port_ptr->port_rx_q_lock);
2312
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002313 if (port_ptr->type == SERVER_PORT) {
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -06002314 mutex_lock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002315 server = msm_ipc_router_lookup_server(
2316 port_ptr->port_name.service,
2317 port_ptr->port_name.instance,
2318 port_ptr->this_port.node_id,
2319 port_ptr->this_port.port_id);
2320 if (server)
2321 msm_ipc_router_destroy_server(server,
2322 port_ptr->this_port.node_id,
2323 port_ptr->this_port.port_id);
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -06002324 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002325 }
2326
Karthikeyan Ramasubramaniandd8c3b52011-11-30 16:26:12 -07002327 wake_lock_destroy(&port_ptr->port_rx_wake_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002328 kfree(port_ptr);
2329 return 0;
2330}
2331
2332int msm_ipc_router_get_curr_pkt_size(struct msm_ipc_port *port_ptr)
2333{
2334 struct rr_packet *pkt;
2335 int rc = 0;
2336
2337 if (!port_ptr)
2338 return -EINVAL;
2339
2340 mutex_lock(&port_ptr->port_rx_q_lock);
2341 if (!list_empty(&port_ptr->port_rx_q)) {
2342 pkt = list_first_entry(&port_ptr->port_rx_q,
2343 struct rr_packet, list);
2344 rc = pkt->length;
2345 }
2346 mutex_unlock(&port_ptr->port_rx_q_lock);
2347
2348 return rc;
2349}
2350
2351int msm_ipc_router_bind_control_port(struct msm_ipc_port *port_ptr)
2352{
2353 if (!port_ptr)
2354 return -EINVAL;
2355
2356 mutex_lock(&local_ports_lock);
2357 list_del(&port_ptr->list);
2358 mutex_unlock(&local_ports_lock);
2359 port_ptr->type = CONTROL_PORT;
2360 mutex_lock(&control_ports_lock);
2361 list_add_tail(&port_ptr->list, &control_ports);
2362 mutex_unlock(&control_ports_lock);
2363
2364 return 0;
2365}
2366
2367int msm_ipc_router_lookup_server_name(struct msm_ipc_port_name *srv_name,
Karthikeyan Ramasubramaniandfde01b2012-06-12 14:25:13 -06002368 struct msm_ipc_server_info *srv_info,
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002369 int num_entries_in_array,
2370 uint32_t lookup_mask)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002371{
2372 struct msm_ipc_server *server;
2373 struct msm_ipc_server_port *server_port;
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002374 int key, i = 0; /*num_entries_found*/
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002375
2376 if (!srv_name) {
2377 pr_err("%s: Invalid srv_name\n", __func__);
2378 return -EINVAL;
2379 }
2380
Karthikeyan Ramasubramaniandfde01b2012-06-12 14:25:13 -06002381 if (num_entries_in_array && !srv_info) {
2382 pr_err("%s: srv_info NULL\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002383 return -EINVAL;
2384 }
2385
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002386 mutex_lock(&server_list_lock);
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002387 if (!lookup_mask)
2388 lookup_mask = 0xFFFFFFFF;
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -06002389 key = (srv_name->service & (SRV_HASH_SIZE - 1));
2390 list_for_each_entry(server, &server_list[key], list) {
2391 if ((server->name.service != srv_name->service) ||
2392 ((server->name.instance & lookup_mask) !=
2393 srv_name->instance))
2394 continue;
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002395
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -06002396 list_for_each_entry(server_port,
2397 &server->server_port_list, list) {
2398 if (i < num_entries_in_array) {
2399 srv_info[i].node_id =
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002400 server_port->server_addr.node_id;
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -06002401 srv_info[i].port_id =
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002402 server_port->server_addr.port_id;
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -06002403 srv_info[i].service = server->name.service;
2404 srv_info[i].instance = server->name.instance;
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002405 }
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -06002406 i++;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002407 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002408 }
2409 mutex_unlock(&server_list_lock);
2410
2411 return i;
2412}
2413
2414int msm_ipc_router_close(void)
2415{
2416 struct msm_ipc_router_xprt_info *xprt_info, *tmp_xprt_info;
2417
2418 mutex_lock(&xprt_info_list_lock);
2419 list_for_each_entry_safe(xprt_info, tmp_xprt_info,
2420 &xprt_info_list, list) {
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -07002421 xprt_info->xprt->close(xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002422 list_del(&xprt_info->list);
2423 kfree(xprt_info);
2424 }
2425 mutex_unlock(&xprt_info_list_lock);
2426 return 0;
2427}
2428
2429#if defined(CONFIG_DEBUG_FS)
2430static int dump_routing_table(char *buf, int max)
2431{
2432 int i = 0, j;
2433 struct msm_ipc_routing_table_entry *rt_entry;
2434
2435 for (j = 0; j < RT_HASH_SIZE; j++) {
2436 mutex_lock(&routing_table_lock);
2437 list_for_each_entry(rt_entry, &routing_table[j], list) {
2438 mutex_lock(&rt_entry->lock);
2439 i += scnprintf(buf + i, max - i,
2440 "Node Id: 0x%08x\n", rt_entry->node_id);
Karthikeyan Ramasubramanianbddeec72012-09-10 16:10:24 -06002441 if (rt_entry->node_id == IPC_ROUTER_NID_LOCAL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002442 i += scnprintf(buf + i, max - i,
2443 "XPRT Name: Loopback\n");
2444 i += scnprintf(buf + i, max - i,
2445 "Next Hop: %d\n", rt_entry->node_id);
2446 } else {
2447 i += scnprintf(buf + i, max - i,
2448 "XPRT Name: %s\n",
2449 rt_entry->xprt_info->xprt->name);
2450 i += scnprintf(buf + i, max - i,
2451 "Next Hop: 0x%08x\n",
2452 rt_entry->xprt_info->remote_node_id);
2453 }
2454 i += scnprintf(buf + i, max - i, "\n");
2455 mutex_unlock(&rt_entry->lock);
2456 }
2457 mutex_unlock(&routing_table_lock);
2458 }
2459
2460 return i;
2461}
2462
2463static int dump_xprt_info(char *buf, int max)
2464{
2465 int i = 0;
2466 struct msm_ipc_router_xprt_info *xprt_info;
2467
2468 mutex_lock(&xprt_info_list_lock);
2469 list_for_each_entry(xprt_info, &xprt_info_list, list) {
2470 i += scnprintf(buf + i, max - i, "XPRT Name: %s\n",
2471 xprt_info->xprt->name);
2472 i += scnprintf(buf + i, max - i, "Link Id: %d\n",
2473 xprt_info->xprt->link_id);
2474 i += scnprintf(buf + i, max - i, "Initialized: %s\n",
2475 (xprt_info->initialized ? "Y" : "N"));
2476 i += scnprintf(buf + i, max - i, "Remote Node Id: 0x%08x\n",
2477 xprt_info->remote_node_id);
2478 i += scnprintf(buf + i, max - i, "\n");
2479 }
2480 mutex_unlock(&xprt_info_list_lock);
2481
2482 return i;
2483}
2484
2485static int dump_servers(char *buf, int max)
2486{
2487 int i = 0, j;
2488 struct msm_ipc_server *server;
2489 struct msm_ipc_server_port *server_port;
2490
2491 mutex_lock(&server_list_lock);
2492 for (j = 0; j < SRV_HASH_SIZE; j++) {
2493 list_for_each_entry(server, &server_list[j], list) {
2494 list_for_each_entry(server_port,
2495 &server->server_port_list,
2496 list) {
2497 i += scnprintf(buf + i, max - i, "Service: "
2498 "0x%08x\n", server->name.service);
2499 i += scnprintf(buf + i, max - i, "Instance: "
2500 "0x%08x\n", server->name.instance);
2501 i += scnprintf(buf + i, max - i,
2502 "Node_id: 0x%08x\n",
2503 server_port->server_addr.node_id);
2504 i += scnprintf(buf + i, max - i,
2505 "Port_id: 0x%08x\n",
2506 server_port->server_addr.port_id);
2507 i += scnprintf(buf + i, max - i, "\n");
2508 }
2509 }
2510 }
2511 mutex_unlock(&server_list_lock);
2512
2513 return i;
2514}
2515
2516static int dump_remote_ports(char *buf, int max)
2517{
2518 int i = 0, j, k;
2519 struct msm_ipc_router_remote_port *rport_ptr;
2520 struct msm_ipc_routing_table_entry *rt_entry;
2521
2522 for (j = 0; j < RT_HASH_SIZE; j++) {
2523 mutex_lock(&routing_table_lock);
2524 list_for_each_entry(rt_entry, &routing_table[j], list) {
2525 mutex_lock(&rt_entry->lock);
2526 for (k = 0; k < RP_HASH_SIZE; k++) {
2527 list_for_each_entry(rport_ptr,
2528 &rt_entry->remote_port_list[k],
2529 list) {
2530 i += scnprintf(buf + i, max - i,
2531 "Node_id: 0x%08x\n",
2532 rport_ptr->node_id);
2533 i += scnprintf(buf + i, max - i,
2534 "Port_id: 0x%08x\n",
2535 rport_ptr->port_id);
2536 i += scnprintf(buf + i, max - i,
2537 "Quota_cnt: %d\n",
2538 rport_ptr->tx_quota_cnt);
2539 i += scnprintf(buf + i, max - i, "\n");
2540 }
2541 }
2542 mutex_unlock(&rt_entry->lock);
2543 }
2544 mutex_unlock(&routing_table_lock);
2545 }
2546
2547 return i;
2548}
2549
2550static int dump_control_ports(char *buf, int max)
2551{
2552 int i = 0;
2553 struct msm_ipc_port *port_ptr;
2554
2555 mutex_lock(&control_ports_lock);
2556 list_for_each_entry(port_ptr, &control_ports, list) {
2557 i += scnprintf(buf + i, max - i, "Node_id: 0x%08x\n",
2558 port_ptr->this_port.node_id);
2559 i += scnprintf(buf + i, max - i, "Port_id: 0x%08x\n",
2560 port_ptr->this_port.port_id);
2561 i += scnprintf(buf + i, max - i, "\n");
2562 }
2563 mutex_unlock(&control_ports_lock);
2564
2565 return i;
2566}
2567
2568static int dump_local_ports(char *buf, int max)
2569{
2570 int i = 0, j;
2571 unsigned long flags;
2572 struct msm_ipc_port *port_ptr;
2573
2574 mutex_lock(&local_ports_lock);
2575 for (j = 0; j < LP_HASH_SIZE; j++) {
2576 list_for_each_entry(port_ptr, &local_ports[j], list) {
2577 spin_lock_irqsave(&port_ptr->port_lock, flags);
2578 i += scnprintf(buf + i, max - i, "Node_id: 0x%08x\n",
2579 port_ptr->this_port.node_id);
2580 i += scnprintf(buf + i, max - i, "Port_id: 0x%08x\n",
2581 port_ptr->this_port.port_id);
2582 i += scnprintf(buf + i, max - i, "# pkts tx'd %d\n",
2583 port_ptr->num_tx);
2584 i += scnprintf(buf + i, max - i, "# pkts rx'd %d\n",
2585 port_ptr->num_rx);
2586 i += scnprintf(buf + i, max - i, "# bytes tx'd %ld\n",
2587 port_ptr->num_tx_bytes);
2588 i += scnprintf(buf + i, max - i, "# bytes rx'd %ld\n",
2589 port_ptr->num_rx_bytes);
2590 spin_unlock_irqrestore(&port_ptr->port_lock, flags);
2591 i += scnprintf(buf + i, max - i, "\n");
2592 }
2593 }
2594 mutex_unlock(&local_ports_lock);
2595
2596 return i;
2597}
2598
2599#define DEBUG_BUFMAX 4096
2600static char debug_buffer[DEBUG_BUFMAX];
2601
2602static ssize_t debug_read(struct file *file, char __user *buf,
2603 size_t count, loff_t *ppos)
2604{
2605 int (*fill)(char *buf, int max) = file->private_data;
2606 int bsize = fill(debug_buffer, DEBUG_BUFMAX);
2607 return simple_read_from_buffer(buf, count, ppos, debug_buffer, bsize);
2608}
2609
2610static int debug_open(struct inode *inode, struct file *file)
2611{
2612 file->private_data = inode->i_private;
2613 return 0;
2614}
2615
2616static const struct file_operations debug_ops = {
2617 .read = debug_read,
2618 .open = debug_open,
2619};
2620
2621static void debug_create(const char *name, mode_t mode,
2622 struct dentry *dent,
2623 int (*fill)(char *buf, int max))
2624{
2625 debugfs_create_file(name, mode, dent, fill, &debug_ops);
2626}
2627
2628static void debugfs_init(void)
2629{
2630 struct dentry *dent;
2631
2632 dent = debugfs_create_dir("msm_ipc_router", 0);
2633 if (IS_ERR(dent))
2634 return;
2635
2636 debug_create("dump_local_ports", 0444, dent,
2637 dump_local_ports);
2638 debug_create("dump_remote_ports", 0444, dent,
2639 dump_remote_ports);
2640 debug_create("dump_control_ports", 0444, dent,
2641 dump_control_ports);
2642 debug_create("dump_servers", 0444, dent,
2643 dump_servers);
2644 debug_create("dump_xprt_info", 0444, dent,
2645 dump_xprt_info);
2646 debug_create("dump_routing_table", 0444, dent,
2647 dump_routing_table);
2648}
2649
2650#else
2651static void debugfs_init(void) {}
2652#endif
2653
2654static int msm_ipc_router_add_xprt(struct msm_ipc_router_xprt *xprt)
2655{
2656 struct msm_ipc_router_xprt_info *xprt_info;
2657 struct msm_ipc_routing_table_entry *rt_entry;
2658
2659 xprt_info = kmalloc(sizeof(struct msm_ipc_router_xprt_info),
2660 GFP_KERNEL);
2661 if (!xprt_info)
2662 return -ENOMEM;
2663
2664 xprt_info->xprt = xprt;
2665 xprt_info->initialized = 0;
2666 xprt_info->remote_node_id = -1;
2667 INIT_LIST_HEAD(&xprt_info->pkt_list);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002668 mutex_init(&xprt_info->rx_lock);
2669 mutex_init(&xprt_info->tx_lock);
2670 wake_lock_init(&xprt_info->wakelock,
2671 WAKE_LOCK_SUSPEND, xprt->name);
2672 xprt_info->need_len = 0;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002673 xprt_info->abort_data_read = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002674 INIT_WORK(&xprt_info->read_data, do_read_data);
2675 INIT_LIST_HEAD(&xprt_info->list);
2676
2677 xprt_info->workqueue = create_singlethread_workqueue(xprt->name);
2678 if (!xprt_info->workqueue) {
2679 kfree(xprt_info);
2680 return -ENOMEM;
2681 }
2682
2683 if (!strcmp(xprt->name, "msm_ipc_router_loopback_xprt")) {
2684 xprt_info->remote_node_id = IPC_ROUTER_NID_LOCAL;
2685 xprt_info->initialized = 1;
2686 }
2687
2688 mutex_lock(&xprt_info_list_lock);
2689 list_add_tail(&xprt_info->list, &xprt_info_list);
2690 mutex_unlock(&xprt_info_list_lock);
2691
2692 mutex_lock(&routing_table_lock);
2693 if (!routing_table_inited) {
2694 init_routing_table();
2695 rt_entry = alloc_routing_table_entry(IPC_ROUTER_NID_LOCAL);
2696 add_routing_table_entry(rt_entry);
2697 routing_table_inited = 1;
2698 }
2699 mutex_unlock(&routing_table_lock);
2700
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002701 xprt->priv = xprt_info;
2702
2703 return 0;
2704}
2705
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002706static void msm_ipc_router_remove_xprt(struct msm_ipc_router_xprt *xprt)
2707{
2708 struct msm_ipc_router_xprt_info *xprt_info;
2709
2710 if (xprt && xprt->priv) {
2711 xprt_info = xprt->priv;
2712
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06002713 mutex_lock(&xprt_info->rx_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002714 xprt_info->abort_data_read = 1;
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06002715 mutex_unlock(&xprt_info->rx_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002716
2717 mutex_lock(&xprt_info_list_lock);
2718 list_del(&xprt_info->list);
2719 mutex_unlock(&xprt_info_list_lock);
2720
2721 flush_workqueue(xprt_info->workqueue);
2722 destroy_workqueue(xprt_info->workqueue);
2723 wake_lock_destroy(&xprt_info->wakelock);
2724
2725 xprt->priv = 0;
2726 kfree(xprt_info);
2727 }
2728}
2729
2730
2731struct msm_ipc_router_xprt_work {
2732 struct msm_ipc_router_xprt *xprt;
2733 struct work_struct work;
2734};
2735
2736static void xprt_open_worker(struct work_struct *work)
2737{
2738 struct msm_ipc_router_xprt_work *xprt_work =
2739 container_of(work, struct msm_ipc_router_xprt_work, work);
2740
2741 msm_ipc_router_add_xprt(xprt_work->xprt);
2742 kfree(xprt_work);
2743}
2744
2745static void xprt_close_worker(struct work_struct *work)
2746{
2747 struct msm_ipc_router_xprt_work *xprt_work =
2748 container_of(work, struct msm_ipc_router_xprt_work, work);
2749
2750 modem_reset_cleanup(xprt_work->xprt->priv);
2751 msm_ipc_router_remove_xprt(xprt_work->xprt);
2752
2753 if (atomic_dec_return(&pending_close_count) == 0)
2754 wake_up(&subsystem_restart_wait);
2755
2756 kfree(xprt_work);
2757}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002758
2759void msm_ipc_router_xprt_notify(struct msm_ipc_router_xprt *xprt,
2760 unsigned event,
2761 void *data)
2762{
2763 struct msm_ipc_router_xprt_info *xprt_info = xprt->priv;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002764 struct msm_ipc_router_xprt_work *xprt_work;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002765 struct rr_packet *pkt;
Karthikeyan Ramasubramanian4af9f7c2011-09-30 15:55:18 -06002766 unsigned long ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002767
Karthikeyan Ramasubramanian4af9f7c2011-09-30 15:55:18 -06002768 if (!msm_ipc_router_workqueue) {
2769 ret = wait_for_completion_timeout(&msm_ipc_local_router_up,
2770 IPC_ROUTER_INIT_TIMEOUT);
2771 if (!ret || !msm_ipc_router_workqueue) {
2772 pr_err("%s: IPC Router not initialized\n", __func__);
2773 return;
2774 }
2775 }
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002776
2777 switch (event) {
2778 case IPC_ROUTER_XPRT_EVENT_OPEN:
2779 D("open event for '%s'\n", xprt->name);
2780 xprt_work = kmalloc(sizeof(struct msm_ipc_router_xprt_work),
2781 GFP_ATOMIC);
2782 xprt_work->xprt = xprt;
2783 INIT_WORK(&xprt_work->work, xprt_open_worker);
2784 queue_work(msm_ipc_router_workqueue, &xprt_work->work);
2785 break;
2786
2787 case IPC_ROUTER_XPRT_EVENT_CLOSE:
2788 D("close event for '%s'\n", xprt->name);
2789 atomic_inc(&pending_close_count);
2790 xprt_work = kmalloc(sizeof(struct msm_ipc_router_xprt_work),
2791 GFP_ATOMIC);
2792 xprt_work->xprt = xprt;
2793 INIT_WORK(&xprt_work->work, xprt_close_worker);
2794 queue_work(msm_ipc_router_workqueue, &xprt_work->work);
2795 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002796 }
2797
2798 if (!data)
2799 return;
2800
2801 while (!xprt_info) {
2802 msleep(100);
2803 xprt_info = xprt->priv;
2804 }
2805
2806 pkt = clone_pkt((struct rr_packet *)data);
2807 if (!pkt)
2808 return;
2809
2810 mutex_lock(&xprt_info->rx_lock);
2811 list_add_tail(&pkt->list, &xprt_info->pkt_list);
2812 wake_lock(&xprt_info->wakelock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002813 mutex_unlock(&xprt_info->rx_lock);
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06002814 queue_work(xprt_info->workqueue, &xprt_info->read_data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002815}
2816
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002817static int modem_restart_notifier_cb(struct notifier_block *this,
2818 unsigned long code,
2819 void *data);
2820static struct notifier_block msm_ipc_router_nb = {
2821 .notifier_call = modem_restart_notifier_cb,
2822};
2823
2824static int modem_restart_notifier_cb(struct notifier_block *this,
2825 unsigned long code,
2826 void *data)
2827{
2828 switch (code) {
2829 case SUBSYS_BEFORE_SHUTDOWN:
2830 D("%s: SUBSYS_BEFORE_SHUTDOWN\n", __func__);
2831 break;
2832
2833 case SUBSYS_BEFORE_POWERUP:
2834 D("%s: waiting for RPC restart to complete\n", __func__);
2835 wait_event(subsystem_restart_wait,
2836 atomic_read(&pending_close_count) == 0);
2837 D("%s: finished restart wait\n", __func__);
2838 break;
2839
2840 default:
2841 break;
2842 }
2843
2844 return NOTIFY_DONE;
2845}
2846
2847static void *restart_notifier_handle;
2848static __init int msm_ipc_router_modem_restart_late_init(void)
2849{
2850 restart_notifier_handle = subsys_notif_register_notifier("modem",
2851 &msm_ipc_router_nb);
2852 return 0;
2853}
2854late_initcall(msm_ipc_router_modem_restart_late_init);
2855
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002856static int __init msm_ipc_router_init(void)
2857{
2858 int i, ret;
2859 struct msm_ipc_routing_table_entry *rt_entry;
2860
2861 msm_ipc_router_debug_mask |= SMEM_LOG;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002862 msm_ipc_router_workqueue =
2863 create_singlethread_workqueue("msm_ipc_router");
2864 if (!msm_ipc_router_workqueue)
2865 return -ENOMEM;
2866
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002867 debugfs_init();
2868
2869 for (i = 0; i < SRV_HASH_SIZE; i++)
2870 INIT_LIST_HEAD(&server_list[i]);
2871
2872 for (i = 0; i < LP_HASH_SIZE; i++)
2873 INIT_LIST_HEAD(&local_ports[i]);
2874
2875 mutex_lock(&routing_table_lock);
2876 if (!routing_table_inited) {
2877 init_routing_table();
2878 rt_entry = alloc_routing_table_entry(IPC_ROUTER_NID_LOCAL);
2879 add_routing_table_entry(rt_entry);
2880 routing_table_inited = 1;
2881 }
2882 mutex_unlock(&routing_table_lock);
2883
2884 init_waitqueue_head(&newserver_wait);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002885 init_waitqueue_head(&subsystem_restart_wait);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002886 ret = msm_ipc_router_init_sockets();
2887 if (ret < 0)
2888 pr_err("%s: Init sockets failed\n", __func__);
2889
Karthikeyan Ramasubramanian5b502d3642012-09-23 22:23:36 -06002890 ret = msm_ipc_router_security_init();
2891 if (ret < 0)
2892 pr_err("%s: Security Init failed\n", __func__);
2893
Karthikeyan Ramasubramanian4af9f7c2011-09-30 15:55:18 -06002894 complete_all(&msm_ipc_local_router_up);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002895 return ret;
2896}
2897
2898module_init(msm_ipc_router_init);
2899MODULE_DESCRIPTION("MSM IPC Router");
2900MODULE_LICENSE("GPL v2");