These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / media / pci / saa7164 / saa7164-core.c
index 9cf3c6c..8bbd092 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Driver for the NXP SAA7164 PCIe bridge
  *
- *  Copyright (c) 2010 Steven Toth <stoth@kernellabs.com>
+ *  Copyright (c) 2010-2015 Steven Toth <stoth@kernellabs.com>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -85,6 +85,11 @@ module_param(guard_checking, int, 0644);
 MODULE_PARM_DESC(guard_checking,
        "enable dma sanity checking for buffer overruns");
 
+static bool enable_msi = true;
+module_param(enable_msi, bool, 0444);
+MODULE_PARM_DESC(enable_msi,
+               "enable the use of an msi interrupt if available");
+
 static unsigned int saa7164_devcount;
 
 static DEFINE_MUTEX(devlist);
@@ -618,12 +623,7 @@ static irqreturn_t saa7164_irq_ts(struct saa7164_port *port)
 static irqreturn_t saa7164_irq(int irq, void *dev_id)
 {
        struct saa7164_dev *dev = dev_id;
-       struct saa7164_port *porta = &dev->ports[SAA7164_PORT_TS1];
-       struct saa7164_port *portb = &dev->ports[SAA7164_PORT_TS2];
-       struct saa7164_port *portc = &dev->ports[SAA7164_PORT_ENC1];
-       struct saa7164_port *portd = &dev->ports[SAA7164_PORT_ENC2];
-       struct saa7164_port *porte = &dev->ports[SAA7164_PORT_VBI1];
-       struct saa7164_port *portf = &dev->ports[SAA7164_PORT_VBI2];
+       struct saa7164_port *porta, *portb, *portc, *portd, *porte, *portf;
 
        u32 intid, intstat[INT_SIZE/4];
        int i, handled = 0, bit;
@@ -634,6 +634,13 @@ static irqreturn_t saa7164_irq(int irq, void *dev_id)
                goto out;
        }
 
+       porta = &dev->ports[SAA7164_PORT_TS1];
+       portb = &dev->ports[SAA7164_PORT_TS2];
+       portc = &dev->ports[SAA7164_PORT_ENC1];
+       portd = &dev->ports[SAA7164_PORT_ENC2];
+       porte = &dev->ports[SAA7164_PORT_VBI1];
+       portf = &dev->ports[SAA7164_PORT_VBI2];
+
        /* Check that the hardware is accessible. If the status bytes are
         * 0xFF then the device is not accessible, the the IRQ belongs
         * to another driver.
@@ -1184,6 +1191,39 @@ static int saa7164_thread_function(void *data)
        return 0;
 }
 
+static bool saa7164_enable_msi(struct pci_dev *pci_dev, struct saa7164_dev *dev)
+{
+       int err;
+
+       if (!enable_msi) {
+               printk(KERN_WARNING "%s() MSI disabled by module parameter 'enable_msi'"
+                      , __func__);
+               return false;
+       }
+
+       err = pci_enable_msi(pci_dev);
+
+       if (err) {
+               printk(KERN_ERR "%s() Failed to enable MSI interrupt."
+                       " Falling back to a shared IRQ\n", __func__);
+               return false;
+       }
+
+       /* 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);
+               return false;
+       }
+
+       return true;
+}
+
 static int saa7164_initdev(struct pci_dev *pci_dev,
                           const struct pci_device_id *pci_id)
 {
@@ -1224,19 +1264,28 @@ static int saa7164_initdev(struct pci_dev *pci_dev,
 
        pci_set_master(pci_dev);
        /* TODO */
-       if (!pci_dma_supported(pci_dev, 0xffffffff)) {
+       err = pci_set_dma_mask(pci_dev, 0xffffffff);
+       if (err) {
                printk("%s/0: Oops: no 32bit PCI DMA ???\n", dev->name);
-               err = -EIO;
                goto fail_irq;
        }
 
-       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);
-               err = -EIO;
-               goto fail_irq;
+       /* irq bit */
+       if (saa7164_enable_msi(pci_dev, dev)) {
+               dev->msi = true;
+       } else {
+               /* if we have an error (i.e. we don't have an interrupt)
+                        or msi is not enabled - fallback to shared 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);
+                       err = -EIO;
+                       goto fail_irq;
+               }
        }
 
        pci_set_drvdata(pci_dev, dev);
@@ -1439,6 +1488,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;
+       }
+
        pci_disable_device(pci_dev);
 
        mutex_lock(&devlist);