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)®s, &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