drm/nouveau: use MSI interrupts
authorLucas Stach <dev@lynxeye.de>
Wed, 28 Aug 2013 00:00:50 +0000 (02:00 +0200)
committerBen Skeggs <bskeggs@redhat.com>
Wed, 4 Sep 2013 03:48:23 +0000 (13:48 +1000)
MSIs were only problematic on some old, broken chipsets. But now that we
already see systems where PCI legacy interrupts are somewhat flaky, it's
really time to move to MSIs.

v2 (Ben Skeggs): blacklist BR02 boards

Signed-off-by: Lucas Stach <dev@lynxeye.de>
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
drivers/gpu/drm/nouveau/core/include/subdev/mc.h
drivers/gpu/drm/nouveau/core/os.h
drivers/gpu/drm/nouveau/core/subdev/mc/base.c

index 9d2cd200625084608b9a6ecb8e866a9dd7cecf2f..ce6569f365a7c133ca7038bcfe4827ab79d55770 100644 (file)
@@ -12,6 +12,7 @@ struct nouveau_mc_intr {
 struct nouveau_mc {
        struct nouveau_subdev base;
        const struct nouveau_mc_intr *intr_map;
+       bool use_msi;
 };
 
 static inline struct nouveau_mc *
index d48683a825853020b9816ef1e86181ab5c92fdb8..191e739f30d14f1c994db7028c759238b6604048 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/reboot.h>
 #include <linux/interrupt.h>
 #include <linux/log2.h>
+#include <linux/pm_runtime.h>
 
 #include <asm/unaligned.h>
 
index 20f9a538746eeba0164bc73c69f9a67a6330e840..37712a6df92358e2583b87a53df4a04cd25ba290 100644 (file)
@@ -23,7 +23,7 @@
  */
 
 #include <subdev/mc.h>
-#include <linux/pm_runtime.h>
+#include <core/option.h>
 
 static irqreturn_t
 nouveau_mc_intr(int irq, void *arg)
@@ -47,6 +47,9 @@ nouveau_mc_intr(int irq, void *arg)
                map++;
        }
 
+       if (pmc->use_msi)
+               nv_wr08(pmc->base.base.parent, 0x00088068, 0xff);
+
        if (intr) {
                nv_error(pmc, "unknown intr 0x%08x\n", stat);
        }
@@ -81,6 +84,8 @@ _nouveau_mc_dtor(struct nouveau_object *object)
        struct nouveau_device *device = nv_device(object);
        struct nouveau_mc *pmc = (void *)object;
        free_irq(device->pdev->irq, pmc);
+       if (pmc->use_msi)
+               pci_disable_msi(device->pdev);
        nouveau_subdev_destroy(&pmc->base);
 }
 
@@ -102,6 +107,23 @@ nouveau_mc_create_(struct nouveau_object *parent, struct nouveau_object *engine,
 
        pmc->intr_map = intr_map;
 
+       switch (device->pdev->device & 0x0ff0) {
+       case 0x00f0: /* BR02? */
+       case 0x02e0: /* BR02? */
+               pmc->use_msi = false;
+               break;
+       default:
+               pmc->use_msi = nouveau_boolopt(device->cfgopt, "NvMSI", true);
+               if (pmc->use_msi) {
+                       pmc->use_msi = pci_enable_msi(device->pdev) == 0;
+                       if (pmc->use_msi) {
+                               nv_info(pmc, "MSI interrupts enabled\n");
+                               nv_wr08(device, 0x00088068, 0xff);
+                       }
+               }
+               break;
+       }
+
        ret = request_irq(device->pdev->irq, nouveau_mc_intr,
                          IRQF_SHARED, "nouveau", pmc);
        if (ret < 0)