summaryrefslogtreecommitdiff
path: root/drivers/soc
diff options
context:
space:
mode:
authorIwona Winiarska <iwona.winiarska@intel.com>2021-12-01 00:20:37 +0300
committerIwona Winiarska <iwona.winiarska@intel.com>2021-12-15 14:57:09 +0300
commitc1000fe8c34d287c6526041e7f890548bfba993e (patch)
tree79ce42f43023f8ade866ef133bce81d269c8c2d2 /drivers/soc
parentd4457cf3ab689cd9b1848a9e96fd1a8a60b743e5 (diff)
downloadlinux-c1000fe8c34d287c6526041e7f890548bfba993e.tar.xz
soc: aspeed: espi-slave: Avoid calling put_user in atomic context
put_user() can sleep, which means that calling it in atomic context can cause deadlock. aspeed-espi-slave is calling it under spin_lock_irqsave(), resulting in the following lockdep splat: [ 18.796723] BUG: sleeping function called from invalid context at drivers/soc/aspeed/aspeed-espi-slave.c:309 [ 18.807742] in_atomic(): 1, irqs_disabled(): 128, non_block: 0, pid: 311, name: host-misc-manag [ 18.817486] INFO: lockdep is turned off. [ 18.821869] irq event stamp: 0 [ 18.825289] hardirqs last enabled at (0): [<00000000>] 0x0 [ 18.831551] hardirqs last disabled at (0): [<8011ed40>] copy_process+0x7b0/0x1be8 [ 18.839941] softirqs last enabled at (0): [<8011ed40>] copy_process+0x7b0/0x1be8 [ 18.848308] softirqs last disabled at (0): [<00000000>] 0x0 [ 18.854538] CPU: 0 PID: 311 Comm: host-misc-manag Not tainted 5.15.0-14fcc87-dirty-7b64388 #1 [ 18.864070] Hardware name: Generic DT based system [ 18.869421] Backtrace: [ 18.872155] [<80a48ec4>] (dump_backtrace) from [<80a492a8>] (show_stack+0x20/0x24) [ 18.880638] r7:0242c06c r6:00000080 r5:80cb88f4 r4:600d0093 [ 18.886969] [<80a49288>] (show_stack) from [<80a5596c>] (dump_stack_lvl+0x60/0x78) [ 18.895440] [<80a5590c>] (dump_stack_lvl) from [<80a5599c>] (dump_stack+0x18/0x1c) [ 18.903907] r7:0242c06c r6:00000135 r5:80d0a958 r4:8ffc2000 [ 18.910226] [<80a55984>] (dump_stack) from [<80160d3c>] (___might_sleep+0x1b0/0x2c0) [ 18.918901] [<80160b8c>] (___might_sleep) from [<80160ebc>] (__might_sleep+0x70/0xac) [ 18.927818] r6:00000000 r5:00000135 r4:80d0a958 [ 18.933024] [<80160e4c>] (__might_sleep) from [<802a1cf8>] (__might_fault+0x48/0xb0) [ 18.941690] r6:8238da58 r5:00000000 r4:ffffe000 [ 18.946848] [<802a1cb0>] (__might_fault) from [<8060ed78>] (aspeed_espi_pltrstn_read+0xac/0x254) [ 18.956679] r5:8238da80 r4:ffffe000 [ 18.960669] [<8060eccc>] (aspeed_espi_pltrstn_read) from [<802d6024>] (vfs_read+0xc0/0x320) [ 18.970011] r10:00000003 r9:8ffc2000 r8:8060eccc r7:00000001 r6:00000001 r5:8ffc3f68 [ 18.978754] r4:84eb48c0 [ 18.981582] [<802d5f64>] (vfs_read) from [<802d6e04>] (ksys_read+0x70/0xf4) [ 18.989378] r10:00000003 r9:8ffc2000 r8:80100224 r7:00000000 r6:00000000 r5:84eb48c0 [ 18.998122] r4:84eb48c0 [ 19.000946] [<802d6d94>] (ksys_read) from [<802d6ea0>] (sys_read+0x18/0x1c) [ 19.008735] r7:00000003 r6:7ec07a00 r5:76fc3070 r4:0242c220 [ 19.015055] [<802d6e88>] (sys_read) from [<80100060>] (ret_fast_syscall+0x0/0x1c) [ 19.023419] Exception stack(0x8ffc3fa8 to 0x8ffc3ff0) [ 19.029063] 3fa0: 0242c220 76fc3070 00000007 0242c06c 00000001 00000000 [ 19.038196] 3fc0: 0242c220 76fc3070 7ec07a00 00000003 0242c23c 0242c06c 00000001 00000000 [ 19.047330] 3fe0: 00446be4 7ec079d8 00424b88 76cb536c Rearrange the code to avoid calling *_user() function under spin_lock. Also, use the regular *_irq() variant instead if *_irqsave(), since it's only used for serializing process context with IRQ handler. Signed-off-by: Iwona Winiarska <iwona.winiarska@intel.com> Change-Id: Iaf17ddd17c020c8ee8c60c2fc98a57b97133e7a6
Diffstat (limited to 'drivers/soc')
-rw-r--r--drivers/soc/aspeed/aspeed-espi-slave.c44
1 files changed, 20 insertions, 24 deletions
diff --git a/drivers/soc/aspeed/aspeed-espi-slave.c b/drivers/soc/aspeed/aspeed-espi-slave.c
index ea68734afa7b..52d900893d32 100644
--- a/drivers/soc/aspeed/aspeed-espi-slave.c
+++ b/drivers/soc/aspeed/aspeed-espi-slave.c
@@ -294,24 +294,17 @@ static ssize_t aspeed_espi_pltrstn_read(struct file *filp, char __user *buf,
{
struct aspeed_espi *priv = to_aspeed_espi(filp);
DECLARE_WAITQUEUE(wait, current);
- unsigned long flags;
- char old_sample;
+ char data, old_sample;
int ret = 0;
- spin_lock_irqsave(&priv->pltrstn_lock, flags);
+ spin_lock_irq(&priv->pltrstn_lock);
if (filp->f_flags & O_NONBLOCK) {
if (!priv->pltrstn_in_avail) {
ret = -EAGAIN;
goto out_unlock;
}
- char data = priv->pltrstn;
- ret = put_user(data, (unsigned long __user *)buf);
- if (!ret){
- ret = sizeof(data);
- } else{
- ret = -EAGAIN;
- }
+ data = priv->pltrstn;
priv->pltrstn_in_avail = false;
} else {
add_wait_queue(&priv->pltrstn_waitq, &wait);
@@ -320,22 +313,18 @@ static ssize_t aspeed_espi_pltrstn_read(struct file *filp, char __user *buf,
old_sample = priv->pltrstn;
do {
- char new_sample = priv->pltrstn;
-
- if (old_sample != new_sample) {
- ret = put_user(new_sample,
- (unsigned long __user *)buf);
- if (!ret)
- ret = sizeof(new_sample);
- } else if (signal_pending(current)) {
- ret = -ERESTARTSYS;
+ if (old_sample != priv->pltrstn) {
+ data = priv->pltrstn;
+ priv->pltrstn_in_avail = false;
+ break;
}
- if (!ret) {
- spin_unlock_irqrestore(&priv->pltrstn_lock,
- flags);
+ if (signal_pending(current)) {
+ ret = -ERESTARTSYS;
+ } else {
+ spin_unlock_irq(&priv->pltrstn_lock);
schedule();
- spin_lock_irqsave(&priv->pltrstn_lock, flags);
+ spin_lock_irq(&priv->pltrstn_lock);
}
} while (!ret);
@@ -343,7 +332,14 @@ static ssize_t aspeed_espi_pltrstn_read(struct file *filp, char __user *buf,
set_current_state(TASK_RUNNING);
}
out_unlock:
- spin_unlock_irqrestore(&priv->pltrstn_lock, flags);
+ spin_unlock_irq(&priv->pltrstn_lock);
+
+ if (ret)
+ return ret;
+
+ ret = put_user(data, buf);
+ if (!ret)
+ ret = sizeof(data);
return ret;
}