| From 65633777e617756ee80a57773bb5be07f026c6a6 Mon Sep 17 00:00:00 2001 |
| From: Guenter Roeck <linux@roeck-us.net> |
| Date: Thu, 4 Apr 2019 10:52:43 -0700 |
| Subject: hwmon: (f71805f) Use request_muxed_region for Super-IO accesses |
| |
| [ Upstream commit 73e6ff71a7ea924fb7121d576a2d41e3be3fc6b5 ] |
| |
| Super-IO accesses may fail on a system with no or unmapped LPC bus. |
| |
| Unable to handle kernel paging request at virtual address ffffffbffee0002e |
| pgd = ffffffc1d68d4000 |
| [ffffffbffee0002e] *pgd=0000000000000000, *pud=0000000000000000 |
| Internal error: Oops: 94000046 [#1] PREEMPT SMP |
| Modules linked in: f71805f(+) hwmon |
| CPU: 3 PID: 1659 Comm: insmod Not tainted 4.5.0+ #88 |
| Hardware name: linux,dummy-virt (DT) |
| task: ffffffc1f6665400 ti: ffffffc1d6418000 task.ti: ffffffc1d6418000 |
| PC is at f71805f_find+0x6c/0x358 [f71805f] |
| |
| Also, other drivers may attempt to access the LPC bus at the same time, |
| resulting in undefined behavior. |
| |
| Use request_muxed_region() to ensure that IO access on the requested |
| address space is supported, and to ensure that access by multiple |
| drivers is synchronized. |
| |
| Fixes: e53004e20a58e ("hwmon: New f71805f driver") |
| Reported-by: Kefeng Wang <wangkefeng.wang@huawei.com> |
| Reported-by: John Garry <john.garry@huawei.com> |
| Cc: John Garry <john.garry@huawei.com> |
| Acked-by: John Garry <john.garry@huawei.com> |
| Signed-off-by: Guenter Roeck <linux@roeck-us.net> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/hwmon/f71805f.c | 15 ++++++++++++--- |
| 1 file changed, 12 insertions(+), 3 deletions(-) |
| |
| diff --git a/drivers/hwmon/f71805f.c b/drivers/hwmon/f71805f.c |
| index 73c681162653b..623736d2a7c1d 100644 |
| --- a/drivers/hwmon/f71805f.c |
| +++ b/drivers/hwmon/f71805f.c |
| @@ -96,17 +96,23 @@ superio_select(int base, int ld) |
| outb(ld, base + 1); |
| } |
| |
| -static inline void |
| +static inline int |
| superio_enter(int base) |
| { |
| + if (!request_muxed_region(base, 2, DRVNAME)) |
| + return -EBUSY; |
| + |
| outb(0x87, base); |
| outb(0x87, base); |
| + |
| + return 0; |
| } |
| |
| static inline void |
| superio_exit(int base) |
| { |
| outb(0xaa, base); |
| + release_region(base, 2); |
| } |
| |
| /* |
| @@ -1561,7 +1567,7 @@ static int __init f71805f_device_add(unsigned short address, |
| static int __init f71805f_find(int sioaddr, unsigned short *address, |
| struct f71805f_sio_data *sio_data) |
| { |
| - int err = -ENODEV; |
| + int err; |
| u16 devid; |
| |
| static const char * const names[] = { |
| @@ -1569,8 +1575,11 @@ static int __init f71805f_find(int sioaddr, unsigned short *address, |
| "F71872F/FG or F71806F/FG", |
| }; |
| |
| - superio_enter(sioaddr); |
| + err = superio_enter(sioaddr); |
| + if (err) |
| + return err; |
| |
| + err = -ENODEV; |
| devid = superio_inw(sioaddr, SIO_REG_MANID); |
| if (devid != SIO_FINTEK_ID) |
| goto exit; |
| -- |
| 2.20.1 |
| |