xref: /titanic_50/usr/src/uts/intel/io/drm/i915_mem.c (revision 0bdffa0f07e70f45f6810116ca9d547631a4c3f8)
1ae115bc7Smrj /* BEGIN CSTYLED */
2ae115bc7Smrj 
3ae115bc7Smrj /* i915_mem.c -- Simple agp/fb memory manager for i915 -*- linux-c -*-
4ae115bc7Smrj  */
5e92e3a86Szw161486 /*
6ae115bc7Smrj  * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
7ae115bc7Smrj  * All Rights Reserved.
8ae115bc7Smrj  *
9ae115bc7Smrj  * Permission is hereby granted, free of charge, to any person obtaining a
10ae115bc7Smrj  * copy of this software and associated documentation files (the
11ae115bc7Smrj  * "Software"), to deal in the Software without restriction, including
12ae115bc7Smrj  * without limitation the rights to use, copy, modify, merge, publish,
13ae115bc7Smrj  * distribute, sub license, and/or sell copies of the Software, and to
14ae115bc7Smrj  * permit persons to whom the Software is furnished to do so, subject to
15ae115bc7Smrj  * the following conditions:
16ae115bc7Smrj  *
17ae115bc7Smrj  * The above copyright notice and this permission notice (including the
18ae115bc7Smrj  * next paragraph) shall be included in all copies or substantial portions
19ae115bc7Smrj  * of the Software.
20ae115bc7Smrj  *
21ae115bc7Smrj  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22ae115bc7Smrj  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23ae115bc7Smrj  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
24ae115bc7Smrj  * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
25ae115bc7Smrj  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
26ae115bc7Smrj  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
27ae115bc7Smrj  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28ae115bc7Smrj  *
29e92e3a86Szw161486  */
30e92e3a86Szw161486 
31e92e3a86Szw161486 /*
32d0538f66Scg149915  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
33e92e3a86Szw161486  * Use is subject to license terms.
34e92e3a86Szw161486  */
35ae115bc7Smrj 
36ae115bc7Smrj #pragma ident	"%Z%%M%	%I%	%E% SMI"
37ae115bc7Smrj 
38ae115bc7Smrj /* This memory manager is integrated into the global/local lru
39ae115bc7Smrj  * mechanisms used by the clients.  Specifically, it operates by
40ae115bc7Smrj  * setting the 'in_use' fields of the global LRU to indicate whether
41ae115bc7Smrj  * this region is privately allocated to a client.
42ae115bc7Smrj  *
43ae115bc7Smrj  * This does require the client to actually respect that field.
44ae115bc7Smrj  *
45ae115bc7Smrj  * Currently no effort is made to allocate 'private' memory in any
46ae115bc7Smrj  * clever way - the LRU information isn't used to determine which
47ae115bc7Smrj  * block to allocate, and the ring is drained prior to allocations --
48ae115bc7Smrj  * in other words allocation is expensive.
49ae115bc7Smrj  */
50ae115bc7Smrj 
51ae115bc7Smrj #include "drmP.h"
52ae115bc7Smrj #include "drm.h"
53ae115bc7Smrj #include "i915_drm.h"
54ae115bc7Smrj #include "i915_drv.h"
55ae115bc7Smrj 
mark_block(drm_device_t * dev,struct mem_block * p,int in_use)56ae115bc7Smrj void mark_block(drm_device_t * dev, struct mem_block *p, int in_use)
57ae115bc7Smrj {
58ae115bc7Smrj 	drm_i915_private_t *dev_priv = dev->dev_private;
59ae115bc7Smrj 	drm_i915_sarea_t *sarea_priv = dev_priv->sarea_priv;
60ae115bc7Smrj 	drm_tex_region_t *list;
61ae115bc7Smrj 	unsigned shift, nr;
62ae115bc7Smrj 	unsigned start;
63ae115bc7Smrj 	unsigned end;
64ae115bc7Smrj 	unsigned i;
65ae115bc7Smrj 	int age;
66ae115bc7Smrj 
67ae115bc7Smrj 	shift = dev_priv->tex_lru_log_granularity;
68ae115bc7Smrj 	nr = I915_NR_TEX_REGIONS;
69ae115bc7Smrj 
70ae115bc7Smrj 	start = p->start >> shift;
71ae115bc7Smrj 	end = (p->start + p->size - 1) >> shift;
72ae115bc7Smrj 
73ae115bc7Smrj 	age = ++sarea_priv->texAge;
74ae115bc7Smrj 	list = sarea_priv->texList;
75ae115bc7Smrj 
76ae115bc7Smrj 	/* Mark the regions with the new flag and update their age.  Move
77ae115bc7Smrj 	 * them to head of list to preserve LRU semantics.
78ae115bc7Smrj 	 */
79ae115bc7Smrj 	for (i = start; i <= end; i++) {
80*0bdffa0fShh224818 		list[i].in_use = (unsigned char)in_use;
81ae115bc7Smrj 		list[i].age = age;
82ae115bc7Smrj 
83ae115bc7Smrj 		/* remove_from_list(i)
84ae115bc7Smrj 		 */
85ae115bc7Smrj 		list[(unsigned)list[i].next].prev = list[i].prev;
86ae115bc7Smrj 		list[(unsigned)list[i].prev].next = list[i].next;
87ae115bc7Smrj 
88ae115bc7Smrj 		/* insert_at_head(list, i)
89ae115bc7Smrj 		 */
90*0bdffa0fShh224818 		list[i].prev = (unsigned char)nr;
91ae115bc7Smrj 		list[i].next = list[nr].next;
92*0bdffa0fShh224818 		list[(unsigned)list[nr].next].prev = (unsigned char)i;
93*0bdffa0fShh224818 		list[nr].next = (unsigned char)i;
94ae115bc7Smrj 	}
95ae115bc7Smrj }
96ae115bc7Smrj 
97ae115bc7Smrj /* Very simple allocator for agp memory, working on a static range
98ae115bc7Smrj  * already mapped into each client's address space.
99ae115bc7Smrj  */
100ae115bc7Smrj 
split_block(struct mem_block * p,int start,int size,drm_file_t * fpriv)101d0538f66Scg149915 static struct mem_block *split_block(struct mem_block *p, int start, int size, drm_file_t *fpriv)
102ae115bc7Smrj {
103ae115bc7Smrj 	/* Maybe cut off the start of an existing block */
104ae115bc7Smrj 	if (start > p->start) {
105ae115bc7Smrj 		struct mem_block *newblock =
106ae115bc7Smrj 		    drm_alloc(sizeof(*newblock), DRM_MEM_BUFLISTS);
107ae115bc7Smrj 		if (!newblock)
108ae115bc7Smrj 			goto out;
109ae115bc7Smrj 		newblock->start = start;
110ae115bc7Smrj 		newblock->size = p->size - (start - p->start);
111ae115bc7Smrj 		newblock->filp = NULL;
112ae115bc7Smrj 		newblock->next = p->next;
113ae115bc7Smrj 		newblock->prev = p;
114ae115bc7Smrj 		p->next->prev = newblock;
115ae115bc7Smrj 		p->next = newblock;
116ae115bc7Smrj 		p->size -= newblock->size;
117ae115bc7Smrj 		p = newblock;
118ae115bc7Smrj 	}
119ae115bc7Smrj 
120ae115bc7Smrj 	/* Maybe cut off the end of an existing block */
121ae115bc7Smrj 	if (size < p->size) {
122ae115bc7Smrj 		struct mem_block *newblock =
123ae115bc7Smrj 		    drm_alloc(sizeof(*newblock), DRM_MEM_BUFLISTS);
124ae115bc7Smrj 		if (!newblock)
125ae115bc7Smrj 			goto out;
126ae115bc7Smrj 		newblock->start = start + size;
127ae115bc7Smrj 		newblock->size = p->size - size;
128ae115bc7Smrj 		newblock->filp = NULL;
129ae115bc7Smrj 		newblock->next = p->next;
130ae115bc7Smrj 		newblock->prev = p;
131ae115bc7Smrj 		p->next->prev = newblock;
132ae115bc7Smrj 		p->next = newblock;
133ae115bc7Smrj 		p->size = size;
134ae115bc7Smrj 	}
135ae115bc7Smrj 
136ae115bc7Smrj       out:
137ae115bc7Smrj 	/* Our block is in the middle */
138d0538f66Scg149915 	p->filp = fpriv;
139ae115bc7Smrj 	return (p);
140ae115bc7Smrj }
141ae115bc7Smrj 
alloc_block(struct mem_block * heap,int size,int align2,drm_file_t * fpriv)142ae115bc7Smrj static struct mem_block *alloc_block(struct mem_block *heap, int size,
143d0538f66Scg149915 				     int align2, drm_file_t *fpriv)
144ae115bc7Smrj {
145ae115bc7Smrj 	struct mem_block *p;
146ae115bc7Smrj 	int mask = (1 << align2) - 1;
147ae115bc7Smrj 
148ae115bc7Smrj 	for (p = heap->next; p != heap; p = p->next) {
149ae115bc7Smrj 		int start = (p->start + mask) & ~mask;
150ae115bc7Smrj 		if (p->filp == NULL && start + size <= p->start + p->size)
151d0538f66Scg149915 			return split_block(p, start, size, fpriv);
152ae115bc7Smrj 	}
153ae115bc7Smrj 
154ae115bc7Smrj 	return NULL;
155ae115bc7Smrj }
156ae115bc7Smrj 
find_block(struct mem_block * heap,int start)157ae115bc7Smrj static struct mem_block *find_block(struct mem_block *heap, int start)
158ae115bc7Smrj {
159ae115bc7Smrj 	struct mem_block *p;
160ae115bc7Smrj 
161ae115bc7Smrj 	for (p = heap->next; p != heap; p = p->next)
162ae115bc7Smrj 		if (p->start == start)
163ae115bc7Smrj 			return (p);
164ae115bc7Smrj 
165ae115bc7Smrj 	return (NULL);
166ae115bc7Smrj }
167ae115bc7Smrj 
find_block_by_proc(struct mem_block * heap,drm_file_t * fpriv)168d0538f66Scg149915 struct mem_block *find_block_by_proc(struct mem_block *heap, drm_file_t *fpriv)
169ae115bc7Smrj {
170ae115bc7Smrj 	struct mem_block *p;
171ae115bc7Smrj 
172ae115bc7Smrj 	for (p = heap->next; p != heap; p = p->next)
173d0538f66Scg149915 		if (p->filp == fpriv)
174ae115bc7Smrj 			return (p);
175ae115bc7Smrj 
176ae115bc7Smrj 	return (NULL);
177ae115bc7Smrj }
178ae115bc7Smrj 
free_block(struct mem_block * p)179ae115bc7Smrj void free_block(struct mem_block *p)
180ae115bc7Smrj {
181ae115bc7Smrj 	p->filp = NULL;
182ae115bc7Smrj 
183ae115bc7Smrj 	/* Assumes a single contiguous range.  Needs a special filp in
184ae115bc7Smrj 	 * 'heap' to stop it being subsumed.
185ae115bc7Smrj 	 */
186ae115bc7Smrj 	if (p->next->filp == NULL) {
187ae115bc7Smrj 		struct mem_block *q = p->next;
188ae115bc7Smrj 		p->size += q->size;
189ae115bc7Smrj 		p->next = q->next;
190ae115bc7Smrj 		p->next->prev = p;
191ae115bc7Smrj 		drm_free(q, sizeof(*q), DRM_MEM_BUFLISTS);
192ae115bc7Smrj 	}
193ae115bc7Smrj 
194ae115bc7Smrj 	if (p->prev->filp == NULL) {
195ae115bc7Smrj 		struct mem_block *q = p->prev;
196ae115bc7Smrj 		q->size += p->size;
197ae115bc7Smrj 		q->next = p->next;
198ae115bc7Smrj 		q->next->prev = q;
199ae115bc7Smrj 		drm_free(p, sizeof(*q), DRM_MEM_BUFLISTS);
200ae115bc7Smrj 	}
201ae115bc7Smrj }
202ae115bc7Smrj 
203ae115bc7Smrj /* Initialize.  How to check for an uninitialized heap?
204ae115bc7Smrj  */
init_heap(struct mem_block ** heap,int start,int size)205ae115bc7Smrj static int init_heap(struct mem_block **heap, int start, int size)
206ae115bc7Smrj {
207ae115bc7Smrj 	struct mem_block *blocks = drm_alloc(sizeof(*blocks), DRM_MEM_BUFLISTS);
208ae115bc7Smrj 
209ae115bc7Smrj 	if (!blocks)
210d0538f66Scg149915 		return (ENOMEM);
211ae115bc7Smrj 
212ae115bc7Smrj 	*heap = drm_alloc(sizeof(**heap), DRM_MEM_BUFLISTS);
213ae115bc7Smrj 	if (!*heap) {
214ae115bc7Smrj 		drm_free(blocks, sizeof(*blocks), DRM_MEM_BUFLISTS);
215d0538f66Scg149915 		return (ENOMEM);
216ae115bc7Smrj 	}
217ae115bc7Smrj 
218ae115bc7Smrj 	blocks->start = start;
219ae115bc7Smrj 	blocks->size = size;
220ae115bc7Smrj 	blocks->filp = NULL;
221ae115bc7Smrj 	blocks->next = blocks->prev = *heap;
222ae115bc7Smrj 
223ae115bc7Smrj 	(void) memset(*heap, 0, sizeof(**heap));
224d0538f66Scg149915 	(*heap)->filp = (drm_file_t *) - 1;
225ae115bc7Smrj 	(*heap)->next = (*heap)->prev = blocks;
226ae115bc7Smrj 	return (0);
227ae115bc7Smrj }
228ae115bc7Smrj 
229ae115bc7Smrj /* Free all blocks associated with the releasing file.
230ae115bc7Smrj  */
i915_mem_release(drm_device_t * dev,drm_file_t * fpriv,struct mem_block * heap)231d0538f66Scg149915 void i915_mem_release(drm_device_t * dev, drm_file_t *fpriv, struct mem_block *heap)
232ae115bc7Smrj {
233ae115bc7Smrj 	struct mem_block *p;
234ae115bc7Smrj 
235ae115bc7Smrj 	if (!heap || !heap->next)
236ae115bc7Smrj 		return;
237ae115bc7Smrj 
238ae115bc7Smrj 	for (p = heap->next; p != heap; p = p->next) {
239d0538f66Scg149915 		if (p->filp == fpriv) {
240ae115bc7Smrj 			p->filp = NULL;
241ae115bc7Smrj 			mark_block(dev, p, 0);
242ae115bc7Smrj 		}
243ae115bc7Smrj 	}
244ae115bc7Smrj 
245ae115bc7Smrj 	/* Assumes a single contiguous range.  Needs a special filp in
246ae115bc7Smrj 	 * 'heap' to stop it being subsumed.
247ae115bc7Smrj 	 */
248ae115bc7Smrj 	for (p = heap->next; p != heap; p = p->next) {
249ae115bc7Smrj 		while (p->filp == NULL && p->next->filp == NULL) {
250ae115bc7Smrj 			struct mem_block *q = p->next;
251ae115bc7Smrj 			p->size += q->size;
252ae115bc7Smrj 			p->next = q->next;
253ae115bc7Smrj 			p->next->prev = p;
254ae115bc7Smrj 			drm_free(q, sizeof(*q), DRM_MEM_BUFLISTS);
255ae115bc7Smrj 		}
256ae115bc7Smrj 	}
257ae115bc7Smrj }
258ae115bc7Smrj 
259ae115bc7Smrj /* Shutdown.
260ae115bc7Smrj  */
i915_mem_takedown(struct mem_block ** heap)261ae115bc7Smrj void i915_mem_takedown(struct mem_block **heap)
262ae115bc7Smrj {
263ae115bc7Smrj 	struct mem_block *p;
264ae115bc7Smrj 
265ae115bc7Smrj 	if (!*heap)
266ae115bc7Smrj 		return;
267ae115bc7Smrj 
268ae115bc7Smrj 	for (p = (*heap)->next; p != *heap;) {
269ae115bc7Smrj 		struct mem_block *q = p;
270ae115bc7Smrj 		p = p->next;
271ae115bc7Smrj 		drm_free(q, sizeof(*q), DRM_MEM_BUFLISTS);
272ae115bc7Smrj 	}
273ae115bc7Smrj 
274ae115bc7Smrj 	drm_free(*heap, sizeof(**heap), DRM_MEM_BUFLISTS);
275ae115bc7Smrj 	*heap = NULL;
276ae115bc7Smrj }
277ae115bc7Smrj 
get_heap(drm_i915_private_t * dev_priv,int region)278ae115bc7Smrj struct mem_block **get_heap(drm_i915_private_t * dev_priv, int region)
279ae115bc7Smrj {
280ae115bc7Smrj 	switch (region) {
281ae115bc7Smrj 	case I915_MEM_REGION_AGP:
282ae115bc7Smrj 		return (&dev_priv->agp_heap);
283ae115bc7Smrj 	default:
284ae115bc7Smrj 		return (NULL);
285ae115bc7Smrj 	}
286ae115bc7Smrj }
287ae115bc7Smrj 
288ae115bc7Smrj /* IOCTL HANDLERS */
289ae115bc7Smrj 
290ae115bc7Smrj /*ARGSUSED*/
i915_mem_alloc(DRM_IOCTL_ARGS)291ae115bc7Smrj int i915_mem_alloc(DRM_IOCTL_ARGS)
292ae115bc7Smrj {
293ae115bc7Smrj 	DRM_DEVICE;
294ae115bc7Smrj 	drm_i915_private_t *dev_priv = dev->dev_private;
295ae115bc7Smrj 	drm_i915_mem_alloc_t alloc;
296ae115bc7Smrj 	struct mem_block *block, **heap;
297ae115bc7Smrj 
298ae115bc7Smrj 	if (!dev_priv) {
299ae115bc7Smrj 		DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
300d0538f66Scg149915 		return (EINVAL);
301ae115bc7Smrj 	}
302ae115bc7Smrj 
303ae115bc7Smrj 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
304ae115bc7Smrj 		drm_i915_mem_alloc32_t	alloc32;
305ae115bc7Smrj 
306d0538f66Scg149915 		DRM_COPYFROM_WITH_RETURN(&alloc32, (void *)data, sizeof (alloc32));
307ae115bc7Smrj 		alloc.region = alloc32.region;
308ae115bc7Smrj 		alloc.alignment = alloc32.alignment;
309ae115bc7Smrj 		alloc.size = alloc32.size;
310d0538f66Scg149915 		alloc.region_offset = (int *)(uintptr_t)alloc32.region_offset;
311ae115bc7Smrj 	} else
312d0538f66Scg149915 		DRM_COPYFROM_WITH_RETURN(&alloc, (void *) data, sizeof(alloc));
313ae115bc7Smrj 
314ae115bc7Smrj 	heap = get_heap(dev_priv, alloc.region);
315ae115bc7Smrj 	if (!heap || !*heap)
316d0538f66Scg149915 		return (EFAULT);
317ae115bc7Smrj 
318ae115bc7Smrj 	/* Make things easier on ourselves: all allocations at least
319ae115bc7Smrj 	 * 4k aligned.
320ae115bc7Smrj 	 */
321ae115bc7Smrj 	if (alloc.alignment < 12)
322ae115bc7Smrj 		alloc.alignment = 12;
323ae115bc7Smrj 
324d0538f66Scg149915 	block = alloc_block(*heap, alloc.size, alloc.alignment, fpriv);
325ae115bc7Smrj 
326ae115bc7Smrj 	if (!block)
327d0538f66Scg149915 		return (ENOMEM);
328ae115bc7Smrj 
329ae115bc7Smrj 	mark_block(dev, block, 1);
330ae115bc7Smrj 
331ae115bc7Smrj 	if (DRM_COPY_TO_USER(alloc.region_offset, &block->start, sizeof(int))) {
332ae115bc7Smrj 		DRM_ERROR("copy_to_user\n");
333d0538f66Scg149915 		return (EFAULT);
334ae115bc7Smrj 	}
335ae115bc7Smrj 
336ae115bc7Smrj 	return (0);
337ae115bc7Smrj }
338ae115bc7Smrj 
339ae115bc7Smrj /*ARGSUSED*/
i915_mem_free(DRM_IOCTL_ARGS)340ae115bc7Smrj int i915_mem_free(DRM_IOCTL_ARGS)
341ae115bc7Smrj {
342ae115bc7Smrj 	DRM_DEVICE;
343ae115bc7Smrj 	drm_i915_private_t *dev_priv = dev->dev_private;
344ae115bc7Smrj 	drm_i915_mem_free_t memfree;
345ae115bc7Smrj 	struct mem_block *block, **heap;
346ae115bc7Smrj 
347ae115bc7Smrj 	if (!dev_priv) {
348ae115bc7Smrj 		DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
349d0538f66Scg149915 		return (EINVAL);
350ae115bc7Smrj 	}
351ae115bc7Smrj 
352d0538f66Scg149915 	DRM_COPYFROM_WITH_RETURN(&memfree, (void *)data, sizeof(memfree));
353ae115bc7Smrj 
354ae115bc7Smrj 	heap = get_heap(dev_priv, memfree.region);
355ae115bc7Smrj 	if (!heap || !*heap)
356d0538f66Scg149915 		return (EFAULT);
357ae115bc7Smrj 
358ae115bc7Smrj 	block = find_block(*heap, memfree.region_offset);
359ae115bc7Smrj 	if (!block)
360d0538f66Scg149915 		return (EFAULT);
361ae115bc7Smrj 
362d0538f66Scg149915 	if (block->filp != fpriv)
363d0538f66Scg149915 		return (EPERM);
364ae115bc7Smrj 
365ae115bc7Smrj 	mark_block(dev, block, 0);
366ae115bc7Smrj 	free_block(block);
367ae115bc7Smrj 	return (0);
368ae115bc7Smrj }
369ae115bc7Smrj 
370ae115bc7Smrj /*ARGSUSED*/
i915_mem_init_heap(DRM_IOCTL_ARGS)371ae115bc7Smrj int i915_mem_init_heap(DRM_IOCTL_ARGS)
372ae115bc7Smrj {
373ae115bc7Smrj 	DRM_DEVICE;
374ae115bc7Smrj 	drm_i915_private_t *dev_priv = dev->dev_private;
375ae115bc7Smrj 	drm_i915_mem_init_heap_t initheap;
376ae115bc7Smrj 	struct mem_block **heap;
377ae115bc7Smrj 
378ae115bc7Smrj 	if (!dev_priv) {
379ae115bc7Smrj 		DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
380d0538f66Scg149915 		return (EINVAL);
381ae115bc7Smrj 	}
382ae115bc7Smrj 
383d0538f66Scg149915 	DRM_COPYFROM_WITH_RETURN(&initheap, (void *)data, sizeof(initheap));
384ae115bc7Smrj 
385ae115bc7Smrj 	heap = get_heap(dev_priv, initheap.region);
386ae115bc7Smrj 	if (!heap)
387d0538f66Scg149915 		return (EFAULT);
388ae115bc7Smrj 
389ae115bc7Smrj 	if (*heap) {
390ae115bc7Smrj 		DRM_ERROR("heap already initialized?");
391d0538f66Scg149915 		return (EFAULT);
392ae115bc7Smrj 	}
393ae115bc7Smrj 
394ae115bc7Smrj 	return init_heap(heap, initheap.start, initheap.size);
395ae115bc7Smrj }
396e92e3a86Szw161486 
397e92e3a86Szw161486 /*ARGSUSED*/
i915_mem_destroy_heap(DRM_IOCTL_ARGS)398e92e3a86Szw161486 int i915_mem_destroy_heap(DRM_IOCTL_ARGS)
399e92e3a86Szw161486 {
400e92e3a86Szw161486 	DRM_DEVICE;
401e92e3a86Szw161486 	drm_i915_private_t *dev_priv = dev->dev_private;
402e92e3a86Szw161486 	drm_i915_mem_destroy_heap_t destroyheap;
403e92e3a86Szw161486 	struct mem_block **heap;
404e92e3a86Szw161486 
405e92e3a86Szw161486 	if (!dev_priv) {
406e92e3a86Szw161486 		DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
407d0538f66Scg149915 		return (EINVAL);
408e92e3a86Szw161486 	}
409e92e3a86Szw161486 
410d0538f66Scg149915 	DRM_COPYFROM_WITH_RETURN(&destroyheap, (void *)data, sizeof(destroyheap));
411e92e3a86Szw161486 
412e92e3a86Szw161486 	heap = get_heap(dev_priv, destroyheap.region);
413e92e3a86Szw161486 	if (!heap) {
414e92e3a86Szw161486 		DRM_ERROR("get_heap failed");
415d0538f66Scg149915 		return (EFAULT);
416e92e3a86Szw161486 	}
417e92e3a86Szw161486 
418e92e3a86Szw161486 	if (!*heap) {
419e92e3a86Szw161486 		DRM_ERROR("heap not initialized?");
420d0538f66Scg149915 		return (EFAULT);
421e92e3a86Szw161486 	}
422e92e3a86Szw161486 
423e92e3a86Szw161486 	i915_mem_takedown(heap);
424e92e3a86Szw161486 	return (0);
425e92e3a86Szw161486 }
426