xref: /gfx-drm/usr/src/uts/common/io/drm/drm_scatter.c (revision 47dc10d7)
1 /*
2  * Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved.
3  */
4 
5 /*
6  * Copyright (c) 2012 Intel Corporation.  All rights reserved.
7  */
8 
9 /**
10  * \file drm_scatter.c
11  * IOCTLs to manage scatter/gather memory
12  *
13  * \author Gareth Hughes <gareth@valinux.com>
14  */
15 
16 /*
17  * Created: Mon Dec 18 23:20:54 2000 by gareth@valinux.com
18  *
19  * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
20  * All Rights Reserved.
21  *
22  * Permission is hereby granted, free of charge, to any person obtaining a
23  * copy of this software and associated documentation files (the "Software"),
24  * to deal in the Software without restriction, including without limitation
25  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
26  * and/or sell copies of the Software, and to permit persons to whom the
27  * Software is furnished to do so, subject to the following conditions:
28  *
29  * The above copyright notice and this permission notice (including the next
30  * paragraph) shall be included in all copies or substantial portions of the
31  * Software.
32  *
33  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
36  * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
37  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
38  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
39  * DEALINGS IN THE SOFTWARE.
40  */
41 
42 #include "drmP.h"
43 #include "drm_io32.h"
44 
45 #define DEBUG_SCATTER 0
46 
drm_sg_cleanup(struct drm_sg_mem * entry)47 void drm_sg_cleanup(struct drm_sg_mem *entry)
48 {
49 	int pages = entry->pages;
50 
51 	if (entry->busaddr) {
52 		kmem_free(entry->busaddr, sizeof (*entry->busaddr) * pages);
53 		entry->busaddr = NULL;
54 	}
55 
56 	ASSERT(entry->umem_cookie == NULL);
57 
58 	if (entry->dmah_sg) {
59 		drm_pci_free(entry->dmah_sg);
60 		entry->dmah_sg = NULL;
61 	}
62 
63 	if (entry->dmah_gart) {
64 		drm_pci_free(entry->dmah_gart);
65 		entry->dmah_gart = NULL;
66 	}
67 
68 	kfree(entry, sizeof (struct drm_sg_mem));
69 }
70 
71 #ifdef	_LP64
72 #define	ScatterHandle(x) (unsigned int)((x >> 32) + (x & ((1L << 32) - 1)))
73 #else
74 #define	ScatterHandle(x) (unsigned int)(x)
75 #endif
76 
drm_sg_alloc(struct drm_device * dev,struct drm_scatter_gather * request)77 int drm_sg_alloc(struct drm_device *dev, struct drm_scatter_gather * request)
78 {
79 	struct drm_sg_mem *entry;
80 	unsigned long pages;
81 	drm_dma_handle_t *dmah;
82 
83 	DRM_DEBUG("\n");
84 
85 	if (!drm_core_check_feature(dev, DRIVER_SG))
86 		return -EINVAL;
87 
88 	if (dev->sg)
89 		return -EINVAL;
90 
91 	entry = kmalloc(sizeof(*entry), GFP_KERNEL);
92 	if (!entry)
93 		return -ENOMEM;
94 
95 	(void) memset(entry, 0, sizeof(*entry));
96 	pages = (request->size + PAGE_SIZE - 1) / PAGE_SIZE;
97 	DRM_DEBUG("size=%ld pages=%ld\n", request->size, pages);
98 
99 	entry->pages = (int)pages;
100 	dmah = drm_pci_alloc(dev, ptob(pages), 4096, 0xfffffffful, pages);
101 	if (dmah == NULL)
102 		goto err_exit;
103 	entry->busaddr = (void *)kmem_zalloc(sizeof (*entry->busaddr) *
104 	    pages, KM_SLEEP);
105 
106 	entry->handle = ScatterHandle((unsigned long)dmah->vaddr);
107 	entry->virtual = (void *)dmah->vaddr;
108 	request->handle = entry->handle;
109 	entry->dmah_sg = dmah;
110 
111 	dev->sg = entry;
112 
113 	return 0;
114 
115 err_exit:
116 	drm_sg_cleanup(entry);
117 	return -ENOMEM;
118 }
119 
120 /* LINTED */
drm_sg_alloc_ioctl(DRM_IOCTL_ARGS)121 int drm_sg_alloc_ioctl(DRM_IOCTL_ARGS)
122 {
123 	struct drm_scatter_gather *request = data;
124 
125 	return drm_sg_alloc(dev, request);
126 
127 }
128 
129 /* LINTED */
drm_sg_free(DRM_IOCTL_ARGS)130 int drm_sg_free(DRM_IOCTL_ARGS)
131 {
132 	struct drm_scatter_gather *request = data;
133 	struct drm_sg_mem *entry;
134 
135 	if (!drm_core_check_feature(dev, DRIVER_SG))
136 		return -EINVAL;
137 
138 	entry = dev->sg;
139 	dev->sg = NULL;
140 
141 	if (!entry || entry->handle != request->handle)
142 		return -EINVAL;
143 
144 	DRM_DEBUG("virtual  = %p\n", entry->virtual);
145 
146 	drm_sg_cleanup(entry);
147 
148 	return 0;
149 }
150