xref: /freebsd-src/sys/dev/drm2/drm_scatter.c (revision 685dc743dc3b5645e34836464128e1c0558b404b)
1592ffb21SWarner Losh /*-
2592ffb21SWarner Losh  * Copyright (c) 2009 Robert C. Noland III <rnoland@FreeBSD.org>
3592ffb21SWarner Losh  * All Rights Reserved.
4592ffb21SWarner Losh  *
5592ffb21SWarner Losh  * Permission is hereby granted, free of charge, to any person obtaining a
6592ffb21SWarner Losh  * copy of this software and associated documentation files (the "Software"),
7592ffb21SWarner Losh  * to deal in the Software without restriction, including without limitation
8592ffb21SWarner Losh  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9592ffb21SWarner Losh  * and/or sell copies of the Software, and to permit persons to whom the
10592ffb21SWarner Losh  * Software is furnished to do so, subject to the following conditions:
11592ffb21SWarner Losh  *
12592ffb21SWarner Losh  * The above copyright notice and this permission notice (including the next
13592ffb21SWarner Losh  * paragraph) shall be included in all copies or substantial portions of the
14592ffb21SWarner Losh  * Software.
15592ffb21SWarner Losh  *
16592ffb21SWarner Losh  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17592ffb21SWarner Losh  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18592ffb21SWarner Losh  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19592ffb21SWarner Losh  * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20592ffb21SWarner Losh  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21592ffb21SWarner Losh  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22592ffb21SWarner Losh  * DEALINGS IN THE SOFTWARE.
23592ffb21SWarner Losh  */
24592ffb21SWarner Losh 
25592ffb21SWarner Losh #include <sys/cdefs.h>
26592ffb21SWarner Losh /** @file drm_scatter.c
27592ffb21SWarner Losh  * Allocation of memory for scatter-gather mappings by the graphics chip.
28592ffb21SWarner Losh  * The memory allocated here is then made into an aperture in the card
29592ffb21SWarner Losh  * by mapping the pages into the GART.
30592ffb21SWarner Losh  */
31592ffb21SWarner Losh 
32592ffb21SWarner Losh #include <dev/drm2/drmP.h>
33592ffb21SWarner Losh 
34592ffb21SWarner Losh #define DEBUG_SCATTER 0
35592ffb21SWarner Losh 
drm_vmalloc_dma(vm_size_t size)36*f49fd63aSJohn Baldwin static inline void *drm_vmalloc_dma(vm_size_t size)
37592ffb21SWarner Losh {
38592ffb21SWarner Losh 	return kmem_alloc_attr(size, M_NOWAIT | M_ZERO, 0,
39592ffb21SWarner Losh 	    BUS_SPACE_MAXADDR_32BIT, VM_MEMATTR_WRITE_COMBINING);
40592ffb21SWarner Losh }
41592ffb21SWarner Losh 
drm_sg_cleanup(struct drm_sg_mem * entry)42592ffb21SWarner Losh void drm_sg_cleanup(struct drm_sg_mem * entry)
43592ffb21SWarner Losh {
44592ffb21SWarner Losh 	if (entry == NULL)
45592ffb21SWarner Losh 		return;
46592ffb21SWarner Losh 
47*f49fd63aSJohn Baldwin 	if (entry->vaddr != NULL)
4849bfa624SAlan Cox 		kmem_free(entry->vaddr, IDX_TO_OFF(entry->pages));
49592ffb21SWarner Losh 
50592ffb21SWarner Losh 	free(entry->busaddr, DRM_MEM_SGLISTS);
51592ffb21SWarner Losh 	free(entry, DRM_MEM_DRIVER);
52592ffb21SWarner Losh }
53592ffb21SWarner Losh 
drm_sg_alloc(struct drm_device * dev,struct drm_scatter_gather * request)54592ffb21SWarner Losh int drm_sg_alloc(struct drm_device *dev, struct drm_scatter_gather * request)
55592ffb21SWarner Losh {
56592ffb21SWarner Losh 	struct drm_sg_mem *entry;
57592ffb21SWarner Losh 	vm_size_t size;
58592ffb21SWarner Losh 	vm_pindex_t pindex;
59592ffb21SWarner Losh 
60592ffb21SWarner Losh 	DRM_DEBUG("\n");
61592ffb21SWarner Losh 
62592ffb21SWarner Losh 	if (!drm_core_check_feature(dev, DRIVER_SG))
63592ffb21SWarner Losh 		return -EINVAL;
64592ffb21SWarner Losh 
65592ffb21SWarner Losh 	if (dev->sg)
66592ffb21SWarner Losh 		return -EINVAL;
67592ffb21SWarner Losh 
68592ffb21SWarner Losh 	entry = malloc(sizeof(*entry), DRM_MEM_DRIVER, M_NOWAIT | M_ZERO);
69592ffb21SWarner Losh 	if (!entry)
70592ffb21SWarner Losh 		return -ENOMEM;
71592ffb21SWarner Losh 
72592ffb21SWarner Losh 	DRM_DEBUG("request size=%ld\n", request->size);
73592ffb21SWarner Losh 
74592ffb21SWarner Losh 	size = round_page(request->size);
75592ffb21SWarner Losh 	entry->pages = atop(size);
76592ffb21SWarner Losh 	entry->busaddr = malloc(entry->pages * sizeof(*entry->busaddr),
77592ffb21SWarner Losh 	    DRM_MEM_SGLISTS, M_NOWAIT | M_ZERO);
78592ffb21SWarner Losh 	if (!entry->busaddr) {
79592ffb21SWarner Losh 		free(entry, DRM_MEM_DRIVER);
80592ffb21SWarner Losh 		return -ENOMEM;
81592ffb21SWarner Losh 	}
82592ffb21SWarner Losh 
83592ffb21SWarner Losh 	entry->vaddr = drm_vmalloc_dma(size);
84*f49fd63aSJohn Baldwin 	if (entry->vaddr == NULL) {
85592ffb21SWarner Losh 		free(entry->busaddr, DRM_MEM_DRIVER);
86592ffb21SWarner Losh 		free(entry, DRM_MEM_DRIVER);
87592ffb21SWarner Losh 		return -ENOMEM;
88592ffb21SWarner Losh 	}
89592ffb21SWarner Losh 
90592ffb21SWarner Losh 	for (pindex = 0; pindex < entry->pages; pindex++) {
91592ffb21SWarner Losh 		entry->busaddr[pindex] =
92*f49fd63aSJohn Baldwin 		    vtophys((uintptr_t)entry->vaddr + IDX_TO_OFF(pindex));
93592ffb21SWarner Losh 	}
94592ffb21SWarner Losh 
95*f49fd63aSJohn Baldwin 	request->handle = (uintptr_t)entry->vaddr;
96592ffb21SWarner Losh 
97592ffb21SWarner Losh 	dev->sg = entry;
98592ffb21SWarner Losh 
99*f49fd63aSJohn Baldwin 	DRM_DEBUG("allocated %ju pages @ %p, contents=%08lx\n",
100592ffb21SWarner Losh 	    entry->pages, entry->vaddr, *(unsigned long *)entry->vaddr);
101592ffb21SWarner Losh 
102592ffb21SWarner Losh 	return 0;
103592ffb21SWarner Losh }
104592ffb21SWarner Losh 
drm_sg_alloc_ioctl(struct drm_device * dev,void * data,struct drm_file * file_priv)105592ffb21SWarner Losh int drm_sg_alloc_ioctl(struct drm_device *dev, void *data,
106592ffb21SWarner Losh 		       struct drm_file *file_priv)
107592ffb21SWarner Losh {
108592ffb21SWarner Losh 	struct drm_scatter_gather *request = data;
109592ffb21SWarner Losh 
110592ffb21SWarner Losh 	return drm_sg_alloc(dev, request);
111592ffb21SWarner Losh 
112592ffb21SWarner Losh }
113592ffb21SWarner Losh 
drm_sg_free(struct drm_device * dev,void * data,struct drm_file * file_priv)114592ffb21SWarner Losh int drm_sg_free(struct drm_device *dev, void *data,
115592ffb21SWarner Losh 		struct drm_file *file_priv)
116592ffb21SWarner Losh {
117592ffb21SWarner Losh 	struct drm_scatter_gather *request = data;
118592ffb21SWarner Losh 	struct drm_sg_mem *entry;
119592ffb21SWarner Losh 
120592ffb21SWarner Losh 	if (!drm_core_check_feature(dev, DRIVER_SG))
121592ffb21SWarner Losh 		return -EINVAL;
122592ffb21SWarner Losh 
123592ffb21SWarner Losh 	entry = dev->sg;
124592ffb21SWarner Losh 	dev->sg = NULL;
125592ffb21SWarner Losh 
126*f49fd63aSJohn Baldwin 	if (!entry || (uintptr_t)entry->vaddr != request->handle)
127592ffb21SWarner Losh 		return -EINVAL;
128592ffb21SWarner Losh 
129*f49fd63aSJohn Baldwin 	DRM_DEBUG("free %p\n", entry->vaddr);
130592ffb21SWarner Losh 
131592ffb21SWarner Losh 	drm_sg_cleanup(entry);
132592ffb21SWarner Losh 
133592ffb21SWarner Losh 	return 0;
134592ffb21SWarner Losh }
135