1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright (c) 2007, Intel Corporation. |
4 | * All Rights Reserved. |
5 | * |
6 | * Authors: Thomas Hellstrom <thomas-at-tungstengraphics.com> |
7 | * Alan Cox <alan@linux.intel.com> |
8 | */ |
9 | |
10 | #include "gem.h" /* TODO: for struct psb_gem_object, see psb_gtt_restore() */ |
11 | #include "psb_drv.h" |
12 | |
13 | |
14 | /* |
15 | * GTT resource allocator - manage page mappings in GTT space |
16 | */ |
17 | |
18 | int psb_gtt_allocate_resource(struct drm_psb_private *pdev, struct resource *res, |
19 | const char *name, resource_size_t size, resource_size_t align, |
20 | bool stolen, u32 *offset) |
21 | { |
22 | struct resource *root = pdev->gtt_mem; |
23 | resource_size_t start, end; |
24 | int ret; |
25 | |
26 | if (stolen) { |
27 | /* The start of the GTT is backed by stolen pages. */ |
28 | start = root->start; |
29 | end = root->start + pdev->gtt.stolen_size - 1; |
30 | } else { |
31 | /* The rest is backed by system pages. */ |
32 | start = root->start + pdev->gtt.stolen_size; |
33 | end = root->end; |
34 | } |
35 | |
36 | res->name = name; |
37 | ret = allocate_resource(root, new: res, size, min: start, max: end, align, NULL, NULL); |
38 | if (ret) |
39 | return ret; |
40 | *offset = res->start - root->start; |
41 | |
42 | return 0; |
43 | } |
44 | |
45 | /** |
46 | * psb_gtt_mask_pte - generate GTT pte entry |
47 | * @pfn: page number to encode |
48 | * @type: type of memory in the GTT |
49 | * |
50 | * Set the GTT entry for the appropriate memory type. |
51 | */ |
52 | uint32_t psb_gtt_mask_pte(uint32_t pfn, int type) |
53 | { |
54 | uint32_t mask = PSB_PTE_VALID; |
55 | |
56 | /* Ensure we explode rather than put an invalid low mapping of |
57 | a high mapping page into the gtt */ |
58 | BUG_ON(pfn & ~(0xFFFFFFFF >> PAGE_SHIFT)); |
59 | |
60 | if (type & PSB_MMU_CACHED_MEMORY) |
61 | mask |= PSB_PTE_CACHED; |
62 | if (type & PSB_MMU_RO_MEMORY) |
63 | mask |= PSB_PTE_RO; |
64 | if (type & PSB_MMU_WO_MEMORY) |
65 | mask |= PSB_PTE_WO; |
66 | |
67 | return (pfn << PAGE_SHIFT) | mask; |
68 | } |
69 | |
70 | static u32 __iomem *psb_gtt_entry(struct drm_psb_private *pdev, const struct resource *res) |
71 | { |
72 | unsigned long offset = res->start - pdev->gtt_mem->start; |
73 | |
74 | return pdev->gtt_map + (offset >> PAGE_SHIFT); |
75 | } |
76 | |
77 | /* Acquires GTT mutex internally. */ |
78 | void psb_gtt_insert_pages(struct drm_psb_private *pdev, const struct resource *res, |
79 | struct page **pages) |
80 | { |
81 | resource_size_t npages, i; |
82 | u32 __iomem *gtt_slot; |
83 | u32 pte; |
84 | |
85 | mutex_lock(&pdev->gtt_mutex); |
86 | |
87 | /* Write our page entries into the GTT itself */ |
88 | |
89 | npages = resource_size(res) >> PAGE_SHIFT; |
90 | gtt_slot = psb_gtt_entry(pdev, res); |
91 | |
92 | for (i = 0; i < npages; ++i, ++gtt_slot) { |
93 | pte = psb_gtt_mask_pte(page_to_pfn(pages[i]), PSB_MMU_CACHED_MEMORY); |
94 | iowrite32(pte, gtt_slot); |
95 | } |
96 | |
97 | /* Make sure all the entries are set before we return */ |
98 | ioread32(gtt_slot - 1); |
99 | |
100 | mutex_unlock(lock: &pdev->gtt_mutex); |
101 | } |
102 | |
103 | /* Acquires GTT mutex internally. */ |
104 | void psb_gtt_remove_pages(struct drm_psb_private *pdev, const struct resource *res) |
105 | { |
106 | resource_size_t npages, i; |
107 | u32 __iomem *gtt_slot; |
108 | u32 pte; |
109 | |
110 | mutex_lock(&pdev->gtt_mutex); |
111 | |
112 | /* Install scratch page for the resource */ |
113 | |
114 | pte = psb_gtt_mask_pte(page_to_pfn(pdev->scratch_page), PSB_MMU_CACHED_MEMORY); |
115 | |
116 | npages = resource_size(res) >> PAGE_SHIFT; |
117 | gtt_slot = psb_gtt_entry(pdev, res); |
118 | |
119 | for (i = 0; i < npages; ++i, ++gtt_slot) |
120 | iowrite32(pte, gtt_slot); |
121 | |
122 | /* Make sure all the entries are set before we return */ |
123 | ioread32(gtt_slot - 1); |
124 | |
125 | mutex_unlock(lock: &pdev->gtt_mutex); |
126 | } |
127 | |
128 | static int psb_gtt_enable(struct drm_psb_private *dev_priv) |
129 | { |
130 | struct drm_device *dev = &dev_priv->dev; |
131 | struct pci_dev *pdev = to_pci_dev(dev->dev); |
132 | int ret; |
133 | |
134 | ret = pci_read_config_word(dev: pdev, PSB_GMCH_CTRL, val: &dev_priv->gmch_ctrl); |
135 | if (ret) |
136 | return pcibios_err_to_errno(err: ret); |
137 | ret = pci_write_config_word(dev: pdev, PSB_GMCH_CTRL, val: dev_priv->gmch_ctrl | _PSB_GMCH_ENABLED); |
138 | if (ret) |
139 | return pcibios_err_to_errno(err: ret); |
140 | |
141 | dev_priv->pge_ctl = PSB_RVDC32(PSB_PGETBL_CTL); |
142 | PSB_WVDC32(dev_priv->pge_ctl | _PSB_PGETBL_ENABLED, PSB_PGETBL_CTL); |
143 | |
144 | (void)PSB_RVDC32(PSB_PGETBL_CTL); |
145 | |
146 | return 0; |
147 | } |
148 | |
149 | static void psb_gtt_disable(struct drm_psb_private *dev_priv) |
150 | { |
151 | struct drm_device *dev = &dev_priv->dev; |
152 | struct pci_dev *pdev = to_pci_dev(dev->dev); |
153 | |
154 | pci_write_config_word(dev: pdev, PSB_GMCH_CTRL, val: dev_priv->gmch_ctrl); |
155 | PSB_WVDC32(dev_priv->pge_ctl, PSB_PGETBL_CTL); |
156 | |
157 | (void)PSB_RVDC32(PSB_PGETBL_CTL); |
158 | } |
159 | |
160 | void psb_gtt_fini(struct drm_device *dev) |
161 | { |
162 | struct drm_psb_private *dev_priv = to_drm_psb_private(dev); |
163 | |
164 | iounmap(addr: dev_priv->gtt_map); |
165 | psb_gtt_disable(dev_priv); |
166 | mutex_destroy(lock: &dev_priv->gtt_mutex); |
167 | } |
168 | |
169 | /* Clear GTT. Use a scratch page to avoid accidents or scribbles. */ |
170 | static void psb_gtt_clear(struct drm_psb_private *pdev) |
171 | { |
172 | resource_size_t pfn_base; |
173 | unsigned long i; |
174 | uint32_t pte; |
175 | |
176 | pfn_base = page_to_pfn(pdev->scratch_page); |
177 | pte = psb_gtt_mask_pte(pfn: pfn_base, PSB_MMU_CACHED_MEMORY); |
178 | |
179 | for (i = 0; i < pdev->gtt.gtt_pages; ++i) |
180 | iowrite32(pte, pdev->gtt_map + i); |
181 | |
182 | (void)ioread32(pdev->gtt_map + i - 1); |
183 | } |
184 | |
185 | static void psb_gtt_init_ranges(struct drm_psb_private *dev_priv) |
186 | { |
187 | struct drm_device *dev = &dev_priv->dev; |
188 | struct pci_dev *pdev = to_pci_dev(dev->dev); |
189 | struct psb_gtt *pg = &dev_priv->gtt; |
190 | resource_size_t gtt_phys_start, mmu_gatt_start, gtt_start, gtt_pages, |
191 | gatt_start, gatt_pages; |
192 | struct resource *gtt_mem; |
193 | |
194 | /* The root resource we allocate address space from */ |
195 | gtt_phys_start = dev_priv->pge_ctl & PAGE_MASK; |
196 | |
197 | /* |
198 | * The video MMU has a HW bug when accessing 0x0d0000000. Make |
199 | * GATT start at 0x0e0000000. This doesn't actually matter for |
200 | * us now, but maybe will if the video acceleration ever gets |
201 | * opened up. |
202 | */ |
203 | mmu_gatt_start = 0xe0000000; |
204 | |
205 | gtt_start = pci_resource_start(pdev, PSB_GTT_RESOURCE); |
206 | gtt_pages = pci_resource_len(pdev, PSB_GTT_RESOURCE) >> PAGE_SHIFT; |
207 | |
208 | /* CDV doesn't report this. In which case the system has 64 gtt pages */ |
209 | if (!gtt_start || !gtt_pages) { |
210 | dev_dbg(dev->dev, "GTT PCI BAR not initialized.\n" ); |
211 | gtt_pages = 64; |
212 | gtt_start = dev_priv->pge_ctl; |
213 | } |
214 | |
215 | gatt_start = pci_resource_start(pdev, PSB_GATT_RESOURCE); |
216 | gatt_pages = pci_resource_len(pdev, PSB_GATT_RESOURCE) >> PAGE_SHIFT; |
217 | |
218 | if (!gatt_pages || !gatt_start) { |
219 | static struct resource fudge; /* Preferably peppermint */ |
220 | |
221 | /* |
222 | * This can occur on CDV systems. Fudge it in this case. We |
223 | * really don't care what imaginary space is being allocated |
224 | * at this point. |
225 | */ |
226 | dev_dbg(dev->dev, "GATT PCI BAR not initialized.\n" ); |
227 | gatt_start = 0x40000000; |
228 | gatt_pages = (128 * 1024 * 1024) >> PAGE_SHIFT; |
229 | |
230 | /* |
231 | * This is a little confusing but in fact the GTT is providing |
232 | * a view from the GPU into memory and not vice versa. As such |
233 | * this is really allocating space that is not the same as the |
234 | * CPU address space on CDV. |
235 | */ |
236 | fudge.start = 0x40000000; |
237 | fudge.end = 0x40000000 + 128 * 1024 * 1024 - 1; |
238 | fudge.name = "fudge" ; |
239 | fudge.flags = IORESOURCE_MEM; |
240 | |
241 | gtt_mem = &fudge; |
242 | } else { |
243 | gtt_mem = &pdev->resource[PSB_GATT_RESOURCE]; |
244 | } |
245 | |
246 | pg->gtt_phys_start = gtt_phys_start; |
247 | pg->mmu_gatt_start = mmu_gatt_start; |
248 | pg->gtt_start = gtt_start; |
249 | pg->gtt_pages = gtt_pages; |
250 | pg->gatt_start = gatt_start; |
251 | pg->gatt_pages = gatt_pages; |
252 | dev_priv->gtt_mem = gtt_mem; |
253 | } |
254 | |
255 | int psb_gtt_init(struct drm_device *dev) |
256 | { |
257 | struct drm_psb_private *dev_priv = to_drm_psb_private(dev); |
258 | struct psb_gtt *pg = &dev_priv->gtt; |
259 | int ret; |
260 | |
261 | mutex_init(&dev_priv->gtt_mutex); |
262 | |
263 | ret = psb_gtt_enable(dev_priv); |
264 | if (ret) |
265 | goto err_mutex_destroy; |
266 | |
267 | psb_gtt_init_ranges(dev_priv); |
268 | |
269 | dev_priv->gtt_map = ioremap(offset: pg->gtt_phys_start, size: pg->gtt_pages << PAGE_SHIFT); |
270 | if (!dev_priv->gtt_map) { |
271 | dev_err(dev->dev, "Failure to map gtt.\n" ); |
272 | ret = -ENOMEM; |
273 | goto err_psb_gtt_disable; |
274 | } |
275 | |
276 | psb_gtt_clear(pdev: dev_priv); |
277 | |
278 | return 0; |
279 | |
280 | err_psb_gtt_disable: |
281 | psb_gtt_disable(dev_priv); |
282 | err_mutex_destroy: |
283 | mutex_destroy(lock: &dev_priv->gtt_mutex); |
284 | return ret; |
285 | } |
286 | |
287 | int psb_gtt_resume(struct drm_device *dev) |
288 | { |
289 | struct drm_psb_private *dev_priv = to_drm_psb_private(dev); |
290 | struct psb_gtt *pg = &dev_priv->gtt; |
291 | unsigned int old_gtt_pages = pg->gtt_pages; |
292 | int ret; |
293 | |
294 | /* Enable the GTT */ |
295 | ret = psb_gtt_enable(dev_priv); |
296 | if (ret) |
297 | return ret; |
298 | |
299 | psb_gtt_init_ranges(dev_priv); |
300 | |
301 | if (old_gtt_pages != pg->gtt_pages) { |
302 | dev_err(dev->dev, "GTT resume error.\n" ); |
303 | ret = -ENODEV; |
304 | goto err_psb_gtt_disable; |
305 | } |
306 | |
307 | psb_gtt_clear(pdev: dev_priv); |
308 | |
309 | err_psb_gtt_disable: |
310 | psb_gtt_disable(dev_priv); |
311 | return ret; |
312 | } |
313 | |