2 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
7 * drm_agpsupport.h -- DRM support for AGP/GART backend -*- linux-c -*-
8 * Created: Mon Dec 13 09:56:45 1999 by faith@precisioninsight.com
11 * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
12 * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
13 * Copyright (c) 2009, Intel Corporation.
14 * All Rights Reserved.
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:
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
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.
36 * Rickard E. (Rik) Faith <faith@valinux.com>
37 * Gareth Hughes <gareth@valinux.com>
45 #define AGP_PAGE_SIZE 4096
46 #define AGP_PAGE_SHIFT 12
50 * The agpa_key field of struct agp_allocate_t actually is
51 * an index to an array. It can be zero. But we will use
52 * this agpa_key as a handle returned to userland. Generally,
53 * 0 is not a valid value for a handle, so we add an offset
54 * to the key to get a handle.
56 #define DRM_AGP_KEY_OFFSET 8
58 extern int drm_supp_device_capability(void *handle
, int capid
);
62 drm_device_is_agp(drm_device_t
*dev
)
66 if (dev
->driver
->device_is_agp
!= NULL
) {
68 * device_is_agp returns a tristate:
71 * 2 = fall back to PCI capability
73 ret
= (*dev
->driver
->device_is_agp
)(dev
);
74 if (ret
!= DRM_MIGHT_BE_AGP
)
78 return (drm_supp_device_capability(dev
->drm_handle
, PCIY_AGP
));
84 drm_device_is_pcie(drm_device_t
*dev
)
86 return (drm_supp_device_capability(dev
->drm_handle
, PCIY_EXPRESS
));
92 drm_agp_info(DRM_IOCTL_ARGS
)
98 if (!dev
->agp
|| !dev
->agp
->acquired
)
101 agpinfo
= &dev
->agp
->agp_info
;
102 info
.agp_version_major
= agpinfo
->agpi_version
.agpv_major
;
103 info
.agp_version_minor
= agpinfo
->agpi_version
.agpv_minor
;
104 info
.mode
= agpinfo
->agpi_mode
;
105 info
.aperture_base
= agpinfo
->agpi_aperbase
;
106 info
.aperture_size
= agpinfo
->agpi_apersize
* 1024 * 1024;
107 info
.memory_allowed
= agpinfo
->agpi_pgtotal
<< PAGE_SHIFT
;
108 info
.memory_used
= agpinfo
->agpi_pgused
<< PAGE_SHIFT
;
109 info
.id_vendor
= agpinfo
->agpi_devid
& 0xffff;
110 info
.id_device
= agpinfo
->agpi_devid
>> 16;
112 DRM_COPYTO_WITH_RETURN((void *)data
, &info
, sizeof (info
));
118 drm_agp_acquire(DRM_IOCTL_ARGS
)
124 DRM_ERROR("drm_agp_acquire : agp isn't initialized yet");
127 ret
= ldi_ioctl(dev
->agp
->agpgart_lh
, AGPIOC_ACQUIRE
,
128 (uintptr_t)0, FKIOCTL
, kcred
, &rval
);
130 DRM_ERROR("drm_agp_acquired: AGPIOC_ACQUIRE failed\n");
133 dev
->agp
->acquired
= 1;
140 drm_agp_release(DRM_IOCTL_ARGS
)
147 if (!dev
->agp
->acquired
)
150 ret
= ldi_ioctl(dev
->agp
->agpgart_lh
, AGPIOC_RELEASE
,
151 (intptr_t)0, FKIOCTL
, kcred
, &rval
);
153 DRM_ERROR("drm_agp_release: AGPIOC_RELEASE failed\n");
156 dev
->agp
->acquired
= 0;
163 drm_agp_do_release(drm_device_t
*dev
)
167 ret
= ldi_ioctl(dev
->agp
->agpgart_lh
, AGPIOC_RELEASE
,
168 (intptr_t)0, FKIOCTL
, kcred
, &rval
);
171 dev
->agp
->acquired
= 0;
178 drm_agp_enable(DRM_IOCTL_ARGS
)
181 drm_agp_mode_t modes
;
187 if (!dev
->agp
->acquired
)
190 DRM_COPYFROM_WITH_RETURN(&modes
, (void *)data
, sizeof (modes
));
192 dev
->agp
->mode
= modes
.mode
;
193 setup
.agps_mode
= (uint32_t)modes
.mode
;
196 DRM_DEBUG("drm_agp_enable: dev->agp->mode=%lx", modes
.mode
);
198 ret
= ldi_ioctl(dev
->agp
->agpgart_lh
, AGPIOC_SETUP
,
199 (intptr_t)&setup
, FKIOCTL
, kcred
, &rval
);
201 DRM_ERROR("drm_agp_enable: failed");
205 dev
->agp
->base
= dev
->agp
->agp_info
.agpi_aperbase
;
206 dev
->agp
->enabled
= 1;
208 DRM_DEBUG("drm_agp_enable: dev->agp->base=0x%lx", dev
->agp
->base
);
214 drm_agp_alloc(DRM_IOCTL_ARGS
)
217 drm_agp_mem_t
*entry
;
218 agp_allocate_t alloc
;
219 drm_agp_buffer_t request
;
223 if (!dev
->agp
|| !dev
->agp
->acquired
)
226 DRM_COPYFROM_WITH_RETURN(&request
, (void *)data
, sizeof (request
));
228 entry
= kmem_zalloc(sizeof (*entry
), KM_SLEEP
);
230 pages
= btopr(request
.size
);
231 alloc
.agpa_pgcount
= pages
;
232 alloc
.agpa_type
= AGP_NORMAL
;
233 ret
= ldi_ioctl(dev
->agp
->agpgart_lh
, AGPIOC_ALLOCATE
,
234 (intptr_t)&alloc
, FKIOCTL
, kcred
, &rval
);
236 DRM_ERROR("drm_agp_alloc: AGPIOC_ALLOCATE failed, ret=%d", ret
);
237 kmem_free(entry
, sizeof (*entry
));
242 entry
->pages
= pages
;
243 entry
->handle
= (void*)(uintptr_t)(alloc
.agpa_key
+ DRM_AGP_KEY_OFFSET
);
245 entry
->phys_addr
= (void*)(uintptr_t)alloc
.agpa_physical
;
246 entry
->next
= dev
->agp
->memory
;
247 if (dev
->agp
->memory
)
248 dev
->agp
->memory
->prev
= entry
;
249 dev
->agp
->memory
= entry
;
251 DRM_DEBUG("entry->phys_addr %lx", entry
->phys_addr
);
253 /* physical is used only by i810 driver */
254 request
.physical
= alloc
.agpa_physical
;
255 request
.handle
= (unsigned long)entry
->handle
;
258 * If failed to ddi_copyout(), we will free allocated AGP memory
261 DRM_COPYTO_WITH_RETURN((void *)data
, &request
, sizeof (request
));
267 static drm_agp_mem_t
*
268 drm_agp_lookup_entry(drm_device_t
*dev
, void *handle
)
270 drm_agp_mem_t
*entry
;
272 for (entry
= dev
->agp
->memory
; entry
; entry
= entry
->next
) {
273 if (entry
->handle
== handle
)
282 drm_agp_unbind(DRM_IOCTL_ARGS
)
286 drm_agp_binding_t request
;
287 drm_agp_mem_t
*entry
;
290 if (!dev
->agp
|| !dev
->agp
->acquired
)
293 DRM_COPYFROM_WITH_RETURN(&request
, (void *)data
, sizeof (request
));
295 if (!(entry
= drm_agp_lookup_entry(dev
, (void *)request
.handle
)))
301 unbind
.agpu_key
= (uintptr_t)entry
->handle
- DRM_AGP_KEY_OFFSET
;
303 ret
= ldi_ioctl(dev
->agp
->agpgart_lh
, AGPIOC_UNBIND
,
304 (intptr_t)&unbind
, FKIOCTL
, kcred
, &rval
);
306 DRM_ERROR("drm_agp_unbind: AGPIOC_UNBIND failed");
315 drm_agp_bind(DRM_IOCTL_ARGS
)
318 drm_agp_binding_t request
;
319 drm_agp_mem_t
*entry
;
323 if (!dev
->agp
|| !dev
->agp
->acquired
)
326 DRM_COPYFROM_WITH_RETURN(&request
, (void *)data
, sizeof (request
));
328 entry
= drm_agp_lookup_entry(dev
, (void *)request
.handle
);
329 if (!entry
|| entry
->bound
)
332 key
= (uintptr_t)entry
->handle
- DRM_AGP_KEY_OFFSET
;
333 start
= btopr(request
.offset
);
334 if (drm_agp_bind_memory(key
, start
, dev
)) {
335 DRM_ERROR("drm_agp_bind: failed key=%x, start=0x%x, "
336 "agp_base=0x%lx", key
, start
, dev
->agp
->base
);
340 entry
->bound
= dev
->agp
->base
+ (start
<< AGP_PAGE_SHIFT
);
347 drm_agp_free(DRM_IOCTL_ARGS
)
350 drm_agp_buffer_t request
;
351 drm_agp_mem_t
*entry
;
355 DRM_COPYFROM_WITH_RETURN(&request
, (void *)data
, sizeof (request
));
356 if (!dev
->agp
|| !dev
->agp
->acquired
)
358 if (!(entry
= drm_agp_lookup_entry(dev
, (void *)request
.handle
)))
361 (void) drm_agp_unbind_memory(request
.handle
, dev
);
363 if (entry
== dev
->agp
->memory
)
364 dev
->agp
->memory
= entry
->next
;
366 entry
->prev
->next
= entry
->next
;
368 entry
->next
->prev
= entry
->prev
;
370 agpu_key
= (uintptr_t)entry
->handle
- DRM_AGP_KEY_OFFSET
;
371 ret
= ldi_ioctl(dev
->agp
->agpgart_lh
, AGPIOC_DEALLOCATE
,
372 (intptr_t)agpu_key
, FKIOCTL
, kcred
, &rval
);
374 DRM_ERROR("drm_agp_free: AGPIOC_DEALLOCATE failed,"
375 "akey=%d, ret=%d", agpu_key
, ret
);
378 drm_free(entry
, sizeof (*entry
), DRM_MEM_AGPLISTS
);
384 drm_agp_init(drm_device_t
*dev
)
386 drm_agp_head_t
*agp
= NULL
;
389 agp
= kmem_zalloc(sizeof (drm_agp_head_t
), KM_SLEEP
);
391 retval
= ldi_ident_from_dip(dev
->dip
, &agp
->agpgart_li
);
393 DRM_ERROR("drm_agp_init: failed to get layerd ident, retval=%d",
398 retval
= ldi_open_by_name(AGP_DEVICE
, FEXCL
, kcred
,
399 &agp
->agpgart_lh
, agp
->agpgart_li
);
401 DRM_ERROR("drm_agp_init: failed to open %s, retval=%d",
406 retval
= ldi_ioctl(agp
->agpgart_lh
, AGPIOC_INFO
,
407 (intptr_t)&agp
->agp_info
, FKIOCTL
, kcred
, &rval
);
410 DRM_ERROR("drm_agp_init: failed to get agpinfo, retval=%d",
418 (void) ldi_close(agp
->agpgart_lh
, FEXCL
, kcred
);
421 ldi_ident_release(agp
->agpgart_li
);
424 kmem_free(agp
, sizeof (drm_agp_head_t
));
430 drm_agp_fini(drm_device_t
*dev
)
432 drm_agp_head_t
*agp
= dev
->agp
;
433 (void) ldi_close(agp
->agpgart_lh
, FEXCL
, kcred
);
434 ldi_ident_release(agp
->agpgart_li
);
435 kmem_free(agp
, sizeof (drm_agp_head_t
));
442 drm_agp_allocate_memory(size_t pages
, uint32_t type
, drm_device_t
*dev
)
449 drm_agp_free_memory(agp_allocate_t
*handle
, drm_device_t
*dev
)
456 drm_agp_bind_memory(unsigned int key
, uint32_t start
, drm_device_t
*dev
)
461 bind
.agpb_pgstart
= start
;
463 ret
= ldi_ioctl(dev
->agp
->agpgart_lh
, AGPIOC_BIND
,
464 (intptr_t)&bind
, FKIOCTL
, kcred
, &rval
);
466 DRM_DEBUG("drm_agp_bind_meory: AGPIOC_BIND failed");
474 drm_agp_unbind_memory(unsigned long handle
, drm_device_t
*dev
)
477 drm_agp_mem_t
*entry
;
480 if (!dev
->agp
|| !dev
->agp
->acquired
)
483 entry
= drm_agp_lookup_entry(dev
, (void *)handle
);
484 if (!entry
|| !entry
->bound
)
488 unbind
.agpu_key
= (uintptr_t)entry
->handle
- DRM_AGP_KEY_OFFSET
;
490 ret
= ldi_ioctl(dev
->agp
->agpgart_lh
, AGPIOC_UNBIND
,
491 (intptr_t)&unbind
, FKIOCTL
, kcred
, &rval
);
493 DRM_ERROR("drm_agp_unbind: AGPIO_UNBIND failed");
501 * Binds a collection of pages into AGP memory at the given offset, returning
502 * the AGP memory structure containing them.
504 * No reference is held on the pages during this time -- it is up to the
505 * caller to handle that.
508 drm_agp_bind_pages(drm_device_t
*dev
,
510 unsigned long num_pages
,
514 agp_bind_pages_t bind
;
517 bind
.agpb_pgstart
= gtt_offset
/ AGP_PAGE_SIZE
;
518 bind
.agpb_pgcount
= num_pages
;
519 bind
.agpb_pages
= pages
;
520 ret
= ldi_ioctl(dev
->agp
->agpgart_lh
, AGPIOC_PAGES_BIND
,
521 (intptr_t)&bind
, FKIOCTL
, kcred
, &rval
);
523 DRM_ERROR("AGPIOC_PAGES_BIND failed ret %d", ret
);
530 drm_agp_unbind_pages(drm_device_t
*dev
,
531 unsigned long num_pages
,
536 agp_unbind_pages_t unbind
;
539 unbind
.agpb_pgstart
= gtt_offset
/ AGP_PAGE_SIZE
;
540 unbind
.agpb_pgcount
= num_pages
;
541 unbind
.agpb_type
= type
;
542 ret
= ldi_ioctl(dev
->agp
->agpgart_lh
, AGPIOC_PAGES_UNBIND
,
543 (intptr_t)&unbind
, FKIOCTL
, kcred
, &rval
);
545 DRM_DEBUG("drm_agp_unbind_pages AGPIOC_PAGES_UNBIND failed");
552 * Certain Intel chipsets contains a global write buffer, and this can require
553 * flushing from the drm or X.org to make sure all data has hit RAM before
554 * initiating a GPU transfer, due to a lack of coherency with the integrated
555 * graphics device and this buffer.
558 drm_agp_chipset_flush(struct drm_device
*dev
)
562 DRM_DEBUG("agp_chipset_flush");
563 ret
= ldi_ioctl(dev
->agp
->agpgart_lh
, AGPIOC_FLUSHCHIPSET
,
564 (intptr_t)0, FKIOCTL
, kcred
, &rval
);
566 DRM_ERROR("Failed to drm_agp_chipset_flush ret %d", ret
);
571 * The pages are evict on suspend, so re-bind it at resume time
574 drm_agp_rebind(struct drm_device
*dev
)
582 ret
= ldi_ioctl(dev
->agp
->agpgart_lh
, AGPIOC_PAGES_REBIND
,
583 (intptr_t)0, FKIOCTL
, kcred
, &rval
);
585 DRM_ERROR("rebind failed %d", ret
);