Commit 0fde9064 authored by Brad Love's avatar Brad Love Committed by Greg Kroah-Hartman

media: cx23885: only reset DMA on problematic CPUs

commit 4bd46aa0 upstream.

It is reported that commit 95f408bb ("media: cx23885: Ryzen DMA
related RiSC engine stall fixes") caused regresssions with other CPUs.

Ensure that the quirk will be applied only for the CPUs that
are known to cause problems.

A module option is added for explicit control of the behaviour.

Fixes: 95f408bb ("media: cx23885: Ryzen DMA related RiSC engine stall fixes")
Signed-off-by: default avatarBrad Love <brad@nextdimension.cc>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab+samsung@kernel.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent e9ef9dd3
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include <linux/moduleparam.h> #include <linux/moduleparam.h>
#include <linux/kmod.h> #include <linux/kmod.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/delay.h> #include <linux/delay.h>
...@@ -41,6 +42,18 @@ MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>"); ...@@ -41,6 +42,18 @@ MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_VERSION(CX23885_VERSION); MODULE_VERSION(CX23885_VERSION);
/*
* Some platforms have been found to require periodic resetting of the DMA
* engine. Ryzen and XEON platforms are known to be affected. The symptom
* encountered is "mpeg risc op code error". Only Ryzen platforms employ
* this workaround if the option equals 1. The workaround can be explicitly
* disabled for all platforms by setting to 0, the workaround can be forced
* on for any platform by setting to 2.
*/
static unsigned int dma_reset_workaround = 1;
module_param(dma_reset_workaround, int, 0644);
MODULE_PARM_DESC(dma_reset_workaround, "periodic RiSC dma engine reset; 0-force disable, 1-driver detect (default), 2-force enable");
static unsigned int debug; static unsigned int debug;
module_param(debug, int, 0644); module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "enable debug messages"); MODULE_PARM_DESC(debug, "enable debug messages");
...@@ -603,8 +616,13 @@ static void cx23885_risc_disasm(struct cx23885_tsport *port, ...@@ -603,8 +616,13 @@ static void cx23885_risc_disasm(struct cx23885_tsport *port,
static void cx23885_clear_bridge_error(struct cx23885_dev *dev) static void cx23885_clear_bridge_error(struct cx23885_dev *dev)
{ {
uint32_t reg1_val = cx_read(TC_REQ); /* read-only */ uint32_t reg1_val, reg2_val;
uint32_t reg2_val = cx_read(TC_REQ_SET);
if (!dev->need_dma_reset)
return;
reg1_val = cx_read(TC_REQ); /* read-only */
reg2_val = cx_read(TC_REQ_SET);
if (reg1_val && reg2_val) { if (reg1_val && reg2_val) {
cx_write(TC_REQ, reg1_val); cx_write(TC_REQ, reg1_val);
...@@ -2058,6 +2076,37 @@ void cx23885_gpio_enable(struct cx23885_dev *dev, u32 mask, int asoutput) ...@@ -2058,6 +2076,37 @@ void cx23885_gpio_enable(struct cx23885_dev *dev, u32 mask, int asoutput)
/* TODO: 23-19 */ /* TODO: 23-19 */
} }
static struct {
int vendor, dev;
} const broken_dev_id[] = {
/* According with
* https://openbenchmarking.org/system/1703021-RI-AMDZEN08075/Ryzen%207%201800X/lspci,
* 0x1451 is PCI ID for the IOMMU found on Ryzen
*/
{ PCI_VENDOR_ID_AMD, 0x1451 },
};
static bool cx23885_does_need_dma_reset(void)
{
int i;
struct pci_dev *pdev = NULL;
if (dma_reset_workaround == 0)
return false;
else if (dma_reset_workaround == 2)
return true;
for (i = 0; i < ARRAY_SIZE(broken_dev_id); i++) {
pdev = pci_get_device(broken_dev_id[i].vendor,
broken_dev_id[i].dev, NULL);
if (pdev) {
pci_dev_put(pdev);
return true;
}
}
return false;
}
static int cx23885_initdev(struct pci_dev *pci_dev, static int cx23885_initdev(struct pci_dev *pci_dev,
const struct pci_device_id *pci_id) const struct pci_device_id *pci_id)
{ {
...@@ -2069,6 +2118,8 @@ static int cx23885_initdev(struct pci_dev *pci_dev, ...@@ -2069,6 +2118,8 @@ static int cx23885_initdev(struct pci_dev *pci_dev,
if (NULL == dev) if (NULL == dev)
return -ENOMEM; return -ENOMEM;
dev->need_dma_reset = cx23885_does_need_dma_reset();
err = v4l2_device_register(&pci_dev->dev, &dev->v4l2_dev); err = v4l2_device_register(&pci_dev->dev, &dev->v4l2_dev);
if (err < 0) if (err < 0)
goto fail_free; goto fail_free;
......
...@@ -451,6 +451,8 @@ struct cx23885_dev { ...@@ -451,6 +451,8 @@ struct cx23885_dev {
/* Analog raw audio */ /* Analog raw audio */
struct cx23885_audio_dev *audio_dev; struct cx23885_audio_dev *audio_dev;
/* Does the system require periodic DMA resets? */
unsigned int need_dma_reset:1;
}; };
static inline struct cx23885_dev *to_cx23885(struct v4l2_device *v4l2_dev) static inline struct cx23885_dev *to_cx23885(struct v4l2_device *v4l2_dev)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment