diff options
-rw-r--r-- | sys/dev/drm/drm.h | 463 | ||||
-rw-r--r-- | sys/dev/drm/drmP.h | 20 | ||||
-rw-r--r-- | sys/dev/drm/drm_bufs.h | 10 | ||||
-rw-r--r-- | sys/dev/drm/drm_drv.h | 30 | ||||
-rw-r--r-- | sys/dev/drm/drm_fops.h | 8 | ||||
-rw-r--r-- | sys/dev/drm/drm_ioctl.h | 91 | ||||
-rw-r--r-- | sys/dev/drm/drm_irq.h | 119 | ||||
-rw-r--r-- | sys/dev/drm/drm_os_freebsd.h | 6 | ||||
-rw-r--r-- | sys/dev/drm/mga_dma.c | 2 | ||||
-rw-r--r-- | sys/dev/drm/r128_cce.c | 2 | ||||
-rw-r--r-- | sys/dev/drm/radeon.h | 21 | ||||
-rw-r--r-- | sys/dev/drm/radeon_cp.c | 31 | ||||
-rw-r--r-- | sys/dev/drm/radeon_drm.h | 16 | ||||
-rw-r--r-- | sys/dev/drm/radeon_drv.h | 5 | ||||
-rw-r--r-- | sys/dev/drm/radeon_state.c | 323 |
15 files changed, 833 insertions, 314 deletions
diff --git a/sys/dev/drm/drm.h b/sys/dev/drm/drm.h index 6026580..9ef223d 100644 --- a/sys/dev/drm/drm.h +++ b/sys/dev/drm/drm.h @@ -1,6 +1,14 @@ -/* drm.h -- Header for Direct Rendering Manager -*- linux-c -*- - * Created: Mon Jan 4 10:05:05 1999 by faith@precisioninsight.com +/** + * \file drm.h + * Header for the Direct Rendering Manager + * + * \author Rickard E. (Rik) Faith <faith@valinux.com> * + * \par Acknowledgments: + * Dec 1999, Richard Henderson <rth@twiddle.net>, move to generic \c cmpxchg. + */ + +/* * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. * All rights reserved. @@ -24,15 +32,10 @@ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * - * Authors: - * Rickard E. (Rik) Faith <faith@valinux.com> - * - * Acknowledgements: - * Dec 1999, Richard Henderson <rth@twiddle.net>, move to generic cmpxchg. - * * $FreeBSD$ */ + #ifndef _DRM_H_ #define _DRM_H_ @@ -79,29 +82,42 @@ #define DRM_DEV_GID 0 #endif -#define DRM_NAME "drm" /* Name in kernel, /dev, and /proc */ -#define DRM_MIN_ORDER 5 /* At least 2^5 bytes = 32 bytes */ -#define DRM_MAX_ORDER 22 /* Up to 2^22 bytes = 4MB */ -#define DRM_RAM_PERCENT 10 /* How much system ram can we lock? */ +#if CONFIG_XFREE86_VERSION >= XFREE86_VERSION(4,1,0,0) +#ifdef __OpenBSD__ +#define DRM_MAJOR 81 +#endif +#if defined(__linux__) || defined(__NetBSD__) +#define DRM_MAJOR 226 +#endif +#define DRM_MAX_MINOR 15 +#endif +#define DRM_NAME "drm" /**< Name in kernel, /dev, and /proc */ +#define DRM_MIN_ORDER 5 /**< At least 2^5 bytes = 32 bytes */ +#define DRM_MAX_ORDER 22 /**< Up to 2^22 bytes = 4MB */ +#define DRM_RAM_PERCENT 10 /**< How much system ram can we lock? */ -#define _DRM_LOCK_HELD 0x80000000 /* Hardware lock is held */ -#define _DRM_LOCK_CONT 0x40000000 /* Hardware lock is contended */ +#define _DRM_LOCK_HELD 0x80000000 /**< Hardware lock is held */ +#define _DRM_LOCK_CONT 0x40000000 /**< Hardware lock is contended */ #define _DRM_LOCK_IS_HELD(lock) ((lock) & _DRM_LOCK_HELD) #define _DRM_LOCK_IS_CONT(lock) ((lock) & _DRM_LOCK_CONT) #define _DRM_LOCKING_CONTEXT(lock) ((lock) & ~(_DRM_LOCK_HELD|_DRM_LOCK_CONT)) + typedef unsigned long drm_handle_t; typedef unsigned int drm_context_t; typedef unsigned int drm_drawable_t; typedef unsigned int drm_magic_t; -/* Warning: If you change this structure, make sure you change - * XF86DRIClipRectRec in the server as well */ -/* KW: Actually it's illegal to change either for +/** + * Cliprect. + * + * \warning: If you change this structure, make sure you change + * XF86DRIClipRectRec in the server as well + * + * \note KW: Actually it's illegal to change either for * backwards-compatibility reasons. */ - typedef struct drm_clip_rect { unsigned short x1; unsigned short y1; @@ -109,6 +125,10 @@ typedef struct drm_clip_rect { unsigned short y2; } drm_clip_rect_t; + +/** + * Texture region, + */ typedef struct drm_tex_region { unsigned char next; unsigned char prev; @@ -117,32 +137,52 @@ typedef struct drm_tex_region { unsigned int age; } drm_tex_region_t; + +/** + * DRM_IOCTL_VERSION ioctl argument type. + * + * \sa drmGetVersion(). + */ typedef struct drm_version { - int version_major; /* Major version */ - int version_minor; /* Minor version */ - int version_patchlevel;/* Patch level */ - size_t name_len; /* Length of name buffer */ - char *name; /* Name of driver */ - size_t date_len; /* Length of date buffer */ - char *date; /* User-space buffer to hold date */ - size_t desc_len; /* Length of desc buffer */ - char *desc; /* User-space buffer to hold desc */ + int version_major; /**< Major version */ + int version_minor; /**< Minor version */ + int version_patchlevel;/**< Patch level */ + size_t name_len; /**< Length of name buffer */ + char *name; /**< Name of driver */ + size_t date_len; /**< Length of date buffer */ + char *date; /**< User-space buffer to hold date */ + size_t desc_len; /**< Length of desc buffer */ + char *desc; /**< User-space buffer to hold desc */ } drm_version_t; + +/** + * DRM_IOCTL_GET_UNIQUE ioctl argument type. + * + * \sa drmGetBusid() and drmSetBusId(). + */ typedef struct drm_unique { - size_t unique_len; /* Length of unique */ - char *unique; /* Unique name for driver instantiation */ + size_t unique_len; /**< Length of unique */ + char *unique; /**< Unique name for driver instantiation */ } drm_unique_t; + typedef struct drm_list { - int count; /* Length of user-space structures */ + int count; /**< Length of user-space structures */ drm_version_t *version; } drm_list_t; + typedef struct drm_block { int unused; } drm_block_t; + +/** + * DRM_IOCTL_CONTROL ioctl argument type. + * + * \sa drmCtlInstHandler() and drmCtlUninstHandler(). + */ typedef struct drm_control { enum { DRM_ADD_COMMAND, @@ -153,49 +193,70 @@ typedef struct drm_control { int irq; } drm_control_t; + +/** + * Type of memory to map. + */ typedef enum drm_map_type { - _DRM_FRAME_BUFFER = 0, /* WC (no caching), no core dump */ - _DRM_REGISTERS = 1, /* no caching, no core dump */ - _DRM_SHM = 2, /* shared, cached */ - _DRM_AGP = 3, /* AGP/GART */ - _DRM_SCATTER_GATHER = 4 /* Scatter/gather memory for PCI DMA */ + _DRM_FRAME_BUFFER = 0, /**< WC (no caching), no core dump */ + _DRM_REGISTERS = 1, /**< no caching, no core dump */ + _DRM_SHM = 2, /**< shared, cached */ + _DRM_AGP = 3, /**< AGP/GART */ + _DRM_SCATTER_GATHER = 4 /**< Scatter/gather memory for PCI DMA */ } drm_map_type_t; + +/** + * Memory mapping flags. + */ typedef enum drm_map_flags { - _DRM_RESTRICTED = 0x01, /* Cannot be mapped to user-virtual */ + _DRM_RESTRICTED = 0x01, /**< Cannot be mapped to user-virtual */ _DRM_READ_ONLY = 0x02, - _DRM_LOCKED = 0x04, /* shared, cached, locked */ - _DRM_KERNEL = 0x08, /* kernel requires access */ - _DRM_WRITE_COMBINING = 0x10, /* use write-combining if available */ - _DRM_CONTAINS_LOCK = 0x20, /* SHM page that contains lock */ - _DRM_REMOVABLE = 0x40 /* Removable mapping */ + _DRM_LOCKED = 0x04, /**< shared, cached, locked */ + _DRM_KERNEL = 0x08, /**< kernel requires access */ + _DRM_WRITE_COMBINING = 0x10, /**< use write-combining if available */ + _DRM_CONTAINS_LOCK = 0x20, /**< SHM page that contains lock */ + _DRM_REMOVABLE = 0x40 /**< Removable mapping */ } drm_map_flags_t; + typedef struct drm_ctx_priv_map { - unsigned int ctx_id; /* Context requesting private mapping */ - void *handle; /* Handle of map */ + unsigned int ctx_id; /**< Context requesting private mapping */ + void *handle; /**< Handle of map */ } drm_ctx_priv_map_t; + +/** + * DRM_IOCTL_GET_MAP, DRM_IOCTL_ADD_MAP and DRM_IOCTL_RM_MAP ioctls + * argument type. + * + * \sa drmAddMap(). + */ typedef struct drm_map { - unsigned long offset; /* Requested physical address (0 for SAREA)*/ - unsigned long size; /* Requested physical size (bytes) */ - drm_map_type_t type; /* Type of memory to map */ - drm_map_flags_t flags; /* Flags */ - void *handle; /* User-space: "Handle" to pass to mmap */ - /* Kernel-space: kernel-virtual address */ - int mtrr; /* MTRR slot used */ - /* Private data */ + unsigned long offset; /**< Requested physical address (0 for SAREA)*/ + unsigned long size; /**< Requested physical size (bytes) */ + drm_map_type_t type; /**< Type of memory to map */ + drm_map_flags_t flags; /**< Flags */ + void *handle; /**< User-space: "Handle" to pass to mmap() */ + /**< Kernel-space: kernel-virtual address */ + int mtrr; /**< MTRR slot used */ + /* Private data */ } drm_map_t; + +/** + * DRM_IOCTL_GET_CLIENT ioctl argument type. + */ typedef struct drm_client { - int idx; /* Which client desired? */ - int auth; /* Is client authenticated? */ - unsigned long pid; /* Process id */ - unsigned long uid; /* User id */ - unsigned long magic; /* Magic */ - unsigned long iocs; /* Ioctl count */ + int idx; /**< Which client desired? */ + int auth; /**< Is client authenticated? */ + unsigned long pid; /**< Process ID */ + unsigned long uid; /**< User ID */ + unsigned long magic; /**< Magic */ + unsigned long iocs; /**< Ioctl count */ } drm_client_t; + typedef enum { _DRM_STAT_LOCK, _DRM_STAT_OPENS, @@ -203,20 +264,24 @@ typedef enum { _DRM_STAT_IOCTLS, _DRM_STAT_LOCKS, _DRM_STAT_UNLOCKS, - _DRM_STAT_VALUE, /* Generic value */ - _DRM_STAT_BYTE, /* Generic byte counter (1024bytes/K) */ - _DRM_STAT_COUNT, /* Generic non-byte counter (1000/k) */ + _DRM_STAT_VALUE, /**< Generic value */ + _DRM_STAT_BYTE, /**< Generic byte counter (1024bytes/K) */ + _DRM_STAT_COUNT, /**< Generic non-byte counter (1000/k) */ - _DRM_STAT_IRQ, /* IRQ */ - _DRM_STAT_PRIMARY, /* Primary DMA bytes */ - _DRM_STAT_SECONDARY, /* Secondary DMA bytes */ - _DRM_STAT_DMA, /* DMA */ - _DRM_STAT_SPECIAL, /* Special DMA (e.g., priority or polled) */ - _DRM_STAT_MISSED /* Missed DMA opportunity */ + _DRM_STAT_IRQ, /**< IRQ */ + _DRM_STAT_PRIMARY, /**< Primary DMA bytes */ + _DRM_STAT_SECONDARY, /**< Secondary DMA bytes */ + _DRM_STAT_DMA, /**< DMA */ + _DRM_STAT_SPECIAL, /**< Special DMA (e.g., priority or polled) */ + _DRM_STAT_MISSED /**< Missed DMA opportunity */ /* Add to the *END* of the list */ } drm_stat_type_t; + +/** + * DRM_IOCTL_GET_STATS ioctl argument type. + */ typedef struct drm_stats { unsigned long count; struct { @@ -225,137 +290,220 @@ typedef struct drm_stats { } data[15]; } drm_stats_t; + +/** + * Hardware locking flags. + */ typedef enum drm_lock_flags { - _DRM_LOCK_READY = 0x01, /* Wait until hardware is ready for DMA */ - _DRM_LOCK_QUIESCENT = 0x02, /* Wait until hardware quiescent */ - _DRM_LOCK_FLUSH = 0x04, /* Flush this context's DMA queue first */ - _DRM_LOCK_FLUSH_ALL = 0x08, /* Flush all DMA queues first */ + _DRM_LOCK_READY = 0x01, /**< Wait until hardware is ready for DMA */ + _DRM_LOCK_QUIESCENT = 0x02, /**< Wait until hardware quiescent */ + _DRM_LOCK_FLUSH = 0x04, /**< Flush this context's DMA queue first */ + _DRM_LOCK_FLUSH_ALL = 0x08, /**< Flush all DMA queues first */ /* These *HALT* flags aren't supported yet -- they will be used to support the full-screen DGA-like mode. */ - _DRM_HALT_ALL_QUEUES = 0x10, /* Halt all current and future queues */ - _DRM_HALT_CUR_QUEUES = 0x20 /* Halt all current queues */ + _DRM_HALT_ALL_QUEUES = 0x10, /**< Halt all current and future queues */ + _DRM_HALT_CUR_QUEUES = 0x20 /**< Halt all current queues */ } drm_lock_flags_t; + +/** + * DRM_IOCTL_LOCK, DRM_IOCTL_UNLOCK and DRM_IOCTL_FINISH ioctl argument type. + * + * \sa drmGetLock() and drmUnlock(). + */ typedef struct drm_lock { int context; drm_lock_flags_t flags; } drm_lock_t; -typedef enum drm_dma_flags { /* These values *MUST* match xf86drm.h */ - /* Flags for DMA buffer dispatch */ - _DRM_DMA_BLOCK = 0x01, /* Block until buffer dispatched. - Note, the buffer may not yet have - been processed by the hardware -- - getting a hardware lock with the - hardware quiescent will ensure - that the buffer has been - processed. */ - _DRM_DMA_WHILE_LOCKED = 0x02, /* Dispatch while lock held */ - _DRM_DMA_PRIORITY = 0x04, /* High priority dispatch */ - - /* Flags for DMA buffer request */ - _DRM_DMA_WAIT = 0x10, /* Wait for free buffers */ - _DRM_DMA_SMALLER_OK = 0x20, /* Smaller-than-requested buffers ok */ - _DRM_DMA_LARGER_OK = 0x40 /* Larger-than-requested buffers ok */ + +/** + * DMA flags + * + * \warning + * These values \e must match xf86drm.h. + * + * \sa drm_dma. + */ +typedef enum drm_dma_flags { + /* Flags for DMA buffer dispatch */ + _DRM_DMA_BLOCK = 0x01, /**< + * Block until buffer dispatched. + * + * \note The buffer may not yet have + * been processed by the hardware -- + * getting a hardware lock with the + * hardware quiescent will ensure + * that the buffer has been + * processed. + */ + _DRM_DMA_WHILE_LOCKED = 0x02, /**< Dispatch while lock held */ + _DRM_DMA_PRIORITY = 0x04, /**< High priority dispatch */ + + /* Flags for DMA buffer request */ + _DRM_DMA_WAIT = 0x10, /**< Wait for free buffers */ + _DRM_DMA_SMALLER_OK = 0x20, /**< Smaller-than-requested buffers OK */ + _DRM_DMA_LARGER_OK = 0x40 /**< Larger-than-requested buffers OK */ } drm_dma_flags_t; + +/** + * DRM_IOCTL_ADD_BUFS and DRM_IOCTL_MARK_BUFS ioctl argument type. + * + * \sa drmAddBufs(). + */ typedef struct drm_buf_desc { - int count; /* Number of buffers of this size */ - int size; /* Size in bytes */ - int low_mark; /* Low water mark */ - int high_mark; /* High water mark */ + int count; /**< Number of buffers of this size */ + int size; /**< Size in bytes */ + int low_mark; /**< Low water mark */ + int high_mark; /**< High water mark */ enum { - _DRM_PAGE_ALIGN = 0x01, /* Align on page boundaries for DMA */ - _DRM_AGP_BUFFER = 0x02, /* Buffer is in agp space */ - _DRM_SG_BUFFER = 0x04 /* Scatter/gather memory buffer */ + _DRM_PAGE_ALIGN = 0x01, /**< Align on page boundaries for DMA */ + _DRM_AGP_BUFFER = 0x02, /**< Buffer is in AGP space */ + _DRM_SG_BUFFER = 0x04 /**< Scatter/gather memory buffer */ } flags; - unsigned long agp_start; /* Start address of where the agp buffers - * are in the agp aperture */ + unsigned long agp_start; /**< + * Start address of where the AGP buffers are + * in the AGP aperture + */ } drm_buf_desc_t; + +/** + * DRM_IOCTL_INFO_BUFS ioctl argument type. + */ typedef struct drm_buf_info { - int count; /* Entries in list */ + int count; /**< Entries in list */ drm_buf_desc_t *list; } drm_buf_info_t; + +/** + * DRM_IOCTL_FREE_BUFS ioctl argument type. + */ typedef struct drm_buf_free { int count; int *list; } drm_buf_free_t; + +/** + * Buffer information + * + * \sa drm_buf_map. + */ typedef struct drm_buf_pub { - int idx; /* Index into master buflist */ - int total; /* Buffer size */ - int used; /* Amount of buffer in use (for DMA) */ - void *address; /* Address of buffer */ + int idx; /**< Index into the master buffer list */ + int total; /**< Buffer size */ + int used; /**< Amount of buffer in use (for DMA) */ + void *address; /**< Address of buffer */ } drm_buf_pub_t; + +/** + * DRM_IOCTL_MAP_BUFS ioctl argument type. + */ typedef struct drm_buf_map { - int count; /* Length of buflist */ - void *virtual; /* Mmaped area in user-virtual */ - drm_buf_pub_t *list; /* Buffer information */ + int count; /**< Length of the buffer list */ + void *virtual; /**< Mmap'd area in user-virtual */ + drm_buf_pub_t *list; /**< Buffer information */ } drm_buf_map_t; + +/** + * DRM_IOCTL_DMA ioctl argument type. + * + * Indices here refer to the offset into the buffer list in drm_buf_get. + * + * \sa drmDMA(). + */ typedef struct drm_dma { - /* Indices here refer to the offset into - buflist in drm_buf_get_t. */ - int context; /* Context handle */ - int send_count; /* Number of buffers to send */ - int *send_indices; /* List of handles to buffers */ - int *send_sizes; /* Lengths of data to send */ - drm_dma_flags_t flags; /* Flags */ - int request_count; /* Number of buffers requested */ - int request_size; /* Desired size for buffers */ - int *request_indices; /* Buffer information */ + int context; /**< Context handle */ + int send_count; /**< Number of buffers to send */ + int *send_indices; /**< List of handles to buffers */ + int *send_sizes; /**< Lengths of data to send */ + drm_dma_flags_t flags; /**< Flags */ + int request_count; /**< Number of buffers requested */ + int request_size; /**< Desired size for buffers */ + int *request_indices; /**< Buffer information */ int *request_sizes; - int granted_count; /* Number of buffers granted */ + int granted_count; /**< Number of buffers granted */ } drm_dma_t; + typedef enum { _DRM_CONTEXT_PRESERVED = 0x01, _DRM_CONTEXT_2DONLY = 0x02 } drm_ctx_flags_t; + +/** + * DRM_IOCTL_ADD_CTX ioctl argument type. + * + * \sa drmCreateContext() and drmDestroyContext(). + */ typedef struct drm_ctx { drm_context_t handle; drm_ctx_flags_t flags; } drm_ctx_t; + +/** + * DRM_IOCTL_RES_CTX ioctl argument type. + */ typedef struct drm_ctx_res { int count; drm_ctx_t *contexts; } drm_ctx_res_t; + +/** + * DRM_IOCTL_ADD_DRAW and DRM_IOCTL_RM_DRAW ioctl argument type. + */ typedef struct drm_draw { drm_drawable_t handle; } drm_draw_t; + +/** + * DRM_IOCTL_GET_MAGIC and DRM_IOCTL_AUTH_MAGIC ioctl argument type. + */ typedef struct drm_auth { drm_magic_t magic; } drm_auth_t; + +/** + * DRM_IOCTL_IRQ_BUSID ioctl argument type. + * + * \sa drmGetInterruptFromBusID(). + */ typedef struct drm_irq_busid { - int irq; - int busnum; - int devnum; - int funcnum; + int irq; /**< IRQ number */ + int busnum; /**< bus number */ + int devnum; /**< device number */ + int funcnum; /**< function number */ } drm_irq_busid_t; + typedef enum { - _DRM_VBLANK_ABSOLUTE = 0x0, /* Wait for specific vblank sequence number */ - _DRM_VBLANK_RELATIVE = 0x1, /* Wait for given number of vblanks */ - _DRM_VBLANK_SIGNAL = 0x40000000 /* Send signal instead of blocking */ + _DRM_VBLANK_ABSOLUTE = 0x0, /**< Wait for specific vblank sequence number */ + _DRM_VBLANK_RELATIVE = 0x1, /**< Wait for given number of vblanks */ + _DRM_VBLANK_SIGNAL = 0x40000000 /**< Send signal instead of blocking */ } drm_vblank_seq_type_t; + #define _DRM_VBLANK_FLAGS_MASK _DRM_VBLANK_SIGNAL + struct drm_wait_vblank_request { drm_vblank_seq_type_t type; unsigned int sequence; unsigned long signal; }; + struct drm_wait_vblank_reply { drm_vblank_seq_type_t type; unsigned int sequence; @@ -363,29 +511,59 @@ struct drm_wait_vblank_reply { long tval_usec; }; + +/** + * DRM_IOCTL_WAIT_VBLANK ioctl argument type. + * + * \sa drmWaitVBlank(). + */ typedef union drm_wait_vblank { struct drm_wait_vblank_request request; struct drm_wait_vblank_reply reply; } drm_wait_vblank_t; + +/** + * DRM_IOCTL_AGP_ENABLE ioctl argument type. + * + * \sa drmAgpEnable(). + */ typedef struct drm_agp_mode { - unsigned long mode; + unsigned long mode; /**< AGP mode */ } drm_agp_mode_t; - /* For drm_agp_alloc -- allocated a buffer */ + +/** + * DRM_IOCTL_AGP_ALLOC and DRM_IOCTL_AGP_FREE ioctls argument type. + * + * \sa drmAgpAlloc() and drmAgpFree(). + */ typedef struct drm_agp_buffer { - unsigned long size; /* In bytes -- will round to page boundary */ - unsigned long handle; /* Used for BIND/UNBIND ioctls */ - unsigned long type; /* Type of memory to allocate */ - unsigned long physical; /* Physical used by i810 */ + unsigned long size; /**< In bytes -- will round to page boundary */ + unsigned long handle; /**< Used for binding / unbinding */ + unsigned long type; /**< Type of memory to allocate */ + unsigned long physical; /**< Physical used by i810 */ } drm_agp_buffer_t; - /* For drm_agp_bind */ + +/** + * DRM_IOCTL_AGP_BIND and DRM_IOCTL_AGP_UNBIND ioctls argument type. + * + * \sa drmAgpBind() and drmAgpUnbind(). + */ typedef struct drm_agp_binding { - unsigned long handle; /* From drm_agp_buffer */ - unsigned long offset; /* In bytes -- will round to page boundary */ + unsigned long handle; /**< From drm_agp_buffer */ + unsigned long offset; /**< In bytes -- will round to page boundary */ } drm_agp_binding_t; + +/** + * DRM_IOCTL_AGP_INFO ioctl argument type. + * + * \sa drmAgpVersionMajor(), drmAgpVersionMinor(), drmAgpGetMode(), + * drmAgpBase(), drmAgpSize(), drmAgpMemoryUsed(), drmAgpMemoryAvail(), + * drmAgpVendorId() and drmAgpDeviceId(). + */ typedef struct drm_agp_info { int agp_version_major; int agp_version_minor; @@ -400,11 +578,18 @@ typedef struct drm_agp_info { unsigned short id_device; } drm_agp_info_t; + +/** + * DRM_IOCTL_SG_ALLOC ioctl argument type. + */ typedef struct drm_scatter_gather { - unsigned long size; /* In bytes -- will round to page boundary */ - unsigned long handle; /* Used for mapping / unmapping */ + unsigned long size; /**< In bytes -- will round to page boundary */ + unsigned long handle; /**< Used for mapping / unmapping */ } drm_scatter_gather_t; +/** + * DRM_IOCTL_SET_VERSION ioctl argument type. + */ typedef struct drm_set_version { int drm_di_major; int drm_di_minor; @@ -412,6 +597,7 @@ typedef struct drm_set_version { int drm_dd_minor; } drm_set_version_t; + #define DRM_IOCTL_BASE 'd' #define DRM_IO(nr) _IO(DRM_IOCTL_BASE,nr) #define DRM_IOR(nr,type) _IOR(DRM_IOCTL_BASE,nr,type) @@ -472,8 +658,13 @@ typedef struct drm_set_version { #define DRM_IOCTL_WAIT_VBLANK DRM_IOWR(0x3a, drm_wait_vblank_t) -/* Device specfic ioctls should only be in their respective headers - * The device specific ioctl range is 0x40 to 0x79. */ +/** + * Device specific ioctls should only be in their respective headers + * The device specific ioctl range is from 0x40 to 0x79. + * + * \sa drmCommandNone(), drmCommandRead(), drmCommandWrite(), and + * drmCommandReadWrite(). + */ #define DRM_COMMAND_BASE 0x40 #endif diff --git a/sys/dev/drm/drmP.h b/sys/dev/drm/drmP.h index adf9953..dc1ab7e 100644 --- a/sys/dev/drm/drmP.h +++ b/sys/dev/drm/drmP.h @@ -119,6 +119,8 @@ typedef struct drm_file drm_file_t; #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 DRM_GET_PRIV_SAREA(_dev, _ctx, _map) do { \ (_map) = (_dev)->context_sareas[_ctx]; \ } while(0) @@ -211,6 +213,9 @@ struct drm_file { drm_magic_t magic; unsigned long ioctl_count; struct drm_device *devXX; +#ifdef DRIVER_FILE_FIELDS + DRIVER_FILE_FIELDS; +#endif }; typedef struct drm_lock_data { @@ -314,6 +319,7 @@ struct drm_device { device_t device; /* Device instance from newbus */ #endif dev_t devnode; /* Device number for mknod */ + int if_version; /* Highest interface version set */ int flags; /* Flags to open(2) */ @@ -330,7 +336,6 @@ struct drm_device { /* Usage Counters */ int open_count; /* Outstanding files open */ int buf_use; /* Buffers in use -- cannot alloc */ - int buf_alloc; /* Buffer allocation in progress */ /* Performance counters */ unsigned long counters; @@ -354,14 +359,21 @@ struct drm_device { /* Context support */ int irq; /* Interrupt used by board */ - int irqrid; /* Interrupt used by board */ + int irq_enabled; /* True if the irq handler is enabled */ #ifdef __FreeBSD__ + int irqrid; /* Interrupt used by board */ struct resource *irqr; /* Resource for interrupt used by board */ #elif defined(__NetBSD__) struct pci_attach_args pa; pci_intr_handle_t ih; #endif void *irqh; /* Handle from bus_setup_intr */ + + 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 */ #if __FreeBSD_version >= 400005 @@ -444,7 +456,7 @@ extern void DRM(reclaim_buffers)(drm_device_t *dev, DRMFILE filp); #if __HAVE_IRQ /* IRQ support (drm_irq.h) */ -extern int DRM(irq_install)( drm_device_t *dev, int irq ); +extern int DRM(irq_install)(drm_device_t *dev); extern int DRM(irq_uninstall)( drm_device_t *dev ); extern irqreturn_t DRM(irq_handler)( DRM_IRQ_ARGS ); extern void DRM(driver_irq_preinstall)( drm_device_t *dev ); @@ -493,7 +505,7 @@ extern int DRM(version)( DRM_IOCTL_ARGS ); extern int DRM(setversion)( DRM_IOCTL_ARGS ); /* Misc. IOCTL support (drm_ioctl.h) */ -extern int DRM(irq_busid)(DRM_IOCTL_ARGS); +extern int DRM(irq_by_busid)(DRM_IOCTL_ARGS); extern int DRM(getunique)(DRM_IOCTL_ARGS); extern int DRM(setunique)(DRM_IOCTL_ARGS); extern int DRM(getmap)(DRM_IOCTL_ARGS); diff --git a/sys/dev/drm/drm_bufs.h b/sys/dev/drm/drm_bufs.h index efb8ce7..5053d36 100644 --- a/sys/dev/drm/drm_bufs.h +++ b/sys/dev/drm/drm_bufs.h @@ -137,7 +137,17 @@ int DRM(addmap)( DRM_IOCTL_ARGS ) } map->offset = (unsigned long)map->handle; 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(); + DRM(free)(map->handle, map->size, + DRM_MEM_SAREA); + DRM(free)(map, sizeof(*map), DRM_MEM_MAPS); + return DRM_ERR(EBUSY); + } dev->lock.hw_lock = map->handle; /* Pointer to lock */ + DRM_UNLOCK(); } break; #if __REALLY_HAVE_AGP diff --git a/sys/dev/drm/drm_drv.h b/sys/dev/drm/drm_drv.h index 191dc9f..395ba0b 100644 --- a/sys/dev/drm/drm_drv.h +++ b/sys/dev/drm/drm_drv.h @@ -102,6 +102,9 @@ #ifndef DRIVER_IOCTLS #define DRIVER_IOCTLS #endif +#ifndef DRIVER_OPEN_HELPER +#define DRIVER_OPEN_HELPER( priv, dev ) +#endif #ifndef DRIVER_FOPS #endif @@ -132,7 +135,9 @@ static drm_ioctl_desc_t DRM(ioctls)[] = { [DRM_IOCTL_NR(DRM_IOCTL_VERSION)] = { DRM(version), 0, 0 }, [DRM_IOCTL_NR(DRM_IOCTL_GET_UNIQUE)] = { DRM(getunique), 0, 0 }, [DRM_IOCTL_NR(DRM_IOCTL_GET_MAGIC)] = { DRM(getmagic), 0, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_IRQ_BUSID)] = { DRM(irq_busid), 0, 1 }, +#if __HAVE_IRQ + [DRM_IOCTL_NR(DRM_IOCTL_IRQ_BUSID)] = { DRM(irq_by_busid), 0, 1 }, +#endif [DRM_IOCTL_NR(DRM_IOCTL_GET_MAP)] = { DRM(getmap), 0, 0 }, [DRM_IOCTL_NR(DRM_IOCTL_GET_CLIENT)] = { DRM(getclient), 0, 0 }, [DRM_IOCTL_NR(DRM_IOCTL_GET_STATS)] = { DRM(getstats), 0, 0 }, @@ -413,14 +418,15 @@ const char *DRM(find_description)(int vendor, int device) { return NULL; } -/* Initialize the DRM on first open. Called with device's lock held */ +/* Initialize the DRM on first open. */ static int DRM(setup)( drm_device_t *dev ) { int i; + DRM_SPINLOCK_ASSERT(&dev->dev_lock); + DRIVER_PRESETUP(); dev->buf_use = 0; - dev->buf_alloc = 0; #if __HAVE_DMA i = DRM(dma_setup)( dev ); @@ -476,9 +482,10 @@ static int DRM(setup)( drm_device_t *dev ) dev->lock.hw_lock = NULL; dev->lock.lock_queue = 0; - dev->irq = 0; + dev->irq_enabled = 0; dev->context_flag = 0; dev->last_context = 0; + dev->if_version = 0; #ifdef __FreeBSD__ dev->buf_sigio = NULL; @@ -492,9 +499,7 @@ static int DRM(setup)( drm_device_t *dev ) return 0; } -/* Free resources associated with the DRM on the last close. - * Called with the device's lock held. - */ +/* Free resources associated with the DRM on the last close. */ static int DRM(takedown)( drm_device_t *dev ) { drm_magic_entry_t *pt, *next; @@ -502,11 +507,13 @@ static int DRM(takedown)( drm_device_t *dev ) drm_map_list_entry_t *list; int i; + DRM_SPINLOCK_ASSERT(&dev->dev_lock); + DRM_DEBUG( "\n" ); DRIVER_PRETAKEDOWN(); #if __HAVE_IRQ - if (dev->irq != 0) + if (dev->irq_enabled) DRM(irq_uninstall)( dev ); #endif @@ -643,6 +650,13 @@ static int DRM(init)( device_t nbdev ) unit = minor(dev->device.dv_unit); #endif + dev->irq = pci_get_irq(dev->device); + /* XXX Fix domain number (alpha hoses) */ + dev->pci_domain = 0; + 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->maplist = DRM(calloc)(1, sizeof(*dev->maplist), DRM_MEM_MAPS); if (dev->maplist == NULL) { retcode = ENOMEM; diff --git a/sys/dev/drm/drm_fops.h b/sys/dev/drm/drm_fops.h index eb44970..190b708 100644 --- a/sys/dev/drm/drm_fops.h +++ b/sys/dev/drm/drm_fops.h @@ -34,7 +34,6 @@ #include "dev/drm/drmP.h" -/* Requires device lock held */ drm_file_t *DRM(find_file_by_proc)(drm_device_t *dev, DRM_STRUCTPROC *p) { #if __FreeBSD_version >= 500021 @@ -46,6 +45,8 @@ drm_file_t *DRM(find_file_by_proc)(drm_device_t *dev, DRM_STRUCTPROC *p) #endif drm_file_t *priv; + DRM_SPINLOCK_ASSERT(&dev->dev_lock); + TAILQ_FOREACH(priv, &dev->files, link) if (priv->pid == pid && priv->uid == uid) return priv; @@ -66,7 +67,7 @@ int DRM(open_helper)(dev_t kdev, int flags, int fmt, DRM_STRUCTPROC *p, DRM_DEBUG("pid = %d, minor = %d\n", DRM_CURRENTPID, m); DRM_LOCK(); - priv = (drm_file_t *) DRM(find_file_by_proc)(dev, p); + priv = DRM(find_file_by_proc)(dev, p); if (priv) { priv->refs++; } else { @@ -89,6 +90,9 @@ int DRM(open_helper)(dev_t kdev, int flags, int fmt, DRM_STRUCTPROC *p, priv->devXX = dev; priv->ioctl_count = 0; priv->authenticated = !DRM_SUSER(p); + + DRIVER_OPEN_HELPER( priv, dev ); + TAILQ_INSERT_TAIL(&dev->files, priv, link); } DRM_UNLOCK(); diff --git a/sys/dev/drm/drm_ioctl.h b/sys/dev/drm/drm_ioctl.h index 83953c7..d348519 100644 --- a/sys/dev/drm/drm_ioctl.h +++ b/sys/dev/drm/drm_ioctl.h @@ -33,53 +33,6 @@ #include "dev/drm/drmP.h" -int DRM(irq_busid)( DRM_IOCTL_ARGS ) -{ -#ifdef __FreeBSD__ - drm_irq_busid_t id; - devclass_t pci; - device_t bus, dev; - device_t *kids; - int error, i, num_kids; - - DRM_COPY_FROM_USER_IOCTL( id, (drm_irq_busid_t *)data, sizeof(id) ); - - pci = devclass_find("pci"); - if (!pci) - return ENOENT; - bus = devclass_get_device(pci, id.busnum); - if (!bus) - return ENOENT; - error = device_get_children(bus, &kids, &num_kids); - if (error) - return error; - - dev = 0; - for (i = 0; i < num_kids; i++) { - dev = kids[i]; - if (pci_get_slot(dev) == id.devnum - && pci_get_function(dev) == id.funcnum) - break; - } - - free(kids, M_TEMP); - - if (i != num_kids) - id.irq = pci_get_irq(dev); - else - id.irq = 0; - DRM_DEBUG("%d:%d:%d => IRQ %d\n", - id.busnum, id.devnum, id.funcnum, id.irq); - - DRM_COPY_TO_USER_IOCTL( (drm_irq_busid_t *)data, id, sizeof(id) ); - - return 0; -#else - /* don't support interrupt-driven drivers on Net yet */ - return ENOENT; -#endif -} - /* * Beginning in revision 1.1 of the DRM interface, getunique will return * a unique in the form pci:oooo:bb:dd.f (o=domain, b=bus, d=device, f=function) @@ -110,7 +63,8 @@ int DRM(getunique)( DRM_IOCTL_ARGS ) int DRM(setunique)( DRM_IOCTL_ARGS ) { DRM_DEVICE; - drm_unique_t u; + drm_unique_t u; + int domain, bus, slot, func, ret; if (dev->unique_len || dev->unique) return DRM_ERR(EBUSY); @@ -131,6 +85,21 @@ int DRM(setunique)( DRM_IOCTL_ARGS ) dev->unique[dev->unique_len] = '\0'; + /* Return error if the busid submitted doesn't match the device's actual + * busid. + */ + ret = sscanf(dev->unique, "PCI:%d:%d:%d", &bus, &slot, &func); + if (ret != 3) + return DRM_ERR(EINVAL); + domain = bus >> 8; + bus &= 0xff; + + if ((domain != dev->pci_domain) || + (bus != dev->pci_bus) || + (slot != dev->pci_slot) || + (func != dev->pci_func)) + return DRM_ERR(EINVAL); + return 0; } @@ -147,10 +116,8 @@ DRM(set_busid)(drm_device_t *dev) if (dev->unique == NULL) return ENOMEM; - /* XXX Fix domain number (alpha hoses) */ snprintf(dev->unique, dev->unique_len, "pci:%04x:%02x:%02x.%1x", - 0, pci_get_bus(dev->device), pci_get_slot(dev->device), - pci_get_function(dev->device)); + dev->pci_domain, dev->pci_bus, dev->pci_slot, dev->pci_func); return 0; } @@ -261,26 +228,31 @@ int DRM(getstats)( DRM_IOCTL_ARGS ) return 0; } +#define DRM_IF_MAJOR 1 +#define DRM_IF_MINOR 2 + int DRM(setversion)(DRM_IOCTL_ARGS) { DRM_DEVICE; drm_set_version_t sv; drm_set_version_t retv; + int if_version; DRM_COPY_FROM_USER_IOCTL(sv, (drm_set_version_t *)data, sizeof(sv)); - retv.drm_di_major = 1; - retv.drm_di_minor = 1; + retv.drm_di_major = DRM_IF_MAJOR; + retv.drm_di_minor = DRM_IF_MINOR; retv.drm_dd_major = DRIVER_MAJOR; retv.drm_dd_minor = DRIVER_MINOR; DRM_COPY_TO_USER_IOCTL((drm_set_version_t *)data, retv, sizeof(sv)); if (sv.drm_di_major != -1) { - if (sv.drm_di_major != 1 || sv.drm_di_minor < 0) - return EINVAL; - if (sv.drm_di_minor > 1) + if (sv.drm_di_major != DRM_IF_MAJOR || + sv.drm_di_minor < 0 || sv.drm_di_minor > DRM_IF_MINOR) return EINVAL; + if_version = DRM_IF_VERSION(sv.drm_di_major, sv.drm_dd_minor); + dev->if_version = DRM_MAX(if_version, dev->if_version); if (sv.drm_di_minor >= 1) { /* * Version 1.1 includes tying of DRM to specific device @@ -290,12 +262,11 @@ int DRM(setversion)(DRM_IOCTL_ARGS) } if (sv.drm_dd_major != -1) { - if (sv.drm_dd_major != DRIVER_MAJOR || sv.drm_dd_minor < 0) - return EINVAL; - if (sv.drm_dd_minor > DRIVER_MINOR) + if (sv.drm_dd_major != DRIVER_MAJOR || + sv.drm_dd_minor < 0 || sv.drm_dd_minor > DRIVER_MINOR) return EINVAL; #ifdef DRIVER_SETVERSION - DRIVER_SETVERSION(dev, sv); + DRIVER_SETVERSION(dev, &sv); #endif } return 0; diff --git a/sys/dev/drm/drm_irq.h b/sys/dev/drm/drm_irq.h index e062f6c..7275269 100644 --- a/sys/dev/drm/drm_irq.h +++ b/sys/dev/drm/drm_irq.h @@ -29,6 +29,29 @@ * $FreeBSD$ */ +int DRM(irq_by_busid)( DRM_IOCTL_ARGS ) +{ + DRM_DEVICE; + drm_irq_busid_t irq; + + DRM_COPY_FROM_USER_IOCTL(irq, (drm_irq_busid_t *)data, sizeof(irq)); + + 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); + + DRM_COPY_TO_USER_IOCTL( (drm_irq_busid_t *)data, irq, sizeof(irq) ); + + return 0; +} + #if defined(__FreeBSD__) && __FreeBSD_version >= 500000 static irqreturn_t DRM(irq_handler_wrap)(DRM_IRQ_ARGS) @@ -41,22 +64,22 @@ DRM(irq_handler_wrap)(DRM_IRQ_ARGS) } #endif -int DRM(irq_install)( drm_device_t *dev, int irq ) +int DRM(irq_install)(drm_device_t *dev) { int retcode; - if ( irq == 0 || dev->dev_private == NULL) + if (dev->irq == 0 || dev->dev_private == NULL) return DRM_ERR(EINVAL); DRM_LOCK(); - if ( dev->irq ) { + if (dev->irq_enabled) { DRM_UNLOCK(); return DRM_ERR(EBUSY); } - dev->irq = irq; + dev->irq_enabled = 1; DRM_UNLOCK(); - DRM_DEBUG( "%s: irq=%d\n", __FUNCTION__, irq ); + DRM_DEBUG( "%s: irq=%d\n", __FUNCTION__, dev->irq ); dev->context_flag = 0; @@ -69,31 +92,18 @@ int DRM(irq_install)( drm_device_t *dev, int irq ) DRM_SPININIT(dev->irq_lock, "DRM IRQ lock"); -#if __HAVE_VBL_IRQ && 0 /* disabled */ - TAILQ_INIT( &dev->vbl_sig_list ); -#endif - /* Before installing handler */ DRM(driver_irq_preinstall)( dev ); /* Install handler */ - dev->irqrid = 0; #ifdef __FreeBSD__ + dev->irqrid = 0; dev->irqr = bus_alloc_resource(dev->device, SYS_RES_IRQ, &dev->irqrid, 0, ~0, 1, RF_SHAREABLE); if (!dev->irqr) { -#elif defined(__NetBSD__) - if (pci_intr_map(&dev->pa, &dev->ih) != 0) { -#endif - DRM_LOCK(); - DRM_SPINUNINIT(dev->irq_lock); - dev->irq = 0; - dev->irqrid = 0; - DRM_UNLOCK(); - return ENOENT; + retcode = ENOENT; + goto err; } - -#ifdef __FreeBSD__ #if __FreeBSD_version < 500000 retcode = bus_setup_intr(dev->device, dev->irqr, INTR_TYPE_TTY, DRM(irq_handler), dev, &dev->irqh); @@ -101,45 +111,55 @@ int DRM(irq_install)( drm_device_t *dev, int irq ) retcode = bus_setup_intr(dev->device, dev->irqr, INTR_TYPE_TTY | INTR_MPSAFE, DRM(irq_handler_wrap), dev, &dev->irqh); #endif - if ( retcode ) { + if (retcode != 0) + goto err; #elif defined(__NetBSD__) + if (pci_intr_map(&dev->pa, &dev->ih) != 0) { + retcode = ENOENT; + goto err; + } dev->irqh = pci_intr_establish(&dev->pa.pa_pc, dev->ih, IPL_TTY, (irqreturn_t (*)(DRM_IRQ_ARGS))DRM(irq_handler), dev); - if ( !dev->irqh ) { -#endif - DRM_LOCK(); -#ifdef __FreeBSD__ - bus_release_resource(dev->device, SYS_RES_IRQ, dev->irqrid, dev->irqr); -#endif - DRM_SPINUNINIT(dev->irq_lock); - dev->irq = 0; - dev->irqrid = 0; - DRM_UNLOCK(); - return retcode; + if (!dev->irqh) { + retcode = ENOENT; + goto err; } +#endif /* After installing handler */ DRM(driver_irq_postinstall)( dev ); return 0; +err: + DRM_LOCK(); + dev->irq_enabled = 0; +#ifdef ___FreeBSD__ + if (dev->irqrid != 0) { + bus_release_resource(dev->device, SYS_RES_IRQ, dev->irqrid, + dev->irqr); + dev->irqrid = 0; + } +#endif + DRM_SPINUNINIT(dev->irq_lock); + DRM_UNLOCK(); + return retcode; } +/* XXX: This function needs to be called with the device lock held. In some + * cases it isn't, so far. + */ int DRM(irq_uninstall)( drm_device_t *dev ) { - int irq; int irqrid; - - DRM_LOCK(); - irq = dev->irq; - irqrid = dev->irqrid; - dev->irq = 0; - dev->irqrid = 0; - DRM_UNLOCK(); - if ( !irq ) + if (!dev->irq_enabled) return DRM_ERR(EINVAL); - DRM_DEBUG( "%s: irq=%d\n", __FUNCTION__, irq ); + dev->irq_enabled = 0; + irqrid = dev->irqrid; + dev->irqrid = 0; + + DRM_DEBUG( "%s: irq=%d\n", __FUNCTION__, dev->irq ); DRM(driver_irq_uninstall)( dev ); @@ -158,14 +178,21 @@ int DRM(control)( DRM_IOCTL_ARGS ) { DRM_DEVICE; drm_control_t ctl; + int err; DRM_COPY_FROM_USER_IOCTL( ctl, (drm_control_t *) data, sizeof(ctl) ); switch ( ctl.func ) { case DRM_INST_HANDLER: - return DRM(irq_install)( dev, ctl.irq ); + if (dev->if_version < DRM_IF_VERSION(1, 2) && + ctl.irq != dev->irq) + return DRM_ERR(EINVAL); + return DRM(irq_install)(dev); case DRM_UNINST_HANDLER: - return DRM(irq_uninstall)( dev ); + DRM_LOCK(); + err = DRM(irq_uninstall)( dev ); + DRM_UNLOCK(); + return err; default: return DRM_ERR(EINVAL); } @@ -179,7 +206,7 @@ int DRM(wait_vblank)( DRM_IOCTL_ARGS ) struct timeval now; int ret; - if (!dev->irq) + if (!dev->irq_enabled) return DRM_ERR(EINVAL); DRM_COPY_FROM_USER_IOCTL( vblwait, (drm_wait_vblank_t *)data, diff --git a/sys/dev/drm/drm_os_freebsd.h b/sys/dev/drm/drm_os_freebsd.h index de03771..43b6524 100644 --- a/sys/dev/drm/drm_os_freebsd.h +++ b/sys/dev/drm/drm_os_freebsd.h @@ -124,6 +124,7 @@ #define DRM_SPINUNINIT(l) mtx_destroy(&l) #define DRM_SPINLOCK(l) mtx_lock(l) #define DRM_SPINUNLOCK(u) 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) @@ -139,6 +140,7 @@ #define DRM_SPINUNINIT(l) #define DRM_SPINLOCK(l) #define DRM_SPINUNLOCK(u) +#define DRM_SPINLOCK_ASSERT(l) #define DRM_CURRENTPID curproc->p_pid #define DRM_LOCK() #define DRM_UNLOCK() @@ -269,8 +271,12 @@ for ( ret = 0 ; !ret && !(condition) ; ) { \ (!useracc((caddr_t)uaddr, size, VM_PROT_READ)) #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) = fuword(uaddr), 0) +#define DRM_PUT_USER_UNCHECKED(uaddr, val) \ + suword(uaddr, val) /* DRM_READMEMORYBARRIER() prevents reordering of reads. * DRM_WRITEMEMORYBARRIER() prevents reordering of writes. diff --git a/sys/dev/drm/mga_dma.c b/sys/dev/drm/mga_dma.c index 6745d65..01406b5 100644 --- a/sys/dev/drm/mga_dma.c +++ b/sys/dev/drm/mga_dma.c @@ -646,7 +646,7 @@ int mga_do_cleanup_dma( drm_device_t *dev ) * may not have been called from userspace and after dev_private * is freed, it's too late. */ - if ( dev->irq ) DRM(irq_uninstall)(dev); + if ( dev->irq_enabled ) DRM(irq_uninstall)(dev); #endif if ( dev->dev_private ) { diff --git a/sys/dev/drm/r128_cce.c b/sys/dev/drm/r128_cce.c index 87c4d81..39b37a8 100644 --- a/sys/dev/drm/r128_cce.c +++ b/sys/dev/drm/r128_cce.c @@ -601,7 +601,7 @@ int r128_do_cleanup_cce( drm_device_t *dev ) * may not have been called from userspace and after dev_private * is freed, it's too late. */ - if ( dev->irq ) DRM(irq_uninstall)(dev); + if ( dev->irq_enabled ) DRM(irq_uninstall)(dev); #endif if ( dev->dev_private ) { diff --git a/sys/dev/drm/radeon.h b/sys/dev/drm/radeon.h index 3dbf9a1..3cdf7fb 100644 --- a/sys/dev/drm/radeon.h +++ b/sys/dev/drm/radeon.h @@ -53,7 +53,7 @@ #define DRIVER_DATE "20020828" #define DRIVER_MAJOR 1 -#define DRIVER_MINOR 9 +#define DRIVER_MINOR 10 #define DRIVER_PATCHLEVEL 0 /* Interface history: @@ -83,6 +83,9 @@ * Add 'GET' queries for starting additional clients on different VT's. * 1.9 - Add DRM_IOCTL_RADEON_CP_RESUME ioctl. * Add texture rectangle support for r100. + * 1.10- Add SETPARAM ioctl; first parameter to set is FB_LOCATION, which + * clients use to tell the DRM where they think the framebuffer is + * located in the card's address space */ #define DRIVER_IOCTLS \ [DRM_IOCTL_NR(DRM_IOCTL_DMA)] = { radeon_cp_buffers, 1, 0 }, \ @@ -108,8 +111,9 @@ [DRM_IOCTL_NR(DRM_IOCTL_RADEON_ALLOC)] = { radeon_mem_alloc, 1, 0 }, \ [DRM_IOCTL_NR(DRM_IOCTL_RADEON_FREE)] = { radeon_mem_free, 1, 0 }, \ [DRM_IOCTL_NR(DRM_IOCTL_RADEON_INIT_HEAP)] = { radeon_mem_init_heap, 1, 1 }, \ - [DRM_IOCTL_NR(DRM_IOCTL_RADEON_IRQ_EMIT)] = { radeon_irq_emit, 1, 0 }, \ - [DRM_IOCTL_NR(DRM_IOCTL_RADEON_IRQ_WAIT)] = { radeon_irq_wait, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_RADEON_IRQ_EMIT)] = { radeon_irq_emit, 1, 0 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_RADEON_IRQ_WAIT)] = { radeon_irq_wait, 1, 0 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_RADEON_SETPARAM)] = { radeon_cp_setparam, 1, 0 }, \ #define DRIVER_PCI_IDS \ {0x1002, 0x4242, 0, "ATI Radeon BB R200 AIW 8500DV"}, \ @@ -149,6 +153,17 @@ {0x1002, 0x5961, 0, "ATI Radeon RV280 9200"}, \ {0, 0, 0, NULL} +#define DRIVER_FILE_FIELDS \ + int64_t radeon_fb_delta; \ + +#define DRIVER_OPEN_HELPER( filp_priv, dev ) \ +do { \ + drm_radeon_private_t *dev_priv = dev->dev_private; \ + if ( dev_priv ) \ + filp_priv->radeon_fb_delta = dev_priv->fb_location; \ + else \ + filp_priv->radeon_fb_delta = 0; \ +} while( 0 ) /* When a client dies: * - Check for and clean up flipped page state diff --git a/sys/dev/drm/radeon_cp.c b/sys/dev/drm/radeon_cp.c index b134f95..6ec65b7 100644 --- a/sys/dev/drm/radeon_cp.c +++ b/sys/dev/drm/radeon_cp.c @@ -857,7 +857,8 @@ static void radeon_cp_init_ring_buffer( drm_device_t *dev, /* Initialize the memory controller */ RADEON_WRITE( RADEON_MC_FB_LOCATION, - (dev_priv->gart_vm_start - 1) & 0xffff0000 ); + ( ( dev_priv->gart_vm_start - 1 ) & 0xffff0000 ) + | ( dev_priv->fb_location >> 16 ) ); #if __REALLY_HAVE_AGP if ( !dev_priv->is_pci ) { @@ -1073,13 +1074,6 @@ static int radeon_do_init_cp( drm_device_t *dev, drm_radeon_init_t *init ) dev_priv->depth_offset = init->depth_offset; dev_priv->depth_pitch = init->depth_pitch; - dev_priv->front_pitch_offset = (((dev_priv->front_pitch/64) << 22) | - (dev_priv->front_offset >> 10)); - dev_priv->back_pitch_offset = (((dev_priv->back_pitch/64) << 22) | - (dev_priv->back_offset >> 10)); - dev_priv->depth_pitch_offset = (((dev_priv->depth_pitch/64) << 22) | - (dev_priv->depth_offset >> 10)); - /* Hardware state for depth clears. Remove this if/when we no * longer clear the depth buffer with a 3D rectangle. Hard-code * all values to prevent unwanted 3D state from slipping through @@ -1206,9 +1200,26 @@ static int radeon_do_init_cp( drm_device_t *dev, drm_radeon_init_t *init ) dev_priv->buffers->handle ); } + dev_priv->fb_location = ( RADEON_READ( RADEON_MC_FB_LOCATION ) + & 0xffff ) << 16; + + dev_priv->front_pitch_offset = (((dev_priv->front_pitch/64) << 22) | + ( ( dev_priv->front_offset + + dev_priv->fb_location ) >> 10 ) ); + + dev_priv->back_pitch_offset = (((dev_priv->back_pitch/64) << 22) | + ( ( dev_priv->back_offset + + dev_priv->fb_location ) >> 10 ) ); + + dev_priv->depth_pitch_offset = (((dev_priv->depth_pitch/64) << 22) | + ( ( dev_priv->depth_offset + + dev_priv->fb_location ) >> 10 ) ); + dev_priv->gart_size = init->gart_size; - dev_priv->gart_vm_start = RADEON_READ( RADEON_CONFIG_APER_SIZE ); + dev_priv->gart_vm_start = dev_priv->fb_location + + RADEON_READ( RADEON_CONFIG_APER_SIZE ); + #if __REALLY_HAVE_AGP if ( !dev_priv->is_pci ) dev_priv->gart_buffers_offset = (dev_priv->buffers->offset @@ -1278,7 +1289,7 @@ int radeon_do_cleanup_cp( drm_device_t *dev ) * may not have been called from userspace and after dev_private * is freed, it's too late. */ - if ( dev->irq ) DRM(irq_uninstall)(dev); + if ( dev->irq_enabled ) DRM(irq_uninstall)(dev); #endif if ( dev->dev_private ) { diff --git a/sys/dev/drm/radeon_drm.h b/sys/dev/drm/radeon_drm.h index 3bf4877..bd4dde3 100644 --- a/sys/dev/drm/radeon_drm.h +++ b/sys/dev/drm/radeon_drm.h @@ -392,6 +392,7 @@ typedef struct { #define DRM_IOCTL_RADEON_IRQ_WAIT DRM_IOW( 0x57, drm_radeon_irq_wait_t) /* added by Charl P. Botha - see radeon_cp.c for details */ #define DRM_IOCTL_RADEON_CP_RESUME DRM_IO(0x58) +#define DRM_IOCTL_RADEON_SETPARAM DRM_IOW(0x59, drm_radeon_setparam_t) typedef struct drm_radeon_init { enum { @@ -504,7 +505,7 @@ typedef struct drm_radeon_tex_image { } drm_radeon_tex_image_t; typedef struct drm_radeon_texture { - int offset; + unsigned int offset; int pitch; int format; int width; /* Texture image coordinates */ @@ -539,6 +540,7 @@ typedef struct drm_radeon_indirect { #define RADEON_PARAM_STATUS_HANDLE 8 #define RADEON_PARAM_SAREA_HANDLE 9 #define RADEON_PARAM_GART_TEX_HANDLE 10 +#define RADEON_PARAM_SCRATCH_OFFSET 11 typedef struct drm_radeon_getparam { int param; @@ -580,4 +582,16 @@ typedef struct drm_radeon_irq_wait { } drm_radeon_irq_wait_t; +/* 1.10: Clients tell the DRM where they think the framebuffer is located in + * the card's address space, via a new generic ioctl to set parameters + */ + +typedef struct drm_radeon_setparam { + unsigned int param; + int64_t value; +} drm_radeon_setparam_t; + +#define RADEON_SETPARAM_FB_LOCATION 1 /* determined framebuffer location */ + + #endif diff --git a/sys/dev/drm/radeon_drv.h b/sys/dev/drm/radeon_drv.h index 1e9d2af..6a04349 100644 --- a/sys/dev/drm/radeon_drv.h +++ b/sys/dev/drm/radeon_drv.h @@ -75,6 +75,8 @@ typedef struct drm_radeon_private { drm_radeon_ring_buffer_t ring; drm_radeon_sarea_t *sarea_priv; + u32 fb_location; + int gart_size; u32 gart_vm_start; unsigned long gart_buffers_offset; @@ -186,6 +188,7 @@ extern int radeon_cp_indirect( DRM_IOCTL_ARGS ); extern int radeon_cp_vertex2( DRM_IOCTL_ARGS ); extern int radeon_cp_cmdbuf( DRM_IOCTL_ARGS ); extern int radeon_cp_getparam( DRM_IOCTL_ARGS ); +extern int radeon_cp_setparam( DRM_IOCTL_ARGS ); extern int radeon_cp_flip( DRM_IOCTL_ARGS ); extern int radeon_mem_alloc( DRM_IOCTL_ARGS ); @@ -241,6 +244,7 @@ extern void radeon_do_release(drm_device_t *dev); #define RADEON_CRTC2_OFFSET 0x0324 #define RADEON_CRTC2_OFFSET_CNTL 0x0328 +#define RADEON_RB3D_COLOROFFSET 0x1c40 #define RADEON_RB3D_COLORPITCH 0x1c48 #define RADEON_DP_GUI_MASTER_CNTL 0x146c @@ -334,6 +338,7 @@ extern void radeon_do_release(drm_device_t *dev); #define RADEON_PP_MISC 0x1c14 #define RADEON_PP_ROT_MATRIX_0 0x1d58 #define RADEON_PP_TXFILTER_0 0x1c54 +#define RADEON_PP_TXOFFSET_0 0x1c5c #define RADEON_PP_TXFILTER_1 0x1c6c #define RADEON_PP_TXFILTER_2 0x1c84 diff --git a/sys/dev/drm/radeon_state.c b/sys/dev/drm/radeon_state.c index cbeeedd..eb3cf20 100644 --- a/sys/dev/drm/radeon_state.c +++ b/sys/dev/drm/radeon_state.c @@ -38,6 +38,151 @@ /* ================================================================ + * Helper functions for client state checking and fixup + */ + +static __inline__ int radeon_check_and_fixup_offset( drm_radeon_private_t *dev_priv, + drm_file_t *filp_priv, + u32 *offset ) { + u32 off = *offset; + + if ( off >= dev_priv->fb_location && + off < ( dev_priv->gart_vm_start + dev_priv->gart_size ) ) + return 0; + + off += filp_priv->radeon_fb_delta; + + DRM_DEBUG( "offset fixed up to 0x%x\n", off ); + + if ( off < dev_priv->fb_location || + off >= ( dev_priv->gart_vm_start + dev_priv->gart_size ) ) + return DRM_ERR( EINVAL ); + + *offset = off; + + return 0; +} + +static __inline__ int radeon_check_and_fixup_offset_user( drm_radeon_private_t *dev_priv, + drm_file_t *filp_priv, + u32 *offset ) { + u32 off; + + DRM_GET_USER_UNCHECKED( off, offset ); + + if ( radeon_check_and_fixup_offset( dev_priv, filp_priv, &off ) ) + return DRM_ERR( EINVAL ); + + DRM_PUT_USER_UNCHECKED( offset, off ); + + return 0; +} + +static __inline__ int radeon_check_and_fixup_packets( drm_radeon_private_t *dev_priv, + drm_file_t *filp_priv, + int id, + u32 *data ) { + if ( id == RADEON_EMIT_PP_MISC && + radeon_check_and_fixup_offset_user( dev_priv, filp_priv, + &data[( RADEON_RB3D_DEPTHOFFSET + - RADEON_PP_MISC ) / 4] ) ) { + DRM_ERROR( "Invalid depth buffer offset\n" ); + return DRM_ERR( EINVAL ); + } else if ( id == RADEON_EMIT_PP_CNTL && + radeon_check_and_fixup_offset_user( dev_priv, filp_priv, + &data[( RADEON_RB3D_COLOROFFSET + - RADEON_PP_CNTL ) / 4] ) ) { + DRM_ERROR( "Invalid colour buffer offset\n" ); + return DRM_ERR( EINVAL ); + } else if ( id >= R200_EMIT_PP_TXOFFSET_0 && + id <= R200_EMIT_PP_TXOFFSET_5 && + radeon_check_and_fixup_offset_user( dev_priv, filp_priv, + &data[0] ) ) { + DRM_ERROR( "Invalid R200 texture offset\n" ); + return DRM_ERR( EINVAL ); + } else if ( ( id == RADEON_EMIT_PP_TXFILTER_0 || id == RADEON_EMIT_PP_TXFILTER_1 || + id == RADEON_EMIT_PP_TXFILTER_2 /*|| id == RADEON_EMIT_PP_TXFILTER_3 || + id == RADEON_EMIT_PP_TXFILTER_4 || id == RADEON_EMIT_PP_TXFILTER_5*/ ) && + radeon_check_and_fixup_offset_user( dev_priv, filp_priv, + &data[( RADEON_PP_TXOFFSET_0 + - RADEON_PP_TXFILTER_0 ) / 4] ) ) { + DRM_ERROR( "Invalid R100 texture offset\n" ); + return DRM_ERR( EINVAL ); + } else if ( id == R200_PP_CUBIC_OFFSET_F1_0 || id == R200_PP_CUBIC_OFFSET_F1_1 || + id == R200_PP_CUBIC_OFFSET_F1_2 || id == R200_PP_CUBIC_OFFSET_F1_3 || + id == R200_PP_CUBIC_OFFSET_F1_4 || id == R200_PP_CUBIC_OFFSET_F1_5 ) { + int i; + for ( i = 0; i < 6; i++ ) { + if ( radeon_check_and_fixup_offset_user( dev_priv, + filp_priv, + &data[i] ) ) { + DRM_ERROR( "Invalid R200 cubic texture offset\n" ); + return DRM_ERR( EINVAL ); + } + } + } + + return 0; +} + +static __inline__ int radeon_check_and_fixup_packet3( drm_radeon_private_t *dev_priv, + drm_file_t *filp_priv, + drm_radeon_cmd_buffer_t *cmdbuf, + unsigned int *cmdsz ) { + u32 tmp[4], *cmd = ( u32* )cmdbuf->buf; + + if ( DRM_COPY_FROM_USER_UNCHECKED( tmp, cmd, sizeof( tmp ) ) ) { + DRM_ERROR( "Failed to copy data from user space\n" ); + return DRM_ERR( EFAULT ); + } + + *cmdsz = 2 + ( ( tmp[0] & RADEON_CP_PACKET_COUNT_MASK ) >> 16 ); + + if ( ( tmp[0] & 0xc0000000 ) != RADEON_CP_PACKET3 ) { + DRM_ERROR( "Not a type 3 packet\n" ); + return DRM_ERR( EINVAL ); + } + + if ( 4 * *cmdsz > cmdbuf->bufsz ) { + DRM_ERROR( "Packet size larger than size of data provided\n" ); + return DRM_ERR( EINVAL ); + } + + /* Check client state and fix it up if necessary */ + if ( tmp[0] & 0x8000 ) { /* MSB of opcode: next DWORD GUI_CNTL */ + u32 offset; + + if ( tmp[1] & ( RADEON_GMC_SRC_PITCH_OFFSET_CNTL + | RADEON_GMC_DST_PITCH_OFFSET_CNTL ) ) { + offset = tmp[2] << 10; + if ( radeon_check_and_fixup_offset( dev_priv, filp_priv, &offset ) ) { + DRM_ERROR( "Invalid first packet offset\n" ); + return DRM_ERR( EINVAL ); + } + tmp[2] = ( tmp[2] & 0xffc00000 ) | offset >> 10; + } + + if ( ( tmp[1] & RADEON_GMC_SRC_PITCH_OFFSET_CNTL ) && + ( tmp[1] & RADEON_GMC_DST_PITCH_OFFSET_CNTL ) ) { + offset = tmp[3] << 10; + if ( radeon_check_and_fixup_offset( dev_priv, filp_priv, &offset ) ) { + DRM_ERROR( "Invalid second packet offset\n" ); + return DRM_ERR( EINVAL ); + } + tmp[3] = ( tmp[3] & 0xffc00000 ) | offset >> 10; + } + + if ( DRM_COPY_TO_USER_UNCHECKED( cmd, tmp, sizeof( tmp ) ) ) { + DRM_ERROR( "Failed to copy data to user space\n" ); + return DRM_ERR( EFAULT ); + } + } + + return 0; +} + + +/* ================================================================ * CP hardware state programming functions */ @@ -59,15 +204,28 @@ static __inline__ void radeon_emit_clip_rect( drm_radeon_private_t *dev_priv, /* Emit 1.1 state */ -static void radeon_emit_state( drm_radeon_private_t *dev_priv, - drm_radeon_context_regs_t *ctx, - drm_radeon_texture_regs_t *tex, - unsigned int dirty ) +static int radeon_emit_state( drm_radeon_private_t *dev_priv, + drm_file_t *filp_priv, + drm_radeon_context_regs_t *ctx, + drm_radeon_texture_regs_t *tex, + unsigned int dirty ) { RING_LOCALS; DRM_DEBUG( "dirty=0x%08x\n", dirty ); if ( dirty & RADEON_UPLOAD_CONTEXT ) { + if ( radeon_check_and_fixup_offset( dev_priv, filp_priv, + &ctx->rb3d_depthoffset ) ) { + DRM_ERROR( "Invalid depth buffer offset\n" ); + return DRM_ERR( EINVAL ); + } + + if ( radeon_check_and_fixup_offset( dev_priv, filp_priv, + &ctx->rb3d_coloroffset ) ) { + DRM_ERROR( "Invalid depth buffer offset\n" ); + return DRM_ERR( EINVAL ); + } + BEGIN_RING( 14 ); OUT_RING( CP_PACKET0( RADEON_PP_MISC, 6 ) ); OUT_RING( ctx->pp_misc ); @@ -151,6 +309,12 @@ static void radeon_emit_state( drm_radeon_private_t *dev_priv, } if ( dirty & RADEON_UPLOAD_TEX0 ) { + if ( radeon_check_and_fixup_offset( dev_priv, filp_priv, + &tex[0].pp_txoffset ) ) { + DRM_ERROR( "Invalid texture offset for unit 0\n" ); + return DRM_ERR( EINVAL ); + } + BEGIN_RING( 9 ); OUT_RING( CP_PACKET0( RADEON_PP_TXFILTER_0, 5 ) ); OUT_RING( tex[0].pp_txfilter ); @@ -165,6 +329,12 @@ static void radeon_emit_state( drm_radeon_private_t *dev_priv, } if ( dirty & RADEON_UPLOAD_TEX1 ) { + if ( radeon_check_and_fixup_offset( dev_priv, filp_priv, + &tex[1].pp_txoffset ) ) { + DRM_ERROR( "Invalid texture offset for unit 1\n" ); + return DRM_ERR( EINVAL ); + } + BEGIN_RING( 9 ); OUT_RING( CP_PACKET0( RADEON_PP_TXFILTER_1, 5 ) ); OUT_RING( tex[1].pp_txfilter ); @@ -179,6 +349,12 @@ static void radeon_emit_state( drm_radeon_private_t *dev_priv, } if ( dirty & RADEON_UPLOAD_TEX2 ) { + if ( radeon_check_and_fixup_offset( dev_priv, filp_priv, + &tex[2].pp_txoffset ) ) { + DRM_ERROR( "Invalid texture offset for unit 2\n" ); + return DRM_ERR( EINVAL ); + } + BEGIN_RING( 9 ); OUT_RING( CP_PACKET0( RADEON_PP_TXFILTER_2, 5 ) ); OUT_RING( tex[2].pp_txfilter ); @@ -191,12 +367,15 @@ static void radeon_emit_state( drm_radeon_private_t *dev_priv, OUT_RING( tex[2].pp_border_color ); ADVANCE_RING(); } + + return 0; } /* Emit 1.2 state */ -static void radeon_emit_state2( drm_radeon_private_t *dev_priv, - drm_radeon_state_t *state ) +static int radeon_emit_state2( drm_radeon_private_t *dev_priv, + drm_file_t *filp_priv, + drm_radeon_state_t *state ) { RING_LOCALS; @@ -208,7 +387,7 @@ static void radeon_emit_state2( drm_radeon_private_t *dev_priv, ADVANCE_RING(); } - radeon_emit_state( dev_priv, &state->context, + return radeon_emit_state( dev_priv, filp_priv, &state->context, state->tex, state->dirty ); } @@ -1067,6 +1246,7 @@ static int radeon_cp_dispatch_texture( DRMFILE filp, drm_radeon_tex_image_t *image ) { drm_radeon_private_t *dev_priv = dev->dev_private; + drm_file_t *filp_priv; drm_buf_t *buf; u32 format; u32 *buffer; @@ -1076,6 +1256,13 @@ static int radeon_cp_dispatch_texture( DRMFILE filp, int i; RING_LOCALS; + DRM_GET_PRIV_WITH_RETURN( filp_priv, filp ); + + if ( radeon_check_and_fixup_offset( dev_priv, filp_priv, &tex->offset ) ) { + DRM_ERROR( "Invalid destination offset\n" ); + return DRM_ERR( EINVAL ); + } + dev_priv->stats.boxes |= RADEON_BOX_TEXTURE_LOAD; /* Flush the pixel cache. This ensures no pixel data gets mixed @@ -1379,6 +1566,7 @@ int radeon_cp_vertex( DRM_IOCTL_ARGS ) { DRM_DEVICE; drm_radeon_private_t *dev_priv = dev->dev_private; + drm_file_t *filp_priv; drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; drm_device_dma_t *dma = dev->dma; drm_buf_t *buf; @@ -1392,6 +1580,8 @@ int radeon_cp_vertex( DRM_IOCTL_ARGS ) return DRM_ERR(EINVAL); } + DRM_GET_PRIV_WITH_RETURN( filp_priv, filp ); + DRM_COPY_FROM_USER_IOCTL( vertex, (drm_radeon_vertex_t *)data, sizeof(vertex) ); @@ -1431,11 +1621,14 @@ int radeon_cp_vertex( DRM_IOCTL_ARGS ) buf->used = vertex.count; /* not used? */ if ( sarea_priv->dirty & ~RADEON_UPLOAD_CLIPRECTS ) { - radeon_emit_state( dev_priv, - &sarea_priv->context_state, - sarea_priv->tex_state, - sarea_priv->dirty ); - + if ( radeon_emit_state( dev_priv, filp_priv, + &sarea_priv->context_state, + sarea_priv->tex_state, + sarea_priv->dirty ) ) { + DRM_ERROR( "radeon_emit_state failed\n" ); + return DRM_ERR( EINVAL ); + } + sarea_priv->dirty &= ~(RADEON_UPLOAD_TEX0IMAGES | RADEON_UPLOAD_TEX1IMAGES | RADEON_UPLOAD_TEX2IMAGES | @@ -1463,6 +1656,7 @@ int radeon_cp_indices( DRM_IOCTL_ARGS ) { DRM_DEVICE; drm_radeon_private_t *dev_priv = dev->dev_private; + drm_file_t *filp_priv; drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; drm_device_dma_t *dma = dev->dma; drm_buf_t *buf; @@ -1477,6 +1671,8 @@ int radeon_cp_indices( DRM_IOCTL_ARGS ) return DRM_ERR(EINVAL); } + DRM_GET_PRIV_WITH_RETURN( filp_priv, filp ); + DRM_COPY_FROM_USER_IOCTL( elts, (drm_radeon_indices_t *)data, sizeof(elts) ); @@ -1525,10 +1721,13 @@ int radeon_cp_indices( DRM_IOCTL_ARGS ) buf->used = elts.end; if ( sarea_priv->dirty & ~RADEON_UPLOAD_CLIPRECTS ) { - radeon_emit_state( dev_priv, - &sarea_priv->context_state, - sarea_priv->tex_state, - sarea_priv->dirty ); + if ( radeon_emit_state( dev_priv, filp_priv, + &sarea_priv->context_state, + sarea_priv->tex_state, + sarea_priv->dirty ) ) { + DRM_ERROR( "radeon_emit_state failed\n" ); + return DRM_ERR( EINVAL ); + } sarea_priv->dirty &= ~(RADEON_UPLOAD_TEX0IMAGES | RADEON_UPLOAD_TEX1IMAGES | @@ -1688,6 +1887,7 @@ int radeon_cp_vertex2( DRM_IOCTL_ARGS ) { DRM_DEVICE; drm_radeon_private_t *dev_priv = dev->dev_private; + drm_file_t *filp_priv; drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; drm_device_dma_t *dma = dev->dma; drm_buf_t *buf; @@ -1702,6 +1902,8 @@ int radeon_cp_vertex2( DRM_IOCTL_ARGS ) return DRM_ERR(EINVAL); } + DRM_GET_PRIV_WITH_RETURN( filp_priv, filp ); + DRM_COPY_FROM_USER_IOCTL( vertex, (drm_radeon_vertex2_t *)data, sizeof(vertex) ); @@ -1749,7 +1951,10 @@ int radeon_cp_vertex2( DRM_IOCTL_ARGS ) sizeof(state) ) ) return DRM_ERR(EFAULT); - radeon_emit_state2( dev_priv, &state ); + if ( radeon_emit_state2( dev_priv, filp_priv, &state ) ) { + DRM_ERROR( "radeon_emit_state2 failed\n" ); + return DRM_ERR( EINVAL ); + } laststate = prim.stateidx; } @@ -1786,6 +1991,7 @@ int radeon_cp_vertex2( DRM_IOCTL_ARGS ) static int radeon_emit_packets( drm_radeon_private_t *dev_priv, + drm_file_t *filp_priv, drm_radeon_cmd_header_t header, drm_radeon_cmd_buffer_t *cmdbuf ) { @@ -1800,8 +2006,15 @@ static int radeon_emit_packets( sz = packet[id].len; reg = packet[id].start; - if (sz * sizeof(int) > cmdbuf->bufsz) + if (sz * sizeof(int) > cmdbuf->bufsz) { + DRM_ERROR( "Packet size provided larger than data provided\n" ); return DRM_ERR(EINVAL); + } + + if ( radeon_check_and_fixup_packets( dev_priv, filp_priv, id, data ) ) { + DRM_ERROR( "Packet verification failed\n" ); + return DRM_ERR( EINVAL ); + } BEGIN_RING(sz+1); OUT_RING( CP_PACKET0( reg, (sz-1) ) ); @@ -1884,24 +2097,21 @@ static __inline__ int radeon_emit_vectors( static int radeon_emit_packet3( drm_device_t *dev, + drm_file_t *filp_priv, drm_radeon_cmd_buffer_t *cmdbuf ) { drm_radeon_private_t *dev_priv = dev->dev_private; - int cmdsz, tmp; - int *cmd = (int *)cmdbuf->buf; + unsigned int cmdsz; + int *cmd = (int *)cmdbuf->buf, ret; RING_LOCALS; - DRM_DEBUG("\n"); - if (DRM_GET_USER_UNCHECKED( tmp, &cmd[0])) - return DRM_ERR(EFAULT); - - cmdsz = 2 + ((tmp & RADEON_CP_PACKET_COUNT_MASK) >> 16); - - if ((tmp & 0xc0000000) != RADEON_CP_PACKET3 || - cmdsz * 4 > cmdbuf->bufsz) - return DRM_ERR(EINVAL); + if ( ( ret = radeon_check_and_fixup_packet3( dev_priv, filp_priv, + cmdbuf, &cmdsz ) ) ) { + DRM_ERROR( "Packet verification failed\n" ); + return ret; + } BEGIN_RING( cmdsz ); OUT_RING_USER_TABLE( cmd, cmdsz ); @@ -1914,27 +2124,25 @@ static int radeon_emit_packet3( drm_device_t *dev, static int radeon_emit_packet3_cliprect( drm_device_t *dev, + drm_file_t *filp_priv, drm_radeon_cmd_buffer_t *cmdbuf, int orig_nbox ) { drm_radeon_private_t *dev_priv = dev->dev_private; drm_clip_rect_t box; - int cmdsz, tmp; - int *cmd = (int *)cmdbuf->buf; + unsigned int cmdsz; + int *cmd = (int *)cmdbuf->buf, ret; drm_clip_rect_t *boxes = cmdbuf->boxes; int i = 0; RING_LOCALS; DRM_DEBUG("\n"); - if (DRM_GET_USER_UNCHECKED( tmp, &cmd[0])) - return DRM_ERR(EFAULT); - - cmdsz = 2 + ((tmp & RADEON_CP_PACKET_COUNT_MASK) >> 16); - - if ((tmp & 0xc0000000) != RADEON_CP_PACKET3 || - cmdsz * 4 > cmdbuf->bufsz) - return DRM_ERR(EINVAL); + if ( ( ret = radeon_check_and_fixup_packet3( dev_priv, filp_priv, + cmdbuf, &cmdsz ) ) ) { + DRM_ERROR( "Packet verification failed\n" ); + return ret; + } if (!orig_nbox) goto out; @@ -2011,6 +2219,7 @@ int radeon_cp_cmdbuf( DRM_IOCTL_ARGS ) { DRM_DEVICE; drm_radeon_private_t *dev_priv = dev->dev_private; + drm_file_t *filp_priv; drm_device_dma_t *dma = dev->dma; drm_buf_t *buf = 0; int idx; @@ -2025,6 +2234,8 @@ int radeon_cp_cmdbuf( DRM_IOCTL_ARGS ) return DRM_ERR(EINVAL); } + DRM_GET_PRIV_WITH_RETURN( filp_priv, filp ); + DRM_COPY_FROM_USER_IOCTL( cmdbuf, (drm_radeon_cmd_buffer_t *)data, sizeof(cmdbuf) ); @@ -2055,7 +2266,7 @@ int radeon_cp_cmdbuf( DRM_IOCTL_ARGS ) switch (header.header.cmd_type) { case RADEON_CMD_PACKET: DRM_DEBUG("RADEON_CMD_PACKET\n"); - if (radeon_emit_packets( dev_priv, header, &cmdbuf )) { + if (radeon_emit_packets( dev_priv, filp_priv, header, &cmdbuf )) { DRM_ERROR("radeon_emit_packets failed\n"); return DRM_ERR(EINVAL); } @@ -2098,7 +2309,7 @@ int radeon_cp_cmdbuf( DRM_IOCTL_ARGS ) case RADEON_CMD_PACKET3: DRM_DEBUG("RADEON_CMD_PACKET3\n"); - if (radeon_emit_packet3( dev, &cmdbuf )) { + if (radeon_emit_packet3( dev, filp_priv, &cmdbuf )) { DRM_ERROR("radeon_emit_packet3 failed\n"); return DRM_ERR(EINVAL); } @@ -2106,7 +2317,7 @@ int radeon_cp_cmdbuf( DRM_IOCTL_ARGS ) case RADEON_CMD_PACKET3_CLIP: DRM_DEBUG("RADEON_CMD_PACKET3_CLIP\n"); - if (radeon_emit_packet3_cliprect( dev, &cmdbuf, orig_nbox )) { + if (radeon_emit_packet3_cliprect( dev, filp_priv, &cmdbuf, orig_nbox )) { DRM_ERROR("radeon_emit_packet3_clip failed\n"); return DRM_ERR(EINVAL); } @@ -2205,3 +2416,31 @@ int radeon_cp_getparam( DRM_IOCTL_ARGS ) return 0; } + +int radeon_cp_setparam( DRM_IOCTL_ARGS ) { + DRM_DEVICE; + drm_radeon_private_t *dev_priv = dev->dev_private; + drm_file_t *filp_priv; + drm_radeon_setparam_t sp; + + if ( !dev_priv ) { + DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ ); + return DRM_ERR( EINVAL ); + } + + DRM_GET_PRIV_WITH_RETURN( filp_priv, filp ); + + DRM_COPY_FROM_USER_IOCTL( sp, ( drm_radeon_setparam_t* )data, + sizeof( sp ) ); + + switch( sp.param ) { + case RADEON_SETPARAM_FB_LOCATION: + filp_priv->radeon_fb_delta = dev_priv->fb_location - sp.value; + break; + default: + DRM_DEBUG( "Invalid parameter %d\n", sp.param ); + return DRM_ERR( EINVAL ); + } + + return 0; +} |