[intel] Quirk away MSI support on 945G/GM.
[platform/upstream/libdrm.git] / linux-core / drm_vm_nopage_compat.c
1 /**
2  * \file drm_vm.c
3  * Memory mapping for DRM
4  *
5  * \author Rickard E. (Rik) Faith <faith@valinux.com>
6  * \author Gareth Hughes <gareth@valinux.com>
7  */
8
9 /*
10  * Created: Mon Jan  4 08:58:31 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 "drmP.h"
37
38 #ifdef DRM_VM_NOPAGE
39 /**
40  * \c nopage method for AGP virtual memory.
41  *
42  * \param vma virtual memory area.
43  * \param address access address.
44  * \return pointer to the page structure.
45  *
46  * Find the right map and if it's AGP memory find the real physical page to
47  * map, get the page, increment the use count and return it.
48  */
49 #if __OS_HAS_AGP
50 static __inline__ struct page *drm_do_vm_nopage(struct vm_area_struct *vma,
51                                                 unsigned long address)
52 {
53         struct drm_file *priv = vma->vm_file->private_data;
54         struct drm_device *dev = priv->minor->dev;
55         struct drm_map *map = NULL;
56         struct drm_map_list *r_list;
57         struct drm_hash_item *hash;
58
59         /*
60          * Find the right map
61          */
62         if (!drm_core_has_AGP(dev))
63                 goto vm_nopage_error;
64
65         if (!dev->agp || !dev->agp->cant_use_aperture)
66                 goto vm_nopage_error;
67
68         if (drm_ht_find_item(&dev->map_hash, vma->vm_pgoff, &hash))
69                 goto vm_nopage_error;
70
71         r_list = drm_hash_entry(hash, struct drm_map_list, hash);
72         map = r_list->map;
73
74         if (map && map->type == _DRM_AGP) {
75                 unsigned long offset = address - vma->vm_start;
76                 unsigned long baddr = map->offset + offset;
77                 struct drm_agp_mem *agpmem;
78                 struct page *page;
79
80 #ifdef __alpha__
81                 /*
82                  * Adjust to a bus-relative address
83                  */
84                 baddr -= dev->hose->mem_space->start;
85 #endif
86
87                 /*
88                  * It's AGP memory - find the real physical page to map
89                  */
90                 list_for_each_entry(agpmem, &dev->agp->memory, head) {
91                         if (agpmem->bound <= baddr &&
92                             agpmem->bound + agpmem->pages * PAGE_SIZE > baddr)
93                                 break;
94                 }
95
96                 if (!agpmem)
97                         goto vm_nopage_error;
98
99                 /*
100                  * Get the page, inc the use count, and return it
101                  */
102                 offset = (baddr - agpmem->bound) >> PAGE_SHIFT;
103                 page = virt_to_page(__va(agpmem->memory->memory[offset]));
104                 get_page(page);
105
106 #if 0
107                 /* page_count() not defined everywhere */
108                 DRM_DEBUG
109                     ("baddr = 0x%lx page = 0x%p, offset = 0x%lx, count=%d\n",
110                      baddr, __va(agpmem->memory->memory[offset]), offset,
111                      page_count(page));
112 #endif
113
114                 return page;
115         }
116       vm_nopage_error:
117         return NOPAGE_SIGBUS;   /* Disallow mremap */
118 }
119 #else                           /* __OS_HAS_AGP */
120 static __inline__ struct page *drm_do_vm_nopage(struct vm_area_struct *vma,
121                                                 unsigned long address)
122 {
123         return NOPAGE_SIGBUS;
124 }
125 #endif                          /* __OS_HAS_AGP */
126
127 /**
128  * \c nopage method for shared virtual memory.
129  *
130  * \param vma virtual memory area.
131  * \param address access address.
132  * \return pointer to the page structure.
133  *
134  * Get the mapping, find the real physical page to map, get the page, and
135  * return it.
136  */
137 static __inline__ struct page *drm_do_vm_shm_nopage(struct vm_area_struct *vma,
138                                                     unsigned long address)
139 {
140         struct drm_map *map = (struct drm_map *) vma->vm_private_data;
141         unsigned long offset;
142         unsigned long i;
143         struct page *page;
144
145         if (address > vma->vm_end)
146                 return NOPAGE_SIGBUS;   /* Disallow mremap */
147         if (!map)
148                 return NOPAGE_SIGBUS;   /* Nothing allocated */
149
150         offset = address - vma->vm_start;
151         i = (unsigned long)map->handle + offset;
152         page = vmalloc_to_page((void *)i);
153         if (!page)
154                 return NOPAGE_SIGBUS;
155         get_page(page);
156
157         DRM_DEBUG("0x%lx\n", address);
158         return page;
159 }
160
161 /**
162  * \c nopage method for DMA virtual memory.
163  *
164  * \param vma virtual memory area.
165  * \param address access address.
166  * \return pointer to the page structure.
167  *
168  * Determine the page number from the page offset and get it from drm_device_dma::pagelist.
169  */
170 static __inline__ struct page *drm_do_vm_dma_nopage(struct vm_area_struct *vma,
171                                                     unsigned long address)
172 {
173         struct drm_file *priv = vma->vm_file->private_data;
174         struct drm_device *dev = priv->minor->dev;
175         struct drm_device_dma *dma = dev->dma;
176         unsigned long offset;
177         unsigned long page_nr;
178         struct page *page;
179
180         if (!dma)
181                 return NOPAGE_SIGBUS;   /* Error */
182         if (address > vma->vm_end)
183                 return NOPAGE_SIGBUS;   /* Disallow mremap */
184         if (!dma->pagelist)
185                 return NOPAGE_SIGBUS;   /* Nothing allocated */
186
187         offset = address - vma->vm_start;       /* vm_[pg]off[set] should be 0 */
188         page_nr = offset >> PAGE_SHIFT;
189         page = virt_to_page((dma->pagelist[page_nr] + (offset & (~PAGE_MASK))));
190
191         get_page(page);
192
193         DRM_DEBUG("0x%lx (page %lu)\n", address, page_nr);
194         return page;
195 }
196
197 /**
198  * \c nopage method for scatter-gather virtual memory.
199  *
200  * \param vma virtual memory area.
201  * \param address access address.
202  * \return pointer to the page structure.
203  *
204  * Determine the map offset from the page offset and get it from drm_sg_mem::pagelist.
205  */
206 static __inline__ struct page *drm_do_vm_sg_nopage(struct vm_area_struct *vma,
207                                                    unsigned long address)
208 {
209         struct drm_map *map = (struct drm_map *) vma->vm_private_data;
210         struct drm_file *priv = vma->vm_file->private_data;
211         struct drm_device *dev = priv->minor->dev;
212         struct drm_sg_mem *entry = dev->sg;
213         unsigned long offset;
214         unsigned long map_offset;
215         unsigned long page_offset;
216         struct page *page;
217
218         DRM_DEBUG("\n");
219         if (!entry)
220                 return NOPAGE_SIGBUS;   /* Error */
221         if (address > vma->vm_end)
222                 return NOPAGE_SIGBUS;   /* Disallow mremap */
223         if (!entry->pagelist)
224                 return NOPAGE_SIGBUS;   /* Nothing allocated */
225
226         offset = address - vma->vm_start;
227         map_offset = map->offset - (unsigned long)dev->sg->virtual;
228         page_offset = (offset >> PAGE_SHIFT) + (map_offset >> PAGE_SHIFT);
229         page = entry->pagelist[page_offset];
230         get_page(page);
231
232         return page;
233 }
234
235
236 struct page *drm_vm_nopage(struct vm_area_struct *vma,
237                            unsigned long address, int *type)
238 {
239         if (type)
240                 *type = VM_FAULT_MINOR;
241         return drm_do_vm_nopage(vma, address);
242 }
243
244 struct page *drm_vm_shm_nopage(struct vm_area_struct *vma,
245                                unsigned long address, int *type)
246 {
247         if (type)
248                 *type = VM_FAULT_MINOR;
249         return drm_do_vm_shm_nopage(vma, address);
250 }
251
252 struct page *drm_vm_dma_nopage(struct vm_area_struct *vma,
253                                unsigned long address, int *type)
254 {
255         if (type)
256                 *type = VM_FAULT_MINOR;
257         return drm_do_vm_dma_nopage(vma, address);
258 }
259
260 struct page *drm_vm_sg_nopage(struct vm_area_struct *vma,
261                               unsigned long address, int *type)
262 {
263         if (type)
264                 *type = VM_FAULT_MINOR;
265         return drm_do_vm_sg_nopage(vma, address);
266 }
267 #endif