blob: c0bff63a3f53205b7b4db9dc28ab3ce3ebdc2fb9 [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
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -0600475/*
476 * Should be called with local_ports_lock locked
477 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700478static struct msm_ipc_port *msm_ipc_router_lookup_local_port(uint32_t port_id)
479{
480 int key = (port_id & (LP_HASH_SIZE - 1));
481 struct msm_ipc_port *port_ptr;
482
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700483 list_for_each_entry(port_ptr, &local_ports[key], list) {
484 if (port_ptr->this_port.port_id == port_id) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700485 return port_ptr;
486 }
487 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700488 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
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06001435 rport_ptr = msm_ipc_router_lookup_remote_port(hdr->src_node_id,
1436 hdr->src_port_id);
1437
1438 mutex_lock(&local_ports_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001439 port_ptr = msm_ipc_router_lookup_local_port(hdr->dst_port_id);
1440 if (!port_ptr) {
1441 pr_err("%s: No local port id %08x\n", __func__,
1442 hdr->dst_port_id);
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06001443 mutex_unlock(&local_ports_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001444 release_pkt(pkt);
1445 goto process_done;
1446 }
1447
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001448 if (!rport_ptr) {
1449 rport_ptr = msm_ipc_router_create_remote_port(
1450 hdr->src_node_id,
1451 hdr->src_port_id);
1452 if (!rport_ptr) {
1453 pr_err("%s: Remote port %08x:%08x creation failed\n",
1454 __func__, hdr->src_node_id, hdr->src_port_id);
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06001455 mutex_unlock(&local_ports_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001456 goto process_done;
1457 }
1458 }
1459
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001460 if (!port_ptr->notify) {
1461 mutex_lock(&port_ptr->port_rx_q_lock);
1462 wake_lock(&port_ptr->port_rx_wake_lock);
1463 list_add_tail(&pkt->list, &port_ptr->port_rx_q);
1464 wake_up(&port_ptr->port_rx_wait_q);
1465 mutex_unlock(&port_ptr->port_rx_q_lock);
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06001466 mutex_unlock(&local_ports_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001467 } else {
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06001468 mutex_lock(&port_ptr->port_rx_q_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001469 src_addr = kmalloc(sizeof(struct msm_ipc_port_addr),
1470 GFP_KERNEL);
1471 if (src_addr) {
1472 src_addr->node_id = hdr->src_node_id;
1473 src_addr->port_id = hdr->src_port_id;
1474 }
1475 skb_pull(head_skb, IPC_ROUTER_HDR_SIZE);
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06001476 mutex_unlock(&local_ports_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001477 port_ptr->notify(MSM_IPC_ROUTER_READ_CB, pkt->pkt_fragment_q,
1478 src_addr, port_ptr->priv);
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06001479 mutex_unlock(&port_ptr->port_rx_q_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001480 pkt->pkt_fragment_q = NULL;
1481 src_addr = NULL;
1482 release_pkt(pkt);
1483 }
1484
1485process_done:
1486 if (resume_tx) {
1487 union rr_control_msg msg;
1488
1489 msg.cmd = IPC_ROUTER_CTRL_CMD_RESUME_TX;
1490 msg.cli.node_id = resume_tx_node_id;
1491 msg.cli.port_id = resume_tx_port_id;
1492
1493 RR("x RESUME_TX id=%d:%08x\n",
1494 msg.cli.node_id, msg.cli.port_id);
1495 msm_ipc_router_send_control_msg(xprt_info, &msg);
1496 }
1497
1498done:
1499 queue_work(xprt_info->workqueue, &xprt_info->read_data);
1500 return;
1501
1502fail_data:
1503 release_pkt(pkt);
1504fail_io:
1505 pr_err("ipc_router has died\n");
1506}
1507
1508int msm_ipc_router_register_server(struct msm_ipc_port *port_ptr,
1509 struct msm_ipc_addr *name)
1510{
1511 struct msm_ipc_server *server;
1512 unsigned long flags;
1513 union rr_control_msg ctl;
1514
1515 if (!port_ptr || !name)
1516 return -EINVAL;
1517
1518 if (name->addrtype != MSM_IPC_ADDR_NAME)
1519 return -EINVAL;
1520
1521 server = msm_ipc_router_lookup_server(name->addr.port_name.service,
1522 name->addr.port_name.instance,
1523 IPC_ROUTER_NID_LOCAL,
1524 port_ptr->this_port.port_id);
1525 if (server) {
1526 pr_err("%s: Server already present\n", __func__);
1527 return -EINVAL;
1528 }
1529
1530 server = msm_ipc_router_create_server(name->addr.port_name.service,
1531 name->addr.port_name.instance,
1532 IPC_ROUTER_NID_LOCAL,
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001533 port_ptr->this_port.port_id,
1534 NULL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001535 if (!server) {
1536 pr_err("%s: Server Creation failed\n", __func__);
1537 return -EINVAL;
1538 }
1539
1540 ctl.cmd = IPC_ROUTER_CTRL_CMD_NEW_SERVER;
1541 ctl.srv.service = server->name.service;
1542 ctl.srv.instance = server->name.instance;
1543 ctl.srv.node_id = IPC_ROUTER_NID_LOCAL;
1544 ctl.srv.port_id = port_ptr->this_port.port_id;
1545 broadcast_ctl_msg(&ctl);
1546 spin_lock_irqsave(&port_ptr->port_lock, flags);
1547 port_ptr->type = SERVER_PORT;
1548 port_ptr->port_name.service = server->name.service;
1549 port_ptr->port_name.instance = server->name.instance;
1550 spin_unlock_irqrestore(&port_ptr->port_lock, flags);
1551 return 0;
1552}
1553
1554int msm_ipc_router_unregister_server(struct msm_ipc_port *port_ptr)
1555{
1556 struct msm_ipc_server *server;
1557 unsigned long flags;
1558 union rr_control_msg ctl;
1559
1560 if (!port_ptr)
1561 return -EINVAL;
1562
1563 if (port_ptr->type != SERVER_PORT) {
1564 pr_err("%s: Trying to unregister a non-server port\n",
1565 __func__);
1566 return -EINVAL;
1567 }
1568
1569 if (port_ptr->this_port.node_id != IPC_ROUTER_NID_LOCAL) {
1570 pr_err("%s: Trying to unregister a remote server locally\n",
1571 __func__);
1572 return -EINVAL;
1573 }
1574
1575 server = msm_ipc_router_lookup_server(port_ptr->port_name.service,
1576 port_ptr->port_name.instance,
1577 port_ptr->this_port.node_id,
1578 port_ptr->this_port.port_id);
1579 if (!server) {
1580 pr_err("%s: Server lookup failed\n", __func__);
1581 return -ENODEV;
1582 }
1583
1584 ctl.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_SERVER;
1585 ctl.srv.service = server->name.service;
1586 ctl.srv.instance = server->name.instance;
1587 ctl.srv.node_id = IPC_ROUTER_NID_LOCAL;
1588 ctl.srv.port_id = port_ptr->this_port.port_id;
1589 broadcast_ctl_msg(&ctl);
1590 msm_ipc_router_destroy_server(server, port_ptr->this_port.node_id,
1591 port_ptr->this_port.port_id);
1592 spin_lock_irqsave(&port_ptr->port_lock, flags);
1593 port_ptr->type = CLIENT_PORT;
1594 spin_unlock_irqrestore(&port_ptr->port_lock, flags);
1595 return 0;
1596}
1597
1598static int loopback_data(struct msm_ipc_port *src,
1599 uint32_t port_id,
1600 struct sk_buff_head *data)
1601{
1602 struct sk_buff *head_skb;
1603 struct rr_header *hdr;
1604 struct msm_ipc_port *port_ptr;
1605 struct rr_packet *pkt;
1606
1607 if (!data) {
1608 pr_err("%s: Invalid pkt pointer\n", __func__);
1609 return -EINVAL;
1610 }
1611
1612 pkt = create_pkt(data);
1613 if (!pkt) {
1614 pr_err("%s: New pkt create failed\n", __func__);
1615 return -ENOMEM;
1616 }
1617
1618 head_skb = skb_peek(pkt->pkt_fragment_q);
Karthikeyan Ramasubramanian9024dd82011-12-19 18:44:19 -07001619 if (!head_skb) {
1620 pr_err("%s: pkt_fragment_q is empty\n", __func__);
1621 return -EINVAL;
1622 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001623 hdr = (struct rr_header *)skb_push(head_skb, IPC_ROUTER_HDR_SIZE);
1624 if (!hdr) {
1625 pr_err("%s: Prepend Header failed\n", __func__);
1626 release_pkt(pkt);
1627 return -ENOMEM;
1628 }
1629 hdr->version = IPC_ROUTER_VERSION;
1630 hdr->type = IPC_ROUTER_CTRL_CMD_DATA;
1631 hdr->src_node_id = src->this_port.node_id;
1632 hdr->src_port_id = src->this_port.port_id;
1633 hdr->size = pkt->length;
1634 hdr->confirm_rx = 0;
1635 hdr->dst_node_id = IPC_ROUTER_NID_LOCAL;
1636 hdr->dst_port_id = port_id;
1637 pkt->length += IPC_ROUTER_HDR_SIZE;
1638
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06001639 mutex_lock(&local_ports_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001640 port_ptr = msm_ipc_router_lookup_local_port(port_id);
1641 if (!port_ptr) {
1642 pr_err("%s: Local port %d not present\n", __func__, port_id);
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06001643 mutex_unlock(&local_ports_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001644 release_pkt(pkt);
1645 return -ENODEV;
1646 }
1647
1648 mutex_lock(&port_ptr->port_rx_q_lock);
1649 wake_lock(&port_ptr->port_rx_wake_lock);
1650 list_add_tail(&pkt->list, &port_ptr->port_rx_q);
1651 wake_up(&port_ptr->port_rx_wait_q);
1652 mutex_unlock(&port_ptr->port_rx_q_lock);
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06001653 mutex_unlock(&local_ports_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001654
1655 return pkt->length;
1656}
1657
1658static int msm_ipc_router_write_pkt(struct msm_ipc_port *src,
1659 struct msm_ipc_router_remote_port *rport_ptr,
1660 struct rr_packet *pkt)
1661{
1662 struct sk_buff *head_skb;
1663 struct rr_header *hdr;
1664 struct msm_ipc_router_xprt_info *xprt_info;
1665 struct msm_ipc_routing_table_entry *rt_entry;
1666 int ret;
1667 DEFINE_WAIT(__wait);
1668
1669 if (!rport_ptr || !src || !pkt)
1670 return -EINVAL;
1671
1672 head_skb = skb_peek(pkt->pkt_fragment_q);
Karthikeyan Ramasubramanian9024dd82011-12-19 18:44:19 -07001673 if (!head_skb) {
1674 pr_err("%s: pkt_fragment_q is empty\n", __func__);
1675 return -EINVAL;
1676 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001677 hdr = (struct rr_header *)skb_push(head_skb, IPC_ROUTER_HDR_SIZE);
1678 if (!hdr) {
1679 pr_err("%s: Prepend Header failed\n", __func__);
1680 return -ENOMEM;
1681 }
1682 hdr->version = IPC_ROUTER_VERSION;
1683 hdr->type = IPC_ROUTER_CTRL_CMD_DATA;
1684 hdr->src_node_id = src->this_port.node_id;
1685 hdr->src_port_id = src->this_port.port_id;
1686 hdr->size = pkt->length;
1687 hdr->confirm_rx = 0;
1688 hdr->dst_node_id = rport_ptr->node_id;
1689 hdr->dst_port_id = rport_ptr->port_id;
1690 pkt->length += IPC_ROUTER_HDR_SIZE;
1691
1692 for (;;) {
1693 prepare_to_wait(&rport_ptr->quota_wait, &__wait,
1694 TASK_INTERRUPTIBLE);
1695 mutex_lock(&rport_ptr->quota_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001696 if (rport_ptr->restart_state != RESTART_NORMAL)
1697 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001698 if (rport_ptr->tx_quota_cnt <
1699 IPC_ROUTER_DEFAULT_RX_QUOTA)
1700 break;
1701 if (signal_pending(current))
1702 break;
1703 mutex_unlock(&rport_ptr->quota_lock);
1704 schedule();
1705 }
1706 finish_wait(&rport_ptr->quota_wait, &__wait);
1707
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001708 if (rport_ptr->restart_state != RESTART_NORMAL) {
1709 mutex_unlock(&rport_ptr->quota_lock);
1710 return -ENETRESET;
1711 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001712 if (signal_pending(current)) {
1713 mutex_unlock(&rport_ptr->quota_lock);
1714 return -ERESTARTSYS;
1715 }
1716 rport_ptr->tx_quota_cnt++;
1717 if (rport_ptr->tx_quota_cnt == IPC_ROUTER_DEFAULT_RX_QUOTA)
1718 hdr->confirm_rx = 1;
1719 mutex_unlock(&rport_ptr->quota_lock);
1720
1721 mutex_lock(&routing_table_lock);
1722 rt_entry = lookup_routing_table(hdr->dst_node_id);
1723 if (!rt_entry || !rt_entry->xprt_info) {
1724 mutex_unlock(&routing_table_lock);
1725 pr_err("%s: Remote node %d not up\n",
1726 __func__, hdr->dst_node_id);
1727 return -ENODEV;
1728 }
1729 mutex_lock(&rt_entry->lock);
1730 xprt_info = rt_entry->xprt_info;
1731 mutex_lock(&xprt_info->tx_lock);
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -07001732 ret = xprt_info->xprt->write(pkt, pkt->length, xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001733 mutex_unlock(&xprt_info->tx_lock);
1734 mutex_unlock(&rt_entry->lock);
1735 mutex_unlock(&routing_table_lock);
1736
1737 if (ret < 0) {
1738 pr_err("%s: Write on XPRT failed\n", __func__);
1739 return ret;
1740 }
1741
1742 RAW_HDR("[w rr_h] "
1743 "ver=%i,type=%s,src_nid=%08x,src_port_id=%08x,"
1744 "confirm_rx=%i,size=%3i,dst_pid=%08x,dst_cid=%08x\n",
1745 hdr->version, type_to_str(hdr->type),
1746 hdr->src_node_id, hdr->src_port_id,
1747 hdr->confirm_rx, hdr->size,
1748 hdr->dst_node_id, hdr->dst_port_id);
1749
1750#if defined(CONFIG_MSM_SMD_LOGGING)
1751#if defined(DEBUG)
1752 if (msm_ipc_router_debug_mask & SMEM_LOG) {
1753 smem_log_event((SMEM_LOG_PROC_ID_APPS |
1754 SMEM_LOG_RPC_ROUTER_EVENT_BASE |
1755 IPC_ROUTER_LOG_EVENT_TX),
1756 (hdr->src_node_id << 24) |
1757 (hdr->src_port_id & 0xffffff),
1758 (hdr->dst_node_id << 24) |
1759 (hdr->dst_port_id & 0xffffff),
1760 (hdr->type << 24) | (hdr->confirm_rx << 16) |
1761 (hdr->size & 0xffff));
1762 }
1763#endif
1764#endif
1765
1766 return pkt->length;
1767}
1768
1769int msm_ipc_router_send_to(struct msm_ipc_port *src,
1770 struct sk_buff_head *data,
1771 struct msm_ipc_addr *dest)
1772{
1773 uint32_t dst_node_id = 0, dst_port_id = 0;
1774 struct msm_ipc_server *server;
1775 struct msm_ipc_server_port *server_port;
1776 struct msm_ipc_router_remote_port *rport_ptr = NULL;
1777 struct rr_packet *pkt;
1778 int ret;
1779
1780 if (!src || !data || !dest) {
1781 pr_err("%s: Invalid Parameters\n", __func__);
1782 return -EINVAL;
1783 }
1784
1785 /* Resolve Address*/
1786 if (dest->addrtype == MSM_IPC_ADDR_ID) {
1787 dst_node_id = dest->addr.port_addr.node_id;
1788 dst_port_id = dest->addr.port_addr.port_id;
1789 } else if (dest->addrtype == MSM_IPC_ADDR_NAME) {
1790 server = msm_ipc_router_lookup_server(
1791 dest->addr.port_name.service,
1792 dest->addr.port_name.instance,
1793 0, 0);
1794 if (!server) {
1795 pr_err("%s: Destination not reachable\n", __func__);
1796 return -ENODEV;
1797 }
1798 mutex_lock(&server_list_lock);
1799 server_port = list_first_entry(&server->server_port_list,
1800 struct msm_ipc_server_port,
1801 list);
1802 dst_node_id = server_port->server_addr.node_id;
1803 dst_port_id = server_port->server_addr.port_id;
1804 mutex_unlock(&server_list_lock);
1805 }
1806 if (dst_node_id == IPC_ROUTER_NID_LOCAL) {
1807 ret = loopback_data(src, dst_port_id, data);
1808 return ret;
1809 }
1810
1811 /* Achieve Flow control */
1812 rport_ptr = msm_ipc_router_lookup_remote_port(dst_node_id,
1813 dst_port_id);
1814 if (!rport_ptr) {
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001815 pr_err("%s: Could not create remote port\n", __func__);
1816 return -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001817 }
1818
1819 pkt = create_pkt(data);
1820 if (!pkt) {
1821 pr_err("%s: Pkt creation failed\n", __func__);
1822 return -ENOMEM;
1823 }
1824
1825 ret = msm_ipc_router_write_pkt(src, rport_ptr, pkt);
1826 release_pkt(pkt);
1827
1828 return ret;
1829}
1830
1831int msm_ipc_router_read(struct msm_ipc_port *port_ptr,
1832 struct sk_buff_head **data,
1833 size_t buf_len)
1834{
1835 struct rr_packet *pkt;
1836 int ret;
1837
1838 if (!port_ptr || !data)
1839 return -EINVAL;
1840
1841 mutex_lock(&port_ptr->port_rx_q_lock);
1842 if (list_empty(&port_ptr->port_rx_q)) {
1843 mutex_unlock(&port_ptr->port_rx_q_lock);
1844 return -EAGAIN;
1845 }
1846
1847 pkt = list_first_entry(&port_ptr->port_rx_q, struct rr_packet, list);
1848 if ((buf_len) && ((pkt->length - IPC_ROUTER_HDR_SIZE) > buf_len)) {
1849 mutex_unlock(&port_ptr->port_rx_q_lock);
1850 return -ETOOSMALL;
1851 }
1852 list_del(&pkt->list);
1853 if (list_empty(&port_ptr->port_rx_q))
1854 wake_unlock(&port_ptr->port_rx_wake_lock);
1855 *data = pkt->pkt_fragment_q;
1856 ret = pkt->length;
1857 kfree(pkt);
1858 mutex_unlock(&port_ptr->port_rx_q_lock);
1859
1860 return ret;
1861}
1862
1863int msm_ipc_router_recv_from(struct msm_ipc_port *port_ptr,
1864 struct sk_buff_head **data,
1865 struct msm_ipc_addr *src,
1866 unsigned long timeout)
1867{
1868 int ret, data_len, align_size;
1869 struct sk_buff *temp_skb;
1870 struct rr_header *hdr = NULL;
1871
1872 if (!port_ptr || !data) {
1873 pr_err("%s: Invalid pointers being passed\n", __func__);
1874 return -EINVAL;
1875 }
1876
1877 *data = NULL;
1878 mutex_lock(&port_ptr->port_rx_q_lock);
1879 while (list_empty(&port_ptr->port_rx_q)) {
1880 mutex_unlock(&port_ptr->port_rx_q_lock);
1881 if (timeout < 0) {
1882 ret = wait_event_interruptible(
1883 port_ptr->port_rx_wait_q,
1884 !list_empty(&port_ptr->port_rx_q));
1885 if (ret)
1886 return ret;
1887 } else if (timeout > 0) {
1888 timeout = wait_event_interruptible_timeout(
1889 port_ptr->port_rx_wait_q,
1890 !list_empty(&port_ptr->port_rx_q),
1891 timeout);
1892 if (timeout < 0)
1893 return -EFAULT;
1894 }
1895 if (timeout == 0)
1896 return -ETIMEDOUT;
1897 mutex_lock(&port_ptr->port_rx_q_lock);
1898 }
1899 mutex_unlock(&port_ptr->port_rx_q_lock);
1900
1901 ret = msm_ipc_router_read(port_ptr, data, 0);
1902 if (ret <= 0 || !(*data))
1903 return ret;
1904
1905 temp_skb = skb_peek(*data);
1906 hdr = (struct rr_header *)(temp_skb->data);
1907 if (src) {
1908 src->addrtype = MSM_IPC_ADDR_ID;
1909 src->addr.port_addr.node_id = hdr->src_node_id;
1910 src->addr.port_addr.port_id = hdr->src_port_id;
1911 }
1912
1913 data_len = hdr->size;
1914 skb_pull(temp_skb, IPC_ROUTER_HDR_SIZE);
1915 align_size = ALIGN_SIZE(data_len);
1916 if (align_size) {
1917 temp_skb = skb_peek_tail(*data);
1918 skb_trim(temp_skb, (temp_skb->len - align_size));
1919 }
1920 return data_len;
1921}
1922
1923struct msm_ipc_port *msm_ipc_router_create_port(
1924 void (*notify)(unsigned event, void *data, void *addr, void *priv),
1925 void *priv)
1926{
1927 struct msm_ipc_port *port_ptr;
1928
1929 port_ptr = msm_ipc_router_create_raw_port(NULL, notify, priv);
1930 if (!port_ptr)
1931 pr_err("%s: port_ptr alloc failed\n", __func__);
1932
1933 return port_ptr;
1934}
1935
1936int msm_ipc_router_close_port(struct msm_ipc_port *port_ptr)
1937{
1938 union rr_control_msg msg;
1939 struct rr_packet *pkt, *temp_pkt;
1940 struct msm_ipc_server *server;
1941
1942 if (!port_ptr)
1943 return -EINVAL;
1944
1945 if (port_ptr->type == SERVER_PORT || port_ptr->type == CLIENT_PORT) {
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06001946 mutex_lock(&local_ports_lock);
1947 list_del(&port_ptr->list);
1948 mutex_unlock(&local_ports_lock);
1949
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001950 if (port_ptr->type == SERVER_PORT) {
1951 msg.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_SERVER;
1952 msg.srv.service = port_ptr->port_name.service;
1953 msg.srv.instance = port_ptr->port_name.instance;
1954 msg.srv.node_id = port_ptr->this_port.node_id;
1955 msg.srv.port_id = port_ptr->this_port.port_id;
1956 RR("x REMOVE_SERVER Name=%d:%08x Id=%d:%08x\n",
1957 msg.srv.service, msg.srv.instance,
1958 msg.srv.node_id, msg.srv.port_id);
1959 } else if (port_ptr->type == CLIENT_PORT) {
1960 msg.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT;
1961 msg.cli.node_id = port_ptr->this_port.node_id;
1962 msg.cli.port_id = port_ptr->this_port.port_id;
1963 RR("x REMOVE_CLIENT id=%d:%08x\n",
1964 msg.cli.node_id, msg.cli.port_id);
1965 }
1966 broadcast_ctl_msg(&msg);
1967 broadcast_ctl_msg_locally(&msg);
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06001968 } else if (port_ptr->type == CONTROL_PORT) {
1969 mutex_lock(&control_ports_lock);
1970 list_del(&port_ptr->list);
1971 mutex_unlock(&control_ports_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001972 }
1973
1974 mutex_lock(&port_ptr->port_rx_q_lock);
1975 list_for_each_entry_safe(pkt, temp_pkt, &port_ptr->port_rx_q, list) {
1976 list_del(&pkt->list);
1977 release_pkt(pkt);
1978 }
1979 mutex_unlock(&port_ptr->port_rx_q_lock);
1980
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001981 if (port_ptr->type == SERVER_PORT) {
1982 server = msm_ipc_router_lookup_server(
1983 port_ptr->port_name.service,
1984 port_ptr->port_name.instance,
1985 port_ptr->this_port.node_id,
1986 port_ptr->this_port.port_id);
1987 if (server)
1988 msm_ipc_router_destroy_server(server,
1989 port_ptr->this_port.node_id,
1990 port_ptr->this_port.port_id);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001991 }
1992
Karthikeyan Ramasubramaniandd8c3b52011-11-30 16:26:12 -07001993 wake_lock_destroy(&port_ptr->port_rx_wake_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001994 kfree(port_ptr);
1995 return 0;
1996}
1997
1998int msm_ipc_router_get_curr_pkt_size(struct msm_ipc_port *port_ptr)
1999{
2000 struct rr_packet *pkt;
2001 int rc = 0;
2002
2003 if (!port_ptr)
2004 return -EINVAL;
2005
2006 mutex_lock(&port_ptr->port_rx_q_lock);
2007 if (!list_empty(&port_ptr->port_rx_q)) {
2008 pkt = list_first_entry(&port_ptr->port_rx_q,
2009 struct rr_packet, list);
2010 rc = pkt->length;
2011 }
2012 mutex_unlock(&port_ptr->port_rx_q_lock);
2013
2014 return rc;
2015}
2016
2017int msm_ipc_router_bind_control_port(struct msm_ipc_port *port_ptr)
2018{
2019 if (!port_ptr)
2020 return -EINVAL;
2021
2022 mutex_lock(&local_ports_lock);
2023 list_del(&port_ptr->list);
2024 mutex_unlock(&local_ports_lock);
2025 port_ptr->type = CONTROL_PORT;
2026 mutex_lock(&control_ports_lock);
2027 list_add_tail(&port_ptr->list, &control_ports);
2028 mutex_unlock(&control_ports_lock);
2029
2030 return 0;
2031}
2032
2033int msm_ipc_router_lookup_server_name(struct msm_ipc_port_name *srv_name,
Karthikeyan Ramasubramaniandfde01b2012-06-12 14:25:13 -06002034 struct msm_ipc_server_info *srv_info,
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002035 int num_entries_in_array,
2036 uint32_t lookup_mask)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002037{
2038 struct msm_ipc_server *server;
2039 struct msm_ipc_server_port *server_port;
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002040 int key, i = 0; /*num_entries_found*/
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002041
2042 if (!srv_name) {
2043 pr_err("%s: Invalid srv_name\n", __func__);
2044 return -EINVAL;
2045 }
2046
Karthikeyan Ramasubramaniandfde01b2012-06-12 14:25:13 -06002047 if (num_entries_in_array && !srv_info) {
2048 pr_err("%s: srv_info NULL\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002049 return -EINVAL;
2050 }
2051
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002052 mutex_lock(&server_list_lock);
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002053 if (!lookup_mask)
2054 lookup_mask = 0xFFFFFFFF;
2055 for (key = 0; key < SRV_HASH_SIZE; key++) {
2056 list_for_each_entry(server, &server_list[key], list) {
2057 if ((server->name.service != srv_name->service) ||
2058 ((server->name.instance & lookup_mask) !=
2059 srv_name->instance))
2060 continue;
2061
2062 list_for_each_entry(server_port,
2063 &server->server_port_list, list) {
2064 if (i < num_entries_in_array) {
Karthikeyan Ramasubramaniandfde01b2012-06-12 14:25:13 -06002065 srv_info[i].node_id =
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002066 server_port->server_addr.node_id;
Karthikeyan Ramasubramaniandfde01b2012-06-12 14:25:13 -06002067 srv_info[i].port_id =
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002068 server_port->server_addr.port_id;
Karthikeyan Ramasubramaniandfde01b2012-06-12 14:25:13 -06002069 srv_info[i].service =
2070 server->name.service;
2071 srv_info[i].instance =
2072 server->name.instance;
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002073 }
2074 i++;
2075 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002076 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002077 }
2078 mutex_unlock(&server_list_lock);
2079
2080 return i;
2081}
2082
2083int msm_ipc_router_close(void)
2084{
2085 struct msm_ipc_router_xprt_info *xprt_info, *tmp_xprt_info;
2086
2087 mutex_lock(&xprt_info_list_lock);
2088 list_for_each_entry_safe(xprt_info, tmp_xprt_info,
2089 &xprt_info_list, list) {
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -07002090 xprt_info->xprt->close(xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002091 list_del(&xprt_info->list);
2092 kfree(xprt_info);
2093 }
2094 mutex_unlock(&xprt_info_list_lock);
2095 return 0;
2096}
2097
2098#if defined(CONFIG_DEBUG_FS)
2099static int dump_routing_table(char *buf, int max)
2100{
2101 int i = 0, j;
2102 struct msm_ipc_routing_table_entry *rt_entry;
2103
2104 for (j = 0; j < RT_HASH_SIZE; j++) {
2105 mutex_lock(&routing_table_lock);
2106 list_for_each_entry(rt_entry, &routing_table[j], list) {
2107 mutex_lock(&rt_entry->lock);
2108 i += scnprintf(buf + i, max - i,
2109 "Node Id: 0x%08x\n", rt_entry->node_id);
2110 if (j == IPC_ROUTER_NID_LOCAL) {
2111 i += scnprintf(buf + i, max - i,
2112 "XPRT Name: Loopback\n");
2113 i += scnprintf(buf + i, max - i,
2114 "Next Hop: %d\n", rt_entry->node_id);
2115 } else {
2116 i += scnprintf(buf + i, max - i,
2117 "XPRT Name: %s\n",
2118 rt_entry->xprt_info->xprt->name);
2119 i += scnprintf(buf + i, max - i,
2120 "Next Hop: 0x%08x\n",
2121 rt_entry->xprt_info->remote_node_id);
2122 }
2123 i += scnprintf(buf + i, max - i, "\n");
2124 mutex_unlock(&rt_entry->lock);
2125 }
2126 mutex_unlock(&routing_table_lock);
2127 }
2128
2129 return i;
2130}
2131
2132static int dump_xprt_info(char *buf, int max)
2133{
2134 int i = 0;
2135 struct msm_ipc_router_xprt_info *xprt_info;
2136
2137 mutex_lock(&xprt_info_list_lock);
2138 list_for_each_entry(xprt_info, &xprt_info_list, list) {
2139 i += scnprintf(buf + i, max - i, "XPRT Name: %s\n",
2140 xprt_info->xprt->name);
2141 i += scnprintf(buf + i, max - i, "Link Id: %d\n",
2142 xprt_info->xprt->link_id);
2143 i += scnprintf(buf + i, max - i, "Initialized: %s\n",
2144 (xprt_info->initialized ? "Y" : "N"));
2145 i += scnprintf(buf + i, max - i, "Remote Node Id: 0x%08x\n",
2146 xprt_info->remote_node_id);
2147 i += scnprintf(buf + i, max - i, "\n");
2148 }
2149 mutex_unlock(&xprt_info_list_lock);
2150
2151 return i;
2152}
2153
2154static int dump_servers(char *buf, int max)
2155{
2156 int i = 0, j;
2157 struct msm_ipc_server *server;
2158 struct msm_ipc_server_port *server_port;
2159
2160 mutex_lock(&server_list_lock);
2161 for (j = 0; j < SRV_HASH_SIZE; j++) {
2162 list_for_each_entry(server, &server_list[j], list) {
2163 list_for_each_entry(server_port,
2164 &server->server_port_list,
2165 list) {
2166 i += scnprintf(buf + i, max - i, "Service: "
2167 "0x%08x\n", server->name.service);
2168 i += scnprintf(buf + i, max - i, "Instance: "
2169 "0x%08x\n", server->name.instance);
2170 i += scnprintf(buf + i, max - i,
2171 "Node_id: 0x%08x\n",
2172 server_port->server_addr.node_id);
2173 i += scnprintf(buf + i, max - i,
2174 "Port_id: 0x%08x\n",
2175 server_port->server_addr.port_id);
2176 i += scnprintf(buf + i, max - i, "\n");
2177 }
2178 }
2179 }
2180 mutex_unlock(&server_list_lock);
2181
2182 return i;
2183}
2184
2185static int dump_remote_ports(char *buf, int max)
2186{
2187 int i = 0, j, k;
2188 struct msm_ipc_router_remote_port *rport_ptr;
2189 struct msm_ipc_routing_table_entry *rt_entry;
2190
2191 for (j = 0; j < RT_HASH_SIZE; j++) {
2192 mutex_lock(&routing_table_lock);
2193 list_for_each_entry(rt_entry, &routing_table[j], list) {
2194 mutex_lock(&rt_entry->lock);
2195 for (k = 0; k < RP_HASH_SIZE; k++) {
2196 list_for_each_entry(rport_ptr,
2197 &rt_entry->remote_port_list[k],
2198 list) {
2199 i += scnprintf(buf + i, max - i,
2200 "Node_id: 0x%08x\n",
2201 rport_ptr->node_id);
2202 i += scnprintf(buf + i, max - i,
2203 "Port_id: 0x%08x\n",
2204 rport_ptr->port_id);
2205 i += scnprintf(buf + i, max - i,
2206 "Quota_cnt: %d\n",
2207 rport_ptr->tx_quota_cnt);
2208 i += scnprintf(buf + i, max - i, "\n");
2209 }
2210 }
2211 mutex_unlock(&rt_entry->lock);
2212 }
2213 mutex_unlock(&routing_table_lock);
2214 }
2215
2216 return i;
2217}
2218
2219static int dump_control_ports(char *buf, int max)
2220{
2221 int i = 0;
2222 struct msm_ipc_port *port_ptr;
2223
2224 mutex_lock(&control_ports_lock);
2225 list_for_each_entry(port_ptr, &control_ports, list) {
2226 i += scnprintf(buf + i, max - i, "Node_id: 0x%08x\n",
2227 port_ptr->this_port.node_id);
2228 i += scnprintf(buf + i, max - i, "Port_id: 0x%08x\n",
2229 port_ptr->this_port.port_id);
2230 i += scnprintf(buf + i, max - i, "\n");
2231 }
2232 mutex_unlock(&control_ports_lock);
2233
2234 return i;
2235}
2236
2237static int dump_local_ports(char *buf, int max)
2238{
2239 int i = 0, j;
2240 unsigned long flags;
2241 struct msm_ipc_port *port_ptr;
2242
2243 mutex_lock(&local_ports_lock);
2244 for (j = 0; j < LP_HASH_SIZE; j++) {
2245 list_for_each_entry(port_ptr, &local_ports[j], list) {
2246 spin_lock_irqsave(&port_ptr->port_lock, flags);
2247 i += scnprintf(buf + i, max - i, "Node_id: 0x%08x\n",
2248 port_ptr->this_port.node_id);
2249 i += scnprintf(buf + i, max - i, "Port_id: 0x%08x\n",
2250 port_ptr->this_port.port_id);
2251 i += scnprintf(buf + i, max - i, "# pkts tx'd %d\n",
2252 port_ptr->num_tx);
2253 i += scnprintf(buf + i, max - i, "# pkts rx'd %d\n",
2254 port_ptr->num_rx);
2255 i += scnprintf(buf + i, max - i, "# bytes tx'd %ld\n",
2256 port_ptr->num_tx_bytes);
2257 i += scnprintf(buf + i, max - i, "# bytes rx'd %ld\n",
2258 port_ptr->num_rx_bytes);
2259 spin_unlock_irqrestore(&port_ptr->port_lock, flags);
2260 i += scnprintf(buf + i, max - i, "\n");
2261 }
2262 }
2263 mutex_unlock(&local_ports_lock);
2264
2265 return i;
2266}
2267
2268#define DEBUG_BUFMAX 4096
2269static char debug_buffer[DEBUG_BUFMAX];
2270
2271static ssize_t debug_read(struct file *file, char __user *buf,
2272 size_t count, loff_t *ppos)
2273{
2274 int (*fill)(char *buf, int max) = file->private_data;
2275 int bsize = fill(debug_buffer, DEBUG_BUFMAX);
2276 return simple_read_from_buffer(buf, count, ppos, debug_buffer, bsize);
2277}
2278
2279static int debug_open(struct inode *inode, struct file *file)
2280{
2281 file->private_data = inode->i_private;
2282 return 0;
2283}
2284
2285static const struct file_operations debug_ops = {
2286 .read = debug_read,
2287 .open = debug_open,
2288};
2289
2290static void debug_create(const char *name, mode_t mode,
2291 struct dentry *dent,
2292 int (*fill)(char *buf, int max))
2293{
2294 debugfs_create_file(name, mode, dent, fill, &debug_ops);
2295}
2296
2297static void debugfs_init(void)
2298{
2299 struct dentry *dent;
2300
2301 dent = debugfs_create_dir("msm_ipc_router", 0);
2302 if (IS_ERR(dent))
2303 return;
2304
2305 debug_create("dump_local_ports", 0444, dent,
2306 dump_local_ports);
2307 debug_create("dump_remote_ports", 0444, dent,
2308 dump_remote_ports);
2309 debug_create("dump_control_ports", 0444, dent,
2310 dump_control_ports);
2311 debug_create("dump_servers", 0444, dent,
2312 dump_servers);
2313 debug_create("dump_xprt_info", 0444, dent,
2314 dump_xprt_info);
2315 debug_create("dump_routing_table", 0444, dent,
2316 dump_routing_table);
2317}
2318
2319#else
2320static void debugfs_init(void) {}
2321#endif
2322
2323static int msm_ipc_router_add_xprt(struct msm_ipc_router_xprt *xprt)
2324{
2325 struct msm_ipc_router_xprt_info *xprt_info;
2326 struct msm_ipc_routing_table_entry *rt_entry;
2327
2328 xprt_info = kmalloc(sizeof(struct msm_ipc_router_xprt_info),
2329 GFP_KERNEL);
2330 if (!xprt_info)
2331 return -ENOMEM;
2332
2333 xprt_info->xprt = xprt;
2334 xprt_info->initialized = 0;
2335 xprt_info->remote_node_id = -1;
2336 INIT_LIST_HEAD(&xprt_info->pkt_list);
2337 init_waitqueue_head(&xprt_info->read_wait);
2338 mutex_init(&xprt_info->rx_lock);
2339 mutex_init(&xprt_info->tx_lock);
2340 wake_lock_init(&xprt_info->wakelock,
2341 WAKE_LOCK_SUSPEND, xprt->name);
2342 xprt_info->need_len = 0;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002343 xprt_info->abort_data_read = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002344 INIT_WORK(&xprt_info->read_data, do_read_data);
2345 INIT_LIST_HEAD(&xprt_info->list);
2346
2347 xprt_info->workqueue = create_singlethread_workqueue(xprt->name);
2348 if (!xprt_info->workqueue) {
2349 kfree(xprt_info);
2350 return -ENOMEM;
2351 }
2352
2353 if (!strcmp(xprt->name, "msm_ipc_router_loopback_xprt")) {
2354 xprt_info->remote_node_id = IPC_ROUTER_NID_LOCAL;
2355 xprt_info->initialized = 1;
2356 }
2357
2358 mutex_lock(&xprt_info_list_lock);
2359 list_add_tail(&xprt_info->list, &xprt_info_list);
2360 mutex_unlock(&xprt_info_list_lock);
2361
2362 mutex_lock(&routing_table_lock);
2363 if (!routing_table_inited) {
2364 init_routing_table();
2365 rt_entry = alloc_routing_table_entry(IPC_ROUTER_NID_LOCAL);
2366 add_routing_table_entry(rt_entry);
2367 routing_table_inited = 1;
2368 }
2369 mutex_unlock(&routing_table_lock);
2370
2371 queue_work(xprt_info->workqueue, &xprt_info->read_data);
2372
2373 xprt->priv = xprt_info;
2374
2375 return 0;
2376}
2377
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002378static void msm_ipc_router_remove_xprt(struct msm_ipc_router_xprt *xprt)
2379{
2380 struct msm_ipc_router_xprt_info *xprt_info;
2381
2382 if (xprt && xprt->priv) {
2383 xprt_info = xprt->priv;
2384
2385 xprt_info->abort_data_read = 1;
2386 wake_up(&xprt_info->read_wait);
2387
2388 mutex_lock(&xprt_info_list_lock);
2389 list_del(&xprt_info->list);
2390 mutex_unlock(&xprt_info_list_lock);
2391
2392 flush_workqueue(xprt_info->workqueue);
2393 destroy_workqueue(xprt_info->workqueue);
2394 wake_lock_destroy(&xprt_info->wakelock);
2395
2396 xprt->priv = 0;
2397 kfree(xprt_info);
2398 }
2399}
2400
2401
2402struct msm_ipc_router_xprt_work {
2403 struct msm_ipc_router_xprt *xprt;
2404 struct work_struct work;
2405};
2406
2407static void xprt_open_worker(struct work_struct *work)
2408{
2409 struct msm_ipc_router_xprt_work *xprt_work =
2410 container_of(work, struct msm_ipc_router_xprt_work, work);
2411
2412 msm_ipc_router_add_xprt(xprt_work->xprt);
2413 kfree(xprt_work);
2414}
2415
2416static void xprt_close_worker(struct work_struct *work)
2417{
2418 struct msm_ipc_router_xprt_work *xprt_work =
2419 container_of(work, struct msm_ipc_router_xprt_work, work);
2420
2421 modem_reset_cleanup(xprt_work->xprt->priv);
2422 msm_ipc_router_remove_xprt(xprt_work->xprt);
2423
2424 if (atomic_dec_return(&pending_close_count) == 0)
2425 wake_up(&subsystem_restart_wait);
2426
2427 kfree(xprt_work);
2428}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002429
2430void msm_ipc_router_xprt_notify(struct msm_ipc_router_xprt *xprt,
2431 unsigned event,
2432 void *data)
2433{
2434 struct msm_ipc_router_xprt_info *xprt_info = xprt->priv;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002435 struct msm_ipc_router_xprt_work *xprt_work;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002436 struct rr_packet *pkt;
Karthikeyan Ramasubramanian4af9f7c2011-09-30 15:55:18 -06002437 unsigned long ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002438
Karthikeyan Ramasubramanian4af9f7c2011-09-30 15:55:18 -06002439 if (!msm_ipc_router_workqueue) {
2440 ret = wait_for_completion_timeout(&msm_ipc_local_router_up,
2441 IPC_ROUTER_INIT_TIMEOUT);
2442 if (!ret || !msm_ipc_router_workqueue) {
2443 pr_err("%s: IPC Router not initialized\n", __func__);
2444 return;
2445 }
2446 }
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002447
2448 switch (event) {
2449 case IPC_ROUTER_XPRT_EVENT_OPEN:
2450 D("open event for '%s'\n", xprt->name);
2451 xprt_work = kmalloc(sizeof(struct msm_ipc_router_xprt_work),
2452 GFP_ATOMIC);
2453 xprt_work->xprt = xprt;
2454 INIT_WORK(&xprt_work->work, xprt_open_worker);
2455 queue_work(msm_ipc_router_workqueue, &xprt_work->work);
2456 break;
2457
2458 case IPC_ROUTER_XPRT_EVENT_CLOSE:
2459 D("close event for '%s'\n", xprt->name);
2460 atomic_inc(&pending_close_count);
2461 xprt_work = kmalloc(sizeof(struct msm_ipc_router_xprt_work),
2462 GFP_ATOMIC);
2463 xprt_work->xprt = xprt;
2464 INIT_WORK(&xprt_work->work, xprt_close_worker);
2465 queue_work(msm_ipc_router_workqueue, &xprt_work->work);
2466 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002467 }
2468
2469 if (!data)
2470 return;
2471
2472 while (!xprt_info) {
2473 msleep(100);
2474 xprt_info = xprt->priv;
2475 }
2476
2477 pkt = clone_pkt((struct rr_packet *)data);
2478 if (!pkt)
2479 return;
2480
2481 mutex_lock(&xprt_info->rx_lock);
2482 list_add_tail(&pkt->list, &xprt_info->pkt_list);
2483 wake_lock(&xprt_info->wakelock);
2484 wake_up(&xprt_info->read_wait);
2485 mutex_unlock(&xprt_info->rx_lock);
2486}
2487
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002488static int modem_restart_notifier_cb(struct notifier_block *this,
2489 unsigned long code,
2490 void *data);
2491static struct notifier_block msm_ipc_router_nb = {
2492 .notifier_call = modem_restart_notifier_cb,
2493};
2494
2495static int modem_restart_notifier_cb(struct notifier_block *this,
2496 unsigned long code,
2497 void *data)
2498{
2499 switch (code) {
2500 case SUBSYS_BEFORE_SHUTDOWN:
2501 D("%s: SUBSYS_BEFORE_SHUTDOWN\n", __func__);
2502 break;
2503
2504 case SUBSYS_BEFORE_POWERUP:
2505 D("%s: waiting for RPC restart to complete\n", __func__);
2506 wait_event(subsystem_restart_wait,
2507 atomic_read(&pending_close_count) == 0);
2508 D("%s: finished restart wait\n", __func__);
2509 break;
2510
2511 default:
2512 break;
2513 }
2514
2515 return NOTIFY_DONE;
2516}
2517
2518static void *restart_notifier_handle;
2519static __init int msm_ipc_router_modem_restart_late_init(void)
2520{
2521 restart_notifier_handle = subsys_notif_register_notifier("modem",
2522 &msm_ipc_router_nb);
2523 return 0;
2524}
2525late_initcall(msm_ipc_router_modem_restart_late_init);
2526
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002527static int __init msm_ipc_router_init(void)
2528{
2529 int i, ret;
2530 struct msm_ipc_routing_table_entry *rt_entry;
2531
2532 msm_ipc_router_debug_mask |= SMEM_LOG;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002533 msm_ipc_router_workqueue =
2534 create_singlethread_workqueue("msm_ipc_router");
2535 if (!msm_ipc_router_workqueue)
2536 return -ENOMEM;
2537
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002538 debugfs_init();
2539
2540 for (i = 0; i < SRV_HASH_SIZE; i++)
2541 INIT_LIST_HEAD(&server_list[i]);
2542
2543 for (i = 0; i < LP_HASH_SIZE; i++)
2544 INIT_LIST_HEAD(&local_ports[i]);
2545
2546 mutex_lock(&routing_table_lock);
2547 if (!routing_table_inited) {
2548 init_routing_table();
2549 rt_entry = alloc_routing_table_entry(IPC_ROUTER_NID_LOCAL);
2550 add_routing_table_entry(rt_entry);
2551 routing_table_inited = 1;
2552 }
2553 mutex_unlock(&routing_table_lock);
2554
2555 init_waitqueue_head(&newserver_wait);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002556 init_waitqueue_head(&subsystem_restart_wait);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002557 ret = msm_ipc_router_init_sockets();
2558 if (ret < 0)
2559 pr_err("%s: Init sockets failed\n", __func__);
2560
Karthikeyan Ramasubramanian4af9f7c2011-09-30 15:55:18 -06002561 complete_all(&msm_ipc_local_router_up);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002562 return ret;
2563}
2564
2565module_init(msm_ipc_router_init);
2566MODULE_DESCRIPTION("MSM IPC Router");
2567MODULE_LICENSE("GPL v2");