Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9d92106b authored by Ravi Aravamudhan's avatar Ravi Aravamudhan
Browse files

diag: Create separate buffer for command responses



Diag driver was using an exisiting SMD Modem buffer for encoding
command responses. Make changes to add a new buffer to avoid
stomping on modem data.

Change-Id: I88ad0a2785dd8eef74f7a866bf9b3525d371e1f7
Signed-off-by: default avatarRavi Aravamudhan <aravamud@codeaurora.org>
parent 78025e56
Loading
Loading
Loading
Loading
+4 −2
Original line number Diff line number Diff line
@@ -109,7 +109,8 @@ static ssize_t diag_dbgfs_read_status(struct file *file, char __user *ubuf,
		"Received Feature mask from Modem: %d\n"
		"Received Feature mask from LPASS: %d\n"
		"Received Feature mask from WCNSS: %d\n"
		"logging_mode: %d\n",
		"logging_mode: %d\n"
		"rsp_in_busy: %d\n",
		driver->smd_data[MODEM_DATA].ch,
		driver->smd_data[LPASS_DATA].ch,
		driver->smd_data[WCNSS_DATA].ch,
@@ -178,7 +179,8 @@ static ssize_t diag_dbgfs_read_status(struct file *file, char __user *ubuf,
		driver->rcvd_feature_mask[MODEM_DATA],
		driver->rcvd_feature_mask[LPASS_DATA],
		driver->rcvd_feature_mask[WCNSS_DATA],
		driver->logging_mode);
		driver->logging_mode,
		driver->rsp_buf_busy);

#ifdef CONFIG_DIAG_OVER_USB
	ret += scnprintf(buf+ret, buf_size-ret,
+5 −0
Original line number Diff line number Diff line
@@ -404,6 +404,11 @@ struct diagchar_dev {
	struct diag_ctrl_msg_mask *msg_mask;
	struct diag_ctrl_feature_mask *feature_mask;
	struct mutex log_mask_mutex;
	/* Members for Sending response */
	unsigned char *encoded_rsp_buf;
	uint8_t rsp_buf_busy;
	struct diag_request *rsp_write_ptr;
	spinlock_t rsp_buf_busy_lock;
	/* State for diag forwarding */
	struct diag_smd_info smd_data[NUM_SMD_DATA_CHANNELS];
	struct diag_smd_info smd_cntl[NUM_SMD_CONTROL_CHANNELS];
+85 −39
Original line number Diff line number Diff line
@@ -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);