blob: 1f2448def43e62191cdb2bbbf1e56f9fdd17b7c8 [file] [log] [blame]
Duy Truonge833aca2013-02-12 13:35:08 -08001/* Copyright (c) 2011-2012, 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>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070036
37#include "ipc_router.h"
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -060038#include "modem_notifier.h"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070039
40enum {
41 SMEM_LOG = 1U << 0,
42 RTR_DBG = 1U << 1,
43 R2R_MSG = 1U << 2,
44 R2R_RAW = 1U << 3,
45 NTFY_MSG = 1U << 4,
46 R2R_RAW_HDR = 1U << 5,
47};
48
49static int msm_ipc_router_debug_mask;
50module_param_named(debug_mask, msm_ipc_router_debug_mask,
51 int, S_IRUGO | S_IWUSR | S_IWGRP);
52
53#define DIAG(x...) pr_info("[RR] ERROR " x)
54
55#if defined(DEBUG)
56#define D(x...) do { \
57if (msm_ipc_router_debug_mask & RTR_DBG) \
58 pr_info(x); \
59} while (0)
60
61#define RR(x...) do { \
62if (msm_ipc_router_debug_mask & R2R_MSG) \
63 pr_info("[RR] "x); \
64} while (0)
65
66#define RAW(x...) do { \
67if (msm_ipc_router_debug_mask & R2R_RAW) \
68 pr_info("[RAW] "x); \
69} while (0)
70
71#define NTFY(x...) do { \
72if (msm_ipc_router_debug_mask & NTFY_MSG) \
73 pr_info("[NOTIFY] "x); \
74} while (0)
75
76#define RAW_HDR(x...) do { \
77if (msm_ipc_router_debug_mask & R2R_RAW_HDR) \
78 pr_info("[HDR] "x); \
79} while (0)
80#else
81#define D(x...) do { } while (0)
82#define RR(x...) do { } while (0)
83#define RAW(x...) do { } while (0)
84#define RAW_HDR(x...) do { } while (0)
85#define NTFY(x...) do { } while (0)
86#endif
87
88#define IPC_ROUTER_LOG_EVENT_ERROR 0x10
89#define IPC_ROUTER_LOG_EVENT_TX 0x11
90#define IPC_ROUTER_LOG_EVENT_RX 0x12
91
92static LIST_HEAD(control_ports);
93static DEFINE_MUTEX(control_ports_lock);
94
95#define LP_HASH_SIZE 32
96static struct list_head local_ports[LP_HASH_SIZE];
97static DEFINE_MUTEX(local_ports_lock);
98
99#define SRV_HASH_SIZE 32
100static struct list_head server_list[SRV_HASH_SIZE];
101static DEFINE_MUTEX(server_list_lock);
102static wait_queue_head_t newserver_wait;
103
104struct msm_ipc_server {
105 struct list_head list;
106 struct msm_ipc_port_name name;
107 struct list_head server_port_list;
108};
109
110struct msm_ipc_server_port {
111 struct list_head list;
112 struct msm_ipc_port_addr server_addr;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600113 struct msm_ipc_router_xprt_info *xprt_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700114};
115
116#define RP_HASH_SIZE 32
117struct msm_ipc_router_remote_port {
118 struct list_head list;
119 uint32_t node_id;
120 uint32_t port_id;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600121 uint32_t restart_state;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700122 wait_queue_head_t quota_wait;
123 uint32_t tx_quota_cnt;
124 struct mutex quota_lock;
125};
126
127struct msm_ipc_router_xprt_info {
128 struct list_head list;
129 struct msm_ipc_router_xprt *xprt;
130 uint32_t remote_node_id;
131 uint32_t initialized;
132 struct list_head pkt_list;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700133 struct wake_lock wakelock;
134 struct mutex rx_lock;
135 struct mutex tx_lock;
136 uint32_t need_len;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600137 uint32_t abort_data_read;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700138 struct work_struct read_data;
139 struct workqueue_struct *workqueue;
140};
141
142#define RT_HASH_SIZE 4
143struct msm_ipc_routing_table_entry {
144 struct list_head list;
145 uint32_t node_id;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600146 uint32_t neighbor_node_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700147 struct list_head remote_port_list[RP_HASH_SIZE];
148 struct msm_ipc_router_xprt_info *xprt_info;
149 struct mutex lock;
150 unsigned long num_tx_bytes;
151 unsigned long num_rx_bytes;
152};
153
154static struct list_head routing_table[RT_HASH_SIZE];
155static DEFINE_MUTEX(routing_table_lock);
156static int routing_table_inited;
157
158static LIST_HEAD(msm_ipc_board_dev_list);
159static DEFINE_MUTEX(msm_ipc_board_dev_list_lock);
160
161static void do_read_data(struct work_struct *work);
162
163#define RR_STATE_IDLE 0
164#define RR_STATE_HEADER 1
165#define RR_STATE_BODY 2
166#define RR_STATE_ERROR 3
167
168#define RESTART_NORMAL 0
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600169#define RESTART_PEND 1
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700170
171/* State for remote ep following restart */
172#define RESTART_QUOTA_ABORT 1
173
174static LIST_HEAD(xprt_info_list);
175static DEFINE_MUTEX(xprt_info_list_lock);
176
Karthikeyan Ramasubramanian4af9f7c2011-09-30 15:55:18 -0600177static DECLARE_COMPLETION(msm_ipc_local_router_up);
178#define IPC_ROUTER_INIT_TIMEOUT (10 * HZ)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700179
180static uint32_t next_port_id;
181static DEFINE_MUTEX(next_port_id_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600182static atomic_t pending_close_count = ATOMIC_INIT(0);
183static wait_queue_head_t subsystem_restart_wait;
184static struct workqueue_struct *msm_ipc_router_workqueue;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700185
186enum {
187 CLIENT_PORT,
188 SERVER_PORT,
189 CONTROL_PORT,
190};
191
192enum {
193 DOWN,
194 UP,
195};
196
197static void init_routing_table(void)
198{
199 int i;
200 for (i = 0; i < RT_HASH_SIZE; i++)
201 INIT_LIST_HEAD(&routing_table[i]);
202}
203
204static struct msm_ipc_routing_table_entry *alloc_routing_table_entry(
205 uint32_t node_id)
206{
207 int i;
208 struct msm_ipc_routing_table_entry *rt_entry;
209
210 rt_entry = kmalloc(sizeof(struct msm_ipc_routing_table_entry),
211 GFP_KERNEL);
212 if (!rt_entry) {
213 pr_err("%s: rt_entry allocation failed for %d\n",
214 __func__, node_id);
215 return NULL;
216 }
217
218 for (i = 0; i < RP_HASH_SIZE; i++)
219 INIT_LIST_HEAD(&rt_entry->remote_port_list[i]);
220
221 mutex_init(&rt_entry->lock);
222 rt_entry->node_id = node_id;
223 rt_entry->xprt_info = NULL;
224 return rt_entry;
225}
226
227/*Please take routing_table_lock before calling this function*/
228static int add_routing_table_entry(
229 struct msm_ipc_routing_table_entry *rt_entry)
230{
231 uint32_t key;
232
233 if (!rt_entry)
234 return -EINVAL;
235
236 key = (rt_entry->node_id % RT_HASH_SIZE);
237 list_add_tail(&rt_entry->list, &routing_table[key]);
238 return 0;
239}
240
241/*Please take routing_table_lock before calling this function*/
242static struct msm_ipc_routing_table_entry *lookup_routing_table(
243 uint32_t node_id)
244{
245 uint32_t key = (node_id % RT_HASH_SIZE);
246 struct msm_ipc_routing_table_entry *rt_entry;
247
248 list_for_each_entry(rt_entry, &routing_table[key], list) {
249 if (rt_entry->node_id == node_id)
250 return rt_entry;
251 }
252 return NULL;
253}
254
255struct rr_packet *rr_read(struct msm_ipc_router_xprt_info *xprt_info)
256{
257 struct rr_packet *temp_pkt;
258
259 if (!xprt_info)
260 return NULL;
261
262 mutex_lock(&xprt_info->rx_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600263 if (xprt_info->abort_data_read) {
264 mutex_unlock(&xprt_info->rx_lock);
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -0600265 pr_err("%s detected SSR & exiting now\n",
266 xprt_info->xprt->name);
267 return NULL;
268 }
269
270 if (list_empty(&xprt_info->pkt_list)) {
271 mutex_unlock(&xprt_info->rx_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600272 return NULL;
273 }
274
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700275 temp_pkt = list_first_entry(&xprt_info->pkt_list,
276 struct rr_packet, list);
277 list_del(&temp_pkt->list);
278 if (list_empty(&xprt_info->pkt_list))
279 wake_unlock(&xprt_info->wakelock);
280 mutex_unlock(&xprt_info->rx_lock);
281 return temp_pkt;
282}
283
284struct rr_packet *clone_pkt(struct rr_packet *pkt)
285{
286 struct rr_packet *cloned_pkt;
287 struct sk_buff *temp_skb, *cloned_skb;
288 struct sk_buff_head *pkt_fragment_q;
289
290 cloned_pkt = kzalloc(sizeof(struct rr_packet), GFP_KERNEL);
291 if (!cloned_pkt) {
292 pr_err("%s: failure\n", __func__);
293 return NULL;
294 }
295
296 pkt_fragment_q = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
297 if (!pkt_fragment_q) {
298 pr_err("%s: pkt_frag_q alloc failure\n", __func__);
299 kfree(cloned_pkt);
300 return NULL;
301 }
302 skb_queue_head_init(pkt_fragment_q);
303
304 skb_queue_walk(pkt->pkt_fragment_q, temp_skb) {
305 cloned_skb = skb_clone(temp_skb, GFP_KERNEL);
306 if (!cloned_skb)
307 goto fail_clone;
308 skb_queue_tail(pkt_fragment_q, cloned_skb);
309 }
310 cloned_pkt->pkt_fragment_q = pkt_fragment_q;
311 cloned_pkt->length = pkt->length;
312 return cloned_pkt;
313
314fail_clone:
315 while (!skb_queue_empty(pkt_fragment_q)) {
316 temp_skb = skb_dequeue(pkt_fragment_q);
317 kfree_skb(temp_skb);
318 }
319 kfree(pkt_fragment_q);
320 kfree(cloned_pkt);
321 return NULL;
322}
323
324struct rr_packet *create_pkt(struct sk_buff_head *data)
325{
326 struct rr_packet *pkt;
327 struct sk_buff *temp_skb;
328
329 pkt = kzalloc(sizeof(struct rr_packet), GFP_KERNEL);
330 if (!pkt) {
331 pr_err("%s: failure\n", __func__);
332 return NULL;
333 }
334
335 pkt->pkt_fragment_q = data;
336 skb_queue_walk(pkt->pkt_fragment_q, temp_skb)
337 pkt->length += temp_skb->len;
338 return pkt;
339}
340
341void release_pkt(struct rr_packet *pkt)
342{
343 struct sk_buff *temp_skb;
344
345 if (!pkt)
346 return;
347
348 if (!pkt->pkt_fragment_q) {
349 kfree(pkt);
350 return;
351 }
352
353 while (!skb_queue_empty(pkt->pkt_fragment_q)) {
354 temp_skb = skb_dequeue(pkt->pkt_fragment_q);
355 kfree_skb(temp_skb);
356 }
357 kfree(pkt->pkt_fragment_q);
358 kfree(pkt);
359 return;
360}
361
362static int post_control_ports(struct rr_packet *pkt)
363{
364 struct msm_ipc_port *port_ptr;
365 struct rr_packet *cloned_pkt;
366
367 if (!pkt)
368 return -EINVAL;
369
370 mutex_lock(&control_ports_lock);
371 list_for_each_entry(port_ptr, &control_ports, list) {
372 mutex_lock(&port_ptr->port_rx_q_lock);
373 cloned_pkt = clone_pkt(pkt);
374 wake_lock(&port_ptr->port_rx_wake_lock);
375 list_add_tail(&cloned_pkt->list, &port_ptr->port_rx_q);
376 wake_up(&port_ptr->port_rx_wait_q);
377 mutex_unlock(&port_ptr->port_rx_q_lock);
378 }
379 mutex_unlock(&control_ports_lock);
380 return 0;
381}
382
383static uint32_t allocate_port_id(void)
384{
385 uint32_t port_id = 0, prev_port_id, key;
386 struct msm_ipc_port *port_ptr;
387
388 mutex_lock(&next_port_id_lock);
389 prev_port_id = next_port_id;
390 mutex_lock(&local_ports_lock);
391 do {
392 next_port_id++;
393 if ((next_port_id & 0xFFFFFFFE) == 0xFFFFFFFE)
394 next_port_id = 1;
395
396 key = (next_port_id & (LP_HASH_SIZE - 1));
397 if (list_empty(&local_ports[key])) {
398 port_id = next_port_id;
399 break;
400 }
401 list_for_each_entry(port_ptr, &local_ports[key], list) {
402 if (port_ptr->this_port.port_id == next_port_id) {
403 port_id = next_port_id;
404 break;
405 }
406 }
407 if (!port_id) {
408 port_id = next_port_id;
409 break;
410 }
411 port_id = 0;
412 } while (next_port_id != prev_port_id);
413 mutex_unlock(&local_ports_lock);
414 mutex_unlock(&next_port_id_lock);
415
416 return port_id;
417}
418
419void msm_ipc_router_add_local_port(struct msm_ipc_port *port_ptr)
420{
421 uint32_t key;
422
423 if (!port_ptr)
424 return;
425
426 key = (port_ptr->this_port.port_id & (LP_HASH_SIZE - 1));
427 mutex_lock(&local_ports_lock);
428 list_add_tail(&port_ptr->list, &local_ports[key]);
429 mutex_unlock(&local_ports_lock);
430}
431
432struct msm_ipc_port *msm_ipc_router_create_raw_port(void *endpoint,
433 void (*notify)(unsigned event, void *data,
434 void *addr, void *priv),
435 void *priv)
436{
437 struct msm_ipc_port *port_ptr;
438
439 port_ptr = kzalloc(sizeof(struct msm_ipc_port), GFP_KERNEL);
440 if (!port_ptr)
441 return NULL;
442
443 port_ptr->this_port.node_id = IPC_ROUTER_NID_LOCAL;
444 port_ptr->this_port.port_id = allocate_port_id();
445 if (!port_ptr->this_port.port_id) {
446 pr_err("%s: All port ids are in use\n", __func__);
447 kfree(port_ptr);
448 return NULL;
449 }
450
451 spin_lock_init(&port_ptr->port_lock);
452 INIT_LIST_HEAD(&port_ptr->incomplete);
453 mutex_init(&port_ptr->incomplete_lock);
454 INIT_LIST_HEAD(&port_ptr->port_rx_q);
455 mutex_init(&port_ptr->port_rx_q_lock);
456 init_waitqueue_head(&port_ptr->port_rx_wait_q);
Karthikeyan Ramasubramanianb4aeeb92012-03-13 12:31:43 -0600457 snprintf(port_ptr->rx_wakelock_name, MAX_WAKELOCK_NAME_SZ,
458 "msm_ipc_read%08x:%08x",
459 port_ptr->this_port.node_id,
460 port_ptr->this_port.port_id);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700461 wake_lock_init(&port_ptr->port_rx_wake_lock,
Karthikeyan Ramasubramanianb4aeeb92012-03-13 12:31:43 -0600462 WAKE_LOCK_SUSPEND, port_ptr->rx_wakelock_name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700463
464 port_ptr->endpoint = endpoint;
465 port_ptr->notify = notify;
466 port_ptr->priv = priv;
467
468 msm_ipc_router_add_local_port(port_ptr);
469 return port_ptr;
470}
471
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -0600472/*
473 * Should be called with local_ports_lock locked
474 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700475static struct msm_ipc_port *msm_ipc_router_lookup_local_port(uint32_t port_id)
476{
477 int key = (port_id & (LP_HASH_SIZE - 1));
478 struct msm_ipc_port *port_ptr;
479
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700480 list_for_each_entry(port_ptr, &local_ports[key], list) {
481 if (port_ptr->this_port.port_id == port_id) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700482 return port_ptr;
483 }
484 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700485 return NULL;
486}
487
488static struct msm_ipc_router_remote_port *msm_ipc_router_lookup_remote_port(
489 uint32_t node_id,
490 uint32_t port_id)
491{
492 struct msm_ipc_router_remote_port *rport_ptr;
493 struct msm_ipc_routing_table_entry *rt_entry;
494 int key = (port_id & (RP_HASH_SIZE - 1));
495
496 mutex_lock(&routing_table_lock);
497 rt_entry = lookup_routing_table(node_id);
498 if (!rt_entry) {
499 mutex_unlock(&routing_table_lock);
500 pr_err("%s: Node is not up\n", __func__);
501 return NULL;
502 }
503
504 mutex_lock(&rt_entry->lock);
505 list_for_each_entry(rport_ptr,
506 &rt_entry->remote_port_list[key], list) {
507 if (rport_ptr->port_id == port_id) {
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600508 if (rport_ptr->restart_state != RESTART_NORMAL)
509 rport_ptr = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700510 mutex_unlock(&rt_entry->lock);
511 mutex_unlock(&routing_table_lock);
512 return rport_ptr;
513 }
514 }
515 mutex_unlock(&rt_entry->lock);
516 mutex_unlock(&routing_table_lock);
517 return NULL;
518}
519
520static struct msm_ipc_router_remote_port *msm_ipc_router_create_remote_port(
521 uint32_t node_id,
522 uint32_t port_id)
523{
524 struct msm_ipc_router_remote_port *rport_ptr;
525 struct msm_ipc_routing_table_entry *rt_entry;
526 int key = (port_id & (RP_HASH_SIZE - 1));
527
528 mutex_lock(&routing_table_lock);
529 rt_entry = lookup_routing_table(node_id);
530 if (!rt_entry) {
531 mutex_unlock(&routing_table_lock);
532 pr_err("%s: Node is not up\n", __func__);
533 return NULL;
534 }
535
536 mutex_lock(&rt_entry->lock);
537 rport_ptr = kmalloc(sizeof(struct msm_ipc_router_remote_port),
538 GFP_KERNEL);
539 if (!rport_ptr) {
540 mutex_unlock(&rt_entry->lock);
541 mutex_unlock(&routing_table_lock);
542 pr_err("%s: Remote port alloc failed\n", __func__);
543 return NULL;
544 }
545 rport_ptr->port_id = port_id;
546 rport_ptr->node_id = node_id;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600547 rport_ptr->restart_state = RESTART_NORMAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700548 rport_ptr->tx_quota_cnt = 0;
549 init_waitqueue_head(&rport_ptr->quota_wait);
550 mutex_init(&rport_ptr->quota_lock);
551 list_add_tail(&rport_ptr->list,
552 &rt_entry->remote_port_list[key]);
553 mutex_unlock(&rt_entry->lock);
554 mutex_unlock(&routing_table_lock);
555 return rport_ptr;
556}
557
558static void msm_ipc_router_destroy_remote_port(
559 struct msm_ipc_router_remote_port *rport_ptr)
560{
561 uint32_t node_id;
562 struct msm_ipc_routing_table_entry *rt_entry;
563
564 if (!rport_ptr)
565 return;
566
567 node_id = rport_ptr->node_id;
568 mutex_lock(&routing_table_lock);
569 rt_entry = lookup_routing_table(node_id);
570 if (!rt_entry) {
571 mutex_unlock(&routing_table_lock);
572 pr_err("%s: Node %d is not up\n", __func__, node_id);
573 return;
574 }
575
576 mutex_lock(&rt_entry->lock);
577 list_del(&rport_ptr->list);
578 kfree(rport_ptr);
579 mutex_unlock(&rt_entry->lock);
580 mutex_unlock(&routing_table_lock);
581 return;
582}
583
584static struct msm_ipc_server *msm_ipc_router_lookup_server(
585 uint32_t service,
586 uint32_t instance,
587 uint32_t node_id,
588 uint32_t port_id)
589{
590 struct msm_ipc_server *server;
591 struct msm_ipc_server_port *server_port;
592 int key = (instance & (SRV_HASH_SIZE - 1));
593
594 mutex_lock(&server_list_lock);
595 list_for_each_entry(server, &server_list[key], list) {
596 if ((server->name.service != service) ||
597 (server->name.instance != instance))
598 continue;
599 if ((node_id == 0) && (port_id == 0)) {
600 mutex_unlock(&server_list_lock);
601 return server;
602 }
603 list_for_each_entry(server_port, &server->server_port_list,
604 list) {
605 if ((server_port->server_addr.node_id == node_id) &&
606 (server_port->server_addr.port_id == port_id)) {
607 mutex_unlock(&server_list_lock);
608 return server;
609 }
610 }
611 }
612 mutex_unlock(&server_list_lock);
613 return NULL;
614}
615
616static struct msm_ipc_server *msm_ipc_router_create_server(
617 uint32_t service,
618 uint32_t instance,
619 uint32_t node_id,
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600620 uint32_t port_id,
621 struct msm_ipc_router_xprt_info *xprt_info)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700622{
623 struct msm_ipc_server *server = NULL;
624 struct msm_ipc_server_port *server_port;
625 int key = (instance & (SRV_HASH_SIZE - 1));
626
627 mutex_lock(&server_list_lock);
628 list_for_each_entry(server, &server_list[key], list) {
629 if ((server->name.service == service) &&
630 (server->name.instance == instance))
631 goto create_srv_port;
632 }
633
634 server = kmalloc(sizeof(struct msm_ipc_server), GFP_KERNEL);
635 if (!server) {
636 mutex_unlock(&server_list_lock);
637 pr_err("%s: Server allocation failed\n", __func__);
638 return NULL;
639 }
640 server->name.service = service;
641 server->name.instance = instance;
642 INIT_LIST_HEAD(&server->server_port_list);
643 list_add_tail(&server->list, &server_list[key]);
644
645create_srv_port:
646 server_port = kmalloc(sizeof(struct msm_ipc_server_port), GFP_KERNEL);
647 if (!server_port) {
648 if (list_empty(&server->server_port_list)) {
649 list_del(&server->list);
650 kfree(server);
651 }
652 mutex_unlock(&server_list_lock);
653 pr_err("%s: Server Port allocation failed\n", __func__);
654 return NULL;
655 }
656 server_port->server_addr.node_id = node_id;
657 server_port->server_addr.port_id = port_id;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600658 server_port->xprt_info = xprt_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700659 list_add_tail(&server_port->list, &server->server_port_list);
660 mutex_unlock(&server_list_lock);
661
662 return server;
663}
664
665static void msm_ipc_router_destroy_server(struct msm_ipc_server *server,
666 uint32_t node_id, uint32_t port_id)
667{
668 struct msm_ipc_server_port *server_port;
669
670 if (!server)
671 return;
672
673 mutex_lock(&server_list_lock);
674 list_for_each_entry(server_port, &server->server_port_list, list) {
675 if ((server_port->server_addr.node_id == node_id) &&
676 (server_port->server_addr.port_id == port_id))
677 break;
678 }
679 if (server_port) {
680 list_del(&server_port->list);
681 kfree(server_port);
682 }
683 if (list_empty(&server->server_port_list)) {
684 list_del(&server->list);
685 kfree(server);
686 }
687 mutex_unlock(&server_list_lock);
688 return;
689}
690
691static int msm_ipc_router_send_control_msg(
692 struct msm_ipc_router_xprt_info *xprt_info,
693 union rr_control_msg *msg)
694{
695 struct rr_packet *pkt;
696 struct sk_buff *ipc_rtr_pkt;
697 struct rr_header *hdr;
698 int pkt_size;
699 void *data;
700 struct sk_buff_head *pkt_fragment_q;
701 int ret;
702
703 if (!xprt_info || ((msg->cmd != IPC_ROUTER_CTRL_CMD_HELLO) &&
704 !xprt_info->initialized)) {
705 pr_err("%s: xprt_info not initialized\n", __func__);
706 return -EINVAL;
707 }
708
709 if (xprt_info->remote_node_id == IPC_ROUTER_NID_LOCAL)
710 return 0;
711
712 pkt = kzalloc(sizeof(struct rr_packet), GFP_KERNEL);
713 if (!pkt) {
714 pr_err("%s: pkt alloc failed\n", __func__);
715 return -ENOMEM;
716 }
717
718 pkt_fragment_q = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
719 if (!pkt_fragment_q) {
720 pr_err("%s: pkt_fragment_q alloc failed\n", __func__);
721 kfree(pkt);
722 return -ENOMEM;
723 }
724 skb_queue_head_init(pkt_fragment_q);
725
726 pkt_size = IPC_ROUTER_HDR_SIZE + sizeof(*msg);
727 ipc_rtr_pkt = alloc_skb(pkt_size, GFP_KERNEL);
728 if (!ipc_rtr_pkt) {
729 pr_err("%s: ipc_rtr_pkt alloc failed\n", __func__);
730 kfree(pkt_fragment_q);
731 kfree(pkt);
732 return -ENOMEM;
733 }
734
735 skb_reserve(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
736 data = skb_put(ipc_rtr_pkt, sizeof(*msg));
737 memcpy(data, msg, sizeof(*msg));
738 hdr = (struct rr_header *)skb_push(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
739 if (!hdr) {
740 pr_err("%s: skb_push failed\n", __func__);
741 kfree_skb(ipc_rtr_pkt);
742 kfree(pkt_fragment_q);
743 kfree(pkt);
744 return -ENOMEM;
745 }
746
747 hdr->version = IPC_ROUTER_VERSION;
748 hdr->type = msg->cmd;
749 hdr->src_node_id = IPC_ROUTER_NID_LOCAL;
750 hdr->src_port_id = IPC_ROUTER_ADDRESS;
751 hdr->confirm_rx = 0;
752 hdr->size = sizeof(*msg);
753 hdr->dst_node_id = xprt_info->remote_node_id;
754 hdr->dst_port_id = IPC_ROUTER_ADDRESS;
755 skb_queue_tail(pkt_fragment_q, ipc_rtr_pkt);
756 pkt->pkt_fragment_q = pkt_fragment_q;
757 pkt->length = pkt_size;
758
759 mutex_lock(&xprt_info->tx_lock);
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700760 ret = xprt_info->xprt->write(pkt, pkt_size, xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700761 mutex_unlock(&xprt_info->tx_lock);
762
763 release_pkt(pkt);
764 return ret;
765}
766
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -0600767static int msm_ipc_router_send_server_list(uint32_t node_id,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700768 struct msm_ipc_router_xprt_info *xprt_info)
769{
770 union rr_control_msg ctl;
771 struct msm_ipc_server *server;
772 struct msm_ipc_server_port *server_port;
773 int i;
774
775 if (!xprt_info || !xprt_info->initialized) {
776 pr_err("%s: Xprt info not initialized\n", __func__);
777 return -EINVAL;
778 }
779
780 ctl.cmd = IPC_ROUTER_CTRL_CMD_NEW_SERVER;
781
782 mutex_lock(&server_list_lock);
783 for (i = 0; i < SRV_HASH_SIZE; i++) {
784 list_for_each_entry(server, &server_list[i], list) {
785 ctl.srv.service = server->name.service;
786 ctl.srv.instance = server->name.instance;
787 list_for_each_entry(server_port,
788 &server->server_port_list, list) {
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -0600789 if (server_port->server_addr.node_id !=
790 node_id)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700791 continue;
792
793 ctl.srv.node_id =
794 server_port->server_addr.node_id;
795 ctl.srv.port_id =
796 server_port->server_addr.port_id;
797 msm_ipc_router_send_control_msg(xprt_info,
798 &ctl);
799 }
800 }
801 }
802 mutex_unlock(&server_list_lock);
803
804 return 0;
805}
806
807#if defined(DEBUG)
808static char *type_to_str(int i)
809{
810 switch (i) {
811 case IPC_ROUTER_CTRL_CMD_DATA:
812 return "data ";
813 case IPC_ROUTER_CTRL_CMD_HELLO:
814 return "hello ";
815 case IPC_ROUTER_CTRL_CMD_BYE:
816 return "bye ";
817 case IPC_ROUTER_CTRL_CMD_NEW_SERVER:
818 return "new_srvr";
819 case IPC_ROUTER_CTRL_CMD_REMOVE_SERVER:
820 return "rmv_srvr";
821 case IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT:
822 return "rmv_clnt";
823 case IPC_ROUTER_CTRL_CMD_RESUME_TX:
824 return "resum_tx";
825 case IPC_ROUTER_CTRL_CMD_EXIT:
826 return "cmd_exit";
827 default:
828 return "invalid";
829 }
830}
831#endif
832
833static int broadcast_ctl_msg_locally(union rr_control_msg *msg)
834{
835 struct rr_packet *pkt;
836 struct sk_buff *ipc_rtr_pkt;
837 struct rr_header *hdr;
838 int pkt_size;
839 void *data;
840 struct sk_buff_head *pkt_fragment_q;
841 int ret;
842
843 pkt = kzalloc(sizeof(struct rr_packet), GFP_KERNEL);
844 if (!pkt) {
845 pr_err("%s: pkt alloc failed\n", __func__);
846 return -ENOMEM;
847 }
848
849 pkt_fragment_q = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
850 if (!pkt_fragment_q) {
851 pr_err("%s: pkt_fragment_q alloc failed\n", __func__);
852 kfree(pkt);
853 return -ENOMEM;
854 }
855 skb_queue_head_init(pkt_fragment_q);
856
857 pkt_size = IPC_ROUTER_HDR_SIZE + sizeof(*msg);
858 ipc_rtr_pkt = alloc_skb(pkt_size, GFP_KERNEL);
859 if (!ipc_rtr_pkt) {
860 pr_err("%s: ipc_rtr_pkt alloc failed\n", __func__);
861 kfree(pkt_fragment_q);
862 kfree(pkt);
863 return -ENOMEM;
864 }
865
866 skb_reserve(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
867 data = skb_put(ipc_rtr_pkt, sizeof(*msg));
868 memcpy(data, msg, sizeof(*msg));
869 hdr = (struct rr_header *)skb_push(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
870 if (!hdr) {
871 pr_err("%s: skb_push failed\n", __func__);
872 kfree_skb(ipc_rtr_pkt);
873 kfree(pkt_fragment_q);
874 kfree(pkt);
875 return -ENOMEM;
876 }
877 hdr->version = IPC_ROUTER_VERSION;
878 hdr->type = msg->cmd;
879 hdr->src_node_id = IPC_ROUTER_NID_LOCAL;
880 hdr->src_port_id = IPC_ROUTER_ADDRESS;
881 hdr->confirm_rx = 0;
882 hdr->size = sizeof(*msg);
883 hdr->dst_node_id = IPC_ROUTER_NID_LOCAL;
884 hdr->dst_port_id = IPC_ROUTER_ADDRESS;
885 skb_queue_tail(pkt_fragment_q, ipc_rtr_pkt);
886 pkt->pkt_fragment_q = pkt_fragment_q;
887 pkt->length = pkt_size;
888
889 ret = post_control_ports(pkt);
890 release_pkt(pkt);
891 return ret;
892}
893
894static int broadcast_ctl_msg(union rr_control_msg *ctl)
895{
896 struct msm_ipc_router_xprt_info *xprt_info;
897
898 mutex_lock(&xprt_info_list_lock);
899 list_for_each_entry(xprt_info, &xprt_info_list, list) {
900 msm_ipc_router_send_control_msg(xprt_info, ctl);
901 }
902 mutex_unlock(&xprt_info_list_lock);
903
904 return 0;
905}
906
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600907static int relay_ctl_msg(struct msm_ipc_router_xprt_info *xprt_info,
908 union rr_control_msg *ctl)
909{
910 struct msm_ipc_router_xprt_info *fwd_xprt_info;
911
912 if (!xprt_info || !ctl)
913 return -EINVAL;
914
915 mutex_lock(&xprt_info_list_lock);
916 list_for_each_entry(fwd_xprt_info, &xprt_info_list, list) {
917 if (xprt_info->xprt->link_id != fwd_xprt_info->xprt->link_id)
918 msm_ipc_router_send_control_msg(fwd_xprt_info, ctl);
919 }
920 mutex_unlock(&xprt_info_list_lock);
921
922 return 0;
923}
924
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700925static int relay_msg(struct msm_ipc_router_xprt_info *xprt_info,
926 struct rr_packet *pkt)
927{
928 struct msm_ipc_router_xprt_info *fwd_xprt_info;
929
930 if (!xprt_info || !pkt)
931 return -EINVAL;
932
933 mutex_lock(&xprt_info_list_lock);
934 list_for_each_entry(fwd_xprt_info, &xprt_info_list, list) {
935 mutex_lock(&fwd_xprt_info->tx_lock);
936 if (xprt_info->xprt->link_id != fwd_xprt_info->xprt->link_id)
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700937 fwd_xprt_info->xprt->write(pkt, pkt->length,
938 fwd_xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700939 mutex_unlock(&fwd_xprt_info->tx_lock);
940 }
941 mutex_unlock(&xprt_info_list_lock);
942 return 0;
943}
944
945static int forward_msg(struct msm_ipc_router_xprt_info *xprt_info,
946 struct rr_packet *pkt)
947{
948 uint32_t dst_node_id;
949 struct sk_buff *head_pkt;
950 struct rr_header *hdr;
951 struct msm_ipc_router_xprt_info *fwd_xprt_info;
952 struct msm_ipc_routing_table_entry *rt_entry;
953
954 if (!xprt_info || !pkt)
955 return -EINVAL;
956
957 head_pkt = skb_peek(pkt->pkt_fragment_q);
958 if (!head_pkt)
959 return -EINVAL;
960
961 hdr = (struct rr_header *)head_pkt->data;
962 dst_node_id = hdr->dst_node_id;
963 mutex_lock(&routing_table_lock);
964 rt_entry = lookup_routing_table(dst_node_id);
965 if (!(rt_entry) || !(rt_entry->xprt_info)) {
966 mutex_unlock(&routing_table_lock);
967 pr_err("%s: Routing table not initialized\n", __func__);
968 return -ENODEV;
969 }
970
971 mutex_lock(&rt_entry->lock);
972 fwd_xprt_info = rt_entry->xprt_info;
973 mutex_lock(&fwd_xprt_info->tx_lock);
974 if (xprt_info->remote_node_id == fwd_xprt_info->remote_node_id) {
975 mutex_unlock(&fwd_xprt_info->tx_lock);
976 mutex_unlock(&rt_entry->lock);
977 mutex_unlock(&routing_table_lock);
978 pr_err("%s: Discarding Command to route back\n", __func__);
979 return -EINVAL;
980 }
981
982 if (xprt_info->xprt->link_id == fwd_xprt_info->xprt->link_id) {
983 mutex_unlock(&fwd_xprt_info->tx_lock);
984 mutex_unlock(&rt_entry->lock);
985 mutex_unlock(&routing_table_lock);
986 pr_err("%s: DST in the same cluster\n", __func__);
987 return 0;
988 }
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700989 fwd_xprt_info->xprt->write(pkt, pkt->length, fwd_xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700990 mutex_unlock(&fwd_xprt_info->tx_lock);
991 mutex_unlock(&rt_entry->lock);
992 mutex_unlock(&routing_table_lock);
993
994 return 0;
995}
996
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600997static void reset_remote_port_info(uint32_t node_id, uint32_t port_id)
998{
999 struct msm_ipc_router_remote_port *rport_ptr;
1000
1001 rport_ptr = msm_ipc_router_lookup_remote_port(node_id, port_id);
1002 if (!rport_ptr) {
1003 pr_err("%s: No such remote port %08x:%08x\n",
1004 __func__, node_id, port_id);
1005 return;
1006 }
1007 mutex_lock(&rport_ptr->quota_lock);
1008 rport_ptr->restart_state = RESTART_PEND;
1009 wake_up(&rport_ptr->quota_wait);
1010 mutex_unlock(&rport_ptr->quota_lock);
1011 return;
1012}
1013
1014static void msm_ipc_cleanup_remote_server_info(
1015 struct msm_ipc_router_xprt_info *xprt_info)
1016{
1017 struct msm_ipc_server *svr, *tmp_svr;
1018 struct msm_ipc_server_port *svr_port, *tmp_svr_port;
1019 int i;
1020 union rr_control_msg ctl;
1021
1022 if (!xprt_info) {
1023 pr_err("%s: Invalid xprt_info\n", __func__);
1024 return;
1025 }
1026
1027 ctl.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_SERVER;
1028 mutex_lock(&server_list_lock);
1029 for (i = 0; i < SRV_HASH_SIZE; i++) {
1030 list_for_each_entry_safe(svr, tmp_svr, &server_list[i], list) {
1031 ctl.srv.service = svr->name.service;
1032 ctl.srv.instance = svr->name.instance;
1033 list_for_each_entry_safe(svr_port, tmp_svr_port,
1034 &svr->server_port_list, list) {
1035 if (svr_port->xprt_info != xprt_info)
1036 continue;
1037 D("Remove server %08x:%08x - %08x:%08x",
1038 ctl.srv.service, ctl.srv.instance,
1039 svr_port->server_addr.node_id,
1040 svr_port->server_addr.port_id);
1041 reset_remote_port_info(
1042 svr_port->server_addr.node_id,
1043 svr_port->server_addr.port_id);
1044 ctl.srv.node_id = svr_port->server_addr.node_id;
1045 ctl.srv.port_id = svr_port->server_addr.port_id;
1046 relay_ctl_msg(xprt_info, &ctl);
1047 broadcast_ctl_msg_locally(&ctl);
1048 list_del(&svr_port->list);
1049 kfree(svr_port);
1050 }
1051 if (list_empty(&svr->server_port_list)) {
1052 list_del(&svr->list);
1053 kfree(svr);
1054 }
1055 }
1056 }
1057 mutex_unlock(&server_list_lock);
1058}
1059
1060static void msm_ipc_cleanup_remote_client_info(
1061 struct msm_ipc_router_xprt_info *xprt_info)
1062{
1063 struct msm_ipc_routing_table_entry *rt_entry;
1064 struct msm_ipc_router_remote_port *rport_ptr;
1065 int i, j;
1066 union rr_control_msg ctl;
1067
1068 if (!xprt_info) {
1069 pr_err("%s: Invalid xprt_info\n", __func__);
1070 return;
1071 }
1072
1073 ctl.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT;
1074 mutex_lock(&routing_table_lock);
1075 for (i = 0; i < RT_HASH_SIZE; i++) {
1076 list_for_each_entry(rt_entry, &routing_table[i], list) {
1077 mutex_lock(&rt_entry->lock);
1078 if (rt_entry->xprt_info != xprt_info) {
1079 mutex_unlock(&rt_entry->lock);
1080 continue;
1081 }
1082 for (j = 0; j < RP_HASH_SIZE; j++) {
1083 list_for_each_entry(rport_ptr,
1084 &rt_entry->remote_port_list[j], list) {
1085 if (rport_ptr->restart_state ==
1086 RESTART_PEND)
1087 continue;
1088 mutex_lock(&rport_ptr->quota_lock);
1089 rport_ptr->restart_state = RESTART_PEND;
1090 wake_up(&rport_ptr->quota_wait);
1091 mutex_unlock(&rport_ptr->quota_lock);
1092 ctl.cli.node_id = rport_ptr->node_id;
1093 ctl.cli.port_id = rport_ptr->port_id;
1094 broadcast_ctl_msg_locally(&ctl);
1095 }
1096 }
1097 mutex_unlock(&rt_entry->lock);
1098 }
1099 }
1100 mutex_unlock(&routing_table_lock);
1101}
1102
1103static void msm_ipc_cleanup_remote_port_info(uint32_t node_id)
1104{
1105 struct msm_ipc_routing_table_entry *rt_entry, *tmp_rt_entry;
1106 struct msm_ipc_router_remote_port *rport_ptr, *tmp_rport_ptr;
1107 int i, j;
1108
1109 mutex_lock(&routing_table_lock);
1110 for (i = 0; i < RT_HASH_SIZE; i++) {
1111 list_for_each_entry_safe(rt_entry, tmp_rt_entry,
1112 &routing_table[i], list) {
1113 mutex_lock(&rt_entry->lock);
1114 if (rt_entry->neighbor_node_id != node_id) {
1115 mutex_unlock(&rt_entry->lock);
1116 continue;
1117 }
1118 for (j = 0; j < RP_HASH_SIZE; j++) {
1119 list_for_each_entry_safe(rport_ptr,
1120 tmp_rport_ptr,
1121 &rt_entry->remote_port_list[j], list) {
1122 list_del(&rport_ptr->list);
1123 kfree(rport_ptr);
1124 }
1125 }
1126 mutex_unlock(&rt_entry->lock);
1127 }
1128 }
1129 mutex_unlock(&routing_table_lock);
1130}
1131
1132static void msm_ipc_cleanup_routing_table(
1133 struct msm_ipc_router_xprt_info *xprt_info)
1134{
1135 int i;
1136 struct msm_ipc_routing_table_entry *rt_entry;
1137
1138 if (!xprt_info) {
1139 pr_err("%s: Invalid xprt_info\n", __func__);
1140 return;
1141 }
1142
1143 mutex_lock(&routing_table_lock);
1144 for (i = 0; i < RT_HASH_SIZE; i++) {
1145 list_for_each_entry(rt_entry, &routing_table[i], list) {
1146 mutex_lock(&rt_entry->lock);
1147 if (rt_entry->xprt_info == xprt_info)
1148 rt_entry->xprt_info = NULL;
1149 mutex_unlock(&rt_entry->lock);
1150 }
1151 }
1152 mutex_unlock(&routing_table_lock);
1153}
1154
1155static void modem_reset_cleanup(struct msm_ipc_router_xprt_info *xprt_info)
1156{
1157
1158 if (!xprt_info) {
1159 pr_err("%s: Invalid xprt_info\n", __func__);
1160 return;
1161 }
1162
1163 msm_ipc_cleanup_remote_server_info(xprt_info);
1164 msm_ipc_cleanup_remote_client_info(xprt_info);
1165 msm_ipc_cleanup_routing_table(xprt_info);
1166}
1167
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001168static int process_hello_msg(struct msm_ipc_router_xprt_info *xprt_info,
1169 struct rr_header *hdr)
1170{
1171 int i, rc = 0;
1172 union rr_control_msg ctl;
1173 struct msm_ipc_routing_table_entry *rt_entry;
1174
1175 if (!hdr)
1176 return -EINVAL;
1177
1178 RR("o HELLO NID %d\n", hdr->src_node_id);
1179
1180 xprt_info->remote_node_id = hdr->src_node_id;
1181 /*
1182 * Find the entry from Routing Table corresponding to Node ID.
1183 * Under SSR, an entry will be found. When the system boots up
1184 * for the 1st time, an entry will not be found and hence allocate
1185 * an entry. Update the entry with the Node ID that it corresponds
1186 * to and the XPRT through which it can be reached.
1187 */
1188 mutex_lock(&routing_table_lock);
1189 rt_entry = lookup_routing_table(hdr->src_node_id);
1190 if (!rt_entry) {
1191 rt_entry = alloc_routing_table_entry(hdr->src_node_id);
1192 if (!rt_entry) {
1193 mutex_unlock(&routing_table_lock);
1194 pr_err("%s: rt_entry allocation failed\n", __func__);
1195 return -ENOMEM;
1196 }
1197 add_routing_table_entry(rt_entry);
1198 }
1199 mutex_lock(&rt_entry->lock);
1200 rt_entry->neighbor_node_id = xprt_info->remote_node_id;
1201 rt_entry->xprt_info = xprt_info;
1202 mutex_unlock(&rt_entry->lock);
1203 mutex_unlock(&routing_table_lock);
1204
1205 /* Cleanup any remote ports, if the node is coming out of reset */
1206 msm_ipc_cleanup_remote_port_info(xprt_info->remote_node_id);
1207
1208 /* Send a reply HELLO message */
1209 memset(&ctl, 0, sizeof(ctl));
1210 ctl.cmd = IPC_ROUTER_CTRL_CMD_HELLO;
1211 rc = msm_ipc_router_send_control_msg(xprt_info, &ctl);
1212 if (rc < 0) {
1213 pr_err("%s: Error sending reply HELLO message\n", __func__);
1214 return rc;
1215 }
1216 xprt_info->initialized = 1;
1217
1218 /*
1219 * Send list of servers from the local node and from nodes
1220 * outside the mesh network in which this XPRT is part of.
1221 */
1222 mutex_lock(&routing_table_lock);
1223 for (i = 0; i < RT_HASH_SIZE; i++) {
1224 list_for_each_entry(rt_entry, &routing_table[i], list) {
1225 if ((rt_entry->node_id != IPC_ROUTER_NID_LOCAL) &&
1226 (rt_entry->xprt_info->xprt->link_id ==
1227 xprt_info->xprt->link_id))
1228 continue;
1229 rc = msm_ipc_router_send_server_list(rt_entry->node_id,
1230 xprt_info);
1231 if (rc < 0) {
1232 mutex_unlock(&routing_table_lock);
1233 return rc;
1234 }
1235 }
1236 }
1237 mutex_unlock(&routing_table_lock);
1238 RR("HELLO message processed\n");
1239 return rc;
1240}
1241
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001242static int process_control_msg(struct msm_ipc_router_xprt_info *xprt_info,
1243 struct rr_packet *pkt)
1244{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001245 union rr_control_msg *msg;
1246 struct msm_ipc_router_remote_port *rport_ptr;
1247 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001248 struct sk_buff *temp_ptr;
1249 struct rr_header *hdr;
1250 struct msm_ipc_server *server;
1251 struct msm_ipc_routing_table_entry *rt_entry;
1252
1253 if (pkt->length != (IPC_ROUTER_HDR_SIZE + sizeof(*msg))) {
1254 pr_err("%s: r2r msg size %d != %d\n", __func__, pkt->length,
1255 (IPC_ROUTER_HDR_SIZE + sizeof(*msg)));
1256 return -EINVAL;
1257 }
1258
1259 temp_ptr = skb_peek(pkt->pkt_fragment_q);
Karthikeyan Ramasubramanian9024dd82011-12-19 18:44:19 -07001260 if (!temp_ptr) {
1261 pr_err("%s: pkt_fragment_q is empty\n", __func__);
1262 return -EINVAL;
1263 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001264 hdr = (struct rr_header *)temp_ptr->data;
Karthikeyan Ramasubramanian9024dd82011-12-19 18:44:19 -07001265 if (!hdr) {
1266 pr_err("%s: No data inside the skb\n", __func__);
1267 return -EINVAL;
1268 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001269 msg = (union rr_control_msg *)((char *)hdr + IPC_ROUTER_HDR_SIZE);
1270
1271 switch (msg->cmd) {
1272 case IPC_ROUTER_CTRL_CMD_HELLO:
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001273 rc = process_hello_msg(xprt_info, hdr);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001274 break;
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001275
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001276 case IPC_ROUTER_CTRL_CMD_RESUME_TX:
1277 RR("o RESUME_TX id=%d:%08x\n",
1278 msg->cli.node_id, msg->cli.port_id);
1279
1280 rport_ptr = msm_ipc_router_lookup_remote_port(msg->cli.node_id,
1281 msg->cli.port_id);
1282 if (!rport_ptr) {
1283 pr_err("%s: Unable to resume client\n", __func__);
1284 break;
1285 }
1286 mutex_lock(&rport_ptr->quota_lock);
1287 rport_ptr->tx_quota_cnt = 0;
1288 mutex_unlock(&rport_ptr->quota_lock);
1289 wake_up(&rport_ptr->quota_wait);
1290 break;
1291
1292 case IPC_ROUTER_CTRL_CMD_NEW_SERVER:
1293 if (msg->srv.instance == 0) {
1294 pr_err(
1295 "rpcrouter: Server create rejected, version = 0, "
1296 "service = %08x\n", msg->srv.service);
1297 break;
1298 }
1299
1300 RR("o NEW_SERVER id=%d:%08x service=%08x:%08x\n",
1301 msg->srv.node_id, msg->srv.port_id,
1302 msg->srv.service, msg->srv.instance);
1303
1304 mutex_lock(&routing_table_lock);
1305 rt_entry = lookup_routing_table(msg->srv.node_id);
1306 if (!rt_entry) {
1307 rt_entry = alloc_routing_table_entry(msg->srv.node_id);
1308 if (!rt_entry) {
1309 mutex_unlock(&routing_table_lock);
1310 pr_err("%s: rt_entry allocation failed\n",
1311 __func__);
1312 return -ENOMEM;
1313 }
1314 mutex_lock(&rt_entry->lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001315 rt_entry->neighbor_node_id = xprt_info->remote_node_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001316 rt_entry->xprt_info = xprt_info;
1317 mutex_unlock(&rt_entry->lock);
1318 add_routing_table_entry(rt_entry);
1319 }
1320 mutex_unlock(&routing_table_lock);
1321
1322 server = msm_ipc_router_lookup_server(msg->srv.service,
1323 msg->srv.instance,
1324 msg->srv.node_id,
1325 msg->srv.port_id);
1326 if (!server) {
1327 server = msm_ipc_router_create_server(
1328 msg->srv.service, msg->srv.instance,
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001329 msg->srv.node_id, msg->srv.port_id, xprt_info);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001330 if (!server) {
1331 pr_err("%s: Server Create failed\n", __func__);
1332 return -ENOMEM;
1333 }
1334
1335 if (!msm_ipc_router_lookup_remote_port(
1336 msg->srv.node_id, msg->srv.port_id)) {
1337 rport_ptr = msm_ipc_router_create_remote_port(
1338 msg->srv.node_id, msg->srv.port_id);
1339 if (!rport_ptr)
1340 pr_err("%s: Remote port create "
1341 "failed\n", __func__);
1342 }
1343 wake_up(&newserver_wait);
1344 }
1345
1346 relay_msg(xprt_info, pkt);
1347 post_control_ports(pkt);
1348 break;
1349 case IPC_ROUTER_CTRL_CMD_REMOVE_SERVER:
1350 RR("o REMOVE_SERVER service=%08x:%d\n",
1351 msg->srv.service, msg->srv.instance);
1352 server = msm_ipc_router_lookup_server(msg->srv.service,
1353 msg->srv.instance,
1354 msg->srv.node_id,
1355 msg->srv.port_id);
1356 if (server) {
1357 msm_ipc_router_destroy_server(server,
1358 msg->srv.node_id,
1359 msg->srv.port_id);
1360 relay_msg(xprt_info, pkt);
1361 post_control_ports(pkt);
1362 }
1363 break;
1364 case IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT:
1365 RR("o REMOVE_CLIENT id=%d:%08x\n",
1366 msg->cli.node_id, msg->cli.port_id);
1367 rport_ptr = msm_ipc_router_lookup_remote_port(msg->cli.node_id,
1368 msg->cli.port_id);
1369 if (rport_ptr)
1370 msm_ipc_router_destroy_remote_port(rport_ptr);
1371
1372 relay_msg(xprt_info, pkt);
1373 post_control_ports(pkt);
1374 break;
1375 case IPC_ROUTER_CTRL_CMD_PING:
1376 /* No action needed for ping messages received */
1377 RR("o PING\n");
1378 break;
1379 default:
1380 RR("o UNKNOWN(%08x)\n", msg->cmd);
1381 rc = -ENOSYS;
1382 }
1383
1384 return rc;
1385}
1386
1387static void do_read_data(struct work_struct *work)
1388{
1389 struct rr_header *hdr;
1390 struct rr_packet *pkt = NULL;
1391 struct msm_ipc_port *port_ptr;
1392 struct sk_buff *head_skb;
1393 struct msm_ipc_port_addr *src_addr;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001394 struct msm_ipc_router_remote_port *rport_ptr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001395 uint32_t resume_tx, resume_tx_node_id, resume_tx_port_id;
1396
1397 struct msm_ipc_router_xprt_info *xprt_info =
1398 container_of(work,
1399 struct msm_ipc_router_xprt_info,
1400 read_data);
1401
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001402 while ((pkt = rr_read(xprt_info)) != NULL) {
1403 if (pkt->length < IPC_ROUTER_HDR_SIZE ||
1404 pkt->length > MAX_IPC_PKT_SIZE) {
1405 pr_err("%s: Invalid pkt length %d\n",
1406 __func__, pkt->length);
1407 goto fail_data;
1408 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001409
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001410 head_skb = skb_peek(pkt->pkt_fragment_q);
1411 if (!head_skb) {
1412 pr_err("%s: head_skb is invalid\n", __func__);
1413 goto fail_data;
1414 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001415
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001416 hdr = (struct rr_header *)(head_skb->data);
1417 RR("- ver=%d type=%d src=%d:%08x crx=%d siz=%d dst=%d:%08x\n",
1418 hdr->version, hdr->type, hdr->src_node_id, hdr->src_port_id,
1419 hdr->confirm_rx, hdr->size, hdr->dst_node_id,
1420 hdr->dst_port_id);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001421
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001422 if (hdr->version != IPC_ROUTER_VERSION) {
1423 pr_err("version %d != %d\n",
1424 hdr->version, IPC_ROUTER_VERSION);
1425 goto fail_data;
1426 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001427
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001428 if ((hdr->dst_node_id != IPC_ROUTER_NID_LOCAL) &&
1429 ((hdr->type == IPC_ROUTER_CTRL_CMD_RESUME_TX) ||
1430 (hdr->type == IPC_ROUTER_CTRL_CMD_DATA))) {
1431 forward_msg(xprt_info, pkt);
1432 release_pkt(pkt);
1433 continue;
1434 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001435
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001436 if ((hdr->dst_port_id == IPC_ROUTER_ADDRESS) ||
1437 (hdr->type == IPC_ROUTER_CTRL_CMD_HELLO)) {
1438 process_control_msg(xprt_info, pkt);
1439 release_pkt(pkt);
1440 continue;
1441 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001442#if defined(CONFIG_MSM_SMD_LOGGING)
1443#if defined(DEBUG)
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001444 if (msm_ipc_router_debug_mask & SMEM_LOG) {
1445 smem_log_event((SMEM_LOG_PROC_ID_APPS |
1446 SMEM_LOG_RPC_ROUTER_EVENT_BASE |
1447 IPC_ROUTER_LOG_EVENT_RX),
1448 (hdr->src_node_id << 24) |
1449 (hdr->src_port_id & 0xffffff),
1450 (hdr->dst_node_id << 24) |
1451 (hdr->dst_port_id & 0xffffff),
1452 (hdr->type << 24) | (hdr->confirm_rx << 16) |
1453 (hdr->size & 0xffff));
1454 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001455#endif
1456#endif
1457
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001458 resume_tx = hdr->confirm_rx;
1459 resume_tx_node_id = hdr->dst_node_id;
1460 resume_tx_port_id = hdr->dst_port_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001461
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001462 rport_ptr = msm_ipc_router_lookup_remote_port(hdr->src_node_id,
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06001463 hdr->src_port_id);
1464
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001465 mutex_lock(&local_ports_lock);
1466 port_ptr = msm_ipc_router_lookup_local_port(hdr->dst_port_id);
1467 if (!port_ptr) {
1468 pr_err("%s: No local port id %08x\n", __func__,
1469 hdr->dst_port_id);
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06001470 mutex_unlock(&local_ports_lock);
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001471 release_pkt(pkt);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001472 goto process_done;
1473 }
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001474
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001475 if (!rport_ptr) {
1476 rport_ptr = msm_ipc_router_create_remote_port(
1477 hdr->src_node_id,
1478 hdr->src_port_id);
1479 if (!rport_ptr) {
1480 pr_err("%s: Rmt Prt %08x:%08x create failed\n",
1481 __func__, hdr->src_node_id,
1482 hdr->src_port_id);
1483 mutex_unlock(&local_ports_lock);
1484 goto process_done;
1485 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001486 }
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001487
1488 if (!port_ptr->notify) {
1489 mutex_lock(&port_ptr->port_rx_q_lock);
1490 wake_lock(&port_ptr->port_rx_wake_lock);
1491 list_add_tail(&pkt->list, &port_ptr->port_rx_q);
1492 wake_up(&port_ptr->port_rx_wait_q);
1493 mutex_unlock(&port_ptr->port_rx_q_lock);
1494 mutex_unlock(&local_ports_lock);
1495 } else {
1496 mutex_lock(&port_ptr->port_rx_q_lock);
1497 src_addr = kmalloc(sizeof(struct msm_ipc_port_addr),
1498 GFP_KERNEL);
1499 if (src_addr) {
1500 src_addr->node_id = hdr->src_node_id;
1501 src_addr->port_id = hdr->src_port_id;
1502 }
1503 skb_pull(head_skb, IPC_ROUTER_HDR_SIZE);
1504 mutex_unlock(&local_ports_lock);
1505 port_ptr->notify(MSM_IPC_ROUTER_READ_CB,
1506 pkt->pkt_fragment_q, src_addr, port_ptr->priv);
1507 mutex_unlock(&port_ptr->port_rx_q_lock);
1508 pkt->pkt_fragment_q = NULL;
1509 src_addr = NULL;
1510 release_pkt(pkt);
1511 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001512
1513process_done:
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001514 if (resume_tx) {
1515 union rr_control_msg msg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001516
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001517 msg.cmd = IPC_ROUTER_CTRL_CMD_RESUME_TX;
1518 msg.cli.node_id = resume_tx_node_id;
1519 msg.cli.port_id = resume_tx_port_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001520
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001521 RR("x RESUME_TX id=%d:%08x\n",
1522 msg.cli.node_id, msg.cli.port_id);
1523 msm_ipc_router_send_control_msg(xprt_info, &msg);
1524 }
1525
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001526 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001527 return;
1528
1529fail_data:
1530 release_pkt(pkt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001531 pr_err("ipc_router has died\n");
1532}
1533
1534int msm_ipc_router_register_server(struct msm_ipc_port *port_ptr,
1535 struct msm_ipc_addr *name)
1536{
1537 struct msm_ipc_server *server;
1538 unsigned long flags;
1539 union rr_control_msg ctl;
1540
1541 if (!port_ptr || !name)
1542 return -EINVAL;
1543
1544 if (name->addrtype != MSM_IPC_ADDR_NAME)
1545 return -EINVAL;
1546
1547 server = msm_ipc_router_lookup_server(name->addr.port_name.service,
1548 name->addr.port_name.instance,
1549 IPC_ROUTER_NID_LOCAL,
1550 port_ptr->this_port.port_id);
1551 if (server) {
1552 pr_err("%s: Server already present\n", __func__);
1553 return -EINVAL;
1554 }
1555
1556 server = msm_ipc_router_create_server(name->addr.port_name.service,
1557 name->addr.port_name.instance,
1558 IPC_ROUTER_NID_LOCAL,
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001559 port_ptr->this_port.port_id,
1560 NULL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001561 if (!server) {
1562 pr_err("%s: Server Creation failed\n", __func__);
1563 return -EINVAL;
1564 }
1565
1566 ctl.cmd = IPC_ROUTER_CTRL_CMD_NEW_SERVER;
1567 ctl.srv.service = server->name.service;
1568 ctl.srv.instance = server->name.instance;
1569 ctl.srv.node_id = IPC_ROUTER_NID_LOCAL;
1570 ctl.srv.port_id = port_ptr->this_port.port_id;
1571 broadcast_ctl_msg(&ctl);
1572 spin_lock_irqsave(&port_ptr->port_lock, flags);
1573 port_ptr->type = SERVER_PORT;
1574 port_ptr->port_name.service = server->name.service;
1575 port_ptr->port_name.instance = server->name.instance;
1576 spin_unlock_irqrestore(&port_ptr->port_lock, flags);
1577 return 0;
1578}
1579
1580int msm_ipc_router_unregister_server(struct msm_ipc_port *port_ptr)
1581{
1582 struct msm_ipc_server *server;
1583 unsigned long flags;
1584 union rr_control_msg ctl;
1585
1586 if (!port_ptr)
1587 return -EINVAL;
1588
1589 if (port_ptr->type != SERVER_PORT) {
1590 pr_err("%s: Trying to unregister a non-server port\n",
1591 __func__);
1592 return -EINVAL;
1593 }
1594
1595 if (port_ptr->this_port.node_id != IPC_ROUTER_NID_LOCAL) {
1596 pr_err("%s: Trying to unregister a remote server locally\n",
1597 __func__);
1598 return -EINVAL;
1599 }
1600
1601 server = msm_ipc_router_lookup_server(port_ptr->port_name.service,
1602 port_ptr->port_name.instance,
1603 port_ptr->this_port.node_id,
1604 port_ptr->this_port.port_id);
1605 if (!server) {
1606 pr_err("%s: Server lookup failed\n", __func__);
1607 return -ENODEV;
1608 }
1609
1610 ctl.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_SERVER;
1611 ctl.srv.service = server->name.service;
1612 ctl.srv.instance = server->name.instance;
1613 ctl.srv.node_id = IPC_ROUTER_NID_LOCAL;
1614 ctl.srv.port_id = port_ptr->this_port.port_id;
1615 broadcast_ctl_msg(&ctl);
1616 msm_ipc_router_destroy_server(server, port_ptr->this_port.node_id,
1617 port_ptr->this_port.port_id);
1618 spin_lock_irqsave(&port_ptr->port_lock, flags);
1619 port_ptr->type = CLIENT_PORT;
1620 spin_unlock_irqrestore(&port_ptr->port_lock, flags);
1621 return 0;
1622}
1623
1624static int loopback_data(struct msm_ipc_port *src,
1625 uint32_t port_id,
1626 struct sk_buff_head *data)
1627{
1628 struct sk_buff *head_skb;
1629 struct rr_header *hdr;
1630 struct msm_ipc_port *port_ptr;
1631 struct rr_packet *pkt;
1632
1633 if (!data) {
1634 pr_err("%s: Invalid pkt pointer\n", __func__);
1635 return -EINVAL;
1636 }
1637
1638 pkt = create_pkt(data);
1639 if (!pkt) {
1640 pr_err("%s: New pkt create failed\n", __func__);
1641 return -ENOMEM;
1642 }
1643
1644 head_skb = skb_peek(pkt->pkt_fragment_q);
Karthikeyan Ramasubramanian9024dd82011-12-19 18:44:19 -07001645 if (!head_skb) {
1646 pr_err("%s: pkt_fragment_q is empty\n", __func__);
1647 return -EINVAL;
1648 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001649 hdr = (struct rr_header *)skb_push(head_skb, IPC_ROUTER_HDR_SIZE);
1650 if (!hdr) {
1651 pr_err("%s: Prepend Header failed\n", __func__);
1652 release_pkt(pkt);
1653 return -ENOMEM;
1654 }
1655 hdr->version = IPC_ROUTER_VERSION;
1656 hdr->type = IPC_ROUTER_CTRL_CMD_DATA;
1657 hdr->src_node_id = src->this_port.node_id;
1658 hdr->src_port_id = src->this_port.port_id;
1659 hdr->size = pkt->length;
1660 hdr->confirm_rx = 0;
1661 hdr->dst_node_id = IPC_ROUTER_NID_LOCAL;
1662 hdr->dst_port_id = port_id;
1663 pkt->length += IPC_ROUTER_HDR_SIZE;
1664
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06001665 mutex_lock(&local_ports_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001666 port_ptr = msm_ipc_router_lookup_local_port(port_id);
1667 if (!port_ptr) {
1668 pr_err("%s: Local port %d not present\n", __func__, port_id);
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06001669 mutex_unlock(&local_ports_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001670 release_pkt(pkt);
1671 return -ENODEV;
1672 }
1673
1674 mutex_lock(&port_ptr->port_rx_q_lock);
1675 wake_lock(&port_ptr->port_rx_wake_lock);
1676 list_add_tail(&pkt->list, &port_ptr->port_rx_q);
1677 wake_up(&port_ptr->port_rx_wait_q);
1678 mutex_unlock(&port_ptr->port_rx_q_lock);
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06001679 mutex_unlock(&local_ports_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001680
1681 return pkt->length;
1682}
1683
1684static int msm_ipc_router_write_pkt(struct msm_ipc_port *src,
1685 struct msm_ipc_router_remote_port *rport_ptr,
1686 struct rr_packet *pkt)
1687{
1688 struct sk_buff *head_skb;
1689 struct rr_header *hdr;
1690 struct msm_ipc_router_xprt_info *xprt_info;
1691 struct msm_ipc_routing_table_entry *rt_entry;
1692 int ret;
1693 DEFINE_WAIT(__wait);
1694
1695 if (!rport_ptr || !src || !pkt)
1696 return -EINVAL;
1697
1698 head_skb = skb_peek(pkt->pkt_fragment_q);
Karthikeyan Ramasubramanian9024dd82011-12-19 18:44:19 -07001699 if (!head_skb) {
1700 pr_err("%s: pkt_fragment_q is empty\n", __func__);
1701 return -EINVAL;
1702 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001703 hdr = (struct rr_header *)skb_push(head_skb, IPC_ROUTER_HDR_SIZE);
1704 if (!hdr) {
1705 pr_err("%s: Prepend Header failed\n", __func__);
1706 return -ENOMEM;
1707 }
1708 hdr->version = IPC_ROUTER_VERSION;
1709 hdr->type = IPC_ROUTER_CTRL_CMD_DATA;
1710 hdr->src_node_id = src->this_port.node_id;
1711 hdr->src_port_id = src->this_port.port_id;
1712 hdr->size = pkt->length;
1713 hdr->confirm_rx = 0;
1714 hdr->dst_node_id = rport_ptr->node_id;
1715 hdr->dst_port_id = rport_ptr->port_id;
1716 pkt->length += IPC_ROUTER_HDR_SIZE;
1717
1718 for (;;) {
1719 prepare_to_wait(&rport_ptr->quota_wait, &__wait,
1720 TASK_INTERRUPTIBLE);
1721 mutex_lock(&rport_ptr->quota_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001722 if (rport_ptr->restart_state != RESTART_NORMAL)
1723 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001724 if (rport_ptr->tx_quota_cnt <
1725 IPC_ROUTER_DEFAULT_RX_QUOTA)
1726 break;
1727 if (signal_pending(current))
1728 break;
1729 mutex_unlock(&rport_ptr->quota_lock);
1730 schedule();
1731 }
1732 finish_wait(&rport_ptr->quota_wait, &__wait);
1733
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001734 if (rport_ptr->restart_state != RESTART_NORMAL) {
1735 mutex_unlock(&rport_ptr->quota_lock);
1736 return -ENETRESET;
1737 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001738 if (signal_pending(current)) {
1739 mutex_unlock(&rport_ptr->quota_lock);
1740 return -ERESTARTSYS;
1741 }
1742 rport_ptr->tx_quota_cnt++;
1743 if (rport_ptr->tx_quota_cnt == IPC_ROUTER_DEFAULT_RX_QUOTA)
1744 hdr->confirm_rx = 1;
1745 mutex_unlock(&rport_ptr->quota_lock);
1746
1747 mutex_lock(&routing_table_lock);
1748 rt_entry = lookup_routing_table(hdr->dst_node_id);
1749 if (!rt_entry || !rt_entry->xprt_info) {
1750 mutex_unlock(&routing_table_lock);
1751 pr_err("%s: Remote node %d not up\n",
1752 __func__, hdr->dst_node_id);
1753 return -ENODEV;
1754 }
1755 mutex_lock(&rt_entry->lock);
1756 xprt_info = rt_entry->xprt_info;
1757 mutex_lock(&xprt_info->tx_lock);
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -07001758 ret = xprt_info->xprt->write(pkt, pkt->length, xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001759 mutex_unlock(&xprt_info->tx_lock);
1760 mutex_unlock(&rt_entry->lock);
1761 mutex_unlock(&routing_table_lock);
1762
1763 if (ret < 0) {
1764 pr_err("%s: Write on XPRT failed\n", __func__);
1765 return ret;
1766 }
1767
1768 RAW_HDR("[w rr_h] "
1769 "ver=%i,type=%s,src_nid=%08x,src_port_id=%08x,"
1770 "confirm_rx=%i,size=%3i,dst_pid=%08x,dst_cid=%08x\n",
1771 hdr->version, type_to_str(hdr->type),
1772 hdr->src_node_id, hdr->src_port_id,
1773 hdr->confirm_rx, hdr->size,
1774 hdr->dst_node_id, hdr->dst_port_id);
1775
1776#if defined(CONFIG_MSM_SMD_LOGGING)
1777#if defined(DEBUG)
1778 if (msm_ipc_router_debug_mask & SMEM_LOG) {
1779 smem_log_event((SMEM_LOG_PROC_ID_APPS |
1780 SMEM_LOG_RPC_ROUTER_EVENT_BASE |
1781 IPC_ROUTER_LOG_EVENT_TX),
1782 (hdr->src_node_id << 24) |
1783 (hdr->src_port_id & 0xffffff),
1784 (hdr->dst_node_id << 24) |
1785 (hdr->dst_port_id & 0xffffff),
1786 (hdr->type << 24) | (hdr->confirm_rx << 16) |
1787 (hdr->size & 0xffff));
1788 }
1789#endif
1790#endif
1791
1792 return pkt->length;
1793}
1794
1795int msm_ipc_router_send_to(struct msm_ipc_port *src,
1796 struct sk_buff_head *data,
1797 struct msm_ipc_addr *dest)
1798{
1799 uint32_t dst_node_id = 0, dst_port_id = 0;
1800 struct msm_ipc_server *server;
1801 struct msm_ipc_server_port *server_port;
1802 struct msm_ipc_router_remote_port *rport_ptr = NULL;
1803 struct rr_packet *pkt;
1804 int ret;
1805
1806 if (!src || !data || !dest) {
1807 pr_err("%s: Invalid Parameters\n", __func__);
1808 return -EINVAL;
1809 }
1810
1811 /* Resolve Address*/
1812 if (dest->addrtype == MSM_IPC_ADDR_ID) {
1813 dst_node_id = dest->addr.port_addr.node_id;
1814 dst_port_id = dest->addr.port_addr.port_id;
1815 } else if (dest->addrtype == MSM_IPC_ADDR_NAME) {
1816 server = msm_ipc_router_lookup_server(
1817 dest->addr.port_name.service,
1818 dest->addr.port_name.instance,
1819 0, 0);
1820 if (!server) {
1821 pr_err("%s: Destination not reachable\n", __func__);
1822 return -ENODEV;
1823 }
1824 mutex_lock(&server_list_lock);
1825 server_port = list_first_entry(&server->server_port_list,
1826 struct msm_ipc_server_port,
1827 list);
1828 dst_node_id = server_port->server_addr.node_id;
1829 dst_port_id = server_port->server_addr.port_id;
1830 mutex_unlock(&server_list_lock);
1831 }
1832 if (dst_node_id == IPC_ROUTER_NID_LOCAL) {
1833 ret = loopback_data(src, dst_port_id, data);
1834 return ret;
1835 }
1836
1837 /* Achieve Flow control */
1838 rport_ptr = msm_ipc_router_lookup_remote_port(dst_node_id,
1839 dst_port_id);
1840 if (!rport_ptr) {
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001841 pr_err("%s: Could not create remote port\n", __func__);
1842 return -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001843 }
1844
1845 pkt = create_pkt(data);
1846 if (!pkt) {
1847 pr_err("%s: Pkt creation failed\n", __func__);
1848 return -ENOMEM;
1849 }
1850
1851 ret = msm_ipc_router_write_pkt(src, rport_ptr, pkt);
1852 release_pkt(pkt);
1853
1854 return ret;
1855}
1856
1857int msm_ipc_router_read(struct msm_ipc_port *port_ptr,
1858 struct sk_buff_head **data,
1859 size_t buf_len)
1860{
1861 struct rr_packet *pkt;
1862 int ret;
1863
1864 if (!port_ptr || !data)
1865 return -EINVAL;
1866
1867 mutex_lock(&port_ptr->port_rx_q_lock);
1868 if (list_empty(&port_ptr->port_rx_q)) {
1869 mutex_unlock(&port_ptr->port_rx_q_lock);
1870 return -EAGAIN;
1871 }
1872
1873 pkt = list_first_entry(&port_ptr->port_rx_q, struct rr_packet, list);
1874 if ((buf_len) && ((pkt->length - IPC_ROUTER_HDR_SIZE) > buf_len)) {
1875 mutex_unlock(&port_ptr->port_rx_q_lock);
1876 return -ETOOSMALL;
1877 }
1878 list_del(&pkt->list);
1879 if (list_empty(&port_ptr->port_rx_q))
1880 wake_unlock(&port_ptr->port_rx_wake_lock);
1881 *data = pkt->pkt_fragment_q;
1882 ret = pkt->length;
1883 kfree(pkt);
1884 mutex_unlock(&port_ptr->port_rx_q_lock);
1885
1886 return ret;
1887}
1888
1889int msm_ipc_router_recv_from(struct msm_ipc_port *port_ptr,
1890 struct sk_buff_head **data,
1891 struct msm_ipc_addr *src,
1892 unsigned long timeout)
1893{
1894 int ret, data_len, align_size;
1895 struct sk_buff *temp_skb;
1896 struct rr_header *hdr = NULL;
1897
1898 if (!port_ptr || !data) {
1899 pr_err("%s: Invalid pointers being passed\n", __func__);
1900 return -EINVAL;
1901 }
1902
1903 *data = NULL;
1904 mutex_lock(&port_ptr->port_rx_q_lock);
1905 while (list_empty(&port_ptr->port_rx_q)) {
1906 mutex_unlock(&port_ptr->port_rx_q_lock);
1907 if (timeout < 0) {
1908 ret = wait_event_interruptible(
1909 port_ptr->port_rx_wait_q,
1910 !list_empty(&port_ptr->port_rx_q));
1911 if (ret)
1912 return ret;
1913 } else if (timeout > 0) {
1914 timeout = wait_event_interruptible_timeout(
1915 port_ptr->port_rx_wait_q,
1916 !list_empty(&port_ptr->port_rx_q),
1917 timeout);
1918 if (timeout < 0)
1919 return -EFAULT;
1920 }
1921 if (timeout == 0)
1922 return -ETIMEDOUT;
1923 mutex_lock(&port_ptr->port_rx_q_lock);
1924 }
1925 mutex_unlock(&port_ptr->port_rx_q_lock);
1926
1927 ret = msm_ipc_router_read(port_ptr, data, 0);
1928 if (ret <= 0 || !(*data))
1929 return ret;
1930
1931 temp_skb = skb_peek(*data);
1932 hdr = (struct rr_header *)(temp_skb->data);
1933 if (src) {
1934 src->addrtype = MSM_IPC_ADDR_ID;
1935 src->addr.port_addr.node_id = hdr->src_node_id;
1936 src->addr.port_addr.port_id = hdr->src_port_id;
1937 }
1938
1939 data_len = hdr->size;
1940 skb_pull(temp_skb, IPC_ROUTER_HDR_SIZE);
1941 align_size = ALIGN_SIZE(data_len);
1942 if (align_size) {
1943 temp_skb = skb_peek_tail(*data);
1944 skb_trim(temp_skb, (temp_skb->len - align_size));
1945 }
1946 return data_len;
1947}
1948
1949struct msm_ipc_port *msm_ipc_router_create_port(
1950 void (*notify)(unsigned event, void *data, void *addr, void *priv),
1951 void *priv)
1952{
1953 struct msm_ipc_port *port_ptr;
1954
1955 port_ptr = msm_ipc_router_create_raw_port(NULL, notify, priv);
1956 if (!port_ptr)
1957 pr_err("%s: port_ptr alloc failed\n", __func__);
1958
1959 return port_ptr;
1960}
1961
1962int msm_ipc_router_close_port(struct msm_ipc_port *port_ptr)
1963{
1964 union rr_control_msg msg;
1965 struct rr_packet *pkt, *temp_pkt;
1966 struct msm_ipc_server *server;
1967
1968 if (!port_ptr)
1969 return -EINVAL;
1970
1971 if (port_ptr->type == SERVER_PORT || port_ptr->type == CLIENT_PORT) {
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06001972 mutex_lock(&local_ports_lock);
1973 list_del(&port_ptr->list);
1974 mutex_unlock(&local_ports_lock);
1975
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001976 if (port_ptr->type == SERVER_PORT) {
1977 msg.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_SERVER;
1978 msg.srv.service = port_ptr->port_name.service;
1979 msg.srv.instance = port_ptr->port_name.instance;
1980 msg.srv.node_id = port_ptr->this_port.node_id;
1981 msg.srv.port_id = port_ptr->this_port.port_id;
1982 RR("x REMOVE_SERVER Name=%d:%08x Id=%d:%08x\n",
1983 msg.srv.service, msg.srv.instance,
1984 msg.srv.node_id, msg.srv.port_id);
1985 } else if (port_ptr->type == CLIENT_PORT) {
1986 msg.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT;
1987 msg.cli.node_id = port_ptr->this_port.node_id;
1988 msg.cli.port_id = port_ptr->this_port.port_id;
1989 RR("x REMOVE_CLIENT id=%d:%08x\n",
1990 msg.cli.node_id, msg.cli.port_id);
1991 }
1992 broadcast_ctl_msg(&msg);
1993 broadcast_ctl_msg_locally(&msg);
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06001994 } else if (port_ptr->type == CONTROL_PORT) {
1995 mutex_lock(&control_ports_lock);
1996 list_del(&port_ptr->list);
1997 mutex_unlock(&control_ports_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001998 }
1999
2000 mutex_lock(&port_ptr->port_rx_q_lock);
2001 list_for_each_entry_safe(pkt, temp_pkt, &port_ptr->port_rx_q, list) {
2002 list_del(&pkt->list);
2003 release_pkt(pkt);
2004 }
2005 mutex_unlock(&port_ptr->port_rx_q_lock);
2006
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002007 if (port_ptr->type == SERVER_PORT) {
2008 server = msm_ipc_router_lookup_server(
2009 port_ptr->port_name.service,
2010 port_ptr->port_name.instance,
2011 port_ptr->this_port.node_id,
2012 port_ptr->this_port.port_id);
2013 if (server)
2014 msm_ipc_router_destroy_server(server,
2015 port_ptr->this_port.node_id,
2016 port_ptr->this_port.port_id);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002017 }
2018
Karthikeyan Ramasubramaniandd8c3b52011-11-30 16:26:12 -07002019 wake_lock_destroy(&port_ptr->port_rx_wake_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002020 kfree(port_ptr);
2021 return 0;
2022}
2023
2024int msm_ipc_router_get_curr_pkt_size(struct msm_ipc_port *port_ptr)
2025{
2026 struct rr_packet *pkt;
2027 int rc = 0;
2028
2029 if (!port_ptr)
2030 return -EINVAL;
2031
2032 mutex_lock(&port_ptr->port_rx_q_lock);
2033 if (!list_empty(&port_ptr->port_rx_q)) {
2034 pkt = list_first_entry(&port_ptr->port_rx_q,
2035 struct rr_packet, list);
2036 rc = pkt->length;
2037 }
2038 mutex_unlock(&port_ptr->port_rx_q_lock);
2039
2040 return rc;
2041}
2042
2043int msm_ipc_router_bind_control_port(struct msm_ipc_port *port_ptr)
2044{
2045 if (!port_ptr)
2046 return -EINVAL;
2047
2048 mutex_lock(&local_ports_lock);
2049 list_del(&port_ptr->list);
2050 mutex_unlock(&local_ports_lock);
2051 port_ptr->type = CONTROL_PORT;
2052 mutex_lock(&control_ports_lock);
2053 list_add_tail(&port_ptr->list, &control_ports);
2054 mutex_unlock(&control_ports_lock);
2055
2056 return 0;
2057}
2058
2059int msm_ipc_router_lookup_server_name(struct msm_ipc_port_name *srv_name,
Karthikeyan Ramasubramaniandfde01b2012-06-12 14:25:13 -06002060 struct msm_ipc_server_info *srv_info,
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002061 int num_entries_in_array,
2062 uint32_t lookup_mask)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002063{
2064 struct msm_ipc_server *server;
2065 struct msm_ipc_server_port *server_port;
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002066 int key, i = 0; /*num_entries_found*/
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002067
2068 if (!srv_name) {
2069 pr_err("%s: Invalid srv_name\n", __func__);
2070 return -EINVAL;
2071 }
2072
Karthikeyan Ramasubramaniandfde01b2012-06-12 14:25:13 -06002073 if (num_entries_in_array && !srv_info) {
2074 pr_err("%s: srv_info NULL\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002075 return -EINVAL;
2076 }
2077
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002078 mutex_lock(&server_list_lock);
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002079 if (!lookup_mask)
2080 lookup_mask = 0xFFFFFFFF;
2081 for (key = 0; key < SRV_HASH_SIZE; key++) {
2082 list_for_each_entry(server, &server_list[key], list) {
2083 if ((server->name.service != srv_name->service) ||
2084 ((server->name.instance & lookup_mask) !=
2085 srv_name->instance))
2086 continue;
2087
2088 list_for_each_entry(server_port,
2089 &server->server_port_list, list) {
2090 if (i < num_entries_in_array) {
Karthikeyan Ramasubramaniandfde01b2012-06-12 14:25:13 -06002091 srv_info[i].node_id =
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002092 server_port->server_addr.node_id;
Karthikeyan Ramasubramaniandfde01b2012-06-12 14:25:13 -06002093 srv_info[i].port_id =
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002094 server_port->server_addr.port_id;
Karthikeyan Ramasubramaniandfde01b2012-06-12 14:25:13 -06002095 srv_info[i].service =
2096 server->name.service;
2097 srv_info[i].instance =
2098 server->name.instance;
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002099 }
2100 i++;
2101 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002102 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002103 }
2104 mutex_unlock(&server_list_lock);
2105
2106 return i;
2107}
2108
2109int msm_ipc_router_close(void)
2110{
2111 struct msm_ipc_router_xprt_info *xprt_info, *tmp_xprt_info;
2112
2113 mutex_lock(&xprt_info_list_lock);
2114 list_for_each_entry_safe(xprt_info, tmp_xprt_info,
2115 &xprt_info_list, list) {
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -07002116 xprt_info->xprt->close(xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002117 list_del(&xprt_info->list);
2118 kfree(xprt_info);
2119 }
2120 mutex_unlock(&xprt_info_list_lock);
2121 return 0;
2122}
2123
2124#if defined(CONFIG_DEBUG_FS)
2125static int dump_routing_table(char *buf, int max)
2126{
2127 int i = 0, j;
2128 struct msm_ipc_routing_table_entry *rt_entry;
2129
2130 for (j = 0; j < RT_HASH_SIZE; j++) {
2131 mutex_lock(&routing_table_lock);
2132 list_for_each_entry(rt_entry, &routing_table[j], list) {
2133 mutex_lock(&rt_entry->lock);
2134 i += scnprintf(buf + i, max - i,
2135 "Node Id: 0x%08x\n", rt_entry->node_id);
Karthikeyan Ramasubramanianc1a4e3a2012-09-10 16:10:24 -06002136 if (rt_entry->node_id == IPC_ROUTER_NID_LOCAL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002137 i += scnprintf(buf + i, max - i,
2138 "XPRT Name: Loopback\n");
2139 i += scnprintf(buf + i, max - i,
2140 "Next Hop: %d\n", rt_entry->node_id);
2141 } else {
2142 i += scnprintf(buf + i, max - i,
2143 "XPRT Name: %s\n",
2144 rt_entry->xprt_info->xprt->name);
2145 i += scnprintf(buf + i, max - i,
2146 "Next Hop: 0x%08x\n",
2147 rt_entry->xprt_info->remote_node_id);
2148 }
2149 i += scnprintf(buf + i, max - i, "\n");
2150 mutex_unlock(&rt_entry->lock);
2151 }
2152 mutex_unlock(&routing_table_lock);
2153 }
2154
2155 return i;
2156}
2157
2158static int dump_xprt_info(char *buf, int max)
2159{
2160 int i = 0;
2161 struct msm_ipc_router_xprt_info *xprt_info;
2162
2163 mutex_lock(&xprt_info_list_lock);
2164 list_for_each_entry(xprt_info, &xprt_info_list, list) {
2165 i += scnprintf(buf + i, max - i, "XPRT Name: %s\n",
2166 xprt_info->xprt->name);
2167 i += scnprintf(buf + i, max - i, "Link Id: %d\n",
2168 xprt_info->xprt->link_id);
2169 i += scnprintf(buf + i, max - i, "Initialized: %s\n",
2170 (xprt_info->initialized ? "Y" : "N"));
2171 i += scnprintf(buf + i, max - i, "Remote Node Id: 0x%08x\n",
2172 xprt_info->remote_node_id);
2173 i += scnprintf(buf + i, max - i, "\n");
2174 }
2175 mutex_unlock(&xprt_info_list_lock);
2176
2177 return i;
2178}
2179
2180static int dump_servers(char *buf, int max)
2181{
2182 int i = 0, j;
2183 struct msm_ipc_server *server;
2184 struct msm_ipc_server_port *server_port;
2185
2186 mutex_lock(&server_list_lock);
2187 for (j = 0; j < SRV_HASH_SIZE; j++) {
2188 list_for_each_entry(server, &server_list[j], list) {
2189 list_for_each_entry(server_port,
2190 &server->server_port_list,
2191 list) {
2192 i += scnprintf(buf + i, max - i, "Service: "
2193 "0x%08x\n", server->name.service);
2194 i += scnprintf(buf + i, max - i, "Instance: "
2195 "0x%08x\n", server->name.instance);
2196 i += scnprintf(buf + i, max - i,
2197 "Node_id: 0x%08x\n",
2198 server_port->server_addr.node_id);
2199 i += scnprintf(buf + i, max - i,
2200 "Port_id: 0x%08x\n",
2201 server_port->server_addr.port_id);
2202 i += scnprintf(buf + i, max - i, "\n");
2203 }
2204 }
2205 }
2206 mutex_unlock(&server_list_lock);
2207
2208 return i;
2209}
2210
2211static int dump_remote_ports(char *buf, int max)
2212{
2213 int i = 0, j, k;
2214 struct msm_ipc_router_remote_port *rport_ptr;
2215 struct msm_ipc_routing_table_entry *rt_entry;
2216
2217 for (j = 0; j < RT_HASH_SIZE; j++) {
2218 mutex_lock(&routing_table_lock);
2219 list_for_each_entry(rt_entry, &routing_table[j], list) {
2220 mutex_lock(&rt_entry->lock);
2221 for (k = 0; k < RP_HASH_SIZE; k++) {
2222 list_for_each_entry(rport_ptr,
2223 &rt_entry->remote_port_list[k],
2224 list) {
2225 i += scnprintf(buf + i, max - i,
2226 "Node_id: 0x%08x\n",
2227 rport_ptr->node_id);
2228 i += scnprintf(buf + i, max - i,
2229 "Port_id: 0x%08x\n",
2230 rport_ptr->port_id);
2231 i += scnprintf(buf + i, max - i,
2232 "Quota_cnt: %d\n",
2233 rport_ptr->tx_quota_cnt);
2234 i += scnprintf(buf + i, max - i, "\n");
2235 }
2236 }
2237 mutex_unlock(&rt_entry->lock);
2238 }
2239 mutex_unlock(&routing_table_lock);
2240 }
2241
2242 return i;
2243}
2244
2245static int dump_control_ports(char *buf, int max)
2246{
2247 int i = 0;
2248 struct msm_ipc_port *port_ptr;
2249
2250 mutex_lock(&control_ports_lock);
2251 list_for_each_entry(port_ptr, &control_ports, list) {
2252 i += scnprintf(buf + i, max - i, "Node_id: 0x%08x\n",
2253 port_ptr->this_port.node_id);
2254 i += scnprintf(buf + i, max - i, "Port_id: 0x%08x\n",
2255 port_ptr->this_port.port_id);
2256 i += scnprintf(buf + i, max - i, "\n");
2257 }
2258 mutex_unlock(&control_ports_lock);
2259
2260 return i;
2261}
2262
2263static int dump_local_ports(char *buf, int max)
2264{
2265 int i = 0, j;
2266 unsigned long flags;
2267 struct msm_ipc_port *port_ptr;
2268
2269 mutex_lock(&local_ports_lock);
2270 for (j = 0; j < LP_HASH_SIZE; j++) {
2271 list_for_each_entry(port_ptr, &local_ports[j], list) {
2272 spin_lock_irqsave(&port_ptr->port_lock, flags);
2273 i += scnprintf(buf + i, max - i, "Node_id: 0x%08x\n",
2274 port_ptr->this_port.node_id);
2275 i += scnprintf(buf + i, max - i, "Port_id: 0x%08x\n",
2276 port_ptr->this_port.port_id);
2277 i += scnprintf(buf + i, max - i, "# pkts tx'd %d\n",
2278 port_ptr->num_tx);
2279 i += scnprintf(buf + i, max - i, "# pkts rx'd %d\n",
2280 port_ptr->num_rx);
2281 i += scnprintf(buf + i, max - i, "# bytes tx'd %ld\n",
2282 port_ptr->num_tx_bytes);
2283 i += scnprintf(buf + i, max - i, "# bytes rx'd %ld\n",
2284 port_ptr->num_rx_bytes);
2285 spin_unlock_irqrestore(&port_ptr->port_lock, flags);
2286 i += scnprintf(buf + i, max - i, "\n");
2287 }
2288 }
2289 mutex_unlock(&local_ports_lock);
2290
2291 return i;
2292}
2293
2294#define DEBUG_BUFMAX 4096
2295static char debug_buffer[DEBUG_BUFMAX];
2296
2297static ssize_t debug_read(struct file *file, char __user *buf,
2298 size_t count, loff_t *ppos)
2299{
2300 int (*fill)(char *buf, int max) = file->private_data;
2301 int bsize = fill(debug_buffer, DEBUG_BUFMAX);
2302 return simple_read_from_buffer(buf, count, ppos, debug_buffer, bsize);
2303}
2304
2305static int debug_open(struct inode *inode, struct file *file)
2306{
2307 file->private_data = inode->i_private;
2308 return 0;
2309}
2310
2311static const struct file_operations debug_ops = {
2312 .read = debug_read,
2313 .open = debug_open,
2314};
2315
2316static void debug_create(const char *name, mode_t mode,
2317 struct dentry *dent,
2318 int (*fill)(char *buf, int max))
2319{
2320 debugfs_create_file(name, mode, dent, fill, &debug_ops);
2321}
2322
2323static void debugfs_init(void)
2324{
2325 struct dentry *dent;
2326
2327 dent = debugfs_create_dir("msm_ipc_router", 0);
2328 if (IS_ERR(dent))
2329 return;
2330
2331 debug_create("dump_local_ports", 0444, dent,
2332 dump_local_ports);
2333 debug_create("dump_remote_ports", 0444, dent,
2334 dump_remote_ports);
2335 debug_create("dump_control_ports", 0444, dent,
2336 dump_control_ports);
2337 debug_create("dump_servers", 0444, dent,
2338 dump_servers);
2339 debug_create("dump_xprt_info", 0444, dent,
2340 dump_xprt_info);
2341 debug_create("dump_routing_table", 0444, dent,
2342 dump_routing_table);
2343}
2344
2345#else
2346static void debugfs_init(void) {}
2347#endif
2348
2349static int msm_ipc_router_add_xprt(struct msm_ipc_router_xprt *xprt)
2350{
2351 struct msm_ipc_router_xprt_info *xprt_info;
2352 struct msm_ipc_routing_table_entry *rt_entry;
2353
2354 xprt_info = kmalloc(sizeof(struct msm_ipc_router_xprt_info),
2355 GFP_KERNEL);
2356 if (!xprt_info)
2357 return -ENOMEM;
2358
2359 xprt_info->xprt = xprt;
2360 xprt_info->initialized = 0;
2361 xprt_info->remote_node_id = -1;
2362 INIT_LIST_HEAD(&xprt_info->pkt_list);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002363 mutex_init(&xprt_info->rx_lock);
2364 mutex_init(&xprt_info->tx_lock);
2365 wake_lock_init(&xprt_info->wakelock,
2366 WAKE_LOCK_SUSPEND, xprt->name);
2367 xprt_info->need_len = 0;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002368 xprt_info->abort_data_read = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002369 INIT_WORK(&xprt_info->read_data, do_read_data);
2370 INIT_LIST_HEAD(&xprt_info->list);
2371
2372 xprt_info->workqueue = create_singlethread_workqueue(xprt->name);
2373 if (!xprt_info->workqueue) {
2374 kfree(xprt_info);
2375 return -ENOMEM;
2376 }
2377
2378 if (!strcmp(xprt->name, "msm_ipc_router_loopback_xprt")) {
2379 xprt_info->remote_node_id = IPC_ROUTER_NID_LOCAL;
2380 xprt_info->initialized = 1;
2381 }
2382
2383 mutex_lock(&xprt_info_list_lock);
2384 list_add_tail(&xprt_info->list, &xprt_info_list);
2385 mutex_unlock(&xprt_info_list_lock);
2386
2387 mutex_lock(&routing_table_lock);
2388 if (!routing_table_inited) {
2389 init_routing_table();
2390 rt_entry = alloc_routing_table_entry(IPC_ROUTER_NID_LOCAL);
2391 add_routing_table_entry(rt_entry);
2392 routing_table_inited = 1;
2393 }
2394 mutex_unlock(&routing_table_lock);
2395
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002396 xprt->priv = xprt_info;
2397
2398 return 0;
2399}
2400
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002401static void msm_ipc_router_remove_xprt(struct msm_ipc_router_xprt *xprt)
2402{
2403 struct msm_ipc_router_xprt_info *xprt_info;
2404
2405 if (xprt && xprt->priv) {
2406 xprt_info = xprt->priv;
2407
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06002408 mutex_lock(&xprt_info->rx_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002409 xprt_info->abort_data_read = 1;
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06002410 mutex_unlock(&xprt_info->rx_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002411
2412 mutex_lock(&xprt_info_list_lock);
2413 list_del(&xprt_info->list);
2414 mutex_unlock(&xprt_info_list_lock);
2415
2416 flush_workqueue(xprt_info->workqueue);
2417 destroy_workqueue(xprt_info->workqueue);
2418 wake_lock_destroy(&xprt_info->wakelock);
2419
2420 xprt->priv = 0;
2421 kfree(xprt_info);
2422 }
2423}
2424
2425
2426struct msm_ipc_router_xprt_work {
2427 struct msm_ipc_router_xprt *xprt;
2428 struct work_struct work;
2429};
2430
2431static void xprt_open_worker(struct work_struct *work)
2432{
2433 struct msm_ipc_router_xprt_work *xprt_work =
2434 container_of(work, struct msm_ipc_router_xprt_work, work);
2435
2436 msm_ipc_router_add_xprt(xprt_work->xprt);
2437 kfree(xprt_work);
2438}
2439
2440static void xprt_close_worker(struct work_struct *work)
2441{
2442 struct msm_ipc_router_xprt_work *xprt_work =
2443 container_of(work, struct msm_ipc_router_xprt_work, work);
2444
2445 modem_reset_cleanup(xprt_work->xprt->priv);
2446 msm_ipc_router_remove_xprt(xprt_work->xprt);
2447
2448 if (atomic_dec_return(&pending_close_count) == 0)
2449 wake_up(&subsystem_restart_wait);
2450
2451 kfree(xprt_work);
2452}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002453
2454void msm_ipc_router_xprt_notify(struct msm_ipc_router_xprt *xprt,
2455 unsigned event,
2456 void *data)
2457{
2458 struct msm_ipc_router_xprt_info *xprt_info = xprt->priv;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002459 struct msm_ipc_router_xprt_work *xprt_work;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002460 struct rr_packet *pkt;
Karthikeyan Ramasubramanian4af9f7c2011-09-30 15:55:18 -06002461 unsigned long ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002462
Karthikeyan Ramasubramanian4af9f7c2011-09-30 15:55:18 -06002463 if (!msm_ipc_router_workqueue) {
2464 ret = wait_for_completion_timeout(&msm_ipc_local_router_up,
2465 IPC_ROUTER_INIT_TIMEOUT);
2466 if (!ret || !msm_ipc_router_workqueue) {
2467 pr_err("%s: IPC Router not initialized\n", __func__);
2468 return;
2469 }
2470 }
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002471
2472 switch (event) {
2473 case IPC_ROUTER_XPRT_EVENT_OPEN:
2474 D("open event for '%s'\n", xprt->name);
2475 xprt_work = kmalloc(sizeof(struct msm_ipc_router_xprt_work),
2476 GFP_ATOMIC);
2477 xprt_work->xprt = xprt;
2478 INIT_WORK(&xprt_work->work, xprt_open_worker);
2479 queue_work(msm_ipc_router_workqueue, &xprt_work->work);
2480 break;
2481
2482 case IPC_ROUTER_XPRT_EVENT_CLOSE:
2483 D("close event for '%s'\n", xprt->name);
2484 atomic_inc(&pending_close_count);
2485 xprt_work = kmalloc(sizeof(struct msm_ipc_router_xprt_work),
2486 GFP_ATOMIC);
2487 xprt_work->xprt = xprt;
2488 INIT_WORK(&xprt_work->work, xprt_close_worker);
2489 queue_work(msm_ipc_router_workqueue, &xprt_work->work);
2490 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002491 }
2492
2493 if (!data)
2494 return;
2495
2496 while (!xprt_info) {
2497 msleep(100);
2498 xprt_info = xprt->priv;
2499 }
2500
2501 pkt = clone_pkt((struct rr_packet *)data);
2502 if (!pkt)
2503 return;
2504
2505 mutex_lock(&xprt_info->rx_lock);
2506 list_add_tail(&pkt->list, &xprt_info->pkt_list);
2507 wake_lock(&xprt_info->wakelock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002508 mutex_unlock(&xprt_info->rx_lock);
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06002509 queue_work(xprt_info->workqueue, &xprt_info->read_data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002510}
2511
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002512static int modem_restart_notifier_cb(struct notifier_block *this,
2513 unsigned long code,
2514 void *data);
2515static struct notifier_block msm_ipc_router_nb = {
2516 .notifier_call = modem_restart_notifier_cb,
2517};
2518
2519static int modem_restart_notifier_cb(struct notifier_block *this,
2520 unsigned long code,
2521 void *data)
2522{
2523 switch (code) {
2524 case SUBSYS_BEFORE_SHUTDOWN:
2525 D("%s: SUBSYS_BEFORE_SHUTDOWN\n", __func__);
2526 break;
2527
2528 case SUBSYS_BEFORE_POWERUP:
2529 D("%s: waiting for RPC restart to complete\n", __func__);
2530 wait_event(subsystem_restart_wait,
2531 atomic_read(&pending_close_count) == 0);
2532 D("%s: finished restart wait\n", __func__);
2533 break;
2534
2535 default:
2536 break;
2537 }
2538
2539 return NOTIFY_DONE;
2540}
2541
2542static void *restart_notifier_handle;
2543static __init int msm_ipc_router_modem_restart_late_init(void)
2544{
2545 restart_notifier_handle = subsys_notif_register_notifier("modem",
2546 &msm_ipc_router_nb);
2547 return 0;
2548}
2549late_initcall(msm_ipc_router_modem_restart_late_init);
2550
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002551static int __init msm_ipc_router_init(void)
2552{
2553 int i, ret;
2554 struct msm_ipc_routing_table_entry *rt_entry;
2555
2556 msm_ipc_router_debug_mask |= SMEM_LOG;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002557 msm_ipc_router_workqueue =
2558 create_singlethread_workqueue("msm_ipc_router");
2559 if (!msm_ipc_router_workqueue)
2560 return -ENOMEM;
2561
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002562 debugfs_init();
2563
2564 for (i = 0; i < SRV_HASH_SIZE; i++)
2565 INIT_LIST_HEAD(&server_list[i]);
2566
2567 for (i = 0; i < LP_HASH_SIZE; i++)
2568 INIT_LIST_HEAD(&local_ports[i]);
2569
2570 mutex_lock(&routing_table_lock);
2571 if (!routing_table_inited) {
2572 init_routing_table();
2573 rt_entry = alloc_routing_table_entry(IPC_ROUTER_NID_LOCAL);
2574 add_routing_table_entry(rt_entry);
2575 routing_table_inited = 1;
2576 }
2577 mutex_unlock(&routing_table_lock);
2578
2579 init_waitqueue_head(&newserver_wait);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002580 init_waitqueue_head(&subsystem_restart_wait);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002581 ret = msm_ipc_router_init_sockets();
2582 if (ret < 0)
2583 pr_err("%s: Init sockets failed\n", __func__);
2584
Karthikeyan Ramasubramanian4af9f7c2011-09-30 15:55:18 -06002585 complete_all(&msm_ipc_local_router_up);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002586 return ret;
2587}
2588
2589module_init(msm_ipc_router_init);
2590MODULE_DESCRIPTION("MSM IPC Router");
2591MODULE_LICENSE("GPL v2");