All of lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH] hwmon: applesmc: avoid overlong udelay()
@ 2020-11-06 23:17 Matt Turner
  2020-11-06 23:21 ` Nathan Chancellor
  0 siblings, 1 reply; 4+ messages in thread
From: Matt Turner @ 2020-11-06 23:17 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Henrik Rydberg, Jean Delvare, Guenter Roeck, Richard Fontana,
	Dmitry Torokhov, linux-hwmon, linux-kernel, clang-built-linux

[-- Attachment #1: Type: text/plain, Size: 1588 bytes --]

On my late 2013 Macbook Pro, I have a couple of scripts that set the
fans to auto or full-speed:

fan-hi:
#!/bin/sh
sudo sh -c 'echo 1 > /sys/devices/platform/applesmc.768/fan1_manual
             echo 1 > /sys/devices/platform/applesmc.768/fan2_manual
             cat /sys/devices/platform/applesmc.768/fan1_max > /sys/devices/platform/applesmc.768/fan1_output
             cat /sys/devices/platform/applesmc.768/fan2_max > /sys/devices/platform/applesmc.768/fan2_output'

fan-auto:
#!/bin/sh
sudo sh -c 'echo 0 > /sys/devices/platform/applesmc.768/fan1_manual
             echo 0 > /sys/devices/platform/applesmc.768/fan2_manual'

Running ./fan-hi and then ./fan-auto on Linux v5.6 works and doesn't
cause any problems, but after updating to v5.9 I see this in dmesg:

[Nov 6 17:24] applesmc: send_byte(0x01, 0x0300) fail: 0x40
[  +0.000005] applesmc: FS! : write data fail
[  +0.191777] applesmc: send_byte(0x30, 0x0300) fail: 0x40
[  +0.000009] applesmc: F0Tg: write data fail
[  +7.097416] applesmc: send_byte(0x00, 0x0300) fail: 0x40
[  +0.000006] applesmc: FS! : write data fail

and the fan controls don't work.

Googling turned up this [1] which looks like the same problem. They said
it began occurring between v5.7 and v5.8, so I looked and found this
commit.

After reverting commit fff2d0f701e6753591609739f8ab9be1c8e80ebb from
v5.9, I no longer see the errors in dmesg and the fan controls work
again.

Any ideas what the problem is?

Thanks,
Matt

[1] https://stackoverflow.com/questions/63505469/cant-write-data-to-applesmc-error-after-upgrade-to-arch-linux-kernel-5-8-1

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 376 bytes --]

^ permalink raw reply	[flat|nested] 4+ messages in thread
* [PATCH] hwmon: applesmc: avoid overlong udelay()
@ 2020-05-27 13:51 Arnd Bergmann
  2020-05-27 16:22 ` Guenter Roeck
  0 siblings, 1 reply; 4+ messages in thread
From: Arnd Bergmann @ 2020-05-27 13:51 UTC (permalink / raw)
  To: Henrik Rydberg, Jean Delvare, Guenter Roeck
  Cc: Arnd Bergmann, Richard Fontana, Dmitry Torokhov, linux-hwmon,
	linux-kernel, clang-built-linux

Building this driver with "clang -O3" produces a link error
after the compiler partially unrolls the loop and 256ms
becomes a compile-time constant that triggers the check
in udelay():

ld.lld: error: undefined symbol: __bad_udelay
>>> referenced by applesmc.c
>>>               hwmon/applesmc.o:(read_smc) in archive drivers/built-in.a

I can see no reason against using a sleeping function here,
as no part of the driver runs in atomic context, so instead use
usleep_range() with a wide range and use jiffies for the
end condition.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
 drivers/hwmon/applesmc.c | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c
index ec93b8d673f5..316618409315 100644
--- a/drivers/hwmon/applesmc.c
+++ b/drivers/hwmon/applesmc.c
@@ -156,14 +156,19 @@ static struct workqueue_struct *applesmc_led_wq;
  */
 static int wait_read(void)
 {
+	unsigned long end = jiffies + (APPLESMC_MAX_WAIT * HZ) / USEC_PER_SEC;
 	u8 status;
 	int us;
+
 	for (us = APPLESMC_MIN_WAIT; us < APPLESMC_MAX_WAIT; us <<= 1) {
-		udelay(us);
+		usleep_range(us, us * 16);
 		status = inb(APPLESMC_CMD_PORT);
 		/* read: wait for smc to settle */
 		if (status & 0x01)
 			return 0;
+		/* timeout: give up */
+		if (time_after(jiffies, end))
+			break;
 	}
 
 	pr_warn("wait_read() fail: 0x%02x\n", status);
@@ -178,10 +183,11 @@ static int send_byte(u8 cmd, u16 port)
 {
 	u8 status;
 	int us;
+	unsigned long end = jiffies + (APPLESMC_MAX_WAIT * HZ) / USEC_PER_SEC;
 
 	outb(cmd, port);
 	for (us = APPLESMC_MIN_WAIT; us < APPLESMC_MAX_WAIT; us <<= 1) {
-		udelay(us);
+		usleep_range(us, us * 16);
 		status = inb(APPLESMC_CMD_PORT);
 		/* write: wait for smc to settle */
 		if (status & 0x02)
@@ -190,7 +196,7 @@ static int send_byte(u8 cmd, u16 port)
 		if (status & 0x04)
 			return 0;
 		/* timeout: give up */
-		if (us << 1 == APPLESMC_MAX_WAIT)
+		if (time_after(jiffies, end))
 			break;
 		/* busy: long wait and resend */
 		udelay(APPLESMC_RETRY_WAIT);
-- 
2.26.2


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

end of thread, other threads:[~2020-11-06 23:22 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2020-11-06 23:17 [PATCH] hwmon: applesmc: avoid overlong udelay() Matt Turner
2020-11-06 23:21 ` Nathan Chancellor
  -- strict thread matches above, loose matches on Subject: below --
2020-05-27 13:51 Arnd Bergmann
2020-05-27 16:22 ` Guenter Roeck

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.