blob: a93c1142f1e1bbf835433d44cd23269aaa865e03 [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
Zaheerulla Meera34fc662013-04-17 01:16:47 +0530136struct msm_ipc_resume_tx_port {
137 struct list_head list;
138 uint32_t port_id;
139 uint32_t node_id;
140};
141
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700142#define RP_HASH_SIZE 32
143struct msm_ipc_router_remote_port {
144 struct list_head list;
145 uint32_t node_id;
146 uint32_t port_id;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600147 uint32_t restart_state;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700148 uint32_t tx_quota_cnt;
149 struct mutex quota_lock;
Zaheerulla Meera34fc662013-04-17 01:16:47 +0530150 struct list_head resume_tx_port_list;
Karthikeyan Ramasubramanian1668cc62012-09-23 22:23:36 -0600151 void *sec_rule;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700152};
153
154struct msm_ipc_router_xprt_info {
155 struct list_head list;
156 struct msm_ipc_router_xprt *xprt;
157 uint32_t remote_node_id;
158 uint32_t initialized;
159 struct list_head pkt_list;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700160 struct wake_lock wakelock;
161 struct mutex rx_lock;
162 struct mutex tx_lock;
163 uint32_t need_len;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600164 uint32_t abort_data_read;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700165 struct work_struct read_data;
166 struct workqueue_struct *workqueue;
167};
168
169#define RT_HASH_SIZE 4
170struct msm_ipc_routing_table_entry {
171 struct list_head list;
172 uint32_t node_id;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600173 uint32_t neighbor_node_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700174 struct list_head remote_port_list[RP_HASH_SIZE];
175 struct msm_ipc_router_xprt_info *xprt_info;
176 struct mutex lock;
177 unsigned long num_tx_bytes;
178 unsigned long num_rx_bytes;
179};
180
181static struct list_head routing_table[RT_HASH_SIZE];
182static DEFINE_MUTEX(routing_table_lock);
183static int routing_table_inited;
184
185static LIST_HEAD(msm_ipc_board_dev_list);
186static DEFINE_MUTEX(msm_ipc_board_dev_list_lock);
187
188static void do_read_data(struct work_struct *work);
189
190#define RR_STATE_IDLE 0
191#define RR_STATE_HEADER 1
192#define RR_STATE_BODY 2
193#define RR_STATE_ERROR 3
194
195#define RESTART_NORMAL 0
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600196#define RESTART_PEND 1
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700197
198/* State for remote ep following restart */
199#define RESTART_QUOTA_ABORT 1
200
201static LIST_HEAD(xprt_info_list);
202static DEFINE_MUTEX(xprt_info_list_lock);
203
Karthikeyan Ramasubramanian4af9f7c2011-09-30 15:55:18 -0600204static DECLARE_COMPLETION(msm_ipc_local_router_up);
205#define IPC_ROUTER_INIT_TIMEOUT (10 * HZ)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700206
207static uint32_t next_port_id;
208static DEFINE_MUTEX(next_port_id_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600209static struct workqueue_struct *msm_ipc_router_workqueue;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700210
211enum {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700212 DOWN,
213 UP,
214};
215
216static void init_routing_table(void)
217{
218 int i;
219 for (i = 0; i < RT_HASH_SIZE; i++)
220 INIT_LIST_HEAD(&routing_table[i]);
221}
222
223static struct msm_ipc_routing_table_entry *alloc_routing_table_entry(
224 uint32_t node_id)
225{
226 int i;
227 struct msm_ipc_routing_table_entry *rt_entry;
228
229 rt_entry = kmalloc(sizeof(struct msm_ipc_routing_table_entry),
230 GFP_KERNEL);
231 if (!rt_entry) {
232 pr_err("%s: rt_entry allocation failed for %d\n",
233 __func__, node_id);
234 return NULL;
235 }
236
237 for (i = 0; i < RP_HASH_SIZE; i++)
238 INIT_LIST_HEAD(&rt_entry->remote_port_list[i]);
239
240 mutex_init(&rt_entry->lock);
241 rt_entry->node_id = node_id;
242 rt_entry->xprt_info = NULL;
243 return rt_entry;
244}
245
246/*Please take routing_table_lock before calling this function*/
247static int add_routing_table_entry(
248 struct msm_ipc_routing_table_entry *rt_entry)
249{
250 uint32_t key;
251
252 if (!rt_entry)
253 return -EINVAL;
254
255 key = (rt_entry->node_id % RT_HASH_SIZE);
256 list_add_tail(&rt_entry->list, &routing_table[key]);
257 return 0;
258}
259
260/*Please take routing_table_lock before calling this function*/
261static struct msm_ipc_routing_table_entry *lookup_routing_table(
262 uint32_t node_id)
263{
264 uint32_t key = (node_id % RT_HASH_SIZE);
265 struct msm_ipc_routing_table_entry *rt_entry;
266
267 list_for_each_entry(rt_entry, &routing_table[key], list) {
268 if (rt_entry->node_id == node_id)
269 return rt_entry;
270 }
271 return NULL;
272}
273
274struct rr_packet *rr_read(struct msm_ipc_router_xprt_info *xprt_info)
275{
276 struct rr_packet *temp_pkt;
277
278 if (!xprt_info)
279 return NULL;
280
281 mutex_lock(&xprt_info->rx_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600282 if (xprt_info->abort_data_read) {
283 mutex_unlock(&xprt_info->rx_lock);
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -0600284 pr_err("%s detected SSR & exiting now\n",
285 xprt_info->xprt->name);
286 return NULL;
287 }
288
289 if (list_empty(&xprt_info->pkt_list)) {
290 mutex_unlock(&xprt_info->rx_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600291 return NULL;
292 }
293
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700294 temp_pkt = list_first_entry(&xprt_info->pkt_list,
295 struct rr_packet, list);
296 list_del(&temp_pkt->list);
297 if (list_empty(&xprt_info->pkt_list))
298 wake_unlock(&xprt_info->wakelock);
299 mutex_unlock(&xprt_info->rx_lock);
300 return temp_pkt;
301}
302
303struct rr_packet *clone_pkt(struct rr_packet *pkt)
304{
305 struct rr_packet *cloned_pkt;
306 struct sk_buff *temp_skb, *cloned_skb;
307 struct sk_buff_head *pkt_fragment_q;
308
309 cloned_pkt = kzalloc(sizeof(struct rr_packet), GFP_KERNEL);
310 if (!cloned_pkt) {
311 pr_err("%s: failure\n", __func__);
312 return NULL;
313 }
314
315 pkt_fragment_q = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
316 if (!pkt_fragment_q) {
317 pr_err("%s: pkt_frag_q alloc failure\n", __func__);
318 kfree(cloned_pkt);
319 return NULL;
320 }
321 skb_queue_head_init(pkt_fragment_q);
322
323 skb_queue_walk(pkt->pkt_fragment_q, temp_skb) {
324 cloned_skb = skb_clone(temp_skb, GFP_KERNEL);
325 if (!cloned_skb)
326 goto fail_clone;
327 skb_queue_tail(pkt_fragment_q, cloned_skb);
328 }
329 cloned_pkt->pkt_fragment_q = pkt_fragment_q;
330 cloned_pkt->length = pkt->length;
331 return cloned_pkt;
332
333fail_clone:
334 while (!skb_queue_empty(pkt_fragment_q)) {
335 temp_skb = skb_dequeue(pkt_fragment_q);
336 kfree_skb(temp_skb);
337 }
338 kfree(pkt_fragment_q);
339 kfree(cloned_pkt);
340 return NULL;
341}
342
343struct rr_packet *create_pkt(struct sk_buff_head *data)
344{
345 struct rr_packet *pkt;
346 struct sk_buff *temp_skb;
347
348 pkt = kzalloc(sizeof(struct rr_packet), GFP_KERNEL);
349 if (!pkt) {
350 pr_err("%s: failure\n", __func__);
351 return NULL;
352 }
353
354 pkt->pkt_fragment_q = data;
355 skb_queue_walk(pkt->pkt_fragment_q, temp_skb)
356 pkt->length += temp_skb->len;
357 return pkt;
358}
359
360void release_pkt(struct rr_packet *pkt)
361{
362 struct sk_buff *temp_skb;
363
364 if (!pkt)
365 return;
366
367 if (!pkt->pkt_fragment_q) {
368 kfree(pkt);
369 return;
370 }
371
372 while (!skb_queue_empty(pkt->pkt_fragment_q)) {
373 temp_skb = skb_dequeue(pkt->pkt_fragment_q);
374 kfree_skb(temp_skb);
375 }
376 kfree(pkt->pkt_fragment_q);
377 kfree(pkt);
378 return;
379}
380
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -0600381static struct sk_buff_head *msm_ipc_router_buf_to_skb(void *buf,
382 unsigned int buf_len)
383{
384 struct sk_buff_head *skb_head;
385 struct sk_buff *skb;
386 int first = 1, offset = 0;
387 int skb_size, data_size;
388 void *data;
389
390 skb_head = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
391 if (!skb_head) {
392 pr_err("%s: Couldnot allocate skb_head\n", __func__);
393 return NULL;
394 }
395 skb_queue_head_init(skb_head);
396
397 data_size = buf_len;
398 while (offset != buf_len) {
399 skb_size = data_size;
400 if (first)
401 skb_size += IPC_ROUTER_HDR_SIZE;
402
403 skb = alloc_skb(skb_size, GFP_KERNEL);
404 if (!skb) {
405 if (skb_size <= (PAGE_SIZE/2)) {
406 pr_err("%s: cannot allocate skb\n", __func__);
407 goto buf_to_skb_error;
408 }
409 data_size = data_size / 2;
410 continue;
411 }
412
413 if (first) {
414 skb_reserve(skb, IPC_ROUTER_HDR_SIZE);
415 first = 0;
416 }
417
418 data = skb_put(skb, data_size);
419 memcpy(skb->data, buf + offset, data_size);
420 skb_queue_tail(skb_head, skb);
421 offset += data_size;
422 data_size = buf_len - offset;
423 }
424 return skb_head;
425
426buf_to_skb_error:
427 while (!skb_queue_empty(skb_head)) {
428 skb = skb_dequeue(skb_head);
429 kfree_skb(skb);
430 }
431 kfree(skb_head);
432 return NULL;
433}
434
435static void *msm_ipc_router_skb_to_buf(struct sk_buff_head *skb_head,
436 unsigned int len)
437{
438 struct sk_buff *temp;
439 int offset = 0, buf_len = 0, copy_len;
440 void *buf;
441
442 if (!skb_head) {
443 pr_err("%s: NULL skb_head\n", __func__);
444 return NULL;
445 }
446
447 temp = skb_peek(skb_head);
448 buf_len = len;
449 buf = kmalloc(buf_len, GFP_KERNEL);
450 if (!buf) {
451 pr_err("%s: cannot allocate buf\n", __func__);
452 return NULL;
453 }
454 skb_queue_walk(skb_head, temp) {
455 copy_len = buf_len < temp->len ? buf_len : temp->len;
456 memcpy(buf + offset, temp->data, copy_len);
457 offset += copy_len;
458 buf_len -= copy_len;
459 }
460 return buf;
461}
462
463static void msm_ipc_router_free_skb(struct sk_buff_head *skb_head)
464{
465 struct sk_buff *temp_skb;
466
467 if (!skb_head)
468 return;
469
470 while (!skb_queue_empty(skb_head)) {
471 temp_skb = skb_dequeue(skb_head);
472 kfree_skb(temp_skb);
473 }
474 kfree(skb_head);
475}
476
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700477static int post_control_ports(struct rr_packet *pkt)
478{
479 struct msm_ipc_port *port_ptr;
480 struct rr_packet *cloned_pkt;
481
482 if (!pkt)
483 return -EINVAL;
484
485 mutex_lock(&control_ports_lock);
486 list_for_each_entry(port_ptr, &control_ports, list) {
487 mutex_lock(&port_ptr->port_rx_q_lock);
488 cloned_pkt = clone_pkt(pkt);
489 wake_lock(&port_ptr->port_rx_wake_lock);
490 list_add_tail(&cloned_pkt->list, &port_ptr->port_rx_q);
491 wake_up(&port_ptr->port_rx_wait_q);
492 mutex_unlock(&port_ptr->port_rx_q_lock);
493 }
494 mutex_unlock(&control_ports_lock);
495 return 0;
496}
497
498static uint32_t allocate_port_id(void)
499{
500 uint32_t port_id = 0, prev_port_id, key;
501 struct msm_ipc_port *port_ptr;
502
503 mutex_lock(&next_port_id_lock);
504 prev_port_id = next_port_id;
505 mutex_lock(&local_ports_lock);
506 do {
507 next_port_id++;
508 if ((next_port_id & 0xFFFFFFFE) == 0xFFFFFFFE)
509 next_port_id = 1;
510
511 key = (next_port_id & (LP_HASH_SIZE - 1));
512 if (list_empty(&local_ports[key])) {
513 port_id = next_port_id;
514 break;
515 }
516 list_for_each_entry(port_ptr, &local_ports[key], list) {
517 if (port_ptr->this_port.port_id == next_port_id) {
518 port_id = next_port_id;
519 break;
520 }
521 }
522 if (!port_id) {
523 port_id = next_port_id;
524 break;
525 }
526 port_id = 0;
527 } while (next_port_id != prev_port_id);
528 mutex_unlock(&local_ports_lock);
529 mutex_unlock(&next_port_id_lock);
530
531 return port_id;
532}
533
534void msm_ipc_router_add_local_port(struct msm_ipc_port *port_ptr)
535{
536 uint32_t key;
537
538 if (!port_ptr)
539 return;
540
541 key = (port_ptr->this_port.port_id & (LP_HASH_SIZE - 1));
542 mutex_lock(&local_ports_lock);
543 list_add_tail(&port_ptr->list, &local_ports[key]);
544 mutex_unlock(&local_ports_lock);
545}
546
547struct msm_ipc_port *msm_ipc_router_create_raw_port(void *endpoint,
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -0600548 void (*notify)(unsigned event, void *priv),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700549 void *priv)
550{
551 struct msm_ipc_port *port_ptr;
552
553 port_ptr = kzalloc(sizeof(struct msm_ipc_port), GFP_KERNEL);
554 if (!port_ptr)
555 return NULL;
556
557 port_ptr->this_port.node_id = IPC_ROUTER_NID_LOCAL;
558 port_ptr->this_port.port_id = allocate_port_id();
559 if (!port_ptr->this_port.port_id) {
560 pr_err("%s: All port ids are in use\n", __func__);
561 kfree(port_ptr);
562 return NULL;
563 }
564
565 spin_lock_init(&port_ptr->port_lock);
566 INIT_LIST_HEAD(&port_ptr->incomplete);
567 mutex_init(&port_ptr->incomplete_lock);
568 INIT_LIST_HEAD(&port_ptr->port_rx_q);
569 mutex_init(&port_ptr->port_rx_q_lock);
570 init_waitqueue_head(&port_ptr->port_rx_wait_q);
Karthikeyan Ramasubramanianb4aeeb92012-03-13 12:31:43 -0600571 snprintf(port_ptr->rx_wakelock_name, MAX_WAKELOCK_NAME_SZ,
Karthikeyan Ramasubramanian090486e2013-02-14 13:53:20 -0700572 "ipc%08x_%s",
573 port_ptr->this_port.port_id,
574 current->comm);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700575 wake_lock_init(&port_ptr->port_rx_wake_lock,
Karthikeyan Ramasubramanianb4aeeb92012-03-13 12:31:43 -0600576 WAKE_LOCK_SUSPEND, port_ptr->rx_wakelock_name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700577
578 port_ptr->endpoint = endpoint;
579 port_ptr->notify = notify;
580 port_ptr->priv = priv;
581
582 msm_ipc_router_add_local_port(port_ptr);
583 return port_ptr;
584}
585
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -0600586/*
587 * Should be called with local_ports_lock locked
588 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700589static struct msm_ipc_port *msm_ipc_router_lookup_local_port(uint32_t port_id)
590{
591 int key = (port_id & (LP_HASH_SIZE - 1));
592 struct msm_ipc_port *port_ptr;
593
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700594 list_for_each_entry(port_ptr, &local_ports[key], list) {
595 if (port_ptr->this_port.port_id == port_id) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700596 return port_ptr;
597 }
598 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700599 return NULL;
600}
601
602static struct msm_ipc_router_remote_port *msm_ipc_router_lookup_remote_port(
603 uint32_t node_id,
604 uint32_t port_id)
605{
606 struct msm_ipc_router_remote_port *rport_ptr;
607 struct msm_ipc_routing_table_entry *rt_entry;
608 int key = (port_id & (RP_HASH_SIZE - 1));
609
610 mutex_lock(&routing_table_lock);
611 rt_entry = lookup_routing_table(node_id);
612 if (!rt_entry) {
613 mutex_unlock(&routing_table_lock);
614 pr_err("%s: Node is not up\n", __func__);
615 return NULL;
616 }
617
618 mutex_lock(&rt_entry->lock);
619 list_for_each_entry(rport_ptr,
620 &rt_entry->remote_port_list[key], list) {
621 if (rport_ptr->port_id == port_id) {
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600622 if (rport_ptr->restart_state != RESTART_NORMAL)
623 rport_ptr = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700624 mutex_unlock(&rt_entry->lock);
625 mutex_unlock(&routing_table_lock);
626 return rport_ptr;
627 }
628 }
629 mutex_unlock(&rt_entry->lock);
630 mutex_unlock(&routing_table_lock);
631 return NULL;
632}
633
634static struct msm_ipc_router_remote_port *msm_ipc_router_create_remote_port(
635 uint32_t node_id,
636 uint32_t port_id)
637{
638 struct msm_ipc_router_remote_port *rport_ptr;
639 struct msm_ipc_routing_table_entry *rt_entry;
640 int key = (port_id & (RP_HASH_SIZE - 1));
641
642 mutex_lock(&routing_table_lock);
643 rt_entry = lookup_routing_table(node_id);
644 if (!rt_entry) {
645 mutex_unlock(&routing_table_lock);
646 pr_err("%s: Node is not up\n", __func__);
647 return NULL;
648 }
649
650 mutex_lock(&rt_entry->lock);
651 rport_ptr = kmalloc(sizeof(struct msm_ipc_router_remote_port),
652 GFP_KERNEL);
653 if (!rport_ptr) {
654 mutex_unlock(&rt_entry->lock);
655 mutex_unlock(&routing_table_lock);
656 pr_err("%s: Remote port alloc failed\n", __func__);
657 return NULL;
658 }
659 rport_ptr->port_id = port_id;
660 rport_ptr->node_id = node_id;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600661 rport_ptr->restart_state = RESTART_NORMAL;
Karthikeyan Ramasubramanian1668cc62012-09-23 22:23:36 -0600662 rport_ptr->sec_rule = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700663 rport_ptr->tx_quota_cnt = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700664 mutex_init(&rport_ptr->quota_lock);
Zaheerulla Meera34fc662013-04-17 01:16:47 +0530665 INIT_LIST_HEAD(&rport_ptr->resume_tx_port_list);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700666 list_add_tail(&rport_ptr->list,
667 &rt_entry->remote_port_list[key]);
668 mutex_unlock(&rt_entry->lock);
669 mutex_unlock(&routing_table_lock);
670 return rport_ptr;
671}
672
Zaheerulla Meera34fc662013-04-17 01:16:47 +0530673/**
674 * msm_ipc_router_free_resume_tx_port() - Free the resume_tx ports
675 * @rport_ptr: Pointer to the remote port.
676 *
677 * This function deletes all the resume_tx ports associated with a remote port
678 * and frees the memory allocated to each resume_tx port.
679 *
680 * Must be called with rport_ptr->quota_lock locked.
681 */
682static void msm_ipc_router_free_resume_tx_port(
683 struct msm_ipc_router_remote_port *rport_ptr)
684{
685 struct msm_ipc_resume_tx_port *rtx_port, *tmp_rtx_port;
686
687 list_for_each_entry_safe(rtx_port, tmp_rtx_port,
688 &rport_ptr->resume_tx_port_list, list) {
689 list_del(&rtx_port->list);
690 kfree(rtx_port);
691 }
692}
693
694/**
695 * msm_ipc_router_lookup_resume_tx_port() - Lookup resume_tx port list
696 * @rport_ptr: Remote port whose resume_tx port list needs to be looked.
697 * @port_id: Port ID which needs to be looked from the list.
698 *
699 * return 1 if the port_id is found in the list, else 0.
700 *
701 * This function is used to lookup the existence of a local port in
702 * remote port's resume_tx list. This function is used to ensure that
703 * the same port is not added to the remote_port's resume_tx list repeatedly.
704 *
705 * Must be called with rport_ptr->quota_lock locked.
706 */
707static int msm_ipc_router_lookup_resume_tx_port(
708 struct msm_ipc_router_remote_port *rport_ptr, uint32_t port_id)
709{
710 struct msm_ipc_resume_tx_port *rtx_port;
711
712 list_for_each_entry(rtx_port, &rport_ptr->resume_tx_port_list, list) {
713 if (port_id == rtx_port->port_id)
714 return 1;
715 }
716 return 0;
717}
718
719/**
720 * post_resume_tx() - Post the resume_tx event
721 * @rport_ptr: Pointer to the remote port
722 * @pkt : The data packet that is received on a resume_tx event
723 *
724 * This function informs about the reception of the resume_tx message from a
725 * remote port pointed by rport_ptr to all the local ports that are in the
726 * resume_tx_ports_list of this remote port. On posting the information, this
727 * function sequentially deletes each entry in the resume_tx_port_list of the
728 * remote port.
729 *
730 * Must be called with rport_ptr->quota_lock locked.
731 */
732static void post_resume_tx(struct msm_ipc_router_remote_port *rport_ptr,
733 struct rr_packet *pkt)
734{
735 struct msm_ipc_resume_tx_port *rtx_port, *tmp_rtx_port;
736 struct msm_ipc_port *local_port;
737 struct rr_packet *cloned_pkt;
738
739 list_for_each_entry_safe(rtx_port, tmp_rtx_port,
740 &rport_ptr->resume_tx_port_list, list) {
741 mutex_lock(&local_ports_lock);
742 local_port =
743 msm_ipc_router_lookup_local_port(rtx_port->port_id);
744 if (local_port) {
745 cloned_pkt = clone_pkt(pkt);
746 if (cloned_pkt) {
747 mutex_lock(&local_port->port_rx_q_lock);
748 list_add_tail(&cloned_pkt->list,
749 &local_port->port_rx_q);
750 wake_up(&local_port->port_rx_wait_q);
751 mutex_unlock(&local_port->port_rx_q_lock);
752 } else {
753 pr_err("%s: Clone_pkt failed for %08x:%08x\n",
754 __func__, local_port->this_port.node_id,
755 local_port->this_port.port_id);
756 }
757 }
758 mutex_unlock(&local_ports_lock);
759 list_del(&rtx_port->list);
760 kfree(rtx_port);
761 }
762}
763
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700764static void msm_ipc_router_destroy_remote_port(
765 struct msm_ipc_router_remote_port *rport_ptr)
766{
767 uint32_t node_id;
768 struct msm_ipc_routing_table_entry *rt_entry;
769
770 if (!rport_ptr)
771 return;
772
773 node_id = rport_ptr->node_id;
774 mutex_lock(&routing_table_lock);
775 rt_entry = lookup_routing_table(node_id);
776 if (!rt_entry) {
777 mutex_unlock(&routing_table_lock);
778 pr_err("%s: Node %d is not up\n", __func__, node_id);
779 return;
780 }
Zaheerulla Meera34fc662013-04-17 01:16:47 +0530781 mutex_lock(&rport_ptr->quota_lock);
782 msm_ipc_router_free_resume_tx_port(rport_ptr);
783 mutex_unlock(&rport_ptr->quota_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700784 mutex_lock(&rt_entry->lock);
785 list_del(&rport_ptr->list);
786 kfree(rport_ptr);
787 mutex_unlock(&rt_entry->lock);
788 mutex_unlock(&routing_table_lock);
789 return;
790}
791
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -0600792/**
793 * msm_ipc_router_lookup_server() - Lookup server information
794 * @service: Service ID of the server info to be looked up.
795 * @instance: Instance ID of the server info to be looked up.
796 * @node_id: Node/Processor ID in which the server is hosted.
797 * @port_id: Port ID within the node in which the server is hosted.
798 *
799 * @return: If found Pointer to server structure, else NULL.
800 *
801 * Note1: Lock the server_list_lock before accessing this function.
802 * Note2: If the <node_id:port_id> are <0:0>, then the lookup is restricted
803 * to <service:instance>. Used only when a client wants to send a
804 * message to any QMI server.
805 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700806static struct msm_ipc_server *msm_ipc_router_lookup_server(
807 uint32_t service,
808 uint32_t instance,
809 uint32_t node_id,
810 uint32_t port_id)
811{
812 struct msm_ipc_server *server;
813 struct msm_ipc_server_port *server_port;
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -0600814 int key = (service & (SRV_HASH_SIZE - 1));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700815
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700816 list_for_each_entry(server, &server_list[key], list) {
817 if ((server->name.service != service) ||
818 (server->name.instance != instance))
819 continue;
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -0600820 if ((node_id == 0) && (port_id == 0))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700821 return server;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700822 list_for_each_entry(server_port, &server->server_port_list,
823 list) {
824 if ((server_port->server_addr.node_id == node_id) &&
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -0600825 (server_port->server_addr.port_id == port_id))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700826 return server;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700827 }
828 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700829 return NULL;
830}
831
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -0600832static void dummy_release(struct device *dev)
833{
834}
835
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -0600836/**
837 * msm_ipc_router_create_server() - Add server info to hash table
838 * @service: Service ID of the server info to be created.
839 * @instance: Instance ID of the server info to be created.
840 * @node_id: Node/Processor ID in which the server is hosted.
841 * @port_id: Port ID within the node in which the server is hosted.
842 * @xprt_info: XPRT through which the node hosting the server is reached.
843 *
844 * @return: Pointer to server structure on success, else NULL.
845 *
846 * This function adds the server info to the hash table. If the same
847 * server(i.e. <service_id:instance_id>) is hosted in different nodes,
848 * they are maintained as list of "server_port" under "server" structure.
849 * Note: Lock the server_list_lock before accessing this function.
850 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700851static struct msm_ipc_server *msm_ipc_router_create_server(
852 uint32_t service,
853 uint32_t instance,
854 uint32_t node_id,
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600855 uint32_t port_id,
856 struct msm_ipc_router_xprt_info *xprt_info)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700857{
858 struct msm_ipc_server *server = NULL;
859 struct msm_ipc_server_port *server_port;
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -0600860 int key = (service & (SRV_HASH_SIZE - 1));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700861
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700862 list_for_each_entry(server, &server_list[key], list) {
863 if ((server->name.service == service) &&
864 (server->name.instance == instance))
865 goto create_srv_port;
866 }
867
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -0600868 server = kzalloc(sizeof(struct msm_ipc_server), GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700869 if (!server) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700870 pr_err("%s: Server allocation failed\n", __func__);
871 return NULL;
872 }
873 server->name.service = service;
874 server->name.instance = instance;
Karthikeyan Ramasubramanian1668cc62012-09-23 22:23:36 -0600875 server->synced_sec_rule = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700876 INIT_LIST_HEAD(&server->server_port_list);
877 list_add_tail(&server->list, &server_list[key]);
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -0600878 scnprintf(server->pdev_name, sizeof(server->pdev_name),
879 "QMI%08x:%08x", service, instance);
880 server->next_pdev_id = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700881
882create_srv_port:
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -0600883 server_port = kzalloc(sizeof(struct msm_ipc_server_port), GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700884 if (!server_port) {
885 if (list_empty(&server->server_port_list)) {
886 list_del(&server->list);
887 kfree(server);
888 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700889 pr_err("%s: Server Port allocation failed\n", __func__);
890 return NULL;
891 }
892 server_port->server_addr.node_id = node_id;
893 server_port->server_addr.port_id = port_id;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600894 server_port->xprt_info = xprt_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700895 list_add_tail(&server_port->list, &server->server_port_list);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700896
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -0600897 server_port->pdev.name = server->pdev_name;
898 server_port->pdev.id = server->next_pdev_id++;
899 server_port->pdev.dev.release = dummy_release;
900 platform_device_register(&server_port->pdev);
901
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700902 return server;
903}
904
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -0600905/**
906 * msm_ipc_router_destroy_server() - Remove server info from hash table
907 * @server: Server info to be removed.
908 * @node_id: Node/Processor ID in which the server is hosted.
909 * @port_id: Port ID within the node in which the server is hosted.
910 *
911 * This function removes the server_port identified using <node_id:port_id>
912 * from the server structure. If the server_port list under server structure
913 * is empty after removal, then remove the server structure from the server
914 * hash table.
915 * Note: Lock the server_list_lock before accessing this function.
916 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700917static void msm_ipc_router_destroy_server(struct msm_ipc_server *server,
918 uint32_t node_id, uint32_t port_id)
919{
920 struct msm_ipc_server_port *server_port;
921
922 if (!server)
923 return;
924
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700925 list_for_each_entry(server_port, &server->server_port_list, list) {
926 if ((server_port->server_addr.node_id == node_id) &&
927 (server_port->server_addr.port_id == port_id))
928 break;
929 }
930 if (server_port) {
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -0600931 platform_device_unregister(&server_port->pdev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700932 list_del(&server_port->list);
933 kfree(server_port);
934 }
935 if (list_empty(&server->server_port_list)) {
936 list_del(&server->list);
937 kfree(server);
938 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700939 return;
940}
941
942static int msm_ipc_router_send_control_msg(
943 struct msm_ipc_router_xprt_info *xprt_info,
944 union rr_control_msg *msg)
945{
946 struct rr_packet *pkt;
947 struct sk_buff *ipc_rtr_pkt;
948 struct rr_header *hdr;
949 int pkt_size;
950 void *data;
951 struct sk_buff_head *pkt_fragment_q;
952 int ret;
953
954 if (!xprt_info || ((msg->cmd != IPC_ROUTER_CTRL_CMD_HELLO) &&
955 !xprt_info->initialized)) {
956 pr_err("%s: xprt_info not initialized\n", __func__);
957 return -EINVAL;
958 }
959
960 if (xprt_info->remote_node_id == IPC_ROUTER_NID_LOCAL)
961 return 0;
962
963 pkt = kzalloc(sizeof(struct rr_packet), GFP_KERNEL);
964 if (!pkt) {
965 pr_err("%s: pkt alloc failed\n", __func__);
966 return -ENOMEM;
967 }
968
969 pkt_fragment_q = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
970 if (!pkt_fragment_q) {
971 pr_err("%s: pkt_fragment_q alloc failed\n", __func__);
972 kfree(pkt);
973 return -ENOMEM;
974 }
975 skb_queue_head_init(pkt_fragment_q);
976
977 pkt_size = IPC_ROUTER_HDR_SIZE + sizeof(*msg);
978 ipc_rtr_pkt = alloc_skb(pkt_size, GFP_KERNEL);
979 if (!ipc_rtr_pkt) {
980 pr_err("%s: ipc_rtr_pkt alloc failed\n", __func__);
981 kfree(pkt_fragment_q);
982 kfree(pkt);
983 return -ENOMEM;
984 }
985
986 skb_reserve(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
987 data = skb_put(ipc_rtr_pkt, sizeof(*msg));
988 memcpy(data, msg, sizeof(*msg));
989 hdr = (struct rr_header *)skb_push(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
990 if (!hdr) {
991 pr_err("%s: skb_push failed\n", __func__);
992 kfree_skb(ipc_rtr_pkt);
993 kfree(pkt_fragment_q);
994 kfree(pkt);
995 return -ENOMEM;
996 }
997
998 hdr->version = IPC_ROUTER_VERSION;
999 hdr->type = msg->cmd;
1000 hdr->src_node_id = IPC_ROUTER_NID_LOCAL;
1001 hdr->src_port_id = IPC_ROUTER_ADDRESS;
1002 hdr->confirm_rx = 0;
1003 hdr->size = sizeof(*msg);
1004 hdr->dst_node_id = xprt_info->remote_node_id;
1005 hdr->dst_port_id = IPC_ROUTER_ADDRESS;
1006 skb_queue_tail(pkt_fragment_q, ipc_rtr_pkt);
1007 pkt->pkt_fragment_q = pkt_fragment_q;
1008 pkt->length = pkt_size;
1009
1010 mutex_lock(&xprt_info->tx_lock);
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -07001011 ret = xprt_info->xprt->write(pkt, pkt_size, xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001012 mutex_unlock(&xprt_info->tx_lock);
1013
1014 release_pkt(pkt);
1015 return ret;
1016}
1017
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001018static int msm_ipc_router_send_server_list(uint32_t node_id,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001019 struct msm_ipc_router_xprt_info *xprt_info)
1020{
1021 union rr_control_msg ctl;
1022 struct msm_ipc_server *server;
1023 struct msm_ipc_server_port *server_port;
1024 int i;
1025
1026 if (!xprt_info || !xprt_info->initialized) {
1027 pr_err("%s: Xprt info not initialized\n", __func__);
1028 return -EINVAL;
1029 }
1030
1031 ctl.cmd = IPC_ROUTER_CTRL_CMD_NEW_SERVER;
1032
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001033 for (i = 0; i < SRV_HASH_SIZE; i++) {
1034 list_for_each_entry(server, &server_list[i], list) {
1035 ctl.srv.service = server->name.service;
1036 ctl.srv.instance = server->name.instance;
1037 list_for_each_entry(server_port,
1038 &server->server_port_list, list) {
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001039 if (server_port->server_addr.node_id !=
1040 node_id)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001041 continue;
1042
1043 ctl.srv.node_id =
1044 server_port->server_addr.node_id;
1045 ctl.srv.port_id =
1046 server_port->server_addr.port_id;
1047 msm_ipc_router_send_control_msg(xprt_info,
1048 &ctl);
1049 }
1050 }
1051 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001052
1053 return 0;
1054}
1055
1056#if defined(DEBUG)
1057static char *type_to_str(int i)
1058{
1059 switch (i) {
1060 case IPC_ROUTER_CTRL_CMD_DATA:
1061 return "data ";
1062 case IPC_ROUTER_CTRL_CMD_HELLO:
1063 return "hello ";
1064 case IPC_ROUTER_CTRL_CMD_BYE:
1065 return "bye ";
1066 case IPC_ROUTER_CTRL_CMD_NEW_SERVER:
1067 return "new_srvr";
1068 case IPC_ROUTER_CTRL_CMD_REMOVE_SERVER:
1069 return "rmv_srvr";
1070 case IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT:
1071 return "rmv_clnt";
1072 case IPC_ROUTER_CTRL_CMD_RESUME_TX:
1073 return "resum_tx";
1074 case IPC_ROUTER_CTRL_CMD_EXIT:
1075 return "cmd_exit";
1076 default:
1077 return "invalid";
1078 }
1079}
1080#endif
1081
1082static int broadcast_ctl_msg_locally(union rr_control_msg *msg)
1083{
1084 struct rr_packet *pkt;
1085 struct sk_buff *ipc_rtr_pkt;
1086 struct rr_header *hdr;
1087 int pkt_size;
1088 void *data;
1089 struct sk_buff_head *pkt_fragment_q;
1090 int ret;
1091
1092 pkt = kzalloc(sizeof(struct rr_packet), GFP_KERNEL);
1093 if (!pkt) {
1094 pr_err("%s: pkt alloc failed\n", __func__);
1095 return -ENOMEM;
1096 }
1097
1098 pkt_fragment_q = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
1099 if (!pkt_fragment_q) {
1100 pr_err("%s: pkt_fragment_q alloc failed\n", __func__);
1101 kfree(pkt);
1102 return -ENOMEM;
1103 }
1104 skb_queue_head_init(pkt_fragment_q);
1105
1106 pkt_size = IPC_ROUTER_HDR_SIZE + sizeof(*msg);
1107 ipc_rtr_pkt = alloc_skb(pkt_size, GFP_KERNEL);
1108 if (!ipc_rtr_pkt) {
1109 pr_err("%s: ipc_rtr_pkt alloc failed\n", __func__);
1110 kfree(pkt_fragment_q);
1111 kfree(pkt);
1112 return -ENOMEM;
1113 }
1114
1115 skb_reserve(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
1116 data = skb_put(ipc_rtr_pkt, sizeof(*msg));
1117 memcpy(data, msg, sizeof(*msg));
1118 hdr = (struct rr_header *)skb_push(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
1119 if (!hdr) {
1120 pr_err("%s: skb_push failed\n", __func__);
1121 kfree_skb(ipc_rtr_pkt);
1122 kfree(pkt_fragment_q);
1123 kfree(pkt);
1124 return -ENOMEM;
1125 }
1126 hdr->version = IPC_ROUTER_VERSION;
1127 hdr->type = msg->cmd;
1128 hdr->src_node_id = IPC_ROUTER_NID_LOCAL;
1129 hdr->src_port_id = IPC_ROUTER_ADDRESS;
1130 hdr->confirm_rx = 0;
1131 hdr->size = sizeof(*msg);
1132 hdr->dst_node_id = IPC_ROUTER_NID_LOCAL;
1133 hdr->dst_port_id = IPC_ROUTER_ADDRESS;
1134 skb_queue_tail(pkt_fragment_q, ipc_rtr_pkt);
1135 pkt->pkt_fragment_q = pkt_fragment_q;
1136 pkt->length = pkt_size;
1137
1138 ret = post_control_ports(pkt);
1139 release_pkt(pkt);
1140 return ret;
1141}
1142
1143static int broadcast_ctl_msg(union rr_control_msg *ctl)
1144{
1145 struct msm_ipc_router_xprt_info *xprt_info;
1146
1147 mutex_lock(&xprt_info_list_lock);
1148 list_for_each_entry(xprt_info, &xprt_info_list, list) {
1149 msm_ipc_router_send_control_msg(xprt_info, ctl);
1150 }
1151 mutex_unlock(&xprt_info_list_lock);
1152
1153 return 0;
1154}
1155
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001156static int relay_ctl_msg(struct msm_ipc_router_xprt_info *xprt_info,
1157 union rr_control_msg *ctl)
1158{
1159 struct msm_ipc_router_xprt_info *fwd_xprt_info;
1160
1161 if (!xprt_info || !ctl)
1162 return -EINVAL;
1163
1164 mutex_lock(&xprt_info_list_lock);
1165 list_for_each_entry(fwd_xprt_info, &xprt_info_list, list) {
1166 if (xprt_info->xprt->link_id != fwd_xprt_info->xprt->link_id)
1167 msm_ipc_router_send_control_msg(fwd_xprt_info, ctl);
1168 }
1169 mutex_unlock(&xprt_info_list_lock);
1170
1171 return 0;
1172}
1173
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001174static int relay_msg(struct msm_ipc_router_xprt_info *xprt_info,
1175 struct rr_packet *pkt)
1176{
1177 struct msm_ipc_router_xprt_info *fwd_xprt_info;
1178
1179 if (!xprt_info || !pkt)
1180 return -EINVAL;
1181
1182 mutex_lock(&xprt_info_list_lock);
1183 list_for_each_entry(fwd_xprt_info, &xprt_info_list, list) {
1184 mutex_lock(&fwd_xprt_info->tx_lock);
1185 if (xprt_info->xprt->link_id != fwd_xprt_info->xprt->link_id)
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -07001186 fwd_xprt_info->xprt->write(pkt, pkt->length,
1187 fwd_xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001188 mutex_unlock(&fwd_xprt_info->tx_lock);
1189 }
1190 mutex_unlock(&xprt_info_list_lock);
1191 return 0;
1192}
1193
1194static int forward_msg(struct msm_ipc_router_xprt_info *xprt_info,
1195 struct rr_packet *pkt)
1196{
1197 uint32_t dst_node_id;
1198 struct sk_buff *head_pkt;
1199 struct rr_header *hdr;
1200 struct msm_ipc_router_xprt_info *fwd_xprt_info;
1201 struct msm_ipc_routing_table_entry *rt_entry;
1202
1203 if (!xprt_info || !pkt)
1204 return -EINVAL;
1205
1206 head_pkt = skb_peek(pkt->pkt_fragment_q);
1207 if (!head_pkt)
1208 return -EINVAL;
1209
1210 hdr = (struct rr_header *)head_pkt->data;
1211 dst_node_id = hdr->dst_node_id;
1212 mutex_lock(&routing_table_lock);
1213 rt_entry = lookup_routing_table(dst_node_id);
1214 if (!(rt_entry) || !(rt_entry->xprt_info)) {
1215 mutex_unlock(&routing_table_lock);
1216 pr_err("%s: Routing table not initialized\n", __func__);
1217 return -ENODEV;
1218 }
1219
1220 mutex_lock(&rt_entry->lock);
1221 fwd_xprt_info = rt_entry->xprt_info;
1222 mutex_lock(&fwd_xprt_info->tx_lock);
1223 if (xprt_info->remote_node_id == fwd_xprt_info->remote_node_id) {
1224 mutex_unlock(&fwd_xprt_info->tx_lock);
1225 mutex_unlock(&rt_entry->lock);
1226 mutex_unlock(&routing_table_lock);
1227 pr_err("%s: Discarding Command to route back\n", __func__);
1228 return -EINVAL;
1229 }
1230
1231 if (xprt_info->xprt->link_id == fwd_xprt_info->xprt->link_id) {
1232 mutex_unlock(&fwd_xprt_info->tx_lock);
1233 mutex_unlock(&rt_entry->lock);
1234 mutex_unlock(&routing_table_lock);
1235 pr_err("%s: DST in the same cluster\n", __func__);
1236 return 0;
1237 }
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -07001238 fwd_xprt_info->xprt->write(pkt, pkt->length, fwd_xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001239 mutex_unlock(&fwd_xprt_info->tx_lock);
1240 mutex_unlock(&rt_entry->lock);
1241 mutex_unlock(&routing_table_lock);
1242
1243 return 0;
1244}
1245
Karthikeyan Ramasubramaniandc9c4442013-05-02 17:25:54 -06001246static int msm_ipc_router_send_remove_client(struct comm_mode_info *mode_info,
1247 uint32_t node_id, uint32_t port_id)
1248{
1249 union rr_control_msg msg;
1250 struct msm_ipc_router_xprt_info *tmp_xprt_info;
1251 int mode;
1252 void *xprt_info;
1253 int rc = 0;
1254
1255 if (!mode_info) {
1256 pr_err("%s: NULL mode_info\n", __func__);
1257 return -EINVAL;
1258 }
1259 mode = mode_info->mode;
1260 xprt_info = mode_info->xprt_info;
1261
1262 msg.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT;
1263 msg.cli.node_id = node_id;
1264 msg.cli.port_id = port_id;
1265
1266 if ((mode == SINGLE_LINK_MODE) && xprt_info) {
1267 mutex_lock(&xprt_info_list_lock);
1268 list_for_each_entry(tmp_xprt_info, &xprt_info_list, list) {
1269 if (tmp_xprt_info != xprt_info)
1270 continue;
1271 msm_ipc_router_send_control_msg(tmp_xprt_info, &msg);
1272 break;
1273 }
1274 mutex_unlock(&xprt_info_list_lock);
1275 } else if ((mode == SINGLE_LINK_MODE) && !xprt_info) {
1276 broadcast_ctl_msg_locally(&msg);
1277 } else if (mode == MULTI_LINK_MODE) {
1278 broadcast_ctl_msg(&msg);
1279 broadcast_ctl_msg_locally(&msg);
1280 } else if (mode != NULL_MODE) {
1281 pr_err("%s: Invalid mode(%d) + xprt_inf(%p) for %08x:%08x\n",
1282 __func__, mode, xprt_info, node_id, port_id);
1283 rc = -EINVAL;
1284 }
1285 return rc;
1286}
1287
1288static void update_comm_mode_info(struct comm_mode_info *mode_info,
1289 struct msm_ipc_router_xprt_info *xprt_info)
1290{
1291 if (!mode_info) {
1292 pr_err("%s: NULL mode_info\n", __func__);
1293 return;
1294 }
1295
1296 if (mode_info->mode == NULL_MODE) {
1297 mode_info->xprt_info = xprt_info;
1298 mode_info->mode = SINGLE_LINK_MODE;
1299 } else if (mode_info->mode == SINGLE_LINK_MODE &&
1300 mode_info->xprt_info != xprt_info) {
1301 mode_info->mode = MULTI_LINK_MODE;
1302 }
1303
1304 return;
1305}
1306
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001307static void reset_remote_port_info(uint32_t node_id, uint32_t port_id)
1308{
1309 struct msm_ipc_router_remote_port *rport_ptr;
1310
1311 rport_ptr = msm_ipc_router_lookup_remote_port(node_id, port_id);
1312 if (!rport_ptr) {
1313 pr_err("%s: No such remote port %08x:%08x\n",
1314 __func__, node_id, port_id);
1315 return;
1316 }
1317 mutex_lock(&rport_ptr->quota_lock);
1318 rport_ptr->restart_state = RESTART_PEND;
Zaheerulla Meera34fc662013-04-17 01:16:47 +05301319 msm_ipc_router_free_resume_tx_port(rport_ptr);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001320 mutex_unlock(&rport_ptr->quota_lock);
1321 return;
1322}
1323
1324static void msm_ipc_cleanup_remote_server_info(
1325 struct msm_ipc_router_xprt_info *xprt_info)
1326{
1327 struct msm_ipc_server *svr, *tmp_svr;
1328 struct msm_ipc_server_port *svr_port, *tmp_svr_port;
1329 int i;
1330 union rr_control_msg ctl;
1331
1332 if (!xprt_info) {
1333 pr_err("%s: Invalid xprt_info\n", __func__);
1334 return;
1335 }
1336
1337 ctl.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_SERVER;
1338 mutex_lock(&server_list_lock);
1339 for (i = 0; i < SRV_HASH_SIZE; i++) {
1340 list_for_each_entry_safe(svr, tmp_svr, &server_list[i], list) {
1341 ctl.srv.service = svr->name.service;
1342 ctl.srv.instance = svr->name.instance;
1343 list_for_each_entry_safe(svr_port, tmp_svr_port,
1344 &svr->server_port_list, list) {
1345 if (svr_port->xprt_info != xprt_info)
1346 continue;
1347 D("Remove server %08x:%08x - %08x:%08x",
1348 ctl.srv.service, ctl.srv.instance,
1349 svr_port->server_addr.node_id,
1350 svr_port->server_addr.port_id);
1351 reset_remote_port_info(
1352 svr_port->server_addr.node_id,
1353 svr_port->server_addr.port_id);
1354 ctl.srv.node_id = svr_port->server_addr.node_id;
1355 ctl.srv.port_id = svr_port->server_addr.port_id;
1356 relay_ctl_msg(xprt_info, &ctl);
1357 broadcast_ctl_msg_locally(&ctl);
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -06001358 platform_device_unregister(&svr_port->pdev);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001359 list_del(&svr_port->list);
1360 kfree(svr_port);
1361 }
1362 if (list_empty(&svr->server_port_list)) {
1363 list_del(&svr->list);
1364 kfree(svr);
1365 }
1366 }
1367 }
1368 mutex_unlock(&server_list_lock);
1369}
1370
1371static void msm_ipc_cleanup_remote_client_info(
1372 struct msm_ipc_router_xprt_info *xprt_info)
1373{
1374 struct msm_ipc_routing_table_entry *rt_entry;
1375 struct msm_ipc_router_remote_port *rport_ptr;
1376 int i, j;
1377 union rr_control_msg ctl;
1378
1379 if (!xprt_info) {
1380 pr_err("%s: Invalid xprt_info\n", __func__);
1381 return;
1382 }
1383
1384 ctl.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT;
1385 mutex_lock(&routing_table_lock);
1386 for (i = 0; i < RT_HASH_SIZE; i++) {
1387 list_for_each_entry(rt_entry, &routing_table[i], list) {
1388 mutex_lock(&rt_entry->lock);
1389 if (rt_entry->xprt_info != xprt_info) {
1390 mutex_unlock(&rt_entry->lock);
1391 continue;
1392 }
1393 for (j = 0; j < RP_HASH_SIZE; j++) {
1394 list_for_each_entry(rport_ptr,
1395 &rt_entry->remote_port_list[j], list) {
1396 if (rport_ptr->restart_state ==
1397 RESTART_PEND)
1398 continue;
1399 mutex_lock(&rport_ptr->quota_lock);
1400 rport_ptr->restart_state = RESTART_PEND;
Zaheerulla Meera34fc662013-04-17 01:16:47 +05301401 msm_ipc_router_free_resume_tx_port(
1402 rport_ptr);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001403 mutex_unlock(&rport_ptr->quota_lock);
1404 ctl.cli.node_id = rport_ptr->node_id;
1405 ctl.cli.port_id = rport_ptr->port_id;
1406 broadcast_ctl_msg_locally(&ctl);
1407 }
1408 }
1409 mutex_unlock(&rt_entry->lock);
1410 }
1411 }
1412 mutex_unlock(&routing_table_lock);
1413}
1414
1415static void msm_ipc_cleanup_remote_port_info(uint32_t node_id)
1416{
1417 struct msm_ipc_routing_table_entry *rt_entry, *tmp_rt_entry;
1418 struct msm_ipc_router_remote_port *rport_ptr, *tmp_rport_ptr;
1419 int i, j;
1420
1421 mutex_lock(&routing_table_lock);
1422 for (i = 0; i < RT_HASH_SIZE; i++) {
1423 list_for_each_entry_safe(rt_entry, tmp_rt_entry,
1424 &routing_table[i], list) {
1425 mutex_lock(&rt_entry->lock);
1426 if (rt_entry->neighbor_node_id != node_id) {
1427 mutex_unlock(&rt_entry->lock);
1428 continue;
1429 }
1430 for (j = 0; j < RP_HASH_SIZE; j++) {
1431 list_for_each_entry_safe(rport_ptr,
1432 tmp_rport_ptr,
1433 &rt_entry->remote_port_list[j], list) {
1434 list_del(&rport_ptr->list);
1435 kfree(rport_ptr);
1436 }
1437 }
1438 mutex_unlock(&rt_entry->lock);
1439 }
1440 }
1441 mutex_unlock(&routing_table_lock);
1442}
1443
1444static void msm_ipc_cleanup_routing_table(
1445 struct msm_ipc_router_xprt_info *xprt_info)
1446{
1447 int i;
1448 struct msm_ipc_routing_table_entry *rt_entry;
1449
1450 if (!xprt_info) {
1451 pr_err("%s: Invalid xprt_info\n", __func__);
1452 return;
1453 }
1454
1455 mutex_lock(&routing_table_lock);
1456 for (i = 0; i < RT_HASH_SIZE; i++) {
1457 list_for_each_entry(rt_entry, &routing_table[i], list) {
1458 mutex_lock(&rt_entry->lock);
1459 if (rt_entry->xprt_info == xprt_info)
1460 rt_entry->xprt_info = NULL;
1461 mutex_unlock(&rt_entry->lock);
1462 }
1463 }
1464 mutex_unlock(&routing_table_lock);
1465}
1466
1467static void modem_reset_cleanup(struct msm_ipc_router_xprt_info *xprt_info)
1468{
1469
1470 if (!xprt_info) {
1471 pr_err("%s: Invalid xprt_info\n", __func__);
1472 return;
1473 }
1474
1475 msm_ipc_cleanup_remote_server_info(xprt_info);
1476 msm_ipc_cleanup_remote_client_info(xprt_info);
1477 msm_ipc_cleanup_routing_table(xprt_info);
1478}
1479
Karthikeyan Ramasubramanian1668cc62012-09-23 22:23:36 -06001480/**
1481 * sync_sec_rule() - Synchrnoize the security rule into the server structure
1482 * @server: Server structure where the rule has to be synchronized.
1483 * @rule: Security tule to be synchronized.
1484 *
1485 * This function is used to update the server structure with the security
1486 * rule configured for the <service:instance> corresponding to that server.
1487 */
1488static void sync_sec_rule(struct msm_ipc_server *server, void *rule)
1489{
1490 struct msm_ipc_server_port *server_port;
1491 struct msm_ipc_router_remote_port *rport_ptr = NULL;
1492
1493 list_for_each_entry(server_port, &server->server_port_list, list) {
1494 rport_ptr = msm_ipc_router_lookup_remote_port(
1495 server_port->server_addr.node_id,
1496 server_port->server_addr.port_id);
1497 if (!rport_ptr)
1498 continue;
1499 rport_ptr->sec_rule = rule;
1500 }
1501 server->synced_sec_rule = 1;
1502}
1503
1504/**
1505 * msm_ipc_sync_sec_rule() - Sync the security rule to the service
1506 * @service: Service for which the rule has to be synchronized.
1507 * @instance: Instance for which the rule has to be synchronized.
1508 * @rule: Security rule to be synchronized.
1509 *
1510 * This function is used to syncrhonize the security rule with the server
1511 * hash table, if the user-space script configures the rule after the service
1512 * has come up. This function is used to synchronize the security rule to a
1513 * specific service and optionally a specific instance.
1514 */
1515void msm_ipc_sync_sec_rule(uint32_t service, uint32_t instance, void *rule)
1516{
1517 int key = (service & (SRV_HASH_SIZE - 1));
1518 struct msm_ipc_server *server;
1519
1520 mutex_lock(&server_list_lock);
1521 list_for_each_entry(server, &server_list[key], list) {
1522 if (server->name.service != service)
1523 continue;
1524
1525 if (server->name.instance != instance &&
1526 instance != ALL_INSTANCE)
1527 continue;
1528
1529 /*
1530 * If the rule applies to all instances and if the specific
1531 * instance of a service has a rule synchronized already,
1532 * do not apply the rule for that specific instance.
1533 */
1534 if (instance == ALL_INSTANCE && server->synced_sec_rule)
1535 continue;
1536
1537 sync_sec_rule(server, rule);
1538 }
1539 mutex_unlock(&server_list_lock);
1540}
1541
1542/**
1543 * msm_ipc_sync_default_sec_rule() - Default security rule to all services
1544 * @rule: Security rule to be synchronized.
1545 *
1546 * This function is used to syncrhonize the security rule with the server
1547 * hash table, if the user-space script configures the rule after the service
1548 * has come up. This function is used to synchronize the security rule that
1549 * applies to all services, if the concerned service do not have any rule
1550 * defined.
1551 */
1552void msm_ipc_sync_default_sec_rule(void *rule)
1553{
1554 int key;
1555 struct msm_ipc_server *server;
1556
1557 mutex_lock(&server_list_lock);
1558 for (key = 0; key < SRV_HASH_SIZE; key++) {
1559 list_for_each_entry(server, &server_list[key], list) {
1560 if (server->synced_sec_rule)
1561 continue;
1562
1563 sync_sec_rule(server, rule);
1564 }
1565 }
1566 mutex_unlock(&server_list_lock);
1567}
1568
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001569static int process_hello_msg(struct msm_ipc_router_xprt_info *xprt_info,
1570 struct rr_header *hdr)
1571{
1572 int i, rc = 0;
1573 union rr_control_msg ctl;
1574 struct msm_ipc_routing_table_entry *rt_entry;
1575
1576 if (!hdr)
1577 return -EINVAL;
1578
1579 RR("o HELLO NID %d\n", hdr->src_node_id);
1580
1581 xprt_info->remote_node_id = hdr->src_node_id;
1582 /*
1583 * Find the entry from Routing Table corresponding to Node ID.
1584 * Under SSR, an entry will be found. When the system boots up
1585 * for the 1st time, an entry will not be found and hence allocate
1586 * an entry. Update the entry with the Node ID that it corresponds
1587 * to and the XPRT through which it can be reached.
1588 */
1589 mutex_lock(&routing_table_lock);
1590 rt_entry = lookup_routing_table(hdr->src_node_id);
1591 if (!rt_entry) {
1592 rt_entry = alloc_routing_table_entry(hdr->src_node_id);
1593 if (!rt_entry) {
1594 mutex_unlock(&routing_table_lock);
1595 pr_err("%s: rt_entry allocation failed\n", __func__);
1596 return -ENOMEM;
1597 }
1598 add_routing_table_entry(rt_entry);
1599 }
1600 mutex_lock(&rt_entry->lock);
1601 rt_entry->neighbor_node_id = xprt_info->remote_node_id;
1602 rt_entry->xprt_info = xprt_info;
1603 mutex_unlock(&rt_entry->lock);
1604 mutex_unlock(&routing_table_lock);
1605
1606 /* Cleanup any remote ports, if the node is coming out of reset */
1607 msm_ipc_cleanup_remote_port_info(xprt_info->remote_node_id);
1608
1609 /* Send a reply HELLO message */
1610 memset(&ctl, 0, sizeof(ctl));
1611 ctl.cmd = IPC_ROUTER_CTRL_CMD_HELLO;
1612 rc = msm_ipc_router_send_control_msg(xprt_info, &ctl);
1613 if (rc < 0) {
1614 pr_err("%s: Error sending reply HELLO message\n", __func__);
1615 return rc;
1616 }
1617 xprt_info->initialized = 1;
1618
1619 /*
1620 * Send list of servers from the local node and from nodes
1621 * outside the mesh network in which this XPRT is part of.
1622 */
Karthikeyan Ramasubramaniane8ad5352012-10-31 15:12:08 -06001623 mutex_lock(&server_list_lock);
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001624 mutex_lock(&routing_table_lock);
1625 for (i = 0; i < RT_HASH_SIZE; i++) {
1626 list_for_each_entry(rt_entry, &routing_table[i], list) {
1627 if ((rt_entry->node_id != IPC_ROUTER_NID_LOCAL) &&
Karthikeyan Ramasubramanian72ad5792013-01-30 14:17:57 -07001628 (!rt_entry->xprt_info ||
1629 (rt_entry->xprt_info->xprt->link_id ==
1630 xprt_info->xprt->link_id)))
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001631 continue;
1632 rc = msm_ipc_router_send_server_list(rt_entry->node_id,
1633 xprt_info);
1634 if (rc < 0) {
1635 mutex_unlock(&routing_table_lock);
Karthikeyan Ramasubramaniane8ad5352012-10-31 15:12:08 -06001636 mutex_unlock(&server_list_lock);
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001637 return rc;
1638 }
1639 }
1640 }
1641 mutex_unlock(&routing_table_lock);
Karthikeyan Ramasubramaniane8ad5352012-10-31 15:12:08 -06001642 mutex_unlock(&server_list_lock);
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001643 RR("HELLO message processed\n");
1644 return rc;
1645}
1646
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001647static int process_control_msg(struct msm_ipc_router_xprt_info *xprt_info,
1648 struct rr_packet *pkt)
1649{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001650 union rr_control_msg *msg;
1651 struct msm_ipc_router_remote_port *rport_ptr;
1652 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001653 struct sk_buff *temp_ptr;
1654 struct rr_header *hdr;
1655 struct msm_ipc_server *server;
1656 struct msm_ipc_routing_table_entry *rt_entry;
1657
1658 if (pkt->length != (IPC_ROUTER_HDR_SIZE + sizeof(*msg))) {
1659 pr_err("%s: r2r msg size %d != %d\n", __func__, pkt->length,
1660 (IPC_ROUTER_HDR_SIZE + sizeof(*msg)));
1661 return -EINVAL;
1662 }
1663
1664 temp_ptr = skb_peek(pkt->pkt_fragment_q);
Karthikeyan Ramasubramanian9024dd82011-12-19 18:44:19 -07001665 if (!temp_ptr) {
1666 pr_err("%s: pkt_fragment_q is empty\n", __func__);
1667 return -EINVAL;
1668 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001669 hdr = (struct rr_header *)temp_ptr->data;
Karthikeyan Ramasubramanian9024dd82011-12-19 18:44:19 -07001670 if (!hdr) {
1671 pr_err("%s: No data inside the skb\n", __func__);
1672 return -EINVAL;
1673 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001674 msg = (union rr_control_msg *)((char *)hdr + IPC_ROUTER_HDR_SIZE);
1675
1676 switch (msg->cmd) {
1677 case IPC_ROUTER_CTRL_CMD_HELLO:
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001678 rc = process_hello_msg(xprt_info, hdr);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001679 break;
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001680
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001681 case IPC_ROUTER_CTRL_CMD_RESUME_TX:
1682 RR("o RESUME_TX id=%d:%08x\n",
1683 msg->cli.node_id, msg->cli.port_id);
1684
1685 rport_ptr = msm_ipc_router_lookup_remote_port(msg->cli.node_id,
1686 msg->cli.port_id);
1687 if (!rport_ptr) {
1688 pr_err("%s: Unable to resume client\n", __func__);
1689 break;
1690 }
1691 mutex_lock(&rport_ptr->quota_lock);
1692 rport_ptr->tx_quota_cnt = 0;
Zaheerulla Meera34fc662013-04-17 01:16:47 +05301693 post_resume_tx(rport_ptr, pkt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001694 mutex_unlock(&rport_ptr->quota_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001695 break;
1696
1697 case IPC_ROUTER_CTRL_CMD_NEW_SERVER:
1698 if (msg->srv.instance == 0) {
1699 pr_err(
1700 "rpcrouter: Server create rejected, version = 0, "
1701 "service = %08x\n", msg->srv.service);
1702 break;
1703 }
1704
1705 RR("o NEW_SERVER id=%d:%08x service=%08x:%08x\n",
1706 msg->srv.node_id, msg->srv.port_id,
1707 msg->srv.service, msg->srv.instance);
1708
1709 mutex_lock(&routing_table_lock);
1710 rt_entry = lookup_routing_table(msg->srv.node_id);
1711 if (!rt_entry) {
1712 rt_entry = alloc_routing_table_entry(msg->srv.node_id);
1713 if (!rt_entry) {
1714 mutex_unlock(&routing_table_lock);
1715 pr_err("%s: rt_entry allocation failed\n",
1716 __func__);
1717 return -ENOMEM;
1718 }
1719 mutex_lock(&rt_entry->lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001720 rt_entry->neighbor_node_id = xprt_info->remote_node_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001721 rt_entry->xprt_info = xprt_info;
1722 mutex_unlock(&rt_entry->lock);
1723 add_routing_table_entry(rt_entry);
1724 }
1725 mutex_unlock(&routing_table_lock);
1726
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001727 mutex_lock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001728 server = msm_ipc_router_lookup_server(msg->srv.service,
1729 msg->srv.instance,
1730 msg->srv.node_id,
1731 msg->srv.port_id);
1732 if (!server) {
1733 server = msm_ipc_router_create_server(
1734 msg->srv.service, msg->srv.instance,
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001735 msg->srv.node_id, msg->srv.port_id, xprt_info);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001736 if (!server) {
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001737 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001738 pr_err("%s: Server Create failed\n", __func__);
1739 return -ENOMEM;
1740 }
1741
1742 if (!msm_ipc_router_lookup_remote_port(
1743 msg->srv.node_id, msg->srv.port_id)) {
1744 rport_ptr = msm_ipc_router_create_remote_port(
1745 msg->srv.node_id, msg->srv.port_id);
1746 if (!rport_ptr)
1747 pr_err("%s: Remote port create "
1748 "failed\n", __func__);
Brent Hronik0e83d3b2013-05-01 16:25:00 -06001749 else
1750 rport_ptr->sec_rule =
1751 msm_ipc_get_security_rule(
1752 msg->srv.service,
1753 msg->srv.instance);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001754 }
1755 wake_up(&newserver_wait);
1756 }
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001757 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001758
1759 relay_msg(xprt_info, pkt);
1760 post_control_ports(pkt);
1761 break;
1762 case IPC_ROUTER_CTRL_CMD_REMOVE_SERVER:
1763 RR("o REMOVE_SERVER service=%08x:%d\n",
1764 msg->srv.service, msg->srv.instance);
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001765 mutex_lock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001766 server = msm_ipc_router_lookup_server(msg->srv.service,
1767 msg->srv.instance,
1768 msg->srv.node_id,
1769 msg->srv.port_id);
1770 if (server) {
1771 msm_ipc_router_destroy_server(server,
1772 msg->srv.node_id,
1773 msg->srv.port_id);
1774 relay_msg(xprt_info, pkt);
1775 post_control_ports(pkt);
1776 }
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001777 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001778 break;
1779 case IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT:
1780 RR("o REMOVE_CLIENT id=%d:%08x\n",
1781 msg->cli.node_id, msg->cli.port_id);
1782 rport_ptr = msm_ipc_router_lookup_remote_port(msg->cli.node_id,
1783 msg->cli.port_id);
1784 if (rport_ptr)
1785 msm_ipc_router_destroy_remote_port(rport_ptr);
1786
1787 relay_msg(xprt_info, pkt);
1788 post_control_ports(pkt);
1789 break;
1790 case IPC_ROUTER_CTRL_CMD_PING:
1791 /* No action needed for ping messages received */
1792 RR("o PING\n");
1793 break;
1794 default:
1795 RR("o UNKNOWN(%08x)\n", msg->cmd);
1796 rc = -ENOSYS;
1797 }
1798
1799 return rc;
1800}
1801
1802static void do_read_data(struct work_struct *work)
1803{
1804 struct rr_header *hdr;
1805 struct rr_packet *pkt = NULL;
1806 struct msm_ipc_port *port_ptr;
1807 struct sk_buff *head_skb;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001808 struct msm_ipc_router_remote_port *rport_ptr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001809 uint32_t resume_tx, resume_tx_node_id, resume_tx_port_id;
1810
1811 struct msm_ipc_router_xprt_info *xprt_info =
1812 container_of(work,
1813 struct msm_ipc_router_xprt_info,
1814 read_data);
1815
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001816 while ((pkt = rr_read(xprt_info)) != NULL) {
1817 if (pkt->length < IPC_ROUTER_HDR_SIZE ||
1818 pkt->length > MAX_IPC_PKT_SIZE) {
1819 pr_err("%s: Invalid pkt length %d\n",
1820 __func__, pkt->length);
1821 goto fail_data;
1822 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001823
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001824 head_skb = skb_peek(pkt->pkt_fragment_q);
1825 if (!head_skb) {
1826 pr_err("%s: head_skb is invalid\n", __func__);
1827 goto fail_data;
1828 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001829
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001830 hdr = (struct rr_header *)(head_skb->data);
Karthikeyan Ramasubramanian682ebcc2013-03-22 10:47:20 -06001831 RAW("ver=%d type=%d src=%d:%08x crx=%d siz=%d dst=%d:%08x\n",
1832 hdr->version, hdr->type, hdr->src_node_id,
1833 hdr->src_port_id, hdr->confirm_rx, hdr->size,
1834 hdr->dst_node_id, hdr->dst_port_id);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001835
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001836 if (hdr->version != IPC_ROUTER_VERSION) {
1837 pr_err("version %d != %d\n",
1838 hdr->version, IPC_ROUTER_VERSION);
1839 goto fail_data;
1840 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001841
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001842 if ((hdr->dst_node_id != IPC_ROUTER_NID_LOCAL) &&
1843 ((hdr->type == IPC_ROUTER_CTRL_CMD_RESUME_TX) ||
1844 (hdr->type == IPC_ROUTER_CTRL_CMD_DATA))) {
1845 forward_msg(xprt_info, pkt);
1846 release_pkt(pkt);
1847 continue;
1848 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001849
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001850 if ((hdr->dst_port_id == IPC_ROUTER_ADDRESS) ||
1851 (hdr->type == IPC_ROUTER_CTRL_CMD_HELLO)) {
1852 process_control_msg(xprt_info, pkt);
1853 release_pkt(pkt);
1854 continue;
1855 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001856#if defined(CONFIG_MSM_SMD_LOGGING)
1857#if defined(DEBUG)
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001858 if (msm_ipc_router_debug_mask & SMEM_LOG) {
1859 smem_log_event((SMEM_LOG_PROC_ID_APPS |
1860 SMEM_LOG_RPC_ROUTER_EVENT_BASE |
1861 IPC_ROUTER_LOG_EVENT_RX),
1862 (hdr->src_node_id << 24) |
1863 (hdr->src_port_id & 0xffffff),
1864 (hdr->dst_node_id << 24) |
1865 (hdr->dst_port_id & 0xffffff),
1866 (hdr->type << 24) | (hdr->confirm_rx << 16) |
1867 (hdr->size & 0xffff));
1868 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001869#endif
1870#endif
1871
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001872 resume_tx = hdr->confirm_rx;
1873 resume_tx_node_id = hdr->dst_node_id;
1874 resume_tx_port_id = hdr->dst_port_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001875
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001876 rport_ptr = msm_ipc_router_lookup_remote_port(hdr->src_node_id,
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06001877 hdr->src_port_id);
1878
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001879 mutex_lock(&local_ports_lock);
1880 port_ptr = msm_ipc_router_lookup_local_port(hdr->dst_port_id);
1881 if (!port_ptr) {
1882 pr_err("%s: No local port id %08x\n", __func__,
1883 hdr->dst_port_id);
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06001884 mutex_unlock(&local_ports_lock);
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001885 release_pkt(pkt);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001886 goto process_done;
1887 }
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001888
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001889 if (!rport_ptr) {
1890 rport_ptr = msm_ipc_router_create_remote_port(
1891 hdr->src_node_id,
1892 hdr->src_port_id);
1893 if (!rport_ptr) {
1894 pr_err("%s: Rmt Prt %08x:%08x create failed\n",
1895 __func__, hdr->src_node_id,
1896 hdr->src_port_id);
1897 mutex_unlock(&local_ports_lock);
1898 goto process_done;
1899 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001900 }
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001901
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -06001902 mutex_lock(&port_ptr->port_rx_q_lock);
1903 wake_lock(&port_ptr->port_rx_wake_lock);
1904 list_add_tail(&pkt->list, &port_ptr->port_rx_q);
1905 wake_up(&port_ptr->port_rx_wait_q);
1906 if (port_ptr->notify)
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001907 port_ptr->notify(MSM_IPC_ROUTER_READ_CB,
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -06001908 port_ptr->priv);
1909 mutex_unlock(&port_ptr->port_rx_q_lock);
1910 mutex_unlock(&local_ports_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001911
1912process_done:
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001913 if (resume_tx) {
1914 union rr_control_msg msg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001915
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001916 msg.cmd = IPC_ROUTER_CTRL_CMD_RESUME_TX;
1917 msg.cli.node_id = resume_tx_node_id;
1918 msg.cli.port_id = resume_tx_port_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001919
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001920 RR("x RESUME_TX id=%d:%08x\n",
1921 msg.cli.node_id, msg.cli.port_id);
1922 msm_ipc_router_send_control_msg(xprt_info, &msg);
1923 }
1924
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001925 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001926 return;
1927
1928fail_data:
1929 release_pkt(pkt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001930 pr_err("ipc_router has died\n");
1931}
1932
1933int msm_ipc_router_register_server(struct msm_ipc_port *port_ptr,
1934 struct msm_ipc_addr *name)
1935{
1936 struct msm_ipc_server *server;
1937 unsigned long flags;
1938 union rr_control_msg ctl;
1939
1940 if (!port_ptr || !name)
1941 return -EINVAL;
1942
1943 if (name->addrtype != MSM_IPC_ADDR_NAME)
1944 return -EINVAL;
1945
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001946 mutex_lock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001947 server = msm_ipc_router_lookup_server(name->addr.port_name.service,
1948 name->addr.port_name.instance,
1949 IPC_ROUTER_NID_LOCAL,
1950 port_ptr->this_port.port_id);
1951 if (server) {
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001952 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001953 pr_err("%s: Server already present\n", __func__);
1954 return -EINVAL;
1955 }
1956
1957 server = msm_ipc_router_create_server(name->addr.port_name.service,
1958 name->addr.port_name.instance,
1959 IPC_ROUTER_NID_LOCAL,
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001960 port_ptr->this_port.port_id,
1961 NULL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001962 if (!server) {
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001963 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001964 pr_err("%s: Server Creation failed\n", __func__);
1965 return -EINVAL;
1966 }
1967
1968 ctl.cmd = IPC_ROUTER_CTRL_CMD_NEW_SERVER;
1969 ctl.srv.service = server->name.service;
1970 ctl.srv.instance = server->name.instance;
1971 ctl.srv.node_id = IPC_ROUTER_NID_LOCAL;
1972 ctl.srv.port_id = port_ptr->this_port.port_id;
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001973 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001974 broadcast_ctl_msg(&ctl);
1975 spin_lock_irqsave(&port_ptr->port_lock, flags);
1976 port_ptr->type = SERVER_PORT;
Karthikeyan Ramasubramaniandc9c4442013-05-02 17:25:54 -06001977 port_ptr->mode_info.mode = MULTI_LINK_MODE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001978 port_ptr->port_name.service = server->name.service;
1979 port_ptr->port_name.instance = server->name.instance;
1980 spin_unlock_irqrestore(&port_ptr->port_lock, flags);
1981 return 0;
1982}
1983
1984int msm_ipc_router_unregister_server(struct msm_ipc_port *port_ptr)
1985{
1986 struct msm_ipc_server *server;
1987 unsigned long flags;
1988 union rr_control_msg ctl;
1989
1990 if (!port_ptr)
1991 return -EINVAL;
1992
1993 if (port_ptr->type != SERVER_PORT) {
1994 pr_err("%s: Trying to unregister a non-server port\n",
1995 __func__);
1996 return -EINVAL;
1997 }
1998
1999 if (port_ptr->this_port.node_id != IPC_ROUTER_NID_LOCAL) {
2000 pr_err("%s: Trying to unregister a remote server locally\n",
2001 __func__);
2002 return -EINVAL;
2003 }
2004
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002005 mutex_lock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002006 server = msm_ipc_router_lookup_server(port_ptr->port_name.service,
2007 port_ptr->port_name.instance,
2008 port_ptr->this_port.node_id,
2009 port_ptr->this_port.port_id);
2010 if (!server) {
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002011 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002012 pr_err("%s: Server lookup failed\n", __func__);
2013 return -ENODEV;
2014 }
2015
2016 ctl.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_SERVER;
2017 ctl.srv.service = server->name.service;
2018 ctl.srv.instance = server->name.instance;
2019 ctl.srv.node_id = IPC_ROUTER_NID_LOCAL;
2020 ctl.srv.port_id = port_ptr->this_port.port_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002021 msm_ipc_router_destroy_server(server, port_ptr->this_port.node_id,
2022 port_ptr->this_port.port_id);
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002023 mutex_unlock(&server_list_lock);
2024 broadcast_ctl_msg(&ctl);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002025 spin_lock_irqsave(&port_ptr->port_lock, flags);
2026 port_ptr->type = CLIENT_PORT;
2027 spin_unlock_irqrestore(&port_ptr->port_lock, flags);
2028 return 0;
2029}
2030
2031static int loopback_data(struct msm_ipc_port *src,
2032 uint32_t port_id,
2033 struct sk_buff_head *data)
2034{
2035 struct sk_buff *head_skb;
2036 struct rr_header *hdr;
2037 struct msm_ipc_port *port_ptr;
2038 struct rr_packet *pkt;
Karthikeyan Ramasubramanian0a801c12013-02-08 13:07:42 -07002039 int ret_len;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002040
2041 if (!data) {
2042 pr_err("%s: Invalid pkt pointer\n", __func__);
2043 return -EINVAL;
2044 }
2045
2046 pkt = create_pkt(data);
2047 if (!pkt) {
2048 pr_err("%s: New pkt create failed\n", __func__);
2049 return -ENOMEM;
2050 }
2051
2052 head_skb = skb_peek(pkt->pkt_fragment_q);
Karthikeyan Ramasubramanian9024dd82011-12-19 18:44:19 -07002053 if (!head_skb) {
2054 pr_err("%s: pkt_fragment_q is empty\n", __func__);
Brent Hronik0e83d3b2013-05-01 16:25:00 -06002055 release_pkt(pkt);
Karthikeyan Ramasubramanian9024dd82011-12-19 18:44:19 -07002056 return -EINVAL;
2057 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002058 hdr = (struct rr_header *)skb_push(head_skb, IPC_ROUTER_HDR_SIZE);
2059 if (!hdr) {
2060 pr_err("%s: Prepend Header failed\n", __func__);
2061 release_pkt(pkt);
2062 return -ENOMEM;
2063 }
2064 hdr->version = IPC_ROUTER_VERSION;
2065 hdr->type = IPC_ROUTER_CTRL_CMD_DATA;
2066 hdr->src_node_id = src->this_port.node_id;
2067 hdr->src_port_id = src->this_port.port_id;
2068 hdr->size = pkt->length;
2069 hdr->confirm_rx = 0;
2070 hdr->dst_node_id = IPC_ROUTER_NID_LOCAL;
2071 hdr->dst_port_id = port_id;
2072 pkt->length += IPC_ROUTER_HDR_SIZE;
2073
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06002074 mutex_lock(&local_ports_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002075 port_ptr = msm_ipc_router_lookup_local_port(port_id);
2076 if (!port_ptr) {
2077 pr_err("%s: Local port %d not present\n", __func__, port_id);
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06002078 mutex_unlock(&local_ports_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002079 release_pkt(pkt);
2080 return -ENODEV;
2081 }
2082
2083 mutex_lock(&port_ptr->port_rx_q_lock);
2084 wake_lock(&port_ptr->port_rx_wake_lock);
2085 list_add_tail(&pkt->list, &port_ptr->port_rx_q);
Karthikeyan Ramasubramanian0a801c12013-02-08 13:07:42 -07002086 ret_len = pkt->length;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002087 wake_up(&port_ptr->port_rx_wait_q);
2088 mutex_unlock(&port_ptr->port_rx_q_lock);
Karthikeyan Ramasubramaniandc9c4442013-05-02 17:25:54 -06002089 update_comm_mode_info(&src->mode_info, NULL);
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06002090 mutex_unlock(&local_ports_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002091
Karthikeyan Ramasubramanian0a801c12013-02-08 13:07:42 -07002092 return ret_len;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002093}
2094
2095static int msm_ipc_router_write_pkt(struct msm_ipc_port *src,
2096 struct msm_ipc_router_remote_port *rport_ptr,
2097 struct rr_packet *pkt)
2098{
2099 struct sk_buff *head_skb;
2100 struct rr_header *hdr;
2101 struct msm_ipc_router_xprt_info *xprt_info;
2102 struct msm_ipc_routing_table_entry *rt_entry;
Zaheerulla Meera34fc662013-04-17 01:16:47 +05302103 struct msm_ipc_resume_tx_port *resume_tx_port;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002104 int ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002105
2106 if (!rport_ptr || !src || !pkt)
2107 return -EINVAL;
2108
2109 head_skb = skb_peek(pkt->pkt_fragment_q);
Karthikeyan Ramasubramanian9024dd82011-12-19 18:44:19 -07002110 if (!head_skb) {
2111 pr_err("%s: pkt_fragment_q is empty\n", __func__);
2112 return -EINVAL;
2113 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002114 hdr = (struct rr_header *)skb_push(head_skb, IPC_ROUTER_HDR_SIZE);
2115 if (!hdr) {
2116 pr_err("%s: Prepend Header failed\n", __func__);
2117 return -ENOMEM;
2118 }
2119 hdr->version = IPC_ROUTER_VERSION;
2120 hdr->type = IPC_ROUTER_CTRL_CMD_DATA;
2121 hdr->src_node_id = src->this_port.node_id;
2122 hdr->src_port_id = src->this_port.port_id;
2123 hdr->size = pkt->length;
2124 hdr->confirm_rx = 0;
2125 hdr->dst_node_id = rport_ptr->node_id;
2126 hdr->dst_port_id = rport_ptr->port_id;
2127 pkt->length += IPC_ROUTER_HDR_SIZE;
2128
Zaheerulla Meera34fc662013-04-17 01:16:47 +05302129 mutex_lock(&rport_ptr->quota_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002130 if (rport_ptr->restart_state != RESTART_NORMAL) {
2131 mutex_unlock(&rport_ptr->quota_lock);
2132 return -ENETRESET;
2133 }
Zaheerulla Meera34fc662013-04-17 01:16:47 +05302134 if (rport_ptr->tx_quota_cnt == IPC_ROUTER_DEFAULT_RX_QUOTA) {
2135 if (msm_ipc_router_lookup_resume_tx_port(
2136 rport_ptr, src->this_port.port_id)) {
2137 mutex_unlock(&rport_ptr->quota_lock);
2138 return -EAGAIN;
2139 }
2140 resume_tx_port =
2141 kzalloc(sizeof(struct msm_ipc_resume_tx_port),
2142 GFP_KERNEL);
2143 if (!resume_tx_port) {
2144 pr_err("%s: Resume_Tx port allocation failed\n",
2145 __func__);
2146 mutex_unlock(&rport_ptr->quota_lock);
2147 return -ENOMEM;
2148 }
2149 INIT_LIST_HEAD(&resume_tx_port->list);
2150 resume_tx_port->port_id = src->this_port.port_id;
2151 resume_tx_port->node_id = src->this_port.node_id;
2152 list_add_tail(&resume_tx_port->list,
2153 &rport_ptr->resume_tx_port_list);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002154 mutex_unlock(&rport_ptr->quota_lock);
Zaheerulla Meera34fc662013-04-17 01:16:47 +05302155 return -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002156 }
2157 rport_ptr->tx_quota_cnt++;
2158 if (rport_ptr->tx_quota_cnt == IPC_ROUTER_DEFAULT_RX_QUOTA)
2159 hdr->confirm_rx = 1;
2160 mutex_unlock(&rport_ptr->quota_lock);
2161
2162 mutex_lock(&routing_table_lock);
2163 rt_entry = lookup_routing_table(hdr->dst_node_id);
2164 if (!rt_entry || !rt_entry->xprt_info) {
2165 mutex_unlock(&routing_table_lock);
2166 pr_err("%s: Remote node %d not up\n",
2167 __func__, hdr->dst_node_id);
2168 return -ENODEV;
2169 }
2170 mutex_lock(&rt_entry->lock);
2171 xprt_info = rt_entry->xprt_info;
2172 mutex_lock(&xprt_info->tx_lock);
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -07002173 ret = xprt_info->xprt->write(pkt, pkt->length, xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002174 mutex_unlock(&xprt_info->tx_lock);
2175 mutex_unlock(&rt_entry->lock);
2176 mutex_unlock(&routing_table_lock);
2177
2178 if (ret < 0) {
2179 pr_err("%s: Write on XPRT failed\n", __func__);
2180 return ret;
2181 }
Karthikeyan Ramasubramaniandc9c4442013-05-02 17:25:54 -06002182 update_comm_mode_info(&src->mode_info, xprt_info);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002183
2184 RAW_HDR("[w rr_h] "
2185 "ver=%i,type=%s,src_nid=%08x,src_port_id=%08x,"
2186 "confirm_rx=%i,size=%3i,dst_pid=%08x,dst_cid=%08x\n",
2187 hdr->version, type_to_str(hdr->type),
2188 hdr->src_node_id, hdr->src_port_id,
2189 hdr->confirm_rx, hdr->size,
2190 hdr->dst_node_id, hdr->dst_port_id);
2191
2192#if defined(CONFIG_MSM_SMD_LOGGING)
2193#if defined(DEBUG)
2194 if (msm_ipc_router_debug_mask & SMEM_LOG) {
2195 smem_log_event((SMEM_LOG_PROC_ID_APPS |
2196 SMEM_LOG_RPC_ROUTER_EVENT_BASE |
2197 IPC_ROUTER_LOG_EVENT_TX),
2198 (hdr->src_node_id << 24) |
2199 (hdr->src_port_id & 0xffffff),
2200 (hdr->dst_node_id << 24) |
2201 (hdr->dst_port_id & 0xffffff),
2202 (hdr->type << 24) | (hdr->confirm_rx << 16) |
2203 (hdr->size & 0xffff));
2204 }
2205#endif
2206#endif
2207
2208 return pkt->length;
2209}
2210
2211int msm_ipc_router_send_to(struct msm_ipc_port *src,
2212 struct sk_buff_head *data,
2213 struct msm_ipc_addr *dest)
2214{
2215 uint32_t dst_node_id = 0, dst_port_id = 0;
2216 struct msm_ipc_server *server;
2217 struct msm_ipc_server_port *server_port;
2218 struct msm_ipc_router_remote_port *rport_ptr = NULL;
2219 struct rr_packet *pkt;
2220 int ret;
2221
2222 if (!src || !data || !dest) {
2223 pr_err("%s: Invalid Parameters\n", __func__);
2224 return -EINVAL;
2225 }
2226
2227 /* Resolve Address*/
2228 if (dest->addrtype == MSM_IPC_ADDR_ID) {
2229 dst_node_id = dest->addr.port_addr.node_id;
2230 dst_port_id = dest->addr.port_addr.port_id;
2231 } else if (dest->addrtype == MSM_IPC_ADDR_NAME) {
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002232 mutex_lock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002233 server = msm_ipc_router_lookup_server(
2234 dest->addr.port_name.service,
2235 dest->addr.port_name.instance,
2236 0, 0);
2237 if (!server) {
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002238 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002239 pr_err("%s: Destination not reachable\n", __func__);
2240 return -ENODEV;
2241 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002242 server_port = list_first_entry(&server->server_port_list,
2243 struct msm_ipc_server_port,
2244 list);
2245 dst_node_id = server_port->server_addr.node_id;
2246 dst_port_id = server_port->server_addr.port_id;
2247 mutex_unlock(&server_list_lock);
2248 }
2249 if (dst_node_id == IPC_ROUTER_NID_LOCAL) {
2250 ret = loopback_data(src, dst_port_id, data);
2251 return ret;
2252 }
2253
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002254 rport_ptr = msm_ipc_router_lookup_remote_port(dst_node_id,
2255 dst_port_id);
2256 if (!rport_ptr) {
Zaheerulla Meer2c515312013-05-10 15:51:28 +05302257 pr_err("%s: Remote port not found\n", __func__);
2258 return -ENODEV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002259 }
2260
Karthikeyan Ramasubramanian1668cc62012-09-23 22:23:36 -06002261 if (src->check_send_permissions) {
2262 ret = src->check_send_permissions(rport_ptr->sec_rule);
2263 if (ret <= 0) {
2264 pr_err("%s: permission failure for %s\n",
2265 __func__, current->comm);
2266 return -EPERM;
2267 }
2268 }
2269
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002270 pkt = create_pkt(data);
2271 if (!pkt) {
2272 pr_err("%s: Pkt creation failed\n", __func__);
2273 return -ENOMEM;
2274 }
2275
2276 ret = msm_ipc_router_write_pkt(src, rport_ptr, pkt);
2277 release_pkt(pkt);
2278
2279 return ret;
2280}
2281
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -06002282int msm_ipc_router_send_msg(struct msm_ipc_port *src,
2283 struct msm_ipc_addr *dest,
2284 void *data, unsigned int data_len)
2285{
2286 struct sk_buff_head *out_skb_head;
2287 int ret;
2288
2289 out_skb_head = msm_ipc_router_buf_to_skb(data, data_len);
2290 if (!out_skb_head) {
2291 pr_err("%s: SKB conversion failed\n", __func__);
2292 return -EFAULT;
2293 }
2294
2295 ret = msm_ipc_router_send_to(src, out_skb_head, dest);
2296 if (ret < 0) {
2297 pr_err("%s: msm_ipc_router_send_to failed - ret: %d\n",
2298 __func__, ret);
2299 msm_ipc_router_free_skb(out_skb_head);
2300 }
2301 return 0;
2302}
2303
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002304int msm_ipc_router_read(struct msm_ipc_port *port_ptr,
2305 struct sk_buff_head **data,
2306 size_t buf_len)
2307{
2308 struct rr_packet *pkt;
2309 int ret;
2310
2311 if (!port_ptr || !data)
2312 return -EINVAL;
2313
2314 mutex_lock(&port_ptr->port_rx_q_lock);
2315 if (list_empty(&port_ptr->port_rx_q)) {
2316 mutex_unlock(&port_ptr->port_rx_q_lock);
2317 return -EAGAIN;
2318 }
2319
2320 pkt = list_first_entry(&port_ptr->port_rx_q, struct rr_packet, list);
2321 if ((buf_len) && ((pkt->length - IPC_ROUTER_HDR_SIZE) > buf_len)) {
2322 mutex_unlock(&port_ptr->port_rx_q_lock);
2323 return -ETOOSMALL;
2324 }
2325 list_del(&pkt->list);
2326 if (list_empty(&port_ptr->port_rx_q))
2327 wake_unlock(&port_ptr->port_rx_wake_lock);
2328 *data = pkt->pkt_fragment_q;
2329 ret = pkt->length;
2330 kfree(pkt);
2331 mutex_unlock(&port_ptr->port_rx_q_lock);
2332
2333 return ret;
2334}
2335
2336int msm_ipc_router_recv_from(struct msm_ipc_port *port_ptr,
2337 struct sk_buff_head **data,
2338 struct msm_ipc_addr *src,
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -06002339 long timeout)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002340{
2341 int ret, data_len, align_size;
2342 struct sk_buff *temp_skb;
2343 struct rr_header *hdr = NULL;
2344
2345 if (!port_ptr || !data) {
2346 pr_err("%s: Invalid pointers being passed\n", __func__);
2347 return -EINVAL;
2348 }
2349
2350 *data = NULL;
2351 mutex_lock(&port_ptr->port_rx_q_lock);
2352 while (list_empty(&port_ptr->port_rx_q)) {
2353 mutex_unlock(&port_ptr->port_rx_q_lock);
2354 if (timeout < 0) {
2355 ret = wait_event_interruptible(
2356 port_ptr->port_rx_wait_q,
2357 !list_empty(&port_ptr->port_rx_q));
2358 if (ret)
2359 return ret;
2360 } else if (timeout > 0) {
2361 timeout = wait_event_interruptible_timeout(
2362 port_ptr->port_rx_wait_q,
2363 !list_empty(&port_ptr->port_rx_q),
2364 timeout);
2365 if (timeout < 0)
2366 return -EFAULT;
2367 }
2368 if (timeout == 0)
2369 return -ETIMEDOUT;
2370 mutex_lock(&port_ptr->port_rx_q_lock);
2371 }
2372 mutex_unlock(&port_ptr->port_rx_q_lock);
2373
2374 ret = msm_ipc_router_read(port_ptr, data, 0);
2375 if (ret <= 0 || !(*data))
2376 return ret;
2377
2378 temp_skb = skb_peek(*data);
2379 hdr = (struct rr_header *)(temp_skb->data);
2380 if (src) {
2381 src->addrtype = MSM_IPC_ADDR_ID;
2382 src->addr.port_addr.node_id = hdr->src_node_id;
2383 src->addr.port_addr.port_id = hdr->src_port_id;
2384 }
2385
2386 data_len = hdr->size;
2387 skb_pull(temp_skb, IPC_ROUTER_HDR_SIZE);
2388 align_size = ALIGN_SIZE(data_len);
2389 if (align_size) {
2390 temp_skb = skb_peek_tail(*data);
2391 skb_trim(temp_skb, (temp_skb->len - align_size));
2392 }
2393 return data_len;
2394}
2395
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -06002396int msm_ipc_router_read_msg(struct msm_ipc_port *port_ptr,
2397 struct msm_ipc_addr *src,
2398 unsigned char **data,
2399 unsigned int *len)
2400{
2401 struct sk_buff_head *in_skb_head;
2402 int ret;
2403
2404 ret = msm_ipc_router_recv_from(port_ptr, &in_skb_head, src, -1);
2405 if (ret < 0) {
2406 pr_err("%s: msm_ipc_router_recv_from failed - ret: %d\n",
2407 __func__, ret);
2408 return ret;
2409 }
2410
2411 *data = msm_ipc_router_skb_to_buf(in_skb_head, ret);
2412 if (!(*data))
2413 pr_err("%s: Buf conversion failed\n", __func__);
2414
2415 *len = ret;
2416 msm_ipc_router_free_skb(in_skb_head);
2417 return 0;
2418}
2419
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002420struct msm_ipc_port *msm_ipc_router_create_port(
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -06002421 void (*notify)(unsigned event, void *priv),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002422 void *priv)
2423{
2424 struct msm_ipc_port *port_ptr;
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -06002425 int ret;
2426
2427 ret = wait_for_completion_interruptible(&msm_ipc_local_router_up);
2428 if (ret < 0) {
2429 pr_err("%s: Error waiting for local router\n", __func__);
2430 return NULL;
2431 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002432
2433 port_ptr = msm_ipc_router_create_raw_port(NULL, notify, priv);
2434 if (!port_ptr)
2435 pr_err("%s: port_ptr alloc failed\n", __func__);
2436
2437 return port_ptr;
2438}
2439
2440int msm_ipc_router_close_port(struct msm_ipc_port *port_ptr)
2441{
2442 union rr_control_msg msg;
2443 struct rr_packet *pkt, *temp_pkt;
2444 struct msm_ipc_server *server;
2445
2446 if (!port_ptr)
2447 return -EINVAL;
2448
2449 if (port_ptr->type == SERVER_PORT || port_ptr->type == CLIENT_PORT) {
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06002450 mutex_lock(&local_ports_lock);
2451 list_del(&port_ptr->list);
2452 mutex_unlock(&local_ports_lock);
2453
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002454 if (port_ptr->type == SERVER_PORT) {
2455 msg.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_SERVER;
2456 msg.srv.service = port_ptr->port_name.service;
2457 msg.srv.instance = port_ptr->port_name.instance;
2458 msg.srv.node_id = port_ptr->this_port.node_id;
2459 msg.srv.port_id = port_ptr->this_port.port_id;
2460 RR("x REMOVE_SERVER Name=%d:%08x Id=%d:%08x\n",
2461 msg.srv.service, msg.srv.instance,
2462 msg.srv.node_id, msg.srv.port_id);
Karthikeyan Ramasubramanian25e91872013-01-10 17:09:13 -07002463 broadcast_ctl_msg(&msg);
2464 broadcast_ctl_msg_locally(&msg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002465 }
Karthikeyan Ramasubramanian25e91872013-01-10 17:09:13 -07002466
2467 /*
2468 * Server port could have been a client port earlier.
2469 * Send REMOVE_CLIENT message in either case.
2470 */
Karthikeyan Ramasubramanian25e91872013-01-10 17:09:13 -07002471 RR("x REMOVE_CLIENT id=%d:%08x\n",
Karthikeyan Ramasubramaniandc9c4442013-05-02 17:25:54 -06002472 port_ptr->this_port.node_id, port_ptr->this_port.port_id);
2473 msm_ipc_router_send_remove_client(&port_ptr->mode_info,
2474 port_ptr->this_port.node_id,
2475 port_ptr->this_port.port_id);
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06002476 } else if (port_ptr->type == CONTROL_PORT) {
2477 mutex_lock(&control_ports_lock);
2478 list_del(&port_ptr->list);
2479 mutex_unlock(&control_ports_lock);
Karthikeyan Ramasubramaniand6dbfae2013-01-16 09:00:28 -07002480 } else if (port_ptr->type == IRSC_PORT) {
2481 mutex_lock(&local_ports_lock);
2482 list_del(&port_ptr->list);
2483 mutex_unlock(&local_ports_lock);
2484 signal_irsc_completion();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002485 }
2486
2487 mutex_lock(&port_ptr->port_rx_q_lock);
2488 list_for_each_entry_safe(pkt, temp_pkt, &port_ptr->port_rx_q, list) {
2489 list_del(&pkt->list);
2490 release_pkt(pkt);
2491 }
2492 mutex_unlock(&port_ptr->port_rx_q_lock);
2493
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002494 if (port_ptr->type == SERVER_PORT) {
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002495 mutex_lock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002496 server = msm_ipc_router_lookup_server(
2497 port_ptr->port_name.service,
2498 port_ptr->port_name.instance,
2499 port_ptr->this_port.node_id,
2500 port_ptr->this_port.port_id);
2501 if (server)
2502 msm_ipc_router_destroy_server(server,
2503 port_ptr->this_port.node_id,
2504 port_ptr->this_port.port_id);
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002505 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002506 }
2507
Karthikeyan Ramasubramaniandd8c3b52011-11-30 16:26:12 -07002508 wake_lock_destroy(&port_ptr->port_rx_wake_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002509 kfree(port_ptr);
2510 return 0;
2511}
2512
2513int msm_ipc_router_get_curr_pkt_size(struct msm_ipc_port *port_ptr)
2514{
2515 struct rr_packet *pkt;
2516 int rc = 0;
2517
2518 if (!port_ptr)
2519 return -EINVAL;
2520
2521 mutex_lock(&port_ptr->port_rx_q_lock);
2522 if (!list_empty(&port_ptr->port_rx_q)) {
2523 pkt = list_first_entry(&port_ptr->port_rx_q,
2524 struct rr_packet, list);
2525 rc = pkt->length;
2526 }
2527 mutex_unlock(&port_ptr->port_rx_q_lock);
2528
2529 return rc;
2530}
2531
2532int msm_ipc_router_bind_control_port(struct msm_ipc_port *port_ptr)
2533{
2534 if (!port_ptr)
2535 return -EINVAL;
2536
2537 mutex_lock(&local_ports_lock);
2538 list_del(&port_ptr->list);
2539 mutex_unlock(&local_ports_lock);
2540 port_ptr->type = CONTROL_PORT;
2541 mutex_lock(&control_ports_lock);
2542 list_add_tail(&port_ptr->list, &control_ports);
2543 mutex_unlock(&control_ports_lock);
2544
2545 return 0;
2546}
2547
2548int msm_ipc_router_lookup_server_name(struct msm_ipc_port_name *srv_name,
Karthikeyan Ramasubramaniandfde01b2012-06-12 14:25:13 -06002549 struct msm_ipc_server_info *srv_info,
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002550 int num_entries_in_array,
2551 uint32_t lookup_mask)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002552{
2553 struct msm_ipc_server *server;
2554 struct msm_ipc_server_port *server_port;
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002555 int key, i = 0; /*num_entries_found*/
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002556
2557 if (!srv_name) {
2558 pr_err("%s: Invalid srv_name\n", __func__);
2559 return -EINVAL;
2560 }
2561
Karthikeyan Ramasubramaniandfde01b2012-06-12 14:25:13 -06002562 if (num_entries_in_array && !srv_info) {
2563 pr_err("%s: srv_info NULL\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002564 return -EINVAL;
2565 }
2566
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002567 mutex_lock(&server_list_lock);
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002568 if (!lookup_mask)
2569 lookup_mask = 0xFFFFFFFF;
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002570 key = (srv_name->service & (SRV_HASH_SIZE - 1));
2571 list_for_each_entry(server, &server_list[key], list) {
2572 if ((server->name.service != srv_name->service) ||
2573 ((server->name.instance & lookup_mask) !=
2574 srv_name->instance))
2575 continue;
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002576
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002577 list_for_each_entry(server_port,
2578 &server->server_port_list, list) {
2579 if (i < num_entries_in_array) {
2580 srv_info[i].node_id =
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002581 server_port->server_addr.node_id;
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002582 srv_info[i].port_id =
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002583 server_port->server_addr.port_id;
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002584 srv_info[i].service = server->name.service;
2585 srv_info[i].instance = server->name.instance;
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002586 }
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002587 i++;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002588 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002589 }
2590 mutex_unlock(&server_list_lock);
2591
2592 return i;
2593}
2594
2595int msm_ipc_router_close(void)
2596{
2597 struct msm_ipc_router_xprt_info *xprt_info, *tmp_xprt_info;
2598
2599 mutex_lock(&xprt_info_list_lock);
2600 list_for_each_entry_safe(xprt_info, tmp_xprt_info,
2601 &xprt_info_list, list) {
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -07002602 xprt_info->xprt->close(xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002603 list_del(&xprt_info->list);
2604 kfree(xprt_info);
2605 }
2606 mutex_unlock(&xprt_info_list_lock);
2607 return 0;
2608}
2609
2610#if defined(CONFIG_DEBUG_FS)
2611static int dump_routing_table(char *buf, int max)
2612{
2613 int i = 0, j;
2614 struct msm_ipc_routing_table_entry *rt_entry;
2615
2616 for (j = 0; j < RT_HASH_SIZE; j++) {
2617 mutex_lock(&routing_table_lock);
2618 list_for_each_entry(rt_entry, &routing_table[j], list) {
2619 mutex_lock(&rt_entry->lock);
2620 i += scnprintf(buf + i, max - i,
2621 "Node Id: 0x%08x\n", rt_entry->node_id);
Karthikeyan Ramasubramanianc1a4e3a2012-09-10 16:10:24 -06002622 if (rt_entry->node_id == IPC_ROUTER_NID_LOCAL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002623 i += scnprintf(buf + i, max - i,
2624 "XPRT Name: Loopback\n");
2625 i += scnprintf(buf + i, max - i,
2626 "Next Hop: %d\n", rt_entry->node_id);
2627 } else {
2628 i += scnprintf(buf + i, max - i,
2629 "XPRT Name: %s\n",
2630 rt_entry->xprt_info->xprt->name);
2631 i += scnprintf(buf + i, max - i,
2632 "Next Hop: 0x%08x\n",
2633 rt_entry->xprt_info->remote_node_id);
2634 }
2635 i += scnprintf(buf + i, max - i, "\n");
2636 mutex_unlock(&rt_entry->lock);
2637 }
2638 mutex_unlock(&routing_table_lock);
2639 }
2640
2641 return i;
2642}
2643
2644static int dump_xprt_info(char *buf, int max)
2645{
2646 int i = 0;
2647 struct msm_ipc_router_xprt_info *xprt_info;
2648
2649 mutex_lock(&xprt_info_list_lock);
2650 list_for_each_entry(xprt_info, &xprt_info_list, list) {
2651 i += scnprintf(buf + i, max - i, "XPRT Name: %s\n",
2652 xprt_info->xprt->name);
2653 i += scnprintf(buf + i, max - i, "Link Id: %d\n",
2654 xprt_info->xprt->link_id);
2655 i += scnprintf(buf + i, max - i, "Initialized: %s\n",
2656 (xprt_info->initialized ? "Y" : "N"));
2657 i += scnprintf(buf + i, max - i, "Remote Node Id: 0x%08x\n",
2658 xprt_info->remote_node_id);
2659 i += scnprintf(buf + i, max - i, "\n");
2660 }
2661 mutex_unlock(&xprt_info_list_lock);
2662
2663 return i;
2664}
2665
2666static int dump_servers(char *buf, int max)
2667{
2668 int i = 0, j;
2669 struct msm_ipc_server *server;
2670 struct msm_ipc_server_port *server_port;
2671
2672 mutex_lock(&server_list_lock);
2673 for (j = 0; j < SRV_HASH_SIZE; j++) {
2674 list_for_each_entry(server, &server_list[j], list) {
2675 list_for_each_entry(server_port,
2676 &server->server_port_list,
2677 list) {
2678 i += scnprintf(buf + i, max - i, "Service: "
2679 "0x%08x\n", server->name.service);
2680 i += scnprintf(buf + i, max - i, "Instance: "
2681 "0x%08x\n", server->name.instance);
2682 i += scnprintf(buf + i, max - i,
2683 "Node_id: 0x%08x\n",
2684 server_port->server_addr.node_id);
2685 i += scnprintf(buf + i, max - i,
2686 "Port_id: 0x%08x\n",
2687 server_port->server_addr.port_id);
2688 i += scnprintf(buf + i, max - i, "\n");
2689 }
2690 }
2691 }
2692 mutex_unlock(&server_list_lock);
2693
2694 return i;
2695}
2696
2697static int dump_remote_ports(char *buf, int max)
2698{
2699 int i = 0, j, k;
2700 struct msm_ipc_router_remote_port *rport_ptr;
2701 struct msm_ipc_routing_table_entry *rt_entry;
2702
2703 for (j = 0; j < RT_HASH_SIZE; j++) {
2704 mutex_lock(&routing_table_lock);
2705 list_for_each_entry(rt_entry, &routing_table[j], list) {
2706 mutex_lock(&rt_entry->lock);
2707 for (k = 0; k < RP_HASH_SIZE; k++) {
2708 list_for_each_entry(rport_ptr,
2709 &rt_entry->remote_port_list[k],
2710 list) {
2711 i += scnprintf(buf + i, max - i,
2712 "Node_id: 0x%08x\n",
2713 rport_ptr->node_id);
2714 i += scnprintf(buf + i, max - i,
2715 "Port_id: 0x%08x\n",
2716 rport_ptr->port_id);
2717 i += scnprintf(buf + i, max - i,
2718 "Quota_cnt: %d\n",
2719 rport_ptr->tx_quota_cnt);
2720 i += scnprintf(buf + i, max - i, "\n");
2721 }
2722 }
2723 mutex_unlock(&rt_entry->lock);
2724 }
2725 mutex_unlock(&routing_table_lock);
2726 }
2727
2728 return i;
2729}
2730
2731static int dump_control_ports(char *buf, int max)
2732{
2733 int i = 0;
2734 struct msm_ipc_port *port_ptr;
2735
2736 mutex_lock(&control_ports_lock);
2737 list_for_each_entry(port_ptr, &control_ports, list) {
2738 i += scnprintf(buf + i, max - i, "Node_id: 0x%08x\n",
2739 port_ptr->this_port.node_id);
2740 i += scnprintf(buf + i, max - i, "Port_id: 0x%08x\n",
2741 port_ptr->this_port.port_id);
2742 i += scnprintf(buf + i, max - i, "\n");
2743 }
2744 mutex_unlock(&control_ports_lock);
2745
2746 return i;
2747}
2748
2749static int dump_local_ports(char *buf, int max)
2750{
2751 int i = 0, j;
2752 unsigned long flags;
2753 struct msm_ipc_port *port_ptr;
2754
2755 mutex_lock(&local_ports_lock);
2756 for (j = 0; j < LP_HASH_SIZE; j++) {
2757 list_for_each_entry(port_ptr, &local_ports[j], list) {
2758 spin_lock_irqsave(&port_ptr->port_lock, flags);
2759 i += scnprintf(buf + i, max - i, "Node_id: 0x%08x\n",
2760 port_ptr->this_port.node_id);
2761 i += scnprintf(buf + i, max - i, "Port_id: 0x%08x\n",
2762 port_ptr->this_port.port_id);
2763 i += scnprintf(buf + i, max - i, "# pkts tx'd %d\n",
2764 port_ptr->num_tx);
2765 i += scnprintf(buf + i, max - i, "# pkts rx'd %d\n",
2766 port_ptr->num_rx);
2767 i += scnprintf(buf + i, max - i, "# bytes tx'd %ld\n",
2768 port_ptr->num_tx_bytes);
2769 i += scnprintf(buf + i, max - i, "# bytes rx'd %ld\n",
2770 port_ptr->num_rx_bytes);
2771 spin_unlock_irqrestore(&port_ptr->port_lock, flags);
2772 i += scnprintf(buf + i, max - i, "\n");
2773 }
2774 }
2775 mutex_unlock(&local_ports_lock);
2776
2777 return i;
2778}
2779
2780#define DEBUG_BUFMAX 4096
2781static char debug_buffer[DEBUG_BUFMAX];
2782
2783static ssize_t debug_read(struct file *file, char __user *buf,
2784 size_t count, loff_t *ppos)
2785{
2786 int (*fill)(char *buf, int max) = file->private_data;
2787 int bsize = fill(debug_buffer, DEBUG_BUFMAX);
2788 return simple_read_from_buffer(buf, count, ppos, debug_buffer, bsize);
2789}
2790
2791static int debug_open(struct inode *inode, struct file *file)
2792{
2793 file->private_data = inode->i_private;
2794 return 0;
2795}
2796
2797static const struct file_operations debug_ops = {
2798 .read = debug_read,
2799 .open = debug_open,
2800};
2801
2802static void debug_create(const char *name, mode_t mode,
2803 struct dentry *dent,
2804 int (*fill)(char *buf, int max))
2805{
2806 debugfs_create_file(name, mode, dent, fill, &debug_ops);
2807}
2808
2809static void debugfs_init(void)
2810{
2811 struct dentry *dent;
2812
2813 dent = debugfs_create_dir("msm_ipc_router", 0);
2814 if (IS_ERR(dent))
2815 return;
2816
2817 debug_create("dump_local_ports", 0444, dent,
2818 dump_local_ports);
2819 debug_create("dump_remote_ports", 0444, dent,
2820 dump_remote_ports);
2821 debug_create("dump_control_ports", 0444, dent,
2822 dump_control_ports);
2823 debug_create("dump_servers", 0444, dent,
2824 dump_servers);
2825 debug_create("dump_xprt_info", 0444, dent,
2826 dump_xprt_info);
2827 debug_create("dump_routing_table", 0444, dent,
2828 dump_routing_table);
2829}
2830
2831#else
2832static void debugfs_init(void) {}
2833#endif
2834
2835static int msm_ipc_router_add_xprt(struct msm_ipc_router_xprt *xprt)
2836{
2837 struct msm_ipc_router_xprt_info *xprt_info;
2838 struct msm_ipc_routing_table_entry *rt_entry;
2839
2840 xprt_info = kmalloc(sizeof(struct msm_ipc_router_xprt_info),
2841 GFP_KERNEL);
2842 if (!xprt_info)
2843 return -ENOMEM;
2844
2845 xprt_info->xprt = xprt;
2846 xprt_info->initialized = 0;
2847 xprt_info->remote_node_id = -1;
2848 INIT_LIST_HEAD(&xprt_info->pkt_list);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002849 mutex_init(&xprt_info->rx_lock);
2850 mutex_init(&xprt_info->tx_lock);
2851 wake_lock_init(&xprt_info->wakelock,
2852 WAKE_LOCK_SUSPEND, xprt->name);
2853 xprt_info->need_len = 0;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002854 xprt_info->abort_data_read = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002855 INIT_WORK(&xprt_info->read_data, do_read_data);
2856 INIT_LIST_HEAD(&xprt_info->list);
2857
2858 xprt_info->workqueue = create_singlethread_workqueue(xprt->name);
2859 if (!xprt_info->workqueue) {
2860 kfree(xprt_info);
2861 return -ENOMEM;
2862 }
2863
2864 if (!strcmp(xprt->name, "msm_ipc_router_loopback_xprt")) {
2865 xprt_info->remote_node_id = IPC_ROUTER_NID_LOCAL;
2866 xprt_info->initialized = 1;
2867 }
2868
2869 mutex_lock(&xprt_info_list_lock);
2870 list_add_tail(&xprt_info->list, &xprt_info_list);
2871 mutex_unlock(&xprt_info_list_lock);
2872
2873 mutex_lock(&routing_table_lock);
2874 if (!routing_table_inited) {
2875 init_routing_table();
2876 rt_entry = alloc_routing_table_entry(IPC_ROUTER_NID_LOCAL);
2877 add_routing_table_entry(rt_entry);
2878 routing_table_inited = 1;
2879 }
2880 mutex_unlock(&routing_table_lock);
2881
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002882 xprt->priv = xprt_info;
2883
2884 return 0;
2885}
2886
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002887static void msm_ipc_router_remove_xprt(struct msm_ipc_router_xprt *xprt)
2888{
2889 struct msm_ipc_router_xprt_info *xprt_info;
2890
2891 if (xprt && xprt->priv) {
2892 xprt_info = xprt->priv;
2893
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06002894 mutex_lock(&xprt_info->rx_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002895 xprt_info->abort_data_read = 1;
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06002896 mutex_unlock(&xprt_info->rx_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002897
2898 mutex_lock(&xprt_info_list_lock);
2899 list_del(&xprt_info->list);
2900 mutex_unlock(&xprt_info_list_lock);
2901
2902 flush_workqueue(xprt_info->workqueue);
2903 destroy_workqueue(xprt_info->workqueue);
2904 wake_lock_destroy(&xprt_info->wakelock);
2905
2906 xprt->priv = 0;
2907 kfree(xprt_info);
2908 }
2909}
2910
2911
2912struct msm_ipc_router_xprt_work {
2913 struct msm_ipc_router_xprt *xprt;
2914 struct work_struct work;
2915};
2916
2917static void xprt_open_worker(struct work_struct *work)
2918{
2919 struct msm_ipc_router_xprt_work *xprt_work =
2920 container_of(work, struct msm_ipc_router_xprt_work, work);
2921
2922 msm_ipc_router_add_xprt(xprt_work->xprt);
2923 kfree(xprt_work);
2924}
2925
2926static void xprt_close_worker(struct work_struct *work)
2927{
2928 struct msm_ipc_router_xprt_work *xprt_work =
2929 container_of(work, struct msm_ipc_router_xprt_work, work);
2930
2931 modem_reset_cleanup(xprt_work->xprt->priv);
2932 msm_ipc_router_remove_xprt(xprt_work->xprt);
Zaheerulla Meer35893a62013-06-19 16:54:44 +05302933 xprt_work->xprt->sft_close_done(xprt_work->xprt);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002934 kfree(xprt_work);
2935}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002936
2937void msm_ipc_router_xprt_notify(struct msm_ipc_router_xprt *xprt,
2938 unsigned event,
2939 void *data)
2940{
2941 struct msm_ipc_router_xprt_info *xprt_info = xprt->priv;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002942 struct msm_ipc_router_xprt_work *xprt_work;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002943 struct rr_packet *pkt;
Karthikeyan Ramasubramanian4af9f7c2011-09-30 15:55:18 -06002944 unsigned long ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002945
Karthikeyan Ramasubramanian4af9f7c2011-09-30 15:55:18 -06002946 if (!msm_ipc_router_workqueue) {
2947 ret = wait_for_completion_timeout(&msm_ipc_local_router_up,
2948 IPC_ROUTER_INIT_TIMEOUT);
2949 if (!ret || !msm_ipc_router_workqueue) {
2950 pr_err("%s: IPC Router not initialized\n", __func__);
2951 return;
2952 }
2953 }
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002954
2955 switch (event) {
2956 case IPC_ROUTER_XPRT_EVENT_OPEN:
2957 D("open event for '%s'\n", xprt->name);
2958 xprt_work = kmalloc(sizeof(struct msm_ipc_router_xprt_work),
2959 GFP_ATOMIC);
Karthikeyan Ramasubramanianc51456c2013-05-16 15:51:29 -06002960 if (xprt_work) {
2961 xprt_work->xprt = xprt;
2962 INIT_WORK(&xprt_work->work, xprt_open_worker);
2963 queue_work(msm_ipc_router_workqueue, &xprt_work->work);
2964 } else {
2965 pr_err("%s: malloc failure - Couldn't notify OPEN event",
2966 __func__);
2967 }
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002968 break;
2969
2970 case IPC_ROUTER_XPRT_EVENT_CLOSE:
2971 D("close event for '%s'\n", xprt->name);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002972 xprt_work = kmalloc(sizeof(struct msm_ipc_router_xprt_work),
2973 GFP_ATOMIC);
Karthikeyan Ramasubramanianc51456c2013-05-16 15:51:29 -06002974 if (xprt_work) {
2975 xprt_work->xprt = xprt;
2976 INIT_WORK(&xprt_work->work, xprt_close_worker);
2977 queue_work(msm_ipc_router_workqueue, &xprt_work->work);
2978 } else {
2979 pr_err("%s: malloc failure - Couldn't notify CLOSE event",
2980 __func__);
2981 }
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002982 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002983 }
2984
2985 if (!data)
2986 return;
2987
2988 while (!xprt_info) {
2989 msleep(100);
2990 xprt_info = xprt->priv;
2991 }
2992
2993 pkt = clone_pkt((struct rr_packet *)data);
2994 if (!pkt)
2995 return;
2996
2997 mutex_lock(&xprt_info->rx_lock);
2998 list_add_tail(&pkt->list, &xprt_info->pkt_list);
2999 wake_lock(&xprt_info->wakelock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003000 mutex_unlock(&xprt_info->rx_lock);
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06003001 queue_work(xprt_info->workqueue, &xprt_info->read_data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003002}
3003
3004static int __init msm_ipc_router_init(void)
3005{
3006 int i, ret;
3007 struct msm_ipc_routing_table_entry *rt_entry;
3008
3009 msm_ipc_router_debug_mask |= SMEM_LOG;
Karthikeyan Ramasubramanian682ebcc2013-03-22 10:47:20 -06003010 ipc_rtr_log_ctxt = ipc_log_context_create(IPC_RTR_LOG_PAGES,
3011 "ipc_router");
3012 if (!ipc_rtr_log_ctxt)
3013 pr_err("%s: Unable to create IPC logging for IPC RTR",
3014 __func__);
3015
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06003016 msm_ipc_router_workqueue =
3017 create_singlethread_workqueue("msm_ipc_router");
3018 if (!msm_ipc_router_workqueue)
3019 return -ENOMEM;
3020
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003021 debugfs_init();
3022
3023 for (i = 0; i < SRV_HASH_SIZE; i++)
3024 INIT_LIST_HEAD(&server_list[i]);
3025
3026 for (i = 0; i < LP_HASH_SIZE; i++)
3027 INIT_LIST_HEAD(&local_ports[i]);
3028
3029 mutex_lock(&routing_table_lock);
3030 if (!routing_table_inited) {
3031 init_routing_table();
3032 rt_entry = alloc_routing_table_entry(IPC_ROUTER_NID_LOCAL);
3033 add_routing_table_entry(rt_entry);
3034 routing_table_inited = 1;
3035 }
3036 mutex_unlock(&routing_table_lock);
3037
3038 init_waitqueue_head(&newserver_wait);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003039 ret = msm_ipc_router_init_sockets();
3040 if (ret < 0)
3041 pr_err("%s: Init sockets failed\n", __func__);
3042
Karthikeyan Ramasubramanian1668cc62012-09-23 22:23:36 -06003043 ret = msm_ipc_router_security_init();
3044 if (ret < 0)
3045 pr_err("%s: Security Init failed\n", __func__);
3046
Karthikeyan Ramasubramanian4af9f7c2011-09-30 15:55:18 -06003047 complete_all(&msm_ipc_local_router_up);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003048 return ret;
3049}
3050
3051module_init(msm_ipc_router_init);
3052MODULE_DESCRIPTION("MSM IPC Router");
3053MODULE_LICENSE("GPL v2");