diff options
author | Daniel Vetter <daniel.vetter@ffwll.ch> | 2012-02-09 11:15:46 -0500 |
---|---|---|
committer | Daniel Vetter <daniel.vetter@ffwll.ch> | 2012-02-09 15:25:11 -0500 |
commit | 1d2a314c97ceaf383de8e23cdde46729927d433c (patch) | |
tree | 31df6c81a19d80b3611c39cb17c613561a9f0b0b /drivers/gpu/drm/i915/i915_gem_gtt.c | |
parent | 428ccb21b740f603a6a1f08cbe6d935fb3177620 (diff) |
drm/i915: initialization/teardown for the aliasing ppgtt
This just adds the setup and teardown code for the ppgtt PDE and the
last-level pagetables, which are fixed for the entire lifetime, at
least for the moment.
v2: Kill the stray debug printk noted by and improve the pte
definitions as suggested by Chris Wilson.
v3: Clean up the aperture stealing code as noted by Ben Widawsky.
v4: Paint the init code in a more pleasing colour as suggest by Chris
Wilson.
v5: Explain the magic numbers noticed by Ben Widawsky.
Reviewed-by: Ben Widawsky <ben@bwidawsk.net>
Tested-by: Chris Wilson <chris@chris-wilson.co.uk>
Tested-by: Eugeni Dodonov <eugeni.dodonov@intel.com>
Reviewed-by: Eugeni Dodonov <eugeni.dodonov@intel.com>
Signed-Off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers/gpu/drm/i915/i915_gem_gtt.c')
-rw-r--r-- | drivers/gpu/drm/i915/i915_gem_gtt.c | 139 |
1 files changed, 139 insertions, 0 deletions
diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 11bddd5a5a6..f408f8c710d 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c | |||
@@ -29,6 +29,145 @@ | |||
29 | #include "i915_trace.h" | 29 | #include "i915_trace.h" |
30 | #include "intel_drv.h" | 30 | #include "intel_drv.h" |
31 | 31 | ||
32 | /* PPGTT support for Sandybdrige/Gen6 and later */ | ||
33 | static void i915_ppgtt_clear_range(struct i915_hw_ppgtt *ppgtt, | ||
34 | unsigned first_entry, | ||
35 | unsigned num_entries) | ||
36 | { | ||
37 | int i, j; | ||
38 | uint32_t *pt_vaddr; | ||
39 | uint32_t scratch_pte; | ||
40 | |||
41 | scratch_pte = GEN6_PTE_ADDR_ENCODE(ppgtt->scratch_page_dma_addr); | ||
42 | scratch_pte |= GEN6_PTE_VALID | GEN6_PTE_CACHE_LLC; | ||
43 | |||
44 | for (i = 0; i < ppgtt->num_pd_entries; i++) { | ||
45 | pt_vaddr = kmap_atomic(ppgtt->pt_pages[i]); | ||
46 | |||
47 | for (j = 0; j < I915_PPGTT_PT_ENTRIES; j++) | ||
48 | pt_vaddr[j] = scratch_pte; | ||
49 | |||
50 | kunmap_atomic(pt_vaddr); | ||
51 | } | ||
52 | |||
53 | } | ||
54 | |||
55 | int i915_gem_init_aliasing_ppgtt(struct drm_device *dev) | ||
56 | { | ||
57 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
58 | struct i915_hw_ppgtt *ppgtt; | ||
59 | uint32_t pd_entry; | ||
60 | unsigned first_pd_entry_in_global_pt; | ||
61 | uint32_t __iomem *pd_addr; | ||
62 | int i; | ||
63 | int ret = -ENOMEM; | ||
64 | |||
65 | /* ppgtt PDEs reside in the global gtt pagetable, which has 512*1024 | ||
66 | * entries. For aliasing ppgtt support we just steal them at the end for | ||
67 | * now. */ | ||
68 | first_pd_entry_in_global_pt = 512*1024 - I915_PPGTT_PD_ENTRIES; | ||
69 | |||
70 | ppgtt = kzalloc(sizeof(*ppgtt), GFP_KERNEL); | ||
71 | if (!ppgtt) | ||
72 | return ret; | ||
73 | |||
74 | ppgtt->num_pd_entries = I915_PPGTT_PD_ENTRIES; | ||
75 | ppgtt->pt_pages = kzalloc(sizeof(struct page *)*ppgtt->num_pd_entries, | ||
76 | GFP_KERNEL); | ||
77 | if (!ppgtt->pt_pages) | ||
78 | goto err_ppgtt; | ||
79 | |||
80 | for (i = 0; i < ppgtt->num_pd_entries; i++) { | ||
81 | ppgtt->pt_pages[i] = alloc_page(GFP_KERNEL); | ||
82 | if (!ppgtt->pt_pages[i]) | ||
83 | goto err_pt_alloc; | ||
84 | } | ||
85 | |||
86 | if (dev_priv->mm.gtt->needs_dmar) { | ||
87 | ppgtt->pt_dma_addr = kzalloc(sizeof(dma_addr_t) | ||
88 | *ppgtt->num_pd_entries, | ||
89 | GFP_KERNEL); | ||
90 | if (!ppgtt->pt_dma_addr) | ||
91 | goto err_pt_alloc; | ||
92 | } | ||
93 | |||
94 | pd_addr = dev_priv->mm.gtt->gtt + first_pd_entry_in_global_pt; | ||
95 | for (i = 0; i < ppgtt->num_pd_entries; i++) { | ||
96 | dma_addr_t pt_addr; | ||
97 | if (dev_priv->mm.gtt->needs_dmar) { | ||
98 | pt_addr = pci_map_page(dev->pdev, ppgtt->pt_pages[i], | ||
99 | 0, 4096, | ||
100 | PCI_DMA_BIDIRECTIONAL); | ||
101 | |||
102 | if (pci_dma_mapping_error(dev->pdev, | ||
103 | pt_addr)) { | ||
104 | ret = -EIO; | ||
105 | goto err_pd_pin; | ||
106 | |||
107 | } | ||
108 | ppgtt->pt_dma_addr[i] = pt_addr; | ||
109 | } else | ||
110 | pt_addr = page_to_phys(ppgtt->pt_pages[i]); | ||
111 | |||
112 | pd_entry = GEN6_PDE_ADDR_ENCODE(pt_addr); | ||
113 | pd_entry |= GEN6_PDE_VALID; | ||
114 | |||
115 | writel(pd_entry, pd_addr + i); | ||
116 | } | ||
117 | readl(pd_addr); | ||
118 | |||
119 | ppgtt->scratch_page_dma_addr = dev_priv->mm.gtt->scratch_page_dma; | ||
120 | |||
121 | i915_ppgtt_clear_range(ppgtt, 0, | ||
122 | ppgtt->num_pd_entries*I915_PPGTT_PT_ENTRIES); | ||
123 | |||
124 | ppgtt->pd_offset = (first_pd_entry_in_global_pt)*sizeof(uint32_t); | ||
125 | |||
126 | dev_priv->mm.aliasing_ppgtt = ppgtt; | ||
127 | |||
128 | return 0; | ||
129 | |||
130 | err_pd_pin: | ||
131 | if (ppgtt->pt_dma_addr) { | ||
132 | for (i--; i >= 0; i--) | ||
133 | pci_unmap_page(dev->pdev, ppgtt->pt_dma_addr[i], | ||
134 | 4096, PCI_DMA_BIDIRECTIONAL); | ||
135 | } | ||
136 | err_pt_alloc: | ||
137 | kfree(ppgtt->pt_dma_addr); | ||
138 | for (i = 0; i < ppgtt->num_pd_entries; i++) { | ||
139 | if (ppgtt->pt_pages[i]) | ||
140 | __free_page(ppgtt->pt_pages[i]); | ||
141 | } | ||
142 | kfree(ppgtt->pt_pages); | ||
143 | err_ppgtt: | ||
144 | kfree(ppgtt); | ||
145 | |||
146 | return ret; | ||
147 | } | ||
148 | |||
149 | void i915_gem_cleanup_aliasing_ppgtt(struct drm_device *dev) | ||
150 | { | ||
151 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
152 | struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt; | ||
153 | int i; | ||
154 | |||
155 | if (!ppgtt) | ||
156 | return; | ||
157 | |||
158 | if (ppgtt->pt_dma_addr) { | ||
159 | for (i = 0; i < ppgtt->num_pd_entries; i++) | ||
160 | pci_unmap_page(dev->pdev, ppgtt->pt_dma_addr[i], | ||
161 | 4096, PCI_DMA_BIDIRECTIONAL); | ||
162 | } | ||
163 | |||
164 | kfree(ppgtt->pt_dma_addr); | ||
165 | for (i = 0; i < ppgtt->num_pd_entries; i++) | ||
166 | __free_page(ppgtt->pt_pages[i]); | ||
167 | kfree(ppgtt->pt_pages); | ||
168 | kfree(ppgtt); | ||
169 | } | ||
170 | |||
32 | /* XXX kill agp_type! */ | 171 | /* XXX kill agp_type! */ |
33 | static unsigned int cache_level_to_agp_type(struct drm_device *dev, | 172 | static unsigned int cache_level_to_agp_type(struct drm_device *dev, |
34 | enum i915_cache_level cache_level) | 173 | enum i915_cache_level cache_level) |