e1000 - Literally import e1000 driver from FreeBSD
[dragonfly.git] / sys / dev / drm / drm_scatter.c
blob34a2bcc6b6a91774033ac5e37559f5ab5a2cc2e4
1 /*-
2 * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
3 * All Rights Reserved.
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
24 * Authors:
25 * Gareth Hughes <gareth@valinux.com>
26 * Eric Anholt <anholt@FreeBSD.org>
30 /** @file drm_scatter.c
31 * Allocation of memory for scatter-gather mappings by the graphics chip.
33 * The memory allocated here is then made into an aperture in the card
34 * by drm_ati_pcigart_init().
37 #include "dev/drm/drmP.h"
39 static void drm_sg_alloc_cb(void *arg, bus_dma_segment_t *segs,
40 int nsegs, int error);
42 int
43 drm_sg_alloc(struct drm_device *dev, struct drm_scatter_gather *request)
45 struct drm_sg_mem *entry;
46 struct drm_dma_handle *dmah;
47 unsigned long pages;
48 int ret;
50 if (dev->sg)
51 return EINVAL;
53 entry = malloc(sizeof(*entry), DRM_MEM_SGLISTS, M_WAITOK | M_ZERO);
54 if (!entry)
55 return ENOMEM;
57 pages = round_page(request->size) / PAGE_SIZE;
58 DRM_DEBUG("sg size=%ld pages=%ld\n", request->size, pages);
60 entry->pages = pages;
62 entry->busaddr = malloc(pages * sizeof(*entry->busaddr), DRM_MEM_PAGES,
63 M_WAITOK | M_ZERO);
64 if (!entry->busaddr) {
65 free(entry, DRM_MEM_SGLISTS);
66 return ENOMEM;
69 dmah = malloc(sizeof(struct drm_dma_handle), DRM_MEM_DMA,
70 M_ZERO | M_NOWAIT);
71 if (dmah == NULL) {
72 free(entry->busaddr, DRM_MEM_PAGES);
73 free(entry, DRM_MEM_SGLISTS);
74 return ENOMEM;
77 ret = bus_dma_tag_create(NULL, PAGE_SIZE, 0, /* tag, align, boundary */
78 BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, /* lowaddr, highaddr */
79 NULL, NULL, /* filtfunc, filtfuncargs */
80 request->size, pages, /* maxsize, nsegs */
81 PAGE_SIZE, 0, /* maxsegsize, flags */
82 &dmah->tag);
83 if (ret != 0) {
84 free(dmah, DRM_MEM_DMA);
85 free(entry->busaddr, DRM_MEM_PAGES);
86 free(entry, DRM_MEM_SGLISTS);
87 return ENOMEM;
90 /* XXX BUS_DMA_NOCACHE */
91 ret = bus_dmamem_alloc(dmah->tag, &dmah->vaddr,
92 BUS_DMA_WAITOK | BUS_DMA_ZERO , &dmah->map);
93 if (ret != 0) {
94 bus_dma_tag_destroy(dmah->tag);
95 free(dmah, DRM_MEM_DMA);
96 free(entry->busaddr, DRM_MEM_PAGES);
97 free(entry, DRM_MEM_SGLISTS);
98 return ENOMEM;
101 ret = bus_dmamap_load(dmah->tag, dmah->map, dmah->vaddr,
102 request->size, drm_sg_alloc_cb, entry, BUS_DMA_NOWAIT);
103 if (ret != 0) {
104 bus_dmamem_free(dmah->tag, dmah->vaddr, dmah->map);
105 bus_dma_tag_destroy(dmah->tag);
106 free(dmah, DRM_MEM_DMA);
107 free(entry->busaddr, DRM_MEM_PAGES);
108 free(entry, DRM_MEM_SGLISTS);
109 return ENOMEM;
112 entry->dmah = dmah;
113 entry->handle = (unsigned long)dmah->vaddr;
115 DRM_DEBUG("sg alloc handle = %08lx\n", entry->handle);
117 entry->virtual = (void *)entry->handle;
118 request->handle = entry->handle;
120 DRM_LOCK();
121 if (dev->sg) {
122 DRM_UNLOCK();
123 drm_sg_cleanup(entry);
124 return EINVAL;
126 dev->sg = entry;
127 DRM_UNLOCK();
129 return 0;
132 static void
133 drm_sg_alloc_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
135 struct drm_sg_mem *entry = arg;
136 int i;
138 if (error != 0)
139 return;
141 for(i = 0 ; i < nsegs ; i++) {
142 entry->busaddr[i] = segs[i].ds_addr;
147 drm_sg_alloc_ioctl(struct drm_device *dev, void *data,
148 struct drm_file *file_priv)
150 struct drm_scatter_gather *request = data;
152 DRM_DEBUG("\n");
154 return drm_sg_alloc(dev, request);
157 void
158 drm_sg_cleanup(struct drm_sg_mem *entry)
160 struct drm_dma_handle *dmah = entry->dmah;
162 bus_dmamap_unload(dmah->tag, dmah->map);
163 bus_dmamem_free(dmah->tag, dmah->vaddr, dmah->map);
164 bus_dma_tag_destroy(dmah->tag);
165 free(dmah, DRM_MEM_DMA);
166 free(entry->busaddr, DRM_MEM_PAGES);
167 free(entry, DRM_MEM_SGLISTS);
171 drm_sg_free(struct drm_device *dev, void *data, struct drm_file *file_priv)
173 struct drm_scatter_gather *request = data;
174 struct drm_sg_mem *entry;
176 DRM_LOCK();
177 entry = dev->sg;
178 dev->sg = NULL;
179 DRM_UNLOCK();
181 if (!entry || entry->handle != request->handle)
182 return EINVAL;
184 DRM_DEBUG("sg free virtual = 0x%lx\n", entry->handle);
186 drm_sg_cleanup(entry);
188 return 0;