xref: /openbsd-src/sys/dev/pci/drm/drm_scatter.c (revision 43003dfe3ad45d1698bed8a37f2b0f5b14f20d4f)
1 /*-
2  * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
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, sublicense,
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 next
13  * paragraph) shall be included in all copies or substantial portions of the
14  * 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 NONINFRINGEMENT.  IN NO EVENT SHALL
19  * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20  * 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  * Authors:
25  *   Gareth Hughes <gareth@valinux.com>
26  *   Eric Anholt <anholt@FreeBSD.org>
27  *
28  */
29 
30 /*
31  * Allocation of memory for scatter-gather mappings by the graphics chip.
32  *
33  * The memory allocated here is then made into an aperture in the card
34  * by drm_ati_pcigart_init().
35  */
36 #include "drmP.h"
37 
38 void
39 drm_sg_cleanup(struct drm_device *dev, struct drm_sg_mem *entry)
40 {
41 	if (entry == NULL)
42 		return;
43 
44 	drm_dmamem_free(dev->dmat, entry->mem);
45 	drm_free(entry);
46 }
47 
48 int
49 drm_sg_alloc(struct drm_device * dev, struct drm_scatter_gather *request)
50 {
51 	struct drm_sg_mem	*entry;
52 	bus_size_t		 size;
53 	unsigned long		 pages;
54 
55 	if (dev->sg != NULL)
56 		return (EINVAL);
57 
58 	entry = drm_calloc(1, sizeof(*entry));
59         if (entry == NULL)
60                 return (ENOMEM);
61 
62 	pages = round_page(request->size) / PAGE_SIZE;
63 	size = pages << PAGE_SHIFT;
64 
65 	DRM_DEBUG("sg size=%ld pages=%ld\n", request->size, pages);
66 
67 	if ((entry->mem = drm_dmamem_alloc(dev->dmat, size, PAGE_SIZE, pages,
68 	    PAGE_SIZE, 0, 0)) == NULL)
69 		return (ENOMEM);
70 
71 	request->handle = entry->handle = (unsigned long)entry->mem->kva;
72 	DRM_DEBUG("sg alloc handle  = %08lx\n", entry->handle);
73 
74 	DRM_LOCK();
75 	if (dev->sg) {
76 		DRM_UNLOCK();
77 		drm_sg_cleanup(dev, entry);
78 		return EINVAL;
79 	}
80 	dev->sg = entry;
81 	DRM_UNLOCK();
82 
83 	return (0);
84 }
85 
86 int
87 drm_sg_alloc_ioctl(struct drm_device *dev, void *data,
88     struct drm_file *file_priv)
89 {
90 	struct drm_scatter_gather	*request = data;
91 	int				 ret;
92 
93 	DRM_DEBUG("\n");
94 
95 	ret = drm_sg_alloc(dev, request);
96 	return ret;
97 }
98 
99 int
100 drm_sg_free(struct drm_device *dev, void *data, struct drm_file *file_priv)
101 {
102 	struct drm_scatter_gather	*request = data;
103 	struct drm_sg_mem		*entry;
104 
105 	DRM_LOCK();
106 	entry = dev->sg;
107 	dev->sg = NULL;
108 	DRM_UNLOCK();
109 
110 	if (entry == NULL || entry->handle != request->handle)
111 		return EINVAL;
112 
113 	DRM_DEBUG("sg free virtual  = 0x%lx\n", entry->handle);
114 
115 	drm_sg_cleanup(dev, entry);
116 
117 	return 0;
118 }
119