linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Sasha Levin <sashal@kernel.org>
To: linux-kernel@vger.kernel.org, stable@vger.kernel.org
Cc: Ulrich Hecht <uli+renesas@fpond.eu>,
	Wolfram Sang <wsa+renesas@sang-engineering.com>,
	Geert Uytterhoeven <geert+renesas@glider.be>,
	Wolfram Sang <wsa@kernel.org>, Sasha Levin <sashal@kernel.org>,
	linux-i2c@vger.kernel.org, linux-media@vger.kernel.org,
	dri-devel@lists.freedesktop.org, linaro-mm-sig@lists.linaro.org
Subject: [PATCH AUTOSEL 5.4 39/42] i2c: sh_mobile: implement atomic transfers
Date: Mon,  9 Nov 2020 22:54:37 -0500	[thread overview]
Message-ID: <20201110035440.424258-39-sashal@kernel.org> (raw)
In-Reply-To: <20201110035440.424258-1-sashal@kernel.org>

From: Ulrich Hecht <uli+renesas@fpond.eu>

[ Upstream commit a49cc1fe9d64a2dc4e19b599204f403e5d25f44b ]

Implements atomic transfers to fix reboot/shutdown on r8a7790 Lager and
similar boards.

Signed-off-by: Ulrich Hecht <uli+renesas@fpond.eu>
Tested-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
Tested-by: Geert Uytterhoeven <geert+renesas@glider.be>
[wsa: some whitespace fixing]
Signed-off-by: Wolfram Sang <wsa@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
 drivers/i2c/busses/i2c-sh_mobile.c | 86 +++++++++++++++++++++++-------
 1 file changed, 66 insertions(+), 20 deletions(-)

diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c
index 8777af4c695e9..d5dd58c27ce5f 100644
--- a/drivers/i2c/busses/i2c-sh_mobile.c
+++ b/drivers/i2c/busses/i2c-sh_mobile.c
@@ -129,6 +129,7 @@ struct sh_mobile_i2c_data {
 	int sr;
 	bool send_stop;
 	bool stop_after_dma;
+	bool atomic_xfer;
 
 	struct resource *res;
 	struct dma_chan *dma_tx;
@@ -333,13 +334,15 @@ static unsigned char i2c_op(struct sh_mobile_i2c_data *pd, enum sh_mobile_i2c_op
 		ret = iic_rd(pd, ICDR);
 		break;
 	case OP_RX_STOP: /* enable DTE interrupt, issue stop */
-		iic_wr(pd, ICIC,
-		       ICIC_DTEE | ICIC_WAITE | ICIC_ALE | ICIC_TACKE);
+		if (!pd->atomic_xfer)
+			iic_wr(pd, ICIC,
+			       ICIC_DTEE | ICIC_WAITE | ICIC_ALE | ICIC_TACKE);
 		iic_wr(pd, ICCR, ICCR_ICE | ICCR_RACK);
 		break;
 	case OP_RX_STOP_DATA: /* enable DTE interrupt, read data, issue stop */
-		iic_wr(pd, ICIC,
-		       ICIC_DTEE | ICIC_WAITE | ICIC_ALE | ICIC_TACKE);
+		if (!pd->atomic_xfer)
+			iic_wr(pd, ICIC,
+			       ICIC_DTEE | ICIC_WAITE | ICIC_ALE | ICIC_TACKE);
 		ret = iic_rd(pd, ICDR);
 		iic_wr(pd, ICCR, ICCR_ICE | ICCR_RACK);
 		break;
@@ -435,7 +438,8 @@ static irqreturn_t sh_mobile_i2c_isr(int irq, void *dev_id)
 
 	if (wakeup) {
 		pd->sr |= SW_DONE;
-		wake_up(&pd->wait);
+		if (!pd->atomic_xfer)
+			wake_up(&pd->wait);
 	}
 
 	/* defeat write posting to avoid spurious WAIT interrupts */
@@ -587,6 +591,9 @@ static void start_ch(struct sh_mobile_i2c_data *pd, struct i2c_msg *usr_msg,
 	pd->pos = -1;
 	pd->sr = 0;
 
+	if (pd->atomic_xfer)
+		return;
+
 	pd->dma_buf = i2c_get_dma_safe_msg_buf(pd->msg, 8);
 	if (pd->dma_buf)
 		sh_mobile_i2c_xfer_dma(pd);
@@ -643,15 +650,13 @@ static int poll_busy(struct sh_mobile_i2c_data *pd)
 	return i ? 0 : -ETIMEDOUT;
 }
 
-static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter,
-			      struct i2c_msg *msgs,
-			      int num)
+static int sh_mobile_xfer(struct sh_mobile_i2c_data *pd,
+			 struct i2c_msg *msgs, int num)
 {
-	struct sh_mobile_i2c_data *pd = i2c_get_adapdata(adapter);
 	struct i2c_msg	*msg;
 	int err = 0;
 	int i;
-	long timeout;
+	long time_left;
 
 	/* Wake up device and enable clock */
 	pm_runtime_get_sync(pd->dev);
@@ -668,15 +673,35 @@ static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter,
 		if (do_start)
 			i2c_op(pd, OP_START);
 
-		/* The interrupt handler takes care of the rest... */
-		timeout = wait_event_timeout(pd->wait,
-				       pd->sr & (ICSR_TACK | SW_DONE),
-				       adapter->timeout);
-
-		/* 'stop_after_dma' tells if DMA transfer was complete */
-		i2c_put_dma_safe_msg_buf(pd->dma_buf, pd->msg, pd->stop_after_dma);
+		if (pd->atomic_xfer) {
+			unsigned long j = jiffies + pd->adap.timeout;
+
+			time_left = time_before_eq(jiffies, j);
+			while (time_left &&
+			       !(pd->sr & (ICSR_TACK | SW_DONE))) {
+				unsigned char sr = iic_rd(pd, ICSR);
+
+				if (sr & (ICSR_AL   | ICSR_TACK |
+					  ICSR_WAIT | ICSR_DTE)) {
+					sh_mobile_i2c_isr(0, pd);
+					udelay(150);
+				} else {
+					cpu_relax();
+				}
+				time_left = time_before_eq(jiffies, j);
+			}
+		} else {
+			/* The interrupt handler takes care of the rest... */
+			time_left = wait_event_timeout(pd->wait,
+					pd->sr & (ICSR_TACK | SW_DONE),
+					pd->adap.timeout);
+
+			/* 'stop_after_dma' tells if DMA xfer was complete */
+			i2c_put_dma_safe_msg_buf(pd->dma_buf, pd->msg,
+						 pd->stop_after_dma);
+		}
 
-		if (!timeout) {
+		if (!time_left) {
 			dev_err(pd->dev, "Transfer request timed out\n");
 			if (pd->dma_direction != DMA_NONE)
 				sh_mobile_i2c_cleanup_dma(pd);
@@ -702,14 +727,35 @@ static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter,
 	return err ?: num;
 }
 
+static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter,
+			      struct i2c_msg *msgs,
+			      int num)
+{
+	struct sh_mobile_i2c_data *pd = i2c_get_adapdata(adapter);
+
+	pd->atomic_xfer = false;
+	return sh_mobile_xfer(pd, msgs, num);
+}
+
+static int sh_mobile_i2c_xfer_atomic(struct i2c_adapter *adapter,
+				     struct i2c_msg *msgs,
+				     int num)
+{
+	struct sh_mobile_i2c_data *pd = i2c_get_adapdata(adapter);
+
+	pd->atomic_xfer = true;
+	return sh_mobile_xfer(pd, msgs, num);
+}
+
 static u32 sh_mobile_i2c_func(struct i2c_adapter *adapter)
 {
 	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_PROTOCOL_MANGLING;
 }
 
 static const struct i2c_algorithm sh_mobile_i2c_algorithm = {
-	.functionality	= sh_mobile_i2c_func,
-	.master_xfer	= sh_mobile_i2c_xfer,
+	.functionality = sh_mobile_i2c_func,
+	.master_xfer = sh_mobile_i2c_xfer,
+	.master_xfer_atomic = sh_mobile_i2c_xfer_atomic,
 };
 
 static const struct i2c_adapter_quirks sh_mobile_i2c_quirks = {
-- 
2.27.0


  parent reply	other threads:[~2020-11-10  4:01 UTC|newest]

Thread overview: 42+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-11-10  3:53 [PATCH AUTOSEL 5.4 01/42] ASoC: qcom: sdm845: set driver name correctly Sasha Levin
2020-11-10  3:54 ` [PATCH AUTOSEL 5.4 02/42] ASoC: cs42l51: manage mclk shutdown delay Sasha Levin
2020-11-10  3:54 ` [PATCH AUTOSEL 5.4 03/42] usb: dwc3: pci: add support for the Intel Alder Lake-S Sasha Levin
2020-11-10  3:54 ` [PATCH AUTOSEL 5.4 04/42] opp: Reduce the size of critical section in _opp_table_kref_release() Sasha Levin
2020-11-10  3:54 ` [PATCH AUTOSEL 5.4 05/42] usb: gadget: goku_udc: fix potential crashes in probe Sasha Levin
2020-11-10  3:54 ` [PATCH AUTOSEL 5.4 06/42] selftests/ftrace: check for do_sys_openat2 in user-memory test Sasha Levin
2020-11-10  3:54 ` [PATCH AUTOSEL 5.4 07/42] selftests: pidfd: fix compilation errors due to wait.h Sasha Levin
2020-11-10  3:54 ` [PATCH AUTOSEL 5.4 08/42] ALSA: hda: Separate runtime and system suspend Sasha Levin
2020-11-10  3:54 ` [PATCH AUTOSEL 5.4 09/42] ALSA: hda: Reinstate runtime_allow() for all hda controllers Sasha Levin
2020-11-10  3:54 ` [PATCH AUTOSEL 5.4 10/42] gfs2: Free rd_bits later in gfs2_clear_rgrpd to fix use-after-free Sasha Levin
2020-11-10  3:54 ` [PATCH AUTOSEL 5.4 11/42] gfs2: Add missing truncate_inode_pages_final for sd_aspace Sasha Levin
2020-11-10  3:54 ` [PATCH AUTOSEL 5.4 12/42] gfs2: check for live vs. read-only file system in gfs2_fitrim Sasha Levin
2020-11-10  3:54 ` [PATCH AUTOSEL 5.4 13/42] scsi: hpsa: Fix memory leak in hpsa_init_one() Sasha Levin
2020-11-10  3:54 ` [PATCH AUTOSEL 5.4 14/42] drm/amdgpu: perform srbm soft reset always on SDMA resume Sasha Levin
2020-11-10  3:54 ` [PATCH AUTOSEL 5.4 15/42] drm/amd/pm: perform SMC reset on suspend/hibernation Sasha Levin
2020-11-10  3:54 ` [PATCH AUTOSEL 5.4 16/42] drm/amd/pm: do not use ixFEATURE_STATUS for checking smc running Sasha Levin
2020-11-10  3:54 ` [PATCH AUTOSEL 5.4 17/42] mac80211: fix use of skb payload instead of header Sasha Levin
2020-11-10  3:54 ` [PATCH AUTOSEL 5.4 18/42] cfg80211: initialize wdev data earlier Sasha Levin
2020-11-10  3:54 ` [PATCH AUTOSEL 5.4 19/42] mac80211: always wind down STA state Sasha Levin
2020-11-10  3:54 ` [PATCH AUTOSEL 5.4 20/42] cfg80211: regulatory: Fix inconsistent format argument Sasha Levin
2020-11-10  3:54 ` [PATCH AUTOSEL 5.4 21/42] tracing: Fix the checking of stackidx in __ftrace_trace_stack Sasha Levin
2020-11-10  3:54 ` [PATCH AUTOSEL 5.4 22/42] scsi: scsi_dh_alua: Avoid crash during alua_bus_detach() Sasha Levin
2020-11-10  3:54 ` [PATCH AUTOSEL 5.4 23/42] scsi: mpt3sas: Fix timeouts observed while reenabling IRQ Sasha Levin
2020-11-10  3:54 ` [PATCH AUTOSEL 5.4 24/42] nvme: introduce nvme_sync_io_queues Sasha Levin
2020-11-10  3:54 ` [PATCH AUTOSEL 5.4 25/42] nvme-rdma: avoid race between time out and tear down Sasha Levin
2020-11-10  3:54 ` [PATCH AUTOSEL 5.4 26/42] nvme-tcp: " Sasha Levin
2020-11-10  3:54 ` [PATCH AUTOSEL 5.4 27/42] nvme-rdma: avoid repeated request completion Sasha Levin
2020-11-10  3:54 ` [PATCH AUTOSEL 5.4 28/42] nvme-tcp: " Sasha Levin
2020-11-10  3:54 ` [PATCH AUTOSEL 5.4 29/42] iommu/amd: Increase interrupt remapping table limit to 512 entries Sasha Levin
2020-11-10  3:54 ` [PATCH AUTOSEL 5.4 30/42] s390/smp: move rcu_cpu_starting() earlier Sasha Levin
2020-11-10  3:54 ` [PATCH AUTOSEL 5.4 31/42] vfio: platform: fix reference leak in vfio_platform_open Sasha Levin
2020-11-10  3:54 ` [PATCH AUTOSEL 5.4 32/42] vfio/pci: Bypass IGD init in case of -ENODEV Sasha Levin
2020-11-10  3:54 ` [PATCH AUTOSEL 5.4 33/42] i2c: mediatek: move dma reset before i2c reset Sasha Levin
2020-11-10  3:54 ` [PATCH AUTOSEL 5.4 34/42] net: usb: qmi_wwan: add Telit LE910Cx 0x1230 composition Sasha Levin
2020-11-10  3:54 ` [PATCH AUTOSEL 5.4 35/42] amd/amdgpu: Disable VCN DPG mode for Picasso Sasha Levin
2020-11-10  3:54 ` [PATCH AUTOSEL 5.4 36/42] kprobes: Tell lockdep about kprobe nesting Sasha Levin
2020-11-10  3:54 ` [PATCH AUTOSEL 5.4 37/42] selftests: proc: fix warning: _GNU_SOURCE redefined Sasha Levin
2020-11-10  3:54 ` [PATCH AUTOSEL 5.4 38/42] riscv: Set text_offset correctly for M-Mode Sasha Levin
2020-11-10  3:54 ` Sasha Levin [this message]
2020-11-10  3:54 ` [PATCH AUTOSEL 5.4 40/42] tpm_tis: Disable interrupts on ThinkPad T490s Sasha Levin
2020-11-10  3:54 ` [PATCH AUTOSEL 5.4 41/42] vt: Disable KD_FONT_OP_COPY Sasha Levin
2020-11-10  3:54 ` [PATCH AUTOSEL 5.4 42/42] fork: fix copy_process(CLONE_PARENT) race with the exiting ->real_parent Sasha Levin

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=20201110035440.424258-39-sashal@kernel.org \
    --to=sashal@kernel.org \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=geert+renesas@glider.be \
    --cc=linaro-mm-sig@lists.linaro.org \
    --cc=linux-i2c@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-media@vger.kernel.org \
    --cc=stable@vger.kernel.org \
    --cc=uli+renesas@fpond.eu \
    --cc=wsa+renesas@sang-engineering.com \
    --cc=wsa@kernel.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).