]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
media: cobalt: fix race condition in setting HPD
authorHans Verkuil <hverkuil-cisco@xs4all.nl>
Fri, 23 Apr 2021 08:00:49 +0000 (10:00 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 20 Jul 2021 14:20:58 +0000 (16:20 +0200)
[ Upstream commit 3d37ef41bed0854805ab9af22c422267510e1344 ]

The cobalt_s_bit_sysctrl reads the old register value over PCI,
then changes a bit and sets writes the new value to the register.

This is used among other things for setting the HPD output pin.

But if the HPD is changed for multiple inputs at the same time,
then this causes a race condition where a stale value is read.

Serialize this function with a mutex.

Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/media/pci/cobalt/cobalt-driver.c
drivers/media/pci/cobalt/cobalt-driver.h

index 979634000597f79124befabb48af909d4b8f6a6e..17b717a1c7fa3d067115df6960f0b44431486855 100644 (file)
@@ -689,6 +689,7 @@ static int cobalt_probe(struct pci_dev *pci_dev,
                return -ENOMEM;
        cobalt->pci_dev = pci_dev;
        cobalt->instance = i;
+       mutex_init(&cobalt->pci_lock);
 
        retval = v4l2_device_register(&pci_dev->dev, &cobalt->v4l2_dev);
        if (retval) {
index ed00dc9d93995e03ddf128dfb476dbc73ae086a3..8f9454d30b95e5255123802ec97756b1d5768094 100644 (file)
@@ -262,6 +262,8 @@ struct cobalt {
        int instance;
        struct pci_dev *pci_dev;
        struct v4l2_device v4l2_dev;
+       /* serialize PCI access in cobalt_s_bit_sysctrl() */
+       struct mutex pci_lock;
 
        void __iomem *bar0, *bar1;
 
@@ -333,10 +335,13 @@ static inline u32 cobalt_g_sysctrl(struct cobalt *cobalt)
 static inline void cobalt_s_bit_sysctrl(struct cobalt *cobalt,
                                        int bit, int val)
 {
-       u32 ctrl = cobalt_read_bar1(cobalt, COBALT_SYS_CTRL_BASE);
+       u32 ctrl;
 
+       mutex_lock(&cobalt->pci_lock);
+       ctrl = cobalt_read_bar1(cobalt, COBALT_SYS_CTRL_BASE);
        cobalt_write_bar1(cobalt, COBALT_SYS_CTRL_BASE,
                        (ctrl & ~(1UL << bit)) | (val << bit));
+       mutex_unlock(&cobalt->pci_lock);
 }
 
 static inline u32 cobalt_g_sysstat(struct cobalt *cobalt)