diff options
38 files changed, 5282 insertions, 1668 deletions
diff --git a/linux-core/Makefile b/linux-core/Makefile index 9cfe7d5c..1bff058f 100644 --- a/linux-core/Makefile +++ b/linux-core/Makefile @@ -50,12 +50,12 @@ endif MACHINE := $(shell uname -m) # Modules for all architectures -MODULE_LIST := tdfx.o r128.o radeon.o mga.o sis.o savage.o via.o mach64.o +MODULE_LIST := #tdfx.o r128.o radeon.o mga.o sis.o savage.o via.o mach64.o # Modules only for ix86 architectures ifneq (,$(findstring 86,$(MACHINE))) ARCHX86 := 1 -MODULE_LIST += i830.o i810.o i915.o +MODULE_LIST += #i830.o i810.o i915.o endif ifneq (,$(findstring sparc64,$(MACHINE))) diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel index 92e3f73e..8e68d40a 100644 --- a/linux-core/Makefile.kernel +++ b/linux-core/Makefile.kernel @@ -7,6 +7,7 @@ # $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/Makefile.kernel,v 1.18 2003/08/16 17:59:17 dawes Exp $ # +drmcore-objs := tdfx-objs := tdfx_drv.o r128-objs := r128_drv.o r128_cce.o r128_state.o r128_irq.o mga-objs := mga_drv.o mga_dma.o mga_state.o mga_warp.o mga_irq.o @@ -41,9 +42,11 @@ obj- := export-objs := via_mm.o endif +drmcore-y := drm_bufs.o drm_memory.o drm_memory_debug.o drm_agpsupport.o drm_dma.o ati_pcigart.o drm_proc.o drmcore_exports.o +obj-m += drmcore.o radeon.o obj-$(CONFIG_DRM_TDFX) += tdfx.o -obj-$(CONFIG_DRM_R128) += r128.o -obj-$(CONFIG_DRM_RADEON)+= radeon.o +obj-$(CONFIG_DRM_R128) += r128.o +obj-$(CONFIG_DRM_RADEON)+= radeon.o drmcore.o obj-$(CONFIG_DRM_MGA) += mga.o obj-$(CONFIG_DRM_I810) += i810.o obj-$(CONFIG_DRM_I830) += i830.o diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 495277f6..b26f6189 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -36,179 +36,27 @@ #ifdef __KERNEL__ -#ifdef __alpha__ -/* add include of current.h so that "current" is defined - * before static inline funcs in wait.h. Doing this so we - * can build the DRM (part of PI DRI). 4/21/2000 S + B */ -#include <asm/current.h> -#endif /* __alpha__ */ -#include <linux/config.h> -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/miscdevice.h> -#include <linux/fs.h> -#include <linux/proc_fs.h> -#include <linux/init.h> -#include <linux/file.h> -#include <linux/pci.h> -#include <linux/version.h> -#include <linux/sched.h> -#include <linux/smp_lock.h> /* For (un)lock_kernel */ -#include <linux/mm.h> -#include <linux/pagemap.h> -#if defined(__alpha__) || defined(__powerpc__) -#include <asm/pgtable.h> /* For pte_wrprotect */ -#endif -#include <asm/io.h> -#include <asm/mman.h> -#include <asm/uaccess.h> -#ifdef CONFIG_MTRR -#include <asm/mtrr.h> -#endif -#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE) -#include <linux/types.h> -#include <linux/agp_backend.h> -#endif -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,41) -#define HAS_WORKQUEUE 0 -#else -#define HAS_WORKQUEUE 1 -#endif -#if !HAS_WORKQUEUE -#include <linux/tqueue.h> -#else -#include <linux/workqueue.h> -#endif -#include <linux/poll.h> -#include <asm/pgalloc.h> -#include "drm.h" - -#include "drm_os_linux.h" /* If you want the memory alloc debug functionality, change define below */ /* #define DEBUG_MEMORY */ /***********************************************************************/ -/** \name DRM template customization defaults */ -/*@{*/ - -/* driver capabilities and requirements mask */ -#define DRIVER_USE_AGP 0x1 -#define DRIVER_REQUIRE_AGP 0x2 -#define DRIVER_USE_MTRR 0x4 -#define DRIVER_HAVE_DMA 0x10 -#define DRIVER_HAVE_IRQ 0x20 -#define DRIVER_SG 0x40 -#define DRIVER_PCI_DMA 0x80 -#define DRIVER_IRQ_SHARED 0x100 -#define DRIVER_IRQ_VBL 0x200 -#define DRIVER_DMA_QUEUE 0x800 - -#define __OS_HAS_AGP (defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE)) -#define __OS_HAS_MTRR (defined(CONFIG_MTRR)) -/*@}*/ - - -/***********************************************************************/ /** \name Begin the DRM... */ /*@{*/ -#define DRM_DEBUG_CODE 2 /**< Include debugging code if > 1, then - also include looping detection. */ - -#define DRM_HASH_SIZE 16 /**< Size of key hash table. Must be power of 2. */ -#define DRM_KERNEL_CONTEXT 0 /**< Change drm_resctx if changed */ -#define DRM_RESERVED_CONTEXTS 1 /**< Change drm_resctx if changed */ -#define DRM_LOOPING_LIMIT 5000000 -#define DRM_BSZ 1024 /**< Buffer size for /dev/drm? output */ -#define DRM_TIME_SLICE (HZ/20) /**< Time slice for GLXContexts */ -#define DRM_LOCK_SLICE 1 /**< Time slice for lock, in jiffies */ - -#define DRM_FLAG_DEBUG 0x01 - -#define DRM_MEM_DMA 0 -#define DRM_MEM_SAREA 1 -#define DRM_MEM_DRIVER 2 -#define DRM_MEM_MAGIC 3 -#define DRM_MEM_IOCTLS 4 -#define DRM_MEM_MAPS 5 -#define DRM_MEM_VMAS 6 -#define DRM_MEM_BUFS 7 -#define DRM_MEM_SEGS 8 -#define DRM_MEM_PAGES 9 -#define DRM_MEM_FILES 10 -#define DRM_MEM_QUEUES 11 -#define DRM_MEM_CMDS 12 -#define DRM_MEM_MAPPINGS 13 -#define DRM_MEM_BUFLISTS 14 -#define DRM_MEM_AGPLISTS 15 -#define DRM_MEM_TOTALAGP 16 -#define DRM_MEM_BOUNDAGP 17 -#define DRM_MEM_CTXBITMAP 18 -#define DRM_MEM_STUB 19 -#define DRM_MEM_SGLISTS 20 -#define DRM_MEM_CTXLIST 21 #define DRM_MAX_CTXBITMAP (PAGE_SIZE * 8) /*@}*/ -#include "drm_compat.h" +#include "drm_core.h" /***********************************************************************/ /** \name Macros to make printk easier */ /*@{*/ -/** - * Error output. - * - * \param fmt printf() like format string. - * \param arg arguments - */ -#define DRM_ERROR(fmt, arg...) \ - printk(KERN_ERR "[" DRM_NAME ":%s] *ERROR* " fmt , __FUNCTION__ , ##arg) - -/** - * Memory error output. - * - * \param area memory area where the error occurred. - * \param fmt printf() like format string. - * \param arg arguments - */ -#define DRM_MEM_ERROR(area, fmt, arg...) \ - printk(KERN_ERR "[" DRM_NAME ":%s:%s] *ERROR* " fmt , __FUNCTION__, \ - DRM(mem_stats)[area].name , ##arg) -#define DRM_INFO(fmt, arg...) printk(KERN_INFO "[" DRM_NAME "] " fmt , ##arg) - -/** - * Debug output. - * - * \param fmt printf() like format string. - * \param arg arguments - */ -#if DRM_DEBUG_CODE -#define DRM_DEBUG(fmt, arg...) \ - do { \ - if ( DRM(flags) & DRM_FLAG_DEBUG ) \ - printk(KERN_DEBUG \ - "[" DRM_NAME ":%s] " fmt , \ - __FUNCTION__ , ##arg); \ - } while (0) -#else -#define DRM_DEBUG(fmt, arg...) do { } while (0) -#endif - -#define DRM_PROC_LIMIT (PAGE_SIZE-80) - -#define DRM_PROC_PRINT(fmt, arg...) \ - len += sprintf(&buf[len], fmt , ##arg); \ - if (len > DRM_PROC_LIMIT) { *eof = 1; return len - offset; } - -#define DRM_PROC_PRINT_RET(ret, fmt, arg...) \ - len += sprintf(&buf[len], fmt , ##arg); \ - if (len > DRM_PROC_LIMIT) { ret; *eof = 1; return len - offset; } /*@}*/ @@ -221,9 +69,6 @@ #define DRM_MIN(a,b) ((a)<(b)?(a):(b)) #define DRM_MAX(a,b) ((a)>(b)?(a):(b)) -#define DRM_LEFTCOUNT(x) (((x)->rp + (x)->count - (x)->wp) % ((x)->count + 1)) -#define DRM_BUFCOUNT(x) ((x)->count - DRM_LEFTCOUNT(x)) -#define DRM_WAITCOUNT(dev,idx) DRM_BUFCOUNT(&dev->queuelist[idx]->waitlist) #define DRM_IF_VERSION(maj, min) (maj << 16 | min) /** @@ -253,440 +98,6 @@ do { \ } \ } while (0) -/** - * Ioctl function type. - * - * \param inode device inode. - * \param filp file pointer. - * \param cmd command. - * \param arg argument. - */ -typedef int drm_ioctl_t( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ); - -typedef struct drm_ioctl_desc { - drm_ioctl_t *func; - int auth_needed; - int root_only; -} drm_ioctl_desc_t; - -typedef struct drm_devstate { - pid_t owner; /**< X server pid holding x_lock */ -} drm_devstate_t; - -typedef struct drm_magic_entry { - drm_magic_t magic; - struct drm_file *priv; - struct drm_magic_entry *next; -} drm_magic_entry_t; - -typedef struct drm_magic_head { - struct drm_magic_entry *head; - struct drm_magic_entry *tail; -} drm_magic_head_t; - -typedef struct drm_vma_entry { - struct vm_area_struct *vma; - struct drm_vma_entry *next; - pid_t pid; -} drm_vma_entry_t; - -/** - * DMA buffer. - */ -typedef struct drm_buf { - int idx; /**< Index into master buflist */ - int total; /**< Buffer size */ - int order; /**< log-base-2(total) */ - int used; /**< Amount of buffer in use (for DMA) */ - unsigned long offset; /**< Byte offset (used internally) */ - void *address; /**< Address of buffer */ - unsigned long bus_address; /**< Bus address of buffer */ - struct drm_buf *next; /**< Kernel-only: used for free list */ - __volatile__ int waiting; /**< On kernel DMA queue */ - __volatile__ int pending; /**< On hardware DMA queue */ - wait_queue_head_t dma_wait; /**< Processes waiting */ - struct file *filp; /**< Pointer to holding file descr */ - int context; /**< Kernel queue for this buffer */ - int while_locked;/**< Dispatch this buffer while locked */ - enum { - DRM_LIST_NONE = 0, - DRM_LIST_FREE = 1, - DRM_LIST_WAIT = 2, - DRM_LIST_PEND = 3, - DRM_LIST_PRIO = 4, - DRM_LIST_RECLAIM = 5 - } list; /**< Which list we're on */ - - int dev_priv_size; /**< Size of buffer private storage */ - void *dev_private; /**< Per-buffer private storage */ -} drm_buf_t; - - -/** bufs is one longer than it has to be */ -typedef struct drm_waitlist { - int count; /**< Number of possible buffers */ - drm_buf_t **bufs; /**< List of pointers to buffers */ - drm_buf_t **rp; /**< Read pointer */ - drm_buf_t **wp; /**< Write pointer */ - drm_buf_t **end; /**< End pointer */ - spinlock_t read_lock; - spinlock_t write_lock; -} drm_waitlist_t; - -typedef struct drm_freelist { - int initialized; /**< Freelist in use */ - atomic_t count; /**< Number of free buffers */ - drm_buf_t *next; /**< End pointer */ - - wait_queue_head_t waiting; /**< Processes waiting on free bufs */ - int low_mark; /**< Low water mark */ - int high_mark; /**< High water mark */ - atomic_t wfh; /**< If waiting for high mark */ - spinlock_t lock; -} drm_freelist_t; - -/** - * Buffer entry. There is one of this for each buffer size order. - */ -typedef struct drm_buf_entry { - int buf_size; /**< size */ - int buf_count; /**< number of buffers */ - drm_buf_t *buflist; /**< buffer list */ - int seg_count; - int page_order; - unsigned long *seglist; - - drm_freelist_t freelist; -} drm_buf_entry_t; - -/** File private data */ -typedef struct drm_file { - int authenticated; - int minor; - pid_t pid; - uid_t uid; - drm_magic_t magic; - unsigned long ioctl_count; - struct drm_file *next; - struct drm_file *prev; - struct drm_device *dev; - int remove_auth_on_close; - unsigned long lock_count; - void *driver_priv; -} drm_file_t; - -/** Wait queue */ -typedef struct drm_queue { - atomic_t use_count; /**< Outstanding uses (+1) */ - atomic_t finalization; /**< Finalization in progress */ - atomic_t block_count; /**< Count of processes waiting */ - atomic_t block_read; /**< Queue blocked for reads */ - wait_queue_head_t read_queue; /**< Processes waiting on block_read */ - atomic_t block_write; /**< Queue blocked for writes */ - wait_queue_head_t write_queue; /**< Processes waiting on block_write */ -#if 1 - atomic_t total_queued; /**< Total queued statistic */ - atomic_t total_flushed;/**< Total flushes statistic */ - atomic_t total_locks; /**< Total locks statistics */ -#endif - drm_ctx_flags_t flags; /**< Context preserving and 2D-only */ - drm_waitlist_t waitlist; /**< Pending buffers */ - wait_queue_head_t flush_queue; /**< Processes waiting until flush */ -} drm_queue_t; - -/** - * Lock data. - */ -typedef struct drm_lock_data { - drm_hw_lock_t *hw_lock; /**< Hardware lock */ - struct file *filp; /**< File descr of lock holder (0=kernel) */ - wait_queue_head_t lock_queue; /**< Queue of blocked processes */ - unsigned long lock_time; /**< Time of last lock in jiffies */ -} drm_lock_data_t; - -/** - * DMA data. - */ -typedef struct drm_device_dma { - - drm_buf_entry_t bufs[DRM_MAX_ORDER+1]; /**< buffers, grouped by their size order */ - int buf_count; /**< total number of buffers */ - drm_buf_t **buflist; /**< Vector of pointers into drm_device_dma::bufs */ - int seg_count; - int page_count; /**< number of pages */ - unsigned long *pagelist; /**< page list */ - unsigned long byte_count; - enum { - _DRM_DMA_USE_AGP = 0x01, - _DRM_DMA_USE_SG = 0x02 - } flags; - - /** \name DMA support */ - /*@{*/ - drm_buf_t *this_buffer; /**< Buffer being sent */ - drm_buf_t *next_buffer; /**< Selected buffer to send */ - drm_queue_t *next_queue; /**< Queue from which buffer selected*/ - wait_queue_head_t waiting; /**< Processes waiting on free bufs */ - /*@}*/ -} drm_device_dma_t; - -#if __OS_HAS_AGP -/** - * AGP memory entry. Stored as a doubly linked list. - */ -typedef struct drm_agp_mem { - unsigned long handle; /**< handle */ - DRM_AGP_MEM *memory; - unsigned long bound; /**< address */ - int pages; - struct drm_agp_mem *prev; /**< previous entry */ - struct drm_agp_mem *next; /**< next entry */ -} drm_agp_mem_t; - -/** - * AGP data. - * - * \sa DRM(agp_init)() and drm_device::agp. - */ -typedef struct drm_agp_head { - DRM_AGP_KERN agp_info; /**< AGP device information */ - drm_agp_mem_t *memory; /**< memory entries */ - unsigned long mode; /**< AGP mode */ - int enabled; /**< whether the AGP bus as been enabled */ - int acquired; /**< whether the AGP device has been acquired */ - unsigned long base; - int agp_mtrr; - int cant_use_aperture; - unsigned long page_mask; -} drm_agp_head_t; -#endif - -/** - * Scatter-gather memory. - */ -typedef struct drm_sg_mem { - unsigned long handle; - void *virtual; - int pages; - struct page **pagelist; - dma_addr_t *busaddr; -} drm_sg_mem_t; - -typedef struct drm_sigdata { - int context; - drm_hw_lock_t *lock; -} drm_sigdata_t; - -/** - * Mappings list - */ -typedef struct drm_map_list { - struct list_head head; /**< list head */ - drm_map_t *map; /**< mapping */ -} drm_map_list_t; - -typedef drm_map_t drm_local_map_t; - -/** - * Context handle list - */ -typedef struct drm_ctx_list { - struct list_head head; /**< list head */ - drm_context_t handle; /**< context handle */ - drm_file_t *tag; /**< associated fd private data */ -} drm_ctx_list_t; - - -typedef struct drm_vbl_sig { - struct list_head head; - unsigned int sequence; - struct siginfo info; - struct task_struct *task; -} drm_vbl_sig_t; - - -/** - * DRM device functions structure - */ -struct drm_device; - -struct drm_driver_fn { - int (*preinit)(struct drm_device *, unsigned long flags); - int (*postinit)(struct drm_device *, unsigned long flags); - void (*prerelease)(struct drm_device *, struct file *filp); - void (*pretakedown)(struct drm_device *); - int (*postcleanup)(struct drm_device *); - int (*presetup)(struct drm_device *); - int (*postsetup)(struct drm_device *); - - /* these are opposites at the moment */ - int (*open_helper)(struct drm_device *, drm_file_t *); - void (*free_filp_private)(struct drm_device *, drm_file_t *); - - void (*release)(struct drm_device *, struct file *filp); - void (*dma_ready)(struct drm_device *); - int (*dma_quiescent)(struct drm_device *); - int (*context_ctor)(struct drm_device *dev, int context); - int (*context_dtor)(struct drm_device *dev, int context); - int (*kernel_context_switch)(struct drm_device *dev, int old, int new); - int (*kernel_context_switch_unlock)(struct drm_device *dev); - int (*vblank_wait)(struct drm_device *dev, unsigned int *sequence); -/* these have to be filled in */ - irqreturn_t (*irq_handler)( DRM_IRQ_ARGS ); - void (*irq_preinstall)(struct drm_device *dev); - void (*irq_postinstall)(struct drm_device *dev); - void (*irq_uninstall)(struct drm_device *dev); - void (*reclaim_buffers)(struct file *filp); - unsigned long (*get_map_ofs)(drm_map_t *map); - unsigned long (*get_reg_ofs)(struct drm_device *dev); - void (*set_version)(struct drm_device *dev, drm_set_version_t *sv); -}; - -/** - * DRM device structure. - */ -typedef struct drm_device { - const char *name; /**< Simple driver name */ - char *unique; /**< Unique identifier: e.g., busid */ - int unique_len; /**< Length of unique field */ - dev_t device; /**< Device number for mknod */ - char *devname; /**< For /proc/interrupts */ - int minor; /**< Minor device number */ - int if_version; /**< Highest interface version set */ - - int blocked; /**< Blocked due to VC switch? */ - struct proc_dir_entry *root; /**< Root for this device's entries */ - - /** \name Locks */ - /*@{*/ - spinlock_t count_lock; /**< For inuse, drm_device::open_count, drm_device::buf_use */ - struct semaphore struct_sem; /**< For others */ - /*@}*/ - - /** \name Usage Counters */ - /*@{*/ - int open_count; /**< Outstanding files open */ - atomic_t ioctl_count; /**< Outstanding IOCTLs pending */ - atomic_t vma_count; /**< Outstanding vma areas open */ - int buf_use; /**< Buffers in use -- cannot alloc */ - atomic_t buf_alloc; /**< Buffer allocation in progress */ - /*@}*/ - - /** \name Performance counters */ - /*@{*/ - unsigned long counters; - drm_stat_type_t types[15]; - atomic_t counts[15]; - /*@}*/ - - /** \name Authentication */ - /*@{*/ - drm_file_t *file_first; /**< file list head */ - drm_file_t *file_last; /**< file list tail */ - drm_magic_head_t magiclist[DRM_HASH_SIZE]; /**< magic hash table */ - /*@}*/ - - /** \name Memory management */ - /*@{*/ - drm_map_list_t *maplist; /**< Linked list of regions */ - int map_count; /**< Number of mappable regions */ - - /** \name Context handle management */ - /*@{*/ - drm_ctx_list_t *ctxlist; /**< Linked list of context handles */ - int ctx_count; /**< Number of context handles */ - struct semaphore ctxlist_sem; /**< For ctxlist */ - - drm_map_t **context_sareas; /**< per-context SAREA's */ - int max_context; - - drm_vma_entry_t *vmalist; /**< List of vmas (for debugging) */ - drm_lock_data_t lock; /**< Information on hardware lock */ - /*@}*/ - - /** \name DMA queues (contexts) */ - /*@{*/ - int queue_count; /**< Number of active DMA queues */ - int queue_reserved; /**< Number of reserved DMA queues */ - int queue_slots; /**< Actual length of queuelist */ - drm_queue_t **queuelist; /**< Vector of pointers to DMA queues */ - drm_device_dma_t *dma; /**< Optional pointer for DMA support */ - /*@}*/ - - /** \name Context support */ - /*@{*/ - int irq; /**< Interrupt used by board */ - int irq_enabled; /**< True if irq handler is enabled */ - __volatile__ long context_flag; /**< Context swapping flag */ - __volatile__ long interrupt_flag; /**< Interruption handler flag */ - __volatile__ long dma_flag; /**< DMA dispatch flag */ - struct timer_list timer; /**< Timer for delaying ctx switch */ - wait_queue_head_t context_wait; /**< Processes waiting on ctx switch */ - int last_checked; /**< Last context checked for DMA */ - int last_context; /**< Last current context */ - unsigned long last_switch; /**< jiffies at last context switch */ - /*@}*/ - -#if !HAS_WORKQUEUE - struct tq_struct tq; -#else - struct work_struct work; -#endif - /** \name VBLANK IRQ support */ - /*@{*/ - - wait_queue_head_t vbl_queue; /**< VBLANK wait queue */ - atomic_t vbl_received; - spinlock_t vbl_lock; - drm_vbl_sig_t vbl_sigs; /**< signal list to send on VBLANK */ - unsigned int vbl_pending; - - /*@}*/ - cycles_t ctx_start; - cycles_t lck_start; - - char buf[DRM_BSZ]; /**< Output buffer */ - char *buf_rp; /**< Read pointer */ - char *buf_wp; /**< Write pointer */ - char *buf_end; /**< End pointer */ - struct fasync_struct *buf_async;/**< Processes waiting for SIGIO */ - wait_queue_head_t buf_readers; /**< Processes waiting to read */ - wait_queue_head_t buf_writers; /**< Processes waiting to ctx switch */ - -#if __OS_HAS_AGP - drm_agp_head_t *agp; /**< AGP data */ -#endif - - struct pci_dev *pdev; /**< PCI device structure */ - int pci_domain; /**< PCI bus domain number */ - int pci_bus; /**< PCI bus number */ - int pci_slot; /**< PCI slot number */ - int pci_func; /**< PCI function number */ -#ifdef __alpha__ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,3) - struct pci_controler *hose; -#else - struct pci_controller *hose; -#endif -#endif - drm_sg_mem_t *sg; /**< Scatter gather memory */ - unsigned long *ctx_bitmap; /**< context bitmap */ - void *dev_private; /**< device private data */ - drm_sigdata_t sigdata; /**< For block_all_signals */ - sigset_t sigmask; - - int need_reset; /**< secondary device needing reset */ - struct drm_driver_fn fn_tbl; - drm_local_map_t *agp_buffer_map; - int dev_priv_size; - u32 driver_features; -} drm_device_t; - -static __inline__ int drm_core_check_feature(struct drm_device *dev, int feature) -{ - return ((dev->driver_features & feature) ? 1 : 0); -} extern void DRM(driver_register_fns)(struct drm_device *dev); @@ -729,27 +140,6 @@ extern int DRM(mmap)(struct file *filp, struct vm_area_struct *vma); extern unsigned int DRM(poll)(struct file *filp, struct poll_table_struct *wait); extern ssize_t DRM(read)(struct file *filp, char __user *buf, size_t count, loff_t *off); - /* Memory management support (drm_memory.h) */ -extern void DRM(mem_init)(void); -extern int DRM(mem_info)(char *buf, char **start, off_t offset, - int request, int *eof, void *data); -extern void *DRM(calloc)(size_t nmemb, size_t size, int area); -extern void *DRM(realloc)(void *oldpt, size_t oldsize, size_t size, - int area); -extern unsigned long DRM(alloc_pages)(int order, int area); -extern void DRM(free_pages)(unsigned long address, int order, - int area); -extern void *DRM(ioremap)(unsigned long offset, unsigned long size, drm_device_t *dev); -extern void *DRM(ioremap_nocache)(unsigned long offset, unsigned long size, - drm_device_t *dev); -extern void DRM(ioremapfree)(void *pt, unsigned long size, drm_device_t *dev); - -#if __OS_HAS_AGP -extern DRM_AGP_MEM *DRM(alloc_agp)(int pages, u32 type); -extern int DRM(free_agp)(DRM_AGP_MEM *handle, int pages); -extern int DRM(bind_agp)(DRM_AGP_MEM *handle, unsigned int start); -extern int DRM(unbind_agp)(DRM_AGP_MEM *handle); -#endif /* Misc. IOCTL support (drm_ioctl.h) */ extern int DRM(irq_by_busid)(struct inode *inode, struct file *filp, @@ -825,31 +215,6 @@ extern int DRM(lock_free)(drm_device_t *dev, unsigned int context); extern int DRM(notifier)(void *priv); - /* Buffer management support (drm_bufs.h) */ -extern int DRM(order)( unsigned long size ); -extern int DRM(addmap)( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ); -extern int DRM(rmmap)( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ); -extern int DRM(initmap)( drm_device_t *dev, unsigned int offset, - unsigned int size, int type, int flags ); -extern int DRM(addbufs)( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ); -extern int DRM(infobufs)( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ); -extern int DRM(markbufs)( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ); -extern int DRM(freebufs)( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ); -extern int DRM(mapbufs)( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ); - - /* DMA support (drm_dma.h) */ -extern int DRM(dma_setup)(drm_device_t *dev); -extern void DRM(dma_takedown)(drm_device_t *dev); -extern void DRM(free_buffer)(drm_device_t *dev, drm_buf_t *buf); -extern void DRM(reclaim_buffers)( struct file *filp ); - /* IRQ support (drm_irq.h) */ extern int DRM(control)( struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg ); @@ -866,32 +231,7 @@ extern int DRM(vblank_wait)(drm_device_t *dev, unsigned int *vbl_seq); extern void DRM(vbl_send_signals)( drm_device_t *dev ); -#if __OS_HAS_AGP - /* AGP/GART support (drm_agpsupport.h) */ -extern drm_agp_head_t *DRM(agp_init)(void); -extern void DRM(agp_uninit)(void); -extern int DRM(agp_acquire)(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); -extern void DRM(agp_do_release)(void); -extern int DRM(agp_release)(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); -extern int DRM(agp_enable)(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); -extern int DRM(agp_info)(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); -extern int DRM(agp_alloc)(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); -extern int DRM(agp_free)(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); -extern int DRM(agp_unbind)(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); -extern int DRM(agp_bind)(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); -extern DRM_AGP_MEM *DRM(agp_allocate_memory)(size_t pages, u32 type); -extern int DRM(agp_free_memory)(DRM_AGP_MEM *handle); -extern int DRM(agp_bind_memory)(DRM_AGP_MEM *handle, off_t start); -extern int DRM(agp_unbind_memory)(DRM_AGP_MEM *handle); -#endif + /* Stub support (drm_stub.h) */ int DRM(stub_register)(const char *name, @@ -900,11 +240,11 @@ int DRM(stub_register)(const char *name, int DRM(stub_unregister)(int minor); /* Proc support (drm_proc.h) */ -extern int DRM(proc_init)(drm_device_t *dev, +extern int drm_proc_init(drm_device_t *dev, int minor, struct proc_dir_entry *root, struct proc_dir_entry **dev_root); -extern int DRM(proc_cleanup)(int minor, +extern int drm_proc_cleanup(int minor, struct proc_dir_entry *root, struct proc_dir_entry *dev_root); @@ -915,13 +255,7 @@ extern int DRM(sg_alloc)(struct inode *inode, struct file *filp, extern int DRM(sg_free)(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); - /* ATI PCIGART support (ati_pcigart.h) */ -extern int DRM(ati_pcigart_init)(drm_device_t *dev, - unsigned long *addr, - dma_addr_t *bus_addr); -extern int DRM(ati_pcigart_cleanup)(drm_device_t *dev, - unsigned long addr, - dma_addr_t bus_addr); + extern void *DRM(pci_alloc)(drm_device_t *dev, size_t size, size_t align, dma_addr_t maxaddr, @@ -930,56 +264,9 @@ extern void DRM(pci_free)(drm_device_t *dev, size_t size, void *vaddr, dma_addr_t busaddr); -/* Inline replacements for DRM_IOREMAP macros */ -static __inline__ void drm_core_ioremap(struct drm_map *map, struct drm_device *dev) -{ - map->handle = DRM(ioremap)( map->offset, map->size, dev ); -} - -static __inline__ void drm_core_ioremap_nocache(struct drm_map *map, struct drm_device *dev) -{ - map->handle = DRM(ioremap_nocache)(map->offset, map->size, dev); -} - -static __inline__ void drm_core_ioremapfree(struct drm_map *map, struct drm_device *dev) -{ - if ( map->handle && map->size ) - DRM(ioremapfree)( map->handle, map->size, dev ); -} - -static __inline__ struct drm_map *drm_core_findmap(struct drm_device *dev, unsigned long offset) -{ - struct list_head *_list; - list_for_each( _list, &dev->maplist->head ) { - drm_map_list_t *_entry = list_entry( _list, drm_map_list_t, head ); - if ( _entry->map && - _entry->map->offset == offset ) { - return _entry->map; - } - } - return NULL; -} - -static __inline__ void drm_core_dropmap(struct drm_map *map) -{ -} - -#ifndef DEBUG_MEMORY -/** Wrapper around kmalloc() */ -static __inline__ void *DRM(alloc)(size_t size, int area) -{ - return kmalloc(size, GFP_KERNEL); -} - -/** Wrapper around kfree() */ -static __inline__ void DRM(free)(void *pt, size_t size, int area) -{ - kfree(pt); -} -#else -extern void *DRM(alloc)(size_t size, int area); -extern void DRM(free)(void *pt, size_t size, int area); -#endif + + + /*@}*/ diff --git a/linux-core/drm_auth.c b/linux-core/drm_auth.c index fe099871..2931ac22 100644 --- a/linux-core/drm_auth.c +++ b/linux-core/drm_auth.c @@ -95,7 +95,7 @@ int DRM(add_magic)(drm_device_t *dev, drm_file_t *priv, drm_magic_t magic) DRM_DEBUG("%d\n", magic); hash = DRM(hash_magic)(magic); - entry = DRM(alloc)(sizeof(*entry), DRM_MEM_MAGIC); + entry = drm_core_alloc(sizeof(*entry), DRM_MEM_MAGIC); if (!entry) return -ENOMEM; memset(entry, 0, sizeof(*entry)); entry->magic = magic; @@ -152,7 +152,7 @@ int DRM(remove_magic)(drm_device_t *dev, drm_magic_t magic) } up(&dev->struct_sem); - DRM(free)(pt, sizeof(*pt), DRM_MEM_MAGIC); + drm_core_free(pt, sizeof(*pt), DRM_MEM_MAGIC); return -EINVAL; } diff --git a/linux-core/drm_context.c b/linux-core/drm_context.c index e1cb95c6..8bad6b39 100644 --- a/linux-core/drm_context.c +++ b/linux-core/drm_context.c @@ -100,7 +100,7 @@ int DRM(ctxbitmap_next)( drm_device_t *dev ) if(dev->context_sareas) { drm_map_t **ctx_sareas; - ctx_sareas = DRM(realloc)(dev->context_sareas, + ctx_sareas = drm_core_realloc(dev->context_sareas, (dev->max_context - 1) * sizeof(*dev->context_sareas), dev->max_context * @@ -115,7 +115,7 @@ int DRM(ctxbitmap_next)( drm_device_t *dev ) dev->context_sareas[bit] = NULL; } else { /* max_context == 1 at this point */ - dev->context_sareas = DRM(alloc)( + dev->context_sareas = drm_core_alloc( dev->max_context * sizeof(*dev->context_sareas), DRM_MEM_MAPS); @@ -148,7 +148,7 @@ int DRM(ctxbitmap_init)( drm_device_t *dev ) int temp; down(&dev->struct_sem); - dev->ctx_bitmap = (unsigned long *) DRM(alloc)( PAGE_SIZE, + dev->ctx_bitmap = (unsigned long *) drm_core_alloc( PAGE_SIZE, DRM_MEM_CTXBITMAP ); if ( dev->ctx_bitmap == NULL ) { up(&dev->struct_sem); @@ -178,11 +178,11 @@ int DRM(ctxbitmap_init)( drm_device_t *dev ) void DRM(ctxbitmap_cleanup)( drm_device_t *dev ) { down(&dev->struct_sem); - if( dev->context_sareas ) DRM(free)( dev->context_sareas, + if( dev->context_sareas ) drm_core_free( dev->context_sareas, sizeof(*dev->context_sareas) * dev->max_context, DRM_MEM_MAPS ); - DRM(free)( (void *)dev->ctx_bitmap, PAGE_SIZE, DRM_MEM_CTXBITMAP ); + drm_core_free( (void *)dev->ctx_bitmap, PAGE_SIZE, DRM_MEM_CTXBITMAP ); up(&dev->struct_sem); } @@ -421,7 +421,7 @@ int DRM(addctx)( struct inode *inode, struct file *filp, dev->fn_tbl.context_ctor(dev, ctx.handle); } - ctx_entry = DRM(alloc)( sizeof(*ctx_entry), DRM_MEM_CTXLIST ); + ctx_entry = drm_core_alloc( sizeof(*ctx_entry), DRM_MEM_CTXLIST ); if ( !ctx_entry ) { DRM_DEBUG("out of memory\n"); return -ENOMEM; @@ -564,7 +564,7 @@ int DRM(rmctx)( struct inode *inode, struct file *filp, list_for_each_entry_safe( pos, n, &dev->ctxlist->head, head ) { if ( pos->handle == ctx.handle ) { list_del( &pos->head ); - DRM(free)( pos, sizeof(*pos), DRM_MEM_CTXLIST ); + drm_core_free( pos, sizeof(*pos), DRM_MEM_CTXLIST ); --dev->ctx_count; } } diff --git a/linux-core/drm_core.h b/linux-core/drm_core.h new file mode 100644 index 00000000..435d5cbf --- /dev/null +++ b/linux-core/drm_core.h @@ -0,0 +1,699 @@ +#ifndef DRM_CORE_H +#define DRM_CORE_H + +#include "drm_compat.h" +#define DRM_PROC_LIMIT (PAGE_SIZE-80) + +#define DRM_PROC_PRINT(fmt, arg...) \ + len += sprintf(&buf[len], fmt , ##arg); \ + if (len > DRM_PROC_LIMIT) { *eof = 1; return len - offset; } + +#define DRM_PROC_PRINT_RET(ret, fmt, arg...) \ + len += sprintf(&buf[len], fmt , ##arg); \ + if (len > DRM_PROC_LIMIT) { ret; *eof = 1; return len - offset; } + +/** + * Memory error output. + * + * \param area memory area where the error occurred. + * \param fmt printf() like format string. + * \param arg arguments + */ +#define DRM_INFO(fmt, arg...) printk(KERN_INFO "[" DRM_NAME "] " fmt , ##arg) + +/** + * Error output. + * + * \param fmt printf() like format string. + * \param arg arguments + */ +#define DRM_ERROR(fmt, arg...) \ + printk(KERN_ERR "[" DRM_NAME ":%s] *ERROR* " fmt , __FUNCTION__ , ##arg) + +#if DRM_DEBUG_CODE +#define DRM_DEBUG(fmt, arg...) \ + do { \ + if (1) \ + printk(KERN_DEBUG \ + "[" DRM_NAME ":%s] " fmt , \ + __FUNCTION__ , ##arg); \ + } while (0) +#else +#define DRM_DEBUG(fmt, arg...) do { } while (0) +#endif + +#define DRM_LEFTCOUNT(x) (((x)->rp + (x)->count - (x)->wp) % ((x)->count + 1)) +#define DRM_BUFCOUNT(x) ((x)->count - DRM_LEFTCOUNT(x)) +#define DRM_WAITCOUNT(dev,idx) DRM_BUFCOUNT(&dev->queuelist[idx]->waitlist) + + +/* driver capabilities and requirements mask */ +#define DRIVER_USE_AGP 0x1 +#define DRIVER_REQUIRE_AGP 0x2 +#define DRIVER_USE_MTRR 0x4 +#define DRIVER_HAVE_DMA 0x10 +#define DRIVER_HAVE_IRQ 0x20 +#define DRIVER_SG 0x40 +#define DRIVER_PCI_DMA 0x80 +#define DRIVER_IRQ_SHARED 0x100 +#define DRIVER_IRQ_VBL 0x200 +#define DRIVER_DMA_QUEUE 0x800 + +#define __OS_HAS_AGP (defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE)) +#define __OS_HAS_MTRR (defined(CONFIG_MTRR)) +/*@}*/ +#define DRM_DEBUG_CODE 2 /**< Include debugging code if > 1, then + also include looping detection. */ + +#define DRM_HASH_SIZE 16 /**< Size of key hash table. Must be power of 2. */ +#define DRM_KERNEL_CONTEXT 0 /**< Change drm_resctx if changed */ +#define DRM_RESERVED_CONTEXTS 1 /**< Change drm_resctx if changed */ +#define DRM_LOOPING_LIMIT 5000000 +#define DRM_BSZ 1024 /**< Buffer size for /dev/drm? output */ +#define DRM_TIME_SLICE (HZ/20) /**< Time slice for GLXContexts */ +#define DRM_LOCK_SLICE 1 /**< Time slice for lock, in jiffies */ + +#define DRM_FLAG_DEBUG 0x01 + +#define DRM_MEM_DMA 0 +#define DRM_MEM_SAREA 1 +#define DRM_MEM_DRIVER 2 +#define DRM_MEM_MAGIC 3 +#define DRM_MEM_IOCTLS 4 +#define DRM_MEM_MAPS 5 +#define DRM_MEM_VMAS 6 +#define DRM_MEM_BUFS 7 +#define DRM_MEM_SEGS 8 +#define DRM_MEM_PAGES 9 +#define DRM_MEM_FILES 10 +#define DRM_MEM_QUEUES 11 +#define DRM_MEM_CMDS 12 +#define DRM_MEM_MAPPINGS 13 +#define DRM_MEM_BUFLISTS 14 +#define DRM_MEM_AGPLISTS 15 +#define DRM_MEM_TOTALAGP 16 +#define DRM_MEM_BOUNDAGP 17 +#define DRM_MEM_CTXBITMAP 18 +#define DRM_MEM_STUB 19 +#define DRM_MEM_SGLISTS 20 +#define DRM_MEM_CTXLIST 21 + +/** + * Ioctl function type. + * + * \param inode device inode. + * \param filp file pointer. + * \param cmd command. + * \param arg argument. + */ +typedef int drm_ioctl_t( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ); + +typedef struct drm_ioctl_desc { + drm_ioctl_t *func; + int auth_needed; + int root_only; +} drm_ioctl_desc_t; + +typedef struct drm_devstate { + pid_t owner; /**< X server pid holding x_lock */ +} drm_devstate_t; + +typedef struct drm_magic_entry { + drm_magic_t magic; + struct drm_file *priv; + struct drm_magic_entry *next; +} drm_magic_entry_t; + +typedef struct drm_magic_head { + struct drm_magic_entry *head; + struct drm_magic_entry *tail; +} drm_magic_head_t; + +typedef struct drm_vma_entry { + struct vm_area_struct *vma; + struct drm_vma_entry *next; + pid_t pid; +} drm_vma_entry_t; + +/** + * DMA buffer. + */ +typedef struct drm_buf { + int idx; /**< Index into master buflist */ + int total; /**< Buffer size */ + int order; /**< log-base-2(total) */ + int used; /**< Amount of buffer in use (for DMA) */ + unsigned long offset; /**< Byte offset (used internally) */ + void *address; /**< Address of buffer */ + unsigned long bus_address; /**< Bus address of buffer */ + struct drm_buf *next; /**< Kernel-only: used for free list */ + __volatile__ int waiting; /**< On kernel DMA queue */ + __volatile__ int pending; /**< On hardware DMA queue */ + wait_queue_head_t dma_wait; /**< Processes waiting */ + struct file *filp; /**< Pointer to holding file descr */ + int context; /**< Kernel queue for this buffer */ + int while_locked;/**< Dispatch this buffer while locked */ + enum { + DRM_LIST_NONE = 0, + DRM_LIST_FREE = 1, + DRM_LIST_WAIT = 2, + DRM_LIST_PEND = 3, + DRM_LIST_PRIO = 4, + DRM_LIST_RECLAIM = 5 + } list; /**< Which list we're on */ + + int dev_priv_size; /**< Size of buffer private storage */ + void *dev_private; /**< Per-buffer private storage */ +} drm_buf_t; + + +/** bufs is one longer than it has to be */ +typedef struct drm_waitlist { + int count; /**< Number of possible buffers */ + drm_buf_t **bufs; /**< List of pointers to buffers */ + drm_buf_t **rp; /**< Read pointer */ + drm_buf_t **wp; /**< Write pointer */ + drm_buf_t **end; /**< End pointer */ + spinlock_t read_lock; + spinlock_t write_lock; +} drm_waitlist_t; + +typedef struct drm_freelist { + int initialized; /**< Freelist in use */ + atomic_t count; /**< Number of free buffers */ + drm_buf_t *next; /**< End pointer */ + + wait_queue_head_t waiting; /**< Processes waiting on free bufs */ + int low_mark; /**< Low water mark */ + int high_mark; /**< High water mark */ + atomic_t wfh; /**< If waiting for high mark */ + spinlock_t lock; +} drm_freelist_t; + +/** + * Buffer entry. There is one of this for each buffer size order. + */ +typedef struct drm_buf_entry { + int buf_size; /**< size */ + int buf_count; /**< number of buffers */ + drm_buf_t *buflist; /**< buffer list */ + int seg_count; + int page_order; + unsigned long *seglist; + + drm_freelist_t freelist; +} drm_buf_entry_t; + +/** File private data */ +typedef struct drm_file { + int authenticated; + int minor; + pid_t pid; + uid_t uid; + drm_magic_t magic; + unsigned long ioctl_count; + struct drm_file *next; + struct drm_file *prev; + struct drm_device *dev; + int remove_auth_on_close; + unsigned long lock_count; + void *driver_priv; +} drm_file_t; + +/** Wait queue */ +typedef struct drm_queue { + atomic_t use_count; /**< Outstanding uses (+1) */ + atomic_t finalization; /**< Finalization in progress */ + atomic_t block_count; /**< Count of processes waiting */ + atomic_t block_read; /**< Queue blocked for reads */ + wait_queue_head_t read_queue; /**< Processes waiting on block_read */ + atomic_t block_write; /**< Queue blocked for writes */ + wait_queue_head_t write_queue; /**< Processes waiting on block_write */ +#if 1 + atomic_t total_queued; /**< Total queued statistic */ + atomic_t total_flushed;/**< Total flushes statistic */ + atomic_t total_locks; /**< Total locks statistics */ +#endif + drm_ctx_flags_t flags; /**< Context preserving and 2D-only */ + drm_waitlist_t waitlist; /**< Pending buffers */ + wait_queue_head_t flush_queue; /**< Processes waiting until flush */ +} drm_queue_t; + +/** + * Lock data. + */ +typedef struct drm_lock_data { + drm_hw_lock_t *hw_lock; /**< Hardware lock */ + struct file *filp; /**< File descr of lock holder (0=kernel) */ + wait_queue_head_t lock_queue; /**< Queue of blocked processes */ + unsigned long lock_time; /**< Time of last lock in jiffies */ +} drm_lock_data_t; + +/** + * DMA data. + */ +typedef struct drm_device_dma { + + drm_buf_entry_t bufs[DRM_MAX_ORDER+1]; /**< buffers, grouped by their size order */ + int buf_count; /**< total number of buffers */ + drm_buf_t **buflist; /**< Vector of pointers into drm_device_dma::bufs */ + int seg_count; + int page_count; /**< number of pages */ + unsigned long *pagelist; /**< page list */ + unsigned long byte_count; + enum { + _DRM_DMA_USE_AGP = 0x01, + _DRM_DMA_USE_SG = 0x02 + } flags; + + /** \name DMA support */ + /*@{*/ + drm_buf_t *this_buffer; /**< Buffer being sent */ + drm_buf_t *next_buffer; /**< Selected buffer to send */ + drm_queue_t *next_queue; /**< Queue from which buffer selected*/ + wait_queue_head_t waiting; /**< Processes waiting on free bufs */ + /*@}*/ +} drm_device_dma_t; + +#if __OS_HAS_AGP +/** + * AGP memory entry. Stored as a doubly linked list. + */ +typedef struct drm_agp_mem { + unsigned long handle; /**< handle */ + DRM_AGP_MEM *memory; + unsigned long bound; /**< address */ + int pages; + struct drm_agp_mem *prev; /**< previous entry */ + struct drm_agp_mem *next; /**< next entry */ +} drm_agp_mem_t; + +/** + * AGP data. + * + * \sa DRM(agp_init)() and drm_device::agp. + */ +typedef struct drm_agp_head { + DRM_AGP_KERN agp_info; /**< AGP device information */ + drm_agp_mem_t *memory; /**< memory entries */ + unsigned long mode; /**< AGP mode */ + int enabled; /**< whether the AGP bus as been enabled */ + int acquired; /**< whether the AGP device has been acquired */ + unsigned long base; + int agp_mtrr; + int cant_use_aperture; + unsigned long page_mask; +} drm_agp_head_t; +#endif + +/** + * Scatter-gather memory. + */ +typedef struct drm_sg_mem { + unsigned long handle; + void *virtual; + int pages; + struct page **pagelist; + dma_addr_t *busaddr; +} drm_sg_mem_t; + +typedef struct drm_sigdata { + int context; + drm_hw_lock_t *lock; +} drm_sigdata_t; + +/** + * Mappings list + */ +typedef struct drm_map_list { + struct list_head head; /**< list head */ + drm_map_t *map; /**< mapping */ +} drm_map_list_t; + +typedef drm_map_t drm_local_map_t; + +/** + * Context handle list + */ +typedef struct drm_ctx_list { + struct list_head head; /**< list head */ + drm_context_t handle; /**< context handle */ + drm_file_t *tag; /**< associated fd private data */ +} drm_ctx_list_t; + + +typedef struct drm_vbl_sig { + struct list_head head; + unsigned int sequence; + struct siginfo info; + struct task_struct *task; +} drm_vbl_sig_t; + + +/** + * DRM device functions structure + */ +struct drm_device; + +struct drm_driver_fn { + int (*preinit)(struct drm_device *, unsigned long flags); + int (*postinit)(struct drm_device *, unsigned long flags); + void (*prerelease)(struct drm_device *, struct file *filp); + void (*pretakedown)(struct drm_device *); + int (*postcleanup)(struct drm_device *); + int (*presetup)(struct drm_device *); + int (*postsetup)(struct drm_device *); + + /* these are opposites at the moment */ + int (*open_helper)(struct drm_device *, drm_file_t *); + void (*free_filp_private)(struct drm_device *, drm_file_t *); + + void (*release)(struct drm_device *, struct file *filp); + void (*dma_ready)(struct drm_device *); + int (*dma_quiescent)(struct drm_device *); + int (*context_ctor)(struct drm_device *dev, int context); + int (*context_dtor)(struct drm_device *dev, int context); + int (*kernel_context_switch)(struct drm_device *dev, int old, int new); + int (*kernel_context_switch_unlock)(struct drm_device *dev); + int (*vblank_wait)(struct drm_device *dev, unsigned int *sequence); +/* these have to be filled in */ + irqreturn_t (*irq_handler)( DRM_IRQ_ARGS ); + void (*irq_preinstall)(struct drm_device *dev); + void (*irq_postinstall)(struct drm_device *dev); + void (*irq_uninstall)(struct drm_device *dev); + void (*reclaim_buffers)(struct file *filp); + unsigned long (*get_map_ofs)(drm_map_t *map); + unsigned long (*get_reg_ofs)(struct drm_device *dev); + void (*set_version)(struct drm_device *dev, drm_set_version_t *sv); +}; + +/** + * DRM device structure. + */ +typedef struct drm_device { + const char *name; /**< Simple driver name */ + char *unique; /**< Unique identifier: e.g., busid */ + int unique_len; /**< Length of unique field */ + dev_t device; /**< Device number for mknod */ + char *devname; /**< For /proc/interrupts */ + int minor; /**< Minor device number */ + int if_version; /**< Highest interface version set */ + + int blocked; /**< Blocked due to VC switch? */ + struct proc_dir_entry *root; /**< Root for this device's entries */ + + /** \name Locks */ + /*@{*/ + spinlock_t count_lock; /**< For inuse, drm_device::open_count, drm_device::buf_use */ + struct semaphore struct_sem; /**< For others */ + /*@}*/ + + /** \name Usage Counters */ + /*@{*/ + int open_count; /**< Outstanding files open */ + atomic_t ioctl_count; /**< Outstanding IOCTLs pending */ + atomic_t vma_count; /**< Outstanding vma areas open */ + int buf_use; /**< Buffers in use -- cannot alloc */ + atomic_t buf_alloc; /**< Buffer allocation in progress */ + /*@}*/ + + /** \name Performance counters */ + /*@{*/ + unsigned long counters; + drm_stat_type_t types[15]; + atomic_t counts[15]; + /*@}*/ + + /** \name Authentication */ + /*@{*/ + drm_file_t *file_first; /**< file list head */ + drm_file_t *file_last; /**< file list tail */ + drm_magic_head_t magiclist[DRM_HASH_SIZE]; /**< magic hash table */ + /*@}*/ + + /** \name Memory management */ + /*@{*/ + drm_map_list_t *maplist; /**< Linked list of regions */ + int map_count; /**< Number of mappable regions */ + + /** \name Context handle management */ + /*@{*/ + drm_ctx_list_t *ctxlist; /**< Linked list of context handles */ + int ctx_count; /**< Number of context handles */ + struct semaphore ctxlist_sem; /**< For ctxlist */ + + drm_map_t **context_sareas; /**< per-context SAREA's */ + int max_context; + + drm_vma_entry_t *vmalist; /**< List of vmas (for debugging) */ + drm_lock_data_t lock; /**< Information on hardware lock */ + /*@}*/ + + /** \name DMA queues (contexts) */ + /*@{*/ + int queue_count; /**< Number of active DMA queues */ + int queue_reserved; /**< Number of reserved DMA queues */ + int queue_slots; /**< Actual length of queuelist */ + drm_queue_t **queuelist; /**< Vector of pointers to DMA queues */ + drm_device_dma_t *dma; /**< Optional pointer for DMA support */ + /*@}*/ + + /** \name Context support */ + /*@{*/ + int irq; /**< Interrupt used by board */ + int irq_enabled; /**< True if irq handler is enabled */ + __volatile__ long context_flag; /**< Context swapping flag */ + __volatile__ long interrupt_flag; /**< Interruption handler flag */ + __volatile__ long dma_flag; /**< DMA dispatch flag */ + struct timer_list timer; /**< Timer for delaying ctx switch */ + wait_queue_head_t context_wait; /**< Processes waiting on ctx switch */ + int last_checked; /**< Last context checked for DMA */ + int last_context; /**< Last current context */ + unsigned long last_switch; /**< jiffies at last context switch */ + /*@}*/ + +#if !HAS_WORKQUEUE + struct tq_struct tq; +#else + struct work_struct work; +#endif + /** \name VBLANK IRQ support */ + /*@{*/ + + wait_queue_head_t vbl_queue; /**< VBLANK wait queue */ + atomic_t vbl_received; + spinlock_t vbl_lock; + drm_vbl_sig_t vbl_sigs; /**< signal list to send on VBLANK */ + unsigned int vbl_pending; + + /*@}*/ + cycles_t ctx_start; + cycles_t lck_start; + + char buf[DRM_BSZ]; /**< Output buffer */ + char *buf_rp; /**< Read pointer */ + char *buf_wp; /**< Write pointer */ + char *buf_end; /**< End pointer */ + struct fasync_struct *buf_async;/**< Processes waiting for SIGIO */ + wait_queue_head_t buf_readers; /**< Processes waiting to read */ + wait_queue_head_t buf_writers; /**< Processes waiting to ctx switch */ + +#if __OS_HAS_AGP + drm_agp_head_t *agp; /**< AGP data */ +#endif + + struct pci_dev *pdev; /**< PCI device structure */ + int pci_domain; /**< PCI bus domain number */ + int pci_bus; /**< PCI bus number */ + int pci_slot; /**< PCI slot number */ + int pci_func; /**< PCI function number */ +#ifdef __alpha__ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,3) + struct pci_controler *hose; +#else + struct pci_controller *hose; +#endif +#endif + drm_sg_mem_t *sg; /**< Scatter gather memory */ + unsigned long *ctx_bitmap; /**< context bitmap */ + void *dev_private; /**< device private data */ + drm_sigdata_t sigdata; /**< For block_all_signals */ + sigset_t sigmask; + + int need_reset; /**< secondary device needing reset */ + struct drm_driver_fn fn_tbl; + drm_local_map_t *agp_buffer_map; + int dev_priv_size; + u32 driver_features; +} drm_device_t; + +#if __OS_HAS_AGP +extern DRM_AGP_MEM *drm_memory_alloc_agp(int pages, u32 type); +extern int drm_memory_free_agp(DRM_AGP_MEM *handle, int pages); +extern int drm_memory_bind_agp(DRM_AGP_MEM *handle, unsigned int start); +extern int drm_memory_unbind_agp(DRM_AGP_MEM *handle); +#endif + /* Buffer management support (drm_bufs.h) */ +extern int drm_core_order( unsigned long size ); +extern int drm_core_addmap( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ); +extern int drm_core_rmmap( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ); +extern int drm_core_initmap( drm_device_t *dev, unsigned int offset, + unsigned int size, int type, int flags ); +extern int drm_core_addbufs( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ); +extern int drm_core_infobufs( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ); +extern int drm_core_markbufs( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ); +extern int drm_core_freebufs( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ); +extern int drm_core_mapbufs( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ); + + /* DMA support (drm_dma.h) */ +extern int drm_core_dma_setup(drm_device_t *dev); +extern void drm_core_dma_takedown(drm_device_t *dev); +extern void drm_core_free_buffer(drm_device_t *dev, drm_buf_t *buf); +extern void drm_core_reclaim_buffers( struct file *filp ); + +#if __OS_HAS_AGP + /* AGP/GART support (drm_agpsupport.h) */ +extern drm_agp_head_t *drm_memory_agp_init(void); +extern void drm_memory_agp_uninit(void); +extern int drm_memory_agp_acquire(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern void drm_memory_agp_do_release(void); +extern int drm_memory_agp_release(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_memory_agp_enable(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_memory_agp_info(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_memory_agp_alloc(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_memory_agp_free(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_memory_agp_unbind(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_memory_agp_bind(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern DRM_AGP_MEM *drm_memory_agp_allocate_memory(size_t pages, u32 type); +extern int drm_memory_agp_free_memory(DRM_AGP_MEM *handle); +extern int drm_memory_agp_bind_memory(DRM_AGP_MEM *handle, off_t start); +extern int drm_memory_agp_unbind_memory(DRM_AGP_MEM *handle); +#endif + + /* ATI PCIGART support (ati_pcigart.h) */ +extern int drm_ati_pcigart_init(drm_device_t *dev, + unsigned long *addr, + dma_addr_t *bus_addr); +extern int drm_ati_pcigart_cleanup(drm_device_t *dev, + unsigned long addr, + dma_addr_t bus_addr); + + /* Proc support (drm_proc.h) */ +extern int drm_proc_init(drm_device_t *dev, + int minor, + struct proc_dir_entry *root, + struct proc_dir_entry **dev_root); +extern int drm_proc_cleanup(int minor, + struct proc_dir_entry *root, + struct proc_dir_entry *dev_root); + + +static __inline__ int drm_core_check_feature(struct drm_device *dev, int feature) +{ + return ((dev->driver_features & feature) ? 1 : 0); +} + +#include "drm_core_memory.h" + +#ifndef DEBUG_MEMORY +/** Wrapper around kmalloc() */ +static __inline__ void *drm_core_alloc(size_t size, int area) +{ + return kmalloc(size, GFP_KERNEL); +} + +/** Wrapper around kfree() */ +static __inline__ void drm_core_free(void *pt, size_t size, int area) +{ + kfree(pt); +} + +static __inline__ void drm_core_ioremap(struct drm_map *map, struct drm_device *dev) +{ + map->handle = drm_ioremap( map->offset, map->size, dev ); +} + +static __inline__ void drm_core_ioremap_nocache(struct drm_map *map, struct drm_device *dev) +{ + map->handle = drm_ioremap_nocache(map->offset, map->size, dev); +} + +static __inline__ void drm_core_ioremapfree(struct drm_map *map, struct drm_device *dev) +{ + if ( map->handle && map->size ) + drm_ioremapfree( map->handle, map->size, dev ); +} + +static __inline__ void drm_core_free_pages(unsigned long address, int order, int area) +{ + drm_memory_free_pages(address, order, area); +} + +static __inline__ void *drm_core_realloc(void *oldpt, size_t oldsize, size_t size, int area) +{ + return drm_memory_realloc(oldpt, oldsize, size, area); +} + +static __inline__ unsigned long drm_core_alloc_pages(int order, int area) +{ + return drm_memory_alloc_pages(order, area); +} + +static __inline__ void drm_core_mem_init(void) +{ + drm_memory_mem_init(); +} + +#else +static __inline__ void *drm_core_alloc(size_t size, int area) +{ + return drm_memory_debug_alloc(size, area); +} +static __inline__ void drm_core_free(void *pt, size_t size, int area) +{ + drm_memory_debug_free(pt, size, area); +} +#endif + + +static __inline__ struct drm_map *drm_core_findmap(struct drm_device *dev, unsigned long offset) +{ + struct list_head *_list; + list_for_each( _list, &dev->maplist->head ) { + drm_map_list_t *_entry = list_entry( _list, drm_map_list_t, head ); + if ( _entry->map && + _entry->map->offset == offset ) { + return _entry->map; + } + } + return NULL; +} + +static __inline__ void drm_core_dropmap(struct drm_map *map) +{ +} + +extern int drm_core_dma_setup( drm_device_t *dev ); +extern void drm_core_dma_takedown(drm_device_t *dev); +extern void drm_core_free_buffer(drm_device_t *dev, drm_buf_t *buf); +extern void drm_core_reclaim_buffers( struct file *filp ); + + + +#endif diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index 8f42e357..e8cf159b 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -126,8 +126,8 @@ drm_ioctl_desc_t DRM(ioctls)[] = { [DRM_IOCTL_NR(DRM_IOCTL_UNBLOCK)] = { DRM(noop), 1, 1 }, [DRM_IOCTL_NR(DRM_IOCTL_AUTH_MAGIC)] = { DRM(authmagic), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_ADD_MAP)] = { DRM(addmap), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_RM_MAP)] = { DRM(rmmap), 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_ADD_MAP)] = { drm_core_addmap, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_RM_MAP)] = { drm_core_rmmap, 1, 0 }, [DRM_IOCTL_NR(DRM_IOCTL_SET_SAREA_CTX)] = { DRM(setsareactx), 1, 1 }, [DRM_IOCTL_NR(DRM_IOCTL_GET_SAREA_CTX)] = { DRM(getsareactx), 1, 0 }, @@ -148,24 +148,24 @@ drm_ioctl_desc_t DRM(ioctls)[] = { [DRM_IOCTL_NR(DRM_IOCTL_FINISH)] = { DRM(noop), 1, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_ADD_BUFS)] = { DRM(addbufs), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_MARK_BUFS)] = { DRM(markbufs), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_INFO_BUFS)] = { DRM(infobufs), 1, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_MAP_BUFS)] = { DRM(mapbufs), 1, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_FREE_BUFS)] = { DRM(freebufs), 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_ADD_BUFS)] = { drm_core_addbufs, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_MARK_BUFS)] = { drm_core_markbufs, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_INFO_BUFS)] = { drm_core_infobufs, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_MAP_BUFS)] = { drm_core_mapbufs, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_FREE_BUFS)] = { drm_core_freebufs, 1, 0 }, /* The DRM_IOCTL_DMA ioctl should be defined by the driver. */ [DRM_IOCTL_NR(DRM_IOCTL_CONTROL)] = { DRM(control), 1, 1 }, #if __OS_HAS_AGP - [DRM_IOCTL_NR(DRM_IOCTL_AGP_ACQUIRE)] = { DRM(agp_acquire), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_AGP_RELEASE)] = { DRM(agp_release), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_AGP_ENABLE)] = { DRM(agp_enable), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_AGP_INFO)] = { DRM(agp_info), 1, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_AGP_ALLOC)] = { DRM(agp_alloc), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_AGP_FREE)] = { DRM(agp_free), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_AGP_BIND)] = { DRM(agp_bind), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_AGP_UNBIND)] = { DRM(agp_unbind), 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_ACQUIRE)] = { drm_memory_agp_acquire, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_RELEASE)] = { drm_memory_agp_release, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_ENABLE)] = { drm_memory_agp_enable, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_INFO)] = { drm_memory_agp_info, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_ALLOC)] = { drm_memory_agp_alloc, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_FREE)] = { drm_memory_agp_free, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_BIND)] = { drm_memory_agp_bind, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_UNBIND)] = { drm_memory_agp_unbind, 1, 1 }, #endif [DRM_IOCTL_NR(DRM_IOCTL_SG_ALLOC)] = { DRM(sg_alloc), 1, 1 }, @@ -201,7 +201,7 @@ static int DRM(setup)( drm_device_t *dev ) if (drm_core_check_feature(dev, DRIVER_HAVE_DMA)) { - i = DRM(dma_setup)( dev ); + i = drm_core_dma_setup( dev ); if ( i < 0 ) return i; } @@ -249,7 +249,7 @@ static int DRM(setup)( drm_device_t *dev ) dev->magiclist[i].tail = NULL; } - dev->ctxlist = DRM(alloc)(sizeof(*dev->ctxlist), + dev->ctxlist = drm_core_alloc(sizeof(*dev->ctxlist), DRM_MEM_CTXLIST); if(dev->ctxlist == NULL) return -ENOMEM; memset(dev->ctxlist, 0, sizeof(*dev->ctxlist)); @@ -327,13 +327,13 @@ static int DRM(takedown)( drm_device_t *dev ) del_timer( &dev->timer ); if ( dev->devname ) { - DRM(free)( dev->devname, strlen( dev->devname ) + 1, + drm_core_free( dev->devname, strlen( dev->devname ) + 1, DRM_MEM_DRIVER ); dev->devname = NULL; } if ( dev->unique ) { - DRM(free)( dev->unique, strlen( dev->unique ) + 1, + drm_core_free( dev->unique, strlen( dev->unique ) + 1, DRM_MEM_DRIVER ); dev->unique = NULL; dev->unique_len = 0; @@ -342,7 +342,7 @@ static int DRM(takedown)( drm_device_t *dev ) for ( i = 0 ; i < DRM_HASH_SIZE ; i++ ) { for ( pt = dev->magiclist[i].head ; pt ; pt = next ) { next = pt->next; - DRM(free)( pt, sizeof(*pt), DRM_MEM_MAGIC ); + drm_core_free( pt, sizeof(*pt), DRM_MEM_MAGIC ); } dev->magiclist[i].head = dev->magiclist[i].tail = NULL; } @@ -357,13 +357,13 @@ static int DRM(takedown)( drm_device_t *dev ) intact until drv_cleanup is called. */ for ( entry = dev->agp->memory ; entry ; entry = nexte ) { nexte = entry->next; - if ( entry->bound ) DRM(unbind_agp)( entry->memory ); - DRM(free_agp)( entry->memory, entry->pages ); - DRM(free)( entry, sizeof(*entry), DRM_MEM_AGPLISTS ); + if ( entry->bound ) drm_memory_unbind_agp( entry->memory ); + drm_memory_free_agp( entry->memory, entry->pages ); + drm_core_free( entry, sizeof(*entry), DRM_MEM_AGPLISTS ); } dev->agp->memory = NULL; - if ( dev->agp->acquired ) DRM(agp_do_release)(); + if ( dev->agp->acquired ) drm_memory_agp_do_release(); dev->agp->acquired = 0; dev->agp->enabled = 0; @@ -374,7 +374,7 @@ static int DRM(takedown)( drm_device_t *dev ) if ( dev->vmalist ) { for ( vma = dev->vmalist ; vma ; vma = vma_next ) { vma_next = vma->next; - DRM(free)( vma, sizeof(*vma), DRM_MEM_VMAS ); + drm_core_free( vma, sizeof(*vma), DRM_MEM_VMAS ); } dev->vmalist = NULL; } @@ -406,10 +406,10 @@ static int DRM(takedown)( drm_device_t *dev ) } break; } - DRM(free)(map, sizeof(*map), DRM_MEM_MAPS); + drm_core_free(map, sizeof(*map), DRM_MEM_MAPS); } list_del( list ); - DRM(free)(r_list, sizeof(*r_list), DRM_MEM_MAPS); + drm_core_free(r_list, sizeof(*r_list), DRM_MEM_MAPS); } } @@ -418,13 +418,13 @@ static int DRM(takedown)( drm_device_t *dev ) for ( i = 0 ; i < dev->queue_count ; i++ ) { if ( dev->queuelist[i] ) { - DRM(free)( dev->queuelist[i], + drm_core_free( dev->queuelist[i], sizeof(*dev->queuelist[0]), DRM_MEM_QUEUES ); dev->queuelist[i] = NULL; } } - DRM(free)( dev->queuelist, + drm_core_free( dev->queuelist, dev->queue_slots * sizeof(*dev->queuelist), DRM_MEM_QUEUES ); dev->queuelist = NULL; @@ -432,7 +432,7 @@ static int DRM(takedown)( drm_device_t *dev ) dev->queue_count = 0; if (drm_core_check_feature(dev, DRIVER_HAVE_DMA)) - DRM(dma_takedown)( dev ); + drm_core_dma_takedown( dev ); if ( dev->lock.hw_lock ) { dev->sigdata.lock = dev->lock.hw_lock = NULL; /* SHM removed */ @@ -447,7 +447,7 @@ static int DRM(takedown)( drm_device_t *dev ) static void DRM(init_fn_table)(struct drm_device *dev) { - dev->fn_tbl.reclaim_buffers = DRM(core_reclaim_buffers); + dev->fn_tbl.reclaim_buffers = drm_core_reclaim_buffers; dev->fn_tbl.get_map_ofs = DRM(core_get_map_ofs); dev->fn_tbl.get_reg_ofs = DRM(core_get_reg_ofs); } @@ -493,7 +493,7 @@ static int drm_probe(struct pci_dev *pdev, const struct pci_device_id *ent) dev->pci_func = PCI_FUNC(pdev->devfn); dev->irq = pdev->irq; - dev->maplist = DRM(alloc)(sizeof(*dev->maplist), DRM_MEM_MAPS); + dev->maplist = drm_core_alloc(sizeof(*dev->maplist), DRM_MEM_MAPS); if(dev->maplist == NULL) return -ENOMEM; memset(dev->maplist, 0, sizeof(*dev->maplist)); INIT_LIST_HEAD(&dev->maplist->head); @@ -511,7 +511,7 @@ static int drm_probe(struct pci_dev *pdev, const struct pci_device_id *ent) #if __OS_HAS_AGP if (drm_core_check_feature(dev, DRIVER_USE_AGP)) { - dev->agp = DRM(agp_init)(); + dev->agp = drm_memory_agp_init(); if ( drm_core_check_feature(dev, DRIVER_REQUIRE_AGP) && dev->agp == NULL ) { DRM_ERROR( "Cannot initialize the agpgart module.\n" ); retcode = -EINVAL; @@ -609,7 +609,7 @@ static int __init drm_init( void ) DRM(parse_options)( drm_opts ); #endif - DRM(mem_init)(); + drm_core_mem_init(); for (i=0; (DRM(pciidlist)[i].vendor != 0) && !DRM(fb_loaded); i++) { pid = &DRM(pciidlist[i]); @@ -676,7 +676,7 @@ static void __exit drm_cleanup( drm_device_t *dev ) if ( ( map = r_list->map ) ) { switch ( map->type ) { case _DRM_REGISTERS: - DRM(ioremapfree)( map->handle, map->size, dev ); + drm_core_ioremapfree( map, dev ); break; case _DRM_FRAME_BUFFER: @@ -699,12 +699,12 @@ static void __exit drm_cleanup( drm_device_t *dev ) DRM_DEBUG("Extra maplist item\n"); break; } - DRM(free)(map, sizeof(*map), DRM_MEM_MAPS); + drm_core_free(map, sizeof(*map), DRM_MEM_MAPS); } list_del( list ); - DRM(free)(r_list, sizeof(*r_list), DRM_MEM_MAPS); + drm_core_free(r_list, sizeof(*r_list), DRM_MEM_MAPS); } - DRM(free)(dev->maplist, sizeof(*dev->maplist), DRM_MEM_MAPS); + drm_core_free(dev->maplist, sizeof(*dev->maplist), DRM_MEM_MAPS); dev->maplist = NULL; } if (DRM(fb_loaded)==0) @@ -730,8 +730,8 @@ static void __exit drm_cleanup( drm_device_t *dev ) } #endif if ( drm_core_check_feature(dev, DRIVER_USE_AGP) && dev->agp ) { - DRM(agp_uninit)(); - DRM(free)( dev->agp, sizeof(*dev->agp), DRM_MEM_AGPLISTS ); + drm_memory_agp_uninit(); + drm_core_free( dev->agp, sizeof(*dev->agp), DRM_MEM_AGPLISTS ); dev->agp = NULL; } #endif @@ -956,7 +956,7 @@ int DRM(release)( struct inode *inode, struct file *filp ) DRM(ctxbitmap_free)( dev, pos->handle ); list_del( &pos->head ); - DRM(free)( pos, sizeof(*pos), DRM_MEM_CTXLIST ); + drm_core_free( pos, sizeof(*pos), DRM_MEM_CTXLIST ); --dev->ctx_count; } } @@ -985,7 +985,7 @@ int DRM(release)( struct inode *inode, struct file *filp ) if (dev->fn_tbl.free_filp_private) dev->fn_tbl.free_filp_private( dev, priv ); - DRM(free)( priv, sizeof(*priv), DRM_MEM_FILES ); + drm_core_free( priv, sizeof(*priv), DRM_MEM_FILES ); /* ======================================================== * End inline drm_release @@ -1129,29 +1129,28 @@ int DRM(lock)( struct inode *inode, struct file *filp, current->state = TASK_RUNNING; remove_wait_queue( &dev->lock.lock_queue, &entry ); - if ( !ret ) { - sigemptyset( &dev->sigmask ); - sigaddset( &dev->sigmask, SIGSTOP ); - sigaddset( &dev->sigmask, SIGTSTP ); - sigaddset( &dev->sigmask, SIGTTIN ); - sigaddset( &dev->sigmask, SIGTTOU ); - dev->sigdata.context = lock.context; - dev->sigdata.lock = dev->lock.hw_lock; - block_all_signals( DRM(notifier), - &dev->sigdata, &dev->sigmask ); - - if (dev->fn_tbl.dma_ready && (lock.flags & _DRM_LOCK_READY)) - dev->fn_tbl.dma_ready(dev); - - if ( dev->fn_tbl.dma_quiescent && (lock.flags & _DRM_LOCK_QUIESCENT )) - return dev->fn_tbl.dma_quiescent(dev); - - - if ( dev->fn_tbl.kernel_context_switch && dev->last_context != lock.context ) { - dev->fn_tbl.kernel_context_switch(dev, dev->last_context, - lock.context); - } - } + sigemptyset( &dev->sigmask ); + sigaddset( &dev->sigmask, SIGSTOP ); + sigaddset( &dev->sigmask, SIGTSTP ); + sigaddset( &dev->sigmask, SIGTTIN ); + sigaddset( &dev->sigmask, SIGTTOU ); + dev->sigdata.context = lock.context; + dev->sigdata.lock = dev->lock.hw_lock; + block_all_signals( DRM(notifier), + &dev->sigdata, &dev->sigmask ); + + if (dev->fn_tbl.dma_ready && (lock.flags & _DRM_LOCK_READY)) + dev->fn_tbl.dma_ready(dev); + + if ( dev->fn_tbl.dma_quiescent && (lock.flags & _DRM_LOCK_QUIESCENT )) + return dev->fn_tbl.dma_quiescent(dev); + + + if ( dev->fn_tbl.kernel_context_switch && dev->last_context != lock.context ) { + dev->fn_tbl.kernel_context_switch(dev, dev->last_context, + lock.context); + } + DRM_DEBUG( "%d %s\n", lock.context, ret ? "interrupted" : "has lock" ); diff --git a/linux-core/drm_fops.c b/linux-core/drm_fops.c index 21935b7a..32c6177c 100644 --- a/linux-core/drm_fops.c +++ b/linux-core/drm_fops.c @@ -60,7 +60,7 @@ int DRM(open_helper)(struct inode *inode, struct file *filp, drm_device_t *dev) DRM_DEBUG("pid = %d, minor = %d\n", current->pid, minor); - priv = DRM(alloc)(sizeof(*priv), DRM_MEM_FILES); + priv = drm_core_alloc(sizeof(*priv), DRM_MEM_FILES); if(!priv) return -ENOMEM; memset(priv, 0, sizeof(*priv)); @@ -111,7 +111,7 @@ int DRM(open_helper)(struct inode *inode, struct file *filp, drm_device_t *dev) return 0; out_free: - DRM(free)(priv, sizeof(*priv), DRM_MEM_FILES); + drm_core_free(priv, sizeof(*priv), DRM_MEM_FILES); return ret; } diff --git a/linux-core/drm_ioctl.c b/linux-core/drm_ioctl.c index c3725668..4e5055ef 100644 --- a/linux-core/drm_ioctl.c +++ b/linux-core/drm_ioctl.c @@ -98,14 +98,14 @@ int DRM(setunique)(struct inode *inode, struct file *filp, if (!u.unique_len || u.unique_len > 1024) return -EINVAL; dev->unique_len = u.unique_len; - dev->unique = DRM(alloc)(u.unique_len + 1, DRM_MEM_DRIVER); + dev->unique = drm_core_alloc(u.unique_len + 1, DRM_MEM_DRIVER); if(!dev->unique) return -ENOMEM; if (copy_from_user(dev->unique, u.unique, dev->unique_len)) return -EFAULT; dev->unique[dev->unique_len] = '\0'; - dev->devname = DRM(alloc)(strlen(dev->name) + strlen(dev->unique) + 2, + dev->devname = drm_core_alloc(strlen(dev->name) + strlen(dev->unique) + 2, DRM_MEM_DRIVER); if (!dev->devname) return -ENOMEM; @@ -137,14 +137,14 @@ DRM(set_busid)(drm_device_t *dev) return EBUSY; dev->unique_len = 20; - dev->unique = DRM(alloc)(dev->unique_len + 1, DRM_MEM_DRIVER); + dev->unique = drm_core_alloc(dev->unique_len + 1, DRM_MEM_DRIVER); if (dev->unique == NULL) return ENOMEM; snprintf(dev->unique, dev->unique_len, "pci:%04x:%02x:%02x.%d", dev->pci_domain, dev->pci_bus, dev->pci_slot, dev->pci_func); - dev->devname = DRM(alloc)(strlen(dev->name) + dev->unique_len + 2, + dev->devname = drm_core_alloc(strlen(dev->name) + dev->unique_len + 2, DRM_MEM_DRIVER); if (dev->devname == NULL) return ENOMEM; diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c index a1622c0e..a88edf98 100644 --- a/linux-core/drm_irq.c +++ b/linux-core/drm_irq.c @@ -304,7 +304,7 @@ int DRM(wait_vblank)( DRM_IOCTL_ARGS ) spin_unlock_irqrestore( &dev->vbl_lock, irqflags ); - if ( !( vbl_sig = DRM(alloc)( sizeof( drm_vbl_sig_t ), DRM_MEM_DRIVER ) ) ) { + if ( !( vbl_sig = drm_core_alloc( sizeof( drm_vbl_sig_t ), DRM_MEM_DRIVER ) ) ) { return -ENOMEM; } @@ -360,7 +360,7 @@ void DRM(vbl_send_signals)( drm_device_t *dev ) list_del( list ); - DRM(free)( vbl_sig, sizeof(*vbl_sig), DRM_MEM_DRIVER ); + drm_core_free( vbl_sig, sizeof(*vbl_sig), DRM_MEM_DRIVER ); dev->vbl_pending--; } diff --git a/linux-core/drm_scatter.c b/linux-core/drm_scatter.c index 888e6296..02e82781 100644 --- a/linux-core/drm_scatter.c +++ b/linux-core/drm_scatter.c @@ -50,13 +50,13 @@ void DRM(sg_cleanup)( drm_sg_mem_t *entry ) vfree( entry->virtual ); - DRM(free)( entry->busaddr, + drm_core_free( entry->busaddr, entry->pages * sizeof(*entry->busaddr), DRM_MEM_PAGES ); - DRM(free)( entry->pagelist, + drm_core_free( entry->pagelist, entry->pages * sizeof(*entry->pagelist), DRM_MEM_PAGES ); - DRM(free)( entry, + drm_core_free( entry, sizeof(*entry), DRM_MEM_SGLISTS ); } @@ -82,7 +82,7 @@ int DRM(sg_alloc)( struct inode *inode, struct file *filp, if ( copy_from_user( &request, argp, sizeof(request) ) ) return -EFAULT; - entry = DRM(alloc)( sizeof(*entry), DRM_MEM_SGLISTS ); + entry = drm_core_alloc( sizeof(*entry), DRM_MEM_SGLISTS ); if ( !entry ) return -ENOMEM; @@ -92,22 +92,22 @@ int DRM(sg_alloc)( struct inode *inode, struct file *filp, DRM_DEBUG( "sg size=%ld pages=%ld\n", request.size, pages ); entry->pages = pages; - entry->pagelist = DRM(alloc)( pages * sizeof(*entry->pagelist), + entry->pagelist = drm_core_alloc( pages * sizeof(*entry->pagelist), DRM_MEM_PAGES ); if ( !entry->pagelist ) { - DRM(free)( entry, sizeof(*entry), DRM_MEM_SGLISTS ); + drm_core_free( entry, sizeof(*entry), DRM_MEM_SGLISTS ); return -ENOMEM; } memset(entry->pagelist, 0, pages * sizeof(*entry->pagelist)); - entry->busaddr = DRM(alloc)( pages * sizeof(*entry->busaddr), + entry->busaddr = drm_core_alloc( pages * sizeof(*entry->busaddr), DRM_MEM_PAGES ); if ( !entry->busaddr ) { - DRM(free)( entry->pagelist, + drm_core_free( entry->pagelist, entry->pages * sizeof(*entry->pagelist), DRM_MEM_PAGES ); - DRM(free)( entry, + drm_core_free( entry, sizeof(*entry), DRM_MEM_SGLISTS ); return -ENOMEM; @@ -116,13 +116,13 @@ int DRM(sg_alloc)( struct inode *inode, struct file *filp, entry->virtual = vmalloc_32( pages << PAGE_SHIFT ); if ( !entry->virtual ) { - DRM(free)( entry->busaddr, + drm_core_free( entry->busaddr, entry->pages * sizeof(*entry->busaddr), DRM_MEM_PAGES ); - DRM(free)( entry->pagelist, + drm_core_free( entry->pagelist, entry->pages * sizeof(*entry->pagelist), DRM_MEM_PAGES ); - DRM(free)( entry, + drm_core_free( entry, sizeof(*entry), DRM_MEM_SGLISTS ); return -ENOMEM; diff --git a/linux-core/drm_stub.c b/linux-core/drm_stub.c index 3d9ade35..53f75f4c 100644 --- a/linux-core/drm_stub.c +++ b/linux-core/drm_stub.c @@ -162,7 +162,7 @@ static int DRM(stub_getminor)(const char *name, struct file_operations *fops, int i; if (!DRM(stub_list)) { - DRM(stub_list) = DRM(alloc)(sizeof(*DRM(stub_list)) + DRM(stub_list) = drm_core_alloc(sizeof(*DRM(stub_list)) * DRM_STUB_MAXCARDS, DRM_MEM_STUB); if(!DRM(stub_list)) return -1; for (i = 0; i < DRM_STUB_MAXCARDS; i++) { @@ -174,7 +174,7 @@ static int DRM(stub_getminor)(const char *name, struct file_operations *fops, if (!DRM(stub_list)[i].fops) { DRM(stub_list)[i].name = name; DRM(stub_list)[i].fops = fops; - DRM(proc_init)(dev, i, DRM(stub_info).proc_root, + drm_proc_init(dev, i, DRM(stub_info).proc_root, &DRM(stub_list)[i].dev_root); (*DRM(stub_info).info_count)++; DRM_DEBUG("info count increased %d\n", *DRM(stub_info).info_count); @@ -200,7 +200,7 @@ static int DRM(stub_putminor)(int minor) if (minor < 0 || minor >= DRM_STUB_MAXCARDS) return -1; DRM(stub_list)[minor].name = NULL; DRM(stub_list)[minor].fops = NULL; - DRM(proc_cleanup)(minor, DRM(stub_info).proc_root, + drm_proc_cleanup(minor, DRM(stub_info).proc_root, DRM(stub_list)[minor].dev_root); (*DRM(stub_info).info_count)--; @@ -213,7 +213,7 @@ static int DRM(stub_putminor)(int minor) } else { DRM_DEBUG("unregistering inter_module \n"); inter_module_unregister("drm"); - DRM(free)(DRM(stub_list), + drm_core_free(DRM(stub_list), sizeof(*DRM(stub_list)) * DRM_STUB_MAXCARDS, DRM_MEM_STUB); remove_proc_entry("dri", NULL); diff --git a/linux-core/drm_vm.c b/linux-core/drm_vm.c index f13db00b..86fe9426 100644 --- a/linux-core/drm_vm.c +++ b/linux-core/drm_vm.c @@ -183,7 +183,7 @@ void DRM(vm_shm_close)(struct vm_area_struct *vma) } else { dev->vmalist = pt->next; } - DRM(free)(pt, sizeof(*pt), DRM_MEM_VMAS); + drm_core_free(pt, sizeof(*pt), DRM_MEM_VMAS); } else { prev = pt; } @@ -214,7 +214,7 @@ void DRM(vm_shm_close)(struct vm_area_struct *vma) DRM_DEBUG("mtrr_del = %d\n", retcode); } #endif - DRM(ioremapfree)(map->handle, map->size, dev); + drm_core_ioremapfree(map, dev); break; case _DRM_SHM: vfree(map->handle); @@ -223,7 +223,7 @@ void DRM(vm_shm_close)(struct vm_area_struct *vma) case _DRM_SCATTER_GATHER: break; } - DRM(free)(map, sizeof(*map), DRM_MEM_MAPS); + drm_core_free(map, sizeof(*map), DRM_MEM_MAPS); } } up(&dev->struct_sem); @@ -405,7 +405,7 @@ void DRM(vm_open)(struct vm_area_struct *vma) vma->vm_start, vma->vm_end - vma->vm_start); atomic_inc(&dev->vma_count); - vma_entry = DRM(alloc)(sizeof(*vma_entry), DRM_MEM_VMAS); + vma_entry = drm_core_alloc(sizeof(*vma_entry), DRM_MEM_VMAS); if (vma_entry) { down(&dev->struct_sem); vma_entry->vma = vma; @@ -442,7 +442,7 @@ void DRM(vm_close)(struct vm_area_struct *vma) } else { dev->vmalist = pt->next; } - DRM(free)(pt, sizeof(*pt), DRM_MEM_VMAS); + drm_core_free(pt, sizeof(*pt), DRM_MEM_VMAS); break; } } diff --git a/linux-core/radeon_drv.c b/linux-core/radeon_drv.c index 74e32df0..582d172c 100644 --- a/linux-core/radeon_drv.c +++ b/linux-core/radeon_drv.c @@ -31,18 +31,16 @@ #include <linux/config.h> +#include "drm_headers.h" + #include "radeon.h" #include "drmP.h" #include "drm.h" #include "radeon_drm.h" #include "radeon_drv.h" -#include "ati_pcigart.h" -#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" #include "drm_fops.h" @@ -50,8 +48,6 @@ #include "drm_ioctl.h" #include "drm_irq.h" #include "drm_lock.h" -#include "drm_memory.h" -#include "drm_proc.h" #include "drm_vm.h" #include "drm_stub.h" #include "drm_scatter.h" diff --git a/linux/Makefile b/linux/Makefile index 9cfe7d5c..1bff058f 100644 --- a/linux/Makefile +++ b/linux/Makefile @@ -50,12 +50,12 @@ endif MACHINE := $(shell uname -m) # Modules for all architectures -MODULE_LIST := tdfx.o r128.o radeon.o mga.o sis.o savage.o via.o mach64.o +MODULE_LIST := #tdfx.o r128.o radeon.o mga.o sis.o savage.o via.o mach64.o # Modules only for ix86 architectures ifneq (,$(findstring 86,$(MACHINE))) ARCHX86 := 1 -MODULE_LIST += i830.o i810.o i915.o +MODULE_LIST += #i830.o i810.o i915.o endif ifneq (,$(findstring sparc64,$(MACHINE))) diff --git a/linux/Makefile.kernel b/linux/Makefile.kernel index 92e3f73e..8e68d40a 100644 --- a/linux/Makefile.kernel +++ b/linux/Makefile.kernel @@ -7,6 +7,7 @@ # $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/Makefile.kernel,v 1.18 2003/08/16 17:59:17 dawes Exp $ # +drmcore-objs := tdfx-objs := tdfx_drv.o r128-objs := r128_drv.o r128_cce.o r128_state.o r128_irq.o mga-objs := mga_drv.o mga_dma.o mga_state.o mga_warp.o mga_irq.o @@ -41,9 +42,11 @@ obj- := export-objs := via_mm.o endif +drmcore-y := drm_bufs.o drm_memory.o drm_memory_debug.o drm_agpsupport.o drm_dma.o ati_pcigart.o drm_proc.o drmcore_exports.o +obj-m += drmcore.o radeon.o obj-$(CONFIG_DRM_TDFX) += tdfx.o -obj-$(CONFIG_DRM_R128) += r128.o -obj-$(CONFIG_DRM_RADEON)+= radeon.o +obj-$(CONFIG_DRM_R128) += r128.o +obj-$(CONFIG_DRM_RADEON)+= radeon.o drmcore.o obj-$(CONFIG_DRM_MGA) += mga.o obj-$(CONFIG_DRM_I810) += i810.o obj-$(CONFIG_DRM_I830) += i830.o diff --git a/linux/ati_pcigart.c b/linux/ati_pcigart.c new file mode 100644 index 00000000..54e3e242 --- /dev/null +++ b/linux/ati_pcigart.c @@ -0,0 +1,206 @@ +/** + * \file ati_pcigart.h + * ATI PCI GART support + * + * \author Gareth Hughes <gareth@valinux.com> + */ + +/* + * Created: Wed Dec 13 21:52:19 2000 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 + * 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 "drm_headers.h" + +#if PAGE_SIZE == 65536 +# define ATI_PCIGART_TABLE_ORDER 0 +# define ATI_PCIGART_TABLE_PAGES (1 << 0) +#elif PAGE_SIZE == 16384 +# define ATI_PCIGART_TABLE_ORDER 1 +# define ATI_PCIGART_TABLE_PAGES (1 << 1) +#elif PAGE_SIZE == 8192 +# define ATI_PCIGART_TABLE_ORDER 2 +# define ATI_PCIGART_TABLE_PAGES (1 << 2) +#elif PAGE_SIZE == 4096 +# define ATI_PCIGART_TABLE_ORDER 3 +# define ATI_PCIGART_TABLE_PAGES (1 << 3) +#else +# error - PAGE_SIZE not 64K, 16K, 8K or 4K +#endif + +# define ATI_MAX_PCIGART_PAGES 8192 /**< 32 MB aperture, 4K pages */ +# define ATI_PCIGART_PAGE_SIZE 4096 /**< PCI GART page size */ + +static unsigned long drm_ati_alloc_pcigart_table( void ) +{ + unsigned long address; + struct page *page; + int i; + DRM_DEBUG( "%s\n", __FUNCTION__ ); + + address = __get_free_pages( GFP_KERNEL, ATI_PCIGART_TABLE_ORDER ); + if ( address == 0UL ) { + return 0; + } + + page = virt_to_page( address ); + + for ( i = 0 ; i < ATI_PCIGART_TABLE_PAGES ; i++, page++ ) { + get_page(page); + SetPageReserved( page ); + } + + DRM_DEBUG( "%s: returning 0x%08lx\n", __FUNCTION__, address ); + return address; +} + +static void drm_ati_free_pcigart_table( unsigned long address ) +{ + struct page *page; + int i; + DRM_DEBUG( "%s\n", __FUNCTION__ ); + + page = virt_to_page( address ); + + for ( i = 0 ; i < ATI_PCIGART_TABLE_PAGES ; i++, page++ ) { + __put_page(page); + ClearPageReserved( page ); + } + + free_pages( address, ATI_PCIGART_TABLE_ORDER ); +} + +int drm_ati_pcigart_init( drm_device_t *dev, + unsigned long *addr, + dma_addr_t *bus_addr) +{ + drm_sg_mem_t *entry = dev->sg; + unsigned long address = 0; + unsigned long pages; + u32 *pci_gart, page_base, bus_address = 0; + int i, j, ret = 0; + + if ( !entry ) { + DRM_ERROR( "no scatter/gather memory!\n" ); + goto done; + } + + address = drm_ati_alloc_pcigart_table(); + if ( !address ) { + DRM_ERROR( "cannot allocate PCI GART page!\n" ); + goto done; + } + + if ( !dev->pdev ) { + DRM_ERROR( "PCI device unknown!\n" ); + goto done; + } + + bus_address = pci_map_single(dev->pdev, (void *)address, + ATI_PCIGART_TABLE_PAGES * PAGE_SIZE, + PCI_DMA_TODEVICE); + if (bus_address == 0) { + DRM_ERROR( "unable to map PCIGART pages!\n" ); + drm_ati_free_pcigart_table( address ); + address = 0; + goto done; + } + + pci_gart = (u32 *)address; + + pages = ( entry->pages <= ATI_MAX_PCIGART_PAGES ) + ? entry->pages : ATI_MAX_PCIGART_PAGES; + + memset( pci_gart, 0, ATI_MAX_PCIGART_PAGES * sizeof(u32) ); + + for ( i = 0 ; i < pages ; i++ ) { + /* we need to support large memory configurations */ + entry->busaddr[i] = pci_map_single(dev->pdev, + page_address( entry->pagelist[i] ), + PAGE_SIZE, + PCI_DMA_TODEVICE); + if (entry->busaddr[i] == 0) { + DRM_ERROR( "unable to map PCIGART pages!\n" ); + drm_ati_pcigart_cleanup( dev, address, bus_address ); + address = 0; + bus_address = 0; + goto done; + } + page_base = (u32) entry->busaddr[i]; + + for (j = 0; j < (PAGE_SIZE / ATI_PCIGART_PAGE_SIZE); j++) { + *pci_gart++ = cpu_to_le32( page_base ); + page_base += ATI_PCIGART_PAGE_SIZE; + } + } + + ret = 1; + +#if defined(__i386__) || defined(__AMD64__) || defined(__x86_64__) + asm volatile ( "wbinvd" ::: "memory" ); +#else + mb(); +#endif + +done: + *addr = address; + *bus_addr = bus_address; + return ret; +} + +int drm_ati_pcigart_cleanup( drm_device_t *dev, + unsigned long addr, + dma_addr_t bus_addr) +{ + drm_sg_mem_t *entry = dev->sg; + unsigned long pages; + int i; + + /* we need to support large memory configurations */ + if ( !entry ) { + DRM_ERROR( "no scatter/gather memory!\n" ); + return 0; + } + + if ( bus_addr ) { + pci_unmap_single(dev->pdev, bus_addr, + ATI_PCIGART_TABLE_PAGES * PAGE_SIZE, + PCI_DMA_TODEVICE); + + pages = ( entry->pages <= ATI_MAX_PCIGART_PAGES ) + ? entry->pages : ATI_MAX_PCIGART_PAGES; + + for ( i = 0 ; i < pages ; i++ ) { + if ( !entry->busaddr[i] ) break; + pci_unmap_single(dev->pdev, entry->busaddr[i], + PAGE_SIZE, PCI_DMA_TODEVICE); + } + } + + if ( addr ) { + drm_ati_free_pcigart_table( addr ); + } + + return 1; +} diff --git a/linux/drmP.h b/linux/drmP.h index 495277f6..b26f6189 100644 --- a/linux/drmP.h +++ b/linux/drmP.h @@ -36,179 +36,27 @@ #ifdef __KERNEL__ -#ifdef __alpha__ -/* add include of current.h so that "current" is defined - * before static inline funcs in wait.h. Doing this so we - * can build the DRM (part of PI DRI). 4/21/2000 S + B */ -#include <asm/current.h> -#endif /* __alpha__ */ -#include <linux/config.h> -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/miscdevice.h> -#include <linux/fs.h> -#include <linux/proc_fs.h> -#include <linux/init.h> -#include <linux/file.h> -#include <linux/pci.h> -#include <linux/version.h> -#include <linux/sched.h> -#include <linux/smp_lock.h> /* For (un)lock_kernel */ -#include <linux/mm.h> -#include <linux/pagemap.h> -#if defined(__alpha__) || defined(__powerpc__) -#include <asm/pgtable.h> /* For pte_wrprotect */ -#endif -#include <asm/io.h> -#include <asm/mman.h> -#include <asm/uaccess.h> -#ifdef CONFIG_MTRR -#include <asm/mtrr.h> -#endif -#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE) -#include <linux/types.h> -#include <linux/agp_backend.h> -#endif -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,41) -#define HAS_WORKQUEUE 0 -#else -#define HAS_WORKQUEUE 1 -#endif -#if !HAS_WORKQUEUE -#include <linux/tqueue.h> -#else -#include <linux/workqueue.h> -#endif -#include <linux/poll.h> -#include <asm/pgalloc.h> -#include "drm.h" - -#include "drm_os_linux.h" /* If you want the memory alloc debug functionality, change define below */ /* #define DEBUG_MEMORY */ /***********************************************************************/ -/** \name DRM template customization defaults */ -/*@{*/ - -/* driver capabilities and requirements mask */ -#define DRIVER_USE_AGP 0x1 -#define DRIVER_REQUIRE_AGP 0x2 -#define DRIVER_USE_MTRR 0x4 -#define DRIVER_HAVE_DMA 0x10 -#define DRIVER_HAVE_IRQ 0x20 -#define DRIVER_SG 0x40 -#define DRIVER_PCI_DMA 0x80 -#define DRIVER_IRQ_SHARED 0x100 -#define DRIVER_IRQ_VBL 0x200 -#define DRIVER_DMA_QUEUE 0x800 - -#define __OS_HAS_AGP (defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE)) -#define __OS_HAS_MTRR (defined(CONFIG_MTRR)) -/*@}*/ - - -/***********************************************************************/ /** \name Begin the DRM... */ /*@{*/ -#define DRM_DEBUG_CODE 2 /**< Include debugging code if > 1, then - also include looping detection. */ - -#define DRM_HASH_SIZE 16 /**< Size of key hash table. Must be power of 2. */ -#define DRM_KERNEL_CONTEXT 0 /**< Change drm_resctx if changed */ -#define DRM_RESERVED_CONTEXTS 1 /**< Change drm_resctx if changed */ -#define DRM_LOOPING_LIMIT 5000000 -#define DRM_BSZ 1024 /**< Buffer size for /dev/drm? output */ -#define DRM_TIME_SLICE (HZ/20) /**< Time slice for GLXContexts */ -#define DRM_LOCK_SLICE 1 /**< Time slice for lock, in jiffies */ - -#define DRM_FLAG_DEBUG 0x01 - -#define DRM_MEM_DMA 0 -#define DRM_MEM_SAREA 1 -#define DRM_MEM_DRIVER 2 -#define DRM_MEM_MAGIC 3 -#define DRM_MEM_IOCTLS 4 -#define DRM_MEM_MAPS 5 -#define DRM_MEM_VMAS 6 -#define DRM_MEM_BUFS 7 -#define DRM_MEM_SEGS 8 -#define DRM_MEM_PAGES 9 -#define DRM_MEM_FILES 10 -#define DRM_MEM_QUEUES 11 -#define DRM_MEM_CMDS 12 -#define DRM_MEM_MAPPINGS 13 -#define DRM_MEM_BUFLISTS 14 -#define DRM_MEM_AGPLISTS 15 -#define DRM_MEM_TOTALAGP 16 -#define DRM_MEM_BOUNDAGP 17 -#define DRM_MEM_CTXBITMAP 18 -#define DRM_MEM_STUB 19 -#define DRM_MEM_SGLISTS 20 -#define DRM_MEM_CTXLIST 21 #define DRM_MAX_CTXBITMAP (PAGE_SIZE * 8) /*@}*/ -#include "drm_compat.h" +#include "drm_core.h" /***********************************************************************/ /** \name Macros to make printk easier */ /*@{*/ -/** - * Error output. - * - * \param fmt printf() like format string. - * \param arg arguments - */ -#define DRM_ERROR(fmt, arg...) \ - printk(KERN_ERR "[" DRM_NAME ":%s] *ERROR* " fmt , __FUNCTION__ , ##arg) - -/** - * Memory error output. - * - * \param area memory area where the error occurred. - * \param fmt printf() like format string. - * \param arg arguments - */ -#define DRM_MEM_ERROR(area, fmt, arg...) \ - printk(KERN_ERR "[" DRM_NAME ":%s:%s] *ERROR* " fmt , __FUNCTION__, \ - DRM(mem_stats)[area].name , ##arg) -#define DRM_INFO(fmt, arg...) printk(KERN_INFO "[" DRM_NAME "] " fmt , ##arg) - -/** - * Debug output. - * - * \param fmt printf() like format string. - * \param arg arguments - */ -#if DRM_DEBUG_CODE -#define DRM_DEBUG(fmt, arg...) \ - do { \ - if ( DRM(flags) & DRM_FLAG_DEBUG ) \ - printk(KERN_DEBUG \ - "[" DRM_NAME ":%s] " fmt , \ - __FUNCTION__ , ##arg); \ - } while (0) -#else -#define DRM_DEBUG(fmt, arg...) do { } while (0) -#endif - -#define DRM_PROC_LIMIT (PAGE_SIZE-80) - -#define DRM_PROC_PRINT(fmt, arg...) \ - len += sprintf(&buf[len], fmt , ##arg); \ - if (len > DRM_PROC_LIMIT) { *eof = 1; return len - offset; } - -#define DRM_PROC_PRINT_RET(ret, fmt, arg...) \ - len += sprintf(&buf[len], fmt , ##arg); \ - if (len > DRM_PROC_LIMIT) { ret; *eof = 1; return len - offset; } /*@}*/ @@ -221,9 +69,6 @@ #define DRM_MIN(a,b) ((a)<(b)?(a):(b)) #define DRM_MAX(a,b) ((a)>(b)?(a):(b)) -#define DRM_LEFTCOUNT(x) (((x)->rp + (x)->count - (x)->wp) % ((x)->count + 1)) -#define DRM_BUFCOUNT(x) ((x)->count - DRM_LEFTCOUNT(x)) -#define DRM_WAITCOUNT(dev,idx) DRM_BUFCOUNT(&dev->queuelist[idx]->waitlist) #define DRM_IF_VERSION(maj, min) (maj << 16 | min) /** @@ -253,440 +98,6 @@ do { \ } \ } while (0) -/** - * Ioctl function type. - * - * \param inode device inode. - * \param filp file pointer. - * \param cmd command. - * \param arg argument. - */ -typedef int drm_ioctl_t( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ); - -typedef struct drm_ioctl_desc { - drm_ioctl_t *func; - int auth_needed; - int root_only; -} drm_ioctl_desc_t; - -typedef struct drm_devstate { - pid_t owner; /**< X server pid holding x_lock */ -} drm_devstate_t; - -typedef struct drm_magic_entry { - drm_magic_t magic; - struct drm_file *priv; - struct drm_magic_entry *next; -} drm_magic_entry_t; - -typedef struct drm_magic_head { - struct drm_magic_entry *head; - struct drm_magic_entry *tail; -} drm_magic_head_t; - -typedef struct drm_vma_entry { - struct vm_area_struct *vma; - struct drm_vma_entry *next; - pid_t pid; -} drm_vma_entry_t; - -/** - * DMA buffer. - */ -typedef struct drm_buf { - int idx; /**< Index into master buflist */ - int total; /**< Buffer size */ - int order; /**< log-base-2(total) */ - int used; /**< Amount of buffer in use (for DMA) */ - unsigned long offset; /**< Byte offset (used internally) */ - void *address; /**< Address of buffer */ - unsigned long bus_address; /**< Bus address of buffer */ - struct drm_buf *next; /**< Kernel-only: used for free list */ - __volatile__ int waiting; /**< On kernel DMA queue */ - __volatile__ int pending; /**< On hardware DMA queue */ - wait_queue_head_t dma_wait; /**< Processes waiting */ - struct file *filp; /**< Pointer to holding file descr */ - int context; /**< Kernel queue for this buffer */ - int while_locked;/**< Dispatch this buffer while locked */ - enum { - DRM_LIST_NONE = 0, - DRM_LIST_FREE = 1, - DRM_LIST_WAIT = 2, - DRM_LIST_PEND = 3, - DRM_LIST_PRIO = 4, - DRM_LIST_RECLAIM = 5 - } list; /**< Which list we're on */ - - int dev_priv_size; /**< Size of buffer private storage */ - void *dev_private; /**< Per-buffer private storage */ -} drm_buf_t; - - -/** bufs is one longer than it has to be */ -typedef struct drm_waitlist { - int count; /**< Number of possible buffers */ - drm_buf_t **bufs; /**< List of pointers to buffers */ - drm_buf_t **rp; /**< Read pointer */ - drm_buf_t **wp; /**< Write pointer */ - drm_buf_t **end; /**< End pointer */ - spinlock_t read_lock; - spinlock_t write_lock; -} drm_waitlist_t; - -typedef struct drm_freelist { - int initialized; /**< Freelist in use */ - atomic_t count; /**< Number of free buffers */ - drm_buf_t *next; /**< End pointer */ - - wait_queue_head_t waiting; /**< Processes waiting on free bufs */ - int low_mark; /**< Low water mark */ - int high_mark; /**< High water mark */ - atomic_t wfh; /**< If waiting for high mark */ - spinlock_t lock; -} drm_freelist_t; - -/** - * Buffer entry. There is one of this for each buffer size order. - */ -typedef struct drm_buf_entry { - int buf_size; /**< size */ - int buf_count; /**< number of buffers */ - drm_buf_t *buflist; /**< buffer list */ - int seg_count; - int page_order; - unsigned long *seglist; - - drm_freelist_t freelist; -} drm_buf_entry_t; - -/** File private data */ -typedef struct drm_file { - int authenticated; - int minor; - pid_t pid; - uid_t uid; - drm_magic_t magic; - unsigned long ioctl_count; - struct drm_file *next; - struct drm_file *prev; - struct drm_device *dev; - int remove_auth_on_close; - unsigned long lock_count; - void *driver_priv; -} drm_file_t; - -/** Wait queue */ -typedef struct drm_queue { - atomic_t use_count; /**< Outstanding uses (+1) */ - atomic_t finalization; /**< Finalization in progress */ - atomic_t block_count; /**< Count of processes waiting */ - atomic_t block_read; /**< Queue blocked for reads */ - wait_queue_head_t read_queue; /**< Processes waiting on block_read */ - atomic_t block_write; /**< Queue blocked for writes */ - wait_queue_head_t write_queue; /**< Processes waiting on block_write */ -#if 1 - atomic_t total_queued; /**< Total queued statistic */ - atomic_t total_flushed;/**< Total flushes statistic */ - atomic_t total_locks; /**< Total locks statistics */ -#endif - drm_ctx_flags_t flags; /**< Context preserving and 2D-only */ - drm_waitlist_t waitlist; /**< Pending buffers */ - wait_queue_head_t flush_queue; /**< Processes waiting until flush */ -} drm_queue_t; - -/** - * Lock data. - */ -typedef struct drm_lock_data { - drm_hw_lock_t *hw_lock; /**< Hardware lock */ - struct file *filp; /**< File descr of lock holder (0=kernel) */ - wait_queue_head_t lock_queue; /**< Queue of blocked processes */ - unsigned long lock_time; /**< Time of last lock in jiffies */ -} drm_lock_data_t; - -/** - * DMA data. - */ -typedef struct drm_device_dma { - - drm_buf_entry_t bufs[DRM_MAX_ORDER+1]; /**< buffers, grouped by their size order */ - int buf_count; /**< total number of buffers */ - drm_buf_t **buflist; /**< Vector of pointers into drm_device_dma::bufs */ - int seg_count; - int page_count; /**< number of pages */ - unsigned long *pagelist; /**< page list */ - unsigned long byte_count; - enum { - _DRM_DMA_USE_AGP = 0x01, - _DRM_DMA_USE_SG = 0x02 - } flags; - - /** \name DMA support */ - /*@{*/ - drm_buf_t *this_buffer; /**< Buffer being sent */ - drm_buf_t *next_buffer; /**< Selected buffer to send */ - drm_queue_t *next_queue; /**< Queue from which buffer selected*/ - wait_queue_head_t waiting; /**< Processes waiting on free bufs */ - /*@}*/ -} drm_device_dma_t; - -#if __OS_HAS_AGP -/** - * AGP memory entry. Stored as a doubly linked list. - */ -typedef struct drm_agp_mem { - unsigned long handle; /**< handle */ - DRM_AGP_MEM *memory; - unsigned long bound; /**< address */ - int pages; - struct drm_agp_mem *prev; /**< previous entry */ - struct drm_agp_mem *next; /**< next entry */ -} drm_agp_mem_t; - -/** - * AGP data. - * - * \sa DRM(agp_init)() and drm_device::agp. - */ -typedef struct drm_agp_head { - DRM_AGP_KERN agp_info; /**< AGP device information */ - drm_agp_mem_t *memory; /**< memory entries */ - unsigned long mode; /**< AGP mode */ - int enabled; /**< whether the AGP bus as been enabled */ - int acquired; /**< whether the AGP device has been acquired */ - unsigned long base; - int agp_mtrr; - int cant_use_aperture; - unsigned long page_mask; -} drm_agp_head_t; -#endif - -/** - * Scatter-gather memory. - */ -typedef struct drm_sg_mem { - unsigned long handle; - void *virtual; - int pages; - struct page **pagelist; - dma_addr_t *busaddr; -} drm_sg_mem_t; - -typedef struct drm_sigdata { - int context; - drm_hw_lock_t *lock; -} drm_sigdata_t; - -/** - * Mappings list - */ -typedef struct drm_map_list { - struct list_head head; /**< list head */ - drm_map_t *map; /**< mapping */ -} drm_map_list_t; - -typedef drm_map_t drm_local_map_t; - -/** - * Context handle list - */ -typedef struct drm_ctx_list { - struct list_head head; /**< list head */ - drm_context_t handle; /**< context handle */ - drm_file_t *tag; /**< associated fd private data */ -} drm_ctx_list_t; - - -typedef struct drm_vbl_sig { - struct list_head head; - unsigned int sequence; - struct siginfo info; - struct task_struct *task; -} drm_vbl_sig_t; - - -/** - * DRM device functions structure - */ -struct drm_device; - -struct drm_driver_fn { - int (*preinit)(struct drm_device *, unsigned long flags); - int (*postinit)(struct drm_device *, unsigned long flags); - void (*prerelease)(struct drm_device *, struct file *filp); - void (*pretakedown)(struct drm_device *); - int (*postcleanup)(struct drm_device *); - int (*presetup)(struct drm_device *); - int (*postsetup)(struct drm_device *); - - /* these are opposites at the moment */ - int (*open_helper)(struct drm_device *, drm_file_t *); - void (*free_filp_private)(struct drm_device *, drm_file_t *); - - void (*release)(struct drm_device *, struct file *filp); - void (*dma_ready)(struct drm_device *); - int (*dma_quiescent)(struct drm_device *); - int (*context_ctor)(struct drm_device *dev, int context); - int (*context_dtor)(struct drm_device *dev, int context); - int (*kernel_context_switch)(struct drm_device *dev, int old, int new); - int (*kernel_context_switch_unlock)(struct drm_device *dev); - int (*vblank_wait)(struct drm_device *dev, unsigned int *sequence); -/* these have to be filled in */ - irqreturn_t (*irq_handler)( DRM_IRQ_ARGS ); - void (*irq_preinstall)(struct drm_device *dev); - void (*irq_postinstall)(struct drm_device *dev); - void (*irq_uninstall)(struct drm_device *dev); - void (*reclaim_buffers)(struct file *filp); - unsigned long (*get_map_ofs)(drm_map_t *map); - unsigned long (*get_reg_ofs)(struct drm_device *dev); - void (*set_version)(struct drm_device *dev, drm_set_version_t *sv); -}; - -/** - * DRM device structure. - */ -typedef struct drm_device { - const char *name; /**< Simple driver name */ - char *unique; /**< Unique identifier: e.g., busid */ - int unique_len; /**< Length of unique field */ - dev_t device; /**< Device number for mknod */ - char *devname; /**< For /proc/interrupts */ - int minor; /**< Minor device number */ - int if_version; /**< Highest interface version set */ - - int blocked; /**< Blocked due to VC switch? */ - struct proc_dir_entry *root; /**< Root for this device's entries */ - - /** \name Locks */ - /*@{*/ - spinlock_t count_lock; /**< For inuse, drm_device::open_count, drm_device::buf_use */ - struct semaphore struct_sem; /**< For others */ - /*@}*/ - - /** \name Usage Counters */ - /*@{*/ - int open_count; /**< Outstanding files open */ - atomic_t ioctl_count; /**< Outstanding IOCTLs pending */ - atomic_t vma_count; /**< Outstanding vma areas open */ - int buf_use; /**< Buffers in use -- cannot alloc */ - atomic_t buf_alloc; /**< Buffer allocation in progress */ - /*@}*/ - - /** \name Performance counters */ - /*@{*/ - unsigned long counters; - drm_stat_type_t types[15]; - atomic_t counts[15]; - /*@}*/ - - /** \name Authentication */ - /*@{*/ - drm_file_t *file_first; /**< file list head */ - drm_file_t *file_last; /**< file list tail */ - drm_magic_head_t magiclist[DRM_HASH_SIZE]; /**< magic hash table */ - /*@}*/ - - /** \name Memory management */ - /*@{*/ - drm_map_list_t *maplist; /**< Linked list of regions */ - int map_count; /**< Number of mappable regions */ - - /** \name Context handle management */ - /*@{*/ - drm_ctx_list_t *ctxlist; /**< Linked list of context handles */ - int ctx_count; /**< Number of context handles */ - struct semaphore ctxlist_sem; /**< For ctxlist */ - - drm_map_t **context_sareas; /**< per-context SAREA's */ - int max_context; - - drm_vma_entry_t *vmalist; /**< List of vmas (for debugging) */ - drm_lock_data_t lock; /**< Information on hardware lock */ - /*@}*/ - - /** \name DMA queues (contexts) */ - /*@{*/ - int queue_count; /**< Number of active DMA queues */ - int queue_reserved; /**< Number of reserved DMA queues */ - int queue_slots; /**< Actual length of queuelist */ - drm_queue_t **queuelist; /**< Vector of pointers to DMA queues */ - drm_device_dma_t *dma; /**< Optional pointer for DMA support */ - /*@}*/ - - /** \name Context support */ - /*@{*/ - int irq; /**< Interrupt used by board */ - int irq_enabled; /**< True if irq handler is enabled */ - __volatile__ long context_flag; /**< Context swapping flag */ - __volatile__ long interrupt_flag; /**< Interruption handler flag */ - __volatile__ long dma_flag; /**< DMA dispatch flag */ - struct timer_list timer; /**< Timer for delaying ctx switch */ - wait_queue_head_t context_wait; /**< Processes waiting on ctx switch */ - int last_checked; /**< Last context checked for DMA */ - int last_context; /**< Last current context */ - unsigned long last_switch; /**< jiffies at last context switch */ - /*@}*/ - -#if !HAS_WORKQUEUE - struct tq_struct tq; -#else - struct work_struct work; -#endif - /** \name VBLANK IRQ support */ - /*@{*/ - - wait_queue_head_t vbl_queue; /**< VBLANK wait queue */ - atomic_t vbl_received; - spinlock_t vbl_lock; - drm_vbl_sig_t vbl_sigs; /**< signal list to send on VBLANK */ - unsigned int vbl_pending; - - /*@}*/ - cycles_t ctx_start; - cycles_t lck_start; - - char buf[DRM_BSZ]; /**< Output buffer */ - char *buf_rp; /**< Read pointer */ - char *buf_wp; /**< Write pointer */ - char *buf_end; /**< End pointer */ - struct fasync_struct *buf_async;/**< Processes waiting for SIGIO */ - wait_queue_head_t buf_readers; /**< Processes waiting to read */ - wait_queue_head_t buf_writers; /**< Processes waiting to ctx switch */ - -#if __OS_HAS_AGP - drm_agp_head_t *agp; /**< AGP data */ -#endif - - struct pci_dev *pdev; /**< PCI device structure */ - int pci_domain; /**< PCI bus domain number */ - int pci_bus; /**< PCI bus number */ - int pci_slot; /**< PCI slot number */ - int pci_func; /**< PCI function number */ -#ifdef __alpha__ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,3) - struct pci_controler *hose; -#else - struct pci_controller *hose; -#endif -#endif - drm_sg_mem_t *sg; /**< Scatter gather memory */ - unsigned long *ctx_bitmap; /**< context bitmap */ - void *dev_private; /**< device private data */ - drm_sigdata_t sigdata; /**< For block_all_signals */ - sigset_t sigmask; - - int need_reset; /**< secondary device needing reset */ - struct drm_driver_fn fn_tbl; - drm_local_map_t *agp_buffer_map; - int dev_priv_size; - u32 driver_features; -} drm_device_t; - -static __inline__ int drm_core_check_feature(struct drm_device *dev, int feature) -{ - return ((dev->driver_features & feature) ? 1 : 0); -} extern void DRM(driver_register_fns)(struct drm_device *dev); @@ -729,27 +140,6 @@ extern int DRM(mmap)(struct file *filp, struct vm_area_struct *vma); extern unsigned int DRM(poll)(struct file *filp, struct poll_table_struct *wait); extern ssize_t DRM(read)(struct file *filp, char __user *buf, size_t count, loff_t *off); - /* Memory management support (drm_memory.h) */ -extern void DRM(mem_init)(void); -extern int DRM(mem_info)(char *buf, char **start, off_t offset, - int request, int *eof, void *data); -extern void *DRM(calloc)(size_t nmemb, size_t size, int area); -extern void *DRM(realloc)(void *oldpt, size_t oldsize, size_t size, - int area); -extern unsigned long DRM(alloc_pages)(int order, int area); -extern void DRM(free_pages)(unsigned long address, int order, - int area); -extern void *DRM(ioremap)(unsigned long offset, unsigned long size, drm_device_t *dev); -extern void *DRM(ioremap_nocache)(unsigned long offset, unsigned long size, - drm_device_t *dev); -extern void DRM(ioremapfree)(void *pt, unsigned long size, drm_device_t *dev); - -#if __OS_HAS_AGP -extern DRM_AGP_MEM *DRM(alloc_agp)(int pages, u32 type); -extern int DRM(free_agp)(DRM_AGP_MEM *handle, int pages); -extern int DRM(bind_agp)(DRM_AGP_MEM *handle, unsigned int start); -extern int DRM(unbind_agp)(DRM_AGP_MEM *handle); -#endif /* Misc. IOCTL support (drm_ioctl.h) */ extern int DRM(irq_by_busid)(struct inode *inode, struct file *filp, @@ -825,31 +215,6 @@ extern int DRM(lock_free)(drm_device_t *dev, unsigned int context); extern int DRM(notifier)(void *priv); - /* Buffer management support (drm_bufs.h) */ -extern int DRM(order)( unsigned long size ); -extern int DRM(addmap)( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ); -extern int DRM(rmmap)( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ); -extern int DRM(initmap)( drm_device_t *dev, unsigned int offset, - unsigned int size, int type, int flags ); -extern int DRM(addbufs)( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ); -extern int DRM(infobufs)( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ); -extern int DRM(markbufs)( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ); -extern int DRM(freebufs)( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ); -extern int DRM(mapbufs)( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ); - - /* DMA support (drm_dma.h) */ -extern int DRM(dma_setup)(drm_device_t *dev); -extern void DRM(dma_takedown)(drm_device_t *dev); -extern void DRM(free_buffer)(drm_device_t *dev, drm_buf_t *buf); -extern void DRM(reclaim_buffers)( struct file *filp ); - /* IRQ support (drm_irq.h) */ extern int DRM(control)( struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg ); @@ -866,32 +231,7 @@ extern int DRM(vblank_wait)(drm_device_t *dev, unsigned int *vbl_seq); extern void DRM(vbl_send_signals)( drm_device_t *dev ); -#if __OS_HAS_AGP - /* AGP/GART support (drm_agpsupport.h) */ -extern drm_agp_head_t *DRM(agp_init)(void); -extern void DRM(agp_uninit)(void); -extern int DRM(agp_acquire)(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); -extern void DRM(agp_do_release)(void); -extern int DRM(agp_release)(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); -extern int DRM(agp_enable)(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); -extern int DRM(agp_info)(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); -extern int DRM(agp_alloc)(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); -extern int DRM(agp_free)(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); -extern int DRM(agp_unbind)(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); -extern int DRM(agp_bind)(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); -extern DRM_AGP_MEM *DRM(agp_allocate_memory)(size_t pages, u32 type); -extern int DRM(agp_free_memory)(DRM_AGP_MEM *handle); -extern int DRM(agp_bind_memory)(DRM_AGP_MEM *handle, off_t start); -extern int DRM(agp_unbind_memory)(DRM_AGP_MEM *handle); -#endif + /* Stub support (drm_stub.h) */ int DRM(stub_register)(const char *name, @@ -900,11 +240,11 @@ int DRM(stub_register)(const char *name, int DRM(stub_unregister)(int minor); /* Proc support (drm_proc.h) */ -extern int DRM(proc_init)(drm_device_t *dev, +extern int drm_proc_init(drm_device_t *dev, int minor, struct proc_dir_entry *root, struct proc_dir_entry **dev_root); -extern int DRM(proc_cleanup)(int minor, +extern int drm_proc_cleanup(int minor, struct proc_dir_entry *root, struct proc_dir_entry *dev_root); @@ -915,13 +255,7 @@ extern int DRM(sg_alloc)(struct inode *inode, struct file *filp, extern int DRM(sg_free)(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); - /* ATI PCIGART support (ati_pcigart.h) */ -extern int DRM(ati_pcigart_init)(drm_device_t *dev, - unsigned long *addr, - dma_addr_t *bus_addr); -extern int DRM(ati_pcigart_cleanup)(drm_device_t *dev, - unsigned long addr, - dma_addr_t bus_addr); + extern void *DRM(pci_alloc)(drm_device_t *dev, size_t size, size_t align, dma_addr_t maxaddr, @@ -930,56 +264,9 @@ extern void DRM(pci_free)(drm_device_t *dev, size_t size, void *vaddr, dma_addr_t busaddr); -/* Inline replacements for DRM_IOREMAP macros */ -static __inline__ void drm_core_ioremap(struct drm_map *map, struct drm_device *dev) -{ - map->handle = DRM(ioremap)( map->offset, map->size, dev ); -} - -static __inline__ void drm_core_ioremap_nocache(struct drm_map *map, struct drm_device *dev) -{ - map->handle = DRM(ioremap_nocache)(map->offset, map->size, dev); -} - -static __inline__ void drm_core_ioremapfree(struct drm_map *map, struct drm_device *dev) -{ - if ( map->handle && map->size ) - DRM(ioremapfree)( map->handle, map->size, dev ); -} - -static __inline__ struct drm_map *drm_core_findmap(struct drm_device *dev, unsigned long offset) -{ - struct list_head *_list; - list_for_each( _list, &dev->maplist->head ) { - drm_map_list_t *_entry = list_entry( _list, drm_map_list_t, head ); - if ( _entry->map && - _entry->map->offset == offset ) { - return _entry->map; - } - } - return NULL; -} - -static __inline__ void drm_core_dropmap(struct drm_map *map) -{ -} - -#ifndef DEBUG_MEMORY -/** Wrapper around kmalloc() */ -static __inline__ void *DRM(alloc)(size_t size, int area) -{ - return kmalloc(size, GFP_KERNEL); -} - -/** Wrapper around kfree() */ -static __inline__ void DRM(free)(void *pt, size_t size, int area) -{ - kfree(pt); -} -#else -extern void *DRM(alloc)(size_t size, int area); -extern void DRM(free)(void *pt, size_t size, int area); -#endif + + + /*@}*/ diff --git a/linux/drm_agpsupport.c b/linux/drm_agpsupport.c new file mode 100644 index 00000000..2e2e4ebe --- /dev/null +++ b/linux/drm_agpsupport.c @@ -0,0 +1,473 @@ +/** + * \file drm_agpsupport.h + * DRM support for AGP/GART backend + * + * \author Rickard E. (Rik) Faith <faith@valinux.com> + * \author Gareth Hughes <gareth@valinux.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. + */ + +#include "drm_headers.h" + +#define DRM(x) drm_memory_##x + +#if __OS_HAS_AGP + +#define DRM_AGP_GET (drm_agp_t *)inter_module_get("drm_agp") +#define DRM_AGP_PUT inter_module_put("drm_agp") + +/** + * Pointer to the drm_agp_t structure made available by the agpgart module. + */ +static const drm_agp_t *drm_agp = NULL; + +/** + * AGP information ioctl. + * + * \param inode device inode. + * \param filp file pointer. + * \param cmd command. + * \param arg pointer to a (output) drm_agp_info structure. + * \return zero on success or a negative number on failure. + * + * Verifies the AGP device has been initialized and acquired and fills in the + * drm_agp_info structure with the information in drm_agp_head::agp_info. + */ +int DRM(agp_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_AGP_KERN *kern; + drm_agp_info_t info; + + if (!dev->agp || !dev->agp->acquired || !drm_agp->copy_info) + return -EINVAL; + + kern = &dev->agp->agp_info; + info.agp_version_major = kern->version.major; + info.agp_version_minor = kern->version.minor; + info.mode = kern->mode; + info.aperture_base = kern->aper_base; + info.aperture_size = kern->aper_size * 1024 * 1024; + info.memory_allowed = kern->max_memory << PAGE_SHIFT; + info.memory_used = kern->current_memory << PAGE_SHIFT; + info.id_vendor = kern->device->vendor; + info.id_device = kern->device->device; + + if (copy_to_user((drm_agp_info_t __user *)arg, &info, sizeof(info))) + return -EFAULT; + return 0; +} + +/** + * Acquire the AGP device (ioctl). + * + * \param inode device inode. + * \param filp file pointer. + * \param cmd command. + * \param arg user argument. + * \return zero on success or a negative number on failure. + * + * Verifies the AGP device hasn't been acquired before and calls + * drm_agp->acquire(). + */ +int DRM(agp_acquire)(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; + + if (!dev->agp) + return -ENODEV; + if (dev->agp->acquired) + return -EBUSY; + if (!drm_agp->acquire) + return -EINVAL; +#ifndef VMAP_4_ARGS + if ( dev->agp->cant_use_aperture ) + return -EINVAL; +#endif + if ((retcode = drm_agp->acquire())) + return retcode; + dev->agp->acquired = 1; + return 0; +} + +/** + * Release the AGP device (ioctl). + * + * \param inode device inode. + * \param filp file pointer. + * \param cmd command. + * \param arg user argument. + * \return zero on success or a negative number on failure. + * + * Verifies the AGP device has been acquired and calls drm_agp->release(). + */ +int DRM(agp_release)(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; + + if (!dev->agp || !dev->agp->acquired || !drm_agp->release) + return -EINVAL; + drm_agp->release(); + dev->agp->acquired = 0; + return 0; + +} + +/** + * Release the AGP device. + * + * Calls drm_agp->release(). + */ +void DRM(agp_do_release)(void) +{ + if (drm_agp->release) + drm_agp->release(); +} + +/** + * Enable the AGP bus. + * + * \param inode device inode. + * \param filp file pointer. + * \param cmd command. + * \param arg pointer to a drm_agp_mode structure. + * \return zero on success or a negative number on failure. + * + * Verifies the AGP device has been acquired but not enabled, and calls + * drm_agp->enable(). + */ +int DRM(agp_enable)(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_agp_mode_t mode; + + if (!dev->agp || !dev->agp->acquired || !drm_agp->enable) + return -EINVAL; + + if (copy_from_user(&mode, (drm_agp_mode_t __user *)arg, sizeof(mode))) + return -EFAULT; + + dev->agp->mode = mode.mode; + drm_agp->enable(mode.mode); + dev->agp->base = dev->agp->agp_info.aper_base; + dev->agp->enabled = 1; + return 0; +} + +/** + * Allocate AGP memory. + * + * \param inode device inode. + * \param filp file pointer. + * \param cmd command. + * \param arg pointer to a drm_agp_buffer structure. + * \return zero on success or a negative number on failure. + * + * Verifies the AGP device is present and has been acquired, allocates the + * memory via alloc_agp() and creates a drm_agp_mem entry for it. + */ +int DRM(agp_alloc)(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_agp_buffer_t request; + drm_agp_mem_t *entry; + DRM_AGP_MEM *memory; + unsigned long pages; + u32 type; + drm_agp_buffer_t __user *argp = (void __user *)arg; + + if (!dev->agp || !dev->agp->acquired) + return -EINVAL; + if (copy_from_user(&request, argp, sizeof(request))) + return -EFAULT; + if (!(entry = drm_core_alloc(sizeof(*entry), DRM_MEM_AGPLISTS))) + return -ENOMEM; + + memset(entry, 0, sizeof(*entry)); + + pages = (request.size + PAGE_SIZE - 1) / PAGE_SIZE; + type = (u32) request.type; + + if (!(memory = DRM(alloc_agp)(pages, type))) { + drm_core_free(entry, sizeof(*entry), DRM_MEM_AGPLISTS); + return -ENOMEM; + } + + entry->handle = (unsigned long)memory->key + 1; + entry->memory = memory; + entry->bound = 0; + entry->pages = pages; + entry->prev = NULL; + entry->next = dev->agp->memory; + if (dev->agp->memory) + dev->agp->memory->prev = entry; + dev->agp->memory = entry; + + request.handle = entry->handle; + request.physical = memory->physical; + + if (copy_to_user(argp, &request, sizeof(request))) { + dev->agp->memory = entry->next; + dev->agp->memory->prev = NULL; + DRM(free_agp)(memory, pages); + drm_core_free(entry, sizeof(*entry), DRM_MEM_AGPLISTS); + return -EFAULT; + } + return 0; +} + +/** + * Search for the AGP memory entry associated with a handle. + * + * \param dev DRM device structure. + * \param handle AGP memory handle. + * \return pointer to the drm_agp_mem structure associated with \p handle. + * + * Walks through drm_agp_head::memory until finding a matching handle. + */ +static drm_agp_mem_t *DRM(agp_lookup_entry)(drm_device_t *dev, + unsigned long handle) +{ + drm_agp_mem_t *entry; + + for (entry = dev->agp->memory; entry; entry = entry->next) { + if (entry->handle == handle) + return entry; + } + return NULL; +} + +/** + * Unbind AGP memory from the GATT (ioctl). + * + * \param inode device inode. + * \param filp file pointer. + * \param cmd command. + * \param arg pointer to a drm_agp_binding structure. + * \return zero on success or a negative number on failure. + * + * Verifies the AGP device is present and acquired, looks-up the AGP memory + * entry and passes it to the unbind_agp() function. + */ +int DRM(agp_unbind)(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_agp_binding_t request; + drm_agp_mem_t *entry; + int ret; + + if (!dev->agp || !dev->agp->acquired) + return -EINVAL; + if (copy_from_user(&request, (drm_agp_binding_t __user *)arg, sizeof(request))) + return -EFAULT; + if (!(entry = DRM(agp_lookup_entry)(dev, request.handle))) + return -EINVAL; + if (!entry->bound) + return -EINVAL; + ret = DRM(unbind_agp)(entry->memory); + if (ret == 0) + entry->bound = 0; + return ret; +} + +/** + * Bind AGP memory into the GATT (ioctl) + * + * \param inode device inode. + * \param filp file pointer. + * \param cmd command. + * \param arg pointer to a drm_agp_binding structure. + * \return zero on success or a negative number on failure. + * + * Verifies the AGP device is present and has been acquired and that no memory + * is currently bound into the GATT. Looks-up the AGP memory entry and passes + * it to bind_agp() function. + */ +int DRM(agp_bind)(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_agp_binding_t request; + drm_agp_mem_t *entry; + int retcode; + int page; + + if (!dev->agp || !dev->agp->acquired || !drm_agp->bind_memory) + return -EINVAL; + if (copy_from_user(&request, (drm_agp_binding_t __user *)arg, sizeof(request))) + return -EFAULT; + if (!(entry = DRM(agp_lookup_entry)(dev, request.handle))) + return -EINVAL; + if (entry->bound) + return -EINVAL; + page = (request.offset + PAGE_SIZE - 1) / PAGE_SIZE; + if ((retcode = DRM(bind_agp)(entry->memory, page))) + return retcode; + entry->bound = dev->agp->base + (page << PAGE_SHIFT); + DRM_DEBUG("base = 0x%lx entry->bound = 0x%lx\n", + dev->agp->base, entry->bound); + return 0; +} + +/** + * Free AGP memory (ioctl). + * + * \param inode device inode. + * \param filp file pointer. + * \param cmd command. + * \param arg pointer to a drm_agp_buffer structure. + * \return zero on success or a negative number on failure. + * + * Verifies the AGP device is present and has been acquired and looks up the + * AGP memory entry. If the memory it's currently bound, unbind it via + * unbind_agp(). Frees it via free_agp() as well as the entry itself + * and unlinks from the doubly linked list it's inserted in. + */ +int DRM(agp_free)(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_agp_buffer_t request; + drm_agp_mem_t *entry; + + if (!dev->agp || !dev->agp->acquired) + return -EINVAL; + if (copy_from_user(&request, (drm_agp_buffer_t __user *)arg, sizeof(request))) + return -EFAULT; + if (!(entry = DRM(agp_lookup_entry)(dev, request.handle))) + return -EINVAL; + if (entry->bound) + DRM(unbind_agp)(entry->memory); + + if (entry->prev) + entry->prev->next = entry->next; + else + dev->agp->memory = entry->next; + + if (entry->next) + entry->next->prev = entry->prev; + + DRM(free_agp)(entry->memory, entry->pages); + drm_core_free(entry, sizeof(*entry), DRM_MEM_AGPLISTS); + return 0; +} + +/** + * Initialize the AGP resources. + * + * \return pointer to a drm_agp_head structure. + * + * Gets the drm_agp_t structure which is made available by the agpgart module + * via the inter_module_* functions. Creates and initializes a drm_agp_head + * structure. + */ +drm_agp_head_t *DRM(agp_init)(void) +{ + drm_agp_head_t *head = NULL; + + drm_agp = DRM_AGP_GET; + if (drm_agp) { + if (!(head = drm_core_alloc(sizeof(*head), DRM_MEM_AGPLISTS))) + return NULL; + memset((void *)head, 0, sizeof(*head)); + drm_agp->copy_info(&head->agp_info); + if (head->agp_info.chipset == NOT_SUPPORTED) { + drm_core_free(head, sizeof(*head), DRM_MEM_AGPLISTS); + return NULL; + } + head->memory = NULL; +#if LINUX_VERSION_CODE <= 0x020408 + head->cant_use_aperture = 0; + head->page_mask = ~(0xfff); +#else + head->cant_use_aperture = head->agp_info.cant_use_aperture; + head->page_mask = head->agp_info.page_mask; +#endif + } + return head; +} + +/** + * Free the AGP resources. + * + * Releases the pointer in ::drm_agp. + */ +void DRM(agp_uninit)(void) +{ + DRM_AGP_PUT; + drm_agp = NULL; +} + +/** Calls drm_agp->allocate_memory() */ +DRM_AGP_MEM *DRM(agp_allocate_memory)(size_t pages, u32 type) +{ + if (!drm_agp->allocate_memory) + return NULL; + return drm_agp->allocate_memory(pages, type); +} + +/** Calls drm_agp->free_memory() */ +int DRM(agp_free_memory)(DRM_AGP_MEM *handle) +{ + if (!handle || !drm_agp->free_memory) + return 0; + drm_agp->free_memory(handle); + return 1; +} + +/** Calls drm_agp->bind_memory() */ +int DRM(agp_bind_memory)(DRM_AGP_MEM *handle, off_t start) +{ + if (!handle || !drm_agp->bind_memory) + return -EINVAL; + return drm_agp->bind_memory(handle, start); +} + +/** Calls drm_agp->unbind_memory() */ +int DRM(agp_unbind_memory)(DRM_AGP_MEM *handle) +{ + if (!handle || !drm_agp->unbind_memory) + return -EINVAL; + return drm_agp->unbind_memory(handle); +} + +#endif /* __OS_HAS_AGP */ diff --git a/linux/drm_auth.h b/linux/drm_auth.h index fe099871..2931ac22 100644 --- a/linux/drm_auth.h +++ b/linux/drm_auth.h @@ -95,7 +95,7 @@ int DRM(add_magic)(drm_device_t *dev, drm_file_t *priv, drm_magic_t magic) DRM_DEBUG("%d\n", magic); hash = DRM(hash_magic)(magic); - entry = DRM(alloc)(sizeof(*entry), DRM_MEM_MAGIC); + entry = drm_core_alloc(sizeof(*entry), DRM_MEM_MAGIC); if (!entry) return -ENOMEM; memset(entry, 0, sizeof(*entry)); entry->magic = magic; @@ -152,7 +152,7 @@ int DRM(remove_magic)(drm_device_t *dev, drm_magic_t magic) } up(&dev->struct_sem); - DRM(free)(pt, sizeof(*pt), DRM_MEM_MAGIC); + drm_core_free(pt, sizeof(*pt), DRM_MEM_MAGIC); return -EINVAL; } diff --git a/linux/drm_bufs.c b/linux/drm_bufs.c new file mode 100644 index 00000000..f53dd523 --- /dev/null +++ b/linux/drm_bufs.c @@ -0,0 +1,1346 @@ +/** + * \file drm_bufs.c + * Generic buffer Library File + * + * \author Rickard E. (Rik) Faith <faith@valinux.com> + * \author Gareth Hughes <gareth@valinux.com> + */ + +/* + * Created: Thu Nov 23 03:10:50 2000 by gareth@valinux.com + * + * Copyright 1999, 2000 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. + */ + +#include "drm_headers.h" +/** + * Compute size order. Returns the exponent of the smaller power of two which + * is greater or equal to given number. + * + * \param size size. + * \return order. + * + * \todo Can be made faster. + */ +int drm_core_order( unsigned long size ) +{ + int order; + unsigned long tmp; + + for (order = 0, tmp = size >> 1; tmp; tmp >>= 1, order++) + ; + + if (size & (size - 1)) + ++order; + + return order; +} + + /** + * Adjusts the memory offset to its absolute value according to the mapping + * type. Adds the map to the map list drm_device::maplist. Adds MTRR's where + * applicable and if supported by the kernel. + */ +int drm_core_initmap( drm_device_t *dev, unsigned int offset, unsigned int size, int type, int flags ) +{ + drm_map_t *map; + drm_map_list_t *list; + + DRM_DEBUG("\n"); + + if ( (offset & (~PAGE_MASK)) || (size & (~PAGE_MASK)) ) + return -EINVAL; +#if !defined(__sparc__) && !defined(__alpha__) + if ( offset + size < offset || offset < virt_to_phys(high_memory) ) + return -EINVAL; +#endif + if ( !(list = drm_core_alloc( sizeof(*list), DRM_MEM_MAPS ))) + return -ENOMEM; + memset(list, 0, sizeof(*list)); + + if ( !(map = drm_core_alloc( sizeof(*map), DRM_MEM_MAPS ))) { + drm_core_free(list, sizeof(*list), DRM_MEM_MAPS); + return -ENOMEM; + } + + *map = (drm_map_t){ + .offset = offset, + .size = size, + .type = type, + .flags = flags, + .mtrr = -1, + .handle = 0, + }; + list->map = map; + + DRM_DEBUG( "initmap offset = 0x%08lx, size = 0x%08lx, type = %d\n", + map->offset, map->size, map->type ); + +#ifdef __alpha__ + map->offset += dev->hose->mem_space->start; +#endif +#if __OS_HAS_MTRR + if ( drm_core_check_feature(dev, DRIVER_USE_MTRR) ) { + if ( map->type == _DRM_FRAME_BUFFER || + (map->flags & _DRM_WRITE_COMBINING) ) { + map->mtrr = mtrr_add( map->offset, map->size, + MTRR_TYPE_WRCOMB, 1 ); + } + } +#endif + if (map->type == _DRM_REGISTERS) + drm_core_ioremap( map, dev ); + + down(&dev->struct_sem); + list_add(&list->head, &dev->maplist->head); + up(&dev->struct_sem); + + DRM_DEBUG("finished\n"); + + return 0; +} + +/** + * Ioctl to specify a range of memory that is available for mapping by a non-root process. + * + * \param inode device inode. + * \param filp file pointer. + * \param cmd command. + * \param arg pointer to a drm_map structure. + * \return zero on success or a negative value on error. + * + * Adjusts the memory offset to its absolute value according to the mapping + * type. Adds the map to the map list drm_device::maplist. Adds MTRR's where + * applicable and if supported by the kernel. + */ +int drm_core_addmap( 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_map_t *map; + drm_map_t __user *argp = (void __user *)arg; + drm_map_list_t *list; + + if ( !(filp->f_mode & 3) ) return -EACCES; /* Require read/write */ + + map = drm_core_alloc( sizeof(*map), DRM_MEM_MAPS ); + if ( !map ) + return -ENOMEM; + + if ( copy_from_user( map, argp, sizeof(*map) ) ) { + drm_core_free( map, sizeof(*map), DRM_MEM_MAPS ); + return -EFAULT; + } + + /* Only allow shared memory to be removable since we only keep enough + * book keeping information about shared memory to allow for removal + * when processes fork. + */ + if ( (map->flags & _DRM_REMOVABLE) && map->type != _DRM_SHM ) { + drm_core_free( map, sizeof(*map), DRM_MEM_MAPS ); + return -EINVAL; + } + DRM_DEBUG( "offset = 0x%08lx, size = 0x%08lx, type = %d\n", + map->offset, map->size, map->type ); + if ( (map->offset & (~PAGE_MASK)) || (map->size & (~PAGE_MASK)) ) { + drm_core_free( map, sizeof(*map), DRM_MEM_MAPS ); + return -EINVAL; + } + map->mtrr = -1; + map->handle = NULL; + + switch ( map->type ) { + case _DRM_REGISTERS: + case _DRM_FRAME_BUFFER: { + /* after all the drivers switch to permanent mapping this should just return an error */ + struct list_head *_list; + + /* if map already exists, return the existing one instead of creating a new one */ + list_for_each( _list, &dev->maplist->head ) { + drm_map_list_t *_entry = list_entry( _list, drm_map_list_t, head ); + if ( _entry->map && _entry->map->type == map->type ) { + drm_core_free( map, sizeof(*map), DRM_MEM_MAPS ); + map = _entry->map; + DRM_DEBUG( "Found existing: offset = 0x%08lx, size = 0x%08lx, type = %d\n", + map->offset, map->size, map->type ); + goto found_it; + } + } +#if !defined(__sparc__) && !defined(__alpha__) && !defined(__ia64__) + if ( map->offset + map->size < map->offset || + map->offset < virt_to_phys(high_memory) ) { + drm_core_free( map, sizeof(*map), DRM_MEM_MAPS ); + return -EINVAL; + } +#endif +#ifdef __alpha__ + map->offset += dev->hose->mem_space->start; +#endif +#if __OS_HAS_MTRR + if (drm_core_check_feature(dev, DRIVER_USE_MTRR)) { + if ( map->type == _DRM_FRAME_BUFFER || + (map->flags & _DRM_WRITE_COMBINING) ) { + map->mtrr = mtrr_add( map->offset, map->size, + MTRR_TYPE_WRCOMB, 1 ); + } + } +#endif + if (map->type == _DRM_REGISTERS) + drm_core_ioremap( map, dev ); + break; + } + case _DRM_SHM: + map->handle = vmalloc_32(map->size); + DRM_DEBUG( "%lu %d %p\n", + map->size, drm_core_order( map->size ), map->handle ); + if ( !map->handle ) { + drm_core_free( map, sizeof(*map), DRM_MEM_MAPS ); + return -ENOMEM; + } + map->offset = (unsigned long)map->handle; + if ( map->flags & _DRM_CONTAINS_LOCK ) { + /* Prevent a 2nd X Server from creating a 2nd lock */ + if (dev->lock.hw_lock != NULL) { + vfree( map->handle ); + drm_core_free( map, sizeof(*map), DRM_MEM_MAPS ); + return -EBUSY; + } + dev->sigdata.lock = + dev->lock.hw_lock = map->handle; /* Pointer to lock */ + } + break; +#if __OS_HAS_AGP + case _DRM_AGP: + if (drm_core_check_feature(dev, DRIVER_USE_AGP)) { +#ifdef __alpha__ + map->offset += dev->hose->mem_space->start; +#endif + map->offset += dev->agp->base; + map->mtrr = dev->agp->agp_mtrr; /* for getmap */ + } + break; +#endif + case _DRM_SCATTER_GATHER: + if (!dev->sg) { + drm_core_free(map, sizeof(*map), DRM_MEM_MAPS); + return -EINVAL; + } + map->offset += dev->sg->handle; + break; + + default: + drm_core_free( map, sizeof(*map), DRM_MEM_MAPS ); + return -EINVAL; + } + + list = drm_core_alloc(sizeof(*list), DRM_MEM_MAPS); + if(!list) { + drm_core_free(map, sizeof(*map), DRM_MEM_MAPS); + return -EINVAL; + } + memset(list, 0, sizeof(*list)); + list->map = map; + + down(&dev->struct_sem); + list_add(&list->head, &dev->maplist->head); + up(&dev->struct_sem); +found_it: + if ( copy_to_user( argp, map, sizeof(*map) ) ) + return -EFAULT; + if ( map->type != _DRM_SHM ) { + if ( copy_to_user( &argp->handle, + &map->offset, + sizeof(map->offset) ) ) + return -EFAULT; + } + return 0; +} + + +/** + * Remove a map private from list and deallocate resources if the mapping + * isn't in use. + * + * \param inode device inode. + * \param filp file pointer. + * \param cmd command. + * \param arg pointer to a drm_map_t structure. + * \return zero on success or a negative value on error. + * + * Searches the map on drm_device::maplist, removes it from the list, see if + * its being used, and free any associate resource (such as MTRR's) if it's not + * being on use. + * + * \sa addmap(). + */ +int drm_core_rmmap(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; + struct list_head *list; + drm_map_list_t *r_list = NULL; + drm_vma_entry_t *pt, *prev; + drm_map_t *map; + drm_map_t request; + int found_maps = 0; + + if (copy_from_user(&request, (drm_map_t __user *)arg, + sizeof(request))) { + return -EFAULT; + } + + down(&dev->struct_sem); + list = &dev->maplist->head; + list_for_each(list, &dev->maplist->head) { + r_list = list_entry(list, drm_map_list_t, head); + + if(r_list->map && + r_list->map->handle == request.handle && + r_list->map->flags & _DRM_REMOVABLE) break; + } + + /* List has wrapped around to the head pointer, or its empty we didn't + * find anything. + */ + if(list == (&dev->maplist->head)) { + up(&dev->struct_sem); + return -EINVAL; + } + map = r_list->map; + + /* Register and framebuffer maps are permanent */ + if ((map->type == _DRM_REGISTERS) || (map->type == _DRM_FRAME_BUFFER)) { + up(&dev->struct_sem); + return 0; + } + list_del(list); + drm_core_free(list, sizeof(*list), DRM_MEM_MAPS); + + for (pt = dev->vmalist, prev = NULL; pt; prev = pt, pt = pt->next) { + if (pt->vma->vm_private_data == map) found_maps++; + } + + if(!found_maps) { + switch (map->type) { + case _DRM_REGISTERS: + case _DRM_FRAME_BUFFER: + break; /* Can't get here, make compiler happy */ + case _DRM_SHM: + vfree(map->handle); + break; + case _DRM_AGP: + case _DRM_SCATTER_GATHER: + break; + } + drm_core_free(map, sizeof(*map), DRM_MEM_MAPS); + } + up(&dev->struct_sem); + return 0; +} + +/** + * Cleanup after an error on one of the addbufs() functions. + * + * \param entry buffer entry where the error occurred. + * + * Frees any pages and buffers associated with the given entry. + */ +static void drm_cleanup_buf_error(drm_device_t *dev, drm_buf_entry_t *entry) +{ + int i; + + if (entry->seg_count) { + for (i = 0; i < entry->seg_count; i++) { + if (entry->seglist[i]) { + drm_core_free_pages(entry->seglist[i], + entry->page_order, + DRM_MEM_DMA); + } + } + drm_core_free(entry->seglist, + entry->seg_count * + sizeof(*entry->seglist), + DRM_MEM_SEGS); + + entry->seg_count = 0; + } + + if (entry->buf_count) { + for (i = 0; i < entry->buf_count; i++) { + if (entry->buflist[i].dev_private) { + drm_core_free(entry->buflist[i].dev_private, + entry->buflist[i].dev_priv_size, + DRM_MEM_BUFS); + } + } + drm_core_free(entry->buflist, + entry->buf_count * + sizeof(*entry->buflist), + DRM_MEM_BUFS); + + entry->buf_count = 0; + } +} + +#if __OS_HAS_AGP +/** + * Add AGP buffers for DMA transfers (ioctl). + * + * \param inode device inode. + * \param filp file pointer. + * \param cmd command. + * \param arg pointer to a drm_buf_desc_t request. + * \return zero on success or a negative number on failure. + * + * After some sanity checks creates a drm_buf structure for each buffer and + * reallocates the buffer list of the same size order to accommodate the new + * buffers. + */ +int drm_core_addbufs_agp( 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_buf_desc_t request; + drm_buf_entry_t *entry; + drm_buf_t *buf; + unsigned long offset; + unsigned long agp_offset; + int count; + int order; + int size; + int alignment; + int page_order; + int total; + int byte_count; + int i; + drm_buf_t **temp_buflist; + drm_buf_desc_t __user *argp = (void __user *)arg; + + if ( !dma ) return -EINVAL; + + if ( copy_from_user( &request, argp, + sizeof(request) ) ) + return -EFAULT; + + count = request.count; + order = drm_core_order( request.size ); + size = 1 << order; + + alignment = (request.flags & _DRM_PAGE_ALIGN) + ? PAGE_ALIGN(size) : size; + page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0; + total = PAGE_SIZE << page_order; + + byte_count = 0; + agp_offset = dev->agp->base + request.agp_start; + + DRM_DEBUG( "count: %d\n", count ); + DRM_DEBUG( "order: %d\n", order ); + DRM_DEBUG( "size: %d\n", size ); + DRM_DEBUG( "agp_offset: %lu\n", agp_offset ); + DRM_DEBUG( "alignment: %d\n", alignment ); + DRM_DEBUG( "page_order: %d\n", page_order ); + DRM_DEBUG( "total: %d\n", total ); + + if ( order < DRM_MIN_ORDER || order > DRM_MAX_ORDER ) return -EINVAL; + if ( dev->queue_count ) return -EBUSY; /* Not while in use */ + + spin_lock( &dev->count_lock ); + if ( dev->buf_use ) { + spin_unlock( &dev->count_lock ); + return -EBUSY; + } + atomic_inc( &dev->buf_alloc ); + spin_unlock( &dev->count_lock ); + + down( &dev->struct_sem ); + entry = &dma->bufs[order]; + if ( entry->buf_count ) { + up( &dev->struct_sem ); + atomic_dec( &dev->buf_alloc ); + return -ENOMEM; /* May only call once for each order */ + } + + if (count < 0 || count > 4096) { + up( &dev->struct_sem ); + atomic_dec( &dev->buf_alloc ); + return -EINVAL; + } + + entry->buflist = drm_core_alloc( count * sizeof(*entry->buflist), + DRM_MEM_BUFS ); + if ( !entry->buflist ) { + up( &dev->struct_sem ); + atomic_dec( &dev->buf_alloc ); + return -ENOMEM; + } + memset( entry->buflist, 0, count * sizeof(*entry->buflist) ); + + entry->buf_size = size; + entry->page_order = page_order; + + offset = 0; + + while ( entry->buf_count < count ) { + buf = &entry->buflist[entry->buf_count]; + buf->idx = dma->buf_count + entry->buf_count; + buf->total = alignment; + buf->order = order; + buf->used = 0; + + buf->offset = (dma->byte_count + offset); + buf->bus_address = agp_offset + offset; + buf->address = (void *)(agp_offset + offset); + buf->next = NULL; + buf->waiting = 0; + buf->pending = 0; + init_waitqueue_head( &buf->dma_wait ); + buf->filp = NULL; + + buf->dev_priv_size = dev->dev_priv_size; + buf->dev_private = drm_core_alloc( buf->dev_priv_size, + DRM_MEM_BUFS ); + if(!buf->dev_private) { + /* Set count correctly so we free the proper amount. */ + entry->buf_count = count; + drm_cleanup_buf_error(dev,entry); + up( &dev->struct_sem ); + atomic_dec( &dev->buf_alloc ); + return -ENOMEM; + } + memset( buf->dev_private, 0, buf->dev_priv_size ); + + DRM_DEBUG( "buffer %d @ %p\n", + entry->buf_count, buf->address ); + + offset += alignment; + entry->buf_count++; + byte_count += PAGE_SIZE << page_order; + } + + DRM_DEBUG( "byte_count: %d\n", byte_count ); + + temp_buflist = drm_core_realloc( dma->buflist, + dma->buf_count * sizeof(*dma->buflist), + (dma->buf_count + entry->buf_count) + * sizeof(*dma->buflist), + DRM_MEM_BUFS ); + if(!temp_buflist) { + /* Free the entry because it isn't valid */ + drm_cleanup_buf_error(dev,entry); + up( &dev->struct_sem ); + atomic_dec( &dev->buf_alloc ); + return -ENOMEM; + } + dma->buflist = temp_buflist; + + for ( i = 0 ; i < entry->buf_count ; i++ ) { + dma->buflist[i + dma->buf_count] = &entry->buflist[i]; + } + + dma->buf_count += entry->buf_count; + dma->byte_count += byte_count; + + DRM_DEBUG( "dma->buf_count : %d\n", dma->buf_count ); + DRM_DEBUG( "entry->buf_count : %d\n", entry->buf_count ); + + up( &dev->struct_sem ); + + request.count = entry->buf_count; + request.size = size; + + if ( copy_to_user( argp, &request, sizeof(request) ) ) + return -EFAULT; + + dma->flags = _DRM_DMA_USE_AGP; + + atomic_dec( &dev->buf_alloc ); + return 0; +} +#endif /* __OS_HAS_AGP */ + +int drm_core_addbufs_pci( 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_buf_desc_t request; + int count; + int order; + int size; + int total; + int page_order; + drm_buf_entry_t *entry; + unsigned long page; + drm_buf_t *buf; + int alignment; + unsigned long offset; + int i; + int byte_count; + int page_count; + unsigned long *temp_pagelist; + drm_buf_t **temp_buflist; + drm_buf_desc_t __user *argp = (void __user *)arg; + + if (!drm_core_check_feature(dev, DRIVER_PCI_DMA)) return -EINVAL; + + if ( !dma ) return -EINVAL; + + if ( copy_from_user( &request, argp, sizeof(request) ) ) + return -EFAULT; + + count = request.count; + order = drm_core_order( request.size ); + size = 1 << order; + + DRM_DEBUG( "count=%d, size=%d (%d), order=%d, queue_count=%d\n", + request.count, request.size, size, + order, dev->queue_count ); + + if ( order < DRM_MIN_ORDER || order > DRM_MAX_ORDER ) return -EINVAL; + if ( dev->queue_count ) return -EBUSY; /* Not while in use */ + + alignment = (request.flags & _DRM_PAGE_ALIGN) + ? PAGE_ALIGN(size) : size; + page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0; + total = PAGE_SIZE << page_order; + + spin_lock( &dev->count_lock ); + if ( dev->buf_use ) { + spin_unlock( &dev->count_lock ); + return -EBUSY; + } + atomic_inc( &dev->buf_alloc ); + spin_unlock( &dev->count_lock ); + + down( &dev->struct_sem ); + entry = &dma->bufs[order]; + if ( entry->buf_count ) { + up( &dev->struct_sem ); + atomic_dec( &dev->buf_alloc ); + return -ENOMEM; /* May only call once for each order */ + } + + if (count < 0 || count > 4096) { + up( &dev->struct_sem ); + atomic_dec( &dev->buf_alloc ); + return -EINVAL; + } + + entry->buflist = drm_core_alloc( count * sizeof(*entry->buflist), + DRM_MEM_BUFS ); + if ( !entry->buflist ) { + up( &dev->struct_sem ); + atomic_dec( &dev->buf_alloc ); + return -ENOMEM; + } + memset( entry->buflist, 0, count * sizeof(*entry->buflist) ); + + entry->seglist = drm_core_alloc( count * sizeof(*entry->seglist), + DRM_MEM_SEGS ); + if ( !entry->seglist ) { + drm_core_free( entry->buflist, + count * sizeof(*entry->buflist), + DRM_MEM_BUFS ); + up( &dev->struct_sem ); + atomic_dec( &dev->buf_alloc ); + return -ENOMEM; + } + memset( entry->seglist, 0, count * sizeof(*entry->seglist) ); + + /* Keep the original pagelist until we know all the allocations + * have succeeded + */ + temp_pagelist = drm_core_alloc( (dma->page_count + (count << page_order)) + * sizeof(*dma->pagelist), + DRM_MEM_PAGES ); + if (!temp_pagelist) { + drm_core_free( entry->buflist, + count * sizeof(*entry->buflist), + DRM_MEM_BUFS ); + drm_core_free( entry->seglist, + count * sizeof(*entry->seglist), + DRM_MEM_SEGS ); + up( &dev->struct_sem ); + atomic_dec( &dev->buf_alloc ); + return -ENOMEM; + } + memcpy(temp_pagelist, + dma->pagelist, + dma->page_count * sizeof(*dma->pagelist)); + DRM_DEBUG( "pagelist: %d entries\n", + dma->page_count + (count << page_order) ); + + entry->buf_size = size; + entry->page_order = page_order; + byte_count = 0; + page_count = 0; + + while ( entry->buf_count < count ) { + page = drm_core_alloc_pages( page_order, DRM_MEM_DMA ); + if ( !page ) { + /* Set count correctly so we free the proper amount. */ + entry->buf_count = count; + entry->seg_count = count; + drm_cleanup_buf_error(dev,entry); + drm_core_free( temp_pagelist, + (dma->page_count + (count << page_order)) + * sizeof(*dma->pagelist), + DRM_MEM_PAGES ); + up( &dev->struct_sem ); + atomic_dec( &dev->buf_alloc ); + return -ENOMEM; + } + entry->seglist[entry->seg_count++] = page; + for ( i = 0 ; i < (1 << page_order) ; i++ ) { + DRM_DEBUG( "page %d @ 0x%08lx\n", + dma->page_count + page_count, + page + PAGE_SIZE * i ); + temp_pagelist[dma->page_count + page_count++] + = page + PAGE_SIZE * i; + } + for ( offset = 0 ; + offset + size <= total && entry->buf_count < count ; + offset += alignment, ++entry->buf_count ) { + buf = &entry->buflist[entry->buf_count]; + buf->idx = dma->buf_count + entry->buf_count; + buf->total = alignment; + buf->order = order; + buf->used = 0; + buf->offset = (dma->byte_count + byte_count + offset); + buf->address = (void *)(page + offset); + buf->bus_address = virt_to_bus(buf->address); + buf->next = NULL; + buf->waiting = 0; + buf->pending = 0; + init_waitqueue_head( &buf->dma_wait ); + buf->filp = NULL; + + buf->dev_priv_size = dev->dev_priv_size; + buf->dev_private = drm_core_alloc( dev->dev_priv_size, + DRM_MEM_BUFS ); + if(!buf->dev_private) { + /* Set count correctly so we free the proper amount. */ + entry->buf_count = count; + entry->seg_count = count; + drm_cleanup_buf_error(dev,entry); + drm_core_free( temp_pagelist, + (dma->page_count + (count << page_order)) + * sizeof(*dma->pagelist), + DRM_MEM_PAGES ); + up( &dev->struct_sem ); + atomic_dec( &dev->buf_alloc ); + return -ENOMEM; + } + memset( buf->dev_private, 0, buf->dev_priv_size ); + + DRM_DEBUG( "buffer %d @ %p\n", + entry->buf_count, buf->address ); + } + byte_count += PAGE_SIZE << page_order; + } + + temp_buflist = drm_core_realloc( dma->buflist, + dma->buf_count * sizeof(*dma->buflist), + (dma->buf_count + entry->buf_count) + * sizeof(*dma->buflist), + DRM_MEM_BUFS ); + if (!temp_buflist) { + /* Free the entry because it isn't valid */ + drm_cleanup_buf_error(dev,entry); + drm_core_free( temp_pagelist, + (dma->page_count + (count << page_order)) + * sizeof(*dma->pagelist), + DRM_MEM_PAGES ); + up( &dev->struct_sem ); + atomic_dec( &dev->buf_alloc ); + return -ENOMEM; + } + dma->buflist = temp_buflist; + + for ( i = 0 ; i < entry->buf_count ; i++ ) { + dma->buflist[i + dma->buf_count] = &entry->buflist[i]; + } + + /* No allocations failed, so now we can replace the orginal pagelist + * with the new one. + */ + if (dma->page_count) { + drm_core_free(dma->pagelist, + dma->page_count * sizeof(*dma->pagelist), + DRM_MEM_PAGES); + } + dma->pagelist = temp_pagelist; + + dma->buf_count += entry->buf_count; + dma->seg_count += entry->seg_count; + dma->page_count += entry->seg_count << page_order; + dma->byte_count += PAGE_SIZE * (entry->seg_count << page_order); + + up( &dev->struct_sem ); + + request.count = entry->buf_count; + request.size = size; + + if ( copy_to_user( argp, &request, sizeof(request) ) ) + return -EFAULT; + + atomic_dec( &dev->buf_alloc ); + return 0; + +} + +int drm_core_addbufs_sg( 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_buf_desc_t __user *argp = (void __user *)arg; + drm_buf_desc_t request; + drm_buf_entry_t *entry; + drm_buf_t *buf; + unsigned long offset; + unsigned long agp_offset; + int count; + int order; + int size; + int alignment; + int page_order; + int total; + int byte_count; + int i; + drm_buf_t **temp_buflist; + + if (!drm_core_check_feature(dev, DRIVER_SG)) return -EINVAL; + + if ( !dma ) return -EINVAL; + + if ( copy_from_user( &request, argp, sizeof(request) ) ) + return -EFAULT; + + count = request.count; + order = drm_core_order( request.size ); + size = 1 << order; + + alignment = (request.flags & _DRM_PAGE_ALIGN) + ? PAGE_ALIGN(size) : size; + page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0; + total = PAGE_SIZE << page_order; + + byte_count = 0; + agp_offset = request.agp_start; + + DRM_DEBUG( "count: %d\n", count ); + DRM_DEBUG( "order: %d\n", order ); + DRM_DEBUG( "size: %d\n", size ); + DRM_DEBUG( "agp_offset: %lu\n", agp_offset ); + DRM_DEBUG( "alignment: %d\n", alignment ); + DRM_DEBUG( "page_order: %d\n", page_order ); + DRM_DEBUG( "total: %d\n", total ); + + if ( order < DRM_MIN_ORDER || order > DRM_MAX_ORDER ) return -EINVAL; + if ( dev->queue_count ) return -EBUSY; /* Not while in use */ + + spin_lock( &dev->count_lock ); + if ( dev->buf_use ) { + spin_unlock( &dev->count_lock ); + return -EBUSY; + } + atomic_inc( &dev->buf_alloc ); + spin_unlock( &dev->count_lock ); + + down( &dev->struct_sem ); + entry = &dma->bufs[order]; + if ( entry->buf_count ) { + up( &dev->struct_sem ); + atomic_dec( &dev->buf_alloc ); + return -ENOMEM; /* May only call once for each order */ + } + + if (count < 0 || count > 4096) { + up( &dev->struct_sem ); + atomic_dec( &dev->buf_alloc ); + return -EINVAL; + } + + entry->buflist = drm_core_alloc( count * sizeof(*entry->buflist), + DRM_MEM_BUFS ); + if ( !entry->buflist ) { + up( &dev->struct_sem ); + atomic_dec( &dev->buf_alloc ); + return -ENOMEM; + } + memset( entry->buflist, 0, count * sizeof(*entry->buflist) ); + + entry->buf_size = size; + entry->page_order = page_order; + + offset = 0; + + while ( entry->buf_count < count ) { + buf = &entry->buflist[entry->buf_count]; + buf->idx = dma->buf_count + entry->buf_count; + buf->total = alignment; + buf->order = order; + buf->used = 0; + + buf->offset = (dma->byte_count + offset); + buf->bus_address = agp_offset + offset; + buf->address = (void *)(agp_offset + offset + dev->sg->handle); + buf->next = NULL; + buf->waiting = 0; + buf->pending = 0; + init_waitqueue_head( &buf->dma_wait ); + buf->filp = NULL; + + buf->dev_priv_size = dev->dev_priv_size; + buf->dev_private = drm_core_alloc( dev->dev_priv_size, + DRM_MEM_BUFS ); + if(!buf->dev_private) { + /* Set count correctly so we free the proper amount. */ + entry->buf_count = count; + drm_cleanup_buf_error(dev,entry); + up( &dev->struct_sem ); + atomic_dec( &dev->buf_alloc ); + return -ENOMEM; + } + + memset( buf->dev_private, 0, buf->dev_priv_size ); + + DRM_DEBUG( "buffer %d @ %p\n", + entry->buf_count, buf->address ); + + offset += alignment; + entry->buf_count++; + byte_count += PAGE_SIZE << page_order; + } + + DRM_DEBUG( "byte_count: %d\n", byte_count ); + + temp_buflist = drm_core_realloc( dma->buflist, + dma->buf_count * sizeof(*dma->buflist), + (dma->buf_count + entry->buf_count) + * sizeof(*dma->buflist), + DRM_MEM_BUFS ); + if(!temp_buflist) { + /* Free the entry because it isn't valid */ + drm_cleanup_buf_error(dev,entry); + up( &dev->struct_sem ); + atomic_dec( &dev->buf_alloc ); + return -ENOMEM; + } + dma->buflist = temp_buflist; + + for ( i = 0 ; i < entry->buf_count ; i++ ) { + dma->buflist[i + dma->buf_count] = &entry->buflist[i]; + } + + dma->buf_count += entry->buf_count; + dma->byte_count += byte_count; + + DRM_DEBUG( "dma->buf_count : %d\n", dma->buf_count ); + DRM_DEBUG( "entry->buf_count : %d\n", entry->buf_count ); + + up( &dev->struct_sem ); + + request.count = entry->buf_count; + request.size = size; + + if ( copy_to_user( argp, &request, sizeof(request) ) ) + return -EFAULT; + + dma->flags = _DRM_DMA_USE_SG; + + atomic_dec( &dev->buf_alloc ); + return 0; +} + +/** + * Add buffers for DMA transfers (ioctl). + * + * \param inode device inode. + * \param filp file pointer. + * \param cmd command. + * \param arg pointer to a drm_buf_desc_t request. + * \return zero on success or a negative number on failure. + * + * According with the memory type specified in drm_buf_desc::flags and the + * build options, it dispatches the call either to addbufs_agp(), + * addbufs_sg() or addbufs_pci() for AGP, scatter-gather or consistent + * PCI memory respectively. + */ +int drm_core_addbufs( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ) +{ + drm_buf_desc_t request; + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + + if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA)) + return -EINVAL; + + if ( copy_from_user( &request, (drm_buf_desc_t __user *)arg, + sizeof(request) ) ) + return -EFAULT; + +#if __OS_HAS_AGP + if ( request.flags & _DRM_AGP_BUFFER ) + return drm_core_addbufs_agp( inode, filp, cmd, arg ); + else +#endif + if ( request.flags & _DRM_SG_BUFFER ) + return drm_core_addbufs_sg( inode, filp, cmd, arg ); + else + return drm_core_addbufs_pci( inode, filp, cmd, arg ); +} + + +/** + * Get information about the buffer mappings. + * + * This was originally mean for debugging purposes, or by a sophisticated + * client library to determine how best to use the available buffers (e.g., + * large buffers can be used for image transfer). + * + * \param inode device inode. + * \param filp file pointer. + * \param cmd command. + * \param arg pointer to a drm_buf_info structure. + * \return zero on success or a negative number on failure. + * + * Increments drm_device::buf_use while holding the drm_device::count_lock + * lock, preventing of allocating more buffers after this call. Information + * about each requested buffer is then copied into user space. + */ +int drm_core_infobufs( 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_buf_info_t request; + drm_buf_info_t __user *argp = (void __user *)arg; + int i; + int count; + + if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA)) + return -EINVAL; + + if ( !dma ) return -EINVAL; + + spin_lock( &dev->count_lock ); + if ( atomic_read( &dev->buf_alloc ) ) { + spin_unlock( &dev->count_lock ); + return -EBUSY; + } + ++dev->buf_use; /* Can't allocate more after this call */ + spin_unlock( &dev->count_lock ); + + if ( copy_from_user( &request, argp, sizeof(request) ) ) + return -EFAULT; + + for ( i = 0, count = 0 ; i < DRM_MAX_ORDER + 1 ; i++ ) { + if ( dma->bufs[i].buf_count ) ++count; + } + + DRM_DEBUG( "count = %d\n", count ); + + if ( request.count >= count ) { + for ( i = 0, count = 0 ; i < DRM_MAX_ORDER + 1 ; i++ ) { + if ( dma->bufs[i].buf_count ) { + drm_buf_desc_t __user *to = &request.list[count]; + drm_buf_entry_t *from = &dma->bufs[i]; + drm_freelist_t *list = &dma->bufs[i].freelist; + if ( copy_to_user( &to->count, + &from->buf_count, + sizeof(from->buf_count) ) || + copy_to_user( &to->size, + &from->buf_size, + sizeof(from->buf_size) ) || + copy_to_user( &to->low_mark, + &list->low_mark, + sizeof(list->low_mark) ) || + copy_to_user( &to->high_mark, + &list->high_mark, + sizeof(list->high_mark) ) ) + return -EFAULT; + + DRM_DEBUG( "%d %d %d %d %d\n", + i, + dma->bufs[i].buf_count, + dma->bufs[i].buf_size, + dma->bufs[i].freelist.low_mark, + dma->bufs[i].freelist.high_mark ); + ++count; + } + } + } + request.count = count; + + if ( copy_to_user( argp, &request, sizeof(request) ) ) + return -EFAULT; + + return 0; +} + +/** + * Specifies a low and high water mark for buffer allocation + * + * \param inode device inode. + * \param filp file pointer. + * \param cmd command. + * \param arg a pointer to a drm_buf_desc structure. + * \return zero on success or a negative number on failure. + * + * Verifies that the size order is bounded between the admissible orders and + * updates the respective drm_device_dma::bufs entry low and high water mark. + * + * \note This ioctl is deprecated and mostly never used. + */ +int drm_core_markbufs( 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_buf_desc_t request; + int order; + drm_buf_entry_t *entry; + + if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA)) + return -EINVAL; + + if ( !dma ) return -EINVAL; + + if ( copy_from_user( &request, + (drm_buf_desc_t __user *)arg, + sizeof(request) ) ) + return -EFAULT; + + DRM_DEBUG( "%d, %d, %d\n", + request.size, request.low_mark, request.high_mark ); + order = drm_core_order( request.size ); + if ( order < DRM_MIN_ORDER || order > DRM_MAX_ORDER ) return -EINVAL; + entry = &dma->bufs[order]; + + if ( request.low_mark < 0 || request.low_mark > entry->buf_count ) + return -EINVAL; + if ( request.high_mark < 0 || request.high_mark > entry->buf_count ) + return -EINVAL; + + entry->freelist.low_mark = request.low_mark; + entry->freelist.high_mark = request.high_mark; + + return 0; +} + +/** + * Unreserve the buffers in list, previously reserved using drmDMA. + * + * \param inode device inode. + * \param filp file pointer. + * \param cmd command. + * \param arg pointer to a drm_buf_free structure. + * \return zero on success or a negative number on failure. + * + * Calls free_buffer() for each used buffer. + * This function is primarily used for debugging. + */ +int drm_core_freebufs( 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_buf_free_t request; + int i; + int idx; + drm_buf_t *buf; + + if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA)) + return -EINVAL; + + if ( !dma ) return -EINVAL; + + if ( copy_from_user( &request, + (drm_buf_free_t __user *)arg, + sizeof(request) ) ) + return -EFAULT; + + DRM_DEBUG( "%d\n", request.count ); + for ( i = 0 ; i < request.count ; i++ ) { + if ( copy_from_user( &idx, + &request.list[i], + sizeof(idx) ) ) + return -EFAULT; + if ( idx < 0 || idx >= dma->buf_count ) { + DRM_ERROR( "Index %d (of %d max)\n", + idx, dma->buf_count - 1 ); + return -EINVAL; + } + buf = dma->buflist[idx]; + if ( buf->filp != filp ) { + DRM_ERROR( "Process %d freeing buffer not owned\n", + current->pid ); + return -EINVAL; + } + drm_core_free_buffer( dev, buf ); + } + + return 0; +} + +/** + * Maps all of the DMA buffers into client-virtual space (ioctl). + * + * \param inode device inode. + * \param filp file pointer. + * \param cmd command. + * \param arg pointer to a drm_buf_map structure. + * \return zero on success or a negative number on failure. + * + * Maps the AGP or SG buffer region with do_mmap(), and copies information + * about each buffer into user space. The PCI buffers are already mapped on the + * addbufs_pci() call. + */ +int drm_core_mapbufs( 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_buf_map_t __user *argp = (void __user *)arg; + int retcode = 0; + const int zero = 0; + unsigned long virtual; + unsigned long address; + drm_buf_map_t request; + int i; + + if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA)) + return -EINVAL; + + if ( !dma ) return -EINVAL; + + spin_lock( &dev->count_lock ); + if ( atomic_read( &dev->buf_alloc ) ) { + spin_unlock( &dev->count_lock ); + return -EBUSY; + } + dev->buf_use++; /* Can't allocate more after this call */ + spin_unlock( &dev->count_lock ); + + if ( copy_from_user( &request, argp, sizeof(request) ) ) + return -EFAULT; + + if ( request.count >= dma->buf_count ) { + if (( drm_core_check_feature(dev, DRIVER_USE_AGP) && (dma->flags & _DRM_DMA_USE_AGP)) || + ( drm_core_check_feature(dev, DRIVER_SG) && (dma->flags & _DRM_DMA_USE_SG)) ) { + drm_map_t *map = dev->agp_buffer_map; + + if ( !map ) { + retcode = -EINVAL; + goto done; + } + +#if LINUX_VERSION_CODE <= 0x020402 + down( ¤t->mm->mmap_sem ); +#else + down_write( ¤t->mm->mmap_sem ); +#endif + virtual = do_mmap( filp, 0, map->size, + PROT_READ | PROT_WRITE, + MAP_SHARED, + (unsigned long)map->offset ); +#if LINUX_VERSION_CODE <= 0x020402 + up( ¤t->mm->mmap_sem ); +#else + up_write( ¤t->mm->mmap_sem ); +#endif + } else { +#if LINUX_VERSION_CODE <= 0x020402 + down( ¤t->mm->mmap_sem ); +#else + down_write( ¤t->mm->mmap_sem ); +#endif + virtual = do_mmap( filp, 0, dma->byte_count, + PROT_READ | PROT_WRITE, + MAP_SHARED, 0 ); +#if LINUX_VERSION_CODE <= 0x020402 + up( ¤t->mm->mmap_sem ); +#else + up_write( ¤t->mm->mmap_sem ); +#endif + } + if ( virtual > -1024UL ) { + /* Real error */ + retcode = (signed long)virtual; + goto done; + } + request.virtual = (void __user *)virtual; + + for ( i = 0 ; i < dma->buf_count ; i++ ) { + if ( copy_to_user( &request.list[i].idx, + &dma->buflist[i]->idx, + sizeof(request.list[0].idx) ) ) { + retcode = -EFAULT; + goto done; + } + if ( copy_to_user( &request.list[i].total, + &dma->buflist[i]->total, + sizeof(request.list[0].total) ) ) { + retcode = -EFAULT; + goto done; + } + if ( copy_to_user( &request.list[i].used, + &zero, + sizeof(zero) ) ) { + retcode = -EFAULT; + goto done; + } + address = virtual + dma->buflist[i]->offset; /* *** */ + if ( copy_to_user( &request.list[i].address, + &address, + sizeof(address) ) ) { + retcode = -EFAULT; + goto done; + } + } + } + done: + request.count = dma->buf_count; + DRM_DEBUG( "%d buffers, retcode = %d\n", request.count, retcode ); + + if ( copy_to_user( argp, &request, sizeof(request) ) ) + return -EFAULT; + + return retcode; +} + diff --git a/linux/drm_context.h b/linux/drm_context.h index e1cb95c6..8bad6b39 100644 --- a/linux/drm_context.h +++ b/linux/drm_context.h @@ -100,7 +100,7 @@ int DRM(ctxbitmap_next)( drm_device_t *dev ) if(dev->context_sareas) { drm_map_t **ctx_sareas; - ctx_sareas = DRM(realloc)(dev->context_sareas, + ctx_sareas = drm_core_realloc(dev->context_sareas, (dev->max_context - 1) * sizeof(*dev->context_sareas), dev->max_context * @@ -115,7 +115,7 @@ int DRM(ctxbitmap_next)( drm_device_t *dev ) dev->context_sareas[bit] = NULL; } else { /* max_context == 1 at this point */ - dev->context_sareas = DRM(alloc)( + dev->context_sareas = drm_core_alloc( dev->max_context * sizeof(*dev->context_sareas), DRM_MEM_MAPS); @@ -148,7 +148,7 @@ int DRM(ctxbitmap_init)( drm_device_t *dev ) int temp; down(&dev->struct_sem); - dev->ctx_bitmap = (unsigned long *) DRM(alloc)( PAGE_SIZE, + dev->ctx_bitmap = (unsigned long *) drm_core_alloc( PAGE_SIZE, DRM_MEM_CTXBITMAP ); if ( dev->ctx_bitmap == NULL ) { up(&dev->struct_sem); @@ -178,11 +178,11 @@ int DRM(ctxbitmap_init)( drm_device_t *dev ) void DRM(ctxbitmap_cleanup)( drm_device_t *dev ) { down(&dev->struct_sem); - if( dev->context_sareas ) DRM(free)( dev->context_sareas, + if( dev->context_sareas ) drm_core_free( dev->context_sareas, sizeof(*dev->context_sareas) * dev->max_context, DRM_MEM_MAPS ); - DRM(free)( (void *)dev->ctx_bitmap, PAGE_SIZE, DRM_MEM_CTXBITMAP ); + drm_core_free( (void *)dev->ctx_bitmap, PAGE_SIZE, DRM_MEM_CTXBITMAP ); up(&dev->struct_sem); } @@ -421,7 +421,7 @@ int DRM(addctx)( struct inode *inode, struct file *filp, dev->fn_tbl.context_ctor(dev, ctx.handle); } - ctx_entry = DRM(alloc)( sizeof(*ctx_entry), DRM_MEM_CTXLIST ); + ctx_entry = drm_core_alloc( sizeof(*ctx_entry), DRM_MEM_CTXLIST ); if ( !ctx_entry ) { DRM_DEBUG("out of memory\n"); return -ENOMEM; @@ -564,7 +564,7 @@ int DRM(rmctx)( struct inode *inode, struct file *filp, list_for_each_entry_safe( pos, n, &dev->ctxlist->head, head ) { if ( pos->handle == ctx.handle ) { list_del( &pos->head ); - DRM(free)( pos, sizeof(*pos), DRM_MEM_CTXLIST ); + drm_core_free( pos, sizeof(*pos), DRM_MEM_CTXLIST ); --dev->ctx_count; } } diff --git a/linux/drm_core.h b/linux/drm_core.h new file mode 100644 index 00000000..435d5cbf --- /dev/null +++ b/linux/drm_core.h @@ -0,0 +1,699 @@ +#ifndef DRM_CORE_H +#define DRM_CORE_H + +#include "drm_compat.h" +#define DRM_PROC_LIMIT (PAGE_SIZE-80) + +#define DRM_PROC_PRINT(fmt, arg...) \ + len += sprintf(&buf[len], fmt , ##arg); \ + if (len > DRM_PROC_LIMIT) { *eof = 1; return len - offset; } + +#define DRM_PROC_PRINT_RET(ret, fmt, arg...) \ + len += sprintf(&buf[len], fmt , ##arg); \ + if (len > DRM_PROC_LIMIT) { ret; *eof = 1; return len - offset; } + +/** + * Memory error output. + * + * \param area memory area where the error occurred. + * \param fmt printf() like format string. + * \param arg arguments + */ +#define DRM_INFO(fmt, arg...) printk(KERN_INFO "[" DRM_NAME "] " fmt , ##arg) + +/** + * Error output. + * + * \param fmt printf() like format string. + * \param arg arguments + */ +#define DRM_ERROR(fmt, arg...) \ + printk(KERN_ERR "[" DRM_NAME ":%s] *ERROR* " fmt , __FUNCTION__ , ##arg) + +#if DRM_DEBUG_CODE +#define DRM_DEBUG(fmt, arg...) \ + do { \ + if (1) \ + printk(KERN_DEBUG \ + "[" DRM_NAME ":%s] " fmt , \ + __FUNCTION__ , ##arg); \ + } while (0) +#else +#define DRM_DEBUG(fmt, arg...) do { } while (0) +#endif + +#define DRM_LEFTCOUNT(x) (((x)->rp + (x)->count - (x)->wp) % ((x)->count + 1)) +#define DRM_BUFCOUNT(x) ((x)->count - DRM_LEFTCOUNT(x)) +#define DRM_WAITCOUNT(dev,idx) DRM_BUFCOUNT(&dev->queuelist[idx]->waitlist) + + +/* driver capabilities and requirements mask */ +#define DRIVER_USE_AGP 0x1 +#define DRIVER_REQUIRE_AGP 0x2 +#define DRIVER_USE_MTRR 0x4 +#define DRIVER_HAVE_DMA 0x10 +#define DRIVER_HAVE_IRQ 0x20 +#define DRIVER_SG 0x40 +#define DRIVER_PCI_DMA 0x80 +#define DRIVER_IRQ_SHARED 0x100 +#define DRIVER_IRQ_VBL 0x200 +#define DRIVER_DMA_QUEUE 0x800 + +#define __OS_HAS_AGP (defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE)) +#define __OS_HAS_MTRR (defined(CONFIG_MTRR)) +/*@}*/ +#define DRM_DEBUG_CODE 2 /**< Include debugging code if > 1, then + also include looping detection. */ + +#define DRM_HASH_SIZE 16 /**< Size of key hash table. Must be power of 2. */ +#define DRM_KERNEL_CONTEXT 0 /**< Change drm_resctx if changed */ +#define DRM_RESERVED_CONTEXTS 1 /**< Change drm_resctx if changed */ +#define DRM_LOOPING_LIMIT 5000000 +#define DRM_BSZ 1024 /**< Buffer size for /dev/drm? output */ +#define DRM_TIME_SLICE (HZ/20) /**< Time slice for GLXContexts */ +#define DRM_LOCK_SLICE 1 /**< Time slice for lock, in jiffies */ + +#define DRM_FLAG_DEBUG 0x01 + +#define DRM_MEM_DMA 0 +#define DRM_MEM_SAREA 1 +#define DRM_MEM_DRIVER 2 +#define DRM_MEM_MAGIC 3 +#define DRM_MEM_IOCTLS 4 +#define DRM_MEM_MAPS 5 +#define DRM_MEM_VMAS 6 +#define DRM_MEM_BUFS 7 +#define DRM_MEM_SEGS 8 +#define DRM_MEM_PAGES 9 +#define DRM_MEM_FILES 10 +#define DRM_MEM_QUEUES 11 +#define DRM_MEM_CMDS 12 +#define DRM_MEM_MAPPINGS 13 +#define DRM_MEM_BUFLISTS 14 +#define DRM_MEM_AGPLISTS 15 +#define DRM_MEM_TOTALAGP 16 +#define DRM_MEM_BOUNDAGP 17 +#define DRM_MEM_CTXBITMAP 18 +#define DRM_MEM_STUB 19 +#define DRM_MEM_SGLISTS 20 +#define DRM_MEM_CTXLIST 21 + +/** + * Ioctl function type. + * + * \param inode device inode. + * \param filp file pointer. + * \param cmd command. + * \param arg argument. + */ +typedef int drm_ioctl_t( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ); + +typedef struct drm_ioctl_desc { + drm_ioctl_t *func; + int auth_needed; + int root_only; +} drm_ioctl_desc_t; + +typedef struct drm_devstate { + pid_t owner; /**< X server pid holding x_lock */ +} drm_devstate_t; + +typedef struct drm_magic_entry { + drm_magic_t magic; + struct drm_file *priv; + struct drm_magic_entry *next; +} drm_magic_entry_t; + +typedef struct drm_magic_head { + struct drm_magic_entry *head; + struct drm_magic_entry *tail; +} drm_magic_head_t; + +typedef struct drm_vma_entry { + struct vm_area_struct *vma; + struct drm_vma_entry *next; + pid_t pid; +} drm_vma_entry_t; + +/** + * DMA buffer. + */ +typedef struct drm_buf { + int idx; /**< Index into master buflist */ + int total; /**< Buffer size */ + int order; /**< log-base-2(total) */ + int used; /**< Amount of buffer in use (for DMA) */ + unsigned long offset; /**< Byte offset (used internally) */ + void *address; /**< Address of buffer */ + unsigned long bus_address; /**< Bus address of buffer */ + struct drm_buf *next; /**< Kernel-only: used for free list */ + __volatile__ int waiting; /**< On kernel DMA queue */ + __volatile__ int pending; /**< On hardware DMA queue */ + wait_queue_head_t dma_wait; /**< Processes waiting */ + struct file *filp; /**< Pointer to holding file descr */ + int context; /**< Kernel queue for this buffer */ + int while_locked;/**< Dispatch this buffer while locked */ + enum { + DRM_LIST_NONE = 0, + DRM_LIST_FREE = 1, + DRM_LIST_WAIT = 2, + DRM_LIST_PEND = 3, + DRM_LIST_PRIO = 4, + DRM_LIST_RECLAIM = 5 + } list; /**< Which list we're on */ + + int dev_priv_size; /**< Size of buffer private storage */ + void *dev_private; /**< Per-buffer private storage */ +} drm_buf_t; + + +/** bufs is one longer than it has to be */ +typedef struct drm_waitlist { + int count; /**< Number of possible buffers */ + drm_buf_t **bufs; /**< List of pointers to buffers */ + drm_buf_t **rp; /**< Read pointer */ + drm_buf_t **wp; /**< Write pointer */ + drm_buf_t **end; /**< End pointer */ + spinlock_t read_lock; + spinlock_t write_lock; +} drm_waitlist_t; + +typedef struct drm_freelist { + int initialized; /**< Freelist in use */ + atomic_t count; /**< Number of free buffers */ + drm_buf_t *next; /**< End pointer */ + + wait_queue_head_t waiting; /**< Processes waiting on free bufs */ + int low_mark; /**< Low water mark */ + int high_mark; /**< High water mark */ + atomic_t wfh; /**< If waiting for high mark */ + spinlock_t lock; +} drm_freelist_t; + +/** + * Buffer entry. There is one of this for each buffer size order. + */ +typedef struct drm_buf_entry { + int buf_size; /**< size */ + int buf_count; /**< number of buffers */ + drm_buf_t *buflist; /**< buffer list */ + int seg_count; + int page_order; + unsigned long *seglist; + + drm_freelist_t freelist; +} drm_buf_entry_t; + +/** File private data */ +typedef struct drm_file { + int authenticated; + int minor; + pid_t pid; + uid_t uid; + drm_magic_t magic; + unsigned long ioctl_count; + struct drm_file *next; + struct drm_file *prev; + struct drm_device *dev; + int remove_auth_on_close; + unsigned long lock_count; + void *driver_priv; +} drm_file_t; + +/** Wait queue */ +typedef struct drm_queue { + atomic_t use_count; /**< Outstanding uses (+1) */ + atomic_t finalization; /**< Finalization in progress */ + atomic_t block_count; /**< Count of processes waiting */ + atomic_t block_read; /**< Queue blocked for reads */ + wait_queue_head_t read_queue; /**< Processes waiting on block_read */ + atomic_t block_write; /**< Queue blocked for writes */ + wait_queue_head_t write_queue; /**< Processes waiting on block_write */ +#if 1 + atomic_t total_queued; /**< Total queued statistic */ + atomic_t total_flushed;/**< Total flushes statistic */ + atomic_t total_locks; /**< Total locks statistics */ +#endif + drm_ctx_flags_t flags; /**< Context preserving and 2D-only */ + drm_waitlist_t waitlist; /**< Pending buffers */ + wait_queue_head_t flush_queue; /**< Processes waiting until flush */ +} drm_queue_t; + +/** + * Lock data. + */ +typedef struct drm_lock_data { + drm_hw_lock_t *hw_lock; /**< Hardware lock */ + struct file *filp; /**< File descr of lock holder (0=kernel) */ + wait_queue_head_t lock_queue; /**< Queue of blocked processes */ + unsigned long lock_time; /**< Time of last lock in jiffies */ +} drm_lock_data_t; + +/** + * DMA data. + */ +typedef struct drm_device_dma { + + drm_buf_entry_t bufs[DRM_MAX_ORDER+1]; /**< buffers, grouped by their size order */ + int buf_count; /**< total number of buffers */ + drm_buf_t **buflist; /**< Vector of pointers into drm_device_dma::bufs */ + int seg_count; + int page_count; /**< number of pages */ + unsigned long *pagelist; /**< page list */ + unsigned long byte_count; + enum { + _DRM_DMA_USE_AGP = 0x01, + _DRM_DMA_USE_SG = 0x02 + } flags; + + /** \name DMA support */ + /*@{*/ + drm_buf_t *this_buffer; /**< Buffer being sent */ + drm_buf_t *next_buffer; /**< Selected buffer to send */ + drm_queue_t *next_queue; /**< Queue from which buffer selected*/ + wait_queue_head_t waiting; /**< Processes waiting on free bufs */ + /*@}*/ +} drm_device_dma_t; + +#if __OS_HAS_AGP +/** + * AGP memory entry. Stored as a doubly linked list. + */ +typedef struct drm_agp_mem { + unsigned long handle; /**< handle */ + DRM_AGP_MEM *memory; + unsigned long bound; /**< address */ + int pages; + struct drm_agp_mem *prev; /**< previous entry */ + struct drm_agp_mem *next; /**< next entry */ +} drm_agp_mem_t; + +/** + * AGP data. + * + * \sa DRM(agp_init)() and drm_device::agp. + */ +typedef struct drm_agp_head { + DRM_AGP_KERN agp_info; /**< AGP device information */ + drm_agp_mem_t *memory; /**< memory entries */ + unsigned long mode; /**< AGP mode */ + int enabled; /**< whether the AGP bus as been enabled */ + int acquired; /**< whether the AGP device has been acquired */ + unsigned long base; + int agp_mtrr; + int cant_use_aperture; + unsigned long page_mask; +} drm_agp_head_t; +#endif + +/** + * Scatter-gather memory. + */ +typedef struct drm_sg_mem { + unsigned long handle; + void *virtual; + int pages; + struct page **pagelist; + dma_addr_t *busaddr; +} drm_sg_mem_t; + +typedef struct drm_sigdata { + int context; + drm_hw_lock_t *lock; +} drm_sigdata_t; + +/** + * Mappings list + */ +typedef struct drm_map_list { + struct list_head head; /**< list head */ + drm_map_t *map; /**< mapping */ +} drm_map_list_t; + +typedef drm_map_t drm_local_map_t; + +/** + * Context handle list + */ +typedef struct drm_ctx_list { + struct list_head head; /**< list head */ + drm_context_t handle; /**< context handle */ + drm_file_t *tag; /**< associated fd private data */ +} drm_ctx_list_t; + + +typedef struct drm_vbl_sig { + struct list_head head; + unsigned int sequence; + struct siginfo info; + struct task_struct *task; +} drm_vbl_sig_t; + + +/** + * DRM device functions structure + */ +struct drm_device; + +struct drm_driver_fn { + int (*preinit)(struct drm_device *, unsigned long flags); + int (*postinit)(struct drm_device *, unsigned long flags); + void (*prerelease)(struct drm_device *, struct file *filp); + void (*pretakedown)(struct drm_device *); + int (*postcleanup)(struct drm_device *); + int (*presetup)(struct drm_device *); + int (*postsetup)(struct drm_device *); + + /* these are opposites at the moment */ + int (*open_helper)(struct drm_device *, drm_file_t *); + void (*free_filp_private)(struct drm_device *, drm_file_t *); + + void (*release)(struct drm_device *, struct file *filp); + void (*dma_ready)(struct drm_device *); + int (*dma_quiescent)(struct drm_device *); + int (*context_ctor)(struct drm_device *dev, int context); + int (*context_dtor)(struct drm_device *dev, int context); + int (*kernel_context_switch)(struct drm_device *dev, int old, int new); + int (*kernel_context_switch_unlock)(struct drm_device *dev); + int (*vblank_wait)(struct drm_device *dev, unsigned int *sequence); +/* these have to be filled in */ + irqreturn_t (*irq_handler)( DRM_IRQ_ARGS ); + void (*irq_preinstall)(struct drm_device *dev); + void (*irq_postinstall)(struct drm_device *dev); + void (*irq_uninstall)(struct drm_device *dev); + void (*reclaim_buffers)(struct file *filp); + unsigned long (*get_map_ofs)(drm_map_t *map); + unsigned long (*get_reg_ofs)(struct drm_device *dev); + void (*set_version)(struct drm_device *dev, drm_set_version_t *sv); +}; + +/** + * DRM device structure. + */ +typedef struct drm_device { + const char *name; /**< Simple driver name */ + char *unique; /**< Unique identifier: e.g., busid */ + int unique_len; /**< Length of unique field */ + dev_t device; /**< Device number for mknod */ + char *devname; /**< For /proc/interrupts */ + int minor; /**< Minor device number */ + int if_version; /**< Highest interface version set */ + + int blocked; /**< Blocked due to VC switch? */ + struct proc_dir_entry *root; /**< Root for this device's entries */ + + /** \name Locks */ + /*@{*/ + spinlock_t count_lock; /**< For inuse, drm_device::open_count, drm_device::buf_use */ + struct semaphore struct_sem; /**< For others */ + /*@}*/ + + /** \name Usage Counters */ + /*@{*/ + int open_count; /**< Outstanding files open */ + atomic_t ioctl_count; /**< Outstanding IOCTLs pending */ + atomic_t vma_count; /**< Outstanding vma areas open */ + int buf_use; /**< Buffers in use -- cannot alloc */ + atomic_t buf_alloc; /**< Buffer allocation in progress */ + /*@}*/ + + /** \name Performance counters */ + /*@{*/ + unsigned long counters; + drm_stat_type_t types[15]; + atomic_t counts[15]; + /*@}*/ + + /** \name Authentication */ + /*@{*/ + drm_file_t *file_first; /**< file list head */ + drm_file_t *file_last; /**< file list tail */ + drm_magic_head_t magiclist[DRM_HASH_SIZE]; /**< magic hash table */ + /*@}*/ + + /** \name Memory management */ + /*@{*/ + drm_map_list_t *maplist; /**< Linked list of regions */ + int map_count; /**< Number of mappable regions */ + + /** \name Context handle management */ + /*@{*/ + drm_ctx_list_t *ctxlist; /**< Linked list of context handles */ + int ctx_count; /**< Number of context handles */ + struct semaphore ctxlist_sem; /**< For ctxlist */ + + drm_map_t **context_sareas; /**< per-context SAREA's */ + int max_context; + + drm_vma_entry_t *vmalist; /**< List of vmas (for debugging) */ + drm_lock_data_t lock; /**< Information on hardware lock */ + /*@}*/ + + /** \name DMA queues (contexts) */ + /*@{*/ + int queue_count; /**< Number of active DMA queues */ + int queue_reserved; /**< Number of reserved DMA queues */ + int queue_slots; /**< Actual length of queuelist */ + drm_queue_t **queuelist; /**< Vector of pointers to DMA queues */ + drm_device_dma_t *dma; /**< Optional pointer for DMA support */ + /*@}*/ + + /** \name Context support */ + /*@{*/ + int irq; /**< Interrupt used by board */ + int irq_enabled; /**< True if irq handler is enabled */ + __volatile__ long context_flag; /**< Context swapping flag */ + __volatile__ long interrupt_flag; /**< Interruption handler flag */ + __volatile__ long dma_flag; /**< DMA dispatch flag */ + struct timer_list timer; /**< Timer for delaying ctx switch */ + wait_queue_head_t context_wait; /**< Processes waiting on ctx switch */ + int last_checked; /**< Last context checked for DMA */ + int last_context; /**< Last current context */ + unsigned long last_switch; /**< jiffies at last context switch */ + /*@}*/ + +#if !HAS_WORKQUEUE + struct tq_struct tq; +#else + struct work_struct work; +#endif + /** \name VBLANK IRQ support */ + /*@{*/ + + wait_queue_head_t vbl_queue; /**< VBLANK wait queue */ + atomic_t vbl_received; + spinlock_t vbl_lock; + drm_vbl_sig_t vbl_sigs; /**< signal list to send on VBLANK */ + unsigned int vbl_pending; + + /*@}*/ + cycles_t ctx_start; + cycles_t lck_start; + + char buf[DRM_BSZ]; /**< Output buffer */ + char *buf_rp; /**< Read pointer */ + char *buf_wp; /**< Write pointer */ + char *buf_end; /**< End pointer */ + struct fasync_struct *buf_async;/**< Processes waiting for SIGIO */ + wait_queue_head_t buf_readers; /**< Processes waiting to read */ + wait_queue_head_t buf_writers; /**< Processes waiting to ctx switch */ + +#if __OS_HAS_AGP + drm_agp_head_t *agp; /**< AGP data */ +#endif + + struct pci_dev *pdev; /**< PCI device structure */ + int pci_domain; /**< PCI bus domain number */ + int pci_bus; /**< PCI bus number */ + int pci_slot; /**< PCI slot number */ + int pci_func; /**< PCI function number */ +#ifdef __alpha__ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,3) + struct pci_controler *hose; +#else + struct pci_controller *hose; +#endif +#endif + drm_sg_mem_t *sg; /**< Scatter gather memory */ + unsigned long *ctx_bitmap; /**< context bitmap */ + void *dev_private; /**< device private data */ + drm_sigdata_t sigdata; /**< For block_all_signals */ + sigset_t sigmask; + + int need_reset; /**< secondary device needing reset */ + struct drm_driver_fn fn_tbl; + drm_local_map_t *agp_buffer_map; + int dev_priv_size; + u32 driver_features; +} drm_device_t; + +#if __OS_HAS_AGP +extern DRM_AGP_MEM *drm_memory_alloc_agp(int pages, u32 type); +extern int drm_memory_free_agp(DRM_AGP_MEM *handle, int pages); +extern int drm_memory_bind_agp(DRM_AGP_MEM *handle, unsigned int start); +extern int drm_memory_unbind_agp(DRM_AGP_MEM *handle); +#endif + /* Buffer management support (drm_bufs.h) */ +extern int drm_core_order( unsigned long size ); +extern int drm_core_addmap( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ); +extern int drm_core_rmmap( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ); +extern int drm_core_initmap( drm_device_t *dev, unsigned int offset, + unsigned int size, int type, int flags ); +extern int drm_core_addbufs( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ); +extern int drm_core_infobufs( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ); +extern int drm_core_markbufs( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ); +extern int drm_core_freebufs( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ); +extern int drm_core_mapbufs( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ); + + /* DMA support (drm_dma.h) */ +extern int drm_core_dma_setup(drm_device_t *dev); +extern void drm_core_dma_takedown(drm_device_t *dev); +extern void drm_core_free_buffer(drm_device_t *dev, drm_buf_t *buf); +extern void drm_core_reclaim_buffers( struct file *filp ); + +#if __OS_HAS_AGP + /* AGP/GART support (drm_agpsupport.h) */ +extern drm_agp_head_t *drm_memory_agp_init(void); +extern void drm_memory_agp_uninit(void); +extern int drm_memory_agp_acquire(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern void drm_memory_agp_do_release(void); +extern int drm_memory_agp_release(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_memory_agp_enable(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_memory_agp_info(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_memory_agp_alloc(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_memory_agp_free(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_memory_agp_unbind(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int drm_memory_agp_bind(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern DRM_AGP_MEM *drm_memory_agp_allocate_memory(size_t pages, u32 type); +extern int drm_memory_agp_free_memory(DRM_AGP_MEM *handle); +extern int drm_memory_agp_bind_memory(DRM_AGP_MEM *handle, off_t start); +extern int drm_memory_agp_unbind_memory(DRM_AGP_MEM *handle); +#endif + + /* ATI PCIGART support (ati_pcigart.h) */ +extern int drm_ati_pcigart_init(drm_device_t *dev, + unsigned long *addr, + dma_addr_t *bus_addr); +extern int drm_ati_pcigart_cleanup(drm_device_t *dev, + unsigned long addr, + dma_addr_t bus_addr); + + /* Proc support (drm_proc.h) */ +extern int drm_proc_init(drm_device_t *dev, + int minor, + struct proc_dir_entry *root, + struct proc_dir_entry **dev_root); +extern int drm_proc_cleanup(int minor, + struct proc_dir_entry *root, + struct proc_dir_entry *dev_root); + + +static __inline__ int drm_core_check_feature(struct drm_device *dev, int feature) +{ + return ((dev->driver_features & feature) ? 1 : 0); +} + +#include "drm_core_memory.h" + +#ifndef DEBUG_MEMORY +/** Wrapper around kmalloc() */ +static __inline__ void *drm_core_alloc(size_t size, int area) +{ + return kmalloc(size, GFP_KERNEL); +} + +/** Wrapper around kfree() */ +static __inline__ void drm_core_free(void *pt, size_t size, int area) +{ + kfree(pt); +} + +static __inline__ void drm_core_ioremap(struct drm_map *map, struct drm_device *dev) +{ + map->handle = drm_ioremap( map->offset, map->size, dev ); +} + +static __inline__ void drm_core_ioremap_nocache(struct drm_map *map, struct drm_device *dev) +{ + map->handle = drm_ioremap_nocache(map->offset, map->size, dev); +} + +static __inline__ void drm_core_ioremapfree(struct drm_map *map, struct drm_device *dev) +{ + if ( map->handle && map->size ) + drm_ioremapfree( map->handle, map->size, dev ); +} + +static __inline__ void drm_core_free_pages(unsigned long address, int order, int area) +{ + drm_memory_free_pages(address, order, area); +} + +static __inline__ void *drm_core_realloc(void *oldpt, size_t oldsize, size_t size, int area) +{ + return drm_memory_realloc(oldpt, oldsize, size, area); +} + +static __inline__ unsigned long drm_core_alloc_pages(int order, int area) +{ + return drm_memory_alloc_pages(order, area); +} + +static __inline__ void drm_core_mem_init(void) +{ + drm_memory_mem_init(); +} + +#else +static __inline__ void *drm_core_alloc(size_t size, int area) +{ + return drm_memory_debug_alloc(size, area); +} +static __inline__ void drm_core_free(void *pt, size_t size, int area) +{ + drm_memory_debug_free(pt, size, area); +} +#endif + + +static __inline__ struct drm_map *drm_core_findmap(struct drm_device *dev, unsigned long offset) +{ + struct list_head *_list; + list_for_each( _list, &dev->maplist->head ) { + drm_map_list_t *_entry = list_entry( _list, drm_map_list_t, head ); + if ( _entry->map && + _entry->map->offset == offset ) { + return _entry->map; + } + } + return NULL; +} + +static __inline__ void drm_core_dropmap(struct drm_map *map) +{ +} + +extern int drm_core_dma_setup( drm_device_t *dev ); +extern void drm_core_dma_takedown(drm_device_t *dev); +extern void drm_core_free_buffer(drm_device_t *dev, drm_buf_t *buf); +extern void drm_core_reclaim_buffers( struct file *filp ); + + + +#endif diff --git a/linux/drm_core_memory.h b/linux/drm_core_memory.h new file mode 100644 index 00000000..640de3d8 --- /dev/null +++ b/linux/drm_core_memory.h @@ -0,0 +1,147 @@ +#ifndef DRM_CORE_MEMORY_H +#define DRM_CORE_MEMORY_H + +#if __OS_HAS_AGP && defined(VMAP_4_ARGS) + +#ifdef HAVE_PAGE_AGP +#include <asm/agp.h> +#else +#ifdef __powerpc__ +# define PAGE_AGP __pgprot(_PAGE_KERNEL | _PAGE_NO_CACHE) +#else +# define PAGE_AGP PAGE_KERNEL +#endif +#endif + +void drm_memory_free_pages(unsigned long address, int order, int area); +void *drm_memory_realloc(void *oldpt, size_t oldsize, size_t size, int area); +unsigned long drm_memory_alloc_pages(int order, int area); +void drm_memory_mem_init(void); +/* + * Find the drm_map that covers the range [offset, offset+size). + */ +static inline drm_map_t * +drm_lookup_map (unsigned long offset, unsigned long size, drm_device_t *dev) +{ + struct list_head *list; + drm_map_list_t *r_list; + drm_map_t *map; + + list_for_each(list, &dev->maplist->head) { + r_list = (drm_map_list_t *) list; + map = r_list->map; + if (!map) + continue; + if (map->offset <= offset && (offset + size) <= (map->offset + map->size)) + return map; + } + return NULL; +} + +static inline void * +agp_remap (unsigned long offset, unsigned long size, drm_device_t *dev) +{ + unsigned long *phys_addr_map, i, num_pages = PAGE_ALIGN(size) / PAGE_SIZE; + struct drm_agp_mem *agpmem; + struct page **page_map; + void *addr; + + size = PAGE_ALIGN(size); + +#ifdef __alpha__ + offset -= dev->hose->mem_space->start; +#endif + + for (agpmem = dev->agp->memory; agpmem; agpmem = agpmem->next) + if (agpmem->bound <= offset + && (agpmem->bound + (agpmem->pages << PAGE_SHIFT)) >= (offset + size)) + break; + if (!agpmem) + return NULL; + + /* + * OK, we're mapping AGP space on a chipset/platform on which memory accesses by + * the CPU do not get remapped by the GART. We fix this by using the kernel's + * page-table instead (that's probably faster anyhow...). + */ + /* note: use vmalloc() because num_pages could be large... */ + page_map = vmalloc(num_pages * sizeof(struct page *)); + if (!page_map) + return NULL; + + phys_addr_map = agpmem->memory->memory + (offset - agpmem->bound) / PAGE_SIZE; + for (i = 0; i < num_pages; ++i) + page_map[i] = pfn_to_page(phys_addr_map[i] >> PAGE_SHIFT); + addr = vmap(page_map, num_pages, VM_IOREMAP, PAGE_AGP); + vfree(page_map); + + return addr; +} + +static inline unsigned long +drm_follow_page (void *vaddr) +{ + pgd_t *pgd = pgd_offset_k((unsigned long) vaddr); + pmd_t *pmd = pmd_offset(pgd, (unsigned long) vaddr); + pte_t *ptep = pte_offset_kernel(pmd, (unsigned long) vaddr); + return pte_pfn(*ptep) << PAGE_SHIFT; +} + +#endif /* __OS_HAS_AGP && defined(VMAP_4_ARGS) */ + +static inline void *drm_ioremap(unsigned long offset, unsigned long size, drm_device_t *dev) +{ +#if __OS_HAS_AGP && defined(VMAP_4_ARGS) + if ( drm_core_check_feature(dev, DRIVER_USE_AGP) && dev->agp && dev->agp->cant_use_aperture) { + drm_map_t *map = drm_lookup_map(offset, size, dev); + + if (map && map->type == _DRM_AGP) + return agp_remap(offset, size, dev); + } +#endif + + return ioremap(offset, size); +} + +static inline void *drm_ioremap_nocache(unsigned long offset, unsigned long size, + drm_device_t *dev) +{ +#if __OS_HAS_AGP&& defined(VMAP_4_ARGS) + if ( drm_core_check_feature(dev, DRIVER_USE_AGP) && dev->agp && dev->agp->cant_use_aperture) { + drm_map_t *map = drm_lookup_map(offset, size, dev); + + if (map && map->type == _DRM_AGP) + return agp_remap(offset, size, dev); + } +#endif + + return ioremap_nocache(offset, size); +} + +static inline void drm_ioremapfree(void *pt, unsigned long size, drm_device_t *dev) +{ +#if __OS_HAS_AGP && defined(VMAP_4_ARGS) + /* + * This is a bit ugly. It would be much cleaner if the DRM API would use separate + * routines for handling mappings in the AGP space. Hopefully this can be done in + * a future revision of the interface... + */ + if (drm_core_check_feature(dev, DRIVER_USE_AGP) && dev->agp && dev->agp->cant_use_aperture + && ((unsigned long) pt >= VMALLOC_START && (unsigned long) pt < VMALLOC_END)) + { + unsigned long offset; + drm_map_t *map; + + offset = drm_follow_page(pt) | ((unsigned long) pt & ~PAGE_MASK); + map = drm_lookup_map(offset, size, dev); + if (map && map->type == _DRM_AGP) { + vunmap(pt); + return; + } + } +#endif + + iounmap(pt); +} + +#endif diff --git a/linux/drm_dma.c b/linux/drm_dma.c new file mode 100644 index 00000000..59a9b281 --- /dev/null +++ b/linux/drm_dma.c @@ -0,0 +1,183 @@ +/** + * \file drm_dma.h + * DMA IOCTL and function support + * + * \author Rickard E. (Rik) Faith <faith@valinux.com> + * \author Gareth Hughes <gareth@valinux.com> + */ + +/* + * Created: Fri Mar 19 14:30:16 1999 by faith@valinux.com + * + * Copyright 1999, 2000 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. + */ + +#include "drm_headers.h" + + +/** + * Initialize the DMA data. + * + * \param dev DRM device. + * \return zero on success or a negative value on failure. + * + * Allocate and initialize a drm_device_dma structure. + */ +int drm_core_dma_setup( drm_device_t *dev ) +{ + int i; + + dev->dma = drm_core_alloc( sizeof(*dev->dma), DRM_MEM_DRIVER ); + if ( !dev->dma ) + return -ENOMEM; + + memset( dev->dma, 0, sizeof(*dev->dma) ); + + for ( i = 0 ; i <= DRM_MAX_ORDER ; i++ ) + memset(&dev->dma->bufs[i], 0, sizeof(dev->dma->bufs[0])); + + return 0; +} + +/** + * Cleanup the DMA resources. + * + * \param dev DRM device. + * + * Free all pages associated with DMA buffers, the buffers and pages lists, and + * finally the the drm_device::dma structure itself. + */ +void drm_core_dma_takedown(drm_device_t *dev) +{ + drm_device_dma_t *dma = dev->dma; + int i, j; + + if (!dma) return; + + /* Clear dma buffers */ + for (i = 0; i <= DRM_MAX_ORDER; i++) { + if (dma->bufs[i].seg_count) { + DRM_DEBUG("order %d: buf_count = %d," + " seg_count = %d\n", + i, + dma->bufs[i].buf_count, + dma->bufs[i].seg_count); + for (j = 0; j < dma->bufs[i].seg_count; j++) { + if (dma->bufs[i].seglist[j]) { + drm_core_free_pages(dma->bufs[i].seglist[j], + dma->bufs[i].page_order, + DRM_MEM_DMA); + } + } + drm_core_free(dma->bufs[i].seglist, + dma->bufs[i].seg_count + * sizeof(*dma->bufs[0].seglist), + DRM_MEM_SEGS); + } + if (dma->bufs[i].buf_count) { + for (j = 0; j < dma->bufs[i].buf_count; j++) { + if (dma->bufs[i].buflist[j].dev_private) { + drm_core_free(dma->bufs[i].buflist[j].dev_private, + dma->bufs[i].buflist[j].dev_priv_size, + DRM_MEM_BUFS); + } + } + drm_core_free(dma->bufs[i].buflist, + dma->bufs[i].buf_count * + sizeof(*dma->bufs[0].buflist), + DRM_MEM_BUFS); + + } + } + + if (dma->buflist) { + drm_core_free(dma->buflist, + dma->buf_count * sizeof(*dma->buflist), + DRM_MEM_BUFS); + } + + if (dma->pagelist) { + drm_core_free(dma->pagelist, + dma->page_count * sizeof(*dma->pagelist), + DRM_MEM_PAGES); + } + drm_core_free(dev->dma, sizeof(*dev->dma), DRM_MEM_DRIVER); + dev->dma = NULL; +} + + +/** + * Free a buffer. + * + * \param dev DRM device. + * \param buf buffer to free. + * + * Resets the fields of \p buf. + */ +void drm_core_free_buffer(drm_device_t *dev, drm_buf_t *buf) +{ + if (!buf) return; + + buf->waiting = 0; + buf->pending = 0; + buf->filp = NULL; + buf->used = 0; + + if ( drm_core_check_feature(dev, DRIVER_DMA_QUEUE) && waitqueue_active(&buf->dma_wait)) { + wake_up_interruptible(&buf->dma_wait); + } +} + +/** + * Reclaim the buffers. + * + * \param filp file pointer. + * + * Frees each buffer associated with \p filp not already on the hardware. + */ +void drm_core_reclaim_buffers( struct file *filp ) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_device_dma_t *dma = dev->dma; + int i; + + if (!dma) return; + for (i = 0; i < dma->buf_count; i++) { + if (dma->buflist[i]->filp == filp) { + switch (dma->buflist[i]->list) { + case DRM_LIST_NONE: + drm_core_free_buffer(dev, dma->buflist[i]); + break; + case DRM_LIST_WAIT: + dma->buflist[i]->list = DRM_LIST_RECLAIM; + break; + default: + /* Buffer already on hardware. */ + break; + } + } + } +} + diff --git a/linux/drm_drv.h b/linux/drm_drv.h index 8f42e357..e8cf159b 100644 --- a/linux/drm_drv.h +++ b/linux/drm_drv.h @@ -126,8 +126,8 @@ drm_ioctl_desc_t DRM(ioctls)[] = { [DRM_IOCTL_NR(DRM_IOCTL_UNBLOCK)] = { DRM(noop), 1, 1 }, [DRM_IOCTL_NR(DRM_IOCTL_AUTH_MAGIC)] = { DRM(authmagic), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_ADD_MAP)] = { DRM(addmap), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_RM_MAP)] = { DRM(rmmap), 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_ADD_MAP)] = { drm_core_addmap, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_RM_MAP)] = { drm_core_rmmap, 1, 0 }, [DRM_IOCTL_NR(DRM_IOCTL_SET_SAREA_CTX)] = { DRM(setsareactx), 1, 1 }, [DRM_IOCTL_NR(DRM_IOCTL_GET_SAREA_CTX)] = { DRM(getsareactx), 1, 0 }, @@ -148,24 +148,24 @@ drm_ioctl_desc_t DRM(ioctls)[] = { [DRM_IOCTL_NR(DRM_IOCTL_FINISH)] = { DRM(noop), 1, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_ADD_BUFS)] = { DRM(addbufs), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_MARK_BUFS)] = { DRM(markbufs), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_INFO_BUFS)] = { DRM(infobufs), 1, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_MAP_BUFS)] = { DRM(mapbufs), 1, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_FREE_BUFS)] = { DRM(freebufs), 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_ADD_BUFS)] = { drm_core_addbufs, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_MARK_BUFS)] = { drm_core_markbufs, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_INFO_BUFS)] = { drm_core_infobufs, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_MAP_BUFS)] = { drm_core_mapbufs, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_FREE_BUFS)] = { drm_core_freebufs, 1, 0 }, /* The DRM_IOCTL_DMA ioctl should be defined by the driver. */ [DRM_IOCTL_NR(DRM_IOCTL_CONTROL)] = { DRM(control), 1, 1 }, #if __OS_HAS_AGP - [DRM_IOCTL_NR(DRM_IOCTL_AGP_ACQUIRE)] = { DRM(agp_acquire), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_AGP_RELEASE)] = { DRM(agp_release), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_AGP_ENABLE)] = { DRM(agp_enable), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_AGP_INFO)] = { DRM(agp_info), 1, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_AGP_ALLOC)] = { DRM(agp_alloc), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_AGP_FREE)] = { DRM(agp_free), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_AGP_BIND)] = { DRM(agp_bind), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_AGP_UNBIND)] = { DRM(agp_unbind), 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_ACQUIRE)] = { drm_memory_agp_acquire, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_RELEASE)] = { drm_memory_agp_release, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_ENABLE)] = { drm_memory_agp_enable, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_INFO)] = { drm_memory_agp_info, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_ALLOC)] = { drm_memory_agp_alloc, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_FREE)] = { drm_memory_agp_free, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_BIND)] = { drm_memory_agp_bind, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_UNBIND)] = { drm_memory_agp_unbind, 1, 1 }, #endif [DRM_IOCTL_NR(DRM_IOCTL_SG_ALLOC)] = { DRM(sg_alloc), 1, 1 }, @@ -201,7 +201,7 @@ static int DRM(setup)( drm_device_t *dev ) if (drm_core_check_feature(dev, DRIVER_HAVE_DMA)) { - i = DRM(dma_setup)( dev ); + i = drm_core_dma_setup( dev ); if ( i < 0 ) return i; } @@ -249,7 +249,7 @@ static int DRM(setup)( drm_device_t *dev ) dev->magiclist[i].tail = NULL; } - dev->ctxlist = DRM(alloc)(sizeof(*dev->ctxlist), + dev->ctxlist = drm_core_alloc(sizeof(*dev->ctxlist), DRM_MEM_CTXLIST); if(dev->ctxlist == NULL) return -ENOMEM; memset(dev->ctxlist, 0, sizeof(*dev->ctxlist)); @@ -327,13 +327,13 @@ static int DRM(takedown)( drm_device_t *dev ) del_timer( &dev->timer ); if ( dev->devname ) { - DRM(free)( dev->devname, strlen( dev->devname ) + 1, + drm_core_free( dev->devname, strlen( dev->devname ) + 1, DRM_MEM_DRIVER ); dev->devname = NULL; } if ( dev->unique ) { - DRM(free)( dev->unique, strlen( dev->unique ) + 1, + drm_core_free( dev->unique, strlen( dev->unique ) + 1, DRM_MEM_DRIVER ); dev->unique = NULL; dev->unique_len = 0; @@ -342,7 +342,7 @@ static int DRM(takedown)( drm_device_t *dev ) for ( i = 0 ; i < DRM_HASH_SIZE ; i++ ) { for ( pt = dev->magiclist[i].head ; pt ; pt = next ) { next = pt->next; - DRM(free)( pt, sizeof(*pt), DRM_MEM_MAGIC ); + drm_core_free( pt, sizeof(*pt), DRM_MEM_MAGIC ); } dev->magiclist[i].head = dev->magiclist[i].tail = NULL; } @@ -357,13 +357,13 @@ static int DRM(takedown)( drm_device_t *dev ) intact until drv_cleanup is called. */ for ( entry = dev->agp->memory ; entry ; entry = nexte ) { nexte = entry->next; - if ( entry->bound ) DRM(unbind_agp)( entry->memory ); - DRM(free_agp)( entry->memory, entry->pages ); - DRM(free)( entry, sizeof(*entry), DRM_MEM_AGPLISTS ); + if ( entry->bound ) drm_memory_unbind_agp( entry->memory ); + drm_memory_free_agp( entry->memory, entry->pages ); + drm_core_free( entry, sizeof(*entry), DRM_MEM_AGPLISTS ); } dev->agp->memory = NULL; - if ( dev->agp->acquired ) DRM(agp_do_release)(); + if ( dev->agp->acquired ) drm_memory_agp_do_release(); dev->agp->acquired = 0; dev->agp->enabled = 0; @@ -374,7 +374,7 @@ static int DRM(takedown)( drm_device_t *dev ) if ( dev->vmalist ) { for ( vma = dev->vmalist ; vma ; vma = vma_next ) { vma_next = vma->next; - DRM(free)( vma, sizeof(*vma), DRM_MEM_VMAS ); + drm_core_free( vma, sizeof(*vma), DRM_MEM_VMAS ); } dev->vmalist = NULL; } @@ -406,10 +406,10 @@ static int DRM(takedown)( drm_device_t *dev ) } break; } - DRM(free)(map, sizeof(*map), DRM_MEM_MAPS); + drm_core_free(map, sizeof(*map), DRM_MEM_MAPS); } list_del( list ); - DRM(free)(r_list, sizeof(*r_list), DRM_MEM_MAPS); + drm_core_free(r_list, sizeof(*r_list), DRM_MEM_MAPS); } } @@ -418,13 +418,13 @@ static int DRM(takedown)( drm_device_t *dev ) for ( i = 0 ; i < dev->queue_count ; i++ ) { if ( dev->queuelist[i] ) { - DRM(free)( dev->queuelist[i], + drm_core_free( dev->queuelist[i], sizeof(*dev->queuelist[0]), DRM_MEM_QUEUES ); dev->queuelist[i] = NULL; } } - DRM(free)( dev->queuelist, + drm_core_free( dev->queuelist, dev->queue_slots * sizeof(*dev->queuelist), DRM_MEM_QUEUES ); dev->queuelist = NULL; @@ -432,7 +432,7 @@ static int DRM(takedown)( drm_device_t *dev ) dev->queue_count = 0; if (drm_core_check_feature(dev, DRIVER_HAVE_DMA)) - DRM(dma_takedown)( dev ); + drm_core_dma_takedown( dev ); if ( dev->lock.hw_lock ) { dev->sigdata.lock = dev->lock.hw_lock = NULL; /* SHM removed */ @@ -447,7 +447,7 @@ static int DRM(takedown)( drm_device_t *dev ) static void DRM(init_fn_table)(struct drm_device *dev) { - dev->fn_tbl.reclaim_buffers = DRM(core_reclaim_buffers); + dev->fn_tbl.reclaim_buffers = drm_core_reclaim_buffers; dev->fn_tbl.get_map_ofs = DRM(core_get_map_ofs); dev->fn_tbl.get_reg_ofs = DRM(core_get_reg_ofs); } @@ -493,7 +493,7 @@ static int drm_probe(struct pci_dev *pdev, const struct pci_device_id *ent) dev->pci_func = PCI_FUNC(pdev->devfn); dev->irq = pdev->irq; - dev->maplist = DRM(alloc)(sizeof(*dev->maplist), DRM_MEM_MAPS); + dev->maplist = drm_core_alloc(sizeof(*dev->maplist), DRM_MEM_MAPS); if(dev->maplist == NULL) return -ENOMEM; memset(dev->maplist, 0, sizeof(*dev->maplist)); INIT_LIST_HEAD(&dev->maplist->head); @@ -511,7 +511,7 @@ static int drm_probe(struct pci_dev *pdev, const struct pci_device_id *ent) #if __OS_HAS_AGP if (drm_core_check_feature(dev, DRIVER_USE_AGP)) { - dev->agp = DRM(agp_init)(); + dev->agp = drm_memory_agp_init(); if ( drm_core_check_feature(dev, DRIVER_REQUIRE_AGP) && dev->agp == NULL ) { DRM_ERROR( "Cannot initialize the agpgart module.\n" ); retcode = -EINVAL; @@ -609,7 +609,7 @@ static int __init drm_init( void ) DRM(parse_options)( drm_opts ); #endif - DRM(mem_init)(); + drm_core_mem_init(); for (i=0; (DRM(pciidlist)[i].vendor != 0) && !DRM(fb_loaded); i++) { pid = &DRM(pciidlist[i]); @@ -676,7 +676,7 @@ static void __exit drm_cleanup( drm_device_t *dev ) if ( ( map = r_list->map ) ) { switch ( map->type ) { case _DRM_REGISTERS: - DRM(ioremapfree)( map->handle, map->size, dev ); + drm_core_ioremapfree( map, dev ); break; case _DRM_FRAME_BUFFER: @@ -699,12 +699,12 @@ static void __exit drm_cleanup( drm_device_t *dev ) DRM_DEBUG("Extra maplist item\n"); break; } - DRM(free)(map, sizeof(*map), DRM_MEM_MAPS); + drm_core_free(map, sizeof(*map), DRM_MEM_MAPS); } list_del( list ); - DRM(free)(r_list, sizeof(*r_list), DRM_MEM_MAPS); + drm_core_free(r_list, sizeof(*r_list), DRM_MEM_MAPS); } - DRM(free)(dev->maplist, sizeof(*dev->maplist), DRM_MEM_MAPS); + drm_core_free(dev->maplist, sizeof(*dev->maplist), DRM_MEM_MAPS); dev->maplist = NULL; } if (DRM(fb_loaded)==0) @@ -730,8 +730,8 @@ static void __exit drm_cleanup( drm_device_t *dev ) } #endif if ( drm_core_check_feature(dev, DRIVER_USE_AGP) && dev->agp ) { - DRM(agp_uninit)(); - DRM(free)( dev->agp, sizeof(*dev->agp), DRM_MEM_AGPLISTS ); + drm_memory_agp_uninit(); + drm_core_free( dev->agp, sizeof(*dev->agp), DRM_MEM_AGPLISTS ); dev->agp = NULL; } #endif @@ -956,7 +956,7 @@ int DRM(release)( struct inode *inode, struct file *filp ) DRM(ctxbitmap_free)( dev, pos->handle ); list_del( &pos->head ); - DRM(free)( pos, sizeof(*pos), DRM_MEM_CTXLIST ); + drm_core_free( pos, sizeof(*pos), DRM_MEM_CTXLIST ); --dev->ctx_count; } } @@ -985,7 +985,7 @@ int DRM(release)( struct inode *inode, struct file *filp ) if (dev->fn_tbl.free_filp_private) dev->fn_tbl.free_filp_private( dev, priv ); - DRM(free)( priv, sizeof(*priv), DRM_MEM_FILES ); + drm_core_free( priv, sizeof(*priv), DRM_MEM_FILES ); /* ======================================================== * End inline drm_release @@ -1129,29 +1129,28 @@ int DRM(lock)( struct inode *inode, struct file *filp, current->state = TASK_RUNNING; remove_wait_queue( &dev->lock.lock_queue, &entry ); - if ( !ret ) { - sigemptyset( &dev->sigmask ); - sigaddset( &dev->sigmask, SIGSTOP ); - sigaddset( &dev->sigmask, SIGTSTP ); - sigaddset( &dev->sigmask, SIGTTIN ); - sigaddset( &dev->sigmask, SIGTTOU ); - dev->sigdata.context = lock.context; - dev->sigdata.lock = dev->lock.hw_lock; - block_all_signals( DRM(notifier), - &dev->sigdata, &dev->sigmask ); - - if (dev->fn_tbl.dma_ready && (lock.flags & _DRM_LOCK_READY)) - dev->fn_tbl.dma_ready(dev); - - if ( dev->fn_tbl.dma_quiescent && (lock.flags & _DRM_LOCK_QUIESCENT )) - return dev->fn_tbl.dma_quiescent(dev); - - - if ( dev->fn_tbl.kernel_context_switch && dev->last_context != lock.context ) { - dev->fn_tbl.kernel_context_switch(dev, dev->last_context, - lock.context); - } - } + sigemptyset( &dev->sigmask ); + sigaddset( &dev->sigmask, SIGSTOP ); + sigaddset( &dev->sigmask, SIGTSTP ); + sigaddset( &dev->sigmask, SIGTTIN ); + sigaddset( &dev->sigmask, SIGTTOU ); + dev->sigdata.context = lock.context; + dev->sigdata.lock = dev->lock.hw_lock; + block_all_signals( DRM(notifier), + &dev->sigdata, &dev->sigmask ); + + if (dev->fn_tbl.dma_ready && (lock.flags & _DRM_LOCK_READY)) + dev->fn_tbl.dma_ready(dev); + + if ( dev->fn_tbl.dma_quiescent && (lock.flags & _DRM_LOCK_QUIESCENT )) + return dev->fn_tbl.dma_quiescent(dev); + + + if ( dev->fn_tbl.kernel_context_switch && dev->last_context != lock.context ) { + dev->fn_tbl.kernel_context_switch(dev, dev->last_context, + lock.context); + } + DRM_DEBUG( "%d %s\n", lock.context, ret ? "interrupted" : "has lock" ); diff --git a/linux/drm_fops.h b/linux/drm_fops.h index 21935b7a..32c6177c 100644 --- a/linux/drm_fops.h +++ b/linux/drm_fops.h @@ -60,7 +60,7 @@ int DRM(open_helper)(struct inode *inode, struct file *filp, drm_device_t *dev) DRM_DEBUG("pid = %d, minor = %d\n", current->pid, minor); - priv = DRM(alloc)(sizeof(*priv), DRM_MEM_FILES); + priv = drm_core_alloc(sizeof(*priv), DRM_MEM_FILES); if(!priv) return -ENOMEM; memset(priv, 0, sizeof(*priv)); @@ -111,7 +111,7 @@ int DRM(open_helper)(struct inode *inode, struct file *filp, drm_device_t *dev) return 0; out_free: - DRM(free)(priv, sizeof(*priv), DRM_MEM_FILES); + drm_core_free(priv, sizeof(*priv), DRM_MEM_FILES); return ret; } diff --git a/linux/drm_headers.h b/linux/drm_headers.h new file mode 100644 index 00000000..13d2b41e --- /dev/null +++ b/linux/drm_headers.h @@ -0,0 +1,52 @@ + +#ifdef __alpha__ +/* add include of current.h so that "current" is defined + * before static inline funcs in wait.h. Doing this so we + * can build the DRM (part of PI DRI). 4/21/2000 S + B */ +#include <asm/current.h> +#endif /* __alpha__ */ +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/miscdevice.h> +#include <linux/fs.h> +#include <linux/proc_fs.h> +#include <linux/init.h> +#include <linux/file.h> +#include <linux/pci.h> +#include <linux/version.h> +#include <linux/sched.h> +#include <linux/smp_lock.h> /* For (un)lock_kernel */ +#include <linux/mm.h> +#include <linux/pagemap.h> +#if defined(__alpha__) || defined(__powerpc__) +#include <asm/pgtable.h> /* For pte_wrprotect */ +#endif +#include <asm/io.h> +#include <asm/mman.h> +#include <asm/uaccess.h> +#ifdef CONFIG_MTRR +#include <asm/mtrr.h> +#endif +#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE) +#include <linux/types.h> +#include <linux/agp_backend.h> +#endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,41) +#define HAS_WORKQUEUE 0 +#else +#define HAS_WORKQUEUE 1 +#endif +#if !HAS_WORKQUEUE +#include <linux/tqueue.h> +#else +#include <linux/workqueue.h> +#endif +#include <linux/poll.h> +#include <asm/pgalloc.h> +#include "drm.h" + +#include "drm_os_linux.h" + +#include "drm_core.h" +#include "drm_core_memory.h" diff --git a/linux/drm_ioctl.h b/linux/drm_ioctl.h index c3725668..4e5055ef 100644 --- a/linux/drm_ioctl.h +++ b/linux/drm_ioctl.h @@ -98,14 +98,14 @@ int DRM(setunique)(struct inode *inode, struct file *filp, if (!u.unique_len || u.unique_len > 1024) return -EINVAL; dev->unique_len = u.unique_len; - dev->unique = DRM(alloc)(u.unique_len + 1, DRM_MEM_DRIVER); + dev->unique = drm_core_alloc(u.unique_len + 1, DRM_MEM_DRIVER); if(!dev->unique) return -ENOMEM; if (copy_from_user(dev->unique, u.unique, dev->unique_len)) return -EFAULT; dev->unique[dev->unique_len] = '\0'; - dev->devname = DRM(alloc)(strlen(dev->name) + strlen(dev->unique) + 2, + dev->devname = drm_core_alloc(strlen(dev->name) + strlen(dev->unique) + 2, DRM_MEM_DRIVER); if (!dev->devname) return -ENOMEM; @@ -137,14 +137,14 @@ DRM(set_busid)(drm_device_t *dev) return EBUSY; dev->unique_len = 20; - dev->unique = DRM(alloc)(dev->unique_len + 1, DRM_MEM_DRIVER); + dev->unique = drm_core_alloc(dev->unique_len + 1, DRM_MEM_DRIVER); if (dev->unique == NULL) return ENOMEM; snprintf(dev->unique, dev->unique_len, "pci:%04x:%02x:%02x.%d", dev->pci_domain, dev->pci_bus, dev->pci_slot, dev->pci_func); - dev->devname = DRM(alloc)(strlen(dev->name) + dev->unique_len + 2, + dev->devname = drm_core_alloc(strlen(dev->name) + dev->unique_len + 2, DRM_MEM_DRIVER); if (dev->devname == NULL) return ENOMEM; diff --git a/linux/drm_irq.h b/linux/drm_irq.h index a1622c0e..a88edf98 100644 --- a/linux/drm_irq.h +++ b/linux/drm_irq.h @@ -304,7 +304,7 @@ int DRM(wait_vblank)( DRM_IOCTL_ARGS ) spin_unlock_irqrestore( &dev->vbl_lock, irqflags ); - if ( !( vbl_sig = DRM(alloc)( sizeof( drm_vbl_sig_t ), DRM_MEM_DRIVER ) ) ) { + if ( !( vbl_sig = drm_core_alloc( sizeof( drm_vbl_sig_t ), DRM_MEM_DRIVER ) ) ) { return -ENOMEM; } @@ -360,7 +360,7 @@ void DRM(vbl_send_signals)( drm_device_t *dev ) list_del( list ); - DRM(free)( vbl_sig, sizeof(*vbl_sig), DRM_MEM_DRIVER ); + drm_core_free( vbl_sig, sizeof(*vbl_sig), DRM_MEM_DRIVER ); dev->vbl_pending--; } diff --git a/linux/drm_memory.c b/linux/drm_memory.c new file mode 100644 index 00000000..76c14865 --- /dev/null +++ b/linux/drm_memory.c @@ -0,0 +1,203 @@ +/** + * \file drm_memory.h + * Memory management wrappers for DRM + * + * \author Rickard E. (Rik) Faith <faith@valinux.com> + * \author Gareth Hughes <gareth@valinux.com> + */ + +/* + * Created: Thu Feb 4 14:00:34 1999 by faith@valinux.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. + */ + +#include "drm_headers.h" + +/** + * Cut down version of drm_memory_debug.h, which used to be called + * drm_memory.h. + */ + +/* Need the 4-argument version of vmap(). */ +#if __OS_HAS_AGP && defined(VMAP_4_ARGS) + +#include <linux/vmalloc.h> + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) +#ifndef pte_offset_kernel +# define pte_offset_kernel(dir, address) pte_offset(dir, address) +#endif +#ifndef pte_pfn +# define pte_pfn(pte) (pte_page(pte) - mem_map) +#endif +#ifndef pfn_to_page +# define pfn_to_page(pfn) (mem_map + (pfn)) +#endif +#endif + + + + +#ifdef DEBUG_MEMORY +#include "drm_memory_debug.h" +#else + +/** No-op. */ +void drm_memory_mem_init(void) +{ +} + +/** + * Called when "/proc/dri/%dev%/mem" is read. + * + * \param buf output buffer. + * \param start start of output data. + * \param offset requested start offset. + * \param len requested number of bytes. + * \param eof whether there is no more data to return. + * \param data private data. + * \return number of written bytes. + * + * No-op. + */ +int drm_memory_mem_info(char *buf, char **start, off_t offset, + int len, int *eof, void *data) +{ + return 0; +} + +/** Wrapper around kmalloc() */ +void *drm_memory_calloc(size_t nmemb, size_t size, int area) +{ + void *addr; + + addr = kmalloc(size * nmemb, GFP_KERNEL); + if (addr != NULL) + memset((void *)addr, 0, size * nmemb); + + return addr; +} + +/** Wrapper around kmalloc() and kfree() */ +void *drm_memory_realloc(void *oldpt, size_t oldsize, size_t size, int area) +{ + void *pt; + + if (!(pt = kmalloc(size, GFP_KERNEL))) return NULL; + if (oldpt && oldsize) { + memcpy(pt, oldpt, oldsize); + kfree(oldpt); + } + return pt; +} + +/** + * Allocate pages. + * + * \param order size order. + * \param area memory area. (Not used.) + * \return page address on success, or zero on failure. + * + * Allocate and reserve free pages. + */ +unsigned long drm_memory_alloc_pages(int order, int area) +{ + unsigned long address; + unsigned long bytes = PAGE_SIZE << order; + unsigned long addr; + unsigned int sz; + + address = __get_free_pages(GFP_KERNEL, order); + if (!address) + return 0; + + /* Zero */ + memset((void *)address, 0, bytes); + + /* Reserve */ + for (addr = address, sz = bytes; + sz > 0; + addr += PAGE_SIZE, sz -= PAGE_SIZE) { + SetPageReserved(virt_to_page(addr)); + } + + return address; +} + +/** + * Free pages. + * + * \param address address of the pages to free. + * \param order size order. + * \param area memory area. (Not used.) + * + * Unreserve and free pages allocated by alloc_pages(). + */ +void drm_memory_free_pages(unsigned long address, int order, int area) +{ + unsigned long bytes = PAGE_SIZE << order; + unsigned long addr; + unsigned int sz; + + if (!address) + return; + + /* Unreserve */ + for (addr = address, sz = bytes; + sz > 0; + addr += PAGE_SIZE, sz -= PAGE_SIZE) { + ClearPageReserved(virt_to_page(addr)); + } + + free_pages(address, order); +} + +#if __OS_HAS_AGP +/** Wrapper around agp_allocate_memory() */ +DRM_AGP_MEM *drm_memory_alloc_agp(int pages, u32 type) +{ + return drm_memory_agp_allocate_memory (pages, type); +} + +/** Wrapper around agp_free_memory() */ +int drm_memory_free_agp(DRM_AGP_MEM *handle, int pages) +{ + return drm_memory_agp_free_memory(handle) ? 0 : -EINVAL; +} + +/** Wrapper around agp_bind_memory() */ +int drm_memory_bind_agp(DRM_AGP_MEM *handle, unsigned int start) +{ + return drm_memory_agp_bind_memory(handle, start); +} + +/** Wrapper around agp_unbind_memory() */ +int drm_memory_unbind_agp(DRM_AGP_MEM *handle) +{ + return drm_memory_agp_unbind_memory(handle); +} +#endif /* agp */ +#endif /* debug_memory */ +#endif diff --git a/linux/drm_memory_debug.c b/linux/drm_memory_debug.c new file mode 100644 index 00000000..a15a304d --- /dev/null +++ b/linux/drm_memory_debug.c @@ -0,0 +1,463 @@ +/** + * \file drm_memory.h + * Memory management wrappers for DRM. + * + * \author Rickard E. (Rik) Faith <faith@valinux.com> + * \author Gareth Hughes <gareth@valinux.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. + */ + +#include "drm_headers.h" + +#define DRM_MEM_ERROR(area, fmt, arg...) \ + printk(KERN_ERR "[" DRM_NAME ":%s:%s] *ERROR* " fmt , __FUNCTION__, \ + drm_memory_debug_mem_stats[area].name , ##arg) + + +typedef struct drm_mem_stats { + const char *name; + int succeed_count; + int free_count; + int fail_count; + unsigned long bytes_allocated; + unsigned long bytes_freed; +} drm_mem_stats_t; + +static spinlock_t drm_memory_debug_mem_lock = SPIN_LOCK_UNLOCKED; +static unsigned long drm_memory_debug_ram_available = 0; /* In pages */ +static unsigned long drm_memory_debug_ram_used = 0; +static drm_mem_stats_t drm_memory_debug_mem_stats[] = { + [DRM_MEM_DMA] = { "dmabufs" }, + [DRM_MEM_SAREA] = { "sareas" }, + [DRM_MEM_DRIVER] = { "driver" }, + [DRM_MEM_MAGIC] = { "magic" }, + [DRM_MEM_IOCTLS] = { "ioctltab" }, + [DRM_MEM_MAPS] = { "maplist" }, + [DRM_MEM_VMAS] = { "vmalist" }, + [DRM_MEM_BUFS] = { "buflist" }, + [DRM_MEM_SEGS] = { "seglist" }, + [DRM_MEM_PAGES] = { "pagelist" }, + [DRM_MEM_FILES] = { "files" }, + [DRM_MEM_QUEUES] = { "queues" }, + [DRM_MEM_CMDS] = { "commands" }, + [DRM_MEM_MAPPINGS] = { "mappings" }, + [DRM_MEM_BUFLISTS] = { "buflists" }, + [DRM_MEM_AGPLISTS] = { "agplist" }, + [DRM_MEM_SGLISTS] = { "sglist" }, + [DRM_MEM_TOTALAGP] = { "totalagp" }, + [DRM_MEM_BOUNDAGP] = { "boundagp" }, + [DRM_MEM_CTXBITMAP] = { "ctxbitmap"}, + [DRM_MEM_CTXLIST] = { "ctxlist" }, + [DRM_MEM_STUB] = { "stub" }, + { NULL, 0, } /* Last entry must be null */ +}; + +void drm_memory_debug_mem_init(void) +{ + drm_mem_stats_t *mem; + struct sysinfo si; + + for (mem = drm_memory_debug_mem_stats; mem->name; ++mem) { + mem->succeed_count = 0; + mem->free_count = 0; + mem->fail_count = 0; + mem->bytes_allocated = 0; + mem->bytes_freed = 0; + } + + si_meminfo(&si); + drm_memory_debug_ram_available = si.totalram; + drm_memory_debug_ram_used = 0; +} + +/* drm_mem_info is called whenever a process reads /dev/drm/mem. */ + +static int drm_memory_debug__mem_info(char *buf, char **start, off_t offset, + int request, int *eof, void *data) +{ + drm_mem_stats_t *pt; + int len = 0; + + if (offset > DRM_PROC_LIMIT) { + *eof = 1; + return 0; + } + + *eof = 0; + *start = &buf[offset]; + + DRM_PROC_PRINT(" total counts " + " | outstanding \n"); + DRM_PROC_PRINT("type alloc freed fail bytes freed" + " | allocs bytes\n\n"); + DRM_PROC_PRINT("%-9.9s %5d %5d %4d %10lu kB |\n", + "system", 0, 0, 0, + drm_memory_debug_ram_available << (PAGE_SHIFT - 10)); + DRM_PROC_PRINT("%-9.9s %5d %5d %4d %10lu kB |\n", + "locked", 0, 0, 0, drm_memory_debug_ram_used >> 10); + DRM_PROC_PRINT("\n"); + for (pt = drm_memory_debug_mem_stats; pt->name; pt++) { + DRM_PROC_PRINT("%-9.9s %5d %5d %4d %10lu %10lu | %6d %10ld\n", + pt->name, + pt->succeed_count, + pt->free_count, + pt->fail_count, + pt->bytes_allocated, + pt->bytes_freed, + pt->succeed_count - pt->free_count, + (long)pt->bytes_allocated + - (long)pt->bytes_freed); + } + + if (len > request + offset) return request; + *eof = 1; + return len - offset; +} + +int drm_memory_debug_mem_info(char *buf, char **start, off_t offset, + int len, int *eof, void *data) +{ + int ret; + + spin_lock(&drm_memory_debug_mem_lock); + ret = drm_memory_debug__mem_info(buf, start, offset, len, eof, data); + spin_unlock(&drm_memory_debug_mem_lock); + return ret; +} + +void *drm_memory_debug_alloc(size_t size, int area) +{ + void *pt; + + if (!size) { + DRM_MEM_ERROR(area, "Allocating 0 bytes\n"); + return NULL; + } + + if (!(pt = kmalloc(size, GFP_KERNEL))) { + spin_lock(&drm_memory_debug_mem_lock); + ++drm_memory_debug_mem_stats[area].fail_count; + spin_unlock(&drm_memory_debug_mem_lock); + return NULL; + } + spin_lock(&drm_memory_debug_mem_lock); + ++drm_memory_debug_mem_stats[area].succeed_count; + drm_memory_debug_mem_stats[area].bytes_allocated += size; + spin_unlock(&drm_memory_debug_mem_lock); + return pt; +} + +void *drm_memory_debug_calloc(size_t nmemb, size_t size, int area) +{ + void *addr; + + addr = drm_memory_debug_alloc(nmemb * size, area); + if (addr != NULL) + memset((void *)addr, 0, size * nmemb); + + return addr; +} + +void *drm_memory_debug_realloc(void *oldpt, size_t oldsize, size_t size, int area) +{ + void *pt; + + if (!(pt = drm_memory_debug_alloc(size, area))) return NULL; + if (oldpt && oldsize) { + memcpy(pt, oldpt, oldsize); + drm_memory_debug_free(oldpt, oldsize, area); + } + return pt; +} + +void drm_memory_debug_free(void *pt, size_t size, int area) +{ + int alloc_count; + int free_count; + + if (!pt) DRM_MEM_ERROR(area, "Attempt to free NULL pointer\n"); + else kfree(pt); + spin_lock(&drm_memory_debug_mem_lock); + drm_memory_debug_mem_stats[area].bytes_freed += size; + free_count = ++drm_memory_debug_mem_stats[area].free_count; + alloc_count = drm_memory_debug_mem_stats[area].succeed_count; + spin_unlock(&drm_memory_debug_mem_lock); + if (free_count > alloc_count) { + DRM_MEM_ERROR(area, "Excess frees: %d frees, %d allocs\n", + free_count, alloc_count); + } +} + +unsigned long drm_debug_alloc_pages(int order, int area) +{ + unsigned long address; + unsigned long bytes = PAGE_SIZE << order; + unsigned long addr; + unsigned int sz; + + spin_lock(&drm_memory_debug_mem_lock); + if ((drm_memory_debug_ram_used >> PAGE_SHIFT) + > (DRM_RAM_PERCENT * drm_memory_debug_ram_available) / 100) { + spin_unlock(&drm_memory_debug_mem_lock); + return 0; + } + spin_unlock(&drm_memory_debug_mem_lock); + + address = __get_free_pages(GFP_KERNEL, order); + if (!address) { + spin_lock(&drm_memory_debug_mem_lock); + ++drm_memory_debug_mem_stats[area].fail_count; + spin_unlock(&drm_memory_debug_mem_lock); + return 0; + } + spin_lock(&drm_memory_debug_mem_lock); + ++drm_memory_debug_mem_stats[area].succeed_count; + drm_memory_debug_mem_stats[area].bytes_allocated += bytes; + drm_memory_debug_ram_used += bytes; + spin_unlock(&drm_memory_debug_mem_lock); + + + /* Zero outside the lock */ + memset((void *)address, 0, bytes); + + /* Reserve */ + for (addr = address, sz = bytes; + sz > 0; + addr += PAGE_SIZE, sz -= PAGE_SIZE) { + SetPageReserved(virt_to_page(addr)); + } + + return address; +} + +void drm_memory_debug_free_pages(unsigned long address, int order, int area) +{ + unsigned long bytes = PAGE_SIZE << order; + int alloc_count; + int free_count; + unsigned long addr; + unsigned int sz; + + if (!address) { + DRM_MEM_ERROR(area, "Attempt to free address 0\n"); + } else { + /* Unreserve */ + for (addr = address, sz = bytes; + sz > 0; + addr += PAGE_SIZE, sz -= PAGE_SIZE) { + ClearPageReserved(virt_to_page(addr)); + } + free_pages(address, order); + } + + spin_lock(&drm_memory_debug_mem_lock); + free_count = ++drm_memory_debug_mem_stats[area].free_count; + alloc_count = drm_memory_debug_mem_stats[area].succeed_count; + drm_memory_debug_mem_stats[area].bytes_freed += bytes; + drm_memory_debug_ram_used -= bytes; + spin_unlock(&drm_memory_debug_mem_lock); + if (free_count > alloc_count) { + DRM_MEM_ERROR(area, + "Excess frees: %d frees, %d allocs\n", + free_count, alloc_count); + } +} + +void *drm_memory_debug_ioremap(unsigned long offset, unsigned long size, drm_device_t *dev) +{ + void *pt; + + if (!size) { + DRM_MEM_ERROR(DRM_MEM_MAPPINGS, + "Mapping 0 bytes at 0x%08lx\n", offset); + return NULL; + } + + if (!(pt = drm_ioremap(offset, size, dev))) { + spin_lock(&drm_memory_debug_mem_lock); + ++drm_memory_debug_mem_stats[DRM_MEM_MAPPINGS].fail_count; + spin_unlock(&drm_memory_debug_mem_lock); + return NULL; + } + spin_lock(&drm_memory_debug_mem_lock); + ++drm_memory_debug_mem_stats[DRM_MEM_MAPPINGS].succeed_count; + drm_memory_debug_mem_stats[DRM_MEM_MAPPINGS].bytes_allocated += size; + spin_unlock(&drm_memory_debug_mem_lock); + return pt; +} + +void *drm_memory_ioremap_nocache(unsigned long offset, unsigned long size, drm_device_t *dev) +{ + void *pt; + + if (!size) { + DRM_MEM_ERROR(DRM_MEM_MAPPINGS, + "Mapping 0 bytes at 0x%08lx\n", offset); + return NULL; + } + + if (!(pt = drm_ioremap_nocache(offset, size, dev))) { + spin_lock(&drm_memory_debug_mem_lock); + ++drm_memory_debug_mem_stats[DRM_MEM_MAPPINGS].fail_count; + spin_unlock(&drm_memory_debug_mem_lock); + return NULL; + } + spin_lock(&drm_memory_debug_mem_lock); + ++drm_memory_debug_mem_stats[DRM_MEM_MAPPINGS].succeed_count; + drm_memory_debug_mem_stats[DRM_MEM_MAPPINGS].bytes_allocated += size; + spin_unlock(&drm_memory_debug_mem_lock); + return pt; +} + +void drm_memory_debug_ioremapfree(void *pt, unsigned long size, drm_device_t *dev) +{ + int alloc_count; + int free_count; + + if (!pt) + DRM_MEM_ERROR(DRM_MEM_MAPPINGS, + "Attempt to free NULL pointer\n"); + else + drm_ioremapfree(pt, size, dev); + + spin_lock(&drm_memory_debug_mem_lock); + drm_memory_debug_mem_stats[DRM_MEM_MAPPINGS].bytes_freed += size; + free_count = ++drm_memory_debug_mem_stats[DRM_MEM_MAPPINGS].free_count; + alloc_count = drm_memory_debug_mem_stats[DRM_MEM_MAPPINGS].succeed_count; + spin_unlock(&drm_memory_debug_mem_lock); + if (free_count > alloc_count) { + DRM_MEM_ERROR(DRM_MEM_MAPPINGS, + "Excess frees: %d frees, %d allocs\n", + free_count, alloc_count); + } +} + +#if __OS_HAS_AGP + +DRM_AGP_MEM *drm_memory_debug_alloc_agp(int pages, u32 type) +{ + DRM_AGP_MEM *handle; + + if (!pages) { + DRM_MEM_ERROR(DRM_MEM_TOTALAGP, "Allocating 0 pages\n"); + return NULL; + } + + if ((handle = drm_memory_agp_allocate_memory(pages, type))) { + spin_lock(&drm_memory_debug_mem_lock); + ++drm_memory_debug_mem_stats[DRM_MEM_TOTALAGP].succeed_count; + drm_memory_debug_mem_stats[DRM_MEM_TOTALAGP].bytes_allocated + += pages << PAGE_SHIFT; + spin_unlock(&drm_memory_debug_mem_lock); + return handle; + } + spin_lock(&drm_memory_debug_mem_lock); + ++drm_memory_debug_mem_stats[DRM_MEM_TOTALAGP].fail_count; + spin_unlock(&drm_memory_debug_mem_lock); + return NULL; +} + +int drm_memory_debug_free_agp(DRM_AGP_MEM *handle, int pages) +{ + int alloc_count; + int free_count; + int retval = -EINVAL; + + if (!handle) { + DRM_MEM_ERROR(DRM_MEM_TOTALAGP, + "Attempt to free NULL AGP handle\n"); + return retval; + } + + if (drm_memory_agp_free_memory(handle)) { + spin_lock(&drm_memory_debug_mem_lock); + free_count = ++drm_memory_debug_mem_stats[DRM_MEM_TOTALAGP].free_count; + alloc_count = drm_memory_debug_mem_stats[DRM_MEM_TOTALAGP].succeed_count; + drm_memory_debug_mem_stats[DRM_MEM_TOTALAGP].bytes_freed + += pages << PAGE_SHIFT; + spin_unlock(&drm_memory_debug_mem_lock); + if (free_count > alloc_count) { + DRM_MEM_ERROR(DRM_MEM_TOTALAGP, + "Excess frees: %d frees, %d allocs\n", + free_count, alloc_count); + } + return 0; + } + return retval; +} + +int drm_memory_debug_bind_agp(DRM_AGP_MEM *handle, unsigned int start) +{ + int retcode = -EINVAL; + + if (!handle) { + DRM_MEM_ERROR(DRM_MEM_BOUNDAGP, + "Attempt to bind NULL AGP handle\n"); + return retcode; + } + + if (!(retcode = drm_memory_agp_bind_memory(handle, start))) { + spin_lock(&drm_memory_debug_mem_lock); + ++drm_memory_debug_mem_stats[DRM_MEM_BOUNDAGP].succeed_count; + drm_memory_debug_mem_stats[DRM_MEM_BOUNDAGP].bytes_allocated + += handle->page_count << PAGE_SHIFT; + spin_unlock(&drm_memory_debug_mem_lock); + return retcode; + } + spin_lock(&drm_memory_debug_mem_lock); + ++drm_memory_debug_mem_stats[DRM_MEM_BOUNDAGP].fail_count; + spin_unlock(&drm_memory_debug_mem_lock); + return retcode; +} + +int drm_memory_debug_unbind_agp(DRM_AGP_MEM *handle) +{ + int alloc_count; + int free_count; + int retcode = -EINVAL; + + if (!handle) { + DRM_MEM_ERROR(DRM_MEM_BOUNDAGP, + "Attempt to unbind NULL AGP handle\n"); + return retcode; + } + + if ((retcode = drm_memory_agp_unbind_memory(handle))) return retcode; + spin_lock(&drm_memory_debug_mem_lock); + free_count = ++drm_memory_debug_mem_stats[DRM_MEM_BOUNDAGP].free_count; + alloc_count = drm_memory_debug_mem_stats[DRM_MEM_BOUNDAGP].succeed_count; + drm_memory_debug_mem_stats[DRM_MEM_BOUNDAGP].bytes_freed + += handle->page_count << PAGE_SHIFT; + spin_unlock(&drm_memory_debug_mem_lock); + if (free_count > alloc_count) { + DRM_MEM_ERROR(DRM_MEM_BOUNDAGP, + "Excess frees: %d frees, %d allocs\n", + free_count, alloc_count); + } + return retcode; +} +#endif diff --git a/linux/drm_proc.c b/linux/drm_proc.c new file mode 100644 index 00000000..9390f079 --- /dev/null +++ b/linux/drm_proc.c @@ -0,0 +1,541 @@ +/** + * \file drm_proc.h + * /proc support for DRM + * + * \author Rickard E. (Rik) Faith <faith@valinux.com> + * \author Gareth Hughes <gareth@valinux.com> + * + * \par Acknowledgements: + * Matthew J Sottek <matthew.j.sottek@intel.com> sent in a patch to fix + * the problem with the proc files not outputting all their information. + */ + +/* + * Created: Mon Jan 11 09:48:47 1999 by faith@valinux.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. + */ + +#include "drm_headers.h" + +extern int drm_memory_mem_info(char *buf, char **start, off_t offset, + int len, int *eof, void *data); + +static int drm_proc_name_info(char *buf, char **start, off_t offset, + int request, int *eof, void *data); +static int drm_proc_vm_info(char *buf, char **start, off_t offset, + int request, int *eof, void *data); +static int drm_proc_clients_info(char *buf, char **start, off_t offset, + int request, int *eof, void *data); +static int drm_proc_queues_info(char *buf, char **start, off_t offset, + int request, int *eof, void *data); +static int drm_proc_bufs_info(char *buf, char **start, off_t offset, + int request, int *eof, void *data); +#if DRM_DEBUG_CODE +static int drm_proc_vma_info(char *buf, char **start, off_t offset, + int request, int *eof, void *data); +#endif + +/** + * Proc file list. + */ +struct drm_proc_list { + const char *name; /**< file name */ + int (*f)(char *, char **, off_t, int, int *, void *); /**< proc callback*/ +} drm_proc_list[] = { + { "name", drm_proc_name_info }, + { "mem", drm_memory_mem_info }, + { "vm", drm_proc_vm_info }, + { "clients", drm_proc_clients_info }, + { "queues", drm_proc_queues_info }, + { "bufs", drm_proc_bufs_info }, +#if DRM_DEBUG_CODE + { "vma", drm_proc_vma_info }, +#endif +}; +#define DRM_PROC_ENTRIES (sizeof(drm_proc_list)/sizeof(drm_proc_list[0])) + +/** + * Initialize the DRI proc filesystem for a device. + * + * \param dev DRM device. + * \param minor device minor number. + * \param root DRI proc dir entry. + * \param dev_root resulting DRI device proc dir entry. + * \return root entry pointer on success, or NULL on failure. + * + * Create the DRI proc root entry "/proc/dri", the device proc root entry + * "/proc/dri/%minor%/", and each entry in proc_list as + * "/proc/dri/%minor%/%name%". + */ +int drm_proc_init(drm_device_t *dev, int minor, + struct proc_dir_entry *root, + struct proc_dir_entry **dev_root) +{ + struct proc_dir_entry *ent; + int i, j; + char name[64]; + + sprintf(name, "%d", minor); + *dev_root = create_proc_entry(name, S_IFDIR, root); + if (!*dev_root) { + DRM_ERROR("Cannot create /proc/dri/%s\n", name); + return -1; + } + + for (i = 0; i < DRM_PROC_ENTRIES; i++) { + ent = create_proc_entry(drm_proc_list[i].name, + S_IFREG|S_IRUGO, *dev_root); + if (!ent) { + DRM_ERROR("Cannot create /proc/dri/%s/%s\n", + name, drm_proc_list[i].name); + for (j = 0; j < i; j++) + remove_proc_entry(drm_proc_list[i].name, + *dev_root); + remove_proc_entry(name, root); + return -1; + } + ent->read_proc = drm_proc_list[i].f; + ent->data = dev; + } + return 0; +} + + +/** + * Cleanup the proc filesystem resources. + * + * \param minor device minor number. + * \param root DRI proc dir entry. + * \param dev_root DRI device proc dir entry. + * \return always zero. + * + * Remove all proc entries created by proc_init(). + */ +int drm_proc_cleanup(int minor, struct proc_dir_entry *root, + struct proc_dir_entry *dev_root) +{ + int i; + char name[64]; + + if (!root || !dev_root) return 0; + + for (i = 0; i < DRM_PROC_ENTRIES; i++) + remove_proc_entry(drm_proc_list[i].name, dev_root); + sprintf(name, "%d", minor); + remove_proc_entry(name, root); + + return 0; +} + +/** + * Called when "/proc/dri/.../name" is read. + * + * \param buf output buffer. + * \param start start of output data. + * \param offset requested start offset. + * \param request requested number of bytes. + * \param eof whether there is no more data to return. + * \param data private data. + * \return number of written bytes. + * + * Prints the device name together with the bus id if available. + */ +static int drm_proc_name_info(char *buf, char **start, off_t offset, int request, + int *eof, void *data) +{ + drm_device_t *dev = (drm_device_t *)data; + int len = 0; + + if (offset > DRM_PROC_LIMIT) { + *eof = 1; + return 0; + } + + *start = &buf[offset]; + *eof = 0; + + if (dev->unique) { + DRM_PROC_PRINT("%s 0x%lx %s\n", + dev->name, (long)old_encode_dev(dev->device), dev->unique); + } else { + DRM_PROC_PRINT("%s 0x%lx\n", dev->name, (long)old_encode_dev(dev->device)); + } + + if (len > request + offset) return request; + *eof = 1; + return len - offset; +} + +/** + * Called when "/proc/dri/.../vm" is read. + * + * \param buf output buffer. + * \param start start of output data. + * \param offset requested start offset. + * \param request requested number of bytes. + * \param eof whether there is no more data to return. + * \param data private data. + * \return number of written bytes. + * + * Prints information about all mappings in drm_device::maplist. + */ +static int drm_proc__vm_info(char *buf, char **start, off_t offset, int request, + int *eof, void *data) +{ + drm_device_t *dev = (drm_device_t *)data; + int len = 0; + drm_map_t *map; + drm_map_list_t *r_list; + struct list_head *list; + + /* Hardcoded from _DRM_FRAME_BUFFER, + _DRM_REGISTERS, _DRM_SHM, _DRM_AGP, and + _DRM_SCATTER_GATHER. */ + const char *types[] = { "FB", "REG", "SHM", "AGP", "SG" }; + const char *type; + int i; + + if (offset > DRM_PROC_LIMIT) { + *eof = 1; + return 0; + } + + *start = &buf[offset]; + *eof = 0; + + DRM_PROC_PRINT("slot offset size type flags " + "address mtrr\n\n"); + i = 0; + if (dev->maplist != NULL) list_for_each(list, &dev->maplist->head) { + r_list = list_entry(list, drm_map_list_t, head); + map = r_list->map; + if(!map) continue; + if (map->type < 0 || map->type > 4) type = "??"; + else type = types[map->type]; + DRM_PROC_PRINT("%4d 0x%08lx 0x%08lx %4.4s 0x%02x 0x%08lx ", + i, + map->offset, + map->size, + type, + map->flags, + (unsigned long)map->handle); + if (map->mtrr < 0) { + DRM_PROC_PRINT("none\n"); + } else { + DRM_PROC_PRINT("%4d\n", map->mtrr); + } + i++; + } + + if (len > request + offset) return request; + *eof = 1; + return len - offset; +} + +/** + * Simply calls _vm_info() while holding the drm_device::struct_sem lock. + */ +static int drm_proc_vm_info(char *buf, char **start, off_t offset, int request, + int *eof, void *data) +{ + drm_device_t *dev = (drm_device_t *)data; + int ret; + + down(&dev->struct_sem); + ret = drm_proc__vm_info(buf, start, offset, request, eof, data); + up(&dev->struct_sem); + return ret; +} + +/** + * Called when "/proc/dri/.../queues" is read. + * + * \param buf output buffer. + * \param start start of output data. + * \param offset requested start offset. + * \param request requested number of bytes. + * \param eof whether there is no more data to return. + * \param data private data. + * \return number of written bytes. + */ +static int drm_proc__queues_info(char *buf, char **start, off_t offset, + int request, int *eof, void *data) +{ + drm_device_t *dev = (drm_device_t *)data; + int len = 0; + int i; + drm_queue_t *q; + + if (offset > DRM_PROC_LIMIT) { + *eof = 1; + return 0; + } + + *start = &buf[offset]; + *eof = 0; + + DRM_PROC_PRINT(" ctx/flags use fin" + " blk/rw/rwf wait flushed queued" + " locks\n\n"); + for (i = 0; i < dev->queue_count; i++) { + q = dev->queuelist[i]; + atomic_inc(&q->use_count); + DRM_PROC_PRINT_RET(atomic_dec(&q->use_count), + "%5d/0x%03x %5d %5d" + " %5d/%c%c/%c%c%c %5Zd\n", + i, + q->flags, + atomic_read(&q->use_count), + atomic_read(&q->finalization), + atomic_read(&q->block_count), + atomic_read(&q->block_read) ? 'r' : '-', + atomic_read(&q->block_write) ? 'w' : '-', + waitqueue_active(&q->read_queue) ? 'r':'-', + waitqueue_active(&q->write_queue) ? 'w':'-', + waitqueue_active(&q->flush_queue) ? 'f':'-', + DRM_BUFCOUNT(&q->waitlist)); + atomic_dec(&q->use_count); + } + + if (len > request + offset) return request; + *eof = 1; + return len - offset; +} + +/** + * Simply calls _queues_info() while holding the drm_device::struct_sem lock. + */ +static int drm_proc_queues_info(char *buf, char **start, off_t offset, int request, + int *eof, void *data) +{ + drm_device_t *dev = (drm_device_t *)data; + int ret; + + down(&dev->struct_sem); + ret = drm_proc__queues_info(buf, start, offset, request, eof, data); + up(&dev->struct_sem); + return ret; +} + +/** + * Called when "/proc/dri/.../bufs" is read. + * + * \param buf output buffer. + * \param start start of output data. + * \param offset requested start offset. + * \param request requested number of bytes. + * \param eof whether there is no more data to return. + * \param data private data. + * \return number of written bytes. + */ +static int drm_proc__bufs_info(char *buf, char **start, off_t offset, int request, + int *eof, void *data) +{ + drm_device_t *dev = (drm_device_t *)data; + int len = 0; + drm_device_dma_t *dma = dev->dma; + int i; + + if (!dma || offset > DRM_PROC_LIMIT) { + *eof = 1; + return 0; + } + + *start = &buf[offset]; + *eof = 0; + + DRM_PROC_PRINT(" o size count free segs pages kB\n\n"); + for (i = 0; i <= DRM_MAX_ORDER; i++) { + if (dma->bufs[i].buf_count) + DRM_PROC_PRINT("%2d %8d %5d %5d %5d %5d %5ld\n", + i, + dma->bufs[i].buf_size, + dma->bufs[i].buf_count, + atomic_read(&dma->bufs[i] + .freelist.count), + dma->bufs[i].seg_count, + dma->bufs[i].seg_count + *(1 << dma->bufs[i].page_order), + (dma->bufs[i].seg_count + * (1 << dma->bufs[i].page_order)) + * PAGE_SIZE / 1024); + } + DRM_PROC_PRINT("\n"); + for (i = 0; i < dma->buf_count; i++) { + if (i && !(i%32)) DRM_PROC_PRINT("\n"); + DRM_PROC_PRINT(" %d", dma->buflist[i]->list); + } + DRM_PROC_PRINT("\n"); + + if (len > request + offset) return request; + *eof = 1; + return len - offset; +} + +/** + * Simply calls _bufs_info() while holding the drm_device::struct_sem lock. + */ +static int drm_proc_bufs_info(char *buf, char **start, off_t offset, int request, + int *eof, void *data) +{ + drm_device_t *dev = (drm_device_t *)data; + int ret; + + down(&dev->struct_sem); + ret = drm_proc__bufs_info(buf, start, offset, request, eof, data); + up(&dev->struct_sem); + return ret; +} + +/** + * Called when "/proc/dri/.../clients" is read. + * + * \param buf output buffer. + * \param start start of output data. + * \param offset requested start offset. + * \param request requested number of bytes. + * \param eof whether there is no more data to return. + * \param data private data. + * \return number of written bytes. + */ +static int drm_proc__clients_info(char *buf, char **start, off_t offset, + int request, int *eof, void *data) +{ + drm_device_t *dev = (drm_device_t *)data; + int len = 0; + drm_file_t *priv; + + if (offset > DRM_PROC_LIMIT) { + *eof = 1; + return 0; + } + + *start = &buf[offset]; + *eof = 0; + + DRM_PROC_PRINT("a dev pid uid magic ioctls\n\n"); + for (priv = dev->file_first; priv; priv = priv->next) { + DRM_PROC_PRINT("%c %3d %5d %5d %10u %10lu\n", + priv->authenticated ? 'y' : 'n', + priv->minor, + priv->pid, + priv->uid, + priv->magic, + priv->ioctl_count); + } + + if (len > request + offset) return request; + *eof = 1; + return len - offset; +} + +/** + * Simply calls _clients_info() while holding the drm_device::struct_sem lock. + */ +static int drm_proc_clients_info(char *buf, char **start, off_t offset, + int request, int *eof, void *data) +{ + drm_device_t *dev = (drm_device_t *)data; + int ret; + + down(&dev->struct_sem); + ret = drm_proc__clients_info(buf, start, offset, request, eof, data); + up(&dev->struct_sem); + return ret; +} + +#if DRM_DEBUG_CODE + +static int drm_proc__vma_info(char *buf, char **start, off_t offset, int request, + int *eof, void *data) +{ + drm_device_t *dev = (drm_device_t *)data; + int len = 0; + drm_vma_entry_t *pt; + struct vm_area_struct *vma; +#if defined(__i386__) + unsigned int pgprot; +#endif + + if (offset > DRM_PROC_LIMIT) { + *eof = 1; + return 0; + } + + *start = &buf[offset]; + *eof = 0; + + DRM_PROC_PRINT("vma use count: %d, high_memory = %p, 0x%08lx\n", + atomic_read(&dev->vma_count), + high_memory, virt_to_phys(high_memory)); + for (pt = dev->vmalist; pt; pt = pt->next) { + if (!(vma = pt->vma)) continue; + DRM_PROC_PRINT("\n%5d 0x%08lx-0x%08lx %c%c%c%c%c%c 0x%08lx", + pt->pid, + vma->vm_start, + vma->vm_end, + vma->vm_flags & VM_READ ? 'r' : '-', + vma->vm_flags & VM_WRITE ? 'w' : '-', + vma->vm_flags & VM_EXEC ? 'x' : '-', + vma->vm_flags & VM_MAYSHARE ? 's' : 'p', + vma->vm_flags & VM_LOCKED ? 'l' : '-', + vma->vm_flags & VM_IO ? 'i' : '-', + VM_OFFSET(vma)); + +#if defined(__i386__) + pgprot = pgprot_val(vma->vm_page_prot); + DRM_PROC_PRINT(" %c%c%c%c%c%c%c%c%c", + pgprot & _PAGE_PRESENT ? 'p' : '-', + pgprot & _PAGE_RW ? 'w' : 'r', + pgprot & _PAGE_USER ? 'u' : 's', + pgprot & _PAGE_PWT ? 't' : 'b', + pgprot & _PAGE_PCD ? 'u' : 'c', + pgprot & _PAGE_ACCESSED ? 'a' : '-', + pgprot & _PAGE_DIRTY ? 'd' : '-', + pgprot & _PAGE_PSE ? 'm' : 'k', + pgprot & _PAGE_GLOBAL ? 'g' : 'l' ); +#endif + DRM_PROC_PRINT("\n"); + } + + if (len > request + offset) return request; + *eof = 1; + return len - offset; +} + +static int drm_proc_vma_info(char *buf, char **start, off_t offset, int request, + int *eof, void *data) +{ + drm_device_t *dev = (drm_device_t *)data; + int ret; + + down(&dev->struct_sem); + ret = drm_proc__vma_info(buf, start, offset, request, eof, data); + up(&dev->struct_sem); + return ret; +} +#endif + + diff --git a/linux/drm_scatter.h b/linux/drm_scatter.h index 888e6296..02e82781 100644 --- a/linux/drm_scatter.h +++ b/linux/drm_scatter.h @@ -50,13 +50,13 @@ void DRM(sg_cleanup)( drm_sg_mem_t *entry ) vfree( entry->virtual ); - DRM(free)( entry->busaddr, + drm_core_free( entry->busaddr, entry->pages * sizeof(*entry->busaddr), DRM_MEM_PAGES ); - DRM(free)( entry->pagelist, + drm_core_free( entry->pagelist, entry->pages * sizeof(*entry->pagelist), DRM_MEM_PAGES ); - DRM(free)( entry, + drm_core_free( entry, sizeof(*entry), DRM_MEM_SGLISTS ); } @@ -82,7 +82,7 @@ int DRM(sg_alloc)( struct inode *inode, struct file *filp, if ( copy_from_user( &request, argp, sizeof(request) ) ) return -EFAULT; - entry = DRM(alloc)( sizeof(*entry), DRM_MEM_SGLISTS ); + entry = drm_core_alloc( sizeof(*entry), DRM_MEM_SGLISTS ); if ( !entry ) return -ENOMEM; @@ -92,22 +92,22 @@ int DRM(sg_alloc)( struct inode *inode, struct file *filp, DRM_DEBUG( "sg size=%ld pages=%ld\n", request.size, pages ); entry->pages = pages; - entry->pagelist = DRM(alloc)( pages * sizeof(*entry->pagelist), + entry->pagelist = drm_core_alloc( pages * sizeof(*entry->pagelist), DRM_MEM_PAGES ); if ( !entry->pagelist ) { - DRM(free)( entry, sizeof(*entry), DRM_MEM_SGLISTS ); + drm_core_free( entry, sizeof(*entry), DRM_MEM_SGLISTS ); return -ENOMEM; } memset(entry->pagelist, 0, pages * sizeof(*entry->pagelist)); - entry->busaddr = DRM(alloc)( pages * sizeof(*entry->busaddr), + entry->busaddr = drm_core_alloc( pages * sizeof(*entry->busaddr), DRM_MEM_PAGES ); if ( !entry->busaddr ) { - DRM(free)( entry->pagelist, + drm_core_free( entry->pagelist, entry->pages * sizeof(*entry->pagelist), DRM_MEM_PAGES ); - DRM(free)( entry, + drm_core_free( entry, sizeof(*entry), DRM_MEM_SGLISTS ); return -ENOMEM; @@ -116,13 +116,13 @@ int DRM(sg_alloc)( struct inode *inode, struct file *filp, entry->virtual = vmalloc_32( pages << PAGE_SHIFT ); if ( !entry->virtual ) { - DRM(free)( entry->busaddr, + drm_core_free( entry->busaddr, entry->pages * sizeof(*entry->busaddr), DRM_MEM_PAGES ); - DRM(free)( entry->pagelist, + drm_core_free( entry->pagelist, entry->pages * sizeof(*entry->pagelist), DRM_MEM_PAGES ); - DRM(free)( entry, + drm_core_free( entry, sizeof(*entry), DRM_MEM_SGLISTS ); return -ENOMEM; diff --git a/linux/drm_stub.h b/linux/drm_stub.h index 3d9ade35..53f75f4c 100644 --- a/linux/drm_stub.h +++ b/linux/drm_stub.h @@ -162,7 +162,7 @@ static int DRM(stub_getminor)(const char *name, struct file_operations *fops, int i; if (!DRM(stub_list)) { - DRM(stub_list) = DRM(alloc)(sizeof(*DRM(stub_list)) + DRM(stub_list) = drm_core_alloc(sizeof(*DRM(stub_list)) * DRM_STUB_MAXCARDS, DRM_MEM_STUB); if(!DRM(stub_list)) return -1; for (i = 0; i < DRM_STUB_MAXCARDS; i++) { @@ -174,7 +174,7 @@ static int DRM(stub_getminor)(const char *name, struct file_operations *fops, if (!DRM(stub_list)[i].fops) { DRM(stub_list)[i].name = name; DRM(stub_list)[i].fops = fops; - DRM(proc_init)(dev, i, DRM(stub_info).proc_root, + drm_proc_init(dev, i, DRM(stub_info).proc_root, &DRM(stub_list)[i].dev_root); (*DRM(stub_info).info_count)++; DRM_DEBUG("info count increased %d\n", *DRM(stub_info).info_count); @@ -200,7 +200,7 @@ static int DRM(stub_putminor)(int minor) if (minor < 0 || minor >= DRM_STUB_MAXCARDS) return -1; DRM(stub_list)[minor].name = NULL; DRM(stub_list)[minor].fops = NULL; - DRM(proc_cleanup)(minor, DRM(stub_info).proc_root, + drm_proc_cleanup(minor, DRM(stub_info).proc_root, DRM(stub_list)[minor].dev_root); (*DRM(stub_info).info_count)--; @@ -213,7 +213,7 @@ static int DRM(stub_putminor)(int minor) } else { DRM_DEBUG("unregistering inter_module \n"); inter_module_unregister("drm"); - DRM(free)(DRM(stub_list), + drm_core_free(DRM(stub_list), sizeof(*DRM(stub_list)) * DRM_STUB_MAXCARDS, DRM_MEM_STUB); remove_proc_entry("dri", NULL); diff --git a/linux/drm_vm.h b/linux/drm_vm.h index f13db00b..86fe9426 100644 --- a/linux/drm_vm.h +++ b/linux/drm_vm.h @@ -183,7 +183,7 @@ void DRM(vm_shm_close)(struct vm_area_struct *vma) } else { dev->vmalist = pt->next; } - DRM(free)(pt, sizeof(*pt), DRM_MEM_VMAS); + drm_core_free(pt, sizeof(*pt), DRM_MEM_VMAS); } else { prev = pt; } @@ -214,7 +214,7 @@ void DRM(vm_shm_close)(struct vm_area_struct *vma) DRM_DEBUG("mtrr_del = %d\n", retcode); } #endif - DRM(ioremapfree)(map->handle, map->size, dev); + drm_core_ioremapfree(map, dev); break; case _DRM_SHM: vfree(map->handle); @@ -223,7 +223,7 @@ void DRM(vm_shm_close)(struct vm_area_struct *vma) case _DRM_SCATTER_GATHER: break; } - DRM(free)(map, sizeof(*map), DRM_MEM_MAPS); + drm_core_free(map, sizeof(*map), DRM_MEM_MAPS); } } up(&dev->struct_sem); @@ -405,7 +405,7 @@ void DRM(vm_open)(struct vm_area_struct *vma) vma->vm_start, vma->vm_end - vma->vm_start); atomic_inc(&dev->vma_count); - vma_entry = DRM(alloc)(sizeof(*vma_entry), DRM_MEM_VMAS); + vma_entry = drm_core_alloc(sizeof(*vma_entry), DRM_MEM_VMAS); if (vma_entry) { down(&dev->struct_sem); vma_entry->vma = vma; @@ -442,7 +442,7 @@ void DRM(vm_close)(struct vm_area_struct *vma) } else { dev->vmalist = pt->next; } - DRM(free)(pt, sizeof(*pt), DRM_MEM_VMAS); + drm_core_free(pt, sizeof(*pt), DRM_MEM_VMAS); break; } } diff --git a/linux/drmcore_exports.c b/linux/drmcore_exports.c new file mode 100644 index 00000000..69a32dfe --- /dev/null +++ b/linux/drmcore_exports.c @@ -0,0 +1,32 @@ +#include "drm_headers.h" + +EXPORT_SYMBOL(drm_core_reclaim_buffers); +EXPORT_SYMBOL(drm_memory_agp_uninit); +EXPORT_SYMBOL(drm_core_rmmap); +EXPORT_SYMBOL(drm_ati_pcigart_cleanup); +EXPORT_SYMBOL(drm_core_infobufs); +EXPORT_SYMBOL(drm_proc_init); +EXPORT_SYMBOL(drm_core_dma_takedown); +EXPORT_SYMBOL(drm_proc_cleanup); +EXPORT_SYMBOL(drm_core_dma_setup); +EXPORT_SYMBOL(drm_memory_agp_bind); +EXPORT_SYMBOL(drm_core_freebufs); +EXPORT_SYMBOL(drm_ati_pcigart_init); +EXPORT_SYMBOL(drm_memory_unbind_agp); +EXPORT_SYMBOL(drm_core_markbufs); +EXPORT_SYMBOL(drm_memory_agp_init); +EXPORT_SYMBOL(drm_memory_agp_info); +EXPORT_SYMBOL(drm_memory_agp_alloc); +EXPORT_SYMBOL(drm_memory_agp_do_release); +EXPORT_SYMBOL(drm_memory_agp_release); +EXPORT_SYMBOL(drm_memory_realloc); +EXPORT_SYMBOL(drm_memory_agp_enable); +EXPORT_SYMBOL(drm_memory_agp_acquire); +EXPORT_SYMBOL(drm_memory_agp_free); +EXPORT_SYMBOL(drm_core_addbufs); +EXPORT_SYMBOL(drm_core_order); +EXPORT_SYMBOL(drm_memory_mem_init); +EXPORT_SYMBOL(drm_core_mapbufs); +EXPORT_SYMBOL(drm_core_addmap); +EXPORT_SYMBOL(drm_memory_agp_unbind); +EXPORT_SYMBOL(drm_memory_free_agp); diff --git a/linux/radeon_drv.c b/linux/radeon_drv.c index 74e32df0..582d172c 100644 --- a/linux/radeon_drv.c +++ b/linux/radeon_drv.c @@ -31,18 +31,16 @@ #include <linux/config.h> +#include "drm_headers.h" + #include "radeon.h" #include "drmP.h" #include "drm.h" #include "radeon_drm.h" #include "radeon_drv.h" -#include "ati_pcigart.h" -#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" #include "drm_fops.h" @@ -50,8 +48,6 @@ #include "drm_ioctl.h" #include "drm_irq.h" #include "drm_lock.h" -#include "drm_memory.h" -#include "drm_proc.h" #include "drm_vm.h" #include "drm_stub.h" #include "drm_scatter.h" |