diff mbox series

Input: synaptics-rmi4 - retry reading SMBus version on resume

Message ID 20230510192731.300786-1-jefferymiller@google.com (mailing list archive)
State Superseded
Headers show
Series Input: synaptics-rmi4 - retry reading SMBus version on resume | expand

Commit Message

Jeffery Miller May 10, 2023, 7:27 p.m. UTC
On resume there can be a period of time after the
preceding serio_resume -> psmouse_deactivate call
where calls to rmi_smb_get_version fail with
-ENXIO.

The call path in rmi_smb_resume is rmi_smb_resume -> rmi_smb_reset ->
rmi_smb_enable_smbus_mode -> rmi_smb_get_version where
this failure would occur.

Adding a retry loop ensures that after rmi_smb_reset returns
the following rmi_driver_resume calls in rmi_smbus_resume can
succeed.

This behavior was seen on a Lenovo T440p machine that required
a delay of approximately 7-12ms.
The retry limit of 5 is chosen to be larger than
this observed delay.

With this patch the trimmed resume logs look similar to:
```
psmouse serio1: PM: calling serio_resume+0x0/0x8c @ 5399, parent: i8042
[5399] libps2:__ps2_command:316: psmouse serio1: f5 [] - 0/00000000 []
psmouse serio1: PM: serio_resume+0x0/0x8c returned 0 after 3259 usecs
...
rmi4_smbus 0-002c: PM: calling rmi_smb_resume ... @ 5454, parent: i2c-0
...
[5454] i2c_i801:i801_check_post:414: i801_smbus 0000:00:1f.3: No response
smbus_result: i2c-0 a=02c f=0000 c=fd BYTE_DATA rd res=-6
rmi4_smbus 0-002c: failed to get SMBus version number!
rmi4_smbus 0-002c: sleeping to retry getting the SMBus version number
...
rmi4_smbus 0-002c: PM: rmi_smb_resume ... returned 0 after 21351 usecs
```

Signed-off-by: Jeffery Miller <jefferymiller@google.com>
---

Early boot dmesg include:
```
rmi4_smbus 0-002c: registering SMbus-connected sensor
rmi4_f01 rmi4-00.fn01: found RMI device, manufacturer: Synaptics, product: TM2722-001, fw id: 0
```

The resume order looks correct. The `psmouse serio1` resume returns
before the rmi_smb_resume is called showing the patch from
https://lore.kernel.org/all/89456fcd-a113-4c82-4b10-a9bcaefac68f@google.com/
is applied and working for that ordering.

I attempted to try to rule out some interaction between the concurrent
input resume calls for other i8042 devices.
Adding a 7ms delay after psmouse_deactivate which is called in the
preceding psmouse serio1 serio_resume function also allows
this version call to succeed.

If the rmi_smb_probe device_disable_async_suspend patch is applied
it will also avoid this issue. However the time between
the psmouse_deactivate call for serio_resume and rmi_smb_resume
was over 60ms on my test machine. This would naturally be long
enough to avoid this particular delay.


 drivers/input/rmi4/rmi_smbus.c | 23 +++++++++++++++++------
 1 file changed, 17 insertions(+), 6 deletions(-)

Comments

Dmitry Torokhov May 10, 2023, 8:06 p.m. UTC | #1
On Wed, May 10, 2023 at 07:27:22PM +0000, Jeffery Miller wrote:
> On resume there can be a period of time after the
> preceding serio_resume -> psmouse_deactivate call
> where calls to rmi_smb_get_version fail with
> -ENXIO.
> 
> The call path in rmi_smb_resume is rmi_smb_resume -> rmi_smb_reset ->
> rmi_smb_enable_smbus_mode -> rmi_smb_get_version where
> this failure would occur.
> 
> Adding a retry loop ensures that after rmi_smb_reset returns
> the following rmi_driver_resume calls in rmi_smbus_resume can
> succeed.
> 
> This behavior was seen on a Lenovo T440p machine that required
> a delay of approximately 7-12ms.
> The retry limit of 5 is chosen to be larger than
> this observed delay.
> 
> With this patch the trimmed resume logs look similar to:
> ```
> psmouse serio1: PM: calling serio_resume+0x0/0x8c @ 5399, parent: i8042
> [5399] libps2:__ps2_command:316: psmouse serio1: f5 [] - 0/00000000 []
> psmouse serio1: PM: serio_resume+0x0/0x8c returned 0 after 3259 usecs
> ...
> rmi4_smbus 0-002c: PM: calling rmi_smb_resume ... @ 5454, parent: i2c-0
> ...
> [5454] i2c_i801:i801_check_post:414: i801_smbus 0000:00:1f.3: No response
> smbus_result: i2c-0 a=02c f=0000 c=fd BYTE_DATA rd res=-6
> rmi4_smbus 0-002c: failed to get SMBus version number!
> rmi4_smbus 0-002c: sleeping to retry getting the SMBus version number
> ...
> rmi4_smbus 0-002c: PM: rmi_smb_resume ... returned 0 after 21351 usecs
> ```
> 
> Signed-off-by: Jeffery Miller <jefferymiller@google.com>
> ---
> 
> Early boot dmesg include:
> ```
> rmi4_smbus 0-002c: registering SMbus-connected sensor
> rmi4_f01 rmi4-00.fn01: found RMI device, manufacturer: Synaptics, product: TM2722-001, fw id: 0
> ```
> 
> The resume order looks correct. The `psmouse serio1` resume returns
> before the rmi_smb_resume is called showing the patch from
> https://lore.kernel.org/all/89456fcd-a113-4c82-4b10-a9bcaefac68f@google.com/
> is applied and working for that ordering.
> 
> I attempted to try to rule out some interaction between the concurrent
> input resume calls for other i8042 devices.
> Adding a 7ms delay after psmouse_deactivate which is called in the
> preceding psmouse serio1 serio_resume function also allows
> this version call to succeed.

I am not really fond of adding random repeats in the code base. Andrew,
do you know if the Synaptics device needs certain delay when switching
to SMbus mode?

Thanks.
Jeffery Miller May 12, 2023, 7:36 p.m. UTC | #2
On Wed, May 10, 2023 at 3:06 PM Dmitry Torokhov
<dmitry.torokhov@gmail.com> wrote:
>
>
> I am not really fond of adding random repeats in the code base. Andrew,
> do you know if the Synaptics device needs certain delay when switching
> to SMbus mode?
>
That's reasonable. It's true this is a sleep to workaround rmi_smbus'
expectation that
it is able to successfully read from the i801 i2c smbus addr 0x2c on resume
when it cannot.

I do not know why the i801 i2c addr 0x2c is not responding on resume.
Infrequently it won't respond on boot during the initial
psmouse_smbus_create_companion but that is less noticeable since
it will stay in ps/2 mode and just lack features.

I do know adding a sleep in-between the psmouse deactivate call
and rmi_smbus's attempts to read from the 0x2c addr allow it to
succeed on this machine. I do not know the details as to why however.

I can apply workarounds until the underlying issue can be
identified and properly resolved.

I can apply patches and provide any sort of debugging or extra information that
might be useful to anyone familiar with these devices.

The smbus controller in this particular machine is:
00:1f.3 SMBus [0c05]: Intel Corporation 8 Series/C220 Series Chipset
Family SMBus Controller [8086:8c22] (rev 04)

Perhaps there's some way to detect when the addr is available later
and have it trigger a new probe similar to how psmouse_smbus_notifier
is triggered when the i801 bus becomes available?

Thank You,
Jeff
Andrew Duggan May 22, 2023, 11:07 p.m. UTC | #3
> From: Jeffery Miller <jefferymiller@google.com>
> Sent: Friday, May 12, 2023 12:37
> To: Dmitry Torokhov <dmitry.torokhov@gmail.com>
> Cc: Andrew Duggan <andrew@duggan.us>; Jonathan Denose
> <jdenose@chromium.org>; jdenose@google.com; Lyude Paul
> <lyude@redhat.com>; loic.poulain@linaro.org;
> benjamin.tissoires@redhat.com; Andrew Duggan
> <aduggan@synaptics.com>; Jonathan Cameron
> <Jonathan.Cameron@huawei.com>; Maximilian Luz
> <luzmaximilian@gmail.com>; Miguel Ojeda <ojeda@kernel.org>; Uwe Kleine-
> König <u.kleine-koenig@pengutronix.de>; linux-input@vger.kernel.org;
> linux-kernel@vger.kernel.org
> Subject: Re: [PATCH] Input: synaptics-rmi4 - retry reading SMBus version on
> resume
> 
> CAUTION: Email originated externally, do not click links or open attachments
> unless you recognize the sender and know the content is safe.
> 
> 
> On Wed, May 10, 2023 at 3:06 PM Dmitry Torokhov
> <dmitry.torokhov@gmail.com> wrote:
> >
> >
> > I am not really fond of adding random repeats in the code base.
> > Andrew, do you know if the Synaptics device needs certain delay when
> > switching to SMbus mode?
> >
> That's reasonable. It's true this is a sleep to workaround rmi_smbus'
> expectation that
> it is able to successfully read from the i801 i2c smbus addr 0x2c on resume
> when it cannot.
> 
> I do not know why the i801 i2c addr 0x2c is not responding on resume.
> Infrequently it won't respond on boot during the initial
> psmouse_smbus_create_companion but that is less noticeable since it will
> stay in ps/2 mode and just lack features.
> 
> I do know adding a sleep in-between the psmouse deactivate call and
> rmi_smbus's attempts to read from the 0x2c addr allow it to succeed on this
> machine. I do not know the details as to why however.

Our Windows driver does a 30 ms delay between sending the disable command and trying to communicate over SMBus. I don’t know specifically why this delay is needed, but this is how we handle this case.

> 
> I can apply workarounds until the underlying issue can be identified and
> properly resolved.
> 
> I can apply patches and provide any sort of debugging or extra information
> that might be useful to anyone familiar with these devices.
> 
> The smbus controller in this particular machine is:
> 00:1f.3 SMBus [0c05]: Intel Corporation 8 Series/C220 Series Chipset Family
> SMBus Controller [8086:8c22] (rev 04)
> 
> Perhaps there's some way to detect when the addr is available later and have
> it trigger a new probe similar to how psmouse_smbus_notifier is triggered
> when the i801 bus becomes available?
> 
> Thank You,
> Jeff

Andrew
diff mbox series

Patch

diff --git a/drivers/input/rmi4/rmi_smbus.c b/drivers/input/rmi4/rmi_smbus.c
index 4bf0e1df6a4a..386e80ae141b 100644
--- a/drivers/input/rmi4/rmi_smbus.c
+++ b/drivers/input/rmi4/rmi_smbus.c
@@ -43,15 +43,26 @@  static int rmi_smb_get_version(struct rmi_smb_xport *rmi_smb)
 {
 	struct i2c_client *client = rmi_smb->client;
 	int retval;
+	int tries = 0;
 
 	/* Check if for SMBus new version device by reading version byte. */
-	retval = i2c_smbus_read_byte_data(client, SMB_PROTOCOL_VERSION_ADDRESS);
-	if (retval < 0) {
-		dev_err(&client->dev, "failed to get SMBus version number!\n");
-		return retval;
-	}
+	do {
+		if (tries > 0) {
+			dev_warn(&client->dev, "sleeping to retry getting the SMBus version number\n");
+			fsleep(5000);
+		}
+		retval = i2c_smbus_read_byte_data(client,
+				SMB_PROTOCOL_VERSION_ADDRESS);
+		if (retval >= 0)
+			return retval + 1;
 
-	return retval + 1;
+		dev_err(&client->dev, "failed to get SMBus version number!\n");
+		/* On resume the read of the version can
+		 * momentarily return -ENXIO.
+		 * Retry to allow additional time for it to succeed.
+		 */
+	} while (retval == -ENXIO && tries++ < 5);
+	return retval;
 }
 
 /* SMB block write - wrapper over ic2_smb_write_block */