blob: 3ca3ef173a11f8239e5295ab7da877daf7a7457b [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>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070037
38#include "ipc_router.h"
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -060039#include "modem_notifier.h"
Karthikeyan Ramasubramanian1668cc62012-09-23 22:23:36 -060040#include "msm_ipc_router_security.h"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070041
42enum {
43 SMEM_LOG = 1U << 0,
44 RTR_DBG = 1U << 1,
45 R2R_MSG = 1U << 2,
46 R2R_RAW = 1U << 3,
47 NTFY_MSG = 1U << 4,
48 R2R_RAW_HDR = 1U << 5,
49};
50
51static int msm_ipc_router_debug_mask;
52module_param_named(debug_mask, msm_ipc_router_debug_mask,
53 int, S_IRUGO | S_IWUSR | S_IWGRP);
54
55#define DIAG(x...) pr_info("[RR] ERROR " x)
56
57#if defined(DEBUG)
58#define D(x...) do { \
59if (msm_ipc_router_debug_mask & RTR_DBG) \
60 pr_info(x); \
61} while (0)
62
63#define RR(x...) do { \
64if (msm_ipc_router_debug_mask & R2R_MSG) \
65 pr_info("[RR] "x); \
66} while (0)
67
68#define RAW(x...) do { \
69if (msm_ipc_router_debug_mask & R2R_RAW) \
70 pr_info("[RAW] "x); \
71} while (0)
72
73#define NTFY(x...) do { \
74if (msm_ipc_router_debug_mask & NTFY_MSG) \
75 pr_info("[NOTIFY] "x); \
76} while (0)
77
78#define RAW_HDR(x...) do { \
79if (msm_ipc_router_debug_mask & R2R_RAW_HDR) \
80 pr_info("[HDR] "x); \
81} while (0)
82#else
83#define D(x...) do { } while (0)
84#define RR(x...) do { } while (0)
85#define RAW(x...) do { } while (0)
86#define RAW_HDR(x...) do { } while (0)
87#define NTFY(x...) do { } while (0)
88#endif
89
90#define IPC_ROUTER_LOG_EVENT_ERROR 0x10
91#define IPC_ROUTER_LOG_EVENT_TX 0x11
92#define IPC_ROUTER_LOG_EVENT_RX 0x12
93
94static LIST_HEAD(control_ports);
95static DEFINE_MUTEX(control_ports_lock);
96
97#define LP_HASH_SIZE 32
98static struct list_head local_ports[LP_HASH_SIZE];
99static DEFINE_MUTEX(local_ports_lock);
100
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -0600101/*
102 * Server info is organized as a hash table. The server's service ID is
103 * used to index into the hash table. The instance ID of most of the servers
104 * are 1 or 2. The service IDs are well distributed compared to the instance
105 * IDs and hence choosing service ID to index into this hash table optimizes
106 * the hash table operations like add, lookup, destroy.
107 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700108#define SRV_HASH_SIZE 32
109static struct list_head server_list[SRV_HASH_SIZE];
110static DEFINE_MUTEX(server_list_lock);
111static wait_queue_head_t newserver_wait;
112
113struct msm_ipc_server {
114 struct list_head list;
115 struct msm_ipc_port_name name;
Karthikeyan Ramasubramanian1668cc62012-09-23 22:23:36 -0600116 int synced_sec_rule;
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -0600117 char pdev_name[32];
118 int next_pdev_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700119 struct list_head server_port_list;
120};
121
122struct msm_ipc_server_port {
123 struct list_head list;
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -0600124 struct platform_device pdev;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700125 struct msm_ipc_port_addr server_addr;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600126 struct msm_ipc_router_xprt_info *xprt_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700127};
128
129#define RP_HASH_SIZE 32
130struct msm_ipc_router_remote_port {
131 struct list_head list;
132 uint32_t node_id;
133 uint32_t port_id;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600134 uint32_t restart_state;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700135 wait_queue_head_t quota_wait;
136 uint32_t tx_quota_cnt;
137 struct mutex quota_lock;
Karthikeyan Ramasubramanian1668cc62012-09-23 22:23:36 -0600138 void *sec_rule;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700139};
140
141struct msm_ipc_router_xprt_info {
142 struct list_head list;
143 struct msm_ipc_router_xprt *xprt;
144 uint32_t remote_node_id;
145 uint32_t initialized;
146 struct list_head pkt_list;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700147 struct wake_lock wakelock;
148 struct mutex rx_lock;
149 struct mutex tx_lock;
150 uint32_t need_len;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600151 uint32_t abort_data_read;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700152 struct work_struct read_data;
153 struct workqueue_struct *workqueue;
154};
155
156#define RT_HASH_SIZE 4
157struct msm_ipc_routing_table_entry {
158 struct list_head list;
159 uint32_t node_id;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600160 uint32_t neighbor_node_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700161 struct list_head remote_port_list[RP_HASH_SIZE];
162 struct msm_ipc_router_xprt_info *xprt_info;
163 struct mutex lock;
164 unsigned long num_tx_bytes;
165 unsigned long num_rx_bytes;
166};
167
168static struct list_head routing_table[RT_HASH_SIZE];
169static DEFINE_MUTEX(routing_table_lock);
170static int routing_table_inited;
171
172static LIST_HEAD(msm_ipc_board_dev_list);
173static DEFINE_MUTEX(msm_ipc_board_dev_list_lock);
174
175static void do_read_data(struct work_struct *work);
176
177#define RR_STATE_IDLE 0
178#define RR_STATE_HEADER 1
179#define RR_STATE_BODY 2
180#define RR_STATE_ERROR 3
181
182#define RESTART_NORMAL 0
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600183#define RESTART_PEND 1
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700184
185/* State for remote ep following restart */
186#define RESTART_QUOTA_ABORT 1
187
188static LIST_HEAD(xprt_info_list);
189static DEFINE_MUTEX(xprt_info_list_lock);
190
Karthikeyan Ramasubramanian4af9f7c2011-09-30 15:55:18 -0600191static DECLARE_COMPLETION(msm_ipc_local_router_up);
192#define IPC_ROUTER_INIT_TIMEOUT (10 * HZ)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700193
194static uint32_t next_port_id;
195static DEFINE_MUTEX(next_port_id_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600196static struct workqueue_struct *msm_ipc_router_workqueue;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700197
198enum {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700199 DOWN,
200 UP,
201};
202
203static void init_routing_table(void)
204{
205 int i;
206 for (i = 0; i < RT_HASH_SIZE; i++)
207 INIT_LIST_HEAD(&routing_table[i]);
208}
209
210static struct msm_ipc_routing_table_entry *alloc_routing_table_entry(
211 uint32_t node_id)
212{
213 int i;
214 struct msm_ipc_routing_table_entry *rt_entry;
215
216 rt_entry = kmalloc(sizeof(struct msm_ipc_routing_table_entry),
217 GFP_KERNEL);
218 if (!rt_entry) {
219 pr_err("%s: rt_entry allocation failed for %d\n",
220 __func__, node_id);
221 return NULL;
222 }
223
224 for (i = 0; i < RP_HASH_SIZE; i++)
225 INIT_LIST_HEAD(&rt_entry->remote_port_list[i]);
226
227 mutex_init(&rt_entry->lock);
228 rt_entry->node_id = node_id;
229 rt_entry->xprt_info = NULL;
230 return rt_entry;
231}
232
233/*Please take routing_table_lock before calling this function*/
234static int add_routing_table_entry(
235 struct msm_ipc_routing_table_entry *rt_entry)
236{
237 uint32_t key;
238
239 if (!rt_entry)
240 return -EINVAL;
241
242 key = (rt_entry->node_id % RT_HASH_SIZE);
243 list_add_tail(&rt_entry->list, &routing_table[key]);
244 return 0;
245}
246
247/*Please take routing_table_lock before calling this function*/
248static struct msm_ipc_routing_table_entry *lookup_routing_table(
249 uint32_t node_id)
250{
251 uint32_t key = (node_id % RT_HASH_SIZE);
252 struct msm_ipc_routing_table_entry *rt_entry;
253
254 list_for_each_entry(rt_entry, &routing_table[key], list) {
255 if (rt_entry->node_id == node_id)
256 return rt_entry;
257 }
258 return NULL;
259}
260
261struct rr_packet *rr_read(struct msm_ipc_router_xprt_info *xprt_info)
262{
263 struct rr_packet *temp_pkt;
264
265 if (!xprt_info)
266 return NULL;
267
268 mutex_lock(&xprt_info->rx_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600269 if (xprt_info->abort_data_read) {
270 mutex_unlock(&xprt_info->rx_lock);
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -0600271 pr_err("%s detected SSR & exiting now\n",
272 xprt_info->xprt->name);
273 return NULL;
274 }
275
276 if (list_empty(&xprt_info->pkt_list)) {
277 mutex_unlock(&xprt_info->rx_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600278 return NULL;
279 }
280
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700281 temp_pkt = list_first_entry(&xprt_info->pkt_list,
282 struct rr_packet, list);
283 list_del(&temp_pkt->list);
284 if (list_empty(&xprt_info->pkt_list))
285 wake_unlock(&xprt_info->wakelock);
286 mutex_unlock(&xprt_info->rx_lock);
287 return temp_pkt;
288}
289
290struct rr_packet *clone_pkt(struct rr_packet *pkt)
291{
292 struct rr_packet *cloned_pkt;
293 struct sk_buff *temp_skb, *cloned_skb;
294 struct sk_buff_head *pkt_fragment_q;
295
296 cloned_pkt = kzalloc(sizeof(struct rr_packet), GFP_KERNEL);
297 if (!cloned_pkt) {
298 pr_err("%s: failure\n", __func__);
299 return NULL;
300 }
301
302 pkt_fragment_q = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
303 if (!pkt_fragment_q) {
304 pr_err("%s: pkt_frag_q alloc failure\n", __func__);
305 kfree(cloned_pkt);
306 return NULL;
307 }
308 skb_queue_head_init(pkt_fragment_q);
309
310 skb_queue_walk(pkt->pkt_fragment_q, temp_skb) {
311 cloned_skb = skb_clone(temp_skb, GFP_KERNEL);
312 if (!cloned_skb)
313 goto fail_clone;
314 skb_queue_tail(pkt_fragment_q, cloned_skb);
315 }
316 cloned_pkt->pkt_fragment_q = pkt_fragment_q;
317 cloned_pkt->length = pkt->length;
318 return cloned_pkt;
319
320fail_clone:
321 while (!skb_queue_empty(pkt_fragment_q)) {
322 temp_skb = skb_dequeue(pkt_fragment_q);
323 kfree_skb(temp_skb);
324 }
325 kfree(pkt_fragment_q);
326 kfree(cloned_pkt);
327 return NULL;
328}
329
330struct rr_packet *create_pkt(struct sk_buff_head *data)
331{
332 struct rr_packet *pkt;
333 struct sk_buff *temp_skb;
334
335 pkt = kzalloc(sizeof(struct rr_packet), GFP_KERNEL);
336 if (!pkt) {
337 pr_err("%s: failure\n", __func__);
338 return NULL;
339 }
340
341 pkt->pkt_fragment_q = data;
342 skb_queue_walk(pkt->pkt_fragment_q, temp_skb)
343 pkt->length += temp_skb->len;
344 return pkt;
345}
346
347void release_pkt(struct rr_packet *pkt)
348{
349 struct sk_buff *temp_skb;
350
351 if (!pkt)
352 return;
353
354 if (!pkt->pkt_fragment_q) {
355 kfree(pkt);
356 return;
357 }
358
359 while (!skb_queue_empty(pkt->pkt_fragment_q)) {
360 temp_skb = skb_dequeue(pkt->pkt_fragment_q);
361 kfree_skb(temp_skb);
362 }
363 kfree(pkt->pkt_fragment_q);
364 kfree(pkt);
365 return;
366}
367
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -0600368static struct sk_buff_head *msm_ipc_router_buf_to_skb(void *buf,
369 unsigned int buf_len)
370{
371 struct sk_buff_head *skb_head;
372 struct sk_buff *skb;
373 int first = 1, offset = 0;
374 int skb_size, data_size;
375 void *data;
376
377 skb_head = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
378 if (!skb_head) {
379 pr_err("%s: Couldnot allocate skb_head\n", __func__);
380 return NULL;
381 }
382 skb_queue_head_init(skb_head);
383
384 data_size = buf_len;
385 while (offset != buf_len) {
386 skb_size = data_size;
387 if (first)
388 skb_size += IPC_ROUTER_HDR_SIZE;
389
390 skb = alloc_skb(skb_size, GFP_KERNEL);
391 if (!skb) {
392 if (skb_size <= (PAGE_SIZE/2)) {
393 pr_err("%s: cannot allocate skb\n", __func__);
394 goto buf_to_skb_error;
395 }
396 data_size = data_size / 2;
397 continue;
398 }
399
400 if (first) {
401 skb_reserve(skb, IPC_ROUTER_HDR_SIZE);
402 first = 0;
403 }
404
405 data = skb_put(skb, data_size);
406 memcpy(skb->data, buf + offset, data_size);
407 skb_queue_tail(skb_head, skb);
408 offset += data_size;
409 data_size = buf_len - offset;
410 }
411 return skb_head;
412
413buf_to_skb_error:
414 while (!skb_queue_empty(skb_head)) {
415 skb = skb_dequeue(skb_head);
416 kfree_skb(skb);
417 }
418 kfree(skb_head);
419 return NULL;
420}
421
422static void *msm_ipc_router_skb_to_buf(struct sk_buff_head *skb_head,
423 unsigned int len)
424{
425 struct sk_buff *temp;
426 int offset = 0, buf_len = 0, copy_len;
427 void *buf;
428
429 if (!skb_head) {
430 pr_err("%s: NULL skb_head\n", __func__);
431 return NULL;
432 }
433
434 temp = skb_peek(skb_head);
435 buf_len = len;
436 buf = kmalloc(buf_len, GFP_KERNEL);
437 if (!buf) {
438 pr_err("%s: cannot allocate buf\n", __func__);
439 return NULL;
440 }
441 skb_queue_walk(skb_head, temp) {
442 copy_len = buf_len < temp->len ? buf_len : temp->len;
443 memcpy(buf + offset, temp->data, copy_len);
444 offset += copy_len;
445 buf_len -= copy_len;
446 }
447 return buf;
448}
449
450static void msm_ipc_router_free_skb(struct sk_buff_head *skb_head)
451{
452 struct sk_buff *temp_skb;
453
454 if (!skb_head)
455 return;
456
457 while (!skb_queue_empty(skb_head)) {
458 temp_skb = skb_dequeue(skb_head);
459 kfree_skb(temp_skb);
460 }
461 kfree(skb_head);
462}
463
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700464static int post_control_ports(struct rr_packet *pkt)
465{
466 struct msm_ipc_port *port_ptr;
467 struct rr_packet *cloned_pkt;
468
469 if (!pkt)
470 return -EINVAL;
471
472 mutex_lock(&control_ports_lock);
473 list_for_each_entry(port_ptr, &control_ports, list) {
474 mutex_lock(&port_ptr->port_rx_q_lock);
475 cloned_pkt = clone_pkt(pkt);
476 wake_lock(&port_ptr->port_rx_wake_lock);
477 list_add_tail(&cloned_pkt->list, &port_ptr->port_rx_q);
478 wake_up(&port_ptr->port_rx_wait_q);
479 mutex_unlock(&port_ptr->port_rx_q_lock);
480 }
481 mutex_unlock(&control_ports_lock);
482 return 0;
483}
484
485static uint32_t allocate_port_id(void)
486{
487 uint32_t port_id = 0, prev_port_id, key;
488 struct msm_ipc_port *port_ptr;
489
490 mutex_lock(&next_port_id_lock);
491 prev_port_id = next_port_id;
492 mutex_lock(&local_ports_lock);
493 do {
494 next_port_id++;
495 if ((next_port_id & 0xFFFFFFFE) == 0xFFFFFFFE)
496 next_port_id = 1;
497
498 key = (next_port_id & (LP_HASH_SIZE - 1));
499 if (list_empty(&local_ports[key])) {
500 port_id = next_port_id;
501 break;
502 }
503 list_for_each_entry(port_ptr, &local_ports[key], list) {
504 if (port_ptr->this_port.port_id == next_port_id) {
505 port_id = next_port_id;
506 break;
507 }
508 }
509 if (!port_id) {
510 port_id = next_port_id;
511 break;
512 }
513 port_id = 0;
514 } while (next_port_id != prev_port_id);
515 mutex_unlock(&local_ports_lock);
516 mutex_unlock(&next_port_id_lock);
517
518 return port_id;
519}
520
521void msm_ipc_router_add_local_port(struct msm_ipc_port *port_ptr)
522{
523 uint32_t key;
524
525 if (!port_ptr)
526 return;
527
528 key = (port_ptr->this_port.port_id & (LP_HASH_SIZE - 1));
529 mutex_lock(&local_ports_lock);
530 list_add_tail(&port_ptr->list, &local_ports[key]);
531 mutex_unlock(&local_ports_lock);
532}
533
534struct msm_ipc_port *msm_ipc_router_create_raw_port(void *endpoint,
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -0600535 void (*notify)(unsigned event, void *priv),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700536 void *priv)
537{
538 struct msm_ipc_port *port_ptr;
539
540 port_ptr = kzalloc(sizeof(struct msm_ipc_port), GFP_KERNEL);
541 if (!port_ptr)
542 return NULL;
543
544 port_ptr->this_port.node_id = IPC_ROUTER_NID_LOCAL;
545 port_ptr->this_port.port_id = allocate_port_id();
546 if (!port_ptr->this_port.port_id) {
547 pr_err("%s: All port ids are in use\n", __func__);
548 kfree(port_ptr);
549 return NULL;
550 }
551
552 spin_lock_init(&port_ptr->port_lock);
553 INIT_LIST_HEAD(&port_ptr->incomplete);
554 mutex_init(&port_ptr->incomplete_lock);
555 INIT_LIST_HEAD(&port_ptr->port_rx_q);
556 mutex_init(&port_ptr->port_rx_q_lock);
557 init_waitqueue_head(&port_ptr->port_rx_wait_q);
Karthikeyan Ramasubramanianb4aeeb92012-03-13 12:31:43 -0600558 snprintf(port_ptr->rx_wakelock_name, MAX_WAKELOCK_NAME_SZ,
Karthikeyan Ramasubramanian090486e2013-02-14 13:53:20 -0700559 "ipc%08x_%s",
560 port_ptr->this_port.port_id,
561 current->comm);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700562 wake_lock_init(&port_ptr->port_rx_wake_lock,
Karthikeyan Ramasubramanianb4aeeb92012-03-13 12:31:43 -0600563 WAKE_LOCK_SUSPEND, port_ptr->rx_wakelock_name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700564
565 port_ptr->endpoint = endpoint;
566 port_ptr->notify = notify;
567 port_ptr->priv = priv;
568
569 msm_ipc_router_add_local_port(port_ptr);
570 return port_ptr;
571}
572
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -0600573/*
574 * Should be called with local_ports_lock locked
575 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700576static struct msm_ipc_port *msm_ipc_router_lookup_local_port(uint32_t port_id)
577{
578 int key = (port_id & (LP_HASH_SIZE - 1));
579 struct msm_ipc_port *port_ptr;
580
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700581 list_for_each_entry(port_ptr, &local_ports[key], list) {
582 if (port_ptr->this_port.port_id == port_id) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700583 return port_ptr;
584 }
585 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700586 return NULL;
587}
588
589static struct msm_ipc_router_remote_port *msm_ipc_router_lookup_remote_port(
590 uint32_t node_id,
591 uint32_t port_id)
592{
593 struct msm_ipc_router_remote_port *rport_ptr;
594 struct msm_ipc_routing_table_entry *rt_entry;
595 int key = (port_id & (RP_HASH_SIZE - 1));
596
597 mutex_lock(&routing_table_lock);
598 rt_entry = lookup_routing_table(node_id);
599 if (!rt_entry) {
600 mutex_unlock(&routing_table_lock);
601 pr_err("%s: Node is not up\n", __func__);
602 return NULL;
603 }
604
605 mutex_lock(&rt_entry->lock);
606 list_for_each_entry(rport_ptr,
607 &rt_entry->remote_port_list[key], list) {
608 if (rport_ptr->port_id == port_id) {
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600609 if (rport_ptr->restart_state != RESTART_NORMAL)
610 rport_ptr = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700611 mutex_unlock(&rt_entry->lock);
612 mutex_unlock(&routing_table_lock);
613 return rport_ptr;
614 }
615 }
616 mutex_unlock(&rt_entry->lock);
617 mutex_unlock(&routing_table_lock);
618 return NULL;
619}
620
621static struct msm_ipc_router_remote_port *msm_ipc_router_create_remote_port(
622 uint32_t node_id,
623 uint32_t port_id)
624{
625 struct msm_ipc_router_remote_port *rport_ptr;
626 struct msm_ipc_routing_table_entry *rt_entry;
627 int key = (port_id & (RP_HASH_SIZE - 1));
628
629 mutex_lock(&routing_table_lock);
630 rt_entry = lookup_routing_table(node_id);
631 if (!rt_entry) {
632 mutex_unlock(&routing_table_lock);
633 pr_err("%s: Node is not up\n", __func__);
634 return NULL;
635 }
636
637 mutex_lock(&rt_entry->lock);
638 rport_ptr = kmalloc(sizeof(struct msm_ipc_router_remote_port),
639 GFP_KERNEL);
640 if (!rport_ptr) {
641 mutex_unlock(&rt_entry->lock);
642 mutex_unlock(&routing_table_lock);
643 pr_err("%s: Remote port alloc failed\n", __func__);
644 return NULL;
645 }
646 rport_ptr->port_id = port_id;
647 rport_ptr->node_id = node_id;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600648 rport_ptr->restart_state = RESTART_NORMAL;
Karthikeyan Ramasubramanian1668cc62012-09-23 22:23:36 -0600649 rport_ptr->sec_rule = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700650 rport_ptr->tx_quota_cnt = 0;
651 init_waitqueue_head(&rport_ptr->quota_wait);
652 mutex_init(&rport_ptr->quota_lock);
653 list_add_tail(&rport_ptr->list,
654 &rt_entry->remote_port_list[key]);
655 mutex_unlock(&rt_entry->lock);
656 mutex_unlock(&routing_table_lock);
657 return rport_ptr;
658}
659
660static void msm_ipc_router_destroy_remote_port(
661 struct msm_ipc_router_remote_port *rport_ptr)
662{
663 uint32_t node_id;
664 struct msm_ipc_routing_table_entry *rt_entry;
665
666 if (!rport_ptr)
667 return;
668
669 node_id = rport_ptr->node_id;
670 mutex_lock(&routing_table_lock);
671 rt_entry = lookup_routing_table(node_id);
672 if (!rt_entry) {
673 mutex_unlock(&routing_table_lock);
674 pr_err("%s: Node %d is not up\n", __func__, node_id);
675 return;
676 }
677
678 mutex_lock(&rt_entry->lock);
679 list_del(&rport_ptr->list);
680 kfree(rport_ptr);
681 mutex_unlock(&rt_entry->lock);
682 mutex_unlock(&routing_table_lock);
683 return;
684}
685
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -0600686/**
687 * msm_ipc_router_lookup_server() - Lookup server information
688 * @service: Service ID of the server info to be looked up.
689 * @instance: Instance ID of the server info to be looked up.
690 * @node_id: Node/Processor ID in which the server is hosted.
691 * @port_id: Port ID within the node in which the server is hosted.
692 *
693 * @return: If found Pointer to server structure, else NULL.
694 *
695 * Note1: Lock the server_list_lock before accessing this function.
696 * Note2: If the <node_id:port_id> are <0:0>, then the lookup is restricted
697 * to <service:instance>. Used only when a client wants to send a
698 * message to any QMI server.
699 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700700static struct msm_ipc_server *msm_ipc_router_lookup_server(
701 uint32_t service,
702 uint32_t instance,
703 uint32_t node_id,
704 uint32_t port_id)
705{
706 struct msm_ipc_server *server;
707 struct msm_ipc_server_port *server_port;
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -0600708 int key = (service & (SRV_HASH_SIZE - 1));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700709
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700710 list_for_each_entry(server, &server_list[key], list) {
711 if ((server->name.service != service) ||
712 (server->name.instance != instance))
713 continue;
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -0600714 if ((node_id == 0) && (port_id == 0))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700715 return server;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700716 list_for_each_entry(server_port, &server->server_port_list,
717 list) {
718 if ((server_port->server_addr.node_id == node_id) &&
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -0600719 (server_port->server_addr.port_id == port_id))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700720 return server;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700721 }
722 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700723 return NULL;
724}
725
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -0600726static void dummy_release(struct device *dev)
727{
728}
729
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -0600730/**
731 * msm_ipc_router_create_server() - Add server info to hash table
732 * @service: Service ID of the server info to be created.
733 * @instance: Instance ID of the server info to be created.
734 * @node_id: Node/Processor ID in which the server is hosted.
735 * @port_id: Port ID within the node in which the server is hosted.
736 * @xprt_info: XPRT through which the node hosting the server is reached.
737 *
738 * @return: Pointer to server structure on success, else NULL.
739 *
740 * This function adds the server info to the hash table. If the same
741 * server(i.e. <service_id:instance_id>) is hosted in different nodes,
742 * they are maintained as list of "server_port" under "server" structure.
743 * Note: Lock the server_list_lock before accessing this function.
744 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700745static struct msm_ipc_server *msm_ipc_router_create_server(
746 uint32_t service,
747 uint32_t instance,
748 uint32_t node_id,
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600749 uint32_t port_id,
750 struct msm_ipc_router_xprt_info *xprt_info)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700751{
752 struct msm_ipc_server *server = NULL;
753 struct msm_ipc_server_port *server_port;
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -0600754 int key = (service & (SRV_HASH_SIZE - 1));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700755
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700756 list_for_each_entry(server, &server_list[key], list) {
757 if ((server->name.service == service) &&
758 (server->name.instance == instance))
759 goto create_srv_port;
760 }
761
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -0600762 server = kzalloc(sizeof(struct msm_ipc_server), GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700763 if (!server) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700764 pr_err("%s: Server allocation failed\n", __func__);
765 return NULL;
766 }
767 server->name.service = service;
768 server->name.instance = instance;
Karthikeyan Ramasubramanian1668cc62012-09-23 22:23:36 -0600769 server->synced_sec_rule = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700770 INIT_LIST_HEAD(&server->server_port_list);
771 list_add_tail(&server->list, &server_list[key]);
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -0600772 scnprintf(server->pdev_name, sizeof(server->pdev_name),
773 "QMI%08x:%08x", service, instance);
774 server->next_pdev_id = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700775
776create_srv_port:
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -0600777 server_port = kzalloc(sizeof(struct msm_ipc_server_port), GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700778 if (!server_port) {
779 if (list_empty(&server->server_port_list)) {
780 list_del(&server->list);
781 kfree(server);
782 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700783 pr_err("%s: Server Port allocation failed\n", __func__);
784 return NULL;
785 }
786 server_port->server_addr.node_id = node_id;
787 server_port->server_addr.port_id = port_id;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600788 server_port->xprt_info = xprt_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700789 list_add_tail(&server_port->list, &server->server_port_list);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700790
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -0600791 server_port->pdev.name = server->pdev_name;
792 server_port->pdev.id = server->next_pdev_id++;
793 server_port->pdev.dev.release = dummy_release;
794 platform_device_register(&server_port->pdev);
795
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700796 return server;
797}
798
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -0600799/**
800 * msm_ipc_router_destroy_server() - Remove server info from hash table
801 * @server: Server info to be removed.
802 * @node_id: Node/Processor ID in which the server is hosted.
803 * @port_id: Port ID within the node in which the server is hosted.
804 *
805 * This function removes the server_port identified using <node_id:port_id>
806 * from the server structure. If the server_port list under server structure
807 * is empty after removal, then remove the server structure from the server
808 * hash table.
809 * Note: Lock the server_list_lock before accessing this function.
810 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700811static void msm_ipc_router_destroy_server(struct msm_ipc_server *server,
812 uint32_t node_id, uint32_t port_id)
813{
814 struct msm_ipc_server_port *server_port;
815
816 if (!server)
817 return;
818
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700819 list_for_each_entry(server_port, &server->server_port_list, list) {
820 if ((server_port->server_addr.node_id == node_id) &&
821 (server_port->server_addr.port_id == port_id))
822 break;
823 }
824 if (server_port) {
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -0600825 platform_device_unregister(&server_port->pdev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700826 list_del(&server_port->list);
827 kfree(server_port);
828 }
829 if (list_empty(&server->server_port_list)) {
830 list_del(&server->list);
831 kfree(server);
832 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700833 return;
834}
835
836static int msm_ipc_router_send_control_msg(
837 struct msm_ipc_router_xprt_info *xprt_info,
838 union rr_control_msg *msg)
839{
840 struct rr_packet *pkt;
841 struct sk_buff *ipc_rtr_pkt;
842 struct rr_header *hdr;
843 int pkt_size;
844 void *data;
845 struct sk_buff_head *pkt_fragment_q;
846 int ret;
847
848 if (!xprt_info || ((msg->cmd != IPC_ROUTER_CTRL_CMD_HELLO) &&
849 !xprt_info->initialized)) {
850 pr_err("%s: xprt_info not initialized\n", __func__);
851 return -EINVAL;
852 }
853
854 if (xprt_info->remote_node_id == IPC_ROUTER_NID_LOCAL)
855 return 0;
856
857 pkt = kzalloc(sizeof(struct rr_packet), GFP_KERNEL);
858 if (!pkt) {
859 pr_err("%s: pkt alloc failed\n", __func__);
860 return -ENOMEM;
861 }
862
863 pkt_fragment_q = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
864 if (!pkt_fragment_q) {
865 pr_err("%s: pkt_fragment_q alloc failed\n", __func__);
866 kfree(pkt);
867 return -ENOMEM;
868 }
869 skb_queue_head_init(pkt_fragment_q);
870
871 pkt_size = IPC_ROUTER_HDR_SIZE + sizeof(*msg);
872 ipc_rtr_pkt = alloc_skb(pkt_size, GFP_KERNEL);
873 if (!ipc_rtr_pkt) {
874 pr_err("%s: ipc_rtr_pkt alloc failed\n", __func__);
875 kfree(pkt_fragment_q);
876 kfree(pkt);
877 return -ENOMEM;
878 }
879
880 skb_reserve(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
881 data = skb_put(ipc_rtr_pkt, sizeof(*msg));
882 memcpy(data, msg, sizeof(*msg));
883 hdr = (struct rr_header *)skb_push(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
884 if (!hdr) {
885 pr_err("%s: skb_push failed\n", __func__);
886 kfree_skb(ipc_rtr_pkt);
887 kfree(pkt_fragment_q);
888 kfree(pkt);
889 return -ENOMEM;
890 }
891
892 hdr->version = IPC_ROUTER_VERSION;
893 hdr->type = msg->cmd;
894 hdr->src_node_id = IPC_ROUTER_NID_LOCAL;
895 hdr->src_port_id = IPC_ROUTER_ADDRESS;
896 hdr->confirm_rx = 0;
897 hdr->size = sizeof(*msg);
898 hdr->dst_node_id = xprt_info->remote_node_id;
899 hdr->dst_port_id = IPC_ROUTER_ADDRESS;
900 skb_queue_tail(pkt_fragment_q, ipc_rtr_pkt);
901 pkt->pkt_fragment_q = pkt_fragment_q;
902 pkt->length = pkt_size;
903
904 mutex_lock(&xprt_info->tx_lock);
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700905 ret = xprt_info->xprt->write(pkt, pkt_size, xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700906 mutex_unlock(&xprt_info->tx_lock);
907
908 release_pkt(pkt);
909 return ret;
910}
911
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -0600912static int msm_ipc_router_send_server_list(uint32_t node_id,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700913 struct msm_ipc_router_xprt_info *xprt_info)
914{
915 union rr_control_msg ctl;
916 struct msm_ipc_server *server;
917 struct msm_ipc_server_port *server_port;
918 int i;
919
920 if (!xprt_info || !xprt_info->initialized) {
921 pr_err("%s: Xprt info not initialized\n", __func__);
922 return -EINVAL;
923 }
924
925 ctl.cmd = IPC_ROUTER_CTRL_CMD_NEW_SERVER;
926
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700927 for (i = 0; i < SRV_HASH_SIZE; i++) {
928 list_for_each_entry(server, &server_list[i], list) {
929 ctl.srv.service = server->name.service;
930 ctl.srv.instance = server->name.instance;
931 list_for_each_entry(server_port,
932 &server->server_port_list, list) {
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -0600933 if (server_port->server_addr.node_id !=
934 node_id)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700935 continue;
936
937 ctl.srv.node_id =
938 server_port->server_addr.node_id;
939 ctl.srv.port_id =
940 server_port->server_addr.port_id;
941 msm_ipc_router_send_control_msg(xprt_info,
942 &ctl);
943 }
944 }
945 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700946
947 return 0;
948}
949
950#if defined(DEBUG)
951static char *type_to_str(int i)
952{
953 switch (i) {
954 case IPC_ROUTER_CTRL_CMD_DATA:
955 return "data ";
956 case IPC_ROUTER_CTRL_CMD_HELLO:
957 return "hello ";
958 case IPC_ROUTER_CTRL_CMD_BYE:
959 return "bye ";
960 case IPC_ROUTER_CTRL_CMD_NEW_SERVER:
961 return "new_srvr";
962 case IPC_ROUTER_CTRL_CMD_REMOVE_SERVER:
963 return "rmv_srvr";
964 case IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT:
965 return "rmv_clnt";
966 case IPC_ROUTER_CTRL_CMD_RESUME_TX:
967 return "resum_tx";
968 case IPC_ROUTER_CTRL_CMD_EXIT:
969 return "cmd_exit";
970 default:
971 return "invalid";
972 }
973}
974#endif
975
976static int broadcast_ctl_msg_locally(union rr_control_msg *msg)
977{
978 struct rr_packet *pkt;
979 struct sk_buff *ipc_rtr_pkt;
980 struct rr_header *hdr;
981 int pkt_size;
982 void *data;
983 struct sk_buff_head *pkt_fragment_q;
984 int ret;
985
986 pkt = kzalloc(sizeof(struct rr_packet), GFP_KERNEL);
987 if (!pkt) {
988 pr_err("%s: pkt alloc failed\n", __func__);
989 return -ENOMEM;
990 }
991
992 pkt_fragment_q = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
993 if (!pkt_fragment_q) {
994 pr_err("%s: pkt_fragment_q alloc failed\n", __func__);
995 kfree(pkt);
996 return -ENOMEM;
997 }
998 skb_queue_head_init(pkt_fragment_q);
999
1000 pkt_size = IPC_ROUTER_HDR_SIZE + sizeof(*msg);
1001 ipc_rtr_pkt = alloc_skb(pkt_size, GFP_KERNEL);
1002 if (!ipc_rtr_pkt) {
1003 pr_err("%s: ipc_rtr_pkt alloc failed\n", __func__);
1004 kfree(pkt_fragment_q);
1005 kfree(pkt);
1006 return -ENOMEM;
1007 }
1008
1009 skb_reserve(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
1010 data = skb_put(ipc_rtr_pkt, sizeof(*msg));
1011 memcpy(data, msg, sizeof(*msg));
1012 hdr = (struct rr_header *)skb_push(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
1013 if (!hdr) {
1014 pr_err("%s: skb_push failed\n", __func__);
1015 kfree_skb(ipc_rtr_pkt);
1016 kfree(pkt_fragment_q);
1017 kfree(pkt);
1018 return -ENOMEM;
1019 }
1020 hdr->version = IPC_ROUTER_VERSION;
1021 hdr->type = msg->cmd;
1022 hdr->src_node_id = IPC_ROUTER_NID_LOCAL;
1023 hdr->src_port_id = IPC_ROUTER_ADDRESS;
1024 hdr->confirm_rx = 0;
1025 hdr->size = sizeof(*msg);
1026 hdr->dst_node_id = IPC_ROUTER_NID_LOCAL;
1027 hdr->dst_port_id = IPC_ROUTER_ADDRESS;
1028 skb_queue_tail(pkt_fragment_q, ipc_rtr_pkt);
1029 pkt->pkt_fragment_q = pkt_fragment_q;
1030 pkt->length = pkt_size;
1031
1032 ret = post_control_ports(pkt);
1033 release_pkt(pkt);
1034 return ret;
1035}
1036
1037static int broadcast_ctl_msg(union rr_control_msg *ctl)
1038{
1039 struct msm_ipc_router_xprt_info *xprt_info;
1040
1041 mutex_lock(&xprt_info_list_lock);
1042 list_for_each_entry(xprt_info, &xprt_info_list, list) {
1043 msm_ipc_router_send_control_msg(xprt_info, ctl);
1044 }
1045 mutex_unlock(&xprt_info_list_lock);
1046
1047 return 0;
1048}
1049
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001050static int relay_ctl_msg(struct msm_ipc_router_xprt_info *xprt_info,
1051 union rr_control_msg *ctl)
1052{
1053 struct msm_ipc_router_xprt_info *fwd_xprt_info;
1054
1055 if (!xprt_info || !ctl)
1056 return -EINVAL;
1057
1058 mutex_lock(&xprt_info_list_lock);
1059 list_for_each_entry(fwd_xprt_info, &xprt_info_list, list) {
1060 if (xprt_info->xprt->link_id != fwd_xprt_info->xprt->link_id)
1061 msm_ipc_router_send_control_msg(fwd_xprt_info, ctl);
1062 }
1063 mutex_unlock(&xprt_info_list_lock);
1064
1065 return 0;
1066}
1067
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001068static int relay_msg(struct msm_ipc_router_xprt_info *xprt_info,
1069 struct rr_packet *pkt)
1070{
1071 struct msm_ipc_router_xprt_info *fwd_xprt_info;
1072
1073 if (!xprt_info || !pkt)
1074 return -EINVAL;
1075
1076 mutex_lock(&xprt_info_list_lock);
1077 list_for_each_entry(fwd_xprt_info, &xprt_info_list, list) {
1078 mutex_lock(&fwd_xprt_info->tx_lock);
1079 if (xprt_info->xprt->link_id != fwd_xprt_info->xprt->link_id)
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -07001080 fwd_xprt_info->xprt->write(pkt, pkt->length,
1081 fwd_xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001082 mutex_unlock(&fwd_xprt_info->tx_lock);
1083 }
1084 mutex_unlock(&xprt_info_list_lock);
1085 return 0;
1086}
1087
1088static int forward_msg(struct msm_ipc_router_xprt_info *xprt_info,
1089 struct rr_packet *pkt)
1090{
1091 uint32_t dst_node_id;
1092 struct sk_buff *head_pkt;
1093 struct rr_header *hdr;
1094 struct msm_ipc_router_xprt_info *fwd_xprt_info;
1095 struct msm_ipc_routing_table_entry *rt_entry;
1096
1097 if (!xprt_info || !pkt)
1098 return -EINVAL;
1099
1100 head_pkt = skb_peek(pkt->pkt_fragment_q);
1101 if (!head_pkt)
1102 return -EINVAL;
1103
1104 hdr = (struct rr_header *)head_pkt->data;
1105 dst_node_id = hdr->dst_node_id;
1106 mutex_lock(&routing_table_lock);
1107 rt_entry = lookup_routing_table(dst_node_id);
1108 if (!(rt_entry) || !(rt_entry->xprt_info)) {
1109 mutex_unlock(&routing_table_lock);
1110 pr_err("%s: Routing table not initialized\n", __func__);
1111 return -ENODEV;
1112 }
1113
1114 mutex_lock(&rt_entry->lock);
1115 fwd_xprt_info = rt_entry->xprt_info;
1116 mutex_lock(&fwd_xprt_info->tx_lock);
1117 if (xprt_info->remote_node_id == fwd_xprt_info->remote_node_id) {
1118 mutex_unlock(&fwd_xprt_info->tx_lock);
1119 mutex_unlock(&rt_entry->lock);
1120 mutex_unlock(&routing_table_lock);
1121 pr_err("%s: Discarding Command to route back\n", __func__);
1122 return -EINVAL;
1123 }
1124
1125 if (xprt_info->xprt->link_id == fwd_xprt_info->xprt->link_id) {
1126 mutex_unlock(&fwd_xprt_info->tx_lock);
1127 mutex_unlock(&rt_entry->lock);
1128 mutex_unlock(&routing_table_lock);
1129 pr_err("%s: DST in the same cluster\n", __func__);
1130 return 0;
1131 }
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -07001132 fwd_xprt_info->xprt->write(pkt, pkt->length, fwd_xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001133 mutex_unlock(&fwd_xprt_info->tx_lock);
1134 mutex_unlock(&rt_entry->lock);
1135 mutex_unlock(&routing_table_lock);
1136
1137 return 0;
1138}
1139
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001140static void reset_remote_port_info(uint32_t node_id, uint32_t port_id)
1141{
1142 struct msm_ipc_router_remote_port *rport_ptr;
1143
1144 rport_ptr = msm_ipc_router_lookup_remote_port(node_id, port_id);
1145 if (!rport_ptr) {
1146 pr_err("%s: No such remote port %08x:%08x\n",
1147 __func__, node_id, port_id);
1148 return;
1149 }
1150 mutex_lock(&rport_ptr->quota_lock);
1151 rport_ptr->restart_state = RESTART_PEND;
1152 wake_up(&rport_ptr->quota_wait);
1153 mutex_unlock(&rport_ptr->quota_lock);
1154 return;
1155}
1156
1157static void msm_ipc_cleanup_remote_server_info(
1158 struct msm_ipc_router_xprt_info *xprt_info)
1159{
1160 struct msm_ipc_server *svr, *tmp_svr;
1161 struct msm_ipc_server_port *svr_port, *tmp_svr_port;
1162 int i;
1163 union rr_control_msg ctl;
1164
1165 if (!xprt_info) {
1166 pr_err("%s: Invalid xprt_info\n", __func__);
1167 return;
1168 }
1169
1170 ctl.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_SERVER;
1171 mutex_lock(&server_list_lock);
1172 for (i = 0; i < SRV_HASH_SIZE; i++) {
1173 list_for_each_entry_safe(svr, tmp_svr, &server_list[i], list) {
1174 ctl.srv.service = svr->name.service;
1175 ctl.srv.instance = svr->name.instance;
1176 list_for_each_entry_safe(svr_port, tmp_svr_port,
1177 &svr->server_port_list, list) {
1178 if (svr_port->xprt_info != xprt_info)
1179 continue;
1180 D("Remove server %08x:%08x - %08x:%08x",
1181 ctl.srv.service, ctl.srv.instance,
1182 svr_port->server_addr.node_id,
1183 svr_port->server_addr.port_id);
1184 reset_remote_port_info(
1185 svr_port->server_addr.node_id,
1186 svr_port->server_addr.port_id);
1187 ctl.srv.node_id = svr_port->server_addr.node_id;
1188 ctl.srv.port_id = svr_port->server_addr.port_id;
1189 relay_ctl_msg(xprt_info, &ctl);
1190 broadcast_ctl_msg_locally(&ctl);
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -06001191 platform_device_unregister(&svr_port->pdev);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001192 list_del(&svr_port->list);
1193 kfree(svr_port);
1194 }
1195 if (list_empty(&svr->server_port_list)) {
1196 list_del(&svr->list);
1197 kfree(svr);
1198 }
1199 }
1200 }
1201 mutex_unlock(&server_list_lock);
1202}
1203
1204static void msm_ipc_cleanup_remote_client_info(
1205 struct msm_ipc_router_xprt_info *xprt_info)
1206{
1207 struct msm_ipc_routing_table_entry *rt_entry;
1208 struct msm_ipc_router_remote_port *rport_ptr;
1209 int i, j;
1210 union rr_control_msg ctl;
1211
1212 if (!xprt_info) {
1213 pr_err("%s: Invalid xprt_info\n", __func__);
1214 return;
1215 }
1216
1217 ctl.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT;
1218 mutex_lock(&routing_table_lock);
1219 for (i = 0; i < RT_HASH_SIZE; i++) {
1220 list_for_each_entry(rt_entry, &routing_table[i], list) {
1221 mutex_lock(&rt_entry->lock);
1222 if (rt_entry->xprt_info != xprt_info) {
1223 mutex_unlock(&rt_entry->lock);
1224 continue;
1225 }
1226 for (j = 0; j < RP_HASH_SIZE; j++) {
1227 list_for_each_entry(rport_ptr,
1228 &rt_entry->remote_port_list[j], list) {
1229 if (rport_ptr->restart_state ==
1230 RESTART_PEND)
1231 continue;
1232 mutex_lock(&rport_ptr->quota_lock);
1233 rport_ptr->restart_state = RESTART_PEND;
1234 wake_up(&rport_ptr->quota_wait);
1235 mutex_unlock(&rport_ptr->quota_lock);
1236 ctl.cli.node_id = rport_ptr->node_id;
1237 ctl.cli.port_id = rport_ptr->port_id;
1238 broadcast_ctl_msg_locally(&ctl);
1239 }
1240 }
1241 mutex_unlock(&rt_entry->lock);
1242 }
1243 }
1244 mutex_unlock(&routing_table_lock);
1245}
1246
1247static void msm_ipc_cleanup_remote_port_info(uint32_t node_id)
1248{
1249 struct msm_ipc_routing_table_entry *rt_entry, *tmp_rt_entry;
1250 struct msm_ipc_router_remote_port *rport_ptr, *tmp_rport_ptr;
1251 int i, j;
1252
1253 mutex_lock(&routing_table_lock);
1254 for (i = 0; i < RT_HASH_SIZE; i++) {
1255 list_for_each_entry_safe(rt_entry, tmp_rt_entry,
1256 &routing_table[i], list) {
1257 mutex_lock(&rt_entry->lock);
1258 if (rt_entry->neighbor_node_id != node_id) {
1259 mutex_unlock(&rt_entry->lock);
1260 continue;
1261 }
1262 for (j = 0; j < RP_HASH_SIZE; j++) {
1263 list_for_each_entry_safe(rport_ptr,
1264 tmp_rport_ptr,
1265 &rt_entry->remote_port_list[j], list) {
1266 list_del(&rport_ptr->list);
1267 kfree(rport_ptr);
1268 }
1269 }
1270 mutex_unlock(&rt_entry->lock);
1271 }
1272 }
1273 mutex_unlock(&routing_table_lock);
1274}
1275
1276static void msm_ipc_cleanup_routing_table(
1277 struct msm_ipc_router_xprt_info *xprt_info)
1278{
1279 int i;
1280 struct msm_ipc_routing_table_entry *rt_entry;
1281
1282 if (!xprt_info) {
1283 pr_err("%s: Invalid xprt_info\n", __func__);
1284 return;
1285 }
1286
1287 mutex_lock(&routing_table_lock);
1288 for (i = 0; i < RT_HASH_SIZE; i++) {
1289 list_for_each_entry(rt_entry, &routing_table[i], list) {
1290 mutex_lock(&rt_entry->lock);
1291 if (rt_entry->xprt_info == xprt_info)
1292 rt_entry->xprt_info = NULL;
1293 mutex_unlock(&rt_entry->lock);
1294 }
1295 }
1296 mutex_unlock(&routing_table_lock);
1297}
1298
1299static void modem_reset_cleanup(struct msm_ipc_router_xprt_info *xprt_info)
1300{
1301
1302 if (!xprt_info) {
1303 pr_err("%s: Invalid xprt_info\n", __func__);
1304 return;
1305 }
1306
1307 msm_ipc_cleanup_remote_server_info(xprt_info);
1308 msm_ipc_cleanup_remote_client_info(xprt_info);
1309 msm_ipc_cleanup_routing_table(xprt_info);
1310}
1311
Karthikeyan Ramasubramanian1668cc62012-09-23 22:23:36 -06001312/**
1313 * sync_sec_rule() - Synchrnoize the security rule into the server structure
1314 * @server: Server structure where the rule has to be synchronized.
1315 * @rule: Security tule to be synchronized.
1316 *
1317 * This function is used to update the server structure with the security
1318 * rule configured for the <service:instance> corresponding to that server.
1319 */
1320static void sync_sec_rule(struct msm_ipc_server *server, void *rule)
1321{
1322 struct msm_ipc_server_port *server_port;
1323 struct msm_ipc_router_remote_port *rport_ptr = NULL;
1324
1325 list_for_each_entry(server_port, &server->server_port_list, list) {
1326 rport_ptr = msm_ipc_router_lookup_remote_port(
1327 server_port->server_addr.node_id,
1328 server_port->server_addr.port_id);
1329 if (!rport_ptr)
1330 continue;
1331 rport_ptr->sec_rule = rule;
1332 }
1333 server->synced_sec_rule = 1;
1334}
1335
1336/**
1337 * msm_ipc_sync_sec_rule() - Sync the security rule to the service
1338 * @service: Service for which the rule has to be synchronized.
1339 * @instance: Instance for which the rule has to be synchronized.
1340 * @rule: Security rule to be synchronized.
1341 *
1342 * This function is used to syncrhonize the security rule with the server
1343 * hash table, if the user-space script configures the rule after the service
1344 * has come up. This function is used to synchronize the security rule to a
1345 * specific service and optionally a specific instance.
1346 */
1347void msm_ipc_sync_sec_rule(uint32_t service, uint32_t instance, void *rule)
1348{
1349 int key = (service & (SRV_HASH_SIZE - 1));
1350 struct msm_ipc_server *server;
1351
1352 mutex_lock(&server_list_lock);
1353 list_for_each_entry(server, &server_list[key], list) {
1354 if (server->name.service != service)
1355 continue;
1356
1357 if (server->name.instance != instance &&
1358 instance != ALL_INSTANCE)
1359 continue;
1360
1361 /*
1362 * If the rule applies to all instances and if the specific
1363 * instance of a service has a rule synchronized already,
1364 * do not apply the rule for that specific instance.
1365 */
1366 if (instance == ALL_INSTANCE && server->synced_sec_rule)
1367 continue;
1368
1369 sync_sec_rule(server, rule);
1370 }
1371 mutex_unlock(&server_list_lock);
1372}
1373
1374/**
1375 * msm_ipc_sync_default_sec_rule() - Default security rule to all services
1376 * @rule: Security rule to be synchronized.
1377 *
1378 * This function is used to syncrhonize the security rule with the server
1379 * hash table, if the user-space script configures the rule after the service
1380 * has come up. This function is used to synchronize the security rule that
1381 * applies to all services, if the concerned service do not have any rule
1382 * defined.
1383 */
1384void msm_ipc_sync_default_sec_rule(void *rule)
1385{
1386 int key;
1387 struct msm_ipc_server *server;
1388
1389 mutex_lock(&server_list_lock);
1390 for (key = 0; key < SRV_HASH_SIZE; key++) {
1391 list_for_each_entry(server, &server_list[key], list) {
1392 if (server->synced_sec_rule)
1393 continue;
1394
1395 sync_sec_rule(server, rule);
1396 }
1397 }
1398 mutex_unlock(&server_list_lock);
1399}
1400
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001401static int process_hello_msg(struct msm_ipc_router_xprt_info *xprt_info,
1402 struct rr_header *hdr)
1403{
1404 int i, rc = 0;
1405 union rr_control_msg ctl;
1406 struct msm_ipc_routing_table_entry *rt_entry;
1407
1408 if (!hdr)
1409 return -EINVAL;
1410
1411 RR("o HELLO NID %d\n", hdr->src_node_id);
1412
1413 xprt_info->remote_node_id = hdr->src_node_id;
1414 /*
1415 * Find the entry from Routing Table corresponding to Node ID.
1416 * Under SSR, an entry will be found. When the system boots up
1417 * for the 1st time, an entry will not be found and hence allocate
1418 * an entry. Update the entry with the Node ID that it corresponds
1419 * to and the XPRT through which it can be reached.
1420 */
1421 mutex_lock(&routing_table_lock);
1422 rt_entry = lookup_routing_table(hdr->src_node_id);
1423 if (!rt_entry) {
1424 rt_entry = alloc_routing_table_entry(hdr->src_node_id);
1425 if (!rt_entry) {
1426 mutex_unlock(&routing_table_lock);
1427 pr_err("%s: rt_entry allocation failed\n", __func__);
1428 return -ENOMEM;
1429 }
1430 add_routing_table_entry(rt_entry);
1431 }
1432 mutex_lock(&rt_entry->lock);
1433 rt_entry->neighbor_node_id = xprt_info->remote_node_id;
1434 rt_entry->xprt_info = xprt_info;
1435 mutex_unlock(&rt_entry->lock);
1436 mutex_unlock(&routing_table_lock);
1437
1438 /* Cleanup any remote ports, if the node is coming out of reset */
1439 msm_ipc_cleanup_remote_port_info(xprt_info->remote_node_id);
1440
1441 /* Send a reply HELLO message */
1442 memset(&ctl, 0, sizeof(ctl));
1443 ctl.cmd = IPC_ROUTER_CTRL_CMD_HELLO;
1444 rc = msm_ipc_router_send_control_msg(xprt_info, &ctl);
1445 if (rc < 0) {
1446 pr_err("%s: Error sending reply HELLO message\n", __func__);
1447 return rc;
1448 }
1449 xprt_info->initialized = 1;
1450
1451 /*
1452 * Send list of servers from the local node and from nodes
1453 * outside the mesh network in which this XPRT is part of.
1454 */
Karthikeyan Ramasubramaniane8ad5352012-10-31 15:12:08 -06001455 mutex_lock(&server_list_lock);
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001456 mutex_lock(&routing_table_lock);
1457 for (i = 0; i < RT_HASH_SIZE; i++) {
1458 list_for_each_entry(rt_entry, &routing_table[i], list) {
1459 if ((rt_entry->node_id != IPC_ROUTER_NID_LOCAL) &&
Karthikeyan Ramasubramanian72ad5792013-01-30 14:17:57 -07001460 (!rt_entry->xprt_info ||
1461 (rt_entry->xprt_info->xprt->link_id ==
1462 xprt_info->xprt->link_id)))
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001463 continue;
1464 rc = msm_ipc_router_send_server_list(rt_entry->node_id,
1465 xprt_info);
1466 if (rc < 0) {
1467 mutex_unlock(&routing_table_lock);
Karthikeyan Ramasubramaniane8ad5352012-10-31 15:12:08 -06001468 mutex_unlock(&server_list_lock);
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001469 return rc;
1470 }
1471 }
1472 }
1473 mutex_unlock(&routing_table_lock);
Karthikeyan Ramasubramaniane8ad5352012-10-31 15:12:08 -06001474 mutex_unlock(&server_list_lock);
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001475 RR("HELLO message processed\n");
1476 return rc;
1477}
1478
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001479static int process_control_msg(struct msm_ipc_router_xprt_info *xprt_info,
1480 struct rr_packet *pkt)
1481{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001482 union rr_control_msg *msg;
1483 struct msm_ipc_router_remote_port *rport_ptr;
1484 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001485 struct sk_buff *temp_ptr;
1486 struct rr_header *hdr;
1487 struct msm_ipc_server *server;
1488 struct msm_ipc_routing_table_entry *rt_entry;
1489
1490 if (pkt->length != (IPC_ROUTER_HDR_SIZE + sizeof(*msg))) {
1491 pr_err("%s: r2r msg size %d != %d\n", __func__, pkt->length,
1492 (IPC_ROUTER_HDR_SIZE + sizeof(*msg)));
1493 return -EINVAL;
1494 }
1495
1496 temp_ptr = skb_peek(pkt->pkt_fragment_q);
Karthikeyan Ramasubramanian9024dd82011-12-19 18:44:19 -07001497 if (!temp_ptr) {
1498 pr_err("%s: pkt_fragment_q is empty\n", __func__);
1499 return -EINVAL;
1500 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001501 hdr = (struct rr_header *)temp_ptr->data;
Karthikeyan Ramasubramanian9024dd82011-12-19 18:44:19 -07001502 if (!hdr) {
1503 pr_err("%s: No data inside the skb\n", __func__);
1504 return -EINVAL;
1505 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001506 msg = (union rr_control_msg *)((char *)hdr + IPC_ROUTER_HDR_SIZE);
1507
1508 switch (msg->cmd) {
1509 case IPC_ROUTER_CTRL_CMD_HELLO:
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001510 rc = process_hello_msg(xprt_info, hdr);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001511 break;
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001512
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001513 case IPC_ROUTER_CTRL_CMD_RESUME_TX:
1514 RR("o RESUME_TX id=%d:%08x\n",
1515 msg->cli.node_id, msg->cli.port_id);
1516
1517 rport_ptr = msm_ipc_router_lookup_remote_port(msg->cli.node_id,
1518 msg->cli.port_id);
1519 if (!rport_ptr) {
1520 pr_err("%s: Unable to resume client\n", __func__);
1521 break;
1522 }
1523 mutex_lock(&rport_ptr->quota_lock);
1524 rport_ptr->tx_quota_cnt = 0;
1525 mutex_unlock(&rport_ptr->quota_lock);
1526 wake_up(&rport_ptr->quota_wait);
1527 break;
1528
1529 case IPC_ROUTER_CTRL_CMD_NEW_SERVER:
1530 if (msg->srv.instance == 0) {
1531 pr_err(
1532 "rpcrouter: Server create rejected, version = 0, "
1533 "service = %08x\n", msg->srv.service);
1534 break;
1535 }
1536
1537 RR("o NEW_SERVER id=%d:%08x service=%08x:%08x\n",
1538 msg->srv.node_id, msg->srv.port_id,
1539 msg->srv.service, msg->srv.instance);
1540
1541 mutex_lock(&routing_table_lock);
1542 rt_entry = lookup_routing_table(msg->srv.node_id);
1543 if (!rt_entry) {
1544 rt_entry = alloc_routing_table_entry(msg->srv.node_id);
1545 if (!rt_entry) {
1546 mutex_unlock(&routing_table_lock);
1547 pr_err("%s: rt_entry allocation failed\n",
1548 __func__);
1549 return -ENOMEM;
1550 }
1551 mutex_lock(&rt_entry->lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001552 rt_entry->neighbor_node_id = xprt_info->remote_node_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001553 rt_entry->xprt_info = xprt_info;
1554 mutex_unlock(&rt_entry->lock);
1555 add_routing_table_entry(rt_entry);
1556 }
1557 mutex_unlock(&routing_table_lock);
1558
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001559 mutex_lock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001560 server = msm_ipc_router_lookup_server(msg->srv.service,
1561 msg->srv.instance,
1562 msg->srv.node_id,
1563 msg->srv.port_id);
1564 if (!server) {
1565 server = msm_ipc_router_create_server(
1566 msg->srv.service, msg->srv.instance,
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001567 msg->srv.node_id, msg->srv.port_id, xprt_info);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001568 if (!server) {
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001569 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001570 pr_err("%s: Server Create failed\n", __func__);
1571 return -ENOMEM;
1572 }
1573
1574 if (!msm_ipc_router_lookup_remote_port(
1575 msg->srv.node_id, msg->srv.port_id)) {
1576 rport_ptr = msm_ipc_router_create_remote_port(
1577 msg->srv.node_id, msg->srv.port_id);
1578 if (!rport_ptr)
1579 pr_err("%s: Remote port create "
1580 "failed\n", __func__);
Brent Hronik0e83d3b2013-05-01 16:25:00 -06001581 else
1582 rport_ptr->sec_rule =
1583 msm_ipc_get_security_rule(
1584 msg->srv.service,
1585 msg->srv.instance);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001586 }
1587 wake_up(&newserver_wait);
1588 }
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001589 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001590
1591 relay_msg(xprt_info, pkt);
1592 post_control_ports(pkt);
1593 break;
1594 case IPC_ROUTER_CTRL_CMD_REMOVE_SERVER:
1595 RR("o REMOVE_SERVER service=%08x:%d\n",
1596 msg->srv.service, msg->srv.instance);
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001597 mutex_lock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001598 server = msm_ipc_router_lookup_server(msg->srv.service,
1599 msg->srv.instance,
1600 msg->srv.node_id,
1601 msg->srv.port_id);
1602 if (server) {
1603 msm_ipc_router_destroy_server(server,
1604 msg->srv.node_id,
1605 msg->srv.port_id);
1606 relay_msg(xprt_info, pkt);
1607 post_control_ports(pkt);
1608 }
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001609 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001610 break;
1611 case IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT:
1612 RR("o REMOVE_CLIENT id=%d:%08x\n",
1613 msg->cli.node_id, msg->cli.port_id);
1614 rport_ptr = msm_ipc_router_lookup_remote_port(msg->cli.node_id,
1615 msg->cli.port_id);
1616 if (rport_ptr)
1617 msm_ipc_router_destroy_remote_port(rport_ptr);
1618
1619 relay_msg(xprt_info, pkt);
1620 post_control_ports(pkt);
1621 break;
1622 case IPC_ROUTER_CTRL_CMD_PING:
1623 /* No action needed for ping messages received */
1624 RR("o PING\n");
1625 break;
1626 default:
1627 RR("o UNKNOWN(%08x)\n", msg->cmd);
1628 rc = -ENOSYS;
1629 }
1630
1631 return rc;
1632}
1633
1634static void do_read_data(struct work_struct *work)
1635{
1636 struct rr_header *hdr;
1637 struct rr_packet *pkt = NULL;
1638 struct msm_ipc_port *port_ptr;
1639 struct sk_buff *head_skb;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001640 struct msm_ipc_router_remote_port *rport_ptr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001641 uint32_t resume_tx, resume_tx_node_id, resume_tx_port_id;
1642
1643 struct msm_ipc_router_xprt_info *xprt_info =
1644 container_of(work,
1645 struct msm_ipc_router_xprt_info,
1646 read_data);
1647
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001648 while ((pkt = rr_read(xprt_info)) != NULL) {
1649 if (pkt->length < IPC_ROUTER_HDR_SIZE ||
1650 pkt->length > MAX_IPC_PKT_SIZE) {
1651 pr_err("%s: Invalid pkt length %d\n",
1652 __func__, pkt->length);
1653 goto fail_data;
1654 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001655
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001656 head_skb = skb_peek(pkt->pkt_fragment_q);
1657 if (!head_skb) {
1658 pr_err("%s: head_skb is invalid\n", __func__);
1659 goto fail_data;
1660 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001661
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001662 hdr = (struct rr_header *)(head_skb->data);
1663 RR("- ver=%d type=%d src=%d:%08x crx=%d siz=%d dst=%d:%08x\n",
1664 hdr->version, hdr->type, hdr->src_node_id, hdr->src_port_id,
1665 hdr->confirm_rx, hdr->size, hdr->dst_node_id,
1666 hdr->dst_port_id);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001667
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001668 if (hdr->version != IPC_ROUTER_VERSION) {
1669 pr_err("version %d != %d\n",
1670 hdr->version, IPC_ROUTER_VERSION);
1671 goto fail_data;
1672 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001673
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001674 if ((hdr->dst_node_id != IPC_ROUTER_NID_LOCAL) &&
1675 ((hdr->type == IPC_ROUTER_CTRL_CMD_RESUME_TX) ||
1676 (hdr->type == IPC_ROUTER_CTRL_CMD_DATA))) {
1677 forward_msg(xprt_info, pkt);
1678 release_pkt(pkt);
1679 continue;
1680 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001681
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001682 if ((hdr->dst_port_id == IPC_ROUTER_ADDRESS) ||
1683 (hdr->type == IPC_ROUTER_CTRL_CMD_HELLO)) {
1684 process_control_msg(xprt_info, pkt);
1685 release_pkt(pkt);
1686 continue;
1687 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001688#if defined(CONFIG_MSM_SMD_LOGGING)
1689#if defined(DEBUG)
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001690 if (msm_ipc_router_debug_mask & SMEM_LOG) {
1691 smem_log_event((SMEM_LOG_PROC_ID_APPS |
1692 SMEM_LOG_RPC_ROUTER_EVENT_BASE |
1693 IPC_ROUTER_LOG_EVENT_RX),
1694 (hdr->src_node_id << 24) |
1695 (hdr->src_port_id & 0xffffff),
1696 (hdr->dst_node_id << 24) |
1697 (hdr->dst_port_id & 0xffffff),
1698 (hdr->type << 24) | (hdr->confirm_rx << 16) |
1699 (hdr->size & 0xffff));
1700 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001701#endif
1702#endif
1703
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001704 resume_tx = hdr->confirm_rx;
1705 resume_tx_node_id = hdr->dst_node_id;
1706 resume_tx_port_id = hdr->dst_port_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001707
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001708 rport_ptr = msm_ipc_router_lookup_remote_port(hdr->src_node_id,
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06001709 hdr->src_port_id);
1710
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001711 mutex_lock(&local_ports_lock);
1712 port_ptr = msm_ipc_router_lookup_local_port(hdr->dst_port_id);
1713 if (!port_ptr) {
1714 pr_err("%s: No local port id %08x\n", __func__,
1715 hdr->dst_port_id);
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06001716 mutex_unlock(&local_ports_lock);
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001717 release_pkt(pkt);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001718 goto process_done;
1719 }
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001720
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001721 if (!rport_ptr) {
1722 rport_ptr = msm_ipc_router_create_remote_port(
1723 hdr->src_node_id,
1724 hdr->src_port_id);
1725 if (!rport_ptr) {
1726 pr_err("%s: Rmt Prt %08x:%08x create failed\n",
1727 __func__, hdr->src_node_id,
1728 hdr->src_port_id);
1729 mutex_unlock(&local_ports_lock);
1730 goto process_done;
1731 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001732 }
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001733
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -06001734 mutex_lock(&port_ptr->port_rx_q_lock);
1735 wake_lock(&port_ptr->port_rx_wake_lock);
1736 list_add_tail(&pkt->list, &port_ptr->port_rx_q);
1737 wake_up(&port_ptr->port_rx_wait_q);
1738 if (port_ptr->notify)
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001739 port_ptr->notify(MSM_IPC_ROUTER_READ_CB,
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -06001740 port_ptr->priv);
1741 mutex_unlock(&port_ptr->port_rx_q_lock);
1742 mutex_unlock(&local_ports_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001743
1744process_done:
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001745 if (resume_tx) {
1746 union rr_control_msg msg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001747
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001748 msg.cmd = IPC_ROUTER_CTRL_CMD_RESUME_TX;
1749 msg.cli.node_id = resume_tx_node_id;
1750 msg.cli.port_id = resume_tx_port_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001751
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001752 RR("x RESUME_TX id=%d:%08x\n",
1753 msg.cli.node_id, msg.cli.port_id);
1754 msm_ipc_router_send_control_msg(xprt_info, &msg);
1755 }
1756
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001757 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001758 return;
1759
1760fail_data:
1761 release_pkt(pkt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001762 pr_err("ipc_router has died\n");
1763}
1764
1765int msm_ipc_router_register_server(struct msm_ipc_port *port_ptr,
1766 struct msm_ipc_addr *name)
1767{
1768 struct msm_ipc_server *server;
1769 unsigned long flags;
1770 union rr_control_msg ctl;
1771
1772 if (!port_ptr || !name)
1773 return -EINVAL;
1774
1775 if (name->addrtype != MSM_IPC_ADDR_NAME)
1776 return -EINVAL;
1777
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001778 mutex_lock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001779 server = msm_ipc_router_lookup_server(name->addr.port_name.service,
1780 name->addr.port_name.instance,
1781 IPC_ROUTER_NID_LOCAL,
1782 port_ptr->this_port.port_id);
1783 if (server) {
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001784 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001785 pr_err("%s: Server already present\n", __func__);
1786 return -EINVAL;
1787 }
1788
1789 server = msm_ipc_router_create_server(name->addr.port_name.service,
1790 name->addr.port_name.instance,
1791 IPC_ROUTER_NID_LOCAL,
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001792 port_ptr->this_port.port_id,
1793 NULL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001794 if (!server) {
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001795 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001796 pr_err("%s: Server Creation failed\n", __func__);
1797 return -EINVAL;
1798 }
1799
1800 ctl.cmd = IPC_ROUTER_CTRL_CMD_NEW_SERVER;
1801 ctl.srv.service = server->name.service;
1802 ctl.srv.instance = server->name.instance;
1803 ctl.srv.node_id = IPC_ROUTER_NID_LOCAL;
1804 ctl.srv.port_id = port_ptr->this_port.port_id;
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001805 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001806 broadcast_ctl_msg(&ctl);
1807 spin_lock_irqsave(&port_ptr->port_lock, flags);
1808 port_ptr->type = SERVER_PORT;
1809 port_ptr->port_name.service = server->name.service;
1810 port_ptr->port_name.instance = server->name.instance;
1811 spin_unlock_irqrestore(&port_ptr->port_lock, flags);
1812 return 0;
1813}
1814
1815int msm_ipc_router_unregister_server(struct msm_ipc_port *port_ptr)
1816{
1817 struct msm_ipc_server *server;
1818 unsigned long flags;
1819 union rr_control_msg ctl;
1820
1821 if (!port_ptr)
1822 return -EINVAL;
1823
1824 if (port_ptr->type != SERVER_PORT) {
1825 pr_err("%s: Trying to unregister a non-server port\n",
1826 __func__);
1827 return -EINVAL;
1828 }
1829
1830 if (port_ptr->this_port.node_id != IPC_ROUTER_NID_LOCAL) {
1831 pr_err("%s: Trying to unregister a remote server locally\n",
1832 __func__);
1833 return -EINVAL;
1834 }
1835
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001836 mutex_lock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001837 server = msm_ipc_router_lookup_server(port_ptr->port_name.service,
1838 port_ptr->port_name.instance,
1839 port_ptr->this_port.node_id,
1840 port_ptr->this_port.port_id);
1841 if (!server) {
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001842 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001843 pr_err("%s: Server lookup failed\n", __func__);
1844 return -ENODEV;
1845 }
1846
1847 ctl.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_SERVER;
1848 ctl.srv.service = server->name.service;
1849 ctl.srv.instance = server->name.instance;
1850 ctl.srv.node_id = IPC_ROUTER_NID_LOCAL;
1851 ctl.srv.port_id = port_ptr->this_port.port_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001852 msm_ipc_router_destroy_server(server, port_ptr->this_port.node_id,
1853 port_ptr->this_port.port_id);
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001854 mutex_unlock(&server_list_lock);
1855 broadcast_ctl_msg(&ctl);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001856 spin_lock_irqsave(&port_ptr->port_lock, flags);
1857 port_ptr->type = CLIENT_PORT;
1858 spin_unlock_irqrestore(&port_ptr->port_lock, flags);
1859 return 0;
1860}
1861
1862static int loopback_data(struct msm_ipc_port *src,
1863 uint32_t port_id,
1864 struct sk_buff_head *data)
1865{
1866 struct sk_buff *head_skb;
1867 struct rr_header *hdr;
1868 struct msm_ipc_port *port_ptr;
1869 struct rr_packet *pkt;
Karthikeyan Ramasubramanian0a801c12013-02-08 13:07:42 -07001870 int ret_len;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001871
1872 if (!data) {
1873 pr_err("%s: Invalid pkt pointer\n", __func__);
1874 return -EINVAL;
1875 }
1876
1877 pkt = create_pkt(data);
1878 if (!pkt) {
1879 pr_err("%s: New pkt create failed\n", __func__);
1880 return -ENOMEM;
1881 }
1882
1883 head_skb = skb_peek(pkt->pkt_fragment_q);
Karthikeyan Ramasubramanian9024dd82011-12-19 18:44:19 -07001884 if (!head_skb) {
1885 pr_err("%s: pkt_fragment_q is empty\n", __func__);
Brent Hronik0e83d3b2013-05-01 16:25:00 -06001886 release_pkt(pkt);
Karthikeyan Ramasubramanian9024dd82011-12-19 18:44:19 -07001887 return -EINVAL;
1888 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001889 hdr = (struct rr_header *)skb_push(head_skb, IPC_ROUTER_HDR_SIZE);
1890 if (!hdr) {
1891 pr_err("%s: Prepend Header failed\n", __func__);
1892 release_pkt(pkt);
1893 return -ENOMEM;
1894 }
1895 hdr->version = IPC_ROUTER_VERSION;
1896 hdr->type = IPC_ROUTER_CTRL_CMD_DATA;
1897 hdr->src_node_id = src->this_port.node_id;
1898 hdr->src_port_id = src->this_port.port_id;
1899 hdr->size = pkt->length;
1900 hdr->confirm_rx = 0;
1901 hdr->dst_node_id = IPC_ROUTER_NID_LOCAL;
1902 hdr->dst_port_id = port_id;
1903 pkt->length += IPC_ROUTER_HDR_SIZE;
1904
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06001905 mutex_lock(&local_ports_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001906 port_ptr = msm_ipc_router_lookup_local_port(port_id);
1907 if (!port_ptr) {
1908 pr_err("%s: Local port %d not present\n", __func__, port_id);
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06001909 mutex_unlock(&local_ports_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001910 release_pkt(pkt);
1911 return -ENODEV;
1912 }
1913
1914 mutex_lock(&port_ptr->port_rx_q_lock);
1915 wake_lock(&port_ptr->port_rx_wake_lock);
1916 list_add_tail(&pkt->list, &port_ptr->port_rx_q);
Karthikeyan Ramasubramanian0a801c12013-02-08 13:07:42 -07001917 ret_len = pkt->length;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001918 wake_up(&port_ptr->port_rx_wait_q);
1919 mutex_unlock(&port_ptr->port_rx_q_lock);
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06001920 mutex_unlock(&local_ports_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001921
Karthikeyan Ramasubramanian0a801c12013-02-08 13:07:42 -07001922 return ret_len;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001923}
1924
1925static int msm_ipc_router_write_pkt(struct msm_ipc_port *src,
1926 struct msm_ipc_router_remote_port *rport_ptr,
1927 struct rr_packet *pkt)
1928{
1929 struct sk_buff *head_skb;
1930 struct rr_header *hdr;
1931 struct msm_ipc_router_xprt_info *xprt_info;
1932 struct msm_ipc_routing_table_entry *rt_entry;
1933 int ret;
1934 DEFINE_WAIT(__wait);
1935
1936 if (!rport_ptr || !src || !pkt)
1937 return -EINVAL;
1938
1939 head_skb = skb_peek(pkt->pkt_fragment_q);
Karthikeyan Ramasubramanian9024dd82011-12-19 18:44:19 -07001940 if (!head_skb) {
1941 pr_err("%s: pkt_fragment_q is empty\n", __func__);
1942 return -EINVAL;
1943 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001944 hdr = (struct rr_header *)skb_push(head_skb, IPC_ROUTER_HDR_SIZE);
1945 if (!hdr) {
1946 pr_err("%s: Prepend Header failed\n", __func__);
1947 return -ENOMEM;
1948 }
1949 hdr->version = IPC_ROUTER_VERSION;
1950 hdr->type = IPC_ROUTER_CTRL_CMD_DATA;
1951 hdr->src_node_id = src->this_port.node_id;
1952 hdr->src_port_id = src->this_port.port_id;
1953 hdr->size = pkt->length;
1954 hdr->confirm_rx = 0;
1955 hdr->dst_node_id = rport_ptr->node_id;
1956 hdr->dst_port_id = rport_ptr->port_id;
1957 pkt->length += IPC_ROUTER_HDR_SIZE;
1958
1959 for (;;) {
1960 prepare_to_wait(&rport_ptr->quota_wait, &__wait,
1961 TASK_INTERRUPTIBLE);
1962 mutex_lock(&rport_ptr->quota_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001963 if (rport_ptr->restart_state != RESTART_NORMAL)
1964 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001965 if (rport_ptr->tx_quota_cnt <
1966 IPC_ROUTER_DEFAULT_RX_QUOTA)
1967 break;
1968 if (signal_pending(current))
1969 break;
1970 mutex_unlock(&rport_ptr->quota_lock);
1971 schedule();
1972 }
1973 finish_wait(&rport_ptr->quota_wait, &__wait);
1974
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001975 if (rport_ptr->restart_state != RESTART_NORMAL) {
1976 mutex_unlock(&rport_ptr->quota_lock);
1977 return -ENETRESET;
1978 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001979 if (signal_pending(current)) {
1980 mutex_unlock(&rport_ptr->quota_lock);
1981 return -ERESTARTSYS;
1982 }
1983 rport_ptr->tx_quota_cnt++;
1984 if (rport_ptr->tx_quota_cnt == IPC_ROUTER_DEFAULT_RX_QUOTA)
1985 hdr->confirm_rx = 1;
1986 mutex_unlock(&rport_ptr->quota_lock);
1987
1988 mutex_lock(&routing_table_lock);
1989 rt_entry = lookup_routing_table(hdr->dst_node_id);
1990 if (!rt_entry || !rt_entry->xprt_info) {
1991 mutex_unlock(&routing_table_lock);
1992 pr_err("%s: Remote node %d not up\n",
1993 __func__, hdr->dst_node_id);
1994 return -ENODEV;
1995 }
1996 mutex_lock(&rt_entry->lock);
1997 xprt_info = rt_entry->xprt_info;
1998 mutex_lock(&xprt_info->tx_lock);
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -07001999 ret = xprt_info->xprt->write(pkt, pkt->length, xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002000 mutex_unlock(&xprt_info->tx_lock);
2001 mutex_unlock(&rt_entry->lock);
2002 mutex_unlock(&routing_table_lock);
2003
2004 if (ret < 0) {
2005 pr_err("%s: Write on XPRT failed\n", __func__);
2006 return ret;
2007 }
2008
2009 RAW_HDR("[w rr_h] "
2010 "ver=%i,type=%s,src_nid=%08x,src_port_id=%08x,"
2011 "confirm_rx=%i,size=%3i,dst_pid=%08x,dst_cid=%08x\n",
2012 hdr->version, type_to_str(hdr->type),
2013 hdr->src_node_id, hdr->src_port_id,
2014 hdr->confirm_rx, hdr->size,
2015 hdr->dst_node_id, hdr->dst_port_id);
2016
2017#if defined(CONFIG_MSM_SMD_LOGGING)
2018#if defined(DEBUG)
2019 if (msm_ipc_router_debug_mask & SMEM_LOG) {
2020 smem_log_event((SMEM_LOG_PROC_ID_APPS |
2021 SMEM_LOG_RPC_ROUTER_EVENT_BASE |
2022 IPC_ROUTER_LOG_EVENT_TX),
2023 (hdr->src_node_id << 24) |
2024 (hdr->src_port_id & 0xffffff),
2025 (hdr->dst_node_id << 24) |
2026 (hdr->dst_port_id & 0xffffff),
2027 (hdr->type << 24) | (hdr->confirm_rx << 16) |
2028 (hdr->size & 0xffff));
2029 }
2030#endif
2031#endif
2032
2033 return pkt->length;
2034}
2035
2036int msm_ipc_router_send_to(struct msm_ipc_port *src,
2037 struct sk_buff_head *data,
2038 struct msm_ipc_addr *dest)
2039{
2040 uint32_t dst_node_id = 0, dst_port_id = 0;
2041 struct msm_ipc_server *server;
2042 struct msm_ipc_server_port *server_port;
2043 struct msm_ipc_router_remote_port *rport_ptr = NULL;
2044 struct rr_packet *pkt;
2045 int ret;
2046
2047 if (!src || !data || !dest) {
2048 pr_err("%s: Invalid Parameters\n", __func__);
2049 return -EINVAL;
2050 }
2051
2052 /* Resolve Address*/
2053 if (dest->addrtype == MSM_IPC_ADDR_ID) {
2054 dst_node_id = dest->addr.port_addr.node_id;
2055 dst_port_id = dest->addr.port_addr.port_id;
2056 } else if (dest->addrtype == MSM_IPC_ADDR_NAME) {
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002057 mutex_lock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002058 server = msm_ipc_router_lookup_server(
2059 dest->addr.port_name.service,
2060 dest->addr.port_name.instance,
2061 0, 0);
2062 if (!server) {
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002063 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002064 pr_err("%s: Destination not reachable\n", __func__);
2065 return -ENODEV;
2066 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002067 server_port = list_first_entry(&server->server_port_list,
2068 struct msm_ipc_server_port,
2069 list);
2070 dst_node_id = server_port->server_addr.node_id;
2071 dst_port_id = server_port->server_addr.port_id;
2072 mutex_unlock(&server_list_lock);
2073 }
2074 if (dst_node_id == IPC_ROUTER_NID_LOCAL) {
2075 ret = loopback_data(src, dst_port_id, data);
2076 return ret;
2077 }
2078
2079 /* Achieve Flow control */
2080 rport_ptr = msm_ipc_router_lookup_remote_port(dst_node_id,
2081 dst_port_id);
2082 if (!rport_ptr) {
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002083 pr_err("%s: Could not create remote port\n", __func__);
2084 return -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002085 }
2086
Karthikeyan Ramasubramanian1668cc62012-09-23 22:23:36 -06002087 if (src->check_send_permissions) {
2088 ret = src->check_send_permissions(rport_ptr->sec_rule);
2089 if (ret <= 0) {
2090 pr_err("%s: permission failure for %s\n",
2091 __func__, current->comm);
2092 return -EPERM;
2093 }
2094 }
2095
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002096 pkt = create_pkt(data);
2097 if (!pkt) {
2098 pr_err("%s: Pkt creation failed\n", __func__);
2099 return -ENOMEM;
2100 }
2101
2102 ret = msm_ipc_router_write_pkt(src, rport_ptr, pkt);
2103 release_pkt(pkt);
2104
2105 return ret;
2106}
2107
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -06002108int msm_ipc_router_send_msg(struct msm_ipc_port *src,
2109 struct msm_ipc_addr *dest,
2110 void *data, unsigned int data_len)
2111{
2112 struct sk_buff_head *out_skb_head;
2113 int ret;
2114
2115 out_skb_head = msm_ipc_router_buf_to_skb(data, data_len);
2116 if (!out_skb_head) {
2117 pr_err("%s: SKB conversion failed\n", __func__);
2118 return -EFAULT;
2119 }
2120
2121 ret = msm_ipc_router_send_to(src, out_skb_head, dest);
2122 if (ret < 0) {
2123 pr_err("%s: msm_ipc_router_send_to failed - ret: %d\n",
2124 __func__, ret);
2125 msm_ipc_router_free_skb(out_skb_head);
2126 }
2127 return 0;
2128}
2129
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002130int msm_ipc_router_read(struct msm_ipc_port *port_ptr,
2131 struct sk_buff_head **data,
2132 size_t buf_len)
2133{
2134 struct rr_packet *pkt;
2135 int ret;
2136
2137 if (!port_ptr || !data)
2138 return -EINVAL;
2139
2140 mutex_lock(&port_ptr->port_rx_q_lock);
2141 if (list_empty(&port_ptr->port_rx_q)) {
2142 mutex_unlock(&port_ptr->port_rx_q_lock);
2143 return -EAGAIN;
2144 }
2145
2146 pkt = list_first_entry(&port_ptr->port_rx_q, struct rr_packet, list);
2147 if ((buf_len) && ((pkt->length - IPC_ROUTER_HDR_SIZE) > buf_len)) {
2148 mutex_unlock(&port_ptr->port_rx_q_lock);
2149 return -ETOOSMALL;
2150 }
2151 list_del(&pkt->list);
2152 if (list_empty(&port_ptr->port_rx_q))
2153 wake_unlock(&port_ptr->port_rx_wake_lock);
2154 *data = pkt->pkt_fragment_q;
2155 ret = pkt->length;
2156 kfree(pkt);
2157 mutex_unlock(&port_ptr->port_rx_q_lock);
2158
2159 return ret;
2160}
2161
2162int msm_ipc_router_recv_from(struct msm_ipc_port *port_ptr,
2163 struct sk_buff_head **data,
2164 struct msm_ipc_addr *src,
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -06002165 long timeout)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002166{
2167 int ret, data_len, align_size;
2168 struct sk_buff *temp_skb;
2169 struct rr_header *hdr = NULL;
2170
2171 if (!port_ptr || !data) {
2172 pr_err("%s: Invalid pointers being passed\n", __func__);
2173 return -EINVAL;
2174 }
2175
2176 *data = NULL;
2177 mutex_lock(&port_ptr->port_rx_q_lock);
2178 while (list_empty(&port_ptr->port_rx_q)) {
2179 mutex_unlock(&port_ptr->port_rx_q_lock);
2180 if (timeout < 0) {
2181 ret = wait_event_interruptible(
2182 port_ptr->port_rx_wait_q,
2183 !list_empty(&port_ptr->port_rx_q));
2184 if (ret)
2185 return ret;
2186 } else if (timeout > 0) {
2187 timeout = wait_event_interruptible_timeout(
2188 port_ptr->port_rx_wait_q,
2189 !list_empty(&port_ptr->port_rx_q),
2190 timeout);
2191 if (timeout < 0)
2192 return -EFAULT;
2193 }
2194 if (timeout == 0)
2195 return -ETIMEDOUT;
2196 mutex_lock(&port_ptr->port_rx_q_lock);
2197 }
2198 mutex_unlock(&port_ptr->port_rx_q_lock);
2199
2200 ret = msm_ipc_router_read(port_ptr, data, 0);
2201 if (ret <= 0 || !(*data))
2202 return ret;
2203
2204 temp_skb = skb_peek(*data);
2205 hdr = (struct rr_header *)(temp_skb->data);
2206 if (src) {
2207 src->addrtype = MSM_IPC_ADDR_ID;
2208 src->addr.port_addr.node_id = hdr->src_node_id;
2209 src->addr.port_addr.port_id = hdr->src_port_id;
2210 }
2211
2212 data_len = hdr->size;
2213 skb_pull(temp_skb, IPC_ROUTER_HDR_SIZE);
2214 align_size = ALIGN_SIZE(data_len);
2215 if (align_size) {
2216 temp_skb = skb_peek_tail(*data);
2217 skb_trim(temp_skb, (temp_skb->len - align_size));
2218 }
2219 return data_len;
2220}
2221
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -06002222int msm_ipc_router_read_msg(struct msm_ipc_port *port_ptr,
2223 struct msm_ipc_addr *src,
2224 unsigned char **data,
2225 unsigned int *len)
2226{
2227 struct sk_buff_head *in_skb_head;
2228 int ret;
2229
2230 ret = msm_ipc_router_recv_from(port_ptr, &in_skb_head, src, -1);
2231 if (ret < 0) {
2232 pr_err("%s: msm_ipc_router_recv_from failed - ret: %d\n",
2233 __func__, ret);
2234 return ret;
2235 }
2236
2237 *data = msm_ipc_router_skb_to_buf(in_skb_head, ret);
2238 if (!(*data))
2239 pr_err("%s: Buf conversion failed\n", __func__);
2240
2241 *len = ret;
2242 msm_ipc_router_free_skb(in_skb_head);
2243 return 0;
2244}
2245
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002246struct msm_ipc_port *msm_ipc_router_create_port(
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -06002247 void (*notify)(unsigned event, void *priv),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002248 void *priv)
2249{
2250 struct msm_ipc_port *port_ptr;
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -06002251 int ret;
2252
2253 ret = wait_for_completion_interruptible(&msm_ipc_local_router_up);
2254 if (ret < 0) {
2255 pr_err("%s: Error waiting for local router\n", __func__);
2256 return NULL;
2257 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002258
2259 port_ptr = msm_ipc_router_create_raw_port(NULL, notify, priv);
2260 if (!port_ptr)
2261 pr_err("%s: port_ptr alloc failed\n", __func__);
2262
2263 return port_ptr;
2264}
2265
2266int msm_ipc_router_close_port(struct msm_ipc_port *port_ptr)
2267{
2268 union rr_control_msg msg;
2269 struct rr_packet *pkt, *temp_pkt;
2270 struct msm_ipc_server *server;
2271
2272 if (!port_ptr)
2273 return -EINVAL;
2274
2275 if (port_ptr->type == SERVER_PORT || port_ptr->type == CLIENT_PORT) {
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06002276 mutex_lock(&local_ports_lock);
2277 list_del(&port_ptr->list);
2278 mutex_unlock(&local_ports_lock);
2279
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002280 if (port_ptr->type == SERVER_PORT) {
2281 msg.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_SERVER;
2282 msg.srv.service = port_ptr->port_name.service;
2283 msg.srv.instance = port_ptr->port_name.instance;
2284 msg.srv.node_id = port_ptr->this_port.node_id;
2285 msg.srv.port_id = port_ptr->this_port.port_id;
2286 RR("x REMOVE_SERVER Name=%d:%08x Id=%d:%08x\n",
2287 msg.srv.service, msg.srv.instance,
2288 msg.srv.node_id, msg.srv.port_id);
Karthikeyan Ramasubramanian25e91872013-01-10 17:09:13 -07002289 broadcast_ctl_msg(&msg);
2290 broadcast_ctl_msg_locally(&msg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002291 }
Karthikeyan Ramasubramanian25e91872013-01-10 17:09:13 -07002292
2293 /*
2294 * Server port could have been a client port earlier.
2295 * Send REMOVE_CLIENT message in either case.
2296 */
2297 msg.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT;
2298 msg.cli.node_id = port_ptr->this_port.node_id;
2299 msg.cli.port_id = port_ptr->this_port.port_id;
2300 RR("x REMOVE_CLIENT id=%d:%08x\n",
2301 msg.cli.node_id, msg.cli.port_id);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002302 broadcast_ctl_msg(&msg);
2303 broadcast_ctl_msg_locally(&msg);
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06002304 } else if (port_ptr->type == CONTROL_PORT) {
2305 mutex_lock(&control_ports_lock);
2306 list_del(&port_ptr->list);
2307 mutex_unlock(&control_ports_lock);
Karthikeyan Ramasubramaniand6dbfae2013-01-16 09:00:28 -07002308 } else if (port_ptr->type == IRSC_PORT) {
2309 mutex_lock(&local_ports_lock);
2310 list_del(&port_ptr->list);
2311 mutex_unlock(&local_ports_lock);
2312 signal_irsc_completion();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002313 }
2314
2315 mutex_lock(&port_ptr->port_rx_q_lock);
2316 list_for_each_entry_safe(pkt, temp_pkt, &port_ptr->port_rx_q, list) {
2317 list_del(&pkt->list);
2318 release_pkt(pkt);
2319 }
2320 mutex_unlock(&port_ptr->port_rx_q_lock);
2321
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002322 if (port_ptr->type == SERVER_PORT) {
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002323 mutex_lock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002324 server = msm_ipc_router_lookup_server(
2325 port_ptr->port_name.service,
2326 port_ptr->port_name.instance,
2327 port_ptr->this_port.node_id,
2328 port_ptr->this_port.port_id);
2329 if (server)
2330 msm_ipc_router_destroy_server(server,
2331 port_ptr->this_port.node_id,
2332 port_ptr->this_port.port_id);
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002333 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002334 }
2335
Karthikeyan Ramasubramaniandd8c3b52011-11-30 16:26:12 -07002336 wake_lock_destroy(&port_ptr->port_rx_wake_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002337 kfree(port_ptr);
2338 return 0;
2339}
2340
2341int msm_ipc_router_get_curr_pkt_size(struct msm_ipc_port *port_ptr)
2342{
2343 struct rr_packet *pkt;
2344 int rc = 0;
2345
2346 if (!port_ptr)
2347 return -EINVAL;
2348
2349 mutex_lock(&port_ptr->port_rx_q_lock);
2350 if (!list_empty(&port_ptr->port_rx_q)) {
2351 pkt = list_first_entry(&port_ptr->port_rx_q,
2352 struct rr_packet, list);
2353 rc = pkt->length;
2354 }
2355 mutex_unlock(&port_ptr->port_rx_q_lock);
2356
2357 return rc;
2358}
2359
2360int msm_ipc_router_bind_control_port(struct msm_ipc_port *port_ptr)
2361{
2362 if (!port_ptr)
2363 return -EINVAL;
2364
2365 mutex_lock(&local_ports_lock);
2366 list_del(&port_ptr->list);
2367 mutex_unlock(&local_ports_lock);
2368 port_ptr->type = CONTROL_PORT;
2369 mutex_lock(&control_ports_lock);
2370 list_add_tail(&port_ptr->list, &control_ports);
2371 mutex_unlock(&control_ports_lock);
2372
2373 return 0;
2374}
2375
2376int msm_ipc_router_lookup_server_name(struct msm_ipc_port_name *srv_name,
Karthikeyan Ramasubramaniandfde01b2012-06-12 14:25:13 -06002377 struct msm_ipc_server_info *srv_info,
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002378 int num_entries_in_array,
2379 uint32_t lookup_mask)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002380{
2381 struct msm_ipc_server *server;
2382 struct msm_ipc_server_port *server_port;
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002383 int key, i = 0; /*num_entries_found*/
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002384
2385 if (!srv_name) {
2386 pr_err("%s: Invalid srv_name\n", __func__);
2387 return -EINVAL;
2388 }
2389
Karthikeyan Ramasubramaniandfde01b2012-06-12 14:25:13 -06002390 if (num_entries_in_array && !srv_info) {
2391 pr_err("%s: srv_info NULL\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002392 return -EINVAL;
2393 }
2394
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002395 mutex_lock(&server_list_lock);
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002396 if (!lookup_mask)
2397 lookup_mask = 0xFFFFFFFF;
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002398 key = (srv_name->service & (SRV_HASH_SIZE - 1));
2399 list_for_each_entry(server, &server_list[key], list) {
2400 if ((server->name.service != srv_name->service) ||
2401 ((server->name.instance & lookup_mask) !=
2402 srv_name->instance))
2403 continue;
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002404
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002405 list_for_each_entry(server_port,
2406 &server->server_port_list, list) {
2407 if (i < num_entries_in_array) {
2408 srv_info[i].node_id =
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002409 server_port->server_addr.node_id;
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002410 srv_info[i].port_id =
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002411 server_port->server_addr.port_id;
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002412 srv_info[i].service = server->name.service;
2413 srv_info[i].instance = server->name.instance;
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002414 }
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002415 i++;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002416 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002417 }
2418 mutex_unlock(&server_list_lock);
2419
2420 return i;
2421}
2422
2423int msm_ipc_router_close(void)
2424{
2425 struct msm_ipc_router_xprt_info *xprt_info, *tmp_xprt_info;
2426
2427 mutex_lock(&xprt_info_list_lock);
2428 list_for_each_entry_safe(xprt_info, tmp_xprt_info,
2429 &xprt_info_list, list) {
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -07002430 xprt_info->xprt->close(xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002431 list_del(&xprt_info->list);
2432 kfree(xprt_info);
2433 }
2434 mutex_unlock(&xprt_info_list_lock);
2435 return 0;
2436}
2437
2438#if defined(CONFIG_DEBUG_FS)
2439static int dump_routing_table(char *buf, int max)
2440{
2441 int i = 0, j;
2442 struct msm_ipc_routing_table_entry *rt_entry;
2443
2444 for (j = 0; j < RT_HASH_SIZE; j++) {
2445 mutex_lock(&routing_table_lock);
2446 list_for_each_entry(rt_entry, &routing_table[j], list) {
2447 mutex_lock(&rt_entry->lock);
2448 i += scnprintf(buf + i, max - i,
2449 "Node Id: 0x%08x\n", rt_entry->node_id);
Karthikeyan Ramasubramanianc1a4e3a2012-09-10 16:10:24 -06002450 if (rt_entry->node_id == IPC_ROUTER_NID_LOCAL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002451 i += scnprintf(buf + i, max - i,
2452 "XPRT Name: Loopback\n");
2453 i += scnprintf(buf + i, max - i,
2454 "Next Hop: %d\n", rt_entry->node_id);
2455 } else {
2456 i += scnprintf(buf + i, max - i,
2457 "XPRT Name: %s\n",
2458 rt_entry->xprt_info->xprt->name);
2459 i += scnprintf(buf + i, max - i,
2460 "Next Hop: 0x%08x\n",
2461 rt_entry->xprt_info->remote_node_id);
2462 }
2463 i += scnprintf(buf + i, max - i, "\n");
2464 mutex_unlock(&rt_entry->lock);
2465 }
2466 mutex_unlock(&routing_table_lock);
2467 }
2468
2469 return i;
2470}
2471
2472static int dump_xprt_info(char *buf, int max)
2473{
2474 int i = 0;
2475 struct msm_ipc_router_xprt_info *xprt_info;
2476
2477 mutex_lock(&xprt_info_list_lock);
2478 list_for_each_entry(xprt_info, &xprt_info_list, list) {
2479 i += scnprintf(buf + i, max - i, "XPRT Name: %s\n",
2480 xprt_info->xprt->name);
2481 i += scnprintf(buf + i, max - i, "Link Id: %d\n",
2482 xprt_info->xprt->link_id);
2483 i += scnprintf(buf + i, max - i, "Initialized: %s\n",
2484 (xprt_info->initialized ? "Y" : "N"));
2485 i += scnprintf(buf + i, max - i, "Remote Node Id: 0x%08x\n",
2486 xprt_info->remote_node_id);
2487 i += scnprintf(buf + i, max - i, "\n");
2488 }
2489 mutex_unlock(&xprt_info_list_lock);
2490
2491 return i;
2492}
2493
2494static int dump_servers(char *buf, int max)
2495{
2496 int i = 0, j;
2497 struct msm_ipc_server *server;
2498 struct msm_ipc_server_port *server_port;
2499
2500 mutex_lock(&server_list_lock);
2501 for (j = 0; j < SRV_HASH_SIZE; j++) {
2502 list_for_each_entry(server, &server_list[j], list) {
2503 list_for_each_entry(server_port,
2504 &server->server_port_list,
2505 list) {
2506 i += scnprintf(buf + i, max - i, "Service: "
2507 "0x%08x\n", server->name.service);
2508 i += scnprintf(buf + i, max - i, "Instance: "
2509 "0x%08x\n", server->name.instance);
2510 i += scnprintf(buf + i, max - i,
2511 "Node_id: 0x%08x\n",
2512 server_port->server_addr.node_id);
2513 i += scnprintf(buf + i, max - i,
2514 "Port_id: 0x%08x\n",
2515 server_port->server_addr.port_id);
2516 i += scnprintf(buf + i, max - i, "\n");
2517 }
2518 }
2519 }
2520 mutex_unlock(&server_list_lock);
2521
2522 return i;
2523}
2524
2525static int dump_remote_ports(char *buf, int max)
2526{
2527 int i = 0, j, k;
2528 struct msm_ipc_router_remote_port *rport_ptr;
2529 struct msm_ipc_routing_table_entry *rt_entry;
2530
2531 for (j = 0; j < RT_HASH_SIZE; j++) {
2532 mutex_lock(&routing_table_lock);
2533 list_for_each_entry(rt_entry, &routing_table[j], list) {
2534 mutex_lock(&rt_entry->lock);
2535 for (k = 0; k < RP_HASH_SIZE; k++) {
2536 list_for_each_entry(rport_ptr,
2537 &rt_entry->remote_port_list[k],
2538 list) {
2539 i += scnprintf(buf + i, max - i,
2540 "Node_id: 0x%08x\n",
2541 rport_ptr->node_id);
2542 i += scnprintf(buf + i, max - i,
2543 "Port_id: 0x%08x\n",
2544 rport_ptr->port_id);
2545 i += scnprintf(buf + i, max - i,
2546 "Quota_cnt: %d\n",
2547 rport_ptr->tx_quota_cnt);
2548 i += scnprintf(buf + i, max - i, "\n");
2549 }
2550 }
2551 mutex_unlock(&rt_entry->lock);
2552 }
2553 mutex_unlock(&routing_table_lock);
2554 }
2555
2556 return i;
2557}
2558
2559static int dump_control_ports(char *buf, int max)
2560{
2561 int i = 0;
2562 struct msm_ipc_port *port_ptr;
2563
2564 mutex_lock(&control_ports_lock);
2565 list_for_each_entry(port_ptr, &control_ports, list) {
2566 i += scnprintf(buf + i, max - i, "Node_id: 0x%08x\n",
2567 port_ptr->this_port.node_id);
2568 i += scnprintf(buf + i, max - i, "Port_id: 0x%08x\n",
2569 port_ptr->this_port.port_id);
2570 i += scnprintf(buf + i, max - i, "\n");
2571 }
2572 mutex_unlock(&control_ports_lock);
2573
2574 return i;
2575}
2576
2577static int dump_local_ports(char *buf, int max)
2578{
2579 int i = 0, j;
2580 unsigned long flags;
2581 struct msm_ipc_port *port_ptr;
2582
2583 mutex_lock(&local_ports_lock);
2584 for (j = 0; j < LP_HASH_SIZE; j++) {
2585 list_for_each_entry(port_ptr, &local_ports[j], list) {
2586 spin_lock_irqsave(&port_ptr->port_lock, flags);
2587 i += scnprintf(buf + i, max - i, "Node_id: 0x%08x\n",
2588 port_ptr->this_port.node_id);
2589 i += scnprintf(buf + i, max - i, "Port_id: 0x%08x\n",
2590 port_ptr->this_port.port_id);
2591 i += scnprintf(buf + i, max - i, "# pkts tx'd %d\n",
2592 port_ptr->num_tx);
2593 i += scnprintf(buf + i, max - i, "# pkts rx'd %d\n",
2594 port_ptr->num_rx);
2595 i += scnprintf(buf + i, max - i, "# bytes tx'd %ld\n",
2596 port_ptr->num_tx_bytes);
2597 i += scnprintf(buf + i, max - i, "# bytes rx'd %ld\n",
2598 port_ptr->num_rx_bytes);
2599 spin_unlock_irqrestore(&port_ptr->port_lock, flags);
2600 i += scnprintf(buf + i, max - i, "\n");
2601 }
2602 }
2603 mutex_unlock(&local_ports_lock);
2604
2605 return i;
2606}
2607
2608#define DEBUG_BUFMAX 4096
2609static char debug_buffer[DEBUG_BUFMAX];
2610
2611static ssize_t debug_read(struct file *file, char __user *buf,
2612 size_t count, loff_t *ppos)
2613{
2614 int (*fill)(char *buf, int max) = file->private_data;
2615 int bsize = fill(debug_buffer, DEBUG_BUFMAX);
2616 return simple_read_from_buffer(buf, count, ppos, debug_buffer, bsize);
2617}
2618
2619static int debug_open(struct inode *inode, struct file *file)
2620{
2621 file->private_data = inode->i_private;
2622 return 0;
2623}
2624
2625static const struct file_operations debug_ops = {
2626 .read = debug_read,
2627 .open = debug_open,
2628};
2629
2630static void debug_create(const char *name, mode_t mode,
2631 struct dentry *dent,
2632 int (*fill)(char *buf, int max))
2633{
2634 debugfs_create_file(name, mode, dent, fill, &debug_ops);
2635}
2636
2637static void debugfs_init(void)
2638{
2639 struct dentry *dent;
2640
2641 dent = debugfs_create_dir("msm_ipc_router", 0);
2642 if (IS_ERR(dent))
2643 return;
2644
2645 debug_create("dump_local_ports", 0444, dent,
2646 dump_local_ports);
2647 debug_create("dump_remote_ports", 0444, dent,
2648 dump_remote_ports);
2649 debug_create("dump_control_ports", 0444, dent,
2650 dump_control_ports);
2651 debug_create("dump_servers", 0444, dent,
2652 dump_servers);
2653 debug_create("dump_xprt_info", 0444, dent,
2654 dump_xprt_info);
2655 debug_create("dump_routing_table", 0444, dent,
2656 dump_routing_table);
2657}
2658
2659#else
2660static void debugfs_init(void) {}
2661#endif
2662
2663static int msm_ipc_router_add_xprt(struct msm_ipc_router_xprt *xprt)
2664{
2665 struct msm_ipc_router_xprt_info *xprt_info;
2666 struct msm_ipc_routing_table_entry *rt_entry;
2667
2668 xprt_info = kmalloc(sizeof(struct msm_ipc_router_xprt_info),
2669 GFP_KERNEL);
2670 if (!xprt_info)
2671 return -ENOMEM;
2672
2673 xprt_info->xprt = xprt;
2674 xprt_info->initialized = 0;
2675 xprt_info->remote_node_id = -1;
2676 INIT_LIST_HEAD(&xprt_info->pkt_list);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002677 mutex_init(&xprt_info->rx_lock);
2678 mutex_init(&xprt_info->tx_lock);
2679 wake_lock_init(&xprt_info->wakelock,
2680 WAKE_LOCK_SUSPEND, xprt->name);
2681 xprt_info->need_len = 0;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002682 xprt_info->abort_data_read = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002683 INIT_WORK(&xprt_info->read_data, do_read_data);
2684 INIT_LIST_HEAD(&xprt_info->list);
2685
2686 xprt_info->workqueue = create_singlethread_workqueue(xprt->name);
2687 if (!xprt_info->workqueue) {
2688 kfree(xprt_info);
2689 return -ENOMEM;
2690 }
2691
2692 if (!strcmp(xprt->name, "msm_ipc_router_loopback_xprt")) {
2693 xprt_info->remote_node_id = IPC_ROUTER_NID_LOCAL;
2694 xprt_info->initialized = 1;
2695 }
2696
2697 mutex_lock(&xprt_info_list_lock);
2698 list_add_tail(&xprt_info->list, &xprt_info_list);
2699 mutex_unlock(&xprt_info_list_lock);
2700
2701 mutex_lock(&routing_table_lock);
2702 if (!routing_table_inited) {
2703 init_routing_table();
2704 rt_entry = alloc_routing_table_entry(IPC_ROUTER_NID_LOCAL);
2705 add_routing_table_entry(rt_entry);
2706 routing_table_inited = 1;
2707 }
2708 mutex_unlock(&routing_table_lock);
2709
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002710 xprt->priv = xprt_info;
2711
2712 return 0;
2713}
2714
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002715static void msm_ipc_router_remove_xprt(struct msm_ipc_router_xprt *xprt)
2716{
2717 struct msm_ipc_router_xprt_info *xprt_info;
2718
2719 if (xprt && xprt->priv) {
2720 xprt_info = xprt->priv;
2721
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06002722 mutex_lock(&xprt_info->rx_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002723 xprt_info->abort_data_read = 1;
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06002724 mutex_unlock(&xprt_info->rx_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002725
2726 mutex_lock(&xprt_info_list_lock);
2727 list_del(&xprt_info->list);
2728 mutex_unlock(&xprt_info_list_lock);
2729
2730 flush_workqueue(xprt_info->workqueue);
2731 destroy_workqueue(xprt_info->workqueue);
2732 wake_lock_destroy(&xprt_info->wakelock);
2733
2734 xprt->priv = 0;
2735 kfree(xprt_info);
2736 }
2737}
2738
2739
2740struct msm_ipc_router_xprt_work {
2741 struct msm_ipc_router_xprt *xprt;
2742 struct work_struct work;
2743};
2744
2745static void xprt_open_worker(struct work_struct *work)
2746{
2747 struct msm_ipc_router_xprt_work *xprt_work =
2748 container_of(work, struct msm_ipc_router_xprt_work, work);
2749
2750 msm_ipc_router_add_xprt(xprt_work->xprt);
2751 kfree(xprt_work);
2752}
2753
2754static void xprt_close_worker(struct work_struct *work)
2755{
2756 struct msm_ipc_router_xprt_work *xprt_work =
2757 container_of(work, struct msm_ipc_router_xprt_work, work);
2758
2759 modem_reset_cleanup(xprt_work->xprt->priv);
2760 msm_ipc_router_remove_xprt(xprt_work->xprt);
Zaheerulla Meer35893a62013-06-19 16:54:44 +05302761 xprt_work->xprt->sft_close_done(xprt_work->xprt);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002762 kfree(xprt_work);
2763}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002764
2765void msm_ipc_router_xprt_notify(struct msm_ipc_router_xprt *xprt,
2766 unsigned event,
2767 void *data)
2768{
2769 struct msm_ipc_router_xprt_info *xprt_info = xprt->priv;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002770 struct msm_ipc_router_xprt_work *xprt_work;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002771 struct rr_packet *pkt;
Karthikeyan Ramasubramanian4af9f7c2011-09-30 15:55:18 -06002772 unsigned long ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002773
Karthikeyan Ramasubramanian4af9f7c2011-09-30 15:55:18 -06002774 if (!msm_ipc_router_workqueue) {
2775 ret = wait_for_completion_timeout(&msm_ipc_local_router_up,
2776 IPC_ROUTER_INIT_TIMEOUT);
2777 if (!ret || !msm_ipc_router_workqueue) {
2778 pr_err("%s: IPC Router not initialized\n", __func__);
2779 return;
2780 }
2781 }
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002782
2783 switch (event) {
2784 case IPC_ROUTER_XPRT_EVENT_OPEN:
2785 D("open event for '%s'\n", xprt->name);
2786 xprt_work = kmalloc(sizeof(struct msm_ipc_router_xprt_work),
2787 GFP_ATOMIC);
2788 xprt_work->xprt = xprt;
2789 INIT_WORK(&xprt_work->work, xprt_open_worker);
2790 queue_work(msm_ipc_router_workqueue, &xprt_work->work);
2791 break;
2792
2793 case IPC_ROUTER_XPRT_EVENT_CLOSE:
2794 D("close event for '%s'\n", xprt->name);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002795 xprt_work = kmalloc(sizeof(struct msm_ipc_router_xprt_work),
2796 GFP_ATOMIC);
2797 xprt_work->xprt = xprt;
2798 INIT_WORK(&xprt_work->work, xprt_close_worker);
2799 queue_work(msm_ipc_router_workqueue, &xprt_work->work);
2800 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002801 }
2802
2803 if (!data)
2804 return;
2805
2806 while (!xprt_info) {
2807 msleep(100);
2808 xprt_info = xprt->priv;
2809 }
2810
2811 pkt = clone_pkt((struct rr_packet *)data);
2812 if (!pkt)
2813 return;
2814
2815 mutex_lock(&xprt_info->rx_lock);
2816 list_add_tail(&pkt->list, &xprt_info->pkt_list);
2817 wake_lock(&xprt_info->wakelock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002818 mutex_unlock(&xprt_info->rx_lock);
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06002819 queue_work(xprt_info->workqueue, &xprt_info->read_data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002820}
2821
2822static int __init msm_ipc_router_init(void)
2823{
2824 int i, ret;
2825 struct msm_ipc_routing_table_entry *rt_entry;
2826
2827 msm_ipc_router_debug_mask |= SMEM_LOG;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002828 msm_ipc_router_workqueue =
2829 create_singlethread_workqueue("msm_ipc_router");
2830 if (!msm_ipc_router_workqueue)
2831 return -ENOMEM;
2832
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002833 debugfs_init();
2834
2835 for (i = 0; i < SRV_HASH_SIZE; i++)
2836 INIT_LIST_HEAD(&server_list[i]);
2837
2838 for (i = 0; i < LP_HASH_SIZE; i++)
2839 INIT_LIST_HEAD(&local_ports[i]);
2840
2841 mutex_lock(&routing_table_lock);
2842 if (!routing_table_inited) {
2843 init_routing_table();
2844 rt_entry = alloc_routing_table_entry(IPC_ROUTER_NID_LOCAL);
2845 add_routing_table_entry(rt_entry);
2846 routing_table_inited = 1;
2847 }
2848 mutex_unlock(&routing_table_lock);
2849
2850 init_waitqueue_head(&newserver_wait);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002851 ret = msm_ipc_router_init_sockets();
2852 if (ret < 0)
2853 pr_err("%s: Init sockets failed\n", __func__);
2854
Karthikeyan Ramasubramanian1668cc62012-09-23 22:23:36 -06002855 ret = msm_ipc_router_security_init();
2856 if (ret < 0)
2857 pr_err("%s: Security Init failed\n", __func__);
2858
Karthikeyan Ramasubramanian4af9f7c2011-09-30 15:55:18 -06002859 complete_all(&msm_ipc_local_router_up);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002860 return ret;
2861}
2862
2863module_init(msm_ipc_router_init);
2864MODULE_DESCRIPTION("MSM IPC Router");
2865MODULE_LICENSE("GPL v2");