linux-input.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Jiada Wang <jiada_wang@mentor.com>
To: <nick@shmanahar.org>, <dmitry.torokhov@gmail.com>,
	<jikos@kernel.org>, <benjamin.tissoires@redhat.com>,
	<bsz@semihalf.com>, <rydberg@bitmath.org>
Cc: <linux-input@vger.kernel.org>, <linux-kernel@vger.kernel.org>,
	<erosca@de.adit-jv.com>, <Andrew_Gabbasov@mentor.com>,
	<jiada_wang@mentor.com>
Subject: [PATCH v9 54/55] Input: atmel_mxt_ts: Implement synchronization during various operation
Date: Wed, 25 Mar 2020 06:33:33 -0700	[thread overview]
Message-ID: <20200325133334.19346-55-jiada_wang@mentor.com> (raw)
In-Reply-To: <20200325133334.19346-1-jiada_wang@mentor.com>

From: Sanjeev Chugh <sanjeev_chugh@mentor.com>

There could be scope of race conditions when sysfs is being handled
and at the same time, device removal is occurring. For example,
we don't want the device removal to begin if the Atmel device
cfg update is going on or firmware update is going on. In such
cases, wait for device update to be completed before the removal
continues.

    Thread                                          Thread 2:
=========================                       =========================
mxt_update_fw_store()                           mxt_remove()
mutex_lock(&data->lock)                         ...
mxt_initialize()                                //Tries to acquire lock
  request_firmware_nowait()                     mutex_lock(&data->lock)
...                                             ==>waits for lock()
...                                             .
...                                             .
mutex_unlock(&data->lock)                       .
                                                //Gets lock and proceeds
                                                mxt_free_input_device();
                                                ...
                                                mutex_unlock(&data->lock)
                                                //Frees atmel driver data
                                                kfree(data)

If the request_firmware_nowait() completes after the driver removal,
and callback is triggered. But kernel crashes since the module is
already removed.

This commit adds state machine to serialize such scenarios.

Signed-off-by: Sanjeev Chugh <sanjeev_chugh@mentor.com>
Signed-off-by: Bhuvanesh Surachari <bhuvanesh_surachari@mentor.com>
Signed-off-by: Jiada Wang <jiada_wang@mentor.com>
---
 drivers/input/touchscreen/atmel_mxt_ts.c | 218 ++++++++++++++++++++---
 1 file changed, 194 insertions(+), 24 deletions(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 1ba34c5f12bd..7bd926f04e9f 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -224,6 +224,7 @@ enum t100_type {
 #define MXT_POWERON_DELAY	150	/* msec */
 #define MXT_BOOTLOADER_WAIT	36E5	/* 1 minute */
 #define MXT_WATCHDOG_TIMEOUT	1000	/* msec */
+#define MXT_CONFIG_TIMEOUT	36E5	/* msec */
 
 /* Command to unlock bootloader */
 #define MXT_UNLOCK_CMD_MSB	0xaa
@@ -247,6 +248,20 @@ enum t100_type {
 
 #define DEBUG_MSG_MAX		200
 
+enum device_state {
+	MXT_STATE_READY,
+	MXT_STATE_UPDATING_CONFIG,
+	MXT_STATE_UPDATING_CONFIG_ASYNC,
+	MXT_STATE_START,
+	MXT_STATE_STOP,
+	MXT_STATE_GOING_AWAY
+};
+
+enum mxt_cmd {
+	UPDATE_CFG,
+	UPDATE_FW
+};
+
 struct mxt_info {
 	u8 family_id;
 	u8 variant_id;
@@ -426,11 +441,15 @@ struct mxt_data {
 	/* Indicates whether device is in suspend */
 	bool suspended;
 
-	/* Indicates whether device is updating configuration */
-	bool updating_config;
+	struct mutex lock;
 
 	unsigned int mtu;
 	bool t25_status;
+
+	/* State handling for probe/remove, open/close and config update */
+	enum device_state e_state;
+
+	struct completion update_cfg_completion;
 };
 
 struct mxt_vb2_buffer {
@@ -1654,6 +1673,7 @@ static irqreturn_t mxt_interrupt(int irq, void *dev_id)
 	struct mxt_data *data = dev_id;
 	int ret;
 
+	mutex_lock(&data->lock);
 	data->mxt_status.intp_triggered = true;
 
 	if (data->in_bootloader) {
@@ -1681,6 +1701,8 @@ static irqreturn_t mxt_interrupt(int irq, void *dev_id)
 
 exit:
 	data->mxt_status.intp_triggered = false;
+	mutex_unlock(&data->lock);
+
 	return ret;
 }
 
@@ -2263,6 +2285,8 @@ static void mxt_free_object_table(struct mxt_data *data)
 	video_unregister_device(&data->dbg.vdev);
 	v4l2_device_unregister(&data->dbg.v4l2);
 #endif
+	mutex_lock(&data->lock);
+
 	data->object_table = NULL;
 	kfree(data->info);
 	data->info = NULL;
@@ -2292,6 +2316,8 @@ static void mxt_free_object_table(struct mxt_data *data)
 	data->T100_reportid_min = 0;
 	data->T100_reportid_max = 0;
 	data->max_reportid = 0;
+
+	mutex_unlock(&data->lock);
 }
 
 static int mxt_parse_object_table(struct mxt_data *data,
@@ -2973,8 +2999,15 @@ static int mxt_configure_objects(struct mxt_data *data,
 
 static void mxt_config_cb(const struct firmware *cfg, void *ctx)
 {
+	struct mxt_data *data = ctx;
+
 	mxt_configure_objects(ctx, cfg);
 	release_firmware(cfg);
+	complete(&data->update_cfg_completion);
+	mutex_lock(&data->lock);
+	if (data->e_state != MXT_STATE_GOING_AWAY)
+		data->e_state = MXT_STATE_READY;
+	mutex_unlock(&data->lock);
 }
 
 static int mxt_bootloader_status(struct mxt_data *data)
@@ -3090,6 +3123,15 @@ static int mxt_initialize(struct mxt_data *data)
 		goto err_free_sysfs;
 
 	if (data->cfg_name) {
+		mutex_lock(&data->lock);
+		if (data->e_state != MXT_STATE_GOING_AWAY) {
+			data->e_state = MXT_STATE_UPDATING_CONFIG_ASYNC;
+		} else {
+			mutex_unlock(&data->lock);
+			return -EBUSY;
+		}
+		reinit_completion(&data->update_cfg_completion);
+		mutex_unlock(&data->lock);
 		error = request_firmware_nowait(THIS_MODULE, true,
 						data->cfg_name,
 						&client->dev,
@@ -3869,30 +3911,58 @@ static int mxt_update_file_name(struct device *dev, char **file_name,
 	return 0;
 }
 
+static int mxt_process_operation(struct mxt_data *data,
+				 enum mxt_cmd cmd,
+				 void *cmd_data);
+
 static ssize_t update_fw_store(struct device *dev,
 			       struct device_attribute *attr,
 			       const char *buf, size_t count)
 {
 	struct mxt_data *data = dev_get_drvdata(dev);
+	char *filename = NULL;
+	int ret;
+
+	ret = mxt_update_file_name(dev, &filename, buf, count);
+	if (ret)
+		goto out;
+
+	ret = mxt_process_operation(data, UPDATE_FW, filename);
+	kfree(filename);
+
+	if (ret)
+		goto out;
+
+	return count;
+out:
+	return ret;
+}
+
+static int mxt_fw_update(struct mxt_data *data,
+			 const char *filename)
+{
+	struct device *dev = &data->client->dev;
+	unsigned int len = 0;
 	int error;
 
-	error = mxt_update_file_name(dev, &data->fw_name, buf, count);
+	len = strlen(filename);
+	error = mxt_update_file_name(dev, &data->fw_name, filename, len);
 	if (error)
 		return error;
 
 	error = mxt_load_fw(dev);
 	if (error) {
 		dev_err(dev, "The firmware update failed(%d)\n", error);
-		count = error;
-	} else {
-		dev_info(dev, "The firmware update succeeded\n");
-
-		error = mxt_initialize(data);
-		if (error)
-			return error;
+		return error;
 	}
 
-	return count;
+	error = mxt_initialize(data);
+	if (error)
+		return error;
+
+	dev_info(dev, "The firmware update succeeded\n");
+
+	return error;
 }
 
 static ssize_t update_cfg_store(struct device *dev,
@@ -3900,14 +3970,38 @@ static ssize_t update_cfg_store(struct device *dev,
 				const char *buf, size_t count)
 {
 	struct mxt_data *data = dev_get_drvdata(dev);
+	char *filename = NULL;
+	int ret;
+
+	ret = mxt_update_file_name(dev, &filename, buf, count);
+	if (ret)
+		goto out;
+
+	ret = mxt_process_operation(data, UPDATE_CFG, filename);
+	kfree(filename);
+
+	if (ret)
+		goto out;
+
+	return count;
+out:
+	return ret;
+}
+
+static int mxt_cfg_update(struct mxt_data *data,
+			  char *filename)
+{
+	struct device *dev = &data->client->dev;
 	const struct firmware *cfg;
+	unsigned int len = 0;
 	int ret;
 
-	ret = mxt_update_file_name(dev, &data->cfg_name, buf, count);
+	len = strlen(filename);
+	ret = mxt_update_file_name(dev, &data->cfg_name, filename, len);
 	if (ret)
 		return ret;
 
-	ret = request_firmware(&cfg, data->cfg_name, dev);
+	ret = request_firmware(&cfg, data->cfg_name, &data->client->dev);
 	if (ret < 0) {
 		dev_err(dev, "Failure to request config file %s\n",
 			data->cfg_name);
@@ -3915,8 +4009,6 @@ static ssize_t update_cfg_store(struct device *dev,
 		goto out;
 	}
 
-	data->updating_config = true;
-
 	mxt_free_input_device(data);
 
 	if (data->suspended) {
@@ -3932,15 +4024,8 @@ static ssize_t update_cfg_store(struct device *dev,
 	}
 
 	ret = mxt_configure_objects(data, cfg);
-	if (ret)
-		goto release;
-
-	ret = count;
-
-release:
 	release_firmware(cfg);
 out:
-	data->updating_config = false;
 	return ret;
 }
 
@@ -4212,8 +4297,17 @@ static int mxt_start(struct mxt_data *data)
 {
 	int ret = 0;
 
-	if (!data->suspended || data->in_bootloader)
+	mutex_lock(&data->lock);
+	if (!data->suspended) {
+		mutex_unlock(&data->lock);
 		return 0;
+	}
+	if (data->in_bootloader || data->e_state != MXT_STATE_READY) {
+		mutex_unlock(&data->lock);
+		return -EBUSY;
+	}
+	data->e_state = MXT_STATE_START;
+	mutex_unlock(&data->lock);
 
 	switch (data->suspend_mode) {
 	case MXT_SUSPEND_T9_CTRL:
@@ -4257,8 +4351,12 @@ static int mxt_start(struct mxt_data *data)
 		ret = mxt_acquire_irq(data);
 	}
 
+	mutex_lock(&data->lock);
 	if (!ret)
 		data->suspended = false;
+	if (data->e_state != MXT_STATE_GOING_AWAY)
+		data->e_state = MXT_STATE_READY;
+	mutex_unlock(&data->lock);
 
 	return ret;
 }
@@ -4267,8 +4365,19 @@ static int mxt_stop(struct mxt_data *data)
 {
 	int ret;
 
-	if (data->suspended || data->in_bootloader || data->updating_config)
+	mutex_lock(&data->lock);
+	if (data->suspended || data->e_state == MXT_STATE_UPDATING_CONFIG) {
+		mutex_unlock(&data->lock);
 		return 0;
+	}
+	if ((data->e_state != MXT_STATE_READY &&
+	     data->e_state != MXT_STATE_GOING_AWAY)) {
+		mutex_unlock(&data->lock);
+		return -EBUSY;
+	}
+	if (data->e_state != MXT_STATE_GOING_AWAY)
+		data->e_state = MXT_STATE_STOP;
+	mutex_unlock(&data->lock);
 
 	switch (data->suspend_mode) {
 	case MXT_SUSPEND_T9_CTRL:
@@ -4298,8 +4407,15 @@ static int mxt_stop(struct mxt_data *data)
 		break;
 	}
 
+	mutex_lock(&data->lock);
 	data->suspended = true;
+
+	if (data->e_state != MXT_STATE_GOING_AWAY)
+		data->e_state = MXT_STATE_READY;
+	mutex_unlock(&data->lock);
+
 	return 0;
+
 }
 
 static int mxt_input_open(struct input_dev *dev)
@@ -4454,12 +4570,15 @@ static int mxt_probe(struct i2c_client *client, const struct i2c_device_id *id)
 	snprintf(data->phys, sizeof(data->phys), "i2c-%u-%04x/input0",
 		 client->adapter->nr, client->addr);
 
+	mutex_init(&data->lock);
+
 	data->client = client;
 	i2c_set_clientdata(client, data);
 
 	init_completion(&data->chg_completion);
 	init_completion(&data->reset_completion);
 	init_completion(&data->crc_completion);
+	init_completion(&data->update_cfg_completion);
 	mutex_init(&data->debug_msg_lock);
 
 	data->suspend_mode = dmi_check_system(chromebook_T9_suspend_dmi) ?
@@ -4553,6 +4672,18 @@ static int mxt_remove(struct i2c_client *client)
 {
 	struct mxt_data *data = i2c_get_clientdata(client);
 
+	mutex_lock(&data->lock);
+	if (data->e_state == MXT_STATE_UPDATING_CONFIG_ASYNC ||
+	    data->e_state == MXT_STATE_UPDATING_CONFIG) {
+		data->e_state = MXT_STATE_GOING_AWAY;
+		mutex_unlock(&data->lock);
+		mxt_wait_for_completion(data, &data->update_cfg_completion,
+					MXT_CONFIG_TIMEOUT);
+	} else {
+		data->e_state = MXT_STATE_GOING_AWAY;
+		mutex_unlock(&data->lock);
+	}
+
 	disable_irq(data->irq);
 	sysfs_remove_group(&client->dev.kobj, &mxt_fw_attr_group);
 	if (data->reset_gpio) {
@@ -4613,6 +4744,45 @@ static int __maybe_unused mxt_resume(struct device *dev)
 	return ret;
 }
 
+static int mxt_process_operation(struct mxt_data *data,
+				 enum mxt_cmd cmd,
+				 void *cmd_data)
+{
+	int ret = 0;
+
+	mutex_lock(&data->lock);
+	if (data->e_state != MXT_STATE_READY) {
+		mutex_unlock(&data->lock);
+		dev_err(&data->client->dev, "Atmel touch device is shutting down\n");
+		return -EBUSY;
+	}
+	data->e_state = MXT_STATE_UPDATING_CONFIG;
+	reinit_completion(&data->update_cfg_completion);
+	mutex_unlock(&data->lock);
+
+	switch (cmd) {
+	case UPDATE_CFG:
+	case UPDATE_FW:
+		if (cmd == UPDATE_CFG)
+			ret = mxt_cfg_update(data, (char *)cmd_data);
+		else
+			ret = mxt_fw_update(data, (char *)cmd_data);
+		break;
+
+	default:
+		break;
+	}
+	mutex_lock(&data->lock);
+	if (data->e_state != MXT_STATE_UPDATING_CONFIG_ASYNC) {
+		complete(&data->update_cfg_completion);
+		if (data->e_state != MXT_STATE_GOING_AWAY)
+			data->e_state = MXT_STATE_READY;
+	}
+	mutex_unlock(&data->lock);
+
+	return ret;
+}
+
 static SIMPLE_DEV_PM_OPS(mxt_pm_ops, mxt_suspend, mxt_resume);
 
 static const struct of_device_id mxt_of_match[] = {
-- 
2.17.1


  parent reply	other threads:[~2020-03-25 13:37 UTC|newest]

Thread overview: 65+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-03-25 13:32 [PATCH v9 00/55] atmel_mxt_ts misc Jiada Wang
2020-03-25 13:32 ` [PATCH v9 01/55] Input: introduce input_mt_report_slot_inactive Jiada Wang
2020-03-25 13:32 ` [PATCH v9 02/55] Input: atmel_mxt_ts - rework sysfs init/remove Jiada Wang
2020-03-25 13:32 ` [PATCH v9 03/55] Input: atmel_mxt_ts - only read messages in mxt_acquire_irq() when necessary Jiada Wang
2020-03-25 13:32 ` [PATCH v9 04/55] Input: atmel_mxt_ts - split large i2c transfers into blocks Jiada Wang
2020-03-25 13:32 ` [PATCH v9 05/55] Input: atmel_mxt_ts - output status from T48 Noise Supression Jiada Wang
2020-03-25 13:32 ` [PATCH v9 06/55] Input: atmel_mxt_ts - output status from T42 Touch Suppression Jiada Wang
2020-03-25 13:32 ` [PATCH v9 07/55] Input: atmel_mxt_ts - implement T9 vector/orientation support Jiada Wang
2020-03-25 13:32 ` [PATCH v9 08/55] Input: atmel_mxt_ts - implement T15 Key Array support Jiada Wang
2020-03-25 13:32 ` [PATCH v9 09/55] Input: atmel_mxt_ts - handle reports from T47 Stylus object Jiada Wang
2020-03-25 13:32 ` [PATCH v9 10/55] Input: atmel_mxt_ts - implement support for T107 active stylus Jiada Wang
2020-03-25 13:32 ` [PATCH v9 11/55] Input: atmel_mxt_ts - add debug for T92 gesture and T93 touch seq msgs Jiada Wang
2020-03-25 13:32 ` [PATCH v9 12/55] Input: atmel_mxt_ts - release touch state during suspend Jiada Wang
2020-03-25 13:32 ` [PATCH v9 13/55] Input: atmel_mxt_ts - add regulator control support Jiada Wang
2020-03-25 19:05   ` Dmitry Osipenko
2020-03-27 11:09     ` Wang, Jiada
2020-03-29 18:54       ` Dmitry Osipenko
2020-03-30  4:10         ` Wang, Jiada
2020-03-25 13:32 ` [PATCH v9 14/55] dt-bindings: input: atmel: add suspend mode support Jiada Wang
2020-03-25 13:32 ` [PATCH v9 15/55] Input: atmel_mxt_ts - report failures in suspend/resume Jiada Wang
2020-03-25 13:32 ` [PATCH v9 16/55] Input: atmel_mxt_ts - allow specification of firmware file name Jiada Wang
2020-03-25 13:32 ` [PATCH v9 17/55] Input: atmel_mxt_ts: Rename mxt_fw_version_show to fw_version_show Jiada Wang
2020-03-25 13:32 ` [PATCH v9 18/55] Input: atmel_mxt_ts: Rename mxt_hw_version_show to hw_version_show Jiada Wang
2020-03-25 13:32 ` [PATCH v9 19/55] Input: atmel_mxt_ts: rename mxt_update_fw_store to update_fw_store Jiada Wang
2020-03-25 13:32 ` [PATCH v9 20/55] Input: atmel_mxt_ts - handle cfg filename via pdata/sysfs Jiada Wang
2020-03-25 13:33 ` [PATCH v9 21/55] dt-bindings: input: atmel: provide name of configuration file Jiada Wang
2020-03-25 13:33 ` [PATCH v9 22/55] Input: atmel_mxt_ts - allow input name to be specified in platform data Jiada Wang
2020-03-25 13:33 ` [PATCH v9 23/55] dt-bindings: input: atmel: support to specify input name Jiada Wang
2020-03-25 13:33 ` [PATCH v9 24/55] Input: atmel_mxt_ts - add config checksum attribute to sysfs Jiada Wang
2020-03-25 13:33 ` [PATCH v9 25/55] Input: atmel_mxt_ts - refactor firmware flash to extract context into struct Jiada Wang
2020-03-25 13:33 ` [PATCH v9 26/55] Input: atmel_mxt_ts - refactor code to enter bootloader into separate func Jiada Wang
2020-03-25 13:33 ` [PATCH v9 27/55] Input: atmel_mxt_ts - combine bootloader version query with probe Jiada Wang
2020-03-25 13:33 ` [PATCH v9 28/55] Input: atmel_mxt_ts - improve bootloader state machine handling Jiada Wang
2020-03-25 13:33 ` [PATCH v9 29/55] Input: atmel_mxt_ts - rename bl_completion to chg_completion Jiada Wang
2020-03-25 13:33 ` [PATCH v9 30/55] Input: atmel_mxt_ts - make bootloader interrupt driven Jiada Wang
2020-03-25 13:33 ` [PATCH v9 31/55] Input: atmel_mxt_ts - delay enabling IRQ when not using regulators Jiada Wang
2020-03-25 13:33 ` [PATCH v9 32/55] Input: atmel_mxt_ts - implement I2C retries Jiada Wang
2020-03-25 13:33 ` [PATCH v9 33/55] Input: atmel_mxt_ts - orientation is not present in hover Jiada Wang
2020-03-25 13:33 ` [PATCH v9 34/55] Input: atmel_mxt_ts - implement debug output for messages Jiada Wang
2020-03-25 13:33 ` [PATCH v9 35/55] Input: atmel_mxt_ts - implement improved debug message interface Jiada Wang
2020-03-25 13:33 ` [PATCH v9 36/55] Input: atmel_mxt_ts - eliminate data->raw_info_block Jiada Wang
2020-03-25 13:33 ` [PATCH v9 37/55] Input: atmel_mxt_ts - Change call-points of mxt_free_* functions Jiada Wang
2020-03-25 13:33 ` [PATCH v9 38/55] Input: atmel_mxt_ts - rely on calculated_crc rather than file config_crc Jiada Wang
2020-03-25 13:33 ` [PATCH v9 39/55] input: atmel_mxt_ts: export GPIO reset line via sysfs Jiada Wang
2020-03-25 13:33 ` [PATCH v9 40/55] input: atmel_mxt_ts: Add Missing Delay for reset handling of Atmel touch panel controller in detachable displays Jiada Wang
2020-03-25 13:33 ` [PATCH v9 41/55] Input: atmel_mxt_ts: Add support for run self-test routine Jiada Wang
2020-03-25 13:33 ` [PATCH v9 42/55] Input: atmel_mxt_ts: Limit the max bytes transferred in an i2c transaction Jiada Wang
2020-03-25 13:33 ` [PATCH v9 43/55] dt-bindings: input: atmel: support to set max bytes transferred Jiada Wang
2020-03-25 13:33 ` [PATCH v9 44/55] Input: atmel_mxt_ts: return error from mxt_process_messages_until_invalid() Jiada Wang
2020-03-25 13:33 ` [PATCH v9 45/55] Input: Atmel: improve error handling in mxt_start() Jiada Wang
2020-03-25 13:33 ` [PATCH v9 46/55] Input: Atmel: improve error handling in mxt_initialize() Jiada Wang
2020-03-25 13:33 ` [PATCH v9 47/55] Input: Atmel: improve error handling in mxt_update_cfg() Jiada Wang
2020-03-25 13:33 ` [PATCH v9 48/55] Input: Atmel: Improve error handling in mxt_initialize_input_device() Jiada Wang
2020-03-25 13:33 ` [PATCH v9 49/55] Input: Atmel: handle ReportID "0x00" while processing T5 messages Jiada Wang
2020-03-25 13:33 ` [PATCH v9 50/55] Input: Atmel: use T44 object to process " Jiada Wang
2020-03-25 13:33 ` [PATCH v9 51/55] Input: atmel_mxt_ts: use gpiod_set_value_cansleep for reset pin Jiada Wang
2020-03-25 13:33 ` [PATCH v9 52/55] input: touchscreen: atmel_mxt_ts: Added sysfs entry for touchscreen status Jiada Wang
2020-03-25 19:35   ` Dmitry Osipenko
2020-03-25 19:41     ` Dmitry Osipenko
2020-03-27 12:49     ` Wang, Jiada
2020-03-27 13:37       ` Dmitry Osipenko
2020-03-27 13:43         ` Dmitry Osipenko
2020-03-25 13:33 ` [PATCH v9 53/55] input: atmel_mxt_ts: added sysfs interface to update atmel T38 data Jiada Wang
2020-03-25 13:33 ` Jiada Wang [this message]
2020-03-25 13:33 ` [PATCH v9 55/55] Input: atmel_mxt_ts - Fix compilation warning Jiada Wang

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200325133334.19346-55-jiada_wang@mentor.com \
    --to=jiada_wang@mentor.com \
    --cc=Andrew_Gabbasov@mentor.com \
    --cc=benjamin.tissoires@redhat.com \
    --cc=bsz@semihalf.com \
    --cc=dmitry.torokhov@gmail.com \
    --cc=erosca@de.adit-jv.com \
    --cc=jikos@kernel.org \
    --cc=linux-input@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=nick@shmanahar.org \
    --cc=rydberg@bitmath.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).