xref: /dflybsd-src/sys/dev/drm/radeon/radeon_gart.c (revision a85cb24f18e3804e75ab8bcda7692564d0563317)
1926deccbSFrançois Tigeot /*
2926deccbSFrançois Tigeot  * Copyright 2008 Advanced Micro Devices, Inc.
3926deccbSFrançois Tigeot  * Copyright 2008 Red Hat Inc.
4926deccbSFrançois Tigeot  * Copyright 2009 Jerome Glisse.
5926deccbSFrançois Tigeot  *
6926deccbSFrançois Tigeot  * Permission is hereby granted, free of charge, to any person obtaining a
7926deccbSFrançois Tigeot  * copy of this software and associated documentation files (the "Software"),
8926deccbSFrançois Tigeot  * to deal in the Software without restriction, including without limitation
9926deccbSFrançois Tigeot  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10926deccbSFrançois Tigeot  * and/or sell copies of the Software, and to permit persons to whom the
11926deccbSFrançois Tigeot  * Software is furnished to do so, subject to the following conditions:
12926deccbSFrançois Tigeot  *
13926deccbSFrançois Tigeot  * The above copyright notice and this permission notice shall be included in
14926deccbSFrançois Tigeot  * all copies or substantial portions of the Software.
15926deccbSFrançois Tigeot  *
16926deccbSFrançois Tigeot  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17926deccbSFrançois Tigeot  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18926deccbSFrançois Tigeot  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19926deccbSFrançois Tigeot  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
20926deccbSFrançois Tigeot  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21926deccbSFrançois Tigeot  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22926deccbSFrançois Tigeot  * OTHER DEALINGS IN THE SOFTWARE.
23926deccbSFrançois Tigeot  *
24926deccbSFrançois Tigeot  * Authors: Dave Airlie
25926deccbSFrançois Tigeot  *          Alex Deucher
26926deccbSFrançois Tigeot  *          Jerome Glisse
27926deccbSFrançois Tigeot  */
28926deccbSFrançois Tigeot #include <drm/drmP.h>
2983b4b9b9SFrançois Tigeot #include <drm/radeon_drm.h>
30*a85cb24fSFrançois Tigeot #ifdef CONFIG_X86
31*a85cb24fSFrançois Tigeot #include <asm/set_memory.h>
32*a85cb24fSFrançois Tigeot #endif
33926deccbSFrançois Tigeot #include "radeon.h"
34926deccbSFrançois Tigeot 
35926deccbSFrançois Tigeot /*
36926deccbSFrançois Tigeot  * GART
37926deccbSFrançois Tigeot  * The GART (Graphics Aperture Remapping Table) is an aperture
38926deccbSFrançois Tigeot  * in the GPU's address space.  System pages can be mapped into
39926deccbSFrançois Tigeot  * the aperture and look like contiguous pages from the GPU's
40926deccbSFrançois Tigeot  * perspective.  A page table maps the pages in the aperture
41926deccbSFrançois Tigeot  * to the actual backing pages in system memory.
42926deccbSFrançois Tigeot  *
43926deccbSFrançois Tigeot  * Radeon GPUs support both an internal GART, as described above,
44926deccbSFrançois Tigeot  * and AGP.  AGP works similarly, but the GART table is configured
45926deccbSFrançois Tigeot  * and maintained by the northbridge rather than the driver.
46926deccbSFrançois Tigeot  * Radeon hw has a separate AGP aperture that is programmed to
47926deccbSFrançois Tigeot  * point to the AGP aperture provided by the northbridge and the
48926deccbSFrançois Tigeot  * requests are passed through to the northbridge aperture.
49926deccbSFrançois Tigeot  * Both AGP and internal GART can be used at the same time, however
50926deccbSFrançois Tigeot  * that is not currently supported by the driver.
51926deccbSFrançois Tigeot  *
52926deccbSFrançois Tigeot  * This file handles the common internal GART management.
53926deccbSFrançois Tigeot  */
54926deccbSFrançois Tigeot 
55926deccbSFrançois Tigeot /*
56926deccbSFrançois Tigeot  * Common GART table functions.
57926deccbSFrançois Tigeot  */
58926deccbSFrançois Tigeot /**
59926deccbSFrançois Tigeot  * radeon_gart_table_ram_alloc - allocate system ram for gart page table
60926deccbSFrançois Tigeot  *
61926deccbSFrançois Tigeot  * @rdev: radeon_device pointer
62926deccbSFrançois Tigeot  *
63926deccbSFrançois Tigeot  * Allocate system memory for GART page table
64926deccbSFrançois Tigeot  * (r1xx-r3xx, non-pcie r4xx, rs400).  These asics require the
65926deccbSFrançois Tigeot  * gart table to be in system memory.
66926deccbSFrançois Tigeot  * Returns 0 for success, -ENOMEM for failure.
67926deccbSFrançois Tigeot  */
radeon_gart_table_ram_alloc(struct radeon_device * rdev)68926deccbSFrançois Tigeot int radeon_gart_table_ram_alloc(struct radeon_device *rdev)
69926deccbSFrançois Tigeot {
70f3ac4187SFrançois Tigeot 	void *ptr;
71926deccbSFrançois Tigeot 
72f3ac4187SFrançois Tigeot 	ptr = pci_alloc_consistent(rdev->pdev, rdev->gart.table_size,
73f3ac4187SFrançois Tigeot 				   &rdev->gart.table_addr);
74f3ac4187SFrançois Tigeot 	if (ptr == NULL) {
75926deccbSFrançois Tigeot 		return -ENOMEM;
76926deccbSFrançois Tigeot 	}
77f3ac4187SFrançois Tigeot #ifdef CONFIG_X86
78926deccbSFrançois Tigeot 	if (rdev->family == CHIP_RS400 || rdev->family == CHIP_RS480 ||
79926deccbSFrançois Tigeot 	    rdev->family == CHIP_RS690 || rdev->family == CHIP_RS740) {
80f3ac4187SFrançois Tigeot 		set_memory_uc((unsigned long)ptr,
81f3ac4187SFrançois Tigeot 			      rdev->gart.table_size >> PAGE_SHIFT);
82926deccbSFrançois Tigeot 	}
83926deccbSFrançois Tigeot #endif
84f3ac4187SFrançois Tigeot 	rdev->gart.ptr = ptr;
85926deccbSFrançois Tigeot 	memset((void *)rdev->gart.ptr, 0, rdev->gart.table_size);
86926deccbSFrançois Tigeot 	return 0;
87926deccbSFrançois Tigeot }
88926deccbSFrançois Tigeot 
89926deccbSFrançois Tigeot /**
90926deccbSFrançois Tigeot  * radeon_gart_table_ram_free - free system ram for gart page table
91926deccbSFrançois Tigeot  *
92926deccbSFrançois Tigeot  * @rdev: radeon_device pointer
93926deccbSFrançois Tigeot  *
94926deccbSFrançois Tigeot  * Free system memory for GART page table
95926deccbSFrançois Tigeot  * (r1xx-r3xx, non-pcie r4xx, rs400).  These asics require the
96926deccbSFrançois Tigeot  * gart table to be in system memory.
97926deccbSFrançois Tigeot  */
radeon_gart_table_ram_free(struct radeon_device * rdev)98926deccbSFrançois Tigeot void radeon_gart_table_ram_free(struct radeon_device *rdev)
99926deccbSFrançois Tigeot {
100926deccbSFrançois Tigeot 	if (rdev->gart.ptr == NULL) {
101926deccbSFrançois Tigeot 		return;
102926deccbSFrançois Tigeot 	}
103*a85cb24fSFrançois Tigeot #ifdef CONFIG_X86
104926deccbSFrançois Tigeot 	if (rdev->family == CHIP_RS400 || rdev->family == CHIP_RS480 ||
105926deccbSFrançois Tigeot 	    rdev->family == CHIP_RS690 || rdev->family == CHIP_RS740) {
106*a85cb24fSFrançois Tigeot 		set_memory_wb((unsigned long)rdev->gart.ptr,
107*a85cb24fSFrançois Tigeot 			      rdev->gart.table_size >> PAGE_SHIFT);
108926deccbSFrançois Tigeot 	}
109926deccbSFrançois Tigeot #endif
110*a85cb24fSFrançois Tigeot 	pci_free_consistent(rdev->pdev, rdev->gart.table_size,
111*a85cb24fSFrançois Tigeot 			    (void *)rdev->gart.ptr,
112*a85cb24fSFrançois Tigeot 			    rdev->gart.table_addr);
113926deccbSFrançois Tigeot 	rdev->gart.ptr = NULL;
114926deccbSFrançois Tigeot 	rdev->gart.table_addr = 0;
115926deccbSFrançois Tigeot }
116926deccbSFrançois Tigeot 
117926deccbSFrançois Tigeot /**
118926deccbSFrançois Tigeot  * radeon_gart_table_vram_alloc - allocate vram for gart page table
119926deccbSFrançois Tigeot  *
120926deccbSFrançois Tigeot  * @rdev: radeon_device pointer
121926deccbSFrançois Tigeot  *
122926deccbSFrançois Tigeot  * Allocate video memory for GART page table
123926deccbSFrançois Tigeot  * (pcie r4xx, r5xx+).  These asics require the
124926deccbSFrançois Tigeot  * gart table to be in video memory.
125926deccbSFrançois Tigeot  * Returns 0 for success, error for failure.
126926deccbSFrançois Tigeot  */
radeon_gart_table_vram_alloc(struct radeon_device * rdev)127926deccbSFrançois Tigeot int radeon_gart_table_vram_alloc(struct radeon_device *rdev)
128926deccbSFrançois Tigeot {
129926deccbSFrançois Tigeot 	int r;
130926deccbSFrançois Tigeot 
131926deccbSFrançois Tigeot 	if (rdev->gart.robj == NULL) {
132926deccbSFrançois Tigeot 		r = radeon_bo_create(rdev, rdev->gart.table_size,
133926deccbSFrançois Tigeot 				     PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM,
1347dcf36dcSFrançois Tigeot 				     0, NULL, NULL, &rdev->gart.robj);
135926deccbSFrançois Tigeot 		if (r) {
136926deccbSFrançois Tigeot 			return r;
137926deccbSFrançois Tigeot 		}
138926deccbSFrançois Tigeot 	}
139926deccbSFrançois Tigeot 	return 0;
140926deccbSFrançois Tigeot }
141926deccbSFrançois Tigeot 
142926deccbSFrançois Tigeot /**
143926deccbSFrançois Tigeot  * radeon_gart_table_vram_pin - pin gart page table in vram
144926deccbSFrançois Tigeot  *
145926deccbSFrançois Tigeot  * @rdev: radeon_device pointer
146926deccbSFrançois Tigeot  *
147926deccbSFrançois Tigeot  * Pin the GART page table in vram so it will not be moved
148926deccbSFrançois Tigeot  * by the memory manager (pcie r4xx, r5xx+).  These asics require the
149926deccbSFrançois Tigeot  * gart table to be in video memory.
150926deccbSFrançois Tigeot  * Returns 0 for success, error for failure.
151926deccbSFrançois Tigeot  */
radeon_gart_table_vram_pin(struct radeon_device * rdev)152926deccbSFrançois Tigeot int radeon_gart_table_vram_pin(struct radeon_device *rdev)
153926deccbSFrançois Tigeot {
154ee479021SImre Vadász 	u64 gpu_addr;
155926deccbSFrançois Tigeot 	int r;
156926deccbSFrançois Tigeot 
157926deccbSFrançois Tigeot 	r = radeon_bo_reserve(rdev->gart.robj, false);
158926deccbSFrançois Tigeot 	if (unlikely(r != 0))
159926deccbSFrançois Tigeot 		return r;
160926deccbSFrançois Tigeot 	r = radeon_bo_pin(rdev->gart.robj,
161ee479021SImre Vadász 				RADEON_GEM_DOMAIN_VRAM, &gpu_addr);
162926deccbSFrançois Tigeot 	if (r) {
163926deccbSFrançois Tigeot 		radeon_bo_unreserve(rdev->gart.robj);
164926deccbSFrançois Tigeot 		return r;
165926deccbSFrançois Tigeot 	}
166926deccbSFrançois Tigeot 	r = radeon_bo_kmap(rdev->gart.robj, &rdev->gart.ptr);
167926deccbSFrançois Tigeot 	if (r)
168926deccbSFrançois Tigeot 		radeon_bo_unpin(rdev->gart.robj);
169926deccbSFrançois Tigeot 	radeon_bo_unreserve(rdev->gart.robj);
170926deccbSFrançois Tigeot 	rdev->gart.table_addr = gpu_addr;
1717dcf36dcSFrançois Tigeot 
1727dcf36dcSFrançois Tigeot 	if (!r) {
1737dcf36dcSFrançois Tigeot 		int i;
1747dcf36dcSFrançois Tigeot 
1757dcf36dcSFrançois Tigeot 		/* We might have dropped some GART table updates while it wasn't
1767dcf36dcSFrançois Tigeot 		 * mapped, restore all entries
1777dcf36dcSFrançois Tigeot 		 */
1787dcf36dcSFrançois Tigeot 		for (i = 0; i < rdev->gart.num_gpu_pages; i++)
1797dcf36dcSFrançois Tigeot 			radeon_gart_set_page(rdev, i, rdev->gart.pages_entry[i]);
1807dcf36dcSFrançois Tigeot 		mb();
1817dcf36dcSFrançois Tigeot 		radeon_gart_tlb_flush(rdev);
1827dcf36dcSFrançois Tigeot 	}
1837dcf36dcSFrançois Tigeot 
184926deccbSFrançois Tigeot 	return r;
185926deccbSFrançois Tigeot }
186926deccbSFrançois Tigeot 
187926deccbSFrançois Tigeot /**
188926deccbSFrançois Tigeot  * radeon_gart_table_vram_unpin - unpin gart page table in vram
189926deccbSFrançois Tigeot  *
190926deccbSFrançois Tigeot  * @rdev: radeon_device pointer
191926deccbSFrançois Tigeot  *
192926deccbSFrançois Tigeot  * Unpin the GART page table in vram (pcie r4xx, r5xx+).
193926deccbSFrançois Tigeot  * These asics require the gart table to be in video memory.
194926deccbSFrançois Tigeot  */
radeon_gart_table_vram_unpin(struct radeon_device * rdev)195926deccbSFrançois Tigeot void radeon_gart_table_vram_unpin(struct radeon_device *rdev)
196926deccbSFrançois Tigeot {
197926deccbSFrançois Tigeot 	int r;
198926deccbSFrançois Tigeot 
199926deccbSFrançois Tigeot 	if (rdev->gart.robj == NULL) {
200926deccbSFrançois Tigeot 		return;
201926deccbSFrançois Tigeot 	}
202926deccbSFrançois Tigeot 	r = radeon_bo_reserve(rdev->gart.robj, false);
203926deccbSFrançois Tigeot 	if (likely(r == 0)) {
204926deccbSFrançois Tigeot 		radeon_bo_kunmap(rdev->gart.robj);
205926deccbSFrançois Tigeot 		radeon_bo_unpin(rdev->gart.robj);
206926deccbSFrançois Tigeot 		radeon_bo_unreserve(rdev->gart.robj);
207926deccbSFrançois Tigeot 		rdev->gart.ptr = NULL;
208926deccbSFrançois Tigeot 	}
209926deccbSFrançois Tigeot }
210926deccbSFrançois Tigeot 
211926deccbSFrançois Tigeot /**
212926deccbSFrançois Tigeot  * radeon_gart_table_vram_free - free gart page table vram
213926deccbSFrançois Tigeot  *
214926deccbSFrançois Tigeot  * @rdev: radeon_device pointer
215926deccbSFrançois Tigeot  *
216926deccbSFrançois Tigeot  * Free the video memory used for the GART page table
217926deccbSFrançois Tigeot  * (pcie r4xx, r5xx+).  These asics require the gart table to
218926deccbSFrançois Tigeot  * be in video memory.
219926deccbSFrançois Tigeot  */
radeon_gart_table_vram_free(struct radeon_device * rdev)220926deccbSFrançois Tigeot void radeon_gart_table_vram_free(struct radeon_device *rdev)
221926deccbSFrançois Tigeot {
222926deccbSFrançois Tigeot 	if (rdev->gart.robj == NULL) {
223926deccbSFrançois Tigeot 		return;
224926deccbSFrançois Tigeot 	}
225926deccbSFrançois Tigeot 	radeon_bo_unref(&rdev->gart.robj);
226926deccbSFrançois Tigeot }
227926deccbSFrançois Tigeot 
228926deccbSFrançois Tigeot /*
229926deccbSFrançois Tigeot  * Common gart functions.
230926deccbSFrançois Tigeot  */
231926deccbSFrançois Tigeot /**
232926deccbSFrançois Tigeot  * radeon_gart_unbind - unbind pages from the gart page table
233926deccbSFrançois Tigeot  *
234926deccbSFrançois Tigeot  * @rdev: radeon_device pointer
235926deccbSFrançois Tigeot  * @offset: offset into the GPU's gart aperture
236926deccbSFrançois Tigeot  * @pages: number of pages to unbind
237926deccbSFrançois Tigeot  *
238926deccbSFrançois Tigeot  * Unbinds the requested pages from the gart page table and
239926deccbSFrançois Tigeot  * replaces them with the dummy page (all asics).
240926deccbSFrançois Tigeot  */
radeon_gart_unbind(struct radeon_device * rdev,unsigned offset,int pages)241926deccbSFrançois Tigeot void radeon_gart_unbind(struct radeon_device *rdev, unsigned offset,
242926deccbSFrançois Tigeot 			int pages)
243926deccbSFrançois Tigeot {
244926deccbSFrançois Tigeot 	unsigned t;
245926deccbSFrançois Tigeot 	unsigned p;
246926deccbSFrançois Tigeot 	int i, j;
247926deccbSFrançois Tigeot 
248926deccbSFrançois Tigeot 	if (!rdev->gart.ready) {
249c4ef309bSzrj 		WARN(1, "trying to unbind memory from uninitialized GART !\n");
250926deccbSFrançois Tigeot 		return;
251926deccbSFrançois Tigeot 	}
252926deccbSFrançois Tigeot 	t = offset / RADEON_GPU_PAGE_SIZE;
253926deccbSFrançois Tigeot 	p = t / (PAGE_SIZE / RADEON_GPU_PAGE_SIZE);
254926deccbSFrançois Tigeot 	for (i = 0; i < pages; i++, p++) {
255926deccbSFrançois Tigeot 		if (rdev->gart.pages[p]) {
256926deccbSFrançois Tigeot 			rdev->gart.pages[p] = NULL;
257926deccbSFrançois Tigeot 			for (j = 0; j < (PAGE_SIZE / RADEON_GPU_PAGE_SIZE); j++, t++) {
2587dcf36dcSFrançois Tigeot 				rdev->gart.pages_entry[t] = rdev->dummy_page.entry;
259926deccbSFrançois Tigeot 				if (rdev->gart.ptr) {
2607dcf36dcSFrançois Tigeot 					radeon_gart_set_page(rdev, t,
2617dcf36dcSFrançois Tigeot 							     rdev->dummy_page.entry);
262ee479021SImre Vadász 				}
263926deccbSFrançois Tigeot 			}
264926deccbSFrançois Tigeot 		}
265926deccbSFrançois Tigeot 	}
266c59a5c48SFrançois Tigeot 	if (rdev->gart.ptr) {
267c4ef309bSzrj 		mb();
268926deccbSFrançois Tigeot 		radeon_gart_tlb_flush(rdev);
269926deccbSFrançois Tigeot 	}
270c59a5c48SFrançois Tigeot }
271926deccbSFrançois Tigeot 
272926deccbSFrançois Tigeot /**
273926deccbSFrançois Tigeot  * radeon_gart_bind - bind pages into the gart page table
274926deccbSFrançois Tigeot  *
275926deccbSFrançois Tigeot  * @rdev: radeon_device pointer
276926deccbSFrançois Tigeot  * @offset: offset into the GPU's gart aperture
277926deccbSFrançois Tigeot  * @pages: number of pages to bind
278926deccbSFrançois Tigeot  * @pagelist: pages to bind
279926deccbSFrançois Tigeot  * @dma_addr: DMA addresses of pages
280c6f73aabSFrançois Tigeot  * @flags: RADEON_GART_PAGE_* flags
281926deccbSFrançois Tigeot  *
282926deccbSFrançois Tigeot  * Binds the requested pages to the gart page table
283926deccbSFrançois Tigeot  * (all asics).
284926deccbSFrançois Tigeot  * Returns 0 for success, -EINVAL for failure.
285926deccbSFrançois Tigeot  */
radeon_gart_bind(struct radeon_device * rdev,unsigned offset,int pages,struct page ** pagelist,dma_addr_t * dma_addr,uint32_t flags)286926deccbSFrançois Tigeot int radeon_gart_bind(struct radeon_device *rdev, unsigned offset,
287f0bba3d1SFrançois Tigeot 		     int pages, struct page **pagelist, dma_addr_t *dma_addr,
288c6f73aabSFrançois Tigeot 		     uint32_t flags)
289926deccbSFrançois Tigeot {
290926deccbSFrançois Tigeot 	unsigned t;
291926deccbSFrançois Tigeot 	unsigned p;
2927dcf36dcSFrançois Tigeot 	uint64_t page_base, page_entry;
293926deccbSFrançois Tigeot 	int i, j;
294926deccbSFrançois Tigeot 
295926deccbSFrançois Tigeot 	if (!rdev->gart.ready) {
296c4ef309bSzrj 		WARN(1, "trying to bind memory to uninitialized GART !\n");
297926deccbSFrançois Tigeot 		return -EINVAL;
298926deccbSFrançois Tigeot 	}
299926deccbSFrançois Tigeot 	t = offset / RADEON_GPU_PAGE_SIZE;
300926deccbSFrançois Tigeot 	p = t / (PAGE_SIZE / RADEON_GPU_PAGE_SIZE);
301926deccbSFrançois Tigeot 
302926deccbSFrançois Tigeot 	for (i = 0; i < pages; i++, p++) {
303926deccbSFrançois Tigeot 		rdev->gart.pages[p] = pagelist[i];
3047dcf36dcSFrançois Tigeot 		page_base = dma_addr[i];
305ee479021SImre Vadász 		for (j = 0; j < (PAGE_SIZE / RADEON_GPU_PAGE_SIZE); j++, t++) {
3067dcf36dcSFrançois Tigeot 			page_entry = radeon_gart_get_page_entry(page_base, flags);
3077dcf36dcSFrançois Tigeot 			rdev->gart.pages_entry[t] = page_entry;
3087dcf36dcSFrançois Tigeot 			if (rdev->gart.ptr) {
3097dcf36dcSFrançois Tigeot 				radeon_gart_set_page(rdev, t, page_entry);
310926deccbSFrançois Tigeot 			}
3117dcf36dcSFrançois Tigeot 			page_base += RADEON_GPU_PAGE_SIZE;
312926deccbSFrançois Tigeot 		}
313ee479021SImre Vadász 	}
314c59a5c48SFrançois Tigeot 	if (rdev->gart.ptr) {
315c4ef309bSzrj 		mb();
316926deccbSFrançois Tigeot 		radeon_gart_tlb_flush(rdev);
317c59a5c48SFrançois Tigeot 	}
318926deccbSFrançois Tigeot 	return 0;
319926deccbSFrançois Tigeot }
320926deccbSFrançois Tigeot 
321926deccbSFrançois Tigeot /**
322926deccbSFrançois Tigeot  * radeon_gart_init - init the driver info for managing the gart
323926deccbSFrançois Tigeot  *
324926deccbSFrançois Tigeot  * @rdev: radeon_device pointer
325926deccbSFrançois Tigeot  *
326926deccbSFrançois Tigeot  * Allocate the dummy page and init the gart driver info (all asics).
327926deccbSFrançois Tigeot  * Returns 0 for success, error for failure.
328926deccbSFrançois Tigeot  */
radeon_gart_init(struct radeon_device * rdev)329926deccbSFrançois Tigeot int radeon_gart_init(struct radeon_device *rdev)
330926deccbSFrançois Tigeot {
331926deccbSFrançois Tigeot 	int r, i;
332926deccbSFrançois Tigeot 
333926deccbSFrançois Tigeot 	if (rdev->gart.pages) {
334926deccbSFrançois Tigeot 		return 0;
335926deccbSFrançois Tigeot 	}
336926deccbSFrançois Tigeot 	/* We need PAGE_SIZE >= RADEON_GPU_PAGE_SIZE */
337926deccbSFrançois Tigeot 	if (PAGE_SIZE < RADEON_GPU_PAGE_SIZE) {
338926deccbSFrançois Tigeot 		DRM_ERROR("Page size is smaller than GPU page size!\n");
339926deccbSFrançois Tigeot 		return -EINVAL;
340926deccbSFrançois Tigeot 	}
341926deccbSFrançois Tigeot 	r = radeon_dummy_page_init(rdev);
342926deccbSFrançois Tigeot 	if (r)
343926deccbSFrançois Tigeot 		return r;
344926deccbSFrançois Tigeot 	/* Compute table size */
345926deccbSFrançois Tigeot 	rdev->gart.num_cpu_pages = rdev->mc.gtt_size / PAGE_SIZE;
346926deccbSFrançois Tigeot 	rdev->gart.num_gpu_pages = rdev->mc.gtt_size / RADEON_GPU_PAGE_SIZE;
347926deccbSFrançois Tigeot 	DRM_INFO("GART: num cpu pages %u, num gpu pages %u\n",
348926deccbSFrançois Tigeot 		 rdev->gart.num_cpu_pages, rdev->gart.num_gpu_pages);
349926deccbSFrançois Tigeot 	/* Allocate pages table */
3507dcf36dcSFrançois Tigeot 	rdev->gart.pages = vzalloc(sizeof(void *) * rdev->gart.num_cpu_pages);
351926deccbSFrançois Tigeot 	if (rdev->gart.pages == NULL) {
352926deccbSFrançois Tigeot 		radeon_gart_fini(rdev);
353926deccbSFrançois Tigeot 		return -ENOMEM;
354926deccbSFrançois Tigeot 	}
3557dcf36dcSFrançois Tigeot 	rdev->gart.pages_entry = vmalloc(sizeof(uint64_t) *
3567dcf36dcSFrançois Tigeot 					 rdev->gart.num_gpu_pages);
3577dcf36dcSFrançois Tigeot 	if (rdev->gart.pages_entry == NULL) {
358926deccbSFrançois Tigeot 		radeon_gart_fini(rdev);
359926deccbSFrançois Tigeot 		return -ENOMEM;
360926deccbSFrançois Tigeot 	}
361926deccbSFrançois Tigeot 	/* set GART entry to point to the dummy page by default */
3627dcf36dcSFrançois Tigeot 	for (i = 0; i < rdev->gart.num_gpu_pages; i++)
3637dcf36dcSFrançois Tigeot 		rdev->gart.pages_entry[i] = rdev->dummy_page.entry;
364926deccbSFrançois Tigeot 	return 0;
365926deccbSFrançois Tigeot }
366926deccbSFrançois Tigeot 
367926deccbSFrançois Tigeot /**
368926deccbSFrançois Tigeot  * radeon_gart_fini - tear down the driver info for managing the gart
369926deccbSFrançois Tigeot  *
370926deccbSFrançois Tigeot  * @rdev: radeon_device pointer
371926deccbSFrançois Tigeot  *
372926deccbSFrançois Tigeot  * Tear down the gart driver info and free the dummy page (all asics).
373926deccbSFrançois Tigeot  */
radeon_gart_fini(struct radeon_device * rdev)374926deccbSFrançois Tigeot void radeon_gart_fini(struct radeon_device *rdev)
375926deccbSFrançois Tigeot {
3767dcf36dcSFrançois Tigeot 	if (rdev->gart.ready) {
377926deccbSFrançois Tigeot 		/* unbind pages */
378926deccbSFrançois Tigeot 		radeon_gart_unbind(rdev, 0, rdev->gart.num_cpu_pages);
379926deccbSFrançois Tigeot 	}
380926deccbSFrançois Tigeot 	rdev->gart.ready = false;
3817dcf36dcSFrançois Tigeot 	vfree(rdev->gart.pages);
3827dcf36dcSFrançois Tigeot 	vfree(rdev->gart.pages_entry);
383926deccbSFrançois Tigeot 	rdev->gart.pages = NULL;
3847dcf36dcSFrançois Tigeot 	rdev->gart.pages_entry = NULL;
385926deccbSFrançois Tigeot 
386926deccbSFrançois Tigeot 	radeon_dummy_page_fini(rdev);
387926deccbSFrançois Tigeot }
388