Index: head/sys/dev/drm/drmP.h =================================================================== --- head/sys/dev/drm/drmP.h (revision 283998) +++ head/sys/dev/drm/drmP.h (revision 283999) @@ -1,1022 +1,1012 @@ /* drmP.h -- Private header for Direct Rendering Manager -*- linux-c -*- * Created: Mon Jan 4 10:05:05 1999 by faith@precisioninsight.com */ /*- * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. * All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * * Authors: * Rickard E. (Rik) Faith * Gareth Hughes * */ #include __FBSDID("$FreeBSD$"); #ifndef _DRM_P_H_ #define _DRM_P_H_ #if defined(_KERNEL) || defined(__KERNEL__) struct drm_device; struct drm_file; #include #include #include #include #include #include #include #include #include -#if __FreeBSD_version >= 700000 #include -#endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(__i386__) || defined(__amd64__) #include #endif #include #include #if _BYTE_ORDER == _BIG_ENDIAN #define __BIG_ENDIAN 1 #else #define __LITTLE_ENDIAN 1 #endif #include #include #include -#if __FreeBSD_version >= 800004 #include -#else /* __FreeBSD_version >= 800004 */ -#include -#endif /* __FreeBSD_version >= 800004 */ #include #include #include #include #include #include #include "dev/drm/drm.h" #include "dev/drm/drm_atomic.h" #include "dev/drm/drm_internal.h" #include "dev/drm/drm_linux_list.h" #include #ifdef DRM_DEBUG #undef DRM_DEBUG #define DRM_DEBUG_DEFAULT_ON 1 #endif /* DRM_DEBUG */ #if defined(DRM_LINUX) && DRM_LINUX && !defined(__amd64__) #include #include #include #include #else /* Either it was defined when it shouldn't be (FreeBSD amd64) or it isn't * supported on this OS yet. */ #undef DRM_LINUX #define DRM_LINUX 0 #endif /* driver capabilities and requirements mask */ #define DRIVER_USE_AGP 0x1 #define DRIVER_REQUIRE_AGP 0x2 #define DRIVER_USE_MTRR 0x4 #define DRIVER_PCI_DMA 0x8 #define DRIVER_SG 0x10 #define DRIVER_HAVE_DMA 0x20 #define DRIVER_HAVE_IRQ 0x40 #define DRIVER_DMA_QUEUE 0x100 #define DRM_HASH_SIZE 16 /* Size of key hash table */ #define DRM_KERNEL_CONTEXT 0 /* Change drm_resctx if changed */ #define DRM_RESERVED_CONTEXTS 1 /* Change drm_resctx if changed */ MALLOC_DECLARE(DRM_MEM_DMA); MALLOC_DECLARE(DRM_MEM_SAREA); MALLOC_DECLARE(DRM_MEM_DRIVER); MALLOC_DECLARE(DRM_MEM_MAGIC); MALLOC_DECLARE(DRM_MEM_IOCTLS); MALLOC_DECLARE(DRM_MEM_MAPS); MALLOC_DECLARE(DRM_MEM_BUFS); MALLOC_DECLARE(DRM_MEM_SEGS); MALLOC_DECLARE(DRM_MEM_PAGES); MALLOC_DECLARE(DRM_MEM_FILES); MALLOC_DECLARE(DRM_MEM_QUEUES); MALLOC_DECLARE(DRM_MEM_CMDS); MALLOC_DECLARE(DRM_MEM_MAPPINGS); MALLOC_DECLARE(DRM_MEM_BUFLISTS); MALLOC_DECLARE(DRM_MEM_AGPLISTS); MALLOC_DECLARE(DRM_MEM_CTXBITMAP); MALLOC_DECLARE(DRM_MEM_SGLISTS); MALLOC_DECLARE(DRM_MEM_DRAWABLE); MALLOC_DECLARE(DRM_MEM_MM); MALLOC_DECLARE(DRM_MEM_HASHTAB); SYSCTL_DECL(_hw_drm); #define DRM_MAX_CTXBITMAP (PAGE_SIZE * 8) /* Internal types and structures */ #define DRM_ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) #define DRM_MIN(a,b) ((a)<(b)?(a):(b)) #define DRM_MAX(a,b) ((a)>(b)?(a):(b)) #define DRM_IF_VERSION(maj, min) (maj << 16 | min) #define __OS_HAS_AGP 1 #define DRM_DEV_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) #define DRM_DEV_UID 0 #define DRM_DEV_GID 0 #define wait_queue_head_t atomic_t #define DRM_WAKEUP(w) wakeup((void *)w) #define DRM_WAKEUP_INT(w) wakeup(w) #define DRM_INIT_WAITQUEUE(queue) do {(void)(queue);} while (0) #define DRM_CURPROC curthread #define DRM_STRUCTPROC struct thread #define DRM_SPINTYPE struct mtx #define DRM_SPININIT(l,name) mtx_init(l, name, NULL, MTX_DEF) #define DRM_SPINUNINIT(l) mtx_destroy(l) #define DRM_SPINLOCK(l) mtx_lock(l) #define DRM_SPINUNLOCK(u) mtx_unlock(u) #define DRM_SPINLOCK_IRQSAVE(l, irqflags) do { \ mtx_lock(l); \ (void)irqflags; \ } while (0) #define DRM_SPINUNLOCK_IRQRESTORE(u, irqflags) mtx_unlock(u) #define DRM_SPINLOCK_ASSERT(l) mtx_assert(l, MA_OWNED) #define DRM_CURRENTPID curthread->td_proc->p_pid #define DRM_LOCK() mtx_lock(&dev->dev_lock) #define DRM_UNLOCK() mtx_unlock(&dev->dev_lock) #define DRM_SYSCTL_HANDLER_ARGS (SYSCTL_HANDLER_ARGS) #define DRM_IRQ_ARGS void *arg typedef void irqreturn_t; #define IRQ_HANDLED /* nothing */ #define IRQ_NONE /* nothing */ #define unlikely(x) __builtin_expect(!!(x), 0) #define container_of(ptr, type, member) ({ \ __typeof( ((type *)0)->member ) *__mptr = (ptr); \ (type *)( (char *)__mptr - offsetof(type,member) );}) enum { DRM_IS_NOT_AGP, DRM_IS_AGP, DRM_MIGHT_BE_AGP }; #define DRM_AGP_MEM struct agp_memory_info #define drm_get_device_from_kdev(_kdev) (_kdev->si_drv1) #define PAGE_ALIGN(addr) round_page(addr) /* DRM_SUSER returns true if the user is superuser */ -#if __FreeBSD_version >= 700000 #define DRM_SUSER(p) (priv_check(p, PRIV_DRIVER) == 0) -#else -#define DRM_SUSER(p) (suser(p) == 0) -#endif #define DRM_AGP_FIND_DEVICE() agp_find_device() #define DRM_MTRR_WC MDF_WRITECOMBINE #define jiffies ticks typedef vm_paddr_t dma_addr_t; typedef u_int64_t u64; typedef u_int32_t u32; typedef u_int16_t u16; typedef u_int8_t u8; /* DRM_READMEMORYBARRIER() prevents reordering of reads. * DRM_WRITEMEMORYBARRIER() prevents reordering of writes. * DRM_MEMORYBARRIER() prevents reordering of reads and writes. */ #define DRM_READMEMORYBARRIER() rmb() #define DRM_WRITEMEMORYBARRIER() wmb() #define DRM_MEMORYBARRIER() mb() #define DRM_READ8(map, offset) \ *(volatile u_int8_t *)(((vm_offset_t)(map)->virtual) + \ (vm_offset_t)(offset)) #define DRM_READ16(map, offset) \ le16toh(*(volatile u_int16_t *)(((vm_offset_t)(map)->virtual) + \ (vm_offset_t)(offset))) #define DRM_READ32(map, offset) \ le32toh(*(volatile u_int32_t *)(((vm_offset_t)(map)->virtual) + \ (vm_offset_t)(offset))) #define DRM_WRITE8(map, offset, val) \ *(volatile u_int8_t *)(((vm_offset_t)(map)->virtual) + \ (vm_offset_t)(offset)) = val #define DRM_WRITE16(map, offset, val) \ *(volatile u_int16_t *)(((vm_offset_t)(map)->virtual) + \ (vm_offset_t)(offset)) = htole16(val) #define DRM_WRITE32(map, offset, val) \ *(volatile u_int32_t *)(((vm_offset_t)(map)->virtual) + \ (vm_offset_t)(offset)) = htole32(val) #define DRM_VERIFYAREA_READ( uaddr, size ) \ (!useracc(__DECONST(caddr_t, uaddr), size, VM_PROT_READ)) #define DRM_COPY_TO_USER(user, kern, size) \ copyout(kern, user, size) #define DRM_COPY_FROM_USER(kern, user, size) \ copyin(user, kern, size) #define DRM_COPY_FROM_USER_UNCHECKED(arg1, arg2, arg3) \ copyin(arg2, arg1, arg3) #define DRM_COPY_TO_USER_UNCHECKED(arg1, arg2, arg3) \ copyout(arg2, arg1, arg3) #define DRM_GET_USER_UNCHECKED(val, uaddr) \ ((val) = fuword32(uaddr), 0) #define cpu_to_le32(x) htole32(x) #define le32_to_cpu(x) le32toh(x) #define DRM_HZ hz #define DRM_UDELAY(udelay) DELAY(udelay) #define DRM_TIME_SLICE (hz/20) /* Time slice for GLXContexts */ #define DRM_GET_PRIV_SAREA(_dev, _ctx, _map) do { \ (_map) = (_dev)->context_sareas[_ctx]; \ } while(0) #define LOCK_TEST_WITH_RETURN(dev, file_priv) \ do { \ if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) || \ dev->lock.file_priv != file_priv) { \ DRM_ERROR("%s called without lock held\n", \ __FUNCTION__); \ return EINVAL; \ } \ } while (0) /* Returns -errno to shared code */ #define DRM_WAIT_ON( ret, queue, timeout, condition ) \ for ( ret = 0 ; !ret && !(condition) ; ) { \ DRM_UNLOCK(); \ mtx_lock(&dev->irq_lock); \ if (!(condition)) \ ret = -mtx_sleep(&(queue), &dev->irq_lock, \ PCATCH, "drmwtq", (timeout)); \ mtx_unlock(&dev->irq_lock); \ DRM_LOCK(); \ } #define DRM_ERROR(fmt, ...) \ printf("error: [" DRM_NAME ":pid%d:%s] *ERROR* " fmt, \ DRM_CURRENTPID, __func__ , ##__VA_ARGS__) #define DRM_INFO(fmt, ...) printf("info: [" DRM_NAME "] " fmt , ##__VA_ARGS__) #define DRM_DEBUG(fmt, ...) do { \ if (drm_debug_flag) \ printf("[" DRM_NAME ":pid%d:%s] " fmt, DRM_CURRENTPID, \ __func__ , ##__VA_ARGS__); \ } while (0) typedef struct drm_pci_id_list { int vendor; int device; long driver_private; char *name; } drm_pci_id_list_t; struct drm_msi_blacklist_entry { int vendor; int device; }; #define DRM_AUTH 0x1 #define DRM_MASTER 0x2 #define DRM_ROOT_ONLY 0x4 typedef struct drm_ioctl_desc { unsigned long cmd; int (*func)(struct drm_device *dev, void *data, struct drm_file *file_priv); int flags; } drm_ioctl_desc_t; /** * Creates a driver or general drm_ioctl_desc array entry for the given * ioctl, for use by drm_ioctl(). */ #define DRM_IOCTL_DEF(ioctl, func, flags) \ [DRM_IOCTL_NR(ioctl)] = {ioctl, func, flags} 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_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 pending; /* On hardware DMA queue */ struct drm_file *file_priv; /* Unique identifier of holding process */ int context; /* Kernel queue for this buffer */ 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 stoarge */ void *dev_private; /* Per-buffer private storage */ } drm_buf_t; typedef struct drm_freelist { int initialized; /* Freelist in use */ atomic_t count; /* Number of free buffers */ drm_buf_t *next; /* End pointer */ int low_mark; /* Low water mark */ int high_mark; /* High water mark */ } drm_freelist_t; typedef struct drm_dma_handle { void *vaddr; bus_addr_t busaddr; bus_dma_tag_t tag; bus_dmamap_t map; } drm_dma_handle_t; typedef struct drm_buf_entry { int buf_size; int buf_count; drm_buf_t *buflist; int seg_count; drm_dma_handle_t **seglist; int page_order; drm_freelist_t freelist; } drm_buf_entry_t; typedef TAILQ_HEAD(drm_file_list, drm_file) drm_file_list_t; struct drm_file { TAILQ_ENTRY(drm_file) link; struct drm_device *dev; int authenticated; int master; pid_t pid; uid_t uid; drm_magic_t magic; unsigned long ioctl_count; void *driver_priv; }; typedef struct drm_lock_data { struct drm_hw_lock *hw_lock; /* Hardware lock */ struct drm_file *file_priv; /* Unique identifier of holding process (NULL is kernel)*/ int lock_queue; /* Queue of blocked processes */ unsigned long lock_time; /* Time of last lock in jiffies */ } drm_lock_data_t; /* This structure, in the struct drm_device, is always initialized while the * device * is open. dev->dma_lock protects the incrementing of dev->buf_use, which * when set marks that no further bufs may be allocated until device teardown * occurs (when the last open of the device has closed). The high/low * watermarks of bufs are only touched by the X Server, and thus not * concurrently accessed, so no locking is needed. */ typedef struct drm_device_dma { drm_buf_entry_t bufs[DRM_MAX_ORDER+1]; int buf_count; drm_buf_t **buflist; /* Vector of pointers info bufs */ int seg_count; int page_count; unsigned long *pagelist; unsigned long byte_count; enum { _DRM_DMA_USE_AGP = 0x01, _DRM_DMA_USE_SG = 0x02 } flags; } drm_device_dma_t; typedef struct drm_agp_mem { void *handle; unsigned long bound; /* address */ int pages; struct drm_agp_mem *prev; struct drm_agp_mem *next; } drm_agp_mem_t; typedef struct drm_agp_head { device_t agpdev; struct agp_info info; const char *chipset; drm_agp_mem_t *memory; unsigned long mode; int enabled; int acquired; unsigned long base; int mtrr; int cant_use_aperture; unsigned long page_mask; } drm_agp_head_t; typedef struct drm_sg_mem { vm_offset_t vaddr; vm_paddr_t *busaddr; vm_pindex_t pages; } drm_sg_mem_t; #define DRM_MAP_HANDLE_BITS (sizeof(void *) == 4 ? 4 : 24) #define DRM_MAP_HANDLE_SHIFT (sizeof(void *) * 8 - DRM_MAP_HANDLE_BITS) typedef TAILQ_HEAD(drm_map_list, drm_local_map) drm_map_list_t; typedef struct drm_local_map { unsigned long offset; /* Physical address (0 for SAREA) */ unsigned long size; /* Physical size (bytes) */ enum drm_map_type type; /* Type of memory mapped */ enum drm_map_flags flags; /* Flags */ void *handle; /* User-space: "Handle" to pass to mmap */ /* Kernel-space: kernel-virtual address */ int mtrr; /* Boolean: MTRR used */ /* Private data */ int rid; /* PCI resource ID for bus_space */ void *virtual; /* Kernel-space: kernel-virtual address */ struct resource *bsr; bus_space_tag_t bst; bus_space_handle_t bsh; drm_dma_handle_t *dmah; TAILQ_ENTRY(drm_local_map) link; } drm_local_map_t; struct drm_vblank_info { wait_queue_head_t queue; /* vblank wait queue */ atomic_t count; /* number of VBLANK interrupts */ /* (driver must alloc the right number of counters) */ atomic_t refcount; /* number of users of vblank interrupts */ u32 last; /* protected by dev->vbl_lock, used */ /* for wraparound handling */ int enabled; /* so we don't call enable more than */ /* once per disable */ int inmodeset; /* Display driver is setting mode */ }; /* location of GART table */ #define DRM_ATI_GART_MAIN 1 #define DRM_ATI_GART_FB 2 #define DRM_ATI_GART_PCI 1 #define DRM_ATI_GART_PCIE 2 #define DRM_ATI_GART_IGP 3 struct drm_ati_pcigart_info { int gart_table_location; int gart_reg_if; void *addr; dma_addr_t bus_addr; dma_addr_t table_mask; dma_addr_t member_mask; struct drm_dma_handle *table_handle; drm_local_map_t mapping; int table_size; struct drm_dma_handle *dmah; /* handle for ATI PCIGART table */ }; #ifndef DMA_BIT_MASK #define DMA_BIT_MASK(n) (((n) == 64) ? ~0ULL : (1ULL<<(n)) - 1) #endif #define upper_32_bits(n) ((u32)(((n) >> 16) >> 16)) struct drm_driver_info { int (*load)(struct drm_device *, unsigned long flags); int (*firstopen)(struct drm_device *); int (*open)(struct drm_device *, struct drm_file *); void (*preclose)(struct drm_device *, struct drm_file *file_priv); void (*postclose)(struct drm_device *, struct drm_file *); void (*lastclose)(struct drm_device *); int (*unload)(struct drm_device *); void (*reclaim_buffers_locked)(struct drm_device *, struct drm_file *file_priv); int (*dma_ioctl)(struct drm_device *dev, void *data, struct drm_file *file_priv); void (*dma_ready)(struct drm_device *); int (*dma_quiescent)(struct drm_device *); int (*dma_flush_block_and_flush)(struct drm_device *, int context, enum drm_lock_flags flags); int (*dma_flush_unblock)(struct drm_device *, int context, enum drm_lock_flags flags); 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); void (*irq_preinstall)(struct drm_device *dev); int (*irq_postinstall)(struct drm_device *dev); void (*irq_uninstall)(struct drm_device *dev); void (*irq_handler)(DRM_IRQ_ARGS); u32 (*get_vblank_counter)(struct drm_device *dev, int crtc); int (*enable_vblank)(struct drm_device *dev, int crtc); void (*disable_vblank)(struct drm_device *dev, int crtc); drm_pci_id_list_t *id_entry; /* PCI ID, name, and chipset private */ /** * Called by \c drm_device_is_agp. Typically used to determine if a * card is really attached to AGP or not. * * \param dev DRM device handle * * \returns * One of three values is returned depending on whether or not the * card is absolutely \b not AGP (return of 0), absolutely \b is AGP * (return of 1), or may or may not be AGP (return of 2). */ int (*device_is_agp) (struct drm_device * dev); drm_ioctl_desc_t *ioctls; int max_ioctl; int buf_priv_size; int major; int minor; int patchlevel; const char *name; /* Simple driver name */ const char *desc; /* Longer driver name */ const char *date; /* Date of last major changes. */ u32 driver_features; }; /* Length for the array of resource pointers for drm_get_resource_*. */ #define DRM_MAX_PCI_RESOURCE 6 /** * DRM device functions structure */ struct drm_device { struct drm_driver_info *driver; drm_pci_id_list_t *id_entry; /* PCI ID, name, and chipset private */ u_int16_t pci_device; /* PCI device id */ u_int16_t pci_vendor; /* PCI vendor id */ char *unique; /* Unique identifier: e.g., busid */ int unique_len; /* Length of unique field */ device_t device; /* Device instance from newbus */ struct cdev *devnode; /* Device number for mknod */ int if_version; /* Highest interface version set */ int flags; /* Flags to open(2) */ /* Locks */ struct mtx vbl_lock; /* protects vblank operations */ struct mtx dma_lock; /* protects dev->dma */ struct mtx irq_lock; /* protects irq condition checks */ struct mtx dev_lock; /* protects everything else */ DRM_SPINTYPE drw_lock; /* Usage Counters */ int open_count; /* Outstanding files open */ int buf_use; /* Buffers in use -- cannot alloc */ /* Performance counters */ unsigned long counters; enum drm_stat_type types[15]; atomic_t counts[15]; /* Authentication */ drm_file_list_t files; drm_magic_head_t magiclist[DRM_HASH_SIZE]; /* Linked list of mappable regions. Protected by dev_lock */ drm_map_list_t maplist; struct unrhdr *map_unrhdr; drm_local_map_t **context_sareas; int max_context; drm_lock_data_t lock; /* Information on hardware lock */ /* DMA queues (contexts) */ drm_device_dma_t *dma; /* Optional pointer for DMA support */ /* Context support */ int irq; /* Interrupt used by board */ int irq_enabled; /* True if the irq handler is enabled */ int msi_enabled; /* MSI enabled */ int irqrid; /* Interrupt used by board */ struct resource *irqr; /* Resource for interrupt used by board */ void *irqh; /* Handle from bus_setup_intr */ /* Storage of resource pointers for drm_get_resource_* */ struct resource *pcir[DRM_MAX_PCI_RESOURCE]; int pcirid[DRM_MAX_PCI_RESOURCE]; int pci_domain; int pci_bus; int pci_slot; int pci_func; atomic_t context_flag; /* Context swapping flag */ int last_context; /* Last current context */ int vblank_disable_allowed; struct callout vblank_disable_timer; u32 max_vblank_count; /* size of vblank counter register */ struct drm_vblank_info *vblank; /* per crtc vblank info */ int num_crtcs; struct sigio *buf_sigio; /* Processes waiting for SIGIO */ /* Sysctl support */ struct drm_sysctl_info *sysctl; drm_agp_head_t *agp; drm_sg_mem_t *sg; /* Scatter gather memory */ atomic_t *ctx_bitmap; void *dev_private; unsigned int agp_buffer_token; drm_local_map_t *agp_buffer_map; struct unrhdr *drw_unrhdr; /* RB tree of drawable infos */ RB_HEAD(drawable_tree, bsd_drm_drawable_info) drw_head; }; static __inline__ int drm_core_check_feature(struct drm_device *dev, int feature) { return ((dev->driver->driver_features & feature) ? 1 : 0); } #if __OS_HAS_AGP static inline int drm_core_has_AGP(struct drm_device *dev) { return drm_core_check_feature(dev, DRIVER_USE_AGP); } #else #define drm_core_has_AGP(dev) (0) #endif extern int drm_debug_flag; /* Device setup support (drm_drv.c) */ int drm_probe(device_t kdev, drm_pci_id_list_t *idlist); int drm_attach(device_t kdev, drm_pci_id_list_t *idlist); void drm_close(void *data); int drm_detach(device_t kdev); d_ioctl_t drm_ioctl; d_open_t drm_open; d_read_t drm_read; d_poll_t drm_poll; d_mmap_t drm_mmap; extern drm_local_map_t *drm_getsarea(struct drm_device *dev); /* File operations helpers (drm_fops.c) */ extern int drm_open_helper(struct cdev *kdev, int flags, int fmt, DRM_STRUCTPROC *p, struct drm_device *dev); /* Memory management support (drm_memory.c) */ void drm_mem_init(void); void drm_mem_uninit(void); void *drm_ioremap_wc(struct drm_device *dev, drm_local_map_t *map); void *drm_ioremap(struct drm_device *dev, drm_local_map_t *map); void drm_ioremapfree(drm_local_map_t *map); int drm_mtrr_add(unsigned long offset, size_t size, int flags); int drm_mtrr_del(int handle, unsigned long offset, size_t size, int flags); int drm_context_switch(struct drm_device *dev, int old, int new); int drm_context_switch_complete(struct drm_device *dev, int new); int drm_ctxbitmap_init(struct drm_device *dev); void drm_ctxbitmap_cleanup(struct drm_device *dev); void drm_ctxbitmap_free(struct drm_device *dev, int ctx_handle); int drm_ctxbitmap_next(struct drm_device *dev); /* Locking IOCTL support (drm_lock.c) */ int drm_lock_take(struct drm_lock_data *lock_data, unsigned int context); int drm_lock_transfer(struct drm_lock_data *lock_data, unsigned int context); int drm_lock_free(struct drm_lock_data *lock_data, unsigned int context); /* Buffer management support (drm_bufs.c) */ unsigned long drm_get_resource_start(struct drm_device *dev, unsigned int resource); unsigned long drm_get_resource_len(struct drm_device *dev, unsigned int resource); void drm_rmmap(struct drm_device *dev, drm_local_map_t *map); int drm_order(unsigned long size); int drm_addmap(struct drm_device *dev, unsigned long offset, unsigned long size, enum drm_map_type type, enum drm_map_flags flags, drm_local_map_t **map_ptr); int drm_addbufs_pci(struct drm_device *dev, struct drm_buf_desc *request); int drm_addbufs_sg(struct drm_device *dev, struct drm_buf_desc *request); int drm_addbufs_agp(struct drm_device *dev, struct drm_buf_desc *request); /* DMA support (drm_dma.c) */ int drm_dma_setup(struct drm_device *dev); void drm_dma_takedown(struct drm_device *dev); void drm_free_buffer(struct drm_device *dev, drm_buf_t *buf); void drm_reclaim_buffers(struct drm_device *dev, struct drm_file *file_priv); #define drm_core_reclaim_buffers drm_reclaim_buffers /* IRQ support (drm_irq.c) */ int drm_irq_install(struct drm_device *dev); int drm_irq_uninstall(struct drm_device *dev); irqreturn_t drm_irq_handler(DRM_IRQ_ARGS); void drm_driver_irq_preinstall(struct drm_device *dev); void drm_driver_irq_postinstall(struct drm_device *dev); void drm_driver_irq_uninstall(struct drm_device *dev); void drm_handle_vblank(struct drm_device *dev, int crtc); u32 drm_vblank_count(struct drm_device *dev, int crtc); int drm_vblank_get(struct drm_device *dev, int crtc); void drm_vblank_put(struct drm_device *dev, int crtc); void drm_vblank_cleanup(struct drm_device *dev); int drm_vblank_wait(struct drm_device *dev, unsigned int *vbl_seq); int drm_vblank_init(struct drm_device *dev, int num_crtcs); int drm_modeset_ctl(struct drm_device *dev, void *data, struct drm_file *file_priv); /* AGP/PCI Express/GART support (drm_agpsupport.c) */ int drm_device_is_agp(struct drm_device *dev); int drm_device_is_pcie(struct drm_device *dev); drm_agp_head_t *drm_agp_init(void); int drm_agp_acquire(struct drm_device *dev); int drm_agp_release(struct drm_device *dev); int drm_agp_info(struct drm_device * dev, struct drm_agp_info *info); int drm_agp_enable(struct drm_device *dev, struct drm_agp_mode mode); void *drm_agp_allocate_memory(size_t pages, u32 type); int drm_agp_free_memory(void *handle); int drm_agp_bind_memory(void *handle, off_t start); int drm_agp_unbind_memory(void *handle); int drm_agp_alloc(struct drm_device *dev, struct drm_agp_buffer *request); int drm_agp_free(struct drm_device *dev, struct drm_agp_buffer *request); int drm_agp_bind(struct drm_device *dev, struct drm_agp_binding *request); int drm_agp_unbind(struct drm_device *dev, struct drm_agp_binding *request); /* Scatter Gather Support (drm_scatter.c) */ void drm_sg_cleanup(drm_sg_mem_t *entry); int drm_sg_alloc(struct drm_device *dev, struct drm_scatter_gather * request); /* sysctl support (drm_sysctl.h) */ extern int drm_sysctl_init(struct drm_device *dev); extern int drm_sysctl_cleanup(struct drm_device *dev); /* ATI PCIGART support (ati_pcigart.c) */ int drm_ati_pcigart_init(struct drm_device *dev, struct drm_ati_pcigart_info *gart_info); int drm_ati_pcigart_cleanup(struct drm_device *dev, struct drm_ati_pcigart_info *gart_info); /* Locking IOCTL support (drm_drv.c) */ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv); int drm_unlock(struct drm_device *dev, void *data, struct drm_file *file_priv); int drm_version(struct drm_device *dev, void *data, struct drm_file *file_priv); int drm_setversion(struct drm_device *dev, void *data, struct drm_file *file_priv); /* Misc. IOCTL support (drm_ioctl.c) */ int drm_irq_by_busid(struct drm_device *dev, void *data, struct drm_file *file_priv); int drm_getunique(struct drm_device *dev, void *data, struct drm_file *file_priv); int drm_setunique(struct drm_device *dev, void *data, struct drm_file *file_priv); int drm_getmap(struct drm_device *dev, void *data, struct drm_file *file_priv); int drm_getclient(struct drm_device *dev, void *data, struct drm_file *file_priv); int drm_getstats(struct drm_device *dev, void *data, struct drm_file *file_priv); int drm_noop(struct drm_device *dev, void *data, struct drm_file *file_priv); /* Context IOCTL support (drm_context.c) */ int drm_resctx(struct drm_device *dev, void *data, struct drm_file *file_priv); int drm_addctx(struct drm_device *dev, void *data, struct drm_file *file_priv); int drm_modctx(struct drm_device *dev, void *data, struct drm_file *file_priv); int drm_getctx(struct drm_device *dev, void *data, struct drm_file *file_priv); int drm_switchctx(struct drm_device *dev, void *data, struct drm_file *file_priv); int drm_newctx(struct drm_device *dev, void *data, struct drm_file *file_priv); int drm_rmctx(struct drm_device *dev, void *data, struct drm_file *file_priv); int drm_setsareactx(struct drm_device *dev, void *data, struct drm_file *file_priv); int drm_getsareactx(struct drm_device *dev, void *data, struct drm_file *file_priv); /* Drawable IOCTL support (drm_drawable.c) */ int drm_adddraw(struct drm_device *dev, void *data, struct drm_file *file_priv); int drm_rmdraw(struct drm_device *dev, void *data, struct drm_file *file_priv); int drm_update_draw(struct drm_device *dev, void *data, struct drm_file *file_priv); struct drm_drawable_info *drm_get_drawable_info(struct drm_device *dev, int handle); /* Drawable support (drm_drawable.c) */ void drm_drawable_free_all(struct drm_device *dev); /* Authentication IOCTL support (drm_auth.c) */ int drm_getmagic(struct drm_device *dev, void *data, struct drm_file *file_priv); int drm_authmagic(struct drm_device *dev, void *data, struct drm_file *file_priv); /* Buffer management support (drm_bufs.c) */ int drm_addmap_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); int drm_rmmap_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); int drm_addbufs(struct drm_device *dev, void *data, struct drm_file *file_priv); int drm_infobufs(struct drm_device *dev, void *data, struct drm_file *file_priv); int drm_markbufs(struct drm_device *dev, void *data, struct drm_file *file_priv); int drm_freebufs(struct drm_device *dev, void *data, struct drm_file *file_priv); int drm_mapbufs(struct drm_device *dev, void *data, struct drm_file *file_priv); /* DMA support (drm_dma.c) */ int drm_dma(struct drm_device *dev, void *data, struct drm_file *file_priv); /* IRQ support (drm_irq.c) */ int drm_control(struct drm_device *dev, void *data, struct drm_file *file_priv); int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_priv); /* AGP/GART support (drm_agpsupport.c) */ int drm_agp_acquire_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); int drm_agp_release_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); int drm_agp_enable_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); int drm_agp_info_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); int drm_agp_alloc_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); int drm_agp_free_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); int drm_agp_unbind_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); int drm_agp_bind_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); /* Scatter Gather Support (drm_scatter.c) */ int drm_sg_alloc_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); int drm_sg_free(struct drm_device *dev, void *data, struct drm_file *file_priv); /* consistent PCI memory functions (drm_pci.c) */ drm_dma_handle_t *drm_pci_alloc(struct drm_device *dev, size_t size, size_t align, dma_addr_t maxaddr); void drm_pci_free(struct drm_device *dev, drm_dma_handle_t *dmah); /* Inline replacements for drm_alloc and friends */ static __inline__ void * drm_alloc(size_t size, struct malloc_type *area) { return malloc(size, area, M_NOWAIT); } static __inline__ void * drm_calloc(size_t nmemb, size_t size, struct malloc_type *area) { return malloc(size * nmemb, area, M_NOWAIT | M_ZERO); } static __inline__ void * drm_realloc(void *oldpt, size_t oldsize, size_t size, struct malloc_type *area) { return reallocf(oldpt, size, area, M_NOWAIT); } static __inline__ void drm_free(void *pt, size_t size, struct malloc_type *area) { free(pt, area); } /* Inline replacements for DRM_IOREMAP macros */ static __inline__ void drm_core_ioremap_wc(struct drm_local_map *map, struct drm_device *dev) { map->virtual = drm_ioremap_wc(dev, map); } static __inline__ void drm_core_ioremap(struct drm_local_map *map, struct drm_device *dev) { map->virtual = drm_ioremap(dev, map); } static __inline__ void drm_core_ioremapfree(struct drm_local_map *map, struct drm_device *dev) { if ( map->virtual && map->size ) drm_ioremapfree(map); } static __inline__ struct drm_local_map * drm_core_findmap(struct drm_device *dev, unsigned long offset) { drm_local_map_t *map; DRM_SPINLOCK_ASSERT(&dev->dev_lock); TAILQ_FOREACH(map, &dev->maplist, link) { if (offset == (unsigned long)map->handle) return map; } return NULL; } static __inline__ void drm_core_dropmap(struct drm_map *map) { } #endif /* __KERNEL__ */ #endif /* _DRM_P_H_ */ Index: head/sys/dev/drm/drm_agpsupport.c =================================================================== --- head/sys/dev/drm/drm_agpsupport.c (revision 283998) +++ head/sys/dev/drm/drm_agpsupport.c (revision 283999) @@ -1,469 +1,434 @@ /*- * 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. * * Author: * Rickard E. (Rik) Faith * Gareth Hughes * */ #include __FBSDID("$FreeBSD$"); /** @file drm_agpsupport.c * Support code for tying the kernel AGP support to DRM drivers and * the DRM's AGP ioctls. */ #include "dev/drm/drmP.h" -#if __FreeBSD_version >= 800004 #include -#else /* __FreeBSD_version >= 800004 */ -#include -#endif /* __FreeBSD_version >= 800004 */ #include /* Returns 1 if AGP or 0 if not. */ static int drm_device_find_capability(struct drm_device *dev, int cap) { -#if __FreeBSD_version >= 602102 return (pci_find_cap(dev->device, cap, NULL) == 0); -#else - /* Code taken from agp.c. IWBNI that was a public interface. */ - u_int32_t status; - u_int8_t ptr, next; - - /* - * Check the CAP_LIST bit of the PCI status register first. - */ - status = pci_read_config(dev->device, PCIR_STATUS, 2); - if (!(status & 0x10)) - return 0; - - /* - * Traverse the capabilities list. - */ - for (ptr = pci_read_config(dev->device, AGP_CAPPTR, 1); - ptr != 0; - ptr = next) { - u_int32_t capid = pci_read_config(dev->device, ptr, 4); - next = AGP_CAPID_GET_NEXT_PTR(capid); - - /* - * If this capability entry ID is cap, then we are done. - */ - if (AGP_CAPID_GET_CAP_ID(capid) == cap) - return 1; - } - - return 0; -#endif } int drm_device_is_agp(struct drm_device *dev) { if (dev->driver->device_is_agp != NULL) { int ret; /* device_is_agp returns a tristate, 0 = not AGP, 1 = definitely * AGP, 2 = fall back to PCI capability */ ret = (*dev->driver->device_is_agp)(dev); if (ret != DRM_MIGHT_BE_AGP) return ret; } return (drm_device_find_capability(dev, PCIY_AGP)); } int drm_device_is_pcie(struct drm_device *dev) { return (drm_device_find_capability(dev, PCIY_EXPRESS)); } int drm_agp_info(struct drm_device * dev, struct drm_agp_info *info) { struct agp_info *kern; if (!dev->agp || !dev->agp->acquired) return EINVAL; kern = &dev->agp->info; agp_get_info(dev->agp->agpdev, kern); info->agp_version_major = 1; info->agp_version_minor = 0; info->mode = kern->ai_mode; info->aperture_base = kern->ai_aperture_base; info->aperture_size = kern->ai_aperture_size; info->memory_allowed = kern->ai_memory_allowed; info->memory_used = kern->ai_memory_used; info->id_vendor = kern->ai_devid & 0xffff; info->id_device = kern->ai_devid >> 16; return 0; } int drm_agp_info_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { int err; struct drm_agp_info info; err = drm_agp_info(dev, &info); if (err != 0) return err; *(struct drm_agp_info *) data = info; return 0; } int drm_agp_acquire_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { return drm_agp_acquire(dev); } int drm_agp_acquire(struct drm_device *dev) { int retcode; if (!dev->agp || dev->agp->acquired) return EINVAL; retcode = agp_acquire(dev->agp->agpdev); if (retcode) return retcode; dev->agp->acquired = 1; return 0; } int drm_agp_release_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { return drm_agp_release(dev); } int drm_agp_release(struct drm_device * dev) { if (!dev->agp || !dev->agp->acquired) return EINVAL; agp_release(dev->agp->agpdev); dev->agp->acquired = 0; return 0; } int drm_agp_enable(struct drm_device *dev, struct drm_agp_mode mode) { if (!dev->agp || !dev->agp->acquired) return EINVAL; dev->agp->mode = mode.mode; agp_enable(dev->agp->agpdev, mode.mode); dev->agp->enabled = 1; return 0; } int drm_agp_enable_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_agp_mode mode; mode = *(struct drm_agp_mode *) data; return drm_agp_enable(dev, mode); } int drm_agp_alloc(struct drm_device *dev, struct drm_agp_buffer *request) { drm_agp_mem_t *entry; void *handle; unsigned long pages; u_int32_t type; struct agp_memory_info info; if (!dev->agp || !dev->agp->acquired) return EINVAL; entry = malloc(sizeof(*entry), DRM_MEM_AGPLISTS, M_NOWAIT | M_ZERO); if (entry == NULL) return ENOMEM; pages = (request->size + PAGE_SIZE - 1) / PAGE_SIZE; type = (u_int32_t) request->type; DRM_UNLOCK(); handle = drm_agp_allocate_memory(pages, type); DRM_LOCK(); if (handle == NULL) { free(entry, DRM_MEM_AGPLISTS); return ENOMEM; } entry->handle = handle; 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; agp_memory_info(dev->agp->agpdev, entry->handle, &info); request->handle = (unsigned long) entry->handle; request->physical = info.ami_physical; return 0; } int drm_agp_alloc_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_agp_buffer request; int retcode; request = *(struct drm_agp_buffer *) data; DRM_LOCK(); retcode = drm_agp_alloc(dev, &request); DRM_UNLOCK(); *(struct drm_agp_buffer *) data = request; return retcode; } static drm_agp_mem_t * drm_agp_lookup_entry(struct drm_device *dev, void *handle) { drm_agp_mem_t *entry; for (entry = dev->agp->memory; entry; entry = entry->next) { if (entry->handle == handle) return entry; } return NULL; } int drm_agp_unbind(struct drm_device *dev, struct drm_agp_binding *request) { drm_agp_mem_t *entry; int retcode; if (!dev->agp || !dev->agp->acquired) return EINVAL; entry = drm_agp_lookup_entry(dev, (void *)request->handle); if (entry == NULL || !entry->bound) return EINVAL; DRM_UNLOCK(); retcode = drm_agp_unbind_memory(entry->handle); DRM_LOCK(); if (retcode == 0) entry->bound = 0; return retcode; } int drm_agp_unbind_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_agp_binding request; int retcode; request = *(struct drm_agp_binding *) data; DRM_LOCK(); retcode = drm_agp_unbind(dev, &request); DRM_UNLOCK(); return retcode; } int drm_agp_bind(struct drm_device *dev, struct drm_agp_binding *request) { drm_agp_mem_t *entry; int retcode; int page; if (!dev->agp || !dev->agp->acquired) return EINVAL; DRM_DEBUG("agp_bind, page_size=%x\n", (int)PAGE_SIZE); entry = drm_agp_lookup_entry(dev, (void *)request->handle); if (entry == NULL || entry->bound) return EINVAL; page = (request->offset + PAGE_SIZE - 1) / PAGE_SIZE; DRM_UNLOCK(); retcode = drm_agp_bind_memory(entry->handle, page); DRM_LOCK(); if (retcode == 0) entry->bound = dev->agp->base + (page << PAGE_SHIFT); return retcode; } int drm_agp_bind_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_agp_binding request; int retcode; request = *(struct drm_agp_binding *) data; DRM_LOCK(); retcode = drm_agp_bind(dev, &request); DRM_UNLOCK(); return retcode; } int drm_agp_free(struct drm_device *dev, struct drm_agp_buffer *request) { drm_agp_mem_t *entry; if (!dev->agp || !dev->agp->acquired) return EINVAL; entry = drm_agp_lookup_entry(dev, (void*)request->handle); if (entry == NULL) return EINVAL; if (entry->prev) entry->prev->next = entry->next; else dev->agp->memory = entry->next; if (entry->next) entry->next->prev = entry->prev; DRM_UNLOCK(); if (entry->bound) drm_agp_unbind_memory(entry->handle); drm_agp_free_memory(entry->handle); DRM_LOCK(); free(entry, DRM_MEM_AGPLISTS); return 0; } int drm_agp_free_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_agp_buffer request; int retcode; request = *(struct drm_agp_buffer *) data; DRM_LOCK(); retcode = drm_agp_free(dev, &request); DRM_UNLOCK(); return retcode; } drm_agp_head_t *drm_agp_init(void) { device_t agpdev; drm_agp_head_t *head = NULL; int agp_available = 1; agpdev = DRM_AGP_FIND_DEVICE(); if (!agpdev) agp_available = 0; DRM_DEBUG("agp_available = %d\n", agp_available); if (agp_available) { head = malloc(sizeof(*head), DRM_MEM_AGPLISTS, M_NOWAIT | M_ZERO); if (head == NULL) return NULL; head->agpdev = agpdev; agp_get_info(agpdev, &head->info); head->base = head->info.ai_aperture_base; head->memory = NULL; DRM_INFO("AGP at 0x%08lx %dMB\n", (long)head->info.ai_aperture_base, (int)(head->info.ai_aperture_size >> 20)); } return head; } void *drm_agp_allocate_memory(size_t pages, u32 type) { device_t agpdev; agpdev = DRM_AGP_FIND_DEVICE(); if (!agpdev) return NULL; return agp_alloc_memory(agpdev, type, pages << AGP_PAGE_SHIFT); } int drm_agp_free_memory(void *handle) { device_t agpdev; agpdev = DRM_AGP_FIND_DEVICE(); if (!agpdev || !handle) return 0; agp_free_memory(agpdev, handle); return 1; } int drm_agp_bind_memory(void *handle, off_t start) { device_t agpdev; agpdev = DRM_AGP_FIND_DEVICE(); if (!agpdev || !handle) return EINVAL; return agp_bind_memory(agpdev, handle, start * PAGE_SIZE); } int drm_agp_unbind_memory(void *handle) { device_t agpdev; agpdev = DRM_AGP_FIND_DEVICE(); if (!agpdev || !handle) return EINVAL; return agp_unbind_memory(agpdev, handle); } Index: head/sys/dev/drm/drm_bufs.c =================================================================== --- head/sys/dev/drm/drm_bufs.c (revision 283998) +++ head/sys/dev/drm/drm_bufs.c (revision 283999) @@ -1,1130 +1,1124 @@ /*- * 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. * * Authors: * Rickard E. (Rik) Faith * Gareth Hughes * */ #include __FBSDID("$FreeBSD$"); /** @file drm_bufs.c * Implementation of the ioctls for setup of DRM mappings and DMA buffers. */ #include "dev/pci/pcireg.h" #include "dev/drm/drmP.h" /* Allocation of PCI memory resources (framebuffer, registers, etc.) for * drm_get_resource_*. Note that they are not RF_ACTIVE, so there's no virtual * address for accessing them. Cleaned up at unload. */ static int drm_alloc_resource(struct drm_device *dev, int resource) { struct resource *res; int rid; DRM_SPINLOCK_ASSERT(&dev->dev_lock); if (resource >= DRM_MAX_PCI_RESOURCE) { DRM_ERROR("Resource %d too large\n", resource); return 1; } if (dev->pcir[resource] != NULL) { return 0; } DRM_UNLOCK(); rid = PCIR_BAR(resource); res = bus_alloc_resource_any(dev->device, SYS_RES_MEMORY, &rid, RF_SHAREABLE); DRM_LOCK(); if (res == NULL) { DRM_ERROR("Couldn't find resource 0x%x\n", resource); return 1; } if (dev->pcir[resource] == NULL) { dev->pcirid[resource] = rid; dev->pcir[resource] = res; } return 0; } unsigned long drm_get_resource_start(struct drm_device *dev, unsigned int resource) { if (drm_alloc_resource(dev, resource) != 0) return 0; return rman_get_start(dev->pcir[resource]); } unsigned long drm_get_resource_len(struct drm_device *dev, unsigned int resource) { if (drm_alloc_resource(dev, resource) != 0) return 0; return rman_get_size(dev->pcir[resource]); } int drm_addmap(struct drm_device * dev, unsigned long offset, unsigned long size, enum drm_map_type type, enum drm_map_flags flags, drm_local_map_t **map_ptr) { drm_local_map_t *map; int align; /*drm_agp_mem_t *entry; int valid;*/ /* 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 ((flags & _DRM_REMOVABLE) && type != _DRM_SHM) { DRM_ERROR("Requested removable map for non-DRM_SHM\n"); return EINVAL; } if ((offset & PAGE_MASK) || (size & PAGE_MASK)) { DRM_ERROR("offset/size not page aligned: 0x%lx/0x%lx\n", offset, size); return EINVAL; } if (offset + size < offset) { DRM_ERROR("offset and size wrap around: 0x%lx/0x%lx\n", offset, size); return EINVAL; } DRM_DEBUG("offset = 0x%08lx, size = 0x%08lx, type = %d\n", offset, size, type); /* Check if this is just another version of a kernel-allocated map, and * just hand that back if so. */ if (type == _DRM_REGISTERS || type == _DRM_FRAME_BUFFER || type == _DRM_SHM) { TAILQ_FOREACH(map, &dev->maplist, link) { if (map->type == type && (map->offset == offset || (map->type == _DRM_SHM && map->flags == _DRM_CONTAINS_LOCK))) { map->size = size; DRM_DEBUG("Found kernel map %d\n", type); goto done; } } } DRM_UNLOCK(); /* Allocate a new map structure, fill it in, and do any type-specific * initialization necessary. */ map = malloc(sizeof(*map), DRM_MEM_MAPS, M_ZERO | M_NOWAIT); if (!map) { DRM_LOCK(); return ENOMEM; } map->offset = offset; map->size = size; map->type = type; map->flags = flags; map->handle = (void *)((unsigned long)alloc_unr(dev->map_unrhdr) << DRM_MAP_HANDLE_SHIFT); switch (map->type) { case _DRM_REGISTERS: map->virtual = drm_ioremap(dev, map); if (!(map->flags & _DRM_WRITE_COMBINING)) break; /* FALLTHROUGH */ case _DRM_FRAME_BUFFER: if (drm_mtrr_add(map->offset, map->size, DRM_MTRR_WC) == 0) map->mtrr = 1; break; case _DRM_SHM: map->virtual = malloc(map->size, DRM_MEM_MAPS, M_NOWAIT); DRM_DEBUG("%lu %d %p\n", map->size, drm_order(map->size), map->virtual); if (!map->virtual) { free(map, DRM_MEM_MAPS); DRM_LOCK(); return ENOMEM; } map->offset = (unsigned long)map->virtual; if (map->flags & _DRM_CONTAINS_LOCK) { /* Prevent a 2nd X Server from creating a 2nd lock */ DRM_LOCK(); if (dev->lock.hw_lock != NULL) { DRM_UNLOCK(); free(map->virtual, DRM_MEM_MAPS); free(map, DRM_MEM_MAPS); return EBUSY; } dev->lock.hw_lock = map->virtual; /* Pointer to lock */ DRM_UNLOCK(); } break; case _DRM_AGP: /*valid = 0;*/ /* In some cases (i810 driver), user space may have already * added the AGP base itself, because dev->agp->base previously * only got set during AGP enable. So, only add the base * address if the map's offset isn't already within the * aperture. */ if (map->offset < dev->agp->base || map->offset > dev->agp->base + dev->agp->info.ai_aperture_size - 1) { map->offset += dev->agp->base; } map->mtrr = dev->agp->mtrr; /* for getmap */ /*for (entry = dev->agp->memory; entry; entry = entry->next) { if ((map->offset >= entry->bound) && (map->offset + map->size <= entry->bound + entry->pages * PAGE_SIZE)) { valid = 1; break; } } if (!valid) { free(map, DRM_MEM_MAPS); DRM_LOCK(); return EACCES; }*/ break; case _DRM_SCATTER_GATHER: if (!dev->sg) { free(map, DRM_MEM_MAPS); DRM_LOCK(); return EINVAL; } map->virtual = (void *)(dev->sg->vaddr + offset); map->offset = dev->sg->vaddr + offset; break; case _DRM_CONSISTENT: /* Unfortunately, we don't get any alignment specification from * the caller, so we have to guess. drm_pci_alloc requires * a power-of-two alignment, so try to align the bus address of * the map to it size if possible, otherwise just assume * PAGE_SIZE alignment. */ align = map->size; if ((align & (align - 1)) != 0) align = PAGE_SIZE; map->dmah = drm_pci_alloc(dev, map->size, align, 0xfffffffful); if (map->dmah == NULL) { free(map, DRM_MEM_MAPS); DRM_LOCK(); return ENOMEM; } map->virtual = map->dmah->vaddr; map->offset = map->dmah->busaddr; break; default: DRM_ERROR("Bad map type %d\n", map->type); free(map, DRM_MEM_MAPS); DRM_LOCK(); return EINVAL; } DRM_LOCK(); TAILQ_INSERT_TAIL(&dev->maplist, map, link); done: /* Jumped to, with lock held, when a kernel map is found. */ DRM_DEBUG("Added map %d 0x%lx/0x%lx\n", map->type, map->offset, map->size); *map_ptr = map; return 0; } int drm_addmap_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_map *request = data; drm_local_map_t *map; int err; if (!(dev->flags & (FREAD|FWRITE))) return EACCES; /* Require read/write */ if (!DRM_SUSER(DRM_CURPROC) && request->type != _DRM_AGP) return EACCES; DRM_LOCK(); err = drm_addmap(dev, request->offset, request->size, request->type, request->flags, &map); DRM_UNLOCK(); if (err != 0) return err; request->offset = map->offset; request->size = map->size; request->type = map->type; request->flags = map->flags; request->mtrr = map->mtrr; request->handle = (void *)map->handle; return 0; } void drm_rmmap(struct drm_device *dev, drm_local_map_t *map) { DRM_SPINLOCK_ASSERT(&dev->dev_lock); if (map == NULL) return; TAILQ_REMOVE(&dev->maplist, map, link); switch (map->type) { case _DRM_REGISTERS: if (map->bsr == NULL) drm_ioremapfree(map); /* FALLTHROUGH */ case _DRM_FRAME_BUFFER: if (map->mtrr) { int __unused retcode; retcode = drm_mtrr_del(0, map->offset, map->size, DRM_MTRR_WC); DRM_DEBUG("mtrr_del = %d\n", retcode); } break; case _DRM_SHM: free(map->virtual, DRM_MEM_MAPS); break; case _DRM_AGP: case _DRM_SCATTER_GATHER: break; case _DRM_CONSISTENT: drm_pci_free(dev, map->dmah); break; default: DRM_ERROR("Bad map type %d\n", map->type); break; } if (map->bsr != NULL) { bus_release_resource(dev->device, SYS_RES_MEMORY, map->rid, map->bsr); } DRM_UNLOCK(); if (map->handle) free_unr(dev->map_unrhdr, (unsigned long)map->handle >> DRM_MAP_HANDLE_SHIFT); DRM_LOCK(); free(map, DRM_MEM_MAPS); } /* Remove a map private from list and deallocate resources if the mapping * isn't in use. */ int drm_rmmap_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { drm_local_map_t *map; struct drm_map *request = data; DRM_LOCK(); TAILQ_FOREACH(map, &dev->maplist, link) { if (map->handle == request->handle && map->flags & _DRM_REMOVABLE) break; } /* No match found. */ if (map == NULL) { DRM_UNLOCK(); return EINVAL; } drm_rmmap(dev, map); DRM_UNLOCK(); return 0; } static void drm_cleanup_buf_error(struct drm_device *dev, drm_buf_entry_t *entry) { int i; if (entry->seg_count) { for (i = 0; i < entry->seg_count; i++) { drm_pci_free(dev, entry->seglist[i]); } free(entry->seglist, DRM_MEM_SEGS); entry->seg_count = 0; } if (entry->buf_count) { for (i = 0; i < entry->buf_count; i++) { free(entry->buflist[i].dev_private, DRM_MEM_BUFS); } free(entry->buflist, DRM_MEM_BUFS); entry->buf_count = 0; } } static int drm_do_addbufs_agp(struct drm_device *dev, struct drm_buf_desc *request) { drm_device_dma_t *dma = dev->dma; drm_buf_entry_t *entry; /*drm_agp_mem_t *agp_entry; int valid*/ 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; count = request->count; order = drm_order(request->size); size = 1 << order; alignment = (request->flags & _DRM_PAGE_ALIGN) ? round_page(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: 0x%lx\n", agp_offset); DRM_DEBUG("alignment: %d\n", alignment); DRM_DEBUG("page_order: %d\n", page_order); DRM_DEBUG("total: %d\n", total); /* Make sure buffers are located in AGP memory that we own */ /* Breaks MGA due to drm_alloc_agp not setting up entries for the * memory. Safe to ignore for now because these ioctls are still * root-only. */ /*valid = 0; for (agp_entry = dev->agp->memory; agp_entry; agp_entry = agp_entry->next) { if ((agp_offset >= agp_entry->bound) && (agp_offset + total * count <= agp_entry->bound + agp_entry->pages * PAGE_SIZE)) { valid = 1; break; } } if (!valid) { DRM_DEBUG("zone invalid\n"); return EINVAL; }*/ entry = &dma->bufs[order]; entry->buflist = malloc(count * sizeof(*entry->buflist), DRM_MEM_BUFS, M_NOWAIT | M_ZERO); if (!entry->buflist) { return ENOMEM; } 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->pending = 0; buf->file_priv = NULL; buf->dev_priv_size = dev->driver->buf_priv_size; buf->dev_private = malloc(buf->dev_priv_size, DRM_MEM_BUFS, M_NOWAIT | M_ZERO); if (buf->dev_private == NULL) { /* Set count correctly so we free the proper amount. */ entry->buf_count = count; drm_cleanup_buf_error(dev, entry); return ENOMEM; } offset += alignment; entry->buf_count++; byte_count += PAGE_SIZE << page_order; } DRM_DEBUG("byte_count: %d\n", byte_count); temp_buflist = realloc(dma->buflist, (dma->buf_count + entry->buf_count) * sizeof(*dma->buflist), DRM_MEM_BUFS, M_NOWAIT); if (temp_buflist == NULL) { /* Free the entry because it isn't valid */ drm_cleanup_buf_error(dev, entry); 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); request->count = entry->buf_count; request->size = size; dma->flags = _DRM_DMA_USE_AGP; return 0; } static int drm_do_addbufs_pci(struct drm_device *dev, struct drm_buf_desc *request) { drm_device_dma_t *dma = dev->dma; int count; int order; int size; int total; int page_order; drm_buf_entry_t *entry; 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; count = request->count; order = drm_order(request->size); size = 1 << order; DRM_DEBUG("count=%d, size=%d (%d), order=%d\n", request->count, request->size, size, order); alignment = (request->flags & _DRM_PAGE_ALIGN) ? round_page(size) : size; page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0; total = PAGE_SIZE << page_order; entry = &dma->bufs[order]; entry->buflist = malloc(count * sizeof(*entry->buflist), DRM_MEM_BUFS, M_NOWAIT | M_ZERO); entry->seglist = malloc(count * sizeof(*entry->seglist), DRM_MEM_SEGS, M_NOWAIT | M_ZERO); /* Keep the original pagelist until we know all the allocations * have succeeded */ temp_pagelist = malloc((dma->page_count + (count << page_order)) * sizeof(*dma->pagelist), DRM_MEM_PAGES, M_NOWAIT); if (entry->buflist == NULL || entry->seglist == NULL || temp_pagelist == NULL) { free(temp_pagelist, DRM_MEM_PAGES); free(entry->seglist, DRM_MEM_SEGS); free(entry->buflist, DRM_MEM_BUFS); 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) { DRM_SPINUNLOCK(&dev->dma_lock); drm_dma_handle_t *dmah = drm_pci_alloc(dev, size, alignment, 0xfffffffful); DRM_SPINLOCK(&dev->dma_lock); if (dmah == NULL) { /* Set count correctly so we free the proper amount. */ entry->buf_count = count; entry->seg_count = count; drm_cleanup_buf_error(dev, entry); free(temp_pagelist, DRM_MEM_PAGES); return ENOMEM; } entry->seglist[entry->seg_count++] = dmah; for (i = 0; i < (1 << page_order); i++) { DRM_DEBUG("page %d @ %p\n", dma->page_count + page_count, (char *)dmah->vaddr + PAGE_SIZE * i); temp_pagelist[dma->page_count + page_count++] = (long)dmah->vaddr + 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 = ((char *)dmah->vaddr + offset); buf->bus_address = dmah->busaddr + offset; buf->next = NULL; buf->pending = 0; buf->file_priv = NULL; buf->dev_priv_size = dev->driver->buf_priv_size; buf->dev_private = malloc(buf->dev_priv_size, DRM_MEM_BUFS, M_NOWAIT | M_ZERO); if (buf->dev_private == NULL) { /* Set count correctly so we free the proper amount. */ entry->buf_count = count; entry->seg_count = count; drm_cleanup_buf_error(dev, entry); free(temp_pagelist, DRM_MEM_PAGES); return ENOMEM; } DRM_DEBUG("buffer %d @ %p\n", entry->buf_count, buf->address); } byte_count += PAGE_SIZE << page_order; } temp_buflist = realloc(dma->buflist, (dma->buf_count + entry->buf_count) * sizeof(*dma->buflist), DRM_MEM_BUFS, M_NOWAIT); if (temp_buflist == NULL) { /* Free the entry because it isn't valid */ drm_cleanup_buf_error(dev, entry); free(temp_pagelist, DRM_MEM_PAGES); 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. */ free(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); request->count = entry->buf_count; request->size = size; return 0; } static int drm_do_addbufs_sg(struct drm_device *dev, struct drm_buf_desc *request) { drm_device_dma_t *dma = dev->dma; 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; count = request->count; order = drm_order(request->size); size = 1 << order; alignment = (request->flags & _DRM_PAGE_ALIGN) ? round_page(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: %ld\n", agp_offset); DRM_DEBUG("alignment: %d\n", alignment); DRM_DEBUG("page_order: %d\n", page_order); DRM_DEBUG("total: %d\n", total); entry = &dma->bufs[order]; entry->buflist = malloc(count * sizeof(*entry->buflist), DRM_MEM_BUFS, M_NOWAIT | M_ZERO); if (entry->buflist == NULL) return ENOMEM; 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->vaddr); buf->next = NULL; buf->pending = 0; buf->file_priv = NULL; buf->dev_priv_size = dev->driver->buf_priv_size; buf->dev_private = malloc(buf->dev_priv_size, DRM_MEM_BUFS, M_NOWAIT | M_ZERO); if (buf->dev_private == NULL) { /* Set count correctly so we free the proper amount. */ entry->buf_count = count; drm_cleanup_buf_error(dev, entry); return ENOMEM; } 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 = realloc(dma->buflist, (dma->buf_count + entry->buf_count) * sizeof(*dma->buflist), DRM_MEM_BUFS, M_NOWAIT); if (temp_buflist == NULL) { /* Free the entry because it isn't valid */ drm_cleanup_buf_error(dev, entry); 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); request->count = entry->buf_count; request->size = size; dma->flags = _DRM_DMA_USE_SG; return 0; } int drm_addbufs_agp(struct drm_device *dev, struct drm_buf_desc *request) { int order, ret; if (request->count < 0 || request->count > 4096) return EINVAL; order = drm_order(request->size); if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) return EINVAL; DRM_SPINLOCK(&dev->dma_lock); /* No more allocations after first buffer-using ioctl. */ if (dev->buf_use != 0) { DRM_SPINUNLOCK(&dev->dma_lock); return EBUSY; } /* No more than one allocation per order */ if (dev->dma->bufs[order].buf_count != 0) { DRM_SPINUNLOCK(&dev->dma_lock); return ENOMEM; } ret = drm_do_addbufs_agp(dev, request); DRM_SPINUNLOCK(&dev->dma_lock); return ret; } int drm_addbufs_sg(struct drm_device *dev, struct drm_buf_desc *request) { int order, ret; if (!DRM_SUSER(DRM_CURPROC)) return EACCES; if (request->count < 0 || request->count > 4096) return EINVAL; order = drm_order(request->size); if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) return EINVAL; DRM_SPINLOCK(&dev->dma_lock); /* No more allocations after first buffer-using ioctl. */ if (dev->buf_use != 0) { DRM_SPINUNLOCK(&dev->dma_lock); return EBUSY; } /* No more than one allocation per order */ if (dev->dma->bufs[order].buf_count != 0) { DRM_SPINUNLOCK(&dev->dma_lock); return ENOMEM; } ret = drm_do_addbufs_sg(dev, request); DRM_SPINUNLOCK(&dev->dma_lock); return ret; } int drm_addbufs_pci(struct drm_device *dev, struct drm_buf_desc *request) { int order, ret; if (!DRM_SUSER(DRM_CURPROC)) return EACCES; if (request->count < 0 || request->count > 4096) return EINVAL; order = drm_order(request->size); if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) return EINVAL; DRM_SPINLOCK(&dev->dma_lock); /* No more allocations after first buffer-using ioctl. */ if (dev->buf_use != 0) { DRM_SPINUNLOCK(&dev->dma_lock); return EBUSY; } /* No more than one allocation per order */ if (dev->dma->bufs[order].buf_count != 0) { DRM_SPINUNLOCK(&dev->dma_lock); return ENOMEM; } ret = drm_do_addbufs_pci(dev, request); DRM_SPINUNLOCK(&dev->dma_lock); return ret; } int drm_addbufs(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_buf_desc *request = data; int err; if (request->flags & _DRM_AGP_BUFFER) err = drm_addbufs_agp(dev, request); else if (request->flags & _DRM_SG_BUFFER) err = drm_addbufs_sg(dev, request); else err = drm_addbufs_pci(dev, request); return err; } int drm_infobufs(struct drm_device *dev, void *data, struct drm_file *file_priv) { drm_device_dma_t *dma = dev->dma; struct drm_buf_info *request = data; int i; int count; int retcode = 0; DRM_SPINLOCK(&dev->dma_lock); ++dev->buf_use; /* Can't allocate more after this call */ DRM_SPINUNLOCK(&dev->dma_lock); 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) { struct drm_buf_desc from; from.count = dma->bufs[i].buf_count; from.size = dma->bufs[i].buf_size; from.low_mark = dma->bufs[i].freelist.low_mark; from.high_mark = dma->bufs[i].freelist.high_mark; if (DRM_COPY_TO_USER(&request->list[count], &from, sizeof(struct drm_buf_desc)) != 0) { retcode = EFAULT; break; } 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; return retcode; } int drm_markbufs(struct drm_device *dev, void *data, struct drm_file *file_priv) { drm_device_dma_t *dma = dev->dma; struct drm_buf_desc *request = data; int order; DRM_DEBUG("%d, %d, %d\n", request->size, request->low_mark, request->high_mark); order = drm_order(request->size); if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER || request->low_mark < 0 || request->high_mark < 0) { return EINVAL; } DRM_SPINLOCK(&dev->dma_lock); if (request->low_mark > dma->bufs[order].buf_count || request->high_mark > dma->bufs[order].buf_count) { DRM_SPINUNLOCK(&dev->dma_lock); return EINVAL; } dma->bufs[order].freelist.low_mark = request->low_mark; dma->bufs[order].freelist.high_mark = request->high_mark; DRM_SPINUNLOCK(&dev->dma_lock); return 0; } int drm_freebufs(struct drm_device *dev, void *data, struct drm_file *file_priv) { drm_device_dma_t *dma = dev->dma; struct drm_buf_free *request = data; int i; int idx; drm_buf_t *buf; int retcode = 0; DRM_DEBUG("%d\n", request->count); DRM_SPINLOCK(&dev->dma_lock); for (i = 0; i < request->count; i++) { if (DRM_COPY_FROM_USER(&idx, &request->list[i], sizeof(idx))) { retcode = EFAULT; break; } if (idx < 0 || idx >= dma->buf_count) { DRM_ERROR("Index %d (of %d max)\n", idx, dma->buf_count - 1); retcode = EINVAL; break; } buf = dma->buflist[idx]; if (buf->file_priv != file_priv) { DRM_ERROR("Process %d freeing buffer not owned\n", DRM_CURRENTPID); retcode = EINVAL; break; } drm_free_buffer(dev, buf); } DRM_SPINUNLOCK(&dev->dma_lock); return retcode; } int drm_mapbufs(struct drm_device *dev, void *data, struct drm_file *file_priv) { drm_device_dma_t *dma = dev->dma; int retcode = 0; const int zero = 0; vm_offset_t address; struct vmspace *vms; vm_ooffset_t foff; vm_size_t size; vm_offset_t vaddr; struct drm_buf_map *request = data; int i; vms = DRM_CURPROC->td_proc->p_vmspace; DRM_SPINLOCK(&dev->dma_lock); dev->buf_use++; /* Can't allocate more after this call */ DRM_SPINUNLOCK(&dev->dma_lock); if (request->count < dma->buf_count) goto done; if ((drm_core_has_AGP(dev) && (dma->flags & _DRM_DMA_USE_AGP)) || (drm_core_check_feature(dev, DRIVER_SG) && (dma->flags & _DRM_DMA_USE_SG))) { drm_local_map_t *map = dev->agp_buffer_map; if (map == NULL) { retcode = EINVAL; goto done; } size = round_page(map->size); foff = (unsigned long)map->handle; } else { size = round_page(dma->byte_count), foff = 0; } vaddr = round_page((vm_offset_t)vms->vm_daddr + MAXDSIZ); -#if __FreeBSD_version >= 600023 retcode = vm_mmap(&vms->vm_map, &vaddr, size, VM_PROT_READ | VM_PROT_WRITE, VM_PROT_ALL, MAP_SHARED | MAP_NOSYNC, OBJT_DEVICE, dev->devnode, foff); -#else - retcode = vm_mmap(&vms->vm_map, &vaddr, size, VM_PROT_READ | - VM_PROT_WRITE, VM_PROT_ALL, MAP_SHARED | MAP_NOSYNC, - SLIST_FIRST(&dev->devnode->si_hlist), foff); -#endif if (retcode) goto done; request->virtual = (void *)vaddr; for (i = 0; i < dma->buf_count; i++) { if (DRM_COPY_TO_USER(&request->list[i].idx, &dma->buflist[i]->idx, sizeof(request->list[0].idx))) { retcode = EFAULT; goto done; } if (DRM_COPY_TO_USER(&request->list[i].total, &dma->buflist[i]->total, sizeof(request->list[0].total))) { retcode = EFAULT; goto done; } if (DRM_COPY_TO_USER(&request->list[i].used, &zero, sizeof(zero))) { retcode = EFAULT; goto done; } address = vaddr + dma->buflist[i]->offset; /* *** */ if (DRM_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); return retcode; } /* * Compute order. Can be made faster. */ int drm_order(unsigned long size) { int order; if (size == 0) return 0; order = flsl(size) - 1; if (size & ~(1ul << order)) ++order; return order; } Index: head/sys/dev/drm/drm_drv.c =================================================================== --- head/sys/dev/drm/drm_drv.c (revision 283998) +++ head/sys/dev/drm/drm_drv.c (revision 283999) @@ -1,855 +1,833 @@ /*- * 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. * * Authors: * Rickard E. (Rik) Faith * Gareth Hughes * */ #include __FBSDID("$FreeBSD$"); /** @file drm_drv.c * The catch-all file for DRM device support, including module setup/teardown, * open/close, and ioctl dispatch. */ #include #include "dev/drm/drmP.h" #include "dev/drm/drm.h" #include "dev/drm/drm_sarea.h" #ifdef DRM_DEBUG_DEFAULT_ON int drm_debug_flag = 1; #else int drm_debug_flag = 0; #endif static int drm_load(struct drm_device *dev); static void drm_unload(struct drm_device *dev); static drm_pci_id_list_t *drm_find_description(int vendor, int device, drm_pci_id_list_t *idlist); MODULE_VERSION(drm, 1); MODULE_DEPEND(drm, agp, 1, 1, 1); MODULE_DEPEND(drm, pci, 1, 1, 1); MODULE_DEPEND(drm, mem, 1, 1, 1); static drm_ioctl_desc_t drm_ioctls[256] = { DRM_IOCTL_DEF(DRM_IOCTL_VERSION, drm_version, 0), DRM_IOCTL_DEF(DRM_IOCTL_GET_UNIQUE, drm_getunique, 0), DRM_IOCTL_DEF(DRM_IOCTL_GET_MAGIC, drm_getmagic, 0), DRM_IOCTL_DEF(DRM_IOCTL_IRQ_BUSID, drm_irq_by_busid, DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_GET_MAP, drm_getmap, 0), DRM_IOCTL_DEF(DRM_IOCTL_GET_CLIENT, drm_getclient, 0), DRM_IOCTL_DEF(DRM_IOCTL_GET_STATS, drm_getstats, 0), DRM_IOCTL_DEF(DRM_IOCTL_SET_VERSION, drm_setversion, DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_SET_UNIQUE, drm_setunique, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_BLOCK, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_UNBLOCK, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_AUTH_MAGIC, drm_authmagic, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_ADD_MAP, drm_addmap_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_RM_MAP, drm_rmmap_ioctl, DRM_AUTH), DRM_IOCTL_DEF(DRM_IOCTL_SET_SAREA_CTX, drm_setsareactx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_GET_SAREA_CTX, drm_getsareactx, DRM_AUTH), DRM_IOCTL_DEF(DRM_IOCTL_ADD_CTX, drm_addctx, DRM_AUTH|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_RM_CTX, drm_rmctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_MOD_CTX, drm_modctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_GET_CTX, drm_getctx, DRM_AUTH), DRM_IOCTL_DEF(DRM_IOCTL_SWITCH_CTX, drm_switchctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_NEW_CTX, drm_newctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_RES_CTX, drm_resctx, DRM_AUTH), DRM_IOCTL_DEF(DRM_IOCTL_ADD_DRAW, drm_adddraw, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_RM_DRAW, drm_rmdraw, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_LOCK, drm_lock, DRM_AUTH), DRM_IOCTL_DEF(DRM_IOCTL_UNLOCK, drm_unlock, DRM_AUTH), DRM_IOCTL_DEF(DRM_IOCTL_FINISH, drm_noop, DRM_AUTH), DRM_IOCTL_DEF(DRM_IOCTL_ADD_BUFS, drm_addbufs, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_MARK_BUFS, drm_markbufs, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_INFO_BUFS, drm_infobufs, DRM_AUTH), DRM_IOCTL_DEF(DRM_IOCTL_MAP_BUFS, drm_mapbufs, DRM_AUTH), DRM_IOCTL_DEF(DRM_IOCTL_FREE_BUFS, drm_freebufs, DRM_AUTH), DRM_IOCTL_DEF(DRM_IOCTL_DMA, drm_dma, DRM_AUTH), DRM_IOCTL_DEF(DRM_IOCTL_CONTROL, drm_control, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_AGP_ACQUIRE, drm_agp_acquire_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_AGP_RELEASE, drm_agp_release_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_AGP_ENABLE, drm_agp_enable_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_AGP_INFO, drm_agp_info_ioctl, DRM_AUTH), DRM_IOCTL_DEF(DRM_IOCTL_AGP_ALLOC, drm_agp_alloc_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_AGP_FREE, drm_agp_free_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_AGP_BIND, drm_agp_bind_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_AGP_UNBIND, drm_agp_unbind_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_SG_ALLOC, drm_sg_alloc_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_SG_FREE, drm_sg_free, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_WAIT_VBLANK, drm_wait_vblank, 0), DRM_IOCTL_DEF(DRM_IOCTL_MODESET_CTL, drm_modeset_ctl, 0), DRM_IOCTL_DEF(DRM_IOCTL_UPDATE_DRAW, drm_update_draw, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), }; static struct cdevsw drm_cdevsw = { .d_version = D_VERSION, .d_open = drm_open, .d_read = drm_read, .d_ioctl = drm_ioctl, .d_poll = drm_poll, .d_mmap = drm_mmap, .d_name = "drm", .d_flags = D_TRACKCLOSE }; static int drm_msi = 1; /* Enable by default. */ SYSCTL_NODE(_hw, OID_AUTO, drm, CTLFLAG_RW, NULL, "DRM device"); SYSCTL_INT(_hw_drm, OID_AUTO, msi, CTLFLAG_RDTUN, &drm_msi, 1, "Enable MSI interrupts for drm devices"); static struct drm_msi_blacklist_entry drm_msi_blacklist[] = { {0x8086, 0x2772}, /* Intel i945G */ \ {0x8086, 0x27A2}, /* Intel i945GM */ \ {0x8086, 0x27AE}, /* Intel i945GME */ \ {0, 0} }; static int drm_msi_is_blacklisted(int vendor, int device) { int i = 0; for (i = 0; drm_msi_blacklist[i].vendor != 0; i++) { if ((drm_msi_blacklist[i].vendor == vendor) && (drm_msi_blacklist[i].device == device)) { return 1; } } return 0; } int drm_probe(device_t kdev, drm_pci_id_list_t *idlist) { drm_pci_id_list_t *id_entry; int vendor, device; -#if __FreeBSD_version < 700010 - device_t realdev; - - if (!strcmp(device_get_name(kdev), "drmsub")) - realdev = device_get_parent(kdev); - else - realdev = kdev; - vendor = pci_get_vendor(realdev); - device = pci_get_device(realdev); -#else vendor = pci_get_vendor(kdev); device = pci_get_device(kdev); -#endif if (pci_get_class(kdev) != PCIC_DISPLAY || pci_get_subclass(kdev) != PCIS_DISPLAY_VGA) return ENXIO; id_entry = drm_find_description(vendor, device, idlist); if (id_entry != NULL) { if (!device_get_desc(kdev)) { DRM_DEBUG("desc : %s\n", device_get_desc(kdev)); device_set_desc(kdev, id_entry->name); } return 0; } return ENXIO; } int drm_attach(device_t kdev, drm_pci_id_list_t *idlist) { struct drm_device *dev; drm_pci_id_list_t *id_entry; int unit, msicount; unit = device_get_unit(kdev); dev = device_get_softc(kdev); -#if __FreeBSD_version < 700010 - if (!strcmp(device_get_name(kdev), "drmsub")) - dev->device = device_get_parent(kdev); - else - dev->device = kdev; -#else dev->device = kdev; -#endif dev->devnode = make_dev(&drm_cdevsw, 0, DRM_DEV_UID, DRM_DEV_GID, DRM_DEV_MODE, "dri/card%d", unit); dev->devnode->si_drv1 = dev; -#if __FreeBSD_version >= 700053 dev->pci_domain = pci_get_domain(dev->device); -#else - dev->pci_domain = 0; -#endif dev->pci_bus = pci_get_bus(dev->device); dev->pci_slot = pci_get_slot(dev->device); dev->pci_func = pci_get_function(dev->device); dev->pci_vendor = pci_get_vendor(dev->device); dev->pci_device = pci_get_device(dev->device); if (drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) { if (drm_msi && !drm_msi_is_blacklisted(dev->pci_vendor, dev->pci_device)) { msicount = pci_msi_count(dev->device); DRM_DEBUG("MSI count = %d\n", msicount); if (msicount > 1) msicount = 1; if (pci_alloc_msi(dev->device, &msicount) == 0) { DRM_INFO("MSI enabled %d message(s)\n", msicount); dev->msi_enabled = 1; dev->irqrid = 1; } } dev->irqr = bus_alloc_resource_any(dev->device, SYS_RES_IRQ, &dev->irqrid, RF_SHAREABLE); if (!dev->irqr) { return ENOENT; } dev->irq = (int) rman_get_start(dev->irqr); } mtx_init(&dev->dev_lock, "drmdev", NULL, MTX_DEF); mtx_init(&dev->irq_lock, "drmirq", NULL, MTX_DEF); mtx_init(&dev->vbl_lock, "drmvbl", NULL, MTX_DEF); mtx_init(&dev->drw_lock, "drmdrw", NULL, MTX_DEF); id_entry = drm_find_description(dev->pci_vendor, dev->pci_device, idlist); dev->id_entry = id_entry; return drm_load(dev); } int drm_detach(device_t kdev) { struct drm_device *dev; dev = device_get_softc(kdev); drm_unload(dev); if (dev->irqr) { bus_release_resource(dev->device, SYS_RES_IRQ, dev->irqrid, dev->irqr); if (dev->msi_enabled) { pci_release_msi(dev->device); DRM_INFO("MSI released\n"); } } return 0; } #ifndef DRM_DEV_NAME #define DRM_DEV_NAME "drm" #endif devclass_t drm_devclass; drm_pci_id_list_t *drm_find_description(int vendor, int device, drm_pci_id_list_t *idlist) { int i = 0; for (i = 0; idlist[i].vendor != 0; i++) { if ((idlist[i].vendor == vendor) && ((idlist[i].device == device) || (idlist[i].device == 0))) { return &idlist[i]; } } return NULL; } static int drm_firstopen(struct drm_device *dev) { drm_local_map_t *map; int i; DRM_SPINLOCK_ASSERT(&dev->dev_lock); /* prebuild the SAREA */ i = drm_addmap(dev, 0, SAREA_MAX, _DRM_SHM, _DRM_CONTAINS_LOCK, &map); if (i != 0) return i; if (dev->driver->firstopen) dev->driver->firstopen(dev); dev->buf_use = 0; if (drm_core_check_feature(dev, DRIVER_HAVE_DMA)) { i = drm_dma_setup(dev); if (i != 0) return i; } for (i = 0; i < DRM_HASH_SIZE; i++) { dev->magiclist[i].head = NULL; dev->magiclist[i].tail = NULL; } dev->lock.lock_queue = 0; dev->irq_enabled = 0; dev->context_flag = 0; dev->last_context = 0; dev->if_version = 0; dev->buf_sigio = NULL; DRM_DEBUG("\n"); return 0; } static int drm_lastclose(struct drm_device *dev) { drm_magic_entry_t *pt, *next; drm_local_map_t *map, *mapsave; int i; DRM_SPINLOCK_ASSERT(&dev->dev_lock); DRM_DEBUG("\n"); if (dev->driver->lastclose != NULL) dev->driver->lastclose(dev); if (dev->irq_enabled) drm_irq_uninstall(dev); if (dev->unique) { free(dev->unique, DRM_MEM_DRIVER); dev->unique = NULL; dev->unique_len = 0; } /* Clear pid list */ for (i = 0; i < DRM_HASH_SIZE; i++) { for (pt = dev->magiclist[i].head; pt; pt = next) { next = pt->next; free(pt, DRM_MEM_MAGIC); } dev->magiclist[i].head = dev->magiclist[i].tail = NULL; } DRM_UNLOCK(); drm_drawable_free_all(dev); DRM_LOCK(); /* Clear AGP information */ if (dev->agp) { drm_agp_mem_t *entry; drm_agp_mem_t *nexte; /* Remove AGP resources, but leave dev->agp intact until * drm_unload is called. */ for (entry = dev->agp->memory; entry; entry = nexte) { nexte = entry->next; if (entry->bound) drm_agp_unbind_memory(entry->handle); drm_agp_free_memory(entry->handle); free(entry, DRM_MEM_AGPLISTS); } dev->agp->memory = NULL; if (dev->agp->acquired) drm_agp_release(dev); dev->agp->acquired = 0; dev->agp->enabled = 0; } if (dev->sg != NULL) { drm_sg_cleanup(dev->sg); dev->sg = NULL; } TAILQ_FOREACH_SAFE(map, &dev->maplist, link, mapsave) { if (!(map->flags & _DRM_DRIVER)) drm_rmmap(dev, map); } drm_dma_takedown(dev); if (dev->lock.hw_lock) { dev->lock.hw_lock = NULL; /* SHM removed */ dev->lock.file_priv = NULL; DRM_WAKEUP_INT((void *)&dev->lock.lock_queue); } return 0; } static int drm_load(struct drm_device *dev) { int i, retcode; DRM_DEBUG("\n"); TAILQ_INIT(&dev->maplist); dev->map_unrhdr = new_unrhdr(1, ((1 << DRM_MAP_HANDLE_BITS) - 1), NULL); if (dev->map_unrhdr == NULL) { DRM_ERROR("Couldn't allocate map number allocator\n"); return EINVAL; } drm_mem_init(); drm_sysctl_init(dev); TAILQ_INIT(&dev->files); dev->counters = 6; dev->types[0] = _DRM_STAT_LOCK; dev->types[1] = _DRM_STAT_OPENS; dev->types[2] = _DRM_STAT_CLOSES; dev->types[3] = _DRM_STAT_IOCTLS; dev->types[4] = _DRM_STAT_LOCKS; dev->types[5] = _DRM_STAT_UNLOCKS; for (i = 0; i < DRM_ARRAY_SIZE(dev->counts); i++) atomic_set(&dev->counts[i], 0); if (dev->driver->load != NULL) { DRM_LOCK(); /* Shared code returns -errno. */ retcode = -dev->driver->load(dev, dev->id_entry->driver_private); if (pci_enable_busmaster(dev->device)) DRM_ERROR("Request to enable bus-master failed.\n"); DRM_UNLOCK(); if (retcode != 0) goto error; } if (drm_core_has_AGP(dev)) { if (drm_device_is_agp(dev)) dev->agp = drm_agp_init(); if (drm_core_check_feature(dev, DRIVER_REQUIRE_AGP) && dev->agp == NULL) { DRM_ERROR("Card isn't AGP, or couldn't initialize " "AGP.\n"); retcode = ENOMEM; goto error; } if (dev->agp != NULL && dev->agp->info.ai_aperture_base != 0) { if (drm_mtrr_add(dev->agp->info.ai_aperture_base, dev->agp->info.ai_aperture_size, DRM_MTRR_WC) == 0) dev->agp->mtrr = 1; } } retcode = drm_ctxbitmap_init(dev); if (retcode != 0) { DRM_ERROR("Cannot allocate memory for context bitmap.\n"); goto error; } dev->drw_unrhdr = new_unrhdr(1, INT_MAX, NULL); if (dev->drw_unrhdr == NULL) { DRM_ERROR("Couldn't allocate drawable number allocator\n"); goto error; } DRM_INFO("Initialized %s %d.%d.%d %s\n", dev->driver->name, dev->driver->major, dev->driver->minor, dev->driver->patchlevel, dev->driver->date); return 0; error: drm_sysctl_cleanup(dev); DRM_LOCK(); drm_lastclose(dev); DRM_UNLOCK(); destroy_dev(dev->devnode); mtx_destroy(&dev->drw_lock); mtx_destroy(&dev->vbl_lock); mtx_destroy(&dev->irq_lock); mtx_destroy(&dev->dev_lock); return retcode; } static void drm_unload(struct drm_device *dev) { int i; DRM_DEBUG("\n"); drm_sysctl_cleanup(dev); destroy_dev(dev->devnode); drm_ctxbitmap_cleanup(dev); if (dev->agp && dev->agp->mtrr) { int __unused retcode; retcode = drm_mtrr_del(0, dev->agp->info.ai_aperture_base, dev->agp->info.ai_aperture_size, DRM_MTRR_WC); DRM_DEBUG("mtrr_del = %d", retcode); } drm_vblank_cleanup(dev); DRM_LOCK(); drm_lastclose(dev); DRM_UNLOCK(); /* Clean up PCI resources allocated by drm_bufs.c. We're not really * worried about resource consumption while the DRM is inactive (between * lastclose and firstopen or unload) because these aren't actually * taking up KVA, just keeping the PCI resource allocated. */ for (i = 0; i < DRM_MAX_PCI_RESOURCE; i++) { if (dev->pcir[i] == NULL) continue; bus_release_resource(dev->device, SYS_RES_MEMORY, dev->pcirid[i], dev->pcir[i]); dev->pcir[i] = NULL; } if (dev->agp) { free(dev->agp, DRM_MEM_AGPLISTS); dev->agp = NULL; } if (dev->driver->unload != NULL) { DRM_LOCK(); dev->driver->unload(dev); DRM_UNLOCK(); } delete_unrhdr(dev->drw_unrhdr); delete_unrhdr(dev->map_unrhdr); drm_mem_uninit(); if (pci_disable_busmaster(dev->device)) DRM_ERROR("Request to disable bus-master failed.\n"); mtx_destroy(&dev->drw_lock); mtx_destroy(&dev->vbl_lock); mtx_destroy(&dev->irq_lock); mtx_destroy(&dev->dev_lock); } int drm_version(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_version *version = data; int len; #define DRM_COPY( name, value ) \ len = strlen( value ); \ if ( len > name##_len ) len = name##_len; \ name##_len = strlen( value ); \ if ( len && name ) { \ if ( DRM_COPY_TO_USER( name, value, len ) ) \ return EFAULT; \ } version->version_major = dev->driver->major; version->version_minor = dev->driver->minor; version->version_patchlevel = dev->driver->patchlevel; DRM_COPY(version->name, dev->driver->name); DRM_COPY(version->date, dev->driver->date); DRM_COPY(version->desc, dev->driver->desc); return 0; } int drm_open(struct cdev *kdev, int flags, int fmt, DRM_STRUCTPROC *p) { struct drm_device *dev = NULL; int retcode = 0; dev = kdev->si_drv1; DRM_DEBUG("open_count = %d\n", dev->open_count); retcode = drm_open_helper(kdev, flags, fmt, p, dev); if (!retcode) { atomic_inc(&dev->counts[_DRM_STAT_OPENS]); DRM_LOCK(); device_busy(dev->device); if (!dev->open_count++) retcode = drm_firstopen(dev); DRM_UNLOCK(); } return retcode; } void drm_close(void *data) { struct drm_file *file_priv = data; struct drm_device *dev = file_priv->dev; int retcode = 0; DRM_DEBUG("open_count = %d\n", dev->open_count); DRM_LOCK(); if (dev->driver->preclose != NULL) dev->driver->preclose(dev, file_priv); /* ======================================================== * Begin inline drm_release */ DRM_DEBUG("pid = %d, device = 0x%lx, open_count = %d\n", DRM_CURRENTPID, (long)dev->device, dev->open_count); if (dev->lock.hw_lock && _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) && dev->lock.file_priv == file_priv) { DRM_DEBUG("Process %d dead, freeing lock for context %d\n", DRM_CURRENTPID, _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); if (dev->driver->reclaim_buffers_locked != NULL) dev->driver->reclaim_buffers_locked(dev, file_priv); drm_lock_free(&dev->lock, _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); /* FIXME: may require heavy-handed reset of hardware at this point, possibly processed via a callback to the X server. */ } else if (dev->driver->reclaim_buffers_locked != NULL && dev->lock.hw_lock != NULL) { /* The lock is required to reclaim buffers */ for (;;) { if (!dev->lock.hw_lock) { /* Device has been unregistered */ retcode = EINTR; break; } if (drm_lock_take(&dev->lock, DRM_KERNEL_CONTEXT)) { dev->lock.file_priv = file_priv; dev->lock.lock_time = jiffies; atomic_inc(&dev->counts[_DRM_STAT_LOCKS]); break; /* Got lock */ } /* Contention */ retcode = mtx_sleep((void *)&dev->lock.lock_queue, &dev->dev_lock, PCATCH, "drmlk2", 0); if (retcode) break; } if (retcode == 0) { dev->driver->reclaim_buffers_locked(dev, file_priv); drm_lock_free(&dev->lock, DRM_KERNEL_CONTEXT); } } if (drm_core_check_feature(dev, DRIVER_HAVE_DMA) && !dev->driver->reclaim_buffers_locked) drm_reclaim_buffers(dev, file_priv); funsetown(&dev->buf_sigio); if (dev->driver->postclose != NULL) dev->driver->postclose(dev, file_priv); TAILQ_REMOVE(&dev->files, file_priv, link); free(file_priv, DRM_MEM_FILES); /* ======================================================== * End inline drm_release */ atomic_inc(&dev->counts[_DRM_STAT_CLOSES]); device_unbusy(dev->device); if (--dev->open_count == 0) { retcode = drm_lastclose(dev); } DRM_UNLOCK(); } /* drm_ioctl is called whenever a process performs an ioctl on /dev/drm. */ int drm_ioctl(struct cdev *kdev, u_long cmd, caddr_t data, int flags, DRM_STRUCTPROC *p) { struct drm_device *dev = drm_get_device_from_kdev(kdev); int retcode = 0; drm_ioctl_desc_t *ioctl; int (*func)(struct drm_device *dev, void *data, struct drm_file *file_priv); int nr = DRM_IOCTL_NR(cmd); int is_driver_ioctl = 0; struct drm_file *file_priv; retcode = devfs_get_cdevpriv((void **)&file_priv); if (retcode != 0) { DRM_ERROR("can't find authenticator\n"); return EINVAL; } atomic_inc(&dev->counts[_DRM_STAT_IOCTLS]); ++file_priv->ioctl_count; DRM_DEBUG("pid=%d, cmd=0x%02lx, nr=0x%02x, dev 0x%lx, auth=%d\n", DRM_CURRENTPID, cmd, nr, (long)dev->device, file_priv->authenticated); switch (cmd) { case FIONBIO: case FIOASYNC: return 0; case FIOSETOWN: return fsetown(*(int *)data, &dev->buf_sigio); case FIOGETOWN: *(int *) data = fgetown(&dev->buf_sigio); return 0; } if (IOCGROUP(cmd) != DRM_IOCTL_BASE) { DRM_DEBUG("Bad ioctl group 0x%x\n", (int)IOCGROUP(cmd)); return EINVAL; } ioctl = &drm_ioctls[nr]; /* It's not a core DRM ioctl, try driver-specific. */ if (ioctl->func == NULL && nr >= DRM_COMMAND_BASE) { /* The array entries begin at DRM_COMMAND_BASE ioctl nr */ nr -= DRM_COMMAND_BASE; if (nr > dev->driver->max_ioctl) { DRM_DEBUG("Bad driver ioctl number, 0x%x (of 0x%x)\n", nr, dev->driver->max_ioctl); return EINVAL; } ioctl = &dev->driver->ioctls[nr]; is_driver_ioctl = 1; } func = ioctl->func; if (func == NULL) { DRM_DEBUG("no function\n"); return EINVAL; } if (((ioctl->flags & DRM_ROOT_ONLY) && !DRM_SUSER(p)) || ((ioctl->flags & DRM_AUTH) && !file_priv->authenticated) || ((ioctl->flags & DRM_MASTER) && !file_priv->master)) return EACCES; if (is_driver_ioctl) { DRM_LOCK(); /* shared code returns -errno */ retcode = -func(dev, data, file_priv); DRM_UNLOCK(); } else { retcode = func(dev, data, file_priv); } if (retcode != 0) DRM_DEBUG(" returning %d\n", retcode); return retcode; } drm_local_map_t *drm_getsarea(struct drm_device *dev) { drm_local_map_t *map; DRM_SPINLOCK_ASSERT(&dev->dev_lock); TAILQ_FOREACH(map, &dev->maplist, link) { if (map->type == _DRM_SHM && (map->flags & _DRM_CONTAINS_LOCK)) return map; } return NULL; } #if DRM_LINUX #include MODULE_DEPEND(DRIVER_NAME, linux, 1, 1, 1); #define LINUX_IOCTL_DRM_MIN 0x6400 #define LINUX_IOCTL_DRM_MAX 0x64ff static linux_ioctl_function_t drm_linux_ioctl; static struct linux_ioctl_handler drm_handler = {drm_linux_ioctl, LINUX_IOCTL_DRM_MIN, LINUX_IOCTL_DRM_MAX}; SYSINIT(drm_register, SI_SUB_KLD, SI_ORDER_MIDDLE, linux_ioctl_register_handler, &drm_handler); SYSUNINIT(drm_unregister, SI_SUB_KLD, SI_ORDER_MIDDLE, linux_ioctl_unregister_handler, &drm_handler); /* The bits for in/out are switched on Linux */ #define LINUX_IOC_IN IOC_OUT #define LINUX_IOC_OUT IOC_IN static int drm_linux_ioctl(DRM_STRUCTPROC *p, struct linux_ioctl_args* args) { int error; int cmd = args->cmd; args->cmd &= ~(LINUX_IOC_IN | LINUX_IOC_OUT); if (cmd & LINUX_IOC_IN) args->cmd |= IOC_IN; if (cmd & LINUX_IOC_OUT) args->cmd |= IOC_OUT; error = ioctl(p, (struct ioctl_args *)args); return error; } #endif /* DRM_LINUX */ Index: head/sys/dev/drm/drm_irq.c =================================================================== --- head/sys/dev/drm/drm_irq.c (revision 283998) +++ head/sys/dev/drm/drm_irq.c (revision 283999) @@ -1,497 +1,491 @@ /*- * Copyright 2003 Eric Anholt * 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 * ERIC ANHOLT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * Authors: * Eric Anholt * */ #include __FBSDID("$FreeBSD$"); /** @file drm_irq.c * Support code for handling setup/teardown of interrupt handlers and * handing interrupt handlers off to the drivers. */ #include "dev/drm/drmP.h" #include "dev/drm/drm.h" int drm_irq_by_busid(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_irq_busid *irq = data; if ((irq->busnum >> 8) != dev->pci_domain || (irq->busnum & 0xff) != dev->pci_bus || irq->devnum != dev->pci_slot || irq->funcnum != dev->pci_func) return EINVAL; irq->irq = dev->irq; DRM_DEBUG("%d:%d:%d => IRQ %d\n", irq->busnum, irq->devnum, irq->funcnum, irq->irq); return 0; } static irqreturn_t drm_irq_handler_wrap(DRM_IRQ_ARGS) { struct drm_device *dev = arg; DRM_SPINLOCK(&dev->irq_lock); dev->driver->irq_handler(arg); DRM_SPINUNLOCK(&dev->irq_lock); } static void vblank_disable_fn(void *arg) { struct drm_device *dev = (struct drm_device *)arg; int i; /* Make sure that we are called with the lock held */ mtx_assert(&dev->vbl_lock, MA_OWNED); if (callout_pending(&dev->vblank_disable_timer)) { /* callout was reset */ return; } if (!callout_active(&dev->vblank_disable_timer)) { /* callout was stopped */ return; } callout_deactivate(&dev->vblank_disable_timer); DRM_DEBUG("vblank_disable: %s\n", dev->vblank_disable_allowed ? "allowed" : "denied"); if (!dev->vblank_disable_allowed) return; for (i = 0; i < dev->num_crtcs; i++) { if (dev->vblank[i].refcount == 0 && dev->vblank[i].enabled && !dev->vblank[i].inmodeset) { DRM_DEBUG("disabling vblank on crtc %d\n", i); dev->vblank[i].last = dev->driver->get_vblank_counter(dev, i); dev->driver->disable_vblank(dev, i); dev->vblank[i].enabled = 0; } } } void drm_vblank_cleanup(struct drm_device *dev) { /* Bail if the driver didn't call drm_vblank_init() */ if (dev->num_crtcs == 0) return; DRM_SPINLOCK(&dev->vbl_lock); callout_stop(&dev->vblank_disable_timer); DRM_SPINUNLOCK(&dev->vbl_lock); callout_drain(&dev->vblank_disable_timer); DRM_SPINLOCK(&dev->vbl_lock); vblank_disable_fn((void *)dev); DRM_SPINUNLOCK(&dev->vbl_lock); free(dev->vblank, DRM_MEM_DRIVER); dev->num_crtcs = 0; } int drm_vblank_init(struct drm_device *dev, int num_crtcs) { int i, ret = ENOMEM; callout_init_mtx(&dev->vblank_disable_timer, &dev->vbl_lock, 0); dev->num_crtcs = num_crtcs; dev->vblank = malloc(sizeof(struct drm_vblank_info) * num_crtcs, DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); if (!dev->vblank) goto err; DRM_DEBUG("\n"); /* Zero per-crtc vblank stuff */ DRM_SPINLOCK(&dev->vbl_lock); for (i = 0; i < num_crtcs; i++) { DRM_INIT_WAITQUEUE(&dev->vblank[i].queue); dev->vblank[i].refcount = 0; atomic_store_rel_32(&dev->vblank[i].count, 0); } dev->vblank_disable_allowed = 0; DRM_SPINUNLOCK(&dev->vbl_lock); return 0; err: drm_vblank_cleanup(dev); return ret; } int drm_irq_install(struct drm_device *dev) { int crtc, retcode; if (dev->irq == 0 || dev->dev_private == NULL) return EINVAL; DRM_DEBUG("irq=%d\n", dev->irq); DRM_LOCK(); if (dev->irq_enabled) { DRM_UNLOCK(); return EBUSY; } dev->irq_enabled = 1; dev->context_flag = 0; /* Before installing handler */ dev->driver->irq_preinstall(dev); DRM_UNLOCK(); /* Install handler */ -#if __FreeBSD_version >= 700031 retcode = bus_setup_intr(dev->device, dev->irqr, INTR_TYPE_TTY | INTR_MPSAFE, NULL, drm_irq_handler_wrap, dev, &dev->irqh); -#else - retcode = bus_setup_intr(dev->device, dev->irqr, - INTR_TYPE_TTY | INTR_MPSAFE, - drm_irq_handler_wrap, dev, &dev->irqh); -#endif if (retcode != 0) goto err; /* After installing handler */ DRM_LOCK(); dev->driver->irq_postinstall(dev); DRM_UNLOCK(); if (dev->driver->enable_vblank) { DRM_SPINLOCK(&dev->vbl_lock); for( crtc = 0 ; crtc < dev->num_crtcs ; crtc++) { if (dev->driver->enable_vblank(dev, crtc) == 0) { dev->vblank[crtc].enabled = 1; } } callout_reset(&dev->vblank_disable_timer, 5 * DRM_HZ, (timeout_t *)vblank_disable_fn, (void *)dev); DRM_SPINUNLOCK(&dev->vbl_lock); } return 0; err: DRM_LOCK(); dev->irq_enabled = 0; DRM_UNLOCK(); return retcode; } int drm_irq_uninstall(struct drm_device *dev) { int crtc; if (!dev->irq_enabled) return EINVAL; dev->irq_enabled = 0; /* * Wake up any waiters so they don't hang. */ DRM_SPINLOCK(&dev->vbl_lock); for (crtc = 0; crtc < dev->num_crtcs; crtc++) { if (dev->vblank[crtc].enabled) { DRM_WAKEUP(&dev->vblank[crtc].queue); dev->vblank[crtc].last = dev->driver->get_vblank_counter(dev, crtc); dev->vblank[crtc].enabled = 0; } } DRM_SPINUNLOCK(&dev->vbl_lock); DRM_DEBUG("irq=%d\n", dev->irq); dev->driver->irq_uninstall(dev); DRM_UNLOCK(); bus_teardown_intr(dev->device, dev->irqr, dev->irqh); DRM_LOCK(); return 0; } int drm_control(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_control *ctl = data; int err; switch (ctl->func) { case DRM_INST_HANDLER: /* Handle drivers whose DRM used to require IRQ setup but the * no longer does. */ if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) return 0; if (dev->if_version < DRM_IF_VERSION(1, 2) && ctl->irq != dev->irq) return EINVAL; return drm_irq_install(dev); case DRM_UNINST_HANDLER: if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) return 0; DRM_LOCK(); err = drm_irq_uninstall(dev); DRM_UNLOCK(); return err; default: return EINVAL; } } u32 drm_vblank_count(struct drm_device *dev, int crtc) { return atomic_load_acq_32(&dev->vblank[crtc].count); } static void drm_update_vblank_count(struct drm_device *dev, int crtc) { u32 cur_vblank, diff; /* * Interrupts were disabled prior to this call, so deal with counter * wrap if needed. * NOTE! It's possible we lost a full dev->max_vblank_count events * here if the register is small or we had vblank interrupts off for * a long time. */ cur_vblank = dev->driver->get_vblank_counter(dev, crtc); diff = cur_vblank - dev->vblank[crtc].last; if (cur_vblank < dev->vblank[crtc].last) { diff += dev->max_vblank_count; DRM_DEBUG("vblank[%d].last=0x%x, cur_vblank=0x%x => diff=0x%x\n", crtc, dev->vblank[crtc].last, cur_vblank, diff); } DRM_DEBUG("enabling vblank interrupts on crtc %d, missed %d\n", crtc, diff); atomic_add_rel_32(&dev->vblank[crtc].count, diff); } int drm_vblank_get(struct drm_device *dev, int crtc) { int ret = 0; /* Make sure that we are called with the lock held */ mtx_assert(&dev->vbl_lock, MA_OWNED); /* Going from 0->1 means we have to enable interrupts again */ if (++dev->vblank[crtc].refcount == 1 && !dev->vblank[crtc].enabled) { ret = dev->driver->enable_vblank(dev, crtc); DRM_DEBUG("enabling vblank on crtc %d, ret: %d\n", crtc, ret); if (ret) --dev->vblank[crtc].refcount; else { dev->vblank[crtc].enabled = 1; drm_update_vblank_count(dev, crtc); } } if (dev->vblank[crtc].enabled) dev->vblank[crtc].last = dev->driver->get_vblank_counter(dev, crtc); return ret; } void drm_vblank_put(struct drm_device *dev, int crtc) { /* Make sure that we are called with the lock held */ mtx_assert(&dev->vbl_lock, MA_OWNED); KASSERT(dev->vblank[crtc].refcount > 0, ("invalid refcount")); /* Last user schedules interrupt disable */ if (--dev->vblank[crtc].refcount == 0) callout_reset(&dev->vblank_disable_timer, 5 * DRM_HZ, (timeout_t *)vblank_disable_fn, (void *)dev); } int drm_modeset_ctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_modeset_ctl *modeset = data; int crtc, ret = 0; /* If drm_vblank_init() hasn't been called yet, just no-op */ if (!dev->num_crtcs) goto out; crtc = modeset->crtc; if (crtc >= dev->num_crtcs) { ret = EINVAL; goto out; } /* * To avoid all the problems that might happen if interrupts * were enabled/disabled around or between these calls, we just * have the kernel take a reference on the CRTC (just once though * to avoid corrupting the count if multiple, mismatch calls occur), * so that interrupts remain enabled in the interim. */ switch (modeset->cmd) { case _DRM_PRE_MODESET: DRM_DEBUG("pre-modeset, crtc %d\n", crtc); DRM_SPINLOCK(&dev->vbl_lock); if (!dev->vblank[crtc].inmodeset) { dev->vblank[crtc].inmodeset = 0x1; if (drm_vblank_get(dev, crtc) == 0) dev->vblank[crtc].inmodeset |= 0x2; } DRM_SPINUNLOCK(&dev->vbl_lock); break; case _DRM_POST_MODESET: DRM_DEBUG("post-modeset, crtc %d\n", crtc); DRM_SPINLOCK(&dev->vbl_lock); if (dev->vblank[crtc].inmodeset) { if (dev->vblank[crtc].inmodeset & 0x2) drm_vblank_put(dev, crtc); dev->vblank[crtc].inmodeset = 0; } dev->vblank_disable_allowed = 1; DRM_SPINUNLOCK(&dev->vbl_lock); break; default: ret = EINVAL; break; } out: return ret; } int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_priv) { union drm_wait_vblank *vblwait = data; unsigned int flags, seq, crtc; int ret = 0; if (!dev->irq_enabled) return EINVAL; if (vblwait->request.type & ~(_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK)) { DRM_ERROR("Unsupported type value 0x%x, supported mask 0x%x\n", vblwait->request.type, (_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK)); return EINVAL; } flags = vblwait->request.type & _DRM_VBLANK_FLAGS_MASK; crtc = flags & _DRM_VBLANK_SECONDARY ? 1 : 0; if (crtc >= dev->num_crtcs) return EINVAL; DRM_SPINLOCK(&dev->vbl_lock); ret = drm_vblank_get(dev, crtc); DRM_SPINUNLOCK(&dev->vbl_lock); if (ret) { DRM_ERROR("failed to acquire vblank counter, %d\n", ret); return ret; } seq = drm_vblank_count(dev, crtc); switch (vblwait->request.type & _DRM_VBLANK_TYPES_MASK) { case _DRM_VBLANK_RELATIVE: vblwait->request.sequence += seq; vblwait->request.type &= ~_DRM_VBLANK_RELATIVE; case _DRM_VBLANK_ABSOLUTE: break; default: ret = EINVAL; goto done; } if ((flags & _DRM_VBLANK_NEXTONMISS) && (seq - vblwait->request.sequence) <= (1<<23)) { vblwait->request.sequence = seq + 1; } if (flags & _DRM_VBLANK_SIGNAL) { /* There have never been any consumers */ ret = EINVAL; } else { DRM_DEBUG("waiting on vblank count %d, crtc %d\n", vblwait->request.sequence, crtc); for ( ret = 0 ; !ret && !(((drm_vblank_count(dev, crtc) - vblwait->request.sequence) <= (1 << 23)) || !dev->irq_enabled) ; ) { mtx_lock(&dev->irq_lock); if (!(((drm_vblank_count(dev, crtc) - vblwait->request.sequence) <= (1 << 23)) || !dev->irq_enabled)) ret = mtx_sleep(&dev->vblank[crtc].queue, &dev->irq_lock, PCATCH, "vblwtq", DRM_HZ); mtx_unlock(&dev->irq_lock); } if (ret != EINTR && ret != ERESTART) { struct timeval now; microtime(&now); vblwait->reply.tval_sec = now.tv_sec; vblwait->reply.tval_usec = now.tv_usec; vblwait->reply.sequence = drm_vblank_count(dev, crtc); DRM_DEBUG("returning %d to client, irq_enabled %d\n", vblwait->reply.sequence, dev->irq_enabled); } else { DRM_DEBUG("vblank wait interrupted by signal\n"); } } done: DRM_SPINLOCK(&dev->vbl_lock); drm_vblank_put(dev, crtc); DRM_SPINUNLOCK(&dev->vbl_lock); return ret; } void drm_handle_vblank(struct drm_device *dev, int crtc) { atomic_add_rel_32(&dev->vblank[crtc].count, 1); DRM_WAKEUP(&dev->vblank[crtc].queue); } Index: head/sys/dev/drm/i915_drv.c =================================================================== --- head/sys/dev/drm/i915_drv.c (revision 283998) +++ head/sys/dev/drm/i915_drv.c (revision 283999) @@ -1,165 +1,157 @@ /* i915_drv.c -- Intel i915 driver -*- linux-c -*- * Created: Wed Feb 14 17:10:04 2001 by gareth@valinux.com */ /*- * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * * Authors: * Gareth Hughes * */ #include __FBSDID("$FreeBSD$"); #include "dev/drm/drmP.h" #include "dev/drm/drm.h" #include "dev/drm/drm_mm.h" #include "dev/drm/i915_drm.h" #include "dev/drm/i915_drv.h" #include "dev/drm/drm_pciids.h" /* drv_PCI_IDs comes from drm_pciids.h, generated from drm_pciids.txt. */ static drm_pci_id_list_t i915_pciidlist[] = { i915_PCI_IDS }; static int i915_suspend(device_t kdev) { struct drm_device *dev = device_get_softc(kdev); if (!dev || !dev->dev_private) { DRM_ERROR("DRM not initialized, aborting suspend.\n"); return -ENODEV; } DRM_LOCK(); DRM_DEBUG("starting suspend\n"); i915_save_state(dev); DRM_UNLOCK(); return (bus_generic_suspend(kdev)); } static int i915_resume(device_t kdev) { struct drm_device *dev = device_get_softc(kdev); DRM_LOCK(); i915_restore_state(dev); DRM_DEBUG("finished resume\n"); DRM_UNLOCK(); return (bus_generic_resume(kdev)); } static void i915_configure(struct drm_device *dev) { dev->driver->driver_features = DRIVER_USE_AGP | DRIVER_REQUIRE_AGP | DRIVER_USE_MTRR | DRIVER_HAVE_IRQ; dev->driver->buf_priv_size = sizeof(drm_i915_private_t); dev->driver->load = i915_driver_load; dev->driver->unload = i915_driver_unload; dev->driver->preclose = i915_driver_preclose; dev->driver->lastclose = i915_driver_lastclose; dev->driver->device_is_agp = i915_driver_device_is_agp; dev->driver->enable_vblank = i915_enable_vblank; dev->driver->disable_vblank = i915_disable_vblank; dev->driver->irq_preinstall = i915_driver_irq_preinstall; dev->driver->irq_postinstall = i915_driver_irq_postinstall; dev->driver->irq_uninstall = i915_driver_irq_uninstall; dev->driver->irq_handler = i915_driver_irq_handler; dev->driver->ioctls = i915_ioctls; dev->driver->max_ioctl = i915_max_ioctl; dev->driver->name = DRIVER_NAME; dev->driver->desc = DRIVER_DESC; dev->driver->date = DRIVER_DATE; dev->driver->major = DRIVER_MAJOR; dev->driver->minor = DRIVER_MINOR; dev->driver->patchlevel = DRIVER_PATCHLEVEL; } static int i915_probe(device_t kdev) { return drm_probe(kdev, i915_pciidlist); } static int i915_attach(device_t kdev) { struct drm_device *dev = device_get_softc(kdev); dev->driver = malloc(sizeof(struct drm_driver_info), DRM_MEM_DRIVER, M_WAITOK | M_ZERO); i915_configure(dev); return drm_attach(kdev, i915_pciidlist); } static int i915_detach(device_t kdev) { struct drm_device *dev = device_get_softc(kdev); int ret; ret = drm_detach(kdev); free(dev->driver, DRM_MEM_DRIVER); return ret; } static device_method_t i915_methods[] = { /* Device interface */ DEVMETHOD(device_probe, i915_probe), DEVMETHOD(device_attach, i915_attach), DEVMETHOD(device_suspend, i915_suspend), DEVMETHOD(device_resume, i915_resume), DEVMETHOD(device_detach, i915_detach), { 0, 0 } }; static driver_t i915_driver = { -#if __FreeBSD_version >= 700010 "drm", -#else - "drmsub", -#endif i915_methods, sizeof(struct drm_device) }; extern devclass_t drm_devclass; -#if __FreeBSD_version >= 700010 DRIVER_MODULE(i915, vgapci, i915_driver, drm_devclass, 0, 0); -#else -DRIVER_MODULE(i915, agp, i915_driver, drm_devclass, 0, 0); -#endif MODULE_DEPEND(i915, drm, 1, 1, 1); Index: head/sys/dev/drm/mach64_drv.c =================================================================== --- head/sys/dev/drm/mach64_drv.c (revision 283998) +++ head/sys/dev/drm/mach64_drv.c (revision 283999) @@ -1,138 +1,134 @@ /* mach64_drv.c -- ATI Rage 128 driver -*- linux-c -*- * Created: Mon Dec 13 09:47:27 1999 by faith@precisioninsight.com */ /*- * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * * Authors: * Rickard E. (Rik) Faith * Gareth Hughes */ #include __FBSDID("$FreeBSD$"); #include #include "dev/drm/drmP.h" #include "dev/drm/drm.h" #include "dev/drm/mach64_drm.h" #include "dev/drm/mach64_drv.h" #include "dev/drm/drm_pciids.h" /* drv_PCI_IDs comes from drm_pciids.h, generated from drm_pciids.txt. */ static drm_pci_id_list_t mach64_pciidlist[] = { mach64_PCI_IDS }; static void mach64_configure(struct drm_device *dev) { dev->driver->driver_features = DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ; dev->driver->buf_priv_size = 1; /* No dev_priv */ dev->driver->load = mach64_driver_load; dev->driver->lastclose = mach64_driver_lastclose; dev->driver->get_vblank_counter = mach64_get_vblank_counter; dev->driver->enable_vblank = mach64_enable_vblank; dev->driver->disable_vblank = mach64_disable_vblank; dev->driver->irq_preinstall = mach64_driver_irq_preinstall; dev->driver->irq_postinstall = mach64_driver_irq_postinstall; dev->driver->irq_uninstall = mach64_driver_irq_uninstall; dev->driver->irq_handler = mach64_driver_irq_handler; dev->driver->dma_ioctl = mach64_dma_buffers; dev->driver->ioctls = mach64_ioctls; dev->driver->max_ioctl = mach64_max_ioctl; dev->driver->name = DRIVER_NAME; dev->driver->desc = DRIVER_DESC; dev->driver->date = DRIVER_DATE; dev->driver->major = DRIVER_MAJOR; dev->driver->minor = DRIVER_MINOR; dev->driver->patchlevel = DRIVER_PATCHLEVEL; } static int mach64_probe(device_t kdev) { return drm_probe(kdev, mach64_pciidlist); } static int mach64_attach(device_t kdev) { struct drm_device *dev = device_get_softc(kdev); dev->driver = malloc(sizeof(struct drm_driver_info), DRM_MEM_DRIVER, M_WAITOK | M_ZERO); mach64_configure(dev); return drm_attach(kdev, mach64_pciidlist); } int mach64_driver_load(struct drm_device * dev, unsigned long flags) { return drm_vblank_init(dev, 1); } static int mach64_detach(device_t kdev) { struct drm_device *dev = device_get_softc(kdev); int ret; ret = drm_detach(kdev); free(dev->driver, DRM_MEM_DRIVER); return ret; } static device_method_t mach64_methods[] = { /* Device interface */ DEVMETHOD(device_probe, mach64_probe), DEVMETHOD(device_attach, mach64_attach), DEVMETHOD(device_detach, mach64_detach), { 0, 0 } }; static driver_t mach64_driver = { "drm", mach64_methods, sizeof(struct drm_device) }; extern devclass_t drm_devclass; -#if __FreeBSD_version >= 700010 DRIVER_MODULE(mach64, vgapci, mach64_driver, drm_devclass, 0, 0); -#else -DRIVER_MODULE(mach64, pci, mach64_driver, drm_devclass, 0, 0); -#endif MODULE_DEPEND(mach64, drm, 1, 1, 1); Index: head/sys/dev/drm/mga_drv.c =================================================================== --- head/sys/dev/drm/mga_drv.c (revision 283998) +++ head/sys/dev/drm/mga_drv.c (revision 283999) @@ -1,175 +1,167 @@ /* mga_drv.c -- Matrox G200/G400 driver -*- linux-c -*- * Created: Mon Dec 13 01:56:22 1999 by jhartmann@precisioninsight.com */ /*- * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * * Authors: * Rickard E. (Rik) Faith * Gareth Hughes * */ #include __FBSDID("$FreeBSD$"); #include "dev/drm/drmP.h" #include "dev/drm/drm.h" #include "dev/drm/mga_drm.h" #include "dev/drm/mga_drv.h" #include "dev/drm/drm_pciids.h" /* drv_PCI_IDs comes from drm_pciids.h, generated from drm_pciids.txt. */ static drm_pci_id_list_t mga_pciidlist[] = { mga_PCI_IDS }; /** * Determine if the device really is AGP or not. * * In addition to the usual tests performed by \c drm_device_is_agp, this * function detects PCI G450 cards that appear to the system exactly like * AGP G450 cards. * * \param dev The device to be tested. * * \returns * If the device is a PCI G450, zero is returned. Otherwise non-zero is * returned. * * \bug * This function needs to be filled in! The implementation in * linux-core/mga_drv.c shows what needs to be done. */ static int mga_driver_device_is_agp(struct drm_device * dev) { device_t bus; /* There are PCI versions of the G450. These cards have the * same PCI ID as the AGP G450, but have an additional PCI-to-PCI * bridge chip. We detect these cards, which are not currently * supported by this driver, by looking at the device ID of the * bus the "card" is on. If vendor is 0x3388 (Hint Corp) and the * device is 0x0021 (HB6 Universal PCI-PCI bridge), we reject the * device. */ -#if __FreeBSD_version >= 700010 bus = device_get_parent(device_get_parent(dev->device)); -#else - bus = device_get_parent(dev->device); -#endif if (pci_get_device(dev->device) == 0x0525 && pci_get_vendor(bus) == 0x3388 && pci_get_device(bus) == 0x0021) return DRM_IS_NOT_AGP; else return DRM_MIGHT_BE_AGP; } static void mga_configure(struct drm_device *dev) { dev->driver->driver_features = DRIVER_USE_AGP | DRIVER_REQUIRE_AGP | DRIVER_USE_MTRR | DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ; dev->driver->buf_priv_size = sizeof(drm_mga_buf_priv_t); dev->driver->load = mga_driver_load; dev->driver->unload = mga_driver_unload; dev->driver->lastclose = mga_driver_lastclose; dev->driver->get_vblank_counter = mga_get_vblank_counter; dev->driver->enable_vblank = mga_enable_vblank; dev->driver->disable_vblank = mga_disable_vblank; dev->driver->irq_preinstall = mga_driver_irq_preinstall; dev->driver->irq_postinstall = mga_driver_irq_postinstall; dev->driver->irq_uninstall = mga_driver_irq_uninstall; dev->driver->irq_handler = mga_driver_irq_handler; dev->driver->dma_ioctl = mga_dma_buffers; dev->driver->dma_quiescent = mga_driver_dma_quiescent; dev->driver->device_is_agp = mga_driver_device_is_agp; dev->driver->ioctls = mga_ioctls; dev->driver->max_ioctl = mga_max_ioctl; dev->driver->name = DRIVER_NAME; dev->driver->desc = DRIVER_DESC; dev->driver->date = DRIVER_DATE; dev->driver->major = DRIVER_MAJOR; dev->driver->minor = DRIVER_MINOR; dev->driver->patchlevel = DRIVER_PATCHLEVEL; } static int mga_probe(device_t kdev) { return drm_probe(kdev, mga_pciidlist); } static int mga_attach(device_t kdev) { struct drm_device *dev = device_get_softc(kdev); dev->driver = malloc(sizeof(struct drm_driver_info), DRM_MEM_DRIVER, M_WAITOK | M_ZERO); mga_configure(dev); return drm_attach(kdev, mga_pciidlist); } static int mga_detach(device_t kdev) { struct drm_device *dev = device_get_softc(kdev); int ret; ret = drm_detach(kdev); free(dev->driver, DRM_MEM_DRIVER); return ret; } static device_method_t mga_methods[] = { /* Device interface */ DEVMETHOD(device_probe, mga_probe), DEVMETHOD(device_attach, mga_attach), DEVMETHOD(device_detach, mga_detach), { 0, 0 } }; static driver_t mga_driver = { "drm", mga_methods, sizeof(struct drm_device) }; extern devclass_t drm_devclass; -#if __FreeBSD_version >= 700010 DRIVER_MODULE(mga, vgapci, mga_driver, drm_devclass, 0, 0); -#else -DRIVER_MODULE(mga, pci, mga_driver, drm_devclass, 0, 0); -#endif MODULE_DEPEND(mga, drm, 1, 1, 1); Index: head/sys/dev/drm/r128_drv.c =================================================================== --- head/sys/dev/drm/r128_drv.c (revision 283998) +++ head/sys/dev/drm/r128_drv.c (revision 283999) @@ -1,136 +1,132 @@ /* r128_drv.c -- ATI Rage 128 driver -*- linux-c -*- * Created: Mon Dec 13 09:47:27 1999 by faith@precisioninsight.com */ /*- * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * * Authors: * Rickard E. (Rik) Faith * Gareth Hughes * */ #include __FBSDID("$FreeBSD$"); #include "dev/drm/drmP.h" #include "dev/drm/drm.h" #include "dev/drm/r128_drm.h" #include "dev/drm/r128_drv.h" #include "dev/drm/drm_pciids.h" /* drv_PCI_IDs comes from drm_pciids.h, generated from drm_pciids.txt. */ static drm_pci_id_list_t r128_pciidlist[] = { r128_PCI_IDS }; static void r128_configure(struct drm_device *dev) { dev->driver->driver_features = DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_SG | DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ; dev->driver->buf_priv_size = sizeof(drm_r128_buf_priv_t); dev->driver->load = r128_driver_load; dev->driver->preclose = r128_driver_preclose; dev->driver->lastclose = r128_driver_lastclose; dev->driver->get_vblank_counter = r128_get_vblank_counter; dev->driver->enable_vblank = r128_enable_vblank; dev->driver->disable_vblank = r128_disable_vblank; dev->driver->irq_preinstall = r128_driver_irq_preinstall; dev->driver->irq_postinstall = r128_driver_irq_postinstall; dev->driver->irq_uninstall = r128_driver_irq_uninstall; dev->driver->irq_handler = r128_driver_irq_handler; dev->driver->dma_ioctl = r128_cce_buffers; dev->driver->ioctls = r128_ioctls; dev->driver->max_ioctl = r128_max_ioctl; dev->driver->name = DRIVER_NAME; dev->driver->desc = DRIVER_DESC; dev->driver->date = DRIVER_DATE; dev->driver->major = DRIVER_MAJOR; dev->driver->minor = DRIVER_MINOR; dev->driver->patchlevel = DRIVER_PATCHLEVEL; } static int r128_probe(device_t kdev) { return drm_probe(kdev, r128_pciidlist); } static int r128_attach(device_t kdev) { struct drm_device *dev = device_get_softc(kdev); dev->driver = malloc(sizeof(struct drm_driver_info), DRM_MEM_DRIVER, M_WAITOK | M_ZERO); r128_configure(dev); return drm_attach(kdev, r128_pciidlist); } int r128_driver_load(struct drm_device * dev, unsigned long flags) { return drm_vblank_init(dev, 1); } static int r128_detach(device_t kdev) { struct drm_device *dev = device_get_softc(kdev); int ret; ret = drm_detach(kdev); free(dev->driver, DRM_MEM_DRIVER); return ret; } static device_method_t r128_methods[] = { /* Device interface */ DEVMETHOD(device_probe, r128_probe), DEVMETHOD(device_attach, r128_attach), DEVMETHOD(device_detach, r128_detach), { 0, 0 } }; static driver_t r128_driver = { "drm", r128_methods, sizeof(struct drm_device) }; extern devclass_t drm_devclass; -#if __FreeBSD_version >= 700010 DRIVER_MODULE(r128, vgapci, r128_driver, drm_devclass, 0, 0); -#else -DRIVER_MODULE(r128, pci, r128_driver, drm_devclass, 0, 0); -#endif MODULE_DEPEND(r128, drm, 1, 1, 1); Index: head/sys/dev/drm/radeon_drv.c =================================================================== --- head/sys/dev/drm/radeon_drv.c (revision 283998) +++ head/sys/dev/drm/radeon_drv.c (revision 283999) @@ -1,135 +1,131 @@ /* radeon_drv.c -- ATI Radeon driver -*- linux-c -*- * Created: Wed Feb 14 17:10:04 2001 by gareth@valinux.com */ /*- * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * * Authors: * Gareth Hughes * */ #include __FBSDID("$FreeBSD$"); #include "dev/drm/drmP.h" #include "dev/drm/drm.h" #include "dev/drm/radeon_drm.h" #include "dev/drm/radeon_drv.h" #include "dev/drm/drm_pciids.h" int radeon_no_wb; /* drv_PCI_IDs comes from drm_pciids.h, generated from drm_pciids.txt. */ static drm_pci_id_list_t radeon_pciidlist[] = { radeon_PCI_IDS }; static void radeon_configure(struct drm_device *dev) { dev->driver->driver_features = DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_SG | DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ; dev->driver->buf_priv_size = sizeof(drm_radeon_buf_priv_t); dev->driver->load = radeon_driver_load; dev->driver->unload = radeon_driver_unload; dev->driver->firstopen = radeon_driver_firstopen; dev->driver->open = radeon_driver_open; dev->driver->preclose = radeon_driver_preclose; dev->driver->postclose = radeon_driver_postclose; dev->driver->lastclose = radeon_driver_lastclose; dev->driver->get_vblank_counter = radeon_get_vblank_counter; dev->driver->enable_vblank = radeon_enable_vblank; dev->driver->disable_vblank = radeon_disable_vblank; dev->driver->irq_preinstall = radeon_driver_irq_preinstall; dev->driver->irq_postinstall = radeon_driver_irq_postinstall; dev->driver->irq_uninstall = radeon_driver_irq_uninstall; dev->driver->irq_handler = radeon_driver_irq_handler; dev->driver->dma_ioctl = radeon_cp_buffers; dev->driver->ioctls = radeon_ioctls; dev->driver->max_ioctl = radeon_max_ioctl; dev->driver->name = DRIVER_NAME; dev->driver->desc = DRIVER_DESC; dev->driver->date = DRIVER_DATE; dev->driver->major = DRIVER_MAJOR; dev->driver->minor = DRIVER_MINOR; dev->driver->patchlevel = DRIVER_PATCHLEVEL; } static int radeon_probe(device_t kdev) { return drm_probe(kdev, radeon_pciidlist); } static int radeon_attach(device_t kdev) { struct drm_device *dev = device_get_softc(kdev); dev->driver = malloc(sizeof(struct drm_driver_info), DRM_MEM_DRIVER, M_WAITOK | M_ZERO); radeon_configure(dev); return drm_attach(kdev, radeon_pciidlist); } static int radeon_detach(device_t kdev) { struct drm_device *dev = device_get_softc(kdev); int ret; ret = drm_detach(kdev); free(dev->driver, DRM_MEM_DRIVER); return ret; } static device_method_t radeon_methods[] = { /* Device interface */ DEVMETHOD(device_probe, radeon_probe), DEVMETHOD(device_attach, radeon_attach), DEVMETHOD(device_detach, radeon_detach), { 0, 0 } }; static driver_t radeon_driver = { "drm", radeon_methods, sizeof(struct drm_device) }; extern devclass_t drm_devclass; -#if __FreeBSD_version >= 700010 DRIVER_MODULE(radeon, vgapci, radeon_driver, drm_devclass, 0, 0); -#else -DRIVER_MODULE(radeon, pci, radeon_driver, drm_devclass, 0, 0); -#endif MODULE_DEPEND(radeon, drm, 1, 1, 1); Index: head/sys/dev/drm/savage_drv.c =================================================================== --- head/sys/dev/drm/savage_drv.c (revision 283998) +++ head/sys/dev/drm/savage_drv.c (revision 283999) @@ -1,121 +1,117 @@ /* savage_drv.c -- Savage DRI driver */ /*- * Copyright 2005 Eric Anholt * 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 * ERIC ANHOLT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * Authors: * Eric Anholt */ #include __FBSDID("$FreeBSD$"); #include "dev/drm/drmP.h" #include "dev/drm/drm.h" #include "dev/drm/savage_drm.h" #include "dev/drm/savage_drv.h" #include "dev/drm/drm_pciids.h" /* drv_PCI_IDs comes from drm_pciids.h, generated from drm_pciids.txt. */ static drm_pci_id_list_t savage_pciidlist[] = { savage_PCI_IDS }; static void savage_configure(struct drm_device *dev) { dev->driver->driver_features = DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_HAVE_DMA; dev->driver->buf_priv_size = sizeof(drm_savage_buf_priv_t); dev->driver->load = savage_driver_load; dev->driver->firstopen = savage_driver_firstopen; dev->driver->lastclose = savage_driver_lastclose; dev->driver->unload = savage_driver_unload; dev->driver->reclaim_buffers_locked = savage_reclaim_buffers; dev->driver->dma_ioctl = savage_bci_buffers; dev->driver->ioctls = savage_ioctls; dev->driver->max_ioctl = savage_max_ioctl; dev->driver->name = DRIVER_NAME; dev->driver->desc = DRIVER_DESC; dev->driver->date = DRIVER_DATE; dev->driver->major = DRIVER_MAJOR; dev->driver->minor = DRIVER_MINOR; dev->driver->patchlevel = DRIVER_PATCHLEVEL; } static int savage_probe(device_t kdev) { return drm_probe(kdev, savage_pciidlist); } static int savage_attach(device_t kdev) { struct drm_device *dev = device_get_softc(kdev); dev->driver = malloc(sizeof(struct drm_driver_info), DRM_MEM_DRIVER, M_WAITOK | M_ZERO); savage_configure(dev); return drm_attach(kdev, savage_pciidlist); } static int savage_detach(device_t kdev) { struct drm_device *dev = device_get_softc(kdev); int ret; ret = drm_detach(kdev); free(dev->driver, DRM_MEM_DRIVER); return ret; } static device_method_t savage_methods[] = { /* Device interface */ DEVMETHOD(device_probe, savage_probe), DEVMETHOD(device_attach, savage_attach), DEVMETHOD(device_detach, savage_detach), { 0, 0 } }; static driver_t savage_driver = { "drm", savage_methods, sizeof(struct drm_device) }; extern devclass_t drm_devclass; -#if __FreeBSD_version >= 700010 DRIVER_MODULE(savage, vgapci, savage_driver, drm_devclass, 0, 0); -#else -DRIVER_MODULE(savage, pci, savage_driver, drm_devclass, 0, 0); -#endif MODULE_DEPEND(savage, drm, 1, 1, 1); Index: head/sys/dev/drm/sis_drv.c =================================================================== --- head/sys/dev/drm/sis_drv.c (revision 283998) +++ head/sys/dev/drm/sis_drv.c (revision 283999) @@ -1,115 +1,111 @@ /* sis.c -- sis driver -*- linux-c -*- */ /*- * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * */ #include __FBSDID("$FreeBSD$"); #include "dev/drm/drmP.h" #include "dev/drm/sis_drm.h" #include "dev/drm/sis_drv.h" #include "dev/drm/drm_pciids.h" /* drv_PCI_IDs comes from drm_pciids.h, generated from drm_pciids.txt. */ static drm_pci_id_list_t sis_pciidlist[] = { sis_PCI_IDS }; static void sis_configure(struct drm_device *dev) { dev->driver->driver_features = DRIVER_USE_AGP | DRIVER_USE_MTRR; dev->driver->buf_priv_size = 1; /* No dev_priv */ dev->driver->context_ctor = sis_init_context; dev->driver->context_dtor = sis_final_context; dev->driver->ioctls = sis_ioctls; dev->driver->max_ioctl = sis_max_ioctl; dev->driver->name = DRIVER_NAME; dev->driver->desc = DRIVER_DESC; dev->driver->date = DRIVER_DATE; dev->driver->major = DRIVER_MAJOR; dev->driver->minor = DRIVER_MINOR; dev->driver->patchlevel = DRIVER_PATCHLEVEL; } static int sis_probe(device_t kdev) { return drm_probe(kdev, sis_pciidlist); } static int sis_attach(device_t kdev) { struct drm_device *dev = device_get_softc(kdev); dev->driver = malloc(sizeof(struct drm_driver_info), DRM_MEM_DRIVER, M_WAITOK | M_ZERO); sis_configure(dev); return drm_attach(kdev, sis_pciidlist); } static int sis_detach(device_t kdev) { struct drm_device *dev = device_get_softc(kdev); int ret; ret = drm_detach(kdev); free(dev->driver, DRM_MEM_DRIVER); return ret; } static device_method_t sis_methods[] = { /* Device interface */ DEVMETHOD(device_probe, sis_probe), DEVMETHOD(device_attach, sis_attach), DEVMETHOD(device_detach, sis_detach), { 0, 0 } }; static driver_t sis_driver = { "drm", sis_methods, sizeof(struct drm_device) }; extern devclass_t drm_devclass; -#if __FreeBSD_version >= 700010 DRIVER_MODULE(sisdrm, vgapci, sis_driver, drm_devclass, 0, 0); -#else -DRIVER_MODULE(sisdrm, pci, sis_driver, drm_devclass, 0, 0); -#endif MODULE_DEPEND(sisdrm, drm, 1, 1, 1); Index: head/sys/dev/drm/tdfx_drv.c =================================================================== --- head/sys/dev/drm/tdfx_drv.c (revision 283998) +++ head/sys/dev/drm/tdfx_drv.c (revision 283999) @@ -1,117 +1,113 @@ /* tdfx_drv.c -- tdfx driver -*- linux-c -*- * Created: Thu Oct 7 10:38:32 1999 by faith@precisioninsight.com */ /*- * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * * Authors: * Rickard E. (Rik) Faith * Daryll Strauss * Gareth Hughes * */ #include __FBSDID("$FreeBSD$"); #include "dev/drm/tdfx_drv.h" #include "dev/drm/drmP.h" #include "dev/drm/drm_pciids.h" /* drv_PCI_IDs comes from drm_pciids.h, generated from drm_pciids.txt. */ static drm_pci_id_list_t tdfx_pciidlist[] = { tdfx_PCI_IDS }; static void tdfx_configure(struct drm_device *dev) { dev->driver->driver_features = DRIVER_USE_MTRR; dev->driver->buf_priv_size = 1; /* No dev_priv */ dev->driver->max_ioctl = 0; dev->driver->name = DRIVER_NAME; dev->driver->desc = DRIVER_DESC; dev->driver->date = DRIVER_DATE; dev->driver->major = DRIVER_MAJOR; dev->driver->minor = DRIVER_MINOR; dev->driver->patchlevel = DRIVER_PATCHLEVEL; } static int tdfx_probe(device_t kdev) { return drm_probe(kdev, tdfx_pciidlist); } static int tdfx_attach(device_t kdev) { struct drm_device *dev = device_get_softc(kdev); dev->driver = malloc(sizeof(struct drm_driver_info), DRM_MEM_DRIVER, M_WAITOK | M_ZERO); tdfx_configure(dev); return drm_attach(kdev, tdfx_pciidlist); } static int tdfx_detach(device_t kdev) { struct drm_device *dev = device_get_softc(kdev); int ret; ret = drm_detach(kdev); free(dev->driver, DRM_MEM_DRIVER); return ret; } static device_method_t tdfx_methods[] = { /* Device interface */ DEVMETHOD(device_probe, tdfx_probe), DEVMETHOD(device_attach, tdfx_attach), DEVMETHOD(device_detach, tdfx_detach), { 0, 0 } }; static driver_t tdfx_driver = { "drm", tdfx_methods, sizeof(struct drm_device) }; extern devclass_t drm_devclass; -#if __FreeBSD_version >= 700010 DRIVER_MODULE(tdfx, vgapci, tdfx_driver, drm_devclass, 0, 0); -#else -DRIVER_MODULE(tdfx, pci, tdfx_driver, drm_devclass, 0, 0); -#endif MODULE_DEPEND(tdfx, drm, 1, 1, 1);