aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2010-10-21 00:07:03 -0400
committerBen Skeggs <bskeggs@redhat.com>2010-12-03 00:11:03 -0500
commit35fa2f2ad161024e735fb0cd571cb92e50171afd (patch)
treee6c45b234f2af49d0a4fb4634954042daa64c06e
parent01d63187d1aad6236dd229d5824c61a60f1ab42c (diff)
drm/nouveau: add support for MSI
Only supported on NV50+ so far, and disabled by default currently. The module parameter "msi=1" will enable it. There's a kernel bug which will cause this to fail if the module (or the NVIDIA binary driver) has ever been loaded before loading nouveau with MSI enabled. As such, this is only safe to enable if you have nouveau load on boot, and don't wish to ever reload it. The workaround is to "echo 0 > /sys/bus/pci/devices/<device>/enable" until the enable count reads 0. Then you should be able to load nouveau with MSI enabled. Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drv.c4
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drv.h5
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_irq.c35
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_state.c9
4 files changed, 47 insertions, 6 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.c b/drivers/gpu/drm/nouveau/nouveau_drv.c
index 6dbb8818c530..db926ecf5b6f 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.c
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.c
@@ -115,6 +115,10 @@ MODULE_PARM_DESC(perflvl_wr, "Allow perflvl changes (warning: dangerous!)\n");
115int nouveau_perflvl_wr; 115int nouveau_perflvl_wr;
116module_param_named(perflvl_wr, nouveau_perflvl_wr, int, 0400); 116module_param_named(perflvl_wr, nouveau_perflvl_wr, int, 0400);
117 117
118MODULE_PARM_DESC(msi, "Enable MSI (default: off)\n");
119int nouveau_msi;
120module_param_named(msi, nouveau_msi, int, 0400);
121
118int nouveau_fbpercrtc; 122int nouveau_fbpercrtc;
119#if 0 123#if 0
120module_param_named(fbpercrtc, nouveau_fbpercrtc, int, 0400); 124module_param_named(fbpercrtc, nouveau_fbpercrtc, int, 0400);
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
index bf34f25c7a54..9ab7dc8ede4e 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.h
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
@@ -593,6 +593,8 @@ struct drm_nouveau_private {
593 593
594 struct nouveau_bo *vga_ram; 594 struct nouveau_bo *vga_ram;
595 595
596 /* interrupt handling */
597 bool msi_enabled;
596 struct workqueue_struct *wq; 598 struct workqueue_struct *wq;
597 struct work_struct irq_work; 599 struct work_struct irq_work;
598 struct work_struct hpd_work; 600 struct work_struct hpd_work;
@@ -754,6 +756,7 @@ extern int nouveau_force_post;
754extern int nouveau_override_conntype; 756extern int nouveau_override_conntype;
755extern char *nouveau_perflvl; 757extern char *nouveau_perflvl;
756extern int nouveau_perflvl_wr; 758extern int nouveau_perflvl_wr;
759extern int nouveau_msi;
757 760
758extern int nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state); 761extern int nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state);
759extern int nouveau_pci_resume(struct pci_dev *pdev); 762extern int nouveau_pci_resume(struct pci_dev *pdev);
@@ -872,6 +875,8 @@ extern int nouveau_ioctl_gpuobj_free(struct drm_device *, void *data,
872 struct drm_file *); 875 struct drm_file *);
873 876
874/* nouveau_irq.c */ 877/* nouveau_irq.c */
878extern int nouveau_irq_init(struct drm_device *);
879extern void nouveau_irq_fini(struct drm_device *);
875extern irqreturn_t nouveau_irq_handler(DRM_IRQ_ARGS); 880extern irqreturn_t nouveau_irq_handler(DRM_IRQ_ARGS);
876extern void nouveau_irq_preinstall(struct drm_device *); 881extern void nouveau_irq_preinstall(struct drm_device *);
877extern int nouveau_irq_postinstall(struct drm_device *); 882extern int nouveau_irq_postinstall(struct drm_device *);
diff --git a/drivers/gpu/drm/nouveau/nouveau_irq.c b/drivers/gpu/drm/nouveau/nouveau_irq.c
index ca9b969f4f9c..17e2fa86cde7 100644
--- a/drivers/gpu/drm/nouveau/nouveau_irq.c
+++ b/drivers/gpu/drm/nouveau/nouveau_irq.c
@@ -68,8 +68,13 @@ nouveau_irq_preinstall(struct drm_device *dev)
68int 68int
69nouveau_irq_postinstall(struct drm_device *dev) 69nouveau_irq_postinstall(struct drm_device *dev)
70{ 70{
71 struct drm_nouveau_private *dev_priv = dev->dev_private;
72
71 /* Master enable */ 73 /* Master enable */
72 nv_wr32(dev, NV03_PMC_INTR_EN_0, NV_PMC_INTR_EN_0_MASTER_ENABLE); 74 nv_wr32(dev, NV03_PMC_INTR_EN_0, NV_PMC_INTR_EN_0_MASTER_ENABLE);
75 if (dev_priv->msi_enabled)
76 nv_wr08(dev, 0x00088068, 0xff);
77
73 return 0; 78 return 0;
74} 79}
75 80
@@ -1263,5 +1268,35 @@ nouveau_irq_handler(DRM_IRQ_ARGS)
1263 1268
1264 spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); 1269 spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
1265 1270
1271 if (dev_priv->msi_enabled)
1272 nv_wr08(dev, 0x00088068, 0xff);
1273
1266 return IRQ_HANDLED; 1274 return IRQ_HANDLED;
1267} 1275}
1276
1277int
1278nouveau_irq_init(struct drm_device *dev)
1279{
1280 struct drm_nouveau_private *dev_priv = dev->dev_private;
1281 int ret;
1282
1283 if (nouveau_msi != 0 && dev_priv->card_type >= NV_50) {
1284 ret = pci_enable_msi(dev->pdev);
1285 if (ret == 0) {
1286 NV_INFO(dev, "enabled MSI\n");
1287 dev_priv->msi_enabled = true;
1288 }
1289 }
1290
1291 return drm_irq_install(dev);
1292}
1293
1294void
1295nouveau_irq_fini(struct drm_device *dev)
1296{
1297 struct drm_nouveau_private *dev_priv = dev->dev_private;
1298
1299 drm_irq_uninstall(dev);
1300 if (dev_priv->msi_enabled)
1301 pci_disable_msi(dev->pdev);
1302}
diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c
index f13134aa8c4f..410a79f5e0cd 100644
--- a/drivers/gpu/drm/nouveau/nouveau_state.c
+++ b/drivers/gpu/drm/nouveau/nouveau_state.c
@@ -667,10 +667,7 @@ nouveau_card_init(struct drm_device *dev)
667 if (ret) 667 if (ret)
668 goto out_fifo; 668 goto out_fifo;
669 669
670 /* this call irq_preinstall, register irq handler and 670 ret = nouveau_irq_init(dev);
671 * call irq_postinstall
672 */
673 ret = drm_irq_install(dev);
674 if (ret) 671 if (ret)
675 goto out_display; 672 goto out_display;
676 673
@@ -701,7 +698,7 @@ nouveau_card_init(struct drm_device *dev)
701out_fence: 698out_fence:
702 nouveau_fence_fini(dev); 699 nouveau_fence_fini(dev);
703out_irq: 700out_irq:
704 drm_irq_uninstall(dev); 701 nouveau_irq_fini(dev);
705out_display: 702out_display:
706 engine->display.destroy(dev); 703 engine->display.destroy(dev);
707out_fifo: 704out_fifo:
@@ -772,7 +769,7 @@ static void nouveau_card_takedown(struct drm_device *dev)
772 nouveau_gpuobj_takedown(dev); 769 nouveau_gpuobj_takedown(dev);
773 nouveau_mem_vram_fini(dev); 770 nouveau_mem_vram_fini(dev);
774 771
775 drm_irq_uninstall(dev); 772 nouveau_irq_fini(dev);
776 773
777 nouveau_pm_fini(dev); 774 nouveau_pm_fini(dev);
778 nouveau_bios_takedown(dev); 775 nouveau_bios_takedown(dev);