1/*-
2 *Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
3 * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the next
14 * paragraph) shall be included in all copies or substantial portions of the
15 * Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20 * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 * OTHER DEALINGS IN THE SOFTWARE.
24 *
25 * Authors:
26 *    Rickard E. (Rik) Faith <faith@valinux.com>
27 *    Gareth Hughes <gareth@valinux.com>
28 *
29 */
30
31/** @file drm_memory.c
32 * Wrappers for kernel memory allocation routines, and MTRR management support.
33 *
34 * This file previously implemented a memory consumption tracking system using
35 * the "area" argument for various different types of allocations, but that
36 * has been stripped out for now.
37 */
38
39#include "drmP.h"
40
41#if defined(__NetBSD__)
42# ifdef DRM_NO_AGP
43#  define NAGP_I810 0
44# else
45#  if defined(_KERNEL_OPT)
46#    include "agp_i810.h"
47#    include "genfb.h"
48#  else
49#   define NAGP_I810 1
50#   define NGENFB 0
51#  endif
52# endif
53# if NAGP_I810 > 0
54#  include <dev/pci/agpvar.h>
55# endif
56# if NGENFB > 0
57#  include <dev/wsfb/genfbvar.h>
58# endif
59#endif
60
61MALLOC_DEFINE(DRM_MEM_DMA, "drm_dma", "DRM DMA Data Structures");
62MALLOC_DEFINE(DRM_MEM_SAREA, "drm_sarea", "DRM SAREA Data Structures");
63MALLOC_DEFINE(DRM_MEM_DRIVER, "drm_driver", "DRM DRIVER Data Structures");
64MALLOC_DEFINE(DRM_MEM_MAGIC, "drm_magic", "DRM MAGIC Data Structures");
65MALLOC_DEFINE(DRM_MEM_IOCTLS, "drm_ioctls", "DRM IOCTL Data Structures");
66MALLOC_DEFINE(DRM_MEM_MAPS, "drm_maps", "DRM MAP Data Structures");
67MALLOC_DEFINE(DRM_MEM_BUFS, "drm_bufs", "DRM BUFFER Data Structures");
68MALLOC_DEFINE(DRM_MEM_SEGS, "drm_segs", "DRM SEGMENTS Data Structures");
69MALLOC_DEFINE(DRM_MEM_PAGES, "drm_pages", "DRM PAGES Data Structures");
70MALLOC_DEFINE(DRM_MEM_FILES, "drm_files", "DRM FILE Data Structures");
71MALLOC_DEFINE(DRM_MEM_QUEUES, "drm_queues", "DRM QUEUE Data Structures");
72MALLOC_DEFINE(DRM_MEM_CMDS, "drm_cmds", "DRM COMMAND Data Structures");
73MALLOC_DEFINE(DRM_MEM_MAPPINGS, "drm_mapping", "DRM MAPPING Data Structures");
74MALLOC_DEFINE(DRM_MEM_BUFLISTS, "drm_buflists", "DRM BUFLISTS Data Structures");
75MALLOC_DEFINE(DRM_MEM_AGPLISTS, "drm_agplists", "DRM AGPLISTS Data Structures");
76MALLOC_DEFINE(DRM_MEM_CTXBITMAP, "drm_ctxbitmap",
77    "DRM CTXBITMAP Data Structures");
78MALLOC_DEFINE(DRM_MEM_SGLISTS, "drm_sglists", "DRM SGLISTS Data Structures");
79MALLOC_DEFINE(DRM_MEM_DRAWABLE, "drm_drawable", "DRM DRAWABLE Data Structures");
80MALLOC_DEFINE(DRM_MEM_MM, "drm_mm", "DRM MM Data Structures");
81
82void drm_mem_init(void)
83{
84}
85
86void drm_mem_uninit(void)
87{
88}
89
90#if defined(__NetBSD__)
91static void *
92drm_netbsd_ioremap(struct drm_device *dev, drm_local_map_t *map, int wc)
93{
94	bus_space_handle_t h;
95	int i, reg, reason;
96	for(i = 0; i<DRM_MAX_PCI_RESOURCE; i++) {
97		reg = PCI_MAPREG_START + i*4;
98
99		/* Does the requested mapping lie within this resource? */
100		if ((dev->pci_map_data[i].maptype == PCI_MAPREG_TYPE_MEM ||
101		     dev->pci_map_data[i].maptype ==
102                      (PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_64BIT)) &&
103		    map->offset >= dev->pci_map_data[i].base             &&
104		    map->offset + map->size <= dev->pci_map_data[i].base +
105                                              dev->pci_map_data[i].size)
106		{
107			map->bst = dev->pa.pa_memt;
108			map->fullmap = &(dev->pci_map_data[i]);
109			map->mapsize = map->size;
110			dev->pci_map_data[i].mapped++;
111
112			/* If we've already mapped this resource in, handle
113			 * submapping if needed, give caller a bus_space handle
114			 * and pointer for the offest they asked for */
115			if (dev->pci_map_data[i].mapped > 1)
116			{
117				if ((reason = bus_space_subregion(
118						dev->pa.pa_memt,
119						dev->pci_map_data[i].bsh,
120						map->offset - dev->pci_map_data[i].base,
121						map->size, &h)) != 0)  {
122					DRM_DEBUG("ioremap failed to "
123						"bus_space_subregion: %d\n",
124						reason);
125					return NULL;
126				}
127				map->bsh = h;
128				map->handle = bus_space_vaddr(dev->pa.pa_memt,
129									h);
130				return map->handle;
131			}
132
133			/* Map in entirety of resource - full size and handle
134			 * go in pci_map_data, specific mapping in callers
135			 * drm_local_map_t */
136			DRM_DEBUG("ioremap%s: flags %d\n", wc ? "_wc" : "",
137				  dev->pci_map_data[i].flags);
138			if ((reason = bus_space_map(map->bst,
139					dev->pci_map_data[i].base,
140					dev->pci_map_data[i].size,
141					dev->pci_map_data[i].flags,
142					&dev->pci_map_data[i].bsh)))
143			{
144				dev->pci_map_data[i].mapped--;
145#if NAGP_I810 > 0 /* XXX horrible kludge: agp might have mapped it */
146				if (agp_i810_borrow(map->offset, &map->bsh))
147					return bus_space_vaddr(map->bst, map->bsh);
148#endif
149#if NGENFB > 0
150				if (genfb_borrow(map->offset, &map->bsh))
151					return bus_space_vaddr(map->bst, map->bsh);
152#endif
153				DRM_DEBUG("ioremap: failed to map (%d)\n",
154					  reason);
155				return NULL;
156			}
157
158			dev->pci_map_data[i].vaddr = bus_space_vaddr(map->bst,
159						dev->pci_map_data[i].bsh);
160
161			/* Caller might have requested a submapping of that */
162			if ((reason = bus_space_subregion(
163					dev->pa.pa_memt,
164					dev->pci_map_data[i].bsh,
165					map->offset - dev->pci_map_data[i].base,
166					map->size, &h)) != 0)  {
167				DRM_DEBUG("ioremap failed to "
168					"bus_space_subregion: %d\n",
169					reason);
170				return NULL;
171			}
172
173			DRM_DEBUG("ioremap mem found for %lx, %lx: %p\n",
174				map->offset, map->size,
175				dev->agp_map_data[i].vaddr);
176
177			map->bsh = h;
178			map->handle = bus_space_vaddr(dev->pa.pa_memt, h);
179			return map->handle;
180		}
181	}
182	/* failed to find a valid mapping; all hope isn't lost though */
183	for(i = 0; i<DRM_MAX_PCI_RESOURCE; i++) {
184		if (dev->agp_map_data[i].mapped > 0 &&
185		    dev->agp_map_data[i].base == map->offset &&
186		    dev->agp_map_data[i].size >= map->size) {
187			map->bst = dev->pa.pa_memt;
188			map->fullmap = &(dev->agp_map_data[i]);
189			map->mapsize = dev->agp_map_data[i].size;
190			dev->agp_map_data[i].mapped++;
191			map->bsh = dev->agp_map_data[i].bsh;
192			return dev->agp_map_data[i].vaddr;
193		}
194		if (dev->agp_map_data[i].mapped == 0) {
195			int rv;
196
197			map->bst = dev->pa.pa_memt;
198			dev->agp_map_data[i].mapped++;
199			dev->agp_map_data[i].base = map->offset;
200			dev->agp_map_data[i].size = map->size;
201			dev->agp_map_data[i].flags = BUS_SPACE_MAP_LINEAR |
202			    BUS_SPACE_MAP_PREFETCHABLE;
203			dev->agp_map_data[i].maptype = PCI_MAPREG_TYPE_MEM;
204			map->fullmap = &(dev->agp_map_data[i]);
205			map->mapsize = dev->agp_map_data[i].size;
206
207			DRM_DEBUG("ioremap%s: flags %d\n", wc ? "_wc" : "",
208				  dev->agp_map_data[i].flags);
209			rv = bus_space_map(map->bst, map->offset,
210				dev->agp_map_data[i].size,
211				dev->agp_map_data[i].flags, &map->bsh);
212			if (rv) {
213				dev->agp_map_data[i].mapped--;
214				DRM_DEBUG("ioremap: failed to map (%d)\n", rv);
215				return NULL;
216			}
217			dev->agp_map_data[i].bsh = map->bsh;
218			dev->agp_map_data[i].vaddr =
219			    bus_space_vaddr(map->bst, map->bsh);
220			DRM_DEBUG("ioremap agp mem found for %lx, %lx: %p\n",
221				map->offset, map->size,
222				dev->agp_map_data[i].vaddr);
223			return dev->agp_map_data[i].vaddr;
224		}
225	}
226
227	/* now we can give up... */
228	DRM_DEBUG("drm_ioremap failed: offset=%lx size=%lu\n",
229		  map->offset, map->size);
230	return NULL;
231}
232#endif
233
234void *drm_ioremap_wc(struct drm_device *dev, drm_local_map_t *map)
235{
236#if defined(__FreeBSD__)
237	return pmap_mapdev_attr(map->offset, map->size, PAT_WRITE_COMBINING);
238#elif   defined(__NetBSD__)
239	return drm_netbsd_ioremap(dev, map, 1);
240#endif
241}
242
243void *drm_ioremap(struct drm_device *dev, drm_local_map_t *map)
244{
245#if defined(__FreeBSD__)
246	return pmap_mapdev(map->offset, map->size);
247#elif   defined(__NetBSD__)
248	return drm_netbsd_ioremap(dev, map, 0);
249#endif
250}
251
252void drm_ioremapfree(drm_local_map_t *map)
253{
254#if defined(__FreeBSD__)
255	pmap_unmapdev((vm_offset_t) map->handle, map->size);
256#elif   defined(__NetBSD__)
257	if (map->fullmap == NULL) {
258		DRM_INFO("drm_ioremapfree called for unknown map\n");
259		return;
260	}
261
262	if (map->fullmap->mapped > 0) {
263		map->fullmap->mapped--;
264		if(map->fullmap->mapped == 0)
265			bus_space_unmap(map->bst, map->fullmap->bsh,
266					map->fullmap->size);
267	}
268#endif
269}
270
271#if defined(__FreeBSD__)
272int
273drm_mtrr_add(unsigned long offset, size_t size, int flags)
274{
275	int act;
276	struct mem_range_desc mrdesc;
277
278	mrdesc.mr_base = offset;
279	mrdesc.mr_len = size;
280	mrdesc.mr_flags = flags;
281	act = MEMRANGE_SET_UPDATE;
282	strlcpy(mrdesc.mr_owner, "drm", sizeof(mrdesc.mr_owner));
283	return mem_range_attr_set(&mrdesc, &act);
284}
285
286int
287drm_mtrr_del(int __unused handle, unsigned long offset, size_t size, int flags)
288{
289	int act;
290	struct mem_range_desc mrdesc;
291
292	mrdesc.mr_base = offset;
293	mrdesc.mr_len = size;
294	mrdesc.mr_flags = flags;
295	act = MEMRANGE_SET_REMOVE;
296	strlcpy(mrdesc.mr_owner, "drm", sizeof(mrdesc.mr_owner));
297	return mem_range_attr_set(&mrdesc, &act);
298}
299#elif   defined(__NetBSD__)
300int
301drm_mtrr_add(unsigned long offset, size_t size, int flags)
302{
303#ifdef MTRR_GETSET_KERNEL
304	struct mtrr mtrrmap;
305	int one = 1;
306
307	mtrrmap.base = offset;
308	mtrrmap.len = size;
309	mtrrmap.type = flags;
310	mtrrmap.flags = MTRR_VALID;
311	return mtrr_set(&mtrrmap, &one, NULL, MTRR_GETSET_KERNEL);
312#else
313	return 0;
314#endif
315}
316
317int
318drm_mtrr_del(int __unused handle, unsigned long offset, size_t size, int flags)
319{
320#ifdef MTRR_GETSET_KERNEL
321	struct mtrr mtrrmap;
322	int one = 1;
323
324	mtrrmap.base = offset;
325	mtrrmap.len = size;
326	mtrrmap.type = flags;
327	mtrrmap.flags = 0;
328	return mtrr_set(&mtrrmap, &one, NULL, MTRR_GETSET_KERNEL);
329#else
330	return 0;
331#endif
332}
333#endif
334