blob: 6fa435a43eaf71045b23c30bdfc1619738fe50f8 [file] [log] [blame]
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -07001/* Copyright (c) 2011-2012, Code Aurora Forum. 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;
133 wait_queue_head_t read_wait;
134 struct wake_lock wakelock;
135 struct mutex rx_lock;
136 struct mutex tx_lock;
137 uint32_t need_len;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600138 uint32_t abort_data_read;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700139 struct work_struct read_data;
140 struct workqueue_struct *workqueue;
141};
142
143#define RT_HASH_SIZE 4
144struct msm_ipc_routing_table_entry {
145 struct list_head list;
146 uint32_t node_id;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600147 uint32_t neighbor_node_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700148 struct list_head remote_port_list[RP_HASH_SIZE];
149 struct msm_ipc_router_xprt_info *xprt_info;
150 struct mutex lock;
151 unsigned long num_tx_bytes;
152 unsigned long num_rx_bytes;
153};
154
155static struct list_head routing_table[RT_HASH_SIZE];
156static DEFINE_MUTEX(routing_table_lock);
157static int routing_table_inited;
158
159static LIST_HEAD(msm_ipc_board_dev_list);
160static DEFINE_MUTEX(msm_ipc_board_dev_list_lock);
161
162static void do_read_data(struct work_struct *work);
163
164#define RR_STATE_IDLE 0
165#define RR_STATE_HEADER 1
166#define RR_STATE_BODY 2
167#define RR_STATE_ERROR 3
168
169#define RESTART_NORMAL 0
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600170#define RESTART_PEND 1
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700171
172/* State for remote ep following restart */
173#define RESTART_QUOTA_ABORT 1
174
175static LIST_HEAD(xprt_info_list);
176static DEFINE_MUTEX(xprt_info_list_lock);
177
178DECLARE_COMPLETION(msm_ipc_remote_router_up);
Karthikeyan Ramasubramanian4af9f7c2011-09-30 15:55:18 -0600179static DECLARE_COMPLETION(msm_ipc_local_router_up);
180#define IPC_ROUTER_INIT_TIMEOUT (10 * HZ)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700181
182static uint32_t next_port_id;
183static DEFINE_MUTEX(next_port_id_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600184static atomic_t pending_close_count = ATOMIC_INIT(0);
185static wait_queue_head_t subsystem_restart_wait;
186static struct workqueue_struct *msm_ipc_router_workqueue;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700187
188enum {
189 CLIENT_PORT,
190 SERVER_PORT,
191 CONTROL_PORT,
192};
193
194enum {
195 DOWN,
196 UP,
197};
198
199static void init_routing_table(void)
200{
201 int i;
202 for (i = 0; i < RT_HASH_SIZE; i++)
203 INIT_LIST_HEAD(&routing_table[i]);
204}
205
206static struct msm_ipc_routing_table_entry *alloc_routing_table_entry(
207 uint32_t node_id)
208{
209 int i;
210 struct msm_ipc_routing_table_entry *rt_entry;
211
212 rt_entry = kmalloc(sizeof(struct msm_ipc_routing_table_entry),
213 GFP_KERNEL);
214 if (!rt_entry) {
215 pr_err("%s: rt_entry allocation failed for %d\n",
216 __func__, node_id);
217 return NULL;
218 }
219
220 for (i = 0; i < RP_HASH_SIZE; i++)
221 INIT_LIST_HEAD(&rt_entry->remote_port_list[i]);
222
223 mutex_init(&rt_entry->lock);
224 rt_entry->node_id = node_id;
225 rt_entry->xprt_info = NULL;
226 return rt_entry;
227}
228
229/*Please take routing_table_lock before calling this function*/
230static int add_routing_table_entry(
231 struct msm_ipc_routing_table_entry *rt_entry)
232{
233 uint32_t key;
234
235 if (!rt_entry)
236 return -EINVAL;
237
238 key = (rt_entry->node_id % RT_HASH_SIZE);
239 list_add_tail(&rt_entry->list, &routing_table[key]);
240 return 0;
241}
242
243/*Please take routing_table_lock before calling this function*/
244static struct msm_ipc_routing_table_entry *lookup_routing_table(
245 uint32_t node_id)
246{
247 uint32_t key = (node_id % RT_HASH_SIZE);
248 struct msm_ipc_routing_table_entry *rt_entry;
249
250 list_for_each_entry(rt_entry, &routing_table[key], list) {
251 if (rt_entry->node_id == node_id)
252 return rt_entry;
253 }
254 return NULL;
255}
256
257struct rr_packet *rr_read(struct msm_ipc_router_xprt_info *xprt_info)
258{
259 struct rr_packet *temp_pkt;
260
261 if (!xprt_info)
262 return NULL;
263
264 mutex_lock(&xprt_info->rx_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600265 while (!(xprt_info->abort_data_read) &&
266 list_empty(&xprt_info->pkt_list)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700267 mutex_unlock(&xprt_info->rx_lock);
268 wait_event(xprt_info->read_wait,
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600269 ((xprt_info->abort_data_read) ||
270 !list_empty(&xprt_info->pkt_list)));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700271 mutex_lock(&xprt_info->rx_lock);
272 }
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600273 if (xprt_info->abort_data_read) {
274 mutex_unlock(&xprt_info->rx_lock);
275 return NULL;
276 }
277
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700278 temp_pkt = list_first_entry(&xprt_info->pkt_list,
279 struct rr_packet, list);
280 list_del(&temp_pkt->list);
281 if (list_empty(&xprt_info->pkt_list))
282 wake_unlock(&xprt_info->wakelock);
283 mutex_unlock(&xprt_info->rx_lock);
284 return temp_pkt;
285}
286
287struct rr_packet *clone_pkt(struct rr_packet *pkt)
288{
289 struct rr_packet *cloned_pkt;
290 struct sk_buff *temp_skb, *cloned_skb;
291 struct sk_buff_head *pkt_fragment_q;
292
293 cloned_pkt = kzalloc(sizeof(struct rr_packet), GFP_KERNEL);
294 if (!cloned_pkt) {
295 pr_err("%s: failure\n", __func__);
296 return NULL;
297 }
298
299 pkt_fragment_q = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
300 if (!pkt_fragment_q) {
301 pr_err("%s: pkt_frag_q alloc failure\n", __func__);
302 kfree(cloned_pkt);
303 return NULL;
304 }
305 skb_queue_head_init(pkt_fragment_q);
306
307 skb_queue_walk(pkt->pkt_fragment_q, temp_skb) {
308 cloned_skb = skb_clone(temp_skb, GFP_KERNEL);
309 if (!cloned_skb)
310 goto fail_clone;
311 skb_queue_tail(pkt_fragment_q, cloned_skb);
312 }
313 cloned_pkt->pkt_fragment_q = pkt_fragment_q;
314 cloned_pkt->length = pkt->length;
315 return cloned_pkt;
316
317fail_clone:
318 while (!skb_queue_empty(pkt_fragment_q)) {
319 temp_skb = skb_dequeue(pkt_fragment_q);
320 kfree_skb(temp_skb);
321 }
322 kfree(pkt_fragment_q);
323 kfree(cloned_pkt);
324 return NULL;
325}
326
327struct rr_packet *create_pkt(struct sk_buff_head *data)
328{
329 struct rr_packet *pkt;
330 struct sk_buff *temp_skb;
331
332 pkt = kzalloc(sizeof(struct rr_packet), GFP_KERNEL);
333 if (!pkt) {
334 pr_err("%s: failure\n", __func__);
335 return NULL;
336 }
337
338 pkt->pkt_fragment_q = data;
339 skb_queue_walk(pkt->pkt_fragment_q, temp_skb)
340 pkt->length += temp_skb->len;
341 return pkt;
342}
343
344void release_pkt(struct rr_packet *pkt)
345{
346 struct sk_buff *temp_skb;
347
348 if (!pkt)
349 return;
350
351 if (!pkt->pkt_fragment_q) {
352 kfree(pkt);
353 return;
354 }
355
356 while (!skb_queue_empty(pkt->pkt_fragment_q)) {
357 temp_skb = skb_dequeue(pkt->pkt_fragment_q);
358 kfree_skb(temp_skb);
359 }
360 kfree(pkt->pkt_fragment_q);
361 kfree(pkt);
362 return;
363}
364
365static int post_control_ports(struct rr_packet *pkt)
366{
367 struct msm_ipc_port *port_ptr;
368 struct rr_packet *cloned_pkt;
369
370 if (!pkt)
371 return -EINVAL;
372
373 mutex_lock(&control_ports_lock);
374 list_for_each_entry(port_ptr, &control_ports, list) {
375 mutex_lock(&port_ptr->port_rx_q_lock);
376 cloned_pkt = clone_pkt(pkt);
377 wake_lock(&port_ptr->port_rx_wake_lock);
378 list_add_tail(&cloned_pkt->list, &port_ptr->port_rx_q);
379 wake_up(&port_ptr->port_rx_wait_q);
380 mutex_unlock(&port_ptr->port_rx_q_lock);
381 }
382 mutex_unlock(&control_ports_lock);
383 return 0;
384}
385
386static uint32_t allocate_port_id(void)
387{
388 uint32_t port_id = 0, prev_port_id, key;
389 struct msm_ipc_port *port_ptr;
390
391 mutex_lock(&next_port_id_lock);
392 prev_port_id = next_port_id;
393 mutex_lock(&local_ports_lock);
394 do {
395 next_port_id++;
396 if ((next_port_id & 0xFFFFFFFE) == 0xFFFFFFFE)
397 next_port_id = 1;
398
399 key = (next_port_id & (LP_HASH_SIZE - 1));
400 if (list_empty(&local_ports[key])) {
401 port_id = next_port_id;
402 break;
403 }
404 list_for_each_entry(port_ptr, &local_ports[key], list) {
405 if (port_ptr->this_port.port_id == next_port_id) {
406 port_id = next_port_id;
407 break;
408 }
409 }
410 if (!port_id) {
411 port_id = next_port_id;
412 break;
413 }
414 port_id = 0;
415 } while (next_port_id != prev_port_id);
416 mutex_unlock(&local_ports_lock);
417 mutex_unlock(&next_port_id_lock);
418
419 return port_id;
420}
421
422void msm_ipc_router_add_local_port(struct msm_ipc_port *port_ptr)
423{
424 uint32_t key;
425
426 if (!port_ptr)
427 return;
428
429 key = (port_ptr->this_port.port_id & (LP_HASH_SIZE - 1));
430 mutex_lock(&local_ports_lock);
431 list_add_tail(&port_ptr->list, &local_ports[key]);
432 mutex_unlock(&local_ports_lock);
433}
434
435struct msm_ipc_port *msm_ipc_router_create_raw_port(void *endpoint,
436 void (*notify)(unsigned event, void *data,
437 void *addr, void *priv),
438 void *priv)
439{
440 struct msm_ipc_port *port_ptr;
441
442 port_ptr = kzalloc(sizeof(struct msm_ipc_port), GFP_KERNEL);
443 if (!port_ptr)
444 return NULL;
445
446 port_ptr->this_port.node_id = IPC_ROUTER_NID_LOCAL;
447 port_ptr->this_port.port_id = allocate_port_id();
448 if (!port_ptr->this_port.port_id) {
449 pr_err("%s: All port ids are in use\n", __func__);
450 kfree(port_ptr);
451 return NULL;
452 }
453
454 spin_lock_init(&port_ptr->port_lock);
455 INIT_LIST_HEAD(&port_ptr->incomplete);
456 mutex_init(&port_ptr->incomplete_lock);
457 INIT_LIST_HEAD(&port_ptr->port_rx_q);
458 mutex_init(&port_ptr->port_rx_q_lock);
459 init_waitqueue_head(&port_ptr->port_rx_wait_q);
Karthikeyan Ramasubramanianb4aeeb92012-03-13 12:31:43 -0600460 snprintf(port_ptr->rx_wakelock_name, MAX_WAKELOCK_NAME_SZ,
461 "msm_ipc_read%08x:%08x",
462 port_ptr->this_port.node_id,
463 port_ptr->this_port.port_id);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700464 wake_lock_init(&port_ptr->port_rx_wake_lock,
Karthikeyan Ramasubramanianb4aeeb92012-03-13 12:31:43 -0600465 WAKE_LOCK_SUSPEND, port_ptr->rx_wakelock_name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700466
467 port_ptr->endpoint = endpoint;
468 port_ptr->notify = notify;
469 port_ptr->priv = priv;
470
471 msm_ipc_router_add_local_port(port_ptr);
472 return port_ptr;
473}
474
475static 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
480 mutex_lock(&local_ports_lock);
481 list_for_each_entry(port_ptr, &local_ports[key], list) {
482 if (port_ptr->this_port.port_id == port_id) {
483 mutex_unlock(&local_ports_lock);
484 return port_ptr;
485 }
486 }
487 mutex_unlock(&local_ports_lock);
488 return NULL;
489}
490
491static struct msm_ipc_router_remote_port *msm_ipc_router_lookup_remote_port(
492 uint32_t node_id,
493 uint32_t port_id)
494{
495 struct msm_ipc_router_remote_port *rport_ptr;
496 struct msm_ipc_routing_table_entry *rt_entry;
497 int key = (port_id & (RP_HASH_SIZE - 1));
498
499 mutex_lock(&routing_table_lock);
500 rt_entry = lookup_routing_table(node_id);
501 if (!rt_entry) {
502 mutex_unlock(&routing_table_lock);
503 pr_err("%s: Node is not up\n", __func__);
504 return NULL;
505 }
506
507 mutex_lock(&rt_entry->lock);
508 list_for_each_entry(rport_ptr,
509 &rt_entry->remote_port_list[key], list) {
510 if (rport_ptr->port_id == port_id) {
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600511 if (rport_ptr->restart_state != RESTART_NORMAL)
512 rport_ptr = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700513 mutex_unlock(&rt_entry->lock);
514 mutex_unlock(&routing_table_lock);
515 return rport_ptr;
516 }
517 }
518 mutex_unlock(&rt_entry->lock);
519 mutex_unlock(&routing_table_lock);
520 return NULL;
521}
522
523static struct msm_ipc_router_remote_port *msm_ipc_router_create_remote_port(
524 uint32_t node_id,
525 uint32_t port_id)
526{
527 struct msm_ipc_router_remote_port *rport_ptr;
528 struct msm_ipc_routing_table_entry *rt_entry;
529 int key = (port_id & (RP_HASH_SIZE - 1));
530
531 mutex_lock(&routing_table_lock);
532 rt_entry = lookup_routing_table(node_id);
533 if (!rt_entry) {
534 mutex_unlock(&routing_table_lock);
535 pr_err("%s: Node is not up\n", __func__);
536 return NULL;
537 }
538
539 mutex_lock(&rt_entry->lock);
540 rport_ptr = kmalloc(sizeof(struct msm_ipc_router_remote_port),
541 GFP_KERNEL);
542 if (!rport_ptr) {
543 mutex_unlock(&rt_entry->lock);
544 mutex_unlock(&routing_table_lock);
545 pr_err("%s: Remote port alloc failed\n", __func__);
546 return NULL;
547 }
548 rport_ptr->port_id = port_id;
549 rport_ptr->node_id = node_id;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600550 rport_ptr->restart_state = RESTART_NORMAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700551 rport_ptr->tx_quota_cnt = 0;
552 init_waitqueue_head(&rport_ptr->quota_wait);
553 mutex_init(&rport_ptr->quota_lock);
554 list_add_tail(&rport_ptr->list,
555 &rt_entry->remote_port_list[key]);
556 mutex_unlock(&rt_entry->lock);
557 mutex_unlock(&routing_table_lock);
558 return rport_ptr;
559}
560
561static void msm_ipc_router_destroy_remote_port(
562 struct msm_ipc_router_remote_port *rport_ptr)
563{
564 uint32_t node_id;
565 struct msm_ipc_routing_table_entry *rt_entry;
566
567 if (!rport_ptr)
568 return;
569
570 node_id = rport_ptr->node_id;
571 mutex_lock(&routing_table_lock);
572 rt_entry = lookup_routing_table(node_id);
573 if (!rt_entry) {
574 mutex_unlock(&routing_table_lock);
575 pr_err("%s: Node %d is not up\n", __func__, node_id);
576 return;
577 }
578
579 mutex_lock(&rt_entry->lock);
580 list_del(&rport_ptr->list);
581 kfree(rport_ptr);
582 mutex_unlock(&rt_entry->lock);
583 mutex_unlock(&routing_table_lock);
584 return;
585}
586
587static struct msm_ipc_server *msm_ipc_router_lookup_server(
588 uint32_t service,
589 uint32_t instance,
590 uint32_t node_id,
591 uint32_t port_id)
592{
593 struct msm_ipc_server *server;
594 struct msm_ipc_server_port *server_port;
595 int key = (instance & (SRV_HASH_SIZE - 1));
596
597 mutex_lock(&server_list_lock);
598 list_for_each_entry(server, &server_list[key], list) {
599 if ((server->name.service != service) ||
600 (server->name.instance != instance))
601 continue;
602 if ((node_id == 0) && (port_id == 0)) {
603 mutex_unlock(&server_list_lock);
604 return server;
605 }
606 list_for_each_entry(server_port, &server->server_port_list,
607 list) {
608 if ((server_port->server_addr.node_id == node_id) &&
609 (server_port->server_addr.port_id == port_id)) {
610 mutex_unlock(&server_list_lock);
611 return server;
612 }
613 }
614 }
615 mutex_unlock(&server_list_lock);
616 return NULL;
617}
618
619static struct msm_ipc_server *msm_ipc_router_create_server(
620 uint32_t service,
621 uint32_t instance,
622 uint32_t node_id,
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600623 uint32_t port_id,
624 struct msm_ipc_router_xprt_info *xprt_info)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700625{
626 struct msm_ipc_server *server = NULL;
627 struct msm_ipc_server_port *server_port;
628 int key = (instance & (SRV_HASH_SIZE - 1));
629
630 mutex_lock(&server_list_lock);
631 list_for_each_entry(server, &server_list[key], list) {
632 if ((server->name.service == service) &&
633 (server->name.instance == instance))
634 goto create_srv_port;
635 }
636
637 server = kmalloc(sizeof(struct msm_ipc_server), GFP_KERNEL);
638 if (!server) {
639 mutex_unlock(&server_list_lock);
640 pr_err("%s: Server allocation failed\n", __func__);
641 return NULL;
642 }
643 server->name.service = service;
644 server->name.instance = instance;
645 INIT_LIST_HEAD(&server->server_port_list);
646 list_add_tail(&server->list, &server_list[key]);
647
648create_srv_port:
649 server_port = kmalloc(sizeof(struct msm_ipc_server_port), GFP_KERNEL);
650 if (!server_port) {
651 if (list_empty(&server->server_port_list)) {
652 list_del(&server->list);
653 kfree(server);
654 }
655 mutex_unlock(&server_list_lock);
656 pr_err("%s: Server Port allocation failed\n", __func__);
657 return NULL;
658 }
659 server_port->server_addr.node_id = node_id;
660 server_port->server_addr.port_id = port_id;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600661 server_port->xprt_info = xprt_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700662 list_add_tail(&server_port->list, &server->server_port_list);
663 mutex_unlock(&server_list_lock);
664
665 return server;
666}
667
668static void msm_ipc_router_destroy_server(struct msm_ipc_server *server,
669 uint32_t node_id, uint32_t port_id)
670{
671 struct msm_ipc_server_port *server_port;
672
673 if (!server)
674 return;
675
676 mutex_lock(&server_list_lock);
677 list_for_each_entry(server_port, &server->server_port_list, list) {
678 if ((server_port->server_addr.node_id == node_id) &&
679 (server_port->server_addr.port_id == port_id))
680 break;
681 }
682 if (server_port) {
683 list_del(&server_port->list);
684 kfree(server_port);
685 }
686 if (list_empty(&server->server_port_list)) {
687 list_del(&server->list);
688 kfree(server);
689 }
690 mutex_unlock(&server_list_lock);
691 return;
692}
693
694static int msm_ipc_router_send_control_msg(
695 struct msm_ipc_router_xprt_info *xprt_info,
696 union rr_control_msg *msg)
697{
698 struct rr_packet *pkt;
699 struct sk_buff *ipc_rtr_pkt;
700 struct rr_header *hdr;
701 int pkt_size;
702 void *data;
703 struct sk_buff_head *pkt_fragment_q;
704 int ret;
705
706 if (!xprt_info || ((msg->cmd != IPC_ROUTER_CTRL_CMD_HELLO) &&
707 !xprt_info->initialized)) {
708 pr_err("%s: xprt_info not initialized\n", __func__);
709 return -EINVAL;
710 }
711
712 if (xprt_info->remote_node_id == IPC_ROUTER_NID_LOCAL)
713 return 0;
714
715 pkt = kzalloc(sizeof(struct rr_packet), GFP_KERNEL);
716 if (!pkt) {
717 pr_err("%s: pkt alloc failed\n", __func__);
718 return -ENOMEM;
719 }
720
721 pkt_fragment_q = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
722 if (!pkt_fragment_q) {
723 pr_err("%s: pkt_fragment_q alloc failed\n", __func__);
724 kfree(pkt);
725 return -ENOMEM;
726 }
727 skb_queue_head_init(pkt_fragment_q);
728
729 pkt_size = IPC_ROUTER_HDR_SIZE + sizeof(*msg);
730 ipc_rtr_pkt = alloc_skb(pkt_size, GFP_KERNEL);
731 if (!ipc_rtr_pkt) {
732 pr_err("%s: ipc_rtr_pkt alloc failed\n", __func__);
733 kfree(pkt_fragment_q);
734 kfree(pkt);
735 return -ENOMEM;
736 }
737
738 skb_reserve(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
739 data = skb_put(ipc_rtr_pkt, sizeof(*msg));
740 memcpy(data, msg, sizeof(*msg));
741 hdr = (struct rr_header *)skb_push(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
742 if (!hdr) {
743 pr_err("%s: skb_push failed\n", __func__);
744 kfree_skb(ipc_rtr_pkt);
745 kfree(pkt_fragment_q);
746 kfree(pkt);
747 return -ENOMEM;
748 }
749
750 hdr->version = IPC_ROUTER_VERSION;
751 hdr->type = msg->cmd;
752 hdr->src_node_id = IPC_ROUTER_NID_LOCAL;
753 hdr->src_port_id = IPC_ROUTER_ADDRESS;
754 hdr->confirm_rx = 0;
755 hdr->size = sizeof(*msg);
756 hdr->dst_node_id = xprt_info->remote_node_id;
757 hdr->dst_port_id = IPC_ROUTER_ADDRESS;
758 skb_queue_tail(pkt_fragment_q, ipc_rtr_pkt);
759 pkt->pkt_fragment_q = pkt_fragment_q;
760 pkt->length = pkt_size;
761
762 mutex_lock(&xprt_info->tx_lock);
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700763 ret = xprt_info->xprt->write(pkt, pkt_size, xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700764 mutex_unlock(&xprt_info->tx_lock);
765
766 release_pkt(pkt);
767 return ret;
768}
769
770static int msm_ipc_router_send_server_list(
771 struct msm_ipc_router_xprt_info *xprt_info)
772{
773 union rr_control_msg ctl;
774 struct msm_ipc_server *server;
775 struct msm_ipc_server_port *server_port;
776 int i;
777
778 if (!xprt_info || !xprt_info->initialized) {
779 pr_err("%s: Xprt info not initialized\n", __func__);
780 return -EINVAL;
781 }
782
783 ctl.cmd = IPC_ROUTER_CTRL_CMD_NEW_SERVER;
784
785 mutex_lock(&server_list_lock);
786 for (i = 0; i < SRV_HASH_SIZE; i++) {
787 list_for_each_entry(server, &server_list[i], list) {
788 ctl.srv.service = server->name.service;
789 ctl.srv.instance = server->name.instance;
790 list_for_each_entry(server_port,
791 &server->server_port_list, list) {
792 if (server_port->server_addr.node_id ==
793 xprt_info->remote_node_id)
794 continue;
795
796 ctl.srv.node_id =
797 server_port->server_addr.node_id;
798 ctl.srv.port_id =
799 server_port->server_addr.port_id;
800 msm_ipc_router_send_control_msg(xprt_info,
801 &ctl);
802 }
803 }
804 }
805 mutex_unlock(&server_list_lock);
806
807 return 0;
808}
809
810#if defined(DEBUG)
811static char *type_to_str(int i)
812{
813 switch (i) {
814 case IPC_ROUTER_CTRL_CMD_DATA:
815 return "data ";
816 case IPC_ROUTER_CTRL_CMD_HELLO:
817 return "hello ";
818 case IPC_ROUTER_CTRL_CMD_BYE:
819 return "bye ";
820 case IPC_ROUTER_CTRL_CMD_NEW_SERVER:
821 return "new_srvr";
822 case IPC_ROUTER_CTRL_CMD_REMOVE_SERVER:
823 return "rmv_srvr";
824 case IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT:
825 return "rmv_clnt";
826 case IPC_ROUTER_CTRL_CMD_RESUME_TX:
827 return "resum_tx";
828 case IPC_ROUTER_CTRL_CMD_EXIT:
829 return "cmd_exit";
830 default:
831 return "invalid";
832 }
833}
834#endif
835
836static int broadcast_ctl_msg_locally(union rr_control_msg *msg)
837{
838 struct rr_packet *pkt;
839 struct sk_buff *ipc_rtr_pkt;
840 struct rr_header *hdr;
841 int pkt_size;
842 void *data;
843 struct sk_buff_head *pkt_fragment_q;
844 int ret;
845
846 pkt = kzalloc(sizeof(struct rr_packet), GFP_KERNEL);
847 if (!pkt) {
848 pr_err("%s: pkt alloc failed\n", __func__);
849 return -ENOMEM;
850 }
851
852 pkt_fragment_q = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
853 if (!pkt_fragment_q) {
854 pr_err("%s: pkt_fragment_q alloc failed\n", __func__);
855 kfree(pkt);
856 return -ENOMEM;
857 }
858 skb_queue_head_init(pkt_fragment_q);
859
860 pkt_size = IPC_ROUTER_HDR_SIZE + sizeof(*msg);
861 ipc_rtr_pkt = alloc_skb(pkt_size, GFP_KERNEL);
862 if (!ipc_rtr_pkt) {
863 pr_err("%s: ipc_rtr_pkt alloc failed\n", __func__);
864 kfree(pkt_fragment_q);
865 kfree(pkt);
866 return -ENOMEM;
867 }
868
869 skb_reserve(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
870 data = skb_put(ipc_rtr_pkt, sizeof(*msg));
871 memcpy(data, msg, sizeof(*msg));
872 hdr = (struct rr_header *)skb_push(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
873 if (!hdr) {
874 pr_err("%s: skb_push failed\n", __func__);
875 kfree_skb(ipc_rtr_pkt);
876 kfree(pkt_fragment_q);
877 kfree(pkt);
878 return -ENOMEM;
879 }
880 hdr->version = IPC_ROUTER_VERSION;
881 hdr->type = msg->cmd;
882 hdr->src_node_id = IPC_ROUTER_NID_LOCAL;
883 hdr->src_port_id = IPC_ROUTER_ADDRESS;
884 hdr->confirm_rx = 0;
885 hdr->size = sizeof(*msg);
886 hdr->dst_node_id = IPC_ROUTER_NID_LOCAL;
887 hdr->dst_port_id = IPC_ROUTER_ADDRESS;
888 skb_queue_tail(pkt_fragment_q, ipc_rtr_pkt);
889 pkt->pkt_fragment_q = pkt_fragment_q;
890 pkt->length = pkt_size;
891
892 ret = post_control_ports(pkt);
893 release_pkt(pkt);
894 return ret;
895}
896
897static int broadcast_ctl_msg(union rr_control_msg *ctl)
898{
899 struct msm_ipc_router_xprt_info *xprt_info;
900
901 mutex_lock(&xprt_info_list_lock);
902 list_for_each_entry(xprt_info, &xprt_info_list, list) {
903 msm_ipc_router_send_control_msg(xprt_info, ctl);
904 }
905 mutex_unlock(&xprt_info_list_lock);
906
907 return 0;
908}
909
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600910static int relay_ctl_msg(struct msm_ipc_router_xprt_info *xprt_info,
911 union rr_control_msg *ctl)
912{
913 struct msm_ipc_router_xprt_info *fwd_xprt_info;
914
915 if (!xprt_info || !ctl)
916 return -EINVAL;
917
918 mutex_lock(&xprt_info_list_lock);
919 list_for_each_entry(fwd_xprt_info, &xprt_info_list, list) {
920 if (xprt_info->xprt->link_id != fwd_xprt_info->xprt->link_id)
921 msm_ipc_router_send_control_msg(fwd_xprt_info, ctl);
922 }
923 mutex_unlock(&xprt_info_list_lock);
924
925 return 0;
926}
927
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700928static int relay_msg(struct msm_ipc_router_xprt_info *xprt_info,
929 struct rr_packet *pkt)
930{
931 struct msm_ipc_router_xprt_info *fwd_xprt_info;
932
933 if (!xprt_info || !pkt)
934 return -EINVAL;
935
936 mutex_lock(&xprt_info_list_lock);
937 list_for_each_entry(fwd_xprt_info, &xprt_info_list, list) {
938 mutex_lock(&fwd_xprt_info->tx_lock);
939 if (xprt_info->xprt->link_id != fwd_xprt_info->xprt->link_id)
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700940 fwd_xprt_info->xprt->write(pkt, pkt->length,
941 fwd_xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700942 mutex_unlock(&fwd_xprt_info->tx_lock);
943 }
944 mutex_unlock(&xprt_info_list_lock);
945 return 0;
946}
947
948static int forward_msg(struct msm_ipc_router_xprt_info *xprt_info,
949 struct rr_packet *pkt)
950{
951 uint32_t dst_node_id;
952 struct sk_buff *head_pkt;
953 struct rr_header *hdr;
954 struct msm_ipc_router_xprt_info *fwd_xprt_info;
955 struct msm_ipc_routing_table_entry *rt_entry;
956
957 if (!xprt_info || !pkt)
958 return -EINVAL;
959
960 head_pkt = skb_peek(pkt->pkt_fragment_q);
961 if (!head_pkt)
962 return -EINVAL;
963
964 hdr = (struct rr_header *)head_pkt->data;
965 dst_node_id = hdr->dst_node_id;
966 mutex_lock(&routing_table_lock);
967 rt_entry = lookup_routing_table(dst_node_id);
968 if (!(rt_entry) || !(rt_entry->xprt_info)) {
969 mutex_unlock(&routing_table_lock);
970 pr_err("%s: Routing table not initialized\n", __func__);
971 return -ENODEV;
972 }
973
974 mutex_lock(&rt_entry->lock);
975 fwd_xprt_info = rt_entry->xprt_info;
976 mutex_lock(&fwd_xprt_info->tx_lock);
977 if (xprt_info->remote_node_id == fwd_xprt_info->remote_node_id) {
978 mutex_unlock(&fwd_xprt_info->tx_lock);
979 mutex_unlock(&rt_entry->lock);
980 mutex_unlock(&routing_table_lock);
981 pr_err("%s: Discarding Command to route back\n", __func__);
982 return -EINVAL;
983 }
984
985 if (xprt_info->xprt->link_id == fwd_xprt_info->xprt->link_id) {
986 mutex_unlock(&fwd_xprt_info->tx_lock);
987 mutex_unlock(&rt_entry->lock);
988 mutex_unlock(&routing_table_lock);
989 pr_err("%s: DST in the same cluster\n", __func__);
990 return 0;
991 }
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700992 fwd_xprt_info->xprt->write(pkt, pkt->length, fwd_xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700993 mutex_unlock(&fwd_xprt_info->tx_lock);
994 mutex_unlock(&rt_entry->lock);
995 mutex_unlock(&routing_table_lock);
996
997 return 0;
998}
999
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001000static void reset_remote_port_info(uint32_t node_id, uint32_t port_id)
1001{
1002 struct msm_ipc_router_remote_port *rport_ptr;
1003
1004 rport_ptr = msm_ipc_router_lookup_remote_port(node_id, port_id);
1005 if (!rport_ptr) {
1006 pr_err("%s: No such remote port %08x:%08x\n",
1007 __func__, node_id, port_id);
1008 return;
1009 }
1010 mutex_lock(&rport_ptr->quota_lock);
1011 rport_ptr->restart_state = RESTART_PEND;
1012 wake_up(&rport_ptr->quota_wait);
1013 mutex_unlock(&rport_ptr->quota_lock);
1014 return;
1015}
1016
1017static void msm_ipc_cleanup_remote_server_info(
1018 struct msm_ipc_router_xprt_info *xprt_info)
1019{
1020 struct msm_ipc_server *svr, *tmp_svr;
1021 struct msm_ipc_server_port *svr_port, *tmp_svr_port;
1022 int i;
1023 union rr_control_msg ctl;
1024
1025 if (!xprt_info) {
1026 pr_err("%s: Invalid xprt_info\n", __func__);
1027 return;
1028 }
1029
1030 ctl.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_SERVER;
1031 mutex_lock(&server_list_lock);
1032 for (i = 0; i < SRV_HASH_SIZE; i++) {
1033 list_for_each_entry_safe(svr, tmp_svr, &server_list[i], list) {
1034 ctl.srv.service = svr->name.service;
1035 ctl.srv.instance = svr->name.instance;
1036 list_for_each_entry_safe(svr_port, tmp_svr_port,
1037 &svr->server_port_list, list) {
1038 if (svr_port->xprt_info != xprt_info)
1039 continue;
1040 D("Remove server %08x:%08x - %08x:%08x",
1041 ctl.srv.service, ctl.srv.instance,
1042 svr_port->server_addr.node_id,
1043 svr_port->server_addr.port_id);
1044 reset_remote_port_info(
1045 svr_port->server_addr.node_id,
1046 svr_port->server_addr.port_id);
1047 ctl.srv.node_id = svr_port->server_addr.node_id;
1048 ctl.srv.port_id = svr_port->server_addr.port_id;
1049 relay_ctl_msg(xprt_info, &ctl);
1050 broadcast_ctl_msg_locally(&ctl);
1051 list_del(&svr_port->list);
1052 kfree(svr_port);
1053 }
1054 if (list_empty(&svr->server_port_list)) {
1055 list_del(&svr->list);
1056 kfree(svr);
1057 }
1058 }
1059 }
1060 mutex_unlock(&server_list_lock);
1061}
1062
1063static void msm_ipc_cleanup_remote_client_info(
1064 struct msm_ipc_router_xprt_info *xprt_info)
1065{
1066 struct msm_ipc_routing_table_entry *rt_entry;
1067 struct msm_ipc_router_remote_port *rport_ptr;
1068 int i, j;
1069 union rr_control_msg ctl;
1070
1071 if (!xprt_info) {
1072 pr_err("%s: Invalid xprt_info\n", __func__);
1073 return;
1074 }
1075
1076 ctl.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT;
1077 mutex_lock(&routing_table_lock);
1078 for (i = 0; i < RT_HASH_SIZE; i++) {
1079 list_for_each_entry(rt_entry, &routing_table[i], list) {
1080 mutex_lock(&rt_entry->lock);
1081 if (rt_entry->xprt_info != xprt_info) {
1082 mutex_unlock(&rt_entry->lock);
1083 continue;
1084 }
1085 for (j = 0; j < RP_HASH_SIZE; j++) {
1086 list_for_each_entry(rport_ptr,
1087 &rt_entry->remote_port_list[j], list) {
1088 if (rport_ptr->restart_state ==
1089 RESTART_PEND)
1090 continue;
1091 mutex_lock(&rport_ptr->quota_lock);
1092 rport_ptr->restart_state = RESTART_PEND;
1093 wake_up(&rport_ptr->quota_wait);
1094 mutex_unlock(&rport_ptr->quota_lock);
1095 ctl.cli.node_id = rport_ptr->node_id;
1096 ctl.cli.port_id = rport_ptr->port_id;
1097 broadcast_ctl_msg_locally(&ctl);
1098 }
1099 }
1100 mutex_unlock(&rt_entry->lock);
1101 }
1102 }
1103 mutex_unlock(&routing_table_lock);
1104}
1105
1106static void msm_ipc_cleanup_remote_port_info(uint32_t node_id)
1107{
1108 struct msm_ipc_routing_table_entry *rt_entry, *tmp_rt_entry;
1109 struct msm_ipc_router_remote_port *rport_ptr, *tmp_rport_ptr;
1110 int i, j;
1111
1112 mutex_lock(&routing_table_lock);
1113 for (i = 0; i < RT_HASH_SIZE; i++) {
1114 list_for_each_entry_safe(rt_entry, tmp_rt_entry,
1115 &routing_table[i], list) {
1116 mutex_lock(&rt_entry->lock);
1117 if (rt_entry->neighbor_node_id != node_id) {
1118 mutex_unlock(&rt_entry->lock);
1119 continue;
1120 }
1121 for (j = 0; j < RP_HASH_SIZE; j++) {
1122 list_for_each_entry_safe(rport_ptr,
1123 tmp_rport_ptr,
1124 &rt_entry->remote_port_list[j], list) {
1125 list_del(&rport_ptr->list);
1126 kfree(rport_ptr);
1127 }
1128 }
1129 mutex_unlock(&rt_entry->lock);
1130 }
1131 }
1132 mutex_unlock(&routing_table_lock);
1133}
1134
1135static void msm_ipc_cleanup_routing_table(
1136 struct msm_ipc_router_xprt_info *xprt_info)
1137{
1138 int i;
1139 struct msm_ipc_routing_table_entry *rt_entry;
1140
1141 if (!xprt_info) {
1142 pr_err("%s: Invalid xprt_info\n", __func__);
1143 return;
1144 }
1145
1146 mutex_lock(&routing_table_lock);
1147 for (i = 0; i < RT_HASH_SIZE; i++) {
1148 list_for_each_entry(rt_entry, &routing_table[i], list) {
1149 mutex_lock(&rt_entry->lock);
1150 if (rt_entry->xprt_info == xprt_info)
1151 rt_entry->xprt_info = NULL;
1152 mutex_unlock(&rt_entry->lock);
1153 }
1154 }
1155 mutex_unlock(&routing_table_lock);
1156}
1157
1158static void modem_reset_cleanup(struct msm_ipc_router_xprt_info *xprt_info)
1159{
1160
1161 if (!xprt_info) {
1162 pr_err("%s: Invalid xprt_info\n", __func__);
1163 return;
1164 }
1165
1166 msm_ipc_cleanup_remote_server_info(xprt_info);
1167 msm_ipc_cleanup_remote_client_info(xprt_info);
1168 msm_ipc_cleanup_routing_table(xprt_info);
1169}
1170
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001171static int process_control_msg(struct msm_ipc_router_xprt_info *xprt_info,
1172 struct rr_packet *pkt)
1173{
1174 union rr_control_msg ctl;
1175 union rr_control_msg *msg;
1176 struct msm_ipc_router_remote_port *rport_ptr;
1177 int rc = 0;
1178 static uint32_t first = 1;
1179 struct sk_buff *temp_ptr;
1180 struct rr_header *hdr;
1181 struct msm_ipc_server *server;
1182 struct msm_ipc_routing_table_entry *rt_entry;
1183
1184 if (pkt->length != (IPC_ROUTER_HDR_SIZE + sizeof(*msg))) {
1185 pr_err("%s: r2r msg size %d != %d\n", __func__, pkt->length,
1186 (IPC_ROUTER_HDR_SIZE + sizeof(*msg)));
1187 return -EINVAL;
1188 }
1189
1190 temp_ptr = skb_peek(pkt->pkt_fragment_q);
Karthikeyan Ramasubramanian9024dd82011-12-19 18:44:19 -07001191 if (!temp_ptr) {
1192 pr_err("%s: pkt_fragment_q is empty\n", __func__);
1193 return -EINVAL;
1194 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001195 hdr = (struct rr_header *)temp_ptr->data;
Karthikeyan Ramasubramanian9024dd82011-12-19 18:44:19 -07001196 if (!hdr) {
1197 pr_err("%s: No data inside the skb\n", __func__);
1198 return -EINVAL;
1199 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001200 msg = (union rr_control_msg *)((char *)hdr + IPC_ROUTER_HDR_SIZE);
1201
1202 switch (msg->cmd) {
1203 case IPC_ROUTER_CTRL_CMD_HELLO:
1204 RR("o HELLO NID %d\n", hdr->src_node_id);
1205 xprt_info->remote_node_id = hdr->src_node_id;
1206
1207 mutex_lock(&routing_table_lock);
1208 rt_entry = lookup_routing_table(hdr->src_node_id);
1209 if (!rt_entry) {
1210 rt_entry = alloc_routing_table_entry(hdr->src_node_id);
1211 if (!rt_entry) {
1212 mutex_unlock(&routing_table_lock);
1213 pr_err("%s: rt_entry allocation failed\n",
1214 __func__);
1215 return -ENOMEM;
1216 }
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001217 add_routing_table_entry(rt_entry);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001218 }
1219 mutex_lock(&rt_entry->lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001220 rt_entry->neighbor_node_id = xprt_info->remote_node_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001221 rt_entry->xprt_info = xprt_info;
1222 mutex_unlock(&rt_entry->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001223 mutex_unlock(&routing_table_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001224 msm_ipc_cleanup_remote_port_info(xprt_info->remote_node_id);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001225
1226 memset(&ctl, 0, sizeof(ctl));
1227 ctl.cmd = IPC_ROUTER_CTRL_CMD_HELLO;
1228 msm_ipc_router_send_control_msg(xprt_info, &ctl);
1229
1230 xprt_info->initialized = 1;
1231
1232 /* Send list of servers one at a time */
1233 msm_ipc_router_send_server_list(xprt_info);
1234
1235 if (first) {
1236 first = 0;
1237 complete_all(&msm_ipc_remote_router_up);
1238 }
1239 RR("HELLO message processed\n");
1240 break;
1241 case IPC_ROUTER_CTRL_CMD_RESUME_TX:
1242 RR("o RESUME_TX id=%d:%08x\n",
1243 msg->cli.node_id, msg->cli.port_id);
1244
1245 rport_ptr = msm_ipc_router_lookup_remote_port(msg->cli.node_id,
1246 msg->cli.port_id);
1247 if (!rport_ptr) {
1248 pr_err("%s: Unable to resume client\n", __func__);
1249 break;
1250 }
1251 mutex_lock(&rport_ptr->quota_lock);
1252 rport_ptr->tx_quota_cnt = 0;
1253 mutex_unlock(&rport_ptr->quota_lock);
1254 wake_up(&rport_ptr->quota_wait);
1255 break;
1256
1257 case IPC_ROUTER_CTRL_CMD_NEW_SERVER:
1258 if (msg->srv.instance == 0) {
1259 pr_err(
1260 "rpcrouter: Server create rejected, version = 0, "
1261 "service = %08x\n", msg->srv.service);
1262 break;
1263 }
1264
1265 RR("o NEW_SERVER id=%d:%08x service=%08x:%08x\n",
1266 msg->srv.node_id, msg->srv.port_id,
1267 msg->srv.service, msg->srv.instance);
1268
1269 mutex_lock(&routing_table_lock);
1270 rt_entry = lookup_routing_table(msg->srv.node_id);
1271 if (!rt_entry) {
1272 rt_entry = alloc_routing_table_entry(msg->srv.node_id);
1273 if (!rt_entry) {
1274 mutex_unlock(&routing_table_lock);
1275 pr_err("%s: rt_entry allocation failed\n",
1276 __func__);
1277 return -ENOMEM;
1278 }
1279 mutex_lock(&rt_entry->lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001280 rt_entry->neighbor_node_id = xprt_info->remote_node_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001281 rt_entry->xprt_info = xprt_info;
1282 mutex_unlock(&rt_entry->lock);
1283 add_routing_table_entry(rt_entry);
1284 }
1285 mutex_unlock(&routing_table_lock);
1286
1287 server = msm_ipc_router_lookup_server(msg->srv.service,
1288 msg->srv.instance,
1289 msg->srv.node_id,
1290 msg->srv.port_id);
1291 if (!server) {
1292 server = msm_ipc_router_create_server(
1293 msg->srv.service, msg->srv.instance,
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001294 msg->srv.node_id, msg->srv.port_id, xprt_info);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001295 if (!server) {
1296 pr_err("%s: Server Create failed\n", __func__);
1297 return -ENOMEM;
1298 }
1299
1300 if (!msm_ipc_router_lookup_remote_port(
1301 msg->srv.node_id, msg->srv.port_id)) {
1302 rport_ptr = msm_ipc_router_create_remote_port(
1303 msg->srv.node_id, msg->srv.port_id);
1304 if (!rport_ptr)
1305 pr_err("%s: Remote port create "
1306 "failed\n", __func__);
1307 }
1308 wake_up(&newserver_wait);
1309 }
1310
1311 relay_msg(xprt_info, pkt);
1312 post_control_ports(pkt);
1313 break;
1314 case IPC_ROUTER_CTRL_CMD_REMOVE_SERVER:
1315 RR("o REMOVE_SERVER service=%08x:%d\n",
1316 msg->srv.service, msg->srv.instance);
1317 server = msm_ipc_router_lookup_server(msg->srv.service,
1318 msg->srv.instance,
1319 msg->srv.node_id,
1320 msg->srv.port_id);
1321 if (server) {
1322 msm_ipc_router_destroy_server(server,
1323 msg->srv.node_id,
1324 msg->srv.port_id);
1325 relay_msg(xprt_info, pkt);
1326 post_control_ports(pkt);
1327 }
1328 break;
1329 case IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT:
1330 RR("o REMOVE_CLIENT id=%d:%08x\n",
1331 msg->cli.node_id, msg->cli.port_id);
1332 rport_ptr = msm_ipc_router_lookup_remote_port(msg->cli.node_id,
1333 msg->cli.port_id);
1334 if (rport_ptr)
1335 msm_ipc_router_destroy_remote_port(rport_ptr);
1336
1337 relay_msg(xprt_info, pkt);
1338 post_control_ports(pkt);
1339 break;
1340 case IPC_ROUTER_CTRL_CMD_PING:
1341 /* No action needed for ping messages received */
1342 RR("o PING\n");
1343 break;
1344 default:
1345 RR("o UNKNOWN(%08x)\n", msg->cmd);
1346 rc = -ENOSYS;
1347 }
1348
1349 return rc;
1350}
1351
1352static void do_read_data(struct work_struct *work)
1353{
1354 struct rr_header *hdr;
1355 struct rr_packet *pkt = NULL;
1356 struct msm_ipc_port *port_ptr;
1357 struct sk_buff *head_skb;
1358 struct msm_ipc_port_addr *src_addr;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001359 struct msm_ipc_router_remote_port *rport_ptr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001360 uint32_t resume_tx, resume_tx_node_id, resume_tx_port_id;
1361
1362 struct msm_ipc_router_xprt_info *xprt_info =
1363 container_of(work,
1364 struct msm_ipc_router_xprt_info,
1365 read_data);
1366
1367 pkt = rr_read(xprt_info);
1368 if (!pkt) {
1369 pr_err("%s: rr_read failed\n", __func__);
1370 goto fail_io;
1371 }
1372
1373 if (pkt->length < IPC_ROUTER_HDR_SIZE ||
1374 pkt->length > MAX_IPC_PKT_SIZE) {
1375 pr_err("%s: Invalid pkt length %d\n", __func__, pkt->length);
1376 goto fail_data;
1377 }
1378
1379 head_skb = skb_peek(pkt->pkt_fragment_q);
1380 if (!head_skb) {
1381 pr_err("%s: head_skb is invalid\n", __func__);
1382 goto fail_data;
1383 }
1384
1385 hdr = (struct rr_header *)(head_skb->data);
1386 RR("- ver=%d type=%d src=%d:%08x crx=%d siz=%d dst=%d:%08x\n",
1387 hdr->version, hdr->type, hdr->src_node_id, hdr->src_port_id,
1388 hdr->confirm_rx, hdr->size, hdr->dst_node_id, hdr->dst_port_id);
1389 RAW_HDR("[r rr_h] "
1390 "ver=%i,type=%s,src_node_id=%08x,src_port_id=%08x,"
1391 "confirm_rx=%i,size=%3i,dst_node_id=%08x,dst_port_id=%08x\n",
1392 hdr->version, type_to_str(hdr->type), hdr->src_node_id,
1393 hdr->src_port_id, hdr->confirm_rx, hdr->size, hdr->dst_node_id,
1394 hdr->dst_port_id);
1395
1396 if (hdr->version != IPC_ROUTER_VERSION) {
1397 pr_err("version %d != %d\n", hdr->version, IPC_ROUTER_VERSION);
1398 goto fail_data;
1399 }
1400
1401 if ((hdr->dst_node_id != IPC_ROUTER_NID_LOCAL) &&
1402 ((hdr->type == IPC_ROUTER_CTRL_CMD_RESUME_TX) ||
1403 (hdr->type == IPC_ROUTER_CTRL_CMD_DATA))) {
1404 forward_msg(xprt_info, pkt);
1405 release_pkt(pkt);
1406 goto done;
1407 }
1408
1409 if ((hdr->dst_port_id == IPC_ROUTER_ADDRESS) ||
1410 (hdr->type == IPC_ROUTER_CTRL_CMD_HELLO)) {
1411 process_control_msg(xprt_info, pkt);
1412 release_pkt(pkt);
1413 goto done;
1414 }
1415#if defined(CONFIG_MSM_SMD_LOGGING)
1416#if defined(DEBUG)
1417 if (msm_ipc_router_debug_mask & SMEM_LOG) {
1418 smem_log_event((SMEM_LOG_PROC_ID_APPS |
1419 SMEM_LOG_RPC_ROUTER_EVENT_BASE |
1420 IPC_ROUTER_LOG_EVENT_RX),
1421 (hdr->src_node_id << 24) |
1422 (hdr->src_port_id & 0xffffff),
1423 (hdr->dst_node_id << 24) |
1424 (hdr->dst_port_id & 0xffffff),
1425 (hdr->type << 24) | (hdr->confirm_rx << 16) |
1426 (hdr->size & 0xffff));
1427 }
1428#endif
1429#endif
1430
1431 resume_tx = hdr->confirm_rx;
1432 resume_tx_node_id = hdr->dst_node_id;
1433 resume_tx_port_id = hdr->dst_port_id;
1434
1435 port_ptr = msm_ipc_router_lookup_local_port(hdr->dst_port_id);
1436 if (!port_ptr) {
1437 pr_err("%s: No local port id %08x\n", __func__,
1438 hdr->dst_port_id);
1439 release_pkt(pkt);
1440 goto process_done;
1441 }
1442
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001443 rport_ptr = msm_ipc_router_lookup_remote_port(hdr->src_node_id,
1444 hdr->src_port_id);
1445 if (!rport_ptr) {
1446 rport_ptr = msm_ipc_router_create_remote_port(
1447 hdr->src_node_id,
1448 hdr->src_port_id);
1449 if (!rport_ptr) {
1450 pr_err("%s: Remote port %08x:%08x creation failed\n",
1451 __func__, hdr->src_node_id, hdr->src_port_id);
1452 goto process_done;
1453 }
1454 }
1455
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001456 if (!port_ptr->notify) {
1457 mutex_lock(&port_ptr->port_rx_q_lock);
1458 wake_lock(&port_ptr->port_rx_wake_lock);
1459 list_add_tail(&pkt->list, &port_ptr->port_rx_q);
1460 wake_up(&port_ptr->port_rx_wait_q);
1461 mutex_unlock(&port_ptr->port_rx_q_lock);
1462 } else {
1463 src_addr = kmalloc(sizeof(struct msm_ipc_port_addr),
1464 GFP_KERNEL);
1465 if (src_addr) {
1466 src_addr->node_id = hdr->src_node_id;
1467 src_addr->port_id = hdr->src_port_id;
1468 }
1469 skb_pull(head_skb, IPC_ROUTER_HDR_SIZE);
1470 port_ptr->notify(MSM_IPC_ROUTER_READ_CB, pkt->pkt_fragment_q,
1471 src_addr, port_ptr->priv);
1472 pkt->pkt_fragment_q = NULL;
1473 src_addr = NULL;
1474 release_pkt(pkt);
1475 }
1476
1477process_done:
1478 if (resume_tx) {
1479 union rr_control_msg msg;
1480
1481 msg.cmd = IPC_ROUTER_CTRL_CMD_RESUME_TX;
1482 msg.cli.node_id = resume_tx_node_id;
1483 msg.cli.port_id = resume_tx_port_id;
1484
1485 RR("x RESUME_TX id=%d:%08x\n",
1486 msg.cli.node_id, msg.cli.port_id);
1487 msm_ipc_router_send_control_msg(xprt_info, &msg);
1488 }
1489
1490done:
1491 queue_work(xprt_info->workqueue, &xprt_info->read_data);
1492 return;
1493
1494fail_data:
1495 release_pkt(pkt);
1496fail_io:
1497 pr_err("ipc_router has died\n");
1498}
1499
1500int msm_ipc_router_register_server(struct msm_ipc_port *port_ptr,
1501 struct msm_ipc_addr *name)
1502{
1503 struct msm_ipc_server *server;
1504 unsigned long flags;
1505 union rr_control_msg ctl;
1506
1507 if (!port_ptr || !name)
1508 return -EINVAL;
1509
1510 if (name->addrtype != MSM_IPC_ADDR_NAME)
1511 return -EINVAL;
1512
1513 server = msm_ipc_router_lookup_server(name->addr.port_name.service,
1514 name->addr.port_name.instance,
1515 IPC_ROUTER_NID_LOCAL,
1516 port_ptr->this_port.port_id);
1517 if (server) {
1518 pr_err("%s: Server already present\n", __func__);
1519 return -EINVAL;
1520 }
1521
1522 server = msm_ipc_router_create_server(name->addr.port_name.service,
1523 name->addr.port_name.instance,
1524 IPC_ROUTER_NID_LOCAL,
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001525 port_ptr->this_port.port_id,
1526 NULL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001527 if (!server) {
1528 pr_err("%s: Server Creation failed\n", __func__);
1529 return -EINVAL;
1530 }
1531
1532 ctl.cmd = IPC_ROUTER_CTRL_CMD_NEW_SERVER;
1533 ctl.srv.service = server->name.service;
1534 ctl.srv.instance = server->name.instance;
1535 ctl.srv.node_id = IPC_ROUTER_NID_LOCAL;
1536 ctl.srv.port_id = port_ptr->this_port.port_id;
1537 broadcast_ctl_msg(&ctl);
1538 spin_lock_irqsave(&port_ptr->port_lock, flags);
1539 port_ptr->type = SERVER_PORT;
1540 port_ptr->port_name.service = server->name.service;
1541 port_ptr->port_name.instance = server->name.instance;
1542 spin_unlock_irqrestore(&port_ptr->port_lock, flags);
1543 return 0;
1544}
1545
1546int msm_ipc_router_unregister_server(struct msm_ipc_port *port_ptr)
1547{
1548 struct msm_ipc_server *server;
1549 unsigned long flags;
1550 union rr_control_msg ctl;
1551
1552 if (!port_ptr)
1553 return -EINVAL;
1554
1555 if (port_ptr->type != SERVER_PORT) {
1556 pr_err("%s: Trying to unregister a non-server port\n",
1557 __func__);
1558 return -EINVAL;
1559 }
1560
1561 if (port_ptr->this_port.node_id != IPC_ROUTER_NID_LOCAL) {
1562 pr_err("%s: Trying to unregister a remote server locally\n",
1563 __func__);
1564 return -EINVAL;
1565 }
1566
1567 server = msm_ipc_router_lookup_server(port_ptr->port_name.service,
1568 port_ptr->port_name.instance,
1569 port_ptr->this_port.node_id,
1570 port_ptr->this_port.port_id);
1571 if (!server) {
1572 pr_err("%s: Server lookup failed\n", __func__);
1573 return -ENODEV;
1574 }
1575
1576 ctl.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_SERVER;
1577 ctl.srv.service = server->name.service;
1578 ctl.srv.instance = server->name.instance;
1579 ctl.srv.node_id = IPC_ROUTER_NID_LOCAL;
1580 ctl.srv.port_id = port_ptr->this_port.port_id;
1581 broadcast_ctl_msg(&ctl);
1582 msm_ipc_router_destroy_server(server, port_ptr->this_port.node_id,
1583 port_ptr->this_port.port_id);
1584 spin_lock_irqsave(&port_ptr->port_lock, flags);
1585 port_ptr->type = CLIENT_PORT;
1586 spin_unlock_irqrestore(&port_ptr->port_lock, flags);
1587 return 0;
1588}
1589
1590static int loopback_data(struct msm_ipc_port *src,
1591 uint32_t port_id,
1592 struct sk_buff_head *data)
1593{
1594 struct sk_buff *head_skb;
1595 struct rr_header *hdr;
1596 struct msm_ipc_port *port_ptr;
1597 struct rr_packet *pkt;
1598
1599 if (!data) {
1600 pr_err("%s: Invalid pkt pointer\n", __func__);
1601 return -EINVAL;
1602 }
1603
1604 pkt = create_pkt(data);
1605 if (!pkt) {
1606 pr_err("%s: New pkt create failed\n", __func__);
1607 return -ENOMEM;
1608 }
1609
1610 head_skb = skb_peek(pkt->pkt_fragment_q);
Karthikeyan Ramasubramanian9024dd82011-12-19 18:44:19 -07001611 if (!head_skb) {
1612 pr_err("%s: pkt_fragment_q is empty\n", __func__);
1613 return -EINVAL;
1614 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001615 hdr = (struct rr_header *)skb_push(head_skb, IPC_ROUTER_HDR_SIZE);
1616 if (!hdr) {
1617 pr_err("%s: Prepend Header failed\n", __func__);
1618 release_pkt(pkt);
1619 return -ENOMEM;
1620 }
1621 hdr->version = IPC_ROUTER_VERSION;
1622 hdr->type = IPC_ROUTER_CTRL_CMD_DATA;
1623 hdr->src_node_id = src->this_port.node_id;
1624 hdr->src_port_id = src->this_port.port_id;
1625 hdr->size = pkt->length;
1626 hdr->confirm_rx = 0;
1627 hdr->dst_node_id = IPC_ROUTER_NID_LOCAL;
1628 hdr->dst_port_id = port_id;
1629 pkt->length += IPC_ROUTER_HDR_SIZE;
1630
1631 port_ptr = msm_ipc_router_lookup_local_port(port_id);
1632 if (!port_ptr) {
1633 pr_err("%s: Local port %d not present\n", __func__, port_id);
1634 release_pkt(pkt);
1635 return -ENODEV;
1636 }
1637
1638 mutex_lock(&port_ptr->port_rx_q_lock);
1639 wake_lock(&port_ptr->port_rx_wake_lock);
1640 list_add_tail(&pkt->list, &port_ptr->port_rx_q);
1641 wake_up(&port_ptr->port_rx_wait_q);
1642 mutex_unlock(&port_ptr->port_rx_q_lock);
1643
1644 return pkt->length;
1645}
1646
1647static int msm_ipc_router_write_pkt(struct msm_ipc_port *src,
1648 struct msm_ipc_router_remote_port *rport_ptr,
1649 struct rr_packet *pkt)
1650{
1651 struct sk_buff *head_skb;
1652 struct rr_header *hdr;
1653 struct msm_ipc_router_xprt_info *xprt_info;
1654 struct msm_ipc_routing_table_entry *rt_entry;
1655 int ret;
1656 DEFINE_WAIT(__wait);
1657
1658 if (!rport_ptr || !src || !pkt)
1659 return -EINVAL;
1660
1661 head_skb = skb_peek(pkt->pkt_fragment_q);
Karthikeyan Ramasubramanian9024dd82011-12-19 18:44:19 -07001662 if (!head_skb) {
1663 pr_err("%s: pkt_fragment_q is empty\n", __func__);
1664 return -EINVAL;
1665 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001666 hdr = (struct rr_header *)skb_push(head_skb, IPC_ROUTER_HDR_SIZE);
1667 if (!hdr) {
1668 pr_err("%s: Prepend Header failed\n", __func__);
1669 return -ENOMEM;
1670 }
1671 hdr->version = IPC_ROUTER_VERSION;
1672 hdr->type = IPC_ROUTER_CTRL_CMD_DATA;
1673 hdr->src_node_id = src->this_port.node_id;
1674 hdr->src_port_id = src->this_port.port_id;
1675 hdr->size = pkt->length;
1676 hdr->confirm_rx = 0;
1677 hdr->dst_node_id = rport_ptr->node_id;
1678 hdr->dst_port_id = rport_ptr->port_id;
1679 pkt->length += IPC_ROUTER_HDR_SIZE;
1680
1681 for (;;) {
1682 prepare_to_wait(&rport_ptr->quota_wait, &__wait,
1683 TASK_INTERRUPTIBLE);
1684 mutex_lock(&rport_ptr->quota_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001685 if (rport_ptr->restart_state != RESTART_NORMAL)
1686 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001687 if (rport_ptr->tx_quota_cnt <
1688 IPC_ROUTER_DEFAULT_RX_QUOTA)
1689 break;
1690 if (signal_pending(current))
1691 break;
1692 mutex_unlock(&rport_ptr->quota_lock);
1693 schedule();
1694 }
1695 finish_wait(&rport_ptr->quota_wait, &__wait);
1696
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001697 if (rport_ptr->restart_state != RESTART_NORMAL) {
1698 mutex_unlock(&rport_ptr->quota_lock);
1699 return -ENETRESET;
1700 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001701 if (signal_pending(current)) {
1702 mutex_unlock(&rport_ptr->quota_lock);
1703 return -ERESTARTSYS;
1704 }
1705 rport_ptr->tx_quota_cnt++;
1706 if (rport_ptr->tx_quota_cnt == IPC_ROUTER_DEFAULT_RX_QUOTA)
1707 hdr->confirm_rx = 1;
1708 mutex_unlock(&rport_ptr->quota_lock);
1709
1710 mutex_lock(&routing_table_lock);
1711 rt_entry = lookup_routing_table(hdr->dst_node_id);
1712 if (!rt_entry || !rt_entry->xprt_info) {
1713 mutex_unlock(&routing_table_lock);
1714 pr_err("%s: Remote node %d not up\n",
1715 __func__, hdr->dst_node_id);
1716 return -ENODEV;
1717 }
1718 mutex_lock(&rt_entry->lock);
1719 xprt_info = rt_entry->xprt_info;
1720 mutex_lock(&xprt_info->tx_lock);
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -07001721 ret = xprt_info->xprt->write(pkt, pkt->length, xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001722 mutex_unlock(&xprt_info->tx_lock);
1723 mutex_unlock(&rt_entry->lock);
1724 mutex_unlock(&routing_table_lock);
1725
1726 if (ret < 0) {
1727 pr_err("%s: Write on XPRT failed\n", __func__);
1728 return ret;
1729 }
1730
1731 RAW_HDR("[w rr_h] "
1732 "ver=%i,type=%s,src_nid=%08x,src_port_id=%08x,"
1733 "confirm_rx=%i,size=%3i,dst_pid=%08x,dst_cid=%08x\n",
1734 hdr->version, type_to_str(hdr->type),
1735 hdr->src_node_id, hdr->src_port_id,
1736 hdr->confirm_rx, hdr->size,
1737 hdr->dst_node_id, hdr->dst_port_id);
1738
1739#if defined(CONFIG_MSM_SMD_LOGGING)
1740#if defined(DEBUG)
1741 if (msm_ipc_router_debug_mask & SMEM_LOG) {
1742 smem_log_event((SMEM_LOG_PROC_ID_APPS |
1743 SMEM_LOG_RPC_ROUTER_EVENT_BASE |
1744 IPC_ROUTER_LOG_EVENT_TX),
1745 (hdr->src_node_id << 24) |
1746 (hdr->src_port_id & 0xffffff),
1747 (hdr->dst_node_id << 24) |
1748 (hdr->dst_port_id & 0xffffff),
1749 (hdr->type << 24) | (hdr->confirm_rx << 16) |
1750 (hdr->size & 0xffff));
1751 }
1752#endif
1753#endif
1754
1755 return pkt->length;
1756}
1757
1758int msm_ipc_router_send_to(struct msm_ipc_port *src,
1759 struct sk_buff_head *data,
1760 struct msm_ipc_addr *dest)
1761{
1762 uint32_t dst_node_id = 0, dst_port_id = 0;
1763 struct msm_ipc_server *server;
1764 struct msm_ipc_server_port *server_port;
1765 struct msm_ipc_router_remote_port *rport_ptr = NULL;
1766 struct rr_packet *pkt;
1767 int ret;
1768
1769 if (!src || !data || !dest) {
1770 pr_err("%s: Invalid Parameters\n", __func__);
1771 return -EINVAL;
1772 }
1773
1774 /* Resolve Address*/
1775 if (dest->addrtype == MSM_IPC_ADDR_ID) {
1776 dst_node_id = dest->addr.port_addr.node_id;
1777 dst_port_id = dest->addr.port_addr.port_id;
1778 } else if (dest->addrtype == MSM_IPC_ADDR_NAME) {
1779 server = msm_ipc_router_lookup_server(
1780 dest->addr.port_name.service,
1781 dest->addr.port_name.instance,
1782 0, 0);
1783 if (!server) {
1784 pr_err("%s: Destination not reachable\n", __func__);
1785 return -ENODEV;
1786 }
1787 mutex_lock(&server_list_lock);
1788 server_port = list_first_entry(&server->server_port_list,
1789 struct msm_ipc_server_port,
1790 list);
1791 dst_node_id = server_port->server_addr.node_id;
1792 dst_port_id = server_port->server_addr.port_id;
1793 mutex_unlock(&server_list_lock);
1794 }
1795 if (dst_node_id == IPC_ROUTER_NID_LOCAL) {
1796 ret = loopback_data(src, dst_port_id, data);
1797 return ret;
1798 }
1799
1800 /* Achieve Flow control */
1801 rport_ptr = msm_ipc_router_lookup_remote_port(dst_node_id,
1802 dst_port_id);
1803 if (!rport_ptr) {
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001804 pr_err("%s: Could not create remote port\n", __func__);
1805 return -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001806 }
1807
1808 pkt = create_pkt(data);
1809 if (!pkt) {
1810 pr_err("%s: Pkt creation failed\n", __func__);
1811 return -ENOMEM;
1812 }
1813
1814 ret = msm_ipc_router_write_pkt(src, rport_ptr, pkt);
1815 release_pkt(pkt);
1816
1817 return ret;
1818}
1819
1820int msm_ipc_router_read(struct msm_ipc_port *port_ptr,
1821 struct sk_buff_head **data,
1822 size_t buf_len)
1823{
1824 struct rr_packet *pkt;
1825 int ret;
1826
1827 if (!port_ptr || !data)
1828 return -EINVAL;
1829
1830 mutex_lock(&port_ptr->port_rx_q_lock);
1831 if (list_empty(&port_ptr->port_rx_q)) {
1832 mutex_unlock(&port_ptr->port_rx_q_lock);
1833 return -EAGAIN;
1834 }
1835
1836 pkt = list_first_entry(&port_ptr->port_rx_q, struct rr_packet, list);
1837 if ((buf_len) && ((pkt->length - IPC_ROUTER_HDR_SIZE) > buf_len)) {
1838 mutex_unlock(&port_ptr->port_rx_q_lock);
1839 return -ETOOSMALL;
1840 }
1841 list_del(&pkt->list);
1842 if (list_empty(&port_ptr->port_rx_q))
1843 wake_unlock(&port_ptr->port_rx_wake_lock);
1844 *data = pkt->pkt_fragment_q;
1845 ret = pkt->length;
1846 kfree(pkt);
1847 mutex_unlock(&port_ptr->port_rx_q_lock);
1848
1849 return ret;
1850}
1851
1852int msm_ipc_router_recv_from(struct msm_ipc_port *port_ptr,
1853 struct sk_buff_head **data,
1854 struct msm_ipc_addr *src,
1855 unsigned long timeout)
1856{
1857 int ret, data_len, align_size;
1858 struct sk_buff *temp_skb;
1859 struct rr_header *hdr = NULL;
1860
1861 if (!port_ptr || !data) {
1862 pr_err("%s: Invalid pointers being passed\n", __func__);
1863 return -EINVAL;
1864 }
1865
1866 *data = NULL;
1867 mutex_lock(&port_ptr->port_rx_q_lock);
1868 while (list_empty(&port_ptr->port_rx_q)) {
1869 mutex_unlock(&port_ptr->port_rx_q_lock);
1870 if (timeout < 0) {
1871 ret = wait_event_interruptible(
1872 port_ptr->port_rx_wait_q,
1873 !list_empty(&port_ptr->port_rx_q));
1874 if (ret)
1875 return ret;
1876 } else if (timeout > 0) {
1877 timeout = wait_event_interruptible_timeout(
1878 port_ptr->port_rx_wait_q,
1879 !list_empty(&port_ptr->port_rx_q),
1880 timeout);
1881 if (timeout < 0)
1882 return -EFAULT;
1883 }
1884 if (timeout == 0)
1885 return -ETIMEDOUT;
1886 mutex_lock(&port_ptr->port_rx_q_lock);
1887 }
1888 mutex_unlock(&port_ptr->port_rx_q_lock);
1889
1890 ret = msm_ipc_router_read(port_ptr, data, 0);
1891 if (ret <= 0 || !(*data))
1892 return ret;
1893
1894 temp_skb = skb_peek(*data);
1895 hdr = (struct rr_header *)(temp_skb->data);
1896 if (src) {
1897 src->addrtype = MSM_IPC_ADDR_ID;
1898 src->addr.port_addr.node_id = hdr->src_node_id;
1899 src->addr.port_addr.port_id = hdr->src_port_id;
1900 }
1901
1902 data_len = hdr->size;
1903 skb_pull(temp_skb, IPC_ROUTER_HDR_SIZE);
1904 align_size = ALIGN_SIZE(data_len);
1905 if (align_size) {
1906 temp_skb = skb_peek_tail(*data);
1907 skb_trim(temp_skb, (temp_skb->len - align_size));
1908 }
1909 return data_len;
1910}
1911
1912struct msm_ipc_port *msm_ipc_router_create_port(
1913 void (*notify)(unsigned event, void *data, void *addr, void *priv),
1914 void *priv)
1915{
1916 struct msm_ipc_port *port_ptr;
1917
1918 port_ptr = msm_ipc_router_create_raw_port(NULL, notify, priv);
1919 if (!port_ptr)
1920 pr_err("%s: port_ptr alloc failed\n", __func__);
1921
1922 return port_ptr;
1923}
1924
1925int msm_ipc_router_close_port(struct msm_ipc_port *port_ptr)
1926{
1927 union rr_control_msg msg;
1928 struct rr_packet *pkt, *temp_pkt;
1929 struct msm_ipc_server *server;
1930
1931 if (!port_ptr)
1932 return -EINVAL;
1933
1934 if (port_ptr->type == SERVER_PORT || port_ptr->type == CLIENT_PORT) {
1935 if (port_ptr->type == SERVER_PORT) {
1936 msg.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_SERVER;
1937 msg.srv.service = port_ptr->port_name.service;
1938 msg.srv.instance = port_ptr->port_name.instance;
1939 msg.srv.node_id = port_ptr->this_port.node_id;
1940 msg.srv.port_id = port_ptr->this_port.port_id;
1941 RR("x REMOVE_SERVER Name=%d:%08x Id=%d:%08x\n",
1942 msg.srv.service, msg.srv.instance,
1943 msg.srv.node_id, msg.srv.port_id);
1944 } else if (port_ptr->type == CLIENT_PORT) {
1945 msg.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT;
1946 msg.cli.node_id = port_ptr->this_port.node_id;
1947 msg.cli.port_id = port_ptr->this_port.port_id;
1948 RR("x REMOVE_CLIENT id=%d:%08x\n",
1949 msg.cli.node_id, msg.cli.port_id);
1950 }
1951 broadcast_ctl_msg(&msg);
1952 broadcast_ctl_msg_locally(&msg);
1953 }
1954
1955 mutex_lock(&port_ptr->port_rx_q_lock);
1956 list_for_each_entry_safe(pkt, temp_pkt, &port_ptr->port_rx_q, list) {
1957 list_del(&pkt->list);
1958 release_pkt(pkt);
1959 }
1960 mutex_unlock(&port_ptr->port_rx_q_lock);
1961
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001962 if (port_ptr->type == SERVER_PORT) {
1963 server = msm_ipc_router_lookup_server(
1964 port_ptr->port_name.service,
1965 port_ptr->port_name.instance,
1966 port_ptr->this_port.node_id,
1967 port_ptr->this_port.port_id);
1968 if (server)
1969 msm_ipc_router_destroy_server(server,
1970 port_ptr->this_port.node_id,
1971 port_ptr->this_port.port_id);
1972 mutex_lock(&local_ports_lock);
1973 list_del(&port_ptr->list);
1974 mutex_unlock(&local_ports_lock);
1975 } else if (port_ptr->type == CLIENT_PORT) {
1976 mutex_lock(&local_ports_lock);
1977 list_del(&port_ptr->list);
1978 mutex_unlock(&local_ports_lock);
1979 } else if (port_ptr->type == CONTROL_PORT) {
1980 mutex_lock(&control_ports_lock);
1981 list_del(&port_ptr->list);
1982 mutex_unlock(&control_ports_lock);
1983 }
1984
Karthikeyan Ramasubramaniandd8c3b52011-11-30 16:26:12 -07001985 wake_lock_destroy(&port_ptr->port_rx_wake_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001986 kfree(port_ptr);
1987 return 0;
1988}
1989
1990int msm_ipc_router_get_curr_pkt_size(struct msm_ipc_port *port_ptr)
1991{
1992 struct rr_packet *pkt;
1993 int rc = 0;
1994
1995 if (!port_ptr)
1996 return -EINVAL;
1997
1998 mutex_lock(&port_ptr->port_rx_q_lock);
1999 if (!list_empty(&port_ptr->port_rx_q)) {
2000 pkt = list_first_entry(&port_ptr->port_rx_q,
2001 struct rr_packet, list);
2002 rc = pkt->length;
2003 }
2004 mutex_unlock(&port_ptr->port_rx_q_lock);
2005
2006 return rc;
2007}
2008
2009int msm_ipc_router_bind_control_port(struct msm_ipc_port *port_ptr)
2010{
2011 if (!port_ptr)
2012 return -EINVAL;
2013
2014 mutex_lock(&local_ports_lock);
2015 list_del(&port_ptr->list);
2016 mutex_unlock(&local_ports_lock);
2017 port_ptr->type = CONTROL_PORT;
2018 mutex_lock(&control_ports_lock);
2019 list_add_tail(&port_ptr->list, &control_ports);
2020 mutex_unlock(&control_ports_lock);
2021
2022 return 0;
2023}
2024
2025int msm_ipc_router_lookup_server_name(struct msm_ipc_port_name *srv_name,
2026 struct msm_ipc_port_addr *srv_addr,
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002027 int num_entries_in_array,
2028 uint32_t lookup_mask)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002029{
2030 struct msm_ipc_server *server;
2031 struct msm_ipc_server_port *server_port;
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002032 int key, i = 0; /*num_entries_found*/
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002033
2034 if (!srv_name) {
2035 pr_err("%s: Invalid srv_name\n", __func__);
2036 return -EINVAL;
2037 }
2038
2039 if (num_entries_in_array && !srv_addr) {
2040 pr_err("%s: srv_addr NULL\n", __func__);
2041 return -EINVAL;
2042 }
2043
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002044 mutex_lock(&server_list_lock);
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002045 if (!lookup_mask)
2046 lookup_mask = 0xFFFFFFFF;
2047 for (key = 0; key < SRV_HASH_SIZE; key++) {
2048 list_for_each_entry(server, &server_list[key], list) {
2049 if ((server->name.service != srv_name->service) ||
2050 ((server->name.instance & lookup_mask) !=
2051 srv_name->instance))
2052 continue;
2053
2054 list_for_each_entry(server_port,
2055 &server->server_port_list, list) {
2056 if (i < num_entries_in_array) {
2057 srv_addr[i].node_id =
2058 server_port->server_addr.node_id;
2059 srv_addr[i].port_id =
2060 server_port->server_addr.port_id;
2061 }
2062 i++;
2063 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002064 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002065 }
2066 mutex_unlock(&server_list_lock);
2067
2068 return i;
2069}
2070
2071int msm_ipc_router_close(void)
2072{
2073 struct msm_ipc_router_xprt_info *xprt_info, *tmp_xprt_info;
2074
2075 mutex_lock(&xprt_info_list_lock);
2076 list_for_each_entry_safe(xprt_info, tmp_xprt_info,
2077 &xprt_info_list, list) {
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -07002078 xprt_info->xprt->close(xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002079 list_del(&xprt_info->list);
2080 kfree(xprt_info);
2081 }
2082 mutex_unlock(&xprt_info_list_lock);
2083 return 0;
2084}
2085
2086#if defined(CONFIG_DEBUG_FS)
2087static int dump_routing_table(char *buf, int max)
2088{
2089 int i = 0, j;
2090 struct msm_ipc_routing_table_entry *rt_entry;
2091
2092 for (j = 0; j < RT_HASH_SIZE; j++) {
2093 mutex_lock(&routing_table_lock);
2094 list_for_each_entry(rt_entry, &routing_table[j], list) {
2095 mutex_lock(&rt_entry->lock);
2096 i += scnprintf(buf + i, max - i,
2097 "Node Id: 0x%08x\n", rt_entry->node_id);
2098 if (j == IPC_ROUTER_NID_LOCAL) {
2099 i += scnprintf(buf + i, max - i,
2100 "XPRT Name: Loopback\n");
2101 i += scnprintf(buf + i, max - i,
2102 "Next Hop: %d\n", rt_entry->node_id);
2103 } else {
2104 i += scnprintf(buf + i, max - i,
2105 "XPRT Name: %s\n",
2106 rt_entry->xprt_info->xprt->name);
2107 i += scnprintf(buf + i, max - i,
2108 "Next Hop: 0x%08x\n",
2109 rt_entry->xprt_info->remote_node_id);
2110 }
2111 i += scnprintf(buf + i, max - i, "\n");
2112 mutex_unlock(&rt_entry->lock);
2113 }
2114 mutex_unlock(&routing_table_lock);
2115 }
2116
2117 return i;
2118}
2119
2120static int dump_xprt_info(char *buf, int max)
2121{
2122 int i = 0;
2123 struct msm_ipc_router_xprt_info *xprt_info;
2124
2125 mutex_lock(&xprt_info_list_lock);
2126 list_for_each_entry(xprt_info, &xprt_info_list, list) {
2127 i += scnprintf(buf + i, max - i, "XPRT Name: %s\n",
2128 xprt_info->xprt->name);
2129 i += scnprintf(buf + i, max - i, "Link Id: %d\n",
2130 xprt_info->xprt->link_id);
2131 i += scnprintf(buf + i, max - i, "Initialized: %s\n",
2132 (xprt_info->initialized ? "Y" : "N"));
2133 i += scnprintf(buf + i, max - i, "Remote Node Id: 0x%08x\n",
2134 xprt_info->remote_node_id);
2135 i += scnprintf(buf + i, max - i, "\n");
2136 }
2137 mutex_unlock(&xprt_info_list_lock);
2138
2139 return i;
2140}
2141
2142static int dump_servers(char *buf, int max)
2143{
2144 int i = 0, j;
2145 struct msm_ipc_server *server;
2146 struct msm_ipc_server_port *server_port;
2147
2148 mutex_lock(&server_list_lock);
2149 for (j = 0; j < SRV_HASH_SIZE; j++) {
2150 list_for_each_entry(server, &server_list[j], list) {
2151 list_for_each_entry(server_port,
2152 &server->server_port_list,
2153 list) {
2154 i += scnprintf(buf + i, max - i, "Service: "
2155 "0x%08x\n", server->name.service);
2156 i += scnprintf(buf + i, max - i, "Instance: "
2157 "0x%08x\n", server->name.instance);
2158 i += scnprintf(buf + i, max - i,
2159 "Node_id: 0x%08x\n",
2160 server_port->server_addr.node_id);
2161 i += scnprintf(buf + i, max - i,
2162 "Port_id: 0x%08x\n",
2163 server_port->server_addr.port_id);
2164 i += scnprintf(buf + i, max - i, "\n");
2165 }
2166 }
2167 }
2168 mutex_unlock(&server_list_lock);
2169
2170 return i;
2171}
2172
2173static int dump_remote_ports(char *buf, int max)
2174{
2175 int i = 0, j, k;
2176 struct msm_ipc_router_remote_port *rport_ptr;
2177 struct msm_ipc_routing_table_entry *rt_entry;
2178
2179 for (j = 0; j < RT_HASH_SIZE; j++) {
2180 mutex_lock(&routing_table_lock);
2181 list_for_each_entry(rt_entry, &routing_table[j], list) {
2182 mutex_lock(&rt_entry->lock);
2183 for (k = 0; k < RP_HASH_SIZE; k++) {
2184 list_for_each_entry(rport_ptr,
2185 &rt_entry->remote_port_list[k],
2186 list) {
2187 i += scnprintf(buf + i, max - i,
2188 "Node_id: 0x%08x\n",
2189 rport_ptr->node_id);
2190 i += scnprintf(buf + i, max - i,
2191 "Port_id: 0x%08x\n",
2192 rport_ptr->port_id);
2193 i += scnprintf(buf + i, max - i,
2194 "Quota_cnt: %d\n",
2195 rport_ptr->tx_quota_cnt);
2196 i += scnprintf(buf + i, max - i, "\n");
2197 }
2198 }
2199 mutex_unlock(&rt_entry->lock);
2200 }
2201 mutex_unlock(&routing_table_lock);
2202 }
2203
2204 return i;
2205}
2206
2207static int dump_control_ports(char *buf, int max)
2208{
2209 int i = 0;
2210 struct msm_ipc_port *port_ptr;
2211
2212 mutex_lock(&control_ports_lock);
2213 list_for_each_entry(port_ptr, &control_ports, list) {
2214 i += scnprintf(buf + i, max - i, "Node_id: 0x%08x\n",
2215 port_ptr->this_port.node_id);
2216 i += scnprintf(buf + i, max - i, "Port_id: 0x%08x\n",
2217 port_ptr->this_port.port_id);
2218 i += scnprintf(buf + i, max - i, "\n");
2219 }
2220 mutex_unlock(&control_ports_lock);
2221
2222 return i;
2223}
2224
2225static int dump_local_ports(char *buf, int max)
2226{
2227 int i = 0, j;
2228 unsigned long flags;
2229 struct msm_ipc_port *port_ptr;
2230
2231 mutex_lock(&local_ports_lock);
2232 for (j = 0; j < LP_HASH_SIZE; j++) {
2233 list_for_each_entry(port_ptr, &local_ports[j], list) {
2234 spin_lock_irqsave(&port_ptr->port_lock, flags);
2235 i += scnprintf(buf + i, max - i, "Node_id: 0x%08x\n",
2236 port_ptr->this_port.node_id);
2237 i += scnprintf(buf + i, max - i, "Port_id: 0x%08x\n",
2238 port_ptr->this_port.port_id);
2239 i += scnprintf(buf + i, max - i, "# pkts tx'd %d\n",
2240 port_ptr->num_tx);
2241 i += scnprintf(buf + i, max - i, "# pkts rx'd %d\n",
2242 port_ptr->num_rx);
2243 i += scnprintf(buf + i, max - i, "# bytes tx'd %ld\n",
2244 port_ptr->num_tx_bytes);
2245 i += scnprintf(buf + i, max - i, "# bytes rx'd %ld\n",
2246 port_ptr->num_rx_bytes);
2247 spin_unlock_irqrestore(&port_ptr->port_lock, flags);
2248 i += scnprintf(buf + i, max - i, "\n");
2249 }
2250 }
2251 mutex_unlock(&local_ports_lock);
2252
2253 return i;
2254}
2255
2256#define DEBUG_BUFMAX 4096
2257static char debug_buffer[DEBUG_BUFMAX];
2258
2259static ssize_t debug_read(struct file *file, char __user *buf,
2260 size_t count, loff_t *ppos)
2261{
2262 int (*fill)(char *buf, int max) = file->private_data;
2263 int bsize = fill(debug_buffer, DEBUG_BUFMAX);
2264 return simple_read_from_buffer(buf, count, ppos, debug_buffer, bsize);
2265}
2266
2267static int debug_open(struct inode *inode, struct file *file)
2268{
2269 file->private_data = inode->i_private;
2270 return 0;
2271}
2272
2273static const struct file_operations debug_ops = {
2274 .read = debug_read,
2275 .open = debug_open,
2276};
2277
2278static void debug_create(const char *name, mode_t mode,
2279 struct dentry *dent,
2280 int (*fill)(char *buf, int max))
2281{
2282 debugfs_create_file(name, mode, dent, fill, &debug_ops);
2283}
2284
2285static void debugfs_init(void)
2286{
2287 struct dentry *dent;
2288
2289 dent = debugfs_create_dir("msm_ipc_router", 0);
2290 if (IS_ERR(dent))
2291 return;
2292
2293 debug_create("dump_local_ports", 0444, dent,
2294 dump_local_ports);
2295 debug_create("dump_remote_ports", 0444, dent,
2296 dump_remote_ports);
2297 debug_create("dump_control_ports", 0444, dent,
2298 dump_control_ports);
2299 debug_create("dump_servers", 0444, dent,
2300 dump_servers);
2301 debug_create("dump_xprt_info", 0444, dent,
2302 dump_xprt_info);
2303 debug_create("dump_routing_table", 0444, dent,
2304 dump_routing_table);
2305}
2306
2307#else
2308static void debugfs_init(void) {}
2309#endif
2310
2311static int msm_ipc_router_add_xprt(struct msm_ipc_router_xprt *xprt)
2312{
2313 struct msm_ipc_router_xprt_info *xprt_info;
2314 struct msm_ipc_routing_table_entry *rt_entry;
2315
2316 xprt_info = kmalloc(sizeof(struct msm_ipc_router_xprt_info),
2317 GFP_KERNEL);
2318 if (!xprt_info)
2319 return -ENOMEM;
2320
2321 xprt_info->xprt = xprt;
2322 xprt_info->initialized = 0;
2323 xprt_info->remote_node_id = -1;
2324 INIT_LIST_HEAD(&xprt_info->pkt_list);
2325 init_waitqueue_head(&xprt_info->read_wait);
2326 mutex_init(&xprt_info->rx_lock);
2327 mutex_init(&xprt_info->tx_lock);
2328 wake_lock_init(&xprt_info->wakelock,
2329 WAKE_LOCK_SUSPEND, xprt->name);
2330 xprt_info->need_len = 0;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002331 xprt_info->abort_data_read = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002332 INIT_WORK(&xprt_info->read_data, do_read_data);
2333 INIT_LIST_HEAD(&xprt_info->list);
2334
2335 xprt_info->workqueue = create_singlethread_workqueue(xprt->name);
2336 if (!xprt_info->workqueue) {
2337 kfree(xprt_info);
2338 return -ENOMEM;
2339 }
2340
2341 if (!strcmp(xprt->name, "msm_ipc_router_loopback_xprt")) {
2342 xprt_info->remote_node_id = IPC_ROUTER_NID_LOCAL;
2343 xprt_info->initialized = 1;
2344 }
2345
2346 mutex_lock(&xprt_info_list_lock);
2347 list_add_tail(&xprt_info->list, &xprt_info_list);
2348 mutex_unlock(&xprt_info_list_lock);
2349
2350 mutex_lock(&routing_table_lock);
2351 if (!routing_table_inited) {
2352 init_routing_table();
2353 rt_entry = alloc_routing_table_entry(IPC_ROUTER_NID_LOCAL);
2354 add_routing_table_entry(rt_entry);
2355 routing_table_inited = 1;
2356 }
2357 mutex_unlock(&routing_table_lock);
2358
2359 queue_work(xprt_info->workqueue, &xprt_info->read_data);
2360
2361 xprt->priv = xprt_info;
2362
2363 return 0;
2364}
2365
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002366static void msm_ipc_router_remove_xprt(struct msm_ipc_router_xprt *xprt)
2367{
2368 struct msm_ipc_router_xprt_info *xprt_info;
2369
2370 if (xprt && xprt->priv) {
2371 xprt_info = xprt->priv;
2372
2373 xprt_info->abort_data_read = 1;
2374 wake_up(&xprt_info->read_wait);
2375
2376 mutex_lock(&xprt_info_list_lock);
2377 list_del(&xprt_info->list);
2378 mutex_unlock(&xprt_info_list_lock);
2379
2380 flush_workqueue(xprt_info->workqueue);
2381 destroy_workqueue(xprt_info->workqueue);
2382 wake_lock_destroy(&xprt_info->wakelock);
2383
2384 xprt->priv = 0;
2385 kfree(xprt_info);
2386 }
2387}
2388
2389
2390struct msm_ipc_router_xprt_work {
2391 struct msm_ipc_router_xprt *xprt;
2392 struct work_struct work;
2393};
2394
2395static void xprt_open_worker(struct work_struct *work)
2396{
2397 struct msm_ipc_router_xprt_work *xprt_work =
2398 container_of(work, struct msm_ipc_router_xprt_work, work);
2399
2400 msm_ipc_router_add_xprt(xprt_work->xprt);
2401 kfree(xprt_work);
2402}
2403
2404static void xprt_close_worker(struct work_struct *work)
2405{
2406 struct msm_ipc_router_xprt_work *xprt_work =
2407 container_of(work, struct msm_ipc_router_xprt_work, work);
2408
2409 modem_reset_cleanup(xprt_work->xprt->priv);
2410 msm_ipc_router_remove_xprt(xprt_work->xprt);
2411
2412 if (atomic_dec_return(&pending_close_count) == 0)
2413 wake_up(&subsystem_restart_wait);
2414
2415 kfree(xprt_work);
2416}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002417
2418void msm_ipc_router_xprt_notify(struct msm_ipc_router_xprt *xprt,
2419 unsigned event,
2420 void *data)
2421{
2422 struct msm_ipc_router_xprt_info *xprt_info = xprt->priv;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002423 struct msm_ipc_router_xprt_work *xprt_work;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002424 struct rr_packet *pkt;
Karthikeyan Ramasubramanian4af9f7c2011-09-30 15:55:18 -06002425 unsigned long ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002426
Karthikeyan Ramasubramanian4af9f7c2011-09-30 15:55:18 -06002427 if (!msm_ipc_router_workqueue) {
2428 ret = wait_for_completion_timeout(&msm_ipc_local_router_up,
2429 IPC_ROUTER_INIT_TIMEOUT);
2430 if (!ret || !msm_ipc_router_workqueue) {
2431 pr_err("%s: IPC Router not initialized\n", __func__);
2432 return;
2433 }
2434 }
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002435
2436 switch (event) {
2437 case IPC_ROUTER_XPRT_EVENT_OPEN:
2438 D("open event for '%s'\n", xprt->name);
2439 xprt_work = kmalloc(sizeof(struct msm_ipc_router_xprt_work),
2440 GFP_ATOMIC);
2441 xprt_work->xprt = xprt;
2442 INIT_WORK(&xprt_work->work, xprt_open_worker);
2443 queue_work(msm_ipc_router_workqueue, &xprt_work->work);
2444 break;
2445
2446 case IPC_ROUTER_XPRT_EVENT_CLOSE:
2447 D("close event for '%s'\n", xprt->name);
2448 atomic_inc(&pending_close_count);
2449 xprt_work = kmalloc(sizeof(struct msm_ipc_router_xprt_work),
2450 GFP_ATOMIC);
2451 xprt_work->xprt = xprt;
2452 INIT_WORK(&xprt_work->work, xprt_close_worker);
2453 queue_work(msm_ipc_router_workqueue, &xprt_work->work);
2454 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002455 }
2456
2457 if (!data)
2458 return;
2459
2460 while (!xprt_info) {
2461 msleep(100);
2462 xprt_info = xprt->priv;
2463 }
2464
2465 pkt = clone_pkt((struct rr_packet *)data);
2466 if (!pkt)
2467 return;
2468
2469 mutex_lock(&xprt_info->rx_lock);
2470 list_add_tail(&pkt->list, &xprt_info->pkt_list);
2471 wake_lock(&xprt_info->wakelock);
2472 wake_up(&xprt_info->read_wait);
2473 mutex_unlock(&xprt_info->rx_lock);
2474}
2475
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002476static int modem_restart_notifier_cb(struct notifier_block *this,
2477 unsigned long code,
2478 void *data);
2479static struct notifier_block msm_ipc_router_nb = {
2480 .notifier_call = modem_restart_notifier_cb,
2481};
2482
2483static int modem_restart_notifier_cb(struct notifier_block *this,
2484 unsigned long code,
2485 void *data)
2486{
2487 switch (code) {
2488 case SUBSYS_BEFORE_SHUTDOWN:
2489 D("%s: SUBSYS_BEFORE_SHUTDOWN\n", __func__);
2490 break;
2491
2492 case SUBSYS_BEFORE_POWERUP:
2493 D("%s: waiting for RPC restart to complete\n", __func__);
2494 wait_event(subsystem_restart_wait,
2495 atomic_read(&pending_close_count) == 0);
2496 D("%s: finished restart wait\n", __func__);
2497 break;
2498
2499 default:
2500 break;
2501 }
2502
2503 return NOTIFY_DONE;
2504}
2505
2506static void *restart_notifier_handle;
2507static __init int msm_ipc_router_modem_restart_late_init(void)
2508{
2509 restart_notifier_handle = subsys_notif_register_notifier("modem",
2510 &msm_ipc_router_nb);
2511 return 0;
2512}
2513late_initcall(msm_ipc_router_modem_restart_late_init);
2514
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002515static int __init msm_ipc_router_init(void)
2516{
2517 int i, ret;
2518 struct msm_ipc_routing_table_entry *rt_entry;
2519
2520 msm_ipc_router_debug_mask |= SMEM_LOG;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002521 msm_ipc_router_workqueue =
2522 create_singlethread_workqueue("msm_ipc_router");
2523 if (!msm_ipc_router_workqueue)
2524 return -ENOMEM;
2525
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002526 debugfs_init();
2527
2528 for (i = 0; i < SRV_HASH_SIZE; i++)
2529 INIT_LIST_HEAD(&server_list[i]);
2530
2531 for (i = 0; i < LP_HASH_SIZE; i++)
2532 INIT_LIST_HEAD(&local_ports[i]);
2533
2534 mutex_lock(&routing_table_lock);
2535 if (!routing_table_inited) {
2536 init_routing_table();
2537 rt_entry = alloc_routing_table_entry(IPC_ROUTER_NID_LOCAL);
2538 add_routing_table_entry(rt_entry);
2539 routing_table_inited = 1;
2540 }
2541 mutex_unlock(&routing_table_lock);
2542
2543 init_waitqueue_head(&newserver_wait);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002544 init_waitqueue_head(&subsystem_restart_wait);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002545 ret = msm_ipc_router_init_sockets();
2546 if (ret < 0)
2547 pr_err("%s: Init sockets failed\n", __func__);
2548
Karthikeyan Ramasubramanian4af9f7c2011-09-30 15:55:18 -06002549 complete_all(&msm_ipc_local_router_up);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002550 return ret;
2551}
2552
2553module_init(msm_ipc_router_init);
2554MODULE_DESCRIPTION("MSM IPC Router");
2555MODULE_LICENSE("GPL v2");