#
-# drm device configuration
+# Drm device configuration
#
# This driver provides support for the
# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
tristate ' ATI Rage 128' CONFIG_DRM_R128
dep_tristate ' ATI Radeon' CONFIG_DRM_RADEON $CONFIG_AGP
dep_tristate ' Intel I810' CONFIG_DRM_I810 $CONFIG_AGP
+ dep_tristate ' Intel 830M' CONFIG_DRM_I830 $CONFIG_AGP
dep_tristate ' Matrox g200/g400' CONFIG_DRM_MGA $CONFIG_AGP
fi
r128-objs := r128_drv.o r128_cce.o r128_state.o
mga-objs := mga_drv.o mga_dma.o mga_state.o mga_warp.o
i810-objs := i810_drv.o i810_dma.o
+i830-objs := i830_drv.o i830_dma.o
radeon-objs := radeon_drv.o radeon_cp.o radeon_state.o
ffb-objs := ffb_drv.o ffb_context.o
obj-$(CONFIG_DRM_RADEON)+= radeon.o
obj-$(CONFIG_DRM_MGA) += mga.o
obj-$(CONFIG_DRM_I810) += i810.o
+obj-$(CONFIG_DRM_I830) += i830.o
obj-$(CONFIG_DRM_FFB) += ffb.o
include $(TOPDIR)/Rules.make
#include "i810_drm.h"
#include "r128_drm.h"
#include "radeon_drm.h"
-#ifdef CONFIG_DRM_SIS
#include "sis_drm.h"
-#endif
+#include "i830_drm.h"
+#include "gamma_drm.h"
typedef struct drm_version {
int version_major; /* Major version */
#define DRM_IOCTL_I810_SWAP DRM_IO( 0x46)
#define DRM_IOCTL_I810_COPY DRM_IOW( 0x47, drm_i810_copy_t)
#define DRM_IOCTL_I810_DOCOPY DRM_IO( 0x48)
+#define DRM_IOCTL_I810_OV0INFO DRM_IOR( 0x49, drm_i810_overlay_t)
+#define DRM_IOCTL_I810_FSTATUS DRM_IO ( 0x4a)
+#define DRM_IOCTL_I810_OV0FLIP DRM_IO ( 0x4b)
+#define DRM_IOCTL_I810_MC DRM_IOW( 0x4c, drm_i810_mc_t)
+#define DRM_IOCTL_I810_RSTATUS DRM_IO ( 0x4d )
+
/* Rage 128 specific ioctls */
#define DRM_IOCTL_R128_INIT DRM_IOW( 0x40, drm_r128_init_t)
#define DRM_IOCTL_R128_STIPPLE DRM_IOW( 0x4d, drm_r128_stipple_t)
#define DRM_IOCTL_R128_INDIRECT DRM_IOWR(0x4f, drm_r128_indirect_t)
#define DRM_IOCTL_R128_FULLSCREEN DRM_IOW( 0x50, drm_r128_fullscreen_t)
+#define DRM_IOCTL_R128_CLEAR2 DRM_IOW( 0x51, drm_r128_clear2_t)
/* Radeon specific ioctls */
#define DRM_IOCTL_RADEON_CP_INIT DRM_IOW( 0x40, drm_radeon_init_t)
#define DRM_IOCTL_RADEON_STIPPLE DRM_IOW( 0x4c, drm_radeon_stipple_t)
#define DRM_IOCTL_RADEON_INDIRECT DRM_IOWR(0x4d, drm_radeon_indirect_t)
#define DRM_IOCTL_RADEON_TEXTURE DRM_IOWR(0x4e, drm_radeon_texture_t)
+#define DRM_IOCTL_RADEON_VERTEX2 DRM_IOW( 0x4f, drm_radeon_vertex_t)
+#define DRM_IOCTL_RADEON_CMDBUF DRM_IOW( 0x50, drm_radeon_cmd_buffer_t)
+#define DRM_IOCTL_RADEON_GETPARAM DRM_IOWR(0x51, drm_radeon_getparam_t)
+#define DRM_IOCTL_RADEON_FLIP DRM_IO( 0x52)
+
+/* Gamma specific ioctls */
+#define DRM_IOCTL_GAMMA_INIT DRM_IOW( 0x40, drm_gamma_init_t)
+#define DRM_IOCTL_GAMMA_COPY DRM_IOW( 0x41, drm_gamma_copy_t)
-#ifdef CONFIG_DRM_SIS
/* SiS specific ioctls */
#define SIS_IOCTL_FB_ALLOC DRM_IOWR(0x44, drm_sis_mem_t)
#define SIS_IOCTL_FB_FREE DRM_IOW( 0x45, drm_sis_mem_t)
#define SIS_IOCTL_FLIP DRM_IOW( 0x48, drm_sis_flip_t)
#define SIS_IOCTL_FLIP_INIT DRM_IO( 0x49)
#define SIS_IOCTL_FLIP_FINAL DRM_IO( 0x50)
-#endif
+
+/* I830 specific ioctls */
+#define DRM_IOCTL_I830_INIT DRM_IOW( 0x40, drm_i830_init_t)
+#define DRM_IOCTL_I830_VERTEX DRM_IOW( 0x41, drm_i830_vertex_t)
+#define DRM_IOCTL_I830_CLEAR DRM_IOW( 0x42, drm_i830_clear_t)
+#define DRM_IOCTL_I830_FLUSH DRM_IO ( 0x43)
+#define DRM_IOCTL_I830_GETAGE DRM_IO ( 0x44)
+#define DRM_IOCTL_I830_GETBUF DRM_IOWR(0x45, drm_i830_dma_t)
+#define DRM_IOCTL_I830_SWAP DRM_IO ( 0x46)
+#define DRM_IOCTL_I830_COPY DRM_IOW( 0x47, drm_i830_copy_t)
+#define DRM_IOCTL_I830_DOCOPY DRM_IO ( 0x48)
#endif
#include <linux/types.h>
#include <linux/agp_backend.h>
#endif
-#if LINUX_VERSION_CODE >= 0x020100 /* KERNEL_VERSION(2,1,0) */
#include <linux/tqueue.h>
#include <linux/poll.h>
-#endif
-#if LINUX_VERSION_CODE < 0x020400
-#include "compat-pre24.h"
-#endif
#include <asm/pgalloc.h>
#include "drm.h"
-/* page_to_bus for earlier kernels, not optimal in all cases */
-#ifndef page_to_bus
-#define page_to_bus(page) ((unsigned int)(virt_to_bus(page_address(page))))
-#endif
-
-/* We just use virt_to_bus for pci_map_single on older kernels */
-#if LINUX_VERSION_CODE < 0x020400
-#define pci_map_single(hwdev, ptr, size, direction) virt_to_bus(ptr)
-#define pci_unmap_single(hwdev, dma_addr, size, direction)
-#endif
-
/* DRM template customization defaults
*/
#ifndef __HAVE_AGP
#define DRM_MAX_CTXBITMAP (PAGE_SIZE * 8)
/* Backward compatibility section */
- /* _PAGE_WT changed to _PAGE_PWT in 2.2.6 */
-#ifndef _PAGE_PWT
-#define _PAGE_PWT _PAGE_WT
-#endif
- /* Wait queue declarations changed in 2.3.1 */
-#ifndef DECLARE_WAITQUEUE
-#define DECLARE_WAITQUEUE(w,c) struct wait_queue w = { c, NULL }
-typedef struct wait_queue *wait_queue_head_t;
-#define init_waitqueue_head(q) *q = NULL;
-#endif
-
- /* _PAGE_4M changed to _PAGE_PSE in 2.3.23 */
-#ifndef _PAGE_PSE
-#define _PAGE_PSE _PAGE_4M
+#ifndef minor
+#define minor(x) MINOR((x))
#endif
- /* vm_offset changed to vm_pgoff in 2.3.25 */
-#if LINUX_VERSION_CODE < 0x020319
-#define VM_OFFSET(vma) ((vma)->vm_offset)
-#else
-#define VM_OFFSET(vma) ((vma)->vm_pgoff << PAGE_SHIFT)
+#ifndef MODULE_LICENSE
+#define MODULE_LICENSE(x)
#endif
- /* *_nopage return values defined in 2.3.26 */
-#ifndef NOPAGE_SIGBUS
-#define NOPAGE_SIGBUS 0
-#endif
-#ifndef NOPAGE_OOM
-#define NOPAGE_OOM 0
+#ifndef preempt_disable
+#define preempt_disable()
+#define preempt_enable()
#endif
- /* module_init/module_exit added in 2.3.13 */
-#ifndef module_init
-#define module_init(x) int init_module(void) { return x(); }
-#endif
-#ifndef module_exit
-#define module_exit(x) void cleanup_module(void) { x(); }
+#ifndef pte_offset_map
+#define pte_offset_map pte_offset
+#define pte_unmap(pte)
#endif
- /* Generic cmpxchg added in 2.3.x */
-#ifndef __HAVE_ARCH_CMPXCHG
- /* Include this here so that driver can be
- used with older kernels. */
-#if defined(__alpha__)
-static __inline__ unsigned long
-__cmpxchg_u32(volatile int *m, int old, int new)
+#if LINUX_VERSION_CODE < 0x020500
+static inline struct page * vmalloc_to_page(void * vmalloc_addr)
{
- unsigned long prev, cmp;
-
- __asm__ __volatile__(
- "1: ldl_l %0,%5\n"
- " cmpeq %0,%3,%1\n"
- " beq %1,2f\n"
- " mov %4,%1\n"
- " stl_c %1,%2\n"
- " beq %1,3f\n"
- "2: mb\n"
- ".subsection 2\n"
- "3: br 1b\n"
- ".previous"
- : "=&r"(prev), "=&r"(cmp), "=m"(*m)
- : "r"((long) old), "r"(new), "m"(*m)
- : "memory" );
-
- return prev;
-}
-
-static __inline__ unsigned long
-__cmpxchg_u64(volatile long *m, unsigned long old, unsigned long new)
-{
- unsigned long prev, cmp;
-
- __asm__ __volatile__(
- "1: ldq_l %0,%5\n"
- " cmpeq %0,%3,%1\n"
- " beq %1,2f\n"
- " mov %4,%1\n"
- " stq_c %1,%2\n"
- " beq %1,3f\n"
- "2: mb\n"
- ".subsection 2\n"
- "3: br 1b\n"
- ".previous"
- : "=&r"(prev), "=&r"(cmp), "=m"(*m)
- : "r"((long) old), "r"(new), "m"(*m)
- : "memory" );
-
- return prev;
-}
-
-static __inline__ unsigned long
-__cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size)
-{
- switch (size) {
- case 4:
- return __cmpxchg_u32(ptr, old, new);
- case 8:
- return __cmpxchg_u64(ptr, old, new);
+ unsigned long addr = (unsigned long) vmalloc_addr;
+ struct page *page = NULL;
+ pgd_t *pgd = pgd_offset_k(addr);
+ pmd_t *pmd;
+ pte_t *ptep, pte;
+
+ if (!pgd_none(*pgd)) {
+ pmd = pmd_offset(pgd, addr);
+ if (!pmd_none(*pmd)) {
+ preempt_disable();
+ ptep = pte_offset_map(pmd, addr);
+ pte = *ptep;
+ if (pte_present(pte))
+ page = pte_page(pte);
+ pte_unmap(ptep);
+ preempt_enable();
+ }
}
- return old;
+ return page;
}
-#define cmpxchg(ptr,o,n) \
- ({ \
- __typeof__(*(ptr)) _o_ = (o); \
- __typeof__(*(ptr)) _n_ = (n); \
- (__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_, \
- (unsigned long)_n_, sizeof(*(ptr))); \
- })
-
-#elif __i386__
-static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
- unsigned long new, int size)
-{
- unsigned long prev;
- switch (size) {
- case 1:
- __asm__ __volatile__(LOCK_PREFIX "cmpxchgb %b1,%2"
- : "=a"(prev)
- : "q"(new), "m"(*__xg(ptr)), "0"(old)
- : "memory");
- return prev;
- case 2:
- __asm__ __volatile__(LOCK_PREFIX "cmpxchgw %w1,%2"
- : "=a"(prev)
- : "q"(new), "m"(*__xg(ptr)), "0"(old)
- : "memory");
- return prev;
- case 4:
- __asm__ __volatile__(LOCK_PREFIX "cmpxchgl %1,%2"
- : "=a"(prev)
- : "q"(new), "m"(*__xg(ptr)), "0"(old)
- : "memory");
- return prev;
- }
- return old;
-}
-
-#elif defined(__powerpc__)
-extern void __cmpxchg_called_with_bad_pointer(void);
-static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
- unsigned long new, int size)
-{
- unsigned long prev;
-
- switch (size) {
- case 4:
- __asm__ __volatile__(
- "sync;"
- "0: lwarx %0,0,%1 ;"
- " cmpl 0,%0,%3;"
- " bne 1f;"
- " stwcx. %2,0,%1;"
- " bne- 0b;"
- "1: "
- "sync;"
- : "=&r"(prev)
- : "r"(ptr), "r"(new), "r"(old)
- : "cr0", "memory");
- return prev;
- }
- __cmpxchg_called_with_bad_pointer();
- return old;
-}
-
-#endif /* i386, powerpc & alpha */
+#endif
-#ifndef __alpha__
-#define cmpxchg(ptr,o,n) \
- ((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o), \
- (unsigned long)(n),sizeof(*(ptr))))
+#if LINUX_VERSION_CODE < 0x020500
+#define DRM_RPR_ARG(vma)
+#else
+#define DRM_RPR_ARG(vma) vma,
#endif
-#endif /* !__HAVE_ARCH_CMPXCHG */
+
+#define VM_OFFSET(vma) ((vma)->vm_pgoff << PAGE_SHIFT)
/* Macros to make printk easier */
#define DRM_ERROR(fmt, arg...) \
#define DRM_IOREMAP(map) \
(map)->handle = DRM(ioremap)( (map)->offset, (map)->size )
+#define DRM_IOREMAP_NOCACHE(map) \
+ (map)->handle = DRM(ioremap_nocache)((map)->offset, (map)->size)
+
#define DRM_IOREMAPFREE(map) \
do { \
if ( (map)->handle && (map)->size ) \
struct poll_table_struct *wait);
/* Mapping support (drm_vm.h) */
-#if LINUX_VERSION_CODE < 0x020317
-extern unsigned long DRM(vm_nopage)(struct vm_area_struct *vma,
- unsigned long address,
- int unused);
-extern unsigned long DRM(vm_shm_nopage)(struct vm_area_struct *vma,
- unsigned long address,
- int unused);
-extern unsigned long DRM(vm_dma_nopage)(struct vm_area_struct *vma,
- unsigned long address,
- int unused);
-extern unsigned long DRM(vm_sg_nopage)(struct vm_area_struct *vma,
- unsigned long address,
- int unused);
-#else
- /* Return type changed in 2.3.23 */
extern struct page *DRM(vm_nopage)(struct vm_area_struct *vma,
unsigned long address,
- int unused);
+ int write_access);
extern struct page *DRM(vm_shm_nopage)(struct vm_area_struct *vma,
unsigned long address,
- int unused);
+ int write_access);
extern struct page *DRM(vm_dma_nopage)(struct vm_area_struct *vma,
unsigned long address,
- int unused);
+ int write_access);
extern struct page *DRM(vm_sg_nopage)(struct vm_area_struct *vma,
unsigned long address,
- int unused);
-#endif
+ int write_access);
extern void DRM(vm_open)(struct vm_area_struct *vma);
extern void DRM(vm_close)(struct vm_area_struct *vma);
extern void DRM(vm_shm_close)(struct vm_area_struct *vma);
extern void DRM(free_pages)(unsigned long address, int order,
int area);
extern void *DRM(ioremap)(unsigned long offset, unsigned long size);
+extern void *DRM(ioremap_nocache)(unsigned long offset, unsigned long size);
extern void DRM(ioremapfree)(void *pt, unsigned long size);
#if __REALLY_HAVE_AGP
#if __REALLY_HAVE_AGP
-#if LINUX_VERSION_CODE < 0x020400
-#include "agpsupport-pre24.h"
-#else
#define DRM_AGP_GET (drm_agp_t *)inter_module_get("drm_agp")
#define DRM_AGP_PUT inter_module_put("drm_agp")
-#endif
static const drm_agp_t *drm_agp = NULL;
case INTEL_GX: head->chipset = "Intel 440GX"; break;
case INTEL_I810: head->chipset = "Intel i810"; break;
-#if LINUX_VERSION_CODE >= 0x020400
case INTEL_I815: head->chipset = "Intel i815"; break;
+#if LINUX_VERSION_CODE >= 0x020415
case INTEL_I820: head->chipset = "Intel i820"; break;
+#endif
case INTEL_I840: head->chipset = "Intel i840"; break;
+#if LINUX_VERSION_CODE >= 0x020415
case INTEL_I845: head->chipset = "Intel i845"; break;
- case INTEL_I850: head->chipset = "Intel i850"; break;
#endif
+ case INTEL_I850: head->chipset = "Intel i850"; break;
case VIA_GENERIC: head->chipset = "VIA"; break;
case VIA_VP3: head->chipset = "VIA VP3"; break;
case VIA_MVP3: head->chipset = "VIA MVP3"; break;
-#if LINUX_VERSION_CODE >= 0x020400
case VIA_MVP4: head->chipset = "VIA MVP4"; break;
case VIA_APOLLO_KX133: head->chipset = "VIA Apollo KX133";
break;
case VIA_APOLLO_KT133: head->chipset = "VIA Apollo KT133";
break;
-#endif
case VIA_APOLLO_PRO: head->chipset = "VIA Apollo Pro";
break;
hash = DRM(hash_magic)(magic);
entry = DRM(alloc)(sizeof(*entry), DRM_MEM_MAGIC);
if (!entry) return -ENOMEM;
+ memset(entry, 0, sizeof(*entry));
entry->magic = magic;
entry->priv = priv;
entry->next = NULL;
DRM(free)(list, sizeof(*list), DRM_MEM_MAPS);
for (pt = dev->vmalist, prev = NULL; pt; prev = pt, pt = pt->next) {
-#if LINUX_VERSION_CODE >= 0x020300
if (pt->vma->vm_private_data == map) found_maps++;
-#else
- if (pt->vma->vm_pte == map) found_maps++;
-#endif
}
if(!found_maps) {
* Authors:
* Rickard E. (Rik) Faith <faith@valinux.com>
* Gareth Hughes <gareth@valinux.com>
+ * ChangeLog:
+ * 2001-11-16 Torsten Duwe <duwe@caldera.de>
+ * added context constructor/destructor hooks,
+ * needed by SiS driver's memory management.
*/
#define __NO_VERSION__
/* Should this return -EBUSY instead? */
return -ENOMEM;
}
+#ifdef DRIVER_CTX_CTOR
+ if ( ctx.handle != DRM_KERNEL_CONTEXT )
+ DRIVER_CTX_CTOR(ctx.handle); /* XXX: also pass dev ? */
+#endif
if ( copy_to_user( (drm_ctx_t *)arg, &ctx, sizeof(ctx) ) )
return -EFAULT;
priv->remove_auth_on_close = 1;
}
if ( ctx.handle != DRM_KERNEL_CONTEXT ) {
+#ifdef DRIVER_CTX_DTOR
+ DRIVER_CTX_DTOR(ctx.handle); /* XXX: also pass dev ? */
+#endif
DRM(ctxbitmap_free)( dev, ctx.handle );
}
}
}
+#else
+
+int DRM(control)( struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg )
+{
+ drm_control_t ctl;
+
+ if ( copy_from_user( &ctl, (drm_control_t *)arg, sizeof(ctl) ) )
+ return -EFAULT;
+
+ switch ( ctl.func ) {
+ case DRM_INST_HANDLER:
+ case DRM_UNINST_HANDLER:
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
#endif /* __HAVE_DMA_IRQ */
#endif /* __HAVE_DMA */
#define DRIVER_IOCTLS
#endif
#ifndef DRIVER_FOPS
-#if LINUX_VERSION_CODE >= 0x020400
#define DRIVER_FOPS \
static struct file_operations DRM(fops) = { \
owner: THIS_MODULE, \
fasync: DRM(fasync), \
poll: DRM(poll), \
}
-#else
-#define DRIVER_FOPS \
-static struct file_operations DRM(fops) = { \
- open: DRM(open), \
- flush: DRM(flush), \
- release: DRM(release), \
- ioctl: DRM(ioctl), \
- mmap: DRM(mmap), \
- read: DRM(read), \
- fasync: DRM(fasync), \
- poll: DRM(poll), \
-}
-#endif
#endif
/* The DRM_IOCTL_DMA ioctl should be defined by the driver.
*/
-#if __HAVE_DMA_IRQ
[DRM_IOCTL_NR(DRM_IOCTL_CONTROL)] = { DRM(control), 1, 1 },
#endif
-#endif
#if __REALLY_HAVE_AGP
[DRM_IOCTL_NR(DRM_IOCTL_AGP_ACQUIRE)] = { DRM(agp_acquire), 1, 1 },
retcode = DRM(open_helper)( inode, filp, dev );
if ( !retcode ) {
-#if LINUX_VERSION_CODE < 0x020333
- MOD_INC_USE_COUNT; /* Needed before Linux 2.3.51 */
-#endif
atomic_inc( &dev->counts[_DRM_STAT_OPENS] );
spin_lock( &dev->count_lock );
if ( !dev->open_count++ ) {
* End inline drm_release
*/
-#if LINUX_VERSION_CODE < 0x020333
- MOD_DEC_USE_COUNT; /* Needed before Linux 2.3.51 */
-#endif
atomic_inc( &dev->counts[_DRM_STAT_CLOSES] );
spin_lock( &dev->count_lock );
if ( !--dev->open_count ) {
send -= count;
}
-#if LINUX_VERSION_CODE < 0x020315 && !defined(KILLFASYNCHASTHREEPARAMETERS)
- /* The extra parameter to kill_fasync was added in 2.3.21, and is
- _not_ present in _stock_ 2.2.14 and 2.2.15. However, some
- distributions patch 2.2.x kernels to add this parameter. The
- Makefile.linux attempts to detect this addition and defines
- KILLFASYNCHASTHREEPARAMETERS if three parameters are found. */
- if (dev->buf_async) kill_fasync(dev->buf_async, SIGIO);
-#else
-
- /* Parameter added in 2.3.21. */
-#if LINUX_VERSION_CODE < 0x020400
- if (dev->buf_async) kill_fasync(dev->buf_async, SIGIO, POLL_IN);
-#else
- /* Type of first parameter changed in
- Linux 2.4.0-test2... */
if (dev->buf_async) kill_fasync(&dev->buf_async, SIGIO, POLL_IN);
-#endif
-#endif
+
DRM_DEBUG("waking\n");
wake_up_interruptible(&dev->buf_readers);
return 0;
DRM_MEM_BUFLISTS);
if(!bl->bufs) return -ENOMEM;
-
+ memset(bl->bufs, 0, sizeof(*bl->bufs));
bl->count = count;
bl->rp = bl->bufs;
bl->wp = bl->bufs;
}
si_meminfo(&si);
-#if LINUX_VERSION_CODE < 0x020317
- /* Changed to page count in 2.3.23 */
- DRM(ram_available) = si.totalram >> PAGE_SHIFT;
-#else
DRM(ram_available) = si.totalram;
-#endif
DRM(ram_used) = 0;
}
for (addr = address, sz = bytes;
sz > 0;
addr += PAGE_SIZE, sz -= PAGE_SIZE) {
-#if LINUX_VERSION_CODE >= 0x020400
- /* Argument type changed in 2.4.0-test6/pre8 */
mem_map_reserve(virt_to_page(addr));
-#else
- mem_map_reserve(MAP_NR(addr));
-#endif
}
return address;
for (addr = address, sz = bytes;
sz > 0;
addr += PAGE_SIZE, sz -= PAGE_SIZE) {
-#if LINUX_VERSION_CODE >= 0x020400
- /* Argument type changed in 2.4.0-test6/pre8 */
mem_map_unreserve(virt_to_page(addr));
-#else
- mem_map_unreserve(MAP_NR(addr));
-#endif
}
free_pages(address, order);
}
return pt;
}
+void *DRM(ioremap_nocache)(unsigned long offset, unsigned long size)
+{
+ void *pt;
+
+ if (!size) {
+ DRM_MEM_ERROR(DRM_MEM_MAPPINGS,
+ "Mapping 0 bytes at 0x%08lx\n", offset);
+ return NULL;
+ }
+
+ if (!(pt = ioremap_nocache(offset, size))) {
+ spin_lock(&DRM(mem_lock));
+ ++DRM(mem_stats)[DRM_MEM_MAPPINGS].fail_count;
+ spin_unlock(&DRM(mem_lock));
+ return NULL;
+ }
+ spin_lock(&DRM(mem_lock));
+ ++DRM(mem_stats)[DRM_MEM_MAPPINGS].succeed_count;
+ DRM(mem_stats)[DRM_MEM_MAPPINGS].bytes_allocated += size;
+ spin_unlock(&DRM(mem_lock));
+ return pt;
+}
+
void DRM(ioremapfree)(void *pt, unsigned long size)
{
int alloc_count;
return -ENOMEM;
}
+ memset(entry->pagelist, 0, pages * sizeof(*entry->pagelist));
+
entry->busaddr = DRM(alloc)( pages * sizeof(*entry->busaddr),
DRM_MEM_PAGES );
if ( !entry->busaddr ) {
#define __NO_VERSION__
#include "drmP.h"
-#if LINUX_VERSION_CODE < 0x020400
-#include "stubsupport-pre24.h"
-#endif
-
#define DRM_STUB_MAXCARDS 16 /* Enough for one machine */
static struct drm_stub_list {
}
static struct file_operations DRM(stub_fops) = {
-#if LINUX_VERSION_CODE >= 0x020400
owner: THIS_MODULE,
-#endif
open: DRM(stub_open)
};
close: DRM(vm_close),
};
-#if LINUX_VERSION_CODE < 0x020317
-unsigned long DRM(vm_nopage)(struct vm_area_struct *vma,
- unsigned long address,
- int unused)
-#else
- /* Return type changed in 2.3.23 */
struct page *DRM(vm_nopage)(struct vm_area_struct *vma,
unsigned long address,
- int unused)
-#endif
+ int write_access)
{
#if __REALLY_HAVE_AGP
drm_file_t *priv = vma->vm_file->private_data;
DRM_DEBUG("baddr = 0x%lx page = 0x%p, offset = 0x%lx\n",
baddr, __va(agpmem->memory->memory[offset]), offset);
-#if LINUX_VERSION_CODE < 0x020317
- return page_address(page);
-#else
return page;
-#endif
}
vm_nopage_error:
#endif /* __REALLY_HAVE_AGP */
return NOPAGE_SIGBUS; /* Disallow mremap */
}
-#if LINUX_VERSION_CODE < 0x020317
-unsigned long DRM(vm_shm_nopage)(struct vm_area_struct *vma,
- unsigned long address,
- int unused)
-#else
- /* Return type changed in 2.3.23 */
struct page *DRM(vm_shm_nopage)(struct vm_area_struct *vma,
unsigned long address,
- int unused)
-#endif
+ int write_access)
{
-#if LINUX_VERSION_CODE >= 0x020300
drm_map_t *map = (drm_map_t *)vma->vm_private_data;
-#else
- drm_map_t *map = (drm_map_t *)vma->vm_pte;
-#endif
unsigned long offset;
unsigned long i;
struct page *page;
get_page(page);
DRM_DEBUG("shm_nopage 0x%lx\n", address);
-#if LINUX_VERSION_CODE < 0x020317
- return page_address(page);
-#else
return page;
-#endif
}
/* Special close routine which deletes map information if we are the last
DRM_DEBUG("0x%08lx,0x%08lx\n",
vma->vm_start, vma->vm_end - vma->vm_start);
-#if LINUX_VERSION_CODE < 0x020333
- MOD_DEC_USE_COUNT; /* Needed before Linux 2.3.51 */
-#endif
atomic_dec(&dev->vma_count);
-#if LINUX_VERSION_CODE >= 0x020300
map = vma->vm_private_data;
-#else
- map = vma->vm_pte;
-#endif
down(&dev->struct_sem);
for (pt = dev->vmalist, prev = NULL; pt; pt = next) {
next = pt->next;
-#if LINUX_VERSION_CODE >= 0x020300
if (pt->vma->vm_private_data == map) found_maps++;
-#else
- if (pt->vma->vm_pte == map) found_maps++;
-#endif
if (pt->vma == vma) {
if (prev) {
prev->next = pt->next;
up(&dev->struct_sem);
}
-#if LINUX_VERSION_CODE < 0x020317
-unsigned long DRM(vm_dma_nopage)(struct vm_area_struct *vma,
- unsigned long address,
- int unused)
-#else
- /* Return type changed in 2.3.23 */
struct page *DRM(vm_dma_nopage)(struct vm_area_struct *vma,
unsigned long address,
- int unused)
-#endif
+ int write_access)
{
drm_file_t *priv = vma->vm_file->private_data;
drm_device_t *dev = priv->dev;
get_page(page);
- DRM_DEBUG("dma_nopage 0x%lx (page %lu)\n", address, page_nr);
-#if LINUX_VERSION_CODE < 0x020317
- return page_address(page);
-#else
+ DRM_DEBUG("dma_nopage 0x%lx (page %lu)\n", address, page_nr);
return page;
-#endif
}
-#if LINUX_VERSION_CODE < 0x020317
-unsigned long DRM(vm_sg_nopage)(struct vm_area_struct *vma,
- unsigned long address,
- int unused)
-#else
- /* Return type changed in 2.3.23 */
struct page *DRM(vm_sg_nopage)(struct vm_area_struct *vma,
unsigned long address,
- int unused)
-#endif
+ int write_access)
{
-#if LINUX_VERSION_CODE >= 0x020300
drm_map_t *map = (drm_map_t *)vma->vm_private_data;
-#else
- drm_map_t *map = (drm_map_t *)vma->vm_pte;
-#endif
drm_file_t *priv = vma->vm_file->private_data;
drm_device_t *dev = priv->dev;
drm_sg_mem_t *entry = dev->sg;
page = entry->pagelist[page_offset];
get_page(page);
-#if LINUX_VERSION_CODE < 0x020317
- return page_address(page);
-#else
return page;
-#endif
}
void DRM(vm_open)(struct vm_area_struct *vma)
DRM_DEBUG("0x%08lx,0x%08lx\n",
vma->vm_start, vma->vm_end - vma->vm_start);
atomic_inc(&dev->vma_count);
-#if LINUX_VERSION_CODE < 0x020333
- /* The map can exist after the fd is closed. */
- MOD_INC_USE_COUNT; /* Needed before Linux 2.3.51 */
-#endif
vma_entry = DRM(alloc)(sizeof(*vma_entry), DRM_MEM_VMAS);
if (vma_entry) {
DRM_DEBUG("0x%08lx,0x%08lx\n",
vma->vm_start, vma->vm_end - vma->vm_start);
-#if LINUX_VERSION_CODE < 0x020333
- MOD_DEC_USE_COUNT; /* Needed before Linux 2.3.51 */
-#endif
atomic_dec(&dev->vma_count);
down(&dev->struct_sem);
unlock_kernel();
vma->vm_ops = &DRM(vm_dma_ops);
- vma->vm_flags |= VM_RESERVED; /* Don't swap */
-#if LINUX_VERSION_CODE < 0x020203 /* KERNEL_VERSION(2,2,3) */
- /* In Linux 2.2.3 and above, this is
- handled in do_mmap() in mm/mmap.c. */
- ++filp->f_count;
+#if LINUX_VERSION_CODE <= 0x020414
+ vma->vm_flags |= VM_LOCKED | VM_SHM; /* Don't swap */
+#else
+ vma->vm_flags |= VM_RESERVED; /* Don't swap */
#endif
+
vma->vm_file = filp; /* Needed for drm_vm_open() */
DRM(vm_open)(vma);
return 0;
}
offset = DRIVER_GET_REG_OFS();
#ifdef __sparc__
- if (io_remap_page_range(vma, vma->vm_start,
+ if (io_remap_page_range(DRM_RPR_ARG(vma) vma->vm_start,
VM_OFFSET(vma) + offset,
vma->vm_end - vma->vm_start,
vma->vm_page_prot, 0))
#else
- if (remap_page_range(vma, vma->vm_start,
+ if (remap_page_range(DRM_RPR_ARG(vma) vma->vm_start,
VM_OFFSET(vma) + offset,
vma->vm_end - vma->vm_start,
vma->vm_page_prot))
break;
case _DRM_SHM:
vma->vm_ops = &DRM(vm_shm_ops);
-#if LINUX_VERSION_CODE >= 0x020300
vma->vm_private_data = (void *)map;
-#else
- vma->vm_pte = (unsigned long)map;
-#endif
/* Don't let this area swap. Change when
DRM_KERNEL advisory is supported. */
+#if LINUX_VERSION_CODE <= 0x020414
+ vma->vm_flags |= VM_LOCKED;
+#else
vma->vm_flags |= VM_RESERVED;
+#endif
break;
case _DRM_SCATTER_GATHER:
vma->vm_ops = &DRM(vm_sg_ops);
-#if LINUX_VERSION_CODE >= 0x020300
vma->vm_private_data = (void *)map;
+#if LINUX_VERSION_CODE <= 0x020414
+ vma->vm_flags |= VM_LOCKED;
#else
- vma->vm_pte = (unsigned long)map;
+ vma->vm_flags |= VM_RESERVED;
#endif
- vma->vm_flags |= VM_RESERVED;
break;
default:
return -EINVAL; /* This should never happen. */
}
+#if LINUX_VERSION_CODE <= 0x020414
+ vma->vm_flags |= VM_LOCKED | VM_SHM; /* Don't swap */
+#else
vma->vm_flags |= VM_RESERVED; /* Don't swap */
-
-#if LINUX_VERSION_CODE < 0x020203 /* KERNEL_VERSION(2,2,3) */
- /* In Linux 2.2.3 and above, this is
- handled in do_mmap() in mm/mmap.c. */
- ++filp->f_count;
#endif
+
vma->vm_file = filp; /* Needed for drm_vm_open() */
DRM(vm_open)(vma);
return 0;
/* DMA customization:
*/
#define __HAVE_DMA 1
+#define __HAVE_AGP 1
+#define __MUST_HAVE_AGP 0
#define __HAVE_OLD_DMA 1
#define __HAVE_PCI_DMA 1
#define __HAVE_DMA_QUIESCENT 1
#define DRIVER_DMA_QUIESCENT() do { \
/* FIXME ! */ \
- gamma_dma_quiescent_dual(dev); \
+ gamma_dma_quiescent_single(dev); \
return 0; \
} while (0)
#define __HAVE_DMA_IRQ 1
#define __HAVE_DMA_IRQ_BH 1
+
+#if 1
#define DRIVER_PREINSTALL() do { \
drm_gamma_private_t *dev_priv = \
(drm_gamma_private_t *)dev->dev_private;\
- GAMMA_WRITE( GAMMA_GCOMMANDMODE, 0x00000000 ); \
+ while(GAMMA_READ(GAMMA_INFIFOSPACE) < 2); \
+ GAMMA_WRITE( GAMMA_GCOMMANDMODE, 0x00000004 ); \
GAMMA_WRITE( GAMMA_GDMACONTROL, 0x00000000 ); \
} while (0)
-
#define DRIVER_POSTINSTALL() do { \
drm_gamma_private_t *dev_priv = \
(drm_gamma_private_t *)dev->dev_private;\
+ while(GAMMA_READ(GAMMA_INFIFOSPACE) < 2); \
+ while(GAMMA_READ(GAMMA_INFIFOSPACE) < 3); \
GAMMA_WRITE( GAMMA_GINTENABLE, 0x00002001 ); \
GAMMA_WRITE( GAMMA_COMMANDINTENABLE, 0x00000008 ); \
GAMMA_WRITE( GAMMA_GDELAYTIMER, 0x00039090 ); \
} while (0)
+#else
+#define DRIVER_POSTINSTALL() do { \
+ drm_gamma_private_t *dev_priv = \
+ (drm_gamma_private_t *)dev->dev_private;\
+ while(GAMMA_READ(GAMMA_INFIFOSPACE) < 2); \
+ while(GAMMA_READ(GAMMA_INFIFOSPACE) < 2); \
+ GAMMA_WRITE( GAMMA_GINTENABLE, 0x00002000 ); \
+ GAMMA_WRITE( GAMMA_COMMANDINTENABLE, 0x00000004 ); \
+} while (0)
+
+#define DRIVER_PREINSTALL() do { \
+ drm_gamma_private_t *dev_priv = \
+ (drm_gamma_private_t *)dev->dev_private;\
+ while(GAMMA_READ(GAMMA_INFIFOSPACE) < 2); \
+ while(GAMMA_READ(GAMMA_INFIFOSPACE) < 2); \
+ GAMMA_WRITE( GAMMA_GCOMMANDMODE, GAMMA_QUEUED_DMA_MODE );\
+ GAMMA_WRITE( GAMMA_GDMACONTROL, 0x00000000 );\
+} while (0)
+#endif
#define DRIVER_UNINSTALL() do { \
drm_gamma_private_t *dev_priv = \
(drm_gamma_private_t *)dev->dev_private;\
+ while(GAMMA_READ(GAMMA_INFIFOSPACE) < 2); \
+ while(GAMMA_READ(GAMMA_INFIFOSPACE) < 3); \
GAMMA_WRITE( GAMMA_GDELAYTIMER, 0x00000000 ); \
GAMMA_WRITE( GAMMA_COMMANDINTENABLE, 0x00000000 ); \
GAMMA_WRITE( GAMMA_GINTENABLE, 0x00000000 ); \
} while (0)
+#define DRIVER_AGP_BUFFERS_MAP( dev ) \
+ ((drm_gamma_private_t *)((dev)->dev_private))->buffers
+
#endif /* __GAMMA_H__ */
#include <linux/interrupt.h> /* For task queue support */
#include <linux/delay.h>
-
static inline void gamma_dma_dispatch(drm_device_t *dev, unsigned long address,
unsigned long length)
{
drm_gamma_private_t *dev_priv =
- (drm_gamma_private_t *)dev->dev_private;
-
- GAMMA_WRITE(GAMMA_DMAADDRESS, virt_to_phys((void *)address));
- while (GAMMA_READ(GAMMA_GCOMMANDSTATUS) != 4)
- ;
+ (drm_gamma_private_t *)dev->dev_private;
+ mb();
+ while ( GAMMA_READ(GAMMA_INFIFOSPACE) < 2);
+ GAMMA_WRITE(GAMMA_DMAADDRESS, address);
+ while (GAMMA_READ(GAMMA_GCOMMANDSTATUS) != 4);
GAMMA_WRITE(GAMMA_DMACOUNT, length / 4);
}
void gamma_dma_quiescent_single(drm_device_t *dev)
{
drm_gamma_private_t *dev_priv =
- (drm_gamma_private_t *)dev->dev_private;
+ (drm_gamma_private_t *)dev->dev_private;
+ while (GAMMA_READ(GAMMA_DMACOUNT));
- while (GAMMA_READ(GAMMA_DMACOUNT))
- ;
- while (GAMMA_READ(GAMMA_INFIFOSPACE) < 3)
- ;
+ while (GAMMA_READ(GAMMA_INFIFOSPACE) < 2);
GAMMA_WRITE(GAMMA_FILTERMODE, 1 << 10);
GAMMA_WRITE(GAMMA_SYNC, 0);
void gamma_dma_quiescent_dual(drm_device_t *dev)
{
drm_gamma_private_t *dev_priv =
- (drm_gamma_private_t *)dev->dev_private;
+ (drm_gamma_private_t *)dev->dev_private;
+ while (GAMMA_READ(GAMMA_DMACOUNT));
- while (GAMMA_READ(GAMMA_DMACOUNT))
- ;
- while (GAMMA_READ(GAMMA_INFIFOSPACE) < 3)
- ;
+ while (GAMMA_READ(GAMMA_INFIFOSPACE) < 3);
GAMMA_WRITE(GAMMA_BROADCASTMASK, 3);
-
GAMMA_WRITE(GAMMA_FILTERMODE, 1 << 10);
GAMMA_WRITE(GAMMA_SYNC, 0);
- /* Read from first MX */
+ /* Read from first MX */
do {
- while (!GAMMA_READ(GAMMA_OUTFIFOWORDS))
- ;
+ while (!GAMMA_READ(GAMMA_OUTFIFOWORDS));
} while (GAMMA_READ(GAMMA_OUTPUTFIFO) != GAMMA_SYNC_TAG);
- /* Read from second MX */
+ /* Read from second MX */
do {
- while (!GAMMA_READ(GAMMA_OUTFIFOWORDS + 0x10000))
- ;
+ while (!GAMMA_READ(GAMMA_OUTFIFOWORDS + 0x10000));
} while (GAMMA_READ(GAMMA_OUTPUTFIFO + 0x10000) != GAMMA_SYNC_TAG);
}
void gamma_dma_ready(drm_device_t *dev)
{
drm_gamma_private_t *dev_priv =
- (drm_gamma_private_t *)dev->dev_private;
-
- while (GAMMA_READ(GAMMA_DMACOUNT))
- ;
+ (drm_gamma_private_t *)dev->dev_private;
+ while (GAMMA_READ(GAMMA_DMACOUNT));
}
static inline int gamma_dma_is_ready(drm_device_t *dev)
{
drm_gamma_private_t *dev_priv =
- (drm_gamma_private_t *)dev->dev_private;
-
- return !GAMMA_READ(GAMMA_DMACOUNT);
+ (drm_gamma_private_t *)dev->dev_private;
+ return(!GAMMA_READ(GAMMA_DMACOUNT));
}
void gamma_dma_service(int irq, void *device, struct pt_regs *regs)
{
- drm_device_t *dev = (drm_device_t *)device;
- drm_device_dma_t *dma = dev->dma;
+ drm_device_t *dev = (drm_device_t *)device;
+ drm_device_dma_t *dma = dev->dma;
drm_gamma_private_t *dev_priv =
- (drm_gamma_private_t *)dev->dev_private;
+ (drm_gamma_private_t *)dev->dev_private;
atomic_inc(&dev->counts[6]); /* _DRM_STAT_IRQ */
+
+ while (GAMMA_READ(GAMMA_INFIFOSPACE) < 3);
GAMMA_WRITE(GAMMA_GDELAYTIMER, 0xc350/2); /* 0x05S */
GAMMA_WRITE(GAMMA_GCOMMANDINTFLAGS, 8);
GAMMA_WRITE(GAMMA_GINTFLAGS, 0x2001);
}
buf = dma->next_buffer;
- address = (unsigned long)buf->address;
+ /* WE NOW ARE ON LOGICAL PAGES!! - using page table setup in dma_init */
+ /* So we pass the buffer index value into the physical page offset */
+ address = buf->idx << 12;
length = buf->used;
DRM_DEBUG("context %d, buffer %d (%ld bytes)\n",
buf->time_dispatched = get_cycles();
#endif
+ /* WE NOW ARE ON LOGICAL PAGES!!! - overriding address */
+ address = buf->idx << 12;
+
gamma_dma_dispatch(dev, address, length);
gamma_free_buffer(dev, dma->this_buffer);
dma->this_buffer = buf;
return retcode;
}
+
+/* =============================================================
+ * DMA initialization, cleanup
+ */
+
+static int gamma_do_init_dma( drm_device_t *dev, drm_gamma_init_t *init )
+{
+ drm_gamma_private_t *dev_priv;
+ drm_device_dma_t *dma = dev->dma;
+ drm_buf_t *buf;
+ int i;
+ struct list_head *list;
+ unsigned int *pgt;
+
+ DRM_DEBUG( "%s\n", __FUNCTION__ );
+
+ dev_priv = DRM(alloc)( sizeof(drm_gamma_private_t),
+ DRM_MEM_DRIVER );
+ if ( !dev_priv )
+ return -ENOMEM;
+
+ dev->dev_private = (void *)dev_priv;
+
+ memset( dev_priv, 0, sizeof(drm_gamma_private_t) );
+
+ list_for_each(list, &dev->maplist->head) {
+ drm_map_list_t *r_list = (drm_map_list_t *)list;
+ if( r_list->map &&
+ r_list->map->type == _DRM_SHM &&
+ r_list->map->flags & _DRM_CONTAINS_LOCK ) {
+ dev_priv->sarea = r_list->map;
+ break;
+ }
+ }
+
+ DRM_FIND_MAP( dev_priv->mmio0, init->mmio0 );
+ DRM_FIND_MAP( dev_priv->mmio1, init->mmio1 );
+ DRM_FIND_MAP( dev_priv->mmio2, init->mmio2 );
+ DRM_FIND_MAP( dev_priv->mmio3, init->mmio3 );
+
+ dev_priv->sarea_priv = (drm_gamma_sarea_t *)
+ ((u8 *)dev_priv->sarea->handle +
+ init->sarea_priv_offset);
+
+ if (init->pcimode) {
+ buf = dma->buflist[GLINT_DRI_BUF_COUNT];
+ pgt = buf->address;
+
+ for (i = 0; i < GLINT_DRI_BUF_COUNT; i++) {
+ buf = dma->buflist[i];
+ *pgt = virt_to_phys((void*)buf->address) | 0x07;
+ pgt++;
+ }
+
+ buf = dma->buflist[GLINT_DRI_BUF_COUNT];
+ } else {
+ DRM_FIND_MAP( dev_priv->buffers, init->buffers_offset );
+
+ DRM_IOREMAP( dev_priv->buffers );
+
+ buf = dma->buflist[GLINT_DRI_BUF_COUNT];
+ pgt = buf->address;
+
+ for (i = 0; i < GLINT_DRI_BUF_COUNT; i++) {
+ buf = dma->buflist[i];
+ *pgt = (unsigned int)buf->address + 0x07;
+ pgt++;
+ }
+
+ buf = dma->buflist[GLINT_DRI_BUF_COUNT];
+
+ while (GAMMA_READ(GAMMA_INFIFOSPACE) < 1);
+ GAMMA_WRITE( GAMMA_GDMACONTROL, 0xe);
+ }
+ while (GAMMA_READ(GAMMA_INFIFOSPACE) < 2);
+ GAMMA_WRITE( GAMMA_PAGETABLEADDR, virt_to_phys((void*)buf->address) );
+ GAMMA_WRITE( GAMMA_PAGETABLELENGTH, 2 );
+
+ return 0;
+}
+
+int gamma_do_cleanup_dma( drm_device_t *dev )
+{
+ DRM_DEBUG( "%s\n", __FUNCTION__ );
+
+ if ( dev->dev_private ) {
+ drm_gamma_private_t *dev_priv = dev->dev_private;
+
+ DRM_IOREMAPFREE( dev_priv->buffers );
+
+ DRM(free)( dev->dev_private, sizeof(drm_gamma_private_t),
+ DRM_MEM_DRIVER );
+ dev->dev_private = NULL;
+ }
+
+ return 0;
+}
+
+int gamma_dma_init( struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg )
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ drm_gamma_init_t init;
+
+ if ( copy_from_user( &init, (drm_gamma_init_t *)arg, sizeof(init) ) )
+ return -EFAULT;
+
+ switch ( init.func ) {
+ case GAMMA_INIT_DMA:
+ return gamma_do_init_dma( dev, &init );
+ case GAMMA_CLEANUP_DMA:
+ return gamma_do_cleanup_dma( dev );
+ }
+
+ return -EINVAL;
+}
+
+static int gamma_do_copy_dma( drm_device_t *dev, drm_gamma_copy_t *copy )
+{
+ drm_device_dma_t *dma = dev->dma;
+ unsigned int *screenbuf;
+
+ DRM_DEBUG( "%s\n", __FUNCTION__ );
+
+ /* We've DRM_RESTRICTED this DMA buffer */
+
+ screenbuf = dma->buflist[ GLINT_DRI_BUF_COUNT + 1 ]->address;
+
+#if 0
+ *buffer++ = 0x180; /* Tag (FilterMode) */
+ *buffer++ = 0x200; /* Allow FBColor through */
+ *buffer++ = 0x53B; /* Tag */
+ *buffer++ = copy->Pitch;
+ *buffer++ = 0x53A; /* Tag */
+ *buffer++ = copy->SrcAddress;
+ *buffer++ = 0x539; /* Tag */
+ *buffer++ = copy->WidthHeight; /* Initiates transfer */
+ *buffer++ = 0x53C; /* Tag - DMAOutputAddress */
+ *buffer++ = virt_to_phys((void*)screenbuf);
+ *buffer++ = 0x53D; /* Tag - DMAOutputCount */
+ *buffer++ = copy->Count; /* Reads HostOutFifo BLOCKS until ..*/
+
+ /* Data now sitting in dma->buflist[ GLINT_DRI_BUF_COUNT + 1 ] */
+ /* Now put it back to the screen */
+
+ *buffer++ = 0x180; /* Tag (FilterMode) */
+ *buffer++ = 0x400; /* Allow Sync through */
+ *buffer++ = 0x538; /* Tag - DMARectangleReadTarget */
+ *buffer++ = 0x155; /* FBSourceData | count */
+ *buffer++ = 0x537; /* Tag */
+ *buffer++ = copy->Pitch;
+ *buffer++ = 0x536; /* Tag */
+ *buffer++ = copy->DstAddress;
+ *buffer++ = 0x535; /* Tag */
+ *buffer++ = copy->WidthHeight; /* Initiates transfer */
+ *buffer++ = 0x530; /* Tag - DMAAddr */
+ *buffer++ = virt_to_phys((void*)screenbuf);
+ *buffer++ = 0x531;
+ *buffer++ = copy->Count; /* initiates DMA transfer of color data */
+#endif
+
+ /* need to dispatch it now */
+
+ return 0;
+}
+
+int gamma_dma_copy( struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg )
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ drm_gamma_copy_t copy;
+
+ if ( copy_from_user( ©, (drm_gamma_copy_t *)arg, sizeof(copy) ) )
+ return -EFAULT;
+
+ return gamma_do_copy_dma( dev, © );
+}
+
+/* =============================================================
+ * Per Context SAREA Support
+ */
+
+int gamma_getsareactx(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ drm_ctx_priv_map_t request;
+ drm_map_t *map;
+
+ if (copy_from_user(&request,
+ (drm_ctx_priv_map_t *)arg,
+ sizeof(request)))
+ return -EFAULT;
+
+ down(&dev->struct_sem);
+ if ((int)request.ctx_id >= dev->max_context) {
+ up(&dev->struct_sem);
+ return -EINVAL;
+ }
+
+ map = dev->context_sareas[request.ctx_id];
+ up(&dev->struct_sem);
+
+ request.handle = map->handle;
+ if (copy_to_user((drm_ctx_priv_map_t *)arg, &request, sizeof(request)))
+ return -EFAULT;
+ return 0;
+}
+
+int gamma_setsareactx(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ drm_ctx_priv_map_t request;
+ drm_map_t *map = NULL;
+ drm_map_list_t *r_list;
+ struct list_head *list;
+
+ if (copy_from_user(&request,
+ (drm_ctx_priv_map_t *)arg,
+ sizeof(request)))
+ return -EFAULT;
+
+ down(&dev->struct_sem);
+ r_list = NULL;
+ list_for_each(list, &dev->maplist->head) {
+ r_list = (drm_map_list_t *)list;
+ if(r_list->map &&
+ r_list->map->handle == request.handle) break;
+ }
+ if (list == &(dev->maplist->head)) {
+ up(&dev->struct_sem);
+ return -EINVAL;
+ }
+ map = r_list->map;
+ up(&dev->struct_sem);
+
+ if (!map) return -EINVAL;
+
+ down(&dev->struct_sem);
+ if ((int)request.ctx_id >= dev->max_context) {
+ up(&dev->struct_sem);
+ return -EINVAL;
+ }
+ dev->context_sareas[request.ctx_id] = map;
+ up(&dev->struct_sem);
+ return 0;
+}
--- /dev/null
+#ifndef _GAMMA_DRM_H_
+#define _GAMMA_DRM_H_
+
+typedef struct _drm_gamma_tex_region {
+ unsigned char next, prev; /* indices to form a circular LRU */
+ unsigned char in_use; /* owned by a client, or free? */
+ int age; /* tracked by clients to update local LRU's */
+} drm_gamma_tex_region_t;
+
+typedef struct {
+ unsigned int GDeltaMode;
+ unsigned int GDepthMode;
+ unsigned int GGeometryMode;
+ unsigned int GTransformMode;
+} drm_gamma_context_regs_t;
+
+typedef struct _drm_gamma_sarea {
+ drm_gamma_context_regs_t context_state;
+
+ unsigned int dirty;
+
+
+ /* Maintain an LRU of contiguous regions of texture space. If
+ * you think you own a region of texture memory, and it has an
+ * age different to the one you set, then you are mistaken and
+ * it has been stolen by another client. If global texAge
+ * hasn't changed, there is no need to walk the list.
+ *
+ * These regions can be used as a proxy for the fine-grained
+ * texture information of other clients - by maintaining them
+ * in the same lru which is used to age their own textures,
+ * clients have an approximate lru for the whole of global
+ * texture space, and can make informed decisions as to which
+ * areas to kick out. There is no need to choose whether to
+ * kick out your own texture or someone else's - simply eject
+ * them all in LRU order.
+ */
+
+#define GAMMA_NR_TEX_REGIONS 64
+ drm_gamma_tex_region_t texList[GAMMA_NR_TEX_REGIONS+1];
+ /* Last elt is sentinal */
+ int texAge; /* last time texture was uploaded */
+ int last_enqueue; /* last time a buffer was enqueued */
+ int last_dispatch; /* age of the most recently dispatched buffer */
+ int last_quiescent; /* */
+ int ctxOwner; /* last context to upload state */
+
+ int vertex_prim;
+} drm_gamma_sarea_t;
+
+typedef struct drm_gamma_copy {
+ unsigned int DMAOutputAddress;
+ unsigned int DMAOutputCount;
+ unsigned int DMAReadGLINTSource;
+ unsigned int DMARectangleWriteAddress;
+ unsigned int DMARectangleWriteLinePitch;
+ unsigned int DMARectangleWrite;
+ unsigned int DMARectangleReadAddress;
+ unsigned int DMARectangleReadLinePitch;
+ unsigned int DMARectangleRead;
+ unsigned int DMARectangleReadTarget;
+} drm_gamma_copy_t;
+
+typedef struct drm_gamma_init {
+ enum {
+ GAMMA_INIT_DMA = 0x01,
+ GAMMA_CLEANUP_DMA = 0x02
+ } func;
+
+ int sarea_priv_offset;
+ int pcimode;
+ unsigned int mmio0;
+ unsigned int mmio1;
+ unsigned int mmio2;
+ unsigned int mmio3;
+ unsigned int buffers_offset;
+} drm_gamma_init_t;
+
+#endif /* _GAMMA_DRM_H_ */
#define DRIVER_NAME "gamma"
#define DRIVER_DESC "3DLabs gamma"
-#define DRIVER_DATE "20010216"
+#define DRIVER_DATE "20010624"
-#define DRIVER_MAJOR 1
+#define DRIVER_MAJOR 2
#define DRIVER_MINOR 0
#define DRIVER_PATCHLEVEL 0
#define DRIVER_IOCTLS \
- [DRM_IOCTL_NR(DRM_IOCTL_DMA)] = { gamma_dma, 1, 0 }
+ [DRM_IOCTL_NR(DRM_IOCTL_DMA)] = { gamma_dma, 1, 0 }, \
+ [DRM_IOCTL_NR(DRM_IOCTL_GAMMA_INIT)] = { gamma_dma_init, 1, 1 }, \
+ [DRM_IOCTL_NR(DRM_IOCTL_GAMMA_COPY)] = { gamma_dma_copy, 1, 1 }
+#define IOCTL_TABLE_NAME DRM(ioctls)
+#define IOCTL_FUNC_NAME DRM(ioctl)
#define __HAVE_COUNTERS 5
#define __HAVE_COUNTER6 _DRM_STAT_IRQ
#include "drm_auth.h"
+#include "drm_agpsupport.h"
#include "drm_bufs.h"
#include "drm_context.h"
#include "drm_dma.h"
__setup( DRIVER_NAME "=", gamma_options );
#endif
-
#include "drm_fops.h"
#include "drm_init.h"
#include "drm_ioctl.h"
#ifndef _GAMMA_DRV_H_
#define _GAMMA_DRV_H_
-
typedef struct drm_gamma_private {
+ drm_gamma_sarea_t *sarea_priv;
+ drm_map_t *sarea;
drm_map_t *buffers;
drm_map_t *mmio0;
drm_map_t *mmio1;
} \
} while (0)
+ /* gamma_dma.c */
+extern int gamma_dma_init( struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg );
+extern int gamma_dma_copy( struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg );
extern void gamma_dma_ready(drm_device_t *dev);
extern void gamma_dma_quiescent_single(drm_device_t *dev);
extern int gamma_find_devices(void);
extern int gamma_found(void);
+#define GLINT_DRI_BUF_COUNT 256
#define GAMMA_OFF(reg) \
((reg < 0x1000) \
((reg < 0x10000) ? dev_priv->mmio1->handle : \
((reg < 0x11000) ? dev_priv->mmio2->handle : \
dev_priv->mmio3->handle))))
-
#define GAMMA_ADDR(reg) (GAMMA_BASE(reg) + GAMMA_OFF(reg))
#define GAMMA_DEREF(reg) *(__volatile__ int *)GAMMA_ADDR(reg)
#define GAMMA_READ(reg) GAMMA_DEREF(reg)
#define GAMMA_FILTERMODE 0x8c00
#define GAMMA_GCOMMANDINTFLAGS 0x0c50
#define GAMMA_GCOMMANDMODE 0x0c40
+#define GAMMA_QUEUED_DMA_MODE 1<<1
#define GAMMA_GCOMMANDSTATUS 0x0c60
#define GAMMA_GDELAYTIMER 0x0c38
#define GAMMA_GDMACONTROL 0x0060
+#define GAMMA_USE_AGP 1<<1
#define GAMMA_GINTENABLE 0x0808
#define GAMMA_GINTFLAGS 0x0810
#define GAMMA_INFIFOSPACE 0x0018
#define GAMMA_OUTPUTFIFO 0x2000
#define GAMMA_SYNC 0x8c40
#define GAMMA_SYNC_TAG 0x0188
+#define GAMMA_PAGETABLEADDR 0x0C00
+#define GAMMA_PAGETABLELENGTH 0x0C08
+
+#define GAMMA_PASSTHROUGH 0x1FE
+#define GAMMA_DMAADDRTAG 0x530
+#define GAMMA_DMACOUNTTAG 0x531
+#define GAMMA_COMMANDINTTAG 0x532
#endif
i810_dma_quiescent( dev ); \
} while (0)
-#define __HAVE_DMA_IRQ 1
-#define __HAVE_DMA_IRQ_BH 1
-#define __HAVE_SHARED_IRQ 1
-#define DRIVER_PREINSTALL() do { \
- drm_i810_private_t *dev_priv = \
- (drm_i810_private_t *)dev->dev_private; \
- u16 tmp; \
- tmp = I810_READ16( I810REG_HWSTAM ); \
- tmp = tmp & 0x6000; \
- I810_WRITE16( I810REG_HWSTAM, tmp ); \
- \
- tmp = I810_READ16( I810REG_INT_MASK_R ); \
- tmp = tmp & 0x6000; /* Unmask interrupts */ \
- I810_WRITE16( I810REG_INT_MASK_R, tmp ); \
- tmp = I810_READ16( I810REG_INT_ENABLE_R ); \
- tmp = tmp & 0x6000; /* Disable all interrupts */ \
- I810_WRITE16( I810REG_INT_ENABLE_R, tmp ); \
-} while (0)
-
-#define DRIVER_POSTINSTALL() do { \
- drm_i810_private_t *dev_priv = \
- (drm_i810_private_t *)dev->dev_private; \
- u16 tmp; \
- tmp = I810_READ16( I810REG_INT_ENABLE_R ); \
- tmp = tmp & 0x6000; \
- tmp = tmp | 0x0003; /* Enable bp & user interrupts */ \
- I810_WRITE16( I810REG_INT_ENABLE_R, tmp ); \
-} while (0)
-
-#define DRIVER_UNINSTALL() do { \
- drm_i810_private_t *dev_priv = \
- (drm_i810_private_t *)dev->dev_private; \
- u16 tmp; \
- if ( dev_priv ) { \
- tmp = I810_READ16( I810REG_INT_IDENTITY_R ); \
- tmp = tmp & ~(0x6000); /* Clear all interrupts */ \
- if ( tmp != 0 ) \
- I810_WRITE16( I810REG_INT_IDENTITY_R, tmp ); \
- \
- tmp = I810_READ16( I810REG_INT_ENABLE_R ); \
- tmp = tmp & 0x6000; /* Disable all interrupts */ \
- I810_WRITE16( I810REG_INT_ENABLE_R, tmp ); \
- } \
-} while (0)
+/* Don't need an irq any more. The template code will make sure that
+ * a noop stub is generated for compatibility.
+ */
+#define __HAVE_DMA_IRQ 0
/* Buffer customization:
*/
*
* Authors: Rickard E. (Rik) Faith <faith@valinux.com>
* Jeff Hartmann <jhartmann@valinux.com>
- * Keith Whitwell <keithw@valinux.com>
+ * Keith Whitwell <keith_whitwell@yahoo.com>
*
*/
#include "i810_drv.h"
#include <linux/interrupt.h> /* For task queue support */
-/* in case we don't have a 2.3.99-pre6 kernel or later: */
-#ifndef VM_DONTCOPY
-#define VM_DONTCOPY 0
-#endif
-
#define I810_BUF_FREE 2
#define I810_BUF_CLIENT 1
#define I810_BUF_HARDWARE 0
#define RING_LOCALS unsigned int outring, ringmask; volatile char *virt;
-#define BEGIN_LP_RING(n) do { \
- if (I810_VERBOSE) \
- DRM_DEBUG("BEGIN_LP_RING(%d) in %s\n", \
- n, __FUNCTION__); \
- if (dev_priv->ring.space < n*4) \
- i810_wait_ring(dev, n*4); \
- dev_priv->ring.space -= n*4; \
- outring = dev_priv->ring.tail; \
- ringmask = dev_priv->ring.tail_mask; \
- virt = dev_priv->ring.virtual_start; \
+#define BEGIN_LP_RING(n) do { \
+ if (0) DRM_DEBUG("BEGIN_LP_RING(%d) in %s\n", n, __FUNCTION__); \
+ if (dev_priv->ring.space < n*4) \
+ i810_wait_ring(dev, n*4); \
+ dev_priv->ring.space -= n*4; \
+ outring = dev_priv->ring.tail; \
+ ringmask = dev_priv->ring.tail_mask; \
+ virt = dev_priv->ring.virtual_start; \
} while (0)
-#define ADVANCE_LP_RING() do { \
- if (I810_VERBOSE) DRM_DEBUG("ADVANCE_LP_RING\n"); \
- dev_priv->ring.tail = outring; \
- I810_WRITE(LP_RING + RING_TAIL, outring); \
+#define ADVANCE_LP_RING() do { \
+ if (0) DRM_DEBUG("ADVANCE_LP_RING\n"); \
+ dev_priv->ring.tail = outring; \
+ I810_WRITE(LP_RING + RING_TAIL, outring); \
} while(0)
-#define OUT_RING(n) do { \
- if (I810_VERBOSE) DRM_DEBUG(" OUT_RING %x\n", (int)(n)); \
- *(volatile unsigned int *)(virt + outring) = n; \
- outring += 4; \
- outring &= ringmask; \
+#define OUT_RING(n) do { \
+ if (0) DRM_DEBUG(" OUT_RING %x\n", (int)(n)); \
+ *(volatile unsigned int *)(virt + outring) = n; \
+ outring += 4; \
+ outring &= ringmask; \
} while (0)
static inline void i810_print_status_page(drm_device_t *dev)
DRM_DEBUG( "hw_status: LpRing Head ptr : %x\n", temp[1]);
DRM_DEBUG( "hw_status: IRing Head ptr : %x\n", temp[2]);
DRM_DEBUG( "hw_status: Reserved : %x\n", temp[3]);
+ DRM_DEBUG( "hw_status: Last Render: %x\n", temp[4]);
DRM_DEBUG( "hw_status: Driver Counter : %d\n", temp[5]);
for(i = 6; i < dma->buf_count + 6; i++) {
DRM_DEBUG( "buffer status idx : %d used: %d\n", i - 6, temp[i]);
buf_priv->currently_mapped = I810_BUF_MAPPED;
unlock_kernel();
- if (remap_page_range(vma, vma->vm_start,
+ if (remap_page_range(DRM_RPR_ARG(vma) vma->vm_start,
VM_OFFSET(vma),
vma->vm_end - vma->vm_start,
vma->vm_page_prot)) return -EAGAIN;
if(buf_priv->currently_mapped == I810_BUF_MAPPED) return -EINVAL;
- if(VM_DONTCOPY != 0) {
#if LINUX_VERSION_CODE <= 0x020402
- down( ¤t->mm->mmap_sem );
+ down( ¤t->mm->mmap_sem );
#else
- down_write( ¤t->mm->mmap_sem );
+ down_write( ¤t->mm->mmap_sem );
#endif
- old_fops = filp->f_op;
- filp->f_op = &i810_buffer_fops;
- dev_priv->mmap_buffer = buf;
- buf_priv->virtual = (void *)do_mmap(filp, 0, buf->total,
- PROT_READ|PROT_WRITE,
- MAP_SHARED,
- buf->bus_address);
- dev_priv->mmap_buffer = NULL;
- filp->f_op = old_fops;
- if ((unsigned long)buf_priv->virtual > -1024UL) {
- /* Real error */
- DRM_DEBUG("mmap error\n");
- retcode = (signed int)buf_priv->virtual;
- buf_priv->virtual = 0;
- }
+ old_fops = filp->f_op;
+ filp->f_op = &i810_buffer_fops;
+ dev_priv->mmap_buffer = buf;
+ buf_priv->virtual = (void *)do_mmap(filp, 0, buf->total,
+ PROT_READ|PROT_WRITE,
+ MAP_SHARED,
+ buf->bus_address);
+ dev_priv->mmap_buffer = NULL;
+ filp->f_op = old_fops;
+ if ((unsigned long)buf_priv->virtual > -1024UL) {
+ /* Real error */
+ DRM_DEBUG("mmap error\n");
+ retcode = (signed int)buf_priv->virtual;
+ buf_priv->virtual = 0;
+ }
#if LINUX_VERSION_CODE <= 0x020402
- up( ¤t->mm->mmap_sem );
+ up( ¤t->mm->mmap_sem );
#else
- up_write( ¤t->mm->mmap_sem );
+ up_write( ¤t->mm->mmap_sem );
#endif
- } else {
- buf_priv->virtual = buf_priv->kernel_virtual;
- buf_priv->currently_mapped = I810_BUF_MAPPED;
- }
return retcode;
}
drm_i810_buf_priv_t *buf_priv = buf->dev_private;
int retcode = 0;
- if(VM_DONTCOPY != 0) {
- if(buf_priv->currently_mapped != I810_BUF_MAPPED)
- return -EINVAL;
+ if(buf_priv->currently_mapped != I810_BUF_MAPPED)
+ return -EINVAL;
#if LINUX_VERSION_CODE <= 0x020402
- down( ¤t->mm->mmap_sem );
+ down( ¤t->mm->mmap_sem );
#else
- down_write( ¤t->mm->mmap_sem );
-#endif
-#if LINUX_VERSION_CODE < 0x020399
- retcode = do_munmap((unsigned long)buf_priv->virtual,
- (size_t) buf->total);
-#else
- retcode = do_munmap(current->mm,
- (unsigned long)buf_priv->virtual,
- (size_t) buf->total);
+ down_write( ¤t->mm->mmap_sem );
#endif
+ retcode = do_munmap(current->mm,
+ (unsigned long)buf_priv->virtual,
+ (size_t) buf->total);
#if LINUX_VERSION_CODE <= 0x020402
- up( ¤t->mm->mmap_sem );
+ up( ¤t->mm->mmap_sem );
#else
- up_write( ¤t->mm->mmap_sem );
+ up_write( ¤t->mm->mmap_sem );
#endif
- }
buf_priv->currently_mapped = I810_BUF_UNMAPPED;
buf_priv->virtual = 0;
if(address == 0UL)
return 0;
+#if LINUX_VERSION_CODE < 0x020500
+ atomic_inc(&virt_to_page(address)->count);
+ set_bit(PG_locked, &virt_to_page(address)->flags);
+#else
get_page(virt_to_page(address));
SetPageLocked(virt_to_page(address));
-
+#endif
return address;
}
static void i810_free_page(drm_device_t *dev, unsigned long page)
{
if (page) {
+#if LINUX_VERSION_CODE < 0x020500
+ atomic_dec(&virt_to_page(page)->count);
+ clear_bit(PG_locked, &virt_to_page(page)->flags);
+ wake_up(&virt_to_page(page)->wait);
+#else
struct page *p = virt_to_page(page);
put_page(p);
unlock_page(p);
+#endif
free_page(page);
}
}
DRM_ERROR("lockup\n");
goto out_wait_ring;
}
-
- for (i = 0 ; i < 2000 ; i++) ;
+ udelay(1);
}
out_wait_ring:
((u8 *)dev_priv->sarea_map->handle +
init->sarea_priv_offset);
- atomic_set(&dev_priv->flush_done, 0);
- init_waitqueue_head(&dev_priv->flush_queue);
-
dev_priv->ring.Start = init->ring_start;
dev_priv->ring.End = init->ring_end;
dev_priv->ring.Size = init->ring_size;
dev_priv->back_offset = init->back_offset;
dev_priv->depth_offset = init->depth_offset;
+ dev_priv->overlay_offset = init->overlay_offset;
+ dev_priv->overlay_physical = init->overlay_physical;
+
dev_priv->front_di1 = init->front_offset | init->pitch_bits;
dev_priv->back_di1 = init->back_offset | init->pitch_bits;
dev_priv->zi1 = init->depth_offset | init->pitch_bits;
/* Most efficient way to verify state for the i810 is as it is
* emitted. Non-conformant state is silently dropped.
- *
- * Use 'volatile' & local var tmp to force the emitted values to be
- * identical to the verified ones.
*/
static void i810EmitContextVerified( drm_device_t *dev,
- volatile unsigned int *code )
+ unsigned int *code )
{
drm_i810_private_t *dev_priv = dev->dev_private;
int i, j = 0;
- unsigned int tmp;
RING_LOCALS;
BEGIN_LP_RING( I810_CTX_SETUP_SIZE );
OUT_RING( code[I810_CTXREG_ST1] );
for ( i = 4 ; i < I810_CTX_SETUP_SIZE ; i++ ) {
- tmp = code[i];
-
- if ((tmp & (7<<29)) == (3<<29) &&
- (tmp & (0x1f<<24)) < (0x1d<<24))
+ if ((code[i] & (7<<29)) == (3<<29) &&
+ (code[i] & (0x1f<<24)) < (0x1d<<24))
{
- OUT_RING( tmp );
+ OUT_RING( code[i] );
j++;
}
+ else printk("constext state dropped!!!\n");
}
if (j & 1)
{
drm_i810_private_t *dev_priv = dev->dev_private;
int i, j = 0;
- unsigned int tmp;
RING_LOCALS;
BEGIN_LP_RING( I810_TEX_SETUP_SIZE );
OUT_RING( code[I810_TEXREG_MI3] );
for ( i = 4 ; i < I810_TEX_SETUP_SIZE ; i++ ) {
- tmp = code[i];
- if ((tmp & (7<<29)) == (3<<29) &&
- (tmp & (0x1f<<24)) < (0x1d<<24))
+ if ((code[i] & (7<<29)) == (3<<29) &&
+ (code[i] & (0x1f<<24)) < (0x1d<<24))
{
- OUT_RING( tmp );
+ OUT_RING( code[i] );
j++;
}
+ else printk("texture state dropped!!!\n");
}
if (j & 1)
if (tmp == dev_priv->front_di1 || tmp == dev_priv->back_di1) {
OUT_RING( CMD_OP_DESTBUFFER_INFO );
OUT_RING( tmp );
- } else
- DRM_DEBUG("bad di1 %x (allow %x or %x)\n",
- tmp, dev_priv->front_di1, dev_priv->back_di1);
+ }
+ else
+ printk("buffer state dropped\n");
/* invarient:
*/
continue;
if ( flags & I810_FRONT ) {
- DRM_DEBUG("clear front\n");
BEGIN_LP_RING( 6 );
OUT_RING( BR00_BITBLT_CLIENT |
BR00_OP_COLOR_BLT | 0x3 );
}
if ( flags & I810_BACK ) {
- DRM_DEBUG("clear back\n");
BEGIN_LP_RING( 6 );
OUT_RING( BR00_BITBLT_CLIENT |
BR00_OP_COLOR_BLT | 0x3 );
}
if ( flags & I810_DEPTH ) {
- DRM_DEBUG("clear depth\n");
BEGIN_LP_RING( 6 );
OUT_RING( BR00_BITBLT_CLIENT |
BR00_OP_COLOR_BLT | 0x3 );
int i;
RING_LOCALS;
- DRM_DEBUG("swapbuffers\n");
-
i810_kernel_lost_context(dev);
if (nbox > I810_NR_SAREA_CLIPRECTS)
pbox->y2 > dev_priv->h)
continue;
- DRM_DEBUG("dispatch swap %d,%d-%d,%d!\n",
- pbox[i].x1, pbox[i].y1,
- pbox[i].x2, pbox[i].y2);
-
BEGIN_LP_RING( 6 );
OUT_RING( BR00_BITBLT_CLIENT | BR00_OP_SRC_COPY_BLT | 0x4 );
OUT_RING( pitch | (0xCC << 16));
int nbox = sarea_priv->nbox;
unsigned long address = (unsigned long)buf->bus_address;
unsigned long start = address - dev->agp->base;
- int i = 0, u;
+ int i = 0;
RING_LOCALS;
i810_kernel_lost_context(dev);
if (nbox > I810_NR_SAREA_CLIPRECTS)
nbox = I810_NR_SAREA_CLIPRECTS;
- if (discard) {
- u = cmpxchg(buf_priv->in_use, I810_BUF_CLIENT,
- I810_BUF_HARDWARE);
- if(u != I810_BUF_CLIENT) {
- DRM_DEBUG("xxxx 2\n");
- }
- }
-
if (used > 4*1024)
used = 0;
if (sarea_priv->dirty)
i810EmitState( dev );
- DRM_DEBUG("dispatch vertex addr 0x%lx, used 0x%x nbox %d\n",
- address, used, nbox);
-
- dev_priv->counter++;
- DRM_DEBUG( "dispatch counter : %ld\n", dev_priv->counter);
- DRM_DEBUG( "i810_dma_dispatch\n");
- DRM_DEBUG( "start : %lx\n", start);
- DRM_DEBUG( "used : %d\n", used);
- DRM_DEBUG( "start + used - 4 : %ld\n", start + used - 4);
-
if (buf_priv->currently_mapped == I810_BUF_MAPPED) {
- *(u32 *)buf_priv->virtual = (GFX_OP_PRIMITIVE |
- sarea_priv->vertex_prim |
+ unsigned int prim = (sarea_priv->vertex_prim & PR_MASK);
+
+ *(u32 *)buf_priv->virtual = (GFX_OP_PRIMITIVE | prim |
((used/4)-2));
if (used & 4) {
} while (++i < nbox);
}
- BEGIN_LP_RING(10);
- OUT_RING( CMD_STORE_DWORD_IDX );
- OUT_RING( 20 );
- OUT_RING( dev_priv->counter );
- OUT_RING( 0 );
-
if (discard) {
+ dev_priv->counter++;
+
+ (void) cmpxchg(buf_priv->in_use, I810_BUF_CLIENT,
+ I810_BUF_HARDWARE);
+
+ BEGIN_LP_RING(8);
+ OUT_RING( CMD_STORE_DWORD_IDX );
+ OUT_RING( 20 );
+ OUT_RING( dev_priv->counter );
OUT_RING( CMD_STORE_DWORD_IDX );
OUT_RING( buf_priv->my_use_idx );
OUT_RING( I810_BUF_FREE );
+ OUT_RING( CMD_REPORT_HEAD );
OUT_RING( 0 );
+ ADVANCE_LP_RING();
}
-
- OUT_RING( CMD_REPORT_HEAD );
- OUT_RING( 0 );
- ADVANCE_LP_RING();
-}
-
-
-/* Interrupts are only for flushing */
-void i810_dma_service(int irq, void *device, struct pt_regs *regs)
-{
- drm_device_t *dev = (drm_device_t *)device;
- drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
- u16 temp;
-
- atomic_inc(&dev->counts[_DRM_STAT_IRQ]);
- temp = I810_READ16(I810REG_INT_IDENTITY_R);
- temp = temp & ~(0x6000);
- if(temp != 0) I810_WRITE16(I810REG_INT_IDENTITY_R,
- temp); /* Clear all interrupts */
- else
- return;
-
- queue_task(&dev->tq, &tq_immediate);
- mark_bh(IMMEDIATE_BH);
-}
-
-void i810_dma_immediate_bh(void *device)
-{
- drm_device_t *dev = (drm_device_t *) device;
- drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
-
- atomic_set(&dev_priv->flush_done, 1);
- wake_up_interruptible(&dev_priv->flush_queue);
}
-static inline void i810_dma_emit_flush(drm_device_t *dev)
-{
- drm_i810_private_t *dev_priv = dev->dev_private;
- RING_LOCALS;
-
- i810_kernel_lost_context(dev);
-
- BEGIN_LP_RING(2);
- OUT_RING( CMD_REPORT_HEAD );
- OUT_RING( GFX_OP_USER_INTERRUPT );
- ADVANCE_LP_RING();
-
-/* i810_wait_ring( dev, dev_priv->ring.Size - 8 ); */
-/* atomic_set(&dev_priv->flush_done, 1); */
-/* wake_up_interruptible(&dev_priv->flush_queue); */
-}
-static inline void i810_dma_quiescent_emit(drm_device_t *dev)
+void i810_dma_quiescent(drm_device_t *dev)
{
drm_i810_private_t *dev_priv = dev->dev_private;
RING_LOCALS;
+/* printk("%s\n", __FUNCTION__); */
+
i810_kernel_lost_context(dev);
BEGIN_LP_RING(4);
OUT_RING( INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE );
OUT_RING( CMD_REPORT_HEAD );
OUT_RING( 0 );
- OUT_RING( GFX_OP_USER_INTERRUPT );
+ OUT_RING( 0 );
ADVANCE_LP_RING();
-/* i810_wait_ring( dev, dev_priv->ring.Size - 8 ); */
-/* atomic_set(&dev_priv->flush_done, 1); */
-/* wake_up_interruptible(&dev_priv->flush_queue); */
-}
-
-void i810_dma_quiescent(drm_device_t *dev)
-{
- DECLARE_WAITQUEUE(entry, current);
- drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
- unsigned long end;
-
- if(dev_priv == NULL) {
- return;
- }
- atomic_set(&dev_priv->flush_done, 0);
- add_wait_queue(&dev_priv->flush_queue, &entry);
- end = jiffies + (HZ*3);
-
- for (;;) {
- current->state = TASK_INTERRUPTIBLE;
- i810_dma_quiescent_emit(dev);
- if (atomic_read(&dev_priv->flush_done) == 1) break;
- if((signed)(end - jiffies) <= 0) {
- DRM_ERROR("lockup\n");
- break;
- }
- schedule_timeout(HZ*3);
- if (signal_pending(current)) {
- break;
- }
- }
-
- current->state = TASK_RUNNING;
- remove_wait_queue(&dev_priv->flush_queue, &entry);
-
- return;
+ i810_wait_ring( dev, dev_priv->ring.Size - 8 );
}
static int i810_flush_queue(drm_device_t *dev)
{
- DECLARE_WAITQUEUE(entry, current);
- drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
+ drm_i810_private_t *dev_priv = dev->dev_private;
drm_device_dma_t *dma = dev->dma;
- unsigned long end;
int i, ret = 0;
+ RING_LOCALS;
+
+/* printk("%s\n", __FUNCTION__); */
- if(dev_priv == NULL) {
- return 0;
- }
- atomic_set(&dev_priv->flush_done, 0);
- add_wait_queue(&dev_priv->flush_queue, &entry);
- end = jiffies + (HZ*3);
- for (;;) {
- current->state = TASK_INTERRUPTIBLE;
- i810_dma_emit_flush(dev);
- if (atomic_read(&dev_priv->flush_done) == 1) break;
- if((signed)(end - jiffies) <= 0) {
- DRM_ERROR("lockup\n");
- break;
- }
- schedule_timeout(HZ*3);
- if (signal_pending(current)) {
- ret = -EINTR; /* Can't restart */
- break;
- }
- }
+ i810_kernel_lost_context(dev);
- current->state = TASK_RUNNING;
- remove_wait_queue(&dev_priv->flush_queue, &entry);
+ BEGIN_LP_RING(2);
+ OUT_RING( CMD_REPORT_HEAD );
+ OUT_RING( 0 );
+ ADVANCE_LP_RING();
+ i810_wait_ring( dev, dev_priv->ring.Size - 8 );
for (i = 0; i < dma->buf_count; i++) {
drm_buf_t *buf = dma->buflist[ i ];
if (used == I810_BUF_HARDWARE)
DRM_DEBUG("reclaimed from HARDWARE\n");
if (used == I810_BUF_CLIENT)
- DRM_DEBUG("still on client HARDWARE\n");
+ DRM_DEBUG("still on client\n");
}
return ret;
drm_file_t *priv = filp->private_data;
drm_device_t *dev = priv->dev;
- DRM_DEBUG("i810_flush_ioctl\n");
if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
DRM_ERROR("i810_flush_ioctl called without lock held\n");
return -EINVAL;
return -EINVAL;
}
- DRM_DEBUG("i810 dma vertex, idx %d used %d discard %d\n",
- vertex.idx, vertex.used, vertex.discard);
-
if(vertex.idx < 0 || vertex.idx > dma->buf_count) return -EINVAL;
i810_dma_dispatch_vertex( dev,
drm_file_t *priv = filp->private_data;
drm_device_t *dev = priv->dev;
- DRM_DEBUG("i810_swap_bufs\n");
-
if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
DRM_ERROR("i810_swap_buf called without lock held\n");
return -EINVAL;
drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *)
dev_priv->sarea_priv;
- DRM_DEBUG("getbuf\n");
if (copy_from_user(&d, (drm_i810_dma_t *)arg, sizeof(d)))
return -EFAULT;
retcode = i810_dma_get_buffer(dev, &d, filp);
- DRM_DEBUG("i810_dma: %d returning %d, granted = %d\n",
- current->pid, retcode, d.granted);
-
if (copy_to_user((drm_dma_t *)arg, &d, sizeof(d)))
return -EFAULT;
sarea_priv->last_dispatch = (int) hw_status[5];
return retcode;
}
-int i810_copybuf(struct inode *inode, struct file *filp, unsigned int cmd,
+int i810_copybuf(struct inode *inode,
+ struct file *filp,
+ unsigned int cmd,
+ unsigned long arg)
+{
+ /* Never copy - 2.4.x doesn't need it */
+ return 0;
+}
+
+int i810_docopy(struct inode *inode, struct file *filp, unsigned int cmd,
unsigned long arg)
{
- drm_file_t *priv = filp->private_data;
- drm_device_t *dev = priv->dev;
- drm_i810_copy_t d;
- drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
- u32 *hw_status = (u32 *)dev_priv->hw_status_page;
- drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *)
- dev_priv->sarea_priv;
- drm_buf_t *buf;
- drm_i810_buf_priv_t *buf_priv;
+ /* Never copy - 2.4.x doesn't need it */
+ return 0;
+}
+
+static void i810_dma_dispatch_mc(drm_device_t *dev, drm_buf_t *buf, int used,
+ unsigned int last_render)
+{
+ drm_i810_private_t *dev_priv = dev->dev_private;
+ drm_i810_buf_priv_t *buf_priv = buf->dev_private;
+ drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv;
+ unsigned long address = (unsigned long)buf->bus_address;
+ unsigned long start = address - dev->agp->base;
+ int u;
+ RING_LOCALS;
+
+ i810_kernel_lost_context(dev);
+
+ u = cmpxchg(buf_priv->in_use, I810_BUF_CLIENT,
+ I810_BUF_HARDWARE);
+ if(u != I810_BUF_CLIENT) {
+ DRM_DEBUG("MC found buffer that isn't mine!\n");
+ }
+
+ if (used > 4*1024)
+ used = 0;
+
+ sarea_priv->dirty = 0x7f;
+
+ DRM_DEBUG("dispatch mc addr 0x%lx, used 0x%x\n",
+ address, used);
+
+ dev_priv->counter++;
+ DRM_DEBUG("dispatch counter : %ld\n", dev_priv->counter);
+ DRM_DEBUG("i810_dma_dispatch_mc\n");
+ DRM_DEBUG("start : %lx\n", start);
+ DRM_DEBUG("used : %d\n", used);
+ DRM_DEBUG("start + used - 4 : %ld\n", start + used - 4);
+
+ if (buf_priv->currently_mapped == I810_BUF_MAPPED) {
+ if (used & 4) {
+ *(u32 *)((u32)buf_priv->virtual + used) = 0;
+ used += 4;
+ }
+
+ i810_unmap_buffer(buf);
+ }
+ BEGIN_LP_RING(4);
+ OUT_RING( CMD_OP_BATCH_BUFFER );
+ OUT_RING( start | BB1_PROTECTED );
+ OUT_RING( start + used - 4 );
+ OUT_RING( 0 );
+ ADVANCE_LP_RING();
+
+
+ BEGIN_LP_RING(8);
+ OUT_RING( CMD_STORE_DWORD_IDX );
+ OUT_RING( buf_priv->my_use_idx );
+ OUT_RING( I810_BUF_FREE );
+ OUT_RING( 0 );
+
+ OUT_RING( CMD_STORE_DWORD_IDX );
+ OUT_RING( 16 );
+ OUT_RING( last_render );
+ OUT_RING( 0 );
+ ADVANCE_LP_RING();
+}
+
+int i810_dma_mc(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
drm_device_dma_t *dma = dev->dma;
+ drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
+ u32 *hw_status = (u32 *)dev_priv->hw_status_page;
+ drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *)
+ dev_priv->sarea_priv;
+ drm_i810_mc_t mc;
+
+ if (copy_from_user(&mc, (drm_i810_mc_t *)arg, sizeof(mc)))
+ return -EFAULT;
+
if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
- DRM_ERROR("i810_dma called without lock held\n");
+ DRM_ERROR("i810_dma_mc called without lock held\n");
return -EINVAL;
}
- if (copy_from_user(&d, (drm_i810_copy_t *)arg, sizeof(d)))
- return -EFAULT;
+ i810_dma_dispatch_mc(dev, dma->buflist[mc.idx], mc.used,
+ mc.last_render );
- if(d.idx < 0 || d.idx > dma->buf_count) return -EINVAL;
- buf = dma->buflist[ d.idx ];
- buf_priv = buf->dev_private;
- if (buf_priv->currently_mapped != I810_BUF_MAPPED) return -EPERM;
+ atomic_add(mc.used, &dev->counts[_DRM_STAT_SECONDARY]);
+ atomic_inc(&dev->counts[_DRM_STAT_DMA]);
+ sarea_priv->last_enqueue = dev_priv->counter-1;
+ sarea_priv->last_dispatch = (int) hw_status[5];
- if(d.used < 0 || d.used > buf->total) return -EINVAL;
+ return 0;
+}
- if (copy_from_user(buf_priv->virtual, d.address, d.used))
- return -EFAULT;
+int i810_rstatus(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
- sarea_priv->last_dispatch = (int) hw_status[5];
+ return (int)(((u32 *)(dev_priv->hw_status_page))[4]);
+}
+int i810_ov0_info(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
+ drm_i810_overlay_t data;
+
+ data.offset = dev_priv->overlay_offset;
+ data.physical = dev_priv->overlay_physical;
+ copy_to_user((drm_i810_overlay_t *)arg,&data,sizeof(data));
return 0;
}
-int i810_docopy(struct inode *inode, struct file *filp, unsigned int cmd,
- unsigned long arg)
+int i810_fstatus(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg)
{
- if(VM_DONTCOPY == 0) return 1;
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
+
+ if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+ DRM_ERROR("i810_fstatus called without lock held\n");
+ return -EINVAL;
+ }
+ return I810_READ(0x30008);
+}
+
+int i810_ov0_flip(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
+
+ if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+ DRM_ERROR("i810_ov0_flip called without lock held\n");
+ return -EINVAL;
+ }
+
+ //Tell the overlay to update
+ I810_WRITE(0x30000,dev_priv->overlay_physical | 0x80000000);
+
return 0;
}
+
+
#define I810_TEXREG_MCS 7 /* GFX_OP_MAP_COORD_SETS ??? */
#define I810_TEX_SETUP_SIZE 8
+/* Flags for clear ioctl
+ */
#define I810_FRONT 0x1
#define I810_BACK 0x2
#define I810_DEPTH 0x4
unsigned int front_offset;
unsigned int back_offset;
unsigned int depth_offset;
+ unsigned int overlay_offset;
+ unsigned int overlay_physical;
unsigned int w;
unsigned int h;
unsigned int pitch;
void *address; /* Address to copy from */
} drm_i810_copy_t;
+#define PR_TRIANGLES (0x0<<18)
+#define PR_TRISTRIP_0 (0x1<<18)
+#define PR_TRISTRIP_1 (0x2<<18)
+#define PR_TRIFAN (0x3<<18)
+#define PR_POLYGON (0x4<<18)
+#define PR_LINES (0x5<<18)
+#define PR_LINESTRIP (0x6<<18)
+#define PR_RECTS (0x7<<18)
+#define PR_MASK (0x7<<18)
+
+
typedef struct drm_i810_dma {
void *virtual;
int request_idx;
int granted;
} drm_i810_dma_t;
+typedef struct _drm_i810_overlay_t {
+ unsigned int offset; /* Address of the Overlay Regs */
+ unsigned int physical;
+} drm_i810_overlay_t;
+
+typedef struct _drm_i810_mc {
+ int idx; /* buffer index */
+ int used; /* nr bytes in use */
+ int num_blocks; /* number of GFXBlocks */
+ int *length; /* List of lengths for GFXBlocks (FUTURE)*/
+ unsigned int last_render; /* Last Render Request */
+} drm_i810_mc_t;
+
+
#endif /* _I810_DRM_H_ */
#define DRIVER_NAME "i810"
#define DRIVER_DESC "Intel i810"
-#define DRIVER_DATE "20010616"
+#define DRIVER_DATE "20020211"
+/* Interface history
+ *
+ * 1.1 - XFree86 4.1
+ * 1.2 - XvMC interfaces
+ * - XFree86 4.2
+ * 1.2.1 - Disable copying code (leave stub ioctls for backwards compatibility)
+ * - Remove requirement for interrupt (leave stubs again)
+ */
#define DRIVER_MAJOR 1
-#define DRIVER_MINOR 1
-#define DRIVER_PATCHLEVEL 0
+#define DRIVER_MINOR 2
+#define DRIVER_PATCHLEVEL 1
#define DRIVER_IOCTLS \
[DRM_IOCTL_NR(DRM_IOCTL_I810_INIT)] = { i810_dma_init, 1, 1 }, \
[DRM_IOCTL_NR(DRM_IOCTL_I810_GETBUF)] = { i810_getbuf, 1, 0 }, \
[DRM_IOCTL_NR(DRM_IOCTL_I810_SWAP)] = { i810_swap_bufs, 1, 0 }, \
[DRM_IOCTL_NR(DRM_IOCTL_I810_COPY)] = { i810_copybuf, 1, 0 }, \
- [DRM_IOCTL_NR(DRM_IOCTL_I810_DOCOPY)] = { i810_docopy, 1, 0 },
+ [DRM_IOCTL_NR(DRM_IOCTL_I810_DOCOPY)] = { i810_docopy, 1, 0 }, \
+ [DRM_IOCTL_NR(DRM_IOCTL_I810_OV0INFO)] = { i810_ov0_info, 1, 0 }, \
+ [DRM_IOCTL_NR(DRM_IOCTL_I810_FSTATUS)] = { i810_fstatus, 1, 0 }, \
+ [DRM_IOCTL_NR(DRM_IOCTL_I810_OV0FLIP)] = { i810_ov0_flip, 1, 0 }, \
+ [DRM_IOCTL_NR(DRM_IOCTL_I810_MC)] = { i810_dma_mc, 1, 1 }, \
+ [DRM_IOCTL_NR(DRM_IOCTL_I810_RSTATUS)] = { i810_rstatus, 1, 0 }
#define __HAVE_COUNTERS 4
unsigned long hw_status_page;
unsigned long counter;
- atomic_t flush_done;
- wait_queue_head_t flush_queue; /* Processes waiting until flush */
drm_buf_t *mmap_buffer;
int back_offset;
int depth_offset;
+ int overlay_offset;
+ int overlay_physical;
int w, h;
int pitch;
+
} drm_i810_private_t;
/* i810_dma.c */
extern int i810_getage(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
extern int i810_mmap_buffers(struct file *filp, struct vm_area_struct *vma);
+
+/* Obsolete:
+ */
extern int i810_copybuf(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
+/* Obsolete:
+ */
extern int i810_docopy(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
-extern void i810_dma_quiescent(drm_device_t *dev);
+extern int i810_rstatus(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+extern int i810_ov0_info(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+extern int i810_fstatus(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+extern int i810_ov0_flip(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+extern int i810_dma_mc(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
-#define I810_VERBOSE 0
+extern void i810_dma_quiescent(drm_device_t *dev);
int i810_dma_vertex(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
--- /dev/null
+/* i830.h -- Intel I830 DRM template customization -*- linux-c -*-
+ * Created: Thu Feb 15 00:01:12 2001 by gareth@valinux.com
+ *
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Gareth Hughes <gareth@valinux.com>
+ */
+
+#ifndef __I830_H__
+#define __I830_H__
+
+/* This remains constant for all DRM template files.
+ */
+#define DRM(x) i830_##x
+
+/* General customization:
+ */
+#define __HAVE_AGP 1
+#define __MUST_HAVE_AGP 1
+#define __HAVE_MTRR 1
+#define __HAVE_CTX_BITMAP 1
+
+/* Driver customization:
+ */
+#define __HAVE_RELEASE 1
+#define DRIVER_RELEASE() do { \
+ i830_reclaim_buffers( dev, priv->pid ); \
+} while (0)
+
+/* DMA customization:
+ */
+#define __HAVE_DMA 1
+#define __HAVE_DMA_QUEUE 1
+#define __HAVE_DMA_WAITLIST 1
+#define __HAVE_DMA_RECLAIM 1
+
+#define __HAVE_DMA_QUIESCENT 1
+#define DRIVER_DMA_QUIESCENT() do { \
+ i830_dma_quiescent( dev ); \
+} while (0)
+
+#define __HAVE_DMA_IRQ 1
+#define __HAVE_DMA_IRQ_BH 1
+#define __HAVE_SHARED_IRQ 1
+#define DRIVER_PREINSTALL() do { \
+ drm_i830_private_t *dev_priv = \
+ (drm_i830_private_t *)dev->dev_private; \
+ u16 tmp; \
+ tmp = I830_READ16( I830REG_HWSTAM ); \
+ tmp = tmp & 0x6000; \
+ I830_WRITE16( I830REG_HWSTAM, tmp ); \
+ \
+ tmp = I830_READ16( I830REG_INT_MASK_R ); \
+ tmp = tmp & 0x6000; /* Unmask interrupts */ \
+ I830_WRITE16( I830REG_INT_MASK_R, tmp ); \
+ tmp = I830_READ16( I830REG_INT_ENABLE_R ); \
+ tmp = tmp & 0x6000; /* Disable all interrupts */ \
+ I830_WRITE16( I830REG_INT_ENABLE_R, tmp ); \
+} while (0)
+
+#define DRIVER_POSTINSTALL() do { \
+ drm_i830_private_t *dev_priv = \
+ (drm_i830_private_t *)dev->dev_private; \
+ u16 tmp; \
+ tmp = I830_READ16( I830REG_INT_ENABLE_R ); \
+ tmp = tmp & 0x6000; \
+ tmp = tmp | 0x0003; /* Enable bp & user interrupts */ \
+ I830_WRITE16( I830REG_INT_ENABLE_R, tmp ); \
+} while (0)
+
+#define DRIVER_UNINSTALL() do { \
+ drm_i830_private_t *dev_priv = \
+ (drm_i830_private_t *)dev->dev_private; \
+ u16 tmp; \
+ if ( dev_priv ) { \
+ tmp = I830_READ16( I830REG_INT_IDENTITY_R ); \
+ tmp = tmp & ~(0x6000); /* Clear all interrupts */ \
+ if ( tmp != 0 ) \
+ I830_WRITE16( I830REG_INT_IDENTITY_R, tmp ); \
+ \
+ tmp = I830_READ16( I830REG_INT_ENABLE_R ); \
+ tmp = tmp & 0x6000; /* Disable all interrupts */ \
+ I830_WRITE16( I830REG_INT_ENABLE_R, tmp ); \
+ } \
+} while (0)
+
+/* Buffer customization:
+ */
+
+#define DRIVER_BUF_PRIV_T drm_i830_buf_priv_t
+
+#define DRIVER_AGP_BUFFERS_MAP( dev ) \
+ ((drm_i830_private_t *)((dev)->dev_private))->buffer_map
+
+#endif
--- /dev/null
+/* i830_dma.c -- DMA support for the I830 -*- linux-c -*-
+ * Created: Mon Dec 13 01:50:01 1999 by jhartmann@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Rickard E. (Rik) Faith <faith@valinux.com>
+ * Jeff Hartmann <jhartmann@valinux.com>
+ * Keith Whitwell <keithw@valinux.com>
+ * Abraham vd Merwe <abraham@2d3d.co.za>
+ *
+ */
+
+#define __NO_VERSION__
+#include "i830.h"
+#include "drmP.h"
+#include "i830_drv.h"
+#include <linux/interrupt.h> /* For task queue support */
+
+/* in case we don't have a 2.3.99-pre6 kernel or later: */
+#ifndef VM_DONTCOPY
+#define VM_DONTCOPY 0
+#endif
+
+#define I830_BUF_FREE 2
+#define I830_BUF_CLIENT 1
+#define I830_BUF_HARDWARE 0
+
+#define I830_BUF_UNMAPPED 0
+#define I830_BUF_MAPPED 1
+
+#define RING_LOCALS unsigned int outring, ringmask; volatile char *virt;
+
+
+#define DO_IDLE_WORKAROUND() \
+do { \
+ int _head; \
+ int _tail; \
+ int _i; \
+ do { \
+ _head = I830_READ(LP_RING + RING_HEAD) & HEAD_ADDR; \
+ _tail = I830_READ(LP_RING + RING_TAIL) & TAIL_ADDR; \
+ udelay(10); \
+ } while(_head != _tail); \
+} while(0)
+
+#define I830_SYNC_WORKAROUND 0
+
+#define BEGIN_LP_RING(n) do { \
+ if (I830_VERBOSE) \
+ DRM_DEBUG("BEGIN_LP_RING(%d) in %s\n", \
+ n, __FUNCTION__); \
+ if (I830_SYNC_WORKAROUND) \
+ DO_IDLE_WORKAROUND(); \
+ if (dev_priv->ring.space < n*4) \
+ i830_wait_ring(dev, n*4); \
+ dev_priv->ring.space -= n*4; \
+ outring = dev_priv->ring.tail; \
+ ringmask = dev_priv->ring.tail_mask; \
+ virt = dev_priv->ring.virtual_start; \
+} while (0)
+
+#define ADVANCE_LP_RING() do { \
+ if (I830_VERBOSE) DRM_DEBUG("ADVANCE_LP_RING\n"); \
+ dev_priv->ring.tail = outring; \
+ I830_WRITE(LP_RING + RING_TAIL, outring); \
+} while(0)
+
+#define OUT_RING(n) do { \
+ if (I830_VERBOSE) DRM_DEBUG(" OUT_RING %x\n", (int)(n)); \
+ *(volatile unsigned int *)(virt + outring) = n; \
+ outring += 4; \
+ outring &= ringmask; \
+} while (0)
+
+static inline void i830_print_status_page(drm_device_t *dev)
+{
+ drm_device_dma_t *dma = dev->dma;
+ drm_i830_private_t *dev_priv = dev->dev_private;
+ u32 *temp = (u32 *)dev_priv->hw_status_page;
+ int i;
+
+ DRM_DEBUG( "hw_status: Interrupt Status : %x\n", temp[0]);
+ DRM_DEBUG( "hw_status: LpRing Head ptr : %x\n", temp[1]);
+ DRM_DEBUG( "hw_status: IRing Head ptr : %x\n", temp[2]);
+ DRM_DEBUG( "hw_status: Reserved : %x\n", temp[3]);
+ DRM_DEBUG( "hw_status: Driver Counter : %d\n", temp[5]);
+ for(i = 9; i < dma->buf_count + 9; i++) {
+ DRM_DEBUG( "buffer status idx : %d used: %d\n", i - 9, temp[i]);
+ }
+}
+
+static drm_buf_t *i830_freelist_get(drm_device_t *dev)
+{
+ drm_device_dma_t *dma = dev->dma;
+ int i;
+ int used;
+
+ /* Linear search might not be the best solution */
+
+ for (i = 0; i < dma->buf_count; i++) {
+ drm_buf_t *buf = dma->buflist[ i ];
+ drm_i830_buf_priv_t *buf_priv = buf->dev_private;
+ /* In use is already a pointer */
+ used = cmpxchg(buf_priv->in_use, I830_BUF_FREE,
+ I830_BUF_CLIENT);
+ if(used == I830_BUF_FREE) {
+ return buf;
+ }
+ }
+ return NULL;
+}
+
+/* This should only be called if the buffer is not sent to the hardware
+ * yet, the hardware updates in use for us once its on the ring buffer.
+ */
+
+static int i830_freelist_put(drm_device_t *dev, drm_buf_t *buf)
+{
+ drm_i830_buf_priv_t *buf_priv = buf->dev_private;
+ int used;
+
+ /* In use is already a pointer */
+ used = cmpxchg(buf_priv->in_use, I830_BUF_CLIENT, I830_BUF_FREE);
+ if(used != I830_BUF_CLIENT) {
+ DRM_ERROR("Freeing buffer thats not in use : %d\n", buf->idx);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static struct file_operations i830_buffer_fops = {
+ open: DRM(open),
+ flush: DRM(flush),
+ release: DRM(release),
+ ioctl: DRM(ioctl),
+ mmap: i830_mmap_buffers,
+ read: DRM(read),
+ fasync: DRM(fasync),
+ poll: DRM(poll),
+};
+
+int i830_mmap_buffers(struct file *filp, struct vm_area_struct *vma)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev;
+ drm_i830_private_t *dev_priv;
+ drm_buf_t *buf;
+ drm_i830_buf_priv_t *buf_priv;
+
+ lock_kernel();
+ dev = priv->dev;
+ dev_priv = dev->dev_private;
+ buf = dev_priv->mmap_buffer;
+ buf_priv = buf->dev_private;
+
+ vma->vm_flags |= (VM_IO | VM_DONTCOPY);
+ vma->vm_file = filp;
+
+ buf_priv->currently_mapped = I830_BUF_MAPPED;
+ unlock_kernel();
+
+ if (remap_page_range(DRM_RPR_ARG(vma) vma->vm_start,
+ VM_OFFSET(vma),
+ vma->vm_end - vma->vm_start,
+ vma->vm_page_prot)) return -EAGAIN;
+ return 0;
+}
+
+static int i830_map_buffer(drm_buf_t *buf, struct file *filp)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ drm_i830_buf_priv_t *buf_priv = buf->dev_private;
+ drm_i830_private_t *dev_priv = dev->dev_private;
+ struct file_operations *old_fops;
+ int retcode = 0;
+
+ if(buf_priv->currently_mapped == I830_BUF_MAPPED) return -EINVAL;
+
+ if(VM_DONTCOPY != 0) {
+#if LINUX_VERSION_CODE <= 0x020402
+ down( ¤t->mm->mmap_sem );
+#else
+ down_write( ¤t->mm->mmap_sem );
+#endif
+ old_fops = filp->f_op;
+ filp->f_op = &i830_buffer_fops;
+ dev_priv->mmap_buffer = buf;
+ buf_priv->virtual = (void *)do_mmap(filp, 0, buf->total,
+ PROT_READ|PROT_WRITE,
+ MAP_SHARED,
+ buf->bus_address);
+ dev_priv->mmap_buffer = NULL;
+ filp->f_op = old_fops;
+ if ((unsigned long)buf_priv->virtual > -1024UL) {
+ /* Real error */
+ DRM_DEBUG("mmap error\n");
+ retcode = (signed int)buf_priv->virtual;
+ buf_priv->virtual = 0;
+ }
+#if LINUX_VERSION_CODE <= 0x020402
+ up( ¤t->mm->mmap_sem );
+#else
+ up_write( ¤t->mm->mmap_sem );
+#endif
+ } else {
+ buf_priv->virtual = buf_priv->kernel_virtual;
+ buf_priv->currently_mapped = I830_BUF_MAPPED;
+ }
+ return retcode;
+}
+
+static int i830_unmap_buffer(drm_buf_t *buf)
+{
+ drm_i830_buf_priv_t *buf_priv = buf->dev_private;
+ int retcode = 0;
+
+ if(VM_DONTCOPY != 0) {
+ if(buf_priv->currently_mapped != I830_BUF_MAPPED)
+ return -EINVAL;
+#if LINUX_VERSION_CODE <= 0x020402
+ down( ¤t->mm->mmap_sem );
+#else
+ down_write( ¤t->mm->mmap_sem );
+#endif
+
+ retcode = do_munmap(current->mm,
+ (unsigned long)buf_priv->virtual,
+ (size_t) buf->total);
+
+#if LINUX_VERSION_CODE <= 0x020402
+ up( ¤t->mm->mmap_sem );
+#else
+ up_write( ¤t->mm->mmap_sem );
+#endif
+ }
+ buf_priv->currently_mapped = I830_BUF_UNMAPPED;
+ buf_priv->virtual = 0;
+
+ return retcode;
+}
+
+static int i830_dma_get_buffer(drm_device_t *dev, drm_i830_dma_t *d,
+ struct file *filp)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_buf_t *buf;
+ drm_i830_buf_priv_t *buf_priv;
+ int retcode = 0;
+
+ buf = i830_freelist_get(dev);
+ if (!buf) {
+ retcode = -ENOMEM;
+ DRM_DEBUG("retcode=%d\n", retcode);
+ return retcode;
+ }
+
+ retcode = i830_map_buffer(buf, filp);
+ if(retcode) {
+ i830_freelist_put(dev, buf);
+ DRM_DEBUG("mapbuf failed, retcode %d\n", retcode);
+ return retcode;
+ }
+ buf->pid = priv->pid;
+ buf_priv = buf->dev_private;
+ d->granted = 1;
+ d->request_idx = buf->idx;
+ d->request_size = buf->total;
+ d->virtual = buf_priv->virtual;
+
+ return retcode;
+}
+
+static unsigned long i830_alloc_page(drm_device_t *dev)
+{
+ unsigned long address;
+
+ address = __get_free_page(GFP_KERNEL);
+ if(address == 0UL)
+ return 0;
+
+#if LINUX_VERSION_CODE < 0x020500
+ atomic_inc(&virt_to_page(address)->count);
+ set_bit(PG_locked, &virt_to_page(address)->flags);
+#else
+ get_page(virt_to_page(address));
+ SetPageLocked(virt_to_page(address));
+#endif
+ return address;
+}
+
+static void i830_free_page(drm_device_t *dev, unsigned long page)
+{
+ if (page) {
+#if LINUX_VERSION_CODE < 0x020500
+ atomic_dec(&virt_to_page(page)->count);
+ clear_bit(PG_locked, &virt_to_page(page)->flags);
+ wake_up(&virt_to_page(page)->wait);
+#else
+ struct page *p = virt_to_page(page);
+ put_page(p);
+ unlock_page(p);
+#endif
+ free_page(page);
+ }
+}
+
+static int i830_dma_cleanup(drm_device_t *dev)
+{
+ drm_device_dma_t *dma = dev->dma;
+
+ if(dev->dev_private) {
+ int i;
+ drm_i830_private_t *dev_priv =
+ (drm_i830_private_t *) dev->dev_private;
+
+ if(dev_priv->ring.virtual_start) {
+ DRM(ioremapfree)((void *) dev_priv->ring.virtual_start,
+ dev_priv->ring.Size);
+ }
+ if(dev_priv->hw_status_page != 0UL) {
+ i830_free_page(dev, dev_priv->hw_status_page);
+ /* Need to rewrite hardware status page */
+ I830_WRITE(0x02080, 0x1ffff000);
+ }
+ DRM(free)(dev->dev_private, sizeof(drm_i830_private_t),
+ DRM_MEM_DRIVER);
+ dev->dev_private = NULL;
+
+ for (i = 0; i < dma->buf_count; i++) {
+ drm_buf_t *buf = dma->buflist[ i ];
+ drm_i830_buf_priv_t *buf_priv = buf->dev_private;
+ DRM(ioremapfree)(buf_priv->kernel_virtual, buf->total);
+ }
+ }
+ return 0;
+}
+
+static int i830_wait_ring(drm_device_t *dev, int n)
+{
+ drm_i830_private_t *dev_priv = dev->dev_private;
+ drm_i830_ring_buffer_t *ring = &(dev_priv->ring);
+ int iters = 0;
+ unsigned long end;
+ unsigned int last_head = I830_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
+
+ end = jiffies + (HZ*3);
+ while (ring->space < n) {
+ int i;
+
+ ring->head = I830_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
+ ring->space = ring->head - (ring->tail+8);
+ if (ring->space < 0) ring->space += ring->Size;
+
+ if (ring->head != last_head) {
+ end = jiffies + (HZ*3);
+ last_head = ring->head;
+ }
+
+ iters++;
+ if((signed)(end - jiffies) <= 0) {
+ DRM_ERROR("space: %d wanted %d\n", ring->space, n);
+ DRM_ERROR("lockup\n");
+ goto out_wait_ring;
+ }
+
+ udelay(1);
+ }
+
+out_wait_ring:
+ return iters;
+}
+
+static void i830_kernel_lost_context(drm_device_t *dev)
+{
+ drm_i830_private_t *dev_priv = dev->dev_private;
+ drm_i830_ring_buffer_t *ring = &(dev_priv->ring);
+
+ ring->head = I830_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
+ ring->tail = I830_READ(LP_RING + RING_TAIL);
+ ring->space = ring->head - (ring->tail+8);
+ if (ring->space < 0) ring->space += ring->Size;
+}
+
+static int i830_freelist_init(drm_device_t *dev, drm_i830_private_t *dev_priv)
+{
+ drm_device_dma_t *dma = dev->dma;
+ int my_idx = 36;
+ u32 *hw_status = (u32 *)(dev_priv->hw_status_page + my_idx);
+ int i;
+
+ if(dma->buf_count > 1019) {
+ /* Not enough space in the status page for the freelist */
+ return -EINVAL;
+ }
+
+ for (i = 0; i < dma->buf_count; i++) {
+ drm_buf_t *buf = dma->buflist[ i ];
+ drm_i830_buf_priv_t *buf_priv = buf->dev_private;
+
+ buf_priv->in_use = hw_status++;
+ buf_priv->my_use_idx = my_idx;
+ my_idx += 4;
+
+ *buf_priv->in_use = I830_BUF_FREE;
+
+ buf_priv->kernel_virtual = DRM(ioremap)(buf->bus_address,
+ buf->total);
+ }
+ return 0;
+}
+
+static int i830_dma_initialize(drm_device_t *dev,
+ drm_i830_private_t *dev_priv,
+ drm_i830_init_t *init)
+{
+ struct list_head *list;
+
+ memset(dev_priv, 0, sizeof(drm_i830_private_t));
+
+ list_for_each(list, &dev->maplist->head) {
+ drm_map_list_t *r_list = (drm_map_list_t *)list;
+ if( r_list->map &&
+ r_list->map->type == _DRM_SHM &&
+ r_list->map->flags & _DRM_CONTAINS_LOCK ) {
+ dev_priv->sarea_map = r_list->map;
+ break;
+ }
+ }
+
+ if(!dev_priv->sarea_map) {
+ dev->dev_private = (void *)dev_priv;
+ i830_dma_cleanup(dev);
+ DRM_ERROR("can not find sarea!\n");
+ return -EINVAL;
+ }
+ DRM_FIND_MAP( dev_priv->mmio_map, init->mmio_offset );
+ if(!dev_priv->mmio_map) {
+ dev->dev_private = (void *)dev_priv;
+ i830_dma_cleanup(dev);
+ DRM_ERROR("can not find mmio map!\n");
+ return -EINVAL;
+ }
+ DRM_FIND_MAP( dev_priv->buffer_map, init->buffers_offset );
+ if(!dev_priv->buffer_map) {
+ dev->dev_private = (void *)dev_priv;
+ i830_dma_cleanup(dev);
+ DRM_ERROR("can not find dma buffer map!\n");
+ return -EINVAL;
+ }
+
+ dev_priv->sarea_priv = (drm_i830_sarea_t *)
+ ((u8 *)dev_priv->sarea_map->handle +
+ init->sarea_priv_offset);
+
+ atomic_set(&dev_priv->flush_done, 0);
+ init_waitqueue_head(&dev_priv->flush_queue);
+
+ dev_priv->ring.Start = init->ring_start;
+ dev_priv->ring.End = init->ring_end;
+ dev_priv->ring.Size = init->ring_size;
+
+ dev_priv->ring.virtual_start = DRM(ioremap)(dev->agp->base +
+ init->ring_start,
+ init->ring_size);
+
+ if (dev_priv->ring.virtual_start == NULL) {
+ dev->dev_private = (void *) dev_priv;
+ i830_dma_cleanup(dev);
+ DRM_ERROR("can not ioremap virtual address for"
+ " ring buffer\n");
+ return -ENOMEM;
+ }
+
+ dev_priv->ring.tail_mask = dev_priv->ring.Size - 1;
+
+ dev_priv->w = init->w;
+ dev_priv->h = init->h;
+ dev_priv->pitch = init->pitch;
+ dev_priv->back_offset = init->back_offset;
+ dev_priv->depth_offset = init->depth_offset;
+
+ dev_priv->front_di1 = init->front_offset | init->pitch_bits;
+ dev_priv->back_di1 = init->back_offset | init->pitch_bits;
+ dev_priv->zi1 = init->depth_offset | init->pitch_bits;
+
+ dev_priv->cpp = init->cpp;
+ /* We are using seperate values as placeholders for mechanisms for
+ * private backbuffer/depthbuffer usage.
+ */
+
+ dev_priv->back_pitch = init->back_pitch;
+ dev_priv->depth_pitch = init->depth_pitch;
+
+ /* Program Hardware Status Page */
+ dev_priv->hw_status_page = i830_alloc_page(dev);
+ if(dev_priv->hw_status_page == 0UL) {
+ dev->dev_private = (void *)dev_priv;
+ i830_dma_cleanup(dev);
+ DRM_ERROR("Can not allocate hardware status page\n");
+ return -ENOMEM;
+ }
+ memset((void *) dev_priv->hw_status_page, 0, PAGE_SIZE);
+ DRM_DEBUG("hw status page @ %lx\n", dev_priv->hw_status_page);
+
+ I830_WRITE(0x02080, virt_to_bus((void *)dev_priv->hw_status_page));
+ DRM_DEBUG("Enabled hardware status page\n");
+
+ /* Now we need to init our freelist */
+ if(i830_freelist_init(dev, dev_priv) != 0) {
+ dev->dev_private = (void *)dev_priv;
+ i830_dma_cleanup(dev);
+ DRM_ERROR("Not enough space in the status page for"
+ " the freelist\n");
+ return -ENOMEM;
+ }
+ dev->dev_private = (void *)dev_priv;
+
+ return 0;
+}
+
+int i830_dma_init(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ drm_i830_private_t *dev_priv;
+ drm_i830_init_t init;
+ int retcode = 0;
+
+ if (copy_from_user(&init, (drm_i830_init_t *)arg, sizeof(init)))
+ return -EFAULT;
+
+ switch(init.func) {
+ case I830_INIT_DMA:
+ dev_priv = DRM(alloc)(sizeof(drm_i830_private_t),
+ DRM_MEM_DRIVER);
+ if(dev_priv == NULL) return -ENOMEM;
+ retcode = i830_dma_initialize(dev, dev_priv, &init);
+ break;
+ case I830_CLEANUP_DMA:
+ retcode = i830_dma_cleanup(dev);
+ break;
+ default:
+ retcode = -EINVAL;
+ break;
+ }
+
+ return retcode;
+}
+
+/* Most efficient way to verify state for the i830 is as it is
+ * emitted. Non-conformant state is silently dropped.
+ *
+ * Use 'volatile' & local var tmp to force the emitted values to be
+ * identical to the verified ones.
+ */
+static void i830EmitContextVerified( drm_device_t *dev,
+ volatile unsigned int *code )
+{
+ drm_i830_private_t *dev_priv = dev->dev_private;
+ int i, j = 0;
+ unsigned int tmp;
+ RING_LOCALS;
+
+ BEGIN_LP_RING( I830_CTX_SETUP_SIZE );
+ for ( i = 0 ; i < I830_CTX_SETUP_SIZE ; i++ ) {
+ tmp = code[i];
+
+#if 0
+ if ((tmp & (7<<29)) == (3<<29) &&
+ (tmp & (0x1f<<24)) < (0x1d<<24)) {
+ OUT_RING( tmp );
+ j++;
+ } else {
+ printk("Skipping %d\n", i);
+ }
+#else
+ OUT_RING( tmp );
+ j++;
+#endif
+ }
+
+ if (j & 1)
+ OUT_RING( 0 );
+
+ ADVANCE_LP_RING();
+}
+
+static void i830EmitTexVerified( drm_device_t *dev,
+ volatile unsigned int *code )
+{
+ drm_i830_private_t *dev_priv = dev->dev_private;
+ int i, j = 0;
+ unsigned int tmp;
+ RING_LOCALS;
+
+ BEGIN_LP_RING( I830_TEX_SETUP_SIZE );
+
+ OUT_RING( GFX_OP_MAP_INFO );
+ OUT_RING( code[I830_TEXREG_MI1] );
+ OUT_RING( code[I830_TEXREG_MI2] );
+ OUT_RING( code[I830_TEXREG_MI3] );
+ OUT_RING( code[I830_TEXREG_MI4] );
+ OUT_RING( code[I830_TEXREG_MI5] );
+
+ for ( i = 6 ; i < I830_TEX_SETUP_SIZE ; i++ ) {
+ tmp = code[i];
+ OUT_RING( tmp );
+ j++;
+ }
+
+ if (j & 1)
+ OUT_RING( 0 );
+
+ ADVANCE_LP_RING();
+}
+
+static void i830EmitTexBlendVerified( drm_device_t *dev,
+ volatile unsigned int *code,
+ volatile unsigned int num)
+{
+ drm_i830_private_t *dev_priv = dev->dev_private;
+ int i, j = 0;
+ unsigned int tmp;
+ RING_LOCALS;
+
+ BEGIN_LP_RING( num );
+
+ for ( i = 0 ; i < num ; i++ ) {
+ tmp = code[i];
+ OUT_RING( tmp );
+ j++;
+ }
+
+ if (j & 1)
+ OUT_RING( 0 );
+
+ ADVANCE_LP_RING();
+}
+
+static void i830EmitTexPalette( drm_device_t *dev,
+ unsigned int *palette,
+ int number,
+ int is_shared )
+{
+ drm_i830_private_t *dev_priv = dev->dev_private;
+ int i;
+ RING_LOCALS;
+
+ BEGIN_LP_RING( 258 );
+
+ if(is_shared == 1) {
+ OUT_RING(CMD_OP_MAP_PALETTE_LOAD |
+ MAP_PALETTE_NUM(0) |
+ MAP_PALETTE_BOTH);
+ } else {
+ OUT_RING(CMD_OP_MAP_PALETTE_LOAD | MAP_PALETTE_NUM(number));
+ }
+ for(i = 0; i < 256; i++) {
+ OUT_RING(palette[i]);
+ }
+ OUT_RING(0);
+}
+
+/* Need to do some additional checking when setting the dest buffer.
+ */
+static void i830EmitDestVerified( drm_device_t *dev,
+ volatile unsigned int *code )
+{
+ drm_i830_private_t *dev_priv = dev->dev_private;
+ unsigned int tmp;
+ RING_LOCALS;
+
+ BEGIN_LP_RING( I830_DEST_SETUP_SIZE + 6 );
+
+ tmp = code[I830_DESTREG_CBUFADDR];
+ if (tmp == dev_priv->front_di1) {
+ /* Don't use fence when front buffer rendering */
+ OUT_RING( CMD_OP_DESTBUFFER_INFO );
+ OUT_RING( BUF_3D_ID_COLOR_BACK |
+ BUF_3D_PITCH(dev_priv->back_pitch * dev_priv->cpp) );
+ OUT_RING( tmp );
+
+ OUT_RING( CMD_OP_DESTBUFFER_INFO );
+ OUT_RING( BUF_3D_ID_DEPTH |
+ BUF_3D_PITCH(dev_priv->depth_pitch * dev_priv->cpp));
+ OUT_RING( dev_priv->zi1 );
+ } else if(tmp == dev_priv->back_di1) {
+ OUT_RING( CMD_OP_DESTBUFFER_INFO );
+ OUT_RING( BUF_3D_ID_COLOR_BACK |
+ BUF_3D_PITCH(dev_priv->back_pitch * dev_priv->cpp) |
+ BUF_3D_USE_FENCE);
+ OUT_RING( tmp );
+
+ OUT_RING( CMD_OP_DESTBUFFER_INFO );
+ OUT_RING( BUF_3D_ID_DEPTH | BUF_3D_USE_FENCE |
+ BUF_3D_PITCH(dev_priv->depth_pitch * dev_priv->cpp));
+ OUT_RING( dev_priv->zi1 );
+ } else {
+ DRM_DEBUG("bad di1 %x (allow %x or %x)\n",
+ tmp, dev_priv->front_di1, dev_priv->back_di1);
+ }
+
+ /* invarient:
+ */
+
+
+ OUT_RING( GFX_OP_DESTBUFFER_VARS );
+ OUT_RING( code[I830_DESTREG_DV1] );
+
+ OUT_RING( GFX_OP_DRAWRECT_INFO );
+ OUT_RING( code[I830_DESTREG_DR1] );
+ OUT_RING( code[I830_DESTREG_DR2] );
+ OUT_RING( code[I830_DESTREG_DR3] );
+ OUT_RING( code[I830_DESTREG_DR4] );
+
+ /* Need to verify this */
+ tmp = code[I830_DESTREG_SENABLE];
+ if((tmp & ~0x3) == GFX_OP_SCISSOR_ENABLE) {
+ OUT_RING( tmp );
+ } else {
+ DRM_DEBUG("bad scissor enable\n");
+ OUT_RING( 0 );
+ }
+
+ OUT_RING( code[I830_DESTREG_SENABLE] );
+
+ OUT_RING( GFX_OP_SCISSOR_RECT );
+ OUT_RING( code[I830_DESTREG_SR1] );
+ OUT_RING( code[I830_DESTREG_SR2] );
+
+ ADVANCE_LP_RING();
+}
+
+static void i830EmitState( drm_device_t *dev )
+{
+ drm_i830_private_t *dev_priv = dev->dev_private;
+ drm_i830_sarea_t *sarea_priv = dev_priv->sarea_priv;
+ unsigned int dirty = sarea_priv->dirty;
+
+ if (dirty & I830_UPLOAD_BUFFERS) {
+ i830EmitDestVerified( dev, sarea_priv->BufferState );
+ sarea_priv->dirty &= ~I830_UPLOAD_BUFFERS;
+ }
+
+ if (dirty & I830_UPLOAD_CTX) {
+ i830EmitContextVerified( dev, sarea_priv->ContextState );
+ sarea_priv->dirty &= ~I830_UPLOAD_CTX;
+ }
+
+ if (dirty & I830_UPLOAD_TEX0) {
+ i830EmitTexVerified( dev, sarea_priv->TexState[0] );
+ sarea_priv->dirty &= ~I830_UPLOAD_TEX0;
+ }
+
+ if (dirty & I830_UPLOAD_TEX1) {
+ i830EmitTexVerified( dev, sarea_priv->TexState[1] );
+ sarea_priv->dirty &= ~I830_UPLOAD_TEX1;
+ }
+
+ if (dirty & I830_UPLOAD_TEXBLEND0) {
+ i830EmitTexBlendVerified( dev, sarea_priv->TexBlendState[0],
+ sarea_priv->TexBlendStateWordsUsed[0]);
+ sarea_priv->dirty &= ~I830_UPLOAD_TEXBLEND0;
+ }
+
+ if (dirty & I830_UPLOAD_TEXBLEND1) {
+ i830EmitTexBlendVerified( dev, sarea_priv->TexBlendState[1],
+ sarea_priv->TexBlendStateWordsUsed[1]);
+ sarea_priv->dirty &= ~I830_UPLOAD_TEXBLEND1;
+ }
+
+ if (dirty & I830_UPLOAD_TEX_PALETTE_SHARED) {
+ i830EmitTexPalette(dev, sarea_priv->Palette[0], 0, 1);
+ } else {
+ if (dirty & I830_UPLOAD_TEX_PALETTE_N(0)) {
+ i830EmitTexPalette(dev, sarea_priv->Palette[0], 0, 0);
+ sarea_priv->dirty &= ~I830_UPLOAD_TEX_PALETTE_N(0);
+ }
+ if (dirty & I830_UPLOAD_TEX_PALETTE_N(1)) {
+ i830EmitTexPalette(dev, sarea_priv->Palette[1], 1, 0);
+ sarea_priv->dirty &= ~I830_UPLOAD_TEX_PALETTE_N(1);
+ }
+ }
+}
+
+static void i830_dma_dispatch_clear( drm_device_t *dev, int flags,
+ unsigned int clear_color,
+ unsigned int clear_zval,
+ unsigned int clear_depthmask)
+{
+ drm_i830_private_t *dev_priv = dev->dev_private;
+ drm_i830_sarea_t *sarea_priv = dev_priv->sarea_priv;
+ int nbox = sarea_priv->nbox;
+ drm_clip_rect_t *pbox = sarea_priv->boxes;
+ int pitch = dev_priv->pitch;
+ int cpp = dev_priv->cpp;
+ int i;
+ unsigned int BR13, CMD, D_CMD;
+ RING_LOCALS;
+
+ i830_kernel_lost_context(dev);
+
+ switch(cpp) {
+ case 2:
+ BR13 = (0xF0 << 16) | (pitch * cpp) | (1<<24);
+ D_CMD = CMD = XY_COLOR_BLT_CMD;
+ break;
+ case 4:
+ BR13 = (0xF0 << 16) | (pitch * cpp) | (1<<24) | (1<<25);
+ CMD = (XY_COLOR_BLT_CMD | XY_COLOR_BLT_WRITE_ALPHA |
+ XY_COLOR_BLT_WRITE_RGB);
+ D_CMD = XY_COLOR_BLT_CMD;
+ if(clear_depthmask & 0x00ffffff)
+ D_CMD |= XY_COLOR_BLT_WRITE_RGB;
+ if(clear_depthmask & 0xff000000)
+ D_CMD |= XY_COLOR_BLT_WRITE_ALPHA;
+ break;
+ default:
+ BR13 = (0xF0 << 16) | (pitch * cpp) | (1<<24);
+ D_CMD = CMD = XY_COLOR_BLT_CMD;
+ break;
+ }
+
+ if (nbox > I830_NR_SAREA_CLIPRECTS)
+ nbox = I830_NR_SAREA_CLIPRECTS;
+
+ for (i = 0 ; i < nbox ; i++, pbox++) {
+ if (pbox->x1 > pbox->x2 ||
+ pbox->y1 > pbox->y2 ||
+ pbox->x2 > dev_priv->w ||
+ pbox->y2 > dev_priv->h)
+ continue;
+
+ if ( flags & I830_FRONT ) {
+ DRM_DEBUG("clear front\n");
+ BEGIN_LP_RING( 6 );
+ OUT_RING( CMD );
+ OUT_RING( BR13 );
+ OUT_RING( (pbox->y1 << 16) | pbox->x1 );
+ OUT_RING( (pbox->y2 << 16) | pbox->x2 );
+ OUT_RING( 0 );
+ OUT_RING( clear_color );
+ ADVANCE_LP_RING();
+ }
+
+ if ( flags & I830_BACK ) {
+ DRM_DEBUG("clear back\n");
+ BEGIN_LP_RING( 6 );
+ OUT_RING( CMD );
+ OUT_RING( BR13 );
+ OUT_RING( (pbox->y1 << 16) | pbox->x1 );
+ OUT_RING( (pbox->y2 << 16) | pbox->x2 );
+ OUT_RING( dev_priv->back_offset );
+ OUT_RING( clear_color );
+ ADVANCE_LP_RING();
+ }
+
+ if ( flags & I830_DEPTH ) {
+ DRM_DEBUG("clear depth\n");
+ BEGIN_LP_RING( 6 );
+ OUT_RING( D_CMD );
+ OUT_RING( BR13 );
+ OUT_RING( (pbox->y1 << 16) | pbox->x1 );
+ OUT_RING( (pbox->y2 << 16) | pbox->x2 );
+ OUT_RING( dev_priv->depth_offset );
+ OUT_RING( clear_zval );
+ ADVANCE_LP_RING();
+ }
+ }
+}
+
+static void i830_dma_dispatch_swap( drm_device_t *dev )
+{
+ drm_i830_private_t *dev_priv = dev->dev_private;
+ drm_i830_sarea_t *sarea_priv = dev_priv->sarea_priv;
+ int nbox = sarea_priv->nbox;
+ drm_clip_rect_t *pbox = sarea_priv->boxes;
+ int pitch = dev_priv->pitch;
+ int cpp = dev_priv->cpp;
+ int ofs = dev_priv->back_offset;
+ int i;
+ unsigned int CMD, BR13;
+ RING_LOCALS;
+
+ DRM_DEBUG("swapbuffers\n");
+
+ switch(cpp) {
+ case 2:
+ BR13 = (pitch * cpp) | (0xCC << 16) | (1<<24);
+ CMD = XY_SRC_COPY_BLT_CMD;
+ break;
+ case 4:
+ BR13 = (pitch * cpp) | (0xCC << 16) | (1<<24) | (1<<25);
+ CMD = (XY_SRC_COPY_BLT_CMD | XY_SRC_COPY_BLT_WRITE_ALPHA |
+ XY_SRC_COPY_BLT_WRITE_RGB);
+ break;
+ default:
+ BR13 = (pitch * cpp) | (0xCC << 16) | (1<<24);
+ CMD = XY_SRC_COPY_BLT_CMD;
+ break;
+ }
+
+ i830_kernel_lost_context(dev);
+
+ if (nbox > I830_NR_SAREA_CLIPRECTS)
+ nbox = I830_NR_SAREA_CLIPRECTS;
+
+ for (i = 0 ; i < nbox; i++, pbox++)
+ {
+ if (pbox->x1 > pbox->x2 ||
+ pbox->y1 > pbox->y2 ||
+ pbox->x2 > dev_priv->w ||
+ pbox->y2 > dev_priv->h)
+ continue;
+
+ DRM_DEBUG("dispatch swap %d,%d-%d,%d!\n",
+ pbox->x1, pbox->y1,
+ pbox->x2, pbox->y2);
+
+ BEGIN_LP_RING( 8 );
+ OUT_RING( CMD );
+ OUT_RING( BR13 );
+
+ OUT_RING( (pbox->y1 << 16) |
+ pbox->x1 );
+ OUT_RING( (pbox->y2 << 16) |
+ pbox->x2 );
+
+ OUT_RING( 0 /* front ofs always zero */ );
+ OUT_RING( (pbox->y1 << 16) |
+ pbox->x1 );
+
+ OUT_RING( BR13 & 0xffff );
+ OUT_RING( ofs );
+
+ ADVANCE_LP_RING();
+ }
+}
+
+
+static void i830_dma_dispatch_vertex(drm_device_t *dev,
+ drm_buf_t *buf,
+ int discard,
+ int used)
+{
+ drm_i830_private_t *dev_priv = dev->dev_private;
+ drm_i830_buf_priv_t *buf_priv = buf->dev_private;
+ drm_i830_sarea_t *sarea_priv = dev_priv->sarea_priv;
+ drm_clip_rect_t *box = sarea_priv->boxes;
+ int nbox = sarea_priv->nbox;
+ unsigned long address = (unsigned long)buf->bus_address;
+ unsigned long start = address - dev->agp->base;
+ int i = 0, u;
+ RING_LOCALS;
+
+ i830_kernel_lost_context(dev);
+
+ if (nbox > I830_NR_SAREA_CLIPRECTS)
+ nbox = I830_NR_SAREA_CLIPRECTS;
+
+ if (discard) {
+ u = cmpxchg(buf_priv->in_use, I830_BUF_CLIENT,
+ I830_BUF_HARDWARE);
+ if(u != I830_BUF_CLIENT) {
+ DRM_DEBUG("xxxx 2\n");
+ }
+ }
+
+ if (used > 4*1024)
+ used = 0;
+
+ if (sarea_priv->dirty)
+ i830EmitState( dev );
+
+ DRM_DEBUG("dispatch vertex addr 0x%lx, used 0x%x nbox %d\n",
+ address, used, nbox);
+
+ dev_priv->counter++;
+ DRM_DEBUG( "dispatch counter : %ld\n", dev_priv->counter);
+ DRM_DEBUG( "i830_dma_dispatch\n");
+ DRM_DEBUG( "start : %lx\n", start);
+ DRM_DEBUG( "used : %d\n", used);
+ DRM_DEBUG( "start + used - 4 : %ld\n", start + used - 4);
+
+ if (buf_priv->currently_mapped == I830_BUF_MAPPED) {
+ *(u32 *)buf_priv->virtual = (GFX_OP_PRIMITIVE |
+ sarea_priv->vertex_prim |
+ ((used/4)-2));
+
+ if (used & 4) {
+ *(u32 *)((u32)buf_priv->virtual + used) = 0;
+ used += 4;
+ }
+
+ i830_unmap_buffer(buf);
+ }
+
+ if (used) {
+ do {
+ if (i < nbox) {
+ BEGIN_LP_RING(6);
+ OUT_RING( GFX_OP_DRAWRECT_INFO );
+ OUT_RING( sarea_priv->BufferState[I830_DESTREG_DR1] );
+ OUT_RING( box[i].x1 | (box[i].y1<<16) );
+ OUT_RING( box[i].x2 | (box[i].y2<<16) );
+ OUT_RING( sarea_priv->BufferState[I830_DESTREG_DR4] );
+ OUT_RING( 0 );
+ ADVANCE_LP_RING();
+ }
+
+ BEGIN_LP_RING(4);
+
+ OUT_RING( MI_BATCH_BUFFER );
+ OUT_RING( start | MI_BATCH_NON_SECURE );
+ OUT_RING( start + used - 4 );
+ OUT_RING( 0 );
+ ADVANCE_LP_RING();
+
+ } while (++i < nbox);
+ }
+
+ BEGIN_LP_RING(10);
+ OUT_RING( CMD_STORE_DWORD_IDX );
+ OUT_RING( 20 );
+ OUT_RING( dev_priv->counter );
+ OUT_RING( 0 );
+
+ if (discard) {
+ OUT_RING( CMD_STORE_DWORD_IDX );
+ OUT_RING( buf_priv->my_use_idx );
+ OUT_RING( I830_BUF_FREE );
+ OUT_RING( 0 );
+ }
+
+ OUT_RING( CMD_REPORT_HEAD );
+ OUT_RING( 0 );
+ ADVANCE_LP_RING();
+}
+
+/* Interrupts are only for flushing */
+void i830_dma_service(int irq, void *device, struct pt_regs *regs)
+{
+ drm_device_t *dev = (drm_device_t *)device;
+ drm_i830_private_t *dev_priv = (drm_i830_private_t *)dev->dev_private;
+ u16 temp;
+
+ temp = I830_READ16(I830REG_INT_IDENTITY_R);
+ temp = temp & ~(0x6000);
+ if(temp != 0) I830_WRITE16(I830REG_INT_IDENTITY_R,
+ temp); /* Clear all interrupts */
+ else
+ return;
+
+ queue_task(&dev->tq, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+}
+
+void DRM(dma_immediate_bh)(void *device)
+{
+ drm_device_t *dev = (drm_device_t *) device;
+ drm_i830_private_t *dev_priv = (drm_i830_private_t *)dev->dev_private;
+
+ atomic_set(&dev_priv->flush_done, 1);
+ wake_up_interruptible(&dev_priv->flush_queue);
+}
+
+static inline void i830_dma_emit_flush(drm_device_t *dev)
+{
+ drm_i830_private_t *dev_priv = dev->dev_private;
+ RING_LOCALS;
+
+ i830_kernel_lost_context(dev);
+
+ BEGIN_LP_RING(2);
+ OUT_RING( CMD_REPORT_HEAD );
+ OUT_RING( GFX_OP_USER_INTERRUPT );
+ ADVANCE_LP_RING();
+
+ i830_wait_ring( dev, dev_priv->ring.Size - 8 );
+ atomic_set(&dev_priv->flush_done, 1);
+ wake_up_interruptible(&dev_priv->flush_queue);
+}
+
+static inline void i830_dma_quiescent_emit(drm_device_t *dev)
+{
+ drm_i830_private_t *dev_priv = dev->dev_private;
+ RING_LOCALS;
+
+ i830_kernel_lost_context(dev);
+
+ BEGIN_LP_RING(4);
+ OUT_RING( INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE );
+ OUT_RING( CMD_REPORT_HEAD );
+ OUT_RING( 0 );
+ OUT_RING( GFX_OP_USER_INTERRUPT );
+ ADVANCE_LP_RING();
+
+ i830_wait_ring( dev, dev_priv->ring.Size - 8 );
+ atomic_set(&dev_priv->flush_done, 1);
+ wake_up_interruptible(&dev_priv->flush_queue);
+}
+
+void i830_dma_quiescent(drm_device_t *dev)
+{
+ DECLARE_WAITQUEUE(entry, current);
+ drm_i830_private_t *dev_priv = (drm_i830_private_t *)dev->dev_private;
+ unsigned long end;
+
+ if(dev_priv == NULL) {
+ return;
+ }
+ atomic_set(&dev_priv->flush_done, 0);
+ add_wait_queue(&dev_priv->flush_queue, &entry);
+ end = jiffies + (HZ*3);
+
+ for (;;) {
+ current->state = TASK_INTERRUPTIBLE;
+ i830_dma_quiescent_emit(dev);
+ if (atomic_read(&dev_priv->flush_done) == 1) break;
+ if((signed)(end - jiffies) <= 0) {
+ DRM_ERROR("lockup\n");
+ break;
+ }
+ schedule_timeout(HZ*3);
+ if (signal_pending(current)) {
+ break;
+ }
+ }
+
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&dev_priv->flush_queue, &entry);
+
+ return;
+}
+
+static int i830_flush_queue(drm_device_t *dev)
+{
+ DECLARE_WAITQUEUE(entry, current);
+ drm_i830_private_t *dev_priv = (drm_i830_private_t *)dev->dev_private;
+ drm_device_dma_t *dma = dev->dma;
+ unsigned long end;
+ int i, ret = 0;
+
+ if(dev_priv == NULL) {
+ return 0;
+ }
+ atomic_set(&dev_priv->flush_done, 0);
+ add_wait_queue(&dev_priv->flush_queue, &entry);
+ end = jiffies + (HZ*3);
+ for (;;) {
+ current->state = TASK_INTERRUPTIBLE;
+ i830_dma_emit_flush(dev);
+ if (atomic_read(&dev_priv->flush_done) == 1) break;
+ if((signed)(end - jiffies) <= 0) {
+ DRM_ERROR("lockup\n");
+ break;
+ }
+ schedule_timeout(HZ*3);
+ if (signal_pending(current)) {
+ ret = -EINTR; /* Can't restart */
+ break;
+ }
+ }
+
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&dev_priv->flush_queue, &entry);
+
+
+ for (i = 0; i < dma->buf_count; i++) {
+ drm_buf_t *buf = dma->buflist[ i ];
+ drm_i830_buf_priv_t *buf_priv = buf->dev_private;
+
+ int used = cmpxchg(buf_priv->in_use, I830_BUF_HARDWARE,
+ I830_BUF_FREE);
+
+ if (used == I830_BUF_HARDWARE)
+ DRM_DEBUG("reclaimed from HARDWARE\n");
+ if (used == I830_BUF_CLIENT)
+ DRM_DEBUG("still on client HARDWARE\n");
+ }
+
+ return ret;
+}
+
+/* Must be called with the lock held */
+void i830_reclaim_buffers(drm_device_t *dev, pid_t pid)
+{
+ drm_device_dma_t *dma = dev->dma;
+ int i;
+
+ if (!dma) return;
+ if (!dev->dev_private) return;
+ if (!dma->buflist) return;
+
+ i830_flush_queue(dev);
+
+ for (i = 0; i < dma->buf_count; i++) {
+ drm_buf_t *buf = dma->buflist[ i ];
+ drm_i830_buf_priv_t *buf_priv = buf->dev_private;
+
+ if (buf->pid == pid && buf_priv) {
+ int used = cmpxchg(buf_priv->in_use, I830_BUF_CLIENT,
+ I830_BUF_FREE);
+
+ if (used == I830_BUF_CLIENT)
+ DRM_DEBUG("reclaimed from client\n");
+ if(buf_priv->currently_mapped == I830_BUF_MAPPED)
+ buf_priv->currently_mapped = I830_BUF_UNMAPPED;
+ }
+ }
+}
+
+int i830_flush_ioctl(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+
+ DRM_DEBUG("i830_flush_ioctl\n");
+ if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+ DRM_ERROR("i830_flush_ioctl called without lock held\n");
+ return -EINVAL;
+ }
+
+ i830_flush_queue(dev);
+ return 0;
+}
+
+int i830_dma_vertex(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ drm_device_dma_t *dma = dev->dma;
+ drm_i830_private_t *dev_priv = (drm_i830_private_t *)dev->dev_private;
+ u32 *hw_status = (u32 *)dev_priv->hw_status_page;
+ drm_i830_sarea_t *sarea_priv = (drm_i830_sarea_t *)
+ dev_priv->sarea_priv;
+ drm_i830_vertex_t vertex;
+
+ if (copy_from_user(&vertex, (drm_i830_vertex_t *)arg, sizeof(vertex)))
+ return -EFAULT;
+
+ if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+ DRM_ERROR("i830_dma_vertex called without lock held\n");
+ return -EINVAL;
+ }
+
+ DRM_DEBUG("i830 dma vertex, idx %d used %d discard %d\n",
+ vertex.idx, vertex.used, vertex.discard);
+
+ if(vertex.idx < 0 || vertex.idx > dma->buf_count) return -EINVAL;
+
+ i830_dma_dispatch_vertex( dev,
+ dma->buflist[ vertex.idx ],
+ vertex.discard, vertex.used );
+
+ sarea_priv->last_enqueue = dev_priv->counter-1;
+ sarea_priv->last_dispatch = (int) hw_status[5];
+
+ return 0;
+}
+
+int i830_clear_bufs(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ drm_i830_clear_t clear;
+
+ if (copy_from_user(&clear, (drm_i830_clear_t *)arg, sizeof(clear)))
+ return -EFAULT;
+
+ if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+ DRM_ERROR("i830_clear_bufs called without lock held\n");
+ return -EINVAL;
+ }
+
+ /* GH: Someone's doing nasty things... */
+ if (!dev->dev_private) {
+ return -EINVAL;
+ }
+
+ i830_dma_dispatch_clear( dev, clear.flags,
+ clear.clear_color,
+ clear.clear_depth,
+ clear.clear_depthmask);
+ return 0;
+}
+
+int i830_swap_bufs(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+
+ DRM_DEBUG("i830_swap_bufs\n");
+
+ if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+ DRM_ERROR("i830_swap_buf called without lock held\n");
+ return -EINVAL;
+ }
+
+ i830_dma_dispatch_swap( dev );
+ return 0;
+}
+
+int i830_getage(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ drm_i830_private_t *dev_priv = (drm_i830_private_t *)dev->dev_private;
+ u32 *hw_status = (u32 *)dev_priv->hw_status_page;
+ drm_i830_sarea_t *sarea_priv = (drm_i830_sarea_t *)
+ dev_priv->sarea_priv;
+
+ sarea_priv->last_dispatch = (int) hw_status[5];
+ return 0;
+}
+
+int i830_getbuf(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ int retcode = 0;
+ drm_i830_dma_t d;
+ drm_i830_private_t *dev_priv = (drm_i830_private_t *)dev->dev_private;
+ u32 *hw_status = (u32 *)dev_priv->hw_status_page;
+ drm_i830_sarea_t *sarea_priv = (drm_i830_sarea_t *)
+ dev_priv->sarea_priv;
+
+ DRM_DEBUG("getbuf\n");
+ if (copy_from_user(&d, (drm_i830_dma_t *)arg, sizeof(d)))
+ return -EFAULT;
+
+ if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+ DRM_ERROR("i830_dma called without lock held\n");
+ return -EINVAL;
+ }
+
+ d.granted = 0;
+
+ retcode = i830_dma_get_buffer(dev, &d, filp);
+
+ DRM_DEBUG("i830_dma: %d returning %d, granted = %d\n",
+ current->pid, retcode, d.granted);
+
+ if (copy_to_user((drm_dma_t *)arg, &d, sizeof(d)))
+ return -EFAULT;
+ sarea_priv->last_dispatch = (int) hw_status[5];
+
+ return retcode;
+}
+
+int i830_copybuf(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ drm_i830_copy_t d;
+ drm_i830_private_t *dev_priv = (drm_i830_private_t *)dev->dev_private;
+ u32 *hw_status = (u32 *)dev_priv->hw_status_page;
+ drm_i830_sarea_t *sarea_priv = (drm_i830_sarea_t *)
+ dev_priv->sarea_priv;
+ drm_buf_t *buf;
+ drm_i830_buf_priv_t *buf_priv;
+ drm_device_dma_t *dma = dev->dma;
+
+ if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+ DRM_ERROR("i830_dma called without lock held\n");
+ return -EINVAL;
+ }
+
+ if (copy_from_user(&d, (drm_i830_copy_t *)arg, sizeof(d)))
+ return -EFAULT;
+
+ if(d.idx < 0 || d.idx > dma->buf_count) return -EINVAL;
+ buf = dma->buflist[ d.idx ];
+ buf_priv = buf->dev_private;
+ if (buf_priv->currently_mapped != I830_BUF_MAPPED) return -EPERM;
+
+ if(d.used < 0 || d.used > buf->total) return -EINVAL;
+
+ if (copy_from_user(buf_priv->virtual, d.address, d.used))
+ return -EFAULT;
+
+ sarea_priv->last_dispatch = (int) hw_status[5];
+
+ return 0;
+}
+
+int i830_docopy(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ if(VM_DONTCOPY == 0) return 1;
+ return 0;
+}
--- /dev/null
+#ifndef _I830_DRM_H_
+#define _I830_DRM_H_
+
+/* WARNING: These defines must be the same as what the Xserver uses.
+ * if you change them, you must change the defines in the Xserver.
+ */
+
+#ifndef _I830_DEFINES_
+#define _I830_DEFINES_
+
+#define I830_DMA_BUF_ORDER 12
+#define I830_DMA_BUF_SZ (1<<I830_DMA_BUF_ORDER)
+#define I830_DMA_BUF_NR 256
+#define I830_NR_SAREA_CLIPRECTS 8
+
+/* Each region is a minimum of 64k, and there are at most 64 of them.
+ */
+#define I830_NR_TEX_REGIONS 64
+#define I830_LOG_MIN_TEX_REGION_SIZE 16
+
+/* if defining I830_ENABLE_4_TEXTURES, do it in i830_3d_reg.h, too */
+#if !defined(I830_ENABLE_4_TEXTURES)
+#define I830_TEXTURE_COUNT 2
+#define I830_TEXBLEND_COUNT 2 /* always same as TEXTURE_COUNT? */
+#else /* defined(I830_ENABLE_4_TEXTURES) */
+#define I830_TEXTURE_COUNT 4
+#define I830_TEXBLEND_COUNT 4 /* always same as TEXTURE_COUNT? */
+#endif /* I830_ENABLE_4_TEXTURES */
+
+#define I830_TEXBLEND_SIZE 12 /* (4 args + op) * 2 + COLOR_FACTOR */
+
+#define I830_UPLOAD_CTX 0x1
+#define I830_UPLOAD_BUFFERS 0x2
+#define I830_UPLOAD_CLIPRECTS 0x4
+#define I830_UPLOAD_TEX0_IMAGE 0x100 /* handled clientside */
+#define I830_UPLOAD_TEX0_CUBE 0x200 /* handled clientside */
+#define I830_UPLOAD_TEX1_IMAGE 0x400 /* handled clientside */
+#define I830_UPLOAD_TEX1_CUBE 0x800 /* handled clientside */
+#define I830_UPLOAD_TEX2_IMAGE 0x1000 /* handled clientside */
+#define I830_UPLOAD_TEX2_CUBE 0x2000 /* handled clientside */
+#define I830_UPLOAD_TEX3_IMAGE 0x4000 /* handled clientside */
+#define I830_UPLOAD_TEX3_CUBE 0x8000 /* handled clientside */
+#define I830_UPLOAD_TEX_N_IMAGE(n) (0x100 << (n * 2))
+#define I830_UPLOAD_TEX_N_CUBE(n) (0x200 << (n * 2))
+#define I830_UPLOAD_TEXIMAGE_MASK 0xff00
+#define I830_UPLOAD_TEX0 0x10000
+#define I830_UPLOAD_TEX1 0x20000
+#define I830_UPLOAD_TEX2 0x40000
+#define I830_UPLOAD_TEX3 0x80000
+#define I830_UPLOAD_TEX_N(n) (0x10000 << (n))
+#define I830_UPLOAD_TEX_MASK 0xf0000
+#define I830_UPLOAD_TEXBLEND0 0x100000
+#define I830_UPLOAD_TEXBLEND1 0x200000
+#define I830_UPLOAD_TEXBLEND2 0x400000
+#define I830_UPLOAD_TEXBLEND3 0x800000
+#define I830_UPLOAD_TEXBLEND_N(n) (0x100000 << (n))
+#define I830_UPLOAD_TEXBLEND_MASK 0xf00000
+#define I830_UPLOAD_TEX_PALETTE_N(n) (0x1000000 << (n))
+#define I830_UPLOAD_TEX_PALETTE_SHARED 0x4000000
+
+/* Indices into buf.Setup where various bits of state are mirrored per
+ * context and per buffer. These can be fired at the card as a unit,
+ * or in a piecewise fashion as required.
+ */
+
+/* Destbuffer state
+ * - backbuffer linear offset and pitch -- invarient in the current dri
+ * - zbuffer linear offset and pitch -- also invarient
+ * - drawing origin in back and depth buffers.
+ *
+ * Keep the depth/back buffer state here to acommodate private buffers
+ * in the future.
+ */
+
+#define I830_DESTREG_CBUFADDR 0
+/* Invarient */
+#define I830_DESTREG_DBUFADDR 1
+#define I830_DESTREG_DV0 2
+#define I830_DESTREG_DV1 3
+#define I830_DESTREG_SENABLE 4
+#define I830_DESTREG_SR0 5
+#define I830_DESTREG_SR1 6
+#define I830_DESTREG_SR2 7
+#define I830_DESTREG_DR0 8
+#define I830_DESTREG_DR1 9
+#define I830_DESTREG_DR2 10
+#define I830_DESTREG_DR3 11
+#define I830_DESTREG_DR4 12
+#define I830_DEST_SETUP_SIZE 13
+
+/* Context state
+ */
+#define I830_CTXREG_STATE1 0
+#define I830_CTXREG_STATE2 1
+#define I830_CTXREG_STATE3 2
+#define I830_CTXREG_STATE4 3
+#define I830_CTXREG_STATE5 4
+#define I830_CTXREG_IALPHAB 5
+#define I830_CTXREG_STENCILTST 6
+#define I830_CTXREG_ENABLES_1 7
+#define I830_CTXREG_ENABLES_2 8
+#define I830_CTXREG_AA 9
+#define I830_CTXREG_FOGCOLOR 10
+#define I830_CTXREG_BLENDCOLR0 11
+#define I830_CTXREG_BLENDCOLR 12 /* Dword 1 of 2 dword command */
+#define I830_CTXREG_VF 13
+#define I830_CTXREG_VF2 14
+#define I830_CTXREG_MCSB0 15
+#define I830_CTXREG_MCSB1 16
+#define I830_CTX_SETUP_SIZE 17
+
+/* Texture state (per tex unit)
+ */
+
+#define I830_TEXREG_MI0 0 /* GFX_OP_MAP_INFO (6 dwords) */
+#define I830_TEXREG_MI1 1
+#define I830_TEXREG_MI2 2
+#define I830_TEXREG_MI3 3
+#define I830_TEXREG_MI4 4
+#define I830_TEXREG_MI5 5
+#define I830_TEXREG_MF 6 /* GFX_OP_MAP_FILTER */
+#define I830_TEXREG_MLC 7 /* GFX_OP_MAP_LOD_CTL */
+#define I830_TEXREG_MLL 8 /* GFX_OP_MAP_LOD_LIMITS */
+#define I830_TEXREG_MCS 9 /* GFX_OP_MAP_COORD_SETS */
+#define I830_TEX_SETUP_SIZE 10
+
+#define I830_FRONT 0x1
+#define I830_BACK 0x2
+#define I830_DEPTH 0x4
+
+#endif /* _I830_DEFINES_ */
+
+typedef struct _drm_i830_init {
+ enum {
+ I830_INIT_DMA = 0x01,
+ I830_CLEANUP_DMA = 0x02
+ } func;
+ unsigned int mmio_offset;
+ unsigned int buffers_offset;
+ int sarea_priv_offset;
+ unsigned int ring_start;
+ unsigned int ring_end;
+ unsigned int ring_size;
+ unsigned int front_offset;
+ unsigned int back_offset;
+ unsigned int depth_offset;
+ unsigned int w;
+ unsigned int h;
+ unsigned int pitch;
+ unsigned int pitch_bits;
+ unsigned int back_pitch;
+ unsigned int depth_pitch;
+ unsigned int cpp;
+} drm_i830_init_t;
+
+/* Warning: If you change the SAREA structure you must change the Xserver
+ * structure as well */
+
+typedef struct _drm_i830_tex_region {
+ unsigned char next, prev; /* indices to form a circular LRU */
+ unsigned char in_use; /* owned by a client, or free? */
+ int age; /* tracked by clients to update local LRU's */
+} drm_i830_tex_region_t;
+
+typedef struct _drm_i830_sarea {
+ unsigned int ContextState[I830_CTX_SETUP_SIZE];
+ unsigned int BufferState[I830_DEST_SETUP_SIZE];
+ unsigned int TexState[I830_TEXTURE_COUNT][I830_TEX_SETUP_SIZE];
+ unsigned int TexBlendState[I830_TEXBLEND_COUNT][I830_TEXBLEND_SIZE];
+ unsigned int TexBlendStateWordsUsed[I830_TEXBLEND_COUNT];
+ unsigned int Palette[2][256];
+ unsigned int dirty;
+
+ unsigned int nbox;
+ drm_clip_rect_t boxes[I830_NR_SAREA_CLIPRECTS];
+
+ /* Maintain an LRU of contiguous regions of texture space. If
+ * you think you own a region of texture memory, and it has an
+ * age different to the one you set, then you are mistaken and
+ * it has been stolen by another client. If global texAge
+ * hasn't changed, there is no need to walk the list.
+ *
+ * These regions can be used as a proxy for the fine-grained
+ * texture information of other clients - by maintaining them
+ * in the same lru which is used to age their own textures,
+ * clients have an approximate lru for the whole of global
+ * texture space, and can make informed decisions as to which
+ * areas to kick out. There is no need to choose whether to
+ * kick out your own texture or someone else's - simply eject
+ * them all in LRU order.
+ */
+
+ drm_i830_tex_region_t texList[I830_NR_TEX_REGIONS+1];
+ /* Last elt is sentinal */
+ int texAge; /* last time texture was uploaded */
+ int last_enqueue; /* last time a buffer was enqueued */
+ int last_dispatch; /* age of the most recently dispatched buffer */
+ int last_quiescent; /* */
+ int ctxOwner; /* last context to upload state */
+
+ int vertex_prim;
+} drm_i830_sarea_t;
+
+typedef struct _drm_i830_clear {
+ int clear_color;
+ int clear_depth;
+ int flags;
+ unsigned int clear_colormask;
+ unsigned int clear_depthmask;
+} drm_i830_clear_t;
+
+
+
+/* These may be placeholders if we have more cliprects than
+ * I830_NR_SAREA_CLIPRECTS. In that case, the client sets discard to
+ * false, indicating that the buffer will be dispatched again with a
+ * new set of cliprects.
+ */
+typedef struct _drm_i830_vertex {
+ int idx; /* buffer index */
+ int used; /* nr bytes in use */
+ int discard; /* client is finished with the buffer? */
+} drm_i830_vertex_t;
+
+typedef struct _drm_i830_copy_t {
+ int idx; /* buffer index */
+ int used; /* nr bytes in use */
+ void *address; /* Address to copy from */
+} drm_i830_copy_t;
+
+typedef struct drm_i830_dma {
+ void *virtual;
+ int request_idx;
+ int request_size;
+ int granted;
+} drm_i830_dma_t;
+
+#endif /* _I830_DRM_H_ */
--- /dev/null
+/* i830_drv.c -- I810 driver -*- linux-c -*-
+ * Created: Mon Dec 13 01:56:22 1999 by jhartmann@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Rickard E. (Rik) Faith <faith@valinux.com>
+ * Jeff Hartmann <jhartmann@valinux.com>
+ * Gareth Hughes <gareth@valinux.com>
+ * Abraham vd Merwe <abraham@2d3d.co.za>
+ */
+
+#include <linux/config.h>
+#include "i830.h"
+#include "drmP.h"
+#include "i830_drv.h"
+
+#define DRIVER_AUTHOR "VA Linux Systems Inc."
+
+#define DRIVER_NAME "i830"
+#define DRIVER_DESC "Intel 830M"
+#define DRIVER_DATE "20011004"
+
+#define DRIVER_MAJOR 1
+#define DRIVER_MINOR 2
+#define DRIVER_PATCHLEVEL 0
+
+#define DRIVER_IOCTLS \
+ [DRM_IOCTL_NR(DRM_IOCTL_I830_INIT)] = { i830_dma_init, 1, 1 }, \
+ [DRM_IOCTL_NR(DRM_IOCTL_I830_VERTEX)] = { i830_dma_vertex, 1, 0 }, \
+ [DRM_IOCTL_NR(DRM_IOCTL_I830_CLEAR)] = { i830_clear_bufs, 1, 0 }, \
+ [DRM_IOCTL_NR(DRM_IOCTL_I830_FLUSH)] = { i830_flush_ioctl, 1, 0 }, \
+ [DRM_IOCTL_NR(DRM_IOCTL_I830_GETAGE)] = { i830_getage, 1, 0 }, \
+ [DRM_IOCTL_NR(DRM_IOCTL_I830_GETBUF)] = { i830_getbuf, 1, 0 }, \
+ [DRM_IOCTL_NR(DRM_IOCTL_I830_SWAP)] = { i830_swap_bufs, 1, 0 }, \
+ [DRM_IOCTL_NR(DRM_IOCTL_I830_COPY)] = { i830_copybuf, 1, 0 }, \
+ [DRM_IOCTL_NR(DRM_IOCTL_I830_DOCOPY)] = { i830_docopy, 1, 0 },
+
+#define __HAVE_COUNTERS 4
+#define __HAVE_COUNTER6 _DRM_STAT_IRQ
+#define __HAVE_COUNTER7 _DRM_STAT_PRIMARY
+#define __HAVE_COUNTER8 _DRM_STAT_SECONDARY
+#define __HAVE_COUNTER9 _DRM_STAT_DMA
+
+
+#include "drm_agpsupport.h"
+#include "drm_auth.h"
+#include "drm_bufs.h"
+#include "drm_context.h"
+#include "drm_dma.h"
+#include "drm_drawable.h"
+#include "drm_drv.h"
+
+#ifndef MODULE
+/* DRM(options) is called by the kernel to parse command-line options
+ * passed via the boot-loader (e.g., LILO). It calls the insmod option
+ * routine, drm_parse_drm.
+ */
+
+/* JH- We have to hand expand the string ourselves because of the cpp. If
+ * anyone can think of a way that we can fit into the __setup macro without
+ * changing it, then please send the solution my way.
+ */
+static int __init i830_options( char *str )
+{
+ DRM(parse_options)( str );
+ return 1;
+}
+
+__setup( DRIVER_NAME "=", i830_options );
+#endif
+
+#include "drm_fops.h"
+#include "drm_init.h"
+#include "drm_ioctl.h"
+#include "drm_lock.h"
+#include "drm_lists.h"
+#include "drm_memory.h"
+#include "drm_proc.h"
+#include "drm_vm.h"
+#include "drm_stub.h"
--- /dev/null
+/* i830_drv.h -- Private header for the I830 driver -*- linux-c -*-
+ * Created: Mon Dec 13 01:50:01 1999 by jhartmann@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Rickard E. (Rik) Faith <faith@valinux.com>
+ * Jeff Hartmann <jhartmann@valinux.com>
+ *
+ */
+
+#ifndef _I830_DRV_H_
+#define _I830_DRV_H_
+
+typedef struct drm_i830_buf_priv {
+ u32 *in_use;
+ int my_use_idx;
+ int currently_mapped;
+ void *virtual;
+ void *kernel_virtual;
+ int map_count;
+ struct vm_area_struct *vma;
+} drm_i830_buf_priv_t;
+
+typedef struct _drm_i830_ring_buffer{
+ int tail_mask;
+ unsigned long Start;
+ unsigned long End;
+ unsigned long Size;
+ u8 *virtual_start;
+ int head;
+ int tail;
+ int space;
+} drm_i830_ring_buffer_t;
+
+typedef struct drm_i830_private {
+ drm_map_t *sarea_map;
+ drm_map_t *buffer_map;
+ drm_map_t *mmio_map;
+
+ drm_i830_sarea_t *sarea_priv;
+ drm_i830_ring_buffer_t ring;
+
+ unsigned long hw_status_page;
+ unsigned long counter;
+
+ atomic_t flush_done;
+ wait_queue_head_t flush_queue; /* Processes waiting until flush */
+ drm_buf_t *mmap_buffer;
+
+ u32 front_di1, back_di1, zi1;
+
+ int back_offset;
+ int depth_offset;
+ int w, h;
+ int pitch;
+ int back_pitch;
+ int depth_pitch;
+ unsigned int cpp;
+} drm_i830_private_t;
+
+ /* i830_dma.c */
+extern int i830_dma_schedule(drm_device_t *dev, int locked);
+extern int i830_getbuf(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+extern int i830_dma_init(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+extern int i830_flush_ioctl(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+extern void i830_reclaim_buffers(drm_device_t *dev, pid_t pid);
+extern int i830_getage(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg);
+extern int i830_mmap_buffers(struct file *filp, struct vm_area_struct *vma);
+extern int i830_copybuf(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+extern int i830_docopy(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+
+extern void i830_dma_quiescent(drm_device_t *dev);
+
+extern int i830_dma_vertex(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+
+extern int i830_swap_bufs(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+
+extern int i830_clear_bufs(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+
+#define I830_VERBOSE 0
+
+#define I830_BASE(reg) ((unsigned long) \
+ dev_priv->mmio_map->handle)
+#define I830_ADDR(reg) (I830_BASE(reg) + reg)
+#define I830_DEREF(reg) *(__volatile__ int *)I830_ADDR(reg)
+#define I830_READ(reg) I830_DEREF(reg)
+#define I830_WRITE(reg,val) do { I830_DEREF(reg) = val; } while (0)
+#define I830_DEREF16(reg) *(__volatile__ u16 *)I830_ADDR(reg)
+#define I830_READ16(reg) I830_DEREF16(reg)
+#define I830_WRITE16(reg,val) do { I830_DEREF16(reg) = val; } while (0)
+
+#define GFX_OP_USER_INTERRUPT ((0<<29)|(2<<23))
+#define GFX_OP_BREAKPOINT_INTERRUPT ((0<<29)|(1<<23))
+#define CMD_REPORT_HEAD (7<<23)
+#define CMD_STORE_DWORD_IDX ((0x21<<23) | 0x1)
+#define CMD_OP_BATCH_BUFFER ((0x0<<29)|(0x30<<23)|0x1)
+
+#define INST_PARSER_CLIENT 0x00000000
+#define INST_OP_FLUSH 0x02000000
+#define INST_FLUSH_MAP_CACHE 0x00000001
+
+
+#define BB1_START_ADDR_MASK (~0x7)
+#define BB1_PROTECTED (1<<0)
+#define BB1_UNPROTECTED (0<<0)
+#define BB2_END_ADDR_MASK (~0x7)
+
+#define I830REG_HWSTAM 0x02098
+#define I830REG_INT_IDENTITY_R 0x020a4
+#define I830REG_INT_MASK_R 0x020a8
+#define I830REG_INT_ENABLE_R 0x020a0
+
+#define LP_RING 0x2030
+#define HP_RING 0x2040
+#define RING_TAIL 0x00
+#define TAIL_ADDR 0x000FFFF8
+#define RING_HEAD 0x04
+#define HEAD_WRAP_COUNT 0xFFE00000
+#define HEAD_WRAP_ONE 0x00200000
+#define HEAD_ADDR 0x001FFFFC
+#define RING_START 0x08
+#define START_ADDR 0x00FFFFF8
+#define RING_LEN 0x0C
+#define RING_NR_PAGES 0x000FF000
+#define RING_REPORT_MASK 0x00000006
+#define RING_REPORT_64K 0x00000002
+#define RING_REPORT_128K 0x00000004
+#define RING_NO_REPORT 0x00000000
+#define RING_VALID_MASK 0x00000001
+#define RING_VALID 0x00000001
+#define RING_INVALID 0x00000000
+
+#define GFX_OP_SCISSOR ((0x3<<29)|(0x1c<<24)|(0x10<<19))
+#define SC_UPDATE_SCISSOR (0x1<<1)
+#define SC_ENABLE_MASK (0x1<<0)
+#define SC_ENABLE (0x1<<0)
+
+#define GFX_OP_SCISSOR_INFO ((0x3<<29)|(0x1d<<24)|(0x81<<16)|(0x1))
+#define SCI_YMIN_MASK (0xffff<<16)
+#define SCI_XMIN_MASK (0xffff<<0)
+#define SCI_YMAX_MASK (0xffff<<16)
+#define SCI_XMAX_MASK (0xffff<<0)
+
+#define GFX_OP_SCISSOR_ENABLE ((0x3<<29)|(0x1c<<24)|(0x10<<19))
+#define GFX_OP_SCISSOR_RECT ((0x3<<29)|(0x1d<<24)|(0x81<<16)|1)
+#define GFX_OP_COLOR_FACTOR ((0x3<<29)|(0x1d<<24)|(0x1<<16)|0x0)
+#define GFX_OP_STIPPLE ((0x3<<29)|(0x1d<<24)|(0x83<<16))
+#define GFX_OP_MAP_INFO ((0x3<<29)|(0x1d<<24)|0x4)
+#define GFX_OP_DESTBUFFER_VARS ((0x3<<29)|(0x1d<<24)|(0x85<<16)|0x0)
+#define GFX_OP_DRAWRECT_INFO ((0x3<<29)|(0x1d<<24)|(0x80<<16)|(0x3))
+#define GFX_OP_PRIMITIVE ((0x3<<29)|(0x1f<<24))
+
+#define CMD_OP_DESTBUFFER_INFO ((0x3<<29)|(0x1d<<24)|(0x8e<<16)|1)
+
+
+#define BR00_BITBLT_CLIENT 0x40000000
+#define BR00_OP_COLOR_BLT 0x10000000
+#define BR00_OP_SRC_COPY_BLT 0x10C00000
+#define BR13_SOLID_PATTERN 0x80000000
+
+#define BUF_3D_ID_COLOR_BACK (0x3<<24)
+#define BUF_3D_ID_DEPTH (0x7<<24)
+#define BUF_3D_USE_FENCE (1<<23)
+#define BUF_3D_PITCH(x) (((x)/4)<<2)
+
+#define CMD_OP_MAP_PALETTE_LOAD ((3<<29)|(0x1d<<24)|(0x82<<16)|255)
+#define MAP_PALETTE_NUM(x) ((x<<8) & (1<<8))
+#define MAP_PALETTE_BOTH (1<<11)
+
+#define XY_COLOR_BLT_CMD ((2<<29)|(0x50<<22)|0x4)
+#define XY_COLOR_BLT_WRITE_ALPHA (1<<21)
+#define XY_COLOR_BLT_WRITE_RGB (1<<20)
+
+#define XY_SRC_COPY_BLT_CMD ((2<<29)|(0x53<<22)|6)
+#define XY_SRC_COPY_BLT_WRITE_ALPHA (1<<21)
+#define XY_SRC_COPY_BLT_WRITE_RGB (1<<20)
+
+#define MI_BATCH_BUFFER ((0x30<<23)|1)
+#define MI_BATCH_NON_SECURE (1)
+
+
+#endif
+
drm_mga_texture_regs_t *tex = &sarea_priv->tex_state[0];
DMA_LOCALS;
+/* printk("mga_g400_emit_tex0 %x %x %x\n", tex->texorg, */
+/* tex->texctl, tex->texctl2); */
+
BEGIN_DMA( 6 );
DMA_BLOCK( MGA_TEXCTL2, tex->texctl2 | MGA_G400_TC2_MAGIC,
drm_mga_texture_regs_t *tex = &sarea_priv->tex_state[1];
DMA_LOCALS;
+/* printk("mga_g400_emit_tex1 %x %x %x\n", tex->texorg, */
+/* tex->texctl, tex->texctl2); */
+
BEGIN_DMA( 5 );
DMA_BLOCK( MGA_TEXCTL2, (tex->texctl2 |
unsigned int pipe = sarea_priv->warp_pipe;
DMA_LOCALS;
+/* printk("mga_g400_emit_pipe %x\n", pipe); */
+
BEGIN_DMA( 10 );
DMA_BLOCK( MGA_WIADDR2, MGA_WMODE_SUSPEND,
#define DRIVER_NAME "r128"
#define DRIVER_DESC "ATI Rage 128"
-#define DRIVER_DATE "20010405"
+#define DRIVER_DATE "20010917"
#define DRIVER_MAJOR 2
-#define DRIVER_MINOR 1
-#define DRIVER_PATCHLEVEL 6
+#define DRIVER_MINOR 2
+#define DRIVER_PATCHLEVEL 0
#define DRIVER_IOCTLS \
[DRM_IOCTL_NR(DRM_IOCTL_DMA)] = { r128_cce_buffers, 1, 0 }, \
{
drm_file_t *priv = filp->private_data;
drm_device_t *dev = priv->dev;
+ drm_r128_private_t *dev_priv = dev->dev_private;
+ drm_device_dma_t *dma = dev->dma;
+ drm_buf_t *buf;
+ drm_r128_buf_priv_t *buf_priv;
+ drm_r128_indirect_t indirect;
+#if 0
+ RING_LOCALS;
+#endif
LOCK_TEST_WITH_RETURN( dev );
- /* Indirect buffer firing is not supported at this time.
+ if ( !dev_priv ) {
+ DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ );
+ return -EINVAL;
+ }
+
+ if ( copy_from_user( &indirect, (drm_r128_indirect_t *)arg,
+ sizeof(indirect) ) )
+ return -EFAULT;
+
+ DRM_DEBUG( "indirect: idx=%d s=%d e=%d d=%d\n",
+ indirect.idx, indirect.start,
+ indirect.end, indirect.discard );
+
+ if ( indirect.idx < 0 || indirect.idx >= dma->buf_count ) {
+ DRM_ERROR( "buffer index %d (of %d max)\n",
+ indirect.idx, dma->buf_count - 1 );
+ return -EINVAL;
+ }
+
+ buf = dma->buflist[indirect.idx];
+ buf_priv = buf->dev_private;
+
+ if ( buf->pid != current->pid ) {
+ DRM_ERROR( "process %d using buffer owned by %d\n",
+ current->pid, buf->pid );
+ return -EINVAL;
+ }
+ if ( buf->pending ) {
+ DRM_ERROR( "sending pending buffer %d\n", indirect.idx );
+ return -EINVAL;
+ }
+
+ if ( indirect.start < buf->used ) {
+ DRM_ERROR( "reusing indirect: start=0x%x actual=0x%x\n",
+ indirect.start, buf->used );
+ return -EINVAL;
+ }
+
+ RING_SPACE_TEST_WITH_RETURN( dev_priv );
+ VB_AGE_TEST_WITH_RETURN( dev_priv );
+
+ buf->used = indirect.end;
+ buf_priv->discard = indirect.discard;
+
+#if 0
+ /* Wait for the 3D stream to idle before the indirect buffer
+ * containing 2D acceleration commands is processed.
*/
- return -EINVAL;
+ BEGIN_RING( 2 );
+ RADEON_WAIT_UNTIL_3D_IDLE();
+ ADVANCE_RING();
+#endif
+
+ /* Dispatch the indirect buffer full of commands from the
+ * X server. This is insecure and is thus only available to
+ * privileged clients.
+ */
+ r128_cce_dispatch_indirect( dev, buf, indirect.start, indirect.end );
+
+ return 0;
}
* and screwing with the clear operation.
*/
dev_priv->depth_clear.rb3d_cntl = (RADEON_PLANE_MASK_ENABLE |
- RADEON_Z_ENABLE |
(dev_priv->color_fmt << 10) |
- RADEON_ZBLOCK16);
+ (1<<15));
- dev_priv->depth_clear.rb3d_zstencilcntl = (dev_priv->depth_fmt |
- RADEON_Z_TEST_ALWAYS |
- RADEON_STENCIL_TEST_ALWAYS |
- RADEON_STENCIL_S_FAIL_KEEP |
- RADEON_STENCIL_ZPASS_KEEP |
- RADEON_STENCIL_ZFAIL_KEEP |
- RADEON_Z_WRITE_ENABLE);
+ dev_priv->depth_clear.rb3d_zstencilcntl =
+ (dev_priv->depth_fmt |
+ RADEON_Z_TEST_ALWAYS |
+ RADEON_STENCIL_TEST_ALWAYS |
+ RADEON_STENCIL_S_FAIL_REPLACE |
+ RADEON_STENCIL_ZPASS_REPLACE |
+ RADEON_STENCIL_ZFAIL_REPLACE |
+ RADEON_Z_WRITE_ENABLE);
dev_priv->depth_clear.se_cntl = (RADEON_FFACE_CULL_CW |
RADEON_BFACE_SOLID |
radeon_cp_load_microcode( dev_priv );
radeon_cp_init_ring_buffer( dev, dev_priv );
-#if ROTATE_BUFS
dev_priv->last_buf = 0;
-#endif
dev->dev_private = (void *)dev_priv;
* Fullscreen mode
*/
-static int radeon_do_init_pageflip( drm_device_t *dev )
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
- DRM_DEBUG( "%s\n", __FUNCTION__ );
-
- dev_priv->crtc_offset = RADEON_READ( RADEON_CRTC_OFFSET );
- dev_priv->crtc_offset_cntl = RADEON_READ( RADEON_CRTC_OFFSET_CNTL );
-
- RADEON_WRITE( RADEON_CRTC_OFFSET, dev_priv->front_offset );
- RADEON_WRITE( RADEON_CRTC_OFFSET_CNTL,
- dev_priv->crtc_offset_cntl |
- RADEON_CRTC_OFFSET_FLIP_CNTL );
-
- dev_priv->page_flipping = 1;
- dev_priv->current_page = 0;
-
- return 0;
-}
-
-int radeon_do_cleanup_pageflip( drm_device_t *dev )
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
- DRM_DEBUG( "%s\n", __FUNCTION__ );
-
- RADEON_WRITE( RADEON_CRTC_OFFSET, dev_priv->crtc_offset );
- RADEON_WRITE( RADEON_CRTC_OFFSET_CNTL, dev_priv->crtc_offset_cntl );
-
- dev_priv->page_flipping = 0;
- dev_priv->current_page = 0;
-
- return 0;
-}
-
+/* KW: Deprecated to say the least:
+ */
int radeon_fullscreen( struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg )
{
- drm_file_t *priv = filp->private_data;
- drm_device_t *dev = priv->dev;
- drm_radeon_fullscreen_t fs;
-
- LOCK_TEST_WITH_RETURN( dev );
-
- if ( copy_from_user( &fs, (drm_radeon_fullscreen_t *)arg,
- sizeof(fs) ) )
- return -EFAULT;
-
- switch ( fs.func ) {
- case RADEON_INIT_FULLSCREEN:
- return radeon_do_init_pageflip( dev );
- case RADEON_CLEANUP_FULLSCREEN:
- return radeon_do_cleanup_pageflip( dev );
- }
-
- return -EINVAL;
+ return 0;
}
/* ================================================================
* Freelist management
*/
-#define RADEON_BUFFER_USED 0xffffffff
-#define RADEON_BUFFER_FREE 0
-
-#if 0
-static int radeon_freelist_init( drm_device_t *dev )
-{
- drm_device_dma_t *dma = dev->dma;
- drm_radeon_private_t *dev_priv = dev->dev_private;
- drm_buf_t *buf;
- drm_radeon_buf_priv_t *buf_priv;
- drm_radeon_freelist_t *entry;
- int i;
-
- dev_priv->head = DRM(alloc)( sizeof(drm_radeon_freelist_t),
- DRM_MEM_DRIVER );
- if ( dev_priv->head == NULL )
- return -ENOMEM;
-
- memset( dev_priv->head, 0, sizeof(drm_radeon_freelist_t) );
- dev_priv->head->age = RADEON_BUFFER_USED;
-
- for ( i = 0 ; i < dma->buf_count ; i++ ) {
- buf = dma->buflist[i];
- buf_priv = buf->dev_private;
-
- entry = DRM(alloc)( sizeof(drm_radeon_freelist_t),
- DRM_MEM_DRIVER );
- if ( !entry ) return -ENOMEM;
-
- entry->age = RADEON_BUFFER_FREE;
- entry->buf = buf;
- entry->prev = dev_priv->head;
- entry->next = dev_priv->head->next;
- if ( !entry->next )
- dev_priv->tail = entry;
- buf_priv->discard = 0;
- buf_priv->dispatched = 0;
- buf_priv->list_entry = entry;
-
- dev_priv->head->next = entry;
-
- if ( dev_priv->head->next )
- dev_priv->head->next->prev = entry;
- }
-
- return 0;
-
-}
-#endif
+/* Original comment: FIXME: ROTATE_BUFS is a hack to cycle through
+ * bufs until freelist code is used. Note this hides a problem with
+ * the scratch register * (used to keep track of last buffer
+ * completed) being written to before * the last buffer has actually
+ * completed rendering.
+ *
+ * KW: It's also a good way to find free buffers quickly.
+ */
drm_buf_t *radeon_freelist_get( drm_device_t *dev )
{
drm_radeon_buf_priv_t *buf_priv;
drm_buf_t *buf;
int i, t;
-#if ROTATE_BUFS
int start;
-#endif
-
- /* FIXME: Optimize -- use freelist code */
- for ( i = 0 ; i < dma->buf_count ; i++ ) {
- buf = dma->buflist[i];
- buf_priv = buf->dev_private;
- if ( buf->pid == 0 ) {
- DRM_DEBUG( " ret buf=%d last=%d pid=0\n",
- buf->idx, dev_priv->last_buf );
- return buf;
- }
- DRM_DEBUG( " skipping buf=%d pid=%d\n",
- buf->idx, buf->pid );
- }
-
-#if ROTATE_BUFS
if ( ++dev_priv->last_buf >= dma->buf_count )
dev_priv->last_buf = 0;
+
start = dev_priv->last_buf;
-#endif
+
for ( t = 0 ; t < dev_priv->usec_timeout ; t++ ) {
-#if 0
- /* FIXME: Disable this for now */
- u32 done_age = dev_priv->scratch[RADEON_LAST_DISPATCH];
-#else
u32 done_age = RADEON_READ( RADEON_LAST_DISPATCH_REG );
-#endif
-#if ROTATE_BUFS
for ( i = start ; i < dma->buf_count ; i++ ) {
-#else
- for ( i = 0 ; i < dma->buf_count ; i++ ) {
-#endif
buf = dma->buflist[i];
buf_priv = buf->dev_private;
- if ( buf->pending && buf_priv->age <= done_age ) {
- /* The buffer has been processed, so it
- * can now be used.
- */
+ if ( buf->pid == 0 || (buf->pending &&
+ buf_priv->age <= done_age) ) {
buf->pending = 0;
- DRM_DEBUG( " ret buf=%d last=%d age=%d done=%d\n", buf->idx, dev_priv->last_buf, buf_priv->age, done_age );
return buf;
}
- DRM_DEBUG( " skipping buf=%d age=%d done=%d\n",
- buf->idx, buf_priv->age,
- done_age );
-#if ROTATE_BUFS
start = 0;
-#endif
}
udelay( 1 );
}
void radeon_freelist_reset( drm_device_t *dev )
{
drm_device_dma_t *dma = dev->dma;
-#if ROTATE_BUFS
drm_radeon_private_t *dev_priv = dev->dev_private;
-#endif
int i;
-#if ROTATE_BUFS
dev_priv->last_buf = 0;
-#endif
for ( i = 0 ; i < dma->buf_count ; i++ ) {
drm_buf_t *buf = dma->buflist[i];
drm_radeon_buf_priv_t *buf_priv = buf->dev_private;
*
* Copyright 2000 Precision Insight, Inc., Cedar Park, Texas.
* Copyright 2000 VA Linux Systems, Inc., Fremont, California.
+ * Copyright 2002 Tungsten Graphics, Inc., Cedar Park, Texas.
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* Authors:
* Kevin E. Martin <martin@valinux.com>
* Gareth Hughes <gareth@valinux.com>
+ * Keith Whitwell <keith_whitwell@yahoo.com>
*/
#ifndef __RADEON_DRM_H__
#ifndef __RADEON_SAREA_DEFINES__
#define __RADEON_SAREA_DEFINES__
-/* What needs to be changed for the current vertex buffer?
+/* Old style state flags, required for sarea interface (1.1 and 1.2
+ * clears) and 1.2 drm_vertex2 ioctl.
*/
#define RADEON_UPLOAD_CONTEXT 0x00000001
#define RADEON_UPLOAD_VERTFMT 0x00000002
#define RADEON_UPLOAD_TEX2IMAGES 0x00004000
#define RADEON_UPLOAD_CLIPRECTS 0x00008000 /* handled client-side */
#define RADEON_REQUIRE_QUIESCENCE 0x00010000
-#define RADEON_UPLOAD_ALL 0x0001ffff
+#define RADEON_UPLOAD_ZBIAS 0x00020000 /* version 1.2 and newer */
+#define RADEON_UPLOAD_ALL 0x003effff
+#define RADEON_UPLOAD_CONTEXT_ALL 0x003e01ff
+
+
+/* New style per-packet identifiers for use in cmd_buffer ioctl with
+ * the RADEON_EMIT_PACKET command. Comments relate new packets to old
+ * state bits and the packet size:
+ */
+#define RADEON_EMIT_PP_MISC 0 /* context/7 */
+#define RADEON_EMIT_PP_CNTL 1 /* context/3 */
+#define RADEON_EMIT_RB3D_COLORPITCH 2 /* context/1 */
+#define RADEON_EMIT_RE_LINE_PATTERN 3 /* line/2 */
+#define RADEON_EMIT_SE_LINE_WIDTH 4 /* line/1 */
+#define RADEON_EMIT_PP_LUM_MATRIX 5 /* bumpmap/1 */
+#define RADEON_EMIT_PP_ROT_MATRIX_0 6 /* bumpmap/2 */
+#define RADEON_EMIT_RB3D_STENCILREFMASK 7 /* masks/3 */
+#define RADEON_EMIT_SE_VPORT_XSCALE 8 /* viewport/6 */
+#define RADEON_EMIT_SE_CNTL 9 /* setup/2 */
+#define RADEON_EMIT_SE_CNTL_STATUS 10 /* setup/1 */
+#define RADEON_EMIT_RE_MISC 11 /* misc/1 */
+#define RADEON_EMIT_PP_TXFILTER_0 12 /* tex0/6 */
+#define RADEON_EMIT_PP_BORDER_COLOR_0 13 /* tex0/1 */
+#define RADEON_EMIT_PP_TXFILTER_1 14 /* tex1/6 */
+#define RADEON_EMIT_PP_BORDER_COLOR_1 15 /* tex1/1 */
+#define RADEON_EMIT_PP_TXFILTER_2 16 /* tex2/6 */
+#define RADEON_EMIT_PP_BORDER_COLOR_2 17 /* tex2/1 */
+#define RADEON_EMIT_SE_ZBIAS_FACTOR 18 /* zbias/2 */
+#define RADEON_EMIT_SE_TCL_OUTPUT_VTX_FMT 19 /* tcl/11 */
+#define RADEON_EMIT_SE_TCL_MATERIAL_EMMISSIVE_RED 20 /* material/17 */
+#define RADEON_MAX_STATE_PACKETS 21
+
+
+/* Commands understood by cmd_buffer ioctl. More can be added but
+ * obviously these can't be removed or changed:
+ */
+#define RADEON_CMD_PACKET 1 /* emit one of the register packets above */
+#define RADEON_CMD_SCALARS 2 /* emit scalar data */
+#define RADEON_CMD_VECTORS 3 /* emit vector data */
+#define RADEON_CMD_DMA_DISCARD 4 /* discard current dma buf */
+#define RADEON_CMD_PACKET3 5 /* emit hw packet */
+#define RADEON_CMD_PACKET3_CLIP 6 /* emit hw packet wrapped in cliprects */
+
+
+typedef union {
+ int i;
+ struct {
+ char cmd_type, pad0, pad1, pad2;
+ } header;
+ struct {
+ char cmd_type, packet_id, pad0, pad1;
+ } packet;
+ struct {
+ char cmd_type, offset, stride, count;
+ } scalars;
+ struct {
+ char cmd_type, offset, stride, count;
+ } vectors;
+ struct {
+ char cmd_type, buf_idx, pad0, pad1;
+ } dma;
+} drm_radeon_cmd_header_t;
+
#define RADEON_FRONT 0x1
#define RADEON_BACK 0x2
#define RADEON_DEPTH 0x4
+#define RADEON_STENCIL 0x8
/* Primitive types
*/
/* Byte offsets for indirect buffer data
*/
#define RADEON_INDEX_PRIM_OFFSET 20
-#define RADEON_HOSTDATA_BLIT_OFFSET 32
#define RADEON_SCRATCH_REG_OFFSET 32
-/* Keep these small for testing
- */
#define RADEON_NR_SAREA_CLIPRECTS 12
/* There are 2 heaps (local/AGP). Each region within a heap is a
#define RADEON_NR_TEX_REGIONS 64
#define RADEON_LOG_TEX_GRANULARITY 16
-#define RADEON_MAX_TEXTURE_LEVELS 11
+#define RADEON_MAX_TEXTURE_LEVELS 12
#define RADEON_MAX_TEXTURE_UNITS 3
#endif /* __RADEON_SAREA_DEFINES__ */
/* Setup state */
unsigned int se_cntl_status; /* 0x2140 */
-#ifdef TCL_ENABLE
- /* TCL state */
- radeon_color_regs_t se_tcl_material_emmissive; /* 0x2210 */
- radeon_color_regs_t se_tcl_material_ambient;
- radeon_color_regs_t se_tcl_material_diffuse;
- radeon_color_regs_t se_tcl_material_specular;
- unsigned int se_tcl_shininess;
- unsigned int se_tcl_output_vtx_fmt;
- unsigned int se_tcl_output_vtx_sel;
- unsigned int se_tcl_matrix_select_0;
- unsigned int se_tcl_matrix_select_1;
- unsigned int se_tcl_ucp_vert_blend_ctl;
- unsigned int se_tcl_texture_proc_ctl;
- unsigned int se_tcl_light_model_ctl;
- unsigned int se_tcl_per_light_ctl[4];
-#endif
-
/* Misc state */
unsigned int re_top_left; /* 0x26c0 */
unsigned int re_misc;
} drm_radeon_context_regs_t;
+typedef struct {
+ /* Zbias state */
+ unsigned int se_zbias_factor; /* 0x1dac */
+ unsigned int se_zbias_constant;
+} drm_radeon_context2_regs_t;
+
+
/* Setup registers for each texture unit
*/
typedef struct {
unsigned int pp_txcblend;
unsigned int pp_txablend;
unsigned int pp_tfactor;
-
unsigned int pp_border_color;
-
-#ifdef CUBIC_ENABLE
- unsigned int pp_cubic_faces;
- unsigned int pp_cubic_offset[5];
-#endif
} drm_radeon_texture_regs_t;
+typedef struct {
+ unsigned int start;
+ unsigned int finish;
+ unsigned int prim:8;
+ unsigned int stateidx:8;
+ unsigned int numverts:16; /* overloaded as offset/64 for elt prims */
+ unsigned int vc_format; /* vertex format */
+} drm_radeon_prim_t;
+
+
+typedef struct {
+ drm_radeon_context_regs_t context;
+ drm_radeon_texture_regs_t tex[RADEON_MAX_TEXTURE_UNITS];
+ drm_radeon_context2_regs_t context2;
+ unsigned int dirty;
+} drm_radeon_state_t;
+
+
typedef struct {
unsigned char next, prev;
unsigned char in_use;
} drm_radeon_tex_region_t;
typedef struct {
- /* The channel for communication of state information to the kernel
- * on firing a vertex buffer.
+ /* The channel for communication of state information to the
+ * kernel on firing a vertex buffer with either of the
+ * obsoleted vertex/index ioctls.
*/
drm_radeon_context_regs_t context_state;
drm_radeon_texture_regs_t tex_state[RADEON_MAX_TEXTURE_UNITS];
drm_radeon_tex_region_t tex_list[RADEON_NR_TEX_HEAPS][RADEON_NR_TEX_REGIONS+1];
int tex_age[RADEON_NR_TEX_HEAPS];
int ctx_owner;
+ int pfState; /* number of 3d windows (0,1,2ormore) */
+ int pfCurrentPage; /* which buffer is being displayed? */
} drm_radeon_sarea_t;
/* WARNING: If you change any of these defines, make sure to change the
* defines in the Xserver file (xf86drmRadeon.h)
+ *
+ * KW: actually it's illegal to change any of this (backwards compatibility).
*/
typedef struct drm_radeon_init {
enum {
unsigned int clear_color;
unsigned int clear_depth;
unsigned int color_mask;
- unsigned int depth_mask;
+ unsigned int depth_mask; /* misnamed field: should be stencil */
drm_radeon_clear_rect_t *depth_boxes;
} drm_radeon_clear_t;
int discard; /* Client finished with buffer? */
} drm_radeon_indices_t;
+/* v1.2 - obsoletes drm_radeon_vertex and drm_radeon_indices
+ * - allows multiple primitives and state changes in a single ioctl
+ * - supports driver change to emit native primitives
+ */
+typedef struct drm_radeon_vertex2 {
+ int idx; /* Index of vertex buffer */
+ int discard; /* Client finished with buffer? */
+ int nr_states;
+ drm_radeon_state_t *state;
+ int nr_prims;
+ drm_radeon_prim_t *prim;
+} drm_radeon_vertex2_t;
+
+/* v1.3 - obsoletes drm_radeon_vertex2
+ * - allows arbitarily large cliprect list
+ * - allows updating of tcl packet, vector and scalar state
+ * - allows memory-efficient description of state updates
+ * - allows state to be emitted without a primitive
+ * (for clears, ctx switches)
+ * - allows more than one dma buffer to be referenced per ioctl
+ * - supports tcl driver
+ * - may be extended in future versions with new cmd types, packets
+ */
+typedef struct drm_radeon_cmd_buffer {
+ int bufsz;
+ char *buf;
+ int nbox;
+ drm_clip_rect_t *boxes;
+} drm_radeon_cmd_buffer_t;
+
typedef struct drm_radeon_tex_image {
unsigned int x, y; /* Blit coordinates */
unsigned int width, height;
int discard;
} drm_radeon_indirect_t;
+
+/* 1.3: An ioctl to get parameters that aren't available to the 3d
+ * client any other way.
+ */
+#define RADEON_PARAM_AGP_BUFFER_OFFSET 0x1
+
+typedef struct drm_radeon_getparam {
+ int param;
+ int *value;
+} drm_radeon_getparam_t;
+
#endif
#define DRIVER_NAME "radeon"
#define DRIVER_DESC "ATI Radeon"
-#define DRIVER_DATE "20010405"
+#define DRIVER_DATE "20020521"
#define DRIVER_MAJOR 1
-#define DRIVER_MINOR 1
-#define DRIVER_PATCHLEVEL 1
+#define DRIVER_MINOR 3
+#define DRIVER_PATCHLEVEL 0
+/* Interface history:
+ *
+ * 1.1 - ??
+ * 1.2 - Add vertex2 ioctl (keith)
+ * - Add stencil capability to clear ioctl (gareth, keith)
+ * - Increase MAX_TEXTURE_LEVELS (brian)
+ * 1.3 - Add cmdbuf ioctl (keith)
+ * - Add support for new radeon packets (keith)
+ * - Add getparam ioctl (keith)
+ * - Add flip-buffers ioctl, deprecate fullscreen foo (keith).
+ */
#define DRIVER_IOCTLS \
[DRM_IOCTL_NR(DRM_IOCTL_DMA)] = { radeon_cp_buffers, 1, 0 }, \
[DRM_IOCTL_NR(DRM_IOCTL_RADEON_CP_INIT)] = { radeon_cp_init, 1, 1 }, \
[DRM_IOCTL_NR(DRM_IOCTL_RADEON_INDICES)] = { radeon_cp_indices, 1, 0 }, \
[DRM_IOCTL_NR(DRM_IOCTL_RADEON_TEXTURE)] = { radeon_cp_texture, 1, 0 }, \
[DRM_IOCTL_NR(DRM_IOCTL_RADEON_STIPPLE)] = { radeon_cp_stipple, 1, 0 }, \
- [DRM_IOCTL_NR(DRM_IOCTL_RADEON_INDIRECT)] = { radeon_cp_indirect, 1, 1 },
-
-
-#if 0
-/* GH: Count data sent to card via ring or vertex/indirect buffers.
- */
-#define __HAVE_COUNTERS 3
-#define __HAVE_COUNTER6 _DRM_STAT_IRQ
-#define __HAVE_COUNTER7 _DRM_STAT_PRIMARY
-#define __HAVE_COUNTER8 _DRM_STAT_SECONDARY
-#endif
+ [DRM_IOCTL_NR(DRM_IOCTL_RADEON_INDIRECT)] = { radeon_cp_indirect, 1, 1 }, \
+ [DRM_IOCTL_NR(DRM_IOCTL_RADEON_VERTEX2)] = { radeon_cp_vertex2, 1, 0 }, \
+ [DRM_IOCTL_NR(DRM_IOCTL_RADEON_CMDBUF)] = { radeon_cp_cmdbuf, 1, 0 }, \
+ [DRM_IOCTL_NR(DRM_IOCTL_RADEON_GETPARAM)] = { radeon_cp_getparam, 1, 0 }, \
+ [DRM_IOCTL_NR(DRM_IOCTL_RADEON_FLIP)] = { radeon_cp_flip, 1, 0 },
#include "drm_agpsupport.h"
drm_radeon_freelist_t *head;
drm_radeon_freelist_t *tail;
-/* FIXME: ROTATE_BUFS is a hask to cycle through bufs until freelist
- code is used. Note this hides a problem with the scratch register
- (used to keep track of last buffer completed) being written to before
- the last buffer has actually completed rendering. */
-#define ROTATE_BUFS 1
-#if ROTATE_BUFS
int last_buf;
-#endif
volatile u32 *scratch;
int usec_timeout;
typedef struct drm_radeon_buf_priv {
u32 age;
- int prim;
- int discard;
- int dispatched;
- drm_radeon_freelist_t *list_entry;
} drm_radeon_buf_priv_t;
/* radeon_cp.c */
unsigned int cmd, unsigned long arg );
extern int radeon_cp_indirect( struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg );
+extern int radeon_cp_vertex2( struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg );
+extern int radeon_cp_cmdbuf( struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg );
+extern int radeon_cp_getparam( struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg );
+extern int radeon_cp_flip( struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg );
+
/* Register definitions, register access macros and drmAddMap constants
# define RADEON_CRTC_OFFSET_FLIP_CNTL (1 << 16)
#define RADEON_RB3D_COLORPITCH 0x1c48
-#define RADEON_RB3D_DEPTHCLEARVALUE 0x1c30
-#define RADEON_RB3D_DEPTHXY_OFFSET 0x1c60
#define RADEON_DP_GUI_MASTER_CNTL 0x146c
# define RADEON_GMC_SRC_PITCH_OFFSET_CNTL (1 << 0)
# define RADEON_ROP_ENABLE (1 << 6)
# define RADEON_STENCIL_ENABLE (1 << 7)
# define RADEON_Z_ENABLE (1 << 8)
-# define RADEON_DEPTH_XZ_OFFEST_ENABLE (1 << 9)
-# define RADEON_ZBLOCK8 (0 << 15)
-# define RADEON_ZBLOCK16 (1 << 15)
#define RADEON_RB3D_DEPTHOFFSET 0x1c24
#define RADEON_RB3D_PLANEMASK 0x1d84
#define RADEON_RB3D_STENCILREFMASK 0x1d7c
# define RADEON_Z_TEST_MASK (7 << 4)
# define RADEON_Z_TEST_ALWAYS (7 << 4)
# define RADEON_STENCIL_TEST_ALWAYS (7 << 12)
-# define RADEON_STENCIL_S_FAIL_KEEP (0 << 16)
-# define RADEON_STENCIL_ZPASS_KEEP (0 << 20)
-# define RADEON_STENCIL_ZFAIL_KEEP (0 << 20)
+# define RADEON_STENCIL_S_FAIL_REPLACE (2 << 16)
+# define RADEON_STENCIL_ZPASS_REPLACE (2 << 20)
+# define RADEON_STENCIL_ZFAIL_REPLACE (2 << 24)
# define RADEON_Z_WRITE_ENABLE (1 << 30)
#define RADEON_RBBM_SOFT_RESET 0x00f0
# define RADEON_SOFT_RESET_CP (1 << 0)
#define RADEON_SE_CNTL_STATUS 0x2140
#define RADEON_SE_LINE_WIDTH 0x1db8
#define RADEON_SE_VPORT_XSCALE 0x1d98
+#define RADEON_SE_ZBIAS_FACTOR 0x1db0
+#define RADEON_SE_TCL_MATERIAL_EMMISSIVE_RED 0x2210
+#define RADEON_SE_TCL_OUTPUT_VTX_FMT 0x2254
+#define RADEON_SE_TCL_VECTOR_INDX_REG 0x2200
+# define RADEON_VEC_INDX_OCTWORD_STRIDE_SHIFT 16
+# define RADEON_VEC_INDX_DWORD_COUNT_SHIFT 28
+#define RADEON_SE_TCL_VECTOR_DATA_REG 0x2204
+#define RADEON_SE_TCL_SCALAR_INDX_REG 0x2208
+# define RADEON_SCAL_INDX_DWORD_STRIDE_SHIFT 16
+#define RADEON_SE_TCL_SCALAR_DATA_REG 0x220C
#define RADEON_SURFACE_ACCESS_FLAGS 0x0bf8
#define RADEON_SURFACE_ACCESS_CLR 0x0bfc
#define RADEON_SURFACE_CNTL 0x0b00
#define RADEON_CP_PACKET3 0xC0000000
# define RADEON_3D_RNDR_GEN_INDX_PRIM 0x00002300
# define RADEON_WAIT_FOR_IDLE 0x00002600
+# define RADEON_3D_DRAW_VBUF 0x00002800
# define RADEON_3D_DRAW_IMMD 0x00002900
-# define RADEON_3D_CLEAR_ZMASK 0x00003200
+# define RADEON_3D_DRAW_INDX 0x00002A00
+# define RADEON_3D_LOAD_VBPNTR 0x00002F00
# define RADEON_CNTL_HOSTDATA_BLT 0x00009400
# define RADEON_CNTL_PAINT_MULTI 0x00009A00
# define RADEON_CNTL_BITBLT_MULTI 0x00009B00
#define RADEON_CP_PACKET1_REG1_MASK 0x003ff800
#define RADEON_VTX_Z_PRESENT (1 << 31)
+#define RADEON_VTX_PKCOLOR_PRESENT (1 << 3)
#define RADEON_PRIM_TYPE_NONE (0 << 0)
#define RADEON_PRIM_TYPE_POINT (1 << 0)
#define RADEON_PRIM_TYPE_RECT_LIST (8 << 0)
#define RADEON_PRIM_TYPE_3VRT_POINT_LIST (9 << 0)
#define RADEON_PRIM_TYPE_3VRT_LINE_LIST (10 << 0)
+#define RADEON_PRIM_TYPE_MASK 0xf
#define RADEON_PRIM_WALK_IND (1 << 4)
#define RADEON_PRIM_WALK_LIST (2 << 4)
#define RADEON_PRIM_WALK_RING (3 << 4)
#define RADEON_VERBOSE 0
-#define RING_LOCALS int write; unsigned int mask; volatile u32 *ring;
+#define RING_LOCALS int write, _nr; unsigned int mask; volatile u32 *ring;
#define BEGIN_RING( n ) do { \
if ( RADEON_VERBOSE ) { \
if ( dev_priv->ring.space <= (n) * sizeof(u32) ) { \
radeon_wait_ring( dev_priv, (n) * sizeof(u32) ); \
} \
- dev_priv->ring.space -= (n) * sizeof(u32); \
+ _nr = n; dev_priv->ring.space -= (n) * sizeof(u32); \
ring = dev_priv->ring.start; \
write = dev_priv->ring.tail; \
mask = dev_priv->ring.tail_mask; \
write, dev_priv->ring.tail ); \
} \
radeon_flush_write_combine(); \
- dev_priv->ring.tail = write; \
+ if (((dev_priv->ring.tail + _nr) & mask) != write) { \
+ DRM_ERROR( \
+ "ADVANCE_RING(): mismatch: nr: %x write: %x\n", \
+ ((dev_priv->ring.tail + _nr) & mask), \
+ write); \
+ } else \
+ dev_priv->ring.tail = write; \
RADEON_WRITE( RADEON_CP_RB_WPTR, write ); \
} while (0)
write &= mask; \
} while (0)
+#define OUT_RING_REG( reg, val ) do { \
+ OUT_RING( CP_PACKET0( reg, 0 ) ); \
+ OUT_RING( val ); \
+} while (0)
+
#define RADEON_PERFORMANCE_BOXES 0
#endif /* __RADEON_DRV_H__ */
box->x1, box->y1, box->x2, box->y2 );
BEGIN_RING( 4 );
-
OUT_RING( CP_PACKET0( RADEON_RE_TOP_LEFT, 0 ) );
OUT_RING( (box->y1 << 16) | box->x1 );
-
OUT_RING( CP_PACKET0( RADEON_RE_WIDTH_HEIGHT, 0 ) );
- OUT_RING( ((box->y2 - 1) << 16) | (box->x2 - 1) );
-
- ADVANCE_RING();
-}
-
-static inline void radeon_emit_context( drm_radeon_private_t *dev_priv )
-{
- drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
- drm_radeon_context_regs_t *ctx = &sarea_priv->context_state;
- RING_LOCALS;
- DRM_DEBUG( " %s\n", __FUNCTION__ );
-
- BEGIN_RING( 14 );
-
- OUT_RING( CP_PACKET0( RADEON_PP_MISC, 6 ) );
- OUT_RING( ctx->pp_misc );
- OUT_RING( ctx->pp_fog_color );
- OUT_RING( ctx->re_solid_color );
- OUT_RING( ctx->rb3d_blendcntl );
- OUT_RING( ctx->rb3d_depthoffset );
- OUT_RING( ctx->rb3d_depthpitch );
- OUT_RING( ctx->rb3d_zstencilcntl );
-
- OUT_RING( CP_PACKET0( RADEON_PP_CNTL, 2 ) );
- OUT_RING( ctx->pp_cntl );
- OUT_RING( ctx->rb3d_cntl );
- OUT_RING( ctx->rb3d_coloroffset );
-
- OUT_RING( CP_PACKET0( RADEON_RB3D_COLORPITCH, 0 ) );
- OUT_RING( ctx->rb3d_colorpitch );
-
- ADVANCE_RING();
-}
-
-static inline void radeon_emit_vertfmt( drm_radeon_private_t *dev_priv )
-{
- drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
- drm_radeon_context_regs_t *ctx = &sarea_priv->context_state;
- RING_LOCALS;
- DRM_DEBUG( " %s\n", __FUNCTION__ );
-
- BEGIN_RING( 2 );
-
- OUT_RING( CP_PACKET0( RADEON_SE_COORD_FMT, 0 ) );
- OUT_RING( ctx->se_coord_fmt );
-
- ADVANCE_RING();
-}
-
-static inline void radeon_emit_line( drm_radeon_private_t *dev_priv )
-{
- drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
- drm_radeon_context_regs_t *ctx = &sarea_priv->context_state;
- RING_LOCALS;
- DRM_DEBUG( " %s\n", __FUNCTION__ );
-
- BEGIN_RING( 5 );
-
- OUT_RING( CP_PACKET0( RADEON_RE_LINE_PATTERN, 1 ) );
- OUT_RING( ctx->re_line_pattern );
- OUT_RING( ctx->re_line_state );
-
- OUT_RING( CP_PACKET0( RADEON_SE_LINE_WIDTH, 0 ) );
- OUT_RING( ctx->se_line_width );
-
- ADVANCE_RING();
-}
-
-static inline void radeon_emit_bumpmap( drm_radeon_private_t *dev_priv )
-{
- drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
- drm_radeon_context_regs_t *ctx = &sarea_priv->context_state;
- RING_LOCALS;
- DRM_DEBUG( " %s\n", __FUNCTION__ );
-
- BEGIN_RING( 5 );
-
- OUT_RING( CP_PACKET0( RADEON_PP_LUM_MATRIX, 0 ) );
- OUT_RING( ctx->pp_lum_matrix );
-
- OUT_RING( CP_PACKET0( RADEON_PP_ROT_MATRIX_0, 1 ) );
- OUT_RING( ctx->pp_rot_matrix_0 );
- OUT_RING( ctx->pp_rot_matrix_1 );
-
- ADVANCE_RING();
-}
-
-static inline void radeon_emit_masks( drm_radeon_private_t *dev_priv )
-{
- drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
- drm_radeon_context_regs_t *ctx = &sarea_priv->context_state;
- RING_LOCALS;
- DRM_DEBUG( " %s\n", __FUNCTION__ );
-
- BEGIN_RING( 4 );
-
- OUT_RING( CP_PACKET0( RADEON_RB3D_STENCILREFMASK, 2 ) );
- OUT_RING( ctx->rb3d_stencilrefmask );
- OUT_RING( ctx->rb3d_ropcntl );
- OUT_RING( ctx->rb3d_planemask );
-
- ADVANCE_RING();
-}
-
-static inline void radeon_emit_viewport( drm_radeon_private_t *dev_priv )
-{
- drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
- drm_radeon_context_regs_t *ctx = &sarea_priv->context_state;
- RING_LOCALS;
- DRM_DEBUG( " %s\n", __FUNCTION__ );
-
- BEGIN_RING( 7 );
-
- OUT_RING( CP_PACKET0( RADEON_SE_VPORT_XSCALE, 5 ) );
- OUT_RING( ctx->se_vport_xscale );
- OUT_RING( ctx->se_vport_xoffset );
- OUT_RING( ctx->se_vport_yscale );
- OUT_RING( ctx->se_vport_yoffset );
- OUT_RING( ctx->se_vport_zscale );
- OUT_RING( ctx->se_vport_zoffset );
-
- ADVANCE_RING();
-}
-
-static inline void radeon_emit_setup( drm_radeon_private_t *dev_priv )
-{
- drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
- drm_radeon_context_regs_t *ctx = &sarea_priv->context_state;
- RING_LOCALS;
- DRM_DEBUG( " %s\n", __FUNCTION__ );
-
- BEGIN_RING( 4 );
-
- OUT_RING( CP_PACKET0( RADEON_SE_CNTL, 0 ) );
- OUT_RING( ctx->se_cntl );
- OUT_RING( CP_PACKET0( RADEON_SE_CNTL_STATUS, 0 ) );
- OUT_RING( ctx->se_cntl_status );
-
- ADVANCE_RING();
-}
-
-static inline void radeon_emit_tcl( drm_radeon_private_t *dev_priv )
-{
-#ifdef TCL_ENABLE
- drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
- drm_radeon_context_regs_t *ctx = &sarea_priv->context_state;
- RING_LOCALS;
- DRM_DEBUG( " %s\n", __FUNCTION__ );
-
- BEGIN_RING( 29 );
-
- OUT_RING( CP_PACKET0( RADEON_SE_TCL_MATERIAL_EMMISSIVE_RED, 27 ) );
- OUT_RING( ctx->se_tcl_material_emmissive.red );
- OUT_RING( ctx->se_tcl_material_emmissive.green );
- OUT_RING( ctx->se_tcl_material_emmissive.blue );
- OUT_RING( ctx->se_tcl_material_emmissive.alpha );
- OUT_RING( ctx->se_tcl_material_ambient.red );
- OUT_RING( ctx->se_tcl_material_ambient.green );
- OUT_RING( ctx->se_tcl_material_ambient.blue );
- OUT_RING( ctx->se_tcl_material_ambient.alpha );
- OUT_RING( ctx->se_tcl_material_diffuse.red );
- OUT_RING( ctx->se_tcl_material_diffuse.green );
- OUT_RING( ctx->se_tcl_material_diffuse.blue );
- OUT_RING( ctx->se_tcl_material_diffuse.alpha );
- OUT_RING( ctx->se_tcl_material_specular.red );
- OUT_RING( ctx->se_tcl_material_specular.green );
- OUT_RING( ctx->se_tcl_material_specular.blue );
- OUT_RING( ctx->se_tcl_material_specular.alpha );
- OUT_RING( ctx->se_tcl_shininess );
- OUT_RING( ctx->se_tcl_output_vtx_fmt );
- OUT_RING( ctx->se_tcl_output_vtx_sel );
- OUT_RING( ctx->se_tcl_matrix_select_0 );
- OUT_RING( ctx->se_tcl_matrix_select_1 );
- OUT_RING( ctx->se_tcl_ucp_vert_blend_ctl );
- OUT_RING( ctx->se_tcl_texture_proc_ctl );
- OUT_RING( ctx->se_tcl_light_model_ctl );
- for ( i = 0 ; i < 4 ; i++ ) {
- OUT_RING( ctx->se_tcl_per_light_ctl[i] );
- }
-
- ADVANCE_RING();
-#else
- DRM_ERROR( "TCL not enabled!\n" );
-#endif
-}
-
-static inline void radeon_emit_misc( drm_radeon_private_t *dev_priv )
-{
- drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
- drm_radeon_context_regs_t *ctx = &sarea_priv->context_state;
- RING_LOCALS;
- DRM_DEBUG( " %s\n", __FUNCTION__ );
-
- BEGIN_RING( 2 );
-
- OUT_RING( CP_PACKET0( RADEON_RE_MISC, 0 ) );
- OUT_RING( ctx->re_misc );
-
- ADVANCE_RING();
-}
-
-static inline void radeon_emit_tex0( drm_radeon_private_t *dev_priv )
-{
- drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
- drm_radeon_texture_regs_t *tex = &sarea_priv->tex_state[0];
- RING_LOCALS;
- DRM_DEBUG( " %s: offset=0x%x\n", __FUNCTION__, tex->pp_txoffset );
-
- BEGIN_RING( 9 );
-
- OUT_RING( CP_PACKET0( RADEON_PP_TXFILTER_0, 5 ) );
- OUT_RING( tex->pp_txfilter );
- OUT_RING( tex->pp_txformat );
- OUT_RING( tex->pp_txoffset );
- OUT_RING( tex->pp_txcblend );
- OUT_RING( tex->pp_txablend );
- OUT_RING( tex->pp_tfactor );
-
- OUT_RING( CP_PACKET0( RADEON_PP_BORDER_COLOR_0, 0 ) );
- OUT_RING( tex->pp_border_color );
-
- ADVANCE_RING();
-}
-
-static inline void radeon_emit_tex1( drm_radeon_private_t *dev_priv )
-{
- drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
- drm_radeon_texture_regs_t *tex = &sarea_priv->tex_state[1];
- RING_LOCALS;
- DRM_DEBUG( " %s: offset=0x%x\n", __FUNCTION__, tex->pp_txoffset );
-
- BEGIN_RING( 9 );
-
- OUT_RING( CP_PACKET0( RADEON_PP_TXFILTER_1, 5 ) );
- OUT_RING( tex->pp_txfilter );
- OUT_RING( tex->pp_txformat );
- OUT_RING( tex->pp_txoffset );
- OUT_RING( tex->pp_txcblend );
- OUT_RING( tex->pp_txablend );
- OUT_RING( tex->pp_tfactor );
-
- OUT_RING( CP_PACKET0( RADEON_PP_BORDER_COLOR_1, 0 ) );
- OUT_RING( tex->pp_border_color );
-
+/* OUT_RING( ((box->y2 - 1) << 16) | (box->x2 - 1) );*/
+ OUT_RING( (box->y2 << 16) | box->x2 );
ADVANCE_RING();
}
-static inline void radeon_emit_tex2( drm_radeon_private_t *dev_priv )
+/* Emit 1.1 state
+ */
+static void radeon_emit_state( drm_radeon_private_t *dev_priv,
+ drm_radeon_context_regs_t *ctx,
+ drm_radeon_texture_regs_t *tex,
+ unsigned int dirty )
{
- drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
- drm_radeon_texture_regs_t *tex = &sarea_priv->tex_state[2];
RING_LOCALS;
- DRM_DEBUG( " %s\n", __FUNCTION__ );
-
- BEGIN_RING( 9 );
-
- OUT_RING( CP_PACKET0( RADEON_PP_TXFILTER_2, 5 ) );
- OUT_RING( tex->pp_txfilter );
- OUT_RING( tex->pp_txformat );
- OUT_RING( tex->pp_txoffset );
- OUT_RING( tex->pp_txcblend );
- OUT_RING( tex->pp_txablend );
- OUT_RING( tex->pp_tfactor );
-
- OUT_RING( CP_PACKET0( RADEON_PP_BORDER_COLOR_2, 0 ) );
- OUT_RING( tex->pp_border_color );
-
- ADVANCE_RING();
-}
-
-static inline void radeon_emit_state( drm_radeon_private_t *dev_priv )
-{
- drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
- unsigned int dirty = sarea_priv->dirty;
-
DRM_DEBUG( "%s: dirty=0x%08x\n", __FUNCTION__, dirty );
if ( dirty & RADEON_UPLOAD_CONTEXT ) {
- radeon_emit_context( dev_priv );
- sarea_priv->dirty &= ~RADEON_UPLOAD_CONTEXT;
+ BEGIN_RING( 14 );
+ OUT_RING( CP_PACKET0( RADEON_PP_MISC, 6 ) );
+ OUT_RING( ctx->pp_misc );
+ OUT_RING( ctx->pp_fog_color );
+ OUT_RING( ctx->re_solid_color );
+ OUT_RING( ctx->rb3d_blendcntl );
+ OUT_RING( ctx->rb3d_depthoffset );
+ OUT_RING( ctx->rb3d_depthpitch );
+ OUT_RING( ctx->rb3d_zstencilcntl );
+ OUT_RING( CP_PACKET0( RADEON_PP_CNTL, 2 ) );
+ OUT_RING( ctx->pp_cntl );
+ OUT_RING( ctx->rb3d_cntl );
+ OUT_RING( ctx->rb3d_coloroffset );
+ OUT_RING( CP_PACKET0( RADEON_RB3D_COLORPITCH, 0 ) );
+ OUT_RING( ctx->rb3d_colorpitch );
+ ADVANCE_RING();
}
if ( dirty & RADEON_UPLOAD_VERTFMT ) {
- radeon_emit_vertfmt( dev_priv );
- sarea_priv->dirty &= ~RADEON_UPLOAD_VERTFMT;
+ BEGIN_RING( 2 );
+ OUT_RING( CP_PACKET0( RADEON_SE_COORD_FMT, 0 ) );
+ OUT_RING( ctx->se_coord_fmt );
+ ADVANCE_RING();
}
if ( dirty & RADEON_UPLOAD_LINE ) {
- radeon_emit_line( dev_priv );
- sarea_priv->dirty &= ~RADEON_UPLOAD_LINE;
+ BEGIN_RING( 5 );
+ OUT_RING( CP_PACKET0( RADEON_RE_LINE_PATTERN, 1 ) );
+ OUT_RING( ctx->re_line_pattern );
+ OUT_RING( ctx->re_line_state );
+ OUT_RING( CP_PACKET0( RADEON_SE_LINE_WIDTH, 0 ) );
+ OUT_RING( ctx->se_line_width );
+ ADVANCE_RING();
}
if ( dirty & RADEON_UPLOAD_BUMPMAP ) {
- radeon_emit_bumpmap( dev_priv );
- sarea_priv->dirty &= ~RADEON_UPLOAD_BUMPMAP;
+ BEGIN_RING( 5 );
+ OUT_RING( CP_PACKET0( RADEON_PP_LUM_MATRIX, 0 ) );
+ OUT_RING( ctx->pp_lum_matrix );
+ OUT_RING( CP_PACKET0( RADEON_PP_ROT_MATRIX_0, 1 ) );
+ OUT_RING( ctx->pp_rot_matrix_0 );
+ OUT_RING( ctx->pp_rot_matrix_1 );
+ ADVANCE_RING();
}
if ( dirty & RADEON_UPLOAD_MASKS ) {
- radeon_emit_masks( dev_priv );
- sarea_priv->dirty &= ~RADEON_UPLOAD_MASKS;
+ BEGIN_RING( 4 );
+ OUT_RING( CP_PACKET0( RADEON_RB3D_STENCILREFMASK, 2 ) );
+ OUT_RING( ctx->rb3d_stencilrefmask );
+ OUT_RING( ctx->rb3d_ropcntl );
+ OUT_RING( ctx->rb3d_planemask );
+ ADVANCE_RING();
}
if ( dirty & RADEON_UPLOAD_VIEWPORT ) {
- radeon_emit_viewport( dev_priv );
- sarea_priv->dirty &= ~RADEON_UPLOAD_VIEWPORT;
+ BEGIN_RING( 7 );
+ OUT_RING( CP_PACKET0( RADEON_SE_VPORT_XSCALE, 5 ) );
+ OUT_RING( ctx->se_vport_xscale );
+ OUT_RING( ctx->se_vport_xoffset );
+ OUT_RING( ctx->se_vport_yscale );
+ OUT_RING( ctx->se_vport_yoffset );
+ OUT_RING( ctx->se_vport_zscale );
+ OUT_RING( ctx->se_vport_zoffset );
+ ADVANCE_RING();
}
if ( dirty & RADEON_UPLOAD_SETUP ) {
- radeon_emit_setup( dev_priv );
- sarea_priv->dirty &= ~RADEON_UPLOAD_SETUP;
- }
-
- if ( dirty & RADEON_UPLOAD_TCL ) {
-#ifdef TCL_ENABLE
- radeon_emit_tcl( dev_priv );
-#endif
- sarea_priv->dirty &= ~RADEON_UPLOAD_TCL;
+ BEGIN_RING( 4 );
+ OUT_RING( CP_PACKET0( RADEON_SE_CNTL, 0 ) );
+ OUT_RING( ctx->se_cntl );
+ OUT_RING( CP_PACKET0( RADEON_SE_CNTL_STATUS, 0 ) );
+ OUT_RING( ctx->se_cntl_status );
+ ADVANCE_RING();
}
if ( dirty & RADEON_UPLOAD_MISC ) {
- radeon_emit_misc( dev_priv );
- sarea_priv->dirty &= ~RADEON_UPLOAD_MISC;
+ BEGIN_RING( 2 );
+ OUT_RING( CP_PACKET0( RADEON_RE_MISC, 0 ) );
+ OUT_RING( ctx->re_misc );
+ ADVANCE_RING();
}
if ( dirty & RADEON_UPLOAD_TEX0 ) {
- radeon_emit_tex0( dev_priv );
- sarea_priv->dirty &= ~RADEON_UPLOAD_TEX0;
+ BEGIN_RING( 9 );
+ OUT_RING( CP_PACKET0( RADEON_PP_TXFILTER_0, 5 ) );
+ OUT_RING( tex[0].pp_txfilter );
+ OUT_RING( tex[0].pp_txformat );
+ OUT_RING( tex[0].pp_txoffset );
+ OUT_RING( tex[0].pp_txcblend );
+ OUT_RING( tex[0].pp_txablend );
+ OUT_RING( tex[0].pp_tfactor );
+ OUT_RING( CP_PACKET0( RADEON_PP_BORDER_COLOR_0, 0 ) );
+ OUT_RING( tex[0].pp_border_color );
+ ADVANCE_RING();
}
if ( dirty & RADEON_UPLOAD_TEX1 ) {
- radeon_emit_tex1( dev_priv );
- sarea_priv->dirty &= ~RADEON_UPLOAD_TEX1;
+ BEGIN_RING( 9 );
+ OUT_RING( CP_PACKET0( RADEON_PP_TXFILTER_1, 5 ) );
+ OUT_RING( tex[1].pp_txfilter );
+ OUT_RING( tex[1].pp_txformat );
+ OUT_RING( tex[1].pp_txoffset );
+ OUT_RING( tex[1].pp_txcblend );
+ OUT_RING( tex[1].pp_txablend );
+ OUT_RING( tex[1].pp_tfactor );
+ OUT_RING( CP_PACKET0( RADEON_PP_BORDER_COLOR_1, 0 ) );
+ OUT_RING( tex[1].pp_border_color );
+ ADVANCE_RING();
}
if ( dirty & RADEON_UPLOAD_TEX2 ) {
-#if 0
- radeon_emit_tex2( dev_priv );
-#endif
- sarea_priv->dirty &= ~RADEON_UPLOAD_TEX2;
+ BEGIN_RING( 9 );
+ OUT_RING( CP_PACKET0( RADEON_PP_TXFILTER_2, 5 ) );
+ OUT_RING( tex[2].pp_txfilter );
+ OUT_RING( tex[2].pp_txformat );
+ OUT_RING( tex[2].pp_txoffset );
+ OUT_RING( tex[2].pp_txcblend );
+ OUT_RING( tex[2].pp_txablend );
+ OUT_RING( tex[2].pp_tfactor );
+ OUT_RING( CP_PACKET0( RADEON_PP_BORDER_COLOR_2, 0 ) );
+ OUT_RING( tex[2].pp_border_color );
+ ADVANCE_RING();
+ }
+}
+
+/* Emit 1.2 state
+ */
+static void radeon_emit_state2( drm_radeon_private_t *dev_priv,
+ drm_radeon_state_t *state )
+{
+ RING_LOCALS;
+
+ if (state->dirty & RADEON_UPLOAD_ZBIAS) {
+ BEGIN_RING( 3 );
+ OUT_RING( CP_PACKET0( RADEON_SE_ZBIAS_FACTOR, 1 ) );
+ OUT_RING( state->context2.se_zbias_factor );
+ OUT_RING( state->context2.se_zbias_constant );
+ ADVANCE_RING();
}
- sarea_priv->dirty &= ~(RADEON_UPLOAD_TEX0IMAGES |
- RADEON_UPLOAD_TEX1IMAGES |
- RADEON_UPLOAD_TEX2IMAGES |
- RADEON_REQUIRE_QUIESCENCE);
+ radeon_emit_state( dev_priv, &state->context,
+ state->tex, state->dirty );
}
+/* New (1.3) state mechanism. 3 commands (packet, scalar, vector) in
+ * 1.3 cmdbuffers allow all previous state to be updated as well as
+ * the tcl scalar and vector areas.
+ */
+static struct {
+ int start;
+ int len;
+ const char *name;
+} packet[RADEON_MAX_STATE_PACKETS] = {
+ { RADEON_PP_MISC,7,"RADEON_PP_MISC" },
+ { RADEON_PP_CNTL,3,"RADEON_PP_CNTL" },
+ { RADEON_RB3D_COLORPITCH,1,"RADEON_RB3D_COLORPITCH" },
+ { RADEON_RE_LINE_PATTERN,2,"RADEON_RE_LINE_PATTERN" },
+ { RADEON_SE_LINE_WIDTH,1,"RADEON_SE_LINE_WIDTH" },
+ { RADEON_PP_LUM_MATRIX,1,"RADEON_PP_LUM_MATRIX" },
+ { RADEON_PP_ROT_MATRIX_0,2,"RADEON_PP_ROT_MATRIX_0" },
+ { RADEON_RB3D_STENCILREFMASK,3,"RADEON_RB3D_STENCILREFMASK" },
+ { RADEON_SE_VPORT_XSCALE,6,"RADEON_SE_VPORT_XSCALE" },
+ { RADEON_SE_CNTL,2,"RADEON_SE_CNTL" },
+ { RADEON_SE_CNTL_STATUS,1,"RADEON_SE_CNTL_STATUS" },
+ { RADEON_RE_MISC,1,"RADEON_RE_MISC" },
+ { RADEON_PP_TXFILTER_0,6,"RADEON_PP_TXFILTER_0" },
+ { RADEON_PP_BORDER_COLOR_0,1,"RADEON_PP_BORDER_COLOR_0" },
+ { RADEON_PP_TXFILTER_1,6,"RADEON_PP_TXFILTER_1" },
+ { RADEON_PP_BORDER_COLOR_1,1,"RADEON_PP_BORDER_COLOR_1" },
+ { RADEON_PP_TXFILTER_2,6,"RADEON_PP_TXFILTER_2" },
+ { RADEON_PP_BORDER_COLOR_2,1,"RADEON_PP_BORDER_COLOR_2" },
+ { RADEON_SE_ZBIAS_FACTOR,2,"RADEON_SE_ZBIAS_FACTOR" },
+ { RADEON_SE_TCL_OUTPUT_VTX_FMT,11,"RADEON_SE_TCL_OUTPUT_VTX_FMT" },
+ { RADEON_SE_TCL_MATERIAL_EMMISSIVE_RED,17,"RADEON_SE_TCL_MATERIAL_EMMISSIVE_RED" },
+};
+
+
+
+
+
+
+
+
+
#if RADEON_PERFORMANCE_BOXES
/* ================================================================
* CP command dispatch functions
*/
-static void radeon_print_dirty( const char *msg, unsigned int flags )
-{
- DRM_DEBUG( "%s: (0x%x) %s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
- msg,
- flags,
- (flags & RADEON_UPLOAD_CONTEXT) ? "context, " : "",
- (flags & RADEON_UPLOAD_VERTFMT) ? "vertfmt, " : "",
- (flags & RADEON_UPLOAD_LINE) ? "line, " : "",
- (flags & RADEON_UPLOAD_BUMPMAP) ? "bumpmap, " : "",
- (flags & RADEON_UPLOAD_MASKS) ? "masks, " : "",
- (flags & RADEON_UPLOAD_VIEWPORT) ? "viewport, " : "",
- (flags & RADEON_UPLOAD_SETUP) ? "setup, " : "",
- (flags & RADEON_UPLOAD_TCL) ? "tcl, " : "",
- (flags & RADEON_UPLOAD_MISC) ? "misc, " : "",
- (flags & RADEON_UPLOAD_TEX0) ? "tex0, " : "",
- (flags & RADEON_UPLOAD_TEX1) ? "tex1, " : "",
- (flags & RADEON_UPLOAD_TEX2) ? "tex2, " : "",
- (flags & RADEON_UPLOAD_CLIPRECTS) ? "cliprects, " : "",
- (flags & RADEON_REQUIRE_QUIESCENCE) ? "quiescence, " : "" );
-}
-
static void radeon_cp_dispatch_clear( drm_device_t *dev,
drm_radeon_clear_t *clear,
drm_radeon_clear_rect_t *depth_boxes )
{
drm_radeon_private_t *dev_priv = dev->dev_private;
drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
+ drm_radeon_depth_clear_t *depth_clear = &dev_priv->depth_clear;
int nbox = sarea_priv->nbox;
drm_clip_rect_t *pbox = sarea_priv->boxes;
unsigned int flags = clear->flags;
+ u32 rb3d_cntl = 0, rb3d_stencilrefmask= 0;
int i;
RING_LOCALS;
- DRM_DEBUG( "%s\n", __FUNCTION__ );
+ DRM_DEBUG( __FUNCTION__": flags = 0x%x\n", flags );
if ( dev_priv->page_flipping && dev_priv->current_page == 1 ) {
unsigned int tmp = flags;
if ( tmp & RADEON_BACK ) flags |= RADEON_FRONT;
}
+ /* We have to clear the depth and/or stencil buffers by
+ * rendering a quad into just those buffers. Thus, we have to
+ * make sure the 3D engine is configured correctly.
+ */
+ if ( flags & (RADEON_DEPTH | RADEON_STENCIL) ) {
+ rb3d_cntl = depth_clear->rb3d_cntl;
+
+ if ( flags & RADEON_DEPTH ) {
+ rb3d_cntl |= RADEON_Z_ENABLE;
+ } else {
+ rb3d_cntl &= ~RADEON_Z_ENABLE;
+ }
+
+ if ( flags & RADEON_STENCIL ) {
+ rb3d_cntl |= RADEON_STENCIL_ENABLE;
+ rb3d_stencilrefmask = clear->depth_mask; /* misnamed field */
+ } else {
+ rb3d_cntl &= ~RADEON_STENCIL_ENABLE;
+ rb3d_stencilrefmask = 0x00000000;
+ }
+ }
+
for ( i = 0 ; i < nbox ; i++ ) {
int x = pbox[i].x1;
int y = pbox[i].y1;
/* Make sure we restore the 3D state next time.
*/
- dev_priv->sarea_priv->dirty |= (RADEON_UPLOAD_CONTEXT |
- RADEON_UPLOAD_MASKS);
+ dev_priv->sarea_priv->ctx_owner = 0;
}
if ( flags & RADEON_FRONT ) {
OUT_RING( (w << 16) | h );
ADVANCE_RING();
-
}
- if ( flags & RADEON_DEPTH ) {
- drm_radeon_depth_clear_t *depth_clear =
- &dev_priv->depth_clear;
+ if ( flags & (RADEON_DEPTH | RADEON_STENCIL) ) {
- if ( sarea_priv->dirty & ~RADEON_UPLOAD_CLIPRECTS ) {
- radeon_emit_state( dev_priv );
- }
+ radeon_emit_clip_rect( dev_priv,
+ &sarea_priv->boxes[i] );
- /* FIXME: Render a rectangle to clear the depth
- * buffer. So much for those "fast Z clears"...
- */
- BEGIN_RING( 23 );
+ BEGIN_RING( 28 );
RADEON_WAIT_UNTIL_2D_IDLE();
OUT_RING( CP_PACKET0( RADEON_PP_CNTL, 1 ) );
OUT_RING( 0x00000000 );
- OUT_RING( depth_clear->rb3d_cntl );
- OUT_RING( CP_PACKET0( RADEON_RB3D_ZSTENCILCNTL, 0 ) );
- OUT_RING( depth_clear->rb3d_zstencilcntl );
- OUT_RING( CP_PACKET0( RADEON_RB3D_PLANEMASK, 0 ) );
- OUT_RING( 0x00000000 );
- OUT_RING( CP_PACKET0( RADEON_SE_CNTL, 0 ) );
- OUT_RING( depth_clear->se_cntl );
-
- OUT_RING( CP_PACKET3( RADEON_3D_DRAW_IMMD, 10 ) );
- OUT_RING( RADEON_VTX_Z_PRESENT );
+ OUT_RING( rb3d_cntl );
+
+ OUT_RING_REG( RADEON_RB3D_ZSTENCILCNTL,
+ depth_clear->rb3d_zstencilcntl );
+ OUT_RING_REG( RADEON_RB3D_STENCILREFMASK,
+ rb3d_stencilrefmask );
+ OUT_RING_REG( RADEON_RB3D_PLANEMASK,
+ 0x00000000 );
+ OUT_RING_REG( RADEON_SE_CNTL,
+ depth_clear->se_cntl );
+
+ /* Radeon 7500 doesn't like vertices without
+ * color.
+ */
+ OUT_RING( CP_PACKET3( RADEON_3D_DRAW_IMMD, 13 ) );
+ OUT_RING( RADEON_VTX_Z_PRESENT |
+ RADEON_VTX_PKCOLOR_PRESENT);
OUT_RING( (RADEON_PRIM_TYPE_RECT_LIST |
RADEON_PRIM_WALK_RING |
RADEON_MAOS_ENABLE |
OUT_RING( depth_boxes[i].ui[CLEAR_X1] );
OUT_RING( depth_boxes[i].ui[CLEAR_Y1] );
OUT_RING( depth_boxes[i].ui[CLEAR_DEPTH] );
+ OUT_RING( 0x0 );
OUT_RING( depth_boxes[i].ui[CLEAR_X1] );
OUT_RING( depth_boxes[i].ui[CLEAR_Y2] );
OUT_RING( depth_boxes[i].ui[CLEAR_DEPTH] );
+ OUT_RING( 0x0 );
OUT_RING( depth_boxes[i].ui[CLEAR_X2] );
OUT_RING( depth_boxes[i].ui[CLEAR_Y2] );
OUT_RING( depth_boxes[i].ui[CLEAR_DEPTH] );
+ OUT_RING( 0x0 );
ADVANCE_RING();
/* Make sure we restore the 3D state next time.
*/
- dev_priv->sarea_priv->dirty |= (RADEON_UPLOAD_CONTEXT |
- RADEON_UPLOAD_SETUP |
- RADEON_UPLOAD_MASKS);
+ dev_priv->sarea_priv->ctx_owner = 0;
}
}
RADEON_DP_SRC_SOURCE_MEMORY |
RADEON_GMC_CLR_CMP_CNTL_DIS |
RADEON_GMC_WR_MSK_DIS );
-
- OUT_RING( dev_priv->back_pitch_offset );
- OUT_RING( dev_priv->front_pitch_offset );
+
+ /* Make this work even if front & back are flipped:
+ */
+ if (dev_priv->current_page == 0) {
+ OUT_RING( dev_priv->back_pitch_offset );
+ OUT_RING( dev_priv->front_pitch_offset );
+ }
+ else {
+ OUT_RING( dev_priv->front_pitch_offset );
+ OUT_RING( dev_priv->back_pitch_offset );
+ }
OUT_RING( (x << 16) | y );
OUT_RING( (x << 16) | y );
radeon_cp_performance_boxes( dev_priv );
#endif
- BEGIN_RING( 6 );
+ BEGIN_RING( 4 );
RADEON_WAIT_UNTIL_3D_IDLE();
+/*
RADEON_WAIT_UNTIL_PAGE_FLIPPED();
-
+*/
OUT_RING( CP_PACKET0( RADEON_CRTC_OFFSET, 0 ) );
if ( dev_priv->current_page == 0 ) {
* performing the swapbuffer ioctl.
*/
dev_priv->sarea_priv->last_frame++;
+ dev_priv->sarea_priv->pfCurrentPage = dev_priv->current_page;
BEGIN_RING( 2 );
ADVANCE_RING();
}
+static int bad_prim_vertex_nr( int primitive, int nr )
+{
+ switch (primitive & RADEON_PRIM_TYPE_MASK) {
+ case RADEON_PRIM_TYPE_NONE:
+ case RADEON_PRIM_TYPE_POINT:
+ return nr < 1;
+ case RADEON_PRIM_TYPE_LINE:
+ return (nr & 1) || nr == 0;
+ case RADEON_PRIM_TYPE_LINE_STRIP:
+ return nr < 2;
+ case RADEON_PRIM_TYPE_TRI_LIST:
+ case RADEON_PRIM_TYPE_3VRT_POINT_LIST:
+ case RADEON_PRIM_TYPE_3VRT_LINE_LIST:
+ case RADEON_PRIM_TYPE_RECT_LIST:
+ return nr % 3 || nr == 0;
+ case RADEON_PRIM_TYPE_TRI_FAN:
+ case RADEON_PRIM_TYPE_TRI_STRIP:
+ return nr < 3;
+ default:
+ return 1;
+ }
+}
+
+
+
+typedef struct {
+ unsigned int start;
+ unsigned int finish;
+ unsigned int prim;
+ unsigned int numverts;
+ unsigned int offset;
+ unsigned int vc_format;
+} drm_radeon_tcl_prim_t;
+
static void radeon_cp_dispatch_vertex( drm_device_t *dev,
- drm_buf_t *buf )
+ drm_buf_t *buf,
+ drm_radeon_tcl_prim_t *prim,
+ drm_clip_rect_t *boxes,
+ int nbox )
+
{
drm_radeon_private_t *dev_priv = dev->dev_private;
- drm_radeon_buf_priv_t *buf_priv = buf->dev_private;
- drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
- int format = sarea_priv->vc_format;
- int offset = dev_priv->agp_buffers_offset + buf->offset;
- int size = buf->used;
- int prim = buf_priv->prim;
+ drm_clip_rect_t box;
+ int offset = dev_priv->agp_buffers_offset + buf->offset + prim->start;
+ int numverts = (int)prim->numverts;
int i = 0;
RING_LOCALS;
- DRM_DEBUG( "%s: nbox=%d\n", __FUNCTION__, sarea_priv->nbox );
- if ( 0 )
- radeon_print_dirty( "dispatch_vertex", sarea_priv->dirty );
- if ( buf->used ) {
- buf_priv->dispatched = 1;
+ DRM_DEBUG("%s: hwprim 0x%x vfmt 0x%x %d..%d %d verts\n",
+ __FUNCTION__,
+ prim->prim,
+ prim->vc_format,
+ prim->start,
+ prim->finish,
+ prim->numverts);
- if ( sarea_priv->dirty & ~RADEON_UPLOAD_CLIPRECTS ) {
- radeon_emit_state( dev_priv );
+ if (bad_prim_vertex_nr( prim->prim, prim->numverts )) {
+ DRM_ERROR( "bad prim %x numverts %d\n",
+ prim->prim, prim->numverts );
+ return;
+ }
+
+
+ do {
+ /* Emit the next cliprect */
+ if ( i < nbox ) {
+ if (__copy_from_user( &box, &boxes[i], sizeof(box) ))
+ return;
+
+ radeon_emit_clip_rect( dev_priv, &box );
}
- do {
- /* Emit the next set of up to three cliprects */
- if ( i < sarea_priv->nbox ) {
- radeon_emit_clip_rect( dev_priv,
- &sarea_priv->boxes[i] );
- }
+ /* Emit the vertex buffer rendering commands */
+ BEGIN_RING( 5 );
- /* Emit the vertex buffer rendering commands */
- BEGIN_RING( 5 );
+ OUT_RING( CP_PACKET3( RADEON_3D_RNDR_GEN_INDX_PRIM, 3 ) );
+ OUT_RING( offset );
+ OUT_RING( numverts );
+ OUT_RING( prim->vc_format );
+ OUT_RING( prim->prim | RADEON_PRIM_WALK_LIST |
+ RADEON_COLOR_ORDER_RGBA |
+ RADEON_VTX_FMT_RADEON_MODE |
+ (numverts << RADEON_NUM_VERTICES_SHIFT) );
- OUT_RING( CP_PACKET3( RADEON_3D_RNDR_GEN_INDX_PRIM, 3 ) );
- OUT_RING( offset );
- OUT_RING( size );
- OUT_RING( format );
- OUT_RING( prim | RADEON_PRIM_WALK_LIST |
- RADEON_COLOR_ORDER_RGBA |
- RADEON_VTX_FMT_RADEON_MODE |
- (size << RADEON_NUM_VERTICES_SHIFT) );
+ ADVANCE_RING();
- ADVANCE_RING();
+ i++;
+ } while ( i < nbox );
+}
- i++;
- } while ( i < sarea_priv->nbox );
- }
- if ( buf_priv->discard ) {
- buf_priv->age = dev_priv->sarea_priv->last_dispatch;
- /* Emit the vertex buffer age */
- BEGIN_RING( 2 );
- RADEON_DISPATCH_AGE( buf_priv->age );
- ADVANCE_RING();
+static void radeon_cp_discard_buffer( drm_device_t *dev, drm_buf_t *buf )
+{
+ drm_radeon_private_t *dev_priv = dev->dev_private;
+ drm_radeon_buf_priv_t *buf_priv = buf->dev_private;
+ RING_LOCALS;
- buf->pending = 1;
- buf->used = 0;
- /* FIXME: Check dispatched field */
- buf_priv->dispatched = 0;
- }
+ buf_priv->age = ++dev_priv->sarea_priv->last_dispatch;
- dev_priv->sarea_priv->last_dispatch++;
+ /* Emit the vertex buffer age */
+ BEGIN_RING( 2 );
+ RADEON_DISPATCH_AGE( buf_priv->age );
+ ADVANCE_RING();
- sarea_priv->dirty &= ~RADEON_UPLOAD_CLIPRECTS;
- sarea_priv->nbox = 0;
+ buf->pending = 1;
+ buf->used = 0;
}
-
static void radeon_cp_dispatch_indirect( drm_device_t *dev,
drm_buf_t *buf,
int start, int end )
{
drm_radeon_private_t *dev_priv = dev->dev_private;
- drm_radeon_buf_priv_t *buf_priv = buf->dev_private;
RING_LOCALS;
DRM_DEBUG( "indirect: buf=%d s=0x%x e=0x%x\n",
buf->idx, start, end );
data[dwords++] = RADEON_CP_PACKET2;
}
- buf_priv->dispatched = 1;
-
/* Fire off the indirect buffer */
BEGIN_RING( 3 );
ADVANCE_RING();
}
-
- if ( buf_priv->discard ) {
- buf_priv->age = dev_priv->sarea_priv->last_dispatch;
-
- /* Emit the indirect buffer age */
- BEGIN_RING( 2 );
- RADEON_DISPATCH_AGE( buf_priv->age );
- ADVANCE_RING();
-
- buf->pending = 1;
- buf->used = 0;
- /* FIXME: Check dispatched field */
- buf_priv->dispatched = 0;
- }
-
- dev_priv->sarea_priv->last_dispatch++;
}
+
static void radeon_cp_dispatch_indices( drm_device_t *dev,
- drm_buf_t *buf,
- int start, int end,
- int count )
+ drm_buf_t *elt_buf,
+ drm_radeon_tcl_prim_t *prim,
+ drm_clip_rect_t *boxes,
+ int nbox )
{
drm_radeon_private_t *dev_priv = dev->dev_private;
- drm_radeon_buf_priv_t *buf_priv = buf->dev_private;
- drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
- int format = sarea_priv->vc_format;
- int offset = dev_priv->agp_buffers_offset;
- int prim = buf_priv->prim;
+ drm_clip_rect_t box;
+ int offset = dev_priv->agp_buffers_offset + prim->offset;
u32 *data;
int dwords;
int i = 0;
- RING_LOCALS;
- DRM_DEBUG( "indices: s=%d e=%d c=%d\n", start, end, count );
-
- if ( 0 )
- radeon_print_dirty( "dispatch_indices", sarea_priv->dirty );
-
- if ( start != end ) {
- buf_priv->dispatched = 1;
-
- if ( sarea_priv->dirty & ~RADEON_UPLOAD_CLIPRECTS ) {
- radeon_emit_state( dev_priv );
- }
-
- dwords = (end - start + 3) / sizeof(u32);
-
- data = (u32 *)((char *)dev_priv->buffers->handle
- + buf->offset + start);
-
- data[0] = CP_PACKET3( RADEON_3D_RNDR_GEN_INDX_PRIM, dwords-2 );
-
- data[1] = offset;
- data[2] = RADEON_MAX_VB_VERTS;
- data[3] = format;
- data[4] = (prim | RADEON_PRIM_WALK_IND |
- RADEON_COLOR_ORDER_RGBA |
- RADEON_VTX_FMT_RADEON_MODE |
- (count << RADEON_NUM_VERTICES_SHIFT) );
-
- if ( count & 0x1 ) {
- data[dwords-1] &= 0x0000ffff;
- }
-
- do {
- /* Emit the next set of up to three cliprects */
- if ( i < sarea_priv->nbox ) {
- radeon_emit_clip_rect( dev_priv,
- &sarea_priv->boxes[i] );
- }
+ int start = prim->start + RADEON_INDEX_PRIM_OFFSET;
+ int count = (prim->finish - start) / sizeof(u16);
+
+ DRM_DEBUG("%s: hwprim 0x%x vfmt 0x%x %d..%d offset: %x nr %d\n",
+ __FUNCTION__,
+ prim->prim,
+ prim->vc_format,
+ prim->start,
+ prim->finish,
+ prim->offset,
+ prim->numverts);
+
+ if (bad_prim_vertex_nr( prim->prim, count )) {
+ DRM_ERROR( "bad prim %x count %d\n",
+ prim->prim, count );
+ return;
+ }
- radeon_cp_dispatch_indirect( dev, buf, start, end );
- i++;
- } while ( i < sarea_priv->nbox );
+ if ( start >= prim->finish ||
+ (prim->start & 0x7) ) {
+ DRM_ERROR( "buffer prim %d\n", prim->prim );
+ return;
}
- if ( buf_priv->discard ) {
- buf_priv->age = dev_priv->sarea_priv->last_dispatch;
-
- /* Emit the vertex buffer age */
- BEGIN_RING( 2 );
- RADEON_DISPATCH_AGE( buf_priv->age );
- ADVANCE_RING();
+ dwords = (prim->finish - prim->start + 3) / sizeof(u32);
+
+ data = (u32 *)((char *)dev_priv->buffers->handle +
+ elt_buf->offset + prim->start);
+
+ data[0] = CP_PACKET3( RADEON_3D_RNDR_GEN_INDX_PRIM, dwords-2 );
+ data[1] = offset;
+ data[2] = prim->numverts;
+ data[3] = prim->vc_format;
+ data[4] = (prim->prim |
+ RADEON_PRIM_WALK_IND |
+ RADEON_COLOR_ORDER_RGBA |
+ RADEON_VTX_FMT_RADEON_MODE |
+ (count << RADEON_NUM_VERTICES_SHIFT) );
+
+ do {
+ if ( i < nbox ) {
+ if (__copy_from_user( &box, &boxes[i], sizeof(box) ))
+ return;
+
+ radeon_emit_clip_rect( dev_priv, &box );
+ }
- buf->pending = 1;
- /* FIXME: Check dispatched field */
- buf_priv->dispatched = 0;
- }
+ radeon_cp_dispatch_indirect( dev, elt_buf,
+ prim->start,
+ prim->finish );
- dev_priv->sarea_priv->last_dispatch++;
+ i++;
+ } while ( i < nbox );
- sarea_priv->dirty &= ~RADEON_UPLOAD_CLIPRECTS;
- sarea_priv->nbox = 0;
}
#define RADEON_MAX_TEXTURE_SIZE (RADEON_BUFFER_SIZE - 8 * sizeof(u32))
{
drm_radeon_private_t *dev_priv = dev->dev_private;
drm_buf_t *buf;
- drm_radeon_buf_priv_t *buf_priv;
u32 format;
u32 *buffer;
u8 *data;
tex->offset >> 10, tex->pitch, tex->format,
image->x, image->y, image->width, image->height );
- buf_priv = buf->dev_private;
-
/* The compiler won't optimize away a division by a variable,
* even if the only legal values are powers of two. Thus, we'll
* use a shift instead.
DRM_ERROR( "EFAULT on tex->image\n" );
return -EFAULT;
}
- } else if ( size < 4 ) {
+ } else if ( size < 4 && size > 0 ) {
size = 4;
}
buf->pid = current->pid;
buf->used = (dwords + 8) * sizeof(u32);
- buf_priv->discard = 1;
radeon_cp_dispatch_indirect( dev, buf, 0, buf->used );
+ radeon_cp_discard_buffer( dev, buf );
/* Flush the pixel cache after the blit completes. This ensures
* the texture data is written out to memory before rendering
return 0;
}
-int radeon_cp_swap( struct inode *inode, struct file *filp,
+
+
+/* Not sure why this isn't set all the time:
+ */
+static int radeon_do_init_pageflip( drm_device_t *dev )
+{
+ drm_radeon_private_t *dev_priv = dev->dev_private;
+ DRM_DEBUG( "%s\n", __FUNCTION__ );
+
+ dev_priv->crtc_offset = RADEON_READ( RADEON_CRTC_OFFSET );
+ dev_priv->crtc_offset_cntl = RADEON_READ( RADEON_CRTC_OFFSET_CNTL );
+
+ RADEON_WRITE( RADEON_CRTC_OFFSET, dev_priv->front_offset );
+ RADEON_WRITE( RADEON_CRTC_OFFSET_CNTL,
+ dev_priv->crtc_offset_cntl |
+ RADEON_CRTC_OFFSET_FLIP_CNTL );
+
+ dev_priv->page_flipping = 1;
+ dev_priv->current_page = 0;
+
+ return 0;
+}
+
+int radeon_do_cleanup_pageflip( drm_device_t *dev )
+{
+ drm_radeon_private_t *dev_priv = dev->dev_private;
+ DRM_DEBUG( "%s\n", __FUNCTION__ );
+
+ RADEON_WRITE( RADEON_CRTC_OFFSET, dev_priv->crtc_offset );
+ RADEON_WRITE( RADEON_CRTC_OFFSET_CNTL, dev_priv->crtc_offset_cntl );
+
+ dev_priv->page_flipping = 0;
+ dev_priv->current_page = 0;
+
+ return 0;
+}
+
+/* Swapping and flipping are different operations, need different ioctls.
+ * They can & should be intermixed to support multiple 3d windows.
+ */
+int radeon_cp_flip( struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg )
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ drm_radeon_private_t *dev_priv = dev->dev_private;
+ DRM_DEBUG( "%s\n", __FUNCTION__ );
+
+ LOCK_TEST_WITH_RETURN( dev );
+
+ RING_SPACE_TEST_WITH_RETURN( dev_priv );
+
+ if (!dev_priv->page_flipping)
+ radeon_do_init_pageflip( dev );
+
+ radeon_cp_dispatch_flip( dev );
+
+ return 0;
+}
+
+int radeon_cp_swap( struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg )
{
drm_file_t *priv = filp->private_data;
if ( sarea_priv->nbox > RADEON_NR_SAREA_CLIPRECTS )
sarea_priv->nbox = RADEON_NR_SAREA_CLIPRECTS;
- if ( !dev_priv->page_flipping ) {
- radeon_cp_dispatch_swap( dev );
- dev_priv->sarea_priv->dirty |= (RADEON_UPLOAD_CONTEXT |
- RADEON_UPLOAD_MASKS);
- } else {
- radeon_cp_dispatch_flip( dev );
- }
+ radeon_cp_dispatch_swap( dev );
+ dev_priv->sarea_priv->ctx_owner = 0;
return 0;
}
drm_file_t *priv = filp->private_data;
drm_device_t *dev = priv->dev;
drm_radeon_private_t *dev_priv = dev->dev_private;
+ drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
drm_device_dma_t *dma = dev->dma;
drm_buf_t *buf;
- drm_radeon_buf_priv_t *buf_priv;
drm_radeon_vertex_t vertex;
+ drm_radeon_tcl_prim_t prim;
LOCK_TEST_WITH_RETURN( dev );
VB_AGE_TEST_WITH_RETURN( dev_priv );
buf = dma->buflist[vertex.idx];
- buf_priv = buf->dev_private;
if ( buf->pid != current->pid ) {
DRM_ERROR( "process %d using buffer owned by %d\n",
return -EINVAL;
}
- buf->used = vertex.count;
- buf_priv->prim = vertex.prim;
- buf_priv->discard = vertex.discard;
+ /* Build up a prim_t record:
+ */
+ if (vertex.count) {
+ buf->used = vertex.count; /* not used? */
- radeon_cp_dispatch_vertex( dev, buf );
+ if ( sarea_priv->dirty & ~RADEON_UPLOAD_CLIPRECTS ) {
+ radeon_emit_state( dev_priv,
+ &sarea_priv->context_state,
+ sarea_priv->tex_state,
+ sarea_priv->dirty );
+
+ sarea_priv->dirty &= ~(RADEON_UPLOAD_TEX0IMAGES |
+ RADEON_UPLOAD_TEX1IMAGES |
+ RADEON_UPLOAD_TEX2IMAGES |
+ RADEON_REQUIRE_QUIESCENCE);
+ }
+
+ prim.start = 0;
+ prim.finish = vertex.count; /* unused */
+ prim.prim = vertex.prim;
+ prim.numverts = vertex.count;
+ prim.vc_format = dev_priv->sarea_priv->vc_format;
+
+ radeon_cp_dispatch_vertex( dev, buf, &prim,
+ dev_priv->sarea_priv->boxes,
+ dev_priv->sarea_priv->nbox );
+ }
+
+ if (vertex.discard) {
+ radeon_cp_discard_buffer( dev, buf );
+ }
return 0;
}
drm_file_t *priv = filp->private_data;
drm_device_t *dev = priv->dev;
drm_radeon_private_t *dev_priv = dev->dev_private;
+ drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
drm_device_dma_t *dma = dev->dma;
drm_buf_t *buf;
- drm_radeon_buf_priv_t *buf_priv;
drm_radeon_indices_t elts;
+ drm_radeon_tcl_prim_t prim;
int count;
LOCK_TEST_WITH_RETURN( dev );
VB_AGE_TEST_WITH_RETURN( dev_priv );
buf = dma->buflist[elts.idx];
- buf_priv = buf->dev_private;
if ( buf->pid != current->pid ) {
DRM_ERROR( "process %d using buffer owned by %d\n",
}
buf->used = elts.end;
- buf_priv->prim = elts.prim;
- buf_priv->discard = elts.discard;
- radeon_cp_dispatch_indices( dev, buf, elts.start, elts.end, count );
+ if ( sarea_priv->dirty & ~RADEON_UPLOAD_CLIPRECTS ) {
+ radeon_emit_state( dev_priv,
+ &sarea_priv->context_state,
+ sarea_priv->tex_state,
+ sarea_priv->dirty );
+
+ sarea_priv->dirty &= ~(RADEON_UPLOAD_TEX0IMAGES |
+ RADEON_UPLOAD_TEX1IMAGES |
+ RADEON_UPLOAD_TEX2IMAGES |
+ RADEON_REQUIRE_QUIESCENCE);
+ }
+
+
+ /* Build up a prim_t record:
+ */
+ prim.start = elts.start;
+ prim.finish = elts.end;
+ prim.prim = elts.prim;
+ prim.offset = 0; /* offset from start of dma buffers */
+ prim.numverts = RADEON_MAX_VB_VERTS; /* duh */
+ prim.vc_format = dev_priv->sarea_priv->vc_format;
+
+ radeon_cp_dispatch_indices( dev, buf, &prim,
+ dev_priv->sarea_priv->boxes,
+ dev_priv->sarea_priv->nbox );
+ if (elts.discard) {
+ radeon_cp_discard_buffer( dev, buf );
+ }
return 0;
}
drm_radeon_private_t *dev_priv = dev->dev_private;
drm_device_dma_t *dma = dev->dma;
drm_buf_t *buf;
- drm_radeon_buf_priv_t *buf_priv;
drm_radeon_indirect_t indirect;
RING_LOCALS;
}
buf = dma->buflist[indirect.idx];
- buf_priv = buf->dev_private;
if ( buf->pid != current->pid ) {
DRM_ERROR( "process %d using buffer owned by %d\n",
VB_AGE_TEST_WITH_RETURN( dev_priv );
buf->used = indirect.end;
- buf_priv->discard = indirect.discard;
/* Wait for the 3D stream to idle before the indirect buffer
* containing 2D acceleration commands is processed.
* privileged clients.
*/
radeon_cp_dispatch_indirect( dev, buf, indirect.start, indirect.end );
+ if (indirect.discard) {
+ radeon_cp_discard_buffer( dev, buf );
+ }
+
+
+ return 0;
+}
+int radeon_cp_vertex2( struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg )
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ drm_radeon_private_t *dev_priv = dev->dev_private;
+ drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
+ drm_device_dma_t *dma = dev->dma;
+ drm_buf_t *buf;
+ drm_radeon_vertex2_t vertex;
+ int i;
+ unsigned char laststate;
+
+ LOCK_TEST_WITH_RETURN( dev );
+
+ if ( !dev_priv ) {
+ DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ );
+ return -EINVAL;
+ }
+
+ if ( copy_from_user( &vertex, (drm_radeon_vertex_t *)arg,
+ sizeof(vertex) ) )
+ return -EFAULT;
+
+ DRM_DEBUG( __FUNCTION__": pid=%d index=%d discard=%d\n",
+ current->pid, vertex.idx, vertex.discard );
+
+ if ( vertex.idx < 0 || vertex.idx >= dma->buf_count ) {
+ DRM_ERROR( "buffer index %d (of %d max)\n",
+ vertex.idx, dma->buf_count - 1 );
+ return -EINVAL;
+ }
+
+ RING_SPACE_TEST_WITH_RETURN( dev_priv );
+ VB_AGE_TEST_WITH_RETURN( dev_priv );
+
+ buf = dma->buflist[vertex.idx];
+
+ if ( buf->pid != current->pid ) {
+ DRM_ERROR( "process %d using buffer owned by %d\n",
+ current->pid, buf->pid );
+ return -EINVAL;
+ }
+
+ if ( buf->pending ) {
+ DRM_ERROR( "sending pending buffer %d\n", vertex.idx );
+ return -EINVAL;
+ }
+
+ if (sarea_priv->nbox > RADEON_NR_SAREA_CLIPRECTS)
+ return -EINVAL;
+
+ for (laststate = 0xff, i = 0 ; i < vertex.nr_prims ; i++) {
+ drm_radeon_prim_t prim;
+ drm_radeon_tcl_prim_t tclprim;
+
+ if ( copy_from_user( &prim, &vertex.prim[i], sizeof(prim) ) )
+ return -EFAULT;
+
+ if ( prim.stateidx != laststate ) {
+ drm_radeon_state_t state;
+
+ if ( copy_from_user( &state,
+ &vertex.state[prim.stateidx],
+ sizeof(state) ) )
+ return -EFAULT;
+
+ radeon_emit_state2( dev_priv, &state );
+
+ laststate = prim.stateidx;
+ }
+
+ tclprim.start = prim.start;
+ tclprim.finish = prim.finish;
+ tclprim.prim = prim.prim;
+ tclprim.vc_format = prim.vc_format;
+
+ if ( prim.prim & RADEON_PRIM_WALK_IND ) {
+ tclprim.offset = prim.numverts * 64;
+ tclprim.numverts = RADEON_MAX_VB_VERTS; /* duh */
+
+ radeon_cp_dispatch_indices( dev, buf, &tclprim,
+ sarea_priv->boxes,
+ sarea_priv->nbox);
+ } else {
+ tclprim.numverts = prim.numverts;
+ tclprim.offset = 0; /* not used */
+
+ radeon_cp_dispatch_vertex( dev, buf, &tclprim,
+ sarea_priv->boxes,
+ sarea_priv->nbox);
+ }
+
+ if (sarea_priv->nbox == 1)
+ sarea_priv->nbox = 0;
+ }
+
+ if ( vertex.discard ) {
+ radeon_cp_discard_buffer( dev, buf );
+ }
+
+ return 0;
+}
+
+
+static int radeon_emit_packets(
+ drm_radeon_private_t *dev_priv,
+ drm_radeon_cmd_header_t header,
+ drm_radeon_cmd_buffer_t *cmdbuf )
+{
+ int sz = packet[(int)header.packet.packet_id].len;
+ int reg = packet[(int)header.packet.packet_id].start;
+ int i, tmp, *data = (int *)cmdbuf->buf;
+ RING_LOCALS;
+
+ if (sz * sizeof(int) > cmdbuf->bufsz)
+ return -EINVAL;
+
+ BEGIN_RING( (sz+1) );
+ OUT_RING( CP_PACKET0( reg, (sz-1) ) );
+ for ( i = 0 ; i < sz ; i++ ) {
+ if (__get_user( tmp, &data[i] ))
+ return -EFAULT;
+ OUT_RING( tmp );
+ }
+ ADVANCE_RING();
+
+ cmdbuf->buf += sz * sizeof(int);
+ cmdbuf->bufsz -= sz * sizeof(int);
+ return 0;
+}
+
+static inline int radeon_emit_scalars(
+ drm_radeon_private_t *dev_priv,
+ drm_radeon_cmd_header_t header,
+ drm_radeon_cmd_buffer_t *cmdbuf )
+{
+ int sz = header.scalars.count;
+ int i, tmp, *data = (int *)cmdbuf->buf;
+ int start = header.scalars.offset;
+ int stride = header.scalars.stride;
+ RING_LOCALS;
+
+ BEGIN_RING( 3+sz );
+ OUT_RING( CP_PACKET0( RADEON_SE_TCL_SCALAR_INDX_REG, 0 ) );
+ OUT_RING( start | (stride << RADEON_SCAL_INDX_DWORD_STRIDE_SHIFT));
+ OUT_RING( CP_PACKET0_TABLE( RADEON_SE_TCL_SCALAR_DATA_REG, sz-1 ) );
+ for ( i = 0 ; i < sz ; i++ ) {
+ if (__get_user( tmp, &data[i] ))
+ return -EFAULT;
+ OUT_RING( tmp );
+ }
+ ADVANCE_RING();
+ cmdbuf->buf += sz * sizeof(int);
+ cmdbuf->bufsz -= sz * sizeof(int);
+ return 0;
+}
+
+static inline int radeon_emit_vectors(
+ drm_radeon_private_t *dev_priv,
+ drm_radeon_cmd_header_t header,
+ drm_radeon_cmd_buffer_t *cmdbuf )
+{
+ int sz = header.vectors.count;
+ int i, tmp, *data = (int *)cmdbuf->buf;
+ int start = header.vectors.offset;
+ int stride = header.vectors.stride;
+ RING_LOCALS;
+
+ BEGIN_RING( 3+sz );
+ OUT_RING( CP_PACKET0( RADEON_SE_TCL_VECTOR_INDX_REG, 0 ) );
+ OUT_RING( start | (stride << RADEON_VEC_INDX_OCTWORD_STRIDE_SHIFT));
+ OUT_RING( CP_PACKET0_TABLE( RADEON_SE_TCL_VECTOR_DATA_REG, (sz-1) ) );
+ for ( i = 0 ; i < sz ; i++ ) {
+ if (__get_user( tmp, &data[i] ))
+ return -EFAULT;
+ OUT_RING( tmp );
+ }
+ ADVANCE_RING();
+
+ cmdbuf->buf += sz * sizeof(int);
+ cmdbuf->bufsz -= sz * sizeof(int);
+ return 0;
+}
+
+
+static int radeon_emit_packet3( drm_device_t *dev,
+ drm_radeon_cmd_buffer_t *cmdbuf )
+{
+ drm_radeon_private_t *dev_priv = dev->dev_private;
+ int cmdsz, tmp;
+ int *cmd = (int *)cmdbuf->buf;
+ int j;
+ RING_LOCALS;
+
+ DRM_DEBUG("%s\n", __FUNCTION__);
+
+ if (__get_user( tmp, &cmd[0]))
+ return -EFAULT;
+
+ cmdsz = 2 + ((tmp & RADEON_CP_PACKET_COUNT_MASK) >> 16);
+
+ if ((tmp & 0xc0000000) != RADEON_CP_PACKET3 ||
+ cmdsz * 4 > cmdbuf->bufsz)
+ return -EINVAL;
+
+
+ BEGIN_RING( cmdsz );
+ for (j = 0 ; j < cmdsz ; j++) {
+ if (__get_user( tmp, &cmd[j] ))
+ return -EFAULT;
+/* printk( "pk3 %d: %x\n", j, tmp); */
+ OUT_RING( tmp );
+ }
+ ADVANCE_RING();
+
+ cmdbuf->buf += cmdsz * 4;
+ cmdbuf->bufsz -= cmdsz * 4;
+ return 0;
+}
+
+
+static int radeon_emit_packet3_cliprect( drm_device_t *dev,
+ drm_radeon_cmd_buffer_t *cmdbuf )
+{
+ drm_radeon_private_t *dev_priv = dev->dev_private;
+ drm_clip_rect_t box;
+ int cmdsz, tmp;
+ int *cmd = (int *)cmdbuf->buf;
+ drm_clip_rect_t *boxes = cmdbuf->boxes;
+ int i = 0, j;
+ RING_LOCALS;
+
+ DRM_DEBUG("%s\n", __FUNCTION__);
+
+ if (__get_user( tmp, &cmd[0]))
+ return -EFAULT;
+
+ cmdsz = 2 + ((tmp & RADEON_CP_PACKET_COUNT_MASK) >> 16);
+
+ if ((tmp & 0xc0000000) != RADEON_CP_PACKET3 ||
+ cmdsz * 4 > cmdbuf->bufsz)
+ return -EINVAL;
+
+ do {
+ if ( i < cmdbuf->nbox ) {
+ if (__copy_from_user( &box, &boxes[i], sizeof(box) ))
+ return -EFAULT;
+ radeon_emit_clip_rect( dev_priv, &box );
+ }
+
+ BEGIN_RING( cmdsz );
+ for (j = 0 ; j < cmdsz ; j++) {
+ if (__get_user( tmp, &cmd[j] ))
+ return -EFAULT;
+/* printk( "pk3_clip %d: %x\n", j, tmp); */
+ OUT_RING( tmp );
+ }
+ ADVANCE_RING();
+
+ } while ( ++i < cmdbuf->nbox );
+
+ if (cmdbuf->nbox == 1)
+ cmdbuf->nbox = 0;
+
+ cmdbuf->buf += cmdsz * 4;
+ cmdbuf->bufsz -= cmdsz * 4;
+ return 0;
+}
+
+
+
+int radeon_cp_cmdbuf( struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg )
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ drm_radeon_private_t *dev_priv = dev->dev_private;
+ drm_device_dma_t *dma = dev->dma;
+ drm_buf_t *buf = 0;
+ int idx;
+ drm_radeon_cmd_buffer_t cmdbuf;
+ drm_radeon_cmd_header_t header;
+
+ LOCK_TEST_WITH_RETURN( dev );
+
+ if ( !dev_priv ) {
+ DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ );
+ return -EINVAL;
+ }
+
+ if ( copy_from_user( &cmdbuf, (drm_radeon_cmd_buffer_t *)arg,
+ sizeof(cmdbuf) ) ) {
+ DRM_ERROR("copy_from_user\n");
+ return -EFAULT;
+ }
+
+ DRM_DEBUG( __FUNCTION__": pid=%d\n", current->pid );
+ RING_SPACE_TEST_WITH_RETURN( dev_priv );
+ VB_AGE_TEST_WITH_RETURN( dev_priv );
+
+
+ if (verify_area( VERIFY_READ, cmdbuf.buf, cmdbuf.bufsz ))
+ return -EFAULT;
+
+ if (verify_area( VERIFY_READ, cmdbuf.boxes,
+ cmdbuf.nbox * sizeof(drm_clip_rect_t)))
+ return -EFAULT;
+
+ while ( cmdbuf.bufsz >= sizeof(header) ) {
+
+ if (__get_user( header.i, (int *)cmdbuf.buf )) {
+ DRM_ERROR("__get_user %p\n", cmdbuf.buf);
+ return -EFAULT;
+ }
+
+ cmdbuf.buf += sizeof(header);
+ cmdbuf.bufsz -= sizeof(header);
+
+ switch (header.header.cmd_type) {
+ case RADEON_CMD_PACKET:
+ if (radeon_emit_packets( dev_priv, header, &cmdbuf )) {
+ DRM_ERROR("radeon_emit_packets failed\n");
+ return -EINVAL;
+ }
+ break;
+
+ case RADEON_CMD_SCALARS:
+ if (radeon_emit_scalars( dev_priv, header, &cmdbuf )) {
+ DRM_ERROR("radeon_emit_scalars failed\n");
+ return -EINVAL;
+ }
+ break;
+
+ case RADEON_CMD_VECTORS:
+ if (radeon_emit_vectors( dev_priv, header, &cmdbuf )) {
+ DRM_ERROR("radeon_emit_vectors failed\n");
+ return -EINVAL;
+ }
+ break;
+
+ case RADEON_CMD_DMA_DISCARD:
+ idx = header.dma.buf_idx;
+ if ( idx < 0 || idx >= dma->buf_count ) {
+ DRM_ERROR( "buffer index %d (of %d max)\n",
+ idx, dma->buf_count - 1 );
+ return -EINVAL;
+ }
+
+ buf = dma->buflist[idx];
+ if ( buf->pid != current->pid || buf->pending ) {
+ DRM_ERROR( "bad buffer\n" );
+ return -EINVAL;
+ }
+
+ radeon_cp_discard_buffer( dev, buf );
+ break;
+
+ case RADEON_CMD_PACKET3:
+ if (radeon_emit_packet3( dev, &cmdbuf )) {
+ DRM_ERROR("radeon_emit_packet3 failed\n");
+ return -EINVAL;
+ }
+ break;
+
+ case RADEON_CMD_PACKET3_CLIP:
+ if (radeon_emit_packet3_cliprect( dev, &cmdbuf )) {
+ DRM_ERROR("radeon_emit_packet3_clip failed\n");
+ return -EINVAL;
+ }
+ break;
+
+ default:
+ DRM_ERROR("bad cmd_type %d at %p\n",
+ header.header.cmd_type,
+ cmdbuf.buf - sizeof(header));
+ return -EINVAL;
+ }
+ }
+
+
+ return 0;
+}
+
+
+
+int radeon_cp_getparam( struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg )
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ drm_radeon_private_t *dev_priv = dev->dev_private;
+ drm_radeon_getparam_t param;
+ int value;
+
+ if ( !dev_priv ) {
+ DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ );
+ return -EINVAL;
+ }
+
+ if ( copy_from_user( ¶m, (drm_radeon_getparam_t *)arg,
+ sizeof(param) ) ) {
+ DRM_ERROR("copy_from_user\n");
+ return -EFAULT;
+ }
+
+ DRM_DEBUG( __FUNCTION__": pid=%d\n", current->pid );
+
+ switch( param.param ) {
+ case RADEON_PARAM_AGP_BUFFER_OFFSET:
+ value = dev_priv->agp_buffers_offset;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if ( copy_to_user( param.value, &value, sizeof(int) ) ) {
+ DRM_ERROR( "copy_to_user\n" );
+ return -EFAULT;
+ }
+
return 0;
}
--- /dev/null
+/* sis_drv.h -- Private header for sis driver -*- linux-c -*-
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+/* $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/sis.h,v 1.2 2001/12/19 21:25:59 dawes Exp $ */
+
+#ifndef __SIS_H__
+#define __SIS_H__
+
+/* This remains constant for all DRM template files.
+ * Name it sisdrv_##x as there's a conflict with sis_free/malloc in the kernel
+ * that's used for fb devices
+ */
+#define DRM(x) sisdrv_##x
+
+/* General customization:
+ */
+#define __HAVE_AGP 1
+#define __MUST_HAVE_AGP 0
+#define __HAVE_MTRR 1
+#define __HAVE_CTX_BITMAP 1
+
+/* Buffer customization:
+ */
+#define DRIVER_AGP_BUFFERS_MAP( dev ) \
+ ((drm_sis_private_t *)((dev)->dev_private))->buffers
+
+extern int sis_init_context(int context);
+extern int sis_final_context(int context);
+
+#define DRIVER_CTX_CTOR sis_init_context
+#define DRIVER_CTX_DTOR sis_final_context
+
+#endif
--- /dev/null
+
+#ifndef _sis_drm_public_h_
+#define _sis_drm_public_h_
+
+typedef struct {
+ int context;
+ unsigned int offset;
+ unsigned int size;
+ unsigned int free;
+} drm_sis_mem_t;
+
+typedef struct {
+ unsigned int offset, size;
+} drm_sis_agp_t;
+
+typedef struct {
+ unsigned int left, right;
+} drm_sis_flip_t;
+
+#ifdef __KERNEL__
+
+int sis_fb_alloc(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg);
+int sis_fb_free(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg);
+
+int sisp_agp_init(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg);
+int sisp_agp_alloc(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg);
+int sisp_agp_free(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg);
+
+#endif
+
+#endif
--- /dev/null
+/* sis.c -- sis driver -*- linux-c -*-
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include <linux/config.h>
+#include "sis.h"
+#include "drmP.h"
+#include "sis_drm.h"
+#include "sis_drv.h"
+
+#define DRIVER_AUTHOR "SIS"
+#define DRIVER_NAME "sis"
+#define DRIVER_DESC "SIS 300/630/540"
+#define DRIVER_DATE "20010503"
+#define DRIVER_MAJOR 1
+#define DRIVER_MINOR 0
+#define DRIVER_PATCHLEVEL 0
+
+#define DRIVER_IOCTLS \
+ [DRM_IOCTL_NR(SIS_IOCTL_FB_ALLOC)] = { sis_fb_alloc, 1, 0 }, \
+ [DRM_IOCTL_NR(SIS_IOCTL_FB_FREE)] = { sis_fb_free, 1, 0 }, \
+ /* AGP Memory Management */ \
+ [DRM_IOCTL_NR(SIS_IOCTL_AGP_INIT)] = { sisp_agp_init, 1, 0 }, \
+ [DRM_IOCTL_NR(SIS_IOCTL_AGP_ALLOC)] = { sisp_agp_alloc, 1, 0 }, \
+ [DRM_IOCTL_NR(SIS_IOCTL_AGP_FREE)] = { sisp_agp_free, 1, 0 }
+#if 0 /* these don't appear to be defined */
+ /* SIS Stereo */
+ [DRM_IOCTL_NR(DRM_IOCTL_CONTROL)] = { sis_control, 1, 1 },
+ [DRM_IOCTL_NR(SIS_IOCTL_FLIP)] = { sis_flip, 1, 1 },
+ [DRM_IOCTL_NR(SIS_IOCTL_FLIP_INIT)] = { sis_flip_init, 1, 1 },
+ [DRM_IOCTL_NR(SIS_IOCTL_FLIP_FINAL)] = { sis_flip_final, 1, 1 }
+#endif
+
+#define __HAVE_COUNTERS 5
+
+#include "drm_auth.h"
+#include "drm_agpsupport.h"
+#include "drm_bufs.h"
+#include "drm_context.h"
+#include "drm_dma.h"
+#include "drm_drawable.h"
+#include "drm_drv.h"
+#include "drm_fops.h"
+#include "drm_init.h"
+#include "drm_ioctl.h"
+#include "drm_lists.h"
+#include "drm_lock.h"
+#include "drm_memory.h"
+#include "drm_proc.h"
+#include "drm_vm.h"
+#include "drm_stub.h"
--- /dev/null
+/* sis_drv.h -- Private header for sis driver -*- linux-c -*-
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef _SIS_DRV_H_
+#define _SIS_DRV_H_
+
+typedef struct drm_sis_private {
+ drm_map_t *buffers;
+} drm_sis_private_t;
+
+/* Stereo ? - this was never committed */
+
+int sis_flip(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg);
+int sis_flip_init(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg);
+int sis_flip_final(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg);
+void flip_final(void);
+
+#endif
--- /dev/null
+/* sis_ds.c -- Private header for Direct Rendering Manager -*- linux-c -*-
+ * Created: Mon Jan 4 10:05:05 1999 by sclin@sis.com.tw
+ *
+ * Copyright 2000 Silicon Integrated Systems Corp, Inc., HsinChu, Taiwan.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Sung-Ching Lin <sclin@sis.com.tw>
+ *
+ */
+
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <asm/io.h>
+#include <linux/pci.h>
+
+#include "sis_ds.h"
+
+/* Set Data Structure, not check repeated value
+ * temporarily used
+ */
+
+set_t *setInit(void)
+{
+ int i;
+ set_t *set;
+
+ set = (set_t *)MALLOC(sizeof(set_t));
+ for(i = 0; i < SET_SIZE; i++){
+ set->list[i].free_next = i+1;
+ set->list[i].alloc_next = -1;
+ }
+ set->list[SET_SIZE-1].free_next = -1;
+ set->free = 0;
+ set->alloc = -1;
+ set->trace = -1;
+
+ return set;
+}
+
+int setAdd(set_t *set, ITEM_TYPE item)
+{
+ int free = set->free;
+
+ if(free != -1){
+ set->list[free].val = item;
+ set->free = set->list[free].free_next;
+ }
+ else{
+ return 0;
+ }
+
+ set->list[free].alloc_next = set->alloc;
+ set->alloc = free;
+ set->list[free].free_next = -1;
+
+ return 1;
+}
+
+int setDel(set_t *set, ITEM_TYPE item)
+{
+ int alloc = set->alloc;
+ int prev = -1;
+
+ while(alloc != -1){
+ if(set->list[alloc].val == item){
+ if(prev != -1)
+ set->list[prev].alloc_next = set->list[alloc].alloc_next;
+ else
+ set->alloc = set->list[alloc].alloc_next;
+ break;
+ }
+ prev = alloc;
+ alloc = set->list[alloc].alloc_next;
+ }
+
+ if(alloc == -1)
+ return 0;
+
+ set->list[alloc].free_next = set->free;
+ set->free = alloc;
+ set->list[alloc].alloc_next = -1;
+
+ return 1;
+}
+
+/* setFirst -> setAdd -> setNext is wrong */
+
+int setFirst(set_t *set, ITEM_TYPE *item)
+{
+ if(set->alloc == -1)
+ return 0;
+
+ *item = set->list[set->alloc].val;
+ set->trace = set->list[set->alloc].alloc_next;
+
+ return 1;
+}
+
+int setNext(set_t *set, ITEM_TYPE *item)
+{
+ if(set->trace == -1)
+ return 0;
+
+ *item = set->list[set->trace].val;
+ set->trace = set->list[set->trace].alloc_next;
+
+ return 1;
+}
+
+int setDestroy(set_t *set)
+{
+ FREE(set);
+
+ return 1;
+}
+
+/*
+ * GLX Hardware Device Driver common code
+ * Copyright (C) 1999 Keith Whitwell
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * KEITH WHITWELL, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
+ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#define ISFREE(bptr) ((bptr)->free)
+
+#define PRINTF(fmt, arg...) do{}while(0)
+#define fprintf(fmt, arg...) do{}while(0)
+
+static void *calloc(size_t nmemb, size_t size)
+{
+ void *addr;
+ addr = kmalloc(nmemb*size, GFP_KERNEL);
+ memset(addr, 0, nmemb*size);
+ return addr;
+}
+#define free(n) kfree(n)
+
+void mmDumpMemInfo( memHeap_t *heap )
+{
+ TMemBlock *p;
+
+ PRINTF ("Memory heap %p:\n", heap);
+ if (heap == 0) {
+ PRINTF (" heap == 0\n");
+ } else {
+ p = (TMemBlock *)heap;
+ while (p) {
+ PRINTF (" Offset:%08x, Size:%08x, %c%c\n",p->ofs,p->size,
+ p->free ? '.':'U',
+ p->reserved ? 'R':'.');
+ p = p->next;
+ }
+ }
+ PRINTF ("End of memory blocks\n");
+}
+
+memHeap_t *mmInit(int ofs,
+ int size)
+{
+ PMemBlock blocks;
+
+ if (size <= 0) {
+ return 0;
+ }
+ blocks = (TMemBlock *) calloc(1,sizeof(TMemBlock));
+ if (blocks) {
+ blocks->ofs = ofs;
+ blocks->size = size;
+ blocks->free = 1;
+ return (memHeap_t *)blocks;
+ } else
+ return 0;
+}
+
+/* Kludgey workaround for existing i810 server. Remove soon.
+ */
+memHeap_t *mmAddRange( memHeap_t *heap,
+ int ofs,
+ int size )
+{
+ PMemBlock blocks;
+ blocks = (TMemBlock *) calloc(2,sizeof(TMemBlock));
+ if (blocks) {
+ blocks[0].size = size;
+ blocks[0].free = 1;
+ blocks[0].ofs = ofs;
+ blocks[0].next = &blocks[1];
+
+ /* Discontinuity - stops JoinBlock from trying to join non-adjacent
+ * ranges.
+ */
+ blocks[1].size = 0;
+ blocks[1].free = 0;
+ blocks[1].ofs = ofs+size;
+ blocks[1].next = (PMemBlock) heap;
+ return (memHeap_t *)blocks;
+ }
+ else
+ return heap;
+}
+
+static TMemBlock* SliceBlock(TMemBlock *p,
+ int startofs, int size,
+ int reserved, int alignment)
+{
+ TMemBlock *newblock;
+
+ /* break left */
+ if (startofs > p->ofs) {
+ newblock = (TMemBlock*) calloc(1,sizeof(TMemBlock));
+ newblock->ofs = startofs;
+ newblock->size = p->size - (startofs - p->ofs);
+ newblock->free = 1;
+ newblock->next = p->next;
+ p->size -= newblock->size;
+ p->next = newblock;
+ p = newblock;
+ }
+
+ /* break right */
+ if (size < p->size) {
+ newblock = (TMemBlock*) calloc(1,sizeof(TMemBlock));
+ newblock->ofs = startofs + size;
+ newblock->size = p->size - size;
+ newblock->free = 1;
+ newblock->next = p->next;
+ p->size = size;
+ p->next = newblock;
+ }
+
+ /* p = middle block */
+ p->align = alignment;
+ p->free = 0;
+ p->reserved = reserved;
+ return p;
+}
+
+PMemBlock mmAllocMem( memHeap_t *heap, int size, int align2, int startSearch)
+{
+ int mask,startofs,endofs;
+ TMemBlock *p;
+
+ if (!heap || align2 < 0 || size <= 0)
+ return NULL;
+ mask = (1 << align2)-1;
+ startofs = 0;
+ p = (TMemBlock *)heap;
+ while (p) {
+ if (ISFREE(p)) {
+ startofs = (p->ofs + mask) & ~mask;
+ if ( startofs < startSearch ) {
+ startofs = startSearch;
+ }
+ endofs = startofs+size;
+ if (endofs <= (p->ofs+p->size))
+ break;
+ }
+ p = p->next;
+ }
+ if (!p)
+ return NULL;
+ p = SliceBlock(p,startofs,size,0,mask+1);
+ p->heap = heap;
+ return p;
+}
+
+static __inline__ int Join2Blocks(TMemBlock *p)
+{
+ if (p->free && p->next && p->next->free) {
+ TMemBlock *q = p->next;
+ p->size += q->size;
+ p->next = q->next;
+ free(q);
+ return 1;
+ }
+ return 0;
+}
+
+int mmFreeMem(PMemBlock b)
+{
+ TMemBlock *p,*prev;
+
+ if (!b)
+ return 0;
+ if (!b->heap) {
+ fprintf(stderr, "no heap\n");
+ return -1;
+ }
+ p = b->heap;
+ prev = NULL;
+ while (p && p != b) {
+ prev = p;
+ p = p->next;
+ }
+ if (!p || p->free || p->reserved) {
+ if (!p)
+ fprintf(stderr, "block not found in heap\n");
+ else if (p->free)
+ fprintf(stderr, "block already free\n");
+ else
+ fprintf(stderr, "block is reserved\n");
+ return -1;
+ }
+ p->free = 1;
+ Join2Blocks(p);
+ if (prev)
+ Join2Blocks(prev);
+ return 0;
+}
+
+int mmReserveMem(memHeap_t *heap, int offset,int size)
+{
+ int endofs;
+ TMemBlock *p;
+
+ if (!heap || size <= 0)
+ return -1;
+ endofs = offset+size;
+ p = (TMemBlock *)heap;
+ while (p && p->ofs <= offset) {
+ if (ISFREE(p) && endofs <= (p->ofs+p->size)) {
+ SliceBlock(p,offset,size,1,1);
+ return 0;
+ }
+ p = p->next;
+ }
+ return -1;
+}
+
+int mmFreeReserved(memHeap_t *heap, int offset)
+{
+ TMemBlock *p,*prev;
+
+ if (!heap)
+ return -1;
+ p = (TMemBlock *)heap;
+ prev = NULL;
+ while (p && p->ofs != offset) {
+ prev = p;
+ p = p->next;
+ }
+ if (!p || !p->reserved)
+ return -1;
+ p->free = 1;
+ p->reserved = 0;
+ Join2Blocks(p);
+ if (prev)
+ Join2Blocks(prev);
+ return 0;
+}
+
+void mmDestroy(memHeap_t *heap)
+{
+ TMemBlock *p,*q;
+
+ if (!heap)
+ return;
+ p = (TMemBlock *)heap;
+ while (p) {
+ q = p->next;
+ free(p);
+ p = q;
+ }
+}
--- /dev/null
+/* sis_ds.h -- Private header for Direct Rendering Manager -*- linux-c -*-
+ * Created: Mon Jan 4 10:05:05 1999 by sclin@sis.com.tw
+ *
+ * Copyright 2000 Silicon Integrated Systems Corp, Inc., HsinChu, Taiwan.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Sung-Ching Lin <sclin@sis.com.tw>
+ *
+ */
+
+#ifndef _sis_ds_h_
+#define _sis_ds_h_
+
+/* Set Data Structure */
+
+#define SET_SIZE 5000
+#define MALLOC(s) kmalloc(s, GFP_KERNEL)
+#define FREE(s) kfree(s)
+
+typedef unsigned int ITEM_TYPE;
+
+typedef struct {
+ ITEM_TYPE val;
+ int alloc_next, free_next;
+} list_item_t;
+
+typedef struct {
+ int alloc;
+ int free;
+ int trace;
+ list_item_t list[SET_SIZE];
+} set_t;
+
+set_t *setInit(void);
+int setAdd(set_t *set, ITEM_TYPE item);
+int setDel(set_t *set, ITEM_TYPE item);
+int setFirst(set_t *set, ITEM_TYPE *item);
+int setNext(set_t *set, ITEM_TYPE *item);
+int setDestroy(set_t *set);
+
+#endif
+
+/*
+ * GLX Hardware Device Driver common code
+ * Copyright (C) 1999 Keith Whitwell
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * KEITH WHITWELL, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
+ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef MM_INC
+#define MM_INC
+
+struct mem_block_t {
+ struct mem_block_t *next;
+ struct mem_block_t *heap;
+ int ofs,size;
+ int align;
+ int free:1;
+ int reserved:1;
+};
+typedef struct mem_block_t TMemBlock;
+typedef struct mem_block_t *PMemBlock;
+
+/* a heap is just the first block in a chain */
+typedef struct mem_block_t memHeap_t;
+
+static __inline__ int mmBlockSize(PMemBlock b)
+{ return b->size; }
+
+static __inline__ int mmOffset(PMemBlock b)
+{ return b->ofs; }
+
+static __inline__ void mmMarkReserved(PMemBlock b)
+{ b->reserved = 1; }
+
+/*
+ * input: total size in bytes
+ * return: a heap pointer if OK, NULL if error
+ */
+memHeap_t *mmInit( int ofs, int size );
+
+
+
+memHeap_t *mmAddRange( memHeap_t *heap,
+ int ofs,
+ int size );
+
+
+/*
+ * Allocate 'size' bytes with 2^align2 bytes alignment,
+ * restrict the search to free memory after 'startSearch'
+ * depth and back buffers should be in different 4mb banks
+ * to get better page hits if possible
+ * input: size = size of block
+ * align2 = 2^align2 bytes alignment
+ * startSearch = linear offset from start of heap to begin search
+ * return: pointer to the allocated block, 0 if error
+ */
+PMemBlock mmAllocMem( memHeap_t *heap, int size, int align2, int startSearch );
+
+/*
+ * Free block starts at offset
+ * input: pointer to a block
+ * return: 0 if OK, -1 if error
+ */
+int mmFreeMem( PMemBlock b );
+
+/*
+ * Reserve 'size' bytes block start at offset
+ * This is used to prevent allocation of memory already used
+ * by the X server for the front buffer, pixmaps, and cursor
+ * input: size, offset
+ * output: 0 if OK, -1 if error
+ */
+int mmReserveMem( memHeap_t *heap, int offset,int size );
+int mmFreeReserved( memHeap_t *heap, int offset );
+
+/*
+ * destroy MM
+ */
+void mmDestroy( memHeap_t *mmInit );
+
+/* For debuging purpose. */
+void mmDumpMemInfo( memHeap_t *mmInit );
+
+#endif
--- /dev/null
+/* sis_mm.c -- Private header for Direct Rendering Manager -*- linux-c -*-
+ * Created: Mon Jan 4 10:05:05 1999 by sclin@sis.com.tw
+ *
+ * Copyright 2000 Silicon Integrated Systems Corp, Inc., HsinChu, Taiwan.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Sung-Ching Lin <sclin@sis.com.tw>
+ *
+ */
+
+#define __NO_VERSION__
+#include "sis.h"
+#include <linux/sisfb.h>
+#include "drmP.h"
+#include "sis_drm.h"
+#include "sis_drv.h"
+#include "sis_ds.h"
+
+#define MAX_CONTEXT 100
+#define VIDEO_TYPE 0
+#define AGP_TYPE 1
+
+typedef struct {
+ int used;
+ int context;
+ set_t *sets[2]; /* 0 for video, 1 for AGP */
+} sis_context_t;
+
+static sis_context_t global_ppriv[MAX_CONTEXT];
+
+static int add_alloc_set(int context, int type, unsigned int val)
+{
+ int i, retval = 0;
+
+ for(i = 0; i < MAX_CONTEXT; i++)
+ if(global_ppriv[i].used && global_ppriv[i].context == context){
+ retval = setAdd(global_ppriv[i].sets[type], val);
+ break;
+ }
+ return retval;
+}
+
+static int del_alloc_set(int context, int type, unsigned int val)
+{
+ int i, retval = 0;
+ for(i = 0; i < MAX_CONTEXT; i++)
+ if(global_ppriv[i].used && global_ppriv[i].context == context){
+ retval = setDel(global_ppriv[i].sets[type], val);
+ break;
+ }
+ return retval;
+}
+
+/* fb management via fb device */
+#if 1
+int sis_fb_alloc(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_sis_mem_t fb;
+ struct sis_memreq req;
+ int retval = 0;
+
+ if (copy_from_user(&fb, (drm_sis_mem_t *)arg, sizeof(fb)))
+ return -EFAULT;
+
+ req.size = fb.size;
+ sis_malloc(&req);
+ if(req.offset){
+ /* TODO */
+ fb.offset = req.offset;
+ fb.free = req.offset;
+ if(!add_alloc_set(fb.context, VIDEO_TYPE, fb.free)){
+ DRM_DEBUG("adding to allocation set fails\n");
+ sis_free(req.offset);
+ retval = -1;
+ }
+ }
+ else{
+ fb.offset = 0;
+ fb.size = 0;
+ fb.free = 0;
+ }
+
+ if (copy_to_user((drm_sis_mem_t *)arg, &fb, sizeof(fb))) return -EFAULT;
+
+ DRM_DEBUG("alloc fb, size = %d, offset = %ld\n", fb.size, req.offset);
+
+ return retval;
+}
+
+int sis_fb_free(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_sis_mem_t fb;
+ int retval = 0;
+
+ if (copy_from_user(&fb, (drm_sis_mem_t *)arg, sizeof(fb)))
+ return -EFAULT;
+
+ if(!fb.free){
+ return -1;
+ }
+
+ sis_free(fb.free);
+ if(!del_alloc_set(fb.context, VIDEO_TYPE, fb.free))
+ retval = -1;
+
+ DRM_DEBUG("free fb, offset = %d\n", fb.free);
+
+ return retval;
+}
+
+#else
+
+int sis_fb_alloc(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ return -1;
+}
+
+int sis_fb_free(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ return 0;
+}
+
+#endif
+
+/* agp memory management */
+#if 1
+
+static memHeap_t *AgpHeap = NULL;
+
+int sisp_agp_init(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_sis_agp_t agp;
+
+ if (copy_from_user(&agp, (drm_sis_agp_t *)arg, sizeof(agp)))
+ return -EFAULT;
+
+ AgpHeap = mmInit(agp.offset, agp.size);
+
+ DRM_DEBUG("offset = %u, size = %u", agp.offset, agp.size);
+
+ return 0;
+}
+
+int sisp_agp_alloc(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_sis_mem_t agp;
+ PMemBlock block;
+ int retval = 0;
+
+ if(!AgpHeap)
+ return -1;
+
+ if (copy_from_user(&agp, (drm_sis_mem_t *)arg, sizeof(agp)))
+ return -EFAULT;
+
+ block = mmAllocMem(AgpHeap, agp.size, 0, 0);
+ if(block){
+ /* TODO */
+ agp.offset = block->ofs;
+ agp.free = (unsigned int)block;
+ if(!add_alloc_set(agp.context, AGP_TYPE, agp.free)){
+ DRM_DEBUG("adding to allocation set fails\n");
+ mmFreeMem((PMemBlock)agp.free);
+ retval = -1;
+ }
+ }
+ else{
+ agp.offset = 0;
+ agp.size = 0;
+ agp.free = 0;
+ }
+
+ if (copy_to_user((drm_sis_mem_t *)arg, &agp, sizeof(agp))) return -EFAULT;
+
+ DRM_DEBUG("alloc agp, size = %d, offset = %d\n", agp.size, agp.offset);
+
+ return retval;
+}
+
+int sisp_agp_free(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_sis_mem_t agp;
+ int retval = 0;
+
+ if(!AgpHeap)
+ return -1;
+
+ if (copy_from_user(&agp, (drm_sis_mem_t *)arg, sizeof(agp)))
+ return -EFAULT;
+
+ if(!agp.free){
+ return -1;
+ }
+
+ mmFreeMem((PMemBlock)agp.free);
+ if(!del_alloc_set(agp.context, AGP_TYPE, agp.free))
+ retval = -1;
+
+ DRM_DEBUG("free agp, free = %d\n", agp.free);
+
+ return retval;
+}
+
+#endif
+
+int sis_init_context(int context)
+{
+ int i;
+
+ for(i = 0; i < MAX_CONTEXT ; i++)
+ if(global_ppriv[i].used && (global_ppriv[i].context == context))
+ break;
+
+ if(i >= MAX_CONTEXT){
+ for(i = 0; i < MAX_CONTEXT ; i++){
+ if(!global_ppriv[i].used){
+ global_ppriv[i].context = context;
+ global_ppriv[i].used = 1;
+ global_ppriv[i].sets[0] = setInit();
+ global_ppriv[i].sets[1] = setInit();
+ DRM_DEBUG("init allocation set, socket=%d, context = %d\n",
+ i, context);
+ break;
+ }
+ }
+ if((i >= MAX_CONTEXT) || (global_ppriv[i].sets[0] == NULL) ||
+ (global_ppriv[i].sets[1] == NULL)){
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+int sis_final_context(int context)
+{
+ int i;
+
+ for(i=0; i<MAX_CONTEXT; i++)
+ if(global_ppriv[i].used && (global_ppriv[i].context == context))
+ break;
+
+ if(i < MAX_CONTEXT){
+ set_t *set;
+ unsigned int item;
+ int retval;
+
+ DRM_DEBUG("find socket %d, context = %d\n", i, context);
+
+ /* Video Memory */
+ set = global_ppriv[i].sets[0];
+ retval = setFirst(set, &item);
+ while(retval){
+ DRM_DEBUG("free video memory 0x%x\n", item);
+ sis_free(item);
+ retval = setNext(set, &item);
+ }
+ setDestroy(set);
+
+ /* AGP Memory */
+ set = global_ppriv[i].sets[1];
+ retval = setFirst(set, &item);
+ while(retval){
+ DRM_DEBUG("free agp memory 0x%x\n", item);
+ mmFreeMem((PMemBlock)item);
+ retval = setNext(set, &item);
+ }
+ setDestroy(set);
+
+ global_ppriv[i].used = 0;
+ }
+
+ /* turn-off auto-flip */
+ /* TODO */
+#if defined(SIS_STEREO)
+ flip_final();
+#endif
+
+ return 1;
+}