xref: /dragonfly/sys/dev/drm/drm_bufs.c (revision 7048805a)
1 /*-
2  * Copyright 1999, 2000 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_bufs.c
32  * Implementation of the ioctls for setup of DRM mappings and DMA buffers.
33  */
34 
35 #include "bus/pci/pcireg.h"
36 
37 #include "dev/drm/drmP.h"
38 
39 /* Allocation of PCI memory resources (framebuffer, registers, etc.) for
40  * drm_get_resource_*.  Note that they are not RF_ACTIVE, so there's no virtual
41  * address for accessing them.  Cleaned up at unload.
42  */
43 static int drm_alloc_resource(struct drm_device *dev, int resource)
44 {
45 	if (resource >= DRM_MAX_PCI_RESOURCE) {
46 		DRM_ERROR("Resource %d too large\n", resource);
47 		return 1;
48 	}
49 
50 	DRM_UNLOCK();
51 	if (dev->pcir[resource] != NULL) {
52 		DRM_LOCK();
53 		return 0;
54 	}
55 
56 	dev->pcirid[resource] = PCIR_BAR(resource);
57 	dev->pcir[resource] = bus_alloc_resource_any(dev->device,
58 	    SYS_RES_MEMORY, &dev->pcirid[resource], RF_SHAREABLE);
59 	DRM_LOCK();
60 
61 	if (dev->pcir[resource] == NULL) {
62 		DRM_ERROR("Couldn't find resource 0x%x\n", resource);
63 		return 1;
64 	}
65 
66 	return 0;
67 }
68 
69 unsigned long drm_get_resource_start(struct drm_device *dev,
70 				     unsigned int resource)
71 {
72 	if (drm_alloc_resource(dev, resource) != 0)
73 		return 0;
74 
75 	return rman_get_start(dev->pcir[resource]);
76 }
77 
78 unsigned long drm_get_resource_len(struct drm_device *dev,
79 				   unsigned int resource)
80 {
81 	if (drm_alloc_resource(dev, resource) != 0)
82 		return 0;
83 
84 	return rman_get_size(dev->pcir[resource]);
85 }
86 
87 int drm_addmap(struct drm_device * dev, unsigned long offset,
88 	       unsigned long size,
89     enum drm_map_type type, enum drm_map_flags flags, drm_local_map_t **map_ptr)
90 {
91 	drm_local_map_t *map;
92 	int align;
93 	/*drm_agp_mem_t *entry;
94 	int valid;*/
95 
96 	/* Only allow shared memory to be removable since we only keep enough
97 	 * book keeping information about shared memory to allow for removal
98 	 * when processes fork.
99 	 */
100 	if ((flags & _DRM_REMOVABLE) && type != _DRM_SHM) {
101 		DRM_ERROR("Requested removable map for non-DRM_SHM\n");
102 		return EINVAL;
103 	}
104 	if ((offset & PAGE_MASK) || (size & PAGE_MASK)) {
105 		DRM_ERROR("offset/size not page aligned: 0x%lx/0x%lx\n",
106 		    offset, size);
107 		return EINVAL;
108 	}
109 	if (offset + size < offset) {
110 		DRM_ERROR("offset and size wrap around: 0x%lx/0x%lx\n",
111 		    offset, size);
112 		return EINVAL;
113 	}
114 
115 	DRM_DEBUG("offset = 0x%08lx, size = 0x%08lx, type = %d\n", offset,
116 	    size, type);
117 
118 	/* Check if this is just another version of a kernel-allocated map, and
119 	 * just hand that back if so.
120 	 */
121 	if (type == _DRM_REGISTERS || type == _DRM_FRAME_BUFFER ||
122 	    type == _DRM_SHM) {
123 		TAILQ_FOREACH(map, &dev->maplist, link) {
124 			if (map->type == type && (map->offset == offset ||
125 			    (map->type == _DRM_SHM &&
126 			    map->flags == _DRM_CONTAINS_LOCK))) {
127 				map->size = size;
128 				DRM_DEBUG("Found kernel map %d\n", type);
129 				goto done;
130 			}
131 		}
132 	}
133 	DRM_UNLOCK();
134 
135 	/* Allocate a new map structure, fill it in, and do any type-specific
136 	 * initialization necessary.
137 	 */
138 	map = malloc(sizeof(*map), DRM_MEM_MAPS, M_ZERO | M_NOWAIT);
139 	if (!map) {
140 		DRM_LOCK();
141 		return ENOMEM;
142 	}
143 
144 	map->offset = offset;
145 	map->size = size;
146 	map->type = type;
147 	map->flags = flags;
148 
149 	switch (map->type) {
150 	case _DRM_REGISTERS:
151 		map->handle = drm_ioremap(dev, map);
152 		if (!(map->flags & _DRM_WRITE_COMBINING))
153 			break;
154 		/* FALLTHROUGH */
155 	case _DRM_FRAME_BUFFER:
156 		if (drm_mtrr_add(map->offset, map->size, DRM_MTRR_WC) == 0)
157 			map->mtrr = 1;
158 		break;
159 	case _DRM_SHM:
160 		map->handle = malloc(map->size, DRM_MEM_MAPS, M_NOWAIT);
161 		DRM_DEBUG("%lu %d %p\n",
162 		    map->size, drm_order(map->size), map->handle);
163 		if (!map->handle) {
164 			free(map, DRM_MEM_MAPS);
165 			DRM_LOCK();
166 			return ENOMEM;
167 		}
168 		map->offset = (unsigned long)map->handle;
169 		if (map->flags & _DRM_CONTAINS_LOCK) {
170 			/* Prevent a 2nd X Server from creating a 2nd lock */
171 			DRM_LOCK();
172 			if (dev->lock.hw_lock != NULL) {
173 				DRM_UNLOCK();
174 				free(map->handle, DRM_MEM_MAPS);
175 				free(map, DRM_MEM_MAPS);
176 				return EBUSY;
177 			}
178 			dev->lock.hw_lock = map->handle; /* Pointer to lock */
179 			DRM_UNLOCK();
180 		}
181 		break;
182 	case _DRM_AGP:
183 		/*valid = 0;*/
184 		/* In some cases (i810 driver), user space may have already
185 		 * added the AGP base itself, because dev->agp->base previously
186 		 * only got set during AGP enable.  So, only add the base
187 		 * address if the map's offset isn't already within the
188 		 * aperture.
189 		 */
190 		if (map->offset < dev->agp->base ||
191 		    map->offset > dev->agp->base +
192 		    dev->agp->info.ai_aperture_size - 1) {
193 			map->offset += dev->agp->base;
194 		}
195 		map->mtrr   = dev->agp->mtrr; /* for getmap */
196 		/*for (entry = dev->agp->memory; entry; entry = entry->next) {
197 			if ((map->offset >= entry->bound) &&
198 			    (map->offset + map->size <=
199 			    entry->bound + entry->pages * PAGE_SIZE)) {
200 				valid = 1;
201 				break;
202 			}
203 		}
204 		if (!valid) {
205 			free(map, DRM_MEM_MAPS);
206 			DRM_LOCK();
207 			return EACCES;
208 		}*/
209 		break;
210 	case _DRM_SCATTER_GATHER:
211 		if (!dev->sg) {
212 			free(map, DRM_MEM_MAPS);
213 			DRM_LOCK();
214 			return EINVAL;
215 		}
216 		map->offset += dev->sg->handle;
217 		break;
218 	case _DRM_CONSISTENT:
219 		/* Unfortunately, we don't get any alignment specification from
220 		 * the caller, so we have to guess.  drm_pci_alloc requires
221 		 * a power-of-two alignment, so try to align the bus address of
222 		 * the map to it size if possible, otherwise just assume
223 		 * PAGE_SIZE alignment.
224 		 */
225 		align = map->size;
226 		if ((align & (align - 1)) != 0)
227 			align = PAGE_SIZE;
228 		map->dmah = drm_pci_alloc(dev, map->size, align, 0xfffffffful);
229 		if (map->dmah == NULL) {
230 			free(map, DRM_MEM_MAPS);
231 			DRM_LOCK();
232 			return ENOMEM;
233 		}
234 		map->handle = map->dmah->vaddr;
235 		map->offset = map->dmah->busaddr;
236 		break;
237 	default:
238 		DRM_ERROR("Bad map type %d\n", map->type);
239 		free(map, DRM_MEM_MAPS);
240 		DRM_LOCK();
241 		return EINVAL;
242 	}
243 
244 	DRM_LOCK();
245 	TAILQ_INSERT_TAIL(&dev->maplist, map, link);
246 
247 done:
248 	/* Jumped to, with lock held, when a kernel map is found. */
249 
250 	DRM_DEBUG("Added map %d 0x%lx/0x%lx\n", map->type, map->offset,
251 	    map->size);
252 
253 	*map_ptr = map;
254 
255 	return 0;
256 }
257 
258 int drm_addmap_ioctl(struct drm_device *dev, void *data,
259 		     struct drm_file *file_priv)
260 {
261 	struct drm_map *request = data;
262 	drm_local_map_t *map;
263 	int err;
264 
265 	if (!(dev->flags & (FREAD|FWRITE)))
266 		return EACCES; /* Require read/write */
267 
268 	if (!DRM_SUSER(DRM_CURPROC) && request->type != _DRM_AGP)
269 		return EACCES;
270 
271 	DRM_LOCK();
272 	err = drm_addmap(dev, request->offset, request->size, request->type,
273 	    request->flags, &map);
274 	DRM_UNLOCK();
275 	if (err != 0)
276 		return err;
277 
278 	request->offset = map->offset;
279 	request->size = map->size;
280 	request->type = map->type;
281 	request->flags = map->flags;
282 	request->mtrr   = map->mtrr;
283 	request->handle = map->handle;
284 
285 	if (request->type != _DRM_SHM) {
286 		request->handle = (void *)request->offset;
287 	}
288 
289 	return 0;
290 }
291 
292 void drm_rmmap(struct drm_device *dev, drm_local_map_t *map)
293 {
294 	DRM_SPINLOCK_ASSERT(&dev->dev_lock);
295 
296 	TAILQ_REMOVE(&dev->maplist, map, link);
297 
298 	switch (map->type) {
299 	case _DRM_REGISTERS:
300 		if (map->bsr == NULL)
301 			drm_ioremapfree(map);
302 		/* FALLTHROUGH */
303 	case _DRM_FRAME_BUFFER:
304 		if (map->mtrr) {
305 			int __unused retcode;
306 
307 			retcode = drm_mtrr_del(0, map->offset, map->size,
308 			    DRM_MTRR_WC);
309 			DRM_DEBUG("mtrr_del = %d\n", retcode);
310 		}
311 		break;
312 	case _DRM_SHM:
313 		free(map->handle, DRM_MEM_MAPS);
314 		break;
315 	case _DRM_AGP:
316 	case _DRM_SCATTER_GATHER:
317 		break;
318 	case _DRM_CONSISTENT:
319 		drm_pci_free(dev, map->dmah);
320 		break;
321 	default:
322 		DRM_ERROR("Bad map type %d\n", map->type);
323 		break;
324 	}
325 
326 	if (map->bsr != NULL) {
327 		bus_release_resource(dev->device, SYS_RES_MEMORY, map->rid,
328 		    map->bsr);
329 	}
330 
331 	free(map, DRM_MEM_MAPS);
332 }
333 
334 /* Remove a map private from list and deallocate resources if the mapping
335  * isn't in use.
336  */
337 
338 int drm_rmmap_ioctl(struct drm_device *dev, void *data,
339 		    struct drm_file *file_priv)
340 {
341 	drm_local_map_t *map;
342 	struct drm_map *request = data;
343 
344 	DRM_LOCK();
345 	TAILQ_FOREACH(map, &dev->maplist, link) {
346 		if (map->handle == request->handle &&
347 		    map->flags & _DRM_REMOVABLE)
348 			break;
349 	}
350 
351 	/* No match found. */
352 	if (map == NULL) {
353 		DRM_UNLOCK();
354 		return EINVAL;
355 	}
356 
357 	drm_rmmap(dev, map);
358 
359 	DRM_UNLOCK();
360 
361 	return 0;
362 }
363 
364 
365 static void drm_cleanup_buf_error(struct drm_device *dev,
366 				  drm_buf_entry_t *entry)
367 {
368 	int i;
369 
370 	if (entry->seg_count) {
371 		for (i = 0; i < entry->seg_count; i++) {
372 			drm_pci_free(dev, entry->seglist[i]);
373 		}
374 		free(entry->seglist, DRM_MEM_SEGS);
375 
376 		entry->seg_count = 0;
377 	}
378 
379    	if (entry->buf_count) {
380 	   	for (i = 0; i < entry->buf_count; i++) {
381 			free(entry->buflist[i].dev_private, DRM_MEM_BUFS);
382 		}
383 		free(entry->buflist, DRM_MEM_BUFS);
384 
385 		entry->buf_count = 0;
386 	}
387 }
388 
389 static int drm_do_addbufs_agp(struct drm_device *dev, struct drm_buf_desc *request)
390 {
391 	drm_device_dma_t *dma = dev->dma;
392 	drm_buf_entry_t *entry;
393 	/*drm_agp_mem_t *agp_entry;
394 	int valid*/
395 	drm_buf_t *buf;
396 	unsigned long offset;
397 	unsigned long agp_offset;
398 	int count;
399 	int order;
400 	int size;
401 	int alignment;
402 	int page_order;
403 	int total;
404 	int byte_count;
405 	int i;
406 	drm_buf_t **temp_buflist;
407 
408 	count = request->count;
409 	order = drm_order(request->size);
410 	size = 1 << order;
411 
412 	alignment  = (request->flags & _DRM_PAGE_ALIGN)
413 	    ? round_page(size) : size;
414 	page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0;
415 	total = PAGE_SIZE << page_order;
416 
417 	byte_count = 0;
418 	agp_offset = dev->agp->base + request->agp_start;
419 
420 	DRM_DEBUG("count:      %d\n",  count);
421 	DRM_DEBUG("order:      %d\n",  order);
422 	DRM_DEBUG("size:       %d\n",  size);
423 	DRM_DEBUG("agp_offset: 0x%lx\n", agp_offset);
424 	DRM_DEBUG("alignment:  %d\n",  alignment);
425 	DRM_DEBUG("page_order: %d\n",  page_order);
426 	DRM_DEBUG("total:      %d\n",  total);
427 
428 	/* Make sure buffers are located in AGP memory that we own */
429 	/* Breaks MGA due to drm_alloc_agp not setting up entries for the
430 	 * memory.  Safe to ignore for now because these ioctls are still
431 	 * root-only.
432 	 */
433 	/*valid = 0;
434 	for (agp_entry = dev->agp->memory; agp_entry;
435 	    agp_entry = agp_entry->next) {
436 		if ((agp_offset >= agp_entry->bound) &&
437 		    (agp_offset + total * count <=
438 		    agp_entry->bound + agp_entry->pages * PAGE_SIZE)) {
439 			valid = 1;
440 			break;
441 		}
442 	}
443 	if (!valid) {
444 		DRM_DEBUG("zone invalid\n");
445 		return EINVAL;
446 	}*/
447 
448 	entry = &dma->bufs[order];
449 
450 	entry->buflist = malloc(count * sizeof(*entry->buflist), DRM_MEM_BUFS,
451 	    M_NOWAIT | M_ZERO);
452 	if (!entry->buflist) {
453 		return ENOMEM;
454 	}
455 
456 	entry->buf_size = size;
457 	entry->page_order = page_order;
458 
459 	offset = 0;
460 
461 	while (entry->buf_count < count) {
462 		buf          = &entry->buflist[entry->buf_count];
463 		buf->idx     = dma->buf_count + entry->buf_count;
464 		buf->total   = alignment;
465 		buf->order   = order;
466 		buf->used    = 0;
467 
468 		buf->offset  = (dma->byte_count + offset);
469 		buf->bus_address = agp_offset + offset;
470 		buf->address = (void *)(agp_offset + offset);
471 		buf->next    = NULL;
472 		buf->pending = 0;
473 		buf->file_priv = NULL;
474 
475 		buf->dev_priv_size = dev->driver->buf_priv_size;
476 		buf->dev_private = malloc(buf->dev_priv_size, DRM_MEM_BUFS,
477 		    M_NOWAIT | M_ZERO);
478 		if (buf->dev_private == NULL) {
479 			/* Set count correctly so we free the proper amount. */
480 			entry->buf_count = count;
481 			drm_cleanup_buf_error(dev, entry);
482 			return ENOMEM;
483 		}
484 
485 		offset += alignment;
486 		entry->buf_count++;
487 		byte_count += PAGE_SIZE << page_order;
488 	}
489 
490 	DRM_DEBUG("byte_count: %d\n", byte_count);
491 
492 	temp_buflist = realloc(dma->buflist,
493 	    (dma->buf_count + entry->buf_count) * sizeof(*dma->buflist),
494 	    DRM_MEM_BUFS, M_NOWAIT);
495 	if (temp_buflist == NULL) {
496 		/* Free the entry because it isn't valid */
497 		drm_cleanup_buf_error(dev, entry);
498 		return ENOMEM;
499 	}
500 	dma->buflist = temp_buflist;
501 
502 	for (i = 0; i < entry->buf_count; i++) {
503 		dma->buflist[i + dma->buf_count] = &entry->buflist[i];
504 	}
505 
506 	dma->buf_count += entry->buf_count;
507 	dma->byte_count += byte_count;
508 
509 	DRM_DEBUG("dma->buf_count : %d\n", dma->buf_count);
510 	DRM_DEBUG("entry->buf_count : %d\n", entry->buf_count);
511 
512 	request->count = entry->buf_count;
513 	request->size = size;
514 
515 	dma->flags = _DRM_DMA_USE_AGP;
516 
517 	return 0;
518 }
519 
520 static int drm_do_addbufs_pci(struct drm_device *dev, struct drm_buf_desc *request)
521 {
522 	drm_device_dma_t *dma = dev->dma;
523 	int count;
524 	int order;
525 	int size;
526 	int total;
527 	int page_order;
528 	drm_buf_entry_t *entry;
529 	drm_buf_t *buf;
530 	int alignment;
531 	unsigned long offset;
532 	int i;
533 	int byte_count;
534 	int page_count;
535 	unsigned long *temp_pagelist;
536 	drm_buf_t **temp_buflist;
537 
538 	count = request->count;
539 	order = drm_order(request->size);
540 	size = 1 << order;
541 
542 	DRM_DEBUG("count=%d, size=%d (%d), order=%d\n",
543 	    request->count, request->size, size, order);
544 
545 	alignment = (request->flags & _DRM_PAGE_ALIGN)
546 	    ? round_page(size) : size;
547 	page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0;
548 	total = PAGE_SIZE << page_order;
549 
550 	entry = &dma->bufs[order];
551 
552 	entry->buflist = malloc(count * sizeof(*entry->buflist), DRM_MEM_BUFS,
553 	    M_NOWAIT | M_ZERO);
554 	entry->seglist = malloc(count * sizeof(*entry->seglist), DRM_MEM_SEGS,
555 	    M_NOWAIT | M_ZERO);
556 
557 	/* Keep the original pagelist until we know all the allocations
558 	 * have succeeded
559 	 */
560 	temp_pagelist = malloc((dma->page_count + (count << page_order)) *
561 	    sizeof(*dma->pagelist), DRM_MEM_PAGES, M_NOWAIT);
562 
563 	if (entry->buflist == NULL || entry->seglist == NULL ||
564 	    temp_pagelist == NULL) {
565 		free(temp_pagelist, DRM_MEM_PAGES);
566 		free(entry->seglist, DRM_MEM_SEGS);
567 		free(entry->buflist, DRM_MEM_BUFS);
568 		return ENOMEM;
569 	}
570 
571 	memcpy(temp_pagelist, dma->pagelist, dma->page_count *
572 	    sizeof(*dma->pagelist));
573 
574 	DRM_DEBUG("pagelist: %d entries\n",
575 	    dma->page_count + (count << page_order));
576 
577 	entry->buf_size	= size;
578 	entry->page_order = page_order;
579 	byte_count = 0;
580 	page_count = 0;
581 
582 	while (entry->buf_count < count) {
583 		DRM_SPINUNLOCK(&dev->dma_lock);
584 		drm_dma_handle_t *dmah = drm_pci_alloc(dev, size, alignment,
585 		    0xfffffffful);
586 		DRM_SPINLOCK(&dev->dma_lock);
587 		if (dmah == NULL) {
588 			/* Set count correctly so we free the proper amount. */
589 			entry->buf_count = count;
590 			entry->seg_count = count;
591 			drm_cleanup_buf_error(dev, entry);
592 			free(temp_pagelist, DRM_MEM_PAGES);
593 			return ENOMEM;
594 		}
595 
596 		entry->seglist[entry->seg_count++] = dmah;
597 		for (i = 0; i < (1 << page_order); i++) {
598 			DRM_DEBUG("page %d @ %p\n",
599 			    dma->page_count + page_count,
600 			    (char *)dmah->vaddr + PAGE_SIZE * i);
601 			temp_pagelist[dma->page_count + page_count++] =
602 			    (long)dmah->vaddr + PAGE_SIZE * i;
603 		}
604 		for (offset = 0;
605 		    offset + size <= total && entry->buf_count < count;
606 		    offset += alignment, ++entry->buf_count) {
607 			buf	     = &entry->buflist[entry->buf_count];
608 			buf->idx     = dma->buf_count + entry->buf_count;
609 			buf->total   = alignment;
610 			buf->order   = order;
611 			buf->used    = 0;
612 			buf->offset  = (dma->byte_count + byte_count + offset);
613 			buf->address = ((char *)dmah->vaddr + offset);
614 			buf->bus_address = dmah->busaddr + offset;
615 			buf->next    = NULL;
616 			buf->pending = 0;
617 			buf->file_priv = NULL;
618 
619 			buf->dev_priv_size = dev->driver->buf_priv_size;
620 			buf->dev_private = malloc(buf->dev_priv_size,
621 			    DRM_MEM_BUFS, M_NOWAIT | M_ZERO);
622 			if (buf->dev_private == NULL) {
623 				/* Set count correctly so we free the proper amount. */
624 				entry->buf_count = count;
625 				entry->seg_count = count;
626 				drm_cleanup_buf_error(dev, entry);
627 				free(temp_pagelist, DRM_MEM_PAGES);
628 				return ENOMEM;
629 			}
630 
631 			DRM_DEBUG("buffer %d @ %p\n",
632 			    entry->buf_count, buf->address);
633 		}
634 		byte_count += PAGE_SIZE << page_order;
635 	}
636 
637 	temp_buflist = realloc(dma->buflist,
638 	    (dma->buf_count + entry->buf_count) * sizeof(*dma->buflist),
639 	    DRM_MEM_BUFS, M_NOWAIT);
640 	if (temp_buflist == NULL) {
641 		/* Free the entry because it isn't valid */
642 		drm_cleanup_buf_error(dev, entry);
643 		free(temp_pagelist, DRM_MEM_PAGES);
644 		return ENOMEM;
645 	}
646 	dma->buflist = temp_buflist;
647 
648 	for (i = 0; i < entry->buf_count; i++) {
649 		dma->buflist[i + dma->buf_count] = &entry->buflist[i];
650 	}
651 
652 	/* No allocations failed, so now we can replace the orginal pagelist
653 	 * with the new one.
654 	 */
655 	free(dma->pagelist, DRM_MEM_PAGES);
656 	dma->pagelist = temp_pagelist;
657 
658 	dma->buf_count += entry->buf_count;
659 	dma->seg_count += entry->seg_count;
660 	dma->page_count += entry->seg_count << page_order;
661 	dma->byte_count += PAGE_SIZE * (entry->seg_count << page_order);
662 
663 	request->count = entry->buf_count;
664 	request->size = size;
665 
666 	return 0;
667 
668 }
669 
670 static int drm_do_addbufs_sg(struct drm_device *dev, struct drm_buf_desc *request)
671 {
672 	drm_device_dma_t *dma = dev->dma;
673 	drm_buf_entry_t *entry;
674 	drm_buf_t *buf;
675 	unsigned long offset;
676 	unsigned long agp_offset;
677 	int count;
678 	int order;
679 	int size;
680 	int alignment;
681 	int page_order;
682 	int total;
683 	int byte_count;
684 	int i;
685 	drm_buf_t **temp_buflist;
686 
687 	count = request->count;
688 	order = drm_order(request->size);
689 	size = 1 << order;
690 
691 	alignment  = (request->flags & _DRM_PAGE_ALIGN)
692 	    ? round_page(size) : size;
693 	page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0;
694 	total = PAGE_SIZE << page_order;
695 
696 	byte_count = 0;
697 	agp_offset = request->agp_start;
698 
699 	DRM_DEBUG("count:      %d\n",  count);
700 	DRM_DEBUG("order:      %d\n",  order);
701 	DRM_DEBUG("size:       %d\n",  size);
702 	DRM_DEBUG("agp_offset: %ld\n", agp_offset);
703 	DRM_DEBUG("alignment:  %d\n",  alignment);
704 	DRM_DEBUG("page_order: %d\n",  page_order);
705 	DRM_DEBUG("total:      %d\n",  total);
706 
707 	entry = &dma->bufs[order];
708 
709 	entry->buflist = malloc(count * sizeof(*entry->buflist), DRM_MEM_BUFS,
710 	    M_NOWAIT | M_ZERO);
711 	if (entry->buflist == NULL)
712 		return ENOMEM;
713 
714 	entry->buf_size = size;
715 	entry->page_order = page_order;
716 
717 	offset = 0;
718 
719 	while (entry->buf_count < count) {
720 		buf          = &entry->buflist[entry->buf_count];
721 		buf->idx     = dma->buf_count + entry->buf_count;
722 		buf->total   = alignment;
723 		buf->order   = order;
724 		buf->used    = 0;
725 
726 		buf->offset  = (dma->byte_count + offset);
727 		buf->bus_address = agp_offset + offset;
728 		buf->address = (void *)(agp_offset + offset + dev->sg->handle);
729 		buf->next    = NULL;
730 		buf->pending = 0;
731 		buf->file_priv = NULL;
732 
733 		buf->dev_priv_size = dev->driver->buf_priv_size;
734 		buf->dev_private = malloc(buf->dev_priv_size, DRM_MEM_BUFS,
735 		    M_NOWAIT | M_ZERO);
736 		if (buf->dev_private == NULL) {
737 			/* Set count correctly so we free the proper amount. */
738 			entry->buf_count = count;
739 			drm_cleanup_buf_error(dev, entry);
740 			return ENOMEM;
741 		}
742 
743 		DRM_DEBUG("buffer %d @ %p\n",
744 		    entry->buf_count, buf->address);
745 
746 		offset += alignment;
747 		entry->buf_count++;
748 		byte_count += PAGE_SIZE << page_order;
749 	}
750 
751 	DRM_DEBUG("byte_count: %d\n", byte_count);
752 
753 	temp_buflist = realloc(dma->buflist,
754 	    (dma->buf_count + entry->buf_count) * sizeof(*dma->buflist),
755 	    DRM_MEM_BUFS, M_NOWAIT);
756 	if (temp_buflist == NULL) {
757 		/* Free the entry because it isn't valid */
758 		drm_cleanup_buf_error(dev, entry);
759 		return ENOMEM;
760 	}
761 	dma->buflist = temp_buflist;
762 
763 	for (i = 0; i < entry->buf_count; i++) {
764 		dma->buflist[i + dma->buf_count] = &entry->buflist[i];
765 	}
766 
767 	dma->buf_count += entry->buf_count;
768 	dma->byte_count += byte_count;
769 
770 	DRM_DEBUG("dma->buf_count : %d\n", dma->buf_count);
771 	DRM_DEBUG("entry->buf_count : %d\n", entry->buf_count);
772 
773 	request->count = entry->buf_count;
774 	request->size = size;
775 
776 	dma->flags = _DRM_DMA_USE_SG;
777 
778 	return 0;
779 }
780 
781 int drm_addbufs_agp(struct drm_device *dev, struct drm_buf_desc *request)
782 {
783 	int order, ret;
784 
785 	if (request->count < 0 || request->count > 4096)
786 		return EINVAL;
787 
788 	order = drm_order(request->size);
789 	if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER)
790 		return EINVAL;
791 
792 	DRM_SPINLOCK(&dev->dma_lock);
793 
794 	/* No more allocations after first buffer-using ioctl. */
795 	if (dev->buf_use != 0) {
796 		DRM_SPINUNLOCK(&dev->dma_lock);
797 		return EBUSY;
798 	}
799 	/* No more than one allocation per order */
800 	if (dev->dma->bufs[order].buf_count != 0) {
801 		DRM_SPINUNLOCK(&dev->dma_lock);
802 		return ENOMEM;
803 	}
804 
805 	ret = drm_do_addbufs_agp(dev, request);
806 
807 	DRM_SPINUNLOCK(&dev->dma_lock);
808 
809 	return ret;
810 }
811 
812 int drm_addbufs_sg(struct drm_device *dev, struct drm_buf_desc *request)
813 {
814 	int order, ret;
815 
816 	if (!DRM_SUSER(DRM_CURPROC))
817 		return EACCES;
818 
819 	if (request->count < 0 || request->count > 4096)
820 		return EINVAL;
821 
822 	order = drm_order(request->size);
823 	if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER)
824 		return EINVAL;
825 
826 	DRM_SPINLOCK(&dev->dma_lock);
827 
828 	/* No more allocations after first buffer-using ioctl. */
829 	if (dev->buf_use != 0) {
830 		DRM_SPINUNLOCK(&dev->dma_lock);
831 		return EBUSY;
832 	}
833 	/* No more than one allocation per order */
834 	if (dev->dma->bufs[order].buf_count != 0) {
835 		DRM_SPINUNLOCK(&dev->dma_lock);
836 		return ENOMEM;
837 	}
838 
839 	ret = drm_do_addbufs_sg(dev, request);
840 
841 	DRM_SPINUNLOCK(&dev->dma_lock);
842 
843 	return ret;
844 }
845 
846 int drm_addbufs_pci(struct drm_device *dev, struct drm_buf_desc *request)
847 {
848 	int order, ret;
849 
850 	if (!DRM_SUSER(DRM_CURPROC))
851 		return EACCES;
852 
853 	if (request->count < 0 || request->count > 4096)
854 		return EINVAL;
855 
856 	order = drm_order(request->size);
857 	if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER)
858 		return EINVAL;
859 
860 	DRM_SPINLOCK(&dev->dma_lock);
861 
862 	/* No more allocations after first buffer-using ioctl. */
863 	if (dev->buf_use != 0) {
864 		DRM_SPINUNLOCK(&dev->dma_lock);
865 		return EBUSY;
866 	}
867 	/* No more than one allocation per order */
868 	if (dev->dma->bufs[order].buf_count != 0) {
869 		DRM_SPINUNLOCK(&dev->dma_lock);
870 		return ENOMEM;
871 	}
872 
873 	ret = drm_do_addbufs_pci(dev, request);
874 
875 	DRM_SPINUNLOCK(&dev->dma_lock);
876 
877 	return ret;
878 }
879 
880 int drm_addbufs(struct drm_device *dev, void *data, struct drm_file *file_priv)
881 {
882 	struct drm_buf_desc *request = data;
883 	int err;
884 
885 	if (request->flags & _DRM_AGP_BUFFER)
886 		err = drm_addbufs_agp(dev, request);
887 	else if (request->flags & _DRM_SG_BUFFER)
888 		err = drm_addbufs_sg(dev, request);
889 	else
890 		err = drm_addbufs_pci(dev, request);
891 
892 	return err;
893 }
894 
895 int drm_infobufs(struct drm_device *dev, void *data, struct drm_file *file_priv)
896 {
897 	drm_device_dma_t *dma = dev->dma;
898 	struct drm_buf_info *request = data;
899 	int i;
900 	int count;
901 	int retcode = 0;
902 
903 	DRM_SPINLOCK(&dev->dma_lock);
904 	++dev->buf_use;		/* Can't allocate more after this call */
905 	DRM_SPINUNLOCK(&dev->dma_lock);
906 
907 	for (i = 0, count = 0; i < DRM_MAX_ORDER + 1; i++) {
908 		if (dma->bufs[i].buf_count)
909 			++count;
910 	}
911 
912 	DRM_DEBUG("count = %d\n", count);
913 
914 	if (request->count >= count) {
915 		for (i = 0, count = 0; i < DRM_MAX_ORDER + 1; i++) {
916 			if (dma->bufs[i].buf_count) {
917 				struct drm_buf_desc from;
918 
919 				from.count = dma->bufs[i].buf_count;
920 				from.size = dma->bufs[i].buf_size;
921 				from.low_mark = dma->bufs[i].freelist.low_mark;
922 				from.high_mark = dma->bufs[i].freelist.high_mark;
923 
924 				if (DRM_COPY_TO_USER(&request->list[count], &from,
925 				    sizeof(struct drm_buf_desc)) != 0) {
926 					retcode = EFAULT;
927 					break;
928 				}
929 
930 				DRM_DEBUG("%d %d %d %d %d\n",
931 				    i, dma->bufs[i].buf_count,
932 				    dma->bufs[i].buf_size,
933 				    dma->bufs[i].freelist.low_mark,
934 				    dma->bufs[i].freelist.high_mark);
935 				++count;
936 			}
937 		}
938 	}
939 	request->count = count;
940 
941 	return retcode;
942 }
943 
944 int drm_markbufs(struct drm_device *dev, void *data, struct drm_file *file_priv)
945 {
946 	drm_device_dma_t *dma = dev->dma;
947 	struct drm_buf_desc *request = data;
948 	int order;
949 
950 	DRM_DEBUG("%d, %d, %d\n",
951 		  request->size, request->low_mark, request->high_mark);
952 
953 
954 	order = drm_order(request->size);
955 	if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER ||
956 	    request->low_mark < 0 || request->high_mark < 0) {
957 		return EINVAL;
958 	}
959 
960 	DRM_SPINLOCK(&dev->dma_lock);
961 	if (request->low_mark > dma->bufs[order].buf_count ||
962 	    request->high_mark > dma->bufs[order].buf_count) {
963 		DRM_SPINUNLOCK(&dev->dma_lock);
964 		return EINVAL;
965 	}
966 
967 	dma->bufs[order].freelist.low_mark  = request->low_mark;
968 	dma->bufs[order].freelist.high_mark = request->high_mark;
969 	DRM_SPINUNLOCK(&dev->dma_lock);
970 
971 	return 0;
972 }
973 
974 int drm_freebufs(struct drm_device *dev, void *data, struct drm_file *file_priv)
975 {
976 	drm_device_dma_t *dma = dev->dma;
977 	struct drm_buf_free *request = data;
978 	int i;
979 	int idx;
980 	drm_buf_t *buf;
981 	int retcode = 0;
982 
983 	DRM_DEBUG("%d\n", request->count);
984 
985 	DRM_SPINLOCK(&dev->dma_lock);
986 	for (i = 0; i < request->count; i++) {
987 		if (DRM_COPY_FROM_USER(&idx, &request->list[i], sizeof(idx))) {
988 			retcode = EFAULT;
989 			break;
990 		}
991 		if (idx < 0 || idx >= dma->buf_count) {
992 			DRM_ERROR("Index %d (of %d max)\n",
993 			    idx, dma->buf_count - 1);
994 			retcode = EINVAL;
995 			break;
996 		}
997 		buf = dma->buflist[idx];
998 		if (buf->file_priv != file_priv) {
999 			DRM_ERROR("Process %d freeing buffer not owned\n",
1000 			    DRM_CURRENTPID);
1001 			retcode = EINVAL;
1002 			break;
1003 		}
1004 		drm_free_buffer(dev, buf);
1005 	}
1006 	DRM_SPINUNLOCK(&dev->dma_lock);
1007 
1008 	return retcode;
1009 }
1010 
1011 int drm_mapbufs(struct drm_device *dev, void *data, struct drm_file *file_priv)
1012 {
1013 	drm_device_dma_t *dma = dev->dma;
1014 	int retcode = 0;
1015 	const int zero = 0;
1016 	vm_offset_t address;
1017 	struct vmspace *vms;
1018 	vm_ooffset_t foff;
1019 	vm_size_t size;
1020 	vm_offset_t vaddr;
1021 	struct drm_buf_map *request = data;
1022 	int i;
1023 
1024 	vms = DRM_CURPROC->td_proc->p_vmspace;
1025 
1026 	DRM_SPINLOCK(&dev->dma_lock);
1027 	dev->buf_use++;		/* Can't allocate more after this call */
1028 	DRM_SPINUNLOCK(&dev->dma_lock);
1029 
1030 	if (request->count < dma->buf_count)
1031 		goto done;
1032 
1033 	if ((drm_core_has_AGP(dev) && (dma->flags & _DRM_DMA_USE_AGP)) ||
1034 	    (drm_core_check_feature(dev, DRIVER_SG) &&
1035 	    (dma->flags & _DRM_DMA_USE_SG))) {
1036 		drm_local_map_t *map = dev->agp_buffer_map;
1037 
1038 		if (map == NULL) {
1039 			retcode = EINVAL;
1040 			goto done;
1041 		}
1042 		size = round_page(map->size);
1043 		foff = map->offset;
1044 	} else {
1045 		size = round_page(dma->byte_count),
1046 		foff = 0;
1047 	}
1048 
1049 	vaddr = round_page((vm_offset_t)vms->vm_daddr + MAXDSIZ);
1050 #if __FreeBSD_version >= 600023
1051 	retcode = vm_mmap(&vms->vm_map, &vaddr, size, PROT_READ | PROT_WRITE,
1052 	    VM_PROT_ALL, MAP_SHARED | MAP_NOSYNC, OBJT_DEVICE,
1053 	    dev->devnode, foff);
1054 #else
1055 	retcode = vm_mmap(&vms->vm_map, &vaddr, size, PROT_READ | PROT_WRITE,
1056 	    VM_PROT_ALL, MAP_SHARED | MAP_NOSYNC,
1057 	    SLIST_FIRST(&dev->devnode->si_hlist), foff);
1058 #endif
1059 	if (retcode)
1060 		goto done;
1061 
1062 	request->virtual = (void *)vaddr;
1063 
1064 	for (i = 0; i < dma->buf_count; i++) {
1065 		if (DRM_COPY_TO_USER(&request->list[i].idx,
1066 		    &dma->buflist[i]->idx, sizeof(request->list[0].idx))) {
1067 			retcode = EFAULT;
1068 			goto done;
1069 		}
1070 		if (DRM_COPY_TO_USER(&request->list[i].total,
1071 		    &dma->buflist[i]->total, sizeof(request->list[0].total))) {
1072 			retcode = EFAULT;
1073 			goto done;
1074 		}
1075 		if (DRM_COPY_TO_USER(&request->list[i].used, &zero,
1076 		    sizeof(zero))) {
1077 			retcode = EFAULT;
1078 			goto done;
1079 		}
1080 		address = vaddr + dma->buflist[i]->offset; /* *** */
1081 		if (DRM_COPY_TO_USER(&request->list[i].address, &address,
1082 		    sizeof(address))) {
1083 			retcode = EFAULT;
1084 			goto done;
1085 		}
1086 	}
1087 
1088  done:
1089 	request->count = dma->buf_count;
1090 
1091 	DRM_DEBUG("%d buffers, retcode = %d\n", request->count, retcode);
1092 
1093 	return retcode;
1094 }
1095 
1096 /*
1097  * Compute order.  Can be made faster.
1098  */
1099 int drm_order(unsigned long size)
1100 {
1101 	int order;
1102 
1103 	if (size == 0)
1104 		return 0;
1105 
1106 	order = flsl(size) - 1;
1107 	if (size & ~(1ul << order))
1108 		++order;
1109 
1110 	return order;
1111 }
1112