blob: cc64f47f2ee7b9a2e54ef09db5f9626f2bf59cbe [file] [log] [blame]
Sreelakshmi Gownipalli8d477d32017-02-08 19:49:06 -08001/* Copyright (c) 2008-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/init.h>
14#include <linux/module.h>
15#include <linux/device.h>
16#include <linux/err.h>
17#include <linux/sched.h>
18#include <linux/ratelimit.h>
19#include <linux/workqueue.h>
20#include <linux/pm_runtime.h>
21#include <linux/diagchar.h>
22#include <linux/delay.h>
23#include <linux/reboot.h>
24#include <linux/of.h>
25#include <linux/kmemleak.h>
26#ifdef CONFIG_DIAG_OVER_USB
27#include <linux/usb/usbdiag.h>
28#endif
29#include <soc/qcom/socinfo.h>
30#include <soc/qcom/restart.h>
31#include "diagmem.h"
32#include "diagchar.h"
33#include "diagfwd.h"
34#include "diagfwd_peripheral.h"
35#include "diagfwd_cntl.h"
36#include "diagchar_hdlc.h"
37#include "diag_dci.h"
38#include "diag_masks.h"
39#include "diag_usb.h"
40#include "diag_mux.h"
Manoj Prabhu B571cf422017-08-08 19:01:41 +053041#include "diag_ipc_logging.h"
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -070042
43#define STM_CMD_VERSION_OFFSET 4
44#define STM_CMD_MASK_OFFSET 5
45#define STM_CMD_DATA_OFFSET 6
46#define STM_CMD_NUM_BYTES 7
47
48#define STM_RSP_SUPPORTED_INDEX 7
49#define STM_RSP_STATUS_INDEX 8
50#define STM_RSP_NUM_BYTES 9
51
52static int timestamp_switch;
53module_param(timestamp_switch, int, 0644);
54
55int wrap_enabled;
56uint16_t wrap_count;
57static struct diag_hdlc_decode_type *hdlc_decode;
58
59#define DIAG_NUM_COMMON_CMD 1
60static uint8_t common_cmds[DIAG_NUM_COMMON_CMD] = {
61 DIAG_CMD_LOG_ON_DMND
62};
63
64static uint8_t hdlc_timer_in_progress;
65
66/* Determine if this device uses a device tree */
67#ifdef CONFIG_OF
68static int has_device_tree(void)
69{
70 struct device_node *node;
71
72 node = of_find_node_by_path("/");
73 if (node) {
74 of_node_put(node);
75 return 1;
76 }
77 return 0;
78}
79#else
80static int has_device_tree(void)
81{
82 return 0;
83}
84#endif
85
86int chk_config_get_id(void)
87{
88 switch (socinfo_get_msm_cpu()) {
89 case MSM_CPU_8X60:
90 return APQ8060_TOOLS_ID;
91 case MSM_CPU_8960:
92 case MSM_CPU_8960AB:
93 return AO8960_TOOLS_ID;
94 case MSM_CPU_8064:
95 case MSM_CPU_8064AB:
96 case MSM_CPU_8064AA:
97 return APQ8064_TOOLS_ID;
98 case MSM_CPU_8930:
99 case MSM_CPU_8930AA:
100 case MSM_CPU_8930AB:
101 return MSM8930_TOOLS_ID;
102 case MSM_CPU_8974:
103 return MSM8974_TOOLS_ID;
104 case MSM_CPU_8625:
105 return MSM8625_TOOLS_ID;
106 case MSM_CPU_8084:
107 return APQ8084_TOOLS_ID;
108 case MSM_CPU_8916:
109 return MSM8916_TOOLS_ID;
110 case MSM_CPU_8939:
111 return MSM8939_TOOLS_ID;
112 case MSM_CPU_8994:
113 return MSM8994_TOOLS_ID;
114 case MSM_CPU_8226:
115 return APQ8026_TOOLS_ID;
116 case MSM_CPU_8909:
117 return MSM8909_TOOLS_ID;
118 case MSM_CPU_8992:
119 return MSM8992_TOOLS_ID;
120 case MSM_CPU_8996:
121 return MSM_8996_TOOLS_ID;
122 default:
123 if (driver->use_device_tree) {
124 if (machine_is_msm8974())
125 return MSM8974_TOOLS_ID;
126 else if (machine_is_apq8074())
127 return APQ8074_TOOLS_ID;
128 else
129 return 0;
130 } else {
131 return 0;
132 }
133 }
134}
135
136/*
137 * This will return TRUE for targets which support apps only mode and hence SSR.
138 * This applies to 8960 and newer targets.
139 */
140int chk_apps_only(void)
141{
142 if (driver->use_device_tree)
143 return 1;
144
145 switch (socinfo_get_msm_cpu()) {
146 case MSM_CPU_8960:
147 case MSM_CPU_8960AB:
148 case MSM_CPU_8064:
149 case MSM_CPU_8064AB:
150 case MSM_CPU_8064AA:
151 case MSM_CPU_8930:
152 case MSM_CPU_8930AA:
153 case MSM_CPU_8930AB:
154 case MSM_CPU_8627:
155 case MSM_CPU_9615:
156 case MSM_CPU_8974:
157 return 1;
158 default:
159 return 0;
160 }
161}
162
163/*
164 * This will return TRUE for targets which support apps as master.
165 * Thus, SW DLOAD and Mode Reset are supported on apps processor.
166 * This applies to 8960 and newer targets.
167 */
168int chk_apps_master(void)
169{
170 if (driver->use_device_tree)
171 return 1;
172 else
173 return 0;
174}
175
176int chk_polling_response(void)
177{
178 if (!(driver->polling_reg_flag) && chk_apps_master())
179 /*
180 * If the apps processor is master and no other processor
181 * has registered to respond for polling
182 */
183 return 1;
184 else if (!(driver->diagfwd_cntl[PERIPHERAL_MODEM] &&
185 driver->diagfwd_cntl[PERIPHERAL_MODEM]->ch_open) &&
186 (driver->feature[PERIPHERAL_MODEM].rcvd_feature_mask))
187 /*
188 * If the apps processor is not the master and the modem
189 * is not up or we did not receive the feature masks from Modem
190 */
191 return 1;
192 else
193 return 0;
194}
195
196/*
197 * This function should be called if you feel that the logging process may
198 * need to be woken up. For instance, if the logging mode is MEMORY_DEVICE MODE
199 * and while trying to read data from data channel there are no buffers
200 * available to read the data into, then this function should be called to
201 * determine if the logging process needs to be woken up.
202 */
203void chk_logging_wakeup(void)
204{
205 int i;
206 int j;
207 int pid = 0;
208
209 for (j = 0; j < NUM_MD_SESSIONS; j++) {
210 if (!driver->md_session_map[j])
211 continue;
212 pid = driver->md_session_map[j]->pid;
213
214 /* Find the index of the logging process */
215 for (i = 0; i < driver->num_clients; i++) {
216 if (driver->client_map[i].pid != pid)
217 continue;
218 if (driver->data_ready[i] & USER_SPACE_DATA_TYPE)
219 continue;
220 /*
221 * At very high logging rates a race condition can
222 * occur where the buffers containing the data from
223 * a channel are all in use, but the data_ready flag
224 * is cleared. In this case, the buffers never have
225 * their data read/logged. Detect and remedy this
226 * situation.
227 */
228 driver->data_ready[i] |= USER_SPACE_DATA_TYPE;
229 pr_debug("diag: Force wakeup of logging process\n");
230 wake_up_interruptible(&driver->wait_q);
231 break;
232 }
233 /*
234 * Diag Memory Device is in normal. Check only for the first
235 * index as all the indices point to the same session
236 * structure.
237 */
238 if ((driver->md_session_mask == DIAG_CON_ALL) && (j == 0))
239 break;
240 }
241}
242
Chris Lewc937d692017-10-12 13:13:18 +0530243static void pack_rsp_and_send(unsigned char *buf, int len,
244 struct diag_md_session_t *info)
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700245{
246 int err;
Chris Lewc937d692017-10-12 13:13:18 +0530247 int retry_count = 0, i, rsp_ctxt;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700248 uint32_t write_len = 0;
249 unsigned long flags;
250 unsigned char *rsp_ptr = driver->encoded_rsp_buf;
251 struct diag_pkt_frame_t header;
252
253 if (!rsp_ptr || !buf)
254 return;
255
256 if (len > DIAG_MAX_RSP_SIZE || len < 0) {
257 pr_err("diag: In %s, invalid len %d, permissible len %d\n",
258 __func__, len, DIAG_MAX_RSP_SIZE);
259 return;
260 }
261
262 /*
Chris Lewc937d692017-10-12 13:13:18 +0530263 * Explicitly check for the Peripheral Modem here
264 * is necessary till a way to identify a peripheral
265 * if its supporting qshrink4 feature.
266 */
267 if (info && info->peripheral_mask) {
268 if (info->peripheral_mask == DIAG_CON_ALL ||
269 (info->peripheral_mask & (1 << APPS_DATA)) ||
270 (info->peripheral_mask & (1 << PERIPHERAL_MODEM))) {
271 rsp_ctxt = SET_BUF_CTXT(APPS_DATA, TYPE_CMD, 1);
272 } else {
273 for (i = 0; i < NUM_MD_SESSIONS; i++) {
274 if (info->peripheral_mask & (1 << i))
275 break;
276 }
277 rsp_ctxt = SET_BUF_CTXT(i, TYPE_CMD, 1);
278 }
279 } else
280 rsp_ctxt = driver->rsp_buf_ctxt;
281
282 /*
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700283 * Keep trying till we get the buffer back. It should probably
284 * take one or two iterations. When this loops till UINT_MAX, it
285 * means we did not get a write complete for the previous
286 * response.
287 */
288 while (retry_count < UINT_MAX) {
289 if (!driver->rsp_buf_busy)
290 break;
291 /*
292 * Wait for sometime and try again. The value 10000 was chosen
293 * empirically as an optimum value for USB to complete a write
294 */
295 usleep_range(10000, 10100);
296 retry_count++;
297
298 /*
299 * There can be a race conditon that clears the data ready flag
300 * for responses. Make sure we don't miss previous wakeups for
301 * draining responses when we are in Memory Device Mode.
302 */
303 if (driver->logging_mode == DIAG_MEMORY_DEVICE_MODE ||
304 driver->logging_mode == DIAG_MULTI_MODE)
305 chk_logging_wakeup();
306 }
307 if (driver->rsp_buf_busy) {
308 pr_err("diag: unable to get hold of response buffer\n");
309 return;
310 }
311
312 driver->rsp_buf_busy = 1;
313 header.start = CONTROL_CHAR;
314 header.version = 1;
315 header.length = len;
316 memcpy(rsp_ptr, &header, sizeof(header));
317 write_len += sizeof(header);
318 memcpy(rsp_ptr + write_len, buf, len);
319 write_len += len;
320 *(uint8_t *)(rsp_ptr + write_len) = CONTROL_CHAR;
321 write_len += sizeof(uint8_t);
322
Chris Lewc937d692017-10-12 13:13:18 +0530323 err = diag_mux_write(DIAG_LOCAL_PROC, rsp_ptr, write_len, rsp_ctxt);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700324 if (err) {
325 pr_err("diag: In %s, unable to write to mux, err: %d\n",
326 __func__, err);
327 spin_lock_irqsave(&driver->rsp_buf_busy_lock, flags);
328 driver->rsp_buf_busy = 0;
329 spin_unlock_irqrestore(&driver->rsp_buf_busy_lock, flags);
330 }
331}
332
Chris Lewc937d692017-10-12 13:13:18 +0530333static void encode_rsp_and_send(unsigned char *buf, int len,
334 struct diag_md_session_t *info)
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700335{
336 struct diag_send_desc_type send = { NULL, NULL, DIAG_STATE_START, 0 };
337 struct diag_hdlc_dest_type enc = { NULL, NULL, 0 };
338 unsigned char *rsp_ptr = driver->encoded_rsp_buf;
Chris Lewc937d692017-10-12 13:13:18 +0530339 int err, i, rsp_ctxt, retry_count = 0;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700340 unsigned long flags;
341
342 if (!rsp_ptr || !buf)
343 return;
344
345 if (len > DIAG_MAX_RSP_SIZE || len < 0) {
346 pr_err("diag: In %s, invalid len %d, permissible len %d\n",
347 __func__, len, DIAG_MAX_RSP_SIZE);
348 return;
349 }
350
351 /*
Chris Lewc937d692017-10-12 13:13:18 +0530352 * Explicitly check for the Peripheral Modem here
353 * is necessary till a way to identify a peripheral
354 * if its supporting qshrink4 feature.
355 */
356 if (info && info->peripheral_mask) {
357 if (info->peripheral_mask == DIAG_CON_ALL ||
358 (info->peripheral_mask & (1 << APPS_DATA)) ||
359 (info->peripheral_mask & (1 << PERIPHERAL_MODEM))) {
360 rsp_ctxt = SET_BUF_CTXT(APPS_DATA, TYPE_CMD, 1);
361 } else {
362 for (i = 0; i < NUM_MD_SESSIONS; i++) {
363 if (info->peripheral_mask & (1 << i))
364 break;
365 }
366 rsp_ctxt = SET_BUF_CTXT(i, TYPE_CMD, 1);
367 }
368 } else
369 rsp_ctxt = driver->rsp_buf_ctxt;
370
371 /*
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700372 * Keep trying till we get the buffer back. It should probably
373 * take one or two iterations. When this loops till UINT_MAX, it
374 * means we did not get a write complete for the previous
375 * response.
376 */
377 while (retry_count < UINT_MAX) {
378 if (!driver->rsp_buf_busy)
379 break;
380 /*
381 * Wait for sometime and try again. The value 10000 was chosen
382 * empirically as an optimum value for USB to complete a write
383 */
384 usleep_range(10000, 10100);
385 retry_count++;
386
387 /*
388 * There can be a race conditon that clears the data ready flag
389 * for responses. Make sure we don't miss previous wakeups for
390 * draining responses when we are in Memory Device Mode.
391 */
392 if (driver->logging_mode == DIAG_MEMORY_DEVICE_MODE ||
393 driver->logging_mode == DIAG_MULTI_MODE)
394 chk_logging_wakeup();
395 }
396
397 if (driver->rsp_buf_busy) {
398 pr_err("diag: unable to get hold of response buffer\n");
399 return;
400 }
401
402 spin_lock_irqsave(&driver->rsp_buf_busy_lock, flags);
403 driver->rsp_buf_busy = 1;
404 spin_unlock_irqrestore(&driver->rsp_buf_busy_lock, flags);
405 send.state = DIAG_STATE_START;
406 send.pkt = buf;
407 send.last = (void *)(buf + len - 1);
408 send.terminate = 1;
409 enc.dest = rsp_ptr;
410 enc.dest_last = (void *)(rsp_ptr + DIAG_MAX_HDLC_BUF_SIZE - 1);
411 diag_hdlc_encode(&send, &enc);
412 driver->encoded_rsp_len = (int)(enc.dest - (void *)rsp_ptr);
413 err = diag_mux_write(DIAG_LOCAL_PROC, rsp_ptr, driver->encoded_rsp_len,
Chris Lewc937d692017-10-12 13:13:18 +0530414 rsp_ctxt);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700415 if (err) {
416 pr_err("diag: In %s, Unable to write to device, err: %d\n",
417 __func__, err);
418 spin_lock_irqsave(&driver->rsp_buf_busy_lock, flags);
419 driver->rsp_buf_busy = 0;
420 spin_unlock_irqrestore(&driver->rsp_buf_busy_lock, flags);
421 }
422 memset(buf, '\0', DIAG_MAX_RSP_SIZE);
423}
424
Chris Lewc937d692017-10-12 13:13:18 +0530425static void diag_send_rsp(unsigned char *buf, int len,
426 struct diag_md_session_t *info)
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700427{
428 struct diag_md_session_t *session_info = NULL;
429 uint8_t hdlc_disabled;
430
Chris Lewc937d692017-10-12 13:13:18 +0530431 session_info = (info) ? info :
432 diag_md_session_get_peripheral(APPS_DATA);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700433 if (session_info)
434 hdlc_disabled = session_info->hdlc_disabled;
435 else
436 hdlc_disabled = driver->hdlc_disabled;
437
438 if (hdlc_disabled)
Chris Lewc937d692017-10-12 13:13:18 +0530439 pack_rsp_and_send(buf, len, session_info);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700440 else
Chris Lewc937d692017-10-12 13:13:18 +0530441 encode_rsp_and_send(buf, len, session_info);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700442}
443
444void diag_update_pkt_buffer(unsigned char *buf, uint32_t len, int type)
445{
446 unsigned char *ptr = NULL;
447 unsigned char *temp = buf;
448 int *in_busy = NULL;
449 uint32_t *length = NULL;
450 uint32_t max_len = 0;
451
452 if (!buf || len == 0) {
453 pr_err("diag: In %s, Invalid ptr %pK and length %d\n",
454 __func__, buf, len);
455 return;
456 }
457
458 switch (type) {
459 case PKT_TYPE:
460 ptr = driver->apps_req_buf;
461 length = &driver->apps_req_buf_len;
462 max_len = DIAG_MAX_REQ_SIZE;
463 in_busy = &driver->in_busy_pktdata;
464 break;
465 case DCI_PKT_TYPE:
466 ptr = driver->dci_pkt_buf;
467 length = &driver->dci_pkt_length;
468 max_len = DCI_BUF_SIZE;
469 in_busy = &driver->in_busy_dcipktdata;
470 break;
471 default:
472 pr_err("diag: Invalid type %d in %s\n", type, __func__);
473 return;
474 }
475
476 mutex_lock(&driver->diagchar_mutex);
477 if (CHK_OVERFLOW(ptr, ptr, ptr + max_len, len)) {
478 memcpy(ptr, temp, len);
479 *length = len;
480 *in_busy = 1;
481 } else {
482 pr_alert("diag: In %s, no space for response packet, len: %d, type: %d\n",
483 __func__, len, type);
484 }
485 mutex_unlock(&driver->diagchar_mutex);
486}
487
488void diag_update_userspace_clients(unsigned int type)
489{
490 int i;
491
492 mutex_lock(&driver->diagchar_mutex);
493 for (i = 0; i < driver->num_clients; i++)
494 if (driver->client_map[i].pid != 0)
495 driver->data_ready[i] |= type;
496 wake_up_interruptible(&driver->wait_q);
497 mutex_unlock(&driver->diagchar_mutex);
498}
499
500void diag_update_md_clients(unsigned int type)
501{
502 int i, j;
503
504 mutex_lock(&driver->diagchar_mutex);
505 for (i = 0; i < NUM_MD_SESSIONS; i++) {
506 if (driver->md_session_map[i] != NULL)
507 for (j = 0; j < driver->num_clients; j++) {
508 if (driver->client_map[j].pid != 0 &&
509 driver->client_map[j].pid ==
510 driver->md_session_map[i]->pid) {
511 driver->data_ready[j] |= type;
512 break;
513 }
514 }
515 }
516 wake_up_interruptible(&driver->wait_q);
517 mutex_unlock(&driver->diagchar_mutex);
518}
519void diag_update_sleeping_process(int process_id, int data_type)
520{
521 int i;
522
523 mutex_lock(&driver->diagchar_mutex);
524 for (i = 0; i < driver->num_clients; i++)
525 if (driver->client_map[i].pid == process_id) {
526 driver->data_ready[i] |= data_type;
527 break;
528 }
529 wake_up_interruptible(&driver->wait_q);
530 mutex_unlock(&driver->diagchar_mutex);
531}
532
533static int diag_send_data(struct diag_cmd_reg_t *entry, unsigned char *buf,
534 int len)
535{
536 if (!entry)
537 return -EIO;
538
539 if (entry->proc == APPS_DATA) {
540 diag_update_pkt_buffer(buf, len, PKT_TYPE);
541 diag_update_sleeping_process(entry->pid, PKT_TYPE);
542 return 0;
543 }
544
545 return diagfwd_write(entry->proc, TYPE_CMD, buf, len);
546}
547
548void diag_process_stm_mask(uint8_t cmd, uint8_t data_mask, int data_type)
549{
550 int status = 0;
551
552 if (data_type >= PERIPHERAL_MODEM && data_type <= PERIPHERAL_SENSORS) {
553 if (driver->feature[data_type].stm_support) {
554 status = diag_send_stm_state(data_type, cmd);
555 if (status == 0)
556 driver->stm_state[data_type] = cmd;
557 }
558 driver->stm_state_requested[data_type] = cmd;
559 } else if (data_type == APPS_DATA) {
560 driver->stm_state[data_type] = cmd;
561 driver->stm_state_requested[data_type] = cmd;
562 }
563}
564
565int diag_process_stm_cmd(unsigned char *buf, unsigned char *dest_buf)
566{
567 uint8_t version, mask, cmd;
568 uint8_t rsp_supported = 0;
569 uint8_t rsp_status = 0;
570 int i;
571
572 if (!buf || !dest_buf) {
573 pr_err("diag: Invalid pointers buf: %pK, dest_buf %pK in %s\n",
574 buf, dest_buf, __func__);
575 return -EIO;
576 }
577
578 version = *(buf + STM_CMD_VERSION_OFFSET);
579 mask = *(buf + STM_CMD_MASK_OFFSET);
580 cmd = *(buf + STM_CMD_DATA_OFFSET);
581
582 /*
583 * Check if command is valid. If the command is asking for
584 * status, then the processor mask field is to be ignored.
585 */
586 if ((version != 2) || (cmd > STATUS_STM) ||
587 ((cmd != STATUS_STM) && ((mask == 0) || (0 != (mask >> 4))))) {
588 /* Command is invalid. Send bad param message response */
589 dest_buf[0] = BAD_PARAM_RESPONSE_MESSAGE;
590 for (i = 0; i < STM_CMD_NUM_BYTES; i++)
591 dest_buf[i+1] = *(buf + i);
592 return STM_CMD_NUM_BYTES+1;
593 } else if (cmd != STATUS_STM) {
594 if (mask & DIAG_STM_MODEM)
595 diag_process_stm_mask(cmd, DIAG_STM_MODEM,
596 PERIPHERAL_MODEM);
597
598 if (mask & DIAG_STM_LPASS)
599 diag_process_stm_mask(cmd, DIAG_STM_LPASS,
600 PERIPHERAL_LPASS);
601
602 if (mask & DIAG_STM_WCNSS)
603 diag_process_stm_mask(cmd, DIAG_STM_WCNSS,
604 PERIPHERAL_WCNSS);
605
606 if (mask & DIAG_STM_SENSORS)
607 diag_process_stm_mask(cmd, DIAG_STM_SENSORS,
608 PERIPHERAL_SENSORS);
609 if (mask & DIAG_STM_WDSP)
610 diag_process_stm_mask(cmd, DIAG_STM_WDSP,
611 PERIPHERAL_WDSP);
612
Sreelakshmi Gownipalli588a31d2016-11-02 13:33:43 -0700613 if (mask & DIAG_STM_CDSP)
614 diag_process_stm_mask(cmd, DIAG_STM_CDSP,
615 PERIPHERAL_CDSP);
616
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700617 if (mask & DIAG_STM_APPS)
618 diag_process_stm_mask(cmd, DIAG_STM_APPS, APPS_DATA);
619 }
620
621 for (i = 0; i < STM_CMD_NUM_BYTES; i++)
622 dest_buf[i] = *(buf + i);
623
624 /* Set mask denoting which peripherals support STM */
625 if (driver->feature[PERIPHERAL_MODEM].stm_support)
626 rsp_supported |= DIAG_STM_MODEM;
627
628 if (driver->feature[PERIPHERAL_LPASS].stm_support)
629 rsp_supported |= DIAG_STM_LPASS;
630
631 if (driver->feature[PERIPHERAL_WCNSS].stm_support)
632 rsp_supported |= DIAG_STM_WCNSS;
633
634 if (driver->feature[PERIPHERAL_SENSORS].stm_support)
635 rsp_supported |= DIAG_STM_SENSORS;
636
637 if (driver->feature[PERIPHERAL_WDSP].stm_support)
638 rsp_supported |= DIAG_STM_WDSP;
639
Sreelakshmi Gownipalli588a31d2016-11-02 13:33:43 -0700640 if (driver->feature[PERIPHERAL_CDSP].stm_support)
641 rsp_supported |= DIAG_STM_CDSP;
642
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700643 rsp_supported |= DIAG_STM_APPS;
644
645 /* Set mask denoting STM state/status for each peripheral/APSS */
646 if (driver->stm_state[PERIPHERAL_MODEM])
647 rsp_status |= DIAG_STM_MODEM;
648
649 if (driver->stm_state[PERIPHERAL_LPASS])
650 rsp_status |= DIAG_STM_LPASS;
651
652 if (driver->stm_state[PERIPHERAL_WCNSS])
653 rsp_status |= DIAG_STM_WCNSS;
654
655 if (driver->stm_state[PERIPHERAL_SENSORS])
656 rsp_status |= DIAG_STM_SENSORS;
657
658 if (driver->stm_state[PERIPHERAL_WDSP])
659 rsp_status |= DIAG_STM_WDSP;
660
Sreelakshmi Gownipalli588a31d2016-11-02 13:33:43 -0700661 if (driver->stm_state[PERIPHERAL_CDSP])
662 rsp_status |= DIAG_STM_CDSP;
663
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700664 if (driver->stm_state[APPS_DATA])
665 rsp_status |= DIAG_STM_APPS;
666
667 dest_buf[STM_RSP_SUPPORTED_INDEX] = rsp_supported;
668 dest_buf[STM_RSP_STATUS_INDEX] = rsp_status;
669
670 return STM_RSP_NUM_BYTES;
671}
672
673int diag_process_time_sync_query_cmd(unsigned char *src_buf, int src_len,
674 unsigned char *dest_buf, int dest_len)
675{
676 int write_len = 0;
677 struct diag_cmd_time_sync_query_req_t *req = NULL;
678 struct diag_cmd_time_sync_query_rsp_t rsp;
679
680 if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0) {
681 pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d",
682 __func__, src_buf, src_len, dest_buf, dest_len);
683 return -EINVAL;
684 }
685
686 req = (struct diag_cmd_time_sync_query_req_t *)src_buf;
687 rsp.header.cmd_code = req->header.cmd_code;
688 rsp.header.subsys_id = req->header.subsys_id;
689 rsp.header.subsys_cmd_code = req->header.subsys_cmd_code;
690 rsp.version = req->version;
691 rsp.time_api = driver->uses_time_api;
692 memcpy(dest_buf, &rsp, sizeof(rsp));
693 write_len = sizeof(rsp);
694 return write_len;
695}
696
Sreelakshmi Gownipalli8d477d32017-02-08 19:49:06 -0800697int diag_process_diag_id_query_cmd(unsigned char *src_buf, int src_len,
698 unsigned char *dest_buf, int dest_len)
699{
700 int write_len = 0;
701 struct diag_cmd_diag_id_query_req_t *req = NULL;
702 struct diag_cmd_diag_id_query_rsp_t rsp;
703 struct list_head *start;
704 struct list_head *temp;
705 struct diag_id_tbl_t *item = NULL;
706 int rsp_len = 0;
707 int num_entries = 0;
708 uint8_t process_name_len = 0;
709
710 if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0) {
711 pr_err("diag: Invalid input in %s, src_buf:%pK, src_len:%d, dest_buf:%pK, dest_len:%d\n",
712 __func__, src_buf, src_len, dest_buf, dest_len);
713 return -EINVAL;
714 }
715 req = (struct diag_cmd_diag_id_query_req_t *) src_buf;
716 rsp.header.cmd_code = req->header.cmd_code;
717 rsp.header.subsys_id = req->header.subsys_id;
718 rsp.header.subsys_cmd_code = req->header.subsys_cmd_code;
719 rsp.version = req->version;
720 rsp.entry.process_name = NULL;
721 rsp.entry.len = 0;
722 rsp.entry.diag_id = 0;
723 write_len = sizeof(rsp.header) + sizeof(rsp.version) +
724 sizeof(rsp.num_entries);
725 rsp_len = write_len;
726 mutex_lock(&driver->diag_id_mutex);
727 list_for_each_safe(start, temp, &driver->diag_id_list) {
728 item = list_entry(start, struct diag_id_tbl_t, link);
729 memcpy(dest_buf + write_len, &item->diag_id,
730 sizeof(item->diag_id));
731 write_len = write_len + sizeof(item->diag_id);
732 process_name_len = strlen(item->process_name) + 1;
733 memcpy(dest_buf + write_len, &process_name_len,
734 sizeof(process_name_len));
735 write_len = write_len + sizeof(process_name_len);
736 memcpy(dest_buf + write_len, item->process_name,
737 strlen(item->process_name) + 1);
738 write_len = write_len + strlen(item->process_name) + 1;
739 num_entries++;
740 }
741 mutex_unlock(&driver->diag_id_mutex);
742 rsp.num_entries = num_entries;
743 memcpy(dest_buf, &rsp, rsp_len);
744 return write_len;
745}
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700746int diag_process_time_sync_switch_cmd(unsigned char *src_buf, int src_len,
747 unsigned char *dest_buf, int dest_len)
748{
749 uint8_t peripheral, status = 0;
750 struct diag_cmd_time_sync_switch_req_t *req = NULL;
751 struct diag_cmd_time_sync_switch_rsp_t rsp;
752 struct diag_ctrl_msg_time_sync time_sync_msg;
753 int msg_size = sizeof(struct diag_ctrl_msg_time_sync);
754 int err = 0, write_len = 0;
755
756 if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0) {
757 pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d",
758 __func__, src_buf, src_len, dest_buf, dest_len);
759 return -EINVAL;
760 }
761
762 req = (struct diag_cmd_time_sync_switch_req_t *)src_buf;
763 rsp.header.cmd_code = req->header.cmd_code;
764 rsp.header.subsys_id = req->header.subsys_id;
765 rsp.header.subsys_cmd_code = req->header.subsys_cmd_code;
766 rsp.version = req->version;
767 rsp.time_api = req->time_api;
768 if ((req->version > 1) || (req->time_api > 1) ||
769 (req->persist_time > 0)) {
770 dest_buf[0] = BAD_PARAM_RESPONSE_MESSAGE;
771 rsp.time_api_status = 0;
772 rsp.persist_time_status = PERSIST_TIME_NOT_SUPPORTED;
773 memcpy(dest_buf + 1, &rsp, sizeof(rsp));
774 write_len = sizeof(rsp) + 1;
775 timestamp_switch = 0;
776 return write_len;
777 }
778
779 time_sync_msg.ctrl_pkt_id = DIAG_CTRL_MSG_TIME_SYNC_PKT;
780 time_sync_msg.ctrl_pkt_data_len = 5;
781 time_sync_msg.version = 1;
782 time_sync_msg.time_api = req->time_api;
783
784 for (peripheral = 0; peripheral < NUM_PERIPHERALS; peripheral++) {
785 err = diagfwd_write(peripheral, TYPE_CNTL, &time_sync_msg,
786 msg_size);
787 if (err && err != -ENODEV) {
788 pr_err("diag: In %s, unable to write to peripheral: %d, type: %d, len: %d, err: %d\n",
789 __func__, peripheral, TYPE_CNTL,
790 msg_size, err);
791 status |= (1 << peripheral);
792 }
793 }
794
795 driver->time_sync_enabled = 1;
796 driver->uses_time_api = req->time_api;
797
798 switch (req->time_api) {
799 case 0:
800 timestamp_switch = 0;
801 break;
802 case 1:
803 timestamp_switch = 1;
804 break;
805 default:
806 timestamp_switch = 0;
807 break;
808 }
809
810 rsp.time_api_status = status;
811 rsp.persist_time_status = PERSIST_TIME_NOT_SUPPORTED;
812 memcpy(dest_buf, &rsp, sizeof(rsp));
813 write_len = sizeof(rsp);
814 return write_len;
815}
816
817int diag_cmd_log_on_demand(unsigned char *src_buf, int src_len,
818 unsigned char *dest_buf, int dest_len)
819{
820 int write_len = 0;
821 struct diag_log_on_demand_rsp_t header;
822
823 if (!driver->diagfwd_cntl[PERIPHERAL_MODEM] ||
824 !driver->diagfwd_cntl[PERIPHERAL_MODEM]->ch_open ||
825 !driver->log_on_demand_support)
826 return 0;
827
828 if (!src_buf || !dest_buf || src_len <= 0 || dest_len <= 0) {
829 pr_err("diag: Invalid input in %s, src_buf: %pK, src_len: %d, dest_buf: %pK, dest_len: %d",
830 __func__, src_buf, src_len, dest_buf, dest_len);
831 return -EINVAL;
832 }
833
834 header.cmd_code = DIAG_CMD_LOG_ON_DMND;
835 header.log_code = *(uint16_t *)(src_buf + 1);
836 header.status = 1;
837 memcpy(dest_buf, &header, sizeof(struct diag_log_on_demand_rsp_t));
838 write_len += sizeof(struct diag_log_on_demand_rsp_t);
839
840 return write_len;
841}
842
843int diag_cmd_get_mobile_id(unsigned char *src_buf, int src_len,
844 unsigned char *dest_buf, int dest_len)
845{
846 int write_len = 0;
847 struct diag_pkt_header_t *header = NULL;
848 struct diag_cmd_ext_mobile_rsp_t rsp;
849
850 if (!src_buf || src_len != sizeof(*header) || !dest_buf ||
851 dest_len < sizeof(rsp))
852 return -EIO;
853
854 header = (struct diag_pkt_header_t *)src_buf;
855 rsp.header.cmd_code = header->cmd_code;
856 rsp.header.subsys_id = header->subsys_id;
857 rsp.header.subsys_cmd_code = header->subsys_cmd_code;
858 rsp.version = 2;
859 rsp.padding[0] = 0;
860 rsp.padding[1] = 0;
861 rsp.padding[2] = 0;
862 rsp.family = 0;
863 rsp.chip_id = (uint32_t)socinfo_get_id();
864
865 memcpy(dest_buf, &rsp, sizeof(rsp));
866 write_len += sizeof(rsp);
867
868 return write_len;
869}
870
871int diag_check_common_cmd(struct diag_pkt_header_t *header)
872{
873 int i;
874
875 if (!header)
876 return -EIO;
877
878 for (i = 0; i < DIAG_NUM_COMMON_CMD; i++) {
879 if (header->cmd_code == common_cmds[i])
880 return 1;
881 }
882
883 return 0;
884}
885
886static int diag_cmd_chk_stats(unsigned char *src_buf, int src_len,
887 unsigned char *dest_buf, int dest_len)
888{
889 int payload = 0;
890 int write_len = 0;
891 struct diag_pkt_header_t *header = NULL;
892 struct diag_cmd_stats_rsp_t rsp;
893
894 if (!src_buf || src_len < sizeof(struct diag_pkt_header_t) ||
895 !dest_buf || dest_len < sizeof(rsp))
896 return -EINVAL;
897
898 header = (struct diag_pkt_header_t *)src_buf;
899
900 if (header->cmd_code != DIAG_CMD_DIAG_SUBSYS ||
901 header->subsys_id != DIAG_SS_DIAG)
902 return -EINVAL;
903
904 switch (header->subsys_cmd_code) {
905 case DIAG_CMD_OP_GET_MSG_ALLOC:
906 payload = driver->msg_stats.alloc_count;
907 break;
908 case DIAG_CMD_OP_GET_MSG_DROP:
909 payload = driver->msg_stats.drop_count;
910 break;
911 case DIAG_CMD_OP_RESET_MSG_STATS:
912 diag_record_stats(DATA_TYPE_F3, PKT_RESET);
913 break;
914 case DIAG_CMD_OP_GET_LOG_ALLOC:
915 payload = driver->log_stats.alloc_count;
916 break;
917 case DIAG_CMD_OP_GET_LOG_DROP:
918 payload = driver->log_stats.drop_count;
919 break;
920 case DIAG_CMD_OP_RESET_LOG_STATS:
921 diag_record_stats(DATA_TYPE_LOG, PKT_RESET);
922 break;
923 case DIAG_CMD_OP_GET_EVENT_ALLOC:
924 payload = driver->event_stats.alloc_count;
925 break;
926 case DIAG_CMD_OP_GET_EVENT_DROP:
927 payload = driver->event_stats.drop_count;
928 break;
929 case DIAG_CMD_OP_RESET_EVENT_STATS:
930 diag_record_stats(DATA_TYPE_EVENT, PKT_RESET);
931 break;
932 default:
933 return -EINVAL;
934 }
935
936 memcpy(&rsp.header, header, sizeof(struct diag_pkt_header_t));
937 rsp.payload = payload;
938 write_len = sizeof(rsp);
939 memcpy(dest_buf, &rsp, sizeof(rsp));
940
941 return write_len;
942}
943
944static int diag_cmd_disable_hdlc(unsigned char *src_buf, int src_len,
945 unsigned char *dest_buf, int dest_len)
946{
947 struct diag_pkt_header_t *header = NULL;
948 struct diag_cmd_hdlc_disable_rsp_t rsp;
949 int write_len = 0;
950
951 if (!src_buf || src_len < sizeof(*header) ||
952 !dest_buf || dest_len < sizeof(rsp)) {
953 return -EIO;
954 }
955
956 header = (struct diag_pkt_header_t *)src_buf;
957 if (header->cmd_code != DIAG_CMD_DIAG_SUBSYS ||
958 header->subsys_id != DIAG_SS_DIAG ||
959 header->subsys_cmd_code != DIAG_CMD_OP_HDLC_DISABLE) {
960 return -EINVAL;
961 }
962
963 memcpy(&rsp.header, header, sizeof(struct diag_pkt_header_t));
964 rsp.framing_version = 1;
965 rsp.result = 0;
966 write_len = sizeof(rsp);
967 memcpy(dest_buf, &rsp, sizeof(rsp));
968
969 return write_len;
970}
971
Chris Lewc937d692017-10-12 13:13:18 +0530972void diag_send_error_rsp(unsigned char *buf, int len,
973 struct diag_md_session_t *info)
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700974{
975 /* -1 to accommodate the first byte 0x13 */
976 if (len > (DIAG_MAX_RSP_SIZE - 1)) {
977 pr_err("diag: cannot send err rsp, huge length: %d\n", len);
978 return;
979 }
980
981 *(uint8_t *)driver->apps_rsp_buf = DIAG_CMD_ERROR;
982 memcpy((driver->apps_rsp_buf + sizeof(uint8_t)), buf, len);
Chris Lewc937d692017-10-12 13:13:18 +0530983 diag_send_rsp(driver->apps_rsp_buf, len + 1, info);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700984}
985
986int diag_process_apps_pkt(unsigned char *buf, int len,
987 struct diag_md_session_t *info)
988{
989 int i;
990 int mask_ret;
991 int write_len = 0;
992 unsigned char *temp = NULL;
993 struct diag_cmd_reg_entry_t entry;
994 struct diag_cmd_reg_entry_t *temp_entry = NULL;
995 struct diag_cmd_reg_t *reg_item = NULL;
996
997 if (!buf)
998 return -EIO;
999
1000 /* Check if the command is a supported mask command */
1001 mask_ret = diag_process_apps_masks(buf, len, info);
1002 if (mask_ret > 0) {
Chris Lewc937d692017-10-12 13:13:18 +05301003 diag_send_rsp(driver->apps_rsp_buf, mask_ret, info);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001004 return 0;
1005 }
1006
1007 temp = buf;
1008 entry.cmd_code = (uint16_t)(*(uint8_t *)temp);
1009 temp += sizeof(uint8_t);
1010 entry.subsys_id = (uint16_t)(*(uint8_t *)temp);
1011 temp += sizeof(uint8_t);
1012 entry.cmd_code_hi = (uint16_t)(*(uint16_t *)temp);
1013 entry.cmd_code_lo = (uint16_t)(*(uint16_t *)temp);
1014 temp += sizeof(uint16_t);
1015
1016 pr_debug("diag: In %s, received cmd %02x %02x %02x\n",
1017 __func__, entry.cmd_code, entry.subsys_id, entry.cmd_code_hi);
1018
1019 if (*buf == DIAG_CMD_LOG_ON_DMND && driver->log_on_demand_support &&
1020 driver->feature[PERIPHERAL_MODEM].rcvd_feature_mask) {
1021 write_len = diag_cmd_log_on_demand(buf, len,
1022 driver->apps_rsp_buf,
1023 DIAG_MAX_RSP_SIZE);
1024 if (write_len > 0)
Chris Lewc937d692017-10-12 13:13:18 +05301025 diag_send_rsp(driver->apps_rsp_buf, write_len, info);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001026 return 0;
1027 }
1028
1029 mutex_lock(&driver->cmd_reg_mutex);
1030 temp_entry = diag_cmd_search(&entry, ALL_PROC);
1031 if (temp_entry) {
1032 reg_item = container_of(temp_entry, struct diag_cmd_reg_t,
1033 entry);
1034 if (info) {
Chris Lewc937d692017-10-12 13:13:18 +05301035 if ((MD_PERIPHERAL_MASK(reg_item->proc) &
1036 info->peripheral_mask) ||
1037 (MD_PERIPHERAL_PD_MASK(reg_item->proc) &
1038 info->peripheral_mask))
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001039 write_len = diag_send_data(reg_item, buf, len);
1040 } else {
1041 if (MD_PERIPHERAL_MASK(reg_item->proc) &
1042 driver->logging_mask)
Chris Lewc937d692017-10-12 13:13:18 +05301043 diag_send_error_rsp(buf, len, info);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001044 else
1045 write_len = diag_send_data(reg_item, buf, len);
1046 }
1047 mutex_unlock(&driver->cmd_reg_mutex);
1048 return write_len;
1049 }
1050 mutex_unlock(&driver->cmd_reg_mutex);
1051
1052#if defined(CONFIG_DIAG_OVER_USB)
1053 /* Check for the command/respond msg for the maximum packet length */
1054 if ((*buf == 0x4b) && (*(buf+1) == 0x12) &&
1055 (*(uint16_t *)(buf+2) == 0x0055)) {
1056 for (i = 0; i < 4; i++)
1057 *(driver->apps_rsp_buf+i) = *(buf+i);
1058 *(uint32_t *)(driver->apps_rsp_buf+4) = DIAG_MAX_REQ_SIZE;
Chris Lewc937d692017-10-12 13:13:18 +05301059 diag_send_rsp(driver->apps_rsp_buf, 8, info);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001060 return 0;
1061 } else if ((*buf == 0x4b) && (*(buf+1) == 0x12) &&
1062 (*(uint16_t *)(buf+2) == DIAG_DIAG_STM)) {
1063 len = diag_process_stm_cmd(buf, driver->apps_rsp_buf);
1064 if (len > 0) {
Chris Lewc937d692017-10-12 13:13:18 +05301065 diag_send_rsp(driver->apps_rsp_buf, len, info);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001066 return 0;
1067 }
1068 return len;
1069 }
1070 /* Check for time sync query command */
1071 else if ((*buf == DIAG_CMD_DIAG_SUBSYS) &&
1072 (*(buf+1) == DIAG_SS_DIAG) &&
1073 (*(uint16_t *)(buf+2) == DIAG_GET_TIME_API)) {
1074 write_len = diag_process_time_sync_query_cmd(buf, len,
1075 driver->apps_rsp_buf,
1076 DIAG_MAX_RSP_SIZE);
1077 if (write_len > 0)
Chris Lewc937d692017-10-12 13:13:18 +05301078 diag_send_rsp(driver->apps_rsp_buf, write_len, info);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001079 return 0;
1080 }
1081 /* Check for time sync switch command */
1082 else if ((*buf == DIAG_CMD_DIAG_SUBSYS) &&
1083 (*(buf+1) == DIAG_SS_DIAG) &&
1084 (*(uint16_t *)(buf+2) == DIAG_SET_TIME_API)) {
1085 write_len = diag_process_time_sync_switch_cmd(buf, len,
1086 driver->apps_rsp_buf,
1087 DIAG_MAX_RSP_SIZE);
1088 if (write_len > 0)
Chris Lewc937d692017-10-12 13:13:18 +05301089 diag_send_rsp(driver->apps_rsp_buf, write_len, info);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001090 return 0;
1091 }
Sreelakshmi Gownipalli8d477d32017-02-08 19:49:06 -08001092 /* Check for diag id command */
1093 else if ((*buf == DIAG_CMD_DIAG_SUBSYS) &&
1094 (*(buf+1) == DIAG_SS_DIAG) &&
1095 (*(uint16_t *)(buf+2) == DIAG_GET_DIAG_ID)) {
1096 write_len = diag_process_diag_id_query_cmd(buf, len,
1097 driver->apps_rsp_buf,
1098 DIAG_MAX_RSP_SIZE);
1099 if (write_len > 0)
Chris Lewc937d692017-10-12 13:13:18 +05301100 diag_send_rsp(driver->apps_rsp_buf, write_len, info);
Sreelakshmi Gownipalli8d477d32017-02-08 19:49:06 -08001101 return 0;
1102 }
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001103 /* Check for download command */
1104 else if ((chk_apps_master()) && (*buf == 0x3A)) {
1105 /* send response back */
1106 driver->apps_rsp_buf[0] = *buf;
Chris Lewc937d692017-10-12 13:13:18 +05301107 diag_send_rsp(driver->apps_rsp_buf, 1, info);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001108 msleep(5000);
1109 /* call download API */
1110 msm_set_restart_mode(RESTART_DLOAD);
1111 pr_crit("diag: download mode set, Rebooting SoC..\n");
1112 kernel_restart(NULL);
1113 /* Not required, represents that command isn't sent to modem */
1114 return 0;
1115 }
1116 /* Check for polling for Apps only DIAG */
1117 else if ((*buf == 0x4b) && (*(buf+1) == 0x32) &&
1118 (*(buf+2) == 0x03)) {
1119 /* If no one has registered for polling */
1120 if (chk_polling_response()) {
1121 /* Respond to polling for Apps only DIAG */
1122 for (i = 0; i < 3; i++)
1123 driver->apps_rsp_buf[i] = *(buf+i);
1124 for (i = 0; i < 13; i++)
1125 driver->apps_rsp_buf[i+3] = 0;
1126
Chris Lewc937d692017-10-12 13:13:18 +05301127 diag_send_rsp(driver->apps_rsp_buf, 16, info);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001128 return 0;
1129 }
1130 }
1131 /* Return the Delayed Response Wrap Status */
1132 else if ((*buf == 0x4b) && (*(buf+1) == 0x32) &&
1133 (*(buf+2) == 0x04) && (*(buf+3) == 0x0)) {
1134 memcpy(driver->apps_rsp_buf, buf, 4);
1135 driver->apps_rsp_buf[4] = wrap_enabled;
Chris Lewc937d692017-10-12 13:13:18 +05301136 diag_send_rsp(driver->apps_rsp_buf, 5, info);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001137 return 0;
1138 }
1139 /* Wrap the Delayed Rsp ID */
1140 else if ((*buf == 0x4b) && (*(buf+1) == 0x32) &&
1141 (*(buf+2) == 0x05) && (*(buf+3) == 0x0)) {
1142 wrap_enabled = true;
1143 memcpy(driver->apps_rsp_buf, buf, 4);
1144 driver->apps_rsp_buf[4] = wrap_count;
Chris Lewc937d692017-10-12 13:13:18 +05301145 diag_send_rsp(driver->apps_rsp_buf, 6, info);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001146 return 0;
1147 }
1148 /* Mobile ID Rsp */
1149 else if ((*buf == DIAG_CMD_DIAG_SUBSYS) &&
1150 (*(buf+1) == DIAG_SS_PARAMS) &&
1151 (*(buf+2) == DIAG_EXT_MOBILE_ID) && (*(buf+3) == 0x0)) {
1152 write_len = diag_cmd_get_mobile_id(buf, len,
1153 driver->apps_rsp_buf,
1154 DIAG_MAX_RSP_SIZE);
1155 if (write_len > 0) {
Chris Lewc937d692017-10-12 13:13:18 +05301156 diag_send_rsp(driver->apps_rsp_buf, write_len, info);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001157 return 0;
1158 }
1159 }
1160 /*
1161 * If the apps processor is master and no other
1162 * processor has registered for polling command.
1163 * If modem is not up and we have not received feature
1164 * mask update from modem, in that case APPS should
1165 * respond for 0X7C command
1166 */
1167 else if (chk_apps_master() &&
1168 !(driver->polling_reg_flag) &&
1169 !(driver->diagfwd_cntl[PERIPHERAL_MODEM]->ch_open) &&
1170 !(driver->feature[PERIPHERAL_MODEM].rcvd_feature_mask)) {
1171 /* respond to 0x0 command */
1172 if (*buf == 0x00) {
1173 for (i = 0; i < 55; i++)
1174 driver->apps_rsp_buf[i] = 0;
1175
Chris Lewc937d692017-10-12 13:13:18 +05301176 diag_send_rsp(driver->apps_rsp_buf, 55, info);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001177 return 0;
1178 }
1179 /* respond to 0x7c command */
1180 else if (*buf == 0x7c) {
1181 driver->apps_rsp_buf[0] = 0x7c;
1182 for (i = 1; i < 8; i++)
1183 driver->apps_rsp_buf[i] = 0;
1184 /* Tools ID for APQ 8060 */
1185 *(int *)(driver->apps_rsp_buf + 8) =
1186 chk_config_get_id();
1187 *(unsigned char *)(driver->apps_rsp_buf + 12) = '\0';
1188 *(unsigned char *)(driver->apps_rsp_buf + 13) = '\0';
Chris Lewc937d692017-10-12 13:13:18 +05301189 diag_send_rsp(driver->apps_rsp_buf, 14, info);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001190 return 0;
1191 }
1192 }
1193 write_len = diag_cmd_chk_stats(buf, len, driver->apps_rsp_buf,
1194 DIAG_MAX_RSP_SIZE);
1195 if (write_len > 0) {
Chris Lewc937d692017-10-12 13:13:18 +05301196 diag_send_rsp(driver->apps_rsp_buf, write_len, info);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001197 return 0;
1198 }
1199 write_len = diag_cmd_disable_hdlc(buf, len, driver->apps_rsp_buf,
1200 DIAG_MAX_RSP_SIZE);
1201 if (write_len > 0) {
1202 /*
1203 * This mutex lock is necessary since we need to drain all the
1204 * pending buffers from peripherals which may be HDLC encoded
1205 * before disabling HDLC encoding on Apps processor.
1206 */
1207 mutex_lock(&driver->hdlc_disable_mutex);
Chris Lewc937d692017-10-12 13:13:18 +05301208 diag_send_rsp(driver->apps_rsp_buf, write_len, info);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001209 /*
1210 * Set the value of hdlc_disabled after sending the response to
1211 * the tools. This is required since the tools is expecting a
1212 * HDLC encoded response for this request.
1213 */
1214 pr_debug("diag: In %s, disabling HDLC encoding\n",
1215 __func__);
1216 if (info)
1217 info->hdlc_disabled = 1;
1218 else
1219 driver->hdlc_disabled = 1;
1220 diag_update_md_clients(HDLC_SUPPORT_TYPE);
1221 mutex_unlock(&driver->hdlc_disable_mutex);
1222 return 0;
1223 }
1224#endif
1225
1226 /* We have now come to the end of the function. */
1227 if (chk_apps_only())
Chris Lewc937d692017-10-12 13:13:18 +05301228 diag_send_error_rsp(buf, len, info);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001229
1230 return 0;
1231}
1232
1233void diag_process_hdlc_pkt(void *data, unsigned int len,
1234 struct diag_md_session_t *info)
1235{
1236 int err = 0;
1237 int ret = 0;
1238
1239 if (len > DIAG_MAX_HDLC_BUF_SIZE) {
1240 pr_err("diag: In %s, invalid length: %d\n", __func__, len);
1241 return;
1242 }
1243
1244 mutex_lock(&driver->diag_hdlc_mutex);
1245 pr_debug("diag: In %s, received packet of length: %d, req_buf_len: %d\n",
1246 __func__, len, driver->hdlc_buf_len);
1247
1248 if (driver->hdlc_buf_len >= DIAG_MAX_REQ_SIZE) {
1249 pr_err("diag: In %s, request length is more than supported len. Dropping packet.\n",
1250 __func__);
1251 goto fail;
1252 }
1253
1254 hdlc_decode->dest_ptr = driver->hdlc_buf + driver->hdlc_buf_len;
1255 hdlc_decode->dest_size = DIAG_MAX_HDLC_BUF_SIZE - driver->hdlc_buf_len;
1256 hdlc_decode->src_ptr = data;
1257 hdlc_decode->src_size = len;
1258 hdlc_decode->src_idx = 0;
1259 hdlc_decode->dest_idx = 0;
1260
1261 ret = diag_hdlc_decode(hdlc_decode);
1262 /*
1263 * driver->hdlc_buf is of size DIAG_MAX_HDLC_BUF_SIZE. But the decoded
1264 * packet should be within DIAG_MAX_REQ_SIZE.
1265 */
1266 if (driver->hdlc_buf_len + hdlc_decode->dest_idx <= DIAG_MAX_REQ_SIZE) {
1267 driver->hdlc_buf_len += hdlc_decode->dest_idx;
1268 } else {
1269 pr_err_ratelimited("diag: In %s, Dropping packet. pkt_size: %d, max: %d\n",
1270 __func__,
1271 driver->hdlc_buf_len + hdlc_decode->dest_idx,
1272 DIAG_MAX_REQ_SIZE);
1273 goto fail;
1274 }
1275
1276 if (ret == HDLC_COMPLETE) {
1277 err = crc_check(driver->hdlc_buf, driver->hdlc_buf_len);
1278 if (err) {
1279 /* CRC check failed. */
1280 pr_err_ratelimited("diag: In %s, bad CRC. Dropping packet\n",
1281 __func__);
1282 goto fail;
1283 }
1284 driver->hdlc_buf_len -= HDLC_FOOTER_LEN;
1285
1286 if (driver->hdlc_buf_len < 1) {
1287 pr_err_ratelimited("diag: In %s, message is too short, len: %d, dest len: %d\n",
1288 __func__, driver->hdlc_buf_len,
1289 hdlc_decode->dest_idx);
1290 goto fail;
1291 }
1292
1293 err = diag_process_apps_pkt(driver->hdlc_buf,
1294 driver->hdlc_buf_len, info);
1295 if (err < 0)
1296 goto fail;
1297 } else {
1298 goto end;
1299 }
1300
1301 driver->hdlc_buf_len = 0;
1302 mutex_unlock(&driver->diag_hdlc_mutex);
1303 return;
1304
1305fail:
1306 /*
1307 * Tools needs to get a response in order to start its
1308 * recovery algorithm. Send an error response if the
1309 * packet is not in expected format.
1310 */
Chris Lewc937d692017-10-12 13:13:18 +05301311 diag_send_error_rsp(driver->hdlc_buf, driver->hdlc_buf_len, info);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001312 driver->hdlc_buf_len = 0;
1313end:
1314 mutex_unlock(&driver->diag_hdlc_mutex);
1315}
1316
1317static int diagfwd_mux_open(int id, int mode)
1318{
1319 uint8_t i;
1320 unsigned long flags;
1321
1322 switch (mode) {
1323 case DIAG_USB_MODE:
1324 driver->usb_connected = 1;
1325 break;
1326 case DIAG_MEMORY_DEVICE_MODE:
1327 break;
1328 default:
1329 return -EINVAL;
1330 }
1331
1332 if (driver->rsp_buf_busy) {
1333 /*
1334 * When a client switches from callback mode to USB mode
1335 * explicitly, there can be a situation when the last response
1336 * is not drained to the user space application. Reset the
1337 * in_busy flag in this case.
1338 */
1339 spin_lock_irqsave(&driver->rsp_buf_busy_lock, flags);
1340 driver->rsp_buf_busy = 0;
1341 spin_unlock_irqrestore(&driver->rsp_buf_busy_lock, flags);
1342 }
1343 for (i = 0; i < NUM_PERIPHERALS; i++) {
1344 diagfwd_open(i, TYPE_DATA);
1345 diagfwd_open(i, TYPE_CMD);
1346 }
1347 queue_work(driver->diag_real_time_wq, &driver->diag_real_time_work);
1348 return 0;
1349}
1350
1351static int diagfwd_mux_close(int id, int mode)
1352{
Manoj Prabhu B95427a22016-11-04 11:58:11 +05301353 uint8_t i;
1354
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001355 switch (mode) {
1356 case DIAG_USB_MODE:
1357 driver->usb_connected = 0;
1358 break;
1359 case DIAG_MEMORY_DEVICE_MODE:
1360 break;
1361 default:
1362 return -EINVAL;
1363 }
1364
1365 if ((driver->logging_mode == DIAG_MULTI_MODE &&
1366 driver->md_session_mode == DIAG_MD_NONE) ||
1367 (driver->md_session_mode == DIAG_MD_PERIPHERAL)) {
1368 /*
1369 * This case indicates that the USB is removed
1370 * but there is a client running in background
1371 * with Memory Device mode.
1372 */
1373 } else {
1374 /*
Manoj Prabhu B95427a22016-11-04 11:58:11 +05301375 * With sysfs parameter to clear masks set,
1376 * peripheral masks are cleared on ODL exit and
1377 * USB disconnection and buffers are not marked busy.
1378 * This enables read and drop of stale packets.
1379 *
1380 * With sysfs parameter to clear masks cleared,
1381 * masks are not cleared and buffers are to be marked
1382 * busy to ensure traffic generated by peripheral
1383 * are not read
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001384 */
Manoj Prabhu B95427a22016-11-04 11:58:11 +05301385 if (!(diag_mask_param())) {
1386 for (i = 0; i < NUM_PERIPHERALS; i++) {
1387 diagfwd_close(i, TYPE_DATA);
1388 diagfwd_close(i, TYPE_CMD);
1389 }
1390 }
1391 /* Re enable HDLC encoding */
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001392 pr_debug("diag: In %s, re-enabling HDLC encoding\n",
1393 __func__);
1394 mutex_lock(&driver->hdlc_disable_mutex);
1395 if (driver->md_session_mode == DIAG_MD_NONE)
1396 driver->hdlc_disabled = 0;
1397 mutex_unlock(&driver->hdlc_disable_mutex);
1398 queue_work(driver->diag_wq,
1399 &(driver->update_user_clients));
1400 }
1401 queue_work(driver->diag_real_time_wq,
1402 &driver->diag_real_time_work);
1403 return 0;
1404}
1405
1406static uint8_t hdlc_reset;
1407
1408static void hdlc_reset_timer_start(struct diag_md_session_t *info)
1409{
Manoj Prabhu Bdc4cf782016-11-15 19:01:54 +05301410 mutex_lock(&driver->md_session_lock);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001411 if (!hdlc_timer_in_progress) {
1412 hdlc_timer_in_progress = 1;
1413 if (info)
1414 mod_timer(&info->hdlc_reset_timer,
1415 jiffies + msecs_to_jiffies(200));
1416 else
1417 mod_timer(&driver->hdlc_reset_timer,
1418 jiffies + msecs_to_jiffies(200));
1419 }
Manoj Prabhu Bdc4cf782016-11-15 19:01:54 +05301420 mutex_unlock(&driver->md_session_lock);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001421}
1422
1423static void hdlc_reset_timer_func(unsigned long data)
1424{
1425 pr_debug("diag: In %s, re-enabling HDLC encoding\n",
1426 __func__);
1427 if (hdlc_reset) {
1428 driver->hdlc_disabled = 0;
1429 queue_work(driver->diag_wq,
1430 &(driver->update_user_clients));
1431 }
1432 hdlc_timer_in_progress = 0;
1433}
1434
1435void diag_md_hdlc_reset_timer_func(unsigned long pid)
1436{
1437 struct diag_md_session_t *session_info = NULL;
1438
1439 pr_debug("diag: In %s, re-enabling HDLC encoding\n",
1440 __func__);
1441 if (hdlc_reset) {
1442 session_info = diag_md_session_get_pid(pid);
1443 if (session_info)
1444 session_info->hdlc_disabled = 0;
1445 queue_work(driver->diag_wq,
1446 &(driver->update_md_clients));
1447 }
1448 hdlc_timer_in_progress = 0;
1449}
1450
1451static void diag_hdlc_start_recovery(unsigned char *buf, int len,
1452 struct diag_md_session_t *info)
1453{
1454 int i;
1455 static uint32_t bad_byte_counter;
1456 unsigned char *start_ptr = NULL;
1457 struct diag_pkt_frame_t *actual_pkt = NULL;
1458
1459 hdlc_reset = 1;
1460 hdlc_reset_timer_start(info);
1461
1462 actual_pkt = (struct diag_pkt_frame_t *)buf;
1463 for (i = 0; i < len; i++) {
1464 if (actual_pkt->start == CONTROL_CHAR &&
1465 actual_pkt->version == 1 &&
1466 actual_pkt->length < len &&
1467 (*(uint8_t *)(buf +
1468 sizeof(struct diag_pkt_frame_t) +
1469 actual_pkt->length) == CONTROL_CHAR)) {
1470 start_ptr = &buf[i];
1471 break;
1472 }
1473 bad_byte_counter++;
1474 if (bad_byte_counter > (DIAG_MAX_REQ_SIZE +
1475 sizeof(struct diag_pkt_frame_t) + 1)) {
1476 bad_byte_counter = 0;
1477 pr_err("diag: In %s, re-enabling HDLC encoding\n",
1478 __func__);
1479 mutex_lock(&driver->hdlc_disable_mutex);
1480 if (info)
1481 info->hdlc_disabled = 0;
1482 else
1483 driver->hdlc_disabled = 0;
1484 mutex_unlock(&driver->hdlc_disable_mutex);
1485 diag_update_md_clients(HDLC_SUPPORT_TYPE);
1486
1487 return;
1488 }
1489 }
1490
1491 if (start_ptr) {
1492 /* Discard any partial packet reads */
Hardik Arya62dce9f2017-06-15 10:39:34 +05301493 mutex_lock(&driver->hdlc_recovery_mutex);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001494 driver->incoming_pkt.processing = 0;
Hardik Arya62dce9f2017-06-15 10:39:34 +05301495 mutex_unlock(&driver->hdlc_recovery_mutex);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001496 diag_process_non_hdlc_pkt(start_ptr, len - i, info);
1497 }
1498}
1499
1500void diag_process_non_hdlc_pkt(unsigned char *buf, int len,
1501 struct diag_md_session_t *info)
1502{
1503 int err = 0;
1504 uint16_t pkt_len = 0;
1505 uint32_t read_bytes = 0;
1506 const uint32_t header_len = sizeof(struct diag_pkt_frame_t);
1507 struct diag_pkt_frame_t *actual_pkt = NULL;
1508 unsigned char *data_ptr = NULL;
Hardik Arya62dce9f2017-06-15 10:39:34 +05301509 struct diag_partial_pkt_t *partial_pkt = NULL;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001510
Hardik Arya62dce9f2017-06-15 10:39:34 +05301511 mutex_lock(&driver->hdlc_recovery_mutex);
1512 if (!buf || len <= 0) {
1513 mutex_unlock(&driver->hdlc_recovery_mutex);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001514 return;
Hardik Arya62dce9f2017-06-15 10:39:34 +05301515 }
1516 partial_pkt = &driver->incoming_pkt;
1517 if (!partial_pkt->processing) {
1518 mutex_unlock(&driver->hdlc_recovery_mutex);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001519 goto start;
Hardik Arya62dce9f2017-06-15 10:39:34 +05301520 }
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001521
1522 if (partial_pkt->remaining > len) {
1523 if ((partial_pkt->read_len + len) > partial_pkt->capacity) {
1524 pr_err("diag: Invalid length %d, %d received in %s\n",
1525 partial_pkt->read_len, len, __func__);
Hardik Arya62dce9f2017-06-15 10:39:34 +05301526 mutex_unlock(&driver->hdlc_recovery_mutex);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001527 goto end;
1528 }
1529 memcpy(partial_pkt->data + partial_pkt->read_len, buf, len);
1530 read_bytes += len;
1531 buf += read_bytes;
1532 partial_pkt->read_len += len;
1533 partial_pkt->remaining -= len;
1534 } else {
1535 if ((partial_pkt->read_len + partial_pkt->remaining) >
1536 partial_pkt->capacity) {
1537 pr_err("diag: Invalid length during partial read %d, %d received in %s\n",
1538 partial_pkt->read_len,
1539 partial_pkt->remaining, __func__);
Hardik Arya62dce9f2017-06-15 10:39:34 +05301540 mutex_unlock(&driver->hdlc_recovery_mutex);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001541 goto end;
1542 }
1543 memcpy(partial_pkt->data + partial_pkt->read_len, buf,
1544 partial_pkt->remaining);
1545 read_bytes += partial_pkt->remaining;
1546 buf += read_bytes;
1547 partial_pkt->read_len += partial_pkt->remaining;
1548 partial_pkt->remaining = 0;
1549 }
1550
1551 if (partial_pkt->remaining == 0) {
1552 actual_pkt = (struct diag_pkt_frame_t *)(partial_pkt->data);
1553 data_ptr = partial_pkt->data + header_len;
Hardik Arya62dce9f2017-06-15 10:39:34 +05301554 if (*(uint8_t *)(data_ptr + actual_pkt->length) !=
1555 CONTROL_CHAR) {
1556 mutex_unlock(&driver->hdlc_recovery_mutex);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001557 diag_hdlc_start_recovery(buf, len, info);
Hardik Arya62dce9f2017-06-15 10:39:34 +05301558 mutex_lock(&driver->hdlc_recovery_mutex);
1559 }
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001560 err = diag_process_apps_pkt(data_ptr,
1561 actual_pkt->length, info);
1562 if (err) {
1563 pr_err("diag: In %s, unable to process incoming data packet, err: %d\n",
1564 __func__, err);
Hardik Arya62dce9f2017-06-15 10:39:34 +05301565 mutex_unlock(&driver->hdlc_recovery_mutex);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001566 goto end;
1567 }
1568 partial_pkt->read_len = 0;
1569 partial_pkt->total_len = 0;
1570 partial_pkt->processing = 0;
Hardik Arya62dce9f2017-06-15 10:39:34 +05301571 mutex_unlock(&driver->hdlc_recovery_mutex);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001572 goto start;
1573 }
Hardik Arya62dce9f2017-06-15 10:39:34 +05301574 mutex_unlock(&driver->hdlc_recovery_mutex);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001575 goto end;
1576
1577start:
1578 while (read_bytes < len) {
1579 actual_pkt = (struct diag_pkt_frame_t *)buf;
1580 pkt_len = actual_pkt->length;
1581
1582 if (actual_pkt->start != CONTROL_CHAR) {
1583 diag_hdlc_start_recovery(buf, len, info);
Chris Lewc937d692017-10-12 13:13:18 +05301584 diag_send_error_rsp(buf, len, info);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001585 goto end;
1586 }
Hardik Arya62dce9f2017-06-15 10:39:34 +05301587 mutex_lock(&driver->hdlc_recovery_mutex);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001588 if (pkt_len + header_len > partial_pkt->capacity) {
1589 pr_err("diag: In %s, incoming data is too large for the request buffer %d\n",
1590 __func__, pkt_len);
Hardik Arya62dce9f2017-06-15 10:39:34 +05301591 mutex_unlock(&driver->hdlc_recovery_mutex);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001592 diag_hdlc_start_recovery(buf, len, info);
1593 break;
1594 }
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001595 if ((pkt_len + header_len) > (len - read_bytes)) {
1596 partial_pkt->read_len = len - read_bytes;
1597 partial_pkt->total_len = pkt_len + header_len;
1598 partial_pkt->remaining = partial_pkt->total_len -
1599 partial_pkt->read_len;
1600 partial_pkt->processing = 1;
1601 memcpy(partial_pkt->data, buf, partial_pkt->read_len);
Hardik Arya62dce9f2017-06-15 10:39:34 +05301602 mutex_unlock(&driver->hdlc_recovery_mutex);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001603 break;
1604 }
1605 data_ptr = buf + header_len;
Hardik Arya62dce9f2017-06-15 10:39:34 +05301606 if (*(uint8_t *)(data_ptr + actual_pkt->length) !=
1607 CONTROL_CHAR) {
1608 mutex_unlock(&driver->hdlc_recovery_mutex);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001609 diag_hdlc_start_recovery(buf, len, info);
Hardik Arya62dce9f2017-06-15 10:39:34 +05301610 mutex_lock(&driver->hdlc_recovery_mutex);
1611 }
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001612 else
1613 hdlc_reset = 0;
1614 err = diag_process_apps_pkt(data_ptr,
1615 actual_pkt->length, info);
Hardik Arya62dce9f2017-06-15 10:39:34 +05301616 if (err) {
1617 mutex_unlock(&driver->hdlc_recovery_mutex);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001618 break;
Hardik Arya62dce9f2017-06-15 10:39:34 +05301619 }
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001620 read_bytes += header_len + pkt_len + 1;
1621 buf += header_len + pkt_len + 1; /* advance to next pkt */
Hardik Arya62dce9f2017-06-15 10:39:34 +05301622 mutex_unlock(&driver->hdlc_recovery_mutex);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001623 }
1624end:
1625 return;
1626}
1627
1628static int diagfwd_mux_read_done(unsigned char *buf, int len, int ctxt)
1629{
1630 if (!buf || len <= 0)
1631 return -EINVAL;
1632
1633 if (!driver->hdlc_disabled)
1634 diag_process_hdlc_pkt(buf, len, NULL);
1635 else
1636 diag_process_non_hdlc_pkt(buf, len, NULL);
1637
1638 diag_mux_queue_read(ctxt);
1639 return 0;
1640}
1641
1642static int diagfwd_mux_write_done(unsigned char *buf, int len, int buf_ctxt,
1643 int ctxt)
1644{
1645 unsigned long flags;
1646 int peripheral = -1;
1647 int type = -1;
1648 int num = -1;
1649
1650 if (!buf || len < 0)
1651 return -EINVAL;
1652
1653 peripheral = GET_BUF_PERIPHERAL(buf_ctxt);
1654 type = GET_BUF_TYPE(buf_ctxt);
1655 num = GET_BUF_NUM(buf_ctxt);
1656
1657 switch (type) {
1658 case TYPE_DATA:
1659 if (peripheral >= 0 && peripheral < NUM_PERIPHERALS) {
Hardik Arya53bf3452017-09-06 15:34:19 +05301660 DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
1661 "Marking buffer as free after write done p: %d, t: %d, buf_num: %d\n",
1662 peripheral, type, num);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001663 diagfwd_write_done(peripheral, type, num);
1664 diag_ws_on_copy(DIAG_WS_MUX);
1665 } else if (peripheral == APPS_DATA) {
1666 diagmem_free(driver, (unsigned char *)buf,
1667 POOL_TYPE_HDLC);
1668 buf = NULL;
1669 } else {
1670 pr_err_ratelimited("diag: Invalid peripheral %d in %s, type: %d\n",
1671 peripheral, __func__, type);
1672 }
1673 break;
1674 case TYPE_CMD:
1675 if (peripheral >= 0 && peripheral < NUM_PERIPHERALS) {
1676 diagfwd_write_done(peripheral, type, num);
Hardik Arya53bf3452017-09-06 15:34:19 +05301677 DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
1678 "Marking buffer as free after write done p: %d, t: %d, buf_num: %d\n",
1679 peripheral, type, num);
Chris Lewc937d692017-10-12 13:13:18 +05301680 }
1681 if (peripheral == APPS_DATA ||
1682 ctxt == DIAG_MEMORY_DEVICE_MODE) {
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001683 spin_lock_irqsave(&driver->rsp_buf_busy_lock, flags);
1684 driver->rsp_buf_busy = 0;
1685 driver->encoded_rsp_len = 0;
1686 spin_unlock_irqrestore(&driver->rsp_buf_busy_lock,
1687 flags);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001688 }
1689 break;
1690 default:
1691 pr_err_ratelimited("diag: Incorrect data type %d, buf_ctxt: %d in %s\n",
1692 type, buf_ctxt, __func__);
1693 break;
1694 }
1695
1696 return 0;
1697}
1698
1699static struct diag_mux_ops diagfwd_mux_ops = {
1700 .open = diagfwd_mux_open,
1701 .close = diagfwd_mux_close,
1702 .read_done = diagfwd_mux_read_done,
1703 .write_done = diagfwd_mux_write_done
1704};
1705
1706int diagfwd_init(void)
1707{
1708 int ret;
1709 int i;
1710
1711 wrap_enabled = 0;
1712 wrap_count = 0;
1713 driver->use_device_tree = has_device_tree();
1714 for (i = 0; i < DIAG_NUM_PROC; i++)
1715 driver->real_time_mode[i] = 1;
1716 driver->supports_separate_cmdrsp = 1;
1717 driver->supports_apps_hdlc_encoding = 1;
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301718 driver->supports_apps_header_untagging = 1;
1719 for (i = 0; i < NUM_PERIPHERALS; i++)
1720 driver->peripheral_untag[i] = 0;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001721 mutex_init(&driver->diag_hdlc_mutex);
1722 mutex_init(&driver->diag_cntl_mutex);
1723 mutex_init(&driver->mode_lock);
1724 driver->encoded_rsp_buf = kzalloc(DIAG_MAX_HDLC_BUF_SIZE +
1725 APF_DIAG_PADDING, GFP_KERNEL);
1726 if (!driver->encoded_rsp_buf)
1727 goto err;
1728 kmemleak_not_leak(driver->encoded_rsp_buf);
1729 hdlc_decode = kzalloc(sizeof(struct diag_hdlc_decode_type),
1730 GFP_KERNEL);
1731 if (!hdlc_decode)
1732 goto err;
1733 setup_timer(&driver->hdlc_reset_timer, hdlc_reset_timer_func, 0);
1734 kmemleak_not_leak(hdlc_decode);
1735 driver->encoded_rsp_len = 0;
1736 driver->rsp_buf_busy = 0;
1737 spin_lock_init(&driver->rsp_buf_busy_lock);
1738 driver->user_space_data_busy = 0;
1739 driver->hdlc_buf_len = 0;
1740 INIT_LIST_HEAD(&driver->cmd_reg_list);
1741 driver->cmd_reg_count = 0;
1742 mutex_init(&driver->cmd_reg_mutex);
1743
1744 for (i = 0; i < NUM_PERIPHERALS; i++) {
1745 driver->feature[i].separate_cmd_rsp = 0;
1746 driver->feature[i].stm_support = DISABLE_STM;
1747 driver->feature[i].rcvd_feature_mask = 0;
1748 driver->feature[i].peripheral_buffering = 0;
1749 driver->feature[i].encode_hdlc = 0;
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301750 driver->feature[i].untag_header =
1751 DISABLE_PKT_HEADER_UNTAGGING;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001752 driver->feature[i].mask_centralization = 0;
1753 driver->feature[i].log_on_demand = 0;
1754 driver->feature[i].sent_feature_mask = 0;
Manoj Prabhu B571cf422017-08-08 19:01:41 +05301755 driver->feature[i].diag_id_support = 0;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001756 driver->buffering_mode[i].peripheral = i;
1757 driver->buffering_mode[i].mode = DIAG_BUFFERING_MODE_STREAMING;
1758 driver->buffering_mode[i].high_wm_val = DEFAULT_HIGH_WM_VAL;
1759 driver->buffering_mode[i].low_wm_val = DEFAULT_LOW_WM_VAL;
1760 }
1761
1762 for (i = 0; i < NUM_STM_PROCESSORS; i++) {
1763 driver->stm_state_requested[i] = DISABLE_STM;
1764 driver->stm_state[i] = DISABLE_STM;
1765 }
1766
1767 if (driver->hdlc_buf == NULL) {
1768 driver->hdlc_buf = kzalloc(DIAG_MAX_HDLC_BUF_SIZE, GFP_KERNEL);
1769 if (!driver->hdlc_buf)
1770 goto err;
1771 kmemleak_not_leak(driver->hdlc_buf);
1772 }
1773 if (driver->user_space_data_buf == NULL)
1774 driver->user_space_data_buf = kzalloc(USER_SPACE_DATA,
1775 GFP_KERNEL);
1776 if (driver->user_space_data_buf == NULL)
1777 goto err;
1778 kmemleak_not_leak(driver->user_space_data_buf);
1779
1780 if (!driver->client_map) {
1781 driver->client_map = kcalloc(driver->num_clients,
1782 sizeof(struct diag_client_map), GFP_KERNEL);
1783 if (!driver->client_map)
1784 goto err;
1785 }
1786 kmemleak_not_leak(driver->client_map);
1787
1788 if (!driver->data_ready) {
1789 driver->data_ready = kcalloc(driver->num_clients,
1790 sizeof(int), GFP_KERNEL);
1791 if (!driver->data_ready)
1792 goto err;
1793 }
1794 kmemleak_not_leak(driver->data_ready);
1795
1796 if (driver->apps_req_buf == NULL) {
1797 driver->apps_req_buf = kzalloc(DIAG_MAX_REQ_SIZE, GFP_KERNEL);
1798 if (!driver->apps_req_buf)
1799 goto err;
1800 kmemleak_not_leak(driver->apps_req_buf);
1801 }
1802 if (driver->dci_pkt_buf == NULL) {
1803 driver->dci_pkt_buf = kzalloc(DCI_BUF_SIZE, GFP_KERNEL);
1804 if (!driver->dci_pkt_buf)
1805 goto err;
1806 kmemleak_not_leak(driver->dci_pkt_buf);
1807 }
1808 if (driver->apps_rsp_buf == NULL) {
1809 driver->apps_rsp_buf = kzalloc(DIAG_MAX_RSP_SIZE, GFP_KERNEL);
1810 if (driver->apps_rsp_buf == NULL)
1811 goto err;
1812 kmemleak_not_leak(driver->apps_rsp_buf);
1813 }
1814 driver->diag_wq = create_singlethread_workqueue("diag_wq");
1815 if (!driver->diag_wq)
1816 goto err;
1817 ret = diag_mux_register(DIAG_LOCAL_PROC, DIAG_LOCAL_PROC,
1818 &diagfwd_mux_ops);
1819 if (ret) {
1820 pr_err("diag: Unable to register with USB, err: %d\n", ret);
1821 goto err;
1822 }
1823
1824 return 0;
1825err:
1826 pr_err("diag: In %s, couldn't initialize diag\n", __func__);
1827
1828 diag_usb_exit(DIAG_USB_LOCAL);
1829 kfree(driver->encoded_rsp_buf);
1830 kfree(driver->hdlc_buf);
1831 kfree(driver->client_map);
1832 kfree(driver->data_ready);
1833 kfree(driver->apps_req_buf);
1834 kfree(driver->dci_pkt_buf);
1835 kfree(driver->apps_rsp_buf);
1836 kfree(hdlc_decode);
1837 kfree(driver->user_space_data_buf);
1838 if (driver->diag_wq)
1839 destroy_workqueue(driver->diag_wq);
1840 return -ENOMEM;
1841}
1842
1843void diagfwd_exit(void)
1844{
1845 kfree(driver->encoded_rsp_buf);
1846 kfree(driver->hdlc_buf);
1847 kfree(hdlc_decode);
1848 kfree(driver->client_map);
1849 kfree(driver->data_ready);
1850 kfree(driver->apps_req_buf);
1851 kfree(driver->dci_pkt_buf);
1852 kfree(driver->apps_rsp_buf);
1853 kfree(driver->user_space_data_buf);
1854 destroy_workqueue(driver->diag_wq);
1855}