summaryrefslogtreecommitdiff
path: root/drivers/char/diag
diff options
context:
space:
mode:
authorManoj Prabhu B <bmanoj@codeaurora.org>2018-03-14 14:53:52 +0530
committerGerrit - the friendly Code Review server <code-review@localhost>2018-03-20 21:35:06 -0700
commit43f15aca94921ffa8c56bc417f014ef01436f203 (patch)
tree412cd603e312c1aa17c1617537b08de3445d17ee /drivers/char/diag
parentbb9c0e0ec85aa211716bff72ae378e0c87dae4a2 (diff)
diag: Remove hdlc status dependeny on session_info
The patch removes the hdlc status dependency on session_info protected by md_session_lock inserting delay in processing data off peripheral. CRs-Fixed: 2193991 Change-Id: Ia79c0efe82803c15ccae42b00d95258f52242eee Signed-off-by: Manoj Prabhu B <bmanoj@codeaurora.org>
Diffstat (limited to 'drivers/char/diag')
-rw-r--r--drivers/char/diag/diagchar.h5
-rw-r--r--drivers/char/diag/diagchar_core.c99
-rw-r--r--drivers/char/diag/diagfwd.c146
-rw-r--r--drivers/char/diag/diagfwd_peripheral.c22
4 files changed, 218 insertions, 54 deletions
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index 75080f0d4c39..afea5f40bfee 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2008-2018, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -580,6 +580,7 @@ struct diagchar_dev {
/* buffer for updating mask to peripherals */
unsigned char *buf_feature_mask_update;
uint8_t hdlc_disabled;
+ uint8_t p_hdlc_disabled[NUM_MD_SESSIONS];
struct mutex hdlc_disable_mutex;
struct mutex hdlc_recovery_mutex;
struct timer_list hdlc_reset_timer;
@@ -604,6 +605,7 @@ struct diagchar_dev {
struct work_struct diag_drain_work;
struct work_struct update_user_clients;
struct work_struct update_md_clients;
+ struct work_struct diag_hdlc_reset_work;
struct workqueue_struct *diag_cntl_wq;
uint8_t log_on_demand_support;
uint8_t *apps_req_buf;
@@ -683,5 +685,6 @@ void diag_record_stats(int type, int flag);
struct diag_md_session_t *diag_md_session_get_pid(int pid);
struct diag_md_session_t *diag_md_session_get_peripheral(uint8_t peripheral);
+int diag_md_session_match_pid_peripheral(int pid, uint8_t peripheral);
#endif
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index ed982f426923..be7a565ca04e 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -252,18 +252,13 @@ static void diag_update_md_client_work_fn(struct work_struct *work)
void diag_drain_work_fn(struct work_struct *work)
{
- struct diag_md_session_t *session_info = NULL;
uint8_t hdlc_disabled = 0;
timer_in_progress = 0;
mutex_lock(&apps_data_mutex);
- mutex_lock(&driver->md_session_lock);
- session_info = diag_md_session_get_peripheral(APPS_DATA);
- if (session_info)
- hdlc_disabled = session_info->hdlc_disabled;
- else
- hdlc_disabled = driver->hdlc_disabled;
- mutex_unlock(&driver->md_session_lock);
+ mutex_lock(&driver->hdlc_disable_mutex);
+ hdlc_disabled = driver->p_hdlc_disabled[APPS_DATA];
+ mutex_unlock(&driver->hdlc_disable_mutex);
if (!hdlc_disabled)
diag_drain_apps_data(&hdlc_data);
else
@@ -1029,7 +1024,6 @@ static int diag_send_raw_data_remote(int proc, void *buf, int len,
struct diag_send_desc_type send = { NULL, NULL, DIAG_STATE_START, 0 };
struct diag_hdlc_dest_type enc = { NULL, NULL, 0 };
int bridge_index = proc - 1;
- struct diag_md_session_t *session_info = NULL;
uint8_t hdlc_disabled = 0;
if (!buf)
@@ -1055,13 +1049,9 @@ static int diag_send_raw_data_remote(int proc, void *buf, int len,
if (driver->hdlc_encode_buf_len != 0)
return -EAGAIN;
- mutex_lock(&driver->md_session_lock);
- session_info = diag_md_session_get_peripheral(APPS_DATA);
- if (session_info)
- hdlc_disabled = session_info->hdlc_disabled;
- else
- hdlc_disabled = driver->hdlc_disabled;
- mutex_unlock(&driver->md_session_lock);
+ mutex_lock(&driver->hdlc_disable_mutex);
+ hdlc_disabled = driver->p_hdlc_disabled[APPS_DATA];
+ mutex_unlock(&driver->hdlc_disable_mutex);
if (hdlc_disabled) {
if (len < 4) {
pr_err("diag: In %s, invalid len: %d of non_hdlc pkt",
@@ -1483,6 +1473,43 @@ struct diag_md_session_t *diag_md_session_get_peripheral(uint8_t peripheral)
return driver->md_session_map[peripheral];
}
+/*
+ * diag_md_session_match_pid_peripheral
+ *
+ * 1. Pass valid PID and get all the peripherals in logging session
+ * for that PID
+ * 2. Pass valid Peipheral and get the pid logging for that peripheral
+ *
+ */
+
+int diag_md_session_match_pid_peripheral(int pid,
+ uint8_t peripheral)
+{
+ int i, flag = 0;
+
+ if (pid <= 0 || peripheral >= NUM_MD_SESSIONS)
+ return -EINVAL;
+
+ if (!peripheral) {
+ for (i = 0; i < NUM_MD_SESSIONS; i++) {
+ if (driver->md_session_map[i] &&
+ driver->md_session_map[i]->pid == pid) {
+ peripheral |= 1 << i;
+ flag = 1;
+ }
+ }
+ if (flag)
+ return peripheral;
+ }
+
+ if (!pid) {
+ if (driver->md_session_map[peripheral])
+ return driver->md_session_map[peripheral]->pid;
+ }
+
+ return -EINVAL;
+}
+
static int diag_md_peripheral_switch(int pid,
int peripheral_mask, int req_mode) {
int i, bit = 0;
@@ -1637,6 +1664,13 @@ static int diag_md_session_check(int curr_mode, int req_mode,
}
err = diag_md_session_create(DIAG_MD_PERIPHERAL,
param->peripheral_mask, DIAG_LOCAL_PROC);
+ mutex_lock(&driver->hdlc_disable_mutex);
+ for (i = 0; i < NUM_MD_SESSIONS; i++) {
+ if ((param->peripheral_mask > 0) &&
+ (param->peripheral_mask & (1 << i)))
+ driver->p_hdlc_disabled[i] = 0;
+ }
+ mutex_unlock(&driver->hdlc_disable_mutex);
}
*change_mode = 1;
return err;
@@ -2085,11 +2119,14 @@ static int diag_ioctl_dci_support(unsigned long ioarg)
static int diag_ioctl_hdlc_toggle(unsigned long ioarg)
{
- uint8_t hdlc_support;
+ uint8_t hdlc_support, i;
+ int peripheral = -EINVAL;
struct diag_md_session_t *session_info = NULL;
+
if (copy_from_user(&hdlc_support, (void __user *)ioarg,
sizeof(uint8_t)))
return -EFAULT;
+
mutex_lock(&driver->hdlc_disable_mutex);
mutex_lock(&driver->md_session_lock);
session_info = diag_md_session_get_pid(current->tgid);
@@ -2097,6 +2134,25 @@ static int diag_ioctl_hdlc_toggle(unsigned long ioarg)
session_info->hdlc_disabled = hdlc_support;
else
driver->hdlc_disabled = hdlc_support;
+
+ peripheral =
+ diag_md_session_match_pid_peripheral(current->tgid,
+ 0);
+ for (i = 0; i < NUM_MD_SESSIONS; i++) {
+ if (peripheral > 0 && session_info) {
+ if (peripheral & (1 << i))
+ driver->p_hdlc_disabled[i] =
+ session_info->hdlc_disabled;
+ else if (!diag_md_session_get_peripheral(i))
+ driver->p_hdlc_disabled[i] =
+ driver->hdlc_disabled;
+ } else {
+ if (!diag_md_session_get_peripheral(i))
+ driver->p_hdlc_disabled[i] =
+ driver->hdlc_disabled;
+ }
+ }
+
mutex_unlock(&driver->md_session_lock);
mutex_unlock(&driver->hdlc_disable_mutex);
diag_update_md_clients(HDLC_SUPPORT_TYPE);
@@ -2970,7 +3026,6 @@ static int diag_user_process_apps_data(const char __user *buf, int len,
int stm_size = 0;
const int mempool = POOL_TYPE_COPY;
unsigned char *user_space_data = NULL;
- struct diag_md_session_t *session_info = NULL;
uint8_t hdlc_disabled;
if (!buf || len <= 0 || len > DIAG_MAX_RSP_SIZE) {
@@ -3024,13 +3079,7 @@ static int diag_user_process_apps_data(const char __user *buf, int len,
mutex_lock(&apps_data_mutex);
mutex_lock(&driver->hdlc_disable_mutex);
- mutex_lock(&driver->md_session_lock);
- session_info = diag_md_session_get_peripheral(APPS_DATA);
- if (session_info)
- hdlc_disabled = session_info->hdlc_disabled;
- else
- hdlc_disabled = driver->hdlc_disabled;
- mutex_unlock(&driver->md_session_lock);
+ hdlc_disabled = driver->p_hdlc_disabled[APPS_DATA];
if (hdlc_disabled)
ret = diag_process_apps_data_non_hdlc(user_space_data, len,
pkt_type);
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index f6027ae96833..c7b46304dc84 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -49,6 +49,11 @@
#define STM_RSP_STATUS_INDEX 8
#define STM_RSP_NUM_BYTES 9
+struct diag_md_hdlc_reset_work {
+ int pid;
+ struct work_struct work;
+};
+
static int timestamp_switch;
module_param(timestamp_switch, int, 0644);
@@ -436,6 +441,7 @@ static void diag_send_rsp(unsigned char *buf, int len, int pid)
{
struct diag_md_session_t *session_info = NULL, *info = NULL;
uint8_t hdlc_disabled;
+
mutex_lock(&driver->md_session_lock);
info = diag_md_session_get_pid(pid);
session_info = (info) ? info :
@@ -445,6 +451,7 @@ static void diag_send_rsp(unsigned char *buf, int len, int pid)
else
hdlc_disabled = driver->hdlc_disabled;
mutex_unlock(&driver->md_session_lock);
+
if (hdlc_disabled)
pack_rsp_and_send(buf, len, pid);
else
@@ -948,7 +955,7 @@ void diag_send_error_rsp(unsigned char *buf, int len,
int diag_process_apps_pkt(unsigned char *buf, int len, int pid)
{
int i, p_mask = 0;
- int mask_ret;
+ int mask_ret, peripheral = -EINVAL;
int write_len = 0;
unsigned char *temp = NULL;
struct diag_cmd_reg_entry_t entry;
@@ -1175,6 +1182,22 @@ int diag_process_apps_pkt(unsigned char *buf, int len, int pid)
info->hdlc_disabled = 1;
else
driver->hdlc_disabled = 1;
+ peripheral =
+ diag_md_session_match_pid_peripheral(pid, 0);
+ for (i = 0; i < NUM_MD_SESSIONS; i++) {
+ if (peripheral > 0 && info) {
+ if (peripheral & (1 << i))
+ driver->p_hdlc_disabled[i] =
+ info->hdlc_disabled;
+ else if (!diag_md_session_get_peripheral(i))
+ driver->p_hdlc_disabled[i] =
+ driver->hdlc_disabled;
+ } else {
+ if (!diag_md_session_get_peripheral(i))
+ driver->p_hdlc_disabled[i] =
+ driver->hdlc_disabled;
+ }
+ }
mutex_unlock(&driver->md_session_lock);
diag_update_md_clients(HDLC_SUPPORT_TYPE);
mutex_unlock(&driver->hdlc_disable_mutex);
@@ -1350,8 +1373,17 @@ static int diagfwd_mux_close(int id, int mode)
pr_debug("diag: In %s, re-enabling HDLC encoding\n",
__func__);
mutex_lock(&driver->hdlc_disable_mutex);
- if (driver->md_session_mode == DIAG_MD_NONE)
+ if (driver->md_session_mode == DIAG_MD_NONE) {
driver->hdlc_disabled = 0;
+ /*
+ * HDLC encoding is re-enabled when
+ * there is logical/physical disconnection of diag
+ * to USB.
+ */
+ for (i = 0; i < NUM_MD_SESSIONS; i++)
+ driver->p_hdlc_disabled[i] =
+ driver->hdlc_disabled;
+ }
mutex_unlock(&driver->hdlc_disable_mutex);
queue_work(driver->diag_wq,
&(driver->update_user_clients));
@@ -1366,6 +1398,7 @@ static uint8_t hdlc_reset;
static void hdlc_reset_timer_start(int pid)
{
struct diag_md_session_t *info = NULL;
+
mutex_lock(&driver->md_session_lock);
info = diag_md_session_get_pid(pid);
if (!hdlc_timer_in_progress) {
@@ -1380,30 +1413,99 @@ static void hdlc_reset_timer_start(int pid)
mutex_unlock(&driver->md_session_lock);
}
+/*
+ * diag_timer_work_fn
+ * Queued in workqueue to protect md_session_info structure
+ *
+ * Update hdlc_disabled for each peripheral
+ * which are not in any md_session_info.
+ *
+ */
+static void diag_timer_work_fn(struct work_struct *work)
+{
+ int i = 0;
+ struct diag_md_session_t *session_info = NULL;
+
+ mutex_lock(&driver->hdlc_disable_mutex);
+ driver->hdlc_disabled = 0;
+ mutex_lock(&driver->md_session_lock);
+ for (i = 0; i < NUM_MD_SESSIONS; i++) {
+ session_info = diag_md_session_get_peripheral(i);
+ if (!session_info)
+ driver->p_hdlc_disabled[i] =
+ driver->hdlc_disabled;
+ }
+ mutex_unlock(&driver->md_session_lock);
+ mutex_unlock(&driver->hdlc_disable_mutex);
+}
+
+/*
+ * diag_md_timer_work_fn
+ * Queued in workqueue to protect md_session_info structure
+ *
+ * Update hdlc_disabled for each peripheral
+ * which are in any md_session_info
+ *
+ */
+static void diag_md_timer_work_fn(struct work_struct *work)
+{
+ int peripheral = -EINVAL, i = 0;
+ struct diag_md_session_t *session_info = NULL;
+ struct diag_md_hdlc_reset_work *hdlc_work = container_of(work,
+ struct diag_md_hdlc_reset_work, work);
+
+ if (!hdlc_work)
+ return;
+
+ mutex_lock(&driver->hdlc_disable_mutex);
+ mutex_lock(&driver->md_session_lock);
+ session_info = diag_md_session_get_pid(hdlc_work->pid);
+ if (session_info)
+ session_info->hdlc_disabled = 0;
+ peripheral =
+ diag_md_session_match_pid_peripheral(hdlc_work->pid, 0);
+ if (peripheral > 0 && session_info) {
+ for (i = 0; i < NUM_MD_SESSIONS; i++) {
+ if (peripheral & (1 << i))
+ driver->p_hdlc_disabled[i] =
+ session_info->hdlc_disabled;
+ }
+ }
+ kfree(hdlc_work);
+ mutex_unlock(&driver->md_session_lock);
+ mutex_unlock(&driver->hdlc_disable_mutex);
+}
+
static void hdlc_reset_timer_func(unsigned long data)
{
pr_debug("diag: In %s, re-enabling HDLC encoding\n",
__func__);
+
if (hdlc_reset) {
- driver->hdlc_disabled = 0;
- queue_work(driver->diag_wq,
- &(driver->update_user_clients));
+ queue_work(driver->diag_wq, &(driver->diag_hdlc_reset_work));
+ queue_work(driver->diag_wq, &(driver->update_user_clients));
}
hdlc_timer_in_progress = 0;
}
void diag_md_hdlc_reset_timer_func(unsigned long pid)
{
- struct diag_md_session_t *session_info = NULL;
+ struct diag_md_hdlc_reset_work *hdlc_reset_work = NULL;
pr_debug("diag: In %s, re-enabling HDLC encoding\n",
__func__);
+ hdlc_reset_work = kmalloc(sizeof(*hdlc_reset_work), GFP_ATOMIC);
+ if (!hdlc_reset_work) {
+ DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+ "diag: Could not allocate hdlc_reset_work\n");
+ hdlc_timer_in_progress = 0;
+ return;
+ }
if (hdlc_reset) {
- session_info = diag_md_session_get_pid(pid);
- if (session_info)
- session_info->hdlc_disabled = 0;
- queue_work(driver->diag_wq,
- &(driver->update_md_clients));
+ hdlc_reset_work->pid = pid;
+ INIT_WORK(&hdlc_reset_work->work, diag_md_timer_work_fn);
+ queue_work(driver->diag_wq, &(hdlc_reset_work->work));
+ queue_work(driver->diag_wq, &(driver->update_md_clients));
}
hdlc_timer_in_progress = 0;
}
@@ -1411,7 +1513,7 @@ void diag_md_hdlc_reset_timer_func(unsigned long pid)
static void diag_hdlc_start_recovery(unsigned char *buf, int len,
int pid)
{
- int i;
+ int i, peripheral = -EINVAL;
static uint32_t bad_byte_counter;
unsigned char *start_ptr = NULL;
struct diag_pkt_frame_t *actual_pkt = NULL;
@@ -1443,6 +1545,24 @@ static void diag_hdlc_start_recovery(unsigned char *buf, int len,
info->hdlc_disabled = 0;
else
driver->hdlc_disabled = 0;
+
+ peripheral =
+ diag_md_session_match_pid_peripheral(pid, 0);
+ for (i = 0; i < NUM_MD_SESSIONS; i++) {
+ if (peripheral > 0 && info) {
+ if (peripheral & (1 << i))
+ driver->p_hdlc_disabled[i] =
+ info->hdlc_disabled;
+ else if (
+ !diag_md_session_get_peripheral(i))
+ driver->p_hdlc_disabled[i] =
+ driver->hdlc_disabled;
+ } else {
+ if (!diag_md_session_get_peripheral(i))
+ driver->p_hdlc_disabled[i] =
+ driver->hdlc_disabled;
+ }
+ }
mutex_unlock(&driver->md_session_lock);
mutex_unlock(&driver->hdlc_disable_mutex);
diag_update_md_clients(HDLC_SUPPORT_TYPE);
@@ -1700,6 +1820,8 @@ int diagfwd_init(void)
INIT_LIST_HEAD(&driver->cmd_reg_list);
driver->cmd_reg_count = 0;
mutex_init(&driver->cmd_reg_mutex);
+ INIT_WORK(&(driver->diag_hdlc_reset_work),
+ diag_timer_work_fn);
for (i = 0; i < NUM_PERIPHERALS; i++) {
driver->feature[i].separate_cmd_rsp = 0;
diff --git a/drivers/char/diag/diagfwd_peripheral.c b/drivers/char/diag/diagfwd_peripheral.c
index a7abe3dafb69..6b74c0056d1b 100644
--- a/drivers/char/diag/diagfwd_peripheral.c
+++ b/drivers/char/diag/diagfwd_peripheral.c
@@ -284,7 +284,6 @@ static void diagfwd_data_process_done(struct diagfwd_info *fwd_info,
int err = 0;
int write_len = 0, peripheral = 0;
unsigned char *write_buf = NULL;
- struct diag_md_session_t *session_info = NULL;
uint8_t hdlc_disabled = 0;
if (!fwd_info || !buf || len <= 0) {
@@ -316,13 +315,9 @@ static void diagfwd_data_process_done(struct diagfwd_info *fwd_info,
diag_ws_release();
return;
}
- mutex_lock(&driver->md_session_lock);
- session_info = diag_md_session_get_peripheral(peripheral);
- if (session_info)
- hdlc_disabled = session_info->hdlc_disabled;
- else
- hdlc_disabled = driver->hdlc_disabled;
- mutex_unlock(&driver->md_session_lock);
+
+ hdlc_disabled = driver->p_hdlc_disabled[peripheral];
+
if (hdlc_disabled) {
/* The data is raw and and on APPS side HDLC is disabled */
if (!buf) {
@@ -615,7 +610,6 @@ static void diagfwd_data_read_done(struct diagfwd_info *fwd_info,
int write_len = 0;
unsigned char *write_buf = NULL;
struct diagfwd_buf_t *temp_buf = NULL;
- struct diag_md_session_t *session_info = NULL;
uint8_t hdlc_disabled = 0;
if (!fwd_info || !buf || len <= 0) {
@@ -637,13 +631,9 @@ static void diagfwd_data_read_done(struct diagfwd_info *fwd_info,
mutex_lock(&driver->hdlc_disable_mutex);
mutex_lock(&fwd_info->data_mutex);
- mutex_lock(&driver->md_session_lock);
- session_info = diag_md_session_get_peripheral(fwd_info->peripheral);
- if (session_info)
- hdlc_disabled = session_info->hdlc_disabled;
- else
- hdlc_disabled = driver->hdlc_disabled;
- mutex_unlock(&driver->md_session_lock);
+
+ hdlc_disabled = driver->p_hdlc_disabled[fwd_info->peripheral];
+
if (!driver->feature[fwd_info->peripheral].encode_hdlc) {
if (fwd_info->buf_1 && fwd_info->buf_1->data == buf) {
temp_buf = fwd_info->buf_1;