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