blob: 6960d2e89f805f0d27d139a9bae8da05b3132dec [file] [log] [blame]
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -07001/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13/*
14 * IPC ROUTER SMD XPRT module.
15 */
16#define DEBUG
17
18#include <linux/platform_device.h>
19#include <linux/types.h>
20
21#include <mach/msm_smd.h>
22
23#include "ipc_router.h"
24#include "smd_private.h"
25
26static int msm_ipc_router_smd_xprt_debug_mask;
27module_param_named(debug_mask, msm_ipc_router_smd_xprt_debug_mask,
28 int, S_IRUGO | S_IWUSR | S_IWGRP);
29
30#if defined(DEBUG)
31#define D(x...) do { \
32if (msm_ipc_router_smd_xprt_debug_mask) \
33 pr_info(x); \
34} while (0)
35#else
36#define D(x...) do { } while (0)
37#endif
38
39#define MIN_FRAG_SZ (IPC_ROUTER_HDR_SIZE + sizeof(union rr_control_msg))
40
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -070041#define NUM_SMD_XPRTS 2
42#define XPRT_NAME_LEN (SMD_MAX_CH_NAME_LEN + 12)
43
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070044struct msm_ipc_router_smd_xprt {
45 struct msm_ipc_router_xprt xprt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070046 smd_channel_t *channel;
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -070047 struct workqueue_struct *smd_xprt_wq;
48 wait_queue_head_t write_avail_wait_q;
49 struct rr_packet *in_pkt;
50 int is_partial_in_pkt;
51 struct delayed_work read_work;
52 spinlock_t ss_reset_lock; /*Subsystem reset lock*/
53 int ss_reset;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070054};
55
Karthikeyan Ramasubramaniandd7daab2011-09-30 15:16:59 -060056struct msm_ipc_router_smd_xprt_work {
57 struct msm_ipc_router_xprt *xprt;
58 struct work_struct work;
59};
60
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070061static void smd_xprt_read_data(struct work_struct *work);
Karthikeyan Ramasubramaniandd7daab2011-09-30 15:16:59 -060062static void smd_xprt_open_event(struct work_struct *work);
63static void smd_xprt_close_event(struct work_struct *work);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070064
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -070065struct msm_ipc_router_smd_xprt_config {
66 char ch_name[SMD_MAX_CH_NAME_LEN];
67 char xprt_name[XPRT_NAME_LEN];
68 uint32_t edge;
69 uint32_t link_id;
70};
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070071
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -070072struct msm_ipc_router_smd_xprt_config smd_xprt_cfg[] = {
73 {"RPCRPY_CNTL", "ipc_rtr_smd_rpcrpy_cntl", SMD_APPS_MODEM, 1},
74 {"IPCRTR", "ipc_rtr_smd_ipcrtr", SMD_APPS_MODEM, 1},
75};
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -060076
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -070077static struct msm_ipc_router_smd_xprt smd_remote_xprt[NUM_SMD_XPRTS];
78
79static int find_smd_xprt_cfg(const char *name)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070080{
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -070081 int i;
82
83 for (i = 0; i < NUM_SMD_XPRTS; i++) {
84 if (!strncmp(name, smd_xprt_cfg[i].ch_name, 20))
85 return i;
86 }
87
88 return -ENODEV;
89}
90
91static int msm_ipc_router_smd_remote_write_avail(
92 struct msm_ipc_router_xprt *xprt)
93{
94 struct msm_ipc_router_smd_xprt *smd_xprtp =
95 container_of(xprt, struct msm_ipc_router_smd_xprt, xprt);
96
97 return smd_write_avail(smd_xprtp->channel);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070098}
99
100static int msm_ipc_router_smd_remote_write(void *data,
101 uint32_t len,
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700102 struct msm_ipc_router_xprt *xprt)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700103{
104 struct rr_packet *pkt = (struct rr_packet *)data;
105 struct sk_buff *ipc_rtr_pkt;
106 int align_sz, align_data = 0;
107 int offset, sz_written = 0;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600108 int ret, num_retries = 0;
109 unsigned long flags;
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700110 struct msm_ipc_router_smd_xprt *smd_xprtp =
111 container_of(xprt, struct msm_ipc_router_smd_xprt, xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700112
113 if (!pkt)
114 return -EINVAL;
115
116 if (!len || pkt->length != len)
117 return -EINVAL;
118
119 align_sz = ALIGN_SIZE(pkt->length);
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700120 while ((ret = smd_write_start(smd_xprtp->channel,
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600121 (len + align_sz))) < 0) {
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700122 spin_lock_irqsave(&smd_xprtp->ss_reset_lock, flags);
123 if (smd_xprtp->ss_reset) {
124 spin_unlock_irqrestore(&smd_xprtp->ss_reset_lock,
125 flags);
126 pr_err("%s: %s chnl reset\n", __func__, xprt->name);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600127 return -ENETRESET;
128 }
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700129 spin_unlock_irqrestore(&smd_xprtp->ss_reset_lock, flags);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600130 if (num_retries >= 5) {
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700131 pr_err("%s: Error %d @smd_write_start for %s\n",
132 __func__, ret, xprt->name);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600133 return ret;
134 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700135 msleep(50);
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700136 num_retries++;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600137 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700138
139 D("%s: Ready to write\n", __func__);
140 skb_queue_walk(pkt->pkt_fragment_q, ipc_rtr_pkt) {
141 offset = 0;
142 while (offset < ipc_rtr_pkt->len) {
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700143 if (!smd_write_avail(smd_xprtp->channel))
144 smd_enable_read_intr(smd_xprtp->channel);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700145
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700146 wait_event(smd_xprtp->write_avail_wait_q,
147 (smd_write_avail(smd_xprtp->channel) ||
148 smd_xprtp->ss_reset));
149 smd_disable_read_intr(smd_xprtp->channel);
150 spin_lock_irqsave(&smd_xprtp->ss_reset_lock, flags);
151 if (smd_xprtp->ss_reset) {
152 spin_unlock_irqrestore(
153 &smd_xprtp->ss_reset_lock, flags);
154 pr_err("%s: %s chnl reset\n",
155 __func__, xprt->name);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600156 return -ENETRESET;
157 }
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700158 spin_unlock_irqrestore(&smd_xprtp->ss_reset_lock,
159 flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700160
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700161 sz_written = smd_write_segment(smd_xprtp->channel,
162 ipc_rtr_pkt->data + offset,
163 (ipc_rtr_pkt->len - offset), 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700164 offset += sz_written;
165 sz_written = 0;
166 }
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700167 D("%s: Wrote %d bytes over %s\n",
168 __func__, offset, xprt->name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700169 }
170
171 if (align_sz) {
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700172 if (smd_write_avail(smd_xprtp->channel) < align_sz)
173 smd_enable_read_intr(smd_xprtp->channel);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700174
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700175 wait_event(smd_xprtp->write_avail_wait_q,
176 ((smd_write_avail(smd_xprtp->channel) >=
177 align_sz) || smd_xprtp->ss_reset));
178 smd_disable_read_intr(smd_xprtp->channel);
179 spin_lock_irqsave(&smd_xprtp->ss_reset_lock, flags);
180 if (smd_xprtp->ss_reset) {
181 spin_unlock_irqrestore(
182 &smd_xprtp->ss_reset_lock, flags);
183 pr_err("%s: %s chnl reset\n",
184 __func__, xprt->name);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600185 return -ENETRESET;
186 }
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700187 spin_unlock_irqrestore(&smd_xprtp->ss_reset_lock,
188 flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700189
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700190 smd_write_segment(smd_xprtp->channel,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700191 &align_data, align_sz, 0);
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700192 D("%s: Wrote %d align bytes over %s\n",
193 __func__, align_sz, xprt->name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700194 }
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700195 if (!smd_write_end(smd_xprtp->channel))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700196 D("%s: Finished writing\n", __func__);
197 return len;
198}
199
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700200static int msm_ipc_router_smd_remote_close(struct msm_ipc_router_xprt *xprt)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700201{
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700202 struct msm_ipc_router_smd_xprt *smd_xprtp =
203 container_of(xprt, struct msm_ipc_router_smd_xprt, xprt);
204
205 return smd_close(smd_xprtp->channel);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700206}
207
208static void smd_xprt_read_data(struct work_struct *work)
209{
210 int pkt_size, sz_read, sz;
211 struct sk_buff *ipc_rtr_pkt;
212 void *data;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600213 unsigned long flags;
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700214 struct delayed_work *rwork = to_delayed_work(work);
215 struct msm_ipc_router_smd_xprt *smd_xprtp =
216 container_of(rwork, struct msm_ipc_router_smd_xprt, read_work);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600217
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700218 spin_lock_irqsave(&smd_xprtp->ss_reset_lock, flags);
219 if (smd_xprtp->ss_reset) {
220 spin_unlock_irqrestore(&smd_xprtp->ss_reset_lock, flags);
221 if (smd_xprtp->in_pkt)
222 release_pkt(smd_xprtp->in_pkt);
223 smd_xprtp->is_partial_in_pkt = 0;
224 pr_err("%s: %s channel reset\n",
225 __func__, smd_xprtp->xprt.name);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600226 return;
227 }
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700228 spin_unlock_irqrestore(&smd_xprtp->ss_reset_lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700229
230 D("%s pkt_size: %d, read_avail: %d\n", __func__,
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700231 smd_cur_packet_size(smd_xprtp->channel),
232 smd_read_avail(smd_xprtp->channel));
233 while ((pkt_size = smd_cur_packet_size(smd_xprtp->channel)) &&
234 smd_read_avail(smd_xprtp->channel)) {
235 if (!smd_xprtp->is_partial_in_pkt) {
236 smd_xprtp->in_pkt = kzalloc(sizeof(struct rr_packet),
237 GFP_KERNEL);
238 if (!smd_xprtp->in_pkt) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700239 pr_err("%s: Couldn't alloc rr_packet\n",
240 __func__);
241 return;
242 }
243
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700244 smd_xprtp->in_pkt->pkt_fragment_q =
245 kmalloc(sizeof(struct sk_buff_head),
246 GFP_KERNEL);
247 if (!smd_xprtp->in_pkt->pkt_fragment_q) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700248 pr_err("%s: Couldn't alloc pkt_fragment_q\n",
249 __func__);
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700250 kfree(smd_xprtp->in_pkt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700251 return;
252 }
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700253 skb_queue_head_init(smd_xprtp->in_pkt->pkt_fragment_q);
254 smd_xprtp->is_partial_in_pkt = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700255 D("%s: Allocated rr_packet\n", __func__);
256 }
257
Karthikeyan Ramasubramanian51247a02011-10-12 14:53:15 -0600258 if (((pkt_size >= MIN_FRAG_SZ) &&
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700259 (smd_read_avail(smd_xprtp->channel) < MIN_FRAG_SZ)) ||
Karthikeyan Ramasubramanian51247a02011-10-12 14:53:15 -0600260 ((pkt_size < MIN_FRAG_SZ) &&
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700261 (smd_read_avail(smd_xprtp->channel) < pkt_size)))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700262 return;
263
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700264 sz = smd_read_avail(smd_xprtp->channel);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700265 do {
266 ipc_rtr_pkt = alloc_skb(sz, GFP_KERNEL);
267 if (!ipc_rtr_pkt) {
268 if (sz <= (PAGE_SIZE/2)) {
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700269 queue_delayed_work(
270 smd_xprtp->smd_xprt_wq,
271 &smd_xprtp->read_work,
272 msecs_to_jiffies(100));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700273 return;
274 }
275 sz = sz / 2;
276 }
277 } while (!ipc_rtr_pkt);
278
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700279 D("%s: Allocated the sk_buff of size %d\n", __func__, sz);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700280 data = skb_put(ipc_rtr_pkt, sz);
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700281 sz_read = smd_read(smd_xprtp->channel, data, sz);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700282 if (sz_read != sz) {
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700283 pr_err("%s: Couldn't read %s completely\n",
284 __func__, smd_xprtp->xprt.name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700285 kfree_skb(ipc_rtr_pkt);
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700286 release_pkt(smd_xprtp->in_pkt);
287 smd_xprtp->is_partial_in_pkt = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700288 return;
289 }
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700290 skb_queue_tail(smd_xprtp->in_pkt->pkt_fragment_q, ipc_rtr_pkt);
291 smd_xprtp->in_pkt->length += sz_read;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700292 if (sz_read != pkt_size)
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700293 smd_xprtp->is_partial_in_pkt = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700294 else
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700295 smd_xprtp->is_partial_in_pkt = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700296
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700297 if (!smd_xprtp->is_partial_in_pkt) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700298 D("%s: Packet size read %d\n",
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700299 __func__, smd_xprtp->in_pkt->length);
300 msm_ipc_router_xprt_notify(&smd_xprtp->xprt,
301 IPC_ROUTER_XPRT_EVENT_DATA,
302 (void *)smd_xprtp->in_pkt);
303 release_pkt(smd_xprtp->in_pkt);
304 smd_xprtp->in_pkt = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700305 }
306 }
307}
308
Karthikeyan Ramasubramaniandd7daab2011-09-30 15:16:59 -0600309static void smd_xprt_open_event(struct work_struct *work)
310{
311 struct msm_ipc_router_smd_xprt_work *xprt_work =
312 container_of(work, struct msm_ipc_router_smd_xprt_work, work);
313
314 msm_ipc_router_xprt_notify(xprt_work->xprt,
315 IPC_ROUTER_XPRT_EVENT_OPEN, NULL);
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700316 D("%s: Notified IPC Router of %s OPEN\n",
317 __func__, xprt_work->xprt->name);
Karthikeyan Ramasubramaniandd7daab2011-09-30 15:16:59 -0600318 kfree(xprt_work);
319}
320
321static void smd_xprt_close_event(struct work_struct *work)
322{
323 struct msm_ipc_router_smd_xprt_work *xprt_work =
324 container_of(work, struct msm_ipc_router_smd_xprt_work, work);
325
326 msm_ipc_router_xprt_notify(xprt_work->xprt,
327 IPC_ROUTER_XPRT_EVENT_CLOSE, NULL);
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700328 D("%s: Notified IPC Router of %s CLOSE\n",
329 __func__, xprt_work->xprt->name);
Karthikeyan Ramasubramaniandd7daab2011-09-30 15:16:59 -0600330 kfree(xprt_work);
331}
332
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700333static void msm_ipc_router_smd_remote_notify(void *_dev, unsigned event)
334{
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600335 unsigned long flags;
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700336 struct msm_ipc_router_smd_xprt *smd_xprtp;
Karthikeyan Ramasubramaniandd7daab2011-09-30 15:16:59 -0600337 struct msm_ipc_router_smd_xprt_work *xprt_work;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600338
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700339 smd_xprtp = (struct msm_ipc_router_smd_xprt *)_dev;
340 if (!smd_xprtp)
341 return;
342
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600343 switch (event) {
344 case SMD_EVENT_DATA:
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700345 if (smd_read_avail(smd_xprtp->channel))
346 queue_delayed_work(smd_xprtp->smd_xprt_wq,
347 &smd_xprtp->read_work, 0);
348 if (smd_write_avail(smd_xprtp->channel))
349 wake_up(&smd_xprtp->write_avail_wait_q);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600350 break;
351
352 case SMD_EVENT_OPEN:
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700353 spin_lock_irqsave(&smd_xprtp->ss_reset_lock, flags);
354 smd_xprtp->ss_reset = 0;
355 spin_unlock_irqrestore(&smd_xprtp->ss_reset_lock, flags);
Karthikeyan Ramasubramaniandd7daab2011-09-30 15:16:59 -0600356 xprt_work = kmalloc(sizeof(struct msm_ipc_router_smd_xprt_work),
357 GFP_ATOMIC);
358 if (!xprt_work) {
359 pr_err("%s: Couldn't notify %d event to IPC Router\n",
360 __func__, event);
361 return;
362 }
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700363 xprt_work->xprt = &smd_xprtp->xprt;
Karthikeyan Ramasubramaniandd7daab2011-09-30 15:16:59 -0600364 INIT_WORK(&xprt_work->work, smd_xprt_open_event);
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700365 queue_work(smd_xprtp->smd_xprt_wq, &xprt_work->work);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600366 break;
367
368 case SMD_EVENT_CLOSE:
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700369 spin_lock_irqsave(&smd_xprtp->ss_reset_lock, flags);
370 smd_xprtp->ss_reset = 1;
371 spin_unlock_irqrestore(&smd_xprtp->ss_reset_lock, flags);
372 wake_up(&smd_xprtp->write_avail_wait_q);
Karthikeyan Ramasubramaniandd7daab2011-09-30 15:16:59 -0600373 xprt_work = kmalloc(sizeof(struct msm_ipc_router_smd_xprt_work),
374 GFP_ATOMIC);
375 if (!xprt_work) {
376 pr_err("%s: Couldn't notify %d event to IPC Router\n",
377 __func__, event);
378 return;
379 }
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700380 xprt_work->xprt = &smd_xprtp->xprt;
Karthikeyan Ramasubramaniandd7daab2011-09-30 15:16:59 -0600381 INIT_WORK(&xprt_work->work, smd_xprt_close_event);
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700382 queue_work(smd_xprtp->smd_xprt_wq, &xprt_work->work);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600383 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700384 }
385}
386
387static int msm_ipc_router_smd_remote_probe(struct platform_device *pdev)
388{
389 int rc;
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700390 int id; /*Index into the smd_xprt_cfg table*/
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700391
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700392 id = find_smd_xprt_cfg(pdev->name);
393 if (id < 0) {
394 pr_err("%s: called for unknown ch %s\n",
395 __func__, pdev->name);
396 return id;
397 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700398
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700399 smd_remote_xprt[id].smd_xprt_wq =
400 create_singlethread_workqueue(pdev->name);
401 if (!smd_remote_xprt[id].smd_xprt_wq) {
402 pr_err("%s: WQ creation failed for %s\n",
403 __func__, pdev->name);
404 return -EFAULT;
405 }
406
407 smd_remote_xprt[id].xprt.name = smd_xprt_cfg[id].xprt_name;
408 smd_remote_xprt[id].xprt.link_id = smd_xprt_cfg[id].link_id;
409 smd_remote_xprt[id].xprt.read_avail = NULL;
410 smd_remote_xprt[id].xprt.read = NULL;
411 smd_remote_xprt[id].xprt.write_avail =
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700412 msm_ipc_router_smd_remote_write_avail;
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700413 smd_remote_xprt[id].xprt.write = msm_ipc_router_smd_remote_write;
414 smd_remote_xprt[id].xprt.close = msm_ipc_router_smd_remote_close;
415 smd_remote_xprt[id].xprt.priv = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700416
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700417 init_waitqueue_head(&smd_remote_xprt[id].write_avail_wait_q);
418 smd_remote_xprt[id].in_pkt = NULL;
419 smd_remote_xprt[id].is_partial_in_pkt = 0;
420 INIT_DELAYED_WORK(&smd_remote_xprt[id].read_work, smd_xprt_read_data);
421 spin_lock_init(&smd_remote_xprt[id].ss_reset_lock);
422 smd_remote_xprt[id].ss_reset = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700423
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700424 rc = smd_named_open_on_edge(smd_xprt_cfg[id].ch_name,
425 smd_xprt_cfg[id].edge,
426 &smd_remote_xprt[id].channel,
427 &smd_remote_xprt[id],
428 msm_ipc_router_smd_remote_notify);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700429 if (rc < 0) {
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700430 pr_err("%s: Channel open failed for %s\n",
431 __func__, smd_xprt_cfg[id].ch_name);
432 destroy_workqueue(smd_remote_xprt[id].smd_xprt_wq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700433 return rc;
434 }
435
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700436 smd_disable_read_intr(smd_remote_xprt[id].channel);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700437
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700438 smsm_change_state(SMSM_APPS_STATE, 0, SMSM_RPCINIT);
439
440 return 0;
441}
442
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700443static struct platform_driver msm_ipc_router_smd_remote_driver[] = {
444 {
445 .probe = msm_ipc_router_smd_remote_probe,
446 .driver = {
447 .name = "RPCRPY_CNTL",
448 .owner = THIS_MODULE,
449 },
450 },
451 {
452 .probe = msm_ipc_router_smd_remote_probe,
453 .driver = {
454 .name = "IPCRTR",
455 .owner = THIS_MODULE,
456 },
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700457 },
458};
459
460static int __init msm_ipc_router_smd_init(void)
461{
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700462 int i, ret, rc = 0;
463 BUG_ON(ARRAY_SIZE(msm_ipc_router_smd_remote_driver) != NUM_SMD_XPRTS);
464 BUG_ON(ARRAY_SIZE(smd_xprt_cfg) != NUM_SMD_XPRTS);
465 for (i = 0; i < NUM_SMD_XPRTS; i++) {
466 ret = platform_driver_register(
467 &msm_ipc_router_smd_remote_driver[i]);
468 if (ret) {
469 pr_err("%s: Failed to register platform driver for"
470 " xprt%d. Continuing...\n", __func__, i);
471 rc = ret;
472 }
473 }
474 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700475}
476
477module_init(msm_ipc_router_smd_init);
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700478MODULE_DESCRIPTION("IPC Router SMD XPRT");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700479MODULE_LICENSE("GPL v2");