drm_scatter.c revision 183833
1145132Sanholt/*-
2145132Sanholt * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
3145132Sanholt * All Rights Reserved.
4145132Sanholt *
5145132Sanholt * Permission is hereby granted, free of charge, to any person obtaining a
6145132Sanholt * copy of this software and associated documentation files (the "Software"),
7145132Sanholt * to deal in the Software without restriction, including without limitation
8145132Sanholt * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9145132Sanholt * and/or sell copies of the Software, and to permit persons to whom the
10145132Sanholt * Software is furnished to do so, subject to the following conditions:
11145132Sanholt *
12145132Sanholt * The above copyright notice and this permission notice (including the next
13145132Sanholt * paragraph) shall be included in all copies or substantial portions of the
14145132Sanholt * Software.
15145132Sanholt *
16145132Sanholt * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17145132Sanholt * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18145132Sanholt * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19145132Sanholt * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20145132Sanholt * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21145132Sanholt * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22145132Sanholt * DEALINGS IN THE SOFTWARE.
23145132Sanholt *
24145132Sanholt * Authors:
25145132Sanholt *   Gareth Hughes <gareth@valinux.com>
26145132Sanholt *   Eric Anholt <anholt@FreeBSD.org>
27145132Sanholt *
28145132Sanholt */
29145132Sanholt
30152909Sanholt#include <sys/cdefs.h>
31152909Sanholt__FBSDID("$FreeBSD: head/sys/dev/drm/drm_scatter.c 183833 2008-10-13 18:03:27Z rnoland $");
32152909Sanholt
33182080Srnoland/** @file drm_scatter.c
34182080Srnoland * Allocation of memory for scatter-gather mappings by the graphics chip.
35182080Srnoland *
36182080Srnoland * The memory allocated here is then made into an aperture in the card
37182080Srnoland * by drm_ati_pcigart_init().
38182080Srnoland */
39182080Srnoland
40145132Sanholt#include "dev/drm/drmP.h"
41145132Sanholt
42145132Sanholt#define DEBUG_SCATTER 0
43145132Sanholt
44145132Sanholtvoid drm_sg_cleanup(drm_sg_mem_t *entry)
45145132Sanholt{
46183833Srnoland	free((void *)entry->handle, DRM_MEM_PAGES);
47183833Srnoland	free(entry->busaddr, DRM_MEM_PAGES);
48183833Srnoland	free(entry, DRM_MEM_SGLISTS);
49145132Sanholt}
50145132Sanholt
51183573Srnolandint drm_sg_alloc(struct drm_device * dev, struct drm_scatter_gather * request)
52145132Sanholt{
53145132Sanholt	drm_sg_mem_t *entry;
54145132Sanholt	unsigned long pages;
55152909Sanholt	int i;
56145132Sanholt
57183573Srnoland	if (dev->sg)
58145132Sanholt		return EINVAL;
59145132Sanholt
60183833Srnoland	entry = malloc(sizeof(*entry), DRM_MEM_SGLISTS, M_WAITOK | M_ZERO);
61183573Srnoland	if (!entry)
62145132Sanholt		return ENOMEM;
63145132Sanholt
64182080Srnoland	pages = round_page(request->size) / PAGE_SIZE;
65183573Srnoland	DRM_DEBUG("sg size=%ld pages=%ld\n", request->size, pages);
66145132Sanholt
67145132Sanholt	entry->pages = pages;
68145132Sanholt
69183833Srnoland	entry->busaddr = malloc(pages * sizeof(*entry->busaddr), DRM_MEM_PAGES,
70145132Sanholt	    M_WAITOK | M_ZERO);
71183573Srnoland	if (!entry->busaddr) {
72145132Sanholt		drm_sg_cleanup(entry);
73145132Sanholt		return ENOMEM;
74145132Sanholt	}
75145132Sanholt
76183833Srnoland	entry->handle = (long)malloc(pages << PAGE_SHIFT, DRM_MEM_PAGES,
77152909Sanholt	    M_WAITOK | M_ZERO);
78152909Sanholt	if (entry->handle == 0) {
79145132Sanholt		drm_sg_cleanup(entry);
80145132Sanholt		return ENOMEM;
81145132Sanholt	}
82145132Sanholt
83152909Sanholt	for (i = 0; i < pages; i++) {
84152909Sanholt		entry->busaddr[i] = vtophys(entry->handle + i * PAGE_SIZE);
85152909Sanholt	}
86145132Sanholt
87183573Srnoland	DRM_DEBUG("sg alloc handle  = %08lx\n", entry->handle);
88145132Sanholt
89158682Sanholt	entry->virtual = (void *)entry->handle;
90182080Srnoland	request->handle = entry->handle;
91145132Sanholt
92145132Sanholt	DRM_LOCK();
93145132Sanholt	if (dev->sg) {
94145132Sanholt		DRM_UNLOCK();
95145132Sanholt		drm_sg_cleanup(entry);
96145132Sanholt		return EINVAL;
97145132Sanholt	}
98145132Sanholt	dev->sg = entry;
99145132Sanholt	DRM_UNLOCK();
100145132Sanholt
101145132Sanholt	return 0;
102145132Sanholt}
103145132Sanholt
104182080Srnolandint drm_sg_alloc_ioctl(struct drm_device *dev, void *data,
105182080Srnoland		       struct drm_file *file_priv)
106145132Sanholt{
107183573Srnoland	struct drm_scatter_gather *request = data;
108182080Srnoland	int ret;
109182080Srnoland
110183573Srnoland	DRM_DEBUG("%s\n", __FUNCTION__);
111182080Srnoland
112182080Srnoland	ret = drm_sg_alloc(dev, request);
113182080Srnoland	return ret;
114182080Srnoland}
115182080Srnoland
116182080Srnolandint drm_sg_free(struct drm_device *dev, void *data, struct drm_file *file_priv)
117182080Srnoland{
118183573Srnoland	struct drm_scatter_gather *request = data;
119145132Sanholt	drm_sg_mem_t *entry;
120145132Sanholt
121145132Sanholt	DRM_LOCK();
122145132Sanholt	entry = dev->sg;
123145132Sanholt	dev->sg = NULL;
124145132Sanholt	DRM_UNLOCK();
125145132Sanholt
126183573Srnoland	if (!entry || entry->handle != request->handle)
127145132Sanholt		return EINVAL;
128145132Sanholt
129183573Srnoland	DRM_DEBUG("sg free virtual = 0x%lx\n", entry->handle);
130145132Sanholt
131145132Sanholt	drm_sg_cleanup(entry);
132145132Sanholt
133145132Sanholt	return 0;
134145132Sanholt}
135