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

Commit 9dd88d96 authored by Manoj Prabhu B's avatar Manoj Prabhu B
Browse files

diag: Synchronize rpmsg read and write



Use per peripheral channel_mutex to synchronize the rpmsg read
and write to avoid race condition and use per channel and per
peripheral buffers effectively.

Change-Id: Ida08db6776f03cb729a24b15b445fd726e25a153
Signed-off-by: default avatarManoj Prabhu B <bmanoj@codeaurora.org>
parent 59c32a06
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -41,6 +41,10 @@

#define MAX_SSID_PER_RANGE	200

#define NUM_CHANNEL_BUFFERS		2
#define BUF_1_INDEX		0
#define BUF_2_INDEX		1

#define ALL_PROC		-1

#define REMOTE_DATA		4
+26 −7
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
/* Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
 */
#include <linux/slab.h>
#include <linux/err.h>
@@ -746,8 +746,10 @@ static void diagfwd_cntl_read_done(struct diagfwd_info *fwd_info,
	 */
	diag_ws_on_copy_fail(DIAG_WS_MUX);
	/* Reset the buffer in_busy value after processing the data */
	if (fwd_info->buf_1)
	if (fwd_info->buf_1) {
		atomic_set(&fwd_info->buf_1->in_busy, 0);
		fwd_info->buffer_status[BUF_1_INDEX] = 0;
	}

	diagfwd_queue_read(fwd_info);
	diagfwd_queue_read(&peripheral_info[TYPE_DATA][fwd_info->peripheral]);
@@ -772,8 +774,10 @@ static void diagfwd_dci_read_done(struct diagfwd_info *fwd_info,

	diag_dci_process_peripheral_data(fwd_info, (void *)buf, len);
	/* Reset the buffer in_busy value after processing the data */
	if (fwd_info->buf_1)
	if (fwd_info->buf_1) {
		atomic_set(&fwd_info->buf_1->in_busy, 0);
		fwd_info->buffer_status[BUF_1_INDEX] = 0;
	}

	diagfwd_queue_read(fwd_info);
}
@@ -785,15 +789,22 @@ static void diagfwd_reset_buffers(struct diagfwd_info *fwd_info,
		return;

	if (!driver->feature[fwd_info->peripheral].encode_hdlc) {
		if (fwd_info->buf_1 && fwd_info->buf_1->data == buf)
		if (fwd_info->buf_1 && fwd_info->buf_1->data == buf) {
			atomic_set(&fwd_info->buf_1->in_busy, 0);
		else if (fwd_info->buf_2 && fwd_info->buf_2->data == buf)
			fwd_info->buffer_status[BUF_1_INDEX] = 0;
		} else if (fwd_info->buf_2 && fwd_info->buf_2->data == buf) {
			atomic_set(&fwd_info->buf_2->in_busy, 0);
			fwd_info->buffer_status[BUF_2_INDEX] = 0;
		}
	} else {
		if (fwd_info->buf_1 && fwd_info->buf_1->data_raw == buf)
		if (fwd_info->buf_1 && fwd_info->buf_1->data_raw == buf) {
			atomic_set(&fwd_info->buf_1->in_busy, 0);
		else if (fwd_info->buf_2 && fwd_info->buf_2->data_raw == buf)
			fwd_info->buffer_status[BUF_1_INDEX] = 0;
		} else if (fwd_info->buf_2 &&
			fwd_info->buf_2->data_raw == buf) {
			atomic_set(&fwd_info->buf_2->in_busy, 0);
			fwd_info->buffer_status[BUF_2_INDEX] = 0;
		}
	}
	if (fwd_info->buf_1 && !atomic_read(&(fwd_info->buf_1->in_busy))) {
		DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
@@ -1181,12 +1192,14 @@ static void __diag_fwd_open(struct diagfwd_info *fwd_info)
	if (driver->logging_mode != DIAG_USB_MODE) {
		if (fwd_info->buf_1) {
			atomic_set(&fwd_info->buf_1->in_busy, 0);
			fwd_info->buffer_status[BUF_1_INDEX] = 0;
			DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
			"Buffer 1 for core PD is marked free, p: %d, t: %d\n",
			fwd_info->peripheral, fwd_info->type);
		}
		if (fwd_info->buf_2) {
			atomic_set(&fwd_info->buf_2->in_busy, 0);
			fwd_info->buffer_status[BUF_2_INDEX] = 0;
			DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
			"Buffer 2 for core PD is marked free, p: %d, t: %d\n",
			fwd_info->peripheral, fwd_info->type);
@@ -1302,12 +1315,14 @@ int diagfwd_channel_close(struct diagfwd_info *fwd_info)

	if (fwd_info->buf_1 && fwd_info->buf_1->data) {
		atomic_set(&fwd_info->buf_1->in_busy, 0);
		fwd_info->buffer_status[BUF_1_INDEX] = 0;
		DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
		"Buffer 1 for core PD is marked free, p: %d, t: %d\n",
			fwd_info->peripheral, fwd_info->type);
	}
	if (fwd_info->buf_2 && fwd_info->buf_2->data) {
		atomic_set(&fwd_info->buf_2->in_busy, 0);
		fwd_info->buffer_status[BUF_2_INDEX] = 0;
		DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
		"Buffer 2 for core PD is marked free, p: %d, t: %d\n",
				fwd_info->peripheral, fwd_info->type);
@@ -1381,6 +1396,7 @@ void diagfwd_write_done(uint8_t peripheral, uint8_t type, int buf_num)
		 */
		if (!upd_valid_len) {
			atomic_set(&fwd_info->buf_1->in_busy, 0);
			fwd_info->buffer_status[BUF_1_INDEX] = 0;
			DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
			"Buffer 1 for core PD is marked free, p: %d, t: %d, buf_num: %d\n",
				fwd_info->peripheral, fwd_info->type, buf_num);
@@ -1406,6 +1422,7 @@ void diagfwd_write_done(uint8_t peripheral, uint8_t type, int buf_num)
		 */
		if (!upd_valid_len) {
			atomic_set(&fwd_info->buf_2->in_busy, 0);
			fwd_info->buffer_status[BUF_2_INDEX] = 0;
			DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
			"Buffer 2 for core PD is marked free, p: %d, t: %d, buf_num: %d\n",
				fwd_info->peripheral, fwd_info->type, buf_num);
@@ -1440,6 +1457,7 @@ void diagfwd_write_done(uint8_t peripheral, uint8_t type, int buf_num)
		 */
		if (!upd_valid_len && !fwd_info->cpd_len_1) {
			atomic_set(&fwd_info->buf_1->in_busy, 0);
			fwd_info->buffer_status[BUF_1_INDEX] = 0;
			DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
				"Buffer 1 for core PD is marked free, p: %d, t: %d, buf_num: %d\n",
				fwd_info->peripheral, fwd_info->type, buf_num);
@@ -1474,6 +1492,7 @@ void diagfwd_write_done(uint8_t peripheral, uint8_t type, int buf_num)
		 */
		if (!upd_valid_len && !fwd_info->cpd_len_2) {
			atomic_set(&fwd_info->buf_2->in_busy, 0);
			fwd_info->buffer_status[BUF_2_INDEX] = 0;
			DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
			"Buffer 2 for core PD is marked free, p: %d, t: %d, buf_num: %d\n",
			fwd_info->peripheral, fwd_info->type, buf_num);
+2 −1
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
/* Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
 */

#ifndef DIAGFWD_PERIPHERAL_H
@@ -70,6 +70,7 @@ struct diagfwd_info {
	int cpd_len_1;
	int cpd_len_2;
	int upd_len[MAX_PERIPHERAL_UPD][2];
	int buffer_status[NUM_CHANNEL_BUFFERS];
	atomic_t opened;
	unsigned long read_bytes;
	unsigned long write_bytes;
+43 −15
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
 */

#include <linux/slab.h>
@@ -383,6 +383,7 @@ int diag_rpmsg_check_state(void *ctxt)
static int diag_rpmsg_read(void *ctxt, unsigned char *buf, int buf_len)
{
	struct diag_rpmsg_info *rpmsg_info =  NULL;
	struct diagfwd_info *fwd_info = NULL;
	int ret_val = 0;

	if (!ctxt || !buf || buf_len <= 0)
@@ -390,15 +391,26 @@ static int diag_rpmsg_read(void *ctxt, unsigned char *buf, int buf_len)

	rpmsg_info = (struct diag_rpmsg_info *)ctxt;
	if (!rpmsg_info || !atomic_read(&rpmsg_info->opened) ||
		!rpmsg_info->hdl || !rpmsg_info->inited) {
		!rpmsg_info->hdl || !rpmsg_info->inited ||
		!rpmsg_info->fwd_ctxt) {
		DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
			"diag:RPMSG channel not opened");
		return -EIO;
	}
	if (!rpmsg_info->buf1)

	fwd_info = rpmsg_info->fwd_ctxt;

	mutex_lock(&driver->diagfwd_channel_mutex[rpmsg_info->peripheral]);

	if (!rpmsg_info->buf1 && !fwd_info->buffer_status[BUF_1_INDEX] &&
		atomic_read(&fwd_info->buf_1->in_busy)) {
		rpmsg_info->buf1 = buf;
	else if (!rpmsg_info->buf2)
	} else if (!rpmsg_info->buf2 && (fwd_info->type == TYPE_DATA) &&
		!fwd_info->buffer_status[BUF_2_INDEX] &&
		atomic_read(&fwd_info->buf_2->in_busy)) {
		rpmsg_info->buf2 = buf;
	}
	mutex_unlock(&driver->diagfwd_channel_mutex[rpmsg_info->peripheral]);

	return ret_val;
}
@@ -499,12 +511,15 @@ static int diag_rpmsg_notify_cb(struct rpmsg_device *rpdev, void *data, int len,
						void *priv, u32 src)
{
	struct diag_rpmsg_info *rpmsg_info = NULL;
	struct diag_rpmsg_read_work *read_work;
	void *buf;
	struct diagfwd_info *fwd_info = NULL;
	struct diag_rpmsg_read_work *read_work = NULL;
	void *buf = NULL;

	rpmsg_info = dev_get_drvdata(&rpdev->dev);
	if (!rpmsg_info)
	if (!rpmsg_info || !rpmsg_info->fwd_ctxt) {
		DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "diag: Invalid rpmsg info\n");
		return 0;
	}

	if (!rpmsg_info->buf1 && !rpmsg_info->buf2) {
		DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
@@ -513,10 +528,24 @@ static int diag_rpmsg_notify_cb(struct rpmsg_device *rpdev, void *data, int len,
		return 0;
	}

	if (rpmsg_info->buf1)
	fwd_info = rpmsg_info->fwd_ctxt;

	DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
		"diag: received data of length: %d for p:%d, t:%d\n",
		len, rpmsg_info->peripheral, rpmsg_info->type);

	if (rpmsg_info->buf1 && !fwd_info->buffer_status[BUF_1_INDEX] &&
			atomic_read(&fwd_info->buf_1->in_busy)) {
		buf = rpmsg_info->buf1;
	else
		fwd_info->buffer_status[BUF_1_INDEX] = 1;
	} else if (rpmsg_info->buf2 && !fwd_info->buffer_status[BUF_2_INDEX] &&
			atomic_read(&fwd_info->buf_2->in_busy) &&
			(fwd_info->type == TYPE_DATA)) {
		buf = rpmsg_info->buf2;
		fwd_info->buffer_status[BUF_2_INDEX] = 1;
	} else {
		buf = NULL;
	}

	if (!buf)
		return 0;
@@ -542,26 +571,25 @@ static void diag_rpmsg_notify_rx_work_fn(struct work_struct *work)
	struct diag_rpmsg_read_work *read_work = container_of(work,
				struct diag_rpmsg_read_work, work);
	struct diag_rpmsg_info *rpmsg_info = read_work->rpmsg_info;
	struct mutex *channel_mutex;

	if (!rpmsg_info || !rpmsg_info->hdl) {
		kfree(read_work);
		read_work = NULL;
		return;
	}

	channel_mutex = &driver->diagfwd_channel_mutex[rpmsg_info->peripheral];
	mutex_lock(channel_mutex);
	mutex_lock(&driver->diagfwd_channel_mutex[rpmsg_info->peripheral]);
	diagfwd_channel_read_done(rpmsg_info->fwd_ctxt,
			(unsigned char *)(read_work->ptr_read_done),
			read_work->ptr_read_size);
	mutex_unlock(channel_mutex);

	if (read_work->ptr_read_done == rpmsg_info->buf1)
		rpmsg_info->buf1 = NULL;
	else if (read_work->ptr_read_done == rpmsg_info->buf2)
		rpmsg_info->buf2 = NULL;

	kfree(read_work);
	read_work = NULL;
	mutex_unlock(&driver->diagfwd_channel_mutex[rpmsg_info->peripheral]);
}

static void rpmsg_late_init(struct diag_rpmsg_info *rpmsg_info)