Branch data Line data Source code
1 : : /*
2 : : * \file drm_memory.c
3 : : * Memory management wrappers for DRM
4 : : *
5 : : * \author Rickard E. (Rik) Faith <faith@valinux.com>
6 : : * \author Gareth Hughes <gareth@valinux.com>
7 : : */
8 : :
9 : : /*
10 : : * Created: Thu Feb 4 14:00:34 1999 by faith@valinux.com
11 : : *
12 : : * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
13 : : * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
14 : : * All Rights Reserved.
15 : : *
16 : : * Permission is hereby granted, free of charge, to any person obtaining a
17 : : * copy of this software and associated documentation files (the "Software"),
18 : : * to deal in the Software without restriction, including without limitation
19 : : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
20 : : * and/or sell copies of the Software, and to permit persons to whom the
21 : : * Software is furnished to do so, subject to the following conditions:
22 : : *
23 : : * The above copyright notice and this permission notice (including the next
24 : : * paragraph) shall be included in all copies or substantial portions of the
25 : : * Software.
26 : : *
27 : : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
28 : : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
29 : : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
30 : : * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
31 : : * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
32 : : * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
33 : : * OTHER DEALINGS IN THE SOFTWARE.
34 : : */
35 : :
36 : : #include <linux/export.h>
37 : : #include <linux/highmem.h>
38 : : #include <linux/pci.h>
39 : : #include <linux/vmalloc.h>
40 : : #include <xen/xen.h>
41 : :
42 : : #include <drm/drm_agpsupport.h>
43 : : #include <drm/drm_cache.h>
44 : : #include <drm/drm_device.h>
45 : :
46 : : #include "drm_legacy.h"
47 : :
48 : : #if IS_ENABLED(CONFIG_AGP)
49 : :
50 : : #ifdef HAVE_PAGE_AGP
51 : : # include <asm/agp.h>
52 : : #else
53 : : # ifdef __powerpc__
54 : : # define PAGE_AGP pgprot_noncached_wc(PAGE_KERNEL)
55 : : # else
56 : : # define PAGE_AGP PAGE_KERNEL
57 : : # endif
58 : : #endif
59 : :
60 : : static void *agp_remap(unsigned long offset, unsigned long size,
61 : : struct drm_device *dev)
62 : : {
63 : : unsigned long i, num_pages =
64 : : PAGE_ALIGN(size) / PAGE_SIZE;
65 : : struct drm_agp_mem *agpmem;
66 : : struct page **page_map;
67 : : struct page **phys_page_map;
68 : : void *addr;
69 : :
70 : : size = PAGE_ALIGN(size);
71 : :
72 : : #ifdef __alpha__
73 : : offset -= dev->hose->mem_space->start;
74 : : #endif
75 : :
76 : : list_for_each_entry(agpmem, &dev->agp->memory, head)
77 : : if (agpmem->bound <= offset
78 : : && (agpmem->bound + (agpmem->pages << PAGE_SHIFT)) >=
79 : : (offset + size))
80 : : break;
81 : : if (&agpmem->head == &dev->agp->memory)
82 : : return NULL;
83 : :
84 : : /*
85 : : * OK, we're mapping AGP space on a chipset/platform on which memory accesses by
86 : : * the CPU do not get remapped by the GART. We fix this by using the kernel's
87 : : * page-table instead (that's probably faster anyhow...).
88 : : */
89 : : /* note: use vmalloc() because num_pages could be large... */
90 : : page_map = vmalloc(array_size(num_pages, sizeof(struct page *)));
91 : : if (!page_map)
92 : : return NULL;
93 : :
94 : : phys_page_map = (agpmem->memory->pages + (offset - agpmem->bound) / PAGE_SIZE);
95 : : for (i = 0; i < num_pages; ++i)
96 : : page_map[i] = phys_page_map[i];
97 : : addr = vmap(page_map, num_pages, VM_IOREMAP, PAGE_AGP);
98 : : vfree(page_map);
99 : :
100 : : return addr;
101 : : }
102 : :
103 : : /** Wrapper around agp_free_memory() */
104 : 0 : void drm_free_agp(struct agp_memory *handle, int pages)
105 : : {
106 : 0 : agp_free_memory(handle);
107 : 0 : }
108 : :
109 : : /** Wrapper around agp_bind_memory() */
110 : 0 : int drm_bind_agp(struct agp_memory *handle, unsigned int start)
111 : : {
112 : 0 : return agp_bind_memory(handle, start);
113 : : }
114 : :
115 : : /** Wrapper around agp_unbind_memory() */
116 : 0 : int drm_unbind_agp(struct agp_memory *handle)
117 : : {
118 : 0 : return agp_unbind_memory(handle);
119 : : }
120 : :
121 : : #else /* CONFIG_AGP */
122 : : static inline void *agp_remap(unsigned long offset, unsigned long size,
123 : : struct drm_device *dev)
124 : : {
125 : : return NULL;
126 : : }
127 : :
128 : : #endif /* CONFIG_AGP */
129 : :
130 : 0 : void drm_legacy_ioremap(struct drm_local_map *map, struct drm_device *dev)
131 : : {
132 [ # # # # : 0 : if (dev->agp && dev->agp->cant_use_aperture && map->type == _DRM_AGP)
# # ]
133 : 0 : map->handle = agp_remap(map->offset, map->size, dev);
134 : : else
135 : 0 : map->handle = ioremap(map->offset, map->size);
136 : 0 : }
137 : : EXPORT_SYMBOL(drm_legacy_ioremap);
138 : :
139 : 0 : void drm_legacy_ioremap_wc(struct drm_local_map *map, struct drm_device *dev)
140 : : {
141 [ # # # # : 0 : if (dev->agp && dev->agp->cant_use_aperture && map->type == _DRM_AGP)
# # ]
142 : 0 : map->handle = agp_remap(map->offset, map->size, dev);
143 : : else
144 : 0 : map->handle = ioremap_wc(map->offset, map->size);
145 : 0 : }
146 : : EXPORT_SYMBOL(drm_legacy_ioremap_wc);
147 : :
148 : 0 : void drm_legacy_ioremapfree(struct drm_local_map *map, struct drm_device *dev)
149 : : {
150 [ # # # # ]: 0 : if (!map->handle || !map->size)
151 : : return;
152 : :
153 [ # # # # : 0 : if (dev->agp && dev->agp->cant_use_aperture && map->type == _DRM_AGP)
# # ]
154 : 0 : vunmap(map->handle);
155 : : else
156 : 0 : iounmap(map->handle);
157 : : }
158 : : EXPORT_SYMBOL(drm_legacy_ioremapfree);
159 : :
160 : 0 : bool drm_need_swiotlb(int dma_bits)
161 : : {
162 : 0 : struct resource *tmp;
163 : 0 : resource_size_t max_iomem = 0;
164 : :
165 : : /*
166 : : * Xen paravirtual hosts require swiotlb regardless of requested dma
167 : : * transfer size.
168 : : *
169 : : * NOTE: Really, what it requires is use of the dma_alloc_coherent
170 : : * allocator used in ttm_dma_populate() instead of
171 : : * ttm_populate_and_map_pages(), which bounce buffers so much in
172 : : * Xen it leads to swiotlb buffer exhaustion.
173 : : */
174 : 0 : if (xen_pv_domain())
175 : : return true;
176 : :
177 : : /*
178 : : * Enforce dma_alloc_coherent when memory encryption is active as well
179 : : * for the same reasons as for Xen paravirtual hosts.
180 : : */
181 : 0 : if (mem_encrypt_active())
182 : : return true;
183 : :
184 [ # # ]: 0 : for (tmp = iomem_resource.child; tmp; tmp = tmp->sibling) {
185 : 0 : max_iomem = max(max_iomem, tmp->end);
186 : : }
187 : :
188 : 0 : return max_iomem > ((u64)1 << dma_bits);
189 : : }
190 : : EXPORT_SYMBOL(drm_need_swiotlb);
|