1 /* $NetBSD: drm_dma.c,v 1.3 2021/12/18 23:44:57 riastradh Exp $ */ 2 3 /* 4 * \file drm_dma.c 5 * DMA IOCTL and function support 6 * 7 * \author Rickard E. (Rik) Faith <faith (at) valinux.com> 8 * \author Gareth Hughes <gareth (at) valinux.com> 9 */ 10 11 /* 12 * Created: Fri Mar 19 14:30:16 1999 by faith (at) valinux.com 13 * 14 * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas. 15 * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. 16 * All Rights Reserved. 17 * 18 * Permission is hereby granted, free of charge, to any person obtaining a 19 * copy of this software and associated documentation files (the "Software"), 20 * to deal in the Software without restriction, including without limitation 21 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 22 * and/or sell copies of the Software, and to permit persons to whom the 23 * Software is furnished to do so, subject to the following conditions: 24 * 25 * The above copyright notice and this permission notice (including the next 26 * paragraph) shall be included in all copies or substantial portions of the 27 * Software. 28 * 29 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 30 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 31 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 32 * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 33 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 34 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 35 * OTHER DEALINGS IN THE SOFTWARE. 36 */ 37 38 #include <sys/cdefs.h> 39 __KERNEL_RCSID(0, "$NetBSD: drm_dma.c,v 1.3 2021/12/18 23:44:57 riastradh Exp $"); 40 41 #include <linux/export.h> 42 43 #include <drm/drm_drv.h> 44 #include <drm/drm_pci.h> 45 #include <drm/drm_print.h> 46 47 #include "drm_legacy.h" 48 49 /** 50 * Initialize the DMA data. 51 * 52 * \param dev DRM device. 53 * \return zero on success or a negative value on failure. 54 * 55 * Allocate and initialize a drm_device_dma structure. 56 */ 57 int drm_legacy_dma_setup(struct drm_device *dev) 58 { 59 int i; 60 61 if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA) || 62 !drm_core_check_feature(dev, DRIVER_LEGACY)) 63 return 0; 64 65 dev->buf_use = 0; 66 atomic_set(&dev->buf_alloc, 0); 67 68 dev->dma = kzalloc(sizeof(*dev->dma), GFP_KERNEL); 69 if (!dev->dma) 70 return -ENOMEM; 71 72 for (i = 0; i <= DRM_MAX_ORDER; i++) 73 memset(&dev->dma->bufs[i], 0, sizeof(dev->dma->bufs[0])); 74 75 return 0; 76 } 77 78 /** 79 * Cleanup the DMA resources. 80 * 81 * \param dev DRM device. 82 * 83 * Free all pages associated with DMA buffers, the buffers and pages lists, and 84 * finally the drm_device::dma structure itself. 85 */ 86 void drm_legacy_dma_takedown(struct drm_device *dev) 87 { 88 struct drm_device_dma *dma = dev->dma; 89 int i, j; 90 91 if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA) || 92 !drm_core_check_feature(dev, DRIVER_LEGACY)) 93 return; 94 95 if (!dma) 96 return; 97 98 /* Clear dma buffers */ 99 for (i = 0; i <= DRM_MAX_ORDER; i++) { 100 if (dma->bufs[i].seg_count) { 101 DRM_DEBUG("order %d: buf_count = %d," 102 " seg_count = %d\n", 103 i, 104 dma->bufs[i].buf_count, 105 dma->bufs[i].seg_count); 106 for (j = 0; j < dma->bufs[i].seg_count; j++) { 107 if (dma->bufs[i].seglist[j]) { 108 drm_pci_free(dev, dma->bufs[i].seglist[j]); 109 } 110 } 111 kfree(dma->bufs[i].seglist); 112 } 113 if (dma->bufs[i].buf_count) { 114 for (j = 0; j < dma->bufs[i].buf_count; j++) { 115 kfree(dma->bufs[i].buflist[j].dev_private); 116 } 117 kfree(dma->bufs[i].buflist); 118 } 119 } 120 121 kfree(dma->buflist); 122 kfree(dma->pagelist); 123 kfree(dev->dma); 124 dev->dma = NULL; 125 } 126 127 /** 128 * Free a buffer. 129 * 130 * \param dev DRM device. 131 * \param buf buffer to free. 132 * 133 * Resets the fields of \p buf. 134 */ 135 void drm_legacy_free_buffer(struct drm_device *dev, struct drm_buf * buf) 136 { 137 if (!buf) 138 return; 139 140 buf->waiting = 0; 141 buf->pending = 0; 142 buf->file_priv = NULL; 143 buf->used = 0; 144 } 145 146 /** 147 * Reclaim the buffers. 148 * 149 * \param file_priv DRM file private. 150 * 151 * Frees each buffer associated with \p file_priv not already on the hardware. 152 */ 153 void drm_legacy_reclaim_buffers(struct drm_device *dev, 154 struct drm_file *file_priv) 155 { 156 struct drm_device_dma *dma = dev->dma; 157 int i; 158 159 if (!dma) 160 return; 161 for (i = 0; i < dma->buf_count; i++) { 162 if (dma->buflist[i]->file_priv == file_priv) { 163 switch (dma->buflist[i]->list) { 164 case DRM_LIST_NONE: 165 drm_legacy_free_buffer(dev, dma->buflist[i]); 166 break; 167 case DRM_LIST_WAIT: 168 dma->buflist[i]->list = DRM_LIST_RECLAIM; 169 break; 170 default: 171 /* Buffer already on hardware. */ 172 break; 173 } 174 } 175 } 176 } 177