1/*- 2 * Copyright 2006 Tungsten Graphics Inc., Bismarck, ND., USA. 3 * All rights reserved. 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the "Software"), 7 * to deal in the Software without restriction, including without limitation 8 * the rights to use, copy, modify, merge, publish, distribute, sub license, 9 * and/or sell copies of the Software, and to permit persons to whom the 10 * Software is furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice (including the 13 * next paragraph) shall be included in all copies or substantial portions 14 * of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS OR COPYRIGHT HOLDERS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, 20 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 22 * DEALINGS IN THE SOFTWARE. 23 */ 24 25/* 26 * Authors: Thomas Hellström <thomas-at-tungstengraphics-dot-com> 27 */ 28 29#include <sys/cdefs.h> 30__FBSDID("$FreeBSD$"); 31 32#include "dev/drm/drmP.h" 33#include "dev/drm/via_drm.h" 34#include "dev/drm/via_drv.h" 35#include "dev/drm/drm_sman.h" 36 37#define VIA_MM_ALIGN_SHIFT 4 38#define VIA_MM_ALIGN_MASK ( (1 << VIA_MM_ALIGN_SHIFT) - 1) 39 40int via_agp_init(struct drm_device *dev, void *data, struct drm_file *file_priv) 41{ 42 drm_via_agp_t *agp = data; 43 drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; 44 int ret; 45 46 ret = drm_sman_set_range(&dev_priv->sman, VIA_MEM_AGP, 0, 47 agp->size >> VIA_MM_ALIGN_SHIFT); 48 if (ret) { 49 DRM_ERROR("AGP memory manager initialisation error\n"); 50 return ret; 51 } 52 53 dev_priv->agp_initialized = 1; 54 dev_priv->agp_offset = agp->offset; 55 56 DRM_DEBUG("offset = %u, size = %u\n", agp->offset, agp->size); 57 return 0; 58} 59 60int via_fb_init(struct drm_device *dev, void *data, struct drm_file *file_priv) 61{ 62 drm_via_fb_t *fb = data; 63 drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; 64 int ret; 65 66 ret = drm_sman_set_range(&dev_priv->sman, VIA_MEM_VIDEO, 0, 67 fb->size >> VIA_MM_ALIGN_SHIFT); 68 if (ret) { 69 DRM_ERROR("VRAM memory manager initialisation error\n"); 70 return ret; 71 } 72 73 dev_priv->vram_initialized = 1; 74 dev_priv->vram_offset = fb->offset; 75 76 DRM_DEBUG("offset = %u, size = %u\n", fb->offset, fb->size); 77 78 return 0; 79 80} 81 82int via_final_context(struct drm_device *dev, int context) 83{ 84 drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; 85 86 via_release_futex(dev_priv, context); 87 88#ifdef __linux__ 89 /* Linux specific until context tracking code gets ported to BSD */ 90 /* Last context, perform cleanup */ 91 if (dev->ctx_count == 1 && dev->dev_private) { 92 DRM_DEBUG("Last Context\n"); 93 drm_irq_uninstall(dev); 94 via_cleanup_futex(dev_priv); 95 via_do_cleanup_map(dev); 96 } 97#endif 98 return 1; 99} 100 101void via_lastclose(struct drm_device *dev) 102{ 103 drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; 104 105 if (!dev_priv) 106 return; 107 108 drm_sman_cleanup(&dev_priv->sman); 109 dev_priv->vram_initialized = 0; 110 dev_priv->agp_initialized = 0; 111} 112 113int via_mem_alloc(struct drm_device *dev, void *data, 114 struct drm_file *file_priv) 115{ 116 drm_via_mem_t *mem = data; 117 int retval = 0; 118 struct drm_memblock_item *item; 119 drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; 120 unsigned long tmpSize; 121 122 if (mem->type > VIA_MEM_AGP) { 123 DRM_ERROR("Unknown memory type allocation\n"); 124 return -EINVAL; 125 } 126 if (0 == ((mem->type == VIA_MEM_VIDEO) ? dev_priv->vram_initialized : 127 dev_priv->agp_initialized)) { 128 DRM_ERROR 129 ("Attempt to allocate from uninitialized memory manager.\n"); 130 return -EINVAL; 131 } 132 133 tmpSize = (mem->size + VIA_MM_ALIGN_MASK) >> VIA_MM_ALIGN_SHIFT; 134 item = drm_sman_alloc(&dev_priv->sman, mem->type, tmpSize, 0, 135 (unsigned long)file_priv); 136 if (item) { 137 mem->offset = ((mem->type == VIA_MEM_VIDEO) ? 138 dev_priv->vram_offset : dev_priv->agp_offset) + 139 (item->mm-> 140 offset(item->mm, item->mm_info) << VIA_MM_ALIGN_SHIFT); 141 mem->index = item->user_hash.key; 142 } else { 143 mem->offset = 0; 144 mem->size = 0; 145 mem->index = 0; 146 DRM_DEBUG("Video memory allocation failed\n"); 147 retval = -ENOMEM; 148 } 149 150 return retval; 151} 152 153int via_mem_free(struct drm_device *dev, void *data, struct drm_file *file_priv) 154{ 155 drm_via_private_t *dev_priv = dev->dev_private; 156 drm_via_mem_t *mem = data; 157 int ret; 158 159 ret = drm_sman_free_key(&dev_priv->sman, mem->index); 160 DRM_DEBUG("free = 0x%lx\n", mem->index); 161 162 return ret; 163} 164 165 166void via_reclaim_buffers_locked(struct drm_device * dev, 167 struct drm_file *file_priv) 168{ 169 drm_via_private_t *dev_priv = dev->dev_private; 170 171 if (drm_sman_owner_clean(&dev_priv->sman, (unsigned long)file_priv)) 172 return; 173 174 if (dev->driver->dma_quiescent) 175 dev->driver->dma_quiescent(dev); 176 177 drm_sman_owner_cleanup(&dev_priv->sman, (unsigned long)file_priv); 178 179 return; 180} 181