blob: a5721c432d92411edc6e8daf7b57442cf1e8d3e0 [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>
Karthikeyan Ramasubramanian6b963bd2012-05-01 11:27:54 -060022#include <mach/peripheral-loader.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070023
24#include "ipc_router.h"
25#include "smd_private.h"
26
27static int msm_ipc_router_smd_xprt_debug_mask;
28module_param_named(debug_mask, msm_ipc_router_smd_xprt_debug_mask,
29 int, S_IRUGO | S_IWUSR | S_IWGRP);
30
31#if defined(DEBUG)
32#define D(x...) do { \
33if (msm_ipc_router_smd_xprt_debug_mask) \
34 pr_info(x); \
35} while (0)
36#else
37#define D(x...) do { } while (0)
38#endif
39
40#define MIN_FRAG_SZ (IPC_ROUTER_HDR_SIZE + sizeof(union rr_control_msg))
41
Karthikeyan Ramasubramanianccc47262012-03-07 11:59:33 -070042#define NUM_SMD_XPRTS 3
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -070043#define XPRT_NAME_LEN (SMD_MAX_CH_NAME_LEN + 12)
44
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070045struct msm_ipc_router_smd_xprt {
46 struct msm_ipc_router_xprt xprt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070047 smd_channel_t *channel;
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -070048 struct workqueue_struct *smd_xprt_wq;
49 wait_queue_head_t write_avail_wait_q;
50 struct rr_packet *in_pkt;
51 int is_partial_in_pkt;
52 struct delayed_work read_work;
53 spinlock_t ss_reset_lock; /*Subsystem reset lock*/
54 int ss_reset;
Karthikeyan Ramasubramanianc29692c2012-06-04 14:46:02 -060055 void *pil;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070056};
57
Karthikeyan Ramasubramaniandd7daab2011-09-30 15:16:59 -060058struct msm_ipc_router_smd_xprt_work {
59 struct msm_ipc_router_xprt *xprt;
60 struct work_struct work;
61};
62
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070063static void smd_xprt_read_data(struct work_struct *work);
Karthikeyan Ramasubramaniandd7daab2011-09-30 15:16:59 -060064static void smd_xprt_open_event(struct work_struct *work);
65static void smd_xprt_close_event(struct work_struct *work);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070066
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -070067struct msm_ipc_router_smd_xprt_config {
68 char ch_name[SMD_MAX_CH_NAME_LEN];
69 char xprt_name[XPRT_NAME_LEN];
70 uint32_t edge;
71 uint32_t link_id;
72};
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070073
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -070074struct msm_ipc_router_smd_xprt_config smd_xprt_cfg[] = {
75 {"RPCRPY_CNTL", "ipc_rtr_smd_rpcrpy_cntl", SMD_APPS_MODEM, 1},
76 {"IPCRTR", "ipc_rtr_smd_ipcrtr", SMD_APPS_MODEM, 1},
Karthikeyan Ramasubramanianccc47262012-03-07 11:59:33 -070077 {"IPCRTR", "ipc_rtr_q6_ipcrtr", SMD_APPS_QDSP, 1},
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -070078};
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -060079
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -070080static struct msm_ipc_router_smd_xprt smd_remote_xprt[NUM_SMD_XPRTS];
81
Karthikeyan Ramasubramanianccc47262012-03-07 11:59:33 -070082static int find_smd_xprt_cfg(struct platform_device *pdev)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070083{
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -070084 int i;
85
86 for (i = 0; i < NUM_SMD_XPRTS; i++) {
Karthikeyan Ramasubramanianccc47262012-03-07 11:59:33 -070087 if (!strncmp(pdev->name, smd_xprt_cfg[i].ch_name, 20) &&
88 (pdev->id == smd_xprt_cfg[i].edge))
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -070089 return i;
90 }
91
92 return -ENODEV;
93}
94
95static int msm_ipc_router_smd_remote_write_avail(
96 struct msm_ipc_router_xprt *xprt)
97{
98 struct msm_ipc_router_smd_xprt *smd_xprtp =
99 container_of(xprt, struct msm_ipc_router_smd_xprt, xprt);
100
101 return smd_write_avail(smd_xprtp->channel);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700102}
103
104static int msm_ipc_router_smd_remote_write(void *data,
105 uint32_t len,
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700106 struct msm_ipc_router_xprt *xprt)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700107{
108 struct rr_packet *pkt = (struct rr_packet *)data;
109 struct sk_buff *ipc_rtr_pkt;
110 int align_sz, align_data = 0;
111 int offset, sz_written = 0;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600112 int ret, num_retries = 0;
113 unsigned long flags;
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700114 struct msm_ipc_router_smd_xprt *smd_xprtp =
115 container_of(xprt, struct msm_ipc_router_smd_xprt, xprt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700116
117 if (!pkt)
118 return -EINVAL;
119
120 if (!len || pkt->length != len)
121 return -EINVAL;
122
123 align_sz = ALIGN_SIZE(pkt->length);
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700124 while ((ret = smd_write_start(smd_xprtp->channel,
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600125 (len + align_sz))) < 0) {
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700126 spin_lock_irqsave(&smd_xprtp->ss_reset_lock, flags);
127 if (smd_xprtp->ss_reset) {
128 spin_unlock_irqrestore(&smd_xprtp->ss_reset_lock,
129 flags);
130 pr_err("%s: %s chnl reset\n", __func__, xprt->name);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600131 return -ENETRESET;
132 }
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700133 spin_unlock_irqrestore(&smd_xprtp->ss_reset_lock, flags);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600134 if (num_retries >= 5) {
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700135 pr_err("%s: Error %d @smd_write_start for %s\n",
136 __func__, ret, xprt->name);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600137 return ret;
138 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700139 msleep(50);
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700140 num_retries++;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600141 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700142
143 D("%s: Ready to write\n", __func__);
144 skb_queue_walk(pkt->pkt_fragment_q, ipc_rtr_pkt) {
145 offset = 0;
146 while (offset < ipc_rtr_pkt->len) {
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700147 if (!smd_write_avail(smd_xprtp->channel))
148 smd_enable_read_intr(smd_xprtp->channel);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700149
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700150 wait_event(smd_xprtp->write_avail_wait_q,
151 (smd_write_avail(smd_xprtp->channel) ||
152 smd_xprtp->ss_reset));
153 smd_disable_read_intr(smd_xprtp->channel);
154 spin_lock_irqsave(&smd_xprtp->ss_reset_lock, flags);
155 if (smd_xprtp->ss_reset) {
156 spin_unlock_irqrestore(
157 &smd_xprtp->ss_reset_lock, flags);
158 pr_err("%s: %s chnl reset\n",
159 __func__, xprt->name);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600160 return -ENETRESET;
161 }
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700162 spin_unlock_irqrestore(&smd_xprtp->ss_reset_lock,
163 flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700164
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700165 sz_written = smd_write_segment(smd_xprtp->channel,
166 ipc_rtr_pkt->data + offset,
167 (ipc_rtr_pkt->len - offset), 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700168 offset += sz_written;
169 sz_written = 0;
170 }
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700171 D("%s: Wrote %d bytes over %s\n",
172 __func__, offset, xprt->name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700173 }
174
175 if (align_sz) {
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700176 if (smd_write_avail(smd_xprtp->channel) < align_sz)
177 smd_enable_read_intr(smd_xprtp->channel);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700178
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700179 wait_event(smd_xprtp->write_avail_wait_q,
180 ((smd_write_avail(smd_xprtp->channel) >=
181 align_sz) || smd_xprtp->ss_reset));
182 smd_disable_read_intr(smd_xprtp->channel);
183 spin_lock_irqsave(&smd_xprtp->ss_reset_lock, flags);
184 if (smd_xprtp->ss_reset) {
185 spin_unlock_irqrestore(
186 &smd_xprtp->ss_reset_lock, flags);
187 pr_err("%s: %s chnl reset\n",
188 __func__, xprt->name);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600189 return -ENETRESET;
190 }
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700191 spin_unlock_irqrestore(&smd_xprtp->ss_reset_lock,
192 flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700193
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700194 smd_write_segment(smd_xprtp->channel,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700195 &align_data, align_sz, 0);
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700196 D("%s: Wrote %d align bytes over %s\n",
197 __func__, align_sz, xprt->name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700198 }
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700199 if (!smd_write_end(smd_xprtp->channel))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700200 D("%s: Finished writing\n", __func__);
201 return len;
202}
203
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700204static int msm_ipc_router_smd_remote_close(struct msm_ipc_router_xprt *xprt)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700205{
Karthikeyan Ramasubramanianc29692c2012-06-04 14:46:02 -0600206 int rc;
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700207 struct msm_ipc_router_smd_xprt *smd_xprtp =
208 container_of(xprt, struct msm_ipc_router_smd_xprt, xprt);
209
Karthikeyan Ramasubramanianc29692c2012-06-04 14:46:02 -0600210 rc = smd_close(smd_xprtp->channel);
211 if (smd_xprtp->pil) {
212 pil_put(smd_xprtp->pil);
213 smd_xprtp->pil = NULL;
214 }
215 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700216}
217
218static void smd_xprt_read_data(struct work_struct *work)
219{
220 int pkt_size, sz_read, sz;
221 struct sk_buff *ipc_rtr_pkt;
222 void *data;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600223 unsigned long flags;
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700224 struct delayed_work *rwork = to_delayed_work(work);
225 struct msm_ipc_router_smd_xprt *smd_xprtp =
226 container_of(rwork, struct msm_ipc_router_smd_xprt, read_work);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600227
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700228 spin_lock_irqsave(&smd_xprtp->ss_reset_lock, flags);
229 if (smd_xprtp->ss_reset) {
230 spin_unlock_irqrestore(&smd_xprtp->ss_reset_lock, flags);
231 if (smd_xprtp->in_pkt)
232 release_pkt(smd_xprtp->in_pkt);
233 smd_xprtp->is_partial_in_pkt = 0;
234 pr_err("%s: %s channel reset\n",
235 __func__, smd_xprtp->xprt.name);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600236 return;
237 }
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700238 spin_unlock_irqrestore(&smd_xprtp->ss_reset_lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700239
240 D("%s pkt_size: %d, read_avail: %d\n", __func__,
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700241 smd_cur_packet_size(smd_xprtp->channel),
242 smd_read_avail(smd_xprtp->channel));
243 while ((pkt_size = smd_cur_packet_size(smd_xprtp->channel)) &&
244 smd_read_avail(smd_xprtp->channel)) {
245 if (!smd_xprtp->is_partial_in_pkt) {
246 smd_xprtp->in_pkt = kzalloc(sizeof(struct rr_packet),
247 GFP_KERNEL);
248 if (!smd_xprtp->in_pkt) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700249 pr_err("%s: Couldn't alloc rr_packet\n",
250 __func__);
251 return;
252 }
253
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700254 smd_xprtp->in_pkt->pkt_fragment_q =
255 kmalloc(sizeof(struct sk_buff_head),
256 GFP_KERNEL);
257 if (!smd_xprtp->in_pkt->pkt_fragment_q) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700258 pr_err("%s: Couldn't alloc pkt_fragment_q\n",
259 __func__);
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700260 kfree(smd_xprtp->in_pkt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700261 return;
262 }
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700263 skb_queue_head_init(smd_xprtp->in_pkt->pkt_fragment_q);
264 smd_xprtp->is_partial_in_pkt = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700265 D("%s: Allocated rr_packet\n", __func__);
266 }
267
Karthikeyan Ramasubramanian51247a02011-10-12 14:53:15 -0600268 if (((pkt_size >= MIN_FRAG_SZ) &&
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700269 (smd_read_avail(smd_xprtp->channel) < MIN_FRAG_SZ)) ||
Karthikeyan Ramasubramanian51247a02011-10-12 14:53:15 -0600270 ((pkt_size < MIN_FRAG_SZ) &&
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700271 (smd_read_avail(smd_xprtp->channel) < pkt_size)))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700272 return;
273
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700274 sz = smd_read_avail(smd_xprtp->channel);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700275 do {
276 ipc_rtr_pkt = alloc_skb(sz, GFP_KERNEL);
277 if (!ipc_rtr_pkt) {
278 if (sz <= (PAGE_SIZE/2)) {
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700279 queue_delayed_work(
280 smd_xprtp->smd_xprt_wq,
281 &smd_xprtp->read_work,
282 msecs_to_jiffies(100));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700283 return;
284 }
285 sz = sz / 2;
286 }
287 } while (!ipc_rtr_pkt);
288
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700289 D("%s: Allocated the sk_buff of size %d\n", __func__, sz);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700290 data = skb_put(ipc_rtr_pkt, sz);
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700291 sz_read = smd_read(smd_xprtp->channel, data, sz);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700292 if (sz_read != sz) {
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700293 pr_err("%s: Couldn't read %s completely\n",
294 __func__, smd_xprtp->xprt.name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700295 kfree_skb(ipc_rtr_pkt);
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700296 release_pkt(smd_xprtp->in_pkt);
297 smd_xprtp->is_partial_in_pkt = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700298 return;
299 }
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700300 skb_queue_tail(smd_xprtp->in_pkt->pkt_fragment_q, ipc_rtr_pkt);
301 smd_xprtp->in_pkt->length += sz_read;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700302 if (sz_read != pkt_size)
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700303 smd_xprtp->is_partial_in_pkt = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700304 else
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700305 smd_xprtp->is_partial_in_pkt = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700306
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700307 if (!smd_xprtp->is_partial_in_pkt) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700308 D("%s: Packet size read %d\n",
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700309 __func__, smd_xprtp->in_pkt->length);
310 msm_ipc_router_xprt_notify(&smd_xprtp->xprt,
311 IPC_ROUTER_XPRT_EVENT_DATA,
312 (void *)smd_xprtp->in_pkt);
313 release_pkt(smd_xprtp->in_pkt);
314 smd_xprtp->in_pkt = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700315 }
316 }
317}
318
Karthikeyan Ramasubramaniandd7daab2011-09-30 15:16:59 -0600319static void smd_xprt_open_event(struct work_struct *work)
320{
321 struct msm_ipc_router_smd_xprt_work *xprt_work =
322 container_of(work, struct msm_ipc_router_smd_xprt_work, work);
323
324 msm_ipc_router_xprt_notify(xprt_work->xprt,
325 IPC_ROUTER_XPRT_EVENT_OPEN, NULL);
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700326 D("%s: Notified IPC Router of %s OPEN\n",
327 __func__, xprt_work->xprt->name);
Karthikeyan Ramasubramaniandd7daab2011-09-30 15:16:59 -0600328 kfree(xprt_work);
329}
330
331static void smd_xprt_close_event(struct work_struct *work)
332{
333 struct msm_ipc_router_smd_xprt_work *xprt_work =
334 container_of(work, struct msm_ipc_router_smd_xprt_work, work);
335
336 msm_ipc_router_xprt_notify(xprt_work->xprt,
337 IPC_ROUTER_XPRT_EVENT_CLOSE, NULL);
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700338 D("%s: Notified IPC Router of %s CLOSE\n",
339 __func__, xprt_work->xprt->name);
Karthikeyan Ramasubramaniandd7daab2011-09-30 15:16:59 -0600340 kfree(xprt_work);
341}
342
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700343static void msm_ipc_router_smd_remote_notify(void *_dev, unsigned event)
344{
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600345 unsigned long flags;
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700346 struct msm_ipc_router_smd_xprt *smd_xprtp;
Karthikeyan Ramasubramaniandd7daab2011-09-30 15:16:59 -0600347 struct msm_ipc_router_smd_xprt_work *xprt_work;
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600348
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700349 smd_xprtp = (struct msm_ipc_router_smd_xprt *)_dev;
350 if (!smd_xprtp)
351 return;
352
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600353 switch (event) {
354 case SMD_EVENT_DATA:
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700355 if (smd_read_avail(smd_xprtp->channel))
356 queue_delayed_work(smd_xprtp->smd_xprt_wq,
357 &smd_xprtp->read_work, 0);
358 if (smd_write_avail(smd_xprtp->channel))
359 wake_up(&smd_xprtp->write_avail_wait_q);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600360 break;
361
362 case SMD_EVENT_OPEN:
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700363 spin_lock_irqsave(&smd_xprtp->ss_reset_lock, flags);
364 smd_xprtp->ss_reset = 0;
365 spin_unlock_irqrestore(&smd_xprtp->ss_reset_lock, flags);
Karthikeyan Ramasubramaniandd7daab2011-09-30 15:16:59 -0600366 xprt_work = kmalloc(sizeof(struct msm_ipc_router_smd_xprt_work),
367 GFP_ATOMIC);
368 if (!xprt_work) {
369 pr_err("%s: Couldn't notify %d event to IPC Router\n",
370 __func__, event);
371 return;
372 }
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700373 xprt_work->xprt = &smd_xprtp->xprt;
Karthikeyan Ramasubramaniandd7daab2011-09-30 15:16:59 -0600374 INIT_WORK(&xprt_work->work, smd_xprt_open_event);
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700375 queue_work(smd_xprtp->smd_xprt_wq, &xprt_work->work);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600376 break;
377
378 case SMD_EVENT_CLOSE:
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700379 spin_lock_irqsave(&smd_xprtp->ss_reset_lock, flags);
380 smd_xprtp->ss_reset = 1;
381 spin_unlock_irqrestore(&smd_xprtp->ss_reset_lock, flags);
382 wake_up(&smd_xprtp->write_avail_wait_q);
Karthikeyan Ramasubramaniandd7daab2011-09-30 15:16:59 -0600383 xprt_work = kmalloc(sizeof(struct msm_ipc_router_smd_xprt_work),
384 GFP_ATOMIC);
385 if (!xprt_work) {
386 pr_err("%s: Couldn't notify %d event to IPC Router\n",
387 __func__, event);
388 return;
389 }
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700390 xprt_work->xprt = &smd_xprtp->xprt;
Karthikeyan Ramasubramaniandd7daab2011-09-30 15:16:59 -0600391 INIT_WORK(&xprt_work->work, smd_xprt_close_event);
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700392 queue_work(smd_xprtp->smd_xprt_wq, &xprt_work->work);
Karthikeyan Ramasubramanianff6fbae2011-06-09 11:13:19 -0600393 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700394 }
395}
396
Karthikeyan Ramasubramanianc29692c2012-06-04 14:46:02 -0600397static void *msm_ipc_load_subsystem(uint32_t edge)
398{
399 void *pil = NULL;
400 const char *peripheral;
401
402 peripheral = smd_edge_to_subsystem(edge);
403 if (peripheral) {
404 pil = pil_get(peripheral);
405 if (IS_ERR(pil)) {
406 pr_err("%s: Failed to load %s\n",
407 __func__, peripheral);
408 pil = NULL;
409 }
410 }
411 return pil;
412}
413
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700414static int msm_ipc_router_smd_remote_probe(struct platform_device *pdev)
415{
416 int rc;
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700417 int id; /*Index into the smd_xprt_cfg table*/
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700418
Karthikeyan Ramasubramanianccc47262012-03-07 11:59:33 -0700419 id = find_smd_xprt_cfg(pdev);
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700420 if (id < 0) {
421 pr_err("%s: called for unknown ch %s\n",
422 __func__, pdev->name);
423 return id;
424 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700425
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700426 smd_remote_xprt[id].smd_xprt_wq =
427 create_singlethread_workqueue(pdev->name);
428 if (!smd_remote_xprt[id].smd_xprt_wq) {
429 pr_err("%s: WQ creation failed for %s\n",
430 __func__, pdev->name);
431 return -EFAULT;
432 }
433
434 smd_remote_xprt[id].xprt.name = smd_xprt_cfg[id].xprt_name;
435 smd_remote_xprt[id].xprt.link_id = smd_xprt_cfg[id].link_id;
436 smd_remote_xprt[id].xprt.read_avail = NULL;
437 smd_remote_xprt[id].xprt.read = NULL;
438 smd_remote_xprt[id].xprt.write_avail =
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700439 msm_ipc_router_smd_remote_write_avail;
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700440 smd_remote_xprt[id].xprt.write = msm_ipc_router_smd_remote_write;
441 smd_remote_xprt[id].xprt.close = msm_ipc_router_smd_remote_close;
442 smd_remote_xprt[id].xprt.priv = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700443
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700444 init_waitqueue_head(&smd_remote_xprt[id].write_avail_wait_q);
445 smd_remote_xprt[id].in_pkt = NULL;
446 smd_remote_xprt[id].is_partial_in_pkt = 0;
447 INIT_DELAYED_WORK(&smd_remote_xprt[id].read_work, smd_xprt_read_data);
448 spin_lock_init(&smd_remote_xprt[id].ss_reset_lock);
449 smd_remote_xprt[id].ss_reset = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700450
Karthikeyan Ramasubramanianc29692c2012-06-04 14:46:02 -0600451 smd_remote_xprt[id].pil = msm_ipc_load_subsystem(
452 smd_xprt_cfg[id].edge);
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700453 rc = smd_named_open_on_edge(smd_xprt_cfg[id].ch_name,
454 smd_xprt_cfg[id].edge,
455 &smd_remote_xprt[id].channel,
456 &smd_remote_xprt[id],
457 msm_ipc_router_smd_remote_notify);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700458 if (rc < 0) {
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700459 pr_err("%s: Channel open failed for %s\n",
460 __func__, smd_xprt_cfg[id].ch_name);
Karthikeyan Ramasubramanianc29692c2012-06-04 14:46:02 -0600461 if (smd_remote_xprt[id].pil) {
462 pil_put(smd_remote_xprt[id].pil);
463 smd_remote_xprt[id].pil = NULL;
464 }
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700465 destroy_workqueue(smd_remote_xprt[id].smd_xprt_wq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700466 return rc;
467 }
468
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700469 smd_disable_read_intr(smd_remote_xprt[id].channel);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700470
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700471 smsm_change_state(SMSM_APPS_STATE, 0, SMSM_RPCINIT);
472
473 return 0;
474}
475
Karthikeyan Ramasubramanian6b963bd2012-05-01 11:27:54 -0600476void *msm_ipc_load_default_node(void)
477{
478 void *pil = NULL;
479 const char *peripheral;
480
481 peripheral = smd_edge_to_subsystem(SMD_APPS_MODEM);
482 if (peripheral && !strncmp(peripheral, "modem", 6)) {
483 pil = pil_get(peripheral);
484 if (IS_ERR(pil)) {
485 pr_err("%s: Failed to load %s\n",
486 __func__, peripheral);
487 pil = NULL;
488 }
489 }
490 return pil;
491}
492EXPORT_SYMBOL(msm_ipc_load_default_node);
493
494void msm_ipc_unload_default_node(void *pil)
495{
496 if (pil)
497 pil_put(pil);
498}
499EXPORT_SYMBOL(msm_ipc_unload_default_node);
500
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700501static struct platform_driver msm_ipc_router_smd_remote_driver[] = {
502 {
503 .probe = msm_ipc_router_smd_remote_probe,
504 .driver = {
505 .name = "RPCRPY_CNTL",
506 .owner = THIS_MODULE,
507 },
508 },
509 {
510 .probe = msm_ipc_router_smd_remote_probe,
511 .driver = {
512 .name = "IPCRTR",
513 .owner = THIS_MODULE,
514 },
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700515 },
516};
517
518static int __init msm_ipc_router_smd_init(void)
519{
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700520 int i, ret, rc = 0;
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700521 BUG_ON(ARRAY_SIZE(smd_xprt_cfg) != NUM_SMD_XPRTS);
Karthikeyan Ramasubramanianccc47262012-03-07 11:59:33 -0700522 for (i = 0; i < ARRAY_SIZE(msm_ipc_router_smd_remote_driver); i++) {
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700523 ret = platform_driver_register(
524 &msm_ipc_router_smd_remote_driver[i]);
525 if (ret) {
526 pr_err("%s: Failed to register platform driver for"
527 " xprt%d. Continuing...\n", __func__, i);
528 rc = ret;
529 }
530 }
531 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700532}
533
534module_init(msm_ipc_router_smd_init);
Karthikeyan Ramasubramanian8cec5922012-02-16 17:41:58 -0700535MODULE_DESCRIPTION("IPC Router SMD XPRT");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700536MODULE_LICENSE("GPL v2");