blob: 32493984e3777219e0ba203f905a761310b2461d [file] [log] [blame]
Karthikeyan Ramasubramanian25e91872013-01-10 17:09:13 -07001/* Copyright (c) 2011-2013, 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>
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -060030#include <linux/rwsem.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070031
32#include <asm/uaccess.h>
33#include <asm/byteorder.h>
34
35#include <mach/smem_log.h>
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -060036#include <mach/subsystem_notif.h>
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -060037#include <mach/msm_ipc_router.h>
Karthikeyan Ramasubramanian682ebcc2013-03-22 10:47:20 -060038#include <mach/msm_ipc_logging.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070039
40#include "ipc_router.h"
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -060041#include "modem_notifier.h"
Karthikeyan Ramasubramanian1668cc62012-09-23 22:23:36 -060042#include "msm_ipc_router_security.h"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070043
44enum {
45 SMEM_LOG = 1U << 0,
46 RTR_DBG = 1U << 1,
47 R2R_MSG = 1U << 2,
48 R2R_RAW = 1U << 3,
49 NTFY_MSG = 1U << 4,
50 R2R_RAW_HDR = 1U << 5,
51};
52
53static int msm_ipc_router_debug_mask;
54module_param_named(debug_mask, msm_ipc_router_debug_mask,
55 int, S_IRUGO | S_IWUSR | S_IWGRP);
56
Karthikeyan Ramasubramanian682ebcc2013-03-22 10:47:20 -060057static void *ipc_rtr_log_ctxt;
58#define IPC_RTR_LOG_PAGES 5
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070059#define DIAG(x...) pr_info("[RR] ERROR " x)
60
61#if defined(DEBUG)
62#define D(x...) do { \
Karthikeyan Ramasubramanian682ebcc2013-03-22 10:47:20 -060063if (ipc_rtr_log_ctxt) \
64 ipc_log_string(ipc_rtr_log_ctxt, x); \
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070065if (msm_ipc_router_debug_mask & RTR_DBG) \
66 pr_info(x); \
67} while (0)
68
69#define RR(x...) do { \
Karthikeyan Ramasubramanian682ebcc2013-03-22 10:47:20 -060070if (ipc_rtr_log_ctxt) \
71 ipc_log_string(ipc_rtr_log_ctxt, x); \
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070072if (msm_ipc_router_debug_mask & R2R_MSG) \
73 pr_info("[RR] "x); \
74} while (0)
75
76#define RAW(x...) do { \
77if (msm_ipc_router_debug_mask & R2R_RAW) \
78 pr_info("[RAW] "x); \
79} while (0)
80
81#define NTFY(x...) do { \
82if (msm_ipc_router_debug_mask & NTFY_MSG) \
83 pr_info("[NOTIFY] "x); \
84} while (0)
85
86#define RAW_HDR(x...) do { \
87if (msm_ipc_router_debug_mask & R2R_RAW_HDR) \
88 pr_info("[HDR] "x); \
89} while (0)
90#else
91#define D(x...) do { } while (0)
92#define RR(x...) do { } while (0)
93#define RAW(x...) do { } while (0)
94#define RAW_HDR(x...) do { } while (0)
95#define NTFY(x...) do { } while (0)
96#endif
97
Zaheerulla Meer1ee914e2013-06-19 16:31:17 +053098#define IPC_ROUTER_LOG_EVENT_ERROR 0x00
99#define IPC_ROUTER_LOG_EVENT_TX 0x01
100#define IPC_ROUTER_LOG_EVENT_RX 0x02
Zaheerulla Meer3ce2dfb2013-07-11 19:24:40 +0530101#define IPC_ROUTER_DUMMY_DEST_NODE 0xFFFFFFFF
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700102
103static LIST_HEAD(control_ports);
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -0600104static DECLARE_RWSEM(control_ports_lock_lha5);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700105
106#define LP_HASH_SIZE 32
107static struct list_head local_ports[LP_HASH_SIZE];
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -0600108static DECLARE_RWSEM(local_ports_lock_lha2);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700109
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -0600110/*
111 * Server info is organized as a hash table. The server's service ID is
112 * used to index into the hash table. The instance ID of most of the servers
113 * are 1 or 2. The service IDs are well distributed compared to the instance
114 * IDs and hence choosing service ID to index into this hash table optimizes
115 * the hash table operations like add, lookup, destroy.
116 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700117#define SRV_HASH_SIZE 32
118static struct list_head server_list[SRV_HASH_SIZE];
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -0600119static DECLARE_RWSEM(server_list_lock_lha2);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700120
121struct msm_ipc_server {
122 struct list_head list;
123 struct msm_ipc_port_name name;
Karthikeyan Ramasubramanian1668cc62012-09-23 22:23:36 -0600124 int synced_sec_rule;
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -0600125 char pdev_name[32];
126 int next_pdev_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700127 struct list_head server_port_list;
128};
129
130struct msm_ipc_server_port {
131 struct list_head list;
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -0600132 struct platform_device pdev;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700133 struct msm_ipc_port_addr server_addr;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600134 struct msm_ipc_router_xprt_info *xprt_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700135};
136
Zaheerulla Meera34fc662013-04-17 01:16:47 +0530137struct msm_ipc_resume_tx_port {
138 struct list_head list;
139 uint32_t port_id;
140 uint32_t node_id;
141};
142
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700143#define RP_HASH_SIZE 32
144struct msm_ipc_router_remote_port {
145 struct list_head list;
146 uint32_t node_id;
147 uint32_t port_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700148 uint32_t tx_quota_cnt;
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -0600149 struct mutex quota_lock_lhb2;
Zaheerulla Meera34fc662013-04-17 01:16:47 +0530150 struct list_head resume_tx_port_list;
Karthikeyan Ramasubramanian1668cc62012-09-23 22:23:36 -0600151 void *sec_rule;
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -0600152 struct msm_ipc_server *server;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700153};
154
155struct msm_ipc_router_xprt_info {
156 struct list_head list;
157 struct msm_ipc_router_xprt *xprt;
158 uint32_t remote_node_id;
159 uint32_t initialized;
160 struct list_head pkt_list;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700161 struct wake_lock wakelock;
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -0600162 struct mutex rx_lock_lhb2;
163 struct mutex tx_lock_lhb2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700164 uint32_t need_len;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600165 uint32_t abort_data_read;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700166 struct work_struct read_data;
167 struct workqueue_struct *workqueue;
168};
169
170#define RT_HASH_SIZE 4
171struct msm_ipc_routing_table_entry {
172 struct list_head list;
173 uint32_t node_id;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600174 uint32_t neighbor_node_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700175 struct list_head remote_port_list[RP_HASH_SIZE];
176 struct msm_ipc_router_xprt_info *xprt_info;
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -0600177 struct rw_semaphore lock_lha4;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700178 unsigned long num_tx_bytes;
179 unsigned long num_rx_bytes;
180};
181
182static struct list_head routing_table[RT_HASH_SIZE];
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -0600183static DECLARE_RWSEM(routing_table_lock_lha3);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700184static int routing_table_inited;
185
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700186static void do_read_data(struct work_struct *work);
187
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700188static LIST_HEAD(xprt_info_list);
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -0600189static DECLARE_RWSEM(xprt_info_list_lock_lha5);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700190
Karthikeyan Ramasubramanian4af9f7c2011-09-30 15:55:18 -0600191static DECLARE_COMPLETION(msm_ipc_local_router_up);
192#define IPC_ROUTER_INIT_TIMEOUT (10 * HZ)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700193
194static uint32_t next_port_id;
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -0600195static DEFINE_MUTEX(next_port_id_lock_lha1);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600196static struct workqueue_struct *msm_ipc_router_workqueue;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700197
198enum {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700199 DOWN,
200 UP,
201};
202
203static void init_routing_table(void)
204{
205 int i;
206 for (i = 0; i < RT_HASH_SIZE; i++)
207 INIT_LIST_HEAD(&routing_table[i]);
208}
209
210static struct msm_ipc_routing_table_entry *alloc_routing_table_entry(
211 uint32_t node_id)
212{
213 int i;
214 struct msm_ipc_routing_table_entry *rt_entry;
215
216 rt_entry = kmalloc(sizeof(struct msm_ipc_routing_table_entry),
217 GFP_KERNEL);
218 if (!rt_entry) {
219 pr_err("%s: rt_entry allocation failed for %d\n",
220 __func__, node_id);
221 return NULL;
222 }
223
224 for (i = 0; i < RP_HASH_SIZE; i++)
225 INIT_LIST_HEAD(&rt_entry->remote_port_list[i]);
226
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -0600227 init_rwsem(&rt_entry->lock_lha4);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700228 rt_entry->node_id = node_id;
229 rt_entry->xprt_info = NULL;
230 return rt_entry;
231}
232
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -0600233/* Must be called with routing_table_lock_lha3 locked. */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700234static int add_routing_table_entry(
235 struct msm_ipc_routing_table_entry *rt_entry)
236{
237 uint32_t key;
238
239 if (!rt_entry)
240 return -EINVAL;
241
242 key = (rt_entry->node_id % RT_HASH_SIZE);
243 list_add_tail(&rt_entry->list, &routing_table[key]);
244 return 0;
245}
246
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -0600247/* Must be called with routing_table_lock_lha3 locked. */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700248static struct msm_ipc_routing_table_entry *lookup_routing_table(
249 uint32_t node_id)
250{
251 uint32_t key = (node_id % RT_HASH_SIZE);
252 struct msm_ipc_routing_table_entry *rt_entry;
253
254 list_for_each_entry(rt_entry, &routing_table[key], list) {
255 if (rt_entry->node_id == node_id)
256 return rt_entry;
257 }
258 return NULL;
259}
260
261struct rr_packet *rr_read(struct msm_ipc_router_xprt_info *xprt_info)
262{
263 struct rr_packet *temp_pkt;
264
265 if (!xprt_info)
266 return NULL;
267
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -0600268 mutex_lock(&xprt_info->rx_lock_lhb2);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600269 if (xprt_info->abort_data_read) {
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -0600270 mutex_unlock(&xprt_info->rx_lock_lhb2);
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -0600271 pr_err("%s detected SSR & exiting now\n",
272 xprt_info->xprt->name);
273 return NULL;
274 }
275
276 if (list_empty(&xprt_info->pkt_list)) {
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -0600277 mutex_unlock(&xprt_info->rx_lock_lhb2);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600278 return NULL;
279 }
280
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700281 temp_pkt = list_first_entry(&xprt_info->pkt_list,
282 struct rr_packet, list);
283 list_del(&temp_pkt->list);
284 if (list_empty(&xprt_info->pkt_list))
285 wake_unlock(&xprt_info->wakelock);
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -0600286 mutex_unlock(&xprt_info->rx_lock_lhb2);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700287 return temp_pkt;
288}
289
290struct rr_packet *clone_pkt(struct rr_packet *pkt)
291{
292 struct rr_packet *cloned_pkt;
293 struct sk_buff *temp_skb, *cloned_skb;
294 struct sk_buff_head *pkt_fragment_q;
295
296 cloned_pkt = kzalloc(sizeof(struct rr_packet), GFP_KERNEL);
297 if (!cloned_pkt) {
298 pr_err("%s: failure\n", __func__);
299 return NULL;
300 }
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -0600301 memcpy(&(cloned_pkt->hdr), &(pkt->hdr), sizeof(struct rr_header_v1));
302 /* TODO: Copy optional headers, if available */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700303
304 pkt_fragment_q = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
305 if (!pkt_fragment_q) {
306 pr_err("%s: pkt_frag_q alloc failure\n", __func__);
307 kfree(cloned_pkt);
308 return NULL;
309 }
310 skb_queue_head_init(pkt_fragment_q);
311
312 skb_queue_walk(pkt->pkt_fragment_q, temp_skb) {
313 cloned_skb = skb_clone(temp_skb, GFP_KERNEL);
314 if (!cloned_skb)
315 goto fail_clone;
316 skb_queue_tail(pkt_fragment_q, cloned_skb);
317 }
318 cloned_pkt->pkt_fragment_q = pkt_fragment_q;
319 cloned_pkt->length = pkt->length;
320 return cloned_pkt;
321
322fail_clone:
323 while (!skb_queue_empty(pkt_fragment_q)) {
324 temp_skb = skb_dequeue(pkt_fragment_q);
325 kfree_skb(temp_skb);
326 }
327 kfree(pkt_fragment_q);
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -0600328 /* TODO: Free optional headers, if present */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700329 kfree(cloned_pkt);
330 return NULL;
331}
332
333struct rr_packet *create_pkt(struct sk_buff_head *data)
334{
335 struct rr_packet *pkt;
336 struct sk_buff *temp_skb;
337
338 pkt = kzalloc(sizeof(struct rr_packet), GFP_KERNEL);
339 if (!pkt) {
340 pr_err("%s: failure\n", __func__);
341 return NULL;
342 }
343
344 pkt->pkt_fragment_q = data;
345 skb_queue_walk(pkt->pkt_fragment_q, temp_skb)
346 pkt->length += temp_skb->len;
347 return pkt;
348}
349
350void release_pkt(struct rr_packet *pkt)
351{
352 struct sk_buff *temp_skb;
353
354 if (!pkt)
355 return;
356
357 if (!pkt->pkt_fragment_q) {
358 kfree(pkt);
359 return;
360 }
361
362 while (!skb_queue_empty(pkt->pkt_fragment_q)) {
363 temp_skb = skb_dequeue(pkt->pkt_fragment_q);
364 kfree_skb(temp_skb);
365 }
366 kfree(pkt->pkt_fragment_q);
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -0600367 /* TODO: Free Optional headers, if present */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700368 kfree(pkt);
369 return;
370}
371
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -0600372static struct sk_buff_head *msm_ipc_router_buf_to_skb(void *buf,
373 unsigned int buf_len)
374{
375 struct sk_buff_head *skb_head;
376 struct sk_buff *skb;
377 int first = 1, offset = 0;
378 int skb_size, data_size;
379 void *data;
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -0600380 int last = 1;
381 int align_size;
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -0600382
383 skb_head = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
384 if (!skb_head) {
385 pr_err("%s: Couldnot allocate skb_head\n", __func__);
386 return NULL;
387 }
388 skb_queue_head_init(skb_head);
389
390 data_size = buf_len;
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -0600391 align_size = ALIGN_SIZE(data_size);
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -0600392 while (offset != buf_len) {
393 skb_size = data_size;
394 if (first)
395 skb_size += IPC_ROUTER_HDR_SIZE;
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -0600396 if (last)
397 skb_size += align_size;
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -0600398
399 skb = alloc_skb(skb_size, GFP_KERNEL);
400 if (!skb) {
401 if (skb_size <= (PAGE_SIZE/2)) {
402 pr_err("%s: cannot allocate skb\n", __func__);
403 goto buf_to_skb_error;
404 }
405 data_size = data_size / 2;
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -0600406 last = 0;
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -0600407 continue;
408 }
409
410 if (first) {
411 skb_reserve(skb, IPC_ROUTER_HDR_SIZE);
412 first = 0;
413 }
414
415 data = skb_put(skb, data_size);
416 memcpy(skb->data, buf + offset, data_size);
417 skb_queue_tail(skb_head, skb);
418 offset += data_size;
419 data_size = buf_len - offset;
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -0600420 last = 1;
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -0600421 }
422 return skb_head;
423
424buf_to_skb_error:
425 while (!skb_queue_empty(skb_head)) {
426 skb = skb_dequeue(skb_head);
427 kfree_skb(skb);
428 }
429 kfree(skb_head);
430 return NULL;
431}
432
433static void *msm_ipc_router_skb_to_buf(struct sk_buff_head *skb_head,
434 unsigned int len)
435{
436 struct sk_buff *temp;
437 int offset = 0, buf_len = 0, copy_len;
438 void *buf;
439
440 if (!skb_head) {
441 pr_err("%s: NULL skb_head\n", __func__);
442 return NULL;
443 }
444
445 temp = skb_peek(skb_head);
446 buf_len = len;
447 buf = kmalloc(buf_len, GFP_KERNEL);
448 if (!buf) {
449 pr_err("%s: cannot allocate buf\n", __func__);
450 return NULL;
451 }
452 skb_queue_walk(skb_head, temp) {
453 copy_len = buf_len < temp->len ? buf_len : temp->len;
454 memcpy(buf + offset, temp->data, copy_len);
455 offset += copy_len;
456 buf_len -= copy_len;
457 }
458 return buf;
459}
460
461static void msm_ipc_router_free_skb(struct sk_buff_head *skb_head)
462{
463 struct sk_buff *temp_skb;
464
465 if (!skb_head)
466 return;
467
468 while (!skb_queue_empty(skb_head)) {
469 temp_skb = skb_dequeue(skb_head);
470 kfree_skb(temp_skb);
471 }
472 kfree(skb_head);
473}
474
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -0600475/**
476 * extract_header_v1() - Extract IPC Router header of version 1
477 * @pkt: Packet structure into which the header has to be extraced.
478 * @skb: SKB from which the header has to be extracted.
479 *
480 * @return: 0 on success, standard Linux error codes on failure.
481 */
482static int extract_header_v1(struct rr_packet *pkt, struct sk_buff *skb)
483{
484 if (!pkt || !skb) {
485 pr_err("%s: Invalid pkt or skb\n", __func__);
486 return -EINVAL;
487 }
488
489 memcpy(&pkt->hdr, skb->data, sizeof(struct rr_header_v1));
490 skb_pull(skb, sizeof(struct rr_header_v1));
491 pkt->length -= sizeof(struct rr_header_v1);
492 return 0;
493}
494
495/**
496 * extract_header_v2() - Extract IPC Router header of version 2
497 * @pkt: Packet structure into which the header has to be extraced.
498 * @skb: SKB from which the header has to be extracted.
499 *
500 * @return: 0 on success, standard Linux error codes on failure.
501 */
502static int extract_header_v2(struct rr_packet *pkt, struct sk_buff *skb)
503{
504 struct rr_header_v2 *hdr;
505
506 if (!pkt || !skb) {
507 pr_err("%s: Invalid pkt or skb\n", __func__);
508 return -EINVAL;
509 }
510
511 hdr = (struct rr_header_v2 *)skb->data;
512 pkt->hdr.version = (uint32_t)hdr->version;
513 pkt->hdr.type = (uint32_t)hdr->type;
514 pkt->hdr.src_node_id = (uint32_t)hdr->src_node_id;
515 pkt->hdr.src_port_id = (uint32_t)hdr->src_port_id;
516 pkt->hdr.size = (uint32_t)hdr->size;
517 pkt->hdr.control_flag = (uint32_t)hdr->control_flag;
518 pkt->hdr.dst_node_id = (uint32_t)hdr->dst_node_id;
519 pkt->hdr.dst_port_id = (uint32_t)hdr->dst_port_id;
520 skb_pull(skb, sizeof(struct rr_header_v2));
521 pkt->length -= sizeof(struct rr_header_v2);
522 return 0;
523}
524
525/**
526 * extract_header() - Extract IPC Router header
527 * @pkt: Packet from which the header has to be extraced.
528 *
529 * @return: 0 on success, standard Linux error codes on failure.
530 *
531 * This function will check if the header version is v1 or v2 and invoke
532 * the corresponding helper function to extract the IPC Router header.
533 */
534static int extract_header(struct rr_packet *pkt)
535{
536 struct sk_buff *temp_skb;
537 int ret;
538
539 if (!pkt) {
540 pr_err("%s: NULL PKT\n", __func__);
541 return -EINVAL;
542 }
543
544 temp_skb = skb_peek(pkt->pkt_fragment_q);
545 if (!temp_skb || !temp_skb->data) {
546 pr_err("%s: No SKBs in skb_queue\n", __func__);
547 return -EINVAL;
548 }
549
550 if (temp_skb->data[0] == IPC_ROUTER_V1) {
551 ret = extract_header_v1(pkt, temp_skb);
552 } else if (temp_skb->data[0] == IPC_ROUTER_V2) {
553 ret = extract_header_v2(pkt, temp_skb);
554 /* TODO: Extract optional headers if present */
555 } else {
556 pr_err("%s: Invalid Header version %02x\n",
557 __func__, temp_skb->data[0]);
558 print_hex_dump(KERN_ERR, "Header: ", DUMP_PREFIX_ADDRESS,
559 16, 1, temp_skb->data, pkt->length, true);
560 return -EINVAL;
561 }
562 return ret;
563}
564
565/**
566 * calc_tx_header_size() - Calculate header size to be reserved in SKB
567 * @pkt: Packet in which the space for header has to be reserved.
568 * @dst_xprt_info: XPRT through which the destination is reachable.
569 *
570 * @return: required header size on success,
571 * starndard Linux error codes on failure.
572 *
573 * This function is used to calculate the header size that has to be reserved
574 * in a transmit SKB. The header size is calculated based on the XPRT through
575 * which the destination node is reachable.
576 */
577static int calc_tx_header_size(struct rr_packet *pkt,
578 struct msm_ipc_router_xprt_info *dst_xprt_info)
579{
580 int hdr_size = 0;
581 int xprt_version = 0;
582 struct msm_ipc_routing_table_entry *rt_entry;
583 struct msm_ipc_router_xprt_info *xprt_info = dst_xprt_info;
584
585 if (!pkt) {
586 pr_err("%s: NULL PKT\n", __func__);
587 return -EINVAL;
588 }
589
590 if (!xprt_info) {
591 rt_entry = lookup_routing_table(pkt->hdr.dst_node_id);
592 if (!rt_entry || !(rt_entry->xprt_info)) {
593 pr_err("%s: Node %d is not up\n",
594 __func__, pkt->hdr.dst_node_id);
595 return -ENODEV;
596 }
597
598 xprt_info = rt_entry->xprt_info;
599 }
600 if (xprt_info)
601 xprt_version = xprt_info->xprt->get_version(xprt_info->xprt);
602
603 if (xprt_version == IPC_ROUTER_V1) {
604 pkt->hdr.version = IPC_ROUTER_V1;
605 hdr_size = sizeof(struct rr_header_v1);
606 } else if (xprt_version == IPC_ROUTER_V2) {
607 pkt->hdr.version = IPC_ROUTER_V2;
608 hdr_size = sizeof(struct rr_header_v2);
609 /* TODO: Calculate optional header length, if present */
610 } else {
611 pr_err("%s: Invalid xprt_version %d\n",
612 __func__, xprt_version);
613 hdr_size = -EINVAL;
614 }
615
616 return hdr_size;
617}
618
619/**
620 * prepend_header_v1() - Prepend IPC Router header of version 1
621 * @pkt: Packet structure which contains the header info to be prepended.
622 * @hdr_size: Size of the header
623 *
624 * @return: 0 on success, standard Linux error codes on failure.
625 */
626static int prepend_header_v1(struct rr_packet *pkt, int hdr_size)
627{
628 struct sk_buff *temp_skb;
629 struct rr_header_v1 *hdr;
630
631 if (!pkt || hdr_size <= 0) {
632 pr_err("%s: Invalid input parameters\n", __func__);
633 return -EINVAL;
634 }
635
636 temp_skb = skb_peek(pkt->pkt_fragment_q);
637 if (!temp_skb || !temp_skb->data) {
638 pr_err("%s: No SKBs in skb_queue\n", __func__);
639 return -EINVAL;
640 }
641
642 if (skb_headroom(temp_skb) < hdr_size) {
643 temp_skb = alloc_skb(hdr_size, GFP_KERNEL);
644 if (!temp_skb) {
645 pr_err("%s: Could not allocate SKB of size %d\n",
646 __func__, hdr_size);
647 return -ENOMEM;
648 }
649 }
650
651 hdr = (struct rr_header_v1 *)skb_push(temp_skb, hdr_size);
652 memcpy(hdr, &pkt->hdr, hdr_size);
653 if (temp_skb != skb_peek(pkt->pkt_fragment_q))
654 skb_queue_head(pkt->pkt_fragment_q, temp_skb);
655 pkt->length += hdr_size;
656 return 0;
657}
658
659/**
660 * prepend_header_v2() - Prepend IPC Router header of version 2
661 * @pkt: Packet structure which contains the header info to be prepended.
662 * @hdr_size: Size of the header
663 *
664 * @return: 0 on success, standard Linux error codes on failure.
665 */
666static int prepend_header_v2(struct rr_packet *pkt, int hdr_size)
667{
668 struct sk_buff *temp_skb;
669 struct rr_header_v2 *hdr;
670
671 if (!pkt || hdr_size <= 0) {
672 pr_err("%s: Invalid input parameters\n", __func__);
673 return -EINVAL;
674 }
675
676 temp_skb = skb_peek(pkt->pkt_fragment_q);
677 if (!temp_skb || !temp_skb->data) {
678 pr_err("%s: No SKBs in skb_queue\n", __func__);
679 return -EINVAL;
680 }
681
682 if (skb_headroom(temp_skb) < hdr_size) {
683 temp_skb = alloc_skb(hdr_size, GFP_KERNEL);
684 if (!temp_skb) {
685 pr_err("%s: Could not allocate SKB of size %d\n",
686 __func__, hdr_size);
687 return -ENOMEM;
688 }
689 }
690
691 hdr = (struct rr_header_v2 *)skb_push(temp_skb, hdr_size);
692 hdr->version = (uint8_t)pkt->hdr.version;
693 hdr->type = (uint8_t)pkt->hdr.type;
694 hdr->control_flag = (uint16_t)pkt->hdr.control_flag;
695 hdr->size = (uint32_t)pkt->hdr.size;
696 hdr->src_node_id = (uint16_t)pkt->hdr.src_node_id;
697 hdr->src_port_id = (uint16_t)pkt->hdr.src_port_id;
698 hdr->dst_node_id = (uint16_t)pkt->hdr.dst_node_id;
699 hdr->dst_port_id = (uint16_t)pkt->hdr.dst_port_id;
700 /* TODO: Add optional headers, if present */
701 if (temp_skb != skb_peek(pkt->pkt_fragment_q))
702 skb_queue_head(pkt->pkt_fragment_q, temp_skb);
703 pkt->length += hdr_size;
704 return 0;
705}
706
707/**
708 * prepend_header() - Prepend IPC Router header
709 * @pkt: Packet structure which contains the header info to be prepended.
710 * @xprt_info: XPRT through which the packet is transmitted.
711 *
712 * @return: 0 on success, standard Linux error codes on failure.
713 *
714 * This function prepends the header to the packet to be transmitted. The
715 * IPC Router header version to be prepended depends on the XPRT through
716 * which the destination is reachable.
717 */
718static int prepend_header(struct rr_packet *pkt,
719 struct msm_ipc_router_xprt_info *xprt_info)
720{
721 int hdr_size;
722 struct sk_buff *temp_skb;
723
724 if (!pkt) {
725 pr_err("%s: NULL PKT\n", __func__);
726 return -EINVAL;
727 }
728
729 temp_skb = skb_peek(pkt->pkt_fragment_q);
730 if (!temp_skb || !temp_skb->data) {
731 pr_err("%s: No SKBs in skb_queue\n", __func__);
732 return -EINVAL;
733 }
734
735 hdr_size = calc_tx_header_size(pkt, xprt_info);
736 if (hdr_size <= 0)
737 return hdr_size;
738
739 if (pkt->hdr.version == IPC_ROUTER_V1)
740 return prepend_header_v1(pkt, hdr_size);
741 else if (pkt->hdr.version == IPC_ROUTER_V2)
742 return prepend_header_v2(pkt, hdr_size);
743 else
744 return -EINVAL;
745}
746
747/**
748 * defragment_pkt() - Defragment and linearize the packet
749 * @pkt: Packet to be linearized.
750 *
751 * @return: 0 on success, standard Linux error codes on failure.
752 *
753 * Some packets contain fragments of data over multiple SKBs. If an XPRT
754 * does not supported fragmented writes, linearize multiple SKBs into one
755 * single SKB.
756 */
757static int defragment_pkt(struct rr_packet *pkt)
758{
759 struct sk_buff *dst_skb, *src_skb, *temp_skb;
760 int offset = 0, buf_len = 0, copy_len;
761 void *buf;
762 int align_size;
763
764 if (!pkt || pkt->length <= 0) {
765 pr_err("%s: Invalid PKT\n", __func__);
766 return -EINVAL;
767 }
768
769 if (skb_queue_len(pkt->pkt_fragment_q) == 1)
770 return 0;
771
772 align_size = ALIGN_SIZE(pkt->length);
773 dst_skb = alloc_skb(pkt->length + align_size, GFP_KERNEL);
774 if (!dst_skb) {
775 pr_err("%s: could not allocate one skb of size %d\n",
776 __func__, pkt->length);
777 return -ENOMEM;
778 }
779 buf = skb_put(dst_skb, pkt->length);
780 buf_len = pkt->length;
781
782 skb_queue_walk(pkt->pkt_fragment_q, src_skb) {
783 copy_len = buf_len < src_skb->len ? buf_len : src_skb->len;
784 memcpy(buf + offset, src_skb->data, copy_len);
785 offset += copy_len;
786 buf_len -= copy_len;
787 }
788
789 while (!skb_queue_empty(pkt->pkt_fragment_q)) {
790 temp_skb = skb_dequeue(pkt->pkt_fragment_q);
791 kfree_skb(temp_skb);
792 }
793 skb_queue_tail(pkt->pkt_fragment_q, dst_skb);
794 return 0;
795}
796
Karthikeyan Ramasubramaniand1af6252013-05-17 15:19:56 -0600797static int post_pkt_to_port(struct msm_ipc_port *port_ptr,
798 struct rr_packet *pkt, int clone)
799{
800 struct rr_packet *temp_pkt = pkt;
Zaheerulla Meer29302cf2013-05-24 21:19:18 +0530801 void (*notify)(unsigned event, void *priv);
Karthikeyan Ramasubramaniand1af6252013-05-17 15:19:56 -0600802
803 if (unlikely(!port_ptr || !pkt))
804 return -EINVAL;
805
806 if (clone) {
807 temp_pkt = clone_pkt(pkt);
808 if (!temp_pkt) {
809 pr_err("%s: Error cloning packet for port %08x:%08x\n",
810 __func__, port_ptr->this_port.node_id,
811 port_ptr->this_port.port_id);
812 return -ENOMEM;
813 }
814 }
815
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -0600816 mutex_lock(&port_ptr->port_rx_q_lock_lhb3);
Karthikeyan Ramasubramaniand1af6252013-05-17 15:19:56 -0600817 wake_lock(&port_ptr->port_rx_wake_lock);
818 list_add_tail(&temp_pkt->list, &port_ptr->port_rx_q);
819 wake_up(&port_ptr->port_rx_wait_q);
Zaheerulla Meer29302cf2013-05-24 21:19:18 +0530820 notify = port_ptr->notify;
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -0600821 mutex_unlock(&port_ptr->port_rx_q_lock_lhb3);
Zaheerulla Meer29302cf2013-05-24 21:19:18 +0530822 if (notify)
823 notify(MSM_IPC_ROUTER_READ_CB, port_ptr->priv);
Karthikeyan Ramasubramaniand1af6252013-05-17 15:19:56 -0600824 return 0;
825}
826
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700827static int post_control_ports(struct rr_packet *pkt)
828{
829 struct msm_ipc_port *port_ptr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700830
831 if (!pkt)
832 return -EINVAL;
833
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -0600834 down_read(&control_ports_lock_lha5);
Karthikeyan Ramasubramaniand1af6252013-05-17 15:19:56 -0600835 list_for_each_entry(port_ptr, &control_ports, list)
836 post_pkt_to_port(port_ptr, pkt, 1);
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -0600837 up_read(&control_ports_lock_lha5);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700838 return 0;
839}
840
841static uint32_t allocate_port_id(void)
842{
843 uint32_t port_id = 0, prev_port_id, key;
844 struct msm_ipc_port *port_ptr;
845
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -0600846 mutex_lock(&next_port_id_lock_lha1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700847 prev_port_id = next_port_id;
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -0600848 down_read(&local_ports_lock_lha2);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700849 do {
850 next_port_id++;
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -0600851 if ((next_port_id & IPC_ROUTER_ADDRESS) == IPC_ROUTER_ADDRESS)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700852 next_port_id = 1;
853
854 key = (next_port_id & (LP_HASH_SIZE - 1));
855 if (list_empty(&local_ports[key])) {
856 port_id = next_port_id;
857 break;
858 }
859 list_for_each_entry(port_ptr, &local_ports[key], list) {
860 if (port_ptr->this_port.port_id == next_port_id) {
861 port_id = next_port_id;
862 break;
863 }
864 }
865 if (!port_id) {
866 port_id = next_port_id;
867 break;
868 }
869 port_id = 0;
870 } while (next_port_id != prev_port_id);
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -0600871 up_read(&local_ports_lock_lha2);
872 mutex_unlock(&next_port_id_lock_lha1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700873
874 return port_id;
875}
876
877void msm_ipc_router_add_local_port(struct msm_ipc_port *port_ptr)
878{
879 uint32_t key;
880
881 if (!port_ptr)
882 return;
883
884 key = (port_ptr->this_port.port_id & (LP_HASH_SIZE - 1));
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -0600885 down_write(&local_ports_lock_lha2);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700886 list_add_tail(&port_ptr->list, &local_ports[key]);
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -0600887 up_write(&local_ports_lock_lha2);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700888}
889
890struct msm_ipc_port *msm_ipc_router_create_raw_port(void *endpoint,
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -0600891 void (*notify)(unsigned event, void *priv),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700892 void *priv)
893{
894 struct msm_ipc_port *port_ptr;
895
896 port_ptr = kzalloc(sizeof(struct msm_ipc_port), GFP_KERNEL);
897 if (!port_ptr)
898 return NULL;
899
900 port_ptr->this_port.node_id = IPC_ROUTER_NID_LOCAL;
901 port_ptr->this_port.port_id = allocate_port_id();
902 if (!port_ptr->this_port.port_id) {
903 pr_err("%s: All port ids are in use\n", __func__);
904 kfree(port_ptr);
905 return NULL;
906 }
907
908 spin_lock_init(&port_ptr->port_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700909 INIT_LIST_HEAD(&port_ptr->port_rx_q);
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -0600910 mutex_init(&port_ptr->port_rx_q_lock_lhb3);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700911 init_waitqueue_head(&port_ptr->port_rx_wait_q);
Karthikeyan Ramasubramanianb4aeeb92012-03-13 12:31:43 -0600912 snprintf(port_ptr->rx_wakelock_name, MAX_WAKELOCK_NAME_SZ,
Karthikeyan Ramasubramanian090486e2013-02-14 13:53:20 -0700913 "ipc%08x_%s",
914 port_ptr->this_port.port_id,
915 current->comm);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700916 wake_lock_init(&port_ptr->port_rx_wake_lock,
Karthikeyan Ramasubramanianb4aeeb92012-03-13 12:31:43 -0600917 WAKE_LOCK_SUSPEND, port_ptr->rx_wakelock_name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700918
919 port_ptr->endpoint = endpoint;
920 port_ptr->notify = notify;
921 port_ptr->priv = priv;
922
923 msm_ipc_router_add_local_port(port_ptr);
924 return port_ptr;
925}
926
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -0600927/* Must be called with local_ports_lock_lha2 locked. */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700928static struct msm_ipc_port *msm_ipc_router_lookup_local_port(uint32_t port_id)
929{
930 int key = (port_id & (LP_HASH_SIZE - 1));
931 struct msm_ipc_port *port_ptr;
932
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700933 list_for_each_entry(port_ptr, &local_ports[key], list) {
934 if (port_ptr->this_port.port_id == port_id) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700935 return port_ptr;
936 }
937 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700938 return NULL;
939}
940
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -0600941/* Must be called with routing_table_lock_lha3 locked. */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700942static struct msm_ipc_router_remote_port *msm_ipc_router_lookup_remote_port(
943 uint32_t node_id,
944 uint32_t port_id)
945{
946 struct msm_ipc_router_remote_port *rport_ptr;
947 struct msm_ipc_routing_table_entry *rt_entry;
948 int key = (port_id & (RP_HASH_SIZE - 1));
949
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700950 rt_entry = lookup_routing_table(node_id);
951 if (!rt_entry) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700952 pr_err("%s: Node is not up\n", __func__);
953 return NULL;
954 }
955
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -0600956 down_read(&rt_entry->lock_lha4);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700957 list_for_each_entry(rport_ptr,
958 &rt_entry->remote_port_list[key], list) {
959 if (rport_ptr->port_id == port_id) {
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -0600960 up_read(&rt_entry->lock_lha4);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700961 return rport_ptr;
962 }
963 }
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -0600964 up_read(&rt_entry->lock_lha4);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700965 return NULL;
966}
967
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -0600968/* Must be called with routing_table_lock_lha3 locked. */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700969static struct msm_ipc_router_remote_port *msm_ipc_router_create_remote_port(
970 uint32_t node_id,
971 uint32_t port_id)
972{
973 struct msm_ipc_router_remote_port *rport_ptr;
974 struct msm_ipc_routing_table_entry *rt_entry;
975 int key = (port_id & (RP_HASH_SIZE - 1));
976
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700977 rt_entry = lookup_routing_table(node_id);
978 if (!rt_entry) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700979 pr_err("%s: Node is not up\n", __func__);
980 return NULL;
981 }
982
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700983 rport_ptr = kmalloc(sizeof(struct msm_ipc_router_remote_port),
984 GFP_KERNEL);
985 if (!rport_ptr) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700986 pr_err("%s: Remote port alloc failed\n", __func__);
987 return NULL;
988 }
989 rport_ptr->port_id = port_id;
990 rport_ptr->node_id = node_id;
Karthikeyan Ramasubramanian1668cc62012-09-23 22:23:36 -0600991 rport_ptr->sec_rule = NULL;
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -0600992 rport_ptr->server = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700993 rport_ptr->tx_quota_cnt = 0;
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -0600994 mutex_init(&rport_ptr->quota_lock_lhb2);
Zaheerulla Meera34fc662013-04-17 01:16:47 +0530995 INIT_LIST_HEAD(&rport_ptr->resume_tx_port_list);
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -0600996 down_write(&rt_entry->lock_lha4);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700997 list_add_tail(&rport_ptr->list,
998 &rt_entry->remote_port_list[key]);
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -0600999 up_write(&rt_entry->lock_lha4);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001000 return rport_ptr;
1001}
1002
Zaheerulla Meera34fc662013-04-17 01:16:47 +05301003/**
1004 * msm_ipc_router_free_resume_tx_port() - Free the resume_tx ports
1005 * @rport_ptr: Pointer to the remote port.
1006 *
1007 * This function deletes all the resume_tx ports associated with a remote port
1008 * and frees the memory allocated to each resume_tx port.
1009 *
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06001010 * Must be called with rport_ptr->quota_lock_lhb2 locked.
Zaheerulla Meera34fc662013-04-17 01:16:47 +05301011 */
1012static void msm_ipc_router_free_resume_tx_port(
1013 struct msm_ipc_router_remote_port *rport_ptr)
1014{
1015 struct msm_ipc_resume_tx_port *rtx_port, *tmp_rtx_port;
1016
1017 list_for_each_entry_safe(rtx_port, tmp_rtx_port,
1018 &rport_ptr->resume_tx_port_list, list) {
1019 list_del(&rtx_port->list);
1020 kfree(rtx_port);
1021 }
1022}
1023
1024/**
1025 * msm_ipc_router_lookup_resume_tx_port() - Lookup resume_tx port list
1026 * @rport_ptr: Remote port whose resume_tx port list needs to be looked.
1027 * @port_id: Port ID which needs to be looked from the list.
1028 *
1029 * return 1 if the port_id is found in the list, else 0.
1030 *
1031 * This function is used to lookup the existence of a local port in
1032 * remote port's resume_tx list. This function is used to ensure that
1033 * the same port is not added to the remote_port's resume_tx list repeatedly.
1034 *
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06001035 * Must be called with rport_ptr->quota_lock_lhb2 locked.
Zaheerulla Meera34fc662013-04-17 01:16:47 +05301036 */
1037static int msm_ipc_router_lookup_resume_tx_port(
1038 struct msm_ipc_router_remote_port *rport_ptr, uint32_t port_id)
1039{
1040 struct msm_ipc_resume_tx_port *rtx_port;
1041
1042 list_for_each_entry(rtx_port, &rport_ptr->resume_tx_port_list, list) {
1043 if (port_id == rtx_port->port_id)
1044 return 1;
1045 }
1046 return 0;
1047}
1048
1049/**
1050 * post_resume_tx() - Post the resume_tx event
1051 * @rport_ptr: Pointer to the remote port
1052 * @pkt : The data packet that is received on a resume_tx event
1053 *
1054 * This function informs about the reception of the resume_tx message from a
1055 * remote port pointed by rport_ptr to all the local ports that are in the
1056 * resume_tx_ports_list of this remote port. On posting the information, this
1057 * function sequentially deletes each entry in the resume_tx_port_list of the
1058 * remote port.
1059 *
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06001060 * Must be called with rport_ptr->quota_lock_lhb2 locked.
Zaheerulla Meera34fc662013-04-17 01:16:47 +05301061 */
1062static void post_resume_tx(struct msm_ipc_router_remote_port *rport_ptr,
1063 struct rr_packet *pkt)
1064{
1065 struct msm_ipc_resume_tx_port *rtx_port, *tmp_rtx_port;
1066 struct msm_ipc_port *local_port;
Zaheerulla Meera34fc662013-04-17 01:16:47 +05301067
1068 list_for_each_entry_safe(rtx_port, tmp_rtx_port,
1069 &rport_ptr->resume_tx_port_list, list) {
Zaheerulla Meera34fc662013-04-17 01:16:47 +05301070 local_port =
1071 msm_ipc_router_lookup_local_port(rtx_port->port_id);
Zaheerulla Meerc8400402013-05-08 19:27:27 +05301072 if (local_port && local_port->notify)
1073 local_port->notify(MSM_IPC_ROUTER_RESUME_TX,
1074 local_port->priv);
1075 else if (local_port)
Karthikeyan Ramasubramaniand1af6252013-05-17 15:19:56 -06001076 post_pkt_to_port(local_port, pkt, 1);
Zaheerulla Meerc8400402013-05-08 19:27:27 +05301077 else
1078 pr_err("%s: Local Port %d not Found",
1079 __func__, rtx_port->port_id);
Zaheerulla Meera34fc662013-04-17 01:16:47 +05301080 list_del(&rtx_port->list);
1081 kfree(rtx_port);
1082 }
1083}
1084
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06001085/* Must be called with routing_table_lock_lha3 locked. */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001086static void msm_ipc_router_destroy_remote_port(
1087 struct msm_ipc_router_remote_port *rport_ptr)
1088{
1089 uint32_t node_id;
1090 struct msm_ipc_routing_table_entry *rt_entry;
1091
1092 if (!rport_ptr)
1093 return;
1094
1095 node_id = rport_ptr->node_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001096 rt_entry = lookup_routing_table(node_id);
1097 if (!rt_entry) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001098 pr_err("%s: Node %d is not up\n", __func__, node_id);
1099 return;
1100 }
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06001101 down_write(&rt_entry->lock_lha4);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001102 list_del(&rport_ptr->list);
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06001103 up_write(&rt_entry->lock_lha4);
1104 mutex_lock(&rport_ptr->quota_lock_lhb2);
1105 msm_ipc_router_free_resume_tx_port(rport_ptr);
1106 mutex_unlock(&rport_ptr->quota_lock_lhb2);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001107 kfree(rport_ptr);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001108 return;
1109}
1110
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001111/**
1112 * msm_ipc_router_lookup_server() - Lookup server information
1113 * @service: Service ID of the server info to be looked up.
1114 * @instance: Instance ID of the server info to be looked up.
1115 * @node_id: Node/Processor ID in which the server is hosted.
1116 * @port_id: Port ID within the node in which the server is hosted.
1117 *
1118 * @return: If found Pointer to server structure, else NULL.
1119 *
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06001120 * Note1: Lock the server_list_lock_lha2 before accessing this function.
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001121 * Note2: If the <node_id:port_id> are <0:0>, then the lookup is restricted
1122 * to <service:instance>. Used only when a client wants to send a
1123 * message to any QMI server.
1124 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001125static struct msm_ipc_server *msm_ipc_router_lookup_server(
1126 uint32_t service,
1127 uint32_t instance,
1128 uint32_t node_id,
1129 uint32_t port_id)
1130{
1131 struct msm_ipc_server *server;
1132 struct msm_ipc_server_port *server_port;
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001133 int key = (service & (SRV_HASH_SIZE - 1));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001134
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001135 list_for_each_entry(server, &server_list[key], list) {
1136 if ((server->name.service != service) ||
1137 (server->name.instance != instance))
1138 continue;
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001139 if ((node_id == 0) && (port_id == 0))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001140 return server;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001141 list_for_each_entry(server_port, &server->server_port_list,
1142 list) {
1143 if ((server_port->server_addr.node_id == node_id) &&
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001144 (server_port->server_addr.port_id == port_id))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001145 return server;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001146 }
1147 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001148 return NULL;
1149}
1150
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -06001151static void dummy_release(struct device *dev)
1152{
1153}
1154
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001155/**
1156 * msm_ipc_router_create_server() - Add server info to hash table
1157 * @service: Service ID of the server info to be created.
1158 * @instance: Instance ID of the server info to be created.
1159 * @node_id: Node/Processor ID in which the server is hosted.
1160 * @port_id: Port ID within the node in which the server is hosted.
1161 * @xprt_info: XPRT through which the node hosting the server is reached.
1162 *
1163 * @return: Pointer to server structure on success, else NULL.
1164 *
1165 * This function adds the server info to the hash table. If the same
1166 * server(i.e. <service_id:instance_id>) is hosted in different nodes,
1167 * they are maintained as list of "server_port" under "server" structure.
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06001168 * Note: Lock the server_list_lock_lha2 before accessing this function.
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001169 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001170static struct msm_ipc_server *msm_ipc_router_create_server(
1171 uint32_t service,
1172 uint32_t instance,
1173 uint32_t node_id,
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001174 uint32_t port_id,
1175 struct msm_ipc_router_xprt_info *xprt_info)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001176{
1177 struct msm_ipc_server *server = NULL;
1178 struct msm_ipc_server_port *server_port;
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001179 int key = (service & (SRV_HASH_SIZE - 1));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001180
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001181 list_for_each_entry(server, &server_list[key], list) {
1182 if ((server->name.service == service) &&
1183 (server->name.instance == instance))
1184 goto create_srv_port;
1185 }
1186
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -06001187 server = kzalloc(sizeof(struct msm_ipc_server), GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001188 if (!server) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001189 pr_err("%s: Server allocation failed\n", __func__);
1190 return NULL;
1191 }
1192 server->name.service = service;
1193 server->name.instance = instance;
Karthikeyan Ramasubramanian1668cc62012-09-23 22:23:36 -06001194 server->synced_sec_rule = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001195 INIT_LIST_HEAD(&server->server_port_list);
1196 list_add_tail(&server->list, &server_list[key]);
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -06001197 scnprintf(server->pdev_name, sizeof(server->pdev_name),
1198 "QMI%08x:%08x", service, instance);
1199 server->next_pdev_id = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001200
1201create_srv_port:
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -06001202 server_port = kzalloc(sizeof(struct msm_ipc_server_port), GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001203 if (!server_port) {
1204 if (list_empty(&server->server_port_list)) {
1205 list_del(&server->list);
1206 kfree(server);
1207 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001208 pr_err("%s: Server Port allocation failed\n", __func__);
1209 return NULL;
1210 }
1211 server_port->server_addr.node_id = node_id;
1212 server_port->server_addr.port_id = port_id;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001213 server_port->xprt_info = xprt_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001214 list_add_tail(&server_port->list, &server->server_port_list);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001215
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -06001216 server_port->pdev.name = server->pdev_name;
1217 server_port->pdev.id = server->next_pdev_id++;
1218 server_port->pdev.dev.release = dummy_release;
1219 platform_device_register(&server_port->pdev);
1220
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001221 return server;
1222}
1223
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001224/**
1225 * msm_ipc_router_destroy_server() - Remove server info from hash table
1226 * @server: Server info to be removed.
1227 * @node_id: Node/Processor ID in which the server is hosted.
1228 * @port_id: Port ID within the node in which the server is hosted.
1229 *
1230 * This function removes the server_port identified using <node_id:port_id>
1231 * from the server structure. If the server_port list under server structure
1232 * is empty after removal, then remove the server structure from the server
1233 * hash table.
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06001234 * Note: Lock the server_list_lock_lha2 before accessing this function.
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06001235 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001236static void msm_ipc_router_destroy_server(struct msm_ipc_server *server,
1237 uint32_t node_id, uint32_t port_id)
1238{
1239 struct msm_ipc_server_port *server_port;
1240
1241 if (!server)
1242 return;
1243
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001244 list_for_each_entry(server_port, &server->server_port_list, list) {
1245 if ((server_port->server_addr.node_id == node_id) &&
1246 (server_port->server_addr.port_id == port_id))
1247 break;
1248 }
1249 if (server_port) {
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -06001250 platform_device_unregister(&server_port->pdev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001251 list_del(&server_port->list);
1252 kfree(server_port);
1253 }
1254 if (list_empty(&server->server_port_list)) {
1255 list_del(&server->list);
1256 kfree(server);
1257 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001258 return;
1259}
1260
1261static int msm_ipc_router_send_control_msg(
1262 struct msm_ipc_router_xprt_info *xprt_info,
Zaheerulla Meer3ce2dfb2013-07-11 19:24:40 +05301263 union rr_control_msg *msg,
1264 uint32_t dst_node_id)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001265{
1266 struct rr_packet *pkt;
1267 struct sk_buff *ipc_rtr_pkt;
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -06001268 struct rr_header_v1 *hdr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001269 int pkt_size;
1270 void *data;
1271 struct sk_buff_head *pkt_fragment_q;
1272 int ret;
1273
1274 if (!xprt_info || ((msg->cmd != IPC_ROUTER_CTRL_CMD_HELLO) &&
1275 !xprt_info->initialized)) {
1276 pr_err("%s: xprt_info not initialized\n", __func__);
1277 return -EINVAL;
1278 }
1279
1280 if (xprt_info->remote_node_id == IPC_ROUTER_NID_LOCAL)
1281 return 0;
1282
1283 pkt = kzalloc(sizeof(struct rr_packet), GFP_KERNEL);
1284 if (!pkt) {
1285 pr_err("%s: pkt alloc failed\n", __func__);
1286 return -ENOMEM;
1287 }
1288
1289 pkt_fragment_q = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
1290 if (!pkt_fragment_q) {
1291 pr_err("%s: pkt_fragment_q alloc failed\n", __func__);
1292 kfree(pkt);
1293 return -ENOMEM;
1294 }
1295 skb_queue_head_init(pkt_fragment_q);
1296
1297 pkt_size = IPC_ROUTER_HDR_SIZE + sizeof(*msg);
1298 ipc_rtr_pkt = alloc_skb(pkt_size, GFP_KERNEL);
1299 if (!ipc_rtr_pkt) {
1300 pr_err("%s: ipc_rtr_pkt alloc failed\n", __func__);
1301 kfree(pkt_fragment_q);
1302 kfree(pkt);
1303 return -ENOMEM;
1304 }
1305
1306 skb_reserve(ipc_rtr_pkt, IPC_ROUTER_HDR_SIZE);
1307 data = skb_put(ipc_rtr_pkt, sizeof(*msg));
1308 memcpy(data, msg, sizeof(*msg));
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -06001309 skb_queue_tail(pkt_fragment_q, ipc_rtr_pkt);
1310 pkt->pkt_fragment_q = pkt_fragment_q;
1311 pkt->length = sizeof(*msg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001312
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -06001313 hdr = &(pkt->hdr);
1314 hdr->version = IPC_ROUTER_V1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001315 hdr->type = msg->cmd;
1316 hdr->src_node_id = IPC_ROUTER_NID_LOCAL;
1317 hdr->src_port_id = IPC_ROUTER_ADDRESS;
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -06001318 hdr->control_flag = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001319 hdr->size = sizeof(*msg);
Zaheerulla Meer3ce2dfb2013-07-11 19:24:40 +05301320 if (hdr->type == IPC_ROUTER_CTRL_CMD_RESUME_TX)
1321 hdr->dst_node_id = dst_node_id;
1322 else
1323 hdr->dst_node_id = xprt_info->remote_node_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001324 hdr->dst_port_id = IPC_ROUTER_ADDRESS;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001325
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06001326 mutex_lock(&xprt_info->tx_lock_lhb2);
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -06001327 ret = prepend_header(pkt, xprt_info);
1328 if (ret < 0) {
1329 mutex_unlock(&xprt_info->tx_lock_lhb2);
1330 pr_err("%s: Prepend Header failed\n", __func__);
1331 release_pkt(pkt);
1332 return ret;
1333 }
1334
1335 ret = xprt_info->xprt->write(pkt, pkt->length, xprt_info->xprt);
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06001336 mutex_unlock(&xprt_info->tx_lock_lhb2);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001337
1338 release_pkt(pkt);
1339 return ret;
1340}
1341
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001342static int msm_ipc_router_send_server_list(uint32_t node_id,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001343 struct msm_ipc_router_xprt_info *xprt_info)
1344{
1345 union rr_control_msg ctl;
1346 struct msm_ipc_server *server;
1347 struct msm_ipc_server_port *server_port;
1348 int i;
1349
1350 if (!xprt_info || !xprt_info->initialized) {
1351 pr_err("%s: Xprt info not initialized\n", __func__);
1352 return -EINVAL;
1353 }
1354
Karthikeyan Ramasubramanian45008a62013-07-19 15:58:38 -06001355 memset(&ctl, 0, sizeof(ctl));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001356 ctl.cmd = IPC_ROUTER_CTRL_CMD_NEW_SERVER;
1357
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001358 for (i = 0; i < SRV_HASH_SIZE; i++) {
1359 list_for_each_entry(server, &server_list[i], list) {
1360 ctl.srv.service = server->name.service;
1361 ctl.srv.instance = server->name.instance;
1362 list_for_each_entry(server_port,
1363 &server->server_port_list, list) {
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001364 if (server_port->server_addr.node_id !=
1365 node_id)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001366 continue;
1367
1368 ctl.srv.node_id =
1369 server_port->server_addr.node_id;
1370 ctl.srv.port_id =
1371 server_port->server_addr.port_id;
1372 msm_ipc_router_send_control_msg(xprt_info,
Zaheerulla Meer3ce2dfb2013-07-11 19:24:40 +05301373 &ctl, IPC_ROUTER_DUMMY_DEST_NODE);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001374 }
1375 }
1376 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001377
1378 return 0;
1379}
1380
1381#if defined(DEBUG)
1382static char *type_to_str(int i)
1383{
1384 switch (i) {
1385 case IPC_ROUTER_CTRL_CMD_DATA:
1386 return "data ";
1387 case IPC_ROUTER_CTRL_CMD_HELLO:
1388 return "hello ";
1389 case IPC_ROUTER_CTRL_CMD_BYE:
1390 return "bye ";
1391 case IPC_ROUTER_CTRL_CMD_NEW_SERVER:
1392 return "new_srvr";
1393 case IPC_ROUTER_CTRL_CMD_REMOVE_SERVER:
1394 return "rmv_srvr";
1395 case IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT:
1396 return "rmv_clnt";
1397 case IPC_ROUTER_CTRL_CMD_RESUME_TX:
1398 return "resum_tx";
1399 case IPC_ROUTER_CTRL_CMD_EXIT:
1400 return "cmd_exit";
1401 default:
1402 return "invalid";
1403 }
1404}
1405#endif
1406
1407static int broadcast_ctl_msg_locally(union rr_control_msg *msg)
1408{
1409 struct rr_packet *pkt;
1410 struct sk_buff *ipc_rtr_pkt;
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -06001411 struct rr_header_v1 *hdr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001412 int pkt_size;
1413 void *data;
1414 struct sk_buff_head *pkt_fragment_q;
1415 int ret;
1416
1417 pkt = kzalloc(sizeof(struct rr_packet), GFP_KERNEL);
1418 if (!pkt) {
1419 pr_err("%s: pkt alloc failed\n", __func__);
1420 return -ENOMEM;
1421 }
1422
1423 pkt_fragment_q = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
1424 if (!pkt_fragment_q) {
1425 pr_err("%s: pkt_fragment_q alloc failed\n", __func__);
1426 kfree(pkt);
1427 return -ENOMEM;
1428 }
1429 skb_queue_head_init(pkt_fragment_q);
1430
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -06001431 pkt_size = sizeof(*msg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001432 ipc_rtr_pkt = alloc_skb(pkt_size, GFP_KERNEL);
1433 if (!ipc_rtr_pkt) {
1434 pr_err("%s: ipc_rtr_pkt alloc failed\n", __func__);
1435 kfree(pkt_fragment_q);
1436 kfree(pkt);
1437 return -ENOMEM;
1438 }
1439
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001440 data = skb_put(ipc_rtr_pkt, sizeof(*msg));
1441 memcpy(data, msg, sizeof(*msg));
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -06001442 hdr = &(pkt->hdr);
1443 hdr->version = IPC_ROUTER_V1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001444 hdr->type = msg->cmd;
1445 hdr->src_node_id = IPC_ROUTER_NID_LOCAL;
1446 hdr->src_port_id = IPC_ROUTER_ADDRESS;
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -06001447 hdr->control_flag = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001448 hdr->size = sizeof(*msg);
1449 hdr->dst_node_id = IPC_ROUTER_NID_LOCAL;
1450 hdr->dst_port_id = IPC_ROUTER_ADDRESS;
1451 skb_queue_tail(pkt_fragment_q, ipc_rtr_pkt);
1452 pkt->pkt_fragment_q = pkt_fragment_q;
1453 pkt->length = pkt_size;
1454
1455 ret = post_control_ports(pkt);
1456 release_pkt(pkt);
1457 return ret;
1458}
1459
1460static int broadcast_ctl_msg(union rr_control_msg *ctl)
1461{
1462 struct msm_ipc_router_xprt_info *xprt_info;
1463
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06001464 down_read(&xprt_info_list_lock_lha5);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001465 list_for_each_entry(xprt_info, &xprt_info_list, list) {
Zaheerulla Meer3ce2dfb2013-07-11 19:24:40 +05301466 msm_ipc_router_send_control_msg(xprt_info, ctl,
1467 IPC_ROUTER_DUMMY_DEST_NODE);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001468 }
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06001469 up_read(&xprt_info_list_lock_lha5);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001470
1471 return 0;
1472}
1473
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001474static int relay_ctl_msg(struct msm_ipc_router_xprt_info *xprt_info,
1475 union rr_control_msg *ctl)
1476{
1477 struct msm_ipc_router_xprt_info *fwd_xprt_info;
1478
1479 if (!xprt_info || !ctl)
1480 return -EINVAL;
1481
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06001482 down_read(&xprt_info_list_lock_lha5);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001483 list_for_each_entry(fwd_xprt_info, &xprt_info_list, list) {
1484 if (xprt_info->xprt->link_id != fwd_xprt_info->xprt->link_id)
Zaheerulla Meer3ce2dfb2013-07-11 19:24:40 +05301485 msm_ipc_router_send_control_msg(fwd_xprt_info, ctl,
1486 IPC_ROUTER_DUMMY_DEST_NODE);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001487 }
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06001488 up_read(&xprt_info_list_lock_lha5);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001489
1490 return 0;
1491}
1492
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001493static int forward_msg(struct msm_ipc_router_xprt_info *xprt_info,
1494 struct rr_packet *pkt)
1495{
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -06001496 struct rr_header_v1 *hdr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001497 struct msm_ipc_router_xprt_info *fwd_xprt_info;
1498 struct msm_ipc_routing_table_entry *rt_entry;
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06001499 int ret = 0;
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -06001500 int fwd_xprt_option;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001501
1502 if (!xprt_info || !pkt)
1503 return -EINVAL;
1504
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -06001505 hdr = &(pkt->hdr);
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06001506 down_read(&routing_table_lock_lha3);
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -06001507 rt_entry = lookup_routing_table(hdr->dst_node_id);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001508 if (!(rt_entry) || !(rt_entry->xprt_info)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001509 pr_err("%s: Routing table not initialized\n", __func__);
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -06001510 ret = -ENODEV;
1511 goto fm_error1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001512 }
1513
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06001514 down_read(&rt_entry->lock_lha4);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001515 fwd_xprt_info = rt_entry->xprt_info;
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -06001516 ret = prepend_header(pkt, fwd_xprt_info);
1517 if (ret < 0) {
1518 pr_err("%s: Prepend Header failed\n", __func__);
1519 goto fm_error2;
1520 }
1521 fwd_xprt_option = fwd_xprt_info->xprt->get_option(fwd_xprt_info->xprt);
1522 if (!(fwd_xprt_option & FRAG_PKT_WRITE_ENABLE)) {
1523 ret = defragment_pkt(pkt);
1524 if (ret < 0)
1525 goto fm_error2;
1526 }
1527
1528 mutex_lock(&fwd_xprt_info->tx_lock_lhb2);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001529 if (xprt_info->remote_node_id == fwd_xprt_info->remote_node_id) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001530 pr_err("%s: Discarding Command to route back\n", __func__);
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06001531 ret = -EINVAL;
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -06001532 goto fm_error3;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001533 }
1534
1535 if (xprt_info->xprt->link_id == fwd_xprt_info->xprt->link_id) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001536 pr_err("%s: DST in the same cluster\n", __func__);
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -06001537 ret = 0;
1538 goto fm_error3;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001539 }
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -07001540 fwd_xprt_info->xprt->write(pkt, pkt->length, fwd_xprt_info->xprt);
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -06001541
1542fm_error3:
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06001543 mutex_unlock(&fwd_xprt_info->tx_lock_lhb2);
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -06001544fm_error2:
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06001545 up_read(&rt_entry->lock_lha4);
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -06001546fm_error1:
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06001547 up_read(&routing_table_lock_lha3);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001548
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06001549 return ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001550}
1551
Karthikeyan Ramasubramaniandc9c4442013-05-02 17:25:54 -06001552static int msm_ipc_router_send_remove_client(struct comm_mode_info *mode_info,
1553 uint32_t node_id, uint32_t port_id)
1554{
1555 union rr_control_msg msg;
1556 struct msm_ipc_router_xprt_info *tmp_xprt_info;
1557 int mode;
1558 void *xprt_info;
1559 int rc = 0;
1560
1561 if (!mode_info) {
1562 pr_err("%s: NULL mode_info\n", __func__);
1563 return -EINVAL;
1564 }
1565 mode = mode_info->mode;
1566 xprt_info = mode_info->xprt_info;
1567
Karthikeyan Ramasubramanian45008a62013-07-19 15:58:38 -06001568 memset(&msg, 0, sizeof(msg));
Karthikeyan Ramasubramaniandc9c4442013-05-02 17:25:54 -06001569 msg.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT;
1570 msg.cli.node_id = node_id;
1571 msg.cli.port_id = port_id;
1572
1573 if ((mode == SINGLE_LINK_MODE) && xprt_info) {
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06001574 down_read(&xprt_info_list_lock_lha5);
Karthikeyan Ramasubramaniandc9c4442013-05-02 17:25:54 -06001575 list_for_each_entry(tmp_xprt_info, &xprt_info_list, list) {
1576 if (tmp_xprt_info != xprt_info)
1577 continue;
Zaheerulla Meer3ce2dfb2013-07-11 19:24:40 +05301578 msm_ipc_router_send_control_msg(tmp_xprt_info, &msg,
1579 IPC_ROUTER_DUMMY_DEST_NODE);
Karthikeyan Ramasubramaniandc9c4442013-05-02 17:25:54 -06001580 break;
1581 }
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06001582 up_read(&xprt_info_list_lock_lha5);
Karthikeyan Ramasubramaniandc9c4442013-05-02 17:25:54 -06001583 } else if ((mode == SINGLE_LINK_MODE) && !xprt_info) {
1584 broadcast_ctl_msg_locally(&msg);
1585 } else if (mode == MULTI_LINK_MODE) {
1586 broadcast_ctl_msg(&msg);
1587 broadcast_ctl_msg_locally(&msg);
1588 } else if (mode != NULL_MODE) {
1589 pr_err("%s: Invalid mode(%d) + xprt_inf(%p) for %08x:%08x\n",
1590 __func__, mode, xprt_info, node_id, port_id);
1591 rc = -EINVAL;
1592 }
1593 return rc;
1594}
1595
1596static void update_comm_mode_info(struct comm_mode_info *mode_info,
1597 struct msm_ipc_router_xprt_info *xprt_info)
1598{
1599 if (!mode_info) {
1600 pr_err("%s: NULL mode_info\n", __func__);
1601 return;
1602 }
1603
1604 if (mode_info->mode == NULL_MODE) {
1605 mode_info->xprt_info = xprt_info;
1606 mode_info->mode = SINGLE_LINK_MODE;
1607 } else if (mode_info->mode == SINGLE_LINK_MODE &&
1608 mode_info->xprt_info != xprt_info) {
1609 mode_info->mode = MULTI_LINK_MODE;
1610 }
1611
1612 return;
1613}
1614
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06001615static void cleanup_rmt_server(struct msm_ipc_router_xprt_info *xprt_info,
1616 struct msm_ipc_router_remote_port *rport_ptr)
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001617{
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001618 union rr_control_msg ctl;
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06001619 struct msm_ipc_server *server = rport_ptr->server;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001620
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06001621 D("Remove server %08x:%08x - %08x:%08x",
1622 server->name.service, server->name.instance,
1623 rport_ptr->node_id, rport_ptr->port_id);
Karthikeyan Ramasubramanian45008a62013-07-19 15:58:38 -06001624 memset(&ctl, 0, sizeof(ctl));
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001625 ctl.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_SERVER;
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06001626 ctl.srv.service = server->name.service;
1627 ctl.srv.instance = server->name.instance;
1628 ctl.srv.node_id = rport_ptr->node_id;
1629 ctl.srv.port_id = rport_ptr->port_id;
1630 relay_ctl_msg(xprt_info, &ctl);
1631 broadcast_ctl_msg_locally(&ctl);
1632 msm_ipc_router_destroy_server(server,
1633 rport_ptr->node_id, rport_ptr->port_id);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001634}
1635
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06001636static void cleanup_rmt_ports(struct msm_ipc_router_xprt_info *xprt_info,
1637 struct msm_ipc_routing_table_entry *rt_entry)
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001638{
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001639 struct msm_ipc_router_remote_port *rport_ptr, *tmp_rport_ptr;
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06001640 union rr_control_msg ctl;
1641 int j;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001642
Karthikeyan Ramasubramanian45008a62013-07-19 15:58:38 -06001643 memset(&ctl, 0, sizeof(ctl));
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06001644 for (j = 0; j < RP_HASH_SIZE; j++) {
1645 list_for_each_entry_safe(rport_ptr, tmp_rport_ptr,
1646 &rt_entry->remote_port_list[j], list) {
1647 list_del(&rport_ptr->list);
1648 mutex_lock(&rport_ptr->quota_lock_lhb2);
1649 msm_ipc_router_free_resume_tx_port(rport_ptr);
1650 mutex_unlock(&rport_ptr->quota_lock_lhb2);
1651
1652 if (rport_ptr->server)
1653 cleanup_rmt_server(xprt_info, rport_ptr);
1654
1655 ctl.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT;
1656 ctl.cli.node_id = rport_ptr->node_id;
1657 ctl.cli.port_id = rport_ptr->port_id;
1658 relay_ctl_msg(xprt_info, &ctl);
1659 broadcast_ctl_msg_locally(&ctl);
1660 kfree(rport_ptr);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001661 }
1662 }
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001663}
1664
1665static void msm_ipc_cleanup_routing_table(
1666 struct msm_ipc_router_xprt_info *xprt_info)
1667{
1668 int i;
Karthikeyan Ramasubramanian97eec852013-08-06 18:15:52 -06001669 struct msm_ipc_routing_table_entry *rt_entry, *tmp_rt_entry;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001670
1671 if (!xprt_info) {
1672 pr_err("%s: Invalid xprt_info\n", __func__);
1673 return;
1674 }
1675
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06001676 down_write(&server_list_lock_lha2);
1677 down_write(&routing_table_lock_lha3);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001678 for (i = 0; i < RT_HASH_SIZE; i++) {
Karthikeyan Ramasubramanian97eec852013-08-06 18:15:52 -06001679 list_for_each_entry_safe(rt_entry, tmp_rt_entry,
1680 &routing_table[i], list) {
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06001681 down_write(&rt_entry->lock_lha4);
1682 if (rt_entry->xprt_info != xprt_info) {
1683 up_write(&rt_entry->lock_lha4);
1684 continue;
1685 }
1686 cleanup_rmt_ports(xprt_info, rt_entry);
1687 rt_entry->xprt_info = NULL;
1688 up_write(&rt_entry->lock_lha4);
Karthikeyan Ramasubramanian97eec852013-08-06 18:15:52 -06001689 list_del(&rt_entry->list);
1690 kfree(rt_entry);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001691 }
1692 }
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06001693 up_write(&routing_table_lock_lha3);
1694 up_write(&server_list_lock_lha2);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06001695}
1696
Karthikeyan Ramasubramanian1668cc62012-09-23 22:23:36 -06001697/**
1698 * sync_sec_rule() - Synchrnoize the security rule into the server structure
1699 * @server: Server structure where the rule has to be synchronized.
1700 * @rule: Security tule to be synchronized.
1701 *
1702 * This function is used to update the server structure with the security
1703 * rule configured for the <service:instance> corresponding to that server.
1704 */
1705static void sync_sec_rule(struct msm_ipc_server *server, void *rule)
1706{
1707 struct msm_ipc_server_port *server_port;
1708 struct msm_ipc_router_remote_port *rport_ptr = NULL;
1709
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06001710 down_read(&routing_table_lock_lha3);
Karthikeyan Ramasubramanian1668cc62012-09-23 22:23:36 -06001711 list_for_each_entry(server_port, &server->server_port_list, list) {
1712 rport_ptr = msm_ipc_router_lookup_remote_port(
1713 server_port->server_addr.node_id,
1714 server_port->server_addr.port_id);
1715 if (!rport_ptr)
1716 continue;
1717 rport_ptr->sec_rule = rule;
1718 }
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06001719 up_read(&routing_table_lock_lha3);
Karthikeyan Ramasubramanian1668cc62012-09-23 22:23:36 -06001720 server->synced_sec_rule = 1;
1721}
1722
1723/**
1724 * msm_ipc_sync_sec_rule() - Sync the security rule to the service
1725 * @service: Service for which the rule has to be synchronized.
1726 * @instance: Instance for which the rule has to be synchronized.
1727 * @rule: Security rule to be synchronized.
1728 *
1729 * This function is used to syncrhonize the security rule with the server
1730 * hash table, if the user-space script configures the rule after the service
1731 * has come up. This function is used to synchronize the security rule to a
1732 * specific service and optionally a specific instance.
1733 */
1734void msm_ipc_sync_sec_rule(uint32_t service, uint32_t instance, void *rule)
1735{
1736 int key = (service & (SRV_HASH_SIZE - 1));
1737 struct msm_ipc_server *server;
1738
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06001739 down_write(&server_list_lock_lha2);
Karthikeyan Ramasubramanian1668cc62012-09-23 22:23:36 -06001740 list_for_each_entry(server, &server_list[key], list) {
1741 if (server->name.service != service)
1742 continue;
1743
1744 if (server->name.instance != instance &&
1745 instance != ALL_INSTANCE)
1746 continue;
1747
1748 /*
1749 * If the rule applies to all instances and if the specific
1750 * instance of a service has a rule synchronized already,
1751 * do not apply the rule for that specific instance.
1752 */
1753 if (instance == ALL_INSTANCE && server->synced_sec_rule)
1754 continue;
1755
1756 sync_sec_rule(server, rule);
1757 }
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06001758 up_write(&server_list_lock_lha2);
Karthikeyan Ramasubramanian1668cc62012-09-23 22:23:36 -06001759}
1760
1761/**
1762 * msm_ipc_sync_default_sec_rule() - Default security rule to all services
1763 * @rule: Security rule to be synchronized.
1764 *
1765 * This function is used to syncrhonize the security rule with the server
1766 * hash table, if the user-space script configures the rule after the service
1767 * has come up. This function is used to synchronize the security rule that
1768 * applies to all services, if the concerned service do not have any rule
1769 * defined.
1770 */
1771void msm_ipc_sync_default_sec_rule(void *rule)
1772{
1773 int key;
1774 struct msm_ipc_server *server;
1775
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06001776 down_write(&server_list_lock_lha2);
Karthikeyan Ramasubramanian1668cc62012-09-23 22:23:36 -06001777 for (key = 0; key < SRV_HASH_SIZE; key++) {
1778 list_for_each_entry(server, &server_list[key], list) {
1779 if (server->synced_sec_rule)
1780 continue;
1781
1782 sync_sec_rule(server, rule);
1783 }
1784 }
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06001785 up_write(&server_list_lock_lha2);
Karthikeyan Ramasubramanian1668cc62012-09-23 22:23:36 -06001786}
1787
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001788static int process_hello_msg(struct msm_ipc_router_xprt_info *xprt_info,
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -06001789 struct rr_header_v1 *hdr)
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001790{
1791 int i, rc = 0;
1792 union rr_control_msg ctl;
1793 struct msm_ipc_routing_table_entry *rt_entry;
1794
1795 if (!hdr)
1796 return -EINVAL;
1797
1798 RR("o HELLO NID %d\n", hdr->src_node_id);
1799
1800 xprt_info->remote_node_id = hdr->src_node_id;
1801 /*
1802 * Find the entry from Routing Table corresponding to Node ID.
1803 * Under SSR, an entry will be found. When the system boots up
1804 * for the 1st time, an entry will not be found and hence allocate
1805 * an entry. Update the entry with the Node ID that it corresponds
1806 * to and the XPRT through which it can be reached.
1807 */
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06001808 down_write(&routing_table_lock_lha3);
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001809 rt_entry = lookup_routing_table(hdr->src_node_id);
1810 if (!rt_entry) {
1811 rt_entry = alloc_routing_table_entry(hdr->src_node_id);
1812 if (!rt_entry) {
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06001813 up_write(&routing_table_lock_lha3);
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001814 pr_err("%s: rt_entry allocation failed\n", __func__);
1815 return -ENOMEM;
1816 }
1817 add_routing_table_entry(rt_entry);
1818 }
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06001819 down_write(&rt_entry->lock_lha4);
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001820 rt_entry->neighbor_node_id = xprt_info->remote_node_id;
1821 rt_entry->xprt_info = xprt_info;
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06001822 up_write(&rt_entry->lock_lha4);
1823 up_write(&routing_table_lock_lha3);
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001824
1825 /* Send a reply HELLO message */
1826 memset(&ctl, 0, sizeof(ctl));
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -06001827 ctl.hello.cmd = IPC_ROUTER_CTRL_CMD_HELLO;
Zaheerulla Meer3ce2dfb2013-07-11 19:24:40 +05301828 rc = msm_ipc_router_send_control_msg(xprt_info, &ctl,
1829 IPC_ROUTER_DUMMY_DEST_NODE);
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001830 if (rc < 0) {
1831 pr_err("%s: Error sending reply HELLO message\n", __func__);
1832 return rc;
1833 }
1834 xprt_info->initialized = 1;
1835
1836 /*
1837 * Send list of servers from the local node and from nodes
1838 * outside the mesh network in which this XPRT is part of.
1839 */
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06001840 down_read(&server_list_lock_lha2);
1841 down_read(&routing_table_lock_lha3);
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001842 for (i = 0; i < RT_HASH_SIZE; i++) {
1843 list_for_each_entry(rt_entry, &routing_table[i], list) {
1844 if ((rt_entry->node_id != IPC_ROUTER_NID_LOCAL) &&
Karthikeyan Ramasubramanian72ad5792013-01-30 14:17:57 -07001845 (!rt_entry->xprt_info ||
1846 (rt_entry->xprt_info->xprt->link_id ==
1847 xprt_info->xprt->link_id)))
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001848 continue;
1849 rc = msm_ipc_router_send_server_list(rt_entry->node_id,
1850 xprt_info);
1851 if (rc < 0) {
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06001852 up_read(&routing_table_lock_lha3);
1853 up_read(&server_list_lock_lha2);
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001854 return rc;
1855 }
1856 }
1857 }
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06001858 up_read(&routing_table_lock_lha3);
1859 up_read(&server_list_lock_lha2);
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06001860 RR("HELLO message processed\n");
1861 return rc;
1862}
1863
Karthikeyan Ramasubramanian4b4120e2013-05-17 18:18:20 -06001864static int process_resume_tx_msg(union rr_control_msg *msg,
1865 struct rr_packet *pkt)
1866{
1867 struct msm_ipc_router_remote_port *rport_ptr;
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06001868 int ret = 0;
Karthikeyan Ramasubramanian4b4120e2013-05-17 18:18:20 -06001869
1870 RR("o RESUME_TX id=%d:%08x\n", msg->cli.node_id, msg->cli.port_id);
1871
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06001872 down_read(&local_ports_lock_lha2);
1873 down_read(&routing_table_lock_lha3);
Karthikeyan Ramasubramanian4b4120e2013-05-17 18:18:20 -06001874 rport_ptr = msm_ipc_router_lookup_remote_port(msg->cli.node_id,
1875 msg->cli.port_id);
1876 if (!rport_ptr) {
1877 pr_err("%s: Unable to resume client\n", __func__);
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06001878 ret = -ENODEV;
1879 goto prtm_out;
Karthikeyan Ramasubramanian4b4120e2013-05-17 18:18:20 -06001880 }
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06001881 mutex_lock(&rport_ptr->quota_lock_lhb2);
Karthikeyan Ramasubramanian4b4120e2013-05-17 18:18:20 -06001882 rport_ptr->tx_quota_cnt = 0;
1883 post_resume_tx(rport_ptr, pkt);
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06001884 mutex_unlock(&rport_ptr->quota_lock_lhb2);
1885prtm_out:
1886 up_read(&routing_table_lock_lha3);
1887 up_read(&local_ports_lock_lha2);
Karthikeyan Ramasubramanian4b4120e2013-05-17 18:18:20 -06001888 return 0;
1889}
1890
1891static int process_new_server_msg(struct msm_ipc_router_xprt_info *xprt_info,
1892 union rr_control_msg *msg, struct rr_packet *pkt)
1893{
1894 struct msm_ipc_routing_table_entry *rt_entry;
1895 struct msm_ipc_server *server;
1896 struct msm_ipc_router_remote_port *rport_ptr;
1897
1898 if (msg->srv.instance == 0) {
1899 pr_err("%s: Server %08x create rejected, version = 0\n",
1900 __func__, msg->srv.service);
1901 return -EINVAL;
1902 }
1903
1904 RR("o NEW_SERVER id=%d:%08x service=%08x:%08x\n", msg->srv.node_id,
1905 msg->srv.port_id, msg->srv.service, msg->srv.instance);
1906 /*
1907 * Find the entry from Routing Table corresponding to Node ID.
1908 * Under SSR, an entry will be found. When the subsystem hosting
1909 * service is not adjacent, an entry will not be found and hence
1910 * allocate an entry. Update the entry with the Node ID that it
1911 * corresponds to and the XPRT through which it can be reached.
1912 */
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06001913 down_write(&routing_table_lock_lha3);
Karthikeyan Ramasubramanian4b4120e2013-05-17 18:18:20 -06001914 rt_entry = lookup_routing_table(msg->srv.node_id);
1915 if (!rt_entry) {
1916 rt_entry = alloc_routing_table_entry(msg->srv.node_id);
1917 if (!rt_entry) {
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06001918 up_write(&routing_table_lock_lha3);
Karthikeyan Ramasubramanian4b4120e2013-05-17 18:18:20 -06001919 pr_err("%s: rt_entry allocation failed\n", __func__);
1920 return -ENOMEM;
1921 }
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06001922 down_write(&rt_entry->lock_lha4);
Karthikeyan Ramasubramanian4b4120e2013-05-17 18:18:20 -06001923 rt_entry->neighbor_node_id = xprt_info->remote_node_id;
1924 rt_entry->xprt_info = xprt_info;
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06001925 up_write(&rt_entry->lock_lha4);
Karthikeyan Ramasubramanian4b4120e2013-05-17 18:18:20 -06001926 add_routing_table_entry(rt_entry);
1927 }
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06001928 up_write(&routing_table_lock_lha3);
Karthikeyan Ramasubramanian4b4120e2013-05-17 18:18:20 -06001929
1930 /*
1931 * If the service does not exist already in the database, create and
1932 * store the service info. Create a remote port structure in which
1933 * the service is hosted and cache the security rule for the service
1934 * in that remote port structure.
1935 */
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06001936 down_write(&server_list_lock_lha2);
Karthikeyan Ramasubramanian4b4120e2013-05-17 18:18:20 -06001937 server = msm_ipc_router_lookup_server(msg->srv.service,
1938 msg->srv.instance, msg->srv.node_id, msg->srv.port_id);
1939 if (!server) {
1940 server = msm_ipc_router_create_server(
1941 msg->srv.service, msg->srv.instance,
1942 msg->srv.node_id, msg->srv.port_id, xprt_info);
1943 if (!server) {
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06001944 up_write(&server_list_lock_lha2);
Karthikeyan Ramasubramanian4b4120e2013-05-17 18:18:20 -06001945 pr_err("%s: Server Create failed\n", __func__);
1946 return -ENOMEM;
1947 }
1948
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06001949 down_read(&routing_table_lock_lha3);
Karthikeyan Ramasubramanian4b4120e2013-05-17 18:18:20 -06001950 if (!msm_ipc_router_lookup_remote_port(
1951 msg->srv.node_id, msg->srv.port_id)) {
1952 rport_ptr = msm_ipc_router_create_remote_port(
1953 msg->srv.node_id, msg->srv.port_id);
1954 if (!rport_ptr) {
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06001955 up_read(&routing_table_lock_lha3);
1956 up_write(&server_list_lock_lha2);
Karthikeyan Ramasubramanian4b4120e2013-05-17 18:18:20 -06001957 return -ENOMEM;
1958 }
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06001959 rport_ptr->server = server;
Karthikeyan Ramasubramanian4b4120e2013-05-17 18:18:20 -06001960 rport_ptr->sec_rule = msm_ipc_get_security_rule(
1961 msg->srv.service,
1962 msg->srv.instance);
1963 }
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06001964 up_read(&routing_table_lock_lha3);
Karthikeyan Ramasubramanian4b4120e2013-05-17 18:18:20 -06001965 }
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06001966 up_write(&server_list_lock_lha2);
Karthikeyan Ramasubramanian4b4120e2013-05-17 18:18:20 -06001967
1968 /*
1969 * Relay the new server message to other subsystems that do not belong
1970 * to the cluster from which this message is received. Notify the
1971 * local clients waiting for this service.
1972 */
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -06001973 relay_ctl_msg(xprt_info, msg);
Karthikeyan Ramasubramanian4b4120e2013-05-17 18:18:20 -06001974 post_control_ports(pkt);
1975 return 0;
1976}
1977
1978static int process_rmv_server_msg(struct msm_ipc_router_xprt_info *xprt_info,
1979 union rr_control_msg *msg, struct rr_packet *pkt)
1980{
1981 struct msm_ipc_server *server;
1982
1983 RR("o REMOVE_SERVER service=%08x:%d\n",
1984 msg->srv.service, msg->srv.instance);
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06001985 down_write(&server_list_lock_lha2);
Karthikeyan Ramasubramanian4b4120e2013-05-17 18:18:20 -06001986 server = msm_ipc_router_lookup_server(msg->srv.service,
1987 msg->srv.instance, msg->srv.node_id, msg->srv.port_id);
1988 if (server) {
1989 msm_ipc_router_destroy_server(server, msg->srv.node_id,
1990 msg->srv.port_id);
1991 /*
1992 * Relay the new server message to other subsystems that do not
1993 * belong to the cluster from which this message is received.
1994 * Notify the local clients communicating with the service.
1995 */
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -06001996 relay_ctl_msg(xprt_info, msg);
Karthikeyan Ramasubramanian4b4120e2013-05-17 18:18:20 -06001997 post_control_ports(pkt);
1998 }
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06001999 up_write(&server_list_lock_lha2);
Karthikeyan Ramasubramanian4b4120e2013-05-17 18:18:20 -06002000 return 0;
2001}
2002
2003static int process_rmv_client_msg(struct msm_ipc_router_xprt_info *xprt_info,
2004 union rr_control_msg *msg, struct rr_packet *pkt)
2005{
2006 struct msm_ipc_router_remote_port *rport_ptr;
2007
2008 RR("o REMOVE_CLIENT id=%d:%08x\n", msg->cli.node_id, msg->cli.port_id);
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06002009 down_write(&routing_table_lock_lha3);
Karthikeyan Ramasubramanian4b4120e2013-05-17 18:18:20 -06002010 rport_ptr = msm_ipc_router_lookup_remote_port(msg->cli.node_id,
2011 msg->cli.port_id);
2012 if (rport_ptr)
2013 msm_ipc_router_destroy_remote_port(rport_ptr);
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06002014 up_write(&routing_table_lock_lha3);
Karthikeyan Ramasubramanian4b4120e2013-05-17 18:18:20 -06002015
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -06002016 relay_ctl_msg(xprt_info, msg);
Karthikeyan Ramasubramanian4b4120e2013-05-17 18:18:20 -06002017 post_control_ports(pkt);
2018 return 0;
2019}
2020
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002021static int process_control_msg(struct msm_ipc_router_xprt_info *xprt_info,
2022 struct rr_packet *pkt)
2023{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002024 union rr_control_msg *msg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002025 int rc = 0;
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -06002026 struct rr_header_v1 *hdr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002027
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -06002028 if (pkt->length != sizeof(*msg)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002029 pr_err("%s: r2r msg size %d != %d\n", __func__, pkt->length,
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -06002030 sizeof(*msg));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002031 return -EINVAL;
2032 }
2033
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -06002034 hdr = &(pkt->hdr);
2035 msg = msm_ipc_router_skb_to_buf(pkt->pkt_fragment_q, sizeof(*msg));
2036 if (!msg) {
2037 pr_err("%s: Error extracting control msg\n", __func__);
2038 return -ENOMEM;
Karthikeyan Ramasubramanian9024dd82011-12-19 18:44:19 -07002039 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002040
2041 switch (msg->cmd) {
2042 case IPC_ROUTER_CTRL_CMD_HELLO:
Karthikeyan Ramasubramanianb234c242012-10-23 13:12:44 -06002043 rc = process_hello_msg(xprt_info, hdr);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002044 break;
2045 case IPC_ROUTER_CTRL_CMD_RESUME_TX:
Karthikeyan Ramasubramanian4b4120e2013-05-17 18:18:20 -06002046 rc = process_resume_tx_msg(msg, pkt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002047 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002048 case IPC_ROUTER_CTRL_CMD_NEW_SERVER:
Karthikeyan Ramasubramanian4b4120e2013-05-17 18:18:20 -06002049 rc = process_new_server_msg(xprt_info, msg, pkt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002050 break;
2051 case IPC_ROUTER_CTRL_CMD_REMOVE_SERVER:
Karthikeyan Ramasubramanian4b4120e2013-05-17 18:18:20 -06002052 rc = process_rmv_server_msg(xprt_info, msg, pkt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002053 break;
2054 case IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT:
Karthikeyan Ramasubramanian4b4120e2013-05-17 18:18:20 -06002055 rc = process_rmv_client_msg(xprt_info, msg, pkt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002056 break;
2057 case IPC_ROUTER_CTRL_CMD_PING:
2058 /* No action needed for ping messages received */
2059 RR("o PING\n");
2060 break;
2061 default:
2062 RR("o UNKNOWN(%08x)\n", msg->cmd);
2063 rc = -ENOSYS;
2064 }
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -06002065 kfree(msg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002066 return rc;
2067}
2068
2069static void do_read_data(struct work_struct *work)
2070{
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -06002071 struct rr_header_v1 *hdr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002072 struct rr_packet *pkt = NULL;
2073 struct msm_ipc_port *port_ptr;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002074 struct msm_ipc_router_remote_port *rport_ptr;
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -06002075 int ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002076
2077 struct msm_ipc_router_xprt_info *xprt_info =
2078 container_of(work,
2079 struct msm_ipc_router_xprt_info,
2080 read_data);
2081
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06002082 while ((pkt = rr_read(xprt_info)) != NULL) {
2083 if (pkt->length < IPC_ROUTER_HDR_SIZE ||
2084 pkt->length > MAX_IPC_PKT_SIZE) {
2085 pr_err("%s: Invalid pkt length %d\n",
2086 __func__, pkt->length);
2087 goto fail_data;
2088 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002089
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -06002090 ret = extract_header(pkt);
2091 if (ret < 0)
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06002092 goto fail_data;
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -06002093 hdr = &(pkt->hdr);
Karthikeyan Ramasubramanian682ebcc2013-03-22 10:47:20 -06002094 RAW("ver=%d type=%d src=%d:%08x crx=%d siz=%d dst=%d:%08x\n",
2095 hdr->version, hdr->type, hdr->src_node_id,
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -06002096 hdr->src_port_id, hdr->control_flag, hdr->size,
Karthikeyan Ramasubramanian682ebcc2013-03-22 10:47:20 -06002097 hdr->dst_node_id, hdr->dst_port_id);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002098
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06002099 if ((hdr->dst_node_id != IPC_ROUTER_NID_LOCAL) &&
2100 ((hdr->type == IPC_ROUTER_CTRL_CMD_RESUME_TX) ||
2101 (hdr->type == IPC_ROUTER_CTRL_CMD_DATA))) {
2102 forward_msg(xprt_info, pkt);
2103 release_pkt(pkt);
2104 continue;
2105 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002106
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -06002107 if (hdr->type != IPC_ROUTER_CTRL_CMD_DATA) {
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06002108 process_control_msg(xprt_info, pkt);
2109 release_pkt(pkt);
2110 continue;
2111 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002112#if defined(CONFIG_MSM_SMD_LOGGING)
2113#if defined(DEBUG)
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06002114 if (msm_ipc_router_debug_mask & SMEM_LOG) {
2115 smem_log_event((SMEM_LOG_PROC_ID_APPS |
Zaheerulla Meer1ee914e2013-06-19 16:31:17 +05302116 SMEM_LOG_IPC_ROUTER_EVENT_BASE |
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06002117 IPC_ROUTER_LOG_EVENT_RX),
2118 (hdr->src_node_id << 24) |
2119 (hdr->src_port_id & 0xffffff),
2120 (hdr->dst_node_id << 24) |
2121 (hdr->dst_port_id & 0xffffff),
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -06002122 (hdr->type << 24) | (hdr->control_flag << 16) |
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06002123 (hdr->size & 0xffff));
2124 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002125#endif
2126#endif
2127
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06002128 down_read(&local_ports_lock_lha2);
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06002129 port_ptr = msm_ipc_router_lookup_local_port(hdr->dst_port_id);
2130 if (!port_ptr) {
2131 pr_err("%s: No local port id %08x\n", __func__,
2132 hdr->dst_port_id);
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06002133 up_read(&local_ports_lock_lha2);
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06002134 release_pkt(pkt);
Zaheerulla Meer3ce2dfb2013-07-11 19:24:40 +05302135 return;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002136 }
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002137
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06002138 down_read(&routing_table_lock_lha3);
2139 rport_ptr = msm_ipc_router_lookup_remote_port(hdr->src_node_id,
2140 hdr->src_port_id);
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06002141 if (!rport_ptr) {
2142 rport_ptr = msm_ipc_router_create_remote_port(
2143 hdr->src_node_id,
2144 hdr->src_port_id);
2145 if (!rport_ptr) {
2146 pr_err("%s: Rmt Prt %08x:%08x create failed\n",
2147 __func__, hdr->src_node_id,
2148 hdr->src_port_id);
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06002149 up_read(&routing_table_lock_lha3);
2150 up_read(&local_ports_lock_lha2);
Zaheerulla Meer6a309de2013-07-12 16:16:30 +05302151 release_pkt(pkt);
Zaheerulla Meer3ce2dfb2013-07-11 19:24:40 +05302152 return;
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06002153 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002154 }
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06002155 up_read(&routing_table_lock_lha3);
Karthikeyan Ramasubramaniand1af6252013-05-17 15:19:56 -06002156 post_pkt_to_port(port_ptr, pkt, 0);
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06002157 up_read(&local_ports_lock_lha2);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002158 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002159 return;
2160
2161fail_data:
2162 release_pkt(pkt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002163 pr_err("ipc_router has died\n");
2164}
2165
2166int msm_ipc_router_register_server(struct msm_ipc_port *port_ptr,
2167 struct msm_ipc_addr *name)
2168{
2169 struct msm_ipc_server *server;
2170 unsigned long flags;
2171 union rr_control_msg ctl;
2172
2173 if (!port_ptr || !name)
2174 return -EINVAL;
2175
2176 if (name->addrtype != MSM_IPC_ADDR_NAME)
2177 return -EINVAL;
2178
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06002179 down_write(&server_list_lock_lha2);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002180 server = msm_ipc_router_lookup_server(name->addr.port_name.service,
2181 name->addr.port_name.instance,
2182 IPC_ROUTER_NID_LOCAL,
2183 port_ptr->this_port.port_id);
2184 if (server) {
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06002185 up_write(&server_list_lock_lha2);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002186 pr_err("%s: Server already present\n", __func__);
2187 return -EINVAL;
2188 }
2189
2190 server = msm_ipc_router_create_server(name->addr.port_name.service,
2191 name->addr.port_name.instance,
2192 IPC_ROUTER_NID_LOCAL,
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06002193 port_ptr->this_port.port_id,
2194 NULL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002195 if (!server) {
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06002196 up_write(&server_list_lock_lha2);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002197 pr_err("%s: Server Creation failed\n", __func__);
2198 return -EINVAL;
2199 }
2200
Karthikeyan Ramasubramanian45008a62013-07-19 15:58:38 -06002201 memset(&ctl, 0, sizeof(ctl));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002202 ctl.cmd = IPC_ROUTER_CTRL_CMD_NEW_SERVER;
2203 ctl.srv.service = server->name.service;
2204 ctl.srv.instance = server->name.instance;
2205 ctl.srv.node_id = IPC_ROUTER_NID_LOCAL;
2206 ctl.srv.port_id = port_ptr->this_port.port_id;
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06002207 up_write(&server_list_lock_lha2);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002208 broadcast_ctl_msg(&ctl);
Karthikeyan Ramasubramanianfa807952013-08-06 18:04:12 -06002209 broadcast_ctl_msg_locally(&ctl);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002210 spin_lock_irqsave(&port_ptr->port_lock, flags);
2211 port_ptr->type = SERVER_PORT;
Karthikeyan Ramasubramaniandc9c4442013-05-02 17:25:54 -06002212 port_ptr->mode_info.mode = MULTI_LINK_MODE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002213 port_ptr->port_name.service = server->name.service;
2214 port_ptr->port_name.instance = server->name.instance;
2215 spin_unlock_irqrestore(&port_ptr->port_lock, flags);
2216 return 0;
2217}
2218
2219int msm_ipc_router_unregister_server(struct msm_ipc_port *port_ptr)
2220{
2221 struct msm_ipc_server *server;
2222 unsigned long flags;
2223 union rr_control_msg ctl;
2224
2225 if (!port_ptr)
2226 return -EINVAL;
2227
2228 if (port_ptr->type != SERVER_PORT) {
2229 pr_err("%s: Trying to unregister a non-server port\n",
2230 __func__);
2231 return -EINVAL;
2232 }
2233
2234 if (port_ptr->this_port.node_id != IPC_ROUTER_NID_LOCAL) {
2235 pr_err("%s: Trying to unregister a remote server locally\n",
2236 __func__);
2237 return -EINVAL;
2238 }
2239
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06002240 down_write(&server_list_lock_lha2);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002241 server = msm_ipc_router_lookup_server(port_ptr->port_name.service,
2242 port_ptr->port_name.instance,
2243 port_ptr->this_port.node_id,
2244 port_ptr->this_port.port_id);
2245 if (!server) {
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06002246 up_write(&server_list_lock_lha2);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002247 pr_err("%s: Server lookup failed\n", __func__);
2248 return -ENODEV;
2249 }
2250
Karthikeyan Ramasubramanian45008a62013-07-19 15:58:38 -06002251 memset(&ctl, 0, sizeof(ctl));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002252 ctl.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_SERVER;
2253 ctl.srv.service = server->name.service;
2254 ctl.srv.instance = server->name.instance;
2255 ctl.srv.node_id = IPC_ROUTER_NID_LOCAL;
2256 ctl.srv.port_id = port_ptr->this_port.port_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002257 msm_ipc_router_destroy_server(server, port_ptr->this_port.node_id,
2258 port_ptr->this_port.port_id);
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06002259 up_write(&server_list_lock_lha2);
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002260 broadcast_ctl_msg(&ctl);
Karthikeyan Ramasubramanianfa807952013-08-06 18:04:12 -06002261 broadcast_ctl_msg_locally(&ctl);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002262 spin_lock_irqsave(&port_ptr->port_lock, flags);
2263 port_ptr->type = CLIENT_PORT;
2264 spin_unlock_irqrestore(&port_ptr->port_lock, flags);
2265 return 0;
2266}
2267
2268static int loopback_data(struct msm_ipc_port *src,
2269 uint32_t port_id,
2270 struct sk_buff_head *data)
2271{
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -06002272 struct rr_header_v1 *hdr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002273 struct msm_ipc_port *port_ptr;
2274 struct rr_packet *pkt;
Karthikeyan Ramasubramanian0a801c12013-02-08 13:07:42 -07002275 int ret_len;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002276
2277 if (!data) {
2278 pr_err("%s: Invalid pkt pointer\n", __func__);
2279 return -EINVAL;
2280 }
2281
2282 pkt = create_pkt(data);
2283 if (!pkt) {
2284 pr_err("%s: New pkt create failed\n", __func__);
2285 return -ENOMEM;
2286 }
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -06002287 hdr = &(pkt->hdr);
2288 hdr->version = IPC_ROUTER_V1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002289 hdr->type = IPC_ROUTER_CTRL_CMD_DATA;
2290 hdr->src_node_id = src->this_port.node_id;
2291 hdr->src_port_id = src->this_port.port_id;
2292 hdr->size = pkt->length;
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -06002293 hdr->control_flag = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002294 hdr->dst_node_id = IPC_ROUTER_NID_LOCAL;
2295 hdr->dst_port_id = port_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002296
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06002297 down_read(&local_ports_lock_lha2);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002298 port_ptr = msm_ipc_router_lookup_local_port(port_id);
2299 if (!port_ptr) {
2300 pr_err("%s: Local port %d not present\n", __func__, port_id);
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06002301 up_read(&local_ports_lock_lha2);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002302 release_pkt(pkt);
2303 return -ENODEV;
2304 }
2305
Karthikeyan Ramasubramanian0a801c12013-02-08 13:07:42 -07002306 ret_len = pkt->length;
Karthikeyan Ramasubramaniand1af6252013-05-17 15:19:56 -06002307 post_pkt_to_port(port_ptr, pkt, 0);
Karthikeyan Ramasubramaniandc9c4442013-05-02 17:25:54 -06002308 update_comm_mode_info(&src->mode_info, NULL);
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06002309 up_read(&local_ports_lock_lha2);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002310
Karthikeyan Ramasubramanian0a801c12013-02-08 13:07:42 -07002311 return ret_len;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002312}
2313
2314static int msm_ipc_router_write_pkt(struct msm_ipc_port *src,
2315 struct msm_ipc_router_remote_port *rport_ptr,
2316 struct rr_packet *pkt)
2317{
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -06002318 struct rr_header_v1 *hdr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002319 struct msm_ipc_router_xprt_info *xprt_info;
2320 struct msm_ipc_routing_table_entry *rt_entry;
Zaheerulla Meera34fc662013-04-17 01:16:47 +05302321 struct msm_ipc_resume_tx_port *resume_tx_port;
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -06002322 struct sk_buff *temp_skb;
2323 int xprt_option;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002324 int ret;
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -06002325 int align_size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002326
2327 if (!rport_ptr || !src || !pkt)
2328 return -EINVAL;
2329
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -06002330 hdr = &(pkt->hdr);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002331 hdr->type = IPC_ROUTER_CTRL_CMD_DATA;
2332 hdr->src_node_id = src->this_port.node_id;
2333 hdr->src_port_id = src->this_port.port_id;
2334 hdr->size = pkt->length;
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -06002335 hdr->control_flag = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002336 hdr->dst_node_id = rport_ptr->node_id;
2337 hdr->dst_port_id = rport_ptr->port_id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002338
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06002339 mutex_lock(&rport_ptr->quota_lock_lhb2);
Zaheerulla Meera34fc662013-04-17 01:16:47 +05302340 if (rport_ptr->tx_quota_cnt == IPC_ROUTER_DEFAULT_RX_QUOTA) {
2341 if (msm_ipc_router_lookup_resume_tx_port(
2342 rport_ptr, src->this_port.port_id)) {
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06002343 mutex_unlock(&rport_ptr->quota_lock_lhb2);
Zaheerulla Meera34fc662013-04-17 01:16:47 +05302344 return -EAGAIN;
2345 }
2346 resume_tx_port =
2347 kzalloc(sizeof(struct msm_ipc_resume_tx_port),
2348 GFP_KERNEL);
2349 if (!resume_tx_port) {
2350 pr_err("%s: Resume_Tx port allocation failed\n",
2351 __func__);
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06002352 mutex_unlock(&rport_ptr->quota_lock_lhb2);
Zaheerulla Meera34fc662013-04-17 01:16:47 +05302353 return -ENOMEM;
2354 }
2355 INIT_LIST_HEAD(&resume_tx_port->list);
2356 resume_tx_port->port_id = src->this_port.port_id;
2357 resume_tx_port->node_id = src->this_port.node_id;
2358 list_add_tail(&resume_tx_port->list,
2359 &rport_ptr->resume_tx_port_list);
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06002360 mutex_unlock(&rport_ptr->quota_lock_lhb2);
Zaheerulla Meera34fc662013-04-17 01:16:47 +05302361 return -EAGAIN;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002362 }
2363 rport_ptr->tx_quota_cnt++;
2364 if (rport_ptr->tx_quota_cnt == IPC_ROUTER_DEFAULT_RX_QUOTA)
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -06002365 hdr->control_flag |= CONTROL_FLAG_CONFIRM_RX;
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06002366 mutex_unlock(&rport_ptr->quota_lock_lhb2);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002367
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002368 rt_entry = lookup_routing_table(hdr->dst_node_id);
2369 if (!rt_entry || !rt_entry->xprt_info) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002370 pr_err("%s: Remote node %d not up\n",
2371 __func__, hdr->dst_node_id);
2372 return -ENODEV;
2373 }
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06002374 down_read(&rt_entry->lock_lha4);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002375 xprt_info = rt_entry->xprt_info;
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -06002376 ret = prepend_header(pkt, xprt_info);
2377 if (ret < 0) {
2378 up_read(&rt_entry->lock_lha4);
2379 pr_err("%s: Prepend Header failed\n", __func__);
2380 return ret;
2381 }
2382 xprt_option = xprt_info->xprt->get_option(xprt_info->xprt);
2383 if (!(xprt_option & FRAG_PKT_WRITE_ENABLE)) {
2384 ret = defragment_pkt(pkt);
2385 if (ret < 0) {
2386 up_read(&rt_entry->lock_lha4);
2387 return ret;
2388 }
2389 }
2390
2391 temp_skb = skb_peek_tail(pkt->pkt_fragment_q);
2392 align_size = ALIGN_SIZE(pkt->length);
2393 skb_put(temp_skb, align_size);
2394 pkt->length += align_size;
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06002395 mutex_lock(&xprt_info->tx_lock_lhb2);
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -07002396 ret = xprt_info->xprt->write(pkt, pkt->length, xprt_info->xprt);
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06002397 mutex_unlock(&xprt_info->tx_lock_lhb2);
2398 up_read(&rt_entry->lock_lha4);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002399
2400 if (ret < 0) {
2401 pr_err("%s: Write on XPRT failed\n", __func__);
2402 return ret;
2403 }
Karthikeyan Ramasubramaniandc9c4442013-05-02 17:25:54 -06002404 update_comm_mode_info(&src->mode_info, xprt_info);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002405
2406 RAW_HDR("[w rr_h] "
2407 "ver=%i,type=%s,src_nid=%08x,src_port_id=%08x,"
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -06002408 "control_flag=%i,size=%3i,dst_pid=%08x,dst_cid=%08x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002409 hdr->version, type_to_str(hdr->type),
2410 hdr->src_node_id, hdr->src_port_id,
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -06002411 hdr->control_flag, hdr->size,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002412 hdr->dst_node_id, hdr->dst_port_id);
2413
2414#if defined(CONFIG_MSM_SMD_LOGGING)
2415#if defined(DEBUG)
2416 if (msm_ipc_router_debug_mask & SMEM_LOG) {
2417 smem_log_event((SMEM_LOG_PROC_ID_APPS |
Zaheerulla Meer1ee914e2013-06-19 16:31:17 +05302418 SMEM_LOG_IPC_ROUTER_EVENT_BASE |
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002419 IPC_ROUTER_LOG_EVENT_TX),
2420 (hdr->src_node_id << 24) |
2421 (hdr->src_port_id & 0xffffff),
2422 (hdr->dst_node_id << 24) |
2423 (hdr->dst_port_id & 0xffffff),
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -06002424 (hdr->type << 24) | (hdr->control_flag << 16) |
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002425 (hdr->size & 0xffff));
2426 }
2427#endif
2428#endif
2429
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -06002430 return hdr->size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002431}
2432
2433int msm_ipc_router_send_to(struct msm_ipc_port *src,
2434 struct sk_buff_head *data,
2435 struct msm_ipc_addr *dest)
2436{
2437 uint32_t dst_node_id = 0, dst_port_id = 0;
2438 struct msm_ipc_server *server;
2439 struct msm_ipc_server_port *server_port;
2440 struct msm_ipc_router_remote_port *rport_ptr = NULL;
2441 struct rr_packet *pkt;
2442 int ret;
2443
2444 if (!src || !data || !dest) {
2445 pr_err("%s: Invalid Parameters\n", __func__);
2446 return -EINVAL;
2447 }
2448
2449 /* Resolve Address*/
2450 if (dest->addrtype == MSM_IPC_ADDR_ID) {
2451 dst_node_id = dest->addr.port_addr.node_id;
2452 dst_port_id = dest->addr.port_addr.port_id;
2453 } else if (dest->addrtype == MSM_IPC_ADDR_NAME) {
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06002454 down_read(&server_list_lock_lha2);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002455 server = msm_ipc_router_lookup_server(
2456 dest->addr.port_name.service,
2457 dest->addr.port_name.instance,
2458 0, 0);
2459 if (!server) {
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06002460 up_read(&server_list_lock_lha2);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002461 pr_err("%s: Destination not reachable\n", __func__);
2462 return -ENODEV;
2463 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002464 server_port = list_first_entry(&server->server_port_list,
2465 struct msm_ipc_server_port,
2466 list);
2467 dst_node_id = server_port->server_addr.node_id;
2468 dst_port_id = server_port->server_addr.port_id;
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06002469 up_read(&server_list_lock_lha2);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002470 }
2471 if (dst_node_id == IPC_ROUTER_NID_LOCAL) {
2472 ret = loopback_data(src, dst_port_id, data);
2473 return ret;
2474 }
2475
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06002476 down_read(&routing_table_lock_lha3);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002477 rport_ptr = msm_ipc_router_lookup_remote_port(dst_node_id,
2478 dst_port_id);
2479 if (!rport_ptr) {
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06002480 up_read(&routing_table_lock_lha3);
Zaheerulla Meer2c515312013-05-10 15:51:28 +05302481 pr_err("%s: Remote port not found\n", __func__);
2482 return -ENODEV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002483 }
2484
Karthikeyan Ramasubramanian1668cc62012-09-23 22:23:36 -06002485 if (src->check_send_permissions) {
2486 ret = src->check_send_permissions(rport_ptr->sec_rule);
2487 if (ret <= 0) {
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06002488 up_read(&routing_table_lock_lha3);
Karthikeyan Ramasubramanian1668cc62012-09-23 22:23:36 -06002489 pr_err("%s: permission failure for %s\n",
2490 __func__, current->comm);
2491 return -EPERM;
2492 }
2493 }
2494
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002495 pkt = create_pkt(data);
2496 if (!pkt) {
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06002497 up_read(&routing_table_lock_lha3);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002498 pr_err("%s: Pkt creation failed\n", __func__);
2499 return -ENOMEM;
2500 }
2501
2502 ret = msm_ipc_router_write_pkt(src, rport_ptr, pkt);
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06002503 up_read(&routing_table_lock_lha3);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002504 release_pkt(pkt);
2505
2506 return ret;
2507}
2508
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -06002509int msm_ipc_router_send_msg(struct msm_ipc_port *src,
2510 struct msm_ipc_addr *dest,
2511 void *data, unsigned int data_len)
2512{
2513 struct sk_buff_head *out_skb_head;
2514 int ret;
2515
2516 out_skb_head = msm_ipc_router_buf_to_skb(data, data_len);
2517 if (!out_skb_head) {
2518 pr_err("%s: SKB conversion failed\n", __func__);
2519 return -EFAULT;
2520 }
2521
2522 ret = msm_ipc_router_send_to(src, out_skb_head, dest);
Zaheerulla Meerc8400402013-05-08 19:27:27 +05302523 if (ret == -EAGAIN)
2524 return ret;
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -06002525 if (ret < 0) {
2526 pr_err("%s: msm_ipc_router_send_to failed - ret: %d\n",
2527 __func__, ret);
2528 msm_ipc_router_free_skb(out_skb_head);
Zaheerulla Meerfc59a8a2013-06-26 22:39:00 +05302529 return ret;
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -06002530 }
2531 return 0;
2532}
2533
Zaheerulla Meer3ce2dfb2013-07-11 19:24:40 +05302534/**
2535 * msm_ipc_router_send_resume_tx() - Send Resume_Tx message
2536 * @data: Pointer to received data packet that has confirm_rx bit set
2537 *
2538 * @return: On success, number of bytes transferred is returned, else
2539 * standard linux error code is returned.
2540 *
2541 * This function sends the Resume_Tx event to the remote node that
2542 * sent the data with confirm_rx field set. In case of a multi-hop
2543 * scenario also, this function makes sure that the destination node_id
2544 * to which the resume_tx event should reach is right.
2545 */
2546static int msm_ipc_router_send_resume_tx(void *data)
2547{
2548 union rr_control_msg msg;
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -06002549 struct rr_header_v1 *hdr = (struct rr_header_v1 *)data;
Zaheerulla Meer3ce2dfb2013-07-11 19:24:40 +05302550 struct msm_ipc_routing_table_entry *rt_entry;
2551 int ret;
2552
2553 memset(&msg, 0, sizeof(msg));
2554 msg.cmd = IPC_ROUTER_CTRL_CMD_RESUME_TX;
2555 msg.cli.node_id = hdr->dst_node_id;
2556 msg.cli.port_id = hdr->dst_port_id;
2557 down_read(&routing_table_lock_lha3);
2558 rt_entry = lookup_routing_table(hdr->src_node_id);
2559 if (!rt_entry) {
2560 pr_err("%s: %d Node is not present",
2561 __func__, hdr->src_node_id);
2562 up_read(&routing_table_lock_lha3);
2563 return -ENODEV;
2564 }
2565 RR("x RESUME_TX id=%d:%08x\n",
2566 msg.cli.node_id, msg.cli.port_id);
2567 ret = msm_ipc_router_send_control_msg(rt_entry->xprt_info, &msg,
2568 hdr->src_node_id);
2569 up_read(&routing_table_lock_lha3);
2570 if (ret < 0)
2571 pr_err("%s: Send Resume_Tx Failed SRC_NODE: %d SRC_PORT: %d DEST_NODE: %d",
2572 __func__, hdr->dst_node_id, hdr->dst_port_id,
2573 hdr->src_node_id);
2574
2575 return ret;
2576}
2577
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002578int msm_ipc_router_read(struct msm_ipc_port *port_ptr,
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -06002579 struct rr_packet **read_pkt,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002580 size_t buf_len)
2581{
2582 struct rr_packet *pkt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002583
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -06002584 if (!port_ptr || !read_pkt)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002585 return -EINVAL;
2586
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06002587 mutex_lock(&port_ptr->port_rx_q_lock_lhb3);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002588 if (list_empty(&port_ptr->port_rx_q)) {
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06002589 mutex_unlock(&port_ptr->port_rx_q_lock_lhb3);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002590 return -EAGAIN;
2591 }
2592
2593 pkt = list_first_entry(&port_ptr->port_rx_q, struct rr_packet, list);
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -06002594 if ((buf_len) && (pkt->hdr.size > buf_len)) {
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06002595 mutex_unlock(&port_ptr->port_rx_q_lock_lhb3);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002596 return -ETOOSMALL;
2597 }
2598 list_del(&pkt->list);
2599 if (list_empty(&port_ptr->port_rx_q))
2600 wake_unlock(&port_ptr->port_rx_wake_lock);
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -06002601 *read_pkt = pkt;
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06002602 mutex_unlock(&port_ptr->port_rx_q_lock_lhb3);
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -06002603 if (pkt->hdr.control_flag & CONTROL_FLAG_CONFIRM_RX)
2604 msm_ipc_router_send_resume_tx(&pkt->hdr);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002605
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -06002606 return pkt->length;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002607}
2608
Zaheerulla Meer20e84262013-05-22 23:31:59 +05302609/**
Arun Kumar Neelakantam0f73f432013-06-21 17:57:18 +05302610 * msm_ipc_router_rx_data_wait() - Wait for new message destined to a local port.
2611 * @port_ptr: Pointer to the local port
2612 * @timeout: < 0 timeout indicates infinite wait till a message arrives.
2613 * > 0 timeout indicates the wait time.
2614 * 0 indicates that we do not wait.
2615 * @return: 0 if there are pending messages to read,
2616 * standard Linux error code otherwise.
2617 *
2618 * Checks for the availability of messages that are destined to a local port.
2619 * If no messages are present then waits as per @timeout.
2620 */
2621int msm_ipc_router_rx_data_wait(struct msm_ipc_port *port_ptr, long timeout)
2622{
2623 int ret = 0;
2624
2625 mutex_lock(&port_ptr->port_rx_q_lock_lhb3);
2626 while (list_empty(&port_ptr->port_rx_q)) {
2627 mutex_unlock(&port_ptr->port_rx_q_lock_lhb3);
2628 if (timeout < 0) {
2629 ret = wait_event_interruptible(
2630 port_ptr->port_rx_wait_q,
2631 !list_empty(&port_ptr->port_rx_q));
2632 if (ret)
2633 return ret;
2634 } else if (timeout > 0) {
2635 timeout = wait_event_interruptible_timeout(
2636 port_ptr->port_rx_wait_q,
2637 !list_empty(&port_ptr->port_rx_q),
2638 timeout);
2639 if (timeout < 0)
2640 return -EFAULT;
2641 }
2642 if (timeout == 0)
2643 return -ENOMSG;
2644 mutex_lock(&port_ptr->port_rx_q_lock_lhb3);
2645 }
2646 mutex_unlock(&port_ptr->port_rx_q_lock_lhb3);
2647
2648 return ret;
2649}
2650
2651/**
Zaheerulla Meer20e84262013-05-22 23:31:59 +05302652 * msm_ipc_router_recv_from() - Recieve messages destined to a local port.
2653 * @port_ptr: Pointer to the local port
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -06002654 * @pkt : Pointer to the router-to-router packet
Zaheerulla Meer20e84262013-05-22 23:31:59 +05302655 * @src: Pointer to local port address
2656 * @timeout: < 0 timeout indicates infinite wait till a message arrives.
2657 * > 0 timeout indicates the wait time.
2658 * 0 indicates that we do not wait.
2659 * @return: = Number of bytes read(On successful read operation).
Arun Kumar Neelakantam0f73f432013-06-21 17:57:18 +05302660 * = -ENOMSG (If there are no pending messages and timeout is 0).
Zaheerulla Meer20e84262013-05-22 23:31:59 +05302661 * = -EINVAL (If either of the arguments, port_ptr or data is invalid)
2662 * = -EFAULT (If there are no pending messages when timeout is > 0
2663 * and the wait_event_interruptible_timeout has returned value > 0)
2664 * = -ERESTARTSYS (If there are no pending messages when timeout
2665 * is < 0 and wait_event_interruptible was interrupted by a signal)
2666 *
2667 * This function reads the messages that are destined for a local port. It
2668 * is used by modules that exist with-in the kernel and use IPC Router for
2669 * transport. The function checks if there are any messages that are already
2670 * received. If yes, it reads them, else it waits as per the timeout value.
2671 * On a successful read, the return value of the function indicates the number
2672 * of bytes that are read.
2673 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002674int msm_ipc_router_recv_from(struct msm_ipc_port *port_ptr,
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -06002675 struct rr_packet **pkt,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002676 struct msm_ipc_addr *src,
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -06002677 long timeout)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002678{
2679 int ret, data_len, align_size;
2680 struct sk_buff *temp_skb;
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -06002681 struct rr_header_v1 *hdr = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002682
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -06002683 if (!port_ptr || !pkt) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002684 pr_err("%s: Invalid pointers being passed\n", __func__);
2685 return -EINVAL;
2686 }
2687
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -06002688 *pkt = NULL;
Arun Kumar Neelakantam0f73f432013-06-21 17:57:18 +05302689
2690 ret = msm_ipc_router_rx_data_wait(port_ptr, timeout);
2691 if (ret)
2692 return ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002693
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -06002694 ret = msm_ipc_router_read(port_ptr, pkt, 0);
2695 if (ret <= 0 || !(*pkt))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002696 return ret;
2697
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -06002698 hdr = &((*pkt)->hdr);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002699 if (src) {
2700 src->addrtype = MSM_IPC_ADDR_ID;
2701 src->addr.port_addr.node_id = hdr->src_node_id;
2702 src->addr.port_addr.port_id = hdr->src_port_id;
2703 }
2704
2705 data_len = hdr->size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002706 align_size = ALIGN_SIZE(data_len);
2707 if (align_size) {
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -06002708 temp_skb = skb_peek_tail((*pkt)->pkt_fragment_q);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002709 skb_trim(temp_skb, (temp_skb->len - align_size));
2710 }
2711 return data_len;
2712}
2713
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -06002714int msm_ipc_router_read_msg(struct msm_ipc_port *port_ptr,
2715 struct msm_ipc_addr *src,
2716 unsigned char **data,
2717 unsigned int *len)
2718{
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -06002719 struct rr_packet *pkt;
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -06002720 int ret;
2721
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -06002722 ret = msm_ipc_router_recv_from(port_ptr, &pkt, src, 0);
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -06002723 if (ret < 0) {
Arun Kumar Neelakantam0f73f432013-06-21 17:57:18 +05302724 if (ret != -ENOMSG)
2725 pr_err("%s: msm_ipc_router_recv_from failed - ret: %d\n",
2726 __func__, ret);
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -06002727 return ret;
2728 }
2729
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -06002730 *data = msm_ipc_router_skb_to_buf(pkt->pkt_fragment_q, ret);
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -06002731 if (!(*data))
2732 pr_err("%s: Buf conversion failed\n", __func__);
2733
2734 *len = ret;
Karthikeyan Ramasubramanian6e2c9a62013-04-16 23:12:44 -06002735 release_pkt(pkt);
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -06002736 return 0;
2737}
2738
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002739struct msm_ipc_port *msm_ipc_router_create_port(
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -06002740 void (*notify)(unsigned event, void *priv),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002741 void *priv)
2742{
2743 struct msm_ipc_port *port_ptr;
Karthikeyan Ramasubramanian70444192012-07-12 10:25:49 -06002744 int ret;
2745
2746 ret = wait_for_completion_interruptible(&msm_ipc_local_router_up);
2747 if (ret < 0) {
2748 pr_err("%s: Error waiting for local router\n", __func__);
2749 return NULL;
2750 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002751
2752 port_ptr = msm_ipc_router_create_raw_port(NULL, notify, priv);
2753 if (!port_ptr)
2754 pr_err("%s: port_ptr alloc failed\n", __func__);
2755
2756 return port_ptr;
2757}
2758
2759int msm_ipc_router_close_port(struct msm_ipc_port *port_ptr)
2760{
2761 union rr_control_msg msg;
2762 struct rr_packet *pkt, *temp_pkt;
2763 struct msm_ipc_server *server;
2764
2765 if (!port_ptr)
2766 return -EINVAL;
2767
2768 if (port_ptr->type == SERVER_PORT || port_ptr->type == CLIENT_PORT) {
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06002769 down_write(&local_ports_lock_lha2);
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06002770 list_del(&port_ptr->list);
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06002771 up_write(&local_ports_lock_lha2);
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06002772
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002773 if (port_ptr->type == SERVER_PORT) {
Karthikeyan Ramasubramanian45008a62013-07-19 15:58:38 -06002774 memset(&msg, 0, sizeof(msg));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002775 msg.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_SERVER;
2776 msg.srv.service = port_ptr->port_name.service;
2777 msg.srv.instance = port_ptr->port_name.instance;
2778 msg.srv.node_id = port_ptr->this_port.node_id;
2779 msg.srv.port_id = port_ptr->this_port.port_id;
2780 RR("x REMOVE_SERVER Name=%d:%08x Id=%d:%08x\n",
2781 msg.srv.service, msg.srv.instance,
2782 msg.srv.node_id, msg.srv.port_id);
Karthikeyan Ramasubramanian25e91872013-01-10 17:09:13 -07002783 broadcast_ctl_msg(&msg);
2784 broadcast_ctl_msg_locally(&msg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002785 }
Karthikeyan Ramasubramanian25e91872013-01-10 17:09:13 -07002786
2787 /*
2788 * Server port could have been a client port earlier.
2789 * Send REMOVE_CLIENT message in either case.
2790 */
Karthikeyan Ramasubramanian25e91872013-01-10 17:09:13 -07002791 RR("x REMOVE_CLIENT id=%d:%08x\n",
Karthikeyan Ramasubramaniandc9c4442013-05-02 17:25:54 -06002792 port_ptr->this_port.node_id, port_ptr->this_port.port_id);
2793 msm_ipc_router_send_remove_client(&port_ptr->mode_info,
2794 port_ptr->this_port.node_id,
2795 port_ptr->this_port.port_id);
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06002796 } else if (port_ptr->type == CONTROL_PORT) {
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06002797 down_write(&control_ports_lock_lha5);
Karthikeyan Ramasubramanianbe9954b2012-06-13 12:59:54 -06002798 list_del(&port_ptr->list);
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06002799 up_write(&control_ports_lock_lha5);
Karthikeyan Ramasubramaniand6dbfae2013-01-16 09:00:28 -07002800 } else if (port_ptr->type == IRSC_PORT) {
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06002801 down_write(&local_ports_lock_lha2);
Karthikeyan Ramasubramaniand6dbfae2013-01-16 09:00:28 -07002802 list_del(&port_ptr->list);
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06002803 up_write(&local_ports_lock_lha2);
Karthikeyan Ramasubramaniand6dbfae2013-01-16 09:00:28 -07002804 signal_irsc_completion();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002805 }
2806
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06002807 mutex_lock(&port_ptr->port_rx_q_lock_lhb3);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002808 list_for_each_entry_safe(pkt, temp_pkt, &port_ptr->port_rx_q, list) {
2809 list_del(&pkt->list);
2810 release_pkt(pkt);
2811 }
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06002812 mutex_unlock(&port_ptr->port_rx_q_lock_lhb3);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002813
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002814 if (port_ptr->type == SERVER_PORT) {
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06002815 down_write(&server_list_lock_lha2);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002816 server = msm_ipc_router_lookup_server(
2817 port_ptr->port_name.service,
2818 port_ptr->port_name.instance,
2819 port_ptr->this_port.node_id,
2820 port_ptr->this_port.port_id);
2821 if (server)
2822 msm_ipc_router_destroy_server(server,
2823 port_ptr->this_port.node_id,
2824 port_ptr->this_port.port_id);
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06002825 up_write(&server_list_lock_lha2);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002826 }
2827
Karthikeyan Ramasubramaniandd8c3b52011-11-30 16:26:12 -07002828 wake_lock_destroy(&port_ptr->port_rx_wake_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002829 kfree(port_ptr);
2830 return 0;
2831}
2832
2833int msm_ipc_router_get_curr_pkt_size(struct msm_ipc_port *port_ptr)
2834{
2835 struct rr_packet *pkt;
2836 int rc = 0;
2837
2838 if (!port_ptr)
2839 return -EINVAL;
2840
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06002841 mutex_lock(&port_ptr->port_rx_q_lock_lhb3);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002842 if (!list_empty(&port_ptr->port_rx_q)) {
2843 pkt = list_first_entry(&port_ptr->port_rx_q,
2844 struct rr_packet, list);
2845 rc = pkt->length;
2846 }
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06002847 mutex_unlock(&port_ptr->port_rx_q_lock_lhb3);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002848
2849 return rc;
2850}
2851
2852int msm_ipc_router_bind_control_port(struct msm_ipc_port *port_ptr)
2853{
2854 if (!port_ptr)
2855 return -EINVAL;
2856
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06002857 down_write(&local_ports_lock_lha2);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002858 list_del(&port_ptr->list);
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06002859 up_write(&local_ports_lock_lha2);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002860 port_ptr->type = CONTROL_PORT;
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06002861 down_write(&control_ports_lock_lha5);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002862 list_add_tail(&port_ptr->list, &control_ports);
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06002863 up_write(&control_ports_lock_lha5);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002864
2865 return 0;
2866}
2867
2868int msm_ipc_router_lookup_server_name(struct msm_ipc_port_name *srv_name,
Karthikeyan Ramasubramaniandfde01b2012-06-12 14:25:13 -06002869 struct msm_ipc_server_info *srv_info,
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002870 int num_entries_in_array,
2871 uint32_t lookup_mask)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002872{
2873 struct msm_ipc_server *server;
2874 struct msm_ipc_server_port *server_port;
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002875 int key, i = 0; /*num_entries_found*/
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002876
2877 if (!srv_name) {
2878 pr_err("%s: Invalid srv_name\n", __func__);
2879 return -EINVAL;
2880 }
2881
Karthikeyan Ramasubramaniandfde01b2012-06-12 14:25:13 -06002882 if (num_entries_in_array && !srv_info) {
2883 pr_err("%s: srv_info NULL\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002884 return -EINVAL;
2885 }
2886
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06002887 down_read(&server_list_lock_lha2);
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002888 if (!lookup_mask)
2889 lookup_mask = 0xFFFFFFFF;
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002890 key = (srv_name->service & (SRV_HASH_SIZE - 1));
2891 list_for_each_entry(server, &server_list[key], list) {
2892 if ((server->name.service != srv_name->service) ||
2893 ((server->name.instance & lookup_mask) !=
2894 srv_name->instance))
2895 continue;
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002896
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002897 list_for_each_entry(server_port,
2898 &server->server_port_list, list) {
2899 if (i < num_entries_in_array) {
2900 srv_info[i].node_id =
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002901 server_port->server_addr.node_id;
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002902 srv_info[i].port_id =
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002903 server_port->server_addr.port_id;
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002904 srv_info[i].service = server->name.service;
2905 srv_info[i].instance = server->name.instance;
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -06002906 }
Karthikeyan Ramasubramaniana85d09f2012-10-25 15:40:45 -06002907 i++;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002908 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002909 }
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06002910 up_read(&server_list_lock_lha2);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002911
2912 return i;
2913}
2914
2915int msm_ipc_router_close(void)
2916{
2917 struct msm_ipc_router_xprt_info *xprt_info, *tmp_xprt_info;
2918
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06002919 down_write(&xprt_info_list_lock_lha5);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002920 list_for_each_entry_safe(xprt_info, tmp_xprt_info,
2921 &xprt_info_list, list) {
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -07002922 xprt_info->xprt->close(xprt_info->xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002923 list_del(&xprt_info->list);
2924 kfree(xprt_info);
2925 }
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06002926 up_write(&xprt_info_list_lock_lha5);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002927 return 0;
2928}
2929
2930#if defined(CONFIG_DEBUG_FS)
2931static int dump_routing_table(char *buf, int max)
2932{
2933 int i = 0, j;
2934 struct msm_ipc_routing_table_entry *rt_entry;
2935
2936 for (j = 0; j < RT_HASH_SIZE; j++) {
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06002937 down_read(&routing_table_lock_lha3);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002938 list_for_each_entry(rt_entry, &routing_table[j], list) {
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06002939 down_read(&rt_entry->lock_lha4);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002940 i += scnprintf(buf + i, max - i,
2941 "Node Id: 0x%08x\n", rt_entry->node_id);
Karthikeyan Ramasubramanianc1a4e3a2012-09-10 16:10:24 -06002942 if (rt_entry->node_id == IPC_ROUTER_NID_LOCAL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002943 i += scnprintf(buf + i, max - i,
2944 "XPRT Name: Loopback\n");
2945 i += scnprintf(buf + i, max - i,
2946 "Next Hop: %d\n", rt_entry->node_id);
2947 } else {
2948 i += scnprintf(buf + i, max - i,
2949 "XPRT Name: %s\n",
2950 rt_entry->xprt_info->xprt->name);
2951 i += scnprintf(buf + i, max - i,
2952 "Next Hop: 0x%08x\n",
2953 rt_entry->xprt_info->remote_node_id);
2954 }
2955 i += scnprintf(buf + i, max - i, "\n");
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06002956 up_read(&rt_entry->lock_lha4);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002957 }
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06002958 up_read(&routing_table_lock_lha3);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002959 }
2960
2961 return i;
2962}
2963
2964static int dump_xprt_info(char *buf, int max)
2965{
2966 int i = 0;
2967 struct msm_ipc_router_xprt_info *xprt_info;
2968
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06002969 down_read(&xprt_info_list_lock_lha5);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002970 list_for_each_entry(xprt_info, &xprt_info_list, list) {
2971 i += scnprintf(buf + i, max - i, "XPRT Name: %s\n",
2972 xprt_info->xprt->name);
2973 i += scnprintf(buf + i, max - i, "Link Id: %d\n",
2974 xprt_info->xprt->link_id);
2975 i += scnprintf(buf + i, max - i, "Initialized: %s\n",
2976 (xprt_info->initialized ? "Y" : "N"));
2977 i += scnprintf(buf + i, max - i, "Remote Node Id: 0x%08x\n",
2978 xprt_info->remote_node_id);
2979 i += scnprintf(buf + i, max - i, "\n");
2980 }
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06002981 up_read(&xprt_info_list_lock_lha5);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002982
2983 return i;
2984}
2985
2986static int dump_servers(char *buf, int max)
2987{
2988 int i = 0, j;
2989 struct msm_ipc_server *server;
2990 struct msm_ipc_server_port *server_port;
2991
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06002992 down_read(&server_list_lock_lha2);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002993 for (j = 0; j < SRV_HASH_SIZE; j++) {
2994 list_for_each_entry(server, &server_list[j], list) {
2995 list_for_each_entry(server_port,
2996 &server->server_port_list,
2997 list) {
2998 i += scnprintf(buf + i, max - i, "Service: "
2999 "0x%08x\n", server->name.service);
3000 i += scnprintf(buf + i, max - i, "Instance: "
3001 "0x%08x\n", server->name.instance);
3002 i += scnprintf(buf + i, max - i,
3003 "Node_id: 0x%08x\n",
3004 server_port->server_addr.node_id);
3005 i += scnprintf(buf + i, max - i,
3006 "Port_id: 0x%08x\n",
3007 server_port->server_addr.port_id);
3008 i += scnprintf(buf + i, max - i, "\n");
3009 }
3010 }
3011 }
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06003012 up_read(&server_list_lock_lha2);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003013
3014 return i;
3015}
3016
3017static int dump_remote_ports(char *buf, int max)
3018{
3019 int i = 0, j, k;
3020 struct msm_ipc_router_remote_port *rport_ptr;
3021 struct msm_ipc_routing_table_entry *rt_entry;
3022
3023 for (j = 0; j < RT_HASH_SIZE; j++) {
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06003024 down_read(&routing_table_lock_lha3);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003025 list_for_each_entry(rt_entry, &routing_table[j], list) {
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06003026 down_read(&rt_entry->lock_lha4);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003027 for (k = 0; k < RP_HASH_SIZE; k++) {
3028 list_for_each_entry(rport_ptr,
3029 &rt_entry->remote_port_list[k],
3030 list) {
3031 i += scnprintf(buf + i, max - i,
3032 "Node_id: 0x%08x\n",
3033 rport_ptr->node_id);
3034 i += scnprintf(buf + i, max - i,
3035 "Port_id: 0x%08x\n",
3036 rport_ptr->port_id);
3037 i += scnprintf(buf + i, max - i,
3038 "Quota_cnt: %d\n",
3039 rport_ptr->tx_quota_cnt);
3040 i += scnprintf(buf + i, max - i, "\n");
3041 }
3042 }
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06003043 up_read(&rt_entry->lock_lha4);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003044 }
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06003045 up_read(&routing_table_lock_lha3);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003046 }
3047
3048 return i;
3049}
3050
3051static int dump_control_ports(char *buf, int max)
3052{
3053 int i = 0;
3054 struct msm_ipc_port *port_ptr;
3055
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06003056 down_read(&control_ports_lock_lha5);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003057 list_for_each_entry(port_ptr, &control_ports, list) {
3058 i += scnprintf(buf + i, max - i, "Node_id: 0x%08x\n",
3059 port_ptr->this_port.node_id);
3060 i += scnprintf(buf + i, max - i, "Port_id: 0x%08x\n",
3061 port_ptr->this_port.port_id);
3062 i += scnprintf(buf + i, max - i, "\n");
3063 }
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06003064 up_read(&control_ports_lock_lha5);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003065
3066 return i;
3067}
3068
3069static int dump_local_ports(char *buf, int max)
3070{
3071 int i = 0, j;
3072 unsigned long flags;
3073 struct msm_ipc_port *port_ptr;
3074
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06003075 down_read(&local_ports_lock_lha2);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003076 for (j = 0; j < LP_HASH_SIZE; j++) {
3077 list_for_each_entry(port_ptr, &local_ports[j], list) {
3078 spin_lock_irqsave(&port_ptr->port_lock, flags);
3079 i += scnprintf(buf + i, max - i, "Node_id: 0x%08x\n",
3080 port_ptr->this_port.node_id);
3081 i += scnprintf(buf + i, max - i, "Port_id: 0x%08x\n",
3082 port_ptr->this_port.port_id);
3083 i += scnprintf(buf + i, max - i, "# pkts tx'd %d\n",
3084 port_ptr->num_tx);
3085 i += scnprintf(buf + i, max - i, "# pkts rx'd %d\n",
3086 port_ptr->num_rx);
3087 i += scnprintf(buf + i, max - i, "# bytes tx'd %ld\n",
3088 port_ptr->num_tx_bytes);
3089 i += scnprintf(buf + i, max - i, "# bytes rx'd %ld\n",
3090 port_ptr->num_rx_bytes);
3091 spin_unlock_irqrestore(&port_ptr->port_lock, flags);
3092 i += scnprintf(buf + i, max - i, "\n");
3093 }
3094 }
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06003095 up_read(&local_ports_lock_lha2);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003096
3097 return i;
3098}
3099
3100#define DEBUG_BUFMAX 4096
3101static char debug_buffer[DEBUG_BUFMAX];
3102
3103static ssize_t debug_read(struct file *file, char __user *buf,
3104 size_t count, loff_t *ppos)
3105{
3106 int (*fill)(char *buf, int max) = file->private_data;
3107 int bsize = fill(debug_buffer, DEBUG_BUFMAX);
3108 return simple_read_from_buffer(buf, count, ppos, debug_buffer, bsize);
3109}
3110
3111static int debug_open(struct inode *inode, struct file *file)
3112{
3113 file->private_data = inode->i_private;
3114 return 0;
3115}
3116
3117static const struct file_operations debug_ops = {
3118 .read = debug_read,
3119 .open = debug_open,
3120};
3121
3122static void debug_create(const char *name, mode_t mode,
3123 struct dentry *dent,
3124 int (*fill)(char *buf, int max))
3125{
3126 debugfs_create_file(name, mode, dent, fill, &debug_ops);
3127}
3128
3129static void debugfs_init(void)
3130{
3131 struct dentry *dent;
3132
3133 dent = debugfs_create_dir("msm_ipc_router", 0);
3134 if (IS_ERR(dent))
3135 return;
3136
3137 debug_create("dump_local_ports", 0444, dent,
3138 dump_local_ports);
3139 debug_create("dump_remote_ports", 0444, dent,
3140 dump_remote_ports);
3141 debug_create("dump_control_ports", 0444, dent,
3142 dump_control_ports);
3143 debug_create("dump_servers", 0444, dent,
3144 dump_servers);
3145 debug_create("dump_xprt_info", 0444, dent,
3146 dump_xprt_info);
3147 debug_create("dump_routing_table", 0444, dent,
3148 dump_routing_table);
3149}
3150
3151#else
3152static void debugfs_init(void) {}
3153#endif
3154
3155static int msm_ipc_router_add_xprt(struct msm_ipc_router_xprt *xprt)
3156{
3157 struct msm_ipc_router_xprt_info *xprt_info;
3158 struct msm_ipc_routing_table_entry *rt_entry;
3159
3160 xprt_info = kmalloc(sizeof(struct msm_ipc_router_xprt_info),
3161 GFP_KERNEL);
3162 if (!xprt_info)
3163 return -ENOMEM;
3164
3165 xprt_info->xprt = xprt;
3166 xprt_info->initialized = 0;
3167 xprt_info->remote_node_id = -1;
3168 INIT_LIST_HEAD(&xprt_info->pkt_list);
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06003169 mutex_init(&xprt_info->rx_lock_lhb2);
3170 mutex_init(&xprt_info->tx_lock_lhb2);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003171 wake_lock_init(&xprt_info->wakelock,
3172 WAKE_LOCK_SUSPEND, xprt->name);
3173 xprt_info->need_len = 0;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06003174 xprt_info->abort_data_read = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003175 INIT_WORK(&xprt_info->read_data, do_read_data);
3176 INIT_LIST_HEAD(&xprt_info->list);
3177
3178 xprt_info->workqueue = create_singlethread_workqueue(xprt->name);
3179 if (!xprt_info->workqueue) {
3180 kfree(xprt_info);
3181 return -ENOMEM;
3182 }
3183
3184 if (!strcmp(xprt->name, "msm_ipc_router_loopback_xprt")) {
3185 xprt_info->remote_node_id = IPC_ROUTER_NID_LOCAL;
3186 xprt_info->initialized = 1;
3187 }
3188
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06003189 down_write(&xprt_info_list_lock_lha5);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003190 list_add_tail(&xprt_info->list, &xprt_info_list);
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06003191 up_write(&xprt_info_list_lock_lha5);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003192
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06003193 down_write(&routing_table_lock_lha3);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003194 if (!routing_table_inited) {
3195 init_routing_table();
3196 rt_entry = alloc_routing_table_entry(IPC_ROUTER_NID_LOCAL);
3197 add_routing_table_entry(rt_entry);
3198 routing_table_inited = 1;
3199 }
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06003200 up_write(&routing_table_lock_lha3);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003201
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003202 xprt->priv = xprt_info;
3203
3204 return 0;
3205}
3206
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06003207static void msm_ipc_router_remove_xprt(struct msm_ipc_router_xprt *xprt)
3208{
3209 struct msm_ipc_router_xprt_info *xprt_info;
3210
3211 if (xprt && xprt->priv) {
3212 xprt_info = xprt->priv;
3213
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06003214 mutex_lock(&xprt_info->rx_lock_lhb2);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06003215 xprt_info->abort_data_read = 1;
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06003216 mutex_unlock(&xprt_info->rx_lock_lhb2);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06003217
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06003218 down_write(&xprt_info_list_lock_lha5);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06003219 list_del(&xprt_info->list);
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06003220 up_write(&xprt_info_list_lock_lha5);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06003221
3222 flush_workqueue(xprt_info->workqueue);
3223 destroy_workqueue(xprt_info->workqueue);
3224 wake_lock_destroy(&xprt_info->wakelock);
3225
3226 xprt->priv = 0;
3227 kfree(xprt_info);
3228 }
3229}
3230
3231
3232struct msm_ipc_router_xprt_work {
3233 struct msm_ipc_router_xprt *xprt;
3234 struct work_struct work;
3235};
3236
3237static void xprt_open_worker(struct work_struct *work)
3238{
3239 struct msm_ipc_router_xprt_work *xprt_work =
3240 container_of(work, struct msm_ipc_router_xprt_work, work);
3241
3242 msm_ipc_router_add_xprt(xprt_work->xprt);
3243 kfree(xprt_work);
3244}
3245
3246static void xprt_close_worker(struct work_struct *work)
3247{
3248 struct msm_ipc_router_xprt_work *xprt_work =
3249 container_of(work, struct msm_ipc_router_xprt_work, work);
3250
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06003251 msm_ipc_cleanup_routing_table(xprt_work->xprt->priv);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06003252 msm_ipc_router_remove_xprt(xprt_work->xprt);
Zaheerulla Meer35893a62013-06-19 16:54:44 +05303253 xprt_work->xprt->sft_close_done(xprt_work->xprt);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06003254 kfree(xprt_work);
3255}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003256
3257void msm_ipc_router_xprt_notify(struct msm_ipc_router_xprt *xprt,
3258 unsigned event,
3259 void *data)
3260{
3261 struct msm_ipc_router_xprt_info *xprt_info = xprt->priv;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06003262 struct msm_ipc_router_xprt_work *xprt_work;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003263 struct rr_packet *pkt;
Karthikeyan Ramasubramanian4af9f7c2011-09-30 15:55:18 -06003264 unsigned long ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003265
Karthikeyan Ramasubramanian4af9f7c2011-09-30 15:55:18 -06003266 if (!msm_ipc_router_workqueue) {
3267 ret = wait_for_completion_timeout(&msm_ipc_local_router_up,
3268 IPC_ROUTER_INIT_TIMEOUT);
3269 if (!ret || !msm_ipc_router_workqueue) {
3270 pr_err("%s: IPC Router not initialized\n", __func__);
3271 return;
3272 }
3273 }
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06003274
3275 switch (event) {
3276 case IPC_ROUTER_XPRT_EVENT_OPEN:
3277 D("open event for '%s'\n", xprt->name);
3278 xprt_work = kmalloc(sizeof(struct msm_ipc_router_xprt_work),
3279 GFP_ATOMIC);
Karthikeyan Ramasubramanianc51456c2013-05-16 15:51:29 -06003280 if (xprt_work) {
3281 xprt_work->xprt = xprt;
3282 INIT_WORK(&xprt_work->work, xprt_open_worker);
3283 queue_work(msm_ipc_router_workqueue, &xprt_work->work);
3284 } else {
3285 pr_err("%s: malloc failure - Couldn't notify OPEN event",
3286 __func__);
3287 }
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06003288 break;
3289
3290 case IPC_ROUTER_XPRT_EVENT_CLOSE:
3291 D("close event for '%s'\n", xprt->name);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06003292 xprt_work = kmalloc(sizeof(struct msm_ipc_router_xprt_work),
3293 GFP_ATOMIC);
Karthikeyan Ramasubramanianc51456c2013-05-16 15:51:29 -06003294 if (xprt_work) {
3295 xprt_work->xprt = xprt;
3296 INIT_WORK(&xprt_work->work, xprt_close_worker);
3297 queue_work(msm_ipc_router_workqueue, &xprt_work->work);
3298 } else {
3299 pr_err("%s: malloc failure - Couldn't notify CLOSE event",
3300 __func__);
3301 }
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06003302 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003303 }
3304
3305 if (!data)
3306 return;
3307
3308 while (!xprt_info) {
3309 msleep(100);
3310 xprt_info = xprt->priv;
3311 }
3312
3313 pkt = clone_pkt((struct rr_packet *)data);
3314 if (!pkt)
3315 return;
3316
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06003317 mutex_lock(&xprt_info->rx_lock_lhb2);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003318 list_add_tail(&pkt->list, &xprt_info->pkt_list);
3319 wake_lock(&xprt_info->wakelock);
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06003320 mutex_unlock(&xprt_info->rx_lock_lhb2);
Karthikeyan Ramasubramanian872ecd82012-07-25 11:07:48 -06003321 queue_work(xprt_info->workqueue, &xprt_info->read_data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003322}
3323
3324static int __init msm_ipc_router_init(void)
3325{
3326 int i, ret;
3327 struct msm_ipc_routing_table_entry *rt_entry;
3328
3329 msm_ipc_router_debug_mask |= SMEM_LOG;
Karthikeyan Ramasubramanian682ebcc2013-03-22 10:47:20 -06003330 ipc_rtr_log_ctxt = ipc_log_context_create(IPC_RTR_LOG_PAGES,
3331 "ipc_router");
3332 if (!ipc_rtr_log_ctxt)
3333 pr_err("%s: Unable to create IPC logging for IPC RTR",
3334 __func__);
3335
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -06003336 msm_ipc_router_workqueue =
3337 create_singlethread_workqueue("msm_ipc_router");
3338 if (!msm_ipc_router_workqueue)
3339 return -ENOMEM;
3340
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003341 debugfs_init();
3342
3343 for (i = 0; i < SRV_HASH_SIZE; i++)
3344 INIT_LIST_HEAD(&server_list[i]);
3345
3346 for (i = 0; i < LP_HASH_SIZE; i++)
3347 INIT_LIST_HEAD(&local_ports[i]);
3348
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06003349 down_write(&routing_table_lock_lha3);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003350 if (!routing_table_inited) {
3351 init_routing_table();
3352 rt_entry = alloc_routing_table_entry(IPC_ROUTER_NID_LOCAL);
3353 add_routing_table_entry(rt_entry);
3354 routing_table_inited = 1;
3355 }
Karthikeyan Ramasubramaniand06fe072013-05-21 11:49:21 -06003356 up_write(&routing_table_lock_lha3);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003357
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003358 ret = msm_ipc_router_init_sockets();
3359 if (ret < 0)
3360 pr_err("%s: Init sockets failed\n", __func__);
3361
Karthikeyan Ramasubramanian1668cc62012-09-23 22:23:36 -06003362 ret = msm_ipc_router_security_init();
3363 if (ret < 0)
3364 pr_err("%s: Security Init failed\n", __func__);
3365
Karthikeyan Ramasubramanian4af9f7c2011-09-30 15:55:18 -06003366 complete_all(&msm_ipc_local_router_up);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003367 return ret;
3368}
3369
3370module_init(msm_ipc_router_init);
3371MODULE_DESCRIPTION("MSM IPC Router");
3372MODULE_LICENSE("GPL v2");