blob: 8d47ee38cb7dc767915b26389f9c7f66dd9b4cff [file] [log] [blame]
Sreelakshmi Gownipalli8d477d32017-02-08 19:49:06 -08001/* Copyright (c) 2011-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
13#include <linux/slab.h>
14#include <linux/diagchar.h>
15#include <linux/kmemleak.h>
16#include <linux/delay.h>
17#include "diagchar.h"
18#include "diagfwd.h"
19#include "diagfwd_cntl.h"
20#include "diagfwd_peripheral.h"
21#include "diagfwd_bridge.h"
22#include "diag_dci.h"
23#include "diagmem.h"
24#include "diag_masks.h"
25#include "diag_ipc_logging.h"
26#include "diag_mux.h"
27
28#define FEATURE_SUPPORTED(x) ((feature_mask << (i * 8)) & (1 << x))
29
30/* tracks which peripheral is undergoing SSR */
31static uint16_t reg_dirty;
Sreelakshmi Gownipalli8d477d32017-02-08 19:49:06 -080032static uint8_t diag_id = DIAG_ID_APPS;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -070033static void diag_notify_md_client(uint8_t peripheral, int data);
34
35static void diag_mask_update_work_fn(struct work_struct *work)
36{
37 uint8_t peripheral;
38
39 for (peripheral = 0; peripheral <= NUM_PERIPHERALS; peripheral++) {
40 if (!(driver->mask_update & PERIPHERAL_MASK(peripheral)))
41 continue;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -070042 diag_send_updates_peripheral(peripheral);
43 }
44}
45
46void diag_cntl_channel_open(struct diagfwd_info *p_info)
47{
48 if (!p_info)
49 return;
50 driver->mask_update |= PERIPHERAL_MASK(p_info->peripheral);
51 queue_work(driver->cntl_wq, &driver->mask_update_work);
52 diag_notify_md_client(p_info->peripheral, DIAG_STATUS_OPEN);
53}
54
55void diag_cntl_channel_close(struct diagfwd_info *p_info)
56{
57 uint8_t peripheral;
58
59 if (!p_info)
60 return;
61
62 peripheral = p_info->peripheral;
63 if (peripheral >= NUM_PERIPHERALS)
64 return;
65
66 driver->feature[peripheral].sent_feature_mask = 0;
67 driver->feature[peripheral].rcvd_feature_mask = 0;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -070068 reg_dirty |= PERIPHERAL_MASK(peripheral);
69 diag_cmd_remove_reg_by_proc(peripheral);
Manoj Prabhu B571cf422017-08-08 19:01:41 +053070 driver->diag_id_sent[peripheral] = 0;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -070071 driver->feature[peripheral].stm_support = DISABLE_STM;
72 driver->feature[peripheral].log_on_demand = 0;
73 driver->stm_state[peripheral] = DISABLE_STM;
74 driver->stm_state_requested[peripheral] = DISABLE_STM;
75 reg_dirty ^= PERIPHERAL_MASK(peripheral);
76 diag_notify_md_client(peripheral, DIAG_STATUS_CLOSED);
77}
78
79static void diag_stm_update_work_fn(struct work_struct *work)
80{
81 uint8_t i;
82 uint16_t peripheral_mask = 0;
83 int err = 0;
84
85 mutex_lock(&driver->cntl_lock);
86 peripheral_mask = driver->stm_peripheral;
87 driver->stm_peripheral = 0;
88 mutex_unlock(&driver->cntl_lock);
89
90 if (peripheral_mask == 0)
91 return;
92
93 for (i = 0; i < NUM_PERIPHERALS; i++) {
94 if (!driver->feature[i].stm_support)
95 continue;
96 if (peripheral_mask & PERIPHERAL_MASK(i)) {
97 err = diag_send_stm_state(i,
98 (uint8_t)(driver->stm_state_requested[i]));
99 if (!err) {
100 driver->stm_state[i] =
101 driver->stm_state_requested[i];
102 }
103 }
104 }
105}
106
107void diag_notify_md_client(uint8_t peripheral, int data)
108{
109 int stat = 0;
110 struct siginfo info;
Gopikrishna Mogasati8793b692017-04-18 03:32:41 +0530111 struct pid *pid_struct;
112 struct task_struct *result;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700113
114 if (peripheral > NUM_PERIPHERALS)
115 return;
116
117 if (driver->logging_mode != DIAG_MEMORY_DEVICE_MODE)
118 return;
119
120 mutex_lock(&driver->md_session_lock);
121 memset(&info, 0, sizeof(struct siginfo));
122 info.si_code = SI_QUEUE;
123 info.si_int = (PERIPHERAL_MASK(peripheral) | data);
124 info.si_signo = SIGCONT;
Gopikrishna Mogasati8793b692017-04-18 03:32:41 +0530125
126 if (!driver->md_session_map[peripheral] ||
127 driver->md_session_map[peripheral]->pid <= 0) {
128 pr_err("diag: md_session_map[%d] is invalid\n", peripheral);
129 mutex_unlock(&driver->md_session_lock);
130 return;
131 }
132
133 pid_struct = find_get_pid(
134 driver->md_session_map[peripheral]->pid);
135 DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
136 "md_session_map[%d] pid = %d task = %pK\n",
137 peripheral,
138 driver->md_session_map[peripheral]->pid,
139 driver->md_session_map[peripheral]->task);
140
141 if (pid_struct) {
142 result = get_pid_task(pid_struct, PIDTYPE_PID);
143
144 if (!result) {
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700145 DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
Gopikrishna Mogasati8793b692017-04-18 03:32:41 +0530146 "diag: md_session_map[%d] with pid = %d Exited..\n",
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700147 peripheral,
Gopikrishna Mogasati8793b692017-04-18 03:32:41 +0530148 driver->md_session_map[peripheral]->pid);
149 mutex_unlock(&driver->md_session_lock);
150 return;
151 }
152
153 if (driver->md_session_map[peripheral] &&
154 driver->md_session_map[peripheral]->task == result) {
155 stat = send_sig_info(info.si_signo,
156 &info, result);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700157 if (stat)
158 pr_err("diag: Err sending signal to memory device client, signal data: 0x%x, stat: %d\n",
159 info.si_int, stat);
160 } else
161 pr_err("diag: md_session_map[%d] data is corrupted, signal data: 0x%x, stat: %d\n",
162 peripheral, info.si_int, stat);
163 }
164 mutex_unlock(&driver->md_session_lock);
165}
166
167static void process_pd_status(uint8_t *buf, uint32_t len,
168 uint8_t peripheral)
169{
170 struct diag_ctrl_msg_pd_status *pd_msg = NULL;
171 uint32_t pd;
172 int status = DIAG_STATUS_CLOSED;
173
174 if (!buf || peripheral >= NUM_PERIPHERALS || len < sizeof(*pd_msg))
175 return;
176
177 pd_msg = (struct diag_ctrl_msg_pd_status *)buf;
178 pd = pd_msg->pd_id;
179 status = (pd_msg->status == 0) ? DIAG_STATUS_OPEN : DIAG_STATUS_CLOSED;
180 diag_notify_md_client(peripheral, status);
181}
182
183static void enable_stm_feature(uint8_t peripheral)
184{
185 if (peripheral >= NUM_PERIPHERALS)
186 return;
187
188 mutex_lock(&driver->cntl_lock);
189 driver->feature[peripheral].stm_support = ENABLE_STM;
190 driver->stm_peripheral |= PERIPHERAL_MASK(peripheral);
191 mutex_unlock(&driver->cntl_lock);
192
193 queue_work(driver->cntl_wq, &(driver->stm_update_work));
194}
195
196static void enable_socket_feature(uint8_t peripheral)
197{
198 if (peripheral >= NUM_PERIPHERALS)
199 return;
200
201 if (driver->supports_sockets)
202 driver->feature[peripheral].sockets_enabled = 1;
203 else
204 driver->feature[peripheral].sockets_enabled = 0;
205}
206
207static void process_hdlc_encoding_feature(uint8_t peripheral)
208{
209 if (peripheral >= NUM_PERIPHERALS)
210 return;
211
212 if (driver->supports_apps_hdlc_encoding) {
213 driver->feature[peripheral].encode_hdlc =
214 ENABLE_APPS_HDLC_ENCODING;
215 } else {
216 driver->feature[peripheral].encode_hdlc =
217 DISABLE_APPS_HDLC_ENCODING;
218 }
219}
220
Manoj Prabhu B571cf422017-08-08 19:01:41 +0530221static void process_upd_header_untagging_feature(uint8_t peripheral)
222{
223 if (peripheral >= NUM_PERIPHERALS)
224 return;
225
226 if (driver->supports_apps_header_untagging) {
227 driver->feature[peripheral].untag_header =
228 ENABLE_PKT_HEADER_UNTAGGING;
229 } else {
230 driver->feature[peripheral].untag_header =
231 DISABLE_PKT_HEADER_UNTAGGING;
232 }
233}
234
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700235static void process_command_deregistration(uint8_t *buf, uint32_t len,
236 uint8_t peripheral)
237{
238 uint8_t *ptr = buf;
239 int i;
240 int header_len = sizeof(struct diag_ctrl_cmd_dereg);
241 int read_len = 0;
242 struct diag_ctrl_cmd_dereg *dereg = NULL;
243 struct cmd_code_range *range = NULL;
244 struct diag_cmd_reg_entry_t del_entry;
245
246 /*
247 * Perform Basic sanity. The len field is the size of the data payload.
248 * This doesn't include the header size.
249 */
250 if (!buf || peripheral >= NUM_PERIPHERALS || len == 0)
251 return;
252
253 dereg = (struct diag_ctrl_cmd_dereg *)ptr;
254 ptr += header_len;
255 /* Don't account for pkt_id and length */
256 read_len += header_len - (2 * sizeof(uint32_t));
257
258 if (dereg->count_entries == 0) {
259 pr_debug("diag: In %s, received reg tbl with no entries\n",
260 __func__);
261 return;
262 }
263
264 for (i = 0; i < dereg->count_entries && read_len < len; i++) {
265 range = (struct cmd_code_range *)ptr;
266 ptr += sizeof(struct cmd_code_range) - sizeof(uint32_t);
267 read_len += sizeof(struct cmd_code_range) - sizeof(uint32_t);
268 del_entry.cmd_code = dereg->cmd_code;
269 del_entry.subsys_id = dereg->subsysid;
270 del_entry.cmd_code_hi = range->cmd_code_hi;
271 del_entry.cmd_code_lo = range->cmd_code_lo;
272 diag_cmd_remove_reg(&del_entry, peripheral);
273 }
274
275 if (i != dereg->count_entries) {
276 pr_err("diag: In %s, reading less than available, read_len: %d, len: %d count: %d\n",
277 __func__, read_len, len, dereg->count_entries);
278 }
279}
280static void process_command_registration(uint8_t *buf, uint32_t len,
281 uint8_t peripheral)
282{
283 uint8_t *ptr = buf;
284 int i;
285 int header_len = sizeof(struct diag_ctrl_cmd_reg);
286 int read_len = 0;
287 struct diag_ctrl_cmd_reg *reg = NULL;
288 struct cmd_code_range *range = NULL;
289 struct diag_cmd_reg_entry_t new_entry;
290
291 /*
292 * Perform Basic sanity. The len field is the size of the data payload.
293 * This doesn't include the header size.
294 */
295 if (!buf || peripheral >= NUM_PERIPHERALS || len == 0)
296 return;
297
298 reg = (struct diag_ctrl_cmd_reg *)ptr;
299 ptr += header_len;
300 /* Don't account for pkt_id and length */
301 read_len += header_len - (2 * sizeof(uint32_t));
302
303 if (reg->count_entries == 0) {
304 pr_debug("diag: In %s, received reg tbl with no entries\n",
305 __func__);
306 return;
307 }
308
309 for (i = 0; i < reg->count_entries && read_len < len; i++) {
310 range = (struct cmd_code_range *)ptr;
311 ptr += sizeof(struct cmd_code_range);
312 read_len += sizeof(struct cmd_code_range);
313 new_entry.cmd_code = reg->cmd_code;
314 new_entry.subsys_id = reg->subsysid;
315 new_entry.cmd_code_hi = range->cmd_code_hi;
316 new_entry.cmd_code_lo = range->cmd_code_lo;
317 diag_cmd_add_reg(&new_entry, peripheral, INVALID_PID);
318 }
319
320 if (i != reg->count_entries) {
321 pr_err("diag: In %s, reading less than available, read_len: %d, len: %d count: %d\n",
322 __func__, read_len, len, reg->count_entries);
323 }
324}
325
326static void diag_close_transport_work_fn(struct work_struct *work)
327{
328 uint8_t transport;
329 uint8_t peripheral;
330
331 mutex_lock(&driver->cntl_lock);
332 for (peripheral = 0; peripheral <= NUM_PERIPHERALS; peripheral++) {
333 if (!(driver->close_transport & PERIPHERAL_MASK(peripheral)))
334 continue;
335 driver->close_transport ^= PERIPHERAL_MASK(peripheral);
Hardik Aryad6da1cb2017-11-23 20:40:55 +0530336#ifdef CONFIG_DIAG_USES_SMD
337 transport = driver->feature[peripheral].sockets_enabled ?
338 TRANSPORT_SMD : TRANSPORT_SOCKET;
339#else
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700340 transport = driver->feature[peripheral].sockets_enabled ?
341 TRANSPORT_GLINK : TRANSPORT_SOCKET;
Hardik Aryad6da1cb2017-11-23 20:40:55 +0530342#endif
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700343 diagfwd_close_transport(transport, peripheral);
344 }
345 mutex_unlock(&driver->cntl_lock);
346}
347
348static void process_socket_feature(uint8_t peripheral)
349{
350 if (peripheral >= NUM_PERIPHERALS)
351 return;
352
353 mutex_lock(&driver->cntl_lock);
354 driver->close_transport |= PERIPHERAL_MASK(peripheral);
355 queue_work(driver->cntl_wq, &driver->close_transport_work);
356 mutex_unlock(&driver->cntl_lock);
357}
358
359static void process_log_on_demand_feature(uint8_t peripheral)
360{
361 /* Log On Demand command is registered only on Modem */
362 if (peripheral != PERIPHERAL_MODEM)
363 return;
364
365 if (driver->feature[PERIPHERAL_MODEM].log_on_demand)
366 driver->log_on_demand_support = 1;
367 else
368 driver->log_on_demand_support = 0;
369}
370
371static void process_incoming_feature_mask(uint8_t *buf, uint32_t len,
372 uint8_t peripheral)
373{
374 int i;
375 int header_len = sizeof(struct diag_ctrl_feature_mask);
376 int read_len = 0;
377 struct diag_ctrl_feature_mask *header = NULL;
378 uint32_t feature_mask_len = 0;
379 uint32_t feature_mask = 0;
380 uint8_t *ptr = buf;
381
382 if (!buf || peripheral >= NUM_PERIPHERALS || len == 0)
383 return;
384
385 header = (struct diag_ctrl_feature_mask *)ptr;
386 ptr += header_len;
387 feature_mask_len = header->feature_mask_len;
388
389 if (feature_mask_len == 0) {
390 pr_debug("diag: In %s, received invalid feature mask from peripheral %d\n",
391 __func__, peripheral);
392 return;
393 }
394
395 if (feature_mask_len > FEATURE_MASK_LEN) {
396 pr_alert("diag: Receiving feature mask length more than Apps support\n");
397 feature_mask_len = FEATURE_MASK_LEN;
398 }
399
Manoj Prabhu B2a428272016-12-22 15:22:03 +0530400 diag_cmd_remove_reg_by_proc(peripheral);
401
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700402 driver->feature[peripheral].rcvd_feature_mask = 1;
403
404 for (i = 0; i < feature_mask_len && read_len < len; i++) {
405 feature_mask = *(uint8_t *)ptr;
406 driver->feature[peripheral].feature_mask[i] = feature_mask;
407 ptr += sizeof(uint8_t);
408 read_len += sizeof(uint8_t);
409
410 if (FEATURE_SUPPORTED(F_DIAG_LOG_ON_DEMAND_APPS))
411 driver->feature[peripheral].log_on_demand = 1;
412 if (FEATURE_SUPPORTED(F_DIAG_REQ_RSP_SUPPORT))
413 driver->feature[peripheral].separate_cmd_rsp = 1;
414 if (FEATURE_SUPPORTED(F_DIAG_APPS_HDLC_ENCODE))
415 process_hdlc_encoding_feature(peripheral);
Manoj Prabhu B571cf422017-08-08 19:01:41 +0530416 if (FEATURE_SUPPORTED(F_DIAG_PKT_HEADER_UNTAG))
417 process_upd_header_untagging_feature(peripheral);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700418 if (FEATURE_SUPPORTED(F_DIAG_STM))
419 enable_stm_feature(peripheral);
420 if (FEATURE_SUPPORTED(F_DIAG_MASK_CENTRALIZATION))
421 driver->feature[peripheral].mask_centralization = 1;
422 if (FEATURE_SUPPORTED(F_DIAG_PERIPHERAL_BUFFERING))
423 driver->feature[peripheral].peripheral_buffering = 1;
424 if (FEATURE_SUPPORTED(F_DIAG_SOCKETS_ENABLED))
425 enable_socket_feature(peripheral);
Manoj Prabhu B571cf422017-08-08 19:01:41 +0530426 if (FEATURE_SUPPORTED(F_DIAG_DIAGID_SUPPORT))
427 driver->feature[peripheral].diag_id_support = 1;
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +0530428 if (FEATURE_SUPPORTED(F_DIAG_PD_BUFFERING))
429 driver->feature[peripheral].pd_buffering = 1;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700430 }
431
432 process_socket_feature(peripheral);
433 process_log_on_demand_feature(peripheral);
434}
435
436static void process_last_event_report(uint8_t *buf, uint32_t len,
437 uint8_t peripheral)
438{
439 struct diag_ctrl_last_event_report *header = NULL;
440 uint8_t *ptr = buf;
441 uint8_t *temp = NULL;
442 uint32_t pkt_len = sizeof(uint32_t) + sizeof(uint16_t);
443 uint16_t event_size = 0;
444
445 if (!buf || peripheral >= NUM_PERIPHERALS || len != pkt_len)
446 return;
447
448 mutex_lock(&event_mask.lock);
449 header = (struct diag_ctrl_last_event_report *)ptr;
450 event_size = ((header->event_last_id / 8) + 1);
451 if (event_size >= driver->event_mask_size) {
452 pr_debug("diag: In %s, receiving event mask size more that Apps can handle\n",
453 __func__);
454 temp = krealloc(driver->event_mask->ptr, event_size,
455 GFP_KERNEL);
456 if (!temp) {
457 pr_err("diag: In %s, unable to reallocate event mask to support events from %d\n",
458 __func__, peripheral);
459 goto err;
460 }
461 driver->event_mask->ptr = temp;
462 driver->event_mask_size = event_size;
463 }
464
465 driver->num_event_id[peripheral] = header->event_last_id;
466 if (header->event_last_id > driver->last_event_id)
467 driver->last_event_id = header->event_last_id;
468err:
469 mutex_unlock(&event_mask.lock);
470}
471
472static void process_log_range_report(uint8_t *buf, uint32_t len,
473 uint8_t peripheral)
474{
475 int i;
476 int read_len = 0;
477 int header_len = sizeof(struct diag_ctrl_log_range_report);
478 uint8_t *ptr = buf;
479 struct diag_ctrl_log_range_report *header = NULL;
480 struct diag_ctrl_log_range *log_range = NULL;
481 struct diag_log_mask_t *mask_ptr = NULL;
482
483 if (!buf || peripheral >= NUM_PERIPHERALS || len < 0)
484 return;
485
486 header = (struct diag_ctrl_log_range_report *)ptr;
487 ptr += header_len;
488 /* Don't account for pkt_id and length */
489 read_len += header_len - (2 * sizeof(uint32_t));
490
491 driver->num_equip_id[peripheral] = header->num_ranges;
492 for (i = 0; i < header->num_ranges && read_len < len; i++) {
493 log_range = (struct diag_ctrl_log_range *)ptr;
494 ptr += sizeof(struct diag_ctrl_log_range);
495 read_len += sizeof(struct diag_ctrl_log_range);
496
497 if (log_range->equip_id >= MAX_EQUIP_ID) {
498 pr_err("diag: receiving log equip id %d more than supported equip id: %d from peripheral: %d\n",
499 log_range->equip_id, MAX_EQUIP_ID, peripheral);
500 continue;
501 }
502 mask_ptr = (struct diag_log_mask_t *)log_mask.ptr;
503 mask_ptr = &mask_ptr[log_range->equip_id];
504
505 mutex_lock(&(mask_ptr->lock));
506 mask_ptr->num_items = log_range->num_items;
507 mask_ptr->range = LOG_ITEMS_TO_SIZE(log_range->num_items);
508 mutex_unlock(&(mask_ptr->lock));
509 }
510}
511
512static int update_msg_mask_tbl_entry(struct diag_msg_mask_t *mask,
513 struct diag_ssid_range_t *range)
514{
515 uint32_t temp_range;
516
517 if (!mask || !range)
518 return -EIO;
519 if (range->ssid_last < range->ssid_first) {
520 pr_err("diag: In %s, invalid ssid range, first: %d, last: %d\n",
521 __func__, range->ssid_first, range->ssid_last);
522 return -EINVAL;
523 }
524 if (range->ssid_last >= mask->ssid_last) {
525 temp_range = range->ssid_last - mask->ssid_first + 1;
526 mask->ssid_last = range->ssid_last;
527 mask->range = temp_range;
528 }
529
530 return 0;
531}
532
533static void process_ssid_range_report(uint8_t *buf, uint32_t len,
534 uint8_t peripheral)
535{
536 int i;
537 int j;
538 int read_len = 0;
539 int found = 0;
540 int new_size = 0;
541 int err = 0;
542 struct diag_ctrl_ssid_range_report *header = NULL;
543 struct diag_ssid_range_t *ssid_range = NULL;
544 int header_len = sizeof(struct diag_ctrl_ssid_range_report);
545 struct diag_msg_mask_t *mask_ptr = NULL;
546 uint8_t *ptr = buf;
547 uint8_t *temp = NULL;
548 uint32_t min_len = header_len - sizeof(struct diag_ctrl_pkt_header_t);
549
550 if (!buf || peripheral >= NUM_PERIPHERALS || len < min_len)
551 return;
552
553 header = (struct diag_ctrl_ssid_range_report *)ptr;
554 ptr += header_len;
555 /* Don't account for pkt_id and length */
556 read_len += header_len - (2 * sizeof(uint32_t));
557
Gopikrishna Mogasati9a44d8d2017-05-05 16:04:35 +0530558 mutex_lock(&driver->msg_mask_lock);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700559 driver->max_ssid_count[peripheral] = header->count;
560 for (i = 0; i < header->count && read_len < len; i++) {
561 ssid_range = (struct diag_ssid_range_t *)ptr;
562 ptr += sizeof(struct diag_ssid_range_t);
563 read_len += sizeof(struct diag_ssid_range_t);
564 mask_ptr = (struct diag_msg_mask_t *)msg_mask.ptr;
565 found = 0;
566 for (j = 0; j < driver->msg_mask_tbl_count; j++, mask_ptr++) {
567 if (mask_ptr->ssid_first != ssid_range->ssid_first)
568 continue;
569 mutex_lock(&mask_ptr->lock);
570 err = update_msg_mask_tbl_entry(mask_ptr, ssid_range);
571 mutex_unlock(&mask_ptr->lock);
572 if (err == -ENOMEM) {
573 pr_err("diag: In %s, unable to increase the msg mask table range\n",
574 __func__);
575 }
576 found = 1;
577 break;
578 }
579
580 if (found)
581 continue;
582
583 new_size = (driver->msg_mask_tbl_count + 1) *
584 sizeof(struct diag_msg_mask_t);
585 temp = krealloc(msg_mask.ptr, new_size, GFP_KERNEL);
586 if (!temp) {
587 pr_err("diag: In %s, Unable to add new ssid table to msg mask, ssid first: %d, last: %d\n",
588 __func__, ssid_range->ssid_first,
589 ssid_range->ssid_last);
590 continue;
591 }
592 msg_mask.ptr = temp;
593 err = diag_create_msg_mask_table_entry(mask_ptr, ssid_range);
594 if (err) {
595 pr_err("diag: In %s, Unable to create a new msg mask table entry, first: %d last: %d err: %d\n",
596 __func__, ssid_range->ssid_first,
597 ssid_range->ssid_last, err);
598 continue;
599 }
600 driver->msg_mask_tbl_count += 1;
601 }
Gopikrishna Mogasati9a44d8d2017-05-05 16:04:35 +0530602 mutex_unlock(&driver->msg_mask_lock);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700603}
604
605static void diag_build_time_mask_update(uint8_t *buf,
606 struct diag_ssid_range_t *range)
607{
608 int i;
609 int j;
610 int num_items = 0;
611 int err = 0;
612 int found = 0;
613 int new_size = 0;
614 uint8_t *temp = NULL;
615 uint32_t *mask_ptr = (uint32_t *)buf;
616 uint32_t *dest_ptr = NULL;
617 struct diag_msg_mask_t *build_mask = NULL;
618
619 if (!range || !buf)
620 return;
621
622 if (range->ssid_last < range->ssid_first) {
623 pr_err("diag: In %s, invalid ssid range, first: %d, last: %d\n",
624 __func__, range->ssid_first, range->ssid_last);
625 return;
626 }
Gopikrishna Mogasati9a44d8d2017-05-05 16:04:35 +0530627 mutex_lock(&driver->msg_mask_lock);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700628 build_mask = (struct diag_msg_mask_t *)(driver->build_time_mask->ptr);
629 num_items = range->ssid_last - range->ssid_first + 1;
630
Gopikrishna Mogasati9a44d8d2017-05-05 16:04:35 +0530631 for (i = 0; i < driver->bt_msg_mask_tbl_count; i++, build_mask++) {
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700632 if (build_mask->ssid_first != range->ssid_first)
633 continue;
634 found = 1;
635 mutex_lock(&build_mask->lock);
636 err = update_msg_mask_tbl_entry(build_mask, range);
637 if (err == -ENOMEM) {
638 pr_err("diag: In %s, unable to increase the msg build mask table range\n",
639 __func__);
640 }
641 dest_ptr = build_mask->ptr;
642 for (j = 0; j < build_mask->range; j++, mask_ptr++, dest_ptr++)
643 *(uint32_t *)dest_ptr |= *mask_ptr;
644 mutex_unlock(&build_mask->lock);
645 break;
646 }
647
648 if (found)
649 goto end;
Gopikrishna Mogasati9a44d8d2017-05-05 16:04:35 +0530650 new_size = (driver->bt_msg_mask_tbl_count + 1) *
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700651 sizeof(struct diag_msg_mask_t);
652 temp = krealloc(driver->build_time_mask->ptr, new_size, GFP_KERNEL);
653 if (!temp) {
654 pr_err("diag: In %s, unable to create a new entry for build time mask\n",
655 __func__);
656 goto end;
657 }
658 driver->build_time_mask->ptr = temp;
659 err = diag_create_msg_mask_table_entry(build_mask, range);
660 if (err) {
661 pr_err("diag: In %s, Unable to create a new msg mask table entry, err: %d\n",
662 __func__, err);
663 goto end;
664 }
Gopikrishna Mogasati9a44d8d2017-05-05 16:04:35 +0530665 driver->bt_msg_mask_tbl_count += 1;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700666end:
Gopikrishna Mogasati9a44d8d2017-05-05 16:04:35 +0530667 mutex_unlock(&driver->msg_mask_lock);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700668 return;
669}
670
671static void process_build_mask_report(uint8_t *buf, uint32_t len,
672 uint8_t peripheral)
673{
674 int i;
675 int read_len = 0;
676 int num_items = 0;
677 int header_len = sizeof(struct diag_ctrl_build_mask_report);
678 uint8_t *ptr = buf;
679 struct diag_ctrl_build_mask_report *header = NULL;
680 struct diag_ssid_range_t *range = NULL;
681
682 if (!buf || peripheral >= NUM_PERIPHERALS || len < header_len)
683 return;
684
685 header = (struct diag_ctrl_build_mask_report *)ptr;
686 ptr += header_len;
687 /* Don't account for pkt_id and length */
688 read_len += header_len - (2 * sizeof(uint32_t));
689
690 for (i = 0; i < header->count && read_len < len; i++) {
691 range = (struct diag_ssid_range_t *)ptr;
692 ptr += sizeof(struct diag_ssid_range_t);
693 read_len += sizeof(struct diag_ssid_range_t);
694 num_items = range->ssid_last - range->ssid_first + 1;
695 diag_build_time_mask_update(ptr, range);
696 ptr += num_items * sizeof(uint32_t);
697 read_len += num_items * sizeof(uint32_t);
698 }
699}
700
Manoj Prabhu B90e1f502017-11-02 20:01:45 +0530701int diag_add_diag_id_to_list(uint8_t diag_id, char *process_name,
702 uint8_t pd_val, uint8_t peripheral)
Sreelakshmi Gownipalli8d477d32017-02-08 19:49:06 -0800703{
704 struct diag_id_tbl_t *new_item = NULL;
705
706 if (!process_name || diag_id == 0)
707 return -EINVAL;
708
709 new_item = kzalloc(sizeof(struct diag_id_tbl_t), GFP_KERNEL);
710 if (!new_item)
711 return -ENOMEM;
712 kmemleak_not_leak(new_item);
Chris Lewbf225832017-04-21 10:45:53 -0700713 new_item->process_name = kzalloc(strlen(process_name) + 1, GFP_KERNEL);
Sreelakshmi Gownipalli8d477d32017-02-08 19:49:06 -0800714 if (!new_item->process_name) {
715 kfree(new_item);
716 new_item = NULL;
717 return -ENOMEM;
718 }
719 kmemleak_not_leak(new_item->process_name);
720 new_item->diag_id = diag_id;
Manoj Prabhu B90e1f502017-11-02 20:01:45 +0530721 new_item->pd_val = pd_val;
722 new_item->peripheral = peripheral;
Sreelakshmi Gownipalli8d477d32017-02-08 19:49:06 -0800723 strlcpy(new_item->process_name, process_name, strlen(process_name) + 1);
724 INIT_LIST_HEAD(&new_item->link);
725 mutex_lock(&driver->diag_id_mutex);
726 list_add_tail(&new_item->link, &driver->diag_id_list);
727 mutex_unlock(&driver->diag_id_mutex);
728 return 0;
729}
730
731int diag_query_diag_id(char *process_name, uint8_t *diag_id)
732{
733 struct list_head *start;
734 struct list_head *temp;
735 struct diag_id_tbl_t *item = NULL;
736
737 if (!process_name || !diag_id)
738 return -EINVAL;
739
740 mutex_lock(&driver->diag_id_mutex);
741 list_for_each_safe(start, temp, &driver->diag_id_list) {
742 item = list_entry(start, struct diag_id_tbl_t, link);
743 if (strcmp(item->process_name, process_name) == 0) {
744 *diag_id = item->diag_id;
745 mutex_unlock(&driver->diag_id_mutex);
746 return 1;
747 }
748 }
749 mutex_unlock(&driver->diag_id_mutex);
750 return 0;
751}
752static void process_diagid(uint8_t *buf, uint32_t len,
753 uint8_t peripheral)
754{
755 struct diag_ctrl_diagid *header = NULL;
756 struct diag_ctrl_diagid ctrl_pkt;
Manoj Prabhu B90e1f502017-11-02 20:01:45 +0530757 struct diagfwd_info *fwd_info = NULL;
Sreelakshmi Gownipalli8d477d32017-02-08 19:49:06 -0800758 char *process_name = NULL;
759 int err = 0;
Manoj Prabhu B90e1f502017-11-02 20:01:45 +0530760 int pd_val;
Manoj Prabhu Bd7962422017-09-14 14:14:08 +0530761 char *root_str = NULL;
Sreelakshmi Gownipalli8d477d32017-02-08 19:49:06 -0800762 uint8_t local_diag_id = 0;
Manoj Prabhu B90e1f502017-11-02 20:01:45 +0530763 uint8_t new_request = 0, i = 0, ch_type = 0;
Sreelakshmi Gownipalli8d477d32017-02-08 19:49:06 -0800764
765 if (!buf || len == 0 || peripheral >= NUM_PERIPHERALS)
766 return;
Manoj Prabhu B571cf422017-08-08 19:01:41 +0530767
Sreelakshmi Gownipalli8d477d32017-02-08 19:49:06 -0800768 header = (struct diag_ctrl_diagid *)buf;
769 process_name = (char *)&header->process_name;
770 if (diag_query_diag_id(process_name, &local_diag_id))
771 ctrl_pkt.diag_id = local_diag_id;
772 else {
773 diag_id++;
Manoj Prabhu B571cf422017-08-08 19:01:41 +0530774 new_request = 1;
Manoj Prabhu B90e1f502017-11-02 20:01:45 +0530775 pd_val = diag_query_pd(process_name);
776 if (pd_val < 0)
777 return;
778 diag_add_diag_id_to_list(diag_id, process_name,
779 pd_val, peripheral);
780 ctrl_pkt.diag_id = diag_id;
Sreelakshmi Gownipalli8d477d32017-02-08 19:49:06 -0800781 }
Manoj Prabhu Bd7962422017-09-14 14:14:08 +0530782 root_str = strnstr(process_name, DIAG_ID_ROOT_STRING,
783 strlen(process_name));
Manoj Prabhu B571cf422017-08-08 19:01:41 +0530784
785 if (new_request) {
Manoj Prabhu B90e1f502017-11-02 20:01:45 +0530786 for (ch_type = 0; ch_type < NUM_TYPES; ch_type++) {
787 if (ch_type == TYPE_DCI ||
788 ch_type == TYPE_DCI_CMD)
789 continue;
790 fwd_info = &peripheral_info[ch_type][peripheral];
791 fwd_info->num_pd++;
Manoj Prabhu Bd7962422017-09-14 14:14:08 +0530792
Manoj Prabhu B90e1f502017-11-02 20:01:45 +0530793 if (root_str) {
794 fwd_info->root_diag_id.diagid_val =
795 ctrl_pkt.diag_id;
796 fwd_info->root_diag_id.reg_str =
797 process_name;
798 fwd_info->root_diag_id.pd = pd_val;
799 } else {
800 i = fwd_info->num_pd - 2;
801 if (i >= 0 && i < MAX_PERIPHERAL_UPD) {
802 fwd_info->upd_diag_id[i].diagid_val =
803 ctrl_pkt.diag_id;
804 fwd_info->upd_diag_id[i].reg_str =
805 process_name;
806 fwd_info->upd_diag_id[i].pd = pd_val;
807 }
808 }
Manoj Prabhu Bd7962422017-09-14 14:14:08 +0530809 }
Manoj Prabhu B571cf422017-08-08 19:01:41 +0530810 }
811
Manoj Prabhu B571cf422017-08-08 19:01:41 +0530812 DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
813 "diag: peripheral = %d: diag_id string = %s,diag_id = %d\n",
814 peripheral, process_name, ctrl_pkt.diag_id);
815
Sreelakshmi Gownipalli8d477d32017-02-08 19:49:06 -0800816 ctrl_pkt.pkt_id = DIAG_CTRL_MSG_DIAGID;
817 ctrl_pkt.version = 1;
818 strlcpy((char *)&ctrl_pkt.process_name, process_name,
819 strlen(process_name) + 1);
820 ctrl_pkt.len = sizeof(ctrl_pkt.diag_id) + sizeof(ctrl_pkt.version) +
821 strlen(process_name) + 1;
822 err = diagfwd_write(peripheral, TYPE_CNTL, &ctrl_pkt, ctrl_pkt.len +
823 sizeof(ctrl_pkt.pkt_id) + sizeof(ctrl_pkt.len));
824 if (err && err != -ENODEV) {
Manoj Prabhu B571cf422017-08-08 19:01:41 +0530825 pr_err("diag: Unable to send diag id ctrl packet to peripheral %d, err: %d\n",
Sreelakshmi Gownipalli8d477d32017-02-08 19:49:06 -0800826 peripheral, err);
Manoj Prabhu B571cf422017-08-08 19:01:41 +0530827 } else {
Manoj Prabhu B9553b462017-09-25 09:59:47 +0530828 /*
829 * Masks (F3, logs and events) will be sent to
830 * peripheral immediately following feature mask update only
831 * if diag_id support is not present or
832 * diag_id support is present and diag_id has been sent to
833 * peripheral.
834 * With diag_id being sent now, mask will be updated
835 * to peripherals.
836 */
837 if (root_str) {
838 driver->diag_id_sent[peripheral] = 1;
Manoj Prabhu B9ac639f2017-11-21 21:37:11 +0530839 queue_work(driver->cntl_wq, &driver->mask_update_work);
Manoj Prabhu B9553b462017-09-25 09:59:47 +0530840 }
Manoj Prabhu B90e1f502017-11-02 20:01:45 +0530841 fwd_info = &peripheral_info[TYPE_DATA][peripheral];
842 diagfwd_buffers_init(fwd_info);
Manoj Prabhu Bd7962422017-09-14 14:14:08 +0530843 DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
844 "diag: diag_id sent = %d to peripheral = %d with diag_id = %d for %s :\n",
845 driver->diag_id_sent[peripheral], peripheral,
846 ctrl_pkt.diag_id, process_name);
Sreelakshmi Gownipalli8d477d32017-02-08 19:49:06 -0800847 }
848}
849
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700850void diag_cntl_process_read_data(struct diagfwd_info *p_info, void *buf,
851 int len)
852{
853 uint32_t read_len = 0;
854 uint32_t header_len = sizeof(struct diag_ctrl_pkt_header_t);
855 uint8_t *ptr = buf;
856 struct diag_ctrl_pkt_header_t *ctrl_pkt = NULL;
857
858 if (!buf || len <= 0 || !p_info)
859 return;
860
861 if (reg_dirty & PERIPHERAL_MASK(p_info->peripheral)) {
862 pr_err_ratelimited("diag: dropping command registration from peripheral %d\n",
863 p_info->peripheral);
864 return;
865 }
866
867 while (read_len + header_len < len) {
868 ctrl_pkt = (struct diag_ctrl_pkt_header_t *)ptr;
869 switch (ctrl_pkt->pkt_id) {
870 case DIAG_CTRL_MSG_REG:
871 process_command_registration(ptr, ctrl_pkt->len,
872 p_info->peripheral);
873 break;
874 case DIAG_CTRL_MSG_DEREG:
875 process_command_deregistration(ptr, ctrl_pkt->len,
876 p_info->peripheral);
877 break;
878 case DIAG_CTRL_MSG_FEATURE:
879 process_incoming_feature_mask(ptr, ctrl_pkt->len,
880 p_info->peripheral);
881 break;
882 case DIAG_CTRL_MSG_LAST_EVENT_REPORT:
883 process_last_event_report(ptr, ctrl_pkt->len,
884 p_info->peripheral);
885 break;
886 case DIAG_CTRL_MSG_LOG_RANGE_REPORT:
887 process_log_range_report(ptr, ctrl_pkt->len,
888 p_info->peripheral);
889 break;
890 case DIAG_CTRL_MSG_SSID_RANGE_REPORT:
891 process_ssid_range_report(ptr, ctrl_pkt->len,
892 p_info->peripheral);
893 break;
894 case DIAG_CTRL_MSG_BUILD_MASK_REPORT:
895 process_build_mask_report(ptr, ctrl_pkt->len,
896 p_info->peripheral);
897 break;
898 case DIAG_CTRL_MSG_PD_STATUS:
899 process_pd_status(ptr, ctrl_pkt->len,
900 p_info->peripheral);
901 break;
Sreelakshmi Gownipalli8d477d32017-02-08 19:49:06 -0800902 case DIAG_CTRL_MSG_DIAGID:
903 process_diagid(ptr, ctrl_pkt->len,
904 p_info->peripheral);
905 break;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700906 default:
907 pr_debug("diag: Control packet %d not supported\n",
908 ctrl_pkt->pkt_id);
909 }
910 ptr += header_len + ctrl_pkt->len;
911 read_len += header_len + ctrl_pkt->len;
912 }
913}
914
915static int diag_compute_real_time(int idx)
916{
917 int real_time = MODE_REALTIME;
918
919 if (driver->proc_active_mask == 0) {
920 /*
921 * There are no DCI or Memory Device processes. Diag should
922 * be in Real Time mode irrespective of USB connection
923 */
924 real_time = MODE_REALTIME;
925 } else if (driver->proc_rt_vote_mask[idx] & driver->proc_active_mask) {
926 /*
927 * Atleast one process is alive and is voting for Real Time
928 * data - Diag should be in real time mode irrespective of USB
929 * connection.
930 */
931 real_time = MODE_REALTIME;
932 } else if (driver->usb_connected) {
933 /*
934 * If USB is connected, check individual process. If Memory
935 * Device Mode is active, set the mode requested by Memory
936 * Device process. Set to realtime mode otherwise.
937 */
938 if ((driver->proc_rt_vote_mask[idx] &
939 DIAG_PROC_MEMORY_DEVICE) == 0)
940 real_time = MODE_NONREALTIME;
941 else
942 real_time = MODE_REALTIME;
943 } else {
944 /*
945 * We come here if USB is not connected and the active
946 * processes are voting for Non realtime mode.
947 */
948 real_time = MODE_NONREALTIME;
949 }
950 return real_time;
951}
952
953static void diag_create_diag_mode_ctrl_pkt(unsigned char *dest_buf,
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +0530954 uint8_t diag_id, int real_time)
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700955{
956 struct diag_ctrl_msg_diagmode diagmode;
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +0530957 struct diag_ctrl_msg_diagmode_v2 diagmode_v2;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700958 int msg_size = sizeof(struct diag_ctrl_msg_diagmode);
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +0530959 int msg_size_2 = sizeof(struct diag_ctrl_msg_diagmode_v2);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700960
961 if (!dest_buf)
962 return;
963
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +0530964 if (diag_id) {
965 diagmode_v2.ctrl_pkt_id = DIAG_CTRL_MSG_DIAGMODE;
966 diagmode_v2.ctrl_pkt_data_len = DIAG_MODE_PKT_LEN_V2;
967 diagmode_v2.version = 2;
968 diagmode_v2.sleep_vote = real_time ? 1 : 0;
969 /*
970 * 0 - Disables real-time logging (to prevent
971 * frequent APPS wake-ups, etc.).
972 * 1 - Enable real-time logging
973 */
974 diagmode_v2.real_time = real_time;
975 diagmode_v2.use_nrt_values = 0;
976 diagmode_v2.commit_threshold = 0;
977 diagmode_v2.sleep_threshold = 0;
978 diagmode_v2.sleep_time = 0;
979 diagmode_v2.drain_timer_val = 0;
980 diagmode_v2.event_stale_timer_val = 0;
981 diagmode_v2.diag_id = diag_id;
982 memcpy(dest_buf, &diagmode_v2, msg_size_2);
983 } else {
984 diagmode.ctrl_pkt_id = DIAG_CTRL_MSG_DIAGMODE;
985 diagmode.ctrl_pkt_data_len = DIAG_MODE_PKT_LEN;
986 diagmode.version = 1;
987 diagmode.sleep_vote = real_time ? 1 : 0;
988 /*
989 * 0 - Disables real-time logging (to prevent
990 * frequent APPS wake-ups, etc.).
991 * 1 - Enable real-time logging
992 */
993 diagmode.real_time = real_time;
994 diagmode.use_nrt_values = 0;
995 diagmode.commit_threshold = 0;
996 diagmode.sleep_threshold = 0;
997 diagmode.sleep_time = 0;
998 diagmode.drain_timer_val = 0;
999 diagmode.event_stale_timer_val = 0;
1000 memcpy(dest_buf, &diagmode, msg_size);
1001 }
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001002}
1003
1004void diag_update_proc_vote(uint16_t proc, uint8_t vote, int index)
1005{
1006 int i;
1007
1008 mutex_lock(&driver->real_time_mutex);
1009 if (vote)
1010 driver->proc_active_mask |= proc;
1011 else {
1012 driver->proc_active_mask &= ~proc;
1013 if (index == ALL_PROC) {
1014 for (i = 0; i < DIAG_NUM_PROC; i++)
1015 driver->proc_rt_vote_mask[i] |= proc;
1016 } else {
1017 driver->proc_rt_vote_mask[index] |= proc;
1018 }
1019 }
1020 mutex_unlock(&driver->real_time_mutex);
1021}
1022
1023void diag_update_real_time_vote(uint16_t proc, uint8_t real_time, int index)
1024{
1025 int i;
1026
1027 if (index >= DIAG_NUM_PROC) {
1028 pr_err("diag: In %s, invalid index %d\n", __func__, index);
1029 return;
1030 }
1031
1032 mutex_lock(&driver->real_time_mutex);
1033 if (index == ALL_PROC) {
1034 for (i = 0; i < DIAG_NUM_PROC; i++) {
1035 if (real_time)
1036 driver->proc_rt_vote_mask[i] |= proc;
1037 else
1038 driver->proc_rt_vote_mask[i] &= ~proc;
1039 }
1040 } else {
1041 if (real_time)
1042 driver->proc_rt_vote_mask[index] |= proc;
1043 else
1044 driver->proc_rt_vote_mask[index] &= ~proc;
1045 }
1046 mutex_unlock(&driver->real_time_mutex);
1047}
1048
1049
1050#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
1051static void diag_send_diag_mode_update_remote(int token, int real_time)
1052{
1053 unsigned char *buf = NULL;
1054 int err = 0;
1055 struct diag_dci_header_t dci_header;
1056 int dci_header_size = sizeof(struct diag_dci_header_t);
1057 int msg_size = sizeof(struct diag_ctrl_msg_diagmode);
1058 uint32_t write_len = 0;
1059
1060 if (token < 0 || token >= NUM_DCI_PROC) {
1061 pr_err("diag: Invalid remote device channel in %s, token: %d\n",
1062 __func__, token);
1063 return;
1064 }
1065
1066 if (real_time != MODE_REALTIME && real_time != MODE_NONREALTIME) {
1067 pr_err("diag: Invalid real time value in %s, type: %d\n",
1068 __func__, real_time);
1069 return;
1070 }
1071
1072 buf = dci_get_buffer_from_bridge(token);
1073 if (!buf) {
1074 pr_err("diag: In %s, unable to get dci buffers to write data\n",
1075 __func__);
1076 return;
1077 }
1078 /* Frame the DCI header */
1079 dci_header.start = CONTROL_CHAR;
1080 dci_header.version = 1;
1081 dci_header.length = msg_size + 1;
1082 dci_header.cmd_code = DCI_CONTROL_PKT_CODE;
1083
1084 memcpy(buf + write_len, &dci_header, dci_header_size);
1085 write_len += dci_header_size;
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05301086 diag_create_diag_mode_ctrl_pkt(buf + write_len, 0, real_time);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001087 write_len += msg_size;
1088 *(buf + write_len) = CONTROL_CHAR; /* End Terminator */
1089 write_len += sizeof(uint8_t);
1090 err = diagfwd_bridge_write(TOKEN_TO_BRIDGE(token), buf, write_len);
1091 if (err != write_len) {
1092 pr_err("diag: cannot send nrt mode ctrl pkt, err: %d\n", err);
1093 diagmem_free(driver, buf, dci_ops_tbl[token].mempool);
1094 } else {
1095 driver->real_time_mode[token + 1] = real_time;
1096 }
1097}
1098#else
1099static inline void diag_send_diag_mode_update_remote(int token, int real_time)
1100{
1101}
1102#endif
1103
1104#ifdef CONFIG_DIAG_OVER_USB
1105void diag_real_time_work_fn(struct work_struct *work)
1106{
1107 int temp_real_time = MODE_REALTIME, i, j;
1108 uint8_t send_update = 1;
1109
1110 /*
1111 * If any peripheral in the local processor is in either threshold or
1112 * circular buffering mode, don't send the real time mode control
1113 * packet.
1114 */
1115 for (i = 0; i < NUM_PERIPHERALS; i++) {
1116 if (!driver->feature[i].peripheral_buffering)
1117 continue;
1118 switch (driver->buffering_mode[i].mode) {
1119 case DIAG_BUFFERING_MODE_THRESHOLD:
1120 case DIAG_BUFFERING_MODE_CIRCULAR:
1121 send_update = 0;
1122 break;
1123 }
1124 }
1125
1126 mutex_lock(&driver->mode_lock);
1127 for (i = 0; i < DIAG_NUM_PROC; i++) {
1128 temp_real_time = diag_compute_real_time(i);
1129 if (temp_real_time == driver->real_time_mode[i]) {
1130 pr_debug("diag: did not update real time mode on proc %d, already in the req mode %d",
1131 i, temp_real_time);
1132 continue;
1133 }
1134
1135 if (i == DIAG_LOCAL_PROC) {
1136 if (!send_update) {
1137 pr_debug("diag: In %s, cannot send real time mode pkt since one of the periperhal is in buffering mode\n",
1138 __func__);
1139 break;
1140 }
1141 for (j = 0; j < NUM_PERIPHERALS; j++)
1142 diag_send_real_time_update(j,
1143 temp_real_time);
1144 } else {
1145 diag_send_diag_mode_update_remote(i - 1,
1146 temp_real_time);
1147 }
1148 }
1149 mutex_unlock(&driver->mode_lock);
1150
1151 if (driver->real_time_update_busy > 0)
1152 driver->real_time_update_busy--;
1153}
1154#else
1155void diag_real_time_work_fn(struct work_struct *work)
1156{
1157 int temp_real_time = MODE_REALTIME, i, j;
1158
1159 for (i = 0; i < DIAG_NUM_PROC; i++) {
1160 if (driver->proc_active_mask == 0) {
1161 /*
1162 * There are no DCI or Memory Device processes.
1163 * Diag should be in Real Time mode.
1164 */
1165 temp_real_time = MODE_REALTIME;
1166 } else if (!(driver->proc_rt_vote_mask[i] &
1167 driver->proc_active_mask)) {
1168 /* No active process is voting for real time mode */
1169 temp_real_time = MODE_NONREALTIME;
1170 }
1171 if (temp_real_time == driver->real_time_mode[i]) {
1172 pr_debug("diag: did not update real time mode on proc %d, already in the req mode %d",
1173 i, temp_real_time);
1174 continue;
1175 }
1176
1177 if (i == DIAG_LOCAL_PROC) {
1178 for (j = 0; j < NUM_PERIPHERALS; j++)
1179 diag_send_real_time_update(
1180 j, temp_real_time);
1181 } else {
1182 diag_send_diag_mode_update_remote(i - 1,
1183 temp_real_time);
1184 }
1185 }
1186
1187 if (driver->real_time_update_busy > 0)
1188 driver->real_time_update_busy--;
1189}
1190#endif
1191
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05301192static int __diag_send_real_time_update(uint8_t peripheral, int real_time,
1193 uint8_t diag_id)
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001194{
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05301195 char buf[sizeof(struct diag_ctrl_msg_diagmode_v2)];
1196 int msg_size = 0;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001197 int err = 0;
1198
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05301199 if (peripheral >= NUM_PERIPHERALS) {
1200 pr_err("diag: In %s, invalid peripheral %d\n", __func__,
1201 peripheral);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001202 return -EINVAL;
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05301203 }
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001204
1205 if (!driver->diagfwd_cntl[peripheral] ||
1206 !driver->diagfwd_cntl[peripheral]->ch_open) {
1207 pr_debug("diag: In %s, control channel is not open, p: %d\n",
1208 __func__, peripheral);
1209 return err;
1210 }
1211
1212 if (real_time != MODE_NONREALTIME && real_time != MODE_REALTIME) {
1213 pr_err("diag: In %s, invalid real time mode %d, peripheral: %d\n",
1214 __func__, real_time, peripheral);
1215 return -EINVAL;
1216 }
1217
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05301218 msg_size = (diag_id ? sizeof(struct diag_ctrl_msg_diagmode_v2) :
1219 sizeof(struct diag_ctrl_msg_diagmode));
1220
1221 diag_create_diag_mode_ctrl_pkt(buf, diag_id, real_time);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001222
1223 mutex_lock(&driver->diag_cntl_mutex);
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05301224
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001225 err = diagfwd_write(peripheral, TYPE_CNTL, buf, msg_size);
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05301226
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001227 if (err && err != -ENODEV) {
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05301228 pr_err("diag: In %s, unable to write, peripheral: %d, type: %d, len: %d, err: %d\n",
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001229 __func__, peripheral, TYPE_CNTL,
1230 msg_size, err);
1231 } else {
1232 driver->real_time_mode[DIAG_LOCAL_PROC] = real_time;
1233 }
1234
1235 mutex_unlock(&driver->diag_cntl_mutex);
1236
1237 return err;
1238}
1239
1240int diag_send_real_time_update(uint8_t peripheral, int real_time)
1241{
1242 int i;
1243
1244 for (i = 0; i < NUM_PERIPHERALS; i++) {
1245 if (!driver->buffering_flag[i])
1246 continue;
1247 /*
1248 * One of the peripherals is in buffering mode. Don't set
1249 * the RT value.
1250 */
1251 return -EINVAL;
1252 }
1253
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05301254 return __diag_send_real_time_update(peripheral, real_time, 0);
1255}
1256
1257void diag_map_pd_to_diagid(uint8_t pd, uint8_t *diag_id, int *peripheral)
1258{
1259 if (!diag_search_diagid_by_pd(pd, (void *)diag_id,
1260 (void *)peripheral)) {
1261 *diag_id = 0;
1262 if ((pd >= 0) && pd < NUM_PERIPHERALS)
1263 *peripheral = pd;
1264 else
1265 *peripheral = -EINVAL;
1266 }
1267
1268 if (*peripheral >= 0)
1269 if (!driver->feature[*peripheral].pd_buffering)
1270 *diag_id = 0;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001271}
1272
1273int diag_send_peripheral_buffering_mode(struct diag_buffering_mode_t *params)
1274{
1275 int err = 0;
1276 int mode = MODE_REALTIME;
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05301277 int peripheral = 0;
1278 uint8_t diag_id = 0;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001279
1280 if (!params)
1281 return -EIO;
1282
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05301283 diag_map_pd_to_diagid(params->peripheral,
1284 &diag_id, &peripheral);
1285
1286 if ((peripheral < 0) ||
1287 peripheral >= NUM_PERIPHERALS) {
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001288 pr_err("diag: In %s, invalid peripheral %d\n", __func__,
1289 peripheral);
1290 return -EINVAL;
1291 }
1292
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05301293 if (!driver->buffering_flag[params->peripheral]) {
1294 pr_err("diag: In %s, buffering flag not set for %d\n", __func__,
1295 params->peripheral);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001296 return -EINVAL;
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05301297 }
1298
1299 if (!driver->feature[peripheral].peripheral_buffering) {
1300 pr_err("diag: In %s, peripheral %d doesn't support buffering\n",
1301 __func__, peripheral);
1302 return -EIO;
1303 }
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001304
1305 switch (params->mode) {
1306 case DIAG_BUFFERING_MODE_STREAMING:
1307 mode = MODE_REALTIME;
1308 break;
1309 case DIAG_BUFFERING_MODE_THRESHOLD:
1310 case DIAG_BUFFERING_MODE_CIRCULAR:
1311 mode = MODE_NONREALTIME;
1312 break;
1313 default:
1314 pr_err("diag: In %s, invalid tx mode %d\n", __func__,
1315 params->mode);
1316 return -EINVAL;
1317 }
1318
1319 if (!driver->feature[peripheral].peripheral_buffering) {
1320 pr_debug("diag: In %s, peripheral %d doesn't support buffering\n",
1321 __func__, peripheral);
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05301322 driver->buffering_flag[params->peripheral] = 0;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001323 return -EIO;
1324 }
1325
1326 /*
1327 * Perform sanity on watermark values. These values must be
1328 * checked irrespective of the buffering mode.
1329 */
1330 if (((params->high_wm_val > DIAG_MAX_WM_VAL) ||
1331 (params->low_wm_val > DIAG_MAX_WM_VAL)) ||
1332 (params->low_wm_val > params->high_wm_val) ||
1333 ((params->low_wm_val == params->high_wm_val) &&
1334 (params->low_wm_val != DIAG_MIN_WM_VAL))) {
1335 pr_err("diag: In %s, invalid watermark values, high: %d, low: %d, peripheral: %d\n",
1336 __func__, params->high_wm_val, params->low_wm_val,
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05301337 params->peripheral);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001338 return -EINVAL;
1339 }
1340
1341 mutex_lock(&driver->mode_lock);
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05301342 err = diag_send_buffering_tx_mode_pkt(peripheral, diag_id, params);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001343 if (err) {
1344 pr_err("diag: In %s, unable to send buffering mode packet to peripheral %d, err: %d\n",
1345 __func__, peripheral, err);
1346 goto fail;
1347 }
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05301348 err = diag_send_buffering_wm_values(peripheral, diag_id, params);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001349 if (err) {
1350 pr_err("diag: In %s, unable to send buffering wm value packet to peripheral %d, err: %d\n",
1351 __func__, peripheral, err);
1352 goto fail;
1353 }
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05301354 err = __diag_send_real_time_update(peripheral, mode, diag_id);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001355 if (err) {
1356 pr_err("diag: In %s, unable to send mode update to peripheral %d, mode: %d, err: %d\n",
1357 __func__, peripheral, mode, err);
1358 goto fail;
1359 }
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05301360 driver->buffering_mode[params->peripheral].peripheral =
1361 params->peripheral;
1362 driver->buffering_mode[params->peripheral].mode =
1363 params->mode;
1364 driver->buffering_mode[params->peripheral].low_wm_val =
1365 params->low_wm_val;
1366 driver->buffering_mode[params->peripheral].high_wm_val =
1367 params->high_wm_val;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001368 if (params->mode == DIAG_BUFFERING_MODE_STREAMING)
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05301369 driver->buffering_flag[params->peripheral] = 0;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001370fail:
1371 mutex_unlock(&driver->mode_lock);
1372 return err;
1373}
1374
1375int diag_send_stm_state(uint8_t peripheral, uint8_t stm_control_data)
1376{
1377 struct diag_ctrl_msg_stm stm_msg;
1378 int msg_size = sizeof(struct diag_ctrl_msg_stm);
1379 int err = 0;
1380
1381 if (peripheral >= NUM_PERIPHERALS)
1382 return -EIO;
1383
1384 if (!driver->diagfwd_cntl[peripheral] ||
1385 !driver->diagfwd_cntl[peripheral]->ch_open) {
1386 pr_debug("diag: In %s, control channel is not open, p: %d\n",
1387 __func__, peripheral);
1388 return -ENODEV;
1389 }
1390
1391 if (driver->feature[peripheral].stm_support == DISABLE_STM)
1392 return -EINVAL;
1393
1394 stm_msg.ctrl_pkt_id = 21;
1395 stm_msg.ctrl_pkt_data_len = 5;
1396 stm_msg.version = 1;
1397 stm_msg.control_data = stm_control_data;
1398 err = diagfwd_write(peripheral, TYPE_CNTL, &stm_msg, msg_size);
1399 if (err && err != -ENODEV) {
1400 pr_err("diag: In %s, unable to write to socket, peripheral: %d, type: %d, len: %d, err: %d\n",
1401 __func__, peripheral, TYPE_CNTL,
1402 msg_size, err);
1403 }
1404
1405 return err;
1406}
1407
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05301408int diag_send_peripheral_drain_immediate(uint8_t pd,
1409 uint8_t diag_id, int peripheral)
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001410{
1411 int err = 0;
1412 struct diag_ctrl_drain_immediate ctrl_pkt;
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05301413 struct diag_ctrl_drain_immediate_v2 ctrl_pkt_v2;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001414
1415 if (!driver->feature[peripheral].peripheral_buffering) {
1416 pr_debug("diag: In %s, peripheral %d doesn't support buffering\n",
1417 __func__, peripheral);
1418 return -EINVAL;
1419 }
1420
1421 if (!driver->diagfwd_cntl[peripheral] ||
1422 !driver->diagfwd_cntl[peripheral]->ch_open) {
1423 pr_debug("diag: In %s, control channel is not open, p: %d\n",
1424 __func__, peripheral);
1425 return -ENODEV;
1426 }
1427
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05301428 if (diag_id && driver->feature[peripheral].pd_buffering) {
1429 ctrl_pkt_v2.pkt_id = DIAG_CTRL_MSG_PERIPHERAL_BUF_DRAIN_IMM;
1430 /*
1431 * The length of the ctrl pkt is size of version,
1432 * diag_id and stream id
1433 */
1434 ctrl_pkt_v2.len = sizeof(uint32_t) + (2 * sizeof(uint8_t));
1435 ctrl_pkt_v2.version = 2;
1436 ctrl_pkt_v2.diag_id = diag_id;
1437 ctrl_pkt_v2.stream_id = 1;
1438 err = diagfwd_write(peripheral, TYPE_CNTL, &ctrl_pkt_v2,
1439 sizeof(ctrl_pkt_v2));
1440 if (err && err != -ENODEV) {
1441 pr_err("diag: Unable to send drain immediate ctrl packet to peripheral %d, err: %d\n",
1442 peripheral, err);
1443 }
1444 } else {
1445 ctrl_pkt.pkt_id = DIAG_CTRL_MSG_PERIPHERAL_BUF_DRAIN_IMM;
1446 /*
1447 * The length of the ctrl pkt is
1448 * size of version and stream id
1449 */
1450 ctrl_pkt.len = sizeof(uint32_t) + sizeof(uint8_t);
1451 ctrl_pkt.version = 1;
1452 ctrl_pkt.stream_id = 1;
1453 err = diagfwd_write(peripheral, TYPE_CNTL, &ctrl_pkt,
1454 sizeof(ctrl_pkt));
1455 if (err && err != -ENODEV) {
1456 pr_err("diag: Unable to send drain immediate ctrl packet to peripheral %d, err: %d\n",
1457 peripheral, err);
1458 }
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001459 }
1460
1461 return err;
1462}
1463
1464int diag_send_buffering_tx_mode_pkt(uint8_t peripheral,
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05301465 uint8_t diag_id, struct diag_buffering_mode_t *params)
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001466{
1467 int err = 0;
1468 struct diag_ctrl_peripheral_tx_mode ctrl_pkt;
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05301469 struct diag_ctrl_peripheral_tx_mode_v2 ctrl_pkt_v2;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001470
1471 if (!params)
1472 return -EIO;
1473
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05301474 if (peripheral >= NUM_PERIPHERALS) {
1475 pr_err("diag: In %s, invalid peripheral %d\n", __func__,
1476 peripheral);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001477 return -EINVAL;
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05301478 }
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001479
1480 if (!driver->feature[peripheral].peripheral_buffering) {
1481 pr_debug("diag: In %s, peripheral %d doesn't support buffering\n",
1482 __func__, peripheral);
1483 return -EINVAL;
1484 }
1485
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001486 switch (params->mode) {
1487 case DIAG_BUFFERING_MODE_STREAMING:
1488 case DIAG_BUFFERING_MODE_THRESHOLD:
1489 case DIAG_BUFFERING_MODE_CIRCULAR:
1490 break;
1491 default:
1492 pr_err("diag: In %s, invalid tx mode: %d\n", __func__,
1493 params->mode);
1494 return -EINVAL;
1495 }
1496
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05301497 if (diag_id &&
1498 driver->feature[peripheral].pd_buffering) {
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001499
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05301500 ctrl_pkt_v2.pkt_id = DIAG_CTRL_MSG_CONFIG_PERIPHERAL_TX_MODE;
1501 /*
1502 * Control packet length is size of version, diag_id,
1503 * stream_id and tx_mode
1504 */
1505 ctrl_pkt_v2.len = sizeof(uint32_t) + (3 * sizeof(uint8_t));
1506 ctrl_pkt_v2.version = 2;
1507 ctrl_pkt_v2.diag_id = diag_id;
1508 ctrl_pkt_v2.stream_id = 1;
1509 ctrl_pkt_v2.tx_mode = params->mode;
1510
1511 err = diagfwd_write(peripheral, TYPE_CNTL, &ctrl_pkt_v2,
1512 sizeof(ctrl_pkt_v2));
1513 if (err && err != -ENODEV) {
1514 pr_err("diag: Unable to send tx_mode ctrl packet to peripheral %d, err: %d\n",
1515 peripheral, err);
1516 goto fail;
1517 }
1518 } else {
1519 ctrl_pkt.pkt_id = DIAG_CTRL_MSG_CONFIG_PERIPHERAL_TX_MODE;
1520 /*
1521 * Control packet length is size of version,
1522 * stream_id and tx_mode
1523 */
1524 ctrl_pkt.len = sizeof(uint32_t) + (2 * sizeof(uint8_t));
1525 ctrl_pkt.version = 1;
1526 ctrl_pkt.stream_id = 1;
1527 ctrl_pkt.tx_mode = params->mode;
1528
1529 err = diagfwd_write(peripheral, TYPE_CNTL, &ctrl_pkt,
1530 sizeof(ctrl_pkt));
1531 if (err && err != -ENODEV) {
1532 pr_err("diag: Unable to send tx_mode ctrl packet to peripheral %d, err: %d\n",
1533 peripheral, err);
1534 goto fail;
1535 }
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001536 }
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05301537 driver->buffering_mode[params->peripheral].mode = params->mode;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001538
1539fail:
1540 return err;
1541}
1542
1543int diag_send_buffering_wm_values(uint8_t peripheral,
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05301544 uint8_t diag_id, struct diag_buffering_mode_t *params)
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001545{
1546 int err = 0;
1547 struct diag_ctrl_set_wq_val ctrl_pkt;
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05301548 struct diag_ctrl_set_wq_val_v2 ctrl_pkt_v2;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001549
1550 if (!params)
1551 return -EIO;
1552
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05301553 if (peripheral >= NUM_PERIPHERALS) {
1554 pr_err("diag: In %s, invalid peripheral %d\n", __func__,
1555 peripheral);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001556 return -EINVAL;
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05301557 }
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001558
1559 if (!driver->feature[peripheral].peripheral_buffering) {
1560 pr_debug("diag: In %s, peripheral %d doesn't support buffering\n",
1561 __func__, peripheral);
1562 return -EINVAL;
1563 }
1564
1565 if (!driver->diagfwd_cntl[peripheral] ||
1566 !driver->diagfwd_cntl[peripheral]->ch_open) {
1567 pr_debug("diag: In %s, control channel is not open, p: %d\n",
1568 __func__, peripheral);
1569 return -ENODEV;
1570 }
1571
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001572 switch (params->mode) {
1573 case DIAG_BUFFERING_MODE_STREAMING:
1574 case DIAG_BUFFERING_MODE_THRESHOLD:
1575 case DIAG_BUFFERING_MODE_CIRCULAR:
1576 break;
1577 default:
1578 pr_err("diag: In %s, invalid tx mode: %d\n", __func__,
1579 params->mode);
1580 return -EINVAL;
1581 }
1582
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05301583 if (diag_id &&
1584 driver->feature[peripheral].pd_buffering) {
1585 ctrl_pkt_v2.pkt_id = DIAG_CTRL_MSG_CONFIG_PERIPHERAL_WMQ_VAL;
1586 /*
1587 * Control packet length is size of version, diag_id,
1588 * stream_id and wmq values
1589 */
1590 ctrl_pkt_v2.len = sizeof(uint32_t) + (4 * sizeof(uint8_t));
1591 ctrl_pkt_v2.version = 2;
1592 ctrl_pkt_v2.diag_id = diag_id;
1593 ctrl_pkt_v2.stream_id = 1;
1594 ctrl_pkt_v2.high_wm_val = params->high_wm_val;
1595 ctrl_pkt_v2.low_wm_val = params->low_wm_val;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001596
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05301597 err = diagfwd_write(peripheral, TYPE_CNTL, &ctrl_pkt_v2,
1598 sizeof(ctrl_pkt_v2));
1599 if (err && err != -ENODEV) {
1600 pr_err("diag: Unable to send watermark values to peripheral %d, err: %d\n",
1601 peripheral, err);
1602 }
1603 } else {
1604 ctrl_pkt.pkt_id = DIAG_CTRL_MSG_CONFIG_PERIPHERAL_WMQ_VAL;
1605 /*
1606 * Control packet length is size of version,
1607 * stream_id and wmq values
1608 */
1609 ctrl_pkt.len = sizeof(uint32_t) + (3 * sizeof(uint8_t));
1610 ctrl_pkt.version = 1;
1611 ctrl_pkt.stream_id = 1;
1612 ctrl_pkt.high_wm_val = params->high_wm_val;
1613 ctrl_pkt.low_wm_val = params->low_wm_val;
1614
1615 err = diagfwd_write(peripheral, TYPE_CNTL, &ctrl_pkt,
1616 sizeof(ctrl_pkt));
1617 if (err && err != -ENODEV) {
1618 pr_err("diag: Unable to send watermark values to peripheral %d, err: %d\n",
1619 peripheral, err);
1620 }
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001621 }
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001622 return err;
1623}
1624
1625int diagfwd_cntl_init(void)
1626{
1627 uint8_t peripheral = 0;
1628
1629 reg_dirty = 0;
1630 driver->polling_reg_flag = 0;
1631 driver->log_on_demand_support = 1;
1632 driver->stm_peripheral = 0;
1633 driver->close_transport = 0;
1634 for (peripheral = 0; peripheral < NUM_PERIPHERALS; peripheral++)
1635 driver->buffering_flag[peripheral] = 0;
1636
1637 mutex_init(&driver->cntl_lock);
1638 INIT_WORK(&(driver->stm_update_work), diag_stm_update_work_fn);
1639 INIT_WORK(&(driver->mask_update_work), diag_mask_update_work_fn);
1640 INIT_WORK(&(driver->close_transport_work),
1641 diag_close_transport_work_fn);
1642
1643 driver->cntl_wq = create_singlethread_workqueue("diag_cntl_wq");
1644 if (!driver->cntl_wq)
1645 return -ENOMEM;
1646
1647 return 0;
1648}
1649
1650void diagfwd_cntl_channel_init(void)
1651{
1652 uint8_t peripheral;
1653
1654 for (peripheral = 0; peripheral < NUM_PERIPHERALS; peripheral++) {
1655 diagfwd_early_open(peripheral);
1656 diagfwd_open(peripheral, TYPE_CNTL);
1657 }
1658}
1659
1660void diagfwd_cntl_exit(void)
1661{
1662 if (driver->cntl_wq)
1663 destroy_workqueue(driver->cntl_wq);
1664}