via_memmgr.c revision 90b17f1b
1/*
2 * Copyright 2003 Red Hat, Inc. All Rights Reserved.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sub license,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the
12 * next paragraph) shall be included in all copies or substantial portions
13 * of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 */
23
24#ifdef HAVE_CONFIG_H
25#include "config.h"
26#endif
27#include <sys/mman.h>
28
29#include "xf86.h"
30#include "xf86_OSproc.h"
31#include "xf86fbman.h"
32
33#ifdef HAVE_DRI
34#include "xf86drm.h"
35#endif
36
37#include "via_driver.h"
38#ifdef HAVE_DRI
39#include "via_drm.h"
40#endif
41
42/*
43 *	Isolate the wonders of X memory allocation and DRI memory allocation
44 *	and 4.3 or 4.4 differences in one abstraction.
45 *
46 *	The pool code indicates who provided the memory:
47 *	0  -  nobody
48 *	1  -  xf86 linear
49 *	2  -  DRM
50 */
51int
52viaOffScreenLinear(struct buffer_object *obj, ScrnInfoPtr pScrn,
53                   unsigned long size)
54{
55    int depth = pScrn->bitsPerPixel >> 3;
56    FBLinearPtr linear;
57
58    linear = xf86AllocateOffscreenLinear(pScrn->pScreen,
59                                        (size + depth - 1) / depth,
60                                        32, NULL, NULL, NULL);
61    if (!linear)
62        return BadAlloc;
63    obj->offset = linear->offset * depth;
64    obj->handle = (unsigned long) linear;
65    obj->domain = TTM_PL_FLAG_VRAM;
66    obj->size = size;
67    return Success;
68}
69
70struct buffer_object *
71drm_bo_alloc_surface(ScrnInfoPtr pScrn, unsigned int width, unsigned int height,
72                    int format, unsigned int alignment, int domain)
73{
74    struct buffer_object *obj = NULL;
75    int pitch;
76
77    switch (format) {
78    case DRM_FORMAT_C8:
79        pitch = width;
80        break;
81
82    case DRM_FORMAT_XRGB1555:
83    case DRM_FORMAT_RGB565:
84        pitch = width * 2;
85        break;
86
87    case DRM_FORMAT_RGB888:
88        pitch = width * 3;
89        break;
90
91    case DRM_FORMAT_XRGB2101010:
92    case DRM_FORMAT_XRGB8888:
93        pitch = width * 4;
94        break;
95    }
96
97    pitch = ALIGN_TO(pitch, alignment);
98    obj = drm_bo_alloc(pScrn, pitch * height, alignment, domain);
99    if (!obj->pitch)
100        obj->pitch = pitch;
101    return obj;
102}
103
104struct buffer_object *
105drm_bo_alloc(ScrnInfoPtr pScrn, unsigned int size, unsigned int alignment, int domain)
106{
107    struct buffer_object *obj = NULL;
108    VIAPtr pVia = VIAPTR(pScrn);
109    int ret = 0;
110
111    obj = xnfcalloc(1, sizeof(*obj));
112    if (obj) {
113        switch (domain) {
114        case TTM_PL_FLAG_TT:
115        case TTM_PL_FLAG_VRAM:
116            if (pVia->directRenderingType == DRI_NONE) {
117                if (Success != viaOffScreenLinear(obj, pScrn, size)) {
118                    ErrorF("Linear memory allocation failed\n");
119                    ret = -ENOMEM;
120                } else
121                    DEBUG(ErrorF("%lu bytes of Linear memory allocated at %lx, handle %lu\n", obj->size, obj->offset, obj->handle));
122#ifdef HAVE_DRI
123            } else if (pVia->directRenderingType == DRI_1) {
124                drm_via_mem_t drm;
125
126                size = ALIGN_TO(size, alignment);
127                drm.context = DRIGetContext(pScrn->pScreen);
128                drm.size = size;
129                drm.type = (domain == TTM_PL_FLAG_TT ? VIA_MEM_AGP : VIA_MEM_VIDEO);
130                ret = drmCommandWriteRead(pVia->drmmode.fd, DRM_VIA_ALLOCMEM,
131                                            &drm, sizeof(drm_via_mem_t));
132                if (!ret && (size == drm.size)) {
133                    if (domain == TTM_PL_FLAG_VRAM)
134                        drm.offset -= pVia->FBFreeStart;
135                    obj->offset = ALIGN_TO(drm.offset, alignment);
136                    obj->handle = drm.index;
137                    obj->domain = domain;
138                    obj->size = drm.size;
139                    DEBUG(ErrorF("%lu bytes of DRI memory allocated at %lx, handle %lu\n",
140                                obj->size, obj->offset, obj->handle));
141                }
142            } else if (pVia->directRenderingType == DRI_2) {
143                struct drm_via_gem_create args;
144
145                /* Some day this will be moved to libdrm. */
146                args.domains = domain;
147                args.alignment = alignment;
148                args.pitch = 0;
149                args.size = size;
150                ret = drmCommandWriteRead(pVia->drmmode.fd, DRM_VIA_GEM_CREATE,
151                                        &args, sizeof(struct drm_via_gem_create));
152                if (!ret) {
153                    /* Okay the X server expects to know the offset because
154                     * of non-KMS. Once we have KMS working the offset
155                     * will not be valid. */
156                    obj->map_offset = args.map_handle;
157                    obj->offset = args.offset;
158                    obj->handle = args.handle;
159                    obj->pitch = args.pitch;
160                    obj->size = args.size;
161                    obj->domain = domain;
162                    DEBUG(ErrorF("%lu bytes of DRI2 memory allocated at %lx, handle %lu\n",
163                                obj->size, obj->offset, obj->handle));
164                }
165#endif
166            }
167            break;
168
169        case TTM_PL_FLAG_SYSTEM:
170        default:
171            ret = -ENXIO;
172            break;
173        }
174
175        if (ret) {
176            DEBUG(ErrorF("DRM memory allocation failed %d\n", ret));
177            free(obj);
178            obj = NULL;
179        };
180    }
181    return obj;
182}
183
184void*
185drm_bo_map(ScrnInfoPtr pScrn, struct buffer_object *obj)
186{
187    VIAPtr pVia = VIAPTR(pScrn);
188
189    if (pVia->directRenderingType == DRI_2) {
190        obj->ptr = mmap(0, obj->size, PROT_READ | PROT_WRITE,
191                        MAP_SHARED, pVia->drmmode.fd, obj->map_offset);
192        if (obj->ptr == MAP_FAILED) {
193            DEBUG(ErrorF("mmap failed with error %d\n", -errno));
194            obj->ptr = NULL;
195        }
196    } else {
197        switch (obj->domain) {
198#ifdef HAVE_DRI
199        case TTM_PL_FLAG_TT:
200            obj->ptr = (pVia->agpMappedAddr + obj->offset);
201            break;
202#endif
203        case TTM_PL_FLAG_VRAM:
204            obj->ptr = (pVia->FBBase + obj->offset);
205            break;
206        default:
207            obj->ptr = NULL;
208            break;
209        }
210    }
211    return obj->ptr;
212}
213
214void
215drm_bo_unmap(ScrnInfoPtr pScrn, struct buffer_object *obj)
216{
217    VIAPtr pVia = VIAPTR(pScrn);
218
219    if (pVia->directRenderingType == DRI_2)
220        munmap(obj->ptr, obj->size);
221    obj->ptr = NULL;
222}
223
224void
225drm_bo_free(ScrnInfoPtr pScrn, struct buffer_object *obj)
226{
227    VIAPtr pVia = VIAPTR(pScrn);
228
229    if (obj) {
230        DEBUG(ErrorF("Freed %lu (pool %d)\n", obj->offset, obj->domain));
231        switch (obj->domain) {
232        case TTM_PL_FLAG_VRAM:
233        case TTM_PL_FLAG_TT:
234            if (pVia->directRenderingType == DRI_NONE) {
235                FBLinearPtr linear = (FBLinearPtr) obj->handle;
236
237                xf86FreeOffscreenLinear(linear);
238#ifdef HAVE_DRI
239            } else if (pVia->directRenderingType == DRI_1) {
240                drm_via_mem_t drm;
241
242                drm.index = obj->handle;
243                if (drmCommandWrite(pVia->drmmode.fd, DRM_VIA_FREEMEM,
244                                    &drm, sizeof(drm_via_mem_t)) < 0)
245                    ErrorF("DRM failed to free for handle %lu.\n", obj->handle);
246            } else  if (pVia->directRenderingType == DRI_2) {
247                struct drm_gem_close close;
248
249                close.handle = obj->handle;
250                if (drmIoctl(pVia->drmmode.fd, DRM_IOCTL_GEM_CLOSE, &close) < 0)
251                    ErrorF("DRM failed to free for handle %lu.\n", obj->handle);
252#endif
253            }
254            break;
255
256        default:
257            break;
258        }
259        free(obj);
260    }
261}
262
263Bool
264drm_bo_manager_init(ScrnInfoPtr pScrn)
265{
266    VIAPtr pVia = VIAPTR(pScrn);
267    Bool ret = TRUE;
268
269    if (pVia->directRenderingType == DRI_2)
270        return ret;
271    ret = ums_create(pScrn);
272#ifdef HAVE_DRI
273    if (pVia->directRenderingType == DRI_1)
274        ret = VIADRIKernelInit(pScrn);
275#endif
276    return ret;
277}
278