add error messages
[ps3freebsd_ps3gpu.git] / ps3gpu.c
blobc74dabe87856c95313a7371d0217a51edae33cb4
1 /*-
2 * Copyright (C) 2011, 2012 glevand <geoffrey.levand@mail.ru>
3 * All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer,
10 * without modification, immediately at the beginning of the file.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 * $FreeBSD$
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
32 #include <sys/param.h>
33 #include <sys/bus.h>
34 #include <sys/conf.h>
35 #include <sys/kernel.h>
36 #include <sys/mman.h>
37 #include <sys/module.h>
38 #include <sys/systm.h>
39 #include <sys/fcntl.h>
40 #include <sys/sx.h>
41 #include <sys/malloc.h>
42 #include <sys/ioccom.h>
44 #include <vm/pmap.h>
46 #include <machine/pmap.h>
48 #include <powerpc/ps3/ps3-hvcall.h>
50 #include "ps3gpu_heap.h"
51 #include "ps3gpu_ctl.h"
52 #include "ps3gpu.h"
54 static int ps3gpu_open(struct cdev *dev, int oflags, int fmt,
55 struct thread *td);
56 static int ps3gpu_mmap(struct cdev *dev, vm_ooffset_t offset,
57 vm_paddr_t *paddr, int nprot, vm_memattr_t *memattr);
58 static int ps3gpu_ioctl(struct cdev *dev, u_long cmd, caddr_t data,
59 int fflag, struct thread *td);
61 static struct ps3gpu_memory_map *ps3gpu_dev_get_mmap(struct ps3gpu_device *dev,
62 unsigned long handle);
63 static unsigned long ps3gpu_dev_alloc_handle(struct ps3gpu_device *dev);
64 static void ps3gpu_dev_free_handle(struct ps3gpu_device *dev,
65 unsigned long handle);
67 static struct cdevsw ps3gpu_cdevsw = {
68 .d_version = D_VERSION,
69 .d_open = ps3gpu_open,
70 .d_mmap = ps3gpu_mmap,
71 .d_ioctl = ps3gpu_ioctl,
72 .d_name = "ps3gpu",
75 static struct ps3gpu_device *ps3gpu_dev;
77 static struct cdev *ps3gpu_cdev;
79 static MALLOC_DEFINE(M_PS3GPU, "ps3gpu", "PS3 GPU");
80 static MALLOC_DEFINE(M_PS3GPU_GART, "ps3gpu_gart", "PS3 GPU GART memory");
82 int
83 ps3gpu_context_allocate(int vram_size, struct ps3gpu_context **pcontext)
85 struct ps3gpu_context *context;
86 int id;
87 int err;
89 sx_xlock(&ps3gpu_dev->d_lock);
91 for (id = 0; id < PS3GPU_DEVICE_MAX_CONTEXTS; id++) {
92 if (!ps3gpu_dev->d_context[id])
93 break;
96 if (id >= PS3GPU_DEVICE_MAX_CONTEXTS) {
97 sx_xunlock(&ps3gpu_dev->d_lock);
98 return (ENXIO);
101 context = malloc(sizeof(*context), M_PS3GPU, M_WAITOK | M_ZERO);
102 if (!context) {
103 sx_xunlock(&ps3gpu_dev->d_lock);
104 return (ENOMEM);
107 sx_init(&context->ctx_lock, "ps3gpu_context");
109 context->ctx_dev = ps3gpu_dev;
110 context->ctx_id = id;
111 context->ctx_vram_size = vram_size * 1024 * 1024;
113 err = lv1_gpu_memory_allocate(context->ctx_vram_size,
114 0 /* 0x80000 */, 0 /* 0x300000 */, 0 /* 0xf */, 0 /* 0x8 */,
115 &context->ctx_memory_handle, &context->ctx_vram_paddr);
116 if (err) {
117 printf("lv1_gpu_memory_allocate failed (%d)\n", err);
118 err = ENXIO;
119 goto free_context;
122 context->ctx_vram_vaddr = (unsigned long) pmap_mapdev(context->ctx_vram_paddr,
123 context->ctx_vram_size);
124 if (!context->ctx_vram_vaddr) {
125 err = ENXIO;
126 goto free_vram;
129 err = lv1_gpu_context_allocate(context->ctx_memory_handle, 0x822,
130 &context->ctx_handle, &context->ctx_control_paddr,
131 &context->ctx_driver_info_paddr, &context->ctx_reports_paddr,
132 &context->ctx_reports_size);
133 if (err) {
134 printf("lv1_gpu_context_allocate failed (%d)\n", err);
135 err = ENXIO;
136 goto unmap_vram;
139 context->ctx_control_size = PAGE_SIZE;
141 context->ctx_control_vaddr = (unsigned long) pmap_mapdev(context->ctx_control_paddr,
142 context->ctx_control_size);
143 if (!context->ctx_control_vaddr) {
144 err = ENXIO;
145 goto free_gpu_context;
148 context->ctx_driver_info_size = 4 * PAGE_SIZE;
150 context->ctx_driver_info_vaddr = (unsigned long) pmap_mapdev(context->ctx_driver_info_paddr,
151 context->ctx_driver_info_size);
152 if (!context->ctx_driver_info_vaddr) {
153 err = ENXIO;
154 goto unmap_control;
157 context->ctx_reports_vaddr = (unsigned long) pmap_mapdev(context->ctx_reports_paddr,
158 context->ctx_reports_size);
159 if (!context->ctx_reports_vaddr) {
160 err = ENXIO;
161 goto unmap_driver_info;
164 err = ps3gpu_heap_init(&context->ctx_heap[PS3GPU_MEMORY_TYPE_VIDEO],
165 context->ctx_vram_size);
166 if (err)
167 goto unmap_reports;
169 err = ps3gpu_heap_init(&context->ctx_heap[PS3GPU_MEMORY_TYPE_GART],
170 256 * 1024 * 1024);
171 if (err)
172 goto fini_heap_vram;
174 TAILQ_INIT(&context->ctx_mem_queue);
176 ps3gpu_dev->d_context[id] = context;
178 sx_xunlock(&ps3gpu_dev->d_lock);
180 *pcontext = context;
182 return (0);
184 fini_heap_vram:
186 ps3gpu_heap_fini(&context->ctx_heap[PS3GPU_MEMORY_TYPE_VIDEO]);
188 unmap_reports:
190 pmap_unmapdev(context->ctx_reports_vaddr, context->ctx_reports_size);
192 unmap_driver_info:
194 pmap_unmapdev(context->ctx_driver_info_vaddr, context->ctx_driver_info_size);
196 unmap_control:
198 pmap_unmapdev(context->ctx_control_vaddr, context->ctx_control_size);
200 free_gpu_context:
202 lv1_gpu_context_free(context->ctx_handle);
204 unmap_vram:
206 pmap_unmapdev(context->ctx_vram_vaddr,
207 context->ctx_vram_size);
209 free_vram:
211 lv1_gpu_memory_free(context->ctx_memory_handle);
213 free_context:
215 sx_destroy(&context->ctx_lock);
217 free(context, M_PS3GPU);
219 sx_xunlock(&ps3gpu_dev->d_lock);
221 return (err);
225 ps3gpu_context_free(struct ps3gpu_context *context)
227 struct ps3gpu_memory *mem;
229 KASSERT(context != NULL, ("invalid context"));
231 sx_xlock(&context->ctx_dev->d_lock);
232 ps3gpu_dev->d_context[context->ctx_id] = NULL;
233 sx_xunlock(&context->ctx_dev->d_lock);
235 while ((mem = TAILQ_FIRST(&context->ctx_mem_queue)))
236 ps3gpu_memory_free(mem);
238 pmap_unmapdev(context->ctx_vram_vaddr, context->ctx_vram_size);
239 pmap_unmapdev(context->ctx_control_vaddr, context->ctx_control_size);
240 pmap_unmapdev(context->ctx_driver_info_vaddr,
241 context->ctx_driver_info_size);
242 pmap_unmapdev(context->ctx_reports_vaddr, context->ctx_reports_size);
244 ps3gpu_heap_fini(&context->ctx_heap[PS3GPU_MEMORY_TYPE_VIDEO]);
245 ps3gpu_heap_fini(&context->ctx_heap[PS3GPU_MEMORY_TYPE_GART]);
247 lv1_gpu_context_free(context->ctx_handle);
249 lv1_gpu_memory_free(context->ctx_memory_handle);
251 sx_destroy(&context->ctx_lock);
253 free(context, M_PS3GPU);
255 return (0);
259 ps3gpu_memory_allocate(struct ps3gpu_context *context,
260 int type, int size, int align, struct ps3gpu_memory **pmem)
262 struct ps3gpu_memory *mem;
263 int start;
264 int i;
265 int err;
267 KASSERT(context != NULL, ("invalid context"));
268 KASSERT(type == PS3GPU_MEMORY_TYPE_VIDEO ||
269 type == PS3GPU_MEMORY_TYPE_GART, ("invalid memory type"));
270 KASSERT((size % PAGE_SIZE) == 0,
271 ("size is not a multiple of page size"));
272 KASSERT(align >= PAGE_SHIFT, ("alignment is too small"));
274 sx_xlock(&context->ctx_lock);
276 err = ps3gpu_heap_allocate(&context->ctx_heap[type],
277 size, align, &start);
278 if (err) {
279 sx_xunlock(&context->ctx_lock);
280 return (err);
283 mem = malloc(sizeof(*mem), M_PS3GPU, M_WAITOK | M_ZERO);
284 if (!mem) {
285 err = ENOMEM;
286 goto free_heap;
289 mem->m_context = context;
291 mem->m_type = type;
292 mem->m_start = start;
293 mem->m_size = size;
295 if (type == PS3GPU_MEMORY_TYPE_VIDEO) {
296 mem->m_paddr = context->ctx_vram_paddr + mem->m_start;
297 mem->m_vaddr = context->ctx_vram_vaddr + mem->m_start;
298 mem->m_gaddr = mem->m_start;
299 } else {
300 mem->m_vaddr = (unsigned long) malloc(size, M_PS3GPU_GART,
301 M_WAITOK | M_ZERO);
302 if (!mem->m_vaddr) {
303 err = ENOMEM;
304 goto free_memory;
307 mem->m_gaddr = PS3GPU_MEMORY_GART_ADDRESS_OFFSET +
308 mem->m_start;
310 for (i = 0; i < size / PAGE_SIZE; i++) {
311 err = lv1_gpu_context_iomap(context->ctx_handle,
312 mem->m_gaddr + i * PAGE_SIZE,
313 vtophys(mem->m_vaddr + i * PAGE_SIZE),
314 PAGE_SIZE, 0xe000000000000800ul);
315 if (err) {
316 printf("lv1_gpu_context_iomap failed (%d)\n", err);
317 err = ENXIO;
318 goto free_gart;
323 TAILQ_INSERT_TAIL(&context->ctx_mem_queue, mem, m_queue);
325 sx_xunlock(&context->ctx_lock);
327 *pmem = mem;
329 return (0);
331 free_gart:
333 for (i = 0; i < size / PAGE_SIZE; i++) {
334 lv1_gpu_context_iomap(context->ctx_handle,
335 mem->m_gaddr + i * PAGE_SIZE,
336 vtophys(mem->m_vaddr + i * PAGE_SIZE),
337 PAGE_SIZE, 0x2000000000000000ul);
340 free((void *) mem->m_vaddr, M_PS3GPU_GART);
342 free_memory:
344 free(mem, M_PS3GPU);
346 free_heap:
348 ps3gpu_heap_free(&context->ctx_heap[type], start, size);
350 sx_xunlock(&context->ctx_lock);
352 return (err);
356 ps3gpu_memory_free(struct ps3gpu_memory *mem)
358 struct ps3gpu_context *context = mem->m_context;
359 int i;
361 KASSERT(mem != NULL, ("invalid memory"));
362 KASSERT(mem->m_type == PS3GPU_MEMORY_TYPE_VIDEO ||
363 mem->m_type == PS3GPU_MEMORY_TYPE_GART, ("invalid memory type"));
364 KASSERT(context != NULL, ("invalid context"));
366 sx_xlock(&context->ctx_lock);
368 TAILQ_REMOVE(&context->ctx_mem_queue, mem, m_queue);
370 if (mem->m_type == PS3GPU_MEMORY_TYPE_GART) {
371 for (i = 0; i < mem->m_size / PAGE_SIZE; i++) {
372 lv1_gpu_context_iomap(context->ctx_handle,
373 mem->m_gaddr + i * PAGE_SIZE,
374 vtophys(mem->m_vaddr + i * PAGE_SIZE),
375 PAGE_SIZE, 0x2000000000000000ul);
378 free((void *) mem->m_vaddr, M_PS3GPU_GART);
381 ps3gpu_heap_free(&context->ctx_heap[mem->m_type],
382 mem->m_start, mem->m_size);
384 free(mem, M_PS3GPU);
386 sx_xunlock(&context->ctx_lock);
388 return (0);
392 ps3gpu_setup_control(struct ps3gpu_context *context,
393 unsigned int put, unsigned int get, unsigned int ref)
395 int err;
397 KASSERT(context != NULL, ("invalid context"));
399 sx_xlock(&context->ctx_lock);
401 err = lv1_gpu_context_attribute(context->ctx_handle, 0x1,
402 put, get, ref, 0);
403 if (err) {
404 printf("lv1_gpu_context_attribute failed (%d)\n", err);
405 sx_xunlock(&context->ctx_lock);
406 return (ENXIO);
409 sx_xunlock(&context->ctx_lock);
411 return (0);
415 ps3gpu_set_flip_mode(struct ps3gpu_context *context, int head, int mode)
417 int err;
419 KASSERT(context != NULL, ("invalid context"));
420 KASSERT(head == PS3GPU_HEAD_A || head == PS3GPU_HEAD_B,
421 ("invalid head"));
422 KASSERT(mode == PS3GPU_FLIP_MODE_HSYNC ||
423 PS3GPU_FLIP_MODE_VSYNC, ("invalid flip mode"));
425 sx_xlock(&context->ctx_lock);
427 err = lv1_gpu_attribute(0x2, head, 0, 0, 0);
428 if (err) {
429 printf("lv1_gpu_attribute failed (%d)\n", err);
430 sx_xunlock(&context->ctx_lock);
431 return (ENXIO);
434 err = lv1_gpu_context_attribute(context->ctx_handle, 0x101,
435 head, mode, 0, 0);
436 if (err) {
437 printf("lv1_gpu_context_attribute failed (%d)\n", err);
438 sx_xunlock(&context->ctx_lock);
439 return (ENXIO);
442 sx_xunlock(&context->ctx_lock);
444 return (0);
448 ps3gpu_reset_flip_status(struct ps3gpu_context *context, int head)
450 int err;
452 KASSERT(context != NULL, ("invalid context"));
453 KASSERT(head == PS3GPU_HEAD_A || head == PS3GPU_HEAD_B,
454 ("invalid head"));
456 sx_xlock(&context->ctx_lock);
458 err = lv1_gpu_context_attribute(context->ctx_handle, 0x10a,
459 head, 0x7ffffffful, 0x00000000ul, 0);
460 if (err) {
461 printf("lv1_gpu_context_attribute failed (%d)\n", err);
462 sx_xunlock(&context->ctx_lock);
463 return (ENXIO);
466 sx_xunlock(&context->ctx_lock);
468 return (0);
472 ps3gpu_flip(struct ps3gpu_context *context, int head,
473 unsigned int offset)
475 int err;
477 KASSERT(context != NULL, ("invalid context"));
478 KASSERT(head == PS3GPU_HEAD_A || head == PS3GPU_HEAD_B,
479 ("invalid head"));
481 sx_xlock(&context->ctx_lock);
483 err = lv1_gpu_context_attribute(context->ctx_handle, 0x102,
484 head, offset, 0, 0);
485 if (err) {
486 printf("lv1_gpu_context_attribute failed (%d)\n", err);
487 sx_xunlock(&context->ctx_lock);
488 return (ENXIO);
491 sx_xunlock(&context->ctx_lock);
493 return (0);
497 ps3gpu_display_buffer_set(struct ps3gpu_context *context,
498 int buffer_id, int width, int height, int pitch,
499 unsigned int offset)
501 int err;
503 KASSERT(context != NULL, ("invalid context"));
504 KASSERT(buffer_id >= 0 &&
505 buffer_id < PS3GPU_CONTEXT_MAX_DISPLAY_BUFFERS,
506 ("invalid display buffer id"));
508 sx_xlock(&context->ctx_lock);
510 err = lv1_gpu_context_attribute(context->ctx_handle, 0x104,
511 buffer_id, (((unsigned long) width) << 32) | height,
512 (((unsigned long) pitch) << 32) | offset, 0);
513 if (err) {
514 printf("lv1_gpu_context_attribute failed (%d)\n", err);
515 sx_xunlock(&context->ctx_lock);
516 return (ENXIO);
519 sx_xunlock(&context->ctx_lock);
521 return (0);
525 ps3gpu_display_buffer_unset(struct ps3gpu_context *context,
526 int buffer_id)
528 int err;
530 KASSERT(context != NULL, ("invalid context"));
531 KASSERT(buffer_id >= 0 &&
532 buffer_id < PS3GPU_CONTEXT_MAX_DISPLAY_BUFFERS,
533 ("invalid display buffer id"));
535 sx_xlock(&context->ctx_lock);
537 err = lv1_gpu_context_attribute(context->ctx_handle, 0x105,
538 buffer_id, 0, 0, 0);
539 if (err) {
540 printf("lv1_gpu_context_attribute failed (%d)\n", err);
541 sx_xunlock(&context->ctx_lock);
542 return (ENXIO);
545 sx_xunlock(&context->ctx_lock);
547 return (0);
551 ps3gpu_display_buffer_flip(struct ps3gpu_context *context, int head,
552 int buffer_id)
554 int err;
556 KASSERT(context != NULL, ("invalid context"));
557 KASSERT(head == PS3GPU_HEAD_A || head == PS3GPU_HEAD_B,
558 ("invalid head"));
559 KASSERT(buffer_id >= 0 &&
560 buffer_id < PS3GPU_CONTEXT_MAX_DISPLAY_BUFFERS,
561 ("invalid display buffer id"));
563 sx_xlock(&context->ctx_lock);
565 err = lv1_gpu_context_attribute(context->ctx_handle, 0x102,
566 head, 0x80000000ul | (ps3gpu_context_get_channel(context) << 8) |
567 buffer_id, 0, 0);
568 if (err) {
569 printf("lv1_gpu_context_attribute failed (%d)\n", err);
570 sx_xunlock(&context->ctx_lock);
571 return (ENXIO);
574 sx_xunlock(&context->ctx_lock);
576 return (0);
580 ps3gpu_tile_get_pitch(int pitch)
582 static const int tile_pitches[] = {
583 0x00000000, 0x00000200, 0x00000300, 0x00000400,
584 0x00000500, 0x00000600, 0x00000700, 0x00000800,
585 0x00000a00, 0x00000c00, 0x00000d00, 0x00000e00,
586 0x00001000, 0x00001400, 0x00001800, 0x00001a00,
587 0x00001c00, 0x00002000, 0x00002800, 0x00003000,
588 0x00003400, 0x00003800, 0x00004000, 0x00005000,
589 0x00006000, 0x00006800, 0x00007000, 0x00008000,
590 0x0000a000, 0x0000c000, 0x0000d000, 0x0000e000,
591 0x00010000,
594 int i;
596 for (i = 0; i < sizeof(tile_pitches) / sizeof(tile_pitches[0]) - 1; i++) {
597 if ((tile_pitches[i] < pitch) && (pitch <= tile_pitches[i + 1]))
598 return (tile_pitches[i + 1]);
601 return (0);
605 ps3gpu_tile_set(struct ps3gpu_context *context,
606 int tile_id, int mem_type, int size, int pitch, int cmp_mode, int bank,
607 int base, unsigned int offset)
609 int location;
610 unsigned long p1, p2, p3, p4;
611 int err;
613 KASSERT(context != NULL, ("invalid context"));
614 KASSERT(tile_id >= 0 &&
615 tile_id < PS3GPU_CONTEXT_MAX_TILES,
616 ("invalid tile id"));
617 KASSERT(mem_type == PS3GPU_MEMORY_TYPE_VIDEO ||
618 mem_type == PS3GPU_MEMORY_TYPE_GART, ("invalid memory type"));
620 location = (mem_type == PS3GPU_MEMORY_TYPE_GART) ? 1 : 0;
622 p1 = (location << 31) | (offset & ~0xfffful) | (bank << 4) | (location + 1);
623 p2 = (location << 31) | ((offset + size - 1) & ~0xfffful);
624 p3 = pitch & ~0xfffful;
625 p4 = 0x40000000ul | (cmp_mode << 26) | ((base + ((size - 1) >> 16)) << 13) | base;
627 sx_xlock(&context->ctx_lock);
629 err = lv1_gpu_context_attribute(context->ctx_handle, 0x300,
630 tile_id, (p1 << 32) | p2, (p3 << 32) | p4, 0);
631 if (err) {
632 printf("lv1_gpu_context_attribute failed (%d)\n", err);
633 sx_xunlock(&context->ctx_lock);
634 return (ENXIO);
637 sx_xunlock(&context->ctx_lock);
639 return (0);
643 ps3gpu_tile_unset(struct ps3gpu_context *context,
644 int tile_id, int mem_type, int bank, unsigned int offset)
646 int location;
647 unsigned long p1;
648 int err;
650 KASSERT(context != NULL, ("invalid context"));
651 KASSERT(tile_id >= 0 &&
652 tile_id < PS3GPU_CONTEXT_MAX_TILES,
653 ("invalid tile id"));
654 KASSERT(mem_type == PS3GPU_MEMORY_TYPE_VIDEO ||
655 mem_type == PS3GPU_MEMORY_TYPE_GART, ("invalid memory type"));
657 location = (mem_type == PS3GPU_MEMORY_TYPE_GART) ? 1 : 0;
659 p1 = (location << 31) | (offset & ~0xfffful) | (bank << 4);
661 sx_xlock(&context->ctx_lock);
663 err = lv1_gpu_context_attribute(context->ctx_handle, 0x300,
664 tile_id, p1 << 32, 0, 0);
665 if (err) {
666 printf("lv1_gpu_context_attribute failed (%d)\n", err);
667 sx_xunlock(&context->ctx_lock);
668 return (ENXIO);
671 sx_xunlock(&context->ctx_lock);
673 return (0);
677 ps3gpu_cursor_initialize(struct ps3gpu_context *context, int head)
679 int err;
681 KASSERT(context != NULL, ("invalid context"));
682 KASSERT(head == PS3GPU_HEAD_A || head == PS3GPU_HEAD_B,
683 ("invalid head"));
685 sx_xlock(&context->ctx_lock);
687 err = lv1_gpu_context_attribute(context->ctx_handle, 0x10b,
688 head, 0x1, 0, 0);
689 if (err) {
690 printf("lv1_gpu_context_attribute failed (%d)\n", err);
691 sx_xunlock(&context->ctx_lock);
692 return (ENXIO);
695 sx_xunlock(&context->ctx_lock);
697 return (0);
701 ps3gpu_cursor_set_image(struct ps3gpu_context *context, int head,
702 unsigned int offset)
704 int err;
706 KASSERT(context != NULL, ("invalid context"));
707 KASSERT(head == PS3GPU_HEAD_A || head == PS3GPU_HEAD_B,
708 ("invalid head"));
710 sx_xlock(&context->ctx_lock);
712 err = lv1_gpu_context_attribute(context->ctx_handle, 0x10b,
713 head, 0x2, offset, 0);
714 if (err) {
715 printf("lv1_gpu_context_attribute failed (%d)\n", err);
716 sx_xunlock(&context->ctx_lock);
717 return (ENXIO);
720 sx_xunlock(&context->ctx_lock);
722 return (0);
726 ps3gpu_cursor_set_position(struct ps3gpu_context *context, int head,
727 int x, int y)
729 int err;
731 KASSERT(context != NULL, ("invalid context"));
732 KASSERT(head == PS3GPU_HEAD_A || head == PS3GPU_HEAD_B,
733 ("invalid head"));
735 sx_xlock(&context->ctx_lock);
737 err = lv1_gpu_context_attribute(context->ctx_handle, 0x10b,
738 head, 0x3, x, y);
739 if (err) {
740 printf("lv1_gpu_context_attribute failed (%d)\n", err);
741 sx_xunlock(&context->ctx_lock);
742 return (ENXIO);
745 sx_xunlock(&context->ctx_lock);
747 return (0);
751 ps3gpu_cursor_enable(struct ps3gpu_context *context, int head,
752 int enable)
754 int err;
756 KASSERT(context != NULL, ("invalid context"));
757 KASSERT(head == PS3GPU_HEAD_A || head == PS3GPU_HEAD_B,
758 ("invalid head"));
760 sx_xlock(&context->ctx_lock);
762 err = lv1_gpu_context_attribute(context->ctx_handle, 0x10c,
763 head, enable ? 0x1 : 0x2, 0, 0);
764 if (err) {
765 printf("lv1_gpu_context_attribute failed (%d)\n", err);
766 sx_xunlock(&context->ctx_lock);
767 return (ENXIO);
770 sx_xunlock(&context->ctx_lock);
772 return (0);
775 static struct ps3gpu_context *
776 ps3gpu_user_get_context(struct ps3gpu_user *user, int id)
778 struct ps3gpu_context *context;
780 KASSERT(user != NULL, ("invalid user"));
782 sx_xlock(&user->u_lock);
784 TAILQ_FOREACH(context, &user->u_context_queue, ctx_user_queue) {
785 if (context->ctx_id == id) {
786 sx_xunlock(&user->u_lock);
787 return (context);
791 sx_xunlock(&user->u_lock);
793 return (NULL);
796 static int
797 ps3gpu_ctl_context_allocate(struct ps3gpu_user *user,
798 struct ps3gpu_ctl_context_allocate *req)
800 struct ps3gpu_context *context;
801 struct ps3gpu_memory *mem;
802 struct ps3gpu_memory_map *control_mmap;
803 struct ps3gpu_memory_map *driver_info_mmap;
804 struct ps3gpu_memory_map *reports_mmap;
805 int err;
807 KASSERT(user != NULL, ("invalid user"));
808 KASSERT(req != NULL, ("invalid request"));
810 err = ps3gpu_context_allocate(req->vram_size, &context);
811 if (err)
812 return (err);
814 context->ctx_user = user;
816 mem = malloc(sizeof(*mem), M_PS3GPU, M_WAITOK | M_ZERO);
817 if (!mem) {
818 err = ENOMEM;
819 goto free_context;
822 mem->m_context = context;
824 mem->m_type = PS3GPU_MEMORY_TYPE_REGISTER;
825 mem->m_size = context->ctx_control_size;
827 mem->m_paddr = context->ctx_control_paddr;
828 mem->m_vaddr = context->ctx_control_vaddr;
830 context->ctx_control_mem = mem;
832 control_mmap = malloc(sizeof(*control_mmap), M_PS3GPU,
833 M_WAITOK | M_ZERO);
834 if (!control_mmap) {
835 err = ENOMEM;
836 goto free_control_memory;
839 control_mmap->mm_mem = mem;
840 control_mmap->mm_handle = ps3gpu_dev_alloc_handle(context->ctx_dev);
842 mem = malloc(sizeof(*mem), M_PS3GPU, M_WAITOK | M_ZERO);
843 if (!mem) {
844 err = ENOMEM;
845 goto free_control_memory_map;
848 mem->m_context = context;
850 mem->m_type = PS3GPU_MEMORY_TYPE_REGISTER;
851 mem->m_size = context->ctx_driver_info_size;
853 mem->m_paddr = context->ctx_driver_info_paddr;
854 mem->m_vaddr = context->ctx_driver_info_vaddr;
856 context->ctx_driver_info_mem = mem;
858 driver_info_mmap = malloc(sizeof(*driver_info_mmap), M_PS3GPU,
859 M_WAITOK | M_ZERO);
860 if (!driver_info_mmap) {
861 err = ENOMEM;
862 goto free_driver_info_memory;
865 driver_info_mmap->mm_mem = mem;
866 driver_info_mmap->mm_handle = ps3gpu_dev_alloc_handle(context->ctx_dev);
868 mem = malloc(sizeof(*mem), M_PS3GPU, M_WAITOK | M_ZERO);
869 if (!mem) {
870 err = ENOMEM;
871 goto free_driver_info_memory_map;
874 mem->m_context = context;
876 mem->m_type = PS3GPU_MEMORY_TYPE_REGISTER;
877 mem->m_size = context->ctx_reports_size;
879 mem->m_paddr = context->ctx_reports_paddr;
880 mem->m_vaddr = context->ctx_reports_vaddr;
882 context->ctx_reports_mem = mem;
884 reports_mmap = malloc(sizeof(*reports_mmap), M_PS3GPU,
885 M_WAITOK | M_ZERO);
886 if (!reports_mmap) {
887 err = ENOMEM;
888 goto free_reports_memory;
891 reports_mmap->mm_mem = mem;
892 reports_mmap->mm_handle = ps3gpu_dev_alloc_handle(context->ctx_dev);
894 sx_xlock(&context->ctx_dev->d_lock);
895 TAILQ_INSERT_TAIL(&context->ctx_dev->d_mmap_queue, control_mmap, mm_queue);
896 TAILQ_INSERT_TAIL(&context->ctx_dev->d_mmap_queue, driver_info_mmap, mm_queue);
897 TAILQ_INSERT_TAIL(&context->ctx_dev->d_mmap_queue, reports_mmap, mm_queue);
898 sx_xunlock(&context->ctx_dev->d_lock);
900 sx_xlock(&user->u_lock);
901 TAILQ_INSERT_TAIL(&user->u_context_queue, context, ctx_user_queue);
902 sx_xunlock(&user->u_lock);
904 req->context_id = context->ctx_id;
905 req->control_handle = control_mmap->mm_handle;
906 req->control_size = control_mmap->mm_mem->m_size;
907 req->driver_info_handle = driver_info_mmap->mm_handle;
908 req->driver_info_size = driver_info_mmap->mm_mem->m_size;
909 req->reports_handle = reports_mmap->mm_handle;
910 req->reports_size = reports_mmap->mm_mem->m_size;
912 return (0);
914 free_reports_memory:
916 free(context->ctx_reports_mem, M_PS3GPU);
918 free_driver_info_memory_map:
920 ps3gpu_dev_free_handle(context->ctx_dev, driver_info_mmap->mm_handle);
921 free(driver_info_mmap, M_PS3GPU);
923 free_driver_info_memory:
925 free(context->ctx_driver_info_mem, M_PS3GPU);
927 free_control_memory_map:
929 ps3gpu_dev_free_handle(context->ctx_dev, control_mmap->mm_handle);
930 free(control_mmap, M_PS3GPU);
932 free_control_memory:
934 free(context->ctx_control_mem, M_PS3GPU);
936 free_context:
938 ps3gpu_context_free(context);
940 return (err);
943 static int
944 ps3gpu_ctl_context_free(struct ps3gpu_user *user,
945 struct ps3gpu_ctl_context_free *req)
947 struct ps3gpu_context *context;
948 struct ps3gpu_memory_map *mmap, *mmap_temp;
950 KASSERT(user != NULL, ("invalid user"));
951 KASSERT(req != NULL, ("invalid request"));
953 context = ps3gpu_user_get_context(user, req->context_id);
954 if (!context)
955 return (EINVAL);
957 sx_xlock(&user->u_lock);
958 TAILQ_REMOVE(&user->u_context_queue, context, ctx_user_queue);
959 sx_xunlock(&user->u_lock);
961 sx_xlock(&context->ctx_dev->d_lock);
963 TAILQ_FOREACH_SAFE(mmap, &context->ctx_dev->d_mmap_queue, mm_queue, mmap_temp) {
964 if (mmap->mm_mem->m_context == context) {
965 TAILQ_REMOVE(&context->ctx_dev->d_mmap_queue, mmap, mm_queue);
966 free_unr(context->ctx_dev->d_mmap_unrhdr,
967 mmap->mm_handle >> PS3GPU_MEMORY_MAP_HANDLE_SHIFT);
968 free(mmap, M_PS3GPU);
972 sx_xunlock(&context->ctx_dev->d_lock);
974 free(context->ctx_control_mem, M_PS3GPU);
975 free(context->ctx_driver_info_mem, M_PS3GPU);
976 free(context->ctx_reports_mem, M_PS3GPU);
978 ps3gpu_context_free(context);
980 return (0);
983 static int
984 ps3gpu_ctl_memory_allocate(struct ps3gpu_user *user,
985 struct ps3gpu_ctl_memory_allocate *req)
987 struct ps3gpu_context *context;
988 struct ps3gpu_memory *mem;
989 struct ps3gpu_memory_map *mmap;
990 int type;
991 int err;
993 KASSERT(user != NULL, ("invalid user"));
994 KASSERT(req != NULL, ("invalid request"));
996 switch (req->type) {
997 case PS3GPU_CTL_MEMORY_TYPE_VIDEO:
998 type = PS3GPU_MEMORY_TYPE_VIDEO;
999 break;
1000 case PS3GPU_CTL_MEMORY_TYPE_GART:
1001 type = PS3GPU_MEMORY_TYPE_GART;
1002 break;
1003 default:
1004 return (EINVAL);
1007 if (req->size % PAGE_SIZE)
1008 return (EINVAL);
1010 if (req->align < PAGE_SHIFT)
1011 return (EINVAL);
1013 context = ps3gpu_user_get_context(user, req->context_id);
1014 if (!context)
1015 return (EINVAL);
1017 err = ps3gpu_memory_allocate(context, type, req->size, req->align,
1018 &mem);
1019 if (err)
1020 return (err);
1022 mmap = malloc(sizeof(*mmap), M_PS3GPU, M_WAITOK | M_ZERO);
1023 if (err) {
1024 ps3gpu_memory_free(mem);
1025 return (ENOMEM);
1028 mmap->mm_mem = mem;
1029 mmap->mm_handle = ps3gpu_dev_alloc_handle(context->ctx_dev);
1031 sx_xlock(&context->ctx_dev->d_lock);
1032 TAILQ_INSERT_TAIL(&context->ctx_dev->d_mmap_queue, mmap, mm_queue);
1033 sx_xunlock(&context->ctx_dev->d_lock);
1035 req->handle = mmap->mm_handle;
1036 req->gpu_addr = mmap->mm_mem->m_gaddr;
1038 return (0);
1041 static int
1042 ps3gpu_ctl_memory_free(struct ps3gpu_user *user,
1043 struct ps3gpu_ctl_memory_free *req)
1045 struct ps3gpu_context *context;
1046 struct ps3gpu_memory *mem;
1047 struct ps3gpu_memory_map *mmap;
1049 KASSERT(user != NULL, ("invalid user"));
1050 KASSERT(req != NULL, ("invalid request"));
1052 mmap = ps3gpu_dev_get_mmap(ps3gpu_dev, req->handle);
1053 if (!mmap)
1054 return (EINVAL);
1056 mem = mmap->mm_mem;
1057 context = mem->m_context;
1059 KASSERT(context != NULL, ("invalid context"));
1061 sx_xlock(&context->ctx_dev->d_lock);
1062 TAILQ_REMOVE(&context->ctx_dev->d_mmap_queue, mmap, mm_queue);
1063 sx_xunlock(&context->ctx_dev->d_lock);
1065 ps3gpu_dev_free_handle(context->ctx_dev, mmap->mm_handle);
1067 free(mmap, M_PS3GPU);
1069 ps3gpu_memory_free(mem);
1071 return (0);
1074 static int
1075 ps3gpu_ctl_setup_control(struct ps3gpu_user *user,
1076 struct ps3gpu_ctl_setup_control *req)
1078 struct ps3gpu_context *put_context, *get_context;
1079 struct ps3gpu_memory *put_mem, *get_mem;
1080 struct ps3gpu_memory_map *put_mmap, *get_mmap;
1081 unsigned long put_handle, put_offset, get_handle, get_offset;
1082 int err;
1084 KASSERT(user != NULL, ("invalid user"));
1085 KASSERT(req != NULL, ("invalid request"));
1087 put_handle = PS3GPU_MEMORY_MAP_HANDLE(req->put);
1088 put_offset = PS3GPU_MEMORY_MAP_OFFSET(req->put);
1090 put_mmap = ps3gpu_dev_get_mmap(ps3gpu_dev, put_handle);
1091 if (!put_mmap)
1092 return (EINVAL);
1094 put_mem = put_mmap->mm_mem;
1095 put_context = put_mem->m_context;
1097 KASSERT(put_context != NULL, ("invalid context"));
1099 get_handle = PS3GPU_MEMORY_MAP_HANDLE(req->get);
1100 get_offset = PS3GPU_MEMORY_MAP_OFFSET(req->get);
1102 get_mmap = ps3gpu_dev_get_mmap(ps3gpu_dev, get_handle);
1103 if (!get_mmap)
1104 return (EINVAL);
1106 get_mem = get_mmap->mm_mem;
1107 get_context = get_mem->m_context;
1109 KASSERT(get_context != NULL, ("invalid context"));
1111 if (put_context->ctx_id != req->context_id ||
1112 put_context != get_context)
1113 return (EINVAL);
1115 err = ps3gpu_setup_control(put_context, put_mem->m_gaddr + put_offset,
1116 get_mem->m_gaddr + get_offset, req->ref);
1117 if (err)
1118 return (err);
1120 return (0);
1123 static int
1124 ps3gpu_ctl_set_flip_mode(struct ps3gpu_user *user,
1125 struct ps3gpu_ctl_set_flip_mode *req)
1127 struct ps3gpu_context *context;
1128 int head, mode;
1129 int err;
1131 KASSERT(user != NULL, ("invalid user"));
1132 KASSERT(req != NULL, ("invalid request"));
1134 switch (req->head) {
1135 case PS3GPU_CTL_HEAD_A:
1136 head = PS3GPU_HEAD_A;
1137 break;
1138 case PS3GPU_CTL_HEAD_B:
1139 head = PS3GPU_HEAD_B;
1140 break;
1141 default:
1142 return (EINVAL);
1145 switch (req->mode) {
1146 case PS3GPU_CTL_FLIP_MODE_HSYNC:
1147 mode = PS3GPU_FLIP_MODE_HSYNC;
1148 break;
1149 case PS3GPU_CTL_FLIP_MODE_VSYNC:
1150 mode = PS3GPU_FLIP_MODE_VSYNC;
1151 break;
1152 default:
1153 return (EINVAL);
1156 context = ps3gpu_user_get_context(user, req->context_id);
1157 if (!context)
1158 return (EINVAL);
1160 err = ps3gpu_set_flip_mode(context, head, mode);
1161 if (err)
1162 return (err);
1164 return (0);
1167 static int
1168 ps3gpu_ctl_reset_flip_status(struct ps3gpu_user *user,
1169 struct ps3gpu_ctl_reset_flip_status *req)
1171 struct ps3gpu_context *context;
1172 int head;
1173 int err;
1175 KASSERT(user != NULL, ("invalid user"));
1176 KASSERT(req != NULL, ("invalid request"));
1178 switch (req->head) {
1179 case PS3GPU_CTL_HEAD_A:
1180 head = PS3GPU_HEAD_A;
1181 break;
1182 case PS3GPU_CTL_HEAD_B:
1183 head = PS3GPU_HEAD_B;
1184 break;
1185 default:
1186 return (EINVAL);
1189 context = ps3gpu_user_get_context(user, req->context_id);
1190 if (!context)
1191 return (EINVAL);
1193 err = ps3gpu_reset_flip_status(context, head);
1194 if (err)
1195 return (err);
1197 return (0);
1200 static int
1201 ps3gpu_ctl_flip(struct ps3gpu_user *user,
1202 struct ps3gpu_ctl_flip *req)
1204 struct ps3gpu_context *context;
1205 struct ps3gpu_memory *mem;
1206 struct ps3gpu_memory_map *mmap;
1207 int head;
1208 unsigned long handle, offset;
1209 int err;
1211 KASSERT(user != NULL, ("invalid user"));
1212 KASSERT(req != NULL, ("invalid request"));
1214 switch (req->head) {
1215 case PS3GPU_CTL_HEAD_A:
1216 head = PS3GPU_HEAD_A;
1217 break;
1218 case PS3GPU_CTL_HEAD_B:
1219 head = PS3GPU_HEAD_B;
1220 break;
1221 default:
1222 return (EINVAL);
1225 handle = PS3GPU_MEMORY_MAP_HANDLE(req->offset);
1226 offset = PS3GPU_MEMORY_MAP_OFFSET(req->offset);
1228 mmap = ps3gpu_dev_get_mmap(ps3gpu_dev, handle);
1229 if (!mmap)
1230 return (EINVAL);
1232 mem = mmap->mm_mem;
1233 context = mem->m_context;
1235 KASSERT(context != NULL, ("invalid context"));
1237 if (req->context_id != context->ctx_id)
1238 return (EINVAL);
1240 err = ps3gpu_flip(context, head, mem->m_start + offset);
1241 if (err)
1242 return (err);
1244 return (0);
1247 static int
1248 ps3gpu_ctl_display_buffer_set(struct ps3gpu_user *user,
1249 struct ps3gpu_ctl_display_buffer_set *req)
1251 struct ps3gpu_context *context;
1252 struct ps3gpu_memory *mem;
1253 struct ps3gpu_memory_map *mmap;
1254 unsigned long handle, offset;
1255 int err;
1257 KASSERT(user != NULL, ("invalid user"));
1258 KASSERT(req != NULL, ("invalid request"));
1260 if (req->buffer_id < 0 ||
1261 req->buffer_id >= PS3GPU_CONTEXT_MAX_DISPLAY_BUFFERS)
1262 return (EINVAL);
1264 handle = PS3GPU_MEMORY_MAP_HANDLE(req->offset);
1265 offset = PS3GPU_MEMORY_MAP_OFFSET(req->offset);
1267 mmap = ps3gpu_dev_get_mmap(ps3gpu_dev, handle);
1268 if (!mmap)
1269 return (EINVAL);
1271 mem = mmap->mm_mem;
1272 context = mem->m_context;
1274 KASSERT(context != NULL, ("invalid context"));
1276 if (req->context_id != context->ctx_id)
1277 return (EINVAL);
1279 err = ps3gpu_display_buffer_set(context, req->buffer_id,
1280 req->width, req->height, req->pitch, mem->m_gaddr + offset);
1281 if (err)
1282 return (err);
1284 return (0);
1287 static int
1288 ps3gpu_ctl_display_buffer_unset(struct ps3gpu_user *user,
1289 struct ps3gpu_ctl_display_buffer_unset *req)
1291 struct ps3gpu_context *context;
1292 int err;
1294 KASSERT(user != NULL, ("invalid user"));
1295 KASSERT(req != NULL, ("invalid request"));
1297 if (req->buffer_id < 0 ||
1298 req->buffer_id >= PS3GPU_CONTEXT_MAX_DISPLAY_BUFFERS)
1299 return (EINVAL);
1301 context = ps3gpu_user_get_context(user, req->context_id);
1302 if (!context)
1303 return (EINVAL);
1305 err = ps3gpu_display_buffer_unset(context, req->buffer_id);
1306 if (err)
1307 return (err);
1309 return (0);
1312 static int
1313 ps3gpu_ctl_display_buffer_flip(struct ps3gpu_user *user,
1314 struct ps3gpu_ctl_display_buffer_flip *req)
1316 struct ps3gpu_context *context;
1317 int head;
1318 int err;
1320 KASSERT(user != NULL, ("invalid user"));
1321 KASSERT(req != NULL, ("invalid request"));
1323 switch (req->head) {
1324 case PS3GPU_CTL_HEAD_A:
1325 head = PS3GPU_HEAD_A;
1326 break;
1327 case PS3GPU_CTL_HEAD_B:
1328 head = PS3GPU_HEAD_B;
1329 break;
1330 default:
1331 return (EINVAL);
1334 if (req->buffer_id < 0 ||
1335 req->buffer_id >= PS3GPU_CONTEXT_MAX_DISPLAY_BUFFERS)
1336 return (EINVAL);
1338 context = ps3gpu_user_get_context(user, req->context_id);
1339 if (!context)
1340 return (EINVAL);
1342 if (req->context_id != context->ctx_id)
1343 return (EINVAL);
1345 err = ps3gpu_display_buffer_flip(context, head, req->buffer_id);
1346 if (err)
1347 return (err);
1349 return (0);
1352 static int
1353 ps3gpu_ctl_tile_set(struct ps3gpu_user *user,
1354 struct ps3gpu_ctl_tile_set *req)
1356 struct ps3gpu_context *context;
1357 struct ps3gpu_memory *mem;
1358 struct ps3gpu_memory_map *mmap;
1359 unsigned long handle, offset;
1360 int cmp_mode;
1361 int err;
1363 KASSERT(user != NULL, ("invalid user"));
1364 KASSERT(req != NULL, ("invalid request"));
1366 switch (req->cmp_mode) {
1367 case PS3GPU_CTL_TILE_CMP_MODE_NONE:
1368 cmp_mode = PS3GPU_TILE_CMP_MODE_NONE;
1369 break;
1370 case PS3GPU_CTL_TILE_CMP_MODE_C32_2X1:
1371 cmp_mode = PS3GPU_TILE_CMP_MODE_C32_2X1;
1372 break;
1373 case PS3GPU_CTL_TILE_CMP_MODE_C32_2X2:
1374 cmp_mode = PS3GPU_TILE_CMP_MODE_C32_2X2;
1375 break;
1376 case PS3GPU_CTL_TILE_CMP_MODE_Z32_SEP:
1377 cmp_mode = PS3GPU_TILE_CMP_MODE_Z32_SEP;
1378 break;
1379 case PS3GPU_CTL_TILE_CMP_MODE_Z32_SEP_REG:
1380 cmp_mode = PS3GPU_TILE_CMP_MODE_Z32_SEP_REG;
1381 break;
1382 case PS3GPU_CTL_TILE_CMP_MODE_Z32_SEP_DIAG:
1383 cmp_mode = PS3GPU_TILE_CMP_MODE_Z32_SEP_DIAG;
1384 break;
1385 case PS3GPU_CTL_TILE_CMP_MODE_Z32_SEP_ROT:
1386 cmp_mode = PS3GPU_TILE_CMP_MODE_Z32_SEP_ROT;
1387 break;
1388 default:
1389 return (EINVAL);
1392 if (req->tile_id < 0 ||
1393 req->tile_id >= PS3GPU_CONTEXT_MAX_TILES)
1394 return (EINVAL);
1396 handle = PS3GPU_MEMORY_MAP_HANDLE(req->offset);
1397 offset = PS3GPU_MEMORY_MAP_OFFSET(req->offset);
1399 mmap = ps3gpu_dev_get_mmap(ps3gpu_dev, handle);
1400 if (!mmap)
1401 return (EINVAL);
1403 mem = mmap->mm_mem;
1404 context = mem->m_context;
1406 KASSERT(context[0] != NULL, ("invalid context"));
1408 if (req->context_id != context->ctx_id)
1409 return (EINVAL);
1411 if (mem->m_type != PS3GPU_MEMORY_TYPE_VIDEO &&
1412 mem->m_type != PS3GPU_MEMORY_TYPE_GART)
1413 return (EINVAL);
1415 err = ps3gpu_tile_set(context, req->tile_id,
1416 mem->m_type, req->size, req->pitch, cmp_mode, req->bank,
1417 req->base, mem->m_start + offset);
1418 if (err)
1419 return (err);
1421 return (0);
1424 static int
1425 ps3gpu_ctl_tile_unset(struct ps3gpu_user *user,
1426 struct ps3gpu_ctl_tile_unset *req)
1428 struct ps3gpu_context *context;
1429 struct ps3gpu_memory *mem;
1430 struct ps3gpu_memory_map *mmap;
1431 unsigned long handle, offset;
1432 int err;
1434 KASSERT(user != NULL, ("invalid user"));
1435 KASSERT(req != NULL, ("invalid request"));
1437 if (req->tile_id < 0 ||
1438 req->tile_id >= PS3GPU_CONTEXT_MAX_TILES)
1439 return (EINVAL);
1441 handle = PS3GPU_MEMORY_MAP_HANDLE(req->offset);
1442 offset = PS3GPU_MEMORY_MAP_OFFSET(req->offset);
1444 mmap = ps3gpu_dev_get_mmap(ps3gpu_dev, handle);
1445 if (!mmap)
1446 return (EINVAL);
1448 mem = mmap->mm_mem;
1449 context = mem->m_context;
1451 KASSERT(context != NULL, ("invalid context"));
1453 if (req->context_id != context->ctx_id)
1454 return (EINVAL);
1456 if (mem->m_type != PS3GPU_MEMORY_TYPE_VIDEO &&
1457 mem->m_type != PS3GPU_MEMORY_TYPE_GART)
1458 return (EINVAL);
1460 err = ps3gpu_tile_unset(context, req->tile_id, mem->m_type,
1461 req->bank, mem->m_start + offset);
1462 if (err)
1463 return (err);
1465 return (0);
1468 static int
1469 ps3gpu_ctl_cursor_initialize(struct ps3gpu_user *user,
1470 struct ps3gpu_ctl_cursor_initialize *req)
1472 struct ps3gpu_context *context;
1473 int head;
1474 int err;
1476 KASSERT(user != NULL, ("invalid user"));
1477 KASSERT(req != NULL, ("invalid request"));
1479 switch (req->head) {
1480 case PS3GPU_CTL_HEAD_A:
1481 head = PS3GPU_HEAD_A;
1482 break;
1483 case PS3GPU_CTL_HEAD_B:
1484 head = PS3GPU_HEAD_B;
1485 break;
1486 default:
1487 return (EINVAL);
1490 context = ps3gpu_user_get_context(user, req->context_id);
1491 if (!context)
1492 return (EINVAL);
1494 err = ps3gpu_cursor_initialize(context, head);
1495 if (err)
1496 return (err);
1498 return (0);
1501 static int
1502 ps3gpu_ctl_cursor_set_image(struct ps3gpu_user *user,
1503 struct ps3gpu_ctl_cursor_set_image *req)
1505 struct ps3gpu_context *context;
1506 struct ps3gpu_memory *mem;
1507 struct ps3gpu_memory_map *mmap;
1508 int head;
1509 unsigned long handle, offset;
1510 int err;
1512 KASSERT(user != NULL, ("invalid user"));
1513 KASSERT(req != NULL, ("invalid request"));
1515 switch (req->head) {
1516 case PS3GPU_CTL_HEAD_A:
1517 head = PS3GPU_HEAD_A;
1518 break;
1519 case PS3GPU_CTL_HEAD_B:
1520 head = PS3GPU_HEAD_B;
1521 break;
1522 default:
1523 return (EINVAL);
1526 handle = PS3GPU_MEMORY_MAP_HANDLE(req->offset);
1527 offset = PS3GPU_MEMORY_MAP_OFFSET(req->offset);
1529 mmap = ps3gpu_dev_get_mmap(ps3gpu_dev, handle);
1530 if (!mmap)
1531 return (EINVAL);
1533 mem = mmap->mm_mem;
1534 context = mem->m_context;
1536 KASSERT(context != NULL, ("invalid context"));
1538 if (req->context_id != context->ctx_id)
1539 return (EINVAL);
1541 err = ps3gpu_cursor_set_image(context, head, mem->m_start + offset);
1542 if (err)
1543 return (err);
1545 return (0);
1548 static int
1549 ps3gpu_ctl_cursor_set_position(struct ps3gpu_user *user,
1550 struct ps3gpu_ctl_cursor_set_position *req)
1552 struct ps3gpu_context *context;
1553 int head;
1554 int err;
1556 KASSERT(user != NULL, ("invalid user"));
1557 KASSERT(req != NULL, ("invalid request"));
1559 switch (req->head) {
1560 case PS3GPU_CTL_HEAD_A:
1561 head = PS3GPU_HEAD_A;
1562 break;
1563 case PS3GPU_CTL_HEAD_B:
1564 head = PS3GPU_HEAD_B;
1565 break;
1566 default:
1567 return (EINVAL);
1570 context = ps3gpu_user_get_context(user, req->context_id);
1571 if (!context)
1572 return (EINVAL);
1574 err = ps3gpu_cursor_set_position(context, head, req->x, req->y);
1575 if (err)
1576 return (err);
1578 return (0);
1581 static int
1582 ps3gpu_ctl_cursor_enable(struct ps3gpu_user *user,
1583 struct ps3gpu_ctl_cursor_enable *req)
1585 struct ps3gpu_context *context;
1586 int head;
1587 int err;
1589 KASSERT(user != NULL, ("invalid user"));
1590 KASSERT(req != NULL, ("invalid request"));
1592 switch (req->head) {
1593 case PS3GPU_CTL_HEAD_A:
1594 head = PS3GPU_HEAD_A;
1595 break;
1596 case PS3GPU_CTL_HEAD_B:
1597 head = PS3GPU_HEAD_B;
1598 break;
1599 default:
1600 return (EINVAL);
1603 context = ps3gpu_user_get_context(user, req->context_id);
1604 if (!context)
1605 return (EINVAL);
1607 err = ps3gpu_cursor_enable(context, head, req->enable);
1608 if (err)
1609 return (err);
1611 return (0);
1614 static void
1615 ps3gpu_user_dtr(void *data)
1617 struct ps3gpu_user *user = data;
1618 struct ps3gpu_context *context;
1619 struct ps3gpu_memory_map *mmap;
1621 KASSERT(user != NULL, ("invalid user"));
1623 sx_xlock(&user->u_lock);
1625 sx_xlock(&ps3gpu_dev->d_lock);
1627 while ((mmap = TAILQ_FIRST(&ps3gpu_dev->d_mmap_queue))) {
1628 TAILQ_REMOVE(&ps3gpu_dev->d_mmap_queue, mmap, mm_queue);
1629 free_unr(ps3gpu_dev->d_mmap_unrhdr,
1630 mmap->mm_handle >> PS3GPU_MEMORY_MAP_HANDLE_SHIFT);
1631 free(mmap, M_PS3GPU);
1634 sx_xunlock(&ps3gpu_dev->d_lock);
1636 while ((context = TAILQ_FIRST(&user->u_context_queue))) {
1637 TAILQ_REMOVE(&user->u_context_queue, context, ctx_user_queue);
1638 free(context->ctx_control_mem, M_PS3GPU);
1639 free(context->ctx_driver_info_mem, M_PS3GPU);
1640 free(context->ctx_reports_mem, M_PS3GPU);
1641 ps3gpu_context_free(context);
1644 sx_xunlock(&user->u_lock);
1646 sx_destroy(&user->u_lock);
1648 free(user, M_PS3GPU);
1651 static int
1652 ps3gpu_open(struct cdev *dev, int oflags, int fmt,
1653 struct thread *td)
1655 struct ps3gpu_user *user;
1656 int err;
1658 if ((oflags & (FREAD | FWRITE)) != (FREAD | FWRITE))
1659 return (EINVAL);
1661 user = malloc(sizeof(*user), M_PS3GPU, M_WAITOK | M_ZERO);
1662 if (!user)
1663 return (ENOMEM);
1665 sx_init(&user->u_lock, "ps3gpu_user");
1667 TAILQ_INIT(&user->u_context_queue);
1669 err = devfs_set_cdevpriv(user, ps3gpu_user_dtr);
1670 if (err) {
1671 sx_destroy(&user->u_lock);
1672 free(user, M_PS3GPU);
1673 return (err);
1676 return (0);
1679 static int
1680 ps3gpu_mmap(struct cdev *dev, vm_ooffset_t offset,
1681 vm_paddr_t *paddr, int nprot, vm_memattr_t *memattr)
1683 struct ps3gpu_user *user = NULL;
1684 struct ps3gpu_context *context;
1685 struct ps3gpu_memory *mem;
1686 struct ps3gpu_memory_map *mmap;
1687 unsigned long handle;
1689 if (nprot & PROT_EXEC)
1690 return (EINVAL);
1692 devfs_get_cdevpriv((void **) &user);
1694 handle = PS3GPU_MEMORY_MAP_HANDLE(offset);
1695 offset = PS3GPU_MEMORY_MAP_OFFSET(offset);
1697 mmap = ps3gpu_dev_get_mmap(ps3gpu_dev, handle);
1698 if (!mmap)
1699 return (EINVAL);
1701 mem = mmap->mm_mem;
1702 context = mem->m_context;
1704 KASSERT(context != NULL, ("invalid context"));
1706 if (user && context->ctx_user != user)
1707 return (EINVAL);
1709 if (offset >= mem->m_size)
1710 return (EINVAL);
1712 switch (mem->m_type) {
1713 case PS3GPU_MEMORY_TYPE_VIDEO:
1714 *paddr = mem->m_paddr + offset;
1715 *memattr = VM_MEMATTR_WRITE_COMBINING;
1716 break;
1717 case PS3GPU_MEMORY_TYPE_GART:
1718 *paddr = vtophys(mem->m_vaddr + offset);
1719 *memattr = VM_MEMATTR_DEFAULT;
1720 break;
1721 case PS3GPU_MEMORY_TYPE_REGISTER:
1722 *paddr = mem->m_paddr + offset;
1723 *memattr = VM_MEMATTR_UNCACHEABLE;
1724 break;
1727 return (0);
1730 static int
1731 ps3gpu_ioctl(struct cdev *dev, u_long cmd, caddr_t data,
1732 int fflag, struct thread *td)
1734 struct ps3gpu_user *user;
1735 int err;
1737 err = devfs_get_cdevpriv((void **) &user);
1738 if (err)
1739 return (err);
1741 switch (cmd) {
1742 case PS3GPU_CTL_CONTEXT_ALLOCATE:
1744 struct ps3gpu_ctl_context_allocate *req =
1745 (struct ps3gpu_ctl_context_allocate *) data;
1747 err = ps3gpu_ctl_context_allocate(user, req);
1749 break;
1750 case PS3GPU_CTL_CONTEXT_FREE:
1752 struct ps3gpu_ctl_context_free *req =
1753 (struct ps3gpu_ctl_context_free *) data;
1755 err = ps3gpu_ctl_context_free(user, req);
1757 break;
1758 case PS3GPU_CTL_MEMORY_ALLOCATE:
1760 struct ps3gpu_ctl_memory_allocate *req =
1761 (struct ps3gpu_ctl_memory_allocate *) data;
1763 err = ps3gpu_ctl_memory_allocate(user, req);
1765 break;
1766 case PS3GPU_CTL_MEMORY_FREE:
1768 struct ps3gpu_ctl_memory_free *req =
1769 (struct ps3gpu_ctl_memory_free *) data;
1771 err = ps3gpu_ctl_memory_free(user, req);
1773 break;
1774 case PS3GPU_CTL_SETUP_CONTROL:
1776 struct ps3gpu_ctl_setup_control *req =
1777 (struct ps3gpu_ctl_setup_control *) data;
1779 err = ps3gpu_ctl_setup_control(user, req);
1781 break;
1782 case PS3GPU_CTL_SET_FLIP_MODE:
1784 struct ps3gpu_ctl_set_flip_mode *req =
1785 (struct ps3gpu_ctl_set_flip_mode *) data;
1787 err = ps3gpu_ctl_set_flip_mode(user, req);
1789 break;
1790 case PS3GPU_CTL_RESET_FLIP_STATUS:
1792 struct ps3gpu_ctl_reset_flip_status *req =
1793 (struct ps3gpu_ctl_reset_flip_status *) data;
1795 err = ps3gpu_ctl_reset_flip_status(user, req);
1797 break;
1798 case PS3GPU_CTL_FLIP:
1800 struct ps3gpu_ctl_flip *req =
1801 (struct ps3gpu_ctl_flip *) data;
1803 err = ps3gpu_ctl_flip(user, req);
1805 break;
1806 case PS3GPU_CTL_DISPLAY_BUFFER_SET:
1808 struct ps3gpu_ctl_display_buffer_set *req =
1809 (struct ps3gpu_ctl_display_buffer_set *) data;
1811 err = ps3gpu_ctl_display_buffer_set(user, req);
1813 break;
1814 case PS3GPU_CTL_DISPLAY_BUFFER_UNSET:
1816 struct ps3gpu_ctl_display_buffer_unset *req =
1817 (struct ps3gpu_ctl_display_buffer_unset *) data;
1819 err = ps3gpu_ctl_display_buffer_unset(user, req);
1821 break;
1822 case PS3GPU_CTL_DISPLAY_BUFFER_FLIP:
1824 struct ps3gpu_ctl_display_buffer_flip *req =
1825 (struct ps3gpu_ctl_display_buffer_flip *) data;
1827 err = ps3gpu_ctl_display_buffer_flip(user, req);
1829 break;
1830 case PS3GPU_CTL_TILE_SET:
1832 struct ps3gpu_ctl_tile_set *req =
1833 (struct ps3gpu_ctl_tile_set *) data;
1835 err = ps3gpu_ctl_tile_set(user, req);
1837 break;
1838 case PS3GPU_CTL_TILE_UNSET:
1840 struct ps3gpu_ctl_tile_unset *req =
1841 (struct ps3gpu_ctl_tile_unset *) data;
1843 err = ps3gpu_ctl_tile_unset(user, req);
1845 break;
1846 case PS3GPU_CTL_CURSOR_INITIALIZE:
1848 struct ps3gpu_ctl_cursor_initialize *req =
1849 (struct ps3gpu_ctl_cursor_initialize *) data;
1851 err = ps3gpu_ctl_cursor_initialize(user, req);
1853 break;
1854 case PS3GPU_CTL_CURSOR_SET_IMAGE:
1856 struct ps3gpu_ctl_cursor_set_image *req =
1857 (struct ps3gpu_ctl_cursor_set_image *) data;
1859 err = ps3gpu_ctl_cursor_set_image(user, req);
1861 break;
1862 case PS3GPU_CTL_CURSOR_SET_POSITION:
1864 struct ps3gpu_ctl_cursor_set_position *req =
1865 (struct ps3gpu_ctl_cursor_set_position *) data;
1867 err = ps3gpu_ctl_cursor_set_position(user, req);
1869 break;
1870 case PS3GPU_CTL_CURSOR_ENABLE:
1872 struct ps3gpu_ctl_cursor_enable *req =
1873 (struct ps3gpu_ctl_cursor_enable *) data;
1875 err = ps3gpu_ctl_cursor_enable(user, req);
1877 break;
1878 default:
1879 err = ENOIOCTL;
1880 break;
1883 return (err);
1886 static int
1887 ps3gpu_device_init(struct ps3gpu_device **pdev)
1889 struct ps3gpu_device *dev;
1891 dev = malloc(sizeof(*dev), M_PS3GPU, M_WAITOK | M_ZERO);
1892 if (!dev)
1893 return (ENOMEM);
1895 sx_init(&dev->d_lock, "ps3gpu_device");
1897 TAILQ_INIT(&dev->d_mmap_queue);
1899 dev->d_mmap_unrhdr = new_unrhdr(1,
1900 ((1 << PS3GPU_MEMORY_MAP_HANDLE_BITS) - 1), NULL);
1901 if (!dev->d_mmap_unrhdr) {
1902 sx_destroy(&dev->d_lock);
1903 free(dev, M_PS3GPU);
1904 return (ENOMEM);
1907 *pdev = dev;
1909 return (0);
1912 static void
1913 ps3gpu_device_fini(struct ps3gpu_device *dev)
1915 int i;
1917 for (i = 0; i < PS3GPU_DEVICE_MAX_CONTEXTS; i++) {
1918 if (dev->d_context[i])
1919 ps3gpu_context_free(dev->d_context[i]);
1922 delete_unrhdr(dev->d_mmap_unrhdr);
1924 sx_destroy(&dev->d_lock);
1926 free(dev, M_PS3GPU);
1929 static struct ps3gpu_memory_map *
1930 ps3gpu_dev_get_mmap(struct ps3gpu_device *dev,
1931 unsigned long handle)
1933 struct ps3gpu_memory_map *mmap;
1935 sx_xlock(&dev->d_lock);
1937 TAILQ_FOREACH(mmap, &dev->d_mmap_queue, mm_queue) {
1938 if (mmap->mm_handle == handle) {
1939 sx_xunlock(&dev->d_lock);
1940 return (mmap);
1944 sx_xunlock(&dev->d_lock);
1946 return (NULL);
1949 static unsigned long
1950 ps3gpu_dev_alloc_handle(struct ps3gpu_device *dev)
1952 unsigned long handle;
1954 sx_xlock(&dev->d_lock);
1956 handle = (unsigned long) alloc_unr(dev->d_mmap_unrhdr) <<
1957 PS3GPU_MEMORY_MAP_HANDLE_SHIFT;
1959 sx_xunlock(&dev->d_lock);
1961 return (handle);
1964 static void
1965 ps3gpu_dev_free_handle(struct ps3gpu_device *dev,
1966 unsigned long handle)
1968 sx_xlock(&dev->d_lock);
1970 free_unr(dev->d_mmap_unrhdr,
1971 handle >> PS3GPU_MEMORY_MAP_HANDLE_SHIFT);
1973 sx_xunlock(&dev->d_lock);
1977 static int
1978 ps3gpu_modevent(module_t mod, int type, void *arg)
1980 int err;
1982 switch (type) {
1983 case MOD_LOAD:
1984 /* Create GPU device */
1986 err = ps3gpu_device_init(&ps3gpu_dev);
1987 if (err) {
1988 printf("ps3gpu: Failed to create GPU device\n");
1989 return (err);
1992 /* Create char device */
1994 ps3gpu_cdev = make_dev(&ps3gpu_cdevsw, 0,
1995 UID_ROOT, GID_WHEEL, 0600, "ps3gpu");
1996 if (!ps3gpu_cdev) {
1997 printf("ps3gpu: Failed to create /dev/ps3gpu\n");
1998 ps3gpu_device_fini(ps3gpu_dev);
1999 return (ENOMEM);
2001 break;
2002 case MOD_UNLOAD:
2003 /* Destroy char device */
2005 if (ps3gpu_cdev)
2006 destroy_dev(ps3gpu_cdev);
2008 if (ps3gpu_dev)
2009 ps3gpu_device_fini(ps3gpu_dev);
2010 break;
2011 case MOD_SHUTDOWN:
2012 break;
2013 default:
2014 return (EOPNOTSUPP);
2017 return (0);
2020 DEV_MODULE(ps3gpu, ps3gpu_modevent, NULL);
2021 MODULE_VERSION(ps3gpu, 1);