blob: 29ec8fbf7217d208a03513da8dd984d2135c5f65 [file] [log] [blame]
Karthikeyan Ramasubramanian25e91872013-01-10 17:09:13 -07001/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#define DEBUG
14
15#include <linux/slab.h>
16#include <linux/module.h>
17#include <linux/kernel.h>
18#include <linux/string.h>
19#include <linux/errno.h>
20#include <linux/init.h>
21#include <linux/types.h>
22#include <linux/delay.h>
23#include <linux/err.h>
24#include <linux/sched.h>
25#include <linux/poll.h>
26#include <linux/wakelock.h>
27#include <linux/platform_device.h>
28#include <linux/uaccess.h>
29#include <linux/debugfs.h>
30
31#include <asm/uaccess.h>
32#include <asm/byteorder.h>
33
34#include <mach/smem_log.h>
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -060035#include <mach/subsystem_notif.h>
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -060036#include <mach/msm_ipc_router.h>
Karthikeyan Ramasubramanian682ebcc2013-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 Ramasubramanian1668cc62012-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 Ramasubramanian682ebcc2013-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 Ramasubramanian682ebcc2013-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 Ramasubramanian682ebcc2013-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 Ramasubramaniana85d09f2012-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 Ramasubramanian1668cc62012-09-23 22:23:36 -0600123 int synced_sec_rule;
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -0600124 char pdev_name[32];
125 int next_pdev_id;
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 Ramasubramanian70444192012-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 Ramasubramanian1668cc62012-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 struct workqueue_struct *msm_ipc_router_workqueue;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700204
205enum {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700206 DOWN,
207 UP,
208};
209
210static void init_routing_table(void)
211{
212 int i;
213 for (i = 0; i < RT_HASH_SIZE; i++)
214 INIT_LIST_HEAD(&routing_table[i]);
215}
216
217static struct msm_ipc_routing_table_entry *alloc_routing_table_entry(
218 uint32_t node_id)
219{
220 int i;
221 struct msm_ipc_routing_table_entry *rt_entry;
222
223 rt_entry = kmalloc(sizeof(struct msm_ipc_routing_table_entry),
224 GFP_KERNEL);
225 if (!rt_entry) {
226 pr_err("%s: rt_entry allocation failed for %d\n",
227 __func__, node_id);
228 return NULL;
229 }
230
231 for (i = 0; i < RP_HASH_SIZE; i++)
232 INIT_LIST_HEAD(&rt_entry->remote_port_list[i]);
233
234 mutex_init(&rt_entry->lock);
235 rt_entry->node_id = node_id;
236 rt_entry->xprt_info = NULL;
237 return rt_entry;
238}
239
240/*Please take routing_table_lock before calling this function*/
241static int add_routing_table_entry(
242 struct msm_ipc_routing_table_entry *rt_entry)
243{
244 uint32_t key;
245
246 if (!rt_entry)
247 return -EINVAL;
248
249 key = (rt_entry->node_id % RT_HASH_SIZE);
250 list_add_tail(&rt_entry->list, &routing_table[key]);
251 return 0;
252}
253
254/*Please take routing_table_lock before calling this function*/
255static struct msm_ipc_routing_table_entry *lookup_routing_table(
256 uint32_t node_id)
257{
258 uint32_t key = (node_id % RT_HASH_SIZE);
259 struct msm_ipc_routing_table_entry *rt_entry;
260
261 list_for_each_entry(rt_entry, &routing_table[key], list) {
262 if (rt_entry->node_id == node_id)
263 return rt_entry;
264 }
265 return NULL;
266}
267
268struct rr_packet *rr_read(struct msm_ipc_router_xprt_info *xprt_info)
269{
270 struct rr_packet *temp_pkt;
271
272 if (!xprt_info)
273 return NULL;
274
275 mutex_lock(&xprt_info->rx_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600276 if (xprt_info->abort_data_read) {
277 mutex_unlock(&xprt_info->rx_lock);
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -0600278 pr_err("%s detected SSR & exiting now\n",
279 xprt_info->xprt->name);
280 return NULL;
281 }
282
283 if (list_empty(&xprt_info->pkt_list)) {
284 mutex_unlock(&xprt_info->rx_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600285 return NULL;
286 }
287
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700288 temp_pkt = list_first_entry(&xprt_info->pkt_list,
289 struct rr_packet, list);
290 list_del(&temp_pkt->list);
291 if (list_empty(&xprt_info->pkt_list))
292 wake_unlock(&xprt_info->wakelock);
293 mutex_unlock(&xprt_info->rx_lock);
294 return temp_pkt;
295}
296
297struct rr_packet *clone_pkt(struct rr_packet *pkt)
298{
299 struct rr_packet *cloned_pkt;
300 struct sk_buff *temp_skb, *cloned_skb;
301 struct sk_buff_head *pkt_fragment_q;
302
303 cloned_pkt = kzalloc(sizeof(struct rr_packet), GFP_KERNEL);
304 if (!cloned_pkt) {
305 pr_err("%s: failure\n", __func__);
306 return NULL;
307 }
308
309 pkt_fragment_q = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
310 if (!pkt_fragment_q) {
311 pr_err("%s: pkt_frag_q alloc failure\n", __func__);
312 kfree(cloned_pkt);
313 return NULL;
314 }
315 skb_queue_head_init(pkt_fragment_q);
316
317 skb_queue_walk(pkt->pkt_fragment_q, temp_skb) {
318 cloned_skb = skb_clone(temp_skb, GFP_KERNEL);
319 if (!cloned_skb)
320 goto fail_clone;
321 skb_queue_tail(pkt_fragment_q, cloned_skb);
322 }
323 cloned_pkt->pkt_fragment_q = pkt_fragment_q;
324 cloned_pkt->length = pkt->length;
325 return cloned_pkt;
326
327fail_clone:
328 while (!skb_queue_empty(pkt_fragment_q)) {
329 temp_skb = skb_dequeue(pkt_fragment_q);
330 kfree_skb(temp_skb);
331 }
332 kfree(pkt_fragment_q);
333 kfree(cloned_pkt);
334 return NULL;
335}
336
337struct rr_packet *create_pkt(struct sk_buff_head *data)
338{
339 struct rr_packet *pkt;
340 struct sk_buff *temp_skb;
341
342 pkt = kzalloc(sizeof(struct rr_packet), GFP_KERNEL);
343 if (!pkt) {
344 pr_err("%s: failure\n", __func__);
345 return NULL;
346 }
347
348 pkt->pkt_fragment_q = data;
349 skb_queue_walk(pkt->pkt_fragment_q, temp_skb)
350 pkt->length += temp_skb->len;
351 return pkt;
352}
353
354void release_pkt(struct rr_packet *pkt)
355{
356 struct sk_buff *temp_skb;
357
358 if (!pkt)
359 return;
360
361 if (!pkt->pkt_fragment_q) {
362 kfree(pkt);
363 return;
364 }
365
366 while (!skb_queue_empty(pkt->pkt_fragment_q)) {
367 temp_skb = skb_dequeue(pkt->pkt_fragment_q);
368 kfree_skb(temp_skb);
369 }
370 kfree(pkt->pkt_fragment_q);
371 kfree(pkt);
372 return;
373}
374
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -0600375static struct sk_buff_head *msm_ipc_router_buf_to_skb(void *buf,
376 unsigned int buf_len)
377{
378 struct sk_buff_head *skb_head;
379 struct sk_buff *skb;
380 int first = 1, offset = 0;
381 int skb_size, data_size;
382 void *data;
383
384 skb_head = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
385 if (!skb_head) {
386 pr_err("%s: Couldnot allocate skb_head\n", __func__);
387 return NULL;
388 }
389 skb_queue_head_init(skb_head);
390
391 data_size = buf_len;
392 while (offset != buf_len) {
393 skb_size = data_size;
394 if (first)
395 skb_size += IPC_ROUTER_HDR_SIZE;
396
397 skb = alloc_skb(skb_size, GFP_KERNEL);
398 if (!skb) {
399 if (skb_size <= (PAGE_SIZE/2)) {
400 pr_err("%s: cannot allocate skb\n", __func__);
401 goto buf_to_skb_error;
402 }
403 data_size = data_size / 2;
404 continue;
405 }
406
407 if (first) {
408 skb_reserve(skb, IPC_ROUTER_HDR_SIZE);
409 first = 0;
410 }
411
412 data = skb_put(skb, data_size);
413 memcpy(skb->data, buf + offset, data_size);
414 skb_queue_tail(skb_head, skb);
415 offset += data_size;
416 data_size = buf_len - offset;
417 }
418 return skb_head;
419
420buf_to_skb_error:
421 while (!skb_queue_empty(skb_head)) {
422 skb = skb_dequeue(skb_head);
423 kfree_skb(skb);
424 }
425 kfree(skb_head);
426 return NULL;
427}
428
429static void *msm_ipc_router_skb_to_buf(struct sk_buff_head *skb_head,
430 unsigned int len)
431{
432 struct sk_buff *temp;
433 int offset = 0, buf_len = 0, copy_len;
434 void *buf;
435
436 if (!skb_head) {
437 pr_err("%s: NULL skb_head\n", __func__);
438 return NULL;
439 }
440
441 temp = skb_peek(skb_head);
442 buf_len = len;
443 buf = kmalloc(buf_len, GFP_KERNEL);
444 if (!buf) {
445 pr_err("%s: cannot allocate buf\n", __func__);
446 return NULL;
447 }
448 skb_queue_walk(skb_head, temp) {
449 copy_len = buf_len < temp->len ? buf_len : temp->len;
450 memcpy(buf + offset, temp->data, copy_len);
451 offset += copy_len;
452 buf_len -= copy_len;
453 }
454 return buf;
455}
456
457static void msm_ipc_router_free_skb(struct sk_buff_head *skb_head)
458{
459 struct sk_buff *temp_skb;
460
461 if (!skb_head)
462 return;
463
464 while (!skb_queue_empty(skb_head)) {
465 temp_skb = skb_dequeue(skb_head);
466 kfree_skb(temp_skb);
467 }
468 kfree(skb_head);
469}
470
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700471static int post_control_ports(struct rr_packet *pkt)
472{
473 struct msm_ipc_port *port_ptr;
474 struct rr_packet *cloned_pkt;
475
476 if (!pkt)
477 return -EINVAL;
478
479 mutex_lock(&control_ports_lock);
480 list_for_each_entry(port_ptr, &control_ports, list) {
481 mutex_lock(&port_ptr->port_rx_q_lock);
482 cloned_pkt = clone_pkt(pkt);
483 wake_lock(&port_ptr->port_rx_wake_lock);
484 list_add_tail(&cloned_pkt->list, &port_ptr->port_rx_q);
485 wake_up(&port_ptr->port_rx_wait_q);
486 mutex_unlock(&port_ptr->port_rx_q_lock);
487 }
488 mutex_unlock(&control_ports_lock);
489 return 0;
490}
491
492static uint32_t allocate_port_id(void)
493{
494 uint32_t port_id = 0, prev_port_id, key;
495 struct msm_ipc_port *port_ptr;
496
497 mutex_lock(&next_port_id_lock);
498 prev_port_id = next_port_id;
499 mutex_lock(&local_ports_lock);
500 do {
501 next_port_id++;
502 if ((next_port_id & 0xFFFFFFFE) == 0xFFFFFFFE)
503 next_port_id = 1;
504
505 key = (next_port_id & (LP_HASH_SIZE - 1));
506 if (list_empty(&local_ports[key])) {
507 port_id = next_port_id;
508 break;
509 }
510 list_for_each_entry(port_ptr, &local_ports[key], list) {
511 if (port_ptr->this_port.port_id == next_port_id) {
512 port_id = next_port_id;
513 break;
514 }
515 }
516 if (!port_id) {
517 port_id = next_port_id;
518 break;
519 }
520 port_id = 0;
521 } while (next_port_id != prev_port_id);
522 mutex_unlock(&local_ports_lock);
523 mutex_unlock(&next_port_id_lock);
524
525 return port_id;
526}
527
528void msm_ipc_router_add_local_port(struct msm_ipc_port *port_ptr)
529{
530 uint32_t key;
531
532 if (!port_ptr)
533 return;
534
535 key = (port_ptr->this_port.port_id & (LP_HASH_SIZE - 1));
536 mutex_lock(&local_ports_lock);
537 list_add_tail(&port_ptr->list, &local_ports[key]);
538 mutex_unlock(&local_ports_lock);
539}
540
541struct msm_ipc_port *msm_ipc_router_create_raw_port(void *endpoint,
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -0600542 void (*notify)(unsigned event, void *priv),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700543 void *priv)
544{
545 struct msm_ipc_port *port_ptr;
546
547 port_ptr = kzalloc(sizeof(struct msm_ipc_port), GFP_KERNEL);
548 if (!port_ptr)
549 return NULL;
550
551 port_ptr->this_port.node_id = IPC_ROUTER_NID_LOCAL;
552 port_ptr->this_port.port_id = allocate_port_id();
553 if (!port_ptr->this_port.port_id) {
554 pr_err("%s: All port ids are in use\n", __func__);
555 kfree(port_ptr);
556 return NULL;
557 }
558
559 spin_lock_init(&port_ptr->port_lock);
560 INIT_LIST_HEAD(&port_ptr->incomplete);
561 mutex_init(&port_ptr->incomplete_lock);
562 INIT_LIST_HEAD(&port_ptr->port_rx_q);
563 mutex_init(&port_ptr->port_rx_q_lock);
564 init_waitqueue_head(&port_ptr->port_rx_wait_q);
Karthikeyan Ramasubramanianb4aeeb92012-03-13 12:31:43 -0600565 snprintf(port_ptr->rx_wakelock_name, MAX_WAKELOCK_NAME_SZ,
Karthikeyan Ramasubramanian090486e2013-02-14 13:53:20 -0700566 "ipc%08x_%s",
567 port_ptr->this_port.port_id,
568 current->comm);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700569 wake_lock_init(&port_ptr->port_rx_wake_lock,
Karthikeyan Ramasubramanianb4aeeb92012-03-13 12:31:43 -0600570 WAKE_LOCK_SUSPEND, port_ptr->rx_wakelock_name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700571
572 port_ptr->endpoint = endpoint;
573 port_ptr->notify = notify;
574 port_ptr->priv = priv;
575
576 msm_ipc_router_add_local_port(port_ptr);
577 return port_ptr;
578}
579
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -0600580/*
581 * Should be called with local_ports_lock locked
582 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700583static struct msm_ipc_port *msm_ipc_router_lookup_local_port(uint32_t port_id)
584{
585 int key = (port_id & (LP_HASH_SIZE - 1));
586 struct msm_ipc_port *port_ptr;
587
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700588 list_for_each_entry(port_ptr, &local_ports[key], list) {
589 if (port_ptr->this_port.port_id == port_id) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700590 return port_ptr;
591 }
592 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700593 return NULL;
594}
595
596static struct msm_ipc_router_remote_port *msm_ipc_router_lookup_remote_port(
597 uint32_t node_id,
598 uint32_t port_id)
599{
600 struct msm_ipc_router_remote_port *rport_ptr;
601 struct msm_ipc_routing_table_entry *rt_entry;
602 int key = (port_id & (RP_HASH_SIZE - 1));
603
604 mutex_lock(&routing_table_lock);
605 rt_entry = lookup_routing_table(node_id);
606 if (!rt_entry) {
607 mutex_unlock(&routing_table_lock);
608 pr_err("%s: Node is not up\n", __func__);
609 return NULL;
610 }
611
612 mutex_lock(&rt_entry->lock);
613 list_for_each_entry(rport_ptr,
614 &rt_entry->remote_port_list[key], list) {
615 if (rport_ptr->port_id == port_id) {
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600616 if (rport_ptr->restart_state != RESTART_NORMAL)
617 rport_ptr = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700618 mutex_unlock(&rt_entry->lock);
619 mutex_unlock(&routing_table_lock);
620 return rport_ptr;
621 }
622 }
623 mutex_unlock(&rt_entry->lock);
624 mutex_unlock(&routing_table_lock);
625 return NULL;
626}
627
628static struct msm_ipc_router_remote_port *msm_ipc_router_create_remote_port(
629 uint32_t node_id,
630 uint32_t port_id)
631{
632 struct msm_ipc_router_remote_port *rport_ptr;
633 struct msm_ipc_routing_table_entry *rt_entry;
634 int key = (port_id & (RP_HASH_SIZE - 1));
635
636 mutex_lock(&routing_table_lock);
637 rt_entry = lookup_routing_table(node_id);
638 if (!rt_entry) {
639 mutex_unlock(&routing_table_lock);
640 pr_err("%s: Node is not up\n", __func__);
641 return NULL;
642 }
643
644 mutex_lock(&rt_entry->lock);
645 rport_ptr = kmalloc(sizeof(struct msm_ipc_router_remote_port),
646 GFP_KERNEL);
647 if (!rport_ptr) {
648 mutex_unlock(&rt_entry->lock);
649 mutex_unlock(&routing_table_lock);
650 pr_err("%s: Remote port alloc failed\n", __func__);
651 return NULL;
652 }
653 rport_ptr->port_id = port_id;
654 rport_ptr->node_id = node_id;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600655 rport_ptr->restart_state = RESTART_NORMAL;
Karthikeyan Ramasubramanian1668cc62012-09-23 22:23:36 -0600656 rport_ptr->sec_rule = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700657 rport_ptr->tx_quota_cnt = 0;
658 init_waitqueue_head(&rport_ptr->quota_wait);
659 mutex_init(&rport_ptr->quota_lock);
660 list_add_tail(&rport_ptr->list,
661 &rt_entry->remote_port_list[key]);
662 mutex_unlock(&rt_entry->lock);
663 mutex_unlock(&routing_table_lock);
664 return rport_ptr;
665}
666
667static void msm_ipc_router_destroy_remote_port(
668 struct msm_ipc_router_remote_port *rport_ptr)
669{
670 uint32_t node_id;
671 struct msm_ipc_routing_table_entry *rt_entry;
672
673 if (!rport_ptr)
674 return;
675
676 node_id = rport_ptr->node_id;
677 mutex_lock(&routing_table_lock);
678 rt_entry = lookup_routing_table(node_id);
679 if (!rt_entry) {
680 mutex_unlock(&routing_table_lock);
681 pr_err("%s: Node %d is not up\n", __func__, node_id);
682 return;
683 }
684
685 mutex_lock(&rt_entry->lock);
686 list_del(&rport_ptr->list);
687 kfree(rport_ptr);
688 mutex_unlock(&rt_entry->lock);
689 mutex_unlock(&routing_table_lock);
690 return;
691}
692
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -0600693/**
694 * msm_ipc_router_lookup_server() - Lookup server information
695 * @service: Service ID of the server info to be looked up.
696 * @instance: Instance ID of the server info to be looked up.
697 * @node_id: Node/Processor ID in which the server is hosted.
698 * @port_id: Port ID within the node in which the server is hosted.
699 *
700 * @return: If found Pointer to server structure, else NULL.
701 *
702 * Note1: Lock the server_list_lock before accessing this function.
703 * Note2: If the <node_id:port_id> are <0:0>, then the lookup is restricted
704 * to <service:instance>. Used only when a client wants to send a
705 * message to any QMI server.
706 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700707static struct msm_ipc_server *msm_ipc_router_lookup_server(
708 uint32_t service,
709 uint32_t instance,
710 uint32_t node_id,
711 uint32_t port_id)
712{
713 struct msm_ipc_server *server;
714 struct msm_ipc_server_port *server_port;
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -0600715 int key = (service & (SRV_HASH_SIZE - 1));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700716
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700717 list_for_each_entry(server, &server_list[key], list) {
718 if ((server->name.service != service) ||
719 (server->name.instance != instance))
720 continue;
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -0600721 if ((node_id == 0) && (port_id == 0))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700722 return server;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700723 list_for_each_entry(server_port, &server->server_port_list,
724 list) {
725 if ((server_port->server_addr.node_id == node_id) &&
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -0600726 (server_port->server_addr.port_id == port_id))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700727 return server;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700728 }
729 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700730 return NULL;
731}
732
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -0600733static void dummy_release(struct device *dev)
734{
735}
736
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -0600737/**
738 * msm_ipc_router_create_server() - Add server info to hash table
739 * @service: Service ID of the server info to be created.
740 * @instance: Instance ID of the server info to be created.
741 * @node_id: Node/Processor ID in which the server is hosted.
742 * @port_id: Port ID within the node in which the server is hosted.
743 * @xprt_info: XPRT through which the node hosting the server is reached.
744 *
745 * @return: Pointer to server structure on success, else NULL.
746 *
747 * This function adds the server info to the hash table. If the same
748 * server(i.e. <service_id:instance_id>) is hosted in different nodes,
749 * they are maintained as list of "server_port" under "server" structure.
750 * Note: Lock the server_list_lock before accessing this function.
751 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700752static struct msm_ipc_server *msm_ipc_router_create_server(
753 uint32_t service,
754 uint32_t instance,
755 uint32_t node_id,
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600756 uint32_t port_id,
757 struct msm_ipc_router_xprt_info *xprt_info)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700758{
759 struct msm_ipc_server *server = NULL;
760 struct msm_ipc_server_port *server_port;
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -0600761 int key = (service & (SRV_HASH_SIZE - 1));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700762
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700763 list_for_each_entry(server, &server_list[key], list) {
764 if ((server->name.service == service) &&
765 (server->name.instance == instance))
766 goto create_srv_port;
767 }
768
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -0600769 server = kzalloc(sizeof(struct msm_ipc_server), GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700770 if (!server) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700771 pr_err("%s: Server allocation failed\n", __func__);
772 return NULL;
773 }
774 server->name.service = service;
775 server->name.instance = instance;
Karthikeyan Ramasubramanian1668cc62012-09-23 22:23:36 -0600776 server->synced_sec_rule = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700777 INIT_LIST_HEAD(&server->server_port_list);
778 list_add_tail(&server->list, &server_list[key]);
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -0600779 scnprintf(server->pdev_name, sizeof(server->pdev_name),
780 "QMI%08x:%08x", service, instance);
781 server->next_pdev_id = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700782
783create_srv_port:
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -0600784 server_port = kzalloc(sizeof(struct msm_ipc_server_port), GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700785 if (!server_port) {
786 if (list_empty(&server->server_port_list)) {
787 list_del(&server->list);
788 kfree(server);
789 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700790 pr_err("%s: Server Port allocation failed\n", __func__);
791 return NULL;
792 }
793 server_port->server_addr.node_id = node_id;
794 server_port->server_addr.port_id = port_id;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600795 server_port->xprt_info = xprt_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700796 list_add_tail(&server_port->list, &server->server_port_list);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700797
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -0600798 server_port->pdev.name = server->pdev_name;
799 server_port->pdev.id = server->next_pdev_id++;
800 server_port->pdev.dev.release = dummy_release;
801 platform_device_register(&server_port->pdev);
802
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700803 return server;
804}
805
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -0600806/**
807 * msm_ipc_router_destroy_server() - Remove server info from hash table
808 * @server: Server info to be removed.
809 * @node_id: Node/Processor ID in which the server is hosted.
810 * @port_id: Port ID within the node in which the server is hosted.
811 *
812 * This function removes the server_port identified using <node_id:port_id>
813 * from the server structure. If the server_port list under server structure
814 * is empty after removal, then remove the server structure from the server
815 * hash table.
816 * Note: Lock the server_list_lock before accessing this function.
817 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700818static void msm_ipc_router_destroy_server(struct msm_ipc_server *server,
819 uint32_t node_id, uint32_t port_id)
820{
821 struct msm_ipc_server_port *server_port;
822
823 if (!server)
824 return;
825
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700826 list_for_each_entry(server_port, &server->server_port_list, list) {
827 if ((server_port->server_addr.node_id == node_id) &&
828 (server_port->server_addr.port_id == port_id))
829 break;
830 }
831 if (server_port) {
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -0600832 platform_device_unregister(&server_port->pdev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700833 list_del(&server_port->list);
834 kfree(server_port);
835 }
836 if (list_empty(&server->server_port_list)) {
837 list_del(&server->list);
838 kfree(server);
839 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700840 return;
841}
842
843static int msm_ipc_router_send_control_msg(
844 struct msm_ipc_router_xprt_info *xprt_info,
845 union rr_control_msg *msg)
846{
847 struct rr_packet *pkt;
848 struct sk_buff *ipc_rtr_pkt;
849 struct rr_header *hdr;
850 int pkt_size;
851 void *data;
852 struct sk_buff_head *pkt_fragment_q;
853 int ret;
854
855 if (!xprt_info || ((msg->cmd != IPC_ROUTER_CTRL_CMD_HELLO) &&
856 !xprt_info->initialized)) {
857 pr_err("%s: xprt_info not initialized\n", __func__);
858 return -EINVAL;
859 }
860
861 if (xprt_info->remote_node_id == IPC_ROUTER_NID_LOCAL)
862 return 0;
863
864 pkt = kzalloc(sizeof(struct rr_packet), GFP_KERNEL);
865 if (!pkt) {
866 pr_err("%s: pkt alloc failed\n", __func__);
867 return -ENOMEM;
868 }
869
870 pkt_fragment_q = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
871 if (!pkt_fragment_q) {
872 pr_err("%s: pkt_fragment_q alloc failed\n", __func__);
873 kfree(pkt);
874 return -ENOMEM;
875 }
876 skb_queue_head_init(pkt_fragment_q);
877
878 pkt_size = IPC_ROUTER_HDR_SIZE + sizeof(*msg);
879 ipc_rtr_pkt = alloc_skb(pkt_size, GFP_KERNEL);
880 if (!ipc_rtr_pkt) {
881 pr_err("%s: ipc_rtr_pkt alloc failed\n", __func__);
882 kfree(pkt_fragment_q);
883 kfree(pkt);
884 return -ENOMEM;
885 }
886
887 skb_reserve(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
888 data = skb_put(ipc_rtr_pkt, sizeof(*msg));
889 memcpy(data, msg, sizeof(*msg));
890 hdr = (struct rr_header *)skb_push(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
891 if (!hdr) {
892 pr_err("%s: skb_push failed\n", __func__);
893 kfree_skb(ipc_rtr_pkt);
894 kfree(pkt_fragment_q);
895 kfree(pkt);
896 return -ENOMEM;
897 }
898
899 hdr->version = IPC_ROUTER_VERSION;
900 hdr->type = msg->cmd;
901 hdr->src_node_id = IPC_ROUTER_NID_LOCAL;
902 hdr->src_port_id = IPC_ROUTER_ADDRESS;
903 hdr->confirm_rx = 0;
904 hdr->size = sizeof(*msg);
905 hdr->dst_node_id = xprt_info->remote_node_id;
906 hdr->dst_port_id = IPC_ROUTER_ADDRESS;
907 skb_queue_tail(pkt_fragment_q, ipc_rtr_pkt);
908 pkt->pkt_fragment_q = pkt_fragment_q;
909 pkt->length = pkt_size;
910
911 mutex_lock(&xprt_info->tx_lock);
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700912 ret = xprt_info->xprt->write(pkt, pkt_size, xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700913 mutex_unlock(&xprt_info->tx_lock);
914
915 release_pkt(pkt);
916 return ret;
917}
918
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -0600919static int msm_ipc_router_send_server_list(uint32_t node_id,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700920 struct msm_ipc_router_xprt_info *xprt_info)
921{
922 union rr_control_msg ctl;
923 struct msm_ipc_server *server;
924 struct msm_ipc_server_port *server_port;
925 int i;
926
927 if (!xprt_info || !xprt_info->initialized) {
928 pr_err("%s: Xprt info not initialized\n", __func__);
929 return -EINVAL;
930 }
931
932 ctl.cmd = IPC_ROUTER_CTRL_CMD_NEW_SERVER;
933
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700934 for (i = 0; i < SRV_HASH_SIZE; i++) {
935 list_for_each_entry(server, &server_list[i], list) {
936 ctl.srv.service = server->name.service;
937 ctl.srv.instance = server->name.instance;
938 list_for_each_entry(server_port,
939 &server->server_port_list, list) {
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -0600940 if (server_port->server_addr.node_id !=
941 node_id)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700942 continue;
943
944 ctl.srv.node_id =
945 server_port->server_addr.node_id;
946 ctl.srv.port_id =
947 server_port->server_addr.port_id;
948 msm_ipc_router_send_control_msg(xprt_info,
949 &ctl);
950 }
951 }
952 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700953
954 return 0;
955}
956
957#if defined(DEBUG)
958static char *type_to_str(int i)
959{
960 switch (i) {
961 case IPC_ROUTER_CTRL_CMD_DATA:
962 return "data ";
963 case IPC_ROUTER_CTRL_CMD_HELLO:
964 return "hello ";
965 case IPC_ROUTER_CTRL_CMD_BYE:
966 return "bye ";
967 case IPC_ROUTER_CTRL_CMD_NEW_SERVER:
968 return "new_srvr";
969 case IPC_ROUTER_CTRL_CMD_REMOVE_SERVER:
970 return "rmv_srvr";
971 case IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT:
972 return "rmv_clnt";
973 case IPC_ROUTER_CTRL_CMD_RESUME_TX:
974 return "resum_tx";
975 case IPC_ROUTER_CTRL_CMD_EXIT:
976 return "cmd_exit";
977 default:
978 return "invalid";
979 }
980}
981#endif
982
983static int broadcast_ctl_msg_locally(union rr_control_msg *msg)
984{
985 struct rr_packet *pkt;
986 struct sk_buff *ipc_rtr_pkt;
987 struct rr_header *hdr;
988 int pkt_size;
989 void *data;
990 struct sk_buff_head *pkt_fragment_q;
991 int ret;
992
993 pkt = kzalloc(sizeof(struct rr_packet), GFP_KERNEL);
994 if (!pkt) {
995 pr_err("%s: pkt alloc failed\n", __func__);
996 return -ENOMEM;
997 }
998
999 pkt_fragment_q = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
1000 if (!pkt_fragment_q) {
1001 pr_err("%s: pkt_fragment_q alloc failed\n", __func__);
1002 kfree(pkt);
1003 return -ENOMEM;
1004 }
1005 skb_queue_head_init(pkt_fragment_q);
1006
1007 pkt_size = IPC_ROUTER_HDR_SIZE + sizeof(*msg);
1008 ipc_rtr_pkt = alloc_skb(pkt_size, GFP_KERNEL);
1009 if (!ipc_rtr_pkt) {
1010 pr_err("%s: ipc_rtr_pkt alloc failed\n", __func__);
1011 kfree(pkt_fragment_q);
1012 kfree(pkt);
1013 return -ENOMEM;
1014 }
1015
1016 skb_reserve(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
1017 data = skb_put(ipc_rtr_pkt, sizeof(*msg));
1018 memcpy(data, msg, sizeof(*msg));
1019 hdr = (struct rr_header *)skb_push(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
1020 if (!hdr) {
1021 pr_err("%s: skb_push failed\n", __func__);
1022 kfree_skb(ipc_rtr_pkt);
1023 kfree(pkt_fragment_q);
1024 kfree(pkt);
1025 return -ENOMEM;
1026 }
1027 hdr->version = IPC_ROUTER_VERSION;
1028 hdr->type = msg->cmd;
1029 hdr->src_node_id = IPC_ROUTER_NID_LOCAL;
1030 hdr->src_port_id = IPC_ROUTER_ADDRESS;
1031 hdr->confirm_rx = 0;
1032 hdr->size = sizeof(*msg);
1033 hdr->dst_node_id = IPC_ROUTER_NID_LOCAL;
1034 hdr->dst_port_id = IPC_ROUTER_ADDRESS;
1035 skb_queue_tail(pkt_fragment_q, ipc_rtr_pkt);
1036 pkt->pkt_fragment_q = pkt_fragment_q;
1037 pkt->length = pkt_size;
1038
1039 ret = post_control_ports(pkt);
1040 release_pkt(pkt);
1041 return ret;
1042}
1043
1044static int broadcast_ctl_msg(union rr_control_msg *ctl)
1045{
1046 struct msm_ipc_router_xprt_info *xprt_info;
1047
1048 mutex_lock(&xprt_info_list_lock);
1049 list_for_each_entry(xprt_info, &xprt_info_list, list) {
1050 msm_ipc_router_send_control_msg(xprt_info, ctl);
1051 }
1052 mutex_unlock(&xprt_info_list_lock);
1053
1054 return 0;
1055}
1056
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001057static int relay_ctl_msg(struct msm_ipc_router_xprt_info *xprt_info,
1058 union rr_control_msg *ctl)
1059{
1060 struct msm_ipc_router_xprt_info *fwd_xprt_info;
1061
1062 if (!xprt_info || !ctl)
1063 return -EINVAL;
1064
1065 mutex_lock(&xprt_info_list_lock);
1066 list_for_each_entry(fwd_xprt_info, &xprt_info_list, list) {
1067 if (xprt_info->xprt->link_id != fwd_xprt_info->xprt->link_id)
1068 msm_ipc_router_send_control_msg(fwd_xprt_info, ctl);
1069 }
1070 mutex_unlock(&xprt_info_list_lock);
1071
1072 return 0;
1073}
1074
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001075static int relay_msg(struct msm_ipc_router_xprt_info *xprt_info,
1076 struct rr_packet *pkt)
1077{
1078 struct msm_ipc_router_xprt_info *fwd_xprt_info;
1079
1080 if (!xprt_info || !pkt)
1081 return -EINVAL;
1082
1083 mutex_lock(&xprt_info_list_lock);
1084 list_for_each_entry(fwd_xprt_info, &xprt_info_list, list) {
1085 mutex_lock(&fwd_xprt_info->tx_lock);
1086 if (xprt_info->xprt->link_id != fwd_xprt_info->xprt->link_id)
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -07001087 fwd_xprt_info->xprt->write(pkt, pkt->length,
1088 fwd_xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001089 mutex_unlock(&fwd_xprt_info->tx_lock);
1090 }
1091 mutex_unlock(&xprt_info_list_lock);
1092 return 0;
1093}
1094
1095static int forward_msg(struct msm_ipc_router_xprt_info *xprt_info,
1096 struct rr_packet *pkt)
1097{
1098 uint32_t dst_node_id;
1099 struct sk_buff *head_pkt;
1100 struct rr_header *hdr;
1101 struct msm_ipc_router_xprt_info *fwd_xprt_info;
1102 struct msm_ipc_routing_table_entry *rt_entry;
1103
1104 if (!xprt_info || !pkt)
1105 return -EINVAL;
1106
1107 head_pkt = skb_peek(pkt->pkt_fragment_q);
1108 if (!head_pkt)
1109 return -EINVAL;
1110
1111 hdr = (struct rr_header *)head_pkt->data;
1112 dst_node_id = hdr->dst_node_id;
1113 mutex_lock(&routing_table_lock);
1114 rt_entry = lookup_routing_table(dst_node_id);
1115 if (!(rt_entry) || !(rt_entry->xprt_info)) {
1116 mutex_unlock(&routing_table_lock);
1117 pr_err("%s: Routing table not initialized\n", __func__);
1118 return -ENODEV;
1119 }
1120
1121 mutex_lock(&rt_entry->lock);
1122 fwd_xprt_info = rt_entry->xprt_info;
1123 mutex_lock(&fwd_xprt_info->tx_lock);
1124 if (xprt_info->remote_node_id == fwd_xprt_info->remote_node_id) {
1125 mutex_unlock(&fwd_xprt_info->tx_lock);
1126 mutex_unlock(&rt_entry->lock);
1127 mutex_unlock(&routing_table_lock);
1128 pr_err("%s: Discarding Command to route back\n", __func__);
1129 return -EINVAL;
1130 }
1131
1132 if (xprt_info->xprt->link_id == fwd_xprt_info->xprt->link_id) {
1133 mutex_unlock(&fwd_xprt_info->tx_lock);
1134 mutex_unlock(&rt_entry->lock);
1135 mutex_unlock(&routing_table_lock);
1136 pr_err("%s: DST in the same cluster\n", __func__);
1137 return 0;
1138 }
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -07001139 fwd_xprt_info->xprt->write(pkt, pkt->length, fwd_xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001140 mutex_unlock(&fwd_xprt_info->tx_lock);
1141 mutex_unlock(&rt_entry->lock);
1142 mutex_unlock(&routing_table_lock);
1143
1144 return 0;
1145}
1146
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001147static void reset_remote_port_info(uint32_t node_id, uint32_t port_id)
1148{
1149 struct msm_ipc_router_remote_port *rport_ptr;
1150
1151 rport_ptr = msm_ipc_router_lookup_remote_port(node_id, port_id);
1152 if (!rport_ptr) {
1153 pr_err("%s: No such remote port %08x:%08x\n",
1154 __func__, node_id, port_id);
1155 return;
1156 }
1157 mutex_lock(&rport_ptr->quota_lock);
1158 rport_ptr->restart_state = RESTART_PEND;
1159 wake_up(&rport_ptr->quota_wait);
1160 mutex_unlock(&rport_ptr->quota_lock);
1161 return;
1162}
1163
1164static void msm_ipc_cleanup_remote_server_info(
1165 struct msm_ipc_router_xprt_info *xprt_info)
1166{
1167 struct msm_ipc_server *svr, *tmp_svr;
1168 struct msm_ipc_server_port *svr_port, *tmp_svr_port;
1169 int i;
1170 union rr_control_msg ctl;
1171
1172 if (!xprt_info) {
1173 pr_err("%s: Invalid xprt_info\n", __func__);
1174 return;
1175 }
1176
1177 ctl.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_SERVER;
1178 mutex_lock(&server_list_lock);
1179 for (i = 0; i < SRV_HASH_SIZE; i++) {
1180 list_for_each_entry_safe(svr, tmp_svr, &server_list[i], list) {
1181 ctl.srv.service = svr->name.service;
1182 ctl.srv.instance = svr->name.instance;
1183 list_for_each_entry_safe(svr_port, tmp_svr_port,
1184 &svr->server_port_list, list) {
1185 if (svr_port->xprt_info != xprt_info)
1186 continue;
1187 D("Remove server %08x:%08x - %08x:%08x",
1188 ctl.srv.service, ctl.srv.instance,
1189 svr_port->server_addr.node_id,
1190 svr_port->server_addr.port_id);
1191 reset_remote_port_info(
1192 svr_port->server_addr.node_id,
1193 svr_port->server_addr.port_id);
1194 ctl.srv.node_id = svr_port->server_addr.node_id;
1195 ctl.srv.port_id = svr_port->server_addr.port_id;
1196 relay_ctl_msg(xprt_info, &ctl);
1197 broadcast_ctl_msg_locally(&ctl);
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -06001198 platform_device_unregister(&svr_port->pdev);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001199 list_del(&svr_port->list);
1200 kfree(svr_port);
1201 }
1202 if (list_empty(&svr->server_port_list)) {
1203 list_del(&svr->list);
1204 kfree(svr);
1205 }
1206 }
1207 }
1208 mutex_unlock(&server_list_lock);
1209}
1210
1211static void msm_ipc_cleanup_remote_client_info(
1212 struct msm_ipc_router_xprt_info *xprt_info)
1213{
1214 struct msm_ipc_routing_table_entry *rt_entry;
1215 struct msm_ipc_router_remote_port *rport_ptr;
1216 int i, j;
1217 union rr_control_msg ctl;
1218
1219 if (!xprt_info) {
1220 pr_err("%s: Invalid xprt_info\n", __func__);
1221 return;
1222 }
1223
1224 ctl.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT;
1225 mutex_lock(&routing_table_lock);
1226 for (i = 0; i < RT_HASH_SIZE; i++) {
1227 list_for_each_entry(rt_entry, &routing_table[i], list) {
1228 mutex_lock(&rt_entry->lock);
1229 if (rt_entry->xprt_info != xprt_info) {
1230 mutex_unlock(&rt_entry->lock);
1231 continue;
1232 }
1233 for (j = 0; j < RP_HASH_SIZE; j++) {
1234 list_for_each_entry(rport_ptr,
1235 &rt_entry->remote_port_list[j], list) {
1236 if (rport_ptr->restart_state ==
1237 RESTART_PEND)
1238 continue;
1239 mutex_lock(&rport_ptr->quota_lock);
1240 rport_ptr->restart_state = RESTART_PEND;
1241 wake_up(&rport_ptr->quota_wait);
1242 mutex_unlock(&rport_ptr->quota_lock);
1243 ctl.cli.node_id = rport_ptr->node_id;
1244 ctl.cli.port_id = rport_ptr->port_id;
1245 broadcast_ctl_msg_locally(&ctl);
1246 }
1247 }
1248 mutex_unlock(&rt_entry->lock);
1249 }
1250 }
1251 mutex_unlock(&routing_table_lock);
1252}
1253
1254static void msm_ipc_cleanup_remote_port_info(uint32_t node_id)
1255{
1256 struct msm_ipc_routing_table_entry *rt_entry, *tmp_rt_entry;
1257 struct msm_ipc_router_remote_port *rport_ptr, *tmp_rport_ptr;
1258 int i, j;
1259
1260 mutex_lock(&routing_table_lock);
1261 for (i = 0; i < RT_HASH_SIZE; i++) {
1262 list_for_each_entry_safe(rt_entry, tmp_rt_entry,
1263 &routing_table[i], list) {
1264 mutex_lock(&rt_entry->lock);
1265 if (rt_entry->neighbor_node_id != node_id) {
1266 mutex_unlock(&rt_entry->lock);
1267 continue;
1268 }
1269 for (j = 0; j < RP_HASH_SIZE; j++) {
1270 list_for_each_entry_safe(rport_ptr,
1271 tmp_rport_ptr,
1272 &rt_entry->remote_port_list[j], list) {
1273 list_del(&rport_ptr->list);
1274 kfree(rport_ptr);
1275 }
1276 }
1277 mutex_unlock(&rt_entry->lock);
1278 }
1279 }
1280 mutex_unlock(&routing_table_lock);
1281}
1282
1283static void msm_ipc_cleanup_routing_table(
1284 struct msm_ipc_router_xprt_info *xprt_info)
1285{
1286 int i;
1287 struct msm_ipc_routing_table_entry *rt_entry;
1288
1289 if (!xprt_info) {
1290 pr_err("%s: Invalid xprt_info\n", __func__);
1291 return;
1292 }
1293
1294 mutex_lock(&routing_table_lock);
1295 for (i = 0; i < RT_HASH_SIZE; i++) {
1296 list_for_each_entry(rt_entry, &routing_table[i], list) {
1297 mutex_lock(&rt_entry->lock);
1298 if (rt_entry->xprt_info == xprt_info)
1299 rt_entry->xprt_info = NULL;
1300 mutex_unlock(&rt_entry->lock);
1301 }
1302 }
1303 mutex_unlock(&routing_table_lock);
1304}
1305
1306static void modem_reset_cleanup(struct msm_ipc_router_xprt_info *xprt_info)
1307{
1308
1309 if (!xprt_info) {
1310 pr_err("%s: Invalid xprt_info\n", __func__);
1311 return;
1312 }
1313
1314 msm_ipc_cleanup_remote_server_info(xprt_info);
1315 msm_ipc_cleanup_remote_client_info(xprt_info);
1316 msm_ipc_cleanup_routing_table(xprt_info);
1317}
1318
Karthikeyan Ramasubramanian1668cc62012-09-23 22:23:36 -06001319/**
1320 * sync_sec_rule() - Synchrnoize the security rule into the server structure
1321 * @server: Server structure where the rule has to be synchronized.
1322 * @rule: Security tule to be synchronized.
1323 *
1324 * This function is used to update the server structure with the security
1325 * rule configured for the <service:instance> corresponding to that server.
1326 */
1327static void sync_sec_rule(struct msm_ipc_server *server, void *rule)
1328{
1329 struct msm_ipc_server_port *server_port;
1330 struct msm_ipc_router_remote_port *rport_ptr = NULL;
1331
1332 list_for_each_entry(server_port, &server->server_port_list, list) {
1333 rport_ptr = msm_ipc_router_lookup_remote_port(
1334 server_port->server_addr.node_id,
1335 server_port->server_addr.port_id);
1336 if (!rport_ptr)
1337 continue;
1338 rport_ptr->sec_rule = rule;
1339 }
1340 server->synced_sec_rule = 1;
1341}
1342
1343/**
1344 * msm_ipc_sync_sec_rule() - Sync the security rule to the service
1345 * @service: Service for which the rule has to be synchronized.
1346 * @instance: Instance for which the rule has to be synchronized.
1347 * @rule: Security rule to be synchronized.
1348 *
1349 * This function is used to syncrhonize the security rule with the server
1350 * hash table, if the user-space script configures the rule after the service
1351 * has come up. This function is used to synchronize the security rule to a
1352 * specific service and optionally a specific instance.
1353 */
1354void msm_ipc_sync_sec_rule(uint32_t service, uint32_t instance, void *rule)
1355{
1356 int key = (service & (SRV_HASH_SIZE - 1));
1357 struct msm_ipc_server *server;
1358
1359 mutex_lock(&server_list_lock);
1360 list_for_each_entry(server, &server_list[key], list) {
1361 if (server->name.service != service)
1362 continue;
1363
1364 if (server->name.instance != instance &&
1365 instance != ALL_INSTANCE)
1366 continue;
1367
1368 /*
1369 * If the rule applies to all instances and if the specific
1370 * instance of a service has a rule synchronized already,
1371 * do not apply the rule for that specific instance.
1372 */
1373 if (instance == ALL_INSTANCE && server->synced_sec_rule)
1374 continue;
1375
1376 sync_sec_rule(server, rule);
1377 }
1378 mutex_unlock(&server_list_lock);
1379}
1380
1381/**
1382 * msm_ipc_sync_default_sec_rule() - Default security rule to all services
1383 * @rule: Security rule to be synchronized.
1384 *
1385 * This function is used to syncrhonize the security rule with the server
1386 * hash table, if the user-space script configures the rule after the service
1387 * has come up. This function is used to synchronize the security rule that
1388 * applies to all services, if the concerned service do not have any rule
1389 * defined.
1390 */
1391void msm_ipc_sync_default_sec_rule(void *rule)
1392{
1393 int key;
1394 struct msm_ipc_server *server;
1395
1396 mutex_lock(&server_list_lock);
1397 for (key = 0; key < SRV_HASH_SIZE; key++) {
1398 list_for_each_entry(server, &server_list[key], list) {
1399 if (server->synced_sec_rule)
1400 continue;
1401
1402 sync_sec_rule(server, rule);
1403 }
1404 }
1405 mutex_unlock(&server_list_lock);
1406}
1407
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001408static int process_hello_msg(struct msm_ipc_router_xprt_info *xprt_info,
1409 struct rr_header *hdr)
1410{
1411 int i, rc = 0;
1412 union rr_control_msg ctl;
1413 struct msm_ipc_routing_table_entry *rt_entry;
1414
1415 if (!hdr)
1416 return -EINVAL;
1417
1418 RR("o HELLO NID %d\n", hdr->src_node_id);
1419
1420 xprt_info->remote_node_id = hdr->src_node_id;
1421 /*
1422 * Find the entry from Routing Table corresponding to Node ID.
1423 * Under SSR, an entry will be found. When the system boots up
1424 * for the 1st time, an entry will not be found and hence allocate
1425 * an entry. Update the entry with the Node ID that it corresponds
1426 * to and the XPRT through which it can be reached.
1427 */
1428 mutex_lock(&routing_table_lock);
1429 rt_entry = lookup_routing_table(hdr->src_node_id);
1430 if (!rt_entry) {
1431 rt_entry = alloc_routing_table_entry(hdr->src_node_id);
1432 if (!rt_entry) {
1433 mutex_unlock(&routing_table_lock);
1434 pr_err("%s: rt_entry allocation failed\n", __func__);
1435 return -ENOMEM;
1436 }
1437 add_routing_table_entry(rt_entry);
1438 }
1439 mutex_lock(&rt_entry->lock);
1440 rt_entry->neighbor_node_id = xprt_info->remote_node_id;
1441 rt_entry->xprt_info = xprt_info;
1442 mutex_unlock(&rt_entry->lock);
1443 mutex_unlock(&routing_table_lock);
1444
1445 /* Cleanup any remote ports, if the node is coming out of reset */
1446 msm_ipc_cleanup_remote_port_info(xprt_info->remote_node_id);
1447
1448 /* Send a reply HELLO message */
1449 memset(&ctl, 0, sizeof(ctl));
1450 ctl.cmd = IPC_ROUTER_CTRL_CMD_HELLO;
1451 rc = msm_ipc_router_send_control_msg(xprt_info, &ctl);
1452 if (rc < 0) {
1453 pr_err("%s: Error sending reply HELLO message\n", __func__);
1454 return rc;
1455 }
1456 xprt_info->initialized = 1;
1457
1458 /*
1459 * Send list of servers from the local node and from nodes
1460 * outside the mesh network in which this XPRT is part of.
1461 */
Karthikeyan Ramasubramaniane8ad5352012-10-31 15:12:08 -06001462 mutex_lock(&server_list_lock);
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001463 mutex_lock(&routing_table_lock);
1464 for (i = 0; i < RT_HASH_SIZE; i++) {
1465 list_for_each_entry(rt_entry, &routing_table[i], list) {
1466 if ((rt_entry->node_id != IPC_ROUTER_NID_LOCAL) &&
Karthikeyan Ramasubramanian72ad5792013-01-30 14:17:57 -07001467 (!rt_entry->xprt_info ||
1468 (rt_entry->xprt_info->xprt->link_id ==
1469 xprt_info->xprt->link_id)))
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001470 continue;
1471 rc = msm_ipc_router_send_server_list(rt_entry->node_id,
1472 xprt_info);
1473 if (rc < 0) {
1474 mutex_unlock(&routing_table_lock);
Karthikeyan Ramasubramaniane8ad5352012-10-31 15:12:08 -06001475 mutex_unlock(&server_list_lock);
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001476 return rc;
1477 }
1478 }
1479 }
1480 mutex_unlock(&routing_table_lock);
Karthikeyan Ramasubramaniane8ad5352012-10-31 15:12:08 -06001481 mutex_unlock(&server_list_lock);
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001482 RR("HELLO message processed\n");
1483 return rc;
1484}
1485
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001486static int process_control_msg(struct msm_ipc_router_xprt_info *xprt_info,
1487 struct rr_packet *pkt)
1488{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001489 union rr_control_msg *msg;
1490 struct msm_ipc_router_remote_port *rport_ptr;
1491 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001492 struct sk_buff *temp_ptr;
1493 struct rr_header *hdr;
1494 struct msm_ipc_server *server;
1495 struct msm_ipc_routing_table_entry *rt_entry;
1496
1497 if (pkt->length != (IPC_ROUTER_HDR_SIZE + sizeof(*msg))) {
1498 pr_err("%s: r2r msg size %d != %d\n", __func__, pkt->length,
1499 (IPC_ROUTER_HDR_SIZE + sizeof(*msg)));
1500 return -EINVAL;
1501 }
1502
1503 temp_ptr = skb_peek(pkt->pkt_fragment_q);
Karthikeyan Ramasubramanian9024dd82011-12-19 18:44:19 -07001504 if (!temp_ptr) {
1505 pr_err("%s: pkt_fragment_q is empty\n", __func__);
1506 return -EINVAL;
1507 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001508 hdr = (struct rr_header *)temp_ptr->data;
Karthikeyan Ramasubramanian9024dd82011-12-19 18:44:19 -07001509 if (!hdr) {
1510 pr_err("%s: No data inside the skb\n", __func__);
1511 return -EINVAL;
1512 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001513 msg = (union rr_control_msg *)((char *)hdr + IPC_ROUTER_HDR_SIZE);
1514
1515 switch (msg->cmd) {
1516 case IPC_ROUTER_CTRL_CMD_HELLO:
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001517 rc = process_hello_msg(xprt_info, hdr);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001518 break;
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001519
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001520 case IPC_ROUTER_CTRL_CMD_RESUME_TX:
1521 RR("o RESUME_TX id=%d:%08x\n",
1522 msg->cli.node_id, msg->cli.port_id);
1523
1524 rport_ptr = msm_ipc_router_lookup_remote_port(msg->cli.node_id,
1525 msg->cli.port_id);
1526 if (!rport_ptr) {
1527 pr_err("%s: Unable to resume client\n", __func__);
1528 break;
1529 }
1530 mutex_lock(&rport_ptr->quota_lock);
1531 rport_ptr->tx_quota_cnt = 0;
1532 mutex_unlock(&rport_ptr->quota_lock);
1533 wake_up(&rport_ptr->quota_wait);
1534 break;
1535
1536 case IPC_ROUTER_CTRL_CMD_NEW_SERVER:
1537 if (msg->srv.instance == 0) {
1538 pr_err(
1539 "rpcrouter: Server create rejected, version = 0, "
1540 "service = %08x\n", msg->srv.service);
1541 break;
1542 }
1543
1544 RR("o NEW_SERVER id=%d:%08x service=%08x:%08x\n",
1545 msg->srv.node_id, msg->srv.port_id,
1546 msg->srv.service, msg->srv.instance);
1547
1548 mutex_lock(&routing_table_lock);
1549 rt_entry = lookup_routing_table(msg->srv.node_id);
1550 if (!rt_entry) {
1551 rt_entry = alloc_routing_table_entry(msg->srv.node_id);
1552 if (!rt_entry) {
1553 mutex_unlock(&routing_table_lock);
1554 pr_err("%s: rt_entry allocation failed\n",
1555 __func__);
1556 return -ENOMEM;
1557 }
1558 mutex_lock(&rt_entry->lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001559 rt_entry->neighbor_node_id = xprt_info->remote_node_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001560 rt_entry->xprt_info = xprt_info;
1561 mutex_unlock(&rt_entry->lock);
1562 add_routing_table_entry(rt_entry);
1563 }
1564 mutex_unlock(&routing_table_lock);
1565
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001566 mutex_lock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001567 server = msm_ipc_router_lookup_server(msg->srv.service,
1568 msg->srv.instance,
1569 msg->srv.node_id,
1570 msg->srv.port_id);
1571 if (!server) {
1572 server = msm_ipc_router_create_server(
1573 msg->srv.service, msg->srv.instance,
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001574 msg->srv.node_id, msg->srv.port_id, xprt_info);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001575 if (!server) {
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001576 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001577 pr_err("%s: Server Create failed\n", __func__);
1578 return -ENOMEM;
1579 }
1580
1581 if (!msm_ipc_router_lookup_remote_port(
1582 msg->srv.node_id, msg->srv.port_id)) {
1583 rport_ptr = msm_ipc_router_create_remote_port(
1584 msg->srv.node_id, msg->srv.port_id);
1585 if (!rport_ptr)
1586 pr_err("%s: Remote port create "
1587 "failed\n", __func__);
Brent Hronik0e83d3b2013-05-01 16:25:00 -06001588 else
1589 rport_ptr->sec_rule =
1590 msm_ipc_get_security_rule(
1591 msg->srv.service,
1592 msg->srv.instance);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001593 }
1594 wake_up(&newserver_wait);
1595 }
Karthikeyan Ramasubramaniana85d09f2012-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 Ramasubramaniana85d09f2012-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 Ramasubramaniana85d09f2012-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 Ramasubramanian682ebcc2013-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 Ramasubramanian70444192012-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 Ramasubramanian70444192012-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 Ramasubramaniana85d09f2012-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 Ramasubramaniana85d09f2012-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 Ramasubramaniana85d09f2012-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 Ramasubramaniana85d09f2012-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 Ramasubramaniana85d09f2012-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 Ramasubramaniana85d09f2012-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 Ramasubramaniana85d09f2012-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 Ramasubramanian0a801c12013-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__);
Brent Hronik0e83d3b2013-05-01 16:25:00 -06001893 release_pkt(pkt);
Karthikeyan Ramasubramanian9024dd82011-12-19 18:44:19 -07001894 return -EINVAL;
1895 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001896 hdr = (struct rr_header *)skb_push(head_skb, IPC_ROUTER_HDR_SIZE);
1897 if (!hdr) {
1898 pr_err("%s: Prepend Header failed\n", __func__);
1899 release_pkt(pkt);
1900 return -ENOMEM;
1901 }
1902 hdr->version = IPC_ROUTER_VERSION;
1903 hdr->type = IPC_ROUTER_CTRL_CMD_DATA;
1904 hdr->src_node_id = src->this_port.node_id;
1905 hdr->src_port_id = src->this_port.port_id;
1906 hdr->size = pkt->length;
1907 hdr->confirm_rx = 0;
1908 hdr->dst_node_id = IPC_ROUTER_NID_LOCAL;
1909 hdr->dst_port_id = port_id;
1910 pkt->length += IPC_ROUTER_HDR_SIZE;
1911
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06001912 mutex_lock(&local_ports_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001913 port_ptr = msm_ipc_router_lookup_local_port(port_id);
1914 if (!port_ptr) {
1915 pr_err("%s: Local port %d not present\n", __func__, port_id);
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06001916 mutex_unlock(&local_ports_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001917 release_pkt(pkt);
1918 return -ENODEV;
1919 }
1920
1921 mutex_lock(&port_ptr->port_rx_q_lock);
1922 wake_lock(&port_ptr->port_rx_wake_lock);
1923 list_add_tail(&pkt->list, &port_ptr->port_rx_q);
Karthikeyan Ramasubramanian0a801c12013-02-08 13:07:42 -07001924 ret_len = pkt->length;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001925 wake_up(&port_ptr->port_rx_wait_q);
1926 mutex_unlock(&port_ptr->port_rx_q_lock);
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06001927 mutex_unlock(&local_ports_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001928
Karthikeyan Ramasubramanian0a801c12013-02-08 13:07:42 -07001929 return ret_len;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001930}
1931
1932static int msm_ipc_router_write_pkt(struct msm_ipc_port *src,
1933 struct msm_ipc_router_remote_port *rport_ptr,
1934 struct rr_packet *pkt)
1935{
1936 struct sk_buff *head_skb;
1937 struct rr_header *hdr;
1938 struct msm_ipc_router_xprt_info *xprt_info;
1939 struct msm_ipc_routing_table_entry *rt_entry;
1940 int ret;
1941 DEFINE_WAIT(__wait);
1942
1943 if (!rport_ptr || !src || !pkt)
1944 return -EINVAL;
1945
1946 head_skb = skb_peek(pkt->pkt_fragment_q);
Karthikeyan Ramasubramanian9024dd82011-12-19 18:44:19 -07001947 if (!head_skb) {
1948 pr_err("%s: pkt_fragment_q is empty\n", __func__);
1949 return -EINVAL;
1950 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001951 hdr = (struct rr_header *)skb_push(head_skb, IPC_ROUTER_HDR_SIZE);
1952 if (!hdr) {
1953 pr_err("%s: Prepend Header failed\n", __func__);
1954 return -ENOMEM;
1955 }
1956 hdr->version = IPC_ROUTER_VERSION;
1957 hdr->type = IPC_ROUTER_CTRL_CMD_DATA;
1958 hdr->src_node_id = src->this_port.node_id;
1959 hdr->src_port_id = src->this_port.port_id;
1960 hdr->size = pkt->length;
1961 hdr->confirm_rx = 0;
1962 hdr->dst_node_id = rport_ptr->node_id;
1963 hdr->dst_port_id = rport_ptr->port_id;
1964 pkt->length += IPC_ROUTER_HDR_SIZE;
1965
1966 for (;;) {
1967 prepare_to_wait(&rport_ptr->quota_wait, &__wait,
1968 TASK_INTERRUPTIBLE);
1969 mutex_lock(&rport_ptr->quota_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001970 if (rport_ptr->restart_state != RESTART_NORMAL)
1971 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001972 if (rport_ptr->tx_quota_cnt <
1973 IPC_ROUTER_DEFAULT_RX_QUOTA)
1974 break;
1975 if (signal_pending(current))
1976 break;
1977 mutex_unlock(&rport_ptr->quota_lock);
1978 schedule();
1979 }
1980 finish_wait(&rport_ptr->quota_wait, &__wait);
1981
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001982 if (rport_ptr->restart_state != RESTART_NORMAL) {
1983 mutex_unlock(&rport_ptr->quota_lock);
1984 return -ENETRESET;
1985 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001986 if (signal_pending(current)) {
1987 mutex_unlock(&rport_ptr->quota_lock);
1988 return -ERESTARTSYS;
1989 }
1990 rport_ptr->tx_quota_cnt++;
1991 if (rport_ptr->tx_quota_cnt == IPC_ROUTER_DEFAULT_RX_QUOTA)
1992 hdr->confirm_rx = 1;
1993 mutex_unlock(&rport_ptr->quota_lock);
1994
1995 mutex_lock(&routing_table_lock);
1996 rt_entry = lookup_routing_table(hdr->dst_node_id);
1997 if (!rt_entry || !rt_entry->xprt_info) {
1998 mutex_unlock(&routing_table_lock);
1999 pr_err("%s: Remote node %d not up\n",
2000 __func__, hdr->dst_node_id);
2001 return -ENODEV;
2002 }
2003 mutex_lock(&rt_entry->lock);
2004 xprt_info = rt_entry->xprt_info;
2005 mutex_lock(&xprt_info->tx_lock);
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -07002006 ret = xprt_info->xprt->write(pkt, pkt->length, xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002007 mutex_unlock(&xprt_info->tx_lock);
2008 mutex_unlock(&rt_entry->lock);
2009 mutex_unlock(&routing_table_lock);
2010
2011 if (ret < 0) {
2012 pr_err("%s: Write on XPRT failed\n", __func__);
2013 return ret;
2014 }
2015
2016 RAW_HDR("[w rr_h] "
2017 "ver=%i,type=%s,src_nid=%08x,src_port_id=%08x,"
2018 "confirm_rx=%i,size=%3i,dst_pid=%08x,dst_cid=%08x\n",
2019 hdr->version, type_to_str(hdr->type),
2020 hdr->src_node_id, hdr->src_port_id,
2021 hdr->confirm_rx, hdr->size,
2022 hdr->dst_node_id, hdr->dst_port_id);
2023
2024#if defined(CONFIG_MSM_SMD_LOGGING)
2025#if defined(DEBUG)
2026 if (msm_ipc_router_debug_mask & SMEM_LOG) {
2027 smem_log_event((SMEM_LOG_PROC_ID_APPS |
2028 SMEM_LOG_RPC_ROUTER_EVENT_BASE |
2029 IPC_ROUTER_LOG_EVENT_TX),
2030 (hdr->src_node_id << 24) |
2031 (hdr->src_port_id & 0xffffff),
2032 (hdr->dst_node_id << 24) |
2033 (hdr->dst_port_id & 0xffffff),
2034 (hdr->type << 24) | (hdr->confirm_rx << 16) |
2035 (hdr->size & 0xffff));
2036 }
2037#endif
2038#endif
2039
2040 return pkt->length;
2041}
2042
2043int msm_ipc_router_send_to(struct msm_ipc_port *src,
2044 struct sk_buff_head *data,
2045 struct msm_ipc_addr *dest)
2046{
2047 uint32_t dst_node_id = 0, dst_port_id = 0;
2048 struct msm_ipc_server *server;
2049 struct msm_ipc_server_port *server_port;
2050 struct msm_ipc_router_remote_port *rport_ptr = NULL;
2051 struct rr_packet *pkt;
2052 int ret;
2053
2054 if (!src || !data || !dest) {
2055 pr_err("%s: Invalid Parameters\n", __func__);
2056 return -EINVAL;
2057 }
2058
2059 /* Resolve Address*/
2060 if (dest->addrtype == MSM_IPC_ADDR_ID) {
2061 dst_node_id = dest->addr.port_addr.node_id;
2062 dst_port_id = dest->addr.port_addr.port_id;
2063 } else if (dest->addrtype == MSM_IPC_ADDR_NAME) {
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002064 mutex_lock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002065 server = msm_ipc_router_lookup_server(
2066 dest->addr.port_name.service,
2067 dest->addr.port_name.instance,
2068 0, 0);
2069 if (!server) {
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002070 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002071 pr_err("%s: Destination not reachable\n", __func__);
2072 return -ENODEV;
2073 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002074 server_port = list_first_entry(&server->server_port_list,
2075 struct msm_ipc_server_port,
2076 list);
2077 dst_node_id = server_port->server_addr.node_id;
2078 dst_port_id = server_port->server_addr.port_id;
2079 mutex_unlock(&server_list_lock);
2080 }
2081 if (dst_node_id == IPC_ROUTER_NID_LOCAL) {
2082 ret = loopback_data(src, dst_port_id, data);
2083 return ret;
2084 }
2085
2086 /* Achieve Flow control */
2087 rport_ptr = msm_ipc_router_lookup_remote_port(dst_node_id,
2088 dst_port_id);
2089 if (!rport_ptr) {
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002090 pr_err("%s: Could not create remote port\n", __func__);
2091 return -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002092 }
2093
Karthikeyan Ramasubramanian1668cc62012-09-23 22:23:36 -06002094 if (src->check_send_permissions) {
2095 ret = src->check_send_permissions(rport_ptr->sec_rule);
2096 if (ret <= 0) {
2097 pr_err("%s: permission failure for %s\n",
2098 __func__, current->comm);
2099 return -EPERM;
2100 }
2101 }
2102
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002103 pkt = create_pkt(data);
2104 if (!pkt) {
2105 pr_err("%s: Pkt creation failed\n", __func__);
2106 return -ENOMEM;
2107 }
2108
2109 ret = msm_ipc_router_write_pkt(src, rport_ptr, pkt);
2110 release_pkt(pkt);
2111
2112 return ret;
2113}
2114
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -06002115int msm_ipc_router_send_msg(struct msm_ipc_port *src,
2116 struct msm_ipc_addr *dest,
2117 void *data, unsigned int data_len)
2118{
2119 struct sk_buff_head *out_skb_head;
2120 int ret;
2121
2122 out_skb_head = msm_ipc_router_buf_to_skb(data, data_len);
2123 if (!out_skb_head) {
2124 pr_err("%s: SKB conversion failed\n", __func__);
2125 return -EFAULT;
2126 }
2127
2128 ret = msm_ipc_router_send_to(src, out_skb_head, dest);
2129 if (ret < 0) {
2130 pr_err("%s: msm_ipc_router_send_to failed - ret: %d\n",
2131 __func__, ret);
2132 msm_ipc_router_free_skb(out_skb_head);
2133 }
2134 return 0;
2135}
2136
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002137int msm_ipc_router_read(struct msm_ipc_port *port_ptr,
2138 struct sk_buff_head **data,
2139 size_t buf_len)
2140{
2141 struct rr_packet *pkt;
2142 int ret;
2143
2144 if (!port_ptr || !data)
2145 return -EINVAL;
2146
2147 mutex_lock(&port_ptr->port_rx_q_lock);
2148 if (list_empty(&port_ptr->port_rx_q)) {
2149 mutex_unlock(&port_ptr->port_rx_q_lock);
2150 return -EAGAIN;
2151 }
2152
2153 pkt = list_first_entry(&port_ptr->port_rx_q, struct rr_packet, list);
2154 if ((buf_len) && ((pkt->length - IPC_ROUTER_HDR_SIZE) > buf_len)) {
2155 mutex_unlock(&port_ptr->port_rx_q_lock);
2156 return -ETOOSMALL;
2157 }
2158 list_del(&pkt->list);
2159 if (list_empty(&port_ptr->port_rx_q))
2160 wake_unlock(&port_ptr->port_rx_wake_lock);
2161 *data = pkt->pkt_fragment_q;
2162 ret = pkt->length;
2163 kfree(pkt);
2164 mutex_unlock(&port_ptr->port_rx_q_lock);
2165
2166 return ret;
2167}
2168
2169int msm_ipc_router_recv_from(struct msm_ipc_port *port_ptr,
2170 struct sk_buff_head **data,
2171 struct msm_ipc_addr *src,
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -06002172 long timeout)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002173{
2174 int ret, data_len, align_size;
2175 struct sk_buff *temp_skb;
2176 struct rr_header *hdr = NULL;
2177
2178 if (!port_ptr || !data) {
2179 pr_err("%s: Invalid pointers being passed\n", __func__);
2180 return -EINVAL;
2181 }
2182
2183 *data = NULL;
2184 mutex_lock(&port_ptr->port_rx_q_lock);
2185 while (list_empty(&port_ptr->port_rx_q)) {
2186 mutex_unlock(&port_ptr->port_rx_q_lock);
2187 if (timeout < 0) {
2188 ret = wait_event_interruptible(
2189 port_ptr->port_rx_wait_q,
2190 !list_empty(&port_ptr->port_rx_q));
2191 if (ret)
2192 return ret;
2193 } else if (timeout > 0) {
2194 timeout = wait_event_interruptible_timeout(
2195 port_ptr->port_rx_wait_q,
2196 !list_empty(&port_ptr->port_rx_q),
2197 timeout);
2198 if (timeout < 0)
2199 return -EFAULT;
2200 }
2201 if (timeout == 0)
2202 return -ETIMEDOUT;
2203 mutex_lock(&port_ptr->port_rx_q_lock);
2204 }
2205 mutex_unlock(&port_ptr->port_rx_q_lock);
2206
2207 ret = msm_ipc_router_read(port_ptr, data, 0);
2208 if (ret <= 0 || !(*data))
2209 return ret;
2210
2211 temp_skb = skb_peek(*data);
2212 hdr = (struct rr_header *)(temp_skb->data);
2213 if (src) {
2214 src->addrtype = MSM_IPC_ADDR_ID;
2215 src->addr.port_addr.node_id = hdr->src_node_id;
2216 src->addr.port_addr.port_id = hdr->src_port_id;
2217 }
2218
2219 data_len = hdr->size;
2220 skb_pull(temp_skb, IPC_ROUTER_HDR_SIZE);
2221 align_size = ALIGN_SIZE(data_len);
2222 if (align_size) {
2223 temp_skb = skb_peek_tail(*data);
2224 skb_trim(temp_skb, (temp_skb->len - align_size));
2225 }
2226 return data_len;
2227}
2228
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -06002229int msm_ipc_router_read_msg(struct msm_ipc_port *port_ptr,
2230 struct msm_ipc_addr *src,
2231 unsigned char **data,
2232 unsigned int *len)
2233{
2234 struct sk_buff_head *in_skb_head;
2235 int ret;
2236
2237 ret = msm_ipc_router_recv_from(port_ptr, &in_skb_head, src, -1);
2238 if (ret < 0) {
2239 pr_err("%s: msm_ipc_router_recv_from failed - ret: %d\n",
2240 __func__, ret);
2241 return ret;
2242 }
2243
2244 *data = msm_ipc_router_skb_to_buf(in_skb_head, ret);
2245 if (!(*data))
2246 pr_err("%s: Buf conversion failed\n", __func__);
2247
2248 *len = ret;
2249 msm_ipc_router_free_skb(in_skb_head);
2250 return 0;
2251}
2252
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002253struct msm_ipc_port *msm_ipc_router_create_port(
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -06002254 void (*notify)(unsigned event, void *priv),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002255 void *priv)
2256{
2257 struct msm_ipc_port *port_ptr;
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -06002258 int ret;
2259
2260 ret = wait_for_completion_interruptible(&msm_ipc_local_router_up);
2261 if (ret < 0) {
2262 pr_err("%s: Error waiting for local router\n", __func__);
2263 return NULL;
2264 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002265
2266 port_ptr = msm_ipc_router_create_raw_port(NULL, notify, priv);
2267 if (!port_ptr)
2268 pr_err("%s: port_ptr alloc failed\n", __func__);
2269
2270 return port_ptr;
2271}
2272
2273int msm_ipc_router_close_port(struct msm_ipc_port *port_ptr)
2274{
2275 union rr_control_msg msg;
2276 struct rr_packet *pkt, *temp_pkt;
2277 struct msm_ipc_server *server;
2278
2279 if (!port_ptr)
2280 return -EINVAL;
2281
2282 if (port_ptr->type == SERVER_PORT || port_ptr->type == CLIENT_PORT) {
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06002283 mutex_lock(&local_ports_lock);
2284 list_del(&port_ptr->list);
2285 mutex_unlock(&local_ports_lock);
2286
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002287 if (port_ptr->type == SERVER_PORT) {
2288 msg.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_SERVER;
2289 msg.srv.service = port_ptr->port_name.service;
2290 msg.srv.instance = port_ptr->port_name.instance;
2291 msg.srv.node_id = port_ptr->this_port.node_id;
2292 msg.srv.port_id = port_ptr->this_port.port_id;
2293 RR("x REMOVE_SERVER Name=%d:%08x Id=%d:%08x\n",
2294 msg.srv.service, msg.srv.instance,
2295 msg.srv.node_id, msg.srv.port_id);
Karthikeyan Ramasubramanian25e91872013-01-10 17:09:13 -07002296 broadcast_ctl_msg(&msg);
2297 broadcast_ctl_msg_locally(&msg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002298 }
Karthikeyan Ramasubramanian25e91872013-01-10 17:09:13 -07002299
2300 /*
2301 * Server port could have been a client port earlier.
2302 * Send REMOVE_CLIENT message in either case.
2303 */
2304 msg.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT;
2305 msg.cli.node_id = port_ptr->this_port.node_id;
2306 msg.cli.port_id = port_ptr->this_port.port_id;
2307 RR("x REMOVE_CLIENT id=%d:%08x\n",
2308 msg.cli.node_id, msg.cli.port_id);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002309 broadcast_ctl_msg(&msg);
2310 broadcast_ctl_msg_locally(&msg);
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06002311 } else if (port_ptr->type == CONTROL_PORT) {
2312 mutex_lock(&control_ports_lock);
2313 list_del(&port_ptr->list);
2314 mutex_unlock(&control_ports_lock);
Karthikeyan Ramasubramaniand6dbfae2013-01-16 09:00:28 -07002315 } else if (port_ptr->type == IRSC_PORT) {
2316 mutex_lock(&local_ports_lock);
2317 list_del(&port_ptr->list);
2318 mutex_unlock(&local_ports_lock);
2319 signal_irsc_completion();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002320 }
2321
2322 mutex_lock(&port_ptr->port_rx_q_lock);
2323 list_for_each_entry_safe(pkt, temp_pkt, &port_ptr->port_rx_q, list) {
2324 list_del(&pkt->list);
2325 release_pkt(pkt);
2326 }
2327 mutex_unlock(&port_ptr->port_rx_q_lock);
2328
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002329 if (port_ptr->type == SERVER_PORT) {
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002330 mutex_lock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002331 server = msm_ipc_router_lookup_server(
2332 port_ptr->port_name.service,
2333 port_ptr->port_name.instance,
2334 port_ptr->this_port.node_id,
2335 port_ptr->this_port.port_id);
2336 if (server)
2337 msm_ipc_router_destroy_server(server,
2338 port_ptr->this_port.node_id,
2339 port_ptr->this_port.port_id);
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002340 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002341 }
2342
Karthikeyan Ramasubramaniandd8c3b52011-11-30 16:26:12 -07002343 wake_lock_destroy(&port_ptr->port_rx_wake_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002344 kfree(port_ptr);
2345 return 0;
2346}
2347
2348int msm_ipc_router_get_curr_pkt_size(struct msm_ipc_port *port_ptr)
2349{
2350 struct rr_packet *pkt;
2351 int rc = 0;
2352
2353 if (!port_ptr)
2354 return -EINVAL;
2355
2356 mutex_lock(&port_ptr->port_rx_q_lock);
2357 if (!list_empty(&port_ptr->port_rx_q)) {
2358 pkt = list_first_entry(&port_ptr->port_rx_q,
2359 struct rr_packet, list);
2360 rc = pkt->length;
2361 }
2362 mutex_unlock(&port_ptr->port_rx_q_lock);
2363
2364 return rc;
2365}
2366
2367int msm_ipc_router_bind_control_port(struct msm_ipc_port *port_ptr)
2368{
2369 if (!port_ptr)
2370 return -EINVAL;
2371
2372 mutex_lock(&local_ports_lock);
2373 list_del(&port_ptr->list);
2374 mutex_unlock(&local_ports_lock);
2375 port_ptr->type = CONTROL_PORT;
2376 mutex_lock(&control_ports_lock);
2377 list_add_tail(&port_ptr->list, &control_ports);
2378 mutex_unlock(&control_ports_lock);
2379
2380 return 0;
2381}
2382
2383int msm_ipc_router_lookup_server_name(struct msm_ipc_port_name *srv_name,
Karthikeyan Ramasubramaniandfde01b2012-06-12 14:25:13 -06002384 struct msm_ipc_server_info *srv_info,
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002385 int num_entries_in_array,
2386 uint32_t lookup_mask)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002387{
2388 struct msm_ipc_server *server;
2389 struct msm_ipc_server_port *server_port;
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002390 int key, i = 0; /*num_entries_found*/
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002391
2392 if (!srv_name) {
2393 pr_err("%s: Invalid srv_name\n", __func__);
2394 return -EINVAL;
2395 }
2396
Karthikeyan Ramasubramaniandfde01b2012-06-12 14:25:13 -06002397 if (num_entries_in_array && !srv_info) {
2398 pr_err("%s: srv_info NULL\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002399 return -EINVAL;
2400 }
2401
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002402 mutex_lock(&server_list_lock);
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002403 if (!lookup_mask)
2404 lookup_mask = 0xFFFFFFFF;
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002405 key = (srv_name->service & (SRV_HASH_SIZE - 1));
2406 list_for_each_entry(server, &server_list[key], list) {
2407 if ((server->name.service != srv_name->service) ||
2408 ((server->name.instance & lookup_mask) !=
2409 srv_name->instance))
2410 continue;
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002411
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002412 list_for_each_entry(server_port,
2413 &server->server_port_list, list) {
2414 if (i < num_entries_in_array) {
2415 srv_info[i].node_id =
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002416 server_port->server_addr.node_id;
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002417 srv_info[i].port_id =
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002418 server_port->server_addr.port_id;
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002419 srv_info[i].service = server->name.service;
2420 srv_info[i].instance = server->name.instance;
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002421 }
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002422 i++;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002423 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002424 }
2425 mutex_unlock(&server_list_lock);
2426
2427 return i;
2428}
2429
2430int msm_ipc_router_close(void)
2431{
2432 struct msm_ipc_router_xprt_info *xprt_info, *tmp_xprt_info;
2433
2434 mutex_lock(&xprt_info_list_lock);
2435 list_for_each_entry_safe(xprt_info, tmp_xprt_info,
2436 &xprt_info_list, list) {
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -07002437 xprt_info->xprt->close(xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002438 list_del(&xprt_info->list);
2439 kfree(xprt_info);
2440 }
2441 mutex_unlock(&xprt_info_list_lock);
2442 return 0;
2443}
2444
2445#if defined(CONFIG_DEBUG_FS)
2446static int dump_routing_table(char *buf, int max)
2447{
2448 int i = 0, j;
2449 struct msm_ipc_routing_table_entry *rt_entry;
2450
2451 for (j = 0; j < RT_HASH_SIZE; j++) {
2452 mutex_lock(&routing_table_lock);
2453 list_for_each_entry(rt_entry, &routing_table[j], list) {
2454 mutex_lock(&rt_entry->lock);
2455 i += scnprintf(buf + i, max - i,
2456 "Node Id: 0x%08x\n", rt_entry->node_id);
Karthikeyan Ramasubramanianc1a4e3a2012-09-10 16:10:24 -06002457 if (rt_entry->node_id == IPC_ROUTER_NID_LOCAL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002458 i += scnprintf(buf + i, max - i,
2459 "XPRT Name: Loopback\n");
2460 i += scnprintf(buf + i, max - i,
2461 "Next Hop: %d\n", rt_entry->node_id);
2462 } else {
2463 i += scnprintf(buf + i, max - i,
2464 "XPRT Name: %s\n",
2465 rt_entry->xprt_info->xprt->name);
2466 i += scnprintf(buf + i, max - i,
2467 "Next Hop: 0x%08x\n",
2468 rt_entry->xprt_info->remote_node_id);
2469 }
2470 i += scnprintf(buf + i, max - i, "\n");
2471 mutex_unlock(&rt_entry->lock);
2472 }
2473 mutex_unlock(&routing_table_lock);
2474 }
2475
2476 return i;
2477}
2478
2479static int dump_xprt_info(char *buf, int max)
2480{
2481 int i = 0;
2482 struct msm_ipc_router_xprt_info *xprt_info;
2483
2484 mutex_lock(&xprt_info_list_lock);
2485 list_for_each_entry(xprt_info, &xprt_info_list, list) {
2486 i += scnprintf(buf + i, max - i, "XPRT Name: %s\n",
2487 xprt_info->xprt->name);
2488 i += scnprintf(buf + i, max - i, "Link Id: %d\n",
2489 xprt_info->xprt->link_id);
2490 i += scnprintf(buf + i, max - i, "Initialized: %s\n",
2491 (xprt_info->initialized ? "Y" : "N"));
2492 i += scnprintf(buf + i, max - i, "Remote Node Id: 0x%08x\n",
2493 xprt_info->remote_node_id);
2494 i += scnprintf(buf + i, max - i, "\n");
2495 }
2496 mutex_unlock(&xprt_info_list_lock);
2497
2498 return i;
2499}
2500
2501static int dump_servers(char *buf, int max)
2502{
2503 int i = 0, j;
2504 struct msm_ipc_server *server;
2505 struct msm_ipc_server_port *server_port;
2506
2507 mutex_lock(&server_list_lock);
2508 for (j = 0; j < SRV_HASH_SIZE; j++) {
2509 list_for_each_entry(server, &server_list[j], list) {
2510 list_for_each_entry(server_port,
2511 &server->server_port_list,
2512 list) {
2513 i += scnprintf(buf + i, max - i, "Service: "
2514 "0x%08x\n", server->name.service);
2515 i += scnprintf(buf + i, max - i, "Instance: "
2516 "0x%08x\n", server->name.instance);
2517 i += scnprintf(buf + i, max - i,
2518 "Node_id: 0x%08x\n",
2519 server_port->server_addr.node_id);
2520 i += scnprintf(buf + i, max - i,
2521 "Port_id: 0x%08x\n",
2522 server_port->server_addr.port_id);
2523 i += scnprintf(buf + i, max - i, "\n");
2524 }
2525 }
2526 }
2527 mutex_unlock(&server_list_lock);
2528
2529 return i;
2530}
2531
2532static int dump_remote_ports(char *buf, int max)
2533{
2534 int i = 0, j, k;
2535 struct msm_ipc_router_remote_port *rport_ptr;
2536 struct msm_ipc_routing_table_entry *rt_entry;
2537
2538 for (j = 0; j < RT_HASH_SIZE; j++) {
2539 mutex_lock(&routing_table_lock);
2540 list_for_each_entry(rt_entry, &routing_table[j], list) {
2541 mutex_lock(&rt_entry->lock);
2542 for (k = 0; k < RP_HASH_SIZE; k++) {
2543 list_for_each_entry(rport_ptr,
2544 &rt_entry->remote_port_list[k],
2545 list) {
2546 i += scnprintf(buf + i, max - i,
2547 "Node_id: 0x%08x\n",
2548 rport_ptr->node_id);
2549 i += scnprintf(buf + i, max - i,
2550 "Port_id: 0x%08x\n",
2551 rport_ptr->port_id);
2552 i += scnprintf(buf + i, max - i,
2553 "Quota_cnt: %d\n",
2554 rport_ptr->tx_quota_cnt);
2555 i += scnprintf(buf + i, max - i, "\n");
2556 }
2557 }
2558 mutex_unlock(&rt_entry->lock);
2559 }
2560 mutex_unlock(&routing_table_lock);
2561 }
2562
2563 return i;
2564}
2565
2566static int dump_control_ports(char *buf, int max)
2567{
2568 int i = 0;
2569 struct msm_ipc_port *port_ptr;
2570
2571 mutex_lock(&control_ports_lock);
2572 list_for_each_entry(port_ptr, &control_ports, list) {
2573 i += scnprintf(buf + i, max - i, "Node_id: 0x%08x\n",
2574 port_ptr->this_port.node_id);
2575 i += scnprintf(buf + i, max - i, "Port_id: 0x%08x\n",
2576 port_ptr->this_port.port_id);
2577 i += scnprintf(buf + i, max - i, "\n");
2578 }
2579 mutex_unlock(&control_ports_lock);
2580
2581 return i;
2582}
2583
2584static int dump_local_ports(char *buf, int max)
2585{
2586 int i = 0, j;
2587 unsigned long flags;
2588 struct msm_ipc_port *port_ptr;
2589
2590 mutex_lock(&local_ports_lock);
2591 for (j = 0; j < LP_HASH_SIZE; j++) {
2592 list_for_each_entry(port_ptr, &local_ports[j], list) {
2593 spin_lock_irqsave(&port_ptr->port_lock, flags);
2594 i += scnprintf(buf + i, max - i, "Node_id: 0x%08x\n",
2595 port_ptr->this_port.node_id);
2596 i += scnprintf(buf + i, max - i, "Port_id: 0x%08x\n",
2597 port_ptr->this_port.port_id);
2598 i += scnprintf(buf + i, max - i, "# pkts tx'd %d\n",
2599 port_ptr->num_tx);
2600 i += scnprintf(buf + i, max - i, "# pkts rx'd %d\n",
2601 port_ptr->num_rx);
2602 i += scnprintf(buf + i, max - i, "# bytes tx'd %ld\n",
2603 port_ptr->num_tx_bytes);
2604 i += scnprintf(buf + i, max - i, "# bytes rx'd %ld\n",
2605 port_ptr->num_rx_bytes);
2606 spin_unlock_irqrestore(&port_ptr->port_lock, flags);
2607 i += scnprintf(buf + i, max - i, "\n");
2608 }
2609 }
2610 mutex_unlock(&local_ports_lock);
2611
2612 return i;
2613}
2614
2615#define DEBUG_BUFMAX 4096
2616static char debug_buffer[DEBUG_BUFMAX];
2617
2618static ssize_t debug_read(struct file *file, char __user *buf,
2619 size_t count, loff_t *ppos)
2620{
2621 int (*fill)(char *buf, int max) = file->private_data;
2622 int bsize = fill(debug_buffer, DEBUG_BUFMAX);
2623 return simple_read_from_buffer(buf, count, ppos, debug_buffer, bsize);
2624}
2625
2626static int debug_open(struct inode *inode, struct file *file)
2627{
2628 file->private_data = inode->i_private;
2629 return 0;
2630}
2631
2632static const struct file_operations debug_ops = {
2633 .read = debug_read,
2634 .open = debug_open,
2635};
2636
2637static void debug_create(const char *name, mode_t mode,
2638 struct dentry *dent,
2639 int (*fill)(char *buf, int max))
2640{
2641 debugfs_create_file(name, mode, dent, fill, &debug_ops);
2642}
2643
2644static void debugfs_init(void)
2645{
2646 struct dentry *dent;
2647
2648 dent = debugfs_create_dir("msm_ipc_router", 0);
2649 if (IS_ERR(dent))
2650 return;
2651
2652 debug_create("dump_local_ports", 0444, dent,
2653 dump_local_ports);
2654 debug_create("dump_remote_ports", 0444, dent,
2655 dump_remote_ports);
2656 debug_create("dump_control_ports", 0444, dent,
2657 dump_control_ports);
2658 debug_create("dump_servers", 0444, dent,
2659 dump_servers);
2660 debug_create("dump_xprt_info", 0444, dent,
2661 dump_xprt_info);
2662 debug_create("dump_routing_table", 0444, dent,
2663 dump_routing_table);
2664}
2665
2666#else
2667static void debugfs_init(void) {}
2668#endif
2669
2670static int msm_ipc_router_add_xprt(struct msm_ipc_router_xprt *xprt)
2671{
2672 struct msm_ipc_router_xprt_info *xprt_info;
2673 struct msm_ipc_routing_table_entry *rt_entry;
2674
2675 xprt_info = kmalloc(sizeof(struct msm_ipc_router_xprt_info),
2676 GFP_KERNEL);
2677 if (!xprt_info)
2678 return -ENOMEM;
2679
2680 xprt_info->xprt = xprt;
2681 xprt_info->initialized = 0;
2682 xprt_info->remote_node_id = -1;
2683 INIT_LIST_HEAD(&xprt_info->pkt_list);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002684 mutex_init(&xprt_info->rx_lock);
2685 mutex_init(&xprt_info->tx_lock);
2686 wake_lock_init(&xprt_info->wakelock,
2687 WAKE_LOCK_SUSPEND, xprt->name);
2688 xprt_info->need_len = 0;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002689 xprt_info->abort_data_read = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002690 INIT_WORK(&xprt_info->read_data, do_read_data);
2691 INIT_LIST_HEAD(&xprt_info->list);
2692
2693 xprt_info->workqueue = create_singlethread_workqueue(xprt->name);
2694 if (!xprt_info->workqueue) {
2695 kfree(xprt_info);
2696 return -ENOMEM;
2697 }
2698
2699 if (!strcmp(xprt->name, "msm_ipc_router_loopback_xprt")) {
2700 xprt_info->remote_node_id = IPC_ROUTER_NID_LOCAL;
2701 xprt_info->initialized = 1;
2702 }
2703
2704 mutex_lock(&xprt_info_list_lock);
2705 list_add_tail(&xprt_info->list, &xprt_info_list);
2706 mutex_unlock(&xprt_info_list_lock);
2707
2708 mutex_lock(&routing_table_lock);
2709 if (!routing_table_inited) {
2710 init_routing_table();
2711 rt_entry = alloc_routing_table_entry(IPC_ROUTER_NID_LOCAL);
2712 add_routing_table_entry(rt_entry);
2713 routing_table_inited = 1;
2714 }
2715 mutex_unlock(&routing_table_lock);
2716
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002717 xprt->priv = xprt_info;
2718
2719 return 0;
2720}
2721
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002722static void msm_ipc_router_remove_xprt(struct msm_ipc_router_xprt *xprt)
2723{
2724 struct msm_ipc_router_xprt_info *xprt_info;
2725
2726 if (xprt && xprt->priv) {
2727 xprt_info = xprt->priv;
2728
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06002729 mutex_lock(&xprt_info->rx_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002730 xprt_info->abort_data_read = 1;
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06002731 mutex_unlock(&xprt_info->rx_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002732
2733 mutex_lock(&xprt_info_list_lock);
2734 list_del(&xprt_info->list);
2735 mutex_unlock(&xprt_info_list_lock);
2736
2737 flush_workqueue(xprt_info->workqueue);
2738 destroy_workqueue(xprt_info->workqueue);
2739 wake_lock_destroy(&xprt_info->wakelock);
2740
2741 xprt->priv = 0;
2742 kfree(xprt_info);
2743 }
2744}
2745
2746
2747struct msm_ipc_router_xprt_work {
2748 struct msm_ipc_router_xprt *xprt;
2749 struct work_struct work;
2750};
2751
2752static void xprt_open_worker(struct work_struct *work)
2753{
2754 struct msm_ipc_router_xprt_work *xprt_work =
2755 container_of(work, struct msm_ipc_router_xprt_work, work);
2756
2757 msm_ipc_router_add_xprt(xprt_work->xprt);
2758 kfree(xprt_work);
2759}
2760
2761static void xprt_close_worker(struct work_struct *work)
2762{
2763 struct msm_ipc_router_xprt_work *xprt_work =
2764 container_of(work, struct msm_ipc_router_xprt_work, work);
2765
2766 modem_reset_cleanup(xprt_work->xprt->priv);
2767 msm_ipc_router_remove_xprt(xprt_work->xprt);
Zaheerulla Meer35893a62013-06-19 16:54:44 +05302768 xprt_work->xprt->sft_close_done(xprt_work->xprt);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002769 kfree(xprt_work);
2770}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002771
2772void msm_ipc_router_xprt_notify(struct msm_ipc_router_xprt *xprt,
2773 unsigned event,
2774 void *data)
2775{
2776 struct msm_ipc_router_xprt_info *xprt_info = xprt->priv;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002777 struct msm_ipc_router_xprt_work *xprt_work;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002778 struct rr_packet *pkt;
Karthikeyan Ramasubramanian4af9f7c2011-09-30 15:55:18 -06002779 unsigned long ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002780
Karthikeyan Ramasubramanian4af9f7c2011-09-30 15:55:18 -06002781 if (!msm_ipc_router_workqueue) {
2782 ret = wait_for_completion_timeout(&msm_ipc_local_router_up,
2783 IPC_ROUTER_INIT_TIMEOUT);
2784 if (!ret || !msm_ipc_router_workqueue) {
2785 pr_err("%s: IPC Router not initialized\n", __func__);
2786 return;
2787 }
2788 }
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002789
2790 switch (event) {
2791 case IPC_ROUTER_XPRT_EVENT_OPEN:
2792 D("open event for '%s'\n", xprt->name);
2793 xprt_work = kmalloc(sizeof(struct msm_ipc_router_xprt_work),
2794 GFP_ATOMIC);
2795 xprt_work->xprt = xprt;
2796 INIT_WORK(&xprt_work->work, xprt_open_worker);
2797 queue_work(msm_ipc_router_workqueue, &xprt_work->work);
2798 break;
2799
2800 case IPC_ROUTER_XPRT_EVENT_CLOSE:
2801 D("close event for '%s'\n", xprt->name);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002802 xprt_work = kmalloc(sizeof(struct msm_ipc_router_xprt_work),
2803 GFP_ATOMIC);
2804 xprt_work->xprt = xprt;
2805 INIT_WORK(&xprt_work->work, xprt_close_worker);
2806 queue_work(msm_ipc_router_workqueue, &xprt_work->work);
2807 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002808 }
2809
2810 if (!data)
2811 return;
2812
2813 while (!xprt_info) {
2814 msleep(100);
2815 xprt_info = xprt->priv;
2816 }
2817
2818 pkt = clone_pkt((struct rr_packet *)data);
2819 if (!pkt)
2820 return;
2821
2822 mutex_lock(&xprt_info->rx_lock);
2823 list_add_tail(&pkt->list, &xprt_info->pkt_list);
2824 wake_lock(&xprt_info->wakelock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002825 mutex_unlock(&xprt_info->rx_lock);
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06002826 queue_work(xprt_info->workqueue, &xprt_info->read_data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002827}
2828
2829static int __init msm_ipc_router_init(void)
2830{
2831 int i, ret;
2832 struct msm_ipc_routing_table_entry *rt_entry;
2833
2834 msm_ipc_router_debug_mask |= SMEM_LOG;
Karthikeyan Ramasubramanian682ebcc2013-03-22 10:47:20 -06002835 ipc_rtr_log_ctxt = ipc_log_context_create(IPC_RTR_LOG_PAGES,
2836 "ipc_router");
2837 if (!ipc_rtr_log_ctxt)
2838 pr_err("%s: Unable to create IPC logging for IPC RTR",
2839 __func__);
2840
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002841 msm_ipc_router_workqueue =
2842 create_singlethread_workqueue("msm_ipc_router");
2843 if (!msm_ipc_router_workqueue)
2844 return -ENOMEM;
2845
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002846 debugfs_init();
2847
2848 for (i = 0; i < SRV_HASH_SIZE; i++)
2849 INIT_LIST_HEAD(&server_list[i]);
2850
2851 for (i = 0; i < LP_HASH_SIZE; i++)
2852 INIT_LIST_HEAD(&local_ports[i]);
2853
2854 mutex_lock(&routing_table_lock);
2855 if (!routing_table_inited) {
2856 init_routing_table();
2857 rt_entry = alloc_routing_table_entry(IPC_ROUTER_NID_LOCAL);
2858 add_routing_table_entry(rt_entry);
2859 routing_table_inited = 1;
2860 }
2861 mutex_unlock(&routing_table_lock);
2862
2863 init_waitqueue_head(&newserver_wait);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002864 ret = msm_ipc_router_init_sockets();
2865 if (ret < 0)
2866 pr_err("%s: Init sockets failed\n", __func__);
2867
Karthikeyan Ramasubramanian1668cc62012-09-23 22:23:36 -06002868 ret = msm_ipc_router_security_init();
2869 if (ret < 0)
2870 pr_err("%s: Security Init failed\n", __func__);
2871
Karthikeyan Ramasubramanian4af9f7c2011-09-30 15:55:18 -06002872 complete_all(&msm_ipc_local_router_up);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002873 return ret;
2874}
2875
2876module_init(msm_ipc_router_init);
2877MODULE_DESCRIPTION("MSM IPC Router");
2878MODULE_LICENSE("GPL v2");