linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/2] drm/nouveau: i2c over DP AUX fixes
@ 2019-07-25 19:39 Lyude Paul
  2019-07-25 19:40 ` [PATCH 1/2] drm/nouveau: Fix missing elses in g94_i2c_aux_xfer Lyude Paul
  2019-07-25 19:40 ` [PATCH 2/2] drm/nouveau: Don't retry infinitely when receiving no data on i2c over AUX Lyude Paul
  0 siblings, 2 replies; 3+ messages in thread
From: Lyude Paul @ 2019-07-25 19:39 UTC (permalink / raw)
  To: nouveau
  Cc: Daniel Vetter, David Airlie, linux-kernel, dri-devel, Ben Skeggs,
	Lyude Paul

This is another attempt at fixing an issue with

yes | sensors-detect

Causing some machines with nouveau loaded to hang if certain kinds of
displays are attached. I've also included one minor fix that I found
along the way of troubleshooting this issue.

Lyude Paul (2):
  drm/nouveau: Fix missing elses in g94_i2c_aux_xfer
  drm/nouveau: Don't retry infinitely when receiving no data on i2c over
    AUX

 drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.c | 24 +++++++++++++------
 .../gpu/drm/nouveau/nvkm/subdev/i2c/auxg94.c  |  4 ++--
 2 files changed, 19 insertions(+), 9 deletions(-)

-- 
2.21.0


^ permalink raw reply	[flat|nested] 3+ messages in thread

* [PATCH 1/2] drm/nouveau: Fix missing elses in g94_i2c_aux_xfer
  2019-07-25 19:39 [PATCH 0/2] drm/nouveau: i2c over DP AUX fixes Lyude Paul
@ 2019-07-25 19:40 ` Lyude Paul
  2019-07-25 19:40 ` [PATCH 2/2] drm/nouveau: Don't retry infinitely when receiving no data on i2c over AUX Lyude Paul
  1 sibling, 0 replies; 3+ messages in thread
From: Lyude Paul @ 2019-07-25 19:40 UTC (permalink / raw)
  To: nouveau; +Cc: Ben Skeggs, David Airlie, Daniel Vetter, dri-devel, linux-kernel

This looks rather unintentional!

Signed-off-by: Lyude Paul <lyude@redhat.com>
---
 drivers/gpu/drm/nouveau/nvkm/subdev/i2c/auxg94.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/auxg94.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/auxg94.c
index c8ab1b5741a3..9bc9eac08789 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/auxg94.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/auxg94.c
@@ -138,9 +138,9 @@ g94_i2c_aux_xfer(struct nvkm_i2c_aux *obj, bool retry,
 		if ((stat & 0x000f0000) == 0x00080000 ||
 		    (stat & 0x000f0000) == 0x00020000)
 			ret = 1;
-		if ((stat & 0x00000100))
+		else if ((stat & 0x00000100))
 			ret = -ETIMEDOUT;
-		if ((stat & 0x00000e00))
+		else if ((stat & 0x00000e00))
 			ret = -EIO;
 
 		AUX_TRACE(&aux->base, "%02d %08x %08x", retries, ctrl, stat);
-- 
2.21.0


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* [PATCH 2/2] drm/nouveau: Don't retry infinitely when receiving no data on i2c over AUX
  2019-07-25 19:39 [PATCH 0/2] drm/nouveau: i2c over DP AUX fixes Lyude Paul
  2019-07-25 19:40 ` [PATCH 1/2] drm/nouveau: Fix missing elses in g94_i2c_aux_xfer Lyude Paul
@ 2019-07-25 19:40 ` Lyude Paul
  1 sibling, 0 replies; 3+ messages in thread
From: Lyude Paul @ 2019-07-25 19:40 UTC (permalink / raw)
  To: nouveau
  Cc: stable, Ben Skeggs, David Airlie, Daniel Vetter, dri-devel, linux-kernel

While I had thought I had fixed this issue in:

commit 342406e4fbba ("drm/nouveau/i2c: Disable i2c bus access after
->fini()")

It turns out that while I did fix the error messages I was seeing on my
P50 when trying to access i2c busses with the GPU in runtime suspend, I
accidentally had missed one important detail that was mentioned on the
bug report this commit was supposed to fix: that the CPU would only lock
up when trying to access i2c busses _on connected devices_ _while the
GPU is not in runtime suspend_. Whoops. That definitely explains why I
was not able to get my machine to hang with i2c bus interactions until
now, as plugging my P50 into it's dock with an HDMI monitor connected
allowed me to finally reproduce this locally.

Now that I have managed to reproduce this issue properly, it looks like
the problem is much simpler then it looks. It turns out that some
connected devices, such as MST laptop docks, will actually ACK i2c reads
even if no data was actually read:

[  275.063043] nouveau 0000:01:00.0: i2c: aux 000a: 1: 0000004c 1
[  275.063447] nouveau 0000:01:00.0: i2c: aux 000a: 00 01101000 10040000
[  275.063759] nouveau 0000:01:00.0: i2c: aux 000a: rd 00000001
[  275.064024] nouveau 0000:01:00.0: i2c: aux 000a: rd 00000000
[  275.064285] nouveau 0000:01:00.0: i2c: aux 000a: rd 00000000
[  275.064594] nouveau 0000:01:00.0: i2c: aux 000a: rd 00000000

Because we don't handle the situation of i2c ack without any data, we
end up entering an infinite loop in nvkm_i2c_aux_i2c_xfer() since the
value of cnt always remains at 0. This finally properly explains how
this could result in a CPU hang like the ones observed in the
aforementioned commit.

So, fix this by retrying transactions if no data is written or received,
and give up and fail the transaction if we continue to not write or
receive any data after 32 retries.

Signed-off-by: Lyude Paul <lyude@redhat.com>
Cc: stable@vger.kernel.org
---
 drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.c | 24 +++++++++++++------
 1 file changed, 17 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.c
index b4e7404fe660..a11637b0f6cc 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.c
@@ -40,8 +40,7 @@ nvkm_i2c_aux_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
 		u8 *ptr = msg->buf;
 
 		while (remaining) {
-			u8 cnt = (remaining > 16) ? 16 : remaining;
-			u8 cmd;
+			u8 cnt, retries, cmd;
 
 			if (msg->flags & I2C_M_RD)
 				cmd = 1;
@@ -51,10 +50,19 @@ nvkm_i2c_aux_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
 			if (mcnt || remaining > 16)
 				cmd |= 4; /* MOT */
 
-			ret = aux->func->xfer(aux, true, cmd, msg->addr, ptr, &cnt);
-			if (ret < 0) {
-				nvkm_i2c_aux_release(aux);
-				return ret;
+			for (retries = 0, cnt = 0;
+			     retries < 32 && !cnt;
+			     retries++) {
+				cnt = min_t(u8, remaining, 16);
+				ret = aux->func->xfer(aux, true, cmd,
+						      msg->addr, ptr, &cnt);
+				if (ret < 0)
+					goto out;
+			}
+			if (!cnt) {
+				AUX_TRACE(aux, "no data after 32 retries");
+				ret = -EIO;
+				goto out;
 			}
 
 			ptr += cnt;
@@ -64,8 +72,10 @@ nvkm_i2c_aux_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
 		msg++;
 	}
 
+	ret = num;
+out:
 	nvkm_i2c_aux_release(aux);
-	return num;
+	return ret;
 }
 
 static u32
-- 
2.21.0


^ permalink raw reply related	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2019-07-25 19:40 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-07-25 19:39 [PATCH 0/2] drm/nouveau: i2c over DP AUX fixes Lyude Paul
2019-07-25 19:40 ` [PATCH 1/2] drm/nouveau: Fix missing elses in g94_i2c_aux_xfer Lyude Paul
2019-07-25 19:40 ` [PATCH 2/2] drm/nouveau: Don't retry infinitely when receiving no data on i2c over AUX Lyude Paul

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).