summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLucas Stach <dev@lynxeye.de>2013-08-28 02:00:50 +0200
committerBen Skeggs <bskeggs@redhat.com>2013-09-17 08:18:04 +1000
commit9f4306bda87496b50fbd610a213280380d0bb190 (patch)
treec69044acb23376b1b5f711ed983718bff076c8cd
parent3af07077deef3c4ba681e1a29c2133cfeec2ba78 (diff)
downloadnouveau-9f4306bda87496b50fbd610a213280380d0bb190.tar.gz
mc: use MSI interrupts where possible
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>
-rw-r--r--lib/core/os.h11
-rw-r--r--nvkm/include/subdev/mc.h1
-rw-r--r--nvkm/subdev/mc/base.c23
3 files changed, 35 insertions, 0 deletions
diff --git a/lib/core/os.h b/lib/core/os.h
index 76a75d231..1e90357cf 100644
--- a/lib/core/os.h
+++ b/lib/core/os.h
@@ -555,6 +555,17 @@ pci_free_consistent(struct pci_dev *hwdev, size_t size,
{
}
+static inline int
+pci_enable_msi(struct pci_dev *pdev)
+{
+ return -ENOSYS;
+}
+
+static inline void
+pci_disable_msi(struct pci_dev *pdev)
+{
+}
+
#define PCI_DEVFN(a,b) 0
#define pci_get_bus_and_slot(a, b) NULL
#define pci_read_config_dword(a,b,c) *(c) = 0
diff --git a/nvkm/include/subdev/mc.h b/nvkm/include/subdev/mc.h
index 9d2cd2006..ce6569f36 100644
--- a/nvkm/include/subdev/mc.h
+++ b/nvkm/include/subdev/mc.h
@@ -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 *
diff --git a/nvkm/subdev/mc/base.c b/nvkm/subdev/mc/base.c
index ec9cd6f10..92fbf6405 100644
--- a/nvkm/subdev/mc/base.c
+++ b/nvkm/subdev/mc/base.c
@@ -23,6 +23,7 @@
*/
#include <subdev/mc.h>
+#include <core/option.h>
static irqreturn_t
nouveau_mc_intr(int irq, void *arg)
@@ -43,6 +44,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);
}
@@ -75,6 +79,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);
}
@@ -96,6 +102,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)