aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/nouveau/nv50_fb.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/nouveau/nv50_fb.c')
-rw-r--r--drivers/gpu/drm/nouveau/nv50_fb.c71
1 files changed, 66 insertions, 5 deletions
diff --git a/drivers/gpu/drm/nouveau/nv50_fb.c b/drivers/gpu/drm/nouveau/nv50_fb.c
index cd1988b15d2c..50290dea0ac4 100644
--- a/drivers/gpu/drm/nouveau/nv50_fb.c
+++ b/drivers/gpu/drm/nouveau/nv50_fb.c
@@ -3,30 +3,75 @@
3#include "nouveau_drv.h" 3#include "nouveau_drv.h"
4#include "nouveau_drm.h" 4#include "nouveau_drm.h"
5 5
6struct nv50_fb_priv {
7 struct page *r100c08_page;
8 dma_addr_t r100c08;
9};
10
11static int
12nv50_fb_create(struct drm_device *dev)
13{
14 struct drm_nouveau_private *dev_priv = dev->dev_private;
15 struct nv50_fb_priv *priv;
16
17 priv = kzalloc(sizeof(*priv), GFP_KERNEL);
18 if (!priv)
19 return -ENOMEM;
20
21 priv->r100c08_page = alloc_page(GFP_KERNEL | __GFP_ZERO);
22 if (!priv->r100c08_page) {
23 kfree(priv);
24 return -ENOMEM;
25 }
26
27 priv->r100c08 = pci_map_page(dev->pdev, priv->r100c08_page, 0,
28 PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
29 if (pci_dma_mapping_error(dev->pdev, priv->r100c08)) {
30 __free_page(priv->r100c08_page);
31 kfree(priv);
32 return -EFAULT;
33 }
34
35 dev_priv->engine.fb.priv = priv;
36 return 0;
37}
38
6int 39int
7nv50_fb_init(struct drm_device *dev) 40nv50_fb_init(struct drm_device *dev)
8{ 41{
9 struct drm_nouveau_private *dev_priv = dev->dev_private; 42 struct drm_nouveau_private *dev_priv = dev->dev_private;
43 struct nv50_fb_priv *priv;
44 int ret;
45
46 if (!dev_priv->engine.fb.priv) {
47 ret = nv50_fb_create(dev);
48 if (ret)
49 return ret;
50 }
51 priv = dev_priv->engine.fb.priv;
10 52
11 /* Not a clue what this is exactly. Without pointing it at a 53 /* Not a clue what this is exactly. Without pointing it at a
12 * scratch page, VRAM->GART blits with M2MF (as in DDX DFS) 54 * scratch page, VRAM->GART blits with M2MF (as in DDX DFS)
13 * cause IOMMU "read from address 0" errors (rh#561267) 55 * cause IOMMU "read from address 0" errors (rh#561267)
14 */ 56 */
15 nv_wr32(dev, 0x100c08, dev_priv->gart_info.sg_dummy_bus >> 8); 57 nv_wr32(dev, 0x100c08, priv->r100c08 >> 8);
16 58
17 /* This is needed to get meaningful information from 100c90 59 /* This is needed to get meaningful information from 100c90
18 * on traps. No idea what these values mean exactly. */ 60 * on traps. No idea what these values mean exactly. */
19 switch (dev_priv->chipset) { 61 switch (dev_priv->chipset) {
20 case 0x50: 62 case 0x50:
21 nv_wr32(dev, 0x100c90, 0x0707ff); 63 nv_wr32(dev, 0x100c90, 0x000707ff);
22 break; 64 break;
23 case 0xa3: 65 case 0xa3:
24 case 0xa5: 66 case 0xa5:
25 case 0xa8: 67 case 0xa8:
26 nv_wr32(dev, 0x100c90, 0x0d0fff); 68 nv_wr32(dev, 0x100c90, 0x000d0fff);
69 break;
70 case 0xaf:
71 nv_wr32(dev, 0x100c90, 0x089d1fff);
27 break; 72 break;
28 default: 73 default:
29 nv_wr32(dev, 0x100c90, 0x1d07ff); 74 nv_wr32(dev, 0x100c90, 0x001d07ff);
30 break; 75 break;
31 } 76 }
32 77
@@ -36,12 +81,25 @@ nv50_fb_init(struct drm_device *dev)
36void 81void
37nv50_fb_takedown(struct drm_device *dev) 82nv50_fb_takedown(struct drm_device *dev)
38{ 83{
84 struct drm_nouveau_private *dev_priv = dev->dev_private;
85 struct nv50_fb_priv *priv;
86
87 priv = dev_priv->engine.fb.priv;
88 if (!priv)
89 return;
90 dev_priv->engine.fb.priv = NULL;
91
92 pci_unmap_page(dev->pdev, priv->r100c08, PAGE_SIZE,
93 PCI_DMA_BIDIRECTIONAL);
94 __free_page(priv->r100c08_page);
95 kfree(priv);
39} 96}
40 97
41void 98void
42nv50_fb_vm_trap(struct drm_device *dev, int display, const char *name) 99nv50_fb_vm_trap(struct drm_device *dev, int display, const char *name)
43{ 100{
44 struct drm_nouveau_private *dev_priv = dev->dev_private; 101 struct drm_nouveau_private *dev_priv = dev->dev_private;
102 unsigned long flags;
45 u32 trap[6], idx, chinst; 103 u32 trap[6], idx, chinst;
46 int i, ch; 104 int i, ch;
47 105
@@ -60,8 +118,10 @@ nv50_fb_vm_trap(struct drm_device *dev, int display, const char *name)
60 return; 118 return;
61 119
62 chinst = (trap[2] << 16) | trap[1]; 120 chinst = (trap[2] << 16) | trap[1];
121
122 spin_lock_irqsave(&dev_priv->channels.lock, flags);
63 for (ch = 0; ch < dev_priv->engine.fifo.channels; ch++) { 123 for (ch = 0; ch < dev_priv->engine.fifo.channels; ch++) {
64 struct nouveau_channel *chan = dev_priv->fifos[ch]; 124 struct nouveau_channel *chan = dev_priv->channels.ptr[ch];
65 125
66 if (!chan || !chan->ramin) 126 if (!chan || !chan->ramin)
67 continue; 127 continue;
@@ -69,6 +129,7 @@ nv50_fb_vm_trap(struct drm_device *dev, int display, const char *name)
69 if (chinst == chan->ramin->vinst >> 12) 129 if (chinst == chan->ramin->vinst >> 12)
70 break; 130 break;
71 } 131 }
132 spin_unlock_irqrestore(&dev_priv->channels.lock, flags);
72 133
73 NV_INFO(dev, "%s - VM: Trapped %s at %02x%04x%04x status %08x " 134 NV_INFO(dev, "%s - VM: Trapped %s at %02x%04x%04x status %08x "
74 "channel %d (0x%08x)\n", 135 "channel %d (0x%08x)\n",