| From f634230a3ff6389d0f5ceeec83dfefdd1eb62afa Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Fri, 23 Apr 2021 10:00:49 +0200 |
| Subject: media: cobalt: fix race condition in setting HPD |
| |
| From: Hans Verkuil <hverkuil-cisco@xs4all.nl> |
| |
| [ 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 | 1 + |
| drivers/media/pci/cobalt/cobalt-driver.h | 7 ++++++- |
| 2 files changed, 7 insertions(+), 1 deletion(-) |
| |
| diff --git a/drivers/media/pci/cobalt/cobalt-driver.c b/drivers/media/pci/cobalt/cobalt-driver.c |
| index 0695078ef812..1bd8bbe57a30 100644 |
| --- a/drivers/media/pci/cobalt/cobalt-driver.c |
| +++ b/drivers/media/pci/cobalt/cobalt-driver.c |
| @@ -667,6 +667,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) { |
| diff --git a/drivers/media/pci/cobalt/cobalt-driver.h b/drivers/media/pci/cobalt/cobalt-driver.h |
| index bca68572b324..12c33e035904 100644 |
| --- a/drivers/media/pci/cobalt/cobalt-driver.h |
| +++ b/drivers/media/pci/cobalt/cobalt-driver.h |
| @@ -251,6 +251,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; |
| |
| @@ -320,10 +322,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) |
| -- |
| 2.30.2 |
| |