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