From patchwork Sat Jun 8 16:48:06 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: James Simmons X-Patchwork-Id: 2692761 Return-Path: X-Original-To: patchwork-dri-devel@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork1.kernel.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by patchwork1.kernel.org (Postfix) with ESMTP id 1DC673FC23 for ; Sat, 8 Jun 2013 16:48:50 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 101E5E6127 for ; Sat, 8 Jun 2013 09:48:50 -0700 (PDT) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from casper.infradead.org (casper.infradead.org [85.118.1.10]) by gabe.freedesktop.org (Postfix) with ESMTP id 36E2BE6145; Sat, 8 Jun 2013 09:48:10 -0700 (PDT) Received: from jsimmons (helo=localhost) by casper.infradead.org with local-esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1UlMJC-0005yi-SG; Sat, 08 Jun 2013 16:48:08 +0000 Date: Sat, 8 Jun 2013 17:48:06 +0100 (BST) From: James Simmons To: DRI development list Subject: [RFC 6/21] DRM: Add VIA DRM driver Message-ID: User-Agent: Alpine 2.03 (LFD 1266 2009-07-14) MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20130608_174807_038266_D86018EA X-CRM114-Status: GOOD ( 13.61 ) X-Spam-Score: -1.9 (-) X-Spam-Report: SpamAssassin version 3.3.2 on casper.infradead.org summary: Content analysis details: (-1.9 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 NO_RELAYS Informational: message was not relayed via SMTP -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] Cc: OpenChrome Development X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.13 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: dri-devel-bounces+patchwork-dri-devel=patchwork.kernel.org@lists.freedesktop.org Errors-To: dri-devel-bounces+patchwork-dri-devel=patchwork.kernel.org@lists.freedesktop.org commit 5ec2cdc6f99549122329253b1c4d1a04193b81d0 Author: James Simmons Date: Sat Jun 8 07:59:56 2013 -0400 via: TTM and GEM memory handling TTM buffer object life cycle and state handling is done in init_ttm.c. The VIA GEM implemenation is a simple wrapper around the TTM layer that uses our ttm functions from init_ttm.c Signed-Off-by: James Simmons diff --git a/drivers/gpu/drm/via/init_ttm.c b/drivers/gpu/drm/via/init_ttm.c new file mode 100644 index 0000000..ead32a1 --- /dev/null +++ b/drivers/gpu/drm/via/init_ttm.c @@ -0,0 +1,249 @@ +/* + * Copyright (c) 2012 James Simmons + * 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 COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS 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. + */ + +#include "drmP.h" +#include "ttm/ttm_bo_driver.h" +#include "ttm/ttm_placement.h" + +#define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT) + +struct ttm_heap { + uint32_t busy_placements[TTM_NUM_MEM_TYPES]; + uint32_t placements[TTM_NUM_MEM_TYPES]; + struct ttm_buffer_object pbo; +}; + +static int +ttm_global_mem_init(struct drm_global_reference *ref) +{ + return ttm_mem_global_init(ref->object); +} + +static void +ttm_global_mem_release(struct drm_global_reference *ref) +{ + ttm_mem_global_release(ref->object); +} + +void +ttm_global_fini(struct drm_global_reference *global_ref, + struct ttm_bo_global_ref *global_bo, + struct ttm_bo_device *bdev) +{ + if (global_ref->release == NULL) + return; + + if (bdev) + ttm_bo_device_release(bdev); + drm_global_item_unref(&global_bo->ref); + drm_global_item_unref(global_ref); + global_ref->release = NULL; +} + +int +ttm_global_init(struct drm_global_reference *global_ref, + struct ttm_bo_global_ref *global_bo, + struct ttm_bo_driver *driver, + struct ttm_bo_device *bdev, + bool dma32) +{ + struct drm_global_reference *bo_ref; + int rc; + + global_ref->global_type = DRM_GLOBAL_TTM_MEM; + global_ref->size = sizeof(struct ttm_mem_global); + global_ref->init = &ttm_global_mem_init; + global_ref->release = &ttm_global_mem_release; + + rc = drm_global_item_ref(global_ref); + if (unlikely(rc != 0)) { + DRM_ERROR("Failed setting up TTM memory accounting\n"); + global_ref->release = NULL; + return rc; + } + + global_bo->mem_glob = global_ref->object; + bo_ref = &global_bo->ref; + bo_ref->global_type = DRM_GLOBAL_TTM_BO; + bo_ref->size = sizeof(struct ttm_bo_global); + bo_ref->init = &ttm_bo_global_init; + bo_ref->release = &ttm_bo_global_release; + + rc = drm_global_item_ref(bo_ref); + if (unlikely(rc != 0)) { + DRM_ERROR("Failed setting up TTM BO subsystem\n"); + drm_global_item_unref(global_ref); + global_ref->release = NULL; + return rc; + } + + rc = ttm_bo_device_init(bdev, bo_ref->object, driver, + DRM_FILE_PAGE_OFFSET, dma32); + if (rc) { + DRM_ERROR("Error initialising bo driver: %d\n", rc); + ttm_global_fini(global_ref, global_bo, NULL); + } + return rc; +} + +static void +ttm_buffer_object_destroy(struct ttm_buffer_object *bo) +{ + struct ttm_heap *heap = container_of(bo, struct ttm_heap, pbo); + + kfree(heap); + heap = NULL; +} + +/* + * the buffer object domain + */ +void +ttm_placement_from_domain(struct ttm_buffer_object *bo, struct ttm_placement *placement, u32 domains, + struct ttm_bo_device *bdev) +{ + struct ttm_heap *heap = container_of(bo, struct ttm_heap, pbo); + int cnt = 0, i = 0; + + if (!(domains & TTM_PL_MASK_MEM)) domains = TTM_PL_FLAG_SYSTEM; + + do { + int domain = (domains & (1 << i)); + + if (domain) { + heap->busy_placements[cnt] = (domain | bdev->man[i].default_caching); + heap->placements[cnt++] = (domain | bdev->man[i].available_caching); + } + } while (i++ < TTM_NUM_MEM_TYPES); + + placement->num_busy_placement = placement->num_placement = cnt; + placement->busy_placement = heap->busy_placements; + placement->placement = heap->placements; + placement->fpfn = placement->lpfn = 0; +} + +int +ttm_bo_allocate(struct ttm_bo_device *bdev, + unsigned long size, + enum ttm_bo_type origin, + uint32_t domains, + uint32_t byte_align, + uint32_t page_align, + bool interruptible, + struct sg_table *sg, + struct file *persistant_swap_storage, + struct ttm_buffer_object **p_bo) +{ + unsigned long acc_size = sizeof(struct ttm_heap); + struct ttm_buffer_object *bo = NULL; + struct ttm_placement placement; + struct ttm_heap *heap; + int ret = -ENOMEM; + + size = round_up(size, byte_align); + size = ALIGN(size, page_align); + + heap = kzalloc(acc_size, GFP_KERNEL); + if (unlikely(!heap)) + return ret; + + bo = &heap->pbo; + + ttm_placement_from_domain(bo, &placement, domains, bdev); + + ret = ttm_bo_init(bdev, bo, size, origin, &placement, + page_align >> PAGE_SHIFT, + interruptible, persistant_swap_storage, + ttm_bo_dma_acc_size(bdev, size, acc_size), + sg, ttm_buffer_object_destroy); + if (unlikely(ret)) + kfree(heap); + else + *p_bo = bo; + return ret; +} + +int +ttm_bo_pin(struct ttm_buffer_object *bo, struct ttm_bo_kmap_obj *kmap) +{ + struct ttm_heap *heap = container_of(bo, struct ttm_heap, pbo); + struct ttm_placement placement; + int ret; + + ret = ttm_bo_reserve(bo, true, false, false, 0); + if (!ret) { + placement.placement = heap->placements; + placement.fpfn = placement.lpfn = 0; + placement.num_placement = 1; + + heap->placements[0] = (bo->mem.placement | TTM_PL_FLAG_NO_EVICT); + ret = ttm_bo_validate(bo, &placement, false, false); + if (!ret && kmap) + ret = ttm_bo_kmap(bo, 0, bo->num_pages, kmap); + ttm_bo_unreserve(bo); + } + return ret; +} + +int +ttm_bo_unpin(struct ttm_buffer_object *bo, struct ttm_bo_kmap_obj *kmap) +{ + struct ttm_heap *heap = container_of(bo, struct ttm_heap, pbo); + struct ttm_placement placement; + int ret; + + ret = ttm_bo_reserve(bo, true, false, false, 0); + if (!ret) { + if (kmap) + ttm_bo_kunmap(kmap); + + placement.placement = heap->placements; + placement.fpfn = placement.lpfn = 0; + placement.num_placement = 1; + + heap->placements[0] = (bo->mem.placement & ~TTM_PL_FLAG_NO_EVICT); + ret = ttm_bo_validate(bo, &placement, false, false); + ttm_bo_unreserve(bo); + } + return ret; +} + +int +ttm_allocate_kernel_buffer(struct ttm_bo_device *bdev, unsigned long size, + uint32_t alignment, uint32_t domain, + struct ttm_bo_kmap_obj *kmap) +{ + int ret = ttm_bo_allocate(bdev, size, ttm_bo_type_kernel, domain, + alignment, PAGE_SIZE, false, NULL, + NULL, &kmap->bo); + if (likely(!ret)) { + ret = ttm_bo_pin(kmap->bo, kmap); + if (unlikely(ret)) { + DRM_ERROR("failed to mmap the buffer\n"); + ttm_bo_unref(&kmap->bo); + kmap->bo = NULL; + } + } + return ret; +} diff --git a/drivers/gpu/drm/via/ttm_gem.c b/drivers/gpu/drm/via/ttm_gem.c new file mode 100644 index 0000000..4c30b8b --- /dev/null +++ b/drivers/gpu/drm/via/ttm_gem.c @@ -0,0 +1,94 @@ +/* + * Copyright 2012 James Simmons . 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 AUTHOR(S) OR COPYRIGHT HOLDER(S) 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. + */ +#include "drmP.h" +#include "via_drv.h" + +/* + * initialize the gem buffer object + */ +int ttm_gem_init_object(struct drm_gem_object *obj) +{ + return 0; +} + +/* + * free the gem buffer object + */ +void ttm_gem_free_object(struct drm_gem_object *obj) +{ + struct ttm_buffer_object *bo = obj->driver_private; + + if (bo) { + obj->driver_private = NULL; + ttm_bo_unref(&bo); + } + drm_gem_object_release(obj); + kfree(obj); +} + +/* + * file operation mmap + */ +int ttm_mmap(struct file *filp, struct vm_area_struct *vma) +{ + struct drm_via_private *dev_priv; + struct drm_file *file_priv; + + if (unlikely(vma->vm_pgoff < DRM_FILE_PAGE_OFFSET)) + return drm_mmap(filp, vma); + + file_priv = filp->private_data; + dev_priv = file_priv->minor->dev->dev_private; + if (!dev_priv) + return -EINVAL; + + return ttm_bo_mmap(filp, vma, &dev_priv->bdev); +} + +struct drm_gem_object * +ttm_gem_create(struct drm_device *dev, struct ttm_bo_device *bdev, int types, + bool interruptible, int byte_align, int page_align, + unsigned long size) +{ + struct ttm_buffer_object *bo = NULL; + struct drm_gem_object *obj; + int ret; + + size = round_up(size, byte_align); + size = ALIGN(size, page_align); + + obj = drm_gem_object_alloc(dev, size); + if (!obj) + return ERR_PTR(-ENOMEM); + + ret = ttm_bo_allocate(bdev, size, ttm_bo_type_device, types, + byte_align, page_align, interruptible, + NULL, obj->filp, &bo); + if (ret) { + DRM_ERROR("Failed to create buffer object\n"); + drm_gem_object_unreference_unlocked(obj); + return ERR_PTR(ret); + } + obj->driver_private = bo; + return obj; +}