blob: d81dbb4e828ec9fe45e7a90d54171c32c44057ea [file] [log] [blame]
Karthikeyan Ramasubramanian5c568fb2013-01-10 17:09:13 -07001/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#define DEBUG
14
15#include <linux/slab.h>
16#include <linux/module.h>
17#include <linux/kernel.h>
18#include <linux/string.h>
19#include <linux/errno.h>
20#include <linux/init.h>
21#include <linux/types.h>
22#include <linux/delay.h>
23#include <linux/err.h>
24#include <linux/sched.h>
25#include <linux/poll.h>
26#include <linux/wakelock.h>
27#include <linux/platform_device.h>
28#include <linux/uaccess.h>
29#include <linux/debugfs.h>
30
31#include <asm/uaccess.h>
32#include <asm/byteorder.h>
33
34#include <mach/smem_log.h>
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -060035#include <mach/subsystem_notif.h>
Karthikeyan Ramasubramanianefc493b2012-07-12 10:25:49 -060036#include <mach/msm_ipc_router.h>
Karthikeyan Ramasubramanian2bfe8ec2013-03-22 10:47:20 -060037#include <mach/msm_ipc_logging.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070038
39#include "ipc_router.h"
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -060040#include "modem_notifier.h"
Karthikeyan Ramasubramanian5b502d3642012-09-23 22:23:36 -060041#include "msm_ipc_router_security.h"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070042
43enum {
44 SMEM_LOG = 1U << 0,
45 RTR_DBG = 1U << 1,
46 R2R_MSG = 1U << 2,
47 R2R_RAW = 1U << 3,
48 NTFY_MSG = 1U << 4,
49 R2R_RAW_HDR = 1U << 5,
50};
51
52static int msm_ipc_router_debug_mask;
53module_param_named(debug_mask, msm_ipc_router_debug_mask,
54 int, S_IRUGO | S_IWUSR | S_IWGRP);
55
Karthikeyan Ramasubramanian2bfe8ec2013-03-22 10:47:20 -060056static void *ipc_rtr_log_ctxt;
57#define IPC_RTR_LOG_PAGES 5
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070058#define DIAG(x...) pr_info("[RR] ERROR " x)
59
60#if defined(DEBUG)
61#define D(x...) do { \
Karthikeyan Ramasubramanian2bfe8ec2013-03-22 10:47:20 -060062if (ipc_rtr_log_ctxt) \
63 ipc_log_string(ipc_rtr_log_ctxt, x); \
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070064if (msm_ipc_router_debug_mask & RTR_DBG) \
65 pr_info(x); \
66} while (0)
67
68#define RR(x...) do { \
Karthikeyan Ramasubramanian2bfe8ec2013-03-22 10:47:20 -060069if (ipc_rtr_log_ctxt) \
70 ipc_log_string(ipc_rtr_log_ctxt, x); \
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070071if (msm_ipc_router_debug_mask & R2R_MSG) \
72 pr_info("[RR] "x); \
73} while (0)
74
75#define RAW(x...) do { \
76if (msm_ipc_router_debug_mask & R2R_RAW) \
77 pr_info("[RAW] "x); \
78} while (0)
79
80#define NTFY(x...) do { \
81if (msm_ipc_router_debug_mask & NTFY_MSG) \
82 pr_info("[NOTIFY] "x); \
83} while (0)
84
85#define RAW_HDR(x...) do { \
86if (msm_ipc_router_debug_mask & R2R_RAW_HDR) \
87 pr_info("[HDR] "x); \
88} while (0)
89#else
90#define D(x...) do { } while (0)
91#define RR(x...) do { } while (0)
92#define RAW(x...) do { } while (0)
93#define RAW_HDR(x...) do { } while (0)
94#define NTFY(x...) do { } while (0)
95#endif
96
97#define IPC_ROUTER_LOG_EVENT_ERROR 0x10
98#define IPC_ROUTER_LOG_EVENT_TX 0x11
99#define IPC_ROUTER_LOG_EVENT_RX 0x12
100
101static LIST_HEAD(control_ports);
102static DEFINE_MUTEX(control_ports_lock);
103
104#define LP_HASH_SIZE 32
105static struct list_head local_ports[LP_HASH_SIZE];
106static DEFINE_MUTEX(local_ports_lock);
107
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -0600108/*
109 * Server info is organized as a hash table. The server's service ID is
110 * used to index into the hash table. The instance ID of most of the servers
111 * are 1 or 2. The service IDs are well distributed compared to the instance
112 * IDs and hence choosing service ID to index into this hash table optimizes
113 * the hash table operations like add, lookup, destroy.
114 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700115#define SRV_HASH_SIZE 32
116static struct list_head server_list[SRV_HASH_SIZE];
117static DEFINE_MUTEX(server_list_lock);
118static wait_queue_head_t newserver_wait;
119
120struct msm_ipc_server {
121 struct list_head list;
122 struct msm_ipc_port_name name;
Karthikeyan Ramasubramanianefc493b2012-07-12 10:25:49 -0600123 char pdev_name[32];
124 int next_pdev_id;
Karthikeyan Ramasubramanian5b502d3642012-09-23 22:23:36 -0600125 int synced_sec_rule;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700126 struct list_head server_port_list;
127};
128
129struct msm_ipc_server_port {
130 struct list_head list;
Karthikeyan Ramasubramanianefc493b2012-07-12 10:25:49 -0600131 struct platform_device pdev;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700132 struct msm_ipc_port_addr server_addr;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600133 struct msm_ipc_router_xprt_info *xprt_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700134};
135
136#define RP_HASH_SIZE 32
137struct msm_ipc_router_remote_port {
138 struct list_head list;
139 uint32_t node_id;
140 uint32_t port_id;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600141 uint32_t restart_state;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700142 wait_queue_head_t quota_wait;
143 uint32_t tx_quota_cnt;
144 struct mutex quota_lock;
Karthikeyan Ramasubramanian5b502d3642012-09-23 22:23:36 -0600145 void *sec_rule;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700146};
147
148struct msm_ipc_router_xprt_info {
149 struct list_head list;
150 struct msm_ipc_router_xprt *xprt;
151 uint32_t remote_node_id;
152 uint32_t initialized;
153 struct list_head pkt_list;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700154 struct wake_lock wakelock;
155 struct mutex rx_lock;
156 struct mutex tx_lock;
157 uint32_t need_len;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600158 uint32_t abort_data_read;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700159 struct work_struct read_data;
160 struct workqueue_struct *workqueue;
161};
162
163#define RT_HASH_SIZE 4
164struct msm_ipc_routing_table_entry {
165 struct list_head list;
166 uint32_t node_id;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600167 uint32_t neighbor_node_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700168 struct list_head remote_port_list[RP_HASH_SIZE];
169 struct msm_ipc_router_xprt_info *xprt_info;
170 struct mutex lock;
171 unsigned long num_tx_bytes;
172 unsigned long num_rx_bytes;
173};
174
175static struct list_head routing_table[RT_HASH_SIZE];
176static DEFINE_MUTEX(routing_table_lock);
177static int routing_table_inited;
178
179static LIST_HEAD(msm_ipc_board_dev_list);
180static DEFINE_MUTEX(msm_ipc_board_dev_list_lock);
181
182static void do_read_data(struct work_struct *work);
183
184#define RR_STATE_IDLE 0
185#define RR_STATE_HEADER 1
186#define RR_STATE_BODY 2
187#define RR_STATE_ERROR 3
188
189#define RESTART_NORMAL 0
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600190#define RESTART_PEND 1
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700191
192/* State for remote ep following restart */
193#define RESTART_QUOTA_ABORT 1
194
195static LIST_HEAD(xprt_info_list);
196static DEFINE_MUTEX(xprt_info_list_lock);
197
Karthikeyan Ramasubramanian4af9f7c2011-09-30 15:55:18 -0600198static DECLARE_COMPLETION(msm_ipc_local_router_up);
199#define IPC_ROUTER_INIT_TIMEOUT (10 * HZ)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700200
201static uint32_t next_port_id;
202static DEFINE_MUTEX(next_port_id_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600203static atomic_t pending_close_count = ATOMIC_INIT(0);
204static wait_queue_head_t subsystem_restart_wait;
205static struct workqueue_struct *msm_ipc_router_workqueue;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700206
207enum {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700208 DOWN,
209 UP,
210};
211
212static void init_routing_table(void)
213{
214 int i;
215 for (i = 0; i < RT_HASH_SIZE; i++)
216 INIT_LIST_HEAD(&routing_table[i]);
217}
218
219static struct msm_ipc_routing_table_entry *alloc_routing_table_entry(
220 uint32_t node_id)
221{
222 int i;
223 struct msm_ipc_routing_table_entry *rt_entry;
224
225 rt_entry = kmalloc(sizeof(struct msm_ipc_routing_table_entry),
226 GFP_KERNEL);
227 if (!rt_entry) {
228 pr_err("%s: rt_entry allocation failed for %d\n",
229 __func__, node_id);
230 return NULL;
231 }
232
233 for (i = 0; i < RP_HASH_SIZE; i++)
234 INIT_LIST_HEAD(&rt_entry->remote_port_list[i]);
235
236 mutex_init(&rt_entry->lock);
237 rt_entry->node_id = node_id;
238 rt_entry->xprt_info = NULL;
239 return rt_entry;
240}
241
242/*Please take routing_table_lock before calling this function*/
243static int add_routing_table_entry(
244 struct msm_ipc_routing_table_entry *rt_entry)
245{
246 uint32_t key;
247
248 if (!rt_entry)
249 return -EINVAL;
250
251 key = (rt_entry->node_id % RT_HASH_SIZE);
252 list_add_tail(&rt_entry->list, &routing_table[key]);
253 return 0;
254}
255
256/*Please take routing_table_lock before calling this function*/
257static struct msm_ipc_routing_table_entry *lookup_routing_table(
258 uint32_t node_id)
259{
260 uint32_t key = (node_id % RT_HASH_SIZE);
261 struct msm_ipc_routing_table_entry *rt_entry;
262
263 list_for_each_entry(rt_entry, &routing_table[key], list) {
264 if (rt_entry->node_id == node_id)
265 return rt_entry;
266 }
267 return NULL;
268}
269
270struct rr_packet *rr_read(struct msm_ipc_router_xprt_info *xprt_info)
271{
272 struct rr_packet *temp_pkt;
273
274 if (!xprt_info)
275 return NULL;
276
277 mutex_lock(&xprt_info->rx_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600278 if (xprt_info->abort_data_read) {
279 mutex_unlock(&xprt_info->rx_lock);
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -0600280 pr_err("%s detected SSR & exiting now\n",
281 xprt_info->xprt->name);
282 return NULL;
283 }
284
285 if (list_empty(&xprt_info->pkt_list)) {
286 mutex_unlock(&xprt_info->rx_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600287 return NULL;
288 }
289
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700290 temp_pkt = list_first_entry(&xprt_info->pkt_list,
291 struct rr_packet, list);
292 list_del(&temp_pkt->list);
293 if (list_empty(&xprt_info->pkt_list))
294 wake_unlock(&xprt_info->wakelock);
295 mutex_unlock(&xprt_info->rx_lock);
296 return temp_pkt;
297}
298
299struct rr_packet *clone_pkt(struct rr_packet *pkt)
300{
301 struct rr_packet *cloned_pkt;
302 struct sk_buff *temp_skb, *cloned_skb;
303 struct sk_buff_head *pkt_fragment_q;
304
305 cloned_pkt = kzalloc(sizeof(struct rr_packet), GFP_KERNEL);
306 if (!cloned_pkt) {
307 pr_err("%s: failure\n", __func__);
308 return NULL;
309 }
310
311 pkt_fragment_q = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
312 if (!pkt_fragment_q) {
313 pr_err("%s: pkt_frag_q alloc failure\n", __func__);
314 kfree(cloned_pkt);
315 return NULL;
316 }
317 skb_queue_head_init(pkt_fragment_q);
318
319 skb_queue_walk(pkt->pkt_fragment_q, temp_skb) {
320 cloned_skb = skb_clone(temp_skb, GFP_KERNEL);
321 if (!cloned_skb)
322 goto fail_clone;
323 skb_queue_tail(pkt_fragment_q, cloned_skb);
324 }
325 cloned_pkt->pkt_fragment_q = pkt_fragment_q;
326 cloned_pkt->length = pkt->length;
327 return cloned_pkt;
328
329fail_clone:
330 while (!skb_queue_empty(pkt_fragment_q)) {
331 temp_skb = skb_dequeue(pkt_fragment_q);
332 kfree_skb(temp_skb);
333 }
334 kfree(pkt_fragment_q);
335 kfree(cloned_pkt);
336 return NULL;
337}
338
339struct rr_packet *create_pkt(struct sk_buff_head *data)
340{
341 struct rr_packet *pkt;
342 struct sk_buff *temp_skb;
343
344 pkt = kzalloc(sizeof(struct rr_packet), GFP_KERNEL);
345 if (!pkt) {
346 pr_err("%s: failure\n", __func__);
347 return NULL;
348 }
349
350 pkt->pkt_fragment_q = data;
351 skb_queue_walk(pkt->pkt_fragment_q, temp_skb)
352 pkt->length += temp_skb->len;
353 return pkt;
354}
355
356void release_pkt(struct rr_packet *pkt)
357{
358 struct sk_buff *temp_skb;
359
360 if (!pkt)
361 return;
362
363 if (!pkt->pkt_fragment_q) {
364 kfree(pkt);
365 return;
366 }
367
368 while (!skb_queue_empty(pkt->pkt_fragment_q)) {
369 temp_skb = skb_dequeue(pkt->pkt_fragment_q);
370 kfree_skb(temp_skb);
371 }
372 kfree(pkt->pkt_fragment_q);
373 kfree(pkt);
374 return;
375}
376
Karthikeyan Ramasubramanianefc493b2012-07-12 10:25:49 -0600377static struct sk_buff_head *msm_ipc_router_buf_to_skb(void *buf,
378 unsigned int buf_len)
379{
380 struct sk_buff_head *skb_head;
381 struct sk_buff *skb;
382 int first = 1, offset = 0;
383 int skb_size, data_size;
384 void *data;
385
386 skb_head = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
387 if (!skb_head) {
388 pr_err("%s: Couldnot allocate skb_head\n", __func__);
389 return NULL;
390 }
391 skb_queue_head_init(skb_head);
392
393 data_size = buf_len;
394 while (offset != buf_len) {
395 skb_size = data_size;
396 if (first)
397 skb_size += IPC_ROUTER_HDR_SIZE;
398
399 skb = alloc_skb(skb_size, GFP_KERNEL);
400 if (!skb) {
401 if (skb_size <= (PAGE_SIZE/2)) {
402 pr_err("%s: cannot allocate skb\n", __func__);
403 goto buf_to_skb_error;
404 }
405 data_size = data_size / 2;
406 continue;
407 }
408
409 if (first) {
410 skb_reserve(skb, IPC_ROUTER_HDR_SIZE);
411 first = 0;
412 }
413
414 data = skb_put(skb, data_size);
415 memcpy(skb->data, buf + offset, data_size);
416 skb_queue_tail(skb_head, skb);
417 offset += data_size;
418 data_size = buf_len - offset;
419 }
420 return skb_head;
421
422buf_to_skb_error:
423 while (!skb_queue_empty(skb_head)) {
424 skb = skb_dequeue(skb_head);
425 kfree_skb(skb);
426 }
427 kfree(skb_head);
428 return NULL;
429}
430
431static void *msm_ipc_router_skb_to_buf(struct sk_buff_head *skb_head,
432 unsigned int len)
433{
434 struct sk_buff *temp;
435 int offset = 0, buf_len = 0, copy_len;
436 void *buf;
437
438 if (!skb_head) {
439 pr_err("%s: NULL skb_head\n", __func__);
440 return NULL;
441 }
442
443 temp = skb_peek(skb_head);
444 buf_len = len;
445 buf = kmalloc(buf_len, GFP_KERNEL);
446 if (!buf) {
447 pr_err("%s: cannot allocate buf\n", __func__);
448 return NULL;
449 }
450 skb_queue_walk(skb_head, temp) {
451 copy_len = buf_len < temp->len ? buf_len : temp->len;
452 memcpy(buf + offset, temp->data, copy_len);
453 offset += copy_len;
454 buf_len -= copy_len;
455 }
456 return buf;
457}
458
459static void msm_ipc_router_free_skb(struct sk_buff_head *skb_head)
460{
461 struct sk_buff *temp_skb;
462
463 if (!skb_head)
464 return;
465
466 while (!skb_queue_empty(skb_head)) {
467 temp_skb = skb_dequeue(skb_head);
468 kfree_skb(temp_skb);
469 }
470 kfree(skb_head);
471}
472
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700473static int post_control_ports(struct rr_packet *pkt)
474{
475 struct msm_ipc_port *port_ptr;
476 struct rr_packet *cloned_pkt;
477
478 if (!pkt)
479 return -EINVAL;
480
481 mutex_lock(&control_ports_lock);
482 list_for_each_entry(port_ptr, &control_ports, list) {
483 mutex_lock(&port_ptr->port_rx_q_lock);
484 cloned_pkt = clone_pkt(pkt);
485 wake_lock(&port_ptr->port_rx_wake_lock);
486 list_add_tail(&cloned_pkt->list, &port_ptr->port_rx_q);
487 wake_up(&port_ptr->port_rx_wait_q);
488 mutex_unlock(&port_ptr->port_rx_q_lock);
489 }
490 mutex_unlock(&control_ports_lock);
491 return 0;
492}
493
494static uint32_t allocate_port_id(void)
495{
496 uint32_t port_id = 0, prev_port_id, key;
497 struct msm_ipc_port *port_ptr;
498
499 mutex_lock(&next_port_id_lock);
500 prev_port_id = next_port_id;
501 mutex_lock(&local_ports_lock);
502 do {
503 next_port_id++;
504 if ((next_port_id & 0xFFFFFFFE) == 0xFFFFFFFE)
505 next_port_id = 1;
506
507 key = (next_port_id & (LP_HASH_SIZE - 1));
508 if (list_empty(&local_ports[key])) {
509 port_id = next_port_id;
510 break;
511 }
512 list_for_each_entry(port_ptr, &local_ports[key], list) {
513 if (port_ptr->this_port.port_id == next_port_id) {
514 port_id = next_port_id;
515 break;
516 }
517 }
518 if (!port_id) {
519 port_id = next_port_id;
520 break;
521 }
522 port_id = 0;
523 } while (next_port_id != prev_port_id);
524 mutex_unlock(&local_ports_lock);
525 mutex_unlock(&next_port_id_lock);
526
527 return port_id;
528}
529
530void msm_ipc_router_add_local_port(struct msm_ipc_port *port_ptr)
531{
532 uint32_t key;
533
534 if (!port_ptr)
535 return;
536
537 key = (port_ptr->this_port.port_id & (LP_HASH_SIZE - 1));
538 mutex_lock(&local_ports_lock);
539 list_add_tail(&port_ptr->list, &local_ports[key]);
540 mutex_unlock(&local_ports_lock);
541}
542
543struct msm_ipc_port *msm_ipc_router_create_raw_port(void *endpoint,
Karthikeyan Ramasubramanianefc493b2012-07-12 10:25:49 -0600544 void (*notify)(unsigned event, void *priv),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700545 void *priv)
546{
547 struct msm_ipc_port *port_ptr;
548
549 port_ptr = kzalloc(sizeof(struct msm_ipc_port), GFP_KERNEL);
550 if (!port_ptr)
551 return NULL;
552
553 port_ptr->this_port.node_id = IPC_ROUTER_NID_LOCAL;
554 port_ptr->this_port.port_id = allocate_port_id();
555 if (!port_ptr->this_port.port_id) {
556 pr_err("%s: All port ids are in use\n", __func__);
557 kfree(port_ptr);
558 return NULL;
559 }
560
561 spin_lock_init(&port_ptr->port_lock);
562 INIT_LIST_HEAD(&port_ptr->incomplete);
563 mutex_init(&port_ptr->incomplete_lock);
564 INIT_LIST_HEAD(&port_ptr->port_rx_q);
565 mutex_init(&port_ptr->port_rx_q_lock);
566 init_waitqueue_head(&port_ptr->port_rx_wait_q);
Karthikeyan Ramasubramanianb4aeeb92012-03-13 12:31:43 -0600567 snprintf(port_ptr->rx_wakelock_name, MAX_WAKELOCK_NAME_SZ,
Karthikeyan Ramasubramanian6396bdd2013-02-14 13:53:20 -0700568 "ipc%08x_%s",
569 port_ptr->this_port.port_id,
570 current->comm);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700571 wake_lock_init(&port_ptr->port_rx_wake_lock,
Karthikeyan Ramasubramanianb4aeeb92012-03-13 12:31:43 -0600572 WAKE_LOCK_SUSPEND, port_ptr->rx_wakelock_name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700573
574 port_ptr->endpoint = endpoint;
575 port_ptr->notify = notify;
576 port_ptr->priv = priv;
577
578 msm_ipc_router_add_local_port(port_ptr);
579 return port_ptr;
580}
581
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -0600582/*
583 * Should be called with local_ports_lock locked
584 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700585static struct msm_ipc_port *msm_ipc_router_lookup_local_port(uint32_t port_id)
586{
587 int key = (port_id & (LP_HASH_SIZE - 1));
588 struct msm_ipc_port *port_ptr;
589
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700590 list_for_each_entry(port_ptr, &local_ports[key], list) {
591 if (port_ptr->this_port.port_id == port_id) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700592 return port_ptr;
593 }
594 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700595 return NULL;
596}
597
598static struct msm_ipc_router_remote_port *msm_ipc_router_lookup_remote_port(
599 uint32_t node_id,
600 uint32_t port_id)
601{
602 struct msm_ipc_router_remote_port *rport_ptr;
603 struct msm_ipc_routing_table_entry *rt_entry;
604 int key = (port_id & (RP_HASH_SIZE - 1));
605
606 mutex_lock(&routing_table_lock);
607 rt_entry = lookup_routing_table(node_id);
608 if (!rt_entry) {
609 mutex_unlock(&routing_table_lock);
610 pr_err("%s: Node is not up\n", __func__);
611 return NULL;
612 }
613
614 mutex_lock(&rt_entry->lock);
615 list_for_each_entry(rport_ptr,
616 &rt_entry->remote_port_list[key], list) {
617 if (rport_ptr->port_id == port_id) {
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600618 if (rport_ptr->restart_state != RESTART_NORMAL)
619 rport_ptr = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700620 mutex_unlock(&rt_entry->lock);
621 mutex_unlock(&routing_table_lock);
622 return rport_ptr;
623 }
624 }
625 mutex_unlock(&rt_entry->lock);
626 mutex_unlock(&routing_table_lock);
627 return NULL;
628}
629
630static struct msm_ipc_router_remote_port *msm_ipc_router_create_remote_port(
631 uint32_t node_id,
632 uint32_t port_id)
633{
634 struct msm_ipc_router_remote_port *rport_ptr;
635 struct msm_ipc_routing_table_entry *rt_entry;
636 int key = (port_id & (RP_HASH_SIZE - 1));
637
638 mutex_lock(&routing_table_lock);
639 rt_entry = lookup_routing_table(node_id);
640 if (!rt_entry) {
641 mutex_unlock(&routing_table_lock);
642 pr_err("%s: Node is not up\n", __func__);
643 return NULL;
644 }
645
646 mutex_lock(&rt_entry->lock);
647 rport_ptr = kmalloc(sizeof(struct msm_ipc_router_remote_port),
648 GFP_KERNEL);
649 if (!rport_ptr) {
650 mutex_unlock(&rt_entry->lock);
651 mutex_unlock(&routing_table_lock);
652 pr_err("%s: Remote port alloc failed\n", __func__);
653 return NULL;
654 }
655 rport_ptr->port_id = port_id;
656 rport_ptr->node_id = node_id;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600657 rport_ptr->restart_state = RESTART_NORMAL;
Karthikeyan Ramasubramanian5b502d3642012-09-23 22:23:36 -0600658 rport_ptr->sec_rule = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700659 rport_ptr->tx_quota_cnt = 0;
660 init_waitqueue_head(&rport_ptr->quota_wait);
661 mutex_init(&rport_ptr->quota_lock);
662 list_add_tail(&rport_ptr->list,
663 &rt_entry->remote_port_list[key]);
664 mutex_unlock(&rt_entry->lock);
665 mutex_unlock(&routing_table_lock);
666 return rport_ptr;
667}
668
669static void msm_ipc_router_destroy_remote_port(
670 struct msm_ipc_router_remote_port *rport_ptr)
671{
672 uint32_t node_id;
673 struct msm_ipc_routing_table_entry *rt_entry;
674
675 if (!rport_ptr)
676 return;
677
678 node_id = rport_ptr->node_id;
679 mutex_lock(&routing_table_lock);
680 rt_entry = lookup_routing_table(node_id);
681 if (!rt_entry) {
682 mutex_unlock(&routing_table_lock);
683 pr_err("%s: Node %d is not up\n", __func__, node_id);
684 return;
685 }
686
687 mutex_lock(&rt_entry->lock);
688 list_del(&rport_ptr->list);
689 kfree(rport_ptr);
690 mutex_unlock(&rt_entry->lock);
691 mutex_unlock(&routing_table_lock);
692 return;
693}
694
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -0600695/**
696 * msm_ipc_router_lookup_server() - Lookup server information
697 * @service: Service ID of the server info to be looked up.
698 * @instance: Instance ID of the server info to be looked up.
699 * @node_id: Node/Processor ID in which the server is hosted.
700 * @port_id: Port ID within the node in which the server is hosted.
701 *
702 * @return: If found Pointer to server structure, else NULL.
703 *
704 * Note1: Lock the server_list_lock before accessing this function.
705 * Note2: If the <node_id:port_id> are <0:0>, then the lookup is restricted
706 * to <service:instance>. Used only when a client wants to send a
707 * message to any QMI server.
708 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700709static struct msm_ipc_server *msm_ipc_router_lookup_server(
710 uint32_t service,
711 uint32_t instance,
712 uint32_t node_id,
713 uint32_t port_id)
714{
715 struct msm_ipc_server *server;
716 struct msm_ipc_server_port *server_port;
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -0600717 int key = (service & (SRV_HASH_SIZE - 1));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700718
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700719 list_for_each_entry(server, &server_list[key], list) {
720 if ((server->name.service != service) ||
721 (server->name.instance != instance))
722 continue;
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -0600723 if ((node_id == 0) && (port_id == 0))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700724 return server;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700725 list_for_each_entry(server_port, &server->server_port_list,
726 list) {
727 if ((server_port->server_addr.node_id == node_id) &&
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -0600728 (server_port->server_addr.port_id == port_id))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700729 return server;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700730 }
731 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700732 return NULL;
733}
734
Karthikeyan Ramasubramanianefc493b2012-07-12 10:25:49 -0600735static void dummy_release(struct device *dev)
736{
737}
738
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -0600739/**
740 * msm_ipc_router_create_server() - Add server info to hash table
741 * @service: Service ID of the server info to be created.
742 * @instance: Instance ID of the server info to be created.
743 * @node_id: Node/Processor ID in which the server is hosted.
744 * @port_id: Port ID within the node in which the server is hosted.
745 * @xprt_info: XPRT through which the node hosting the server is reached.
746 *
747 * @return: Pointer to server structure on success, else NULL.
748 *
749 * This function adds the server info to the hash table. If the same
750 * server(i.e. <service_id:instance_id>) is hosted in different nodes,
751 * they are maintained as list of "server_port" under "server" structure.
752 * Note: Lock the server_list_lock before accessing this function.
753 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700754static struct msm_ipc_server *msm_ipc_router_create_server(
755 uint32_t service,
756 uint32_t instance,
757 uint32_t node_id,
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600758 uint32_t port_id,
759 struct msm_ipc_router_xprt_info *xprt_info)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700760{
761 struct msm_ipc_server *server = NULL;
762 struct msm_ipc_server_port *server_port;
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -0600763 int key = (service & (SRV_HASH_SIZE - 1));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700764
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700765 list_for_each_entry(server, &server_list[key], list) {
766 if ((server->name.service == service) &&
767 (server->name.instance == instance))
768 goto create_srv_port;
769 }
770
Karthikeyan Ramasubramanianefc493b2012-07-12 10:25:49 -0600771 server = kzalloc(sizeof(struct msm_ipc_server), GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700772 if (!server) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700773 pr_err("%s: Server allocation failed\n", __func__);
774 return NULL;
775 }
776 server->name.service = service;
777 server->name.instance = instance;
Karthikeyan Ramasubramanian5b502d3642012-09-23 22:23:36 -0600778 server->synced_sec_rule = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700779 INIT_LIST_HEAD(&server->server_port_list);
780 list_add_tail(&server->list, &server_list[key]);
Karthikeyan Ramasubramanianefc493b2012-07-12 10:25:49 -0600781 scnprintf(server->pdev_name, sizeof(server->pdev_name),
782 "QMI%08x:%08x", service, instance);
783 server->next_pdev_id = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700784
785create_srv_port:
Karthikeyan Ramasubramanianefc493b2012-07-12 10:25:49 -0600786 server_port = kzalloc(sizeof(struct msm_ipc_server_port), GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700787 if (!server_port) {
788 if (list_empty(&server->server_port_list)) {
789 list_del(&server->list);
790 kfree(server);
791 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700792 pr_err("%s: Server Port allocation failed\n", __func__);
793 return NULL;
794 }
795 server_port->server_addr.node_id = node_id;
796 server_port->server_addr.port_id = port_id;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600797 server_port->xprt_info = xprt_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700798 list_add_tail(&server_port->list, &server->server_port_list);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700799
Karthikeyan Ramasubramanianefc493b2012-07-12 10:25:49 -0600800 server_port->pdev.name = server->pdev_name;
801 server_port->pdev.id = server->next_pdev_id++;
802 server_port->pdev.dev.release = dummy_release;
803 platform_device_register(&server_port->pdev);
804
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700805 return server;
806}
807
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -0600808/**
809 * msm_ipc_router_destroy_server() - Remove server info from hash table
810 * @server: Server info to be removed.
811 * @node_id: Node/Processor ID in which the server is hosted.
812 * @port_id: Port ID within the node in which the server is hosted.
813 *
814 * This function removes the server_port identified using <node_id:port_id>
815 * from the server structure. If the server_port list under server structure
816 * is empty after removal, then remove the server structure from the server
817 * hash table.
818 * Note: Lock the server_list_lock before accessing this function.
819 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700820static void msm_ipc_router_destroy_server(struct msm_ipc_server *server,
821 uint32_t node_id, uint32_t port_id)
822{
823 struct msm_ipc_server_port *server_port;
824
825 if (!server)
826 return;
827
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700828 list_for_each_entry(server_port, &server->server_port_list, list) {
829 if ((server_port->server_addr.node_id == node_id) &&
830 (server_port->server_addr.port_id == port_id))
831 break;
832 }
833 if (server_port) {
Karthikeyan Ramasubramanianefc493b2012-07-12 10:25:49 -0600834 platform_device_unregister(&server_port->pdev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700835 list_del(&server_port->list);
836 kfree(server_port);
837 }
838 if (list_empty(&server->server_port_list)) {
839 list_del(&server->list);
840 kfree(server);
841 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700842 return;
843}
844
845static int msm_ipc_router_send_control_msg(
846 struct msm_ipc_router_xprt_info *xprt_info,
847 union rr_control_msg *msg)
848{
849 struct rr_packet *pkt;
850 struct sk_buff *ipc_rtr_pkt;
851 struct rr_header *hdr;
852 int pkt_size;
853 void *data;
854 struct sk_buff_head *pkt_fragment_q;
855 int ret;
856
857 if (!xprt_info || ((msg->cmd != IPC_ROUTER_CTRL_CMD_HELLO) &&
858 !xprt_info->initialized)) {
859 pr_err("%s: xprt_info not initialized\n", __func__);
860 return -EINVAL;
861 }
862
863 if (xprt_info->remote_node_id == IPC_ROUTER_NID_LOCAL)
864 return 0;
865
866 pkt = kzalloc(sizeof(struct rr_packet), GFP_KERNEL);
867 if (!pkt) {
868 pr_err("%s: pkt alloc failed\n", __func__);
869 return -ENOMEM;
870 }
871
872 pkt_fragment_q = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
873 if (!pkt_fragment_q) {
874 pr_err("%s: pkt_fragment_q alloc failed\n", __func__);
875 kfree(pkt);
876 return -ENOMEM;
877 }
878 skb_queue_head_init(pkt_fragment_q);
879
880 pkt_size = IPC_ROUTER_HDR_SIZE + sizeof(*msg);
881 ipc_rtr_pkt = alloc_skb(pkt_size, GFP_KERNEL);
882 if (!ipc_rtr_pkt) {
883 pr_err("%s: ipc_rtr_pkt alloc failed\n", __func__);
884 kfree(pkt_fragment_q);
885 kfree(pkt);
886 return -ENOMEM;
887 }
888
889 skb_reserve(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
890 data = skb_put(ipc_rtr_pkt, sizeof(*msg));
891 memcpy(data, msg, sizeof(*msg));
892 hdr = (struct rr_header *)skb_push(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
893 if (!hdr) {
894 pr_err("%s: skb_push failed\n", __func__);
895 kfree_skb(ipc_rtr_pkt);
896 kfree(pkt_fragment_q);
897 kfree(pkt);
898 return -ENOMEM;
899 }
900
901 hdr->version = IPC_ROUTER_VERSION;
902 hdr->type = msg->cmd;
903 hdr->src_node_id = IPC_ROUTER_NID_LOCAL;
904 hdr->src_port_id = IPC_ROUTER_ADDRESS;
905 hdr->confirm_rx = 0;
906 hdr->size = sizeof(*msg);
907 hdr->dst_node_id = xprt_info->remote_node_id;
908 hdr->dst_port_id = IPC_ROUTER_ADDRESS;
909 skb_queue_tail(pkt_fragment_q, ipc_rtr_pkt);
910 pkt->pkt_fragment_q = pkt_fragment_q;
911 pkt->length = pkt_size;
912
913 mutex_lock(&xprt_info->tx_lock);
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700914 ret = xprt_info->xprt->write(pkt, pkt_size, xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700915 mutex_unlock(&xprt_info->tx_lock);
916
917 release_pkt(pkt);
918 return ret;
919}
920
Karthikeyan Ramasubramaniana2b7fdb2012-10-23 13:12:44 -0600921static int msm_ipc_router_send_server_list(uint32_t node_id,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700922 struct msm_ipc_router_xprt_info *xprt_info)
923{
924 union rr_control_msg ctl;
925 struct msm_ipc_server *server;
926 struct msm_ipc_server_port *server_port;
927 int i;
928
929 if (!xprt_info || !xprt_info->initialized) {
930 pr_err("%s: Xprt info not initialized\n", __func__);
931 return -EINVAL;
932 }
933
934 ctl.cmd = IPC_ROUTER_CTRL_CMD_NEW_SERVER;
935
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700936 for (i = 0; i < SRV_HASH_SIZE; i++) {
937 list_for_each_entry(server, &server_list[i], list) {
938 ctl.srv.service = server->name.service;
939 ctl.srv.instance = server->name.instance;
940 list_for_each_entry(server_port,
941 &server->server_port_list, list) {
Karthikeyan Ramasubramaniana2b7fdb2012-10-23 13:12:44 -0600942 if (server_port->server_addr.node_id !=
943 node_id)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700944 continue;
945
946 ctl.srv.node_id =
947 server_port->server_addr.node_id;
948 ctl.srv.port_id =
949 server_port->server_addr.port_id;
950 msm_ipc_router_send_control_msg(xprt_info,
951 &ctl);
952 }
953 }
954 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700955
956 return 0;
957}
958
959#if defined(DEBUG)
960static char *type_to_str(int i)
961{
962 switch (i) {
963 case IPC_ROUTER_CTRL_CMD_DATA:
964 return "data ";
965 case IPC_ROUTER_CTRL_CMD_HELLO:
966 return "hello ";
967 case IPC_ROUTER_CTRL_CMD_BYE:
968 return "bye ";
969 case IPC_ROUTER_CTRL_CMD_NEW_SERVER:
970 return "new_srvr";
971 case IPC_ROUTER_CTRL_CMD_REMOVE_SERVER:
972 return "rmv_srvr";
973 case IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT:
974 return "rmv_clnt";
975 case IPC_ROUTER_CTRL_CMD_RESUME_TX:
976 return "resum_tx";
977 case IPC_ROUTER_CTRL_CMD_EXIT:
978 return "cmd_exit";
979 default:
980 return "invalid";
981 }
982}
983#endif
984
985static int broadcast_ctl_msg_locally(union rr_control_msg *msg)
986{
987 struct rr_packet *pkt;
988 struct sk_buff *ipc_rtr_pkt;
989 struct rr_header *hdr;
990 int pkt_size;
991 void *data;
992 struct sk_buff_head *pkt_fragment_q;
993 int ret;
994
995 pkt = kzalloc(sizeof(struct rr_packet), GFP_KERNEL);
996 if (!pkt) {
997 pr_err("%s: pkt alloc failed\n", __func__);
998 return -ENOMEM;
999 }
1000
1001 pkt_fragment_q = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
1002 if (!pkt_fragment_q) {
1003 pr_err("%s: pkt_fragment_q alloc failed\n", __func__);
1004 kfree(pkt);
1005 return -ENOMEM;
1006 }
1007 skb_queue_head_init(pkt_fragment_q);
1008
1009 pkt_size = IPC_ROUTER_HDR_SIZE + sizeof(*msg);
1010 ipc_rtr_pkt = alloc_skb(pkt_size, GFP_KERNEL);
1011 if (!ipc_rtr_pkt) {
1012 pr_err("%s: ipc_rtr_pkt alloc failed\n", __func__);
1013 kfree(pkt_fragment_q);
1014 kfree(pkt);
1015 return -ENOMEM;
1016 }
1017
1018 skb_reserve(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
1019 data = skb_put(ipc_rtr_pkt, sizeof(*msg));
1020 memcpy(data, msg, sizeof(*msg));
1021 hdr = (struct rr_header *)skb_push(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
1022 if (!hdr) {
1023 pr_err("%s: skb_push failed\n", __func__);
1024 kfree_skb(ipc_rtr_pkt);
1025 kfree(pkt_fragment_q);
1026 kfree(pkt);
1027 return -ENOMEM;
1028 }
1029 hdr->version = IPC_ROUTER_VERSION;
1030 hdr->type = msg->cmd;
1031 hdr->src_node_id = IPC_ROUTER_NID_LOCAL;
1032 hdr->src_port_id = IPC_ROUTER_ADDRESS;
1033 hdr->confirm_rx = 0;
1034 hdr->size = sizeof(*msg);
1035 hdr->dst_node_id = IPC_ROUTER_NID_LOCAL;
1036 hdr->dst_port_id = IPC_ROUTER_ADDRESS;
1037 skb_queue_tail(pkt_fragment_q, ipc_rtr_pkt);
1038 pkt->pkt_fragment_q = pkt_fragment_q;
1039 pkt->length = pkt_size;
1040
1041 ret = post_control_ports(pkt);
1042 release_pkt(pkt);
1043 return ret;
1044}
1045
1046static int broadcast_ctl_msg(union rr_control_msg *ctl)
1047{
1048 struct msm_ipc_router_xprt_info *xprt_info;
1049
1050 mutex_lock(&xprt_info_list_lock);
1051 list_for_each_entry(xprt_info, &xprt_info_list, list) {
1052 msm_ipc_router_send_control_msg(xprt_info, ctl);
1053 }
1054 mutex_unlock(&xprt_info_list_lock);
1055
1056 return 0;
1057}
1058
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001059static int relay_ctl_msg(struct msm_ipc_router_xprt_info *xprt_info,
1060 union rr_control_msg *ctl)
1061{
1062 struct msm_ipc_router_xprt_info *fwd_xprt_info;
1063
1064 if (!xprt_info || !ctl)
1065 return -EINVAL;
1066
1067 mutex_lock(&xprt_info_list_lock);
1068 list_for_each_entry(fwd_xprt_info, &xprt_info_list, list) {
1069 if (xprt_info->xprt->link_id != fwd_xprt_info->xprt->link_id)
1070 msm_ipc_router_send_control_msg(fwd_xprt_info, ctl);
1071 }
1072 mutex_unlock(&xprt_info_list_lock);
1073
1074 return 0;
1075}
1076
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001077static int relay_msg(struct msm_ipc_router_xprt_info *xprt_info,
1078 struct rr_packet *pkt)
1079{
1080 struct msm_ipc_router_xprt_info *fwd_xprt_info;
1081
1082 if (!xprt_info || !pkt)
1083 return -EINVAL;
1084
1085 mutex_lock(&xprt_info_list_lock);
1086 list_for_each_entry(fwd_xprt_info, &xprt_info_list, list) {
1087 mutex_lock(&fwd_xprt_info->tx_lock);
1088 if (xprt_info->xprt->link_id != fwd_xprt_info->xprt->link_id)
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -07001089 fwd_xprt_info->xprt->write(pkt, pkt->length,
1090 fwd_xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001091 mutex_unlock(&fwd_xprt_info->tx_lock);
1092 }
1093 mutex_unlock(&xprt_info_list_lock);
1094 return 0;
1095}
1096
1097static int forward_msg(struct msm_ipc_router_xprt_info *xprt_info,
1098 struct rr_packet *pkt)
1099{
1100 uint32_t dst_node_id;
1101 struct sk_buff *head_pkt;
1102 struct rr_header *hdr;
1103 struct msm_ipc_router_xprt_info *fwd_xprt_info;
1104 struct msm_ipc_routing_table_entry *rt_entry;
1105
1106 if (!xprt_info || !pkt)
1107 return -EINVAL;
1108
1109 head_pkt = skb_peek(pkt->pkt_fragment_q);
1110 if (!head_pkt)
1111 return -EINVAL;
1112
1113 hdr = (struct rr_header *)head_pkt->data;
1114 dst_node_id = hdr->dst_node_id;
1115 mutex_lock(&routing_table_lock);
1116 rt_entry = lookup_routing_table(dst_node_id);
1117 if (!(rt_entry) || !(rt_entry->xprt_info)) {
1118 mutex_unlock(&routing_table_lock);
1119 pr_err("%s: Routing table not initialized\n", __func__);
1120 return -ENODEV;
1121 }
1122
1123 mutex_lock(&rt_entry->lock);
1124 fwd_xprt_info = rt_entry->xprt_info;
1125 mutex_lock(&fwd_xprt_info->tx_lock);
1126 if (xprt_info->remote_node_id == fwd_xprt_info->remote_node_id) {
1127 mutex_unlock(&fwd_xprt_info->tx_lock);
1128 mutex_unlock(&rt_entry->lock);
1129 mutex_unlock(&routing_table_lock);
1130 pr_err("%s: Discarding Command to route back\n", __func__);
1131 return -EINVAL;
1132 }
1133
1134 if (xprt_info->xprt->link_id == fwd_xprt_info->xprt->link_id) {
1135 mutex_unlock(&fwd_xprt_info->tx_lock);
1136 mutex_unlock(&rt_entry->lock);
1137 mutex_unlock(&routing_table_lock);
1138 pr_err("%s: DST in the same cluster\n", __func__);
1139 return 0;
1140 }
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -07001141 fwd_xprt_info->xprt->write(pkt, pkt->length, fwd_xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001142 mutex_unlock(&fwd_xprt_info->tx_lock);
1143 mutex_unlock(&rt_entry->lock);
1144 mutex_unlock(&routing_table_lock);
1145
1146 return 0;
1147}
1148
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001149static void reset_remote_port_info(uint32_t node_id, uint32_t port_id)
1150{
1151 struct msm_ipc_router_remote_port *rport_ptr;
1152
1153 rport_ptr = msm_ipc_router_lookup_remote_port(node_id, port_id);
1154 if (!rport_ptr) {
1155 pr_err("%s: No such remote port %08x:%08x\n",
1156 __func__, node_id, port_id);
1157 return;
1158 }
1159 mutex_lock(&rport_ptr->quota_lock);
1160 rport_ptr->restart_state = RESTART_PEND;
1161 wake_up(&rport_ptr->quota_wait);
1162 mutex_unlock(&rport_ptr->quota_lock);
1163 return;
1164}
1165
1166static void msm_ipc_cleanup_remote_server_info(
1167 struct msm_ipc_router_xprt_info *xprt_info)
1168{
1169 struct msm_ipc_server *svr, *tmp_svr;
1170 struct msm_ipc_server_port *svr_port, *tmp_svr_port;
1171 int i;
1172 union rr_control_msg ctl;
1173
1174 if (!xprt_info) {
1175 pr_err("%s: Invalid xprt_info\n", __func__);
1176 return;
1177 }
1178
1179 ctl.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_SERVER;
1180 mutex_lock(&server_list_lock);
1181 for (i = 0; i < SRV_HASH_SIZE; i++) {
1182 list_for_each_entry_safe(svr, tmp_svr, &server_list[i], list) {
1183 ctl.srv.service = svr->name.service;
1184 ctl.srv.instance = svr->name.instance;
1185 list_for_each_entry_safe(svr_port, tmp_svr_port,
1186 &svr->server_port_list, list) {
1187 if (svr_port->xprt_info != xprt_info)
1188 continue;
1189 D("Remove server %08x:%08x - %08x:%08x",
1190 ctl.srv.service, ctl.srv.instance,
1191 svr_port->server_addr.node_id,
1192 svr_port->server_addr.port_id);
1193 reset_remote_port_info(
1194 svr_port->server_addr.node_id,
1195 svr_port->server_addr.port_id);
1196 ctl.srv.node_id = svr_port->server_addr.node_id;
1197 ctl.srv.port_id = svr_port->server_addr.port_id;
1198 relay_ctl_msg(xprt_info, &ctl);
1199 broadcast_ctl_msg_locally(&ctl);
Karthikeyan Ramasubramanianefc493b2012-07-12 10:25:49 -06001200 platform_device_unregister(&svr_port->pdev);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001201 list_del(&svr_port->list);
1202 kfree(svr_port);
1203 }
1204 if (list_empty(&svr->server_port_list)) {
1205 list_del(&svr->list);
1206 kfree(svr);
1207 }
1208 }
1209 }
1210 mutex_unlock(&server_list_lock);
1211}
1212
1213static void msm_ipc_cleanup_remote_client_info(
1214 struct msm_ipc_router_xprt_info *xprt_info)
1215{
1216 struct msm_ipc_routing_table_entry *rt_entry;
1217 struct msm_ipc_router_remote_port *rport_ptr;
1218 int i, j;
1219 union rr_control_msg ctl;
1220
1221 if (!xprt_info) {
1222 pr_err("%s: Invalid xprt_info\n", __func__);
1223 return;
1224 }
1225
1226 ctl.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT;
1227 mutex_lock(&routing_table_lock);
1228 for (i = 0; i < RT_HASH_SIZE; i++) {
1229 list_for_each_entry(rt_entry, &routing_table[i], list) {
1230 mutex_lock(&rt_entry->lock);
1231 if (rt_entry->xprt_info != xprt_info) {
1232 mutex_unlock(&rt_entry->lock);
1233 continue;
1234 }
1235 for (j = 0; j < RP_HASH_SIZE; j++) {
1236 list_for_each_entry(rport_ptr,
1237 &rt_entry->remote_port_list[j], list) {
1238 if (rport_ptr->restart_state ==
1239 RESTART_PEND)
1240 continue;
1241 mutex_lock(&rport_ptr->quota_lock);
1242 rport_ptr->restart_state = RESTART_PEND;
1243 wake_up(&rport_ptr->quota_wait);
1244 mutex_unlock(&rport_ptr->quota_lock);
1245 ctl.cli.node_id = rport_ptr->node_id;
1246 ctl.cli.port_id = rport_ptr->port_id;
1247 broadcast_ctl_msg_locally(&ctl);
1248 }
1249 }
1250 mutex_unlock(&rt_entry->lock);
1251 }
1252 }
1253 mutex_unlock(&routing_table_lock);
1254}
1255
1256static void msm_ipc_cleanup_remote_port_info(uint32_t node_id)
1257{
1258 struct msm_ipc_routing_table_entry *rt_entry, *tmp_rt_entry;
1259 struct msm_ipc_router_remote_port *rport_ptr, *tmp_rport_ptr;
1260 int i, j;
1261
1262 mutex_lock(&routing_table_lock);
1263 for (i = 0; i < RT_HASH_SIZE; i++) {
1264 list_for_each_entry_safe(rt_entry, tmp_rt_entry,
1265 &routing_table[i], list) {
1266 mutex_lock(&rt_entry->lock);
1267 if (rt_entry->neighbor_node_id != node_id) {
1268 mutex_unlock(&rt_entry->lock);
1269 continue;
1270 }
1271 for (j = 0; j < RP_HASH_SIZE; j++) {
1272 list_for_each_entry_safe(rport_ptr,
1273 tmp_rport_ptr,
1274 &rt_entry->remote_port_list[j], list) {
1275 list_del(&rport_ptr->list);
1276 kfree(rport_ptr);
1277 }
1278 }
1279 mutex_unlock(&rt_entry->lock);
1280 }
1281 }
1282 mutex_unlock(&routing_table_lock);
1283}
1284
1285static void msm_ipc_cleanup_routing_table(
1286 struct msm_ipc_router_xprt_info *xprt_info)
1287{
1288 int i;
1289 struct msm_ipc_routing_table_entry *rt_entry;
1290
1291 if (!xprt_info) {
1292 pr_err("%s: Invalid xprt_info\n", __func__);
1293 return;
1294 }
1295
1296 mutex_lock(&routing_table_lock);
1297 for (i = 0; i < RT_HASH_SIZE; i++) {
1298 list_for_each_entry(rt_entry, &routing_table[i], list) {
1299 mutex_lock(&rt_entry->lock);
1300 if (rt_entry->xprt_info == xprt_info)
1301 rt_entry->xprt_info = NULL;
1302 mutex_unlock(&rt_entry->lock);
1303 }
1304 }
1305 mutex_unlock(&routing_table_lock);
1306}
1307
1308static void modem_reset_cleanup(struct msm_ipc_router_xprt_info *xprt_info)
1309{
1310
1311 if (!xprt_info) {
1312 pr_err("%s: Invalid xprt_info\n", __func__);
1313 return;
1314 }
1315
1316 msm_ipc_cleanup_remote_server_info(xprt_info);
1317 msm_ipc_cleanup_remote_client_info(xprt_info);
1318 msm_ipc_cleanup_routing_table(xprt_info);
1319}
1320
Karthikeyan Ramasubramanian5b502d3642012-09-23 22:23:36 -06001321/**
1322 * sync_sec_rule() - Synchrnoize the security rule into the server structure
1323 * @server: Server structure where the rule has to be synchronized.
1324 * @rule: Security tule to be synchronized.
1325 *
1326 * This function is used to update the server structure with the security
1327 * rule configured for the <service:instance> corresponding to that server.
1328 */
1329static void sync_sec_rule(struct msm_ipc_server *server, void *rule)
1330{
1331 struct msm_ipc_server_port *server_port;
1332 struct msm_ipc_router_remote_port *rport_ptr = NULL;
1333
1334 list_for_each_entry(server_port, &server->server_port_list, list) {
1335 rport_ptr = msm_ipc_router_lookup_remote_port(
1336 server_port->server_addr.node_id,
1337 server_port->server_addr.port_id);
1338 if (!rport_ptr)
1339 continue;
1340 rport_ptr->sec_rule = rule;
1341 }
1342 server->synced_sec_rule = 1;
1343}
1344
1345/**
1346 * msm_ipc_sync_sec_rule() - Sync the security rule to the service
1347 * @service: Service for which the rule has to be synchronized.
1348 * @instance: Instance for which the rule has to be synchronized.
1349 * @rule: Security rule to be synchronized.
1350 *
1351 * This function is used to syncrhonize the security rule with the server
1352 * hash table, if the user-space script configures the rule after the service
1353 * has come up. This function is used to synchronize the security rule to a
1354 * specific service and optionally a specific instance.
1355 */
1356void msm_ipc_sync_sec_rule(uint32_t service, uint32_t instance, void *rule)
1357{
1358 int key = (service & (SRV_HASH_SIZE - 1));
1359 struct msm_ipc_server *server;
1360
1361 mutex_lock(&server_list_lock);
1362 list_for_each_entry(server, &server_list[key], list) {
1363 if (server->name.service != service)
1364 continue;
1365
1366 if (server->name.instance != instance &&
1367 instance != ALL_INSTANCE)
1368 continue;
1369
1370 /*
1371 * If the rule applies to all instances and if the specific
1372 * instance of a service has a rule synchronized already,
1373 * do not apply the rule for that specific instance.
1374 */
1375 if (instance == ALL_INSTANCE && server->synced_sec_rule)
1376 continue;
1377
1378 sync_sec_rule(server, rule);
1379 }
1380 mutex_unlock(&server_list_lock);
1381}
1382
1383/**
1384 * msm_ipc_sync_default_sec_rule() - Default security rule to all services
1385 * @rule: Security rule to be synchronized.
1386 *
1387 * This function is used to syncrhonize the security rule with the server
1388 * hash table, if the user-space script configures the rule after the service
1389 * has come up. This function is used to synchronize the security rule that
1390 * applies to all services, if the concerned service do not have any rule
1391 * defined.
1392 */
1393void msm_ipc_sync_default_sec_rule(void *rule)
1394{
1395 int key;
1396 struct msm_ipc_server *server;
1397
1398 mutex_lock(&server_list_lock);
1399 for (key = 0; key < SRV_HASH_SIZE; key++) {
1400 list_for_each_entry(server, &server_list[key], list) {
1401 if (server->synced_sec_rule)
1402 continue;
1403
1404 sync_sec_rule(server, rule);
1405 }
1406 }
1407 mutex_unlock(&server_list_lock);
1408}
1409
Karthikeyan Ramasubramaniana2b7fdb2012-10-23 13:12:44 -06001410static int process_hello_msg(struct msm_ipc_router_xprt_info *xprt_info,
1411 struct rr_header *hdr)
1412{
1413 int i, rc = 0;
1414 union rr_control_msg ctl;
1415 struct msm_ipc_routing_table_entry *rt_entry;
1416
1417 if (!hdr)
1418 return -EINVAL;
1419
1420 RR("o HELLO NID %d\n", hdr->src_node_id);
1421
1422 xprt_info->remote_node_id = hdr->src_node_id;
1423 /*
1424 * Find the entry from Routing Table corresponding to Node ID.
1425 * Under SSR, an entry will be found. When the system boots up
1426 * for the 1st time, an entry will not be found and hence allocate
1427 * an entry. Update the entry with the Node ID that it corresponds
1428 * to and the XPRT through which it can be reached.
1429 */
1430 mutex_lock(&routing_table_lock);
1431 rt_entry = lookup_routing_table(hdr->src_node_id);
1432 if (!rt_entry) {
1433 rt_entry = alloc_routing_table_entry(hdr->src_node_id);
1434 if (!rt_entry) {
1435 mutex_unlock(&routing_table_lock);
1436 pr_err("%s: rt_entry allocation failed\n", __func__);
1437 return -ENOMEM;
1438 }
1439 add_routing_table_entry(rt_entry);
1440 }
1441 mutex_lock(&rt_entry->lock);
1442 rt_entry->neighbor_node_id = xprt_info->remote_node_id;
1443 rt_entry->xprt_info = xprt_info;
1444 mutex_unlock(&rt_entry->lock);
1445 mutex_unlock(&routing_table_lock);
1446
1447 /* Cleanup any remote ports, if the node is coming out of reset */
1448 msm_ipc_cleanup_remote_port_info(xprt_info->remote_node_id);
1449
1450 /* Send a reply HELLO message */
1451 memset(&ctl, 0, sizeof(ctl));
1452 ctl.cmd = IPC_ROUTER_CTRL_CMD_HELLO;
1453 rc = msm_ipc_router_send_control_msg(xprt_info, &ctl);
1454 if (rc < 0) {
1455 pr_err("%s: Error sending reply HELLO message\n", __func__);
1456 return rc;
1457 }
1458 xprt_info->initialized = 1;
1459
1460 /*
1461 * Send list of servers from the local node and from nodes
1462 * outside the mesh network in which this XPRT is part of.
1463 */
Karthikeyan Ramasubramanian05066a82012-10-31 15:12:08 -06001464 mutex_lock(&server_list_lock);
Karthikeyan Ramasubramaniana2b7fdb2012-10-23 13:12:44 -06001465 mutex_lock(&routing_table_lock);
1466 for (i = 0; i < RT_HASH_SIZE; i++) {
1467 list_for_each_entry(rt_entry, &routing_table[i], list) {
1468 if ((rt_entry->node_id != IPC_ROUTER_NID_LOCAL) &&
Karthikeyan Ramasubramanianc4c0aaa2013-01-30 14:17:57 -07001469 (!rt_entry->xprt_info ||
1470 (rt_entry->xprt_info->xprt->link_id ==
1471 xprt_info->xprt->link_id)))
Karthikeyan Ramasubramaniana2b7fdb2012-10-23 13:12:44 -06001472 continue;
1473 rc = msm_ipc_router_send_server_list(rt_entry->node_id,
1474 xprt_info);
1475 if (rc < 0) {
1476 mutex_unlock(&routing_table_lock);
Karthikeyan Ramasubramanian05066a82012-10-31 15:12:08 -06001477 mutex_unlock(&server_list_lock);
Karthikeyan Ramasubramaniana2b7fdb2012-10-23 13:12:44 -06001478 return rc;
1479 }
1480 }
1481 }
1482 mutex_unlock(&routing_table_lock);
Karthikeyan Ramasubramanian05066a82012-10-31 15:12:08 -06001483 mutex_unlock(&server_list_lock);
Karthikeyan Ramasubramaniana2b7fdb2012-10-23 13:12:44 -06001484 RR("HELLO message processed\n");
1485 return rc;
1486}
1487
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001488static int process_control_msg(struct msm_ipc_router_xprt_info *xprt_info,
1489 struct rr_packet *pkt)
1490{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001491 union rr_control_msg *msg;
1492 struct msm_ipc_router_remote_port *rport_ptr;
1493 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001494 struct sk_buff *temp_ptr;
1495 struct rr_header *hdr;
1496 struct msm_ipc_server *server;
1497 struct msm_ipc_routing_table_entry *rt_entry;
1498
1499 if (pkt->length != (IPC_ROUTER_HDR_SIZE + sizeof(*msg))) {
1500 pr_err("%s: r2r msg size %d != %d\n", __func__, pkt->length,
1501 (IPC_ROUTER_HDR_SIZE + sizeof(*msg)));
1502 return -EINVAL;
1503 }
1504
1505 temp_ptr = skb_peek(pkt->pkt_fragment_q);
Karthikeyan Ramasubramanian9024dd82011-12-19 18:44:19 -07001506 if (!temp_ptr) {
1507 pr_err("%s: pkt_fragment_q is empty\n", __func__);
1508 return -EINVAL;
1509 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001510 hdr = (struct rr_header *)temp_ptr->data;
Karthikeyan Ramasubramanian9024dd82011-12-19 18:44:19 -07001511 if (!hdr) {
1512 pr_err("%s: No data inside the skb\n", __func__);
1513 return -EINVAL;
1514 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001515 msg = (union rr_control_msg *)((char *)hdr + IPC_ROUTER_HDR_SIZE);
1516
1517 switch (msg->cmd) {
1518 case IPC_ROUTER_CTRL_CMD_HELLO:
Karthikeyan Ramasubramaniana2b7fdb2012-10-23 13:12:44 -06001519 rc = process_hello_msg(xprt_info, hdr);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001520 break;
Karthikeyan Ramasubramaniana2b7fdb2012-10-23 13:12:44 -06001521
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001522 case IPC_ROUTER_CTRL_CMD_RESUME_TX:
1523 RR("o RESUME_TX id=%d:%08x\n",
1524 msg->cli.node_id, msg->cli.port_id);
1525
1526 rport_ptr = msm_ipc_router_lookup_remote_port(msg->cli.node_id,
1527 msg->cli.port_id);
1528 if (!rport_ptr) {
1529 pr_err("%s: Unable to resume client\n", __func__);
1530 break;
1531 }
1532 mutex_lock(&rport_ptr->quota_lock);
1533 rport_ptr->tx_quota_cnt = 0;
1534 mutex_unlock(&rport_ptr->quota_lock);
1535 wake_up(&rport_ptr->quota_wait);
1536 break;
1537
1538 case IPC_ROUTER_CTRL_CMD_NEW_SERVER:
1539 if (msg->srv.instance == 0) {
1540 pr_err(
1541 "rpcrouter: Server create rejected, version = 0, "
1542 "service = %08x\n", msg->srv.service);
1543 break;
1544 }
1545
1546 RR("o NEW_SERVER id=%d:%08x service=%08x:%08x\n",
1547 msg->srv.node_id, msg->srv.port_id,
1548 msg->srv.service, msg->srv.instance);
1549
1550 mutex_lock(&routing_table_lock);
1551 rt_entry = lookup_routing_table(msg->srv.node_id);
1552 if (!rt_entry) {
1553 rt_entry = alloc_routing_table_entry(msg->srv.node_id);
1554 if (!rt_entry) {
1555 mutex_unlock(&routing_table_lock);
1556 pr_err("%s: rt_entry allocation failed\n",
1557 __func__);
1558 return -ENOMEM;
1559 }
1560 mutex_lock(&rt_entry->lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001561 rt_entry->neighbor_node_id = xprt_info->remote_node_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001562 rt_entry->xprt_info = xprt_info;
1563 mutex_unlock(&rt_entry->lock);
1564 add_routing_table_entry(rt_entry);
1565 }
1566 mutex_unlock(&routing_table_lock);
1567
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -06001568 mutex_lock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001569 server = msm_ipc_router_lookup_server(msg->srv.service,
1570 msg->srv.instance,
1571 msg->srv.node_id,
1572 msg->srv.port_id);
1573 if (!server) {
1574 server = msm_ipc_router_create_server(
1575 msg->srv.service, msg->srv.instance,
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001576 msg->srv.node_id, msg->srv.port_id, xprt_info);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001577 if (!server) {
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -06001578 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001579 pr_err("%s: Server Create failed\n", __func__);
1580 return -ENOMEM;
1581 }
1582
1583 if (!msm_ipc_router_lookup_remote_port(
1584 msg->srv.node_id, msg->srv.port_id)) {
1585 rport_ptr = msm_ipc_router_create_remote_port(
1586 msg->srv.node_id, msg->srv.port_id);
1587 if (!rport_ptr)
1588 pr_err("%s: Remote port create "
1589 "failed\n", __func__);
Karthikeyan Ramasubramanian5b502d3642012-09-23 22:23:36 -06001590 rport_ptr->sec_rule =
1591 msm_ipc_get_security_rule(
1592 msg->srv.service, msg->srv.instance);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001593 }
1594 wake_up(&newserver_wait);
1595 }
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -06001596 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001597
1598 relay_msg(xprt_info, pkt);
1599 post_control_ports(pkt);
1600 break;
1601 case IPC_ROUTER_CTRL_CMD_REMOVE_SERVER:
1602 RR("o REMOVE_SERVER service=%08x:%d\n",
1603 msg->srv.service, msg->srv.instance);
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -06001604 mutex_lock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001605 server = msm_ipc_router_lookup_server(msg->srv.service,
1606 msg->srv.instance,
1607 msg->srv.node_id,
1608 msg->srv.port_id);
1609 if (server) {
1610 msm_ipc_router_destroy_server(server,
1611 msg->srv.node_id,
1612 msg->srv.port_id);
1613 relay_msg(xprt_info, pkt);
1614 post_control_ports(pkt);
1615 }
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -06001616 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001617 break;
1618 case IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT:
1619 RR("o REMOVE_CLIENT id=%d:%08x\n",
1620 msg->cli.node_id, msg->cli.port_id);
1621 rport_ptr = msm_ipc_router_lookup_remote_port(msg->cli.node_id,
1622 msg->cli.port_id);
1623 if (rport_ptr)
1624 msm_ipc_router_destroy_remote_port(rport_ptr);
1625
1626 relay_msg(xprt_info, pkt);
1627 post_control_ports(pkt);
1628 break;
1629 case IPC_ROUTER_CTRL_CMD_PING:
1630 /* No action needed for ping messages received */
1631 RR("o PING\n");
1632 break;
1633 default:
1634 RR("o UNKNOWN(%08x)\n", msg->cmd);
1635 rc = -ENOSYS;
1636 }
1637
1638 return rc;
1639}
1640
1641static void do_read_data(struct work_struct *work)
1642{
1643 struct rr_header *hdr;
1644 struct rr_packet *pkt = NULL;
1645 struct msm_ipc_port *port_ptr;
1646 struct sk_buff *head_skb;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001647 struct msm_ipc_router_remote_port *rport_ptr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001648 uint32_t resume_tx, resume_tx_node_id, resume_tx_port_id;
1649
1650 struct msm_ipc_router_xprt_info *xprt_info =
1651 container_of(work,
1652 struct msm_ipc_router_xprt_info,
1653 read_data);
1654
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001655 while ((pkt = rr_read(xprt_info)) != NULL) {
1656 if (pkt->length < IPC_ROUTER_HDR_SIZE ||
1657 pkt->length > MAX_IPC_PKT_SIZE) {
1658 pr_err("%s: Invalid pkt length %d\n",
1659 __func__, pkt->length);
1660 goto fail_data;
1661 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001662
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001663 head_skb = skb_peek(pkt->pkt_fragment_q);
1664 if (!head_skb) {
1665 pr_err("%s: head_skb is invalid\n", __func__);
1666 goto fail_data;
1667 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001668
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001669 hdr = (struct rr_header *)(head_skb->data);
Karthikeyan Ramasubramanian2bfe8ec2013-03-22 10:47:20 -06001670 RAW("ver=%d type=%d src=%d:%08x crx=%d siz=%d dst=%d:%08x\n",
1671 hdr->version, hdr->type, hdr->src_node_id,
1672 hdr->src_port_id, hdr->confirm_rx, hdr->size,
1673 hdr->dst_node_id, hdr->dst_port_id);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001674
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001675 if (hdr->version != IPC_ROUTER_VERSION) {
1676 pr_err("version %d != %d\n",
1677 hdr->version, IPC_ROUTER_VERSION);
1678 goto fail_data;
1679 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001680
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001681 if ((hdr->dst_node_id != IPC_ROUTER_NID_LOCAL) &&
1682 ((hdr->type == IPC_ROUTER_CTRL_CMD_RESUME_TX) ||
1683 (hdr->type == IPC_ROUTER_CTRL_CMD_DATA))) {
1684 forward_msg(xprt_info, pkt);
1685 release_pkt(pkt);
1686 continue;
1687 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001688
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001689 if ((hdr->dst_port_id == IPC_ROUTER_ADDRESS) ||
1690 (hdr->type == IPC_ROUTER_CTRL_CMD_HELLO)) {
1691 process_control_msg(xprt_info, pkt);
1692 release_pkt(pkt);
1693 continue;
1694 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001695#if defined(CONFIG_MSM_SMD_LOGGING)
1696#if defined(DEBUG)
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001697 if (msm_ipc_router_debug_mask & SMEM_LOG) {
1698 smem_log_event((SMEM_LOG_PROC_ID_APPS |
1699 SMEM_LOG_RPC_ROUTER_EVENT_BASE |
1700 IPC_ROUTER_LOG_EVENT_RX),
1701 (hdr->src_node_id << 24) |
1702 (hdr->src_port_id & 0xffffff),
1703 (hdr->dst_node_id << 24) |
1704 (hdr->dst_port_id & 0xffffff),
1705 (hdr->type << 24) | (hdr->confirm_rx << 16) |
1706 (hdr->size & 0xffff));
1707 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001708#endif
1709#endif
1710
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001711 resume_tx = hdr->confirm_rx;
1712 resume_tx_node_id = hdr->dst_node_id;
1713 resume_tx_port_id = hdr->dst_port_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001714
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001715 rport_ptr = msm_ipc_router_lookup_remote_port(hdr->src_node_id,
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06001716 hdr->src_port_id);
1717
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001718 mutex_lock(&local_ports_lock);
1719 port_ptr = msm_ipc_router_lookup_local_port(hdr->dst_port_id);
1720 if (!port_ptr) {
1721 pr_err("%s: No local port id %08x\n", __func__,
1722 hdr->dst_port_id);
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06001723 mutex_unlock(&local_ports_lock);
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001724 release_pkt(pkt);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001725 goto process_done;
1726 }
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001727
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001728 if (!rport_ptr) {
1729 rport_ptr = msm_ipc_router_create_remote_port(
1730 hdr->src_node_id,
1731 hdr->src_port_id);
1732 if (!rport_ptr) {
1733 pr_err("%s: Rmt Prt %08x:%08x create failed\n",
1734 __func__, hdr->src_node_id,
1735 hdr->src_port_id);
1736 mutex_unlock(&local_ports_lock);
1737 goto process_done;
1738 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001739 }
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001740
Karthikeyan Ramasubramanianefc493b2012-07-12 10:25:49 -06001741 mutex_lock(&port_ptr->port_rx_q_lock);
1742 wake_lock(&port_ptr->port_rx_wake_lock);
1743 list_add_tail(&pkt->list, &port_ptr->port_rx_q);
1744 wake_up(&port_ptr->port_rx_wait_q);
1745 if (port_ptr->notify)
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001746 port_ptr->notify(MSM_IPC_ROUTER_READ_CB,
Karthikeyan Ramasubramanianefc493b2012-07-12 10:25:49 -06001747 port_ptr->priv);
1748 mutex_unlock(&port_ptr->port_rx_q_lock);
1749 mutex_unlock(&local_ports_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001750
1751process_done:
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001752 if (resume_tx) {
1753 union rr_control_msg msg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001754
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001755 msg.cmd = IPC_ROUTER_CTRL_CMD_RESUME_TX;
1756 msg.cli.node_id = resume_tx_node_id;
1757 msg.cli.port_id = resume_tx_port_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001758
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001759 RR("x RESUME_TX id=%d:%08x\n",
1760 msg.cli.node_id, msg.cli.port_id);
1761 msm_ipc_router_send_control_msg(xprt_info, &msg);
1762 }
1763
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001764 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001765 return;
1766
1767fail_data:
1768 release_pkt(pkt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001769 pr_err("ipc_router has died\n");
1770}
1771
1772int msm_ipc_router_register_server(struct msm_ipc_port *port_ptr,
1773 struct msm_ipc_addr *name)
1774{
1775 struct msm_ipc_server *server;
1776 unsigned long flags;
1777 union rr_control_msg ctl;
1778
1779 if (!port_ptr || !name)
1780 return -EINVAL;
1781
1782 if (name->addrtype != MSM_IPC_ADDR_NAME)
1783 return -EINVAL;
1784
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -06001785 mutex_lock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001786 server = msm_ipc_router_lookup_server(name->addr.port_name.service,
1787 name->addr.port_name.instance,
1788 IPC_ROUTER_NID_LOCAL,
1789 port_ptr->this_port.port_id);
1790 if (server) {
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -06001791 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001792 pr_err("%s: Server already present\n", __func__);
1793 return -EINVAL;
1794 }
1795
1796 server = msm_ipc_router_create_server(name->addr.port_name.service,
1797 name->addr.port_name.instance,
1798 IPC_ROUTER_NID_LOCAL,
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001799 port_ptr->this_port.port_id,
1800 NULL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001801 if (!server) {
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -06001802 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001803 pr_err("%s: Server Creation failed\n", __func__);
1804 return -EINVAL;
1805 }
1806
1807 ctl.cmd = IPC_ROUTER_CTRL_CMD_NEW_SERVER;
1808 ctl.srv.service = server->name.service;
1809 ctl.srv.instance = server->name.instance;
1810 ctl.srv.node_id = IPC_ROUTER_NID_LOCAL;
1811 ctl.srv.port_id = port_ptr->this_port.port_id;
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -06001812 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001813 broadcast_ctl_msg(&ctl);
1814 spin_lock_irqsave(&port_ptr->port_lock, flags);
1815 port_ptr->type = SERVER_PORT;
1816 port_ptr->port_name.service = server->name.service;
1817 port_ptr->port_name.instance = server->name.instance;
1818 spin_unlock_irqrestore(&port_ptr->port_lock, flags);
1819 return 0;
1820}
1821
1822int msm_ipc_router_unregister_server(struct msm_ipc_port *port_ptr)
1823{
1824 struct msm_ipc_server *server;
1825 unsigned long flags;
1826 union rr_control_msg ctl;
1827
1828 if (!port_ptr)
1829 return -EINVAL;
1830
1831 if (port_ptr->type != SERVER_PORT) {
1832 pr_err("%s: Trying to unregister a non-server port\n",
1833 __func__);
1834 return -EINVAL;
1835 }
1836
1837 if (port_ptr->this_port.node_id != IPC_ROUTER_NID_LOCAL) {
1838 pr_err("%s: Trying to unregister a remote server locally\n",
1839 __func__);
1840 return -EINVAL;
1841 }
1842
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -06001843 mutex_lock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001844 server = msm_ipc_router_lookup_server(port_ptr->port_name.service,
1845 port_ptr->port_name.instance,
1846 port_ptr->this_port.node_id,
1847 port_ptr->this_port.port_id);
1848 if (!server) {
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -06001849 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001850 pr_err("%s: Server lookup failed\n", __func__);
1851 return -ENODEV;
1852 }
1853
1854 ctl.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_SERVER;
1855 ctl.srv.service = server->name.service;
1856 ctl.srv.instance = server->name.instance;
1857 ctl.srv.node_id = IPC_ROUTER_NID_LOCAL;
1858 ctl.srv.port_id = port_ptr->this_port.port_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001859 msm_ipc_router_destroy_server(server, port_ptr->this_port.node_id,
1860 port_ptr->this_port.port_id);
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -06001861 mutex_unlock(&server_list_lock);
1862 broadcast_ctl_msg(&ctl);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001863 spin_lock_irqsave(&port_ptr->port_lock, flags);
1864 port_ptr->type = CLIENT_PORT;
1865 spin_unlock_irqrestore(&port_ptr->port_lock, flags);
1866 return 0;
1867}
1868
1869static int loopback_data(struct msm_ipc_port *src,
1870 uint32_t port_id,
1871 struct sk_buff_head *data)
1872{
1873 struct sk_buff *head_skb;
1874 struct rr_header *hdr;
1875 struct msm_ipc_port *port_ptr;
1876 struct rr_packet *pkt;
Karthikeyan Ramasubramanianb0e23c52013-02-08 13:07:42 -07001877 int ret_len;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001878
1879 if (!data) {
1880 pr_err("%s: Invalid pkt pointer\n", __func__);
1881 return -EINVAL;
1882 }
1883
1884 pkt = create_pkt(data);
1885 if (!pkt) {
1886 pr_err("%s: New pkt create failed\n", __func__);
1887 return -ENOMEM;
1888 }
1889
1890 head_skb = skb_peek(pkt->pkt_fragment_q);
Karthikeyan Ramasubramanian9024dd82011-12-19 18:44:19 -07001891 if (!head_skb) {
1892 pr_err("%s: pkt_fragment_q is empty\n", __func__);
1893 return -EINVAL;
1894 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001895 hdr = (struct rr_header *)skb_push(head_skb, IPC_ROUTER_HDR_SIZE);
1896 if (!hdr) {
1897 pr_err("%s: Prepend Header failed\n", __func__);
1898 release_pkt(pkt);
1899 return -ENOMEM;
1900 }
1901 hdr->version = IPC_ROUTER_VERSION;
1902 hdr->type = IPC_ROUTER_CTRL_CMD_DATA;
1903 hdr->src_node_id = src->this_port.node_id;
1904 hdr->src_port_id = src->this_port.port_id;
1905 hdr->size = pkt->length;
1906 hdr->confirm_rx = 0;
1907 hdr->dst_node_id = IPC_ROUTER_NID_LOCAL;
1908 hdr->dst_port_id = port_id;
1909 pkt->length += IPC_ROUTER_HDR_SIZE;
1910
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06001911 mutex_lock(&local_ports_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001912 port_ptr = msm_ipc_router_lookup_local_port(port_id);
1913 if (!port_ptr) {
1914 pr_err("%s: Local port %d not present\n", __func__, port_id);
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06001915 mutex_unlock(&local_ports_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001916 release_pkt(pkt);
1917 return -ENODEV;
1918 }
1919
1920 mutex_lock(&port_ptr->port_rx_q_lock);
1921 wake_lock(&port_ptr->port_rx_wake_lock);
1922 list_add_tail(&pkt->list, &port_ptr->port_rx_q);
Karthikeyan Ramasubramanianb0e23c52013-02-08 13:07:42 -07001923 ret_len = pkt->length;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001924 wake_up(&port_ptr->port_rx_wait_q);
1925 mutex_unlock(&port_ptr->port_rx_q_lock);
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06001926 mutex_unlock(&local_ports_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001927
Karthikeyan Ramasubramanianb0e23c52013-02-08 13:07:42 -07001928 return ret_len;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001929}
1930
1931static int msm_ipc_router_write_pkt(struct msm_ipc_port *src,
1932 struct msm_ipc_router_remote_port *rport_ptr,
1933 struct rr_packet *pkt)
1934{
1935 struct sk_buff *head_skb;
1936 struct rr_header *hdr;
1937 struct msm_ipc_router_xprt_info *xprt_info;
1938 struct msm_ipc_routing_table_entry *rt_entry;
1939 int ret;
1940 DEFINE_WAIT(__wait);
1941
1942 if (!rport_ptr || !src || !pkt)
1943 return -EINVAL;
1944
1945 head_skb = skb_peek(pkt->pkt_fragment_q);
Karthikeyan Ramasubramanian9024dd82011-12-19 18:44:19 -07001946 if (!head_skb) {
1947 pr_err("%s: pkt_fragment_q is empty\n", __func__);
1948 return -EINVAL;
1949 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001950 hdr = (struct rr_header *)skb_push(head_skb, IPC_ROUTER_HDR_SIZE);
1951 if (!hdr) {
1952 pr_err("%s: Prepend Header failed\n", __func__);
1953 return -ENOMEM;
1954 }
1955 hdr->version = IPC_ROUTER_VERSION;
1956 hdr->type = IPC_ROUTER_CTRL_CMD_DATA;
1957 hdr->src_node_id = src->this_port.node_id;
1958 hdr->src_port_id = src->this_port.port_id;
1959 hdr->size = pkt->length;
1960 hdr->confirm_rx = 0;
1961 hdr->dst_node_id = rport_ptr->node_id;
1962 hdr->dst_port_id = rport_ptr->port_id;
1963 pkt->length += IPC_ROUTER_HDR_SIZE;
1964
1965 for (;;) {
1966 prepare_to_wait(&rport_ptr->quota_wait, &__wait,
1967 TASK_INTERRUPTIBLE);
1968 mutex_lock(&rport_ptr->quota_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001969 if (rport_ptr->restart_state != RESTART_NORMAL)
1970 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001971 if (rport_ptr->tx_quota_cnt <
1972 IPC_ROUTER_DEFAULT_RX_QUOTA)
1973 break;
1974 if (signal_pending(current))
1975 break;
1976 mutex_unlock(&rport_ptr->quota_lock);
1977 schedule();
1978 }
1979 finish_wait(&rport_ptr->quota_wait, &__wait);
1980
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001981 if (rport_ptr->restart_state != RESTART_NORMAL) {
1982 mutex_unlock(&rport_ptr->quota_lock);
1983 return -ENETRESET;
1984 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001985 if (signal_pending(current)) {
1986 mutex_unlock(&rport_ptr->quota_lock);
1987 return -ERESTARTSYS;
1988 }
1989 rport_ptr->tx_quota_cnt++;
1990 if (rport_ptr->tx_quota_cnt == IPC_ROUTER_DEFAULT_RX_QUOTA)
1991 hdr->confirm_rx = 1;
1992 mutex_unlock(&rport_ptr->quota_lock);
1993
1994 mutex_lock(&routing_table_lock);
1995 rt_entry = lookup_routing_table(hdr->dst_node_id);
1996 if (!rt_entry || !rt_entry->xprt_info) {
1997 mutex_unlock(&routing_table_lock);
1998 pr_err("%s: Remote node %d not up\n",
1999 __func__, hdr->dst_node_id);
2000 return -ENODEV;
2001 }
2002 mutex_lock(&rt_entry->lock);
2003 xprt_info = rt_entry->xprt_info;
2004 mutex_lock(&xprt_info->tx_lock);
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -07002005 ret = xprt_info->xprt->write(pkt, pkt->length, xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002006 mutex_unlock(&xprt_info->tx_lock);
2007 mutex_unlock(&rt_entry->lock);
2008 mutex_unlock(&routing_table_lock);
2009
2010 if (ret < 0) {
2011 pr_err("%s: Write on XPRT failed\n", __func__);
2012 return ret;
2013 }
2014
2015 RAW_HDR("[w rr_h] "
2016 "ver=%i,type=%s,src_nid=%08x,src_port_id=%08x,"
2017 "confirm_rx=%i,size=%3i,dst_pid=%08x,dst_cid=%08x\n",
2018 hdr->version, type_to_str(hdr->type),
2019 hdr->src_node_id, hdr->src_port_id,
2020 hdr->confirm_rx, hdr->size,
2021 hdr->dst_node_id, hdr->dst_port_id);
2022
2023#if defined(CONFIG_MSM_SMD_LOGGING)
2024#if defined(DEBUG)
2025 if (msm_ipc_router_debug_mask & SMEM_LOG) {
2026 smem_log_event((SMEM_LOG_PROC_ID_APPS |
2027 SMEM_LOG_RPC_ROUTER_EVENT_BASE |
2028 IPC_ROUTER_LOG_EVENT_TX),
2029 (hdr->src_node_id << 24) |
2030 (hdr->src_port_id & 0xffffff),
2031 (hdr->dst_node_id << 24) |
2032 (hdr->dst_port_id & 0xffffff),
2033 (hdr->type << 24) | (hdr->confirm_rx << 16) |
2034 (hdr->size & 0xffff));
2035 }
2036#endif
2037#endif
2038
2039 return pkt->length;
2040}
2041
2042int msm_ipc_router_send_to(struct msm_ipc_port *src,
2043 struct sk_buff_head *data,
2044 struct msm_ipc_addr *dest)
2045{
2046 uint32_t dst_node_id = 0, dst_port_id = 0;
2047 struct msm_ipc_server *server;
2048 struct msm_ipc_server_port *server_port;
2049 struct msm_ipc_router_remote_port *rport_ptr = NULL;
2050 struct rr_packet *pkt;
2051 int ret;
2052
2053 if (!src || !data || !dest) {
2054 pr_err("%s: Invalid Parameters\n", __func__);
2055 return -EINVAL;
2056 }
2057
2058 /* Resolve Address*/
2059 if (dest->addrtype == MSM_IPC_ADDR_ID) {
2060 dst_node_id = dest->addr.port_addr.node_id;
2061 dst_port_id = dest->addr.port_addr.port_id;
2062 } else if (dest->addrtype == MSM_IPC_ADDR_NAME) {
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -06002063 mutex_lock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002064 server = msm_ipc_router_lookup_server(
2065 dest->addr.port_name.service,
2066 dest->addr.port_name.instance,
2067 0, 0);
2068 if (!server) {
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -06002069 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002070 pr_err("%s: Destination not reachable\n", __func__);
2071 return -ENODEV;
2072 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002073 server_port = list_first_entry(&server->server_port_list,
2074 struct msm_ipc_server_port,
2075 list);
2076 dst_node_id = server_port->server_addr.node_id;
2077 dst_port_id = server_port->server_addr.port_id;
2078 mutex_unlock(&server_list_lock);
2079 }
2080 if (dst_node_id == IPC_ROUTER_NID_LOCAL) {
2081 ret = loopback_data(src, dst_port_id, data);
2082 return ret;
2083 }
2084
2085 /* Achieve Flow control */
2086 rport_ptr = msm_ipc_router_lookup_remote_port(dst_node_id,
2087 dst_port_id);
2088 if (!rport_ptr) {
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002089 pr_err("%s: Could not create remote port\n", __func__);
2090 return -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002091 }
2092
Karthikeyan Ramasubramanian5b502d3642012-09-23 22:23:36 -06002093 if (src->check_send_permissions) {
2094 ret = src->check_send_permissions(rport_ptr->sec_rule);
2095 if (ret <= 0) {
2096 pr_err("%s: permission failure for %s\n",
2097 __func__, current->comm);
2098 return -EPERM;
2099 }
2100 }
2101
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002102 pkt = create_pkt(data);
2103 if (!pkt) {
2104 pr_err("%s: Pkt creation failed\n", __func__);
2105 return -ENOMEM;
2106 }
2107
2108 ret = msm_ipc_router_write_pkt(src, rport_ptr, pkt);
2109 release_pkt(pkt);
2110
2111 return ret;
2112}
2113
Karthikeyan Ramasubramanianefc493b2012-07-12 10:25:49 -06002114int msm_ipc_router_send_msg(struct msm_ipc_port *src,
2115 struct msm_ipc_addr *dest,
2116 void *data, unsigned int data_len)
2117{
2118 struct sk_buff_head *out_skb_head;
2119 int ret;
2120
2121 out_skb_head = msm_ipc_router_buf_to_skb(data, data_len);
2122 if (!out_skb_head) {
2123 pr_err("%s: SKB conversion failed\n", __func__);
2124 return -EFAULT;
2125 }
2126
2127 ret = msm_ipc_router_send_to(src, out_skb_head, dest);
2128 if (ret < 0) {
2129 pr_err("%s: msm_ipc_router_send_to failed - ret: %d\n",
2130 __func__, ret);
2131 msm_ipc_router_free_skb(out_skb_head);
2132 }
2133 return 0;
2134}
2135
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002136int msm_ipc_router_read(struct msm_ipc_port *port_ptr,
2137 struct sk_buff_head **data,
2138 size_t buf_len)
2139{
2140 struct rr_packet *pkt;
2141 int ret;
2142
2143 if (!port_ptr || !data)
2144 return -EINVAL;
2145
2146 mutex_lock(&port_ptr->port_rx_q_lock);
2147 if (list_empty(&port_ptr->port_rx_q)) {
2148 mutex_unlock(&port_ptr->port_rx_q_lock);
2149 return -EAGAIN;
2150 }
2151
2152 pkt = list_first_entry(&port_ptr->port_rx_q, struct rr_packet, list);
2153 if ((buf_len) && ((pkt->length - IPC_ROUTER_HDR_SIZE) > buf_len)) {
2154 mutex_unlock(&port_ptr->port_rx_q_lock);
2155 return -ETOOSMALL;
2156 }
2157 list_del(&pkt->list);
2158 if (list_empty(&port_ptr->port_rx_q))
2159 wake_unlock(&port_ptr->port_rx_wake_lock);
2160 *data = pkt->pkt_fragment_q;
2161 ret = pkt->length;
2162 kfree(pkt);
2163 mutex_unlock(&port_ptr->port_rx_q_lock);
2164
2165 return ret;
2166}
2167
2168int msm_ipc_router_recv_from(struct msm_ipc_port *port_ptr,
2169 struct sk_buff_head **data,
2170 struct msm_ipc_addr *src,
Karthikeyan Ramasubramanianefc493b2012-07-12 10:25:49 -06002171 long timeout)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002172{
2173 int ret, data_len, align_size;
2174 struct sk_buff *temp_skb;
2175 struct rr_header *hdr = NULL;
2176
2177 if (!port_ptr || !data) {
2178 pr_err("%s: Invalid pointers being passed\n", __func__);
2179 return -EINVAL;
2180 }
2181
2182 *data = NULL;
2183 mutex_lock(&port_ptr->port_rx_q_lock);
2184 while (list_empty(&port_ptr->port_rx_q)) {
2185 mutex_unlock(&port_ptr->port_rx_q_lock);
2186 if (timeout < 0) {
2187 ret = wait_event_interruptible(
2188 port_ptr->port_rx_wait_q,
2189 !list_empty(&port_ptr->port_rx_q));
2190 if (ret)
2191 return ret;
2192 } else if (timeout > 0) {
2193 timeout = wait_event_interruptible_timeout(
2194 port_ptr->port_rx_wait_q,
2195 !list_empty(&port_ptr->port_rx_q),
2196 timeout);
2197 if (timeout < 0)
2198 return -EFAULT;
2199 }
2200 if (timeout == 0)
2201 return -ETIMEDOUT;
2202 mutex_lock(&port_ptr->port_rx_q_lock);
2203 }
2204 mutex_unlock(&port_ptr->port_rx_q_lock);
2205
2206 ret = msm_ipc_router_read(port_ptr, data, 0);
2207 if (ret <= 0 || !(*data))
2208 return ret;
2209
2210 temp_skb = skb_peek(*data);
2211 hdr = (struct rr_header *)(temp_skb->data);
2212 if (src) {
2213 src->addrtype = MSM_IPC_ADDR_ID;
2214 src->addr.port_addr.node_id = hdr->src_node_id;
2215 src->addr.port_addr.port_id = hdr->src_port_id;
2216 }
2217
2218 data_len = hdr->size;
2219 skb_pull(temp_skb, IPC_ROUTER_HDR_SIZE);
2220 align_size = ALIGN_SIZE(data_len);
2221 if (align_size) {
2222 temp_skb = skb_peek_tail(*data);
2223 skb_trim(temp_skb, (temp_skb->len - align_size));
2224 }
2225 return data_len;
2226}
2227
Karthikeyan Ramasubramanianefc493b2012-07-12 10:25:49 -06002228int msm_ipc_router_read_msg(struct msm_ipc_port *port_ptr,
2229 struct msm_ipc_addr *src,
2230 unsigned char **data,
2231 unsigned int *len)
2232{
2233 struct sk_buff_head *in_skb_head;
2234 int ret;
2235
2236 ret = msm_ipc_router_recv_from(port_ptr, &in_skb_head, src, -1);
2237 if (ret < 0) {
2238 pr_err("%s: msm_ipc_router_recv_from failed - ret: %d\n",
2239 __func__, ret);
2240 return ret;
2241 }
2242
2243 *data = msm_ipc_router_skb_to_buf(in_skb_head, ret);
2244 if (!(*data))
2245 pr_err("%s: Buf conversion failed\n", __func__);
2246
2247 *len = ret;
2248 msm_ipc_router_free_skb(in_skb_head);
2249 return 0;
2250}
2251
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002252struct msm_ipc_port *msm_ipc_router_create_port(
Karthikeyan Ramasubramanianefc493b2012-07-12 10:25:49 -06002253 void (*notify)(unsigned event, void *priv),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002254 void *priv)
2255{
2256 struct msm_ipc_port *port_ptr;
Karthikeyan Ramasubramanianefc493b2012-07-12 10:25:49 -06002257 int ret;
2258
2259 ret = wait_for_completion_interruptible(&msm_ipc_local_router_up);
2260 if (ret < 0) {
2261 pr_err("%s: Error waiting for local router\n", __func__);
2262 return NULL;
2263 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002264
2265 port_ptr = msm_ipc_router_create_raw_port(NULL, notify, priv);
2266 if (!port_ptr)
2267 pr_err("%s: port_ptr alloc failed\n", __func__);
2268
2269 return port_ptr;
2270}
2271
2272int msm_ipc_router_close_port(struct msm_ipc_port *port_ptr)
2273{
2274 union rr_control_msg msg;
2275 struct rr_packet *pkt, *temp_pkt;
2276 struct msm_ipc_server *server;
2277
2278 if (!port_ptr)
2279 return -EINVAL;
2280
2281 if (port_ptr->type == SERVER_PORT || port_ptr->type == CLIENT_PORT) {
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06002282 mutex_lock(&local_ports_lock);
2283 list_del(&port_ptr->list);
2284 mutex_unlock(&local_ports_lock);
2285
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002286 if (port_ptr->type == SERVER_PORT) {
2287 msg.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_SERVER;
2288 msg.srv.service = port_ptr->port_name.service;
2289 msg.srv.instance = port_ptr->port_name.instance;
2290 msg.srv.node_id = port_ptr->this_port.node_id;
2291 msg.srv.port_id = port_ptr->this_port.port_id;
2292 RR("x REMOVE_SERVER Name=%d:%08x Id=%d:%08x\n",
2293 msg.srv.service, msg.srv.instance,
2294 msg.srv.node_id, msg.srv.port_id);
Karthikeyan Ramasubramanian5c568fb2013-01-10 17:09:13 -07002295 broadcast_ctl_msg(&msg);
2296 broadcast_ctl_msg_locally(&msg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002297 }
Karthikeyan Ramasubramanian5c568fb2013-01-10 17:09:13 -07002298
2299 /*
2300 * Server port could have been a client port earlier.
2301 * Send REMOVE_CLIENT message in either case.
2302 */
2303 msg.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT;
2304 msg.cli.node_id = port_ptr->this_port.node_id;
2305 msg.cli.port_id = port_ptr->this_port.port_id;
2306 RR("x REMOVE_CLIENT id=%d:%08x\n",
2307 msg.cli.node_id, msg.cli.port_id);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002308 broadcast_ctl_msg(&msg);
2309 broadcast_ctl_msg_locally(&msg);
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06002310 } else if (port_ptr->type == CONTROL_PORT) {
2311 mutex_lock(&control_ports_lock);
2312 list_del(&port_ptr->list);
2313 mutex_unlock(&control_ports_lock);
Karthikeyan Ramasubramanianf7a4b6e2013-01-16 09:00:28 -07002314 } else if (port_ptr->type == IRSC_PORT) {
2315 mutex_lock(&local_ports_lock);
2316 list_del(&port_ptr->list);
2317 mutex_unlock(&local_ports_lock);
2318 signal_irsc_completion();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002319 }
2320
2321 mutex_lock(&port_ptr->port_rx_q_lock);
2322 list_for_each_entry_safe(pkt, temp_pkt, &port_ptr->port_rx_q, list) {
2323 list_del(&pkt->list);
2324 release_pkt(pkt);
2325 }
2326 mutex_unlock(&port_ptr->port_rx_q_lock);
2327
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002328 if (port_ptr->type == SERVER_PORT) {
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -06002329 mutex_lock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002330 server = msm_ipc_router_lookup_server(
2331 port_ptr->port_name.service,
2332 port_ptr->port_name.instance,
2333 port_ptr->this_port.node_id,
2334 port_ptr->this_port.port_id);
2335 if (server)
2336 msm_ipc_router_destroy_server(server,
2337 port_ptr->this_port.node_id,
2338 port_ptr->this_port.port_id);
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -06002339 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002340 }
2341
Karthikeyan Ramasubramaniandd8c3b52011-11-30 16:26:12 -07002342 wake_lock_destroy(&port_ptr->port_rx_wake_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002343 kfree(port_ptr);
2344 return 0;
2345}
2346
2347int msm_ipc_router_get_curr_pkt_size(struct msm_ipc_port *port_ptr)
2348{
2349 struct rr_packet *pkt;
2350 int rc = 0;
2351
2352 if (!port_ptr)
2353 return -EINVAL;
2354
2355 mutex_lock(&port_ptr->port_rx_q_lock);
2356 if (!list_empty(&port_ptr->port_rx_q)) {
2357 pkt = list_first_entry(&port_ptr->port_rx_q,
2358 struct rr_packet, list);
2359 rc = pkt->length;
2360 }
2361 mutex_unlock(&port_ptr->port_rx_q_lock);
2362
2363 return rc;
2364}
2365
2366int msm_ipc_router_bind_control_port(struct msm_ipc_port *port_ptr)
2367{
2368 if (!port_ptr)
2369 return -EINVAL;
2370
2371 mutex_lock(&local_ports_lock);
2372 list_del(&port_ptr->list);
2373 mutex_unlock(&local_ports_lock);
2374 port_ptr->type = CONTROL_PORT;
2375 mutex_lock(&control_ports_lock);
2376 list_add_tail(&port_ptr->list, &control_ports);
2377 mutex_unlock(&control_ports_lock);
2378
2379 return 0;
2380}
2381
2382int msm_ipc_router_lookup_server_name(struct msm_ipc_port_name *srv_name,
Karthikeyan Ramasubramaniandfde01b2012-06-12 14:25:13 -06002383 struct msm_ipc_server_info *srv_info,
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002384 int num_entries_in_array,
2385 uint32_t lookup_mask)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002386{
2387 struct msm_ipc_server *server;
2388 struct msm_ipc_server_port *server_port;
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002389 int key, i = 0; /*num_entries_found*/
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002390
2391 if (!srv_name) {
2392 pr_err("%s: Invalid srv_name\n", __func__);
2393 return -EINVAL;
2394 }
2395
Karthikeyan Ramasubramaniandfde01b2012-06-12 14:25:13 -06002396 if (num_entries_in_array && !srv_info) {
2397 pr_err("%s: srv_info NULL\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002398 return -EINVAL;
2399 }
2400
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002401 mutex_lock(&server_list_lock);
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002402 if (!lookup_mask)
2403 lookup_mask = 0xFFFFFFFF;
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -06002404 key = (srv_name->service & (SRV_HASH_SIZE - 1));
2405 list_for_each_entry(server, &server_list[key], list) {
2406 if ((server->name.service != srv_name->service) ||
2407 ((server->name.instance & lookup_mask) !=
2408 srv_name->instance))
2409 continue;
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002410
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -06002411 list_for_each_entry(server_port,
2412 &server->server_port_list, list) {
2413 if (i < num_entries_in_array) {
2414 srv_info[i].node_id =
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002415 server_port->server_addr.node_id;
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -06002416 srv_info[i].port_id =
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002417 server_port->server_addr.port_id;
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -06002418 srv_info[i].service = server->name.service;
2419 srv_info[i].instance = server->name.instance;
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002420 }
Karthikeyan Ramasubramanianbb8306b2012-10-25 15:40:45 -06002421 i++;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002422 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002423 }
2424 mutex_unlock(&server_list_lock);
2425
2426 return i;
2427}
2428
2429int msm_ipc_router_close(void)
2430{
2431 struct msm_ipc_router_xprt_info *xprt_info, *tmp_xprt_info;
2432
2433 mutex_lock(&xprt_info_list_lock);
2434 list_for_each_entry_safe(xprt_info, tmp_xprt_info,
2435 &xprt_info_list, list) {
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -07002436 xprt_info->xprt->close(xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002437 list_del(&xprt_info->list);
2438 kfree(xprt_info);
2439 }
2440 mutex_unlock(&xprt_info_list_lock);
2441 return 0;
2442}
2443
2444#if defined(CONFIG_DEBUG_FS)
2445static int dump_routing_table(char *buf, int max)
2446{
2447 int i = 0, j;
2448 struct msm_ipc_routing_table_entry *rt_entry;
2449
2450 for (j = 0; j < RT_HASH_SIZE; j++) {
2451 mutex_lock(&routing_table_lock);
2452 list_for_each_entry(rt_entry, &routing_table[j], list) {
2453 mutex_lock(&rt_entry->lock);
2454 i += scnprintf(buf + i, max - i,
2455 "Node Id: 0x%08x\n", rt_entry->node_id);
Karthikeyan Ramasubramanianbddeec72012-09-10 16:10:24 -06002456 if (rt_entry->node_id == IPC_ROUTER_NID_LOCAL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002457 i += scnprintf(buf + i, max - i,
2458 "XPRT Name: Loopback\n");
2459 i += scnprintf(buf + i, max - i,
2460 "Next Hop: %d\n", rt_entry->node_id);
2461 } else {
2462 i += scnprintf(buf + i, max - i,
2463 "XPRT Name: %s\n",
2464 rt_entry->xprt_info->xprt->name);
2465 i += scnprintf(buf + i, max - i,
2466 "Next Hop: 0x%08x\n",
2467 rt_entry->xprt_info->remote_node_id);
2468 }
2469 i += scnprintf(buf + i, max - i, "\n");
2470 mutex_unlock(&rt_entry->lock);
2471 }
2472 mutex_unlock(&routing_table_lock);
2473 }
2474
2475 return i;
2476}
2477
2478static int dump_xprt_info(char *buf, int max)
2479{
2480 int i = 0;
2481 struct msm_ipc_router_xprt_info *xprt_info;
2482
2483 mutex_lock(&xprt_info_list_lock);
2484 list_for_each_entry(xprt_info, &xprt_info_list, list) {
2485 i += scnprintf(buf + i, max - i, "XPRT Name: %s\n",
2486 xprt_info->xprt->name);
2487 i += scnprintf(buf + i, max - i, "Link Id: %d\n",
2488 xprt_info->xprt->link_id);
2489 i += scnprintf(buf + i, max - i, "Initialized: %s\n",
2490 (xprt_info->initialized ? "Y" : "N"));
2491 i += scnprintf(buf + i, max - i, "Remote Node Id: 0x%08x\n",
2492 xprt_info->remote_node_id);
2493 i += scnprintf(buf + i, max - i, "\n");
2494 }
2495 mutex_unlock(&xprt_info_list_lock);
2496
2497 return i;
2498}
2499
2500static int dump_servers(char *buf, int max)
2501{
2502 int i = 0, j;
2503 struct msm_ipc_server *server;
2504 struct msm_ipc_server_port *server_port;
2505
2506 mutex_lock(&server_list_lock);
2507 for (j = 0; j < SRV_HASH_SIZE; j++) {
2508 list_for_each_entry(server, &server_list[j], list) {
2509 list_for_each_entry(server_port,
2510 &server->server_port_list,
2511 list) {
2512 i += scnprintf(buf + i, max - i, "Service: "
2513 "0x%08x\n", server->name.service);
2514 i += scnprintf(buf + i, max - i, "Instance: "
2515 "0x%08x\n", server->name.instance);
2516 i += scnprintf(buf + i, max - i,
2517 "Node_id: 0x%08x\n",
2518 server_port->server_addr.node_id);
2519 i += scnprintf(buf + i, max - i,
2520 "Port_id: 0x%08x\n",
2521 server_port->server_addr.port_id);
2522 i += scnprintf(buf + i, max - i, "\n");
2523 }
2524 }
2525 }
2526 mutex_unlock(&server_list_lock);
2527
2528 return i;
2529}
2530
2531static int dump_remote_ports(char *buf, int max)
2532{
2533 int i = 0, j, k;
2534 struct msm_ipc_router_remote_port *rport_ptr;
2535 struct msm_ipc_routing_table_entry *rt_entry;
2536
2537 for (j = 0; j < RT_HASH_SIZE; j++) {
2538 mutex_lock(&routing_table_lock);
2539 list_for_each_entry(rt_entry, &routing_table[j], list) {
2540 mutex_lock(&rt_entry->lock);
2541 for (k = 0; k < RP_HASH_SIZE; k++) {
2542 list_for_each_entry(rport_ptr,
2543 &rt_entry->remote_port_list[k],
2544 list) {
2545 i += scnprintf(buf + i, max - i,
2546 "Node_id: 0x%08x\n",
2547 rport_ptr->node_id);
2548 i += scnprintf(buf + i, max - i,
2549 "Port_id: 0x%08x\n",
2550 rport_ptr->port_id);
2551 i += scnprintf(buf + i, max - i,
2552 "Quota_cnt: %d\n",
2553 rport_ptr->tx_quota_cnt);
2554 i += scnprintf(buf + i, max - i, "\n");
2555 }
2556 }
2557 mutex_unlock(&rt_entry->lock);
2558 }
2559 mutex_unlock(&routing_table_lock);
2560 }
2561
2562 return i;
2563}
2564
2565static int dump_control_ports(char *buf, int max)
2566{
2567 int i = 0;
2568 struct msm_ipc_port *port_ptr;
2569
2570 mutex_lock(&control_ports_lock);
2571 list_for_each_entry(port_ptr, &control_ports, list) {
2572 i += scnprintf(buf + i, max - i, "Node_id: 0x%08x\n",
2573 port_ptr->this_port.node_id);
2574 i += scnprintf(buf + i, max - i, "Port_id: 0x%08x\n",
2575 port_ptr->this_port.port_id);
2576 i += scnprintf(buf + i, max - i, "\n");
2577 }
2578 mutex_unlock(&control_ports_lock);
2579
2580 return i;
2581}
2582
2583static int dump_local_ports(char *buf, int max)
2584{
2585 int i = 0, j;
2586 unsigned long flags;
2587 struct msm_ipc_port *port_ptr;
2588
2589 mutex_lock(&local_ports_lock);
2590 for (j = 0; j < LP_HASH_SIZE; j++) {
2591 list_for_each_entry(port_ptr, &local_ports[j], list) {
2592 spin_lock_irqsave(&port_ptr->port_lock, flags);
2593 i += scnprintf(buf + i, max - i, "Node_id: 0x%08x\n",
2594 port_ptr->this_port.node_id);
2595 i += scnprintf(buf + i, max - i, "Port_id: 0x%08x\n",
2596 port_ptr->this_port.port_id);
2597 i += scnprintf(buf + i, max - i, "# pkts tx'd %d\n",
2598 port_ptr->num_tx);
2599 i += scnprintf(buf + i, max - i, "# pkts rx'd %d\n",
2600 port_ptr->num_rx);
2601 i += scnprintf(buf + i, max - i, "# bytes tx'd %ld\n",
2602 port_ptr->num_tx_bytes);
2603 i += scnprintf(buf + i, max - i, "# bytes rx'd %ld\n",
2604 port_ptr->num_rx_bytes);
2605 spin_unlock_irqrestore(&port_ptr->port_lock, flags);
2606 i += scnprintf(buf + i, max - i, "\n");
2607 }
2608 }
2609 mutex_unlock(&local_ports_lock);
2610
2611 return i;
2612}
2613
2614#define DEBUG_BUFMAX 4096
2615static char debug_buffer[DEBUG_BUFMAX];
2616
2617static ssize_t debug_read(struct file *file, char __user *buf,
2618 size_t count, loff_t *ppos)
2619{
2620 int (*fill)(char *buf, int max) = file->private_data;
2621 int bsize = fill(debug_buffer, DEBUG_BUFMAX);
2622 return simple_read_from_buffer(buf, count, ppos, debug_buffer, bsize);
2623}
2624
2625static int debug_open(struct inode *inode, struct file *file)
2626{
2627 file->private_data = inode->i_private;
2628 return 0;
2629}
2630
2631static const struct file_operations debug_ops = {
2632 .read = debug_read,
2633 .open = debug_open,
2634};
2635
2636static void debug_create(const char *name, mode_t mode,
2637 struct dentry *dent,
2638 int (*fill)(char *buf, int max))
2639{
2640 debugfs_create_file(name, mode, dent, fill, &debug_ops);
2641}
2642
2643static void debugfs_init(void)
2644{
2645 struct dentry *dent;
2646
2647 dent = debugfs_create_dir("msm_ipc_router", 0);
2648 if (IS_ERR(dent))
2649 return;
2650
2651 debug_create("dump_local_ports", 0444, dent,
2652 dump_local_ports);
2653 debug_create("dump_remote_ports", 0444, dent,
2654 dump_remote_ports);
2655 debug_create("dump_control_ports", 0444, dent,
2656 dump_control_ports);
2657 debug_create("dump_servers", 0444, dent,
2658 dump_servers);
2659 debug_create("dump_xprt_info", 0444, dent,
2660 dump_xprt_info);
2661 debug_create("dump_routing_table", 0444, dent,
2662 dump_routing_table);
2663}
2664
2665#else
2666static void debugfs_init(void) {}
2667#endif
2668
2669static int msm_ipc_router_add_xprt(struct msm_ipc_router_xprt *xprt)
2670{
2671 struct msm_ipc_router_xprt_info *xprt_info;
2672 struct msm_ipc_routing_table_entry *rt_entry;
2673
2674 xprt_info = kmalloc(sizeof(struct msm_ipc_router_xprt_info),
2675 GFP_KERNEL);
2676 if (!xprt_info)
2677 return -ENOMEM;
2678
2679 xprt_info->xprt = xprt;
2680 xprt_info->initialized = 0;
2681 xprt_info->remote_node_id = -1;
2682 INIT_LIST_HEAD(&xprt_info->pkt_list);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002683 mutex_init(&xprt_info->rx_lock);
2684 mutex_init(&xprt_info->tx_lock);
2685 wake_lock_init(&xprt_info->wakelock,
2686 WAKE_LOCK_SUSPEND, xprt->name);
2687 xprt_info->need_len = 0;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002688 xprt_info->abort_data_read = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002689 INIT_WORK(&xprt_info->read_data, do_read_data);
2690 INIT_LIST_HEAD(&xprt_info->list);
2691
2692 xprt_info->workqueue = create_singlethread_workqueue(xprt->name);
2693 if (!xprt_info->workqueue) {
2694 kfree(xprt_info);
2695 return -ENOMEM;
2696 }
2697
2698 if (!strcmp(xprt->name, "msm_ipc_router_loopback_xprt")) {
2699 xprt_info->remote_node_id = IPC_ROUTER_NID_LOCAL;
2700 xprt_info->initialized = 1;
2701 }
2702
2703 mutex_lock(&xprt_info_list_lock);
2704 list_add_tail(&xprt_info->list, &xprt_info_list);
2705 mutex_unlock(&xprt_info_list_lock);
2706
2707 mutex_lock(&routing_table_lock);
2708 if (!routing_table_inited) {
2709 init_routing_table();
2710 rt_entry = alloc_routing_table_entry(IPC_ROUTER_NID_LOCAL);
2711 add_routing_table_entry(rt_entry);
2712 routing_table_inited = 1;
2713 }
2714 mutex_unlock(&routing_table_lock);
2715
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002716 xprt->priv = xprt_info;
2717
2718 return 0;
2719}
2720
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002721static void msm_ipc_router_remove_xprt(struct msm_ipc_router_xprt *xprt)
2722{
2723 struct msm_ipc_router_xprt_info *xprt_info;
2724
2725 if (xprt && xprt->priv) {
2726 xprt_info = xprt->priv;
2727
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06002728 mutex_lock(&xprt_info->rx_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002729 xprt_info->abort_data_read = 1;
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06002730 mutex_unlock(&xprt_info->rx_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002731
2732 mutex_lock(&xprt_info_list_lock);
2733 list_del(&xprt_info->list);
2734 mutex_unlock(&xprt_info_list_lock);
2735
2736 flush_workqueue(xprt_info->workqueue);
2737 destroy_workqueue(xprt_info->workqueue);
2738 wake_lock_destroy(&xprt_info->wakelock);
2739
2740 xprt->priv = 0;
2741 kfree(xprt_info);
2742 }
2743}
2744
2745
2746struct msm_ipc_router_xprt_work {
2747 struct msm_ipc_router_xprt *xprt;
2748 struct work_struct work;
2749};
2750
2751static void xprt_open_worker(struct work_struct *work)
2752{
2753 struct msm_ipc_router_xprt_work *xprt_work =
2754 container_of(work, struct msm_ipc_router_xprt_work, work);
2755
2756 msm_ipc_router_add_xprt(xprt_work->xprt);
2757 kfree(xprt_work);
2758}
2759
2760static void xprt_close_worker(struct work_struct *work)
2761{
2762 struct msm_ipc_router_xprt_work *xprt_work =
2763 container_of(work, struct msm_ipc_router_xprt_work, work);
2764
2765 modem_reset_cleanup(xprt_work->xprt->priv);
2766 msm_ipc_router_remove_xprt(xprt_work->xprt);
2767
2768 if (atomic_dec_return(&pending_close_count) == 0)
2769 wake_up(&subsystem_restart_wait);
2770
2771 kfree(xprt_work);
2772}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002773
2774void msm_ipc_router_xprt_notify(struct msm_ipc_router_xprt *xprt,
2775 unsigned event,
2776 void *data)
2777{
2778 struct msm_ipc_router_xprt_info *xprt_info = xprt->priv;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002779 struct msm_ipc_router_xprt_work *xprt_work;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002780 struct rr_packet *pkt;
Karthikeyan Ramasubramanian4af9f7c2011-09-30 15:55:18 -06002781 unsigned long ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002782
Karthikeyan Ramasubramanian4af9f7c2011-09-30 15:55:18 -06002783 if (!msm_ipc_router_workqueue) {
2784 ret = wait_for_completion_timeout(&msm_ipc_local_router_up,
2785 IPC_ROUTER_INIT_TIMEOUT);
2786 if (!ret || !msm_ipc_router_workqueue) {
2787 pr_err("%s: IPC Router not initialized\n", __func__);
2788 return;
2789 }
2790 }
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002791
2792 switch (event) {
2793 case IPC_ROUTER_XPRT_EVENT_OPEN:
2794 D("open event for '%s'\n", xprt->name);
2795 xprt_work = kmalloc(sizeof(struct msm_ipc_router_xprt_work),
2796 GFP_ATOMIC);
2797 xprt_work->xprt = xprt;
2798 INIT_WORK(&xprt_work->work, xprt_open_worker);
2799 queue_work(msm_ipc_router_workqueue, &xprt_work->work);
2800 break;
2801
2802 case IPC_ROUTER_XPRT_EVENT_CLOSE:
2803 D("close event for '%s'\n", xprt->name);
2804 atomic_inc(&pending_close_count);
2805 xprt_work = kmalloc(sizeof(struct msm_ipc_router_xprt_work),
2806 GFP_ATOMIC);
2807 xprt_work->xprt = xprt;
2808 INIT_WORK(&xprt_work->work, xprt_close_worker);
2809 queue_work(msm_ipc_router_workqueue, &xprt_work->work);
2810 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002811 }
2812
2813 if (!data)
2814 return;
2815
2816 while (!xprt_info) {
2817 msleep(100);
2818 xprt_info = xprt->priv;
2819 }
2820
2821 pkt = clone_pkt((struct rr_packet *)data);
2822 if (!pkt)
2823 return;
2824
2825 mutex_lock(&xprt_info->rx_lock);
2826 list_add_tail(&pkt->list, &xprt_info->pkt_list);
2827 wake_lock(&xprt_info->wakelock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002828 mutex_unlock(&xprt_info->rx_lock);
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06002829 queue_work(xprt_info->workqueue, &xprt_info->read_data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002830}
2831
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002832static int modem_restart_notifier_cb(struct notifier_block *this,
2833 unsigned long code,
2834 void *data);
2835static struct notifier_block msm_ipc_router_nb = {
2836 .notifier_call = modem_restart_notifier_cb,
2837};
2838
2839static int modem_restart_notifier_cb(struct notifier_block *this,
2840 unsigned long code,
2841 void *data)
2842{
2843 switch (code) {
2844 case SUBSYS_BEFORE_SHUTDOWN:
2845 D("%s: SUBSYS_BEFORE_SHUTDOWN\n", __func__);
2846 break;
2847
2848 case SUBSYS_BEFORE_POWERUP:
2849 D("%s: waiting for RPC restart to complete\n", __func__);
2850 wait_event(subsystem_restart_wait,
2851 atomic_read(&pending_close_count) == 0);
2852 D("%s: finished restart wait\n", __func__);
2853 break;
2854
2855 default:
2856 break;
2857 }
2858
2859 return NOTIFY_DONE;
2860}
2861
2862static void *restart_notifier_handle;
2863static __init int msm_ipc_router_modem_restart_late_init(void)
2864{
2865 restart_notifier_handle = subsys_notif_register_notifier("modem",
2866 &msm_ipc_router_nb);
2867 return 0;
2868}
2869late_initcall(msm_ipc_router_modem_restart_late_init);
2870
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002871static int __init msm_ipc_router_init(void)
2872{
2873 int i, ret;
2874 struct msm_ipc_routing_table_entry *rt_entry;
2875
2876 msm_ipc_router_debug_mask |= SMEM_LOG;
Karthikeyan Ramasubramanian2bfe8ec2013-03-22 10:47:20 -06002877 ipc_rtr_log_ctxt = ipc_log_context_create(IPC_RTR_LOG_PAGES,
2878 "ipc_router");
2879 if (!ipc_rtr_log_ctxt)
2880 pr_err("%s: Unable to create IPC logging for IPC RTR",
2881 __func__);
2882
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002883 msm_ipc_router_workqueue =
2884 create_singlethread_workqueue("msm_ipc_router");
2885 if (!msm_ipc_router_workqueue)
2886 return -ENOMEM;
2887
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002888 debugfs_init();
2889
2890 for (i = 0; i < SRV_HASH_SIZE; i++)
2891 INIT_LIST_HEAD(&server_list[i]);
2892
2893 for (i = 0; i < LP_HASH_SIZE; i++)
2894 INIT_LIST_HEAD(&local_ports[i]);
2895
2896 mutex_lock(&routing_table_lock);
2897 if (!routing_table_inited) {
2898 init_routing_table();
2899 rt_entry = alloc_routing_table_entry(IPC_ROUTER_NID_LOCAL);
2900 add_routing_table_entry(rt_entry);
2901 routing_table_inited = 1;
2902 }
2903 mutex_unlock(&routing_table_lock);
2904
2905 init_waitqueue_head(&newserver_wait);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002906 init_waitqueue_head(&subsystem_restart_wait);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002907 ret = msm_ipc_router_init_sockets();
2908 if (ret < 0)
2909 pr_err("%s: Init sockets failed\n", __func__);
2910
Karthikeyan Ramasubramanian5b502d3642012-09-23 22:23:36 -06002911 ret = msm_ipc_router_security_init();
2912 if (ret < 0)
2913 pr_err("%s: Security Init failed\n", __func__);
2914
Karthikeyan Ramasubramanian4af9f7c2011-09-30 15:55:18 -06002915 complete_all(&msm_ipc_local_router_up);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002916 return ret;
2917}
2918
2919module_init(msm_ipc_router_init);
2920MODULE_DESCRIPTION("MSM IPC Router");
2921MODULE_LICENSE("GPL v2");