blob: dcc88e4a1a9429a3ffa1e5e26ba2a7ae11b1512a [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 Arya53bf3452017-09-06 15:34:19 +0530208 if (driver->logging_mode == DIAG_MEMORY_DEVICE_MODE) {
209 ch = &diag_md[DIAG_LOCAL_PROC];
210 for (i = 0; ch != NULL &&
211 i < ch->num_tbl_entries; i++) {
212 if (ch->tbl[i].buf == buf->data) {
213 ctx = ch->tbl[i].ctx;
214 ch->tbl[i].buf = NULL;
215 ch->tbl[i].len = 0;
216 ch->tbl[i].ctx = 0;
217 DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
218 "Flushed mdlog table entries before reallocating data buffer, p:%d, t:%d\n",
219 GET_BUF_PERIPHERAL(ctx),
220 GET_BUF_TYPE(ctx));
221 break;
222 }
223 }
224 }
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700225 temp_buf = krealloc(buf->data, max_size +
226 APF_DIAG_PADDING,
227 GFP_KERNEL);
228 if (!temp_buf)
229 return -ENOMEM;
Hardik Arya53bf3452017-09-06 15:34:19 +0530230 DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
231 "Reallocated data buffer: %pK with size: %d\n",
232 temp_buf, max_size);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700233 buf->data = temp_buf;
234 buf->len = max_size;
235 }
236 }
237
238 return buf->len;
239}
240
Manoj Prabhu B571cf422017-08-08 19:01:41 +0530241int diag_md_get_peripheral(int ctxt)
242{
243 int pd = 0, i = 0;
244 int type = 0, peripheral = -EINVAL;
245 struct diagfwd_info *fwd_info = NULL;
246
247 peripheral = GET_BUF_PERIPHERAL(ctxt);
Chris Lewc937d692017-10-12 13:13:18 +0530248
249 /* Check for peripheral value within bounds
250 * of peripherals and UPD combined.
251 */
252 if (peripheral < 0 || peripheral > NUM_MD_SESSIONS)
Manoj Prabhu B571cf422017-08-08 19:01:41 +0530253 return -EINVAL;
254
255 if (peripheral == APPS_DATA)
256 return peripheral;
257
Chris Lewc937d692017-10-12 13:13:18 +0530258 /* With peripheral value bound checked
259 * return user pd value.
260 */
261 if (peripheral > NUM_PERIPHERALS)
262 return peripheral;
263
Manoj Prabhu B571cf422017-08-08 19:01:41 +0530264 type = GET_BUF_TYPE(ctxt);
265 if (type < 0 || type >= NUM_TYPES)
266 return -EINVAL;
267
268 fwd_info = &peripheral_info[type][peripheral];
269 if (!fwd_info)
270 return -EINVAL;
271
272 pd = GET_PD_CTXT(ctxt);
273
274 if (driver->num_pd_session) {
275 if (pd == fwd_info->diagid_root) {
276 if (peripheral > NUM_PERIPHERALS)
277 peripheral = -EINVAL;
278 } else {
279 for (i = 0; i <= (fwd_info->num_pd - 2); i++) {
280 if (pd == fwd_info->diagid_user[i]) {
281 switch (peripheral) {
282 case PERIPHERAL_MODEM:
283 if (driver->pd_logging_mode[0])
284 peripheral = UPD_WLAN;
285 break;
286 default:
287 peripheral = -EINVAL;
288 break;
289 }
290 }
291 }
292 }
293 }
294 return peripheral;
295}
296
297static void diagfwd_data_process_done(struct diagfwd_info *fwd_info,
298 struct diagfwd_buf_t *buf, int len)
299{
300 int err = 0;
301 int write_len = 0, peripheral = 0;
302 unsigned char *write_buf = NULL;
303 struct diag_md_session_t *session_info = NULL;
304 uint8_t hdlc_disabled = 0;
305
306 if (!fwd_info || !buf || len <= 0) {
307 diag_ws_release();
308 return;
309 }
310
311 switch (fwd_info->type) {
312 case TYPE_DATA:
313 case TYPE_CMD:
314 break;
315 default:
316 pr_err_ratelimited("diag: In %s, invalid type %d for peripheral %d\n",
317 __func__, fwd_info->type,
318 fwd_info->peripheral);
319 diag_ws_release();
320 return;
321 }
322
323 mutex_lock(&driver->hdlc_disable_mutex);
324 mutex_lock(&fwd_info->data_mutex);
325
326 peripheral =
327 diag_md_get_peripheral(buf->ctxt);
328 if (peripheral < 0) {
329 pr_err("diag:%s:%d invalid peripheral = %d\n",
330 __func__, __LINE__, peripheral);
331 mutex_unlock(&fwd_info->data_mutex);
332 mutex_unlock(&driver->hdlc_disable_mutex);
333 diag_ws_release();
334 return;
335 }
336
337 session_info =
338 diag_md_session_get_peripheral(peripheral);
339 if (session_info)
340 hdlc_disabled = session_info->hdlc_disabled;
341 else
342 hdlc_disabled = driver->hdlc_disabled;
343
344 if (hdlc_disabled) {
345 /* The data is raw and and on APPS side HDLC is disabled */
346 if (!buf) {
347 pr_err("diag: In %s, no match for non encode buffer %pK, peripheral %d, type: %d\n",
348 __func__, buf, fwd_info->peripheral,
349 fwd_info->type);
350 goto end;
351 }
352 if (len > PERIPHERAL_BUF_SZ) {
353 pr_err("diag: In %s, Incoming buffer too large %d, peripheral %d, type: %d\n",
354 __func__, len, fwd_info->peripheral,
355 fwd_info->type);
356 goto end;
357 }
358 write_len = len;
359 if (write_len <= 0)
360 goto end;
361 write_buf = buf->data_raw;
362 } else {
363 if (!buf) {
364 pr_err("diag: In %s, no match for non encode buffer %pK, peripheral %d, type: %d\n",
365 __func__, buf, fwd_info->peripheral,
366 fwd_info->type);
367 goto end;
368 }
369
370 write_len = check_bufsize_for_encoding(buf, len);
371 if (write_len <= 0) {
372 pr_err("diag: error in checking buf for encoding\n");
373 goto end;
374 }
375 write_buf = buf->data;
376 err = diag_add_hdlc_encoding(write_buf, &write_len,
377 buf->data_raw, len);
378 if (err) {
379 pr_err("diag: error in adding hdlc encoding\n");
380 goto end;
381 }
382 }
383
384 if (write_len > 0) {
385 err = diag_mux_write(DIAG_LOCAL_PROC, write_buf, write_len,
386 buf->ctxt);
387 if (err) {
388 pr_err_ratelimited("diag: In %s, unable to write to mux error: %d\n",
389 __func__, err);
390 goto end;
391 }
392 }
393 mutex_unlock(&fwd_info->data_mutex);
394 mutex_unlock(&driver->hdlc_disable_mutex);
395 diagfwd_queue_read(fwd_info);
396 return;
397
398end:
399 diag_ws_release();
400 mutex_unlock(&fwd_info->data_mutex);
401 mutex_unlock(&driver->hdlc_disable_mutex);
402 if (buf) {
Hardik Arya53bf3452017-09-06 15:34:19 +0530403 DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
404 "Marking buffer as free p: %d, t: %d, buf_num: %d\n",
405 fwd_info->peripheral, fwd_info->type,
406 GET_BUF_NUM(buf->ctxt));
Manoj Prabhu B571cf422017-08-08 19:01:41 +0530407 diagfwd_write_done(fwd_info->peripheral, fwd_info->type,
408 GET_BUF_NUM(buf->ctxt));
409 }
410 diagfwd_queue_read(fwd_info);
411}
412
413static void diagfwd_data_read_untag_done(struct diagfwd_info *fwd_info,
414 unsigned char *buf, int len)
415{
416 int i = 0;
417 int len_cpd = 0;
418 int ctxt_cpd = 0;
419 int len_upd[MAX_PERIPHERAL_UPD] = {0};
420 int ctxt_upd[MAX_PERIPHERAL_UPD] = {0};
421 int packet_len = 0, processed = 0;
422 unsigned char *temp_buf_main = NULL;
423 unsigned char *temp_buf_cpd = NULL;
424 unsigned char *temp_buf_upd[MAX_PERIPHERAL_UPD] = {NULL};
425 struct diagfwd_buf_t *temp_fwdinfo_cpd = NULL;
426 struct diagfwd_buf_t *temp_fwdinfo_upd = NULL;
427 int flag_buf_1 = 0, flag_buf_2 = 0;
428 uint8_t peripheral;
429
430 if (!fwd_info || !buf || len <= 0) {
431 diag_ws_release();
432 return;
433 }
434
435 switch (fwd_info->type) {
436 case TYPE_DATA:
437 case TYPE_CMD:
438 break;
439 default:
440 pr_err_ratelimited("diag: In %s, invalid type %d for peripheral %d\n",
441 __func__, fwd_info->type,
442 fwd_info->peripheral);
443 diag_ws_release();
444 return;
445 }
446 peripheral = fwd_info->peripheral;
447 if (peripheral >= NUM_PERIPHERALS)
448 return;
449
450 if (driver->feature[peripheral].encode_hdlc &&
451 driver->feature[peripheral].untag_header &&
452 driver->peripheral_untag[peripheral]) {
453 temp_buf_cpd = buf;
454 temp_buf_main = buf;
455 if (fwd_info->buf_1 &&
456 fwd_info->buf_1->data_raw == buf) {
457 flag_buf_1 = 1;
458 temp_fwdinfo_cpd = fwd_info->buf_1;
459 if (fwd_info->type == TYPE_DATA) {
460 for (i = 0; i <= (fwd_info->num_pd - 2); i++)
461 temp_buf_upd[i] =
462 fwd_info->buf_upd[i][0]->data_raw;
463 }
464 } else if (fwd_info->buf_2 &&
465 fwd_info->buf_2->data_raw == buf) {
466 flag_buf_2 = 1;
467 temp_fwdinfo_cpd = fwd_info->buf_2;
468 if (fwd_info->type == TYPE_DATA) {
469 for (i = 0; i <= (fwd_info->num_pd - 2); i++)
470 temp_buf_upd[i] =
471 fwd_info->buf_upd[i][1]->data_raw;
472 }
473 } else {
474 pr_err("diag: In %s, no match for buffer %pK, peripheral %d, type: %d\n",
475 __func__, buf, peripheral,
476 fwd_info->type);
477 goto end;
478 }
479
480 while (processed < len) {
481 pr_debug("diag_fr:untagged packet buf contents: %02x %02x %02x %02x\n",
482 *temp_buf_main, *(temp_buf_main+1),
483 *(temp_buf_main+2), *(temp_buf_main+3));
484 packet_len =
485 *(uint16_t *) (temp_buf_main + 2);
486 if (packet_len > PERIPHERAL_BUF_SZ)
487 goto end;
488 if ((*temp_buf_main) == fwd_info->diagid_root) {
489 ctxt_cpd = fwd_info->diagid_root;
490 len_cpd += packet_len;
491 if (temp_buf_cpd) {
492 memcpy(temp_buf_cpd,
493 (temp_buf_main + 4), packet_len);
494 temp_buf_cpd += packet_len;
495 }
496 } else {
497 for (i = 0; i <= (fwd_info->num_pd - 2); i++)
498 if ((*temp_buf_main) ==
499 fwd_info->diagid_user[i])
500 break;
501 ctxt_upd[i] = fwd_info->diagid_user[i];
502 if (temp_buf_upd[i]) {
503 memcpy(temp_buf_upd[i],
504 (temp_buf_main + 4), packet_len);
505 temp_buf_upd[i] += packet_len;
506 }
507 len_upd[i] += packet_len;
508 }
509 len = len - 4;
510 temp_buf_main += (packet_len + 4);
511 processed += packet_len;
512 }
Hardik Arya53bf3452017-09-06 15:34:19 +0530513
514 if (flag_buf_1) {
515 fwd_info->cpd_len_1 = len_cpd;
516 for (i = 0; i <= (fwd_info->num_pd - 2); i++)
517 if (fwd_info->type == TYPE_DATA)
518 fwd_info->upd_len[i][0] = len_upd[i];
519 } else if (flag_buf_2) {
520 fwd_info->cpd_len_2 = len_cpd;
521 for (i = 0; i <= (fwd_info->num_pd - 2); i++)
522 if (fwd_info->type == TYPE_DATA)
523 fwd_info->upd_len[i][1] = len_upd[i];
524 }
525
Manoj Prabhu B571cf422017-08-08 19:01:41 +0530526 for (i = 0; i <= (fwd_info->num_pd - 2); i++) {
527 if (fwd_info->type == TYPE_DATA && len_upd[i]) {
Hardik Arya53bf3452017-09-06 15:34:19 +0530528 if (flag_buf_1)
Manoj Prabhu B571cf422017-08-08 19:01:41 +0530529 temp_fwdinfo_upd =
530 fwd_info->buf_upd[i][0];
Hardik Arya53bf3452017-09-06 15:34:19 +0530531 else
Manoj Prabhu B571cf422017-08-08 19:01:41 +0530532 temp_fwdinfo_upd =
533 fwd_info->buf_upd[i][1];
Manoj Prabhu B571cf422017-08-08 19:01:41 +0530534 temp_fwdinfo_upd->ctxt &= 0x00FFFFFF;
535 temp_fwdinfo_upd->ctxt |=
536 (SET_PD_CTXT(ctxt_upd[i]));
537 atomic_set(&temp_fwdinfo_upd->in_busy, 1);
538 diagfwd_data_process_done(fwd_info,
539 temp_fwdinfo_upd, len_upd[i]);
540 } else {
541 if (flag_buf_1)
542 fwd_info->upd_len[i][0] = 0;
543 if (flag_buf_2)
544 fwd_info->upd_len[i][1] = 0;
545 }
546 }
Manoj Prabhu B37c77c02017-09-18 11:38:48 +0530547
Manoj Prabhu B571cf422017-08-08 19:01:41 +0530548 if (len_cpd) {
Manoj Prabhu B571cf422017-08-08 19:01:41 +0530549 temp_fwdinfo_cpd->ctxt &= 0x00FFFFFF;
Hardik Arya53bf3452017-09-06 15:34:19 +0530550 temp_fwdinfo_cpd->ctxt |= (SET_PD_CTXT(ctxt_cpd));
Manoj Prabhu B571cf422017-08-08 19:01:41 +0530551 diagfwd_data_process_done(fwd_info,
552 temp_fwdinfo_cpd, len_cpd);
553 } else {
554 if (flag_buf_1)
555 fwd_info->cpd_len_1 = 0;
556 if (flag_buf_2)
557 fwd_info->cpd_len_2 = 0;
558 }
559 } else {
560 diagfwd_data_read_done(fwd_info, buf, len);
561 }
562 return;
563end:
564 diag_ws_release();
565 if (temp_fwdinfo_cpd) {
Hardik Arya53bf3452017-09-06 15:34:19 +0530566 DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
567 "Marking buffer as free p: %d, t: %d, buf_num: %d\n",
568 fwd_info->peripheral, fwd_info->type,
569 GET_BUF_NUM(temp_fwdinfo_cpd->ctxt));
Manoj Prabhu B571cf422017-08-08 19:01:41 +0530570 diagfwd_write_done(fwd_info->peripheral, fwd_info->type,
571 GET_BUF_NUM(temp_fwdinfo_cpd->ctxt));
572 }
573 diagfwd_queue_read(fwd_info);
574}
575
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700576static void diagfwd_data_read_done(struct diagfwd_info *fwd_info,
577 unsigned char *buf, int len)
578{
579 int err = 0;
580 int write_len = 0;
581 unsigned char *write_buf = NULL;
582 struct diagfwd_buf_t *temp_buf = NULL;
583 struct diag_md_session_t *session_info = NULL;
584 uint8_t hdlc_disabled = 0;
585
586 if (!fwd_info || !buf || len <= 0) {
587 diag_ws_release();
588 return;
589 }
590
591 switch (fwd_info->type) {
592 case TYPE_DATA:
593 case TYPE_CMD:
594 break;
595 default:
596 pr_err_ratelimited("diag: In %s, invalid type %d for peripheral %d\n",
597 __func__, fwd_info->type,
598 fwd_info->peripheral);
599 diag_ws_release();
600 return;
601 }
602
603 mutex_lock(&driver->hdlc_disable_mutex);
604 mutex_lock(&fwd_info->data_mutex);
605 session_info = diag_md_session_get_peripheral(fwd_info->peripheral);
606 if (session_info)
607 hdlc_disabled = session_info->hdlc_disabled;
608 else
609 hdlc_disabled = driver->hdlc_disabled;
610
611 if (!driver->feature[fwd_info->peripheral].encode_hdlc) {
612 if (fwd_info->buf_1 && fwd_info->buf_1->data == buf) {
613 temp_buf = fwd_info->buf_1;
614 write_buf = fwd_info->buf_1->data;
615 } else if (fwd_info->buf_2 && fwd_info->buf_2->data == buf) {
616 temp_buf = fwd_info->buf_2;
617 write_buf = fwd_info->buf_2->data;
618 } else {
619 pr_err("diag: In %s, no match for buffer %pK, peripheral %d, type: %d\n",
620 __func__, buf, fwd_info->peripheral,
621 fwd_info->type);
622 goto end;
623 }
624 write_len = len;
625 } else if (hdlc_disabled) {
626 /* The data is raw and and on APPS side HDLC is disabled */
627 if (fwd_info->buf_1 && fwd_info->buf_1->data_raw == buf) {
628 temp_buf = fwd_info->buf_1;
629 } else if (fwd_info->buf_2 &&
630 fwd_info->buf_2->data_raw == buf) {
631 temp_buf = fwd_info->buf_2;
632 } else {
633 pr_err("diag: In %s, no match for non encode buffer %pK, peripheral %d, type: %d\n",
634 __func__, buf, fwd_info->peripheral,
635 fwd_info->type);
636 goto end;
637 }
638 if (len > PERIPHERAL_BUF_SZ) {
639 pr_err("diag: In %s, Incoming buffer too large %d, peripheral %d, type: %d\n",
640 __func__, len, fwd_info->peripheral,
641 fwd_info->type);
642 goto end;
643 }
644 write_len = len;
645 write_buf = buf;
646 } else {
647 if (fwd_info->buf_1 && fwd_info->buf_1->data_raw == buf) {
648 temp_buf = fwd_info->buf_1;
649 } else if (fwd_info->buf_2 &&
650 fwd_info->buf_2->data_raw == buf) {
651 temp_buf = fwd_info->buf_2;
652 } else {
653 pr_err("diag: In %s, no match for non encode buffer %pK, peripheral %d, type: %d\n",
654 __func__, buf, fwd_info->peripheral,
655 fwd_info->type);
656 goto end;
657 }
658 write_len = check_bufsize_for_encoding(temp_buf, len);
659 if (write_len <= 0) {
660 pr_err("diag: error in checking buf for encoding\n");
661 goto end;
662 }
663 write_buf = temp_buf->data;
664 err = diag_add_hdlc_encoding(write_buf, &write_len, buf, len);
665 if (err) {
666 pr_err("diag: error in adding hdlc encoding\n");
667 goto end;
668 }
669 }
670
671 if (write_len > 0) {
672 err = diag_mux_write(DIAG_LOCAL_PROC, write_buf, write_len,
673 temp_buf->ctxt);
674 if (err) {
675 pr_err_ratelimited("diag: In %s, unable to write to mux error: %d\n",
676 __func__, err);
677 goto end;
678 }
679 }
680 mutex_unlock(&fwd_info->data_mutex);
681 mutex_unlock(&driver->hdlc_disable_mutex);
682 diagfwd_queue_read(fwd_info);
683 return;
684
685end:
686 diag_ws_release();
687 mutex_unlock(&fwd_info->data_mutex);
688 mutex_unlock(&driver->hdlc_disable_mutex);
689 if (temp_buf) {
Hardik Arya53bf3452017-09-06 15:34:19 +0530690 DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
691 "Marking buffer as free p: %d, t: %d, buf_num: %d\n",
692 fwd_info->peripheral, fwd_info->type,
693 GET_BUF_NUM(temp_buf->ctxt));
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700694 diagfwd_write_done(fwd_info->peripheral, fwd_info->type,
695 GET_BUF_NUM(temp_buf->ctxt));
696 }
697 diagfwd_queue_read(fwd_info);
698}
699
700static void diagfwd_cntl_read_done(struct diagfwd_info *fwd_info,
701 unsigned char *buf, int len)
702{
703 if (!fwd_info) {
704 diag_ws_release();
705 return;
706 }
707
708 if (fwd_info->type != TYPE_CNTL) {
709 pr_err("diag: In %s, invalid type %d for peripheral %d\n",
710 __func__, fwd_info->type, fwd_info->peripheral);
711 diag_ws_release();
712 return;
713 }
714
715 diag_ws_on_read(DIAG_WS_MUX, len);
716 diag_cntl_process_read_data(fwd_info, buf, len);
717 /*
718 * Control packets are not consumed by the clients. Mimic
719 * consumption by setting and clearing the wakeup source copy_count
720 * explicitly.
721 */
722 diag_ws_on_copy_fail(DIAG_WS_MUX);
723 /* Reset the buffer in_busy value after processing the data */
724 if (fwd_info->buf_1)
725 atomic_set(&fwd_info->buf_1->in_busy, 0);
726
727 diagfwd_queue_read(fwd_info);
728 diagfwd_queue_read(&peripheral_info[TYPE_DATA][fwd_info->peripheral]);
729 diagfwd_queue_read(&peripheral_info[TYPE_CMD][fwd_info->peripheral]);
730}
731
732static void diagfwd_dci_read_done(struct diagfwd_info *fwd_info,
733 unsigned char *buf, int len)
734{
735 if (!fwd_info)
736 return;
737
738 switch (fwd_info->type) {
739 case TYPE_DCI:
740 case TYPE_DCI_CMD:
741 break;
742 default:
743 pr_err("diag: In %s, invalid type %d for peripheral %d\n",
744 __func__, fwd_info->type, fwd_info->peripheral);
745 return;
746 }
747
748 diag_dci_process_peripheral_data(fwd_info, (void *)buf, len);
749 /* Reset the buffer in_busy value after processing the data */
750 if (fwd_info->buf_1)
751 atomic_set(&fwd_info->buf_1->in_busy, 0);
752
753 diagfwd_queue_read(fwd_info);
754}
755
756static void diagfwd_reset_buffers(struct diagfwd_info *fwd_info,
757 unsigned char *buf)
758{
759 if (!fwd_info || !buf)
760 return;
761
762 if (!driver->feature[fwd_info->peripheral].encode_hdlc) {
763 if (fwd_info->buf_1 && fwd_info->buf_1->data == buf)
764 atomic_set(&fwd_info->buf_1->in_busy, 0);
765 else if (fwd_info->buf_2 && fwd_info->buf_2->data == buf)
766 atomic_set(&fwd_info->buf_2->in_busy, 0);
767 } else {
768 if (fwd_info->buf_1 && fwd_info->buf_1->data_raw == buf)
769 atomic_set(&fwd_info->buf_1->in_busy, 0);
770 else if (fwd_info->buf_2 && fwd_info->buf_2->data_raw == buf)
771 atomic_set(&fwd_info->buf_2->in_busy, 0);
772 }
Hardik Arya53bf3452017-09-06 15:34:19 +0530773 if (fwd_info->buf_1 && !atomic_read(&(fwd_info->buf_1->in_busy))) {
774 DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
775 "Buffer 1 for core PD is marked free, p: %d, t: %d\n",
776 fwd_info->peripheral, fwd_info->type);
777 }
778 if (fwd_info->buf_2 && !atomic_read(&(fwd_info->buf_2->in_busy))) {
779 DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
780 "Buffer 2 for core PD is marked free, p: %d, t: %d\n",
781 fwd_info->peripheral, fwd_info->type);
782 }
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700783}
784
785int diagfwd_peripheral_init(void)
786{
787 uint8_t peripheral;
788 uint8_t transport;
789 uint8_t type;
Manoj Prabhu B571cf422017-08-08 19:01:41 +0530790 int i = 0;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700791 struct diagfwd_info *fwd_info = NULL;
792
793 for (transport = 0; transport < NUM_TRANSPORT; transport++) {
794 early_init_info[transport] = kzalloc(
795 sizeof(struct diagfwd_info) * NUM_PERIPHERALS,
796 GFP_KERNEL);
797 if (!early_init_info[transport])
798 return -ENOMEM;
799 kmemleak_not_leak(early_init_info[transport]);
800 }
801
802 for (peripheral = 0; peripheral < NUM_PERIPHERALS; peripheral++) {
803 for (transport = 0; transport < NUM_TRANSPORT; transport++) {
804 fwd_info = &early_init_info[transport][peripheral];
805 fwd_info->peripheral = peripheral;
806 fwd_info->type = TYPE_CNTL;
807 fwd_info->transport = transport;
808 fwd_info->ctxt = NULL;
809 fwd_info->p_ops = NULL;
810 fwd_info->ch_open = 0;
811 fwd_info->inited = 1;
812 fwd_info->read_bytes = 0;
813 fwd_info->write_bytes = 0;
Manoj Prabhu B571cf422017-08-08 19:01:41 +0530814 fwd_info->cpd_len_1 = 0;
815 fwd_info->cpd_len_2 = 0;
816 fwd_info->num_pd = 0;
Sreelakshmi Gownipalliae6c8e82016-11-29 16:01:13 -0800817 mutex_init(&fwd_info->buf_mutex);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700818 mutex_init(&fwd_info->data_mutex);
Sreelakshmi Gownipalliae6c8e82016-11-29 16:01:13 -0800819 spin_lock_init(&fwd_info->write_buf_lock);
Manoj Prabhu B571cf422017-08-08 19:01:41 +0530820
821 for (i = 0; i < MAX_PERIPHERAL_UPD; i++) {
822 fwd_info->diagid_user[i] = 0;
823 fwd_info->upd_len[i][0] = 0;
824 fwd_info->upd_len[i][1] = 0;
825 fwd_info->buf_upd[i][0] = NULL;
826 fwd_info->buf_upd[i][1] = NULL;
827 }
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700828 }
829 }
830
831 for (peripheral = 0; peripheral < NUM_PERIPHERALS; peripheral++) {
832 for (type = 0; type < NUM_TYPES; type++) {
833 fwd_info = &peripheral_info[type][peripheral];
834 fwd_info->peripheral = peripheral;
835 fwd_info->type = type;
836 fwd_info->ctxt = NULL;
837 fwd_info->p_ops = NULL;
838 fwd_info->ch_open = 0;
839 fwd_info->read_bytes = 0;
840 fwd_info->write_bytes = 0;
Manoj Prabhu B571cf422017-08-08 19:01:41 +0530841 fwd_info->num_pd = 0;
842 fwd_info->cpd_len_1 = 0;
843 fwd_info->cpd_len_2 = 0;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700844 spin_lock_init(&fwd_info->write_buf_lock);
Sreelakshmi Gownipalliae6c8e82016-11-29 16:01:13 -0800845 mutex_init(&fwd_info->buf_mutex);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700846 mutex_init(&fwd_info->data_mutex);
Manoj Prabhu B571cf422017-08-08 19:01:41 +0530847
848 for (i = 0; i < MAX_PERIPHERAL_UPD; i++) {
849 fwd_info->diagid_user[i] = 0;
850 fwd_info->upd_len[i][0] = 0;
851 fwd_info->upd_len[i][1] = 0;
852 fwd_info->buf_upd[i][0] = NULL;
853 fwd_info->buf_upd[i][1] = NULL;
854 }
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700855 /*
856 * This state shouldn't be set for Control channels
857 * during initialization. This is set when the feature
858 * mask is received for the first time.
859 */
860 if (type != TYPE_CNTL)
861 fwd_info->inited = 1;
862 }
863 driver->diagfwd_data[peripheral] =
864 &peripheral_info[TYPE_DATA][peripheral];
865 driver->diagfwd_cntl[peripheral] =
866 &peripheral_info[TYPE_CNTL][peripheral];
867 driver->diagfwd_dci[peripheral] =
868 &peripheral_info[TYPE_DCI][peripheral];
869 driver->diagfwd_cmd[peripheral] =
870 &peripheral_info[TYPE_CMD][peripheral];
871 driver->diagfwd_dci_cmd[peripheral] =
872 &peripheral_info[TYPE_DCI_CMD][peripheral];
873 }
874
875 if (driver->supports_sockets)
876 diag_socket_init();
877 diag_glink_init();
878
879 return 0;
880}
881
882void diagfwd_peripheral_exit(void)
883{
884 uint8_t peripheral;
885 uint8_t type;
886 struct diagfwd_info *fwd_info = NULL;
Sreelakshmi Gownipalli323a9212017-09-18 12:41:47 -0700887 int transport = 0;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700888
889 diag_socket_exit();
890
891 for (peripheral = 0; peripheral < NUM_PERIPHERALS; peripheral++) {
892 for (type = 0; type < NUM_TYPES; type++) {
893 fwd_info = &peripheral_info[type][peripheral];
894 fwd_info->ctxt = NULL;
895 fwd_info->p_ops = NULL;
896 fwd_info->ch_open = 0;
897 diagfwd_buffers_exit(fwd_info);
898 }
899 }
900
901 for (peripheral = 0; peripheral < NUM_PERIPHERALS; peripheral++) {
902 driver->diagfwd_data[peripheral] = NULL;
903 driver->diagfwd_cntl[peripheral] = NULL;
904 driver->diagfwd_dci[peripheral] = NULL;
905 driver->diagfwd_cmd[peripheral] = NULL;
906 driver->diagfwd_dci_cmd[peripheral] = NULL;
907 }
908
Sreelakshmi Gownipalli323a9212017-09-18 12:41:47 -0700909 for (transport = 0; transport < NUM_TRANSPORT; transport++) {
910 kfree(early_init_info[transport]);
911 early_init_info[transport] = NULL;
912 }
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700913}
914
915int diagfwd_cntl_register(uint8_t transport, uint8_t peripheral, void *ctxt,
916 struct diag_peripheral_ops *ops,
917 struct diagfwd_info **fwd_ctxt)
918{
919 struct diagfwd_info *fwd_info = NULL;
920
921 if (!ctxt || !ops)
922 return -EIO;
923
924 if (transport >= NUM_TRANSPORT || peripheral >= NUM_PERIPHERALS)
925 return -EINVAL;
926
927 fwd_info = &early_init_info[transport][peripheral];
928 *fwd_ctxt = &early_init_info[transport][peripheral];
929 fwd_info->ctxt = ctxt;
930 fwd_info->p_ops = ops;
931 fwd_info->c_ops = &cntl_ch_ops;
932
933 return 0;
934}
935
936int diagfwd_register(uint8_t transport, uint8_t peripheral, uint8_t type,
937 void *ctxt, struct diag_peripheral_ops *ops,
938 struct diagfwd_info **fwd_ctxt)
939{
940 struct diagfwd_info *fwd_info = NULL;
941
942 if (peripheral >= NUM_PERIPHERALS || type >= NUM_TYPES ||
943 !ctxt || !ops || transport >= NUM_TRANSPORT) {
944 pr_err("diag: In %s, returning error\n", __func__);
945 return -EIO;
946 }
947
948 fwd_info = &peripheral_info[type][peripheral];
949 *fwd_ctxt = &peripheral_info[type][peripheral];
950 fwd_info->ctxt = ctxt;
951 fwd_info->p_ops = ops;
952 fwd_info->transport = transport;
953 fwd_info->ch_open = 0;
954
955 switch (type) {
956 case TYPE_DATA:
957 case TYPE_CMD:
958 fwd_info->c_ops = &data_ch_ops;
959 break;
960 case TYPE_DCI:
961 case TYPE_DCI_CMD:
962 fwd_info->c_ops = &dci_ch_ops;
963 break;
964 default:
965 pr_err("diag: In %s, invalid type: %d\n", __func__, type);
966 return -EINVAL;
967 }
968
969 if (atomic_read(&fwd_info->opened) &&
970 fwd_info->p_ops && fwd_info->p_ops->open) {
971 /*
972 * The registration can happen late, like in the case of
973 * sockets. fwd_info->opened reflects diag_state. Propagate the
974 * state to the peipherals.
975 */
976 fwd_info->p_ops->open(fwd_info->ctxt);
977 }
978
979 return 0;
980}
981
982void diagfwd_deregister(uint8_t peripheral, uint8_t type, void *ctxt)
983{
984 struct diagfwd_info *fwd_info = NULL;
985
986 if (peripheral >= NUM_PERIPHERALS || type >= NUM_TYPES || !ctxt)
987 return;
988
989 fwd_info = &peripheral_info[type][peripheral];
990 if (fwd_info->ctxt != ctxt) {
991 pr_err("diag: In %s, unable to find a match for p: %d t: %d\n",
992 __func__, peripheral, type);
993 return;
994 }
995 fwd_info->ctxt = NULL;
996 fwd_info->p_ops = NULL;
997 fwd_info->ch_open = 0;
998 diagfwd_buffers_exit(fwd_info);
999
1000 switch (type) {
1001 case TYPE_DATA:
1002 driver->diagfwd_data[peripheral] = NULL;
1003 break;
1004 case TYPE_CNTL:
1005 driver->diagfwd_cntl[peripheral] = NULL;
1006 break;
1007 case TYPE_DCI:
1008 driver->diagfwd_dci[peripheral] = NULL;
1009 break;
1010 case TYPE_CMD:
1011 driver->diagfwd_cmd[peripheral] = NULL;
1012 break;
1013 case TYPE_DCI_CMD:
1014 driver->diagfwd_dci_cmd[peripheral] = NULL;
1015 break;
1016 }
1017}
1018
1019void diagfwd_close_transport(uint8_t transport, uint8_t peripheral)
1020{
1021 struct diagfwd_info *fwd_info = NULL;
1022 struct diagfwd_info *dest_info = NULL;
1023 int (*init_fn)(uint8_t) = NULL;
1024 void (*invalidate_fn)(void *, struct diagfwd_info *) = NULL;
1025 int (*check_channel_state)(void *) = NULL;
1026 uint8_t transport_open = 0;
1027 int i = 0;
1028
1029 if (peripheral >= NUM_PERIPHERALS)
1030 return;
1031
1032 switch (transport) {
1033 case TRANSPORT_GLINK:
1034 transport_open = TRANSPORT_SOCKET;
1035 init_fn = diag_socket_init_peripheral;
1036 invalidate_fn = diag_socket_invalidate;
1037 check_channel_state = diag_socket_check_state;
1038 break;
1039 case TRANSPORT_SOCKET:
1040 transport_open = TRANSPORT_GLINK;
1041 init_fn = diag_glink_init_peripheral;
1042 invalidate_fn = diag_glink_invalidate;
1043 check_channel_state = diag_glink_check_state;
1044 break;
1045 default:
1046 return;
1047
1048 }
1049
Manoj Prabhu B98325462017-01-10 20:19:28 +05301050 mutex_lock(&driver->diagfwd_channel_mutex[peripheral]);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001051 fwd_info = &early_init_info[transport][peripheral];
1052 if (fwd_info->p_ops && fwd_info->p_ops->close)
1053 fwd_info->p_ops->close(fwd_info->ctxt);
1054 fwd_info = &early_init_info[transport_open][peripheral];
1055 dest_info = &peripheral_info[TYPE_CNTL][peripheral];
1056 dest_info->inited = 1;
1057 dest_info->ctxt = fwd_info->ctxt;
1058 dest_info->p_ops = fwd_info->p_ops;
1059 dest_info->c_ops = fwd_info->c_ops;
1060 dest_info->ch_open = fwd_info->ch_open;
1061 dest_info->read_bytes = fwd_info->read_bytes;
1062 dest_info->write_bytes = fwd_info->write_bytes;
1063 dest_info->inited = fwd_info->inited;
1064 dest_info->buf_1 = fwd_info->buf_1;
1065 dest_info->buf_2 = fwd_info->buf_2;
1066 dest_info->transport = fwd_info->transport;
1067 invalidate_fn(dest_info->ctxt, dest_info);
1068 for (i = 0; i < NUM_WRITE_BUFFERS; i++)
1069 dest_info->buf_ptr[i] = fwd_info->buf_ptr[i];
1070 if (!check_channel_state(dest_info->ctxt))
1071 diagfwd_late_open(dest_info);
Manoj Prabhu B0e535532017-08-24 09:56:03 +05301072 diagfwd_cntl_open(dest_info);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001073 init_fn(peripheral);
Manoj Prabhu B98325462017-01-10 20:19:28 +05301074 mutex_unlock(&driver->diagfwd_channel_mutex[peripheral]);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001075 diagfwd_queue_read(&peripheral_info[TYPE_DATA][peripheral]);
1076 diagfwd_queue_read(&peripheral_info[TYPE_CMD][peripheral]);
1077}
1078
1079void *diagfwd_request_write_buf(struct diagfwd_info *fwd_info)
1080{
1081 void *buf = NULL;
1082 int index;
1083 unsigned long flags;
1084
1085 spin_lock_irqsave(&fwd_info->write_buf_lock, flags);
1086 for (index = 0 ; index < NUM_WRITE_BUFFERS; index++) {
1087 if (!atomic_read(&(fwd_info->buf_ptr[index]->in_busy))) {
1088 atomic_set(&(fwd_info->buf_ptr[index]->in_busy), 1);
1089 buf = fwd_info->buf_ptr[index]->data;
1090 if (!buf)
1091 return NULL;
1092 break;
1093 }
1094 }
1095 spin_unlock_irqrestore(&fwd_info->write_buf_lock, flags);
1096 return buf;
1097}
1098
1099int diagfwd_write(uint8_t peripheral, uint8_t type, void *buf, int len)
1100{
1101 struct diagfwd_info *fwd_info = NULL;
1102 int err = 0;
1103 uint8_t retry_count = 0;
1104 uint8_t max_retries = 3;
1105 void *buf_ptr = NULL;
1106
1107 if (peripheral >= NUM_PERIPHERALS || type >= NUM_TYPES)
1108 return -EINVAL;
1109
1110 if (type == TYPE_CMD || type == TYPE_DCI_CMD) {
1111 if (!driver->feature[peripheral].rcvd_feature_mask ||
1112 !driver->feature[peripheral].sent_feature_mask) {
1113 pr_debug_ratelimited("diag: In %s, feature mask for peripheral: %d not received or sent yet\n",
1114 __func__, peripheral);
1115 return 0;
1116 }
1117 if (!driver->feature[peripheral].separate_cmd_rsp)
1118 type = (type == TYPE_CMD) ? TYPE_DATA : TYPE_DCI;
1119 }
1120
1121 fwd_info = &peripheral_info[type][peripheral];
1122 if (!fwd_info->inited || !atomic_read(&fwd_info->opened))
1123 return -ENODEV;
1124
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301125 if (type == TYPE_CMD) {
Manoj Prabhu Bd7962422017-09-14 14:14:08 +05301126 if (driver->feature[peripheral].diag_id_support)
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301127 if (!fwd_info->diagid_root ||
1128 (!driver->diag_id_sent[peripheral])) {
1129 DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
1130 "diag: diag_id is not assigned yet\n");
1131 return 0;
1132 }
1133 }
1134
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001135 if (!(fwd_info->p_ops && fwd_info->p_ops->write && fwd_info->ctxt))
1136 return -EIO;
1137
1138 if (fwd_info->transport == TRANSPORT_GLINK) {
1139 buf_ptr = diagfwd_request_write_buf(fwd_info);
1140 if (buf_ptr)
1141 memcpy(buf_ptr, buf, len);
1142 else {
1143 DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
1144 "diag: buffer not found for writing\n");
1145 return -EIO;
1146 }
1147 } else
1148 buf_ptr = buf;
1149
1150 while (retry_count < max_retries) {
1151 err = 0;
1152 err = fwd_info->p_ops->write(fwd_info->ctxt, buf_ptr, len);
1153 if (err && err != -ENODEV) {
1154 usleep_range(100000, 101000);
1155 retry_count++;
1156 continue;
1157 }
1158 break;
1159 }
1160
1161 if (!err)
1162 fwd_info->write_bytes += len;
1163 else
1164 if (fwd_info->transport == TRANSPORT_GLINK)
1165 diagfwd_write_buffer_done(fwd_info, buf_ptr);
1166 return err;
1167}
1168
1169static void __diag_fwd_open(struct diagfwd_info *fwd_info)
1170{
1171 if (!fwd_info)
1172 return;
1173
1174 atomic_set(&fwd_info->opened, 1);
1175 if (!fwd_info->inited)
1176 return;
1177
Manoj Prabhu B1550bdd02017-04-14 12:50:24 +05301178 /*
1179 * Logging mode here is reflecting previous mode
1180 * status and will be updated to new mode later.
1181 *
1182 * Keeping the buffers busy for Memory Device Mode.
1183 */
1184
1185 if ((driver->logging_mode != DIAG_USB_MODE) ||
1186 driver->usb_connected) {
Hardik Arya53bf3452017-09-06 15:34:19 +05301187 if (fwd_info->buf_1) {
Manoj Prabhu B1550bdd02017-04-14 12:50:24 +05301188 atomic_set(&fwd_info->buf_1->in_busy, 0);
Hardik Arya53bf3452017-09-06 15:34:19 +05301189 DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
1190 "Buffer 1 for core PD is marked free, p: %d, t: %d\n",
1191 fwd_info->peripheral, fwd_info->type);
1192 }
1193 if (fwd_info->buf_2) {
Manoj Prabhu B1550bdd02017-04-14 12:50:24 +05301194 atomic_set(&fwd_info->buf_2->in_busy, 0);
Hardik Arya53bf3452017-09-06 15:34:19 +05301195 DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
1196 "Buffer 2 for core PD is marked free, p: %d, t: %d\n",
1197 fwd_info->peripheral, fwd_info->type);
1198 }
Manoj Prabhu B1550bdd02017-04-14 12:50:24 +05301199 }
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001200
1201 if (fwd_info->p_ops && fwd_info->p_ops->open)
1202 fwd_info->p_ops->open(fwd_info->ctxt);
1203
1204 diagfwd_queue_read(fwd_info);
1205}
1206
1207void diagfwd_early_open(uint8_t peripheral)
1208{
1209 uint8_t transport = 0;
1210 struct diagfwd_info *fwd_info = NULL;
1211
1212 if (peripheral >= NUM_PERIPHERALS)
1213 return;
1214
1215 for (transport = 0; transport < NUM_TRANSPORT; transport++) {
1216 fwd_info = &early_init_info[transport][peripheral];
1217 __diag_fwd_open(fwd_info);
1218 }
1219}
1220
1221void diagfwd_open(uint8_t peripheral, uint8_t type)
1222{
1223 struct diagfwd_info *fwd_info = NULL;
1224
1225 if (peripheral >= NUM_PERIPHERALS || type >= NUM_TYPES)
1226 return;
1227
1228 fwd_info = &peripheral_info[type][peripheral];
1229 __diag_fwd_open(fwd_info);
1230}
1231
1232void diagfwd_late_open(struct diagfwd_info *fwd_info)
1233{
1234 __diag_fwd_open(fwd_info);
1235}
1236
1237void diagfwd_close(uint8_t peripheral, uint8_t type)
1238{
1239 struct diagfwd_info *fwd_info = NULL;
1240
1241 if (peripheral >= NUM_PERIPHERALS || type >= NUM_TYPES)
1242 return;
1243
1244 fwd_info = &peripheral_info[type][peripheral];
1245 atomic_set(&fwd_info->opened, 0);
1246 if (!fwd_info->inited)
1247 return;
1248
1249 if (fwd_info->p_ops && fwd_info->p_ops->close)
1250 fwd_info->p_ops->close(fwd_info->ctxt);
1251
1252 if (fwd_info->buf_1)
1253 atomic_set(&fwd_info->buf_1->in_busy, 1);
1254 /*
1255 * Only Data channels have two buffers. Set both the buffers
1256 * to busy on close.
1257 */
1258 if (fwd_info->buf_2)
1259 atomic_set(&fwd_info->buf_2->in_busy, 1);
1260}
1261
1262int diagfwd_channel_open(struct diagfwd_info *fwd_info)
1263{
1264 int i;
1265
1266 if (!fwd_info)
1267 return -EIO;
1268
1269 if (!fwd_info->inited) {
1270 pr_debug("diag: In %s, channel is not inited, p: %d, t: %d\n",
1271 __func__, fwd_info->peripheral, fwd_info->type);
1272 return -EINVAL;
1273 }
1274
1275 if (fwd_info->ch_open) {
1276 pr_debug("diag: In %s, channel is already open, p: %d, t: %d\n",
1277 __func__, fwd_info->peripheral, fwd_info->type);
1278 return 0;
1279 }
Manoj Prabhu Bb989d562017-06-28 11:36:20 +05301280 mutex_lock(&driver->diagfwd_channel_mutex[fwd_info->peripheral]);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001281 fwd_info->ch_open = 1;
1282 diagfwd_buffers_init(fwd_info);
Manoj Prabhu B8ee172f2017-07-14 14:34:26 +05301283
1284 /*
Manoj Prabhu B0e535532017-08-24 09:56:03 +05301285 * Initialize buffers for glink supported
1286 * peripherals only.
Manoj Prabhu B8ee172f2017-07-14 14:34:26 +05301287 */
Manoj Prabhu B0e535532017-08-24 09:56:03 +05301288 if (fwd_info->transport == TRANSPORT_GLINK)
Manoj Prabhu B8ee172f2017-07-14 14:34:26 +05301289 diagfwd_write_buffers_init(fwd_info);
Manoj Prabhu B8ee172f2017-07-14 14:34:26 +05301290
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001291 if (fwd_info && fwd_info->c_ops && fwd_info->c_ops->open)
1292 fwd_info->c_ops->open(fwd_info);
1293 for (i = 0; i < NUM_WRITE_BUFFERS; i++) {
1294 if (fwd_info->buf_ptr[i])
1295 atomic_set(&fwd_info->buf_ptr[i]->in_busy, 0);
1296 }
1297 diagfwd_queue_read(fwd_info);
1298 DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "p: %d t: %d considered opened\n",
1299 fwd_info->peripheral, fwd_info->type);
1300
1301 if (atomic_read(&fwd_info->opened)) {
1302 if (fwd_info->p_ops && fwd_info->p_ops->open)
1303 fwd_info->p_ops->open(fwd_info->ctxt);
1304 }
Manoj Prabhu Bb989d562017-06-28 11:36:20 +05301305 mutex_unlock(&driver->diagfwd_channel_mutex[fwd_info->peripheral]);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001306 return 0;
1307}
1308
1309int diagfwd_channel_close(struct diagfwd_info *fwd_info)
1310{
1311 int i;
1312
1313 if (!fwd_info)
1314 return -EIO;
1315
Mohit Aggarwalaea1a722017-07-24 14:03:56 +05301316 if (fwd_info->type == TYPE_CNTL)
1317 flush_workqueue(driver->cntl_wq);
1318
Manoj Prabhu Bb989d562017-06-28 11:36:20 +05301319 mutex_lock(&driver->diagfwd_channel_mutex[fwd_info->peripheral]);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001320 fwd_info->ch_open = 0;
1321 if (fwd_info && fwd_info->c_ops && fwd_info->c_ops->close)
1322 fwd_info->c_ops->close(fwd_info);
1323
Hardik Arya53bf3452017-09-06 15:34:19 +05301324 if (fwd_info->buf_1 && fwd_info->buf_1->data) {
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001325 atomic_set(&fwd_info->buf_1->in_busy, 0);
Hardik Arya53bf3452017-09-06 15:34:19 +05301326 DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
1327 "Buffer 1 for core PD is marked free, p: %d, t: %d\n",
1328 fwd_info->peripheral, fwd_info->type);
1329 }
1330 if (fwd_info->buf_2 && fwd_info->buf_2->data) {
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001331 atomic_set(&fwd_info->buf_2->in_busy, 0);
Hardik Arya53bf3452017-09-06 15:34:19 +05301332 DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
1333 "Buffer 2 for core PD is marked free, p: %d, t: %d\n",
1334 fwd_info->peripheral, fwd_info->type);
1335 }
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001336
1337 for (i = 0; i < NUM_WRITE_BUFFERS; i++) {
1338 if (fwd_info->buf_ptr[i])
1339 atomic_set(&fwd_info->buf_ptr[i]->in_busy, 1);
1340 }
1341 DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "p: %d t: %d considered closed\n",
1342 fwd_info->peripheral, fwd_info->type);
Manoj Prabhu Bb989d562017-06-28 11:36:20 +05301343 mutex_unlock(&driver->diagfwd_channel_mutex[fwd_info->peripheral]);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001344 return 0;
1345}
1346
1347int diagfwd_channel_read_done(struct diagfwd_info *fwd_info,
1348 unsigned char *buf, uint32_t len)
1349{
1350 if (!fwd_info) {
1351 diag_ws_release();
1352 return -EIO;
1353 }
1354
1355 /*
1356 * Diag peripheral layers should send len as 0 if there is any error
1357 * in reading data from the transport. Use this information to reset the
1358 * in_busy flags. No need to queue read in this case.
1359 */
1360 if (len == 0) {
Hardik Arya53bf3452017-09-06 15:34:19 +05301361 DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
1362 "Read Length is 0, resetting the diag buffers p: %d, t: %d\n",
1363 fwd_info->peripheral, fwd_info->type);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001364 diagfwd_reset_buffers(fwd_info, buf);
1365 diag_ws_release();
1366 return 0;
1367 }
1368
1369 if (fwd_info && fwd_info->c_ops && fwd_info->c_ops->read_done)
1370 fwd_info->c_ops->read_done(fwd_info, buf, len);
1371 fwd_info->read_bytes += len;
1372
1373 return 0;
1374}
1375
Hardik Arya53bf3452017-09-06 15:34:19 +05301376void diagfwd_write_done(uint8_t peripheral, uint8_t type, int buf_num)
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001377{
Manoj Prabhu B37c77c02017-09-18 11:38:48 +05301378 int i = 0, upd_valid_len = 0;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001379 struct diagfwd_info *fwd_info = NULL;
1380
1381 if (peripheral >= NUM_PERIPHERALS || type >= NUM_TYPES)
1382 return;
1383
1384 fwd_info = &peripheral_info[type][peripheral];
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301385 if (!fwd_info)
1386 return;
1387
Hardik Arya53bf3452017-09-06 15:34:19 +05301388 if (buf_num == 1 && fwd_info->buf_1) {
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301389 /* Buffer 1 for core PD is freed */
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301390 fwd_info->cpd_len_1 = 0;
Manoj Prabhu B37c77c02017-09-18 11:38:48 +05301391 for (i = 0; i <= (fwd_info->num_pd - 2); i++) {
1392 if (fwd_info->upd_len[i][0]) {
1393 upd_valid_len = 1;
1394 break;
1395 }
1396 }
Hardik Arya53bf3452017-09-06 15:34:19 +05301397 if (!upd_valid_len) {
Manoj Prabhu B37c77c02017-09-18 11:38:48 +05301398 atomic_set(&fwd_info->buf_1->in_busy, 0);
Hardik Arya53bf3452017-09-06 15:34:19 +05301399 DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
1400 "Buffer 1 for core PD is marked free, p: %d, t: %d, buf_num: %d\n",
1401 fwd_info->peripheral, fwd_info->type, buf_num);
1402 }
1403 } else if (buf_num == 2 && fwd_info->buf_2) {
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301404 /* Buffer 2 for core PD is freed */
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301405 fwd_info->cpd_len_2 = 0;
Manoj Prabhu B37c77c02017-09-18 11:38:48 +05301406 for (i = 0; i <= (fwd_info->num_pd - 2); i++) {
1407 if (fwd_info->upd_len[i][1]) {
1408 upd_valid_len = 1;
1409 break;
1410 }
1411 }
Hardik Arya53bf3452017-09-06 15:34:19 +05301412 if (!upd_valid_len) {
Manoj Prabhu B37c77c02017-09-18 11:38:48 +05301413 atomic_set(&fwd_info->buf_2->in_busy, 0);
Hardik Arya53bf3452017-09-06 15:34:19 +05301414 DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
1415 "Buffer 2 for core PD is marked free, p: %d, t: %d, buf_num: %d\n",
1416 fwd_info->peripheral, fwd_info->type, buf_num);
1417 }
1418 } else if (buf_num >= 3 && (buf_num % 2)) {
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301419 for (i = 0; i <= (fwd_info->num_pd - 2); i++) {
1420 if (fwd_info->buf_upd[i][0]) {
1421 /* Buffer 1 for ith user PD is freed */
1422 atomic_set(&fwd_info->buf_upd[i][0]->in_busy, 0);
1423 fwd_info->upd_len[i][0] = 0;
1424 }
Hardik Arya53bf3452017-09-06 15:34:19 +05301425 if (!fwd_info->cpd_len_1) {
1426 atomic_set(&fwd_info->buf_1->in_busy, 0);
1427 DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
1428 "Buffer 1 for core PD is marked free, p: %d, t: %d, buf_num: %d\n",
1429 fwd_info->peripheral, fwd_info->type, buf_num);
1430 }
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301431 }
Hardik Arya53bf3452017-09-06 15:34:19 +05301432 } else if (buf_num >= 4 && !(buf_num % 2)) {
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301433 for (i = 0; i <= (fwd_info->num_pd - 2); i++) {
1434 if (fwd_info->buf_upd[i][1]) {
1435 /* Buffer 2 for ith user PD is freed */
Hardik Arya53bf3452017-09-06 15:34:19 +05301436 atomic_set(&fwd_info->buf_upd[i][1]->in_busy, 0);
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301437 fwd_info->upd_len[i][1] = 0;
1438 }
Hardik Arya53bf3452017-09-06 15:34:19 +05301439 if (!fwd_info->cpd_len_2) {
1440 atomic_set(&fwd_info->buf_2->in_busy, 0);
1441 DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
1442 "Buffer 2 for core PD is marked free, p: %d, t: %d, buf_num: %d\n",
1443 fwd_info->peripheral, fwd_info->type, buf_num);
1444 }
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301445 }
1446 } else
Hardik Arya53bf3452017-09-06 15:34:19 +05301447 pr_err("diag: In %s, invalid buf_num: %d\n", __func__, buf_num);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001448
1449 diagfwd_queue_read(fwd_info);
1450}
1451
1452int diagfwd_write_buffer_done(struct diagfwd_info *fwd_info, const void *ptr)
1453{
1454
1455 int found = 0;
1456 int index = 0;
1457 unsigned long flags;
1458
1459 if (!fwd_info || !ptr)
1460 return found;
1461 spin_lock_irqsave(&fwd_info->write_buf_lock, flags);
1462 for (index = 0; index < NUM_WRITE_BUFFERS; index++) {
1463 if (fwd_info->buf_ptr[index]->data == ptr) {
1464 atomic_set(&fwd_info->buf_ptr[index]->in_busy, 0);
1465 found = 1;
1466 break;
1467 }
1468 }
1469 spin_unlock_irqrestore(&fwd_info->write_buf_lock, flags);
1470 return found;
1471}
1472
1473void diagfwd_channel_read(struct diagfwd_info *fwd_info)
1474{
1475 int err = 0;
1476 uint32_t read_len = 0;
1477 unsigned char *read_buf = NULL;
1478 struct diagfwd_buf_t *temp_buf = NULL;
1479
1480 if (!fwd_info) {
1481 diag_ws_release();
1482 return;
1483 }
1484
1485 if (!fwd_info->inited || !atomic_read(&fwd_info->opened)) {
1486 pr_debug("diag: In %s, p: %d, t: %d, inited: %d, opened: %d ch_open: %d\n",
1487 __func__, fwd_info->peripheral, fwd_info->type,
1488 fwd_info->inited, atomic_read(&fwd_info->opened),
1489 fwd_info->ch_open);
1490 diag_ws_release();
1491 return;
1492 }
1493
1494 if (fwd_info->buf_1 && !atomic_read(&fwd_info->buf_1->in_busy)) {
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001495 if (driver->feature[fwd_info->peripheral].encode_hdlc &&
1496 (fwd_info->type == TYPE_DATA ||
1497 fwd_info->type == TYPE_CMD)) {
1498 read_buf = fwd_info->buf_1->data_raw;
1499 read_len = fwd_info->buf_1->len_raw;
1500 } else {
1501 read_buf = fwd_info->buf_1->data;
1502 read_len = fwd_info->buf_1->len;
1503 }
Mohit Aggarwal77f227d2016-11-24 13:48:12 +05301504 if (read_buf) {
1505 temp_buf = fwd_info->buf_1;
1506 atomic_set(&temp_buf->in_busy, 1);
1507 }
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001508 } else if (fwd_info->buf_2 && !atomic_read(&fwd_info->buf_2->in_busy)) {
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001509 if (driver->feature[fwd_info->peripheral].encode_hdlc &&
1510 (fwd_info->type == TYPE_DATA ||
1511 fwd_info->type == TYPE_CMD)) {
1512 read_buf = fwd_info->buf_2->data_raw;
1513 read_len = fwd_info->buf_2->len_raw;
1514 } else {
1515 read_buf = fwd_info->buf_2->data;
1516 read_len = fwd_info->buf_2->len;
1517 }
Mohit Aggarwal77f227d2016-11-24 13:48:12 +05301518 if (read_buf) {
1519 temp_buf = fwd_info->buf_2;
1520 atomic_set(&temp_buf->in_busy, 1);
1521 }
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001522 } else {
1523 pr_debug("diag: In %s, both buffers are empty for p: %d, t: %d\n",
1524 __func__, fwd_info->peripheral, fwd_info->type);
1525 }
1526
1527 if (!read_buf) {
1528 diag_ws_release();
1529 return;
1530 }
1531
1532 if (!(fwd_info->p_ops && fwd_info->p_ops->read && fwd_info->ctxt))
1533 goto fail_return;
1534
1535 DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "issued a read p: %d t: %d buf: %pK\n",
1536 fwd_info->peripheral, fwd_info->type, read_buf);
1537 err = fwd_info->p_ops->read(fwd_info->ctxt, read_buf, read_len);
1538 if (err)
1539 goto fail_return;
1540
1541 return;
1542
1543fail_return:
1544 diag_ws_release();
1545 atomic_set(&temp_buf->in_busy, 0);
1546}
1547
1548static void diagfwd_queue_read(struct diagfwd_info *fwd_info)
1549{
1550 if (!fwd_info)
1551 return;
1552
1553 if (!fwd_info->inited || !atomic_read(&fwd_info->opened)) {
1554 pr_debug("diag: In %s, p: %d, t: %d, inited: %d, opened: %d ch_open: %d\n",
1555 __func__, fwd_info->peripheral, fwd_info->type,
1556 fwd_info->inited, atomic_read(&fwd_info->opened),
1557 fwd_info->ch_open);
1558 return;
1559 }
1560
1561 /*
1562 * Don't queue a read on the data and command channels before receiving
1563 * the feature mask from the peripheral. We won't know which buffer to
1564 * use - HDLC or non HDLC buffer for reading.
1565 */
1566 if ((!driver->feature[fwd_info->peripheral].rcvd_feature_mask) &&
1567 (fwd_info->type != TYPE_CNTL)) {
1568 return;
1569 }
1570
1571 if (fwd_info->p_ops && fwd_info->p_ops->queue_read && fwd_info->ctxt)
1572 fwd_info->p_ops->queue_read(fwd_info->ctxt);
1573}
1574
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301575static int diagfwd_buffers_allocate(struct diagfwd_info *fwd_info)
1576{
1577 int i, j;
1578
1579 for (i = 0; ((fwd_info->num_pd > 1) &&
1580 (i <= (fwd_info->num_pd - 2))); i++) {
1581 for (j = 0; j < NUM_WRITE_BUFFERS; j++) {
1582 if (!fwd_info->buf_upd[i][j]) {
1583 fwd_info->buf_upd[i][j] =
1584 kzalloc(sizeof(struct diagfwd_buf_t),
1585 GFP_KERNEL);
1586 if (ZERO_OR_NULL_PTR(fwd_info->buf_upd[i][j]))
1587 return -ENOMEM;
1588 kmemleak_not_leak(fwd_info->buf_upd[i][j]);
1589 }
1590
1591 if (fwd_info->buf_upd[i][j] &&
1592 !fwd_info->buf_upd[i][j]->data) {
1593 fwd_info->buf_upd[i][j]->data =
1594 kzalloc(PERIPHERAL_BUF_SZ +
1595 APF_DIAG_PADDING,
1596 GFP_KERNEL);
1597 if (ZERO_OR_NULL_PTR(
1598 fwd_info->buf_upd[i][j]->data))
1599 return -ENOMEM;
1600 fwd_info->buf_upd[i][j]->len =
1601 PERIPHERAL_BUF_SZ;
1602 kmemleak_not_leak(
1603 fwd_info->buf_upd[i][j]->data);
1604 fwd_info->buf_upd[i][j]->ctxt =
1605 SET_BUF_CTXT(fwd_info->peripheral,
1606 fwd_info->type, ((2 * i) + (j + 3)));
1607 }
1608
1609 if (driver->supports_apps_hdlc_encoding) {
1610 if (fwd_info->buf_upd[i][j] &&
1611 !fwd_info->buf_upd[i][j]->data_raw) {
1612 fwd_info->buf_upd[i][j]->data_raw =
1613 kzalloc(PERIPHERAL_BUF_SZ +
1614 APF_DIAG_PADDING,
1615 GFP_KERNEL);
1616 if (ZERO_OR_NULL_PTR(
1617 fwd_info->buf_upd[i][j]->data_raw))
1618 return -ENOMEM;
1619 fwd_info->buf_upd[i][j]->len_raw =
1620 PERIPHERAL_BUF_SZ;
1621 kmemleak_not_leak(
1622 fwd_info->buf_upd[i][j]->data_raw);
1623 }
1624 }
1625 }
1626 }
1627 return 0;
1628}
1629
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001630void diagfwd_buffers_init(struct diagfwd_info *fwd_info)
1631{
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301632 int ret = 0;
1633 unsigned char *temp_char_buf;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001634
1635 if (!fwd_info)
1636 return;
1637
1638 if (!fwd_info->inited) {
1639 pr_err("diag: In %s, channel not inited, p: %d, t: %d\n",
1640 __func__, fwd_info->peripheral, fwd_info->type);
1641 return;
1642 }
1643
Sreelakshmi Gownipalliae6c8e82016-11-29 16:01:13 -08001644 mutex_lock(&fwd_info->buf_mutex);
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301645
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001646 if (!fwd_info->buf_1) {
1647 fwd_info->buf_1 = kzalloc(sizeof(struct diagfwd_buf_t),
Sreelakshmi Gownipalliae6c8e82016-11-29 16:01:13 -08001648 GFP_KERNEL);
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301649 if (ZERO_OR_NULL_PTR(fwd_info->buf_1))
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001650 goto err;
1651 kmemleak_not_leak(fwd_info->buf_1);
1652 }
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301653
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001654 if (!fwd_info->buf_1->data) {
1655 fwd_info->buf_1->data = kzalloc(PERIPHERAL_BUF_SZ +
1656 APF_DIAG_PADDING,
Sreelakshmi Gownipalliae6c8e82016-11-29 16:01:13 -08001657 GFP_KERNEL);
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301658 if (ZERO_OR_NULL_PTR(fwd_info->buf_1->data))
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001659 goto err;
1660 fwd_info->buf_1->len = PERIPHERAL_BUF_SZ;
1661 kmemleak_not_leak(fwd_info->buf_1->data);
1662 fwd_info->buf_1->ctxt = SET_BUF_CTXT(fwd_info->peripheral,
1663 fwd_info->type, 1);
1664 }
1665
1666 if (fwd_info->type == TYPE_DATA) {
1667 if (!fwd_info->buf_2) {
1668 fwd_info->buf_2 = kzalloc(sizeof(struct diagfwd_buf_t),
Sreelakshmi Gownipalliae6c8e82016-11-29 16:01:13 -08001669 GFP_KERNEL);
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301670 if (ZERO_OR_NULL_PTR(fwd_info->buf_2))
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001671 goto err;
1672 kmemleak_not_leak(fwd_info->buf_2);
1673 }
1674
1675 if (!fwd_info->buf_2->data) {
1676 fwd_info->buf_2->data = kzalloc(PERIPHERAL_BUF_SZ +
1677 APF_DIAG_PADDING,
Sreelakshmi Gownipalliae6c8e82016-11-29 16:01:13 -08001678 GFP_KERNEL);
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301679 if (ZERO_OR_NULL_PTR(fwd_info->buf_2->data))
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001680 goto err;
1681 fwd_info->buf_2->len = PERIPHERAL_BUF_SZ;
1682 kmemleak_not_leak(fwd_info->buf_2->data);
1683 fwd_info->buf_2->ctxt = SET_BUF_CTXT(
1684 fwd_info->peripheral,
1685 fwd_info->type, 2);
1686 }
1687
Manoj Prabhu B0e535532017-08-24 09:56:03 +05301688 if (driver->feature[fwd_info->peripheral].untag_header) {
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301689 ret = diagfwd_buffers_allocate(fwd_info);
1690 if (ret)
1691 goto err;
Manoj Prabhu B0e535532017-08-24 09:56:03 +05301692 }
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301693
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001694 if (driver->supports_apps_hdlc_encoding) {
1695 /* In support of hdlc encoding */
1696 if (!fwd_info->buf_1->data_raw) {
1697 fwd_info->buf_1->data_raw =
1698 kzalloc(PERIPHERAL_BUF_SZ +
1699 APF_DIAG_PADDING,
Sreelakshmi Gownipalliae6c8e82016-11-29 16:01:13 -08001700 GFP_KERNEL);
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301701 temp_char_buf =
1702 fwd_info->buf_1->data_raw;
1703 if (ZERO_OR_NULL_PTR(temp_char_buf))
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001704 goto err;
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301705 fwd_info->buf_1->len_raw =
1706 PERIPHERAL_BUF_SZ;
1707 kmemleak_not_leak(temp_char_buf);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001708 }
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301709
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001710 if (!fwd_info->buf_2->data_raw) {
1711 fwd_info->buf_2->data_raw =
1712 kzalloc(PERIPHERAL_BUF_SZ +
1713 APF_DIAG_PADDING,
Sreelakshmi Gownipalliae6c8e82016-11-29 16:01:13 -08001714 GFP_KERNEL);
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301715 temp_char_buf =
1716 fwd_info->buf_2->data_raw;
1717 if (ZERO_OR_NULL_PTR(temp_char_buf))
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001718 goto err;
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301719 fwd_info->buf_2->len_raw =
1720 PERIPHERAL_BUF_SZ;
1721 kmemleak_not_leak(temp_char_buf);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001722 }
1723 }
1724 }
1725
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301726 if (fwd_info->type == TYPE_CMD &&
1727 driver->supports_apps_hdlc_encoding) {
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001728 /* In support of hdlc encoding */
1729 if (!fwd_info->buf_1->data_raw) {
1730 fwd_info->buf_1->data_raw = kzalloc(PERIPHERAL_BUF_SZ +
1731 APF_DIAG_PADDING,
Sreelakshmi Gownipalliae6c8e82016-11-29 16:01:13 -08001732 GFP_KERNEL);
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301733 temp_char_buf =
1734 fwd_info->buf_1->data_raw;
1735 if (ZERO_OR_NULL_PTR(temp_char_buf))
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001736 goto err;
1737 fwd_info->buf_1->len_raw = PERIPHERAL_BUF_SZ;
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301738 kmemleak_not_leak(temp_char_buf);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001739 }
1740 }
1741
Sreelakshmi Gownipalliae6c8e82016-11-29 16:01:13 -08001742 mutex_unlock(&fwd_info->buf_mutex);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001743 return;
1744
1745err:
Sreelakshmi Gownipalliae6c8e82016-11-29 16:01:13 -08001746 mutex_unlock(&fwd_info->buf_mutex);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001747 diagfwd_buffers_exit(fwd_info);
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301748 return;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001749}
1750
1751static void diagfwd_buffers_exit(struct diagfwd_info *fwd_info)
1752{
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301753 int i = 0;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001754
1755 if (!fwd_info)
1756 return;
1757
Sreelakshmi Gownipalliae6c8e82016-11-29 16:01:13 -08001758 mutex_lock(&fwd_info->buf_mutex);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001759 if (fwd_info->buf_1) {
1760 kfree(fwd_info->buf_1->data);
1761 fwd_info->buf_1->data = NULL;
1762 kfree(fwd_info->buf_1->data_raw);
1763 fwd_info->buf_1->data_raw = NULL;
1764 kfree(fwd_info->buf_1);
1765 fwd_info->buf_1 = NULL;
1766 }
1767 if (fwd_info->buf_2) {
1768 kfree(fwd_info->buf_2->data);
1769 fwd_info->buf_2->data = NULL;
1770 kfree(fwd_info->buf_2->data_raw);
1771 fwd_info->buf_2->data_raw = NULL;
1772 kfree(fwd_info->buf_2);
1773 fwd_info->buf_2 = NULL;
1774 }
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301775 for (i = 0; i <= (fwd_info->num_pd - 2); i++) {
1776 if (fwd_info->buf_upd[i][0]) {
1777 kfree(fwd_info->buf_upd[i][0]->data);
1778 fwd_info->buf_upd[i][0]->data = NULL;
1779 kfree(fwd_info->buf_upd[i][0]->data_raw);
1780 fwd_info->buf_upd[i][0]->data_raw = NULL;
1781 kfree(fwd_info->buf_upd[i][0]);
1782 fwd_info->buf_upd[i][0] = NULL;
1783 }
1784 if (fwd_info->buf_upd[i][1]) {
1785 kfree(fwd_info->buf_upd[i][1]->data);
1786 fwd_info->buf_upd[i][1]->data = NULL;
1787 kfree(fwd_info->buf_upd[i][1]->data_raw);
1788 fwd_info->buf_upd[i][1]->data_raw = NULL;
1789 kfree(fwd_info->buf_upd[i][1]);
1790 fwd_info->buf_upd[i][1] = NULL;
1791 }
1792 }
Sreelakshmi Gownipalliae6c8e82016-11-29 16:01:13 -08001793 mutex_unlock(&fwd_info->buf_mutex);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001794}
1795
1796void diagfwd_write_buffers_init(struct diagfwd_info *fwd_info)
1797{
1798 unsigned long flags;
1799 int i;
1800
1801 if (!fwd_info)
1802 return;
1803
1804 if (!fwd_info->inited) {
1805 pr_err("diag: In %s, channel not inited, p: %d, t: %d\n",
1806 __func__, fwd_info->peripheral, fwd_info->type);
1807 return;
1808 }
1809
1810 spin_lock_irqsave(&fwd_info->write_buf_lock, flags);
1811 for (i = 0; i < NUM_WRITE_BUFFERS; i++) {
1812 if (!fwd_info->buf_ptr[i])
1813 fwd_info->buf_ptr[i] =
1814 kzalloc(sizeof(struct diagfwd_buf_t),
1815 GFP_ATOMIC);
1816 if (!fwd_info->buf_ptr[i])
1817 goto err;
1818 kmemleak_not_leak(fwd_info->buf_ptr[i]);
1819 if (!fwd_info->buf_ptr[i]->data) {
1820 fwd_info->buf_ptr[i]->data = kzalloc(PERIPHERAL_BUF_SZ,
1821 GFP_ATOMIC);
1822 if (!fwd_info->buf_ptr[i]->data)
1823 goto err;
1824 fwd_info->buf_ptr[i]->len = PERIPHERAL_BUF_SZ;
1825 kmemleak_not_leak(fwd_info->buf_ptr[i]->data);
1826 }
1827 }
1828 spin_unlock_irqrestore(&fwd_info->write_buf_lock, flags);
1829 return;
1830
1831err:
1832 spin_unlock_irqrestore(&fwd_info->write_buf_lock, flags);
1833 pr_err("diag:unable to allocate write buffers\n");
1834 diagfwd_write_buffers_exit(fwd_info);
1835
1836}
1837
1838static void diagfwd_write_buffers_exit(struct diagfwd_info *fwd_info)
1839{
1840 unsigned long flags;
1841 int i;
1842
1843 if (!fwd_info)
1844 return;
1845
1846 spin_lock_irqsave(&fwd_info->write_buf_lock, flags);
1847 for (i = 0; i < NUM_WRITE_BUFFERS; i++) {
1848 if (fwd_info->buf_ptr[i]) {
1849 kfree(fwd_info->buf_ptr[i]->data);
1850 fwd_info->buf_ptr[i]->data = NULL;
1851 kfree(fwd_info->buf_ptr[i]);
1852 fwd_info->buf_ptr[i] = NULL;
1853 }
1854 }
1855 spin_unlock_irqrestore(&fwd_info->write_buf_lock, flags);
1856}