blob: 48af999fa88b33e83b542dc85400a02f43851ab3 [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
Karthikeyan Ramasubramaniand1af6252013-05-17 15:19:56 -0600477static int post_pkt_to_port(struct msm_ipc_port *port_ptr,
478 struct rr_packet *pkt, int clone)
479{
480 struct rr_packet *temp_pkt = pkt;
481
482 if (unlikely(!port_ptr || !pkt))
483 return -EINVAL;
484
485 if (clone) {
486 temp_pkt = clone_pkt(pkt);
487 if (!temp_pkt) {
488 pr_err("%s: Error cloning packet for port %08x:%08x\n",
489 __func__, port_ptr->this_port.node_id,
490 port_ptr->this_port.port_id);
491 return -ENOMEM;
492 }
493 }
494
495 mutex_lock(&port_ptr->port_rx_q_lock);
496 wake_lock(&port_ptr->port_rx_wake_lock);
497 list_add_tail(&temp_pkt->list, &port_ptr->port_rx_q);
498 wake_up(&port_ptr->port_rx_wait_q);
499 if (port_ptr->notify)
500 port_ptr->notify(MSM_IPC_ROUTER_READ_CB, port_ptr->priv);
501 mutex_unlock(&port_ptr->port_rx_q_lock);
502 return 0;
503}
504
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700505static int post_control_ports(struct rr_packet *pkt)
506{
507 struct msm_ipc_port *port_ptr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700508
509 if (!pkt)
510 return -EINVAL;
511
512 mutex_lock(&control_ports_lock);
Karthikeyan Ramasubramaniand1af6252013-05-17 15:19:56 -0600513 list_for_each_entry(port_ptr, &control_ports, list)
514 post_pkt_to_port(port_ptr, pkt, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700515 mutex_unlock(&control_ports_lock);
516 return 0;
517}
518
519static uint32_t allocate_port_id(void)
520{
521 uint32_t port_id = 0, prev_port_id, key;
522 struct msm_ipc_port *port_ptr;
523
524 mutex_lock(&next_port_id_lock);
525 prev_port_id = next_port_id;
526 mutex_lock(&local_ports_lock);
527 do {
528 next_port_id++;
529 if ((next_port_id & 0xFFFFFFFE) == 0xFFFFFFFE)
530 next_port_id = 1;
531
532 key = (next_port_id & (LP_HASH_SIZE - 1));
533 if (list_empty(&local_ports[key])) {
534 port_id = next_port_id;
535 break;
536 }
537 list_for_each_entry(port_ptr, &local_ports[key], list) {
538 if (port_ptr->this_port.port_id == next_port_id) {
539 port_id = next_port_id;
540 break;
541 }
542 }
543 if (!port_id) {
544 port_id = next_port_id;
545 break;
546 }
547 port_id = 0;
548 } while (next_port_id != prev_port_id);
549 mutex_unlock(&local_ports_lock);
550 mutex_unlock(&next_port_id_lock);
551
552 return port_id;
553}
554
555void msm_ipc_router_add_local_port(struct msm_ipc_port *port_ptr)
556{
557 uint32_t key;
558
559 if (!port_ptr)
560 return;
561
562 key = (port_ptr->this_port.port_id & (LP_HASH_SIZE - 1));
563 mutex_lock(&local_ports_lock);
564 list_add_tail(&port_ptr->list, &local_ports[key]);
565 mutex_unlock(&local_ports_lock);
566}
567
568struct msm_ipc_port *msm_ipc_router_create_raw_port(void *endpoint,
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -0600569 void (*notify)(unsigned event, void *priv),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700570 void *priv)
571{
572 struct msm_ipc_port *port_ptr;
573
574 port_ptr = kzalloc(sizeof(struct msm_ipc_port), GFP_KERNEL);
575 if (!port_ptr)
576 return NULL;
577
578 port_ptr->this_port.node_id = IPC_ROUTER_NID_LOCAL;
579 port_ptr->this_port.port_id = allocate_port_id();
580 if (!port_ptr->this_port.port_id) {
581 pr_err("%s: All port ids are in use\n", __func__);
582 kfree(port_ptr);
583 return NULL;
584 }
585
586 spin_lock_init(&port_ptr->port_lock);
587 INIT_LIST_HEAD(&port_ptr->incomplete);
588 mutex_init(&port_ptr->incomplete_lock);
589 INIT_LIST_HEAD(&port_ptr->port_rx_q);
590 mutex_init(&port_ptr->port_rx_q_lock);
591 init_waitqueue_head(&port_ptr->port_rx_wait_q);
Karthikeyan Ramasubramanianb4aeeb92012-03-13 12:31:43 -0600592 snprintf(port_ptr->rx_wakelock_name, MAX_WAKELOCK_NAME_SZ,
Karthikeyan Ramasubramanian090486e2013-02-14 13:53:20 -0700593 "ipc%08x_%s",
594 port_ptr->this_port.port_id,
595 current->comm);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700596 wake_lock_init(&port_ptr->port_rx_wake_lock,
Karthikeyan Ramasubramanianb4aeeb92012-03-13 12:31:43 -0600597 WAKE_LOCK_SUSPEND, port_ptr->rx_wakelock_name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700598
599 port_ptr->endpoint = endpoint;
600 port_ptr->notify = notify;
601 port_ptr->priv = priv;
602
603 msm_ipc_router_add_local_port(port_ptr);
604 return port_ptr;
605}
606
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -0600607/*
608 * Should be called with local_ports_lock locked
609 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700610static struct msm_ipc_port *msm_ipc_router_lookup_local_port(uint32_t port_id)
611{
612 int key = (port_id & (LP_HASH_SIZE - 1));
613 struct msm_ipc_port *port_ptr;
614
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700615 list_for_each_entry(port_ptr, &local_ports[key], list) {
616 if (port_ptr->this_port.port_id == port_id) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700617 return port_ptr;
618 }
619 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700620 return NULL;
621}
622
623static struct msm_ipc_router_remote_port *msm_ipc_router_lookup_remote_port(
624 uint32_t node_id,
625 uint32_t port_id)
626{
627 struct msm_ipc_router_remote_port *rport_ptr;
628 struct msm_ipc_routing_table_entry *rt_entry;
629 int key = (port_id & (RP_HASH_SIZE - 1));
630
631 mutex_lock(&routing_table_lock);
632 rt_entry = lookup_routing_table(node_id);
633 if (!rt_entry) {
634 mutex_unlock(&routing_table_lock);
635 pr_err("%s: Node is not up\n", __func__);
636 return NULL;
637 }
638
639 mutex_lock(&rt_entry->lock);
640 list_for_each_entry(rport_ptr,
641 &rt_entry->remote_port_list[key], list) {
642 if (rport_ptr->port_id == port_id) {
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600643 if (rport_ptr->restart_state != RESTART_NORMAL)
644 rport_ptr = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700645 mutex_unlock(&rt_entry->lock);
646 mutex_unlock(&routing_table_lock);
647 return rport_ptr;
648 }
649 }
650 mutex_unlock(&rt_entry->lock);
651 mutex_unlock(&routing_table_lock);
652 return NULL;
653}
654
655static struct msm_ipc_router_remote_port *msm_ipc_router_create_remote_port(
656 uint32_t node_id,
657 uint32_t port_id)
658{
659 struct msm_ipc_router_remote_port *rport_ptr;
660 struct msm_ipc_routing_table_entry *rt_entry;
661 int key = (port_id & (RP_HASH_SIZE - 1));
662
663 mutex_lock(&routing_table_lock);
664 rt_entry = lookup_routing_table(node_id);
665 if (!rt_entry) {
666 mutex_unlock(&routing_table_lock);
667 pr_err("%s: Node is not up\n", __func__);
668 return NULL;
669 }
670
671 mutex_lock(&rt_entry->lock);
672 rport_ptr = kmalloc(sizeof(struct msm_ipc_router_remote_port),
673 GFP_KERNEL);
674 if (!rport_ptr) {
675 mutex_unlock(&rt_entry->lock);
676 mutex_unlock(&routing_table_lock);
677 pr_err("%s: Remote port alloc failed\n", __func__);
678 return NULL;
679 }
680 rport_ptr->port_id = port_id;
681 rport_ptr->node_id = node_id;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600682 rport_ptr->restart_state = RESTART_NORMAL;
Karthikeyan Ramasubramanian1668cc62012-09-23 22:23:36 -0600683 rport_ptr->sec_rule = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700684 rport_ptr->tx_quota_cnt = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700685 mutex_init(&rport_ptr->quota_lock);
Zaheerulla Meera34fc662013-04-17 01:16:47 +0530686 INIT_LIST_HEAD(&rport_ptr->resume_tx_port_list);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700687 list_add_tail(&rport_ptr->list,
688 &rt_entry->remote_port_list[key]);
689 mutex_unlock(&rt_entry->lock);
690 mutex_unlock(&routing_table_lock);
691 return rport_ptr;
692}
693
Zaheerulla Meera34fc662013-04-17 01:16:47 +0530694/**
695 * msm_ipc_router_free_resume_tx_port() - Free the resume_tx ports
696 * @rport_ptr: Pointer to the remote port.
697 *
698 * This function deletes all the resume_tx ports associated with a remote port
699 * and frees the memory allocated to each resume_tx port.
700 *
701 * Must be called with rport_ptr->quota_lock locked.
702 */
703static void msm_ipc_router_free_resume_tx_port(
704 struct msm_ipc_router_remote_port *rport_ptr)
705{
706 struct msm_ipc_resume_tx_port *rtx_port, *tmp_rtx_port;
707
708 list_for_each_entry_safe(rtx_port, tmp_rtx_port,
709 &rport_ptr->resume_tx_port_list, list) {
710 list_del(&rtx_port->list);
711 kfree(rtx_port);
712 }
713}
714
715/**
716 * msm_ipc_router_lookup_resume_tx_port() - Lookup resume_tx port list
717 * @rport_ptr: Remote port whose resume_tx port list needs to be looked.
718 * @port_id: Port ID which needs to be looked from the list.
719 *
720 * return 1 if the port_id is found in the list, else 0.
721 *
722 * This function is used to lookup the existence of a local port in
723 * remote port's resume_tx list. This function is used to ensure that
724 * the same port is not added to the remote_port's resume_tx list repeatedly.
725 *
726 * Must be called with rport_ptr->quota_lock locked.
727 */
728static int msm_ipc_router_lookup_resume_tx_port(
729 struct msm_ipc_router_remote_port *rport_ptr, uint32_t port_id)
730{
731 struct msm_ipc_resume_tx_port *rtx_port;
732
733 list_for_each_entry(rtx_port, &rport_ptr->resume_tx_port_list, list) {
734 if (port_id == rtx_port->port_id)
735 return 1;
736 }
737 return 0;
738}
739
740/**
741 * post_resume_tx() - Post the resume_tx event
742 * @rport_ptr: Pointer to the remote port
743 * @pkt : The data packet that is received on a resume_tx event
744 *
745 * This function informs about the reception of the resume_tx message from a
746 * remote port pointed by rport_ptr to all the local ports that are in the
747 * resume_tx_ports_list of this remote port. On posting the information, this
748 * function sequentially deletes each entry in the resume_tx_port_list of the
749 * remote port.
750 *
751 * Must be called with rport_ptr->quota_lock locked.
752 */
753static void post_resume_tx(struct msm_ipc_router_remote_port *rport_ptr,
754 struct rr_packet *pkt)
755{
756 struct msm_ipc_resume_tx_port *rtx_port, *tmp_rtx_port;
757 struct msm_ipc_port *local_port;
Zaheerulla Meera34fc662013-04-17 01:16:47 +0530758
759 list_for_each_entry_safe(rtx_port, tmp_rtx_port,
760 &rport_ptr->resume_tx_port_list, list) {
761 mutex_lock(&local_ports_lock);
762 local_port =
763 msm_ipc_router_lookup_local_port(rtx_port->port_id);
Karthikeyan Ramasubramaniand1af6252013-05-17 15:19:56 -0600764 if (local_port)
765 post_pkt_to_port(local_port, pkt, 1);
Zaheerulla Meera34fc662013-04-17 01:16:47 +0530766 mutex_unlock(&local_ports_lock);
767 list_del(&rtx_port->list);
768 kfree(rtx_port);
769 }
770}
771
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700772static void msm_ipc_router_destroy_remote_port(
773 struct msm_ipc_router_remote_port *rport_ptr)
774{
775 uint32_t node_id;
776 struct msm_ipc_routing_table_entry *rt_entry;
777
778 if (!rport_ptr)
779 return;
780
781 node_id = rport_ptr->node_id;
782 mutex_lock(&routing_table_lock);
783 rt_entry = lookup_routing_table(node_id);
784 if (!rt_entry) {
785 mutex_unlock(&routing_table_lock);
786 pr_err("%s: Node %d is not up\n", __func__, node_id);
787 return;
788 }
Zaheerulla Meera34fc662013-04-17 01:16:47 +0530789 mutex_lock(&rport_ptr->quota_lock);
790 msm_ipc_router_free_resume_tx_port(rport_ptr);
791 mutex_unlock(&rport_ptr->quota_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700792 mutex_lock(&rt_entry->lock);
793 list_del(&rport_ptr->list);
794 kfree(rport_ptr);
795 mutex_unlock(&rt_entry->lock);
796 mutex_unlock(&routing_table_lock);
797 return;
798}
799
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -0600800/**
801 * msm_ipc_router_lookup_server() - Lookup server information
802 * @service: Service ID of the server info to be looked up.
803 * @instance: Instance ID of the server info to be looked up.
804 * @node_id: Node/Processor ID in which the server is hosted.
805 * @port_id: Port ID within the node in which the server is hosted.
806 *
807 * @return: If found Pointer to server structure, else NULL.
808 *
809 * Note1: Lock the server_list_lock before accessing this function.
810 * Note2: If the <node_id:port_id> are <0:0>, then the lookup is restricted
811 * to <service:instance>. Used only when a client wants to send a
812 * message to any QMI server.
813 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700814static struct msm_ipc_server *msm_ipc_router_lookup_server(
815 uint32_t service,
816 uint32_t instance,
817 uint32_t node_id,
818 uint32_t port_id)
819{
820 struct msm_ipc_server *server;
821 struct msm_ipc_server_port *server_port;
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -0600822 int key = (service & (SRV_HASH_SIZE - 1));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700823
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700824 list_for_each_entry(server, &server_list[key], list) {
825 if ((server->name.service != service) ||
826 (server->name.instance != instance))
827 continue;
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -0600828 if ((node_id == 0) && (port_id == 0))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700829 return server;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700830 list_for_each_entry(server_port, &server->server_port_list,
831 list) {
832 if ((server_port->server_addr.node_id == node_id) &&
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -0600833 (server_port->server_addr.port_id == port_id))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700834 return server;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700835 }
836 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700837 return NULL;
838}
839
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -0600840static void dummy_release(struct device *dev)
841{
842}
843
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -0600844/**
845 * msm_ipc_router_create_server() - Add server info to hash table
846 * @service: Service ID of the server info to be created.
847 * @instance: Instance ID of the server info to be created.
848 * @node_id: Node/Processor ID in which the server is hosted.
849 * @port_id: Port ID within the node in which the server is hosted.
850 * @xprt_info: XPRT through which the node hosting the server is reached.
851 *
852 * @return: Pointer to server structure on success, else NULL.
853 *
854 * This function adds the server info to the hash table. If the same
855 * server(i.e. <service_id:instance_id>) is hosted in different nodes,
856 * they are maintained as list of "server_port" under "server" structure.
857 * Note: Lock the server_list_lock before accessing this function.
858 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700859static struct msm_ipc_server *msm_ipc_router_create_server(
860 uint32_t service,
861 uint32_t instance,
862 uint32_t node_id,
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600863 uint32_t port_id,
864 struct msm_ipc_router_xprt_info *xprt_info)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700865{
866 struct msm_ipc_server *server = NULL;
867 struct msm_ipc_server_port *server_port;
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -0600868 int key = (service & (SRV_HASH_SIZE - 1));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700869
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700870 list_for_each_entry(server, &server_list[key], list) {
871 if ((server->name.service == service) &&
872 (server->name.instance == instance))
873 goto create_srv_port;
874 }
875
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -0600876 server = kzalloc(sizeof(struct msm_ipc_server), GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700877 if (!server) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700878 pr_err("%s: Server allocation failed\n", __func__);
879 return NULL;
880 }
881 server->name.service = service;
882 server->name.instance = instance;
Karthikeyan Ramasubramanian1668cc62012-09-23 22:23:36 -0600883 server->synced_sec_rule = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700884 INIT_LIST_HEAD(&server->server_port_list);
885 list_add_tail(&server->list, &server_list[key]);
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -0600886 scnprintf(server->pdev_name, sizeof(server->pdev_name),
887 "QMI%08x:%08x", service, instance);
888 server->next_pdev_id = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700889
890create_srv_port:
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -0600891 server_port = kzalloc(sizeof(struct msm_ipc_server_port), GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700892 if (!server_port) {
893 if (list_empty(&server->server_port_list)) {
894 list_del(&server->list);
895 kfree(server);
896 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700897 pr_err("%s: Server Port allocation failed\n", __func__);
898 return NULL;
899 }
900 server_port->server_addr.node_id = node_id;
901 server_port->server_addr.port_id = port_id;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600902 server_port->xprt_info = xprt_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700903 list_add_tail(&server_port->list, &server->server_port_list);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700904
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -0600905 server_port->pdev.name = server->pdev_name;
906 server_port->pdev.id = server->next_pdev_id++;
907 server_port->pdev.dev.release = dummy_release;
908 platform_device_register(&server_port->pdev);
909
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700910 return server;
911}
912
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -0600913/**
914 * msm_ipc_router_destroy_server() - Remove server info from hash table
915 * @server: Server info to be removed.
916 * @node_id: Node/Processor ID in which the server is hosted.
917 * @port_id: Port ID within the node in which the server is hosted.
918 *
919 * This function removes the server_port identified using <node_id:port_id>
920 * from the server structure. If the server_port list under server structure
921 * is empty after removal, then remove the server structure from the server
922 * hash table.
923 * Note: Lock the server_list_lock before accessing this function.
924 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700925static void msm_ipc_router_destroy_server(struct msm_ipc_server *server,
926 uint32_t node_id, uint32_t port_id)
927{
928 struct msm_ipc_server_port *server_port;
929
930 if (!server)
931 return;
932
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700933 list_for_each_entry(server_port, &server->server_port_list, list) {
934 if ((server_port->server_addr.node_id == node_id) &&
935 (server_port->server_addr.port_id == port_id))
936 break;
937 }
938 if (server_port) {
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -0600939 platform_device_unregister(&server_port->pdev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700940 list_del(&server_port->list);
941 kfree(server_port);
942 }
943 if (list_empty(&server->server_port_list)) {
944 list_del(&server->list);
945 kfree(server);
946 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700947 return;
948}
949
950static int msm_ipc_router_send_control_msg(
951 struct msm_ipc_router_xprt_info *xprt_info,
952 union rr_control_msg *msg)
953{
954 struct rr_packet *pkt;
955 struct sk_buff *ipc_rtr_pkt;
956 struct rr_header *hdr;
957 int pkt_size;
958 void *data;
959 struct sk_buff_head *pkt_fragment_q;
960 int ret;
961
962 if (!xprt_info || ((msg->cmd != IPC_ROUTER_CTRL_CMD_HELLO) &&
963 !xprt_info->initialized)) {
964 pr_err("%s: xprt_info not initialized\n", __func__);
965 return -EINVAL;
966 }
967
968 if (xprt_info->remote_node_id == IPC_ROUTER_NID_LOCAL)
969 return 0;
970
971 pkt = kzalloc(sizeof(struct rr_packet), GFP_KERNEL);
972 if (!pkt) {
973 pr_err("%s: pkt alloc failed\n", __func__);
974 return -ENOMEM;
975 }
976
977 pkt_fragment_q = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
978 if (!pkt_fragment_q) {
979 pr_err("%s: pkt_fragment_q alloc failed\n", __func__);
980 kfree(pkt);
981 return -ENOMEM;
982 }
983 skb_queue_head_init(pkt_fragment_q);
984
985 pkt_size = IPC_ROUTER_HDR_SIZE + sizeof(*msg);
986 ipc_rtr_pkt = alloc_skb(pkt_size, GFP_KERNEL);
987 if (!ipc_rtr_pkt) {
988 pr_err("%s: ipc_rtr_pkt alloc failed\n", __func__);
989 kfree(pkt_fragment_q);
990 kfree(pkt);
991 return -ENOMEM;
992 }
993
994 skb_reserve(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
995 data = skb_put(ipc_rtr_pkt, sizeof(*msg));
996 memcpy(data, msg, sizeof(*msg));
997 hdr = (struct rr_header *)skb_push(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
998 if (!hdr) {
999 pr_err("%s: skb_push failed\n", __func__);
1000 kfree_skb(ipc_rtr_pkt);
1001 kfree(pkt_fragment_q);
1002 kfree(pkt);
1003 return -ENOMEM;
1004 }
1005
1006 hdr->version = IPC_ROUTER_VERSION;
1007 hdr->type = msg->cmd;
1008 hdr->src_node_id = IPC_ROUTER_NID_LOCAL;
1009 hdr->src_port_id = IPC_ROUTER_ADDRESS;
1010 hdr->confirm_rx = 0;
1011 hdr->size = sizeof(*msg);
1012 hdr->dst_node_id = xprt_info->remote_node_id;
1013 hdr->dst_port_id = IPC_ROUTER_ADDRESS;
1014 skb_queue_tail(pkt_fragment_q, ipc_rtr_pkt);
1015 pkt->pkt_fragment_q = pkt_fragment_q;
1016 pkt->length = pkt_size;
1017
1018 mutex_lock(&xprt_info->tx_lock);
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -07001019 ret = xprt_info->xprt->write(pkt, pkt_size, xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001020 mutex_unlock(&xprt_info->tx_lock);
1021
1022 release_pkt(pkt);
1023 return ret;
1024}
1025
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001026static int msm_ipc_router_send_server_list(uint32_t node_id,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001027 struct msm_ipc_router_xprt_info *xprt_info)
1028{
1029 union rr_control_msg ctl;
1030 struct msm_ipc_server *server;
1031 struct msm_ipc_server_port *server_port;
1032 int i;
1033
1034 if (!xprt_info || !xprt_info->initialized) {
1035 pr_err("%s: Xprt info not initialized\n", __func__);
1036 return -EINVAL;
1037 }
1038
1039 ctl.cmd = IPC_ROUTER_CTRL_CMD_NEW_SERVER;
1040
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001041 for (i = 0; i < SRV_HASH_SIZE; i++) {
1042 list_for_each_entry(server, &server_list[i], list) {
1043 ctl.srv.service = server->name.service;
1044 ctl.srv.instance = server->name.instance;
1045 list_for_each_entry(server_port,
1046 &server->server_port_list, list) {
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001047 if (server_port->server_addr.node_id !=
1048 node_id)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001049 continue;
1050
1051 ctl.srv.node_id =
1052 server_port->server_addr.node_id;
1053 ctl.srv.port_id =
1054 server_port->server_addr.port_id;
1055 msm_ipc_router_send_control_msg(xprt_info,
1056 &ctl);
1057 }
1058 }
1059 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001060
1061 return 0;
1062}
1063
1064#if defined(DEBUG)
1065static char *type_to_str(int i)
1066{
1067 switch (i) {
1068 case IPC_ROUTER_CTRL_CMD_DATA:
1069 return "data ";
1070 case IPC_ROUTER_CTRL_CMD_HELLO:
1071 return "hello ";
1072 case IPC_ROUTER_CTRL_CMD_BYE:
1073 return "bye ";
1074 case IPC_ROUTER_CTRL_CMD_NEW_SERVER:
1075 return "new_srvr";
1076 case IPC_ROUTER_CTRL_CMD_REMOVE_SERVER:
1077 return "rmv_srvr";
1078 case IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT:
1079 return "rmv_clnt";
1080 case IPC_ROUTER_CTRL_CMD_RESUME_TX:
1081 return "resum_tx";
1082 case IPC_ROUTER_CTRL_CMD_EXIT:
1083 return "cmd_exit";
1084 default:
1085 return "invalid";
1086 }
1087}
1088#endif
1089
1090static int broadcast_ctl_msg_locally(union rr_control_msg *msg)
1091{
1092 struct rr_packet *pkt;
1093 struct sk_buff *ipc_rtr_pkt;
1094 struct rr_header *hdr;
1095 int pkt_size;
1096 void *data;
1097 struct sk_buff_head *pkt_fragment_q;
1098 int ret;
1099
1100 pkt = kzalloc(sizeof(struct rr_packet), GFP_KERNEL);
1101 if (!pkt) {
1102 pr_err("%s: pkt alloc failed\n", __func__);
1103 return -ENOMEM;
1104 }
1105
1106 pkt_fragment_q = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
1107 if (!pkt_fragment_q) {
1108 pr_err("%s: pkt_fragment_q alloc failed\n", __func__);
1109 kfree(pkt);
1110 return -ENOMEM;
1111 }
1112 skb_queue_head_init(pkt_fragment_q);
1113
1114 pkt_size = IPC_ROUTER_HDR_SIZE + sizeof(*msg);
1115 ipc_rtr_pkt = alloc_skb(pkt_size, GFP_KERNEL);
1116 if (!ipc_rtr_pkt) {
1117 pr_err("%s: ipc_rtr_pkt alloc failed\n", __func__);
1118 kfree(pkt_fragment_q);
1119 kfree(pkt);
1120 return -ENOMEM;
1121 }
1122
1123 skb_reserve(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
1124 data = skb_put(ipc_rtr_pkt, sizeof(*msg));
1125 memcpy(data, msg, sizeof(*msg));
1126 hdr = (struct rr_header *)skb_push(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
1127 if (!hdr) {
1128 pr_err("%s: skb_push failed\n", __func__);
1129 kfree_skb(ipc_rtr_pkt);
1130 kfree(pkt_fragment_q);
1131 kfree(pkt);
1132 return -ENOMEM;
1133 }
1134 hdr->version = IPC_ROUTER_VERSION;
1135 hdr->type = msg->cmd;
1136 hdr->src_node_id = IPC_ROUTER_NID_LOCAL;
1137 hdr->src_port_id = IPC_ROUTER_ADDRESS;
1138 hdr->confirm_rx = 0;
1139 hdr->size = sizeof(*msg);
1140 hdr->dst_node_id = IPC_ROUTER_NID_LOCAL;
1141 hdr->dst_port_id = IPC_ROUTER_ADDRESS;
1142 skb_queue_tail(pkt_fragment_q, ipc_rtr_pkt);
1143 pkt->pkt_fragment_q = pkt_fragment_q;
1144 pkt->length = pkt_size;
1145
1146 ret = post_control_ports(pkt);
1147 release_pkt(pkt);
1148 return ret;
1149}
1150
1151static int broadcast_ctl_msg(union rr_control_msg *ctl)
1152{
1153 struct msm_ipc_router_xprt_info *xprt_info;
1154
1155 mutex_lock(&xprt_info_list_lock);
1156 list_for_each_entry(xprt_info, &xprt_info_list, list) {
1157 msm_ipc_router_send_control_msg(xprt_info, ctl);
1158 }
1159 mutex_unlock(&xprt_info_list_lock);
1160
1161 return 0;
1162}
1163
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001164static int relay_ctl_msg(struct msm_ipc_router_xprt_info *xprt_info,
1165 union rr_control_msg *ctl)
1166{
1167 struct msm_ipc_router_xprt_info *fwd_xprt_info;
1168
1169 if (!xprt_info || !ctl)
1170 return -EINVAL;
1171
1172 mutex_lock(&xprt_info_list_lock);
1173 list_for_each_entry(fwd_xprt_info, &xprt_info_list, list) {
1174 if (xprt_info->xprt->link_id != fwd_xprt_info->xprt->link_id)
1175 msm_ipc_router_send_control_msg(fwd_xprt_info, ctl);
1176 }
1177 mutex_unlock(&xprt_info_list_lock);
1178
1179 return 0;
1180}
1181
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001182static int relay_msg(struct msm_ipc_router_xprt_info *xprt_info,
1183 struct rr_packet *pkt)
1184{
1185 struct msm_ipc_router_xprt_info *fwd_xprt_info;
1186
1187 if (!xprt_info || !pkt)
1188 return -EINVAL;
1189
1190 mutex_lock(&xprt_info_list_lock);
1191 list_for_each_entry(fwd_xprt_info, &xprt_info_list, list) {
1192 mutex_lock(&fwd_xprt_info->tx_lock);
1193 if (xprt_info->xprt->link_id != fwd_xprt_info->xprt->link_id)
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -07001194 fwd_xprt_info->xprt->write(pkt, pkt->length,
1195 fwd_xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001196 mutex_unlock(&fwd_xprt_info->tx_lock);
1197 }
1198 mutex_unlock(&xprt_info_list_lock);
1199 return 0;
1200}
1201
1202static int forward_msg(struct msm_ipc_router_xprt_info *xprt_info,
1203 struct rr_packet *pkt)
1204{
1205 uint32_t dst_node_id;
1206 struct sk_buff *head_pkt;
1207 struct rr_header *hdr;
1208 struct msm_ipc_router_xprt_info *fwd_xprt_info;
1209 struct msm_ipc_routing_table_entry *rt_entry;
1210
1211 if (!xprt_info || !pkt)
1212 return -EINVAL;
1213
1214 head_pkt = skb_peek(pkt->pkt_fragment_q);
1215 if (!head_pkt)
1216 return -EINVAL;
1217
1218 hdr = (struct rr_header *)head_pkt->data;
1219 dst_node_id = hdr->dst_node_id;
1220 mutex_lock(&routing_table_lock);
1221 rt_entry = lookup_routing_table(dst_node_id);
1222 if (!(rt_entry) || !(rt_entry->xprt_info)) {
1223 mutex_unlock(&routing_table_lock);
1224 pr_err("%s: Routing table not initialized\n", __func__);
1225 return -ENODEV;
1226 }
1227
1228 mutex_lock(&rt_entry->lock);
1229 fwd_xprt_info = rt_entry->xprt_info;
1230 mutex_lock(&fwd_xprt_info->tx_lock);
1231 if (xprt_info->remote_node_id == fwd_xprt_info->remote_node_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: Discarding Command to route back\n", __func__);
1236 return -EINVAL;
1237 }
1238
1239 if (xprt_info->xprt->link_id == fwd_xprt_info->xprt->link_id) {
1240 mutex_unlock(&fwd_xprt_info->tx_lock);
1241 mutex_unlock(&rt_entry->lock);
1242 mutex_unlock(&routing_table_lock);
1243 pr_err("%s: DST in the same cluster\n", __func__);
1244 return 0;
1245 }
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -07001246 fwd_xprt_info->xprt->write(pkt, pkt->length, fwd_xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001247 mutex_unlock(&fwd_xprt_info->tx_lock);
1248 mutex_unlock(&rt_entry->lock);
1249 mutex_unlock(&routing_table_lock);
1250
1251 return 0;
1252}
1253
Karthikeyan Ramasubramaniandc9c4442013-05-02 17:25:54 -06001254static int msm_ipc_router_send_remove_client(struct comm_mode_info *mode_info,
1255 uint32_t node_id, uint32_t port_id)
1256{
1257 union rr_control_msg msg;
1258 struct msm_ipc_router_xprt_info *tmp_xprt_info;
1259 int mode;
1260 void *xprt_info;
1261 int rc = 0;
1262
1263 if (!mode_info) {
1264 pr_err("%s: NULL mode_info\n", __func__);
1265 return -EINVAL;
1266 }
1267 mode = mode_info->mode;
1268 xprt_info = mode_info->xprt_info;
1269
1270 msg.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT;
1271 msg.cli.node_id = node_id;
1272 msg.cli.port_id = port_id;
1273
1274 if ((mode == SINGLE_LINK_MODE) && xprt_info) {
1275 mutex_lock(&xprt_info_list_lock);
1276 list_for_each_entry(tmp_xprt_info, &xprt_info_list, list) {
1277 if (tmp_xprt_info != xprt_info)
1278 continue;
1279 msm_ipc_router_send_control_msg(tmp_xprt_info, &msg);
1280 break;
1281 }
1282 mutex_unlock(&xprt_info_list_lock);
1283 } else if ((mode == SINGLE_LINK_MODE) && !xprt_info) {
1284 broadcast_ctl_msg_locally(&msg);
1285 } else if (mode == MULTI_LINK_MODE) {
1286 broadcast_ctl_msg(&msg);
1287 broadcast_ctl_msg_locally(&msg);
1288 } else if (mode != NULL_MODE) {
1289 pr_err("%s: Invalid mode(%d) + xprt_inf(%p) for %08x:%08x\n",
1290 __func__, mode, xprt_info, node_id, port_id);
1291 rc = -EINVAL;
1292 }
1293 return rc;
1294}
1295
1296static void update_comm_mode_info(struct comm_mode_info *mode_info,
1297 struct msm_ipc_router_xprt_info *xprt_info)
1298{
1299 if (!mode_info) {
1300 pr_err("%s: NULL mode_info\n", __func__);
1301 return;
1302 }
1303
1304 if (mode_info->mode == NULL_MODE) {
1305 mode_info->xprt_info = xprt_info;
1306 mode_info->mode = SINGLE_LINK_MODE;
1307 } else if (mode_info->mode == SINGLE_LINK_MODE &&
1308 mode_info->xprt_info != xprt_info) {
1309 mode_info->mode = MULTI_LINK_MODE;
1310 }
1311
1312 return;
1313}
1314
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001315static void reset_remote_port_info(uint32_t node_id, uint32_t port_id)
1316{
1317 struct msm_ipc_router_remote_port *rport_ptr;
1318
1319 rport_ptr = msm_ipc_router_lookup_remote_port(node_id, port_id);
1320 if (!rport_ptr) {
1321 pr_err("%s: No such remote port %08x:%08x\n",
1322 __func__, node_id, port_id);
1323 return;
1324 }
1325 mutex_lock(&rport_ptr->quota_lock);
1326 rport_ptr->restart_state = RESTART_PEND;
Zaheerulla Meera34fc662013-04-17 01:16:47 +05301327 msm_ipc_router_free_resume_tx_port(rport_ptr);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001328 mutex_unlock(&rport_ptr->quota_lock);
1329 return;
1330}
1331
1332static void msm_ipc_cleanup_remote_server_info(
1333 struct msm_ipc_router_xprt_info *xprt_info)
1334{
1335 struct msm_ipc_server *svr, *tmp_svr;
1336 struct msm_ipc_server_port *svr_port, *tmp_svr_port;
1337 int i;
1338 union rr_control_msg ctl;
1339
1340 if (!xprt_info) {
1341 pr_err("%s: Invalid xprt_info\n", __func__);
1342 return;
1343 }
1344
1345 ctl.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_SERVER;
1346 mutex_lock(&server_list_lock);
1347 for (i = 0; i < SRV_HASH_SIZE; i++) {
1348 list_for_each_entry_safe(svr, tmp_svr, &server_list[i], list) {
1349 ctl.srv.service = svr->name.service;
1350 ctl.srv.instance = svr->name.instance;
1351 list_for_each_entry_safe(svr_port, tmp_svr_port,
1352 &svr->server_port_list, list) {
1353 if (svr_port->xprt_info != xprt_info)
1354 continue;
1355 D("Remove server %08x:%08x - %08x:%08x",
1356 ctl.srv.service, ctl.srv.instance,
1357 svr_port->server_addr.node_id,
1358 svr_port->server_addr.port_id);
1359 reset_remote_port_info(
1360 svr_port->server_addr.node_id,
1361 svr_port->server_addr.port_id);
1362 ctl.srv.node_id = svr_port->server_addr.node_id;
1363 ctl.srv.port_id = svr_port->server_addr.port_id;
1364 relay_ctl_msg(xprt_info, &ctl);
1365 broadcast_ctl_msg_locally(&ctl);
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -06001366 platform_device_unregister(&svr_port->pdev);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001367 list_del(&svr_port->list);
1368 kfree(svr_port);
1369 }
1370 if (list_empty(&svr->server_port_list)) {
1371 list_del(&svr->list);
1372 kfree(svr);
1373 }
1374 }
1375 }
1376 mutex_unlock(&server_list_lock);
1377}
1378
1379static void msm_ipc_cleanup_remote_client_info(
1380 struct msm_ipc_router_xprt_info *xprt_info)
1381{
1382 struct msm_ipc_routing_table_entry *rt_entry;
1383 struct msm_ipc_router_remote_port *rport_ptr;
1384 int i, j;
1385 union rr_control_msg ctl;
1386
1387 if (!xprt_info) {
1388 pr_err("%s: Invalid xprt_info\n", __func__);
1389 return;
1390 }
1391
1392 ctl.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT;
1393 mutex_lock(&routing_table_lock);
1394 for (i = 0; i < RT_HASH_SIZE; i++) {
1395 list_for_each_entry(rt_entry, &routing_table[i], list) {
1396 mutex_lock(&rt_entry->lock);
1397 if (rt_entry->xprt_info != xprt_info) {
1398 mutex_unlock(&rt_entry->lock);
1399 continue;
1400 }
1401 for (j = 0; j < RP_HASH_SIZE; j++) {
1402 list_for_each_entry(rport_ptr,
1403 &rt_entry->remote_port_list[j], list) {
1404 if (rport_ptr->restart_state ==
1405 RESTART_PEND)
1406 continue;
1407 mutex_lock(&rport_ptr->quota_lock);
1408 rport_ptr->restart_state = RESTART_PEND;
Zaheerulla Meera34fc662013-04-17 01:16:47 +05301409 msm_ipc_router_free_resume_tx_port(
1410 rport_ptr);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001411 mutex_unlock(&rport_ptr->quota_lock);
1412 ctl.cli.node_id = rport_ptr->node_id;
1413 ctl.cli.port_id = rport_ptr->port_id;
1414 broadcast_ctl_msg_locally(&ctl);
1415 }
1416 }
1417 mutex_unlock(&rt_entry->lock);
1418 }
1419 }
1420 mutex_unlock(&routing_table_lock);
1421}
1422
1423static void msm_ipc_cleanup_remote_port_info(uint32_t node_id)
1424{
1425 struct msm_ipc_routing_table_entry *rt_entry, *tmp_rt_entry;
1426 struct msm_ipc_router_remote_port *rport_ptr, *tmp_rport_ptr;
1427 int i, j;
1428
1429 mutex_lock(&routing_table_lock);
1430 for (i = 0; i < RT_HASH_SIZE; i++) {
1431 list_for_each_entry_safe(rt_entry, tmp_rt_entry,
1432 &routing_table[i], list) {
1433 mutex_lock(&rt_entry->lock);
1434 if (rt_entry->neighbor_node_id != node_id) {
1435 mutex_unlock(&rt_entry->lock);
1436 continue;
1437 }
1438 for (j = 0; j < RP_HASH_SIZE; j++) {
1439 list_for_each_entry_safe(rport_ptr,
1440 tmp_rport_ptr,
1441 &rt_entry->remote_port_list[j], list) {
1442 list_del(&rport_ptr->list);
1443 kfree(rport_ptr);
1444 }
1445 }
1446 mutex_unlock(&rt_entry->lock);
1447 }
1448 }
1449 mutex_unlock(&routing_table_lock);
1450}
1451
1452static void msm_ipc_cleanup_routing_table(
1453 struct msm_ipc_router_xprt_info *xprt_info)
1454{
1455 int i;
1456 struct msm_ipc_routing_table_entry *rt_entry;
1457
1458 if (!xprt_info) {
1459 pr_err("%s: Invalid xprt_info\n", __func__);
1460 return;
1461 }
1462
1463 mutex_lock(&routing_table_lock);
1464 for (i = 0; i < RT_HASH_SIZE; i++) {
1465 list_for_each_entry(rt_entry, &routing_table[i], list) {
1466 mutex_lock(&rt_entry->lock);
1467 if (rt_entry->xprt_info == xprt_info)
1468 rt_entry->xprt_info = NULL;
1469 mutex_unlock(&rt_entry->lock);
1470 }
1471 }
1472 mutex_unlock(&routing_table_lock);
1473}
1474
1475static void modem_reset_cleanup(struct msm_ipc_router_xprt_info *xprt_info)
1476{
1477
1478 if (!xprt_info) {
1479 pr_err("%s: Invalid xprt_info\n", __func__);
1480 return;
1481 }
1482
1483 msm_ipc_cleanup_remote_server_info(xprt_info);
1484 msm_ipc_cleanup_remote_client_info(xprt_info);
1485 msm_ipc_cleanup_routing_table(xprt_info);
1486}
1487
Karthikeyan Ramasubramanian1668cc62012-09-23 22:23:36 -06001488/**
1489 * sync_sec_rule() - Synchrnoize the security rule into the server structure
1490 * @server: Server structure where the rule has to be synchronized.
1491 * @rule: Security tule to be synchronized.
1492 *
1493 * This function is used to update the server structure with the security
1494 * rule configured for the <service:instance> corresponding to that server.
1495 */
1496static void sync_sec_rule(struct msm_ipc_server *server, void *rule)
1497{
1498 struct msm_ipc_server_port *server_port;
1499 struct msm_ipc_router_remote_port *rport_ptr = NULL;
1500
1501 list_for_each_entry(server_port, &server->server_port_list, list) {
1502 rport_ptr = msm_ipc_router_lookup_remote_port(
1503 server_port->server_addr.node_id,
1504 server_port->server_addr.port_id);
1505 if (!rport_ptr)
1506 continue;
1507 rport_ptr->sec_rule = rule;
1508 }
1509 server->synced_sec_rule = 1;
1510}
1511
1512/**
1513 * msm_ipc_sync_sec_rule() - Sync the security rule to the service
1514 * @service: Service for which the rule has to be synchronized.
1515 * @instance: Instance for which the rule has to be synchronized.
1516 * @rule: Security rule to be synchronized.
1517 *
1518 * This function is used to syncrhonize the security rule with the server
1519 * hash table, if the user-space script configures the rule after the service
1520 * has come up. This function is used to synchronize the security rule to a
1521 * specific service and optionally a specific instance.
1522 */
1523void msm_ipc_sync_sec_rule(uint32_t service, uint32_t instance, void *rule)
1524{
1525 int key = (service & (SRV_HASH_SIZE - 1));
1526 struct msm_ipc_server *server;
1527
1528 mutex_lock(&server_list_lock);
1529 list_for_each_entry(server, &server_list[key], list) {
1530 if (server->name.service != service)
1531 continue;
1532
1533 if (server->name.instance != instance &&
1534 instance != ALL_INSTANCE)
1535 continue;
1536
1537 /*
1538 * If the rule applies to all instances and if the specific
1539 * instance of a service has a rule synchronized already,
1540 * do not apply the rule for that specific instance.
1541 */
1542 if (instance == ALL_INSTANCE && server->synced_sec_rule)
1543 continue;
1544
1545 sync_sec_rule(server, rule);
1546 }
1547 mutex_unlock(&server_list_lock);
1548}
1549
1550/**
1551 * msm_ipc_sync_default_sec_rule() - Default security rule to all services
1552 * @rule: Security rule to be synchronized.
1553 *
1554 * This function is used to syncrhonize the security rule with the server
1555 * hash table, if the user-space script configures the rule after the service
1556 * has come up. This function is used to synchronize the security rule that
1557 * applies to all services, if the concerned service do not have any rule
1558 * defined.
1559 */
1560void msm_ipc_sync_default_sec_rule(void *rule)
1561{
1562 int key;
1563 struct msm_ipc_server *server;
1564
1565 mutex_lock(&server_list_lock);
1566 for (key = 0; key < SRV_HASH_SIZE; key++) {
1567 list_for_each_entry(server, &server_list[key], list) {
1568 if (server->synced_sec_rule)
1569 continue;
1570
1571 sync_sec_rule(server, rule);
1572 }
1573 }
1574 mutex_unlock(&server_list_lock);
1575}
1576
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001577static int process_hello_msg(struct msm_ipc_router_xprt_info *xprt_info,
1578 struct rr_header *hdr)
1579{
1580 int i, rc = 0;
1581 union rr_control_msg ctl;
1582 struct msm_ipc_routing_table_entry *rt_entry;
1583
1584 if (!hdr)
1585 return -EINVAL;
1586
1587 RR("o HELLO NID %d\n", hdr->src_node_id);
1588
1589 xprt_info->remote_node_id = hdr->src_node_id;
1590 /*
1591 * Find the entry from Routing Table corresponding to Node ID.
1592 * Under SSR, an entry will be found. When the system boots up
1593 * for the 1st time, an entry will not be found and hence allocate
1594 * an entry. Update the entry with the Node ID that it corresponds
1595 * to and the XPRT through which it can be reached.
1596 */
1597 mutex_lock(&routing_table_lock);
1598 rt_entry = lookup_routing_table(hdr->src_node_id);
1599 if (!rt_entry) {
1600 rt_entry = alloc_routing_table_entry(hdr->src_node_id);
1601 if (!rt_entry) {
1602 mutex_unlock(&routing_table_lock);
1603 pr_err("%s: rt_entry allocation failed\n", __func__);
1604 return -ENOMEM;
1605 }
1606 add_routing_table_entry(rt_entry);
1607 }
1608 mutex_lock(&rt_entry->lock);
1609 rt_entry->neighbor_node_id = xprt_info->remote_node_id;
1610 rt_entry->xprt_info = xprt_info;
1611 mutex_unlock(&rt_entry->lock);
1612 mutex_unlock(&routing_table_lock);
1613
1614 /* Cleanup any remote ports, if the node is coming out of reset */
1615 msm_ipc_cleanup_remote_port_info(xprt_info->remote_node_id);
1616
1617 /* Send a reply HELLO message */
1618 memset(&ctl, 0, sizeof(ctl));
1619 ctl.cmd = IPC_ROUTER_CTRL_CMD_HELLO;
1620 rc = msm_ipc_router_send_control_msg(xprt_info, &ctl);
1621 if (rc < 0) {
1622 pr_err("%s: Error sending reply HELLO message\n", __func__);
1623 return rc;
1624 }
1625 xprt_info->initialized = 1;
1626
1627 /*
1628 * Send list of servers from the local node and from nodes
1629 * outside the mesh network in which this XPRT is part of.
1630 */
Karthikeyan Ramasubramaniane8ad5352012-10-31 15:12:08 -06001631 mutex_lock(&server_list_lock);
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001632 mutex_lock(&routing_table_lock);
1633 for (i = 0; i < RT_HASH_SIZE; i++) {
1634 list_for_each_entry(rt_entry, &routing_table[i], list) {
1635 if ((rt_entry->node_id != IPC_ROUTER_NID_LOCAL) &&
Karthikeyan Ramasubramanian72ad5792013-01-30 14:17:57 -07001636 (!rt_entry->xprt_info ||
1637 (rt_entry->xprt_info->xprt->link_id ==
1638 xprt_info->xprt->link_id)))
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001639 continue;
1640 rc = msm_ipc_router_send_server_list(rt_entry->node_id,
1641 xprt_info);
1642 if (rc < 0) {
1643 mutex_unlock(&routing_table_lock);
Karthikeyan Ramasubramaniane8ad5352012-10-31 15:12:08 -06001644 mutex_unlock(&server_list_lock);
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001645 return rc;
1646 }
1647 }
1648 }
1649 mutex_unlock(&routing_table_lock);
Karthikeyan Ramasubramaniane8ad5352012-10-31 15:12:08 -06001650 mutex_unlock(&server_list_lock);
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001651 RR("HELLO message processed\n");
1652 return rc;
1653}
1654
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001655static int process_control_msg(struct msm_ipc_router_xprt_info *xprt_info,
1656 struct rr_packet *pkt)
1657{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001658 union rr_control_msg *msg;
1659 struct msm_ipc_router_remote_port *rport_ptr;
1660 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001661 struct sk_buff *temp_ptr;
1662 struct rr_header *hdr;
1663 struct msm_ipc_server *server;
1664 struct msm_ipc_routing_table_entry *rt_entry;
1665
1666 if (pkt->length != (IPC_ROUTER_HDR_SIZE + sizeof(*msg))) {
1667 pr_err("%s: r2r msg size %d != %d\n", __func__, pkt->length,
1668 (IPC_ROUTER_HDR_SIZE + sizeof(*msg)));
1669 return -EINVAL;
1670 }
1671
1672 temp_ptr = skb_peek(pkt->pkt_fragment_q);
Karthikeyan Ramasubramanian9024dd82011-12-19 18:44:19 -07001673 if (!temp_ptr) {
1674 pr_err("%s: pkt_fragment_q is empty\n", __func__);
1675 return -EINVAL;
1676 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001677 hdr = (struct rr_header *)temp_ptr->data;
Karthikeyan Ramasubramanian9024dd82011-12-19 18:44:19 -07001678 if (!hdr) {
1679 pr_err("%s: No data inside the skb\n", __func__);
1680 return -EINVAL;
1681 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001682 msg = (union rr_control_msg *)((char *)hdr + IPC_ROUTER_HDR_SIZE);
1683
1684 switch (msg->cmd) {
1685 case IPC_ROUTER_CTRL_CMD_HELLO:
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001686 rc = process_hello_msg(xprt_info, hdr);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001687 break;
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001688
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001689 case IPC_ROUTER_CTRL_CMD_RESUME_TX:
1690 RR("o RESUME_TX id=%d:%08x\n",
1691 msg->cli.node_id, msg->cli.port_id);
1692
1693 rport_ptr = msm_ipc_router_lookup_remote_port(msg->cli.node_id,
1694 msg->cli.port_id);
1695 if (!rport_ptr) {
1696 pr_err("%s: Unable to resume client\n", __func__);
1697 break;
1698 }
1699 mutex_lock(&rport_ptr->quota_lock);
1700 rport_ptr->tx_quota_cnt = 0;
Zaheerulla Meera34fc662013-04-17 01:16:47 +05301701 post_resume_tx(rport_ptr, pkt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001702 mutex_unlock(&rport_ptr->quota_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001703 break;
1704
1705 case IPC_ROUTER_CTRL_CMD_NEW_SERVER:
1706 if (msg->srv.instance == 0) {
1707 pr_err(
1708 "rpcrouter: Server create rejected, version = 0, "
1709 "service = %08x\n", msg->srv.service);
1710 break;
1711 }
1712
1713 RR("o NEW_SERVER id=%d:%08x service=%08x:%08x\n",
1714 msg->srv.node_id, msg->srv.port_id,
1715 msg->srv.service, msg->srv.instance);
1716
1717 mutex_lock(&routing_table_lock);
1718 rt_entry = lookup_routing_table(msg->srv.node_id);
1719 if (!rt_entry) {
1720 rt_entry = alloc_routing_table_entry(msg->srv.node_id);
1721 if (!rt_entry) {
1722 mutex_unlock(&routing_table_lock);
1723 pr_err("%s: rt_entry allocation failed\n",
1724 __func__);
1725 return -ENOMEM;
1726 }
1727 mutex_lock(&rt_entry->lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001728 rt_entry->neighbor_node_id = xprt_info->remote_node_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001729 rt_entry->xprt_info = xprt_info;
1730 mutex_unlock(&rt_entry->lock);
1731 add_routing_table_entry(rt_entry);
1732 }
1733 mutex_unlock(&routing_table_lock);
1734
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001735 mutex_lock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001736 server = msm_ipc_router_lookup_server(msg->srv.service,
1737 msg->srv.instance,
1738 msg->srv.node_id,
1739 msg->srv.port_id);
1740 if (!server) {
1741 server = msm_ipc_router_create_server(
1742 msg->srv.service, msg->srv.instance,
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001743 msg->srv.node_id, msg->srv.port_id, xprt_info);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001744 if (!server) {
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001745 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001746 pr_err("%s: Server Create failed\n", __func__);
1747 return -ENOMEM;
1748 }
1749
1750 if (!msm_ipc_router_lookup_remote_port(
1751 msg->srv.node_id, msg->srv.port_id)) {
1752 rport_ptr = msm_ipc_router_create_remote_port(
1753 msg->srv.node_id, msg->srv.port_id);
1754 if (!rport_ptr)
1755 pr_err("%s: Remote port create "
1756 "failed\n", __func__);
Brent Hronik0e83d3b2013-05-01 16:25:00 -06001757 else
1758 rport_ptr->sec_rule =
1759 msm_ipc_get_security_rule(
1760 msg->srv.service,
1761 msg->srv.instance);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001762 }
1763 wake_up(&newserver_wait);
1764 }
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001765 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001766
1767 relay_msg(xprt_info, pkt);
1768 post_control_ports(pkt);
1769 break;
1770 case IPC_ROUTER_CTRL_CMD_REMOVE_SERVER:
1771 RR("o REMOVE_SERVER service=%08x:%d\n",
1772 msg->srv.service, msg->srv.instance);
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001773 mutex_lock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001774 server = msm_ipc_router_lookup_server(msg->srv.service,
1775 msg->srv.instance,
1776 msg->srv.node_id,
1777 msg->srv.port_id);
1778 if (server) {
1779 msm_ipc_router_destroy_server(server,
1780 msg->srv.node_id,
1781 msg->srv.port_id);
1782 relay_msg(xprt_info, pkt);
1783 post_control_ports(pkt);
1784 }
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001785 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001786 break;
1787 case IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT:
1788 RR("o REMOVE_CLIENT id=%d:%08x\n",
1789 msg->cli.node_id, msg->cli.port_id);
1790 rport_ptr = msm_ipc_router_lookup_remote_port(msg->cli.node_id,
1791 msg->cli.port_id);
1792 if (rport_ptr)
1793 msm_ipc_router_destroy_remote_port(rport_ptr);
1794
1795 relay_msg(xprt_info, pkt);
1796 post_control_ports(pkt);
1797 break;
1798 case IPC_ROUTER_CTRL_CMD_PING:
1799 /* No action needed for ping messages received */
1800 RR("o PING\n");
1801 break;
1802 default:
1803 RR("o UNKNOWN(%08x)\n", msg->cmd);
1804 rc = -ENOSYS;
1805 }
1806
1807 return rc;
1808}
1809
1810static void do_read_data(struct work_struct *work)
1811{
1812 struct rr_header *hdr;
1813 struct rr_packet *pkt = NULL;
1814 struct msm_ipc_port *port_ptr;
1815 struct sk_buff *head_skb;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001816 struct msm_ipc_router_remote_port *rport_ptr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001817 uint32_t resume_tx, resume_tx_node_id, resume_tx_port_id;
1818
1819 struct msm_ipc_router_xprt_info *xprt_info =
1820 container_of(work,
1821 struct msm_ipc_router_xprt_info,
1822 read_data);
1823
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001824 while ((pkt = rr_read(xprt_info)) != NULL) {
1825 if (pkt->length < IPC_ROUTER_HDR_SIZE ||
1826 pkt->length > MAX_IPC_PKT_SIZE) {
1827 pr_err("%s: Invalid pkt length %d\n",
1828 __func__, pkt->length);
1829 goto fail_data;
1830 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001831
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001832 head_skb = skb_peek(pkt->pkt_fragment_q);
1833 if (!head_skb) {
1834 pr_err("%s: head_skb is invalid\n", __func__);
1835 goto fail_data;
1836 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001837
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001838 hdr = (struct rr_header *)(head_skb->data);
Karthikeyan Ramasubramanian682ebcc2013-03-22 10:47:20 -06001839 RAW("ver=%d type=%d src=%d:%08x crx=%d siz=%d dst=%d:%08x\n",
1840 hdr->version, hdr->type, hdr->src_node_id,
1841 hdr->src_port_id, hdr->confirm_rx, hdr->size,
1842 hdr->dst_node_id, hdr->dst_port_id);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001843
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001844 if (hdr->version != IPC_ROUTER_VERSION) {
1845 pr_err("version %d != %d\n",
1846 hdr->version, IPC_ROUTER_VERSION);
1847 goto fail_data;
1848 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001849
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001850 if ((hdr->dst_node_id != IPC_ROUTER_NID_LOCAL) &&
1851 ((hdr->type == IPC_ROUTER_CTRL_CMD_RESUME_TX) ||
1852 (hdr->type == IPC_ROUTER_CTRL_CMD_DATA))) {
1853 forward_msg(xprt_info, pkt);
1854 release_pkt(pkt);
1855 continue;
1856 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001857
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001858 if ((hdr->dst_port_id == IPC_ROUTER_ADDRESS) ||
1859 (hdr->type == IPC_ROUTER_CTRL_CMD_HELLO)) {
1860 process_control_msg(xprt_info, pkt);
1861 release_pkt(pkt);
1862 continue;
1863 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001864#if defined(CONFIG_MSM_SMD_LOGGING)
1865#if defined(DEBUG)
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001866 if (msm_ipc_router_debug_mask & SMEM_LOG) {
1867 smem_log_event((SMEM_LOG_PROC_ID_APPS |
1868 SMEM_LOG_RPC_ROUTER_EVENT_BASE |
1869 IPC_ROUTER_LOG_EVENT_RX),
1870 (hdr->src_node_id << 24) |
1871 (hdr->src_port_id & 0xffffff),
1872 (hdr->dst_node_id << 24) |
1873 (hdr->dst_port_id & 0xffffff),
1874 (hdr->type << 24) | (hdr->confirm_rx << 16) |
1875 (hdr->size & 0xffff));
1876 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001877#endif
1878#endif
1879
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001880 resume_tx = hdr->confirm_rx;
1881 resume_tx_node_id = hdr->dst_node_id;
1882 resume_tx_port_id = hdr->dst_port_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001883
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001884 rport_ptr = msm_ipc_router_lookup_remote_port(hdr->src_node_id,
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06001885 hdr->src_port_id);
1886
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001887 mutex_lock(&local_ports_lock);
1888 port_ptr = msm_ipc_router_lookup_local_port(hdr->dst_port_id);
1889 if (!port_ptr) {
1890 pr_err("%s: No local port id %08x\n", __func__,
1891 hdr->dst_port_id);
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06001892 mutex_unlock(&local_ports_lock);
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001893 release_pkt(pkt);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001894 goto process_done;
1895 }
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001896
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001897 if (!rport_ptr) {
1898 rport_ptr = msm_ipc_router_create_remote_port(
1899 hdr->src_node_id,
1900 hdr->src_port_id);
1901 if (!rport_ptr) {
1902 pr_err("%s: Rmt Prt %08x:%08x create failed\n",
1903 __func__, hdr->src_node_id,
1904 hdr->src_port_id);
1905 mutex_unlock(&local_ports_lock);
1906 goto process_done;
1907 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001908 }
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001909
Karthikeyan Ramasubramaniand1af6252013-05-17 15:19:56 -06001910 post_pkt_to_port(port_ptr, pkt, 0);
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -06001911 mutex_unlock(&local_ports_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001912
1913process_done:
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001914 if (resume_tx) {
1915 union rr_control_msg msg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001916
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001917 msg.cmd = IPC_ROUTER_CTRL_CMD_RESUME_TX;
1918 msg.cli.node_id = resume_tx_node_id;
1919 msg.cli.port_id = resume_tx_port_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001920
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001921 RR("x RESUME_TX id=%d:%08x\n",
1922 msg.cli.node_id, msg.cli.port_id);
1923 msm_ipc_router_send_control_msg(xprt_info, &msg);
1924 }
1925
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001926 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001927 return;
1928
1929fail_data:
1930 release_pkt(pkt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001931 pr_err("ipc_router has died\n");
1932}
1933
1934int msm_ipc_router_register_server(struct msm_ipc_port *port_ptr,
1935 struct msm_ipc_addr *name)
1936{
1937 struct msm_ipc_server *server;
1938 unsigned long flags;
1939 union rr_control_msg ctl;
1940
1941 if (!port_ptr || !name)
1942 return -EINVAL;
1943
1944 if (name->addrtype != MSM_IPC_ADDR_NAME)
1945 return -EINVAL;
1946
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001947 mutex_lock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001948 server = msm_ipc_router_lookup_server(name->addr.port_name.service,
1949 name->addr.port_name.instance,
1950 IPC_ROUTER_NID_LOCAL,
1951 port_ptr->this_port.port_id);
1952 if (server) {
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001953 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001954 pr_err("%s: Server already present\n", __func__);
1955 return -EINVAL;
1956 }
1957
1958 server = msm_ipc_router_create_server(name->addr.port_name.service,
1959 name->addr.port_name.instance,
1960 IPC_ROUTER_NID_LOCAL,
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001961 port_ptr->this_port.port_id,
1962 NULL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001963 if (!server) {
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001964 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001965 pr_err("%s: Server Creation failed\n", __func__);
1966 return -EINVAL;
1967 }
1968
1969 ctl.cmd = IPC_ROUTER_CTRL_CMD_NEW_SERVER;
1970 ctl.srv.service = server->name.service;
1971 ctl.srv.instance = server->name.instance;
1972 ctl.srv.node_id = IPC_ROUTER_NID_LOCAL;
1973 ctl.srv.port_id = port_ptr->this_port.port_id;
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001974 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001975 broadcast_ctl_msg(&ctl);
1976 spin_lock_irqsave(&port_ptr->port_lock, flags);
1977 port_ptr->type = SERVER_PORT;
Karthikeyan Ramasubramaniandc9c4442013-05-02 17:25:54 -06001978 port_ptr->mode_info.mode = MULTI_LINK_MODE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001979 port_ptr->port_name.service = server->name.service;
1980 port_ptr->port_name.instance = server->name.instance;
1981 spin_unlock_irqrestore(&port_ptr->port_lock, flags);
1982 return 0;
1983}
1984
1985int msm_ipc_router_unregister_server(struct msm_ipc_port *port_ptr)
1986{
1987 struct msm_ipc_server *server;
1988 unsigned long flags;
1989 union rr_control_msg ctl;
1990
1991 if (!port_ptr)
1992 return -EINVAL;
1993
1994 if (port_ptr->type != SERVER_PORT) {
1995 pr_err("%s: Trying to unregister a non-server port\n",
1996 __func__);
1997 return -EINVAL;
1998 }
1999
2000 if (port_ptr->this_port.node_id != IPC_ROUTER_NID_LOCAL) {
2001 pr_err("%s: Trying to unregister a remote server locally\n",
2002 __func__);
2003 return -EINVAL;
2004 }
2005
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002006 mutex_lock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002007 server = msm_ipc_router_lookup_server(port_ptr->port_name.service,
2008 port_ptr->port_name.instance,
2009 port_ptr->this_port.node_id,
2010 port_ptr->this_port.port_id);
2011 if (!server) {
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002012 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002013 pr_err("%s: Server lookup failed\n", __func__);
2014 return -ENODEV;
2015 }
2016
2017 ctl.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_SERVER;
2018 ctl.srv.service = server->name.service;
2019 ctl.srv.instance = server->name.instance;
2020 ctl.srv.node_id = IPC_ROUTER_NID_LOCAL;
2021 ctl.srv.port_id = port_ptr->this_port.port_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002022 msm_ipc_router_destroy_server(server, port_ptr->this_port.node_id,
2023 port_ptr->this_port.port_id);
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002024 mutex_unlock(&server_list_lock);
2025 broadcast_ctl_msg(&ctl);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002026 spin_lock_irqsave(&port_ptr->port_lock, flags);
2027 port_ptr->type = CLIENT_PORT;
2028 spin_unlock_irqrestore(&port_ptr->port_lock, flags);
2029 return 0;
2030}
2031
2032static int loopback_data(struct msm_ipc_port *src,
2033 uint32_t port_id,
2034 struct sk_buff_head *data)
2035{
2036 struct sk_buff *head_skb;
2037 struct rr_header *hdr;
2038 struct msm_ipc_port *port_ptr;
2039 struct rr_packet *pkt;
Karthikeyan Ramasubramanian0a801c12013-02-08 13:07:42 -07002040 int ret_len;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002041
2042 if (!data) {
2043 pr_err("%s: Invalid pkt pointer\n", __func__);
2044 return -EINVAL;
2045 }
2046
2047 pkt = create_pkt(data);
2048 if (!pkt) {
2049 pr_err("%s: New pkt create failed\n", __func__);
2050 return -ENOMEM;
2051 }
2052
2053 head_skb = skb_peek(pkt->pkt_fragment_q);
Karthikeyan Ramasubramanian9024dd82011-12-19 18:44:19 -07002054 if (!head_skb) {
2055 pr_err("%s: pkt_fragment_q is empty\n", __func__);
Brent Hronik0e83d3b2013-05-01 16:25:00 -06002056 release_pkt(pkt);
Karthikeyan Ramasubramanian9024dd82011-12-19 18:44:19 -07002057 return -EINVAL;
2058 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002059 hdr = (struct rr_header *)skb_push(head_skb, IPC_ROUTER_HDR_SIZE);
2060 if (!hdr) {
2061 pr_err("%s: Prepend Header failed\n", __func__);
2062 release_pkt(pkt);
2063 return -ENOMEM;
2064 }
2065 hdr->version = IPC_ROUTER_VERSION;
2066 hdr->type = IPC_ROUTER_CTRL_CMD_DATA;
2067 hdr->src_node_id = src->this_port.node_id;
2068 hdr->src_port_id = src->this_port.port_id;
2069 hdr->size = pkt->length;
2070 hdr->confirm_rx = 0;
2071 hdr->dst_node_id = IPC_ROUTER_NID_LOCAL;
2072 hdr->dst_port_id = port_id;
2073 pkt->length += IPC_ROUTER_HDR_SIZE;
2074
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06002075 mutex_lock(&local_ports_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002076 port_ptr = msm_ipc_router_lookup_local_port(port_id);
2077 if (!port_ptr) {
2078 pr_err("%s: Local port %d not present\n", __func__, port_id);
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06002079 mutex_unlock(&local_ports_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002080 release_pkt(pkt);
2081 return -ENODEV;
2082 }
2083
Karthikeyan Ramasubramanian0a801c12013-02-08 13:07:42 -07002084 ret_len = pkt->length;
Karthikeyan Ramasubramaniand1af6252013-05-17 15:19:56 -06002085 post_pkt_to_port(port_ptr, pkt, 0);
Karthikeyan Ramasubramaniandc9c4442013-05-02 17:25:54 -06002086 update_comm_mode_info(&src->mode_info, NULL);
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06002087 mutex_unlock(&local_ports_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002088
Karthikeyan Ramasubramanian0a801c12013-02-08 13:07:42 -07002089 return ret_len;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002090}
2091
2092static int msm_ipc_router_write_pkt(struct msm_ipc_port *src,
2093 struct msm_ipc_router_remote_port *rport_ptr,
2094 struct rr_packet *pkt)
2095{
2096 struct sk_buff *head_skb;
2097 struct rr_header *hdr;
2098 struct msm_ipc_router_xprt_info *xprt_info;
2099 struct msm_ipc_routing_table_entry *rt_entry;
Zaheerulla Meera34fc662013-04-17 01:16:47 +05302100 struct msm_ipc_resume_tx_port *resume_tx_port;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002101 int ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002102
2103 if (!rport_ptr || !src || !pkt)
2104 return -EINVAL;
2105
2106 head_skb = skb_peek(pkt->pkt_fragment_q);
Karthikeyan Ramasubramanian9024dd82011-12-19 18:44:19 -07002107 if (!head_skb) {
2108 pr_err("%s: pkt_fragment_q is empty\n", __func__);
2109 return -EINVAL;
2110 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002111 hdr = (struct rr_header *)skb_push(head_skb, IPC_ROUTER_HDR_SIZE);
2112 if (!hdr) {
2113 pr_err("%s: Prepend Header failed\n", __func__);
2114 return -ENOMEM;
2115 }
2116 hdr->version = IPC_ROUTER_VERSION;
2117 hdr->type = IPC_ROUTER_CTRL_CMD_DATA;
2118 hdr->src_node_id = src->this_port.node_id;
2119 hdr->src_port_id = src->this_port.port_id;
2120 hdr->size = pkt->length;
2121 hdr->confirm_rx = 0;
2122 hdr->dst_node_id = rport_ptr->node_id;
2123 hdr->dst_port_id = rport_ptr->port_id;
2124 pkt->length += IPC_ROUTER_HDR_SIZE;
2125
Zaheerulla Meera34fc662013-04-17 01:16:47 +05302126 mutex_lock(&rport_ptr->quota_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002127 if (rport_ptr->restart_state != RESTART_NORMAL) {
2128 mutex_unlock(&rport_ptr->quota_lock);
2129 return -ENETRESET;
2130 }
Zaheerulla Meera34fc662013-04-17 01:16:47 +05302131 if (rport_ptr->tx_quota_cnt == IPC_ROUTER_DEFAULT_RX_QUOTA) {
2132 if (msm_ipc_router_lookup_resume_tx_port(
2133 rport_ptr, src->this_port.port_id)) {
2134 mutex_unlock(&rport_ptr->quota_lock);
2135 return -EAGAIN;
2136 }
2137 resume_tx_port =
2138 kzalloc(sizeof(struct msm_ipc_resume_tx_port),
2139 GFP_KERNEL);
2140 if (!resume_tx_port) {
2141 pr_err("%s: Resume_Tx port allocation failed\n",
2142 __func__);
2143 mutex_unlock(&rport_ptr->quota_lock);
2144 return -ENOMEM;
2145 }
2146 INIT_LIST_HEAD(&resume_tx_port->list);
2147 resume_tx_port->port_id = src->this_port.port_id;
2148 resume_tx_port->node_id = src->this_port.node_id;
2149 list_add_tail(&resume_tx_port->list,
2150 &rport_ptr->resume_tx_port_list);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002151 mutex_unlock(&rport_ptr->quota_lock);
Zaheerulla Meera34fc662013-04-17 01:16:47 +05302152 return -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002153 }
2154 rport_ptr->tx_quota_cnt++;
2155 if (rport_ptr->tx_quota_cnt == IPC_ROUTER_DEFAULT_RX_QUOTA)
2156 hdr->confirm_rx = 1;
2157 mutex_unlock(&rport_ptr->quota_lock);
2158
2159 mutex_lock(&routing_table_lock);
2160 rt_entry = lookup_routing_table(hdr->dst_node_id);
2161 if (!rt_entry || !rt_entry->xprt_info) {
2162 mutex_unlock(&routing_table_lock);
2163 pr_err("%s: Remote node %d not up\n",
2164 __func__, hdr->dst_node_id);
2165 return -ENODEV;
2166 }
2167 mutex_lock(&rt_entry->lock);
2168 xprt_info = rt_entry->xprt_info;
2169 mutex_lock(&xprt_info->tx_lock);
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -07002170 ret = xprt_info->xprt->write(pkt, pkt->length, xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002171 mutex_unlock(&xprt_info->tx_lock);
2172 mutex_unlock(&rt_entry->lock);
2173 mutex_unlock(&routing_table_lock);
2174
2175 if (ret < 0) {
2176 pr_err("%s: Write on XPRT failed\n", __func__);
2177 return ret;
2178 }
Karthikeyan Ramasubramaniandc9c4442013-05-02 17:25:54 -06002179 update_comm_mode_info(&src->mode_info, xprt_info);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002180
2181 RAW_HDR("[w rr_h] "
2182 "ver=%i,type=%s,src_nid=%08x,src_port_id=%08x,"
2183 "confirm_rx=%i,size=%3i,dst_pid=%08x,dst_cid=%08x\n",
2184 hdr->version, type_to_str(hdr->type),
2185 hdr->src_node_id, hdr->src_port_id,
2186 hdr->confirm_rx, hdr->size,
2187 hdr->dst_node_id, hdr->dst_port_id);
2188
2189#if defined(CONFIG_MSM_SMD_LOGGING)
2190#if defined(DEBUG)
2191 if (msm_ipc_router_debug_mask & SMEM_LOG) {
2192 smem_log_event((SMEM_LOG_PROC_ID_APPS |
2193 SMEM_LOG_RPC_ROUTER_EVENT_BASE |
2194 IPC_ROUTER_LOG_EVENT_TX),
2195 (hdr->src_node_id << 24) |
2196 (hdr->src_port_id & 0xffffff),
2197 (hdr->dst_node_id << 24) |
2198 (hdr->dst_port_id & 0xffffff),
2199 (hdr->type << 24) | (hdr->confirm_rx << 16) |
2200 (hdr->size & 0xffff));
2201 }
2202#endif
2203#endif
2204
2205 return pkt->length;
2206}
2207
2208int msm_ipc_router_send_to(struct msm_ipc_port *src,
2209 struct sk_buff_head *data,
2210 struct msm_ipc_addr *dest)
2211{
2212 uint32_t dst_node_id = 0, dst_port_id = 0;
2213 struct msm_ipc_server *server;
2214 struct msm_ipc_server_port *server_port;
2215 struct msm_ipc_router_remote_port *rport_ptr = NULL;
2216 struct rr_packet *pkt;
2217 int ret;
2218
2219 if (!src || !data || !dest) {
2220 pr_err("%s: Invalid Parameters\n", __func__);
2221 return -EINVAL;
2222 }
2223
2224 /* Resolve Address*/
2225 if (dest->addrtype == MSM_IPC_ADDR_ID) {
2226 dst_node_id = dest->addr.port_addr.node_id;
2227 dst_port_id = dest->addr.port_addr.port_id;
2228 } else if (dest->addrtype == MSM_IPC_ADDR_NAME) {
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002229 mutex_lock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002230 server = msm_ipc_router_lookup_server(
2231 dest->addr.port_name.service,
2232 dest->addr.port_name.instance,
2233 0, 0);
2234 if (!server) {
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002235 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002236 pr_err("%s: Destination not reachable\n", __func__);
2237 return -ENODEV;
2238 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002239 server_port = list_first_entry(&server->server_port_list,
2240 struct msm_ipc_server_port,
2241 list);
2242 dst_node_id = server_port->server_addr.node_id;
2243 dst_port_id = server_port->server_addr.port_id;
2244 mutex_unlock(&server_list_lock);
2245 }
2246 if (dst_node_id == IPC_ROUTER_NID_LOCAL) {
2247 ret = loopback_data(src, dst_port_id, data);
2248 return ret;
2249 }
2250
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002251 rport_ptr = msm_ipc_router_lookup_remote_port(dst_node_id,
2252 dst_port_id);
2253 if (!rport_ptr) {
Zaheerulla Meer2c515312013-05-10 15:51:28 +05302254 pr_err("%s: Remote port not found\n", __func__);
2255 return -ENODEV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002256 }
2257
Karthikeyan Ramasubramanian1668cc62012-09-23 22:23:36 -06002258 if (src->check_send_permissions) {
2259 ret = src->check_send_permissions(rport_ptr->sec_rule);
2260 if (ret <= 0) {
2261 pr_err("%s: permission failure for %s\n",
2262 __func__, current->comm);
2263 return -EPERM;
2264 }
2265 }
2266
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002267 pkt = create_pkt(data);
2268 if (!pkt) {
2269 pr_err("%s: Pkt creation failed\n", __func__);
2270 return -ENOMEM;
2271 }
2272
2273 ret = msm_ipc_router_write_pkt(src, rport_ptr, pkt);
2274 release_pkt(pkt);
2275
2276 return ret;
2277}
2278
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -06002279int msm_ipc_router_send_msg(struct msm_ipc_port *src,
2280 struct msm_ipc_addr *dest,
2281 void *data, unsigned int data_len)
2282{
2283 struct sk_buff_head *out_skb_head;
2284 int ret;
2285
2286 out_skb_head = msm_ipc_router_buf_to_skb(data, data_len);
2287 if (!out_skb_head) {
2288 pr_err("%s: SKB conversion failed\n", __func__);
2289 return -EFAULT;
2290 }
2291
2292 ret = msm_ipc_router_send_to(src, out_skb_head, dest);
2293 if (ret < 0) {
2294 pr_err("%s: msm_ipc_router_send_to failed - ret: %d\n",
2295 __func__, ret);
2296 msm_ipc_router_free_skb(out_skb_head);
2297 }
2298 return 0;
2299}
2300
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002301int msm_ipc_router_read(struct msm_ipc_port *port_ptr,
2302 struct sk_buff_head **data,
2303 size_t buf_len)
2304{
2305 struct rr_packet *pkt;
2306 int ret;
2307
2308 if (!port_ptr || !data)
2309 return -EINVAL;
2310
2311 mutex_lock(&port_ptr->port_rx_q_lock);
2312 if (list_empty(&port_ptr->port_rx_q)) {
2313 mutex_unlock(&port_ptr->port_rx_q_lock);
2314 return -EAGAIN;
2315 }
2316
2317 pkt = list_first_entry(&port_ptr->port_rx_q, struct rr_packet, list);
2318 if ((buf_len) && ((pkt->length - IPC_ROUTER_HDR_SIZE) > buf_len)) {
2319 mutex_unlock(&port_ptr->port_rx_q_lock);
2320 return -ETOOSMALL;
2321 }
2322 list_del(&pkt->list);
2323 if (list_empty(&port_ptr->port_rx_q))
2324 wake_unlock(&port_ptr->port_rx_wake_lock);
2325 *data = pkt->pkt_fragment_q;
2326 ret = pkt->length;
2327 kfree(pkt);
2328 mutex_unlock(&port_ptr->port_rx_q_lock);
2329
2330 return ret;
2331}
2332
2333int msm_ipc_router_recv_from(struct msm_ipc_port *port_ptr,
2334 struct sk_buff_head **data,
2335 struct msm_ipc_addr *src,
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -06002336 long timeout)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002337{
2338 int ret, data_len, align_size;
2339 struct sk_buff *temp_skb;
2340 struct rr_header *hdr = NULL;
2341
2342 if (!port_ptr || !data) {
2343 pr_err("%s: Invalid pointers being passed\n", __func__);
2344 return -EINVAL;
2345 }
2346
2347 *data = NULL;
2348 mutex_lock(&port_ptr->port_rx_q_lock);
2349 while (list_empty(&port_ptr->port_rx_q)) {
2350 mutex_unlock(&port_ptr->port_rx_q_lock);
2351 if (timeout < 0) {
2352 ret = wait_event_interruptible(
2353 port_ptr->port_rx_wait_q,
2354 !list_empty(&port_ptr->port_rx_q));
2355 if (ret)
2356 return ret;
2357 } else if (timeout > 0) {
2358 timeout = wait_event_interruptible_timeout(
2359 port_ptr->port_rx_wait_q,
2360 !list_empty(&port_ptr->port_rx_q),
2361 timeout);
2362 if (timeout < 0)
2363 return -EFAULT;
2364 }
2365 if (timeout == 0)
2366 return -ETIMEDOUT;
2367 mutex_lock(&port_ptr->port_rx_q_lock);
2368 }
2369 mutex_unlock(&port_ptr->port_rx_q_lock);
2370
2371 ret = msm_ipc_router_read(port_ptr, data, 0);
2372 if (ret <= 0 || !(*data))
2373 return ret;
2374
2375 temp_skb = skb_peek(*data);
2376 hdr = (struct rr_header *)(temp_skb->data);
2377 if (src) {
2378 src->addrtype = MSM_IPC_ADDR_ID;
2379 src->addr.port_addr.node_id = hdr->src_node_id;
2380 src->addr.port_addr.port_id = hdr->src_port_id;
2381 }
2382
2383 data_len = hdr->size;
2384 skb_pull(temp_skb, IPC_ROUTER_HDR_SIZE);
2385 align_size = ALIGN_SIZE(data_len);
2386 if (align_size) {
2387 temp_skb = skb_peek_tail(*data);
2388 skb_trim(temp_skb, (temp_skb->len - align_size));
2389 }
2390 return data_len;
2391}
2392
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -06002393int msm_ipc_router_read_msg(struct msm_ipc_port *port_ptr,
2394 struct msm_ipc_addr *src,
2395 unsigned char **data,
2396 unsigned int *len)
2397{
2398 struct sk_buff_head *in_skb_head;
2399 int ret;
2400
2401 ret = msm_ipc_router_recv_from(port_ptr, &in_skb_head, src, -1);
2402 if (ret < 0) {
2403 pr_err("%s: msm_ipc_router_recv_from failed - ret: %d\n",
2404 __func__, ret);
2405 return ret;
2406 }
2407
2408 *data = msm_ipc_router_skb_to_buf(in_skb_head, ret);
2409 if (!(*data))
2410 pr_err("%s: Buf conversion failed\n", __func__);
2411
2412 *len = ret;
2413 msm_ipc_router_free_skb(in_skb_head);
2414 return 0;
2415}
2416
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002417struct msm_ipc_port *msm_ipc_router_create_port(
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -06002418 void (*notify)(unsigned event, void *priv),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002419 void *priv)
2420{
2421 struct msm_ipc_port *port_ptr;
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -06002422 int ret;
2423
2424 ret = wait_for_completion_interruptible(&msm_ipc_local_router_up);
2425 if (ret < 0) {
2426 pr_err("%s: Error waiting for local router\n", __func__);
2427 return NULL;
2428 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002429
2430 port_ptr = msm_ipc_router_create_raw_port(NULL, notify, priv);
2431 if (!port_ptr)
2432 pr_err("%s: port_ptr alloc failed\n", __func__);
2433
2434 return port_ptr;
2435}
2436
2437int msm_ipc_router_close_port(struct msm_ipc_port *port_ptr)
2438{
2439 union rr_control_msg msg;
2440 struct rr_packet *pkt, *temp_pkt;
2441 struct msm_ipc_server *server;
2442
2443 if (!port_ptr)
2444 return -EINVAL;
2445
2446 if (port_ptr->type == SERVER_PORT || port_ptr->type == CLIENT_PORT) {
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06002447 mutex_lock(&local_ports_lock);
2448 list_del(&port_ptr->list);
2449 mutex_unlock(&local_ports_lock);
2450
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002451 if (port_ptr->type == SERVER_PORT) {
2452 msg.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_SERVER;
2453 msg.srv.service = port_ptr->port_name.service;
2454 msg.srv.instance = port_ptr->port_name.instance;
2455 msg.srv.node_id = port_ptr->this_port.node_id;
2456 msg.srv.port_id = port_ptr->this_port.port_id;
2457 RR("x REMOVE_SERVER Name=%d:%08x Id=%d:%08x\n",
2458 msg.srv.service, msg.srv.instance,
2459 msg.srv.node_id, msg.srv.port_id);
Karthikeyan Ramasubramanian25e91872013-01-10 17:09:13 -07002460 broadcast_ctl_msg(&msg);
2461 broadcast_ctl_msg_locally(&msg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002462 }
Karthikeyan Ramasubramanian25e91872013-01-10 17:09:13 -07002463
2464 /*
2465 * Server port could have been a client port earlier.
2466 * Send REMOVE_CLIENT message in either case.
2467 */
Karthikeyan Ramasubramanian25e91872013-01-10 17:09:13 -07002468 RR("x REMOVE_CLIENT id=%d:%08x\n",
Karthikeyan Ramasubramaniandc9c4442013-05-02 17:25:54 -06002469 port_ptr->this_port.node_id, port_ptr->this_port.port_id);
2470 msm_ipc_router_send_remove_client(&port_ptr->mode_info,
2471 port_ptr->this_port.node_id,
2472 port_ptr->this_port.port_id);
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06002473 } else if (port_ptr->type == CONTROL_PORT) {
2474 mutex_lock(&control_ports_lock);
2475 list_del(&port_ptr->list);
2476 mutex_unlock(&control_ports_lock);
Karthikeyan Ramasubramaniand6dbfae2013-01-16 09:00:28 -07002477 } else if (port_ptr->type == IRSC_PORT) {
2478 mutex_lock(&local_ports_lock);
2479 list_del(&port_ptr->list);
2480 mutex_unlock(&local_ports_lock);
2481 signal_irsc_completion();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002482 }
2483
2484 mutex_lock(&port_ptr->port_rx_q_lock);
2485 list_for_each_entry_safe(pkt, temp_pkt, &port_ptr->port_rx_q, list) {
2486 list_del(&pkt->list);
2487 release_pkt(pkt);
2488 }
2489 mutex_unlock(&port_ptr->port_rx_q_lock);
2490
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002491 if (port_ptr->type == SERVER_PORT) {
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002492 mutex_lock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002493 server = msm_ipc_router_lookup_server(
2494 port_ptr->port_name.service,
2495 port_ptr->port_name.instance,
2496 port_ptr->this_port.node_id,
2497 port_ptr->this_port.port_id);
2498 if (server)
2499 msm_ipc_router_destroy_server(server,
2500 port_ptr->this_port.node_id,
2501 port_ptr->this_port.port_id);
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002502 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002503 }
2504
Karthikeyan Ramasubramaniandd8c3b52011-11-30 16:26:12 -07002505 wake_lock_destroy(&port_ptr->port_rx_wake_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002506 kfree(port_ptr);
2507 return 0;
2508}
2509
2510int msm_ipc_router_get_curr_pkt_size(struct msm_ipc_port *port_ptr)
2511{
2512 struct rr_packet *pkt;
2513 int rc = 0;
2514
2515 if (!port_ptr)
2516 return -EINVAL;
2517
2518 mutex_lock(&port_ptr->port_rx_q_lock);
2519 if (!list_empty(&port_ptr->port_rx_q)) {
2520 pkt = list_first_entry(&port_ptr->port_rx_q,
2521 struct rr_packet, list);
2522 rc = pkt->length;
2523 }
2524 mutex_unlock(&port_ptr->port_rx_q_lock);
2525
2526 return rc;
2527}
2528
2529int msm_ipc_router_bind_control_port(struct msm_ipc_port *port_ptr)
2530{
2531 if (!port_ptr)
2532 return -EINVAL;
2533
2534 mutex_lock(&local_ports_lock);
2535 list_del(&port_ptr->list);
2536 mutex_unlock(&local_ports_lock);
2537 port_ptr->type = CONTROL_PORT;
2538 mutex_lock(&control_ports_lock);
2539 list_add_tail(&port_ptr->list, &control_ports);
2540 mutex_unlock(&control_ports_lock);
2541
2542 return 0;
2543}
2544
2545int msm_ipc_router_lookup_server_name(struct msm_ipc_port_name *srv_name,
Karthikeyan Ramasubramaniandfde01b2012-06-12 14:25:13 -06002546 struct msm_ipc_server_info *srv_info,
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002547 int num_entries_in_array,
2548 uint32_t lookup_mask)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002549{
2550 struct msm_ipc_server *server;
2551 struct msm_ipc_server_port *server_port;
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002552 int key, i = 0; /*num_entries_found*/
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002553
2554 if (!srv_name) {
2555 pr_err("%s: Invalid srv_name\n", __func__);
2556 return -EINVAL;
2557 }
2558
Karthikeyan Ramasubramaniandfde01b2012-06-12 14:25:13 -06002559 if (num_entries_in_array && !srv_info) {
2560 pr_err("%s: srv_info NULL\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002561 return -EINVAL;
2562 }
2563
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002564 mutex_lock(&server_list_lock);
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002565 if (!lookup_mask)
2566 lookup_mask = 0xFFFFFFFF;
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002567 key = (srv_name->service & (SRV_HASH_SIZE - 1));
2568 list_for_each_entry(server, &server_list[key], list) {
2569 if ((server->name.service != srv_name->service) ||
2570 ((server->name.instance & lookup_mask) !=
2571 srv_name->instance))
2572 continue;
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002573
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002574 list_for_each_entry(server_port,
2575 &server->server_port_list, list) {
2576 if (i < num_entries_in_array) {
2577 srv_info[i].node_id =
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002578 server_port->server_addr.node_id;
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002579 srv_info[i].port_id =
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002580 server_port->server_addr.port_id;
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002581 srv_info[i].service = server->name.service;
2582 srv_info[i].instance = server->name.instance;
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002583 }
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002584 i++;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002585 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002586 }
2587 mutex_unlock(&server_list_lock);
2588
2589 return i;
2590}
2591
2592int msm_ipc_router_close(void)
2593{
2594 struct msm_ipc_router_xprt_info *xprt_info, *tmp_xprt_info;
2595
2596 mutex_lock(&xprt_info_list_lock);
2597 list_for_each_entry_safe(xprt_info, tmp_xprt_info,
2598 &xprt_info_list, list) {
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -07002599 xprt_info->xprt->close(xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002600 list_del(&xprt_info->list);
2601 kfree(xprt_info);
2602 }
2603 mutex_unlock(&xprt_info_list_lock);
2604 return 0;
2605}
2606
2607#if defined(CONFIG_DEBUG_FS)
2608static int dump_routing_table(char *buf, int max)
2609{
2610 int i = 0, j;
2611 struct msm_ipc_routing_table_entry *rt_entry;
2612
2613 for (j = 0; j < RT_HASH_SIZE; j++) {
2614 mutex_lock(&routing_table_lock);
2615 list_for_each_entry(rt_entry, &routing_table[j], list) {
2616 mutex_lock(&rt_entry->lock);
2617 i += scnprintf(buf + i, max - i,
2618 "Node Id: 0x%08x\n", rt_entry->node_id);
Karthikeyan Ramasubramanianc1a4e3a2012-09-10 16:10:24 -06002619 if (rt_entry->node_id == IPC_ROUTER_NID_LOCAL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002620 i += scnprintf(buf + i, max - i,
2621 "XPRT Name: Loopback\n");
2622 i += scnprintf(buf + i, max - i,
2623 "Next Hop: %d\n", rt_entry->node_id);
2624 } else {
2625 i += scnprintf(buf + i, max - i,
2626 "XPRT Name: %s\n",
2627 rt_entry->xprt_info->xprt->name);
2628 i += scnprintf(buf + i, max - i,
2629 "Next Hop: 0x%08x\n",
2630 rt_entry->xprt_info->remote_node_id);
2631 }
2632 i += scnprintf(buf + i, max - i, "\n");
2633 mutex_unlock(&rt_entry->lock);
2634 }
2635 mutex_unlock(&routing_table_lock);
2636 }
2637
2638 return i;
2639}
2640
2641static int dump_xprt_info(char *buf, int max)
2642{
2643 int i = 0;
2644 struct msm_ipc_router_xprt_info *xprt_info;
2645
2646 mutex_lock(&xprt_info_list_lock);
2647 list_for_each_entry(xprt_info, &xprt_info_list, list) {
2648 i += scnprintf(buf + i, max - i, "XPRT Name: %s\n",
2649 xprt_info->xprt->name);
2650 i += scnprintf(buf + i, max - i, "Link Id: %d\n",
2651 xprt_info->xprt->link_id);
2652 i += scnprintf(buf + i, max - i, "Initialized: %s\n",
2653 (xprt_info->initialized ? "Y" : "N"));
2654 i += scnprintf(buf + i, max - i, "Remote Node Id: 0x%08x\n",
2655 xprt_info->remote_node_id);
2656 i += scnprintf(buf + i, max - i, "\n");
2657 }
2658 mutex_unlock(&xprt_info_list_lock);
2659
2660 return i;
2661}
2662
2663static int dump_servers(char *buf, int max)
2664{
2665 int i = 0, j;
2666 struct msm_ipc_server *server;
2667 struct msm_ipc_server_port *server_port;
2668
2669 mutex_lock(&server_list_lock);
2670 for (j = 0; j < SRV_HASH_SIZE; j++) {
2671 list_for_each_entry(server, &server_list[j], list) {
2672 list_for_each_entry(server_port,
2673 &server->server_port_list,
2674 list) {
2675 i += scnprintf(buf + i, max - i, "Service: "
2676 "0x%08x\n", server->name.service);
2677 i += scnprintf(buf + i, max - i, "Instance: "
2678 "0x%08x\n", server->name.instance);
2679 i += scnprintf(buf + i, max - i,
2680 "Node_id: 0x%08x\n",
2681 server_port->server_addr.node_id);
2682 i += scnprintf(buf + i, max - i,
2683 "Port_id: 0x%08x\n",
2684 server_port->server_addr.port_id);
2685 i += scnprintf(buf + i, max - i, "\n");
2686 }
2687 }
2688 }
2689 mutex_unlock(&server_list_lock);
2690
2691 return i;
2692}
2693
2694static int dump_remote_ports(char *buf, int max)
2695{
2696 int i = 0, j, k;
2697 struct msm_ipc_router_remote_port *rport_ptr;
2698 struct msm_ipc_routing_table_entry *rt_entry;
2699
2700 for (j = 0; j < RT_HASH_SIZE; j++) {
2701 mutex_lock(&routing_table_lock);
2702 list_for_each_entry(rt_entry, &routing_table[j], list) {
2703 mutex_lock(&rt_entry->lock);
2704 for (k = 0; k < RP_HASH_SIZE; k++) {
2705 list_for_each_entry(rport_ptr,
2706 &rt_entry->remote_port_list[k],
2707 list) {
2708 i += scnprintf(buf + i, max - i,
2709 "Node_id: 0x%08x\n",
2710 rport_ptr->node_id);
2711 i += scnprintf(buf + i, max - i,
2712 "Port_id: 0x%08x\n",
2713 rport_ptr->port_id);
2714 i += scnprintf(buf + i, max - i,
2715 "Quota_cnt: %d\n",
2716 rport_ptr->tx_quota_cnt);
2717 i += scnprintf(buf + i, max - i, "\n");
2718 }
2719 }
2720 mutex_unlock(&rt_entry->lock);
2721 }
2722 mutex_unlock(&routing_table_lock);
2723 }
2724
2725 return i;
2726}
2727
2728static int dump_control_ports(char *buf, int max)
2729{
2730 int i = 0;
2731 struct msm_ipc_port *port_ptr;
2732
2733 mutex_lock(&control_ports_lock);
2734 list_for_each_entry(port_ptr, &control_ports, list) {
2735 i += scnprintf(buf + i, max - i, "Node_id: 0x%08x\n",
2736 port_ptr->this_port.node_id);
2737 i += scnprintf(buf + i, max - i, "Port_id: 0x%08x\n",
2738 port_ptr->this_port.port_id);
2739 i += scnprintf(buf + i, max - i, "\n");
2740 }
2741 mutex_unlock(&control_ports_lock);
2742
2743 return i;
2744}
2745
2746static int dump_local_ports(char *buf, int max)
2747{
2748 int i = 0, j;
2749 unsigned long flags;
2750 struct msm_ipc_port *port_ptr;
2751
2752 mutex_lock(&local_ports_lock);
2753 for (j = 0; j < LP_HASH_SIZE; j++) {
2754 list_for_each_entry(port_ptr, &local_ports[j], list) {
2755 spin_lock_irqsave(&port_ptr->port_lock, flags);
2756 i += scnprintf(buf + i, max - i, "Node_id: 0x%08x\n",
2757 port_ptr->this_port.node_id);
2758 i += scnprintf(buf + i, max - i, "Port_id: 0x%08x\n",
2759 port_ptr->this_port.port_id);
2760 i += scnprintf(buf + i, max - i, "# pkts tx'd %d\n",
2761 port_ptr->num_tx);
2762 i += scnprintf(buf + i, max - i, "# pkts rx'd %d\n",
2763 port_ptr->num_rx);
2764 i += scnprintf(buf + i, max - i, "# bytes tx'd %ld\n",
2765 port_ptr->num_tx_bytes);
2766 i += scnprintf(buf + i, max - i, "# bytes rx'd %ld\n",
2767 port_ptr->num_rx_bytes);
2768 spin_unlock_irqrestore(&port_ptr->port_lock, flags);
2769 i += scnprintf(buf + i, max - i, "\n");
2770 }
2771 }
2772 mutex_unlock(&local_ports_lock);
2773
2774 return i;
2775}
2776
2777#define DEBUG_BUFMAX 4096
2778static char debug_buffer[DEBUG_BUFMAX];
2779
2780static ssize_t debug_read(struct file *file, char __user *buf,
2781 size_t count, loff_t *ppos)
2782{
2783 int (*fill)(char *buf, int max) = file->private_data;
2784 int bsize = fill(debug_buffer, DEBUG_BUFMAX);
2785 return simple_read_from_buffer(buf, count, ppos, debug_buffer, bsize);
2786}
2787
2788static int debug_open(struct inode *inode, struct file *file)
2789{
2790 file->private_data = inode->i_private;
2791 return 0;
2792}
2793
2794static const struct file_operations debug_ops = {
2795 .read = debug_read,
2796 .open = debug_open,
2797};
2798
2799static void debug_create(const char *name, mode_t mode,
2800 struct dentry *dent,
2801 int (*fill)(char *buf, int max))
2802{
2803 debugfs_create_file(name, mode, dent, fill, &debug_ops);
2804}
2805
2806static void debugfs_init(void)
2807{
2808 struct dentry *dent;
2809
2810 dent = debugfs_create_dir("msm_ipc_router", 0);
2811 if (IS_ERR(dent))
2812 return;
2813
2814 debug_create("dump_local_ports", 0444, dent,
2815 dump_local_ports);
2816 debug_create("dump_remote_ports", 0444, dent,
2817 dump_remote_ports);
2818 debug_create("dump_control_ports", 0444, dent,
2819 dump_control_ports);
2820 debug_create("dump_servers", 0444, dent,
2821 dump_servers);
2822 debug_create("dump_xprt_info", 0444, dent,
2823 dump_xprt_info);
2824 debug_create("dump_routing_table", 0444, dent,
2825 dump_routing_table);
2826}
2827
2828#else
2829static void debugfs_init(void) {}
2830#endif
2831
2832static int msm_ipc_router_add_xprt(struct msm_ipc_router_xprt *xprt)
2833{
2834 struct msm_ipc_router_xprt_info *xprt_info;
2835 struct msm_ipc_routing_table_entry *rt_entry;
2836
2837 xprt_info = kmalloc(sizeof(struct msm_ipc_router_xprt_info),
2838 GFP_KERNEL);
2839 if (!xprt_info)
2840 return -ENOMEM;
2841
2842 xprt_info->xprt = xprt;
2843 xprt_info->initialized = 0;
2844 xprt_info->remote_node_id = -1;
2845 INIT_LIST_HEAD(&xprt_info->pkt_list);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002846 mutex_init(&xprt_info->rx_lock);
2847 mutex_init(&xprt_info->tx_lock);
2848 wake_lock_init(&xprt_info->wakelock,
2849 WAKE_LOCK_SUSPEND, xprt->name);
2850 xprt_info->need_len = 0;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002851 xprt_info->abort_data_read = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002852 INIT_WORK(&xprt_info->read_data, do_read_data);
2853 INIT_LIST_HEAD(&xprt_info->list);
2854
2855 xprt_info->workqueue = create_singlethread_workqueue(xprt->name);
2856 if (!xprt_info->workqueue) {
2857 kfree(xprt_info);
2858 return -ENOMEM;
2859 }
2860
2861 if (!strcmp(xprt->name, "msm_ipc_router_loopback_xprt")) {
2862 xprt_info->remote_node_id = IPC_ROUTER_NID_LOCAL;
2863 xprt_info->initialized = 1;
2864 }
2865
2866 mutex_lock(&xprt_info_list_lock);
2867 list_add_tail(&xprt_info->list, &xprt_info_list);
2868 mutex_unlock(&xprt_info_list_lock);
2869
2870 mutex_lock(&routing_table_lock);
2871 if (!routing_table_inited) {
2872 init_routing_table();
2873 rt_entry = alloc_routing_table_entry(IPC_ROUTER_NID_LOCAL);
2874 add_routing_table_entry(rt_entry);
2875 routing_table_inited = 1;
2876 }
2877 mutex_unlock(&routing_table_lock);
2878
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002879 xprt->priv = xprt_info;
2880
2881 return 0;
2882}
2883
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002884static void msm_ipc_router_remove_xprt(struct msm_ipc_router_xprt *xprt)
2885{
2886 struct msm_ipc_router_xprt_info *xprt_info;
2887
2888 if (xprt && xprt->priv) {
2889 xprt_info = xprt->priv;
2890
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06002891 mutex_lock(&xprt_info->rx_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002892 xprt_info->abort_data_read = 1;
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06002893 mutex_unlock(&xprt_info->rx_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002894
2895 mutex_lock(&xprt_info_list_lock);
2896 list_del(&xprt_info->list);
2897 mutex_unlock(&xprt_info_list_lock);
2898
2899 flush_workqueue(xprt_info->workqueue);
2900 destroy_workqueue(xprt_info->workqueue);
2901 wake_lock_destroy(&xprt_info->wakelock);
2902
2903 xprt->priv = 0;
2904 kfree(xprt_info);
2905 }
2906}
2907
2908
2909struct msm_ipc_router_xprt_work {
2910 struct msm_ipc_router_xprt *xprt;
2911 struct work_struct work;
2912};
2913
2914static void xprt_open_worker(struct work_struct *work)
2915{
2916 struct msm_ipc_router_xprt_work *xprt_work =
2917 container_of(work, struct msm_ipc_router_xprt_work, work);
2918
2919 msm_ipc_router_add_xprt(xprt_work->xprt);
2920 kfree(xprt_work);
2921}
2922
2923static void xprt_close_worker(struct work_struct *work)
2924{
2925 struct msm_ipc_router_xprt_work *xprt_work =
2926 container_of(work, struct msm_ipc_router_xprt_work, work);
2927
2928 modem_reset_cleanup(xprt_work->xprt->priv);
2929 msm_ipc_router_remove_xprt(xprt_work->xprt);
Zaheerulla Meer35893a62013-06-19 16:54:44 +05302930 xprt_work->xprt->sft_close_done(xprt_work->xprt);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002931 kfree(xprt_work);
2932}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002933
2934void msm_ipc_router_xprt_notify(struct msm_ipc_router_xprt *xprt,
2935 unsigned event,
2936 void *data)
2937{
2938 struct msm_ipc_router_xprt_info *xprt_info = xprt->priv;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002939 struct msm_ipc_router_xprt_work *xprt_work;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002940 struct rr_packet *pkt;
Karthikeyan Ramasubramanian4af9f7c2011-09-30 15:55:18 -06002941 unsigned long ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002942
Karthikeyan Ramasubramanian4af9f7c2011-09-30 15:55:18 -06002943 if (!msm_ipc_router_workqueue) {
2944 ret = wait_for_completion_timeout(&msm_ipc_local_router_up,
2945 IPC_ROUTER_INIT_TIMEOUT);
2946 if (!ret || !msm_ipc_router_workqueue) {
2947 pr_err("%s: IPC Router not initialized\n", __func__);
2948 return;
2949 }
2950 }
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002951
2952 switch (event) {
2953 case IPC_ROUTER_XPRT_EVENT_OPEN:
2954 D("open event for '%s'\n", xprt->name);
2955 xprt_work = kmalloc(sizeof(struct msm_ipc_router_xprt_work),
2956 GFP_ATOMIC);
Karthikeyan Ramasubramanianc51456c2013-05-16 15:51:29 -06002957 if (xprt_work) {
2958 xprt_work->xprt = xprt;
2959 INIT_WORK(&xprt_work->work, xprt_open_worker);
2960 queue_work(msm_ipc_router_workqueue, &xprt_work->work);
2961 } else {
2962 pr_err("%s: malloc failure - Couldn't notify OPEN event",
2963 __func__);
2964 }
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002965 break;
2966
2967 case IPC_ROUTER_XPRT_EVENT_CLOSE:
2968 D("close event for '%s'\n", xprt->name);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002969 xprt_work = kmalloc(sizeof(struct msm_ipc_router_xprt_work),
2970 GFP_ATOMIC);
Karthikeyan Ramasubramanianc51456c2013-05-16 15:51:29 -06002971 if (xprt_work) {
2972 xprt_work->xprt = xprt;
2973 INIT_WORK(&xprt_work->work, xprt_close_worker);
2974 queue_work(msm_ipc_router_workqueue, &xprt_work->work);
2975 } else {
2976 pr_err("%s: malloc failure - Couldn't notify CLOSE event",
2977 __func__);
2978 }
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002979 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002980 }
2981
2982 if (!data)
2983 return;
2984
2985 while (!xprt_info) {
2986 msleep(100);
2987 xprt_info = xprt->priv;
2988 }
2989
2990 pkt = clone_pkt((struct rr_packet *)data);
2991 if (!pkt)
2992 return;
2993
2994 mutex_lock(&xprt_info->rx_lock);
2995 list_add_tail(&pkt->list, &xprt_info->pkt_list);
2996 wake_lock(&xprt_info->wakelock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002997 mutex_unlock(&xprt_info->rx_lock);
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06002998 queue_work(xprt_info->workqueue, &xprt_info->read_data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002999}
3000
3001static int __init msm_ipc_router_init(void)
3002{
3003 int i, ret;
3004 struct msm_ipc_routing_table_entry *rt_entry;
3005
3006 msm_ipc_router_debug_mask |= SMEM_LOG;
Karthikeyan Ramasubramanian682ebcc2013-03-22 10:47:20 -06003007 ipc_rtr_log_ctxt = ipc_log_context_create(IPC_RTR_LOG_PAGES,
3008 "ipc_router");
3009 if (!ipc_rtr_log_ctxt)
3010 pr_err("%s: Unable to create IPC logging for IPC RTR",
3011 __func__);
3012
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06003013 msm_ipc_router_workqueue =
3014 create_singlethread_workqueue("msm_ipc_router");
3015 if (!msm_ipc_router_workqueue)
3016 return -ENOMEM;
3017
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003018 debugfs_init();
3019
3020 for (i = 0; i < SRV_HASH_SIZE; i++)
3021 INIT_LIST_HEAD(&server_list[i]);
3022
3023 for (i = 0; i < LP_HASH_SIZE; i++)
3024 INIT_LIST_HEAD(&local_ports[i]);
3025
3026 mutex_lock(&routing_table_lock);
3027 if (!routing_table_inited) {
3028 init_routing_table();
3029 rt_entry = alloc_routing_table_entry(IPC_ROUTER_NID_LOCAL);
3030 add_routing_table_entry(rt_entry);
3031 routing_table_inited = 1;
3032 }
3033 mutex_unlock(&routing_table_lock);
3034
3035 init_waitqueue_head(&newserver_wait);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003036 ret = msm_ipc_router_init_sockets();
3037 if (ret < 0)
3038 pr_err("%s: Init sockets failed\n", __func__);
3039
Karthikeyan Ramasubramanian1668cc62012-09-23 22:23:36 -06003040 ret = msm_ipc_router_security_init();
3041 if (ret < 0)
3042 pr_err("%s: Security Init failed\n", __func__);
3043
Karthikeyan Ramasubramanian4af9f7c2011-09-30 15:55:18 -06003044 complete_all(&msm_ipc_local_router_up);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003045 return ret;
3046}
3047
3048module_init(msm_ipc_router_init);
3049MODULE_DESCRIPTION("MSM IPC Router");
3050MODULE_LICENSE("GPL v2");