summaryrefslogtreecommitdiff
path: root/arch/um/kernel
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2020-12-11 10:56:07 +0100
committerRichard Weinberger <richard@nod.at>2020-12-13 22:42:01 +0100
commitcae20ba0a16cdb2c6d218ea3519bb0942f287b69 (patch)
tree86ca8cb75548d5afec41526d95ad493c416f815d /arch/um/kernel
parent452f94cecff692a76eaaa9330fca03fe0f204f6f (diff)
um: irq/sigio: Support suspend/resume handling of workaround IRQs
If the sigio workaround needed to be applied to a file descriptor, set_irq_wake() wouldn't work for it since it would get polled by the thread instead of causing SIGIO, and thus could never really cause a wakeup, since the thread notification FD wasn't marked as being able to wake up the system. Fix this by marking the thread's notification FD explicitly as a wake source FD, i.e. not suppressing SIGIO for it in suspend. In order to not cause spurious wakeups, we then need to remove all FDs that shouldn't wake up the system from the polling thread. In order to do this, add unlocked versions of ignore_sigio_fd() and add_sigio_fd() (nothing else is happening in suspend, so this is fine), and also modify ignore_sigio_fd() to return -ENOENT if the FD wasn't originally in there. This doesn't matter because nothing else currently checks the return value, but the irq code needs to know which ones to restore the workaround for. All told, this lets us use a timerfd for the RTC clock in the next patch, which doesn't send SIGIO. Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: Richard Weinberger <richard@nod.at>
Diffstat (limited to 'arch/um/kernel')
-rw-r--r--arch/um/kernel/irq.c17
1 files changed, 16 insertions, 1 deletions
diff --git a/arch/um/kernel/irq.c b/arch/um/kernel/irq.c
index ea43312cbfd3..3741d2380060 100644
--- a/arch/um/kernel/irq.c
+++ b/arch/um/kernel/irq.c
@@ -45,6 +45,7 @@ struct irq_entry {
int fd;
struct irq_reg reg[NUM_IRQ_TYPES];
bool suspended;
+ bool sigio_workaround;
};
static DEFINE_SPINLOCK(irq_lock);
@@ -392,7 +393,14 @@ void um_irqs_suspend(void)
if (!entry->reg[t].events)
continue;
- if (entry->reg[t].wakeup) {
+ /*
+ * For the SIGIO_WRITE_IRQ, which is used to handle the
+ * SIGIO workaround thread, we need special handling:
+ * enable wake for it itself, but below we tell it about
+ * any FDs that should be suspended.
+ */
+ if (entry->reg[t].wakeup ||
+ entry->reg[t].irq == SIGIO_WRITE_IRQ) {
wake = true;
break;
}
@@ -401,6 +409,8 @@ void um_irqs_suspend(void)
if (!wake) {
entry->suspended = true;
os_clear_fd_async(entry->fd);
+ entry->sigio_workaround =
+ !__ignore_sigio_fd(entry->fd);
}
}
spin_unlock_irqrestore(&irq_lock, flags);
@@ -418,6 +428,11 @@ void um_irqs_resume(void)
WARN(err < 0, "os_set_fd_async returned %d\n", err);
entry->suspended = false;
+
+ if (entry->sigio_workaround) {
+ err = __add_sigio_fd(entry->fd);
+ WARN(err < 0, "add_sigio_returned %d\n", err);
+ }
}
}
spin_unlock_irqrestore(&irq_lock, flags);