xref: /titanic_41/usr/src/uts/common/io/drm/drm_scatter.c (revision dd49f125507979bb2ab505a8daf2a46d1be27051)
1 /*
2  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 /* BEGIN CSTYLED */
7 
8 /* drm_scatter.h -- IOCTLs to manage scatter/gather memory -*- linux-c -*-
9  * Created: Mon Dec 18 23:20:54 2000 by gareth@valinux.com */
10 /*-
11  * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
12  * All Rights Reserved.
13  *
14  * Permission is hereby granted, free of charge, to any person obtaining a
15  * copy of this software and associated documentation files (the "Software"),
16  * to deal in the Software without restriction, including without limitation
17  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
18  * and/or sell copies of the Software, and to permit persons to whom the
19  * Software is furnished to do so, subject to the following conditions:
20  *
21  * The above copyright notice and this permission notice (including the next
22  * paragraph) shall be included in all copies or substantial portions of the
23  * Software.
24  *
25  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
28  * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
29  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
30  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
31  * DEALINGS IN THE SOFTWARE.
32  *
33  * Authors:
34  *   Gareth Hughes <gareth@valinux.com>
35  *   Eric Anholt <anholt@FreeBSD.org>
36  *
37  */
38 /* END CSTYLED */
39 
40 #pragma ident	"%Z%%M%	%I%	%E% SMI"
41 
42 #include "drmP.h"
43 #include <gfx_private.h>
44 #include "drm_io32.h"
45 
46 #define	DEBUG_SCATTER 0
47 
48 #ifdef	_LP64
49 #define	ScatterHandle(x) (unsigned int)((x >> 32) + (x & ((1L << 32) - 1)))
50 #else
51 #define	ScatterHandle(x) (unsigned int)(x)
52 #endif
53 
54 void
55 drm_sg_cleanup(drm_device_t *dev, drm_sg_mem_t *entry)
56 {
57 	int	pages = entry->pages;
58 
59 	if (entry->busaddr) {
60 		kmem_free(entry->busaddr, sizeof (*entry->busaddr) * pages);
61 		entry->busaddr = NULL;
62 	}
63 
64 	ASSERT(entry->umem_cookie == NULL);
65 
66 	if (entry->dmah_sg) {
67 		drm_pci_free(dev, entry->dmah_sg);
68 		entry->dmah_sg = NULL;
69 	}
70 
71 	if (entry->dmah_gart) {
72 		drm_pci_free(dev, entry->dmah_gart);
73 		entry->dmah_gart = NULL;
74 	}
75 
76 	if (entry) {
77 		drm_free(entry, sizeof (drm_sg_mem_t), DRM_MEM_SGLISTS);
78 		entry = NULL;
79 	}
80 }
81 
82 /*ARGSUSED*/
83 int
84 drm_sg_alloc(DRM_IOCTL_ARGS)
85 {
86 	DRM_DEVICE;
87 	unsigned long pages;
88 	drm_sg_mem_t		*entry;
89 	drm_dma_handle_t	*dmah;
90 	drm_scatter_gather_t request;
91 
92 	DRM_DEBUG("%s\n", "drm_sg_alloc");
93 
94 	if (dev->sg)
95 		return (EINVAL);
96 
97 #ifdef	_MULTI_DATAMODEL
98 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
99 		drm_scatter_gather_32_t request32;
100 
101 		DRM_COPYFROM_WITH_RETURN(&request32, (void *)data,
102 		    sizeof (request32));
103 		request.size = request32.size;
104 		request.handle = request32.handle;
105 	} else
106 #endif
107 		DRM_COPYFROM_WITH_RETURN(&request, (void *)data,
108 		    sizeof (request));
109 
110 	pages = btopr(request.size);
111 	DRM_DEBUG("sg size=%ld pages=%ld\n", request.size, pages);
112 	entry = kmem_zalloc(sizeof (*entry), KM_SLEEP);
113 	entry->pages = (int)pages;
114 	dmah = drm_pci_alloc(dev, ptob(pages), 4096, 0xfffffffful, pages);
115 	if (dmah == NULL)
116 		goto err_exit;
117 	entry->busaddr = (void *)kmem_zalloc(sizeof (*entry->busaddr) *
118 	    pages, KM_SLEEP);
119 
120 	entry->handle = ScatterHandle((unsigned long)dmah->vaddr);
121 	entry->virtual = (void *)dmah->vaddr;
122 	request.handle = entry->handle;
123 	entry->dmah_sg = dmah;
124 #ifdef	_MULTI_DATAMODEL
125 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
126 		drm_scatter_gather_32_t data32;
127 
128 		data32.size = (uint32_t)request.size;
129 		data32.handle = (uint32_t)request.handle;
130 
131 		DRM_COPYTO_WITH_RETURN((void *)data, &data32,
132 		    sizeof (data32));
133 	} else
134 #endif
135 		DRM_COPYTO_WITH_RETURN((void *)data, &request,
136 		    sizeof (request));
137 
138 	DRM_LOCK();
139 	if (dev->sg) {
140 		DRM_UNLOCK();
141 		drm_sg_cleanup(dev, entry);
142 		return (EINVAL);
143 	}
144 	dev->sg = entry;
145 	DRM_UNLOCK();
146 
147 	return (0);
148 
149 err_exit:
150 	drm_sg_cleanup(dev, entry);
151 	return (ENOMEM);
152 }
153 
154 /*ARGSUSED*/
155 int
156 drm_sg_free(DRM_IOCTL_ARGS)
157 {
158 	DRM_DEVICE;
159 	drm_scatter_gather_t request;
160 	drm_sg_mem_t *entry;
161 
162 #ifdef	_MULTI_DATAMODEL
163 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
164 		drm_scatter_gather_32_t request32;
165 
166 		DRM_COPYFROM_WITH_RETURN(&request32, (void *)data,
167 		    sizeof (request32));
168 		request.size = request32.size;
169 		request.handle = request32.handle;
170 	} else
171 #endif
172 		DRM_COPYFROM_WITH_RETURN(&request, (void *)data,
173 		    sizeof (request));
174 
175 	DRM_LOCK();
176 	entry = dev->sg;
177 	dev->sg = NULL;
178 	DRM_UNLOCK();
179 
180 	if (!entry || entry->handle != request.handle)
181 		return (EINVAL);
182 
183 	drm_sg_cleanup(dev, entry);
184 
185 	return (0);
186 }
187