From: Brendan McGrath <redmcg@xxxxxxxxxxxxxxxxxxx>
[media] saa7164: use an MSI interrupt when available
Fixes a known crash which most commonly occurs when multiple saa7164
chips are in use.
Signed-off-by: Brendan McGrath <redmcg@xxxxxxxxxxxxxxxxxxx>
---
drivers/media/pci/saa7164/saa7164-core.c | 34
++++++++++++++++++++++++++++++--
drivers/media/pci/saa7164/saa7164.h | 1 +
2 files changed, 33 insertions(+), 2 deletions(-)
This patch falls back to the original code - a 'shared' interrupt - when
MSI is not available (or encounters an error).
Many of today's cards that use the saa7164 chip operate on a PCI-E bus
(thus MSI should be available). Examples: the Hauppage HVR-2200 and HVR-2250
This enhancement also fixes an issue that was causing the driver to crash:
http://permalink.gmane.org/gmane.linux.drivers.video-input-infrastructure/83948
I believe the root cause of the crash is due to a DMA/IRQ race
condition. It most commonly occurs when the saa7164 driver is dealing
with more than one saa7164 chip (the HVR-2200 and HVR-2250 for example
have two - one for each tuner). Given MSI avoids DMA/IRQ race conditions
- this would explain why the patch works as a fix.
diff --git a/drivers/media/pci/saa7164/saa7164-core.c
b/drivers/media/pci/saa7164/saa7164-core.c
index 4b0bec3..083bea4 100644
--- a/drivers/media/pci/saa7164/saa7164-core.c
+++ b/drivers/media/pci/saa7164/saa7164-core.c
@@ -1230,8 +1230,33 @@ static int saa7164_initdev(struct pci_dev *pci_dev,
goto fail_irq;
}
- err = request_irq(pci_dev->irq, saa7164_irq,
- IRQF_SHARED, dev->name, dev);
+ /* irq bit */
+ err = pci_enable_msi(pci_dev);
+
+ if (!err) {
+ /* no error - so request an msi interrupt */
+ err = request_irq(pci_dev->irq, saa7164_irq, 0,
+ dev->name, dev);
+
+ if (err) {
+ /* fall back to legacy interrupt */
+ printk(KERN_ERR "%s() Failed to get an MSI interrupt."
+ " Falling back to a shared IRQ\n", __func__);
+ pci_disable_msi(pci_dev);
+ } else {
+ dev->msi = true;
+ }
+ }
+
+ if (err) {
+ dev->msi = false;
+ /* if we have an error (i.e. we don't have an interrupt)
+ - fallback to legacy interrupt */
+
+ err = request_irq(pci_dev->irq, saa7164_irq,
+ IRQF_SHARED, dev->name, dev);
+ }
+
if (err < 0) {
printk(KERN_ERR "%s: can't get IRQ %d\n", dev->name,
pci_dev->irq);
@@ -1441,6 +1466,11 @@ static void saa7164_finidev(struct pci_dev *pci_dev)
/* unregister stuff */
free_irq(pci_dev->irq, dev);
+ if (dev->msi) {
+ pci_disable_msi(pci_dev);
+ dev->msi = false;
+ }
+
mutex_lock(&devlist);
list_del(&dev->devlist);
mutex_unlock(&devlist);
diff --git a/drivers/media/pci/saa7164/saa7164.h
b/drivers/media/pci/saa7164/saa7164.h
index cd1a07c..6df4b252 100644
--- a/drivers/media/pci/saa7164/saa7164.h
+++ b/drivers/media/pci/saa7164/saa7164.h
@@ -459,6 +459,7 @@ struct saa7164_dev {
/* Interrupt status and ack registers */
u32 int_status;
u32 int_ack;
+ u32 msi;
struct cmd cmds[SAA_CMD_MAX_MSG_UNITS];
struct mutex lock;
--
1.9.1
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html