blob: 15ea8ba2c3d4220d0a40ca2686474a732f53c1d4 [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
2 *
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);
460 wake_lock_init(&port_ptr->port_rx_wake_lock,
461 WAKE_LOCK_SUSPEND, "msm_ipc_read");
462
463 port_ptr->endpoint = endpoint;
464 port_ptr->notify = notify;
465 port_ptr->priv = priv;
466
467 msm_ipc_router_add_local_port(port_ptr);
468 return port_ptr;
469}
470
471static struct msm_ipc_port *msm_ipc_router_lookup_local_port(uint32_t port_id)
472{
473 int key = (port_id & (LP_HASH_SIZE - 1));
474 struct msm_ipc_port *port_ptr;
475
476 mutex_lock(&local_ports_lock);
477 list_for_each_entry(port_ptr, &local_ports[key], list) {
478 if (port_ptr->this_port.port_id == port_id) {
479 mutex_unlock(&local_ports_lock);
480 return port_ptr;
481 }
482 }
483 mutex_unlock(&local_ports_lock);
484 return NULL;
485}
486
487static struct msm_ipc_router_remote_port *msm_ipc_router_lookup_remote_port(
488 uint32_t node_id,
489 uint32_t port_id)
490{
491 struct msm_ipc_router_remote_port *rport_ptr;
492 struct msm_ipc_routing_table_entry *rt_entry;
493 int key = (port_id & (RP_HASH_SIZE - 1));
494
495 mutex_lock(&routing_table_lock);
496 rt_entry = lookup_routing_table(node_id);
497 if (!rt_entry) {
498 mutex_unlock(&routing_table_lock);
499 pr_err("%s: Node is not up\n", __func__);
500 return NULL;
501 }
502
503 mutex_lock(&rt_entry->lock);
504 list_for_each_entry(rport_ptr,
505 &rt_entry->remote_port_list[key], list) {
506 if (rport_ptr->port_id == port_id) {
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600507 if (rport_ptr->restart_state != RESTART_NORMAL)
508 rport_ptr = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700509 mutex_unlock(&rt_entry->lock);
510 mutex_unlock(&routing_table_lock);
511 return rport_ptr;
512 }
513 }
514 mutex_unlock(&rt_entry->lock);
515 mutex_unlock(&routing_table_lock);
516 return NULL;
517}
518
519static struct msm_ipc_router_remote_port *msm_ipc_router_create_remote_port(
520 uint32_t node_id,
521 uint32_t port_id)
522{
523 struct msm_ipc_router_remote_port *rport_ptr;
524 struct msm_ipc_routing_table_entry *rt_entry;
525 int key = (port_id & (RP_HASH_SIZE - 1));
526
527 mutex_lock(&routing_table_lock);
528 rt_entry = lookup_routing_table(node_id);
529 if (!rt_entry) {
530 mutex_unlock(&routing_table_lock);
531 pr_err("%s: Node is not up\n", __func__);
532 return NULL;
533 }
534
535 mutex_lock(&rt_entry->lock);
536 rport_ptr = kmalloc(sizeof(struct msm_ipc_router_remote_port),
537 GFP_KERNEL);
538 if (!rport_ptr) {
539 mutex_unlock(&rt_entry->lock);
540 mutex_unlock(&routing_table_lock);
541 pr_err("%s: Remote port alloc failed\n", __func__);
542 return NULL;
543 }
544 rport_ptr->port_id = port_id;
545 rport_ptr->node_id = node_id;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600546 rport_ptr->restart_state = RESTART_NORMAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700547 rport_ptr->tx_quota_cnt = 0;
548 init_waitqueue_head(&rport_ptr->quota_wait);
549 mutex_init(&rport_ptr->quota_lock);
550 list_add_tail(&rport_ptr->list,
551 &rt_entry->remote_port_list[key]);
552 mutex_unlock(&rt_entry->lock);
553 mutex_unlock(&routing_table_lock);
554 return rport_ptr;
555}
556
557static void msm_ipc_router_destroy_remote_port(
558 struct msm_ipc_router_remote_port *rport_ptr)
559{
560 uint32_t node_id;
561 struct msm_ipc_routing_table_entry *rt_entry;
562
563 if (!rport_ptr)
564 return;
565
566 node_id = rport_ptr->node_id;
567 mutex_lock(&routing_table_lock);
568 rt_entry = lookup_routing_table(node_id);
569 if (!rt_entry) {
570 mutex_unlock(&routing_table_lock);
571 pr_err("%s: Node %d is not up\n", __func__, node_id);
572 return;
573 }
574
575 mutex_lock(&rt_entry->lock);
576 list_del(&rport_ptr->list);
577 kfree(rport_ptr);
578 mutex_unlock(&rt_entry->lock);
579 mutex_unlock(&routing_table_lock);
580 return;
581}
582
583static struct msm_ipc_server *msm_ipc_router_lookup_server(
584 uint32_t service,
585 uint32_t instance,
586 uint32_t node_id,
587 uint32_t port_id)
588{
589 struct msm_ipc_server *server;
590 struct msm_ipc_server_port *server_port;
591 int key = (instance & (SRV_HASH_SIZE - 1));
592
593 mutex_lock(&server_list_lock);
594 list_for_each_entry(server, &server_list[key], list) {
595 if ((server->name.service != service) ||
596 (server->name.instance != instance))
597 continue;
598 if ((node_id == 0) && (port_id == 0)) {
599 mutex_unlock(&server_list_lock);
600 return server;
601 }
602 list_for_each_entry(server_port, &server->server_port_list,
603 list) {
604 if ((server_port->server_addr.node_id == node_id) &&
605 (server_port->server_addr.port_id == port_id)) {
606 mutex_unlock(&server_list_lock);
607 return server;
608 }
609 }
610 }
611 mutex_unlock(&server_list_lock);
612 return NULL;
613}
614
615static struct msm_ipc_server *msm_ipc_router_create_server(
616 uint32_t service,
617 uint32_t instance,
618 uint32_t node_id,
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600619 uint32_t port_id,
620 struct msm_ipc_router_xprt_info *xprt_info)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700621{
622 struct msm_ipc_server *server = NULL;
623 struct msm_ipc_server_port *server_port;
624 int key = (instance & (SRV_HASH_SIZE - 1));
625
626 mutex_lock(&server_list_lock);
627 list_for_each_entry(server, &server_list[key], list) {
628 if ((server->name.service == service) &&
629 (server->name.instance == instance))
630 goto create_srv_port;
631 }
632
633 server = kmalloc(sizeof(struct msm_ipc_server), GFP_KERNEL);
634 if (!server) {
635 mutex_unlock(&server_list_lock);
636 pr_err("%s: Server allocation failed\n", __func__);
637 return NULL;
638 }
639 server->name.service = service;
640 server->name.instance = instance;
641 INIT_LIST_HEAD(&server->server_port_list);
642 list_add_tail(&server->list, &server_list[key]);
643
644create_srv_port:
645 server_port = kmalloc(sizeof(struct msm_ipc_server_port), GFP_KERNEL);
646 if (!server_port) {
647 if (list_empty(&server->server_port_list)) {
648 list_del(&server->list);
649 kfree(server);
650 }
651 mutex_unlock(&server_list_lock);
652 pr_err("%s: Server Port allocation failed\n", __func__);
653 return NULL;
654 }
655 server_port->server_addr.node_id = node_id;
656 server_port->server_addr.port_id = port_id;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600657 server_port->xprt_info = xprt_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700658 list_add_tail(&server_port->list, &server->server_port_list);
659 mutex_unlock(&server_list_lock);
660
661 return server;
662}
663
664static void msm_ipc_router_destroy_server(struct msm_ipc_server *server,
665 uint32_t node_id, uint32_t port_id)
666{
667 struct msm_ipc_server_port *server_port;
668
669 if (!server)
670 return;
671
672 mutex_lock(&server_list_lock);
673 list_for_each_entry(server_port, &server->server_port_list, list) {
674 if ((server_port->server_addr.node_id == node_id) &&
675 (server_port->server_addr.port_id == port_id))
676 break;
677 }
678 if (server_port) {
679 list_del(&server_port->list);
680 kfree(server_port);
681 }
682 if (list_empty(&server->server_port_list)) {
683 list_del(&server->list);
684 kfree(server);
685 }
686 mutex_unlock(&server_list_lock);
687 return;
688}
689
690static int msm_ipc_router_send_control_msg(
691 struct msm_ipc_router_xprt_info *xprt_info,
692 union rr_control_msg *msg)
693{
694 struct rr_packet *pkt;
695 struct sk_buff *ipc_rtr_pkt;
696 struct rr_header *hdr;
697 int pkt_size;
698 void *data;
699 struct sk_buff_head *pkt_fragment_q;
700 int ret;
701
702 if (!xprt_info || ((msg->cmd != IPC_ROUTER_CTRL_CMD_HELLO) &&
703 !xprt_info->initialized)) {
704 pr_err("%s: xprt_info not initialized\n", __func__);
705 return -EINVAL;
706 }
707
708 if (xprt_info->remote_node_id == IPC_ROUTER_NID_LOCAL)
709 return 0;
710
711 pkt = kzalloc(sizeof(struct rr_packet), GFP_KERNEL);
712 if (!pkt) {
713 pr_err("%s: pkt alloc failed\n", __func__);
714 return -ENOMEM;
715 }
716
717 pkt_fragment_q = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
718 if (!pkt_fragment_q) {
719 pr_err("%s: pkt_fragment_q alloc failed\n", __func__);
720 kfree(pkt);
721 return -ENOMEM;
722 }
723 skb_queue_head_init(pkt_fragment_q);
724
725 pkt_size = IPC_ROUTER_HDR_SIZE + sizeof(*msg);
726 ipc_rtr_pkt = alloc_skb(pkt_size, GFP_KERNEL);
727 if (!ipc_rtr_pkt) {
728 pr_err("%s: ipc_rtr_pkt alloc failed\n", __func__);
729 kfree(pkt_fragment_q);
730 kfree(pkt);
731 return -ENOMEM;
732 }
733
734 skb_reserve(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
735 data = skb_put(ipc_rtr_pkt, sizeof(*msg));
736 memcpy(data, msg, sizeof(*msg));
737 hdr = (struct rr_header *)skb_push(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
738 if (!hdr) {
739 pr_err("%s: skb_push failed\n", __func__);
740 kfree_skb(ipc_rtr_pkt);
741 kfree(pkt_fragment_q);
742 kfree(pkt);
743 return -ENOMEM;
744 }
745
746 hdr->version = IPC_ROUTER_VERSION;
747 hdr->type = msg->cmd;
748 hdr->src_node_id = IPC_ROUTER_NID_LOCAL;
749 hdr->src_port_id = IPC_ROUTER_ADDRESS;
750 hdr->confirm_rx = 0;
751 hdr->size = sizeof(*msg);
752 hdr->dst_node_id = xprt_info->remote_node_id;
753 hdr->dst_port_id = IPC_ROUTER_ADDRESS;
754 skb_queue_tail(pkt_fragment_q, ipc_rtr_pkt);
755 pkt->pkt_fragment_q = pkt_fragment_q;
756 pkt->length = pkt_size;
757
758 mutex_lock(&xprt_info->tx_lock);
759 ret = xprt_info->xprt->write(pkt, pkt_size, 0);
760 mutex_unlock(&xprt_info->tx_lock);
761
762 release_pkt(pkt);
763 return ret;
764}
765
766static int msm_ipc_router_send_server_list(
767 struct msm_ipc_router_xprt_info *xprt_info)
768{
769 union rr_control_msg ctl;
770 struct msm_ipc_server *server;
771 struct msm_ipc_server_port *server_port;
772 int i;
773
774 if (!xprt_info || !xprt_info->initialized) {
775 pr_err("%s: Xprt info not initialized\n", __func__);
776 return -EINVAL;
777 }
778
779 ctl.cmd = IPC_ROUTER_CTRL_CMD_NEW_SERVER;
780
781 mutex_lock(&server_list_lock);
782 for (i = 0; i < SRV_HASH_SIZE; i++) {
783 list_for_each_entry(server, &server_list[i], list) {
784 ctl.srv.service = server->name.service;
785 ctl.srv.instance = server->name.instance;
786 list_for_each_entry(server_port,
787 &server->server_port_list, list) {
788 if (server_port->server_addr.node_id ==
789 xprt_info->remote_node_id)
790 continue;
791
792 ctl.srv.node_id =
793 server_port->server_addr.node_id;
794 ctl.srv.port_id =
795 server_port->server_addr.port_id;
796 msm_ipc_router_send_control_msg(xprt_info,
797 &ctl);
798 }
799 }
800 }
801 mutex_unlock(&server_list_lock);
802
803 return 0;
804}
805
806#if defined(DEBUG)
807static char *type_to_str(int i)
808{
809 switch (i) {
810 case IPC_ROUTER_CTRL_CMD_DATA:
811 return "data ";
812 case IPC_ROUTER_CTRL_CMD_HELLO:
813 return "hello ";
814 case IPC_ROUTER_CTRL_CMD_BYE:
815 return "bye ";
816 case IPC_ROUTER_CTRL_CMD_NEW_SERVER:
817 return "new_srvr";
818 case IPC_ROUTER_CTRL_CMD_REMOVE_SERVER:
819 return "rmv_srvr";
820 case IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT:
821 return "rmv_clnt";
822 case IPC_ROUTER_CTRL_CMD_RESUME_TX:
823 return "resum_tx";
824 case IPC_ROUTER_CTRL_CMD_EXIT:
825 return "cmd_exit";
826 default:
827 return "invalid";
828 }
829}
830#endif
831
832static int broadcast_ctl_msg_locally(union rr_control_msg *msg)
833{
834 struct rr_packet *pkt;
835 struct sk_buff *ipc_rtr_pkt;
836 struct rr_header *hdr;
837 int pkt_size;
838 void *data;
839 struct sk_buff_head *pkt_fragment_q;
840 int ret;
841
842 pkt = kzalloc(sizeof(struct rr_packet), GFP_KERNEL);
843 if (!pkt) {
844 pr_err("%s: pkt alloc failed\n", __func__);
845 return -ENOMEM;
846 }
847
848 pkt_fragment_q = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
849 if (!pkt_fragment_q) {
850 pr_err("%s: pkt_fragment_q alloc failed\n", __func__);
851 kfree(pkt);
852 return -ENOMEM;
853 }
854 skb_queue_head_init(pkt_fragment_q);
855
856 pkt_size = IPC_ROUTER_HDR_SIZE + sizeof(*msg);
857 ipc_rtr_pkt = alloc_skb(pkt_size, GFP_KERNEL);
858 if (!ipc_rtr_pkt) {
859 pr_err("%s: ipc_rtr_pkt alloc failed\n", __func__);
860 kfree(pkt_fragment_q);
861 kfree(pkt);
862 return -ENOMEM;
863 }
864
865 skb_reserve(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
866 data = skb_put(ipc_rtr_pkt, sizeof(*msg));
867 memcpy(data, msg, sizeof(*msg));
868 hdr = (struct rr_header *)skb_push(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
869 if (!hdr) {
870 pr_err("%s: skb_push failed\n", __func__);
871 kfree_skb(ipc_rtr_pkt);
872 kfree(pkt_fragment_q);
873 kfree(pkt);
874 return -ENOMEM;
875 }
876 hdr->version = IPC_ROUTER_VERSION;
877 hdr->type = msg->cmd;
878 hdr->src_node_id = IPC_ROUTER_NID_LOCAL;
879 hdr->src_port_id = IPC_ROUTER_ADDRESS;
880 hdr->confirm_rx = 0;
881 hdr->size = sizeof(*msg);
882 hdr->dst_node_id = IPC_ROUTER_NID_LOCAL;
883 hdr->dst_port_id = IPC_ROUTER_ADDRESS;
884 skb_queue_tail(pkt_fragment_q, ipc_rtr_pkt);
885 pkt->pkt_fragment_q = pkt_fragment_q;
886 pkt->length = pkt_size;
887
888 ret = post_control_ports(pkt);
889 release_pkt(pkt);
890 return ret;
891}
892
893static int broadcast_ctl_msg(union rr_control_msg *ctl)
894{
895 struct msm_ipc_router_xprt_info *xprt_info;
896
897 mutex_lock(&xprt_info_list_lock);
898 list_for_each_entry(xprt_info, &xprt_info_list, list) {
899 msm_ipc_router_send_control_msg(xprt_info, ctl);
900 }
901 mutex_unlock(&xprt_info_list_lock);
902
903 return 0;
904}
905
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600906static int relay_ctl_msg(struct msm_ipc_router_xprt_info *xprt_info,
907 union rr_control_msg *ctl)
908{
909 struct msm_ipc_router_xprt_info *fwd_xprt_info;
910
911 if (!xprt_info || !ctl)
912 return -EINVAL;
913
914 mutex_lock(&xprt_info_list_lock);
915 list_for_each_entry(fwd_xprt_info, &xprt_info_list, list) {
916 if (xprt_info->xprt->link_id != fwd_xprt_info->xprt->link_id)
917 msm_ipc_router_send_control_msg(fwd_xprt_info, ctl);
918 }
919 mutex_unlock(&xprt_info_list_lock);
920
921 return 0;
922}
923
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700924static int relay_msg(struct msm_ipc_router_xprt_info *xprt_info,
925 struct rr_packet *pkt)
926{
927 struct msm_ipc_router_xprt_info *fwd_xprt_info;
928
929 if (!xprt_info || !pkt)
930 return -EINVAL;
931
932 mutex_lock(&xprt_info_list_lock);
933 list_for_each_entry(fwd_xprt_info, &xprt_info_list, list) {
934 mutex_lock(&fwd_xprt_info->tx_lock);
935 if (xprt_info->xprt->link_id != fwd_xprt_info->xprt->link_id)
936 fwd_xprt_info->xprt->write(pkt, pkt->length, 0);
937 mutex_unlock(&fwd_xprt_info->tx_lock);
938 }
939 mutex_unlock(&xprt_info_list_lock);
940 return 0;
941}
942
943static int forward_msg(struct msm_ipc_router_xprt_info *xprt_info,
944 struct rr_packet *pkt)
945{
946 uint32_t dst_node_id;
947 struct sk_buff *head_pkt;
948 struct rr_header *hdr;
949 struct msm_ipc_router_xprt_info *fwd_xprt_info;
950 struct msm_ipc_routing_table_entry *rt_entry;
951
952 if (!xprt_info || !pkt)
953 return -EINVAL;
954
955 head_pkt = skb_peek(pkt->pkt_fragment_q);
956 if (!head_pkt)
957 return -EINVAL;
958
959 hdr = (struct rr_header *)head_pkt->data;
960 dst_node_id = hdr->dst_node_id;
961 mutex_lock(&routing_table_lock);
962 rt_entry = lookup_routing_table(dst_node_id);
963 if (!(rt_entry) || !(rt_entry->xprt_info)) {
964 mutex_unlock(&routing_table_lock);
965 pr_err("%s: Routing table not initialized\n", __func__);
966 return -ENODEV;
967 }
968
969 mutex_lock(&rt_entry->lock);
970 fwd_xprt_info = rt_entry->xprt_info;
971 mutex_lock(&fwd_xprt_info->tx_lock);
972 if (xprt_info->remote_node_id == fwd_xprt_info->remote_node_id) {
973 mutex_unlock(&fwd_xprt_info->tx_lock);
974 mutex_unlock(&rt_entry->lock);
975 mutex_unlock(&routing_table_lock);
976 pr_err("%s: Discarding Command to route back\n", __func__);
977 return -EINVAL;
978 }
979
980 if (xprt_info->xprt->link_id == fwd_xprt_info->xprt->link_id) {
981 mutex_unlock(&fwd_xprt_info->tx_lock);
982 mutex_unlock(&rt_entry->lock);
983 mutex_unlock(&routing_table_lock);
984 pr_err("%s: DST in the same cluster\n", __func__);
985 return 0;
986 }
987 fwd_xprt_info->xprt->write(pkt, pkt->length, 0);
988 mutex_unlock(&fwd_xprt_info->tx_lock);
989 mutex_unlock(&rt_entry->lock);
990 mutex_unlock(&routing_table_lock);
991
992 return 0;
993}
994
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600995static void reset_remote_port_info(uint32_t node_id, uint32_t port_id)
996{
997 struct msm_ipc_router_remote_port *rport_ptr;
998
999 rport_ptr = msm_ipc_router_lookup_remote_port(node_id, port_id);
1000 if (!rport_ptr) {
1001 pr_err("%s: No such remote port %08x:%08x\n",
1002 __func__, node_id, port_id);
1003 return;
1004 }
1005 mutex_lock(&rport_ptr->quota_lock);
1006 rport_ptr->restart_state = RESTART_PEND;
1007 wake_up(&rport_ptr->quota_wait);
1008 mutex_unlock(&rport_ptr->quota_lock);
1009 return;
1010}
1011
1012static void msm_ipc_cleanup_remote_server_info(
1013 struct msm_ipc_router_xprt_info *xprt_info)
1014{
1015 struct msm_ipc_server *svr, *tmp_svr;
1016 struct msm_ipc_server_port *svr_port, *tmp_svr_port;
1017 int i;
1018 union rr_control_msg ctl;
1019
1020 if (!xprt_info) {
1021 pr_err("%s: Invalid xprt_info\n", __func__);
1022 return;
1023 }
1024
1025 ctl.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_SERVER;
1026 mutex_lock(&server_list_lock);
1027 for (i = 0; i < SRV_HASH_SIZE; i++) {
1028 list_for_each_entry_safe(svr, tmp_svr, &server_list[i], list) {
1029 ctl.srv.service = svr->name.service;
1030 ctl.srv.instance = svr->name.instance;
1031 list_for_each_entry_safe(svr_port, tmp_svr_port,
1032 &svr->server_port_list, list) {
1033 if (svr_port->xprt_info != xprt_info)
1034 continue;
1035 D("Remove server %08x:%08x - %08x:%08x",
1036 ctl.srv.service, ctl.srv.instance,
1037 svr_port->server_addr.node_id,
1038 svr_port->server_addr.port_id);
1039 reset_remote_port_info(
1040 svr_port->server_addr.node_id,
1041 svr_port->server_addr.port_id);
1042 ctl.srv.node_id = svr_port->server_addr.node_id;
1043 ctl.srv.port_id = svr_port->server_addr.port_id;
1044 relay_ctl_msg(xprt_info, &ctl);
1045 broadcast_ctl_msg_locally(&ctl);
1046 list_del(&svr_port->list);
1047 kfree(svr_port);
1048 }
1049 if (list_empty(&svr->server_port_list)) {
1050 list_del(&svr->list);
1051 kfree(svr);
1052 }
1053 }
1054 }
1055 mutex_unlock(&server_list_lock);
1056}
1057
1058static void msm_ipc_cleanup_remote_client_info(
1059 struct msm_ipc_router_xprt_info *xprt_info)
1060{
1061 struct msm_ipc_routing_table_entry *rt_entry;
1062 struct msm_ipc_router_remote_port *rport_ptr;
1063 int i, j;
1064 union rr_control_msg ctl;
1065
1066 if (!xprt_info) {
1067 pr_err("%s: Invalid xprt_info\n", __func__);
1068 return;
1069 }
1070
1071 ctl.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT;
1072 mutex_lock(&routing_table_lock);
1073 for (i = 0; i < RT_HASH_SIZE; i++) {
1074 list_for_each_entry(rt_entry, &routing_table[i], list) {
1075 mutex_lock(&rt_entry->lock);
1076 if (rt_entry->xprt_info != xprt_info) {
1077 mutex_unlock(&rt_entry->lock);
1078 continue;
1079 }
1080 for (j = 0; j < RP_HASH_SIZE; j++) {
1081 list_for_each_entry(rport_ptr,
1082 &rt_entry->remote_port_list[j], list) {
1083 if (rport_ptr->restart_state ==
1084 RESTART_PEND)
1085 continue;
1086 mutex_lock(&rport_ptr->quota_lock);
1087 rport_ptr->restart_state = RESTART_PEND;
1088 wake_up(&rport_ptr->quota_wait);
1089 mutex_unlock(&rport_ptr->quota_lock);
1090 ctl.cli.node_id = rport_ptr->node_id;
1091 ctl.cli.port_id = rport_ptr->port_id;
1092 broadcast_ctl_msg_locally(&ctl);
1093 }
1094 }
1095 mutex_unlock(&rt_entry->lock);
1096 }
1097 }
1098 mutex_unlock(&routing_table_lock);
1099}
1100
1101static void msm_ipc_cleanup_remote_port_info(uint32_t node_id)
1102{
1103 struct msm_ipc_routing_table_entry *rt_entry, *tmp_rt_entry;
1104 struct msm_ipc_router_remote_port *rport_ptr, *tmp_rport_ptr;
1105 int i, j;
1106
1107 mutex_lock(&routing_table_lock);
1108 for (i = 0; i < RT_HASH_SIZE; i++) {
1109 list_for_each_entry_safe(rt_entry, tmp_rt_entry,
1110 &routing_table[i], list) {
1111 mutex_lock(&rt_entry->lock);
1112 if (rt_entry->neighbor_node_id != node_id) {
1113 mutex_unlock(&rt_entry->lock);
1114 continue;
1115 }
1116 for (j = 0; j < RP_HASH_SIZE; j++) {
1117 list_for_each_entry_safe(rport_ptr,
1118 tmp_rport_ptr,
1119 &rt_entry->remote_port_list[j], list) {
1120 list_del(&rport_ptr->list);
1121 kfree(rport_ptr);
1122 }
1123 }
1124 mutex_unlock(&rt_entry->lock);
1125 }
1126 }
1127 mutex_unlock(&routing_table_lock);
1128}
1129
1130static void msm_ipc_cleanup_routing_table(
1131 struct msm_ipc_router_xprt_info *xprt_info)
1132{
1133 int i;
1134 struct msm_ipc_routing_table_entry *rt_entry;
1135
1136 if (!xprt_info) {
1137 pr_err("%s: Invalid xprt_info\n", __func__);
1138 return;
1139 }
1140
1141 mutex_lock(&routing_table_lock);
1142 for (i = 0; i < RT_HASH_SIZE; i++) {
1143 list_for_each_entry(rt_entry, &routing_table[i], list) {
1144 mutex_lock(&rt_entry->lock);
1145 if (rt_entry->xprt_info == xprt_info)
1146 rt_entry->xprt_info = NULL;
1147 mutex_unlock(&rt_entry->lock);
1148 }
1149 }
1150 mutex_unlock(&routing_table_lock);
1151}
1152
1153static void modem_reset_cleanup(struct msm_ipc_router_xprt_info *xprt_info)
1154{
1155
1156 if (!xprt_info) {
1157 pr_err("%s: Invalid xprt_info\n", __func__);
1158 return;
1159 }
1160
1161 msm_ipc_cleanup_remote_server_info(xprt_info);
1162 msm_ipc_cleanup_remote_client_info(xprt_info);
1163 msm_ipc_cleanup_routing_table(xprt_info);
1164}
1165
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001166static int process_control_msg(struct msm_ipc_router_xprt_info *xprt_info,
1167 struct rr_packet *pkt)
1168{
1169 union rr_control_msg ctl;
1170 union rr_control_msg *msg;
1171 struct msm_ipc_router_remote_port *rport_ptr;
1172 int rc = 0;
1173 static uint32_t first = 1;
1174 struct sk_buff *temp_ptr;
1175 struct rr_header *hdr;
1176 struct msm_ipc_server *server;
1177 struct msm_ipc_routing_table_entry *rt_entry;
1178
1179 if (pkt->length != (IPC_ROUTER_HDR_SIZE + sizeof(*msg))) {
1180 pr_err("%s: r2r msg size %d != %d\n", __func__, pkt->length,
1181 (IPC_ROUTER_HDR_SIZE + sizeof(*msg)));
1182 return -EINVAL;
1183 }
1184
1185 temp_ptr = skb_peek(pkt->pkt_fragment_q);
Karthikeyan Ramasubramanian9024dd82011-12-19 18:44:19 -07001186 if (!temp_ptr) {
1187 pr_err("%s: pkt_fragment_q is empty\n", __func__);
1188 return -EINVAL;
1189 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001190 hdr = (struct rr_header *)temp_ptr->data;
Karthikeyan Ramasubramanian9024dd82011-12-19 18:44:19 -07001191 if (!hdr) {
1192 pr_err("%s: No data inside the skb\n", __func__);
1193 return -EINVAL;
1194 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001195 msg = (union rr_control_msg *)((char *)hdr + IPC_ROUTER_HDR_SIZE);
1196
1197 switch (msg->cmd) {
1198 case IPC_ROUTER_CTRL_CMD_HELLO:
1199 RR("o HELLO NID %d\n", hdr->src_node_id);
1200 xprt_info->remote_node_id = hdr->src_node_id;
1201
1202 mutex_lock(&routing_table_lock);
1203 rt_entry = lookup_routing_table(hdr->src_node_id);
1204 if (!rt_entry) {
1205 rt_entry = alloc_routing_table_entry(hdr->src_node_id);
1206 if (!rt_entry) {
1207 mutex_unlock(&routing_table_lock);
1208 pr_err("%s: rt_entry allocation failed\n",
1209 __func__);
1210 return -ENOMEM;
1211 }
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001212 add_routing_table_entry(rt_entry);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001213 }
1214 mutex_lock(&rt_entry->lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001215 rt_entry->neighbor_node_id = xprt_info->remote_node_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001216 rt_entry->xprt_info = xprt_info;
1217 mutex_unlock(&rt_entry->lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001218 mutex_unlock(&routing_table_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001219 msm_ipc_cleanup_remote_port_info(xprt_info->remote_node_id);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001220
1221 memset(&ctl, 0, sizeof(ctl));
1222 ctl.cmd = IPC_ROUTER_CTRL_CMD_HELLO;
1223 msm_ipc_router_send_control_msg(xprt_info, &ctl);
1224
1225 xprt_info->initialized = 1;
1226
1227 /* Send list of servers one at a time */
1228 msm_ipc_router_send_server_list(xprt_info);
1229
1230 if (first) {
1231 first = 0;
1232 complete_all(&msm_ipc_remote_router_up);
1233 }
1234 RR("HELLO message processed\n");
1235 break;
1236 case IPC_ROUTER_CTRL_CMD_RESUME_TX:
1237 RR("o RESUME_TX id=%d:%08x\n",
1238 msg->cli.node_id, msg->cli.port_id);
1239
1240 rport_ptr = msm_ipc_router_lookup_remote_port(msg->cli.node_id,
1241 msg->cli.port_id);
1242 if (!rport_ptr) {
1243 pr_err("%s: Unable to resume client\n", __func__);
1244 break;
1245 }
1246 mutex_lock(&rport_ptr->quota_lock);
1247 rport_ptr->tx_quota_cnt = 0;
1248 mutex_unlock(&rport_ptr->quota_lock);
1249 wake_up(&rport_ptr->quota_wait);
1250 break;
1251
1252 case IPC_ROUTER_CTRL_CMD_NEW_SERVER:
1253 if (msg->srv.instance == 0) {
1254 pr_err(
1255 "rpcrouter: Server create rejected, version = 0, "
1256 "service = %08x\n", msg->srv.service);
1257 break;
1258 }
1259
1260 RR("o NEW_SERVER id=%d:%08x service=%08x:%08x\n",
1261 msg->srv.node_id, msg->srv.port_id,
1262 msg->srv.service, msg->srv.instance);
1263
1264 mutex_lock(&routing_table_lock);
1265 rt_entry = lookup_routing_table(msg->srv.node_id);
1266 if (!rt_entry) {
1267 rt_entry = alloc_routing_table_entry(msg->srv.node_id);
1268 if (!rt_entry) {
1269 mutex_unlock(&routing_table_lock);
1270 pr_err("%s: rt_entry allocation failed\n",
1271 __func__);
1272 return -ENOMEM;
1273 }
1274 mutex_lock(&rt_entry->lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001275 rt_entry->neighbor_node_id = xprt_info->remote_node_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001276 rt_entry->xprt_info = xprt_info;
1277 mutex_unlock(&rt_entry->lock);
1278 add_routing_table_entry(rt_entry);
1279 }
1280 mutex_unlock(&routing_table_lock);
1281
1282 server = msm_ipc_router_lookup_server(msg->srv.service,
1283 msg->srv.instance,
1284 msg->srv.node_id,
1285 msg->srv.port_id);
1286 if (!server) {
1287 server = msm_ipc_router_create_server(
1288 msg->srv.service, msg->srv.instance,
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001289 msg->srv.node_id, msg->srv.port_id, xprt_info);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001290 if (!server) {
1291 pr_err("%s: Server Create failed\n", __func__);
1292 return -ENOMEM;
1293 }
1294
1295 if (!msm_ipc_router_lookup_remote_port(
1296 msg->srv.node_id, msg->srv.port_id)) {
1297 rport_ptr = msm_ipc_router_create_remote_port(
1298 msg->srv.node_id, msg->srv.port_id);
1299 if (!rport_ptr)
1300 pr_err("%s: Remote port create "
1301 "failed\n", __func__);
1302 }
1303 wake_up(&newserver_wait);
1304 }
1305
1306 relay_msg(xprt_info, pkt);
1307 post_control_ports(pkt);
1308 break;
1309 case IPC_ROUTER_CTRL_CMD_REMOVE_SERVER:
1310 RR("o REMOVE_SERVER service=%08x:%d\n",
1311 msg->srv.service, msg->srv.instance);
1312 server = msm_ipc_router_lookup_server(msg->srv.service,
1313 msg->srv.instance,
1314 msg->srv.node_id,
1315 msg->srv.port_id);
1316 if (server) {
1317 msm_ipc_router_destroy_server(server,
1318 msg->srv.node_id,
1319 msg->srv.port_id);
1320 relay_msg(xprt_info, pkt);
1321 post_control_ports(pkt);
1322 }
1323 break;
1324 case IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT:
1325 RR("o REMOVE_CLIENT id=%d:%08x\n",
1326 msg->cli.node_id, msg->cli.port_id);
1327 rport_ptr = msm_ipc_router_lookup_remote_port(msg->cli.node_id,
1328 msg->cli.port_id);
1329 if (rport_ptr)
1330 msm_ipc_router_destroy_remote_port(rport_ptr);
1331
1332 relay_msg(xprt_info, pkt);
1333 post_control_ports(pkt);
1334 break;
1335 case IPC_ROUTER_CTRL_CMD_PING:
1336 /* No action needed for ping messages received */
1337 RR("o PING\n");
1338 break;
1339 default:
1340 RR("o UNKNOWN(%08x)\n", msg->cmd);
1341 rc = -ENOSYS;
1342 }
1343
1344 return rc;
1345}
1346
1347static void do_read_data(struct work_struct *work)
1348{
1349 struct rr_header *hdr;
1350 struct rr_packet *pkt = NULL;
1351 struct msm_ipc_port *port_ptr;
1352 struct sk_buff *head_skb;
1353 struct msm_ipc_port_addr *src_addr;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001354 struct msm_ipc_router_remote_port *rport_ptr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001355 uint32_t resume_tx, resume_tx_node_id, resume_tx_port_id;
1356
1357 struct msm_ipc_router_xprt_info *xprt_info =
1358 container_of(work,
1359 struct msm_ipc_router_xprt_info,
1360 read_data);
1361
1362 pkt = rr_read(xprt_info);
1363 if (!pkt) {
1364 pr_err("%s: rr_read failed\n", __func__);
1365 goto fail_io;
1366 }
1367
1368 if (pkt->length < IPC_ROUTER_HDR_SIZE ||
1369 pkt->length > MAX_IPC_PKT_SIZE) {
1370 pr_err("%s: Invalid pkt length %d\n", __func__, pkt->length);
1371 goto fail_data;
1372 }
1373
1374 head_skb = skb_peek(pkt->pkt_fragment_q);
1375 if (!head_skb) {
1376 pr_err("%s: head_skb is invalid\n", __func__);
1377 goto fail_data;
1378 }
1379
1380 hdr = (struct rr_header *)(head_skb->data);
1381 RR("- ver=%d type=%d src=%d:%08x crx=%d siz=%d dst=%d:%08x\n",
1382 hdr->version, hdr->type, hdr->src_node_id, hdr->src_port_id,
1383 hdr->confirm_rx, hdr->size, hdr->dst_node_id, hdr->dst_port_id);
1384 RAW_HDR("[r rr_h] "
1385 "ver=%i,type=%s,src_node_id=%08x,src_port_id=%08x,"
1386 "confirm_rx=%i,size=%3i,dst_node_id=%08x,dst_port_id=%08x\n",
1387 hdr->version, type_to_str(hdr->type), hdr->src_node_id,
1388 hdr->src_port_id, hdr->confirm_rx, hdr->size, hdr->dst_node_id,
1389 hdr->dst_port_id);
1390
1391 if (hdr->version != IPC_ROUTER_VERSION) {
1392 pr_err("version %d != %d\n", hdr->version, IPC_ROUTER_VERSION);
1393 goto fail_data;
1394 }
1395
1396 if ((hdr->dst_node_id != IPC_ROUTER_NID_LOCAL) &&
1397 ((hdr->type == IPC_ROUTER_CTRL_CMD_RESUME_TX) ||
1398 (hdr->type == IPC_ROUTER_CTRL_CMD_DATA))) {
1399 forward_msg(xprt_info, pkt);
1400 release_pkt(pkt);
1401 goto done;
1402 }
1403
1404 if ((hdr->dst_port_id == IPC_ROUTER_ADDRESS) ||
1405 (hdr->type == IPC_ROUTER_CTRL_CMD_HELLO)) {
1406 process_control_msg(xprt_info, pkt);
1407 release_pkt(pkt);
1408 goto done;
1409 }
1410#if defined(CONFIG_MSM_SMD_LOGGING)
1411#if defined(DEBUG)
1412 if (msm_ipc_router_debug_mask & SMEM_LOG) {
1413 smem_log_event((SMEM_LOG_PROC_ID_APPS |
1414 SMEM_LOG_RPC_ROUTER_EVENT_BASE |
1415 IPC_ROUTER_LOG_EVENT_RX),
1416 (hdr->src_node_id << 24) |
1417 (hdr->src_port_id & 0xffffff),
1418 (hdr->dst_node_id << 24) |
1419 (hdr->dst_port_id & 0xffffff),
1420 (hdr->type << 24) | (hdr->confirm_rx << 16) |
1421 (hdr->size & 0xffff));
1422 }
1423#endif
1424#endif
1425
1426 resume_tx = hdr->confirm_rx;
1427 resume_tx_node_id = hdr->dst_node_id;
1428 resume_tx_port_id = hdr->dst_port_id;
1429
1430 port_ptr = msm_ipc_router_lookup_local_port(hdr->dst_port_id);
1431 if (!port_ptr) {
1432 pr_err("%s: No local port id %08x\n", __func__,
1433 hdr->dst_port_id);
1434 release_pkt(pkt);
1435 goto process_done;
1436 }
1437
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001438 rport_ptr = msm_ipc_router_lookup_remote_port(hdr->src_node_id,
1439 hdr->src_port_id);
1440 if (!rport_ptr) {
1441 rport_ptr = msm_ipc_router_create_remote_port(
1442 hdr->src_node_id,
1443 hdr->src_port_id);
1444 if (!rport_ptr) {
1445 pr_err("%s: Remote port %08x:%08x creation failed\n",
1446 __func__, hdr->src_node_id, hdr->src_port_id);
1447 goto process_done;
1448 }
1449 }
1450
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001451 if (!port_ptr->notify) {
1452 mutex_lock(&port_ptr->port_rx_q_lock);
1453 wake_lock(&port_ptr->port_rx_wake_lock);
1454 list_add_tail(&pkt->list, &port_ptr->port_rx_q);
1455 wake_up(&port_ptr->port_rx_wait_q);
1456 mutex_unlock(&port_ptr->port_rx_q_lock);
1457 } else {
1458 src_addr = kmalloc(sizeof(struct msm_ipc_port_addr),
1459 GFP_KERNEL);
1460 if (src_addr) {
1461 src_addr->node_id = hdr->src_node_id;
1462 src_addr->port_id = hdr->src_port_id;
1463 }
1464 skb_pull(head_skb, IPC_ROUTER_HDR_SIZE);
1465 port_ptr->notify(MSM_IPC_ROUTER_READ_CB, pkt->pkt_fragment_q,
1466 src_addr, port_ptr->priv);
1467 pkt->pkt_fragment_q = NULL;
1468 src_addr = NULL;
1469 release_pkt(pkt);
1470 }
1471
1472process_done:
1473 if (resume_tx) {
1474 union rr_control_msg msg;
1475
1476 msg.cmd = IPC_ROUTER_CTRL_CMD_RESUME_TX;
1477 msg.cli.node_id = resume_tx_node_id;
1478 msg.cli.port_id = resume_tx_port_id;
1479
1480 RR("x RESUME_TX id=%d:%08x\n",
1481 msg.cli.node_id, msg.cli.port_id);
1482 msm_ipc_router_send_control_msg(xprt_info, &msg);
1483 }
1484
1485done:
1486 queue_work(xprt_info->workqueue, &xprt_info->read_data);
1487 return;
1488
1489fail_data:
1490 release_pkt(pkt);
1491fail_io:
1492 pr_err("ipc_router has died\n");
1493}
1494
1495int msm_ipc_router_register_server(struct msm_ipc_port *port_ptr,
1496 struct msm_ipc_addr *name)
1497{
1498 struct msm_ipc_server *server;
1499 unsigned long flags;
1500 union rr_control_msg ctl;
1501
1502 if (!port_ptr || !name)
1503 return -EINVAL;
1504
1505 if (name->addrtype != MSM_IPC_ADDR_NAME)
1506 return -EINVAL;
1507
1508 server = msm_ipc_router_lookup_server(name->addr.port_name.service,
1509 name->addr.port_name.instance,
1510 IPC_ROUTER_NID_LOCAL,
1511 port_ptr->this_port.port_id);
1512 if (server) {
1513 pr_err("%s: Server already present\n", __func__);
1514 return -EINVAL;
1515 }
1516
1517 server = msm_ipc_router_create_server(name->addr.port_name.service,
1518 name->addr.port_name.instance,
1519 IPC_ROUTER_NID_LOCAL,
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001520 port_ptr->this_port.port_id,
1521 NULL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001522 if (!server) {
1523 pr_err("%s: Server Creation failed\n", __func__);
1524 return -EINVAL;
1525 }
1526
1527 ctl.cmd = IPC_ROUTER_CTRL_CMD_NEW_SERVER;
1528 ctl.srv.service = server->name.service;
1529 ctl.srv.instance = server->name.instance;
1530 ctl.srv.node_id = IPC_ROUTER_NID_LOCAL;
1531 ctl.srv.port_id = port_ptr->this_port.port_id;
1532 broadcast_ctl_msg(&ctl);
1533 spin_lock_irqsave(&port_ptr->port_lock, flags);
1534 port_ptr->type = SERVER_PORT;
1535 port_ptr->port_name.service = server->name.service;
1536 port_ptr->port_name.instance = server->name.instance;
1537 spin_unlock_irqrestore(&port_ptr->port_lock, flags);
1538 return 0;
1539}
1540
1541int msm_ipc_router_unregister_server(struct msm_ipc_port *port_ptr)
1542{
1543 struct msm_ipc_server *server;
1544 unsigned long flags;
1545 union rr_control_msg ctl;
1546
1547 if (!port_ptr)
1548 return -EINVAL;
1549
1550 if (port_ptr->type != SERVER_PORT) {
1551 pr_err("%s: Trying to unregister a non-server port\n",
1552 __func__);
1553 return -EINVAL;
1554 }
1555
1556 if (port_ptr->this_port.node_id != IPC_ROUTER_NID_LOCAL) {
1557 pr_err("%s: Trying to unregister a remote server locally\n",
1558 __func__);
1559 return -EINVAL;
1560 }
1561
1562 server = msm_ipc_router_lookup_server(port_ptr->port_name.service,
1563 port_ptr->port_name.instance,
1564 port_ptr->this_port.node_id,
1565 port_ptr->this_port.port_id);
1566 if (!server) {
1567 pr_err("%s: Server lookup failed\n", __func__);
1568 return -ENODEV;
1569 }
1570
1571 ctl.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_SERVER;
1572 ctl.srv.service = server->name.service;
1573 ctl.srv.instance = server->name.instance;
1574 ctl.srv.node_id = IPC_ROUTER_NID_LOCAL;
1575 ctl.srv.port_id = port_ptr->this_port.port_id;
1576 broadcast_ctl_msg(&ctl);
1577 msm_ipc_router_destroy_server(server, port_ptr->this_port.node_id,
1578 port_ptr->this_port.port_id);
1579 spin_lock_irqsave(&port_ptr->port_lock, flags);
1580 port_ptr->type = CLIENT_PORT;
1581 spin_unlock_irqrestore(&port_ptr->port_lock, flags);
1582 return 0;
1583}
1584
1585static int loopback_data(struct msm_ipc_port *src,
1586 uint32_t port_id,
1587 struct sk_buff_head *data)
1588{
1589 struct sk_buff *head_skb;
1590 struct rr_header *hdr;
1591 struct msm_ipc_port *port_ptr;
1592 struct rr_packet *pkt;
1593
1594 if (!data) {
1595 pr_err("%s: Invalid pkt pointer\n", __func__);
1596 return -EINVAL;
1597 }
1598
1599 pkt = create_pkt(data);
1600 if (!pkt) {
1601 pr_err("%s: New pkt create failed\n", __func__);
1602 return -ENOMEM;
1603 }
1604
1605 head_skb = skb_peek(pkt->pkt_fragment_q);
Karthikeyan Ramasubramanian9024dd82011-12-19 18:44:19 -07001606 if (!head_skb) {
1607 pr_err("%s: pkt_fragment_q is empty\n", __func__);
1608 return -EINVAL;
1609 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001610 hdr = (struct rr_header *)skb_push(head_skb, IPC_ROUTER_HDR_SIZE);
1611 if (!hdr) {
1612 pr_err("%s: Prepend Header failed\n", __func__);
1613 release_pkt(pkt);
1614 return -ENOMEM;
1615 }
1616 hdr->version = IPC_ROUTER_VERSION;
1617 hdr->type = IPC_ROUTER_CTRL_CMD_DATA;
1618 hdr->src_node_id = src->this_port.node_id;
1619 hdr->src_port_id = src->this_port.port_id;
1620 hdr->size = pkt->length;
1621 hdr->confirm_rx = 0;
1622 hdr->dst_node_id = IPC_ROUTER_NID_LOCAL;
1623 hdr->dst_port_id = port_id;
1624 pkt->length += IPC_ROUTER_HDR_SIZE;
1625
1626 port_ptr = msm_ipc_router_lookup_local_port(port_id);
1627 if (!port_ptr) {
1628 pr_err("%s: Local port %d not present\n", __func__, port_id);
1629 release_pkt(pkt);
1630 return -ENODEV;
1631 }
1632
1633 mutex_lock(&port_ptr->port_rx_q_lock);
1634 wake_lock(&port_ptr->port_rx_wake_lock);
1635 list_add_tail(&pkt->list, &port_ptr->port_rx_q);
1636 wake_up(&port_ptr->port_rx_wait_q);
1637 mutex_unlock(&port_ptr->port_rx_q_lock);
1638
1639 return pkt->length;
1640}
1641
1642static int msm_ipc_router_write_pkt(struct msm_ipc_port *src,
1643 struct msm_ipc_router_remote_port *rport_ptr,
1644 struct rr_packet *pkt)
1645{
1646 struct sk_buff *head_skb;
1647 struct rr_header *hdr;
1648 struct msm_ipc_router_xprt_info *xprt_info;
1649 struct msm_ipc_routing_table_entry *rt_entry;
1650 int ret;
1651 DEFINE_WAIT(__wait);
1652
1653 if (!rport_ptr || !src || !pkt)
1654 return -EINVAL;
1655
1656 head_skb = skb_peek(pkt->pkt_fragment_q);
Karthikeyan Ramasubramanian9024dd82011-12-19 18:44:19 -07001657 if (!head_skb) {
1658 pr_err("%s: pkt_fragment_q is empty\n", __func__);
1659 return -EINVAL;
1660 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001661 hdr = (struct rr_header *)skb_push(head_skb, IPC_ROUTER_HDR_SIZE);
1662 if (!hdr) {
1663 pr_err("%s: Prepend Header failed\n", __func__);
1664 return -ENOMEM;
1665 }
1666 hdr->version = IPC_ROUTER_VERSION;
1667 hdr->type = IPC_ROUTER_CTRL_CMD_DATA;
1668 hdr->src_node_id = src->this_port.node_id;
1669 hdr->src_port_id = src->this_port.port_id;
1670 hdr->size = pkt->length;
1671 hdr->confirm_rx = 0;
1672 hdr->dst_node_id = rport_ptr->node_id;
1673 hdr->dst_port_id = rport_ptr->port_id;
1674 pkt->length += IPC_ROUTER_HDR_SIZE;
1675
1676 for (;;) {
1677 prepare_to_wait(&rport_ptr->quota_wait, &__wait,
1678 TASK_INTERRUPTIBLE);
1679 mutex_lock(&rport_ptr->quota_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001680 if (rport_ptr->restart_state != RESTART_NORMAL)
1681 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001682 if (rport_ptr->tx_quota_cnt <
1683 IPC_ROUTER_DEFAULT_RX_QUOTA)
1684 break;
1685 if (signal_pending(current))
1686 break;
1687 mutex_unlock(&rport_ptr->quota_lock);
1688 schedule();
1689 }
1690 finish_wait(&rport_ptr->quota_wait, &__wait);
1691
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001692 if (rport_ptr->restart_state != RESTART_NORMAL) {
1693 mutex_unlock(&rport_ptr->quota_lock);
1694 return -ENETRESET;
1695 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001696 if (signal_pending(current)) {
1697 mutex_unlock(&rport_ptr->quota_lock);
1698 return -ERESTARTSYS;
1699 }
1700 rport_ptr->tx_quota_cnt++;
1701 if (rport_ptr->tx_quota_cnt == IPC_ROUTER_DEFAULT_RX_QUOTA)
1702 hdr->confirm_rx = 1;
1703 mutex_unlock(&rport_ptr->quota_lock);
1704
1705 mutex_lock(&routing_table_lock);
1706 rt_entry = lookup_routing_table(hdr->dst_node_id);
1707 if (!rt_entry || !rt_entry->xprt_info) {
1708 mutex_unlock(&routing_table_lock);
1709 pr_err("%s: Remote node %d not up\n",
1710 __func__, hdr->dst_node_id);
1711 return -ENODEV;
1712 }
1713 mutex_lock(&rt_entry->lock);
1714 xprt_info = rt_entry->xprt_info;
1715 mutex_lock(&xprt_info->tx_lock);
1716 ret = xprt_info->xprt->write(pkt, pkt->length, 0);
1717 mutex_unlock(&xprt_info->tx_lock);
1718 mutex_unlock(&rt_entry->lock);
1719 mutex_unlock(&routing_table_lock);
1720
1721 if (ret < 0) {
1722 pr_err("%s: Write on XPRT failed\n", __func__);
1723 return ret;
1724 }
1725
1726 RAW_HDR("[w rr_h] "
1727 "ver=%i,type=%s,src_nid=%08x,src_port_id=%08x,"
1728 "confirm_rx=%i,size=%3i,dst_pid=%08x,dst_cid=%08x\n",
1729 hdr->version, type_to_str(hdr->type),
1730 hdr->src_node_id, hdr->src_port_id,
1731 hdr->confirm_rx, hdr->size,
1732 hdr->dst_node_id, hdr->dst_port_id);
1733
1734#if defined(CONFIG_MSM_SMD_LOGGING)
1735#if defined(DEBUG)
1736 if (msm_ipc_router_debug_mask & SMEM_LOG) {
1737 smem_log_event((SMEM_LOG_PROC_ID_APPS |
1738 SMEM_LOG_RPC_ROUTER_EVENT_BASE |
1739 IPC_ROUTER_LOG_EVENT_TX),
1740 (hdr->src_node_id << 24) |
1741 (hdr->src_port_id & 0xffffff),
1742 (hdr->dst_node_id << 24) |
1743 (hdr->dst_port_id & 0xffffff),
1744 (hdr->type << 24) | (hdr->confirm_rx << 16) |
1745 (hdr->size & 0xffff));
1746 }
1747#endif
1748#endif
1749
1750 return pkt->length;
1751}
1752
1753int msm_ipc_router_send_to(struct msm_ipc_port *src,
1754 struct sk_buff_head *data,
1755 struct msm_ipc_addr *dest)
1756{
1757 uint32_t dst_node_id = 0, dst_port_id = 0;
1758 struct msm_ipc_server *server;
1759 struct msm_ipc_server_port *server_port;
1760 struct msm_ipc_router_remote_port *rport_ptr = NULL;
1761 struct rr_packet *pkt;
1762 int ret;
1763
1764 if (!src || !data || !dest) {
1765 pr_err("%s: Invalid Parameters\n", __func__);
1766 return -EINVAL;
1767 }
1768
1769 /* Resolve Address*/
1770 if (dest->addrtype == MSM_IPC_ADDR_ID) {
1771 dst_node_id = dest->addr.port_addr.node_id;
1772 dst_port_id = dest->addr.port_addr.port_id;
1773 } else if (dest->addrtype == MSM_IPC_ADDR_NAME) {
1774 server = msm_ipc_router_lookup_server(
1775 dest->addr.port_name.service,
1776 dest->addr.port_name.instance,
1777 0, 0);
1778 if (!server) {
1779 pr_err("%s: Destination not reachable\n", __func__);
1780 return -ENODEV;
1781 }
1782 mutex_lock(&server_list_lock);
1783 server_port = list_first_entry(&server->server_port_list,
1784 struct msm_ipc_server_port,
1785 list);
1786 dst_node_id = server_port->server_addr.node_id;
1787 dst_port_id = server_port->server_addr.port_id;
1788 mutex_unlock(&server_list_lock);
1789 }
1790 if (dst_node_id == IPC_ROUTER_NID_LOCAL) {
1791 ret = loopback_data(src, dst_port_id, data);
1792 return ret;
1793 }
1794
1795 /* Achieve Flow control */
1796 rport_ptr = msm_ipc_router_lookup_remote_port(dst_node_id,
1797 dst_port_id);
1798 if (!rport_ptr) {
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001799 pr_err("%s: Could not create remote port\n", __func__);
1800 return -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001801 }
1802
1803 pkt = create_pkt(data);
1804 if (!pkt) {
1805 pr_err("%s: Pkt creation failed\n", __func__);
1806 return -ENOMEM;
1807 }
1808
1809 ret = msm_ipc_router_write_pkt(src, rport_ptr, pkt);
1810 release_pkt(pkt);
1811
1812 return ret;
1813}
1814
1815int msm_ipc_router_read(struct msm_ipc_port *port_ptr,
1816 struct sk_buff_head **data,
1817 size_t buf_len)
1818{
1819 struct rr_packet *pkt;
1820 int ret;
1821
1822 if (!port_ptr || !data)
1823 return -EINVAL;
1824
1825 mutex_lock(&port_ptr->port_rx_q_lock);
1826 if (list_empty(&port_ptr->port_rx_q)) {
1827 mutex_unlock(&port_ptr->port_rx_q_lock);
1828 return -EAGAIN;
1829 }
1830
1831 pkt = list_first_entry(&port_ptr->port_rx_q, struct rr_packet, list);
1832 if ((buf_len) && ((pkt->length - IPC_ROUTER_HDR_SIZE) > buf_len)) {
1833 mutex_unlock(&port_ptr->port_rx_q_lock);
1834 return -ETOOSMALL;
1835 }
1836 list_del(&pkt->list);
1837 if (list_empty(&port_ptr->port_rx_q))
1838 wake_unlock(&port_ptr->port_rx_wake_lock);
1839 *data = pkt->pkt_fragment_q;
1840 ret = pkt->length;
1841 kfree(pkt);
1842 mutex_unlock(&port_ptr->port_rx_q_lock);
1843
1844 return ret;
1845}
1846
1847int msm_ipc_router_recv_from(struct msm_ipc_port *port_ptr,
1848 struct sk_buff_head **data,
1849 struct msm_ipc_addr *src,
1850 unsigned long timeout)
1851{
1852 int ret, data_len, align_size;
1853 struct sk_buff *temp_skb;
1854 struct rr_header *hdr = NULL;
1855
1856 if (!port_ptr || !data) {
1857 pr_err("%s: Invalid pointers being passed\n", __func__);
1858 return -EINVAL;
1859 }
1860
1861 *data = NULL;
1862 mutex_lock(&port_ptr->port_rx_q_lock);
1863 while (list_empty(&port_ptr->port_rx_q)) {
1864 mutex_unlock(&port_ptr->port_rx_q_lock);
1865 if (timeout < 0) {
1866 ret = wait_event_interruptible(
1867 port_ptr->port_rx_wait_q,
1868 !list_empty(&port_ptr->port_rx_q));
1869 if (ret)
1870 return ret;
1871 } else if (timeout > 0) {
1872 timeout = wait_event_interruptible_timeout(
1873 port_ptr->port_rx_wait_q,
1874 !list_empty(&port_ptr->port_rx_q),
1875 timeout);
1876 if (timeout < 0)
1877 return -EFAULT;
1878 }
1879 if (timeout == 0)
1880 return -ETIMEDOUT;
1881 mutex_lock(&port_ptr->port_rx_q_lock);
1882 }
1883 mutex_unlock(&port_ptr->port_rx_q_lock);
1884
1885 ret = msm_ipc_router_read(port_ptr, data, 0);
1886 if (ret <= 0 || !(*data))
1887 return ret;
1888
1889 temp_skb = skb_peek(*data);
1890 hdr = (struct rr_header *)(temp_skb->data);
1891 if (src) {
1892 src->addrtype = MSM_IPC_ADDR_ID;
1893 src->addr.port_addr.node_id = hdr->src_node_id;
1894 src->addr.port_addr.port_id = hdr->src_port_id;
1895 }
1896
1897 data_len = hdr->size;
1898 skb_pull(temp_skb, IPC_ROUTER_HDR_SIZE);
1899 align_size = ALIGN_SIZE(data_len);
1900 if (align_size) {
1901 temp_skb = skb_peek_tail(*data);
1902 skb_trim(temp_skb, (temp_skb->len - align_size));
1903 }
1904 return data_len;
1905}
1906
1907struct msm_ipc_port *msm_ipc_router_create_port(
1908 void (*notify)(unsigned event, void *data, void *addr, void *priv),
1909 void *priv)
1910{
1911 struct msm_ipc_port *port_ptr;
1912
1913 port_ptr = msm_ipc_router_create_raw_port(NULL, notify, priv);
1914 if (!port_ptr)
1915 pr_err("%s: port_ptr alloc failed\n", __func__);
1916
1917 return port_ptr;
1918}
1919
1920int msm_ipc_router_close_port(struct msm_ipc_port *port_ptr)
1921{
1922 union rr_control_msg msg;
1923 struct rr_packet *pkt, *temp_pkt;
1924 struct msm_ipc_server *server;
1925
1926 if (!port_ptr)
1927 return -EINVAL;
1928
1929 if (port_ptr->type == SERVER_PORT || port_ptr->type == CLIENT_PORT) {
1930 if (port_ptr->type == SERVER_PORT) {
1931 msg.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_SERVER;
1932 msg.srv.service = port_ptr->port_name.service;
1933 msg.srv.instance = port_ptr->port_name.instance;
1934 msg.srv.node_id = port_ptr->this_port.node_id;
1935 msg.srv.port_id = port_ptr->this_port.port_id;
1936 RR("x REMOVE_SERVER Name=%d:%08x Id=%d:%08x\n",
1937 msg.srv.service, msg.srv.instance,
1938 msg.srv.node_id, msg.srv.port_id);
1939 } else if (port_ptr->type == CLIENT_PORT) {
1940 msg.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT;
1941 msg.cli.node_id = port_ptr->this_port.node_id;
1942 msg.cli.port_id = port_ptr->this_port.port_id;
1943 RR("x REMOVE_CLIENT id=%d:%08x\n",
1944 msg.cli.node_id, msg.cli.port_id);
1945 }
1946 broadcast_ctl_msg(&msg);
1947 broadcast_ctl_msg_locally(&msg);
1948 }
1949
1950 mutex_lock(&port_ptr->port_rx_q_lock);
1951 list_for_each_entry_safe(pkt, temp_pkt, &port_ptr->port_rx_q, list) {
1952 list_del(&pkt->list);
1953 release_pkt(pkt);
1954 }
1955 mutex_unlock(&port_ptr->port_rx_q_lock);
1956
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001957 if (port_ptr->type == SERVER_PORT) {
1958 server = msm_ipc_router_lookup_server(
1959 port_ptr->port_name.service,
1960 port_ptr->port_name.instance,
1961 port_ptr->this_port.node_id,
1962 port_ptr->this_port.port_id);
1963 if (server)
1964 msm_ipc_router_destroy_server(server,
1965 port_ptr->this_port.node_id,
1966 port_ptr->this_port.port_id);
1967 mutex_lock(&local_ports_lock);
1968 list_del(&port_ptr->list);
1969 mutex_unlock(&local_ports_lock);
1970 } else if (port_ptr->type == CLIENT_PORT) {
1971 mutex_lock(&local_ports_lock);
1972 list_del(&port_ptr->list);
1973 mutex_unlock(&local_ports_lock);
1974 } else if (port_ptr->type == CONTROL_PORT) {
1975 mutex_lock(&control_ports_lock);
1976 list_del(&port_ptr->list);
1977 mutex_unlock(&control_ports_lock);
1978 }
1979
Karthikeyan Ramasubramaniandd8c3b52011-11-30 16:26:12 -07001980 wake_lock_destroy(&port_ptr->port_rx_wake_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001981 kfree(port_ptr);
1982 return 0;
1983}
1984
1985int msm_ipc_router_get_curr_pkt_size(struct msm_ipc_port *port_ptr)
1986{
1987 struct rr_packet *pkt;
1988 int rc = 0;
1989
1990 if (!port_ptr)
1991 return -EINVAL;
1992
1993 mutex_lock(&port_ptr->port_rx_q_lock);
1994 if (!list_empty(&port_ptr->port_rx_q)) {
1995 pkt = list_first_entry(&port_ptr->port_rx_q,
1996 struct rr_packet, list);
1997 rc = pkt->length;
1998 }
1999 mutex_unlock(&port_ptr->port_rx_q_lock);
2000
2001 return rc;
2002}
2003
2004int msm_ipc_router_bind_control_port(struct msm_ipc_port *port_ptr)
2005{
2006 if (!port_ptr)
2007 return -EINVAL;
2008
2009 mutex_lock(&local_ports_lock);
2010 list_del(&port_ptr->list);
2011 mutex_unlock(&local_ports_lock);
2012 port_ptr->type = CONTROL_PORT;
2013 mutex_lock(&control_ports_lock);
2014 list_add_tail(&port_ptr->list, &control_ports);
2015 mutex_unlock(&control_ports_lock);
2016
2017 return 0;
2018}
2019
2020int msm_ipc_router_lookup_server_name(struct msm_ipc_port_name *srv_name,
2021 struct msm_ipc_port_addr *srv_addr,
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002022 int num_entries_in_array,
2023 uint32_t lookup_mask)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002024{
2025 struct msm_ipc_server *server;
2026 struct msm_ipc_server_port *server_port;
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002027 int key, i = 0; /*num_entries_found*/
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002028
2029 if (!srv_name) {
2030 pr_err("%s: Invalid srv_name\n", __func__);
2031 return -EINVAL;
2032 }
2033
2034 if (num_entries_in_array && !srv_addr) {
2035 pr_err("%s: srv_addr NULL\n", __func__);
2036 return -EINVAL;
2037 }
2038
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002039 mutex_lock(&server_list_lock);
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002040 if (!lookup_mask)
2041 lookup_mask = 0xFFFFFFFF;
2042 for (key = 0; key < SRV_HASH_SIZE; key++) {
2043 list_for_each_entry(server, &server_list[key], list) {
2044 if ((server->name.service != srv_name->service) ||
2045 ((server->name.instance & lookup_mask) !=
2046 srv_name->instance))
2047 continue;
2048
2049 list_for_each_entry(server_port,
2050 &server->server_port_list, list) {
2051 if (i < num_entries_in_array) {
2052 srv_addr[i].node_id =
2053 server_port->server_addr.node_id;
2054 srv_addr[i].port_id =
2055 server_port->server_addr.port_id;
2056 }
2057 i++;
2058 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002059 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002060 }
2061 mutex_unlock(&server_list_lock);
2062
2063 return i;
2064}
2065
2066int msm_ipc_router_close(void)
2067{
2068 struct msm_ipc_router_xprt_info *xprt_info, *tmp_xprt_info;
2069
2070 mutex_lock(&xprt_info_list_lock);
2071 list_for_each_entry_safe(xprt_info, tmp_xprt_info,
2072 &xprt_info_list, list) {
2073 xprt_info->xprt->close();
2074 list_del(&xprt_info->list);
2075 kfree(xprt_info);
2076 }
2077 mutex_unlock(&xprt_info_list_lock);
2078 return 0;
2079}
2080
2081#if defined(CONFIG_DEBUG_FS)
2082static int dump_routing_table(char *buf, int max)
2083{
2084 int i = 0, j;
2085 struct msm_ipc_routing_table_entry *rt_entry;
2086
2087 for (j = 0; j < RT_HASH_SIZE; j++) {
2088 mutex_lock(&routing_table_lock);
2089 list_for_each_entry(rt_entry, &routing_table[j], list) {
2090 mutex_lock(&rt_entry->lock);
2091 i += scnprintf(buf + i, max - i,
2092 "Node Id: 0x%08x\n", rt_entry->node_id);
2093 if (j == IPC_ROUTER_NID_LOCAL) {
2094 i += scnprintf(buf + i, max - i,
2095 "XPRT Name: Loopback\n");
2096 i += scnprintf(buf + i, max - i,
2097 "Next Hop: %d\n", rt_entry->node_id);
2098 } else {
2099 i += scnprintf(buf + i, max - i,
2100 "XPRT Name: %s\n",
2101 rt_entry->xprt_info->xprt->name);
2102 i += scnprintf(buf + i, max - i,
2103 "Next Hop: 0x%08x\n",
2104 rt_entry->xprt_info->remote_node_id);
2105 }
2106 i += scnprintf(buf + i, max - i, "\n");
2107 mutex_unlock(&rt_entry->lock);
2108 }
2109 mutex_unlock(&routing_table_lock);
2110 }
2111
2112 return i;
2113}
2114
2115static int dump_xprt_info(char *buf, int max)
2116{
2117 int i = 0;
2118 struct msm_ipc_router_xprt_info *xprt_info;
2119
2120 mutex_lock(&xprt_info_list_lock);
2121 list_for_each_entry(xprt_info, &xprt_info_list, list) {
2122 i += scnprintf(buf + i, max - i, "XPRT Name: %s\n",
2123 xprt_info->xprt->name);
2124 i += scnprintf(buf + i, max - i, "Link Id: %d\n",
2125 xprt_info->xprt->link_id);
2126 i += scnprintf(buf + i, max - i, "Initialized: %s\n",
2127 (xprt_info->initialized ? "Y" : "N"));
2128 i += scnprintf(buf + i, max - i, "Remote Node Id: 0x%08x\n",
2129 xprt_info->remote_node_id);
2130 i += scnprintf(buf + i, max - i, "\n");
2131 }
2132 mutex_unlock(&xprt_info_list_lock);
2133
2134 return i;
2135}
2136
2137static int dump_servers(char *buf, int max)
2138{
2139 int i = 0, j;
2140 struct msm_ipc_server *server;
2141 struct msm_ipc_server_port *server_port;
2142
2143 mutex_lock(&server_list_lock);
2144 for (j = 0; j < SRV_HASH_SIZE; j++) {
2145 list_for_each_entry(server, &server_list[j], list) {
2146 list_for_each_entry(server_port,
2147 &server->server_port_list,
2148 list) {
2149 i += scnprintf(buf + i, max - i, "Service: "
2150 "0x%08x\n", server->name.service);
2151 i += scnprintf(buf + i, max - i, "Instance: "
2152 "0x%08x\n", server->name.instance);
2153 i += scnprintf(buf + i, max - i,
2154 "Node_id: 0x%08x\n",
2155 server_port->server_addr.node_id);
2156 i += scnprintf(buf + i, max - i,
2157 "Port_id: 0x%08x\n",
2158 server_port->server_addr.port_id);
2159 i += scnprintf(buf + i, max - i, "\n");
2160 }
2161 }
2162 }
2163 mutex_unlock(&server_list_lock);
2164
2165 return i;
2166}
2167
2168static int dump_remote_ports(char *buf, int max)
2169{
2170 int i = 0, j, k;
2171 struct msm_ipc_router_remote_port *rport_ptr;
2172 struct msm_ipc_routing_table_entry *rt_entry;
2173
2174 for (j = 0; j < RT_HASH_SIZE; j++) {
2175 mutex_lock(&routing_table_lock);
2176 list_for_each_entry(rt_entry, &routing_table[j], list) {
2177 mutex_lock(&rt_entry->lock);
2178 for (k = 0; k < RP_HASH_SIZE; k++) {
2179 list_for_each_entry(rport_ptr,
2180 &rt_entry->remote_port_list[k],
2181 list) {
2182 i += scnprintf(buf + i, max - i,
2183 "Node_id: 0x%08x\n",
2184 rport_ptr->node_id);
2185 i += scnprintf(buf + i, max - i,
2186 "Port_id: 0x%08x\n",
2187 rport_ptr->port_id);
2188 i += scnprintf(buf + i, max - i,
2189 "Quota_cnt: %d\n",
2190 rport_ptr->tx_quota_cnt);
2191 i += scnprintf(buf + i, max - i, "\n");
2192 }
2193 }
2194 mutex_unlock(&rt_entry->lock);
2195 }
2196 mutex_unlock(&routing_table_lock);
2197 }
2198
2199 return i;
2200}
2201
2202static int dump_control_ports(char *buf, int max)
2203{
2204 int i = 0;
2205 struct msm_ipc_port *port_ptr;
2206
2207 mutex_lock(&control_ports_lock);
2208 list_for_each_entry(port_ptr, &control_ports, list) {
2209 i += scnprintf(buf + i, max - i, "Node_id: 0x%08x\n",
2210 port_ptr->this_port.node_id);
2211 i += scnprintf(buf + i, max - i, "Port_id: 0x%08x\n",
2212 port_ptr->this_port.port_id);
2213 i += scnprintf(buf + i, max - i, "\n");
2214 }
2215 mutex_unlock(&control_ports_lock);
2216
2217 return i;
2218}
2219
2220static int dump_local_ports(char *buf, int max)
2221{
2222 int i = 0, j;
2223 unsigned long flags;
2224 struct msm_ipc_port *port_ptr;
2225
2226 mutex_lock(&local_ports_lock);
2227 for (j = 0; j < LP_HASH_SIZE; j++) {
2228 list_for_each_entry(port_ptr, &local_ports[j], list) {
2229 spin_lock_irqsave(&port_ptr->port_lock, flags);
2230 i += scnprintf(buf + i, max - i, "Node_id: 0x%08x\n",
2231 port_ptr->this_port.node_id);
2232 i += scnprintf(buf + i, max - i, "Port_id: 0x%08x\n",
2233 port_ptr->this_port.port_id);
2234 i += scnprintf(buf + i, max - i, "# pkts tx'd %d\n",
2235 port_ptr->num_tx);
2236 i += scnprintf(buf + i, max - i, "# pkts rx'd %d\n",
2237 port_ptr->num_rx);
2238 i += scnprintf(buf + i, max - i, "# bytes tx'd %ld\n",
2239 port_ptr->num_tx_bytes);
2240 i += scnprintf(buf + i, max - i, "# bytes rx'd %ld\n",
2241 port_ptr->num_rx_bytes);
2242 spin_unlock_irqrestore(&port_ptr->port_lock, flags);
2243 i += scnprintf(buf + i, max - i, "\n");
2244 }
2245 }
2246 mutex_unlock(&local_ports_lock);
2247
2248 return i;
2249}
2250
2251#define DEBUG_BUFMAX 4096
2252static char debug_buffer[DEBUG_BUFMAX];
2253
2254static ssize_t debug_read(struct file *file, char __user *buf,
2255 size_t count, loff_t *ppos)
2256{
2257 int (*fill)(char *buf, int max) = file->private_data;
2258 int bsize = fill(debug_buffer, DEBUG_BUFMAX);
2259 return simple_read_from_buffer(buf, count, ppos, debug_buffer, bsize);
2260}
2261
2262static int debug_open(struct inode *inode, struct file *file)
2263{
2264 file->private_data = inode->i_private;
2265 return 0;
2266}
2267
2268static const struct file_operations debug_ops = {
2269 .read = debug_read,
2270 .open = debug_open,
2271};
2272
2273static void debug_create(const char *name, mode_t mode,
2274 struct dentry *dent,
2275 int (*fill)(char *buf, int max))
2276{
2277 debugfs_create_file(name, mode, dent, fill, &debug_ops);
2278}
2279
2280static void debugfs_init(void)
2281{
2282 struct dentry *dent;
2283
2284 dent = debugfs_create_dir("msm_ipc_router", 0);
2285 if (IS_ERR(dent))
2286 return;
2287
2288 debug_create("dump_local_ports", 0444, dent,
2289 dump_local_ports);
2290 debug_create("dump_remote_ports", 0444, dent,
2291 dump_remote_ports);
2292 debug_create("dump_control_ports", 0444, dent,
2293 dump_control_ports);
2294 debug_create("dump_servers", 0444, dent,
2295 dump_servers);
2296 debug_create("dump_xprt_info", 0444, dent,
2297 dump_xprt_info);
2298 debug_create("dump_routing_table", 0444, dent,
2299 dump_routing_table);
2300}
2301
2302#else
2303static void debugfs_init(void) {}
2304#endif
2305
2306static int msm_ipc_router_add_xprt(struct msm_ipc_router_xprt *xprt)
2307{
2308 struct msm_ipc_router_xprt_info *xprt_info;
2309 struct msm_ipc_routing_table_entry *rt_entry;
2310
2311 xprt_info = kmalloc(sizeof(struct msm_ipc_router_xprt_info),
2312 GFP_KERNEL);
2313 if (!xprt_info)
2314 return -ENOMEM;
2315
2316 xprt_info->xprt = xprt;
2317 xprt_info->initialized = 0;
2318 xprt_info->remote_node_id = -1;
2319 INIT_LIST_HEAD(&xprt_info->pkt_list);
2320 init_waitqueue_head(&xprt_info->read_wait);
2321 mutex_init(&xprt_info->rx_lock);
2322 mutex_init(&xprt_info->tx_lock);
2323 wake_lock_init(&xprt_info->wakelock,
2324 WAKE_LOCK_SUSPEND, xprt->name);
2325 xprt_info->need_len = 0;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002326 xprt_info->abort_data_read = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002327 INIT_WORK(&xprt_info->read_data, do_read_data);
2328 INIT_LIST_HEAD(&xprt_info->list);
2329
2330 xprt_info->workqueue = create_singlethread_workqueue(xprt->name);
2331 if (!xprt_info->workqueue) {
2332 kfree(xprt_info);
2333 return -ENOMEM;
2334 }
2335
2336 if (!strcmp(xprt->name, "msm_ipc_router_loopback_xprt")) {
2337 xprt_info->remote_node_id = IPC_ROUTER_NID_LOCAL;
2338 xprt_info->initialized = 1;
2339 }
2340
2341 mutex_lock(&xprt_info_list_lock);
2342 list_add_tail(&xprt_info->list, &xprt_info_list);
2343 mutex_unlock(&xprt_info_list_lock);
2344
2345 mutex_lock(&routing_table_lock);
2346 if (!routing_table_inited) {
2347 init_routing_table();
2348 rt_entry = alloc_routing_table_entry(IPC_ROUTER_NID_LOCAL);
2349 add_routing_table_entry(rt_entry);
2350 routing_table_inited = 1;
2351 }
2352 mutex_unlock(&routing_table_lock);
2353
2354 queue_work(xprt_info->workqueue, &xprt_info->read_data);
2355
2356 xprt->priv = xprt_info;
2357
2358 return 0;
2359}
2360
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002361static void msm_ipc_router_remove_xprt(struct msm_ipc_router_xprt *xprt)
2362{
2363 struct msm_ipc_router_xprt_info *xprt_info;
2364
2365 if (xprt && xprt->priv) {
2366 xprt_info = xprt->priv;
2367
2368 xprt_info->abort_data_read = 1;
2369 wake_up(&xprt_info->read_wait);
2370
2371 mutex_lock(&xprt_info_list_lock);
2372 list_del(&xprt_info->list);
2373 mutex_unlock(&xprt_info_list_lock);
2374
2375 flush_workqueue(xprt_info->workqueue);
2376 destroy_workqueue(xprt_info->workqueue);
2377 wake_lock_destroy(&xprt_info->wakelock);
2378
2379 xprt->priv = 0;
2380 kfree(xprt_info);
2381 }
2382}
2383
2384
2385struct msm_ipc_router_xprt_work {
2386 struct msm_ipc_router_xprt *xprt;
2387 struct work_struct work;
2388};
2389
2390static void xprt_open_worker(struct work_struct *work)
2391{
2392 struct msm_ipc_router_xprt_work *xprt_work =
2393 container_of(work, struct msm_ipc_router_xprt_work, work);
2394
2395 msm_ipc_router_add_xprt(xprt_work->xprt);
2396 kfree(xprt_work);
2397}
2398
2399static void xprt_close_worker(struct work_struct *work)
2400{
2401 struct msm_ipc_router_xprt_work *xprt_work =
2402 container_of(work, struct msm_ipc_router_xprt_work, work);
2403
2404 modem_reset_cleanup(xprt_work->xprt->priv);
2405 msm_ipc_router_remove_xprt(xprt_work->xprt);
2406
2407 if (atomic_dec_return(&pending_close_count) == 0)
2408 wake_up(&subsystem_restart_wait);
2409
2410 kfree(xprt_work);
2411}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002412
2413void msm_ipc_router_xprt_notify(struct msm_ipc_router_xprt *xprt,
2414 unsigned event,
2415 void *data)
2416{
2417 struct msm_ipc_router_xprt_info *xprt_info = xprt->priv;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002418 struct msm_ipc_router_xprt_work *xprt_work;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002419 struct rr_packet *pkt;
Karthikeyan Ramasubramanian4af9f7c2011-09-30 15:55:18 -06002420 unsigned long ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002421
Karthikeyan Ramasubramanian4af9f7c2011-09-30 15:55:18 -06002422 if (!msm_ipc_router_workqueue) {
2423 ret = wait_for_completion_timeout(&msm_ipc_local_router_up,
2424 IPC_ROUTER_INIT_TIMEOUT);
2425 if (!ret || !msm_ipc_router_workqueue) {
2426 pr_err("%s: IPC Router not initialized\n", __func__);
2427 return;
2428 }
2429 }
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002430
2431 switch (event) {
2432 case IPC_ROUTER_XPRT_EVENT_OPEN:
2433 D("open event for '%s'\n", xprt->name);
2434 xprt_work = kmalloc(sizeof(struct msm_ipc_router_xprt_work),
2435 GFP_ATOMIC);
2436 xprt_work->xprt = xprt;
2437 INIT_WORK(&xprt_work->work, xprt_open_worker);
2438 queue_work(msm_ipc_router_workqueue, &xprt_work->work);
2439 break;
2440
2441 case IPC_ROUTER_XPRT_EVENT_CLOSE:
2442 D("close event for '%s'\n", xprt->name);
2443 atomic_inc(&pending_close_count);
2444 xprt_work = kmalloc(sizeof(struct msm_ipc_router_xprt_work),
2445 GFP_ATOMIC);
2446 xprt_work->xprt = xprt;
2447 INIT_WORK(&xprt_work->work, xprt_close_worker);
2448 queue_work(msm_ipc_router_workqueue, &xprt_work->work);
2449 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002450 }
2451
2452 if (!data)
2453 return;
2454
2455 while (!xprt_info) {
2456 msleep(100);
2457 xprt_info = xprt->priv;
2458 }
2459
2460 pkt = clone_pkt((struct rr_packet *)data);
2461 if (!pkt)
2462 return;
2463
2464 mutex_lock(&xprt_info->rx_lock);
2465 list_add_tail(&pkt->list, &xprt_info->pkt_list);
2466 wake_lock(&xprt_info->wakelock);
2467 wake_up(&xprt_info->read_wait);
2468 mutex_unlock(&xprt_info->rx_lock);
2469}
2470
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002471static int modem_restart_notifier_cb(struct notifier_block *this,
2472 unsigned long code,
2473 void *data);
2474static struct notifier_block msm_ipc_router_nb = {
2475 .notifier_call = modem_restart_notifier_cb,
2476};
2477
2478static int modem_restart_notifier_cb(struct notifier_block *this,
2479 unsigned long code,
2480 void *data)
2481{
2482 switch (code) {
2483 case SUBSYS_BEFORE_SHUTDOWN:
2484 D("%s: SUBSYS_BEFORE_SHUTDOWN\n", __func__);
2485 break;
2486
2487 case SUBSYS_BEFORE_POWERUP:
2488 D("%s: waiting for RPC restart to complete\n", __func__);
2489 wait_event(subsystem_restart_wait,
2490 atomic_read(&pending_close_count) == 0);
2491 D("%s: finished restart wait\n", __func__);
2492 break;
2493
2494 default:
2495 break;
2496 }
2497
2498 return NOTIFY_DONE;
2499}
2500
2501static void *restart_notifier_handle;
2502static __init int msm_ipc_router_modem_restart_late_init(void)
2503{
2504 restart_notifier_handle = subsys_notif_register_notifier("modem",
2505 &msm_ipc_router_nb);
2506 return 0;
2507}
2508late_initcall(msm_ipc_router_modem_restart_late_init);
2509
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002510static int __init msm_ipc_router_init(void)
2511{
2512 int i, ret;
2513 struct msm_ipc_routing_table_entry *rt_entry;
2514
2515 msm_ipc_router_debug_mask |= SMEM_LOG;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002516 msm_ipc_router_workqueue =
2517 create_singlethread_workqueue("msm_ipc_router");
2518 if (!msm_ipc_router_workqueue)
2519 return -ENOMEM;
2520
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002521 debugfs_init();
2522
2523 for (i = 0; i < SRV_HASH_SIZE; i++)
2524 INIT_LIST_HEAD(&server_list[i]);
2525
2526 for (i = 0; i < LP_HASH_SIZE; i++)
2527 INIT_LIST_HEAD(&local_ports[i]);
2528
2529 mutex_lock(&routing_table_lock);
2530 if (!routing_table_inited) {
2531 init_routing_table();
2532 rt_entry = alloc_routing_table_entry(IPC_ROUTER_NID_LOCAL);
2533 add_routing_table_entry(rt_entry);
2534 routing_table_inited = 1;
2535 }
2536 mutex_unlock(&routing_table_lock);
2537
2538 init_waitqueue_head(&newserver_wait);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002539 init_waitqueue_head(&subsystem_restart_wait);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002540 ret = msm_ipc_router_init_sockets();
2541 if (ret < 0)
2542 pr_err("%s: Init sockets failed\n", __func__);
2543
Karthikeyan Ramasubramanian4af9f7c2011-09-30 15:55:18 -06002544 complete_all(&msm_ipc_local_router_up);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002545 return ret;
2546}
2547
2548module_init(msm_ipc_router_init);
2549MODULE_DESCRIPTION("MSM IPC Router");
2550MODULE_LICENSE("GPL v2");