From fff2d0f701e6753591609739f8ab9be1c8e80ebb Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 27 May 2020 15:51:57 +0200 Subject: [PATCH] hwmon: (applesmc) avoid overlong udelay() 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 Link: https://lore.kernel.org/r/20200527135207.1118624-1-arnd@arndb.de Signed-off-by: Guenter Roeck --- 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);