xref: /gfx-drm/usr/src/uts/common/io/drm/drm_memory.c (revision 47dc10d7)
1 /*
2  * Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved.
3  */
4 
5 /*
6  * drm_memory.h -- Memory management wrappers for DRM -*- linux-c -*-
7  * Created: Thu Feb  4 14:00:34 1999 by faith@valinux.com
8  */
9 /*
10  * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
11  * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
12  * Copyright (c) 2009, 2012, Intel Corporation.
13  * All Rights Reserved.
14  *
15  * Permission is hereby granted, free of charge, to any person obtaining a
16  * copy of this software and associated documentation files (the "Software"),
17  * to deal in the Software without restriction, including without limitation
18  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
19  * and/or sell copies of the Software, and to permit persons to whom the
20  * Software is furnished to do so, subject to the following conditions:
21  *
22  * The above copyright notice and this permission notice (including the next
23  * paragraph) shall be included in all copies or substantial portions of the
24  * Software.
25  *
26  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
27  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
28  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
29  * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
30  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
31  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
32  * OTHER DEALINGS IN THE SOFTWARE.
33  *
34  * Authors:
35  *    Rickard E. (Rik) Faith <faith@valinux.com>
36  *    Gareth Hughes <gareth@valinux.com>
37  *
38  */
39 
40 #include "drmP.h"
41 #ifdef __x86
42 #include "drm_linux_list.h"
43 #endif
44 
45 /* Device memory access structure */
46 
47 typedef struct drm_device_iomap {
48 	uint_t paddr;		/* physical address */
49 	uint_t size;		/* size of mapping */
50 	caddr_t kvaddr;		/* kernel virtual address */
51 	ddi_acc_handle_t acc_handle; 	/* data access handle */
52 } drm_device_iomap_t;
53 
54 void *
drm_alloc(size_t size,int area)55 drm_alloc(size_t size, int area)
56 {
57 	_NOTE(ARGUNUSED(area))
58 
59 	return (kmem_zalloc(1 * size, KM_NOSLEEP));
60 }
61 
62 void *
drm_calloc(size_t nmemb,size_t size,int area)63 drm_calloc(size_t nmemb, size_t size, int area)
64 {
65 	_NOTE(ARGUNUSED(area))
66 
67 	return (kmem_zalloc(size * nmemb, KM_NOSLEEP));
68 }
69 
70 void *
drm_realloc(void * oldpt,size_t oldsize,size_t size,int area)71 drm_realloc(void *oldpt, size_t oldsize, size_t size, int area)
72 {
73 	_NOTE(ARGUNUSED(area))
74 
75 	void *pt;
76 
77 	pt = kmem_zalloc(1 * size, KM_NOSLEEP);
78 	if (pt == NULL) {
79 		DRM_ERROR("pt is NULL strange");
80 		return (NULL);
81 	}
82 	if (oldpt && oldsize) {
83 		bcopy(oldpt, pt, min(oldsize, size));
84 		kmem_free(oldpt, oldsize);
85 	}
86 	return (pt);
87 }
88 
89 void
drm_free(void * pt,size_t size,int area)90 drm_free(void *pt, size_t size, int area)
91 {
92 	_NOTE(ARGUNUSED(area))
93 
94 	if (pt)
95 		kmem_free(pt, size);
96 }
97 
98 int
drm_get_pci_index_reg(dev_info_t * dip,uint_t paddr,uint_t size,off_t * off)99 drm_get_pci_index_reg(dev_info_t *dip, uint_t paddr, uint_t size, off_t *off)
100 {
101 	_NOTE(ARGUNUSED(size))
102 
103 	pci_regspec_t *regs = NULL;
104 	int len;
105 	uint_t regbase, regsize;
106 	int nregs, i;
107 	int regnum;
108 
109 	regnum = -1;
110 
111 	if (ddi_dev_nregs(dip, &nregs) == DDI_FAILURE) {
112 		DRM_ERROR("ddi_dev_nregs() failed");
113 		return (-1);
114 	}
115 
116 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
117 	    "assigned-addresses", (caddr_t)&regs, &len) != DDI_PROP_SUCCESS) {
118 		DRM_ERROR("ddi_getlongprop() failed");
119 		if (regs)
120 			kmem_free(regs, (size_t)len);
121 		return (-1);
122 	}
123 
124 	for (i = 0; i < nregs; i ++) {
125 		regbase = (uint_t)regs[i].pci_phys_low;
126 		regsize = (uint_t)regs[i].pci_size_low;
127 		if ((uint_t)paddr >= regbase &&
128 		    (uint_t)paddr < (regbase + regsize)) {
129 			regnum = i + 1;
130 			*off = (off_t)(paddr - regbase);
131 			break;
132 		}
133 	}
134 
135 	if (regs)
136 		kmem_free(regs, (size_t)len);
137 	return (regnum);
138 }
139 
140 /* data access attributes structure for register access */
141 static ddi_device_acc_attr_t dev_attr = {
142 	DDI_DEVICE_ATTR_V0,
143 #ifdef _BIG_ENDIAN
144 	DDI_STRUCTURE_LE_ACC,
145 #else
146 	DDI_NEVERSWAP_ACC,
147 #endif
148 	DDI_STRICTORDER_ACC,
149 	DDI_FLAGERR_ACC
150 };
151 
152 static int
__ioremap(dev_info_t * dip,drm_device_iomap_t * iomap)153 __ioremap(dev_info_t *dip, drm_device_iomap_t *iomap)
154 {
155 	off_t offset;
156 	int regnum;
157 	int ret;
158 
159 	regnum = drm_get_pci_index_reg(
160 	    dip, iomap->paddr, iomap->size, &offset);
161 	if (regnum < 0) {
162 		DRM_ERROR("can not find register entry: "
163 		    "paddr=0x%x, size=0x%x", iomap->paddr, iomap->size);
164 		return -ENXIO;
165 	}
166 
167 	ret = ddi_regs_map_setup(dip, regnum,
168 	    (caddr_t *)&(iomap->kvaddr), (offset_t)offset,
169 	    (offset_t)iomap->size, &dev_attr, &iomap->acc_handle);
170 	if (ret != DDI_SUCCESS) {
171 		DRM_ERROR("failed to map regs: "
172 		    "regnum=%d, offset=0x%lx", regnum, offset);
173 		iomap->acc_handle = NULL;
174 		return -EFAULT;
175 	}
176 
177 	return 0;
178 }
179 
180 int
drm_ioremap(struct drm_device * dev,struct drm_local_map * map)181 drm_ioremap(struct drm_device *dev, struct drm_local_map *map)
182 {
183 	struct drm_device_iomap iomap;
184 	int ret;
185 
186 	DRM_DEBUG("\n");
187 
188 	iomap.paddr = map->offset;
189 	iomap.size = map->size;
190 
191 	ret = __ioremap(dev->devinfo, &iomap);
192 	if (ret) {
193 		DRM_ERROR("__ioremap failed: paddr=0x%lx, size=0x%lx",
194 		    map->offset, map->size);
195 		return (ret);
196 	}
197 
198 	map->handle = (void *)iomap.kvaddr;
199 	map->acc_handle = iomap.acc_handle;
200 
201 	DRM_DEBUG(
202 	    "map->handle=%p, map->size=%lx",
203 	    (void *)map->handle, map->size);
204 
205 	return (0);
206 }
207 
208 void
drm_ioremapfree(struct drm_local_map * map)209 drm_ioremapfree(struct drm_local_map *map)
210 {
211 	if (map->acc_handle)
212 		ddi_regs_map_free(&map->acc_handle);
213 }
214 
215 #ifdef __x86
216 struct drm_iomem {
217 	void *addr;
218 	size_t size;
219 	struct list_head head;
220 };
221 
222 struct list_head drm_iomem_list;
223 
224 void *
drm_sun_ioremap(uint64_t paddr,size_t size,uint32_t mode)225 drm_sun_ioremap(uint64_t paddr, size_t size, uint32_t mode)
226 {
227 	struct drm_iomem *iomem;
228 	void *addr;
229 
230 	if (mode == DRM_MEM_CACHED)
231 		mode = GFXP_MEMORY_CACHED;
232 	else if (mode == DRM_MEM_UNCACHED)
233 		mode = GFXP_MEMORY_UNCACHED;
234 	else if (mode == DRM_MEM_WC)
235 		mode = GFXP_MEMORY_WRITECOMBINED;
236 	else
237 		return (NULL);
238 
239 	addr = (void *)gfxp_alloc_kernel_space(size);
240 	if(!addr)
241 		return (NULL);
242 	gfxp_load_kernel_space(paddr, size, mode, addr);
243 	iomem = kmem_zalloc(sizeof(*iomem), KM_NOSLEEP);
244 	if(!iomem){
245 		gfxp_unmap_kernel_space(addr, size);
246 		return (NULL);
247 	}
248 	iomem->addr = addr;
249 	iomem->size = size;
250 
251 	INIT_LIST_HEAD(&iomem->head);
252 	list_add(&iomem->head, &drm_iomem_list, (caddr_t)iomem);
253 
254 	return (addr);
255 }
256 
257 void
drm_sun_iounmap(void * addr)258 drm_sun_iounmap(void *addr)
259 {
260 	struct drm_iomem *iomem;
261 
262 	list_for_each_entry(iomem, struct drm_iomem, &drm_iomem_list, head) {
263 		if (iomem->addr == addr) {
264 			gfxp_unmap_kernel_space(addr, iomem->size);
265 			list_del(&iomem->head);
266 			kmem_free(iomem, sizeof(*iomem));
267 			break;
268 		}
269 	}
270 }
271 #endif /* x86 */
272