blob: 0b08230508ac983295defef897eab557e2b61f2d [file] [log] [blame]
Duy Truonge833aca2013-02-12 13:35:08 -08001/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#define DEBUG
14
15#include <linux/slab.h>
16#include <linux/module.h>
17#include <linux/kernel.h>
18#include <linux/string.h>
19#include <linux/errno.h>
20#include <linux/init.h>
21#include <linux/types.h>
22#include <linux/delay.h>
23#include <linux/err.h>
24#include <linux/sched.h>
25#include <linux/poll.h>
26#include <linux/wakelock.h>
27#include <linux/platform_device.h>
28#include <linux/uaccess.h>
29#include <linux/debugfs.h>
30
31#include <asm/uaccess.h>
32#include <asm/byteorder.h>
33
34#include <mach/smem_log.h>
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -060035#include <mach/subsystem_notif.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070036
37#include "ipc_router.h"
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -060038#include "modem_notifier.h"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070039
40enum {
41 SMEM_LOG = 1U << 0,
42 RTR_DBG = 1U << 1,
43 R2R_MSG = 1U << 2,
44 R2R_RAW = 1U << 3,
45 NTFY_MSG = 1U << 4,
46 R2R_RAW_HDR = 1U << 5,
47};
48
49static int msm_ipc_router_debug_mask;
50module_param_named(debug_mask, msm_ipc_router_debug_mask,
51 int, S_IRUGO | S_IWUSR | S_IWGRP);
52
53#define DIAG(x...) pr_info("[RR] ERROR " x)
54
55#if defined(DEBUG)
56#define D(x...) do { \
57if (msm_ipc_router_debug_mask & RTR_DBG) \
58 pr_info(x); \
59} while (0)
60
61#define RR(x...) do { \
62if (msm_ipc_router_debug_mask & R2R_MSG) \
63 pr_info("[RR] "x); \
64} while (0)
65
66#define RAW(x...) do { \
67if (msm_ipc_router_debug_mask & R2R_RAW) \
68 pr_info("[RAW] "x); \
69} while (0)
70
71#define NTFY(x...) do { \
72if (msm_ipc_router_debug_mask & NTFY_MSG) \
73 pr_info("[NOTIFY] "x); \
74} while (0)
75
76#define RAW_HDR(x...) do { \
77if (msm_ipc_router_debug_mask & R2R_RAW_HDR) \
78 pr_info("[HDR] "x); \
79} while (0)
80#else
81#define D(x...) do { } while (0)
82#define RR(x...) do { } while (0)
83#define RAW(x...) do { } while (0)
84#define RAW_HDR(x...) do { } while (0)
85#define NTFY(x...) do { } while (0)
86#endif
87
88#define IPC_ROUTER_LOG_EVENT_ERROR 0x10
89#define IPC_ROUTER_LOG_EVENT_TX 0x11
90#define IPC_ROUTER_LOG_EVENT_RX 0x12
91
92static LIST_HEAD(control_ports);
93static DEFINE_MUTEX(control_ports_lock);
94
95#define LP_HASH_SIZE 32
96static struct list_head local_ports[LP_HASH_SIZE];
97static DEFINE_MUTEX(local_ports_lock);
98
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -060099/*
100 * Server info is organized as a hash table. The server's service ID is
101 * used to index into the hash table. The instance ID of most of the servers
102 * are 1 or 2. The service IDs are well distributed compared to the instance
103 * IDs and hence choosing service ID to index into this hash table optimizes
104 * the hash table operations like add, lookup, destroy.
105 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700106#define SRV_HASH_SIZE 32
107static struct list_head server_list[SRV_HASH_SIZE];
108static DEFINE_MUTEX(server_list_lock);
109static wait_queue_head_t newserver_wait;
110
111struct msm_ipc_server {
112 struct list_head list;
113 struct msm_ipc_port_name name;
114 struct list_head server_port_list;
115};
116
117struct msm_ipc_server_port {
118 struct list_head list;
119 struct msm_ipc_port_addr server_addr;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600120 struct msm_ipc_router_xprt_info *xprt_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700121};
122
123#define RP_HASH_SIZE 32
124struct msm_ipc_router_remote_port {
125 struct list_head list;
126 uint32_t node_id;
127 uint32_t port_id;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600128 uint32_t restart_state;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700129 wait_queue_head_t quota_wait;
130 uint32_t tx_quota_cnt;
131 struct mutex quota_lock;
132};
133
134struct msm_ipc_router_xprt_info {
135 struct list_head list;
136 struct msm_ipc_router_xprt *xprt;
137 uint32_t remote_node_id;
138 uint32_t initialized;
139 struct list_head pkt_list;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700140 struct wake_lock wakelock;
141 struct mutex rx_lock;
142 struct mutex tx_lock;
143 uint32_t need_len;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600144 uint32_t abort_data_read;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700145 struct work_struct read_data;
146 struct workqueue_struct *workqueue;
147};
148
149#define RT_HASH_SIZE 4
150struct msm_ipc_routing_table_entry {
151 struct list_head list;
152 uint32_t node_id;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600153 uint32_t neighbor_node_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700154 struct list_head remote_port_list[RP_HASH_SIZE];
155 struct msm_ipc_router_xprt_info *xprt_info;
156 struct mutex lock;
157 unsigned long num_tx_bytes;
158 unsigned long num_rx_bytes;
159};
160
161static struct list_head routing_table[RT_HASH_SIZE];
162static DEFINE_MUTEX(routing_table_lock);
163static int routing_table_inited;
164
165static LIST_HEAD(msm_ipc_board_dev_list);
166static DEFINE_MUTEX(msm_ipc_board_dev_list_lock);
167
168static void do_read_data(struct work_struct *work);
169
170#define RR_STATE_IDLE 0
171#define RR_STATE_HEADER 1
172#define RR_STATE_BODY 2
173#define RR_STATE_ERROR 3
174
175#define RESTART_NORMAL 0
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600176#define RESTART_PEND 1
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700177
178/* State for remote ep following restart */
179#define RESTART_QUOTA_ABORT 1
180
181static LIST_HEAD(xprt_info_list);
182static DEFINE_MUTEX(xprt_info_list_lock);
183
Karthikeyan Ramasubramanian4af9f7c2011-09-30 15:55:18 -0600184static DECLARE_COMPLETION(msm_ipc_local_router_up);
185#define IPC_ROUTER_INIT_TIMEOUT (10 * HZ)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700186
187static uint32_t next_port_id;
188static DEFINE_MUTEX(next_port_id_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600189static atomic_t pending_close_count = ATOMIC_INIT(0);
190static wait_queue_head_t subsystem_restart_wait;
191static struct workqueue_struct *msm_ipc_router_workqueue;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700192
193enum {
194 CLIENT_PORT,
195 SERVER_PORT,
196 CONTROL_PORT,
197};
198
199enum {
200 DOWN,
201 UP,
202};
203
204static void init_routing_table(void)
205{
206 int i;
207 for (i = 0; i < RT_HASH_SIZE; i++)
208 INIT_LIST_HEAD(&routing_table[i]);
209}
210
211static struct msm_ipc_routing_table_entry *alloc_routing_table_entry(
212 uint32_t node_id)
213{
214 int i;
215 struct msm_ipc_routing_table_entry *rt_entry;
216
217 rt_entry = kmalloc(sizeof(struct msm_ipc_routing_table_entry),
218 GFP_KERNEL);
219 if (!rt_entry) {
220 pr_err("%s: rt_entry allocation failed for %d\n",
221 __func__, node_id);
222 return NULL;
223 }
224
225 for (i = 0; i < RP_HASH_SIZE; i++)
226 INIT_LIST_HEAD(&rt_entry->remote_port_list[i]);
227
228 mutex_init(&rt_entry->lock);
229 rt_entry->node_id = node_id;
230 rt_entry->xprt_info = NULL;
231 return rt_entry;
232}
233
234/*Please take routing_table_lock before calling this function*/
235static int add_routing_table_entry(
236 struct msm_ipc_routing_table_entry *rt_entry)
237{
238 uint32_t key;
239
240 if (!rt_entry)
241 return -EINVAL;
242
243 key = (rt_entry->node_id % RT_HASH_SIZE);
244 list_add_tail(&rt_entry->list, &routing_table[key]);
245 return 0;
246}
247
248/*Please take routing_table_lock before calling this function*/
249static struct msm_ipc_routing_table_entry *lookup_routing_table(
250 uint32_t node_id)
251{
252 uint32_t key = (node_id % RT_HASH_SIZE);
253 struct msm_ipc_routing_table_entry *rt_entry;
254
255 list_for_each_entry(rt_entry, &routing_table[key], list) {
256 if (rt_entry->node_id == node_id)
257 return rt_entry;
258 }
259 return NULL;
260}
261
262struct rr_packet *rr_read(struct msm_ipc_router_xprt_info *xprt_info)
263{
264 struct rr_packet *temp_pkt;
265
266 if (!xprt_info)
267 return NULL;
268
269 mutex_lock(&xprt_info->rx_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600270 if (xprt_info->abort_data_read) {
271 mutex_unlock(&xprt_info->rx_lock);
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -0600272 pr_err("%s detected SSR & exiting now\n",
273 xprt_info->xprt->name);
274 return NULL;
275 }
276
277 if (list_empty(&xprt_info->pkt_list)) {
278 mutex_unlock(&xprt_info->rx_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600279 return NULL;
280 }
281
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700282 temp_pkt = list_first_entry(&xprt_info->pkt_list,
283 struct rr_packet, list);
284 list_del(&temp_pkt->list);
285 if (list_empty(&xprt_info->pkt_list))
286 wake_unlock(&xprt_info->wakelock);
287 mutex_unlock(&xprt_info->rx_lock);
288 return temp_pkt;
289}
290
291struct rr_packet *clone_pkt(struct rr_packet *pkt)
292{
293 struct rr_packet *cloned_pkt;
294 struct sk_buff *temp_skb, *cloned_skb;
295 struct sk_buff_head *pkt_fragment_q;
296
297 cloned_pkt = kzalloc(sizeof(struct rr_packet), GFP_KERNEL);
298 if (!cloned_pkt) {
299 pr_err("%s: failure\n", __func__);
300 return NULL;
301 }
302
303 pkt_fragment_q = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
304 if (!pkt_fragment_q) {
305 pr_err("%s: pkt_frag_q alloc failure\n", __func__);
306 kfree(cloned_pkt);
307 return NULL;
308 }
309 skb_queue_head_init(pkt_fragment_q);
310
311 skb_queue_walk(pkt->pkt_fragment_q, temp_skb) {
312 cloned_skb = skb_clone(temp_skb, GFP_KERNEL);
313 if (!cloned_skb)
314 goto fail_clone;
315 skb_queue_tail(pkt_fragment_q, cloned_skb);
316 }
317 cloned_pkt->pkt_fragment_q = pkt_fragment_q;
318 cloned_pkt->length = pkt->length;
319 return cloned_pkt;
320
321fail_clone:
322 while (!skb_queue_empty(pkt_fragment_q)) {
323 temp_skb = skb_dequeue(pkt_fragment_q);
324 kfree_skb(temp_skb);
325 }
326 kfree(pkt_fragment_q);
327 kfree(cloned_pkt);
328 return NULL;
329}
330
331struct rr_packet *create_pkt(struct sk_buff_head *data)
332{
333 struct rr_packet *pkt;
334 struct sk_buff *temp_skb;
335
336 pkt = kzalloc(sizeof(struct rr_packet), GFP_KERNEL);
337 if (!pkt) {
338 pr_err("%s: failure\n", __func__);
339 return NULL;
340 }
341
342 pkt->pkt_fragment_q = data;
343 skb_queue_walk(pkt->pkt_fragment_q, temp_skb)
344 pkt->length += temp_skb->len;
345 return pkt;
346}
347
348void release_pkt(struct rr_packet *pkt)
349{
350 struct sk_buff *temp_skb;
351
352 if (!pkt)
353 return;
354
355 if (!pkt->pkt_fragment_q) {
356 kfree(pkt);
357 return;
358 }
359
360 while (!skb_queue_empty(pkt->pkt_fragment_q)) {
361 temp_skb = skb_dequeue(pkt->pkt_fragment_q);
362 kfree_skb(temp_skb);
363 }
364 kfree(pkt->pkt_fragment_q);
365 kfree(pkt);
366 return;
367}
368
369static int post_control_ports(struct rr_packet *pkt)
370{
371 struct msm_ipc_port *port_ptr;
372 struct rr_packet *cloned_pkt;
373
374 if (!pkt)
375 return -EINVAL;
376
377 mutex_lock(&control_ports_lock);
378 list_for_each_entry(port_ptr, &control_ports, list) {
379 mutex_lock(&port_ptr->port_rx_q_lock);
380 cloned_pkt = clone_pkt(pkt);
381 wake_lock(&port_ptr->port_rx_wake_lock);
382 list_add_tail(&cloned_pkt->list, &port_ptr->port_rx_q);
383 wake_up(&port_ptr->port_rx_wait_q);
384 mutex_unlock(&port_ptr->port_rx_q_lock);
385 }
386 mutex_unlock(&control_ports_lock);
387 return 0;
388}
389
390static uint32_t allocate_port_id(void)
391{
392 uint32_t port_id = 0, prev_port_id, key;
393 struct msm_ipc_port *port_ptr;
394
395 mutex_lock(&next_port_id_lock);
396 prev_port_id = next_port_id;
397 mutex_lock(&local_ports_lock);
398 do {
399 next_port_id++;
400 if ((next_port_id & 0xFFFFFFFE) == 0xFFFFFFFE)
401 next_port_id = 1;
402
403 key = (next_port_id & (LP_HASH_SIZE - 1));
404 if (list_empty(&local_ports[key])) {
405 port_id = next_port_id;
406 break;
407 }
408 list_for_each_entry(port_ptr, &local_ports[key], list) {
409 if (port_ptr->this_port.port_id == next_port_id) {
410 port_id = next_port_id;
411 break;
412 }
413 }
414 if (!port_id) {
415 port_id = next_port_id;
416 break;
417 }
418 port_id = 0;
419 } while (next_port_id != prev_port_id);
420 mutex_unlock(&local_ports_lock);
421 mutex_unlock(&next_port_id_lock);
422
423 return port_id;
424}
425
426void msm_ipc_router_add_local_port(struct msm_ipc_port *port_ptr)
427{
428 uint32_t key;
429
430 if (!port_ptr)
431 return;
432
433 key = (port_ptr->this_port.port_id & (LP_HASH_SIZE - 1));
434 mutex_lock(&local_ports_lock);
435 list_add_tail(&port_ptr->list, &local_ports[key]);
436 mutex_unlock(&local_ports_lock);
437}
438
439struct msm_ipc_port *msm_ipc_router_create_raw_port(void *endpoint,
440 void (*notify)(unsigned event, void *data,
441 void *addr, void *priv),
442 void *priv)
443{
444 struct msm_ipc_port *port_ptr;
445
446 port_ptr = kzalloc(sizeof(struct msm_ipc_port), GFP_KERNEL);
447 if (!port_ptr)
448 return NULL;
449
450 port_ptr->this_port.node_id = IPC_ROUTER_NID_LOCAL;
451 port_ptr->this_port.port_id = allocate_port_id();
452 if (!port_ptr->this_port.port_id) {
453 pr_err("%s: All port ids are in use\n", __func__);
454 kfree(port_ptr);
455 return NULL;
456 }
457
458 spin_lock_init(&port_ptr->port_lock);
459 INIT_LIST_HEAD(&port_ptr->incomplete);
460 mutex_init(&port_ptr->incomplete_lock);
461 INIT_LIST_HEAD(&port_ptr->port_rx_q);
462 mutex_init(&port_ptr->port_rx_q_lock);
463 init_waitqueue_head(&port_ptr->port_rx_wait_q);
Karthikeyan Ramasubramanianb4aeeb92012-03-13 12:31:43 -0600464 snprintf(port_ptr->rx_wakelock_name, MAX_WAKELOCK_NAME_SZ,
465 "msm_ipc_read%08x:%08x",
466 port_ptr->this_port.node_id,
467 port_ptr->this_port.port_id);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700468 wake_lock_init(&port_ptr->port_rx_wake_lock,
Karthikeyan Ramasubramanianb4aeeb92012-03-13 12:31:43 -0600469 WAKE_LOCK_SUSPEND, port_ptr->rx_wakelock_name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700470
471 port_ptr->endpoint = endpoint;
472 port_ptr->notify = notify;
473 port_ptr->priv = priv;
474
475 msm_ipc_router_add_local_port(port_ptr);
476 return port_ptr;
477}
478
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -0600479/*
480 * Should be called with local_ports_lock locked
481 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700482static struct msm_ipc_port *msm_ipc_router_lookup_local_port(uint32_t port_id)
483{
484 int key = (port_id & (LP_HASH_SIZE - 1));
485 struct msm_ipc_port *port_ptr;
486
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700487 list_for_each_entry(port_ptr, &local_ports[key], list) {
488 if (port_ptr->this_port.port_id == port_id) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700489 return port_ptr;
490 }
491 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700492 return NULL;
493}
494
495static struct msm_ipc_router_remote_port *msm_ipc_router_lookup_remote_port(
496 uint32_t node_id,
497 uint32_t port_id)
498{
499 struct msm_ipc_router_remote_port *rport_ptr;
500 struct msm_ipc_routing_table_entry *rt_entry;
501 int key = (port_id & (RP_HASH_SIZE - 1));
502
503 mutex_lock(&routing_table_lock);
504 rt_entry = lookup_routing_table(node_id);
505 if (!rt_entry) {
506 mutex_unlock(&routing_table_lock);
507 pr_err("%s: Node is not up\n", __func__);
508 return NULL;
509 }
510
511 mutex_lock(&rt_entry->lock);
512 list_for_each_entry(rport_ptr,
513 &rt_entry->remote_port_list[key], list) {
514 if (rport_ptr->port_id == port_id) {
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600515 if (rport_ptr->restart_state != RESTART_NORMAL)
516 rport_ptr = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700517 mutex_unlock(&rt_entry->lock);
518 mutex_unlock(&routing_table_lock);
519 return rport_ptr;
520 }
521 }
522 mutex_unlock(&rt_entry->lock);
523 mutex_unlock(&routing_table_lock);
524 return NULL;
525}
526
527static struct msm_ipc_router_remote_port *msm_ipc_router_create_remote_port(
528 uint32_t node_id,
529 uint32_t port_id)
530{
531 struct msm_ipc_router_remote_port *rport_ptr;
532 struct msm_ipc_routing_table_entry *rt_entry;
533 int key = (port_id & (RP_HASH_SIZE - 1));
534
535 mutex_lock(&routing_table_lock);
536 rt_entry = lookup_routing_table(node_id);
537 if (!rt_entry) {
538 mutex_unlock(&routing_table_lock);
539 pr_err("%s: Node is not up\n", __func__);
540 return NULL;
541 }
542
543 mutex_lock(&rt_entry->lock);
544 rport_ptr = kmalloc(sizeof(struct msm_ipc_router_remote_port),
545 GFP_KERNEL);
546 if (!rport_ptr) {
547 mutex_unlock(&rt_entry->lock);
548 mutex_unlock(&routing_table_lock);
549 pr_err("%s: Remote port alloc failed\n", __func__);
550 return NULL;
551 }
552 rport_ptr->port_id = port_id;
553 rport_ptr->node_id = node_id;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600554 rport_ptr->restart_state = RESTART_NORMAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700555 rport_ptr->tx_quota_cnt = 0;
556 init_waitqueue_head(&rport_ptr->quota_wait);
557 mutex_init(&rport_ptr->quota_lock);
558 list_add_tail(&rport_ptr->list,
559 &rt_entry->remote_port_list[key]);
560 mutex_unlock(&rt_entry->lock);
561 mutex_unlock(&routing_table_lock);
562 return rport_ptr;
563}
564
565static void msm_ipc_router_destroy_remote_port(
566 struct msm_ipc_router_remote_port *rport_ptr)
567{
568 uint32_t node_id;
569 struct msm_ipc_routing_table_entry *rt_entry;
570
571 if (!rport_ptr)
572 return;
573
574 node_id = rport_ptr->node_id;
575 mutex_lock(&routing_table_lock);
576 rt_entry = lookup_routing_table(node_id);
577 if (!rt_entry) {
578 mutex_unlock(&routing_table_lock);
579 pr_err("%s: Node %d is not up\n", __func__, node_id);
580 return;
581 }
582
583 mutex_lock(&rt_entry->lock);
584 list_del(&rport_ptr->list);
585 kfree(rport_ptr);
586 mutex_unlock(&rt_entry->lock);
587 mutex_unlock(&routing_table_lock);
588 return;
589}
590
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -0600591/**
592 * msm_ipc_router_lookup_server() - Lookup server information
593 * @service: Service ID of the server info to be looked up.
594 * @instance: Instance ID of the server info to be looked up.
595 * @node_id: Node/Processor ID in which the server is hosted.
596 * @port_id: Port ID within the node in which the server is hosted.
597 *
598 * @return: If found Pointer to server structure, else NULL.
599 *
600 * Note1: Lock the server_list_lock before accessing this function.
601 * Note2: If the <node_id:port_id> are <0:0>, then the lookup is restricted
602 * to <service:instance>. Used only when a client wants to send a
603 * message to any QMI server.
604 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700605static struct msm_ipc_server *msm_ipc_router_lookup_server(
606 uint32_t service,
607 uint32_t instance,
608 uint32_t node_id,
609 uint32_t port_id)
610{
611 struct msm_ipc_server *server;
612 struct msm_ipc_server_port *server_port;
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -0600613 int key = (service & (SRV_HASH_SIZE - 1));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700614
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700615 list_for_each_entry(server, &server_list[key], list) {
616 if ((server->name.service != service) ||
617 (server->name.instance != instance))
618 continue;
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -0600619 if ((node_id == 0) && (port_id == 0))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700620 return server;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700621 list_for_each_entry(server_port, &server->server_port_list,
622 list) {
623 if ((server_port->server_addr.node_id == node_id) &&
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -0600624 (server_port->server_addr.port_id == port_id))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700625 return server;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700626 }
627 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700628 return NULL;
629}
630
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -0600631/**
632 * msm_ipc_router_create_server() - Add server info to hash table
633 * @service: Service ID of the server info to be created.
634 * @instance: Instance ID of the server info to be created.
635 * @node_id: Node/Processor ID in which the server is hosted.
636 * @port_id: Port ID within the node in which the server is hosted.
637 * @xprt_info: XPRT through which the node hosting the server is reached.
638 *
639 * @return: Pointer to server structure on success, else NULL.
640 *
641 * This function adds the server info to the hash table. If the same
642 * server(i.e. <service_id:instance_id>) is hosted in different nodes,
643 * they are maintained as list of "server_port" under "server" structure.
644 * Note: Lock the server_list_lock before accessing this function.
645 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700646static struct msm_ipc_server *msm_ipc_router_create_server(
647 uint32_t service,
648 uint32_t instance,
649 uint32_t node_id,
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600650 uint32_t port_id,
651 struct msm_ipc_router_xprt_info *xprt_info)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700652{
653 struct msm_ipc_server *server = NULL;
654 struct msm_ipc_server_port *server_port;
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -0600655 int key = (service & (SRV_HASH_SIZE - 1));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700656
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700657 list_for_each_entry(server, &server_list[key], list) {
658 if ((server->name.service == service) &&
659 (server->name.instance == instance))
660 goto create_srv_port;
661 }
662
663 server = kmalloc(sizeof(struct msm_ipc_server), GFP_KERNEL);
664 if (!server) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700665 pr_err("%s: Server allocation failed\n", __func__);
666 return NULL;
667 }
668 server->name.service = service;
669 server->name.instance = instance;
670 INIT_LIST_HEAD(&server->server_port_list);
671 list_add_tail(&server->list, &server_list[key]);
672
673create_srv_port:
674 server_port = kmalloc(sizeof(struct msm_ipc_server_port), GFP_KERNEL);
675 if (!server_port) {
676 if (list_empty(&server->server_port_list)) {
677 list_del(&server->list);
678 kfree(server);
679 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700680 pr_err("%s: Server Port allocation failed\n", __func__);
681 return NULL;
682 }
683 server_port->server_addr.node_id = node_id;
684 server_port->server_addr.port_id = port_id;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600685 server_port->xprt_info = xprt_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700686 list_add_tail(&server_port->list, &server->server_port_list);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700687
688 return server;
689}
690
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -0600691/**
692 * msm_ipc_router_destroy_server() - Remove server info from hash table
693 * @server: Server info to be removed.
694 * @node_id: Node/Processor ID in which the server is hosted.
695 * @port_id: Port ID within the node in which the server is hosted.
696 *
697 * This function removes the server_port identified using <node_id:port_id>
698 * from the server structure. If the server_port list under server structure
699 * is empty after removal, then remove the server structure from the server
700 * hash table.
701 * Note: Lock the server_list_lock before accessing this function.
702 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700703static void msm_ipc_router_destroy_server(struct msm_ipc_server *server,
704 uint32_t node_id, uint32_t port_id)
705{
706 struct msm_ipc_server_port *server_port;
707
708 if (!server)
709 return;
710
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700711 list_for_each_entry(server_port, &server->server_port_list, list) {
712 if ((server_port->server_addr.node_id == node_id) &&
713 (server_port->server_addr.port_id == port_id))
714 break;
715 }
716 if (server_port) {
717 list_del(&server_port->list);
718 kfree(server_port);
719 }
720 if (list_empty(&server->server_port_list)) {
721 list_del(&server->list);
722 kfree(server);
723 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700724 return;
725}
726
727static int msm_ipc_router_send_control_msg(
728 struct msm_ipc_router_xprt_info *xprt_info,
729 union rr_control_msg *msg)
730{
731 struct rr_packet *pkt;
732 struct sk_buff *ipc_rtr_pkt;
733 struct rr_header *hdr;
734 int pkt_size;
735 void *data;
736 struct sk_buff_head *pkt_fragment_q;
737 int ret;
738
739 if (!xprt_info || ((msg->cmd != IPC_ROUTER_CTRL_CMD_HELLO) &&
740 !xprt_info->initialized)) {
741 pr_err("%s: xprt_info not initialized\n", __func__);
742 return -EINVAL;
743 }
744
745 if (xprt_info->remote_node_id == IPC_ROUTER_NID_LOCAL)
746 return 0;
747
748 pkt = kzalloc(sizeof(struct rr_packet), GFP_KERNEL);
749 if (!pkt) {
750 pr_err("%s: pkt alloc failed\n", __func__);
751 return -ENOMEM;
752 }
753
754 pkt_fragment_q = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
755 if (!pkt_fragment_q) {
756 pr_err("%s: pkt_fragment_q alloc failed\n", __func__);
757 kfree(pkt);
758 return -ENOMEM;
759 }
760 skb_queue_head_init(pkt_fragment_q);
761
762 pkt_size = IPC_ROUTER_HDR_SIZE + sizeof(*msg);
763 ipc_rtr_pkt = alloc_skb(pkt_size, GFP_KERNEL);
764 if (!ipc_rtr_pkt) {
765 pr_err("%s: ipc_rtr_pkt alloc failed\n", __func__);
766 kfree(pkt_fragment_q);
767 kfree(pkt);
768 return -ENOMEM;
769 }
770
771 skb_reserve(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
772 data = skb_put(ipc_rtr_pkt, sizeof(*msg));
773 memcpy(data, msg, sizeof(*msg));
774 hdr = (struct rr_header *)skb_push(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
775 if (!hdr) {
776 pr_err("%s: skb_push failed\n", __func__);
777 kfree_skb(ipc_rtr_pkt);
778 kfree(pkt_fragment_q);
779 kfree(pkt);
780 return -ENOMEM;
781 }
782
783 hdr->version = IPC_ROUTER_VERSION;
784 hdr->type = msg->cmd;
785 hdr->src_node_id = IPC_ROUTER_NID_LOCAL;
786 hdr->src_port_id = IPC_ROUTER_ADDRESS;
787 hdr->confirm_rx = 0;
788 hdr->size = sizeof(*msg);
789 hdr->dst_node_id = xprt_info->remote_node_id;
790 hdr->dst_port_id = IPC_ROUTER_ADDRESS;
791 skb_queue_tail(pkt_fragment_q, ipc_rtr_pkt);
792 pkt->pkt_fragment_q = pkt_fragment_q;
793 pkt->length = pkt_size;
794
795 mutex_lock(&xprt_info->tx_lock);
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700796 ret = xprt_info->xprt->write(pkt, pkt_size, xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700797 mutex_unlock(&xprt_info->tx_lock);
798
799 release_pkt(pkt);
800 return ret;
801}
802
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -0600803static int msm_ipc_router_send_server_list(uint32_t node_id,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700804 struct msm_ipc_router_xprt_info *xprt_info)
805{
806 union rr_control_msg ctl;
807 struct msm_ipc_server *server;
808 struct msm_ipc_server_port *server_port;
809 int i;
810
811 if (!xprt_info || !xprt_info->initialized) {
812 pr_err("%s: Xprt info not initialized\n", __func__);
813 return -EINVAL;
814 }
815
816 ctl.cmd = IPC_ROUTER_CTRL_CMD_NEW_SERVER;
817
818 mutex_lock(&server_list_lock);
819 for (i = 0; i < SRV_HASH_SIZE; i++) {
820 list_for_each_entry(server, &server_list[i], list) {
821 ctl.srv.service = server->name.service;
822 ctl.srv.instance = server->name.instance;
823 list_for_each_entry(server_port,
824 &server->server_port_list, list) {
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -0600825 if (server_port->server_addr.node_id !=
826 node_id)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700827 continue;
828
829 ctl.srv.node_id =
830 server_port->server_addr.node_id;
831 ctl.srv.port_id =
832 server_port->server_addr.port_id;
833 msm_ipc_router_send_control_msg(xprt_info,
834 &ctl);
835 }
836 }
837 }
838 mutex_unlock(&server_list_lock);
839
840 return 0;
841}
842
843#if defined(DEBUG)
844static char *type_to_str(int i)
845{
846 switch (i) {
847 case IPC_ROUTER_CTRL_CMD_DATA:
848 return "data ";
849 case IPC_ROUTER_CTRL_CMD_HELLO:
850 return "hello ";
851 case IPC_ROUTER_CTRL_CMD_BYE:
852 return "bye ";
853 case IPC_ROUTER_CTRL_CMD_NEW_SERVER:
854 return "new_srvr";
855 case IPC_ROUTER_CTRL_CMD_REMOVE_SERVER:
856 return "rmv_srvr";
857 case IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT:
858 return "rmv_clnt";
859 case IPC_ROUTER_CTRL_CMD_RESUME_TX:
860 return "resum_tx";
861 case IPC_ROUTER_CTRL_CMD_EXIT:
862 return "cmd_exit";
863 default:
864 return "invalid";
865 }
866}
867#endif
868
869static int broadcast_ctl_msg_locally(union rr_control_msg *msg)
870{
871 struct rr_packet *pkt;
872 struct sk_buff *ipc_rtr_pkt;
873 struct rr_header *hdr;
874 int pkt_size;
875 void *data;
876 struct sk_buff_head *pkt_fragment_q;
877 int ret;
878
879 pkt = kzalloc(sizeof(struct rr_packet), GFP_KERNEL);
880 if (!pkt) {
881 pr_err("%s: pkt alloc failed\n", __func__);
882 return -ENOMEM;
883 }
884
885 pkt_fragment_q = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
886 if (!pkt_fragment_q) {
887 pr_err("%s: pkt_fragment_q alloc failed\n", __func__);
888 kfree(pkt);
889 return -ENOMEM;
890 }
891 skb_queue_head_init(pkt_fragment_q);
892
893 pkt_size = IPC_ROUTER_HDR_SIZE + sizeof(*msg);
894 ipc_rtr_pkt = alloc_skb(pkt_size, GFP_KERNEL);
895 if (!ipc_rtr_pkt) {
896 pr_err("%s: ipc_rtr_pkt alloc failed\n", __func__);
897 kfree(pkt_fragment_q);
898 kfree(pkt);
899 return -ENOMEM;
900 }
901
902 skb_reserve(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
903 data = skb_put(ipc_rtr_pkt, sizeof(*msg));
904 memcpy(data, msg, sizeof(*msg));
905 hdr = (struct rr_header *)skb_push(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
906 if (!hdr) {
907 pr_err("%s: skb_push failed\n", __func__);
908 kfree_skb(ipc_rtr_pkt);
909 kfree(pkt_fragment_q);
910 kfree(pkt);
911 return -ENOMEM;
912 }
913 hdr->version = IPC_ROUTER_VERSION;
914 hdr->type = msg->cmd;
915 hdr->src_node_id = IPC_ROUTER_NID_LOCAL;
916 hdr->src_port_id = IPC_ROUTER_ADDRESS;
917 hdr->confirm_rx = 0;
918 hdr->size = sizeof(*msg);
919 hdr->dst_node_id = IPC_ROUTER_NID_LOCAL;
920 hdr->dst_port_id = IPC_ROUTER_ADDRESS;
921 skb_queue_tail(pkt_fragment_q, ipc_rtr_pkt);
922 pkt->pkt_fragment_q = pkt_fragment_q;
923 pkt->length = pkt_size;
924
925 ret = post_control_ports(pkt);
926 release_pkt(pkt);
927 return ret;
928}
929
930static int broadcast_ctl_msg(union rr_control_msg *ctl)
931{
932 struct msm_ipc_router_xprt_info *xprt_info;
933
934 mutex_lock(&xprt_info_list_lock);
935 list_for_each_entry(xprt_info, &xprt_info_list, list) {
936 msm_ipc_router_send_control_msg(xprt_info, ctl);
937 }
938 mutex_unlock(&xprt_info_list_lock);
939
940 return 0;
941}
942
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600943static int relay_ctl_msg(struct msm_ipc_router_xprt_info *xprt_info,
944 union rr_control_msg *ctl)
945{
946 struct msm_ipc_router_xprt_info *fwd_xprt_info;
947
948 if (!xprt_info || !ctl)
949 return -EINVAL;
950
951 mutex_lock(&xprt_info_list_lock);
952 list_for_each_entry(fwd_xprt_info, &xprt_info_list, list) {
953 if (xprt_info->xprt->link_id != fwd_xprt_info->xprt->link_id)
954 msm_ipc_router_send_control_msg(fwd_xprt_info, ctl);
955 }
956 mutex_unlock(&xprt_info_list_lock);
957
958 return 0;
959}
960
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700961static int relay_msg(struct msm_ipc_router_xprt_info *xprt_info,
962 struct rr_packet *pkt)
963{
964 struct msm_ipc_router_xprt_info *fwd_xprt_info;
965
966 if (!xprt_info || !pkt)
967 return -EINVAL;
968
969 mutex_lock(&xprt_info_list_lock);
970 list_for_each_entry(fwd_xprt_info, &xprt_info_list, list) {
971 mutex_lock(&fwd_xprt_info->tx_lock);
972 if (xprt_info->xprt->link_id != fwd_xprt_info->xprt->link_id)
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700973 fwd_xprt_info->xprt->write(pkt, pkt->length,
974 fwd_xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700975 mutex_unlock(&fwd_xprt_info->tx_lock);
976 }
977 mutex_unlock(&xprt_info_list_lock);
978 return 0;
979}
980
981static int forward_msg(struct msm_ipc_router_xprt_info *xprt_info,
982 struct rr_packet *pkt)
983{
984 uint32_t dst_node_id;
985 struct sk_buff *head_pkt;
986 struct rr_header *hdr;
987 struct msm_ipc_router_xprt_info *fwd_xprt_info;
988 struct msm_ipc_routing_table_entry *rt_entry;
989
990 if (!xprt_info || !pkt)
991 return -EINVAL;
992
993 head_pkt = skb_peek(pkt->pkt_fragment_q);
994 if (!head_pkt)
995 return -EINVAL;
996
997 hdr = (struct rr_header *)head_pkt->data;
998 dst_node_id = hdr->dst_node_id;
999 mutex_lock(&routing_table_lock);
1000 rt_entry = lookup_routing_table(dst_node_id);
1001 if (!(rt_entry) || !(rt_entry->xprt_info)) {
1002 mutex_unlock(&routing_table_lock);
1003 pr_err("%s: Routing table not initialized\n", __func__);
1004 return -ENODEV;
1005 }
1006
1007 mutex_lock(&rt_entry->lock);
1008 fwd_xprt_info = rt_entry->xprt_info;
1009 mutex_lock(&fwd_xprt_info->tx_lock);
1010 if (xprt_info->remote_node_id == fwd_xprt_info->remote_node_id) {
1011 mutex_unlock(&fwd_xprt_info->tx_lock);
1012 mutex_unlock(&rt_entry->lock);
1013 mutex_unlock(&routing_table_lock);
1014 pr_err("%s: Discarding Command to route back\n", __func__);
1015 return -EINVAL;
1016 }
1017
1018 if (xprt_info->xprt->link_id == fwd_xprt_info->xprt->link_id) {
1019 mutex_unlock(&fwd_xprt_info->tx_lock);
1020 mutex_unlock(&rt_entry->lock);
1021 mutex_unlock(&routing_table_lock);
1022 pr_err("%s: DST in the same cluster\n", __func__);
1023 return 0;
1024 }
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -07001025 fwd_xprt_info->xprt->write(pkt, pkt->length, fwd_xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001026 mutex_unlock(&fwd_xprt_info->tx_lock);
1027 mutex_unlock(&rt_entry->lock);
1028 mutex_unlock(&routing_table_lock);
1029
1030 return 0;
1031}
1032
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001033static void reset_remote_port_info(uint32_t node_id, uint32_t port_id)
1034{
1035 struct msm_ipc_router_remote_port *rport_ptr;
1036
1037 rport_ptr = msm_ipc_router_lookup_remote_port(node_id, port_id);
1038 if (!rport_ptr) {
1039 pr_err("%s: No such remote port %08x:%08x\n",
1040 __func__, node_id, port_id);
1041 return;
1042 }
1043 mutex_lock(&rport_ptr->quota_lock);
1044 rport_ptr->restart_state = RESTART_PEND;
1045 wake_up(&rport_ptr->quota_wait);
1046 mutex_unlock(&rport_ptr->quota_lock);
1047 return;
1048}
1049
1050static void msm_ipc_cleanup_remote_server_info(
1051 struct msm_ipc_router_xprt_info *xprt_info)
1052{
1053 struct msm_ipc_server *svr, *tmp_svr;
1054 struct msm_ipc_server_port *svr_port, *tmp_svr_port;
1055 int i;
1056 union rr_control_msg ctl;
1057
1058 if (!xprt_info) {
1059 pr_err("%s: Invalid xprt_info\n", __func__);
1060 return;
1061 }
1062
1063 ctl.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_SERVER;
1064 mutex_lock(&server_list_lock);
1065 for (i = 0; i < SRV_HASH_SIZE; i++) {
1066 list_for_each_entry_safe(svr, tmp_svr, &server_list[i], list) {
1067 ctl.srv.service = svr->name.service;
1068 ctl.srv.instance = svr->name.instance;
1069 list_for_each_entry_safe(svr_port, tmp_svr_port,
1070 &svr->server_port_list, list) {
1071 if (svr_port->xprt_info != xprt_info)
1072 continue;
1073 D("Remove server %08x:%08x - %08x:%08x",
1074 ctl.srv.service, ctl.srv.instance,
1075 svr_port->server_addr.node_id,
1076 svr_port->server_addr.port_id);
1077 reset_remote_port_info(
1078 svr_port->server_addr.node_id,
1079 svr_port->server_addr.port_id);
1080 ctl.srv.node_id = svr_port->server_addr.node_id;
1081 ctl.srv.port_id = svr_port->server_addr.port_id;
1082 relay_ctl_msg(xprt_info, &ctl);
1083 broadcast_ctl_msg_locally(&ctl);
1084 list_del(&svr_port->list);
1085 kfree(svr_port);
1086 }
1087 if (list_empty(&svr->server_port_list)) {
1088 list_del(&svr->list);
1089 kfree(svr);
1090 }
1091 }
1092 }
1093 mutex_unlock(&server_list_lock);
1094}
1095
1096static void msm_ipc_cleanup_remote_client_info(
1097 struct msm_ipc_router_xprt_info *xprt_info)
1098{
1099 struct msm_ipc_routing_table_entry *rt_entry;
1100 struct msm_ipc_router_remote_port *rport_ptr;
1101 int i, j;
1102 union rr_control_msg ctl;
1103
1104 if (!xprt_info) {
1105 pr_err("%s: Invalid xprt_info\n", __func__);
1106 return;
1107 }
1108
1109 ctl.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT;
1110 mutex_lock(&routing_table_lock);
1111 for (i = 0; i < RT_HASH_SIZE; i++) {
1112 list_for_each_entry(rt_entry, &routing_table[i], list) {
1113 mutex_lock(&rt_entry->lock);
1114 if (rt_entry->xprt_info != xprt_info) {
1115 mutex_unlock(&rt_entry->lock);
1116 continue;
1117 }
1118 for (j = 0; j < RP_HASH_SIZE; j++) {
1119 list_for_each_entry(rport_ptr,
1120 &rt_entry->remote_port_list[j], list) {
1121 if (rport_ptr->restart_state ==
1122 RESTART_PEND)
1123 continue;
1124 mutex_lock(&rport_ptr->quota_lock);
1125 rport_ptr->restart_state = RESTART_PEND;
1126 wake_up(&rport_ptr->quota_wait);
1127 mutex_unlock(&rport_ptr->quota_lock);
1128 ctl.cli.node_id = rport_ptr->node_id;
1129 ctl.cli.port_id = rport_ptr->port_id;
1130 broadcast_ctl_msg_locally(&ctl);
1131 }
1132 }
1133 mutex_unlock(&rt_entry->lock);
1134 }
1135 }
1136 mutex_unlock(&routing_table_lock);
1137}
1138
1139static void msm_ipc_cleanup_remote_port_info(uint32_t node_id)
1140{
1141 struct msm_ipc_routing_table_entry *rt_entry, *tmp_rt_entry;
1142 struct msm_ipc_router_remote_port *rport_ptr, *tmp_rport_ptr;
1143 int i, j;
1144
1145 mutex_lock(&routing_table_lock);
1146 for (i = 0; i < RT_HASH_SIZE; i++) {
1147 list_for_each_entry_safe(rt_entry, tmp_rt_entry,
1148 &routing_table[i], list) {
1149 mutex_lock(&rt_entry->lock);
1150 if (rt_entry->neighbor_node_id != node_id) {
1151 mutex_unlock(&rt_entry->lock);
1152 continue;
1153 }
1154 for (j = 0; j < RP_HASH_SIZE; j++) {
1155 list_for_each_entry_safe(rport_ptr,
1156 tmp_rport_ptr,
1157 &rt_entry->remote_port_list[j], list) {
1158 list_del(&rport_ptr->list);
1159 kfree(rport_ptr);
1160 }
1161 }
1162 mutex_unlock(&rt_entry->lock);
1163 }
1164 }
1165 mutex_unlock(&routing_table_lock);
1166}
1167
1168static void msm_ipc_cleanup_routing_table(
1169 struct msm_ipc_router_xprt_info *xprt_info)
1170{
1171 int i;
1172 struct msm_ipc_routing_table_entry *rt_entry;
1173
1174 if (!xprt_info) {
1175 pr_err("%s: Invalid xprt_info\n", __func__);
1176 return;
1177 }
1178
1179 mutex_lock(&routing_table_lock);
1180 for (i = 0; i < RT_HASH_SIZE; i++) {
1181 list_for_each_entry(rt_entry, &routing_table[i], list) {
1182 mutex_lock(&rt_entry->lock);
1183 if (rt_entry->xprt_info == xprt_info)
1184 rt_entry->xprt_info = NULL;
1185 mutex_unlock(&rt_entry->lock);
1186 }
1187 }
1188 mutex_unlock(&routing_table_lock);
1189}
1190
1191static void modem_reset_cleanup(struct msm_ipc_router_xprt_info *xprt_info)
1192{
1193
1194 if (!xprt_info) {
1195 pr_err("%s: Invalid xprt_info\n", __func__);
1196 return;
1197 }
1198
1199 msm_ipc_cleanup_remote_server_info(xprt_info);
1200 msm_ipc_cleanup_remote_client_info(xprt_info);
1201 msm_ipc_cleanup_routing_table(xprt_info);
1202}
1203
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001204static int process_hello_msg(struct msm_ipc_router_xprt_info *xprt_info,
1205 struct rr_header *hdr)
1206{
1207 int i, rc = 0;
1208 union rr_control_msg ctl;
1209 struct msm_ipc_routing_table_entry *rt_entry;
1210
1211 if (!hdr)
1212 return -EINVAL;
1213
1214 RR("o HELLO NID %d\n", hdr->src_node_id);
1215
1216 xprt_info->remote_node_id = hdr->src_node_id;
1217 /*
1218 * Find the entry from Routing Table corresponding to Node ID.
1219 * Under SSR, an entry will be found. When the system boots up
1220 * for the 1st time, an entry will not be found and hence allocate
1221 * an entry. Update the entry with the Node ID that it corresponds
1222 * to and the XPRT through which it can be reached.
1223 */
1224 mutex_lock(&routing_table_lock);
1225 rt_entry = lookup_routing_table(hdr->src_node_id);
1226 if (!rt_entry) {
1227 rt_entry = alloc_routing_table_entry(hdr->src_node_id);
1228 if (!rt_entry) {
1229 mutex_unlock(&routing_table_lock);
1230 pr_err("%s: rt_entry allocation failed\n", __func__);
1231 return -ENOMEM;
1232 }
1233 add_routing_table_entry(rt_entry);
1234 }
1235 mutex_lock(&rt_entry->lock);
1236 rt_entry->neighbor_node_id = xprt_info->remote_node_id;
1237 rt_entry->xprt_info = xprt_info;
1238 mutex_unlock(&rt_entry->lock);
1239 mutex_unlock(&routing_table_lock);
1240
1241 /* Cleanup any remote ports, if the node is coming out of reset */
1242 msm_ipc_cleanup_remote_port_info(xprt_info->remote_node_id);
1243
1244 /* Send a reply HELLO message */
1245 memset(&ctl, 0, sizeof(ctl));
1246 ctl.cmd = IPC_ROUTER_CTRL_CMD_HELLO;
1247 rc = msm_ipc_router_send_control_msg(xprt_info, &ctl);
1248 if (rc < 0) {
1249 pr_err("%s: Error sending reply HELLO message\n", __func__);
1250 return rc;
1251 }
1252 xprt_info->initialized = 1;
1253
1254 /*
1255 * Send list of servers from the local node and from nodes
1256 * outside the mesh network in which this XPRT is part of.
1257 */
1258 mutex_lock(&routing_table_lock);
1259 for (i = 0; i < RT_HASH_SIZE; i++) {
1260 list_for_each_entry(rt_entry, &routing_table[i], list) {
1261 if ((rt_entry->node_id != IPC_ROUTER_NID_LOCAL) &&
1262 (rt_entry->xprt_info->xprt->link_id ==
1263 xprt_info->xprt->link_id))
1264 continue;
1265 rc = msm_ipc_router_send_server_list(rt_entry->node_id,
1266 xprt_info);
1267 if (rc < 0) {
1268 mutex_unlock(&routing_table_lock);
1269 return rc;
1270 }
1271 }
1272 }
1273 mutex_unlock(&routing_table_lock);
1274 RR("HELLO message processed\n");
1275 return rc;
1276}
1277
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001278static int process_control_msg(struct msm_ipc_router_xprt_info *xprt_info,
1279 struct rr_packet *pkt)
1280{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001281 union rr_control_msg *msg;
1282 struct msm_ipc_router_remote_port *rport_ptr;
1283 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001284 struct sk_buff *temp_ptr;
1285 struct rr_header *hdr;
1286 struct msm_ipc_server *server;
1287 struct msm_ipc_routing_table_entry *rt_entry;
1288
1289 if (pkt->length != (IPC_ROUTER_HDR_SIZE + sizeof(*msg))) {
1290 pr_err("%s: r2r msg size %d != %d\n", __func__, pkt->length,
1291 (IPC_ROUTER_HDR_SIZE + sizeof(*msg)));
1292 return -EINVAL;
1293 }
1294
1295 temp_ptr = skb_peek(pkt->pkt_fragment_q);
Karthikeyan Ramasubramanian9024dd82011-12-19 18:44:19 -07001296 if (!temp_ptr) {
1297 pr_err("%s: pkt_fragment_q is empty\n", __func__);
1298 return -EINVAL;
1299 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001300 hdr = (struct rr_header *)temp_ptr->data;
Karthikeyan Ramasubramanian9024dd82011-12-19 18:44:19 -07001301 if (!hdr) {
1302 pr_err("%s: No data inside the skb\n", __func__);
1303 return -EINVAL;
1304 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001305 msg = (union rr_control_msg *)((char *)hdr + IPC_ROUTER_HDR_SIZE);
1306
1307 switch (msg->cmd) {
1308 case IPC_ROUTER_CTRL_CMD_HELLO:
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001309 rc = process_hello_msg(xprt_info, hdr);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001310 break;
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001311
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001312 case IPC_ROUTER_CTRL_CMD_RESUME_TX:
1313 RR("o RESUME_TX id=%d:%08x\n",
1314 msg->cli.node_id, msg->cli.port_id);
1315
1316 rport_ptr = msm_ipc_router_lookup_remote_port(msg->cli.node_id,
1317 msg->cli.port_id);
1318 if (!rport_ptr) {
1319 pr_err("%s: Unable to resume client\n", __func__);
1320 break;
1321 }
1322 mutex_lock(&rport_ptr->quota_lock);
1323 rport_ptr->tx_quota_cnt = 0;
1324 mutex_unlock(&rport_ptr->quota_lock);
1325 wake_up(&rport_ptr->quota_wait);
1326 break;
1327
1328 case IPC_ROUTER_CTRL_CMD_NEW_SERVER:
1329 if (msg->srv.instance == 0) {
1330 pr_err(
1331 "rpcrouter: Server create rejected, version = 0, "
1332 "service = %08x\n", msg->srv.service);
1333 break;
1334 }
1335
1336 RR("o NEW_SERVER id=%d:%08x service=%08x:%08x\n",
1337 msg->srv.node_id, msg->srv.port_id,
1338 msg->srv.service, msg->srv.instance);
1339
1340 mutex_lock(&routing_table_lock);
1341 rt_entry = lookup_routing_table(msg->srv.node_id);
1342 if (!rt_entry) {
1343 rt_entry = alloc_routing_table_entry(msg->srv.node_id);
1344 if (!rt_entry) {
1345 mutex_unlock(&routing_table_lock);
1346 pr_err("%s: rt_entry allocation failed\n",
1347 __func__);
1348 return -ENOMEM;
1349 }
1350 mutex_lock(&rt_entry->lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001351 rt_entry->neighbor_node_id = xprt_info->remote_node_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001352 rt_entry->xprt_info = xprt_info;
1353 mutex_unlock(&rt_entry->lock);
1354 add_routing_table_entry(rt_entry);
1355 }
1356 mutex_unlock(&routing_table_lock);
1357
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001358 mutex_lock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001359 server = msm_ipc_router_lookup_server(msg->srv.service,
1360 msg->srv.instance,
1361 msg->srv.node_id,
1362 msg->srv.port_id);
1363 if (!server) {
1364 server = msm_ipc_router_create_server(
1365 msg->srv.service, msg->srv.instance,
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001366 msg->srv.node_id, msg->srv.port_id, xprt_info);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001367 if (!server) {
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001368 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001369 pr_err("%s: Server Create failed\n", __func__);
1370 return -ENOMEM;
1371 }
1372
1373 if (!msm_ipc_router_lookup_remote_port(
1374 msg->srv.node_id, msg->srv.port_id)) {
1375 rport_ptr = msm_ipc_router_create_remote_port(
1376 msg->srv.node_id, msg->srv.port_id);
1377 if (!rport_ptr)
1378 pr_err("%s: Remote port create "
1379 "failed\n", __func__);
1380 }
1381 wake_up(&newserver_wait);
1382 }
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001383 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001384
1385 relay_msg(xprt_info, pkt);
1386 post_control_ports(pkt);
1387 break;
1388 case IPC_ROUTER_CTRL_CMD_REMOVE_SERVER:
1389 RR("o REMOVE_SERVER service=%08x:%d\n",
1390 msg->srv.service, msg->srv.instance);
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001391 mutex_lock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001392 server = msm_ipc_router_lookup_server(msg->srv.service,
1393 msg->srv.instance,
1394 msg->srv.node_id,
1395 msg->srv.port_id);
1396 if (server) {
1397 msm_ipc_router_destroy_server(server,
1398 msg->srv.node_id,
1399 msg->srv.port_id);
1400 relay_msg(xprt_info, pkt);
1401 post_control_ports(pkt);
1402 }
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001403 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001404 break;
1405 case IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT:
1406 RR("o REMOVE_CLIENT id=%d:%08x\n",
1407 msg->cli.node_id, msg->cli.port_id);
1408 rport_ptr = msm_ipc_router_lookup_remote_port(msg->cli.node_id,
1409 msg->cli.port_id);
1410 if (rport_ptr)
1411 msm_ipc_router_destroy_remote_port(rport_ptr);
1412
1413 relay_msg(xprt_info, pkt);
1414 post_control_ports(pkt);
1415 break;
1416 case IPC_ROUTER_CTRL_CMD_PING:
1417 /* No action needed for ping messages received */
1418 RR("o PING\n");
1419 break;
1420 default:
1421 RR("o UNKNOWN(%08x)\n", msg->cmd);
1422 rc = -ENOSYS;
1423 }
1424
1425 return rc;
1426}
1427
1428static void do_read_data(struct work_struct *work)
1429{
1430 struct rr_header *hdr;
1431 struct rr_packet *pkt = NULL;
1432 struct msm_ipc_port *port_ptr;
1433 struct sk_buff *head_skb;
1434 struct msm_ipc_port_addr *src_addr;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001435 struct msm_ipc_router_remote_port *rport_ptr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001436 uint32_t resume_tx, resume_tx_node_id, resume_tx_port_id;
1437
1438 struct msm_ipc_router_xprt_info *xprt_info =
1439 container_of(work,
1440 struct msm_ipc_router_xprt_info,
1441 read_data);
1442
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001443 while ((pkt = rr_read(xprt_info)) != NULL) {
1444 if (pkt->length < IPC_ROUTER_HDR_SIZE ||
1445 pkt->length > MAX_IPC_PKT_SIZE) {
1446 pr_err("%s: Invalid pkt length %d\n",
1447 __func__, pkt->length);
1448 goto fail_data;
1449 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001450
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001451 head_skb = skb_peek(pkt->pkt_fragment_q);
1452 if (!head_skb) {
1453 pr_err("%s: head_skb is invalid\n", __func__);
1454 goto fail_data;
1455 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001456
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001457 hdr = (struct rr_header *)(head_skb->data);
1458 RR("- ver=%d type=%d src=%d:%08x crx=%d siz=%d dst=%d:%08x\n",
1459 hdr->version, hdr->type, hdr->src_node_id, hdr->src_port_id,
1460 hdr->confirm_rx, hdr->size, hdr->dst_node_id,
1461 hdr->dst_port_id);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001462
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001463 if (hdr->version != IPC_ROUTER_VERSION) {
1464 pr_err("version %d != %d\n",
1465 hdr->version, IPC_ROUTER_VERSION);
1466 goto fail_data;
1467 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001468
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001469 if ((hdr->dst_node_id != IPC_ROUTER_NID_LOCAL) &&
1470 ((hdr->type == IPC_ROUTER_CTRL_CMD_RESUME_TX) ||
1471 (hdr->type == IPC_ROUTER_CTRL_CMD_DATA))) {
1472 forward_msg(xprt_info, pkt);
1473 release_pkt(pkt);
1474 continue;
1475 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001476
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001477 if ((hdr->dst_port_id == IPC_ROUTER_ADDRESS) ||
1478 (hdr->type == IPC_ROUTER_CTRL_CMD_HELLO)) {
1479 process_control_msg(xprt_info, pkt);
1480 release_pkt(pkt);
1481 continue;
1482 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001483#if defined(CONFIG_MSM_SMD_LOGGING)
1484#if defined(DEBUG)
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001485 if (msm_ipc_router_debug_mask & SMEM_LOG) {
1486 smem_log_event((SMEM_LOG_PROC_ID_APPS |
1487 SMEM_LOG_RPC_ROUTER_EVENT_BASE |
1488 IPC_ROUTER_LOG_EVENT_RX),
1489 (hdr->src_node_id << 24) |
1490 (hdr->src_port_id & 0xffffff),
1491 (hdr->dst_node_id << 24) |
1492 (hdr->dst_port_id & 0xffffff),
1493 (hdr->type << 24) | (hdr->confirm_rx << 16) |
1494 (hdr->size & 0xffff));
1495 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001496#endif
1497#endif
1498
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001499 resume_tx = hdr->confirm_rx;
1500 resume_tx_node_id = hdr->dst_node_id;
1501 resume_tx_port_id = hdr->dst_port_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001502
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001503 rport_ptr = msm_ipc_router_lookup_remote_port(hdr->src_node_id,
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06001504 hdr->src_port_id);
1505
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001506 mutex_lock(&local_ports_lock);
1507 port_ptr = msm_ipc_router_lookup_local_port(hdr->dst_port_id);
1508 if (!port_ptr) {
1509 pr_err("%s: No local port id %08x\n", __func__,
1510 hdr->dst_port_id);
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06001511 mutex_unlock(&local_ports_lock);
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001512 release_pkt(pkt);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001513 goto process_done;
1514 }
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001515
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001516 if (!rport_ptr) {
1517 rport_ptr = msm_ipc_router_create_remote_port(
1518 hdr->src_node_id,
1519 hdr->src_port_id);
1520 if (!rport_ptr) {
1521 pr_err("%s: Rmt Prt %08x:%08x create failed\n",
1522 __func__, hdr->src_node_id,
1523 hdr->src_port_id);
1524 mutex_unlock(&local_ports_lock);
1525 goto process_done;
1526 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001527 }
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001528
1529 if (!port_ptr->notify) {
1530 mutex_lock(&port_ptr->port_rx_q_lock);
1531 wake_lock(&port_ptr->port_rx_wake_lock);
1532 list_add_tail(&pkt->list, &port_ptr->port_rx_q);
1533 wake_up(&port_ptr->port_rx_wait_q);
1534 mutex_unlock(&port_ptr->port_rx_q_lock);
1535 mutex_unlock(&local_ports_lock);
1536 } else {
1537 mutex_lock(&port_ptr->port_rx_q_lock);
1538 src_addr = kmalloc(sizeof(struct msm_ipc_port_addr),
1539 GFP_KERNEL);
1540 if (src_addr) {
1541 src_addr->node_id = hdr->src_node_id;
1542 src_addr->port_id = hdr->src_port_id;
1543 }
1544 skb_pull(head_skb, IPC_ROUTER_HDR_SIZE);
1545 mutex_unlock(&local_ports_lock);
1546 port_ptr->notify(MSM_IPC_ROUTER_READ_CB,
1547 pkt->pkt_fragment_q, src_addr, port_ptr->priv);
1548 mutex_unlock(&port_ptr->port_rx_q_lock);
1549 pkt->pkt_fragment_q = NULL;
1550 src_addr = NULL;
1551 release_pkt(pkt);
1552 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001553
1554process_done:
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001555 if (resume_tx) {
1556 union rr_control_msg msg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001557
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001558 msg.cmd = IPC_ROUTER_CTRL_CMD_RESUME_TX;
1559 msg.cli.node_id = resume_tx_node_id;
1560 msg.cli.port_id = resume_tx_port_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001561
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06001562 RR("x RESUME_TX id=%d:%08x\n",
1563 msg.cli.node_id, msg.cli.port_id);
1564 msm_ipc_router_send_control_msg(xprt_info, &msg);
1565 }
1566
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001567 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001568 return;
1569
1570fail_data:
1571 release_pkt(pkt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001572 pr_err("ipc_router has died\n");
1573}
1574
1575int msm_ipc_router_register_server(struct msm_ipc_port *port_ptr,
1576 struct msm_ipc_addr *name)
1577{
1578 struct msm_ipc_server *server;
1579 unsigned long flags;
1580 union rr_control_msg ctl;
1581
1582 if (!port_ptr || !name)
1583 return -EINVAL;
1584
1585 if (name->addrtype != MSM_IPC_ADDR_NAME)
1586 return -EINVAL;
1587
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001588 mutex_lock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001589 server = msm_ipc_router_lookup_server(name->addr.port_name.service,
1590 name->addr.port_name.instance,
1591 IPC_ROUTER_NID_LOCAL,
1592 port_ptr->this_port.port_id);
1593 if (server) {
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001594 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001595 pr_err("%s: Server already present\n", __func__);
1596 return -EINVAL;
1597 }
1598
1599 server = msm_ipc_router_create_server(name->addr.port_name.service,
1600 name->addr.port_name.instance,
1601 IPC_ROUTER_NID_LOCAL,
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001602 port_ptr->this_port.port_id,
1603 NULL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001604 if (!server) {
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001605 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001606 pr_err("%s: Server Creation failed\n", __func__);
1607 return -EINVAL;
1608 }
1609
1610 ctl.cmd = IPC_ROUTER_CTRL_CMD_NEW_SERVER;
1611 ctl.srv.service = server->name.service;
1612 ctl.srv.instance = server->name.instance;
1613 ctl.srv.node_id = IPC_ROUTER_NID_LOCAL;
1614 ctl.srv.port_id = port_ptr->this_port.port_id;
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001615 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001616 broadcast_ctl_msg(&ctl);
1617 spin_lock_irqsave(&port_ptr->port_lock, flags);
1618 port_ptr->type = SERVER_PORT;
1619 port_ptr->port_name.service = server->name.service;
1620 port_ptr->port_name.instance = server->name.instance;
1621 spin_unlock_irqrestore(&port_ptr->port_lock, flags);
1622 return 0;
1623}
1624
1625int msm_ipc_router_unregister_server(struct msm_ipc_port *port_ptr)
1626{
1627 struct msm_ipc_server *server;
1628 unsigned long flags;
1629 union rr_control_msg ctl;
1630
1631 if (!port_ptr)
1632 return -EINVAL;
1633
1634 if (port_ptr->type != SERVER_PORT) {
1635 pr_err("%s: Trying to unregister a non-server port\n",
1636 __func__);
1637 return -EINVAL;
1638 }
1639
1640 if (port_ptr->this_port.node_id != IPC_ROUTER_NID_LOCAL) {
1641 pr_err("%s: Trying to unregister a remote server locally\n",
1642 __func__);
1643 return -EINVAL;
1644 }
1645
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001646 mutex_lock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001647 server = msm_ipc_router_lookup_server(port_ptr->port_name.service,
1648 port_ptr->port_name.instance,
1649 port_ptr->this_port.node_id,
1650 port_ptr->this_port.port_id);
1651 if (!server) {
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001652 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001653 pr_err("%s: Server lookup failed\n", __func__);
1654 return -ENODEV;
1655 }
1656
1657 ctl.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_SERVER;
1658 ctl.srv.service = server->name.service;
1659 ctl.srv.instance = server->name.instance;
1660 ctl.srv.node_id = IPC_ROUTER_NID_LOCAL;
1661 ctl.srv.port_id = port_ptr->this_port.port_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001662 msm_ipc_router_destroy_server(server, port_ptr->this_port.node_id,
1663 port_ptr->this_port.port_id);
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001664 mutex_unlock(&server_list_lock);
1665 broadcast_ctl_msg(&ctl);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001666 spin_lock_irqsave(&port_ptr->port_lock, flags);
1667 port_ptr->type = CLIENT_PORT;
1668 spin_unlock_irqrestore(&port_ptr->port_lock, flags);
1669 return 0;
1670}
1671
1672static int loopback_data(struct msm_ipc_port *src,
1673 uint32_t port_id,
1674 struct sk_buff_head *data)
1675{
1676 struct sk_buff *head_skb;
1677 struct rr_header *hdr;
1678 struct msm_ipc_port *port_ptr;
1679 struct rr_packet *pkt;
1680
1681 if (!data) {
1682 pr_err("%s: Invalid pkt pointer\n", __func__);
1683 return -EINVAL;
1684 }
1685
1686 pkt = create_pkt(data);
1687 if (!pkt) {
1688 pr_err("%s: New pkt create failed\n", __func__);
1689 return -ENOMEM;
1690 }
1691
1692 head_skb = skb_peek(pkt->pkt_fragment_q);
Karthikeyan Ramasubramanian9024dd82011-12-19 18:44:19 -07001693 if (!head_skb) {
1694 pr_err("%s: pkt_fragment_q is empty\n", __func__);
1695 return -EINVAL;
1696 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001697 hdr = (struct rr_header *)skb_push(head_skb, IPC_ROUTER_HDR_SIZE);
1698 if (!hdr) {
1699 pr_err("%s: Prepend Header failed\n", __func__);
1700 release_pkt(pkt);
1701 return -ENOMEM;
1702 }
1703 hdr->version = IPC_ROUTER_VERSION;
1704 hdr->type = IPC_ROUTER_CTRL_CMD_DATA;
1705 hdr->src_node_id = src->this_port.node_id;
1706 hdr->src_port_id = src->this_port.port_id;
1707 hdr->size = pkt->length;
1708 hdr->confirm_rx = 0;
1709 hdr->dst_node_id = IPC_ROUTER_NID_LOCAL;
1710 hdr->dst_port_id = port_id;
1711 pkt->length += IPC_ROUTER_HDR_SIZE;
1712
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06001713 mutex_lock(&local_ports_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001714 port_ptr = msm_ipc_router_lookup_local_port(port_id);
1715 if (!port_ptr) {
1716 pr_err("%s: Local port %d not present\n", __func__, port_id);
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06001717 mutex_unlock(&local_ports_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001718 release_pkt(pkt);
1719 return -ENODEV;
1720 }
1721
1722 mutex_lock(&port_ptr->port_rx_q_lock);
1723 wake_lock(&port_ptr->port_rx_wake_lock);
1724 list_add_tail(&pkt->list, &port_ptr->port_rx_q);
1725 wake_up(&port_ptr->port_rx_wait_q);
1726 mutex_unlock(&port_ptr->port_rx_q_lock);
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06001727 mutex_unlock(&local_ports_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001728
1729 return pkt->length;
1730}
1731
1732static int msm_ipc_router_write_pkt(struct msm_ipc_port *src,
1733 struct msm_ipc_router_remote_port *rport_ptr,
1734 struct rr_packet *pkt)
1735{
1736 struct sk_buff *head_skb;
1737 struct rr_header *hdr;
1738 struct msm_ipc_router_xprt_info *xprt_info;
1739 struct msm_ipc_routing_table_entry *rt_entry;
1740 int ret;
1741 DEFINE_WAIT(__wait);
1742
1743 if (!rport_ptr || !src || !pkt)
1744 return -EINVAL;
1745
1746 head_skb = skb_peek(pkt->pkt_fragment_q);
Karthikeyan Ramasubramanian9024dd82011-12-19 18:44:19 -07001747 if (!head_skb) {
1748 pr_err("%s: pkt_fragment_q is empty\n", __func__);
1749 return -EINVAL;
1750 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001751 hdr = (struct rr_header *)skb_push(head_skb, IPC_ROUTER_HDR_SIZE);
1752 if (!hdr) {
1753 pr_err("%s: Prepend Header failed\n", __func__);
1754 return -ENOMEM;
1755 }
1756 hdr->version = IPC_ROUTER_VERSION;
1757 hdr->type = IPC_ROUTER_CTRL_CMD_DATA;
1758 hdr->src_node_id = src->this_port.node_id;
1759 hdr->src_port_id = src->this_port.port_id;
1760 hdr->size = pkt->length;
1761 hdr->confirm_rx = 0;
1762 hdr->dst_node_id = rport_ptr->node_id;
1763 hdr->dst_port_id = rport_ptr->port_id;
1764 pkt->length += IPC_ROUTER_HDR_SIZE;
1765
1766 for (;;) {
1767 prepare_to_wait(&rport_ptr->quota_wait, &__wait,
1768 TASK_INTERRUPTIBLE);
1769 mutex_lock(&rport_ptr->quota_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001770 if (rport_ptr->restart_state != RESTART_NORMAL)
1771 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001772 if (rport_ptr->tx_quota_cnt <
1773 IPC_ROUTER_DEFAULT_RX_QUOTA)
1774 break;
1775 if (signal_pending(current))
1776 break;
1777 mutex_unlock(&rport_ptr->quota_lock);
1778 schedule();
1779 }
1780 finish_wait(&rport_ptr->quota_wait, &__wait);
1781
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001782 if (rport_ptr->restart_state != RESTART_NORMAL) {
1783 mutex_unlock(&rport_ptr->quota_lock);
1784 return -ENETRESET;
1785 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001786 if (signal_pending(current)) {
1787 mutex_unlock(&rport_ptr->quota_lock);
1788 return -ERESTARTSYS;
1789 }
1790 rport_ptr->tx_quota_cnt++;
1791 if (rport_ptr->tx_quota_cnt == IPC_ROUTER_DEFAULT_RX_QUOTA)
1792 hdr->confirm_rx = 1;
1793 mutex_unlock(&rport_ptr->quota_lock);
1794
1795 mutex_lock(&routing_table_lock);
1796 rt_entry = lookup_routing_table(hdr->dst_node_id);
1797 if (!rt_entry || !rt_entry->xprt_info) {
1798 mutex_unlock(&routing_table_lock);
1799 pr_err("%s: Remote node %d not up\n",
1800 __func__, hdr->dst_node_id);
1801 return -ENODEV;
1802 }
1803 mutex_lock(&rt_entry->lock);
1804 xprt_info = rt_entry->xprt_info;
1805 mutex_lock(&xprt_info->tx_lock);
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -07001806 ret = xprt_info->xprt->write(pkt, pkt->length, xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001807 mutex_unlock(&xprt_info->tx_lock);
1808 mutex_unlock(&rt_entry->lock);
1809 mutex_unlock(&routing_table_lock);
1810
1811 if (ret < 0) {
1812 pr_err("%s: Write on XPRT failed\n", __func__);
1813 return ret;
1814 }
1815
1816 RAW_HDR("[w rr_h] "
1817 "ver=%i,type=%s,src_nid=%08x,src_port_id=%08x,"
1818 "confirm_rx=%i,size=%3i,dst_pid=%08x,dst_cid=%08x\n",
1819 hdr->version, type_to_str(hdr->type),
1820 hdr->src_node_id, hdr->src_port_id,
1821 hdr->confirm_rx, hdr->size,
1822 hdr->dst_node_id, hdr->dst_port_id);
1823
1824#if defined(CONFIG_MSM_SMD_LOGGING)
1825#if defined(DEBUG)
1826 if (msm_ipc_router_debug_mask & SMEM_LOG) {
1827 smem_log_event((SMEM_LOG_PROC_ID_APPS |
1828 SMEM_LOG_RPC_ROUTER_EVENT_BASE |
1829 IPC_ROUTER_LOG_EVENT_TX),
1830 (hdr->src_node_id << 24) |
1831 (hdr->src_port_id & 0xffffff),
1832 (hdr->dst_node_id << 24) |
1833 (hdr->dst_port_id & 0xffffff),
1834 (hdr->type << 24) | (hdr->confirm_rx << 16) |
1835 (hdr->size & 0xffff));
1836 }
1837#endif
1838#endif
1839
1840 return pkt->length;
1841}
1842
1843int msm_ipc_router_send_to(struct msm_ipc_port *src,
1844 struct sk_buff_head *data,
1845 struct msm_ipc_addr *dest)
1846{
1847 uint32_t dst_node_id = 0, dst_port_id = 0;
1848 struct msm_ipc_server *server;
1849 struct msm_ipc_server_port *server_port;
1850 struct msm_ipc_router_remote_port *rport_ptr = NULL;
1851 struct rr_packet *pkt;
1852 int ret;
1853
1854 if (!src || !data || !dest) {
1855 pr_err("%s: Invalid Parameters\n", __func__);
1856 return -EINVAL;
1857 }
1858
1859 /* Resolve Address*/
1860 if (dest->addrtype == MSM_IPC_ADDR_ID) {
1861 dst_node_id = dest->addr.port_addr.node_id;
1862 dst_port_id = dest->addr.port_addr.port_id;
1863 } else if (dest->addrtype == MSM_IPC_ADDR_NAME) {
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001864 mutex_lock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001865 server = msm_ipc_router_lookup_server(
1866 dest->addr.port_name.service,
1867 dest->addr.port_name.instance,
1868 0, 0);
1869 if (!server) {
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001870 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001871 pr_err("%s: Destination not reachable\n", __func__);
1872 return -ENODEV;
1873 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001874 server_port = list_first_entry(&server->server_port_list,
1875 struct msm_ipc_server_port,
1876 list);
1877 dst_node_id = server_port->server_addr.node_id;
1878 dst_port_id = server_port->server_addr.port_id;
1879 mutex_unlock(&server_list_lock);
1880 }
1881 if (dst_node_id == IPC_ROUTER_NID_LOCAL) {
1882 ret = loopback_data(src, dst_port_id, data);
1883 return ret;
1884 }
1885
1886 /* Achieve Flow control */
1887 rport_ptr = msm_ipc_router_lookup_remote_port(dst_node_id,
1888 dst_port_id);
1889 if (!rport_ptr) {
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001890 pr_err("%s: Could not create remote port\n", __func__);
1891 return -ENOMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001892 }
1893
1894 pkt = create_pkt(data);
1895 if (!pkt) {
1896 pr_err("%s: Pkt creation failed\n", __func__);
1897 return -ENOMEM;
1898 }
1899
1900 ret = msm_ipc_router_write_pkt(src, rport_ptr, pkt);
1901 release_pkt(pkt);
1902
1903 return ret;
1904}
1905
1906int msm_ipc_router_read(struct msm_ipc_port *port_ptr,
1907 struct sk_buff_head **data,
1908 size_t buf_len)
1909{
1910 struct rr_packet *pkt;
1911 int ret;
1912
1913 if (!port_ptr || !data)
1914 return -EINVAL;
1915
1916 mutex_lock(&port_ptr->port_rx_q_lock);
1917 if (list_empty(&port_ptr->port_rx_q)) {
1918 mutex_unlock(&port_ptr->port_rx_q_lock);
1919 return -EAGAIN;
1920 }
1921
1922 pkt = list_first_entry(&port_ptr->port_rx_q, struct rr_packet, list);
1923 if ((buf_len) && ((pkt->length - IPC_ROUTER_HDR_SIZE) > buf_len)) {
1924 mutex_unlock(&port_ptr->port_rx_q_lock);
1925 return -ETOOSMALL;
1926 }
1927 list_del(&pkt->list);
1928 if (list_empty(&port_ptr->port_rx_q))
1929 wake_unlock(&port_ptr->port_rx_wake_lock);
1930 *data = pkt->pkt_fragment_q;
1931 ret = pkt->length;
1932 kfree(pkt);
1933 mutex_unlock(&port_ptr->port_rx_q_lock);
1934
1935 return ret;
1936}
1937
1938int msm_ipc_router_recv_from(struct msm_ipc_port *port_ptr,
1939 struct sk_buff_head **data,
1940 struct msm_ipc_addr *src,
1941 unsigned long timeout)
1942{
1943 int ret, data_len, align_size;
1944 struct sk_buff *temp_skb;
1945 struct rr_header *hdr = NULL;
1946
1947 if (!port_ptr || !data) {
1948 pr_err("%s: Invalid pointers being passed\n", __func__);
1949 return -EINVAL;
1950 }
1951
1952 *data = NULL;
1953 mutex_lock(&port_ptr->port_rx_q_lock);
1954 while (list_empty(&port_ptr->port_rx_q)) {
1955 mutex_unlock(&port_ptr->port_rx_q_lock);
1956 if (timeout < 0) {
1957 ret = wait_event_interruptible(
1958 port_ptr->port_rx_wait_q,
1959 !list_empty(&port_ptr->port_rx_q));
1960 if (ret)
1961 return ret;
1962 } else if (timeout > 0) {
1963 timeout = wait_event_interruptible_timeout(
1964 port_ptr->port_rx_wait_q,
1965 !list_empty(&port_ptr->port_rx_q),
1966 timeout);
1967 if (timeout < 0)
1968 return -EFAULT;
1969 }
1970 if (timeout == 0)
1971 return -ETIMEDOUT;
1972 mutex_lock(&port_ptr->port_rx_q_lock);
1973 }
1974 mutex_unlock(&port_ptr->port_rx_q_lock);
1975
1976 ret = msm_ipc_router_read(port_ptr, data, 0);
1977 if (ret <= 0 || !(*data))
1978 return ret;
1979
1980 temp_skb = skb_peek(*data);
1981 hdr = (struct rr_header *)(temp_skb->data);
1982 if (src) {
1983 src->addrtype = MSM_IPC_ADDR_ID;
1984 src->addr.port_addr.node_id = hdr->src_node_id;
1985 src->addr.port_addr.port_id = hdr->src_port_id;
1986 }
1987
1988 data_len = hdr->size;
1989 skb_pull(temp_skb, IPC_ROUTER_HDR_SIZE);
1990 align_size = ALIGN_SIZE(data_len);
1991 if (align_size) {
1992 temp_skb = skb_peek_tail(*data);
1993 skb_trim(temp_skb, (temp_skb->len - align_size));
1994 }
1995 return data_len;
1996}
1997
1998struct msm_ipc_port *msm_ipc_router_create_port(
1999 void (*notify)(unsigned event, void *data, void *addr, void *priv),
2000 void *priv)
2001{
2002 struct msm_ipc_port *port_ptr;
2003
2004 port_ptr = msm_ipc_router_create_raw_port(NULL, notify, priv);
2005 if (!port_ptr)
2006 pr_err("%s: port_ptr alloc failed\n", __func__);
2007
2008 return port_ptr;
2009}
2010
2011int msm_ipc_router_close_port(struct msm_ipc_port *port_ptr)
2012{
2013 union rr_control_msg msg;
2014 struct rr_packet *pkt, *temp_pkt;
2015 struct msm_ipc_server *server;
2016
2017 if (!port_ptr)
2018 return -EINVAL;
2019
2020 if (port_ptr->type == SERVER_PORT || port_ptr->type == CLIENT_PORT) {
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06002021 mutex_lock(&local_ports_lock);
2022 list_del(&port_ptr->list);
2023 mutex_unlock(&local_ports_lock);
2024
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002025 if (port_ptr->type == SERVER_PORT) {
2026 msg.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_SERVER;
2027 msg.srv.service = port_ptr->port_name.service;
2028 msg.srv.instance = port_ptr->port_name.instance;
2029 msg.srv.node_id = port_ptr->this_port.node_id;
2030 msg.srv.port_id = port_ptr->this_port.port_id;
2031 RR("x REMOVE_SERVER Name=%d:%08x Id=%d:%08x\n",
2032 msg.srv.service, msg.srv.instance,
2033 msg.srv.node_id, msg.srv.port_id);
2034 } else if (port_ptr->type == CLIENT_PORT) {
2035 msg.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT;
2036 msg.cli.node_id = port_ptr->this_port.node_id;
2037 msg.cli.port_id = port_ptr->this_port.port_id;
2038 RR("x REMOVE_CLIENT id=%d:%08x\n",
2039 msg.cli.node_id, msg.cli.port_id);
2040 }
2041 broadcast_ctl_msg(&msg);
2042 broadcast_ctl_msg_locally(&msg);
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06002043 } else if (port_ptr->type == CONTROL_PORT) {
2044 mutex_lock(&control_ports_lock);
2045 list_del(&port_ptr->list);
2046 mutex_unlock(&control_ports_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002047 }
2048
2049 mutex_lock(&port_ptr->port_rx_q_lock);
2050 list_for_each_entry_safe(pkt, temp_pkt, &port_ptr->port_rx_q, list) {
2051 list_del(&pkt->list);
2052 release_pkt(pkt);
2053 }
2054 mutex_unlock(&port_ptr->port_rx_q_lock);
2055
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002056 if (port_ptr->type == SERVER_PORT) {
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002057 mutex_lock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002058 server = msm_ipc_router_lookup_server(
2059 port_ptr->port_name.service,
2060 port_ptr->port_name.instance,
2061 port_ptr->this_port.node_id,
2062 port_ptr->this_port.port_id);
2063 if (server)
2064 msm_ipc_router_destroy_server(server,
2065 port_ptr->this_port.node_id,
2066 port_ptr->this_port.port_id);
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002067 mutex_unlock(&server_list_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002068 }
2069
Karthikeyan Ramasubramaniandd8c3b52011-11-30 16:26:12 -07002070 wake_lock_destroy(&port_ptr->port_rx_wake_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002071 kfree(port_ptr);
2072 return 0;
2073}
2074
2075int msm_ipc_router_get_curr_pkt_size(struct msm_ipc_port *port_ptr)
2076{
2077 struct rr_packet *pkt;
2078 int rc = 0;
2079
2080 if (!port_ptr)
2081 return -EINVAL;
2082
2083 mutex_lock(&port_ptr->port_rx_q_lock);
2084 if (!list_empty(&port_ptr->port_rx_q)) {
2085 pkt = list_first_entry(&port_ptr->port_rx_q,
2086 struct rr_packet, list);
2087 rc = pkt->length;
2088 }
2089 mutex_unlock(&port_ptr->port_rx_q_lock);
2090
2091 return rc;
2092}
2093
2094int msm_ipc_router_bind_control_port(struct msm_ipc_port *port_ptr)
2095{
2096 if (!port_ptr)
2097 return -EINVAL;
2098
2099 mutex_lock(&local_ports_lock);
2100 list_del(&port_ptr->list);
2101 mutex_unlock(&local_ports_lock);
2102 port_ptr->type = CONTROL_PORT;
2103 mutex_lock(&control_ports_lock);
2104 list_add_tail(&port_ptr->list, &control_ports);
2105 mutex_unlock(&control_ports_lock);
2106
2107 return 0;
2108}
2109
2110int msm_ipc_router_lookup_server_name(struct msm_ipc_port_name *srv_name,
Karthikeyan Ramasubramaniandfde01b2012-06-12 14:25:13 -06002111 struct msm_ipc_server_info *srv_info,
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002112 int num_entries_in_array,
2113 uint32_t lookup_mask)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002114{
2115 struct msm_ipc_server *server;
2116 struct msm_ipc_server_port *server_port;
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002117 int key, i = 0; /*num_entries_found*/
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002118
2119 if (!srv_name) {
2120 pr_err("%s: Invalid srv_name\n", __func__);
2121 return -EINVAL;
2122 }
2123
Karthikeyan Ramasubramaniandfde01b2012-06-12 14:25:13 -06002124 if (num_entries_in_array && !srv_info) {
2125 pr_err("%s: srv_info NULL\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002126 return -EINVAL;
2127 }
2128
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002129 mutex_lock(&server_list_lock);
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002130 if (!lookup_mask)
2131 lookup_mask = 0xFFFFFFFF;
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002132 key = (srv_name->service & (SRV_HASH_SIZE - 1));
2133 list_for_each_entry(server, &server_list[key], list) {
2134 if ((server->name.service != srv_name->service) ||
2135 ((server->name.instance & lookup_mask) !=
2136 srv_name->instance))
2137 continue;
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002138
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002139 list_for_each_entry(server_port,
2140 &server->server_port_list, list) {
2141 if (i < num_entries_in_array) {
2142 srv_info[i].node_id =
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002143 server_port->server_addr.node_id;
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002144 srv_info[i].port_id =
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002145 server_port->server_addr.port_id;
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002146 srv_info[i].service = server->name.service;
2147 srv_info[i].instance = server->name.instance;
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002148 }
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002149 i++;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002150 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002151 }
2152 mutex_unlock(&server_list_lock);
2153
2154 return i;
2155}
2156
2157int msm_ipc_router_close(void)
2158{
2159 struct msm_ipc_router_xprt_info *xprt_info, *tmp_xprt_info;
2160
2161 mutex_lock(&xprt_info_list_lock);
2162 list_for_each_entry_safe(xprt_info, tmp_xprt_info,
2163 &xprt_info_list, list) {
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -07002164 xprt_info->xprt->close(xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002165 list_del(&xprt_info->list);
2166 kfree(xprt_info);
2167 }
2168 mutex_unlock(&xprt_info_list_lock);
2169 return 0;
2170}
2171
2172#if defined(CONFIG_DEBUG_FS)
2173static int dump_routing_table(char *buf, int max)
2174{
2175 int i = 0, j;
2176 struct msm_ipc_routing_table_entry *rt_entry;
2177
2178 for (j = 0; j < RT_HASH_SIZE; j++) {
2179 mutex_lock(&routing_table_lock);
2180 list_for_each_entry(rt_entry, &routing_table[j], list) {
2181 mutex_lock(&rt_entry->lock);
2182 i += scnprintf(buf + i, max - i,
2183 "Node Id: 0x%08x\n", rt_entry->node_id);
Karthikeyan Ramasubramanianc1a4e3a2012-09-10 16:10:24 -06002184 if (rt_entry->node_id == IPC_ROUTER_NID_LOCAL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002185 i += scnprintf(buf + i, max - i,
2186 "XPRT Name: Loopback\n");
2187 i += scnprintf(buf + i, max - i,
2188 "Next Hop: %d\n", rt_entry->node_id);
2189 } else {
2190 i += scnprintf(buf + i, max - i,
2191 "XPRT Name: %s\n",
2192 rt_entry->xprt_info->xprt->name);
2193 i += scnprintf(buf + i, max - i,
2194 "Next Hop: 0x%08x\n",
2195 rt_entry->xprt_info->remote_node_id);
2196 }
2197 i += scnprintf(buf + i, max - i, "\n");
2198 mutex_unlock(&rt_entry->lock);
2199 }
2200 mutex_unlock(&routing_table_lock);
2201 }
2202
2203 return i;
2204}
2205
2206static int dump_xprt_info(char *buf, int max)
2207{
2208 int i = 0;
2209 struct msm_ipc_router_xprt_info *xprt_info;
2210
2211 mutex_lock(&xprt_info_list_lock);
2212 list_for_each_entry(xprt_info, &xprt_info_list, list) {
2213 i += scnprintf(buf + i, max - i, "XPRT Name: %s\n",
2214 xprt_info->xprt->name);
2215 i += scnprintf(buf + i, max - i, "Link Id: %d\n",
2216 xprt_info->xprt->link_id);
2217 i += scnprintf(buf + i, max - i, "Initialized: %s\n",
2218 (xprt_info->initialized ? "Y" : "N"));
2219 i += scnprintf(buf + i, max - i, "Remote Node Id: 0x%08x\n",
2220 xprt_info->remote_node_id);
2221 i += scnprintf(buf + i, max - i, "\n");
2222 }
2223 mutex_unlock(&xprt_info_list_lock);
2224
2225 return i;
2226}
2227
2228static int dump_servers(char *buf, int max)
2229{
2230 int i = 0, j;
2231 struct msm_ipc_server *server;
2232 struct msm_ipc_server_port *server_port;
2233
2234 mutex_lock(&server_list_lock);
2235 for (j = 0; j < SRV_HASH_SIZE; j++) {
2236 list_for_each_entry(server, &server_list[j], list) {
2237 list_for_each_entry(server_port,
2238 &server->server_port_list,
2239 list) {
2240 i += scnprintf(buf + i, max - i, "Service: "
2241 "0x%08x\n", server->name.service);
2242 i += scnprintf(buf + i, max - i, "Instance: "
2243 "0x%08x\n", server->name.instance);
2244 i += scnprintf(buf + i, max - i,
2245 "Node_id: 0x%08x\n",
2246 server_port->server_addr.node_id);
2247 i += scnprintf(buf + i, max - i,
2248 "Port_id: 0x%08x\n",
2249 server_port->server_addr.port_id);
2250 i += scnprintf(buf + i, max - i, "\n");
2251 }
2252 }
2253 }
2254 mutex_unlock(&server_list_lock);
2255
2256 return i;
2257}
2258
2259static int dump_remote_ports(char *buf, int max)
2260{
2261 int i = 0, j, k;
2262 struct msm_ipc_router_remote_port *rport_ptr;
2263 struct msm_ipc_routing_table_entry *rt_entry;
2264
2265 for (j = 0; j < RT_HASH_SIZE; j++) {
2266 mutex_lock(&routing_table_lock);
2267 list_for_each_entry(rt_entry, &routing_table[j], list) {
2268 mutex_lock(&rt_entry->lock);
2269 for (k = 0; k < RP_HASH_SIZE; k++) {
2270 list_for_each_entry(rport_ptr,
2271 &rt_entry->remote_port_list[k],
2272 list) {
2273 i += scnprintf(buf + i, max - i,
2274 "Node_id: 0x%08x\n",
2275 rport_ptr->node_id);
2276 i += scnprintf(buf + i, max - i,
2277 "Port_id: 0x%08x\n",
2278 rport_ptr->port_id);
2279 i += scnprintf(buf + i, max - i,
2280 "Quota_cnt: %d\n",
2281 rport_ptr->tx_quota_cnt);
2282 i += scnprintf(buf + i, max - i, "\n");
2283 }
2284 }
2285 mutex_unlock(&rt_entry->lock);
2286 }
2287 mutex_unlock(&routing_table_lock);
2288 }
2289
2290 return i;
2291}
2292
2293static int dump_control_ports(char *buf, int max)
2294{
2295 int i = 0;
2296 struct msm_ipc_port *port_ptr;
2297
2298 mutex_lock(&control_ports_lock);
2299 list_for_each_entry(port_ptr, &control_ports, list) {
2300 i += scnprintf(buf + i, max - i, "Node_id: 0x%08x\n",
2301 port_ptr->this_port.node_id);
2302 i += scnprintf(buf + i, max - i, "Port_id: 0x%08x\n",
2303 port_ptr->this_port.port_id);
2304 i += scnprintf(buf + i, max - i, "\n");
2305 }
2306 mutex_unlock(&control_ports_lock);
2307
2308 return i;
2309}
2310
2311static int dump_local_ports(char *buf, int max)
2312{
2313 int i = 0, j;
2314 unsigned long flags;
2315 struct msm_ipc_port *port_ptr;
2316
2317 mutex_lock(&local_ports_lock);
2318 for (j = 0; j < LP_HASH_SIZE; j++) {
2319 list_for_each_entry(port_ptr, &local_ports[j], list) {
2320 spin_lock_irqsave(&port_ptr->port_lock, flags);
2321 i += scnprintf(buf + i, max - i, "Node_id: 0x%08x\n",
2322 port_ptr->this_port.node_id);
2323 i += scnprintf(buf + i, max - i, "Port_id: 0x%08x\n",
2324 port_ptr->this_port.port_id);
2325 i += scnprintf(buf + i, max - i, "# pkts tx'd %d\n",
2326 port_ptr->num_tx);
2327 i += scnprintf(buf + i, max - i, "# pkts rx'd %d\n",
2328 port_ptr->num_rx);
2329 i += scnprintf(buf + i, max - i, "# bytes tx'd %ld\n",
2330 port_ptr->num_tx_bytes);
2331 i += scnprintf(buf + i, max - i, "# bytes rx'd %ld\n",
2332 port_ptr->num_rx_bytes);
2333 spin_unlock_irqrestore(&port_ptr->port_lock, flags);
2334 i += scnprintf(buf + i, max - i, "\n");
2335 }
2336 }
2337 mutex_unlock(&local_ports_lock);
2338
2339 return i;
2340}
2341
2342#define DEBUG_BUFMAX 4096
2343static char debug_buffer[DEBUG_BUFMAX];
2344
2345static ssize_t debug_read(struct file *file, char __user *buf,
2346 size_t count, loff_t *ppos)
2347{
2348 int (*fill)(char *buf, int max) = file->private_data;
2349 int bsize = fill(debug_buffer, DEBUG_BUFMAX);
2350 return simple_read_from_buffer(buf, count, ppos, debug_buffer, bsize);
2351}
2352
2353static int debug_open(struct inode *inode, struct file *file)
2354{
2355 file->private_data = inode->i_private;
2356 return 0;
2357}
2358
2359static const struct file_operations debug_ops = {
2360 .read = debug_read,
2361 .open = debug_open,
2362};
2363
2364static void debug_create(const char *name, mode_t mode,
2365 struct dentry *dent,
2366 int (*fill)(char *buf, int max))
2367{
2368 debugfs_create_file(name, mode, dent, fill, &debug_ops);
2369}
2370
2371static void debugfs_init(void)
2372{
2373 struct dentry *dent;
2374
2375 dent = debugfs_create_dir("msm_ipc_router", 0);
2376 if (IS_ERR(dent))
2377 return;
2378
2379 debug_create("dump_local_ports", 0444, dent,
2380 dump_local_ports);
2381 debug_create("dump_remote_ports", 0444, dent,
2382 dump_remote_ports);
2383 debug_create("dump_control_ports", 0444, dent,
2384 dump_control_ports);
2385 debug_create("dump_servers", 0444, dent,
2386 dump_servers);
2387 debug_create("dump_xprt_info", 0444, dent,
2388 dump_xprt_info);
2389 debug_create("dump_routing_table", 0444, dent,
2390 dump_routing_table);
2391}
2392
2393#else
2394static void debugfs_init(void) {}
2395#endif
2396
2397static int msm_ipc_router_add_xprt(struct msm_ipc_router_xprt *xprt)
2398{
2399 struct msm_ipc_router_xprt_info *xprt_info;
2400 struct msm_ipc_routing_table_entry *rt_entry;
2401
2402 xprt_info = kmalloc(sizeof(struct msm_ipc_router_xprt_info),
2403 GFP_KERNEL);
2404 if (!xprt_info)
2405 return -ENOMEM;
2406
2407 xprt_info->xprt = xprt;
2408 xprt_info->initialized = 0;
2409 xprt_info->remote_node_id = -1;
2410 INIT_LIST_HEAD(&xprt_info->pkt_list);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002411 mutex_init(&xprt_info->rx_lock);
2412 mutex_init(&xprt_info->tx_lock);
2413 wake_lock_init(&xprt_info->wakelock,
2414 WAKE_LOCK_SUSPEND, xprt->name);
2415 xprt_info->need_len = 0;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002416 xprt_info->abort_data_read = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002417 INIT_WORK(&xprt_info->read_data, do_read_data);
2418 INIT_LIST_HEAD(&xprt_info->list);
2419
2420 xprt_info->workqueue = create_singlethread_workqueue(xprt->name);
2421 if (!xprt_info->workqueue) {
2422 kfree(xprt_info);
2423 return -ENOMEM;
2424 }
2425
2426 if (!strcmp(xprt->name, "msm_ipc_router_loopback_xprt")) {
2427 xprt_info->remote_node_id = IPC_ROUTER_NID_LOCAL;
2428 xprt_info->initialized = 1;
2429 }
2430
2431 mutex_lock(&xprt_info_list_lock);
2432 list_add_tail(&xprt_info->list, &xprt_info_list);
2433 mutex_unlock(&xprt_info_list_lock);
2434
2435 mutex_lock(&routing_table_lock);
2436 if (!routing_table_inited) {
2437 init_routing_table();
2438 rt_entry = alloc_routing_table_entry(IPC_ROUTER_NID_LOCAL);
2439 add_routing_table_entry(rt_entry);
2440 routing_table_inited = 1;
2441 }
2442 mutex_unlock(&routing_table_lock);
2443
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002444 xprt->priv = xprt_info;
2445
2446 return 0;
2447}
2448
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002449static void msm_ipc_router_remove_xprt(struct msm_ipc_router_xprt *xprt)
2450{
2451 struct msm_ipc_router_xprt_info *xprt_info;
2452
2453 if (xprt && xprt->priv) {
2454 xprt_info = xprt->priv;
2455
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06002456 mutex_lock(&xprt_info->rx_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002457 xprt_info->abort_data_read = 1;
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06002458 mutex_unlock(&xprt_info->rx_lock);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002459
2460 mutex_lock(&xprt_info_list_lock);
2461 list_del(&xprt_info->list);
2462 mutex_unlock(&xprt_info_list_lock);
2463
2464 flush_workqueue(xprt_info->workqueue);
2465 destroy_workqueue(xprt_info->workqueue);
2466 wake_lock_destroy(&xprt_info->wakelock);
2467
2468 xprt->priv = 0;
2469 kfree(xprt_info);
2470 }
2471}
2472
2473
2474struct msm_ipc_router_xprt_work {
2475 struct msm_ipc_router_xprt *xprt;
2476 struct work_struct work;
2477};
2478
2479static void xprt_open_worker(struct work_struct *work)
2480{
2481 struct msm_ipc_router_xprt_work *xprt_work =
2482 container_of(work, struct msm_ipc_router_xprt_work, work);
2483
2484 msm_ipc_router_add_xprt(xprt_work->xprt);
2485 kfree(xprt_work);
2486}
2487
2488static void xprt_close_worker(struct work_struct *work)
2489{
2490 struct msm_ipc_router_xprt_work *xprt_work =
2491 container_of(work, struct msm_ipc_router_xprt_work, work);
2492
2493 modem_reset_cleanup(xprt_work->xprt->priv);
2494 msm_ipc_router_remove_xprt(xprt_work->xprt);
2495
2496 if (atomic_dec_return(&pending_close_count) == 0)
2497 wake_up(&subsystem_restart_wait);
2498
2499 kfree(xprt_work);
2500}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002501
2502void msm_ipc_router_xprt_notify(struct msm_ipc_router_xprt *xprt,
2503 unsigned event,
2504 void *data)
2505{
2506 struct msm_ipc_router_xprt_info *xprt_info = xprt->priv;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002507 struct msm_ipc_router_xprt_work *xprt_work;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002508 struct rr_packet *pkt;
Karthikeyan Ramasubramanian4af9f7c2011-09-30 15:55:18 -06002509 unsigned long ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002510
Karthikeyan Ramasubramanian4af9f7c2011-09-30 15:55:18 -06002511 if (!msm_ipc_router_workqueue) {
2512 ret = wait_for_completion_timeout(&msm_ipc_local_router_up,
2513 IPC_ROUTER_INIT_TIMEOUT);
2514 if (!ret || !msm_ipc_router_workqueue) {
2515 pr_err("%s: IPC Router not initialized\n", __func__);
2516 return;
2517 }
2518 }
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002519
2520 switch (event) {
2521 case IPC_ROUTER_XPRT_EVENT_OPEN:
2522 D("open event for '%s'\n", xprt->name);
2523 xprt_work = kmalloc(sizeof(struct msm_ipc_router_xprt_work),
2524 GFP_ATOMIC);
2525 xprt_work->xprt = xprt;
2526 INIT_WORK(&xprt_work->work, xprt_open_worker);
2527 queue_work(msm_ipc_router_workqueue, &xprt_work->work);
2528 break;
2529
2530 case IPC_ROUTER_XPRT_EVENT_CLOSE:
2531 D("close event for '%s'\n", xprt->name);
2532 atomic_inc(&pending_close_count);
2533 xprt_work = kmalloc(sizeof(struct msm_ipc_router_xprt_work),
2534 GFP_ATOMIC);
2535 xprt_work->xprt = xprt;
2536 INIT_WORK(&xprt_work->work, xprt_close_worker);
2537 queue_work(msm_ipc_router_workqueue, &xprt_work->work);
2538 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002539 }
2540
2541 if (!data)
2542 return;
2543
2544 while (!xprt_info) {
2545 msleep(100);
2546 xprt_info = xprt->priv;
2547 }
2548
2549 pkt = clone_pkt((struct rr_packet *)data);
2550 if (!pkt)
2551 return;
2552
2553 mutex_lock(&xprt_info->rx_lock);
2554 list_add_tail(&pkt->list, &xprt_info->pkt_list);
2555 wake_lock(&xprt_info->wakelock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002556 mutex_unlock(&xprt_info->rx_lock);
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06002557 queue_work(xprt_info->workqueue, &xprt_info->read_data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002558}
2559
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002560static int modem_restart_notifier_cb(struct notifier_block *this,
2561 unsigned long code,
2562 void *data);
2563static struct notifier_block msm_ipc_router_nb = {
2564 .notifier_call = modem_restart_notifier_cb,
2565};
2566
2567static int modem_restart_notifier_cb(struct notifier_block *this,
2568 unsigned long code,
2569 void *data)
2570{
2571 switch (code) {
2572 case SUBSYS_BEFORE_SHUTDOWN:
2573 D("%s: SUBSYS_BEFORE_SHUTDOWN\n", __func__);
2574 break;
2575
2576 case SUBSYS_BEFORE_POWERUP:
2577 D("%s: waiting for RPC restart to complete\n", __func__);
2578 wait_event(subsystem_restart_wait,
2579 atomic_read(&pending_close_count) == 0);
2580 D("%s: finished restart wait\n", __func__);
2581 break;
2582
2583 default:
2584 break;
2585 }
2586
2587 return NOTIFY_DONE;
2588}
2589
2590static void *restart_notifier_handle;
2591static __init int msm_ipc_router_modem_restart_late_init(void)
2592{
2593 restart_notifier_handle = subsys_notif_register_notifier("modem",
2594 &msm_ipc_router_nb);
2595 return 0;
2596}
2597late_initcall(msm_ipc_router_modem_restart_late_init);
2598
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002599static int __init msm_ipc_router_init(void)
2600{
2601 int i, ret;
2602 struct msm_ipc_routing_table_entry *rt_entry;
2603
2604 msm_ipc_router_debug_mask |= SMEM_LOG;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002605 msm_ipc_router_workqueue =
2606 create_singlethread_workqueue("msm_ipc_router");
2607 if (!msm_ipc_router_workqueue)
2608 return -ENOMEM;
2609
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002610 debugfs_init();
2611
2612 for (i = 0; i < SRV_HASH_SIZE; i++)
2613 INIT_LIST_HEAD(&server_list[i]);
2614
2615 for (i = 0; i < LP_HASH_SIZE; i++)
2616 INIT_LIST_HEAD(&local_ports[i]);
2617
2618 mutex_lock(&routing_table_lock);
2619 if (!routing_table_inited) {
2620 init_routing_table();
2621 rt_entry = alloc_routing_table_entry(IPC_ROUTER_NID_LOCAL);
2622 add_routing_table_entry(rt_entry);
2623 routing_table_inited = 1;
2624 }
2625 mutex_unlock(&routing_table_lock);
2626
2627 init_waitqueue_head(&newserver_wait);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002628 init_waitqueue_head(&subsystem_restart_wait);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002629 ret = msm_ipc_router_init_sockets();
2630 if (ret < 0)
2631 pr_err("%s: Init sockets failed\n", __func__);
2632
Karthikeyan Ramasubramanian4af9f7c2011-09-30 15:55:18 -06002633 complete_all(&msm_ipc_local_router_up);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002634 return ret;
2635}
2636
2637module_init(msm_ipc_router_init);
2638MODULE_DESCRIPTION("MSM IPC Router");
2639MODULE_LICENSE("GPL v2");