OSDN Git Service

nouveau/nv50: hack up initial channel context from current state
[android-x86/external-libdrm.git] / bsd-core / drm_agpsupport.c
1 /* drm_agpsupport.h -- DRM support for AGP/GART backend -*- linux-c -*-
2  * Created: Mon Dec 13 09:56:45 1999 by faith@precisioninsight.com
3  */
4 /*-
5  * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
6  * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
7  * All Rights Reserved.
8  *
9  * Permission is hereby granted, free of charge, to any person obtaining a
10  * copy of this software and associated documentation files (the "Software"),
11  * to deal in the Software without restriction, including without limitation
12  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13  * and/or sell copies of the Software, and to permit persons to whom the
14  * Software is furnished to do so, subject to the following conditions:
15  *
16  * The above copyright notice and this permission notice (including the next
17  * paragraph) shall be included in all copies or substantial portions of the
18  * Software.
19  *
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
23  * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
24  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
25  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
26  * OTHER DEALINGS IN THE SOFTWARE.
27  *
28  * Author:
29  *    Rickard E. (Rik) Faith <faith@valinux.com>
30  *    Gareth Hughes <gareth@valinux.com>
31  *
32  */
33
34 #include "drmP.h"
35
36 #ifdef __FreeBSD__
37 #include <pci/agpreg.h>
38 #include <dev/pci/pcireg.h>
39 #endif
40
41 /* Returns 1 if AGP or 0 if not. */
42 static int
43 drm_device_find_capability(drm_device_t *dev, int cap)
44 {
45 #ifdef __FreeBSD__
46 #if __FreeBSD_version >= 602102
47
48         return (pci_find_extcap(dev->device, cap, NULL) == 0);
49 #else
50         /* Code taken from agp.c.  IWBNI that was a public interface. */
51         u_int32_t status;
52         u_int8_t ptr, next;
53
54         /*
55          * Check the CAP_LIST bit of the PCI status register first.
56          */
57         status = pci_read_config(dev->device, PCIR_STATUS, 2);
58         if (!(status & 0x10))
59                 return 0;
60
61         /*
62          * Traverse the capabilities list.
63          */
64         for (ptr = pci_read_config(dev->device, AGP_CAPPTR, 1);
65              ptr != 0;
66              ptr = next) {
67                 u_int32_t capid = pci_read_config(dev->device, ptr, 4);
68                 next = AGP_CAPID_GET_NEXT_PTR(capid);
69
70                 /*
71                  * If this capability entry ID is cap, then we are done.
72                  */
73                 if (AGP_CAPID_GET_CAP_ID(capid) == cap)
74                         return 1;
75         }
76
77         return 0;
78 #endif
79 #else
80         /* XXX: fill me in for non-FreeBSD */
81         return 1;
82 #endif
83 }
84
85 int drm_device_is_agp(drm_device_t *dev)
86 {
87         if (dev->driver.device_is_agp != NULL) {
88                 int ret;
89
90                 /* device_is_agp returns a tristate, 0 = not AGP, 1 = definitely
91                  * AGP, 2 = fall back to PCI capability
92                  */
93                 ret = (*dev->driver.device_is_agp)(dev);
94                 if (ret != DRM_MIGHT_BE_AGP)
95                         return ret;
96         }
97
98         return (drm_device_find_capability(dev, PCIY_AGP));
99 }
100
101 int drm_device_is_pcie(drm_device_t *dev)
102 {
103         return (drm_device_find_capability(dev, PCIY_EXPRESS));
104 }
105
106 int drm_agp_info(drm_device_t * dev, drm_agp_info_t *info)
107 {
108         struct agp_info *kern;
109
110         if (!dev->agp || !dev->agp->acquired)
111                 return EINVAL;
112
113         kern                   = &dev->agp->info;
114         agp_get_info(dev->agp->agpdev, kern);
115         info->agp_version_major = 1;
116         info->agp_version_minor = 0;
117         info->mode              = kern->ai_mode;
118         info->aperture_base     = kern->ai_aperture_base;
119         info->aperture_size     = kern->ai_aperture_size;
120         info->memory_allowed    = kern->ai_memory_allowed;
121         info->memory_used       = kern->ai_memory_used;
122         info->id_vendor         = kern->ai_devid & 0xffff;
123         info->id_device         = kern->ai_devid >> 16;
124
125         return 0;
126 }
127
128 int drm_agp_info_ioctl(drm_device_t *dev, void *data, struct drm_file *file_priv)
129 {
130         int err;
131         drm_agp_info_t info;
132
133         err = drm_agp_info(dev, &info);
134         if (err != 0)
135                 return err;
136
137         *(drm_agp_info_t *) data = info;
138         return 0;
139 }
140
141 int drm_agp_acquire_ioctl(drm_device_t *dev, void *data, struct drm_file *file_priv)
142 {
143
144         return drm_agp_acquire(dev);
145 }
146
147 int drm_agp_acquire(drm_device_t *dev)
148 {
149         int retcode;
150
151         if (!dev->agp || dev->agp->acquired)
152                 return EINVAL;
153
154         retcode = agp_acquire(dev->agp->agpdev);
155         if (retcode)
156                 return retcode;
157
158         dev->agp->acquired = 1;
159         return 0;
160 }
161
162 int drm_agp_release_ioctl(drm_device_t *dev, void *data, struct drm_file *file_priv)
163 {
164
165         return drm_agp_release(dev);
166 }
167
168 int drm_agp_release(drm_device_t * dev)
169 {
170         if (!dev->agp || !dev->agp->acquired)
171                 return EINVAL;
172         agp_release(dev->agp->agpdev);
173         dev->agp->acquired = 0;
174         return 0;
175 }
176
177 int drm_agp_enable(drm_device_t *dev, drm_agp_mode_t mode)
178 {
179
180         if (!dev->agp || !dev->agp->acquired)
181                 return EINVAL;
182         
183         dev->agp->mode    = mode.mode;
184         agp_enable(dev->agp->agpdev, mode.mode);
185         dev->agp->base    = dev->agp->info.ai_aperture_base;
186         dev->agp->enabled = 1;
187         return 0;
188 }
189
190 int drm_agp_enable_ioctl(drm_device_t *dev, void *data, struct drm_file *file_priv)
191 {
192         drm_agp_mode_t mode;
193
194         mode = *(drm_agp_mode_t *) data;
195
196         return drm_agp_enable(dev, mode);
197 }
198
199 int drm_agp_alloc(drm_device_t *dev, drm_agp_buffer_t *request)
200 {
201         drm_agp_mem_t    *entry;
202         void             *handle;
203         unsigned long    pages;
204         u_int32_t        type;
205         struct agp_memory_info info;
206
207         if (!dev->agp || !dev->agp->acquired)
208                 return EINVAL;
209
210         entry = malloc(sizeof(*entry), M_DRM, M_NOWAIT | M_ZERO);
211         if (entry == NULL)
212                 return ENOMEM;
213
214         pages = (request->size + PAGE_SIZE - 1) / PAGE_SIZE;
215         type = (u_int32_t) request->type;
216
217         DRM_UNLOCK();
218         handle = drm_agp_allocate_memory(pages, type);
219         DRM_LOCK();
220         if (handle == NULL) {
221                 free(entry, M_DRM);
222                 return ENOMEM;
223         }
224         
225         entry->handle    = handle;
226         entry->bound     = 0;
227         entry->pages     = pages;
228         entry->prev      = NULL;
229         entry->next      = dev->agp->memory;
230         if (dev->agp->memory)
231                 dev->agp->memory->prev = entry;
232         dev->agp->memory = entry;
233
234         agp_memory_info(dev->agp->agpdev, entry->handle, &info);
235
236         request->handle   = (unsigned long) entry->handle;
237         request->physical = info.ami_physical;
238
239         return 0;
240 }
241
242 int drm_agp_alloc_ioctl(drm_device_t *dev, void *data, struct drm_file *file_priv)
243 {
244         drm_agp_buffer_t request;
245         int retcode;
246
247         request = *(drm_agp_buffer_t *) data;
248
249         DRM_LOCK();
250         retcode = drm_agp_alloc(dev, &request);
251         DRM_UNLOCK();
252
253         *(drm_agp_buffer_t *) data = request;
254
255         return retcode;
256 }
257
258 static drm_agp_mem_t * drm_agp_lookup_entry(drm_device_t *dev, void *handle)
259 {
260         drm_agp_mem_t *entry;
261
262         for (entry = dev->agp->memory; entry; entry = entry->next) {
263                 if (entry->handle == handle) return entry;
264         }
265         return NULL;
266 }
267
268 int drm_agp_unbind(drm_device_t *dev, drm_agp_binding_t *request)
269 {
270         drm_agp_mem_t     *entry;
271         int retcode;
272
273         if (!dev->agp || !dev->agp->acquired)
274                 return EINVAL;
275
276         entry = drm_agp_lookup_entry(dev, (void *)request->handle);
277         if (entry == NULL || !entry->bound)
278                 return EINVAL;
279
280         DRM_UNLOCK();
281         retcode = drm_agp_unbind_memory(entry->handle);
282         DRM_LOCK();
283
284         if (retcode == 0)
285                 entry->bound = 0;
286
287         return retcode;
288 }
289
290 int drm_agp_unbind_ioctl(drm_device_t *dev, void *data, struct drm_file *file_priv)
291 {
292         drm_agp_binding_t request;
293         int retcode;
294
295         request = *(drm_agp_binding_t *) data;
296
297         DRM_LOCK();
298         retcode = drm_agp_unbind(dev, &request);
299         DRM_UNLOCK();
300
301         return retcode;
302 }
303
304 int drm_agp_bind(drm_device_t *dev, drm_agp_binding_t *request)
305 {
306         drm_agp_mem_t     *entry;
307         int               retcode;
308         int               page;
309         
310         if (!dev->agp || !dev->agp->acquired)
311                 return EINVAL;
312
313         DRM_DEBUG("agp_bind, page_size=%x\n", PAGE_SIZE);
314
315         entry = drm_agp_lookup_entry(dev, (void *)request->handle);
316         if (entry == NULL || entry->bound)
317                 return EINVAL;
318
319         page = (request->offset + PAGE_SIZE - 1) / PAGE_SIZE;
320
321         DRM_UNLOCK();
322         retcode = drm_agp_bind_memory(entry->handle, page);
323         DRM_LOCK();
324         if (retcode == 0)
325                 entry->bound = dev->agp->base + (page << PAGE_SHIFT);
326
327         return retcode;
328 }
329
330 int drm_agp_bind_ioctl(drm_device_t *dev, void *data, struct drm_file *file_priv)
331 {
332         drm_agp_binding_t request;
333         int retcode;
334
335         request = *(drm_agp_binding_t *) data;
336
337         DRM_LOCK();
338         retcode = drm_agp_bind(dev, &request);
339         DRM_UNLOCK();
340
341         return retcode;
342 }
343
344 int drm_agp_free(drm_device_t *dev, drm_agp_buffer_t *request)
345 {
346         drm_agp_mem_t    *entry;
347         
348         if (!dev->agp || !dev->agp->acquired)
349                 return EINVAL;
350
351         entry = drm_agp_lookup_entry(dev, (void*)request->handle);
352         if (entry == NULL)
353                 return EINVAL;
354    
355         if (entry->prev)
356                 entry->prev->next = entry->next;
357         else
358                 dev->agp->memory  = entry->next;
359         if (entry->next)
360                 entry->next->prev = entry->prev;
361
362         DRM_UNLOCK();
363         if (entry->bound)
364                 drm_agp_unbind_memory(entry->handle);
365         drm_agp_free_memory(entry->handle);
366         DRM_LOCK();
367
368         free(entry, M_DRM);
369
370         return 0;
371
372 }
373
374 int drm_agp_free_ioctl(drm_device_t *dev, void *data, struct drm_file *file_priv)
375 {
376         drm_agp_buffer_t request;
377         int retcode;
378
379         request = *(drm_agp_buffer_t *) data;
380
381         DRM_LOCK();
382         retcode = drm_agp_free(dev, &request);
383         DRM_UNLOCK();
384
385         return retcode;
386 }
387
388 drm_agp_head_t *drm_agp_init(void)
389 {
390         device_t agpdev;
391         drm_agp_head_t *head   = NULL;
392         int      agp_available = 1;
393    
394         agpdev = DRM_AGP_FIND_DEVICE();
395         if (!agpdev)
396                 agp_available = 0;
397
398         DRM_DEBUG("agp_available = %d\n", agp_available);
399
400         if (agp_available) {
401                 head = malloc(sizeof(*head), M_DRM, M_NOWAIT | M_ZERO);
402                 if (head == NULL)
403                         return NULL;
404                 head->agpdev = agpdev;
405                 agp_get_info(agpdev, &head->info);
406                 head->memory = NULL;
407                 DRM_INFO("AGP at 0x%08lx %dMB\n",
408                          (long)head->info.ai_aperture_base,
409                          (int)(head->info.ai_aperture_size >> 20));
410         }
411         return head;
412 }
413
414 void *drm_agp_allocate_memory(size_t pages, u32 type)
415 {
416         device_t agpdev;
417
418         agpdev = DRM_AGP_FIND_DEVICE();
419         if (!agpdev)
420                 return NULL;
421
422         return agp_alloc_memory(agpdev, type, pages << AGP_PAGE_SHIFT);
423 }
424
425 int drm_agp_free_memory(void *handle)
426 {
427         device_t agpdev;
428
429         agpdev = DRM_AGP_FIND_DEVICE();
430         if (!agpdev || !handle)
431                 return 0;
432
433         agp_free_memory(agpdev, handle);
434         return 1;
435 }
436
437 int drm_agp_bind_memory(void *handle, off_t start)
438 {
439         device_t agpdev;
440
441         agpdev = DRM_AGP_FIND_DEVICE();
442         if (!agpdev || !handle)
443                 return EINVAL;
444
445         return agp_bind_memory(agpdev, handle, start * PAGE_SIZE);
446 }
447
448 int drm_agp_unbind_memory(void *handle)
449 {
450         device_t agpdev;
451
452         agpdev = DRM_AGP_FIND_DEVICE();
453         if (!agpdev || !handle)
454                 return EINVAL;
455
456         return agp_unbind_memory(agpdev, handle);
457 }