blob: 3279fa84ac7ef69823efdcf11dc3e441e7c172a7 [file] [log] [blame]
Siddartha Mohanadoss603f7652017-01-26 15:59:41 -08001/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
2 *
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#include <linux/module.h>
14#include <linux/kernel.h>
15#include <linux/fs.h>
16#include <linux/types.h>
17#include <linux/cdev.h>
18#include <linux/wait.h>
19#include <linux/uaccess.h>
20#include <linux/slab.h>
21#include <linux/poll.h>
22#include <linux/sched.h>
23#include <linux/tty.h>
24#include <linux/delay.h>
25#include <linux/ipc_logging.h>
26#include <linux/dma-mapping.h>
27#include <linux/msm_ipa.h>
28#include <linux/ipa.h>
29#include <uapi/linux/mhi.h>
30#include "mhi.h"
31
32#define MHI_DEV_NODE_NAME_LEN 13
33#define MHI_MAX_NR_OF_CLIENTS 23
34#define MHI_SOFTWARE_CLIENT_START 0
35#define MHI_SOFTWARE_CLIENT_LIMIT (MHI_MAX_SOFTWARE_CHANNELS/2)
36#define MHI_UCI_IPC_LOG_PAGES (100)
37
38#define MAX_NR_TRBS_PER_CHAN 1
39#define MHI_QTI_IFACE_ID 4
40#define DEVICE_NAME "mhi"
41
42enum uci_dbg_level {
43 UCI_DBG_VERBOSE = 0x0,
44 UCI_DBG_INFO = 0x1,
45 UCI_DBG_DBG = 0x2,
46 UCI_DBG_WARNING = 0x3,
47 UCI_DBG_ERROR = 0x4,
48 UCI_DBG_CRITICAL = 0x5,
49 UCI_DBG_reserved = 0x80000000
50};
51
52static enum uci_dbg_level mhi_uci_msg_lvl = UCI_DBG_CRITICAL;
53static enum uci_dbg_level mhi_uci_ipc_log_lvl = UCI_DBG_INFO;
54static void *mhi_uci_ipc_log;
55
56
57enum mhi_chan_dir {
58 MHI_DIR_INVALID = 0x0,
59 MHI_DIR_OUT = 0x1,
60 MHI_DIR_IN = 0x2,
61 MHI_DIR__reserved = 0x80000000
62};
63
64struct chan_attr {
65 /* SW maintained channel id */
66 enum mhi_client_channel chan_id;
67 /* maximum buffer size for this channel */
68 size_t max_packet_size;
69 /* number of buffers supported in this channel */
70 u32 nr_trbs;
71 /* direction of the channel, see enum mhi_chan_dir */
72 enum mhi_chan_dir dir;
73 u32 uci_ownership;
74};
75
76struct uci_client {
77 u32 client_index;
78 /* write channel - always odd*/
79 u32 out_chan;
80 /* read channel - always even */
81 u32 in_chan;
82 struct mhi_dev_client *out_handle;
83 struct mhi_dev_client *in_handle;
84 wait_queue_head_t read_wq;
85 wait_queue_head_t write_wq;
86 atomic_t read_data_ready;
87 struct device *dev;
88 atomic_t ref_count;
89 int mhi_status;
90 void *pkt_loc;
91 size_t pkt_size;
92 struct mhi_dev_iov *in_buf_list;
93 atomic_t write_data_ready;
94 atomic_t mhi_chans_open;
95 struct mhi_uci_ctxt_t *uci_ctxt;
96 struct mutex in_chan_lock;
97 struct mutex out_chan_lock;
98};
99
100struct mhi_uci_ctxt_t {
101 struct chan_attr chan_attrib[MHI_MAX_SOFTWARE_CHANNELS];
102 struct uci_client client_handles[MHI_SOFTWARE_CLIENT_LIMIT];
103 void (*event_notifier)(struct mhi_dev_client_cb_reason *cb);
104 dev_t start_ctrl_nr;
105 struct cdev cdev[MHI_MAX_SOFTWARE_CHANNELS];
106 struct class *mhi_uci_class;
107 atomic_t mhi_disabled;
108 atomic_t mhi_enable_notif_wq_active;
109};
110
111#define CHAN_TO_CLIENT(_CHAN_NR) (_CHAN_NR / 2)
112
113#define uci_log(_msg_lvl, _msg, ...) do { \
114 if (_msg_lvl >= mhi_uci_msg_lvl) { \
115 pr_err("[%s] "_msg, __func__, ##__VA_ARGS__); \
116 } \
117 if (mhi_uci_ipc_log && (_msg_lvl >= mhi_uci_ipc_log_lvl)) { \
118 ipc_log_string(mhi_uci_ipc_log, \
119 "[%s] " _msg, __func__, ##__VA_ARGS__); \
120 } \
121} while (0)
122
123
124module_param(mhi_uci_msg_lvl, uint, 0644);
125MODULE_PARM_DESC(mhi_uci_msg_lvl, "uci dbg lvl");
126
127module_param(mhi_uci_ipc_log_lvl, uint, 0644);
128MODULE_PARM_DESC(mhi_uci_ipc_log_lvl, "ipc dbg lvl");
129
130static ssize_t mhi_uci_client_read(struct file *file, char __user *buf,
131 size_t count, loff_t *offp);
132static ssize_t mhi_uci_client_write(struct file *file,
133 const char __user *buf, size_t count, loff_t *offp);
134static int mhi_uci_client_open(struct inode *mhi_inode, struct file*);
135static int mhi_uci_client_release(struct inode *mhi_inode,
136 struct file *file_handle);
137static unsigned int mhi_uci_client_poll(struct file *file, poll_table *wait);
138static struct mhi_uci_ctxt_t uci_ctxt;
139
140static int mhi_init_read_chan(struct uci_client *client_handle,
141 enum mhi_client_channel chan)
142{
143 int rc = 0;
144 u32 i, j;
145 struct chan_attr *chan_attributes;
146 size_t buf_size;
147 void *data_loc;
148
149 if (client_handle == NULL) {
150 uci_log(UCI_DBG_ERROR, "Bad Input data, quitting\n");
151 return -EINVAL;
152 }
153 if (chan >= MHI_MAX_SOFTWARE_CHANNELS) {
154 uci_log(UCI_DBG_ERROR, "Incorrect channel number %d\n", chan);
155 return -EINVAL;
156 }
157
158 chan_attributes = &uci_ctxt.chan_attrib[chan];
159 buf_size = chan_attributes->max_packet_size;
160
161 for (i = 0; i < (chan_attributes->nr_trbs); i++) {
162 data_loc = kmalloc(buf_size, GFP_KERNEL);
163 if (!data_loc) {
164 rc = -ENOMEM;
165 goto free_memory;
166 }
167 client_handle->in_buf_list[i].addr = data_loc;
168 client_handle->in_buf_list[i].buf_size = buf_size;
169 }
170
171 return rc;
172
173free_memory:
174 for (j = 0; j < i; j++)
175 kfree(client_handle->in_buf_list[j].addr);
176
177 return rc;
178}
179
180static int mhi_uci_send_packet(struct mhi_dev_client **client_handle, void *buf,
181 u32 size, u32 is_uspace_buf)
182{
183 void *data_loc = NULL;
184 uintptr_t memcpy_result = 0;
185 u32 data_inserted_so_far = 0;
186 struct uci_client *uci_handle;
187
188 uci_handle = container_of(client_handle, struct uci_client,
189 out_handle);
190
191 if (!client_handle || !buf ||
192 !size || !uci_handle)
193 return -EINVAL;
194
195 if (is_uspace_buf) {
196 data_loc = kmalloc(size, GFP_KERNEL);
197 if (!data_loc) {
198 uci_log(UCI_DBG_ERROR,
199 "Failed to allocate memory 0x%x\n",
200 size);
201 return -ENOMEM;
202 }
203 memcpy_result = copy_from_user(data_loc, buf, size);
204 if (memcpy_result)
205 goto error_memcpy;
206 } else {
207 data_loc = buf;
208 }
209
210 data_inserted_so_far = mhi_dev_write_channel(*client_handle, data_loc,
211 size);
212
213error_memcpy:
214 kfree(data_loc);
215 return data_inserted_so_far;
216}
217
218static unsigned int mhi_uci_client_poll(struct file *file, poll_table *wait)
219{
220 unsigned int mask = 0;
221 struct uci_client *uci_handle;
222
223 uci_handle = file->private_data;
224
225 if (!uci_handle)
226 return -ENODEV;
227
228 poll_wait(file, &uci_handle->read_wq, wait);
229 poll_wait(file, &uci_handle->write_wq, wait);
230 if (!atomic_read(&uci_ctxt.mhi_disabled) &&
231 !mhi_dev_channel_isempty(uci_handle->in_handle)) {
232 uci_log(UCI_DBG_VERBOSE,
233 "Client can read chan %d\n", uci_handle->in_chan);
234 mask |= POLLIN | POLLRDNORM;
235 }
236 if (!atomic_read(&uci_ctxt.mhi_disabled) &&
237 !mhi_dev_channel_isempty(uci_handle->out_handle)) {
238 uci_log(UCI_DBG_VERBOSE,
239 "Client can write chan %d\n", uci_handle->out_chan);
240 mask |= POLLOUT | POLLWRNORM;
241 }
242
243 uci_log(UCI_DBG_VERBOSE,
244 "Client attempted to poll chan %d, returning mask 0x%x\n",
245 uci_handle->in_chan, mask);
246 return mask;
247}
248
249static int open_client_mhi_channels(struct uci_client *uci_client)
250{
251 int rc = 0;
252
253 uci_log(UCI_DBG_DBG,
254 "Starting channels %d %d.\n",
255 uci_client->out_chan,
256 uci_client->in_chan);
257 mutex_lock(&uci_client->out_chan_lock);
258 mutex_lock(&uci_client->in_chan_lock);
259 uci_log(UCI_DBG_DBG,
260 "Initializing inbound chan %d.\n",
261 uci_client->in_chan);
262
263 rc = mhi_init_read_chan(uci_client, uci_client->in_chan);
264 if (rc < 0) {
265 uci_log(UCI_DBG_ERROR,
266 "Failed to init inbound 0x%x, ret 0x%x\n",
267 uci_client->in_chan, rc);
268 }
269
270 rc = mhi_dev_open_channel(uci_client->out_chan,
271 &uci_client->out_handle,
272 uci_ctxt.event_notifier);
273 if (rc < 0)
274 goto handle_not_rdy_err;
275
276 rc = mhi_dev_open_channel(uci_client->in_chan,
277 &uci_client->in_handle,
278 uci_ctxt.event_notifier);
279
280 if (rc < 0) {
281 uci_log(UCI_DBG_ERROR,
282 "Failed to open chan %d, ret 0x%x\n",
283 uci_client->out_chan, rc);
284 goto handle_in_err;
285 }
286 atomic_set(&uci_client->mhi_chans_open, 1);
287 mutex_unlock(&uci_client->in_chan_lock);
288 mutex_unlock(&uci_client->out_chan_lock);
289
290 return 0;
291
292handle_in_err:
293 mhi_dev_close_channel(uci_client->out_handle);
294handle_not_rdy_err:
295 mutex_unlock(&uci_client->in_chan_lock);
296 mutex_unlock(&uci_client->out_chan_lock);
297 return rc;
298}
299
300static int mhi_uci_client_open(struct inode *mhi_inode,
301 struct file *file_handle)
302{
303 struct uci_client *uci_handle;
304 int rc = 0;
305
306 uci_handle =
307 &uci_ctxt.client_handles[iminor(mhi_inode)];
308
309 uci_log(UCI_DBG_DBG,
310 "Client opened struct device node 0x%x, ref count 0x%x\n",
311 iminor(mhi_inode), atomic_read(&uci_handle->ref_count));
312 if (atomic_add_return(1, &uci_handle->ref_count) == 1) {
313 if (!uci_handle) {
314 atomic_dec(&uci_handle->ref_count);
315 return -ENOMEM;
316 }
317 uci_handle->uci_ctxt = &uci_ctxt;
318 if (!atomic_read(&uci_handle->mhi_chans_open)) {
319 uci_log(UCI_DBG_INFO,
320 "Opening channels client %d\n",
321 iminor(mhi_inode));
322 rc = open_client_mhi_channels(uci_handle);
323 if (rc) {
324 uci_log(UCI_DBG_INFO,
325 "Failed to open channels ret %d\n", rc);
326 return rc;
327 }
328 }
329 }
330 file_handle->private_data = uci_handle;
331
332 return 0;
333
334}
335
336static int mhi_uci_client_release(struct inode *mhi_inode,
337 struct file *file_handle)
338{
339 struct uci_client *uci_handle = file_handle->private_data;
340 struct mhi_uci_ctxt_t *uci_ctxt = uci_handle->uci_ctxt;
341 u32 nr_in_bufs = 0;
342 int rc = 0;
343 int in_chan = 0;
344 u32 buf_size = 0;
345
346 in_chan = iminor(mhi_inode) + 1;
347 nr_in_bufs = uci_ctxt->chan_attrib[in_chan].nr_trbs;
348 buf_size = uci_ctxt->chan_attrib[in_chan].max_packet_size;
349
350 if (!uci_handle)
351 return -EINVAL;
352 if (atomic_sub_return(1, &uci_handle->ref_count) == 0) {
353 uci_log(UCI_DBG_DBG,
354 "Last client left, closing channel 0x%x\n",
355 iminor(mhi_inode));
356 if (atomic_read(&uci_handle->mhi_chans_open)) {
357 atomic_set(&uci_handle->mhi_chans_open, 0);
358
359 mutex_lock(&uci_handle->out_chan_lock);
360 rc = mhi_dev_close_channel(uci_handle->out_handle);
361 wake_up(&uci_handle->write_wq);
362 mutex_unlock(&uci_handle->out_chan_lock);
363
364 mutex_lock(&uci_handle->in_chan_lock);
365 rc = mhi_dev_close_channel(uci_handle->in_handle);
366 wake_up(&uci_handle->read_wq);
367 mutex_unlock(&uci_handle->in_chan_lock);
368
369 }
370 atomic_set(&uci_handle->read_data_ready, 0);
371 atomic_set(&uci_handle->write_data_ready, 0);
372 file_handle->private_data = NULL;
373 } else {
374 uci_log(UCI_DBG_DBG,
375 "Client close chan %d, ref count 0x%x\n",
376 iminor(mhi_inode),
377 atomic_read(&uci_handle->ref_count));
378 }
379 return rc;
380}
381
382static ssize_t mhi_uci_client_read(struct file *file, char __user *buf,
383 size_t uspace_buf_size, loff_t *bytes_pending)
384{
385 struct uci_client *uci_handle = NULL;
386 struct mhi_dev_client *client_handle = NULL;
387 int bytes_avail = 0;
388 int ret_val = 0;
389 struct mutex *mutex;
390 u32 chan = 0;
391 ssize_t bytes_copied = 0;
392 u32 addr_offset = 0;
393 uint32_t buf_size;
394 uint32_t chained = 0;
395 void *local_buf = NULL;
396
397 if (!file || !buf || !uspace_buf_size ||
398 !file->private_data)
399 return -EINVAL;
400
401 uci_handle = file->private_data;
402 client_handle = uci_handle->in_handle;
403 mutex = &uci_handle->in_chan_lock;
404 chan = uci_handle->in_chan;
405
406 mutex_lock(mutex);
407
408 local_buf = uci_handle->in_buf_list[0].addr;
409 buf_size = uci_handle->in_buf_list[0].buf_size;
410
411
412 uci_log(UCI_DBG_VERBOSE, "Client attempted read on chan %d\n", chan);
413 do {
414 if (!uci_handle->pkt_loc &&
415 !atomic_read(&uci_ctxt.mhi_disabled)) {
416
417 bytes_avail = mhi_dev_read_channel(client_handle,
418 local_buf, buf_size, &chained);
419
420 uci_log(UCI_DBG_VERBOSE,
421 "reading from mhi_core local_buf = %p,buf_size = 0x%x bytes_read = 0x%x\n",
422 local_buf, buf_size, bytes_avail);
423
424 if (bytes_avail < 0) {
425 uci_log(UCI_DBG_ERROR,
426 "Failed to read channel ret %d\n",
427 bytes_avail);
428 ret_val = -EIO;
429 goto error;
430 }
431
432 if (bytes_avail > 0) {
433 uci_handle->pkt_loc = (void *)local_buf;
434 uci_handle->pkt_size = bytes_avail;
435
436 *bytes_pending = (loff_t)uci_handle->pkt_size;
437 uci_log(UCI_DBG_VERBOSE,
438 "Got pkt of size 0x%x at addr %p, chan %d\n",
439 uci_handle->pkt_size, local_buf, chan);
440 } else {
441 uci_handle->pkt_loc = 0;
442 uci_handle->pkt_size = 0;
443 }
444 }
445 if (bytes_avail == 0) {
446
447 /* If nothing was copied yet, wait for data */
448 uci_log(UCI_DBG_VERBOSE,
449 "No data read_data_ready %d, chan %d\n",
450 atomic_read(&uci_handle->read_data_ready),
451 chan);
452
453 ret_val = wait_event_interruptible(uci_handle->read_wq,
454 (!mhi_dev_channel_isempty(client_handle)));
455
456 if (ret_val == -ERESTARTSYS) {
457 uci_log(UCI_DBG_ERROR, "Exit signal caught\n");
458 goto error;
459 }
460 uci_log(UCI_DBG_VERBOSE,
461 "Thread woke up. Got data on chan %d read_data_ready %d\n",
462 chan,
463 atomic_read(&uci_handle->read_data_ready));
464
465 /* A valid packet was returned from MHI */
466 } else if (bytes_avail > 0) {
467 uci_log(UCI_DBG_VERBOSE,
468 "Got packet: avail pkts %d phy_adr %p, chan %d\n",
469 atomic_read(&uci_handle->read_data_ready),
470 local_buf,
471 chan);
472 break;
473 /*
474 * MHI did not return a valid packet, but we have one
475 * which we did not finish returning to user
476 */
477 } else {
478 uci_log(UCI_DBG_CRITICAL,
479 "chan %d err: avail pkts %d phy_adr %p",
480 chan,
481 atomic_read(&uci_handle->read_data_ready),
482 local_buf);
483 return -EIO;
484 }
485 } while (!uci_handle->pkt_loc);
486
487 if (uspace_buf_size >= *bytes_pending) {
488 addr_offset = uci_handle->pkt_size - *bytes_pending;
489 if (copy_to_user(buf, uci_handle->pkt_loc + addr_offset,
490 *bytes_pending)) {
491 ret_val = -EIO;
492 goto error;
493 }
494
495 bytes_copied = *bytes_pending;
496 *bytes_pending = 0;
497 uci_log(UCI_DBG_VERBOSE, "Copied 0x%x of 0x%x, chan %d\n",
498 bytes_copied, (u32)*bytes_pending, chan);
499 } else {
500 addr_offset = uci_handle->pkt_size - *bytes_pending;
501 if (copy_to_user(buf, (void *) (uintptr_t)uci_handle->pkt_loc +
502 addr_offset, uspace_buf_size)) {
503 ret_val = -EIO;
504 goto error;
505 }
506 bytes_copied = uspace_buf_size;
507 *bytes_pending -= uspace_buf_size;
508 uci_log(UCI_DBG_VERBOSE, "Copied 0x%x of 0x%x,chan %d\n",
509 bytes_copied,
510 (u32)*bytes_pending,
511 chan);
512 }
513 /* We finished with this buffer, map it back */
514 if (*bytes_pending == 0) {
515 uci_log(UCI_DBG_VERBOSE,
516 "All data consumed. Pkt loc %p ,chan %d\n",
517 uci_handle->pkt_loc, chan);
518 uci_handle->pkt_loc = 0;
519 uci_handle->pkt_size = 0;
520 }
521 uci_log(UCI_DBG_VERBOSE,
522 "Returning 0x%x bytes, 0x%x bytes left\n",
523 bytes_copied, (u32)*bytes_pending);
524 mutex_unlock(mutex);
525 return bytes_copied;
526error:
527 mutex_unlock(mutex);
528 uci_log(UCI_DBG_ERROR, "Returning %d\n", ret_val);
529 return ret_val;
530}
531
532static ssize_t mhi_uci_client_write(struct file *file,
533 const char __user *buf,
534 size_t count, loff_t *offp)
535{
536 struct uci_client *uci_handle = NULL;
537 int ret_val = 0;
538 u32 chan = 0xFFFFFFFF;
539
540 if (file == NULL || buf == NULL ||
541 !count || file->private_data == NULL)
542 return -EINVAL;
543
544 uci_handle = file->private_data;
545
546 if (atomic_read(&uci_ctxt.mhi_disabled)) {
547 uci_log(UCI_DBG_ERROR,
548 "Client %d attempted to write while MHI is disabled\n",
549 uci_handle->out_chan);
550 return -EIO;
551 }
552 chan = uci_handle->out_chan;
553 mutex_lock(&uci_handle->out_chan_lock);
554 while (!ret_val) {
555 ret_val = mhi_uci_send_packet(&uci_handle->out_handle,
556 (void *)buf, count, 1);
557 if (ret_val < 0) {
558 uci_log(UCI_DBG_ERROR,
559 "Error while writing data to MHI, chan %d, buf %p, size %d\n",
560 chan, (void *)buf, count);
561 ret_val = -EIO;
562 break;
563 }
564 if (!ret_val) {
565 uci_log(UCI_DBG_VERBOSE,
566 "No descriptors available, did we poll, chan %d?\n",
567 chan);
568 mutex_unlock(&uci_handle->out_chan_lock);
569 ret_val = wait_event_interruptible(uci_handle->write_wq,
570 !mhi_dev_channel_isempty(
571 uci_handle->out_handle));
572
573 mutex_lock(&uci_handle->out_chan_lock);
574 if (-ERESTARTSYS == ret_val) {
575 uci_log(UCI_DBG_WARNING,
576 "Waitqueue cancelled by system\n");
577 break;
578 }
579 }
580 }
581 mutex_unlock(&uci_handle->out_chan_lock);
582 return ret_val;
583}
584
585static int uci_init_client_attributes(struct mhi_uci_ctxt_t *uci_ctxt)
586{
587 u32 i = 0;
588 u32 data_size = TRB_MAX_DATA_SIZE;
589 u32 index = 0;
590 struct uci_client *client;
591 struct chan_attr *chan_attrib = NULL;
592
593 for (i = 0; i < ARRAY_SIZE(uci_ctxt->chan_attrib); i++) {
594 chan_attrib = &uci_ctxt->chan_attrib[i];
595 switch (i) {
596 case MHI_CLIENT_LOOPBACK_OUT:
597 case MHI_CLIENT_LOOPBACK_IN:
598 case MHI_CLIENT_SAHARA_OUT:
599 case MHI_CLIENT_SAHARA_IN:
600 case MHI_CLIENT_EFS_OUT:
601 case MHI_CLIENT_EFS_IN:
602 case MHI_CLIENT_QMI_OUT:
603 case MHI_CLIENT_QMI_IN:
604 case MHI_CLIENT_IP_CTRL_0_OUT:
605 case MHI_CLIENT_IP_CTRL_0_IN:
606 case MHI_CLIENT_IP_CTRL_1_OUT:
607 case MHI_CLIENT_IP_CTRL_1_IN:
608 case MHI_CLIENT_DUN_OUT:
609 case MHI_CLIENT_DUN_IN:
610 chan_attrib->uci_ownership = 1;
611 break;
612 default:
613 chan_attrib->uci_ownership = 0;
614 break;
615 }
616 if (chan_attrib->uci_ownership) {
617 chan_attrib->chan_id = i;
618 chan_attrib->max_packet_size = data_size;
619 index = CHAN_TO_CLIENT(i);
620 client = &uci_ctxt->client_handles[index];
621 chan_attrib->nr_trbs = 9;
622 client->in_buf_list =
623 kmalloc(sizeof(struct mhi_dev_iov) *
624 chan_attrib->nr_trbs,
625 GFP_KERNEL);
626 if (client->in_buf_list == NULL)
627 return -ENOMEM;
628 }
629 if (i % 2 == 0)
630 chan_attrib->dir = MHI_DIR_OUT;
631 else
632 chan_attrib->dir = MHI_DIR_IN;
633 }
634 return 0;
635}
636
637
638static void uci_event_notifier(struct mhi_dev_client_cb_reason *reason)
639{
640 int client_index = 0;
641 struct uci_client *uci_handle = NULL;
642
643 if (reason->reason == MHI_DEV_TRE_AVAILABLE) {
644 client_index = reason->ch_id / 2;
645 uci_handle = &uci_ctxt.client_handles[client_index];
646 uci_log(UCI_DBG_DBG,
647 "recived TRE available event for chan %d\n",
648 uci_handle->in_chan);
649
650 if (reason->ch_id % 2) {
651 atomic_set(&uci_handle->write_data_ready, 1);
652 wake_up(&uci_handle->write_wq);
653 } else {
654 atomic_set(&uci_handle->read_data_ready, 1);
655 wake_up(&uci_handle->read_wq);
656 }
657 }
658}
659
660static int mhi_register_client(struct uci_client *mhi_client, int index)
661{
662 init_waitqueue_head(&mhi_client->read_wq);
663 init_waitqueue_head(&mhi_client->write_wq);
664 mhi_client->out_chan = index * 2 + 1;
665 mhi_client->in_chan = index * 2;
666 mhi_client->client_index = index;
667
668 mutex_init(&mhi_client->in_chan_lock);
669 mutex_init(&mhi_client->out_chan_lock);
670
671 uci_log(UCI_DBG_DBG, "Registering chan %d.\n", mhi_client->out_chan);
672 return 0;
673}
674
675static long mhi_uci_client_ioctl(struct file *file, unsigned int cmd,
676 unsigned long arg)
677{
678 struct uci_client *uci_handle = NULL;
679 int rc = 0;
680 struct ep_info epinfo;
681
682 if (file == NULL || file->private_data == NULL)
683 return -EINVAL;
684
685 uci_handle = file->private_data;
686
687 uci_log(UCI_DBG_DBG, "Received command %d for client:%d\n",
688 cmd, uci_handle->client_index);
689
690 if (cmd == MHI_UCI_EP_LOOKUP) {
691 uci_log(UCI_DBG_DBG, "EP_LOOKUP for client:%d\n",
692 uci_handle->client_index);
693 epinfo.ph_ep_info.ep_type = DATA_EP_TYPE_PCIE;
694 epinfo.ph_ep_info.peripheral_iface_id = MHI_QTI_IFACE_ID;
695 epinfo.ipa_ep_pair.cons_pipe_num =
696 ipa_get_ep_mapping(IPA_CLIENT_MHI_PROD);
697 epinfo.ipa_ep_pair.prod_pipe_num =
698 ipa_get_ep_mapping(IPA_CLIENT_MHI_CONS);
699
700 uci_log(UCI_DBG_DBG, "client:%d ep_type:%d intf:%d\n",
701 uci_handle->client_index,
702 epinfo.ph_ep_info.ep_type,
703 epinfo.ph_ep_info.peripheral_iface_id);
704
705 uci_log(UCI_DBG_DBG, "ipa_cons_idx:%d ipa_prod_idx:%d\n",
706 epinfo.ipa_ep_pair.cons_pipe_num,
707 epinfo.ipa_ep_pair.prod_pipe_num);
708
709 rc = copy_to_user((void __user *)arg, &epinfo,
710 sizeof(epinfo));
711 if (rc)
712 uci_log(UCI_DBG_ERROR, "copying to user space failed");
713 } else {
714 uci_log(UCI_DBG_ERROR, "wrong parameter:%d\n", cmd);
715 rc = -EINVAL;
716 }
717
718 return rc;
719}
720
721static const struct file_operations mhi_uci_client_fops = {
722 .read = mhi_uci_client_read,
723 .write = mhi_uci_client_write,
724 .open = mhi_uci_client_open,
725 .release = mhi_uci_client_release,
726 .poll = mhi_uci_client_poll,
727 .unlocked_ioctl = mhi_uci_client_ioctl,
728#ifdef CONFIG_COMPAT
729 .compat_ioctl = mhi_uci_client_ioctl,
730#endif
731};
732
733int mhi_uci_init(void)
734{
735 u32 i = 0;
736 int ret_val = 0;
737 struct uci_client *mhi_client = NULL;
738 s32 r = 0;
739
740 mhi_uci_ipc_log = ipc_log_context_create(MHI_UCI_IPC_LOG_PAGES,
741 "mhi-uci", 0);
742 if (mhi_uci_ipc_log == NULL) {
743 uci_log(UCI_DBG_WARNING,
744 "Failed to create IPC logging context\n");
745 }
746 uci_ctxt.event_notifier = uci_event_notifier;
747
748 uci_log(UCI_DBG_DBG, "Setting up channel attributes.\n");
749
750 ret_val = uci_init_client_attributes(&uci_ctxt);
751 if (ret_val < 0) {
752 uci_log(UCI_DBG_ERROR,
753 "Failed to init client attributes\n");
754 return -EIO;
755 }
756
757 uci_log(UCI_DBG_DBG, "Initializing clients\n");
758 uci_log(UCI_DBG_INFO, "Registering for MHI events.\n");
759
760 for (i = 0; i < MHI_SOFTWARE_CLIENT_LIMIT; i++) {
761 if (uci_ctxt.chan_attrib[i * 2].uci_ownership) {
762 mhi_client = &uci_ctxt.client_handles[i];
763
764 r = mhi_register_client(mhi_client, i);
765
766 if (r) {
767 uci_log(UCI_DBG_CRITICAL,
768 "Failed to reg client %d ret %d\n",
769 r, i);
770 }
771 }
772 }
773 uci_log(UCI_DBG_INFO, "Allocating char devices.\n");
774 r = alloc_chrdev_region(&uci_ctxt.start_ctrl_nr,
775 0, MHI_MAX_SOFTWARE_CHANNELS,
776 DEVICE_NAME);
777
778 if (IS_ERR_VALUE(r)) {
779 uci_log(UCI_DBG_ERROR,
780 "Failed to alloc char devs, ret 0x%x\n", r);
781 goto failed_char_alloc;
782 }
783 uci_log(UCI_DBG_INFO, "Creating class\n");
784 uci_ctxt.mhi_uci_class = class_create(THIS_MODULE,
785 DEVICE_NAME);
786 if (IS_ERR(uci_ctxt.mhi_uci_class)) {
787 uci_log(UCI_DBG_ERROR,
788 "Failed to instantiate class, ret 0x%x\n", r);
789 r = -ENOMEM;
790 goto failed_class_add;
791 }
792
793 uci_log(UCI_DBG_INFO, "Setting up device nodes.\n");
794 for (i = 0; i < MHI_SOFTWARE_CLIENT_LIMIT; i++) {
795 if (uci_ctxt.chan_attrib[i*2].uci_ownership) {
796 cdev_init(&uci_ctxt.cdev[i], &mhi_uci_client_fops);
797 uci_ctxt.cdev[i].owner = THIS_MODULE;
798 r = cdev_add(&uci_ctxt.cdev[i],
799 uci_ctxt.start_ctrl_nr + i, 1);
800 if (IS_ERR_VALUE(r)) {
801 uci_log(UCI_DBG_ERROR,
802 "Failed to add cdev %d, ret 0x%x\n",
803 i, r);
804 goto failed_char_add;
805 }
806 uci_ctxt.client_handles[i].dev =
807 device_create(uci_ctxt.mhi_uci_class, NULL,
808 uci_ctxt.start_ctrl_nr + i,
809 NULL, DEVICE_NAME "_pipe_%d",
810 i * 2);
811
812 if (IS_ERR(uci_ctxt.client_handles[i].dev)) {
813 uci_log(UCI_DBG_ERROR,
814 "Failed to add cdev %d\n", i);
815 cdev_del(&uci_ctxt.cdev[i]);
816 goto failed_device_create;
817 }
818 }
819 }
820 return 0;
821
822failed_char_add:
823failed_device_create:
824 while (--i >= 0) {
825 cdev_del(&uci_ctxt.cdev[i]);
826 device_destroy(uci_ctxt.mhi_uci_class,
827 MKDEV(MAJOR(uci_ctxt.start_ctrl_nr), i * 2));
828 };
829 class_destroy(uci_ctxt.mhi_uci_class);
830failed_class_add:
831 unregister_chrdev_region(MAJOR(uci_ctxt.start_ctrl_nr),
832 MHI_MAX_SOFTWARE_CHANNELS);
833failed_char_alloc:
834 return r;
835}