blob: c7bd2205ae910207c817925aa656758c1ba2b035 [file] [log] [blame]
Manoj Prabhu B98325462017-01-10 20:19:28 +05301/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -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#include <linux/slab.h>
13#include <linux/err.h>
14#include <linux/sched.h>
15#include <linux/ratelimit.h>
16#include <linux/workqueue.h>
17#include <linux/diagchar.h>
18#include <linux/of.h>
19#include <linux/kmemleak.h>
20#include <linux/delay.h>
21#include <linux/atomic.h>
22#include "diagchar.h"
23#include "diagchar_hdlc.h"
24#include "diagfwd_peripheral.h"
25#include "diagfwd_cntl.h"
26#include "diag_masks.h"
27#include "diag_dci.h"
28#include "diagfwd.h"
29#include "diagfwd_socket.h"
30#include "diag_mux.h"
31#include "diag_ipc_logging.h"
32#include "diagfwd_glink.h"
Hardik Arya53bf3452017-09-06 15:34:19 +053033#include "diag_memorydevice.h"
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -070034
35struct data_header {
36 uint8_t control_char;
37 uint8_t version;
38 uint16_t length;
39};
40
41static struct diagfwd_info *early_init_info[NUM_TRANSPORT];
42
43static void diagfwd_queue_read(struct diagfwd_info *fwd_info);
44static void diagfwd_buffers_exit(struct diagfwd_info *fwd_info);
45static void diagfwd_cntl_open(struct diagfwd_info *fwd_info);
46static void diagfwd_cntl_close(struct diagfwd_info *fwd_info);
47static void diagfwd_dci_open(struct diagfwd_info *fwd_info);
48static void diagfwd_dci_close(struct diagfwd_info *fwd_info);
Manoj Prabhu B571cf422017-08-08 19:01:41 +053049static void diagfwd_data_read_untag_done(struct diagfwd_info *fwd_info,
50 unsigned char *buf, int len);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -070051static void diagfwd_data_read_done(struct diagfwd_info *fwd_info,
52 unsigned char *buf, int len);
53static void diagfwd_cntl_read_done(struct diagfwd_info *fwd_info,
54 unsigned char *buf, int len);
55static void diagfwd_dci_read_done(struct diagfwd_info *fwd_info,
56 unsigned char *buf, int len);
57static void diagfwd_write_buffers_init(struct diagfwd_info *fwd_info);
58static void diagfwd_write_buffers_exit(struct diagfwd_info *fwd_info);
59struct diagfwd_info peripheral_info[NUM_TYPES][NUM_PERIPHERALS];
60
61static struct diag_channel_ops data_ch_ops = {
62 .open = NULL,
63 .close = NULL,
Manoj Prabhu B571cf422017-08-08 19:01:41 +053064 .read_done = diagfwd_data_read_untag_done
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -070065};
66
67static struct diag_channel_ops cntl_ch_ops = {
68 .open = diagfwd_cntl_open,
69 .close = diagfwd_cntl_close,
70 .read_done = diagfwd_cntl_read_done
71};
72
73static struct diag_channel_ops dci_ch_ops = {
74 .open = diagfwd_dci_open,
75 .close = diagfwd_dci_close,
76 .read_done = diagfwd_dci_read_done
77};
78
79static void diagfwd_cntl_open(struct diagfwd_info *fwd_info)
80{
81 if (!fwd_info)
82 return;
83 diag_cntl_channel_open(fwd_info);
84}
85
86static void diagfwd_cntl_close(struct diagfwd_info *fwd_info)
87{
88 if (!fwd_info)
89 return;
90 diag_cntl_channel_close(fwd_info);
91}
92
93static void diagfwd_dci_open(struct diagfwd_info *fwd_info)
94{
95 if (!fwd_info)
96 return;
97
98 diag_dci_notify_client(PERIPHERAL_MASK(fwd_info->peripheral),
99 DIAG_STATUS_OPEN, DCI_LOCAL_PROC);
100}
101
102static void diagfwd_dci_close(struct diagfwd_info *fwd_info)
103{
104 if (!fwd_info)
105 return;
106
107 diag_dci_notify_client(PERIPHERAL_MASK(fwd_info->peripheral),
108 DIAG_STATUS_CLOSED, DCI_LOCAL_PROC);
109}
110
111static int diag_add_hdlc_encoding(unsigned char *dest_buf, int *dest_len,
112 unsigned char *buf, int len)
113{
114 struct diag_send_desc_type send = { NULL, NULL, DIAG_STATE_START, 0 };
115 struct diag_hdlc_dest_type enc = { NULL, NULL, 0 };
116 struct data_header *header;
117 int header_size = sizeof(struct data_header);
118 uint8_t *end_control_char = NULL;
119 uint8_t *payload = NULL;
120 uint8_t *temp_buf = NULL;
121 uint8_t *temp_encode_buf = NULL;
122 int src_pkt_len;
123 int encoded_pkt_length;
124 int max_size;
125 int total_processed = 0;
126 int bytes_remaining;
127 int err = 0;
128 uint8_t loop_count = 0;
129
130 if (!dest_buf || !dest_len || !buf)
131 return -EIO;
132
133 temp_buf = buf;
134 temp_encode_buf = dest_buf;
135 bytes_remaining = *dest_len;
136
137 while (total_processed < len) {
138 loop_count++;
139 header = (struct data_header *)temp_buf;
140 /* Perform initial error checking */
141 if (header->control_char != CONTROL_CHAR ||
142 header->version != 1) {
143 err = -EINVAL;
144 break;
145 }
146
147 if (header->length >= bytes_remaining)
148 break;
149
150 payload = temp_buf + header_size;
151 end_control_char = payload + header->length;
152 if (*end_control_char != CONTROL_CHAR) {
153 err = -EINVAL;
154 break;
155 }
156
157 max_size = 2 * header->length + 3;
158 if (bytes_remaining < max_size) {
159 err = -EINVAL;
160 break;
161 }
162
163 /* Prepare for encoding the data */
164 send.state = DIAG_STATE_START;
165 send.pkt = payload;
166 send.last = (void *)(payload + header->length - 1);
167 send.terminate = 1;
168
169 enc.dest = temp_encode_buf;
170 enc.dest_last = (void *)(temp_encode_buf + max_size);
171 enc.crc = 0;
172 diag_hdlc_encode(&send, &enc);
173
174 /* Prepare for next packet */
175 src_pkt_len = (header_size + header->length + 1);
176 total_processed += src_pkt_len;
177 temp_buf += src_pkt_len;
178
179 encoded_pkt_length = (uint8_t *)enc.dest - temp_encode_buf;
180 bytes_remaining -= encoded_pkt_length;
181 temp_encode_buf = enc.dest;
182 }
183
184 *dest_len = (int)(temp_encode_buf - dest_buf);
185
186 return err;
187}
188
189static int check_bufsize_for_encoding(struct diagfwd_buf_t *buf, uint32_t len)
190{
Hardik Arya53bf3452017-09-06 15:34:19 +0530191 int i, ctx = 0;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700192 uint32_t max_size = 0;
193 unsigned char *temp_buf = NULL;
Hardik Arya53bf3452017-09-06 15:34:19 +0530194 struct diag_md_info *ch = NULL;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700195
196 if (!buf || len == 0)
197 return -EINVAL;
198
199 max_size = (2 * len) + 3;
200 if (max_size > PERIPHERAL_BUF_SZ) {
201 if (max_size > MAX_PERIPHERAL_HDLC_BUF_SZ) {
202 pr_err("diag: In %s, max_size is going beyond limit %d\n",
203 __func__, max_size);
204 max_size = MAX_PERIPHERAL_HDLC_BUF_SZ;
205 }
206
207 if (buf->len < max_size) {
Hardik Aryafe005cc2017-12-01 12:31:58 +0530208 if (driver->logging_mode == DIAG_MEMORY_DEVICE_MODE ||
209 driver->logging_mode == DIAG_MULTI_MODE) {
Hardik Arya53bf3452017-09-06 15:34:19 +0530210 ch = &diag_md[DIAG_LOCAL_PROC];
211 for (i = 0; ch != NULL &&
212 i < ch->num_tbl_entries; i++) {
213 if (ch->tbl[i].buf == buf->data) {
214 ctx = ch->tbl[i].ctx;
215 ch->tbl[i].buf = NULL;
216 ch->tbl[i].len = 0;
217 ch->tbl[i].ctx = 0;
218 DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
219 "Flushed mdlog table entries before reallocating data buffer, p:%d, t:%d\n",
220 GET_BUF_PERIPHERAL(ctx),
221 GET_BUF_TYPE(ctx));
222 break;
223 }
224 }
225 }
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700226 temp_buf = krealloc(buf->data, max_size +
227 APF_DIAG_PADDING,
228 GFP_KERNEL);
229 if (!temp_buf)
230 return -ENOMEM;
Hardik Arya53bf3452017-09-06 15:34:19 +0530231 DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
232 "Reallocated data buffer: %pK with size: %d\n",
233 temp_buf, max_size);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700234 buf->data = temp_buf;
235 buf->len = max_size;
236 }
237 }
238
239 return buf->len;
240}
241
Manoj Prabhu B90e1f502017-11-02 20:01:45 +0530242/*
243 * diag_md_get_peripheral(int ctxt)
244 *
245 * Context(ctxt) contains peripheral, channel type, buffer num and diag_id
246 * The function decodes the ctxt, checks for the active user pd session
247 * using diag_id and returns peripheral if not active or the PD if active.
248 *
249 */
Manoj Prabhu B571cf422017-08-08 19:01:41 +0530250int diag_md_get_peripheral(int ctxt)
251{
Manoj Prabhu B90e1f502017-11-02 20:01:45 +0530252 uint8_t diag_id = 0, i = 0, pd = 0;
Manoj Prabhu B571cf422017-08-08 19:01:41 +0530253 int type = 0, peripheral = -EINVAL;
Manoj Prabhu B90e1f502017-11-02 20:01:45 +0530254 int index = 0;
Manoj Prabhu B571cf422017-08-08 19:01:41 +0530255 struct diagfwd_info *fwd_info = NULL;
256
257 peripheral = GET_BUF_PERIPHERAL(ctxt);
Chris Lewc937d692017-10-12 13:13:18 +0530258
259 /* Check for peripheral value within bounds
260 * of peripherals and UPD combined.
261 */
262 if (peripheral < 0 || peripheral > NUM_MD_SESSIONS)
Manoj Prabhu B571cf422017-08-08 19:01:41 +0530263 return -EINVAL;
264
265 if (peripheral == APPS_DATA)
266 return peripheral;
267
Chris Lewc937d692017-10-12 13:13:18 +0530268 /* With peripheral value bound checked
269 * return user pd value.
270 */
271 if (peripheral > NUM_PERIPHERALS)
272 return peripheral;
273
Manoj Prabhu B571cf422017-08-08 19:01:41 +0530274 type = GET_BUF_TYPE(ctxt);
275 if (type < 0 || type >= NUM_TYPES)
276 return -EINVAL;
277
278 fwd_info = &peripheral_info[type][peripheral];
279 if (!fwd_info)
280 return -EINVAL;
281
Manoj Prabhu B90e1f502017-11-02 20:01:45 +0530282 diag_id = GET_PD_CTXT(ctxt);
Manoj Prabhu B571cf422017-08-08 19:01:41 +0530283
Manoj Prabhu B90e1f502017-11-02 20:01:45 +0530284 if (driver->num_pd_session &&
285 driver->feature[peripheral].untag_header) {
286 if (diag_id == fwd_info->root_diag_id.diagid_val) {
287 if (peripheral != fwd_info->root_diag_id.pd)
Manoj Prabhu B571cf422017-08-08 19:01:41 +0530288 peripheral = -EINVAL;
289 } else {
290 for (i = 0; i <= (fwd_info->num_pd - 2); i++) {
Manoj Prabhu B90e1f502017-11-02 20:01:45 +0530291 if (diag_id ==
292 fwd_info->upd_diag_id[i].diagid_val) {
293 pd = fwd_info->upd_diag_id[i].pd;
294 index = pd - UPD_WLAN;
295 if ((index >= 0 && index < NUM_UPD) &&
296 driver->pd_logging_mode[index]) {
297 peripheral = pd;
Manoj Prabhu B571cf422017-08-08 19:01:41 +0530298 break;
299 }
300 }
301 }
302 }
303 }
304 return peripheral;
305}
306
307static void diagfwd_data_process_done(struct diagfwd_info *fwd_info,
308 struct diagfwd_buf_t *buf, int len)
309{
310 int err = 0;
311 int write_len = 0, peripheral = 0;
312 unsigned char *write_buf = NULL;
313 struct diag_md_session_t *session_info = NULL;
314 uint8_t hdlc_disabled = 0;
315
316 if (!fwd_info || !buf || len <= 0) {
317 diag_ws_release();
318 return;
319 }
320
321 switch (fwd_info->type) {
322 case TYPE_DATA:
323 case TYPE_CMD:
324 break;
325 default:
326 pr_err_ratelimited("diag: In %s, invalid type %d for peripheral %d\n",
327 __func__, fwd_info->type,
328 fwd_info->peripheral);
329 diag_ws_release();
330 return;
331 }
332
333 mutex_lock(&driver->hdlc_disable_mutex);
334 mutex_lock(&fwd_info->data_mutex);
335
336 peripheral =
337 diag_md_get_peripheral(buf->ctxt);
338 if (peripheral < 0) {
339 pr_err("diag:%s:%d invalid peripheral = %d\n",
340 __func__, __LINE__, peripheral);
341 mutex_unlock(&fwd_info->data_mutex);
342 mutex_unlock(&driver->hdlc_disable_mutex);
343 diag_ws_release();
344 return;
345 }
346
347 session_info =
348 diag_md_session_get_peripheral(peripheral);
349 if (session_info)
350 hdlc_disabled = session_info->hdlc_disabled;
351 else
352 hdlc_disabled = driver->hdlc_disabled;
353
354 if (hdlc_disabled) {
355 /* The data is raw and and on APPS side HDLC is disabled */
356 if (!buf) {
357 pr_err("diag: In %s, no match for non encode buffer %pK, peripheral %d, type: %d\n",
358 __func__, buf, fwd_info->peripheral,
359 fwd_info->type);
360 goto end;
361 }
362 if (len > PERIPHERAL_BUF_SZ) {
363 pr_err("diag: In %s, Incoming buffer too large %d, peripheral %d, type: %d\n",
364 __func__, len, fwd_info->peripheral,
365 fwd_info->type);
366 goto end;
367 }
368 write_len = len;
369 if (write_len <= 0)
370 goto end;
371 write_buf = buf->data_raw;
372 } else {
373 if (!buf) {
374 pr_err("diag: In %s, no match for non encode buffer %pK, peripheral %d, type: %d\n",
375 __func__, buf, fwd_info->peripheral,
376 fwd_info->type);
377 goto end;
378 }
379
380 write_len = check_bufsize_for_encoding(buf, len);
381 if (write_len <= 0) {
382 pr_err("diag: error in checking buf for encoding\n");
383 goto end;
384 }
385 write_buf = buf->data;
386 err = diag_add_hdlc_encoding(write_buf, &write_len,
387 buf->data_raw, len);
388 if (err) {
389 pr_err("diag: error in adding hdlc encoding\n");
390 goto end;
391 }
392 }
393
394 if (write_len > 0) {
395 err = diag_mux_write(DIAG_LOCAL_PROC, write_buf, write_len,
396 buf->ctxt);
397 if (err) {
398 pr_err_ratelimited("diag: In %s, unable to write to mux error: %d\n",
399 __func__, err);
400 goto end;
401 }
402 }
403 mutex_unlock(&fwd_info->data_mutex);
404 mutex_unlock(&driver->hdlc_disable_mutex);
405 diagfwd_queue_read(fwd_info);
406 return;
407
408end:
409 diag_ws_release();
410 mutex_unlock(&fwd_info->data_mutex);
411 mutex_unlock(&driver->hdlc_disable_mutex);
412 if (buf) {
Hardik Arya53bf3452017-09-06 15:34:19 +0530413 DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
414 "Marking buffer as free p: %d, t: %d, buf_num: %d\n",
415 fwd_info->peripheral, fwd_info->type,
416 GET_BUF_NUM(buf->ctxt));
Manoj Prabhu B571cf422017-08-08 19:01:41 +0530417 diagfwd_write_done(fwd_info->peripheral, fwd_info->type,
418 GET_BUF_NUM(buf->ctxt));
419 }
420 diagfwd_queue_read(fwd_info);
421}
422
Manoj Prabhu B90e1f502017-11-02 20:01:45 +0530423/*
424 * diagfwd_data_read_untag_done(struct diagfwd_info *fwd_info,
425 * unsigned char *buf, int len)
426 *
427 * Data received from the peripheral can contain data from core and user PD
428 * The function segregates the data depending on the diag_id in the header
429 * of the packet chunk and copies to PD specific buffers.
430 * Sets the context for the buffers using diag_id and process it later for
431 * splitting the stream based on active PD logging.
432 *
433 */
434
Manoj Prabhu B571cf422017-08-08 19:01:41 +0530435static void diagfwd_data_read_untag_done(struct diagfwd_info *fwd_info,
436 unsigned char *buf, int len)
437{
438 int i = 0;
439 int len_cpd = 0;
440 int ctxt_cpd = 0;
441 int len_upd[MAX_PERIPHERAL_UPD] = {0};
442 int ctxt_upd[MAX_PERIPHERAL_UPD] = {0};
443 int packet_len = 0, processed = 0;
444 unsigned char *temp_buf_main = NULL;
445 unsigned char *temp_buf_cpd = NULL;
446 unsigned char *temp_buf_upd[MAX_PERIPHERAL_UPD] = {NULL};
447 struct diagfwd_buf_t *temp_fwdinfo_cpd = NULL;
448 struct diagfwd_buf_t *temp_fwdinfo_upd = NULL;
449 int flag_buf_1 = 0, flag_buf_2 = 0;
450 uint8_t peripheral;
451
452 if (!fwd_info || !buf || len <= 0) {
453 diag_ws_release();
454 return;
455 }
456
457 switch (fwd_info->type) {
458 case TYPE_DATA:
459 case TYPE_CMD:
460 break;
461 default:
462 pr_err_ratelimited("diag: In %s, invalid type %d for peripheral %d\n",
463 __func__, fwd_info->type,
464 fwd_info->peripheral);
465 diag_ws_release();
466 return;
467 }
468 peripheral = fwd_info->peripheral;
469 if (peripheral >= NUM_PERIPHERALS)
470 return;
471
472 if (driver->feature[peripheral].encode_hdlc &&
473 driver->feature[peripheral].untag_header &&
474 driver->peripheral_untag[peripheral]) {
475 temp_buf_cpd = buf;
476 temp_buf_main = buf;
477 if (fwd_info->buf_1 &&
478 fwd_info->buf_1->data_raw == buf) {
479 flag_buf_1 = 1;
480 temp_fwdinfo_cpd = fwd_info->buf_1;
481 if (fwd_info->type == TYPE_DATA) {
Hardik Aryac8b90fe2017-11-24 11:55:23 +0530482 for (i = 0; (i <= (fwd_info->num_pd - 2)) &&
483 fwd_info->buf_upd[i][0]; i++)
Manoj Prabhu B571cf422017-08-08 19:01:41 +0530484 temp_buf_upd[i] =
485 fwd_info->buf_upd[i][0]->data_raw;
486 }
487 } else if (fwd_info->buf_2 &&
488 fwd_info->buf_2->data_raw == buf) {
489 flag_buf_2 = 1;
490 temp_fwdinfo_cpd = fwd_info->buf_2;
491 if (fwd_info->type == TYPE_DATA) {
Hardik Aryac8b90fe2017-11-24 11:55:23 +0530492 for (i = 0; (i <= (fwd_info->num_pd - 2)) &&
493 fwd_info->buf_upd[i][1]; i++)
Manoj Prabhu B571cf422017-08-08 19:01:41 +0530494 temp_buf_upd[i] =
495 fwd_info->buf_upd[i][1]->data_raw;
496 }
497 } else {
498 pr_err("diag: In %s, no match for buffer %pK, peripheral %d, type: %d\n",
499 __func__, buf, peripheral,
500 fwd_info->type);
501 goto end;
502 }
503
504 while (processed < len) {
505 pr_debug("diag_fr:untagged packet buf contents: %02x %02x %02x %02x\n",
506 *temp_buf_main, *(temp_buf_main+1),
507 *(temp_buf_main+2), *(temp_buf_main+3));
508 packet_len =
509 *(uint16_t *) (temp_buf_main + 2);
510 if (packet_len > PERIPHERAL_BUF_SZ)
511 goto end;
Manoj Prabhu B90e1f502017-11-02 20:01:45 +0530512 if ((*temp_buf_main) ==
513 fwd_info->root_diag_id.diagid_val) {
514 ctxt_cpd =
515 fwd_info->root_diag_id.diagid_val;
Manoj Prabhu B571cf422017-08-08 19:01:41 +0530516 len_cpd += packet_len;
517 if (temp_buf_cpd) {
518 memcpy(temp_buf_cpd,
519 (temp_buf_main + 4), packet_len);
520 temp_buf_cpd += packet_len;
521 }
522 } else {
Manoj Prabhu B90e1f502017-11-02 20:01:45 +0530523 for (i = 0; i <= (fwd_info->num_pd - 2); i++) {
524 if ((*temp_buf_main) ==
525 fwd_info->upd_diag_id[i].diagid_val) {
526 ctxt_upd[i] =
527 fwd_info->upd_diag_id[i].diagid_val;
528 if (temp_buf_upd[i]) {
529 memcpy(temp_buf_upd[i],
530 (temp_buf_main + 4),
531 packet_len);
532 temp_buf_upd[i] += packet_len;
533 }
534 len_upd[i] += packet_len;
535 }
Manoj Prabhu B571cf422017-08-08 19:01:41 +0530536 }
Manoj Prabhu B571cf422017-08-08 19:01:41 +0530537 }
538 len = len - 4;
539 temp_buf_main += (packet_len + 4);
540 processed += packet_len;
541 }
Hardik Arya53bf3452017-09-06 15:34:19 +0530542
543 if (flag_buf_1) {
544 fwd_info->cpd_len_1 = len_cpd;
545 for (i = 0; i <= (fwd_info->num_pd - 2); i++)
546 if (fwd_info->type == TYPE_DATA)
547 fwd_info->upd_len[i][0] = len_upd[i];
548 } else if (flag_buf_2) {
549 fwd_info->cpd_len_2 = len_cpd;
550 for (i = 0; i <= (fwd_info->num_pd - 2); i++)
551 if (fwd_info->type == TYPE_DATA)
552 fwd_info->upd_len[i][1] = len_upd[i];
553 }
554
Manoj Prabhu B571cf422017-08-08 19:01:41 +0530555 for (i = 0; i <= (fwd_info->num_pd - 2); i++) {
556 if (fwd_info->type == TYPE_DATA && len_upd[i]) {
Hardik Arya53bf3452017-09-06 15:34:19 +0530557 if (flag_buf_1)
Manoj Prabhu B571cf422017-08-08 19:01:41 +0530558 temp_fwdinfo_upd =
559 fwd_info->buf_upd[i][0];
Hardik Arya53bf3452017-09-06 15:34:19 +0530560 else
Manoj Prabhu B571cf422017-08-08 19:01:41 +0530561 temp_fwdinfo_upd =
562 fwd_info->buf_upd[i][1];
Hardik Aryac8b90fe2017-11-24 11:55:23 +0530563 if (!temp_fwdinfo_upd)
564 break;
Manoj Prabhu B571cf422017-08-08 19:01:41 +0530565 temp_fwdinfo_upd->ctxt &= 0x00FFFFFF;
566 temp_fwdinfo_upd->ctxt |=
567 (SET_PD_CTXT(ctxt_upd[i]));
568 atomic_set(&temp_fwdinfo_upd->in_busy, 1);
569 diagfwd_data_process_done(fwd_info,
570 temp_fwdinfo_upd, len_upd[i]);
571 } else {
572 if (flag_buf_1)
573 fwd_info->upd_len[i][0] = 0;
574 if (flag_buf_2)
575 fwd_info->upd_len[i][1] = 0;
576 }
577 }
Manoj Prabhu B37c77c02017-09-18 11:38:48 +0530578
Manoj Prabhu B571cf422017-08-08 19:01:41 +0530579 if (len_cpd) {
Manoj Prabhu B571cf422017-08-08 19:01:41 +0530580 temp_fwdinfo_cpd->ctxt &= 0x00FFFFFF;
Hardik Arya53bf3452017-09-06 15:34:19 +0530581 temp_fwdinfo_cpd->ctxt |= (SET_PD_CTXT(ctxt_cpd));
Manoj Prabhu B571cf422017-08-08 19:01:41 +0530582 diagfwd_data_process_done(fwd_info,
583 temp_fwdinfo_cpd, len_cpd);
584 } else {
585 if (flag_buf_1)
586 fwd_info->cpd_len_1 = 0;
587 if (flag_buf_2)
588 fwd_info->cpd_len_2 = 0;
589 }
590 } else {
591 diagfwd_data_read_done(fwd_info, buf, len);
592 }
593 return;
594end:
595 diag_ws_release();
596 if (temp_fwdinfo_cpd) {
Hardik Arya53bf3452017-09-06 15:34:19 +0530597 DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
598 "Marking buffer as free p: %d, t: %d, buf_num: %d\n",
599 fwd_info->peripheral, fwd_info->type,
600 GET_BUF_NUM(temp_fwdinfo_cpd->ctxt));
Manoj Prabhu B571cf422017-08-08 19:01:41 +0530601 diagfwd_write_done(fwd_info->peripheral, fwd_info->type,
602 GET_BUF_NUM(temp_fwdinfo_cpd->ctxt));
603 }
604 diagfwd_queue_read(fwd_info);
605}
606
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700607static void diagfwd_data_read_done(struct diagfwd_info *fwd_info,
608 unsigned char *buf, int len)
609{
610 int err = 0;
611 int write_len = 0;
612 unsigned char *write_buf = NULL;
613 struct diagfwd_buf_t *temp_buf = NULL;
614 struct diag_md_session_t *session_info = NULL;
615 uint8_t hdlc_disabled = 0;
616
617 if (!fwd_info || !buf || len <= 0) {
618 diag_ws_release();
619 return;
620 }
621
622 switch (fwd_info->type) {
623 case TYPE_DATA:
624 case TYPE_CMD:
625 break;
626 default:
627 pr_err_ratelimited("diag: In %s, invalid type %d for peripheral %d\n",
628 __func__, fwd_info->type,
629 fwd_info->peripheral);
630 diag_ws_release();
631 return;
632 }
633
634 mutex_lock(&driver->hdlc_disable_mutex);
635 mutex_lock(&fwd_info->data_mutex);
636 session_info = diag_md_session_get_peripheral(fwd_info->peripheral);
637 if (session_info)
638 hdlc_disabled = session_info->hdlc_disabled;
639 else
640 hdlc_disabled = driver->hdlc_disabled;
641
642 if (!driver->feature[fwd_info->peripheral].encode_hdlc) {
643 if (fwd_info->buf_1 && fwd_info->buf_1->data == buf) {
644 temp_buf = fwd_info->buf_1;
645 write_buf = fwd_info->buf_1->data;
646 } else if (fwd_info->buf_2 && fwd_info->buf_2->data == buf) {
647 temp_buf = fwd_info->buf_2;
648 write_buf = fwd_info->buf_2->data;
649 } else {
650 pr_err("diag: In %s, no match for buffer %pK, peripheral %d, type: %d\n",
651 __func__, buf, fwd_info->peripheral,
652 fwd_info->type);
653 goto end;
654 }
655 write_len = len;
656 } else if (hdlc_disabled) {
657 /* The data is raw and and on APPS side HDLC is disabled */
658 if (fwd_info->buf_1 && fwd_info->buf_1->data_raw == buf) {
659 temp_buf = fwd_info->buf_1;
660 } else if (fwd_info->buf_2 &&
661 fwd_info->buf_2->data_raw == buf) {
662 temp_buf = fwd_info->buf_2;
663 } else {
664 pr_err("diag: In %s, no match for non encode buffer %pK, peripheral %d, type: %d\n",
665 __func__, buf, fwd_info->peripheral,
666 fwd_info->type);
667 goto end;
668 }
669 if (len > PERIPHERAL_BUF_SZ) {
670 pr_err("diag: In %s, Incoming buffer too large %d, peripheral %d, type: %d\n",
671 __func__, len, fwd_info->peripheral,
672 fwd_info->type);
673 goto end;
674 }
675 write_len = len;
676 write_buf = buf;
677 } else {
678 if (fwd_info->buf_1 && fwd_info->buf_1->data_raw == buf) {
679 temp_buf = fwd_info->buf_1;
680 } else if (fwd_info->buf_2 &&
681 fwd_info->buf_2->data_raw == buf) {
682 temp_buf = fwd_info->buf_2;
683 } else {
684 pr_err("diag: In %s, no match for non encode buffer %pK, peripheral %d, type: %d\n",
685 __func__, buf, fwd_info->peripheral,
686 fwd_info->type);
687 goto end;
688 }
689 write_len = check_bufsize_for_encoding(temp_buf, len);
690 if (write_len <= 0) {
691 pr_err("diag: error in checking buf for encoding\n");
692 goto end;
693 }
694 write_buf = temp_buf->data;
695 err = diag_add_hdlc_encoding(write_buf, &write_len, buf, len);
696 if (err) {
697 pr_err("diag: error in adding hdlc encoding\n");
698 goto end;
699 }
700 }
701
702 if (write_len > 0) {
703 err = diag_mux_write(DIAG_LOCAL_PROC, write_buf, write_len,
704 temp_buf->ctxt);
705 if (err) {
706 pr_err_ratelimited("diag: In %s, unable to write to mux error: %d\n",
707 __func__, err);
708 goto end;
709 }
710 }
711 mutex_unlock(&fwd_info->data_mutex);
712 mutex_unlock(&driver->hdlc_disable_mutex);
713 diagfwd_queue_read(fwd_info);
714 return;
715
716end:
717 diag_ws_release();
718 mutex_unlock(&fwd_info->data_mutex);
719 mutex_unlock(&driver->hdlc_disable_mutex);
720 if (temp_buf) {
Hardik Arya53bf3452017-09-06 15:34:19 +0530721 DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
722 "Marking buffer as free p: %d, t: %d, buf_num: %d\n",
723 fwd_info->peripheral, fwd_info->type,
724 GET_BUF_NUM(temp_buf->ctxt));
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700725 diagfwd_write_done(fwd_info->peripheral, fwd_info->type,
726 GET_BUF_NUM(temp_buf->ctxt));
727 }
728 diagfwd_queue_read(fwd_info);
729}
730
731static void diagfwd_cntl_read_done(struct diagfwd_info *fwd_info,
732 unsigned char *buf, int len)
733{
734 if (!fwd_info) {
735 diag_ws_release();
736 return;
737 }
738
739 if (fwd_info->type != TYPE_CNTL) {
740 pr_err("diag: In %s, invalid type %d for peripheral %d\n",
741 __func__, fwd_info->type, fwd_info->peripheral);
742 diag_ws_release();
743 return;
744 }
745
746 diag_ws_on_read(DIAG_WS_MUX, len);
747 diag_cntl_process_read_data(fwd_info, buf, len);
748 /*
749 * Control packets are not consumed by the clients. Mimic
750 * consumption by setting and clearing the wakeup source copy_count
751 * explicitly.
752 */
753 diag_ws_on_copy_fail(DIAG_WS_MUX);
754 /* Reset the buffer in_busy value after processing the data */
755 if (fwd_info->buf_1)
756 atomic_set(&fwd_info->buf_1->in_busy, 0);
757
758 diagfwd_queue_read(fwd_info);
759 diagfwd_queue_read(&peripheral_info[TYPE_DATA][fwd_info->peripheral]);
760 diagfwd_queue_read(&peripheral_info[TYPE_CMD][fwd_info->peripheral]);
761}
762
763static void diagfwd_dci_read_done(struct diagfwd_info *fwd_info,
764 unsigned char *buf, int len)
765{
766 if (!fwd_info)
767 return;
768
769 switch (fwd_info->type) {
770 case TYPE_DCI:
771 case TYPE_DCI_CMD:
772 break;
773 default:
774 pr_err("diag: In %s, invalid type %d for peripheral %d\n",
775 __func__, fwd_info->type, fwd_info->peripheral);
776 return;
777 }
778
779 diag_dci_process_peripheral_data(fwd_info, (void *)buf, len);
780 /* Reset the buffer in_busy value after processing the data */
781 if (fwd_info->buf_1)
782 atomic_set(&fwd_info->buf_1->in_busy, 0);
783
784 diagfwd_queue_read(fwd_info);
785}
786
787static void diagfwd_reset_buffers(struct diagfwd_info *fwd_info,
788 unsigned char *buf)
789{
790 if (!fwd_info || !buf)
791 return;
792
793 if (!driver->feature[fwd_info->peripheral].encode_hdlc) {
794 if (fwd_info->buf_1 && fwd_info->buf_1->data == buf)
795 atomic_set(&fwd_info->buf_1->in_busy, 0);
796 else if (fwd_info->buf_2 && fwd_info->buf_2->data == buf)
797 atomic_set(&fwd_info->buf_2->in_busy, 0);
798 } else {
799 if (fwd_info->buf_1 && fwd_info->buf_1->data_raw == buf)
800 atomic_set(&fwd_info->buf_1->in_busy, 0);
801 else if (fwd_info->buf_2 && fwd_info->buf_2->data_raw == buf)
802 atomic_set(&fwd_info->buf_2->in_busy, 0);
803 }
Hardik Arya53bf3452017-09-06 15:34:19 +0530804 if (fwd_info->buf_1 && !atomic_read(&(fwd_info->buf_1->in_busy))) {
805 DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
806 "Buffer 1 for core PD is marked free, p: %d, t: %d\n",
807 fwd_info->peripheral, fwd_info->type);
808 }
809 if (fwd_info->buf_2 && !atomic_read(&(fwd_info->buf_2->in_busy))) {
810 DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
811 "Buffer 2 for core PD is marked free, p: %d, t: %d\n",
812 fwd_info->peripheral, fwd_info->type);
813 }
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700814}
815
816int diagfwd_peripheral_init(void)
817{
818 uint8_t peripheral;
819 uint8_t transport;
820 uint8_t type;
Manoj Prabhu B571cf422017-08-08 19:01:41 +0530821 int i = 0;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700822 struct diagfwd_info *fwd_info = NULL;
823
824 for (transport = 0; transport < NUM_TRANSPORT; transport++) {
825 early_init_info[transport] = kzalloc(
826 sizeof(struct diagfwd_info) * NUM_PERIPHERALS,
827 GFP_KERNEL);
828 if (!early_init_info[transport])
829 return -ENOMEM;
830 kmemleak_not_leak(early_init_info[transport]);
831 }
832
833 for (peripheral = 0; peripheral < NUM_PERIPHERALS; peripheral++) {
834 for (transport = 0; transport < NUM_TRANSPORT; transport++) {
835 fwd_info = &early_init_info[transport][peripheral];
836 fwd_info->peripheral = peripheral;
837 fwd_info->type = TYPE_CNTL;
838 fwd_info->transport = transport;
839 fwd_info->ctxt = NULL;
840 fwd_info->p_ops = NULL;
841 fwd_info->ch_open = 0;
842 fwd_info->inited = 1;
843 fwd_info->read_bytes = 0;
844 fwd_info->write_bytes = 0;
Manoj Prabhu B571cf422017-08-08 19:01:41 +0530845 fwd_info->cpd_len_1 = 0;
846 fwd_info->cpd_len_2 = 0;
847 fwd_info->num_pd = 0;
Manoj Prabhu B90e1f502017-11-02 20:01:45 +0530848 fwd_info->root_diag_id.diagid_val = 0;
Sreelakshmi Gownipalliae6c8e82016-11-29 16:01:13 -0800849 mutex_init(&fwd_info->buf_mutex);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700850 mutex_init(&fwd_info->data_mutex);
Sreelakshmi Gownipalliae6c8e82016-11-29 16:01:13 -0800851 spin_lock_init(&fwd_info->write_buf_lock);
Manoj Prabhu B571cf422017-08-08 19:01:41 +0530852
853 for (i = 0; i < MAX_PERIPHERAL_UPD; i++) {
Manoj Prabhu B90e1f502017-11-02 20:01:45 +0530854 fwd_info->upd_diag_id[i].diagid_val = 0;
Manoj Prabhu B571cf422017-08-08 19:01:41 +0530855 fwd_info->upd_len[i][0] = 0;
856 fwd_info->upd_len[i][1] = 0;
857 fwd_info->buf_upd[i][0] = NULL;
858 fwd_info->buf_upd[i][1] = NULL;
859 }
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700860 }
861 }
862
863 for (peripheral = 0; peripheral < NUM_PERIPHERALS; peripheral++) {
864 for (type = 0; type < NUM_TYPES; type++) {
865 fwd_info = &peripheral_info[type][peripheral];
866 fwd_info->peripheral = peripheral;
867 fwd_info->type = type;
868 fwd_info->ctxt = NULL;
869 fwd_info->p_ops = NULL;
870 fwd_info->ch_open = 0;
871 fwd_info->read_bytes = 0;
872 fwd_info->write_bytes = 0;
Manoj Prabhu B571cf422017-08-08 19:01:41 +0530873 fwd_info->num_pd = 0;
874 fwd_info->cpd_len_1 = 0;
875 fwd_info->cpd_len_2 = 0;
Manoj Prabhu B90e1f502017-11-02 20:01:45 +0530876 fwd_info->root_diag_id.diagid_val = 0;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700877 spin_lock_init(&fwd_info->write_buf_lock);
Sreelakshmi Gownipalliae6c8e82016-11-29 16:01:13 -0800878 mutex_init(&fwd_info->buf_mutex);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700879 mutex_init(&fwd_info->data_mutex);
Manoj Prabhu B571cf422017-08-08 19:01:41 +0530880
881 for (i = 0; i < MAX_PERIPHERAL_UPD; i++) {
Manoj Prabhu B90e1f502017-11-02 20:01:45 +0530882 fwd_info->upd_diag_id[i].diagid_val = 0;
Manoj Prabhu B571cf422017-08-08 19:01:41 +0530883 fwd_info->upd_len[i][0] = 0;
884 fwd_info->upd_len[i][1] = 0;
885 fwd_info->buf_upd[i][0] = NULL;
886 fwd_info->buf_upd[i][1] = NULL;
887 }
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700888 /*
889 * This state shouldn't be set for Control channels
890 * during initialization. This is set when the feature
891 * mask is received for the first time.
892 */
893 if (type != TYPE_CNTL)
894 fwd_info->inited = 1;
895 }
896 driver->diagfwd_data[peripheral] =
897 &peripheral_info[TYPE_DATA][peripheral];
898 driver->diagfwd_cntl[peripheral] =
899 &peripheral_info[TYPE_CNTL][peripheral];
900 driver->diagfwd_dci[peripheral] =
901 &peripheral_info[TYPE_DCI][peripheral];
902 driver->diagfwd_cmd[peripheral] =
903 &peripheral_info[TYPE_CMD][peripheral];
904 driver->diagfwd_dci_cmd[peripheral] =
905 &peripheral_info[TYPE_DCI_CMD][peripheral];
906 }
907
908 if (driver->supports_sockets)
909 diag_socket_init();
910 diag_glink_init();
911
912 return 0;
913}
914
915void diagfwd_peripheral_exit(void)
916{
917 uint8_t peripheral;
918 uint8_t type;
919 struct diagfwd_info *fwd_info = NULL;
Sreelakshmi Gownipalli323a9212017-09-18 12:41:47 -0700920 int transport = 0;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700921
922 diag_socket_exit();
923
924 for (peripheral = 0; peripheral < NUM_PERIPHERALS; peripheral++) {
925 for (type = 0; type < NUM_TYPES; type++) {
926 fwd_info = &peripheral_info[type][peripheral];
927 fwd_info->ctxt = NULL;
928 fwd_info->p_ops = NULL;
929 fwd_info->ch_open = 0;
930 diagfwd_buffers_exit(fwd_info);
931 }
932 }
933
934 for (peripheral = 0; peripheral < NUM_PERIPHERALS; peripheral++) {
935 driver->diagfwd_data[peripheral] = NULL;
936 driver->diagfwd_cntl[peripheral] = NULL;
937 driver->diagfwd_dci[peripheral] = NULL;
938 driver->diagfwd_cmd[peripheral] = NULL;
939 driver->diagfwd_dci_cmd[peripheral] = NULL;
940 }
941
Sreelakshmi Gownipalli323a9212017-09-18 12:41:47 -0700942 for (transport = 0; transport < NUM_TRANSPORT; transport++) {
943 kfree(early_init_info[transport]);
944 early_init_info[transport] = NULL;
945 }
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700946}
947
948int diagfwd_cntl_register(uint8_t transport, uint8_t peripheral, void *ctxt,
949 struct diag_peripheral_ops *ops,
950 struct diagfwd_info **fwd_ctxt)
951{
952 struct diagfwd_info *fwd_info = NULL;
953
954 if (!ctxt || !ops)
955 return -EIO;
956
957 if (transport >= NUM_TRANSPORT || peripheral >= NUM_PERIPHERALS)
958 return -EINVAL;
959
960 fwd_info = &early_init_info[transport][peripheral];
961 *fwd_ctxt = &early_init_info[transport][peripheral];
962 fwd_info->ctxt = ctxt;
963 fwd_info->p_ops = ops;
964 fwd_info->c_ops = &cntl_ch_ops;
965
966 return 0;
967}
968
969int diagfwd_register(uint8_t transport, uint8_t peripheral, uint8_t type,
970 void *ctxt, struct diag_peripheral_ops *ops,
971 struct diagfwd_info **fwd_ctxt)
972{
973 struct diagfwd_info *fwd_info = NULL;
974
975 if (peripheral >= NUM_PERIPHERALS || type >= NUM_TYPES ||
976 !ctxt || !ops || transport >= NUM_TRANSPORT) {
977 pr_err("diag: In %s, returning error\n", __func__);
978 return -EIO;
979 }
980
981 fwd_info = &peripheral_info[type][peripheral];
982 *fwd_ctxt = &peripheral_info[type][peripheral];
983 fwd_info->ctxt = ctxt;
984 fwd_info->p_ops = ops;
985 fwd_info->transport = transport;
986 fwd_info->ch_open = 0;
987
988 switch (type) {
989 case TYPE_DATA:
990 case TYPE_CMD:
991 fwd_info->c_ops = &data_ch_ops;
992 break;
993 case TYPE_DCI:
994 case TYPE_DCI_CMD:
995 fwd_info->c_ops = &dci_ch_ops;
996 break;
997 default:
998 pr_err("diag: In %s, invalid type: %d\n", __func__, type);
999 return -EINVAL;
1000 }
1001
1002 if (atomic_read(&fwd_info->opened) &&
1003 fwd_info->p_ops && fwd_info->p_ops->open) {
1004 /*
1005 * The registration can happen late, like in the case of
1006 * sockets. fwd_info->opened reflects diag_state. Propagate the
1007 * state to the peipherals.
1008 */
1009 fwd_info->p_ops->open(fwd_info->ctxt);
1010 }
1011
1012 return 0;
1013}
1014
1015void diagfwd_deregister(uint8_t peripheral, uint8_t type, void *ctxt)
1016{
1017 struct diagfwd_info *fwd_info = NULL;
1018
1019 if (peripheral >= NUM_PERIPHERALS || type >= NUM_TYPES || !ctxt)
1020 return;
1021
1022 fwd_info = &peripheral_info[type][peripheral];
1023 if (fwd_info->ctxt != ctxt) {
1024 pr_err("diag: In %s, unable to find a match for p: %d t: %d\n",
1025 __func__, peripheral, type);
1026 return;
1027 }
1028 fwd_info->ctxt = NULL;
1029 fwd_info->p_ops = NULL;
1030 fwd_info->ch_open = 0;
1031 diagfwd_buffers_exit(fwd_info);
1032
1033 switch (type) {
1034 case TYPE_DATA:
1035 driver->diagfwd_data[peripheral] = NULL;
1036 break;
1037 case TYPE_CNTL:
1038 driver->diagfwd_cntl[peripheral] = NULL;
1039 break;
1040 case TYPE_DCI:
1041 driver->diagfwd_dci[peripheral] = NULL;
1042 break;
1043 case TYPE_CMD:
1044 driver->diagfwd_cmd[peripheral] = NULL;
1045 break;
1046 case TYPE_DCI_CMD:
1047 driver->diagfwd_dci_cmd[peripheral] = NULL;
1048 break;
1049 }
1050}
1051
1052void diagfwd_close_transport(uint8_t transport, uint8_t peripheral)
1053{
1054 struct diagfwd_info *fwd_info = NULL;
1055 struct diagfwd_info *dest_info = NULL;
1056 int (*init_fn)(uint8_t) = NULL;
1057 void (*invalidate_fn)(void *, struct diagfwd_info *) = NULL;
1058 int (*check_channel_state)(void *) = NULL;
1059 uint8_t transport_open = 0;
1060 int i = 0;
1061
1062 if (peripheral >= NUM_PERIPHERALS)
1063 return;
1064
1065 switch (transport) {
1066 case TRANSPORT_GLINK:
1067 transport_open = TRANSPORT_SOCKET;
1068 init_fn = diag_socket_init_peripheral;
1069 invalidate_fn = diag_socket_invalidate;
1070 check_channel_state = diag_socket_check_state;
1071 break;
1072 case TRANSPORT_SOCKET:
1073 transport_open = TRANSPORT_GLINK;
1074 init_fn = diag_glink_init_peripheral;
1075 invalidate_fn = diag_glink_invalidate;
1076 check_channel_state = diag_glink_check_state;
1077 break;
1078 default:
1079 return;
1080
1081 }
1082
Manoj Prabhu B98325462017-01-10 20:19:28 +05301083 mutex_lock(&driver->diagfwd_channel_mutex[peripheral]);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001084 fwd_info = &early_init_info[transport][peripheral];
1085 if (fwd_info->p_ops && fwd_info->p_ops->close)
1086 fwd_info->p_ops->close(fwd_info->ctxt);
1087 fwd_info = &early_init_info[transport_open][peripheral];
1088 dest_info = &peripheral_info[TYPE_CNTL][peripheral];
1089 dest_info->inited = 1;
1090 dest_info->ctxt = fwd_info->ctxt;
1091 dest_info->p_ops = fwd_info->p_ops;
1092 dest_info->c_ops = fwd_info->c_ops;
1093 dest_info->ch_open = fwd_info->ch_open;
1094 dest_info->read_bytes = fwd_info->read_bytes;
1095 dest_info->write_bytes = fwd_info->write_bytes;
1096 dest_info->inited = fwd_info->inited;
1097 dest_info->buf_1 = fwd_info->buf_1;
1098 dest_info->buf_2 = fwd_info->buf_2;
1099 dest_info->transport = fwd_info->transport;
1100 invalidate_fn(dest_info->ctxt, dest_info);
1101 for (i = 0; i < NUM_WRITE_BUFFERS; i++)
1102 dest_info->buf_ptr[i] = fwd_info->buf_ptr[i];
1103 if (!check_channel_state(dest_info->ctxt))
1104 diagfwd_late_open(dest_info);
Manoj Prabhu B0e535532017-08-24 09:56:03 +05301105 diagfwd_cntl_open(dest_info);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001106 init_fn(peripheral);
Manoj Prabhu B98325462017-01-10 20:19:28 +05301107 mutex_unlock(&driver->diagfwd_channel_mutex[peripheral]);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001108 diagfwd_queue_read(&peripheral_info[TYPE_DATA][peripheral]);
1109 diagfwd_queue_read(&peripheral_info[TYPE_CMD][peripheral]);
1110}
1111
1112void *diagfwd_request_write_buf(struct diagfwd_info *fwd_info)
1113{
1114 void *buf = NULL;
1115 int index;
1116 unsigned long flags;
1117
1118 spin_lock_irqsave(&fwd_info->write_buf_lock, flags);
1119 for (index = 0 ; index < NUM_WRITE_BUFFERS; index++) {
1120 if (!atomic_read(&(fwd_info->buf_ptr[index]->in_busy))) {
1121 atomic_set(&(fwd_info->buf_ptr[index]->in_busy), 1);
1122 buf = fwd_info->buf_ptr[index]->data;
1123 if (!buf)
1124 return NULL;
1125 break;
1126 }
1127 }
1128 spin_unlock_irqrestore(&fwd_info->write_buf_lock, flags);
1129 return buf;
1130}
1131
1132int diagfwd_write(uint8_t peripheral, uint8_t type, void *buf, int len)
1133{
1134 struct diagfwd_info *fwd_info = NULL;
1135 int err = 0;
1136 uint8_t retry_count = 0;
1137 uint8_t max_retries = 3;
1138 void *buf_ptr = NULL;
1139
1140 if (peripheral >= NUM_PERIPHERALS || type >= NUM_TYPES)
1141 return -EINVAL;
1142
1143 if (type == TYPE_CMD || type == TYPE_DCI_CMD) {
1144 if (!driver->feature[peripheral].rcvd_feature_mask ||
1145 !driver->feature[peripheral].sent_feature_mask) {
1146 pr_debug_ratelimited("diag: In %s, feature mask for peripheral: %d not received or sent yet\n",
1147 __func__, peripheral);
1148 return 0;
1149 }
1150 if (!driver->feature[peripheral].separate_cmd_rsp)
1151 type = (type == TYPE_CMD) ? TYPE_DATA : TYPE_DCI;
1152 }
1153
1154 fwd_info = &peripheral_info[type][peripheral];
1155 if (!fwd_info->inited || !atomic_read(&fwd_info->opened))
1156 return -ENODEV;
1157
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301158 if (type == TYPE_CMD) {
Manoj Prabhu Bd7962422017-09-14 14:14:08 +05301159 if (driver->feature[peripheral].diag_id_support)
Manoj Prabhu B90e1f502017-11-02 20:01:45 +05301160 if (!fwd_info->root_diag_id.diagid_val ||
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301161 (!driver->diag_id_sent[peripheral])) {
1162 DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
1163 "diag: diag_id is not assigned yet\n");
1164 return 0;
1165 }
1166 }
1167
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001168 if (!(fwd_info->p_ops && fwd_info->p_ops->write && fwd_info->ctxt))
1169 return -EIO;
1170
1171 if (fwd_info->transport == TRANSPORT_GLINK) {
1172 buf_ptr = diagfwd_request_write_buf(fwd_info);
1173 if (buf_ptr)
1174 memcpy(buf_ptr, buf, len);
1175 else {
1176 DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
1177 "diag: buffer not found for writing\n");
1178 return -EIO;
1179 }
1180 } else
1181 buf_ptr = buf;
1182
1183 while (retry_count < max_retries) {
1184 err = 0;
1185 err = fwd_info->p_ops->write(fwd_info->ctxt, buf_ptr, len);
1186 if (err && err != -ENODEV) {
1187 usleep_range(100000, 101000);
1188 retry_count++;
1189 continue;
1190 }
1191 break;
1192 }
1193
1194 if (!err)
1195 fwd_info->write_bytes += len;
1196 else
1197 if (fwd_info->transport == TRANSPORT_GLINK)
1198 diagfwd_write_buffer_done(fwd_info, buf_ptr);
1199 return err;
1200}
1201
1202static void __diag_fwd_open(struct diagfwd_info *fwd_info)
1203{
1204 if (!fwd_info)
1205 return;
1206
1207 atomic_set(&fwd_info->opened, 1);
1208 if (!fwd_info->inited)
1209 return;
1210
Manoj Prabhu B1550bdd02017-04-14 12:50:24 +05301211 /*
1212 * Logging mode here is reflecting previous mode
1213 * status and will be updated to new mode later.
1214 *
1215 * Keeping the buffers busy for Memory Device Mode.
1216 */
1217
1218 if ((driver->logging_mode != DIAG_USB_MODE) ||
1219 driver->usb_connected) {
Hardik Arya53bf3452017-09-06 15:34:19 +05301220 if (fwd_info->buf_1) {
Manoj Prabhu B1550bdd02017-04-14 12:50:24 +05301221 atomic_set(&fwd_info->buf_1->in_busy, 0);
Hardik Arya53bf3452017-09-06 15:34:19 +05301222 DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
1223 "Buffer 1 for core PD is marked free, p: %d, t: %d\n",
Manoj Prabhu B90e1f502017-11-02 20:01:45 +05301224 fwd_info->peripheral, fwd_info->type);
Hardik Arya53bf3452017-09-06 15:34:19 +05301225 }
1226 if (fwd_info->buf_2) {
Manoj Prabhu B1550bdd02017-04-14 12:50:24 +05301227 atomic_set(&fwd_info->buf_2->in_busy, 0);
Hardik Arya53bf3452017-09-06 15:34:19 +05301228 DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
1229 "Buffer 2 for core PD is marked free, p: %d, t: %d\n",
Manoj Prabhu B90e1f502017-11-02 20:01:45 +05301230 fwd_info->peripheral, fwd_info->type);
Hardik Arya53bf3452017-09-06 15:34:19 +05301231 }
Manoj Prabhu B1550bdd02017-04-14 12:50:24 +05301232 }
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001233
1234 if (fwd_info->p_ops && fwd_info->p_ops->open)
1235 fwd_info->p_ops->open(fwd_info->ctxt);
1236
1237 diagfwd_queue_read(fwd_info);
1238}
1239
1240void diagfwd_early_open(uint8_t peripheral)
1241{
1242 uint8_t transport = 0;
1243 struct diagfwd_info *fwd_info = NULL;
1244
1245 if (peripheral >= NUM_PERIPHERALS)
1246 return;
1247
1248 for (transport = 0; transport < NUM_TRANSPORT; transport++) {
1249 fwd_info = &early_init_info[transport][peripheral];
1250 __diag_fwd_open(fwd_info);
1251 }
1252}
1253
1254void diagfwd_open(uint8_t peripheral, uint8_t type)
1255{
1256 struct diagfwd_info *fwd_info = NULL;
1257
1258 if (peripheral >= NUM_PERIPHERALS || type >= NUM_TYPES)
1259 return;
1260
1261 fwd_info = &peripheral_info[type][peripheral];
1262 __diag_fwd_open(fwd_info);
1263}
1264
1265void diagfwd_late_open(struct diagfwd_info *fwd_info)
1266{
1267 __diag_fwd_open(fwd_info);
1268}
1269
1270void diagfwd_close(uint8_t peripheral, uint8_t type)
1271{
1272 struct diagfwd_info *fwd_info = NULL;
1273
1274 if (peripheral >= NUM_PERIPHERALS || type >= NUM_TYPES)
1275 return;
1276
1277 fwd_info = &peripheral_info[type][peripheral];
1278 atomic_set(&fwd_info->opened, 0);
1279 if (!fwd_info->inited)
1280 return;
1281
1282 if (fwd_info->p_ops && fwd_info->p_ops->close)
1283 fwd_info->p_ops->close(fwd_info->ctxt);
1284
1285 if (fwd_info->buf_1)
1286 atomic_set(&fwd_info->buf_1->in_busy, 1);
1287 /*
1288 * Only Data channels have two buffers. Set both the buffers
1289 * to busy on close.
1290 */
1291 if (fwd_info->buf_2)
1292 atomic_set(&fwd_info->buf_2->in_busy, 1);
1293}
1294
1295int diagfwd_channel_open(struct diagfwd_info *fwd_info)
1296{
1297 int i;
1298
1299 if (!fwd_info)
1300 return -EIO;
1301
1302 if (!fwd_info->inited) {
1303 pr_debug("diag: In %s, channel is not inited, p: %d, t: %d\n",
1304 __func__, fwd_info->peripheral, fwd_info->type);
1305 return -EINVAL;
1306 }
1307
1308 if (fwd_info->ch_open) {
1309 pr_debug("diag: In %s, channel is already open, p: %d, t: %d\n",
1310 __func__, fwd_info->peripheral, fwd_info->type);
1311 return 0;
1312 }
Manoj Prabhu Bb989d562017-06-28 11:36:20 +05301313 mutex_lock(&driver->diagfwd_channel_mutex[fwd_info->peripheral]);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001314 fwd_info->ch_open = 1;
1315 diagfwd_buffers_init(fwd_info);
Manoj Prabhu B8ee172f2017-07-14 14:34:26 +05301316
1317 /*
Manoj Prabhu B0e535532017-08-24 09:56:03 +05301318 * Initialize buffers for glink supported
1319 * peripherals only.
Manoj Prabhu B8ee172f2017-07-14 14:34:26 +05301320 */
Manoj Prabhu B0e535532017-08-24 09:56:03 +05301321 if (fwd_info->transport == TRANSPORT_GLINK)
Manoj Prabhu B8ee172f2017-07-14 14:34:26 +05301322 diagfwd_write_buffers_init(fwd_info);
Manoj Prabhu B8ee172f2017-07-14 14:34:26 +05301323
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001324 if (fwd_info && fwd_info->c_ops && fwd_info->c_ops->open)
1325 fwd_info->c_ops->open(fwd_info);
1326 for (i = 0; i < NUM_WRITE_BUFFERS; i++) {
1327 if (fwd_info->buf_ptr[i])
1328 atomic_set(&fwd_info->buf_ptr[i]->in_busy, 0);
1329 }
1330 diagfwd_queue_read(fwd_info);
1331 DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "p: %d t: %d considered opened\n",
1332 fwd_info->peripheral, fwd_info->type);
1333
1334 if (atomic_read(&fwd_info->opened)) {
1335 if (fwd_info->p_ops && fwd_info->p_ops->open)
1336 fwd_info->p_ops->open(fwd_info->ctxt);
1337 }
Manoj Prabhu Bb989d562017-06-28 11:36:20 +05301338 mutex_unlock(&driver->diagfwd_channel_mutex[fwd_info->peripheral]);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001339 return 0;
1340}
1341
1342int diagfwd_channel_close(struct diagfwd_info *fwd_info)
1343{
1344 int i;
1345
1346 if (!fwd_info)
1347 return -EIO;
1348
Mohit Aggarwalaea1a722017-07-24 14:03:56 +05301349 if (fwd_info->type == TYPE_CNTL)
1350 flush_workqueue(driver->cntl_wq);
1351
Manoj Prabhu Bb989d562017-06-28 11:36:20 +05301352 mutex_lock(&driver->diagfwd_channel_mutex[fwd_info->peripheral]);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001353 fwd_info->ch_open = 0;
1354 if (fwd_info && fwd_info->c_ops && fwd_info->c_ops->close)
1355 fwd_info->c_ops->close(fwd_info);
1356
Hardik Arya53bf3452017-09-06 15:34:19 +05301357 if (fwd_info->buf_1 && fwd_info->buf_1->data) {
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001358 atomic_set(&fwd_info->buf_1->in_busy, 0);
Hardik Arya53bf3452017-09-06 15:34:19 +05301359 DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
1360 "Buffer 1 for core PD is marked free, p: %d, t: %d\n",
1361 fwd_info->peripheral, fwd_info->type);
1362 }
1363 if (fwd_info->buf_2 && fwd_info->buf_2->data) {
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001364 atomic_set(&fwd_info->buf_2->in_busy, 0);
Hardik Arya53bf3452017-09-06 15:34:19 +05301365 DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
1366 "Buffer 2 for core PD is marked free, p: %d, t: %d\n",
1367 fwd_info->peripheral, fwd_info->type);
1368 }
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001369
1370 for (i = 0; i < NUM_WRITE_BUFFERS; i++) {
1371 if (fwd_info->buf_ptr[i])
1372 atomic_set(&fwd_info->buf_ptr[i]->in_busy, 1);
1373 }
1374 DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "p: %d t: %d considered closed\n",
1375 fwd_info->peripheral, fwd_info->type);
Manoj Prabhu Bb989d562017-06-28 11:36:20 +05301376 mutex_unlock(&driver->diagfwd_channel_mutex[fwd_info->peripheral]);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001377 return 0;
1378}
1379
1380int diagfwd_channel_read_done(struct diagfwd_info *fwd_info,
1381 unsigned char *buf, uint32_t len)
1382{
1383 if (!fwd_info) {
1384 diag_ws_release();
1385 return -EIO;
1386 }
1387
1388 /*
1389 * Diag peripheral layers should send len as 0 if there is any error
1390 * in reading data from the transport. Use this information to reset the
1391 * in_busy flags. No need to queue read in this case.
1392 */
1393 if (len == 0) {
Hardik Arya53bf3452017-09-06 15:34:19 +05301394 DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
1395 "Read Length is 0, resetting the diag buffers p: %d, t: %d\n",
1396 fwd_info->peripheral, fwd_info->type);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001397 diagfwd_reset_buffers(fwd_info, buf);
1398 diag_ws_release();
1399 return 0;
1400 }
1401
1402 if (fwd_info && fwd_info->c_ops && fwd_info->c_ops->read_done)
1403 fwd_info->c_ops->read_done(fwd_info, buf, len);
1404 fwd_info->read_bytes += len;
1405
1406 return 0;
1407}
1408
Hardik Arya53bf3452017-09-06 15:34:19 +05301409void diagfwd_write_done(uint8_t peripheral, uint8_t type, int buf_num)
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001410{
Manoj Prabhu B37c77c02017-09-18 11:38:48 +05301411 int i = 0, upd_valid_len = 0;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001412 struct diagfwd_info *fwd_info = NULL;
1413
1414 if (peripheral >= NUM_PERIPHERALS || type >= NUM_TYPES)
1415 return;
1416
1417 fwd_info = &peripheral_info[type][peripheral];
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301418 if (!fwd_info)
1419 return;
1420
Hardik Arya53bf3452017-09-06 15:34:19 +05301421 if (buf_num == 1 && fwd_info->buf_1) {
Manoj Prabhu B90e1f502017-11-02 20:01:45 +05301422 /*
1423 * Core PD buffer data is processed and
1424 * length in the buffer is marked zero.
1425 *
1426 * Check if the user PD buffer contains any
1427 * data before freeing core PD buffer.
1428 */
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301429 fwd_info->cpd_len_1 = 0;
Manoj Prabhu B37c77c02017-09-18 11:38:48 +05301430 for (i = 0; i <= (fwd_info->num_pd - 2); i++) {
1431 if (fwd_info->upd_len[i][0]) {
1432 upd_valid_len = 1;
1433 break;
1434 }
1435 }
Manoj Prabhu B90e1f502017-11-02 20:01:45 +05301436 /*
1437 * Do not free the core pd buffer if valid data
1438 * is present in any user PD buffer.
1439 */
Hardik Arya53bf3452017-09-06 15:34:19 +05301440 if (!upd_valid_len) {
Manoj Prabhu B37c77c02017-09-18 11:38:48 +05301441 atomic_set(&fwd_info->buf_1->in_busy, 0);
Hardik Arya53bf3452017-09-06 15:34:19 +05301442 DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
1443 "Buffer 1 for core PD is marked free, p: %d, t: %d, buf_num: %d\n",
1444 fwd_info->peripheral, fwd_info->type, buf_num);
1445 }
1446 } else if (buf_num == 2 && fwd_info->buf_2) {
Manoj Prabhu B90e1f502017-11-02 20:01:45 +05301447 /*
1448 * Core PD buffer data is processed and
1449 * length in the buffer is marked zero.
1450 *
1451 * Check if the user PD buffer contains any
1452 * data before freeing core PD buffer.
1453 */
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301454 fwd_info->cpd_len_2 = 0;
Manoj Prabhu B37c77c02017-09-18 11:38:48 +05301455 for (i = 0; i <= (fwd_info->num_pd - 2); i++) {
1456 if (fwd_info->upd_len[i][1]) {
1457 upd_valid_len = 1;
1458 break;
1459 }
1460 }
Manoj Prabhu B90e1f502017-11-02 20:01:45 +05301461 /*
1462 * Do not free the core pd buffer if valid data
1463 * is present in any user PD buffer
1464 */
Hardik Arya53bf3452017-09-06 15:34:19 +05301465 if (!upd_valid_len) {
Manoj Prabhu B37c77c02017-09-18 11:38:48 +05301466 atomic_set(&fwd_info->buf_2->in_busy, 0);
Hardik Arya53bf3452017-09-06 15:34:19 +05301467 DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
1468 "Buffer 2 for core PD is marked free, p: %d, t: %d, buf_num: %d\n",
1469 fwd_info->peripheral, fwd_info->type, buf_num);
1470 }
1471 } else if (buf_num >= 3 && (buf_num % 2)) {
Manoj Prabhu B90e1f502017-11-02 20:01:45 +05301472 /*
1473 * Go through each User PD buffer, validate the
1474 * request for freeing the buffer by validating
1475 * the buffer number.
1476 *
1477 */
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301478 for (i = 0; i <= (fwd_info->num_pd - 2); i++) {
Manoj Prabhu B90e1f502017-11-02 20:01:45 +05301479 if (fwd_info->buf_upd[i][0] &&
1480 (buf_num == ((2 * i) + 3))) {
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301481 /* Buffer 1 for ith user PD is freed */
Manoj Prabhu B90e1f502017-11-02 20:01:45 +05301482 atomic_set(&fwd_info->buf_upd[i][0]->in_busy,
1483 0);
1484 fwd_info->upd_len[i][0] = 0;
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301485 }
Manoj Prabhu B90e1f502017-11-02 20:01:45 +05301486 /*
1487 * Check if there is any data in user PD buffer other
1488 * than buffer requested for freeing.
1489 *
1490 */
1491 if (fwd_info->upd_len[i][0])
1492 upd_valid_len = 1;
1493 }
1494 /*
1495 * Mark the core pd buffer free if there is no
1496 * data present in core PD buffer and other User PD buffer.
1497 *
1498 */
1499 if (!upd_valid_len && !fwd_info->cpd_len_1) {
1500 atomic_set(&fwd_info->buf_1->in_busy, 0);
1501 DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
Hardik Arya53bf3452017-09-06 15:34:19 +05301502 "Buffer 1 for core PD is marked free, p: %d, t: %d, buf_num: %d\n",
1503 fwd_info->peripheral, fwd_info->type, buf_num);
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301504 }
Hardik Arya53bf3452017-09-06 15:34:19 +05301505 } else if (buf_num >= 4 && !(buf_num % 2)) {
Manoj Prabhu B90e1f502017-11-02 20:01:45 +05301506 /*
1507 * Go through each User PD buffer, validate the
1508 * request for freeing the buffer by validating
1509 * the buffer number.
1510 *
1511 */
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301512 for (i = 0; i <= (fwd_info->num_pd - 2); i++) {
Manoj Prabhu B90e1f502017-11-02 20:01:45 +05301513 if (fwd_info->buf_upd[i][1] &&
1514 (buf_num == ((2 * i) + 4))) {
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301515 /* Buffer 2 for ith user PD is freed */
Manoj Prabhu B90e1f502017-11-02 20:01:45 +05301516 atomic_set(&fwd_info->buf_upd[i][1]->in_busy,
1517 0);
1518 fwd_info->upd_len[i][1] = 0;
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301519 }
Manoj Prabhu B90e1f502017-11-02 20:01:45 +05301520 /*
1521 * Check if there is any data in user PD buffer other
1522 * than buffer requested for freeing.
1523 *
1524 */
1525 if (fwd_info->upd_len[i][1])
1526 upd_valid_len = 1;
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301527 }
Manoj Prabhu B90e1f502017-11-02 20:01:45 +05301528 /*
1529 * Mark the core pd buffer free if there is no
1530 * data present in core PD buffer and other User PD buffer.
1531 *
1532 */
1533 if (!upd_valid_len && !fwd_info->cpd_len_2) {
1534 atomic_set(&fwd_info->buf_2->in_busy, 0);
1535 DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
1536 "Buffer 2 for core PD is marked free, p: %d, t: %d, buf_num: %d\n",
1537 fwd_info->peripheral, fwd_info->type, buf_num);
1538 }
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301539 } else
Manoj Prabhu B90e1f502017-11-02 20:01:45 +05301540 pr_err("diag: In %s, invalid buf_num %d\n", __func__, buf_num);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001541
1542 diagfwd_queue_read(fwd_info);
1543}
1544
1545int diagfwd_write_buffer_done(struct diagfwd_info *fwd_info, const void *ptr)
1546{
1547
1548 int found = 0;
1549 int index = 0;
1550 unsigned long flags;
1551
1552 if (!fwd_info || !ptr)
1553 return found;
1554 spin_lock_irqsave(&fwd_info->write_buf_lock, flags);
1555 for (index = 0; index < NUM_WRITE_BUFFERS; index++) {
1556 if (fwd_info->buf_ptr[index]->data == ptr) {
1557 atomic_set(&fwd_info->buf_ptr[index]->in_busy, 0);
1558 found = 1;
1559 break;
1560 }
1561 }
1562 spin_unlock_irqrestore(&fwd_info->write_buf_lock, flags);
1563 return found;
1564}
1565
1566void diagfwd_channel_read(struct diagfwd_info *fwd_info)
1567{
1568 int err = 0;
1569 uint32_t read_len = 0;
1570 unsigned char *read_buf = NULL;
1571 struct diagfwd_buf_t *temp_buf = NULL;
1572
1573 if (!fwd_info) {
1574 diag_ws_release();
1575 return;
1576 }
1577
1578 if (!fwd_info->inited || !atomic_read(&fwd_info->opened)) {
1579 pr_debug("diag: In %s, p: %d, t: %d, inited: %d, opened: %d ch_open: %d\n",
1580 __func__, fwd_info->peripheral, fwd_info->type,
1581 fwd_info->inited, atomic_read(&fwd_info->opened),
1582 fwd_info->ch_open);
1583 diag_ws_release();
1584 return;
1585 }
1586
1587 if (fwd_info->buf_1 && !atomic_read(&fwd_info->buf_1->in_busy)) {
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001588 if (driver->feature[fwd_info->peripheral].encode_hdlc &&
1589 (fwd_info->type == TYPE_DATA ||
1590 fwd_info->type == TYPE_CMD)) {
1591 read_buf = fwd_info->buf_1->data_raw;
1592 read_len = fwd_info->buf_1->len_raw;
1593 } else {
1594 read_buf = fwd_info->buf_1->data;
1595 read_len = fwd_info->buf_1->len;
1596 }
Mohit Aggarwal77f227d2016-11-24 13:48:12 +05301597 if (read_buf) {
1598 temp_buf = fwd_info->buf_1;
1599 atomic_set(&temp_buf->in_busy, 1);
1600 }
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001601 } else if (fwd_info->buf_2 && !atomic_read(&fwd_info->buf_2->in_busy)) {
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001602 if (driver->feature[fwd_info->peripheral].encode_hdlc &&
1603 (fwd_info->type == TYPE_DATA ||
1604 fwd_info->type == TYPE_CMD)) {
1605 read_buf = fwd_info->buf_2->data_raw;
1606 read_len = fwd_info->buf_2->len_raw;
1607 } else {
1608 read_buf = fwd_info->buf_2->data;
1609 read_len = fwd_info->buf_2->len;
1610 }
Mohit Aggarwal77f227d2016-11-24 13:48:12 +05301611 if (read_buf) {
1612 temp_buf = fwd_info->buf_2;
1613 atomic_set(&temp_buf->in_busy, 1);
1614 }
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001615 } else {
1616 pr_debug("diag: In %s, both buffers are empty for p: %d, t: %d\n",
1617 __func__, fwd_info->peripheral, fwd_info->type);
1618 }
1619
1620 if (!read_buf) {
1621 diag_ws_release();
1622 return;
1623 }
1624
1625 if (!(fwd_info->p_ops && fwd_info->p_ops->read && fwd_info->ctxt))
1626 goto fail_return;
1627
1628 DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "issued a read p: %d t: %d buf: %pK\n",
1629 fwd_info->peripheral, fwd_info->type, read_buf);
1630 err = fwd_info->p_ops->read(fwd_info->ctxt, read_buf, read_len);
1631 if (err)
1632 goto fail_return;
1633
1634 return;
1635
1636fail_return:
1637 diag_ws_release();
1638 atomic_set(&temp_buf->in_busy, 0);
Hardik Aryafe005cc2017-12-01 12:31:58 +05301639 DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
1640 "Buffer for core PD is marked free, p: %d, t: %d, buf_num: %d\n",
1641 fwd_info->peripheral, fwd_info->type,
1642 GET_BUF_NUM(temp_buf->ctxt));
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001643}
1644
1645static void diagfwd_queue_read(struct diagfwd_info *fwd_info)
1646{
1647 if (!fwd_info)
1648 return;
1649
1650 if (!fwd_info->inited || !atomic_read(&fwd_info->opened)) {
1651 pr_debug("diag: In %s, p: %d, t: %d, inited: %d, opened: %d ch_open: %d\n",
1652 __func__, fwd_info->peripheral, fwd_info->type,
1653 fwd_info->inited, atomic_read(&fwd_info->opened),
1654 fwd_info->ch_open);
1655 return;
1656 }
1657
1658 /*
1659 * Don't queue a read on the data and command channels before receiving
1660 * the feature mask from the peripheral. We won't know which buffer to
1661 * use - HDLC or non HDLC buffer for reading.
1662 */
1663 if ((!driver->feature[fwd_info->peripheral].rcvd_feature_mask) &&
1664 (fwd_info->type != TYPE_CNTL)) {
1665 return;
1666 }
1667
1668 if (fwd_info->p_ops && fwd_info->p_ops->queue_read && fwd_info->ctxt)
1669 fwd_info->p_ops->queue_read(fwd_info->ctxt);
1670}
1671
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301672static int diagfwd_buffers_allocate(struct diagfwd_info *fwd_info)
1673{
1674 int i, j;
1675
1676 for (i = 0; ((fwd_info->num_pd > 1) &&
1677 (i <= (fwd_info->num_pd - 2))); i++) {
1678 for (j = 0; j < NUM_WRITE_BUFFERS; j++) {
1679 if (!fwd_info->buf_upd[i][j]) {
1680 fwd_info->buf_upd[i][j] =
1681 kzalloc(sizeof(struct diagfwd_buf_t),
1682 GFP_KERNEL);
1683 if (ZERO_OR_NULL_PTR(fwd_info->buf_upd[i][j]))
1684 return -ENOMEM;
1685 kmemleak_not_leak(fwd_info->buf_upd[i][j]);
1686 }
1687
1688 if (fwd_info->buf_upd[i][j] &&
1689 !fwd_info->buf_upd[i][j]->data) {
1690 fwd_info->buf_upd[i][j]->data =
1691 kzalloc(PERIPHERAL_BUF_SZ +
1692 APF_DIAG_PADDING,
1693 GFP_KERNEL);
1694 if (ZERO_OR_NULL_PTR(
1695 fwd_info->buf_upd[i][j]->data))
1696 return -ENOMEM;
1697 fwd_info->buf_upd[i][j]->len =
1698 PERIPHERAL_BUF_SZ;
1699 kmemleak_not_leak(
1700 fwd_info->buf_upd[i][j]->data);
1701 fwd_info->buf_upd[i][j]->ctxt =
1702 SET_BUF_CTXT(fwd_info->peripheral,
1703 fwd_info->type, ((2 * i) + (j + 3)));
1704 }
1705
1706 if (driver->supports_apps_hdlc_encoding) {
1707 if (fwd_info->buf_upd[i][j] &&
1708 !fwd_info->buf_upd[i][j]->data_raw) {
1709 fwd_info->buf_upd[i][j]->data_raw =
1710 kzalloc(PERIPHERAL_BUF_SZ +
1711 APF_DIAG_PADDING,
1712 GFP_KERNEL);
1713 if (ZERO_OR_NULL_PTR(
1714 fwd_info->buf_upd[i][j]->data_raw))
1715 return -ENOMEM;
1716 fwd_info->buf_upd[i][j]->len_raw =
1717 PERIPHERAL_BUF_SZ;
1718 kmemleak_not_leak(
1719 fwd_info->buf_upd[i][j]->data_raw);
1720 }
1721 }
1722 }
1723 }
1724 return 0;
1725}
1726
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001727void diagfwd_buffers_init(struct diagfwd_info *fwd_info)
1728{
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301729 int ret = 0;
1730 unsigned char *temp_char_buf;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001731
1732 if (!fwd_info)
1733 return;
1734
1735 if (!fwd_info->inited) {
1736 pr_err("diag: In %s, channel not inited, p: %d, t: %d\n",
1737 __func__, fwd_info->peripheral, fwd_info->type);
1738 return;
1739 }
1740
Sreelakshmi Gownipalliae6c8e82016-11-29 16:01:13 -08001741 mutex_lock(&fwd_info->buf_mutex);
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301742
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001743 if (!fwd_info->buf_1) {
1744 fwd_info->buf_1 = kzalloc(sizeof(struct diagfwd_buf_t),
Sreelakshmi Gownipalliae6c8e82016-11-29 16:01:13 -08001745 GFP_KERNEL);
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301746 if (ZERO_OR_NULL_PTR(fwd_info->buf_1))
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001747 goto err;
1748 kmemleak_not_leak(fwd_info->buf_1);
1749 }
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301750
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001751 if (!fwd_info->buf_1->data) {
1752 fwd_info->buf_1->data = kzalloc(PERIPHERAL_BUF_SZ +
1753 APF_DIAG_PADDING,
Sreelakshmi Gownipalliae6c8e82016-11-29 16:01:13 -08001754 GFP_KERNEL);
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301755 if (ZERO_OR_NULL_PTR(fwd_info->buf_1->data))
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001756 goto err;
1757 fwd_info->buf_1->len = PERIPHERAL_BUF_SZ;
1758 kmemleak_not_leak(fwd_info->buf_1->data);
1759 fwd_info->buf_1->ctxt = SET_BUF_CTXT(fwd_info->peripheral,
1760 fwd_info->type, 1);
1761 }
1762
1763 if (fwd_info->type == TYPE_DATA) {
1764 if (!fwd_info->buf_2) {
1765 fwd_info->buf_2 = kzalloc(sizeof(struct diagfwd_buf_t),
Sreelakshmi Gownipalliae6c8e82016-11-29 16:01:13 -08001766 GFP_KERNEL);
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301767 if (ZERO_OR_NULL_PTR(fwd_info->buf_2))
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001768 goto err;
1769 kmemleak_not_leak(fwd_info->buf_2);
1770 }
1771
1772 if (!fwd_info->buf_2->data) {
1773 fwd_info->buf_2->data = kzalloc(PERIPHERAL_BUF_SZ +
1774 APF_DIAG_PADDING,
Sreelakshmi Gownipalliae6c8e82016-11-29 16:01:13 -08001775 GFP_KERNEL);
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301776 if (ZERO_OR_NULL_PTR(fwd_info->buf_2->data))
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001777 goto err;
1778 fwd_info->buf_2->len = PERIPHERAL_BUF_SZ;
1779 kmemleak_not_leak(fwd_info->buf_2->data);
1780 fwd_info->buf_2->ctxt = SET_BUF_CTXT(
1781 fwd_info->peripheral,
1782 fwd_info->type, 2);
1783 }
1784
Manoj Prabhu B0e535532017-08-24 09:56:03 +05301785 if (driver->feature[fwd_info->peripheral].untag_header) {
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301786 ret = diagfwd_buffers_allocate(fwd_info);
1787 if (ret)
1788 goto err;
Manoj Prabhu B0e535532017-08-24 09:56:03 +05301789 }
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301790
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001791 if (driver->supports_apps_hdlc_encoding) {
1792 /* In support of hdlc encoding */
1793 if (!fwd_info->buf_1->data_raw) {
1794 fwd_info->buf_1->data_raw =
1795 kzalloc(PERIPHERAL_BUF_SZ +
1796 APF_DIAG_PADDING,
Sreelakshmi Gownipalliae6c8e82016-11-29 16:01:13 -08001797 GFP_KERNEL);
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301798 temp_char_buf =
1799 fwd_info->buf_1->data_raw;
1800 if (ZERO_OR_NULL_PTR(temp_char_buf))
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001801 goto err;
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301802 fwd_info->buf_1->len_raw =
1803 PERIPHERAL_BUF_SZ;
1804 kmemleak_not_leak(temp_char_buf);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001805 }
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301806
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001807 if (!fwd_info->buf_2->data_raw) {
1808 fwd_info->buf_2->data_raw =
1809 kzalloc(PERIPHERAL_BUF_SZ +
1810 APF_DIAG_PADDING,
Sreelakshmi Gownipalliae6c8e82016-11-29 16:01:13 -08001811 GFP_KERNEL);
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301812 temp_char_buf =
1813 fwd_info->buf_2->data_raw;
1814 if (ZERO_OR_NULL_PTR(temp_char_buf))
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001815 goto err;
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301816 fwd_info->buf_2->len_raw =
1817 PERIPHERAL_BUF_SZ;
1818 kmemleak_not_leak(temp_char_buf);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001819 }
1820 }
1821 }
1822
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301823 if (fwd_info->type == TYPE_CMD &&
1824 driver->supports_apps_hdlc_encoding) {
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001825 /* In support of hdlc encoding */
1826 if (!fwd_info->buf_1->data_raw) {
1827 fwd_info->buf_1->data_raw = kzalloc(PERIPHERAL_BUF_SZ +
1828 APF_DIAG_PADDING,
Sreelakshmi Gownipalliae6c8e82016-11-29 16:01:13 -08001829 GFP_KERNEL);
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301830 temp_char_buf =
1831 fwd_info->buf_1->data_raw;
1832 if (ZERO_OR_NULL_PTR(temp_char_buf))
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001833 goto err;
1834 fwd_info->buf_1->len_raw = PERIPHERAL_BUF_SZ;
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301835 kmemleak_not_leak(temp_char_buf);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001836 }
1837 }
1838
Sreelakshmi Gownipalliae6c8e82016-11-29 16:01:13 -08001839 mutex_unlock(&fwd_info->buf_mutex);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001840 return;
1841
1842err:
Sreelakshmi Gownipalliae6c8e82016-11-29 16:01:13 -08001843 mutex_unlock(&fwd_info->buf_mutex);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001844 diagfwd_buffers_exit(fwd_info);
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301845 return;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001846}
1847
1848static void diagfwd_buffers_exit(struct diagfwd_info *fwd_info)
1849{
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301850 int i = 0;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001851
1852 if (!fwd_info)
1853 return;
1854
Sreelakshmi Gownipalliae6c8e82016-11-29 16:01:13 -08001855 mutex_lock(&fwd_info->buf_mutex);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001856 if (fwd_info->buf_1) {
1857 kfree(fwd_info->buf_1->data);
1858 fwd_info->buf_1->data = NULL;
1859 kfree(fwd_info->buf_1->data_raw);
1860 fwd_info->buf_1->data_raw = NULL;
1861 kfree(fwd_info->buf_1);
1862 fwd_info->buf_1 = NULL;
1863 }
1864 if (fwd_info->buf_2) {
1865 kfree(fwd_info->buf_2->data);
1866 fwd_info->buf_2->data = NULL;
1867 kfree(fwd_info->buf_2->data_raw);
1868 fwd_info->buf_2->data_raw = NULL;
1869 kfree(fwd_info->buf_2);
1870 fwd_info->buf_2 = NULL;
1871 }
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301872 for (i = 0; i <= (fwd_info->num_pd - 2); i++) {
1873 if (fwd_info->buf_upd[i][0]) {
1874 kfree(fwd_info->buf_upd[i][0]->data);
1875 fwd_info->buf_upd[i][0]->data = NULL;
1876 kfree(fwd_info->buf_upd[i][0]->data_raw);
1877 fwd_info->buf_upd[i][0]->data_raw = NULL;
1878 kfree(fwd_info->buf_upd[i][0]);
1879 fwd_info->buf_upd[i][0] = NULL;
1880 }
1881 if (fwd_info->buf_upd[i][1]) {
1882 kfree(fwd_info->buf_upd[i][1]->data);
1883 fwd_info->buf_upd[i][1]->data = NULL;
1884 kfree(fwd_info->buf_upd[i][1]->data_raw);
1885 fwd_info->buf_upd[i][1]->data_raw = NULL;
1886 kfree(fwd_info->buf_upd[i][1]);
1887 fwd_info->buf_upd[i][1] = NULL;
1888 }
1889 }
Sreelakshmi Gownipalliae6c8e82016-11-29 16:01:13 -08001890 mutex_unlock(&fwd_info->buf_mutex);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001891}
1892
1893void diagfwd_write_buffers_init(struct diagfwd_info *fwd_info)
1894{
1895 unsigned long flags;
1896 int i;
1897
1898 if (!fwd_info)
1899 return;
1900
1901 if (!fwd_info->inited) {
1902 pr_err("diag: In %s, channel not inited, p: %d, t: %d\n",
1903 __func__, fwd_info->peripheral, fwd_info->type);
1904 return;
1905 }
1906
1907 spin_lock_irqsave(&fwd_info->write_buf_lock, flags);
1908 for (i = 0; i < NUM_WRITE_BUFFERS; i++) {
1909 if (!fwd_info->buf_ptr[i])
1910 fwd_info->buf_ptr[i] =
1911 kzalloc(sizeof(struct diagfwd_buf_t),
1912 GFP_ATOMIC);
1913 if (!fwd_info->buf_ptr[i])
1914 goto err;
1915 kmemleak_not_leak(fwd_info->buf_ptr[i]);
1916 if (!fwd_info->buf_ptr[i]->data) {
1917 fwd_info->buf_ptr[i]->data = kzalloc(PERIPHERAL_BUF_SZ,
1918 GFP_ATOMIC);
1919 if (!fwd_info->buf_ptr[i]->data)
1920 goto err;
1921 fwd_info->buf_ptr[i]->len = PERIPHERAL_BUF_SZ;
1922 kmemleak_not_leak(fwd_info->buf_ptr[i]->data);
1923 }
1924 }
1925 spin_unlock_irqrestore(&fwd_info->write_buf_lock, flags);
1926 return;
1927
1928err:
1929 spin_unlock_irqrestore(&fwd_info->write_buf_lock, flags);
1930 pr_err("diag:unable to allocate write buffers\n");
1931 diagfwd_write_buffers_exit(fwd_info);
1932
1933}
1934
1935static void diagfwd_write_buffers_exit(struct diagfwd_info *fwd_info)
1936{
1937 unsigned long flags;
1938 int i;
1939
1940 if (!fwd_info)
1941 return;
1942
1943 spin_lock_irqsave(&fwd_info->write_buf_lock, flags);
1944 for (i = 0; i < NUM_WRITE_BUFFERS; i++) {
1945 if (fwd_info->buf_ptr[i]) {
1946 kfree(fwd_info->buf_ptr[i]->data);
1947 fwd_info->buf_ptr[i]->data = NULL;
1948 kfree(fwd_info->buf_ptr[i]);
1949 fwd_info->buf_ptr[i] = NULL;
1950 }
1951 }
1952 spin_unlock_irqrestore(&fwd_info->write_buf_lock, flags);
1953}