summaryrefslogtreecommitdiff
path: root/drivers/char/diag/diagfwd.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char/diag/diagfwd.c')
-rw-r--r--drivers/char/diag/diagfwd.c124
1 files changed, 85 insertions, 39 deletions
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index 7c444fada73d..915568442e69 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -62,45 +62,6 @@ struct diag_master_table entry;
int wrap_enabled;
uint16_t wrap_count;
-void encode_rsp_and_send(int buf_length)
-{
- struct diag_send_desc_type send = { NULL, NULL, DIAG_STATE_START, 0 };
- struct diag_hdlc_dest_type enc = { NULL, NULL, 0 };
- struct diag_smd_info *data = &(driver->smd_data[MODEM_DATA]);
- int err;
- unsigned long flags;
-
- if (buf_length > APPS_BUF_SIZE) {
- pr_err("diag: In %s, invalid len %d, permissible len %d\n",
- __func__, buf_length, APPS_BUF_SIZE);
- return;
- }
-
- send.state = DIAG_STATE_START;
- send.pkt = driver->apps_rsp_buf;
- send.last = (void *)(driver->apps_rsp_buf + buf_length);
- send.terminate = 1;
- if (!data->in_busy_1) {
- spin_lock_irqsave(&data->in_busy_lock, flags);
- enc.dest = data->buf_in_1;
- enc.dest_last = (void *)(data->buf_in_1 + APPS_BUF_SIZE - 1);
- diag_hdlc_encode(&send, &enc);
- data->write_ptr_1->buf = data->buf_in_1;
- data->write_ptr_1->length = (int)(enc.dest -
- (void *)(data->buf_in_1));
- data->in_busy_1 = 1;
- err = diag_device_write(data->buf_in_1, data->peripheral,
- data->write_ptr_1);
- if (err) {
- pr_err("diag: In %s, Unable to write to device, err: %d\n",
- __func__, err);
- data->in_busy_1 = 0;
- }
- memset(driver->apps_rsp_buf, '\0', APPS_BUF_SIZE);
- spin_unlock_irqrestore(&data->in_busy_lock, flags);
- }
-}
-
/* Determine if this device uses a device tree */
#ifdef CONFIG_OF
static int has_device_tree(void)
@@ -868,6 +829,68 @@ static int diag_write_to_usb(struct usb_diag_ch *ch,
}
#endif
+void encode_rsp_and_send(int buf_length)
+{
+ struct diag_send_desc_type send = { NULL, NULL, DIAG_STATE_START, 0 };
+ struct diag_hdlc_dest_type enc = { NULL, NULL, 0 };
+ unsigned char *rsp_ptr = driver->encoded_rsp_buf;
+ int err, retry_count = 0;
+ unsigned long flags;
+
+ if (!rsp_ptr)
+ return;
+
+ if (buf_length > APPS_BUF_SIZE || buf_length <= 0) {
+ pr_err("diag: In %s, invalid len %d, permissible len %d\n",
+ __func__, buf_length, APPS_BUF_SIZE);
+ return;
+ }
+
+ /*
+ * Keep trying till we get the buffer back. It should probably
+ * take one or two iterations. When this loops till UINT_MAX, it
+ * means we did not get a write complete for the previous
+ * response.
+ */
+ while (retry_count < UINT_MAX) {
+ if (!driver->rsp_buf_busy)
+ break;
+ /*
+ * Wait for sometime and try again. The value 10000 was chosen
+ * empirically as an optimum value for USB to complete a write
+ */
+ usleep_range(10000, 10100);
+ retry_count++;
+ }
+ if (driver->rsp_buf_busy) {
+ pr_err("diag: unable to get hold of response buffer\n");
+ return;
+ }
+
+ spin_lock_irqsave(&driver->rsp_buf_busy_lock, flags);
+ driver->rsp_buf_busy = 1;
+ spin_unlock_irqrestore(&driver->rsp_buf_busy_lock, flags);
+ send.state = DIAG_STATE_START;
+ send.pkt = driver->apps_rsp_buf;
+ send.last = (void *)(driver->apps_rsp_buf + buf_length);
+ send.terminate = 1;
+ enc.dest = rsp_ptr;
+ enc.dest_last = (void *)(rsp_ptr + HDLC_OUT_BUF_SIZE - 1);
+ diag_hdlc_encode(&send, &enc);
+ driver->rsp_write_ptr->buf = rsp_ptr;
+ driver->rsp_write_ptr->length = (int)(enc.dest - (void *)rsp_ptr);
+ err = diag_write_to_usb(driver->legacy_ch, driver->rsp_write_ptr);
+ if (err) {
+ pr_err("diag: In %s, Unable to write to device, err: %d\n",
+ __func__, err);
+ spin_lock_irqsave(&driver->rsp_buf_busy_lock, flags);
+ driver->rsp_buf_busy = 0;
+ spin_unlock_irqrestore(&driver->rsp_buf_busy_lock, flags);
+ }
+ memset(driver->apps_rsp_buf, '\0', APPS_BUF_SIZE);
+
+}
+
int diag_device_write(void *buf, int data_type, struct diag_request *write_ptr)
{
int i, err = 0, index;
@@ -2035,6 +2058,7 @@ int diagfwd_write_complete(struct diag_request *diag_write_ptr)
{
unsigned char *buf = diag_write_ptr->buf;
int found_it = 0;
+ unsigned long flags;
/* Determine if the write complete is for data from modem/apps/q6 */
found_it = diagfwd_check_buf_match(NUM_SMD_DATA_CHANNELS,
@@ -2044,6 +2068,13 @@ int diagfwd_write_complete(struct diag_request *diag_write_ptr)
found_it = diagfwd_check_buf_match(NUM_SMD_CMD_CHANNELS,
driver->smd_cmd, buf);
+ if (!found_it && buf == (void *)driver->rsp_write_ptr->buf) {
+ found_it = 1;
+ spin_lock_irqsave(&driver->rsp_buf_busy_lock, flags);
+ driver->rsp_buf_busy = 0;
+ spin_unlock_irqrestore(&driver->rsp_buf_busy_lock, flags);
+ }
+
if (!found_it) {
if (driver->logging_mode != USB_MODE)
pr_debug("diag: freeing buffer when not in usb mode\n");
@@ -2573,6 +2604,17 @@ int diagfwd_init(void)
driver->supports_apps_hdlc_encoding = 1;
mutex_init(&driver->diag_hdlc_mutex);
mutex_init(&driver->diag_cntl_mutex);
+ driver->encoded_rsp_buf = kzalloc(HDLC_OUT_BUF_SIZE, GFP_KERNEL);
+ if (!driver->encoded_rsp_buf)
+ goto err;
+ kmemleak_not_leak(driver->encoded_rsp_buf);
+ driver->rsp_buf_busy = 0;
+ driver->rsp_write_ptr = kzalloc(sizeof(struct diag_request),
+ GFP_KERNEL);
+ if (!driver->rsp_write_ptr)
+ goto err;
+ kmemleak_not_leak(driver->rsp_write_ptr);
+ spin_lock_init(&driver->rsp_buf_busy_lock);
for (i = 0; i < NUM_SMD_CONTROL_CHANNELS; i++) {
driver->separate_cmdrsp[i] = 0;
@@ -2703,6 +2745,8 @@ err:
for (i = 0; i < NUM_SMD_CMD_CHANNELS; i++)
diag_smd_destructor(&driver->smd_cmd[i]);
+ kfree(driver->encoded_rsp_buf);
+ kfree(driver->rsp_write_ptr);
kfree(driver->buf_msg_mask_update);
kfree(driver->buf_log_mask_update);
kfree(driver->buf_event_mask_update);
@@ -2745,6 +2789,8 @@ void diagfwd_exit(void)
}
}
+ kfree(driver->encoded_rsp_buf);
+ kfree(driver->rsp_write_ptr);
kfree(driver->buf_msg_mask_update);
kfree(driver->buf_log_mask_update);
kfree(driver->buf_event_mask_update);