blob: 162d53f3edb4f7c0b9eb2c5aec48f75b40288811 [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);
336 transport = driver->feature[peripheral].sockets_enabled ?
337 TRANSPORT_GLINK : TRANSPORT_SOCKET;
338 diagfwd_close_transport(transport, peripheral);
339 }
340 mutex_unlock(&driver->cntl_lock);
341}
342
343static void process_socket_feature(uint8_t peripheral)
344{
345 if (peripheral >= NUM_PERIPHERALS)
346 return;
347
348 mutex_lock(&driver->cntl_lock);
349 driver->close_transport |= PERIPHERAL_MASK(peripheral);
350 queue_work(driver->cntl_wq, &driver->close_transport_work);
351 mutex_unlock(&driver->cntl_lock);
352}
353
354static void process_log_on_demand_feature(uint8_t peripheral)
355{
356 /* Log On Demand command is registered only on Modem */
357 if (peripheral != PERIPHERAL_MODEM)
358 return;
359
360 if (driver->feature[PERIPHERAL_MODEM].log_on_demand)
361 driver->log_on_demand_support = 1;
362 else
363 driver->log_on_demand_support = 0;
364}
365
366static void process_incoming_feature_mask(uint8_t *buf, uint32_t len,
367 uint8_t peripheral)
368{
369 int i;
370 int header_len = sizeof(struct diag_ctrl_feature_mask);
371 int read_len = 0;
372 struct diag_ctrl_feature_mask *header = NULL;
373 uint32_t feature_mask_len = 0;
374 uint32_t feature_mask = 0;
375 uint8_t *ptr = buf;
376
377 if (!buf || peripheral >= NUM_PERIPHERALS || len == 0)
378 return;
379
380 header = (struct diag_ctrl_feature_mask *)ptr;
381 ptr += header_len;
382 feature_mask_len = header->feature_mask_len;
383
384 if (feature_mask_len == 0) {
385 pr_debug("diag: In %s, received invalid feature mask from peripheral %d\n",
386 __func__, peripheral);
387 return;
388 }
389
390 if (feature_mask_len > FEATURE_MASK_LEN) {
391 pr_alert("diag: Receiving feature mask length more than Apps support\n");
392 feature_mask_len = FEATURE_MASK_LEN;
393 }
394
Manoj Prabhu B2a428272016-12-22 15:22:03 +0530395 diag_cmd_remove_reg_by_proc(peripheral);
396
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700397 driver->feature[peripheral].rcvd_feature_mask = 1;
398
399 for (i = 0; i < feature_mask_len && read_len < len; i++) {
400 feature_mask = *(uint8_t *)ptr;
401 driver->feature[peripheral].feature_mask[i] = feature_mask;
402 ptr += sizeof(uint8_t);
403 read_len += sizeof(uint8_t);
404
405 if (FEATURE_SUPPORTED(F_DIAG_LOG_ON_DEMAND_APPS))
406 driver->feature[peripheral].log_on_demand = 1;
407 if (FEATURE_SUPPORTED(F_DIAG_REQ_RSP_SUPPORT))
408 driver->feature[peripheral].separate_cmd_rsp = 1;
409 if (FEATURE_SUPPORTED(F_DIAG_APPS_HDLC_ENCODE))
410 process_hdlc_encoding_feature(peripheral);
Manoj Prabhu B571cf422017-08-08 19:01:41 +0530411 if (FEATURE_SUPPORTED(F_DIAG_PKT_HEADER_UNTAG))
412 process_upd_header_untagging_feature(peripheral);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700413 if (FEATURE_SUPPORTED(F_DIAG_STM))
414 enable_stm_feature(peripheral);
415 if (FEATURE_SUPPORTED(F_DIAG_MASK_CENTRALIZATION))
416 driver->feature[peripheral].mask_centralization = 1;
417 if (FEATURE_SUPPORTED(F_DIAG_PERIPHERAL_BUFFERING))
418 driver->feature[peripheral].peripheral_buffering = 1;
419 if (FEATURE_SUPPORTED(F_DIAG_SOCKETS_ENABLED))
420 enable_socket_feature(peripheral);
Manoj Prabhu B571cf422017-08-08 19:01:41 +0530421 if (FEATURE_SUPPORTED(F_DIAG_DIAGID_SUPPORT))
422 driver->feature[peripheral].diag_id_support = 1;
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +0530423 if (FEATURE_SUPPORTED(F_DIAG_PD_BUFFERING))
424 driver->feature[peripheral].pd_buffering = 1;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700425 }
426
427 process_socket_feature(peripheral);
428 process_log_on_demand_feature(peripheral);
429}
430
431static void process_last_event_report(uint8_t *buf, uint32_t len,
432 uint8_t peripheral)
433{
434 struct diag_ctrl_last_event_report *header = NULL;
435 uint8_t *ptr = buf;
436 uint8_t *temp = NULL;
437 uint32_t pkt_len = sizeof(uint32_t) + sizeof(uint16_t);
438 uint16_t event_size = 0;
439
440 if (!buf || peripheral >= NUM_PERIPHERALS || len != pkt_len)
441 return;
442
443 mutex_lock(&event_mask.lock);
444 header = (struct diag_ctrl_last_event_report *)ptr;
445 event_size = ((header->event_last_id / 8) + 1);
446 if (event_size >= driver->event_mask_size) {
447 pr_debug("diag: In %s, receiving event mask size more that Apps can handle\n",
448 __func__);
449 temp = krealloc(driver->event_mask->ptr, event_size,
450 GFP_KERNEL);
451 if (!temp) {
452 pr_err("diag: In %s, unable to reallocate event mask to support events from %d\n",
453 __func__, peripheral);
454 goto err;
455 }
456 driver->event_mask->ptr = temp;
457 driver->event_mask_size = event_size;
458 }
459
460 driver->num_event_id[peripheral] = header->event_last_id;
461 if (header->event_last_id > driver->last_event_id)
462 driver->last_event_id = header->event_last_id;
463err:
464 mutex_unlock(&event_mask.lock);
465}
466
467static void process_log_range_report(uint8_t *buf, uint32_t len,
468 uint8_t peripheral)
469{
470 int i;
471 int read_len = 0;
472 int header_len = sizeof(struct diag_ctrl_log_range_report);
473 uint8_t *ptr = buf;
474 struct diag_ctrl_log_range_report *header = NULL;
475 struct diag_ctrl_log_range *log_range = NULL;
476 struct diag_log_mask_t *mask_ptr = NULL;
477
478 if (!buf || peripheral >= NUM_PERIPHERALS || len < 0)
479 return;
480
481 header = (struct diag_ctrl_log_range_report *)ptr;
482 ptr += header_len;
483 /* Don't account for pkt_id and length */
484 read_len += header_len - (2 * sizeof(uint32_t));
485
486 driver->num_equip_id[peripheral] = header->num_ranges;
487 for (i = 0; i < header->num_ranges && read_len < len; i++) {
488 log_range = (struct diag_ctrl_log_range *)ptr;
489 ptr += sizeof(struct diag_ctrl_log_range);
490 read_len += sizeof(struct diag_ctrl_log_range);
491
492 if (log_range->equip_id >= MAX_EQUIP_ID) {
493 pr_err("diag: receiving log equip id %d more than supported equip id: %d from peripheral: %d\n",
494 log_range->equip_id, MAX_EQUIP_ID, peripheral);
495 continue;
496 }
497 mask_ptr = (struct diag_log_mask_t *)log_mask.ptr;
498 mask_ptr = &mask_ptr[log_range->equip_id];
499
500 mutex_lock(&(mask_ptr->lock));
501 mask_ptr->num_items = log_range->num_items;
502 mask_ptr->range = LOG_ITEMS_TO_SIZE(log_range->num_items);
503 mutex_unlock(&(mask_ptr->lock));
504 }
505}
506
507static int update_msg_mask_tbl_entry(struct diag_msg_mask_t *mask,
508 struct diag_ssid_range_t *range)
509{
510 uint32_t temp_range;
511
512 if (!mask || !range)
513 return -EIO;
514 if (range->ssid_last < range->ssid_first) {
515 pr_err("diag: In %s, invalid ssid range, first: %d, last: %d\n",
516 __func__, range->ssid_first, range->ssid_last);
517 return -EINVAL;
518 }
519 if (range->ssid_last >= mask->ssid_last) {
520 temp_range = range->ssid_last - mask->ssid_first + 1;
521 mask->ssid_last = range->ssid_last;
522 mask->range = temp_range;
523 }
524
525 return 0;
526}
527
528static void process_ssid_range_report(uint8_t *buf, uint32_t len,
529 uint8_t peripheral)
530{
531 int i;
532 int j;
533 int read_len = 0;
534 int found = 0;
535 int new_size = 0;
536 int err = 0;
537 struct diag_ctrl_ssid_range_report *header = NULL;
538 struct diag_ssid_range_t *ssid_range = NULL;
539 int header_len = sizeof(struct diag_ctrl_ssid_range_report);
540 struct diag_msg_mask_t *mask_ptr = NULL;
541 uint8_t *ptr = buf;
542 uint8_t *temp = NULL;
543 uint32_t min_len = header_len - sizeof(struct diag_ctrl_pkt_header_t);
544
545 if (!buf || peripheral >= NUM_PERIPHERALS || len < min_len)
546 return;
547
548 header = (struct diag_ctrl_ssid_range_report *)ptr;
549 ptr += header_len;
550 /* Don't account for pkt_id and length */
551 read_len += header_len - (2 * sizeof(uint32_t));
552
Gopikrishna Mogasati9a44d8d2017-05-05 16:04:35 +0530553 mutex_lock(&driver->msg_mask_lock);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700554 driver->max_ssid_count[peripheral] = header->count;
555 for (i = 0; i < header->count && read_len < len; i++) {
556 ssid_range = (struct diag_ssid_range_t *)ptr;
557 ptr += sizeof(struct diag_ssid_range_t);
558 read_len += sizeof(struct diag_ssid_range_t);
559 mask_ptr = (struct diag_msg_mask_t *)msg_mask.ptr;
560 found = 0;
561 for (j = 0; j < driver->msg_mask_tbl_count; j++, mask_ptr++) {
562 if (mask_ptr->ssid_first != ssid_range->ssid_first)
563 continue;
564 mutex_lock(&mask_ptr->lock);
565 err = update_msg_mask_tbl_entry(mask_ptr, ssid_range);
566 mutex_unlock(&mask_ptr->lock);
567 if (err == -ENOMEM) {
568 pr_err("diag: In %s, unable to increase the msg mask table range\n",
569 __func__);
570 }
571 found = 1;
572 break;
573 }
574
575 if (found)
576 continue;
577
578 new_size = (driver->msg_mask_tbl_count + 1) *
579 sizeof(struct diag_msg_mask_t);
580 temp = krealloc(msg_mask.ptr, new_size, GFP_KERNEL);
581 if (!temp) {
582 pr_err("diag: In %s, Unable to add new ssid table to msg mask, ssid first: %d, last: %d\n",
583 __func__, ssid_range->ssid_first,
584 ssid_range->ssid_last);
585 continue;
586 }
587 msg_mask.ptr = temp;
588 err = diag_create_msg_mask_table_entry(mask_ptr, ssid_range);
589 if (err) {
590 pr_err("diag: In %s, Unable to create a new msg mask table entry, first: %d last: %d err: %d\n",
591 __func__, ssid_range->ssid_first,
592 ssid_range->ssid_last, err);
593 continue;
594 }
595 driver->msg_mask_tbl_count += 1;
596 }
Gopikrishna Mogasati9a44d8d2017-05-05 16:04:35 +0530597 mutex_unlock(&driver->msg_mask_lock);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700598}
599
600static void diag_build_time_mask_update(uint8_t *buf,
601 struct diag_ssid_range_t *range)
602{
603 int i;
604 int j;
605 int num_items = 0;
606 int err = 0;
607 int found = 0;
608 int new_size = 0;
609 uint8_t *temp = NULL;
610 uint32_t *mask_ptr = (uint32_t *)buf;
611 uint32_t *dest_ptr = NULL;
612 struct diag_msg_mask_t *build_mask = NULL;
613
614 if (!range || !buf)
615 return;
616
617 if (range->ssid_last < range->ssid_first) {
618 pr_err("diag: In %s, invalid ssid range, first: %d, last: %d\n",
619 __func__, range->ssid_first, range->ssid_last);
620 return;
621 }
Gopikrishna Mogasati9a44d8d2017-05-05 16:04:35 +0530622 mutex_lock(&driver->msg_mask_lock);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700623 build_mask = (struct diag_msg_mask_t *)(driver->build_time_mask->ptr);
624 num_items = range->ssid_last - range->ssid_first + 1;
625
Gopikrishna Mogasati9a44d8d2017-05-05 16:04:35 +0530626 for (i = 0; i < driver->bt_msg_mask_tbl_count; i++, build_mask++) {
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700627 if (build_mask->ssid_first != range->ssid_first)
628 continue;
629 found = 1;
630 mutex_lock(&build_mask->lock);
631 err = update_msg_mask_tbl_entry(build_mask, range);
632 if (err == -ENOMEM) {
633 pr_err("diag: In %s, unable to increase the msg build mask table range\n",
634 __func__);
635 }
636 dest_ptr = build_mask->ptr;
637 for (j = 0; j < build_mask->range; j++, mask_ptr++, dest_ptr++)
638 *(uint32_t *)dest_ptr |= *mask_ptr;
639 mutex_unlock(&build_mask->lock);
640 break;
641 }
642
643 if (found)
644 goto end;
Gopikrishna Mogasati9a44d8d2017-05-05 16:04:35 +0530645 new_size = (driver->bt_msg_mask_tbl_count + 1) *
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700646 sizeof(struct diag_msg_mask_t);
647 temp = krealloc(driver->build_time_mask->ptr, new_size, GFP_KERNEL);
648 if (!temp) {
649 pr_err("diag: In %s, unable to create a new entry for build time mask\n",
650 __func__);
651 goto end;
652 }
653 driver->build_time_mask->ptr = temp;
654 err = diag_create_msg_mask_table_entry(build_mask, range);
655 if (err) {
656 pr_err("diag: In %s, Unable to create a new msg mask table entry, err: %d\n",
657 __func__, err);
658 goto end;
659 }
Gopikrishna Mogasati9a44d8d2017-05-05 16:04:35 +0530660 driver->bt_msg_mask_tbl_count += 1;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700661end:
Gopikrishna Mogasati9a44d8d2017-05-05 16:04:35 +0530662 mutex_unlock(&driver->msg_mask_lock);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700663 return;
664}
665
666static void process_build_mask_report(uint8_t *buf, uint32_t len,
667 uint8_t peripheral)
668{
669 int i;
670 int read_len = 0;
671 int num_items = 0;
672 int header_len = sizeof(struct diag_ctrl_build_mask_report);
673 uint8_t *ptr = buf;
674 struct diag_ctrl_build_mask_report *header = NULL;
675 struct diag_ssid_range_t *range = NULL;
676
677 if (!buf || peripheral >= NUM_PERIPHERALS || len < header_len)
678 return;
679
680 header = (struct diag_ctrl_build_mask_report *)ptr;
681 ptr += header_len;
682 /* Don't account for pkt_id and length */
683 read_len += header_len - (2 * sizeof(uint32_t));
684
685 for (i = 0; i < header->count && read_len < len; i++) {
686 range = (struct diag_ssid_range_t *)ptr;
687 ptr += sizeof(struct diag_ssid_range_t);
688 read_len += sizeof(struct diag_ssid_range_t);
689 num_items = range->ssid_last - range->ssid_first + 1;
690 diag_build_time_mask_update(ptr, range);
691 ptr += num_items * sizeof(uint32_t);
692 read_len += num_items * sizeof(uint32_t);
693 }
694}
695
Manoj Prabhu B90e1f502017-11-02 20:01:45 +0530696int diag_add_diag_id_to_list(uint8_t diag_id, char *process_name,
697 uint8_t pd_val, uint8_t peripheral)
Sreelakshmi Gownipalli8d477d32017-02-08 19:49:06 -0800698{
699 struct diag_id_tbl_t *new_item = NULL;
700
701 if (!process_name || diag_id == 0)
702 return -EINVAL;
703
704 new_item = kzalloc(sizeof(struct diag_id_tbl_t), GFP_KERNEL);
705 if (!new_item)
706 return -ENOMEM;
707 kmemleak_not_leak(new_item);
Chris Lewbf225832017-04-21 10:45:53 -0700708 new_item->process_name = kzalloc(strlen(process_name) + 1, GFP_KERNEL);
Sreelakshmi Gownipalli8d477d32017-02-08 19:49:06 -0800709 if (!new_item->process_name) {
710 kfree(new_item);
711 new_item = NULL;
712 return -ENOMEM;
713 }
714 kmemleak_not_leak(new_item->process_name);
715 new_item->diag_id = diag_id;
Manoj Prabhu B90e1f502017-11-02 20:01:45 +0530716 new_item->pd_val = pd_val;
717 new_item->peripheral = peripheral;
Sreelakshmi Gownipalli8d477d32017-02-08 19:49:06 -0800718 strlcpy(new_item->process_name, process_name, strlen(process_name) + 1);
719 INIT_LIST_HEAD(&new_item->link);
720 mutex_lock(&driver->diag_id_mutex);
721 list_add_tail(&new_item->link, &driver->diag_id_list);
722 mutex_unlock(&driver->diag_id_mutex);
723 return 0;
724}
725
726int diag_query_diag_id(char *process_name, uint8_t *diag_id)
727{
728 struct list_head *start;
729 struct list_head *temp;
730 struct diag_id_tbl_t *item = NULL;
731
732 if (!process_name || !diag_id)
733 return -EINVAL;
734
735 mutex_lock(&driver->diag_id_mutex);
736 list_for_each_safe(start, temp, &driver->diag_id_list) {
737 item = list_entry(start, struct diag_id_tbl_t, link);
738 if (strcmp(item->process_name, process_name) == 0) {
739 *diag_id = item->diag_id;
740 mutex_unlock(&driver->diag_id_mutex);
741 return 1;
742 }
743 }
744 mutex_unlock(&driver->diag_id_mutex);
745 return 0;
746}
747static void process_diagid(uint8_t *buf, uint32_t len,
748 uint8_t peripheral)
749{
750 struct diag_ctrl_diagid *header = NULL;
751 struct diag_ctrl_diagid ctrl_pkt;
Manoj Prabhu B90e1f502017-11-02 20:01:45 +0530752 struct diagfwd_info *fwd_info = NULL;
Sreelakshmi Gownipalli8d477d32017-02-08 19:49:06 -0800753 char *process_name = NULL;
754 int err = 0;
Manoj Prabhu B90e1f502017-11-02 20:01:45 +0530755 int pd_val;
Manoj Prabhu Bd7962422017-09-14 14:14:08 +0530756 char *root_str = NULL;
Sreelakshmi Gownipalli8d477d32017-02-08 19:49:06 -0800757 uint8_t local_diag_id = 0;
Manoj Prabhu B90e1f502017-11-02 20:01:45 +0530758 uint8_t new_request = 0, i = 0, ch_type = 0;
Sreelakshmi Gownipalli8d477d32017-02-08 19:49:06 -0800759
760 if (!buf || len == 0 || peripheral >= NUM_PERIPHERALS)
761 return;
Manoj Prabhu B571cf422017-08-08 19:01:41 +0530762
Sreelakshmi Gownipalli8d477d32017-02-08 19:49:06 -0800763 header = (struct diag_ctrl_diagid *)buf;
764 process_name = (char *)&header->process_name;
765 if (diag_query_diag_id(process_name, &local_diag_id))
766 ctrl_pkt.diag_id = local_diag_id;
767 else {
768 diag_id++;
Manoj Prabhu B571cf422017-08-08 19:01:41 +0530769 new_request = 1;
Manoj Prabhu B90e1f502017-11-02 20:01:45 +0530770 pd_val = diag_query_pd(process_name);
771 if (pd_val < 0)
772 return;
773 diag_add_diag_id_to_list(diag_id, process_name,
774 pd_val, peripheral);
775 ctrl_pkt.diag_id = diag_id;
Sreelakshmi Gownipalli8d477d32017-02-08 19:49:06 -0800776 }
Manoj Prabhu Bd7962422017-09-14 14:14:08 +0530777 root_str = strnstr(process_name, DIAG_ID_ROOT_STRING,
778 strlen(process_name));
Manoj Prabhu B571cf422017-08-08 19:01:41 +0530779
780 if (new_request) {
Manoj Prabhu B90e1f502017-11-02 20:01:45 +0530781 for (ch_type = 0; ch_type < NUM_TYPES; ch_type++) {
782 if (ch_type == TYPE_DCI ||
783 ch_type == TYPE_DCI_CMD)
784 continue;
785 fwd_info = &peripheral_info[ch_type][peripheral];
786 fwd_info->num_pd++;
Manoj Prabhu Bd7962422017-09-14 14:14:08 +0530787
Manoj Prabhu B90e1f502017-11-02 20:01:45 +0530788 if (root_str) {
789 fwd_info->root_diag_id.diagid_val =
790 ctrl_pkt.diag_id;
791 fwd_info->root_diag_id.reg_str =
792 process_name;
793 fwd_info->root_diag_id.pd = pd_val;
794 } else {
795 i = fwd_info->num_pd - 2;
796 if (i >= 0 && i < MAX_PERIPHERAL_UPD) {
797 fwd_info->upd_diag_id[i].diagid_val =
798 ctrl_pkt.diag_id;
799 fwd_info->upd_diag_id[i].reg_str =
800 process_name;
801 fwd_info->upd_diag_id[i].pd = pd_val;
802 }
803 }
Manoj Prabhu Bd7962422017-09-14 14:14:08 +0530804 }
Manoj Prabhu B571cf422017-08-08 19:01:41 +0530805 }
806
Manoj Prabhu B571cf422017-08-08 19:01:41 +0530807 DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
808 "diag: peripheral = %d: diag_id string = %s,diag_id = %d\n",
809 peripheral, process_name, ctrl_pkt.diag_id);
810
Sreelakshmi Gownipalli8d477d32017-02-08 19:49:06 -0800811 ctrl_pkt.pkt_id = DIAG_CTRL_MSG_DIAGID;
812 ctrl_pkt.version = 1;
813 strlcpy((char *)&ctrl_pkt.process_name, process_name,
814 strlen(process_name) + 1);
815 ctrl_pkt.len = sizeof(ctrl_pkt.diag_id) + sizeof(ctrl_pkt.version) +
816 strlen(process_name) + 1;
817 err = diagfwd_write(peripheral, TYPE_CNTL, &ctrl_pkt, ctrl_pkt.len +
818 sizeof(ctrl_pkt.pkt_id) + sizeof(ctrl_pkt.len));
819 if (err && err != -ENODEV) {
Manoj Prabhu B571cf422017-08-08 19:01:41 +0530820 pr_err("diag: Unable to send diag id ctrl packet to peripheral %d, err: %d\n",
Sreelakshmi Gownipalli8d477d32017-02-08 19:49:06 -0800821 peripheral, err);
Manoj Prabhu B571cf422017-08-08 19:01:41 +0530822 } else {
Manoj Prabhu B9553b462017-09-25 09:59:47 +0530823 /*
824 * Masks (F3, logs and events) will be sent to
825 * peripheral immediately following feature mask update only
826 * if diag_id support is not present or
827 * diag_id support is present and diag_id has been sent to
828 * peripheral.
829 * With diag_id being sent now, mask will be updated
830 * to peripherals.
831 */
832 if (root_str) {
833 driver->diag_id_sent[peripheral] = 1;
Manoj Prabhu B9ac639f2017-11-21 21:37:11 +0530834 queue_work(driver->cntl_wq, &driver->mask_update_work);
Manoj Prabhu B9553b462017-09-25 09:59:47 +0530835 }
Manoj Prabhu B90e1f502017-11-02 20:01:45 +0530836 fwd_info = &peripheral_info[TYPE_DATA][peripheral];
837 diagfwd_buffers_init(fwd_info);
Manoj Prabhu Bd7962422017-09-14 14:14:08 +0530838 DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
839 "diag: diag_id sent = %d to peripheral = %d with diag_id = %d for %s :\n",
840 driver->diag_id_sent[peripheral], peripheral,
841 ctrl_pkt.diag_id, process_name);
Sreelakshmi Gownipalli8d477d32017-02-08 19:49:06 -0800842 }
843}
844
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700845void diag_cntl_process_read_data(struct diagfwd_info *p_info, void *buf,
846 int len)
847{
848 uint32_t read_len = 0;
849 uint32_t header_len = sizeof(struct diag_ctrl_pkt_header_t);
850 uint8_t *ptr = buf;
851 struct diag_ctrl_pkt_header_t *ctrl_pkt = NULL;
852
853 if (!buf || len <= 0 || !p_info)
854 return;
855
856 if (reg_dirty & PERIPHERAL_MASK(p_info->peripheral)) {
857 pr_err_ratelimited("diag: dropping command registration from peripheral %d\n",
858 p_info->peripheral);
859 return;
860 }
861
862 while (read_len + header_len < len) {
863 ctrl_pkt = (struct diag_ctrl_pkt_header_t *)ptr;
864 switch (ctrl_pkt->pkt_id) {
865 case DIAG_CTRL_MSG_REG:
866 process_command_registration(ptr, ctrl_pkt->len,
867 p_info->peripheral);
868 break;
869 case DIAG_CTRL_MSG_DEREG:
870 process_command_deregistration(ptr, ctrl_pkt->len,
871 p_info->peripheral);
872 break;
873 case DIAG_CTRL_MSG_FEATURE:
874 process_incoming_feature_mask(ptr, ctrl_pkt->len,
875 p_info->peripheral);
876 break;
877 case DIAG_CTRL_MSG_LAST_EVENT_REPORT:
878 process_last_event_report(ptr, ctrl_pkt->len,
879 p_info->peripheral);
880 break;
881 case DIAG_CTRL_MSG_LOG_RANGE_REPORT:
882 process_log_range_report(ptr, ctrl_pkt->len,
883 p_info->peripheral);
884 break;
885 case DIAG_CTRL_MSG_SSID_RANGE_REPORT:
886 process_ssid_range_report(ptr, ctrl_pkt->len,
887 p_info->peripheral);
888 break;
889 case DIAG_CTRL_MSG_BUILD_MASK_REPORT:
890 process_build_mask_report(ptr, ctrl_pkt->len,
891 p_info->peripheral);
892 break;
893 case DIAG_CTRL_MSG_PD_STATUS:
894 process_pd_status(ptr, ctrl_pkt->len,
895 p_info->peripheral);
896 break;
Sreelakshmi Gownipalli8d477d32017-02-08 19:49:06 -0800897 case DIAG_CTRL_MSG_DIAGID:
898 process_diagid(ptr, ctrl_pkt->len,
899 p_info->peripheral);
900 break;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700901 default:
902 pr_debug("diag: Control packet %d not supported\n",
903 ctrl_pkt->pkt_id);
904 }
905 ptr += header_len + ctrl_pkt->len;
906 read_len += header_len + ctrl_pkt->len;
907 }
908}
909
910static int diag_compute_real_time(int idx)
911{
912 int real_time = MODE_REALTIME;
913
914 if (driver->proc_active_mask == 0) {
915 /*
916 * There are no DCI or Memory Device processes. Diag should
917 * be in Real Time mode irrespective of USB connection
918 */
919 real_time = MODE_REALTIME;
920 } else if (driver->proc_rt_vote_mask[idx] & driver->proc_active_mask) {
921 /*
922 * Atleast one process is alive and is voting for Real Time
923 * data - Diag should be in real time mode irrespective of USB
924 * connection.
925 */
926 real_time = MODE_REALTIME;
927 } else if (driver->usb_connected) {
928 /*
929 * If USB is connected, check individual process. If Memory
930 * Device Mode is active, set the mode requested by Memory
931 * Device process. Set to realtime mode otherwise.
932 */
933 if ((driver->proc_rt_vote_mask[idx] &
934 DIAG_PROC_MEMORY_DEVICE) == 0)
935 real_time = MODE_NONREALTIME;
936 else
937 real_time = MODE_REALTIME;
938 } else {
939 /*
940 * We come here if USB is not connected and the active
941 * processes are voting for Non realtime mode.
942 */
943 real_time = MODE_NONREALTIME;
944 }
945 return real_time;
946}
947
948static void diag_create_diag_mode_ctrl_pkt(unsigned char *dest_buf,
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +0530949 uint8_t diag_id, int real_time)
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700950{
951 struct diag_ctrl_msg_diagmode diagmode;
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +0530952 struct diag_ctrl_msg_diagmode_v2 diagmode_v2;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700953 int msg_size = sizeof(struct diag_ctrl_msg_diagmode);
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +0530954 int msg_size_2 = sizeof(struct diag_ctrl_msg_diagmode_v2);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700955
956 if (!dest_buf)
957 return;
958
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +0530959 if (diag_id) {
960 diagmode_v2.ctrl_pkt_id = DIAG_CTRL_MSG_DIAGMODE;
961 diagmode_v2.ctrl_pkt_data_len = DIAG_MODE_PKT_LEN_V2;
962 diagmode_v2.version = 2;
963 diagmode_v2.sleep_vote = real_time ? 1 : 0;
964 /*
965 * 0 - Disables real-time logging (to prevent
966 * frequent APPS wake-ups, etc.).
967 * 1 - Enable real-time logging
968 */
969 diagmode_v2.real_time = real_time;
970 diagmode_v2.use_nrt_values = 0;
971 diagmode_v2.commit_threshold = 0;
972 diagmode_v2.sleep_threshold = 0;
973 diagmode_v2.sleep_time = 0;
974 diagmode_v2.drain_timer_val = 0;
975 diagmode_v2.event_stale_timer_val = 0;
976 diagmode_v2.diag_id = diag_id;
977 memcpy(dest_buf, &diagmode_v2, msg_size_2);
978 } else {
979 diagmode.ctrl_pkt_id = DIAG_CTRL_MSG_DIAGMODE;
980 diagmode.ctrl_pkt_data_len = DIAG_MODE_PKT_LEN;
981 diagmode.version = 1;
982 diagmode.sleep_vote = real_time ? 1 : 0;
983 /*
984 * 0 - Disables real-time logging (to prevent
985 * frequent APPS wake-ups, etc.).
986 * 1 - Enable real-time logging
987 */
988 diagmode.real_time = real_time;
989 diagmode.use_nrt_values = 0;
990 diagmode.commit_threshold = 0;
991 diagmode.sleep_threshold = 0;
992 diagmode.sleep_time = 0;
993 diagmode.drain_timer_val = 0;
994 diagmode.event_stale_timer_val = 0;
995 memcpy(dest_buf, &diagmode, msg_size);
996 }
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -0700997}
998
999void diag_update_proc_vote(uint16_t proc, uint8_t vote, int index)
1000{
1001 int i;
1002
1003 mutex_lock(&driver->real_time_mutex);
1004 if (vote)
1005 driver->proc_active_mask |= proc;
1006 else {
1007 driver->proc_active_mask &= ~proc;
1008 if (index == ALL_PROC) {
1009 for (i = 0; i < DIAG_NUM_PROC; i++)
1010 driver->proc_rt_vote_mask[i] |= proc;
1011 } else {
1012 driver->proc_rt_vote_mask[index] |= proc;
1013 }
1014 }
1015 mutex_unlock(&driver->real_time_mutex);
1016}
1017
1018void diag_update_real_time_vote(uint16_t proc, uint8_t real_time, int index)
1019{
1020 int i;
1021
1022 if (index >= DIAG_NUM_PROC) {
1023 pr_err("diag: In %s, invalid index %d\n", __func__, index);
1024 return;
1025 }
1026
1027 mutex_lock(&driver->real_time_mutex);
1028 if (index == ALL_PROC) {
1029 for (i = 0; i < DIAG_NUM_PROC; i++) {
1030 if (real_time)
1031 driver->proc_rt_vote_mask[i] |= proc;
1032 else
1033 driver->proc_rt_vote_mask[i] &= ~proc;
1034 }
1035 } else {
1036 if (real_time)
1037 driver->proc_rt_vote_mask[index] |= proc;
1038 else
1039 driver->proc_rt_vote_mask[index] &= ~proc;
1040 }
1041 mutex_unlock(&driver->real_time_mutex);
1042}
1043
1044
1045#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
1046static void diag_send_diag_mode_update_remote(int token, int real_time)
1047{
1048 unsigned char *buf = NULL;
1049 int err = 0;
1050 struct diag_dci_header_t dci_header;
1051 int dci_header_size = sizeof(struct diag_dci_header_t);
1052 int msg_size = sizeof(struct diag_ctrl_msg_diagmode);
1053 uint32_t write_len = 0;
1054
1055 if (token < 0 || token >= NUM_DCI_PROC) {
1056 pr_err("diag: Invalid remote device channel in %s, token: %d\n",
1057 __func__, token);
1058 return;
1059 }
1060
1061 if (real_time != MODE_REALTIME && real_time != MODE_NONREALTIME) {
1062 pr_err("diag: Invalid real time value in %s, type: %d\n",
1063 __func__, real_time);
1064 return;
1065 }
1066
1067 buf = dci_get_buffer_from_bridge(token);
1068 if (!buf) {
1069 pr_err("diag: In %s, unable to get dci buffers to write data\n",
1070 __func__);
1071 return;
1072 }
1073 /* Frame the DCI header */
1074 dci_header.start = CONTROL_CHAR;
1075 dci_header.version = 1;
1076 dci_header.length = msg_size + 1;
1077 dci_header.cmd_code = DCI_CONTROL_PKT_CODE;
1078
1079 memcpy(buf + write_len, &dci_header, dci_header_size);
1080 write_len += dci_header_size;
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05301081 diag_create_diag_mode_ctrl_pkt(buf + write_len, 0, real_time);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001082 write_len += msg_size;
1083 *(buf + write_len) = CONTROL_CHAR; /* End Terminator */
1084 write_len += sizeof(uint8_t);
1085 err = diagfwd_bridge_write(TOKEN_TO_BRIDGE(token), buf, write_len);
1086 if (err != write_len) {
1087 pr_err("diag: cannot send nrt mode ctrl pkt, err: %d\n", err);
1088 diagmem_free(driver, buf, dci_ops_tbl[token].mempool);
1089 } else {
1090 driver->real_time_mode[token + 1] = real_time;
1091 }
1092}
1093#else
1094static inline void diag_send_diag_mode_update_remote(int token, int real_time)
1095{
1096}
1097#endif
1098
1099#ifdef CONFIG_DIAG_OVER_USB
1100void diag_real_time_work_fn(struct work_struct *work)
1101{
1102 int temp_real_time = MODE_REALTIME, i, j;
1103 uint8_t send_update = 1;
1104
1105 /*
1106 * If any peripheral in the local processor is in either threshold or
1107 * circular buffering mode, don't send the real time mode control
1108 * packet.
1109 */
1110 for (i = 0; i < NUM_PERIPHERALS; i++) {
1111 if (!driver->feature[i].peripheral_buffering)
1112 continue;
1113 switch (driver->buffering_mode[i].mode) {
1114 case DIAG_BUFFERING_MODE_THRESHOLD:
1115 case DIAG_BUFFERING_MODE_CIRCULAR:
1116 send_update = 0;
1117 break;
1118 }
1119 }
1120
1121 mutex_lock(&driver->mode_lock);
1122 for (i = 0; i < DIAG_NUM_PROC; i++) {
1123 temp_real_time = diag_compute_real_time(i);
1124 if (temp_real_time == driver->real_time_mode[i]) {
1125 pr_debug("diag: did not update real time mode on proc %d, already in the req mode %d",
1126 i, temp_real_time);
1127 continue;
1128 }
1129
1130 if (i == DIAG_LOCAL_PROC) {
1131 if (!send_update) {
1132 pr_debug("diag: In %s, cannot send real time mode pkt since one of the periperhal is in buffering mode\n",
1133 __func__);
1134 break;
1135 }
1136 for (j = 0; j < NUM_PERIPHERALS; j++)
1137 diag_send_real_time_update(j,
1138 temp_real_time);
1139 } else {
1140 diag_send_diag_mode_update_remote(i - 1,
1141 temp_real_time);
1142 }
1143 }
1144 mutex_unlock(&driver->mode_lock);
1145
1146 if (driver->real_time_update_busy > 0)
1147 driver->real_time_update_busy--;
1148}
1149#else
1150void diag_real_time_work_fn(struct work_struct *work)
1151{
1152 int temp_real_time = MODE_REALTIME, i, j;
1153
1154 for (i = 0; i < DIAG_NUM_PROC; i++) {
1155 if (driver->proc_active_mask == 0) {
1156 /*
1157 * There are no DCI or Memory Device processes.
1158 * Diag should be in Real Time mode.
1159 */
1160 temp_real_time = MODE_REALTIME;
1161 } else if (!(driver->proc_rt_vote_mask[i] &
1162 driver->proc_active_mask)) {
1163 /* No active process is voting for real time mode */
1164 temp_real_time = MODE_NONREALTIME;
1165 }
1166 if (temp_real_time == driver->real_time_mode[i]) {
1167 pr_debug("diag: did not update real time mode on proc %d, already in the req mode %d",
1168 i, temp_real_time);
1169 continue;
1170 }
1171
1172 if (i == DIAG_LOCAL_PROC) {
1173 for (j = 0; j < NUM_PERIPHERALS; j++)
1174 diag_send_real_time_update(
1175 j, temp_real_time);
1176 } else {
1177 diag_send_diag_mode_update_remote(i - 1,
1178 temp_real_time);
1179 }
1180 }
1181
1182 if (driver->real_time_update_busy > 0)
1183 driver->real_time_update_busy--;
1184}
1185#endif
1186
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05301187static int __diag_send_real_time_update(uint8_t peripheral, int real_time,
1188 uint8_t diag_id)
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001189{
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05301190 char buf[sizeof(struct diag_ctrl_msg_diagmode_v2)];
1191 int msg_size = 0;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001192 int err = 0;
1193
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05301194 if (peripheral >= NUM_PERIPHERALS) {
1195 pr_err("diag: In %s, invalid peripheral %d\n", __func__,
1196 peripheral);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001197 return -EINVAL;
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05301198 }
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001199
1200 if (!driver->diagfwd_cntl[peripheral] ||
1201 !driver->diagfwd_cntl[peripheral]->ch_open) {
1202 pr_debug("diag: In %s, control channel is not open, p: %d\n",
1203 __func__, peripheral);
1204 return err;
1205 }
1206
1207 if (real_time != MODE_NONREALTIME && real_time != MODE_REALTIME) {
1208 pr_err("diag: In %s, invalid real time mode %d, peripheral: %d\n",
1209 __func__, real_time, peripheral);
1210 return -EINVAL;
1211 }
1212
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05301213 msg_size = (diag_id ? sizeof(struct diag_ctrl_msg_diagmode_v2) :
1214 sizeof(struct diag_ctrl_msg_diagmode));
1215
1216 diag_create_diag_mode_ctrl_pkt(buf, diag_id, real_time);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001217
1218 mutex_lock(&driver->diag_cntl_mutex);
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05301219
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001220 err = diagfwd_write(peripheral, TYPE_CNTL, buf, msg_size);
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05301221
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001222 if (err && err != -ENODEV) {
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05301223 pr_err("diag: In %s, unable to write, peripheral: %d, type: %d, len: %d, err: %d\n",
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001224 __func__, peripheral, TYPE_CNTL,
1225 msg_size, err);
1226 } else {
1227 driver->real_time_mode[DIAG_LOCAL_PROC] = real_time;
1228 }
1229
1230 mutex_unlock(&driver->diag_cntl_mutex);
1231
1232 return err;
1233}
1234
1235int diag_send_real_time_update(uint8_t peripheral, int real_time)
1236{
1237 int i;
1238
1239 for (i = 0; i < NUM_PERIPHERALS; i++) {
1240 if (!driver->buffering_flag[i])
1241 continue;
1242 /*
1243 * One of the peripherals is in buffering mode. Don't set
1244 * the RT value.
1245 */
1246 return -EINVAL;
1247 }
1248
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05301249 return __diag_send_real_time_update(peripheral, real_time, 0);
1250}
1251
1252void diag_map_pd_to_diagid(uint8_t pd, uint8_t *diag_id, int *peripheral)
1253{
1254 if (!diag_search_diagid_by_pd(pd, (void *)diag_id,
1255 (void *)peripheral)) {
1256 *diag_id = 0;
1257 if ((pd >= 0) && pd < NUM_PERIPHERALS)
1258 *peripheral = pd;
1259 else
1260 *peripheral = -EINVAL;
1261 }
1262
1263 if (*peripheral >= 0)
1264 if (!driver->feature[*peripheral].pd_buffering)
1265 *diag_id = 0;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001266}
1267
1268int diag_send_peripheral_buffering_mode(struct diag_buffering_mode_t *params)
1269{
1270 int err = 0;
1271 int mode = MODE_REALTIME;
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05301272 int peripheral = 0;
1273 uint8_t diag_id = 0;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001274
1275 if (!params)
1276 return -EIO;
1277
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05301278 diag_map_pd_to_diagid(params->peripheral,
1279 &diag_id, &peripheral);
1280
1281 if ((peripheral < 0) ||
1282 peripheral >= NUM_PERIPHERALS) {
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001283 pr_err("diag: In %s, invalid peripheral %d\n", __func__,
1284 peripheral);
1285 return -EINVAL;
1286 }
1287
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05301288 if (!driver->buffering_flag[params->peripheral]) {
1289 pr_err("diag: In %s, buffering flag not set for %d\n", __func__,
1290 params->peripheral);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001291 return -EINVAL;
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05301292 }
1293
1294 if (!driver->feature[peripheral].peripheral_buffering) {
1295 pr_err("diag: In %s, peripheral %d doesn't support buffering\n",
1296 __func__, peripheral);
1297 return -EIO;
1298 }
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001299
1300 switch (params->mode) {
1301 case DIAG_BUFFERING_MODE_STREAMING:
1302 mode = MODE_REALTIME;
1303 break;
1304 case DIAG_BUFFERING_MODE_THRESHOLD:
1305 case DIAG_BUFFERING_MODE_CIRCULAR:
1306 mode = MODE_NONREALTIME;
1307 break;
1308 default:
1309 pr_err("diag: In %s, invalid tx mode %d\n", __func__,
1310 params->mode);
1311 return -EINVAL;
1312 }
1313
1314 if (!driver->feature[peripheral].peripheral_buffering) {
1315 pr_debug("diag: In %s, peripheral %d doesn't support buffering\n",
1316 __func__, peripheral);
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05301317 driver->buffering_flag[params->peripheral] = 0;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001318 return -EIO;
1319 }
1320
1321 /*
1322 * Perform sanity on watermark values. These values must be
1323 * checked irrespective of the buffering mode.
1324 */
1325 if (((params->high_wm_val > DIAG_MAX_WM_VAL) ||
1326 (params->low_wm_val > DIAG_MAX_WM_VAL)) ||
1327 (params->low_wm_val > params->high_wm_val) ||
1328 ((params->low_wm_val == params->high_wm_val) &&
1329 (params->low_wm_val != DIAG_MIN_WM_VAL))) {
1330 pr_err("diag: In %s, invalid watermark values, high: %d, low: %d, peripheral: %d\n",
1331 __func__, params->high_wm_val, params->low_wm_val,
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05301332 params->peripheral);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001333 return -EINVAL;
1334 }
1335
1336 mutex_lock(&driver->mode_lock);
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05301337 err = diag_send_buffering_tx_mode_pkt(peripheral, diag_id, params);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001338 if (err) {
1339 pr_err("diag: In %s, unable to send buffering mode packet to peripheral %d, err: %d\n",
1340 __func__, peripheral, err);
1341 goto fail;
1342 }
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05301343 err = diag_send_buffering_wm_values(peripheral, diag_id, params);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001344 if (err) {
1345 pr_err("diag: In %s, unable to send buffering wm value packet to peripheral %d, err: %d\n",
1346 __func__, peripheral, err);
1347 goto fail;
1348 }
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05301349 err = __diag_send_real_time_update(peripheral, mode, diag_id);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001350 if (err) {
1351 pr_err("diag: In %s, unable to send mode update to peripheral %d, mode: %d, err: %d\n",
1352 __func__, peripheral, mode, err);
1353 goto fail;
1354 }
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05301355 driver->buffering_mode[params->peripheral].peripheral =
1356 params->peripheral;
1357 driver->buffering_mode[params->peripheral].mode =
1358 params->mode;
1359 driver->buffering_mode[params->peripheral].low_wm_val =
1360 params->low_wm_val;
1361 driver->buffering_mode[params->peripheral].high_wm_val =
1362 params->high_wm_val;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001363 if (params->mode == DIAG_BUFFERING_MODE_STREAMING)
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05301364 driver->buffering_flag[params->peripheral] = 0;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001365fail:
1366 mutex_unlock(&driver->mode_lock);
1367 return err;
1368}
1369
1370int diag_send_stm_state(uint8_t peripheral, uint8_t stm_control_data)
1371{
1372 struct diag_ctrl_msg_stm stm_msg;
1373 int msg_size = sizeof(struct diag_ctrl_msg_stm);
1374 int err = 0;
1375
1376 if (peripheral >= NUM_PERIPHERALS)
1377 return -EIO;
1378
1379 if (!driver->diagfwd_cntl[peripheral] ||
1380 !driver->diagfwd_cntl[peripheral]->ch_open) {
1381 pr_debug("diag: In %s, control channel is not open, p: %d\n",
1382 __func__, peripheral);
1383 return -ENODEV;
1384 }
1385
1386 if (driver->feature[peripheral].stm_support == DISABLE_STM)
1387 return -EINVAL;
1388
1389 stm_msg.ctrl_pkt_id = 21;
1390 stm_msg.ctrl_pkt_data_len = 5;
1391 stm_msg.version = 1;
1392 stm_msg.control_data = stm_control_data;
1393 err = diagfwd_write(peripheral, TYPE_CNTL, &stm_msg, msg_size);
1394 if (err && err != -ENODEV) {
1395 pr_err("diag: In %s, unable to write to socket, peripheral: %d, type: %d, len: %d, err: %d\n",
1396 __func__, peripheral, TYPE_CNTL,
1397 msg_size, err);
1398 }
1399
1400 return err;
1401}
1402
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05301403int diag_send_peripheral_drain_immediate(uint8_t pd,
1404 uint8_t diag_id, int peripheral)
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001405{
1406 int err = 0;
1407 struct diag_ctrl_drain_immediate ctrl_pkt;
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05301408 struct diag_ctrl_drain_immediate_v2 ctrl_pkt_v2;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001409
1410 if (!driver->feature[peripheral].peripheral_buffering) {
1411 pr_debug("diag: In %s, peripheral %d doesn't support buffering\n",
1412 __func__, peripheral);
1413 return -EINVAL;
1414 }
1415
1416 if (!driver->diagfwd_cntl[peripheral] ||
1417 !driver->diagfwd_cntl[peripheral]->ch_open) {
1418 pr_debug("diag: In %s, control channel is not open, p: %d\n",
1419 __func__, peripheral);
1420 return -ENODEV;
1421 }
1422
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05301423 if (diag_id && driver->feature[peripheral].pd_buffering) {
1424 ctrl_pkt_v2.pkt_id = DIAG_CTRL_MSG_PERIPHERAL_BUF_DRAIN_IMM;
1425 /*
1426 * The length of the ctrl pkt is size of version,
1427 * diag_id and stream id
1428 */
1429 ctrl_pkt_v2.len = sizeof(uint32_t) + (2 * sizeof(uint8_t));
1430 ctrl_pkt_v2.version = 2;
1431 ctrl_pkt_v2.diag_id = diag_id;
1432 ctrl_pkt_v2.stream_id = 1;
1433 err = diagfwd_write(peripheral, TYPE_CNTL, &ctrl_pkt_v2,
1434 sizeof(ctrl_pkt_v2));
1435 if (err && err != -ENODEV) {
1436 pr_err("diag: Unable to send drain immediate ctrl packet to peripheral %d, err: %d\n",
1437 peripheral, err);
1438 }
1439 } else {
1440 ctrl_pkt.pkt_id = DIAG_CTRL_MSG_PERIPHERAL_BUF_DRAIN_IMM;
1441 /*
1442 * The length of the ctrl pkt is
1443 * size of version and stream id
1444 */
1445 ctrl_pkt.len = sizeof(uint32_t) + sizeof(uint8_t);
1446 ctrl_pkt.version = 1;
1447 ctrl_pkt.stream_id = 1;
1448 err = diagfwd_write(peripheral, TYPE_CNTL, &ctrl_pkt,
1449 sizeof(ctrl_pkt));
1450 if (err && err != -ENODEV) {
1451 pr_err("diag: Unable to send drain immediate ctrl packet to peripheral %d, err: %d\n",
1452 peripheral, err);
1453 }
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001454 }
1455
1456 return err;
1457}
1458
1459int diag_send_buffering_tx_mode_pkt(uint8_t peripheral,
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05301460 uint8_t diag_id, struct diag_buffering_mode_t *params)
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001461{
1462 int err = 0;
1463 struct diag_ctrl_peripheral_tx_mode ctrl_pkt;
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05301464 struct diag_ctrl_peripheral_tx_mode_v2 ctrl_pkt_v2;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001465
1466 if (!params)
1467 return -EIO;
1468
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05301469 if (peripheral >= NUM_PERIPHERALS) {
1470 pr_err("diag: In %s, invalid peripheral %d\n", __func__,
1471 peripheral);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001472 return -EINVAL;
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05301473 }
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001474
1475 if (!driver->feature[peripheral].peripheral_buffering) {
1476 pr_debug("diag: In %s, peripheral %d doesn't support buffering\n",
1477 __func__, peripheral);
1478 return -EINVAL;
1479 }
1480
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001481 switch (params->mode) {
1482 case DIAG_BUFFERING_MODE_STREAMING:
1483 case DIAG_BUFFERING_MODE_THRESHOLD:
1484 case DIAG_BUFFERING_MODE_CIRCULAR:
1485 break;
1486 default:
1487 pr_err("diag: In %s, invalid tx mode: %d\n", __func__,
1488 params->mode);
1489 return -EINVAL;
1490 }
1491
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05301492 if (diag_id &&
1493 driver->feature[peripheral].pd_buffering) {
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001494
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05301495 ctrl_pkt_v2.pkt_id = DIAG_CTRL_MSG_CONFIG_PERIPHERAL_TX_MODE;
1496 /*
1497 * Control packet length is size of version, diag_id,
1498 * stream_id and tx_mode
1499 */
1500 ctrl_pkt_v2.len = sizeof(uint32_t) + (3 * sizeof(uint8_t));
1501 ctrl_pkt_v2.version = 2;
1502 ctrl_pkt_v2.diag_id = diag_id;
1503 ctrl_pkt_v2.stream_id = 1;
1504 ctrl_pkt_v2.tx_mode = params->mode;
1505
1506 err = diagfwd_write(peripheral, TYPE_CNTL, &ctrl_pkt_v2,
1507 sizeof(ctrl_pkt_v2));
1508 if (err && err != -ENODEV) {
1509 pr_err("diag: Unable to send tx_mode ctrl packet to peripheral %d, err: %d\n",
1510 peripheral, err);
1511 goto fail;
1512 }
1513 } else {
1514 ctrl_pkt.pkt_id = DIAG_CTRL_MSG_CONFIG_PERIPHERAL_TX_MODE;
1515 /*
1516 * Control packet length is size of version,
1517 * stream_id and tx_mode
1518 */
1519 ctrl_pkt.len = sizeof(uint32_t) + (2 * sizeof(uint8_t));
1520 ctrl_pkt.version = 1;
1521 ctrl_pkt.stream_id = 1;
1522 ctrl_pkt.tx_mode = params->mode;
1523
1524 err = diagfwd_write(peripheral, TYPE_CNTL, &ctrl_pkt,
1525 sizeof(ctrl_pkt));
1526 if (err && err != -ENODEV) {
1527 pr_err("diag: Unable to send tx_mode ctrl packet to peripheral %d, err: %d\n",
1528 peripheral, err);
1529 goto fail;
1530 }
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001531 }
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05301532 driver->buffering_mode[params->peripheral].mode = params->mode;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001533
1534fail:
1535 return err;
1536}
1537
1538int diag_send_buffering_wm_values(uint8_t peripheral,
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05301539 uint8_t diag_id, struct diag_buffering_mode_t *params)
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001540{
1541 int err = 0;
1542 struct diag_ctrl_set_wq_val ctrl_pkt;
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05301543 struct diag_ctrl_set_wq_val_v2 ctrl_pkt_v2;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001544
1545 if (!params)
1546 return -EIO;
1547
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05301548 if (peripheral >= NUM_PERIPHERALS) {
1549 pr_err("diag: In %s, invalid peripheral %d\n", __func__,
1550 peripheral);
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001551 return -EINVAL;
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05301552 }
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001553
1554 if (!driver->feature[peripheral].peripheral_buffering) {
1555 pr_debug("diag: In %s, peripheral %d doesn't support buffering\n",
1556 __func__, peripheral);
1557 return -EINVAL;
1558 }
1559
1560 if (!driver->diagfwd_cntl[peripheral] ||
1561 !driver->diagfwd_cntl[peripheral]->ch_open) {
1562 pr_debug("diag: In %s, control channel is not open, p: %d\n",
1563 __func__, peripheral);
1564 return -ENODEV;
1565 }
1566
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001567 switch (params->mode) {
1568 case DIAG_BUFFERING_MODE_STREAMING:
1569 case DIAG_BUFFERING_MODE_THRESHOLD:
1570 case DIAG_BUFFERING_MODE_CIRCULAR:
1571 break;
1572 default:
1573 pr_err("diag: In %s, invalid tx mode: %d\n", __func__,
1574 params->mode);
1575 return -EINVAL;
1576 }
1577
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05301578 if (diag_id &&
1579 driver->feature[peripheral].pd_buffering) {
1580 ctrl_pkt_v2.pkt_id = DIAG_CTRL_MSG_CONFIG_PERIPHERAL_WMQ_VAL;
1581 /*
1582 * Control packet length is size of version, diag_id,
1583 * stream_id and wmq values
1584 */
1585 ctrl_pkt_v2.len = sizeof(uint32_t) + (4 * sizeof(uint8_t));
1586 ctrl_pkt_v2.version = 2;
1587 ctrl_pkt_v2.diag_id = diag_id;
1588 ctrl_pkt_v2.stream_id = 1;
1589 ctrl_pkt_v2.high_wm_val = params->high_wm_val;
1590 ctrl_pkt_v2.low_wm_val = params->low_wm_val;
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001591
Manoj Prabhu Bcba38ed2017-11-08 20:24:46 +05301592 err = diagfwd_write(peripheral, TYPE_CNTL, &ctrl_pkt_v2,
1593 sizeof(ctrl_pkt_v2));
1594 if (err && err != -ENODEV) {
1595 pr_err("diag: Unable to send watermark values to peripheral %d, err: %d\n",
1596 peripheral, err);
1597 }
1598 } else {
1599 ctrl_pkt.pkt_id = DIAG_CTRL_MSG_CONFIG_PERIPHERAL_WMQ_VAL;
1600 /*
1601 * Control packet length is size of version,
1602 * stream_id and wmq values
1603 */
1604 ctrl_pkt.len = sizeof(uint32_t) + (3 * sizeof(uint8_t));
1605 ctrl_pkt.version = 1;
1606 ctrl_pkt.stream_id = 1;
1607 ctrl_pkt.high_wm_val = params->high_wm_val;
1608 ctrl_pkt.low_wm_val = params->low_wm_val;
1609
1610 err = diagfwd_write(peripheral, TYPE_CNTL, &ctrl_pkt,
1611 sizeof(ctrl_pkt));
1612 if (err && err != -ENODEV) {
1613 pr_err("diag: Unable to send watermark values to peripheral %d, err: %d\n",
1614 peripheral, err);
1615 }
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001616 }
Sreelakshmi Gownipallicb8893d2016-10-19 16:02:34 -07001617 return err;
1618}
1619
1620int diagfwd_cntl_init(void)
1621{
1622 uint8_t peripheral = 0;
1623
1624 reg_dirty = 0;
1625 driver->polling_reg_flag = 0;
1626 driver->log_on_demand_support = 1;
1627 driver->stm_peripheral = 0;
1628 driver->close_transport = 0;
1629 for (peripheral = 0; peripheral < NUM_PERIPHERALS; peripheral++)
1630 driver->buffering_flag[peripheral] = 0;
1631
1632 mutex_init(&driver->cntl_lock);
1633 INIT_WORK(&(driver->stm_update_work), diag_stm_update_work_fn);
1634 INIT_WORK(&(driver->mask_update_work), diag_mask_update_work_fn);
1635 INIT_WORK(&(driver->close_transport_work),
1636 diag_close_transport_work_fn);
1637
1638 driver->cntl_wq = create_singlethread_workqueue("diag_cntl_wq");
1639 if (!driver->cntl_wq)
1640 return -ENOMEM;
1641
1642 return 0;
1643}
1644
1645void diagfwd_cntl_channel_init(void)
1646{
1647 uint8_t peripheral;
1648
1649 for (peripheral = 0; peripheral < NUM_PERIPHERALS; peripheral++) {
1650 diagfwd_early_open(peripheral);
1651 diagfwd_open(peripheral, TYPE_CNTL);
1652 }
1653}
1654
1655void diagfwd_cntl_exit(void)
1656{
1657 if (driver->cntl_wq)
1658 destroy_workqueue(driver->cntl_wq);
1659}