diff options
| author | Patrick Mochel <mochel@osdl.org> | 2002-09-24 03:26:44 -0700 |
|---|---|---|
| committer | Patrick Mochel <mochel@osdl.org> | 2002-09-24 03:26:44 -0700 |
| commit | cd585d2fff68c7295e524fb540a91cb4318394dc (patch) | |
| tree | 1e86e79f27df65b163f1861b69142df93affaea8 | |
| parent | f6bec0e641f80b097536fc4f8a1d8e7d2cc5c30b (diff) | |
| parent | a9ee74e7051a423db2f5c76723106d12fb756365 (diff) | |
Merge osdl.org:/home/mochel/src/kernel/devel/linux-2.5-virgin
into osdl.org:/home/mochel/src/kernel/devel/linux-2.5
27 files changed, 1034 insertions, 409 deletions
diff --git a/arch/alpha/Makefile b/arch/alpha/Makefile index c60b28e7c709..15284069e87a 100644 --- a/arch/alpha/Makefile +++ b/arch/alpha/Makefile @@ -91,9 +91,9 @@ CFLAGS := $(CFLAGS) -Wa,-mev6 HEAD := arch/alpha/kernel/head.o -core-y := arch/alpha/kernel/ arch/alpha/mm/ -core-$(CONFIG_MATHEMU) += arch/alpha/math-emu/built-in.o -libs-y := arch/alpha/lib +core-y += arch/alpha/kernel/ arch/alpha/mm/ +core-$(CONFIG_MATHEMU) += arch/alpha/math-emu/ +libs-y += arch/alpha/lib/ MAKEBOOT = $(MAKE) -C arch/alpha/boot diff --git a/arch/alpha/kernel/entry.S b/arch/alpha/kernel/entry.S index 144cafd1086a..0e931707a28f 100644 --- a/arch/alpha/kernel/entry.S +++ b/arch/alpha/kernel/entry.S @@ -1119,3 +1119,27 @@ sys_call_table: .quad sys_readahead .quad sys_ni_syscall /* 380, sys_security */ .quad sys_tkill + .quad sys_setxattr + .quad sys_lsetxattr + .quad sys_fsetxattr + .quad sys_getxattr + .quad sys_lgetxattr + .quad sys_fgetxattr + .quad sys_listxattr + .quad sys_llistxattr + .quad sys_flistxattr /* 390 */ + .quad sys_removexattr + .quad sys_lremovexattr + .quad sys_fremovexattr + .quad sys_futex + .quad sys_sched_setaffinity + .quad sys_sched_getaffinity + .quad sys_ni_syscall /* 397, tux */ + .quad sys_io_setup + .quad sys_io_destroy + .quad sys_io_getevents /* 400 */ + .quad sys_io_submit + .quad sys_io_cancel + .quad sys_ni_syscall /* 403, sys_alloc_hugepages */ + .quad sys_ni_syscall /* 404, sys_free_hugepages */ + .quad sys_exit_group diff --git a/arch/alpha/lib/Makefile b/arch/alpha/lib/Makefile index 7f9b3e112c4c..6f5cf9b48e3f 100644 --- a/arch/alpha/lib/Makefile +++ b/arch/alpha/lib/Makefile @@ -2,7 +2,7 @@ # Makefile for alpha-specific library files.. # -EXTRA_AFLAGS := $(CFLAGS) +L_TARGET := lib.a # Many of these routines have implementations tuned for ev6. # Choose them iff we're targeting ev6 specifically. @@ -17,7 +17,7 @@ ifeq ($(CONFIG_ALPHA_EV67),y) ev67 := ev67- endif -OBJS = __divqu.o __remqu.o __divlu.o __remlu.o \ +obj-y = __divqu.o __remqu.o __divlu.o __remlu.o \ udelay.o \ $(ev6)memset.o \ $(ev6)memcpy.o \ @@ -46,12 +46,9 @@ OBJS = __divqu.o __remqu.o __divlu.o __remlu.o \ fpreg.o \ callback_srm.o srm_puts.o srm_printk.o -ifeq ($(CONFIG_SMP),y) - OBJS += dec_and_lock.o -endif +obj-$(CONFIG_SMP) += dec_and_lock.o -lib.a: $(OBJS) - $(AR) rcs lib.a $(OBJS) +include $(TOPDIR)/Rules.make __divqu.o: $(ev6)divide.S $(CC) $(AFLAGS) -DDIV -c -o __divqu.o $(ev6)divide.S @@ -64,5 +61,3 @@ __divlu.o: $(ev6)divide.S __remlu.o: $(ev6)divide.S $(CC) $(AFLAGS) -DREM -DINTSIZE -c -o __remlu.o $(ev6)divide.S - -include $(TOPDIR)/Rules.make diff --git a/arch/alpha/math-emu/Makefile b/arch/alpha/math-emu/Makefile index 17ce0de4e8de..083d51340c3e 100644 --- a/arch/alpha/math-emu/Makefile +++ b/arch/alpha/math-emu/Makefile @@ -2,10 +2,8 @@ # Makefile for the FPU instruction emulation. # -obj-$(CONFIG_MATHEMU) += math-emu.o - -math-emu-objs := math.o qrnnd.o - CFLAGS += -I. -I$(TOPDIR)/include/math-emu -w +obj-$(CONFIG_MATHEMU) += math.o qrnnd.o + include $(TOPDIR)/Rules.make diff --git a/drivers/block/elevator.c b/drivers/block/elevator.c index 15bfca03f35b..10729a1f0c1c 100644 --- a/drivers/block/elevator.c +++ b/drivers/block/elevator.c @@ -157,13 +157,20 @@ inline int elv_try_last_merge(request_queue_t *q, struct request **req, return ret; } +static int bio_rq_before(struct bio *bio, struct request *rq) +{ + if (!kdev_same(to_kdev_t(bio->bi_bdev->bd_dev), rq->rq_dev)) + return 0; + return bio->bi_sector < rq->sector; +} + /* * elevator_linux starts here */ int elevator_linus_merge(request_queue_t *q, struct request **req, struct bio *bio) { - struct list_head *entry; + struct list_head *entry, *good; struct request *__rq; int ret; @@ -171,6 +178,7 @@ int elevator_linus_merge(request_queue_t *q, struct request **req, return ret; entry = &q->queue_head; + good = &q->queue_head; ret = ELEVATOR_NO_MERGE; while ((entry = entry->prev) != &q->queue_head) { __rq = list_entry_rq(entry); @@ -178,37 +186,31 @@ int elevator_linus_merge(request_queue_t *q, struct request **req, if (__rq->flags & (REQ_BARRIER | REQ_STARTED)) break; if (!(__rq->flags & REQ_CMD)) - continue; - - if (elv_linus_sequence(__rq) < bio_sectors(bio)) break; - if (!*req && bio_rq_in_between(bio, __rq, &q->queue_head)) - *req = __rq; + if (bio_data_dir(bio) != rq_data_dir(__rq)) { + if (bio_data_dir(bio) == WRITE) + break; + good = entry->prev; + continue; + } - if ((ret = elv_try_merge(__rq, bio))) { - if (ret == ELEVATOR_FRONT_MERGE) - elv_linus_sequence(__rq) -= bio_sectors(bio); + ret = elv_try_merge(__rq, bio); + if (ret) { *req = __rq; q->last_merge = &__rq->queuelist; - break; + return ret; } - } - /* - * if *req, it's either a seek or merge in the middle of the queue - */ - if (*req) { - struct list_head *entry = &(*req)->queuelist; - int cost = ret ? 1 : ELV_LINUS_SEEK_COST; + if (bio_rq_before(bio, __rq)) + good = entry->prev; - while ((entry = entry->next) != &q->queue_head) { - __rq = list_entry_rq(entry); - elv_linus_sequence(__rq) -= cost; - } } - return ret; + if (good != &q->queue_head) + *req = list_entry_rq(good); + + return ELEVATOR_NO_MERGE; } void elevator_linus_merge_req(request_queue_t *q, struct request *req, diff --git a/drivers/char/drm/Makefile b/drivers/char/drm/Makefile index b7da9f2a71af..6a5eb1823335 100644 --- a/drivers/char/drm/Makefile +++ b/drivers/char/drm/Makefile @@ -8,7 +8,7 @@ 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 +radeon-objs := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o ffb-objs := ffb_drv.o ffb_context.o obj-$(CONFIG_DRM_GAMMA) += gamma.o diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h index b999bbae9e61..2b10c6a9db89 100644 --- a/drivers/char/drm/drmP.h +++ b/drivers/char/drm/drmP.h @@ -165,7 +165,7 @@ #define pte_unmap(pte) #endif -#if LINUX_VERSION_CODE < 0x020413 /* KERNEL_VERSION(2,4,19) */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,19) static inline struct page * vmalloc_to_page(void * vmalloc_addr) { unsigned long addr = (unsigned long) vmalloc_addr; @@ -190,7 +190,7 @@ static inline struct page * vmalloc_to_page(void * vmalloc_addr) } #endif -#if LINUX_VERSION_CODE < 0x020500 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) #define DRM_RPR_ARG(vma) #else #define DRM_RPR_ARG(vma) vma, @@ -597,7 +597,7 @@ typedef struct drm_device { #endif struct pci_dev *pdev; #ifdef __alpha__ -#if LINUX_VERSION_CODE < 0x020403 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,3) struct pci_controler *hose; #else struct pci_controller *hose; diff --git a/drivers/char/drm/drm_bufs.h b/drivers/char/drm/drm_bufs.h index 3ff3527f6172..9ce7cfff7926 100644 --- a/drivers/char/drm/drm_bufs.h +++ b/drivers/char/drm/drm_bufs.h @@ -137,6 +137,7 @@ int DRM(addmap)( struct inode *inode, struct file *filp, } map->offset = (unsigned long)map->handle; if ( map->flags & _DRM_CONTAINS_LOCK ) { + dev->sigdata.lock = dev->lock.hw_lock = map->handle; /* Pointer to lock */ } break; diff --git a/drivers/char/drm/drm_drv.h b/drivers/char/drm/drm_drv.h index 81bd78948826..7e2cfd8c561a 100644 --- a/drivers/char/drm/drm_drv.h +++ b/drivers/char/drm/drm_drv.h @@ -306,7 +306,7 @@ static int DRM(setup)( drm_device_t *dev ) dev->map_count = 0; dev->vmalist = NULL; - dev->lock.hw_lock = NULL; + dev->sigdata.lock = dev->lock.hw_lock = NULL; init_waitqueue_head( &dev->lock.lock_queue ); dev->queue_count = 0; dev->queue_reserved = 0; @@ -491,7 +491,7 @@ static int DRM(takedown)( drm_device_t *dev ) DRM(dma_takedown)( dev ); #endif if ( dev->lock.hw_lock ) { - dev->lock.hw_lock = NULL; /* SHM removed */ + dev->sigdata.lock = dev->lock.hw_lock = NULL; /* SHM removed */ dev->lock.pid = 0; wake_up_interruptible( &dev->lock.lock_queue ); } diff --git a/drivers/char/drm/drm_lock.h b/drivers/char/drm/drm_lock.h index c10cfe2c08c7..c887d1f66f91 100644 --- a/drivers/char/drm/drm_lock.h +++ b/drivers/char/drm/drm_lock.h @@ -237,7 +237,7 @@ int DRM(notifier)(void *priv) /* Allow signal delivery if lock isn't held */ - if (!_DRM_LOCK_IS_HELD(s->lock->lock) + if (!s->lock || !_DRM_LOCK_IS_HELD(s->lock->lock) || _DRM_LOCKING_CONTEXT(s->lock->lock) != s->context) return 1; /* Otherwise, set flag to force call to diff --git a/drivers/char/drm/drm_os_linux.h b/drivers/char/drm/drm_os_linux.h index 8c073f0babf5..cb3043983572 100644 --- a/drivers/char/drm/drm_os_linux.h +++ b/drivers/char/drm/drm_os_linux.h @@ -16,6 +16,9 @@ #define DRM_DEVICE drm_file_t *priv = filp->private_data; \ drm_device_t *dev = priv->dev +#define DRM_IRQ_ARGS int irq, void *arg, struct pt_regs *regs +#define DRM_TASKQUEUE_ARGS void *arg + /* For data going from/to the kernel through the ioctl argument */ #define DRM_COPY_FROM_USER_IOCTL(arg1, arg2, arg3) \ if ( copy_from_user(&arg1, arg2, arg3) ) \ diff --git a/drivers/char/drm/i830.h b/drivers/char/drm/i830.h index 794588b2a40f..b97521882da2 100644 --- a/drivers/char/drm/i830.h +++ b/drivers/char/drm/i830.h @@ -45,11 +45,11 @@ #define DRIVER_NAME "i830" #define DRIVER_DESC "Intel 830M" -#define DRIVER_DATE "20011004" +#define DRIVER_DATE "20020828" #define DRIVER_MAJOR 1 #define DRIVER_MINOR 2 -#define DRIVER_PATCHLEVEL 0 +#define DRIVER_PATCHLEVEL 1 #define DRIVER_IOCTLS \ [DRM_IOCTL_NR(DRM_IOCTL_I830_INIT)] = { i830_dma_init, 1, 1 }, \ @@ -87,50 +87,10 @@ 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) +/* 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: */ diff --git a/drivers/char/drm/i830_dma.c b/drivers/char/drm/i830_dma.c index 643259fc8c3d..70884373d5b0 100644 --- a/drivers/char/drm/i830_dma.c +++ b/drivers/char/drm/i830_dma.c @@ -26,8 +26,8 @@ * * 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> + * Keith Whitwell <keith@tungstengraphics.com> + * Abraham vd Merwe <abraham@2d3d.co.za> * */ @@ -40,9 +40,10 @@ #include <linux/interrupt.h> /* For task queue support */ #include <linux/delay.h> -/* in case we don't have a 2.3.99-pre6 kernel or later: */ -#ifndef VM_DONTCOPY -#define VM_DONTCOPY 0 +#ifdef DO_MUNMAP_4_ARGS +#define DO_MUNMAP(m, a, l) do_munmap(m, a, l, 1) +#else +#define DO_MUNMAP(m, a, l) do_munmap(m, a, l) #endif #define I830_BUF_FREE 2 @@ -54,26 +55,24 @@ #define RING_LOCALS unsigned int outring, ringmask; volatile char *virt; +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,4,2) +#define down_write down +#define up_write up +#endif -#define DO_IDLE_WORKAROUND() \ -do { \ - int _head; \ - int _tail; \ - 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) +#ifndef LockPage +#define LockPage(page) set_bit(PG_locked, &(page)->flags) +#endif +#ifndef UnlockPage +#define UnlockPage(page) unlock_page(page) +#endif -#define I830_SYNC_WORKAROUND 0 +#define I830_VERBOSE 0 #define BEGIN_LP_RING(n) do { \ if (I830_VERBOSE) \ - DRM_DEBUG("BEGIN_LP_RING(%d) in %s\n", \ + printk("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; \ @@ -83,13 +82,13 @@ do { \ } while (0) #define ADVANCE_LP_RING() do { \ - if (I830_VERBOSE) DRM_DEBUG("ADVANCE_LP_RING\n"); \ + if (I830_VERBOSE) printk("ADVANCE_LP_RING %x\n", outring); \ 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)); \ + if (I830_VERBOSE) printk(" OUT_RING %x\n", (int)(n)); \ *(volatile unsigned int *)(virt + outring) = n; \ outring += 4; \ outring &= ringmask; \ @@ -201,36 +200,24 @@ static int i830_map_buffer(drm_buf_t *buf, struct file *filp) 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; + down_write( ¤t->mm->mmap_sem ); + 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_ERROR("mmap error\n"); + retcode = (signed int)buf_priv->virtual; + buf_priv->virtual = 0; } + up_write( ¤t->mm->mmap_sem ); + return retcode; } @@ -239,25 +226,15 @@ 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 + if(buf_priv->currently_mapped != I830_BUF_MAPPED) + return -EINVAL; - retcode = do_munmap(current->mm, - (unsigned long)buf_priv->virtual, - (size_t) buf->total); + down_write(¤t->mm->mmap_sem); + retcode = DO_MUNMAP(current->mm, + (unsigned long)buf_priv->virtual, + (size_t) buf->total); + up_write(¤t->mm->mmap_sem); -#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; @@ -275,14 +252,14 @@ static int i830_dma_get_buffer(drm_device_t *dev, drm_i830_dma_t *d, buf = i830_freelist_get(dev); if (!buf) { retcode = -ENOMEM; - DRM_DEBUG("retcode=%d\n", retcode); + DRM_ERROR("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); + DRM_ERROR("mapbuf failed, retcode %d\n", retcode); return retcode; } buf->pid = priv->pid; @@ -303,32 +280,17 @@ static unsigned long i830_alloc_page(drm_device_t *dev) if(address == 0UL) return 0; -#if LINUX_VERSION_CODE < 0x020409 - atomic_inc(&virt_to_page(address)->count); - set_bit(PG_locked, &virt_to_page(address)->flags); -#else get_page(virt_to_page(address)); -#if LINUX_VERSION_CODE < 0x020500 LockPage(virt_to_page(address)); -#else - SetPageLocked(virt_to_page(address)); -#endif -#endif return address; } static void i830_free_page(drm_device_t *dev, unsigned long page) { if (page) { -#if LINUX_VERSION_CODE < 0x020409 - 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 + UnlockPage(p); free_page(page); } } @@ -384,7 +346,7 @@ static int i830_wait_ring(drm_device_t *dev, int n) } iters++; - if((signed)(end - jiffies) <= 0) { + if(time_before(end, jiffies)) { DRM_ERROR("space: %d wanted %d\n", ring->space, n); DRM_ERROR("lockup\n"); goto out_wait_ring; @@ -402,7 +364,7 @@ static void i830_kernel_lost_context(drm_device_t *dev) 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->tail = I830_READ(LP_RING + RING_TAIL) & TAIL_ADDR; ring->space = ring->head - (ring->tail+8); if (ring->space < 0) ring->space += ring->Size; } @@ -478,9 +440,6 @@ static int i830_dma_initialize(drm_device_t *dev, ((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; @@ -504,11 +463,17 @@ static int i830_dma_initialize(drm_device_t *dev, dev_priv->pitch = init->pitch; dev_priv->back_offset = init->back_offset; dev_priv->depth_offset = init->depth_offset; + dev_priv->front_offset = init->front_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; + DRM_DEBUG("front_di1 %x\n", dev_priv->front_di1); + DRM_DEBUG("back_offset %x\n", dev_priv->back_offset); + DRM_DEBUG("back_di1 %x\n", dev_priv->back_di1); + DRM_DEBUG("pitch_bits %x\n", init->pitch_bits); + dev_priv->cpp = init->cpp; /* We are using seperate values as placeholders for mechanisms for * private backbuffer/depthbuffer usage. @@ -574,38 +539,57 @@ int i830_dma_init(struct inode *inode, struct file *filp, return retcode; } +#define GFX_OP_STIPPLE ((0x3<<29)|(0x1d<<24)|(0x83<<16)) +#define ST1_ENABLE (1<<16) +#define ST1_MASK (0xffff) + /* 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 ) +static void i830EmitContextVerified( drm_device_t *dev, + 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++ ) { + BEGIN_LP_RING( I830_CTX_SETUP_SIZE + 2 ); + + OUT_RING( GFX_OP_STIPPLE ); + OUT_RING( 0 ); + + + for ( i = 0 ; i < I830_CTXREG_BLENDCOLR0 ; i++ ) { tmp = code[i]; + if ((tmp & (7<<29)) == CMD_3D && + (tmp & (0x1f<<24)) < (0x1d<<24)) { + OUT_RING( tmp ); + j++; + } else { + DRM_ERROR("Skipping %d\n", i); + } + } + + OUT_RING( STATE3D_CONST_BLEND_COLOR_CMD ); + OUT_RING( code[I830_CTXREG_BLENDCOLR] ); + j += 2; -#if 0 - if ((tmp & (7<<29)) == (3<<29) && + for ( i = I830_CTXREG_VF ; i < I830_CTXREG_MCSB0 ; i++ ) { + tmp = code[i]; + if ((tmp & (7<<29)) == CMD_3D && (tmp & (0x1f<<24)) < (0x1d<<24)) { OUT_RING( tmp ); j++; } else { - printk("Skipping %d\n", i); + DRM_ERROR("Skipping %d\n", i); } -#else - OUT_RING( tmp ); - j++; -#endif } + OUT_RING( STATE3D_MAP_COORD_SETBIND_CMD ); + OUT_RING( code[I830_CTXREG_MCSB1] ); + j += 2; + if (j & 1) OUT_RING( 0 ); @@ -650,6 +634,9 @@ static void i830EmitTexBlendVerified( drm_device_t *dev, unsigned int tmp; RING_LOCALS; + if (!num) + return; + BEGIN_LP_RING( num ); for ( i = 0 ; i < num ; i++ ) { @@ -723,7 +710,7 @@ static void i830EmitDestVerified( drm_device_t *dev, 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", + DRM_ERROR("bad di1 %x (allow %x or %x)\n", tmp, dev_priv->front_di1, dev_priv->back_di1); } @@ -745,7 +732,7 @@ static void i830EmitDestVerified( drm_device_t *dev, if((tmp & ~0x3) == GFX_OP_SCISSOR_ENABLE) { OUT_RING( tmp ); } else { - DRM_DEBUG("bad scissor enable\n"); + DRM_ERROR("bad scissor enable\n"); OUT_RING( 0 ); } @@ -865,7 +852,7 @@ static void i830_dma_dispatch_clear( drm_device_t *dev, int flags, OUT_RING( BR13 ); OUT_RING( (pbox->y1 << 16) | pbox->x1 ); OUT_RING( (pbox->y2 << 16) | pbox->x2 ); - OUT_RING( 0 ); + OUT_RING( dev_priv->front_offset ); OUT_RING( clear_color ); ADVANCE_LP_RING(); } @@ -953,7 +940,7 @@ static void i830_dma_dispatch_swap( drm_device_t *dev ) OUT_RING( (pbox->y2 << 16) | pbox->x2 ); - OUT_RING( 0 /* front ofs always zero */ ); + OUT_RING( dev_priv->front_offset ); OUT_RING( (pbox->y1 << 16) | pbox->x1 ); @@ -993,7 +980,7 @@ static void i830_dma_dispatch_vertex(drm_device_t *dev, } } - if (used > 4*1024) + if (used > 4*1023) used = 0; if (sarea_priv->dirty) @@ -1010,12 +997,17 @@ static void i830_dma_dispatch_vertex(drm_device_t *dev, 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)); + u32 *vp = buf_priv->virtual; + + vp[0] = (GFX_OP_PRIMITIVE | + sarea_priv->vertex_prim | + ((used/4)-2)); + + vp[used/4] = MI_BATCH_BUFFER_END; + used += 4; if (used & 4) { - *(u32 *)((u32)buf_priv->virtual + used) = 0; + vp[used/4] = 0; used += 4; } @@ -1035,80 +1027,35 @@ static void i830_dma_dispatch_vertex(drm_device_t *dev, ADVANCE_LP_RING(); } - BEGIN_LP_RING(4); - - OUT_RING( MI_BATCH_BUFFER ); + BEGIN_LP_RING(2); + OUT_RING( MI_BATCH_BUFFER_START | (2<<6) ); 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) { + dev_priv->counter++; + + (void) cmpxchg(buf_priv->in_use, I830_BUF_CLIENT, + I830_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( I830_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 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) +void i830_dma_quiescent(drm_device_t *dev) { drm_i830_private_t *dev_priv = dev->dev_private; RING_LOCALS; @@ -1119,79 +1066,27 @@ static inline void i830_dma_quiescent_emit(drm_device_t *dev) 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(); 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_i830_private_t *dev_priv = dev->dev_private; drm_device_dma_t *dma = dev->dma; - unsigned long end; - int i, ret = 0; + int i, ret = 0; + RING_LOCALS; + + i830_kernel_lost_context(dev); - 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); + BEGIN_LP_RING(2); + OUT_RING( CMD_REPORT_HEAD ); + OUT_RING( 0 ); + ADVANCE_LP_RING(); + i830_wait_ring( dev, dev_priv->ring.Size - 8 ); for (i = 0; i < dma->buf_count; i++) { drm_buf_t *buf = dma->buflist[ i ]; @@ -1203,7 +1098,7 @@ static int i830_flush_queue(drm_device_t *dev) if (used == I830_BUF_HARDWARE) DRM_DEBUG("reclaimed from HARDWARE\n"); if (used == I830_BUF_CLIENT) - DRM_DEBUG("still on client HARDWARE\n"); + DRM_DEBUG("still on client\n"); } return ret; @@ -1242,8 +1137,7 @@ int i830_flush_ioctl(struct inode *inode, struct file *filp, { 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; @@ -1381,46 +1275,17 @@ int i830_getbuf(struct inode *inode, struct file *filp, unsigned int cmd, return retcode; } -int i830_copybuf(struct inode *inode, struct file *filp, unsigned int cmd, - unsigned long arg) +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]; - + /* Never copy - 2.4.x doesn't need it */ 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; } diff --git a/drivers/char/drm/i830_drv.c b/drivers/char/drm/i830_drv.c index b5efcef3133a..d9a659a44a42 100644 --- a/drivers/char/drm/i830_drv.c +++ b/drivers/char/drm/i830_drv.c @@ -29,6 +29,7 @@ * Jeff Hartmann <jhartmann@valinux.com> * Gareth Hughes <gareth@valinux.com> * Abraham vd Merwe <abraham@2d3d.co.za> + * Keith Whitwell <keith@tungstengraphics.com> */ #include <linux/config.h> diff --git a/drivers/char/drm/i830_drv.h b/drivers/char/drm/i830_drv.h index 4e9d6c807fd5..527d0ce3d3c4 100644 --- a/drivers/char/drm/i830_drv.h +++ b/drivers/char/drm/i830_drv.h @@ -64,14 +64,13 @@ typedef struct drm_i830_private { 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 front_offset; int w, h; int pitch; int back_pitch; @@ -107,14 +106,13 @@ extern int i830_swap_bufs(struct inode *inode, struct file *filp, 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_DEREF(reg) *(__volatile__ unsigned int *)I830_ADDR(reg) +#define I830_READ(reg) readl((volatile u32 *)I830_ADDR(reg)) +#define I830_WRITE(reg,val) writel(val, (volatile u32 *)I830_ADDR(reg)) #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) @@ -143,15 +141,15 @@ extern int i830_clear_bufs(struct inode *inode, struct file *filp, #define LP_RING 0x2030 #define HP_RING 0x2040 #define RING_TAIL 0x00 -#define TAIL_ADDR 0x000FFFF8 +#define TAIL_ADDR 0x001FFFF8 #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 START_ADDR 0x0xFFFFF000 #define RING_LEN 0x0C -#define RING_NR_PAGES 0x000FF000 +#define RING_NR_PAGES 0x001FF000 #define RING_REPORT_MASK 0x00000006 #define RING_REPORT_64K 0x00000002 #define RING_REPORT_128K 0x00000004 @@ -182,6 +180,9 @@ extern int i830_clear_bufs(struct inode *inode, struct file *filp, #define CMD_OP_DESTBUFFER_INFO ((0x3<<29)|(0x1d<<24)|(0x8e<<16)|1) +#define CMD_3D (0x3<<29) +#define STATE3D_CONST_BLEND_COLOR_CMD (CMD_3D|(0x1d<<24)|(0x88<<16)) +#define STATE3D_MAP_COORD_SETBIND_CMD (CMD_3D|(0x1d<<24)|(0x02<<16)) #define BR00_BITBLT_CLIENT 0x40000000 #define BR00_OP_COLOR_BLT 0x10000000 @@ -206,6 +207,8 @@ extern int i830_clear_bufs(struct inode *inode, struct file *filp, #define XY_SRC_COPY_BLT_WRITE_RGB (1<<20) #define MI_BATCH_BUFFER ((0x30<<23)|1) +#define MI_BATCH_BUFFER_START (0x31<<23) +#define MI_BATCH_BUFFER_END (0xA<<23) #define MI_BATCH_NON_SECURE (1) diff --git a/drivers/char/drm/radeon.h b/drivers/char/drm/radeon.h index 885e4297ff9c..69e16b37d092 100644 --- a/drivers/char/drm/radeon.h +++ b/drivers/char/drm/radeon.h @@ -48,10 +48,10 @@ #define DRIVER_NAME "radeon" #define DRIVER_DESC "ATI Radeon" -#define DRIVER_DATE "20020611" +#define DRIVER_DATE "20020828" #define DRIVER_MAJOR 1 -#define DRIVER_MINOR 5 +#define DRIVER_MINOR 6 #define DRIVER_PATCHLEVEL 0 /* Interface history: @@ -68,6 +68,11 @@ * 1.5 - Add r200 packets to cmdbuf ioctl * - Add r200 function to init ioctl * - Add 'scalar2' instruction to cmdbuf + * 1.6 - Add static agp memory manager + * Add irq handler (won't be turned on unless X server knows to) + * Add irq ioctls and irq_active getparam. + * Add wait command for cmdbuf ioctl + * Add agp offset query for getparam */ #define DRIVER_IOCTLS \ [DRM_IOCTL_NR(DRM_IOCTL_DMA)] = { radeon_cp_buffers, 1, 0 }, \ @@ -88,9 +93,18 @@ [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 }, + [DRM_IOCTL_NR(DRM_IOCTL_RADEON_FLIP)] = { radeon_cp_flip, 1, 0 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_RADEON_ALLOC)] = { radeon_mem_alloc, 1, 0 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_RADEON_FREE)] = { radeon_mem_free, 1, 0 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_RADEON_INIT_HEAP)] = { radeon_mem_init_heap, 1, 1 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_RADEON_IRQ_EMIT)] = { radeon_irq_emit, 1, 0 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_RADEON_IRQ_WAIT)] = { radeon_irq_wait, 1, 0 }, -/* Driver customization: +/* When a client dies: + * - Check for and clean up flipped page state + * - Free any alloced agp memory. + * + * DRM infrastructure takes care of reclaiming dma buffers. */ #define DRIVER_PRERELEASE() do { \ if ( dev->dev_private ) { \ @@ -98,22 +112,78 @@ if ( dev_priv->page_flipping ) { \ radeon_do_cleanup_pageflip( dev ); \ } \ + radeon_mem_release( dev_priv->agp_heap ); \ } \ } while (0) +/* On unloading the module: + * - Free memory heap structure + * - Remove mappings made at startup and free dev_private. + */ #define DRIVER_PRETAKEDOWN() do { \ - if ( dev->dev_private ) radeon_do_cleanup_cp( dev ); \ + if ( dev->dev_private ) { \ + drm_radeon_private_t *dev_priv = dev->dev_private; \ + radeon_mem_takedown( &(dev_priv->agp_heap) ); \ + radeon_do_cleanup_cp( dev ); \ + } \ } while (0) /* DMA customization: */ #define __HAVE_DMA 1 + +#define __HAVE_DMA_IRQ 1 +#define __HAVE_DMA_IRQ_BH 1 +#define __HAVE_SHARED_IRQ 1 + +#define DRIVER_PREINSTALL() do { \ + drm_radeon_private_t *dev_priv = \ + (drm_radeon_private_t *)dev->dev_private; \ + u32 tmp; \ + \ + /* Clear bit if it's already high: */ \ + tmp = RADEON_READ( RADEON_GEN_INT_STATUS ); \ + tmp = tmp & RADEON_SW_INT_TEST_ACK; \ + RADEON_WRITE( RADEON_GEN_INT_STATUS, tmp ); \ + \ + /* Disable *all* interrupts */ \ + RADEON_WRITE( RADEON_GEN_INT_CNTL, 0 ); \ +} while (0) + +#ifdef __linux__ +#define IWH(x) init_waitqueue_head(x) +#else +#define IWH(x) +#endif + +#define DRIVER_POSTINSTALL() do { \ + drm_radeon_private_t *dev_priv = \ + (drm_radeon_private_t *)dev->dev_private; \ + \ + atomic_set(&dev_priv->irq_received, 0); \ + atomic_set(&dev_priv->irq_emitted, 0); \ + IWH(&dev_priv->irq_queue); \ + \ + /* Turn on SW_INT only */ \ + RADEON_WRITE( RADEON_GEN_INT_CNTL, \ + RADEON_SW_INT_ENABLE ); \ +} while (0) + +#define DRIVER_UNINSTALL() do { \ + drm_radeon_private_t *dev_priv = \ + (drm_radeon_private_t *)dev->dev_private; \ + if ( dev_priv ) { \ + /* Disable *all* interrupts */ \ + RADEON_WRITE( RADEON_GEN_INT_CNTL, 0 ); \ + } \ +} while (0) + /* Buffer customization: */ #define DRIVER_BUF_PRIV_T drm_radeon_buf_priv_t -#define DRIVER_AGP_BUFFERS_MAP( dev ) \ +#define DRIVER_AGP_BUFFERS_MAP( dev ) \ ((drm_radeon_private_t *)((dev)->dev_private))->buffers #endif diff --git a/drivers/char/drm/radeon_cp.c b/drivers/char/drm/radeon_cp.c index 86ea01bc808b..c0fb63ef1812 100644 --- a/drivers/char/drm/radeon_cp.c +++ b/drivers/char/drm/radeon_cp.c @@ -1412,6 +1412,9 @@ int radeon_cp_idle( DRM_IOCTL_ARGS ) LOCK_TEST_WITH_RETURN( dev ); +/* if (dev->irq) */ +/* radeon_emit_and_wait_irq( dev ); */ + return radeon_do_cp_idle( dev_priv ); } diff --git a/drivers/char/drm/radeon_drm.h b/drivers/char/drm/radeon_drm.h index 6469bfb8033c..9a747e049b51 100644 --- a/drivers/char/drm/radeon_drm.h +++ b/drivers/char/drm/radeon_drm.h @@ -142,6 +142,9 @@ #define RADEON_CMD_PACKET3 5 /* emit hw packet */ #define RADEON_CMD_PACKET3_CLIP 6 /* emit hw packet wrapped in cliprects */ #define RADEON_CMD_SCALARS2 7 /* r200 stopgap */ +#define RADEON_CMD_WAIT 8 /* emit hw wait commands -- note: + * doesn't make the cpu wait, just + * the graphics hardware */ typedef union { @@ -161,8 +164,14 @@ typedef union { struct { unsigned char cmd_type, buf_idx, pad0, pad1; } dma; + struct { + unsigned char cmd_type, flags, pad0, pad1; + } wait; } drm_radeon_cmd_header_t; +#define RADEON_WAIT_2D 0x1 +#define RADEON_WAIT_3D 0x2 + #define RADEON_FRONT 0x1 #define RADEON_BACK 0x2 @@ -364,6 +373,11 @@ typedef struct { #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) +#define DRM_IOCTL_RADEON_ALLOC DRM_IOWR( 0x53, drm_radeon_mem_alloc_t) +#define DRM_IOCTL_RADEON_FREE DRM_IOW( 0x54, drm_radeon_mem_free_t) +#define DRM_IOCTL_RADEON_INIT_HEAP DRM_IOW( 0x55, drm_radeon_mem_init_heap_t) +#define DRM_IOCTL_RADEON_IRQ_EMIT DRM_IOWR( 0x56, drm_radeon_irq_emit_t) +#define DRM_IOCTL_RADEON_IRQ_WAIT DRM_IOW( 0x57, drm_radeon_irq_wait_t) typedef struct drm_radeon_init { enum { @@ -499,14 +513,51 @@ typedef struct drm_radeon_indirect { /* 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 -#define RADEON_PARAM_LAST_FRAME 0x2 -#define RADEON_PARAM_LAST_DISPATCH 0x3 -#define RADEON_PARAM_LAST_CLEAR 0x4 +#define RADEON_PARAM_AGP_BUFFER_OFFSET 1 /* card offset of 1st agp buffer */ +#define RADEON_PARAM_LAST_FRAME 2 +#define RADEON_PARAM_LAST_DISPATCH 3 +#define RADEON_PARAM_LAST_CLEAR 4 +#define RADEON_PARAM_IRQ_ACTIVE 5 +#define RADEON_PARAM_AGP_BASE 6 /* card offset of agp base */ typedef struct drm_radeon_getparam { int param; int *value; } drm_radeon_getparam_t; +/* 1.6: Set up a memory manager for regions of shared memory: + */ +#define RADEON_MEM_REGION_AGP 1 +#define RADEON_MEM_REGION_FB 2 + +typedef struct drm_radeon_mem_alloc { + int region; + int alignment; + int size; + int *region_offset; /* offset from start of fb or agp */ +} drm_radeon_mem_alloc_t; + +typedef struct drm_radeon_mem_free { + int region; + int region_offset; +} drm_radeon_mem_free_t; + +typedef struct drm_radeon_mem_init_heap { + int region; + int size; + int start; +} drm_radeon_mem_init_heap_t; + + +/* 1.6: Userspace can request & wait on irq's: + */ +typedef struct drm_radeon_irq_emit { + int *irq_seq; +} drm_radeon_irq_emit_t; + +typedef struct drm_radeon_irq_wait { + int irq_seq; +} drm_radeon_irq_wait_t; + + #endif diff --git a/drivers/char/drm/radeon_drv.h b/drivers/char/drm/radeon_drv.h index e012bbbd4fa7..efe3020cf619 100644 --- a/drivers/char/drm/radeon_drv.h +++ b/drivers/char/drm/radeon_drv.h @@ -61,6 +61,15 @@ typedef struct drm_radeon_depth_clear_t { u32 se_cntl; } drm_radeon_depth_clear_t; + +struct mem_block { + struct mem_block *next; + struct mem_block *prev; + int start; + int size; + int pid; /* 0: free, -1: heap, other: real pids */ +}; + typedef struct drm_radeon_private { drm_radeon_ring_buffer_t ring; drm_radeon_sarea_t *sarea_priv; @@ -126,6 +135,14 @@ typedef struct drm_radeon_private { drm_map_t *ring_rptr; drm_map_t *buffers; drm_map_t *agp_textures; + + struct mem_block *agp_heap; + struct mem_block *fb_heap; + + wait_queue_head_t irq_queue; + atomic_t irq_received; + atomic_t irq_emitted; + } drm_radeon_private_t; typedef struct drm_radeon_buf_priv { @@ -164,6 +181,20 @@ extern int radeon_cp_cmdbuf( DRM_IOCTL_ARGS ); extern int radeon_cp_getparam( DRM_IOCTL_ARGS ); extern int radeon_cp_flip( DRM_IOCTL_ARGS ); +extern int radeon_mem_alloc( DRM_IOCTL_ARGS ); +extern int radeon_mem_free( DRM_IOCTL_ARGS ); +extern int radeon_mem_init_heap( DRM_IOCTL_ARGS ); +extern void radeon_mem_takedown( struct mem_block **heap ); +extern void radeon_mem_release( struct mem_block *heap ); + +extern int radeon_irq_emit( DRM_IOCTL_ARGS ); +extern int radeon_irq_wait( DRM_IOCTL_ARGS ); + +extern int radeon_emit_and_wait_irq(drm_device_t *dev); +extern int radeon_wait_irq(drm_device_t *dev, int irq_nr); +extern int radeon_emit_irq(drm_device_t *dev); + + /* Flags for stats.boxes */ #define RADEON_BOX_DMA_IDLE 0x1 @@ -238,6 +269,16 @@ extern int radeon_cp_flip( DRM_IOCTL_ARGS ); ? DRM_READ32( &dev_priv->scratch[(x)] ) \ : RADEON_READ( RADEON_SCRATCH_REG0 + 4*(x) ) ) + +#define RADEON_GEN_INT_CNTL 0x0040 +# define RADEON_GUI_IDLE_INT_ENABLE (1 << 19) +# define RADEON_SW_INT_ENABLE (1 << 25) + +#define RADEON_GEN_INT_STATUS 0x0044 +# define RADEON_GUI_IDLE_INT_TEST_ACK (1 << 19) +# define RADEON_SW_INT_TEST_ACK (1 << 25) +# define RADEON_SW_INT_FIRE (1 << 26) + #define RADEON_HOST_PATH_CNTL 0x0130 # define RADEON_HDP_SOFT_RESET (1 << 26) # define RADEON_HDP_WC_TIMEOUT_MASK (7 << 28) @@ -526,6 +567,8 @@ extern int radeon_cp_flip( DRM_IOCTL_ARGS ); #define RADEON_TXFORMAT_ARGB4444 5 #define RADEON_TXFORMAT_ARGB8888 6 #define RADEON_TXFORMAT_RGBA8888 7 +#define RADEON_TXFORMAT_VYUY422 10 +#define RADEON_TXFORMAT_YVYU422 11 #define R200_PP_TXCBLEND_0 0x2f00 #define R200_PP_TXCBLEND_1 0x2f10 diff --git a/drivers/char/drm/radeon_irq.c b/drivers/char/drm/radeon_irq.c new file mode 100644 index 000000000000..11609393228d --- /dev/null +++ b/drivers/char/drm/radeon_irq.c @@ -0,0 +1,214 @@ +/* radeon_mem.c -- Simple agp/fb memory manager for radeon -*- linux-c -*- + * + * Copyright (C) The Weather Channel, Inc. 2002. All Rights Reserved. + * + * The Weather Channel (TM) funded Tungsten Graphics to develop the + * initial release of the Radeon 8500 driver under the XFree86 license. + * This notice must be preserved. + * + * 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: + * Keith Whitwell <keith@tungstengraphics.com> + */ + +#include "radeon.h" +#include "drmP.h" +#include "drm.h" +#include "radeon_drm.h" +#include "radeon_drv.h" + +/* Interrupts - Used for device synchronization and flushing in the + * following circumstances: + * + * - Exclusive FB access with hw idle: + * - Wait for GUI Idle (?) interrupt, then do normal flush. + * + * - Frame throttling, NV_fence: + * - Drop marker irq's into command stream ahead of time. + * - Wait on irq's with lock *not held* + * - Check each for termination condition + * + * - Internally in cp_getbuffer, etc: + * - as above, but wait with lock held??? + * + * NOTE: These functions are misleadingly named -- the irq's aren't + * tied to dma at all, this is just a hangover from dri prehistory. + */ + +void DRM(dma_service)( DRM_IRQ_ARGS ) +{ + drm_device_t *dev = (drm_device_t *) arg; + drm_radeon_private_t *dev_priv = + (drm_radeon_private_t *)dev->dev_private; + u32 temp; + + /* Need to wait for fifo to drain? + */ + temp = RADEON_READ(RADEON_GEN_INT_STATUS); + temp = temp & RADEON_SW_INT_TEST_ACK; + if (temp == 0) return; + RADEON_WRITE(RADEON_GEN_INT_STATUS, temp); + + atomic_inc(&dev_priv->irq_received); +#ifdef __linux__ + queue_task(&dev->tq, &tq_immediate); + mark_bh(IMMEDIATE_BH); +#endif /* __linux__ */ +#ifdef __FreeBSD__ + taskqueue_enqueue(taskqueue_swi, &dev->task); +#endif /* __FreeBSD__ */ +} + +void DRM(dma_immediate_bh)( DRM_TASKQUEUE_ARGS ) +{ + drm_device_t *dev = (drm_device_t *) arg; + drm_radeon_private_t *dev_priv = + (drm_radeon_private_t *)dev->dev_private; + +#ifdef __linux__ + wake_up_interruptible(&dev_priv->irq_queue); +#endif /* __linux__ */ +#ifdef __FreeBSD__ + wakeup( &dev_priv->irq_queue ); +#endif +} + + +int radeon_emit_irq(drm_device_t *dev) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + RING_LOCALS; + + atomic_inc(&dev_priv->irq_emitted); + + BEGIN_RING(2); + OUT_RING( CP_PACKET0( RADEON_GEN_INT_STATUS, 0 ) ); + OUT_RING( RADEON_SW_INT_FIRE ); + ADVANCE_RING(); + COMMIT_RING(); + + return atomic_read(&dev_priv->irq_emitted); +} + + +int radeon_wait_irq(drm_device_t *dev, int irq_nr) +{ + drm_radeon_private_t *dev_priv = + (drm_radeon_private_t *)dev->dev_private; +#ifdef __linux__ + DECLARE_WAITQUEUE(entry, current); + unsigned long end = jiffies + HZ*3; +#endif /* __linux__ */ + int ret = 0; + + if (atomic_read(&dev_priv->irq_received) >= irq_nr) + return 0; + + dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE; + +#ifdef __linux__ + add_wait_queue(&dev_priv->irq_queue, &entry); + + for (;;) { + current->state = TASK_INTERRUPTIBLE; + if (atomic_read(&dev_priv->irq_received) >= irq_nr) + break; + if((signed)(end - jiffies) <= 0) { + ret = -EBUSY; /* Lockup? Missed irq? */ + break; + } + schedule_timeout(HZ*3); + if (signal_pending(current)) { + ret = -EINTR; + break; + } + } + + current->state = TASK_RUNNING; + remove_wait_queue(&dev_priv->irq_queue, &entry); + return ret; +#endif /* __linux__ */ + +#ifdef __FreeBSD__ + ret = tsleep( &dev_priv->irq_queue, PZERO | PCATCH, \ + "rdnirq", 3*hz ); + if ( (ret == EWOULDBLOCK) || (ret == EINTR) ) + return DRM_ERR(EBUSY); + return ret; +#endif /* __FreeBSD__ */ +} + + +int radeon_emit_and_wait_irq(drm_device_t *dev) +{ + return radeon_wait_irq( dev, radeon_emit_irq(dev) ); +} + + +/* Needs the lock as it touches the ring. + */ +int radeon_irq_emit( DRM_IOCTL_ARGS ) +{ + DRM_DEVICE; + drm_radeon_private_t *dev_priv = dev->dev_private; + drm_radeon_irq_emit_t emit; + int result; + + LOCK_TEST_WITH_RETURN( dev ); + + if ( !dev_priv ) { + DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ ); + return DRM_ERR(EINVAL); + } + + DRM_COPY_FROM_USER_IOCTL( emit, (drm_radeon_irq_emit_t *)data, + sizeof(emit) ); + + result = radeon_emit_irq( dev ); + + if ( DRM_COPY_TO_USER( emit.irq_seq, &result, sizeof(int) ) ) { + DRM_ERROR( "copy_to_user\n" ); + return DRM_ERR(EFAULT); + } + + return 0; +} + + +/* Doesn't need the hardware lock. + */ +int radeon_irq_wait( DRM_IOCTL_ARGS ) +{ + DRM_DEVICE; + drm_radeon_private_t *dev_priv = dev->dev_private; + drm_radeon_irq_wait_t irqwait; + + if ( !dev_priv ) { + DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ ); + return DRM_ERR(EINVAL); + } + + DRM_COPY_FROM_USER_IOCTL( irqwait, (drm_radeon_irq_wait_t *)data, + sizeof(irqwait) ); + + return radeon_wait_irq( dev, irqwait.irq_seq ); +} + diff --git a/drivers/char/drm/radeon_mem.c b/drivers/char/drm/radeon_mem.c new file mode 100644 index 000000000000..d77c60b914f9 --- /dev/null +++ b/drivers/char/drm/radeon_mem.c @@ -0,0 +1,334 @@ +/* radeon_mem.c -- Simple agp/fb memory manager for radeon -*- linux-c -*- + * + * Copyright (C) The Weather Channel, Inc. 2002. All Rights Reserved. + * + * The Weather Channel (TM) funded Tungsten Graphics to develop the + * initial release of the Radeon 8500 driver under the XFree86 license. + * This notice must be preserved. + * + * 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: + * Keith Whitwell <keith@tungstengraphics.com> + */ + +#include "radeon.h" +#include "drmP.h" +#include "drm.h" +#include "radeon_drm.h" +#include "radeon_drv.h" + +/* Very simple allocator for agp memory, working on a static range + * already mapped into each client's address space. + */ + +static struct mem_block *split_block(struct mem_block *p, int start, int size, + int pid ) +{ + /* Maybe cut off the start of an existing block */ + if (start > p->start) { + struct mem_block *newblock = DRM_MALLOC(sizeof(*newblock)); + if (!newblock) + goto out; + newblock->start = start; + newblock->size = p->size - (start - p->start); + newblock->pid = 0; + newblock->next = p->next; + newblock->prev = p; + p->next->prev = newblock; + p->next = newblock; + p->size -= newblock->size; + p = newblock; + } + + /* Maybe cut off the end of an existing block */ + if (size < p->size) { + struct mem_block *newblock = DRM_MALLOC(sizeof(*newblock)); + if (!newblock) + goto out; + newblock->start = start + size; + newblock->size = p->size - size; + newblock->pid = 0; + newblock->next = p->next; + newblock->prev = p; + p->next->prev = newblock; + p->next = newblock; + p->size = size; + } + + out: + /* Our block is in the middle */ + p->pid = pid; + return p; +} + +static struct mem_block *alloc_block( struct mem_block *heap, int size, + int align2, int pid ) +{ + struct mem_block *p; + int mask = (1 << align2)-1; + + for (p = heap->next ; p != heap ; p = p->next) { + int start = (p->start + mask) & ~mask; + if (p->pid == 0 && start + size <= p->start + p->size) + return split_block( p, start, size, pid ); + } + + return NULL; +} + +static struct mem_block *find_block( struct mem_block *heap, int start ) +{ + struct mem_block *p; + + for (p = heap->next ; p != heap ; p = p->next) + if (p->start == start) + return p; + + return NULL; +} + + +static void free_block( struct mem_block *p ) +{ + p->pid = 0; + + /* Assumes a single contiguous range. Needs a special pid in + * 'heap' to stop it being subsumed. + */ + if (p->next->pid == 0) { + struct mem_block *q = p->next; + p->size += q->size; + p->next = q->next; + p->next->prev = p; + DRM_FREE(p); + } + + if (p->prev->pid == 0) { + struct mem_block *q = p->prev; + q->size += p->size; + q->next = p->next; + q->next->prev = q; + DRM_FREE(p); + } +} + +static void print_heap( struct mem_block *heap ) +{ + struct mem_block *p; + + for (p = heap->next ; p != heap ; p = p->next) + DRM_DEBUG("0x%x..0x%x (0x%x) -- owner %d\n", + p->start, p->start + p->size, + p->size, p->pid); +} + +/* Initialize. How to check for an uninitialized heap? + */ +static int init_heap(struct mem_block **heap, int start, int size) +{ + struct mem_block *blocks = DRM_MALLOC(sizeof(*blocks)); + + if (!blocks) + return -ENOMEM; + + *heap = DRM_MALLOC(sizeof(**heap)); + if (!*heap) { + DRM_FREE( blocks ); + return -ENOMEM; + } + + blocks->start = start; + blocks->size = size; + blocks->pid = 0; + blocks->next = blocks->prev = *heap; + + memset( *heap, 0, sizeof(**heap) ); + (*heap)->pid = -1; + (*heap)->next = (*heap)->prev = blocks; + return 0; +} + + +/* Free all blocks associated with the releasing pid. + */ +void radeon_mem_release( struct mem_block *heap ) +{ + int pid = DRM_CURRENTPID; + struct mem_block *p; + + if (!heap || !heap->next) + return; + + for (p = heap->next ; p != heap ; p = p->next) { + if (p->pid == pid) + p->pid = 0; + } + + /* Assumes a single contiguous range. Needs a special pid in + * 'heap' to stop it being subsumed. + */ + for (p = heap->next ; p != heap ; p = p->next) { + while (p->pid == 0 && p->next->pid == 0) { + struct mem_block *q = p->next; + p->size += q->size; + p->next = q->next; + p->next->prev = p; + DRM_FREE(q); + } + } +} + +/* Shutdown. + */ +void radeon_mem_takedown( struct mem_block **heap ) +{ + struct mem_block *p; + + if (!*heap) + return; + + for (p = (*heap)->next ; p != *heap ; ) { + struct mem_block *q = p; + p = p->next; + DRM_FREE(q); + } + + DRM_FREE( *heap ); + *heap = 0; +} + + + +/* IOCTL HANDLERS */ + +static struct mem_block **get_heap( drm_radeon_private_t *dev_priv, + int region ) +{ + switch( region ) { + case RADEON_MEM_REGION_AGP: + return &dev_priv->agp_heap; + case RADEON_MEM_REGION_FB: + return &dev_priv->fb_heap; + default: + return 0; + } +} + +int radeon_mem_alloc( DRM_IOCTL_ARGS ) +{ + DRM_DEVICE; + drm_radeon_private_t *dev_priv = dev->dev_private; + drm_radeon_mem_alloc_t alloc; + struct mem_block *block, **heap; + + if ( !dev_priv ) { + DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ ); + return DRM_ERR(EINVAL); + } + + DRM_COPY_FROM_USER_IOCTL( alloc, (drm_radeon_mem_alloc_t *)data, + sizeof(alloc) ); + + heap = get_heap( dev_priv, alloc.region ); + if (!heap || !*heap) + return DRM_ERR(EFAULT); + + /* Make things easier on ourselves: all allocations at least + * 4k aligned. + */ + if (alloc.alignment < 12) + alloc.alignment = 12; + + block = alloc_block( *heap, alloc.size, alloc.alignment, + DRM_CURRENTPID ); + + if (!block) + return DRM_ERR(ENOMEM); + + if ( DRM_COPY_TO_USER( alloc.region_offset, &block->start, + sizeof(int) ) ) { + DRM_ERROR( "copy_to_user\n" ); + return DRM_ERR(EFAULT); + } + + return 0; +} + + + +int radeon_mem_free( DRM_IOCTL_ARGS ) +{ + DRM_DEVICE; + drm_radeon_private_t *dev_priv = dev->dev_private; + drm_radeon_mem_free_t memfree; + struct mem_block *block, **heap; + + if ( !dev_priv ) { + DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ ); + return DRM_ERR(EINVAL); + } + + DRM_COPY_FROM_USER_IOCTL( memfree, (drm_radeon_mem_free_t *)data, + sizeof(memfree) ); + + heap = get_heap( dev_priv, memfree.region ); + if (!heap || !*heap) + return DRM_ERR(EFAULT); + + block = find_block( *heap, memfree.region_offset ); + if (!block) + return DRM_ERR(EFAULT); + + if (block->pid != DRM_CURRENTPID) + return DRM_ERR(EPERM); + + free_block( block ); + return 0; +} + +int radeon_mem_init_heap( DRM_IOCTL_ARGS ) +{ + DRM_DEVICE; + drm_radeon_private_t *dev_priv = dev->dev_private; + drm_radeon_mem_init_heap_t initheap; + struct mem_block **heap; + + if ( !dev_priv ) { + DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ ); + return DRM_ERR(EINVAL); + } + + DRM_COPY_FROM_USER_IOCTL( initheap, (drm_radeon_mem_init_heap_t *)data, + sizeof(initheap) ); + + heap = get_heap( dev_priv, initheap.region ); + if (!heap) + return DRM_ERR(EFAULT); + + if (*heap) { + DRM_ERROR("heap already initialized?"); + return DRM_ERR(EFAULT); + } + + return init_heap( heap, initheap.start, initheap.size ); +} + + diff --git a/drivers/char/drm/radeon_state.c b/drivers/char/drm/radeon_state.c index 6dbf60936a61..0172128bef5d 100644 --- a/drivers/char/drm/radeon_state.c +++ b/drivers/char/drm/radeon_state.c @@ -719,7 +719,6 @@ static void radeon_cp_dispatch_swap( drm_device_t *dev ) RING_LOCALS; DRM_DEBUG( "\n" ); - /* Do some trivial performance monitoring... */ if (dev_priv->do_boxes) @@ -1088,6 +1087,8 @@ static int radeon_cp_dispatch_texture( drm_device_t *dev, case RADEON_TXFORMAT_ARGB1555: case RADEON_TXFORMAT_RGB565: case RADEON_TXFORMAT_ARGB4444: + case RADEON_TXFORMAT_VYUY422: + case RADEON_TXFORMAT_YVYU422: format = RADEON_COLOR_FORMAT_RGB565; tex_width = tex->width * 2; blit_width = image->width * 2; @@ -1226,6 +1227,7 @@ static int radeon_cp_dispatch_texture( drm_device_t *dev, return ret; } + static void radeon_cp_dispatch_stipple( drm_device_t *dev, u32 *stipple ) { drm_radeon_private_t *dev_priv = dev->dev_private; @@ -1306,6 +1308,9 @@ static int radeon_do_init_pageflip( drm_device_t *dev ) return 0; } +/* Called whenever a client dies, from DRM(release). + * NOTE: Lock isn't necessarily held when this is called! + */ int radeon_do_cleanup_pageflip( drm_device_t *dev ) { drm_radeon_private_t *dev_priv = dev->dev_private; @@ -1936,14 +1941,18 @@ static int radeon_emit_packet3_cliprect( drm_device_t *dev, if ( i < cmdbuf->nbox ) { if (DRM_COPY_FROM_USER_UNCHECKED( &box, &boxes[i], sizeof(box) )) return DRM_ERR(EFAULT); - /* FIXME The second and subsequent times round this loop, send a - * WAIT_UNTIL_3D_IDLE before calling emit_clip_rect(). This - * fixes a lockup on fast machines when sending several - * cliprects with a cmdbuf, as when waving a 2D window over - * a 3D window. Something in the commands from user space - * seems to hang the card when they're sent several times - * in a row. That would be the correct place to fix it but - * this works around it until I can figure that out - Tim Smith */ + /* FIXME The second and subsequent times round + * this loop, send a WAIT_UNTIL_3D_IDLE before + * calling emit_clip_rect(). This fixes a + * lockup on fast machines when sending + * several cliprects with a cmdbuf, as when + * waving a 2D window over a 3D + * window. Something in the commands from user + * space seems to hang the card when they're + * sent several times in a row. That would be + * the correct place to fix it but this works + * around it until I can figure that out - Tim + * Smith */ if ( i ) { BEGIN_RING( 2 ); RADEON_WAIT_UNTIL_3D_IDLE(); @@ -1967,6 +1976,34 @@ static int radeon_emit_packet3_cliprect( drm_device_t *dev, } +static int radeon_emit_wait( drm_device_t *dev, int flags ) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + RING_LOCALS; + + DRM_DEBUG("%s: %x\n", __FUNCTION__, flags); + switch (flags) { + case RADEON_WAIT_2D: + BEGIN_RING( 2 ); + RADEON_WAIT_UNTIL_2D_IDLE(); + ADVANCE_RING(); + break; + case RADEON_WAIT_3D: + BEGIN_RING( 2 ); + RADEON_WAIT_UNTIL_3D_IDLE(); + ADVANCE_RING(); + break; + case RADEON_WAIT_2D|RADEON_WAIT_3D: + BEGIN_RING( 2 ); + RADEON_WAIT_UNTIL_IDLE(); + ADVANCE_RING(); + break; + default: + return DRM_ERR(EINVAL); + } + + return 0; +} int radeon_cp_cmdbuf( DRM_IOCTL_ARGS ) { @@ -1989,7 +2026,6 @@ int radeon_cp_cmdbuf( DRM_IOCTL_ARGS ) DRM_COPY_FROM_USER_IOCTL( cmdbuf, (drm_radeon_cmd_buffer_t *)data, sizeof(cmdbuf) ); - DRM_DEBUG( "pid=%d\n", DRM_CURRENTPID ); RING_SPACE_TEST_WITH_RETURN( dev_priv ); VB_AGE_TEST_WITH_RETURN( dev_priv ); @@ -2080,6 +2116,14 @@ int radeon_cp_cmdbuf( DRM_IOCTL_ARGS ) return DRM_ERR(EINVAL); } break; + + case RADEON_CMD_WAIT: + DRM_DEBUG("RADEON_CMD_WAIT\n"); + if (radeon_emit_wait( dev, header.wait.flags )) { + DRM_ERROR("radeon_emit_wait failed\n"); + return DRM_ERR(EINVAL); + } + break; default: DRM_ERROR("bad cmd_type %d at %p\n", header.header.cmd_type, @@ -2128,6 +2172,12 @@ int radeon_cp_getparam( DRM_IOCTL_ARGS ) dev_priv->stats.last_clear_reads++; value = GET_SCRATCH( 2 ); break; + case RADEON_PARAM_IRQ_ACTIVE: + value = dev->irq ? 1 : 0; + break; + case RADEON_PARAM_AGP_BASE: + value = dev_priv->agp_vm_start; + break; default: return DRM_ERR(EINVAL); } diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index f8d177715a6d..08c2ee09eab1 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c @@ -980,7 +980,7 @@ repeat: best = NULL; drive = hwgroup->drive; do { - if (!list_empty(&drive->queue.queue_head) && (!drive->sleep || time_after_eq(jiffies, drive->sleep))) { + if (!blk_queue_empty(&drive->queue) && (!drive->sleep || time_after_eq(jiffies, drive->sleep))) { if (!best || (drive->sleep && (!best->sleep || 0 < (signed long)(best->sleep - drive->sleep))) || (!best->sleep && 0 < (signed long)(WAKEUP(best) - WAKEUP(drive)))) diff --git a/include/asm-alpha/ide.h b/include/asm-alpha/ide.h index 0ca863142cf5..63bb9f785498 100644 --- a/include/asm-alpha/ide.h +++ b/include/asm-alpha/ide.h @@ -80,17 +80,6 @@ static __inline__ void ide_init_default_hwifs(void) #endif } -#define ide_request_irq(irq,hand,flg,dev,id) request_irq((irq),(hand),(flg),(dev),(id)) -#define ide_free_irq(irq,dev_id) free_irq((irq), (dev_id)) -#define ide_check_region(from,extent) check_region((from), (extent)) -#define ide_request_region(from,extent,name) request_region((from), (extent), (name)) -#define ide_release_region(from,extent) release_region((from), (extent)) - -#define ide_ack_intr(hwif) (1) -#define ide_fix_driveid(id) do {} while (0) -#define ide_release_lock(lock) do {} while (0) -#define ide_get_lock(lock, hdlr, data) do {} while (0) - #endif /* __KERNEL__ */ #endif /* __ASMalpha_IDE_H */ diff --git a/include/asm-alpha/rwsem.h b/include/asm-alpha/rwsem.h index d98ba565ecb4..c3abe5d2d41b 100644 --- a/include/asm-alpha/rwsem.h +++ b/include/asm-alpha/rwsem.h @@ -93,14 +93,16 @@ static inline void __down_read(struct rw_semaphore *sem) */ static inline int __down_read_trylock(struct rw_semaphore *sem) { - long res, tmp; + long old, new, res; res = sem->count; do { - tmp = res + RWSEM_ACTIVE_READ_BIAS; - if (tmp <= 0) + new = res + RWSEM_ACTIVE_READ_BIAS; + if (new <= 0) break; - } while (cmpxchg(&sem->count, res, tmp) != res); + old = res; + res = cmpxchg(&sem->count, old, new); + } while (res != old); return res >= 0 ? 1 : 0; } diff --git a/include/asm-alpha/unistd.h b/include/asm-alpha/unistd.h index 33abc3bd434a..23eb6d2eb42d 100644 --- a/include/asm-alpha/unistd.h +++ b/include/asm-alpha/unistd.h @@ -331,6 +331,18 @@ #define __NR_removexattr 391 #define __NR_lremovexattr 392 #define __NR_fremovexattr 393 +#define __NR_futex 394 +#define __NR_sched_setaffinity 395 +#define __NR_sched_getaffinity 396 +#define __NR_tuxcall 397 +#define __NR_io_setup 398 +#define __NR_io_destroy 399 +#define __NR_io_getevents 400 +#define __NR_io_submit 401 +#define __NR_io_cancel 402 +#define __NR_alloc_hugepages 403 +#define __NR_free_hugepages 404 +#define __NR_exit_group 405 #if defined(__GNUC__) diff --git a/kernel/exit.c b/kernel/exit.c index 6b1629ef433a..fe11fa929746 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -131,9 +131,14 @@ int session_of_pgrp(int pgrp) for_each_task_pid(pgrp, PIDTYPE_PGID, p, l, pid) if (p->session > 0) { sid = p->session; - break; + goto out; } + p = find_task_by_pid(pgrp); + if (p) + sid = p->session; +out: read_unlock(&tasklist_lock); + return sid; } |
