/* * Copyright 2003 Red Hat, Inc. All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sub license, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the * next paragraph) shall be included in all copies or substantial portions * of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include "xf86.h" #include "xf86_OSproc.h" #include "xf86fbman.h" #ifdef HAVE_DRI #include "xf86drm.h" #endif #include "drm_fourcc.h" #include "via_driver.h" #ifdef HAVE_DRI #include "via_drm.h" #else #include "drm_fourcc.h" #endif static int viaOffScreenLinear(ScrnInfoPtr pScrn, struct buffer_object *obj, unsigned long size, unsigned long alignment) { FBLinearPtr linear; int depth = pScrn->bitsPerPixel / 8; int newAlignment; int ret = 0; newAlignment = alignment; linear = xf86AllocateOffscreenLinear(pScrn->pScreen, (size + depth - 1) / depth, newAlignment, NULL, NULL, NULL); if (!linear) { ret = -ENOMEM; goto exit; } obj->offset = linear->offset * depth; obj->handle = (unsigned long) linear; obj->domain = TTM_PL_FLAG_VRAM; obj->size = size; exit: return ret; } struct buffer_object * drm_bo_alloc(ScrnInfoPtr pScrn, unsigned long size, unsigned long alignment, int domain) { struct buffer_object *obj = NULL; VIAPtr pVia = VIAPTR(pScrn); int ret = 0; obj = xnfcalloc(1, sizeof(*obj)); if (!obj) { DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Allocation of a buffer object used for " "memory allocation failed.\n")); goto exit; } switch (domain) { case TTM_PL_FLAG_TT: case TTM_PL_FLAG_VRAM: if (pVia->directRenderingType == DRI_NONE) { if (!pVia->useEXA) { ret = viaOffScreenLinear(pScrn, obj, size, alignment); if (ret) { DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Linear memory allocation " "failed.\n")); } else { DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "%lu bytes of linear memory " "allocated at 0x%lx, handle " "0x%lx.\n", obj->size, obj->offset, obj->handle)); } } else { ret = viaEXAOffscreenAlloc(pScrn, obj, size, alignment); if (ret) { DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "EXA offscreen memory " "allocation failed.\n")); } else { DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "%lu bytes of EXA offscreen " "memory allocated at 0x%lx, " "handle 0x%lx.\n", obj->size, obj->offset, obj->handle)); } } #ifdef HAVE_DRI } else if (pVia->directRenderingType == DRI_1) { drm_via_mem_t drm; size = ALIGN_TO(size, alignment); drm.context = DRIGetContext(pScrn->pScreen); drm.size = size; drm.type = (domain == TTM_PL_FLAG_TT ? VIA_MEM_AGP : VIA_MEM_VIDEO); ret = drmCommandWriteRead(pVia->drmmode.fd, DRM_VIA_ALLOCMEM, &drm, sizeof(drm_via_mem_t)); if (!ret && (size == drm.size)) { if (domain == TTM_PL_FLAG_VRAM) drm.offset -= pVia->FBFreeStart; obj->offset = ALIGN_TO(drm.offset, alignment); obj->handle = drm.index; obj->domain = domain; obj->size = drm.size; DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "%lu bytes of DRI memory " "allocated at 0x%lx, " "handle 0x%lx.\n", obj->size, obj->offset, obj->handle)); } } else if (pVia->directRenderingType == DRI_2) { struct drm_via_gem_object args; /* Some day this will be moved to libdrm. */ args.domains = domain; args.alignment = alignment; args.size = size; ret = drmCommandWriteRead(pVia->drmmode.fd, DRM_VIA_GEM_CREATE, &args, sizeof(struct drm_via_gem_object)); if (!ret) { /* Okay the X server expects to know the offset because * of non-KMS. Once we have KMS working the offset * will not be valid. */ obj->map_offset = args.map_handle; obj->offset = args.offset; obj->handle = args.handle; obj->size = args.size; obj->domain = domain; DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_INFO, "%lu bytes of DRI2 memory " "allocated at 0x%lx, " "handle 0x%lx.\n", obj->size, obj->offset, obj->handle)); } #endif } break; case TTM_PL_FLAG_SYSTEM: default: ret = -ENXIO; break; } if (ret) { DEBUG(xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "DRM memory allocation failed.\n" "Error Code: %d\n", ret)); free(obj); obj = NULL; goto exit; } exit: return obj; } void* drm_bo_map(ScrnInfoPtr pScrn, struct buffer_object *obj) { VIAPtr pVia = VIAPTR(pScrn); if (pVia->directRenderingType == DRI_2) { obj->ptr = mmap(0, obj->size, PROT_READ | PROT_WRITE, MAP_SHARED, pVia->drmmode.fd, obj->map_offset); if (obj->ptr == MAP_FAILED) { DEBUG(ErrorF("mmap failed with error %d\n", -errno)); obj->ptr = NULL; } } else { switch (obj->domain) { #ifdef HAVE_DRI case TTM_PL_FLAG_TT: obj->ptr = (uint8_t*)pVia->agpMappedAddr + obj->offset; break; #endif case TTM_PL_FLAG_VRAM: obj->ptr = pVia->FBBase + obj->offset; break; default: obj->ptr = NULL; break; } } return obj->ptr; } void drm_bo_unmap(ScrnInfoPtr pScrn, struct buffer_object *obj) { VIAPtr pVia = VIAPTR(pScrn); if (pVia->directRenderingType == DRI_2) { munmap(obj->ptr, obj->size); } obj->ptr = NULL; } void drm_bo_free(ScrnInfoPtr pScrn, struct buffer_object *obj) { VIAPtr pVia = VIAPTR(pScrn); if (obj) { DEBUG(ErrorF("Freed %lu (pool %d)\n", obj->offset, obj->domain)); switch (obj->domain) { case TTM_PL_FLAG_VRAM: case TTM_PL_FLAG_TT: if (pVia->directRenderingType == DRI_NONE) { if (!pVia->useEXA) { FBLinearPtr linear = (FBLinearPtr) obj->handle; xf86FreeOffscreenLinear(linear); } else { ExaOffscreenArea *pArea = (ExaOffscreenArea *)obj->handle; exaOffscreenFree(pScrn->pScreen, pArea); } #ifdef HAVE_DRI } else if (pVia->directRenderingType == DRI_1) { drm_via_mem_t drm; drm.index = obj->handle; if (drmCommandWrite(pVia->drmmode.fd, DRM_VIA_FREEMEM, &drm, sizeof(drm_via_mem_t)) < 0) ErrorF("DRM failed to free for handle %lu.\n", obj->handle); } else if (pVia->directRenderingType == DRI_2) { struct drm_gem_close close; close.handle = obj->handle; if (drmIoctl(pVia->drmmode.fd, DRM_IOCTL_GEM_CLOSE, &close) < 0) ErrorF("DRM failed to free for handle %lu.\n", obj->handle); #endif } break; default: break; } free(obj); } }