Home | History | Annotate | Line # | Download | only in src
      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 "drm_fourcc.h"
     38 #include "via_driver.h"
     39 #ifdef HAVE_DRI
     40 #include "via_drm.h"
     41 #else
     42 #include "drm_fourcc.h"
     43 #endif
     44 
     45 /*
     46  *	Isolate the wonders of X memory allocation and DRI memory allocation
     47  *	and 4.3 or 4.4 differences in one abstraction.
     48  *
     49  *	The pool code indicates who provided the memory:
     50  *	0  -  nobody
     51  *	1  -  xf86 linear
     52  *	2  -  DRM
     53  */
     54 int
     55 viaOffScreenLinear(struct buffer_object *obj, ScrnInfoPtr pScrn,
     56                    unsigned long size)
     57 {
     58     int depth = pScrn->bitsPerPixel >> 3;
     59     FBLinearPtr linear;
     60 
     61     linear = xf86AllocateOffscreenLinear(pScrn->pScreen,
     62                                         (size + depth - 1) / depth,
     63                                         32, NULL, NULL, NULL);
     64     if (!linear)
     65         return BadAlloc;
     66     obj->offset = linear->offset * depth;
     67     obj->handle = (unsigned long) linear;
     68     obj->domain = TTM_PL_FLAG_VRAM;
     69     obj->size = size;
     70     return Success;
     71 }
     72 
     73 struct buffer_object *
     74 drm_bo_alloc_surface(ScrnInfoPtr pScrn, unsigned int width, unsigned int height,
     75                     int format, unsigned int alignment, int domain)
     76 {
     77     struct buffer_object *obj = NULL;
     78     int pitch;
     79 
     80     switch (format) {
     81     case DRM_FORMAT_C8:
     82         pitch = width;
     83         break;
     84 
     85     case DRM_FORMAT_XRGB1555:
     86     case DRM_FORMAT_RGB565:
     87         pitch = width * 2;
     88         break;
     89 
     90     case DRM_FORMAT_RGB888:
     91         pitch = width * 3;
     92         break;
     93 
     94     case DRM_FORMAT_XRGB2101010:
     95     case DRM_FORMAT_XRGB8888:
     96         pitch = width * 4;
     97         break;
     98     }
     99 
    100     pitch = ALIGN_TO(pitch, alignment);
    101     obj = drm_bo_alloc(pScrn, pitch * height, alignment, domain);
    102     if (!obj->pitch)
    103         obj->pitch = pitch;
    104     return obj;
    105 }
    106 
    107 struct buffer_object *
    108 drm_bo_alloc(ScrnInfoPtr pScrn, unsigned int size, unsigned int alignment, int domain)
    109 {
    110     struct buffer_object *obj = NULL;
    111     VIAPtr pVia = VIAPTR(pScrn);
    112     int ret = 0;
    113 
    114     obj = xnfcalloc(1, sizeof(*obj));
    115     if (obj) {
    116         switch (domain) {
    117         case TTM_PL_FLAG_TT:
    118         case TTM_PL_FLAG_VRAM:
    119             if (pVia->directRenderingType == DRI_NONE) {
    120                 if (Success != viaOffScreenLinear(obj, pScrn, size)) {
    121                     ErrorF("Linear memory allocation failed\n");
    122                     ret = -ENOMEM;
    123                 } else
    124                     DEBUG(ErrorF("%lu bytes of Linear memory allocated at %lx, handle %lu\n", obj->size, obj->offset, obj->handle));
    125 #ifdef HAVE_DRI
    126             } else if (pVia->directRenderingType == DRI_1) {
    127                 drm_via_mem_t drm;
    128 
    129                 size = ALIGN_TO(size, alignment);
    130                 drm.context = DRIGetContext(pScrn->pScreen);
    131                 drm.size = size;
    132                 drm.type = (domain == TTM_PL_FLAG_TT ? VIA_MEM_AGP : VIA_MEM_VIDEO);
    133                 ret = drmCommandWriteRead(pVia->drmmode.fd, DRM_VIA_ALLOCMEM,
    134                                             &drm, sizeof(drm_via_mem_t));
    135                 if (!ret && (size == drm.size)) {
    136                     if (domain == TTM_PL_FLAG_VRAM)
    137                         drm.offset -= pVia->FBFreeStart;
    138                     obj->offset = ALIGN_TO(drm.offset, alignment);
    139                     obj->handle = drm.index;
    140                     obj->domain = domain;
    141                     obj->size = drm.size;
    142                     DEBUG(ErrorF("%lu bytes of DRI memory allocated at %lx, handle %lu\n",
    143                                 obj->size, obj->offset, obj->handle));
    144                 }
    145             } else if (pVia->directRenderingType == DRI_2) {
    146                 struct drm_via_gem_object args;
    147 
    148                 /* Some day this will be moved to libdrm. */
    149                 args.domains = domain;
    150                 args.alignment = alignment;
    151                 args.pitch = 0;
    152                 args.size = size;
    153                 ret = drmCommandWriteRead(pVia->drmmode.fd, DRM_VIA_GEM_CREATE,
    154                                         &args, sizeof(struct drm_via_gem_object));
    155                 if (!ret) {
    156                     /* Okay the X server expects to know the offset because
    157                      * of non-KMS. Once we have KMS working the offset
    158                      * will not be valid. */
    159                     obj->map_offset = args.map_handle;
    160                     obj->offset = args.offset;
    161                     obj->handle = args.handle;
    162                     obj->pitch = args.pitch;
    163                     obj->size = args.size;
    164                     obj->domain = domain;
    165                     DEBUG(ErrorF("%lu bytes of DRI2 memory allocated at %lx, handle %lu\n",
    166                                 obj->size, obj->offset, obj->handle));
    167                 }
    168 #endif
    169             }
    170             break;
    171 
    172         case TTM_PL_FLAG_SYSTEM:
    173         default:
    174             ret = -ENXIO;
    175             break;
    176         }
    177 
    178         if (ret) {
    179             DEBUG(ErrorF("DRM memory allocation failed %d\n", ret));
    180             free(obj);
    181             obj = NULL;
    182         };
    183     }
    184     return obj;
    185 }
    186 
    187 void*
    188 drm_bo_map(ScrnInfoPtr pScrn, struct buffer_object *obj)
    189 {
    190     VIAPtr pVia = VIAPTR(pScrn);
    191 
    192     if (pVia->directRenderingType == DRI_2) {
    193         obj->ptr = mmap(0, obj->size, PROT_READ | PROT_WRITE,
    194                         MAP_SHARED, pVia->drmmode.fd, obj->map_offset);
    195         if (obj->ptr == MAP_FAILED) {
    196             DEBUG(ErrorF("mmap failed with error %d\n", -errno));
    197             obj->ptr = NULL;
    198         }
    199     } else {
    200         switch (obj->domain) {
    201 #ifdef HAVE_DRI
    202         case TTM_PL_FLAG_TT:
    203             obj->ptr = (pVia->agpMappedAddr + obj->offset);
    204             break;
    205 #endif
    206         case TTM_PL_FLAG_VRAM:
    207             obj->ptr = (pVia->FBBase + obj->offset);
    208             break;
    209         default:
    210             obj->ptr = NULL;
    211             break;
    212         }
    213     }
    214     return obj->ptr;
    215 }
    216 
    217 void
    218 drm_bo_unmap(ScrnInfoPtr pScrn, struct buffer_object *obj)
    219 {
    220     VIAPtr pVia = VIAPTR(pScrn);
    221 
    222     if (pVia->directRenderingType == DRI_2) {
    223         munmap(obj->ptr, obj->size);
    224     }
    225 
    226     obj->ptr = NULL;
    227 }
    228 
    229 void
    230 drm_bo_free(ScrnInfoPtr pScrn, struct buffer_object *obj)
    231 {
    232     VIAPtr pVia = VIAPTR(pScrn);
    233 
    234     if (obj) {
    235         DEBUG(ErrorF("Freed %lu (pool %d)\n", obj->offset, obj->domain));
    236         switch (obj->domain) {
    237         case TTM_PL_FLAG_VRAM:
    238         case TTM_PL_FLAG_TT:
    239             if (pVia->directRenderingType == DRI_NONE) {
    240                 FBLinearPtr linear = (FBLinearPtr) obj->handle;
    241 
    242                 xf86FreeOffscreenLinear(linear);
    243 #ifdef HAVE_DRI
    244             } else if (pVia->directRenderingType == DRI_1) {
    245                 drm_via_mem_t drm;
    246 
    247                 drm.index = obj->handle;
    248                 if (drmCommandWrite(pVia->drmmode.fd, DRM_VIA_FREEMEM,
    249                                     &drm, sizeof(drm_via_mem_t)) < 0)
    250                     ErrorF("DRM failed to free for handle %lu.\n", obj->handle);
    251             } else  if (pVia->directRenderingType == DRI_2) {
    252                 struct drm_gem_close close;
    253 
    254                 close.handle = obj->handle;
    255                 if (drmIoctl(pVia->drmmode.fd, DRM_IOCTL_GEM_CLOSE, &close) < 0)
    256                     ErrorF("DRM failed to free for handle %lu.\n", obj->handle);
    257 #endif
    258             }
    259             break;
    260 
    261         default:
    262             break;
    263         }
    264         free(obj);
    265     }
    266 }
    267 
    268 Bool
    269 drm_bo_manager_init(ScrnInfoPtr pScrn)
    270 {
    271     VIAPtr pVia = VIAPTR(pScrn);
    272     Bool ret = TRUE;
    273 
    274     if (pVia->directRenderingType == DRI_2)
    275         return ret;
    276     ret = umsCreate(pScrn);
    277 #ifdef HAVE_DRI
    278     if (pVia->directRenderingType == DRI_1)
    279         ret = VIADRIKernelInit(pScrn);
    280 #endif
    281     return ret;
    282 }
    283