summaryrefslogtreecommitdiff
path: root/drivers/input
diff options
context:
space:
mode:
authorDmitry Torokhov <dmitry.torokhov@gmail.com>2026-08-30 13:52:49 -0700
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2026-09-20 12:52:10 -0700
commit81d577c0c5c602cffb0e0c16cdbde9ffbc8bb1eb (patch)
tree1ac9f22474bc4832f232a26bc8e4437ebdb90286 /drivers/input
parente73972da25a81844b6f86ceaf4b27e280bfc219c (diff)
downloadlinux-81d577c0c5c602cffb0e0c16cdbde9ffbc8bb1eb.tar.gz
linux-81d577c0c5c602cffb0e0c16cdbde9ffbc8bb1eb.zip
Input: gscps2 - serialize hardware and buffer access in gscps2_flush()
gscps2_flush() reads from hardware registers and resets the ring buffer indices ps2port->act and ps2port->append. In gscps2_enable(), the trailing gscps2_flush() was called without holding ps2port->lock, racing with concurrent hardware interrupts and buffer access. Assert that ps2port->lock is held in gscps2_flush() with lockdep_assert_held(), and ensure all callers acquire ps2port->lock so that multi-step hardware sequences remain fully serialized without unprotected windows. Reported-by: sashiko-bot@kernel.org Assisted-by: LLM Link: https://patch.msgid.link/20260830-gscps2-v1-4-c733d4cae7f9@gmail.com Acked-by: Helge Deller <deller@gmx.de> Tested-by: Helge Deller <deller@gmx.de> Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Diffstat (limited to 'drivers/input')
-rw-r--r--drivers/input/serio/gscps2.c8
1 files changed, 6 insertions, 2 deletions
diff --git a/drivers/input/serio/gscps2.c b/drivers/input/serio/gscps2.c
index fef6fffb6f86..36c25db9ff7f 100644
--- a/drivers/input/serio/gscps2.c
+++ b/drivers/input/serio/gscps2.c
@@ -228,6 +228,8 @@ static int wait_TBE(char __iomem *addr)
*/
static void gscps2_flush(struct gscps2port *ps2port)
{
+ lockdep_assert_held(&ps2port->lock);
+
while (gscps2_readb_status(ps2port->addr) & GSC_STAT_RBNE)
gscps2_readb_input(ps2port->addr);
ps2port->act = 0;
@@ -364,7 +366,8 @@ static void gscps2_enable(struct gscps2port *ps2port, bool enable)
}
wait_TBE(ps2port->addr);
- gscps2_flush(ps2port);
+ scoped_guard(spinlock_irqsave, &ps2port->lock)
+ gscps2_flush(ps2port);
}
/*
@@ -551,7 +554,8 @@ static void __exit gscps2_remove(struct parisc_device *dev)
serio_unregister_port(ps2port->port);
free_irq(dev->irq, ps2port);
- gscps2_flush(ps2port);
+ scoped_guard(spinlock_irqsave, &ps2port->lock)
+ gscps2_flush(ps2port);
iounmap(ps2port->addr);
#if 0
release_mem_region(dev->hpa, GSC_STATUS + 4);