diff options
author | Jean-Sébastien Pédron <dumbbell@FreeBSD.org> | 2015-03-17 18:50:33 +0000 |
---|---|---|
committer | Jean-Sébastien Pédron <dumbbell@FreeBSD.org> | 2015-03-17 18:50:33 +0000 |
commit | 455fa6518ac6e2c25197085a8b900451487642b4 (patch) | |
tree | 4cd126feba58bdd5146facab6c5499f8a7f11467 | |
parent | 758cc3dcd5575a076c2b23025c977ecbe2882ef1 (diff) | |
download | src-455fa6518ac6e2c25197085a8b900451487642b4.tar.gz src-455fa6518ac6e2c25197085a8b900451487642b4.zip |
Notes
158 files changed, 10644 insertions, 8496 deletions
diff --git a/sys/dev/drm2/ati_pcigart.c b/sys/dev/drm2/ati_pcigart.c index 5d3033fc37ce..57fda4d777b4 100644 --- a/sys/dev/drm2/ati_pcigart.c +++ b/sys/dev/drm2/ati_pcigart.c @@ -42,7 +42,7 @@ static int drm_ati_alloc_pcigart_table(struct drm_device *dev, struct drm_ati_pcigart_info *gart_info) { gart_info->table_handle = drm_pci_alloc(dev, gart_info->table_size, - PAGE_SIZE, 0xFFFFFFFFUL); + PAGE_SIZE, BUS_SPACE_MAXADDR); if (gart_info->table_handle == NULL) return -ENOMEM; @@ -97,6 +97,7 @@ int drm_ati_pcigart_cleanup(struct drm_device *dev, struct drm_ati_pcigart_info return 1; } +EXPORT_SYMBOL(drm_ati_pcigart_cleanup); int drm_ati_pcigart_init(struct drm_device *dev, struct drm_ati_pcigart_info *gart_info) { @@ -197,7 +198,7 @@ int drm_ati_pcigart_init(struct drm_device *dev, struct drm_ati_pcigart_info *ga } ret = 1; -#if defined(__i386) || defined(__amd64) +#if defined(__i386__) || defined(__x86_64__) wbinvd(); #else mb(); @@ -208,3 +209,4 @@ int drm_ati_pcigart_init(struct drm_device *dev, struct drm_ati_pcigart_info *ga gart_info->bus_addr = bus_address; return ret; } +EXPORT_SYMBOL(drm_ati_pcigart_init); diff --git a/sys/dev/drm2/drm.h b/sys/dev/drm2/drm.h index eca588531be2..7c40ac07e291 100644 --- a/sys/dev/drm2/drm.h +++ b/sys/dev/drm2/drm.h @@ -36,69 +36,31 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); -/** - * \mainpage - * - * The Direct Rendering Manager (DRM) is a device-independent kernel-level - * device driver that provides support for the XFree86 Direct Rendering - * Infrastructure (DRI). - * - * The DRM supports the Direct Rendering Infrastructure (DRI) in four major - * ways: - * -# The DRM provides synchronized access to the graphics hardware via - * the use of an optimized two-tiered lock. - * -# The DRM enforces the DRI security policy for access to the graphics - * hardware by only allowing authenticated X11 clients access to - * restricted regions of memory. - * -# The DRM provides a generic DMA engine, complete with multiple - * queues and the ability to detect the need for an OpenGL context - * switch. - * -# The DRM is extensible via the use of small device-specific modules - * that rely extensively on the API exported by the DRM module. - * - */ - #ifndef _DRM_H_ #define _DRM_H_ -#ifndef __user -#define __user -#endif -#ifndef __iomem -#define __iomem -#endif +#if defined(__linux__) -#ifdef __GNUC__ -# define DEPRECATED __attribute__ ((deprecated)) -#else -# define DEPRECATED -#endif +#include <linux/types.h> +#include <asm/ioctl.h> +typedef unsigned int drm_handle_t; -#if defined(__linux__) -#include <asm/ioctl.h> /* For _IO* macros */ -#define DRM_IOCTL_NR(n) _IOC_NR(n) -#define DRM_IOC_VOID _IOC_NONE -#define DRM_IOC_READ _IOC_READ -#define DRM_IOC_WRITE _IOC_WRITE -#define DRM_IOC_READWRITE _IOC_READ|_IOC_WRITE -#define DRM_IOC(dir, group, nr, size) _IOC(dir, group, nr, size) -#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) -#include <sys/ioccom.h> -#define DRM_IOCTL_NR(n) ((n) & 0xff) -#define DRM_IOC_VOID IOC_VOID -#define DRM_IOC_READ IOC_OUT -#define DRM_IOC_WRITE IOC_IN -#define DRM_IOC_READWRITE IOC_INOUT -#define DRM_IOC(dir, group, nr, size) _IOC(dir, group, nr, size) -#endif +#else /* One of the BSDs */ -#ifdef __OpenBSD__ -#define DRM_MAJOR 81 -#endif -#if defined(__linux__) || defined(__NetBSD__) -#define DRM_MAJOR 226 +#include <sys/ioccom.h> +#include <sys/types.h> +typedef int8_t __s8; +typedef uint8_t __u8; +typedef int16_t __s16; +typedef uint16_t __u16; +typedef int32_t __s32; +typedef uint32_t __u32; +typedef int64_t __s64; +typedef uint64_t __u64; +typedef unsigned long drm_handle_t; + +#include <dev/drm2/drm_os_freebsd.h> #endif -#define DRM_MAX_MINOR 15 #define DRM_NAME "drm" /**< Name in kernel, /dev, and /proc */ #define DRM_MIN_ORDER 5 /**< At least 2^5 bytes = 32 bytes */ @@ -111,20 +73,14 @@ __FBSDID("$FreeBSD$"); #define _DRM_LOCK_IS_CONT(lock) ((lock) & _DRM_LOCK_CONT) #define _DRM_LOCKING_CONTEXT(lock) ((lock) & ~(_DRM_LOCK_HELD|_DRM_LOCK_CONT)) -#if defined(__linux__) -typedef unsigned int drm_handle_t; -#else -#include <sys/types.h> -typedef unsigned long drm_handle_t; /**< To mapped regions */ -#endif -typedef unsigned int drm_context_t; /**< GLXContext handle */ +typedef unsigned int drm_context_t; typedef unsigned int drm_drawable_t; -typedef unsigned int drm_magic_t; /**< Magic for authentication */ +typedef unsigned int drm_magic_t; /** * Cliprect. * - * \warning If you change this structure, make sure you change + * \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 @@ -138,6 +94,14 @@ struct drm_clip_rect { }; /** + * Drawable information. + */ +struct drm_drawable_info { + unsigned int num_rects; + struct drm_clip_rect *rects; +}; + +/** * Texture region, */ struct drm_tex_region { @@ -160,22 +124,6 @@ struct drm_hw_lock { char padding[60]; /**< Pad to cache line */ }; -/* This is beyond ugly, and only works on GCC. However, it allows me to use - * drm.h in places (i.e., in the X-server) where I can't use size_t. The real - * fix is to use uint32_t instead of size_t, but that fix will break existing - * LP64 (i.e., PowerPC64, SPARC64, Alpha, etc.) systems. That *will* - * eventually happen, though. I chose 'unsigned long' to be the fallback type - * because that works on all the platforms I know about. Hopefully, the - * real fix will happen before that bites us. - */ - -#ifdef __SIZE_TYPE__ -# define DRM_SIZE_T __SIZE_TYPE__ -#else -# warning "__SIZE_TYPE__ not defined. Assuming sizeof(size_t) == sizeof(unsigned long)!" -# define DRM_SIZE_T unsigned long -#endif - /** * DRM_IOCTL_VERSION ioctl argument type. * @@ -185,12 +133,12 @@ struct drm_version { int version_major; /**< Major version */ int version_minor; /**< Minor version */ int version_patchlevel; /**< Patch level */ - DRM_SIZE_T name_len; /**< Length of name buffer */ - char __user *name; /**< Name of driver */ - DRM_SIZE_T date_len; /**< Length of date buffer */ - char __user *date; /**< User-space buffer to hold date */ - DRM_SIZE_T desc_len; /**< Length of desc buffer */ - char __user *desc; /**< User-space buffer to hold desc */ + size_t name_len; /**< Length of name buffer */ + char __user *name; /**< Name of driver */ + size_t date_len; /**< Length of date buffer */ + char __user *date; /**< User-space buffer to hold date */ + size_t desc_len; /**< Length of desc buffer */ + char __user *desc; /**< User-space buffer to hold desc */ }; /** @@ -199,12 +147,10 @@ struct drm_version { * \sa drmGetBusid() and drmSetBusId(). */ struct drm_unique { - DRM_SIZE_T unique_len; /**< Length of unique */ - char __user *unique; /**< Unique name for driver instantiation */ + size_t unique_len; /**< Length of unique */ + char __user *unique; /**< Unique name for driver instantiation */ }; -#undef DRM_SIZE_T - struct drm_list { int count; /**< Length of user-space structures */ struct drm_version __user *version; @@ -239,7 +185,7 @@ enum drm_map_type { _DRM_AGP = 3, /**< AGP/GART */ _DRM_SCATTER_GATHER = 4, /**< Scatter/gather memory for PCI DMA */ _DRM_CONSISTENT = 5, /**< Consistent memory for PCI DMA */ - _DRM_GEM = 6 /**< GEM */ + _DRM_GEM = 6, /**< GEM object */ }; /** @@ -388,8 +334,8 @@ struct drm_buf_desc { 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_FB_BUFFER = 0x08, /**< Buffer is in frame buffer */ + _DRM_SG_BUFFER = 0x04, /**< Scatter/gather memory buffer */ + _DRM_FB_BUFFER = 0x08, /**< Buffer is in frame buffer */ _DRM_PCI_BUFFER_RO = 0x10 /**< Map PCI DMA buffer read-only */ } flags; unsigned long agp_start; /**< @@ -402,8 +348,8 @@ struct drm_buf_desc { * DRM_IOCTL_INFO_BUFS ioctl argument type. */ struct drm_buf_info { - int count; /**< Number of buffers described in list */ - struct drm_buf_desc __user *list; /**< List of buffer descriptions */ + int count; /**< Entries in list */ + struct drm_buf_desc __user *list; }; /** @@ -431,11 +377,7 @@ struct drm_buf_pub { */ struct drm_buf_map { int count; /**< Length of the buffer list */ -#if defined(__cplusplus) - void __user *c_virtual; -#else void __user *virtual; /**< Mmap'd area in user-virtual */ -#endif struct drm_buf_pub __user *list; /**< Buffer information */ }; @@ -454,7 +396,7 @@ struct drm_dma { enum drm_dma_flags flags; /**< Flags */ int request_count; /**< Number of buffers requested */ int request_size; /**< Desired size for buffers */ - int __user *request_indices; /**< Buffer information */ + int __user *request_indices; /**< Buffer information */ int __user *request_sizes; int granted_count; /**< Number of buffers granted */ }; @@ -525,12 +467,13 @@ struct drm_irq_busid { enum drm_vblank_seq_type { _DRM_VBLANK_ABSOLUTE = 0x0, /**< Wait for specific vblank sequence number */ _DRM_VBLANK_RELATIVE = 0x1, /**< Wait for given number of vblanks */ + /* bits 1-6 are reserved for high crtcs */ _DRM_VBLANK_HIGH_CRTC_MASK = 0x0000003e, _DRM_VBLANK_EVENT = 0x4000000, /**< Send event instead of blocking */ - _DRM_VBLANK_FLIP = 0x8000000, /**< Scheduled buffer swap should flip */ + _DRM_VBLANK_FLIP = 0x8000000, /**< Scheduled buffer swap should flip */ _DRM_VBLANK_NEXTONMISS = 0x10000000, /**< If missed, wait for next vblank */ _DRM_VBLANK_SECONDARY = 0x20000000, /**< Secondary display controller */ - _DRM_VBLANK_SIGNAL = 0x40000000 /**< Send signal instead of blocking */ + _DRM_VBLANK_SIGNAL = 0x40000000 /**< Send signal instead of blocking, unsupported */ }; #define _DRM_VBLANK_HIGH_CRTC_SHIFT 1 @@ -561,7 +504,6 @@ union drm_wait_vblank { struct drm_wait_vblank_reply reply; }; - #define _DRM_PRE_MODESET 1 #define _DRM_POST_MODESET 2 @@ -571,8 +513,8 @@ union drm_wait_vblank { * \sa drmModesetCtl(). */ struct drm_modeset_ctl { - uint32_t crtc; - uint32_t cmd; + __u32 crtc; + __u32 cmd; }; /** @@ -617,16 +559,14 @@ struct drm_agp_info { int agp_version_major; int agp_version_minor; unsigned long mode; - unsigned long aperture_base; /**< physical address */ - unsigned long aperture_size; /**< bytes */ - unsigned long memory_allowed; /**< bytes */ + unsigned long aperture_base; /* physical address */ + unsigned long aperture_size; /* bytes */ + unsigned long memory_allowed; /* bytes */ unsigned long memory_used; - /** \name PCI information */ - /*@{ */ + /* PCI information */ unsigned short id_vendor; unsigned short id_device; - /*@} */ }; /** @@ -647,386 +587,52 @@ struct drm_set_version { int drm_dd_minor; }; -#define DRM_FENCE_FLAG_EMIT 0x00000001 -#define DRM_FENCE_FLAG_SHAREABLE 0x00000002 -/** - * On hardware with no interrupt events for operation completion, - * indicates that the kernel should sleep while waiting for any blocking - * operation to complete rather than spinning. - * - * Has no effect otherwise. - */ -#define DRM_FENCE_FLAG_WAIT_LAZY 0x00000004 -#define DRM_FENCE_FLAG_NO_USER 0x00000010 - -/* Reserved for driver use */ -#define DRM_FENCE_MASK_DRIVER 0xFF000000 - -#define DRM_FENCE_TYPE_EXE 0x00000001 - -struct drm_fence_arg { - unsigned int handle; - unsigned int fence_class; - unsigned int type; - unsigned int flags; - unsigned int signaled; - unsigned int error; - unsigned int sequence; - unsigned int pad64; - uint64_t expand_pad[2]; /* Future expansion */ -}; - -/* Buffer permissions, referring to how the GPU uses the buffers. - * these translate to fence types used for the buffers. - * Typically a texture buffer is read, A destination buffer is write and - * a command (batch-) buffer is exe. Can be or-ed together. - */ - -#define DRM_BO_FLAG_READ (1ULL << 0) -#define DRM_BO_FLAG_WRITE (1ULL << 1) -#define DRM_BO_FLAG_EXE (1ULL << 2) - -/* - * All of the bits related to access mode - */ -#define DRM_BO_MASK_ACCESS (DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE | DRM_BO_FLAG_EXE) -/* - * Status flags. Can be read to determine the actual state of a buffer. - * Can also be set in the buffer mask before validation. - */ - -/* - * Mask: Never evict this buffer. Not even with force. This type of buffer is only - * available to root and must be manually removed before buffer manager shutdown - * or lock. - * Flags: Acknowledge - */ -#define DRM_BO_FLAG_NO_EVICT (1ULL << 4) - -/* - * Mask: Require that the buffer is placed in mappable memory when validated. - * If not set the buffer may or may not be in mappable memory when validated. - * Flags: If set, the buffer is in mappable memory. - */ -#define DRM_BO_FLAG_MAPPABLE (1ULL << 5) - -/* Mask: The buffer should be shareable with other processes. - * Flags: The buffer is shareable with other processes. - */ -#define DRM_BO_FLAG_SHAREABLE (1ULL << 6) - -/* Mask: If set, place the buffer in cache-coherent memory if available. - * If clear, never place the buffer in cache coherent memory if validated. - * Flags: The buffer is currently in cache-coherent memory. - */ -#define DRM_BO_FLAG_CACHED (1ULL << 7) - -/* Mask: Make sure that every time this buffer is validated, - * it ends up on the same location provided that the memory mask is the same. - * The buffer will also not be evicted when claiming space for - * other buffers. Basically a pinned buffer but it may be thrown out as - * part of buffer manager shutdown or locking. - * Flags: Acknowledge. - */ -#define DRM_BO_FLAG_NO_MOVE (1ULL << 8) - -/* Mask: Make sure the buffer is in cached memory when mapped. In conjunction - * with DRM_BO_FLAG_CACHED it also allows the buffer to be bound into the GART - * with unsnooped PTEs instead of snooped, by using chipset-specific cache - * flushing at bind time. A better name might be DRM_BO_FLAG_TT_UNSNOOPED, - * as the eviction to local memory (TTM unbind) on map is just a side effect - * to prevent aggressive cache prefetch from the GPU disturbing the cache - * management that the DRM is doing. - * - * Flags: Acknowledge. - * Buffers allocated with this flag should not be used for suballocators - * This type may have issues on CPUs with over-aggressive caching - * http://marc.info/?l=linux-kernel&m=102376926732464&w=2 - */ -#define DRM_BO_FLAG_CACHED_MAPPED (1ULL << 19) - - -/* Mask: Force DRM_BO_FLAG_CACHED flag strictly also if it is set. - * Flags: Acknowledge. - */ -#define DRM_BO_FLAG_FORCE_CACHING (1ULL << 13) - -/* - * Mask: Force DRM_BO_FLAG_MAPPABLE flag strictly also if it is clear. - * Flags: Acknowledge. - */ -#define DRM_BO_FLAG_FORCE_MAPPABLE (1ULL << 14) -#define DRM_BO_FLAG_TILE (1ULL << 15) - -/* - * Memory type flags that can be or'ed together in the mask, but only - * one appears in flags. - */ - -/* System memory */ -#define DRM_BO_FLAG_MEM_LOCAL (1ULL << 24) -/* Translation table memory */ -#define DRM_BO_FLAG_MEM_TT (1ULL << 25) -/* Vram memory */ -#define DRM_BO_FLAG_MEM_VRAM (1ULL << 26) -/* Up to the driver to define. */ -#define DRM_BO_FLAG_MEM_PRIV0 (1ULL << 27) -#define DRM_BO_FLAG_MEM_PRIV1 (1ULL << 28) -#define DRM_BO_FLAG_MEM_PRIV2 (1ULL << 29) -#define DRM_BO_FLAG_MEM_PRIV3 (1ULL << 30) -#define DRM_BO_FLAG_MEM_PRIV4 (1ULL << 31) -/* We can add more of these now with a 64-bit flag type */ - -/* - * This is a mask covering all of the memory type flags; easier to just - * use a single constant than a bunch of | values. It covers - * DRM_BO_FLAG_MEM_LOCAL through DRM_BO_FLAG_MEM_PRIV4 - */ -#define DRM_BO_MASK_MEM 0x00000000FF000000ULL -/* - * This adds all of the CPU-mapping options in with the memory - * type to label all bits which change how the page gets mapped - */ -#define DRM_BO_MASK_MEMTYPE (DRM_BO_MASK_MEM | \ - DRM_BO_FLAG_CACHED_MAPPED | \ - DRM_BO_FLAG_CACHED | \ - DRM_BO_FLAG_MAPPABLE) - -/* Driver-private flags */ -#define DRM_BO_MASK_DRIVER 0xFFFF000000000000ULL - -/* - * Don't block on validate and map. Instead, return EBUSY. - */ -#define DRM_BO_HINT_DONT_BLOCK 0x00000002 -/* - * Don't place this buffer on the unfenced list. This means - * that the buffer will not end up having a fence associated - * with it as a result of this operation - */ -#define DRM_BO_HINT_DONT_FENCE 0x00000004 -/** - * On hardware with no interrupt events for operation completion, - * indicates that the kernel should sleep while waiting for any blocking - * operation to complete rather than spinning. - * - * Has no effect otherwise. - */ -#define DRM_BO_HINT_WAIT_LAZY 0x00000008 -/* - * The client has compute relocations refering to this buffer using the - * offset in the presumed_offset field. If that offset ends up matching - * where this buffer lands, the kernel is free to skip executing those - * relocations - */ -#define DRM_BO_HINT_PRESUMED_OFFSET 0x00000010 - -#define DRM_BO_INIT_MAGIC 0xfe769812 -#define DRM_BO_INIT_MAJOR 1 -#define DRM_BO_INIT_MINOR 0 -#define DRM_BO_INIT_PATCH 0 - - -struct drm_bo_info_req { - uint64_t mask; - uint64_t flags; - unsigned int handle; - unsigned int hint; - unsigned int fence_class; - unsigned int desired_tile_stride; - unsigned int tile_info; - unsigned int pad64; - uint64_t presumed_offset; -}; - -struct drm_bo_create_req { - uint64_t flags; - uint64_t size; - uint64_t buffer_start; - unsigned int hint; - unsigned int page_alignment; -}; - - -/* - * Reply flags - */ - -#define DRM_BO_REP_BUSY 0x00000001 - -struct drm_bo_info_rep { - uint64_t flags; - uint64_t proposed_flags; - uint64_t size; - uint64_t offset; - uint64_t arg_handle; - uint64_t buffer_start; - unsigned int handle; - unsigned int fence_flags; - unsigned int rep_flags; - unsigned int page_alignment; - unsigned int desired_tile_stride; - unsigned int hw_tile_stride; - unsigned int tile_info; - unsigned int pad64; - uint64_t expand_pad[4]; /*Future expansion */ -}; - -struct drm_bo_arg_rep { - struct drm_bo_info_rep bo_info; - int ret; - unsigned int pad64; -}; - -struct drm_bo_create_arg { - union { - struct drm_bo_create_req req; - struct drm_bo_info_rep rep; - } d; -}; - -struct drm_bo_handle_arg { - unsigned int handle; -}; - -struct drm_bo_reference_info_arg { - union { - struct drm_bo_handle_arg req; - struct drm_bo_info_rep rep; - } d; -}; - -struct drm_bo_map_wait_idle_arg { - union { - struct drm_bo_info_req req; - struct drm_bo_info_rep rep; - } d; -}; - -struct drm_bo_op_req { - enum { - drm_bo_validate, - drm_bo_fence, - drm_bo_ref_fence, - } op; - unsigned int arg_handle; - struct drm_bo_info_req bo_req; -}; - - -struct drm_bo_op_arg { - uint64_t next; - union { - struct drm_bo_op_req req; - struct drm_bo_arg_rep rep; - } d; - int handled; - unsigned int pad64; -}; - - -#define DRM_BO_MEM_LOCAL 0 -#define DRM_BO_MEM_TT 1 -#define DRM_BO_MEM_VRAM 2 -#define DRM_BO_MEM_PRIV0 3 -#define DRM_BO_MEM_PRIV1 4 -#define DRM_BO_MEM_PRIV2 5 -#define DRM_BO_MEM_PRIV3 6 -#define DRM_BO_MEM_PRIV4 7 - -#define DRM_BO_MEM_TYPES 8 /* For now. */ - -#define DRM_BO_LOCK_UNLOCK_BM (1 << 0) -#define DRM_BO_LOCK_IGNORE_NO_EVICT (1 << 1) - -struct drm_bo_version_arg { - uint32_t major; - uint32_t minor; - uint32_t patchlevel; -}; - -struct drm_mm_type_arg { - unsigned int mem_type; - unsigned int lock_flags; -}; - -struct drm_mm_init_arg { - unsigned int magic; - unsigned int major; - unsigned int minor; - unsigned int mem_type; - uint64_t p_offset; - uint64_t p_size; -}; - -struct drm_mm_info_arg { - unsigned int mem_type; - uint64_t p_size; -}; - +/** DRM_IOCTL_GEM_CLOSE ioctl argument type */ struct drm_gem_close { /** Handle of the object to be closed. */ - uint32_t handle; - uint32_t pad; + __u32 handle; + __u32 pad; }; +/** DRM_IOCTL_GEM_FLINK ioctl argument type */ struct drm_gem_flink { /** Handle for the object being named */ - uint32_t handle; + __u32 handle; /** Returned global name */ - uint32_t name; + __u32 name; }; +/** DRM_IOCTL_GEM_OPEN ioctl argument type */ struct drm_gem_open { /** Name of object being opened */ - uint32_t name; + __u32 name; /** Returned handle for the object */ - uint32_t handle; - + __u32 handle; + /** Returned size of the object */ - uint64_t size; + __u64 size; }; +/** DRM_IOCTL_GET_CAP ioctl argument type */ struct drm_get_cap { - uint64_t capability; - uint64_t value; + __u64 capability; + __u64 value; }; -struct drm_event { - uint32_t type; - uint32_t length; -}; +#define DRM_CLOEXEC O_CLOEXEC +struct drm_prime_handle { + __u32 handle; -#define DRM_EVENT_VBLANK 0x01 -#define DRM_EVENT_FLIP_COMPLETE 0x02 + /** Flags.. only applicable for handle->fd */ + __u32 flags; -struct drm_event_vblank { - struct drm_event base; - uint64_t user_data; - uint32_t tv_sec; - uint32_t tv_usec; - uint32_t sequence; - uint32_t reserved; + /** Returned dmabuf file descriptor */ + __s32 fd; }; -#define DRM_CAP_DUMB_BUFFER 0x1 -#define DRM_CAP_VBLANK_HIGH_CRTC 0x2 -#define DRM_CAP_DUMB_PREFERRED_DEPTH 0x3 -#define DRM_CAP_DUMB_PREFER_SHADOW 0x4 -#define DRM_CAP_PRIME 0x5 -#define DRM_CAP_TIMESTAMP_MONOTONIC 0x6 - -#define DRM_PRIME_CAP_IMPORT 0x1 -#define DRM_PRIME_CAP_EXPORT 0x2 - -#include "drm_mode.h" - -/** - * \name Ioctls Definitions - */ -/*@{*/ +#include <dev/drm2/drm_mode.h> #define DRM_IOCTL_BASE 'd' #define DRM_IO(nr) _IO(DRM_IOCTL_BASE,nr) @@ -1042,12 +648,10 @@ struct drm_event_vblank { #define DRM_IOCTL_GET_CLIENT DRM_IOWR(0x05, struct drm_client) #define DRM_IOCTL_GET_STATS DRM_IOR( 0x06, struct drm_stats) #define DRM_IOCTL_SET_VERSION DRM_IOWR(0x07, struct drm_set_version) -#define DRM_IOCTL_MODESET_CTL DRM_IOW(0x08, struct drm_modeset_ctl) - +#define DRM_IOCTL_MODESET_CTL DRM_IOW(0x08, struct drm_modeset_ctl) #define DRM_IOCTL_GEM_CLOSE DRM_IOW (0x09, struct drm_gem_close) #define DRM_IOCTL_GEM_FLINK DRM_IOWR(0x0a, struct drm_gem_flink) #define DRM_IOCTL_GEM_OPEN DRM_IOWR(0x0b, struct drm_gem_open) - #define DRM_IOCTL_GET_CAP DRM_IOWR(0x0c, struct drm_get_cap) #define DRM_IOCTL_SET_UNIQUE DRM_IOW( 0x10, struct drm_unique) @@ -1065,7 +669,7 @@ struct drm_event_vblank { #define DRM_IOCTL_RM_MAP DRM_IOW( 0x1b, struct drm_map) #define DRM_IOCTL_SET_SAREA_CTX DRM_IOW( 0x1c, struct drm_ctx_priv_map) -#define DRM_IOCTL_GET_SAREA_CTX DRM_IOWR(0x1d, struct drm_ctx_priv_map) +#define DRM_IOCTL_GET_SAREA_CTX DRM_IOWR(0x1d, struct drm_ctx_priv_map) #define DRM_IOCTL_SET_MASTER DRM_IO(0x1e) #define DRM_IOCTL_DROP_MASTER DRM_IO(0x1f) @@ -1084,7 +688,8 @@ struct drm_event_vblank { #define DRM_IOCTL_UNLOCK DRM_IOW( 0x2b, struct drm_lock) #define DRM_IOCTL_FINISH DRM_IOW( 0x2c, struct drm_lock) -#define DRM_IOCTL_GEM_PRIME_OPEN DRM_IOWR(0x2e, struct drm_gem_open) +#define DRM_IOCTL_PRIME_HANDLE_TO_FD DRM_IOWR(0x2d, struct drm_prime_handle) +#define DRM_IOCTL_PRIME_FD_TO_HANDLE DRM_IOWR(0x2e, struct drm_prime_handle) #define DRM_IOCTL_AGP_ACQUIRE DRM_IO( 0x30) #define DRM_IOCTL_AGP_RELEASE DRM_IO( 0x31) @@ -1100,7 +705,7 @@ struct drm_event_vblank { #define DRM_IOCTL_WAIT_VBLANK DRM_IOWR(0x3a, union drm_wait_vblank) -#define DRM_IOCTL_UPDATE_DRAW DRM_IOW(0x3f, struct drm_update_draw) +#define DRM_IOCTL_UPDATE_DRAW DRM_IOW(0x3f, struct drm_update_draw) #define DRM_IOCTL_MODE_GETRESOURCES DRM_IOWR(0xA0, struct drm_mode_card_res) #define DRM_IOCTL_MODE_GETCRTC DRM_IOWR(0xA1, struct drm_mode_crtc) @@ -1122,43 +727,16 @@ struct drm_event_vblank { #define DRM_IOCTL_MODE_PAGE_FLIP DRM_IOWR(0xB0, struct drm_mode_crtc_page_flip) #define DRM_IOCTL_MODE_DIRTYFB DRM_IOWR(0xB1, struct drm_mode_fb_dirty_cmd) -#define DRM_IOCTL_MODE_CREATE_DUMB DRM_IOWR(0xB2, struct drm_mode_create_dumb) -#define DRM_IOCTL_MODE_MAP_DUMB DRM_IOWR(0xB3, struct drm_mode_map_dumb) -#define DRM_IOCTL_MODE_DESTROY_DUMB DRM_IOWR(0xB4, struct drm_mode_destroy_dumb) +#define DRM_IOCTL_MODE_CREATE_DUMB DRM_IOWR(0xB2, struct drm_mode_create_dumb) +#define DRM_IOCTL_MODE_MAP_DUMB DRM_IOWR(0xB3, struct drm_mode_map_dumb) +#define DRM_IOCTL_MODE_DESTROY_DUMB DRM_IOWR(0xB4, struct drm_mode_destroy_dumb) #define DRM_IOCTL_MODE_GETPLANERESOURCES DRM_IOWR(0xB5, struct drm_mode_get_plane_res) -#define DRM_IOCTL_MODE_GETPLANE DRM_IOWR(0xB6, struct drm_mode_get_plane) -#define DRM_IOCTL_MODE_SETPLANE DRM_IOWR(0xB7, struct drm_mode_set_plane) +#define DRM_IOCTL_MODE_GETPLANE DRM_IOWR(0xB6, struct drm_mode_get_plane) +#define DRM_IOCTL_MODE_SETPLANE DRM_IOWR(0xB7, struct drm_mode_set_plane) #define DRM_IOCTL_MODE_ADDFB2 DRM_IOWR(0xB8, struct drm_mode_fb_cmd2) #define DRM_IOCTL_MODE_OBJ_GETPROPERTIES DRM_IOWR(0xB9, struct drm_mode_obj_get_properties) #define DRM_IOCTL_MODE_OBJ_SETPROPERTY DRM_IOWR(0xBA, struct drm_mode_obj_set_property) -#define DRM_IOCTL_MM_INIT DRM_IOWR(0xc0, struct drm_mm_init_arg) -#define DRM_IOCTL_MM_TAKEDOWN DRM_IOWR(0xc1, struct drm_mm_type_arg) -#define DRM_IOCTL_MM_LOCK DRM_IOWR(0xc2, struct drm_mm_type_arg) -#define DRM_IOCTL_MM_UNLOCK DRM_IOWR(0xc3, struct drm_mm_type_arg) - -#define DRM_IOCTL_FENCE_CREATE DRM_IOWR(0xc4, struct drm_fence_arg) -#define DRM_IOCTL_FENCE_REFERENCE DRM_IOWR(0xc6, struct drm_fence_arg) -#define DRM_IOCTL_FENCE_UNREFERENCE DRM_IOWR(0xc7, struct drm_fence_arg) -#define DRM_IOCTL_FENCE_SIGNALED DRM_IOWR(0xc8, struct drm_fence_arg) -#define DRM_IOCTL_FENCE_FLUSH DRM_IOWR(0xc9, struct drm_fence_arg) -#define DRM_IOCTL_FENCE_WAIT DRM_IOWR(0xca, struct drm_fence_arg) -#define DRM_IOCTL_FENCE_EMIT DRM_IOWR(0xcb, struct drm_fence_arg) -#define DRM_IOCTL_FENCE_BUFFERS DRM_IOWR(0xcc, struct drm_fence_arg) - -#define DRM_IOCTL_BO_CREATE DRM_IOWR(0xcd, struct drm_bo_create_arg) -#define DRM_IOCTL_BO_MAP DRM_IOWR(0xcf, struct drm_bo_map_wait_idle_arg) -#define DRM_IOCTL_BO_UNMAP DRM_IOWR(0xd0, struct drm_bo_handle_arg) -#define DRM_IOCTL_BO_REFERENCE DRM_IOWR(0xd1, struct drm_bo_reference_info_arg) -#define DRM_IOCTL_BO_UNREFERENCE DRM_IOWR(0xd2, struct drm_bo_handle_arg) -#define DRM_IOCTL_BO_SETSTATUS DRM_IOWR(0xd3, struct drm_bo_map_wait_idle_arg) -#define DRM_IOCTL_BO_INFO DRM_IOWR(0xd4, struct drm_bo_reference_info_arg) -#define DRM_IOCTL_BO_WAIT_IDLE DRM_IOWR(0xd5, struct drm_bo_map_wait_idle_arg) -#define DRM_IOCTL_BO_VERSION DRM_IOR(0xd6, struct drm_bo_version_arg) -#define DRM_IOCTL_MM_INFO DRM_IOWR(0xd7, struct drm_mm_info_arg) - -/*@}*/ - /** * Device specific ioctls should only be in their respective headers * The device specific ioctl range is from 0x40 to 0x99. @@ -1168,11 +746,51 @@ struct drm_event_vblank { * drmCommandReadWrite(). */ #define DRM_COMMAND_BASE 0x40 -#define DRM_COMMAND_END 0xA0 +#define DRM_COMMAND_END 0xA0 + +/** + * Header for events written back to userspace on the drm fd. The + * type defines the type of event, the length specifies the total + * length of the event (including the header), and user_data is + * typically a 64 bit value passed with the ioctl that triggered the + * event. A read on the drm fd will always only return complete + * events, that is, if for example the read buffer is 100 bytes, and + * there are two 64 byte events pending, only one will be returned. + * + * Event types 0 - 0x7fffffff are generic drm events, 0x80000000 and + * up are chipset specific. + */ +struct drm_event { + __u32 type; + __u32 length; +}; + +#define DRM_EVENT_VBLANK 0x01 +#define DRM_EVENT_FLIP_COMPLETE 0x02 + +struct drm_event_vblank { + struct drm_event base; + __u64 user_data; + __u32 tv_sec; + __u32 tv_usec; + __u32 sequence; + __u32 reserved; +}; + +#define DRM_CAP_DUMB_BUFFER 0x1 +#define DRM_CAP_VBLANK_HIGH_CRTC 0x2 +#define DRM_CAP_DUMB_PREFERRED_DEPTH 0x3 +#define DRM_CAP_DUMB_PREFER_SHADOW 0x4 +#define DRM_CAP_PRIME 0x5 +#define DRM_CAP_TIMESTAMP_MONOTONIC 0x6 + +#define DRM_PRIME_CAP_IMPORT 0x1 +#define DRM_PRIME_CAP_EXPORT 0x2 /* typedef area */ #ifndef __KERNEL__ typedef struct drm_clip_rect drm_clip_rect_t; +typedef struct drm_drawable_info drm_drawable_info_t; typedef struct drm_tex_region drm_tex_region_t; typedef struct drm_hw_lock drm_hw_lock_t; typedef struct drm_version drm_version_t; @@ -1206,16 +824,12 @@ typedef struct drm_update_draw drm_update_draw_t; typedef struct drm_auth drm_auth_t; typedef struct drm_irq_busid drm_irq_busid_t; typedef enum drm_vblank_seq_type drm_vblank_seq_type_t; + typedef struct drm_agp_buffer drm_agp_buffer_t; typedef struct drm_agp_binding drm_agp_binding_t; typedef struct drm_agp_info drm_agp_info_t; typedef struct drm_scatter_gather drm_scatter_gather_t; typedef struct drm_set_version drm_set_version_t; - -typedef struct drm_fence_arg drm_fence_arg_t; -typedef struct drm_mm_type_arg drm_mm_type_arg_t; -typedef struct drm_mm_init_arg drm_mm_init_arg_t; -typedef enum drm_bo_type drm_bo_type_t; #endif #endif diff --git a/sys/dev/drm2/drmP.h b/sys/dev/drm2/drmP.h index e33ab88003ba..f028d8197cb5 100644 --- a/sys/dev/drm2/drmP.h +++ b/sys/dev/drm2/drmP.h @@ -100,14 +100,17 @@ __FBSDID("$FreeBSD$"); #include <dev/drm2/drm_sarea.h> #include <dev/drm2/drm_atomic.h> -#include <dev/drm2/drm_internal.h> #include <dev/drm2/drm_linux_list.h> #include <dev/drm2/drm_gem_names.h> +#include <dev/drm2/drm_os_freebsd.h> + +#define __OS_HAS_AGP (defined(CONFIG_AGP) || (defined(CONFIG_AGP_MODULE) && defined(MODULE))) +#define __OS_HAS_MTRR (defined(CONFIG_MTRR)) + struct drm_file; struct drm_device; -#include <dev/drm2/drm_os_freebsd.h> #include <dev/drm2/drm_hashtab.h> #include <dev/drm2/drm_mm.h> @@ -146,244 +149,116 @@ struct drm_device; #define DRIVER_GEM 0x1000 #define DRIVER_MODESET 0x2000 #define DRIVER_PRIME 0x4000 -#define DRIVER_LOCKLESS_IRQ 0x8000 - - -#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 */ - -#define DRM_GEM_MAPPING_MASK (3ULL << 62) -#define DRM_GEM_MAPPING_KEY (2ULL << 62) /* Non-canonical address form */ -#define DRM_GEM_MAX_IDX 0x3fffff -#define DRM_GEM_MAPPING_IDX(o) (((o) >> 40) & DRM_GEM_MAX_IDX) -#define DRM_GEM_MAPPING_OFF(i) (((uint64_t)(i)) << 40) -#define DRM_GEM_MAPPING_MAPOFF(o) \ - ((o) & ~(DRM_GEM_MAPPING_OFF(DRM_GEM_MAX_IDX) | DRM_GEM_MAPPING_KEY)) - -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); -MALLOC_DECLARE(DRM_MEM_KMS); -SYSCTL_DECL(_hw_drm); - -#define DRM_MAX_CTXBITMAP (PAGE_SIZE * 8) +#define DRIVER_BUS_PCI 0x1 +#define DRIVER_BUS_PLATFORM 0x2 +#define DRIVER_BUS_USB 0x3 /***********************************************************************/ -/** \name Internal types and structures */ +/** \name Begin the DRM... */ /*@{*/ -#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 DRM_DEBUG_CODE 2 /**< Include debugging code if > 1, then + also include looping detection. */ -#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_MAGIC_HASH_ORDER 4 /**< Size of key hash table. Must be power of 2. */ +#define DRM_KERNEL_CONTEXT 0 /**< Change drm_resctx if changed */ +#define DRM_RESERVED_CONTEXTS 1 /**< Change drm_resctx if changed */ +#define DRM_LOOPING_LIMIT 5000000 +#define DRM_TIME_SLICE (HZ/20) /**< Time slice for GLXContexts */ +#define DRM_LOCK_SLICE 1 /**< Time slice for lock, in jiffies */ -#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(dev) sx_xlock(&(dev)->dev_struct_lock) -#define DRM_UNLOCK(dev) sx_xunlock(&(dev)->dev_struct_lock) -#define DRM_LOCK_SLEEP(dev, chan, flags, msg, timeout) \ - (sx_sleep((chan), &(dev)->dev_struct_lock, (flags), (msg), (timeout))) -#if defined(INVARIANTS) -#define DRM_LOCK_ASSERT(dev) sx_assert(&(dev)->dev_struct_lock, SA_XLOCKED) -#define DRM_UNLOCK_ASSERT(dev) sx_assert(&(dev)->dev_struct_lock, SA_UNLOCKED) -#else -#define DRM_LOCK_ASSERT(d) -#define DRM_UNLOCK_ASSERT(d) -#endif +#define DRM_FLAG_DEBUG 0x01 -#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 DRM_MAX_CTXBITMAP (PAGE_SIZE * 8) +#define DRM_MAP_HASH_OFFSET 0x10000000 -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) +/***********************************************************************/ +/** \name Macros to make printk easier */ +/*@{*/ -#define PAGE_ALIGN(addr) round_page(addr) -/* DRM_SUSER returns true if the user is superuser */ -#define DRM_SUSER(p) (priv_check(p, PRIV_DRIVER) == 0) -#define DRM_AGP_FIND_DEVICE() agp_find_device() -#define DRM_MTRR_WC MDF_WRITECOMBINE -#define jiffies ticks -#define jiffies_to_msecs(x) (((int64_t)(x)) * 1000 / hz) -#define msecs_to_jiffies(x) (((int64_t)(x)) * hz / 1000) -#define time_after(a,b) ((long)(b) - (long)(a) < 0) -#define time_after_eq(a,b) ((long)(b) - (long)(a) <= 0) -#define drm_msleep(x, msg) pause((msg), ((int64_t)(x)) * hz / 1000) - -/* DRM_READMEMORYBARRIER() prevents reordering of reads. - * DRM_WRITEMEMORYBARRIER() prevents reordering of writes. - * DRM_MEMORYBARRIER() prevents reordering of reads and writes. +/** + * Error output. + * + * \param fmt printf() like format string. + * \param arg arguments */ -#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_READ64(map, offset) \ - le64toh(*(volatile u_int64_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_WRITE64(map, offset, val) \ - *(volatile u_int64_t *)(((vm_offset_t)(map)->virtual) + \ - (vm_offset_t)(offset)) = htole64(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 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(dev); \ - mtx_lock(&dev->irq_lock); \ - if (!(condition)) \ - ret = -mtx_sleep(&(queue), &dev->irq_lock, \ - PCATCH, "drmwtq", (timeout)); \ - mtx_unlock(&dev->irq_lock); \ - DRM_LOCK(dev); \ -} - #define DRM_ERROR(fmt, ...) \ printf("error: [" DRM_NAME ":pid%d:%s] *ERROR* " fmt, \ DRM_CURRENTPID, __func__ , ##__VA_ARGS__) +#define DRM_WARNING(fmt, ...) printf("warning: [" DRM_NAME "] " fmt , ##__VA_ARGS__) #define DRM_INFO(fmt, ...) printf("info: [" DRM_NAME "] " fmt , ##__VA_ARGS__) +/** + * Debug output. + * + * \param fmt printf() like format string. + * \param arg arguments + */ #define DRM_DEBUG(fmt, ...) do { \ - if ((drm_debug_flag & DRM_DEBUGBITS_DEBUG) != 0) \ + if ((drm_debug & DRM_DEBUGBITS_DEBUG) != 0) \ printf("[" DRM_NAME ":pid%d:%s] " fmt, DRM_CURRENTPID, \ __func__ , ##__VA_ARGS__); \ } while (0) #define DRM_DEBUG_KMS(fmt, ...) do { \ - if ((drm_debug_flag & DRM_DEBUGBITS_KMS) != 0) \ + if ((drm_debug & DRM_DEBUGBITS_KMS) != 0) \ printf("[" DRM_NAME ":KMS:pid%d:%s] " fmt, DRM_CURRENTPID,\ __func__ , ##__VA_ARGS__); \ } while (0) #define DRM_DEBUG_DRIVER(fmt, ...) do { \ - if ((drm_debug_flag & DRM_DEBUGBITS_KMS) != 0) \ + if ((drm_debug & DRM_DEBUGBITS_KMS) != 0) \ printf("[" DRM_NAME ":KMS:pid%d:%s] " fmt, DRM_CURRENTPID,\ __func__ , ##__VA_ARGS__); \ } while (0) -#define dev_err(dev, fmt, ...) \ - device_printf((dev), "error: " fmt, ## __VA_ARGS__) -#define dev_warn(dev, fmt, ...) \ - device_printf((dev), "warning: " fmt, ## __VA_ARGS__) -#define dev_info(dev, fmt, ...) \ - device_printf((dev), "info: " fmt, ## __VA_ARGS__) -#define dev_dbg(dev, fmt, ...) do { \ - if ((drm_debug_flag& DRM_DEBUGBITS_KMS) != 0) { \ - device_printf((dev), "debug: " fmt, ## __VA_ARGS__); \ - } \ +/*@}*/ + +/***********************************************************************/ +/** \name Internal types and structures */ +/*@{*/ + +#define DRM_ARRAY_SIZE(x) ARRAY_SIZE(x) + +#define DRM_LEFTCOUNT(x) (((x)->rp + (x)->count - (x)->wp) % ((x)->count + 1)) +#define DRM_BUFCOUNT(x) ((x)->count - DRM_LEFTCOUNT(x)) + +#define DRM_IF_VERSION(maj, min) (maj << 16 | min) + +/** + * Test that the hardware lock is held by the caller, returning otherwise. + * + * \param dev DRM device. + * \param filp file pointer of the caller. + */ +#define LOCK_TEST_WITH_RETURN( dev, _file_priv ) \ +do { \ + if (!_DRM_LOCK_IS_HELD(_file_priv->master->lock.hw_lock->lock) || \ + _file_priv->master->lock.file_priv != _file_priv) { \ + DRM_ERROR( "%s called without lock held, held %d owner %p %p\n",\ + __func__, _DRM_LOCK_IS_HELD(_file_priv->master->lock.hw_lock->lock),\ + _file_priv->master->lock.file_priv, _file_priv); \ + return -EINVAL; \ + } \ } while (0) -typedef struct drm_pci_id_list -{ - int vendor; - int device; - long driver_private; - char *name; -} drm_pci_id_list_t; +/** + * Ioctl function type. + * + * \param inode device inode. + * \param file_priv DRM file private pointer. + * \param cmd command. + * \param arg argument. + */ +typedef int drm_ioctl_t(struct drm_device *dev, void *data, + struct drm_file *file_priv); -struct drm_msi_blacklist_entry -{ - int vendor; - int device; -}; +#define DRM_IOCTL_NR(n) ((n) & 0xff) +#define DRM_MAJOR 226 #define DRM_AUTH 0x1 #define DRM_MASTER 0x2 @@ -391,36 +266,34 @@ struct drm_msi_blacklist_entry #define DRM_CONTROL_ALLOW 0x8 #define DRM_UNLOCKED 0x10 -typedef struct drm_ioctl_desc { +struct drm_ioctl_desc { unsigned long cmd; - int (*func)(struct drm_device *dev, void *data, - struct drm_file *file_priv); int flags; + drm_ioctl_t *func; unsigned int cmd_drv; -} 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} + +#define DRM_IOCTL_DEF(ioctl, _func, _flags) \ + [DRM_IOCTL_NR(ioctl)] = {.cmd = ioctl, .func = _func, .flags = _flags, .cmd_drv = 0} #define DRM_IOCTL_DEF_DRV(ioctl, _func, _flags) \ [DRM_IOCTL_NR(DRM_##ioctl)] = {.cmd = DRM_##ioctl, .func = _func, .flags = _flags, .cmd_drv = DRM_IOCTL_##ioctl} -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; +struct drm_magic_entry { + struct list_head head; + struct drm_hash_item hash_item; + struct drm_file *priv; +}; -typedef struct drm_buf { +/** + * DMA buffer. + */ +struct drm_buf { int idx; /**< Index into master buflist */ int total; /**< Buffer size */ int order; /**< log-base-2(total) */ @@ -445,16 +318,23 @@ typedef struct drm_buf { int dev_priv_size; /**< Size of buffer private storage */ 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; +struct drm_freelist { + int initialized; /**< Freelist in use */ + atomic_t count; /**< Number of free buffers */ + struct drm_buf *next; /**< End pointer */ + +#ifdef FREEBSD_NOTYET + wait_queue_head_t waiting; /**< Processes waiting on free bufs */ +#endif /* defined(FREEBSD_NOTYET) */ + int low_mark; /**< Low water mark */ + int high_mark; /**< High water mark */ +#ifdef FREEBSD_NOTYET + atomic_t wfh; /**< If waiting for high mark */ + spinlock_t lock; +#endif /* defined(FREEBSD_NOTYET) */ +}; typedef struct drm_dma_handle { void *vaddr; @@ -463,16 +343,19 @@ typedef struct drm_dma_handle { 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; +/** + * Buffer entry. There is one of this for each buffer size order. + */ +struct drm_buf_entry { + int buf_size; /**< size */ + int buf_count; /**< number of buffers */ + struct drm_buf *buflist; /**< buffer list */ + int seg_count; + int page_order; + struct drm_dma_handle **seglist; - drm_freelist_t freelist; -} drm_buf_entry_t; + struct drm_freelist freelist; +}; /* Event queued up for userspace to read */ struct drm_pending_event { @@ -487,53 +370,53 @@ struct drm_pending_event { /* initial implementaton using a linked list - todo hashtab */ struct drm_prime_file_private { struct list_head head; -#ifdef DUMBBELL_WIP - struct mutex lock; -#endif /* DUMBBELL_WIP */ + struct mtx lock; }; -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; + int authenticated; + pid_t pid; + uid_t uid; + drm_magic_t magic; + unsigned long ioctl_count; + struct list_head lhead; + struct drm_minor *minor; + unsigned long lock_count; + + void *driver_priv; struct drm_gem_names object_names; - int is_master; - struct drm_master *masterp; - - struct list_head fbs; + int is_master; /* this file private is a master for a minor */ + struct drm_master *master; /* master this node is currently associated with + N.B. not always minor->master */ + struct list_head fbs; - struct list_head event_list; - int event_space; - struct selinfo event_poll; + struct selinfo event_poll; + struct list_head event_list; + int event_space; struct drm_prime_file_private prime; }; -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. +/** + * Lock data. + */ +struct drm_lock_data { + struct drm_hw_lock *hw_lock; /**< Hardware lock */ + /** Private of lock holder's file (NULL=kernel) */ + struct drm_file *file_priv; + wait_queue_head_t lock_queue; /**< Queue of blocked processes */ + unsigned long lock_time; /**< Time of last lock in jiffies */ + struct mtx spinlock; + uint32_t kernel_waiters; + uint32_t user_waiters; + int idle_has_lock; +}; + +/** + * DMA data. */ -typedef struct drm_device_dma { +struct drm_device_dma { struct drm_buf_entry bufs[DRM_MAX_ORDER + 1]; /**< buffers, grouped by their size order */ int buf_count; /**< total number of buffers */ @@ -549,68 +432,90 @@ typedef struct drm_device_dma { _DRM_DMA_USE_PCI_RO = 0x08 } 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 { +}; + +/** + * AGP memory entry. Stored as a doubly linked list. + */ +struct drm_agp_mem { + unsigned long handle; /**< handle */ + DRM_AGP_MEM *memory; + unsigned long bound; /**< address */ + int pages; + struct list_head head; +}; + +/** + * AGP data. + * + * \sa drm_agp_init() and drm_device::agp. + */ +struct drm_agp_head { + DRM_AGP_KERN agp_info; /**< AGP device information */ + struct list_head memory; + unsigned long mode; /**< AGP mode */ + device_t bridge; + int enabled; /**< whether the AGP bus as been enabled */ + int acquired; /**< whether the AGP device has been acquired */ + unsigned long base; + int agp_mtrr; + int cant_use_aperture; +}; + +/** + * Scatter-gather memory. + */ +struct drm_sg_mem { vm_offset_t vaddr; vm_paddr_t *busaddr; vm_pindex_t pages; -} drm_sg_mem_t; +}; + +struct drm_sigdata { + int context; + struct drm_hw_lock *lock; +}; +/** + * Kernel side of a mapping + */ #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 */ + +struct drm_local_map { + resource_size_t offset; /**< Requested physical address (0 for SAREA)*/ + unsigned long size; /**< Requested physical size (bytes) */ + enum drm_map_type type; /**< Type of memory to map */ + enum drm_map_flags flags; /**< Flags */ + void *handle; /**< User-space: "Handle" to pass to mmap() */ + /**< Kernel-space: kernel-virtual address */ + int mtrr; /**< MTRR slot 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 */ +typedef struct drm_local_map drm_local_map_t; + +/** + * Mappings list + */ +struct drm_map_list { + struct list_head head; /**< list head */ + struct drm_hash_item hash; + struct drm_local_map *map; /**< mapping */ + uint64_t user_token; + struct drm_master *master; + struct drm_mm_node *file_offset_node; /**< fake offset */ +}; + +/** + * Context handle list + */ +struct drm_ctx_list { + struct list_head head; /**< list head */ + drm_context_t handle; /**< context handle */ + struct drm_file *tag; /**< associated fd private data */ }; /* location of GART table */ @@ -627,29 +532,30 @@ struct drm_ati_pcigart_info { 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; + struct drm_local_map mapping; int table_size; - struct drm_dma_handle *dmah; /* handle for ATI PCIGART table */ + struct drm_dma_handle *dmah; /* handle for ATI PCIGART table FIXME */ }; -typedef vm_paddr_t resource_size_t; - /** * GEM specific mm private for tracking GEM objects */ struct drm_gem_mm { - struct drm_open_hash offset_hash; /**< User token hash table for maps */ struct unrhdr *idxunr; + struct drm_open_hash offset_hash; /**< User token hash table for maps */ }; +/** + * This structure defines the drm_mm memory object, which will be used by the + * DRM for its buffer objects. + */ struct drm_gem_object { /** Reference count of this object */ u_int refcount; /** Handle count of this object. Each handle also holds a reference */ - u_int handle_count; /* number of handles on this object */ + atomic_t handle_count; /* number of handles on this object */ /** Related drm device */ struct drm_device *dev; @@ -657,6 +563,7 @@ struct drm_gem_object { /** File representing the shmem storage: filp in Linux parlance */ vm_object_t vm_obj; + /* Mapping info for this object */ bool on_map; struct drm_hash_item map_list; @@ -692,16 +599,16 @@ struct drm_gem_object { void *driver_private; -#ifdef DUMBBELL_WIP +#ifdef FREEBSD_NOTYET /* dma buf exported from this GEM object */ struct dma_buf *export_dma_buf; /* dma buf attachment backing this object */ struct dma_buf_attachment *import_attach; -#endif /* DUMBBELL_WIP */ +#endif /* FREEBSD_NOTYET */ }; -#include "drm_crtc.h" +#include <dev/drm2/drm_crtc.h> /* per-master structure */ struct drm_master { @@ -743,70 +650,81 @@ struct drm_master { #define DRM_SCANOUTPOS_INVBL (1 << 1) #define DRM_SCANOUTPOS_ACCURATE (1 << 2) -#ifndef DMA_BIT_MASK -#define DMA_BIT_MASK(n) (((n) == 64) ? ~0ULL : (1ULL<<(n)) - 1) -#endif +struct drm_bus { + int bus_type; + int (*get_irq)(struct drm_device *dev); + void (*free_irq)(struct drm_device *dev); + const char *(*get_name)(struct drm_device *dev); + int (*set_busid)(struct drm_device *dev, struct drm_master *master); + int (*set_unique)(struct drm_device *dev, struct drm_master *master, + struct drm_unique *unique); + int (*irq_by_busid)(struct drm_device *dev, struct drm_irq_busid *p); + /* hooks that are for PCI */ + int (*agp_init)(struct drm_device *dev); -#define upper_32_bits(n) ((u32)(((n) >> 16) >> 16)) - -struct drm_driver_info { - int (*load)(struct drm_device *, unsigned long flags); - int (*use_msi)(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); - int (*get_scanout_position)(struct drm_device *dev, int crtc, - int *vpos, int *hpos); - - int (*get_vblank_timestamp)(struct drm_device *dev, int crtc, - int *max_error, struct timeval *vblank_time, - unsigned flags); - - int (*gem_init_object)(struct drm_gem_object *obj); - void (*gem_free_object)(struct drm_gem_object *obj); - int (*gem_open_object)(struct drm_gem_object *, struct drm_file *); - void (*gem_close_object)(struct drm_gem_object *, struct drm_file *); +}; - struct cdev_pager_ops *gem_pager_ops; +/** + * DRM driver structure. This structure represent the common code for + * a family of cards. There will one drm_device for each card present + * in this family + */ +struct drm_driver { + 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 *); + int (*dma_ioctl) (struct drm_device *dev, void *data, struct drm_file *file_priv); + int (*dma_quiescent) (struct drm_device *); + int (*context_dtor) (struct drm_device *dev, int context); - int (*dumb_create)(struct drm_file *file_priv, - struct drm_device *dev, struct drm_mode_create_dumb *args); - int (*dumb_map_offset)(struct drm_file *file_priv, - struct drm_device *dev, uint32_t handle, uint64_t *offset); - int (*dumb_destroy)(struct drm_file *file_priv, - struct drm_device *dev, uint32_t handle); + /** + * get_vblank_counter - get raw hardware vblank counter + * @dev: DRM device + * @crtc: counter to fetch + * + * Driver callback for fetching a raw hardware vblank counter for @crtc. + * If a device doesn't have a hardware counter, the driver can simply + * return the value of drm_vblank_count. The DRM core will account for + * missed vblank events while interrupts where disabled based on system + * timestamps. + * + * Wraparound handling and loss of events due to modesetting is dealt + * with in the DRM core code. + * + * RETURNS + * Raw vblank counter value. + */ + u32 (*get_vblank_counter) (struct drm_device *dev, int crtc); - int (*sysctl_init)(struct drm_device *dev, - struct sysctl_ctx_list *ctx, struct sysctl_oid *top); - void (*sysctl_cleanup)(struct drm_device *dev); + /** + * enable_vblank - enable vblank interrupt events + * @dev: DRM device + * @crtc: which irq to enable + * + * Enable vblank interrupts for @crtc. If the device doesn't have + * a hardware vblank counter, this routine should be a no-op, since + * interrupts will have to stay on to keep the count accurate. + * + * RETURNS + * Zero on success, appropriate errno if the given @crtc's vblank + * interrupt cannot be enabled. + */ + int (*enable_vblank) (struct drm_device *dev, int crtc); - drm_pci_id_list_t *id_entry; /* PCI ID, name, and chipset private */ + /** + * disable_vblank - disable vblank interrupt events + * @dev: DRM device + * @crtc: which irq to enable + * + * Disable vblank interrupts for @crtc. If the device doesn't have + * a hardware vblank counter, this routine should be a no-op, since + * interrupts will have to stay on to keep the count accurate. + */ + void (*disable_vblank) (struct drm_device *dev, int crtc); /** * Called by \c drm_device_is_agp. Typically used to determine if a @@ -819,39 +737,177 @@ struct drm_driver_info { * 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); + int (*device_is_agp) (struct drm_device *dev); - drm_ioctl_desc_t *ioctls; -#ifdef COMPAT_FREEBSD32 - drm_ioctl_desc_t *compat_ioctls; - int *compat_ioctls_nr; -#endif - int max_ioctl; + /** + * Called by vblank timestamping code. + * + * Return the current display scanout position from a crtc. + * + * \param dev DRM device. + * \param crtc Id of the crtc to query. + * \param *vpos Target location for current vertical scanout position. + * \param *hpos Target location for current horizontal scanout position. + * + * Returns vpos as a positive number while in active scanout area. + * Returns vpos as a negative number inside vblank, counting the number + * of scanlines to go until end of vblank, e.g., -1 means "one scanline + * until start of active scanout / end of vblank." + * + * \return Flags, or'ed together as follows: + * + * DRM_SCANOUTPOS_VALID = Query successful. + * DRM_SCANOUTPOS_INVBL = Inside vblank. + * DRM_SCANOUTPOS_ACCURATE = Returned position is accurate. A lack of + * this flag means that returned position may be offset by a constant + * but unknown small number of scanlines wrt. real scanout position. + * + */ + int (*get_scanout_position) (struct drm_device *dev, int crtc, + int *vpos, int *hpos); - int buf_priv_size; + /** + * Called by \c drm_get_last_vbltimestamp. Should return a precise + * timestamp when the most recent VBLANK interval ended or will end. + * + * Specifically, the timestamp in @vblank_time should correspond as + * closely as possible to the time when the first video scanline of + * the video frame after the end of VBLANK will start scanning out, + * the time immediately after end of the VBLANK interval. If the + * @crtc is currently inside VBLANK, this will be a time in the future. + * If the @crtc is currently scanning out a frame, this will be the + * past start time of the current scanout. This is meant to adhere + * to the OpenML OML_sync_control extension specification. + * + * \param dev dev DRM device handle. + * \param crtc crtc for which timestamp should be returned. + * \param *max_error Maximum allowable timestamp error in nanoseconds. + * Implementation should strive to provide timestamp + * with an error of at most *max_error nanoseconds. + * Returns true upper bound on error for timestamp. + * \param *vblank_time Target location for returned vblank timestamp. + * \param flags 0 = Defaults, no special treatment needed. + * \param DRM_CALLED_FROM_VBLIRQ = Function is called from vblank + * irq handler. Some drivers need to apply some workarounds + * for gpu-specific vblank irq quirks if flag is set. + * + * \returns + * Zero if timestamping isn't supported in current display mode or a + * negative number on failure. A positive status code on success, + * which describes how the vblank_time timestamp was computed. + */ + int (*get_vblank_timestamp) (struct drm_device *dev, int crtc, + int *max_error, + struct timeval *vblank_time, + unsigned flags); + + /* these have to be filled in */ + + irqreturn_t(*irq_handler) (DRM_IRQ_ARGS); + void (*irq_preinstall) (struct drm_device *dev); + int (*irq_postinstall) (struct drm_device *dev); + void (*irq_uninstall) (struct drm_device *dev); + void (*set_version) (struct drm_device *dev, + struct drm_set_version *sv); + + /* Master routines */ + int (*master_create)(struct drm_device *dev, struct drm_master *master); + void (*master_destroy)(struct drm_device *dev, struct drm_master *master); + /** + * master_set is called whenever the minor master is set. + * master_drop is called whenever the minor master is dropped. + */ + + int (*master_set)(struct drm_device *dev, struct drm_file *file_priv, + bool from_open); + void (*master_drop)(struct drm_device *dev, struct drm_file *file_priv, + bool from_release); + + /** + * Driver-specific constructor for drm_gem_objects, to set up + * obj->driver_private. + * + * Returns 0 on success. + */ + int (*gem_init_object) (struct drm_gem_object *obj); + void (*gem_free_object) (struct drm_gem_object *obj); + int (*gem_open_object) (struct drm_gem_object *, struct drm_file *); + void (*gem_close_object) (struct drm_gem_object *, struct drm_file *); + +#ifdef FREEBSD_NOTYET + /* prime: */ + /* export handle -> fd (see drm_gem_prime_handle_to_fd() helper) */ + int (*prime_handle_to_fd)(struct drm_device *dev, struct drm_file *file_priv, + uint32_t handle, uint32_t flags, int *prime_fd); + /* import fd -> handle (see drm_gem_prime_fd_to_handle() helper) */ + int (*prime_fd_to_handle)(struct drm_device *dev, struct drm_file *file_priv, + int prime_fd, uint32_t *handle); + /* export GEM -> dmabuf */ + struct dma_buf * (*gem_prime_export)(struct drm_device *dev, + struct drm_gem_object *obj, int flags); + /* import dmabuf -> GEM */ + struct drm_gem_object * (*gem_prime_import)(struct drm_device *dev, + struct dma_buf *dma_buf); +#endif /* defined(FREEBSD_NOTYET) */ + + /* dumb alloc support */ + int (*dumb_create)(struct drm_file *file_priv, + struct drm_device *dev, + struct drm_mode_create_dumb *args); + int (*dumb_map_offset)(struct drm_file *file_priv, + struct drm_device *dev, uint32_t handle, + uint64_t *offset); + int (*dumb_destroy)(struct drm_file *file_priv, + struct drm_device *dev, + uint32_t handle); + + /* Driver private ops for this object */ + struct cdev_pager_ops *gem_pager_ops; + + int (*sysctl_init)(struct drm_device *dev, + struct sysctl_ctx_list *ctx, struct sysctl_oid *top); + void (*sysctl_cleanup)(struct drm_device *dev); - 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. */ + int major; + int minor; + int patchlevel; + char *name; + char *desc; + char *date; u32 driver_features; + int dev_priv_size; + struct drm_ioctl_desc *ioctls; + int num_ioctls; + struct drm_bus *bus; +#ifdef COMPAT_FREEBSD32 + struct drm_ioctl_desc *compat_ioctls; + int *num_compat_ioctls; +#endif + + int buf_priv_size; }; +#define DRM_MINOR_UNASSIGNED 0 +#define DRM_MINOR_LEGACY 1 +#define DRM_MINOR_CONTROL 2 +#define DRM_MINOR_RENDER 3 + /** * DRM minor structure. This structure represents a drm minor number. */ struct drm_minor { int index; /**< Minor device number */ int type; /**< Control or render */ + struct cdev *device; /**< Device number for mknod */ device_t kdev; /**< OS device */ struct drm_device *dev; struct drm_master *master; /* currently active master for this node */ struct list_head master_list; struct drm_mode_group mode_group; + + struct sigio *buf_sigio; /* Processes waiting for SIGIO */ }; /* mode specified on the command line */ @@ -876,105 +932,80 @@ struct drm_pending_vblank_event { struct drm_event_vblank event; }; -/* Length for the array of resource pointers for drm_get_resource_*. */ -#define DRM_MAX_PCI_RESOURCE 6 - /** * DRM device structure. This structure represent a complete card that * may contain multiple heads. */ struct drm_device { - struct drm_driver_info *driver; - drm_pci_id_list_t *id_entry; /* PCI ID, name, and chipset private */ - - uint16_t pci_device; /* PCI device id */ - uint16_t pci_vendor; /* PCI vendor id */ - uint16_t pci_subdevice; /* PCI subsystem device id */ - uint16_t pci_subvendor; /* PCI subsystem 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 dma_lock; /* protects dev->dma */ - struct mtx irq_lock; /* protects irq condition checks */ - struct mtx dev_lock; /* protects everything else */ - struct sx dev_struct_lock; - 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 */ + int if_version; /**< Highest interface version set */ - /* 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 */ + /** \name Locks */ + /*@{ */ + struct mtx count_lock; /**< For inuse, drm_device::open_count, drm_device::buf_use */ + struct sx dev_struct_lock; /**< For others */ + /*@} */ - /* Storage of resource pointers for drm_get_resource_* */ - struct resource *pcir[DRM_MAX_PCI_RESOURCE]; - int pcirid[DRM_MAX_PCI_RESOURCE]; + /** \name Usage Counters */ + /*@{ */ + int open_count; /**< Outstanding files open */ + atomic_t ioctl_count; /**< Outstanding IOCTLs pending */ + atomic_t vma_count; /**< Outstanding vma areas open */ + int buf_use; /**< Buffers in use -- cannot alloc */ + atomic_t buf_alloc; /**< Buffer allocation in progress */ + /*@} */ - int pci_domain; - int pci_bus; - int pci_slot; - int pci_func; + /** \name Performance counters */ + /*@{ */ + unsigned long counters; + enum drm_stat_type types[15]; + atomic_t counts[15]; + /*@} */ - atomic_t context_flag; /* Context swapping flag */ - int last_context; /* Last current context */ + struct list_head filelist; - int num_crtcs; + /** \name Memory management */ + /*@{ */ + struct list_head maplist; /**< Linked list of regions */ + int map_count; /**< Number of mappable regions */ + struct drm_open_hash map_hash; /**< User token hash table for maps */ - struct sigio *buf_sigio; /* Processes waiting for SIGIO */ + /** \name Context handle management */ + /*@{ */ + struct list_head ctxlist; /**< Linked list of context handles */ + int ctx_count; /**< Number of context handles */ + struct mtx ctxlist_mutex; /**< For ctxlist */ + drm_local_map_t **context_sareas; + int max_context; + unsigned long *ctx_bitmap; - /* Sysctl support */ - struct drm_sysctl_info *sysctl; - int sysctl_node_idx; + /*@} */ - drm_agp_head_t *agp; - drm_sg_mem_t *sg; /* Scatter gather memory */ - unsigned long *ctx_bitmap; - void *dev_private; - unsigned int agp_buffer_token; - drm_local_map_t *agp_buffer_map; + /** \name DMA support */ + /*@{ */ + struct drm_device_dma *dma; /**< Optional pointer for DMA support */ + /*@} */ - struct drm_minor *control; /**< Control node for card */ - struct drm_minor *primary; /**< render type primary screen head */ + /** \name Context support */ + /*@{ */ + int irq_enabled; /**< True if irq handler is enabled */ + atomic_t context_flag; /**< Context swapping flag */ + atomic_t interrupt_flag; /**< Interruption handler flag */ + atomic_t dma_flag; /**< DMA dispatch flag */ + wait_queue_head_t context_wait; /**< Processes waiting on ctx switch */ + int last_checked; /**< Last context checked for DMA */ + int last_context; /**< Last current context */ + unsigned long last_switch; /**< jiffies at last context switch */ + /*@} */ - void *drm_ttm_bdev; - struct unrhdr *drw_unrhdr; - /* RB tree of drawable infos */ - RB_HEAD(drawable_tree, bsd_drm_drawable_info) drw_head; + /** \name VBLANK IRQ support */ + /*@{ */ + /* + * At load time, disabling the vblank interrupt won't be allowed since + * old clients may not call the modeset ioctl and therefore misbehave. + * Once the modeset ioctl *has* been called though, we can safely + * disable them when unused. + */ int vblank_disable_allowed; atomic_t *_vblank_count; /**< number of VBLANK interrupts (driver must alloc the right number of counters) */ @@ -992,21 +1023,79 @@ struct drm_device { u32 max_vblank_count; /**< size of vblank counter register */ + /** + * List of events + */ struct list_head vblank_event_list; - struct mtx event_lock; + struct mtx event_lock; + + /*@} */ + + struct drm_agp_head *agp; /**< AGP data */ + + device_t dev; /* Device instance from newbus */ + uint16_t pci_device; /* PCI device id */ + uint16_t pci_vendor; /* PCI vendor id */ + uint16_t pci_subdevice; /* PCI subsystem device id */ + uint16_t pci_subvendor; /* PCI subsystem vendor id */ + + struct drm_sg_mem *sg; /**< Scatter gather memory */ + unsigned int num_crtcs; /**< Number of CRTCs on this device */ + void *dev_private; /**< device private data */ + void *mm_private; + struct drm_sigdata sigdata; /**< For block_all_signals */ + sigset_t sigmask; + + struct drm_driver *driver; + struct drm_local_map *agp_buffer_map; + unsigned int agp_buffer_token; + struct drm_minor *control; /**< Control node for card */ + struct drm_minor *primary; /**< render type primary screen head */ struct drm_mode_config mode_config; /**< Current mode config */ - /* GEM part */ - struct sx object_name_lock; + /** \name GEM information */ + /*@{ */ + struct sx object_name_lock; struct drm_gem_names object_names; - void *mm_private; + /*@} */ + int switch_power_state; + + atomic_t unplugged; /* device has been unplugged or gone away */ + + /* Locks */ + struct mtx dma_lock; /* protects dev->dma */ + struct mtx irq_lock; /* protects irq condition checks */ + + /* Context support */ + int irq; /* Interrupt used by board */ + 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_* */ +#define DRM_MAX_PCI_RESOURCE 6 + struct resource *pcir[DRM_MAX_PCI_RESOURCE]; + int pcirid[DRM_MAX_PCI_RESOURCE]; + struct mtx pcir_lock; + + int pci_domain; + int pci_bus; + int pci_slot; + int pci_func; + + /* Sysctl support */ + struct drm_sysctl_info *sysctl; + int sysctl_node_idx; + + void *drm_ttm_bdev; void *sysctl_private; char busid_str[128]; int modesetting; - int switch_power_state; + drm_pci_id_list_t *id_entry; /* PCI ID, name, and chipset private */ }; #define DRM_SWITCH_POWER_ON 0 @@ -1019,6 +1108,12 @@ static __inline__ int drm_core_check_feature(struct drm_device *dev, return ((dev->driver->driver_features & feature) ? 1 : 0); } +static inline int drm_dev_to_irq(struct drm_device *dev) +{ + return dev->driver->bus->get_irq(dev); +} + + #if __OS_HAS_AGP static inline int drm_core_has_AGP(struct drm_device *dev) { @@ -1028,165 +1123,175 @@ static inline int drm_core_has_AGP(struct drm_device *dev) #define drm_core_has_AGP(dev) (0) #endif -enum dmi_field { - DMI_NONE, - DMI_BIOS_VENDOR, - DMI_BIOS_VERSION, - DMI_BIOS_DATE, - DMI_SYS_VENDOR, - DMI_PRODUCT_NAME, - DMI_PRODUCT_VERSION, - DMI_PRODUCT_SERIAL, - DMI_PRODUCT_UUID, - DMI_BOARD_VENDOR, - DMI_BOARD_NAME, - DMI_BOARD_VERSION, - DMI_BOARD_SERIAL, - DMI_BOARD_ASSET_TAG, - DMI_CHASSIS_VENDOR, - DMI_CHASSIS_TYPE, - DMI_CHASSIS_VERSION, - DMI_CHASSIS_SERIAL, - DMI_CHASSIS_ASSET_TAG, - DMI_STRING_MAX, -}; +#if __OS_HAS_MTRR +static inline int drm_core_has_MTRR(struct drm_device *dev) +{ + return drm_core_check_feature(dev, DRIVER_USE_MTRR); +} -struct dmi_strmatch { - unsigned char slot; - char substr[79]; -}; +#define DRM_MTRR_WC MDF_WRITECOMBINE -struct dmi_system_id { - int (*callback)(const struct dmi_system_id *); - const char *ident; - struct dmi_strmatch matches[4]; -}; -#define DMI_MATCH(a, b) {(a), (b)} -bool dmi_check_system(const struct dmi_system_id *); +int drm_mtrr_add(unsigned long offset, unsigned long size, unsigned int flags); +int drm_mtrr_del(int handle, unsigned long offset, unsigned long size, unsigned int flags); -extern int drm_debug_flag; -extern int drm_notyet_flag; -extern unsigned int drm_vblank_offdelay; -extern unsigned int drm_timestamp_precision; -extern unsigned int drm_timestamp_monotonic; +#else +#define drm_core_has_MTRR(dev) (0) -/* 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); -int drm_create_cdevs(device_t kdev); -void drm_close(void *data); -int drm_detach(device_t kdev); +#define DRM_MTRR_WC 0 + +static inline int drm_mtrr_add(unsigned long offset, unsigned long size, + unsigned int flags) +{ + return 0; +} + +static inline int drm_mtrr_del(int handle, unsigned long offset, + unsigned long size, unsigned int flags) +{ + return 0; +} +#endif + +/******************************************************************/ +/** \name Internal function definitions */ +/*@{*/ + + /* Driver support (drm_drv.h) */ d_ioctl_t drm_ioctl; +extern int drm_lastclose(struct drm_device *dev); + + /* Device support (drm_fops.h) */ +extern struct sx drm_global_mutex; d_open_t drm_open; d_read_t drm_read; -d_poll_t drm_poll; +extern void drm_release(void *data); + + /* Mapping support (drm_vm.h) */ d_mmap_t drm_mmap; -extern drm_local_map_t *drm_getsarea(struct drm_device *dev); +int drm_mmap_single(struct cdev *kdev, vm_ooffset_t *offset, + vm_size_t size, struct vm_object **obj_res, int nprot); +d_poll_t drm_poll; -void drm_event_wakeup(struct drm_pending_event *e); + /* Memory management support (drm_memory.h) */ +extern void drm_free_agp(DRM_AGP_MEM * handle, int pages); +extern int drm_bind_agp(DRM_AGP_MEM * handle, unsigned int start); +#ifdef FREEBSD_NOTYET +extern DRM_AGP_MEM *drm_agp_bind_pages(struct drm_device *dev, + struct page **pages, + unsigned long num_pages, + uint32_t gtt_offset, + uint32_t type); +#endif /* FREEBSD_NOTYET */ +extern int drm_unbind_agp(DRM_AGP_MEM * handle); + + /* Misc. IOCTL support (drm_ioctl.h) */ +extern int drm_irq_by_busid(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int drm_getunique(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int drm_setunique(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int drm_getmap(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int drm_getclient(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int drm_getstats(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int drm_getcap(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int drm_setversion(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int drm_noop(struct drm_device *dev, void *data, + struct drm_file *file_priv); -int drm_add_busid_modesetting(struct drm_device *dev, - struct sysctl_ctx_list *ctx, struct sysctl_oid *top); + /* Context IOCTL support (drm_context.h) */ +extern int drm_resctx(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int drm_addctx(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int drm_modctx(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int drm_getctx(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int drm_switchctx(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int drm_newctx(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int drm_rmctx(struct drm_device *dev, void *data, + struct drm_file *file_priv); -/* 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); +extern int drm_ctxbitmap_init(struct drm_device *dev); +extern void drm_ctxbitmap_cleanup(struct drm_device *dev); +extern void drm_ctxbitmap_free(struct drm_device *dev, int ctx_handle); -#ifdef DUMBBELL_WIP -extern int drm_gem_prime_handle_to_fd(struct drm_device *dev, - struct drm_file *file_priv, uint32_t handle, uint32_t flags, - int *prime_fd); -extern int drm_gem_prime_fd_to_handle(struct drm_device *dev, - struct drm_file *file_priv, int prime_fd, uint32_t *handle); +extern int drm_setsareactx(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int drm_getsareactx(struct drm_device *dev, void *data, + struct drm_file *file_priv); -extern int drm_prime_handle_to_fd_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv); -extern int drm_prime_fd_to_handle_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv); + /* Authentication IOCTL support (drm_auth.h) */ +extern int drm_getmagic(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int drm_authmagic(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int drm_remove_magic(struct drm_master *master, drm_magic_t magic); -#ifdef DUMBBELL_WIP -/* - * See drm_prime.c - * -- dumbbell@ - */ -extern int drm_prime_sg_to_page_addr_arrays(struct sg_table *sgt, vm_page_t *pages, - dma_addr_t *addrs, int max_pages); -#endif /* DUMBBELL_WIP */ -extern struct sg_table *drm_prime_pages_to_sg(vm_page_t *pages, int nr_pages); -extern void drm_prime_gem_destroy(struct drm_gem_object *obj, struct sg_table *sg); +/* Cache management (drm_cache.c) */ +void drm_clflush_pages(vm_page_t *pages, unsigned long num_pages); +void drm_clflush_virt_range(char *addr, unsigned long length); + /* Locking IOCTL support (drm_lock.h) */ +extern int drm_lock(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int drm_unlock(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int drm_lock_free(struct drm_lock_data *lock_data, unsigned int context); +extern void drm_idlelock_take(struct drm_lock_data *lock_data); +extern void drm_idlelock_release(struct drm_lock_data *lock_data); -void drm_prime_init_file_private(struct drm_prime_file_private *prime_fpriv); -void drm_prime_destroy_file_private(struct drm_prime_file_private *prime_fpriv); -int drm_prime_add_imported_buf_handle(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf, uint32_t handle); -int drm_prime_lookup_imported_buf_handle(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf, uint32_t *handle); -void drm_prime_remove_imported_buf_handle(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf); +/* + * These are exported to drivers so that they can implement fencing using + * DMA quiscent + idle. DMA quiescent usually requires the hardware lock. + */ -int drm_prime_add_dma_buf(struct drm_device *dev, struct drm_gem_object *obj); -int drm_prime_lookup_obj(struct drm_device *dev, struct dma_buf *buf, - struct drm_gem_object **obj); -#endif /* DUMBBELL_WIP */ - -/* 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); +extern int drm_i_have_hw_lock(struct drm_device *dev, struct drm_file *file_priv); -/* 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 + /* Buffer management support (drm_bufs.h) */ +extern int drm_addbufs_agp(struct drm_device *dev, struct drm_buf_desc * request); +extern int drm_addbufs_pci(struct drm_device *dev, struct drm_buf_desc * request); +extern int drm_addmap(struct drm_device *dev, resource_size_t offset, + unsigned int size, enum drm_map_type type, + enum drm_map_flags flags, struct drm_local_map **map_ptr); +extern int drm_addmap_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int drm_rmmap(struct drm_device *dev, struct drm_local_map *map); +extern int drm_rmmap_locked(struct drm_device *dev, struct drm_local_map *map); +extern int drm_rmmap_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int drm_addbufs(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int drm_infobufs(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int drm_markbufs(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int drm_freebufs(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int drm_mapbufs(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int drm_order(unsigned long size); -/* 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); + /* DMA support (drm_dma.h) */ +extern int drm_dma_setup(struct drm_device *dev); +extern void drm_dma_takedown(struct drm_device *dev); +extern void drm_free_buffer(struct drm_device *dev, struct drm_buf * buf); +extern void drm_core_reclaim_buffers(struct drm_device *dev, + struct drm_file *filp); -void drm_vblank_pre_modeset(struct drm_device *dev, int crtc); -void drm_vblank_post_modeset(struct drm_device *dev, int crtc); -int drm_modeset_ctl(struct drm_device *dev, void *data, - struct drm_file *file_priv); + /* IRQ support (drm_irq.h) */ +extern int drm_control(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int drm_irq_install(struct drm_device *dev); +extern int drm_irq_uninstall(struct drm_device *dev); extern int drm_vblank_init(struct drm_device *dev, int num_crtcs); extern int drm_wait_vblank(struct drm_device *dev, void *data, @@ -1195,8 +1300,9 @@ extern int drm_vblank_wait(struct drm_device *dev, unsigned int *vbl_seq); extern u32 drm_vblank_count(struct drm_device *dev, int crtc); extern u32 drm_vblank_count_and_time(struct drm_device *dev, int crtc, struct timeval *vblanktime); +extern void drm_send_vblank_event(struct drm_device *dev, int crtc, + struct drm_pending_vblank_event *e); extern bool drm_handle_vblank(struct drm_device *dev, int crtc); -void drm_handle_vblank_events(struct drm_device *dev, int crtc); extern int drm_vblank_get(struct drm_device *dev, int crtc); extern void drm_vblank_put(struct drm_device *dev, int crtc); extern void drm_vblank_off(struct drm_device *dev, int crtc); @@ -1210,303 +1316,261 @@ extern int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, struct drm_crtc *refcrtc); extern void drm_calc_timestamping_constants(struct drm_crtc *crtc); -struct timeval ns_to_timeval(const int64_t nsec); -int64_t timeval_to_ns(const struct timeval *tv); +extern bool +drm_mode_parse_command_line_for_connector(const char *mode_option, + struct drm_connector *connector, + struct drm_cmdline_mode *mode); -/* 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); +extern struct drm_display_mode * +drm_mode_create_from_cmdline_mode(struct drm_device *dev, + struct drm_cmdline_mode *cmd); -/* 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); - -/* Cache management (drm_memory.c) */ -void drm_clflush_pages(vm_page_t *pages, unsigned long num_pages); -void drm_clflush_virt_range(char *addr, unsigned long length); - -/* 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); +/* Modesetting support */ +extern void drm_vblank_pre_modeset(struct drm_device *dev, int crtc); +extern void drm_vblank_post_modeset(struct drm_device *dev, int crtc); +extern int drm_modeset_ctl(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, + /* AGP/GART support (drm_agpsupport.h) */ +extern struct drm_agp_head *drm_agp_init(struct drm_device *dev); +extern int drm_agp_acquire(struct drm_device *dev); +extern int drm_agp_acquire_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int drm_agp_release(struct drm_device *dev); +extern int drm_agp_release_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int drm_agp_enable(struct drm_device *dev, struct drm_agp_mode mode); +extern int drm_agp_enable_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int drm_agp_info(struct drm_device *dev, struct drm_agp_info *info); +extern int drm_agp_info_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int drm_agp_alloc(struct drm_device *dev, struct drm_agp_buffer *request); +extern int drm_agp_alloc_ioctl(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_getcap(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, +extern int drm_agp_free(struct drm_device *dev, struct drm_agp_buffer *request); +extern int drm_agp_free_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); -int drm_getsareactx(struct drm_device *dev, void *data, +extern int drm_agp_unbind(struct drm_device *dev, struct drm_agp_binding *request); +extern int drm_agp_unbind_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int drm_agp_bind(struct drm_device *dev, struct drm_agp_binding *request); +extern int drm_agp_bind_ioctl(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); + /* Stub support (drm_stub.h) */ +extern int drm_setmaster_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int drm_dropmaster_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +struct drm_master *drm_master_create(struct drm_minor *minor); +extern struct drm_master *drm_master_get(struct drm_master *master); +extern void drm_master_put(struct drm_master **master); -/* Drawable support (drm_drawable.c) */ -void drm_drawable_free_all(struct drm_device *dev); +extern void drm_put_dev(struct drm_device *dev); +extern int drm_put_minor(struct drm_minor **minor); +extern void drm_unplug_dev(struct drm_device *dev); +extern unsigned int drm_debug; +extern unsigned int drm_notyet; -/* 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); +extern unsigned int drm_vblank_offdelay; +extern unsigned int drm_timestamp_precision; +extern unsigned int drm_timestamp_monotonic; -/* 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); +extern struct drm_local_map *drm_getsarea(struct drm_device *dev); -/* 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); +#ifdef FREEBSD_NOTYET +extern int drm_gem_prime_handle_to_fd(struct drm_device *dev, + struct drm_file *file_priv, uint32_t handle, uint32_t flags, + int *prime_fd); +extern int drm_gem_prime_fd_to_handle(struct drm_device *dev, + struct drm_file *file_priv, int prime_fd, uint32_t *handle); -/* 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); +extern int drm_prime_handle_to_fd_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +extern int drm_prime_fd_to_handle_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); - /* Stub support (drm_stub.h) */ -extern int drm_setmaster_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv); -extern int drm_dropmaster_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv); +extern int drm_prime_sg_to_page_addr_arrays(struct sg_table *sgt, vm_page_t *pages, + dma_addr_t *addrs, int max_pages); +extern struct sg_table *drm_prime_pages_to_sg(vm_page_t *pages, int nr_pages); +extern void drm_prime_gem_destroy(struct drm_gem_object *obj, struct sg_table *sg); -/* 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); +void drm_prime_init_file_private(struct drm_prime_file_private *prime_fpriv); +void drm_prime_destroy_file_private(struct drm_prime_file_private *prime_fpriv); +int drm_prime_add_imported_buf_handle(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf, uint32_t handle); +int drm_prime_lookup_imported_buf_handle(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf, uint32_t *handle); +void drm_prime_remove_imported_buf_handle(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf); -/* Graphics Execution Manager library functions (drm_gem.c) */ -int drm_gem_init(struct drm_device *dev); -void drm_gem_destroy(struct drm_device *dev); +int drm_prime_add_dma_buf(struct drm_device *dev, struct drm_gem_object *obj); +int drm_prime_lookup_obj(struct drm_device *dev, struct dma_buf *buf, + struct drm_gem_object **obj); +#endif /* FREEBSD_NOTYET */ -int drm_gem_close_ioctl(struct drm_device *dev, void *data, + /* Scatter Gather Support (drm_scatter.h) */ +extern void drm_sg_cleanup(struct drm_sg_mem * entry); +extern int drm_sg_alloc_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); -int drm_gem_flink_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv); -int drm_gem_open_ioctl(struct drm_device *dev, void *data, +extern int drm_sg_alloc(struct drm_device *dev, struct drm_scatter_gather * request); +extern int drm_sg_free(struct drm_device *dev, void *data, struct drm_file *file_priv); -int drm_gem_handle_create(struct drm_file *file_priv, - struct drm_gem_object *obj, - u32 *handlep); -int drm_gem_handle_delete(struct drm_file *file_priv, uint32_t handle); -void drm_gem_object_handle_reference(struct drm_gem_object *obj); -void drm_gem_object_handle_unreference(struct drm_gem_object *obj); -void drm_gem_object_handle_unreference_unlocked(struct drm_gem_object *obj); -void drm_gem_object_handle_free(struct drm_gem_object *obj); -void drm_gem_object_reference(struct drm_gem_object *obj); -void drm_gem_object_unreference(struct drm_gem_object *obj); -void drm_gem_object_unreference_unlocked(struct drm_gem_object *obj); + + /* ATI PCIGART support (ati_pcigart.h) */ +extern int drm_ati_pcigart_init(struct drm_device *dev, + struct drm_ati_pcigart_info * gart_info); +extern int drm_ati_pcigart_cleanup(struct drm_device *dev, + struct drm_ati_pcigart_info * gart_info); + +extern drm_dma_handle_t *drm_pci_alloc(struct drm_device *dev, size_t size, + size_t align, dma_addr_t maxaddr); +extern void __drm_pci_free(struct drm_device *dev, drm_dma_handle_t * dmah); +extern void drm_pci_free(struct drm_device *dev, drm_dma_handle_t * dmah); + +/* Graphics Execution Manager library functions (drm_gem.c) */ +int drm_gem_init(struct drm_device *dev); +void drm_gem_destroy(struct drm_device *dev); void drm_gem_object_release(struct drm_gem_object *obj); void drm_gem_object_free(struct drm_gem_object *obj); -int drm_gem_object_init(struct drm_device *dev, struct drm_gem_object *obj, - size_t size); -int drm_gem_private_object_init(struct drm_device *dev, - struct drm_gem_object *obj, size_t size); struct drm_gem_object *drm_gem_object_alloc(struct drm_device *dev, - size_t size); -struct drm_gem_object *drm_gem_object_lookup(struct drm_device *dev, - struct drm_file *file_priv, uint32_t handle); - -void drm_gem_open(struct drm_device *dev, struct drm_file *file_priv); -void drm_gem_release(struct drm_device *dev, struct drm_file *file_priv); - -int drm_gem_create_mmap_offset(struct drm_gem_object *obj); -void drm_gem_free_mmap_offset(struct drm_gem_object *obj); + size_t size); +int drm_gem_object_init(struct drm_device *dev, + struct drm_gem_object *obj, size_t size); +int drm_gem_private_object_init(struct drm_device *dev, + struct drm_gem_object *obj, size_t size); +void drm_gem_object_handle_free(struct drm_gem_object *obj); int drm_gem_mmap_single(struct drm_device *dev, vm_ooffset_t *offset, vm_size_t size, struct vm_object **obj_res, int nprot); void drm_gem_pager_dtr(void *obj); -struct ttm_bo_device; -int ttm_bo_mmap_single(struct ttm_bo_device *bdev, vm_ooffset_t *offset, - vm_size_t size, struct vm_object **obj_res, int nprot); -struct ttm_buffer_object; -void ttm_bo_release_mmap(struct ttm_buffer_object *bo); +#include <dev/drm2/drm_global.h> -void drm_device_lock_mtx(struct drm_device *dev); -void drm_device_unlock_mtx(struct drm_device *dev); -int drm_device_sleep_mtx(struct drm_device *dev, void *chan, int flags, - const char *msg, int timeout); -void drm_device_assert_mtx_locked(struct drm_device *dev); -void drm_device_assert_mtx_unlocked(struct drm_device *dev); - -void drm_device_lock_struct(struct drm_device *dev); -void drm_device_unlock_struct(struct drm_device *dev); -int drm_device_sleep_struct(struct drm_device *dev, void *chan, int flags, - const char *msg, int timeout); -void drm_device_assert_struct_locked(struct drm_device *dev); -void drm_device_assert_struct_unlocked(struct drm_device *dev); - -void drm_compat_locking_init(struct drm_device *dev); -void drm_sleep_locking_init(struct drm_device *dev); - -/* drm_modes.c */ -bool drm_mode_parse_command_line_for_connector(const char *mode_option, - struct drm_connector *connector, struct drm_cmdline_mode *mode); -struct drm_display_mode *drm_mode_create_from_cmdline_mode( - struct drm_device *dev, struct drm_cmdline_mode *cmd); - -/* drm_edid.c */ -u8 *drm_find_cea_extension(struct edid *edid); - -/* Inline replacements for drm_alloc and friends */ -static __inline__ void * -drm_alloc(size_t size, struct malloc_type *area) +static inline void +drm_gem_object_reference(struct drm_gem_object *obj) { - 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); + KASSERT(obj->refcount > 0, ("Dangling obj %p", obj)); + refcount_acquire(&obj->refcount); } -static __inline__ void * -drm_realloc(void *oldpt, size_t oldsize, size_t size, - struct malloc_type *area) +static inline void +drm_gem_object_unreference(struct drm_gem_object *obj) { - return reallocf(oldpt, size, area, M_NOWAIT); + + if (obj == NULL) + return; + if (refcount_release(&obj->refcount)) + drm_gem_object_free(obj); } -static __inline__ void -drm_free(void *pt, size_t size, struct malloc_type *area) +static inline void +drm_gem_object_unreference_unlocked(struct drm_gem_object *obj) { - free(pt, area); + if (obj != NULL) { + struct drm_device *dev = obj->dev; + DRM_LOCK(dev); + drm_gem_object_unreference(obj); + DRM_UNLOCK(dev); + } } -/* Inline replacements for DRM_IOREMAP macros */ -static __inline__ void -drm_core_ioremap_wc(struct drm_local_map *map, struct drm_device *dev) +int drm_gem_handle_create(struct drm_file *file_priv, + struct drm_gem_object *obj, + u32 *handlep); +int drm_gem_handle_delete(struct drm_file *filp, u32 handle); + +static inline void +drm_gem_object_handle_reference(struct drm_gem_object *obj) { - map->virtual = drm_ioremap_wc(dev, map); + drm_gem_object_reference(obj); + atomic_inc(&obj->handle_count); } -static __inline__ void -drm_core_ioremap(struct drm_local_map *map, struct drm_device *dev) + +static inline void +drm_gem_object_handle_unreference(struct drm_gem_object *obj) { - map->virtual = drm_ioremap(dev, map); + if (obj == NULL) + return; + + if (atomic_read(&obj->handle_count) == 0) + return; + /* + * Must bump handle count first as this may be the last + * ref, in which case the object would disappear before we + * checked for a name + */ + if (atomic_dec_and_test(&obj->handle_count)) + drm_gem_object_handle_free(obj); + drm_gem_object_unreference(obj); } -static __inline__ void -drm_core_ioremapfree(struct drm_local_map *map, struct drm_device *dev) + +static inline void +drm_gem_object_handle_unreference_unlocked(struct drm_gem_object *obj) { - if ( map->virtual && map->size ) - drm_ioremapfree(map); + if (obj == NULL) + return; + + if (atomic_read(&obj->handle_count) == 0) + return; + + /* + * Must bump handle count first as this may be the last + * ref, in which case the object would disappear before we + * checked for a name + */ + + if (atomic_dec_and_test(&obj->handle_count)) + drm_gem_object_handle_free(obj); + drm_gem_object_unreference_unlocked(obj); } -static __inline__ struct drm_local_map * -drm_core_findmap(struct drm_device *dev, unsigned long offset) -{ - drm_local_map_t *map; +void drm_gem_free_mmap_offset(struct drm_gem_object *obj); +int drm_gem_create_mmap_offset(struct drm_gem_object *obj); - DRM_LOCK_ASSERT(dev); - TAILQ_FOREACH(map, &dev->maplist, link) { - if (offset == (unsigned long)map->handle) - return map; - } +struct drm_gem_object *drm_gem_object_lookup(struct drm_device *dev, + struct drm_file *filp, + u32 handle); +int drm_gem_close_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +int drm_gem_flink_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +int drm_gem_open_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); +void drm_gem_open(struct drm_device *dev, struct drm_file *file_private); +void drm_gem_release(struct drm_device *dev, struct drm_file *file_private); + +extern void drm_core_ioremap(struct drm_local_map *map, struct drm_device *dev); +extern void drm_core_ioremap_wc(struct drm_local_map *map, struct drm_device *dev); +extern void drm_core_ioremapfree(struct drm_local_map *map, struct drm_device *dev); + +static __inline__ struct drm_local_map *drm_core_findmap(struct drm_device *dev, + unsigned int token) +{ + struct drm_map_list *_entry; + list_for_each_entry(_entry, &dev->maplist, head) + if (_entry->user_token == token) + return _entry->map; return NULL; } -static __inline__ void drm_core_dropmap(struct drm_map *map) +static __inline__ void drm_core_dropmap(struct drm_local_map *map) { } +extern int drm_fill_in_dev(struct drm_device *dev, + struct drm_driver *driver); +extern void drm_cancel_fill_in_dev(struct drm_device *dev); +int drm_get_minor(struct drm_device *dev, struct drm_minor **minor, int type); +/*@}*/ + +/* PCI section */ +int drm_pci_device_is_agp(struct drm_device *dev); +int drm_pci_device_is_pcie(struct drm_device *dev); + +extern int drm_get_pci_dev(device_t kdev, struct drm_device *dev, + struct drm_driver *driver); + #define DRM_PCIE_SPEED_25 1 #define DRM_PCIE_SPEED_50 2 #define DRM_PCIE_SPEED_80 4 @@ -1515,5 +1579,210 @@ extern int drm_pcie_get_speed_cap_mask(struct drm_device *dev, u32 *speed_mask); #define drm_can_sleep() (DRM_HZ & 1) -#endif /* __KERNEL__ */ -#endif /* _DRM_P_H_ */ +/* FreeBSD specific -- should be moved to drm_os_freebsd.h */ + +#define DRM_GEM_MAPPING_MASK (3ULL << 62) +#define DRM_GEM_MAPPING_KEY (2ULL << 62) /* Non-canonical address form */ +#define DRM_GEM_MAX_IDX 0x3fffff +#define DRM_GEM_MAPPING_IDX(o) (((o) >> 40) & DRM_GEM_MAX_IDX) +#define DRM_GEM_MAPPING_OFF(i) (((uint64_t)(i)) << 40) +#define DRM_GEM_MAPPING_MAPOFF(o) \ + ((o) & ~(DRM_GEM_MAPPING_OFF(DRM_GEM_MAX_IDX) | DRM_GEM_MAPPING_KEY)) + +SYSCTL_DECL(_hw_drm); + +#define DRM_DEV_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) +#define DRM_DEV_UID 0 +#define DRM_DEV_GID 0 + +#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_LOCK_SLEEP(dev, chan, flags, msg, timeout) \ + (sx_sleep((chan), &(dev)->dev_struct_lock, (flags), (msg), (timeout))) +#if defined(INVARIANTS) +#define DRM_LOCK_ASSERT(dev) sx_assert(&(dev)->dev_struct_lock, SA_XLOCKED) +#define DRM_UNLOCK_ASSERT(dev) sx_assert(&(dev)->dev_struct_lock, SA_UNLOCKED) +#else +#define DRM_LOCK_ASSERT(d) +#define DRM_UNLOCK_ASSERT(d) +#endif + +#define DRM_SYSCTL_HANDLER_ARGS (SYSCTL_HANDLER_ARGS) + +enum { + DRM_IS_NOT_AGP, + DRM_IS_AGP, + DRM_MIGHT_BE_AGP +}; + +#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 DRM_GET_PRIV_SAREA(_dev, _ctx, _map) do { \ + (_map) = (_dev)->context_sareas[_ctx]; \ +} while(0) + +/* Returns -errno to shared code */ +#define DRM_WAIT_ON( ret, queue, timeout, condition ) \ +for ( ret = 0 ; !ret && !(condition) ; ) { \ + DRM_UNLOCK(dev); \ + mtx_lock(&dev->irq_lock); \ + if (!(condition)) \ + ret = -mtx_sleep(&(queue), &dev->irq_lock, \ + PCATCH, "drmwtq", (timeout)); \ + if (ret == -ERESTART) \ + ret = -ERESTARTSYS; \ + mtx_unlock(&dev->irq_lock); \ + DRM_LOCK(dev); \ +} + +#define dev_err(dev, fmt, ...) \ + device_printf((dev), "error: " fmt, ## __VA_ARGS__) +#define dev_warn(dev, fmt, ...) \ + device_printf((dev), "warning: " fmt, ## __VA_ARGS__) +#define dev_info(dev, fmt, ...) \ + device_printf((dev), "info: " fmt, ## __VA_ARGS__) +#define dev_dbg(dev, fmt, ...) do { \ + if ((drm_debug& DRM_DEBUGBITS_KMS) != 0) { \ + device_printf((dev), "debug: " fmt, ## __VA_ARGS__); \ + } \ +} while (0) + +struct drm_msi_blacklist_entry +{ + int vendor; + int device; +}; + +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 */ +}; + +#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)) + +enum dmi_field { + DMI_NONE, + DMI_BIOS_VENDOR, + DMI_BIOS_VERSION, + DMI_BIOS_DATE, + DMI_SYS_VENDOR, + DMI_PRODUCT_NAME, + DMI_PRODUCT_VERSION, + DMI_PRODUCT_SERIAL, + DMI_PRODUCT_UUID, + DMI_BOARD_VENDOR, + DMI_BOARD_NAME, + DMI_BOARD_VERSION, + DMI_BOARD_SERIAL, + DMI_BOARD_ASSET_TAG, + DMI_CHASSIS_VENDOR, + DMI_CHASSIS_TYPE, + DMI_CHASSIS_VERSION, + DMI_CHASSIS_SERIAL, + DMI_CHASSIS_ASSET_TAG, + DMI_STRING_MAX, +}; + +struct dmi_strmatch { + unsigned char slot; + char substr[79]; +}; + +struct dmi_system_id { + int (*callback)(const struct dmi_system_id *); + const char *ident; + struct dmi_strmatch matches[4]; +}; +#define DMI_MATCH(a, b) {(a), (b)} +bool dmi_check_system(const struct dmi_system_id *); + +/* Device setup support (drm_drv.c) */ +int drm_probe_helper(device_t kdev, drm_pci_id_list_t *idlist); +int drm_attach_helper(device_t kdev, drm_pci_id_list_t *idlist, + struct drm_driver *driver); +int drm_generic_detach(device_t kdev); + +void drm_event_wakeup(struct drm_pending_event *e); + +int drm_add_busid_modesetting(struct drm_device *dev, + struct sysctl_ctx_list *ctx, struct sysctl_oid *top); + +/* 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); + +/* IRQ support (drm_irq.c) */ +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); + +/* AGP/PCI Express/GART support (drm_agpsupport.c) */ +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); + +/* sysctl support (drm_sysctl.h) */ +extern int drm_sysctl_init(struct drm_device *dev); +extern int drm_sysctl_cleanup(struct drm_device *dev); + +int drm_version(struct drm_device *dev, void *data, + struct drm_file *file_priv); + +/* consistent PCI memory functions (drm_pci.c) */ +int drm_pci_set_busid(struct drm_device *dev, struct drm_master *master); +int drm_pci_set_unique(struct drm_device *dev, struct drm_master *master, + struct drm_unique *u); +int drm_pci_agp_init(struct drm_device *dev); +int drm_pci_enable_msi(struct drm_device *dev); +void drm_pci_disable_msi(struct drm_device *dev); + +struct ttm_bo_device; +int ttm_bo_mmap_single(struct ttm_bo_device *bdev, vm_ooffset_t *offset, + vm_size_t size, struct vm_object **obj_res, int nprot); +struct ttm_buffer_object; +void ttm_bo_release_mmap(struct ttm_buffer_object *bo); + +#endif /* __KERNEL__ */ +#endif diff --git a/sys/dev/drm2/drm_agpsupport.c b/sys/dev/drm2/drm_agpsupport.c index 1f487e36d965..131a9ad9cc91 100644 --- a/sys/dev/drm2/drm_agpsupport.c +++ b/sys/dev/drm2/drm_agpsupport.c @@ -1,4 +1,12 @@ -/*- +/** + * \file drm_agpsupport.c + * DRM support for AGP/GART backend + * + * \author Rickard E. (Rik) Faith <faith@valinux.com> + * \author Gareth Hughes <gareth@valinux.com> + */ + +/* * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. * All Rights Reserved. @@ -21,64 +29,36 @@ * 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 <faith@valinux.com> - * Gareth Hughes <gareth@valinux.com> - * */ #include <sys/cdefs.h> __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/drm2/drmP.h> -#include <dev/agp/agpreg.h> -#include <dev/pci/pcireg.h> - -/* Returns 1 if AGP or 0 if not. */ -static int -drm_device_find_capability(struct drm_device *dev, int cap) -{ - - return (pci_find_cap(dev->device, cap, NULL) == 0); -} - -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)); -} +#if __OS_HAS_AGP -int drm_agp_info(struct drm_device * dev, struct drm_agp_info *info) +/** + * Get AGP information. + * + * \param inode device inode. + * \param file_priv DRM file private. + * \param cmd command. + * \param arg pointer to a (output) drm_agp_info structure. + * \return zero on success or a negative number on failure. + * + * Verifies the AGP device has been initialized and acquired and fills in the + * drm_agp_info structure with the information in drm_agp_head::agp_info. + */ +int drm_agp_info(struct drm_device *dev, struct drm_agp_info *info) { - struct agp_info *kern; + DRM_AGP_KERN *kern; if (!dev->agp || !dev->agp->acquired) - return EINVAL; + return -EINVAL; - kern = &dev->agp->info; - agp_get_info(dev->agp->agpdev, kern); + kern = &dev->agp->agp_info; + agp_get_info(dev->agp->bridge, kern); info->agp_version_major = 1; info->agp_version_minor = 0; info->mode = kern->ai_mode; @@ -92,343 +72,397 @@ int drm_agp_info(struct drm_device * dev, struct drm_agp_info *info) return 0; } +EXPORT_SYMBOL(drm_agp_info); + int drm_agp_info_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { + struct drm_agp_info *info = data; int err; - struct drm_agp_info info; - err = drm_agp_info(dev, &info); - if (err != 0) + err = drm_agp_info(dev, info); + if (err) 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) +/** + * Acquire the AGP device. + * + * \param dev DRM device that is to acquire AGP. + * \return zero on success or a negative number on failure. + * + * Verifies the AGP device hasn't been acquired before and calls + * \c agp_backend_acquire. + */ +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 (!dev->agp) + return -ENODEV; + if (dev->agp->acquired) + return -EBUSY; + retcode = agp_acquire(dev->agp->bridge); if (retcode) - return retcode; - + return -retcode; dev->agp->acquired = 1; return 0; } -int drm_agp_release_ioctl(struct drm_device *dev, void *data, +EXPORT_SYMBOL(drm_agp_acquire); + +/** + * Acquire the AGP device (ioctl). + * + * \param inode device inode. + * \param file_priv DRM file private. + * \param cmd command. + * \param arg user argument. + * \return zero on success or a negative number on failure. + * + * Verifies the AGP device hasn't been acquired before and calls + * \c agp_backend_acquire. + */ +int drm_agp_acquire_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { - - return drm_agp_release(dev); + return drm_agp_acquire((struct drm_device *) file_priv->minor->dev); } +/** + * Release the AGP device. + * + * \param dev DRM device that is to release AGP. + * \return zero on success or a negative number on failure. + * + * Verifies the AGP device has been acquired and calls \c agp_backend_release. + */ int drm_agp_release(struct drm_device * dev) { if (!dev->agp || !dev->agp->acquired) - return EINVAL; - agp_release(dev->agp->agpdev); + return -EINVAL; + agp_release(dev->agp->bridge); dev->agp->acquired = 0; return 0; } +EXPORT_SYMBOL(drm_agp_release); -int drm_agp_enable(struct drm_device *dev, struct drm_agp_mode mode) +int drm_agp_release_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) { + return drm_agp_release(dev); +} +/** + * Enable the AGP bus. + * + * \param dev DRM device that has previously acquired AGP. + * \param mode Requested AGP mode. + * \return zero on success or a negative number on failure. + * + * Verifies the AGP device has been acquired but not enabled, and calls + * \c agp_enable. + */ +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); + return -EINVAL; + + dev->agp->mode = mode.mode; + agp_enable(dev->agp->bridge, mode.mode); dev->agp->enabled = 1; return 0; } +EXPORT_SYMBOL(drm_agp_enable); + int drm_agp_enable_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { - struct drm_agp_mode mode; + struct drm_agp_mode *mode = data; - mode = *(struct drm_agp_mode *) data; - - return drm_agp_enable(dev, mode); + return drm_agp_enable(dev, *mode); } +/** + * Allocate AGP memory. + * + * \param inode device inode. + * \param file_priv file private pointer. + * \param cmd command. + * \param arg pointer to a drm_agp_buffer structure. + * \return zero on success or a negative number on failure. + * + * Verifies the AGP device is present and has been acquired, allocates the + * memory via agp_allocate_memory() and creates a drm_agp_mem entry for it. + */ 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 drm_agp_mem *entry; + DRM_AGP_MEM *memory; + unsigned long pages; + u32 type; struct agp_memory_info info; if (!dev->agp || !dev->agp->acquired) - return EINVAL; + return -EINVAL; + if (!(entry = malloc(sizeof(*entry), DRM_MEM_AGPLISTS, M_NOWAIT))) + return -ENOMEM; - entry = malloc(sizeof(*entry), DRM_MEM_AGPLISTS, M_NOWAIT | M_ZERO); - if (entry == NULL) - return ENOMEM; + memset(entry, 0, sizeof(*entry)); pages = (request->size + PAGE_SIZE - 1) / PAGE_SIZE; - type = (u_int32_t) request->type; - - DRM_UNLOCK(dev); - handle = drm_agp_allocate_memory(pages, type); - DRM_LOCK(dev); - if (handle == NULL) { + type = (u32) request->type; + if (!(memory = agp_alloc_memory(dev->agp->bridge, type, pages << PAGE_SHIFT))) { free(entry, DRM_MEM_AGPLISTS); - return ENOMEM; + 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); + entry->handle = (unsigned long)memory; + entry->memory = memory; + entry->bound = 0; + entry->pages = pages; + list_add(&entry->head, &dev->agp->memory); + + agp_memory_info(dev->agp->bridge, entry->memory, &info); - request->handle = (unsigned long) entry->handle; - request->physical = info.ami_physical; + request->handle = entry->handle; + request->physical = info.ami_physical; return 0; } +EXPORT_SYMBOL(drm_agp_alloc); + int drm_agp_alloc_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { - struct drm_agp_buffer request; - int retcode; + struct drm_agp_buffer *request = data; - request = *(struct drm_agp_buffer *) data; - - DRM_LOCK(dev); - retcode = drm_agp_alloc(dev, &request); - DRM_UNLOCK(dev); - - *(struct drm_agp_buffer *) data = request; - - return retcode; + return drm_agp_alloc(dev, request); } -static drm_agp_mem_t * drm_agp_lookup_entry(struct drm_device *dev, - void *handle) +/** + * Search for the AGP memory entry associated with a handle. + * + * \param dev DRM device structure. + * \param handle AGP memory handle. + * \return pointer to the drm_agp_mem structure associated with \p handle. + * + * Walks through drm_agp_head::memory until finding a matching handle. + */ +static struct drm_agp_mem *drm_agp_lookup_entry(struct drm_device * dev, + unsigned long handle) { - drm_agp_mem_t *entry; + struct drm_agp_mem *entry; - for (entry = dev->agp->memory; entry; entry = entry->next) { - if (entry->handle == handle) return entry; + list_for_each_entry(entry, &dev->agp->memory, head) { + if (entry->handle == handle) + return entry; } return NULL; } +/** + * Unbind AGP memory from the GATT (ioctl). + * + * \param inode device inode. + * \param file_priv DRM file private. + * \param cmd command. + * \param arg pointer to a drm_agp_binding structure. + * \return zero on success or a negative number on failure. + * + * Verifies the AGP device is present and acquired, looks-up the AGP memory + * entry and passes it to the unbind_agp() function. + */ int drm_agp_unbind(struct drm_device *dev, struct drm_agp_binding *request) { - drm_agp_mem_t *entry; - int retcode; + struct drm_agp_mem *entry; + int ret; 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(dev); - retcode = drm_agp_unbind_memory(entry->handle); - DRM_LOCK(dev); - - if (retcode == 0) + return -EINVAL; + if (!(entry = drm_agp_lookup_entry(dev, request->handle))) + return -EINVAL; + if (!entry->bound) + return -EINVAL; + ret = drm_unbind_agp(entry->memory); + if (ret == 0) entry->bound = 0; - - return retcode; + return ret; } +EXPORT_SYMBOL(drm_agp_unbind); + 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; + struct drm_agp_binding *request = data; - DRM_LOCK(dev); - retcode = drm_agp_unbind(dev, &request); - DRM_UNLOCK(dev); - - return retcode; + return drm_agp_unbind(dev, request); } +/** + * Bind AGP memory into the GATT (ioctl) + * + * \param inode device inode. + * \param file_priv DRM file private. + * \param cmd command. + * \param arg pointer to a drm_agp_binding structure. + * \return zero on success or a negative number on failure. + * + * Verifies the AGP device is present and has been acquired and that no memory + * is currently bound into the GATT. Looks-up the AGP memory entry and passes + * it to bind_agp() function. + */ int drm_agp_bind(struct 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; + struct drm_agp_mem *entry; + int retcode; + int page; + if (!dev->agp || !dev->agp->acquired) + return -EINVAL; + if (!(entry = drm_agp_lookup_entry(dev, request->handle))) + return -EINVAL; + if (entry->bound) + return -EINVAL; page = (request->offset + PAGE_SIZE - 1) / PAGE_SIZE; - - DRM_UNLOCK(dev); - retcode = drm_agp_bind_memory(entry->handle, page); - DRM_LOCK(dev); - if (retcode == 0) - entry->bound = dev->agp->base + (page << PAGE_SHIFT); - - return retcode; + if ((retcode = drm_bind_agp(entry->memory, page))) + return retcode; + entry->bound = dev->agp->base + (page << PAGE_SHIFT); + DRM_DEBUG("base = 0x%lx entry->bound = 0x%lx\n", + dev->agp->base, entry->bound); + return 0; } +EXPORT_SYMBOL(drm_agp_bind); + 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; + struct drm_agp_binding *request = data; - DRM_LOCK(dev); - retcode = drm_agp_bind(dev, &request); - DRM_UNLOCK(dev); - - return retcode; + return drm_agp_bind(dev, request); } +/** + * Free AGP memory (ioctl). + * + * \param inode device inode. + * \param file_priv DRM file private. + * \param cmd command. + * \param arg pointer to a drm_agp_buffer structure. + * \return zero on success or a negative number on failure. + * + * Verifies the AGP device is present and has been acquired and looks up the + * AGP memory entry. If the memory it's currently bound, unbind it via + * unbind_agp(). Frees it via free_agp() as well as the entry itself + * and unlinks from the doubly linked list it's inserted in. + */ int drm_agp_free(struct drm_device *dev, struct drm_agp_buffer *request) { - drm_agp_mem_t *entry; - + struct drm_agp_mem *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(dev); + return -EINVAL; + if (!(entry = drm_agp_lookup_entry(dev, request->handle))) + return -EINVAL; if (entry->bound) - drm_agp_unbind_memory(entry->handle); - drm_agp_free_memory(entry->handle); - DRM_LOCK(dev); + drm_unbind_agp(entry->memory); - free(entry, DRM_MEM_AGPLISTS); + list_del(&entry->head); + drm_free_agp(entry->memory, entry->pages); + free(entry, DRM_MEM_AGPLISTS); return 0; - } +EXPORT_SYMBOL(drm_agp_free); + + 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(dev); - retcode = drm_agp_free(dev, &request); - DRM_UNLOCK(dev); + struct drm_agp_buffer *request = data; - return retcode; + return drm_agp_free(dev, request); } -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) +/** + * Initialize the AGP resources. + * + * \return pointer to a drm_agp_head structure. + * + * Gets the drm_agp_t structure which is made available by the agpgart module + * via the inter_module_* functions. Creates and initializes a drm_agp_head + * structure. + */ +struct drm_agp_head *drm_agp_init(struct drm_device *dev) { - device_t agpdev; + struct drm_agp_head *head = NULL; - agpdev = DRM_AGP_FIND_DEVICE(); - if (!agpdev) + if (!(head = malloc(sizeof(*head), DRM_MEM_AGPLISTS, M_NOWAIT))) return NULL; - - return agp_alloc_memory(agpdev, type, pages << PAGE_SHIFT); + memset((void *)head, 0, sizeof(*head)); + head->bridge = agp_find_device(); + if (!head->bridge) { + free(head, DRM_MEM_AGPLISTS); + return NULL; + } else { + agp_get_info(head->bridge, &head->agp_info); + } + INIT_LIST_HEAD(&head->memory); + head->cant_use_aperture = 0; + head->base = head->agp_info.ai_aperture_base; + return head; } -int drm_agp_free_memory(void *handle) +#ifdef FREEBSD_NOTYET +/** + * Binds a collection of pages into AGP memory at the given offset, returning + * the AGP memory structure containing them. + * + * No reference is held on the pages during this time -- it is up to the + * caller to handle that. + */ +DRM_AGP_MEM * +drm_agp_bind_pages(struct drm_device *dev, + struct page **pages, + unsigned long num_pages, + uint32_t gtt_offset, + u32 type) { - device_t agpdev; + DRM_AGP_MEM *mem; + int ret, i; - agpdev = DRM_AGP_FIND_DEVICE(); - if (!agpdev || !handle) - return 0; + DRM_DEBUG("\n"); - agp_free_memory(agpdev, handle); - return 1; -} + mem = agp_allocate_memory(dev->agp->bridge, num_pages, + type); + if (mem == NULL) { + DRM_ERROR("Failed to allocate memory for %ld pages\n", + num_pages); + return NULL; + } -int drm_agp_bind_memory(void *handle, off_t start) -{ - device_t agpdev; + for (i = 0; i < num_pages; i++) + mem->pages[i] = pages[i]; + mem->page_count = num_pages; - agpdev = DRM_AGP_FIND_DEVICE(); - if (!agpdev || !handle) - return EINVAL; + mem->is_flushed = true; + ret = agp_bind_memory(mem, gtt_offset / PAGE_SIZE); + if (ret != 0) { + DRM_ERROR("Failed to bind AGP memory: %d\n", ret); + agp_free_memory(mem); + return NULL; + } - return agp_bind_memory(agpdev, handle, start * PAGE_SIZE); + return mem; } +EXPORT_SYMBOL(drm_agp_bind_pages); +#endif /* FREEBSD_NOTYET */ -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); -} +#endif /* __OS_HAS_AGP */ diff --git a/sys/dev/drm2/drm_atomic.h b/sys/dev/drm2/drm_atomic.h index eb86373f51b7..fd849227b661 100644 --- a/sys/dev/drm2/drm_atomic.h +++ b/sys/dev/drm2/drm_atomic.h @@ -36,12 +36,15 @@ __FBSDID("$FreeBSD$"); typedef u_int atomic_t; typedef uint64_t atomic64_t; -#define BITS_PER_LONG (sizeof(long) * NBBY) -#define BITS_TO_LONGS(x) howmany(x, BITS_PER_LONG) +#define NB_BITS_PER_LONG (sizeof(long) * NBBY) +#define BITS_TO_LONGS(x) howmany(x, NB_BITS_PER_LONG) #define atomic_read(p) (*(volatile u_int *)(p)) #define atomic_set(p, v) do { *(u_int *)(p) = (v); } while (0) +#define atomic64_read(p) atomic_load_acq_64(p) +#define atomic64_set(p, v) atomic_store_rel_64(p, v) + #define atomic_add(v, p) atomic_add_int(p, v) #define atomic_sub(v, p) atomic_subtract_int(p, v) #define atomic_inc(p) atomic_add(1, p) @@ -60,8 +63,8 @@ typedef uint64_t atomic64_t; #define atomic_xchg(p, v) atomic_swap_int(p, v) #define atomic64_xchg(p, v) atomic_swap_64(p, v) -#define __bit_word(b) ((b) / BITS_PER_LONG) -#define __bit_mask(b) (1UL << (b) % BITS_PER_LONG) +#define __bit_word(b) ((b) / NB_BITS_PER_LONG) +#define __bit_mask(b) (1UL << (b) % NB_BITS_PER_LONG) #define __bit_addr(p, b) ((volatile u_long *)(p) + __bit_word(b)) #define clear_bit(b, p) \ @@ -70,17 +73,21 @@ typedef uint64_t atomic64_t; atomic_set_long(__bit_addr(p, b), __bit_mask(b)) #define test_bit(b, p) \ ((*__bit_addr(p, b) & __bit_mask(b)) != 0) +#define test_and_set_bit(b, p) \ + (atomic_xchg((p), 1) != b) +#define cmpxchg(ptr, old, new) \ + (atomic_cmpset_int((volatile u_int *)(ptr),(old),(new)) ? (old) : (0)) static __inline u_long find_first_zero_bit(const u_long *p, u_long max) { u_long i, n; - KASSERT(max % BITS_PER_LONG == 0, ("invalid bitmap size %lu", max)); - for (i = 0; i < max / BITS_PER_LONG; i++) { + KASSERT(max % NB_BITS_PER_LONG == 0, ("invalid bitmap size %lu", max)); + for (i = 0; i < max / NB_BITS_PER_LONG; i++) { n = ~p[i]; if (n != 0) - return (i * BITS_PER_LONG + ffsl(n) - 1); + return (i * NB_BITS_PER_LONG + ffsl(n) - 1); } return (max); } diff --git a/sys/dev/drm2/drm_auth.c b/sys/dev/drm2/drm_auth.c index 69acff9df5a1..f377c00b0fc4 100644 --- a/sys/dev/drm2/drm_auth.c +++ b/sys/dev/drm2/drm_auth.c @@ -1,4 +1,14 @@ -/*- +/** + * \file drm_auth.c + * IOCTLs for authentication + * + * \author Rickard E. (Rik) Faith <faith@valinux.com> + * \author Gareth Hughes <gareth@valinux.com> + */ + +/* + * Created: Tue Feb 2 08:37:54 1999 by faith@valinux.com + * * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. * All Rights Reserved. @@ -21,121 +31,118 @@ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: - * Rickard E. (Rik) Faith <faith@valinux.com> - * Gareth Hughes <gareth@valinux.com> - * */ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); -/** @file drm_auth.c - * Implementation of the get/authmagic ioctls implementing the authentication - * scheme between the master and clients. - */ - #include <dev/drm2/drmP.h> -static int drm_hash_magic(drm_magic_t magic) -{ - return magic & (DRM_HASH_SIZE-1); -} +static struct mtx drm_magic_lock; /** - * Returns the file private associated with the given magic number. + * Find the file with the given magic number. + * + * \param dev DRM device. + * \param magic magic number. + * + * Searches in drm_device::magiclist within all files with the same hash key + * the one with matching magic number, while holding the drm_device::struct_mutex + * lock. */ -static struct drm_file *drm_find_file(struct drm_device *dev, drm_magic_t magic) +static struct drm_file *drm_find_file(struct drm_master *master, drm_magic_t magic) { - drm_magic_entry_t *pt; - int hash = drm_hash_magic(magic); + struct drm_file *retval = NULL; + struct drm_magic_entry *pt; + struct drm_hash_item *hash; + struct drm_device *dev = master->minor->dev; - DRM_LOCK_ASSERT(dev); - - for (pt = dev->magiclist[hash].head; pt; pt = pt->next) { - if (pt->magic == magic) { - return pt->priv; - } + DRM_LOCK(dev); + if (!drm_ht_find_item(&master->magiclist, (unsigned long)magic, &hash)) { + pt = drm_hash_entry(hash, struct drm_magic_entry, hash_item); + retval = pt->priv; } - - return NULL; + DRM_UNLOCK(dev); + return retval; } /** - * Inserts the given magic number into the hash table of used magic number - * lists. + * Adds a magic number. + * + * \param dev DRM device. + * \param priv file private data. + * \param magic magic number. + * + * Creates a drm_magic_entry structure and appends to the linked list + * associated the magic number hash key in drm_device::magiclist, while holding + * the drm_device::struct_mutex lock. */ -static int drm_add_magic(struct drm_device *dev, struct drm_file *priv, +static int drm_add_magic(struct drm_master *master, struct drm_file *priv, drm_magic_t magic) { - int hash; - drm_magic_entry_t *entry; - + struct drm_magic_entry *entry; + struct drm_device *dev = master->minor->dev; DRM_DEBUG("%d\n", magic); - DRM_LOCK_ASSERT(dev); - - hash = drm_hash_magic(magic); entry = malloc(sizeof(*entry), DRM_MEM_MAGIC, M_ZERO | M_NOWAIT); if (!entry) - return ENOMEM; - entry->magic = magic; - entry->priv = priv; - entry->next = NULL; - - if (dev->magiclist[hash].tail) { - dev->magiclist[hash].tail->next = entry; - dev->magiclist[hash].tail = entry; - } else { - dev->magiclist[hash].head = entry; - dev->magiclist[hash].tail = entry; - } + return -ENOMEM; + entry->priv = priv; + entry->hash_item.key = (unsigned long)magic; + DRM_LOCK(dev); + drm_ht_insert_item(&master->magiclist, &entry->hash_item); + list_add_tail(&entry->head, &master->magicfree); + DRM_UNLOCK(dev); return 0; } /** - * Removes the given magic number from the hash table of used magic number - * lists. + * Remove a magic number. + * + * \param dev DRM device. + * \param magic magic number. + * + * Searches and unlinks the entry in drm_device::magiclist with the magic + * number hash key, while holding the drm_device::struct_mutex lock. */ -static int drm_remove_magic(struct drm_device *dev, drm_magic_t magic) +int drm_remove_magic(struct drm_master *master, drm_magic_t magic) { - drm_magic_entry_t *prev = NULL; - drm_magic_entry_t *pt; - int hash; - - DRM_LOCK_ASSERT(dev); + struct drm_magic_entry *pt; + struct drm_hash_item *hash; + struct drm_device *dev = master->minor->dev; DRM_DEBUG("%d\n", magic); - hash = drm_hash_magic(magic); - - for (pt = dev->magiclist[hash].head; pt; prev = pt, pt = pt->next) { - if (pt->magic == magic) { - if (dev->magiclist[hash].head == pt) { - dev->magiclist[hash].head = pt->next; - } - if (dev->magiclist[hash].tail == pt) { - dev->magiclist[hash].tail = prev; - } - if (prev) { - prev->next = pt->next; - } - free(pt, DRM_MEM_MAGIC); - return 0; - } + + DRM_LOCK(dev); + if (drm_ht_find_item(&master->magiclist, (unsigned long)magic, &hash)) { + DRM_UNLOCK(dev); + return -EINVAL; } + pt = drm_hash_entry(hash, struct drm_magic_entry, hash_item); + drm_ht_remove_item(&master->magiclist, hash); + list_del(&pt->head); + DRM_UNLOCK(dev); + + free(pt, DRM_MEM_MAGIC); - return EINVAL; + return 0; } /** - * Called by the client, this returns a unique magic number to be authorized - * by the master. + * Get a unique magic number (ioctl). + * + * \param inode device inode. + * \param file_priv DRM file private. + * \param cmd command. + * \param arg pointer to a resulting drm_auth structure. + * \return zero on success, or a negative number on failure. * - * The master may use its own knowledge of the client (such as the X - * connection that the magic is passed over) to determine if the magic number - * should be authenticated. + * If there is a magic number in drm_file::magic then use it, otherwise + * searches an unique non-zero magic number and add it associating it with \p + * file_priv. + * This ioctl needs protection by the drm_global_mutex, which protects + * struct drm_file::magic and struct drm_magic_entry::priv. */ int drm_getmagic(struct drm_device *dev, void *data, struct drm_file *file_priv) { @@ -146,18 +153,15 @@ int drm_getmagic(struct drm_device *dev, void *data, struct drm_file *file_priv) if (file_priv->magic) { auth->magic = file_priv->magic; } else { - DRM_LOCK(dev); do { - int old = sequence; - - auth->magic = old+1; - - if (!atomic_cmpset_int(&sequence, old, auth->magic)) - continue; - } while (drm_find_file(dev, auth->magic)); + mtx_lock(&drm_magic_lock); + if (!sequence) + ++sequence; /* reserve 0 */ + auth->magic = sequence++; + mtx_unlock(&drm_magic_lock); + } while (drm_find_file(file_priv->master, auth->magic)); file_priv->magic = auth->magic; - drm_add_magic(dev, file_priv, auth->magic); - DRM_UNLOCK(dev); + drm_add_magic(file_priv->master, file_priv, auth->magic); } DRM_DEBUG("%u\n", auth->magic); @@ -166,25 +170,47 @@ int drm_getmagic(struct drm_device *dev, void *data, struct drm_file *file_priv) } /** - * Marks the client associated with the given magic number as authenticated. + * Authenticate with a magic. + * + * \param inode device inode. + * \param file_priv DRM file private. + * \param cmd command. + * \param arg pointer to a drm_auth structure. + * \return zero if authentication successed, or a negative number otherwise. + * + * Checks if \p file_priv is associated with the magic number passed in \arg. + * This ioctl needs protection by the drm_global_mutex, which protects + * struct drm_file::magic and struct drm_magic_entry::priv. */ int drm_authmagic(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_auth *auth = data; - struct drm_file *priv; + struct drm_file *file; DRM_DEBUG("%u\n", auth->magic); - - DRM_LOCK(dev); - priv = drm_find_file(dev, auth->magic); - if (priv != NULL) { - priv->authenticated = 1; - drm_remove_magic(dev, auth->magic); - DRM_UNLOCK(dev); + if ((file = drm_find_file(file_priv->master, auth->magic))) { + file->authenticated = 1; + drm_remove_magic(file_priv->master, auth->magic); return 0; - } else { - DRM_UNLOCK(dev); - return EINVAL; } + return -EINVAL; +} + +static int +drm_magic_init(void *arg) +{ + + mtx_init(&drm_magic_lock, "drm_getmagic__lock", NULL, MTX_DEF); + return (0); +} + +static void +drm_magic_fini(void *arg) +{ + + mtx_destroy(&drm_magic_lock); } + +SYSINIT(drm_magic_init, SI_SUB_KLD, SI_ORDER_MIDDLE, drm_magic_init, NULL); +SYSUNINIT(drm_magic_fini, SI_SUB_KLD, SI_ORDER_MIDDLE, drm_magic_fini, NULL); diff --git a/sys/dev/drm2/drm_buffer.c b/sys/dev/drm2/drm_buffer.c index cdc91a4a509c..f151a61af3e9 100644 --- a/sys/dev/drm2/drm_buffer.c +++ b/sys/dev/drm2/drm_buffer.c @@ -92,6 +92,7 @@ error_out: free(*buf, DRM_MEM_DRIVER); return -ENOMEM; } +EXPORT_SYMBOL(drm_buffer_alloc); /** * Copy the user data to the begin of the buffer and reset the processing @@ -128,6 +129,7 @@ int drm_buffer_copy_from_user(struct drm_buffer *buf, buf->iterator = 0; return 0; } +EXPORT_SYMBOL(drm_buffer_copy_from_user); /** * Free the drm buffer object @@ -145,6 +147,7 @@ void drm_buffer_free(struct drm_buffer *buf) free(buf, DRM_MEM_DRIVER); } } +EXPORT_SYMBOL(drm_buffer_free); /** * Read an object from buffer that may be split to multiple parts. If object @@ -181,3 +184,4 @@ void *drm_buffer_read_object(struct drm_buffer *buf, drm_buffer_advance(buf, objsize); return obj; } +EXPORT_SYMBOL(drm_buffer_read_object); diff --git a/sys/dev/drm2/drm_bufs.c b/sys/dev/drm2/drm_bufs.c index 410c88fa65e3..135946685cba 100644 --- a/sys/dev/drm2/drm_bufs.c +++ b/sys/dev/drm2/drm_bufs.c @@ -1,4 +1,14 @@ -/*- +/** + * \file drm_bufs.c + * Generic buffer template + * + * \author Rickard E. (Rik) Faith <faith@valinux.com> + * \author Gareth Hughes <gareth@valinux.com> + */ + +/* + * Created: Thu Nov 23 03:10:50 2000 by gareth@valinux.com + * * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas. * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. * All Rights Reserved. @@ -21,19 +31,13 @@ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: - * Rickard E. (Rik) Faith <faith@valinux.com> - * Gareth Hughes <gareth@valinux.com> - * */ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); -/** @file drm_bufs.c - * Implementation of the ioctls for setup of DRM mappings and DMA buffers. - */ +#include <sys/param.h> +#include <sys/shm.h> #include <dev/pci/pcireg.h> @@ -48,8 +52,6 @@ static int drm_alloc_resource(struct drm_device *dev, int resource) struct resource *res; int rid; - DRM_LOCK_ASSERT(dev); - if (resource >= DRM_MAX_PCI_RESOURCE) { DRM_ERROR("Resource %d too large\n", resource); return 1; @@ -59,11 +61,9 @@ static int drm_alloc_resource(struct drm_device *dev, int resource) return 0; } - DRM_UNLOCK(dev); rid = PCIR_BAR(resource); - res = bus_alloc_resource_any(dev->device, SYS_RES_MEMORY, &rid, + res = bus_alloc_resource_any(dev->dev, SYS_RES_MEMORY, &rid, RF_SHAREABLE); - DRM_LOCK(dev); if (res == NULL) { DRM_ERROR("Couldn't find resource 0x%x\n", resource); return 1; @@ -80,120 +80,275 @@ static int drm_alloc_resource(struct drm_device *dev, int resource) unsigned long drm_get_resource_start(struct drm_device *dev, unsigned int resource) { + unsigned long start; + + mtx_lock(&dev->pcir_lock); + if (drm_alloc_resource(dev, resource) != 0) return 0; - return rman_get_start(dev->pcir[resource]); + start = rman_get_start(dev->pcir[resource]); + + mtx_unlock(&dev->pcir_lock); + + return (start); } unsigned long drm_get_resource_len(struct drm_device *dev, unsigned int resource) { + unsigned long len; + + mtx_lock(&dev->pcir_lock); + if (drm_alloc_resource(dev, resource) != 0) return 0; - return rman_get_size(dev->pcir[resource]); + len = rman_get_size(dev->pcir[resource]); + + mtx_unlock(&dev->pcir_lock); + + return (len); +} + +static struct drm_map_list *drm_find_matching_map(struct drm_device *dev, + struct drm_local_map *map) +{ + struct drm_map_list *entry; + list_for_each_entry(entry, &dev->maplist, head) { + /* + * Because the kernel-userspace ABI is fixed at a 32-bit offset + * while PCI resources may live above that, we only compare the + * lower 32 bits of the map offset for maps of type + * _DRM_FRAMEBUFFER or _DRM_REGISTERS. + * It is assumed that if a driver have more than one resource + * of each type, the lower 32 bits are different. + */ + if (!entry->map || + map->type != entry->map->type || + entry->master != dev->primary->master) + continue; + switch (map->type) { + case _DRM_SHM: + if (map->flags != _DRM_CONTAINS_LOCK) + break; + return entry; + case _DRM_REGISTERS: + case _DRM_FRAME_BUFFER: + if ((entry->map->offset & 0xffffffff) == + (map->offset & 0xffffffff)) + return entry; + default: /* Make gcc happy */ + ; + } + if (entry->map->offset == map->offset) + return entry; + } + + return NULL; +} + +static int drm_map_handle(struct drm_device *dev, struct drm_hash_item *hash, + unsigned long user_token, int hashed_handle, int shm) +{ + int use_hashed_handle, shift; + unsigned long add; + +#if (BITS_PER_LONG == 64) + use_hashed_handle = ((user_token & 0xFFFFFFFF00000000UL) || hashed_handle); +#elif (BITS_PER_LONG == 32) + use_hashed_handle = hashed_handle; +#else +#error Unsupported long size. Neither 64 nor 32 bits. +#endif + + if (!use_hashed_handle) { + int ret; + hash->key = user_token >> PAGE_SHIFT; + ret = drm_ht_insert_item(&dev->map_hash, hash); + if (ret != -EINVAL) + return ret; + } + + shift = 0; + add = DRM_MAP_HASH_OFFSET >> PAGE_SHIFT; + if (shm && (SHMLBA > PAGE_SIZE)) { + int bits = ilog2(SHMLBA >> PAGE_SHIFT) + 1; + + /* For shared memory, we have to preserve the SHMLBA + * bits of the eventual vma->vm_pgoff value during + * mmap(). Otherwise we run into cache aliasing problems + * on some platforms. On these platforms, the pgoff of + * a mmap() request is used to pick a suitable virtual + * address for the mmap() region such that it will not + * cause cache aliasing problems. + * + * Therefore, make sure the SHMLBA relevant bits of the + * hash value we use are equal to those in the original + * kernel virtual address. + */ + shift = bits; + add |= ((user_token >> PAGE_SHIFT) & ((1UL << bits) - 1UL)); + } + + return drm_ht_just_insert_please(&dev->map_hash, hash, + user_token, 32 - PAGE_SHIFT - 3, + shift, add); } -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) +/** + * Core function to create a range of memory available for mapping by a + * non-root process. + * + * Adjusts the memory offset to its absolute value according to the mapping + * type. Adds the map to the map list drm_device::maplist. Adds MTRR's where + * applicable and if supported by the kernel. + */ +static int drm_addmap_core(struct drm_device * dev, resource_size_t offset, + unsigned int size, enum drm_map_type type, + enum drm_map_flags flags, + struct drm_map_list ** maplist) { - drm_local_map_t *map; + struct drm_local_map *map; + struct drm_map_list *list; + drm_dma_handle_t *dmah; + unsigned long user_token; + int ret; int align; - /*drm_agp_mem_t *entry; - int valid;*/ + + map = malloc(sizeof(*map), DRM_MEM_MAPS, M_NOWAIT); + if (!map) + return -ENOMEM; + + map->offset = offset; + map->size = size; + map->flags = flags; + map->type = type; /* 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; + if ((map->flags & _DRM_REMOVABLE) && map->type != _DRM_SHM) { + free(map, DRM_MEM_MAPS); + return -EINVAL; } + DRM_DEBUG("offset = 0x%08llx, size = 0x%08lx, type = %d\n", + (unsigned long long)map->offset, map->size, map->type); - 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. + /* page-align _DRM_SHM maps. They are allocated here so there is no security + * hole created by that and it works around various broken drivers that use + * a non-aligned quantity to map the SAREA. --BenH */ - 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(dev); + if (map->type == _DRM_SHM) + map->size = PAGE_ALIGN(map->size); - /* Allocate a new map structure, fill it in, and do any type-specific - * initialization necessary. + /* + * FreeBSD port note: FreeBSD's PAGE_MASK is the inverse of + * Linux's one. That's why the test below doesn't inverse the + * constant. */ - map = malloc(sizeof(*map), DRM_MEM_MAPS, M_ZERO | M_NOWAIT); - if (!map) { - DRM_LOCK(dev); - return ENOMEM; + if ((map->offset & ((resource_size_t)PAGE_MASK)) || (map->size & (PAGE_MASK))) { + free(map, DRM_MEM_MAPS); + return -EINVAL; } - - 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); + map->mtrr = -1; + map->handle = NULL; 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; +#ifdef __linux__ +#if !defined(__sparc__) && !defined(__alpha__) && !defined(__ia64__) && !defined(__powerpc64__) && !defined(__x86_64__) && !defined(__arm__) + if (map->offset + (map->size-1) < map->offset || + map->offset < virt_to_phys(high_memory)) { + kfree(map); + return -EINVAL; + } +#endif +#endif + /* Some drivers preinitialize some maps, without the X Server + * needing to be aware of it. Therefore, we just return success + * when the server tries to create a duplicate map. + */ + list = drm_find_matching_map(dev, map); + if (list != NULL) { + if (list->map->size != map->size) { + DRM_DEBUG("Matching maps of type %d with " + "mismatched sizes, (%ld vs %ld)\n", + map->type, map->size, + list->map->size); + list->map->size = map->size; + } + + free(map, DRM_MEM_MAPS); + *maplist = list; + return 0; + } + + if (drm_core_has_MTRR(dev)) { + if (map->type == _DRM_FRAME_BUFFER || + (map->flags & _DRM_WRITE_COMBINING)) { + if (drm_mtrr_add( + map->offset, map->size, + DRM_MTRR_WC) == 0) + map->mtrr = 1; + } + } + if (map->type == _DRM_REGISTERS) { + drm_core_ioremap(map, dev); + if (!map->handle) { + free(map, DRM_MEM_MAPS); + return -ENOMEM; + } + } + break; case _DRM_SHM: - map->virtual = malloc(map->size, DRM_MEM_MAPS, M_NOWAIT); + list = drm_find_matching_map(dev, map); + if (list != NULL) { + if(list->map->size != map->size) { + DRM_DEBUG("Matching maps of type %d with " + "mismatched sizes, (%ld vs %ld)\n", + map->type, map->size, list->map->size); + list->map->size = map->size; + } + + free(map, DRM_MEM_MAPS); + *maplist = list; + return 0; + } + map->handle = 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) { + map->size, drm_order(map->size), map->handle); + if (!map->handle) { free(map, DRM_MEM_MAPS); - DRM_LOCK(dev); - return ENOMEM; + return -ENOMEM; } - map->offset = (unsigned long)map->virtual; + map->offset = (unsigned long)map->handle; if (map->flags & _DRM_CONTAINS_LOCK) { /* Prevent a 2nd X Server from creating a 2nd lock */ - DRM_LOCK(dev); - if (dev->lock.hw_lock != NULL) { - DRM_UNLOCK(dev); - free(map->virtual, DRM_MEM_MAPS); + if (dev->primary->master->lock.hw_lock != NULL) { + free(map->handle, DRM_MEM_MAPS); free(map, DRM_MEM_MAPS); - return EBUSY; + return -EBUSY; } - dev->lock.hw_lock = map->virtual; /* Pointer to lock */ - DRM_UNLOCK(dev); + dev->sigdata.lock = dev->primary->master->lock.hw_lock = map->handle; /* Pointer to lock */ } break; - case _DRM_AGP: - /*valid = 0;*/ + case _DRM_AGP: { + struct drm_agp_mem *entry; + int valid = 0; + + if (!drm_core_has_AGP(dev)) { + free(map, DRM_MEM_MAPS); + return -EINVAL; + } +#ifdef __linux__ +#ifdef __alpha__ + map->offset += dev->hose->mem_space->start; +#endif +#endif /* 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 @@ -202,128 +357,202 @@ int drm_addmap(struct drm_device * dev, unsigned long offset, */ if (map->offset < dev->agp->base || map->offset > dev->agp->base + - dev->agp->info.ai_aperture_size - 1) { + dev->agp->agp_info.ai_aperture_size * 1024 * 1024 - 1) { map->offset += dev->agp->base; } - map->mtrr = dev->agp->mtrr; /* for getmap */ - /*for (entry = dev->agp->memory; entry; entry = entry->next) { + map->mtrr = dev->agp->agp_mtrr; /* for getmap */ + + /* This assumes the DRM is in total control of AGP space. + * It's not always the case as AGP can be in the control + * of user space (i.e. i810 driver). So this loop will get + * skipped and we double check that dev->agp->memory is + * actually set as well as being invalid before EPERM'ing + */ + list_for_each_entry(entry, &dev->agp->memory, head) { if ((map->offset >= entry->bound) && - (map->offset + map->size <= - entry->bound + entry->pages * PAGE_SIZE)) { + (map->offset + map->size <= entry->bound + entry->pages * PAGE_SIZE)) { valid = 1; break; } } - if (!valid) { + if (!list_empty(&dev->agp->memory) && !valid) { free(map, DRM_MEM_MAPS); - DRM_LOCK(dev); - return EACCES; - }*/ + return -EPERM; + } + DRM_DEBUG("AGP offset = 0x%08llx, size = 0x%08lx\n", + (unsigned long long)map->offset, map->size); + + break; + } + case _DRM_GEM: + DRM_ERROR("tried to addmap GEM object\n"); break; case _DRM_SCATTER_GATHER: if (!dev->sg) { free(map, DRM_MEM_MAPS); - DRM_LOCK(dev); - return EINVAL; + return -EINVAL; } - map->virtual = (void *)(dev->sg->vaddr + offset); - map->offset = dev->sg->vaddr + offset; + map->handle = (void *)(dev->sg->vaddr + offset); + map->offset += dev->sg->vaddr; 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. - */ + /* dma_addr_t is 64bit on i386 with CONFIG_HIGHMEM64G, + * As we're limiting the address to 2^32-1 (or less), + * casting it down to 32 bits is no problem, but we + * need to point to a 64bit variable first. */ 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) { + dmah = drm_pci_alloc(dev, map->size, align, BUS_SPACE_MAXADDR); + if (!dmah) { free(map, DRM_MEM_MAPS); - DRM_LOCK(dev); - return ENOMEM; + return -ENOMEM; } - map->virtual = map->dmah->vaddr; - map->offset = map->dmah->busaddr; + map->handle = dmah->vaddr; + map->offset = dmah->busaddr; + map->dmah = dmah; break; default: - DRM_ERROR("Bad map type %d\n", map->type); free(map, DRM_MEM_MAPS); - DRM_LOCK(dev); - return EINVAL; + return -EINVAL; + } + + list = malloc(sizeof(*list), DRM_MEM_MAPS, M_ZERO | M_NOWAIT); + if (!list) { + if (map->type == _DRM_REGISTERS) + drm_core_ioremapfree(map, dev); + free(map, DRM_MEM_MAPS); + return -EINVAL; } + list->map = map; DRM_LOCK(dev); - TAILQ_INSERT_TAIL(&dev->maplist, map, link); + list_add(&list->head, &dev->maplist); + + /* Assign a 32-bit handle */ + /* We do it here so that dev->struct_mutex protects the increment */ + user_token = (map->type == _DRM_SHM) ? (unsigned long)map->handle : + map->offset; + ret = drm_map_handle(dev, &list->hash, user_token, 0, + (map->type == _DRM_SHM)); + if (ret) { + if (map->type == _DRM_REGISTERS) + drm_core_ioremapfree(map, dev); + free(map, DRM_MEM_MAPS); + free(list, DRM_MEM_MAPS); + DRM_UNLOCK(dev); + return ret; + } -done: - /* Jumped to, with lock held, when a kernel map is found. */ + list->user_token = list->hash.key << PAGE_SHIFT; + DRM_UNLOCK(dev); - DRM_DEBUG("Added map %d 0x%lx/0x%lx\n", map->type, map->offset, - map->size); + if (!(map->flags & _DRM_DRIVER)) + list->master = dev->primary->master; + *maplist = list; + return 0; + } - *map_ptr = map; +int drm_addmap(struct drm_device * dev, resource_size_t offset, + unsigned int size, enum drm_map_type type, + enum drm_map_flags flags, struct drm_local_map ** map_ptr) +{ + struct drm_map_list *list; + int rc; - return 0; + rc = drm_addmap_core(dev, offset, size, type, flags, &list); + if (!rc) + *map_ptr = list->map; + return rc; } +EXPORT_SYMBOL(drm_addmap); + +/** + * Ioctl to specify a range of memory that is available for mapping by a + * non-root process. + * + * \param inode device inode. + * \param file_priv DRM file private. + * \param cmd command. + * \param arg pointer to a drm_map structure. + * \return zero on success or a negative value on error. + * + */ 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; + struct drm_map *map = data; + struct drm_map_list *maplist; int err; - if (!(dev->flags & (FREAD|FWRITE))) - return EACCES; /* Require read/write */ + if (!(DRM_SUSER(DRM_CURPROC) || map->type == _DRM_AGP || map->type == _DRM_SHM)) + return -EPERM; - if (!DRM_SUSER(DRM_CURPROC) && request->type != _DRM_AGP) - return EACCES; + err = drm_addmap_core(dev, map->offset, map->size, map->type, + map->flags, &maplist); - DRM_LOCK(dev); - err = drm_addmap(dev, request->offset, request->size, request->type, - request->flags, &map); - DRM_UNLOCK(dev); - if (err != 0) + if (err) 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; - + /* avoid a warning on 64-bit, this casting isn't very nice, but the API is set so too late */ + map->handle = (void *)(unsigned long)maplist->user_token; return 0; } -void drm_rmmap(struct drm_device *dev, drm_local_map_t *map) +/** + * Remove a map private from list and deallocate resources if the mapping + * isn't in use. + * + * Searches the map on drm_device::maplist, removes it from the list, see if + * its being used, and free any associate resource (such as MTRR's) if it's not + * being on use. + * + * \sa drm_addmap + */ +int drm_rmmap_locked(struct drm_device *dev, struct drm_local_map *map) { - DRM_LOCK_ASSERT(dev); - - if (map == NULL) - return; + struct drm_map_list *r_list = NULL, *list_t; + int found = 0; + struct drm_master *master; + + /* Find the list entry for the map and remove it */ + list_for_each_entry_safe(r_list, list_t, &dev->maplist, head) { + if (r_list->map == map) { + master = r_list->master; + list_del(&r_list->head); + drm_ht_remove_key(&dev->map_hash, + r_list->user_token >> PAGE_SHIFT); + free(r_list, DRM_MEM_MAPS); + found = 1; + break; + } + } - TAILQ_REMOVE(&dev->maplist, map, link); + if (!found) + return -EINVAL; switch (map->type) { case _DRM_REGISTERS: - if (map->bsr == NULL) - drm_ioremapfree(map); + drm_core_ioremapfree(map, dev); /* 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); + if (drm_core_has_MTRR(dev) && map->mtrr >= 0) { + int retcode; + retcode = drm_mtrr_del(map->mtrr, map->offset, + map->size, DRM_MTRR_WC); + DRM_DEBUG("mtrr_del=%d\n", retcode); } break; case _DRM_SHM: - free(map->virtual, DRM_MEM_MAPS); + free(map->handle, DRM_MEM_MAPS); + if (master) { + if (dev->sigdata.lock == master->lock.hw_lock) + dev->sigdata.lock = NULL; + master->lock.hw_lock = NULL; /* SHM removed */ + master->lock.file_priv = NULL; + DRM_WAKEUP_INT((void *)&master->lock.lock_queue); + } break; case _DRM_AGP: case _DRM_SCATTER_GATHER: @@ -331,72 +560,108 @@ void drm_rmmap(struct drm_device *dev, drm_local_map_t *map) case _DRM_CONSISTENT: drm_pci_free(dev, map->dmah); break; - default: - DRM_ERROR("Bad map type %d\n", map->type); + case _DRM_GEM: + DRM_ERROR("tried to rmmap GEM object\n"); break; } + free(map, DRM_MEM_MAPS); - if (map->bsr != NULL) { - bus_release_resource(dev->device, SYS_RES_MEMORY, map->rid, - map->bsr); - } + return 0; +} +EXPORT_SYMBOL(drm_rmmap_locked); + +int drm_rmmap(struct drm_device *dev, struct drm_local_map *map) +{ + int ret; - DRM_UNLOCK(dev); - if (map->handle) - free_unr(dev->map_unrhdr, (unsigned long)map->handle >> - DRM_MAP_HANDLE_SHIFT); DRM_LOCK(dev); + ret = drm_rmmap_locked(dev, map); + DRM_UNLOCK(dev); - free(map, DRM_MEM_MAPS); + return ret; } +EXPORT_SYMBOL(drm_rmmap); -/* Remove a map private from list and deallocate resources if the mapping - * isn't in use. +/* The rmmap ioctl appears to be unnecessary. All mappings are torn down on + * the last close of the device, and this is necessary for cleanup when things + * exit uncleanly. Therefore, having userland manually remove mappings seems + * like a pointless exercise since they're going away anyway. + * + * One use case might be after addmap is allowed for normal users for SHM and + * gets used by drivers that the server doesn't need to care about. This seems + * unlikely. + * + * \param inode device inode. + * \param file_priv DRM file private. + * \param cmd command. + * \param arg pointer to a struct drm_map structure. + * \return zero on success or a negative value on error. */ - 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; + struct drm_local_map *map = NULL; + struct drm_map_list *r_list; + int ret; DRM_LOCK(dev); - TAILQ_FOREACH(map, &dev->maplist, link) { - if (map->handle == request->handle && - map->flags & _DRM_REMOVABLE) + list_for_each_entry(r_list, &dev->maplist, head) { + if (r_list->map && + r_list->user_token == (unsigned long)request->handle && + r_list->map->flags & _DRM_REMOVABLE) { + map = r_list->map; break; + } } - /* No match found. */ - if (map == NULL) { + /* List has wrapped around to the head pointer, or its empty we didn't + * find anything. + */ + if (list_empty(&dev->maplist) || !map) { DRM_UNLOCK(dev); - return EINVAL; + return -EINVAL; } - drm_rmmap(dev, map); + /* Register and framebuffer maps are permanent */ + if ((map->type == _DRM_REGISTERS) || (map->type == _DRM_FRAME_BUFFER)) { + DRM_UNLOCK(dev); + return 0; + } + + ret = drm_rmmap_locked(dev, map); DRM_UNLOCK(dev); - return 0; + return ret; } - -static void drm_cleanup_buf_error(struct drm_device *dev, - drm_buf_entry_t *entry) +/** + * Cleanup after an error on one of the addbufs() functions. + * + * \param dev DRM device. + * \param entry buffer entry where the error occurred. + * + * Frees any pages and buffers associated with the given entry. + */ +static void drm_cleanup_buf_error(struct drm_device * dev, + struct drm_buf_entry * entry) { int i; if (entry->seg_count) { for (i = 0; i < entry->seg_count; i++) { - drm_pci_free(dev, entry->seglist[i]); + if (entry->seglist[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++) { + 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); @@ -405,13 +670,24 @@ static void drm_cleanup_buf_error(struct drm_device *dev, } } -static int drm_do_addbufs_agp(struct drm_device *dev, struct drm_buf_desc *request) +#if __OS_HAS_AGP +/** + * Add AGP buffers for DMA transfers. + * + * \param dev struct drm_device to which the buffers are to be added. + * \param request pointer to a struct drm_buf_desc describing the request. + * \return zero on success or a negative number on failure. + * + * After some sanity checks creates a drm_buf structure for each buffer and + * reallocates the buffer list of the same size order to accommodate the new + * buffers. + */ +int drm_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; + struct drm_device_dma *dma = dev->dma; + struct drm_buf_entry *entry; + struct drm_agp_mem *agp_entry; + struct drm_buf *buf; unsigned long offset; unsigned long agp_offset; int count; @@ -421,55 +697,76 @@ static int drm_do_addbufs_agp(struct drm_device *dev, struct drm_buf_desc *reque int page_order; int total; int byte_count; - int i; - drm_buf_t **temp_buflist; + int i, valid; + struct drm_buf **temp_buflist; + + if (!dma) + return -EINVAL; count = request->count; order = drm_order(request->size); size = 1 << order; - alignment = (request->flags & _DRM_PAGE_ALIGN) - ? round_page(size) : size; + alignment = (request->flags & _DRM_PAGE_ALIGN) + ? PAGE_ALIGN(size) : size; page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0; total = PAGE_SIZE << page_order; byte_count = 0; agp_offset = dev->agp->base + request->agp_start; - DRM_DEBUG("count: %d\n", count); - DRM_DEBUG("order: %d\n", order); - DRM_DEBUG("size: %d\n", size); - DRM_DEBUG("agp_offset: 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); + DRM_DEBUG("count: %d\n", count); + DRM_DEBUG("order: %d\n", order); + DRM_DEBUG("size: %d\n", size); + DRM_DEBUG("agp_offset: %lx\n", agp_offset); + DRM_DEBUG("alignment: %d\n", alignment); + DRM_DEBUG("page_order: %d\n", page_order); + DRM_DEBUG("total: %d\n", total); + + if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) + return -EINVAL; /* 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) { + valid = 0; + list_for_each_entry(agp_entry, &dev->agp->memory, head) { if ((agp_offset >= agp_entry->bound) && - (agp_offset + total * count <= - agp_entry->bound + agp_entry->pages * PAGE_SIZE)) { + (agp_offset + total * count <= agp_entry->bound + agp_entry->pages * PAGE_SIZE)) { valid = 1; break; } } - if (!valid) { + if (!list_empty(&dev->agp->memory) && !valid) { DRM_DEBUG("zone invalid\n"); - return EINVAL; - }*/ + return -EINVAL; + } + mtx_lock(&dev->count_lock); + if (dev->buf_use) { + mtx_unlock(&dev->count_lock); + return -EBUSY; + } + atomic_inc(&dev->buf_alloc); + mtx_unlock(&dev->count_lock); + DRM_LOCK(dev); entry = &dma->bufs[order]; + if (entry->buf_count) { + DRM_UNLOCK(dev); + atomic_dec(&dev->buf_alloc); + return -ENOMEM; /* May only call once for each order */ + } + + if (count < 0 || count > 4096) { + DRM_UNLOCK(dev); + atomic_dec(&dev->buf_alloc); + return -EINVAL; + } entry->buflist = malloc(count * sizeof(*entry->buflist), DRM_MEM_BUFS, M_NOWAIT | M_ZERO); if (!entry->buflist) { - return ENOMEM; + DRM_UNLOCK(dev); + atomic_dec(&dev->buf_alloc); + return -ENOMEM; } entry->buf_size = size; @@ -478,29 +775,34 @@ static int drm_do_addbufs_agp(struct drm_device *dev, struct drm_buf_desc *reque 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 = &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->offset = (dma->byte_count + offset); buf->bus_address = agp_offset + offset; buf->address = (void *)(agp_offset + offset); - buf->next = NULL; + buf->next = NULL; + buf->waiting = 0; buf->pending = 0; buf->file_priv = NULL; - buf->dev_priv_size = dev->driver->buf_priv_size; + buf->dev_priv_size = dev->driver->dev_priv_size; buf->dev_private = malloc(buf->dev_priv_size, DRM_MEM_BUFS, M_NOWAIT | M_ZERO); - if (buf->dev_private == NULL) { + if (!buf->dev_private) { /* Set count correctly so we free the proper amount. */ entry->buf_count = count; drm_cleanup_buf_error(dev, entry); - return ENOMEM; + DRM_UNLOCK(dev); + atomic_dec(&dev->buf_alloc); + return -ENOMEM; } + DRM_DEBUG("buffer %d @ %p\n", entry->buf_count, buf->address); + offset += alignment; entry->buf_count++; byte_count += PAGE_SIZE << page_order; @@ -511,10 +813,12 @@ static int drm_do_addbufs_agp(struct drm_device *dev, struct drm_buf_desc *reque temp_buflist = realloc(dma->buflist, (dma->buf_count + entry->buf_count) * sizeof(*dma->buflist), DRM_MEM_BUFS, M_NOWAIT); - if (temp_buflist == NULL) { + if (!temp_buflist) { /* Free the entry because it isn't valid */ drm_cleanup_buf_error(dev, entry); - return ENOMEM; + DRM_UNLOCK(dev); + atomic_dec(&dev->buf_alloc); + return -ENOMEM; } dma->buflist = temp_buflist; @@ -523,132 +827,184 @@ static int drm_do_addbufs_agp(struct drm_device *dev, struct drm_buf_desc *reque } dma->buf_count += entry->buf_count; + dma->seg_count += entry->seg_count; + dma->page_count += byte_count >> PAGE_SHIFT; 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); + DRM_UNLOCK(dev); + request->count = entry->buf_count; request->size = size; dma->flags = _DRM_DMA_USE_AGP; + atomic_dec(&dev->buf_alloc); return 0; } +EXPORT_SYMBOL(drm_addbufs_agp); +#endif /* __OS_HAS_AGP */ -static int drm_do_addbufs_pci(struct drm_device *dev, struct drm_buf_desc *request) +int drm_addbufs_pci(struct drm_device * dev, struct drm_buf_desc * request) { - drm_device_dma_t *dma = dev->dma; + struct drm_device_dma *dma = dev->dma; int count; int order; int size; int total; int page_order; - drm_buf_entry_t *entry; - drm_buf_t *buf; + struct drm_buf_entry *entry; + drm_dma_handle_t *dmah; + struct drm_buf *buf; int alignment; unsigned long offset; int i; int byte_count; int page_count; unsigned long *temp_pagelist; - drm_buf_t **temp_buflist; + struct drm_buf **temp_buflist; + + if (!drm_core_check_feature(dev, DRIVER_PCI_DMA)) + return -EINVAL; + + if (!dma) + return -EINVAL; + + if (!DRM_SUSER(DRM_CURPROC)) + return -EPERM; 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); + request->count, request->size, size, order); + + if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) + return -EINVAL; alignment = (request->flags & _DRM_PAGE_ALIGN) - ? round_page(size) : size; + ? PAGE_ALIGN(size) : size; page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0; total = PAGE_SIZE << page_order; + mtx_lock(&dev->count_lock); + if (dev->buf_use) { + mtx_unlock(&dev->count_lock); + return -EBUSY; + } + atomic_inc(&dev->buf_alloc); + mtx_unlock(&dev->count_lock); + + DRM_LOCK(dev); entry = &dma->bufs[order]; + if (entry->buf_count) { + DRM_UNLOCK(dev); + atomic_dec(&dev->buf_alloc); + return -ENOMEM; /* May only call once for each order */ + } + + if (count < 0 || count > 4096) { + DRM_UNLOCK(dev); + atomic_dec(&dev->buf_alloc); + return -EINVAL; + } entry->buflist = malloc(count * sizeof(*entry->buflist), DRM_MEM_BUFS, M_NOWAIT | M_ZERO); + if (!entry->buflist) { + DRM_UNLOCK(dev); + atomic_dec(&dev->buf_alloc); + return -ENOMEM; + } + entry->seglist = malloc(count * sizeof(*entry->seglist), DRM_MEM_SEGS, M_NOWAIT | M_ZERO); + if (!entry->seglist) { + free(entry->buflist, DRM_MEM_BUFS); + DRM_UNLOCK(dev); + atomic_dec(&dev->buf_alloc); + return -ENOMEM; + } /* 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); + if (!temp_pagelist) { free(entry->buflist, DRM_MEM_BUFS); - return ENOMEM; + free(entry->seglist, DRM_MEM_SEGS); + DRM_UNLOCK(dev); + atomic_dec(&dev->buf_alloc); + return -ENOMEM; } - - memcpy(temp_pagelist, dma->pagelist, dma->page_count * - sizeof(*dma->pagelist)); - + memcpy(temp_pagelist, + dma->pagelist, dma->page_count * sizeof(*dma->pagelist)); DRM_DEBUG("pagelist: %d entries\n", - dma->page_count + (count << page_order)); + dma->page_count + (count << page_order)); - entry->buf_size = size; + 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) { + + dmah = drm_pci_alloc(dev, PAGE_SIZE << page_order, 0x1000, BUS_SPACE_MAXADDR); + + if (!dmah) { /* 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_UNLOCK(dev); + atomic_dec(&dev->buf_alloc); + 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; + DRM_DEBUG("page %d @ 0x%08lx\n", + dma->page_count + page_count, + (unsigned long)dmah->vaddr + PAGE_SIZE * i); + temp_pagelist[dma->page_count + page_count++] + = (unsigned 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); + offset + size <= total && entry->buf_count < count; + offset += alignment, ++entry->buf_count) { + buf = &entry->buflist[entry->buf_count]; + buf->idx = dma->buf_count + entry->buf_count; + buf->total = alignment; + buf->order = order; + buf->used = 0; + buf->offset = (dma->byte_count + byte_count + offset); + buf->address = (void *)((char *)dmah->vaddr + offset); buf->bus_address = dmah->busaddr + offset; - buf->next = NULL; + buf->next = NULL; + buf->waiting = 0; buf->pending = 0; buf->file_priv = NULL; - buf->dev_priv_size = dev->driver->buf_priv_size; + buf->dev_priv_size = dev->driver->dev_priv_size; buf->dev_private = malloc(buf->dev_priv_size, DRM_MEM_BUFS, M_NOWAIT | M_ZERO); - if (buf->dev_private == NULL) { + if (!buf->dev_private) { /* Set count correctly so we free the proper amount. */ entry->buf_count = count; entry->seg_count = count; drm_cleanup_buf_error(dev, entry); free(temp_pagelist, DRM_MEM_PAGES); - return ENOMEM; + DRM_UNLOCK(dev); + atomic_dec(&dev->buf_alloc); + return -ENOMEM; } DRM_DEBUG("buffer %d @ %p\n", - entry->buf_count, buf->address); + entry->buf_count, buf->address); } byte_count += PAGE_SIZE << page_order; } @@ -656,11 +1012,13 @@ static int drm_do_addbufs_pci(struct drm_device *dev, struct drm_buf_desc *reque temp_buflist = realloc(dma->buflist, (dma->buf_count + entry->buf_count) * sizeof(*dma->buflist), DRM_MEM_BUFS, M_NOWAIT); - if (temp_buflist == NULL) { + if (!temp_buflist) { /* Free the entry because it isn't valid */ drm_cleanup_buf_error(dev, entry); free(temp_pagelist, DRM_MEM_PAGES); - return ENOMEM; + DRM_UNLOCK(dev); + atomic_dec(&dev->buf_alloc); + return -ENOMEM; } dma->buflist = temp_buflist; @@ -668,10 +1026,12 @@ static int drm_do_addbufs_pci(struct drm_device *dev, struct drm_buf_desc *reque dma->buflist[i + dma->buf_count] = &entry->buflist[i]; } - /* No allocations failed, so now we can replace the orginal pagelist + /* No allocations failed, so now we can replace the original pagelist * with the new one. */ - free(dma->pagelist, DRM_MEM_PAGES); + if (dma->page_count) { + free(dma->pagelist, DRM_MEM_PAGES); + } dma->pagelist = temp_pagelist; dma->buf_count += entry->buf_count; @@ -679,18 +1039,25 @@ static int drm_do_addbufs_pci(struct drm_device *dev, struct drm_buf_desc *reque dma->page_count += entry->seg_count << page_order; dma->byte_count += PAGE_SIZE * (entry->seg_count << page_order); + DRM_UNLOCK(dev); + request->count = entry->buf_count; request->size = size; + if (request->flags & _DRM_PCI_BUFFER_RO) + dma->flags = _DRM_DMA_USE_PCI_RO; + + atomic_dec(&dev->buf_alloc); return 0; } +EXPORT_SYMBOL(drm_addbufs_pci); -static int drm_do_addbufs_sg(struct drm_device *dev, struct drm_buf_desc *request) +static int drm_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; + struct drm_device_dma *dma = dev->dma; + struct drm_buf_entry *entry; + struct drm_buf *buf; unsigned long offset; unsigned long agp_offset; int count; @@ -701,34 +1068,69 @@ static int drm_do_addbufs_sg(struct drm_device *dev, struct drm_buf_desc *reques int total; int byte_count; int i; - drm_buf_t **temp_buflist; + struct drm_buf **temp_buflist; + + if (!drm_core_check_feature(dev, DRIVER_SG)) + return -EINVAL; + + if (!dma) + return -EINVAL; + + if (!DRM_SUSER(DRM_CURPROC)) + return -EPERM; count = request->count; order = drm_order(request->size); size = 1 << order; - alignment = (request->flags & _DRM_PAGE_ALIGN) - ? round_page(size) : size; + alignment = (request->flags & _DRM_PAGE_ALIGN) + ? PAGE_ALIGN(size) : size; page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0; total = PAGE_SIZE << page_order; byte_count = 0; agp_offset = request->agp_start; - DRM_DEBUG("count: %d\n", count); - DRM_DEBUG("order: %d\n", order); - DRM_DEBUG("size: %d\n", size); - DRM_DEBUG("agp_offset: %ld\n", agp_offset); - DRM_DEBUG("alignment: %d\n", alignment); - DRM_DEBUG("page_order: %d\n", page_order); - DRM_DEBUG("total: %d\n", total); + DRM_DEBUG("count: %d\n", count); + DRM_DEBUG("order: %d\n", order); + DRM_DEBUG("size: %d\n", size); + DRM_DEBUG("agp_offset: %lu\n", agp_offset); + DRM_DEBUG("alignment: %d\n", alignment); + DRM_DEBUG("page_order: %d\n", page_order); + DRM_DEBUG("total: %d\n", total); + + if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) + return -EINVAL; + + mtx_lock(&dev->count_lock); + if (dev->buf_use) { + mtx_unlock(&dev->count_lock); + return -EBUSY; + } + atomic_inc(&dev->buf_alloc); + mtx_unlock(&dev->count_lock); + DRM_LOCK(dev); entry = &dma->bufs[order]; + if (entry->buf_count) { + DRM_UNLOCK(dev); + atomic_dec(&dev->buf_alloc); + return -ENOMEM; /* May only call once for each order */ + } + + if (count < 0 || count > 4096) { + DRM_UNLOCK(dev); + atomic_dec(&dev->buf_alloc); + return -EINVAL; + } entry->buflist = malloc(count * sizeof(*entry->buflist), DRM_MEM_BUFS, M_NOWAIT | M_ZERO); - if (entry->buflist == NULL) - return ENOMEM; + if (!entry->buflist) { + DRM_UNLOCK(dev); + atomic_dec(&dev->buf_alloc); + return -ENOMEM; + } entry->buf_size = size; entry->page_order = page_order; @@ -736,31 +1138,34 @@ static int drm_do_addbufs_sg(struct drm_device *dev, struct drm_buf_desc *reques 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 = &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->offset = (dma->byte_count + offset); buf->bus_address = agp_offset + offset; - buf->address = (void *)(agp_offset + offset + dev->sg->vaddr); - buf->next = NULL; + buf->address = (void *)(agp_offset + offset + + (unsigned long)dev->sg->vaddr); + buf->next = NULL; + buf->waiting = 0; buf->pending = 0; buf->file_priv = NULL; - buf->dev_priv_size = dev->driver->buf_priv_size; + buf->dev_priv_size = dev->driver->dev_priv_size; buf->dev_private = malloc(buf->dev_priv_size, DRM_MEM_BUFS, M_NOWAIT | M_ZERO); - if (buf->dev_private == NULL) { + if (!buf->dev_private) { /* Set count correctly so we free the proper amount. */ entry->buf_count = count; drm_cleanup_buf_error(dev, entry); - return ENOMEM; + DRM_UNLOCK(dev); + atomic_dec(&dev->buf_alloc); + return -ENOMEM; } - DRM_DEBUG("buffer %d @ %p\n", - entry->buf_count, buf->address); + DRM_DEBUG("buffer %d @ %p\n", entry->buf_count, buf->address); offset += alignment; entry->buf_count++; @@ -772,10 +1177,12 @@ static int drm_do_addbufs_sg(struct drm_device *dev, struct drm_buf_desc *reques temp_buflist = realloc(dma->buflist, (dma->buf_count + entry->buf_count) * sizeof(*dma->buflist), DRM_MEM_BUFS, M_NOWAIT); - if (temp_buflist == NULL) { + if (!temp_buflist) { /* Free the entry because it isn't valid */ drm_cleanup_buf_error(dev, entry); - return ENOMEM; + DRM_UNLOCK(dev); + atomic_dec(&dev->buf_alloc); + return -ENOMEM; } dma->buflist = temp_buflist; @@ -784,144 +1191,256 @@ static int drm_do_addbufs_sg(struct drm_device *dev, struct drm_buf_desc *reques } dma->buf_count += entry->buf_count; + dma->seg_count += entry->seg_count; + dma->page_count += byte_count >> PAGE_SHIFT; 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); + DRM_UNLOCK(dev); + request->count = entry->buf_count; request->size = size; dma->flags = _DRM_DMA_USE_SG; + atomic_dec(&dev->buf_alloc); return 0; } -int drm_addbufs_agp(struct drm_device *dev, struct drm_buf_desc *request) +static int drm_addbufs_fb(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); + struct drm_device_dma *dma = dev->dma; + struct drm_buf_entry *entry; + struct drm_buf *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; + struct drm_buf **temp_buflist; - /* 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; - } + if (!drm_core_check_feature(dev, DRIVER_FB_DMA)) + return -EINVAL; - ret = drm_do_addbufs_agp(dev, request); + if (!dma) + return -EINVAL; - DRM_SPINUNLOCK(&dev->dma_lock); + if (!DRM_SUSER(DRM_CURPROC)) + return -EPERM; - return ret; -} + count = request->count; + order = drm_order(request->size); + size = 1 << order; -int drm_addbufs_sg(struct drm_device *dev, struct drm_buf_desc *request) -{ - int order, ret; + alignment = (request->flags & _DRM_PAGE_ALIGN) + ? PAGE_ALIGN(size) : size; + page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0; + total = PAGE_SIZE << page_order; - if (!DRM_SUSER(DRM_CURPROC)) - return EACCES; + byte_count = 0; + agp_offset = request->agp_start; - if (request->count < 0 || request->count > 4096) - return EINVAL; + DRM_DEBUG("count: %d\n", count); + DRM_DEBUG("order: %d\n", order); + DRM_DEBUG("size: %d\n", size); + DRM_DEBUG("agp_offset: %lu\n", agp_offset); + DRM_DEBUG("alignment: %d\n", alignment); + DRM_DEBUG("page_order: %d\n", page_order); + DRM_DEBUG("total: %d\n", total); - order = drm_order(request->size); if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) - return EINVAL; + return -EINVAL; - DRM_SPINLOCK(&dev->dma_lock); + mtx_lock(&dev->count_lock); + if (dev->buf_use) { + mtx_unlock(&dev->count_lock); + return -EBUSY; + } + atomic_inc(&dev->buf_alloc); + mtx_unlock(&dev->count_lock); - /* No more allocations after first buffer-using ioctl. */ - if (dev->buf_use != 0) { - DRM_SPINUNLOCK(&dev->dma_lock); - return EBUSY; + DRM_LOCK(dev); + entry = &dma->bufs[order]; + if (entry->buf_count) { + DRM_UNLOCK(dev); + atomic_dec(&dev->buf_alloc); + return -ENOMEM; /* May only call once for each order */ } - /* No more than one allocation per order */ - if (dev->dma->bufs[order].buf_count != 0) { - DRM_SPINUNLOCK(&dev->dma_lock); - return ENOMEM; + + if (count < 0 || count > 4096) { + DRM_UNLOCK(dev); + atomic_dec(&dev->buf_alloc); + return -EINVAL; } - ret = drm_do_addbufs_sg(dev, request); + entry->buflist = malloc(count * sizeof(*entry->buflist), DRM_MEM_BUFS, + M_NOWAIT | M_ZERO); + if (!entry->buflist) { + DRM_UNLOCK(dev); + atomic_dec(&dev->buf_alloc); + return -ENOMEM; + } - DRM_SPINUNLOCK(&dev->dma_lock); + entry->buf_size = size; + entry->page_order = page_order; - return ret; -} + offset = 0; -int drm_addbufs_pci(struct drm_device *dev, struct drm_buf_desc *request) -{ - int order, ret; + 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; - if (!DRM_SUSER(DRM_CURPROC)) - return EACCES; + buf->offset = (dma->byte_count + offset); + buf->bus_address = agp_offset + offset; + buf->address = (void *)(agp_offset + offset); + buf->next = NULL; + buf->waiting = 0; + buf->pending = 0; + buf->file_priv = NULL; - if (request->count < 0 || request->count > 4096) - return EINVAL; + buf->dev_priv_size = dev->driver->dev_priv_size; + buf->dev_private = malloc(buf->dev_priv_size, DRM_MEM_BUFS, + M_NOWAIT | M_ZERO); + if (!buf->dev_private) { + /* Set count correctly so we free the proper amount. */ + entry->buf_count = count; + drm_cleanup_buf_error(dev, entry); + DRM_UNLOCK(dev); + atomic_dec(&dev->buf_alloc); + return -ENOMEM; + } - order = drm_order(request->size); - if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) - return EINVAL; + DRM_DEBUG("buffer %d @ %p\n", entry->buf_count, buf->address); + + offset += alignment; + entry->buf_count++; + byte_count += PAGE_SIZE << page_order; + } - DRM_SPINLOCK(&dev->dma_lock); + DRM_DEBUG("byte_count: %d\n", byte_count); - /* No more allocations after first buffer-using ioctl. */ - if (dev->buf_use != 0) { - DRM_SPINUNLOCK(&dev->dma_lock); - return EBUSY; + temp_buflist = realloc(dma->buflist, + (dma->buf_count + entry->buf_count) * sizeof(*dma->buflist), + DRM_MEM_BUFS, M_NOWAIT); + if (!temp_buflist) { + /* Free the entry because it isn't valid */ + drm_cleanup_buf_error(dev, entry); + DRM_UNLOCK(dev); + atomic_dec(&dev->buf_alloc); + return -ENOMEM; } - /* No more than one allocation per order */ - if (dev->dma->bufs[order].buf_count != 0) { - DRM_SPINUNLOCK(&dev->dma_lock); - return ENOMEM; + dma->buflist = temp_buflist; + + for (i = 0; i < entry->buf_count; i++) { + dma->buflist[i + dma->buf_count] = &entry->buflist[i]; } - ret = drm_do_addbufs_pci(dev, request); + dma->buf_count += entry->buf_count; + dma->seg_count += entry->seg_count; + dma->page_count += byte_count >> PAGE_SHIFT; + 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); - DRM_SPINUNLOCK(&dev->dma_lock); + DRM_UNLOCK(dev); - return ret; + request->count = entry->buf_count; + request->size = size; + + dma->flags = _DRM_DMA_USE_FB; + + atomic_dec(&dev->buf_alloc); + return 0; } -int drm_addbufs(struct drm_device *dev, void *data, struct drm_file *file_priv) + +/** + * Add buffers for DMA transfers (ioctl). + * + * \param inode device inode. + * \param file_priv DRM file private. + * \param cmd command. + * \param arg pointer to a struct drm_buf_desc request. + * \return zero on success or a negative number on failure. + * + * According with the memory type specified in drm_buf_desc::flags and the + * build options, it dispatches the call either to addbufs_agp(), + * addbufs_sg() or addbufs_pci() for AGP, scatter-gather or consistent + * PCI memory respectively. + */ +int drm_addbufs(struct drm_device *dev, void *data, + struct drm_file *file_priv) { struct drm_buf_desc *request = data; - int err; + int ret; + + if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA)) + return -EINVAL; +#if __OS_HAS_AGP 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); + ret = drm_addbufs_agp(dev, request); + else +#endif + if (request->flags & _DRM_SG_BUFFER) + ret = drm_addbufs_sg(dev, request); + else if (request->flags & _DRM_FB_BUFFER) + ret = drm_addbufs_fb(dev, request); else - err = drm_addbufs_pci(dev, request); + ret = drm_addbufs_pci(dev, request); - return err; + return ret; } -int drm_infobufs(struct drm_device *dev, void *data, struct drm_file *file_priv) +/** + * Get information about the buffer mappings. + * + * This was originally mean for debugging purposes, or by a sophisticated + * client library to determine how best to use the available buffers (e.g., + * large buffers can be used for image transfer). + * + * \param inode device inode. + * \param file_priv DRM file private. + * \param cmd command. + * \param arg pointer to a drm_buf_info structure. + * \return zero on success or a negative number on failure. + * + * Increments drm_device::buf_use while holding the drm_device::count_lock + * lock, preventing of allocating more buffers after this call. Information + * about each requested buffer is then copied into user space. + */ +int drm_infobufs(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - drm_device_dma_t *dma = dev->dma; + struct drm_device_dma *dma = dev->dma; struct drm_buf_info *request = data; int i; int count; - int retcode = 0; - DRM_SPINLOCK(&dev->dma_lock); + if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA)) + return -EINVAL; + + if (!dma) + return -EINVAL; + + mtx_lock(&dev->count_lock); + if (atomic_read(&dev->buf_alloc)) { + mtx_unlock(&dev->count_lock); + return -EBUSY; + } ++dev->buf_use; /* Can't allocate more after this call */ - DRM_SPINUNLOCK(&dev->dma_lock); + mtx_unlock(&dev->count_lock); for (i = 0, count = 0; i < DRM_MAX_ORDER + 1; i++) { if (dma->bufs[i].buf_count) @@ -933,198 +1452,257 @@ int drm_infobufs(struct drm_device *dev, void *data, struct drm_file *file_priv) 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; - } + struct drm_buf_desc __user *to = + &request->list[count]; + struct drm_buf_entry *from = &dma->bufs[i]; + struct drm_freelist *list = &dma->bufs[i].freelist; + if (copy_to_user(&to->count, + &from->buf_count, + sizeof(from->buf_count)) || + copy_to_user(&to->size, + &from->buf_size, + sizeof(from->buf_size)) || + copy_to_user(&to->low_mark, + &list->low_mark, + sizeof(list->low_mark)) || + copy_to_user(&to->high_mark, + &list->high_mark, + sizeof(list->high_mark))) + return -EFAULT; DRM_DEBUG("%d %d %d %d %d\n", - i, dma->bufs[i].buf_count, - dma->bufs[i].buf_size, - dma->bufs[i].freelist.low_mark, - dma->bufs[i].freelist.high_mark); + 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; + return 0; } -int drm_markbufs(struct drm_device *dev, void *data, struct drm_file *file_priv) +/** + * Specifies a low and high water mark for buffer allocation + * + * \param inode device inode. + * \param file_priv DRM file private. + * \param cmd command. + * \param arg a pointer to a drm_buf_desc structure. + * \return zero on success or a negative number on failure. + * + * Verifies that the size order is bounded between the admissible orders and + * updates the respective drm_device_dma::bufs entry low and high water mark. + * + * \note This ioctl is deprecated and mostly never used. + */ +int drm_markbufs(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - drm_device_dma_t *dma = dev->dma; + struct drm_device_dma *dma = dev->dma; struct drm_buf_desc *request = data; int order; + struct drm_buf_entry *entry; + + if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA)) + return -EINVAL; + + if (!dma) + return -EINVAL; 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; - } + order = drm_order(request->size); + if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) + return -EINVAL; + entry = &dma->bufs[order]; - 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; - } + if (request->low_mark < 0 || request->low_mark > entry->buf_count) + return -EINVAL; + if (request->high_mark < 0 || request->high_mark > entry->buf_count) + return -EINVAL; - dma->bufs[order].freelist.low_mark = request->low_mark; - dma->bufs[order].freelist.high_mark = request->high_mark; - DRM_SPINUNLOCK(&dev->dma_lock); + entry->freelist.low_mark = request->low_mark; + entry->freelist.high_mark = request->high_mark; return 0; } -int drm_freebufs(struct drm_device *dev, void *data, struct drm_file *file_priv) +/** + * Unreserve the buffers in list, previously reserved using drmDMA. + * + * \param inode device inode. + * \param file_priv DRM file private. + * \param cmd command. + * \param arg pointer to a drm_buf_free structure. + * \return zero on success or a negative number on failure. + * + * Calls free_buffer() for each used buffer. + * This function is primarily used for debugging. + */ +int drm_freebufs(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - drm_device_dma_t *dma = dev->dma; + struct drm_device_dma *dma = dev->dma; struct drm_buf_free *request = data; int i; int idx; - drm_buf_t *buf; - int retcode = 0; + struct drm_buf *buf; + + if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA)) + return -EINVAL; + + if (!dma) + return -EINVAL; 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 (copy_from_user(&idx, &request->list[i], sizeof(idx))) + return -EFAULT; if (idx < 0 || idx >= dma->buf_count) { DRM_ERROR("Index %d (of %d max)\n", - idx, dma->buf_count - 1); - retcode = EINVAL; - break; + idx, dma->buf_count - 1); + return -EINVAL; } 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_CURRENTPID); + return -EINVAL; } drm_free_buffer(dev, buf); } - DRM_SPINUNLOCK(&dev->dma_lock); - return retcode; + return 0; } -int drm_mapbufs(struct drm_device *dev, void *data, struct drm_file *file_priv) +/** + * Maps all of the DMA buffers into client-virtual space (ioctl). + * + * \param inode device inode. + * \param file_priv DRM file private. + * \param cmd command. + * \param arg pointer to a drm_buf_map structure. + * \return zero on success or a negative number on failure. + * + * Maps the AGP, SG or PCI buffer region with vm_mmap(), and copies information + * about each buffer into user space. For PCI buffers, it calls vm_mmap() with + * offset equal to 0, which drm_mmap() interpretes as PCI buffers and calls + * drm_mmap_dma(). + */ +int drm_mapbufs(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - drm_device_dma_t *dma = dev->dma; + struct drm_device_dma *dma = dev->dma; int retcode = 0; const int zero = 0; + vm_offset_t virtual; 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; + if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA)) + return -EINVAL; - 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 (!dma) + return -EINVAL; - 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; + mtx_lock(&dev->count_lock); + if (atomic_read(&dev->buf_alloc)) { + mtx_unlock(&dev->count_lock); + return -EBUSY; } + dev->buf_use++; /* Can't allocate more after this call */ + mtx_unlock(&dev->count_lock); - vaddr = round_page((vm_offset_t)vms->vm_daddr + MAXDSIZ); -#if __FreeBSD_version >= 600023 - retcode = vm_mmap(&vms->vm_map, &vaddr, size, PROT_READ | PROT_WRITE, - VM_PROT_ALL, MAP_SHARED | MAP_NOSYNC, OBJT_DEVICE, - dev->devnode, foff); -#else - retcode = vm_mmap(&vms->vm_map, &vaddr, size, PROT_READ | 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; + vms = DRM_CURPROC->td_proc->p_vmspace; - 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 (request->count >= dma->buf_count) { + 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_core_check_feature(dev, DRIVER_FB_DMA) + && (dma->flags & _DRM_DMA_USE_FB))) { + struct drm_local_map *map = dev->agp_buffer_map; + vm_ooffset_t token = dev->agp_buffer_token; + + if (!map) { + retcode = -EINVAL; + goto done; + } + retcode = vm_mmap(&vms->vm_map, &virtual, map->size, + PROT_READ | PROT_WRITE, VM_PROT_ALL, + MAP_SHARED | MAP_NOSYNC, OBJT_DEVICE, + file_priv->minor->device, token); + } else { + retcode = vm_mmap(&vms->vm_map, &virtual, dma->byte_count, + PROT_READ | PROT_WRITE, VM_PROT_ALL, + MAP_SHARED | MAP_NOSYNC, OBJT_DEVICE, + file_priv->minor->device, 0); } - if (DRM_COPY_TO_USER(&request->list[i].used, &zero, - sizeof(zero))) { - retcode = EFAULT; + if (retcode) { + /* Real error */ + retcode = -retcode; goto done; } - address = vaddr + dma->buflist[i]->offset; /* *** */ - if (DRM_COPY_TO_USER(&request->list[i].address, &address, - sizeof(address))) { - retcode = EFAULT; - goto done; + request->virtual = (void __user *)virtual; + + for (i = 0; i < dma->buf_count; i++) { + if (copy_to_user(&request->list[i].idx, + &dma->buflist[i]->idx, + sizeof(request->list[0].idx))) { + retcode = -EFAULT; + goto done; + } + if (copy_to_user(&request->list[i].total, + &dma->buflist[i]->total, + sizeof(request->list[0].total))) { + retcode = -EFAULT; + goto done; + } + if (copy_to_user(&request->list[i].used, + &zero, sizeof(zero))) { + retcode = -EFAULT; + goto done; + } + address = virtual + dma->buflist[i]->offset; /* *** */ + if (copy_to_user(&request->list[i].address, + &address, sizeof(address))) { + retcode = -EFAULT; + goto done; + } } } - - done: + done: request->count = dma->buf_count; - DRM_DEBUG("%d buffers, retcode = %d\n", request->count, retcode); return retcode; } -/* - * Compute order. Can be made faster. +/** + * Compute size order. Returns the exponent of the smaller power of two which + * is greater or equal to given number. + * + * \param size size. + * \return order. + * + * \todo Can be made faster. */ int drm_order(unsigned long size) { int order; + unsigned long tmp; - if (size == 0) - return 0; + for (order = 0, tmp = size >> 1; tmp; tmp >>= 1, order++) ; - order = flsl(size) - 1; - if (size & ~(1ul << order)) + if (size & (size - 1)) ++order; return order; } +EXPORT_SYMBOL(drm_order); diff --git a/sys/dev/drm2/drm_context.c b/sys/dev/drm2/drm_context.c index 9ca941e6a8a4..90e08e968006 100644 --- a/sys/dev/drm2/drm_context.c +++ b/sys/dev/drm2/drm_context.c @@ -1,4 +1,14 @@ -/*- +/** + * \file drm_context.c + * IOCTLs for generic contexts + * + * \author Rickard E. (Rik) Faith <faith@valinux.com> + * \author Gareth Hughes <gareth@valinux.com> + */ + +/* + * Created: Fri Nov 24 18:31:37 2000 by gareth@valinux.com + * * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas. * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. * All Rights Reserved. @@ -21,29 +31,37 @@ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: - * Rickard E. (Rik) Faith <faith@valinux.com> - * Gareth Hughes <gareth@valinux.com> - * */ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); -/** @file drm_context.c - * Implementation of the context management ioctls. +/* + * ChangeLog: + * 2001-11-16 Torsten Duwe <duwe@caldera.de> + * added context constructor/destructor hooks, + * needed by SiS driver's memory management. */ #include <dev/drm2/drmP.h> -/* ================================================================ - * Context bitmap support - */ +/******************************************************************/ +/** \name Context bitmap support */ +/*@{*/ -void drm_ctxbitmap_free(struct drm_device *dev, int ctx_handle) +/** + * Free a handle from the context bitmap. + * + * \param dev DRM device. + * \param ctx_handle context handle. + * + * Clears the bit specified by \p ctx_handle in drm_device::ctx_bitmap and the entry + * in drm_device::ctx_idr, while holding the drm_device::struct_mutex + * lock. + */ +void drm_ctxbitmap_free(struct drm_device * dev, int ctx_handle) { - if (ctx_handle < 0 || ctx_handle >= DRM_MAX_CTXBITMAP || + if (ctx_handle < 0 || ctx_handle >= DRM_MAX_CTXBITMAP || dev->ctx_bitmap == NULL) { DRM_ERROR("Attempt to free invalid context handle: %d\n", ctx_handle); @@ -54,10 +72,18 @@ void drm_ctxbitmap_free(struct drm_device *dev, int ctx_handle) clear_bit(ctx_handle, dev->ctx_bitmap); dev->context_sareas[ctx_handle] = NULL; DRM_UNLOCK(dev); - return; } -int drm_ctxbitmap_next(struct drm_device *dev) +/** + * Context bitmap allocation. + * + * \param dev DRM device. + * \return (non-negative) context handle on success or a negative number on failure. + * + * Allocate a new idr from drm_device::ctx_idr while holding the + * drm_device::struct_mutex lock. + */ +static int drm_ctxbitmap_next(struct drm_device * dev) { int bit; @@ -74,7 +100,7 @@ int drm_ctxbitmap_next(struct drm_device *dev) set_bit(bit, dev->ctx_bitmap); DRM_DEBUG("bit : %d\n", bit); if ((bit+1) > dev->max_context) { - drm_local_map_t **ctx_sareas; + struct drm_local_map **ctx_sareas; int max_ctx = (bit+1); ctx_sareas = realloc(dev->context_sareas, @@ -94,7 +120,14 @@ int drm_ctxbitmap_next(struct drm_device *dev) return bit; } -int drm_ctxbitmap_init(struct drm_device *dev) +/** + * Context bitmap initialization. + * + * \param dev DRM device. + * + * Initialise the drm_device::ctx_idr + */ +int drm_ctxbitmap_init(struct drm_device * dev) { int i; int temp; @@ -118,7 +151,15 @@ int drm_ctxbitmap_init(struct drm_device *dev) return 0; } -void drm_ctxbitmap_cleanup(struct drm_device *dev) +/** + * Context bitmap cleanup. + * + * \param dev DRM device. + * + * Free all idr members using drm_ctx_sarea_free helper function + * while holding the drm_device::struct_mutex lock. + */ +void drm_ctxbitmap_cleanup(struct drm_device * dev) { DRM_LOCK(dev); if (dev->context_sareas != NULL) @@ -127,15 +168,29 @@ void drm_ctxbitmap_cleanup(struct drm_device *dev) DRM_UNLOCK(dev); } -/* ================================================================ - * Per Context SAREA Support - */ +/*@}*/ + +/******************************************************************/ +/** \name Per Context SAREA Support */ +/*@{*/ +/** + * Get per-context SAREA. + * + * \param inode device inode. + * \param file_priv DRM file private. + * \param cmd command. + * \param arg user argument pointing to a drm_ctx_priv_map structure. + * \return zero on success or a negative number on failure. + * + * Gets the map from drm_device::ctx_idr with the handle specified and + * returns its handle. + */ int drm_getsareactx(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_ctx_priv_map *request = data; - drm_local_map_t *map; + struct drm_local_map *map; DRM_LOCK(dev); if (dev->max_context < 0 || @@ -152,15 +207,29 @@ int drm_getsareactx(struct drm_device *dev, void *data, return 0; } +/** + * Set per-context SAREA. + * + * \param inode device inode. + * \param file_priv DRM file private. + * \param cmd command. + * \param arg user argument pointing to a drm_ctx_priv_map structure. + * \return zero on success or a negative number on failure. + * + * Searches the mapping specified in \p arg and update the entry in + * drm_device::ctx_idr with it. + */ int drm_setsareactx(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_ctx_priv_map *request = data; - drm_local_map_t *map = NULL; + struct drm_local_map *map = NULL; + struct drm_map_list *r_list = NULL; DRM_LOCK(dev); - TAILQ_FOREACH(map, &dev->maplist, link) { - if (map->handle == request->handle) { + list_for_each_entry(r_list, &dev->maplist, head) { + if (r_list->map + && r_list->user_token == (unsigned long) request->handle) { if (dev->max_context < 0) goto bad; if (request->ctx_id >= (unsigned) dev->max_context) @@ -176,56 +245,91 @@ bad: return EINVAL; } -/* ================================================================ - * The actual DRM context handling routines - */ +/*@}*/ + +/******************************************************************/ +/** \name The actual DRM context handling routines */ +/*@{*/ -int drm_context_switch(struct drm_device *dev, int old, int new) +/** + * Switch context. + * + * \param dev DRM device. + * \param old old context handle. + * \param new new context handle. + * \return zero on success or a negative number on failure. + * + * Attempt to set drm_device::context_flag. + */ +static int drm_context_switch(struct drm_device * dev, int old, int new) { - if (atomic_xchg(&dev->context_flag, 1) != 0) { + if (test_and_set_bit(0, &dev->context_flag)) { DRM_ERROR("Reentering -- FIXME\n"); - return EBUSY; + return -EBUSY; } DRM_DEBUG("Context switch from %d to %d\n", old, new); if (new == dev->last_context) { - atomic_xchg(&dev->context_flag, 0); + clear_bit(0, &dev->context_flag); return 0; } return 0; } -int drm_context_switch_complete(struct drm_device *dev, int new) +/** + * Complete context switch. + * + * \param dev DRM device. + * \param new new context handle. + * \return zero on success or a negative number on failure. + * + * Updates drm_device::last_context and drm_device::last_switch. Verifies the + * hardware lock is held, clears the drm_device::context_flag and wakes up + * drm_device::context_wait. + */ +static int drm_context_switch_complete(struct drm_device *dev, + struct drm_file *file_priv, int new) { - dev->last_context = new; /* PRE/POST: This is the _only_ writer. */ + dev->last_context = new; /* PRE/POST: This is the _only_ writer. */ + dev->last_switch = jiffies; - if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + if (!_DRM_LOCK_IS_HELD(file_priv->master->lock.hw_lock->lock)) { DRM_ERROR("Lock isn't held after context switch\n"); } /* If a context switch is ever initiated when the kernel holds the lock, release that lock here. */ - atomic_xchg(&dev->context_flag, 0); + clear_bit(0, &dev->context_flag); + wakeup(&dev->context_wait); return 0; } -int drm_resctx(struct drm_device *dev, void *data, struct drm_file *file_priv) +/** + * Reserve contexts. + * + * \param inode device inode. + * \param file_priv DRM file private. + * \param cmd command. + * \param arg user argument pointing to a drm_ctx_res structure. + * \return zero on success or a negative number on failure. + */ +int drm_resctx(struct drm_device *dev, void *data, + struct drm_file *file_priv) { struct drm_ctx_res *res = data; struct drm_ctx ctx; int i; if (res->count >= DRM_RESERVED_CONTEXTS) { - bzero(&ctx, sizeof(ctx)); + memset(&ctx, 0, sizeof(ctx)); for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) { ctx.handle = i; - if (DRM_COPY_TO_USER(&res->contexts[i], - &ctx, sizeof(ctx))) - return EFAULT; + if (copy_to_user(&res->contexts[i], &ctx, sizeof(ctx))) + return -EFAULT; } } res->count = DRM_RESERVED_CONTEXTS; @@ -233,8 +337,21 @@ int drm_resctx(struct drm_device *dev, void *data, struct drm_file *file_priv) return 0; } -int drm_addctx(struct drm_device *dev, void *data, struct drm_file *file_priv) +/** + * Add context. + * + * \param inode device inode. + * \param file_priv DRM file private. + * \param cmd command. + * \param arg user argument pointing to a drm_ctx structure. + * \return zero on success or a negative number on failure. + * + * Get a new handle for the context and copy to userspace. + */ +int drm_addctx(struct drm_device *dev, void *data, + struct drm_file *file_priv) { + struct drm_ctx_list *ctx_entry; struct drm_ctx *ctx = data; ctx->handle = drm_ctxbitmap_next(dev); @@ -246,15 +363,24 @@ int drm_addctx(struct drm_device *dev, void *data, struct drm_file *file_priv) if (ctx->handle == -1) { DRM_DEBUG("Not enough free contexts.\n"); /* Should this return -EBUSY instead? */ - return ENOMEM; + return -ENOMEM; } - if (dev->driver->context_ctor && ctx->handle != DRM_KERNEL_CONTEXT) { - DRM_LOCK(dev); - dev->driver->context_ctor(dev, ctx->handle); - DRM_UNLOCK(dev); + ctx_entry = malloc(sizeof(*ctx_entry), DRM_MEM_CTXBITMAP, M_NOWAIT); + if (!ctx_entry) { + DRM_DEBUG("out of memory\n"); + return -ENOMEM; } + INIT_LIST_HEAD(&ctx_entry->head); + ctx_entry->handle = ctx->handle; + ctx_entry->tag = file_priv; + + DRM_LOCK(dev); + list_add(&ctx_entry->head, &dev->ctxlist); + ++dev->ctx_count; + DRM_UNLOCK(dev); + return 0; } @@ -264,6 +390,15 @@ int drm_modctx(struct drm_device *dev, void *data, struct drm_file *file_priv) return 0; } +/** + * Get context. + * + * \param inode device inode. + * \param file_priv DRM file private. + * \param cmd command. + * \param arg user argument pointing to a drm_ctx structure. + * \return zero on success or a negative number on failure. + */ int drm_getctx(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_ctx *ctx = data; @@ -274,6 +409,17 @@ int drm_getctx(struct drm_device *dev, void *data, struct drm_file *file_priv) return 0; } +/** + * Switch context. + * + * \param inode device inode. + * \param file_priv DRM file private. + * \param cmd command. + * \param arg user argument pointing to a drm_ctx structure. + * \return zero on success or a negative number on failure. + * + * Calls context_switch(). + */ int drm_switchctx(struct drm_device *dev, void *data, struct drm_file *file_priv) { @@ -283,30 +429,66 @@ int drm_switchctx(struct drm_device *dev, void *data, return drm_context_switch(dev, dev->last_context, ctx->handle); } -int drm_newctx(struct drm_device *dev, void *data, struct drm_file *file_priv) +/** + * New context. + * + * \param inode device inode. + * \param file_priv DRM file private. + * \param cmd command. + * \param arg user argument pointing to a drm_ctx structure. + * \return zero on success or a negative number on failure. + * + * Calls context_switch_complete(). + */ +int drm_newctx(struct drm_device *dev, void *data, + struct drm_file *file_priv) { struct drm_ctx *ctx = data; DRM_DEBUG("%d\n", ctx->handle); - drm_context_switch_complete(dev, ctx->handle); + drm_context_switch_complete(dev, file_priv, ctx->handle); return 0; } -int drm_rmctx(struct drm_device *dev, void *data, struct drm_file *file_priv) +/** + * Remove context. + * + * \param inode device inode. + * \param file_priv DRM file private. + * \param cmd command. + * \param arg user argument pointing to a drm_ctx structure. + * \return zero on success or a negative number on failure. + * + * If not the special kernel context, calls ctxbitmap_free() to free the specified context. + */ +int drm_rmctx(struct drm_device *dev, void *data, + struct drm_file *file_priv) { struct drm_ctx *ctx = data; DRM_DEBUG("%d\n", ctx->handle); if (ctx->handle != DRM_KERNEL_CONTEXT) { - if (dev->driver->context_dtor) { - DRM_LOCK(dev); + if (dev->driver->context_dtor) dev->driver->context_dtor(dev, ctx->handle); - DRM_UNLOCK(dev); - } - drm_ctxbitmap_free(dev, ctx->handle); } + DRM_LOCK(dev); + if (!list_empty(&dev->ctxlist)) { + struct drm_ctx_list *pos, *n; + + list_for_each_entry_safe(pos, n, &dev->ctxlist, head) { + if (pos->handle == ctx->handle) { + list_del(&pos->head); + free(pos, DRM_MEM_CTXBITMAP); + --dev->ctx_count; + } + } + } + DRM_UNLOCK(dev); + return 0; } + +/*@}*/ diff --git a/sys/dev/drm2/drm_crtc.c b/sys/dev/drm2/drm_crtc.c index e044ec23241e..318a764805cb 100644 --- a/sys/dev/drm2/drm_crtc.c +++ b/sys/dev/drm2/drm_crtc.c @@ -32,19 +32,20 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); -#include <dev/drm2/drm.h> #include <dev/drm2/drmP.h> #include <dev/drm2/drm_crtc.h> #include <dev/drm2/drm_edid.h> #include <dev/drm2/drm_fourcc.h> -#include <sys/limits.h> + +static void drm_property_destroy_blob(struct drm_device *dev, + struct drm_property_blob *blob); /* Avoid boilerplate. I'm tired of typing. */ #define DRM_ENUM_NAME_FN(fnname, list) \ char *fnname(int val) \ { \ int i; \ - for (i = 0; i < DRM_ARRAY_SIZE(list); i++) { \ + for (i = 0; i < ARRAY_SIZE(list); i++) { \ if (list[i].type == val) \ return list[i].name; \ } \ @@ -160,6 +161,7 @@ static struct drm_conn_prop_enum_list drm_connector_enum_list[] = { DRM_MODE_CONNECTOR_HDMIB, "HDMI-B", 0 }, { DRM_MODE_CONNECTOR_TV, "TV", 0 }, { DRM_MODE_CONNECTOR_eDP, "eDP", 0 }, + { DRM_MODE_CONNECTOR_VIRTUAL, "Virtual", 0}, }; static struct drm_prop_enum_list drm_encoder_enum_list[] = @@ -168,11 +170,9 @@ static struct drm_prop_enum_list drm_encoder_enum_list[] = { DRM_MODE_ENCODER_TMDS, "TMDS" }, { DRM_MODE_ENCODER_LVDS, "LVDS" }, { DRM_MODE_ENCODER_TVDAC, "TV" }, + { DRM_MODE_ENCODER_VIRTUAL, "Virtual" }, }; -static void drm_property_destroy_blob(struct drm_device *dev, - struct drm_property_blob *blob); - char *drm_get_encoder_name(struct drm_encoder *encoder) { static char buf[32]; @@ -182,6 +182,7 @@ char *drm_get_encoder_name(struct drm_encoder *encoder) encoder->base.id); return buf; } +EXPORT_SYMBOL(drm_get_encoder_name); char *drm_get_connector_name(struct drm_connector *connector) { @@ -192,6 +193,7 @@ char *drm_get_connector_name(struct drm_connector *connector) connector->connector_type_id); return buf; } +EXPORT_SYMBOL(drm_get_connector_name); char *drm_get_connector_status_name(enum drm_connector_status status) { @@ -221,13 +223,12 @@ char *drm_get_connector_status_name(enum drm_connector_status status) static int drm_mode_object_get(struct drm_device *dev, struct drm_mode_object *obj, uint32_t obj_type) { - int new_id; + int new_id = 0; int ret; - new_id = 0; ret = drm_gem_name_create(&dev->mode_config.crtc_names, obj, &new_id); - if (ret != 0) - return (ret); + if (ret) + return ret; obj->id = new_id; obj->type = obj_type; @@ -254,7 +255,7 @@ static void drm_mode_object_put(struct drm_device *dev, struct drm_mode_object *drm_mode_object_find(struct drm_device *dev, uint32_t id, uint32_t type) { - struct drm_mode_object *obj; + struct drm_mode_object *obj = NULL; obj = drm_gem_name_ref(&dev->mode_config.crtc_names, id, NULL); if (!obj || (obj->type != type) || (obj->id != id)) @@ -262,6 +263,7 @@ struct drm_mode_object *drm_mode_object_find(struct drm_device *dev, return obj; } +EXPORT_SYMBOL(drm_mode_object_find); /** * drm_framebuffer_init - initialize a framebuffer @@ -281,7 +283,7 @@ int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb, { int ret; - DRM_MODE_CONFIG_ASSERT_LOCKED(dev); + refcount_init(&fb->refcount, 1); ret = drm_mode_object_get(dev, &fb->base, DRM_MODE_OBJECT_FB); if (ret) @@ -294,6 +296,39 @@ int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb, return 0; } +EXPORT_SYMBOL(drm_framebuffer_init); + +static void drm_framebuffer_free(struct drm_framebuffer *fb) +{ + fb->funcs->destroy(fb); +} + +/** + * drm_framebuffer_unreference - unref a framebuffer + * + * LOCKING: + * Caller must hold mode config lock. + */ +void drm_framebuffer_unreference(struct drm_framebuffer *fb) +{ + struct drm_device *dev = fb->dev; + DRM_DEBUG("FB ID: %d\n", fb->base.id); + if (!sx_xlocked(&dev->mode_config.mutex)) + DRM_WARNING("%s: dev->mode_config.mutex not locked\n", __func__); + if (refcount_release(&fb->refcount)) + drm_framebuffer_free(fb); +} +EXPORT_SYMBOL(drm_framebuffer_unreference); + +/** + * drm_framebuffer_reference - incr the fb refcnt + */ +void drm_framebuffer_reference(struct drm_framebuffer *fb) +{ + DRM_DEBUG("FB ID: %d\n", fb->base.id); + refcount_acquire(&fb->refcount); +} +EXPORT_SYMBOL(drm_framebuffer_reference); /** * drm_framebuffer_cleanup - remove a framebuffer object @@ -308,13 +343,37 @@ int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb, void drm_framebuffer_cleanup(struct drm_framebuffer *fb) { struct drm_device *dev = fb->dev; + /* + * This could be moved to drm_framebuffer_remove(), but for + * debugging is nice to keep around the list of fb's that are + * no longer associated w/ a drm_file but are not unreferenced + * yet. (i915 and omapdrm have debugfs files which will show + * this.) + */ + drm_mode_object_put(dev, &fb->base); + list_del(&fb->head); + dev->mode_config.num_fb--; +} +EXPORT_SYMBOL(drm_framebuffer_cleanup); + +/** + * drm_framebuffer_remove - remove and unreference a framebuffer object + * @fb: framebuffer to remove + * + * LOCKING: + * Caller must hold mode config lock. + * + * Scans all the CRTCs and planes in @dev's mode_config. If they're + * using @fb, removes it, setting it to NULL. + */ +void drm_framebuffer_remove(struct drm_framebuffer *fb) +{ + struct drm_device *dev = fb->dev; struct drm_crtc *crtc; struct drm_plane *plane; struct drm_mode_set set; int ret; - DRM_MODE_CONFIG_ASSERT_LOCKED(dev); - /* remove from any CRTC */ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { if (crtc->fb == fb) { @@ -340,10 +399,11 @@ void drm_framebuffer_cleanup(struct drm_framebuffer *fb) } } - drm_mode_object_put(dev, &fb->base); - list_del(&fb->head); - dev->mode_config.num_fb--; + list_del(&fb->filp_head); + + drm_framebuffer_unreference(fb); } +EXPORT_SYMBOL(drm_framebuffer_remove); /** * drm_crtc_init - Initialise a new CRTC object @@ -366,8 +426,10 @@ int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc, crtc->dev = dev; crtc->funcs = funcs; + crtc->invert_dimensions = false; sx_xlock(&dev->mode_config.mutex); + ret = drm_mode_object_get(dev, &crtc->base, DRM_MODE_OBJECT_CRTC); if (ret) goto out; @@ -377,11 +439,12 @@ int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc, list_add_tail(&crtc->head, &dev->mode_config.crtc_list); dev->mode_config.num_crtc++; -out: + out: sx_xunlock(&dev->mode_config.mutex); return ret; } +EXPORT_SYMBOL(drm_crtc_init); /** * drm_crtc_cleanup - Cleans up the core crtc usage. @@ -397,17 +460,14 @@ void drm_crtc_cleanup(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; - DRM_MODE_CONFIG_ASSERT_LOCKED(dev); - - if (crtc->gamma_store) { - free(crtc->gamma_store, DRM_MEM_KMS); - crtc->gamma_store = NULL; - } + free(crtc->gamma_store, DRM_MEM_KMS); + crtc->gamma_store = NULL; drm_mode_object_put(dev, &crtc->base); list_del(&crtc->head); dev->mode_config.num_crtc--; } +EXPORT_SYMBOL(drm_crtc_cleanup); /** * drm_mode_probed_add - add a mode to a connector's probed mode list @@ -422,11 +482,9 @@ void drm_crtc_cleanup(struct drm_crtc *crtc) void drm_mode_probed_add(struct drm_connector *connector, struct drm_display_mode *mode) { - - DRM_MODE_CONFIG_ASSERT_LOCKED(connector->dev); - list_add(&mode->head, &connector->probed_modes); } +EXPORT_SYMBOL(drm_mode_probed_add); /** * drm_mode_remove - remove and free a mode @@ -441,12 +499,10 @@ void drm_mode_probed_add(struct drm_connector *connector, void drm_mode_remove(struct drm_connector *connector, struct drm_display_mode *mode) { - - DRM_MODE_CONFIG_ASSERT_LOCKED(connector->dev); - list_del(&mode->head); drm_mode_destroy(connector->dev, mode); } +EXPORT_SYMBOL(drm_mode_remove); /** * drm_connector_init - Init a preallocated connector @@ -487,21 +543,25 @@ int drm_connector_init(struct drm_device *dev, INIT_LIST_HEAD(&connector->probed_modes); INIT_LIST_HEAD(&connector->modes); connector->edid_blob_ptr = NULL; + connector->status = connector_status_unknown; list_add_tail(&connector->head, &dev->mode_config.connector_list); dev->mode_config.num_connector++; - drm_connector_attach_property(connector, - dev->mode_config.edid_property, 0); + if (connector_type != DRM_MODE_CONNECTOR_VIRTUAL) + drm_object_attach_property(&connector->base, + dev->mode_config.edid_property, + 0); - drm_connector_attach_property(connector, + drm_object_attach_property(&connector->base, dev->mode_config.dpms_property, 0); -out: + out: sx_xunlock(&dev->mode_config.mutex); return ret; } +EXPORT_SYMBOL(drm_connector_init); /** * drm_connector_cleanup - cleans up an initialised connector @@ -527,18 +587,30 @@ void drm_connector_cleanup(struct drm_connector *connector) drm_mode_remove(connector, mode); sx_xlock(&dev->mode_config.mutex); - if (connector->edid_blob_ptr) - drm_property_destroy_blob(dev, connector->edid_blob_ptr); drm_mode_object_put(dev, &connector->base); list_del(&connector->head); dev->mode_config.num_connector--; sx_xunlock(&dev->mode_config.mutex); } +EXPORT_SYMBOL(drm_connector_cleanup); + +void drm_connector_unplug_all(struct drm_device *dev) +{ +#ifdef FREEBSD_NOTYET + struct drm_connector *connector; + + /* taking the mode config mutex ends up in a clash with sysfs */ + list_for_each_entry(connector, &dev->mode_config.connector_list, head) + drm_sysfs_connector_remove(connector); +#endif /* FREEBSD_NOTYET */ + +} +EXPORT_SYMBOL(drm_connector_unplug_all); int drm_encoder_init(struct drm_device *dev, - struct drm_encoder *encoder, - const struct drm_encoder_funcs *funcs, - int encoder_type) + struct drm_encoder *encoder, + const struct drm_encoder_funcs *funcs, + int encoder_type) { int ret; @@ -555,22 +627,23 @@ int drm_encoder_init(struct drm_device *dev, list_add_tail(&encoder->head, &dev->mode_config.encoder_list); dev->mode_config.num_encoder++; -out: + out: sx_xunlock(&dev->mode_config.mutex); return ret; } +EXPORT_SYMBOL(drm_encoder_init); void drm_encoder_cleanup(struct drm_encoder *encoder) { struct drm_device *dev = encoder->dev; - sx_xlock(&dev->mode_config.mutex); drm_mode_object_put(dev, &encoder->base); list_del(&encoder->head); dev->mode_config.num_encoder--; sx_xunlock(&dev->mode_config.mutex); } +EXPORT_SYMBOL(drm_encoder_cleanup); int drm_plane_init(struct drm_device *dev, struct drm_plane *plane, unsigned long possible_crtcs, @@ -591,6 +664,12 @@ int drm_plane_init(struct drm_device *dev, struct drm_plane *plane, plane->funcs = funcs; plane->format_types = malloc(sizeof(uint32_t) * format_count, DRM_MEM_KMS, M_WAITOK); + if (!plane->format_types) { + DRM_DEBUG_KMS("out of memory when allocating plane\n"); + drm_mode_object_put(dev, &plane->base); + ret = -ENOMEM; + goto out; + } memcpy(plane->format_types, formats, format_count * sizeof(uint32_t)); plane->format_count = format_count; @@ -607,11 +686,12 @@ int drm_plane_init(struct drm_device *dev, struct drm_plane *plane, INIT_LIST_HEAD(&plane->head); } -out: + out: sx_xunlock(&dev->mode_config.mutex); return ret; } +EXPORT_SYMBOL(drm_plane_init); void drm_plane_cleanup(struct drm_plane *plane) { @@ -627,6 +707,7 @@ void drm_plane_cleanup(struct drm_plane *plane) } sx_xunlock(&dev->mode_config.mutex); } +EXPORT_SYMBOL(drm_plane_cleanup); /** * drm_mode_create - create a new display mode @@ -646,13 +727,17 @@ struct drm_display_mode *drm_mode_create(struct drm_device *dev) nmode = malloc(sizeof(struct drm_display_mode), DRM_MEM_KMS, M_WAITOK | M_ZERO); + if (!nmode) + return NULL; if (drm_mode_object_get(dev, &nmode->base, DRM_MODE_OBJECT_MODE)) { free(nmode, DRM_MEM_KMS); - return (NULL); + return NULL; } + return nmode; } +EXPORT_SYMBOL(drm_mode_create); /** * drm_mode_destroy - remove a mode @@ -673,6 +758,7 @@ void drm_mode_destroy(struct drm_device *dev, struct drm_display_mode *mode) free(mode, DRM_MEM_KMS); } +EXPORT_SYMBOL(drm_mode_destroy); static int drm_mode_create_standard_connector_properties(struct drm_device *dev) { @@ -689,7 +775,7 @@ static int drm_mode_create_standard_connector_properties(struct drm_device *dev) dpms = drm_property_create_enum(dev, 0, "DPMS", drm_dpms_enum_list, - DRM_ARRAY_SIZE(drm_dpms_enum_list)); + ARRAY_SIZE(drm_dpms_enum_list)); dev->mode_config.dpms_property = dpms; return 0; @@ -713,17 +799,18 @@ int drm_mode_create_dvi_i_properties(struct drm_device *dev) drm_property_create_enum(dev, 0, "select subconnector", drm_dvi_i_select_enum_list, - DRM_ARRAY_SIZE(drm_dvi_i_select_enum_list)); + ARRAY_SIZE(drm_dvi_i_select_enum_list)); dev->mode_config.dvi_i_select_subconnector_property = dvi_i_selector; dvi_i_subconnector = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE, "subconnector", drm_dvi_i_subconnector_enum_list, - DRM_ARRAY_SIZE(drm_dvi_i_subconnector_enum_list)); + ARRAY_SIZE(drm_dvi_i_subconnector_enum_list)); dev->mode_config.dvi_i_subconnector_property = dvi_i_subconnector; return 0; } +EXPORT_SYMBOL(drm_mode_create_dvi_i_properties); /** * drm_create_tv_properties - create TV specific connector properties @@ -752,14 +839,14 @@ int drm_mode_create_tv_properties(struct drm_device *dev, int num_modes, tv_selector = drm_property_create_enum(dev, 0, "select subconnector", drm_tv_select_enum_list, - DRM_ARRAY_SIZE(drm_tv_select_enum_list)); + ARRAY_SIZE(drm_tv_select_enum_list)); dev->mode_config.tv_select_subconnector_property = tv_selector; tv_subconnector = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE, "subconnector", drm_tv_subconnector_enum_list, - DRM_ARRAY_SIZE(drm_tv_subconnector_enum_list)); + ARRAY_SIZE(drm_tv_subconnector_enum_list)); dev->mode_config.tv_subconnector_property = tv_subconnector; /* @@ -804,6 +891,7 @@ int drm_mode_create_tv_properties(struct drm_device *dev, int num_modes, return 0; } +EXPORT_SYMBOL(drm_mode_create_tv_properties); /** * drm_mode_create_scaling_mode_property - create scaling mode property @@ -822,12 +910,13 @@ int drm_mode_create_scaling_mode_property(struct drm_device *dev) scaling_mode = drm_property_create_enum(dev, 0, "scaling mode", drm_scaling_mode_enum_list, - DRM_ARRAY_SIZE(drm_scaling_mode_enum_list)); + ARRAY_SIZE(drm_scaling_mode_enum_list)); dev->mode_config.scaling_mode_property = scaling_mode; return 0; } +EXPORT_SYMBOL(drm_mode_create_scaling_mode_property); /** * drm_mode_create_dithering_property - create dithering property @@ -846,11 +935,12 @@ int drm_mode_create_dithering_property(struct drm_device *dev) dithering_mode = drm_property_create_enum(dev, 0, "dithering", drm_dithering_mode_enum_list, - DRM_ARRAY_SIZE(drm_dithering_mode_enum_list)); + ARRAY_SIZE(drm_dithering_mode_enum_list)); dev->mode_config.dithering_mode_property = dithering_mode; return 0; } +EXPORT_SYMBOL(drm_mode_create_dithering_property); /** * drm_mode_create_dirty_property - create dirty property @@ -870,11 +960,12 @@ int drm_mode_create_dirty_info_property(struct drm_device *dev) drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE, "dirty", drm_dirty_info_enum_list, - DRM_ARRAY_SIZE(drm_dirty_info_enum_list)); + ARRAY_SIZE(drm_dirty_info_enum_list)); dev->mode_config.dirty_info_property = dirty_info; return 0; } +EXPORT_SYMBOL(drm_mode_create_dirty_info_property); /** * drm_mode_config_init - initialize DRM mode_configuration structure @@ -908,9 +999,9 @@ void drm_mode_config_init(struct drm_device *dev) dev->mode_config.num_crtc = 0; dev->mode_config.num_encoder = 0; } +EXPORT_SYMBOL(drm_mode_config_init); -static int -drm_mode_group_init(struct drm_device *dev, struct drm_mode_group *group) +int drm_mode_group_init(struct drm_device *dev, struct drm_mode_group *group) { uint32_t total_objects = 0; @@ -920,6 +1011,8 @@ drm_mode_group_init(struct drm_device *dev, struct drm_mode_group *group) group->id_list = malloc(total_objects * sizeof(uint32_t), DRM_MEM_KMS, M_WAITOK | M_ZERO); + if (!group->id_list) + return -ENOMEM; group->num_crtcs = 0; group->num_connectors = 0; @@ -927,6 +1020,12 @@ drm_mode_group_init(struct drm_device *dev, struct drm_mode_group *group) return 0; } +void drm_mode_group_free(struct drm_mode_group *group) +{ + free(group->id_list, DRM_MEM_KMS); + group->id_list = NULL; +} + int drm_mode_group_init_legacy_group(struct drm_device *dev, struct drm_mode_group *group) { @@ -951,6 +1050,7 @@ int drm_mode_group_init_legacy_group(struct drm_device *dev, return 0; } +EXPORT_SYMBOL(drm_mode_group_init_legacy_group); /** * drm_mode_config_cleanup - free up DRM mode_config info @@ -971,6 +1071,7 @@ void drm_mode_config_cleanup(struct drm_device *dev) struct drm_encoder *encoder, *enct; struct drm_framebuffer *fb, *fbt; struct drm_property *property, *pt; + struct drm_property_blob *blob, *bt; struct drm_plane *plane, *plt; list_for_each_entry_safe(encoder, enct, &dev->mode_config.encoder_list, @@ -988,20 +1089,27 @@ void drm_mode_config_cleanup(struct drm_device *dev) drm_property_destroy(dev, property); } - list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) { - fb->funcs->destroy(fb); + list_for_each_entry_safe(blob, bt, &dev->mode_config.property_blob_list, + head) { + drm_property_destroy_blob(dev, blob); } - list_for_each_entry_safe(crtc, ct, &dev->mode_config.crtc_list, head) { - crtc->funcs->destroy(crtc); + list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) { + drm_framebuffer_remove(fb); } list_for_each_entry_safe(plane, plt, &dev->mode_config.plane_list, head) { plane->funcs->destroy(plane); } + + list_for_each_entry_safe(crtc, ct, &dev->mode_config.crtc_list, head) { + crtc->funcs->destroy(crtc); + } + drm_gem_names_fini(&dev->mode_config.crtc_names); } +EXPORT_SYMBOL(drm_mode_config_cleanup); /** * drm_crtc_convert_to_umode - convert a drm_display_mode into a modeinfo @@ -1018,11 +1126,11 @@ static void drm_crtc_convert_to_umode(struct drm_mode_modeinfo *out, const struct drm_display_mode *in) { if (in->hdisplay > USHRT_MAX || in->hsync_start > USHRT_MAX || - in->hsync_end > USHRT_MAX || in->htotal > USHRT_MAX || - in->hskew > USHRT_MAX || in->vdisplay > USHRT_MAX || - in->vsync_start > USHRT_MAX || in->vsync_end > USHRT_MAX || - in->vtotal > USHRT_MAX || in->vscan > USHRT_MAX) - printf("timing values too large for mode info\n"); + in->hsync_end > USHRT_MAX || in->htotal > USHRT_MAX || + in->hskew > USHRT_MAX || in->vdisplay > USHRT_MAX || + in->vsync_start > USHRT_MAX || in->vsync_end > USHRT_MAX || + in->vtotal > USHRT_MAX || in->vscan > USHRT_MAX) + DRM_WARNING("timing values too large for mode info\n"); out->clock = in->clock; out->hdisplay = in->hdisplay; @@ -1060,7 +1168,7 @@ static int drm_crtc_convert_umode(struct drm_display_mode *out, const struct drm_mode_modeinfo *in) { if (in->clock > INT_MAX || in->vrefresh > INT_MAX) - return ERANGE; + return -ERANGE; out->clock = in->clock; out->hdisplay = in->hdisplay; @@ -1122,7 +1230,7 @@ int drm_mode_getresources(struct drm_device *dev, void *data, struct drm_mode_group *mode_group; if (!drm_core_check_feature(dev, DRIVER_MODESET)) - return (EINVAL); + return -EINVAL; sx_xlock(&dev->mode_config.mutex); @@ -1133,13 +1241,8 @@ int drm_mode_getresources(struct drm_device *dev, void *data, list_for_each(lh, &file_priv->fbs) fb_count++; -#if 1 - mode_group = NULL; /* XXXKIB */ - if (1 || file_priv->master) { -#else - mode_group = &file_priv->masterp->minor->mode_group; - if (file_priv->masterp->minor->type == DRM_MINOR_CONTROL) { -#endif + mode_group = &file_priv->master->minor->mode_group; + if (file_priv->master->minor->type == DRM_MINOR_CONTROL) { list_for_each(lh, &dev->mode_config.crtc_list) crtc_count++; @@ -1165,11 +1268,10 @@ int drm_mode_getresources(struct drm_device *dev, void *data, /* FBs */ if (card_res->count_fbs >= fb_count) { copied = 0; - fb_id = (uint32_t *)(uintptr_t)card_res->fb_id_ptr; + fb_id = (uint32_t __user *)(unsigned long)card_res->fb_id_ptr; list_for_each_entry(fb, &file_priv->fbs, filp_head) { - if (copyout(&fb->base.id, fb_id + copied, - sizeof(uint32_t))) { - ret = EFAULT; + if (put_user(fb->base.id, fb_id + copied)) { + ret = -EFAULT; goto out; } copied++; @@ -1180,27 +1282,22 @@ int drm_mode_getresources(struct drm_device *dev, void *data, /* CRTCs */ if (card_res->count_crtcs >= crtc_count) { copied = 0; - crtc_id = (uint32_t *)(uintptr_t)card_res->crtc_id_ptr; -#if 1 - if (1 || file_priv->master) { -#else - if (file_priv->masterp->minor->type == DRM_MINOR_CONTROL) { -#endif + crtc_id = (uint32_t __user *)(unsigned long)card_res->crtc_id_ptr; + if (file_priv->master->minor->type == DRM_MINOR_CONTROL) { list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id); - if (copyout(&crtc->base.id, crtc_id + - copied, sizeof(uint32_t))) { - ret = EFAULT; + if (put_user(crtc->base.id, crtc_id + copied)) { + ret = -EFAULT; goto out; } copied++; } } else { for (i = 0; i < mode_group->num_crtcs; i++) { - if (copyout(&mode_group->id_list[i], - crtc_id + copied, sizeof(uint32_t))) { - ret = EFAULT; + if (put_user(mode_group->id_list[i], + crtc_id + copied)) { + ret = -EFAULT; goto out; } copied++; @@ -1212,31 +1309,25 @@ int drm_mode_getresources(struct drm_device *dev, void *data, /* Encoders */ if (card_res->count_encoders >= encoder_count) { copied = 0; - encoder_id = (uint32_t *)(uintptr_t)card_res->encoder_id_ptr; -#if 1 - if (file_priv->master) { -#else - if (file_priv->masterp->minor->type == DRM_MINOR_CONTROL) { -#endif + encoder_id = (uint32_t __user *)(unsigned long)card_res->encoder_id_ptr; + if (file_priv->master->minor->type == DRM_MINOR_CONTROL) { list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { DRM_DEBUG_KMS("[ENCODER:%d:%s]\n", encoder->base.id, drm_get_encoder_name(encoder)); - if (copyout(&encoder->base.id, encoder_id + - copied, sizeof(uint32_t))) { - ret = EFAULT; + if (put_user(encoder->base.id, encoder_id + + copied)) { + ret = -EFAULT; goto out; } copied++; } } else { - for (i = mode_group->num_crtcs; - i < mode_group->num_crtcs + mode_group->num_encoders; - i++) { - if (copyout(&mode_group->id_list[i], - encoder_id + copied, sizeof(uint32_t))) { - ret = EFAULT; + for (i = mode_group->num_crtcs; i < mode_group->num_crtcs + mode_group->num_encoders; i++) { + if (put_user(mode_group->id_list[i], + encoder_id + copied)) { + ret = -EFAULT; goto out; } copied++; @@ -1249,21 +1340,17 @@ int drm_mode_getresources(struct drm_device *dev, void *data, /* Connectors */ if (card_res->count_connectors >= connector_count) { copied = 0; - connector_id = (uint32_t *)(uintptr_t)card_res->connector_id_ptr; -#if 1 - if (file_priv->master) { -#else - if (file_priv->masterp->minor->type == DRM_MINOR_CONTROL) { -#endif + connector_id = (uint32_t __user *)(unsigned long)card_res->connector_id_ptr; + if (file_priv->master->minor->type == DRM_MINOR_CONTROL) { list_for_each_entry(connector, &dev->mode_config.connector_list, head) { DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", connector->base.id, drm_get_connector_name(connector)); - if (copyout(&connector->base.id, - connector_id + copied, sizeof(uint32_t))) { - ret = EFAULT; + if (put_user(connector->base.id, + connector_id + copied)) { + ret = -EFAULT; goto out; } copied++; @@ -1272,9 +1359,9 @@ int drm_mode_getresources(struct drm_device *dev, void *data, int start = mode_group->num_crtcs + mode_group->num_encoders; for (i = start; i < start + mode_group->num_connectors; i++) { - if (copyout(&mode_group->id_list[i], - connector_id + copied, sizeof(uint32_t))) { - ret = EFAULT; + if (put_user(mode_group->id_list[i], + connector_id + copied)) { + ret = -EFAULT; goto out; } copied++; @@ -1317,14 +1404,14 @@ int drm_mode_getcrtc(struct drm_device *dev, int ret = 0; if (!drm_core_check_feature(dev, DRIVER_MODESET)) - return (EINVAL); + return -EINVAL; sx_xlock(&dev->mode_config.mutex); obj = drm_mode_object_find(dev, crtc_resp->crtc_id, DRM_MODE_OBJECT_CRTC); if (!obj) { - ret = (EINVAL); + ret = -EINVAL; goto out; } crtc = obj_to_crtc(obj); @@ -1383,12 +1470,12 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, int i; struct drm_mode_modeinfo u_mode; struct drm_mode_modeinfo __user *mode_ptr; - uint32_t *prop_ptr; - uint64_t *prop_values; - uint32_t *encoder_ptr; + uint32_t __user *prop_ptr; + uint64_t __user *prop_values; + uint32_t __user *encoder_ptr; if (!drm_core_check_feature(dev, DRIVER_MODESET)) - return (EINVAL); + return -EINVAL; memset(&u_mode, 0, sizeof(struct drm_mode_modeinfo)); @@ -1399,7 +1486,7 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, obj = drm_mode_object_find(dev, out_resp->connector_id, DRM_MODE_OBJECT_CONNECTOR); if (!obj) { - ret = EINVAL; + ret = -EINVAL; goto out; } connector = obj_to_connector(obj); @@ -1440,12 +1527,12 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, */ if ((out_resp->count_modes >= mode_count) && mode_count) { copied = 0; - mode_ptr = (struct drm_mode_modeinfo *)(uintptr_t)out_resp->modes_ptr; + mode_ptr = (struct drm_mode_modeinfo __user *)(unsigned long)out_resp->modes_ptr; list_for_each_entry(mode, &connector->modes, head) { drm_crtc_convert_to_umode(&u_mode, mode); - if (copyout(&u_mode, mode_ptr + copied, - sizeof(u_mode))) { - ret = EFAULT; + if (copy_to_user(mode_ptr + copied, + &u_mode, sizeof(u_mode))) { + ret = -EFAULT; goto out; } copied++; @@ -1455,18 +1542,18 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, if ((out_resp->count_props >= props_count) && props_count) { copied = 0; - prop_ptr = (uint32_t *)(uintptr_t)(out_resp->props_ptr); - prop_values = (uint64_t *)(uintptr_t)(out_resp->prop_values_ptr); + prop_ptr = (uint32_t __user *)(unsigned long)(out_resp->props_ptr); + prop_values = (uint64_t __user *)(unsigned long)(out_resp->prop_values_ptr); for (i = 0; i < connector->properties.count; i++) { - if (copyout(&connector->properties.ids[i], - prop_ptr + copied, sizeof(uint32_t))) { - ret = EFAULT; + if (put_user(connector->properties.ids[i], + prop_ptr + copied)) { + ret = -EFAULT; goto out; } - if (copyout(&connector->properties.values[i], - prop_values + copied, sizeof(uint64_t))) { - ret = EFAULT; + if (put_user(connector->properties.values[i], + prop_values + copied)) { + ret = -EFAULT; goto out; } copied++; @@ -1476,12 +1563,12 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, if ((out_resp->count_encoders >= encoders_count) && encoders_count) { copied = 0; - encoder_ptr = (uint32_t *)(uintptr_t)(out_resp->encoders_ptr); + encoder_ptr = (uint32_t __user *)(unsigned long)(out_resp->encoders_ptr); for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { if (connector->encoder_ids[i] != 0) { - if (copyout(&connector->encoder_ids[i], - encoder_ptr + copied, sizeof(uint32_t))) { - ret = EFAULT; + if (put_user(connector->encoder_ids[i], + encoder_ptr + copied)) { + ret = -EFAULT; goto out; } copied++; @@ -1504,13 +1591,13 @@ int drm_mode_getencoder(struct drm_device *dev, void *data, int ret = 0; if (!drm_core_check_feature(dev, DRIVER_MODESET)) - return (EINVAL); + return -EINVAL; sx_xlock(&dev->mode_config.mutex); obj = drm_mode_object_find(dev, enc_resp->encoder_id, DRM_MODE_OBJECT_ENCODER); if (!obj) { - ret = EINVAL; + ret = -EINVAL; goto out; } encoder = obj_to_encoder(obj); @@ -1546,11 +1633,11 @@ int drm_mode_getplane_res(struct drm_device *dev, void *data, struct drm_mode_get_plane_res *plane_resp = data; struct drm_mode_config *config; struct drm_plane *plane; - uint32_t *plane_ptr; + uint32_t __user *plane_ptr; int copied = 0, ret = 0; if (!drm_core_check_feature(dev, DRIVER_MODESET)) - return (EINVAL); + return -EINVAL; sx_xlock(&dev->mode_config.mutex); config = &dev->mode_config; @@ -1561,12 +1648,11 @@ int drm_mode_getplane_res(struct drm_device *dev, void *data, */ if (config->num_plane && (plane_resp->count_planes >= config->num_plane)) { - plane_ptr = (uint32_t *)(unsigned long)plane_resp->plane_id_ptr; + plane_ptr = (uint32_t __user *)(unsigned long)plane_resp->plane_id_ptr; list_for_each_entry(plane, &config->plane_list, head) { - if (copyout(&plane->base.id, plane_ptr + copied, - sizeof(uint32_t))) { - ret = EFAULT; + if (put_user(plane->base.id, plane_ptr + copied)) { + ret = -EFAULT; goto out; } copied++; @@ -1597,17 +1683,17 @@ int drm_mode_getplane(struct drm_device *dev, void *data, struct drm_mode_get_plane *plane_resp = data; struct drm_mode_object *obj; struct drm_plane *plane; - uint32_t *format_ptr; + uint32_t __user *format_ptr; int ret = 0; if (!drm_core_check_feature(dev, DRIVER_MODESET)) - return (EINVAL); + return -EINVAL; sx_xlock(&dev->mode_config.mutex); obj = drm_mode_object_find(dev, plane_resp->plane_id, DRM_MODE_OBJECT_PLANE); if (!obj) { - ret = ENOENT; + ret = -ENOENT; goto out; } plane = obj_to_plane(obj); @@ -1632,11 +1718,11 @@ int drm_mode_getplane(struct drm_device *dev, void *data, */ if (plane->format_count && (plane_resp->count_format_types >= plane->format_count)) { - format_ptr = (uint32_t *)(unsigned long)plane_resp->format_type_ptr; - if (copyout(format_ptr, + format_ptr = (uint32_t __user *)(unsigned long)plane_resp->format_type_ptr; + if (copy_to_user(format_ptr, plane->format_types, sizeof(uint32_t) * plane->format_count)) { - ret = EFAULT; + ret = -EFAULT; goto out; } } @@ -1672,7 +1758,7 @@ int drm_mode_setplane(struct drm_device *dev, void *data, int i; if (!drm_core_check_feature(dev, DRIVER_MODESET)) - return (EINVAL); + return -EINVAL; sx_xlock(&dev->mode_config.mutex); @@ -1685,7 +1771,7 @@ int drm_mode_setplane(struct drm_device *dev, void *data, if (!obj) { DRM_DEBUG_KMS("Unknown plane ID %d\n", plane_req->plane_id); - ret = ENOENT; + ret = -ENOENT; goto out; } plane = obj_to_plane(obj); @@ -1703,7 +1789,7 @@ int drm_mode_setplane(struct drm_device *dev, void *data, if (!obj) { DRM_DEBUG_KMS("Unknown crtc ID %d\n", plane_req->crtc_id); - ret = ENOENT; + ret = -ENOENT; goto out; } crtc = obj_to_crtc(obj); @@ -1713,7 +1799,7 @@ int drm_mode_setplane(struct drm_device *dev, void *data, if (!obj) { DRM_DEBUG_KMS("Unknown framebuffer ID %d\n", plane_req->fb_id); - ret = ENOENT; + ret = -ENOENT; goto out; } fb = obj_to_fb(obj); @@ -1724,7 +1810,7 @@ int drm_mode_setplane(struct drm_device *dev, void *data, break; if (i == plane->format_count) { DRM_DEBUG_KMS("Invalid pixel format 0x%08x\n", fb->pixel_format); - ret = EINVAL; + ret = -EINVAL; goto out; } @@ -1746,7 +1832,7 @@ int drm_mode_setplane(struct drm_device *dev, void *data, ((plane_req->src_x & 0xffff) * 15625) >> 10, plane_req->src_y >> 16, ((plane_req->src_y & 0xffff) * 15625) >> 10); - ret = ENOSPC; + ret = -ENOSPC; goto out; } @@ -1758,11 +1844,11 @@ int drm_mode_setplane(struct drm_device *dev, void *data, DRM_DEBUG_KMS("Invalid CRTC coordinates %ux%u+%d+%d\n", plane_req->crtc_w, plane_req->crtc_h, plane_req->crtc_x, plane_req->crtc_y); - ret = ERANGE; + ret = -ERANGE; goto out; } - ret = -plane->funcs->update_plane(plane, crtc, fb, + ret = plane->funcs->update_plane(plane, crtc, fb, plane_req->crtc_x, plane_req->crtc_y, plane_req->crtc_w, plane_req->crtc_h, plane_req->src_x, plane_req->src_y, @@ -1806,29 +1892,30 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, struct drm_framebuffer *fb = NULL; struct drm_display_mode *mode = NULL; struct drm_mode_set set; - uint32_t *set_connectors_ptr; + uint32_t __user *set_connectors_ptr; int ret; int i; if (!drm_core_check_feature(dev, DRIVER_MODESET)) - return (EINVAL); + return -EINVAL; /* For some reason crtc x/y offsets are signed internally. */ if (crtc_req->x > INT_MAX || crtc_req->y > INT_MAX) - return (ERANGE); + return -ERANGE; sx_xlock(&dev->mode_config.mutex); obj = drm_mode_object_find(dev, crtc_req->crtc_id, DRM_MODE_OBJECT_CRTC); if (!obj) { DRM_DEBUG_KMS("Unknown CRTC ID %d\n", crtc_req->crtc_id); - ret = EINVAL; + ret = -EINVAL; goto out; } crtc = obj_to_crtc(obj); DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id); if (crtc_req->mode_valid) { + int hdisplay, vdisplay; /* If we have a mode we need a framebuffer. */ /* If we pass -1, set the mode with the currently bound fb */ if (crtc_req->fb_id == -1) { @@ -1844,7 +1931,7 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, if (!obj) { DRM_DEBUG_KMS("Unknown FB ID%d\n", crtc_req->fb_id); - ret = EINVAL; + ret = -EINVAL; goto out; } fb = obj_to_fb(obj); @@ -1852,7 +1939,7 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, mode = drm_mode_create(dev); if (!mode) { - ret = ENOMEM; + ret = -ENOMEM; goto out; } @@ -1864,29 +1951,39 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); - if (mode->hdisplay > fb->width || - mode->vdisplay > fb->height || - crtc_req->x > fb->width - mode->hdisplay || - crtc_req->y > fb->height - mode->vdisplay) { - DRM_DEBUG_KMS("Invalid CRTC viewport %ux%u+%u+%u for fb size %ux%u.\n", - mode->hdisplay, mode->vdisplay, - crtc_req->x, crtc_req->y, - fb->width, fb->height); - ret = ENOSPC; + hdisplay = mode->hdisplay; + vdisplay = mode->vdisplay; + + if (crtc->invert_dimensions) { + int tmp; + tmp = vdisplay; + vdisplay = hdisplay; + hdisplay = tmp; + } + + if (hdisplay > fb->width || + vdisplay > fb->height || + crtc_req->x > fb->width - hdisplay || + crtc_req->y > fb->height - vdisplay) { + DRM_DEBUG_KMS("Invalid fb size %ux%u for CRTC viewport %ux%u+%d+%d%s.\n", + fb->width, fb->height, + hdisplay, vdisplay, crtc_req->x, crtc_req->y, + crtc->invert_dimensions ? " (inverted)" : ""); + ret = -ENOSPC; goto out; } } if (crtc_req->count_connectors == 0 && mode) { DRM_DEBUG_KMS("Count connectors is 0 but mode set\n"); - ret = EINVAL; + ret = -EINVAL; goto out; } if (crtc_req->count_connectors > 0 && (!mode || !fb)) { DRM_DEBUG_KMS("Count connectors is %d but no mode or fb set\n", crtc_req->count_connectors); - ret = EINVAL; + ret = -EINVAL; goto out; } @@ -1895,17 +1992,22 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, /* Avoid unbounded kernel memory allocation */ if (crtc_req->count_connectors > config->num_connector) { - ret = EINVAL; + ret = -EINVAL; goto out; } connector_set = malloc(crtc_req->count_connectors * - sizeof(struct drm_connector *), DRM_MEM_KMS, M_WAITOK); + sizeof(struct drm_connector *), + DRM_MEM_KMS, M_WAITOK); + if (!connector_set) { + ret = -ENOMEM; + goto out; + } for (i = 0; i < crtc_req->count_connectors; i++) { - set_connectors_ptr = (uint32_t *)(uintptr_t)crtc_req->set_connectors_ptr; - if (copyin(&set_connectors_ptr[i], &out_id, sizeof(uint32_t))) { - ret = EFAULT; + set_connectors_ptr = (uint32_t __user *)(unsigned long)crtc_req->set_connectors_ptr; + if (get_user(out_id, &set_connectors_ptr[i])) { + ret = -EFAULT; goto out; } @@ -1914,7 +2016,7 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, if (!obj) { DRM_DEBUG_KMS("Connector id %d unknown\n", out_id); - ret = EINVAL; + ret = -EINVAL; goto out; } connector = obj_to_connector(obj); @@ -1951,27 +2053,27 @@ int drm_mode_cursor_ioctl(struct drm_device *dev, int ret = 0; if (!drm_core_check_feature(dev, DRIVER_MODESET)) - return (EINVAL); + return -EINVAL; - if (!req->flags) - return (EINVAL); + if (!req->flags || (~DRM_MODE_CURSOR_FLAGS & req->flags)) + return -EINVAL; sx_xlock(&dev->mode_config.mutex); obj = drm_mode_object_find(dev, req->crtc_id, DRM_MODE_OBJECT_CRTC); if (!obj) { DRM_DEBUG_KMS("Unknown CRTC ID %d\n", req->crtc_id); - ret = EINVAL; + ret = -EINVAL; goto out; } crtc = obj_to_crtc(obj); if (req->flags & DRM_MODE_CURSOR_BO) { if (!crtc->funcs->cursor_set) { - ret = ENXIO; + ret = -ENXIO; goto out; } /* Turns off the cursor if handle is 0 */ - ret = -crtc->funcs->cursor_set(crtc, file_priv, req->handle, + ret = crtc->funcs->cursor_set(crtc, file_priv, req->handle, req->width, req->height); } @@ -1979,7 +2081,7 @@ int drm_mode_cursor_ioctl(struct drm_device *dev, if (crtc->funcs->cursor_move) { ret = crtc->funcs->cursor_move(crtc, req->x, req->y); } else { - ret = EFAULT; + ret = -EFAULT; goto out; } } @@ -1995,7 +2097,7 @@ uint32_t drm_mode_legacy_fb_format(uint32_t bpp, uint32_t depth) switch (bpp) { case 8: - fmt = DRM_FORMAT_RGB332; + fmt = DRM_FORMAT_C8; break; case 16: if (depth == 15) @@ -2015,13 +2117,14 @@ uint32_t drm_mode_legacy_fb_format(uint32_t bpp, uint32_t depth) fmt = DRM_FORMAT_ARGB8888; break; default: - DRM_ERROR("bad bpp, assuming RGB24 pixel format\n"); + DRM_ERROR("bad bpp, assuming x8r8g8b8 pixel format\n"); fmt = DRM_FORMAT_XRGB8888; break; } return fmt; } +EXPORT_SYMBOL(drm_mode_legacy_fb_format); /** * drm_mode_addfb - add an FB to the graphics configuration @@ -2058,18 +2161,22 @@ int drm_mode_addfb(struct drm_device *dev, r.handles[0] = or->handle; if (!drm_core_check_feature(dev, DRIVER_MODESET)) - return (EINVAL); + return -EINVAL; if ((config->min_width > r.width) || (r.width > config->max_width)) - return (EINVAL); + return -EINVAL; + if ((config->min_height > r.height) || (r.height > config->max_height)) - return (EINVAL); + return -EINVAL; sx_xlock(&dev->mode_config.mutex); - ret = -dev->mode_config.funcs->fb_create(dev, file_priv, &r, &fb); + /* TODO check buffer is sufficiently large */ + /* TODO setup destructor callback */ + + ret = dev->mode_config.funcs->fb_create(dev, file_priv, &r, &fb); if (ret != 0) { - DRM_DEBUG_KMS("could not create framebuffer, error %d\n", ret); + DRM_DEBUG_KMS("could not create framebuffer\n"); goto out; } @@ -2082,7 +2189,7 @@ out: return ret; } -static int format_check(struct drm_mode_fb_cmd2 *r) +static int format_check(const struct drm_mode_fb_cmd2 *r) { uint32_t format = r->pixel_format & ~DRM_FORMAT_BIG_ENDIAN; @@ -2135,6 +2242,8 @@ static int format_check(struct drm_mode_fb_cmd2 *r) case DRM_FORMAT_NV21: case DRM_FORMAT_NV16: case DRM_FORMAT_NV61: + case DRM_FORMAT_NV24: + case DRM_FORMAT_NV42: case DRM_FORMAT_YUV410: case DRM_FORMAT_YVU410: case DRM_FORMAT_YUV411: @@ -2147,11 +2256,11 @@ static int format_check(struct drm_mode_fb_cmd2 *r) case DRM_FORMAT_YVU444: return 0; default: - return (EINVAL); + return -EINVAL; } } -static int framebuffer_check(struct drm_mode_fb_cmd2 *r) +static int framebuffer_check(const struct drm_mode_fb_cmd2 *r) { int ret, hsub, vsub, num_planes, i; @@ -2177,13 +2286,21 @@ static int framebuffer_check(struct drm_mode_fb_cmd2 *r) for (i = 0; i < num_planes; i++) { unsigned int width = r->width / (i != 0 ? hsub : 1); + unsigned int height = r->height / (i != 0 ? vsub : 1); + unsigned int cpp = drm_format_plane_cpp(r->pixel_format, i); if (!r->handles[i]) { DRM_DEBUG_KMS("no buffer object handle for plane %d\n", i); return -EINVAL; } - if (r->pitches[i] < drm_format_plane_cpp(r->pixel_format, i) * width) { + if ((uint64_t) width * cpp > UINT_MAX) + return -ERANGE; + + if ((uint64_t) height * r->pitches[i] + r->offsets[i] > UINT_MAX) + return -ERANGE; + + if (r->pitches[i] < width * cpp) { DRM_DEBUG_KMS("bad pitch %u for plane %d\n", r->pitches[i], i); return -EINVAL; } @@ -2215,34 +2332,36 @@ int drm_mode_addfb2(struct drm_device *dev, struct drm_mode_fb_cmd2 *r = data; struct drm_mode_config *config = &dev->mode_config; struct drm_framebuffer *fb; - int ret = 0; + int ret; if (!drm_core_check_feature(dev, DRIVER_MODESET)) - return (EINVAL); + return -EINVAL; + + if (r->flags & ~DRM_MODE_FB_INTERLACED) { + DRM_DEBUG_KMS("bad framebuffer flags 0x%08x\n", r->flags); + return -EINVAL; + } if ((config->min_width > r->width) || (r->width > config->max_width)) { DRM_DEBUG_KMS("bad framebuffer width %d, should be >= %d && <= %d\n", r->width, config->min_width, config->max_width); - return (EINVAL); + return -EINVAL; } if ((config->min_height > r->height) || (r->height > config->max_height)) { DRM_DEBUG_KMS("bad framebuffer height %d, should be >= %d && <= %d\n", r->height, config->min_height, config->max_height); - return (EINVAL); + return -EINVAL; } ret = framebuffer_check(r); if (ret) - return -ret; + return ret; sx_xlock(&dev->mode_config.mutex); - /* TODO check buffer is sufficiently large */ - /* TODO setup destructor callback */ - - ret = -dev->mode_config.funcs->fb_create(dev, file_priv, r, &fb); + ret = dev->mode_config.funcs->fb_create(dev, file_priv, r, &fb); if (ret != 0) { - DRM_DEBUG_KMS("could not create framebuffer, error %d\n", ret); + DRM_DEBUG_KMS("could not create framebuffer\n"); goto out; } @@ -2252,7 +2371,7 @@ int drm_mode_addfb2(struct drm_device *dev, out: sx_xunlock(&dev->mode_config.mutex); - return (ret); + return ret; } /** @@ -2283,13 +2402,13 @@ int drm_mode_rmfb(struct drm_device *dev, int found = 0; if (!drm_core_check_feature(dev, DRIVER_MODESET)) - return (EINVAL); + return -EINVAL; sx_xlock(&dev->mode_config.mutex); obj = drm_mode_object_find(dev, *id, DRM_MODE_OBJECT_FB); /* TODO check that we really get a framebuffer back. */ if (!obj) { - ret = EINVAL; + ret = -EINVAL; goto out; } fb = obj_to_fb(obj); @@ -2299,15 +2418,11 @@ int drm_mode_rmfb(struct drm_device *dev, found = 1; if (!found) { - ret = EINVAL; + ret = -EINVAL; goto out; } - /* TODO release all crtc connected to the framebuffer */ - /* TODO unhock the destructor from the buffer object */ - - list_del(&fb->filp_head); - fb->funcs->destroy(fb); + drm_framebuffer_remove(fb); out: sx_xunlock(&dev->mode_config.mutex); @@ -2340,12 +2455,12 @@ int drm_mode_getfb(struct drm_device *dev, int ret = 0; if (!drm_core_check_feature(dev, DRIVER_MODESET)) - return (EINVAL); + return -EINVAL; sx_xlock(&dev->mode_config.mutex); obj = drm_mode_object_find(dev, r->fb_id, DRM_MODE_OBJECT_FB); if (!obj) { - ret = EINVAL; + ret = -EINVAL; goto out; } fb = obj_to_fb(obj); @@ -2376,21 +2491,21 @@ int drm_mode_dirtyfb_ioctl(struct drm_device *dev, int ret; if (!drm_core_check_feature(dev, DRIVER_MODESET)) - return (EINVAL); + return -EINVAL; sx_xlock(&dev->mode_config.mutex); obj = drm_mode_object_find(dev, r->fb_id, DRM_MODE_OBJECT_FB); if (!obj) { - ret = EINVAL; + ret = -EINVAL; goto out_err1; } fb = obj_to_fb(obj); num_clips = r->num_clips; - clips_ptr = (struct drm_clip_rect *)(unsigned long)r->clips_ptr; + clips_ptr = (struct drm_clip_rect __user *)(unsigned long)r->clips_ptr; if (!num_clips != !clips_ptr) { - ret = EINVAL; + ret = -EINVAL; goto out_err1; } @@ -2398,28 +2513,35 @@ int drm_mode_dirtyfb_ioctl(struct drm_device *dev, /* If userspace annotates copy, clips must come in pairs */ if (flags & DRM_MODE_FB_DIRTY_ANNOTATE_COPY && (num_clips % 2)) { - ret = EINVAL; + ret = -EINVAL; goto out_err1; } if (num_clips && clips_ptr) { if (num_clips < 0 || num_clips > DRM_MODE_FB_DIRTY_MAX_CLIPS) { - ret = EINVAL; + ret = -EINVAL; goto out_err1; } clips = malloc(num_clips * sizeof(*clips), DRM_MEM_KMS, M_WAITOK | M_ZERO); + if (!clips) { + ret = -ENOMEM; + goto out_err1; + } - ret = copyin(clips_ptr, clips, num_clips * sizeof(*clips)); - if (ret) + ret = copy_from_user(clips, clips_ptr, + num_clips * sizeof(*clips)); + if (ret) { + ret = -EFAULT; goto out_err2; + } } if (fb->funcs->dirty) { - ret = -fb->funcs->dirty(fb, file_priv, flags, r->color, + ret = fb->funcs->dirty(fb, file_priv, flags, r->color, clips, num_clips); } else { - ret = ENOSYS; + ret = -ENOSYS; goto out_err2; } @@ -2447,17 +2569,12 @@ out_err1: */ void drm_fb_release(struct drm_file *priv) { -#if 1 - struct drm_device *dev = priv->dev; -#else struct drm_device *dev = priv->minor->dev; -#endif struct drm_framebuffer *fb, *tfb; sx_xlock(&dev->mode_config.mutex); list_for_each_entry_safe(fb, tfb, &priv->fbs, filp_head) { - list_del(&fb->filp_head); - fb->funcs->destroy(fb); + drm_framebuffer_remove(fb); } sx_xunlock(&dev->mode_config.mutex); } @@ -2491,7 +2608,7 @@ int drm_mode_attachmode_crtc(struct drm_device *dev, struct drm_crtc *crtc, if (connector->encoder->crtc == crtc) { dup_mode = drm_mode_duplicate(dev, mode); if (!dup_mode) { - ret = ENOMEM; + ret = -ENOMEM; goto out; } list_add_tail(&dup_mode->head, &list); @@ -2513,6 +2630,7 @@ int drm_mode_attachmode_crtc(struct drm_device *dev, struct drm_crtc *crtc, return ret; } +EXPORT_SYMBOL(drm_mode_attachmode_crtc); static int drm_mode_detachmode(struct drm_device *dev, struct drm_connector *connector, @@ -2546,6 +2664,7 @@ int drm_mode_detachmode_crtc(struct drm_device *dev, struct drm_display_mode *mo } return 0; } +EXPORT_SYMBOL(drm_mode_detachmode_crtc); /** * drm_fb_attachmode - Attach a user mode to an connector @@ -2656,15 +2775,20 @@ struct drm_property *drm_property_create(struct drm_device *dev, int flags, property = malloc(sizeof(struct drm_property), DRM_MEM_KMS, M_WAITOK | M_ZERO); + if (!property) + return NULL; if (num_values) { property->values = malloc(sizeof(uint64_t)*num_values, DRM_MEM_KMS, M_WAITOK | M_ZERO); + if (!property->values) + goto fail; } ret = drm_mode_object_get(dev, &property->base, DRM_MODE_OBJECT_PROPERTY); if (ret) goto fail; + property->flags = flags; property->num_values = num_values; INIT_LIST_HEAD(&property->enum_blob_list); @@ -2676,12 +2800,12 @@ struct drm_property *drm_property_create(struct drm_device *dev, int flags, list_add_tail(&property->head, &dev->mode_config.property_list); return property; - fail: free(property->values, DRM_MEM_KMS); free(property, DRM_MEM_KMS); - return (NULL); + return NULL; } +EXPORT_SYMBOL(drm_property_create); struct drm_property *drm_property_create_enum(struct drm_device *dev, int flags, const char *name, @@ -2709,6 +2833,7 @@ struct drm_property *drm_property_create_enum(struct drm_device *dev, int flags, return property; } +EXPORT_SYMBOL(drm_property_create_enum); struct drm_property *drm_property_create_bitmask(struct drm_device *dev, int flags, const char *name, @@ -2736,6 +2861,7 @@ struct drm_property *drm_property_create_bitmask(struct drm_device *dev, return property; } +EXPORT_SYMBOL(drm_property_create_bitmask); struct drm_property *drm_property_create_range(struct drm_device *dev, int flags, const char *name, @@ -2754,6 +2880,7 @@ struct drm_property *drm_property_create_range(struct drm_device *dev, int flags return property; } +EXPORT_SYMBOL(drm_property_create_range); int drm_property_add_enum(struct drm_property *property, int index, uint64_t value, const char *name) @@ -2782,6 +2909,8 @@ int drm_property_add_enum(struct drm_property *property, int index, prop_enum = malloc(sizeof(struct drm_property_enum), DRM_MEM_KMS, M_WAITOK | M_ZERO); + if (!prop_enum) + return -ENOMEM; strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN); prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0'; @@ -2791,6 +2920,7 @@ int drm_property_add_enum(struct drm_property *property, int index, list_add_tail(&prop_enum->head, &property->enum_blob_list); return 0; } +EXPORT_SYMBOL(drm_property_add_enum); void drm_property_destroy(struct drm_device *dev, struct drm_property *property) { @@ -2807,24 +2937,7 @@ void drm_property_destroy(struct drm_device *dev, struct drm_property *property) list_del(&property->head); free(property, DRM_MEM_KMS); } - -void drm_connector_attach_property(struct drm_connector *connector, - struct drm_property *property, uint64_t init_val) -{ - drm_object_attach_property(&connector->base, property, init_val); -} - -int drm_connector_property_set_value(struct drm_connector *connector, - struct drm_property *property, uint64_t value) -{ - return drm_object_property_set_value(&connector->base, property, value); -} - -int drm_connector_property_get_value(struct drm_connector *connector, - struct drm_property *property, uint64_t *val) -{ - return drm_object_property_get_value(&connector->base, property, val); -} +EXPORT_SYMBOL(drm_property_destroy); void drm_object_attach_property(struct drm_mode_object *obj, struct drm_property *property, @@ -2833,17 +2946,18 @@ void drm_object_attach_property(struct drm_mode_object *obj, int count = obj->properties->count; if (count == DRM_OBJECT_MAX_PROPERTY) { - printf("Failed to attach object property (type: 0x%x). Please " + DRM_WARNING("Failed to attach object property (type: 0x%x). Please " "increase DRM_OBJECT_MAX_PROPERTY by 1 for each time " "you see this message on the same object type.\n", obj->type); return; - } + } obj->properties->ids[count] = property->base.id; obj->properties->values[count] = init_val; obj->properties->count++; } +EXPORT_SYMBOL(drm_object_attach_property); int drm_object_property_set_value(struct drm_mode_object *obj, struct drm_property *property, uint64_t val) @@ -2859,6 +2973,7 @@ int drm_object_property_set_value(struct drm_mode_object *obj, return -EINVAL; } +EXPORT_SYMBOL(drm_object_property_set_value); int drm_object_property_get_value(struct drm_mode_object *obj, struct drm_property *property, uint64_t *val) @@ -2874,6 +2989,7 @@ int drm_object_property_get_value(struct drm_mode_object *obj, return -EINVAL; } +EXPORT_SYMBOL(drm_object_property_get_value); int drm_mode_getproperty_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) @@ -2889,9 +3005,9 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev, struct drm_property_enum *prop_enum; struct drm_mode_property_enum __user *enum_ptr; struct drm_property_blob *prop_blob; - uint32_t *blob_id_ptr; - uint64_t *values_ptr; - uint32_t *blob_length_ptr; + uint32_t __user *blob_id_ptr; + uint64_t __user *values_ptr; + uint32_t __user *blob_length_ptr; if (!drm_core_check_feature(dev, DRIVER_MODESET)) return -EINVAL; @@ -2919,9 +3035,9 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev, out_resp->flags = property->flags; if ((out_resp->count_values >= value_count) && value_count) { - values_ptr = (uint64_t *)(uintptr_t)out_resp->values_ptr; + values_ptr = (uint64_t __user *)(unsigned long)out_resp->values_ptr; for (i = 0; i < value_count; i++) { - if (copyout(&property->values[i], values_ptr + i, sizeof(uint64_t))) { + if (copy_to_user(values_ptr + i, &property->values[i], sizeof(uint64_t))) { ret = -EFAULT; goto done; } @@ -2932,16 +3048,16 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev, if (property->flags & (DRM_MODE_PROP_ENUM | DRM_MODE_PROP_BITMASK)) { if ((out_resp->count_enum_blobs >= enum_count) && enum_count) { copied = 0; - enum_ptr = (struct drm_mode_property_enum *)(uintptr_t)out_resp->enum_blob_ptr; + enum_ptr = (struct drm_mode_property_enum __user *)(unsigned long)out_resp->enum_blob_ptr; list_for_each_entry(prop_enum, &property->enum_blob_list, head) { - if (copyout(&prop_enum->value, &enum_ptr[copied].value, sizeof(uint64_t))) { + if (copy_to_user(&enum_ptr[copied].value, &prop_enum->value, sizeof(uint64_t))) { ret = -EFAULT; goto done; } - if (copyout(&prop_enum->name, - &enum_ptr[copied].name,DRM_PROP_NAME_LEN)) { + if (copy_to_user(&enum_ptr[copied].name, + &prop_enum->name, DRM_PROP_NAME_LEN)) { ret = -EFAULT; goto done; } @@ -2954,18 +3070,16 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev, if (property->flags & DRM_MODE_PROP_BLOB) { if ((out_resp->count_enum_blobs >= blob_count) && blob_count) { copied = 0; - blob_id_ptr = (uint32_t *)(uintptr_t)out_resp->enum_blob_ptr; - blob_length_ptr = (uint32_t *)(uintptr_t)out_resp->values_ptr; + blob_id_ptr = (uint32_t __user *)(unsigned long)out_resp->enum_blob_ptr; + blob_length_ptr = (uint32_t __user *)(unsigned long)out_resp->values_ptr; list_for_each_entry(prop_blob, &property->enum_blob_list, head) { - if (copyout(&prop_blob->base.id, - blob_id_ptr + copied, sizeof(uint32_t))) { + if (put_user(prop_blob->base.id, blob_id_ptr + copied)) { ret = -EFAULT; goto done; } - if (copyout(&prop_blob->length, - blob_length_ptr + copied, sizeof(uint32_t))) { + if (put_user(prop_blob->length, blob_length_ptr + copied)) { ret = -EFAULT; goto done; } @@ -2989,13 +3103,15 @@ static struct drm_property_blob *drm_property_create_blob(struct drm_device *dev if (!length || !data) return NULL; - blob = malloc(sizeof(struct drm_property_blob) + length, DRM_MEM_KMS, + blob = malloc(sizeof(struct drm_property_blob)+length, DRM_MEM_KMS, M_WAITOK | M_ZERO); + if (!blob) + return NULL; ret = drm_mode_object_get(dev, &blob->base, DRM_MODE_OBJECT_BLOB); if (ret) { free(blob, DRM_MEM_KMS); - return (NULL); + return NULL; } blob->length = length; @@ -3021,7 +3137,7 @@ int drm_mode_getblob_ioctl(struct drm_device *dev, struct drm_mode_get_blob *out_resp = data; struct drm_property_blob *blob; int ret = 0; - void *blob_ptr; + void __user *blob_ptr; if (!drm_core_check_feature(dev, DRIVER_MODESET)) return -EINVAL; @@ -3035,8 +3151,8 @@ int drm_mode_getblob_ioctl(struct drm_device *dev, blob = obj_to_blob(obj); if (out_resp->length == blob->length) { - blob_ptr = (void *)(unsigned long)out_resp->data; - if (copyout(blob->data, blob_ptr, blob->length)){ + blob_ptr = (void __user *)(unsigned long)out_resp->data; + if (copy_to_user(blob_ptr, blob->data, blob->length)){ ret = -EFAULT; goto done; } @@ -3060,23 +3176,26 @@ int drm_mode_connector_update_edid_property(struct drm_connector *connector, /* Delete edid, when there is none. */ if (!edid) { connector->edid_blob_ptr = NULL; - ret = drm_connector_property_set_value(connector, dev->mode_config.edid_property, 0); + ret = drm_object_property_set_value(&connector->base, dev->mode_config.edid_property, 0); return ret; } size = EDID_LENGTH * (1 + edid->extensions); connector->edid_blob_ptr = drm_property_create_blob(connector->dev, size, edid); + if (!connector->edid_blob_ptr) + return -EINVAL; - ret = drm_connector_property_set_value(connector, + ret = drm_object_property_set_value(&connector->base, dev->mode_config.edid_property, connector->edid_blob_ptr->base.id); return ret; } +EXPORT_SYMBOL(drm_mode_connector_update_edid_property); static bool drm_property_change_is_valid(struct drm_property *property, - u64 value) + uint64_t value) { if (property->flags & DRM_MODE_PROP_IMMUTABLE) return false; @@ -3086,10 +3205,13 @@ static bool drm_property_change_is_valid(struct drm_property *property, return true; } else if (property->flags & DRM_MODE_PROP_BITMASK) { int i; - u64 valid_mask = 0; + uint64_t valid_mask = 0; for (i = 0; i < property->num_values; i++) valid_mask |= (1ULL << property->values[i]); return !(value & ~valid_mask); + } else if (property->flags & DRM_MODE_PROP_BLOB) { + /* Only the driver knows */ + return true; } else { int i; for (i = 0; i < property->num_values; i++) @@ -3131,7 +3253,7 @@ static int drm_mode_connector_set_obj_prop(struct drm_mode_object *obj, /* store the property value if successful */ if (!ret) - drm_connector_property_set_value(connector, property, value); + drm_object_property_set_value(&connector->base, property, value); return ret; } @@ -3202,13 +3324,13 @@ int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data, prop_values_ptr = (uint64_t __user *)(unsigned long) (arg->prop_values_ptr); for (i = 0; i < props_count; i++) { - if (copyout(props_ptr + copied, - &obj->properties->ids[i], sizeof(uint32_t))) { + if (put_user(obj->properties->ids[i], + props_ptr + copied)) { ret = -EFAULT; goto out; } - if (copyout(prop_values_ptr + copied, - &obj->properties->values[i], sizeof(uint64_t))) { + if (put_user(obj->properties->values[i], + prop_values_ptr + copied)) { ret = -EFAULT; goto out; } @@ -3289,6 +3411,7 @@ int drm_mode_connector_attach_encoder(struct drm_connector *connector, } return -ENOMEM; } +EXPORT_SYMBOL(drm_mode_connector_attach_encoder); void drm_mode_connector_detach_encoder(struct drm_connector *connector, struct drm_encoder *encoder) @@ -3303,6 +3426,7 @@ void drm_mode_connector_detach_encoder(struct drm_connector *connector, } } } +EXPORT_SYMBOL(drm_mode_connector_detach_encoder); int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc, int gamma_size) @@ -3311,9 +3435,14 @@ int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc, crtc->gamma_store = malloc(gamma_size * sizeof(uint16_t) * 3, DRM_MEM_KMS, M_WAITOK | M_ZERO); + if (!crtc->gamma_store) { + crtc->gamma_size = 0; + return -ENOMEM; + } return 0; } +EXPORT_SYMBOL(drm_mode_crtc_set_gamma_size); int drm_mode_gamma_set_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) @@ -3336,6 +3465,11 @@ int drm_mode_gamma_set_ioctl(struct drm_device *dev, } crtc = obj_to_crtc(obj); + if (crtc->funcs->gamma_set == NULL) { + ret = -ENOSYS; + goto out; + } + /* memcpy into gamma store */ if (crtc_lut->gamma_size != crtc->gamma_size) { ret = -EINVAL; @@ -3344,19 +3478,19 @@ int drm_mode_gamma_set_ioctl(struct drm_device *dev, size = crtc_lut->gamma_size * (sizeof(uint16_t)); r_base = crtc->gamma_store; - if (copyin((void *)(uintptr_t)crtc_lut->red, r_base, size)) { + if (copy_from_user(r_base, (void __user *)(unsigned long)crtc_lut->red, size)) { ret = -EFAULT; goto out; } g_base = (char *)r_base + size; - if (copyin((void *)(uintptr_t)crtc_lut->green, g_base, size)) { + if (copy_from_user(g_base, (void __user *)(unsigned long)crtc_lut->green, size)) { ret = -EFAULT; goto out; } b_base = (char *)g_base + size; - if (copyin((void *)(uintptr_t)crtc_lut->blue, b_base, size)) { + if (copy_from_user(b_base, (void __user *)(unsigned long)crtc_lut->blue, size)) { ret = -EFAULT; goto out; } @@ -3390,11 +3524,6 @@ int drm_mode_gamma_get_ioctl(struct drm_device *dev, } crtc = obj_to_crtc(obj); - if (crtc->funcs->gamma_set == NULL) { - ret = -ENOSYS; - goto out; - } - /* memcpy into gamma store */ if (crtc_lut->gamma_size != crtc->gamma_size) { ret = -EINVAL; @@ -3403,19 +3532,19 @@ int drm_mode_gamma_get_ioctl(struct drm_device *dev, size = crtc_lut->gamma_size * (sizeof(uint16_t)); r_base = crtc->gamma_store; - if (copyout(r_base, (void *)(uintptr_t)crtc_lut->red, size)) { + if (copy_to_user((void __user *)(unsigned long)crtc_lut->red, r_base, size)) { ret = -EFAULT; goto out; } g_base = (char *)r_base + size; - if (copyout(g_base, (void *)(uintptr_t)crtc_lut->green, size)) { + if (copy_to_user((void __user *)(unsigned long)crtc_lut->green, g_base, size)) { ret = -EFAULT; goto out; } b_base = (char *)g_base + size; - if (copyout(b_base, (void *)(uintptr_t)crtc_lut->blue, size)) { + if (copy_to_user((void __user *)(unsigned long)crtc_lut->blue, b_base, size)) { ret = -EFAULT; goto out; } @@ -3425,25 +3554,29 @@ out: } static void -drm_kms_free(void *arg) +free_vblank_event(void *arg) { free(arg, DRM_MEM_KMS); } -int drm_mode_page_flip_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) +int drm_mode_page_flip_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv) { struct drm_mode_crtc_page_flip *page_flip = data; struct drm_mode_object *obj; struct drm_crtc *crtc; struct drm_framebuffer *fb; struct drm_pending_vblank_event *e = NULL; - int ret = EINVAL; +#ifdef __linux__ + unsigned long flags; +#endif + int hdisplay, vdisplay; + int ret = -EINVAL; if (page_flip->flags & ~DRM_MODE_PAGE_FLIP_FLAGS || page_flip->reserved != 0) - return (EINVAL); + return -EINVAL; sx_xlock(&dev->mode_config.mutex); obj = drm_mode_object_find(dev, page_flip->crtc_id, DRM_MODE_OBJECT_CRTC); @@ -3456,7 +3589,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, void *data, * due to a hotplug event, that userspace has not * yet discovered. */ - ret = EBUSY; + ret = -EBUSY; goto out; } @@ -3468,20 +3601,29 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, void *data, goto out; fb = obj_to_fb(obj); - if (crtc->mode.hdisplay > fb->width || - crtc->mode.vdisplay > fb->height || - crtc->x > fb->width - crtc->mode.hdisplay || - crtc->y > fb->height - crtc->mode.vdisplay) { - DRM_DEBUG_KMS("Invalid fb size %ux%u for CRTC viewport %ux%u+%d+%d.\n", - fb->width, fb->height, - crtc->mode.hdisplay, crtc->mode.vdisplay, - crtc->x, crtc->y); - ret = ENOSPC; + hdisplay = crtc->mode.hdisplay; + vdisplay = crtc->mode.vdisplay; + + if (crtc->invert_dimensions) { + int tmp; + tmp = vdisplay; + vdisplay = hdisplay; + hdisplay = tmp; + } + + if (hdisplay > fb->width || + vdisplay > fb->height || + crtc->x > fb->width - hdisplay || + crtc->y > fb->height - vdisplay) { + DRM_DEBUG_KMS("Invalid fb size %ux%u for CRTC viewport %ux%u+%d+%d%s.\n", + fb->width, fb->height, hdisplay, vdisplay, crtc->x, crtc->y, + crtc->invert_dimensions ? " (inverted)" : ""); + ret = -ENOSPC; goto out; } if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) { - ret = ENOMEM; + ret = -ENOMEM; mtx_lock(&dev->event_lock); if (file_priv->event_space < sizeof e->event) { mtx_unlock(&dev->event_lock); @@ -3491,6 +3633,12 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, void *data, mtx_unlock(&dev->event_lock); e = malloc(sizeof *e, DRM_MEM_KMS, M_WAITOK | M_ZERO); + if (e == NULL) { + mtx_lock(&dev->event_lock); + file_priv->event_space += sizeof e->event; + mtx_unlock(&dev->event_lock); + goto out; + } e->event.base.type = DRM_EVENT_FLIP_COMPLETE; e->event.base.length = sizeof e->event; @@ -3498,11 +3646,11 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, void *data, e->base.event = &e->event.base; e->base.file_priv = file_priv; e->base.destroy = - (void (*) (struct drm_pending_event *))drm_kms_free; + (void (*) (struct drm_pending_event *)) free_vblank_event; } - ret = -crtc->funcs->page_flip(crtc, fb, e); - if (ret != 0) { + ret = crtc->funcs->page_flip(crtc, fb, e); + if (ret) { if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) { mtx_lock(&dev->event_lock); file_priv->event_space += sizeof e->event; @@ -3513,9 +3661,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, void *data, out: sx_xunlock(&dev->mode_config.mutex); - CTR3(KTR_DRM, "page_flip_ioctl %d %d %d", curproc->p_pid, - page_flip->crtc_id, ret); - return (ret); + return ret; } void drm_mode_config_reset(struct drm_device *dev) @@ -3532,10 +3678,14 @@ void drm_mode_config_reset(struct drm_device *dev) if (encoder->funcs->reset) encoder->funcs->reset(encoder); - list_for_each_entry(connector, &dev->mode_config.connector_list, head) + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + connector->status = connector_status_unknown; + if (connector->funcs->reset) connector->funcs->reset(connector); + } } +EXPORT_SYMBOL(drm_mode_config_reset); int drm_mode_create_dumb_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) @@ -3543,7 +3693,7 @@ int drm_mode_create_dumb_ioctl(struct drm_device *dev, struct drm_mode_create_dumb *args = data; if (!dev->driver->dumb_create) - return -ENOTSUP; + return -ENOSYS; return dev->driver->dumb_create(file_priv, dev, args); } @@ -3554,7 +3704,7 @@ int drm_mode_mmap_dumb_ioctl(struct drm_device *dev, /* call driver ioctl to get mmap offset */ if (!dev->driver->dumb_map_offset) - return -ENOTSUP; + return -ENOSYS; return dev->driver->dumb_map_offset(file_priv, dev, args->handle, &args->offset); } @@ -3565,7 +3715,7 @@ int drm_mode_destroy_dumb_ioctl(struct drm_device *dev, struct drm_mode_destroy_dumb *args = data; if (!dev->driver->dumb_destroy) - return -ENOTSUP; + return -ENOSYS; return dev->driver->dumb_destroy(file_priv, dev, args->handle); } @@ -3578,6 +3728,7 @@ void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth, int *bpp) { switch (format) { + case DRM_FORMAT_C8: case DRM_FORMAT_RGB332: case DRM_FORMAT_BGR233: *depth = 8; @@ -3636,6 +3787,7 @@ void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth, break; } } +EXPORT_SYMBOL(drm_fb_get_bpp_depth); /** * drm_format_num_planes - get the number of planes for format @@ -3662,11 +3814,14 @@ int drm_format_num_planes(uint32_t format) case DRM_FORMAT_NV21: case DRM_FORMAT_NV16: case DRM_FORMAT_NV61: + case DRM_FORMAT_NV24: + case DRM_FORMAT_NV42: return 2; default: return 1; } } +EXPORT_SYMBOL(drm_format_num_planes); /** * drm_format_plane_cpp - determine the bytes per pixel value @@ -3694,6 +3849,8 @@ int drm_format_plane_cpp(uint32_t format, int plane) case DRM_FORMAT_NV21: case DRM_FORMAT_NV16: case DRM_FORMAT_NV61: + case DRM_FORMAT_NV24: + case DRM_FORMAT_NV42: return plane ? 2 : 1; case DRM_FORMAT_YUV410: case DRM_FORMAT_YVU410: @@ -3711,6 +3868,7 @@ int drm_format_plane_cpp(uint32_t format, int plane) return bpp >> 3; } } +EXPORT_SYMBOL(drm_format_plane_cpp); /** * drm_format_horz_chroma_subsampling - get the horizontal chroma subsampling factor @@ -3745,6 +3903,7 @@ int drm_format_horz_chroma_subsampling(uint32_t format) return 1; } } +EXPORT_SYMBOL(drm_format_horz_chroma_subsampling); /** * drm_format_vert_chroma_subsampling - get the vertical chroma subsampling factor @@ -3769,3 +3928,4 @@ int drm_format_vert_chroma_subsampling(uint32_t format) return 1; } } +EXPORT_SYMBOL(drm_format_vert_chroma_subsampling); diff --git a/sys/dev/drm2/drm_crtc.h b/sys/dev/drm2/drm_crtc.h index 36708c6de658..0ab60c83f9ab 100644 --- a/sys/dev/drm2/drm_crtc.h +++ b/sys/dev/drm2/drm_crtc.h @@ -27,13 +27,15 @@ #ifndef __DRM_CRTC_H__ #define __DRM_CRTC_H__ -#include <dev/drm2/drm_gem_names.h> +#include <dev/drm2/drm_mode.h> + #include <dev/drm2/drm_fourcc.h> struct drm_device; struct drm_mode_set; struct drm_framebuffer; -struct i2c_adapter; +struct drm_object_properties; + #define DRM_MODE_OBJECT_CRTC 0xcccccccc #define DRM_MODE_OBJECT_CONNECTOR 0xc0c0c0c0 @@ -50,7 +52,7 @@ struct drm_mode_object { struct drm_object_properties *properties; }; -#define DRM_OBJECT_MAX_PROPERTY 16 +#define DRM_OBJECT_MAX_PROPERTY 24 struct drm_object_properties { int count; uint32_t ids[DRM_OBJECT_MAX_PROPERTY]; @@ -72,7 +74,7 @@ enum drm_mode_status { MODE_H_ILLEGAL, /* mode has illegal horizontal timings */ MODE_V_ILLEGAL, /* mode has illegal horizontal timings */ MODE_BAD_WIDTH, /* requires an unsupported linepitch */ - MODE_NOMODE, /* no mode with a maching name */ + MODE_NOMODE, /* no mode with a matching name */ MODE_NO_INTERLACE, /* interlaced mode not supported */ MODE_NO_DBLESCAN, /* doublescan mode not supported */ MODE_NO_VSCAN, /* multiscan mode not supported */ @@ -114,7 +116,8 @@ enum drm_mode_status { .hdisplay = (hd), .hsync_start = (hss), .hsync_end = (hse), \ .htotal = (ht), .hskew = (hsk), .vdisplay = (vd), \ .vsync_start = (vss), .vsync_end = (vse), .vtotal = (vt), \ - .vscan = (vs), .flags = (f), .vrefresh = 0 + .vscan = (vs), .flags = (f), .vrefresh = 0, \ + .base.type = DRM_MODE_OBJECT_MODE #define CRTC_INTERLACE_HALVE_V 0x1 /* halve V values for interlacing */ @@ -125,9 +128,8 @@ struct drm_display_mode { char name[DRM_DISPLAY_MODE_LEN]; - int connector_count; enum drm_mode_status status; - int type; + unsigned int type; /* Proposed mode values */ int clock; /* in kHz */ @@ -163,8 +165,6 @@ struct drm_display_mode { int crtc_vsync_start; int crtc_vsync_end; int crtc_vtotal; - int crtc_hadjusted; - int crtc_vadjusted; /* Driver private mode info */ int private_size; @@ -213,11 +213,10 @@ struct drm_display_info { u32 color_formats; u8 cea_rev; - - char *raw_edid; /* if any */ }; struct drm_framebuffer_funcs { + /* note: use drm_framebuffer_remove() */ void (*destroy)(struct drm_framebuffer *framebuffer); int (*create_handle)(struct drm_framebuffer *fb, struct drm_file *file_priv, @@ -242,6 +241,16 @@ struct drm_framebuffer_funcs { struct drm_framebuffer { struct drm_device *dev; + /* + * Note that the fb is refcounted for the benefit of driver internals, + * for example some hw, disabling a CRTC/plane is asynchronous, and + * scanout does not actually complete until the next vblank. So some + * cleanup (like releasing the reference(s) on the backing GEM bo(s)) + * should be deferred. In cases like this, the driver would like to + * hold a ref to the fb even though it has already been removed from + * userspace perspective. + */ + unsigned int refcount; struct list_head head; struct drm_mode_object base; const struct drm_framebuffer_funcs *funcs; @@ -291,20 +300,16 @@ struct drm_plane; /** * drm_crtc_funcs - control CRTCs for a given device - * @reset: reset CRTC after state has been invalidate (e.g. resume) - * @dpms: control display power levels * @save: save CRTC state - * @resore: restore CRTC state - * @lock: lock the CRTC - * @unlock: unlock the CRTC - * @shadow_allocate: allocate shadow pixmap - * @shadow_create: create shadow pixmap for rotation support - * @shadow_destroy: free shadow pixmap - * @mode_fixup: fixup proposed mode - * @mode_set: set the desired mode on the CRTC + * @restore: restore CRTC state + * @reset: reset CRTC after state has been invalidate (e.g. resume) + * @cursor_set: setup the cursor + * @cursor_move: move the cursor * @gamma_set: specify color ramp for CRTC * @destroy: deinit and free object * @set_property: called when a property is changed + * @set_config: apply a new CRTC configuration + * @page_flip: initiate a page flip * * The drm_crtc_funcs structure is the central CRTC management structure * in the DRM. Each CRTC controls one or more connectors (note that the name @@ -338,7 +343,7 @@ struct drm_crtc_funcs { /* * Flip to the given framebuffer. This implements the page - * flip ioctl descibed in drm_mode.h, specifically, the + * flip ioctl described in drm_mode.h, specifically, the * implementation must return immediately and block all * rendering to the current fb until the flip has completed. * If userspace set the event flag in the ioctl, the event @@ -348,16 +353,31 @@ struct drm_crtc_funcs { int (*page_flip)(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_pending_vblank_event *event); + int (*set_property)(struct drm_crtc *crtc, struct drm_property *property, uint64_t val); }; /** * drm_crtc - central CRTC control structure + * @dev: parent DRM device + * @head: list management + * @base: base KMS object for ID tracking etc. * @enabled: is this CRTC enabled? + * @mode: current mode timings + * @hwmode: mode timings as programmed to hw regs + * @invert_dimensions: for purposes of error checking crtc vs fb sizes, + * invert the width/height of the crtc. This is used if the driver + * is performing 90 or 270 degree rotated scanout * @x: x position on screen * @y: y position on screen * @funcs: CRTC control functions + * @gamma_size: size of gamma ramp + * @gamma_store: gamma ramp values + * @framedur_ns: precise frame timing + * @framedur_ns: precise line timing + * @pixeldur_ns: precise pixel timing + * @helper_private: mid-layer private data * @properties: property tracking for this CRTC * * Each CRTC may have one or more connectors associated with it. This structure @@ -382,6 +402,8 @@ struct drm_crtc { */ struct drm_display_mode hwmode; + bool invert_dimensions; + int x, y; const struct drm_crtc_funcs *funcs; @@ -390,7 +412,7 @@ struct drm_crtc { uint16_t *gamma_store; /* Constants needed for precise vblank and swap timestamping. */ - int64_t framedur_ns, linedur_ns, pixeldur_ns; + s64 framedur_ns, linedur_ns, pixeldur_ns; /* if you are using the helper */ void *helper_private; @@ -405,11 +427,8 @@ struct drm_crtc { * @save: save connector state * @restore: restore connector state * @reset: reset connector after state has been invalidate (e.g. resume) - * @mode_valid: is this mode valid on the given connector? - * @mode_fixup: try to fixup proposed mode for this connector - * @mode_set: set this mode * @detect: is this connector active? - * @get_modes: get mode list for this connector + * @fill_modes: fill mode list for this connector * @set_property: property for this connector may need update * @destroy: make object go away * @force: notify the driver the connector is forced on @@ -439,6 +458,13 @@ struct drm_connector_funcs { void (*force)(struct drm_connector *connector); }; +/** + * drm_encoder_funcs - encoder controls + * @reset: reset state (e.g. at init or resume time) + * @destroy: cleanup and free associated data + * + * Encoders sit between CRTCs and connectors. + */ struct drm_encoder_funcs { void (*reset)(struct drm_encoder *encoder); void (*destroy)(struct drm_encoder *encoder); @@ -446,10 +472,22 @@ struct drm_encoder_funcs { #define DRM_CONNECTOR_MAX_UMODES 16 #define DRM_CONNECTOR_LEN 32 -#define DRM_CONNECTOR_MAX_ENCODER 2 +#define DRM_CONNECTOR_MAX_ENCODER 3 /** * drm_encoder - central DRM encoder structure + * @dev: parent DRM device + * @head: list management + * @base: base KMS object + * @encoder_type: one of the %DRM_MODE_ENCODER_<foo> types in drm_mode.h + * @possible_crtcs: bitmask of potential CRTC bindings + * @possible_clones: bitmask of potential sibling encoders for cloning + * @crtc: currently bound CRTC + * @funcs: control functions + * @helper_private: mid-layer private data + * + * CRTCs drive pixels to encoders, which convert them into signals + * appropriate for a given connector or set of connectors. */ struct drm_encoder { struct drm_device *dev; @@ -485,14 +523,36 @@ enum drm_connector_force { /** * drm_connector - central DRM connector control structure - * @crtc: CRTC this connector is currently connected to, NULL if none + * @dev: parent DRM device + * @kdev: kernel device for sysfs attributes + * @attr: sysfs attributes + * @head: list management + * @base: base KMS object + * @connector_type: one of the %DRM_MODE_CONNECTOR_<foo> types from drm_mode.h + * @connector_type_id: index into connector type enum * @interlace_allowed: can this connector handle interlaced modes? * @doublescan_allowed: can this connector handle doublescan? - * @available_modes: modes available on this connector (from get_modes() + user) - * @initial_x: initial x position for this connector - * @initial_y: initial y position for this connector - * @status: connector connected? + * @modes: modes available on this connector (from fill_modes() + user) + * @status: one of the drm_connector_status enums (connected, not, or unknown) + * @probed_modes: list of modes derived directly from the display + * @display_info: information about attached display (e.g. from EDID) * @funcs: connector control functions + * @user_modes: user added mode list + * @edid_blob_ptr: DRM property containing EDID if present + * @properties: property tracking for this connector + * @polled: a %DRM_CONNECTOR_POLL_<foo> value for core driven polling + * @dpms: current dpms state + * @helper_private: mid-layer private data + * @force: a %DRM_FORCE_<foo> state for forced mode sets + * @encoder_ids: valid encoders for this connector + * @encoder: encoder driving this connector, if any + * @eld: EDID-like data, if present + * @dvi_dual: dual link DVI, if found + * @max_tmds_clock: max clock rate, if found + * @latency_present: AV delay info from ELD, if found + * @video_latency: video latency info from ELD, if found + * @audio_latency: audio latency info from ELD, if found + * @null_edid_counter: track sinks that give us all zeros for the EDID * * Each connector may be connected to one or more CRTCs, or may be clonable by * another connector if they can share a CRTC. Each connector also has a specific @@ -501,7 +561,9 @@ enum drm_connector_force { */ struct drm_connector { struct drm_device *dev; - /* struct device kdev; XXXKIB */ +#ifdef FREEBSD_NOTYET + struct device kdev; +#endif /* FREEBSD_NOTYET */ struct device_attribute *attr; struct list_head head; @@ -513,7 +575,6 @@ struct drm_connector { bool doublescan_allowed; struct list_head modes; /* list of modes on this connector */ - int initial_x, initial_y; enum drm_connector_status status; /* these are modes added by probing with DDC or the BIOS */ @@ -536,7 +597,6 @@ struct drm_connector { /* forced on connector */ enum drm_connector_force force; uint32_t encoder_ids[DRM_CONNECTOR_MAX_ENCODER]; - uint32_t force_encoder_id; struct drm_encoder *encoder; /* currently active encoder */ /* EDID bits */ @@ -546,8 +606,8 @@ struct drm_connector { bool latency_present[2]; int video_latency[2]; /* [0]: progressive, [1]: interlaced */ int audio_latency[2]; - int null_edid_counter; /* needed to workaround some HW bugs where we get all 0s */ + unsigned bad_edid_counter; }; /** @@ -566,6 +626,7 @@ struct drm_plane_funcs { uint32_t src_w, uint32_t src_h); int (*disable_plane)(struct drm_plane *plane); void (*destroy)(struct drm_plane *plane); + int (*set_property)(struct drm_plane *plane, struct drm_property *property, uint64_t val); }; @@ -585,7 +646,7 @@ struct drm_plane_funcs { * @enabled: enabled flag * @funcs: helper functions * @helper_private: storage for drver layer - @properties: property tracking for this plane + * @properties: property tracking for this plane */ struct drm_plane { struct drm_device *dev; @@ -613,7 +674,15 @@ struct drm_plane { }; /** - * struct drm_mode_set + * drm_mode_set - new values for a CRTC config change + * @head: list management + * @fb: framebuffer to use for new config + * @crtc: CRTC whose configuration we're about to change + * @mode: mode timings to use + * @x: position of this CRTC relative to @fb + * @y: position of this CRTC relative to @fb + * @connectors: array of connectors to drive with this CRTC if possible + * @num_connectors: size of @connectors array * * Represents a single crtc the connectors that it drives with what mode * and from which framebuffer it scans out from. @@ -621,8 +690,6 @@ struct drm_plane { * This is used to set modes. */ struct drm_mode_set { - struct list_head head; - struct drm_framebuffer *fb; struct drm_crtc *crtc; struct drm_display_mode *mode; @@ -635,15 +702,34 @@ struct drm_mode_set { }; /** - * struct drm_mode_config_funcs - configure CRTCs for a given screen layout + * struct drm_mode_config_funcs - basic driver provided mode setting functions + * @fb_create: create a new framebuffer object + * @output_poll_changed: function to handle output configuration changes + * + * Some global (i.e. not per-CRTC, connector, etc) mode setting functions that + * involve drivers. */ struct drm_mode_config_funcs { int (*fb_create)(struct drm_device *dev, - struct drm_file *file_priv, struct drm_mode_fb_cmd2 *mode_cmd, - struct drm_framebuffer **res); + struct drm_file *file_priv, + struct drm_mode_fb_cmd2 *mode_cmd, + struct drm_framebuffer **fb); void (*output_poll_changed)(struct drm_device *dev); }; +/** + * drm_mode_group - group of mode setting resources for potential sub-grouping + * @num_crtcs: CRTC count + * @num_encoders: encoder count + * @num_connectors: connector count + * @id_list: list of KMS object IDs in this group + * + * Currently this simply tracks the global mode setting state. But in the + * future it could allow groups of objects to be set aside into independent + * control groups for use by different user level processes (e.g. two X servers + * running simultaneously on different heads, each with their own mode + * configuration and freedom of mode setting). + */ struct drm_mode_group { uint32_t num_crtcs; uint32_t num_encoders; @@ -655,11 +741,34 @@ struct drm_mode_group { /** * drm_mode_config - Mode configuration control structure + * @mutex: mutex protecting KMS related lists and structures + * @idr_mutex: mutex for KMS ID allocation and management + * @crtc_idr: main KMS ID tracking object + * @num_fb: number of fbs available + * @fb_list: list of framebuffers available + * @num_connector: number of connectors on this device + * @connector_list: list of connector objects + * @num_encoder: number of encoders on this device + * @encoder_list: list of encoder objects + * @num_crtc: number of CRTCs on this device + * @crtc_list: list of CRTC objects + * @min_width: minimum pixel width on this device + * @min_height: minimum pixel height on this device + * @max_width: maximum pixel width on this device + * @max_height: maximum pixel height on this device + * @funcs: core driver provided mode setting functions + * @fb_base: base address of the framebuffer + * @poll_enabled: track polling status for this device + * @output_poll_work: delayed work for polling in process context + * @*_property: core property tracking * + * Core mode resource tracking structure. All CRTC, encoders, and connectors + * enumerated by the driver are added here, as are global properties. Some + * global restrictions are also here, e.g. dimension restrictions. */ struct drm_mode_config { struct sx mutex; /* protects configuration (mode lists etc.) */ - struct drm_gem_names crtc_names; /* use this idr for all IDs, fb, crtc, connector, modes */ + struct drm_gem_names crtc_names; /* use this idr for all IDs, fb, crtc, connector, modes - just makes life easier */ /* this is limited to one for now */ int num_fb; struct list_head fb_list; @@ -682,7 +791,8 @@ struct drm_mode_config { /* output poll support */ bool poll_enabled; - struct timeout_task output_poll_task; + bool poll_running; + struct timeout_task output_poll_work; /* pointers to standard properties */ struct list_head property_blob_list; @@ -731,16 +841,6 @@ struct drm_prop_enum_list { char *name; }; -#if defined(MODE_SETTING_LOCKING_IS_NOT_BROKEN) -#define DRM_MODE_CONFIG_ASSERT_LOCKED(dev) \ - sx_assert(&dev->mode_config.mutex, SA_XLOCKED) -#else -#define DRM_MODE_CONFIG_ASSERT_LOCKED(dev) -#endif - -extern char *drm_get_dirty_info_name(int val); -extern char *drm_get_connector_status_name(enum drm_connector_status status); - extern int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc, const struct drm_crtc_funcs *funcs); @@ -752,6 +852,8 @@ extern int drm_connector_init(struct drm_device *dev, int connector_type); extern void drm_connector_cleanup(struct drm_connector *connector); +/* helper to unplug all connectors from sysfs for device */ +extern void drm_connector_unplug_all(struct drm_device *dev); extern int drm_encoder_init(struct drm_device *dev, struct drm_encoder *encoder, @@ -769,28 +871,34 @@ extern void drm_plane_cleanup(struct drm_plane *plane); extern void drm_encoder_cleanup(struct drm_encoder *encoder); extern char *drm_get_connector_name(struct drm_connector *connector); +extern char *drm_get_connector_status_name(enum drm_connector_status status); extern char *drm_get_dpms_name(int val); extern char *drm_get_dvi_i_subconnector_name(int val); extern char *drm_get_dvi_i_select_name(int val); extern char *drm_get_tv_subconnector_name(int val); +extern char *drm_get_dirty_info_name(int val); extern char *drm_get_tv_select_name(int val); extern void drm_fb_release(struct drm_file *file_priv); +extern int drm_mode_group_init(struct drm_device *dev, struct drm_mode_group *group); +extern void drm_mode_group_free(struct drm_mode_group *group); extern int drm_mode_group_init_legacy_group(struct drm_device *dev, struct drm_mode_group *group); +extern bool drm_probe_ddc(device_t adapter); extern struct edid *drm_get_edid(struct drm_connector *connector, device_t adapter); extern int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid); extern void drm_mode_probed_add(struct drm_connector *connector, struct drm_display_mode *mode); extern void drm_mode_remove(struct drm_connector *connector, struct drm_display_mode *mode); +extern void drm_mode_copy(struct drm_display_mode *dst, const struct drm_display_mode *src); extern struct drm_display_mode *drm_mode_duplicate(struct drm_device *dev, - const struct drm_display_mode *mode); -extern void drm_mode_debug_printmodeline(struct drm_display_mode *mode); + const struct drm_display_mode *mode); +extern void drm_mode_debug_printmodeline(const struct drm_display_mode *mode); extern void drm_mode_config_init(struct drm_device *dev); extern void drm_mode_config_reset(struct drm_device *dev); extern void drm_mode_config_cleanup(struct drm_device *dev); extern void drm_mode_set_name(struct drm_display_mode *mode); -extern bool drm_mode_equal(struct drm_display_mode *mode1, struct drm_display_mode *mode2); -extern int drm_mode_width(struct drm_display_mode *mode); -extern int drm_mode_height(struct drm_display_mode *mode); +extern bool drm_mode_equal(const struct drm_display_mode *mode1, const struct drm_display_mode *mode2); +extern int drm_mode_width(const struct drm_display_mode *mode); +extern int drm_mode_height(const struct drm_display_mode *mode); /* for us by fb module */ extern int drm_mode_attachmode_crtc(struct drm_device *dev, @@ -806,8 +914,8 @@ extern void drm_mode_validate_size(struct drm_device *dev, struct list_head *mode_list, int maxX, int maxY, int maxPitch); extern void drm_mode_validate_clocks(struct drm_device *dev, - struct list_head *mode_list, - int *min, int *max, int n_ranges); + struct list_head *mode_list, + int *min, int *max, int n_ranges); extern void drm_mode_prune_invalid(struct drm_device *dev, struct list_head *mode_list, bool verbose); extern void drm_mode_sort(struct list_head *mode_list); @@ -818,15 +926,6 @@ extern void drm_mode_set_crtcinfo(struct drm_display_mode *p, extern void drm_mode_connector_list_update(struct drm_connector *connector); extern int drm_mode_connector_update_edid_property(struct drm_connector *connector, struct edid *edid); -extern int drm_connector_property_set_value(struct drm_connector *connector, - struct drm_property *property, - uint64_t value); -extern int drm_connector_property_get_value(struct drm_connector *connector, - struct drm_property *property, - uint64_t *value); -void drm_object_attach_property(struct drm_mode_object *obj, - struct drm_property *property, - uint64_t init_val); extern int drm_object_property_set_value(struct drm_mode_object *obj, struct drm_property *property, uint64_t val); @@ -839,14 +938,18 @@ extern void drm_framebuffer_set_object(struct drm_device *dev, extern int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb, const struct drm_framebuffer_funcs *funcs); +extern void drm_framebuffer_unreference(struct drm_framebuffer *fb); +extern void drm_framebuffer_reference(struct drm_framebuffer *fb); +extern void drm_framebuffer_remove(struct drm_framebuffer *fb); extern void drm_framebuffer_cleanup(struct drm_framebuffer *fb); extern int drmfb_probe(struct drm_device *dev, struct drm_crtc *crtc); extern int drmfb_remove(struct drm_device *dev, struct drm_framebuffer *fb); extern void drm_crtc_probe_connector_modes(struct drm_device *dev, int maxX, int maxY); extern bool drm_crtc_in_use(struct drm_crtc *crtc); -extern void drm_connector_attach_property(struct drm_connector *connector, - struct drm_property *property, uint64_t init_val); +extern void drm_object_attach_property(struct drm_mode_object *obj, + struct drm_property *property, + uint64_t init_val); extern struct drm_property *drm_property_create(struct drm_device *dev, int flags, const char *name, int num_values); extern struct drm_property *drm_property_create_enum(struct drm_device *dev, int flags, @@ -854,9 +957,9 @@ extern struct drm_property *drm_property_create_enum(struct drm_device *dev, int const struct drm_prop_enum_list *props, int num_values); struct drm_property *drm_property_create_bitmask(struct drm_device *dev, - int flags, const char *name, - const struct drm_prop_enum_list *props, - int num_values); + int flags, const char *name, + const struct drm_prop_enum_list *props, + int num_values); struct drm_property *drm_property_create_range(struct drm_device *dev, int flags, const char *name, uint64_t min, uint64_t max); @@ -932,6 +1035,8 @@ extern int drm_mode_gamma_get_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int drm_mode_gamma_set_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); +extern u8 *drm_find_cea_extension(struct edid *edid); +extern u8 drm_match_cea_mode(struct drm_display_mode *to_match); extern bool drm_detect_hdmi_monitor(struct edid *edid); extern bool drm_detect_monitor_audio(struct edid *edid); extern int drm_mode_page_flip_ioctl(struct drm_device *dev, @@ -948,8 +1053,10 @@ extern struct drm_display_mode *drm_gtf_mode_complex(struct drm_device *dev, int GTF_2C, int GTF_K, int GTF_2J); extern int drm_add_modes_noedid(struct drm_connector *connector, int hdisplay, int vdisplay); +extern uint8_t drm_mode_cea_vic(const struct drm_display_mode *mode); extern int drm_edid_header_is_valid(const u8 *raw_edid); +extern bool drm_edid_block_valid(u8 *raw_edid, int block, bool print_bad_edid); extern bool drm_edid_is_valid(struct edid *edid); struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev, int hsize, int vsize, int fresh, diff --git a/sys/dev/drm2/drm_crtc_helper.c b/sys/dev/drm2/drm_crtc_helper.c index 9fb812006f0b..b6e4bd81abf1 100644 --- a/sys/dev/drm2/drm_crtc_helper.c +++ b/sys/dev/drm2/drm_crtc_helper.c @@ -32,48 +32,54 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); -#include <sys/param.h> -#include <sys/systm.h> #include <dev/drm2/drmP.h> #include <dev/drm2/drm_crtc.h> #include <dev/drm2/drm_fourcc.h> #include <dev/drm2/drm_crtc_helper.h> #include <dev/drm2/drm_fb_helper.h> +#include <dev/drm2/drm_edid.h> -bool -drm_fetch_cmdline_mode_from_kenv(struct drm_connector *connector, - struct drm_cmdline_mode *cmdline_mode) +/** + * drm_helper_move_panel_connectors_to_head() - move panels to the front in the + * connector list + * @dev: drm device to operate on + * + * Some userspace presumes that the first connected connector is the main + * display, where it's supposed to display e.g. the login screen. For + * laptops, this should be the main panel. Use this function to sort all + * (eDP/LVDS) panels to the front of the connector list, instead of + * painstakingly trying to initialize them in the right order. + */ +void drm_helper_move_panel_connectors_to_head(struct drm_device *dev) { - char *tun_var_name, *tun_mode; - static const char tun_prefix[] = "drm_mode."; - bool res; - - res = false; - tun_var_name = malloc(sizeof(tun_prefix) + - strlen(drm_get_connector_name(connector)), M_TEMP, M_WAITOK); - strcpy(tun_var_name, tun_prefix); - strcat(tun_var_name, drm_get_connector_name(connector)); - tun_mode = kern_getenv(tun_var_name); - if (tun_mode != NULL) { - res = drm_mode_parse_command_line_for_connector(tun_mode, - connector, cmdline_mode); - freeenv(tun_mode); + struct drm_connector *connector, *tmp; + struct list_head panel_list; + + INIT_LIST_HEAD(&panel_list); + + list_for_each_entry_safe(connector, tmp, + &dev->mode_config.connector_list, head) { + if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS || + connector->connector_type == DRM_MODE_CONNECTOR_eDP) + list_move_tail(&connector->head, &panel_list); } - free(tun_var_name, M_TEMP); - return (res); + + list_splice(&panel_list, &dev->mode_config.connector_list); } +EXPORT_SYMBOL(drm_helper_move_panel_connectors_to_head); static bool drm_kms_helper_poll = true; +module_param_named(poll, drm_kms_helper_poll, bool, 0600); static void drm_mode_validate_flag(struct drm_connector *connector, int flags) { - struct drm_display_mode *mode, *t; + struct drm_display_mode *mode; if (flags == (DRM_MODE_FLAG_DBLSCAN | DRM_MODE_FLAG_INTERLACE)) return; - list_for_each_entry_safe(mode, t, &connector->modes, head) { + list_for_each_entry(mode, &connector->modes, head) { if ((mode->flags & DRM_MODE_FLAG_INTERLACE) && !(flags & DRM_MODE_FLAG_INTERLACE)) mode->status = MODE_NO_INTERLACE; @@ -87,22 +93,21 @@ static void drm_mode_validate_flag(struct drm_connector *connector, /** * drm_helper_probe_single_connector_modes - get complete set of display modes - * @dev: DRM device + * @connector: connector to probe * @maxX: max width for modes * @maxY: max height for modes * * LOCKING: * Caller must hold mode config lock. * - * Based on @dev's mode_config layout, scan all the connectors and try to detect - * modes on them. Modes will first be added to the connector's probed_modes - * list, then culled (based on validity and the @maxX, @maxY parameters) and - * put into the normal modes list. - * - * Intended to be used either at bootup time or when major configuration - * changes have occurred. + * Based on the helper callbacks implemented by @connector try to detect all + * valid modes. Modes will first be added to the connector's probed_modes list, + * then culled (based on validity and the @maxX, @maxY parameters) and put into + * the normal modes list. * - * FIXME: take into account monitor limits + * Intended to be use as a generic implementation of the ->probe() @connector + * callback for drivers that use the crtc helpers for output mode filtering and + * detection. * * RETURNS: * Number of modes found on @connector. @@ -111,17 +116,16 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector, uint32_t maxX, uint32_t maxY) { struct drm_device *dev = connector->dev; - struct drm_display_mode *mode, *t; + struct drm_display_mode *mode; struct drm_connector_helper_funcs *connector_funcs = connector->helper_private; - struct drm_cmdline_mode cmdline_mode; int count = 0; int mode_flags = 0; DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", connector->base.id, drm_get_connector_name(connector)); /* set all modes to the unverified state */ - list_for_each_entry_safe(mode, t, &connector->modes, head) + list_for_each_entry(mode, &connector->modes, head) mode->status = MODE_UNVERIFIED; if (connector->force) { @@ -133,9 +137,14 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector, connector->funcs->force(connector); } else { connector->status = connector->funcs->detect(connector, true); - drm_kms_helper_poll_enable(dev); } + /* Re-enable polling in case the global poll config changed. */ + if (drm_kms_helper_poll != dev->mode_config.poll_running) + drm_kms_helper_poll_enable(dev); + + dev->mode_config.poll_running = drm_kms_helper_poll; + if (connector->status == connector_status_disconnected) { DRM_DEBUG_KMS("[CONNECTOR:%d:%s] disconnected\n", connector->base.id, drm_get_connector_name(connector)); @@ -143,26 +152,14 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector, goto prune; } - count = (*connector_funcs->get_modes)(connector); - if (count == 0 && drm_fetch_cmdline_mode_from_kenv(connector, - &cmdline_mode)) { - mode = drm_mode_create_from_cmdline_mode(dev, - &cmdline_mode); - if (mode != NULL) { - DRM_DEBUG_KMS( - "[CONNECTOR:%d:%s] found manual override ", - connector->base.id, - drm_get_connector_name(connector)); - drm_mode_debug_printmodeline(mode); - drm_mode_probed_add(connector, mode); - count++; - } else { - DRM_ERROR( - "[CONNECTOR:%d:%s] manual override mode: parse error\n", - connector->base.id, - drm_get_connector_name(connector)); - } - } +#ifdef FREEBSD_NOTYET +#ifdef CONFIG_DRM_LOAD_EDID_FIRMWARE + count = drm_load_edid_firmware(connector); + if (count == 0) +#endif +#endif /* FREEBSD_NOTYET */ + count = (*connector_funcs->get_modes)(connector); + if (count == 0 && connector->status == connector_status_connected) count = drm_add_modes_noedid(connector, 1024, 768); if (count == 0) @@ -180,7 +177,7 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector, mode_flags |= DRM_MODE_FLAG_DBLSCAN; drm_mode_validate_flag(connector, mode_flags); - list_for_each_entry_safe(mode, t, &connector->modes, head) { + list_for_each_entry(mode, &connector->modes, head) { if (mode->status == MODE_OK) mode->status = connector_funcs->mode_valid(connector, mode); @@ -196,7 +193,7 @@ prune: DRM_DEBUG_KMS("[CONNECTOR:%d:%s] probed modes :\n", connector->base.id, drm_get_connector_name(connector)); - list_for_each_entry_safe(mode, t, &connector->modes, head) { + list_for_each_entry(mode, &connector->modes, head) { mode->vrefresh = drm_mode_vrefresh(mode); drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); @@ -205,6 +202,7 @@ prune: return count; } +EXPORT_SYMBOL(drm_helper_probe_single_connector_modes); /** * drm_helper_encoder_in_use - check if a given encoder is in use @@ -227,6 +225,7 @@ bool drm_helper_encoder_in_use(struct drm_encoder *encoder) return true; return false; } +EXPORT_SYMBOL(drm_helper_encoder_in_use); /** * drm_helper_crtc_in_use - check if a given CRTC is in a mode_config @@ -250,6 +249,7 @@ bool drm_helper_crtc_in_use(struct drm_crtc *crtc) return true; return false; } +EXPORT_SYMBOL(drm_helper_crtc_in_use); static void drm_encoder_disable(struct drm_encoder *encoder) @@ -305,6 +305,7 @@ void drm_helper_disable_unused_functions(struct drm_device *dev) } } } +EXPORT_SYMBOL(drm_helper_disable_unused_functions); /** * drm_encoder_crtc_ok - can a given crtc drive a given encoder? @@ -360,17 +361,24 @@ drm_crtc_prepare_encoders(struct drm_device *dev) } /** - * drm_crtc_set_mode - set a mode + * drm_crtc_helper_set_mode - internal helper to set a mode * @crtc: CRTC to program * @mode: mode to use - * @x: width of mode - * @y: height of mode + * @x: horizontal offset into the surface + * @y: vertical offset into the surface + * @old_fb: old framebuffer, for cleanup * * LOCKING: * Caller must hold mode config lock. * * Try to set @mode on @crtc. Give @crtc and its associated connectors a chance - * to fixup or reject the mode prior to trying to set it. + * to fixup or reject the mode prior to trying to set it. This is an internal + * helper that drivers could e.g. use to update properties that require the + * entire output pipe to be disabled and re-enabled in a new configuration. For + * example for changing whether audio is enabled on a hdmi link or for changing + * panel fitter or dither attributes. It is also called by the + * drm_crtc_helper_set_config() helper function to drive the mode setting + * sequence. * * RETURNS: * True if the mode was set successfully, or false otherwise. @@ -419,11 +427,13 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, encoder_funcs = encoder->helper_private; if (!(ret = encoder_funcs->mode_fixup(encoder, mode, adjusted_mode))) { + DRM_DEBUG_KMS("Encoder fixup failed\n"); goto done; } } if (!(ret = crtc_funcs->mode_fixup(crtc, mode, adjusted_mode))) { + DRM_DEBUG_KMS("CRTC fixup failed\n"); goto done; } DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id); @@ -495,6 +505,8 @@ done: return ret; } +EXPORT_SYMBOL(drm_crtc_helper_set_mode); + static int drm_crtc_helper_disable(struct drm_crtc *crtc) @@ -522,20 +534,19 @@ drm_crtc_helper_disable(struct drm_crtc *crtc) /** * drm_crtc_helper_set_config - set a new config from userspace - * @crtc: CRTC to setup - * @crtc_info: user provided configuration - * @new_mode: new mode to set - * @connector_set: set of connectors for the new config - * @fb: new framebuffer + * @set: mode set configuration * * LOCKING: * Caller must hold mode config lock. * - * Setup a new configuration, provided by the user in @crtc_info, and enable - * it. + * Setup a new configuration, provided by the upper layers (either an ioctl call + * from userspace or internally e.g. from the fbdev suppport code) in @set, and + * enable it. This is the main helper functions for drivers that implement + * kernel mode setting with the crtc helper functions and the assorted + * ->prepare(), ->modeset() and ->commit() helper callbacks. * * RETURNS: - * Zero. (FIXME) + * Returns 0 on success, -ERRNO on failure. */ int drm_crtc_helper_set_config(struct drm_mode_set *set) { @@ -581,12 +592,25 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) /* Allocate space for the backup of all (non-pointer) crtc, encoder and * connector data. */ - save_crtcs = malloc(dev->mode_config.num_crtc * sizeof(struct drm_crtc), - DRM_MEM_KMS, M_WAITOK | M_ZERO); + save_crtcs = malloc(dev->mode_config.num_crtc * + sizeof(struct drm_crtc), DRM_MEM_KMS, M_NOWAIT | M_ZERO); + if (!save_crtcs) + return -ENOMEM; + save_encoders = malloc(dev->mode_config.num_encoder * - sizeof(struct drm_encoder), DRM_MEM_KMS, M_WAITOK | M_ZERO); + sizeof(struct drm_encoder), DRM_MEM_KMS, M_NOWAIT | M_ZERO); + if (!save_encoders) { + free(save_crtcs, DRM_MEM_KMS); + return -ENOMEM; + } + save_connectors = malloc(dev->mode_config.num_connector * - sizeof(struct drm_connector), DRM_MEM_KMS, M_WAITOK | M_ZERO); + sizeof(struct drm_connector), DRM_MEM_KMS, M_NOWAIT | M_ZERO); + if (!save_connectors) { + free(save_crtcs, DRM_MEM_KMS); + free(save_encoders, DRM_MEM_KMS); + return -ENOMEM; + } /* Copy data. Note that driver private data is not affected. * Should anything bad happen only the expected state is @@ -622,6 +646,11 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) mode_changed = true; } else if (set->fb == NULL) { mode_changed = true; + } else if (set->fb->depth != set->crtc->fb->depth) { + mode_changed = true; + } else if (set->fb->bits_per_pixel != + set->crtc->fb->bits_per_pixel) { + mode_changed = true; } else fb_changed = true; } @@ -732,7 +761,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) for (i = 0; i < set->num_connectors; i++) { DRM_DEBUG_KMS("\t[CONNECTOR:%d:%s] set DPMS on\n", set->connectors[i]->base.id, drm_get_connector_name(set->connectors[i])); - set->connectors[i]->dpms = DRM_MODE_DPMS_ON; + set->connectors[i]->funcs->dpms(set->connectors[i], DRM_MODE_DPMS_ON); } } drm_helper_disable_unused_functions(dev); @@ -784,6 +813,7 @@ fail: free(save_crtcs, DRM_MEM_KMS); return ret; } +EXPORT_SYMBOL(drm_crtc_helper_set_config); static int drm_helper_choose_encoder_dpms(struct drm_encoder *encoder) { @@ -812,12 +842,14 @@ static int drm_helper_choose_crtc_dpms(struct drm_crtc *crtc) } /** - * drm_helper_connector_dpms - * @connector affected connector - * @mode DPMS mode + * drm_helper_connector_dpms() - connector dpms helper implementation + * @connector: affected connector + * @mode: DPMS mode * - * Calls the low-level connector DPMS function, then - * calls appropriate encoder and crtc DPMS functions as well + * This is the main helper function provided by the crtc helper framework for + * implementing the DPMS connector attribute. It computes the new desired DPMS + * state for all encoders and crtcs in the output mesh and calls the ->dpms() + * callback provided by the driver appropriately. */ void drm_helper_connector_dpms(struct drm_connector *connector, int mode) { @@ -865,6 +897,7 @@ void drm_helper_connector_dpms(struct drm_connector *connector, int mode) return; } +EXPORT_SYMBOL(drm_helper_connector_dpms); int drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb, struct drm_mode_fb_cmd2 *mode_cmd) @@ -883,6 +916,7 @@ int drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb, return 0; } +EXPORT_SYMBOL(drm_helper_mode_fill_fb_struct); int drm_helper_resume_force_mode(struct drm_device *dev) { @@ -900,7 +934,7 @@ int drm_helper_resume_force_mode(struct drm_device *dev) ret = drm_crtc_helper_set_mode(crtc, &crtc->mode, crtc->x, crtc->y, crtc->fb); - if (!ret) + if (ret == false) DRM_ERROR("failed to set mode on crtc %p\n", crtc); /* Turn off outputs that were already powered off */ @@ -913,24 +947,36 @@ int drm_helper_resume_force_mode(struct drm_device *dev) encoder_funcs = encoder->helper_private; if (encoder_funcs->dpms) (*encoder_funcs->dpms) (encoder, - drm_helper_choose_encoder_dpms(encoder)); + drm_helper_choose_encoder_dpms(encoder)); } crtc_funcs = crtc->helper_private; if (crtc_funcs->dpms) (*crtc_funcs->dpms) (crtc, - drm_helper_choose_crtc_dpms(crtc)); + drm_helper_choose_crtc_dpms(crtc)); } } /* disable the unused connectors while restoring the modesetting */ drm_helper_disable_unused_functions(dev); return 0; } +EXPORT_SYMBOL(drm_helper_resume_force_mode); -#define DRM_OUTPUT_POLL_PERIOD (10 * hz) +void drm_kms_helper_hotplug_event(struct drm_device *dev) +{ + /* send a uevent + call fbdev */ +#ifdef FREEBSD_NOTYET + drm_sysfs_hotplug_event(dev); +#endif /* FREEBSD_NOTYET */ + if (dev->mode_config.funcs->output_poll_changed) + dev->mode_config.funcs->output_poll_changed(dev); +} +EXPORT_SYMBOL(drm_kms_helper_hotplug_event); + +#define DRM_OUTPUT_POLL_PERIOD (10*HZ) static void output_poll_execute(void *ctx, int pending) { - struct drm_device *dev; + struct drm_device *dev = ctx; struct drm_connector *connector; enum drm_connector_status old_status; bool repoll = false, changed = false; @@ -938,26 +984,25 @@ static void output_poll_execute(void *ctx, int pending) if (!drm_kms_helper_poll) return; - dev = ctx; - sx_xlock(&dev->mode_config.mutex); list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - /* if this is HPD or polled don't check it - - TV out for instance */ - if (!connector->polled) + /* Ignore forced connectors. */ + if (connector->force) continue; - else if (connector->polled & (DRM_CONNECTOR_POLL_CONNECT | - DRM_CONNECTOR_POLL_DISCONNECT)) - repoll = true; + /* Ignore HPD capable connectors and connectors where we don't + * want any hotplug detection at all for polling. */ + if (!connector->polled || connector->polled == DRM_CONNECTOR_POLL_HPD) + continue; + + repoll = true; old_status = connector->status; /* if we are connected and don't want to poll for disconnect skip it */ if (old_status == connector_status_connected && - !(connector->polled & DRM_CONNECTOR_POLL_DISCONNECT) && - !(connector->polled & DRM_CONNECTOR_POLL_HPD)) + !(connector->polled & DRM_CONNECTOR_POLL_DISCONNECT)) continue; connector->status = connector->funcs->detect(connector, false); @@ -971,20 +1016,13 @@ static void output_poll_execute(void *ctx, int pending) sx_xunlock(&dev->mode_config.mutex); - if (changed) { -#if 0 - /* send a uevent + call fbdev */ - drm_sysfs_hotplug_event(dev); -#endif - if (dev->mode_config.funcs->output_poll_changed) - dev->mode_config.funcs->output_poll_changed(dev); - } + if (changed) + drm_kms_helper_hotplug_event(dev); - if (repoll) { + if (repoll) taskqueue_enqueue_timeout(taskqueue_thread, - &dev->mode_config.output_poll_task, + &dev->mode_config.output_poll_work, DRM_OUTPUT_POLL_PERIOD); - } } void drm_kms_helper_poll_disable(struct drm_device *dev) @@ -992,8 +1030,9 @@ void drm_kms_helper_poll_disable(struct drm_device *dev) if (!dev->mode_config.poll_enabled) return; taskqueue_cancel_timeout(taskqueue_thread, - &dev->mode_config.output_poll_task, NULL); + &dev->mode_config.output_poll_work, NULL); } +EXPORT_SYMBOL(drm_kms_helper_poll_disable); void drm_kms_helper_poll_enable(struct drm_device *dev) { @@ -1004,40 +1043,63 @@ void drm_kms_helper_poll_enable(struct drm_device *dev) return; list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - if (connector->polled) + if (connector->polled & (DRM_CONNECTOR_POLL_CONNECT | + DRM_CONNECTOR_POLL_DISCONNECT)) poll = true; } - if (poll) { + if (poll) taskqueue_enqueue_timeout(taskqueue_thread, - &dev->mode_config.output_poll_task, DRM_OUTPUT_POLL_PERIOD); - } + &dev->mode_config.output_poll_work, DRM_OUTPUT_POLL_PERIOD); } +EXPORT_SYMBOL(drm_kms_helper_poll_enable); void drm_kms_helper_poll_init(struct drm_device *dev) { - - TIMEOUT_TASK_INIT(taskqueue_thread, &dev->mode_config.output_poll_task, + TIMEOUT_TASK_INIT(taskqueue_thread, &dev->mode_config.output_poll_work, 0, output_poll_execute, dev); dev->mode_config.poll_enabled = true; drm_kms_helper_poll_enable(dev); } +EXPORT_SYMBOL(drm_kms_helper_poll_init); void drm_kms_helper_poll_fini(struct drm_device *dev) { drm_kms_helper_poll_disable(dev); } +EXPORT_SYMBOL(drm_kms_helper_poll_fini); void drm_helper_hpd_irq_event(struct drm_device *dev) { + struct drm_connector *connector; + enum drm_connector_status old_status; + bool changed = false; + if (!dev->mode_config.poll_enabled) return; - /* kill timer and schedule immediate execution, this doesn't block */ - taskqueue_cancel_timeout(taskqueue_thread, - &dev->mode_config.output_poll_task, NULL); - if (drm_kms_helper_poll) - taskqueue_enqueue_timeout(taskqueue_thread, - &dev->mode_config.output_poll_task, 0); + sx_xlock(&dev->mode_config.mutex); + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + + /* Only handle HPD capable connectors. */ + if (!(connector->polled & DRM_CONNECTOR_POLL_HPD)) + continue; + + old_status = connector->status; + + connector->status = connector->funcs->detect(connector, false); + DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %d to %d\n", + connector->base.id, + drm_get_connector_name(connector), + old_status, connector->status); + if (old_status != connector->status) + changed = true; + } + + sx_xunlock(&dev->mode_config.mutex); + + if (changed) + drm_kms_helper_hotplug_event(dev); } +EXPORT_SYMBOL(drm_helper_hpd_irq_event); diff --git a/sys/dev/drm2/drm_crtc_helper.h b/sys/dev/drm2/drm_crtc_helper.h index 0f36b1fa3d40..e5961dca77e1 100644 --- a/sys/dev/drm2/drm_crtc_helper.h +++ b/sys/dev/drm2/drm_crtc_helper.h @@ -40,6 +40,13 @@ enum mode_set_atomic { ENTER_ATOMIC_MODE_SET, }; +/** + * drm_crtc_helper_funcs - helper operations for CRTCs + * @mode_fixup: try to fixup proposed mode for this connector + * @mode_set: set this mode + * + * The helper operations are called by the mid-layer CRTC helper. + */ struct drm_crtc_helper_funcs { /* * Control power levels on the CRTC. If the mode passed in is @@ -72,13 +79,20 @@ struct drm_crtc_helper_funcs { void (*disable)(struct drm_crtc *crtc); }; +/** + * drm_encoder_helper_funcs - helper operations for encoders + * @mode_fixup: try to fixup proposed mode for this connector + * @mode_set: set this mode + * + * The helper operations are called by the mid-layer CRTC helper. + */ struct drm_encoder_helper_funcs { void (*dpms)(struct drm_encoder *encoder, int mode); void (*save)(struct drm_encoder *encoder); void (*restore)(struct drm_encoder *encoder); bool (*mode_fixup)(struct drm_encoder *encoder, - struct drm_display_mode *mode, + const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode); void (*prepare)(struct drm_encoder *encoder); void (*commit)(struct drm_encoder *encoder); @@ -93,6 +107,13 @@ struct drm_encoder_helper_funcs { void (*disable)(struct drm_encoder *encoder); }; +/** + * drm_connector_helper_funcs - helper operations for connectors + * @get_modes: get mode list for this connector + * @mode_valid: is this mode valid on the given connector? + * + * The helper operations are called by the mid-layer CRTC helper. + */ struct drm_connector_helper_funcs { int (*get_modes)(struct drm_connector *connector); int (*mode_valid)(struct drm_connector *connector, @@ -112,6 +133,8 @@ extern bool drm_helper_encoder_in_use(struct drm_encoder *encoder); extern void drm_helper_connector_dpms(struct drm_connector *connector, int mode); +extern void drm_helper_move_panel_connectors_to_head(struct drm_device *); + extern int drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb, struct drm_mode_fb_cmd2 *mode_cmd); @@ -137,10 +160,8 @@ extern int drm_helper_resume_force_mode(struct drm_device *dev); extern void drm_kms_helper_poll_init(struct drm_device *dev); extern void drm_kms_helper_poll_fini(struct drm_device *dev); extern void drm_helper_hpd_irq_event(struct drm_device *dev); +extern void drm_kms_helper_hotplug_event(struct drm_device *dev); extern void drm_kms_helper_poll_disable(struct drm_device *dev); extern void drm_kms_helper_poll_enable(struct drm_device *dev); - -extern bool drm_fetch_cmdline_mode_from_kenv(struct drm_connector *connector, - struct drm_cmdline_mode *cmdline_mode); #endif diff --git a/sys/dev/drm2/drm_dma.c b/sys/dev/drm2/drm_dma.c index c0a1c809bf96..380be2b8ca31 100644 --- a/sys/dev/drm2/drm_dma.c +++ b/sys/dev/drm2/drm_dma.c @@ -1,4 +1,14 @@ +/** + * \file drm_dma.c + * DMA IOCTL and function support + * + * \author Rickard E. (Rik) Faith <faith@valinux.com> + * \author Gareth Hughes <gareth@valinux.com> + */ + /*- + * Created: Fri Mar 19 14:30:16 1999 by faith@valinux.com + * * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas. * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. * All Rights Reserved. @@ -21,64 +31,72 @@ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: - * Rickard E. (Rik) Faith <faith@valinux.com> - * Gareth Hughes <gareth@valinux.com> - * */ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); -/** @file drm_dma.c - * Support code for DMA buffer management. - * - * The implementation used to be significantly more complicated, but the - * complexity has been moved into the drivers as different buffer management - * schemes evolved. - */ - #include <dev/drm2/drmP.h> +/** + * Initialize the DMA data. + * + * \param dev DRM device. + * \return zero on success or a negative value on failure. + * + * Allocate and initialize a drm_device_dma structure. + */ int drm_dma_setup(struct drm_device *dev) { + int i; dev->dma = malloc(sizeof(*dev->dma), DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); - if (dev->dma == NULL) - return ENOMEM; + if (!dev->dma) + return -ENOMEM; - DRM_SPININIT(&dev->dma_lock, "drmdma"); + for (i = 0; i <= DRM_MAX_ORDER; i++) + memset(&dev->dma->bufs[i], 0, sizeof(dev->dma->bufs[0])); return 0; } +/** + * Cleanup the DMA resources. + * + * \param dev DRM device. + * + * Free all pages associated with DMA buffers, the buffers and pages lists, and + * finally the drm_device::dma structure itself. + */ void drm_dma_takedown(struct drm_device *dev) { - drm_device_dma_t *dma = dev->dma; - int i, j; + struct drm_device_dma *dma = dev->dma; + int i, j; - if (dma == NULL) + if (!dma) return; /* Clear dma buffers */ for (i = 0; i <= DRM_MAX_ORDER; i++) { if (dma->bufs[i].seg_count) { DRM_DEBUG("order %d: buf_count = %d," - " seg_count = %d\n", i, dma->bufs[i].buf_count, - dma->bufs[i].seg_count); + " seg_count = %d\n", + i, + dma->bufs[i].buf_count, + dma->bufs[i].seg_count); for (j = 0; j < dma->bufs[i].seg_count; j++) { - drm_pci_free(dev, dma->bufs[i].seglist[j]); + if (dma->bufs[i].seglist[j]) { + drm_pci_free(dev, dma->bufs[i].seglist[j]); + } } free(dma->bufs[i].seglist, DRM_MEM_SEGS); } - - if (dma->bufs[i].buf_count) { - for (j = 0; j < dma->bufs[i].buf_count; j++) { + if (dma->bufs[i].buf_count) { + for (j = 0; j < dma->bufs[i].buf_count; j++) { free(dma->bufs[i].buflist[j].dev_private, DRM_MEM_BUFS); } - free(dma->bufs[i].buflist, DRM_MEM_BUFS); + free(dma->bufs[i].buflist, DRM_MEM_BUFS); } } @@ -86,28 +104,42 @@ void drm_dma_takedown(struct drm_device *dev) free(dma->pagelist, DRM_MEM_PAGES); free(dev->dma, DRM_MEM_DRIVER); dev->dma = NULL; - DRM_SPINUNINIT(&dev->dma_lock); } - -void drm_free_buffer(struct drm_device *dev, drm_buf_t *buf) +/** + * Free a buffer. + * + * \param dev DRM device. + * \param buf buffer to free. + * + * Resets the fields of \p buf. + */ +void drm_free_buffer(struct drm_device *dev, struct drm_buf * buf) { if (!buf) return; - buf->pending = 0; - buf->file_priv= NULL; - buf->used = 0; + buf->waiting = 0; + buf->pending = 0; + buf->file_priv = NULL; + buf->used = 0; } -void drm_reclaim_buffers(struct drm_device *dev, struct drm_file *file_priv) +/** + * Reclaim the buffers. + * + * \param file_priv DRM file private. + * + * Frees each buffer associated with \p file_priv not already on the hardware. + */ +void drm_core_reclaim_buffers(struct drm_device *dev, + struct drm_file *file_priv) { - drm_device_dma_t *dma = dev->dma; - int i; + struct drm_device_dma *dma = dev->dma; + int i; if (!dma) return; - for (i = 0; i < dma->buf_count; i++) { if (dma->buflist[i]->file_priv == file_priv) { switch (dma->buflist[i]->list) { @@ -125,15 +157,4 @@ void drm_reclaim_buffers(struct drm_device *dev, struct drm_file *file_priv) } } -/* Call into the driver-specific DMA handler */ -int drm_dma(struct drm_device *dev, void *data, struct drm_file *file_priv) -{ - - if (dev->driver->dma_ioctl) { - /* shared code returns -errno */ - return -dev->driver->dma_ioctl(dev, data, file_priv); - } else { - DRM_DEBUG("DMA ioctl on driver with no dma handler\n"); - return EINVAL; - } -} +EXPORT_SYMBOL(drm_core_reclaim_buffers); diff --git a/sys/dev/drm2/drm_dp_helper.c b/sys/dev/drm2/drm_dp_helper.c index d4a03603ed09..5b53e894333e 100644 --- a/sys/dev/drm2/drm_dp_helper.c +++ b/sys/dev/drm2/drm_dp_helper.c @@ -35,6 +35,7 @@ __FBSDID("$FreeBSD$"); * blocks, ... */ +/* Helpers for DP link training */ static u8 dp_link_status(u8 link_status[DP_LINK_STATUS_SIZE], int r) { return link_status[r - DP_LANE0_1_STATUS]; @@ -67,6 +68,7 @@ bool drm_dp_channel_eq_ok(u8 link_status[DP_LINK_STATUS_SIZE], } return true; } +EXPORT_SYMBOL(drm_dp_channel_eq_ok); bool drm_dp_clock_recovery_ok(u8 link_status[DP_LINK_STATUS_SIZE], int lane_count) @@ -81,6 +83,7 @@ bool drm_dp_clock_recovery_ok(u8 link_status[DP_LINK_STATUS_SIZE], } return true; } +EXPORT_SYMBOL(drm_dp_clock_recovery_ok); u8 drm_dp_get_adjust_request_voltage(u8 link_status[DP_LINK_STATUS_SIZE], int lane) @@ -93,6 +96,7 @@ u8 drm_dp_get_adjust_request_voltage(u8 link_status[DP_LINK_STATUS_SIZE], return ((l >> s) & 0x3) << DP_TRAIN_VOLTAGE_SWING_SHIFT; } +EXPORT_SYMBOL(drm_dp_get_adjust_request_voltage); u8 drm_dp_get_adjust_request_pre_emphasis(u8 link_status[DP_LINK_STATUS_SIZE], int lane) @@ -105,20 +109,23 @@ u8 drm_dp_get_adjust_request_pre_emphasis(u8 link_status[DP_LINK_STATUS_SIZE], return ((l >> s) & 0x3) << DP_TRAIN_PRE_EMPHASIS_SHIFT; } +EXPORT_SYMBOL(drm_dp_get_adjust_request_pre_emphasis); void drm_dp_link_train_clock_recovery_delay(u8 dpcd[DP_RECEIVER_CAP_SIZE]) { if (dpcd[DP_TRAINING_AUX_RD_INTERVAL] == 0) - DRM_UDELAY(100); + udelay(100); else - DRM_MDELAY(dpcd[DP_TRAINING_AUX_RD_INTERVAL] * 4); + mdelay(dpcd[DP_TRAINING_AUX_RD_INTERVAL] * 4); } +EXPORT_SYMBOL(drm_dp_link_train_clock_recovery_delay); void drm_dp_link_train_channel_eq_delay(u8 dpcd[DP_RECEIVER_CAP_SIZE]) { if (dpcd[DP_TRAINING_AUX_RD_INTERVAL] == 0) - DRM_UDELAY(400); + udelay(400); else - DRM_MDELAY(dpcd[DP_TRAINING_AUX_RD_INTERVAL] * 4); + mdelay(dpcd[DP_TRAINING_AUX_RD_INTERVAL] * 4); } +EXPORT_SYMBOL(drm_dp_link_train_channel_eq_delay); u8 drm_dp_link_rate_to_bw_code(int link_rate) { @@ -132,6 +139,7 @@ u8 drm_dp_link_rate_to_bw_code(int link_rate) return DP_LINK_BW_5_4; } } +EXPORT_SYMBOL(drm_dp_link_rate_to_bw_code); int drm_dp_bw_code_to_link_rate(u8 link_bw) { @@ -145,3 +153,4 @@ int drm_dp_bw_code_to_link_rate(u8 link_bw) return 540000; } } +EXPORT_SYMBOL(drm_dp_bw_code_to_link_rate); diff --git a/sys/dev/drm2/drm_dp_iic_helper.c b/sys/dev/drm2/drm_dp_iic_helper.c index c4e580307fbf..492e2f9ec559 100644 --- a/sys/dev/drm2/drm_dp_iic_helper.c +++ b/sys/dev/drm2/drm_dp_iic_helper.c @@ -41,7 +41,9 @@ iic_dp_aux_transaction(device_t idev, int mode, uint8_t write_byte, aux_data = device_get_softc(idev); ret = (*aux_data->aux_ch)(idev, mode, write_byte, read_byte); - return (ret); + if (ret < 0) + return (ret); + return (0); } /* @@ -106,7 +108,7 @@ iic_dp_aux_put_byte(device_t idev, u8 byte) aux_data = device_get_softc(idev); if (!aux_data->running) - return (EIO); + return (-EIO); ret = iic_dp_aux_transaction(idev, MODE_I2C_WRITE, byte, NULL); return (ret); @@ -125,7 +127,7 @@ iic_dp_aux_get_byte(device_t idev, u8 *byte_ret) aux_data = device_get_softc(idev); if (!aux_data->running) - return (EIO); + return (-EIO); ret = iic_dp_aux_transaction(idev, MODE_I2C_READ, 0, byte_ret); return (ret); @@ -167,7 +169,7 @@ iic_dp_aux_xfer(device_t idev, struct iic_msg *msgs, uint32_t num) } iic_dp_aux_stop(idev, reading); DRM_DEBUG_KMS("dp_aux_xfer return %d\n", ret); - return (ret); + return (-ret); } static void @@ -183,7 +185,7 @@ iic_dp_aux_reset(device_t idev, u_char speed, u_char addr, u_char *oldaddr) { iic_dp_aux_reset_bus(idev); - return (0); + return (0); } static int @@ -255,7 +257,7 @@ iic_dp_aux_add_bus(device_t dev, const char *name, *adapter = data->port; } mtx_unlock(&Giant); - return (error); + return (-error); } static device_method_t drm_iic_dp_aux_methods[] = { diff --git a/sys/dev/drm2/drm_drawable.c b/sys/dev/drm2/drm_drawable.c deleted file mode 100644 index e8c4e02eaf4b..000000000000 --- a/sys/dev/drm2/drm_drawable.c +++ /dev/null @@ -1,173 +0,0 @@ -/*- - * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. - * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: - * Rickard E. (Rik) Faith <faith@valinux.com> - * Gareth Hughes <gareth@valinux.com> - * - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -/** @file drm_drawable.c - * This file implements ioctls to store information along with DRM drawables, - * such as the current set of cliprects for vblank-synced buffer swaps. - */ - -#include <dev/drm2/drmP.h> - -struct bsd_drm_drawable_info { - struct drm_drawable_info info; - int handle; - RB_ENTRY(bsd_drm_drawable_info) tree; -}; - -static int -drm_drawable_compare(struct bsd_drm_drawable_info *a, - struct bsd_drm_drawable_info *b) -{ - if (a->handle > b->handle) - return 1; - if (a->handle < b->handle) - return -1; - return 0; -} - -RB_GENERATE_STATIC(drawable_tree, bsd_drm_drawable_info, tree, - drm_drawable_compare); - -struct drm_drawable_info * -drm_get_drawable_info(struct drm_device *dev, int handle) -{ - struct bsd_drm_drawable_info find, *result; - - find.handle = handle; - result = RB_FIND(drawable_tree, &dev->drw_head, &find); - - return &result->info; -} - -int drm_adddraw(struct drm_device *dev, void *data, struct drm_file *file_priv) -{ - struct drm_draw *draw = data; - struct bsd_drm_drawable_info *info; - - info = malloc(sizeof(struct bsd_drm_drawable_info), DRM_MEM_DRAWABLE, - M_NOWAIT | M_ZERO); - if (info == NULL) - return ENOMEM; - - info->handle = alloc_unr(dev->drw_unrhdr); - DRM_SPINLOCK(&dev->drw_lock); - RB_INSERT(drawable_tree, &dev->drw_head, info); - draw->handle = info->handle; - DRM_SPINUNLOCK(&dev->drw_lock); - - DRM_DEBUG("%d\n", draw->handle); - - return 0; -} - -int drm_rmdraw(struct drm_device *dev, void *data, struct drm_file *file_priv) -{ - struct drm_draw *draw = (struct drm_draw *)data; - struct drm_drawable_info *info; - - DRM_SPINLOCK(&dev->drw_lock); - info = drm_get_drawable_info(dev, draw->handle); - if (info != NULL) { - RB_REMOVE(drawable_tree, &dev->drw_head, - (struct bsd_drm_drawable_info *)info); - DRM_SPINUNLOCK(&dev->drw_lock); - free_unr(dev->drw_unrhdr, draw->handle); - free(info->rects, DRM_MEM_DRAWABLE); - free(info, DRM_MEM_DRAWABLE); - return 0; - } else { - DRM_SPINUNLOCK(&dev->drw_lock); - return EINVAL; - } -} - -int drm_update_draw(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_drawable_info *info; - struct drm_update_draw *update = (struct drm_update_draw *)data; - int ret; - - info = drm_get_drawable_info(dev, update->handle); - if (info == NULL) - return EINVAL; - - switch (update->type) { - case DRM_DRAWABLE_CLIPRECTS: - DRM_SPINLOCK(&dev->drw_lock); - if (update->num != info->num_rects) { - free(info->rects, DRM_MEM_DRAWABLE); - info->rects = NULL; - info->num_rects = 0; - } - if (update->num == 0) { - DRM_SPINUNLOCK(&dev->drw_lock); - return 0; - } - if (info->rects == NULL) { - info->rects = malloc(sizeof(*info->rects) * - update->num, DRM_MEM_DRAWABLE, M_NOWAIT); - if (info->rects == NULL) { - DRM_SPINUNLOCK(&dev->drw_lock); - return ENOMEM; - } - info->num_rects = update->num; - } - /* For some reason the pointer arg is unsigned long long. */ - ret = copyin((void *)(intptr_t)update->data, info->rects, - sizeof(*info->rects) * info->num_rects); - DRM_SPINUNLOCK(&dev->drw_lock); - return ret; - default: - return EINVAL; - } -} - -void drm_drawable_free_all(struct drm_device *dev) -{ - struct bsd_drm_drawable_info *info, *next; - - DRM_SPINLOCK(&dev->drw_lock); - for (info = RB_MIN(drawable_tree, &dev->drw_head); - info != NULL ; info = next) { - next = RB_NEXT(drawable_tree, &dev->drw_head, info); - RB_REMOVE(drawable_tree, &dev->drw_head, - (struct bsd_drm_drawable_info *)info); - DRM_SPINUNLOCK(&dev->drw_lock); - free_unr(dev->drw_unrhdr, info->handle); - free(info->info.rects, DRM_MEM_DRAWABLE); - free(info, DRM_MEM_DRAWABLE); - DRM_SPINLOCK(&dev->drw_lock); - } - DRM_SPINUNLOCK(&dev->drw_lock); -} diff --git a/sys/dev/drm2/drm_drv.c b/sys/dev/drm2/drm_drv.c index b5150e1821c9..f4431a7d3e8a 100644 --- a/sys/dev/drm2/drm_drv.c +++ b/sys/dev/drm2/drm_drv.c @@ -1,4 +1,27 @@ -/*- +/** + * \file drm_drv.c + * Generic driver template + * + * \author Rickard E. (Rik) Faith <faith@valinux.com> + * \author Gareth Hughes <gareth@valinux.com> + * + * To use this template, you must at least define the following (samples + * given for the MGA driver): + * + * \code + * #define DRIVER_AUTHOR "VA Linux Systems, Inc." + * + * #define DRIVER_NAME "mga" + * #define DRIVER_DESC "Matrox G200/G400" + * #define DRIVER_DATE "20001127" + * + * #define drm_x mga_##x + * \endcode + */ + +/* + * Created: Thu Nov 23 03:10:50 2000 by gareth@valinux.com + * * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas. * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. * All Rights Reserved. @@ -21,94 +44,35 @@ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: - * Rickard E. (Rik) Faith <faith@valinux.com> - * Gareth Hughes <gareth@valinux.com> - * */ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); -/** @file drm_drv.c - * The catch-all file for DRM device support, including module setup/teardown, - * open/close, and ioctl dispatch. - */ - -#include <sys/limits.h> #include <sys/sysent.h> + #include <dev/drm2/drmP.h> -#include <dev/drm2/drm.h> #include <dev/drm2/drm_core.h> #include <dev/drm2/drm_global.h> -#include <dev/drm2/drm_sarea.h> -#include <dev/drm2/drm_mode.h> - -#ifdef DRM_DEBUG_DEFAULT_ON -int drm_debug_flag = (DRM_DEBUGBITS_DEBUG | DRM_DEBUGBITS_KMS | - DRM_DEBUGBITS_FAILED_IOCTL); -#else -int drm_debug_flag = 0; -#endif -int drm_notyet_flag = 0; - -unsigned int drm_vblank_offdelay = 5000; /* Default to 5000 msecs. */ -unsigned int drm_timestamp_precision = 20; /* Default to 20 usecs. */ - -/* - * Default to use monotonic timestamps for wait-for-vblank and page-flip - * complete events. - */ -unsigned int drm_timestamp_monotonic = 1; -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); -static int drm_mmap_single(struct cdev *kdev, vm_ooffset_t *offset, - vm_size_t size, struct vm_object **obj_res, int nprot); +struct sx drm_global_mutex; -static int -drm_modevent(module_t mod, int type, void *data) -{ - - switch (type) { - case MOD_LOAD: - TUNABLE_INT_FETCH("drm.debug", &drm_debug_flag); - TUNABLE_INT_FETCH("drm.notyet", &drm_notyet_flag); - break; - } - return (0); -} - -static moduledata_t drm_mod = { - "drmn", - drm_modevent, - 0 -}; -DECLARE_MODULE(drmn, drm_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST); -MODULE_VERSION(drmn, 1); -MODULE_DEPEND(drmn, agp, 1, 1, 1); -MODULE_DEPEND(drmn, pci, 1, 1, 1); -MODULE_DEPEND(drmn, mem, 1, 1, 1); -MODULE_DEPEND(drmn, iicbus, 1, 1, 1); - -static drm_ioctl_desc_t drm_ioctls[256] = { - DRM_IOCTL_DEF(DRM_IOCTL_VERSION, drm_version, 0), +/** Ioctl table */ +static struct drm_ioctl_desc drm_ioctls[] = { + DRM_IOCTL_DEF(DRM_IOCTL_VERSION, drm_version, DRM_UNLOCKED), 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_GET_MAP, drm_getmap, DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_IOCTL_GET_CLIENT, drm_getclient, DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_IOCTL_GET_STATS, drm_getstats, DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_GET_CAP, drm_getcap, DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_IOCTL_SET_VERSION, drm_setversion, DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_IOCTL_SET_VERSION, drm_setversion, DRM_MASTER), 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_AUTH_MAGIC, drm_authmagic, DRM_AUTH|DRM_MASTER), 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), @@ -127,8 +91,8 @@ static drm_ioctl_desc_t drm_ioctls[256] = { 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_ADD_DRAW, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_IOCTL_RM_DRAW, drm_noop, 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), @@ -140,10 +104,12 @@ static drm_ioctl_desc_t drm_ioctls[256] = { 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), + /* The DRM_IOCTL_DMA ioctl should be defined by the driver. */ + DRM_IOCTL_DEF(DRM_IOCTL_DMA, NULL, DRM_AUTH), DRM_IOCTL_DEF(DRM_IOCTL_CONTROL, drm_control, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), +#if __OS_HAS_AGP 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), @@ -152,710 +118,253 @@ static drm_ioctl_desc_t drm_ioctls[256] = { 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), +#endif 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, DRM_UNLOCKED), + 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), + + DRM_IOCTL_DEF(DRM_IOCTL_UPDATE_DRAW, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_GEM_CLOSE, drm_gem_close_ioctl, DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_GEM_FLINK, drm_gem_flink_ioctl, DRM_AUTH|DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_GEM_OPEN, drm_gem_open_ioctl, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETRESOURCES, drm_mode_getresources, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPLANERESOURCES, drm_mode_getplane_res, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCRTC, drm_mode_getcrtc, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETRESOURCES, drm_mode_getresources, DRM_CONTROL_ALLOW|DRM_UNLOCKED), + +#ifdef FREEBSD_NOTYET + DRM_IOCTL_DEF(DRM_IOCTL_PRIME_HANDLE_TO_FD, drm_prime_handle_to_fd_ioctl, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_IOCTL_PRIME_FD_TO_HANDLE, drm_prime_fd_to_handle_ioctl, DRM_AUTH|DRM_UNLOCKED), +#endif /* FREEBSD_NOTYET */ + + DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPLANERESOURCES, drm_mode_getplane_res, DRM_CONTROL_ALLOW|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCRTC, drm_mode_getcrtc, DRM_CONTROL_ALLOW|DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETCRTC, drm_mode_setcrtc, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPLANE, drm_mode_getplane, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPLANE, drm_mode_getplane, DRM_CONTROL_ALLOW|DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETPLANE, drm_mode_setplane, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_MODE_CURSOR, drm_mode_cursor_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETGAMMA, drm_mode_gamma_get_ioctl, DRM_MASTER|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETGAMMA, drm_mode_gamma_get_ioctl, DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETGAMMA, drm_mode_gamma_set_ioctl, DRM_MASTER|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETENCODER, drm_mode_getencoder, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCONNECTOR, drm_mode_getconnector, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETENCODER, drm_mode_getencoder, DRM_CONTROL_ALLOW|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCONNECTOR, drm_mode_getconnector, DRM_CONTROL_ALLOW|DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATTACHMODE, drm_mode_attachmode_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_MODE_DETACHMODE, drm_mode_detachmode_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPERTY, drm_mode_getproperty_ioctl, DRM_MASTER | DRM_CONTROL_ALLOW|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPERTY, drm_mode_getproperty_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETPROPERTY, drm_mode_connector_property_set_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPBLOB, drm_mode_getblob_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETFB, drm_mode_getfb, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB, drm_mode_addfb, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB2, drm_mode_addfb2, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMFB, drm_mode_rmfb, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPBLOB, drm_mode_getblob_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETFB, drm_mode_getfb, DRM_CONTROL_ALLOW|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB, drm_mode_addfb, DRM_CONTROL_ALLOW|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB2, drm_mode_addfb2, DRM_CONTROL_ALLOW|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMFB, drm_mode_rmfb, DRM_CONTROL_ALLOW|DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_MODE_PAGE_FLIP, drm_mode_page_flip_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_MODE_DIRTYFB, drm_mode_dirtyfb_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_IOCTL_MODE_CREATE_DUMB, drm_mode_create_dumb_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_IOCTL_MODE_MAP_DUMB, drm_mode_mmap_dumb_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_IOCTL_MODE_DESTROY_DUMB, drm_mode_destroy_dumb_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_GETPROPERTIES, drm_mode_obj_get_properties_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_CREATE_DUMB, drm_mode_create_dumb_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_MAP_DUMB, drm_mode_mmap_dumb_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_DESTROY_DUMB, drm_mode_destroy_dumb_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_GETPROPERTIES, drm_mode_obj_get_properties_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_SETPROPERTY, drm_mode_obj_set_property_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), }; -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_mmap_single = drm_mmap_single, - .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(struct drm_device *dev, unsigned long flags) -{ - int i = 0; - - if (dev->driver->use_msi != NULL) { - int use_msi; - - use_msi = dev->driver->use_msi(dev, flags); - - return (!use_msi); - } - - /* TODO: Maybe move this to a callback in i915? */ - for (i = 0; drm_msi_blacklist[i].vendor != 0; i++) { - if ((drm_msi_blacklist[i].vendor == dev->pci_vendor) && - (drm_msi_blacklist[i].device == dev->pci_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; - - vendor = pci_get_vendor(kdev); - device = pci_get_device(kdev); - - if (pci_get_class(kdev) != PCIC_DISPLAY - || (pci_get_subclass(kdev) != PCIS_DISPLAY_VGA && - pci_get_subclass(kdev) != PCIS_DISPLAY_OTHER)) - 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 error, msicount; - - dev = device_get_softc(kdev); - - dev->device = kdev; - - dev->pci_domain = pci_get_domain(dev->device); - 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); - dev->pci_subvendor = pci_get_subvendor(dev->device); - dev->pci_subdevice = pci_get_subdevice(dev->device); - - id_entry = drm_find_description(dev->pci_vendor, - dev->pci_device, idlist); - dev->id_entry = id_entry; - - if (drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) { - if (drm_msi && - !drm_msi_is_blacklisted(dev, dev->id_entry->driver_private)) { - 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); - mtx_init(&dev->event_lock, "drmev", NULL, MTX_DEF); - sx_init(&dev->dev_struct_lock, "drmslk"); - - error = drm_load(dev); - if (error) - goto error; - - error = drm_create_cdevs(kdev); - if (error) - goto error; - - return (error); -error: - if (dev->irqr) { - bus_release_resource(dev->device, SYS_RES_IRQ, - dev->irqrid, dev->irqr); - } - if (dev->msi_enabled) { - pci_release_msi(dev->device); - } - return (error); -} - -int -drm_create_cdevs(device_t kdev) -{ - struct drm_device *dev; - int error, unit; - - unit = device_get_unit(kdev); - dev = device_get_softc(kdev); - - error = make_dev_p(MAKEDEV_WAITOK | MAKEDEV_CHECKNAME, &dev->devnode, - &drm_cdevsw, 0, DRM_DEV_UID, DRM_DEV_GID, - DRM_DEV_MODE, "dri/card%d", unit); - if (error == 0) - dev->devnode->si_drv1 = dev; - return (error); -} - -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" +#ifdef COMPAT_FREEBSD32 +extern struct drm_ioctl_desc drm_compat_ioctls[]; #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_LOCK_ASSERT(dev); - - /* 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; - if (!drm_core_check_feature(dev, DRIVER_MODESET)) - 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; -} +#define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls ) -static int drm_lastclose(struct drm_device *dev) +/** + * Take down the DRM device. + * + * \param dev DRM device structure. + * + * Frees every resource in \p dev. + * + * \sa drm_device + */ +int drm_lastclose(struct drm_device * dev) { - drm_magic_entry_t *pt, *next; - drm_local_map_t *map, *mapsave; - int i; - - DRM_LOCK_ASSERT(dev); +#ifdef __linux__ + struct drm_vma_entry *vma, *vma_temp; +#endif DRM_DEBUG("\n"); - if (dev->driver->lastclose != NULL) + if (dev->driver->lastclose) dev->driver->lastclose(dev); + DRM_DEBUG("driver lastclose completed\n"); - if (!drm_core_check_feature(dev, DRIVER_MODESET) && dev->irq_enabled) + if (dev->irq_enabled && !drm_core_check_feature(dev, DRIVER_MODESET)) 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(dev); - drm_drawable_free_all(dev); DRM_LOCK(dev); /* Clear AGP information */ - if (dev->agp) { - drm_agp_mem_t *entry; - drm_agp_mem_t *nexte; + if (drm_core_has_AGP(dev) && dev->agp && + !drm_core_check_feature(dev, DRIVER_MODESET)) { + struct drm_agp_mem *entry, *tempe; - /* Remove AGP resources, but leave dev->agp intact until - * drm_unload is called. - */ - for (entry = dev->agp->memory; entry; entry = nexte) { - nexte = entry->next; + /* Remove AGP resources, but leave dev->agp + intact until drv_cleanup is called. */ + list_for_each_entry_safe(entry, tempe, &dev->agp->memory, head) { if (entry->bound) - drm_agp_unbind_memory(entry->handle); - drm_agp_free_memory(entry->handle); + drm_unbind_agp(entry->memory); + drm_free_agp(entry->memory, entry->pages); free(entry, DRM_MEM_AGPLISTS); } - dev->agp->memory = NULL; + INIT_LIST_HEAD(&dev->agp->memory); if (dev->agp->acquired) drm_agp_release(dev); dev->agp->acquired = 0; - dev->agp->enabled = 0; + dev->agp->enabled = 0; } - if (dev->sg != NULL) { + if (drm_core_check_feature(dev, DRIVER_SG) && dev->sg && + !drm_core_check_feature(dev, DRIVER_MODESET)) { 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); +#ifdef __linux__ + /* Clear vma list (only built for debugging) */ + list_for_each_entry_safe(vma, vma_temp, &dev->vmalist, head) { + list_del(&vma->head); + kfree(vma); } +#endif - 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); - } + if (drm_core_check_feature(dev, DRIVER_HAVE_DMA) && + !drm_core_check_feature(dev, DRIVER_MODESET)) + drm_dma_takedown(dev); + + DRM_UNLOCK(dev); + DRM_DEBUG("lastclose completed\n"); 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); - - INIT_LIST_HEAD(&dev->vblank_event_list); - - 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; - } - } +#ifdef __linux__ +/** File operations structure */ +static const struct file_operations drm_stub_fops = { + .owner = THIS_MODULE, + .open = drm_stub_open, + .llseek = noop_llseek, +}; +#endif - retcode = drm_ctxbitmap_init(dev); - if (retcode != 0) { - DRM_ERROR("Cannot allocate memory for context bitmap.\n"); - goto error; - } +static int __init drm_core_init(void) +{ - dev->drw_unrhdr = new_unrhdr(1, INT_MAX, NULL); - if (dev->drw_unrhdr == NULL) { - DRM_ERROR("Couldn't allocate drawable number allocator\n"); - retcode = ENOMEM; - goto error; - } + sx_init(&drm_global_mutex, "drm_global_mutex"); - if (dev->driver->driver_features & DRIVER_GEM) { - retcode = drm_gem_init(dev); - if (retcode != 0) { - DRM_ERROR("Cannot initialize graphics execution " - "manager (GEM)\n"); - goto error1; - } - } + drm_global_init(); - if (dev->driver->load != NULL) { - DRM_LOCK(dev); - /* 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(dev); - if (retcode != 0) - goto error1; - } +#if DRM_LINUX + linux_ioctl_register_handler(&drm_handler); +#endif /* DRM_LINUX */ DRM_INFO("Initialized %s %d.%d.%d %s\n", - dev->driver->name, - dev->driver->major, - dev->driver->minor, - dev->driver->patchlevel, - dev->driver->date); - + CORE_NAME, CORE_MAJOR, CORE_MINOR, CORE_PATCHLEVEL, CORE_DATE); return 0; - -error1: - delete_unrhdr(dev->drw_unrhdr); - drm_gem_destroy(dev); -error: - drm_ctxbitmap_cleanup(dev); - drm_sysctl_cleanup(dev); - DRM_LOCK(dev); - drm_lastclose(dev); - DRM_UNLOCK(dev); - if (dev->devnode != NULL) - destroy_dev(dev->devnode); - - mtx_destroy(&dev->drw_lock); - mtx_destroy(&dev->vbl_lock); - mtx_destroy(&dev->irq_lock); - mtx_destroy(&dev->dev_lock); - mtx_destroy(&dev->event_lock); - sx_destroy(&dev->dev_struct_lock); - - return retcode; } -static void drm_unload(struct drm_device *dev) +static void __exit drm_core_exit(void) { - int i; - - DRM_DEBUG("\n"); - - drm_sysctl_cleanup(dev); - if (dev->devnode != NULL) - destroy_dev(dev->devnode); - - drm_ctxbitmap_cleanup(dev); - - if (dev->driver->driver_features & DRIVER_GEM) - drm_gem_destroy(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(dev); - drm_lastclose(dev); - DRM_UNLOCK(dev); - - /* 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); - dev->driver->unload(dev); - DRM_UNLOCK(dev); - } - - delete_unrhdr(dev->drw_unrhdr); - delete_unrhdr(dev->map_unrhdr); - drm_mem_uninit(); +#if DRM_LINUX + linux_ioctl_unregister_handler(&drm_handler); +#endif /* DRM_LINUX */ - if (pci_disable_busmaster(dev->device)) - DRM_ERROR("Request to disable bus-master failed.\n"); + drm_global_release(); - mtx_destroy(&dev->drw_lock); - mtx_destroy(&dev->vbl_lock); - mtx_destroy(&dev->irq_lock); - mtx_destroy(&dev->dev_lock); - mtx_destroy(&dev->event_lock); - sx_destroy(&dev->dev_struct_lock); + sx_destroy(&drm_global_mutex); } -int drm_version(struct drm_device *dev, void *data, struct drm_file *file_priv) +SYSINIT(drm_register, SI_SUB_KLD, SI_ORDER_MIDDLE, + drm_core_init, NULL); +SYSUNINIT(drm_unregister, SI_SUB_KLD, SI_ORDER_MIDDLE, + drm_core_exit, NULL); + +/** + * Copy and IOCTL return string to user space + */ +static int drm_copy_field(char *buf, size_t *buf_len, const char *value) { - 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; + /* don't overflow userbuf */ + len = strlen(value); + if (len > *buf_len) + len = *buf_len; - DRM_COPY(version->name, dev->driver->name); - DRM_COPY(version->date, dev->driver->date); - DRM_COPY(version->desc, dev->driver->desc); + /* let userspace know exact length of driver value (which could be + * larger than the userspace-supplied buffer) */ + *buf_len = strlen(value); + /* finally, try filling in the userbuf */ + if (len && buf) + if (copy_to_user(buf, value, len)) + return -EFAULT; return 0; } -int -drm_open(struct cdev *kdev, int flags, int fmt, DRM_STRUCTPROC *p) -{ - struct drm_device *dev; - int retcode; - - dev = kdev->si_drv1; - if (dev == NULL) - return (ENXIO); - - DRM_DEBUG("open_count = %d\n", dev->open_count); - - retcode = drm_open_helper(kdev, flags, fmt, p, dev); - - if (retcode == 0) { - atomic_inc(&dev->counts[_DRM_STAT_OPENS]); - DRM_LOCK(dev); - mtx_lock(&Giant); - device_busy(dev->device); - mtx_unlock(&Giant); - if (!dev->open_count++) - retcode = drm_firstopen(dev); - DRM_UNLOCK(dev); - } - - return (retcode); -} - -void drm_close(void *data) +/** + * Get version information + * + * \param inode device inode. + * \param filp file pointer. + * \param cmd command. + * \param arg user argument, pointing to a drm_version structure. + * \return zero on success or negative number on failure. + * + * Fills in the version information in \p arg. + */ +int drm_version(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - 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(dev); - - 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->driver->driver_features & DRIVER_GEM) - drm_gem_release(dev, file_priv); - - 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 = DRM_LOCK_SLEEP(dev, &dev->lock.lock_queue, - 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); - seldrain(&file_priv->event_poll); - - 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]); - mtx_lock(&Giant); - device_unbusy(dev->device); - mtx_unlock(&Giant); - if (--dev->open_count == 0) { - retcode = drm_lastclose(dev); - } - - DRM_UNLOCK(dev); + struct drm_version *version = data; + int err; + + version->version_major = dev->driver->major; + version->version_minor = dev->driver->minor; + version->version_patchlevel = dev->driver->patchlevel; + err = drm_copy_field(version->name, &version->name_len, + dev->driver->name); + if (!err) + err = drm_copy_field(version->date, &version->date_len, + dev->driver->date); + if (!err) + err = drm_copy_field(version->desc, &version->desc_len, + dev->driver->desc); + + return err; } -extern drm_ioctl_desc_t drm_compat_ioctls[]; - -/* drm_ioctl is called whenever a process performs an ioctl on /dev/drm. +/** + * Called whenever a process performs an ioctl on /dev/drm. + * + * \param inode device inode. + * \param file_priv DRM file private. + * \param cmd command. + * \param arg user argument. + * \return zero on success or negative number on failure. + * + * Looks up the ioctl function in the ::ioctls table, checking for root + * previleges if so required, and dispatches to the respective function. */ 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; + struct drm_device *dev; + struct drm_ioctl_desc *ioctl; + drm_ioctl_t *func; + unsigned int nr = DRM_IOCTL_NR(cmd); + int retcode; + + dev = drm_get_device_from_kdev(kdev); retcode = devfs_get_cdevpriv((void **)&file_priv); if (retcode != 0) { @@ -863,12 +372,16 @@ int drm_ioctl(struct cdev *kdev, u_long cmd, caddr_t data, int flags, return EINVAL; } + retcode = -EINVAL; + + atomic_inc(&dev->ioctl_count); 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); + DRM_CURRENTPID, cmd, nr, + (long)file_priv->minor->device, + file_priv->authenticated); switch (cmd) { case FIONBIO: @@ -876,10 +389,10 @@ int drm_ioctl(struct cdev *kdev, u_long cmd, caddr_t data, int flags, return 0; case FIOSETOWN: - return fsetown(*(int *)data, &dev->buf_sigio); + return fsetown(*(int *)data, &file_priv->minor->buf_sigio); case FIOGETOWN: - *(int *) data = fgetown(&dev->buf_sigio); + *(int *) data = fgetown(&file_priv->minor->buf_sigio); return 0; } @@ -888,253 +401,99 @@ int drm_ioctl(struct cdev *kdev, u_long cmd, caddr_t data, int flags, return EINVAL; } + if ((nr >= DRM_CORE_IOCTL_COUNT) && + ((nr < DRM_COMMAND_BASE) || (nr >= DRM_COMMAND_END))) + goto err_i1; #ifdef COMPAT_FREEBSD32 - /* - * Called whenever a 32-bit process running under a 64-bit - * kernel performs an ioctl on /dev/drm. - */ - if (SV_CURPROC_FLAG(SV_ILP32) && drm_compat_ioctls[nr].func != NULL) - /* - * Assume that ioctls without an explicit compat - * routine will just work. This may not always be a - * good assumption, but it's better than always - * failing. - */ - ioctl = &drm_compat_ioctls[nr]; - else + if (SV_CURPROC_FLAG(SV_ILP32) && + (nr >= DRM_COMMAND_BASE) && (nr < DRM_COMMAND_END) && + (nr < DRM_COMMAND_BASE + *dev->driver->num_compat_ioctls) && + (dev->driver->compat_ioctls[nr - DRM_COMMAND_BASE].func != NULL)) { + ioctl = &dev->driver->compat_ioctls[nr - DRM_COMMAND_BASE]; + } else #endif - 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; - } + if ((nr >= DRM_COMMAND_BASE) && (nr < DRM_COMMAND_END) && + (nr < DRM_COMMAND_BASE + dev->driver->num_ioctls)) { + ioctl = &dev->driver->ioctls[nr - DRM_COMMAND_BASE]; + } + else if ((nr >= DRM_COMMAND_END) || (nr < DRM_COMMAND_BASE)) { #ifdef COMPAT_FREEBSD32 - if (SV_CURPROC_FLAG(SV_ILP32) && - nr < *dev->driver->compat_ioctls_nr && - dev->driver->compat_ioctls[nr].func != NULL) - ioctl = &dev->driver->compat_ioctls[nr]; + /* + * Called whenever a 32-bit process running under a 64-bit + * kernel performs an ioctl on /dev/drm. + */ + if (SV_CURPROC_FLAG(SV_ILP32) && drm_compat_ioctls[nr].func != NULL) + /* + * Assume that ioctls without an explicit compat + * routine will just work. This may not always be a + * good assumption, but it's better than always + * failing. + */ + ioctl = &drm_compat_ioctls[nr]; else #endif - ioctl = &dev->driver->ioctls[nr]; - is_driver_ioctl = 1; - } + ioctl = &drm_ioctls[nr]; + } else + goto err_i1; + + /* Do not trust userspace, use our own definition */ func = ioctl->func; + /* is there a local override? */ +#ifdef FREEBSD_NOTYET +#ifdef COMPAT_FREEBSD32 + if (SV_CURPROC_FLAG(SV_ILP32) && + (nr == DRM_IOCTL_NR(DRM_IOCTL_DMA)) && dev->driver->dma_compat_ioctl) + func = dev->driver->dma_compat_ioctl; + else +#endif +#endif /* FREEBSD_NOTYET */ + if ((nr == DRM_IOCTL_NR(DRM_IOCTL_DMA)) && dev->driver->dma_ioctl) + func = dev->driver->dma_ioctl; - if (func == NULL) { + if (!func) { 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) { - if ((ioctl->flags & DRM_UNLOCKED) == 0) - DRM_LOCK(dev); - /* shared code returns -errno */ - retcode = -func(dev, data, file_priv); - if ((ioctl->flags & DRM_UNLOCKED) == 0) - DRM_UNLOCK(dev); + retcode = -EINVAL; + } else if (((ioctl->flags & DRM_ROOT_ONLY) && !DRM_SUSER(p)) || + ((ioctl->flags & DRM_AUTH) && !file_priv->authenticated) || + ((ioctl->flags & DRM_MASTER) && !file_priv->is_master) || + (!(ioctl->flags & DRM_CONTROL_ALLOW) && (file_priv->minor->type == DRM_MINOR_CONTROL))) { + retcode = -EACCES; } else { - retcode = func(dev, data, file_priv); + if (ioctl->flags & DRM_UNLOCKED) + retcode = func(dev, data, file_priv); + else { + sx_xlock(&drm_global_mutex); + retcode = func(dev, data, file_priv); + sx_xunlock(&drm_global_mutex); + } } - if (retcode != 0) - DRM_DEBUG(" returning %d\n", retcode); + err_i1: + atomic_dec(&dev->ioctl_count); + if (retcode) + DRM_DEBUG("ret = %d\n", retcode); if (retcode != 0 && - (drm_debug_flag & DRM_DEBUGBITS_FAILED_IOCTL) != 0) { + (drm_debug & DRM_DEBUGBITS_FAILED_IOCTL) != 0) { printf( -"pid %d, cmd 0x%02lx, nr 0x%02x/%1d, dev 0x%lx, auth %d, res %d\n", - DRM_CURRENTPID, cmd, nr, is_driver_ioctl, (long)dev->device, - file_priv->authenticated, retcode); +"pid %d, cmd 0x%02lx, nr 0x%02x, dev 0x%lx, auth %d, res %d\n", + DRM_CURRENTPID, cmd, nr, (long)file_priv->minor->device, + file_priv->authenticated, -retcode); } - return retcode; -} - -drm_local_map_t *drm_getsarea(struct drm_device *dev) -{ - drm_local_map_t *map; - - DRM_LOCK_ASSERT(dev); - TAILQ_FOREACH(map, &dev->maplist, link) { - if (map->type == _DRM_SHM && (map->flags & _DRM_CONTAINS_LOCK)) - return map; - } - - return NULL; -} - -int -drm_add_busid_modesetting(struct drm_device *dev, struct sysctl_ctx_list *ctx, - struct sysctl_oid *top) -{ - struct sysctl_oid *oid; - - snprintf(dev->busid_str, sizeof(dev->busid_str), - "pci:%04x:%02x:%02x.%d", dev->pci_domain, dev->pci_bus, - dev->pci_slot, dev->pci_func); - oid = SYSCTL_ADD_STRING(ctx, SYSCTL_CHILDREN(top), OID_AUTO, "busid", - CTLFLAG_RD, dev->busid_str, 0, NULL); - if (oid == NULL) - return (ENOMEM); - dev->modesetting = (dev->driver->driver_features & DRIVER_MODESET) != 0; - oid = SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(top), OID_AUTO, - "modesetting", CTLFLAG_RD, &dev->modesetting, 0, NULL); - if (oid == NULL) - return (ENOMEM); - - return (0); -} - -static int -drm_mmap_single(struct cdev *kdev, vm_ooffset_t *offset, vm_size_t size, - struct vm_object **obj_res, int nprot) -{ - struct drm_device *dev; - - dev = drm_get_device_from_kdev(kdev); - if (dev->drm_ttm_bdev != NULL) { - return (ttm_bo_mmap_single(dev->drm_ttm_bdev, offset, size, - obj_res, nprot)); - } else if ((dev->driver->driver_features & DRIVER_GEM) != 0) { - return (drm_gem_mmap_single(dev, offset, size, obj_res, nprot)); - } else { - return (ENODEV); - } + return -retcode; } +EXPORT_SYMBOL(drm_ioctl); -#if DRM_LINUX - -#include <sys/sysproto.h> - -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}; - -/* 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) +struct drm_local_map *drm_getsarea(struct drm_device *dev) { - int error; - int cmd = args->cmd; + struct drm_map_list *entry; - 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 */ - - -static int -drm_core_init(void *arg) -{ - - drm_global_init(); - -#if DRM_LINUX - linux_ioctl_register_handler(&drm_handler); -#endif /* DRM_LINUX */ - - DRM_INFO("Initialized %s %d.%d.%d %s\n", - CORE_NAME, CORE_MAJOR, CORE_MINOR, CORE_PATCHLEVEL, CORE_DATE); - return 0; -} - -static void -drm_core_exit(void *arg) -{ - -#if DRM_LINUX - linux_ioctl_unregister_handler(&drm_handler); -#endif /* DRM_LINUX */ - - drm_global_release(); -} - -SYSINIT(drm_register, SI_SUB_KLD, SI_ORDER_MIDDLE, - drm_core_init, NULL); -SYSUNINIT(drm_unregister, SI_SUB_KLD, SI_ORDER_MIDDLE, - drm_core_exit, NULL); - -static bool -dmi_found(const struct dmi_system_id *dsi) -{ - char *hw_vendor, *hw_prod; - int i, slot; - bool res; - - hw_vendor = kern_getenv("smbios.planar.maker"); - hw_prod = kern_getenv("smbios.planar.product"); - res = true; - for (i = 0; i < nitems(dsi->matches); i++) { - slot = dsi->matches[i].slot; - switch (slot) { - case DMI_NONE: - break; - case DMI_SYS_VENDOR: - case DMI_BOARD_VENDOR: - if (hw_vendor != NULL && - !strcmp(hw_vendor, dsi->matches[i].substr)) { - break; - } else { - res = false; - goto out; - } - case DMI_PRODUCT_NAME: - case DMI_BOARD_NAME: - if (hw_prod != NULL && - !strcmp(hw_prod, dsi->matches[i].substr)) { - break; - } else { - res = false; - goto out; - } - default: - res = false; - goto out; + list_for_each_entry(entry, &dev->maplist, head) { + if (entry->map && entry->map->type == _DRM_SHM && + (entry->map->flags & _DRM_CONTAINS_LOCK)) { + return entry->map; } } -out: - freeenv(hw_vendor); - freeenv(hw_prod); - - return (res); -} - -bool -dmi_check_system(const struct dmi_system_id *sysid) -{ - const struct dmi_system_id *dsi; - bool res; - - for (res = false, dsi = sysid; dsi->matches[0].slot != 0 ; dsi++) { - if (dmi_found(dsi)) { - res = true; - if (dsi->callback != NULL && dsi->callback(dsi)) - break; - } - } - return (res); + return NULL; } +EXPORT_SYMBOL(drm_getsarea); diff --git a/sys/dev/drm2/drm_edid.c b/sys/dev/drm2/drm_edid.c index bf4cc9fd2541..a296c72c28be 100644 --- a/sys/dev/drm2/drm_edid.c +++ b/sys/dev/drm2/drm_edid.c @@ -33,7 +33,7 @@ __FBSDID("$FreeBSD$"); #include <dev/drm2/drmP.h> #include <dev/drm2/drm_edid.h> -#include <dev/drm2/drm_edid_modes.h> +#include "drm_edid_modes.h" #include <dev/iicbus/iic.h> #include <dev/iicbus/iiconf.h> #include "iicbus_if.h" @@ -69,6 +69,8 @@ __FBSDID("$FreeBSD$"); #define EDID_QUIRK_FIRST_DETAILED_PREFERRED (1 << 5) /* use +hsync +vsync for detailed mode */ #define EDID_QUIRK_DETAILED_SYNC_PP (1 << 6) +/* Force reduced-blanking timings for detailed modes */ +#define EDID_QUIRK_FORCE_REDUCED_BLANKING (1 << 7) struct detailed_mode_closure { struct drm_connector *connector; @@ -123,6 +125,9 @@ static struct edid_quirk { /* Samsung SyncMaster 22[5-6]BW */ { "SAM", 596, EDID_QUIRK_PREFER_LARGE_60 }, { "SAM", 638, EDID_QUIRK_PREFER_LARGE_60 }, + + /* ViewSonic VA2026w */ + { "VSC", 5020, EDID_QUIRK_FORCE_REDUCED_BLANKING }, }; /*** DDC fetch and block validation ***/ @@ -145,22 +150,30 @@ int drm_edid_header_is_valid(const u8 *raw_edid) return score; } +EXPORT_SYMBOL(drm_edid_header_is_valid); + +static int edid_fixup __read_mostly = 6; +module_param_named(edid_fixup, edid_fixup, int, 0400); +MODULE_PARM_DESC(edid_fixup, + "Minimum number of valid EDID header bytes (0-8, default 6)"); /* * Sanity check the EDID block (base or extension). Return 0 if the block * doesn't check out, or 1 if it's valid. */ -static bool -drm_edid_block_valid(u8 *raw_edid, int block) +bool drm_edid_block_valid(u8 *raw_edid, int block, bool print_bad_edid) { int i; u8 csum = 0; struct edid *edid = (struct edid *)raw_edid; + if (edid_fixup > 8 || edid_fixup < 0) + edid_fixup = 6; + if (block == 0) { int score = drm_edid_header_is_valid(raw_edid); if (score == 8) ; - else if (score >= 6) { + else if (score >= edid_fixup) { DRM_DEBUG("Fixing EDID header, your hardware may be failing\n"); memcpy(raw_edid, edid_header, sizeof(edid_header)); } else { @@ -171,7 +184,9 @@ drm_edid_block_valid(u8 *raw_edid, int block) for (i = 0; i < EDID_LENGTH; i++) csum += raw_edid[i]; if (csum) { - DRM_DEBUG_KMS("EDID checksum is invalid, remainder is %d\n", csum); + if (print_bad_edid) { + DRM_ERROR("EDID checksum is invalid, remainder is %d\n", csum); + } /* allow CEA to slide through, switches mangle this */ if (raw_edid[0] != 0x02) @@ -197,23 +212,22 @@ drm_edid_block_valid(u8 *raw_edid, int block) return 1; bad: - if (raw_edid) { + if (raw_edid && print_bad_edid) { DRM_DEBUG_KMS("Raw EDID:\n"); - if ((drm_debug_flag & DRM_DEBUGBITS_KMS) != 0) { - for (i = 0; i < EDID_LENGTH; ) { - printf("%02x", raw_edid[i]); - i++; - if (i % 16 == 0 || i == EDID_LENGTH) - printf("\n"); - else if (i % 8 == 0) - printf(" "); - else - printf(" "); - } + for (i = 0; i < EDID_LENGTH; ) { + printf("%02x", raw_edid[i]); + i++; + if (i % 16 == 0 || i == EDID_LENGTH) + printf("\n"); + else if (i % 8 == 0) + printf(" "); + else + printf(" "); } } return 0; } +EXPORT_SYMBOL(drm_edid_block_valid); /** * drm_edid_is_valid - sanity check EDID data @@ -230,13 +244,13 @@ bool drm_edid_is_valid(struct edid *edid) return false; for (i = 0; i <= edid->extensions; i++) - if (!drm_edid_block_valid(raw + i * EDID_LENGTH, i)) + if (!drm_edid_block_valid(raw + i * EDID_LENGTH, i, true)) return false; return true; } +EXPORT_SYMBOL(drm_edid_is_valid); -#define DDC_ADDR 0x50 #define DDC_SEGMENT_ADDR 0x30 /** * Get EDID information via I2C. @@ -266,13 +280,13 @@ drm_do_probe_ddc_edid(device_t adapter, unsigned char *buf, do { struct iic_msg msgs[] = { { - .slave = DDC_SEGMENT_ADDR << 1, - .flags = 0, - .len = 1, - .buf = &segment, + .slave = DDC_SEGMENT_ADDR << 1, + .flags = 0, + .len = 1, + .buf = &segment, }, { .slave = DDC_ADDR << 1, - .flags = IIC_M_WR, + .flags = 0, .len = 1, .buf = &start, }, { @@ -294,7 +308,7 @@ drm_do_probe_ddc_edid(device_t adapter, unsigned char *buf, retries, ret); } while (ret != 0 && --retries); - return (ret == 0 ? 0 : -1); + return ret == 0 ? 0 : -1; } static bool drm_edid_is_zero(u8 *in_edid, int length) @@ -305,6 +319,7 @@ static bool drm_edid_is_zero(u8 *in_edid, int length) for (i = 0; i < length / 4; i++) if (*(raw_edid + i) != 0) return false; + return true; } @@ -313,14 +328,16 @@ drm_do_get_edid(struct drm_connector *connector, device_t adapter) { int i, j = 0, valid_extensions = 0; u8 *block, *new; + bool print_bad_edid = !connector->bad_edid_counter || (drm_debug & DRM_DEBUGBITS_KMS); - block = malloc(EDID_LENGTH, DRM_MEM_KMS, M_WAITOK | M_ZERO); + if ((block = malloc(EDID_LENGTH, DRM_MEM_KMS, M_NOWAIT)) == NULL) + return NULL; /* base block fetch */ for (i = 0; i < 4; i++) { if (drm_do_probe_ddc_edid(adapter, block, 0, EDID_LENGTH)) goto out; - if (drm_edid_block_valid(block, 0)) + if (drm_edid_block_valid(block, 0, print_bad_edid)) break; if (i == 0 && drm_edid_is_zero(block, EDID_LENGTH)) { connector->null_edid_counter++; @@ -335,7 +352,9 @@ drm_do_get_edid(struct drm_connector *connector, device_t adapter) return block; new = reallocf(block, (block[0x7e] + 1) * EDID_LENGTH, DRM_MEM_KMS, - M_WAITOK); + M_NOWAIT); + if (!new) + goto out; block = new; for (j = 1; j <= block[0x7e]; j++) { @@ -344,30 +363,39 @@ drm_do_get_edid(struct drm_connector *connector, device_t adapter) block + (valid_extensions + 1) * EDID_LENGTH, j, EDID_LENGTH)) goto out; - if (drm_edid_block_valid(block + (valid_extensions + 1) * EDID_LENGTH, j)) { + if (drm_edid_block_valid(block + (valid_extensions + 1) * EDID_LENGTH, j, print_bad_edid)) { valid_extensions++; break; } } - if (i == 4) - DRM_DEBUG_KMS("%s: Ignoring invalid EDID block %d.\n", - drm_get_connector_name(connector), j); + + if (i == 4 && print_bad_edid) { + dev_warn(connector->dev->dev, + "%s: Ignoring invalid EDID block %d.\n", + drm_get_connector_name(connector), j); + + connector->bad_edid_counter++; + } } if (valid_extensions != block[0x7e]) { block[EDID_LENGTH-1] += block[0x7e] - valid_extensions; block[0x7e] = valid_extensions; new = reallocf(block, (valid_extensions + 1) * EDID_LENGTH, - DRM_MEM_KMS, M_WAITOK); + DRM_MEM_KMS, M_NOWAIT); + if (!new) + goto out; block = new; } - DRM_DEBUG_KMS("got EDID from %s\n", drm_get_connector_name(connector)); return block; carp: - DRM_DEBUG_KMS("%s: EDID block %d invalid.\n", - drm_get_connector_name(connector), j); + if (print_bad_edid) { + dev_warn(connector->dev->dev, "%s: EDID block %d invalid.\n", + drm_get_connector_name(connector), j); + } + connector->bad_edid_counter++; out: free(block, DRM_MEM_KMS); @@ -380,13 +408,14 @@ out: * \param adapter : i2c device adaptor * \return 1 on success */ -static bool +bool drm_probe_ddc(device_t adapter) { unsigned char out; return (drm_do_probe_ddc_edid(adapter, &out, 0, 1) == 0); } +EXPORT_SYMBOL(drm_probe_ddc); /** * drm_get_edid - get EDID data, if available @@ -406,11 +435,9 @@ struct edid *drm_get_edid(struct drm_connector *connector, if (drm_probe_ddc(adapter)) edid = (struct edid *)drm_do_get_edid(connector, adapter); - connector->display_info.raw_edid = (char *)edid; - return edid; - } +EXPORT_SYMBOL(drm_get_edid); /*** EDID parsing ***/ @@ -444,7 +471,7 @@ static u32 edid_get_quirks(struct edid *edid) struct edid_quirk *quirk; int i; - for (i = 0; i < DRM_ARRAY_SIZE(edid_quirk_list); i++) { + for (i = 0; i < ARRAY_SIZE(edid_quirk_list); i++) { quirk = &edid_quirk_list[i]; if (edid_vendor(edid, quirk->vendor) && @@ -531,7 +558,7 @@ struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev, int i; for (i = 0; i < drm_num_dmt_modes; i++) { - struct drm_display_mode *ptr = &drm_dmt_modes[i]; + const struct drm_display_mode *ptr = &drm_dmt_modes[i]; if (hsize != ptr->hdisplay) continue; if (vsize != ptr->vdisplay) @@ -546,6 +573,7 @@ struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev, return NULL; } +EXPORT_SYMBOL(drm_mode_find_dmt); typedef void detailed_cb(struct detailed_timing *timing, void *closure); @@ -553,25 +581,10 @@ static void cea_for_each_detailed_block(u8 *ext, detailed_cb *cb, void *closure) { int i, n = 0; - u8 rev = ext[0x01], d = ext[0x02]; + u8 d = ext[0x02]; u8 *det_base = ext + d; - switch (rev) { - case 0: - /* can't happen */ - return; - case 1: - /* have to infer how many blocks we have, check pixel clock */ - for (i = 0; i < 6; i++) - if (det_base[18*i] || det_base[18*i+1]) - n++; - break; - default: - /* explicit count */ - n = min(ext[0x03] & 0x0f, 6); - break; - } - + n = (127 - d) / 18; for (i = 0; i < n; i++) cb((struct detailed_timing *)(det_base + 18 * i), closure); } @@ -630,7 +643,7 @@ static bool drm_monitor_supports_rb(struct edid *edid) { if (edid->revision >= 4) { - bool ret; + bool ret = false; drm_for_each_detailed_block((u8 *)edid, is_rb, &ret); return ret; } @@ -814,7 +827,7 @@ drm_mode_std(struct drm_connector *connector, struct edid *edid, if (!mode) return NULL; if (drm_mode_hsync(mode) > drm_gtf2_hbreak(edid)) { - free(mode, DRM_MEM_KMS); + drm_mode_destroy(dev, mode); mode = drm_gtf_mode_complex(dev, hsize, vsize, vrefresh_rate, 0, 0, drm_gtf2_m(edid), @@ -859,7 +872,7 @@ drm_mode_do_interlace_quirk(struct drm_display_mode *mode, if (!(pt->misc & DRM_EDID_PT_INTERLACED)) return; - for (i = 0; i < DRM_ARRAY_SIZE(cea_interlaced); i++) { + for (i = 0; i < ARRAY_SIZE(cea_interlaced); i++) { if ((mode->hdisplay == cea_interlaced[i].w) && (mode->vdisplay == cea_interlaced[i].h / 2)) { mode->vdisplay *= 2; @@ -896,7 +909,7 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev, unsigned vblank = (pt->vactive_vblank_hi & 0xf) << 8 | pt->vblank_lo; unsigned hsync_offset = (pt->hsync_vsync_offset_pulse_width_hi & 0xc0) << 2 | pt->hsync_offset_lo; unsigned hsync_pulse_width = (pt->hsync_vsync_offset_pulse_width_hi & 0x30) << 4 | pt->hsync_pulse_width_lo; - unsigned vsync_offset = (pt->hsync_vsync_offset_pulse_width_hi & 0xc) >> 2 | pt->vsync_offset_pulse_width_lo >> 4; + unsigned vsync_offset = (pt->hsync_vsync_offset_pulse_width_hi & 0xc) << 2 | pt->vsync_offset_pulse_width_lo >> 4; unsigned vsync_pulse_width = (pt->hsync_vsync_offset_pulse_width_hi & 0x3) << 4 | (pt->vsync_offset_pulse_width_lo & 0xf); /* ignore tiny modes */ @@ -917,16 +930,23 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev, "Wrong Hsync/Vsync pulse width\n"); return NULL; } + + if (quirks & EDID_QUIRK_FORCE_REDUCED_BLANKING) { + mode = drm_cvt_mode(dev, hactive, vactive, 60, true, false, false); + if (!mode) + return NULL; + + goto set_size; + } + mode = drm_mode_create(dev); if (!mode) return NULL; - mode->type = DRM_MODE_TYPE_DRIVER; - if (quirks & EDID_QUIRK_135_CLOCK_TOO_HIGH) - timing->pixel_clock = htole16(1088); + timing->pixel_clock = cpu_to_le16(1088); - mode->clock = le16toh(timing->pixel_clock) * 10; + mode->clock = le16_to_cpu(timing->pixel_clock) * 10; mode->hdisplay = hactive; mode->hsync_start = mode->hdisplay + hsync_offset; @@ -946,8 +966,6 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev, drm_mode_do_interlace_quirk(mode, pt); - drm_mode_set_name(mode); - if (quirks & EDID_QUIRK_DETAILED_SYNC_PP) { pt->misc |= DRM_EDID_PT_HSYNC_POSITIVE | DRM_EDID_PT_VSYNC_POSITIVE; } @@ -957,6 +975,7 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev, mode->flags |= (pt->misc & DRM_EDID_PT_VSYNC_POSITIVE) ? DRM_MODE_FLAG_PVSYNC : DRM_MODE_FLAG_NVSYNC; +set_size: mode->width_mm = pt->width_mm_lo | (pt->width_height_mm_hi & 0xf0) << 4; mode->height_mm = pt->height_mm_lo | (pt->width_height_mm_hi & 0xf) << 8; @@ -970,11 +989,15 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev, mode->height_mm = edid->height_cm * 10; } + mode->type = DRM_MODE_TYPE_DRIVER; + mode->vrefresh = drm_mode_vrefresh(mode); + drm_mode_set_name(mode); + return mode; } static bool -mode_in_hsync_range(struct drm_display_mode *mode, +mode_in_hsync_range(const struct drm_display_mode *mode, struct edid *edid, u8 *t) { int hsync, hmin, hmax; @@ -991,7 +1014,7 @@ mode_in_hsync_range(struct drm_display_mode *mode, } static bool -mode_in_vsync_range(struct drm_display_mode *mode, +mode_in_vsync_range(const struct drm_display_mode *mode, struct edid *edid, u8 *t) { int vsync, vmin, vmax; @@ -1023,7 +1046,7 @@ range_pixel_clock(struct edid *edid, u8 *t) } static bool -mode_in_range(struct drm_display_mode *mode, struct edid *edid, +mode_in_range(const struct drm_display_mode *mode, struct edid *edid, struct detailed_timing *timing) { u32 max_clock; @@ -1050,6 +1073,24 @@ mode_in_range(struct drm_display_mode *mode, struct edid *edid, return true; } +static bool valid_inferred_mode(const struct drm_connector *connector, + const struct drm_display_mode *mode) +{ + struct drm_display_mode *m; + bool ok = false; + + list_for_each_entry(m, &connector->probed_modes, head) { + if (mode->hdisplay == m->hdisplay && + mode->vdisplay == m->vdisplay && + drm_mode_vrefresh(mode) == drm_mode_vrefresh(m)) + return false; /* duplicated */ + if (mode->hdisplay <= m->hdisplay && + mode->vdisplay <= m->vdisplay) + ok = true; + } + return ok; +} + static int drm_dmt_modes_for_range(struct drm_connector *connector, struct edid *edid, struct detailed_timing *timing) @@ -1059,7 +1100,8 @@ drm_dmt_modes_for_range(struct drm_connector *connector, struct edid *edid, struct drm_device *dev = connector->dev; for (i = 0; i < drm_num_dmt_modes; i++) { - if (mode_in_range(drm_dmt_modes + i, edid, timing)) { + if (mode_in_range(drm_dmt_modes + i, edid, timing) && + valid_inferred_mode(connector, drm_dmt_modes + i)) { newmode = drm_mode_duplicate(dev, &drm_dmt_modes[i]); if (newmode) { drm_mode_probed_add(connector, newmode); @@ -1099,7 +1141,8 @@ drm_gtf_modes_for_range(struct drm_connector *connector, struct edid *edid, return modes; fixup_mode_1366x768(newmode); - if (!mode_in_range(newmode, edid, timing)) { + if (!mode_in_range(newmode, edid, timing) || + !valid_inferred_mode(connector, newmode)) { drm_mode_destroy(dev, newmode); continue; } @@ -1127,7 +1170,8 @@ drm_cvt_modes_for_range(struct drm_connector *connector, struct edid *edid, return modes; fixup_mode_1366x768(newmode); - if (!mode_in_range(newmode, edid, timing)) { + if (!mode_in_range(newmode, edid, timing) || + !valid_inferred_mode(connector, newmode)) { drm_mode_destroy(dev, newmode); continue; } @@ -1201,7 +1245,7 @@ drm_est3_modes(struct drm_connector *connector, struct detailed_timing *timing) for (i = 0; i < 6; i++) { for (j = 7; j > 0; j--) { m = (i * 8) + (7 - j); - if (m >= DRM_ARRAY_SIZE(est3_modes)) + if (m >= ARRAY_SIZE(est3_modes)) break; if (est[i] & (1 << j)) { mode = drm_mode_find_dmt(connector->dev, @@ -1453,6 +1497,7 @@ add_detailed_modes(struct drm_connector *connector, struct edid *edid, #define HDMI_IDENTIFIER 0x000C03 #define AUDIO_BLOCK 0x01 +#define VIDEO_BLOCK 0x02 #define VENDOR_BLOCK 0x03 #define SPEAKER_BLOCK 0x04 #define EDID_BASIC_AUDIO (1 << 6) @@ -1483,21 +1528,133 @@ u8 *drm_find_cea_extension(struct edid *edid) return edid_ext; } +EXPORT_SYMBOL(drm_find_cea_extension); -static void -parse_hdmi_vsdb(struct drm_connector *connector, uint8_t *db) +/* + * Looks for a CEA mode matching given drm_display_mode. + * Returns its CEA Video ID code, or 0 if not found. + */ +u8 drm_match_cea_mode(struct drm_display_mode *to_match) +{ + struct drm_display_mode *cea_mode; + u8 mode; + + for (mode = 0; mode < drm_num_cea_modes; mode++) { + cea_mode = (struct drm_display_mode *)&edid_cea_modes[mode]; + + if (drm_mode_equal(to_match, cea_mode)) + return mode + 1; + } + return 0; +} +EXPORT_SYMBOL(drm_match_cea_mode); + + +static int +do_cea_modes (struct drm_connector *connector, u8 *db, u8 len) +{ + struct drm_device *dev = connector->dev; + u8 * mode, cea_mode; + int modes = 0; + + for (mode = db; mode < db + len; mode++) { + cea_mode = (*mode & 127) - 1; /* CEA modes are numbered 1..127 */ + if (cea_mode < drm_num_cea_modes) { + struct drm_display_mode *newmode; + newmode = drm_mode_duplicate(dev, + &edid_cea_modes[cea_mode]); + if (newmode) { + drm_mode_probed_add(connector, newmode); + modes++; + } + } + } + + return modes; +} + +static int +cea_db_payload_len(const u8 *db) +{ + return db[0] & 0x1f; +} + +static int +cea_db_tag(const u8 *db) +{ + return db[0] >> 5; +} + +static int +cea_revision(const u8 *cea) +{ + return cea[1]; +} + +static int +cea_db_offsets(const u8 *cea, int *start, int *end) { - connector->eld[5] |= (db[6] >> 7) << 1; /* Supports_AI */ + /* Data block offset in CEA extension block */ + *start = 4; + *end = cea[2]; + if (*end == 0) + *end = 127; + if (*end < 4 || *end > 127) + return -ERANGE; + return 0; +} - connector->dvi_dual = db[6] & 1; - connector->max_tmds_clock = db[7] * 5; +#define for_each_cea_db(cea, i, start, end) \ + for ((i) = (start); (i) < (end) && (i) + cea_db_payload_len(&(cea)[(i)]) < (end); (i) += cea_db_payload_len(&(cea)[(i)]) + 1) - connector->latency_present[0] = db[8] >> 7; - connector->latency_present[1] = (db[8] >> 6) & 1; - connector->video_latency[0] = db[9]; - connector->audio_latency[0] = db[10]; - connector->video_latency[1] = db[11]; - connector->audio_latency[1] = db[12]; +static int +add_cea_modes(struct drm_connector *connector, struct edid *edid) +{ + u8 * cea = drm_find_cea_extension(edid); + u8 * db, dbl; + int modes = 0; + + if (cea && cea_revision(cea) >= 3) { + int i, start, end; + + if (cea_db_offsets(cea, &start, &end)) + return 0; + + for_each_cea_db(cea, i, start, end) { + db = &cea[i]; + dbl = cea_db_payload_len(db); + + if (cea_db_tag(db) == VIDEO_BLOCK) + modes += do_cea_modes (connector, db+1, dbl); + } + } + + return modes; +} + +static void +parse_hdmi_vsdb(struct drm_connector *connector, const u8 *db) +{ + u8 len = cea_db_payload_len(db); + + if (len >= 6) { + connector->eld[5] |= (db[6] >> 7) << 1; /* Supports_AI */ + connector->dvi_dual = db[6] & 1; + } + if (len >= 7) + connector->max_tmds_clock = db[7] * 5; + if (len >= 8) { + connector->latency_present[0] = db[8] >> 7; + connector->latency_present[1] = (db[8] >> 6) & 1; + } + if (len >= 9) + connector->video_latency[0] = db[9]; + if (len >= 10) + connector->audio_latency[0] = db[10]; + if (len >= 11) + connector->video_latency[1] = db[11]; + if (len >= 12) + connector->audio_latency[1] = db[12]; DRM_DEBUG_KMS("HDMI: DVI dual %d, " "max TMDS clock %d, " @@ -1521,6 +1678,21 @@ monitor_name(struct detailed_timing *t, void *data) *(u8 **)data = t->data.other_data.data.str.str; } +static bool cea_db_is_hdmi_vsdb(const u8 *db) +{ + int hdmi_id; + + if (cea_db_tag(db) != VENDOR_BLOCK) + return false; + + if (cea_db_payload_len(db) < 5) + return false; + + hdmi_id = db[1] | (db[2] << 8) | (db[3] << 16); + + return hdmi_id == HDMI_IDENTIFIER; +} + /** * drm_edid_to_eld - build ELD from EDID * @connector: connector corresponding to the HDMI/DP sink @@ -1567,24 +1739,38 @@ void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid) eld[18] = edid->prod_code[0]; eld[19] = edid->prod_code[1]; - for (db = cea + 4; db < cea + cea[2]; db += dbl + 1) { - dbl = db[0] & 0x1f; + if (cea_revision(cea) >= 3) { + int i, start, end; - switch ((db[0] & 0xe0) >> 5) { - case AUDIO_BLOCK: /* Audio Data Block, contains SADs */ - sad_count = dbl / 3; - memcpy(eld + 20 + mnl, &db[1], dbl); - break; - case SPEAKER_BLOCK: /* Speaker Allocation Data Block */ - eld[7] = db[1]; - break; - case VENDOR_BLOCK: - /* HDMI Vendor-Specific Data Block */ - if (db[1] == 0x03 && db[2] == 0x0c && db[3] == 0) - parse_hdmi_vsdb(connector, db); - break; - default: - break; + if (cea_db_offsets(cea, &start, &end)) { + start = 0; + end = 0; + } + + for_each_cea_db(cea, i, start, end) { + db = &cea[i]; + dbl = cea_db_payload_len(db); + + switch (cea_db_tag(db)) { + case AUDIO_BLOCK: + /* Audio Data Block, contains SADs */ + sad_count = dbl / 3; + if (dbl >= 1) + memcpy(eld + 20 + mnl, &db[1], dbl); + break; + case SPEAKER_BLOCK: + /* Speaker Allocation Data Block */ + if (dbl >= 1) + eld[7] = db[1]; + break; + case VENDOR_BLOCK: + /* HDMI Vendor-Specific Data Block */ + if (cea_db_is_hdmi_vsdb(db)) + parse_hdmi_vsdb(connector, db); + break; + default: + break; + } } } eld[5] |= sad_count << 4; @@ -1592,6 +1778,7 @@ void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid) DRM_DEBUG_KMS("ELD size %d, SAD count %d\n", (int)eld[2], sad_count); } +EXPORT_SYMBOL(drm_edid_to_eld); /** * drm_av_sync_delay - HDMI/DP sink audio-video sync delay in millisecond @@ -1629,6 +1816,7 @@ int drm_av_sync_delay(struct drm_connector *connector, return max(v - a, 0); } +EXPORT_SYMBOL(drm_av_sync_delay); /** * drm_select_eld - select one ELD from multiple HDMI/DP sinks @@ -1650,6 +1838,7 @@ struct drm_connector *drm_select_eld(struct drm_encoder *encoder, return NULL; } +EXPORT_SYMBOL(drm_select_eld); /** * drm_detect_hdmi_monitor - detect whether monitor is hdmi. @@ -1661,39 +1850,28 @@ struct drm_connector *drm_select_eld(struct drm_encoder *encoder, bool drm_detect_hdmi_monitor(struct edid *edid) { u8 *edid_ext; - int i, hdmi_id; + int i; int start_offset, end_offset; - bool is_hdmi = false; edid_ext = drm_find_cea_extension(edid); if (!edid_ext) - goto end; + return false; - /* Data block offset in CEA extension block */ - start_offset = 4; - end_offset = edid_ext[2]; + if (cea_db_offsets(edid_ext, &start_offset, &end_offset)) + return false; /* * Because HDMI identifier is in Vendor Specific Block, * search it from all data blocks of CEA extension. */ - for (i = start_offset; i < end_offset; - /* Increased by data block len */ - i += ((edid_ext[i] & 0x1f) + 1)) { - /* Find vendor specific block */ - if ((edid_ext[i] >> 5) == VENDOR_BLOCK) { - hdmi_id = edid_ext[i + 1] | (edid_ext[i + 2] << 8) | - edid_ext[i + 3] << 16; - /* Find HDMI identifier */ - if (hdmi_id == HDMI_IDENTIFIER) - is_hdmi = true; - break; - } + for_each_cea_db(edid_ext, i, start_offset, end_offset) { + if (cea_db_is_hdmi_vsdb(&edid_ext[i])) + return true; } -end: - return is_hdmi; + return false; } +EXPORT_SYMBOL(drm_detect_hdmi_monitor); /** * drm_detect_monitor_audio - check monitor audio capability @@ -1723,15 +1901,13 @@ bool drm_detect_monitor_audio(struct edid *edid) goto end; } - /* Data block offset in CEA extension block */ - start_offset = 4; - end_offset = edid_ext[2]; + if (cea_db_offsets(edid_ext, &start_offset, &end_offset)) + goto end; - for (i = start_offset; i < end_offset; - i += ((edid_ext[i] & 0x1f) + 1)) { - if ((edid_ext[i] >> 5) == AUDIO_BLOCK) { + for_each_cea_db(edid_ext, i, start_offset, end_offset) { + if (cea_db_tag(&edid_ext[i]) == AUDIO_BLOCK) { has_audio = true; - for (j = 1; j < (edid_ext[i] & 0x1f); j += 3) + for (j = 1; j < cea_db_payload_len(&edid_ext[i]) + 1; j += 3) DRM_DEBUG_KMS("CEA audio format %d\n", (edid_ext[i + j] >> 3) & 0xf); goto end; @@ -1740,6 +1916,7 @@ bool drm_detect_monitor_audio(struct edid *edid) end: return has_audio; } +EXPORT_SYMBOL(drm_detect_monitor_audio); /** * drm_add_display_info - pull display info out if present @@ -1835,7 +2012,7 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid) return 0; } if (!drm_edid_is_valid(edid)) { - device_printf(connector->dev->device, "%s: EDID invalid.\n", + dev_warn(connector->dev->dev, "%s: EDID invalid.\n", drm_get_connector_name(connector)); return 0; } @@ -1860,7 +2037,9 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid) num_modes += add_cvt_modes(connector, edid); num_modes += add_standard_modes(connector, edid); num_modes += add_established_modes(connector, edid); - num_modes += add_inferred_modes(connector, edid); + if (edid->features & DRM_EDID_FEATURE_DEFAULT_GTF) + num_modes += add_inferred_modes(connector, edid); + num_modes += add_cea_modes(connector, edid); if (quirks & (EDID_QUIRK_PREFER_LARGE_60 | EDID_QUIRK_PREFER_LARGE_75)) edid_fixup_preferred(connector, quirks); @@ -1869,6 +2048,7 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid) return num_modes; } +EXPORT_SYMBOL(drm_add_edid_modes); /** * drm_add_modes_noedid - add modes for the connectors without EDID @@ -1895,7 +2075,7 @@ int drm_add_modes_noedid(struct drm_connector *connector, vdisplay = 0; for (i = 0; i < count; i++) { - struct drm_display_mode *ptr = &drm_dmt_modes[i]; + const struct drm_display_mode *ptr = &drm_dmt_modes[i]; if (hdisplay && vdisplay) { /* * Only when two are valid, they will be used to check @@ -1916,3 +2096,23 @@ int drm_add_modes_noedid(struct drm_connector *connector, } return num_modes; } +EXPORT_SYMBOL(drm_add_modes_noedid); + +/** + * drm_mode_cea_vic - return the CEA-861 VIC of a given mode + * @mode: mode + * + * RETURNS: + * The VIC number, 0 in case it's not a CEA-861 mode. + */ +uint8_t drm_mode_cea_vic(const struct drm_display_mode *mode) +{ + uint8_t i; + + for (i = 0; i < drm_num_cea_modes; i++) + if (drm_mode_equal(mode, &edid_cea_modes[i])) + return i + 1; + + return 0; +} +EXPORT_SYMBOL(drm_mode_cea_vic); diff --git a/sys/dev/drm2/drm_edid.h b/sys/dev/drm2/drm_edid.h index 3dfe6e3c133c..0132b6f6f0f6 100644 --- a/sys/dev/drm2/drm_edid.h +++ b/sys/dev/drm2/drm_edid.h @@ -25,9 +25,6 @@ #ifndef __DRM_EDID_H__ #define __DRM_EDID_H__ -#include <sys/types.h> -#include <dev/drm2/drmP.h> - #define EDID_LENGTH 128 #define DDC_ADDR 0x50 @@ -99,7 +96,7 @@ struct detailed_data_monitor_range { u8 reserved; u8 hfreq_start_khz; /* need to multiply by 2 */ u8 c; /* need to divide by 2 */ - u16 m; + __le16 m; u8 k; u8 j; /* need to divide by 2 */ } __attribute__((packed)) gtf2; @@ -159,7 +156,7 @@ struct detailed_non_pixel { #define EDID_DETAIL_MONITOR_SERIAL 0xff struct detailed_timing { - u16 pixel_clock; /* need to multiply by 10 KHz */ + __le16 pixel_clock; /* need to multiply by 10 KHz */ union { struct detailed_pixel_timing pixel_data; struct detailed_non_pixel other_data; @@ -192,6 +189,7 @@ struct detailed_timing { #define DRM_EDID_FEATURE_DEFAULT_GTF (1 << 0) #define DRM_EDID_FEATURE_PREFERRED_TIMING (1 << 1) #define DRM_EDID_FEATURE_STANDARD_COLOR (1 << 2) +/* If analog */ #define DRM_EDID_FEATURE_DISPLAY_TYPE (3 << 3) /* 00=mono, 01=rgb, 10=non-rgb, 11=unknown */ /* If digital */ #define DRM_EDID_FEATURE_COLOR_MASK (3 << 3) @@ -254,5 +252,6 @@ int drm_av_sync_delay(struct drm_connector *connector, struct drm_display_mode *mode); struct drm_connector *drm_select_eld(struct drm_encoder *encoder, struct drm_display_mode *mode); +int drm_load_edid_firmware(struct drm_connector *connector); #endif /* __DRM_EDID_H__ */ diff --git a/sys/dev/drm2/drm_edid_modes.h b/sys/dev/drm2/drm_edid_modes.h index b6431d36c108..27fe5552f0cf 100644 --- a/sys/dev/drm2/drm_edid_modes.h +++ b/sys/dev/drm2/drm_edid_modes.h @@ -32,7 +32,7 @@ * Autogenerated from the DMT spec. * This table is copied from xfree86/modes/xf86EdidModes.c. */ -static struct drm_display_mode drm_dmt_modes[] = { +static const struct drm_display_mode drm_dmt_modes[] = { /* 640x350@85Hz */ { DRM_MODE("640x350", DRM_MODE_TYPE_DRIVER, 31500, 640, 672, 736, 832, 0, 350, 382, 385, 445, 0, @@ -90,7 +90,7 @@ static struct drm_display_mode drm_dmt_modes[] = { 976, 1088, 0, 480, 486, 494, 517, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 1024x768@43Hz, interlace */ - { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 44900, 1024, 1032, + { DRM_MODE("1024x768i", DRM_MODE_TYPE_DRIVER, 44900, 1024, 1032, 1208, 1264, 0, 768, 768, 772, 817, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC | DRM_MODE_FLAG_INTERLACE) }, @@ -359,7 +359,7 @@ static struct drm_display_mode drm_dmt_modes[] = { static const int drm_num_dmt_modes = sizeof(drm_dmt_modes) / sizeof(struct drm_display_mode); -static struct drm_display_mode edid_est_modes[] = { +static const struct drm_display_mode edid_est_modes[] = { { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 40000, 800, 840, 968, 1056, 0, 600, 601, 605, 628, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 800x600@60Hz */ @@ -396,7 +396,7 @@ static struct drm_display_mode edid_est_modes[] = { { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 65000, 1024, 1048, 1184, 1344, 0, 768, 771, 777, 806, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 1024x768@60Hz */ - { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER,44900, 1024, 1032, + { DRM_MODE("1024x768i", DRM_MODE_TYPE_DRIVER,44900, 1024, 1032, 1208, 1264, 0, 768, 768, 776, 817, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC | DRM_MODE_FLAG_INTERLACE) }, /* 1024x768@43Hz */ { DRM_MODE("832x624", DRM_MODE_TYPE_DRIVER, 57284, 832, 864, @@ -472,7 +472,7 @@ static const struct minimode est3_modes[] = { { 1920, 1440, 60, 0 }, { 1920, 1440, 75, 0 }, }; -static const int num_est3_modes = DRM_ARRAY_SIZE(est3_modes); +static const int num_est3_modes = ARRAY_SIZE(est3_modes); static const struct minimode extra_modes[] = { { 1024, 576, 60, 0 }, @@ -483,7 +483,7 @@ static const struct minimode extra_modes[] = { { 2048, 1152, 60, 0 }, { 2048, 1536, 60, 0 }, }; -static const int num_extra_modes = DRM_ARRAY_SIZE(extra_modes); +static const int num_extra_modes = ARRAY_SIZE(extra_modes); /* * Probably taken from CEA-861 spec. @@ -507,17 +507,17 @@ static const struct drm_display_mode edid_cea_modes[] = { 1430, 1650, 0, 720, 725, 730, 750, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 5 - 1920x1080i@60Hz */ - { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2008, + { DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2008, 2052, 2200, 0, 1080, 1084, 1094, 1125, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC | DRM_MODE_FLAG_INTERLACE) }, /* 6 - 1440x480i@60Hz */ - { DRM_MODE("1440x480", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478, + { DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478, 1602, 1716, 0, 480, 488, 494, 525, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) }, /* 7 - 1440x480i@60Hz */ - { DRM_MODE("1440x480", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478, + { DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478, 1602, 1716, 0, 480, 488, 494, 525, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) }, @@ -532,12 +532,12 @@ static const struct drm_display_mode edid_cea_modes[] = { DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_DBLCLK) }, /* 10 - 2880x480i@60Hz */ - { DRM_MODE("2880x480", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2956, + { DRM_MODE("2880x480i", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2956, 3204, 3432, 0, 480, 488, 494, 525, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_INTERLACE) }, /* 11 - 2880x480i@60Hz */ - { DRM_MODE("2880x480", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2956, + { DRM_MODE("2880x480i", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2956, 3204, 3432, 0, 480, 488, 494, 525, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_INTERLACE) }, @@ -574,17 +574,17 @@ static const struct drm_display_mode edid_cea_modes[] = { 1760, 1980, 0, 720, 725, 730, 750, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 20 - 1920x1080i@50Hz */ - { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2448, + { DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2448, 2492, 2640, 0, 1080, 1084, 1094, 1125, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC | DRM_MODE_FLAG_INTERLACE) }, /* 21 - 1440x576i@50Hz */ - { DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464, + { DRM_MODE("1440x576i", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464, 1590, 1728, 0, 576, 580, 586, 625, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) }, /* 22 - 1440x576i@50Hz */ - { DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464, + { DRM_MODE("1440x576i", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464, 1590, 1728, 0, 576, 580, 586, 625, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) }, @@ -599,12 +599,12 @@ static const struct drm_display_mode edid_cea_modes[] = { DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_DBLCLK) }, /* 25 - 2880x576i@50Hz */ - { DRM_MODE("2880x576", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2928, + { DRM_MODE("2880x576i", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2928, 3180, 3456, 0, 576, 580, 586, 625, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_INTERLACE) }, /* 26 - 2880x576i@50Hz */ - { DRM_MODE("2880x576", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2928, + { DRM_MODE("2880x576i", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2928, 3180, 3456, 0, 576, 580, 586, 625, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_INTERLACE) }, @@ -657,12 +657,12 @@ static const struct drm_display_mode edid_cea_modes[] = { 3184, 3456, 0, 576, 581, 586, 625, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 39 - 1920x1080i@50Hz */ - { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 72000, 1920, 1952, + { DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 72000, 1920, 1952, 2120, 2304, 0, 1080, 1126, 1136, 1250, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_INTERLACE) }, /* 40 - 1920x1080i@100Hz */ - { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2448, + { DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2448, 2492, 2640, 0, 1080, 1084, 1094, 1125, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC | DRM_MODE_FLAG_INTERLACE) }, @@ -689,7 +689,7 @@ static const struct drm_display_mode edid_cea_modes[] = { DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_DBLCLK) }, /* 46 - 1920x1080i@120Hz */ - { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2008, + { DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2008, 2052, 2200, 0, 1080, 1084, 1094, 1125, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC | DRM_MODE_FLAG_INTERLACE) }, @@ -706,12 +706,12 @@ static const struct drm_display_mode edid_cea_modes[] = { 798, 858, 0, 480, 489, 495, 525, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 50 - 1440x480i@120Hz */ - { DRM_MODE("1440x480", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1478, + { DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1478, 1602, 1716, 0, 480, 488, 494, 525, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) }, /* 51 - 1440x480i@120Hz */ - { DRM_MODE("1440x480", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1478, + { DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1478, 1602, 1716, 0, 480, 488, 494, 525, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) }, @@ -724,12 +724,12 @@ static const struct drm_display_mode edid_cea_modes[] = { 796, 864, 0, 576, 581, 586, 625, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 54 - 1440x576i@200Hz */ - { DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1464, + { DRM_MODE("1440x576i", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1464, 1590, 1728, 0, 576, 580, 586, 625, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) }, /* 55 - 1440x576i@200Hz */ - { DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1464, + { DRM_MODE("1440x576i", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1464, 1590, 1728, 0, 576, 580, 586, 625, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) }, @@ -742,12 +742,12 @@ static const struct drm_display_mode edid_cea_modes[] = { 798, 858, 0, 480, 489, 495, 525, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 58 - 1440x480i@240 */ - { DRM_MODE("1440x480", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1478, + { DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1478, 1602, 1716, 0, 480, 488, 494, 525, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) }, /* 59 - 1440x480i@240 */ - { DRM_MODE("1440x480", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1478, + { DRM_MODE("1440x480i", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1478, 1602, 1716, 0, 480, 488, 494, 525, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) }, @@ -772,4 +772,4 @@ static const struct drm_display_mode edid_cea_modes[] = { 2492, 2640, 0, 1080, 1084, 1094, 1125, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, }; -static const int drm_num_cea_modes = DRM_ARRAY_SIZE(edid_cea_modes); +static const int drm_num_cea_modes = ARRAY_SIZE(edid_cea_modes); diff --git a/sys/dev/drm2/drm_fb_helper.c b/sys/dev/drm2/drm_fb_helper.c index e56dce7f1f0c..5014fcdc3280 100644 --- a/sys/dev/drm2/drm_fb_helper.c +++ b/sys/dev/drm2/drm_fb_helper.c @@ -31,23 +31,28 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <dev/drm2/drmP.h> #include <dev/drm2/drm_crtc.h> #include <dev/drm2/drm_fb_helper.h> #include <dev/drm2/drm_crtc_helper.h> +MODULE_AUTHOR("David Airlie, Jesse Barnes"); +MODULE_DESCRIPTION("DRM KMS helper"); +MODULE_LICENSE("GPL and additional rights"); + +static DRM_LIST_HEAD(kernel_fb_helper_list); + #include <sys/kdb.h> #include <sys/param.h> #include <sys/systm.h> struct vt_kms_softc { - struct drm_fb_helper *fb_helper; - struct task fb_mode_task; + struct drm_fb_helper *fb_helper; + struct task fb_mode_task; }; -static fb_enter_t vt_kms_postswitch; -static void vt_restore_fbdev_mode(void *, int); - /* Call restore out of vt(9) locks. */ static void vt_restore_fbdev_mode(void *arg, int pending) @@ -77,25 +82,29 @@ vt_kms_postswitch(void *arg) return (0); } -static DRM_LIST_HEAD(kernel_fb_helper_list); - -/* simple single crtc case helper function */ -int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper) +struct fb_info * +framebuffer_alloc() { - struct drm_device *dev = fb_helper->dev; - struct drm_connector *connector; + struct fb_info *info; + struct vt_kms_softc *sc; - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - struct drm_fb_helper_connector *fb_helper_connector; + info = malloc(sizeof(*info), DRM_MEM_KMS, M_WAITOK | M_ZERO); - fb_helper_connector = malloc( - sizeof(struct drm_fb_helper_connector), DRM_MEM_KMS, - M_WAITOK | M_ZERO); + sc = malloc(sizeof(*sc), DRM_MEM_KMS, M_WAITOK | M_ZERO); + TASK_INIT(&sc->fb_mode_task, 0, vt_restore_fbdev_mode, sc); - fb_helper_connector->connector = connector; - fb_helper->connector_info[fb_helper->connector_count++] = fb_helper_connector; - } - return 0; + info->fb_priv = sc; + info->enter = &vt_kms_postswitch; + + return (info); +} + +void +framebuffer_release(struct fb_info *info) +{ + + free(info->fb_priv, DRM_MEM_KMS); + free(info, DRM_MEM_KMS); } static int @@ -125,9 +134,47 @@ fb_get_options(const char *connector_name, char **option) if (*option == NULL) *option = kern_getenv("kern.vt.fb.default_mode"); - return (*option != NULL ? 0 : 1); + return (*option != NULL ? 0 : -ENOENT); } +/** + * DOC: fbdev helpers + * + * The fb helper functions are useful to provide an fbdev on top of a drm kernel + * mode setting driver. They can be used mostly independantely from the crtc + * helper functions used by many drivers to implement the kernel mode setting + * interfaces. + */ + +/* simple single crtc case helper function */ +int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper) +{ + struct drm_device *dev = fb_helper->dev; + struct drm_connector *connector; + int i; + + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + struct drm_fb_helper_connector *fb_helper_connector; + + fb_helper_connector = malloc(sizeof(struct drm_fb_helper_connector), + DRM_MEM_KMS, M_NOWAIT | M_ZERO); + if (!fb_helper_connector) + goto fail; + + fb_helper_connector->connector = connector; + fb_helper->connector_info[fb_helper->connector_count++] = fb_helper_connector; + } + return 0; +fail: + for (i = 0; i < fb_helper->connector_count; i++) { + free(fb_helper->connector_info[i], DRM_MEM_KMS); + fb_helper->connector_info[i] = NULL; + } + fb_helper->connector_count = 0; + return -ENOMEM; +} +EXPORT_SYMBOL(drm_fb_helper_single_add_all_connectors); + static int drm_fb_helper_parse_command_line(struct drm_fb_helper *fb_helper) { struct drm_fb_helper_connector *fb_helper_conn; @@ -169,7 +216,7 @@ static int drm_fb_helper_parse_command_line(struct drm_fb_helper *fb_helper) connector->force = mode->force; } - DRM_INFO("cmdline mode for connector %s %dx%d@%dHz%s%s%s\n", + DRM_DEBUG_KMS("cmdline mode for connector %s %dx%d@%dHz%s%s%s\n", drm_get_connector_name(connector), mode->xres, mode->yres, mode->refresh_specified ? mode->refresh : 60, @@ -179,12 +226,11 @@ static int drm_fb_helper_parse_command_line(struct drm_fb_helper *fb_helper) } freeenv(option); - } return 0; } -#if 0 +#if 0 && defined(FREEBSD_NOTYET) static void drm_fb_helper_save_lut_atomic(struct drm_crtc *crtc, struct drm_fb_helper *helper) { uint16_t *r_base, *g_base, *b_base; @@ -211,9 +257,7 @@ static void drm_fb_helper_restore_lut_atomic(struct drm_crtc *crtc) crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, 0, crtc->gamma_size); } -#endif -#if 0 int drm_fb_helper_debug_enter(struct fb_info *info) { struct drm_fb_helper *helper = info->par; @@ -243,9 +287,8 @@ int drm_fb_helper_debug_enter(struct fb_info *info) return 0; } -#endif +EXPORT_SYMBOL(drm_fb_helper_debug_enter); -#if 0 /* Find the real fb for a given fb helper CRTC */ static struct drm_framebuffer *drm_mode_config_fb(struct drm_crtc *crtc) { @@ -259,9 +302,7 @@ static struct drm_framebuffer *drm_mode_config_fb(struct drm_crtc *crtc) return NULL; } -#endif -#if 0 int drm_fb_helper_debug_leave(struct fb_info *info) { struct drm_fb_helper *helper = info->par; @@ -291,7 +332,8 @@ int drm_fb_helper_debug_leave(struct fb_info *info) return 0; } -#endif +EXPORT_SYMBOL(drm_fb_helper_debug_leave); +#endif /* FREEBSD_NOTYET */ bool drm_fb_helper_restore_fbdev_mode(struct drm_fb_helper *fb_helper) { @@ -299,15 +341,15 @@ bool drm_fb_helper_restore_fbdev_mode(struct drm_fb_helper *fb_helper) int i, ret; for (i = 0; i < fb_helper->crtc_count; i++) { struct drm_mode_set *mode_set = &fb_helper->crtc_info[i].mode_set; - ret = drm_crtc_helper_set_config(mode_set); + ret = mode_set->crtc->funcs->set_config(mode_set); if (ret) error = true; } return error; } +EXPORT_SYMBOL(drm_fb_helper_restore_fbdev_mode); -#if 0 -bool drm_fb_helper_force_kernel_mode(void) +static bool drm_fb_helper_force_kernel_mode(void) { bool ret, error = false; struct drm_fb_helper *helper; @@ -325,20 +367,27 @@ bool drm_fb_helper_force_kernel_mode(void) } return error; } -#endif -#if 0 +#if 0 && defined(FREEBSD_NOTYET) int drm_fb_helper_panic(struct notifier_block *n, unsigned long ununsed, void *panic_str) { - printf("panic occurred, switching back to text console\n"); + /* + * It's a waste of time and effort to switch back to text console + * if the kernel should reboot before panic messages can be seen. + */ + if (panic_timeout < 0) + return 0; + + pr_err("panic occurred, switching back to text console\n"); return drm_fb_helper_force_kernel_mode(); - return 0; } +EXPORT_SYMBOL(drm_fb_helper_panic); static struct notifier_block paniced = { .notifier_call = drm_fb_helper_panic, }; +#endif /* FREEBSD_NOTYET */ /** * drm_fb_helper_restore - restore the framebuffer console (kernel) config @@ -352,7 +401,9 @@ void drm_fb_helper_restore(void) if (ret == true) DRM_ERROR("Failed to restore crtc configuration\n"); } +EXPORT_SYMBOL(drm_fb_helper_restore); +#ifdef __linux__ #ifdef CONFIG_MAGIC_SYSRQ static void drm_fb_helper_restore_work_fn(struct work_struct *ignored) { @@ -375,127 +426,64 @@ static struct sysrq_key_op sysrq_drm_fb_helper_restore_op = { }; #endif #endif -#if 0 -static void drm_fb_helper_on(struct fb_info *info) +#if 0 && defined(FREEBSD_NOTYET) +static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode) { struct drm_fb_helper *fb_helper = info->par; struct drm_device *dev = fb_helper->dev; struct drm_crtc *crtc; - struct drm_crtc_helper_funcs *crtc_funcs; struct drm_connector *connector; - struct drm_encoder *encoder; int i, j; /* - * For each CRTC in this fb, turn the crtc on then, - * find all associated encoders and turn them on. + * For each CRTC in this fb, turn the connectors on/off. */ sx_xlock(&dev->mode_config.mutex); for (i = 0; i < fb_helper->crtc_count; i++) { crtc = fb_helper->crtc_info[i].mode_set.crtc; - crtc_funcs = crtc->helper_private; if (!crtc->enabled) continue; - crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON); - - /* Walk the connectors & encoders on this fb turning them on */ + /* Walk the connectors & encoders on this fb turning them on/off */ for (j = 0; j < fb_helper->connector_count; j++) { connector = fb_helper->connector_info[j]->connector; - connector->dpms = DRM_MODE_DPMS_ON; - drm_connector_property_set_value(connector, - dev->mode_config.dpms_property, - DRM_MODE_DPMS_ON); - } - /* Found a CRTC on this fb, now find encoders */ - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { - if (encoder->crtc == crtc) { - struct drm_encoder_helper_funcs *encoder_funcs; - - encoder_funcs = encoder->helper_private; - encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON); - } + connector->funcs->dpms(connector, dpms_mode); + drm_object_property_set_value(&connector->base, + dev->mode_config.dpms_property, dpms_mode); } } sx_xunlock(&dev->mode_config.mutex); } -#endif - -#if 0 -static void drm_fb_helper_off(struct fb_info *info, int dpms_mode) -{ - struct drm_fb_helper *fb_helper = info->par; - struct drm_device *dev = fb_helper->dev; - struct drm_crtc *crtc; - struct drm_crtc_helper_funcs *crtc_funcs; - struct drm_connector *connector; - struct drm_encoder *encoder; - int i, j; - /* - * For each CRTC in this fb, find all associated encoders - * and turn them off, then turn off the CRTC. - */ - sx_xlock(&dev->mode_config.mutex); - for (i = 0; i < fb_helper->crtc_count; i++) { - crtc = fb_helper->crtc_info[i].mode_set.crtc; - crtc_funcs = crtc->helper_private; - - if (!crtc->enabled) - continue; - - /* Walk the connectors on this fb and mark them off */ - for (j = 0; j < fb_helper->connector_count; j++) { - connector = fb_helper->connector_info[j]->connector; - connector->dpms = dpms_mode; - drm_connector_property_set_value(connector, - dev->mode_config.dpms_property, - dpms_mode); - } - /* Found a CRTC on this fb, now find encoders */ - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { - if (encoder->crtc == crtc) { - struct drm_encoder_helper_funcs *encoder_funcs; - - encoder_funcs = encoder->helper_private; - encoder_funcs->dpms(encoder, dpms_mode); - } - } - crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF); - } - sx_xunlock(&dev->mode_config.mutex); -} -#endif - -#if 0 int drm_fb_helper_blank(int blank, struct fb_info *info) { switch (blank) { /* Display: On; HSync: On, VSync: On */ case FB_BLANK_UNBLANK: - drm_fb_helper_on(info); + drm_fb_helper_dpms(info, DRM_MODE_DPMS_ON); break; /* Display: Off; HSync: On, VSync: On */ case FB_BLANK_NORMAL: - drm_fb_helper_off(info, DRM_MODE_DPMS_STANDBY); + drm_fb_helper_dpms(info, DRM_MODE_DPMS_STANDBY); break; /* Display: Off; HSync: Off, VSync: On */ case FB_BLANK_HSYNC_SUSPEND: - drm_fb_helper_off(info, DRM_MODE_DPMS_STANDBY); + drm_fb_helper_dpms(info, DRM_MODE_DPMS_STANDBY); break; /* Display: Off; HSync: On, VSync: Off */ case FB_BLANK_VSYNC_SUSPEND: - drm_fb_helper_off(info, DRM_MODE_DPMS_SUSPEND); + drm_fb_helper_dpms(info, DRM_MODE_DPMS_SUSPEND); break; /* Display: Off; HSync: Off, VSync: Off */ case FB_BLANK_POWERDOWN: - drm_fb_helper_off(info, DRM_MODE_DPMS_OFF); + drm_fb_helper_dpms(info, DRM_MODE_DPMS_OFF); break; } return 0; } -#endif +EXPORT_SYMBOL(drm_fb_helper_blank); +#endif /* FREEBSD_NOTYET */ static void drm_fb_helper_crtc_free(struct drm_fb_helper *helper) { @@ -523,52 +511,64 @@ int drm_fb_helper_init(struct drm_device *dev, INIT_LIST_HEAD(&fb_helper->kernel_fb_list); - fb_helper->crtc_info = malloc(crtc_count * - sizeof(struct drm_fb_helper_crtc), DRM_MEM_KMS, M_WAITOK | M_ZERO); + fb_helper->crtc_info = malloc(crtc_count * sizeof(struct drm_fb_helper_crtc), + DRM_MEM_KMS, M_NOWAIT | M_ZERO); + if (!fb_helper->crtc_info) + return -ENOMEM; fb_helper->crtc_count = crtc_count; - fb_helper->connector_info = malloc(dev->mode_config.num_connector * - sizeof(struct drm_fb_helper_connector *), DRM_MEM_KMS, - M_WAITOK | M_ZERO); + fb_helper->connector_info = malloc(dev->mode_config.num_connector * sizeof(struct drm_fb_helper_connector *), + DRM_MEM_KMS, M_NOWAIT | M_ZERO); + if (!fb_helper->connector_info) { + free(fb_helper->crtc_info, DRM_MEM_KMS); + return -ENOMEM; + } fb_helper->connector_count = 0; for (i = 0; i < crtc_count; i++) { fb_helper->crtc_info[i].mode_set.connectors = - malloc(max_conn_count * sizeof(struct drm_connector *), - DRM_MEM_KMS, M_WAITOK | M_ZERO); + malloc(max_conn_count * + sizeof(struct drm_connector *), + DRM_MEM_KMS, M_NOWAIT | M_ZERO); + if (!fb_helper->crtc_info[i].mode_set.connectors) + goto out_free; fb_helper->crtc_info[i].mode_set.num_connectors = 0; } i = 0; list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - fb_helper->crtc_info[i].crtc_id = crtc->base.id; fb_helper->crtc_info[i].mode_set.crtc = crtc; i++; } - fb_helper->conn_limit = max_conn_count; + return 0; +out_free: + drm_fb_helper_crtc_free(fb_helper); + return -ENOMEM; } +EXPORT_SYMBOL(drm_fb_helper_init); void drm_fb_helper_fini(struct drm_fb_helper *fb_helper) { if (!list_empty(&fb_helper->kernel_fb_list)) { list_del(&fb_helper->kernel_fb_list); +#if 0 && defined(FREEBSD_NOTYET) if (list_empty(&kernel_fb_helper_list)) { -#if 0 - printk(KERN_INFO "drm: unregistered panic notifier\n"); + pr_info("drm: unregistered panic notifier\n"); atomic_notifier_chain_unregister(&panic_notifier_list, &paniced); unregister_sysrq_key('v', &sysrq_drm_fb_helper_restore_op); -#endif } +#endif /* FREEBSD_NOTYET */ } drm_fb_helper_crtc_free(fb_helper); } +EXPORT_SYMBOL(drm_fb_helper_fini); -#if 0 +#if 0 && defined(FREEBSD_NOTYET) static int setcolreg(struct drm_crtc *crtc, u16 red, u16 green, u16 blue, u16 regno, struct fb_info *info) { @@ -576,7 +576,7 @@ static int setcolreg(struct drm_crtc *crtc, u16 red, u16 green, struct drm_framebuffer *fb = fb_helper->fb; int pindex; - if (info->fix.visual == FB_VISUAL_trueCOLOR) { + if (info->fix.visual == FB_VISUAL_TRUECOLOR) { u32 *palette; u32 value; /* place color in psuedopalette */ @@ -632,9 +632,7 @@ static int setcolreg(struct drm_crtc *crtc, u16 red, u16 green, fb_helper->funcs->gamma_set(crtc, red, green, blue, pindex); return 0; } -#endif -#if 0 int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info) { struct drm_fb_helper *fb_helper = info->par; @@ -672,9 +670,8 @@ int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info) } return rc; } -#endif +EXPORT_SYMBOL(drm_fb_helper_setcmap); -#if 0 int drm_fb_helper_check_var(struct fb_var_screeninfo *var, struct fb_info *info) { @@ -765,9 +762,8 @@ int drm_fb_helper_check_var(struct fb_var_screeninfo *var, } return 0; } -#endif +EXPORT_SYMBOL(drm_fb_helper_check_var); -#if 0 /* this will let fbcon do the mode init */ int drm_fb_helper_set_par(struct fb_info *info) { @@ -783,16 +779,16 @@ int drm_fb_helper_set_par(struct fb_info *info) return -EINVAL; } - mutex_lock(&dev->mode_config.mutex); + sx_xlock(&dev->mode_config.mutex); for (i = 0; i < fb_helper->crtc_count; i++) { crtc = fb_helper->crtc_info[i].mode_set.crtc; ret = crtc->funcs->set_config(&fb_helper->crtc_info[i].mode_set); if (ret) { - mutex_unlock(&dev->mode_config.mutex); + sx_xunlock(&dev->mode_config.mutex); return ret; } } - mutex_unlock(&dev->mode_config.mutex); + sx_xunlock(&dev->mode_config.mutex); if (fb_helper->delayed_hotplug) { fb_helper->delayed_hotplug = false; @@ -800,9 +796,8 @@ int drm_fb_helper_set_par(struct fb_info *info) } return 0; } -#endif +EXPORT_SYMBOL(drm_fb_helper_set_par); -#if 0 int drm_fb_helper_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) { @@ -813,7 +808,7 @@ int drm_fb_helper_pan_display(struct fb_var_screeninfo *var, int ret = 0; int i; - mutex_lock(&dev->mode_config.mutex); + sx_xlock(&dev->mode_config.mutex); for (i = 0; i < fb_helper->crtc_count; i++) { crtc = fb_helper->crtc_info[i].mode_set.crtc; @@ -830,10 +825,11 @@ int drm_fb_helper_pan_display(struct fb_var_screeninfo *var, } } } - mutex_unlock(&dev->mode_config.mutex); + sx_xunlock(&dev->mode_config.mutex); return ret; } -#endif +EXPORT_SYMBOL(drm_fb_helper_pan_display); +#endif /* FREEBSD_NOTYET */ int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, int preferred_bpp) @@ -844,8 +840,9 @@ int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, struct fb_info *info; struct drm_fb_helper_surface_size sizes; int gamma_size = 0; - struct vt_kms_softc *sc; +#if defined(__FreeBSD__) device_t kdev; +#endif memset(&sizes, 0, sizeof(struct drm_fb_helper_surface_size)); sizes.surface_depth = 24; @@ -855,9 +852,9 @@ int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, /* if driver picks 8 or 16 by default use that for both depth/bpp */ - if (preferred_bpp != sizes.surface_bpp) { + if (preferred_bpp != sizes.surface_bpp) sizes.surface_depth = sizes.surface_bpp = preferred_bpp; - } + /* first up get a count of crtcs now in use and new min/maxes width/heights */ for (i = 0; i < fb_helper->connector_count; i++) { struct drm_fb_helper_connector *fb_helper_conn = fb_helper->connector_info[i]; @@ -922,29 +919,16 @@ int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, if (new_fb < 0) return new_fb; - sc = malloc(sizeof(struct vt_kms_softc), DRM_MEM_KMS, - M_WAITOK | M_ZERO); - sc->fb_helper = fb_helper; - TASK_INIT(&sc->fb_mode_task, 0, vt_restore_fbdev_mode, sc); - info = fb_helper->fbdev; - info->fb_name = device_get_nameunit(fb_helper->dev->device); - info->fb_depth = fb_helper->fb->bits_per_pixel; - info->fb_height = fb_helper->fb->height; - info->fb_width = fb_helper->fb->width; - info->fb_stride = fb_helper->fb->pitches[0]; - info->fb_priv = sc; - info->enter = &vt_kms_postswitch; - - kdev = fb_helper->dev->device; + kdev = fb_helper->dev->dev; info->fb_video_dev = device_get_parent(kdev); /* set the fb pointer */ - for (i = 0; i < fb_helper->crtc_count; i++) { + for (i = 0; i < fb_helper->crtc_count; i++) fb_helper->crtc_info[i].mode_set.fb = fb_helper->fb; - } +#if defined(__FreeBSD__) if (new_fb) { int ret; @@ -959,102 +943,61 @@ int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, DRM_ERROR("Failed to attach fbd device: %d\n", ret); #endif } +#else + if (new_fb) { + info->var.pixclock = 0; + if (register_framebuffer(info) < 0) + return -EINVAL; + + dev_info(fb_helper->dev->dev, "fb%d: %s frame buffer device\n", + info->node, info->fix.id); + + } else { + drm_fb_helper_set_par(info); + } +#endif + +#if 0 && defined(FREEBSD_NOTYET) + /* Switch back to kernel console on panic */ + /* multi card linked list maybe */ + if (list_empty(&kernel_fb_helper_list)) { + dev_info(fb_helper->dev->dev, "registered panic notifier\n"); + atomic_notifier_chain_register(&panic_notifier_list, + &paniced); + register_sysrq_key('v', &sysrq_drm_fb_helper_restore_op); + } +#endif /* FREEBSD_NOTYET */ + if (new_fb) + list_add(&fb_helper->kernel_fb_list, &kernel_fb_helper_list); + return 0; } +EXPORT_SYMBOL(drm_fb_helper_single_fb_probe); -#if 0 void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch, uint32_t depth) { - info->fix.type = FB_TYPE_PACKED_PIXELS; - info->fix.visual = depth == 8 ? FB_VISUAL_PSEUDOCOLOR : - FB_VISUAL_trueCOLOR; - info->fix.mmio_start = 0; - info->fix.mmio_len = 0; - info->fix.type_aux = 0; - info->fix.xpanstep = 1; /* doing it in hw */ - info->fix.ypanstep = 1; /* doing it in hw */ - info->fix.ywrapstep = 0; - info->fix.accel = FB_ACCEL_NONE; - info->fix.type_aux = 0; - - info->fix.line_length = pitch; + info->fb_stride = pitch; + return; } +EXPORT_SYMBOL(drm_fb_helper_fill_fix); void drm_fb_helper_fill_var(struct fb_info *info, struct drm_fb_helper *fb_helper, uint32_t fb_width, uint32_t fb_height) { struct drm_framebuffer *fb = fb_helper->fb; - info->pseudo_palette = fb_helper->pseudo_palette; - info->var.xres_virtual = fb->width; - info->var.yres_virtual = fb->height; - info->var.bits_per_pixel = fb->bits_per_pixel; - info->var.accel_flags = FB_ACCELF_TEXT; - info->var.xoffset = 0; - info->var.yoffset = 0; - info->var.activate = FB_ACTIVATE_NOW; - info->var.height = -1; - info->var.width = -1; - - switch (fb->depth) { - case 8: - info->var.red.offset = 0; - info->var.green.offset = 0; - info->var.blue.offset = 0; - info->var.red.length = 8; /* 8bit DAC */ - info->var.green.length = 8; - info->var.blue.length = 8; - info->var.transp.offset = 0; - info->var.transp.length = 0; - break; - case 15: - info->var.red.offset = 10; - info->var.green.offset = 5; - info->var.blue.offset = 0; - info->var.red.length = 5; - info->var.green.length = 5; - info->var.blue.length = 5; - info->var.transp.offset = 15; - info->var.transp.length = 1; - break; - case 16: - info->var.red.offset = 11; - info->var.green.offset = 5; - info->var.blue.offset = 0; - info->var.red.length = 5; - info->var.green.length = 6; - info->var.blue.length = 5; - info->var.transp.offset = 0; - break; - case 24: - info->var.red.offset = 16; - info->var.green.offset = 8; - info->var.blue.offset = 0; - info->var.red.length = 8; - info->var.green.length = 8; - info->var.blue.length = 8; - info->var.transp.offset = 0; - info->var.transp.length = 0; - break; - case 32: - info->var.red.offset = 16; - info->var.green.offset = 8; - info->var.blue.offset = 0; - info->var.red.length = 8; - info->var.green.length = 8; - info->var.blue.length = 8; - info->var.transp.offset = 24; - info->var.transp.length = 8; - break; - default: - break; - } + struct vt_kms_softc *sc; + + info->fb_name = device_get_nameunit(fb_helper->dev->dev); + info->fb_width = fb->width; + info->fb_height = fb->height; + info->fb_depth = fb->bits_per_pixel; - info->var.xres = fb_width; - info->var.yres = fb_height; + sc = (struct vt_kms_softc *)info->fb_priv; + sc->fb_helper = fb_helper; } -#endif +EXPORT_SYMBOL(drm_fb_helper_fill_var); static int drm_fb_helper_probe_connector_modes(struct drm_fb_helper *fb_helper, uint32_t maxX, @@ -1101,7 +1044,7 @@ static struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_conne cmdline_mode = &fb_helper_conn->cmdline_mode; if (cmdline_mode->specified == false) - return (NULL); + return mode; /* attempt to find a matching mode in the list of modes * we have gotten so far, if not add a CVT mode that conforms @@ -1128,19 +1071,8 @@ static struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_conne } create_mode: - if (cmdline_mode->cvt) - mode = drm_cvt_mode(fb_helper_conn->connector->dev, - cmdline_mode->xres, cmdline_mode->yres, - cmdline_mode->refresh_specified ? cmdline_mode->refresh : 60, - cmdline_mode->rb, cmdline_mode->interlace, - cmdline_mode->margins); - else - mode = drm_gtf_mode(fb_helper_conn->connector->dev, - cmdline_mode->xres, cmdline_mode->yres, - cmdline_mode->refresh_specified ? cmdline_mode->refresh : 60, - cmdline_mode->interlace, - cmdline_mode->margins); - drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); + mode = drm_mode_create_from_cmdline_mode(fb_helper_conn->connector->dev, + cmdline_mode); list_add(&mode->head, &fb_helper_conn->connector->modes); return mode; } @@ -1149,11 +1081,11 @@ static bool drm_connector_enabled(struct drm_connector *connector, bool strict) { bool enable; - if (strict) { + if (strict) enable = connector->status == connector_status_connected; - } else { + else enable = connector->status != connector_status_disconnected; - } + return enable; } @@ -1316,8 +1248,9 @@ static int drm_pick_crtcs(struct drm_fb_helper *fb_helper, return best_score; crtcs = malloc(dev->mode_config.num_connector * - sizeof(struct drm_fb_helper_crtc *), DRM_MEM_KMS, - M_WAITOK | M_ZERO); + sizeof(struct drm_fb_helper_crtc *), DRM_MEM_KMS, M_NOWAIT | M_ZERO); + if (!crtcs) + return best_score; my_score = 1; if (connector->status == connector_status_connected) @@ -1337,9 +1270,8 @@ static int drm_pick_crtcs(struct drm_fb_helper *fb_helper, for (c = 0; c < fb_helper->crtc_count; c++) { crtc = &fb_helper->crtc_info[c]; - if ((encoder->possible_crtcs & (1 << c)) == 0) { + if ((encoder->possible_crtcs & (1 << c)) == 0) continue; - } for (o = 0; o < n; o++) if (best_crtcs[o] == crtc) @@ -1376,7 +1308,6 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper) struct drm_device *dev = fb_helper->dev; struct drm_fb_helper_crtc **crtcs; struct drm_display_mode **modes; - struct drm_encoder *encoder; struct drm_mode_set *modeset; bool *enabled; int width, height; @@ -1387,19 +1318,17 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper) width = dev->mode_config.max_width; height = dev->mode_config.max_height; - /* clean out all the encoder/crtc combos */ - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { - encoder->crtc = NULL; - } - crtcs = malloc(dev->mode_config.num_connector * - sizeof(struct drm_fb_helper_crtc *), DRM_MEM_KMS, - M_WAITOK | M_ZERO); + sizeof(struct drm_fb_helper_crtc *), DRM_MEM_KMS, M_NOWAIT | M_ZERO); modes = malloc(dev->mode_config.num_connector * - sizeof(struct drm_display_mode *), DRM_MEM_KMS, - M_WAITOK | M_ZERO); + sizeof(struct drm_display_mode *), DRM_MEM_KMS, M_NOWAIT | M_ZERO); enabled = malloc(dev->mode_config.num_connector * - sizeof(bool), DRM_MEM_KMS, M_WAITOK | M_ZERO); + sizeof(bool), DRM_MEM_KMS, M_NOWAIT | M_ZERO); + if (!crtcs || !modes || !enabled) { + DRM_ERROR("Memory allocation failed\n"); + goto out; + } + drm_enable_connectors(fb_helper, enabled); @@ -1438,6 +1367,7 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper) } } +out: free(crtcs, DRM_MEM_KMS); free(modes, DRM_MEM_KMS); free(enabled, DRM_MEM_KMS); @@ -1445,12 +1375,14 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper) /** * drm_helper_initial_config - setup a sane initial connector configuration - * @dev: DRM device + * @fb_helper: fb_helper device struct + * @bpp_sel: bpp value to use for the framebuffer configuration * * LOCKING: - * Called at init time, must take mode config lock. + * Called at init time by the driver to set up the @fb_helper initial + * configuration, must take the mode config lock. * - * Scan the CRTCs and connectors and try to put together an initial setup. + * Scans the CRTCs and connectors and tries to put together an initial setup. * At the moment, this is a cloned configuration across all heads with * a new framebuffer object as the backing store. * @@ -1473,20 +1405,35 @@ bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel) /* * we shouldn't end up with no modes here. */ - if (count == 0) { - printf("No connectors reported connected with modes\n"); - } + if (count == 0) + dev_info(fb_helper->dev->dev, "No connectors reported connected with modes\n"); + drm_setup_crtcs(fb_helper); return drm_fb_helper_single_fb_probe(fb_helper, bpp_sel); } +EXPORT_SYMBOL(drm_fb_helper_initial_config); +/** + * drm_fb_helper_hotplug_event - respond to a hotplug notification by + * probing all the outputs attached to the fb + * @fb_helper: the drm_fb_helper + * + * LOCKING: + * Called at runtime, must take mode config lock. + * + * Scan the connectors attached to the fb_helper and try to put together a + * setup after *notification of a change in output configuration. + * + * RETURNS: + * 0 on success and a non-zero error code otherwise. + */ int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper) { struct drm_device *dev = fb_helper->dev; int count = 0; u32 max_width, max_height, bpp_sel; - bool bound = false, crtcs_bound = false; + int bound = 0, crtcs_bound = 0; struct drm_crtc *crtc; if (!fb_helper->fb) @@ -1495,12 +1442,12 @@ int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper) sx_xlock(&dev->mode_config.mutex); list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { if (crtc->fb) - crtcs_bound = true; + crtcs_bound++; if (crtc->fb == fb_helper->fb) - bound = true; + bound++; } - if (!bound && crtcs_bound) { + if (bound < crtcs_bound) { fb_helper->delayed_hotplug = true; sx_xunlock(&dev->mode_config.mutex); return 0; @@ -1518,4 +1465,4 @@ int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper) return drm_fb_helper_single_fb_probe(fb_helper, bpp_sel); } - +EXPORT_SYMBOL(drm_fb_helper_hotplug_event); diff --git a/sys/dev/drm2/drm_fb_helper.h b/sys/dev/drm2/drm_fb_helper.h index 16ef7ee14881..c292752ca945 100644 --- a/sys/dev/drm2/drm_fb_helper.h +++ b/sys/dev/drm2/drm_fb_helper.h @@ -35,7 +35,6 @@ struct drm_fb_helper; struct drm_fb_helper_crtc { - uint32_t crtc_id; struct drm_mode_set mode_set; struct drm_display_mode *desired_mode; }; @@ -74,7 +73,6 @@ struct drm_fb_helper { int connector_count; struct drm_fb_helper_connector **connector_info; struct drm_fb_helper_funcs *funcs; - int conn_limit; struct fb_info *fbdev; u32 pseudo_palette[17]; struct list_head kernel_fb_list; @@ -84,9 +82,6 @@ struct drm_fb_helper { bool delayed_hotplug; }; -struct fb_var_screeninfo; -struct fb_cmap; - int drm_fb_helper_single_fb_probe(struct drm_fb_helper *helper, int preferred_bpp); @@ -95,11 +90,15 @@ int drm_fb_helper_init(struct drm_device *dev, int max_conn); void drm_fb_helper_fini(struct drm_fb_helper *helper); int drm_fb_helper_blank(int blank, struct fb_info *info); +#ifdef FREEBSD_NOTYET int drm_fb_helper_pan_display(struct fb_var_screeninfo *var, struct fb_info *info); +#endif /* FREEBSD_NOTYET */ int drm_fb_helper_set_par(struct fb_info *info); +#ifdef FREEBSD_NOTYET int drm_fb_helper_check_var(struct fb_var_screeninfo *var, struct fb_info *info); +#endif /* FREEBSD_NOTYET */ int drm_fb_helper_setcolreg(unsigned regno, unsigned red, unsigned green, @@ -114,13 +113,14 @@ void drm_fb_helper_fill_var(struct fb_info *info, struct drm_fb_helper *fb_helpe void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch, uint32_t depth); +#ifdef FREEBSD_NOTYET int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info); +#endif /* FREEBSD_NOTYET */ int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper); bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel); int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper); int drm_fb_helper_debug_enter(struct fb_info *info); int drm_fb_helper_debug_leave(struct fb_info *info); -bool drm_fb_helper_force_kernel_mode(void); #endif diff --git a/sys/dev/drm2/drm_fops.c b/sys/dev/drm2/drm_fops.c index 2685ff7b2779..b73cec63d3b7 100644 --- a/sys/dev/drm2/drm_fops.c +++ b/sys/dev/drm2/drm_fops.c @@ -1,4 +1,15 @@ -/*- +/** + * \file drm_fops.c + * File operations for DRM + * + * \author Rickard E. (Rik) Faith <faith@valinux.com> + * \author Daryll Strauss <daryll@valinux.com> + * \author Gareth Hughes <gareth@valinux.com> + */ + +/* + * Created: Mon Jan 4 08:58:31 1999 by faith@valinux.com + * * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. * All Rights Reserved. @@ -21,51 +32,177 @@ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: - * Rickard E. (Rik) Faith <faith@valinux.com> - * Daryll Strauss <daryll@valinux.com> - * Gareth Hughes <gareth@valinux.com> - * */ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); -/** @file drm_fops.c - * Support code for dealing with the file privates associated with each - * open of the DRM device. +#include <dev/drm2/drmP.h> + +static int drm_open_helper(struct cdev *kdev, int flags, int fmt, + DRM_STRUCTPROC *p, struct drm_device *dev); + +static int drm_setup(struct drm_device * dev) +{ + int i; + int ret; + + if (dev->driver->firstopen) { + ret = dev->driver->firstopen(dev); + if (ret != 0) + return ret; + } + + atomic_set(&dev->ioctl_count, 0); + atomic_set(&dev->vma_count, 0); + + if (drm_core_check_feature(dev, DRIVER_HAVE_DMA) && + !drm_core_check_feature(dev, DRIVER_MODESET)) { + dev->buf_use = 0; + atomic_set(&dev->buf_alloc, 0); + + i = drm_dma_setup(dev); + if (i < 0) + return i; + } + + /* + * FIXME Linux<->FreeBSD: counter incremented in drm_open() and + * reset to 0 here. + */ +#if 0 + for (i = 0; i < ARRAY_SIZE(dev->counts); i++) + atomic_set(&dev->counts[i], 0); +#endif + + dev->sigdata.lock = NULL; + + dev->context_flag = 0; + dev->interrupt_flag = 0; + dev->dma_flag = 0; + dev->last_context = 0; + dev->last_switch = 0; + dev->last_checked = 0; + DRM_INIT_WAITQUEUE(&dev->context_wait); + dev->if_version = 0; + +#ifdef FREEBSD_NOTYET + dev->ctx_start = 0; + dev->lck_start = 0; + + dev->buf_async = NULL; + DRM_INIT_WAITQUEUE(&dev->buf_readers); + DRM_INIT_WAITQUEUE(&dev->buf_writers); +#endif /* FREEBSD_NOTYET */ + + DRM_DEBUG("\n"); + + /* + * The kernel's context could be created here, but is now created + * in drm_dma_enqueue. This is more resource-efficient for + * hardware that does not do DMA, but may mean that + * drm_select_queue fails between the time the interrupt is + * initialized and the time the queues are initialized. + */ + + return 0; +} + +/** + * Open file. + * + * \param inode device inode + * \param filp file pointer. + * \return zero on success or a negative number on failure. + * + * Searches the DRM device with the same minor number, calls open_helper(), and + * increments the device open count. If the open count was previous at zero, + * i.e., it's the first that the device is open, then calls setup(). */ +int drm_open(struct cdev *kdev, int flags, int fmt, DRM_STRUCTPROC *p) +{ + struct drm_device *dev = NULL; + struct drm_minor *minor; + int retcode = 0; + int need_setup = 0; -#include <dev/drm2/drmP.h> + minor = kdev->si_drv1; + if (!minor) + return ENODEV; + + if (!(dev = minor->dev)) + return ENODEV; + + sx_xlock(&drm_global_mutex); -/* drm_open_helper is called whenever a process opens /dev/drm. */ -int drm_open_helper(struct cdev *kdev, int flags, int fmt, DRM_STRUCTPROC *p, - struct drm_device *dev) + /* + * FIXME Linux<->FreeBSD: On Linux, counter updated outisde + * global mutex. + */ + if (!dev->open_count++) + need_setup = 1; + + retcode = drm_open_helper(kdev, flags, fmt, p, dev); + if (retcode) { + sx_xunlock(&drm_global_mutex); + return (-retcode); + } + atomic_inc(&dev->counts[_DRM_STAT_OPENS]); + if (need_setup) { + retcode = drm_setup(dev); + if (retcode) + goto err_undo; + } + sx_xunlock(&drm_global_mutex); + return 0; + +err_undo: + mtx_lock(&Giant); /* FIXME: Giant required? */ + device_unbusy(dev->dev); + mtx_unlock(&Giant); + dev->open_count--; + sx_xunlock(&drm_global_mutex); + return -retcode; +} +EXPORT_SYMBOL(drm_open); + +/** + * Called whenever a process opens /dev/drm. + * + * \param inode device inode. + * \param filp file pointer. + * \param dev device. + * \return zero on success or a negative number on failure. + * + * Creates and initializes a drm_file structure for the file private data in \p + * filp and add it into the double linked list in \p dev. + */ +static int drm_open_helper(struct cdev *kdev, int flags, int fmt, + DRM_STRUCTPROC *p, struct drm_device *dev) { struct drm_file *priv; - int retcode; + int ret; if (flags & O_EXCL) - return EBUSY; /* No exclusive opens */ - dev->flags = flags; + return -EBUSY; /* No exclusive opens */ + if (dev->switch_power_state != DRM_SWITCH_POWER_ON) + return -EINVAL; DRM_DEBUG("pid = %d, device = %s\n", DRM_CURRENTPID, devtoname(kdev)); priv = malloc(sizeof(*priv), DRM_MEM_FILES, M_NOWAIT | M_ZERO); - if (priv == NULL) { - return ENOMEM; - } - - DRM_LOCK(dev); - priv->dev = dev; - priv->uid = p->td_ucred->cr_svuid; - priv->pid = p->td_proc->p_pid; - priv->ioctl_count = 0; + if (!priv) + return -ENOMEM; + priv->uid = p->td_ucred->cr_svuid; + priv->pid = p->td_proc->p_pid; + priv->minor = kdev->si_drv1; + priv->ioctl_count = 0; /* for compatibility root is always authenticated */ - priv->authenticated = DRM_SUSER(p); + priv->authenticated = DRM_SUSER(p); + priv->lock_count = 0; + INIT_LIST_HEAD(&priv->lhead); INIT_LIST_HEAD(&priv->fbs); INIT_LIST_HEAD(&priv->event_list); priv->event_space = 4096; /* set aside 4k for event buffer */ @@ -73,47 +210,289 @@ int drm_open_helper(struct cdev *kdev, int flags, int fmt, DRM_STRUCTPROC *p, if (dev->driver->driver_features & DRIVER_GEM) drm_gem_open(dev, priv); +#ifdef FREEBSD_NOTYET + if (drm_core_check_feature(dev, DRIVER_PRIME)) + drm_prime_init_file_private(&priv->prime); +#endif /* FREEBSD_NOTYET */ + if (dev->driver->open) { - /* shared code returns -errno */ - retcode = -dev->driver->open(dev, priv); - if (retcode != 0) { - free(priv, DRM_MEM_FILES); + ret = dev->driver->open(dev, priv); + if (ret < 0) + goto out_free; + } + + + /* if there is no current master make this fd it */ + DRM_LOCK(dev); + if (!priv->minor->master) { + /* create a new master */ + priv->minor->master = drm_master_create(priv->minor); + if (!priv->minor->master) { DRM_UNLOCK(dev); - return retcode; + ret = -ENOMEM; + goto out_free; + } + + priv->is_master = 1; + /* take another reference for the copy in the local file priv */ + priv->master = drm_master_get(priv->minor->master); + + priv->authenticated = 1; + + DRM_UNLOCK(dev); + if (dev->driver->master_create) { + ret = dev->driver->master_create(dev, priv->master); + if (ret) { + DRM_LOCK(dev); + /* drop both references if this fails */ + drm_master_put(&priv->minor->master); + drm_master_put(&priv->master); + DRM_UNLOCK(dev); + goto out_free; + } + } + DRM_LOCK(dev); + if (dev->driver->master_set) { + ret = dev->driver->master_set(dev, priv, true); + if (ret) { + /* drop both references if this fails */ + drm_master_put(&priv->minor->master); + drm_master_put(&priv->master); + DRM_UNLOCK(dev); + goto out_free; + } + } + DRM_UNLOCK(dev); + } else { + /* get a reference to the master */ + priv->master = drm_master_get(priv->minor->master); + DRM_UNLOCK(dev); + } + + DRM_LOCK(dev); + list_add(&priv->lhead, &dev->filelist); + DRM_UNLOCK(dev); + + mtx_lock(&Giant); /* FIXME: Giant required? */ + device_busy(dev->dev); + mtx_unlock(&Giant); + + ret = devfs_set_cdevpriv(priv, drm_release); + if (ret != 0) + drm_release(priv); + + return ret; + out_free: + free(priv, DRM_MEM_FILES); + return ret; +} + +static void drm_master_release(struct drm_device *dev, struct drm_file *file_priv) +{ + + if (drm_i_have_hw_lock(dev, file_priv)) { + DRM_DEBUG("File %p released, freeing lock for context %d\n", + file_priv, _DRM_LOCKING_CONTEXT(file_priv->master->lock.hw_lock->lock)); + drm_lock_free(&file_priv->master->lock, + _DRM_LOCKING_CONTEXT(file_priv->master->lock.hw_lock->lock)); + } +} + +static void drm_events_release(struct drm_file *file_priv) +{ + struct drm_device *dev = file_priv->minor->dev; + struct drm_pending_event *e, *et; + struct drm_pending_vblank_event *v, *vt; + unsigned long flags; + + DRM_SPINLOCK_IRQSAVE(&dev->event_lock, flags); + + /* Remove pending flips */ + list_for_each_entry_safe(v, vt, &dev->vblank_event_list, base.link) + if (v->base.file_priv == file_priv) { + list_del(&v->base.link); + drm_vblank_put(dev, v->pipe); + v->base.destroy(&v->base); + } + + /* Remove unconsumed events */ + list_for_each_entry_safe(e, et, &file_priv->event_list, link) + e->destroy(e); + + DRM_SPINUNLOCK_IRQRESTORE(&dev->event_lock, flags); +} + +/** + * Release file. + * + * \param inode device inode + * \param file_priv DRM file private. + * \return zero on success or a negative number on failure. + * + * If the hardware lock is held then free it, and take it again for the kernel + * context since it's necessary to reclaim buffers. Unlink the file private + * data from its list and free it. Decreases the open count and if it reaches + * zero calls drm_lastclose(). + */ +void drm_release(void *data) +{ + struct drm_file *file_priv = data; + struct drm_device *dev = file_priv->minor->dev; + + sx_xlock(&drm_global_mutex); + + DRM_DEBUG("open_count = %d\n", dev->open_count); + + if (dev->driver->preclose) + dev->driver->preclose(dev, file_priv); + + /* ======================================================== + * Begin inline drm_release + */ + + DRM_DEBUG("pid = %d, device = 0x%lx, open_count = %d\n", + DRM_CURRENTPID, + (long)file_priv->minor->device, + dev->open_count); + + /* Release any auth tokens that might point to this file_priv, + (do that under the drm_global_mutex) */ + if (file_priv->magic) + (void) drm_remove_magic(file_priv->master, file_priv->magic); + + /* if the master has gone away we can't do anything with the lock */ + if (file_priv->minor->master) + drm_master_release(dev, file_priv); + + if (drm_core_check_feature(dev, DRIVER_HAVE_DMA)) + drm_core_reclaim_buffers(dev, file_priv); + + drm_events_release(file_priv); + + seldrain(&file_priv->event_poll); + + if (dev->driver->driver_features & DRIVER_MODESET) + drm_fb_release(file_priv); + + if (dev->driver->driver_features & DRIVER_GEM) + drm_gem_release(dev, file_priv); + +#ifdef FREEBSD_NOTYET + mutex_lock(&dev->ctxlist_mutex); + if (!list_empty(&dev->ctxlist)) { + struct drm_ctx_list *pos, *n; + + list_for_each_entry_safe(pos, n, &dev->ctxlist, head) { + if (pos->tag == file_priv && + pos->handle != DRM_KERNEL_CONTEXT) { + if (dev->driver->context_dtor) + dev->driver->context_dtor(dev, + pos->handle); + + drm_ctxbitmap_free(dev, pos->handle); + + list_del(&pos->head); + kfree(pos); + --dev->ctx_count; + } } } + mutex_unlock(&dev->ctxlist_mutex); +#endif /* FREEBSD_NOTYET */ + + DRM_LOCK(dev); + + if (file_priv->is_master) { + struct drm_master *master = file_priv->master; + struct drm_file *temp; + list_for_each_entry(temp, &dev->filelist, lhead) { + if ((temp->master == file_priv->master) && + (temp != file_priv)) + temp->authenticated = 0; + } + + /** + * Since the master is disappearing, so is the + * possibility to lock. + */ - /* first opener automatically becomes master */ - priv->master = TAILQ_EMPTY(&dev->files); + if (master->lock.hw_lock) { + if (dev->sigdata.lock == master->lock.hw_lock) + dev->sigdata.lock = NULL; + master->lock.hw_lock = NULL; + master->lock.file_priv = NULL; + DRM_WAKEUP_INT(&master->lock.lock_queue); + } + + if (file_priv->minor->master == file_priv->master) { + /* drop the reference held my the minor */ + if (dev->driver->master_drop) + dev->driver->master_drop(dev, file_priv, true); + drm_master_put(&file_priv->minor->master); + } + } - TAILQ_INSERT_TAIL(&dev->files, priv, link); + /* drop the reference held my the file priv */ + drm_master_put(&file_priv->master); + file_priv->is_master = 0; + list_del(&file_priv->lhead); DRM_UNLOCK(dev); - kdev->si_drv1 = dev; - retcode = devfs_set_cdevpriv(priv, drm_close); - if (retcode != 0) - drm_close(priv); + if (dev->driver->postclose) + dev->driver->postclose(dev, file_priv); - return (retcode); +#ifdef FREEBSD_NOTYET + if (drm_core_check_feature(dev, DRIVER_PRIME)) + drm_prime_destroy_file_private(&file_priv->prime); +#endif /* FREEBSD_NOTYET */ + + free(file_priv, DRM_MEM_FILES); + + /* ======================================================== + * End inline drm_release + */ + + atomic_inc(&dev->counts[_DRM_STAT_CLOSES]); + mtx_lock(&Giant); + device_unbusy(dev->dev); + mtx_unlock(&Giant); + if (!--dev->open_count) { + if (atomic_read(&dev->ioctl_count)) { + DRM_ERROR("Device busy: %d\n", + atomic_read(&dev->ioctl_count)); + } else + drm_lastclose(dev); + } + sx_xunlock(&drm_global_mutex); } +EXPORT_SYMBOL(drm_release); static bool -drm_dequeue_event(struct drm_device *dev, struct drm_file *file_priv, - struct uio *uio, struct drm_pending_event **out) +drm_dequeue_event(struct drm_file *file_priv, struct uio *uio, + struct drm_pending_event **out) { struct drm_pending_event *e; + bool ret = false; + /* Already locked in drm_read(). */ + /* DRM_SPINLOCK_IRQSAVE(&dev->event_lock, flags); */ + + *out = NULL; if (list_empty(&file_priv->event_list)) - return (false); + goto out; e = list_first_entry(&file_priv->event_list, - struct drm_pending_event, link); + struct drm_pending_event, link); if (e->event->length > uio->uio_resid) - return (false); + goto out; file_priv->event_space += e->event->length; list_del(&e->link); *out = e; - return (true); + ret = true; + +out: + /* DRM_SPINUNLOCK_IRQRESTORE(&dev->event_lock, flags); */ + return ret; } int @@ -122,13 +501,14 @@ drm_read(struct cdev *kdev, struct uio *uio, int ioflag) struct drm_file *file_priv; struct drm_device *dev; struct drm_pending_event *e; - int error; + ssize_t error; error = devfs_get_cdevpriv((void **)&file_priv); if (error != 0) { DRM_ERROR("can't find authenticator\n"); return (EINVAL); } + dev = drm_get_device_from_kdev(kdev); mtx_lock(&dev->event_lock); while (list_empty(&file_priv->event_list)) { @@ -141,20 +521,24 @@ drm_read(struct cdev *kdev, struct uio *uio, int ioflag) if (error != 0) goto out; } - while (drm_dequeue_event(dev, file_priv, uio, &e)) { + + while (drm_dequeue_event(file_priv, uio, &e)) { mtx_unlock(&dev->event_lock); error = uiomove(e->event, e->event->length, uio); CTR3(KTR_DRM, "drm_event_dequeued %d %d %d", curproc->p_pid, e->event->type, e->event->length); + e->destroy(e); if (error != 0) return (error); mtx_lock(&dev->event_lock); } + out: mtx_unlock(&dev->event_lock); return (error); } +EXPORT_SYMBOL(drm_read); void drm_event_wakeup(struct drm_pending_event *e) @@ -163,7 +547,7 @@ drm_event_wakeup(struct drm_pending_event *e) struct drm_device *dev; file_priv = e->file_priv; - dev = file_priv->dev; + dev = file_priv->minor->dev; mtx_assert(&dev->event_lock, MA_OWNED); wakeup(&file_priv->event_space); @@ -182,6 +566,7 @@ drm_poll(struct cdev *kdev, int events, struct thread *td) DRM_ERROR("can't find authenticator\n"); return (EINVAL); } + dev = drm_get_device_from_kdev(kdev); revents = 0; @@ -198,3 +583,21 @@ drm_poll(struct cdev *kdev, int events, struct thread *td) mtx_unlock(&dev->event_lock); return (revents); } +EXPORT_SYMBOL(drm_poll); + +int +drm_mmap_single(struct cdev *kdev, vm_ooffset_t *offset, vm_size_t size, + struct vm_object **obj_res, int nprot) +{ + struct drm_device *dev; + + dev = drm_get_device_from_kdev(kdev); + if (dev->drm_ttm_bdev != NULL) { + return (-ttm_bo_mmap_single(dev->drm_ttm_bdev, offset, size, + obj_res, nprot)); + } else if ((dev->driver->driver_features & DRIVER_GEM) != 0) { + return (-drm_gem_mmap_single(dev, offset, size, obj_res, nprot)); + } else { + return (ENODEV); + } +} diff --git a/sys/dev/drm2/drm_fourcc.h b/sys/dev/drm2/drm_fourcc.h index 0e871df25d5d..bb35a6e17645 100644 --- a/sys/dev/drm2/drm_fourcc.h +++ b/sys/dev/drm2/drm_fourcc.h @@ -26,10 +26,8 @@ #ifndef DRM_FOURCC_H #define DRM_FOURCC_H -#include <sys/types.h> - -#define fourcc_code(a, b, c, d) ((uint32_t)(a) | ((uint32_t)(b) << 8) | \ - ((uint32_t)(c) << 16) | ((uint32_t)(d) << 24)) +#define fourcc_code(a, b, c, d) ((__u32)(a) | ((__u32)(b) << 8) | \ + ((__u32)(c) << 16) | ((__u32)(d) << 24)) #define DRM_FORMAT_BIG_ENDIAN (1<<31) /* format is big endian instead of little endian */ @@ -108,9 +106,10 @@ #define DRM_FORMAT_NV21 fourcc_code('N', 'V', '2', '1') /* 2x2 subsampled Cb:Cr plane */ #define DRM_FORMAT_NV16 fourcc_code('N', 'V', '1', '6') /* 2x1 subsampled Cr:Cb plane */ #define DRM_FORMAT_NV61 fourcc_code('N', 'V', '6', '1') /* 2x1 subsampled Cb:Cr plane */ +#define DRM_FORMAT_NV24 fourcc_code('N', 'V', '2', '4') /* non-subsampled Cr:Cb plane */ +#define DRM_FORMAT_NV42 fourcc_code('N', 'V', '4', '2') /* non-subsampled Cb:Cr plane */ -/* 2 non contiguous plane YCbCr */ -#define DRM_FORMAT_NV12M fourcc_code('N', 'M', '1', '2') /* 2x2 subsampled Cr:Cb plane */ +/* special NV12 tiled format */ #define DRM_FORMAT_NV12MT fourcc_code('T', 'M', '1', '2') /* 2x2 subsampled Cr:Cb plane 64x32 macroblocks */ /* @@ -133,7 +132,4 @@ #define DRM_FORMAT_YUV444 fourcc_code('Y', 'U', '2', '4') /* non-subsampled Cb (1) and Cr (2) planes */ #define DRM_FORMAT_YVU444 fourcc_code('Y', 'V', '2', '4') /* non-subsampled Cr (1) and Cb (2) planes */ -/* 3 non contiguous plane YCbCr */ -#define DRM_FORMAT_YUV420M fourcc_code('Y', 'M', '1', '2') /* 2x2 subsampled Cb (1) and Cr (2) planes */ - #endif /* DRM_FOURCC_H */ diff --git a/sys/dev/drm2/drm_gem.c b/sys/dev/drm2/drm_gem.c index 04b7659b1e05..aaf99628c166 100644 --- a/sys/dev/drm2/drm_gem.c +++ b/sys/dev/drm2/drm_gem.c @@ -54,7 +54,7 @@ __FBSDID("$FreeBSD$"); * the faked up offset will fit */ -#if ULONG_MAX == UINT64_MAX +#if BITS_PER_LONG == 64 #define DRM_FILE_PAGE_OFFSET_START ((0xFFFFFFFFUL >> PAGE_SHIFT) + 1) #define DRM_FILE_PAGE_OFFSET_SIZE ((0xFFFFFFFFUL >> PAGE_SHIFT) * 16) #else @@ -62,28 +62,40 @@ __FBSDID("$FreeBSD$"); #define DRM_FILE_PAGE_OFFSET_SIZE ((0xFFFFFFFUL >> PAGE_SHIFT) * 16) #endif +/** + * Initialize the GEM device fields + */ + int drm_gem_init(struct drm_device *dev) { struct drm_gem_mm *mm; drm_gem_names_init(&dev->object_names); - mm = malloc(sizeof(*mm), DRM_MEM_DRIVER, M_WAITOK); + + mm = malloc(sizeof(*mm), DRM_MEM_DRIVER, M_NOWAIT); + if (!mm) { + DRM_ERROR("out of memory\n"); + return -ENOMEM; + } + dev->mm_private = mm; - if (drm_ht_create(&mm->offset_hash, 19) != 0) { + + if (drm_ht_create(&mm->offset_hash, 19)) { free(mm, DRM_MEM_DRIVER); - return (ENOMEM); + return -ENOMEM; } + mm->idxunr = new_unrhdr(0, DRM_GEM_MAX_IDX, NULL); - return (0); + + return 0; } void drm_gem_destroy(struct drm_device *dev) { - struct drm_gem_mm *mm; + struct drm_gem_mm *mm = dev->mm_private; - mm = dev->mm_private; dev->mm_private = NULL; drm_ht_remove(&mm->offset_hash); delete_unrhdr(mm->idxunr); @@ -91,11 +103,9 @@ drm_gem_destroy(struct drm_device *dev) drm_gem_names_fini(&dev->object_names); } -int -drm_gem_object_init(struct drm_device *dev, struct drm_gem_object *obj, - size_t size) +int drm_gem_object_init(struct drm_device *dev, + struct drm_gem_object *obj, size_t size) { - KASSERT((size & (PAGE_SIZE - 1)) == 0, ("Bad size %ju", (uintmax_t)size)); @@ -107,14 +117,18 @@ drm_gem_object_init(struct drm_device *dev, struct drm_gem_object *obj, obj->handle_count = 0; obj->size = size; - return (0); + return 0; } +EXPORT_SYMBOL(drm_gem_object_init); -int -drm_gem_private_object_init(struct drm_device *dev, struct drm_gem_object *obj, - size_t size) +/** + * Initialize an already allocated GEM object of the specified size with + * no GEM provided backing store. Instead the caller is responsible for + * backing the object and handling it. + */ +int drm_gem_private_object_init(struct drm_device *dev, + struct drm_gem_object *obj, size_t size) { - MPASS((size & (PAGE_SIZE - 1)) == 0); obj->dev = dev; @@ -124,283 +138,298 @@ drm_gem_private_object_init(struct drm_device *dev, struct drm_gem_object *obj, atomic_store_rel_int(&obj->handle_count, 0); obj->size = size; - return (0); + return 0; } - +EXPORT_SYMBOL(drm_gem_private_object_init); struct drm_gem_object * drm_gem_object_alloc(struct drm_device *dev, size_t size) { struct drm_gem_object *obj; - obj = malloc(sizeof(*obj), DRM_MEM_DRIVER, M_WAITOK | M_ZERO); + obj = malloc(sizeof(*obj), DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); + if (!obj) + goto free; + if (drm_gem_object_init(dev, obj, size) != 0) goto free; if (dev->driver->gem_init_object != NULL && - dev->driver->gem_init_object(obj) != 0) + dev->driver->gem_init_object(obj) != 0) { goto dealloc; - return (obj); + } + return obj; dealloc: vm_object_deallocate(obj->vm_obj); free: free(obj, DRM_MEM_DRIVER); - return (NULL); + return NULL; } +EXPORT_SYMBOL(drm_gem_object_alloc); -void -drm_gem_object_free(struct drm_gem_object *obj) +#if defined(FREEBSD_NOTYET) +static void +drm_gem_remove_prime_handles(struct drm_gem_object *obj, struct drm_file *filp) { - struct drm_device *dev; - - dev = obj->dev; - DRM_LOCK_ASSERT(dev); - if (dev->driver->gem_free_object != NULL) - dev->driver->gem_free_object(obj); -} - -void -drm_gem_object_reference(struct drm_gem_object *obj) -{ - - KASSERT(obj->refcount > 0, ("Dangling obj %p", obj)); - refcount_acquire(&obj->refcount); -} - -void -drm_gem_object_unreference(struct drm_gem_object *obj) -{ - - if (obj == NULL) - return; - if (refcount_release(&obj->refcount)) - drm_gem_object_free(obj); + if (obj->import_attach) { + drm_prime_remove_buf_handle(&filp->prime, + obj->import_attach->dmabuf); + } + if (obj->export_dma_buf) { + drm_prime_remove_buf_handle(&filp->prime, + obj->export_dma_buf); + } } +#endif -void -drm_gem_object_unreference_unlocked(struct drm_gem_object *obj) +/** + * Removes the mapping from handle to filp for this object. + */ +int +drm_gem_handle_delete(struct drm_file *filp, u32 handle) { struct drm_device *dev; + struct drm_gem_object *obj; - if (obj == NULL) - return; + obj = drm_gem_names_remove(&filp->object_names, handle); + if (obj == NULL) { + return -EINVAL; + } dev = obj->dev; - DRM_LOCK(dev); - drm_gem_object_unreference(obj); - DRM_UNLOCK(dev); -} -void -drm_gem_object_handle_reference(struct drm_gem_object *obj) -{ +#if defined(FREEBSD_NOTYET) + drm_gem_remove_prime_handles(obj, filp); +#endif - drm_gem_object_reference(obj); - atomic_add_rel_int(&obj->handle_count, 1); + if (dev->driver->gem_close_object) + dev->driver->gem_close_object(obj, filp); + drm_gem_object_handle_unreference_unlocked(obj); + + return 0; } +EXPORT_SYMBOL(drm_gem_handle_delete); -void -drm_gem_object_handle_free(struct drm_gem_object *obj) +/** + * Create a handle for this object. This adds a handle reference + * to the object, which includes a regular reference count. Callers + * will likely want to dereference the object afterwards. + */ +int +drm_gem_handle_create(struct drm_file *file_priv, + struct drm_gem_object *obj, + u32 *handlep) { - struct drm_device *dev; - struct drm_gem_object *obj1; + struct drm_device *dev = obj->dev; + int ret; - dev = obj->dev; - if (obj->name != 0) { - obj1 = drm_gem_names_remove(&dev->object_names, obj->name); - obj->name = 0; - drm_gem_object_unreference(obj1); - } -} + *handlep = 0; + ret = drm_gem_name_create(&file_priv->object_names, obj, handlep); + if (ret != 0) + return ret; -void -drm_gem_object_handle_unreference(struct drm_gem_object *obj) -{ + drm_gem_object_handle_reference(obj); - if (obj == NULL || - atomic_load_acq_int(&obj->handle_count) == 0) - return; + if (dev->driver->gem_open_object) { + ret = dev->driver->gem_open_object(obj, file_priv); + if (ret) { + drm_gem_handle_delete(file_priv, *handlep); + return ret; + } + } - if (atomic_fetchadd_int(&obj->handle_count, -1) == 1) - drm_gem_object_handle_free(obj); - drm_gem_object_unreference(obj); + return 0; } +EXPORT_SYMBOL(drm_gem_handle_create); void -drm_gem_object_handle_unreference_unlocked(struct drm_gem_object *obj) +drm_gem_free_mmap_offset(struct drm_gem_object *obj) { + struct drm_device *dev = obj->dev; + struct drm_gem_mm *mm = dev->mm_private; + struct drm_hash_item *list = &obj->map_list; - if (obj == NULL || - atomic_load_acq_int(&obj->handle_count) == 0) + if (!obj->on_map) return; - if (atomic_fetchadd_int(&obj->handle_count, -1) == 1) - drm_gem_object_handle_free(obj); - drm_gem_object_unreference_unlocked(obj); + drm_ht_remove_item(&mm->offset_hash, list); + free_unr(mm->idxunr, list->key); + obj->on_map = false; } +EXPORT_SYMBOL(drm_gem_free_mmap_offset); int -drm_gem_handle_create(struct drm_file *file_priv, struct drm_gem_object *obj, - uint32_t *handle) +drm_gem_create_mmap_offset(struct drm_gem_object *obj) { struct drm_device *dev = obj->dev; + struct drm_gem_mm *mm = dev->mm_private; int ret; - ret = drm_gem_name_create(&file_priv->object_names, obj, handle); - if (ret != 0) - return (ret); - drm_gem_object_handle_reference(obj); + if (obj->on_map) + return 0; - if (dev->driver->gem_open_object) { - ret = dev->driver->gem_open_object(obj, file_priv); - if (ret) { - drm_gem_handle_delete(file_priv, *handle); - return ret; - } + obj->map_list.key = alloc_unr(mm->idxunr); + ret = drm_ht_insert_item(&mm->offset_hash, &obj->map_list); + if (ret) { + DRM_ERROR("failed to add to map hash\n"); + free_unr(mm->idxunr, obj->map_list.key); + return ret; } + obj->on_map = true; - return (0); + return 0; } +EXPORT_SYMBOL(drm_gem_create_mmap_offset); -int -drm_gem_handle_delete(struct drm_file *file_priv, uint32_t handle) +/** Returns a reference to the object named by the handle. */ +struct drm_gem_object * +drm_gem_object_lookup(struct drm_device *dev, struct drm_file *filp, + u32 handle) { - struct drm_device *dev; struct drm_gem_object *obj; - obj = drm_gem_names_remove(&file_priv->object_names, handle); - if (obj == NULL) - return (EINVAL); + obj = drm_gem_name_ref(&filp->object_names, handle, + (void (*)(void *))drm_gem_object_reference); - dev = obj->dev; - if (dev->driver->gem_close_object) - dev->driver->gem_close_object(obj, file_priv); - drm_gem_object_handle_unreference_unlocked(obj); + return obj; +} +EXPORT_SYMBOL(drm_gem_object_lookup); - return (0); +int +drm_gem_close_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_gem_close *args = data; + int ret; + + if (!(dev->driver->driver_features & DRIVER_GEM)) + return -ENODEV; + + ret = drm_gem_handle_delete(file_priv, args->handle); + + return ret; } -void -drm_gem_object_release(struct drm_gem_object *obj) +int +drm_gem_flink_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) { + struct drm_gem_flink *args = data; + struct drm_gem_object *obj; + int ret; - /* - * obj->vm_obj can be NULL for private gem objects. - */ - vm_object_deallocate(obj->vm_obj); + if (!(dev->driver->driver_features & DRIVER_GEM)) + return -ENODEV; + + obj = drm_gem_object_lookup(dev, file_priv, args->handle); + if (obj == NULL) + return -ENOENT; + + ret = drm_gem_name_create(&dev->object_names, obj, &obj->name); + if (ret != 0) { + if (ret == -EALREADY) + ret = 0; + drm_gem_object_unreference_unlocked(obj); + } + if (ret == 0) + args->name = obj->name; + return ret; } int drm_gem_open_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) + struct drm_file *file_priv) { - struct drm_gem_open *args; + struct drm_gem_open *args = data; struct drm_gem_object *obj; int ret; - uint32_t handle; + u32 handle; - if (!drm_core_check_feature(dev, DRIVER_GEM)) - return (ENODEV); - args = data; + if (!(dev->driver->driver_features & DRIVER_GEM)) + return -ENODEV; obj = drm_gem_name_ref(&dev->object_names, args->name, (void (*)(void *))drm_gem_object_reference); - if (obj == NULL) - return (ENOENT); - handle = 0; + if (!obj) + return -ENOENT; + ret = drm_gem_handle_create(file_priv, obj, &handle); drm_gem_object_unreference_unlocked(obj); - if (ret != 0) - return (ret); - + if (ret) + return ret; + args->handle = handle; args->size = obj->size; - return (0); + return 0; } void -drm_gem_open(struct drm_device *dev, struct drm_file *file_priv) +drm_gem_open(struct drm_device *dev, struct drm_file *file_private) { - drm_gem_names_init(&file_priv->object_names); + drm_gem_names_init(&file_private->object_names); } static int -drm_gem_object_release_handle(uint32_t name, void *ptr, void *arg) +drm_gem_object_release_handle(uint32_t name, void *ptr, void *data) { - struct drm_file *file_priv; - struct drm_gem_object *obj; - struct drm_device *dev; + struct drm_file *file_priv = data; + struct drm_gem_object *obj = ptr; + struct drm_device *dev = obj->dev; - file_priv = arg; - obj = ptr; - dev = obj->dev; +#if defined(FREEBSD_NOTYET) + drm_gem_remove_prime_handles(obj, file_priv); +#endif if (dev->driver->gem_close_object) dev->driver->gem_close_object(obj, file_priv); - drm_gem_object_handle_unreference(obj); - return (0); + drm_gem_object_handle_unreference_unlocked(obj); + + return 0; } void -drm_gem_release(struct drm_device *dev, struct drm_file *file_priv) +drm_gem_release(struct drm_device *dev, struct drm_file *file_private) { + drm_gem_names_foreach(&file_private->object_names, + drm_gem_object_release_handle, file_private); - drm_gem_names_foreach(&file_priv->object_names, - drm_gem_object_release_handle, file_priv); - drm_gem_names_fini(&file_priv->object_names); + drm_gem_names_fini(&file_private->object_names); } -int -drm_gem_close_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) +void +drm_gem_object_release(struct drm_gem_object *obj) { - struct drm_gem_close *args; - - if (!drm_core_check_feature(dev, DRIVER_GEM)) - return (ENODEV); - args = data; - return (drm_gem_handle_delete(file_priv, args->handle)); + /* + * obj->vm_obj can be NULL for private gem objects. + */ + vm_object_deallocate(obj->vm_obj); } +EXPORT_SYMBOL(drm_gem_object_release); -int -drm_gem_flink_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) +void +drm_gem_object_free(struct drm_gem_object *obj) { - struct drm_gem_flink *args; - struct drm_gem_object *obj; - int error; - - if (!drm_core_check_feature(dev, DRIVER_GEM)) - return (ENODEV); - args = data; + struct drm_device *dev = obj->dev; - obj = drm_gem_name_ref(&file_priv->object_names, args->handle, - (void (*)(void *))drm_gem_object_reference); - if (obj == NULL) - return (ENOENT); - error = drm_gem_name_create(&dev->object_names, obj, &obj->name); - if (error != 0) { - if (error == EALREADY) - error = 0; - drm_gem_object_unreference_unlocked(obj); - } - if (error == 0) - args->name = obj->name; - return (error); + DRM_LOCK_ASSERT(dev); + if (dev->driver->gem_free_object != NULL) + dev->driver->gem_free_object(obj); } +EXPORT_SYMBOL(drm_gem_object_free); -struct drm_gem_object * -drm_gem_object_lookup(struct drm_device *dev, struct drm_file *file_priv, - uint32_t handle) +void drm_gem_object_handle_free(struct drm_gem_object *obj) { - struct drm_gem_object *obj; + struct drm_device *dev = obj->dev; + struct drm_gem_object *obj1; - obj = drm_gem_name_ref(&file_priv->object_names, handle, - (void (*)(void *))drm_gem_object_reference); - return (obj); + if (obj->name) { + obj1 = drm_gem_names_remove(&dev->object_names, obj->name); + obj->name = 0; + drm_gem_object_unreference(obj1); + } } static struct drm_gem_object * @@ -425,46 +454,6 @@ drm_gem_object_from_offset(struct drm_device *dev, vm_ooffset_t offset) } int -drm_gem_create_mmap_offset(struct drm_gem_object *obj) -{ - struct drm_device *dev; - struct drm_gem_mm *mm; - int ret; - - if (obj->on_map) - return (0); - dev = obj->dev; - mm = dev->mm_private; - ret = 0; - - obj->map_list.key = alloc_unr(mm->idxunr); - ret = drm_ht_insert_item(&mm->offset_hash, &obj->map_list); - if (ret != 0) { - DRM_ERROR("failed to add to map hash\n"); - free_unr(mm->idxunr, obj->map_list.key); - return (ret); - } - obj->on_map = true; - return (0); -} - -void -drm_gem_free_mmap_offset(struct drm_gem_object *obj) -{ - struct drm_hash_item *list; - struct drm_gem_mm *mm; - - if (!obj->on_map) - return; - mm = obj->dev->mm_private; - list = &obj->map_list; - - drm_ht_remove_item(&mm->offset_hash, list); - free_unr(mm->idxunr, list->key); - obj->on_map = false; -} - -int drm_gem_mmap_single(struct drm_device *dev, vm_ooffset_t *offset, vm_size_t size, struct vm_object **obj_res, int nprot) { @@ -475,7 +464,7 @@ drm_gem_mmap_single(struct drm_device *dev, vm_ooffset_t *offset, vm_size_t size gem_obj = drm_gem_object_from_offset(dev, *offset); if (gem_obj == NULL) { DRM_UNLOCK(dev); - return (ENODEV); + return (-ENODEV); } drm_gem_object_reference(gem_obj); DRM_UNLOCK(dev); @@ -484,7 +473,7 @@ drm_gem_mmap_single(struct drm_device *dev, vm_ooffset_t *offset, vm_size_t size DRM_GEM_MAPPING_MAPOFF(*offset), curthread->td_ucred); if (vm_obj == NULL) { drm_gem_object_unreference_unlocked(gem_obj); - return (EINVAL); + return (-EINVAL); } *offset = DRM_GEM_MAPPING_MAPOFF(*offset); *obj_res = vm_obj; diff --git a/sys/dev/drm2/drm_gem_names.c b/sys/dev/drm2/drm_gem_names.c index 03ef2c807183..8e47531e0439 100644 --- a/sys/dev/drm2/drm_gem_names.c +++ b/sys/dev/drm2/drm_gem_names.c @@ -151,7 +151,7 @@ drm_gem_name_create(struct drm_gem_names *names, void *p, uint32_t *name) struct drm_gem_name *np; if (*name != 0) { - return (EALREADY); + return (-EALREADY); } np = malloc(sizeof(struct drm_gem_name), M_GEM_NAMES, M_WAITOK); @@ -160,7 +160,7 @@ drm_gem_name_create(struct drm_gem_names *names, void *p, uint32_t *name) if (np->name == -1) { mtx_unlock(&names->lock); free(np, M_GEM_NAMES); - return (ENOMEM); + return (-ENOMEM); } *name = np->name; np->ptr = p; diff --git a/sys/dev/drm2/drm_global.c b/sys/dev/drm2/drm_global.c index 637204490cd0..2778aac3a23c 100644 --- a/sys/dev/drm2/drm_global.c +++ b/sys/dev/drm2/drm_global.c @@ -76,7 +76,11 @@ int drm_global_item_ref(struct drm_global_reference *ref) sx_xlock(&item->mutex); if (item->refcount == 0) { item->object = malloc(ref->size, M_DRM_GLOBAL, - M_WAITOK | M_ZERO); + M_NOWAIT | M_ZERO); + if (unlikely(item->object == NULL)) { + ret = -ENOMEM; + goto out_err; + } ref->object = item->object; ret = ref->init(ref); @@ -94,6 +98,7 @@ out_err: item->object = NULL; return ret; } +EXPORT_SYMBOL(drm_global_item_ref); void drm_global_item_unref(struct drm_global_reference *ref) { @@ -109,3 +114,4 @@ void drm_global_item_unref(struct drm_global_reference *ref) } sx_xunlock(&item->mutex); } +EXPORT_SYMBOL(drm_global_item_unref); diff --git a/sys/dev/drm2/drm_hashtab.c b/sys/dev/drm2/drm_hashtab.c index 8536fb89a86a..f49d59f67ac6 100644 --- a/sys/dev/drm2/drm_hashtab.c +++ b/sys/dev/drm2/drm_hashtab.c @@ -54,6 +54,7 @@ int drm_ht_create(struct drm_open_hash *ht, unsigned int order) } return 0; } +EXPORT_SYMBOL(drm_ht_create); void drm_ht_verbose_list(struct drm_open_hash *ht, unsigned long key) { @@ -69,8 +70,8 @@ void drm_ht_verbose_list(struct drm_open_hash *ht, unsigned long key) DRM_DEBUG("count %d, key: 0x%08lx\n", count++, entry->key); } -static struct drm_hash_item * -drm_ht_find_key(struct drm_open_hash *ht, unsigned long key) +static struct drm_hash_item *drm_ht_find_key(struct drm_open_hash *ht, + unsigned long key) { struct drm_hash_item *entry; struct drm_hash_item_list *h_list; @@ -112,6 +113,7 @@ int drm_ht_insert_item(struct drm_open_hash *ht, struct drm_hash_item *item) } return 0; } +EXPORT_SYMBOL(drm_ht_insert_item); /* * Just insert an item and return any "bits" bit key that hasn't been @@ -140,6 +142,7 @@ int drm_ht_just_insert_please(struct drm_open_hash *ht, struct drm_hash_item *it } return 0; } +EXPORT_SYMBOL(drm_ht_just_insert_please); int drm_ht_find_item(struct drm_open_hash *ht, unsigned long key, struct drm_hash_item **item) @@ -153,6 +156,7 @@ int drm_ht_find_item(struct drm_open_hash *ht, unsigned long key, *item = entry; return 0; } +EXPORT_SYMBOL(drm_ht_find_item); int drm_ht_remove_key(struct drm_open_hash *ht, unsigned long key) { @@ -171,6 +175,7 @@ int drm_ht_remove_item(struct drm_open_hash *ht, struct drm_hash_item *item) LIST_REMOVE(item, head); return 0; } +EXPORT_SYMBOL(drm_ht_remove_item); void drm_ht_remove(struct drm_open_hash *ht) { @@ -179,3 +184,4 @@ void drm_ht_remove(struct drm_open_hash *ht) ht->table = NULL; } } +EXPORT_SYMBOL(drm_ht_remove); diff --git a/sys/dev/drm2/drm_internal.h b/sys/dev/drm2/drm_internal.h deleted file mode 100644 index 0ed1b6f78ee7..000000000000 --- a/sys/dev/drm2/drm_internal.h +++ /dev/null @@ -1,43 +0,0 @@ -/*- - * Copyright 2007 Red Hat, Inc - * All rights reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -/* This header file holds function prototypes and data types that are - * internal to the drm (not exported to user space) but shared across - * drivers and platforms */ - -#ifndef __DRM_INTERNAL_H__ -#define __DRM_INTERNAL_H__ - -/** - * Drawable information. - */ -struct drm_drawable_info { - unsigned int num_rects; - struct drm_clip_rect *rects; -}; - -#endif diff --git a/sys/dev/drm2/drm_ioc32.c b/sys/dev/drm2/drm_ioc32.c index e0519671e7cc..7bbcd43fc44e 100644 --- a/sys/dev/drm2/drm_ioc32.c +++ b/sys/dev/drm2/drm_ioc32.c @@ -20,9 +20,6 @@ * 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: - * Paul Mackerras <paulus@samba.org> */ #include <sys/cdefs.h> @@ -35,10 +32,6 @@ __FBSDID("$FreeBSD$"); #include <dev/drm2/drmP.h> #include <dev/drm2/drm.h> -/** @file drm_ioc32.c - * 32-bit ioctl compatibility routines for the DRM. - */ - #define DRM_IOCTL_VERSION32 DRM_IOWR(0x00, drm_version32_t) #define DRM_IOCTL_GET_UNIQUE32 DRM_IOWR(0x01, drm_unique32_t) #define DRM_IOCTL_GET_MAP32 DRM_IOWR(0x04, drm_map32_t) @@ -87,7 +80,8 @@ typedef struct drm_version_32 { u32 desc; /**< User-space buffer to hold desc */ } drm_version32_t; -static int compat_drm_version(struct drm_device *dev, void *data, struct drm_file *file_priv) +static int compat_drm_version(struct drm_device *dev, void *data, + struct drm_file *file_priv) { drm_version32_t *v32 = data; struct drm_version version; @@ -99,7 +93,7 @@ static int compat_drm_version(struct drm_device *dev, void *data, struct drm_fil version.date = (void *)(unsigned long)v32->date; version.desc_len = v32->desc_len; version.desc = (void *)(unsigned long)v32->desc; - + err = drm_version(dev, (void *)&version, file_priv); if (err) return err; @@ -119,7 +113,8 @@ typedef struct drm_unique32 { u32 unique; /**< Unique name for driver instantiation */ } drm_unique32_t; -static int compat_drm_getunique(struct drm_device *dev, void *data, struct drm_file *file_priv) +static int compat_drm_getunique(struct drm_device *dev, void *data, + struct drm_file *file_priv) { drm_unique32_t *uq32 = data; struct drm_unique u; @@ -137,7 +132,8 @@ static int compat_drm_getunique(struct drm_device *dev, void *data, struct drm_f return 0; } -static int compat_drm_setunique(struct drm_device *dev, void *data, struct drm_file *file_priv) +static int compat_drm_setunique(struct drm_device *dev, void *data, + struct drm_file *file_priv) { drm_unique32_t *uq32 = data; struct drm_unique u; @@ -157,7 +153,8 @@ typedef struct drm_map32 { int mtrr; /**< MTRR slot used */ } drm_map32_t; -static int compat_drm_getmap(struct drm_device *dev, void *data, struct drm_file *file_priv) +static int compat_drm_getmap(struct drm_device *dev, void *data, + struct drm_file *file_priv) { drm_map32_t *m32 = data; struct drm_map map; @@ -183,13 +180,14 @@ static int compat_drm_getmap(struct drm_device *dev, void *data, struct drm_file } -static int compat_drm_addmap(struct drm_device *dev, void *data, struct drm_file *file_priv) +static int compat_drm_addmap(struct drm_device *dev, void *data, + struct drm_file *file_priv) { drm_map32_t *m32 = data; struct drm_map map; int err; void *handle; - + map.offset = (unsigned long)m32->offset; map.size = (unsigned long)m32->size; map.type = m32->type; @@ -202,7 +200,7 @@ static int compat_drm_addmap(struct drm_device *dev, void *data, struct drm_file m32->offset = map.offset; m32->mtrr = map.mtrr; handle = map.handle; - + m32->handle = (unsigned long)handle; if (m32->handle != (unsigned long)handle) DRM_DEBUG("compat_drm_addmap truncated handle" @@ -212,7 +210,8 @@ static int compat_drm_addmap(struct drm_device *dev, void *data, struct drm_file return 0; } -static int compat_drm_rmmap(struct drm_device *dev, void *data, struct drm_file *file_priv) +static int compat_drm_rmmap(struct drm_device *dev, void *data, + struct drm_file *file_priv) { drm_map32_t *m32 = data; struct drm_map map; @@ -231,7 +230,8 @@ typedef struct drm_client32 { u32 iocs; /**< Ioctl count */ } drm_client32_t; -static int compat_drm_getclient(struct drm_device *dev, void *data, struct drm_file *file_priv) +static int compat_drm_getclient(struct drm_device *dev, void *data, + struct drm_file *file_priv) { drm_client32_t *c32 = data; struct drm_client client; @@ -261,7 +261,8 @@ typedef struct drm_stats32 { } data[15]; } drm_stats32_t; -static int compat_drm_getstats(struct drm_device *dev, void *data, struct drm_file *file_priv) +static int compat_drm_getstats(struct drm_device *dev, void *data, + struct drm_file *file_priv) { drm_stats32_t *s32 = data; struct drm_stats stats; @@ -289,7 +290,8 @@ typedef struct drm_buf_desc32 { u32 agp_start; /**< Start address in the AGP aperture */ } drm_buf_desc32_t; -static int compat_drm_addbufs(struct drm_device *dev, void *data, struct drm_file *file_priv) +static int compat_drm_addbufs(struct drm_device *dev, void *data, + struct drm_file *file_priv) { drm_buf_desc32_t *b32 = data; struct drm_buf_desc buf; @@ -312,11 +314,12 @@ static int compat_drm_addbufs(struct drm_device *dev, void *data, struct drm_fil b32->high_mark = buf.high_mark; b32->flags = buf.flags; b32->agp_start = buf.agp_start; - + return 0; } -static int compat_drm_markbufs(struct drm_device *dev, void *data, struct drm_file *file_priv) +static int compat_drm_markbufs(struct drm_device *dev, void *data, + struct drm_file *file_priv) { drm_buf_desc32_t *b32 = data; struct drm_buf_desc buf; @@ -324,7 +327,7 @@ static int compat_drm_markbufs(struct drm_device *dev, void *data, struct drm_fi buf.size = b32->size; buf.low_mark = b32->low_mark; buf.high_mark = b32->high_mark; - + return drm_markbufs(dev, (void *)&buf, file_priv); } @@ -333,7 +336,8 @@ typedef struct drm_buf_info32 { u32 list; } drm_buf_info32_t; -static int compat_drm_infobufs(struct drm_device *dev, void *data, struct drm_file *file_priv) +static int compat_drm_infobufs(struct drm_device *dev, void *data, + struct drm_file *file_priv) { drm_buf_info32_t *req32 = data; drm_buf_desc32_t *to; @@ -351,7 +355,7 @@ static int compat_drm_infobufs(struct drm_device *dev, void *data, struct drm_fi nbytes = sizeof(*request) + count * sizeof(struct drm_buf_desc); request = malloc(nbytes, DRM_MEM_BUFLISTS, M_ZERO | M_NOWAIT); if (!request) - return -EFAULT; + return -ENOMEM; list = (struct drm_buf_desc *) (request + 1); request->count = count; @@ -389,7 +393,8 @@ typedef struct drm_buf_map32 { u32 list; /**< Buffer information */ } drm_buf_map32_t; -static int compat_drm_mapbufs(struct drm_device *dev, void *data, struct drm_file *file_priv) +static int compat_drm_mapbufs(struct drm_device *dev, void *data, + struct drm_file *file_priv) { drm_buf_map32_t *req32 = data; drm_buf_pub32_t *list32; @@ -407,7 +412,7 @@ static int compat_drm_mapbufs(struct drm_device *dev, void *data, struct drm_fil nbytes = sizeof(*request) + count * sizeof(struct drm_buf_pub); request = malloc(nbytes, DRM_MEM_BUFLISTS, M_ZERO | M_NOWAIT); if (!request) - return -EFAULT; + return -ENOMEM; list = (struct drm_buf_pub *) (request + 1); request->count = count; @@ -437,7 +442,8 @@ typedef struct drm_buf_free32 { u32 list; } drm_buf_free32_t; -static int compat_drm_freebufs(struct drm_device *dev, void *data, struct drm_file *file_priv) +static int compat_drm_freebufs(struct drm_device *dev, void *data, + struct drm_file *file_priv) { drm_buf_free32_t *req32 = data; struct drm_buf_free request; @@ -453,7 +459,8 @@ typedef struct drm_ctx_priv_map32 { u32 handle; /**< Handle of map */ } drm_ctx_priv_map32_t; -static int compat_drm_setsareactx(struct drm_device *dev, void *data, struct drm_file *file_priv) +static int compat_drm_setsareactx(struct drm_device *dev, void *data, + struct drm_file *file_priv) { drm_ctx_priv_map32_t *req32 = data; struct drm_ctx_priv_map request; @@ -464,7 +471,8 @@ static int compat_drm_setsareactx(struct drm_device *dev, void *data, struct drm return drm_setsareactx(dev, (void *)&request, file_priv); } -static int compat_drm_getsareactx(struct drm_device *dev, void *data, struct drm_file *file_priv) +static int compat_drm_getsareactx(struct drm_device *dev, void *data, + struct drm_file *file_priv) { drm_ctx_priv_map32_t *req32 = data; struct drm_ctx_priv_map request; @@ -486,7 +494,8 @@ typedef struct drm_ctx_res32 { u32 contexts; } drm_ctx_res32_t; -static int compat_drm_resctx(struct drm_device *dev, void *data, struct drm_file *file_priv) +static int compat_drm_resctx(struct drm_device *dev, void *data, + struct drm_file *file_priv) { drm_ctx_res32_t *res32 = data; struct drm_ctx_res res; @@ -517,12 +526,18 @@ typedef struct drm_dma32 { int granted_count; /**< Number of buffers granted */ } drm_dma32_t; -static int compat_drm_dma(struct drm_device *dev, void *data, struct drm_file *file_priv) +static int compat_drm_dma(struct drm_device *dev, void *data, + struct drm_file *file_priv) { drm_dma32_t *d32 = data; struct drm_dma d; int err; + if (!dev->driver->dma_ioctl) { + DRM_DEBUG("DMA ioctl on driver with no dma handler\n"); + return -EINVAL; + } + d.context = d32->context; d.send_count = d32->send_count; d.send_indices = (int *)(unsigned long)d32->send_indices; @@ -532,7 +547,7 @@ static int compat_drm_dma(struct drm_device *dev, void *data, struct drm_file *f d.request_indices = (int *)(unsigned long)d32->request_indices; d.request_sizes = (int *)(unsigned long)d32->request_sizes; - err = drm_dma(dev, (void *)&d, file_priv); + err = dev->driver->dma_ioctl(dev, (void *)&d, file_priv); if (err) return err; @@ -542,11 +557,13 @@ static int compat_drm_dma(struct drm_device *dev, void *data, struct drm_file *f return 0; } +#if __OS_HAS_AGP typedef struct drm_agp_mode32 { u32 mode; /**< AGP mode */ } drm_agp_mode32_t; -static int compat_drm_agp_enable(struct drm_device *dev, void *data, struct drm_file *file_priv) +static int compat_drm_agp_enable(struct drm_device *dev, void *data, + struct drm_file *file_priv) { drm_agp_mode32_t *m32 = data; struct drm_agp_mode mode; @@ -570,7 +587,8 @@ typedef struct drm_agp_info32 { unsigned short id_device; } drm_agp_info32_t; -static int compat_drm_agp_info(struct drm_device *dev, void *data, struct drm_file *file_priv) +static int compat_drm_agp_info(struct drm_device *dev, void *data, + struct drm_file *file_priv) { drm_agp_info32_t *i32 = data; struct drm_agp_info info; @@ -600,7 +618,8 @@ typedef struct drm_agp_buffer32 { u32 physical; /**< Physical used by i810 */ } drm_agp_buffer32_t; -static int compat_drm_agp_alloc(struct drm_device *dev, void *data, struct drm_file *file_priv) +static int compat_drm_agp_alloc(struct drm_device *dev, void *data, + struct drm_file *file_priv) { drm_agp_buffer32_t *req32 = data; struct drm_agp_buffer request; @@ -619,7 +638,8 @@ static int compat_drm_agp_alloc(struct drm_device *dev, void *data, struct drm_f return 0; } -static int compat_drm_agp_free(struct drm_device *dev, void *data, struct drm_file *file_priv) +static int compat_drm_agp_free(struct drm_device *dev, void *data, + struct drm_file *file_priv) { drm_agp_buffer32_t *req32 = data; struct drm_agp_buffer request; @@ -634,7 +654,8 @@ typedef struct drm_agp_binding32 { u32 offset; /**< In bytes -- will round to page boundary */ } drm_agp_binding32_t; -static int compat_drm_agp_bind(struct drm_device *dev, void *data, struct drm_file *file_priv) +static int compat_drm_agp_bind(struct drm_device *dev, void *data, + struct drm_file *file_priv) { drm_agp_binding32_t *req32 = data; struct drm_agp_binding request; @@ -645,22 +666,25 @@ static int compat_drm_agp_bind(struct drm_device *dev, void *data, struct drm_fi return drm_agp_bind_ioctl(dev, (void *)&request, file_priv); } -static int compat_drm_agp_unbind(struct drm_device *dev, void *data, struct drm_file *file_priv) +static int compat_drm_agp_unbind(struct drm_device *dev, void *data, + struct drm_file *file_priv) { drm_agp_binding32_t *req32 = data; struct drm_agp_binding request; - + request.handle = req32->handle; - + return drm_agp_unbind_ioctl(dev, (void *)&request, file_priv); } +#endif /* __OS_HAS_AGP */ typedef struct drm_scatter_gather32 { u32 size; /**< In bytes -- will round to page boundary */ u32 handle; /**< Used for mapping / unmapping */ } drm_scatter_gather32_t; -static int compat_drm_sg_alloc(struct drm_device *dev, void *data, struct drm_file *file_priv) +static int compat_drm_sg_alloc(struct drm_device *dev, void *data, + struct drm_file *file_priv) { drm_scatter_gather32_t *req32 = data; struct drm_scatter_gather request; @@ -678,7 +702,8 @@ static int compat_drm_sg_alloc(struct drm_device *dev, void *data, struct drm_fi return 0; } -static int compat_drm_sg_free(struct drm_device *dev, void *data, struct drm_file *file_priv) +static int compat_drm_sg_free(struct drm_device *dev, void *data, + struct drm_file *file_priv) { drm_scatter_gather32_t *req32 = data; struct drm_scatter_gather request; @@ -688,6 +713,7 @@ static int compat_drm_sg_free(struct drm_device *dev, void *data, struct drm_fil return drm_sg_free(dev, (void *)&request, file_priv); } +#if defined(CONFIG_X86) || defined(CONFIG_IA64) typedef struct drm_update_draw32 { drm_drawable_t handle; unsigned int type; @@ -695,21 +721,7 @@ typedef struct drm_update_draw32 { /* 64-bit version has a 32-bit pad here */ u64 data; /**< Pointer */ } __attribute__((packed)) drm_update_draw32_t; - -static int compat_drm_update_draw(struct drm_device *dev, void *data, struct drm_file *file_priv) -{ - drm_update_draw32_t *update32 = data; - struct drm_update_draw request; - int err; - - request.handle = update32->handle; - request.type = update32->type; - request.num = update32->num; - request.data = update32->data; - - err = drm_update_draw(dev, (void *)&request, file_priv); - return err; -} +#endif struct drm_wait_vblank_request32 { enum drm_vblank_seq_type type; @@ -729,7 +741,8 @@ typedef union drm_wait_vblank32 { struct drm_wait_vblank_reply32 reply; } drm_wait_vblank32_t; -static int compat_drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_priv) +static int compat_drm_wait_vblank(struct drm_device *dev, void *data, + struct drm_file *file_priv) { drm_wait_vblank32_t *req32 = data; union drm_wait_vblank request; @@ -751,12 +764,12 @@ static int compat_drm_wait_vblank(struct drm_device *dev, void *data, struct drm return 0; } -drm_ioctl_desc_t drm_compat_ioctls[256] = { - DRM_IOCTL_DEF(DRM_IOCTL_VERSION32, compat_drm_version, 0), +struct drm_ioctl_desc drm_compat_ioctls[256] = { + DRM_IOCTL_DEF(DRM_IOCTL_VERSION32, compat_drm_version, DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_GET_UNIQUE32, compat_drm_getunique, 0), - DRM_IOCTL_DEF(DRM_IOCTL_GET_MAP32, compat_drm_getmap, 0), - DRM_IOCTL_DEF(DRM_IOCTL_GET_CLIENT32, compat_drm_getclient, 0), - DRM_IOCTL_DEF(DRM_IOCTL_GET_STATS32, compat_drm_getstats, 0), + DRM_IOCTL_DEF(DRM_IOCTL_GET_MAP32, compat_drm_getmap, DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_IOCTL_GET_CLIENT32, compat_drm_getclient, DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_IOCTL_GET_STATS32, compat_drm_getstats, DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_SET_UNIQUE32, compat_drm_setunique, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_ADD_MAP32, compat_drm_addmap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_ADD_BUFS32, compat_drm_addbufs, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), @@ -769,19 +782,19 @@ drm_ioctl_desc_t drm_compat_ioctls[256] = { DRM_IOCTL_DEF(DRM_IOCTL_GET_SAREA_CTX32, compat_drm_getsareactx, DRM_AUTH), DRM_IOCTL_DEF(DRM_IOCTL_RES_CTX32, compat_drm_resctx, DRM_AUTH), DRM_IOCTL_DEF(DRM_IOCTL_DMA32, compat_drm_dma, DRM_AUTH), - +#if __OS_HAS_AGP DRM_IOCTL_DEF(DRM_IOCTL_AGP_ENABLE32, compat_drm_agp_enable, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_AGP_INFO32, compat_drm_agp_info, DRM_AUTH), DRM_IOCTL_DEF(DRM_IOCTL_AGP_ALLOC32, compat_drm_agp_alloc, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_AGP_FREE32, compat_drm_agp_free, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_AGP_BIND32, compat_drm_agp_bind, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_AGP_UNBIND32, compat_drm_agp_unbind, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - +#endif DRM_IOCTL_DEF(DRM_IOCTL_SG_ALLOC32, compat_drm_sg_alloc, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_SG_FREE32, compat_drm_sg_free, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - - DRM_IOCTL_DEF(DRM_IOCTL_UPDATE_DRAW32, compat_drm_update_draw, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - +#if defined(CONFIG_X86) || defined(CONFIG_IA64) + DRM_IOCTL_DEF(DRM_IOCTL_UPDATE_DRAW32, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), +#endif DRM_IOCTL_DEF(DRM_IOCTL_WAIT_VBLANK32, compat_drm_wait_vblank, DRM_UNLOCKED), }; diff --git a/sys/dev/drm2/drm_ioctl.c b/sys/dev/drm2/drm_ioctl.c index e13eec787af4..a6c508a01450 100644 --- a/sys/dev/drm2/drm_ioctl.c +++ b/sys/dev/drm2/drm_ioctl.c @@ -1,4 +1,14 @@ -/*- +/** + * \file drm_ioctl.c + * IOCTL processing for DRM + * + * \author Rickard E. (Rik) Faith <faith@valinux.com> + * \author Gareth Hughes <gareth@valinux.com> + */ + +/* + * Created: Fri Jan 8 09:01:26 1999 by faith@valinux.com + * * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. * All Rights Reserved. @@ -21,216 +31,237 @@ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: - * Rickard E. (Rik) Faith <faith@valinux.com> - * Gareth Hughes <gareth@valinux.com> - * */ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); -/** @file drm_ioctl.c - * Varios minor DRM ioctls not applicable to other files, such as versioning - * information and reporting DRM information to userland. - */ - #include <dev/drm2/drmP.h> #include <dev/drm2/drm_core.h> -/* - * 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) - * before setunique has been called. The format for the bus-specific part of - * the unique is not defined for any other bus. +/** + * Get the bus id. + * + * \param inode device inode. + * \param file_priv DRM file private. + * \param cmd command. + * \param arg user argument, pointing to a drm_unique structure. + * \return zero on success or a negative number on failure. + * + * Copies the bus id from drm_device::unique into user space. */ int drm_getunique(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_unique *u = data; + struct drm_master *master = file_priv->master; - if (u->unique_len >= dev->unique_len) { - if (DRM_COPY_TO_USER(u->unique, dev->unique, dev->unique_len)) - return EFAULT; + if (u->unique_len >= master->unique_len) { + if (copy_to_user(u->unique, master->unique, master->unique_len)) + return -EFAULT; } - u->unique_len = dev->unique_len; + u->unique_len = master->unique_len; return 0; } -/* Deprecated in DRM version 1.1, and will return EBUSY when setversion has - * requested version 1.1 or greater. +static void +drm_unset_busid(struct drm_device *dev, + struct drm_master *master) +{ + + free(master->unique, DRM_MEM_DRIVER); + master->unique = NULL; + master->unique_len = 0; + master->unique_size = 0; +} + +/** + * Set the bus id. + * + * \param inode device inode. + * \param file_priv DRM file private. + * \param cmd command. + * \param arg user argument, pointing to a drm_unique structure. + * \return zero on success or a negative number on failure. + * + * Copies the bus id from userspace into drm_device::unique, and verifies that + * it matches the device this DRM is attached to (EINVAL otherwise). Deprecated + * in interface version 1.1 and will return EBUSY when setversion has requested + * version 1.1 or greater. */ int drm_setunique(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_unique *u = data; - int domain, bus, slot, func, ret; - char *busid; + struct drm_master *master = file_priv->master; + int ret; - /* Check and copy in the submitted Bus ID */ - if (!u->unique_len || u->unique_len > 1024) - return EINVAL; + if (master->unique_len || master->unique) + return -EBUSY; - busid = malloc(u->unique_len + 1, DRM_MEM_DRIVER, M_WAITOK); - if (busid == NULL) - return ENOMEM; - - if (DRM_COPY_FROM_USER(busid, u->unique, u->unique_len)) { - free(busid, DRM_MEM_DRIVER); - return EFAULT; - } - busid[u->unique_len] = '\0'; - - /* Return error if the busid submitted doesn't match the device's actual - * busid. - */ - ret = sscanf(busid, "PCI:%d:%d:%d", &bus, &slot, &func); - if (ret != 3) { - free(busid, DRM_MEM_DRIVER); - return EINVAL; - } - domain = bus >> 8; - bus &= 0xff; - - if ((domain != dev->pci_domain) || - (bus != dev->pci_bus) || - (slot != dev->pci_slot) || - (func != dev->pci_func)) { - free(busid, DRM_MEM_DRIVER); - return EINVAL; - } + if (!u->unique_len || u->unique_len > 1024) + return -EINVAL; - /* Actually set the device's busid now. */ - DRM_LOCK(dev); - if (dev->unique_len || dev->unique) { - DRM_UNLOCK(dev); - return EBUSY; - } + if (!dev->driver->bus->set_unique) + return -EINVAL; - dev->unique_len = u->unique_len; - dev->unique = busid; - DRM_UNLOCK(dev); + ret = dev->driver->bus->set_unique(dev, master, u); + if (ret) + goto err; return 0; -} +err: + drm_unset_busid(dev, master); + return ret; +} -static int -drm_set_busid(struct drm_device *dev) +static int drm_set_busid(struct drm_device *dev, struct drm_file *file_priv) { + struct drm_master *master = file_priv->master; + int ret; - DRM_LOCK(dev); - - if (dev->unique != NULL) { - DRM_UNLOCK(dev); - return EBUSY; - } - - dev->unique_len = 20; - dev->unique = malloc(dev->unique_len + 1, DRM_MEM_DRIVER, M_NOWAIT); - if (dev->unique == NULL) { - DRM_UNLOCK(dev); - return ENOMEM; - } - - snprintf(dev->unique, dev->unique_len, "pci:%04x:%02x:%02x.%1x", - dev->pci_domain, dev->pci_bus, dev->pci_slot, dev->pci_func); - - DRM_UNLOCK(dev); + if (master->unique != NULL) + drm_unset_busid(dev, master); + ret = dev->driver->bus->set_busid(dev, master); + if (ret) + goto err; return 0; +err: + drm_unset_busid(dev, master); + return ret; } -int drm_getmap(struct drm_device *dev, void *data, struct drm_file *file_priv) +/** + * Get a mapping information. + * + * \param inode device inode. + * \param file_priv DRM file private. + * \param cmd command. + * \param arg user argument, pointing to a drm_map structure. + * + * \return zero on success or a negative number on failure. + * + * Searches for the mapping with the specified offset and copies its information + * into userspace + */ +int drm_getmap(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - struct drm_map *map = data; - drm_local_map_t *mapinlist; - int idx; - int i = 0; + struct drm_map *map = data; + struct drm_map_list *r_list = NULL; + struct list_head *list; + int idx; + int i; idx = map->offset; + if (idx < 0) + return -EINVAL; + i = 0; DRM_LOCK(dev); - if (idx < 0) { - DRM_UNLOCK(dev); - return EINVAL; - } - - TAILQ_FOREACH(mapinlist, &dev->maplist, link) { + list_for_each(list, &dev->maplist) { if (i == idx) { - map->offset = mapinlist->offset; - map->size = mapinlist->size; - map->type = mapinlist->type; - map->flags = mapinlist->flags; - map->handle = mapinlist->handle; - map->mtrr = mapinlist->mtrr; + r_list = list_entry(list, struct drm_map_list, head); break; } i++; } + if (!r_list || !r_list->map) { + DRM_UNLOCK(dev); + return -EINVAL; + } + map->offset = r_list->map->offset; + map->size = r_list->map->size; + map->type = r_list->map->type; + map->flags = r_list->map->flags; + map->handle = (void *)(unsigned long) r_list->user_token; + map->mtrr = r_list->map->mtrr; DRM_UNLOCK(dev); - if (mapinlist == NULL) - return EINVAL; - return 0; } +/** + * Get client information. + * + * \param inode device inode. + * \param file_priv DRM file private. + * \param cmd command. + * \param arg user argument, pointing to a drm_client structure. + * + * \return zero on success or a negative number on failure. + * + * Searches for the client with the specified index and copies its information + * into userspace + */ int drm_getclient(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_client *client = data; struct drm_file *pt; int idx; - int i = 0; + int i; idx = client->idx; + i = 0; + DRM_LOCK(dev); - TAILQ_FOREACH(pt, &dev->files, link) { - if (i == idx) { - client->auth = pt->authenticated; - client->pid = pt->pid; - client->uid = pt->uid; + list_for_each_entry(pt, &dev->filelist, lhead) { + if (i++ >= idx) { + client->auth = pt->authenticated; + client->pid = pt->pid; + client->uid = pt->uid; client->magic = pt->magic; - client->iocs = pt->ioctl_count; + client->iocs = pt->ioctl_count; DRM_UNLOCK(dev); + return 0; } - i++; } DRM_UNLOCK(dev); - return EINVAL; + return -EINVAL; } -int drm_getstats(struct drm_device *dev, void *data, struct drm_file *file_priv) +/** + * Get statistics information. + * + * \param inode device inode. + * \param file_priv DRM file private. + * \param cmd command. + * \param arg user argument, pointing to a drm_stats structure. + * + * \return zero on success or a negative number on failure. + */ +int drm_getstats(struct drm_device *dev, void *data, + struct drm_file *file_priv) { struct drm_stats *stats = data; - int i; + int i; - memset(stats, 0, sizeof(struct drm_stats)); - - DRM_LOCK(dev); + memset(stats, 0, sizeof(*stats)); for (i = 0; i < dev->counters; i++) { if (dev->types[i] == _DRM_STAT_LOCK) stats->data[i].value = - (dev->lock.hw_lock ? dev->lock.hw_lock->lock : 0); - else + (file_priv->master->lock.hw_lock ? file_priv->master->lock.hw_lock->lock : 0); + else stats->data[i].value = atomic_read(&dev->counts[i]); stats->data[i].type = dev->types[i]; } - - stats->count = dev->counters; - DRM_UNLOCK(dev); + stats->count = dev->counters; return 0; } +/** + * Get device/driver capabilities + */ int drm_getcap(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_get_cap *req = data; @@ -258,67 +289,73 @@ int drm_getcap(struct drm_device *dev, void *data, struct drm_file *file_priv) req->value = drm_timestamp_monotonic; break; default: - return EINVAL; + return -EINVAL; } return 0; } -int drm_setversion(struct drm_device *dev, void *data, - struct drm_file *file_priv) +/** + * Setversion ioctl. + * + * \param inode device inode. + * \param file_priv DRM file private. + * \param cmd command. + * \param arg user argument, pointing to a drm_lock structure. + * \return zero on success or negative number on failure. + * + * Sets the requested interface version + */ +int drm_setversion(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_set_version *sv = data; - struct drm_set_version ver; - int if_version; - - /* Save the incoming data, and set the response before continuing - * any further. - */ - ver = *sv; - sv->drm_di_major = DRM_IF_MAJOR; - sv->drm_di_minor = DRM_IF_MINOR; - sv->drm_dd_major = dev->driver->major; - sv->drm_dd_minor = dev->driver->minor; + int if_version, retcode = 0; - DRM_DEBUG("ver.drm_di_major %d ver.drm_di_minor %d " - "ver.drm_dd_major %d ver.drm_dd_minor %d\n", - ver.drm_di_major, ver.drm_di_minor, ver.drm_dd_major, - ver.drm_dd_minor); - DRM_DEBUG("sv->drm_di_major %d sv->drm_di_minor %d " - "sv->drm_dd_major %d sv->drm_dd_minor %d\n", - sv->drm_di_major, sv->drm_di_minor, sv->drm_dd_major, - sv->drm_dd_minor); - - if (ver.drm_di_major != -1) { - if (ver.drm_di_major != DRM_IF_MAJOR || - ver.drm_di_minor < 0 || ver.drm_di_minor > DRM_IF_MINOR) { - return EINVAL; + if (sv->drm_di_major != -1) { + if (sv->drm_di_major != DRM_IF_MAJOR || + sv->drm_di_minor < 0 || sv->drm_di_minor > DRM_IF_MINOR) { + retcode = -EINVAL; + goto done; } - if_version = DRM_IF_VERSION(ver.drm_di_major, - ver.drm_dd_minor); - dev->if_version = DRM_MAX(if_version, dev->if_version); - if (ver.drm_di_minor >= 1) { + if_version = DRM_IF_VERSION(sv->drm_di_major, + sv->drm_di_minor); + dev->if_version = max(if_version, dev->if_version); + if (sv->drm_di_minor >= 1) { /* * Version 1.1 includes tying of DRM to specific device + * Version 1.4 has proper PCI domain support */ - drm_set_busid(dev); + retcode = drm_set_busid(dev, file_priv); + if (retcode) + goto done; } } - if (ver.drm_dd_major != -1) { - if (ver.drm_dd_major != dev->driver->major || - ver.drm_dd_minor < 0 || - ver.drm_dd_minor > dev->driver->minor) - { - return EINVAL; + if (sv->drm_dd_major != -1) { + if (sv->drm_dd_major != dev->driver->major || + sv->drm_dd_minor < 0 || sv->drm_dd_minor > + dev->driver->minor) { + retcode = -EINVAL; + goto done; } + + if (dev->driver->set_version) + dev->driver->set_version(dev, sv); } - return 0; -} +done: + sv->drm_di_major = DRM_IF_MAJOR; + sv->drm_di_minor = DRM_IF_MINOR; + sv->drm_dd_major = dev->driver->major; + sv->drm_dd_minor = dev->driver->minor; + return retcode; +} -int drm_noop(struct drm_device *dev, void *data, struct drm_file *file_priv) +/** No-op ioctl. */ +int drm_noop(struct drm_device *dev, void *data, + struct drm_file *file_priv) { DRM_DEBUG("\n"); return 0; } +EXPORT_SYMBOL(drm_noop); diff --git a/sys/dev/drm2/drm_irq.c b/sys/dev/drm2/drm_irq.c index f79d46a0a07b..f93cd38eddd2 100644 --- a/sys/dev/drm2/drm_irq.c +++ b/sys/dev/drm2/drm_irq.c @@ -1,5 +1,16 @@ -/*- - * Copyright 2003 Eric Anholt +/** + * \file drm_irq.c + * IRQ support + * + * \author Rickard E. (Rik) Faith <faith@valinux.com> + * \author Gareth Hughes <gareth@valinux.com> + */ + +/* + * Created: Fri Mar 19 14:30:16 1999 by faith@valinux.com + * + * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a @@ -16,27 +27,16 @@ * 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 <anholt@FreeBSD.org> - * + * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. */ #include <sys/cdefs.h> __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/drm2/drmP.h> -#include <dev/drm2/drm.h> - -MALLOC_DEFINE(DRM_MEM_VBLANK, "drm_vblank", "DRM VBLANK Handling Data"); /* Access macro for slots in vblank timestamp ringbuffer. */ #define vblanktimestamp(dev, crtc, count) ( \ @@ -53,179 +53,31 @@ MALLOC_DEFINE(DRM_MEM_VBLANK, "drm_vblank", "DRM VBLANK Handling Data"); */ #define DRM_REDUNDANT_VBLIRQ_THRESH_NS 1000000 +/** + * Get interrupt from bus id. + * + * \param inode device inode. + * \param file_priv DRM file private. + * \param cmd command. + * \param arg user argument, pointing to a drm_irq_busid structure. + * \return zero on success or a negative number on failure. + * + * Finds the PCI device with the specified bus id and gets its IRQ number. + * This IOCTL is deprecated, and will now return EINVAL for any busid not equal + * to that of the device that this DRM instance attached to. + */ 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 void -drm_irq_handler_wrap(void *arg) -{ - struct drm_device *dev = arg; - - mtx_lock(&dev->irq_lock); - dev->driver->irq_handler(arg); - mtx_unlock(&dev->irq_lock); -} - -int -drm_irq_install(struct drm_device *dev) -{ - int retcode; - - if (dev->irq == 0 || dev->dev_private == NULL) - return (EINVAL); - - DRM_DEBUG("irq=%d\n", dev->irq); - - DRM_LOCK(dev); - if (dev->irq_enabled) { - DRM_UNLOCK(dev); - return EBUSY; - } - dev->irq_enabled = 1; - - dev->context_flag = 0; - - /* Before installing handler */ - if (dev->driver->irq_preinstall) - dev->driver->irq_preinstall(dev); - DRM_UNLOCK(dev); - - /* Install handler */ - retcode = bus_setup_intr(dev->device, dev->irqr, - INTR_TYPE_TTY | INTR_MPSAFE, NULL, - (dev->driver->driver_features & DRIVER_LOCKLESS_IRQ) != 0 ? - drm_irq_handler_wrap : dev->driver->irq_handler, - dev, &dev->irqh); - if (retcode != 0) - goto err; - - /* After installing handler */ - DRM_LOCK(dev); - if (dev->driver->irq_postinstall) - dev->driver->irq_postinstall(dev); - DRM_UNLOCK(dev); - - return (0); -err: - device_printf(dev->device, "Error setting interrupt: %d\n", retcode); - dev->irq_enabled = 0; - - return (retcode); -} - -int drm_irq_uninstall(struct drm_device *dev) -{ - int i; - - if (!dev->irq_enabled) - return EINVAL; - - dev->irq_enabled = 0; - - /* - * Wake up any waiters so they don't hang. - */ - if (dev->num_crtcs) { - mtx_lock(&dev->vbl_lock); - for (i = 0; i < dev->num_crtcs; i++) { - wakeup(&dev->_vblank_count[i]); - dev->vblank_enabled[i] = 0; - dev->last_vblank[i] = - dev->driver->get_vblank_counter(dev, i); - } - mtx_unlock(&dev->vbl_lock); - } - - DRM_DEBUG("irq=%d\n", dev->irq); + struct drm_irq_busid *p = data; - if (dev->driver->irq_uninstall) - dev->driver->irq_uninstall(dev); - - DRM_UNLOCK(dev); - bus_teardown_intr(dev->device, dev->irqr, dev->irqh); - DRM_LOCK(dev); - - 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 (drm_core_check_feature(dev, DRIVER_MODESET)) - 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; - if (drm_core_check_feature(dev, DRIVER_MODESET)) - return 0; - DRM_LOCK(dev); - err = drm_irq_uninstall(dev); - DRM_UNLOCK(dev); - return err; - default: - return EINVAL; - } -} - -#define NSEC_PER_USEC 1000L -#define NSEC_PER_SEC 1000000000L - -int64_t -timeval_to_ns(const struct timeval *tv) -{ - return ((int64_t)tv->tv_sec * NSEC_PER_SEC) + - tv->tv_usec * NSEC_PER_USEC; -} - -struct timeval -ns_to_timeval(const int64_t nsec) -{ - struct timeval tv; - long rem; + if (!dev->driver->bus->irq_by_busid) + return -EINVAL; - if (nsec == 0) { - tv.tv_sec = 0; - tv.tv_usec = 0; - return (tv); - } + if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) + return -EINVAL; - tv.tv_sec = nsec / NSEC_PER_SEC; - rem = nsec % NSEC_PER_SEC; - if (rem < 0) { - tv.tv_sec--; - rem += NSEC_PER_SEC; - } - tv.tv_usec = rem / 1000; - return (tv); + return dev->driver->bus->irq_by_busid(dev, p); } /* @@ -237,13 +89,6 @@ static void clear_vblank_timestamps(struct drm_device *dev, int crtc) DRM_VBLANKTIME_RBSIZE * sizeof(struct timeval)); } -static int64_t -abs64(int64_t x) -{ - - return (x < 0 ? -x : x); -} - /* * Disable vblank irq's on crtc, make sure that last vblank count * of hardware and corresponding consistent software vblank counter @@ -253,9 +98,10 @@ abs64(int64_t x) static void vblank_disable_and_save(struct drm_device *dev, int crtc) { u32 vblcount; - int64_t diff_ns; + s64 diff_ns; int vblrc; struct timeval tvblank; + int count = DRM_TIMESTAMP_MAXRETRIES; /* Prevent vblank irq processing while disabling vblank irqs, * so no updates of timestamps or count can happen after we've @@ -281,7 +127,10 @@ static void vblank_disable_and_save(struct drm_device *dev, int crtc) do { dev->last_vblank[crtc] = dev->driver->get_vblank_counter(dev, crtc); vblrc = drm_get_last_vbltimestamp(dev, crtc, &tvblank, 0); - } while (dev->last_vblank[crtc] != dev->driver->get_vblank_counter(dev, crtc)); + } while (dev->last_vblank[crtc] != dev->driver->get_vblank_counter(dev, crtc) && (--count) && vblrc); + + if (!count) + vblrc = 0; /* Compute time difference to stored timestamp of last vblank * as updated by last invocation of drm_handle_vblank() in vblank irq. @@ -304,6 +153,7 @@ static void vblank_disable_and_save(struct drm_device *dev, int crtc) */ if ((vblrc > 0) && (abs64(diff_ns) > 1000000)) { atomic_inc(&dev->_vblank_count[crtc]); + smp_mb__after_atomic_inc(); } /* Invalidate all timestamps while vblank irq's are off. */ @@ -312,7 +162,7 @@ static void vblank_disable_and_save(struct drm_device *dev, int crtc) mtx_unlock(&dev->vblank_time_lock); } -static void vblank_disable_fn(void * arg) +static void vblank_disable_fn(void *arg) { struct drm_device *dev = (struct drm_device *)arg; int i; @@ -349,35 +199,58 @@ void drm_vblank_cleanup(struct drm_device *dev) free(dev->vblank_inmodeset, DRM_MEM_VBLANK); free(dev->_vblank_time, DRM_MEM_VBLANK); + mtx_destroy(&dev->vbl_lock); + mtx_destroy(&dev->vblank_time_lock); + dev->num_crtcs = 0; } +EXPORT_SYMBOL(drm_vblank_cleanup); int drm_vblank_init(struct drm_device *dev, int num_crtcs) { - int i; + int i, ret = -ENOMEM; callout_init(&dev->vblank_disable_callout, CALLOUT_MPSAFE); -#if 0 mtx_init(&dev->vbl_lock, "drmvbl", NULL, MTX_DEF); -#endif mtx_init(&dev->vblank_time_lock, "drmvtl", NULL, MTX_DEF); dev->num_crtcs = num_crtcs; dev->_vblank_count = malloc(sizeof(atomic_t) * num_crtcs, - DRM_MEM_VBLANK, M_WAITOK); + DRM_MEM_VBLANK, M_NOWAIT); + if (!dev->_vblank_count) + goto err; + dev->vblank_refcount = malloc(sizeof(atomic_t) * num_crtcs, - DRM_MEM_VBLANK, M_WAITOK); + DRM_MEM_VBLANK, M_NOWAIT); + if (!dev->vblank_refcount) + goto err; + dev->vblank_enabled = malloc(num_crtcs * sizeof(int), - DRM_MEM_VBLANK, M_WAITOK | M_ZERO); + DRM_MEM_VBLANK, M_NOWAIT | M_ZERO); + if (!dev->vblank_enabled) + goto err; + dev->last_vblank = malloc(num_crtcs * sizeof(u32), - DRM_MEM_VBLANK, M_WAITOK | M_ZERO); + DRM_MEM_VBLANK, M_NOWAIT | M_ZERO); + if (!dev->last_vblank) + goto err; + dev->last_vblank_wait = malloc(num_crtcs * sizeof(u32), - DRM_MEM_VBLANK, M_WAITOK | M_ZERO); + DRM_MEM_VBLANK, M_NOWAIT | M_ZERO); + if (!dev->last_vblank_wait) + goto err; + dev->vblank_inmodeset = malloc(num_crtcs * sizeof(int), - DRM_MEM_VBLANK, M_WAITOK | M_ZERO); + DRM_MEM_VBLANK, M_NOWAIT | M_ZERO); + if (!dev->vblank_inmodeset) + goto err; + dev->_vblank_time = malloc(num_crtcs * DRM_VBLANKTIME_RBSIZE * - sizeof(struct timeval), DRM_MEM_VBLANK, M_WAITOK | M_ZERO); + sizeof(struct timeval), DRM_MEM_VBLANK, M_NOWAIT | M_ZERO); + if (!dev->_vblank_time) + goto err; + DRM_INFO("Supports vblank timestamp caching Rev 1 (10.10.2010).\n"); /* Driver specific high-precision vblank timestamping supported? */ @@ -394,16 +267,203 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs) dev->vblank_disable_allowed = 0; return 0; + +err: + drm_vblank_cleanup(dev); + return ret; +} +EXPORT_SYMBOL(drm_vblank_init); + +/** + * Install IRQ handler. + * + * \param dev DRM device. + * + * Initializes the IRQ related data. Installs the handler, calling the driver + * \c irq_preinstall() and \c irq_postinstall() functions + * before and after the installation. + */ +int drm_irq_install(struct drm_device *dev) +{ + int ret; + unsigned long sh_flags = 0; + + if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) + return -EINVAL; + + if (drm_dev_to_irq(dev) == 0) + return -EINVAL; + + DRM_LOCK(dev); + + /* Driver must have been initialized */ + if (!dev->dev_private) { + DRM_UNLOCK(dev); + return -EINVAL; + } + + if (dev->irq_enabled) { + DRM_UNLOCK(dev); + return -EBUSY; + } + dev->irq_enabled = 1; + DRM_UNLOCK(dev); + + DRM_DEBUG("irq=%d\n", drm_dev_to_irq(dev)); + + /* Before installing handler */ + if (dev->driver->irq_preinstall) + dev->driver->irq_preinstall(dev); + + /* Install handler */ + sh_flags = INTR_TYPE_TTY | INTR_MPSAFE; + if (!drm_core_check_feature(dev, DRIVER_IRQ_SHARED)) + /* + * FIXME Linux<->FreeBSD: This seems to make + * bus_setup_intr() unhappy: it was reported to return + * EINVAL on an i915 board (8086:2592 in a Thinkpad + * X41). + * + * For now, no driver we have use that. + */ + sh_flags |= INTR_EXCL; + + ret = -bus_setup_intr(dev->dev, dev->irqr, sh_flags, NULL, + dev->driver->irq_handler, dev, &dev->irqh); + + if (ret < 0) { + device_printf(dev->dev, "Error setting interrupt: %d\n", -ret); + DRM_LOCK(dev); + dev->irq_enabled = 0; + DRM_UNLOCK(dev); + return ret; + } + + /* After installing handler */ + if (dev->driver->irq_postinstall) + ret = dev->driver->irq_postinstall(dev); + + if (ret < 0) { + DRM_LOCK(dev); + dev->irq_enabled = 0; + DRM_UNLOCK(dev); + bus_teardown_intr(dev->dev, dev->irqr, dev->irqh); + dev->driver->bus->free_irq(dev); + } + + return ret; +} +EXPORT_SYMBOL(drm_irq_install); + +/** + * Uninstall the IRQ handler. + * + * \param dev DRM device. + * + * Calls the driver's \c irq_uninstall() function, and stops the irq. + */ +int drm_irq_uninstall(struct drm_device *dev) +{ + int irq_enabled, i; + + if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) + return -EINVAL; + + DRM_LOCK(dev); + irq_enabled = dev->irq_enabled; + dev->irq_enabled = 0; + DRM_UNLOCK(dev); + + /* + * Wake up any waiters so they don't hang. + */ + if (dev->num_crtcs) { + mtx_lock(&dev->vbl_lock); + for (i = 0; i < dev->num_crtcs; i++) { + DRM_WAKEUP(&dev->_vblank_count[i]); + dev->vblank_enabled[i] = 0; + dev->last_vblank[i] = + dev->driver->get_vblank_counter(dev, i); + } + mtx_unlock(&dev->vbl_lock); + } + + if (!irq_enabled) + return -EINVAL; + + DRM_DEBUG("irq=%d\n", drm_dev_to_irq(dev)); + + if (dev->driver->irq_uninstall) + dev->driver->irq_uninstall(dev); + + bus_teardown_intr(dev->dev, dev->irqr, dev->irqh); + dev->driver->bus->free_irq(dev); + + return 0; } +EXPORT_SYMBOL(drm_irq_uninstall); -void -drm_calc_timestamping_constants(struct drm_crtc *crtc) +/** + * IRQ control ioctl. + * + * \param inode device inode. + * \param file_priv DRM file private. + * \param cmd command. + * \param arg user argument, pointing to a drm_control structure. + * \return zero on success or a negative number on failure. + * + * Calls irq_install() or irq_uninstall() according to \p arg. + */ +int drm_control(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - int64_t linedur_ns = 0, pixeldur_ns = 0, framedur_ns = 0; - uint64_t dotclock; + struct drm_control *ctl = data; + + /* if we haven't irq we fallback for compatibility reasons - + * this used to be a separate function in drm_dma.h + */ + + + switch (ctl->func) { + case DRM_INST_HANDLER: + if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) + return 0; + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return 0; + if (dev->if_version < DRM_IF_VERSION(1, 2) && + ctl->irq != drm_dev_to_irq(dev)) + return -EINVAL; + return drm_irq_install(dev); + case DRM_UNINST_HANDLER: + if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) + return 0; + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return 0; + return drm_irq_uninstall(dev); + default: + return -EINVAL; + } +} + +/** + * drm_calc_timestamping_constants - Calculate and + * store various constants which are later needed by + * vblank and swap-completion timestamping, e.g, by + * drm_calc_vbltimestamp_from_scanoutpos(). + * They are derived from crtc's true scanout timing, + * so they take things like panel scaling or other + * adjustments into account. + * + * @crtc drm_crtc whose timestamp constants should be updated. + * + */ +void drm_calc_timestamping_constants(struct drm_crtc *crtc) +{ + s64 linedur_ns = 0, pixeldur_ns = 0, framedur_ns = 0; + u64 dotclock; /* Dot clock in Hz: */ - dotclock = (uint64_t) crtc->hwmode.clock * 1000; + dotclock = (u64) crtc->hwmode.clock * 1000; /* Fields of interlaced scanout modes are only halve a frame duration. * Double the dotclock to get halve the frame-/line-/pixelduration. @@ -417,10 +477,10 @@ drm_calc_timestamping_constants(struct drm_crtc *crtc) * line duration, frame duration and pixel duration in * nanoseconds: */ - pixeldur_ns = (int64_t)1000000000 / dotclock; - linedur_ns = ((uint64_t)crtc->hwmode.crtc_htotal * - 1000000000) / dotclock; - framedur_ns = (int64_t)crtc->hwmode.crtc_vtotal * linedur_ns; + pixeldur_ns = (s64) div64_u64(1000000000, dotclock); + linedur_ns = (s64) div64_u64(((u64) crtc->hwmode.crtc_htotal * + 1000000000), dotclock); + framedur_ns = (s64) crtc->hwmode.crtc_vtotal * linedur_ns; } else DRM_ERROR("crtc %d: Can't calculate constants, dotclock = 0!\n", crtc->base.id); @@ -436,6 +496,7 @@ drm_calc_timestamping_constants(struct drm_crtc *crtc) crtc->base.id, (int) dotclock/1000, (int) framedur_ns, (int) linedur_ns, (int) pixeldur_ns); } +EXPORT_SYMBOL(drm_calc_timestamping_constants); /** * drm_calc_vbltimestamp_from_scanoutpos - helper routine for kms @@ -481,16 +542,17 @@ drm_calc_timestamping_constants(struct drm_crtc *crtc) * DRM_VBLANKTIME_INVBL - Timestamp taken while scanout was in vblank interval. * */ -int -drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc, - int *max_error, struct timeval *vblank_time, unsigned flags, - struct drm_crtc *refcrtc) +int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc, + int *max_error, + struct timeval *vblank_time, + unsigned flags, + struct drm_crtc *refcrtc) { struct timeval stime, raw_time; struct drm_display_mode *mode; int vbl_status, vtotal, vdisplay; int vpos, hpos, i; - int64_t framedur_ns, linedur_ns, pixeldur_ns, delta_ns, duration_ns; + s64 framedur_ns, linedur_ns, pixeldur_ns, delta_ns, duration_ns; bool invbl; if (crtc < 0 || crtc >= dev->num_crtcs) { @@ -530,7 +592,7 @@ drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc, */ for (i = 0; i < DRM_TIMESTAMP_MAXRETRIES; i++) { /* Disable preemption to make it very likely to - * succeed in the first iteration. + * succeed in the first iteration even on PREEMPT_RT kernel. */ critical_enter(); @@ -542,6 +604,10 @@ drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc, /* Get system timestamp after query. */ getmicrouptime(&raw_time); +#ifdef FREEBSD_NOTYET + if (!drm_timestamp_monotonic) + mono_time_offset = ktime_get_monotonic_offset(); +#endif /* FREEBSD_NOTYET */ critical_exit(); @@ -555,7 +621,7 @@ drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc, duration_ns = timeval_to_ns(&raw_time) - timeval_to_ns(&stime); /* Accept result with < max_error nsecs timing uncertainty. */ - if (duration_ns <= (int64_t) *max_error) + if (duration_ns <= (s64) *max_error) break; } @@ -579,7 +645,7 @@ drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc, * since start of scanout at first display scanline. delta_ns * can be negative if start of scanout hasn't happened yet. */ - delta_ns = (int64_t)vpos * linedur_ns + (int64_t)hpos * pixeldur_ns; + delta_ns = (s64) vpos * linedur_ns + (s64) hpos * pixeldur_ns; /* Is vpos outside nominal vblank area, but less than * 1/100 of a frame height away from start of vblank? @@ -599,6 +665,13 @@ drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc, vbl_status |= 0x8; } +#ifdef FREEBSD_NOTYET + if (!drm_timestamp_monotonic) + etime = ktime_sub(etime, mono_time_offset); + + /* save this only for debugging purposes */ + tv_etime = ktime_to_timeval(etime); +#endif /* FREEBSD_NOTYET */ /* Subtract time delta from raw timestamp to get final * vblank_time timestamp for end of vblank. */ @@ -615,6 +688,20 @@ drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc, return vbl_status; } +EXPORT_SYMBOL(drm_calc_vbltimestamp_from_scanoutpos); + +static struct timeval get_drm_timestamp(void) +{ + struct timeval now; + + microtime(&now); +#ifdef FREEBSD_NOTYET + if (!drm_timestamp_monotonic) + now = ktime_sub(now, ktime_get_monotonic_offset()); +#endif /* defined(FREEBSD_NOTYET) */ + + return now; +} /** * drm_get_last_vbltimestamp - retrieve raw timestamp for the most recent @@ -653,12 +740,13 @@ u32 drm_get_last_vbltimestamp(struct drm_device *dev, int crtc, } /* GPU high precision timestamp query unsupported or failed. - * Return gettimeofday timestamp as best estimate. + * Return current monotonic/gettimeofday timestamp as best estimate. */ - microtime(tvblank); + *tvblank = get_drm_timestamp(); return 0; } +EXPORT_SYMBOL(drm_get_last_vbltimestamp); /** * drm_vblank_count - retrieve "cooked" vblank counter value @@ -673,6 +761,7 @@ u32 drm_vblank_count(struct drm_device *dev, int crtc) { return atomic_read(&dev->_vblank_count[crtc]); } +EXPORT_SYMBOL(drm_vblank_count); /** * drm_vblank_count_and_time - retrieve "cooked" vblank counter value @@ -701,11 +790,53 @@ u32 drm_vblank_count_and_time(struct drm_device *dev, int crtc, do { cur_vblank = atomic_read(&dev->_vblank_count[crtc]); *vblanktime = vblanktimestamp(dev, crtc, cur_vblank); - rmb(); + smp_rmb(); } while (cur_vblank != atomic_read(&dev->_vblank_count[crtc])); return cur_vblank; } +EXPORT_SYMBOL(drm_vblank_count_and_time); + +static void send_vblank_event(struct drm_device *dev, + struct drm_pending_vblank_event *e, + unsigned long seq, struct timeval *now) +{ + WARN_ON_SMP(!mtx_owned(&dev->event_lock)); + e->event.sequence = seq; + e->event.tv_sec = now->tv_sec; + e->event.tv_usec = now->tv_usec; + + list_add_tail(&e->base.link, + &e->base.file_priv->event_list); + drm_event_wakeup(&e->base); + CTR3(KTR_DRM, "vblank_event_delivered %d %d %d", + e->base.pid, e->pipe, e->event.sequence); +} + +/** + * drm_send_vblank_event - helper to send vblank event after pageflip + * @dev: DRM device + * @crtc: CRTC in question + * @e: the event to send + * + * Updates sequence # and timestamp on event, and sends it to userspace. + * Caller must hold event lock. + */ +void drm_send_vblank_event(struct drm_device *dev, int crtc, + struct drm_pending_vblank_event *e) +{ + struct timeval now; + unsigned int seq; + if (crtc >= 0) { + seq = drm_vblank_count_and_time(dev, crtc, &now); + } else { + seq = 0; + + now = get_drm_timestamp(); + } + send_vblank_event(dev, e, seq, &now); +} +EXPORT_SYMBOL(drm_send_vblank_event); /** * drm_update_vblank_count - update the master vblank counter @@ -766,7 +897,9 @@ static void drm_update_vblank_count(struct drm_device *dev, int crtc) vblanktimestamp(dev, crtc, tslot) = t_vblank; } + smp_mb__before_atomic_inc(); atomic_add(diff, &dev->_vblank_count[crtc]); + smp_mb__after_atomic_inc(); } /** @@ -795,7 +928,7 @@ int drm_vblank_get(struct drm_device *dev, int crtc) * timestamps. Filtercode in drm_handle_vblank() will * prevent double-accounting of same vblank interval. */ - ret = -dev->driver->enable_vblank(dev, crtc); + ret = dev->driver->enable_vblank(dev, crtc); DRM_DEBUG("enabling vblank on crtc %d, ret: %d\n", crtc, ret); if (ret) @@ -809,13 +942,14 @@ int drm_vblank_get(struct drm_device *dev, int crtc) } else { if (!dev->vblank_enabled[crtc]) { atomic_dec(&dev->vblank_refcount[crtc]); - ret = EINVAL; + ret = -EINVAL; } } mtx_unlock(&dev->vbl_lock); return ret; } +EXPORT_SYMBOL(drm_vblank_get); /** * drm_vblank_put - give up ownership of vblank events @@ -827,8 +961,7 @@ int drm_vblank_get(struct drm_device *dev, int crtc) */ void drm_vblank_put(struct drm_device *dev, int crtc) { - KASSERT(atomic_read(&dev->vblank_refcount[crtc]) != 0, - ("Too many drm_vblank_put for crtc %d", crtc)); + BUG_ON(atomic_read(&dev->vblank_refcount[crtc]) == 0); /* Last user schedules interrupt disable */ if (atomic_dec_and_test(&dev->vblank_refcount[crtc]) && @@ -837,7 +970,15 @@ void drm_vblank_put(struct drm_device *dev, int crtc) (drm_vblank_offdelay * DRM_HZ) / 1000, vblank_disable_fn, dev); } +EXPORT_SYMBOL(drm_vblank_put); +/** + * drm_vblank_off - disable vblank events on a CRTC + * @dev: DRM device + * @crtc: CRTC in question + * + * Caller must hold event lock. + */ void drm_vblank_off(struct drm_device *dev, int crtc) { struct drm_pending_vblank_event *e, *t; @@ -846,37 +987,32 @@ void drm_vblank_off(struct drm_device *dev, int crtc) mtx_lock(&dev->vbl_lock); vblank_disable_and_save(dev, crtc); - mtx_lock(&dev->event_lock); - wakeup(&dev->_vblank_count[crtc]); + DRM_WAKEUP(&dev->_vblank_count[crtc]); /* Send any queued vblank events, lest the natives grow disquiet */ seq = drm_vblank_count_and_time(dev, crtc, &now); + + mtx_lock(&dev->event_lock); list_for_each_entry_safe(e, t, &dev->vblank_event_list, base.link) { if (e->pipe != crtc) continue; DRM_DEBUG("Sending premature vblank event on disable: \ wanted %d, current %d\n", e->event.sequence, seq); - - e->event.sequence = seq; - e->event.tv_sec = now.tv_sec; - e->event.tv_usec = now.tv_usec; + list_del(&e->base.link); drm_vblank_put(dev, e->pipe); - list_move_tail(&e->base.link, &e->base.file_priv->event_list); - drm_event_wakeup(&e->base); - CTR3(KTR_DRM, "vblank_event_delivered %d %d %d", - e->base.pid, e->pipe, e->event.sequence); + send_vblank_event(dev, e, seq, &now); } - mtx_unlock(&dev->event_lock); + mtx_unlock(&dev->vbl_lock); } +EXPORT_SYMBOL(drm_vblank_off); /** * drm_vblank_pre_modeset - account for vblanks across mode sets * @dev: DRM device * @crtc: CRTC in question - * @post: post or pre mode set? * * Account for vblank events across mode setting events, which will likely * reset the hardware frame counter. @@ -899,6 +1035,7 @@ void drm_vblank_pre_modeset(struct drm_device *dev, int crtc) dev->vblank_inmodeset[crtc] |= 0x2; } } +EXPORT_SYMBOL(drm_vblank_pre_modeset); void drm_vblank_post_modeset(struct drm_device *dev, int crtc) { @@ -917,6 +1054,7 @@ void drm_vblank_post_modeset(struct drm_device *dev, int crtc) dev->vblank_inmodeset[crtc] = 0; } } +EXPORT_SYMBOL(drm_vblank_post_modeset); /** * drm_modeset_ctl - handle vblank event counter changes across mode switch @@ -939,6 +1077,10 @@ int drm_modeset_ctl(struct drm_device *dev, void *data, if (!dev->num_crtcs) return 0; + /* KMS drivers handle this internally */ + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return 0; + crtc = modeset->crtc; if (crtc >= dev->num_crtcs) return -EINVAL; @@ -952,7 +1094,6 @@ int drm_modeset_ctl(struct drm_device *dev, void *data, break; default: return -EINVAL; - break; } return 0; @@ -974,7 +1115,11 @@ static int drm_queue_vblank_event(struct drm_device *dev, int pipe, unsigned int seq; int ret; - e = malloc(sizeof *e, DRM_MEM_VBLANK, M_WAITOK | M_ZERO); + e = malloc(sizeof *e, DRM_MEM_VBLANK, M_NOWAIT | M_ZERO); + if (e == NULL) { + ret = -ENOMEM; + goto err_put; + } e->pipe = pipe; e->base.pid = curproc->p_pid; @@ -988,7 +1133,7 @@ static int drm_queue_vblank_event(struct drm_device *dev, int pipe, mtx_lock(&dev->event_lock); if (file_priv->event_space < sizeof e->event) { - ret = EBUSY; + ret = -EBUSY; goto err_unlock; } @@ -1009,15 +1154,9 @@ static int drm_queue_vblank_event(struct drm_device *dev, int pipe, e->event.sequence = vblwait->request.sequence; if ((seq - vblwait->request.sequence) <= (1 << 23)) { - e->event.sequence = seq; - e->event.tv_sec = now.tv_sec; - e->event.tv_usec = now.tv_usec; drm_vblank_put(dev, pipe); - list_add_tail(&e->base.link, &e->base.file_priv->event_list); - drm_event_wakeup(&e->base); + send_vblank_event(dev, e, seq, &now); vblwait->reply.sequence = seq; - CTR3(KTR_DRM, "vblank_event_wakeup p1 %d %d %d", curproc->p_pid, - pipe, vblwait->request.sequence); } else { /* drm_handle_vblank_events will call drm_vblank_put */ list_add_tail(&e->base.link, &dev->vblank_event_list); @@ -1031,6 +1170,7 @@ static int drm_queue_vblank_event(struct drm_device *dev, int pipe, err_unlock: mtx_unlock(&dev->event_lock); free(e, DRM_MEM_VBLANK); +err_put: drm_vblank_put(dev, pipe); return ret; } @@ -1057,10 +1197,10 @@ int drm_wait_vblank(struct drm_device *dev, void *data, unsigned int flags, seq, crtc, high_crtc; if (/*(!drm_dev_to_irq(dev)) || */(!dev->irq_enabled)) - return (EINVAL); + return -EINVAL; if (vblwait->request.type & _DRM_VBLANK_SIGNAL) - return (EINVAL); + return -EINVAL; if (vblwait->request.type & ~(_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK | @@ -1069,7 +1209,7 @@ int drm_wait_vblank(struct drm_device *dev, void *data, vblwait->request.type, (_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK | _DRM_VBLANK_HIGH_CRTC_MASK)); - return (EINVAL); + return -EINVAL; } flags = vblwait->request.type & _DRM_VBLANK_FLAGS_MASK; @@ -1079,12 +1219,12 @@ int drm_wait_vblank(struct drm_device *dev, void *data, else crtc = flags & _DRM_VBLANK_SECONDARY ? 1 : 0; if (crtc >= dev->num_crtcs) - return (EINVAL); + return -EINVAL; ret = drm_vblank_get(dev, crtc); if (ret) { DRM_DEBUG("failed to acquire vblank counter, %d\n", ret); - return (ret); + return ret; } seq = drm_vblank_count(dev, crtc); @@ -1095,7 +1235,7 @@ int drm_wait_vblank(struct drm_device *dev, void *data, case _DRM_VBLANK_ABSOLUTE: break; default: - ret = (EINVAL); + ret = -EINVAL; goto done; } @@ -1111,6 +1251,8 @@ int drm_wait_vblank(struct drm_device *dev, void *data, vblwait->request.sequence = seq + 1; } + DRM_DEBUG("waiting on vblank count %d, crtc %d\n", + vblwait->request.sequence, crtc); dev->last_vblank_wait[crtc] = vblwait->request.sequence; mtx_lock(&dev->vblank_time_lock); while (((drm_vblank_count(dev, crtc) - vblwait->request.sequence) > @@ -1123,13 +1265,15 @@ int drm_wait_vblank(struct drm_device *dev, void *data, * application when crtc is disabled or irq * uninstalled anyway. */ - ret = msleep(&dev->_vblank_count[crtc], &dev->vblank_time_lock, + ret = -msleep(&dev->_vblank_count[crtc], &dev->vblank_time_lock, PCATCH, "drmvbl", 3 * hz); + if (ret == -ERESTART) + ret = -ERESTARTSYS; if (ret != 0) break; } mtx_unlock(&dev->vblank_time_lock); - if (ret != EINTR) { + if (ret != -EINTR) { struct timeval now; long reply_seq; @@ -1137,13 +1281,19 @@ int drm_wait_vblank(struct drm_device *dev, void *data, CTR5(KTR_DRM, "wait_vblank %d %d rt %x success %d %d", curproc->p_pid, crtc, vblwait->request.type, vblwait->request.sequence, reply_seq); + vblwait->reply.sequence = reply_seq; vblwait->reply.tval_sec = now.tv_sec; vblwait->reply.tval_usec = now.tv_usec; + + DRM_DEBUG("returning %d to client\n", + vblwait->reply.sequence); } else { CTR5(KTR_DRM, "wait_vblank %d %d rt %x error %d %d", curproc->p_pid, crtc, vblwait->request.type, ret, vblwait->request.sequence); + + DRM_DEBUG("vblank wait interrupted by signal\n"); } done: @@ -1151,14 +1301,13 @@ done: return ret; } -void drm_handle_vblank_events(struct drm_device *dev, int crtc) +static void drm_handle_vblank_events(struct drm_device *dev, int crtc) { struct drm_pending_vblank_event *e, *t; struct timeval now; unsigned int seq; seq = drm_vblank_count_and_time(dev, crtc, &now); - CTR2(KTR_DRM, "drm_handle_vblank_events %d %d", seq, crtc); mtx_lock(&dev->event_lock); @@ -1168,17 +1317,17 @@ void drm_handle_vblank_events(struct drm_device *dev, int crtc) if ((seq - e->event.sequence) > (1<<23)) continue; - e->event.sequence = seq; - e->event.tv_sec = now.tv_sec; - e->event.tv_usec = now.tv_usec; + DRM_DEBUG("vblank event on %d, current %d\n", + e->event.sequence, seq); + + list_del(&e->base.link); drm_vblank_put(dev, e->pipe); - list_move_tail(&e->base.link, &e->base.file_priv->event_list); - drm_event_wakeup(&e->base); - CTR3(KTR_DRM, "vblank_event_wakeup p2 %d %d %d", e->base.pid, - e->pipe, e->event.sequence); + send_vblank_event(dev, e, seq, &now); } mtx_unlock(&dev->event_lock); + + CTR2(KTR_DRM, "drm_handle_vblank_events %d %d", seq, crtc); } /** @@ -1192,7 +1341,7 @@ void drm_handle_vblank_events(struct drm_device *dev, int crtc) bool drm_handle_vblank(struct drm_device *dev, int crtc) { u32 vblcount; - int64_t diff_ns; + s64 diff_ns; struct timeval tvblank; if (!dev->num_crtcs) @@ -1238,15 +1387,18 @@ bool drm_handle_vblank(struct drm_device *dev, int crtc) /* Increment cooked vblank count. This also atomically commits * the timestamp computed above. */ + smp_mb__before_atomic_inc(); atomic_inc(&dev->_vblank_count[crtc]); + smp_mb__after_atomic_inc(); } else { DRM_DEBUG("crtc %d: Redundant vblirq ignored. diff_ns = %d\n", crtc, (int) diff_ns); } - wakeup(&dev->_vblank_count[crtc]); + DRM_WAKEUP(&dev->_vblank_count[crtc]); drm_handle_vblank_events(dev, crtc); mtx_unlock(&dev->vblank_time_lock); return true; } +EXPORT_SYMBOL(drm_handle_vblank); diff --git a/sys/dev/drm2/drm_lock.c b/sys/dev/drm2/drm_lock.c index 8ae230510d16..1bc681ca44d9 100644 --- a/sys/dev/drm2/drm_lock.c +++ b/sys/dev/drm2/drm_lock.c @@ -1,4 +1,14 @@ -/*- +/** + * \file drm_lock.c + * IOCTLs for locking + * + * \author Rickard E. (Rik) Faith <faith@valinux.com> + * \author Gareth Hughes <gareth@valinux.com> + */ + +/* + * Created: Tue Feb 2 08:37:54 1999 by faith@valinux.com + * * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. * All Rights Reserved. @@ -21,179 +31,346 @@ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: - * Rickard E. (Rik) Faith <faith@valinux.com> - * Gareth Hughes <gareth@valinux.com> - * */ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); -/** @file drm_lock.c - * Implementation of the ioctls and other support code for dealing with the - * hardware lock. - * - * The DRM hardware lock is a shared structure between the kernel and userland. - * - * On uncontended access where the new context was the last context, the - * client may take the lock without dropping down into the kernel, using atomic - * compare-and-set. +#include <dev/drm2/drmP.h> + +static int drm_notifier(void *priv); + +static int drm_lock_take(struct drm_lock_data *lock_data, unsigned int context); + +/** + * Lock ioctl. * - * If the client finds during compare-and-set that it was not the last owner - * of the lock, it calls the DRM lock ioctl, which may sleep waiting for the - * lock, and may have side-effects of kernel-managed context switching. + * \param inode device inode. + * \param file_priv DRM file private. + * \param cmd command. + * \param arg user argument, pointing to a drm_lock structure. + * \return zero on success or negative number on failure. * - * When the client releases the lock, if the lock is marked as being contended - * by another client, then the DRM unlock ioctl is called so that the - * contending client may be woken up. + * Add the current task to the lock wait queue, and attempt to take to lock. */ - -#include <dev/drm2/drmP.h> - int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_lock *lock = data; + struct drm_master *master = file_priv->master; int ret = 0; + ++file_priv->lock_count; + if (lock->context == DRM_KERNEL_CONTEXT) { DRM_ERROR("Process %d using kernel context %d\n", - DRM_CURRENTPID, lock->context); - return EINVAL; + DRM_CURRENTPID, lock->context); + return -EINVAL; } DRM_DEBUG("%d (pid %d) requests lock (0x%08x), flags = 0x%08x\n", - lock->context, DRM_CURRENTPID, dev->lock.hw_lock->lock, - lock->flags); + lock->context, DRM_CURRENTPID, + master->lock.hw_lock->lock, lock->flags); - if (drm_core_check_feature(dev, DRIVER_DMA_QUEUE) && - lock->context < 0) - return EINVAL; + mtx_lock(&master->lock.spinlock); + master->lock.user_waiters++; + mtx_unlock(&master->lock.spinlock); - DRM_LOCK(dev); for (;;) { - if (drm_lock_take(&dev->lock, lock->context)) { - dev->lock.file_priv = file_priv; - dev->lock.lock_time = jiffies; +#if defined(__linux__) + if (!master->lock.hw_lock) { + /* Device has been unregistered */ + send_sig(SIGTERM, current, 0); + ret = -EINTR; + break; + } +#endif + if (drm_lock_take(&master->lock, lock->context)) { + master->lock.file_priv = file_priv; + master->lock.lock_time = jiffies; atomic_inc(&dev->counts[_DRM_STAT_LOCKS]); - break; /* Got lock */ + break; /* Got lock */ } /* Contention */ - ret = DRM_LOCK_SLEEP(dev, &dev->lock.lock_queue, + DRM_UNLOCK_ASSERT(dev); + ret = -sx_sleep(&master->lock.lock_queue, &drm_global_mutex, PCATCH, "drmlk2", 0); + if (ret == -ERESTART) + ret = -ERESTARTSYS; if (ret != 0) break; } - DRM_UNLOCK(dev); - - if (ret == ERESTART) - DRM_DEBUG("restarting syscall\n"); - else - DRM_DEBUG("%d %s\n", lock->context, - ret ? "interrupted" : "has lock"); + mtx_lock(&master->lock.spinlock); + master->lock.user_waiters--; + mtx_unlock(&master->lock.spinlock); - if (ret != 0) - return ret; + DRM_DEBUG("%d %s\n", lock->context, + ret ? "interrupted" : "has lock"); + if (ret) return ret; - /* XXX: Add signal blocking here */ +#if defined(__linux__) + /* don't set the block all signals on the master process for now + * really probably not the correct answer but lets us debug xkb + * xserver for now */ + if (!file_priv->is_master) { + sigemptyset(&dev->sigmask); + sigaddset(&dev->sigmask, SIGSTOP); + sigaddset(&dev->sigmask, SIGTSTP); + sigaddset(&dev->sigmask, SIGTTIN); + sigaddset(&dev->sigmask, SIGTTOU); + dev->sigdata.context = lock->context; + dev->sigdata.lock = master->lock.hw_lock; + block_all_signals(drm_notifier, &dev->sigdata, &dev->sigmask); + } +#endif - if (dev->driver->dma_quiescent != NULL && - (lock->flags & _DRM_LOCK_QUIESCENT)) - dev->driver->dma_quiescent(dev); + if (dev->driver->dma_quiescent && (lock->flags & _DRM_LOCK_QUIESCENT)) + { + if (dev->driver->dma_quiescent(dev)) { + DRM_DEBUG("%d waiting for DMA quiescent\n", + lock->context); + return -EBUSY; + } + } return 0; } +/** + * Unlock ioctl. + * + * \param inode device inode. + * \param file_priv DRM file private. + * \param cmd command. + * \param arg user argument, pointing to a drm_lock structure. + * \return zero on success or negative number on failure. + * + * Transfer and free the lock. + */ int drm_unlock(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_lock *lock = data; - - DRM_DEBUG("%d (pid %d) requests unlock (0x%08x), flags = 0x%08x\n", - lock->context, DRM_CURRENTPID, dev->lock.hw_lock->lock, - lock->flags); + struct drm_master *master = file_priv->master; if (lock->context == DRM_KERNEL_CONTEXT) { DRM_ERROR("Process %d using kernel context %d\n", - DRM_CURRENTPID, lock->context); - return EINVAL; + DRM_CURRENTPID, lock->context); + return -EINVAL; } atomic_inc(&dev->counts[_DRM_STAT_UNLOCKS]); - DRM_LOCK(dev); - drm_lock_transfer(&dev->lock, DRM_KERNEL_CONTEXT); - - if (drm_lock_free(&dev->lock, DRM_KERNEL_CONTEXT)) { - DRM_ERROR("\n"); + if (drm_lock_free(&master->lock, lock->context)) { + /* FIXME: Should really bail out here. */ } - DRM_UNLOCK(dev); +#if defined(__linux__) + unblock_all_signals(); +#endif return 0; } -int drm_lock_take(struct drm_lock_data *lock_data, unsigned int context) +/** + * Take the heavyweight lock. + * + * \param lock lock pointer. + * \param context locking context. + * \return one if the lock is held, or zero otherwise. + * + * Attempt to mark the lock as held by the given context, via the \p cmpxchg instruction. + */ +static +int drm_lock_take(struct drm_lock_data *lock_data, + unsigned int context) { + unsigned int old, new, prev; volatile unsigned int *lock = &lock_data->hw_lock->lock; - unsigned int old, new; + mtx_lock(&lock_data->spinlock); do { old = *lock; if (old & _DRM_LOCK_HELD) new = old | _DRM_LOCK_CONT; - else - new = context | _DRM_LOCK_HELD; - } while (!atomic_cmpset_int(lock, old, new)); + else { + new = context | _DRM_LOCK_HELD | + ((lock_data->user_waiters + lock_data->kernel_waiters > 1) ? + _DRM_LOCK_CONT : 0); + } + prev = cmpxchg(lock, old, new); + } while (prev != old); + mtx_unlock(&lock_data->spinlock); if (_DRM_LOCKING_CONTEXT(old) == context) { if (old & _DRM_LOCK_HELD) { if (context != DRM_KERNEL_CONTEXT) { DRM_ERROR("%d holds heavyweight lock\n", - context); + context); } return 0; } } - if (new == (context | _DRM_LOCK_HELD)) { + + if ((_DRM_LOCKING_CONTEXT(new)) == context && (new & _DRM_LOCK_HELD)) { /* Have lock */ return 1; } return 0; } -/* This takes a lock forcibly and hands it to context. Should ONLY be used - inside *_unlock to give lock to kernel before calling *_dma_schedule. */ -int drm_lock_transfer(struct drm_lock_data *lock_data, unsigned int context) +/** + * This takes a lock forcibly and hands it to context. Should ONLY be used + * inside *_unlock to give lock to kernel before calling *_dma_schedule. + * + * \param dev DRM device. + * \param lock lock pointer. + * \param context locking context. + * \return always one. + * + * Resets the lock file pointer. + * Marks the lock as held by the given context, via the \p cmpxchg instruction. + */ +static int drm_lock_transfer(struct drm_lock_data *lock_data, + unsigned int context) { + unsigned int old, new, prev; volatile unsigned int *lock = &lock_data->hw_lock->lock; - unsigned int old, new; lock_data->file_priv = NULL; do { old = *lock; new = context | _DRM_LOCK_HELD; - } while (!atomic_cmpset_int(lock, old, new)); - + prev = cmpxchg(lock, old, new); + } while (prev != old); return 1; } +/** + * Free lock. + * + * \param dev DRM device. + * \param lock lock. + * \param context context. + * + * Resets the lock file pointer. + * Marks the lock as not held, via the \p cmpxchg instruction. Wakes any task + * waiting on the lock queue. + */ int drm_lock_free(struct drm_lock_data *lock_data, unsigned int context) { + unsigned int old, new, prev; volatile unsigned int *lock = &lock_data->hw_lock->lock; - unsigned int old, new; - lock_data->file_priv = NULL; + mtx_lock(&lock_data->spinlock); + if (lock_data->kernel_waiters != 0) { + drm_lock_transfer(lock_data, 0); + lock_data->idle_has_lock = 1; + mtx_unlock(&lock_data->spinlock); + return 1; + } + mtx_unlock(&lock_data->spinlock); + do { old = *lock; - new = 0; - } while (!atomic_cmpset_int(lock, old, new)); + new = _DRM_LOCKING_CONTEXT(old); + prev = cmpxchg(lock, old, new); + } while (prev != old); if (_DRM_LOCK_IS_HELD(old) && _DRM_LOCKING_CONTEXT(old) != context) { DRM_ERROR("%d freed heavyweight lock held by %d\n", - context, _DRM_LOCKING_CONTEXT(old)); + context, _DRM_LOCKING_CONTEXT(old)); return 1; } - DRM_WAKEUP_INT((void *)&lock_data->lock_queue); + wake_up_interruptible(&lock_data->lock_queue); return 0; } + +/** + * If we get here, it means that the process has called DRM_IOCTL_LOCK + * without calling DRM_IOCTL_UNLOCK. + * + * If the lock is not held, then let the signal proceed as usual. If the lock + * is held, then set the contended flag and keep the signal blocked. + * + * \param priv pointer to a drm_sigdata structure. + * \return one if the signal should be delivered normally, or zero if the + * signal should be blocked. + */ +static int drm_notifier(void *priv) +{ + struct drm_sigdata *s = (struct drm_sigdata *) priv; + unsigned int old, new, prev; + + /* Allow signal delivery if lock isn't held */ + if (!s->lock || !_DRM_LOCK_IS_HELD(s->lock->lock) + || _DRM_LOCKING_CONTEXT(s->lock->lock) != s->context) + return 1; + + /* Otherwise, set flag to force call to + drmUnlock */ + do { + old = s->lock->lock; + new = old | _DRM_LOCK_CONT; + prev = cmpxchg(&s->lock->lock, old, new); + } while (prev != old); + return 0; +} + +/** + * This function returns immediately and takes the hw lock + * with the kernel context if it is free, otherwise it gets the highest priority when and if + * it is eventually released. + * + * This guarantees that the kernel will _eventually_ have the lock _unless_ it is held + * by a blocked process. (In the latter case an explicit wait for the hardware lock would cause + * a deadlock, which is why the "idlelock" was invented). + * + * This should be sufficient to wait for GPU idle without + * having to worry about starvation. + */ + +void drm_idlelock_take(struct drm_lock_data *lock_data) +{ + int ret; + + mtx_lock(&lock_data->spinlock); + lock_data->kernel_waiters++; + if (!lock_data->idle_has_lock) { + + mtx_unlock(&lock_data->spinlock); + ret = drm_lock_take(lock_data, DRM_KERNEL_CONTEXT); + mtx_lock(&lock_data->spinlock); + + if (ret == 1) + lock_data->idle_has_lock = 1; + } + mtx_unlock(&lock_data->spinlock); +} +EXPORT_SYMBOL(drm_idlelock_take); + +void drm_idlelock_release(struct drm_lock_data *lock_data) +{ + unsigned int old, prev; + volatile unsigned int *lock = &lock_data->hw_lock->lock; + + mtx_lock(&lock_data->spinlock); + if (--lock_data->kernel_waiters == 0) { + if (lock_data->idle_has_lock) { + do { + old = *lock; + prev = cmpxchg(lock, old, DRM_KERNEL_CONTEXT); + } while (prev != old); + wake_up_interruptible(&lock_data->lock_queue); + lock_data->idle_has_lock = 0; + } + } + mtx_unlock(&lock_data->spinlock); +} +EXPORT_SYMBOL(drm_idlelock_release); + +int drm_i_have_hw_lock(struct drm_device *dev, struct drm_file *file_priv) +{ + struct drm_master *master = file_priv->master; + return (file_priv->lock_count && master->lock.hw_lock && + _DRM_LOCK_IS_HELD(master->lock.hw_lock->lock) && + master->lock.file_priv == file_priv); +} diff --git a/sys/dev/drm2/drm_memory.c b/sys/dev/drm2/drm_memory.c index af43a89bbfd4..a25e5a288ee1 100644 --- a/sys/dev/drm2/drm_memory.c +++ b/sys/dev/drm2/drm_memory.c @@ -1,11 +1,17 @@ -/*- - *Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. - * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. - * Copyright (c) 2011 The FreeBSD Foundation - * All rights reserved. +/** + * \file drm_memory.c + * Memory management wrappers for DRM + * + * \author Rickard E. (Rik) Faith <faith@valinux.com> + * \author Gareth Hughes <gareth@valinux.com> + */ + +/* + * Created: Thu Feb 4 14:00:34 1999 by faith@valinux.com * - * Portions of this software were developed by Konstantin Belousov - * under sponsorship from the FreeBSD Foundation. + * 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"), @@ -25,111 +31,104 @@ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: - * Rickard E. (Rik) Faith <faith@valinux.com> - * Gareth Hughes <gareth@valinux.com> - * */ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); -/** @file drm_memory.c - * Wrappers for kernel memory allocation routines, and MTRR management support. - * - * This file previously implemented a memory consumption tracking system using - * the "area" argument for various different types of allocations, but that - * has been stripped out for now. - */ - #include <dev/drm2/drmP.h> -MALLOC_DEFINE(DRM_MEM_DMA, "drm_dma", "DRM DMA Data Structures"); -MALLOC_DEFINE(DRM_MEM_SAREA, "drm_sarea", "DRM SAREA Data Structures"); -MALLOC_DEFINE(DRM_MEM_DRIVER, "drm_driver", "DRM DRIVER Data Structures"); -MALLOC_DEFINE(DRM_MEM_MAGIC, "drm_magic", "DRM MAGIC Data Structures"); -MALLOC_DEFINE(DRM_MEM_IOCTLS, "drm_ioctls", "DRM IOCTL Data Structures"); -MALLOC_DEFINE(DRM_MEM_MAPS, "drm_maps", "DRM MAP Data Structures"); -MALLOC_DEFINE(DRM_MEM_BUFS, "drm_bufs", "DRM BUFFER Data Structures"); -MALLOC_DEFINE(DRM_MEM_SEGS, "drm_segs", "DRM SEGMENTS Data Structures"); -MALLOC_DEFINE(DRM_MEM_PAGES, "drm_pages", "DRM PAGES Data Structures"); -MALLOC_DEFINE(DRM_MEM_FILES, "drm_files", "DRM FILE Data Structures"); -MALLOC_DEFINE(DRM_MEM_QUEUES, "drm_queues", "DRM QUEUE Data Structures"); -MALLOC_DEFINE(DRM_MEM_CMDS, "drm_cmds", "DRM COMMAND Data Structures"); -MALLOC_DEFINE(DRM_MEM_MAPPINGS, "drm_mapping", "DRM MAPPING Data Structures"); -MALLOC_DEFINE(DRM_MEM_BUFLISTS, "drm_buflists", "DRM BUFLISTS Data Structures"); -MALLOC_DEFINE(DRM_MEM_AGPLISTS, "drm_agplists", "DRM AGPLISTS Data Structures"); -MALLOC_DEFINE(DRM_MEM_CTXBITMAP, "drm_ctxbitmap", - "DRM CTXBITMAP Data Structures"); -MALLOC_DEFINE(DRM_MEM_SGLISTS, "drm_sglists", "DRM SGLISTS Data Structures"); -MALLOC_DEFINE(DRM_MEM_DRAWABLE, "drm_drawable", "DRM DRAWABLE Data Structures"); -MALLOC_DEFINE(DRM_MEM_MM, "drm_sman", "DRM MEMORY MANAGER Data Structures"); -MALLOC_DEFINE(DRM_MEM_HASHTAB, "drm_hashtab", "DRM HASHTABLE Data Structures"); -MALLOC_DEFINE(DRM_MEM_KMS, "drm_kms", "DRM KMS Data Structures"); - -void drm_mem_init(void) +#if __OS_HAS_AGP +static void *agp_remap(unsigned long offset, unsigned long size, + struct drm_device * dev) { + /* + * FIXME Linux<->FreeBSD: Not implemented. This is never called + * on FreeBSD anyway, because drm_agp_mem->cant_use_aperture is + * set to 0. + */ + return NULL; } -void drm_mem_uninit(void) -{ -} +#define vunmap(handle) -void *drm_ioremap_wc(struct drm_device *dev, drm_local_map_t *map) +/** Wrapper around agp_free_memory() */ +void drm_free_agp(DRM_AGP_MEM * handle, int pages) { - return pmap_mapdev_attr(map->offset, map->size, VM_MEMATTR_WRITE_COMBINING); + device_t agpdev; + + agpdev = agp_find_device(); + if (!agpdev || !handle) + return; + + agp_free_memory(agpdev, handle); } +EXPORT_SYMBOL(drm_free_agp); -void *drm_ioremap(struct drm_device *dev, drm_local_map_t *map) +/** Wrapper around agp_bind_memory() */ +int drm_bind_agp(DRM_AGP_MEM * handle, unsigned int start) { - return pmap_mapdev(map->offset, map->size); + device_t agpdev; + + agpdev = agp_find_device(); + if (!agpdev || !handle) + return -EINVAL; + + return -agp_bind_memory(agpdev, handle, start * PAGE_SIZE); } -void drm_ioremapfree(drm_local_map_t *map) +/** Wrapper around agp_unbind_memory() */ +int drm_unbind_agp(DRM_AGP_MEM * handle) { - pmap_unmapdev((vm_offset_t) map->virtual, map->size); + device_t agpdev; + + agpdev = agp_find_device(); + if (!agpdev || !handle) + return -EINVAL; + + return -agp_unbind_memory(agpdev, handle); } +EXPORT_SYMBOL(drm_unbind_agp); -int -drm_mtrr_add(unsigned long offset, size_t size, int flags) +#else /* __OS_HAS_AGP */ +static inline void *agp_remap(unsigned long offset, unsigned long size, + struct drm_device * dev) { - int act; - struct mem_range_desc mrdesc; - - mrdesc.mr_base = offset; - mrdesc.mr_len = size; - mrdesc.mr_flags = flags; - act = MEMRANGE_SET_UPDATE; - strlcpy(mrdesc.mr_owner, "drm", sizeof(mrdesc.mr_owner)); - return mem_range_attr_set(&mrdesc, &act); + return NULL; } -int -drm_mtrr_del(int __unused handle, unsigned long offset, size_t size, int flags) +#endif /* agp */ + +void drm_core_ioremap(struct drm_local_map *map, struct drm_device *dev) { - int act; - struct mem_range_desc mrdesc; - - mrdesc.mr_base = offset; - mrdesc.mr_len = size; - mrdesc.mr_flags = flags; - act = MEMRANGE_SET_REMOVE; - strlcpy(mrdesc.mr_owner, "drm", sizeof(mrdesc.mr_owner)); - return mem_range_attr_set(&mrdesc, &act); + if (drm_core_has_AGP(dev) && + dev->agp && dev->agp->cant_use_aperture && map->type == _DRM_AGP) + map->handle = agp_remap(map->offset, map->size, dev); + else + map->handle = pmap_mapdev(map->offset, map->size); } +EXPORT_SYMBOL(drm_core_ioremap); -void -drm_clflush_pages(vm_page_t *pages, unsigned long num_pages) +void drm_core_ioremap_wc(struct drm_local_map *map, struct drm_device *dev) { - - pmap_invalidate_cache_pages(pages, num_pages); + if (drm_core_has_AGP(dev) && + dev->agp && dev->agp->cant_use_aperture && map->type == _DRM_AGP) + map->handle = agp_remap(map->offset, map->size, dev); + else + map->handle = pmap_mapdev_attr(map->offset, map->size, + VM_MEMATTR_WRITE_COMBINING); } +EXPORT_SYMBOL(drm_core_ioremap_wc); -void -drm_clflush_virt_range(char *addr, unsigned long length) +void drm_core_ioremapfree(struct drm_local_map *map, struct drm_device *dev) { - - pmap_invalidate_cache_range((vm_offset_t)addr, - (vm_offset_t)addr + length, TRUE); + if (!map->handle || !map->size) + return; + + if (drm_core_has_AGP(dev) && + dev->agp && dev->agp->cant_use_aperture && map->type == _DRM_AGP) + vunmap(map->handle); + else + pmap_unmapdev((vm_offset_t)map->handle, map->size); } +EXPORT_SYMBOL(drm_core_ioremapfree); diff --git a/sys/dev/drm2/drm_mm.c b/sys/dev/drm2/drm_mm.c index 3617b0552715..6c11ff75ff8b 100644 --- a/sys/dev/drm2/drm_mm.c +++ b/sys/dev/drm2/drm_mm.c @@ -53,8 +53,7 @@ static struct drm_mm_node *drm_mm_kmalloc(struct drm_mm *mm, int atomic) { struct drm_mm_node *child; - child = malloc(sizeof(*child), DRM_MEM_MM, M_ZERO | - (atomic ? M_NOWAIT : M_WAITOK)); + child = malloc(sizeof(*child), DRM_MEM_MM, M_NOWAIT | M_ZERO); if (unlikely(child == NULL)) { mtx_lock(&mm->unused_lock); @@ -72,6 +71,11 @@ static struct drm_mm_node *drm_mm_kmalloc(struct drm_mm *mm, int atomic) return child; } +/* drm_mm_pre_get() - pre allocate drm_mm_node structure + * drm_mm: memory manager struct we are pre-allocating for + * + * Returns 0 on success or -ENOMEM if allocation fails. + */ int drm_mm_pre_get(struct drm_mm *mm) { struct drm_mm_node *node; @@ -79,7 +83,7 @@ int drm_mm_pre_get(struct drm_mm *mm) mtx_lock(&mm->unused_lock); while (mm->num_unused < MM_UNUSED_TARGET) { mtx_unlock(&mm->unused_lock); - node = malloc(sizeof(*node), DRM_MEM_MM, M_WAITOK); + node = malloc(sizeof(*node), DRM_MEM_MM, M_NOWAIT | M_ZERO); mtx_lock(&mm->unused_lock); if (unlikely(node == NULL)) { @@ -93,6 +97,7 @@ int drm_mm_pre_get(struct drm_mm *mm) mtx_unlock(&mm->unused_lock); return 0; } +EXPORT_SYMBOL(drm_mm_pre_get); static inline unsigned long drm_mm_hole_node_start(struct drm_mm_node *hole_node) { @@ -110,45 +115,53 @@ static inline unsigned long drm_mm_hole_node_end(struct drm_mm_node *hole_node) static void drm_mm_insert_helper(struct drm_mm_node *hole_node, struct drm_mm_node *node, - unsigned long size, unsigned alignment) + unsigned long size, unsigned alignment, + unsigned long color) { struct drm_mm *mm = hole_node->mm; - unsigned long tmp = 0, wasted = 0; unsigned long hole_start = drm_mm_hole_node_start(hole_node); unsigned long hole_end = drm_mm_hole_node_end(hole_node); + unsigned long adj_start = hole_start; + unsigned long adj_end = hole_end; + + BUG_ON(!hole_node->hole_follows || node->allocated); - KASSERT(hole_node->hole_follows && !node->allocated, ("hole_node")); + if (mm->color_adjust) + mm->color_adjust(hole_node, color, &adj_start, &adj_end); - if (alignment) - tmp = hole_start % alignment; + if (alignment) { + unsigned tmp = adj_start % alignment; + if (tmp) + adj_start += alignment - tmp; + } - if (!tmp) { + if (adj_start == hole_start) { hole_node->hole_follows = 0; - list_del_init(&hole_node->hole_stack); - } else - wasted = alignment - tmp; + list_del(&hole_node->hole_stack); + } - node->start = hole_start + wasted; + node->start = adj_start; node->size = size; node->mm = mm; + node->color = color; node->allocated = 1; INIT_LIST_HEAD(&node->hole_stack); list_add(&node->node_list, &hole_node->node_list); - KASSERT(node->start + node->size <= hole_end, ("hole pos")); + BUG_ON(node->start + node->size > adj_end); + node->hole_follows = 0; if (node->start + node->size < hole_end) { list_add(&node->hole_stack, &mm->hole_stack); node->hole_follows = 1; - } else { - node->hole_follows = 0; } } struct drm_mm_node *drm_mm_get_block_generic(struct drm_mm_node *hole_node, unsigned long size, unsigned alignment, + unsigned long color, int atomic) { struct drm_mm_node *node; @@ -157,72 +170,96 @@ struct drm_mm_node *drm_mm_get_block_generic(struct drm_mm_node *hole_node, if (unlikely(node == NULL)) return NULL; - drm_mm_insert_helper(hole_node, node, size, alignment); + drm_mm_insert_helper(hole_node, node, size, alignment, color); return node; } +EXPORT_SYMBOL(drm_mm_get_block_generic); -int drm_mm_insert_node(struct drm_mm *mm, struct drm_mm_node *node, - unsigned long size, unsigned alignment) +/** + * Search for free space and insert a preallocated memory node. Returns + * -ENOSPC if no suitable free area is available. The preallocated memory node + * must be cleared. + */ +int drm_mm_insert_node_generic(struct drm_mm *mm, struct drm_mm_node *node, + unsigned long size, unsigned alignment, + unsigned long color) { struct drm_mm_node *hole_node; - hole_node = drm_mm_search_free(mm, size, alignment, 0); + hole_node = drm_mm_search_free_generic(mm, size, alignment, + color, 0); if (!hole_node) return -ENOSPC; - drm_mm_insert_helper(hole_node, node, size, alignment); - + drm_mm_insert_helper(hole_node, node, size, alignment, color); return 0; } +EXPORT_SYMBOL(drm_mm_insert_node_generic); + +int drm_mm_insert_node(struct drm_mm *mm, struct drm_mm_node *node, + unsigned long size, unsigned alignment) +{ + return drm_mm_insert_node_generic(mm, node, size, alignment, 0); +} +EXPORT_SYMBOL(drm_mm_insert_node); static void drm_mm_insert_helper_range(struct drm_mm_node *hole_node, struct drm_mm_node *node, unsigned long size, unsigned alignment, + unsigned long color, unsigned long start, unsigned long end) { struct drm_mm *mm = hole_node->mm; - unsigned long tmp = 0, wasted = 0; unsigned long hole_start = drm_mm_hole_node_start(hole_node); unsigned long hole_end = drm_mm_hole_node_end(hole_node); + unsigned long adj_start = hole_start; + unsigned long adj_end = hole_end; - KASSERT(hole_node->hole_follows && !node->allocated, ("hole_node")); + BUG_ON(!hole_node->hole_follows || node->allocated); - if (hole_start < start) - wasted += start - hole_start; - if (alignment) - tmp = (hole_start + wasted) % alignment; + if (adj_start < start) + adj_start = start; + if (adj_end > end) + adj_end = end; - if (tmp) - wasted += alignment - tmp; + if (mm->color_adjust) + mm->color_adjust(hole_node, color, &adj_start, &adj_end); + + if (alignment) { + unsigned tmp = adj_start % alignment; + if (tmp) + adj_start += alignment - tmp; + } - if (!wasted) { + if (adj_start == hole_start) { hole_node->hole_follows = 0; - list_del_init(&hole_node->hole_stack); + list_del(&hole_node->hole_stack); } - node->start = hole_start + wasted; + node->start = adj_start; node->size = size; node->mm = mm; + node->color = color; node->allocated = 1; INIT_LIST_HEAD(&node->hole_stack); list_add(&node->node_list, &hole_node->node_list); - KASSERT(node->start + node->size <= hole_end, ("hole_end")); - KASSERT(node->start + node->size <= end, ("end")); + BUG_ON(node->start + node->size > adj_end); + BUG_ON(node->start + node->size > end); + node->hole_follows = 0; if (node->start + node->size < hole_end) { list_add(&node->hole_stack, &mm->hole_stack); node->hole_follows = 1; - } else { - node->hole_follows = 0; } } struct drm_mm_node *drm_mm_get_block_range_generic(struct drm_mm_node *hole_node, unsigned long size, unsigned alignment, + unsigned long color, unsigned long start, unsigned long end, int atomic) @@ -233,47 +270,66 @@ struct drm_mm_node *drm_mm_get_block_range_generic(struct drm_mm_node *hole_node if (unlikely(node == NULL)) return NULL; - drm_mm_insert_helper_range(hole_node, node, size, alignment, + drm_mm_insert_helper_range(hole_node, node, size, alignment, color, start, end); return node; } +EXPORT_SYMBOL(drm_mm_get_block_range_generic); -int drm_mm_insert_node_in_range(struct drm_mm *mm, struct drm_mm_node *node, - unsigned long size, unsigned alignment, - unsigned long start, unsigned long end) +/** + * Search for free space and insert a preallocated memory node. Returns + * -ENOSPC if no suitable free area is available. This is for range + * restricted allocations. The preallocated memory node must be cleared. + */ +int drm_mm_insert_node_in_range_generic(struct drm_mm *mm, struct drm_mm_node *node, + unsigned long size, unsigned alignment, unsigned long color, + unsigned long start, unsigned long end) { struct drm_mm_node *hole_node; - hole_node = drm_mm_search_free_in_range(mm, size, alignment, - start, end, 0); + hole_node = drm_mm_search_free_in_range_generic(mm, + size, alignment, color, + start, end, 0); if (!hole_node) return -ENOSPC; - drm_mm_insert_helper_range(hole_node, node, size, alignment, + drm_mm_insert_helper_range(hole_node, node, + size, alignment, color, start, end); - return 0; } +EXPORT_SYMBOL(drm_mm_insert_node_in_range_generic); +int drm_mm_insert_node_in_range(struct drm_mm *mm, struct drm_mm_node *node, + unsigned long size, unsigned alignment, + unsigned long start, unsigned long end) +{ + return drm_mm_insert_node_in_range_generic(mm, node, size, alignment, 0, start, end); +} +EXPORT_SYMBOL(drm_mm_insert_node_in_range); + +/** + * Remove a memory node from the allocator. + */ void drm_mm_remove_node(struct drm_mm_node *node) { struct drm_mm *mm = node->mm; struct drm_mm_node *prev_node; - KASSERT(!node->scanned_block && !node->scanned_prev_free - && !node->scanned_next_free, ("node")); + BUG_ON(node->scanned_block || node->scanned_prev_free + || node->scanned_next_free); prev_node = list_entry(node->node_list.prev, struct drm_mm_node, node_list); if (node->hole_follows) { - KASSERT(drm_mm_hole_node_start(node) - != drm_mm_hole_node_end(node), ("hole_follows")); + BUG_ON(drm_mm_hole_node_start(node) + == drm_mm_hole_node_end(node)); list_del(&node->hole_stack); } else - KASSERT(drm_mm_hole_node_start(node) - == drm_mm_hole_node_end(node), ("!hole_follows")); + BUG_ON(drm_mm_hole_node_start(node) + != drm_mm_hole_node_end(node)); if (!prev_node->hole_follows) { prev_node->hole_follows = 1; @@ -284,14 +340,16 @@ void drm_mm_remove_node(struct drm_mm_node *node) list_del(&node->node_list); node->allocated = 0; } +EXPORT_SYMBOL(drm_mm_remove_node); /* - * Put a block. Merge with the previous and / or next block if they are free. - * Otherwise add to the free stack. + * Remove a memory node from the allocator and free the allocated struct + * drm_mm_node. Only to be used on a struct drm_mm_node obtained by one of the + * drm_mm_get_block functions. */ - void drm_mm_put_block(struct drm_mm_node *node) { + struct drm_mm *mm = node->mm; drm_mm_remove_node(node); @@ -304,45 +362,50 @@ void drm_mm_put_block(struct drm_mm_node *node) free(node, DRM_MEM_MM); mtx_unlock(&mm->unused_lock); } +EXPORT_SYMBOL(drm_mm_put_block); static int check_free_hole(unsigned long start, unsigned long end, unsigned long size, unsigned alignment) { - unsigned wasted = 0; - if (end - start < size) return 0; if (alignment) { unsigned tmp = start % alignment; if (tmp) - wasted = alignment - tmp; - } - - if (end >= start + size + wasted) { - return 1; + start += alignment - tmp; } - return 0; + return end >= start + size; } - -struct drm_mm_node *drm_mm_search_free(const struct drm_mm *mm, - unsigned long size, - unsigned alignment, int best_match) +struct drm_mm_node *drm_mm_search_free_generic(const struct drm_mm *mm, + unsigned long size, + unsigned alignment, + unsigned long color, + bool best_match) { struct drm_mm_node *entry; struct drm_mm_node *best; unsigned long best_size; + BUG_ON(mm->scanned_blocks); + best = NULL; best_size = ~0UL; list_for_each_entry(entry, &mm->hole_stack, hole_stack) { - KASSERT(entry->hole_follows, ("hole_follows")); - if (!check_free_hole(drm_mm_hole_node_start(entry), - drm_mm_hole_node_end(entry), - size, alignment)) + unsigned long adj_start = drm_mm_hole_node_start(entry); + unsigned long adj_end = drm_mm_hole_node_end(entry); + + if (mm->color_adjust) { + mm->color_adjust(entry, color, &adj_start, &adj_end); + if (adj_end <= adj_start) + continue; + } + + BUG_ON(!entry->hole_follows); + if (!check_free_hole(adj_start, adj_end, size, alignment)) continue; if (!best_match) @@ -356,19 +419,21 @@ struct drm_mm_node *drm_mm_search_free(const struct drm_mm *mm, return best; } - -struct drm_mm_node *drm_mm_search_free_in_range(const struct drm_mm *mm, - unsigned long size, - unsigned alignment, - unsigned long start, - unsigned long end, - int best_match) +EXPORT_SYMBOL(drm_mm_search_free_generic); + +struct drm_mm_node *drm_mm_search_free_in_range_generic(const struct drm_mm *mm, + unsigned long size, + unsigned alignment, + unsigned long color, + unsigned long start, + unsigned long end, + bool best_match) { struct drm_mm_node *entry; struct drm_mm_node *best; unsigned long best_size; - KASSERT(!mm->scanned_blocks, ("scanned")); + BUG_ON(mm->scanned_blocks); best = NULL; best_size = ~0UL; @@ -379,7 +444,14 @@ struct drm_mm_node *drm_mm_search_free_in_range(const struct drm_mm *mm, unsigned long adj_end = drm_mm_hole_node_end(entry) > end ? end : drm_mm_hole_node_end(entry); - KASSERT(entry->hole_follows, ("hole_follows")); + BUG_ON(!entry->hole_follows); + + if (mm->color_adjust) { + mm->color_adjust(entry, color, &adj_start, &adj_end); + if (adj_end <= adj_start) + continue; + } + if (!check_free_hole(adj_start, adj_end, size, alignment)) continue; @@ -394,7 +466,11 @@ struct drm_mm_node *drm_mm_search_free_in_range(const struct drm_mm *mm, return best; } +EXPORT_SYMBOL(drm_mm_search_free_in_range_generic); +/** + * Moves an allocation. To be used with embedded struct drm_mm_node. + */ void drm_mm_replace_node(struct drm_mm_node *old, struct drm_mm_node *new) { list_replace(&old->node_list, &new->node_list); @@ -403,50 +479,83 @@ void drm_mm_replace_node(struct drm_mm_node *old, struct drm_mm_node *new) new->mm = old->mm; new->start = old->start; new->size = old->size; + new->color = old->color; old->allocated = 0; new->allocated = 1; } +EXPORT_SYMBOL(drm_mm_replace_node); -void drm_mm_init_scan(struct drm_mm *mm, unsigned long size, - unsigned alignment) +/** + * Initializa lru scanning. + * + * This simply sets up the scanning routines with the parameters for the desired + * hole. + * + * Warning: As long as the scan list is non-empty, no other operations than + * adding/removing nodes to/from the scan list are allowed. + */ +void drm_mm_init_scan(struct drm_mm *mm, + unsigned long size, + unsigned alignment, + unsigned long color) { + mm->scan_color = color; mm->scan_alignment = alignment; mm->scan_size = size; mm->scanned_blocks = 0; mm->scan_hit_start = 0; - mm->scan_hit_size = 0; + mm->scan_hit_end = 0; mm->scan_check_range = 0; mm->prev_scanned_node = NULL; } +EXPORT_SYMBOL(drm_mm_init_scan); -void drm_mm_init_scan_with_range(struct drm_mm *mm, unsigned long size, +/** + * Initializa lru scanning. + * + * This simply sets up the scanning routines with the parameters for the desired + * hole. This version is for range-restricted scans. + * + * Warning: As long as the scan list is non-empty, no other operations than + * adding/removing nodes to/from the scan list are allowed. + */ +void drm_mm_init_scan_with_range(struct drm_mm *mm, + unsigned long size, unsigned alignment, + unsigned long color, unsigned long start, unsigned long end) { + mm->scan_color = color; mm->scan_alignment = alignment; mm->scan_size = size; mm->scanned_blocks = 0; mm->scan_hit_start = 0; - mm->scan_hit_size = 0; + mm->scan_hit_end = 0; mm->scan_start = start; mm->scan_end = end; mm->scan_check_range = 1; mm->prev_scanned_node = NULL; } +EXPORT_SYMBOL(drm_mm_init_scan_with_range); +/** + * Add a node to the scan list that might be freed to make space for the desired + * hole. + * + * Returns non-zero, if a hole has been found, zero otherwise. + */ int drm_mm_scan_add_block(struct drm_mm_node *node) { struct drm_mm *mm = node->mm; struct drm_mm_node *prev_node; unsigned long hole_start, hole_end; - unsigned long adj_start; - unsigned long adj_end; + unsigned long adj_start, adj_end; mm->scanned_blocks++; - KASSERT(!node->scanned_block, ("node->scanned_block")); + BUG_ON(node->scanned_block); node->scanned_block = 1; prev_node = list_entry(node->node_list.prev, struct drm_mm_node, @@ -459,29 +568,45 @@ int drm_mm_scan_add_block(struct drm_mm_node *node) node->node_list.next = &mm->prev_scanned_node->node_list; mm->prev_scanned_node = node; - hole_start = drm_mm_hole_node_start(prev_node); - hole_end = drm_mm_hole_node_end(prev_node); + adj_start = hole_start = drm_mm_hole_node_start(prev_node); + adj_end = hole_end = drm_mm_hole_node_end(prev_node); + if (mm->scan_check_range) { - adj_start = hole_start < mm->scan_start ? - mm->scan_start : hole_start; - adj_end = hole_end > mm->scan_end ? - mm->scan_end : hole_end; - } else { - adj_start = hole_start; - adj_end = hole_end; + if (adj_start < mm->scan_start) + adj_start = mm->scan_start; + if (adj_end > mm->scan_end) + adj_end = mm->scan_end; } - if (check_free_hole(adj_start , adj_end, + if (mm->color_adjust) + mm->color_adjust(prev_node, mm->scan_color, + &adj_start, &adj_end); + + if (check_free_hole(adj_start, adj_end, mm->scan_size, mm->scan_alignment)) { mm->scan_hit_start = hole_start; - mm->scan_hit_size = hole_end; - + mm->scan_hit_end = hole_end; return 1; } return 0; } +EXPORT_SYMBOL(drm_mm_scan_add_block); +/** + * Remove a node from the scan list. + * + * Nodes _must_ be removed in the exact same order from the scan list as they + * have been added, otherwise the internal state of the memory manager will be + * corrupted. + * + * When the scan list is empty, the selected memory nodes can be freed. An + * immediately following drm_mm_search_free with best_match = 0 will then return + * the just freed block (because its at the top of the free_stack list). + * + * Returns one if this block should be evicted, zero otherwise. Will always + * return zero when no hole has been found. + */ int drm_mm_scan_remove_block(struct drm_mm_node *node) { struct drm_mm *mm = node->mm; @@ -489,27 +614,19 @@ int drm_mm_scan_remove_block(struct drm_mm_node *node) mm->scanned_blocks--; - KASSERT(node->scanned_block, ("scanned_block")); + BUG_ON(!node->scanned_block); node->scanned_block = 0; prev_node = list_entry(node->node_list.prev, struct drm_mm_node, node_list); prev_node->hole_follows = node->scanned_preceeds_hole; - INIT_LIST_HEAD(&node->node_list); list_add(&node->node_list, &prev_node->node_list); - /* Only need to check for containement because start&size for the - * complete resulting free block (not just the desired part) is - * stored. */ - if (node->start >= mm->scan_hit_start && - node->start + node->size - <= mm->scan_hit_start + mm->scan_hit_size) { - return 1; - } - - return 0; + return (drm_mm_hole_node_end(node) > mm->scan_hit_start && + node->start < mm->scan_hit_end); } +EXPORT_SYMBOL(drm_mm_scan_remove_block); int drm_mm_clean(struct drm_mm * mm) { @@ -517,6 +634,7 @@ int drm_mm_clean(struct drm_mm * mm) return (head->next->next == head); } +EXPORT_SYMBOL(drm_mm_clean); int drm_mm_init(struct drm_mm * mm, unsigned long start, unsigned long size) { @@ -526,6 +644,7 @@ int drm_mm_init(struct drm_mm * mm, unsigned long start, unsigned long size) mm->scanned_blocks = 0; mtx_init(&mm->unused_lock, "drm_unused", NULL, MTX_DEF); + /* Clever trick to avoid a special case in the free hole tracking. */ INIT_LIST_HEAD(&mm->head_node.node_list); INIT_LIST_HEAD(&mm->head_node.hole_stack); mm->head_node.hole_follows = 1; @@ -537,8 +656,11 @@ int drm_mm_init(struct drm_mm * mm, unsigned long start, unsigned long size) mm->head_node.size = start - mm->head_node.start; list_add_tail(&mm->head_node.hole_stack, &mm->hole_stack); + mm->color_adjust = NULL; + return 0; } +EXPORT_SYMBOL(drm_mm_init); void drm_mm_takedown(struct drm_mm * mm) { @@ -557,10 +679,9 @@ void drm_mm_takedown(struct drm_mm * mm) } mtx_unlock(&mm->unused_lock); - mtx_destroy(&mm->unused_lock); - - KASSERT(mm->num_unused == 0, ("num_unused != 0")); + BUG_ON(mm->num_unused != 0); } +EXPORT_SYMBOL(drm_mm_takedown); void drm_mm_debug_table(struct drm_mm *mm, const char *prefix) { @@ -572,13 +693,13 @@ void drm_mm_debug_table(struct drm_mm *mm, const char *prefix) hole_end = drm_mm_hole_node_end(&mm->head_node); hole_size = hole_end - hole_start; if (hole_size) - printf("%s 0x%08lx-0x%08lx: %8lu: free\n", + printk(KERN_DEBUG "%s 0x%08lx-0x%08lx: %8lu: free\n", prefix, hole_start, hole_end, hole_size); total_free += hole_size; drm_mm_for_each_node(entry, mm) { - printf("%s 0x%08lx-0x%08lx: %8lu: used\n", + printk(KERN_DEBUG "%s 0x%08lx-0x%08lx: %8lu: used\n", prefix, entry->start, entry->start + entry->size, entry->size); total_used += entry->size; @@ -587,7 +708,7 @@ void drm_mm_debug_table(struct drm_mm *mm, const char *prefix) hole_start = drm_mm_hole_node_start(entry); hole_end = drm_mm_hole_node_end(entry); hole_size = hole_end - hole_start; - printf("%s 0x%08lx-0x%08lx: %8lu: free\n", + printk(KERN_DEBUG "%s 0x%08lx-0x%08lx: %8lu: free\n", prefix, hole_start, hole_end, hole_size); total_free += hole_size; @@ -595,6 +716,7 @@ void drm_mm_debug_table(struct drm_mm *mm, const char *prefix) } total = total_free + total_used; - printf("%s total: %lu, used %lu free %lu\n", prefix, total, + printk(KERN_DEBUG "%s total: %lu, used %lu free %lu\n", prefix, total, total_used, total_free); } +EXPORT_SYMBOL(drm_mm_debug_table); diff --git a/sys/dev/drm2/drm_mm.h b/sys/dev/drm2/drm_mm.h index 7150e24c1770..1bbc00377fab 100644 --- a/sys/dev/drm2/drm_mm.h +++ b/sys/dev/drm2/drm_mm.h @@ -25,18 +25,20 @@ * * **************************************************************************/ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - /* * Authors: * Thomas Hellstrom <thomas-at-tungstengraphics-dot-com> */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + #ifndef _DRM_MM_H_ #define _DRM_MM_H_ +/* + * Generic range manager structs + */ #include <dev/drm2/drm_linux_list.h> struct drm_mm_node { @@ -48,27 +50,34 @@ struct drm_mm_node { unsigned scanned_next_free : 1; unsigned scanned_preceeds_hole : 1; unsigned allocated : 1; + unsigned long color; unsigned long start; unsigned long size; struct drm_mm *mm; - void *private; }; struct drm_mm { + /* List of all memory nodes that immediately precede a free hole. */ struct list_head hole_stack; + /* head_node.node_list is the list of all memory nodes, ordered + * according to the (increasing) start address of the memory node. */ struct drm_mm_node head_node; struct list_head unused_nodes; int num_unused; struct mtx unused_lock; unsigned int scan_check_range : 1; unsigned scan_alignment; + unsigned long scan_color; unsigned long scan_size; unsigned long scan_hit_start; - unsigned scan_hit_size; + unsigned long scan_hit_end; unsigned scanned_blocks; unsigned long scan_start; unsigned long scan_end; struct drm_mm_node *prev_scanned_node; + + void (*color_adjust)(struct drm_mm_node *node, unsigned long color, + unsigned long *start, unsigned long *end); }; static inline bool drm_mm_node_allocated(struct drm_mm_node *node) @@ -78,7 +87,7 @@ static inline bool drm_mm_node_allocated(struct drm_mm_node *node) static inline bool drm_mm_initialized(struct drm_mm *mm) { - return (mm->hole_stack.next != NULL); + return mm->hole_stack.next; } #define drm_mm_for_each_node(entry, mm) list_for_each_entry(entry, \ &(mm)->head_node.node_list, \ @@ -89,19 +98,20 @@ static inline bool drm_mm_initialized(struct drm_mm *mm) struct drm_mm_node, node_list) : NULL; \ entry != NULL; entry = next, \ next = entry ? list_entry(entry->node_list.next, \ - struct drm_mm_node, node_list) : NULL) - + struct drm_mm_node, node_list) : NULL) \ /* * Basic range manager support (drm_mm.c) */ extern struct drm_mm_node *drm_mm_get_block_generic(struct drm_mm_node *node, unsigned long size, unsigned alignment, + unsigned long color, int atomic); extern struct drm_mm_node *drm_mm_get_block_range_generic( struct drm_mm_node *node, unsigned long size, unsigned alignment, + unsigned long color, unsigned long start, unsigned long end, int atomic); @@ -109,13 +119,13 @@ static inline struct drm_mm_node *drm_mm_get_block(struct drm_mm_node *parent, unsigned long size, unsigned alignment) { - return drm_mm_get_block_generic(parent, size, alignment, 0); + return drm_mm_get_block_generic(parent, size, alignment, 0, 0); } static inline struct drm_mm_node *drm_mm_get_block_atomic(struct drm_mm_node *parent, unsigned long size, unsigned alignment) { - return drm_mm_get_block_generic(parent, size, alignment, 1); + return drm_mm_get_block_generic(parent, size, alignment, 0, 1); } static inline struct drm_mm_node *drm_mm_get_block_range( struct drm_mm_node *parent, @@ -124,8 +134,19 @@ static inline struct drm_mm_node *drm_mm_get_block_range( unsigned long start, unsigned long end) { - return drm_mm_get_block_range_generic(parent, size, alignment, - start, end, 0); + return drm_mm_get_block_range_generic(parent, size, alignment, 0, + start, end, 0); +} +static inline struct drm_mm_node *drm_mm_get_color_block_range( + struct drm_mm_node *parent, + unsigned long size, + unsigned alignment, + unsigned long color, + unsigned long start, + unsigned long end) +{ + return drm_mm_get_block_range_generic(parent, size, alignment, color, + start, end, 0); } static inline struct drm_mm_node *drm_mm_get_block_atomic_range( struct drm_mm_node *parent, @@ -134,38 +155,91 @@ static inline struct drm_mm_node *drm_mm_get_block_atomic_range( unsigned long start, unsigned long end) { - return drm_mm_get_block_range_generic(parent, size, alignment, + return drm_mm_get_block_range_generic(parent, size, alignment, 0, start, end, 1); } -extern int drm_mm_insert_node(struct drm_mm *mm, struct drm_mm_node *node, - unsigned long size, unsigned alignment); + +extern int drm_mm_insert_node(struct drm_mm *mm, + struct drm_mm_node *node, + unsigned long size, + unsigned alignment); extern int drm_mm_insert_node_in_range(struct drm_mm *mm, struct drm_mm_node *node, - unsigned long size, unsigned alignment, - unsigned long start, unsigned long end); + unsigned long size, + unsigned alignment, + unsigned long start, + unsigned long end); +extern int drm_mm_insert_node_generic(struct drm_mm *mm, + struct drm_mm_node *node, + unsigned long size, + unsigned alignment, + unsigned long color); +extern int drm_mm_insert_node_in_range_generic(struct drm_mm *mm, + struct drm_mm_node *node, + unsigned long size, + unsigned alignment, + unsigned long color, + unsigned long start, + unsigned long end); extern void drm_mm_put_block(struct drm_mm_node *cur); extern void drm_mm_remove_node(struct drm_mm_node *node); extern void drm_mm_replace_node(struct drm_mm_node *old, struct drm_mm_node *new); -extern struct drm_mm_node *drm_mm_search_free(const struct drm_mm *mm, - unsigned long size, - unsigned alignment, - int best_match); -extern struct drm_mm_node *drm_mm_search_free_in_range( +extern struct drm_mm_node *drm_mm_search_free_generic(const struct drm_mm *mm, + unsigned long size, + unsigned alignment, + unsigned long color, + bool best_match); +extern struct drm_mm_node *drm_mm_search_free_in_range_generic( + const struct drm_mm *mm, + unsigned long size, + unsigned alignment, + unsigned long color, + unsigned long start, + unsigned long end, + bool best_match); +static inline struct drm_mm_node *drm_mm_search_free(const struct drm_mm *mm, + unsigned long size, + unsigned alignment, + bool best_match) +{ + return drm_mm_search_free_generic(mm,size, alignment, 0, best_match); +} +static inline struct drm_mm_node *drm_mm_search_free_in_range( const struct drm_mm *mm, unsigned long size, unsigned alignment, unsigned long start, unsigned long end, - int best_match); -extern int drm_mm_init(struct drm_mm *mm, unsigned long start, + bool best_match) +{ + return drm_mm_search_free_in_range_generic(mm, size, alignment, 0, + start, end, best_match); +} +static inline struct drm_mm_node *drm_mm_search_free_color(const struct drm_mm *mm, + unsigned long size, + unsigned alignment, + unsigned long color, + bool best_match) +{ + return drm_mm_search_free_generic(mm,size, alignment, color, best_match); +} +static inline struct drm_mm_node *drm_mm_search_free_in_range_color( + const struct drm_mm *mm, + unsigned long size, + unsigned alignment, + unsigned long color, + unsigned long start, + unsigned long end, + bool best_match) +{ + return drm_mm_search_free_in_range_generic(mm, size, alignment, color, + start, end, best_match); +} +extern int drm_mm_init(struct drm_mm *mm, + unsigned long start, unsigned long size); extern void drm_mm_takedown(struct drm_mm *mm); extern int drm_mm_clean(struct drm_mm *mm); -extern unsigned long drm_mm_tail_space(struct drm_mm *mm); -extern int drm_mm_remove_space_from_tail(struct drm_mm *mm, - unsigned long size); -extern int drm_mm_add_space_to_tail(struct drm_mm *mm, - unsigned long size, int atomic); extern int drm_mm_pre_get(struct drm_mm *mm); static inline struct drm_mm *drm_get_mm(struct drm_mm_node *block) @@ -173,15 +247,19 @@ static inline struct drm_mm *drm_get_mm(struct drm_mm_node *block) return block->mm; } -void drm_mm_init_scan(struct drm_mm *mm, unsigned long size, - unsigned alignment); -void drm_mm_init_scan_with_range(struct drm_mm *mm, unsigned long size, +void drm_mm_init_scan(struct drm_mm *mm, + unsigned long size, + unsigned alignment, + unsigned long color); +void drm_mm_init_scan_with_range(struct drm_mm *mm, + unsigned long size, unsigned alignment, + unsigned long color, unsigned long start, unsigned long end); int drm_mm_scan_add_block(struct drm_mm_node *node); int drm_mm_scan_remove_block(struct drm_mm_node *node); -void drm_mm_debug_table(struct drm_mm *mm, const char *prefix); +extern void drm_mm_debug_table(struct drm_mm *mm, const char *prefix); #endif diff --git a/sys/dev/drm2/drm_mode.h b/sys/dev/drm2/drm_mode.h index 79cf933d4c89..395062500df3 100644 --- a/sys/dev/drm2/drm_mode.h +++ b/sys/dev/drm2/drm_mode.h @@ -29,6 +29,8 @@ #ifndef _DRM_MODE_H #define _DRM_MODE_H +#include <dev/drm2/drm_os_freebsd.h> + #define DRM_DISPLAY_INFO_LEN 32 #define DRM_CONNECTOR_NAME_LEN 32 #define DRM_DISPLAY_MODE_LEN 32 @@ -84,41 +86,41 @@ #define DRM_MODE_DIRTY_ANNOTATE 2 struct drm_mode_modeinfo { - uint32_t clock; - uint16_t hdisplay, hsync_start, hsync_end, htotal, hskew; - uint16_t vdisplay, vsync_start, vsync_end, vtotal, vscan; + __u32 clock; + __u16 hdisplay, hsync_start, hsync_end, htotal, hskew; + __u16 vdisplay, vsync_start, vsync_end, vtotal, vscan; - uint32_t vrefresh; + __u32 vrefresh; - uint32_t flags; - uint32_t type; + __u32 flags; + __u32 type; char name[DRM_DISPLAY_MODE_LEN]; }; struct drm_mode_card_res { - uint64_t fb_id_ptr; - uint64_t crtc_id_ptr; - uint64_t connector_id_ptr; - uint64_t encoder_id_ptr; - uint32_t count_fbs; - uint32_t count_crtcs; - uint32_t count_connectors; - uint32_t count_encoders; - uint32_t min_width, max_width; - uint32_t min_height, max_height; + __u64 fb_id_ptr; + __u64 crtc_id_ptr; + __u64 connector_id_ptr; + __u64 encoder_id_ptr; + __u32 count_fbs; + __u32 count_crtcs; + __u32 count_connectors; + __u32 count_encoders; + __u32 min_width, max_width; + __u32 min_height, max_height; }; struct drm_mode_crtc { - uint64_t set_connectors_ptr; - uint32_t count_connectors; + __u64 set_connectors_ptr; + __u32 count_connectors; - uint32_t crtc_id; /**< Id */ - uint32_t fb_id; /**< Id of framebuffer */ + __u32 crtc_id; /**< Id */ + __u32 fb_id; /**< Id of framebuffer */ - uint32_t x, y; /**< Position on the frameuffer */ + __u32 x, y; /**< Position on the frameuffer */ - uint32_t gamma_size; - uint32_t mode_valid; + __u32 gamma_size; + __u32 mode_valid; struct drm_mode_modeinfo mode; }; @@ -127,36 +129,36 @@ struct drm_mode_crtc { /* Planes blend with or override other bits on the CRTC */ struct drm_mode_set_plane { - uint32_t plane_id; - uint32_t crtc_id; - uint32_t fb_id; /* fb object contains surface format type */ - uint32_t flags; /* see above flags */ + __u32 plane_id; + __u32 crtc_id; + __u32 fb_id; /* fb object contains surface format type */ + __u32 flags; /* see above flags */ /* Signed dest location allows it to be partially off screen */ - int32_t crtc_x, crtc_y; - uint32_t crtc_w, crtc_h; + __s32 crtc_x, crtc_y; + __u32 crtc_w, crtc_h; /* Source values are 16.16 fixed point */ - uint32_t src_x, src_y; - uint32_t src_h, src_w; + __u32 src_x, src_y; + __u32 src_h, src_w; }; struct drm_mode_get_plane { - uint32_t plane_id; + __u32 plane_id; - uint32_t crtc_id; - uint32_t fb_id; + __u32 crtc_id; + __u32 fb_id; - uint32_t possible_crtcs; - uint32_t gamma_size; + __u32 possible_crtcs; + __u32 gamma_size; - uint32_t count_format_types; - uint64_t format_type_ptr; + __u32 count_format_types; + __u64 format_type_ptr; }; struct drm_mode_get_plane_res { - uint64_t plane_id_ptr; - uint32_t count_planes; + __u64 plane_id_ptr; + __u32 count_planes; }; #define DRM_MODE_ENCODER_NONE 0 @@ -164,15 +166,16 @@ struct drm_mode_get_plane_res { #define DRM_MODE_ENCODER_TMDS 2 #define DRM_MODE_ENCODER_LVDS 3 #define DRM_MODE_ENCODER_TVDAC 4 +#define DRM_MODE_ENCODER_VIRTUAL 5 struct drm_mode_get_encoder { - uint32_t encoder_id; - uint32_t encoder_type; + __u32 encoder_id; + __u32 encoder_type; - uint32_t crtc_id; /**< Id of crtc */ + __u32 crtc_id; /**< Id of crtc */ - uint32_t possible_crtcs; - uint32_t possible_clones; + __u32 possible_crtcs; + __u32 possible_clones; }; /* This is for connectors with multiple signal types. */ @@ -201,26 +204,27 @@ struct drm_mode_get_encoder { #define DRM_MODE_CONNECTOR_HDMIB 12 #define DRM_MODE_CONNECTOR_TV 13 #define DRM_MODE_CONNECTOR_eDP 14 +#define DRM_MODE_CONNECTOR_VIRTUAL 15 struct drm_mode_get_connector { - uint64_t encoders_ptr; - uint64_t modes_ptr; - uint64_t props_ptr; - uint64_t prop_values_ptr; + __u64 encoders_ptr; + __u64 modes_ptr; + __u64 props_ptr; + __u64 prop_values_ptr; - uint32_t count_modes; - uint32_t count_props; - uint32_t count_encoders; + __u32 count_modes; + __u32 count_props; + __u32 count_encoders; - uint32_t encoder_id; /**< Current Encoder */ - uint32_t connector_id; /**< Id */ - uint32_t connector_type; - uint32_t connector_type_id; + __u32 encoder_id; /**< Current Encoder */ + __u32 connector_id; /**< Id */ + __u32 connector_type; + __u32 connector_type_id; - uint32_t connection; - uint32_t mm_width, mm_height; /**< HxW in millimeters */ - uint32_t subpixel; + __u32 connection; + __u32 mm_width, mm_height; /**< HxW in millimeters */ + __u32 subpixel; }; #define DRM_MODE_PROP_PENDING (1<<0) @@ -231,66 +235,66 @@ struct drm_mode_get_connector { #define DRM_MODE_PROP_BITMASK (1<<5) /* bitmask of enumerated types */ struct drm_mode_property_enum { - uint64_t value; + __u64 value; char name[DRM_PROP_NAME_LEN]; }; struct drm_mode_get_property { - uint64_t values_ptr; /* values and blob lengths */ - uint64_t enum_blob_ptr; /* enum and blob id ptrs */ + __u64 values_ptr; /* values and blob lengths */ + __u64 enum_blob_ptr; /* enum and blob id ptrs */ - uint32_t prop_id; - uint32_t flags; + __u32 prop_id; + __u32 flags; char name[DRM_PROP_NAME_LEN]; - uint32_t count_values; - uint32_t count_enum_blobs; + __u32 count_values; + __u32 count_enum_blobs; }; struct drm_mode_connector_set_property { - uint64_t value; - uint32_t prop_id; - uint32_t connector_id; + __u64 value; + __u32 prop_id; + __u32 connector_id; }; struct drm_mode_obj_get_properties { - uint64_t props_ptr; - uint64_t prop_values_ptr; - uint32_t count_props; - uint32_t obj_id; - uint32_t obj_type; + __u64 props_ptr; + __u64 prop_values_ptr; + __u32 count_props; + __u32 obj_id; + __u32 obj_type; }; struct drm_mode_obj_set_property { - uint64_t value; - uint32_t prop_id; - uint32_t obj_id; - uint32_t obj_type; + __u64 value; + __u32 prop_id; + __u32 obj_id; + __u32 obj_type; }; struct drm_mode_get_blob { - uint32_t blob_id; - uint32_t length; - uint64_t data; + __u32 blob_id; + __u32 length; + __u64 data; }; struct drm_mode_fb_cmd { - uint32_t fb_id; - uint32_t width, height; - uint32_t pitch; - uint32_t bpp; - uint32_t depth; + __u32 fb_id; + __u32 width, height; + __u32 pitch; + __u32 bpp; + __u32 depth; /* driver specific handle */ - uint32_t handle; + __u32 handle; }; -#define DRM_MODE_FB_INTERLACED (1<<0 /* for interlaced framebuffers */ +#define DRM_MODE_FB_INTERLACED (1<<0) /* for interlaced framebuffers */ struct drm_mode_fb_cmd2 { - uint32_t fb_id; - uint32_t width, height; - uint32_t pixel_format; /* fourcc code from drm_fourcc.h */ - uint32_t flags; /* see above flags */ + __u32 fb_id; + __u32 width, height; + __u32 pixel_format; /* fourcc code from drm_fourcc.h */ + __u32 flags; /* see above flags */ /* * In case of planar formats, this ioctl allows up to 4 @@ -306,9 +310,9 @@ struct drm_mode_fb_cmd2 { * offeset[1]. Note that offset[0] will generally * be 0. */ - uint32_t handles[4]; - uint32_t pitches[4]; /* pitch for each plane */ - uint32_t offsets[4]; /* offset of each plane */ + __u32 handles[4]; + __u32 pitches[4]; /* pitch for each plane */ + __u32 offsets[4]; /* offset of each plane */ }; #define DRM_MODE_FB_DIRTY_ANNOTATE_COPY 0x01 @@ -345,23 +349,24 @@ struct drm_mode_fb_cmd2 { */ struct drm_mode_fb_dirty_cmd { - uint32_t fb_id; - uint32_t flags; - uint32_t color; - uint32_t num_clips; - uint64_t clips_ptr; + __u32 fb_id; + __u32 flags; + __u32 color; + __u32 num_clips; + __u64 clips_ptr; }; struct drm_mode_mode_cmd { - uint32_t connector_id; + __u32 connector_id; struct drm_mode_modeinfo mode; }; -#define DRM_MODE_CURSOR_BO (1<<0) -#define DRM_MODE_CURSOR_MOVE (1<<1) +#define DRM_MODE_CURSOR_BO 0x01 +#define DRM_MODE_CURSOR_MOVE 0x02 +#define DRM_MODE_CURSOR_FLAGS 0x03 /* - * depending on the value in flags diffrent members are used. + * depending on the value in flags different members are used. * * CURSOR_BO uses * crtc @@ -375,24 +380,24 @@ struct drm_mode_mode_cmd { * y */ struct drm_mode_cursor { - uint32_t flags; - uint32_t crtc_id; - int32_t x; - int32_t y; - uint32_t width; - uint32_t height; + __u32 flags; + __u32 crtc_id; + __s32 x; + __s32 y; + __u32 width; + __u32 height; /* driver specific handle */ - uint32_t handle; + __u32 handle; }; struct drm_mode_crtc_lut { - uint32_t crtc_id; - uint32_t gamma_size; + __u32 crtc_id; + __u32 gamma_size; /* pointers to arrays */ - uint64_t red; - uint64_t green; - uint64_t blue; + __u64 red; + __u64 green; + __u64 blue; }; #define DRM_MODE_PAGE_FLIP_EVENT 0x01 @@ -421,11 +426,11 @@ struct drm_mode_crtc_lut { */ struct drm_mode_crtc_page_flip { - uint32_t crtc_id; - uint32_t fb_id; - uint32_t flags; - uint32_t reserved; - uint64_t user_data; + __u32 crtc_id; + __u32 fb_id; + __u32 flags; + __u32 reserved; + __u64 user_data; }; /* create a dumb scanout buffer */ @@ -443,14 +448,14 @@ struct drm_mode_create_dumb { /* set up for mmap of a dumb scanout buffer */ struct drm_mode_map_dumb { /** Handle for the object being mapped. */ - uint32_t handle; - uint32_t pad; + __u32 handle; + __u32 pad; /** * Fake offset to use for subsequent mmap call * * This is a fixed-size type for 32/64 compatibility. */ - uint64_t offset; + __u64 offset; }; struct drm_mode_destroy_dumb { diff --git a/sys/dev/drm2/drm_modes.c b/sys/dev/drm2/drm_modes.c index a2dbbdd58a5b..4df8cb12bc7e 100644 --- a/sys/dev/drm2/drm_modes.c +++ b/sys/dev/drm2/drm_modes.c @@ -34,11 +34,8 @@ __FBSDID("$FreeBSD$"); #include <dev/drm2/drmP.h> -#include <dev/drm2/drm.h> #include <dev/drm2/drm_crtc.h> -#define KHZ2PICOS(a) (1000000000UL/(a)) - /** * drm_mode_debug_printmodeline - debug print a mode * @dev: DRM device @@ -49,7 +46,7 @@ __FBSDID("$FreeBSD$"); * * Describe @mode using DRM_DEBUG. */ -void drm_mode_debug_printmodeline(struct drm_display_mode *mode) +void drm_mode_debug_printmodeline(const struct drm_display_mode *mode) { DRM_DEBUG_KMS("Modeline %d:\"%s\" %d %d %d %d %d %d %d %d %d %d " "0x%x 0x%x\n", @@ -59,6 +56,7 @@ void drm_mode_debug_printmodeline(struct drm_display_mode *mode) mode->vdisplay, mode->vsync_start, mode->vsync_end, mode->vtotal, mode->type, mode->flags); } +EXPORT_SYMBOL(drm_mode_debug_printmodeline); /** * drm_cvt_mode -create a modeline based on CVT algorithm @@ -278,6 +276,7 @@ struct drm_display_mode *drm_cvt_mode(struct drm_device *dev, int hdisplay, return drm_mode; } +EXPORT_SYMBOL(drm_cvt_mode); /** * drm_gtf_mode_complex - create the modeline based on full GTF algorithm @@ -463,6 +462,7 @@ drm_gtf_mode_complex(struct drm_device *dev, int hdisplay, int vdisplay, return drm_mode; } +EXPORT_SYMBOL(drm_gtf_mode_complex); /** * drm_gtf_mode - create the modeline based on GTF algorithm @@ -502,6 +502,7 @@ drm_gtf_mode(struct drm_device *dev, int hdisplay, int vdisplay, int vrefresh, return drm_gtf_mode_complex(dev, hdisplay, vdisplay, vrefresh, lace, margins, 600, 40 * 2, 128, 20 * 2); } +EXPORT_SYMBOL(drm_gtf_mode); /** * drm_mode_set_name - set the name on a mode @@ -520,6 +521,7 @@ void drm_mode_set_name(struct drm_display_mode *mode) mode->hdisplay, mode->vdisplay, interlaced ? "i" : ""); } +EXPORT_SYMBOL(drm_mode_set_name); /** * drm_mode_list_concat - move modes from one list to another @@ -540,6 +542,7 @@ void drm_mode_list_concat(struct list_head *head, struct list_head *new) list_move_tail(entry, new); } } +EXPORT_SYMBOL(drm_mode_list_concat); /** * drm_mode_width - get the width of a mode @@ -555,11 +558,12 @@ void drm_mode_list_concat(struct list_head *head, struct list_head *new) * RETURNS: * @mode->hdisplay */ -int drm_mode_width(struct drm_display_mode *mode) +int drm_mode_width(const struct drm_display_mode *mode) { return mode->hdisplay; } +EXPORT_SYMBOL(drm_mode_width); /** * drm_mode_height - get the height of a mode @@ -575,10 +579,11 @@ int drm_mode_width(struct drm_display_mode *mode) * RETURNS: * @mode->vdisplay */ -int drm_mode_height(struct drm_display_mode *mode) +int drm_mode_height(const struct drm_display_mode *mode) { return mode->vdisplay; } +EXPORT_SYMBOL(drm_mode_height); /** drm_mode_hsync - get the hsync of a mode * @mode: mode @@ -604,6 +609,7 @@ int drm_mode_hsync(const struct drm_display_mode *mode) return calc_val; } +EXPORT_SYMBOL(drm_mode_hsync); /** * drm_mode_vrefresh - get the vrefresh of a mode @@ -645,6 +651,7 @@ int drm_mode_vrefresh(const struct drm_display_mode *mode) } return refresh; } +EXPORT_SYMBOL(drm_mode_vrefresh); /** * drm_mode_set_crtcinfo - set CRTC modesetting parameters @@ -678,8 +685,6 @@ void drm_mode_set_crtcinfo(struct drm_display_mode *p, int adjust_flags) p->crtc_vsync_end /= 2; p->crtc_vtotal /= 2; } - - p->crtc_vtotal |= 1; } if (p->flags & DRM_MODE_FLAG_DBLSCAN) { @@ -700,11 +705,30 @@ void drm_mode_set_crtcinfo(struct drm_display_mode *p, int adjust_flags) p->crtc_vblank_end = max(p->crtc_vsync_end, p->crtc_vtotal); p->crtc_hblank_start = min(p->crtc_hsync_start, p->crtc_hdisplay); p->crtc_hblank_end = max(p->crtc_hsync_end, p->crtc_htotal); - - p->crtc_hadjusted = false; - p->crtc_vadjusted = false; } +EXPORT_SYMBOL(drm_mode_set_crtcinfo); + + +/** + * drm_mode_copy - copy the mode + * @dst: mode to overwrite + * @src: mode to copy + * + * LOCKING: + * None. + * + * Copy an existing mode into another mode, preserving the object id + * of the destination mode. + */ +void drm_mode_copy(struct drm_display_mode *dst, const struct drm_display_mode *src) +{ + int id = dst->base.id; + *dst = *src; + dst->base.id = id; + INIT_LIST_HEAD(&dst->head); +} +EXPORT_SYMBOL(drm_mode_copy); /** * drm_mode_duplicate - allocate and duplicate an existing mode @@ -720,18 +744,16 @@ struct drm_display_mode *drm_mode_duplicate(struct drm_device *dev, const struct drm_display_mode *mode) { struct drm_display_mode *nmode; - int new_id; nmode = drm_mode_create(dev); if (!nmode) return NULL; - new_id = nmode->base.id; - *nmode = *mode; - nmode->base.id = new_id; - INIT_LIST_HEAD(&nmode->head); + drm_mode_copy(nmode, mode); + return nmode; } +EXPORT_SYMBOL(drm_mode_duplicate); /** * drm_mode_equal - test modes for equality @@ -744,9 +766,9 @@ struct drm_display_mode *drm_mode_duplicate(struct drm_device *dev, * Check to see if @mode1 and @mode2 are equivalent. * * RETURNS: - * true if the modes are equal, false otherwise. + * True if the modes are equal, false otherwise. */ -bool drm_mode_equal(struct drm_display_mode *mode1, struct drm_display_mode *mode2) +bool drm_mode_equal(const struct drm_display_mode *mode1, const struct drm_display_mode *mode2) { /* do clock check convert to PICOS so fb modes get matched * the same */ @@ -771,6 +793,7 @@ bool drm_mode_equal(struct drm_display_mode *mode1, struct drm_display_mode *mod return false; } +EXPORT_SYMBOL(drm_mode_equal); /** * drm_mode_validate_size - make sure modes adhere to size constraints @@ -804,6 +827,7 @@ void drm_mode_validate_size(struct drm_device *dev, mode->status = MODE_VIRTUAL_Y; } } +EXPORT_SYMBOL(drm_mode_validate_size); /** * drm_mode_validate_clocks - validate modes against clock limits @@ -840,6 +864,7 @@ void drm_mode_validate_clocks(struct drm_device *dev, mode->status = MODE_CLOCK_RANGE; } } +EXPORT_SYMBOL(drm_mode_validate_clocks); /** * drm_mode_prune_invalid - remove invalid modes from mode list @@ -871,6 +896,7 @@ void drm_mode_prune_invalid(struct drm_device *dev, } } } +EXPORT_SYMBOL(drm_mode_prune_invalid); /** * drm_mode_compare - compare modes for favorability @@ -918,6 +944,7 @@ void drm_mode_sort(struct list_head *mode_list) { drm_list_sort(NULL, mode_list, drm_mode_compare); } +EXPORT_SYMBOL(drm_mode_sort); /** * drm_mode_connector_list_update - update the mode list for the connector @@ -959,6 +986,7 @@ void drm_mode_connector_list_update(struct drm_connector *connector) } } } +EXPORT_SYMBOL(drm_mode_connector_list_update); /** * drm_mode_parse_command_line_for_connector - parse command line for connector @@ -986,7 +1014,7 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option, int i; enum drm_connector_force force = DRM_FORCE_UNSPECIFIED; -#ifdef XXX_CONFIG_FB +#ifdef CONFIG_FB if (!mode_option) mode_option = fb_mode_option; #endif @@ -1003,7 +1031,7 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option, case '@': if (!refresh_specified && !bpp_specified && !yres_specified && !cvt && !rb && was_digit) { - refresh = strtol(&name[i+1], NULL, 10); + refresh = simple_strtol(&name[i+1], NULL, 10); refresh_specified = true; was_digit = false; } else @@ -1012,7 +1040,7 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option, case '-': if (!bpp_specified && !yres_specified && !cvt && !rb && was_digit) { - bpp = strtol(&name[i+1], NULL, 10); + bpp = simple_strtol(&name[i+1], NULL, 10); bpp_specified = true; was_digit = false; } else @@ -1020,7 +1048,7 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option, break; case 'x': if (!yres_specified && was_digit) { - yres = strtol(&name[i+1], NULL, 10); + yres = simple_strtol(&name[i+1], NULL, 10); yres_specified = true; was_digit = false; } else @@ -1080,7 +1108,7 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option, if (i < 0 && yres_specified) { char *ch; - xres = strtol(name, &ch, 10); + xres = simple_strtol(name, &ch, 10); if ((ch != NULL) && (*ch == 'x')) res_specified = true; else @@ -1091,7 +1119,8 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option, } done: if (i >= 0) { - printf("parse error at position %i in video mode '%s'\n", + DRM_WARNING( + "parse error at position %i in video mode '%s'\n", i, name); mode->specified = false; return false; @@ -1120,6 +1149,7 @@ done: return true; } +EXPORT_SYMBOL(drm_mode_parse_command_line_for_connector); struct drm_display_mode * drm_mode_create_from_cmdline_mode(struct drm_device *dev, @@ -1145,3 +1175,4 @@ drm_mode_create_from_cmdline_mode(struct drm_device *dev, drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); return mode; } +EXPORT_SYMBOL(drm_mode_create_from_cmdline_mode); diff --git a/sys/dev/drm2/drm_os_freebsd.c b/sys/dev/drm2/drm_os_freebsd.c new file mode 100644 index 000000000000..5baa01adfc16 --- /dev/null +++ b/sys/dev/drm2/drm_os_freebsd.c @@ -0,0 +1,393 @@ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <dev/drm2/drmP.h> + +#include <dev/agp/agpreg.h> +#include <dev/pci/pcireg.h> + +devclass_t drm_devclass; + +MALLOC_DEFINE(DRM_MEM_DMA, "drm_dma", "DRM DMA Data Structures"); +MALLOC_DEFINE(DRM_MEM_SAREA, "drm_sarea", "DRM SAREA Data Structures"); +MALLOC_DEFINE(DRM_MEM_DRIVER, "drm_driver", "DRM DRIVER Data Structures"); +MALLOC_DEFINE(DRM_MEM_MAGIC, "drm_magic", "DRM MAGIC Data Structures"); +MALLOC_DEFINE(DRM_MEM_MINOR, "drm_minor", "DRM MINOR Data Structures"); +MALLOC_DEFINE(DRM_MEM_IOCTLS, "drm_ioctls", "DRM IOCTL Data Structures"); +MALLOC_DEFINE(DRM_MEM_MAPS, "drm_maps", "DRM MAP Data Structures"); +MALLOC_DEFINE(DRM_MEM_BUFS, "drm_bufs", "DRM BUFFER Data Structures"); +MALLOC_DEFINE(DRM_MEM_SEGS, "drm_segs", "DRM SEGMENTS Data Structures"); +MALLOC_DEFINE(DRM_MEM_PAGES, "drm_pages", "DRM PAGES Data Structures"); +MALLOC_DEFINE(DRM_MEM_FILES, "drm_files", "DRM FILE Data Structures"); +MALLOC_DEFINE(DRM_MEM_QUEUES, "drm_queues", "DRM QUEUE Data Structures"); +MALLOC_DEFINE(DRM_MEM_CMDS, "drm_cmds", "DRM COMMAND Data Structures"); +MALLOC_DEFINE(DRM_MEM_MAPPINGS, "drm_mapping", "DRM MAPPING Data Structures"); +MALLOC_DEFINE(DRM_MEM_BUFLISTS, "drm_buflists", "DRM BUFLISTS Data Structures"); +MALLOC_DEFINE(DRM_MEM_AGPLISTS, "drm_agplists", "DRM AGPLISTS Data Structures"); +MALLOC_DEFINE(DRM_MEM_CTXBITMAP, "drm_ctxbitmap", + "DRM CTXBITMAP Data Structures"); +MALLOC_DEFINE(DRM_MEM_SGLISTS, "drm_sglists", "DRM SGLISTS Data Structures"); +MALLOC_DEFINE(DRM_MEM_MM, "drm_sman", "DRM MEMORY MANAGER Data Structures"); +MALLOC_DEFINE(DRM_MEM_HASHTAB, "drm_hashtab", "DRM HASHTABLE Data Structures"); +MALLOC_DEFINE(DRM_MEM_KMS, "drm_kms", "DRM KMS Data Structures"); +MALLOC_DEFINE(DRM_MEM_VBLANK, "drm_vblank", "DRM VBLANK Handling Data"); + +const char *fb_mode_option = NULL; + +#define NSEC_PER_USEC 1000L +#define NSEC_PER_SEC 1000000000L + +int64_t +timeval_to_ns(const struct timeval *tv) +{ + return ((int64_t)tv->tv_sec * NSEC_PER_SEC) + + tv->tv_usec * NSEC_PER_USEC; +} + +struct timeval +ns_to_timeval(const int64_t nsec) +{ + struct timeval tv; + long rem; + + if (nsec == 0) { + tv.tv_sec = 0; + tv.tv_usec = 0; + return (tv); + } + + tv.tv_sec = nsec / NSEC_PER_SEC; + rem = nsec % NSEC_PER_SEC; + if (rem < 0) { + tv.tv_sec--; + rem += NSEC_PER_SEC; + } + tv.tv_usec = rem / 1000; + return (tv); +} + +static 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); +} + +/* + * drm_probe_helper: called by a driver at the end of its probe + * method. + */ +int +drm_probe_helper(device_t kdev, drm_pci_id_list_t *idlist) +{ + drm_pci_id_list_t *id_entry; + int vendor, device; + + vendor = pci_get_vendor(kdev); + device = pci_get_device(kdev); + + if (pci_get_class(kdev) != PCIC_DISPLAY || + (pci_get_subclass(kdev) != PCIS_DISPLAY_VGA && + pci_get_subclass(kdev) != PCIS_DISPLAY_OTHER)) + return (-ENXIO); + + id_entry = drm_find_description(vendor, device, idlist); + if (id_entry != NULL) { + if (device_get_desc(kdev) == NULL) { + DRM_DEBUG("%s desc: %s\n", + device_get_nameunit(kdev), id_entry->name); + device_set_desc(kdev, id_entry->name); + } + return (0); + } + + return (-ENXIO); +} + +/* + * drm_attach_helper: called by a driver at the end of its attach + * method. + */ +int +drm_attach_helper(device_t kdev, drm_pci_id_list_t *idlist, + struct drm_driver *driver) +{ + struct drm_device *dev; + int vendor, device; + int ret; + + dev = device_get_softc(kdev); + + vendor = pci_get_vendor(kdev); + device = pci_get_device(kdev); + dev->id_entry = drm_find_description(vendor, device, idlist); + + ret = drm_get_pci_dev(kdev, dev, driver); + + return (ret); +} + +int +drm_generic_detach(device_t kdev) +{ + struct drm_device *dev; + int i; + + dev = device_get_softc(kdev); + + drm_put_dev(dev); + + /* 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->dev, SYS_RES_MEMORY, + dev->pcirid[i], dev->pcir[i]); + dev->pcir[i] = NULL; + } + + if (pci_disable_busmaster(dev->dev)) + DRM_ERROR("Request to disable bus-master failed.\n"); + + return (0); +} + +int +drm_add_busid_modesetting(struct drm_device *dev, struct sysctl_ctx_list *ctx, + struct sysctl_oid *top) +{ + struct sysctl_oid *oid; + + snprintf(dev->busid_str, sizeof(dev->busid_str), + "pci:%04x:%02x:%02x.%d", dev->pci_domain, dev->pci_bus, + dev->pci_slot, dev->pci_func); + oid = SYSCTL_ADD_STRING(ctx, SYSCTL_CHILDREN(top), OID_AUTO, "busid", + CTLFLAG_RD, dev->busid_str, 0, NULL); + if (oid == NULL) + return (-ENOMEM); + dev->modesetting = (dev->driver->driver_features & DRIVER_MODESET) != 0; + oid = SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(top), OID_AUTO, + "modesetting", CTLFLAG_RD, &dev->modesetting, 0, NULL); + if (oid == NULL) + return (-ENOMEM); + + return (0); +} + +static int +drm_device_find_capability(struct drm_device *dev, int cap) +{ + + return (pci_find_cap(dev->dev, cap, NULL) == 0); +} + +int +drm_pci_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_pci_device_is_pcie(struct drm_device *dev) +{ + + return (drm_device_find_capability(dev, PCIY_EXPRESS)); +} + +static bool +dmi_found(const struct dmi_system_id *dsi) +{ + char *hw_vendor, *hw_prod; + int i, slot; + bool res; + + hw_vendor = kern_getenv("smbios.planar.maker"); + hw_prod = kern_getenv("smbios.planar.product"); + res = true; + for (i = 0; i < nitems(dsi->matches); i++) { + slot = dsi->matches[i].slot; + switch (slot) { + case DMI_NONE: + break; + case DMI_SYS_VENDOR: + case DMI_BOARD_VENDOR: + if (hw_vendor != NULL && + !strcmp(hw_vendor, dsi->matches[i].substr)) { + break; + } else { + res = false; + goto out; + } + case DMI_PRODUCT_NAME: + case DMI_BOARD_NAME: + if (hw_prod != NULL && + !strcmp(hw_prod, dsi->matches[i].substr)) { + break; + } else { + res = false; + goto out; + } + default: + res = false; + goto out; + } + } +out: + freeenv(hw_vendor); + freeenv(hw_prod); + + return (res); +} + +bool +dmi_check_system(const struct dmi_system_id *sysid) +{ + const struct dmi_system_id *dsi; + bool res; + + for (res = false, dsi = sysid; dsi->matches[0].slot != 0 ; dsi++) { + if (dmi_found(dsi)) { + res = true; + if (dsi->callback != NULL && dsi->callback(dsi)) + break; + } + } + return (res); +} + +int +drm_mtrr_add(unsigned long offset, unsigned long size, unsigned int flags) +{ + int act; + struct mem_range_desc mrdesc; + + mrdesc.mr_base = offset; + mrdesc.mr_len = size; + mrdesc.mr_flags = flags; + act = MEMRANGE_SET_UPDATE; + strlcpy(mrdesc.mr_owner, "drm", sizeof(mrdesc.mr_owner)); + return (-mem_range_attr_set(&mrdesc, &act)); +} + +int +drm_mtrr_del(int handle __unused, unsigned long offset, unsigned long size, + unsigned int flags) +{ + int act; + struct mem_range_desc mrdesc; + + mrdesc.mr_base = offset; + mrdesc.mr_len = size; + mrdesc.mr_flags = flags; + act = MEMRANGE_SET_REMOVE; + strlcpy(mrdesc.mr_owner, "drm", sizeof(mrdesc.mr_owner)); + return (-mem_range_attr_set(&mrdesc, &act)); +} + +void +drm_clflush_pages(vm_page_t *pages, unsigned long num_pages) +{ + +#if defined(__i386__) || defined(__amd64__) + pmap_invalidate_cache_pages(pages, num_pages); +#else + DRM_ERROR("drm_clflush_pages not implemented on this architecture"); +#endif +} + +void +drm_clflush_virt_range(char *addr, unsigned long length) +{ + +#if defined(__i386__) || defined(__amd64__) + pmap_invalidate_cache_range((vm_offset_t)addr, + (vm_offset_t)addr + length, TRUE); +#else + DRM_ERROR("drm_clflush_virt_range not implemented on this architecture"); +#endif +} + +#if DRM_LINUX + +#include <sys/sysproto.h> + +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}; + +/* 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 */ + +static int +drm_modevent(module_t mod, int type, void *data) +{ + + switch (type) { + case MOD_LOAD: + TUNABLE_INT_FETCH("drm.debug", &drm_debug); + TUNABLE_INT_FETCH("drm.notyet", &drm_notyet); + break; + } + return (0); +} + +static moduledata_t drm_mod = { + "drmn", + drm_modevent, + 0 +}; + +DECLARE_MODULE(drmn, drm_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST); +MODULE_VERSION(drmn, 1); +MODULE_DEPEND(drmn, agp, 1, 1, 1); +MODULE_DEPEND(drmn, pci, 1, 1, 1); +MODULE_DEPEND(drmn, mem, 1, 1, 1); +MODULE_DEPEND(drmn, iicbus, 1, 1, 1); diff --git a/sys/dev/drm2/drm_os_freebsd.h b/sys/dev/drm2/drm_os_freebsd.h index af03f8dc44ba..8aa660ad212f 100644 --- a/sys/dev/drm2/drm_os_freebsd.h +++ b/sys/dev/drm2/drm_os_freebsd.h @@ -6,6 +6,9 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); +#ifndef _DRM_OS_FREEBSD_H_ +#define _DRM_OS_FREEBSD_H_ + #include <sys/fbio.h> #if _BYTE_ORDER == _BIG_ENDIAN @@ -14,6 +17,19 @@ __FBSDID("$FreeBSD$"); #define __LITTLE_ENDIAN 1234 #endif +#ifdef __LP64__ +#define BITS_PER_LONG 64 +#else +#define BITS_PER_LONG 32 +#endif + +#ifndef __user +#define __user +#endif +#ifndef __iomem +#define __iomem +#endif + #define cpu_to_le16(x) htole16(x) #define le16_to_cpu(x) le16toh(x) #define cpu_to_le32(x) htole32(x) @@ -26,31 +42,96 @@ __FBSDID("$FreeBSD$"); #define be32_to_cpup(x) be32toh(*x) typedef vm_paddr_t dma_addr_t; +typedef vm_paddr_t resource_size_t; +#define wait_queue_head_t atomic_t + typedef uint64_t u64; typedef uint32_t u32; typedef uint16_t u16; -typedef uint8_t u8; +typedef uint8_t u8; typedef int64_t s64; typedef int32_t s32; typedef int16_t s16; -typedef int8_t s8; -typedef int32_t __be32; +typedef int8_t s8; +typedef uint16_t __le16; +typedef uint32_t __le32; +typedef uint64_t __le64; +typedef uint16_t __be16; +typedef uint32_t __be32; +typedef uint64_t __be64; + +#define DRM_IRQ_ARGS void *arg +typedef void irqreturn_t; +#define IRQ_HANDLED /* nothing */ +#define IRQ_NONE /* nothing */ +#define __init +#define __exit +#define __read_mostly + +#define WARN_ON(cond) KASSERT(!(cond), ("WARN ON: " #cond)) +#define WARN_ON_SMP(cond) WARN_ON(cond) +#define BUG_ON(cond) KASSERT(!(cond), ("BUG ON: " #cond)) #define unlikely(x) __builtin_expect(!!(x), 0) #define likely(x) __builtin_expect(!!(x), 1) #define container_of(ptr, type, member) ({ \ __typeof( ((type *)0)->member ) *__mptr = (ptr); \ (type *)( (char *)__mptr - offsetof(type,member) );}) -#define DRM_HZ hz -#define DRM_UDELAY(udelay) DELAY(udelay) -#define DRM_MDELAY(msecs) do { int loops = (msecs); \ +#define KHZ2PICOS(a) (1000000000UL/(a)) + +#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) + +#define HZ hz +#define DRM_HZ hz +#define DRM_CURRENTPID curthread->td_proc->p_pid +#define DRM_SUSER(p) (priv_check(p, PRIV_DRIVER) == 0) +#define udelay(usecs) DELAY(usecs) +#define mdelay(msecs) do { int loops = (msecs); \ while (loops--) DELAY(1000); \ } while (0) -#define DRM_MSLEEP(msecs) drm_msleep((msecs), "drm_msleep") -#define DRM_TIME_SLICE (hz/20) /* Time slice for GLXContexts */ +#define DRM_UDELAY(udelay) DELAY(udelay) +#define drm_msleep(x, msg) pause((msg), ((int64_t)(x)) * hz / 1000) +#define DRM_MSLEEP(msecs) drm_msleep((msecs), "drm_msleep") + +#define DRM_READ8(map, offset) \ + *(volatile u_int8_t *)(((vm_offset_t)(map)->handle) + \ + (vm_offset_t)(offset)) +#define DRM_READ16(map, offset) \ + le16toh(*(volatile u_int16_t *)(((vm_offset_t)(map)->handle) + \ + (vm_offset_t)(offset))) +#define DRM_READ32(map, offset) \ + le32toh(*(volatile u_int32_t *)(((vm_offset_t)(map)->handle) + \ + (vm_offset_t)(offset))) +#define DRM_READ64(map, offset) \ + le64toh(*(volatile u_int64_t *)(((vm_offset_t)(map)->handle) + \ + (vm_offset_t)(offset))) +#define DRM_WRITE8(map, offset, val) \ + *(volatile u_int8_t *)(((vm_offset_t)(map)->handle) + \ + (vm_offset_t)(offset)) = val +#define DRM_WRITE16(map, offset, val) \ + *(volatile u_int16_t *)(((vm_offset_t)(map)->handle) + \ + (vm_offset_t)(offset)) = htole16(val) +#define DRM_WRITE32(map, offset, val) \ + *(volatile u_int32_t *)(((vm_offset_t)(map)->handle) + \ + (vm_offset_t)(offset)) = htole32(val) +#define DRM_WRITE64(map, offset, val) \ + *(volatile u_int64_t *)(((vm_offset_t)(map)->handle) + \ + (vm_offset_t)(offset)) = htole64(val) + +/* 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 smp_rmb() rmb() +#define smp_mb__before_atomic_inc() mb() +#define smp_mb__after_atomic_inc() mb() #define do_div(a, b) ((a) /= (b)) +#define div64_u64(a, b) ((a) / (b)) #define lower_32_bits(n) ((u32)(n)) #define min_t(type, x, y) ({ \ @@ -70,11 +151,14 @@ typedef int32_t __be32; /* XXXKIB what is the right code for the FreeBSD ? */ /* kib@ used ENXIO here -- dumbbell@ */ #define EREMOTEIO EIO -#define ERESTARTSYS ERESTART +#define ERESTARTSYS 512 /* Same value as Linux. */ #define KTR_DRM KTR_DEV #define KTR_DRM_REG KTR_SPARE3 +#define DRM_AGP_KERN struct agp_info +#define DRM_AGP_MEM void + #define PCI_VENDOR_ID_APPLE 0x106b #define PCI_VENDOR_ID_ASUSTEK 0x1043 #define PCI_VENDOR_ID_ATI 0x1002 @@ -92,6 +176,7 @@ typedef int32_t __be32; static inline unsigned long roundup_pow_of_two(unsigned long x) { + return (1UL << flsl(x - 1)); } @@ -102,8 +187,10 @@ roundup_pow_of_two(unsigned long x) * * Source: include/linux/bitops.h */ -static inline uint32_t ror32(uint32_t word, unsigned int shift) +static inline uint32_t +ror32(uint32_t word, unsigned int shift) { + return (word >> shift) | (word << (32 - shift)); } @@ -116,31 +203,184 @@ static inline uint32_t ror32(uint32_t word, unsigned int shift) /* Taken from linux/include/linux/unaligned/le_struct.h. */ struct __una_u32 { u32 x; } __packed; -static inline u32 __get_unaligned_cpu32(const void *p) +static inline u32 +__get_unaligned_cpu32(const void *p) { const struct __una_u32 *ptr = (const struct __una_u32 *)p; - return ptr->x; + + return (ptr->x); } -static inline u32 get_unaligned_le32(const void *p) +static inline u32 +get_unaligned_le32(const void *p) { - return __get_unaligned_cpu32((const u8 *)p); + + return (__get_unaligned_cpu32((const u8 *)p)); } #else /* Taken from linux/include/linux/unaligned/le_byteshift.h. */ -static inline u32 __get_unaligned_le32(const u8 *p) +static inline u32 +__get_unaligned_le32(const u8 *p) +{ + + return (p[0] | p[1] << 8 | p[2] << 16 | p[3] << 24); +} + +static inline u32 +get_unaligned_le32(const void *p) +{ + + return (__get_unaligned_le32((const u8 *)p)); +} +#endif + +static inline unsigned long +ilog2(unsigned long x) +{ + + return (flsl(x) - 1); +} + +static inline int64_t +abs64(int64_t x) +{ + + return (x < 0 ? -x : x); +} + +int64_t timeval_to_ns(const struct timeval *tv); +struct timeval ns_to_timeval(const int64_t nsec); + +#define PAGE_ALIGN(addr) round_page(addr) + +#define drm_get_device_from_kdev(_kdev) (((struct drm_minor *)(_kdev)->si_drv1)->dev) + +#define DRM_IOC_VOID IOC_VOID +#define DRM_IOC_READ IOC_OUT +#define DRM_IOC_WRITE IOC_IN +#define DRM_IOC_READWRITE IOC_INOUT +#define DRM_IOC(dir, group, nr, size) _IOC(dir, group, nr, size) + +static inline long +__copy_to_user(void __user *to, const void *from, unsigned long n) +{ + return (copyout(from, to, n) != 0 ? n : 0); +} +#define copy_to_user(to, from, n) __copy_to_user((to), (from), (n)) + +static inline int +__put_user(size_t size, void *ptr, void *x) { - return p[0] | p[1] << 8 | p[2] << 16 | p[3] << 24; + + size = copy_to_user(ptr, x, size); + + return (size ? -EFAULT : size); } +#define put_user(x, ptr) __put_user(sizeof(*ptr), (ptr), &(x)) -static inline u32 get_unaligned_le32(const void *p) +static inline unsigned long +__copy_from_user(void *to, const void __user *from, unsigned long n) { - return __get_unaligned_le32((const u8 *)p); + return ((copyin(__DECONST(void *, from), to, n) != 0 ? n : 0)); } +#define copy_from_user(to, from, n) __copy_from_user((to), (from), (n)) + +static inline int +__get_user(size_t size, const void *ptr, void *x) +{ + + size = copy_from_user(x, ptr, size); + + return (size ? -EFAULT : size); +} +#define get_user(x, ptr) __get_user(sizeof(*ptr), (ptr), &(x)) + +#define sigemptyset(set) SIGEMPTYSET(set) +#define sigaddset(set, sig) SIGADDSET(set, sig) + +#define DRM_LOCK(dev) sx_xlock(&(dev)->dev_struct_lock) +#define DRM_UNLOCK(dev) sx_xunlock(&(dev)->dev_struct_lock) + +#define jiffies ticks +#define jiffies_to_msecs(x) (((int64_t)(x)) * 1000 / hz) +#define msecs_to_jiffies(x) (((int64_t)(x)) * hz / 1000) +#define time_after(a,b) ((long)(b) - (long)(a) < 0) +#define time_after_eq(a,b) ((long)(b) - (long)(a) <= 0) + +#define wake_up(queue) wakeup((void *)queue) +#define wake_up_interruptible(queue) wakeup((void *)queue) + +MALLOC_DECLARE(DRM_MEM_DMA); +MALLOC_DECLARE(DRM_MEM_SAREA); +MALLOC_DECLARE(DRM_MEM_DRIVER); +MALLOC_DECLARE(DRM_MEM_MAGIC); +MALLOC_DECLARE(DRM_MEM_MINOR); +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_MM); +MALLOC_DECLARE(DRM_MEM_HASHTAB); +MALLOC_DECLARE(DRM_MEM_KMS); +MALLOC_DECLARE(DRM_MEM_VBLANK); + +#define simple_strtol(a, b, c) strtol((a), (b), (c)) + +typedef struct drm_pci_id_list +{ + int vendor; + int device; + long driver_private; + char *name; +} drm_pci_id_list_t; + +#ifdef __i386__ +#define CONFIG_X86 1 +#endif +#ifdef __amd64__ +#define CONFIG_X86 1 +#define CONFIG_X86_64 1 #endif +#ifdef __ia64__ +#define CONFIG_IA64 1 +#endif + +#if defined(__i386__) || defined(__amd64__) +#define CONFIG_ACPI +#endif + +#define CONFIG_AGP 1 +#define CONFIG_MTRR 1 + +#define CONFIG_FB 1 +extern const char *fb_mode_option; + +#define EXPORT_SYMBOL(x) +#define MODULE_AUTHOR(author) +#define MODULE_DESCRIPTION(desc) +#define MODULE_LICENSE(license) +#define MODULE_PARM_DESC(name, desc) +#define module_param_named(name, var, type, perm) + +#define printk printf +#define KERN_DEBUG "" + +struct fb_info * framebuffer_alloc(void); +void framebuffer_release(struct fb_info *info); #define KIB_NOTYET() \ do { \ - if (drm_debug_flag && drm_notyet_flag) \ + if (drm_debug && drm_notyet) \ printf("NOTYET: %s at %s:%d\n", __func__, __FILE__, __LINE__); \ } while (0) + +#endif /* _DRM_OS_FREEBSD_H_ */ diff --git a/sys/dev/drm2/drm_pci.c b/sys/dev/drm2/drm_pci.c index 40431fafd5c5..f2c5bbd2dc5e 100644 --- a/sys/dev/drm2/drm_pci.c +++ b/sys/dev/drm2/drm_pci.c @@ -1,5 +1,20 @@ -/*- - * Copyright 2003 Eric Anholt. +/* drm_pci.h -- PCI DMA memory management wrappers for DRM -*- linux-c -*- */ +/** + * \file drm_pci.c + * \brief Functions and ioctls to manage PCI memory + * + * \warning These interfaces aren't stable yet. + * + * \todo Implement the remaining ioctl's for the PCI pools. + * \todo The wrappers here are so thin that they would be better off inlined.. + * + * \author José Fonseca <jrfonseca@tungstengraphics.com> + * \author Leif Delgass <ldelgass@retinalburn.net> + */ + +/* + * Copyright 2003 José Fonseca. + * Copyright 2003 Leif Delgass. * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a @@ -16,7 +31,7 @@ * 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 THE - * AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * AUTHORS 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. */ @@ -24,15 +39,13 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); -/** - * \file drm_pci.h - * \brief PCI consistent, DMA-accessible memory allocation. - * - * \author Eric Anholt <anholt@FreeBSD.org> - */ - #include <dev/drm2/drmP.h> +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"); + /**********************************************************************/ /** \name PCI memory */ /*@{*/ @@ -50,12 +63,10 @@ drm_pci_busdma_callback(void *arg, bus_dma_segment_t *segs, int nsegs, int error } /** - * \brief Allocate a physically contiguous DMA-accessible consistent - * memory block. + * \brief Allocate a PCI consistent memory block, for DMA. */ -drm_dma_handle_t * -drm_pci_alloc(struct drm_device *dev, size_t size, - size_t align, dma_addr_t maxaddr) +drm_dma_handle_t *drm_pci_alloc(struct drm_device * dev, size_t size, + size_t align, dma_addr_t maxaddr) { drm_dma_handle_t *dmah; int ret; @@ -77,7 +88,7 @@ drm_pci_alloc(struct drm_device *dev, size_t size, DRM_ERROR("called while holding dma_lock\n"); ret = bus_dma_tag_create( - bus_get_dma_tag(dev->device), /* parent */ + bus_get_dma_tag(dev->dev), /* parent */ align, 0, /* align, boundary */ maxaddr, BUS_SPACE_MAXADDR, /* lowaddr, highaddr */ NULL, NULL, /* filtfunc, filtfuncargs */ @@ -109,11 +120,14 @@ drm_pci_alloc(struct drm_device *dev, size_t size, return dmah; } +EXPORT_SYMBOL(drm_pci_alloc); + /** - * \brief Free a DMA-accessible consistent memory block. + * \brief Free a PCI consistent memory block without freeing its descriptor. + * + * This function is for internal use in the Linux-specific DRM core code. */ -void -drm_pci_free(struct drm_device *dev, drm_dma_handle_t *dmah) +void __drm_pci_free(struct drm_device * dev, drm_dma_handle_t * dmah) { if (dmah == NULL) return; @@ -121,11 +135,306 @@ drm_pci_free(struct drm_device *dev, drm_dma_handle_t *dmah) bus_dmamap_unload(dmah->tag, dmah->map); bus_dmamem_free(dmah->tag, dmah->vaddr, dmah->map); bus_dma_tag_destroy(dmah->tag); +} +/** + * \brief Free a PCI consistent memory block + */ +void drm_pci_free(struct drm_device * dev, drm_dma_handle_t * dmah) +{ + __drm_pci_free(dev, dmah); free(dmah, DRM_MEM_DMA); } -/*@}*/ +EXPORT_SYMBOL(drm_pci_free); + +static int drm_get_pci_domain(struct drm_device *dev) +{ + return dev->pci_domain; +} + +static int drm_pci_get_irq(struct drm_device *dev) +{ + + if (dev->irqr) + return (dev->irq); + + dev->irqr = bus_alloc_resource_any(dev->dev, SYS_RES_IRQ, + &dev->irqrid, RF_SHAREABLE); + if (!dev->irqr) { + dev_err(dev->dev, "Failed to allocate IRQ\n"); + return (0); + } + + dev->irq = (int) rman_get_start(dev->irqr); + + return (dev->irq); +} + +static void drm_pci_free_irq(struct drm_device *dev) +{ + if (dev->irqr == NULL) + return; + + bus_release_resource(dev->dev, SYS_RES_IRQ, + dev->irqrid, dev->irqr); + + dev->irqr = NULL; + dev->irq = 0; +} + +static const char *drm_pci_get_name(struct drm_device *dev) +{ + return dev->driver->name; +} + +int drm_pci_set_busid(struct drm_device *dev, struct drm_master *master) +{ + int len, ret; + master->unique_len = 40; + master->unique_size = master->unique_len; + master->unique = malloc(master->unique_size, DRM_MEM_DRIVER, M_NOWAIT); + if (master->unique == NULL) + return -ENOMEM; + + + len = snprintf(master->unique, master->unique_len, + "pci:%04x:%02x:%02x.%d", + dev->pci_domain, + dev->pci_bus, + dev->pci_slot, + dev->pci_func); + + if (len >= master->unique_len) { + DRM_ERROR("buffer overflow"); + ret = -EINVAL; + goto err; + } else + master->unique_len = len; + + return 0; +err: + return ret; +} + +int drm_pci_set_unique(struct drm_device *dev, + struct drm_master *master, + struct drm_unique *u) +{ + int domain, bus, slot, func, ret; + + master->unique_len = u->unique_len; + master->unique_size = u->unique_len + 1; + master->unique = malloc(master->unique_size, DRM_MEM_DRIVER, M_WAITOK); + if (!master->unique) { + ret = -ENOMEM; + goto err; + } + + if (copy_from_user(master->unique, u->unique, master->unique_len)) { + ret = -EFAULT; + goto err; + } + + master->unique[master->unique_len] = '\0'; + + /* Return error if the busid submitted doesn't match the device's actual + * busid. + */ + ret = sscanf(master->unique, "PCI:%d:%d:%d", &bus, &slot, &func); + if (ret != 3) { + ret = -EINVAL; + goto err; + } + + domain = bus >> 8; + bus &= 0xff; + + if ((domain != dev->pci_domain) || + (bus != dev->pci_bus) || + (slot != dev->pci_slot) || + (func != dev->pci_func)) { + ret = -EINVAL; + goto err; + } + return 0; +err: + return ret; +} + + +static int drm_pci_irq_by_busid(struct drm_device *dev, struct drm_irq_busid *p) +{ + if ((p->busnum >> 8) != drm_get_pci_domain(dev) || + (p->busnum & 0xff) != dev->pci_bus || + p->devnum != dev->pci_slot || p->funcnum != dev->pci_func) + return -EINVAL; + + p->irq = dev->irq; + + DRM_DEBUG("%d:%d:%d => IRQ %d\n", p->busnum, p->devnum, p->funcnum, + p->irq); + return 0; +} + +int drm_pci_agp_init(struct drm_device *dev) +{ + if (drm_core_has_AGP(dev)) { + if (drm_pci_device_is_agp(dev)) + dev->agp = drm_agp_init(dev); + if (drm_core_check_feature(dev, DRIVER_REQUIRE_AGP) + && (dev->agp == NULL)) { + DRM_ERROR("Cannot initialize the agpgart module.\n"); + return -EINVAL; + } + if (drm_core_has_MTRR(dev)) { + if (dev->agp && dev->agp->agp_info.ai_aperture_base != 0) { + if (drm_mtrr_add(dev->agp->agp_info.ai_aperture_base, + dev->agp->agp_info.ai_aperture_size, DRM_MTRR_WC) == 0) + dev->agp->agp_mtrr = 1; + else + dev->agp->agp_mtrr = -1; + } + } + } + return 0; +} + +static struct drm_bus drm_pci_bus = { + .bus_type = DRIVER_BUS_PCI, + .get_irq = drm_pci_get_irq, + .free_irq = drm_pci_free_irq, + .get_name = drm_pci_get_name, + .set_busid = drm_pci_set_busid, + .set_unique = drm_pci_set_unique, + .irq_by_busid = drm_pci_irq_by_busid, + .agp_init = drm_pci_agp_init, +}; + +/** + * Register. + * + * \param pdev - PCI device structure + * \param ent entry from the PCI ID table with device type flags + * \return zero on success or a negative number on failure. + * + * Attempt to gets inter module "drm" information. If we are first + * then register the character device and inter module information. + * Try and register, if we fail to register, backout previous work. + */ +int drm_get_pci_dev(device_t kdev, struct drm_device *dev, + struct drm_driver *driver) +{ + int ret; + + DRM_DEBUG("\n"); + + driver->bus = &drm_pci_bus; + + dev->dev = kdev; + + dev->pci_domain = pci_get_domain(dev->dev); + dev->pci_bus = pci_get_bus(dev->dev); + dev->pci_slot = pci_get_slot(dev->dev); + dev->pci_func = pci_get_function(dev->dev); + + dev->pci_vendor = pci_get_vendor(dev->dev); + dev->pci_device = pci_get_device(dev->dev); + dev->pci_subvendor = pci_get_subvendor(dev->dev); + dev->pci_subdevice = pci_get_subdevice(dev->dev); + + sx_xlock(&drm_global_mutex); + + if ((ret = drm_fill_in_dev(dev, driver))) { + DRM_ERROR("Failed to fill in dev: %d\n", ret); + goto err_g1; + } + + if (drm_core_check_feature(dev, DRIVER_MODESET)) { + ret = drm_get_minor(dev, &dev->control, DRM_MINOR_CONTROL); + if (ret) + goto err_g2; + } + + if ((ret = drm_get_minor(dev, &dev->primary, DRM_MINOR_LEGACY))) + goto err_g3; + + if (dev->driver->load) { + ret = dev->driver->load(dev, + dev->id_entry->driver_private); + if (ret) + goto err_g4; + } + + /* setup the grouping for the legacy output */ + if (drm_core_check_feature(dev, DRIVER_MODESET)) { + ret = drm_mode_group_init_legacy_group(dev, + &dev->primary->mode_group); + if (ret) + goto err_g5; + } + +#ifdef FREEBSD_NOTYET + list_add_tail(&dev->driver_item, &driver->device_list); +#endif /* FREEBSD_NOTYET */ + + DRM_INFO("Initialized %s %d.%d.%d %s for %s on minor %d\n", + driver->name, driver->major, driver->minor, driver->patchlevel, + driver->date, device_get_nameunit(dev->dev), dev->primary->index); + + sx_xunlock(&drm_global_mutex); + return 0; + +err_g5: + if (dev->driver->unload) + dev->driver->unload(dev); +err_g4: + drm_put_minor(&dev->primary); +err_g3: + if (drm_core_check_feature(dev, DRIVER_MODESET)) + drm_put_minor(&dev->control); +err_g2: + drm_cancel_fill_in_dev(dev); +err_g1: + sx_xunlock(&drm_global_mutex); + return ret; +} +EXPORT_SYMBOL(drm_get_pci_dev); + +int +drm_pci_enable_msi(struct drm_device *dev) +{ + int msicount, ret; + + if (!drm_msi) + return (-ENOENT); + + msicount = pci_msi_count(dev->dev); + DRM_DEBUG("MSI count = %d\n", msicount); + if (msicount > 1) + msicount = 1; + + ret = pci_alloc_msi(dev->dev, &msicount); + if (ret == 0) { + DRM_INFO("MSI enabled %d message(s)\n", msicount); + dev->msi_enabled = 1; + dev->irqrid = 1; + } + + return (-ret); +} + +void +drm_pci_disable_msi(struct drm_device *dev) +{ + + if (!dev->msi_enabled) + return; + + pci_release_msi(dev->dev); + dev->msi_enabled = 0; + dev->irqrid = 0; +} int drm_pcie_get_speed_cap_mask(struct drm_device *dev, u32 *mask) { @@ -134,14 +443,14 @@ int drm_pcie_get_speed_cap_mask(struct drm_device *dev, u32 *mask) u32 lnkcap = 0, lnkcap2 = 0; *mask = 0; - if (!drm_device_is_pcie(dev)) + if (!drm_pci_device_is_pcie(dev)) return -EINVAL; root = device_get_parent( /* pcib */ device_get_parent( /* `-- pci */ device_get_parent( /* `-- vgapci */ - dev->device))); /* `-- drmn */ + dev->dev))); /* `-- drmn */ pos = 0; pci_find_cap(root, PCIY_EXPRESS, &pos); @@ -180,3 +489,4 @@ int drm_pcie_get_speed_cap_mask(struct drm_device *dev, u32 *mask) DRM_INFO("probing gen 2 caps for device %x:%x = %x/%x\n", pci_get_vendor(root), pci_get_device(root), lnkcap, lnkcap2); return 0; } +EXPORT_SYMBOL(drm_pcie_get_speed_cap_mask); diff --git a/sys/dev/drm2/drm_pciids.h b/sys/dev/drm2/drm_pciids.h index cad56a161ce3..92591d2f59ec 100644 --- a/sys/dev/drm2/drm_pciids.h +++ b/sys/dev/drm2/drm_pciids.h @@ -49,12 +49,12 @@ {0x8086, 0x0166, CHIP_I9XX|CHIP_I915, "Intel IvyBridge (M)"}, \ {0x8086, 0x016A, CHIP_I9XX|CHIP_I915, "Intel IvyBridge (S)"}, \ {0x8086, 0x0402, CHIP_I9XX|CHIP_I915, "Intel Haswell"}, \ - {0x8086, 0x0412, CHIP_I9XX|CHIP_I915, "Intel Haswell"}, \ - {0x8086, 0x040a, CHIP_I9XX|CHIP_I915, "Intel Haswell (S)"}, \ - {0x8086, 0x041a, CHIP_I9XX|CHIP_I915, "Intel Haswell (S)"}, \ {0x8086, 0x0406, CHIP_I9XX|CHIP_I915, "Intel Haswell (M)"}, \ + {0x8086, 0x040A, CHIP_I9XX|CHIP_I915, "Intel Haswell (S)"}, \ + {0x8086, 0x0412, CHIP_I9XX|CHIP_I915, "Intel Haswell"}, \ {0x8086, 0x0416, CHIP_I9XX|CHIP_I915, "Intel Haswell (M)"}, \ - {0x8086, 0x0c16, CHIP_I9XX|CHIP_I915, "Intel Haswell (SDV)"}, \ + {0x8086, 0x041A, CHIP_I9XX|CHIP_I915, "Intel Haswell (S)"}, \ + {0x8086, 0x0C16, CHIP_I9XX|CHIP_I915, "Intel Haswell (SDV)"}, \ {0x8086, 0x2562, CHIP_I8XX, "Intel i845G GMCH"}, \ {0x8086, 0x2572, CHIP_I8XX, "Intel i865G GMCH"}, \ {0x8086, 0x2582, CHIP_I9XX|CHIP_I915, "Intel i915G"}, \ @@ -574,6 +574,7 @@ {0x1002, 0x6819, CHIP_PITCAIRN|RADEON_NEW_MEMMAP, "Pitcairn PRO [Radeon HD 7800]"}, \ {0x1002, 0x6820, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "Radeon HD 8800M Series"}, \ {0x1002, 0x6821, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "Radeon HD 8800M Series"}, \ + {0x1002, 0x6822, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "Venus PRO [Radeon E8860]"}, \ {0x1002, 0x6823, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "Radeon HD 8800M Series"}, \ {0x1002, 0x6824, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "Chelsea [Radeon HD 7700M Series]"}, \ {0x1002, 0x6825, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "Cape Verde [Radeon HD 7800M Series]"}, \ @@ -581,11 +582,13 @@ {0x1002, 0x6827, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "Cape Verde [Radeon HD 7800M Series]"}, \ {0x1002, 0x6828, CHIP_VERDE|RADEON_NEW_MEMMAP, "Cape Verde"}, \ {0x1002, 0x6829, CHIP_VERDE|RADEON_NEW_MEMMAP, "Cape Verde"}, \ + {0x1002, 0x682A, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "Venus PRO"}, \ {0x1002, 0x682B, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "Radeon HD 8800M Series"}, \ {0x1002, 0x682D, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "Unknown device name"}, \ {0x1002, 0x682F, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "Cape Verde [Radeon HD 7700M Series]"}, \ {0x1002, 0x6830, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "Cape Verde [Radeon HD 7800M Series]"}, \ {0x1002, 0x6831, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP, "Cape Verde [AMD Radeon HD 7700M Series]"}, \ + {0x1002, 0x6835, CHIP_VERDE|RADEON_NEW_MEMMAP, "Cape Verde PRX [Radeon R9 255 OEM]"}, \ {0x1002, 0x6837, CHIP_VERDE|RADEON_NEW_MEMMAP, "Cape Verde LE [Radeon HD 7700 Series]"}, \ {0x1002, 0x6838, CHIP_VERDE|RADEON_NEW_MEMMAP, "Cape Verde"}, \ {0x1002, 0x6839, CHIP_VERDE|RADEON_NEW_MEMMAP, "Cape Verde"}, \ @@ -915,6 +918,10 @@ {0x1002, 0x9908, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP, "Trinity [Radeon HD 7600G]"}, \ {0x1002, 0x9909, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP, "Trinity [Radeon HD 7500G]"}, \ {0x1002, 0x990A, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP, "Trinity [Radeon HD 7500G]"}, \ + {0x1002, 0x990B, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP, "Richland [Radeon HD 8650G]"}, \ + {0x1002, 0x990C, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP, "Richland [Radeon HD 8670D]"}, \ + {0x1002, 0x990D, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP, "Richland [Radeon HD 8550G]"}, \ + {0x1002, 0x990E, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP, "Richland [Radeon HD 8570D]"}, \ {0x1002, 0x990F, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP, "Unknown device name"}, \ {0x1002, 0x9910, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP, "Trinity [Radeon HD 7660G]"}, \ {0x1002, 0x9913, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP, "Trinity [Radeon HD 7640G]"}, \ @@ -926,6 +933,15 @@ {0x1002, 0x9992, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP, "Trinity [Radeon HD 7420G]"}, \ {0x1002, 0x9993, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP, "Trinity [Radeon HD 7480D]"}, \ {0x1002, 0x9994, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP, "Trinity [Radeon HD 7400G]"}, \ + {0x1002, 0x9995, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP, "Richland [Radeon HD 8450G]"}, \ + {0x1002, 0x9996, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP, "Richland [Radeon HD 8470D]"}, \ + {0x1002, 0x9997, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP, "Richland [Radeon HD 8350G]"}, \ + {0x1002, 0x9998, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP, "Richland [Radeon HD 8370D]"}, \ + {0x1002, 0x9999, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP, "Richland [Radeon HD 8510G]"}, \ + {0x1002, 0x999A, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP, "Richland [Radeon HD 8410G]"}, \ + {0x1002, 0x999B, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP, "Richland [Radeon HD 8310G]"}, \ + {0x1002, 0x999C, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP, "Richland"}, \ + {0x1002, 0x999D, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP, "Richland [Radeon HD 8550D]"}, \ {0x1002, 0x99A0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP, "Trinity [Radeon HD 7520G]"}, \ {0x1002, 0x99A2, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP, "Trinity [Radeon HD 7420G]"}, \ {0x1002, 0x99A4, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP, "Trinity [Radeon HD 7400G]"}, \ diff --git a/sys/dev/drm2/drm_sarea.h b/sys/dev/drm2/drm_sarea.h index f800cfee96a2..72f52dd737ba 100644 --- a/sys/dev/drm2/drm_sarea.h +++ b/sys/dev/drm2/drm_sarea.h @@ -39,10 +39,12 @@ __FBSDID("$FreeBSD$"); /* SAREA area needs to be at least a page */ #if defined(__alpha__) -#define SAREA_MAX 0x2000 +#define SAREA_MAX 0x2000U +#elif defined(__mips__) +#define SAREA_MAX 0x4000U #else /* Intel 830M driver needs at least 8k SAREA */ -#define SAREA_MAX 0x2000UL +#define SAREA_MAX 0x2000U #endif /** Maximum number of drawables in the SAREA */ diff --git a/sys/dev/drm2/drm_scatter.c b/sys/dev/drm2/drm_scatter.c index 3ff923cbc01a..9be3cb17c7d6 100644 --- a/sys/dev/drm2/drm_scatter.c +++ b/sys/dev/drm2/drm_scatter.c @@ -33,97 +33,104 @@ __FBSDID("$FreeBSD$"); #include <dev/drm2/drmP.h> -int -drm_sg_alloc(struct drm_device *dev, struct drm_scatter_gather *request) +#define DEBUG_SCATTER 0 + +static inline vm_offset_t drm_vmalloc_dma(vm_size_t size) +{ + return kmem_alloc_attr(kernel_arena, size, M_NOWAIT | M_ZERO, + 0, BUS_SPACE_MAXADDR_32BIT, VM_MEMATTR_WRITE_COMBINING); +} + +void drm_sg_cleanup(struct drm_sg_mem * entry) +{ + if (entry == NULL) + return; + + if (entry->vaddr != 0) + kmem_free(kernel_arena, entry->vaddr, IDX_TO_OFF(entry->pages)); + + free(entry->busaddr, DRM_MEM_SGLISTS); + free(entry, DRM_MEM_DRIVER); +} + +int drm_sg_alloc(struct drm_device *dev, struct drm_scatter_gather * request) { struct drm_sg_mem *entry; vm_size_t size; vm_pindex_t pindex; + DRM_DEBUG("\n"); + + if (!drm_core_check_feature(dev, DRIVER_SG)) + return -EINVAL; + if (dev->sg) - return EINVAL; + return -EINVAL; - DRM_DEBUG("request size=%ld\n", request->size); + entry = malloc(sizeof(*entry), DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); + if (!entry) + return -ENOMEM; - entry = malloc(sizeof(*entry), DRM_MEM_DRIVER, M_WAITOK | M_ZERO); + DRM_DEBUG("request size=%ld\n", request->size); size = round_page(request->size); entry->pages = OFF_TO_IDX(size); entry->busaddr = malloc(entry->pages * sizeof(*entry->busaddr), - DRM_MEM_SGLISTS, M_WAITOK | M_ZERO); + DRM_MEM_SGLISTS, M_NOWAIT | M_ZERO); + if (!entry->busaddr) { + free(entry, DRM_MEM_DRIVER); + return -ENOMEM; + } - entry->vaddr = kmem_alloc_attr(kernel_arena, size, M_WAITOK | M_ZERO, - 0, BUS_SPACE_MAXADDR_32BIT, VM_MEMATTR_WRITE_COMBINING); + entry->vaddr = drm_vmalloc_dma(size); if (entry->vaddr == 0) { - drm_sg_cleanup(entry); - return (ENOMEM); + free(entry->busaddr, DRM_MEM_DRIVER); + free(entry, DRM_MEM_DRIVER); + return -ENOMEM; } - for(pindex = 0; pindex < entry->pages; pindex++) { + for (pindex = 0; pindex < entry->pages; pindex++) { entry->busaddr[pindex] = vtophys(entry->vaddr + IDX_TO_OFF(pindex)); } - DRM_LOCK(dev); - if (dev->sg) { - DRM_UNLOCK(dev); - drm_sg_cleanup(entry); - return (EINVAL); - } - dev->sg = entry; - DRM_UNLOCK(dev); - request->handle = entry->vaddr; + dev->sg = entry; + DRM_DEBUG("allocated %ju pages @ 0x%08zx, contents=%08lx\n", entry->pages, entry->vaddr, *(unsigned long *)entry->vaddr); - return (0); + return 0; } -int -drm_sg_alloc_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) +int drm_sg_alloc_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) { struct drm_scatter_gather *request = data; - DRM_DEBUG("\n"); + return drm_sg_alloc(dev, request); - return (drm_sg_alloc(dev, request)); } -void -drm_sg_cleanup(struct drm_sg_mem *entry) -{ - if (entry == NULL) - return; - - if (entry->vaddr != 0) - kmem_free(kernel_arena, entry->vaddr, IDX_TO_OFF(entry->pages)); - - free(entry->busaddr, DRM_MEM_SGLISTS); - free(entry, DRM_MEM_DRIVER); - - return; -} - -int -drm_sg_free(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) { struct drm_scatter_gather *request = data; struct drm_sg_mem *entry; - DRM_LOCK(dev); + if (!drm_core_check_feature(dev, DRIVER_SG)) + return -EINVAL; + entry = dev->sg; dev->sg = NULL; - DRM_UNLOCK(dev); if (!entry || entry->vaddr != request->handle) - return (EINVAL); + return -EINVAL; DRM_DEBUG("free 0x%zx\n", entry->vaddr); drm_sg_cleanup(entry); - return (0); + return 0; } diff --git a/sys/dev/drm2/drm_sman.c b/sys/dev/drm2/drm_sman.c deleted file mode 100644 index 1c1e4af32259..000000000000 --- a/sys/dev/drm2/drm_sman.c +++ /dev/null @@ -1,352 +0,0 @@ -/************************************************************************** - * - * Copyright 2006 Tungsten Graphics, Inc., Bismarck., ND., USA. - * 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, sub license, 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 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 NON-INFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDERS, AUTHORS 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. - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * - **************************************************************************/ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -/* - * Simple memory manager interface that keeps track on allocate regions on a - * per "owner" basis. All regions associated with an "owner" can be released - * with a simple call. Typically if the "owner" exists. The owner is any - * "unsigned long" identifier. Can typically be a pointer to a file private - * struct or a context identifier. - * - * Authors: - * Thomas Hellström <thomas-at-tungstengraphics-dot-com> - */ - -#include <dev/drm2/drmP.h> -#include <dev/drm2/drm_sman.h> - -struct drm_owner_item { - struct drm_hash_item owner_hash; - struct list_head sman_list; - struct list_head mem_blocks; -}; - -void drm_sman_takedown(struct drm_sman * sman) -{ - drm_ht_remove(&sman->user_hash_tab); - drm_ht_remove(&sman->owner_hash_tab); - if (sman->mm) - drm_free(sman->mm, sman->num_managers * sizeof(*sman->mm), - DRM_MEM_MM); -} - -int -drm_sman_init(struct drm_sman * sman, unsigned int num_managers, - unsigned int user_order, unsigned int owner_order) -{ - int ret = 0; - - sman->mm = (struct drm_sman_mm *) drm_calloc(num_managers, - sizeof(*sman->mm), DRM_MEM_MM); - if (!sman->mm) { - ret = -ENOMEM; - goto out; - } - sman->num_managers = num_managers; - INIT_LIST_HEAD(&sman->owner_items); - ret = drm_ht_create(&sman->owner_hash_tab, owner_order); - if (ret) - goto out1; - ret = drm_ht_create(&sman->user_hash_tab, user_order); - if (!ret) - goto out; - - drm_ht_remove(&sman->owner_hash_tab); -out1: - drm_free(sman->mm, num_managers * sizeof(*sman->mm), DRM_MEM_MM); -out: - return ret; -} - -static void *drm_sman_mm_allocate(void *private, unsigned long size, - unsigned alignment) -{ - struct drm_mm *mm = (struct drm_mm *) private; - struct drm_mm_node *tmp; - - tmp = drm_mm_search_free(mm, size, alignment, 1); - if (!tmp) { - return NULL; - } - /* This could be non-atomic, but we are called from a locked path */ - tmp = drm_mm_get_block_atomic(tmp, size, alignment); - return tmp; -} - -static void drm_sman_mm_free(void *private, void *ref) -{ - struct drm_mm_node *node = (struct drm_mm_node *) ref; - - drm_mm_put_block(node); -} - -static void drm_sman_mm_destroy(void *private) -{ - struct drm_mm *mm = (struct drm_mm *) private; - drm_mm_takedown(mm); - drm_free(mm, sizeof(*mm), DRM_MEM_MM); -} - -static unsigned long drm_sman_mm_offset(void *private, void *ref) -{ - struct drm_mm_node *node = (struct drm_mm_node *) ref; - return node->start; -} - -int -drm_sman_set_range(struct drm_sman * sman, unsigned int manager, - unsigned long start, unsigned long size) -{ - struct drm_sman_mm *sman_mm; - struct drm_mm *mm; - int ret; - - KASSERT(manager < sman->num_managers, ("Invalid manager")); - - sman_mm = &sman->mm[manager]; - mm = malloc(sizeof(*mm), DRM_MEM_MM, M_NOWAIT | M_ZERO); - if (!mm) { - return -ENOMEM; - } - sman_mm->private = mm; - ret = drm_mm_init(mm, start, size); - - if (ret) { - drm_free(mm, sizeof(*mm), DRM_MEM_MM); - return ret; - } - - sman_mm->allocate = drm_sman_mm_allocate; - sman_mm->free = drm_sman_mm_free; - sman_mm->destroy = drm_sman_mm_destroy; - sman_mm->offset = drm_sman_mm_offset; - - return 0; -} - -int -drm_sman_set_manager(struct drm_sman * sman, unsigned int manager, - struct drm_sman_mm * allocator) -{ - KASSERT(manager < sman->num_managers, ("Invalid manager")); - sman->mm[manager] = *allocator; - - return 0; -} - -static struct drm_owner_item *drm_sman_get_owner_item(struct drm_sman * sman, - unsigned long owner) -{ - int ret; - struct drm_hash_item *owner_hash_item; - struct drm_owner_item *owner_item; - - ret = drm_ht_find_item(&sman->owner_hash_tab, owner, &owner_hash_item); - if (!ret) { - return drm_hash_entry(owner_hash_item, struct drm_owner_item, - owner_hash); - } - - owner_item = malloc(sizeof(*owner_item), DRM_MEM_MM, M_NOWAIT | M_ZERO); - if (!owner_item) - goto out; - - INIT_LIST_HEAD(&owner_item->mem_blocks); - owner_item->owner_hash.key = owner; - DRM_DEBUG("owner_item = %p, mem_blocks = %p\n", owner_item, &owner_item->mem_blocks); - if (drm_ht_insert_item(&sman->owner_hash_tab, &owner_item->owner_hash)) - goto out1; - - list_add_tail(&owner_item->sman_list, &sman->owner_items); - return owner_item; - -out1: - drm_free(owner_item, sizeof(*owner_item), DRM_MEM_MM); -out: - return NULL; -} - -struct drm_memblock_item *drm_sman_alloc(struct drm_sman *sman, unsigned int manager, - unsigned long size, unsigned alignment, - unsigned long owner) -{ - void *tmp; - struct drm_sman_mm *sman_mm; - struct drm_owner_item *owner_item; - struct drm_memblock_item *memblock; - - KASSERT(manager < sman->num_managers, ("Invalid manager")); - - sman_mm = &sman->mm[manager]; - tmp = sman_mm->allocate(sman_mm->private, size, alignment); - if (!tmp) { - return NULL; - } - - memblock = malloc(sizeof(*memblock), DRM_MEM_MM, M_NOWAIT | M_ZERO); - DRM_DEBUG("allocated mem_block %p\n", memblock); - if (!memblock) - goto out; - - memblock->mm_info = tmp; - memblock->mm = sman_mm; - memblock->sman = sman; - INIT_LIST_HEAD(&memblock->owner_list); - - if (drm_ht_just_insert_please - (&sman->user_hash_tab, &memblock->user_hash, - (unsigned long)memblock, 32, 0, 0)) - goto out1; - - owner_item = drm_sman_get_owner_item(sman, owner); - if (!owner_item) - goto out2; - - DRM_DEBUG("owner_item = %p, mem_blocks = %p\n", owner_item, &owner_item->mem_blocks); - DRM_DEBUG("owner_list.prev = %p, mem_blocks.prev = %p\n", memblock->owner_list.prev, owner_item->mem_blocks.prev); - DRM_DEBUG("owner_list.next = %p, mem_blocks.next = %p\n", memblock->owner_list.next, owner_item->mem_blocks.next); - list_add_tail(&memblock->owner_list, &owner_item->mem_blocks); - - DRM_DEBUG("Complete\n"); - return memblock; - -out2: - drm_ht_remove_item(&sman->user_hash_tab, &memblock->user_hash); -out1: - drm_free(memblock, sizeof(*memblock), DRM_MEM_MM); -out: - sman_mm->free(sman_mm->private, tmp); - - return NULL; -} - -static void drm_sman_free(struct drm_memblock_item *item) -{ - struct drm_sman *sman = item->sman; - - list_del(&item->owner_list); - drm_ht_remove_item(&sman->user_hash_tab, &item->user_hash); - item->mm->free(item->mm->private, item->mm_info); - drm_free(item, sizeof(*item), DRM_MEM_MM); -} - -int drm_sman_free_key(struct drm_sman *sman, unsigned int key) -{ - struct drm_hash_item *hash_item; - struct drm_memblock_item *memblock_item; - - if (drm_ht_find_item(&sman->user_hash_tab, key, &hash_item)) - return -EINVAL; - - memblock_item = drm_hash_entry(hash_item, struct drm_memblock_item, - user_hash); - drm_sman_free(memblock_item); - return 0; -} - -static void drm_sman_remove_owner(struct drm_sman *sman, - struct drm_owner_item *owner_item) -{ - list_del(&owner_item->sman_list); - drm_ht_remove_item(&sman->owner_hash_tab, &owner_item->owner_hash); - drm_free(owner_item, sizeof(*owner_item), DRM_MEM_MM); -} - -int drm_sman_owner_clean(struct drm_sman *sman, unsigned long owner) -{ - - struct drm_hash_item *hash_item; - struct drm_owner_item *owner_item; - - if (drm_ht_find_item(&sman->owner_hash_tab, owner, &hash_item)) { - return -1; - } - - owner_item = drm_hash_entry(hash_item, struct drm_owner_item, owner_hash); - DRM_DEBUG("cleaning owner_item %p\n", owner_item); - if (owner_item->mem_blocks.next == &owner_item->mem_blocks) { - drm_sman_remove_owner(sman, owner_item); - return -1; - } - - return 0; -} - -static void drm_sman_do_owner_cleanup(struct drm_sman *sman, - struct drm_owner_item *owner_item) -{ - struct drm_memblock_item *entry, *next; - - list_for_each_entry_safe(entry, next, &owner_item->mem_blocks, - owner_list) { - DRM_DEBUG("freeing mem_block %p\n", entry); - drm_sman_free(entry); - } - drm_sman_remove_owner(sman, owner_item); -} - -void drm_sman_owner_cleanup(struct drm_sman *sman, unsigned long owner) -{ - - struct drm_hash_item *hash_item; - struct drm_owner_item *owner_item; - - if (drm_ht_find_item(&sman->owner_hash_tab, owner, &hash_item)) { - - return; - } - - owner_item = drm_hash_entry(hash_item, struct drm_owner_item, owner_hash); - drm_sman_do_owner_cleanup(sman, owner_item); -} - -void drm_sman_cleanup(struct drm_sman *sman) -{ - struct drm_owner_item *entry, *next; - unsigned int i; - struct drm_sman_mm *sman_mm; - - DRM_DEBUG("sman = %p, owner_items = %p\n", - sman, &sman->owner_items); - list_for_each_entry_safe(entry, next, &sman->owner_items, sman_list) { - DRM_DEBUG("cleaning owner_item = %p\n", entry); - drm_sman_do_owner_cleanup(sman, entry); - } - if (sman->mm) { - for (i = 0; i < sman->num_managers; ++i) { - sman_mm = &sman->mm[i]; - if (sman_mm->private) { - sman_mm->destroy(sman_mm->private); - sman_mm->private = NULL; - } - } - } -} diff --git a/sys/dev/drm2/drm_sman.h b/sys/dev/drm2/drm_sman.h deleted file mode 100644 index 3b1693fb0ba8..000000000000 --- a/sys/dev/drm2/drm_sman.h +++ /dev/null @@ -1,181 +0,0 @@ -/************************************************************************** - * - * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA. - * 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, sub license, 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 NON-INFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDERS, AUTHORS 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 <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -/* - * Simple memory MANager interface that keeps track on allocate regions on a - * per "owner" basis. All regions associated with an "owner" can be released - * with a simple call. Typically if the "owner" exists. The owner is any - * "unsigned long" identifier. Can typically be a pointer to a file private - * struct or a context identifier. - * - * Authors: - * Thomas Hellström <thomas-at-tungstengraphics-dot-com> - */ - -#ifndef DRM_SMAN_H -#define DRM_SMAN_H - -#include <dev/drm2/drm_hashtab.h> -#include <dev/drm2/drm_linux_list.h> -#include <dev/drm2/drm_mm.h> - -/* - * A class that is an abstration of a simple memory allocator. - * The sman implementation provides a default such allocator - * using the drm_mm.c implementation. But the user can replace it. - * See the SiS implementation, which may use the SiS FB kernel module - * for memory management. - */ - -struct drm_sman_mm { - /* private info. If allocated, needs to be destroyed by the destroy - function */ - void *private; - - /* Allocate a memory block with given size and alignment. - Return an opaque reference to the memory block */ - - void *(*allocate) (void *private, unsigned long size, - unsigned alignment); - - /* Free a memory block. "ref" is the opaque reference that we got from - the "alloc" function */ - - void (*free) (void *private, void *ref); - - /* Free all resources associated with this allocator */ - - void (*destroy) (void *private); - - /* Return a memory offset from the opaque reference returned from the - "alloc" function */ - - unsigned long (*offset) (void *private, void *ref); -}; - -struct drm_memblock_item { - struct list_head owner_list; - struct drm_hash_item user_hash; - void *mm_info; - struct drm_sman_mm *mm; - struct drm_sman *sman; -}; - -struct drm_sman { - struct drm_sman_mm *mm; - int num_managers; - struct drm_open_hash owner_hash_tab; - struct drm_open_hash user_hash_tab; - struct list_head owner_items; -}; - -/* - * Take down a memory manager. This function should only be called after a - * successful init and after a call to drm_sman_cleanup. - */ - -extern void drm_sman_takedown(struct drm_sman * sman); - -/* - * Allocate structures for a manager. - * num_managers are the number of memory pools to manage. (VRAM, AGP, ....) - * user_order is the log2 of the number of buckets in the user hash table. - * set this to approximately log2 of the max number of memory regions - * that will be allocated for _all_ pools together. - * owner_order is the log2 of the number of buckets in the owner hash table. - * set this to approximately log2 of - * the number of client file connections that will - * be using the manager. - * - */ - -extern int drm_sman_init(struct drm_sman * sman, unsigned int num_managers, - unsigned int user_order, unsigned int owner_order); - -/* - * Initialize a drm_mm.c allocator. Should be called only once for each - * manager unless a customized allogator is used. - */ - -extern int drm_sman_set_range(struct drm_sman * sman, unsigned int manager, - unsigned long start, unsigned long size); - -/* - * Initialize a customized allocator for one of the managers. - * (See the SiS module). The object pointed to by "allocator" is copied, - * so it can be destroyed after this call. - */ - -extern int drm_sman_set_manager(struct drm_sman * sman, unsigned int mananger, - struct drm_sman_mm * allocator); - -/* - * Allocate a memory block. Aligment is not implemented yet. - */ - -extern struct drm_memblock_item *drm_sman_alloc(struct drm_sman * sman, - unsigned int manager, - unsigned long size, - unsigned alignment, - unsigned long owner); -/* - * Free a memory block identified by its user hash key. - */ - -extern int drm_sman_free_key(struct drm_sman * sman, unsigned int key); - -/* - * returns 1 iff there are no stale memory blocks associated with this owner. - * Typically called to determine if we need to idle the hardware and call - * drm_sman_owner_cleanup. If there are no stale memory blocks, it removes all - * resources associated with owner. - */ - -extern int drm_sman_owner_clean(struct drm_sman * sman, unsigned long owner); - -/* - * Frees all stale memory blocks associated with this owner. Note that this - * requires that the hardware is finished with all blocks, so the graphics engine - * should be idled before this call is made. This function also frees - * any resources associated with "owner" and should be called when owner - * is not going to be referenced anymore. - */ - -extern void drm_sman_owner_cleanup(struct drm_sman * sman, unsigned long owner); - -/* - * Frees all stale memory blocks associated with the memory manager. - * See idling above. - */ - -extern void drm_sman_cleanup(struct drm_sman * sman); - -#endif diff --git a/sys/dev/drm2/drm_stub.c b/sys/dev/drm2/drm_stub.c index 6f6af51983d5..d7ec6cb31e0e 100644 --- a/sys/dev/drm2/drm_stub.c +++ b/sys/dev/drm2/drm_stub.c @@ -34,27 +34,468 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); -#include "drmP.h" +#include <dev/drm2/drmP.h> +#include <dev/drm2/drm_core.h> -int -drm_setmaster_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) +#ifdef DRM_DEBUG_DEFAULT_ON +unsigned int drm_debug = (DRM_DEBUGBITS_DEBUG | DRM_DEBUGBITS_KMS | + DRM_DEBUGBITS_FAILED_IOCTL); +#else +unsigned int drm_debug = 0; /* 1 to enable debug output */ +#endif +EXPORT_SYMBOL(drm_debug); + +unsigned int drm_notyet = 0; + +unsigned int drm_vblank_offdelay = 5000; /* Default to 5000 msecs. */ +EXPORT_SYMBOL(drm_vblank_offdelay); + +unsigned int drm_timestamp_precision = 20; /* Default to 20 usecs. */ +EXPORT_SYMBOL(drm_timestamp_precision); + +/* + * Default to use monotonic timestamps for wait-for-vblank and page-flip + * complete events. + */ +unsigned int drm_timestamp_monotonic = 1; + +MODULE_AUTHOR(CORE_AUTHOR); +MODULE_DESCRIPTION(CORE_DESC); +MODULE_LICENSE("GPL and additional rights"); +MODULE_PARM_DESC(debug, "Enable debug output"); +MODULE_PARM_DESC(vblankoffdelay, "Delay until vblank irq auto-disable [msecs]"); +MODULE_PARM_DESC(timestamp_precision_usec, "Max. error on timestamps [usecs]"); +MODULE_PARM_DESC(timestamp_monotonic, "Use monotonic timestamps"); + +module_param_named(debug, drm_debug, int, 0600); +module_param_named(vblankoffdelay, drm_vblank_offdelay, int, 0600); +module_param_named(timestamp_precision_usec, drm_timestamp_precision, int, 0600); +module_param_named(timestamp_monotonic, drm_timestamp_monotonic, int, 0600); + +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_single = drm_mmap_single, + .d_name = "drm", + .d_flags = D_TRACKCLOSE +}; + +static int drm_minor_get_id(struct drm_device *dev, int type) +{ + int new_id; + + new_id = device_get_unit(dev->dev); + + if (new_id >= 64) + return -EINVAL; + + if (type == DRM_MINOR_CONTROL) { + new_id += 64; + } else if (type == DRM_MINOR_RENDER) { + new_id += 128; + } + + return new_id; +} + +struct drm_master *drm_master_create(struct drm_minor *minor) +{ + struct drm_master *master; + + master = malloc(sizeof(*master), DRM_MEM_KMS, M_NOWAIT | M_ZERO); + if (!master) + return NULL; + + refcount_init(&master->refcount, 1); + mtx_init(&master->lock.spinlock, "drm_master__lock__spinlock", + NULL, MTX_DEF); + DRM_INIT_WAITQUEUE(&master->lock.lock_queue); + drm_ht_create(&master->magiclist, DRM_MAGIC_HASH_ORDER); + INIT_LIST_HEAD(&master->magicfree); + master->minor = minor; + + list_add_tail(&master->head, &minor->master_list); + + return master; +} + +struct drm_master *drm_master_get(struct drm_master *master) +{ + refcount_acquire(&master->refcount); + return master; +} +EXPORT_SYMBOL(drm_master_get); + +static void drm_master_destroy(struct drm_master *master) +{ + struct drm_magic_entry *pt, *next; + struct drm_device *dev = master->minor->dev; + struct drm_map_list *r_list, *list_temp; + + list_del(&master->head); + + if (dev->driver->master_destroy) + dev->driver->master_destroy(dev, master); + + list_for_each_entry_safe(r_list, list_temp, &dev->maplist, head) { + if (r_list->master == master) { + drm_rmmap_locked(dev, r_list->map); + r_list = NULL; + } + } + + if (master->unique) { + free(master->unique, DRM_MEM_DRIVER); + master->unique = NULL; + master->unique_len = 0; + } + + list_for_each_entry_safe(pt, next, &master->magicfree, head) { + list_del(&pt->head); + drm_ht_remove_item(&master->magiclist, &pt->hash_item); + free(pt, DRM_MEM_MAGIC); + } + + drm_ht_remove(&master->magiclist); + + free(master, DRM_MEM_KMS); +} + +void drm_master_put(struct drm_master **master) +{ + if (refcount_release(&(*master)->refcount)) + drm_master_destroy(*master); + *master = NULL; +} +EXPORT_SYMBOL(drm_master_put); + +int drm_setmaster_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + int ret; + + if (file_priv->is_master) + return 0; + + if (file_priv->minor->master && file_priv->minor->master != file_priv->master) + return -EINVAL; + + if (!file_priv->master) + return -EINVAL; + + if (file_priv->minor->master) + return -EINVAL; + + DRM_LOCK(dev); + file_priv->minor->master = drm_master_get(file_priv->master); + file_priv->is_master = 1; + if (dev->driver->master_set) { + ret = dev->driver->master_set(dev, file_priv, false); + if (unlikely(ret != 0)) { + file_priv->is_master = 0; + drm_master_put(&file_priv->minor->master); + } + } + DRM_UNLOCK(dev); + + return 0; +} + +int drm_dropmaster_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + if (!file_priv->is_master) + return -EINVAL; + + if (!file_priv->minor->master) + return -EINVAL; + + DRM_LOCK(dev); + if (dev->driver->master_drop) + dev->driver->master_drop(dev, file_priv, false); + drm_master_put(&file_priv->minor->master); + file_priv->is_master = 0; + DRM_UNLOCK(dev); + return 0; +} + +int drm_fill_in_dev(struct drm_device *dev, + struct drm_driver *driver) +{ + int retcode, i; + + INIT_LIST_HEAD(&dev->filelist); + INIT_LIST_HEAD(&dev->ctxlist); + INIT_LIST_HEAD(&dev->maplist); + INIT_LIST_HEAD(&dev->vblank_event_list); + + mtx_init(&dev->irq_lock, "drmirq", NULL, MTX_DEF); + mtx_init(&dev->count_lock, "drmcount", NULL, MTX_DEF); + mtx_init(&dev->event_lock, "drmev", NULL, MTX_DEF); + sx_init(&dev->dev_struct_lock, "drmslk"); + mtx_init(&dev->ctxlist_mutex, "drmctxlist", NULL, MTX_DEF); + mtx_init(&dev->pcir_lock, "drmpcir", NULL, MTX_DEF); + + if (drm_ht_create(&dev->map_hash, 12)) { + return -ENOMEM; + } + + /* the DRM has 6 basic counters */ + 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; + + /* + * FIXME Linux<->FreeBSD: this is done in drm_setup() on Linux. + */ + for (i = 0; i < ARRAY_SIZE(dev->counts); i++) + atomic_set(&dev->counts[i], 0); + + dev->driver = driver; + + retcode = drm_pci_agp_init(dev); + if (retcode) + goto error_out_unreg; + + + + retcode = drm_ctxbitmap_init(dev); + if (retcode) { + DRM_ERROR("Cannot allocate memory for context bitmap.\n"); + goto error_out_unreg; + } + + if (driver->driver_features & DRIVER_GEM) { + retcode = drm_gem_init(dev); + if (retcode) { + DRM_ERROR("Cannot initialize graphics execution " + "manager (GEM)\n"); + goto error_out_unreg; + } + } + + retcode = drm_sysctl_init(dev); + if (retcode != 0) { + DRM_ERROR("Failed to create hw.dri sysctl entry: %d\n", + retcode); + } + + return 0; + + error_out_unreg: + drm_cancel_fill_in_dev(dev); + return retcode; +} +EXPORT_SYMBOL(drm_fill_in_dev); + +void drm_cancel_fill_in_dev(struct drm_device *dev) { + struct drm_driver *driver; + + driver = dev->driver; + + drm_sysctl_cleanup(dev); + if (driver->driver_features & DRIVER_GEM) + drm_gem_destroy(dev); + drm_ctxbitmap_cleanup(dev); - DRM_DEBUG("setmaster\n"); + if (drm_core_has_MTRR(dev) && drm_core_has_AGP(dev) && + dev->agp && dev->agp->agp_mtrr >= 0) { + int retval; + retval = drm_mtrr_del(dev->agp->agp_mtrr, + dev->agp->agp_info.ai_aperture_base, + dev->agp->agp_info.ai_aperture_size, + DRM_MTRR_WC); + DRM_DEBUG("mtrr_del=%d\n", retval); + } + free(dev->agp, DRM_MEM_AGPLISTS); + dev->agp = NULL; - if (file_priv->master != 0) - return (0); - return (EPERM); + drm_ht_remove(&dev->map_hash); + + mtx_destroy(&dev->irq_lock); + mtx_destroy(&dev->count_lock); + mtx_destroy(&dev->event_lock); + sx_destroy(&dev->dev_struct_lock); + mtx_destroy(&dev->ctxlist_mutex); + mtx_destroy(&dev->pcir_lock); } -int -drm_dropmaster_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) +/** + * Get a secondary minor number. + * + * \param dev device data structure + * \param sec-minor structure to hold the assigned minor + * \return negative number on failure. + * + * Search an empty entry and initialize it to the given parameters, and + * create the proc init entry via proc_init(). This routines assigns + * minor numbers to secondary heads of multi-headed cards + */ +int drm_get_minor(struct drm_device *dev, struct drm_minor **minor, int type) { + struct drm_minor *new_minor; + int ret; + int minor_id; + const char *minor_devname; + + DRM_DEBUG("\n"); + + minor_id = drm_minor_get_id(dev, type); + if (minor_id < 0) + return minor_id; + + new_minor = malloc(sizeof(struct drm_minor), DRM_MEM_MINOR, + M_NOWAIT | M_ZERO); + if (!new_minor) { + ret = -ENOMEM; + goto err_idr; + } + + new_minor->type = type; + new_minor->dev = dev; + new_minor->index = minor_id; + INIT_LIST_HEAD(&new_minor->master_list); + + new_minor->buf_sigio = NULL; + + switch (type) { + case DRM_MINOR_CONTROL: + minor_devname = "dri/controlD%d"; + break; + case DRM_MINOR_RENDER: + minor_devname = "dri/renderD%d"; + break; + default: + minor_devname = "dri/card%d"; + break; + } + + ret = make_dev_p(MAKEDEV_WAITOK | MAKEDEV_CHECKNAME, &new_minor->device, + &drm_cdevsw, 0, DRM_DEV_UID, DRM_DEV_GID, + DRM_DEV_MODE, minor_devname, minor_id); + if (ret) { + DRM_ERROR("Failed to create cdev: %d\n", ret); + goto err_mem; + } + new_minor->device->si_drv1 = new_minor; + *minor = new_minor; + + DRM_DEBUG("new minor assigned %d\n", minor_id); + return 0; + + +err_mem: + free(new_minor, DRM_MEM_MINOR); +err_idr: + *minor = NULL; + return ret; +} +EXPORT_SYMBOL(drm_get_minor); + +/** + * Put a secondary minor number. + * + * \param sec_minor - structure to be released + * \return always zero + * + * Cleans up the proc resources. Not legal for this to be the + * last minor released. + * + */ +int drm_put_minor(struct drm_minor **minor_p) +{ + struct drm_minor *minor = *minor_p; + + DRM_DEBUG("release secondary minor %d\n", minor->index); + + funsetown(&minor->buf_sigio); + + destroy_dev(minor->device); + + free(minor, DRM_MEM_MINOR); + *minor_p = NULL; + return 0; +} +EXPORT_SYMBOL(drm_put_minor); + +/** + * Called via drm_exit() at module unload time or when pci device is + * unplugged. + * + * Cleans up all DRM device, calling drm_lastclose(). + * + */ +void drm_put_dev(struct drm_device *dev) +{ + struct drm_driver *driver; + struct drm_map_list *r_list, *list_temp; + + DRM_DEBUG("\n"); + + if (!dev) { + DRM_ERROR("cleanup called no dev\n"); + return; + } + driver = dev->driver; + + drm_lastclose(dev); + + if (drm_core_has_MTRR(dev) && drm_core_has_AGP(dev) && + dev->agp && dev->agp->agp_mtrr >= 0) { + int retval; + retval = drm_mtrr_del(dev->agp->agp_mtrr, + dev->agp->agp_info.ai_aperture_base, + dev->agp->agp_info.ai_aperture_size, + DRM_MTRR_WC); + DRM_DEBUG("mtrr_del=%d\n", retval); + } + + if (drm_core_check_feature(dev, DRIVER_MODESET)) + drm_mode_group_free(&dev->primary->mode_group); + + if (dev->driver->unload) + dev->driver->unload(dev); + + drm_sysctl_cleanup(dev); + + if (drm_core_has_AGP(dev) && dev->agp) { + free(dev->agp, DRM_MEM_AGPLISTS); + dev->agp = NULL; + } + + drm_vblank_cleanup(dev); + + list_for_each_entry_safe(r_list, list_temp, &dev->maplist, head) + drm_rmmap(dev, r_list->map); + drm_ht_remove(&dev->map_hash); + + drm_ctxbitmap_cleanup(dev); + + if (drm_core_check_feature(dev, DRIVER_MODESET)) + drm_put_minor(&dev->control); + + if (driver->driver_features & DRIVER_GEM) + drm_gem_destroy(dev); + + drm_put_minor(&dev->primary); + + mtx_destroy(&dev->irq_lock); + mtx_destroy(&dev->count_lock); + mtx_destroy(&dev->event_lock); + sx_destroy(&dev->dev_struct_lock); + mtx_destroy(&dev->ctxlist_mutex); + mtx_destroy(&dev->pcir_lock); - DRM_DEBUG("dropmaster\n"); - if (file_priv->master != 0) - return (EINVAL); - return (0); +#ifdef FREEBSD_NOTYET + list_del(&dev->driver_item); +#endif /* FREEBSD_NOTYET */ } +EXPORT_SYMBOL(drm_put_dev); diff --git a/sys/dev/drm2/drm_sysctl.c b/sys/dev/drm2/drm_sysctl.c index 9564e68df854..1afa399d17b1 100644 --- a/sys/dev/drm2/drm_sysctl.c +++ b/sys/dev/drm2/drm_sysctl.c @@ -8,11 +8,11 @@ * 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 @@ -70,8 +70,11 @@ int drm_sysctl_init(struct drm_device *dev) /* Add the sysctl node for DRI if it doesn't already exist */ drioid = SYSCTL_ADD_NODE(&info->ctx, SYSCTL_CHILDREN(&sysctl___hw), OID_AUTO, "dri", CTLFLAG_RW, NULL, "DRI Graphics"); - if (!drioid) - return 1; + if (!drioid) { + free(dev->sysctl, DRM_MEM_DRIVER); + dev->sysctl = NULL; + return (-ENOMEM); + } /* Find the next free slot under hw.dri */ i = 0; @@ -79,18 +82,22 @@ int drm_sysctl_init(struct drm_device *dev) if (i <= oid->oid_arg2) i = oid->oid_arg2 + 1; } - if (i > 9) - return (1); - + if (i > 9) { + drm_sysctl_cleanup(dev); + return (-ENOSPC); + } + dev->sysctl_node_idx = i; /* Add the hw.dri.x for our device */ info->name[0] = '0' + i; info->name[1] = 0; top = SYSCTL_ADD_NODE(&info->ctx, SYSCTL_CHILDREN(drioid), OID_AUTO, info->name, CTLFLAG_RW, NULL, NULL); - if (!top) - return 1; - + if (!top) { + drm_sysctl_cleanup(dev); + return (-ENOMEM); + } + for (i = 0; i < DRM_SYSCTL_ENTRIES; i++) { oid = SYSCTL_ADD_OID(&info->ctx, SYSCTL_CHILDREN(top), @@ -102,14 +109,16 @@ int drm_sysctl_init(struct drm_device *dev) drm_sysctl_list[i].f, "A", NULL); - if (!oid) - return 1; + if (!oid) { + drm_sysctl_cleanup(dev); + return (-ENOMEM); + } } SYSCTL_ADD_INT(&info->ctx, SYSCTL_CHILDREN(drioid), OID_AUTO, "debug", - CTLFLAG_RW, &drm_debug_flag, sizeof(drm_debug_flag), + CTLFLAG_RW, &drm_debug, sizeof(drm_debug), "Enable debugging output"); SYSCTL_ADD_INT(&info->ctx, SYSCTL_CHILDREN(drioid), OID_AUTO, "notyet", - CTLFLAG_RW, &drm_notyet_flag, sizeof(drm_debug_flag), + CTLFLAG_RW, &drm_notyet, sizeof(drm_debug), "Enable notyet reminders"); if (dev->driver->sysctl_init != NULL) @@ -131,13 +140,16 @@ int drm_sysctl_cleanup(struct drm_device *dev) { int error; + if (dev->sysctl == NULL) + return (0); + error = sysctl_ctx_free(&dev->sysctl->ctx); free(dev->sysctl, DRM_MEM_DRIVER); dev->sysctl = NULL; if (dev->driver->sysctl_cleanup != NULL) dev->driver->sysctl_cleanup(dev); - return (error); + return (-error); } #define DRM_SYSCTL_PRINT(fmt, arg...) \ @@ -151,20 +163,25 @@ do { \ static int drm_name_info DRM_SYSCTL_HANDLER_ARGS { struct drm_device *dev = arg1; + struct drm_minor *minor; + struct drm_master *master; char buf[128]; int retcode; int hasunique = 0; + /* FIXME: This still uses primary minor. */ + minor = dev->primary; DRM_SYSCTL_PRINT("%s 0x%jx", dev->driver->name, - (uintmax_t)dev2udev(dev->devnode)); - + (uintmax_t)dev2udev(minor->device)); + DRM_LOCK(dev); - if (dev->unique) { - snprintf(buf, sizeof(buf), " %s", dev->unique); + master = minor->master; + if (master != NULL && master->unique) { + snprintf(buf, sizeof(buf), " %s", master->unique); hasunique = 1; } DRM_UNLOCK(dev); - + if (hasunique) SYSCTL_OUT(req, buf, strlen(buf)); @@ -177,7 +194,8 @@ done: static int drm_vm_info DRM_SYSCTL_HANDLER_ARGS { struct drm_device *dev = arg1; - drm_local_map_t *map, *tempmaps; + struct drm_map_list *entry; + struct drm_local_map *map, *tempmaps; const char *types[] = { [_DRM_FRAME_BUFFER] = "FB", [_DRM_REGISTERS] = "REG", @@ -198,10 +216,12 @@ static int drm_vm_info DRM_SYSCTL_HANDLER_ARGS DRM_LOCK(dev); mapcount = 0; - TAILQ_FOREACH(map, &dev->maplist, link) - mapcount++; + list_for_each_entry(entry, &dev->maplist, head) { + if (entry->map != NULL) + mapcount++; + } - tempmaps = malloc(sizeof(drm_local_map_t) * mapcount, DRM_MEM_DRIVER, + tempmaps = malloc(sizeof(*tempmaps) * mapcount, DRM_MEM_DRIVER, M_NOWAIT); if (tempmaps == NULL) { DRM_UNLOCK(dev); @@ -209,13 +229,15 @@ static int drm_vm_info DRM_SYSCTL_HANDLER_ARGS } i = 0; - TAILQ_FOREACH(map, &dev->maplist, link) - tempmaps[i++] = *map; + list_for_each_entry(entry, &dev->maplist, head) { + if (entry->map != NULL) + tempmaps[i++] = *entry->map; + } DRM_UNLOCK(dev); DRM_SYSCTL_PRINT("\nslot offset size " - "type flags address handle mtrr\n"); + "type flags address mtrr\n"); for (i = 0; i < mapcount; i++) { map = &tempmaps[i]; @@ -235,17 +257,15 @@ static int drm_vm_info DRM_SYSCTL_HANDLER_ARGS break; } - if (!map->mtrr) + if (map->mtrr < 0) yesno = "no"; else yesno = "yes"; DRM_SYSCTL_PRINT( - "%4d 0x%016lx 0x%08lx %4.4s 0x%02x 0x%016lx %6d %s\n", - i, map->offset, map->size, type, map->flags, - (unsigned long)map->virtual, - (unsigned int)((unsigned long)map->handle >> - DRM_MAP_HANDLE_SHIFT), yesno); + "%4d 0x%016llx 0x%08lx %4.4s 0x%02x 0x%016lx %s\n", + i, (unsigned long long)map->offset, map->size, type, + map->flags, (unsigned long)map->handle, yesno); } SYSCTL_OUT(req, "", 1); @@ -257,8 +277,8 @@ done: static int drm_bufs_info DRM_SYSCTL_HANDLER_ARGS { struct drm_device *dev = arg1; - drm_device_dma_t *dma = dev->dma; - drm_device_dma_t tempdma; + struct drm_device_dma *dma = dev->dma; + struct drm_device_dma tempdma; int *templists; int i; char buf[128]; @@ -322,7 +342,7 @@ static int drm_clients_info DRM_SYSCTL_HANDLER_ARGS DRM_LOCK(dev); privcount = 0; - TAILQ_FOREACH(priv, &dev->files, link) + list_for_each_entry(priv, &dev->filelist, lhead) privcount++; tempprivs = malloc(sizeof(struct drm_file) * privcount, DRM_MEM_DRIVER, @@ -332,7 +352,7 @@ static int drm_clients_info DRM_SYSCTL_HANDLER_ARGS return ENOMEM; } i = 0; - TAILQ_FOREACH(priv, &dev->files, link) + list_for_each_entry(priv, &dev->filelist, lhead) tempprivs[i++] = *priv; DRM_UNLOCK(dev); @@ -343,7 +363,7 @@ static int drm_clients_info DRM_SYSCTL_HANDLER_ARGS priv = &tempprivs[i]; DRM_SYSCTL_PRINT("%c %-12s %5d %5d %10u %10lu\n", priv->authenticated ? 'y' : 'n', - devtoname(priv->dev->devnode), + devtoname(priv->minor->device), priv->pid, priv->uid, priv->magic, diff --git a/sys/dev/drm2/drm_vm.c b/sys/dev/drm2/drm_vm.c index a70fe7b504f8..3fa2aba54ee1 100644 --- a/sys/dev/drm2/drm_vm.c +++ b/sys/dev/drm2/drm_vm.c @@ -1,5 +1,16 @@ -/*- - * Copyright 2003 Eric Anholt +/** + * \file drm_vm.c + * Memory mapping for DRM + * + * \author Rickard E. (Rik) Faith <faith@valinux.com> + * \author Gareth Hughes <gareth@valinux.com> + */ + +/* + * Created: Mon Jan 4 08:58:31 1999 by faith@valinux.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a @@ -8,17 +19,18 @@ * 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. + * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. */ #include <sys/cdefs.h> @@ -31,6 +43,7 @@ __FBSDID("$FreeBSD$"); #include <dev/drm2/drmP.h> #include <dev/drm2/drm.h> +#ifdef FREEBSD_NOTYET int drm_mmap(struct cdev *kdev, vm_ooffset_t offset, vm_paddr_t *paddr, int prot, vm_memattr_t *memattr) @@ -131,4 +144,4 @@ drm_mmap(struct cdev *kdev, vm_ooffset_t offset, vm_paddr_t *paddr, *paddr = phys; return 0; } - +#endif /* FREEBSD_NOTYET */ diff --git a/sys/dev/drm2/i915/i915_debug.c b/sys/dev/drm2/i915/i915_debug.c index 5f44a994481e..43d67f837c41 100644 --- a/sys/dev/drm2/i915/i915_debug.c +++ b/sys/dev/drm2/i915/i915_debug.c @@ -45,14 +45,12 @@ enum { PINNED_LIST, }; -static const char * -yesno(int v) +static const char *yesno(int v) { - return (v ? "yes" : "no"); + return v ? "yes" : "no"; } -static int -i915_capabilities(struct drm_device *dev, struct sbuf *m, void *data) +static int i915_capabilities(struct drm_device *dev, struct sbuf *m, void *data) { const struct intel_device_info *info = INTEL_INFO(dev); @@ -80,11 +78,10 @@ i915_capabilities(struct drm_device *dev, struct sbuf *m, void *data) B(has_llc); #undef B - return (0); + return 0; } -static const char * -get_pin_flag(struct drm_i915_gem_object *obj) +static const char *get_pin_flag(struct drm_i915_gem_object *obj) { if (obj->user_pin_count > 0) return "P"; @@ -94,25 +91,23 @@ get_pin_flag(struct drm_i915_gem_object *obj) return " "; } -static const char * -get_tiling_flag(struct drm_i915_gem_object *obj) +static const char *get_tiling_flag(struct drm_i915_gem_object *obj) { switch (obj->tiling_mode) { default: - case I915_TILING_NONE: return (" "); - case I915_TILING_X: return ("X"); - case I915_TILING_Y: return ("Y"); + case I915_TILING_NONE: return " "; + case I915_TILING_X: return "X"; + case I915_TILING_Y: return "Y"; } } -static const char * -cache_level_str(int type) +static const char *cache_level_str(int type) { switch (type) { case I915_CACHE_NONE: return " uncached"; case I915_CACHE_LLC: return " snooped (LLC)"; case I915_CACHE_LLC_MLC: return " snooped (LLC+MLC)"; - default: return (""); + default: return ""; } } @@ -154,8 +149,7 @@ describe_obj(struct sbuf *m, struct drm_i915_gem_object *obj) sbuf_printf(m, " (%s)", obj->ring->name); } -static int -i915_gem_object_list_info(struct drm_device *dev, struct sbuf *m, void *data) +static int i915_gem_object_list_info(struct drm_device *dev, struct sbuf *m, void *data) { uintptr_t list = (uintptr_t)data; struct list_head *head; @@ -165,7 +159,7 @@ i915_gem_object_list_info(struct drm_device *dev, struct sbuf *m, void *data) int count; if (sx_xlock_sig(&dev->dev_struct_lock)) - return (EINTR); + return -EINTR; switch (list) { case ACTIVE_LIST: @@ -182,7 +176,7 @@ i915_gem_object_list_info(struct drm_device *dev, struct sbuf *m, void *data) break; default: DRM_UNLOCK(dev); - return (EINVAL); + return -EINVAL; } total_obj_size = total_gtt_size = count = 0; @@ -198,7 +192,7 @@ i915_gem_object_list_info(struct drm_device *dev, struct sbuf *m, void *data) sbuf_printf(m, "Total %d objects, %zu bytes, %zu GTT size\n", count, total_obj_size, total_gtt_size); - return (0); + return 0; } #define count_objects(list, member) do { \ @@ -212,8 +206,7 @@ i915_gem_object_list_info(struct drm_device *dev, struct sbuf *m, void *data) } \ } while (0) -static int -i915_gem_object_info(struct drm_device *dev, struct sbuf *m, void *data) +static int i915_gem_object_info(struct drm_device *dev, struct sbuf *m, void *data) { struct drm_i915_private *dev_priv = dev->dev_private; u32 count, mappable_count; @@ -221,7 +214,7 @@ i915_gem_object_info(struct drm_device *dev, struct sbuf *m, void *data) struct drm_i915_gem_object *obj; if (sx_xlock_sig(&dev->dev_struct_lock)) - return (EINTR); + return -EINTR; sbuf_printf(m, "%u objects, %zu bytes\n", dev_priv->mm.object_count, dev_priv->mm.object_memory); @@ -260,13 +253,13 @@ i915_gem_object_info(struct drm_device *dev, struct sbuf *m, void *data) sbuf_printf(m, "%zu [%zu] gtt total\n", dev_priv->mm.gtt_total, dev_priv->mm.mappable_gtt_total); + DRM_UNLOCK(dev); - return (0); + return 0; } -static int -i915_gem_gtt_info(struct drm_device *dev, struct sbuf *m, void *data) +static int i915_gem_gtt_info(struct drm_device *dev, struct sbuf *m, void *data) { struct drm_i915_private *dev_priv = dev->dev_private; uintptr_t list = (uintptr_t)data; @@ -275,7 +268,7 @@ i915_gem_gtt_info(struct drm_device *dev, struct sbuf *m, void *data) int count; if (sx_xlock_sig(&dev->dev_struct_lock)) - return (EINTR); + return -EINTR; total_obj_size = total_gtt_size = count = 0; list_for_each_entry(obj, &dev_priv->mm.gtt_list, gtt_list) { @@ -295,11 +288,10 @@ i915_gem_gtt_info(struct drm_device *dev, struct sbuf *m, void *data) sbuf_printf(m, "Total %d objects, %zu bytes, %zu GTT size\n", count, total_obj_size, total_gtt_size); - return (0); + return 0; } -static int -i915_gem_pageflip_info(struct drm_device *dev, struct sbuf *m, void *data) +static int i915_gem_pageflip_info(struct drm_device *dev, struct sbuf *m, void *data) { struct intel_crtc *crtc; struct drm_i915_gem_object *obj; @@ -307,8 +299,6 @@ i915_gem_pageflip_info(struct drm_device *dev, struct sbuf *m, void *data) char pipe; char plane; - if ((dev->driver->driver_features & DRIVER_MODESET) == 0) - return (0); list_for_each_entry(crtc, &dev->mode_config.crtc_list, base.head) { pipe = pipe_name(crtc->pipe); plane = plane_name(crtc->plane); @@ -346,18 +336,17 @@ i915_gem_pageflip_info(struct drm_device *dev, struct sbuf *m, void *data) mtx_unlock(&dev->event_lock); } - return (0); + return 0; } -static int -i915_gem_request_info(struct drm_device *dev, struct sbuf *m, void *data) +static int i915_gem_request_info(struct drm_device *dev, struct sbuf *m, void *data) { drm_i915_private_t *dev_priv = dev->dev_private; struct drm_i915_gem_request *gem_request; int count; if (sx_xlock_sig(&dev->dev_struct_lock)) - return (EINTR); + return -EINTR; count = 0; if (!list_empty(&dev_priv->rings[RCS].request_list)) { @@ -401,8 +390,7 @@ i915_gem_request_info(struct drm_device *dev, struct sbuf *m, void *data) return 0; } -static void -i915_ring_seqno_info(struct sbuf *m, struct intel_ring_buffer *ring) +static void i915_ring_seqno_info(struct sbuf *m, struct intel_ring_buffer *ring) { if (ring->get_seqno) { sbuf_printf(m, "Current sequence (%s): %d\n", @@ -410,29 +398,30 @@ i915_ring_seqno_info(struct sbuf *m, struct intel_ring_buffer *ring) } } -static int -i915_gem_seqno_info(struct drm_device *dev, struct sbuf *m, void *data) +static int i915_gem_seqno_info(struct drm_device *dev, struct sbuf *m, void *data) { drm_i915_private_t *dev_priv = dev->dev_private; int i; if (sx_xlock_sig(&dev->dev_struct_lock)) - return (EINTR); + return -EINTR; + for (i = 0; i < I915_NUM_RINGS; i++) i915_ring_seqno_info(m, &dev_priv->rings[i]); + DRM_UNLOCK(dev); - return (0); + + return 0; } -static int -i915_interrupt_info(struct drm_device *dev, struct sbuf *m, void *data) +static int i915_interrupt_info(struct drm_device *dev, struct sbuf *m, void *data) { drm_i915_private_t *dev_priv = dev->dev_private; int i, pipe; if (sx_xlock_sig(&dev->dev_struct_lock)) - return (EINTR); + return -EINTR; if (IS_VALLEYVIEW(dev)) { sbuf_printf(m, "Display IER:\t%08x\n", @@ -515,17 +504,16 @@ i915_interrupt_info(struct drm_device *dev, struct sbuf *m, void *data) } DRM_UNLOCK(dev); - return (0); + return 0; } -static int -i915_gem_fence_regs_info(struct drm_device *dev, struct sbuf *m, void *data) +static int i915_gem_fence_regs_info(struct drm_device *dev, struct sbuf *m, void *data) { drm_i915_private_t *dev_priv = dev->dev_private; int i; if (sx_xlock_sig(&dev->dev_struct_lock)) - return (EINTR); + return -EINTR; sbuf_printf(m, "Reserved fences = %d\n", dev_priv->fence_reg_start); sbuf_printf(m, "Total fences = %d\n", dev_priv->num_fence_regs); @@ -541,50 +529,47 @@ i915_gem_fence_regs_info(struct drm_device *dev, struct sbuf *m, void *data) } DRM_UNLOCK(dev); - return (0); + return 0; } -static int -i915_hws_info(struct drm_device *dev, struct sbuf *m, void *data) +static int i915_hws_info(struct drm_device *dev, struct sbuf *m, void *data) { drm_i915_private_t *dev_priv = dev->dev_private; struct intel_ring_buffer *ring; - const volatile u32 *hws; + const volatile u32 __iomem *hws; int i; ring = &dev_priv->rings[(uintptr_t)data]; hws = (volatile u32 *)ring->status_page.page_addr; if (hws == NULL) - return (0); + return 0; for (i = 0; i < 4096 / sizeof(u32) / 4; i += 4) { sbuf_printf(m, "0x%08x: 0x%08x 0x%08x 0x%08x 0x%08x\n", i * 4, hws[i], hws[i + 1], hws[i + 2], hws[i + 3]); } - return (0); + return 0; } -static const char * -ring_str(int ring) +static const char *ring_str(int ring) { switch (ring) { - case RCS: return (" render"); - case VCS: return (" bsd"); - case BCS: return (" blt"); - default: return (""); + case RCS: return " render"; + case VCS: return " bsd"; + case BCS: return " blt"; + default: return ""; } } -static const char * -pin_flag(int pinned) +static const char *pin_flag(int pinned) { if (pinned > 0) - return (" P"); + return " P"; else if (pinned < 0) - return (" p"); + return " p"; else - return (""); + return ""; } static const char *tiling_flag(int tiling) @@ -607,8 +592,10 @@ static const char *purgeable_flag(int purgeable) return purgeable ? " purgeable" : ""; } -static void print_error_buffers(struct sbuf *m, const char *name, - struct drm_i915_error_buffer *err, int count) +static void print_error_buffers(struct sbuf *m, + const char *name, + struct drm_i915_error_buffer *err, + int count) { sbuf_printf(m, "%s [%d]:\n", name, count); @@ -638,9 +625,10 @@ static void print_error_buffers(struct sbuf *m, const char *name, } } -static void -i915_ring_error_state(struct sbuf *m, struct drm_device *dev, - struct drm_i915_error_state *error, unsigned ring) +static void i915_ring_error_state(struct sbuf *m, + struct drm_device *dev, + struct drm_i915_error_state *error, + unsigned ring) { MPASS((ring < I915_NUM_RINGS)); /* shut up confused gcc */ @@ -672,8 +660,7 @@ i915_ring_error_state(struct sbuf *m, struct drm_device *dev, sbuf_printf(m, " ring->tail: 0x%08x\n", error->cpu_ring_tail[ring]); } -static int -i915_error_state(struct drm_device *dev, struct sbuf *m, +static int i915_error_state(struct drm_device *dev, struct sbuf *m, void *unused) { drm_i915_private_t *dev_priv = dev->dev_private; @@ -686,9 +673,9 @@ i915_error_state(struct drm_device *dev, struct sbuf *m, if (error != NULL) refcount_acquire(&error->ref); mtx_unlock(&dev_priv->error_lock); - if (error == NULL) { + if (!error) { sbuf_printf(m, "no error state collected\n"); - return (0); + return 0; } error = dev_priv->first_error; @@ -722,9 +709,9 @@ i915_error_state(struct drm_device *dev, struct sbuf *m, error->pinned_bo, error->pinned_bo_count); - for (i = 0; i < DRM_ARRAY_SIZE(error->ring); i++) { + for (i = 0; i < ARRAY_SIZE(error->ring); i++) { struct drm_i915_error_object *obj; - + if ((obj = error->ring[i].batchbuffer)) { sbuf_printf(m, "%s --- gtt_offset = 0x%08x\n", dev_priv->rings[i].name, @@ -776,7 +763,7 @@ i915_error_state(struct drm_device *dev, struct sbuf *m, if (refcount_release(&error->ref)) i915_error_state_free(error); - return (0); + return 0; } static int @@ -802,8 +789,10 @@ i915_rstdby_delays(struct drm_device *dev, struct sbuf *m, void *unused) u16 crstanddelay; if (sx_xlock_sig(&dev->dev_struct_lock)) - return (EINTR); + return -EINTR; + crstanddelay = I915_READ16(CRSTANDVID); + DRM_UNLOCK(dev); sbuf_printf(m, "w/ctx: %d, w/o ctx: %d\n", @@ -812,8 +801,7 @@ i915_rstdby_delays(struct drm_device *dev, struct sbuf *m, void *unused) return 0; } -static int -i915_cur_delayinfo(struct drm_device *dev, struct sbuf *m, void *unused) +static int i915_cur_delayinfo(struct drm_device *dev, struct sbuf *m, void *unused) { drm_i915_private_t *dev_priv = dev->dev_private; @@ -838,7 +826,7 @@ i915_cur_delayinfo(struct drm_device *dev, struct sbuf *m, void *unused) /* RPSTAT1 is in the GT power well */ if (sx_xlock_sig(&dev->dev_struct_lock)) - return (EINTR); + return -EINTR; gen6_gt_force_wake_get(dev_priv); rpstat = I915_READ(GEN6_RPSTAT1); @@ -893,50 +881,51 @@ i915_cur_delayinfo(struct drm_device *dev, struct sbuf *m, void *unused) return 0; } -static int -i915_delayfreq_table(struct drm_device *dev, struct sbuf *m, void *unused) +static int i915_delayfreq_table(struct drm_device *dev, struct sbuf *m, void *unused) { drm_i915_private_t *dev_priv = dev->dev_private; u32 delayfreq; int i; if (sx_xlock_sig(&dev->dev_struct_lock)) - return (EINTR); + return -EINTR; + for (i = 0; i < 16; i++) { delayfreq = I915_READ(PXVFREQ_BASE + i * 4); sbuf_printf(m, "P%02dVIDFREQ: 0x%08x (VID: %d)\n", i, delayfreq, (delayfreq & PXVFREQ_PX_MASK) >> PXVFREQ_PX_SHIFT); } + DRM_UNLOCK(dev); - return (0); + + return 0; } -static inline int -MAP_TO_MV(int map) +static inline int MAP_TO_MV(int map) { return 1250 - (map * 25); } -static int -i915_inttoext_table(struct drm_device *dev, struct sbuf *m, void *unused) +static int i915_inttoext_table(struct drm_device *dev, struct sbuf *m, void *unused) { drm_i915_private_t *dev_priv = dev->dev_private; u32 inttoext; int i; if (sx_xlock_sig(&dev->dev_struct_lock)) - return (EINTR); + return -EINTR; + for (i = 1; i <= 32; i++) { inttoext = I915_READ(INTTOEXT_BASE_ILK + i * 4); sbuf_printf(m, "INTTOEXT%02d: 0x%08x\n", i, inttoext); } + DRM_UNLOCK(dev); - return (0); + return 0; } -static int -ironlake_drpc_info(struct drm_device *dev, struct sbuf *m) +static int ironlake_drpc_info(struct drm_device *dev, struct sbuf *m) { drm_i915_private_t *dev_priv = dev->dev_private; u32 rgvmodectl; @@ -944,10 +933,12 @@ ironlake_drpc_info(struct drm_device *dev, struct sbuf *m) u16 crstandvid; if (sx_xlock_sig(&dev->dev_struct_lock)) - return (EINTR); + return -EINTR; + rgvmodectl = I915_READ(MEMMODECTL); rstdbyctl = I915_READ(RSTDBYCTL); crstandvid = I915_READ16(CRSTANDVID); + DRM_UNLOCK(dev); sbuf_printf(m, "HD boost: %s\n", (rgvmodectl & MEMMODE_BOOST_EN) ? @@ -998,16 +989,16 @@ ironlake_drpc_info(struct drm_device *dev, struct sbuf *m) return 0; } -static int -gen6_drpc_info(struct drm_device *dev, struct sbuf *m) +static int gen6_drpc_info(struct drm_device *dev, struct sbuf *m) { drm_i915_private_t *dev_priv = dev->dev_private; u32 rpmodectl1, gt_core_status, rcctl1; unsigned forcewake_count; int count=0; + if (sx_xlock_sig(&dev->dev_struct_lock)) - return (EINTR); + return -EINTR; mtx_lock(&dev_priv->gt_lock); forcewake_count = dev_priv->forcewake_count; @@ -1019,7 +1010,7 @@ gen6_drpc_info(struct drm_device *dev, struct sbuf *m) } else { /* NB: we cannot use forcewake, else we read the wrong values */ while (count++ < 50 && (I915_READ_NOTRACE(FORCEWAKE_ACK) & 1)) - DRM_UDELAY(10); + udelay(10); sbuf_printf(m, "RC information accurate: %s\n", yesno(count < 51)); } @@ -1087,12 +1078,12 @@ static int i915_drpc_info(struct drm_device *dev, struct sbuf *m, void *unused) { if (IS_GEN6(dev) || IS_GEN7(dev)) - return (gen6_drpc_info(dev, m)); + return gen6_drpc_info(dev, m); else - return (ironlake_drpc_info(dev, m)); + return ironlake_drpc_info(dev, m); } -static int -i915_fbc_status(struct drm_device *dev, struct sbuf *m, void *unused) + +static int i915_fbc_status(struct drm_device *dev, struct sbuf *m, void *unused) { drm_i915_private_t *dev_priv = dev->dev_private; @@ -1134,8 +1125,7 @@ i915_fbc_status(struct drm_device *dev, struct sbuf *m, void *unused) return 0; } -static int -i915_sr_status(struct drm_device *dev, struct sbuf *m, void *unused) +static int i915_sr_status(struct drm_device *dev, struct sbuf *m, void *unused) { drm_i915_private_t *dev_priv = dev->dev_private; bool sr_enabled = false; @@ -1152,7 +1142,31 @@ i915_sr_status(struct drm_device *dev, struct sbuf *m, void *unused) sbuf_printf(m, "self-refresh: %s", sr_enabled ? "enabled" : "disabled"); - return (0); + return 0; +} + +static int i915_emon_status(struct drm_device *dev, struct sbuf *m, void *unused) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + unsigned long temp, chipset, gfx; + + if (!IS_GEN5(dev)) + return -ENODEV; + + if (sx_xlock_sig(&dev->dev_struct_lock)) + return -EINTR; + + temp = i915_mch_val(dev_priv); + chipset = i915_chipset_val(dev_priv); + gfx = i915_gfx_val(dev_priv); + DRM_UNLOCK(dev); + + sbuf_printf(m, "GMCH temp: %ld\n", temp); + sbuf_printf(m, "Chipset power: %ld\n", chipset); + sbuf_printf(m, "GFX power: %ld\n", gfx); + sbuf_printf(m, "Total power: %ld\n", chipset + gfx); + + return 0; } static int i915_ring_freq_table(struct drm_device *dev, struct sbuf *m, @@ -1163,11 +1177,11 @@ static int i915_ring_freq_table(struct drm_device *dev, struct sbuf *m, if (!(IS_GEN6(dev) || IS_GEN7(dev))) { sbuf_printf(m, "unsupported on this chipset"); - return (0); + return 0; } if (sx_xlock_sig(&dev->dev_struct_lock)) - return (EINTR); + return -EINTR; sbuf_printf(m, "GPU freq (MHz)\tEffective CPU freq (MHz)\n"); @@ -1188,79 +1202,54 @@ static int i915_ring_freq_table(struct drm_device *dev, struct sbuf *m, DRM_UNLOCK(dev); - return (0); + return 0; } -static int -i915_emon_status(struct drm_device *dev, struct sbuf *m, void *unused) +static int i915_gfxec(struct drm_device *dev, struct sbuf *m, void *unused) { drm_i915_private_t *dev_priv = dev->dev_private; - unsigned long temp, chipset, gfx; - - if (!IS_GEN5(dev)) { - sbuf_printf(m, "Not supported\n"); - return (0); - } if (sx_xlock_sig(&dev->dev_struct_lock)) - return (EINTR); - temp = i915_mch_val(dev_priv); - chipset = i915_chipset_val(dev_priv); - gfx = i915_gfx_val(dev_priv); - DRM_UNLOCK(dev); - - sbuf_printf(m, "GMCH temp: %ld\n", temp); - sbuf_printf(m, "Chipset power: %ld\n", chipset); - sbuf_printf(m, "GFX power: %ld\n", gfx); - sbuf_printf(m, "Total power: %ld\n", chipset + gfx); + return -EINTR; - return (0); -} - -static int -i915_gfxec(struct drm_device *dev, struct sbuf *m, void *unused) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - - if (sx_xlock_sig(&dev->dev_struct_lock)) - return (EINTR); sbuf_printf(m, "GFXEC: %ld\n", (unsigned long)I915_READ(0x112f4)); + DRM_UNLOCK(dev); - return (0); + return 0; } #if 0 -static int -i915_opregion(struct drm_device *dev, struct sbuf *m, void *unused) +static int i915_opregion(struct drm_device *dev, struct sbuf *m, void *unused) { drm_i915_private_t *dev_priv = dev->dev_private; struct intel_opregion *opregion = &dev_priv->opregion; if (sx_xlock_sig(&dev->dev_struct_lock)) - return (EINTR); + return -EINTR; + if (opregion->header) seq_write(m, opregion->header, OPREGION_SIZE); + DRM_UNLOCK(dev); return 0; } #endif -static int -i915_gem_framebuffer_info(struct drm_device *dev, struct sbuf *m, void *data) +static int i915_gem_framebuffer_info(struct drm_device *dev, struct sbuf *m, void *data) { drm_i915_private_t *dev_priv = dev->dev_private; struct intel_fbdev *ifbdev; struct intel_framebuffer *fb; if (sx_xlock_sig(&dev->dev_struct_lock)) - return (EINTR); + return -EINTR; ifbdev = dev_priv->fbdev; if (ifbdev == NULL) { DRM_UNLOCK(dev); - return (0); + return 0; } fb = to_intel_framebuffer(ifbdev->helper.fb); @@ -1287,22 +1276,18 @@ i915_gem_framebuffer_info(struct drm_device *dev, struct sbuf *m, void *data) DRM_UNLOCK(dev); - return (0); + return 0; } -static int -i915_context_status(struct drm_device *dev, struct sbuf *m, void *data) +static int i915_context_status(struct drm_device *dev, struct sbuf *m, void *data) { drm_i915_private_t *dev_priv; int ret; - if ((dev->driver->driver_features & DRIVER_MODESET) == 0) - return (0); - dev_priv = dev->dev_private; ret = sx_xlock_sig(&dev->mode_config.mutex); if (ret != 0) - return (EINTR); + return -EINTR; if (dev_priv->pwrctx != NULL) { sbuf_printf(m, "power context "); @@ -1318,11 +1303,10 @@ i915_context_status(struct drm_device *dev, struct sbuf *m, void *data) sx_xunlock(&dev->mode_config.mutex); - return (0); + return 0; } -static int -i915_gen6_forcewake_count_info(struct drm_device *dev, struct sbuf *m, +static int i915_gen6_forcewake_count_info(struct drm_device *dev, struct sbuf *m, void *data) { struct drm_i915_private *dev_priv; @@ -1335,11 +1319,10 @@ i915_gen6_forcewake_count_info(struct drm_device *dev, struct sbuf *m, sbuf_printf(m, "forcewake count = %u\n", forcewake_count); - return (0); + return 0; } -static const char * -swizzle_string(unsigned swizzle) +static const char *swizzle_string(unsigned swizzle) { switch(swizzle) { @@ -1364,8 +1347,7 @@ swizzle_string(unsigned swizzle) return "bug"; } -static int -i915_swizzle_info(struct drm_device *dev, struct sbuf *m, void *data) +static int i915_swizzle_info(struct drm_device *dev, struct sbuf *m, void *data) { struct drm_i915_private *dev_priv; int ret; @@ -1373,7 +1355,7 @@ i915_swizzle_info(struct drm_device *dev, struct sbuf *m, void *data) dev_priv = dev->dev_private; ret = sx_xlock_sig(&dev->dev_struct_lock); if (ret != 0) - return (EINTR); + return -EINTR; sbuf_printf(m, "bit6 swizzle for X-tiling = %s\n", swizzle_string(dev_priv->mm.bit_6_swizzle_x)); @@ -1400,14 +1382,13 @@ i915_swizzle_info(struct drm_device *dev, struct sbuf *m, void *data) I915_READ(ARB_MODE)); sbuf_printf(m, "DISP_ARB_CTL = 0x%08x\n", I915_READ(DISP_ARB_CTL)); - } + } DRM_UNLOCK(dev); - return (0); + return 0; } -static int -i915_ppgtt_info(struct drm_device *dev, struct sbuf *m, void *data) +static int i915_ppgtt_info(struct drm_device *dev, struct sbuf *m, void *data) { struct drm_i915_private *dev_priv; struct intel_ring_buffer *ring; @@ -1417,7 +1398,7 @@ i915_ppgtt_info(struct drm_device *dev, struct sbuf *m, void *data) ret = sx_xlock_sig(&dev->dev_struct_lock); if (ret != 0) - return (EINTR); + return -EINTR; if (INTEL_INFO(dev)->gen == 6) sbuf_printf(m, "GFX_MODE: 0x%08x\n", I915_READ(GFX_MODE)); @@ -1440,7 +1421,7 @@ i915_ppgtt_info(struct drm_device *dev, struct sbuf *m, void *data) sbuf_printf(m, "ECOCHK: 0x%08x\n", I915_READ(GAM_ECOCHK)); DRM_UNLOCK(dev); - return (0); + return 0; } static int i915_dpio_info(struct drm_device *dev, struct sbuf *m, void *data) @@ -1457,7 +1438,7 @@ static int i915_dpio_info(struct drm_device *dev, struct sbuf *m, void *data) ret = sx_xlock_sig(&dev->mode_config.mutex); if (ret != 0) - return (EINTR); + return -EINTR; sbuf_printf(m, "DPIO_CTL: 0x%08x\n", I915_READ(DPIO_CTL)); @@ -1663,7 +1644,7 @@ i915_info_sysctl_handler(SYSCTL_HANDLER_ARGS) if (error != 0) return (error); sbuf_new_for_sysctl(&m, NULL, 128, req); - error = i915_info_sysctl_list[thunk->idx].ptr(dev, &m, + error = -i915_info_sysctl_list[thunk->idx].ptr(dev, &m, thunk->arg); if (error == 0) error = sbuf_finish(&m); @@ -1697,9 +1678,9 @@ i915_sysctl_init(struct drm_device *dev, struct sysctl_ctx_list *ctx, struct i915_info_sysctl_thunk *thunks; int i, error; - thunks = malloc(sizeof(*thunks) * DRM_ARRAY_SIZE(i915_info_sysctl_list), + thunks = malloc(sizeof(*thunks) * ARRAY_SIZE(i915_info_sysctl_list), DRM_MEM_DRIVER, M_WAITOK | M_ZERO); - for (i = 0; i < DRM_ARRAY_SIZE(i915_info_sysctl_list); i++) { + for (i = 0; i < ARRAY_SIZE(i915_info_sysctl_list); i++) { thunks[i].dev = dev; thunks[i].idx = i; thunks[i].arg = i915_info_sysctl_list[i].data; @@ -1708,15 +1689,15 @@ i915_sysctl_init(struct drm_device *dev, struct sysctl_ctx_list *ctx, info = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(top), OID_AUTO, "info", CTLFLAG_RW, NULL, NULL); if (info == NULL) - return (ENOMEM); - for (i = 0; i < DRM_ARRAY_SIZE(i915_info_sysctl_list); i++) { + return (-ENOMEM); + for (i = 0; i < ARRAY_SIZE(i915_info_sysctl_list); i++) { oid = SYSCTL_ADD_OID(ctx, SYSCTL_CHILDREN(info), OID_AUTO, i915_info_sysctl_list[i].name, CTLTYPE_STRING | (i915_info_sysctl_list[i].ptr_w != NULL ? CTLFLAG_RW : CTLFLAG_RD), &thunks[i], 0, i915_info_sysctl_handler, "A", NULL); if (oid == NULL) - return (ENOMEM); + return (-ENOMEM); } oid = SYSCTL_ADD_LONG(ctx, SYSCTL_CHILDREN(info), OID_AUTO, "i915_gem_wired_pages", CTLFLAG_RD, &i915_gem_wired_pages_cnt, @@ -1725,34 +1706,34 @@ i915_sysctl_init(struct drm_device *dev, struct sysctl_ctx_list *ctx, CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, dev, 0, i915_debug_set_wedged, "I", NULL); if (oid == NULL) - return (ENOMEM); + return (-ENOMEM); oid = SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(top), OID_AUTO, "max_freq", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, dev, 0, i915_max_freq, "I", NULL); if (oid == NULL) - return (ENOMEM); + return (-ENOMEM); oid = SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(top), OID_AUTO, "cache_sharing", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, dev, 0, i915_cache_sharing, "I", NULL); if (oid == NULL) - return (ENOMEM); + return (-ENOMEM); oid = SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(top), OID_AUTO, "stop_rings", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, dev, 0, i915_stop_rings, "I", NULL); if (oid == NULL) - return (ENOMEM); + return (-ENOMEM); oid = SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(top), OID_AUTO, "sync_exec", CTLFLAG_RW, &i915_gem_sync_exec_requests, 0, NULL); if (oid == NULL) - return (ENOMEM); + return (-ENOMEM); oid = SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(top), OID_AUTO, "fix_mi", CTLFLAG_RW, &i915_fix_mi_batchbuffer_end, 0, NULL); if (oid == NULL) - return (ENOMEM); + return (-ENOMEM); oid = SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(top), OID_AUTO, "intr_pf", CTLFLAG_RW, &i915_intr_pf, 0, NULL); if (oid == NULL) - return (ENOMEM); + return (-ENOMEM); error = drm_add_busid_modesetting(dev, ctx, top); if (error != 0) diff --git a/sys/dev/drm2/i915/i915_dma.c b/sys/dev/drm2/i915/i915_dma.c index 58dcae7b542d..910b35a4e734 100644 --- a/sys/dev/drm2/i915/i915_dma.c +++ b/sys/dev/drm2/i915/i915_dma.c @@ -65,12 +65,9 @@ intel_read_legacy_status_page(struct drm_i915_private *dev_priv, int reg) #define READ_BREADCRUMB(dev_priv) READ_HWSP(dev_priv, I915_BREADCRUMB_INDEX) #define I915_BREADCRUMB_INDEX 0x21 -static int i915_driver_unload_int(struct drm_device *dev, bool locked); - void i915_update_dri1_breadcrumb(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; -#if 0 struct drm_i915_master_private *master_priv; if (dev->primary->master) { @@ -79,11 +76,6 @@ void i915_update_dri1_breadcrumb(struct drm_device *dev) master_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); } -#else - if (dev_priv->sarea_priv) - dev_priv->sarea_priv->last_dispatch = - READ_BREADCRUMB(dev_priv); -#endif } static void i915_write_hws_pga(struct drm_device *dev) @@ -112,10 +104,8 @@ static int i915_init_phys_hws(struct drm_device *dev) * of allocation is used on <= 965 hardware, that has several * erratas regarding the use of physical memory > 4 GB. */ - DRM_UNLOCK(dev); dev_priv->status_page_dmah = - drm_pci_alloc(dev, PAGE_SIZE, PAGE_SIZE, 0xffffffff); - DRM_LOCK(dev); + drm_pci_alloc(dev, PAGE_SIZE, PAGE_SIZE, BUS_SPACE_MAXADDR); if (!dev_priv->status_page_dmah) { DRM_ERROR("Can not allocate hardware status page\n"); return -ENOMEM; @@ -160,6 +150,7 @@ static void i915_free_hws(struct drm_device *dev) void i915_kernel_lost_context(struct drm_device * dev) { drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_i915_master_private *master_priv; struct intel_ring_buffer *ring = LP_RING(dev_priv); /* @@ -175,15 +166,12 @@ void i915_kernel_lost_context(struct drm_device * dev) if (ring->space < 0) ring->space += ring->size; -#if 1 - KIB_NOTYET(); -#else if (!dev->primary->master) return; -#endif - if (ring->head == ring->tail && dev_priv->sarea_priv) - dev_priv->sarea_priv->perf_boxes |= I915_BOX_RING_EMPTY; + master_priv = dev->primary->master->driver_priv; + if (ring->head == ring->tail && master_priv->sarea_priv) + master_priv->sarea_priv->perf_boxes |= I915_BOX_RING_EMPTY; } static int i915_dma_cleanup(struct drm_device * dev) @@ -199,8 +187,10 @@ static int i915_dma_cleanup(struct drm_device * dev) if (dev->irq_enabled) drm_irq_uninstall(dev); + DRM_LOCK(dev); for (i = 0; i < I915_NUM_RINGS; i++) intel_cleanup_ring_buffer(&dev_priv->rings[i]); + DRM_UNLOCK(dev); /* Clear the HWS virtual address at teardown */ if (I915_NEED_GFX_HWS(dev)) @@ -212,18 +202,17 @@ static int i915_dma_cleanup(struct drm_device * dev) static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init) { drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; int ret; - dev_priv->sarea = drm_getsarea(dev); - if (!dev_priv->sarea) { - DRM_ERROR("can not find sarea!\n"); - i915_dma_cleanup(dev); - return -EINVAL; + master_priv->sarea = drm_getsarea(dev); + if (master_priv->sarea) { + master_priv->sarea_priv = (drm_i915_sarea_t *) + ((u8 *)master_priv->sarea->handle + init->sarea_priv_offset); + } else { + DRM_DEBUG_DRIVER("sarea not found assuming DRI2 userspace\n"); } - dev_priv->sarea_priv = (drm_i915_sarea_t *) - ((u8 *) dev_priv->sarea->virtual + init->sarea_priv_offset); - if (init->ring_size != 0) { if (LP_RING(dev_priv)->obj != NULL) { i915_dma_cleanup(dev); @@ -245,7 +234,8 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init) dev_priv->back_offset = init->back_offset; dev_priv->front_offset = init->front_offset; dev_priv->current_page = 0; - dev_priv->sarea_priv->pf_current_page = 0; + if (master_priv->sarea_priv) + master_priv->sarea_priv->pf_current_page = 0; /* Allow hardware batchbuffers unless told otherwise. */ @@ -485,11 +475,12 @@ i915_emit_box_p(struct drm_device *dev, struct drm_clip_rect *box, static void i915_emit_breadcrumb(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; if (++dev_priv->counter > 0x7FFFFFFFUL) dev_priv->counter = 0; - if (dev_priv->sarea_priv) - dev_priv->sarea_priv->last_enqueue = dev_priv->counter; + if (master_priv->sarea_priv) + master_priv->sarea_priv->last_enqueue = dev_priv->counter; if (BEGIN_LP_RING(4) == 0) { OUT_RING(MI_STORE_DWORD_INDEX); @@ -594,15 +585,17 @@ i915_dispatch_batchbuffer(struct drm_device * dev, static int i915_dispatch_flip(struct drm_device * dev) { drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_i915_master_private *master_priv = + dev->primary->master->driver_priv; int ret; - if (!dev_priv->sarea_priv) + if (!master_priv->sarea_priv) return -EINVAL; DRM_DEBUG("%s: page=%d pfCurrentPage=%d\n", __func__, dev_priv->current_page, - dev_priv->sarea_priv->pf_current_page); + master_priv->sarea_priv->pf_current_page); i915_kernel_lost_context(dev); @@ -628,10 +621,7 @@ static int i915_dispatch_flip(struct drm_device * dev) ADVANCE_LP_RING(); - if (++dev_priv->counter > 0x7FFFFFFFUL) - dev_priv->counter = 0; - if (dev_priv->sarea_priv) - dev_priv->sarea_priv->last_enqueue = dev_priv->counter; + master_priv->sarea_priv->last_enqueue = dev_priv->counter++; if (BEGIN_LP_RING(4) == 0) { OUT_RING(MI_STORE_DWORD_INDEX); @@ -641,7 +631,7 @@ static int i915_dispatch_flip(struct drm_device * dev) ADVANCE_LP_RING(); } - dev_priv->sarea_priv->pf_current_page = dev_priv->current_page; + master_priv->sarea_priv->pf_current_page = dev_priv->current_page; return 0; } @@ -675,7 +665,9 @@ int i915_batchbuffer(struct drm_device *dev, void *data, struct drm_file *file_priv) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - drm_i915_sarea_t *sarea_priv; + struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; + drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *) + master_priv->sarea_priv; drm_i915_batchbuffer_t *batch = data; struct drm_clip_rect *cliprects; size_t cliplen; @@ -685,7 +677,6 @@ int i915_batchbuffer(struct drm_device *dev, void *data, DRM_ERROR("Batchbuffer ioctl disabled\n"); return -EINVAL; } - DRM_UNLOCK(dev); DRM_DEBUG("i915 batchbuffer, start %x used %d cliprects %d\n", batch->start, batch->used, batch->num_cliprects); @@ -700,18 +691,16 @@ int i915_batchbuffer(struct drm_device *dev, void *data, ret = -copyin(batch->cliprects, cliprects, batch->num_cliprects * sizeof(struct drm_clip_rect)); - if (ret != 0) { - DRM_LOCK(dev); + if (ret != 0) goto fail_free; - } } else cliprects = NULL; DRM_LOCK(dev); RING_LOCK_TEST_WITH_RETURN(dev, file_priv); ret = i915_dispatch_batchbuffer(dev, batch, cliprects); + DRM_UNLOCK(dev); - sarea_priv = (drm_i915_sarea_t *)dev_priv->sarea_priv; if (sarea_priv) sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); @@ -724,7 +713,9 @@ int i915_cmdbuffer(struct drm_device *dev, void *data, struct drm_file *file_priv) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - drm_i915_sarea_t *sarea_priv; + struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; + drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *) + master_priv->sarea_priv; drm_i915_cmdbuffer_t *cmdbuf = data; struct drm_clip_rect *cliprects = NULL; void *batch_data; @@ -739,15 +730,11 @@ int i915_cmdbuffer(struct drm_device *dev, void *data, if (cmdbuf->num_cliprects < 0) return -EINVAL; - DRM_UNLOCK(dev); - batch_data = malloc(cmdbuf->sz, DRM_MEM_DMA, M_WAITOK); ret = -copyin(cmdbuf->buf, batch_data, cmdbuf->sz); - if (ret != 0) { - DRM_LOCK(dev); + if (ret != 0) goto fail_batch_free; - } if (cmdbuf->num_cliprects) { cliprects = malloc(cmdbuf->num_cliprects * @@ -755,21 +742,19 @@ int i915_cmdbuffer(struct drm_device *dev, void *data, M_WAITOK | M_ZERO); ret = -copyin(cmdbuf->cliprects, cliprects, cmdbuf->num_cliprects * sizeof(struct drm_clip_rect)); - if (ret != 0) { - DRM_LOCK(dev); + if (ret != 0) goto fail_clip_free; - } } DRM_LOCK(dev); RING_LOCK_TEST_WITH_RETURN(dev, file_priv); ret = i915_dispatch_cmdbuffer(dev, cmdbuf, cliprects, batch_data); + DRM_UNLOCK(dev); if (ret) { DRM_ERROR("i915_dispatch_cmdbuffer failed\n"); goto fail_clip_free; } - sarea_priv = (drm_i915_sarea_t *)dev_priv->sarea_priv; if (sarea_priv) sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); @@ -783,9 +768,7 @@ fail_batch_free: static int i915_emit_irq(struct drm_device * dev) { drm_i915_private_t *dev_priv = dev->dev_private; -#if 0 struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; -#endif i915_kernel_lost_context(dev); @@ -794,13 +777,8 @@ static int i915_emit_irq(struct drm_device * dev) dev_priv->counter++; if (dev_priv->counter > 0x7FFFFFFFUL) dev_priv->counter = 1; -#if 0 if (master_priv->sarea_priv) master_priv->sarea_priv->last_enqueue = dev_priv->counter; -#else - if (dev_priv->sarea_priv) - dev_priv->sarea_priv->last_enqueue = dev_priv->counter; -#endif if (BEGIN_LP_RING(4) == 0) { OUT_RING(MI_STORE_DWORD_INDEX); @@ -816,16 +794,13 @@ static int i915_emit_irq(struct drm_device * dev) static int i915_wait_irq(struct drm_device * dev, int irq_nr) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; -#if 0 struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; -#endif int ret; struct intel_ring_buffer *ring = LP_RING(dev_priv); DRM_DEBUG("irq_nr=%d breadcrumb=%d\n", irq_nr, READ_BREADCRUMB(dev_priv)); -#if 0 if (READ_BREADCRUMB(dev_priv) >= irq_nr) { if (master_priv->sarea_priv) master_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); @@ -834,30 +809,18 @@ static int i915_wait_irq(struct drm_device * dev, int irq_nr) if (master_priv->sarea_priv) master_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT; -#else - if (READ_BREADCRUMB(dev_priv) >= irq_nr) { - if (dev_priv->sarea_priv) { - dev_priv->sarea_priv->last_dispatch = - READ_BREADCRUMB(dev_priv); - } - return 0; - } - - if (dev_priv->sarea_priv) - dev_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT; -#endif ret = 0; mtx_lock(&dev_priv->irq_lock); if (ring->irq_get(ring)) { - DRM_UNLOCK(dev); while (ret == 0 && READ_BREADCRUMB(dev_priv) < irq_nr) { ret = -msleep(ring, &dev_priv->irq_lock, PCATCH, "915wtq", 3 * hz); + if (ret == -ERESTART) + ret = -ERESTARTSYS; } ring->irq_put(ring); mtx_unlock(&dev_priv->irq_lock); - DRM_LOCK(dev); } else { mtx_unlock(&dev_priv->irq_lock); if (_intel_wait_for(dev, READ_BREADCRUMB(dev_priv) >= irq_nr, @@ -977,7 +940,9 @@ static int i915_flip_bufs(struct drm_device *dev, void *data, RING_LOCK_TEST_WITH_RETURN(dev, file_priv); + DRM_LOCK(dev); ret = i915_dispatch_flip(dev); + DRM_UNLOCK(dev); return ret; } @@ -1200,6 +1165,31 @@ cleanup_vga_switcheroo: return (ret); } +int i915_master_create(struct drm_device *dev, struct drm_master *master) +{ + struct drm_i915_master_private *master_priv; + + master_priv = malloc(sizeof(*master_priv), DRM_MEM_DMA, + M_NOWAIT | M_ZERO); + if (!master_priv) + return -ENOMEM; + + master->driver_priv = master_priv; + return 0; +} + +void i915_master_destroy(struct drm_device *dev, struct drm_master *master) +{ + struct drm_i915_master_private *master_priv = master->driver_priv; + + if (!master_priv) + return; + + free(master_priv, DRM_MEM_DMA); + + master->driver_priv = NULL; +} + static int i915_get_bridge_dev(struct drm_device *dev) { @@ -1250,10 +1240,10 @@ intel_alloc_mchbar_resource(struct drm_device *dev) #endif /* Get some space for it */ - vga = device_get_parent(dev->device); + vga = device_get_parent(dev->dev); dev_priv->mch_res_rid = 0x100; dev_priv->mch_res = BUS_ALLOC_RESOURCE(device_get_parent(vga), - dev->device, SYS_RES_MEMORY, &dev_priv->mch_res_rid, 0, ~0UL, + dev->dev, SYS_RES_MEMORY, &dev_priv->mch_res_rid, 0, ~0UL, MCHBAR_SIZE, RF_ACTIVE | RF_SHAREABLE); if (dev_priv->mch_res == NULL) { DRM_ERROR("failed mchbar resource alloc\n"); @@ -1340,10 +1330,10 @@ intel_teardown_mchbar(struct drm_device *dev) } if (dev_priv->mch_res != NULL) { - vga = device_get_parent(dev->device); - BUS_DEACTIVATE_RESOURCE(device_get_parent(vga), dev->device, + vga = device_get_parent(dev->dev); + BUS_DEACTIVATE_RESOURCE(device_get_parent(vga), dev->dev, SYS_RES_MEMORY, dev_priv->mch_res_rid, dev_priv->mch_res); - BUS_RELEASE_RESOURCE(device_get_parent(vga), dev->device, + BUS_RELEASE_RESOURCE(device_get_parent(vga), dev->dev, SYS_RES_MEMORY, dev_priv->mch_res_rid, dev_priv->mch_res); dev_priv->mch_res = NULL; } @@ -1393,6 +1383,11 @@ i915_driver_load(struct drm_device *dev, unsigned long flags) ret = drm_addmap(dev, base, size, _DRM_REGISTERS, _DRM_KERNEL | _DRM_DRIVER, &dev_priv->mmio_map); + if (ret != 0) { + DRM_ERROR("Failed to allocate mmio_map: %d\n", ret); + free(dev_priv, DRM_MEM_DRIVER); + return (ret); + } dev_priv->tq = taskqueue_create("915", M_WAITOK, taskqueue_thread_enqueue, &dev_priv->tq); @@ -1413,13 +1408,26 @@ i915_driver_load(struct drm_device *dev, unsigned long flags) i915_gem_load(dev); + /* On the 945G/GM, the chipset reports the MSI capability on the + * integrated graphics even though the support isn't actually there + * according to the published specs. It doesn't appear to function + * correctly in testing on 945G. + * This may be a side effect of MSI having been made available for PEG + * and the registers being closely associated. + * + * According to chipset errata, on the 965GM, MSI interrupts may + * be lost or delayed, but we use them anyways to avoid + * stuck interrupts on some machines. + */ + if (!IS_I945G(dev) && !IS_I945GM(dev)) + drm_pci_enable_msi(dev); + /* Init HWS */ if (!I915_NEED_GFX_HWS(dev)) { ret = i915_init_phys_hws(dev); if (ret != 0) { drm_rmmap(dev, dev_priv->mmio_map); - drm_free(dev_priv, sizeof(struct drm_i915_private), - DRM_MEM_DRIVER); + free(dev_priv, DRM_MEM_DRIVER); return ret; } } @@ -1443,9 +1451,7 @@ i915_driver_load(struct drm_device *dev, unsigned long flags) intel_detect_pch(dev); if (drm_core_check_feature(dev, DRIVER_MODESET)) { - DRM_UNLOCK(dev); ret = i915_load_modeset_init(dev); - DRM_LOCK(dev); if (ret < 0) { DRM_ERROR("failed to init modeset\n"); goto out_gem_unload; @@ -1465,31 +1471,27 @@ i915_driver_load(struct drm_device *dev, unsigned long flags) out_gem_unload: /* XXXKIB */ - (void) i915_driver_unload_int(dev, true); + (void) i915_driver_unload(dev); return (ret); } -static int -i915_driver_unload_int(struct drm_device *dev, bool locked) +int +i915_driver_unload(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; int ret; - if (!locked) - DRM_LOCK(dev); + DRM_LOCK(dev); ret = i915_gpu_idle(dev); if (ret) DRM_ERROR("failed to idle hardware: %d\n", ret); i915_gem_retire_requests(dev); - if (!locked) - DRM_UNLOCK(dev); + DRM_UNLOCK(dev); i915_free_hws(dev); intel_teardown_mchbar(dev); - if (locked) - DRM_UNLOCK(dev); if (drm_core_check_feature(dev, DRIVER_MODESET)) { intel_fbdev_fini(dev); intel_modeset_cleanup(dev); @@ -1501,19 +1503,17 @@ i915_driver_unload_int(struct drm_device *dev, bool locked) i915_destroy_error_state(dev); - intel_opregion_fini(dev); + if (dev->msi_enabled) + drm_pci_disable_msi(dev); - if (locked) - DRM_LOCK(dev); + intel_opregion_fini(dev); if (drm_core_check_feature(dev, DRIVER_MODESET)) { - if (!locked) - DRM_LOCK(dev); + DRM_LOCK(dev); i915_gem_free_all_phys_object(dev); i915_gem_cleanup_ringbuffer(dev); i915_gem_context_fini(dev); - if (!locked) - DRM_UNLOCK(dev); + DRM_UNLOCK(dev); i915_gem_cleanup_aliasing_ppgtt(dev); #if 1 KIB_NOTYET(); @@ -1536,7 +1536,7 @@ i915_driver_unload_int(struct drm_device *dev, bool locked) if (dev_priv->tq != NULL) taskqueue_free(dev_priv->tq); - bus_generic_detach(dev->device); + bus_generic_detach(dev->dev); drm_rmmap(dev, dev_priv->mmio_map); intel_teardown_gmbus(dev); @@ -1544,20 +1544,12 @@ i915_driver_unload_int(struct drm_device *dev, bool locked) mtx_destroy(&dev_priv->error_lock); mtx_destroy(&dev_priv->error_completion_lock); mtx_destroy(&dev_priv->rps_lock); - drm_free(dev->dev_private, sizeof(drm_i915_private_t), - DRM_MEM_DRIVER); + free(dev->dev_private, DRM_MEM_DRIVER); return (0); } int -i915_driver_unload(struct drm_device *dev) -{ - - return (i915_driver_unload_int(dev, true)); -} - -int i915_driver_open(struct drm_device *dev, struct drm_file *file_priv) { struct drm_i915_file_private *i915_file_priv; @@ -1604,7 +1596,7 @@ void i915_driver_postclose(struct drm_device *dev, struct drm_file *file_priv) struct drm_i915_file_private *i915_file_priv = file_priv->driver_priv; mtx_destroy(&i915_file_priv->mm.lck); - drm_free(i915_file_priv, sizeof(*i915_file_priv), DRM_MEM_FILES); + free(i915_file_priv, DRM_MEM_FILES); } struct drm_ioctl_desc i915_ioctls[] = { @@ -1625,24 +1617,24 @@ struct drm_ioctl_desc i915_ioctls[] = { DRM_IOCTL_DEF(DRM_I915_GET_VBLANK_PIPE, i915_vblank_pipe_get, DRM_AUTH ), DRM_IOCTL_DEF(DRM_I915_VBLANK_SWAP, i915_vblank_swap, DRM_AUTH), DRM_IOCTL_DEF(DRM_I915_HWS_ADDR, i915_set_status_page, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_I915_GEM_INIT, i915_gem_init_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), + DRM_IOCTL_DEF(DRM_I915_GEM_INIT, i915_gem_init_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY|DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_I915_GEM_EXECBUFFER, i915_gem_execbuffer, DRM_AUTH | DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_I915_GEM_EXECBUFFER2, i915_gem_execbuffer2, DRM_AUTH | DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_I915_GEM_PIN, i915_gem_pin_ioctl, DRM_AUTH|DRM_ROOT_ONLY|DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_I915_GEM_UNPIN, i915_gem_unpin_ioctl, DRM_AUTH|DRM_ROOT_ONLY|DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_I915_GEM_BUSY, i915_gem_busy_ioctl, DRM_AUTH|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I915_GEM_THROTTLE, i915_gem_throttle_ioctl, DRM_AUTH), - DRM_IOCTL_DEF(DRM_I915_GEM_ENTERVT, i915_gem_entervt_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_I915_GEM_LEAVEVT, i915_gem_leavevt_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_I915_GEM_CREATE, i915_gem_create_ioctl, 0), + DRM_IOCTL_DEF(DRM_I915_GEM_THROTTLE, i915_gem_throttle_ioctl, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_I915_GEM_ENTERVT, i915_gem_entervt_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_I915_GEM_LEAVEVT, i915_gem_leavevt_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_I915_GEM_CREATE, i915_gem_create_ioctl, DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_I915_GEM_PREAD, i915_gem_pread_ioctl, DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_I915_GEM_PWRITE, i915_gem_pwrite_ioctl, DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I915_GEM_MMAP, i915_gem_mmap_ioctl, 0), + DRM_IOCTL_DEF(DRM_I915_GEM_MMAP, i915_gem_mmap_ioctl, DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_I915_GEM_MMAP_GTT, i915_gem_mmap_gtt_ioctl, DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_I915_GEM_SET_DOMAIN, i915_gem_set_domain_ioctl, DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_I915_GEM_SW_FINISH, i915_gem_sw_finish_ioctl, DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_I915_GEM_SET_TILING, i915_gem_set_tiling, 0), - DRM_IOCTL_DEF(DRM_I915_GEM_GET_TILING, i915_gem_get_tiling, 0), + DRM_IOCTL_DEF(DRM_I915_GEM_SET_TILING, i915_gem_set_tiling, DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_I915_GEM_GET_TILING, i915_gem_get_tiling, DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_I915_GEM_GET_APERTURE, i915_gem_get_aperture_ioctl, DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_I915_GET_PIPE_FROM_CRTC_ID, intel_get_pipe_from_crtc_id, DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_I915_GEM_MADVISE, i915_gem_madvise_ioctl, DRM_UNLOCKED), @@ -1655,14 +1647,18 @@ struct drm_ioctl_desc i915_ioctls[] = { }; #ifdef COMPAT_FREEBSD32 -extern drm_ioctl_desc_t i915_compat_ioctls[]; +extern struct drm_ioctl_desc i915_compat_ioctls[]; extern int i915_compat_ioctls_nr; #endif -struct drm_driver_info i915_driver_info = { - .driver_features = DRIVER_USE_AGP | DRIVER_REQUIRE_AGP | - DRIVER_USE_MTRR | DRIVER_HAVE_IRQ | DRIVER_LOCKLESS_IRQ | - DRIVER_GEM /*| DRIVER_MODESET*/, +struct drm_driver i915_driver_info = { + /* + * FIXME Linux<->FreeBSD: DRIVER_USE_MTRR is commented out on + * Linux. + */ + .driver_features = + DRIVER_USE_AGP | DRIVER_REQUIRE_AGP | DRIVER_USE_MTRR | + DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_GEM | DRIVER_PRIME, .buf_priv_size = sizeof(drm_i915_private_t), .load = i915_driver_load, @@ -1672,6 +1668,8 @@ struct drm_driver_info i915_driver_info = { .lastclose = i915_driver_lastclose, .postclose = i915_driver_postclose, .device_is_agp = i915_driver_device_is_agp, + .master_create = i915_master_create, + .master_destroy = i915_master_destroy, .gem_init_object = i915_gem_init_object, .gem_free_object = i915_gem_free_object, .gem_pager_ops = &i915_gem_pager_ops, @@ -1684,9 +1682,9 @@ struct drm_driver_info i915_driver_info = { .ioctls = i915_ioctls, #ifdef COMPAT_FREEBSD32 .compat_ioctls = i915_compat_ioctls, - .compat_ioctls_nr = &i915_compat_ioctls_nr, + .num_compat_ioctls = &i915_compat_ioctls_nr, #endif - .max_ioctl = DRM_ARRAY_SIZE(i915_ioctls), + .num_ioctls = ARRAY_SIZE(i915_ioctls), .name = DRIVER_NAME, .desc = DRIVER_DESC, @@ -1705,4 +1703,3 @@ int i915_driver_device_is_agp(struct drm_device * dev) { return 1; } - diff --git a/sys/dev/drm2/i915/i915_drm.h b/sys/dev/drm2/i915/i915_drm.h index c6e5c7e6b8f9..968bba54fc14 100644 --- a/sys/dev/drm2/i915/i915_drm.h +++ b/sys/dev/drm2/i915/i915_drm.h @@ -72,7 +72,7 @@ typedef struct _drm_i915_init { unsigned int sarea_handle; } drm_i915_init_t; -typedef struct drm_i915_sarea { +typedef struct _drm_i915_sarea { struct drm_tex_region texList[I915_NR_TEX_REGIONS + 1]; int last_upload; /* last time texture was uploaded */ int last_enqueue; /* last time a buffer was enqueued */ @@ -114,14 +114,14 @@ typedef struct drm_i915_sarea { unsigned int rotated_tiled; unsigned int rotated2_tiled; - int planeA_x; - int planeA_y; - int planeA_w; - int planeA_h; - int planeB_x; - int planeB_y; - int planeB_w; - int planeB_h; + int pipeA_x; + int pipeA_y; + int pipeA_w; + int pipeA_h; + int pipeB_x; + int pipeB_y; + int pipeB_w; + int pipeB_h; /* Triple buffering */ drm_handle_t third_handle; @@ -139,6 +139,16 @@ typedef struct drm_i915_sarea { unsigned int depth_bo_handle; } drm_i915_sarea_t; +/* due to userspace building against these headers we need some compat here */ +#define planeA_x pipeA_x +#define planeA_y pipeA_y +#define planeA_w pipeA_w +#define planeA_h pipeA_h +#define planeB_x pipeB_x +#define planeB_y pipeB_y +#define planeB_w pipeB_w +#define planeB_h pipeB_h + /* Driver specific fence types and classes. */ @@ -224,7 +234,6 @@ typedef struct drm_i915_sarea { #define DRM_IOCTL_I915_GET_VBLANK_PIPE DRM_IOR( DRM_COMMAND_BASE + DRM_I915_GET_VBLANK_PIPE, drm_i915_vblank_pipe_t) #define DRM_IOCTL_I915_VBLANK_SWAP DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_VBLANK_SWAP, drm_i915_vblank_swap_t) #define DRM_IOCTL_I915_MMIO DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_MMIO, drm_i915_mmio) -#define DRM_IOCTL_I915_EXECBUFFER DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_EXECBUFFER, struct drm_i915_execbuffer) #define DRM_IOCTL_I915_GEM_INIT DRM_IOW(DRM_COMMAND_BASE + DRM_I915_GEM_INIT, struct drm_i915_gem_init) #define DRM_IOCTL_I915_GEM_EXECBUFFER DRM_IOW(DRM_COMMAND_BASE + DRM_I915_GEM_EXECBUFFER, struct drm_i915_gem_execbuffer) #define DRM_IOCTL_I915_GEM_EXECBUFFER2 DRM_IOW(DRM_COMMAND_BASE + DRM_I915_GEM_EXECBUFFER2, struct drm_i915_gem_execbuffer2) @@ -447,26 +456,6 @@ typedef struct drm_i915_hws_addr { #define I915_RELOC1_STRIDE 4 -struct drm_i915_op_arg { - uint64_t next; - uint64_t reloc_ptr; - int handled; - unsigned int pad64; - union { - struct drm_bo_op_req req; - struct drm_bo_arg_rep rep; - } d; - -}; - -struct drm_i915_execbuffer { - uint64_t ops_list; - uint32_t num_buffers; - struct drm_i915_batchbuffer batch; - drm_context_t context; /* for lockless use in the future */ - struct drm_fence_arg fence_arg; -}; - struct drm_i915_gem_init { /** * Beginning offset in the GTT to be managed by the DRM memory diff --git a/sys/dev/drm2/i915/i915_drv.c b/sys/dev/drm2/i915/i915_drv.c index ef6a1513b2ee..d38c1c97904b 100644 --- a/sys/dev/drm2/i915/i915_drv.c +++ b/sys/dev/drm2/i915/i915_drv.c @@ -298,13 +298,11 @@ static int i915_drm_freeze(struct drm_device *dev) pci_save_state(dev->pdev); #endif - DRM_LOCK(dev); /* If KMS is active, we do the leavevt stuff here */ if (drm_core_check_feature(dev, DRIVER_MODESET)) { - error = -i915_gem_idle(dev); + error = i915_gem_idle(dev); if (error) { - DRM_UNLOCK(dev); - device_printf(dev->device, + device_printf(dev->dev, "GEM idle failed, resume might fail\n"); return (error); } @@ -317,7 +315,6 @@ static int i915_drm_freeze(struct drm_device *dev) /* Modeset on resume, not lid events */ dev_priv->modeset_on_lid = 0; - DRM_UNLOCK(dev); return 0; } @@ -331,13 +328,13 @@ i915_suspend(device_t kdev) dev = device_get_softc(kdev); if (dev == NULL || dev->dev_private == NULL) { DRM_ERROR("DRM not initialized, aborting suspend.\n"); - return -ENODEV; + return ENODEV; } DRM_DEBUG_KMS("starting suspend\n"); error = i915_drm_freeze(dev); if (error) - return (error); + return (-error); error = bus_generic_suspend(kdev); DRM_DEBUG_KMS("finished suspend %d\n", error); @@ -349,9 +346,10 @@ static int i915_drm_thaw(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; int error = 0; - DRM_LOCK(dev); if (drm_core_check_feature(dev, DRIVER_MODESET)) { + DRM_LOCK(dev); i915_gem_restore_gtt_mappings(dev); + DRM_UNLOCK(dev); } i915_restore_state(dev); @@ -362,6 +360,7 @@ static int i915_drm_thaw(struct drm_device *dev) if (HAS_PCH_SPLIT(dev)) ironlake_init_pch_refclk(dev); + DRM_LOCK(dev); dev_priv->mm.suspended = 0; error = i915_gem_init_hw(dev); @@ -377,15 +376,12 @@ static int i915_drm_thaw(struct drm_device *dev) /* Resume the modeset for every activated CRTC */ drm_helper_resume_force_mode(dev); sx_xunlock(&dev->mode_config.mutex); - DRM_LOCK(dev); } intel_opregion_init(dev); dev_priv->modeset_on_lid = 0; - DRM_UNLOCK(dev); - return error; } @@ -404,9 +400,9 @@ i915_resume(device_t kdev) pci_set_master(dev->pdev); #endif - ret = -i915_drm_thaw(dev); + ret = i915_drm_thaw(dev); if (ret != 0) - return (ret); + return (-ret); drm_kms_helper_poll_enable(dev); ret = bus_generic_resume(kdev); @@ -420,9 +416,9 @@ i915_probe(device_t kdev) const struct intel_device_info *info; int error; - error = drm_probe(kdev, i915_pciidlist); + error = drm_probe_helper(kdev, i915_pciidlist); if (error != 0) - return (error); + return (-error); info = i915_get_device_id(pci_get_device(kdev)); if (info == NULL) return (ENXIO); @@ -434,13 +430,10 @@ int i915_modeset; static int i915_attach(device_t kdev) { - struct drm_device *dev; - dev = device_get_softc(kdev); if (i915_modeset == 1) i915_driver_info.driver_features |= DRIVER_MODESET; - dev->driver = &i915_driver_info; - return (drm_attach(kdev, i915_pciidlist)); + return (-drm_attach_helper(kdev, i915_pciidlist, &i915_driver_info)); } static struct fb_info * @@ -483,7 +476,7 @@ static device_method_t i915_methods[] = { DEVMETHOD(device_attach, i915_attach), DEVMETHOD(device_suspend, i915_suspend), DEVMETHOD(device_resume, i915_resume), - DEVMETHOD(device_detach, drm_detach), + DEVMETHOD(device_detach, drm_generic_detach), /* Framebuffer service methods */ DEVMETHOD(fb_getinfo, i915_fb_helper_getinfo), @@ -773,7 +766,7 @@ i965_reset_complete(struct drm_device *dev) { u8 gdrst; - gdrst = pci_read_config(dev->device, I965_GDRST, 1); + gdrst = pci_read_config(dev->dev, I965_GDRST, 1); return (gdrst & GRDOM_RESET_ENABLE) == 0; } @@ -788,8 +781,8 @@ i965_do_reset(struct drm_device *dev) * well as the reset bit (GR/bit 0). Setting the GR bit * triggers the reset; when done, the hardware will clear it. */ - gdrst = pci_read_config(dev->device, I965_GDRST, 1); - pci_write_config(dev->device, I965_GDRST, + gdrst = pci_read_config(dev->dev, I965_GDRST, 1); + pci_write_config(dev->dev, I965_GDRST, gdrst | GRDOM_RENDER | GRDOM_RESET_ENABLE, 1); ret = wait_for(i965_reset_complete(dev), 500); @@ -797,8 +790,8 @@ i965_do_reset(struct drm_device *dev) return ret; /* We can't reset render&media without also resetting display ... */ - gdrst = pci_read_config(dev->device, I965_GDRST, 1); - pci_write_config(dev->device, I965_GDRST, + gdrst = pci_read_config(dev->dev, I965_GDRST, 1); + pci_write_config(dev->dev, I965_GDRST, gdrst | GRDOM_MEDIA | GRDOM_RESET_ENABLE, 1); return wait_for(i965_reset_complete(dev), 500); @@ -949,9 +942,7 @@ int i915_reset(struct drm_device *dev) if (drm_core_check_feature(dev, DRIVER_MODESET)) intel_modeset_init_hw(dev); - DRM_LOCK(dev); drm_irq_uninstall(dev); - DRM_UNLOCK(dev); drm_irq_install(dev); } else DRM_UNLOCK(dev); diff --git a/sys/dev/drm2/i915/i915_drv.h b/sys/dev/drm2/i915/i915_drv.h index a51282cac08c..0a79d3b5c467 100644 --- a/sys/dev/drm2/i915/i915_drv.h +++ b/sys/dev/drm2/i915/i915_drv.h @@ -248,6 +248,10 @@ struct intel_opregion { }; #define OPREGION_SIZE (8*1024) +struct drm_i915_master_private { + drm_local_map_t *sarea; + struct _drm_i915_sarea *sarea_priv; +}; #define I915_FENCE_REG_NONE -1 #define I915_MAX_NUM_FENCES 16 /* 16 fences + sign bit for FENCE_REG_NONE */ @@ -295,7 +299,6 @@ typedef struct drm_i915_private { int relative_constants_mode; - drm_local_map_t *sarea; drm_local_map_t *mmio_map; /** gt_fifo_count and the subsequent register write are synchronized @@ -306,7 +309,6 @@ typedef struct drm_i915_private { /** gt_lock is also taken in irq contexts. */ struct mtx gt_lock; - drm_i915_sarea_t *sarea_priv; /* drm_i915_ring_buffer_t ring; */ struct intel_ring_buffer rings[I915_NUM_RINGS]; uint32_t next_seqno; @@ -1067,7 +1069,7 @@ struct drm_i915_error_state { extern int intel_iommu_enabled; extern struct drm_ioctl_desc i915_ioctls[]; -extern struct drm_driver_info i915_driver_info; +extern struct drm_driver i915_driver_info; extern struct cdev_pager_ops i915_gem_pager_ops; extern unsigned int i915_fbpercrtc; extern int i915_panel_ignore_lid; @@ -1094,6 +1096,9 @@ int i915_sysctl_init(struct drm_device *dev, struct sysctl_ctx_list *ctx, struct sysctl_oid *top); void i915_sysctl_cleanup(struct drm_device *dev); +extern int i915_master_create(struct drm_device *dev, struct drm_master *master); +extern void i915_master_destroy(struct drm_device *dev, struct drm_master *master); + /* i915_dma.c */ int i915_batchbuffer(struct drm_device *dev, void *data, struct drm_file *file_priv); diff --git a/sys/dev/drm2/i915/i915_gem.c b/sys/dev/drm2/i915/i915_gem.c index cf346fc9a146..a47303155fab 100644 --- a/sys/dev/drm2/i915/i915_gem.c +++ b/sys/dev/drm2/i915/i915_gem.c @@ -161,6 +161,8 @@ i915_gem_wait_for_error(struct drm_device *dev) while (dev_priv->error_completion == 0) { ret = -msleep(&dev_priv->error_completion, &dev_priv->error_completion_lock, PCATCH, "915wco", 0); + if (ret == -ERESTART) + ret = -ERESTARTSYS; if (ret != 0) { mtx_unlock(&dev_priv->error_completion_lock); return (ret); @@ -299,6 +301,7 @@ i915_gem_init_ioctl(struct drm_device *dev, void *data, { struct drm_i915_gem_init *args; drm_i915_private_t *dev_priv; + int error; if (drm_core_check_feature(dev, DRIVER_MODESET)) return -ENODEV; @@ -321,8 +324,11 @@ i915_gem_init_ioctl(struct drm_device *dev, void *data, * XXXKIB. The second-time initialization should be guarded * against. */ - return (i915_gem_init_global_gtt(dev, args->gtt_start, args->gtt_end, - args->gtt_end)); + DRM_LOCK(dev); + error = i915_gem_init_global_gtt(dev, args->gtt_start, + args->gtt_end, args->gtt_end); + DRM_UNLOCK(dev); + return (error); } int @@ -331,20 +337,28 @@ i915_gem_idle(struct drm_device *dev) drm_i915_private_t *dev_priv; int ret; + DRM_LOCK(dev); + dev_priv = dev->dev_private; - if (dev_priv->mm.suspended) + if (dev_priv->mm.suspended) { + DRM_UNLOCK(dev); return (0); + } ret = i915_gpu_idle(dev); - if (ret != 0) + if (ret != 0) { + DRM_UNLOCK(dev); return (ret); + } i915_gem_retire_requests(dev); /* Under UMS, be paranoid and evict. */ if (!drm_core_check_feature(dev, DRIVER_MODESET)) { ret = i915_gem_evict_everything(dev, false); - if (ret != 0) + if (ret != 0) { + DRM_UNLOCK(dev); return ret; + } } i915_gem_reset_fences(dev); @@ -359,6 +373,8 @@ i915_gem_idle(struct drm_device *dev) i915_kernel_lost_context(dev); i915_gem_cleanup_ringbuffer(dev); + DRM_UNLOCK(dev); + /* Cancel the retire work handler, which should be idle now. */ taskqueue_cancel_timeout(dev_priv->tq, &dev_priv->mm.retire_task, NULL); return (ret); @@ -613,7 +629,7 @@ i915_gem_object_pin(struct drm_i915_gem_object *obj, uint32_t alignment, void i915_gem_object_unpin(struct drm_i915_gem_object *obj) { - + KASSERT(obj->pin_count != 0, ("zero pin count")); KASSERT(obj->gtt_space != NULL, ("No gtt mapping")); @@ -873,10 +889,12 @@ i915_gem_entervt_ioctl(struct drm_device *dev, void *data, atomic_store_rel_int(&dev_priv->mm.wedged, 0); } + DRM_LOCK(dev); dev_priv->mm.suspended = 0; ret = i915_gem_init_hw(dev); if (ret != 0) { + DRM_UNLOCK(dev); return (ret); } @@ -884,16 +902,18 @@ i915_gem_entervt_ioctl(struct drm_device *dev, void *data, KASSERT(list_empty(&dev_priv->mm.flushing_list), ("flushing list")); KASSERT(list_empty(&dev_priv->mm.inactive_list), ("inactive list")); DRM_UNLOCK(dev); + ret = drm_irq_install(dev); - DRM_LOCK(dev); if (ret) goto cleanup_ringbuffer; return (0); cleanup_ringbuffer: + DRM_LOCK(dev); i915_gem_cleanup_ringbuffer(dev); dev_priv->mm.suspended = 1; + DRM_UNLOCK(dev); return (ret); } @@ -926,13 +946,12 @@ i915_gem_create(struct drm_file *file, struct drm_device *dev, uint64_t size, if (obj == NULL) return (-ENOMEM); - handle = 0; ret = drm_gem_handle_create(file, &obj->base, &handle); if (ret != 0) { drm_gem_object_release(&obj->base); i915_gem_info_remove_obj(dev->dev_private, obj->base.size); free(obj, DRM_I915_GEM); - return (-ret); + return (ret); } /* drop reference from allocate - handle holds it now */ @@ -976,23 +995,12 @@ i915_gem_create_ioctl(struct drm_device *dev, void *data, #define to_user_ptr(x) ((void *)(uintptr_t)(x)) #define offset_in_page(x) ((x) & PAGE_MASK) #define page_to_phys(x) VM_PAGE_TO_PHYS(x) -static inline long -__copy_to_user(void __user *to, const void *from, unsigned long n) -{ - return (copyout(from, to, n) != 0 ? n : 0); -} static inline int __copy_to_user_inatomic(void __user *to, const void *from, unsigned n) { return (copyout_nofault(from, to, n) != 0 ? n : 0); } static inline unsigned long -__copy_from_user(void *to, const void __user *from, unsigned long n) -{ - return ((copyin(__DECONST(void *, from), to, n) != 0 ? n : 0)); -} -#define copy_from_user(to, from, n) __copy_from_user((to), (from), (n)) -static inline unsigned long __copy_from_user_inatomic_nocache(void *to, const void __user *from, unsigned long n) { @@ -1017,7 +1025,7 @@ fault_in_multipages_readable(const char __user *uaddr, int size) return ret; while (uaddr <= end) { - ret = copyin(uaddr, &c, 1); + ret = -copyin(uaddr, &c, 1); if (ret != 0) return -EFAULT; uaddr += PAGE_SIZE; @@ -1026,10 +1034,10 @@ fault_in_multipages_readable(const char __user *uaddr, int size) /* Check whether the range spilled into the next page. */ if (((unsigned long)uaddr & ~PAGE_MASK) == ((unsigned long)end & ~PAGE_MASK)) { - ret = copyin(end, &c, 1); + ret = -copyin(end, &c, 1); } - return -ret; + return ret; } static inline int @@ -1868,14 +1876,13 @@ i915_gem_mmap_ioctl(struct drm_device *dev, void *data, PROC_LOCK(p); if (map->size + size > lim_cur(p, RLIMIT_VMEM)) { PROC_UNLOCK(p); - error = ENOMEM; + error = -ENOMEM; goto out; } PROC_UNLOCK(p); addr = 0; vm_object_reference(obj->vm_obj); - DRM_UNLOCK(dev); rv = vm_map_find(map, obj->vm_obj, args->offset, &addr, args->size, 0, VMFS_OPTIMAL_SPACE, VM_PROT_READ | VM_PROT_WRITE, VM_PROT_READ | VM_PROT_WRITE, MAP_INHERIT_SHARE); @@ -1885,7 +1892,6 @@ i915_gem_mmap_ioctl(struct drm_device *dev, void *data, } else { args->addr_ptr = (uint64_t)addr; } - DRM_LOCK(dev); out: drm_gem_object_unreference(obj); return (error); @@ -2631,11 +2637,11 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj, if (free_space != NULL) { if (map_and_fenceable) obj->gtt_space = drm_mm_get_block_range_generic( - free_space, size, alignment, 0, + free_space, size, alignment, 0, 0, dev_priv->mm.gtt_mappable_end, 1); else obj->gtt_space = drm_mm_get_block_generic(free_space, - size, alignment, 1); + size, alignment, 0, 1); } if (obj->gtt_space == NULL) { ret = i915_gem_evict_something(dev, size, alignment, @@ -2771,14 +2777,14 @@ i915_gem_object_unbind(struct drm_i915_gem_object *obj) } ret = i915_gem_object_finish_gpu(obj); - if (ret == -ERESTART || ret == -EINTR) + if (ret == -ERESTARTSYS || ret == -EINTR) return (ret); i915_gem_object_finish_gtt(obj); if (ret == 0) ret = i915_gem_object_set_to_cpu_domain(obj, 1); - if (ret == -ERESTART || ret == -EINTR) + if (ret == -ERESTARTSYS || ret == -EINTR) return (ret); if (ret != 0) { i915_gem_clflush_object(obj); @@ -3326,8 +3332,11 @@ static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno, flags = interruptible ? PCATCH : 0; while (!i915_seqno_passed(ring->get_seqno(ring), seqno) && !atomic_load_acq_int(&dev_priv->mm.wedged) && - ret == 0) + ret == 0) { ret = -msleep(ring, &dev_priv->irq_lock, flags, "915gwr", 0); + if (ret == -ERESTART) + ret = -ERESTARTSYS; + } ring->irq_put(ring); mtx_unlock(&dev_priv->irq_lock); @@ -3584,7 +3593,7 @@ i915_gem_retire_requests_ring(struct intel_ring_buffer *ring) seqno = ring->get_seqno(ring); CTR2(KTR_DRM, "retire_request_ring %s %d", ring->name, seqno); - for (i = 0; i < DRM_ARRAY_SIZE(ring->sync_seqno); i++) + for (i = 0; i < ARRAY_SIZE(ring->sync_seqno); i++) if (seqno >= ring->sync_seqno[i]) ring->sync_seqno[i] = 0; @@ -4047,7 +4056,7 @@ i915_gem_init_phys_object(struct drm_device *dev, int id, int size, int align) phys_obj->id = id; - phys_obj->handle = drm_pci_alloc(dev, size, align, ~0); + phys_obj->handle = drm_pci_alloc(dev, size, align, BUS_SPACE_MAXADDR); if (phys_obj->handle == NULL) { ret = -ENOMEM; goto free_obj; @@ -4196,7 +4205,7 @@ i915_gem_attach_phys_object(struct drm_device *dev, } VM_OBJECT_WUNLOCK(obj->base.vm_obj); - return (0); + return (ret); } static int diff --git a/sys/dev/drm2/i915/i915_gem_context.c b/sys/dev/drm2/i915/i915_gem_context.c index dc4204320b67..39d09b00c61c 100644 --- a/sys/dev/drm2/i915/i915_gem_context.c +++ b/sys/dev/drm2/i915/i915_gem_context.c @@ -317,10 +317,10 @@ void i915_gem_context_close(struct drm_device *dev, struct drm_file *file) { struct drm_i915_file_private *file_priv = file->driver_priv; - //DRM_LOCK(dev); /* Called from preclose(), the lock is already owned. */ + DRM_LOCK(dev); drm_gem_names_foreach(&file_priv->context_idr, context_idr_cleanup, NULL); drm_gem_names_fini(&file_priv->context_idr); - //DRM_UNLOCK(dev); + DRM_UNLOCK(dev); } static struct i915_hw_context * diff --git a/sys/dev/drm2/i915/i915_gem_evict.c b/sys/dev/drm2/i915/i915_gem_evict.c index cadd9ff1a26d..e800b8f1c664 100644 --- a/sys/dev/drm2/i915/i915_gem_evict.c +++ b/sys/dev/drm2/i915/i915_gem_evict.c @@ -82,10 +82,10 @@ i915_gem_evict_something(struct drm_device *dev, int min_size, INIT_LIST_HEAD(&unwind_list); if (mappable) drm_mm_init_scan_with_range(&dev_priv->mm.gtt_space, min_size, - alignment, 0, + alignment, 0, 0, dev_priv->mm.gtt_mappable_end); else - drm_mm_init_scan(&dev_priv->mm.gtt_space, min_size, alignment); + drm_mm_init_scan(&dev_priv->mm.gtt_space, min_size, alignment, 0); /* First see if there is a large enough contiguous idle region... */ list_for_each_entry(obj, &dev_priv->mm.inactive_list, mm_list) { diff --git a/sys/dev/drm2/i915/i915_gem_execbuffer.c b/sys/dev/drm2/i915/i915_gem_execbuffer.c index b84dab55fdc4..5f0614c9a8b5 100644 --- a/sys/dev/drm2/i915/i915_gem_execbuffer.c +++ b/sys/dev/drm2/i915/i915_gem_execbuffer.c @@ -1240,14 +1240,16 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, goto pre_struct_lock_err; if (dev_priv->mm.suspended) { + DRM_UNLOCK(dev); ret = -EBUSY; - goto struct_lock_err; + goto pre_struct_lock_err; } eb = eb_create(args->buffer_count); if (eb == NULL) { + DRM_UNLOCK(dev); ret = -ENOMEM; - goto struct_lock_err; + goto pre_struct_lock_err; } /* Look up object handles */ @@ -1394,7 +1396,6 @@ err: list_del_init(&obj->exec_list); drm_gem_object_unreference(&obj->base); } -struct_lock_err: DRM_UNLOCK(dev); pre_struct_lock_err: diff --git a/sys/dev/drm2/i915/i915_gem_gtt.c b/sys/dev/drm2/i915/i915_gem_gtt.c index ce6c53b494a3..89c8060fd3cb 100644 --- a/sys/dev/drm2/i915/i915_gem_gtt.c +++ b/sys/dev/drm2/i915/i915_gem_gtt.c @@ -355,7 +355,7 @@ i915_gem_init_global_gtt(struct drm_device *dev, unsigned long start, /* ... but ensure that we clear the entire range. */ intel_gtt_clear_range(start / PAGE_SIZE, (end-start) / PAGE_SIZE); - device_printf(dev->device, + device_printf(dev->dev, "taking over the fictitious range 0x%lx-0x%lx\n", dev->agp->base + start, dev->agp->base + start + mappable); error = -vm_phys_fictitious_reg_range(dev->agp->base + start, diff --git a/sys/dev/drm2/i915/i915_gem_tiling.c b/sys/dev/drm2/i915/i915_gem_tiling.c index 6ca39627f054..edc0e3c49c2c 100644 --- a/sys/dev/drm2/i915/i915_gem_tiling.c +++ b/sys/dev/drm2/i915/i915_gem_tiling.c @@ -352,6 +352,7 @@ i915_gem_set_tiling(struct drm_device *dev, void *data, } } + DRM_LOCK(dev); if (args->tiling_mode != obj->tiling_mode || args->stride != obj->stride) { /* We need to rebind the object if its current allocation @@ -399,6 +400,7 @@ i915_gem_set_tiling(struct drm_device *dev, void *data, args->stride = obj->stride; args->tiling_mode = obj->tiling_mode; drm_gem_object_unreference(&obj->base); + DRM_UNLOCK(dev); return (ret); } @@ -418,6 +420,8 @@ i915_gem_get_tiling(struct drm_device *dev, void *data, if (&obj->base == NULL) return -ENOENT; + DRM_LOCK(dev); + args->tiling_mode = obj->tiling_mode; switch (obj->tiling_mode) { case I915_TILING_X: @@ -440,6 +444,7 @@ i915_gem_get_tiling(struct drm_device *dev, void *data, args->swizzle_mode = I915_BIT_6_SWIZZLE_9_10; drm_gem_object_unreference(&obj->base); + DRM_UNLOCK(dev); return 0; } diff --git a/sys/dev/drm2/i915/i915_ioc32.c b/sys/dev/drm2/i915/i915_ioc32.c index 26040e858e11..d9a5184c2ac2 100644 --- a/sys/dev/drm2/i915/i915_ioc32.c +++ b/sys/dev/drm2/i915/i915_ioc32.c @@ -127,12 +127,12 @@ typedef struct drm_i915_mem_alloc32 { u32 region_offset; /* offset from start of fb or agp */ } drm_i915_mem_alloc32_t; -drm_ioctl_desc_t i915_compat_ioctls[] = { +struct drm_ioctl_desc i915_compat_ioctls[] = { DRM_IOCTL_DEF(DRM_I915_BATCHBUFFER, compat_i915_batchbuffer, DRM_AUTH), DRM_IOCTL_DEF(DRM_I915_CMDBUFFER, compat_i915_cmdbuffer, DRM_AUTH), DRM_IOCTL_DEF(DRM_I915_GETPARAM, compat_i915_getparam, DRM_AUTH), DRM_IOCTL_DEF(DRM_I915_IRQ_EMIT, compat_i915_irq_emit, DRM_AUTH) }; -int i915_compat_ioctls_nr = DRM_ARRAY_SIZE(i915_compat_ioctls); +int i915_compat_ioctls_nr = ARRAY_SIZE(i915_compat_ioctls); #endif diff --git a/sys/dev/drm2/i915/i915_irq.c b/sys/dev/drm2/i915/i915_irq.c index 346d9c07467c..ac89032994dc 100644 --- a/sys/dev/drm2/i915/i915_irq.c +++ b/sys/dev/drm2/i915/i915_irq.c @@ -1458,11 +1458,11 @@ static int valleyview_irq_postinstall(struct drm_device *dev) dev_priv->pipestat[1] = 0; /* Hack for broken MSIs on VLV */ - pci_write_config(dev->device, 0x94, 0xfee00000, 4); - msid = pci_read_config(dev->device, 0x98, 2); + pci_write_config(dev->dev, 0x94, 0xfee00000, 4); + msid = pci_read_config(dev->dev, 0x98, 2); msid &= 0xff; /* mask out delivery bits */ msid |= (1<<14); - pci_write_config(dev->device, 0x98, msid, 2); + pci_write_config(dev->dev, 0x98, msid, 2); I915_WRITE(VLV_IMR, dev_priv->irq_mask); I915_WRITE(VLV_IER, enable_mask); @@ -2329,7 +2329,7 @@ i915_error_state_free(struct drm_i915_error_state *error) { int i; - for (i = 0; i < DRM_ARRAY_SIZE(error->ring); i++) { + for (i = 0; i < ARRAY_SIZE(error->ring); i++) { i915_error_object_free(error->ring[i].batchbuffer); i915_error_object_free(error->ring[i].ringbuffer); free(error->ring[i].requests, DRM_I915_GEM); diff --git a/sys/dev/drm2/i915/i915_suspend.c b/sys/dev/drm2/i915/i915_suspend.c index fd31120233e9..384a1d1ba951 100644 --- a/sys/dev/drm2/i915/i915_suspend.c +++ b/sys/dev/drm2/i915/i915_suspend.c @@ -460,19 +460,19 @@ static void i915_restore_modeset_reg(struct drm_device *dev) I915_WRITE(dpll_a_reg, dev_priv->saveDPLL_A & ~DPLL_VCO_ENABLE); POSTING_READ(dpll_a_reg); - DRM_UDELAY(150); + udelay(150); } I915_WRITE(fpa0_reg, dev_priv->saveFPA0); I915_WRITE(fpa1_reg, dev_priv->saveFPA1); /* Actually enable it */ I915_WRITE(dpll_a_reg, dev_priv->saveDPLL_A); POSTING_READ(dpll_a_reg); - DRM_UDELAY(150); + udelay(150); if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) { I915_WRITE(_DPLL_A_MD, dev_priv->saveDPLL_A_MD); POSTING_READ(_DPLL_A_MD); } - DRM_UDELAY(150); + udelay(150); /* Restore mode */ I915_WRITE(_HTOTAL_A, dev_priv->saveHTOTAL_A); @@ -529,19 +529,19 @@ static void i915_restore_modeset_reg(struct drm_device *dev) I915_WRITE(dpll_b_reg, dev_priv->saveDPLL_B & ~DPLL_VCO_ENABLE); POSTING_READ(dpll_b_reg); - DRM_UDELAY(150); + udelay(150); } I915_WRITE(fpb0_reg, dev_priv->saveFPB0); I915_WRITE(fpb1_reg, dev_priv->saveFPB1); /* Actually enable it */ I915_WRITE(dpll_b_reg, dev_priv->saveDPLL_B); POSTING_READ(dpll_b_reg); - DRM_UDELAY(150); + udelay(150); if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) { I915_WRITE(_DPLL_B_MD, dev_priv->saveDPLL_B_MD); POSTING_READ(_DPLL_B_MD); } - DRM_UDELAY(150); + udelay(150); /* Restore mode */ I915_WRITE(_HTOTAL_B, dev_priv->saveHTOTAL_B); @@ -792,7 +792,7 @@ static void i915_restore_display(struct drm_device *dev) I915_WRITE(VGA1, dev_priv->saveVGA1); I915_WRITE(VGA_PD, dev_priv->saveVGA_PD); POSTING_READ(VGA_PD); - DRM_UDELAY(150); + udelay(150); i915_restore_vga(dev); } @@ -802,11 +802,13 @@ int i915_save_state(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; int i; - dev_priv->saveLBB = pci_read_config(dev->device, LBB, 1); + dev_priv->saveLBB = pci_read_config(dev->dev, LBB, 1); /* Hardware status page */ dev_priv->saveHWS = I915_READ(HWS_PGA); + DRM_LOCK(dev); + i915_save_display(dev); /* Interrupt state */ @@ -844,6 +846,8 @@ int i915_save_state(struct drm_device *dev) for (i = 0; i < 3; i++) dev_priv->saveSWF2[i] = I915_READ(SWF30 + (i << 2)); + DRM_UNLOCK(dev); + return 0; } @@ -852,8 +856,9 @@ int i915_restore_state(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; int i; - pci_write_config(dev->device, LBB, dev_priv->saveLBB, 1); + pci_write_config(dev->dev, LBB, dev_priv->saveLBB, 1); + DRM_LOCK(dev); /* Hardware status page */ I915_WRITE(HWS_PGA, dev_priv->saveHWS); @@ -887,6 +892,8 @@ int i915_restore_state(struct drm_device *dev) for (i = 0; i < 3; i++) I915_WRITE(SWF30 + (i << 2), dev_priv->saveSWF2[i]); + DRM_UNLOCK(dev); + intel_iic_reset(dev); return 0; diff --git a/sys/dev/drm2/i915/intel_crt.c b/sys/dev/drm2/i915/intel_crt.c index c1b39eb096b5..5f52bfdc8367 100644 --- a/sys/dev/drm2/i915/intel_crt.c +++ b/sys/dev/drm2/i915/intel_crt.c @@ -129,7 +129,7 @@ static int intel_crt_mode_valid(struct drm_connector *connector, } static bool intel_crt_mode_fixup(struct drm_encoder *encoder, - struct drm_display_mode *mode, + const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { return true; @@ -310,7 +310,6 @@ static bool intel_crt_detect_ddc(struct drm_connector *connector) */ if (edid != NULL) { is_digital = edid->input & DRM_EDID_INPUT_DIGITAL; - connector->display_info.raw_edid = NULL; free(edid, DRM_MEM_KMS); } diff --git a/sys/dev/drm2/i915/intel_display.c b/sys/dev/drm2/i915/intel_display.c index a844c7f55f49..aafd4facf781 100644 --- a/sys/dev/drm2/i915/intel_display.c +++ b/sys/dev/drm2/i915/intel_display.c @@ -2051,9 +2051,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, { struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; -#if 0 struct drm_i915_master_private *master_priv; -#endif struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int ret; @@ -2099,7 +2097,6 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, intel_update_fbc(dev); DRM_UNLOCK(dev); -#if 0 if (!dev->primary->master) return 0; @@ -2114,19 +2111,6 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, master_priv->sarea_priv->pipeA_x = x; master_priv->sarea_priv->pipeA_y = y; } -#else - - if (!dev_priv->sarea_priv) - return 0; - - if (intel_crtc->pipe) { - dev_priv->sarea_priv->planeB_x = x; - dev_priv->sarea_priv->planeB_y = y; - } else { - dev_priv->sarea_priv->planeA_x = x; - dev_priv->sarea_priv->planeA_y = y; - } -#endif return 0; } @@ -3329,9 +3313,7 @@ static void intel_crtc_dpms(struct drm_crtc *crtc, int mode) { struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; -#if 0 struct drm_i915_master_private *master_priv; -#endif struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int pipe = intel_crtc->pipe; bool enabled; @@ -3343,38 +3325,23 @@ static void intel_crtc_dpms(struct drm_crtc *crtc, int mode) dev_priv->display.dpms(crtc, mode); -#if 0 if (!dev->primary->master) return; master_priv = dev->primary->master->driver_priv; if (!master_priv->sarea_priv) return; -#else - if (!dev_priv->sarea_priv) - return; -#endif enabled = crtc->enabled && mode != DRM_MODE_DPMS_OFF; switch (pipe) { case 0: -#if 0 master_priv->sarea_priv->pipeA_w = enabled ? crtc->mode.hdisplay : 0; master_priv->sarea_priv->pipeA_h = enabled ? crtc->mode.vdisplay : 0; -#else - dev_priv->sarea_priv->planeA_w = enabled ? crtc->mode.hdisplay : 0; - dev_priv->sarea_priv->planeA_h = enabled ? crtc->mode.vdisplay : 0; -#endif break; case 1: -#if 0 master_priv->sarea_priv->pipeB_w = enabled ? crtc->mode.hdisplay : 0; master_priv->sarea_priv->pipeB_h = enabled ? crtc->mode.vdisplay : 0; -#else - dev_priv->sarea_priv->planeB_w = enabled ? crtc->mode.hdisplay : 0; - dev_priv->sarea_priv->planeB_h = enabled ? crtc->mode.vdisplay : 0; -#endif break; default: DRM_ERROR("Can't update pipe %c in SAREA\n", pipe_name(pipe)); @@ -3502,7 +3469,7 @@ static int i915gm_get_display_clock_speed(struct drm_device *dev) { u16 gcfgc = 0; - gcfgc = pci_read_config(dev->device, GCFGC, 2); + gcfgc = pci_read_config(dev->dev, GCFGC, 2); if (gcfgc & GC_LOW_FREQUENCY_ENABLE) return 133000; @@ -6946,8 +6913,8 @@ static void intel_init_quirks(struct drm_device *dev) device_t d; int i; - d = dev->device; - for (i = 0; i < DRM_ARRAY_SIZE(intel_quirks); i++) { + d = dev->dev; + for (i = 0; i < ARRAY_SIZE(intel_quirks); i++) { q = &intel_quirks[i]; if (pci_get_device(d) == q->device && (pci_get_subvendor(d) == q->subsystem_vendor || @@ -7116,10 +7083,11 @@ void intel_modeset_cleanup(struct drm_device *dev) if (IS_VALLEYVIEW(dev)) vlv_init_dpio(dev); + DRM_UNLOCK(dev); + /* Disable the irq before mode object teardown, for the irq might * enqueue unpin/hotplug work. */ drm_irq_uninstall(dev); - DRM_UNLOCK(dev); if (taskqueue_cancel(dev_priv->tq, &dev_priv->hotplug_task, NULL)) taskqueue_drain(dev_priv->tq, &dev_priv->hotplug_task); diff --git a/sys/dev/drm2/i915/intel_dp.c b/sys/dev/drm2/i915/intel_dp.c index e9674b0d8f24..5791caf319c5 100644 --- a/sys/dev/drm2/i915/intel_dp.c +++ b/sys/dev/drm2/i915/intel_dp.c @@ -665,7 +665,7 @@ intel_dp_i2c_init(struct intel_dp *intel_dp, DRM_DEBUG_KMS("i2c_init %s\n", name); ironlake_edp_panel_vdd_on(intel_dp); - ret = iic_dp_aux_add_bus(intel_connector->base.dev->device, name, + ret = iic_dp_aux_add_bus(intel_connector->base.dev->dev, name, intel_dp_i2c_aux_ch, intel_dp, &intel_dp->dp_iic_bus, &intel_dp->adapter); ironlake_edp_panel_vdd_off(intel_dp, false); @@ -673,7 +673,7 @@ intel_dp_i2c_init(struct intel_dp *intel_dp, } static bool -intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode, +intel_dp_mode_fixup(struct drm_encoder *encoder, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { struct drm_device *dev = encoder->dev; @@ -688,11 +688,6 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode, intel_fixed_panel_mode(intel_dp->panel_fixed_mode, adjusted_mode); intel_pch_panel_fitting(dev, DRM_MODE_SCALE_FULLSCREEN, mode, adjusted_mode); - /* - * the mode->clock is used to calculate the Data&Link M/N - * of the pipe. For the eDP the fixed clock should be used. - */ - mode->clock = intel_dp->panel_fixed_mode->clock; } DRM_DEBUG_KMS("DP link computation with max lane count %i " @@ -703,7 +698,7 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode, return false; bpp = adjusted_mode->private_flags & INTEL_MODE_DP_FORCE_6BPC ? 18 : 24; - mode_rate = intel_dp_link_required(mode->clock, bpp); + mode_rate = intel_dp_link_required(adjusted_mode->clock, bpp); for (lane_count = 1; lane_count <= max_lane_count; lane_count <<= 1) { for (clock = 0; clock <= max_clock; clock++) { @@ -2151,7 +2146,6 @@ intel_dp_detect(struct drm_connector *connector, bool force) edid = intel_dp_get_edid(connector, intel_dp->adapter); if (edid) { intel_dp->has_audio = drm_detect_monitor_audio(edid); - connector->display_info.raw_edid = NULL; free(edid, DRM_MEM_KMS); } } @@ -2217,7 +2211,6 @@ intel_dp_detect_audio(struct drm_connector *connector) if (edid) { has_audio = drm_detect_monitor_audio(edid); - connector->display_info.raw_edid = NULL; free(edid, DRM_MEM_KMS); } @@ -2233,7 +2226,7 @@ intel_dp_set_property(struct drm_connector *connector, struct intel_dp *intel_dp = intel_attached_dp(connector); int ret; - ret = drm_connector_property_set_value(connector, property, val); + ret = drm_object_property_set_value(&connector->base, property, val); if (ret) return ret; @@ -2307,7 +2300,7 @@ static void intel_dp_encoder_destroy(struct drm_encoder *encoder) device_delete_child(intel_dp->dp_iic_bus, intel_dp->adapter); } - device_delete_child(dev->device, intel_dp->dp_iic_bus); + device_delete_child(dev->dev, intel_dp->dp_iic_bus); } drm_encoder_cleanup(encoder); if (is_edp(intel_dp)) { diff --git a/sys/dev/drm2/i915/intel_fb.c b/sys/dev/drm2/i915/intel_fb.c index 124b7693e1b6..130d87a60afb 100644 --- a/sys/dev/drm2/i915/intel_fb.c +++ b/sys/dev/drm2/i915/intel_fb.c @@ -79,20 +79,17 @@ static int intelfb_create(struct intel_fbdev *ifbdev, goto out_unref; } -#if 0 - info = framebuffer_alloc(0, device); + info = framebuffer_alloc(); if (!info) { ret = -ENOMEM; goto out_unpin; } +#if 0 info->par = ifbdev; #else - info = malloc(sizeof(struct fb_info), DRM_MEM_KMS, M_WAITOK | M_ZERO); info->fb_size = size; info->fb_bpp = sizes->surface_bpp; - info->fb_width = sizes->fb_width; - info->fb_height = sizes->fb_height; info->fb_pbase = dev->agp->base + obj->gtt_offset; info->fb_vbase = (vm_offset_t)pmap_mapdev_attr(info->fb_pbase, size, PAT_WRITE_COMBINING); @@ -140,12 +137,12 @@ static int intelfb_create(struct intel_fbdev *ifbdev, info->screen_size = size; // memset(info->screen_base, 0, size); +#endif drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth); drm_fb_helper_fill_var(info, &ifbdev->helper, sizes->fb_width, sizes->fb_height); /* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */ -#endif DRM_DEBUG_KMS("allocated %dx%d (s %dbits) fb: 0x%08x, bo %p\n", fb->width, fb->height, fb->depth, obj->gtt_offset, obj); @@ -192,21 +189,19 @@ static struct drm_fb_helper_funcs intel_fb_helper_funcs = { static void intel_fbdev_destroy(struct drm_device *dev, struct intel_fbdev *ifbdev) { -#if 0 struct fb_info *info; -#endif struct intel_framebuffer *ifb = &ifbdev->ifb; -#if 0 if (ifbdev->helper.fbdev) { info = ifbdev->helper.fbdev; +#if 0 unregister_framebuffer(info); iounmap(info->screen_base); if (info->cmap.len) fb_dealloc_cmap(&info->cmap); +#endif framebuffer_release(info); } -#endif drm_fb_helper_fini(&ifbdev->helper); diff --git a/sys/dev/drm2/i915/intel_hdmi.c b/sys/dev/drm2/i915/intel_hdmi.c index 3f0572f260c7..c009b03e01b3 100644 --- a/sys/dev/drm2/i915/intel_hdmi.c +++ b/sys/dev/drm2/i915/intel_hdmi.c @@ -446,7 +446,7 @@ static int intel_hdmi_mode_valid(struct drm_connector *connector, } static bool intel_hdmi_mode_fixup(struct drm_encoder *encoder, - struct drm_display_mode *mode, + const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { return true; @@ -473,7 +473,6 @@ intel_hdmi_detect(struct drm_connector *connector, bool force) drm_detect_hdmi_monitor(edid); intel_hdmi->has_audio = drm_detect_monitor_audio(edid); } - connector->display_info.raw_edid = NULL; free(edid, DRM_MEM_KMS); } else { DRM_DEBUG_KMS("[CONNECTOR:%d:%s] got no edid, ddc port %d\n", @@ -519,7 +518,6 @@ intel_hdmi_detect_audio(struct drm_connector *connector) if (edid->input & DRM_EDID_INPUT_DIGITAL) has_audio = drm_detect_monitor_audio(edid); - connector->display_info.raw_edid = NULL; free(edid, DRM_MEM_KMS); } @@ -535,7 +533,7 @@ intel_hdmi_set_property(struct drm_connector *connector, struct drm_i915_private *dev_priv = connector->dev->dev_private; int ret; - ret = drm_connector_property_set_value(connector, property, val); + ret = drm_object_property_set_value(&connector->base, property, val); if (ret) return ret; diff --git a/sys/dev/drm2/i915/intel_iic.c b/sys/dev/drm2/i915/intel_iic.c index aa12a784f030..36a5b9e5661b 100644 --- a/sys/dev/drm2/i915/intel_iic.c +++ b/sys/dev/drm2/i915/intel_iic.c @@ -258,9 +258,9 @@ gmbus_xfer_read(struct drm_i915_private *dev_priv, struct iic_msg *msg, (GMBUS_SATOER | GMBUS_HW_RDY)), 50, 1, "915gbr"); if (ret) - return (ETIMEDOUT); + return (-ETIMEDOUT); if (gmbus2 & GMBUS_SATOER) - return (ENXIO); + return (-ENXIO); val = I915_READ(GMBUS3 + reg_offset); do { @@ -308,9 +308,9 @@ gmbus_xfer_write(struct drm_i915_private *dev_priv, struct iic_msg *msg) (GMBUS_SATOER | GMBUS_HW_RDY)), 50, 1, "915gbw"); if (ret) - return (ETIMEDOUT); + return (-ETIMEDOUT); if (gmbus2 & GMBUS_SATOER) - return (ENXIO); + return (-ENXIO); } return 0; } @@ -369,7 +369,7 @@ intel_gmbus_transfer(device_t idev, struct iic_msg *msgs, uint32_t nmsgs) sx_xlock(&dev_priv->gmbus_sx); if (sc->force_bit_dev) { - error = IICBUS_TRANSFER(dev_priv->bbbus[unit], msgs, nmsgs); + error = -IICBUS_TRANSFER(dev_priv->bbbus[unit], msgs, nmsgs); goto out; } @@ -389,9 +389,9 @@ intel_gmbus_transfer(device_t idev, struct iic_msg *msgs, uint32_t nmsgs) error = gmbus_xfer_write(dev_priv, &msgs[i]); } - if (error == ETIMEDOUT) + if (error == -ETIMEDOUT) goto timeout; - if (error == ENXIO) + if (error == -ENXIO) goto clear_err; ret = _intel_wait_for(sc->drm_dev, @@ -419,7 +419,7 @@ intel_gmbus_transfer(device_t idev, struct iic_msg *msgs, uint32_t nmsgs) 10, 1, "915gbu")) { DRM_DEBUG_KMS("GMBUS [%s] timed out waiting for idle\n", sc->name); - error = ETIMEDOUT; + error = -ETIMEDOUT; } I915_WRITE(GMBUS0 + reg_offset, 0); goto out; @@ -454,7 +454,7 @@ clear_err: * So, we always return -ENXIO in all NAK cases, to ensure we send * it at least during the one case that is specified. */ - error = ENXIO; + error = -ENXIO; goto out; timeout: @@ -467,12 +467,12 @@ timeout: * Try GPIO bitbanging instead. */ sc->force_bit_dev = true; - error = IICBUS_TRANSFER(idev, msgs, nmsgs); + error = -IICBUS_TRANSFER(idev, msgs, nmsgs); goto out; out: sx_xunlock(&dev_priv->gmbus_sx); - return (error); + return (-error); } device_t @@ -730,15 +730,15 @@ intel_setup_gmbus(struct drm_device *dev) * gmbus may decide to force quirk transfer in the * attachment code. */ - dev_priv->bbbus_bridge[i] = device_add_child(dev->device, + dev_priv->bbbus_bridge[i] = device_add_child(dev->dev, "intel_iicbb", i); if (dev_priv->bbbus_bridge[i] == NULL) { DRM_ERROR("bbbus bridge %d creation failed\n", i); - ret = ENXIO; + ret = -ENXIO; goto err; } device_quiet(dev_priv->bbbus_bridge[i]); - ret = device_probe_and_attach(dev_priv->bbbus_bridge[i]); + ret = -device_probe_and_attach(dev_priv->bbbus_bridge[i]); if (ret != 0) { DRM_ERROR("bbbus bridge %d attach failed, %d\n", i, ret); @@ -760,19 +760,19 @@ intel_setup_gmbus(struct drm_device *dev) dev_priv->bbbus[i] = iic_dev; - dev_priv->gmbus_bridge[i] = device_add_child(dev->device, + dev_priv->gmbus_bridge[i] = device_add_child(dev->dev, "intel_gmbus", i); if (dev_priv->gmbus_bridge[i] == NULL) { DRM_ERROR("gmbus bridge %d creation failed\n", i); - ret = ENXIO; + ret = -ENXIO; goto err; } device_quiet(dev_priv->gmbus_bridge[i]); - ret = device_probe_and_attach(dev_priv->gmbus_bridge[i]); + ret = -device_probe_and_attach(dev_priv->gmbus_bridge[i]); if (ret != 0) { DRM_ERROR("gmbus bridge %d attach failed, %d\n", i, ret); - ret = ENXIO; + ret = -ENXIO; goto err; } diff --git a/sys/dev/drm2/i915/intel_lvds.c b/sys/dev/drm2/i915/intel_lvds.c index 5f749cedcd97..9e6c6670a6f2 100644 --- a/sys/dev/drm2/i915/intel_lvds.c +++ b/sys/dev/drm2/i915/intel_lvds.c @@ -230,7 +230,7 @@ static inline u32 panel_fitter_scaling(u32 source, u32 target) } static bool intel_lvds_mode_fixup(struct drm_encoder *encoder, - struct drm_display_mode *mode, + const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { struct drm_device *dev = encoder->dev; @@ -978,7 +978,7 @@ bool intel_lvds_init(struct drm_device *dev) * the initial panel fitting mode will be FULL_SCREEN. */ - drm_connector_attach_property(&intel_connector->base, + drm_object_attach_property(&connector->base, dev->mode_config.scaling_mode_property, DRM_MODE_SCALE_ASPECT); intel_lvds->fitting_mode = DRM_MODE_SCALE_ASPECT; diff --git a/sys/dev/drm2/i915/intel_modes.c b/sys/dev/drm2/i915/intel_modes.c index 6b83bae76ea2..d061d0833a3d 100644 --- a/sys/dev/drm2/i915/intel_modes.c +++ b/sys/dev/drm2/i915/intel_modes.c @@ -80,7 +80,6 @@ intel_ddc_get_modes(struct drm_connector *connector, device_t adapter) drm_mode_connector_update_edid_property(connector, edid); ret = drm_add_edid_modes(connector, edid); drm_edid_to_eld(connector, edid); - connector->display_info.raw_edid = NULL; free(edid, DRM_MEM_KMS); } @@ -106,13 +105,13 @@ intel_attach_force_audio_property(struct drm_connector *connector) prop = drm_property_create_enum(dev, 0, "audio", force_audio_names, - DRM_ARRAY_SIZE(force_audio_names)); + ARRAY_SIZE(force_audio_names)); if (prop == NULL) return; dev_priv->force_audio_property = prop; } - drm_connector_attach_property(connector, prop, 0); + drm_object_attach_property(&connector->base, prop, 0); } static const struct drm_prop_enum_list broadcast_rgb_names[] = { @@ -132,12 +131,12 @@ intel_attach_broadcast_rgb_property(struct drm_connector *connector) prop = drm_property_create_enum(dev, DRM_MODE_PROP_ENUM, "Broadcast RGB", broadcast_rgb_names, - DRM_ARRAY_SIZE(broadcast_rgb_names)); + ARRAY_SIZE(broadcast_rgb_names)); if (prop == NULL) return; dev_priv->broadcast_rgb_property = prop; } - drm_connector_attach_property(connector, prop, 0); + drm_object_attach_property(&connector->base, prop, 0); } diff --git a/sys/dev/drm2/i915/intel_opregion.c b/sys/dev/drm2/i915/intel_opregion.c index 7b02f71e196f..411e530da9ec 100644 --- a/sys/dev/drm2/i915/intel_opregion.c +++ b/sys/dev/drm2/i915/intel_opregion.c @@ -147,7 +147,7 @@ struct opregion_asle { #define ACPI_DIGITAL_OUTPUT (3<<8) #define ACPI_LVDS_OUTPUT (4<<8) -#if 1 +#if defined(CONFIG_ACPI) static u32 asle_set_backlight(struct drm_device *dev, u32 bclp) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -350,7 +350,7 @@ static void intel_didl_outputs(struct drm_device *dev) ACPI_STATUS status; int i = 0; - handle = acpi_get_handle(dev->device); + handle = acpi_get_handle(dev->dev); if (!handle) return; @@ -377,7 +377,7 @@ static void intel_didl_outputs(struct drm_device *dev) } if (!acpi_video_bus) { - device_printf(dev->device, "No ACPI video bus found\n"); + device_printf(dev->dev, "No ACPI video bus found\n"); return; } @@ -385,7 +385,7 @@ static void intel_didl_outputs(struct drm_device *dev) while (AcpiGetNextObject(ACPI_TYPE_DEVICE, acpi_video_bus, acpi_cdev, &acpi_cdev) != AE_NOT_FOUND) { if (i >= 8) { - device_printf(dev->device, "More than 8 outputs detected\n"); + device_printf(dev->dev, "More than 8 outputs detected\n"); return; } status = acpi_GetInteger(acpi_cdev, "_ADR", &device_id); @@ -426,7 +426,7 @@ blind_set: list_for_each_entry(connector, &dev->mode_config.connector_list, head) { int output_type = ACPI_OTHER_OUTPUT; if (i >= 8) { - device_printf(dev->device, + device_printf(dev->dev, "More than 8 outputs detected\n"); return; } @@ -569,7 +569,7 @@ int intel_opregion_setup(struct drm_device *dev) u32 asls, mboxes; int err = 0; - asls = pci_read_config(dev->device, PCI_ASLS, 4); + asls = pci_read_config(dev->dev, PCI_ASLS, 4); DRM_DEBUG("graphic opregion physical addr: 0x%x\n", asls); if (asls == 0) { DRM_DEBUG("ACPI OpRegion not supported!\n"); diff --git a/sys/dev/drm2/i915/intel_overlay.c b/sys/dev/drm2/i915/intel_overlay.c index 715da2fe0f1c..94b8d5d481a2 100644 --- a/sys/dev/drm2/i915/intel_overlay.c +++ b/sys/dev/drm2/i915/intel_overlay.c @@ -774,7 +774,6 @@ static int intel_overlay_do_put_image(struct intel_overlay *overlay, KASSERT(overlay != NULL, ("No overlay ?")); DRM_LOCK_ASSERT(overlay->dev); - DRM_MODE_CONFIG_ASSERT_LOCKED(overlay->dev); ret = intel_overlay_release_old_vid(overlay); if (ret != 0) @@ -877,7 +876,6 @@ int intel_overlay_switch_off(struct intel_overlay *overlay) int ret; DRM_LOCK_ASSERT(overlay->dev); - DRM_MODE_CONFIG_ASSERT_LOCKED(overlay->dev); ret = intel_overlay_recover_from_interrupt(overlay); if (ret != 0) @@ -1458,8 +1456,8 @@ void intel_setup_overlay(struct drm_device *dev) intel_overlay_unmap_regs(overlay, regs); dev_priv->overlay = overlay; - DRM_INFO("initialized overlay support\n"); DRM_UNLOCK(dev); + DRM_INFO("initialized overlay support\n"); return; out_unpin_bo: diff --git a/sys/dev/drm2/i915/intel_panel.c b/sys/dev/drm2/i915/intel_panel.c index ef60f4945fe6..2d4210d5cb09 100644 --- a/sys/dev/drm2/i915/intel_panel.c +++ b/sys/dev/drm2/i915/intel_panel.c @@ -226,7 +226,7 @@ u32 intel_panel_get_backlight(struct drm_device *dev) if (is_backlight_combination_mode(dev)) { u8 lbpc; - lbpc = pci_read_config(dev->device, PCI_LBPC, 1); + lbpc = pci_read_config(dev->dev, PCI_LBPC, 1); val *= lbpc; } } @@ -260,7 +260,7 @@ static void intel_panel_actually_set_backlight(struct drm_device *dev, u32 level lbpc = level * 0xfe / max + 1; level /= lbpc; - pci_write_config(dev->device, PCI_LBPC, lbpc, 4); + pci_write_config(dev->dev, PCI_LBPC, lbpc, 4); } tmp = I915_READ(BLC_PWM_CTL); diff --git a/sys/dev/drm2/i915/intel_ringbuffer.c b/sys/dev/drm2/i915/intel_ringbuffer.c index d37386555872..225122060dd6 100644 --- a/sys/dev/drm2/i915/intel_ringbuffer.c +++ b/sys/dev/drm2/i915/intel_ringbuffer.c @@ -1206,16 +1206,11 @@ int intel_wait_ring_buffer(struct intel_ring_buffer *ring, int n) return 0; } -#if 0 if (dev->primary->master) { struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; if (master_priv->sarea_priv) master_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT; } -#else - if (dev_priv->sarea_priv) - dev_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT; -#endif pause("915rng", 1); if (atomic_load_acq_32(&dev_priv->mm.wedged) != 0) { diff --git a/sys/dev/drm2/i915/intel_sdvo.c b/sys/dev/drm2/i915/intel_sdvo.c index 74e479a60f9d..91056d70ee88 100644 --- a/sys/dev/drm2/i915/intel_sdvo.c +++ b/sys/dev/drm2/i915/intel_sdvo.c @@ -416,20 +416,20 @@ static void intel_sdvo_debug_write(struct intel_sdvo *intel_sdvo, u8 cmd, { int i; - if ((drm_debug_flag & DRM_DEBUGBITS_KMS) == 0) + if ((drm_debug & DRM_DEBUGBITS_KMS) == 0) return; DRM_DEBUG_KMS("%s: W: %02X ", SDVO_NAME(intel_sdvo), cmd); for (i = 0; i < args_len; i++) printf("%02X ", ((const u8 *)args)[i]); for (; i < 8; i++) printf(" "); - for (i = 0; i < DRM_ARRAY_SIZE(sdvo_cmd_names); i++) { + for (i = 0; i < ARRAY_SIZE(sdvo_cmd_names); i++) { if (cmd == sdvo_cmd_names[i].cmd) { printf("(%s)", sdvo_cmd_names[i].name); break; } } - if (i == DRM_ARRAY_SIZE(sdvo_cmd_names)) + if (i == ARRAY_SIZE(sdvo_cmd_names)) printf("(%02X)", cmd); printf("\n"); } @@ -525,7 +525,7 @@ intel_sdvo_read_response(struct intel_sdvo *intel_sdvo, void *response, goto log_fail; } - if ((drm_debug_flag & DRM_DEBUGBITS_KMS) != 0) { + if ((drm_debug & DRM_DEBUGBITS_KMS) != 0) { if (status <= SDVO_CMD_STATUS_SCALING_NOT_SUPP) printf("(%s)", cmd_status_names[status]); else @@ -541,15 +541,15 @@ intel_sdvo_read_response(struct intel_sdvo *intel_sdvo, void *response, SDVO_I2C_RETURN_0 + i, &((u8 *)response)[i])) goto log_fail; - if ((drm_debug_flag & DRM_DEBUGBITS_KMS) != 0) + if ((drm_debug & DRM_DEBUGBITS_KMS) != 0) printf(" %02X", ((u8 *)response)[i]); } - if ((drm_debug_flag & DRM_DEBUGBITS_KMS) != 0) + if ((drm_debug & DRM_DEBUGBITS_KMS) != 0) printf("\n"); return (true); log_fail: - if ((drm_debug_flag & DRM_DEBUGBITS_KMS) != 0) + if ((drm_debug & DRM_DEBUGBITS_KMS) != 0) printf("... failed\n"); return (false); } @@ -972,7 +972,7 @@ intel_sdvo_set_input_timings_for_mode(struct intel_sdvo *intel_sdvo, } static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder, - struct drm_display_mode *mode, + const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { struct intel_sdvo *intel_sdvo = to_intel_sdvo(encoder); @@ -1332,7 +1332,6 @@ intel_sdvo_tmds_sink_detect(struct drm_connector *connector) } } else status = connector_status_disconnected; - connector->display_info.raw_edid = NULL; free(edid, DRM_MEM_KMS); } @@ -1406,7 +1405,6 @@ intel_sdvo_detect(struct drm_connector *connector, bool force) else ret = connector_status_disconnected; - connector->display_info.raw_edid = NULL; free(edid, DRM_MEM_KMS); } else ret = connector_status_connected; @@ -1452,7 +1450,6 @@ static void intel_sdvo_get_ddc_modes(struct drm_connector *connector) drm_add_edid_modes(connector, edid); } - connector->display_info.raw_edid = NULL; free(edid, DRM_MEM_KMS); } } @@ -1547,7 +1544,7 @@ static void intel_sdvo_get_tv_modes(struct drm_connector *connector) if (!intel_sdvo_read_response(intel_sdvo, &reply, 3)) return; - for (i = 0; i < DRM_ARRAY_SIZE(sdvo_tv_modes); i++) + for (i = 0; i < ARRAY_SIZE(sdvo_tv_modes); i++) if (reply & (1 << i)) { struct drm_display_mode *nmode; nmode = drm_mode_duplicate(connector->dev, @@ -1697,7 +1694,7 @@ intel_sdvo_set_property(struct drm_connector *connector, uint8_t cmd; int ret; - ret = drm_connector_property_set_value(connector, property, val); + ret = drm_object_property_set_value(&connector->base, property, val); if (ret) return ret; @@ -1752,7 +1749,7 @@ intel_sdvo_set_property(struct drm_connector *connector, } else if (IS_TV_OR_LVDS(intel_sdvo_connector)) { temp_value = val; if (intel_sdvo_connector->left == property) { - drm_connector_property_set_value(connector, + drm_object_property_set_value(&connector->base, intel_sdvo_connector->right, val); if (intel_sdvo_connector->left_margin == temp_value) return 0; @@ -1764,7 +1761,7 @@ intel_sdvo_set_property(struct drm_connector *connector, cmd = SDVO_CMD_SET_OVERSCAN_H; goto set_value; } else if (intel_sdvo_connector->right == property) { - drm_connector_property_set_value(connector, + drm_object_property_set_value(&connector->base, intel_sdvo_connector->left, val); if (intel_sdvo_connector->right_margin == temp_value) return 0; @@ -1776,7 +1773,7 @@ intel_sdvo_set_property(struct drm_connector *connector, cmd = SDVO_CMD_SET_OVERSCAN_H; goto set_value; } else if (intel_sdvo_connector->top == property) { - drm_connector_property_set_value(connector, + drm_object_property_set_value(&connector->base, intel_sdvo_connector->bottom, val); if (intel_sdvo_connector->top_margin == temp_value) return 0; @@ -1788,7 +1785,7 @@ intel_sdvo_set_property(struct drm_connector *connector, cmd = SDVO_CMD_SET_OVERSCAN_V; goto set_value; } else if (intel_sdvo_connector->bottom == property) { - drm_connector_property_set_value(connector, + drm_object_property_set_value(&connector->base, intel_sdvo_connector->top, val); if (intel_sdvo_connector->bottom_margin == temp_value) return 0; @@ -1863,7 +1860,7 @@ static void intel_sdvo_enc_destroy(struct drm_encoder *encoder) drm_mode_destroy(encoder->dev, intel_sdvo->sdvo_lvds_fixed_mode); - device_delete_child(intel_sdvo->base.base.dev->device, + device_delete_child(intel_sdvo->base.base.dev->dev, intel_sdvo->ddc_iic_bus); intel_encoder_destroy(encoder); } @@ -2294,7 +2291,7 @@ static bool intel_sdvo_tv_create_property(struct intel_sdvo *intel_sdvo, i, tv_format_names[intel_sdvo_connector->tv_format_supported[i]]); intel_sdvo->tv_format_index = intel_sdvo_connector->tv_format_supported[0]; - drm_connector_attach_property(&intel_sdvo_connector->base.base, + drm_object_attach_property(&intel_sdvo_connector->base.base.base, intel_sdvo_connector->tv_format, 0); return true; @@ -2310,7 +2307,7 @@ static bool intel_sdvo_tv_create_property(struct intel_sdvo *intel_sdvo, intel_sdvo_connector->name = \ drm_property_create_range(dev, 0, #name, 0, data_value[0]); \ if (!intel_sdvo_connector->name) return false; \ - drm_connector_attach_property(connector, \ + drm_object_attach_property(&connector->base, \ intel_sdvo_connector->name, \ intel_sdvo_connector->cur_##name); \ DRM_DEBUG_KMS(#name ": max %d, default %d, current %d\n", \ @@ -2347,7 +2344,7 @@ intel_sdvo_create_enhance_property_tv(struct intel_sdvo *intel_sdvo, if (!intel_sdvo_connector->left) return false; - drm_connector_attach_property(connector, + drm_object_attach_property(&connector->base, intel_sdvo_connector->left, intel_sdvo_connector->left_margin); @@ -2356,7 +2353,7 @@ intel_sdvo_create_enhance_property_tv(struct intel_sdvo *intel_sdvo, if (!intel_sdvo_connector->right) return false; - drm_connector_attach_property(connector, + drm_object_attach_property(&connector->base, intel_sdvo_connector->right, intel_sdvo_connector->right_margin); DRM_DEBUG_KMS("h_overscan: max %d, " @@ -2384,7 +2381,7 @@ intel_sdvo_create_enhance_property_tv(struct intel_sdvo *intel_sdvo, if (!intel_sdvo_connector->top) return false; - drm_connector_attach_property(connector, + drm_object_attach_property(&connector->base, intel_sdvo_connector->top, intel_sdvo_connector->top_margin); @@ -2394,7 +2391,7 @@ intel_sdvo_create_enhance_property_tv(struct intel_sdvo *intel_sdvo, if (!intel_sdvo_connector->bottom) return false; - drm_connector_attach_property(connector, + drm_object_attach_property(&connector->base, intel_sdvo_connector->bottom, intel_sdvo_connector->bottom_margin); DRM_DEBUG_KMS("v_overscan: max %d, " @@ -2426,7 +2423,7 @@ intel_sdvo_create_enhance_property_tv(struct intel_sdvo *intel_sdvo, if (!intel_sdvo_connector->dot_crawl) return false; - drm_connector_attach_property(connector, + drm_object_attach_property(&connector->base, intel_sdvo_connector->dot_crawl, intel_sdvo_connector->cur_dot_crawl); DRM_DEBUG_KMS("dot crawl: current %d\n", response); @@ -2553,7 +2550,7 @@ intel_sdvo_init_ddc_proxy(struct intel_sdvo *sdvo, struct drm_device *dev, struct intel_sdvo_ddc_proxy_sc *sc; int ret; - sdvo->ddc_iic_bus = device_add_child(dev->device, + sdvo->ddc_iic_bus = device_add_child(dev->dev, "intel_sdvo_ddc_proxy", sdvo_reg); if (sdvo->ddc_iic_bus == NULL) { DRM_ERROR("cannot create ddc proxy bus %d\n", sdvo_reg); @@ -2564,7 +2561,7 @@ intel_sdvo_init_ddc_proxy(struct intel_sdvo *sdvo, struct drm_device *dev, if (ret != 0) { DRM_ERROR("cannot attach proxy bus %d error %d\n", sdvo_reg, ret); - device_delete_child(dev->device, sdvo->ddc_iic_bus); + device_delete_child(dev->dev, sdvo->ddc_iic_bus); return (false); } sc = device_get_softc(sdvo->ddc_iic_bus); diff --git a/sys/dev/drm2/i915/intel_tv.c b/sys/dev/drm2/i915/intel_tv.c index ddc6c97ee12d..bc276d86230c 100644 --- a/sys/dev/drm2/i915/intel_tv.c +++ b/sys/dev/drm2/i915/intel_tv.c @@ -846,7 +846,7 @@ intel_tv_mode_valid(struct drm_connector *connector, static bool -intel_tv_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode, +intel_tv_mode_fixup(struct drm_encoder *encoder, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { struct drm_device *dev = encoder->dev; @@ -1233,7 +1233,7 @@ static void intel_tv_find_better_format(struct drm_connector *connector) } intel_tv->tv_format = tv_mode->name; - drm_connector_property_set_value(connector, + drm_object_property_set_value(&connector->base, connector->dev->mode_config.tv_mode_property, i); } @@ -1326,7 +1326,7 @@ intel_tv_get_modes(struct drm_connector *connector) int j, count = 0; u64 tmp; - for (j = 0; j < DRM_ARRAY_SIZE(input_res_table); + for (j = 0; j < ARRAY_SIZE(input_res_table); j++) { const struct input_res *input = &input_res_table[j]; unsigned int hactive_s = input->w; @@ -1393,7 +1393,7 @@ intel_tv_set_property(struct drm_connector *connector, struct drm_property *prop int ret = 0; bool changed = false; - ret = drm_connector_property_set_value(connector, property, val); + ret = drm_object_property_set_value(&connector->base, property, val); if (ret < 0) goto out; @@ -1414,7 +1414,7 @@ intel_tv_set_property(struct drm_connector *connector, struct drm_property *prop intel_tv->margin[TV_MARGIN_BOTTOM] = val; changed = true; } else if (property == dev->mode_config.tv_mode_property) { - if (val >= DRM_ARRAY_SIZE(tv_modes)) { + if (val >= ARRAY_SIZE(tv_modes)) { ret = -EINVAL; goto out; } @@ -1506,7 +1506,7 @@ intel_tv_init(struct drm_device *dev) struct intel_encoder *intel_encoder; struct intel_connector *intel_connector; u32 tv_dac_on, tv_dac_off, save_tv_dac; - char *tv_format_names[DRM_ARRAY_SIZE(tv_modes)]; + char *tv_format_names[ARRAY_SIZE(tv_modes)]; int i, initial_mode = 0; if ((I915_READ(TV_CTL) & TV_FUSE_STATE_MASK) == TV_FUSE_STATE_DISABLED) @@ -1590,24 +1590,24 @@ intel_tv_init(struct drm_device *dev) connector->doublescan_allowed = false; /* Create TV properties then attach current values */ - for (i = 0; i < DRM_ARRAY_SIZE(tv_modes); i++) + for (i = 0; i < ARRAY_SIZE(tv_modes); i++) tv_format_names[i] = __DECONST(char *, tv_modes[i].name); drm_mode_create_tv_properties(dev, - DRM_ARRAY_SIZE(tv_modes), + ARRAY_SIZE(tv_modes), tv_format_names); - drm_connector_attach_property(connector, dev->mode_config.tv_mode_property, + drm_object_attach_property(&connector->base, dev->mode_config.tv_mode_property, initial_mode); - drm_connector_attach_property(connector, + drm_object_attach_property(&connector->base, dev->mode_config.tv_left_margin_property, intel_tv->margin[TV_MARGIN_LEFT]); - drm_connector_attach_property(connector, + drm_object_attach_property(&connector->base, dev->mode_config.tv_top_margin_property, intel_tv->margin[TV_MARGIN_TOP]); - drm_connector_attach_property(connector, + drm_object_attach_property(&connector->base, dev->mode_config.tv_right_margin_property, intel_tv->margin[TV_MARGIN_RIGHT]); - drm_connector_attach_property(connector, + drm_object_attach_property(&connector->base, dev->mode_config.tv_bottom_margin_property, intel_tv->margin[TV_MARGIN_BOTTOM]); #if 0 diff --git a/sys/dev/drm2/radeon/atom.c b/sys/dev/drm2/radeon/atom.c index 7cecd07a8bbd..f4ca5e915e89 100644 --- a/sys/dev/drm2/radeon/atom.c +++ b/sys/dev/drm2/radeon/atom.c @@ -661,9 +661,9 @@ static void atom_op_delay(atom_exec_context *ctx, int *ptr, int arg) unsigned count = U8((*ptr)++); ATOM_SDEBUG_PRINT(" count: %d\n", count); if (arg == ATOM_UNIT_MICROSEC) - DRM_UDELAY(count); + udelay(count); else if (!drm_can_sleep()) - DRM_MDELAY(count); + mdelay(count); else DRM_MSLEEP(count); } @@ -1178,7 +1178,7 @@ static int atom_execute_table_locked(struct atom_context *ctx, int index, uint32 ectx.abort = false; ectx.last_jump = 0; if (ws) - ectx.ws = malloc(4 * ws, DRM_MEM_DRIVER, M_ZERO | M_WAITOK); + ectx.ws = malloc(4 * ws, DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); else ectx.ws = NULL; @@ -1234,7 +1234,7 @@ static int atom_iio_len[] = { 1, 2, 3, 3, 3, 3, 4, 4, 4, 3 }; static void atom_index_iio(struct atom_context *ctx, int base) { - ctx->iio = malloc(2 * 256, DRM_MEM_DRIVER, M_ZERO | M_WAITOK); + ctx->iio = malloc(2 * 256, DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); while (CU8(base) == ATOM_IIO_START) { ctx->iio[CU8(base + 1)] = base + 2; base += 2; @@ -1248,7 +1248,7 @@ struct atom_context *atom_parse(struct card_info *card, void *bios) { int base; struct atom_context *ctx = - malloc(sizeof(struct atom_context), DRM_MEM_DRIVER, M_ZERO | M_WAITOK); + malloc(sizeof(struct atom_context), DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); char *str; char name[512]; int i; @@ -1386,16 +1386,16 @@ int atom_allocate_fb_scratch(struct atom_context *ctx) firmware_usage = (struct _ATOM_VRAM_USAGE_BY_FIRMWARE *)((char *)ctx->bios + data_offset); DRM_DEBUG("atom firmware requested %08x %dkb\n", - firmware_usage->asFirmwareVramReserveInfo[0].ulStartAddrUsedByFirmware, - firmware_usage->asFirmwareVramReserveInfo[0].usFirmwareUseInKb); + le32_to_cpu(firmware_usage->asFirmwareVramReserveInfo[0].ulStartAddrUsedByFirmware), + le16_to_cpu(firmware_usage->asFirmwareVramReserveInfo[0].usFirmwareUseInKb)); - usage_bytes = firmware_usage->asFirmwareVramReserveInfo[0].usFirmwareUseInKb * 1024; + usage_bytes = le16_to_cpu(firmware_usage->asFirmwareVramReserveInfo[0].usFirmwareUseInKb) * 1024; } ctx->scratch_size_bytes = 0; if (usage_bytes == 0) usage_bytes = 20 * 1024; /* allocate some scratch memory */ - ctx->scratch = malloc(usage_bytes, DRM_MEM_DRIVER, M_ZERO | M_WAITOK); + ctx->scratch = malloc(usage_bytes, DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); if (!ctx->scratch) return -ENOMEM; ctx->scratch_size_bytes = usage_bytes; diff --git a/sys/dev/drm2/radeon/atombios_crtc.c b/sys/dev/drm2/radeon/atombios_crtc.c index c4c5c4606fa8..0be4cf273ff9 100644 --- a/sys/dev/drm2/radeon/atombios_crtc.c +++ b/sys/dev/drm2/radeon/atombios_crtc.c @@ -256,8 +256,6 @@ void atombios_crtc_dpms(struct drm_crtc *crtc, int mode) radeon_crtc->enabled = true; /* adjust pm to dpms changes BEFORE enabling crtcs */ radeon_pm_compute_clocks(rdev); - if (ASIC_IS_DCE6(rdev) && !radeon_crtc->in_mode_set) - atombios_powergate_crtc(crtc, ATOM_DISABLE); atombios_enable_crtc(crtc, ATOM_ENABLE); if (ASIC_IS_DCE3(rdev) && !ASIC_IS_DCE6(rdev)) atombios_enable_crtc_memreq(crtc, ATOM_ENABLE); @@ -275,8 +273,6 @@ void atombios_crtc_dpms(struct drm_crtc *crtc, int mode) atombios_enable_crtc_memreq(crtc, ATOM_DISABLE); atombios_enable_crtc(crtc, ATOM_DISABLE); radeon_crtc->enabled = false; - if (ASIC_IS_DCE6(rdev) && !radeon_crtc->in_mode_set) - atombios_powergate_crtc(crtc, ATOM_ENABLE); /* adjust pm to dpms changes AFTER disabling crtcs */ radeon_pm_compute_clocks(rdev); break; @@ -565,6 +561,9 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc, /* use frac fb div on APUs */ if (ASIC_IS_DCE41(rdev) || ASIC_IS_DCE61(rdev)) radeon_crtc->pll_flags |= RADEON_PLL_USE_FRAC_FB_DIV; + /* use frac fb div on RS780/RS880 */ + if ((rdev->family == CHIP_RS780) || (rdev->family == CHIP_RS880)) + radeon_crtc->pll_flags |= RADEON_PLL_USE_FRAC_FB_DIV; if (ASIC_IS_DCE32(rdev) && mode->clock > 165000) radeon_crtc->pll_flags |= RADEON_PLL_USE_FRAC_FB_DIV; } else { @@ -1848,6 +1847,8 @@ static void atombios_crtc_disable(struct drm_crtc *crtc) int i; atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); + if (ASIC_IS_DCE6(rdev)) + atombios_powergate_crtc(crtc, ATOM_ENABLE); for (i = 0; i < rdev->num_crtc; i++) { if (rdev->mode_info.crtcs[i] && diff --git a/sys/dev/drm2/radeon/atombios_dp.c b/sys/dev/drm2/radeon/atombios_dp.c index f92df621cbbe..1a3f4e1b7c5d 100644 --- a/sys/dev/drm2/radeon/atombios_dp.c +++ b/sys/dev/drm2/radeon/atombios_dp.c @@ -140,7 +140,7 @@ static int radeon_dp_aux_native_write(struct radeon_connector *radeon_connector, if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_ACK) return send_bytes; else if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_DEFER) - DRM_UDELAY(400); + udelay(400); else return -EIO; } @@ -173,7 +173,7 @@ static int radeon_dp_aux_native_read(struct radeon_connector *radeon_connector, if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_ACK) return ret; else if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_DEFER) - DRM_UDELAY(400); + udelay(400); else if (ret == 0) return -EPROTO; else @@ -261,7 +261,7 @@ int radeon_dp_i2c_aux_ch(device_t dev, int mode, u8 write_byte, u8 *read_byte) return -EREMOTEIO; case AUX_NATIVE_REPLY_DEFER: DRM_DEBUG_KMS("aux_ch native defer\n"); - DRM_UDELAY(400); + udelay(400); continue; default: DRM_ERROR("aux_ch invalid native reply 0x%02x\n", ack); @@ -272,13 +272,13 @@ int radeon_dp_i2c_aux_ch(device_t dev, int mode, u8 write_byte, u8 *read_byte) case AUX_I2C_REPLY_ACK: if (mode == MODE_I2C_READ) *read_byte = reply[0]; - return (0); /* Return ret on Linux. */ + return ret; case AUX_I2C_REPLY_NACK: DRM_DEBUG_KMS("aux_i2c nack\n"); return -EREMOTEIO; case AUX_I2C_REPLY_DEFER: DRM_DEBUG_KMS("aux_i2c defer\n"); - DRM_UDELAY(400); + udelay(400); break; default: DRM_ERROR("aux_i2c invalid reply 0x%02x\n", ack); @@ -685,7 +685,7 @@ static int radeon_dp_link_train_init(struct radeon_dp_link_train_info *dp_info) static int radeon_dp_link_train_finish(struct radeon_dp_link_train_info *dp_info) { - DRM_UDELAY(400); + udelay(400); /* disable the training pattern on the sink */ radeon_write_dpcd_reg(dp_info->radeon_connector, @@ -713,7 +713,7 @@ static int radeon_dp_link_train_cr(struct radeon_dp_link_train_info *dp_info) memset(dp_info->train_set, 0, 4); radeon_dp_update_vs_emph(dp_info); - DRM_UDELAY(400); + udelay(400); /* clock recovery loop */ clock_recovery = false; diff --git a/sys/dev/drm2/radeon/atombios_encoders.c b/sys/dev/drm2/radeon/atombios_encoders.c index 9128aacf77f4..3ee6fc55b328 100644 --- a/sys/dev/drm2/radeon/atombios_encoders.c +++ b/sys/dev/drm2/radeon/atombios_encoders.c @@ -197,7 +197,7 @@ void radeon_atom_backlight_init(struct radeon_encoder *radeon_encoder, if (!(rdev->mode_info.firmware_flags & ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU)) return; - pdata = malloc(sizeof(struct radeon_backlight_privdata), DRM_MEM_DRIVER, M_WAITOK); + pdata = malloc(sizeof(struct radeon_backlight_privdata), DRM_MEM_DRIVER, M_NOWAIT); if (!pdata) { DRM_ERROR("Memory allocation failed\n"); goto error; @@ -279,6 +279,12 @@ static void radeon_atom_backlight_exit(struct radeon_encoder *encoder) #endif +#ifdef FREEBSD_WIP /* FreeBSD: to please GCC 4.2. */ +/* evil but including atombios.h is much worse */ +bool radeon_atom_get_tv_timings(struct radeon_device *rdev, int index, + struct drm_display_mode *mode); +#endif + static inline bool radeon_encoder_is_digital(struct drm_encoder *encoder) { @@ -302,7 +308,7 @@ static inline bool radeon_encoder_is_digital(struct drm_encoder *encoder) } static bool radeon_atom_mode_fixup(struct drm_encoder *encoder, - struct drm_display_mode *mode, + const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); @@ -1342,7 +1348,7 @@ atombios_set_edp_panel_power(struct drm_connector *connector, int action) for (i = 0; i < 300; i++) { if (radeon_hpd_sense(rdev, radeon_connector->hpd.hpd)) return true; - DRM_MDELAY(1); + mdelay(1); } return false; } @@ -2451,7 +2457,7 @@ radeon_atom_ext_dpms(struct drm_encoder *encoder, int mode) } static bool radeon_atom_ext_mode_fixup(struct drm_encoder *encoder, - struct drm_display_mode *mode, + const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { return true; @@ -2506,7 +2512,7 @@ radeon_atombios_set_dac_info(struct radeon_encoder *radeon_encoder) struct drm_device *dev = radeon_encoder->base.dev; struct radeon_device *rdev = dev->dev_private; struct radeon_encoder_atom_dac *dac = malloc(sizeof(struct radeon_encoder_atom_dac), - DRM_MEM_DRIVER, M_ZERO | M_WAITOK); + DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); if (!dac) return NULL; @@ -2520,7 +2526,7 @@ radeon_atombios_set_dig_info(struct radeon_encoder *radeon_encoder) { int encoder_enum = (radeon_encoder->encoder_enum & ENUM_ID_MASK) >> ENUM_ID_SHIFT; struct radeon_encoder_atom_dig *dig = malloc(sizeof(struct radeon_encoder_atom_dig), - DRM_MEM_DRIVER, M_ZERO | M_WAITOK); + DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); if (!dig) return NULL; @@ -2559,7 +2565,7 @@ radeon_add_atom_encoder(struct drm_device *dev, /* add a new one */ radeon_encoder = malloc(sizeof(struct radeon_encoder), - DRM_MEM_DRIVER, M_ZERO | M_WAITOK); + DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); if (!radeon_encoder) return; diff --git a/sys/dev/drm2/radeon/atombios_i2c.c b/sys/dev/drm2/radeon/atombios_i2c.c index 40ba15be931e..fb57ff921198 100644 --- a/sys/dev/drm2/radeon/atombios_i2c.c +++ b/sys/dev/drm2/radeon/atombios_i2c.c @@ -60,10 +60,17 @@ static int radeon_process_i2c_ch(struct radeon_i2c_chan *chan, if (flags & HW_I2C_WRITE) { if (num > ATOM_MAX_HW_I2C_WRITE) { DRM_ERROR("hw i2c: tried to write too many bytes (%d vs 2)\n", num); - return EINVAL; + return -EINVAL; } memcpy(&out, buf, num); args.lpI2CDataOut = cpu_to_le16(out); + } else { +#ifdef FREEBSD_WIP /* FreeBSD: to please GCC 4.2. */ + if (num > ATOM_MAX_HW_I2C_READ) { + DRM_ERROR("hw i2c: tried to read too many bytes (%d vs 255)\n", num); + return -EINVAL; + } +#endif } args.ucI2CSpeed = TARGET_HW_I2C_CLOCK; @@ -77,7 +84,7 @@ static int radeon_process_i2c_ch(struct radeon_i2c_chan *chan, /* error */ if (args.ucStatus != HW_ASSISTED_I2C_STATUS_SUCCESS) { DRM_DEBUG_KMS("hw_i2c error\n"); - return EIO; + return -EIO; } if (!(flags & HW_I2C_WRITE)) @@ -101,9 +108,9 @@ radeon_atom_hw_i2c_xfer(device_t dev, struct iic_msg *msgs, u_int num) p->slave, HW_I2C_WRITE, &buf, 1); if (ret) - return ret; + return -ret; /* "ret" is returned on Linux. */ else - return (0); + return (0); /* "num" is returned on Linux. */ } for (i = 0; i < num; i++) { @@ -127,13 +134,13 @@ radeon_atom_hw_i2c_xfer(device_t dev, struct iic_msg *msgs, u_int num) p->slave, flags, &p->buf[buffer_offset], current_count); if (ret) - return ret; + return -ret; /* "ret" is returned on Linux. */ remaining -= current_count; buffer_offset += current_count; } } - return (0); + return (0); /* "num" is returned on Linux. */ } static int diff --git a/sys/dev/drm2/radeon/cayman_blit_shaders.c b/sys/dev/drm2/radeon/cayman_blit_shaders.c index 779f305b6a1b..6130250d757c 100644 --- a/sys/dev/drm2/radeon/cayman_blit_shaders.c +++ b/sys/dev/drm2/radeon/cayman_blit_shaders.c @@ -370,6 +370,6 @@ const u32 cayman_ps[] = 0x00000000, }; -const u32 cayman_ps_size = DRM_ARRAY_SIZE(cayman_ps); -const u32 cayman_vs_size = DRM_ARRAY_SIZE(cayman_vs); -const u32 cayman_default_size = DRM_ARRAY_SIZE(cayman_default_state); +const u32 cayman_ps_size = ARRAY_SIZE(cayman_ps); +const u32 cayman_vs_size = ARRAY_SIZE(cayman_vs); +const u32 cayman_default_size = ARRAY_SIZE(cayman_default_state); diff --git a/sys/dev/drm2/radeon/evergreen.c b/sys/dev/drm2/radeon/evergreen.c index 3c98d53a9bd2..4643d62f916c 100644 --- a/sys/dev/drm2/radeon/evergreen.c +++ b/sys/dev/drm2/radeon/evergreen.c @@ -49,7 +49,14 @@ static const u32 crtc_offsets[6] = }; static void evergreen_gpu_init(struct radeon_device *rdev); +#ifdef FREEBSD_WIP /* FreeBSD: to please GCC 4.2. */ +void evergreen_fini(struct radeon_device *rdev); +#endif void evergreen_pcie_gen2_enable(struct radeon_device *rdev); +#ifdef FREEBSD_WIP /* FreeBSD: to please GCC 4.2. */ +extern void cayman_cp_int_cntl_setup(struct radeon_device *rdev, + int ring, u32 cp_int_cntl); +#endif void evergreen_tiling_fields(unsigned tiling_flags, unsigned *bankw, unsigned *bankh, unsigned *mtaspect, @@ -107,6 +114,27 @@ void evergreen_fix_pci_max_read_req_size(struct radeon_device *rdev) } } +static bool dce4_is_in_vblank(struct radeon_device *rdev, int crtc) +{ + if (RREG32(EVERGREEN_CRTC_STATUS + crtc_offsets[crtc]) & EVERGREEN_CRTC_V_BLANK) + return true; + else + return false; +} + +static bool dce4_is_counter_moving(struct radeon_device *rdev, int crtc) +{ + u32 pos1, pos2; + + pos1 = RREG32(EVERGREEN_CRTC_STATUS_POSITION + crtc_offsets[crtc]); + pos2 = RREG32(EVERGREEN_CRTC_STATUS_POSITION + crtc_offsets[crtc]); + + if (pos1 != pos2) + return true; + else + return false; +} + /** * dce4_wait_for_vblank - vblank wait asic callback. * @@ -117,21 +145,28 @@ void evergreen_fix_pci_max_read_req_size(struct radeon_device *rdev) */ void dce4_wait_for_vblank(struct radeon_device *rdev, int crtc) { - int i; + unsigned i = 0; if (crtc >= rdev->num_crtc) return; - if (RREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[crtc]) & EVERGREEN_CRTC_MASTER_EN) { - for (i = 0; i < rdev->usec_timeout; i++) { - if (!(RREG32(EVERGREEN_CRTC_STATUS + crtc_offsets[crtc]) & EVERGREEN_CRTC_V_BLANK)) + if (!(RREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[crtc]) & EVERGREEN_CRTC_MASTER_EN)) + return; + + /* depending on when we hit vblank, we may be close to active; if so, + * wait for another frame. + */ + while (dce4_is_in_vblank(rdev, crtc)) { + if (i++ % 100 == 0) { + if (!dce4_is_counter_moving(rdev, crtc)) break; - DRM_UDELAY(1); } - for (i = 0; i < rdev->usec_timeout; i++) { - if (RREG32(EVERGREEN_CRTC_STATUS + crtc_offsets[crtc]) & EVERGREEN_CRTC_V_BLANK) + } + + while (!dce4_is_in_vblank(rdev, crtc)) { + if (i++ % 100 == 0) { + if (!dce4_is_counter_moving(rdev, crtc)) break; - DRM_UDELAY(1); } } } @@ -204,7 +239,7 @@ u32 evergreen_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base) for (i = 0; i < rdev->usec_timeout; i++) { if (RREG32(EVERGREEN_GRPH_UPDATE + radeon_crtc->crtc_offset) & EVERGREEN_GRPH_SURFACE_UPDATE_PENDING) break; - DRM_UDELAY(1); + udelay(1); } DRM_DEBUG("Update pending now high. Unlocking vupdate_lock.\n"); @@ -405,6 +440,19 @@ void evergreen_pm_misc(struct radeon_device *rdev) rdev->pm.current_vddc = voltage->voltage; DRM_DEBUG("Setting: vddc: %d\n", voltage->voltage); } + + /* starting with BTC, there is one state that is used for both + * MH and SH. Difference is that we always use the high clock index for + * mclk and vddci. + */ + if ((rdev->pm.pm_method == PM_METHOD_PROFILE) && + (rdev->family >= CHIP_BARTS) && + rdev->pm.active_crtc_count && + ((rdev->pm.profile_index == PM_PROFILE_MID_MH_IDX) || + (rdev->pm.profile_index == PM_PROFILE_LOW_MH_IDX))) + voltage = &rdev->pm.power_state[req_ps_idx]. + clock_info[rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_cm_idx].voltage; + /* 0xff01 is a flag rather then an actual voltage */ if (voltage->vddci == 0xff01) return; @@ -597,6 +645,16 @@ void evergreen_hpd_init(struct radeon_device *rdev) list_for_each_entry(connector, &dev->mode_config.connector_list, head) { struct radeon_connector *radeon_connector = to_radeon_connector(connector); + + if (connector->connector_type == DRM_MODE_CONNECTOR_eDP || + connector->connector_type == DRM_MODE_CONNECTOR_LVDS) { + /* don't try to enable hpd on eDP or LVDS avoid breaking the + * aux dp channel on imac and help (but not completely fix) + * https://bugzilla.redhat.com/show_bug.cgi?id=726143 + * also avoid interrupt storms during dpms. + */ + continue; + } switch (radeon_connector->hpd.hpd) { case RADEON_HPD_1: WREG32(DC_HPD1_CONTROL, tmp); @@ -1146,7 +1204,7 @@ int evergreen_mc_wait_for_idle(struct radeon_device *rdev) tmp = RREG32(SRBM_STATUS) & 0x1F00; if (!tmp) return 0; - DRM_UDELAY(1); + udelay(1); } return -1; } @@ -1173,7 +1231,7 @@ void evergreen_pcie_gart_tlb_flush(struct radeon_device *rdev) if (tmp) { return; } - DRM_UDELAY(1); + udelay(1); } } @@ -1314,17 +1372,16 @@ void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *sav tmp = RREG32(EVERGREEN_CRTC_BLANK_CONTROL + crtc_offsets[i]); if (!(tmp & EVERGREEN_CRTC_BLANK_DATA_EN)) { radeon_wait_for_vblank(rdev, i); - tmp |= EVERGREEN_CRTC_BLANK_DATA_EN; WREG32(EVERGREEN_CRTC_UPDATE_LOCK + crtc_offsets[i], 1); + tmp |= EVERGREEN_CRTC_BLANK_DATA_EN; WREG32(EVERGREEN_CRTC_BLANK_CONTROL + crtc_offsets[i], tmp); - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + crtc_offsets[i], 0); } } else { tmp = RREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[i]); if (!(tmp & EVERGREEN_CRTC_DISP_READ_REQUEST_DISABLE)) { radeon_wait_for_vblank(rdev, i); - tmp |= EVERGREEN_CRTC_DISP_READ_REQUEST_DISABLE; WREG32(EVERGREEN_CRTC_UPDATE_LOCK + crtc_offsets[i], 1); + tmp |= EVERGREEN_CRTC_DISP_READ_REQUEST_DISABLE; WREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[i], tmp); WREG32(EVERGREEN_CRTC_UPDATE_LOCK + crtc_offsets[i], 0); } @@ -1334,8 +1391,17 @@ void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *sav for (j = 0; j < rdev->usec_timeout; j++) { if (radeon_get_vblank_counter(rdev, i) != frame_count) break; - DRM_UDELAY(1); + udelay(1); } + + /* XXX this is a hack to avoid strange behavior with EFI on certain systems */ + WREG32(EVERGREEN_CRTC_UPDATE_LOCK + crtc_offsets[i], 1); + tmp = RREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[i]); + tmp &= ~EVERGREEN_CRTC_MASTER_EN; + WREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[i], tmp); + WREG32(EVERGREEN_CRTC_UPDATE_LOCK + crtc_offsets[i], 0); + save->crtc_enabled[i] = false; + /* ***** */ } else { save->crtc_enabled[i] = false; } @@ -1352,7 +1418,23 @@ void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *sav WREG32(MC_SHARED_BLACKOUT_CNTL, blackout | 1); } /* wait for the MC to settle */ - DRM_UDELAY(100); + udelay(100); + + /* lock double buffered regs */ + for (i = 0; i < rdev->num_crtc; i++) { + if (save->crtc_enabled[i]) { + tmp = RREG32(EVERGREEN_GRPH_UPDATE + crtc_offsets[i]); + if (!(tmp & EVERGREEN_GRPH_UPDATE_LOCK)) { + tmp |= EVERGREEN_GRPH_UPDATE_LOCK; + WREG32(EVERGREEN_GRPH_UPDATE + crtc_offsets[i], tmp); + } + tmp = RREG32(EVERGREEN_MASTER_UPDATE_LOCK + crtc_offsets[i]); + if (!(tmp & 1)) { + tmp |= 1; + WREG32(EVERGREEN_MASTER_UPDATE_LOCK + crtc_offsets[i], tmp); + } + } + } } void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *save) @@ -1374,6 +1456,33 @@ void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *s WREG32(EVERGREEN_VGA_MEMORY_BASE_ADDRESS_HIGH, upper_32_bits(rdev->mc.vram_start)); WREG32(EVERGREEN_VGA_MEMORY_BASE_ADDRESS, (u32)rdev->mc.vram_start); + /* unlock regs and wait for update */ + for (i = 0; i < rdev->num_crtc; i++) { + if (save->crtc_enabled[i]) { + tmp = RREG32(EVERGREEN_MASTER_UPDATE_MODE + crtc_offsets[i]); + if ((tmp & 0x3) != 0) { + tmp &= ~0x3; + WREG32(EVERGREEN_MASTER_UPDATE_MODE + crtc_offsets[i], tmp); + } + tmp = RREG32(EVERGREEN_GRPH_UPDATE + crtc_offsets[i]); + if (tmp & EVERGREEN_GRPH_UPDATE_LOCK) { + tmp &= ~EVERGREEN_GRPH_UPDATE_LOCK; + WREG32(EVERGREEN_GRPH_UPDATE + crtc_offsets[i], tmp); + } + tmp = RREG32(EVERGREEN_MASTER_UPDATE_LOCK + crtc_offsets[i]); + if (tmp & 1) { + tmp &= ~1; + WREG32(EVERGREEN_MASTER_UPDATE_LOCK + crtc_offsets[i], tmp); + } + for (j = 0; j < rdev->usec_timeout; j++) { + tmp = RREG32(EVERGREEN_GRPH_UPDATE + crtc_offsets[i]); + if ((tmp & EVERGREEN_GRPH_SURFACE_UPDATE_PENDING) == 0) + break; + udelay(1); + } + } + } + /* unblackout the MC */ tmp = RREG32(MC_SHARED_BLACKOUT_CNTL); tmp &= ~BLACKOUT_MODE_MASK; @@ -1401,13 +1510,13 @@ void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *s for (j = 0; j < rdev->usec_timeout; j++) { if (radeon_get_vblank_counter(rdev, i) != frame_count) break; - DRM_UDELAY(1); + udelay(1); } } } /* Unlock vga access */ WREG32(VGA_HDP_CONTROL, save->vga_hdp_control); - DRM_MDELAY(1); + mdelay(1); WREG32(VGA_RENDER_CONTROL, save->vga_render_control); } @@ -1639,7 +1748,7 @@ static int evergreen_cp_resume(struct radeon_device *rdev) SOFT_RESET_SPI | SOFT_RESET_SX)); RREG32(GRBM_SOFT_RESET); - DRM_MDELAY(15); + mdelay(15); WREG32(GRBM_SOFT_RESET, 0); RREG32(GRBM_SOFT_RESET); @@ -1675,7 +1784,7 @@ static int evergreen_cp_resume(struct radeon_device *rdev) WREG32(SCRATCH_UMSK, 0); } - DRM_MDELAY(1); + mdelay(1); WREG32(CP_RB_CNTL, tmp); WREG32(CP_RB_BASE, ring->gpu_addr >> 8); @@ -2247,7 +2356,7 @@ static void evergreen_gpu_init(struct radeon_device *rdev) WREG32(PA_CL_ENHANCE, CLIP_VTX_REORDER_ENA | NUM_CLIP_SEQ(3)); - DRM_UDELAY(50); + udelay(50); } @@ -2373,7 +2482,7 @@ static void evergreen_gpu_soft_reset_gfx(struct radeon_device *rdev) dev_info(rdev->dev, " GRBM_SOFT_RESET=0x%08X\n", grbm_reset); WREG32(GRBM_SOFT_RESET, grbm_reset); (void)RREG32(GRBM_SOFT_RESET); - DRM_UDELAY(50); + udelay(50); WREG32(GRBM_SOFT_RESET, 0); (void)RREG32(GRBM_SOFT_RESET); @@ -2413,7 +2522,7 @@ static void evergreen_gpu_soft_reset_dma(struct radeon_device *rdev) /* Reset dma */ WREG32(SRBM_SOFT_RESET, SOFT_RESET_DMA); RREG32(SRBM_SOFT_RESET); - DRM_UDELAY(50); + udelay(50); WREG32(SRBM_SOFT_RESET, 0); dev_info(rdev->dev, " R_00D034_DMA_STATUS_REG = 0x%08X\n", @@ -2447,7 +2556,7 @@ static int evergreen_gpu_soft_reset(struct radeon_device *rdev, u32 reset_mask) evergreen_gpu_soft_reset_dma(rdev); /* Wait a little for things to settle down */ - DRM_UDELAY(50); + udelay(50); evergreen_mc_resume(rdev, &save); return 0; @@ -2871,7 +2980,7 @@ static void evergreen_irq_disable(struct radeon_device *rdev) { r600_disable_interrupts(rdev); /* Wait and acknowledge irq */ - DRM_MDELAY(1); + mdelay(1); evergreen_irq_ack(rdev); evergreen_disable_interrupt_state(rdev); } diff --git a/sys/dev/drm2/radeon/evergreen_blit_shaders.c b/sys/dev/drm2/radeon/evergreen_blit_shaders.c index 6db3cef02557..7121859c5b56 100644 --- a/sys/dev/drm2/radeon/evergreen_blit_shaders.c +++ b/sys/dev/drm2/radeon/evergreen_blit_shaders.c @@ -353,6 +353,6 @@ const u32 evergreen_ps[] = 0x00000000, }; -const u32 evergreen_ps_size = DRM_ARRAY_SIZE(evergreen_ps); -const u32 evergreen_vs_size = DRM_ARRAY_SIZE(evergreen_vs); -const u32 evergreen_default_size = DRM_ARRAY_SIZE(evergreen_default_state); +const u32 evergreen_ps_size = ARRAY_SIZE(evergreen_ps); +const u32 evergreen_vs_size = ARRAY_SIZE(evergreen_vs); +const u32 evergreen_default_size = ARRAY_SIZE(evergreen_default_state); diff --git a/sys/dev/drm2/radeon/evergreen_cs.c b/sys/dev/drm2/radeon/evergreen_cs.c index 1dac26548613..018ffccc95c4 100644 --- a/sys/dev/drm2/radeon/evergreen_cs.c +++ b/sys/dev/drm2/radeon/evergreen_cs.c @@ -40,6 +40,10 @@ __FBSDID("$FreeBSD$"); #define MAX(a,b) (((a)>(b))?(a):(b)) #define MIN(a,b) (((a)<(b))?(a):(b)) +#ifdef FREEBSD_WIP /* FreeBSD: to please GCC 4.2. */ +int r600_dma_cs_next_reloc(struct radeon_cs_parser *p, + struct radeon_cs_reloc **cs_reloc); +#endif static int evergreen_cs_packet_next_reloc(struct radeon_cs_parser *p, struct radeon_cs_reloc **cs_reloc); @@ -1292,9 +1296,9 @@ static int evergreen_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx) int r; if (p->rdev->family >= CHIP_CAYMAN) - last_reg = DRM_ARRAY_SIZE(cayman_reg_safe_bm); + last_reg = ARRAY_SIZE(cayman_reg_safe_bm); else - last_reg = DRM_ARRAY_SIZE(evergreen_reg_safe_bm); + last_reg = ARRAY_SIZE(evergreen_reg_safe_bm); i = (reg >> 7); if (i >= last_reg) { @@ -1960,9 +1964,9 @@ static bool evergreen_is_safe_reg(struct radeon_cs_parser *p, u32 reg, u32 idx) u32 last_reg, m, i; if (p->rdev->family >= CHIP_CAYMAN) - last_reg = DRM_ARRAY_SIZE(cayman_reg_safe_bm); + last_reg = ARRAY_SIZE(cayman_reg_safe_bm); else - last_reg = DRM_ARRAY_SIZE(evergreen_reg_safe_bm); + last_reg = ARRAY_SIZE(evergreen_reg_safe_bm); i = (reg >> 7); if (i >= last_reg) { @@ -2759,7 +2763,7 @@ int evergreen_cs_parse(struct radeon_cs_parser *p) if (p->track == NULL) { /* initialize tracker, we are in kms */ - track = malloc(sizeof(*track), DRM_MEM_DRIVER, M_ZERO | M_WAITOK); + track = malloc(sizeof(*track), DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); if (track == NULL) return -ENOMEM; evergreen_cs_track_init(track); diff --git a/sys/dev/drm2/radeon/evergreen_reg.h b/sys/dev/drm2/radeon/evergreen_reg.h index 7603168d2749..7d3e9d745b27 100644 --- a/sys/dev/drm2/radeon/evergreen_reg.h +++ b/sys/dev/drm2/radeon/evergreen_reg.h @@ -229,6 +229,8 @@ __FBSDID("$FreeBSD$"); #define EVERGREEN_CRTC_STATUS_POSITION 0x6e90 #define EVERGREEN_MASTER_UPDATE_MODE 0x6ef8 #define EVERGREEN_CRTC_UPDATE_LOCK 0x6ed4 +#define EVERGREEN_MASTER_UPDATE_LOCK 0x6ef4 +#define EVERGREEN_MASTER_UPDATE_MODE 0x6ef8 #define EVERGREEN_DC_GPIO_HPD_MASK 0x64b0 #define EVERGREEN_DC_GPIO_HPD_A 0x64b4 diff --git a/sys/dev/drm2/radeon/ni.c b/sys/dev/drm2/radeon/ni.c index 1484b3ed59a2..57ae00c2cabd 100644 --- a/sys/dev/drm2/radeon/ni.c +++ b/sys/dev/drm2/radeon/ni.c @@ -34,7 +34,20 @@ __FBSDID("$FreeBSD$"); #include "ni_reg.h" #include "cayman_blit_shaders.h" +#ifdef FREEBSD_WIP /* FreeBSD: to please GCC 4.2. */ +extern void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *save); +extern void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *save); +extern int evergreen_mc_wait_for_idle(struct radeon_device *rdev); +extern void evergreen_mc_program(struct radeon_device *rdev); +extern void evergreen_irq_suspend(struct radeon_device *rdev); +extern int evergreen_mc_init(struct radeon_device *rdev); +extern void evergreen_fix_pci_max_read_req_size(struct radeon_device *rdev); +#endif extern void evergreen_pcie_gen2_enable(struct radeon_device *rdev); +#ifdef FREEBSD_WIP /* FreeBSD: to please GCC 4.2. */ +extern void si_rlc_fini(struct radeon_device *rdev); +extern int si_rlc_init(struct radeon_device *rdev); +#endif #define EVERGREEN_PFP_UCODE_SIZE 1120 #define EVERGREEN_PM4_UCODE_SIZE 1376 @@ -48,6 +61,27 @@ extern void evergreen_pcie_gen2_enable(struct radeon_device *rdev); #define ARUBA_RLC_UCODE_SIZE 1536 +#ifdef __linux__ +/* Firmware Names */ +MODULE_FIRMWARE("radeon/BARTS_pfp.bin"); +MODULE_FIRMWARE("radeon/BARTS_me.bin"); +MODULE_FIRMWARE("radeon/BARTS_mc.bin"); +MODULE_FIRMWARE("radeon/BTC_rlc.bin"); +MODULE_FIRMWARE("radeon/TURKS_pfp.bin"); +MODULE_FIRMWARE("radeon/TURKS_me.bin"); +MODULE_FIRMWARE("radeon/TURKS_mc.bin"); +MODULE_FIRMWARE("radeon/CAICOS_pfp.bin"); +MODULE_FIRMWARE("radeon/CAICOS_me.bin"); +MODULE_FIRMWARE("radeon/CAICOS_mc.bin"); +MODULE_FIRMWARE("radeon/CAYMAN_pfp.bin"); +MODULE_FIRMWARE("radeon/CAYMAN_me.bin"); +MODULE_FIRMWARE("radeon/CAYMAN_mc.bin"); +MODULE_FIRMWARE("radeon/CAYMAN_rlc.bin"); +MODULE_FIRMWARE("radeon/ARUBA_pfp.bin"); +MODULE_FIRMWARE("radeon/ARUBA_me.bin"); +MODULE_FIRMWARE("radeon/ARUBA_rlc.bin"); +#endif + #define BTC_IO_MC_REGS_SIZE 29 static const u32 barts_io_mc_regs[BTC_IO_MC_REGS_SIZE][2] = { @@ -244,7 +278,7 @@ int ni_mc_load_microcode(struct radeon_device *rdev) for (i = 0; i < rdev->usec_timeout; i++) { if (RREG32(MC_IO_PAD_CNTL_D0) & MEM_FALL_OUT_CMD) break; - DRM_UDELAY(1); + udelay(1); } if (running) @@ -478,21 +512,32 @@ static void cayman_gpu_init(struct radeon_device *rdev) (rdev->ddev->pci_device == 0x9907) || (rdev->ddev->pci_device == 0x9908) || (rdev->ddev->pci_device == 0x9909) || + (rdev->ddev->pci_device == 0x990B) || + (rdev->ddev->pci_device == 0x990C) || + (rdev->ddev->pci_device == 0x990F) || (rdev->ddev->pci_device == 0x9910) || - (rdev->ddev->pci_device == 0x9917)) { + (rdev->ddev->pci_device == 0x9917) || + (rdev->ddev->pci_device == 0x9999) || + (rdev->ddev->pci_device == 0x999C)) { rdev->config.cayman.max_simds_per_se = 6; rdev->config.cayman.max_backends_per_se = 2; } else if ((rdev->ddev->pci_device == 0x9903) || (rdev->ddev->pci_device == 0x9904) || (rdev->ddev->pci_device == 0x990A) || + (rdev->ddev->pci_device == 0x990D) || + (rdev->ddev->pci_device == 0x990E) || (rdev->ddev->pci_device == 0x9913) || - (rdev->ddev->pci_device == 0x9918)) { + (rdev->ddev->pci_device == 0x9918) || + (rdev->ddev->pci_device == 0x999D)) { rdev->config.cayman.max_simds_per_se = 4; rdev->config.cayman.max_backends_per_se = 2; } else if ((rdev->ddev->pci_device == 0x9919) || (rdev->ddev->pci_device == 0x9990) || (rdev->ddev->pci_device == 0x9991) || (rdev->ddev->pci_device == 0x9994) || + (rdev->ddev->pci_device == 0x9995) || + (rdev->ddev->pci_device == 0x9996) || + (rdev->ddev->pci_device == 0x999A) || (rdev->ddev->pci_device == 0x99A0)) { rdev->config.cayman.max_simds_per_se = 3; rdev->config.cayman.max_backends_per_se = 1; @@ -622,15 +667,28 @@ static void cayman_gpu_init(struct radeon_device *rdev) WREG32(GB_ADDR_CONFIG, gb_addr_config); WREG32(DMIF_ADDR_CONFIG, gb_addr_config); + if (ASIC_IS_DCE6(rdev)) + WREG32(DMIF_ADDR_CALC, gb_addr_config); WREG32(HDP_ADDR_CONFIG, gb_addr_config); WREG32(DMA_TILING_CONFIG + DMA0_REGISTER_OFFSET, gb_addr_config); WREG32(DMA_TILING_CONFIG + DMA1_REGISTER_OFFSET, gb_addr_config); - tmp = gb_addr_config & NUM_PIPES_MASK; - tmp = r6xx_remap_render_backend(rdev, tmp, - rdev->config.cayman.max_backends_per_se * - rdev->config.cayman.max_shader_engines, - CAYMAN_MAX_BACKENDS, disabled_rb_mask); + if ((rdev->config.cayman.max_backends_per_se == 1) && + (rdev->flags & RADEON_IS_IGP)) { + if ((disabled_rb_mask & 3) == 1) { + /* RB0 disabled, RB1 enabled */ + tmp = 0x11111111; + } else { + /* RB1 disabled, RB0 enabled */ + tmp = 0x00000000; + } + } else { + tmp = gb_addr_config & NUM_PIPES_MASK; + tmp = r6xx_remap_render_backend(rdev, tmp, + rdev->config.cayman.max_backends_per_se * + rdev->config.cayman.max_shader_engines, + CAYMAN_MAX_BACKENDS, disabled_rb_mask); + } WREG32(GB_BACKEND_MAP, tmp); cgts_tcc_disable = 0xffff0000; @@ -725,7 +783,7 @@ static void cayman_gpu_init(struct radeon_device *rdev) WREG32(PA_CL_ENHANCE, CLIP_VTX_REORDER_ENA | NUM_CLIP_SEQ(3)); - DRM_UDELAY(50); + udelay(50); } /* @@ -1072,7 +1130,7 @@ static int cayman_cp_resume(struct radeon_device *rdev) SOFT_RESET_SPI | SOFT_RESET_SX)); RREG32(GRBM_SOFT_RESET); - DRM_MDELAY(15); + mdelay(15); WREG32(GRBM_SOFT_RESET, 0); RREG32(GRBM_SOFT_RESET); @@ -1122,7 +1180,7 @@ static int cayman_cp_resume(struct radeon_device *rdev) WREG32(ring->rptr_reg, ring->rptr); WREG32(ring->wptr_reg, ring->wptr); - DRM_MDELAY(1); + mdelay(1); WREG32_P(cp_rb_cntl[i], 0, ~RB_RPTR_WR_ENA); } @@ -1236,7 +1294,7 @@ int cayman_dma_resume(struct radeon_device *rdev) /* Reset dma */ WREG32(SRBM_SOFT_RESET, SOFT_RESET_DMA | SOFT_RESET_DMA1); RREG32(SRBM_SOFT_RESET); - DRM_UDELAY(50); + udelay(50); WREG32(SRBM_SOFT_RESET, 0); for (i = 0; i < 2; i++) { @@ -1367,7 +1425,7 @@ static void cayman_gpu_soft_reset_gfx(struct radeon_device *rdev) dev_info(rdev->dev, " GRBM_SOFT_RESET=0x%08X\n", grbm_reset); WREG32(GRBM_SOFT_RESET, grbm_reset); (void)RREG32(GRBM_SOFT_RESET); - DRM_UDELAY(50); + udelay(50); WREG32(GRBM_SOFT_RESET, 0); (void)RREG32(GRBM_SOFT_RESET); @@ -1413,7 +1471,7 @@ static void cayman_gpu_soft_reset_dma(struct radeon_device *rdev) /* Reset dma */ WREG32(SRBM_SOFT_RESET, SOFT_RESET_DMA | SOFT_RESET_DMA1); RREG32(SRBM_SOFT_RESET); - DRM_UDELAY(50); + udelay(50); WREG32(SRBM_SOFT_RESET, 0); dev_info(rdev->dev, " R_00D034_DMA_STATUS_REG = 0x%08X\n", @@ -1457,7 +1515,7 @@ static int cayman_gpu_soft_reset(struct radeon_device *rdev, u32 reset_mask) cayman_gpu_soft_reset_dma(rdev); /* Wait a little for things to settle down */ - DRM_UDELAY(50); + udelay(50); evergreen_mc_resume(rdev, &save); return 0; @@ -1674,6 +1732,7 @@ int cayman_resume(struct radeon_device *rdev) int cayman_suspend(struct radeon_device *rdev) { r600_audio_fini(rdev); + radeon_vm_manager_fini(rdev); cayman_cp_enable(rdev, false); cayman_dma_stop(rdev); evergreen_irq_suspend(rdev); diff --git a/sys/dev/drm2/radeon/nid.h b/sys/dev/drm2/radeon/nid.h index 89c023735716..e68e3867655b 100644 --- a/sys/dev/drm2/radeon/nid.h +++ b/sys/dev/drm2/radeon/nid.h @@ -48,6 +48,10 @@ __FBSDID("$FreeBSD$"); #define ARUBA_GB_ADDR_CONFIG_GOLDEN 0x12010001 #define DMIF_ADDR_CONFIG 0xBD4 + +/* DCE6 only */ +#define DMIF_ADDR_CALC 0xC00 + #define SRBM_GFX_CNTL 0x0E44 #define RINGID(x) (((x) & 0x3) << 0) #define VMID(x) (((x) & 0x7) << 0) diff --git a/sys/dev/drm2/radeon/r100.c b/sys/dev/drm2/radeon/r100.c index a66c7c2418b2..84f47d33f15b 100644 --- a/sys/dev/drm2/radeon/r100.c +++ b/sys/dev/drm2/radeon/r100.c @@ -52,6 +52,16 @@ __FBSDID("$FreeBSD$"); #define FIRMWARE_RS600 "radeonkmsfw_RS600_cp" #define FIRMWARE_R520 "radeonkmsfw_R520_cp" +#ifdef __linux__ +MODULE_FIRMWARE(FIRMWARE_R100); +MODULE_FIRMWARE(FIRMWARE_R200); +MODULE_FIRMWARE(FIRMWARE_R300); +MODULE_FIRMWARE(FIRMWARE_R420); +MODULE_FIRMWARE(FIRMWARE_RS690); +MODULE_FIRMWARE(FIRMWARE_RS600); +MODULE_FIRMWARE(FIRMWARE_R520); +#endif + #include "r100_track.h" /* This files gather functions specifics to: @@ -59,6 +69,38 @@ __FBSDID("$FreeBSD$"); * and others in some cases. */ +static bool r100_is_in_vblank(struct radeon_device *rdev, int crtc) +{ + if (crtc == 0) { + if (RREG32(RADEON_CRTC_STATUS) & RADEON_CRTC_VBLANK_CUR) + return true; + else + return false; + } else { + if (RREG32(RADEON_CRTC2_STATUS) & RADEON_CRTC2_VBLANK_CUR) + return true; + else + return false; + } +} + +static bool r100_is_counter_moving(struct radeon_device *rdev, int crtc) +{ + u32 vline1, vline2; + + if (crtc == 0) { + vline1 = (RREG32(RADEON_CRTC_VLINE_CRNT_VLINE) >> 16) & RADEON_CRTC_V_TOTAL; + vline2 = (RREG32(RADEON_CRTC_VLINE_CRNT_VLINE) >> 16) & RADEON_CRTC_V_TOTAL; + } else { + vline1 = (RREG32(RADEON_CRTC2_VLINE_CRNT_VLINE) >> 16) & RADEON_CRTC_V_TOTAL; + vline2 = (RREG32(RADEON_CRTC2_VLINE_CRNT_VLINE) >> 16) & RADEON_CRTC_V_TOTAL; + } + if (vline1 != vline2) + return true; + else + return false; +} + /** * r100_wait_for_vblank - vblank wait asic callback. * @@ -69,36 +111,33 @@ __FBSDID("$FreeBSD$"); */ void r100_wait_for_vblank(struct radeon_device *rdev, int crtc) { - int i; + unsigned i = 0; if (crtc >= rdev->num_crtc) return; if (crtc == 0) { - if (RREG32(RADEON_CRTC_GEN_CNTL) & RADEON_CRTC_EN) { - for (i = 0; i < rdev->usec_timeout; i++) { - if (!(RREG32(RADEON_CRTC_STATUS) & RADEON_CRTC_VBLANK_CUR)) - break; - DRM_UDELAY(1); - } - for (i = 0; i < rdev->usec_timeout; i++) { - if (RREG32(RADEON_CRTC_STATUS) & RADEON_CRTC_VBLANK_CUR) - break; - DRM_UDELAY(1); - } - } + if (!(RREG32(RADEON_CRTC_GEN_CNTL) & RADEON_CRTC_EN)) + return; } else { - if (RREG32(RADEON_CRTC2_GEN_CNTL) & RADEON_CRTC2_EN) { - for (i = 0; i < rdev->usec_timeout; i++) { - if (!(RREG32(RADEON_CRTC2_STATUS) & RADEON_CRTC2_VBLANK_CUR)) - break; - DRM_UDELAY(1); - } - for (i = 0; i < rdev->usec_timeout; i++) { - if (RREG32(RADEON_CRTC2_STATUS) & RADEON_CRTC2_VBLANK_CUR) - break; - DRM_UDELAY(1); - } + if (!(RREG32(RADEON_CRTC2_GEN_CNTL) & RADEON_CRTC2_EN)) + return; + } + + /* depending on when we hit vblank, we may be close to active; if so, + * wait for another frame. + */ + while (r100_is_in_vblank(rdev, crtc)) { + if (i++ % 100 == 0) { + if (!r100_is_counter_moving(rdev, crtc)) + break; + } + } + + while (!r100_is_in_vblank(rdev, crtc)) { + if (i++ % 100 == 0) { + if (!r100_is_counter_moving(rdev, crtc)) + break; } } } @@ -160,7 +199,7 @@ u32 r100_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base) for (i = 0; i < rdev->usec_timeout; i++) { if (RREG32(RADEON_CRTC_OFFSET + radeon_crtc->crtc_offset) & RADEON_CRTC_OFFSET__GUI_TRIG_OFFSET) break; - DRM_UDELAY(1); + udelay(1); } DRM_DEBUG("Update pending now high. Unlocking vupdate_lock.\n"); @@ -335,7 +374,7 @@ void r100_pm_misc(struct radeon_device *rdev) tmp &= ~(voltage->gpio.mask); WREG32(voltage->gpio.reg, tmp); if (voltage->delay) - DRM_UDELAY(voltage->delay); + udelay(voltage->delay); } else { tmp = RREG32(voltage->gpio.reg); if (voltage->active_high) @@ -344,7 +383,7 @@ void r100_pm_misc(struct radeon_device *rdev) tmp |= voltage->gpio.mask; WREG32(voltage->gpio.reg, tmp); if (voltage->delay) - DRM_UDELAY(voltage->delay); + udelay(voltage->delay); } } @@ -713,7 +752,7 @@ void r100_irq_disable(struct radeon_device *rdev) WREG32(R_000040_GEN_INT_CNTL, 0); /* Wait and acknowledge irq */ - DRM_MDELAY(1); + mdelay(1); tmp = RREG32(R_000044_GEN_INT_STATUS); WREG32(R_000044_GEN_INT_STATUS, tmp); } @@ -924,7 +963,7 @@ static int r100_cp_wait_for_idle(struct radeon_device *rdev) if (!G_000E40_CP_CMDSTRM_BUSY(tmp)) { return 0; } - DRM_UDELAY(1); + udelay(1); } return -1; } @@ -1143,7 +1182,7 @@ int r100_cp_init(struct radeon_device *rdev, unsigned ring_size) } WREG32(RADEON_CP_RB_CNTL, tmp); - DRM_UDELAY(10); + udelay(10); ring->rptr = RREG32(RADEON_CP_RB_RPTR); /* Set cp mode to bus mastering & enable cp*/ WREG32(RADEON_CP_CSQ_MODE, @@ -2616,14 +2655,14 @@ void r100_bm_disable(struct radeon_device *rdev) /* disable bus mastering */ tmp = RREG32(R_000030_BUS_CNTL); WREG32(R_000030_BUS_CNTL, (tmp & 0xFFFFFFFF) | 0x00000044); - DRM_MDELAY(1); + mdelay(1); WREG32(R_000030_BUS_CNTL, (tmp & 0xFFFFFFFF) | 0x00000042); - DRM_MDELAY(1); + mdelay(1); WREG32(R_000030_BUS_CNTL, (tmp & 0xFFFFFFFF) | 0x00000040); tmp = RREG32(RADEON_BUS_CNTL); - DRM_MDELAY(1); + mdelay(1); pci_disable_busmaster(rdev->dev); - DRM_MDELAY(1); + mdelay(1); } int r100_asic_reset(struct radeon_device *rdev) @@ -2655,17 +2694,17 @@ int r100_asic_reset(struct radeon_device *rdev) S_0000F0_SOFT_RESET_PP(1) | S_0000F0_SOFT_RESET_RB(1)); RREG32(R_0000F0_RBBM_SOFT_RESET); - DRM_MDELAY(500); + mdelay(500); WREG32(R_0000F0_RBBM_SOFT_RESET, 0); - DRM_MDELAY(1); + mdelay(1); status = RREG32(R_000E40_RBBM_STATUS); dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status); /* reset CP */ WREG32(R_0000F0_RBBM_SOFT_RESET, S_0000F0_SOFT_RESET_CP(1)); RREG32(R_0000F0_RBBM_SOFT_RESET); - DRM_MDELAY(500); + mdelay(500); WREG32(R_0000F0_RBBM_SOFT_RESET, 0); - DRM_MDELAY(1); + mdelay(1); status = RREG32(R_000E40_RBBM_STATUS); dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status); /* restore PCI & busmastering */ @@ -2931,7 +2970,7 @@ static void r100_pll_errata_after_data(struct radeon_device *rdev) * or the chip could hang on a subsequent access */ if (rdev->pll_errata & CHIP_ERRATA_PLL_DELAY) { - DRM_MDELAY(5); + mdelay(5); } /* This function is required to workaround a hardware bug in some (all?) @@ -2973,10 +3012,10 @@ static void r100_set_safe_registers(struct radeon_device *rdev) { if (ASIC_IS_RN50(rdev)) { rdev->config.r100.reg_safe_bm = rn50_reg_safe_bm; - rdev->config.r100.reg_safe_bm_size = DRM_ARRAY_SIZE(rn50_reg_safe_bm); + rdev->config.r100.reg_safe_bm_size = ARRAY_SIZE(rn50_reg_safe_bm); } else if (rdev->family < CHIP_R200) { rdev->config.r100.reg_safe_bm = r100_reg_safe_bm; - rdev->config.r100.reg_safe_bm_size = DRM_ARRAY_SIZE(r100_reg_safe_bm); + rdev->config.r100.reg_safe_bm_size = ARRAY_SIZE(r100_reg_safe_bm); } else { r200_set_safe_registers(rdev); } diff --git a/sys/dev/drm2/radeon/r200.c b/sys/dev/drm2/radeon/r200.c index 566645fddb95..25a197e27985 100644 --- a/sys/dev/drm2/radeon/r200.c +++ b/sys/dev/drm2/radeon/r200.c @@ -548,5 +548,5 @@ int r200_packet0_check(struct radeon_cs_parser *p, void r200_set_safe_registers(struct radeon_device *rdev) { rdev->config.r100.reg_safe_bm = r200_reg_safe_bm; - rdev->config.r100.reg_safe_bm_size = DRM_ARRAY_SIZE(r200_reg_safe_bm); + rdev->config.r100.reg_safe_bm_size = ARRAY_SIZE(r200_reg_safe_bm); } diff --git a/sys/dev/drm2/radeon/r300.c b/sys/dev/drm2/radeon/r300.c index 56810354c724..caaff4a6bcb7 100644 --- a/sys/dev/drm2/radeon/r300.c +++ b/sys/dev/drm2/radeon/r300.c @@ -407,9 +407,9 @@ int r300_asic_reset(struct radeon_device *rdev) WREG32(R_0000F0_RBBM_SOFT_RESET, S_0000F0_SOFT_RESET_VAP(1) | S_0000F0_SOFT_RESET_GA(1)); RREG32(R_0000F0_RBBM_SOFT_RESET); - DRM_MDELAY(500); + mdelay(500); WREG32(R_0000F0_RBBM_SOFT_RESET, 0); - DRM_MDELAY(1); + mdelay(1); status = RREG32(R_000E40_RBBM_STATUS); dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status); /* resetting the CP seems to be problematic sometimes it end up @@ -419,9 +419,9 @@ int r300_asic_reset(struct radeon_device *rdev) */ WREG32(R_0000F0_RBBM_SOFT_RESET, S_0000F0_SOFT_RESET_CP(1)); RREG32(R_0000F0_RBBM_SOFT_RESET); - DRM_MDELAY(500); + mdelay(500); WREG32(R_0000F0_RBBM_SOFT_RESET, 0); - DRM_MDELAY(1); + mdelay(1); status = RREG32(R_000E40_RBBM_STATUS); dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status); /* restore PCI & busmastering */ @@ -1254,7 +1254,7 @@ int r300_cs_parse(struct radeon_cs_parser *p) struct r100_cs_track *track; int r; - track = malloc(sizeof(*track), DRM_MEM_DRIVER, M_ZERO | M_WAITOK); + track = malloc(sizeof(*track), DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); if (track == NULL) return -ENOMEM; r100_cs_track_clear(p->rdev, track); @@ -1299,7 +1299,7 @@ int r300_cs_parse(struct radeon_cs_parser *p) void r300_set_reg_safe(struct radeon_device *rdev) { rdev->config.r300.reg_safe_bm = r300_reg_safe_bm; - rdev->config.r300.reg_safe_bm_size = DRM_ARRAY_SIZE(r300_reg_safe_bm); + rdev->config.r300.reg_safe_bm_size = ARRAY_SIZE(r300_reg_safe_bm); } void r300_mc_program(struct radeon_device *rdev) diff --git a/sys/dev/drm2/radeon/r300_cmdbuf.c b/sys/dev/drm2/radeon/r300_cmdbuf.c index 4f41b13a27ba..421747c0cc18 100644 --- a/sys/dev/drm2/radeon/r300_cmdbuf.c +++ b/sys/dev/drm2/radeon/r300_cmdbuf.c @@ -1013,7 +1013,7 @@ int r300_do_cp_cmdbuf(struct drm_device *dev, drm_radeon_kcmd_buffer_t *cmdbuf) { drm_radeon_private_t *dev_priv = dev->dev_private; - struct drm_radeon_master_private *master_priv = file_priv->masterp->driver_priv; + struct drm_radeon_master_private *master_priv = file_priv->master->driver_priv; struct drm_device_dma *dma = dev->dma; struct drm_buf *buf = NULL; int emit_dispatch_age = 0; @@ -1120,7 +1120,7 @@ int r300_do_cp_cmdbuf(struct drm_device *dev, } emit_dispatch_age = 1; - r300_discard_buffer(dev, file_priv->masterp, buf); + r300_discard_buffer(dev, file_priv->master, buf); break; case R300_CMD_WAIT: diff --git a/sys/dev/drm2/radeon/r420.c b/sys/dev/drm2/radeon/r420.c index e422f9db6bc9..eb38d46ebb76 100644 --- a/sys/dev/drm2/radeon/r420.c +++ b/sys/dev/drm2/radeon/r420.c @@ -80,7 +80,7 @@ void r420_pm_init_profile(struct radeon_device *rdev) static void r420_set_reg_safe(struct radeon_device *rdev) { rdev->config.r300.reg_safe_bm = r420_reg_safe_bm; - rdev->config.r300.reg_safe_bm_size = DRM_ARRAY_SIZE(r420_reg_safe_bm); + rdev->config.r300.reg_safe_bm_size = ARRAY_SIZE(r420_reg_safe_bm); } void r420_pipes_init(struct radeon_device *rdev) diff --git a/sys/dev/drm2/radeon/r500_reg.h b/sys/dev/drm2/radeon/r500_reg.h index 7b7130ec227f..78e7bd01ed87 100644 --- a/sys/dev/drm2/radeon/r500_reg.h +++ b/sys/dev/drm2/radeon/r500_reg.h @@ -129,10 +129,6 @@ __FBSDID("$FreeBSD$"); # define RS690_MC_INDEX_MASK 0x1ff # define RS690_MC_INDEX_WR_EN (1 << 9) # define RS690_MC_INDEX_WR_ACK 0x7f -#define RS690_MC_NB_CNTL 0x0 -# define RS690_HIDE_MMCFG_BAR (1 << 3) -# define RS690_AGPMODE30 (1 << 4) -# define RS690_AGP30ENHANCED (1 << 5) #define RS690_MC_DATA 0x7c #define RS690_MC_STATUS 0x90 #define RS690_MC_STATUS_IDLE (1 << 0) @@ -364,7 +360,9 @@ __FBSDID("$FreeBSD$"); #define AVIVO_D1CRTC_FRAME_COUNT 0x60a4 #define AVIVO_D1CRTC_STEREO_CONTROL 0x60c4 +#define AVIVO_D1MODE_MASTER_UPDATE_LOCK 0x60e0 #define AVIVO_D1MODE_MASTER_UPDATE_MODE 0x60e4 +#define AVIVO_D1CRTC_UPDATE_LOCK 0x60e8 /* master controls */ #define AVIVO_DC_CRTC_MASTER_EN 0x60f8 diff --git a/sys/dev/drm2/radeon/r600.c b/sys/dev/drm2/radeon/r600.c index 586427d9c8c3..68f417c4fc80 100644 --- a/sys/dev/drm2/radeon/r600.c +++ b/sys/dev/drm2/radeon/r600.c @@ -50,7 +50,7 @@ __FBSDID("$FreeBSD$"); #define CAYMAN_RLC_UCODE_SIZE 1024 #define ARUBA_RLC_UCODE_SIZE 1536 -#ifdef DUMBBELL_WIP +#ifdef __linux__ /* Firmware Names */ MODULE_FIRMWARE("radeon/R600_pfp.bin"); MODULE_FIRMWARE("radeon/R600_me.bin"); @@ -93,12 +93,18 @@ MODULE_FIRMWARE("radeon/SUMO_pfp.bin"); MODULE_FIRMWARE("radeon/SUMO_me.bin"); MODULE_FIRMWARE("radeon/SUMO2_pfp.bin"); MODULE_FIRMWARE("radeon/SUMO2_me.bin"); -#endif /* DUMBBELL_WIP */ +#endif int r600_debugfs_mc_info_init(struct radeon_device *rdev); /* r600,rv610,rv630,rv620,rv635,rv670 */ +#ifdef FREEBSD_WIP /* FreeBSD: to please GCC 4.2. */ +int r600_mc_wait_for_idle(struct radeon_device *rdev); +#endif static void r600_gpu_init(struct radeon_device *rdev); +#ifdef FREEBSD_WIP /* FreeBSD: to please GCC 4.2. */ +void r600_fini(struct radeon_device *rdev); +#endif void r600_irq_disable(struct radeon_device *rdev); static void r600_pcie_gen2_enable(struct radeon_device *rdev); @@ -860,7 +866,7 @@ void r600_pcie_gart_tlb_flush(struct radeon_device *rdev) if (tmp) { return; } - DRM_UDELAY(1); + udelay(1); } } @@ -1021,7 +1027,7 @@ int r600_mc_wait_for_idle(struct radeon_device *rdev) tmp = RREG32(R_000E50_SRBM_STATUS) & 0x3F00; if (!tmp) return 0; - DRM_UDELAY(1); + udelay(1); } return -1; } @@ -1209,7 +1215,7 @@ static int r600_mc_init(struct radeon_device *rdev) int r600_vram_scratch_init(struct radeon_device *rdev) { int r; - void *vram_scratch_ptr_ptr; + void *vram_scratch_ptr_ptr; /* FreeBSD: to please GCC 4.2. */ if (rdev->vram_scratch.robj == NULL) { r = radeon_bo_create(rdev, RADEON_GPU_PAGE_SIZE, @@ -1324,7 +1330,7 @@ static void r600_gpu_soft_reset_gfx(struct radeon_device *rdev) dev_info(rdev->dev, " R_008020_GRBM_SOFT_RESET=0x%08X\n", tmp); WREG32(R_008020_GRBM_SOFT_RESET, tmp); RREG32(R_008020_GRBM_SOFT_RESET); - DRM_MDELAY(15); + mdelay(15); WREG32(R_008020_GRBM_SOFT_RESET, 0); } /* Reset CP (we always reset CP) */ @@ -1332,7 +1338,7 @@ static void r600_gpu_soft_reset_gfx(struct radeon_device *rdev) dev_info(rdev->dev, "R_008020_GRBM_SOFT_RESET=0x%08X\n", tmp); WREG32(R_008020_GRBM_SOFT_RESET, tmp); RREG32(R_008020_GRBM_SOFT_RESET); - DRM_MDELAY(15); + mdelay(15); WREG32(R_008020_GRBM_SOFT_RESET, 0); dev_info(rdev->dev, " R_008010_GRBM_STATUS = 0x%08X\n", @@ -1373,7 +1379,7 @@ static void r600_gpu_soft_reset_dma(struct radeon_device *rdev) else WREG32(SRBM_SOFT_RESET, SOFT_RESET_DMA); RREG32(SRBM_SOFT_RESET); - DRM_UDELAY(50); + udelay(50); WREG32(SRBM_SOFT_RESET, 0); dev_info(rdev->dev, " R_00D034_DMA_STATUS_REG = 0x%08X\n", @@ -1407,7 +1413,7 @@ static int r600_gpu_soft_reset(struct radeon_device *rdev, u32 reset_mask) r600_gpu_soft_reset_dma(rdev); /* Wait a little for things to settle down */ - DRM_MDELAY(1); + mdelay(1); rv515_mc_resume(rdev, &save); return 0; @@ -2168,7 +2174,7 @@ static int r600_cp_load_microcode(struct radeon_device *rdev) /* Reset cp */ WREG32(GRBM_SOFT_RESET, SOFT_RESET_CP); RREG32(GRBM_SOFT_RESET); - DRM_MDELAY(15); + mdelay(15); WREG32(GRBM_SOFT_RESET, 0); WREG32(CP_ME_RAM_WADDR, 0); @@ -2231,7 +2237,7 @@ int r600_cp_resume(struct radeon_device *rdev) /* Reset cp */ WREG32(GRBM_SOFT_RESET, SOFT_RESET_CP); RREG32(GRBM_SOFT_RESET); - DRM_MDELAY(15); + mdelay(15); WREG32(GRBM_SOFT_RESET, 0); /* Set ring buffer size */ @@ -2265,7 +2271,7 @@ int r600_cp_resume(struct radeon_device *rdev) WREG32(SCRATCH_UMSK, 0); } - DRM_MDELAY(1); + mdelay(1); WREG32(CP_RB_CNTL, tmp); WREG32(CP_RB_BASE, ring->gpu_addr >> 8); @@ -2362,7 +2368,7 @@ int r600_dma_resume(struct radeon_device *rdev) else WREG32(SRBM_SOFT_RESET, SOFT_RESET_DMA); RREG32(SRBM_SOFT_RESET); - DRM_UDELAY(50); + udelay(50); WREG32(SRBM_SOFT_RESET, 0); WREG32(DMA_SEM_INCOMPLETE_TIMER_CNTL, 0); @@ -3255,7 +3261,7 @@ void r600_ih_ring_init(struct radeon_device *rdev, unsigned ring_size) int r600_ih_ring_alloc(struct radeon_device *rdev) { int r; - void *ring_ptr; + void *ring_ptr; /* FreeBSD: to please GCC 4.2. */ /* Allocate ring buffer */ if (rdev->ih.ring_obj == NULL) { @@ -3320,7 +3326,7 @@ void r600_rlc_stop(struct radeon_device *rdev) /* r7xx asics need to soft reset RLC before halting */ WREG32(SRBM_SOFT_RESET, SOFT_RESET_RLC); RREG32(SRBM_SOFT_RESET); - DRM_MDELAY(15); + mdelay(15); WREG32(SRBM_SOFT_RESET, 0); RREG32(SRBM_SOFT_RESET); } @@ -3813,7 +3819,7 @@ void r600_irq_disable(struct radeon_device *rdev) { r600_disable_interrupts(rdev); /* Wait and acknowledge irq */ - DRM_MDELAY(1); + mdelay(1); r600_irq_ack(rdev); r600_disable_interrupt_state(rdev); } diff --git a/sys/dev/drm2/radeon/r600_blit.c b/sys/dev/drm2/radeon/r600_blit.c index f44fd797a89f..514a92d44142 100644 --- a/sys/dev/drm2/radeon/r600_blit.c +++ b/sys/dev/drm2/radeon/r600_blit.c @@ -539,7 +539,7 @@ static void r600_nomm_put_vb(struct drm_device *dev) drm_radeon_private_t *dev_priv = dev->dev_private; dev_priv->blit_vb->used = 0; - radeon_cp_discard_buffer(dev, dev_priv->blit_vb->file_priv->masterp, dev_priv->blit_vb); + radeon_cp_discard_buffer(dev, dev_priv->blit_vb->file_priv->master, dev_priv->blit_vb); } static void *r600_nomm_get_vb_ptr(struct drm_device *dev) diff --git a/sys/dev/drm2/radeon/r600_blit_shaders.c b/sys/dev/drm2/radeon/r600_blit_shaders.c index 1095a2c1213f..6f284dea6275 100644 --- a/sys/dev/drm2/radeon/r600_blit_shaders.c +++ b/sys/dev/drm2/radeon/r600_blit_shaders.c @@ -714,7 +714,7 @@ const u32 r6xx_ps[] = 0x00000000, }; -const u32 r6xx_ps_size = DRM_ARRAY_SIZE(r6xx_ps); -const u32 r6xx_vs_size = DRM_ARRAY_SIZE(r6xx_vs); -const u32 r6xx_default_size = DRM_ARRAY_SIZE(r6xx_default_state); -const u32 r7xx_default_size = DRM_ARRAY_SIZE(r7xx_default_state); +const u32 r6xx_ps_size = ARRAY_SIZE(r6xx_ps); +const u32 r6xx_vs_size = ARRAY_SIZE(r6xx_vs); +const u32 r6xx_default_size = ARRAY_SIZE(r6xx_default_state); +const u32 r7xx_default_size = ARRAY_SIZE(r7xx_default_state); diff --git a/sys/dev/drm2/radeon/r600_cp.c b/sys/dev/drm2/radeon/r600_cp.c index 2907bdb2fbe6..f4a78df80984 100644 --- a/sys/dev/drm2/radeon/r600_cp.c +++ b/sys/dev/drm2/radeon/r600_cp.c @@ -44,6 +44,37 @@ __FBSDID("$FreeBSD$"); #define R700_PFP_UCODE_SIZE 848 #define R700_PM4_UCODE_SIZE 1360 +#ifdef __linux__ +/* Firmware Names */ +MODULE_FIRMWARE("radeon/R600_pfp.bin"); +MODULE_FIRMWARE("radeon/R600_me.bin"); +MODULE_FIRMWARE("radeon/RV610_pfp.bin"); +MODULE_FIRMWARE("radeon/RV610_me.bin"); +MODULE_FIRMWARE("radeon/RV630_pfp.bin"); +MODULE_FIRMWARE("radeon/RV630_me.bin"); +MODULE_FIRMWARE("radeon/RV620_pfp.bin"); +MODULE_FIRMWARE("radeon/RV620_me.bin"); +MODULE_FIRMWARE("radeon/RV635_pfp.bin"); +MODULE_FIRMWARE("radeon/RV635_me.bin"); +MODULE_FIRMWARE("radeon/RV670_pfp.bin"); +MODULE_FIRMWARE("radeon/RV670_me.bin"); +MODULE_FIRMWARE("radeon/RS780_pfp.bin"); +MODULE_FIRMWARE("radeon/RS780_me.bin"); +MODULE_FIRMWARE("radeon/RV770_pfp.bin"); +MODULE_FIRMWARE("radeon/RV770_me.bin"); +MODULE_FIRMWARE("radeon/RV730_pfp.bin"); +MODULE_FIRMWARE("radeon/RV730_me.bin"); +MODULE_FIRMWARE("radeon/RV710_pfp.bin"); +MODULE_FIRMWARE("radeon/RV710_me.bin"); +#endif + + +#ifdef FREEBSD_WIP /* FreeBSD: to please GCC 4.2. */ +int r600_cs_legacy(struct drm_device *dev, void *data, struct drm_file *filp, + unsigned family, u32 *ib, int *l); +void r600_cs_legacy_init(void); +#endif + # define ATI_PCIGART_PAGE_SIZE 4096 /**< PCI GART page size */ # define ATI_PCIGART_PAGE_MASK (~(ATI_PCIGART_PAGE_SIZE-1)) @@ -392,7 +423,7 @@ static void r600_cp_load_microcode(drm_radeon_private_t *dev_priv) RADEON_WRITE(R600_GRBM_SOFT_RESET, R600_SOFT_RESET_CP); RADEON_READ(R600_GRBM_SOFT_RESET); - DRM_MDELAY(15); + mdelay(15); RADEON_WRITE(R600_GRBM_SOFT_RESET, 0); fw_data = (const __be32 *)dev_priv->me_fw->data; @@ -485,7 +516,7 @@ static void r700_cp_load_microcode(drm_radeon_private_t *dev_priv) RADEON_WRITE(R600_GRBM_SOFT_RESET, R600_SOFT_RESET_CP); RADEON_READ(R600_GRBM_SOFT_RESET); - DRM_MDELAY(15); + mdelay(15); RADEON_WRITE(R600_GRBM_SOFT_RESET, 0); fw_data = (const __be32 *)dev_priv->pfp_fw->data; @@ -1777,7 +1808,7 @@ static void r600_cp_init_ring_buffer(struct drm_device *dev, RADEON_WRITE(R600_GRBM_SOFT_RESET, R600_SOFT_RESET_CP); RADEON_READ(R600_GRBM_SOFT_RESET); - DRM_MDELAY(15); + mdelay(15); RADEON_WRITE(R600_GRBM_SOFT_RESET, 0); @@ -1907,7 +1938,7 @@ static void r600_cp_init_ring_buffer(struct drm_device *dev, RADEON_WRITE(R600_LAST_CLEAR_REG, 0); /* reset sarea copies of these */ - master_priv = file_priv->masterp->driver_priv; + master_priv = file_priv->master->driver_priv; if (master_priv->sarea_priv) { master_priv->sarea_priv->last_frame = 0; master_priv->sarea_priv->last_dispatch = 0; @@ -1966,7 +1997,7 @@ int r600_do_init_cp(struct drm_device *dev, drm_radeon_init_t *init, struct drm_file *file_priv) { drm_radeon_private_t *dev_priv = dev->dev_private; - struct drm_radeon_master_private *master_priv = file_priv->masterp->driver_priv; + struct drm_radeon_master_private *master_priv = file_priv->master->driver_priv; DRM_DEBUG("\n"); @@ -2401,7 +2432,7 @@ int r600_cp_dispatch_indirect(struct drm_device *dev, void r600_cp_dispatch_swap(struct drm_device *dev, struct drm_file *file_priv) { drm_radeon_private_t *dev_priv = dev->dev_private; - struct drm_master *master = file_priv->masterp; + struct drm_master *master = file_priv->master; struct drm_radeon_master_private *master_priv = master->driver_priv; drm_radeon_sarea_t *sarea_priv = master_priv->sarea_priv; int nbox = sarea_priv->nbox; @@ -2523,7 +2554,7 @@ int r600_cp_dispatch_texture(struct drm_device *dev, r600_blit_copy(dev, src_offset, dst_offset, pass_size); - radeon_cp_discard_buffer(dev, file_priv->masterp, buf); + radeon_cp_discard_buffer(dev, file_priv->master, buf); /* Update the input parameters for next time */ image->data = (const u8 __user *)image->data + pass_size; @@ -2588,7 +2619,7 @@ static void r600_ib_free(struct drm_device *dev, struct drm_buf *buf, if (buf) { if (!r) r600_cp_dispatch_indirect(dev, buf, 0, l * 4); - radeon_cp_discard_buffer(dev, fpriv->masterp, buf); + radeon_cp_discard_buffer(dev, fpriv->master, buf); COMMIT_RING(); } } diff --git a/sys/dev/drm2/radeon/r600_cs.c b/sys/dev/drm2/radeon/r600_cs.c index 9000b3c7d027..4b1a705cdf9b 100644 --- a/sys/dev/drm2/radeon/r600_cs.c +++ b/sys/dev/drm2/radeon/r600_cs.c @@ -43,6 +43,9 @@ static int r600_cs_packet_next_reloc_nomm(struct radeon_cs_parser *p, struct radeon_cs_reloc **cs_reloc); typedef int (*next_reloc_t)(struct radeon_cs_parser*, struct radeon_cs_reloc**); static next_reloc_t r600_cs_packet_next_reloc = &r600_cs_packet_next_reloc_mm; +#ifdef FREEBSD_WIP /* FreeBSD: to please GCC 4.2. */ +extern void r600_cs_legacy_get_tiling_conf(struct drm_device *dev, u32 *npipes, u32 *nbanks, u32 *group_size); +#endif struct r600_cs_track { @@ -186,7 +189,7 @@ static const struct gpu_formats color_formats_table[] = { bool r600_fmt_is_valid_color(u32 format) { - if (format >= DRM_ARRAY_SIZE(color_formats_table)) + if (format >= ARRAY_SIZE(color_formats_table)) return false; if (color_formats_table[format].valid_color) @@ -197,7 +200,7 @@ bool r600_fmt_is_valid_color(u32 format) bool r600_fmt_is_valid_texture(u32 format, enum radeon_family family) { - if (format >= DRM_ARRAY_SIZE(color_formats_table)) + if (format >= ARRAY_SIZE(color_formats_table)) return false; if (family < color_formats_table[format].min_family) @@ -211,7 +214,7 @@ bool r600_fmt_is_valid_texture(u32 format, enum radeon_family family) int r600_fmt_get_blocksize(u32 format) { - if (format >= DRM_ARRAY_SIZE(color_formats_table)) + if (format >= ARRAY_SIZE(color_formats_table)) return 0; return color_formats_table[format].blocksize; @@ -221,7 +224,7 @@ int r600_fmt_get_nblocksx(u32 format, u32 w) { unsigned bw; - if (format >= DRM_ARRAY_SIZE(color_formats_table)) + if (format >= ARRAY_SIZE(color_formats_table)) return 0; bw = color_formats_table[format].blockwidth; @@ -235,7 +238,7 @@ int r600_fmt_get_nblocksy(u32 format, u32 h) { unsigned bh; - if (format >= DRM_ARRAY_SIZE(color_formats_table)) + if (format >= ARRAY_SIZE(color_formats_table)) return 0; bh = color_formats_table[format].blockheight; @@ -1117,7 +1120,7 @@ static int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx) int r; i = (reg >> 7); - if (i >= DRM_ARRAY_SIZE(r600_reg_safe_bm)) { + if (i >= ARRAY_SIZE(r600_reg_safe_bm)) { dev_warn(p->dev, "forbidden register 0x%08x at %d\n", reg, idx); return -EINVAL; } @@ -1741,7 +1744,7 @@ static bool r600_is_safe_reg(struct radeon_cs_parser *p, u32 reg, u32 idx) u32 m, i; i = (reg >> 7); - if (i >= DRM_ARRAY_SIZE(r600_reg_safe_bm)) { + if (i >= ARRAY_SIZE(r600_reg_safe_bm)) { dev_warn(p->dev, "forbidden register 0x%08x at %d\n", reg, idx); return false; } @@ -2400,7 +2403,7 @@ int r600_cs_parse(struct radeon_cs_parser *p) if (p->track == NULL) { /* initialize tracker, we are in kms */ track = malloc(sizeof(*track), - DRM_MEM_DRIVER, M_ZERO | M_WAITOK); + DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); if (track == NULL) return -ENOMEM; r600_cs_track_init(track); @@ -2447,7 +2450,7 @@ int r600_cs_parse(struct radeon_cs_parser *p) #if 0 for (r = 0; r < p->ib.length_dw; r++) { DRM_INFO("%05d 0x%08X\n", r, p->ib.ptr[r]); - DRM_MDELAY(1); + mdelay(1); } #endif free(p->track, DRM_MEM_DRIVER); @@ -2461,7 +2464,7 @@ static int r600_cs_parser_relocs_legacy(struct radeon_cs_parser *p) return 0; } p->relocs = malloc(sizeof(struct radeon_cs_reloc), - DRM_MEM_DRIVER, M_ZERO | M_WAITOK); + DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); if (p->relocs == NULL) { return -ENOMEM; } @@ -2502,7 +2505,7 @@ int r600_cs_legacy(struct drm_device *dev, void *data, struct drm_file *filp, int r; /* initialize tracker */ - track = malloc(sizeof(*track), DRM_MEM_DRIVER, M_ZERO | M_WAITOK); + track = malloc(sizeof(*track), DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); if (track == NULL) return -ENOMEM; r600_cs_track_init(track); @@ -2510,7 +2513,7 @@ int r600_cs_legacy(struct drm_device *dev, void *data, struct drm_file *filp, /* initialize parser */ memset(&parser, 0, sizeof(struct radeon_cs_parser)); parser.filp = filp; - parser.dev = dev->device; + parser.dev = dev->dev; parser.rdev = NULL; parser.family = family; parser.track = track; @@ -2754,7 +2757,7 @@ int r600_dma_cs_parse(struct radeon_cs_parser *p) #if 0 for (r = 0; r < p->ib->length_dw; r++) { DRM_INFO("%05d 0x%08X\n", r, p->ib.ptr[r]); - DRM_MDELAY(1); + mdelay(1); } #endif return 0; diff --git a/sys/dev/drm2/radeon/r600_hdmi.c b/sys/dev/drm2/radeon/r600_hdmi.c index 46a72fbad0ff..d75b3d3e441b 100644 --- a/sys/dev/drm2/radeon/r600_hdmi.c +++ b/sys/dev/drm2/radeon/r600_hdmi.c @@ -493,7 +493,7 @@ void r600_hdmi_enable(struct drm_encoder *encoder) offset = dig->afmt->offset; /* Older chipsets require setting HDMI and routing manually */ - if (rdev->family >= CHIP_R600 && !ASIC_IS_DCE3(rdev)) { + if (ASIC_IS_DCE2(rdev) && !ASIC_IS_DCE3(rdev)) { hdmi = HDMI0_ERROR_ACK | HDMI0_ENABLE; switch (radeon_encoder->encoder_id) { case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: @@ -548,7 +548,6 @@ void r600_hdmi_disable(struct drm_encoder *encoder) /* Called for ATOM_ENCODER_MODE_HDMI only */ if (!dig || !dig->afmt) { - DRM_ERROR("%s: !dig || !dig->afmt", __func__); return; } if (!dig->afmt->enabled) @@ -562,7 +561,7 @@ void r600_hdmi_disable(struct drm_encoder *encoder) radeon_irq_kms_disable_afmt(rdev, dig->afmt->id); /* Older chipsets not handled by AtomBIOS */ - if (rdev->family >= CHIP_R600 && !ASIC_IS_DCE3(rdev)) { + if (ASIC_IS_DCE2(rdev) && !ASIC_IS_DCE3(rdev)) { switch (radeon_encoder->encoder_id) { case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: WREG32_P(AVIVO_TMDSA_CNTL, 0, diff --git a/sys/dev/drm2/radeon/r600d.h b/sys/dev/drm2/radeon/r600d.h index 174b1feda4a9..92f35de9cd6c 100644 --- a/sys/dev/drm2/radeon/r600d.h +++ b/sys/dev/drm2/radeon/r600d.h @@ -48,11 +48,17 @@ __FBSDID("$FreeBSD$"); #define R6XX_MAX_PIPES_MASK 0xff /* PTE flags */ +/* + * FIXME Linux<->FreeBSD: PTE_VALID is already defined on PowerPC on FreeBSD. + * Fortunately, it's never used in the Radeon driver. + */ +/* #define PTE_VALID (1 << 0) #define PTE_SYSTEM (1 << 1) #define PTE_SNOOPED (1 << 2) #define PTE_READABLE (1 << 5) #define PTE_WRITEABLE (1 << 6) +*/ /* tiling bits */ #define ARRAY_LINEAR_GENERAL 0x00000000 diff --git a/sys/dev/drm2/radeon/radeon.h b/sys/dev/drm2/radeon/radeon.h index 8d932d9528ab..4a63cf647332 100644 --- a/sys/dev/drm2/radeon/radeon.h +++ b/sys/dev/drm2/radeon/radeon.h @@ -72,8 +72,10 @@ __FBSDID("$FreeBSD$"); #include <sys/linker.h> #include <sys/firmware.h> +#if defined(CONFIG_ACPI) #include <contrib/dev/acpica/include/acpi.h> #include <dev/acpica/acpivar.h> +#endif #include <dev/drm2/ttm/ttm_bo_api.h> #include <dev/drm2/ttm/ttm_bo_driver.h> @@ -111,7 +113,7 @@ extern int radeon_lockup_timeout; * symbol; */ #define RADEON_MAX_USEC_TIMEOUT 100000 /* 100 ms */ -#define RADEON_FENCE_JIFFIES_TIMEOUT (DRM_HZ / 2) +#define RADEON_FENCE_JIFFIES_TIMEOUT (HZ / 2) /* RADEON_IB_POOL_SIZE must be a power of 2 */ #define RADEON_IB_POOL_SIZE 16 #define RADEON_DEBUGFS_MAX_COMPONENTS 32 @@ -1103,9 +1105,9 @@ struct radeon_pm { /* selected pm method */ enum radeon_pm_method pm_method; /* dynpm power management */ -#ifdef DUMBBELL_WIP +#ifdef FREEBSD_WIP struct delayed_work dynpm_idle_work; -#endif /* DUMBBELL_WIP */ +#endif /* FREEBSD_WIP */ enum radeon_dynpm_state dynpm_state; enum radeon_dynpm_action dynpm_planned_action; unsigned long dynpm_action_timeout; @@ -1117,9 +1119,9 @@ struct radeon_pm { struct radeon_pm_profile profiles[PM_PROFILE_MAX]; /* internal thermal controller on rv6xx+ */ enum radeon_int_thermal_type int_thermal_type; -#ifdef DUMBBELL_WIP +#ifdef FREEBSD_WIP struct device *int_hwmon_dev; -#endif /* DUMBBELL_WIP */ +#endif /* FREEBSD_WIP */ }; int radeon_pm_get_type_index(struct radeon_device *rdev, @@ -1637,10 +1639,12 @@ struct radeon_device { struct sx dc_hw_i2c_mutex; /* display controller hw i2c mutex */ bool audio_enabled; struct r600_audio audio_status; /* audio stuff */ +#if defined(CONFIG_ACPI) struct { ACPI_HANDLE handle; ACPI_NOTIFY_HANDLER notifier_call; } acpi; +#endif /* only one userspace can use Hyperz features or CMASK at a time */ struct drm_file *hyperz_filp; struct drm_file *cmask_filp; @@ -1796,7 +1800,7 @@ void radeon_atombios_fini(struct radeon_device *rdev); /* * RING helpers. */ -#if !defined(DRM_DEBUG_CODE) || DRM_DEBUG_CODE == 0 +#if DRM_DEBUG_CODE == 0 static inline void radeon_ring_write(struct radeon_ring *ring, uint32_t v) { ring->ring[ring->wptr++] = v; @@ -1985,8 +1989,13 @@ extern int ni_mc_load_microcode(struct radeon_device *rdev); extern void ni_fini_microcode(struct radeon_device *rdev); /* radeon_acpi.c */ +#if defined(CONFIG_ACPI) extern int radeon_acpi_init(struct radeon_device *rdev); extern void radeon_acpi_fini(struct radeon_device *rdev); +#else +static inline int radeon_acpi_init(struct radeon_device *rdev) { return 0; } +static inline void radeon_acpi_fini(struct radeon_device *rdev) { } +#endif /* Prototypes added by @dumbbell. */ diff --git a/sys/dev/drm2/radeon/radeon_acpi.c b/sys/dev/drm2/radeon/radeon_acpi.c index 176e160ffb0f..a725ab78624e 100644 --- a/sys/dev/drm2/radeon/radeon_acpi.c +++ b/sys/dev/drm2/radeon/radeon_acpi.c @@ -32,6 +32,8 @@ __FBSDID("$FreeBSD$"); #define ACPI_AC_CLASS "ac_adapter" +extern void radeon_pm_acpi_event_handler(struct radeon_device *rdev); + struct atif_verify_interface { u16 size; /* structure size in bytes (includes size field) */ u16 version; /* version */ @@ -358,7 +360,7 @@ void radeon_atif_handler(struct radeon_device *rdev, radeon_set_backlight_level(rdev, enc, req.backlight_level); -#ifdef DUMBBELL_WIP +#ifdef FREEBSD_WIP if (rdev->is_atom_bios) { struct radeon_encoder_atom_dig *dig = enc->enc_priv; backlight_force_update(dig->bl_dev, @@ -368,7 +370,7 @@ void radeon_atif_handler(struct radeon_device *rdev, backlight_force_update(dig->bl_dev, BACKLIGHT_UPDATE_HOTKEY); } -#endif /* DUMBBELL_WIP */ +#endif /* FREEBSD_WIP */ } } /* TODO: check other events */ @@ -508,7 +510,7 @@ static void radeon_acpi_event(ACPI_HANDLE handle, UINT32 type, { struct radeon_device *rdev = (struct radeon_device *)context; -#ifdef DUMBBELL_WIP +#ifdef FREEBSD_WIP if (strcmp(entry->device_class, ACPI_AC_CLASS) == 0) { if (power_supply_is_system_supplied() > 0) DRM_DEBUG_DRIVER("pm: AC\n"); @@ -517,7 +519,7 @@ static void radeon_acpi_event(ACPI_HANDLE handle, UINT32 type, radeon_pm_acpi_event_handler(rdev); } -#endif /* DUMBBELL_WIP */ +#endif /* FREEBSD_WIP */ /* Check for pending SBIOS requests */ radeon_atif_handler(rdev, type); diff --git a/sys/dev/drm2/radeon/radeon_agp.c b/sys/dev/drm2/radeon/radeon_agp.c index 0ac376b53433..aabdf72dec95 100644 --- a/sys/dev/drm2/radeon/radeon_agp.c +++ b/sys/dev/drm2/radeon/radeon_agp.c @@ -153,11 +153,11 @@ int radeon_agp_init(struct radeon_device *rdev) return ret; } - if ((rdev->ddev->agp->info.ai_aperture_size >> 20) < 32) { + if ((rdev->ddev->agp->agp_info.ai_aperture_size >> 20) < 32) { drm_agp_release(rdev->ddev); dev_warn(rdev->dev, "AGP aperture too small (%zuM) " "need at least 32M, disabling AGP\n", - rdev->ddev->agp->info.ai_aperture_size >> 20); + rdev->ddev->agp->agp_info.ai_aperture_size >> 20); return -EINVAL; } @@ -245,8 +245,8 @@ int radeon_agp_init(struct radeon_device *rdev) return ret; } - rdev->mc.agp_base = rdev->ddev->agp->info.ai_aperture_base; - rdev->mc.gtt_size = rdev->ddev->agp->info.ai_aperture_size; + rdev->mc.agp_base = rdev->ddev->agp->agp_info.ai_aperture_base; + rdev->mc.gtt_size = rdev->ddev->agp->agp_info.ai_aperture_size; rdev->mc.gtt_start = rdev->mc.agp_base; rdev->mc.gtt_end = rdev->mc.gtt_start + rdev->mc.gtt_size - 1; dev_info(rdev->dev, "GTT: %juM 0x%08jX - 0x%08jX\n", diff --git a/sys/dev/drm2/radeon/radeon_atombios.c b/sys/dev/drm2/radeon/radeon_atombios.c index 309f1477154b..e00c8b37ac39 100644 --- a/sys/dev/drm2/radeon/radeon_atombios.c +++ b/sys/dev/drm2/radeon/radeon_atombios.c @@ -35,6 +35,34 @@ __FBSDID("$FreeBSD$"); #include "atom.h" #include "atom-bits.h" +#ifdef FREEBSD_WIP /* FreeBSD: to please GCC 4.2. */ +/* from radeon_encoder.c */ +extern uint32_t +radeon_get_encoder_enum(struct drm_device *dev, uint32_t supported_device, + uint8_t dac); +extern void radeon_link_encoder_connector(struct drm_device *dev); +extern void +radeon_add_atom_encoder(struct drm_device *dev, uint32_t encoder_enum, + uint32_t supported_device, u16 caps); + +/* from radeon_connector.c */ +extern void +radeon_add_atom_connector(struct drm_device *dev, + uint32_t connector_id, + uint32_t supported_device, + int connector_type, + struct radeon_i2c_bus_rec *i2c_bus, + uint32_t igp_lane_info, + uint16_t connector_object_id, + struct radeon_hpd *hpd, + struct radeon_router *router); + +/* from radeon_legacy_encoder.c */ +extern void +radeon_add_legacy_encoder(struct drm_device *dev, uint32_t encoder_enum, + uint32_t supported_device); +#endif + /* local */ static int radeon_atom_get_max_vddc(struct radeon_device *rdev, u8 voltage_type, u16 voltage_id, u16 *voltage); @@ -904,7 +932,7 @@ bool radeon_get_atom_connector_info_from_supported_devices_table(struct router.ddc_valid = false; router.cd_valid = false; - bios_connectors = malloc(bc_size, DRM_MEM_DRIVER, M_WAITOK | M_ZERO); + bios_connectors = malloc(bc_size, DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); if (!bios_connectors) return false; @@ -1532,7 +1560,7 @@ struct radeon_encoder_atom_dig *radeon_atombios_get_lvds_info(struct (union lvds_info *)((char *)mode_info->atom_context->bios + data_offset); lvds = malloc(sizeof(struct radeon_encoder_atom_dig), - DRM_MEM_DRIVER, M_WAITOK | M_ZERO); + DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); if (!lvds) return NULL; @@ -1619,7 +1647,7 @@ struct radeon_encoder_atom_dig *radeon_atombios_get_lvds_info(struct struct edid *edid; int edid_size = max((int)EDID_LENGTH, (int)fake_edid_record->ucFakeEDIDLength); - edid = malloc(edid_size, DRM_MEM_KMS, M_WAITOK); + edid = malloc(edid_size, DRM_MEM_KMS, M_NOWAIT); if (edid) { memcpy((u8 *)edid, (u8 *)&fake_edid_record->ucFakeEDIDString[0], fake_edid_record->ucFakeEDIDLength); @@ -1671,7 +1699,7 @@ radeon_atombios_get_primary_dac_info(struct radeon_encoder *encoder) ((char *)mode_info->atom_context->bios + data_offset); p_dac = malloc(sizeof(struct radeon_encoder_primary_dac), - DRM_MEM_DRIVER, M_WAITOK | M_ZERO); + DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); if (!p_dac) return NULL; @@ -1857,7 +1885,7 @@ radeon_atombios_get_tv_dac_info(struct radeon_encoder *encoder) ((char *)mode_info->atom_context->bios + data_offset); tv_dac = malloc(sizeof(struct radeon_encoder_tv_dac), - DRM_MEM_DRIVER, M_WAITOK | M_ZERO); + DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); if (!tv_dac) return NULL; @@ -1992,13 +2020,13 @@ static int radeon_atombios_parse_power_table_1_3(struct radeon_device *rdev) /* add the i2c bus for thermal/fan chip */ if ((power_info->info.ucOverdriveThermalController > 0) && - (power_info->info.ucOverdriveThermalController < DRM_ARRAY_SIZE(thermal_controller_names))) { + (power_info->info.ucOverdriveThermalController < ARRAY_SIZE(thermal_controller_names))) { DRM_INFO("Possible %s thermal controller at 0x%02x\n", thermal_controller_names[power_info->info.ucOverdriveThermalController], power_info->info.ucOverdriveControllerAddress >> 1); i2c_bus = radeon_lookup_i2c_gpio(rdev, power_info->info.ucOverdriveI2cLine); rdev->pm.i2c_bus = radeon_i2c_lookup(rdev, &i2c_bus); -#ifdef DUMBBELL_WIP +#ifdef FREEBSD_WIP if (rdev->pm.i2c_bus) { struct i2c_board_info info = { }; const char *name = thermal_controller_names[power_info->info. @@ -2007,20 +2035,22 @@ static int radeon_atombios_parse_power_table_1_3(struct radeon_device *rdev) strlcpy(info.type, name, sizeof(info.type)); i2c_new_device(&rdev->pm.i2c_bus->adapter, &info); } -#endif /* DUMBBELL_WIP */ +#endif /* FREEBSD_WIP */ } num_modes = power_info->info.ucNumOfPowerModeEntries; if (num_modes > ATOM_MAX_NUMBEROF_POWER_BLOCK) num_modes = ATOM_MAX_NUMBEROF_POWER_BLOCK; + if (num_modes == 0) + return state_index; rdev->pm.power_state = malloc(sizeof(struct radeon_power_state) * num_modes, - DRM_MEM_DRIVER, M_WAITOK | M_ZERO); + DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); if (!rdev->pm.power_state) return state_index; /* last mode is usually default, array is low to high */ for (i = 0; i < num_modes; i++) { rdev->pm.power_state[state_index].clock_info = malloc(sizeof(struct radeon_pm_clock_info) * 1, - DRM_MEM_DRIVER, M_WAITOK | M_ZERO); + DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); if (!rdev->pm.power_state[state_index].clock_info) return state_index; rdev->pm.power_state[state_index].num_clock_modes = 1; @@ -2200,7 +2230,7 @@ static void radeon_atombios_add_pplib_thermal_controller(struct radeon_device *r (controller->ucType == ATOM_PP_THERMALCONTROLLER_EMC2103_WITH_INTERNAL)) { DRM_INFO("Special thermal controller config\n"); - } else if (controller->ucType < DRM_ARRAY_SIZE(pp_lib_thermal_controller_names)) { + } else if (controller->ucType < ARRAY_SIZE(pp_lib_thermal_controller_names)) { DRM_INFO("Possible %s thermal controller at 0x%02x %s fan control\n", pp_lib_thermal_controller_names[controller->ucType], controller->ucI2cAddress >> 1, @@ -2208,7 +2238,7 @@ static void radeon_atombios_add_pplib_thermal_controller(struct radeon_device *r ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); i2c_bus = radeon_lookup_i2c_gpio(rdev, controller->ucI2cLine); rdev->pm.i2c_bus = radeon_i2c_lookup(rdev, &i2c_bus); -#ifdef DUMBBELL_WIP +#ifdef FREEBSD_WIP if (rdev->pm.i2c_bus) { struct i2c_board_info info = { }; const char *name = pp_lib_thermal_controller_names[controller->ucType]; @@ -2216,7 +2246,7 @@ static void radeon_atombios_add_pplib_thermal_controller(struct radeon_device *r strlcpy(info.type, name, sizeof(info.type)); i2c_new_device(&rdev->pm.i2c_bus->adapter, &info); } -#endif /* DUMBBELL_WIP */ +#endif /* FREEBSD_WIP */ } else { DRM_INFO("Unknown thermal controller type %d at 0x%02x %s fan control\n", controller->ucType, @@ -2420,9 +2450,11 @@ static int radeon_atombios_parse_power_table_4_5(struct radeon_device *rdev) power_info = (union power_info *)((char *)mode_info->atom_context->bios + data_offset); radeon_atombios_add_pplib_thermal_controller(rdev, &power_info->pplib.sThermalController); + if (power_info->pplib.ucNumStates == 0) + return state_index; rdev->pm.power_state = malloc(sizeof(struct radeon_power_state) * power_info->pplib.ucNumStates, - DRM_MEM_DRIVER, M_WAITOK | M_ZERO); + DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); if (!rdev->pm.power_state) return state_index; /* first mode is usually default, followed by low to high */ @@ -2440,7 +2472,7 @@ static int radeon_atombios_parse_power_table_4_5(struct radeon_device *rdev) rdev->pm.power_state[i].clock_info = malloc(sizeof(struct radeon_pm_clock_info) * ((power_info->pplib.ucStateEntrySize - 1) ? (power_info->pplib.ucStateEntrySize - 1) : 1), - DRM_MEM_DRIVER, M_WAITOK | M_ZERO); + DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); if (!rdev->pm.power_state[i].clock_info) return state_index; if (power_info->pplib.ucStateEntrySize - 1) { @@ -2503,6 +2535,7 @@ static int radeon_atombios_parse_power_table_6(struct radeon_device *rdev) int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo); u16 data_offset; u8 frev, crev; + u8 *power_state_offset; if (!atom_parse_data_header(mode_info->atom_context, index, NULL, &frev, &crev, &data_offset)) @@ -2519,30 +2552,29 @@ static int radeon_atombios_parse_power_table_6(struct radeon_device *rdev) non_clock_info_array = (struct _NonClockInfoArray *) ((char *)mode_info->atom_context->bios + data_offset + le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset)); + if (state_array->ucNumEntries == 0) + return state_index; rdev->pm.power_state = malloc(sizeof(struct radeon_power_state) * state_array->ucNumEntries, - DRM_MEM_DRIVER, M_WAITOK | M_ZERO); + DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); if (!rdev->pm.power_state) return state_index; + power_state_offset = (u8 *)state_array->states; for (i = 0; i < state_array->ucNumEntries; i++) { mode_index = 0; - power_state = (union pplib_power_state *)&state_array->states[i]; - /* XXX this might be an inagua bug... */ - non_clock_array_index = i; /* power_state->v2.nonClockInfoIndex */ + power_state = (union pplib_power_state *)power_state_offset; + non_clock_array_index = power_state->v2.nonClockInfoIndex; non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *) &non_clock_info_array->nonClockInfo[non_clock_array_index]; rdev->pm.power_state[i].clock_info = malloc(sizeof(struct radeon_pm_clock_info) * (power_state->v2.ucNumDPMLevels ? power_state->v2.ucNumDPMLevels : 1), - DRM_MEM_DRIVER, M_WAITOK | M_ZERO); + DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); if (!rdev->pm.power_state[i].clock_info) return state_index; if (power_state->v2.ucNumDPMLevels) { for (j = 0; j < power_state->v2.ucNumDPMLevels; j++) { clock_array_index = power_state->v2.clockInfoIndex[j]; - /* XXX this might be an inagua bug... */ - if (clock_array_index >= clock_info_array->ucNumEntries) - continue; clock_info = (union pplib_clock_info *) &clock_info_array->clockInfo[clock_array_index * clock_info_array->ucEntrySize]; valid = radeon_atombios_parse_pplib_clock_info(rdev, @@ -2564,6 +2596,7 @@ static int radeon_atombios_parse_power_table_6(struct radeon_device *rdev) non_clock_info); state_index++; } + power_state_offset += 2 + power_state->v2.ucNumDPMLevels; } /* if multiple clock modes, mark the lowest as no display */ for (i = 0; i < state_index; i++) { @@ -2610,13 +2643,15 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) default: break; } - } else { + } + + if (state_index == 0) { rdev->pm.power_state = malloc(sizeof(struct radeon_power_state), - DRM_MEM_DRIVER, M_WAITOK | M_ZERO); + DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); if (rdev->pm.power_state) { rdev->pm.power_state[0].clock_info = malloc(sizeof(struct radeon_pm_clock_info) * 1, - DRM_MEM_DRIVER, M_WAITOK | M_ZERO); + DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); if (rdev->pm.power_state[0].clock_info) { /* add the default mode */ rdev->pm.power_state[state_index].type = diff --git a/sys/dev/drm2/radeon/radeon_atpx_handler.c b/sys/dev/drm2/radeon/radeon_atpx_handler.c deleted file mode 100644 index 4cfd7434cde6..000000000000 --- a/sys/dev/drm2/radeon/radeon_atpx_handler.c +++ /dev/null @@ -1,506 +0,0 @@ -/* - * Copyright (c) 2010 Red Hat Inc. - * Author : Dave Airlie <airlied@redhat.com> - * - * Licensed under GPLv2 - * - * ATPX support for both Intel/ATI - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/bus.h> -#include <sys/linker.h> - -#include <contrib/dev/acpica/include/acpi.h> -#include <dev/acpica/acpivar.h> - -#include <dev/drm2/drmP.h> -#include <dev/drm2/radeon/radeon_drm.h> -#include "radeon_acpi.h" -#include "radeon_drv.h" - -#ifdef DUMBBELL_WIP -struct radeon_atpx_functions { - bool px_params; - bool power_cntl; - bool disp_mux_cntl; - bool i2c_mux_cntl; - bool switch_start; - bool switch_end; - bool disp_connectors_mapping; - bool disp_detetion_ports; -}; - -struct radeon_atpx { - ACPI_HANDLE handle; - struct radeon_atpx_functions functions; -}; - -static struct radeon_atpx_priv { - bool atpx_detected; - /* handle for device - and atpx */ - ACPI_HANDLE dhandle; - struct radeon_atpx atpx; -} radeon_atpx_priv; - -struct atpx_verify_interface { - u16 size; /* structure size in bytes (includes size field) */ - u16 version; /* version */ - u32 function_bits; /* supported functions bit vector */ -} __packed; - -struct atpx_power_control { - u16 size; - u8 dgpu_state; -} __packed; - -struct atpx_mux { - u16 size; - u16 mux; -} __packed; - -/** - * radeon_atpx_call - call an ATPX method - * - * @handle: acpi handle - * @function: the ATPX function to execute - * @params: ATPX function params - * - * Executes the requested ATPX function (all asics). - * Returns a pointer to the acpi output buffer. - */ -static ACPI_OBJECT *radeon_atpx_call(ACPI_HANDLE handle, int function, - ACPI_BUFFER *params) -{ - ACPI_STATUS status; - ACPI_OBJECT atpx_arg_elements[2]; - ACPI_OBJECT_LIST atpx_arg; - ACPI_BUFFER buffer = { ACPI_ALLOCATE_BUFFER, NULL }; - - atpx_arg.Count = 2; - atpx_arg.Pointer = &atpx_arg_elements[0]; - - atpx_arg_elements[0].Type = ACPI_TYPE_INTEGER; - atpx_arg_elements[0].Integer.Value = function; - - if (params) { - atpx_arg_elements[1].Type = ACPI_TYPE_BUFFER; - atpx_arg_elements[1].Buffer.Length = params->Length; - atpx_arg_elements[1].Buffer.Pointer = params->Pointer; - } else { - /* We need a second fake parameter */ - atpx_arg_elements[1].Type = ACPI_TYPE_INTEGER; - atpx_arg_elements[1].Integer.Value = 0; - } - - status = AcpiEvaluateObject(handle, NULL, &atpx_arg, &buffer); - - /* Fail only if calling the method fails and ATPX is supported */ - if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { - DRM_ERROR("failed to evaluate ATPX got %s\n", - AcpiFormatException(status)); - AcpiOsFree(buffer.Pointer); - return NULL; - } - - return buffer.Pointer; -} - -/** - * radeon_atpx_parse_functions - parse supported functions - * - * @f: supported functions struct - * @mask: supported functions mask from ATPX - * - * Use the supported functions mask from ATPX function - * ATPX_FUNCTION_VERIFY_INTERFACE to determine what functions - * are supported (all asics). - */ -static void radeon_atpx_parse_functions(struct radeon_atpx_functions *f, u32 mask) -{ - f->px_params = mask & ATPX_GET_PX_PARAMETERS_SUPPORTED; - f->power_cntl = mask & ATPX_POWER_CONTROL_SUPPORTED; - f->disp_mux_cntl = mask & ATPX_DISPLAY_MUX_CONTROL_SUPPORTED; - f->i2c_mux_cntl = mask & ATPX_I2C_MUX_CONTROL_SUPPORTED; - f->switch_start = mask & ATPX_GRAPHICS_DEVICE_SWITCH_START_NOTIFICATION_SUPPORTED; - f->switch_end = mask & ATPX_GRAPHICS_DEVICE_SWITCH_END_NOTIFICATION_SUPPORTED; - f->disp_connectors_mapping = mask & ATPX_GET_DISPLAY_CONNECTORS_MAPPING_SUPPORTED; - f->disp_detetion_ports = mask & ATPX_GET_DISPLAY_DETECTION_PORTS_SUPPORTED; -} - -/** - * radeon_atpx_verify_interface - verify ATPX - * - * @handle: acpi handle - * @atpx: radeon atpx struct - * - * Execute the ATPX_FUNCTION_VERIFY_INTERFACE ATPX function - * to initialize ATPX and determine what features are supported - * (all asics). - * returns 0 on success, error on failure. - */ -static int radeon_atpx_verify_interface(struct radeon_atpx *atpx) -{ - ACPI_OBJECT *info; - struct atpx_verify_interface output; - size_t size; - int err = 0; - - info = radeon_atpx_call(atpx->handle, ATPX_FUNCTION_VERIFY_INTERFACE, NULL); - if (!info) - return -EIO; - - memset(&output, 0, sizeof(output)); - - size = *(u16 *) info->Buffer.Pointer; - if (size < 8) { - DRM_ERROR("ATPX buffer is too small: %zu\n", size); - err = -EINVAL; - goto out; - } - size = min(sizeof(output), size); - - memcpy(&output, info->Buffer.Pointer, size); - - /* TODO: check version? */ - DRM_INFO("ATPX version %u\n", output.version); - - radeon_atpx_parse_functions(&atpx->functions, output.function_bits); - -out: - AcpiOsFree(info); - return err; -} - -/** - * radeon_atpx_set_discrete_state - power up/down discrete GPU - * - * @atpx: atpx info struct - * @state: discrete GPU state (0 = power down, 1 = power up) - * - * Execute the ATPX_FUNCTION_POWER_CONTROL ATPX function to - * power down/up the discrete GPU (all asics). - * Returns 0 on success, error on failure. - */ -static int radeon_atpx_set_discrete_state(struct radeon_atpx *atpx, u8 state) -{ - ACPI_BUFFER params; - ACPI_OBJECT *info; - struct atpx_power_control input; - - if (atpx->functions.power_cntl) { - input.size = 3; - input.dgpu_state = state; - params.Length = input.size; - params.Pointer = &input; - info = radeon_atpx_call(atpx->handle, - ATPX_FUNCTION_POWER_CONTROL, - ¶ms); - if (!info) - return -EIO; - AcpiOsFree(info); - } - return 0; -} - -/** - * radeon_atpx_switch_disp_mux - switch display mux - * - * @atpx: atpx info struct - * @mux_id: mux state (0 = integrated GPU, 1 = discrete GPU) - * - * Execute the ATPX_FUNCTION_DISPLAY_MUX_CONTROL ATPX function to - * switch the display mux between the discrete GPU and integrated GPU - * (all asics). - * Returns 0 on success, error on failure. - */ -static int radeon_atpx_switch_disp_mux(struct radeon_atpx *atpx, u16 mux_id) -{ - ACPI_BUFFER params; - ACPI_OBJECT *info; - struct atpx_mux input; - - if (atpx->functions.disp_mux_cntl) { - input.size = 4; - input.mux = mux_id; - params.Length = input.size; - params.Pointer = &input; - info = radeon_atpx_call(atpx->handle, - ATPX_FUNCTION_DISPLAY_MUX_CONTROL, - ¶ms); - if (!info) - return -EIO; - AcpiOsFree(info); - } - return 0; -} - -/** - * radeon_atpx_switch_i2c_mux - switch i2c/hpd mux - * - * @atpx: atpx info struct - * @mux_id: mux state (0 = integrated GPU, 1 = discrete GPU) - * - * Execute the ATPX_FUNCTION_I2C_MUX_CONTROL ATPX function to - * switch the i2c/hpd mux between the discrete GPU and integrated GPU - * (all asics). - * Returns 0 on success, error on failure. - */ -static int radeon_atpx_switch_i2c_mux(struct radeon_atpx *atpx, u16 mux_id) -{ - ACPI_BUFFER params; - ACPI_OBJECT *info; - struct atpx_mux input; - - if (atpx->functions.i2c_mux_cntl) { - input.size = 4; - input.mux = mux_id; - params.Length = input.size; - params.Pointer = &input; - info = radeon_atpx_call(atpx->handle, - ATPX_FUNCTION_I2C_MUX_CONTROL, - ¶ms); - if (!info) - return -EIO; - AcpiOsFree(info); - } - return 0; -} - -/** - * radeon_atpx_switch_start - notify the sbios of a GPU switch - * - * @atpx: atpx info struct - * @mux_id: mux state (0 = integrated GPU, 1 = discrete GPU) - * - * Execute the ATPX_FUNCTION_GRAPHICS_DEVICE_SWITCH_START_NOTIFICATION ATPX - * function to notify the sbios that a switch between the discrete GPU and - * integrated GPU has begun (all asics). - * Returns 0 on success, error on failure. - */ -static int radeon_atpx_switch_start(struct radeon_atpx *atpx, u16 mux_id) -{ - ACPI_BUFFER params; - ACPI_OBJECT *info; - struct atpx_mux input; - - if (atpx->functions.switch_start) { - input.size = 4; - input.mux = mux_id; - params.Length = input.size; - params.Pointer = &input; - info = radeon_atpx_call(atpx->handle, - ATPX_FUNCTION_GRAPHICS_DEVICE_SWITCH_START_NOTIFICATION, - ¶ms); - if (!info) - return -EIO; - AcpiOsFree(info); - } - return 0; -} - -/** - * radeon_atpx_switch_end - notify the sbios of a GPU switch - * - * @atpx: atpx info struct - * @mux_id: mux state (0 = integrated GPU, 1 = discrete GPU) - * - * Execute the ATPX_FUNCTION_GRAPHICS_DEVICE_SWITCH_END_NOTIFICATION ATPX - * function to notify the sbios that a switch between the discrete GPU and - * integrated GPU has ended (all asics). - * Returns 0 on success, error on failure. - */ -static int radeon_atpx_switch_end(struct radeon_atpx *atpx, u16 mux_id) -{ - ACPI_BUFFER params; - ACPI_OBJECT *info; - struct atpx_mux input; - - if (atpx->functions.switch_end) { - input.size = 4; - input.mux = mux_id; - params.Length = input.size; - params.Pointer = &input; - info = radeon_atpx_call(atpx->handle, - ATPX_FUNCTION_GRAPHICS_DEVICE_SWITCH_END_NOTIFICATION, - ¶ms); - if (!info) - return -EIO; - AcpiOsFree(info); - } - return 0; -} - -/** - * radeon_atpx_switchto - switch to the requested GPU - * - * @id: GPU to switch to - * - * Execute the necessary ATPX functions to switch between the discrete GPU and - * integrated GPU (all asics). - * Returns 0 on success, error on failure. - */ -static int radeon_atpx_switchto(enum vga_switcheroo_client_id id) -{ - u16 gpu_id; - - if (id == VGA_SWITCHEROO_IGD) - gpu_id = ATPX_INTEGRATED_GPU; - else - gpu_id = ATPX_DISCRETE_GPU; - - radeon_atpx_switch_start(&radeon_atpx_priv.atpx, gpu_id); - radeon_atpx_switch_disp_mux(&radeon_atpx_priv.atpx, gpu_id); - radeon_atpx_switch_i2c_mux(&radeon_atpx_priv.atpx, gpu_id); - radeon_atpx_switch_end(&radeon_atpx_priv.atpx, gpu_id); - - return 0; -} - -/** - * radeon_atpx_power_state - power down/up the requested GPU - * - * @id: GPU to power down/up - * @state: requested power state (0 = off, 1 = on) - * - * Execute the necessary ATPX function to power down/up the discrete GPU - * (all asics). - * Returns 0 on success, error on failure. - */ -static int radeon_atpx_power_state(enum vga_switcheroo_client_id id, - enum vga_switcheroo_state state) -{ - /* on w500 ACPI can't change intel gpu state */ - if (id == VGA_SWITCHEROO_IGD) - return 0; - - radeon_atpx_set_discrete_state(&radeon_atpx_priv.atpx, state); - return 0; -} - -/** - * radeon_atpx_pci_probe_handle - look up the ATPX handle - * - * @pdev: pci device - * - * Look up the ATPX handles (all asics). - * Returns true if the handles are found, false if not. - */ -static bool radeon_atpx_pci_probe_handle(struct pci_dev *pdev) -{ - ACPI_HANDLE dhandle, atpx_handle; - ACPI_STATUS status; - - dhandle = DEVICE_ACPI_HANDLE(&pdev->dev); - if (!dhandle) - return false; - - status = AcpiGetHandle(dhandle, "ATPX", &atpx_handle); - if (ACPI_FAILURE(status)) - return false; - - radeon_atpx_priv.dhandle = dhandle; - radeon_atpx_priv.atpx.handle = atpx_handle; - return true; -} - -/** - * radeon_atpx_init - verify the ATPX interface - * - * Verify the ATPX interface (all asics). - * Returns 0 on success, error on failure. - */ -static int radeon_atpx_init(void) -{ - /* set up the ATPX handle */ - return radeon_atpx_verify_interface(&radeon_atpx_priv.atpx); -} - -/** - * radeon_atpx_get_client_id - get the client id - * - * @pdev: pci device - * - * look up whether we are the integrated or discrete GPU (all asics). - * Returns the client id. - */ -static int radeon_atpx_get_client_id(struct pci_dev *pdev) -{ - if (radeon_atpx_priv.dhandle == DEVICE_ACPI_HANDLE(&pdev->dev)) - return VGA_SWITCHEROO_IGD; - else - return VGA_SWITCHEROO_DIS; -} - -static struct vga_switcheroo_handler radeon_atpx_handler = { - .switchto = radeon_atpx_switchto, - .power_state = radeon_atpx_power_state, - .init = radeon_atpx_init, - .get_client_id = radeon_atpx_get_client_id, -}; - -/** - * radeon_atpx_detect - detect whether we have PX - * - * Check if we have a PX system (all asics). - * Returns true if we have a PX system, false if not. - */ -static bool radeon_atpx_detect(void) -{ - char acpi_method_name[255] = { 0 }; - ACPI_BUFFER buffer = {sizeof(acpi_method_name), acpi_method_name}; - struct pci_dev *pdev = NULL; - bool has_atpx = false; - int vga_count = 0; - - while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) { - vga_count++; - - has_atpx |= (radeon_atpx_pci_probe_handle(pdev) == true); - } - - if (has_atpx && vga_count == 2) { - AcpiGetName(radeon_atpx_priv.atpx.handle, ACPI_FULL_PATHNAME, &buffer); - DRM_INFO("VGA switcheroo: detected switching method %s handle\n", - acpi_method_name); - radeon_atpx_priv.atpx_detected = true; - return true; - } - return false; -} -#endif /* DUMBBELL_WIP */ - -/** - * radeon_register_atpx_handler - register with vga_switcheroo - * - * Register the PX callbacks with vga_switcheroo (all asics). - */ -void radeon_register_atpx_handler(void) -{ -#ifdef DUMBBELL_WIP - bool r; - - /* detect if we have any ATPX + 2 VGA in the system */ - r = radeon_atpx_detect(); - if (!r) - return; - - vga_switcheroo_register_handler(&radeon_atpx_handler); -#endif /* DUMBBELL_WIP */ -} - -/** - * radeon_unregister_atpx_handler - unregister with vga_switcheroo - * - * Unregister the PX callbacks with vga_switcheroo (all asics). - */ -void radeon_unregister_atpx_handler(void) -{ -#ifdef DUMBBELL_WIP - vga_switcheroo_unregister_handler(); -#endif /* DUMBBELL_WIP */ -} diff --git a/sys/dev/drm2/radeon/radeon_benchmark.c b/sys/dev/drm2/radeon/radeon_benchmark.c index ce39748ecff4..a90ebf6bc036 100644 --- a/sys/dev/drm2/radeon/radeon_benchmark.c +++ b/sys/dev/drm2/radeon/radeon_benchmark.c @@ -139,13 +139,15 @@ static void radeon_benchmark_move(struct radeon_device *rdev, unsigned size, sdomain, ddomain, "dma"); } - time = radeon_benchmark_do_move(rdev, size, saddr, daddr, - RADEON_BENCHMARK_COPY_BLIT, n); - if (time < 0) - goto out_cleanup; - if (time > 0) - radeon_benchmark_log_results(n, size, time, - sdomain, ddomain, "blit"); + if (rdev->asic->copy.blit) { + time = radeon_benchmark_do_move(rdev, size, saddr, daddr, + RADEON_BENCHMARK_COPY_BLIT, n); + if (time < 0) + goto out_cleanup; + if (time > 0) + radeon_benchmark_log_results(n, size, time, + sdomain, ddomain, "blit"); + } out_cleanup: if (sobj) { diff --git a/sys/dev/drm2/radeon/radeon_bios.c b/sys/dev/drm2/radeon/radeon_bios.c index ee48268469e9..ffb37561ff51 100644 --- a/sys/dev/drm2/radeon/radeon_bios.c +++ b/sys/dev/drm2/radeon/radeon_bios.c @@ -46,7 +46,7 @@ __FBSDID("$FreeBSD$"); */ static bool igp_read_bios_from_vram(struct radeon_device *rdev) { - drm_local_map_t bios_map; + struct drm_local_map bios_map; uint8_t __iomem *bios; resource_size_t vram_base; resource_size_t size = 256 * 1024; /* ??? */ @@ -70,11 +70,11 @@ static bool igp_read_bios_from_vram(struct radeon_device *rdev) bios_map.flags = 0; bios_map.mtrr = 0; drm_core_ioremap(&bios_map, rdev->ddev); - if (bios_map.virtual == NULL) { + if (bios_map.handle == NULL) { DRM_INFO("%s: failed to ioremap\n", __func__); return false; } - bios = bios_map.virtual; + bios = bios_map.handle; size = bios_map.size; DRM_INFO("%s: Map address: %p (%ju bytes)\n", __func__, bios, (uintmax_t)size); @@ -88,7 +88,7 @@ static bool igp_read_bios_from_vram(struct radeon_device *rdev) drm_core_ioremapfree(&bios_map, rdev->ddev); return false; } - rdev->bios = malloc(size, DRM_MEM_DRIVER, M_WAITOK); + rdev->bios = malloc(size, DRM_MEM_DRIVER, M_NOWAIT); if (rdev->bios == NULL) { drm_core_ioremapfree(&bios_map, rdev->ddev); return false; @@ -125,12 +125,17 @@ static bool radeon_read_bios(struct radeon_device *rdev) vga_pci_unmap_bios(vga_dev, bios); return false; } - rdev->bios = malloc(size, DRM_MEM_DRIVER, M_WAITOK); + rdev->bios = malloc(size, DRM_MEM_DRIVER, M_NOWAIT); + if (rdev->bios == NULL) { + vga_pci_unmap_bios(vga_dev, bios); + return false; + } memcpy(rdev->bios, bios, size); vga_pci_unmap_bios(vga_dev, bios); return true; } +#ifdef CONFIG_ACPI /* ATRM is used to get the BIOS on the discrete cards in * dual-gpu systems. */ @@ -197,9 +202,9 @@ static bool radeon_atrm_get_bios(struct radeon_device *rdev) return false; } -#ifdef DUMBBELL_WIP +#ifdef FREEBSD_WIP while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) { -#endif /* DUMBBELL_WIP */ +#endif /* FREEBSD_WIP */ if ((dev = pci_find_class(PCIC_DISPLAY, PCIS_DISPLAY_VGA)) != NULL) { DRM_INFO("%s: pci_find_class() found: %d:%d:%d:%d, vendor=%04x, device=%04x\n", __func__, @@ -211,10 +216,10 @@ static bool radeon_atrm_get_bios(struct radeon_device *rdev) pci_get_device(dev)); DRM_INFO("%s: Get ACPI device handle\n", __func__); dhandle = acpi_get_handle(dev); -#ifdef DUMBBELL_WIP +#ifdef FREEBSD_WIP if (!dhandle) continue; -#endif /* DUMBBELL_WIP */ +#endif /* FREEBSD_WIP */ if (!dhandle) return false; @@ -222,9 +227,9 @@ static bool radeon_atrm_get_bios(struct radeon_device *rdev) status = AcpiGetHandle(dhandle, "ATRM", &atrm_handle); if (!ACPI_FAILURE(status)) { found = true; -#ifdef DUMBBELL_WIP +#ifdef FREEBSD_WIP break; -#endif /* DUMBBELL_WIP */ +#endif /* FREEBSD_WIP */ } else { DRM_INFO("%s: Failed to get \"ATRM\" handle: %s\n", __func__, AcpiFormatException(status)); @@ -234,7 +239,7 @@ static bool radeon_atrm_get_bios(struct radeon_device *rdev) if (!found) return false; - rdev->bios = malloc(size, DRM_MEM_DRIVER, M_WAITOK); + rdev->bios = malloc(size, DRM_MEM_DRIVER, M_NOWAIT); if (!rdev->bios) { DRM_ERROR("Unable to allocate bios\n"); return false; @@ -262,6 +267,12 @@ static bool radeon_atrm_get_bios(struct radeon_device *rdev) } return true; } +#else +static inline bool radeon_atrm_get_bios(struct radeon_device *rdev) +{ + return false; +} +#endif static bool ni_read_disabled_bios(struct radeon_device *rdev) { @@ -620,6 +631,7 @@ static bool radeon_read_disabled_bios(struct radeon_device *rdev) return legacy_read_disabled_bios(rdev); } +#ifdef CONFIG_ACPI static bool radeon_acpi_vfct_bios(struct radeon_device *rdev) { bool ret = false; @@ -671,13 +683,20 @@ static bool radeon_acpi_vfct_bios(struct radeon_device *rdev) goto out_unmap; } - rdev->bios = malloc(vhdr->ImageLength, DRM_MEM_DRIVER, M_WAITOK); - memcpy(rdev->bios, &vbios->VbiosContent, vhdr->ImageLength); + rdev->bios = malloc(vhdr->ImageLength, DRM_MEM_DRIVER, M_NOWAIT); + if (rdev->bios) + memcpy(rdev->bios, &vbios->VbiosContent, vhdr->ImageLength); ret = !!rdev->bios; out_unmap: return ret; } +#else +static inline bool radeon_acpi_vfct_bios(struct radeon_device *rdev) +{ + return false; +} +#endif bool radeon_get_bios(struct radeon_device *rdev) { diff --git a/sys/dev/drm2/radeon/radeon_clocks.c b/sys/dev/drm2/radeon/radeon_clocks.c index 9ecd18adb949..4bd9f0d9477e 100644 --- a/sys/dev/drm2/radeon/radeon_clocks.c +++ b/sys/dev/drm2/radeon/radeon_clocks.c @@ -405,19 +405,19 @@ void radeon_legacy_set_engine_clock(struct radeon_device *rdev, tmp &= ~RADEON_SCLK_SRC_SEL_MASK; WREG32_PLL(RADEON_SCLK_CNTL, tmp); - DRM_UDELAY(10); + udelay(10); tmp = RREG32_PLL(RADEON_SPLL_CNTL); tmp |= RADEON_SPLL_SLEEP; WREG32_PLL(RADEON_SPLL_CNTL, tmp); - DRM_UDELAY(2); + udelay(2); tmp = RREG32_PLL(RADEON_SPLL_CNTL); tmp |= RADEON_SPLL_RESET; WREG32_PLL(RADEON_SPLL_CNTL, tmp); - DRM_UDELAY(200); + udelay(200); tmp = RREG32_PLL(RADEON_M_SPLL_REF_FB_DIV); tmp &= ~(RADEON_SPLL_FB_DIV_MASK << RADEON_SPLL_FB_DIV_SHIFT); @@ -437,13 +437,13 @@ void radeon_legacy_set_engine_clock(struct radeon_device *rdev, tmp &= ~RADEON_SPLL_SLEEP; WREG32_PLL(RADEON_SPLL_CNTL, tmp); - DRM_UDELAY(2); + udelay(2); tmp = RREG32_PLL(RADEON_SPLL_CNTL); tmp &= ~RADEON_SPLL_RESET; WREG32_PLL(RADEON_SPLL_CNTL, tmp); - DRM_UDELAY(200); + udelay(200); tmp = RREG32_PLL(RADEON_SCLK_CNTL); tmp &= ~RADEON_SCLK_SRC_SEL_MASK; @@ -464,13 +464,13 @@ void radeon_legacy_set_engine_clock(struct radeon_device *rdev, } WREG32_PLL(RADEON_SCLK_CNTL, tmp); - DRM_UDELAY(20); + udelay(20); tmp = RREG32_PLL(RADEON_CLK_PIN_CNTL); tmp |= RADEON_DONT_USE_XTALIN; WREG32_PLL(RADEON_CLK_PIN_CNTL, tmp); - DRM_UDELAY(10); + udelay(10); } void radeon_legacy_set_clock_gating(struct radeon_device *rdev, int enable) @@ -638,7 +638,7 @@ void radeon_legacy_set_clock_gating(struct radeon_device *rdev, int enable) tmp &= ~(R300_SCLK_FORCE_VAP); tmp |= RADEON_SCLK_FORCE_CP; WREG32_PLL(RADEON_SCLK_CNTL, tmp); - DRM_MDELAY(15); + mdelay(15); tmp = RREG32_PLL(R300_SCLK_CNTL2); tmp &= ~(R300_SCLK_FORCE_TCL | @@ -656,12 +656,12 @@ void radeon_legacy_set_clock_gating(struct radeon_device *rdev, int enable) tmp |= (RADEON_ENGIN_DYNCLK_MODE | (0x01 << RADEON_ACTIVE_HILO_LAT_SHIFT)); WREG32_PLL(RADEON_CLK_PWRMGT_CNTL, tmp); - DRM_MDELAY(15); + mdelay(15); tmp = RREG32_PLL(RADEON_CLK_PIN_CNTL); tmp |= RADEON_SCLK_DYN_START_CNTL; WREG32_PLL(RADEON_CLK_PIN_CNTL, tmp); - DRM_MDELAY(15); + mdelay(15); /* When DRI is enabled, setting DYN_STOP_LAT to zero can cause some R200 to lockup randomly, leave them as set by BIOS. @@ -701,7 +701,7 @@ void radeon_legacy_set_clock_gating(struct radeon_device *rdev, int enable) tmp |= RADEON_SCLK_MORE_FORCEON; } WREG32_PLL(RADEON_SCLK_MORE_CNTL, tmp); - DRM_MDELAY(15); + mdelay(15); } /* RV200::A11 A12, RV250::A11 A12 */ @@ -714,7 +714,7 @@ void radeon_legacy_set_clock_gating(struct radeon_device *rdev, int enable) tmp |= RADEON_TCL_BYPASS_DISABLE; WREG32_PLL(RADEON_PLL_PWRMGT_CNTL, tmp); } - DRM_MDELAY(15); + mdelay(15); /*enable dynamic mode for display clocks (PIXCLK and PIX2CLK) */ tmp = RREG32_PLL(RADEON_PIXCLKS_CNTL); @@ -727,14 +727,14 @@ void radeon_legacy_set_clock_gating(struct radeon_device *rdev, int enable) RADEON_PIXCLK_TMDS_ALWAYS_ONb); WREG32_PLL(RADEON_PIXCLKS_CNTL, tmp); - DRM_MDELAY(15); + mdelay(15); tmp = RREG32_PLL(RADEON_VCLK_ECP_CNTL); tmp |= (RADEON_PIXCLK_ALWAYS_ONb | RADEON_PIXCLK_DAC_ALWAYS_ONb); WREG32_PLL(RADEON_VCLK_ECP_CNTL, tmp); - DRM_MDELAY(15); + mdelay(15); } } else { /* Turn everything OFF (ForceON to everything) */ @@ -866,7 +866,7 @@ void radeon_legacy_set_clock_gating(struct radeon_device *rdev, int enable) } WREG32_PLL(RADEON_SCLK_CNTL, tmp); - DRM_MDELAY(16); + mdelay(16); if ((rdev->family == CHIP_R300) || (rdev->family == CHIP_R350)) { @@ -875,7 +875,7 @@ void radeon_legacy_set_clock_gating(struct radeon_device *rdev, int enable) R300_SCLK_FORCE_GA | R300_SCLK_FORCE_CBA); WREG32_PLL(R300_SCLK_CNTL2, tmp); - DRM_MDELAY(16); + mdelay(16); } if (rdev->flags & RADEON_IS_IGP) { @@ -883,7 +883,7 @@ void radeon_legacy_set_clock_gating(struct radeon_device *rdev, int enable) tmp &= ~(RADEON_FORCEON_MCLKA | RADEON_FORCEON_YCLKA); WREG32_PLL(RADEON_MCLK_CNTL, tmp); - DRM_MDELAY(16); + mdelay(16); } if ((rdev->family == CHIP_RV200) || @@ -892,7 +892,7 @@ void radeon_legacy_set_clock_gating(struct radeon_device *rdev, int enable) tmp = RREG32_PLL(RADEON_SCLK_MORE_CNTL); tmp |= RADEON_SCLK_MORE_FORCEON; WREG32_PLL(RADEON_SCLK_MORE_CNTL, tmp); - DRM_MDELAY(16); + mdelay(16); } tmp = RREG32_PLL(RADEON_PIXCLKS_CNTL); @@ -905,7 +905,7 @@ void radeon_legacy_set_clock_gating(struct radeon_device *rdev, int enable) RADEON_PIXCLK_TMDS_ALWAYS_ONb); WREG32_PLL(RADEON_PIXCLKS_CNTL, tmp); - DRM_MDELAY(16); + mdelay(16); tmp = RREG32_PLL(RADEON_VCLK_ECP_CNTL); tmp &= ~(RADEON_PIXCLK_ALWAYS_ONb | diff --git a/sys/dev/drm2/radeon/radeon_combios.c b/sys/dev/drm2/radeon/radeon_combios.c index caa8a0035892..7d0fd61e7b96 100644 --- a/sys/dev/drm2/radeon/radeon_combios.c +++ b/sys/dev/drm2/radeon/radeon_combios.c @@ -41,6 +41,29 @@ __FBSDID("$FreeBSD$"); #include <asm/pci-bridge.h> #endif /* CONFIG_PPC_PMAC */ +#ifdef FREEBSD_WIP /* FreeBSD: to please GCC 4.2. */ +/* from radeon_encoder.c */ +extern uint32_t +radeon_get_encoder_enum(struct drm_device *dev, uint32_t supported_device, + uint8_t dac); +extern void radeon_link_encoder_connector(struct drm_device *dev); + +/* from radeon_connector.c */ +extern void +radeon_add_legacy_connector(struct drm_device *dev, + uint32_t connector_id, + uint32_t supported_device, + int connector_type, + struct radeon_i2c_bus_rec *i2c_bus, + uint16_t connector_object_id, + struct radeon_hpd *hpd); + +/* from radeon_legacy_encoder.c */ +extern void +radeon_add_legacy_encoder(struct drm_device *dev, uint32_t encoder_enum, + uint32_t supported_device); +#endif + /* old legacy ATI BIOS routines */ /* COMBIOS table offsets */ @@ -440,7 +463,7 @@ bool radeon_combios_check_hardcoded_edid(struct radeon_device *rdev) raw = rdev->bios + edid_info; size = EDID_LENGTH * (raw[0x7e] + 1); - edid = malloc(size, DRM_MEM_KMS, M_WAITOK); + edid = malloc(size, DRM_MEM_KMS, M_NOWAIT); if (edid == NULL) return false; @@ -464,7 +487,7 @@ radeon_bios_get_hardcoded_edid(struct radeon_device *rdev) if (rdev->mode_info.bios_hardcoded_edid) { edid = malloc(rdev->mode_info.bios_hardcoded_edid_size, - DRM_MEM_KMS, M_WAITOK); + DRM_MEM_KMS, M_NOWAIT); if (edid) { memcpy((unsigned char *)edid, (unsigned char *)rdev->mode_info.bios_hardcoded_edid, @@ -931,7 +954,7 @@ struct radeon_encoder_primary_dac *radeon_combios_get_primary_dac_info(struct int found = 0; p_dac = malloc(sizeof(struct radeon_encoder_primary_dac), - DRM_MEM_DRIVER, M_WAITOK | M_ZERO); + DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); if (!p_dac) return NULL; @@ -954,6 +977,15 @@ struct radeon_encoder_primary_dac *radeon_combios_get_primary_dac_info(struct found = 1; } + /* quirks */ + /* Radeon 9100 (R200) */ + if ((dev->pci_device == 0x514D) && + (dev->pci_subvendor == 0x174B) && + (dev->pci_subdevice == 0x7149)) { + /* vbios value is bad, use the default */ + found = 0; + } + if (!found) /* fallback to defaults */ radeon_legacy_get_primary_dac_info_from_table(rdev, p_dac); @@ -1067,7 +1099,7 @@ struct radeon_encoder_tv_dac *radeon_combios_get_tv_dac_info(struct int found = 0; tv_dac = malloc(sizeof(struct radeon_encoder_tv_dac), - DRM_MEM_DRIVER, M_WAITOK | M_ZERO); + DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); if (!tv_dac) return NULL; @@ -1156,7 +1188,7 @@ static struct radeon_encoder_lvds *radeon_legacy_get_lvds_info_from_regs(struct uint32_t lvds_ss_gen_cntl = RREG32(RADEON_LVDS_SS_GEN_CNTL); lvds = malloc(sizeof(struct radeon_encoder_lvds), - DRM_MEM_DRIVER, M_WAITOK | M_ZERO); + DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); if (!lvds) return NULL; @@ -1232,7 +1264,7 @@ struct radeon_encoder_lvds *radeon_combios_get_lvds_info(struct radeon_encoder if (lcd_info) { lvds = malloc(sizeof(struct radeon_encoder_lvds), - DRM_MEM_DRIVER, M_WAITOK | M_ZERO); + DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); if (!lvds) return NULL; @@ -2690,15 +2722,15 @@ void radeon_combios_get_power_modes(struct radeon_device *rdev) /* allocate 2 power states */ rdev->pm.power_state = malloc(sizeof(struct radeon_power_state) * 2, - DRM_MEM_DRIVER, M_WAITOK | M_ZERO); + DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); if (rdev->pm.power_state) { /* allocate 1 clock mode per state */ rdev->pm.power_state[0].clock_info = malloc(sizeof(struct radeon_pm_clock_info) * 1, - DRM_MEM_DRIVER, M_WAITOK | M_ZERO); + DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); rdev->pm.power_state[1].clock_info = malloc(sizeof(struct radeon_pm_clock_info) * 1, - DRM_MEM_DRIVER, M_WAITOK | M_ZERO); + DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); if (!rdev->pm.power_state[0].clock_info || !rdev->pm.power_state[1].clock_info) goto pm_failed; @@ -2743,13 +2775,13 @@ void radeon_combios_get_power_modes(struct radeon_device *rdev) i2c_bus = combios_setup_i2c_bus(rdev, gpio, 0, 0); rdev->pm.i2c_bus = radeon_i2c_lookup(rdev, &i2c_bus); if (rdev->pm.i2c_bus) { -#ifdef DUMBBELL_WIP +#ifdef FREEBSD_WIP struct i2c_board_info info = { }; const char *name = thermal_controller_names[thermal_controller]; info.addr = i2c_addr >> 1; strlcpy(info.type, name, sizeof(info.type)); i2c_new_device(&rdev->pm.i2c_bus->adapter, &info); -#endif /* DUMBBELL_WIP */ +#endif /* FREEBSD_WIP */ } } } else { @@ -2762,7 +2794,7 @@ void radeon_combios_get_power_modes(struct radeon_device *rdev) i2c_bus = combios_setup_i2c_bus(rdev, DDC_MONID, 0, 0); rdev->pm.i2c_bus = radeon_i2c_lookup(rdev, &i2c_bus); if (rdev->pm.i2c_bus) { -#ifdef DUMBBELL_WIP +#ifdef FREEBSD_WIP struct i2c_board_info info = { }; const char *name = "f75375"; info.addr = 0x28; @@ -2770,7 +2802,7 @@ void radeon_combios_get_power_modes(struct radeon_device *rdev) i2c_new_device(&rdev->pm.i2c_bus->adapter, &info); DRM_INFO("Possible %s thermal controller at 0x%02x\n", name, info.addr); -#endif /* DUMBBELL_WIP */ +#endif /* FREEBSD_WIP */ } } } @@ -2974,12 +3006,12 @@ bool radeon_combios_external_tmds_setup(struct drm_encoder *encoder) case 3: val = RBIOS16(index); index += 2; - DRM_UDELAY(val); + udelay(val); break; case 4: val = RBIOS16(index); index += 2; - DRM_MDELAY(val); + mdelay(val); break; case 6: slave_addr = id & 0xff; @@ -3028,7 +3060,7 @@ bool radeon_combios_external_tmds_setup(struct drm_encoder *encoder) case 4: val = RBIOS16(index); index += 2; - DRM_UDELAY(val); + udelay(val); break; case 5: reg = id & 0x1fff; @@ -3106,7 +3138,7 @@ static void combios_parse_mmio_table(struct drm_device *dev, uint16_t offset) case 4: val = RBIOS16(offset); offset += 2; - DRM_UDELAY(val); + udelay(val); break; case 5: val = RBIOS16(offset); @@ -3175,10 +3207,10 @@ static void combios_parse_pll_table(struct drm_device *dev, uint16_t offset) tmp = 1000; switch (addr) { case 1: - DRM_UDELAY(150); + udelay(150); break; case 2: - DRM_MDELAY(1); + mdelay(1); break; case 3: while (tmp--) { @@ -3209,13 +3241,13 @@ static void combios_parse_pll_table(struct drm_device *dev, uint16_t offset) /*mclk_cntl |= 0x00001111;*//* ??? */ WREG32_PLL(RADEON_MCLK_CNTL, mclk_cntl); - DRM_MDELAY(10); + mdelay(10); #endif WREG32_PLL (RADEON_CLK_PWRMGT_CNTL, tmp & ~RADEON_CG_NO1_DEBUG_0); - DRM_MDELAY(10); + mdelay(10); } break; default: diff --git a/sys/dev/drm2/radeon/radeon_connectors.c b/sys/dev/drm2/radeon/radeon_connectors.c index d303dfa47bc2..8c553250a068 100644 --- a/sys/dev/drm2/radeon/radeon_connectors.c +++ b/sys/dev/drm2/radeon/radeon_connectors.c @@ -35,6 +35,17 @@ __FBSDID("$FreeBSD$"); #include "radeon.h" #include "atom.h" +#ifdef FREEBSD_WIP /* FreeBSD: to please GCC 4.2. */ +extern void +radeon_combios_connected_scratch_regs(struct drm_connector *connector, + struct drm_encoder *encoder, + bool connected); +extern void +radeon_atombios_connected_scratch_regs(struct drm_connector *connector, + struct drm_encoder *encoder, + bool connected); +#endif + void radeon_connector_hotplug(struct drm_connector *connector) { struct drm_device *dev = connector->dev; @@ -641,9 +652,9 @@ static void radeon_connector_destroy(struct drm_connector *connector) if (radeon_connector->edid) free(radeon_connector->edid, DRM_MEM_KMS); free(radeon_connector->con_priv, DRM_MEM_DRIVER); -#ifdef DUMBBELL_WIP +#ifdef FREEBSD_WIP drm_sysfs_connector_remove(connector); -#endif /* DUMBBELL_WIP */ +#endif /* FREEBSD_WIP */ drm_connector_cleanup(connector); free(connector, DRM_MEM_DRIVER); } @@ -1211,9 +1222,9 @@ static void radeon_dp_connector_destroy(struct drm_connector *connector) if (radeon_dig_connector->dp_i2c_bus) radeon_i2c_destroy(radeon_dig_connector->dp_i2c_bus); free(radeon_connector->con_priv, DRM_MEM_DRIVER); -#ifdef DUMBBELL_WIP +#ifdef FREEBSD_WIP drm_sysfs_connector_remove(connector); -#endif /* DUMBBELL_WIP */ +#endif /* FREEBSD_WIP */ drm_connector_cleanup(connector); free(connector, DRM_MEM_DRIVER); } @@ -1555,7 +1566,7 @@ radeon_add_atom_connector(struct drm_device *dev, } radeon_connector = malloc(sizeof(struct radeon_connector), - DRM_MEM_DRIVER, M_ZERO | M_WAITOK); + DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); if (!radeon_connector) return; @@ -1577,7 +1588,7 @@ radeon_add_atom_connector(struct drm_device *dev, if (is_dp_bridge) { radeon_dig_connector = malloc( sizeof(struct radeon_connector_atom_dig), - DRM_MEM_DRIVER, M_ZERO | M_WAITOK); + DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); if (!radeon_dig_connector) goto failed; radeon_dig_connector->igp_lane_info = igp_lane_info; @@ -1603,7 +1614,7 @@ radeon_add_atom_connector(struct drm_device *dev, connector->interlace_allowed = true; connector->doublescan_allowed = true; radeon_connector->dac_load_detect = true; - drm_connector_attach_property(&radeon_connector->base, + drm_object_attach_property(&radeon_connector->base.base, rdev->mode_info.load_detect_property, 1); break; @@ -1612,13 +1623,13 @@ radeon_add_atom_connector(struct drm_device *dev, case DRM_MODE_CONNECTOR_HDMIA: case DRM_MODE_CONNECTOR_HDMIB: case DRM_MODE_CONNECTOR_DisplayPort: - drm_connector_attach_property(&radeon_connector->base, + drm_object_attach_property(&radeon_connector->base.base, rdev->mode_info.underscan_property, UNDERSCAN_OFF); - drm_connector_attach_property(&radeon_connector->base, + drm_object_attach_property(&radeon_connector->base.base, rdev->mode_info.underscan_hborder_property, 0); - drm_connector_attach_property(&radeon_connector->base, + drm_object_attach_property(&radeon_connector->base.base, rdev->mode_info.underscan_vborder_property, 0); subpixel_order = SubPixelHorizontalRGB; @@ -1629,14 +1640,14 @@ radeon_add_atom_connector(struct drm_device *dev, connector->doublescan_allowed = false; if (connector_type == DRM_MODE_CONNECTOR_DVII) { radeon_connector->dac_load_detect = true; - drm_connector_attach_property(&radeon_connector->base, + drm_object_attach_property(&radeon_connector->base.base, rdev->mode_info.load_detect_property, 1); } break; case DRM_MODE_CONNECTOR_LVDS: case DRM_MODE_CONNECTOR_eDP: - drm_connector_attach_property(&radeon_connector->base, + drm_object_attach_property(&radeon_connector->base.base, dev->mode_config.scaling_mode_property, DRM_MODE_SCALE_FULLSCREEN); subpixel_order = SubPixelHorizontalRGB; @@ -1655,7 +1666,7 @@ radeon_add_atom_connector(struct drm_device *dev, DRM_ERROR("VGA: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); } radeon_connector->dac_load_detect = true; - drm_connector_attach_property(&radeon_connector->base, + drm_object_attach_property(&radeon_connector->base.base, rdev->mode_info.load_detect_property, 1); /* no HPD on analog connectors */ @@ -1673,7 +1684,7 @@ radeon_add_atom_connector(struct drm_device *dev, DRM_ERROR("DVIA: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); } radeon_connector->dac_load_detect = true; - drm_connector_attach_property(&radeon_connector->base, + drm_object_attach_property(&radeon_connector->base.base, rdev->mode_info.load_detect_property, 1); /* no HPD on analog connectors */ @@ -1685,7 +1696,7 @@ radeon_add_atom_connector(struct drm_device *dev, case DRM_MODE_CONNECTOR_DVID: radeon_dig_connector = malloc( sizeof(struct radeon_connector_atom_dig), - DRM_MEM_DRIVER, M_ZERO | M_WAITOK); + DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); if (!radeon_dig_connector) goto failed; radeon_dig_connector->igp_lane_info = igp_lane_info; @@ -1698,23 +1709,23 @@ radeon_add_atom_connector(struct drm_device *dev, DRM_ERROR("DVI: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); } subpixel_order = SubPixelHorizontalRGB; - drm_connector_attach_property(&radeon_connector->base, + drm_object_attach_property(&radeon_connector->base.base, rdev->mode_info.coherent_mode_property, 1); if (ASIC_IS_AVIVO(rdev)) { - drm_connector_attach_property(&radeon_connector->base, + drm_object_attach_property(&radeon_connector->base.base, rdev->mode_info.underscan_property, UNDERSCAN_OFF); - drm_connector_attach_property(&radeon_connector->base, + drm_object_attach_property(&radeon_connector->base.base, rdev->mode_info.underscan_hborder_property, 0); - drm_connector_attach_property(&radeon_connector->base, + drm_object_attach_property(&radeon_connector->base.base, rdev->mode_info.underscan_vborder_property, 0); } if (connector_type == DRM_MODE_CONNECTOR_DVII) { radeon_connector->dac_load_detect = true; - drm_connector_attach_property(&radeon_connector->base, + drm_object_attach_property(&radeon_connector->base.base, rdev->mode_info.load_detect_property, 1); } @@ -1728,7 +1739,7 @@ radeon_add_atom_connector(struct drm_device *dev, case DRM_MODE_CONNECTOR_HDMIB: radeon_dig_connector = malloc( sizeof(struct radeon_connector_atom_dig), - DRM_MEM_DRIVER, M_ZERO | M_WAITOK); + DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); if (!radeon_dig_connector) goto failed; radeon_dig_connector->igp_lane_info = igp_lane_info; @@ -1740,17 +1751,17 @@ radeon_add_atom_connector(struct drm_device *dev, if (!radeon_connector->ddc_bus) DRM_ERROR("HDMI: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); } - drm_connector_attach_property(&radeon_connector->base, + drm_object_attach_property(&radeon_connector->base.base, rdev->mode_info.coherent_mode_property, 1); if (ASIC_IS_AVIVO(rdev)) { - drm_connector_attach_property(&radeon_connector->base, + drm_object_attach_property(&radeon_connector->base.base, rdev->mode_info.underscan_property, UNDERSCAN_OFF); - drm_connector_attach_property(&radeon_connector->base, + drm_object_attach_property(&radeon_connector->base.base, rdev->mode_info.underscan_hborder_property, 0); - drm_connector_attach_property(&radeon_connector->base, + drm_object_attach_property(&radeon_connector->base.base, rdev->mode_info.underscan_vborder_property, 0); } @@ -1764,7 +1775,7 @@ radeon_add_atom_connector(struct drm_device *dev, case DRM_MODE_CONNECTOR_DisplayPort: radeon_dig_connector = malloc( sizeof(struct radeon_connector_atom_dig), - DRM_MEM_DRIVER, M_ZERO | M_WAITOK); + DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); if (!radeon_dig_connector) goto failed; radeon_dig_connector->igp_lane_info = igp_lane_info; @@ -1781,17 +1792,17 @@ radeon_add_atom_connector(struct drm_device *dev, DRM_ERROR("DP: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); } subpixel_order = SubPixelHorizontalRGB; - drm_connector_attach_property(&radeon_connector->base, + drm_object_attach_property(&radeon_connector->base.base, rdev->mode_info.coherent_mode_property, 1); if (ASIC_IS_AVIVO(rdev)) { - drm_connector_attach_property(&radeon_connector->base, + drm_object_attach_property(&radeon_connector->base.base, rdev->mode_info.underscan_property, UNDERSCAN_OFF); - drm_connector_attach_property(&radeon_connector->base, + drm_object_attach_property(&radeon_connector->base.base, rdev->mode_info.underscan_hborder_property, 0); - drm_connector_attach_property(&radeon_connector->base, + drm_object_attach_property(&radeon_connector->base.base, rdev->mode_info.underscan_vborder_property, 0); } @@ -1802,7 +1813,7 @@ radeon_add_atom_connector(struct drm_device *dev, case DRM_MODE_CONNECTOR_eDP: radeon_dig_connector = malloc( sizeof(struct radeon_connector_atom_dig), - DRM_MEM_DRIVER, M_ZERO | M_WAITOK); + DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); if (!radeon_dig_connector) goto failed; radeon_dig_connector->igp_lane_info = igp_lane_info; @@ -1818,7 +1829,7 @@ radeon_add_atom_connector(struct drm_device *dev, if (!radeon_connector->ddc_bus) DRM_ERROR("DP: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); } - drm_connector_attach_property(&radeon_connector->base, + drm_object_attach_property(&radeon_connector->base.base, dev->mode_config.scaling_mode_property, DRM_MODE_SCALE_FULLSCREEN); subpixel_order = SubPixelHorizontalRGB; @@ -1831,10 +1842,10 @@ radeon_add_atom_connector(struct drm_device *dev, drm_connector_init(dev, &radeon_connector->base, &radeon_tv_connector_funcs, connector_type); drm_connector_helper_add(&radeon_connector->base, &radeon_tv_connector_helper_funcs); radeon_connector->dac_load_detect = true; - drm_connector_attach_property(&radeon_connector->base, + drm_object_attach_property(&radeon_connector->base.base, rdev->mode_info.load_detect_property, 1); - drm_connector_attach_property(&radeon_connector->base, + drm_object_attach_property(&radeon_connector->base.base, rdev->mode_info.tv_std_property, radeon_atombios_get_tv_info(rdev)); /* no HPD on analog connectors */ @@ -1845,7 +1856,7 @@ radeon_add_atom_connector(struct drm_device *dev, case DRM_MODE_CONNECTOR_LVDS: radeon_dig_connector = malloc( sizeof(struct radeon_connector_atom_dig), - DRM_MEM_DRIVER, M_ZERO | M_WAITOK); + DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); if (!radeon_dig_connector) goto failed; radeon_dig_connector->igp_lane_info = igp_lane_info; @@ -1857,7 +1868,7 @@ radeon_add_atom_connector(struct drm_device *dev, if (!radeon_connector->ddc_bus) DRM_ERROR("LVDS: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); } - drm_connector_attach_property(&radeon_connector->base, + drm_object_attach_property(&radeon_connector->base.base, dev->mode_config.scaling_mode_property, DRM_MODE_SCALE_FULLSCREEN); subpixel_order = SubPixelHorizontalRGB; @@ -1874,9 +1885,9 @@ radeon_add_atom_connector(struct drm_device *dev, connector->polled = DRM_CONNECTOR_POLL_HPD; connector->display_info.subpixel_order = subpixel_order; -#ifdef DUMBBELL_WIP +#ifdef FREEBSD_WIP drm_sysfs_connector_add(connector); -#endif /* DUMBBELL_WIP */ +#endif /* FREEBSD_WIP */ return; failed: @@ -1918,7 +1929,7 @@ radeon_add_legacy_connector(struct drm_device *dev, } radeon_connector = malloc(sizeof(struct radeon_connector), - DRM_MEM_DRIVER, M_ZERO | M_WAITOK); + DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); if (!radeon_connector) return; @@ -1939,7 +1950,7 @@ radeon_add_legacy_connector(struct drm_device *dev, DRM_ERROR("VGA: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); } radeon_connector->dac_load_detect = true; - drm_connector_attach_property(&radeon_connector->base, + drm_object_attach_property(&radeon_connector->base.base, rdev->mode_info.load_detect_property, 1); /* no HPD on analog connectors */ @@ -1957,7 +1968,7 @@ radeon_add_legacy_connector(struct drm_device *dev, DRM_ERROR("DVIA: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); } radeon_connector->dac_load_detect = true; - drm_connector_attach_property(&radeon_connector->base, + drm_object_attach_property(&radeon_connector->base.base, rdev->mode_info.load_detect_property, 1); /* no HPD on analog connectors */ @@ -1976,7 +1987,7 @@ radeon_add_legacy_connector(struct drm_device *dev, } if (connector_type == DRM_MODE_CONNECTOR_DVII) { radeon_connector->dac_load_detect = true; - drm_connector_attach_property(&radeon_connector->base, + drm_object_attach_property(&radeon_connector->base.base, rdev->mode_info.load_detect_property, 1); } @@ -2000,10 +2011,10 @@ radeon_add_legacy_connector(struct drm_device *dev, */ if (rdev->family == CHIP_RS400 || rdev->family == CHIP_RS480) radeon_connector->dac_load_detect = false; - drm_connector_attach_property(&radeon_connector->base, + drm_object_attach_property(&radeon_connector->base.base, rdev->mode_info.load_detect_property, radeon_connector->dac_load_detect); - drm_connector_attach_property(&radeon_connector->base, + drm_object_attach_property(&radeon_connector->base.base, rdev->mode_info.tv_std_property, radeon_combios_get_tv_info(rdev)); /* no HPD on analog connectors */ @@ -2019,7 +2030,7 @@ radeon_add_legacy_connector(struct drm_device *dev, if (!radeon_connector->ddc_bus) DRM_ERROR("LVDS: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); } - drm_connector_attach_property(&radeon_connector->base, + drm_object_attach_property(&radeon_connector->base.base, dev->mode_config.scaling_mode_property, DRM_MODE_SCALE_FULLSCREEN); subpixel_order = SubPixelHorizontalRGB; @@ -2034,7 +2045,7 @@ radeon_add_legacy_connector(struct drm_device *dev, } else connector->polled = DRM_CONNECTOR_POLL_HPD; connector->display_info.subpixel_order = subpixel_order; -#ifdef DUMBBELL_WIP +#ifdef FREEBSD_WIP drm_sysfs_connector_add(connector); -#endif /* DUMBBELL_WIP */ +#endif /* FREEBSD_WIP */ } diff --git a/sys/dev/drm2/radeon/radeon_cp.c b/sys/dev/drm2/radeon/radeon_cp.c index 4ec2773fd08f..e53c6d0f67b1 100644 --- a/sys/dev/drm2/radeon/radeon_cp.c +++ b/sys/dev/drm2/radeon/radeon_cp.c @@ -53,6 +53,16 @@ __FBSDID("$FreeBSD$"); #define FIRMWARE_RS600 "radeonkmsfw_RS600_cp" #define FIRMWARE_R520 "radeonkmsfw_R520_cp" +#ifdef __linux__ +MODULE_FIRMWARE(FIRMWARE_R100); +MODULE_FIRMWARE(FIRMWARE_R200); +MODULE_FIRMWARE(FIRMWARE_R300); +MODULE_FIRMWARE(FIRMWARE_R420); +MODULE_FIRMWARE(FIRMWARE_RS690); +MODULE_FIRMWARE(FIRMWARE_RS600); +MODULE_FIRMWARE(FIRMWARE_R520); +#endif + static int radeon_do_cleanup_cp(struct drm_device * dev); static void radeon_do_cp_start(drm_radeon_private_t * dev_priv); @@ -834,7 +844,7 @@ static void radeon_cp_init_ring_buffer(struct drm_device * dev, RADEON_WRITE(RADEON_LAST_CLEAR_REG, 0); /* reset sarea copies of these */ - master_priv = file_priv->masterp->driver_priv; + master_priv = file_priv->master->driver_priv; if (master_priv->sarea_priv) { master_priv->sarea_priv->last_frame = 0; master_priv->sarea_priv->last_dispatch = 0; @@ -1163,7 +1173,7 @@ static int radeon_do_init_cp(struct drm_device *dev, drm_radeon_init_t *init, struct drm_file *file_priv) { drm_radeon_private_t *dev_priv = dev->dev_private; - struct drm_radeon_master_private *master_priv = file_priv->masterp->driver_priv; + struct drm_radeon_master_private *master_priv = file_priv->master->driver_priv; DRM_DEBUG("\n"); @@ -1655,7 +1665,6 @@ int radeon_cp_init(struct drm_device *dev, void *data, struct drm_file *file_pri return radeon_do_init_cp(dev, init, file_priv); case RADEON_INIT_R600_CP: return r600_do_init_cp(dev, init, file_priv); - break; case RADEON_CLEANUP_CP: if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600) return r600_do_cleanup_cp(dev); @@ -2066,7 +2075,7 @@ int radeon_driver_load(struct drm_device *dev, unsigned long flags) int ret = 0; dev_priv = malloc(sizeof(drm_radeon_private_t), - DRM_MEM_DRIVER, M_ZERO | M_WAITOK); + DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); if (dev_priv == NULL) return -ENOMEM; @@ -2093,11 +2102,11 @@ int radeon_driver_load(struct drm_device *dev, unsigned long flags) break; } - pci_enable_busmaster(dev->device); + pci_enable_busmaster(dev->dev); - if (drm_device_is_agp(dev)) + if (drm_pci_device_is_agp(dev)) dev_priv->flags |= RADEON_IS_AGP; - else if (drm_device_is_pcie(dev)) + else if (drm_pci_device_is_pcie(dev)) dev_priv->flags |= RADEON_IS_PCIE; else dev_priv->flags |= RADEON_IS_PCI; @@ -2126,7 +2135,7 @@ int radeon_master_create(struct drm_device *dev, struct drm_master *master) int ret; master_priv = malloc(sizeof(*master_priv), - DRM_MEM_DRIVER, M_ZERO | M_WAITOK); + DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); if (!master_priv) return -ENOMEM; @@ -2160,11 +2169,7 @@ void radeon_master_destroy(struct drm_device *dev, struct drm_master *master) master_priv->sarea_priv = NULL; if (master_priv->sarea) -#ifdef __linux__ drm_rmmap_locked(dev, master_priv->sarea); -#else - drm_rmmap(dev, master_priv->sarea); -#endif free(master_priv, DRM_MEM_DRIVER); diff --git a/sys/dev/drm2/radeon/radeon_cs.c b/sys/dev/drm2/radeon/radeon_cs.c index ee299fa72067..7adde83ef975 100644 --- a/sys/dev/drm2/radeon/radeon_cs.c +++ b/sys/dev/drm2/radeon/radeon_cs.c @@ -51,12 +51,12 @@ static int radeon_cs_parser_relocs(struct radeon_cs_parser *p) /* FIXME: we assume that each relocs use 4 dwords */ p->nrelocs = chunk->length_dw / 4; p->relocs_ptr = malloc(p->nrelocs * sizeof(void *), - DRM_MEM_DRIVER, M_ZERO | M_WAITOK); + DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); if (p->relocs_ptr == NULL) { return -ENOMEM; } p->relocs = malloc(p->nrelocs * sizeof(struct radeon_cs_reloc), - DRM_MEM_DRIVER, M_ZERO | M_WAITOK); + DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); if (p->relocs == NULL) { return -ENOMEM; } @@ -182,7 +182,7 @@ int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data) p->chunk_flags_idx = -1; p->chunk_const_ib_idx = -1; p->chunks_array = malloc(cs->num_chunks * sizeof(uint64_t), - DRM_MEM_DRIVER, M_ZERO | M_WAITOK); + DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); if (p->chunks_array == NULL) { return -ENOMEM; } @@ -194,7 +194,7 @@ int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data) p->cs_flags = 0; p->nchunks = cs->num_chunks; p->chunks = malloc(p->nchunks * sizeof(struct radeon_cs_chunk), - DRM_MEM_DRIVER, M_ZERO | M_WAITOK); + DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); if (p->chunks == NULL) { return -ENOMEM; } @@ -241,7 +241,7 @@ int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data) if ((p->chunks[i].chunk_id == RADEON_CHUNK_ID_RELOCS) || (p->chunks[i].chunk_id == RADEON_CHUNK_ID_FLAGS)) { size = p->chunks[i].length_dw * sizeof(uint32_t); - p->chunks[i].kdata = malloc(size, DRM_MEM_DRIVER, M_WAITOK); + p->chunks[i].kdata = malloc(size, DRM_MEM_DRIVER, M_NOWAIT); if (p->chunks[i].kdata == NULL) { return -ENOMEM; } @@ -288,8 +288,8 @@ int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data) return -EINVAL; } if (p->rdev && (p->rdev->flags & RADEON_IS_AGP)) { - p->chunks[p->chunk_ib_idx].kpage[0] = malloc(PAGE_SIZE, DRM_MEM_DRIVER, M_WAITOK); - p->chunks[p->chunk_ib_idx].kpage[1] = malloc(PAGE_SIZE, DRM_MEM_DRIVER, M_WAITOK); + p->chunks[p->chunk_ib_idx].kpage[0] = malloc(PAGE_SIZE, DRM_MEM_DRIVER, M_NOWAIT); + p->chunks[p->chunk_ib_idx].kpage[1] = malloc(PAGE_SIZE, DRM_MEM_DRIVER, M_NOWAIT); if (p->chunks[p->chunk_ib_idx].kpage[0] == NULL || p->chunks[p->chunk_ib_idx].kpage[1] == NULL) { free(p->chunks[p->chunk_ib_idx].kpage[0], DRM_MEM_DRIVER); diff --git a/sys/dev/drm2/radeon/radeon_device.c b/sys/dev/drm2/radeon/radeon_device.c index 370e54185b17..e5c676b11ed4 100644 --- a/sys/dev/drm2/radeon/radeon_device.c +++ b/sys/dev/drm2/radeon/radeon_device.c @@ -248,7 +248,7 @@ void radeon_wb_fini(struct radeon_device *rdev) int radeon_wb_init(struct radeon_device *rdev) { int r; - void *wb_ptr; + void *wb_ptr; /* FreeBSD: to please GCC 4.2. */ if (rdev->wb.wb_obj == NULL) { r = radeon_bo_create(rdev, RADEON_GPU_PAGE_SIZE, PAGE_SIZE, true, @@ -430,11 +430,11 @@ bool radeon_card_posted(struct radeon_device *rdev) { uint32_t reg; -#ifdef DUMBBELL_WIP +#ifdef FREEBSD_WIP if (efi_enabled(EFI_BOOT) && rdev->dev->pci_subvendor == PCI_VENDOR_ID_APPLE) return false; -#endif /* DUMBBELL_WIP */ +#endif /* FREEBSD_WIP */ /* first check CRTCs */ if (ASIC_IS_DCE41(rdev)) { @@ -548,7 +548,7 @@ int radeon_dummy_page_init(struct radeon_device *rdev) if (rdev->dummy_page.dmah) return 0; rdev->dummy_page.dmah = drm_pci_alloc(rdev->ddev, - PAGE_SIZE, PAGE_SIZE, BUS_SPACE_MAXSIZE_32BIT); + PAGE_SIZE, PAGE_SIZE, BUS_SPACE_MAXADDR_32BIT); if (rdev->dummy_page.dmah == NULL) return -ENOMEM; rdev->dummy_page.addr = rdev->dummy_page.dmah->busaddr; @@ -731,7 +731,7 @@ int radeon_atombios_init(struct radeon_device *rdev) { struct card_info *atom_card_info = malloc(sizeof(struct card_info), - DRM_MEM_DRIVER, M_ZERO | M_WAITOK); + DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); if (!atom_card_info) return -ENOMEM; @@ -814,7 +814,7 @@ void radeon_combios_fini(struct radeon_device *rdev) { } -#ifdef DUMBBELL_WIP +#ifdef FREEBSD_WIP /* if we get transitioned to only one device, take VGA back */ /** * radeon_vga_set_decode - enable/disable vga decode @@ -835,7 +835,7 @@ static unsigned int radeon_vga_set_decode(void *cookie, bool state) else return VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM; } -#endif /* DUMBBELL_WIP */ +#endif /* FREEBSD_WIP */ /** * radeon_check_pot_argument - check that argument is a power of two @@ -903,7 +903,7 @@ static void radeon_check_arguments(struct radeon_device *rdev) * * @pdev: pci dev pointer */ -#ifdef DUMBBELL_WIP +#ifdef FREEBSD_WIP static bool radeon_switcheroo_quirk_long_wakeup(struct pci_dev *pdev) { @@ -916,7 +916,7 @@ static bool radeon_switcheroo_quirk_long_wakeup(struct pci_dev *pdev) return false; } -#endif /* DUMBBELL_WIP */ +#endif /* FREEBSD_WIP */ /** * radeon_switcheroo_set_state - set switcheroo state @@ -927,7 +927,7 @@ static bool radeon_switcheroo_quirk_long_wakeup(struct pci_dev *pdev) * Callback for the switcheroo driver. Suspends or resumes the * the asics before or after it is powered up using ACPI methods. */ -#ifdef DUMBBELL_WIP +#ifdef FREEBSD_WIP static void radeon_switcheroo_set_state(struct pci_dev *pdev, enum vga_switcheroo_state state) { struct drm_device *dev = pci_get_drvdata(pdev); @@ -956,7 +956,7 @@ static void radeon_switcheroo_set_state(struct pci_dev *pdev, enum vga_switchero dev->switch_power_state = DRM_SWITCH_POWER_OFF; } } -#endif /* DUMBBELL_WIP */ +#endif /* FREEBSD_WIP */ /** * radeon_switcheroo_can_switch - see if switcheroo state can change @@ -967,7 +967,7 @@ static void radeon_switcheroo_set_state(struct pci_dev *pdev, enum vga_switchero * state can be changed. * Returns true if the state can be changed, false if not. */ -#ifdef DUMBBELL_WIP +#ifdef FREEBSD_WIP static bool radeon_switcheroo_can_switch(struct pci_dev *pdev) { struct drm_device *dev = pci_get_drvdata(pdev); @@ -984,7 +984,7 @@ static const struct vga_switcheroo_client_ops radeon_switcheroo_ops = { .reprobe = NULL, .can_switch = radeon_switcheroo_can_switch, }; -#endif /* DUMBBELL_WIP */ +#endif /* FREEBSD_WIP */ /** * radeon_device_init - initialize the driver @@ -1005,7 +1005,7 @@ int radeon_device_init(struct radeon_device *rdev, int dma_bits; rdev->shutdown = false; - rdev->dev = ddev->device; + rdev->dev = ddev->dev; rdev->ddev = ddev; rdev->flags = flags; rdev->family = flags & RADEON_FAMILY_MASK; @@ -1079,7 +1079,7 @@ int radeon_device_init(struct radeon_device *rdev, rdev->need_dma32 = true; dma_bits = rdev->need_dma32 ? 32 : 40; -#ifdef DUMBBELL_WIP +#ifdef FREEBSD_WIP r = pci_set_dma_mask(rdev->pdev, DMA_BIT_MASK(dma_bits)); if (r) { rdev->need_dma32 = true; @@ -1091,7 +1091,7 @@ int radeon_device_init(struct radeon_device *rdev, pci_set_consistent_dma_mask(rdev->pdev, DMA_BIT_MASK(32)); printk(KERN_WARNING "radeon: No coherent DMA available.\n"); } -#endif /* DUMBBELL_WIP */ +#endif /* FREEBSD_WIP */ /* Registers mapping */ /* TODO: block userspace mapping of io register */ @@ -1127,13 +1127,13 @@ int radeon_device_init(struct radeon_device *rdev, taskqueue_thread_enqueue, &rdev->tq); taskqueue_start_threads(&rdev->tq, 1, PWAIT, "radeon taskq"); -#ifdef DUMBBELL_WIP +#ifdef FREEBSD_WIP /* if we have > 1 VGA cards, then disable the radeon VGA resources */ /* this will fail for cards that aren't VGA class devices, just * ignore it */ vga_client_register(rdev->pdev, rdev, NULL, radeon_vga_set_decode); vga_switcheroo_register_client(rdev->pdev, &radeon_switcheroo_ops); -#endif /* DUMBBELL_WIP */ +#endif /* FREEBSD_WIP */ r = radeon_init(rdev); if (r) @@ -1200,9 +1200,9 @@ int radeon_device_init(struct radeon_device *rdev, return 0; } -#ifdef DUMBBELL_WIP +#ifdef FREEBSD_WIP static void radeon_debugfs_remove_files(struct radeon_device *rdev); -#endif /* DUMBBELL_WIP */ +#endif /* FREEBSD_WIP */ /** * radeon_device_fini - tear down the driver @@ -1233,10 +1233,10 @@ void radeon_device_fini(struct radeon_device *rdev) #endif radeon_fini(rdev); -#ifdef DUMBBELL_WIP +#ifdef FREEBSD_WIP vga_switcheroo_unregister_client(rdev->pdev); vga_client_register(rdev->pdev, NULL, NULL, NULL); -#endif /* DUMBBELL_WIP */ +#endif /* FREEBSD_WIP */ if (rdev->tq != NULL) { taskqueue_free(rdev->tq); @@ -1250,9 +1250,9 @@ void radeon_device_fini(struct radeon_device *rdev) bus_release_resource(rdev->dev, SYS_RES_MEMORY, rdev->rmmio_rid, rdev->rmmio); rdev->rmmio = NULL; -#ifdef DUMBBELL_WIP +#ifdef FREEBSD_WIP radeon_debugfs_remove_files(rdev); -#endif /* DUMBBELL_WIP */ +#endif /* FREEBSD_WIP */ } @@ -1280,11 +1280,11 @@ int radeon_suspend_kms(struct drm_device *dev) if (dev == NULL || dev->dev_private == NULL) { return -ENODEV; } -#ifdef DUMBBELL_WIP +#ifdef FREEBSD_WIP if (state.event == PM_EVENT_PRETHAW) { return 0; } -#endif /* DUMBBELL_WIP */ +#endif /* FREEBSD_WIP */ rdev = dev->dev_private; if (dev->switch_power_state == DRM_SWITCH_POWER_OFF) @@ -1342,21 +1342,21 @@ int radeon_suspend_kms(struct drm_device *dev) radeon_agp_suspend(rdev); - pci_save_state(device_get_parent(rdev->dev)); -#ifdef DUMBBELL_WIP + pci_save_state(device_get_parent(dev->dev)); +#ifdef FREEBSD_WIP if (state.event == PM_EVENT_SUSPEND) { /* Shut down the device */ pci_disable_device(dev->pdev); -#endif /* DUMBBELL_WIP */ - pci_set_powerstate(dev->device, PCI_POWERSTATE_D3); -#ifdef DUMBBELL_WIP +#endif /* FREEBSD_WIP */ + pci_set_powerstate(dev->dev, PCI_POWERSTATE_D3); +#ifdef FREEBSD_WIP } console_lock(); -#endif /* DUMBBELL_WIP */ +#endif /* FREEBSD_WIP */ radeon_fbdev_set_suspend(rdev, 1); -#ifdef DUMBBELL_WIP +#ifdef FREEBSD_WIP console_unlock(); -#endif /* DUMBBELL_WIP */ +#endif /* FREEBSD_WIP */ return 0; } @@ -1378,17 +1378,17 @@ int radeon_resume_kms(struct drm_device *dev) if (dev->switch_power_state == DRM_SWITCH_POWER_OFF) return 0; -#ifdef DUMBBELL_WIP +#ifdef FREEBSD_WIP console_lock(); -#endif /* DUMBBELL_WIP */ - pci_set_powerstate(dev->device, PCI_POWERSTATE_D0); - pci_restore_state(device_get_parent(rdev->dev)); -#ifdef DUMBBELL_WIP +#endif /* FREEBSD_WIP */ + pci_set_powerstate(device_get_parent(dev->dev), PCI_POWERSTATE_D0); + pci_restore_state(device_get_parent(dev->dev)); +#ifdef FREEBSD_WIP if (pci_enable_device(dev->pdev)) { console_unlock(); return -1; } -#endif /* DUMBBELL_WIP */ +#endif /* FREEBSD_WIP */ /* resume AGP if in use */ radeon_agp_resume(rdev); radeon_resume(rdev); @@ -1401,9 +1401,9 @@ int radeon_resume_kms(struct drm_device *dev) radeon_restore_bios_scratch_regs(rdev); radeon_fbdev_set_suspend(rdev, 0); -#ifdef DUMBBELL_WIP +#ifdef FREEBSD_WIP console_unlock(); -#endif /* DUMBBELL_WIP */ +#endif /* FREEBSD_WIP */ /* init dig PHYs, disp eng pll */ if (rdev->is_atom_bios) { @@ -1513,7 +1513,7 @@ retry: /* * Debugfs */ -#ifdef DUMBBELL_WIP +#ifdef FREEBSD_WIP int radeon_debugfs_add_files(struct radeon_device *rdev, struct drm_info_list *files, unsigned nfiles) @@ -1573,5 +1573,5 @@ int radeon_debugfs_init(struct drm_minor *minor) void radeon_debugfs_cleanup(struct drm_minor *minor) { } -#endif /* DUMBBELL_WIP */ +#endif /* FREEBSD_WIP */ #endif diff --git a/sys/dev/drm2/radeon/radeon_display.c b/sys/dev/drm2/radeon/radeon_display.c index ee74ed453a2d..1f9b9175622e 100644 --- a/sys/dev/drm2/radeon/radeon_display.c +++ b/sys/dev/drm2/radeon/radeon_display.c @@ -363,7 +363,7 @@ static int radeon_crtc_page_flip(struct drm_crtc *crtc, u64 base; int r; - work = malloc(sizeof *work, DRM_MEM_DRIVER, M_WAITOK | M_ZERO); + work = malloc(sizeof *work, DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); if (work == NULL) return -ENOMEM; @@ -511,7 +511,7 @@ static void radeon_crtc_init(struct drm_device *dev, int index) struct radeon_crtc *radeon_crtc; int i; - radeon_crtc = malloc(sizeof(struct radeon_crtc) + (RADEONFB_CONN_LIMIT * sizeof(struct drm_connector *)), DRM_MEM_DRIVER, M_WAITOK | M_ZERO); + radeon_crtc = malloc(sizeof(struct radeon_crtc) + (RADEONFB_CONN_LIMIT * sizeof(struct drm_connector *)), DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); if (radeon_crtc == NULL) return; @@ -1112,12 +1112,12 @@ radeon_user_framebuffer_create(struct drm_device *dev, obj = drm_gem_object_lookup(dev, file_priv, mode_cmd->handles[0]); if (obj == NULL) { - dev_err(dev->device, "No GEM object associated to handle 0x%08X, " + dev_err(dev->dev, "No GEM object associated to handle 0x%08X, " "can't create framebuffer\n", mode_cmd->handles[0]); return -ENOENT; } - radeon_fb = malloc(sizeof(*radeon_fb), DRM_MEM_DRIVER, M_WAITOK | M_ZERO); + radeon_fb = malloc(sizeof(*radeon_fb), DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); if (radeon_fb == NULL) { drm_gem_object_unreference_unlocked(obj); return (-ENOMEM); @@ -1179,7 +1179,7 @@ static int radeon_modeset_create_props(struct radeon_device *rdev) } if (!ASIC_IS_AVIVO(rdev)) { - sz = DRM_ARRAY_SIZE(radeon_tmds_pll_enum_list); + sz = ARRAY_SIZE(radeon_tmds_pll_enum_list); rdev->mode_info.tmds_pll_property = drm_property_create_enum(rdev->ddev, 0, "tmds_pll", @@ -1193,13 +1193,13 @@ static int radeon_modeset_create_props(struct radeon_device *rdev) drm_mode_create_scaling_mode_property(rdev->ddev); - sz = DRM_ARRAY_SIZE(radeon_tv_std_enum_list); + sz = ARRAY_SIZE(radeon_tv_std_enum_list); rdev->mode_info.tv_std_property = drm_property_create_enum(rdev->ddev, 0, "tv standard", radeon_tv_std_enum_list, sz); - sz = DRM_ARRAY_SIZE(radeon_underscan_enum_list); + sz = ARRAY_SIZE(radeon_underscan_enum_list); rdev->mode_info.underscan_property = drm_property_create_enum(rdev->ddev, 0, "underscan", @@ -1256,38 +1256,38 @@ static void radeon_afmt_init(struct radeon_device *rdev) /* DCE4/5 has 6 audio blocks tied to DIG encoders */ /* DCE4.1 has 2 audio blocks tied to DIG encoders */ rdev->mode_info.afmt[0] = malloc(sizeof(struct radeon_afmt), - DRM_MEM_DRIVER, M_WAITOK | M_ZERO); + DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); if (rdev->mode_info.afmt[0]) { rdev->mode_info.afmt[0]->offset = EVERGREEN_CRTC0_REGISTER_OFFSET; rdev->mode_info.afmt[0]->id = 0; } rdev->mode_info.afmt[1] = malloc(sizeof(struct radeon_afmt), - DRM_MEM_DRIVER, M_WAITOK | M_ZERO); + DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); if (rdev->mode_info.afmt[1]) { rdev->mode_info.afmt[1]->offset = EVERGREEN_CRTC1_REGISTER_OFFSET; rdev->mode_info.afmt[1]->id = 1; } if (!ASIC_IS_DCE41(rdev)) { rdev->mode_info.afmt[2] = malloc(sizeof(struct radeon_afmt), - DRM_MEM_DRIVER, M_WAITOK | M_ZERO); + DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); if (rdev->mode_info.afmt[2]) { rdev->mode_info.afmt[2]->offset = EVERGREEN_CRTC2_REGISTER_OFFSET; rdev->mode_info.afmt[2]->id = 2; } rdev->mode_info.afmt[3] = malloc(sizeof(struct radeon_afmt), - DRM_MEM_DRIVER, M_WAITOK | M_ZERO); + DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); if (rdev->mode_info.afmt[3]) { rdev->mode_info.afmt[3]->offset = EVERGREEN_CRTC3_REGISTER_OFFSET; rdev->mode_info.afmt[3]->id = 3; } rdev->mode_info.afmt[4] = malloc(sizeof(struct radeon_afmt), - DRM_MEM_DRIVER, M_WAITOK | M_ZERO); + DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); if (rdev->mode_info.afmt[4]) { rdev->mode_info.afmt[4]->offset = EVERGREEN_CRTC4_REGISTER_OFFSET; rdev->mode_info.afmt[4]->id = 4; } rdev->mode_info.afmt[5] = malloc(sizeof(struct radeon_afmt), - DRM_MEM_DRIVER, M_WAITOK | M_ZERO); + DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); if (rdev->mode_info.afmt[5]) { rdev->mode_info.afmt[5]->offset = EVERGREEN_CRTC5_REGISTER_OFFSET; rdev->mode_info.afmt[5]->id = 5; @@ -1296,13 +1296,13 @@ static void radeon_afmt_init(struct radeon_device *rdev) } else if (ASIC_IS_DCE3(rdev)) { /* DCE3.x has 2 audio blocks tied to DIG encoders */ rdev->mode_info.afmt[0] = malloc(sizeof(struct radeon_afmt), - DRM_MEM_DRIVER, M_WAITOK | M_ZERO); + DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); if (rdev->mode_info.afmt[0]) { rdev->mode_info.afmt[0]->offset = DCE3_HDMI_OFFSET0; rdev->mode_info.afmt[0]->id = 0; } rdev->mode_info.afmt[1] = malloc(sizeof(struct radeon_afmt), - DRM_MEM_DRIVER, M_WAITOK | M_ZERO); + DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); if (rdev->mode_info.afmt[1]) { rdev->mode_info.afmt[1]->offset = DCE3_HDMI_OFFSET1; rdev->mode_info.afmt[1]->id = 1; @@ -1310,7 +1310,7 @@ static void radeon_afmt_init(struct radeon_device *rdev) } else if (ASIC_IS_DCE2(rdev)) { /* DCE2 has at least 1 routable audio block */ rdev->mode_info.afmt[0] = malloc(sizeof(struct radeon_afmt), - DRM_MEM_DRIVER, M_WAITOK | M_ZERO); + DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); if (rdev->mode_info.afmt[0]) { rdev->mode_info.afmt[0]->offset = DCE2_HDMI_OFFSET0; rdev->mode_info.afmt[0]->id = 0; @@ -1318,7 +1318,7 @@ static void radeon_afmt_init(struct radeon_device *rdev) /* r6xx has 2 routable audio blocks */ if (rdev->family >= CHIP_R600) { rdev->mode_info.afmt[1] = malloc(sizeof(struct radeon_afmt), - DRM_MEM_DRIVER, M_WAITOK | M_ZERO); + DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); if (rdev->mode_info.afmt[1]) { rdev->mode_info.afmt[1]->offset = DCE2_HDMI_OFFSET1; rdev->mode_info.afmt[1]->id = 1; @@ -1419,9 +1419,7 @@ void radeon_modeset_fini(struct radeon_device *rdev) radeon_afmt_fini(rdev); drm_kms_helper_poll_fini(rdev->ddev); radeon_hpd_fini(rdev); - DRM_UNLOCK(rdev->ddev); /* Work around lock recursion. dumbbell@ */ drm_mode_config_cleanup(rdev->ddev); - DRM_LOCK(rdev->ddev); rdev->mode_info.mode_config_initialized = false; } /* free i2c buses */ diff --git a/sys/dev/drm2/radeon/radeon_drm.h b/sys/dev/drm2/radeon/radeon_drm.h index e84500c118fa..a33975381be0 100644 --- a/sys/dev/drm2/radeon/radeon_drm.h +++ b/sys/dev/drm2/radeon/radeon_drm.h @@ -760,7 +760,7 @@ typedef struct drm_radeon_irq_wait { typedef struct drm_radeon_setparam { unsigned int param; - int64_t value; + __s64 value; } drm_radeon_setparam_t; #define RADEON_SETPARAM_FB_LOCATION 1 /* determined framebuffer location */ diff --git a/sys/dev/drm2/radeon/radeon_drv.c b/sys/dev/drm2/radeon/radeon_drv.c index 37b4e265ffc3..7c433c6ed886 100644 --- a/sys/dev/drm2/radeon/radeon_drv.c +++ b/sys/dev/drm2/radeon/radeon_drv.c @@ -85,13 +85,9 @@ extern int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc, int *vpos, int *hpos); extern struct drm_ioctl_desc radeon_ioctls_kms[]; extern int radeon_max_kms_ioctl; -#ifdef COMPAT_FREEBSD32 -extern struct drm_ioctl_desc radeon_compat_ioctls[]; -extern int radeon_num_compat_ioctls; -#endif -#ifdef DUMBBELL_WIP +#ifdef FREEBSD_WIP int radeon_mmap(struct file *filp, struct vm_area_struct *vma); -#endif /* DUMBBELL_WIP */ +#endif /* FREEBSD_WIP */ int radeon_mode_dumb_mmap(struct drm_file *filp, struct drm_device *dev, uint32_t handle, uint64_t *offset_p); @@ -131,7 +127,6 @@ int radeon_pcie_gen2 = -1; int radeon_msi = -1; int radeon_lockup_timeout = 10000; -#ifdef DUMBBELL_WIP MODULE_PARM_DESC(no_wb, "Disable AGP writeback for scratch registers"); module_param_named(no_wb, radeon_no_wb, int, 0444); @@ -183,165 +178,11 @@ module_param_named(msi, radeon_msi, int, 0444); MODULE_PARM_DESC(lockup_timeout, "GPU lockup timeout in ms (defaul 10000 = 10 seconds, 0 = disable)"); module_param_named(lockup_timeout, radeon_lockup_timeout, int, 0444); -static int radeon_suspend(struct drm_device *dev, pm_message_t state) -{ - drm_radeon_private_t *dev_priv = dev->dev_private; - - if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600) - return 0; - - /* Disable *all* interrupts */ - if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS600) - RADEON_WRITE(R500_DxMODE_INT_MASK, 0); - RADEON_WRITE(RADEON_GEN_INT_CNTL, 0); - return 0; -} - -static int radeon_resume(struct drm_device *dev) -{ - drm_radeon_private_t *dev_priv = dev->dev_private; - - if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600) - return 0; - - /* Restore interrupt registers */ - if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS600) - RADEON_WRITE(R500_DxMODE_INT_MASK, dev_priv->r500_disp_irq_reg); - RADEON_WRITE(RADEON_GEN_INT_CNTL, dev_priv->irq_enable_reg); - return 0; -} -#endif /* DUMBBELL_WIP */ - static drm_pci_id_list_t pciidlist[] = { radeon_PCI_IDS }; -#ifdef DUMBBELL_WIP -static const struct file_operations radeon_driver_old_fops = { - .owner = THIS_MODULE, - .open = drm_open, - .release = drm_release, - .unlocked_ioctl = drm_ioctl, - .mmap = drm_mmap, - .poll = drm_poll, - .fasync = drm_fasync, - .read = drm_read, -#ifdef CONFIG_COMPAT - .compat_ioctl = radeon_compat_ioctl, -#endif - .llseek = noop_llseek, -}; - -static struct drm_driver driver_old = { - .driver_features = - DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_SG | - DRIVER_HAVE_IRQ | DRIVER_HAVE_DMA | DRIVER_IRQ_SHARED, - .dev_priv_size = sizeof(drm_radeon_buf_priv_t), - .load = radeon_driver_load, - .firstopen = radeon_driver_firstopen, - .open = radeon_driver_open, - .preclose = radeon_driver_preclose, - .postclose = radeon_driver_postclose, - .lastclose = radeon_driver_lastclose, - .unload = radeon_driver_unload, -#ifdef DUMBBELL_WIP - .suspend = radeon_suspend, - .resume = radeon_resume, -#endif /* DUMBBELL_WIP */ - .get_vblank_counter = radeon_get_vblank_counter, - .enable_vblank = radeon_enable_vblank, - .disable_vblank = radeon_disable_vblank, - .master_create = radeon_master_create, - .master_destroy = radeon_master_destroy, - .irq_preinstall = radeon_driver_irq_preinstall, - .irq_postinstall = radeon_driver_irq_postinstall, - .irq_uninstall = radeon_driver_irq_uninstall, - .irq_handler = radeon_driver_irq_handler, - .ioctls = radeon_ioctls, - .dma_ioctl = radeon_cp_buffers, - .fops = &radeon_driver_old_fops, - .name = DRIVER_NAME, - .desc = DRIVER_DESC, - .date = DRIVER_DATE, - .major = DRIVER_MAJOR, - .minor = DRIVER_MINOR, - .patchlevel = DRIVER_PATCHLEVEL, -}; -#endif /* DUMBBELL_WIP */ - -static struct drm_driver_info kms_driver; - -#ifdef DUMBBELL_WIP -static int radeon_kick_out_firmware_fb(struct pci_dev *pdev) -{ - struct apertures_struct *ap; - bool primary = false; - - ap = alloc_apertures(1); - if (!ap) - return -ENOMEM; - - ap->ranges[0].base = pci_resource_start(pdev, 0); - ap->ranges[0].size = pci_resource_len(pdev, 0); - -#ifdef CONFIG_X86 - primary = pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW; -#endif - remove_conflicting_framebuffers(ap, "radeondrmfb", primary); - kfree(ap); - - return 0; -} - -static int radeon_pci_probe(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - int ret; - - /* Get rid of things like offb */ - ret = radeon_kick_out_firmware_fb(pdev); - if (ret) - return ret; - - return drm_get_pci_dev(pdev, ent, &kms_driver); -} - -static void -radeon_pci_remove(struct pci_dev *pdev) -{ - struct drm_device *dev = pci_get_drvdata(pdev); - - drm_put_dev(dev); -} - -static int -radeon_pci_suspend(struct pci_dev *pdev, pm_message_t state) -{ - struct drm_device *dev = pci_get_drvdata(pdev); - return radeon_suspend_kms(dev, state); -} - -static int -radeon_pci_resume(struct pci_dev *pdev) -{ - struct drm_device *dev = pci_get_drvdata(pdev); - return radeon_resume_kms(dev); -} - -static const struct file_operations radeon_driver_kms_fops = { - .owner = THIS_MODULE, - .open = drm_open, - .release = drm_release, - .unlocked_ioctl = drm_ioctl, - .mmap = radeon_mmap, - .poll = drm_poll, - .fasync = drm_fasync, - .read = drm_read, -#ifdef CONFIG_COMPAT - .compat_ioctl = radeon_kms_compat_ioctl, -#endif -}; -#endif /* DUMBBELL_WIP */ +static struct drm_driver kms_driver; static int radeon_sysctl_init(struct drm_device *dev, struct sysctl_ctx_list *ctx, struct sysctl_oid *top) @@ -349,31 +190,34 @@ static int radeon_sysctl_init(struct drm_device *dev, struct sysctl_ctx_list *ct return drm_add_busid_modesetting(dev, ctx, top); } -static struct drm_driver_info kms_driver = { +static struct drm_driver kms_driver = { .driver_features = DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_SG | DRIVER_HAVE_IRQ | DRIVER_HAVE_DMA | DRIVER_IRQ_SHARED | DRIVER_GEM | - DRIVER_PRIME /* | DRIVE_MODESET */, -#ifdef DUMBBELL_WIP + DRIVER_PRIME, +#ifdef FREEBSD_WIP .dev_priv_size = 0, -#endif /* DUMBBELL_WIP */ +#endif /* FREEBSD_WIP */ .load = radeon_driver_load_kms, - .use_msi = radeon_msi_ok, .firstopen = radeon_driver_firstopen_kms, .open = radeon_driver_open_kms, .preclose = radeon_driver_preclose_kms, .postclose = radeon_driver_postclose_kms, .lastclose = radeon_driver_lastclose_kms, .unload = radeon_driver_unload_kms, -#ifdef DUMBBELL_WIP +#ifdef FREEBSD_WIP .suspend = radeon_suspend_kms, .resume = radeon_resume_kms, -#endif /* DUMBBELL_WIP */ +#endif /* FREEBSD_WIP */ .get_vblank_counter = radeon_get_vblank_counter_kms, .enable_vblank = radeon_enable_vblank_kms, .disable_vblank = radeon_disable_vblank_kms, .get_vblank_timestamp = radeon_get_vblank_timestamp_kms, .get_scanout_position = radeon_get_crtc_scanoutpos, +#if defined(CONFIG_DEBUG_FS) + .debugfs_init = radeon_debugfs_init, + .debugfs_cleanup = radeon_debugfs_cleanup, +#endif .irq_preinstall = radeon_driver_irq_preinstall_kms, .irq_postinstall = radeon_driver_irq_postinstall_kms, .irq_uninstall = radeon_driver_irq_uninstall_kms, @@ -388,16 +232,16 @@ static struct drm_driver_info kms_driver = { .dumb_create = radeon_mode_dumb_create, .dumb_map_offset = radeon_mode_dumb_mmap, .dumb_destroy = radeon_mode_dumb_destroy, -#ifdef DUMBBELL_WIP +#ifdef FREEBSD_WIP .fops = &radeon_driver_kms_fops, -#endif /* DUMBBELL_WIP */ +#endif /* FREEBSD_WIP */ -#ifdef DUMBBELL_WIP +#ifdef FREEBSD_WIP .prime_handle_to_fd = drm_gem_prime_handle_to_fd, .prime_fd_to_handle = drm_gem_prime_fd_to_handle, .gem_prime_export = radeon_gem_prime_export, .gem_prime_import = radeon_gem_prime_import, -#endif /* DUMBBELL_WIP */ +#endif /* FREEBSD_WIP */ .name = DRIVER_NAME, .desc = DRIVER_DESC, @@ -407,7 +251,7 @@ static struct drm_driver_info kms_driver = { .patchlevel = KMS_DRIVER_PATCHLEVEL, }; -#ifdef DUMBBELL_WIP +#ifdef FREEBSD_WIP static int __init radeon_init(void) { driver = &driver_old; @@ -450,7 +294,7 @@ static void __exit radeon_exit(void) drm_pci_exit(driver, pdriver); radeon_unregister_atpx_handler(); } -#endif /* DUMBBELL_WIP */ +#endif /* FREEBSD_WIP */ /* =================================================================== */ @@ -458,26 +302,23 @@ static int radeon_probe(device_t kdev) { - return drm_probe(kdev, pciidlist); + return (-drm_probe_helper(kdev, pciidlist)); } static int radeon_attach(device_t kdev) { - struct drm_device *dev; - dev = device_get_softc(kdev); if (radeon_modeset == 1) { kms_driver.driver_features |= DRIVER_MODESET; - kms_driver.max_ioctl = radeon_max_kms_ioctl; + kms_driver.num_ioctls = radeon_max_kms_ioctl; #ifdef COMPAT_FREEBSD32 kms_driver.compat_ioctls = radeon_compat_ioctls; - kms_driver.compat_ioctls_nr = &radeon_num_compat_ioctls; + kms_driver.num_compat_ioctls = &radeon_num_compat_ioctls; #endif radeon_register_atpx_handler(); } - dev->driver = &kms_driver; - return (drm_attach(kdev, pciidlist)); + return (-drm_attach_helper(kdev, pciidlist, &kms_driver)); } static int @@ -488,8 +329,12 @@ radeon_suspend(device_t kdev) dev = device_get_softc(kdev); ret = radeon_suspend_kms(dev); + if (ret) + return (-ret); - return (-ret); + ret = bus_generic_suspend(kdev); + + return (ret); } static int @@ -500,8 +345,12 @@ radeon_resume(device_t kdev) dev = device_get_softc(kdev); ret = radeon_resume_kms(dev); + if (ret) + return (-ret); + + ret = bus_generic_resume(kdev); - return (-ret); + return (ret); } extern struct fb_info * radeon_fb_helper_getinfo(device_t kdev); @@ -512,7 +361,7 @@ static device_method_t radeon_methods[] = { DEVMETHOD(device_attach, radeon_attach), DEVMETHOD(device_suspend, radeon_suspend), DEVMETHOD(device_resume, radeon_resume), - DEVMETHOD(device_detach, drm_detach), + DEVMETHOD(device_detach, drm_generic_detach), /* Framebuffer service methods */ DEVMETHOD(fb_getinfo, radeon_fb_helper_getinfo), diff --git a/sys/dev/drm2/radeon/radeon_drv.h b/sys/dev/drm2/radeon/radeon_drv.h index 99c6aa402b0d..af05bbf529af 100644 --- a/sys/dev/drm2/radeon/radeon_drv.h +++ b/sys/dev/drm2/radeon/radeon_drv.h @@ -328,6 +328,10 @@ typedef struct drm_radeon_kcmd_buffer { extern int radeon_no_wb; extern struct drm_ioctl_desc radeon_ioctls[]; extern int radeon_max_ioctl; +#ifdef COMPAT_FREEBSD32 +extern struct drm_ioctl_desc radeon_compat_ioctls[]; +extern int radeon_num_compat_ioctls; +#endif extern u32 radeon_get_ring_head(drm_radeon_private_t *dev_priv); extern void radeon_set_ring_head(drm_radeon_private_t *dev_priv, u32 val); @@ -463,8 +467,13 @@ extern void r600_blit_swap(struct drm_device *dev, int w, int h, int src_pitch, int dst_pitch, int cpp); /* atpx handler */ +#if defined(CONFIG_VGA_SWITCHEROO) void radeon_register_atpx_handler(void); void radeon_unregister_atpx_handler(void); +#else +static inline void radeon_register_atpx_handler(void) {} +static inline void radeon_unregister_atpx_handler(void) {} +#endif /* Flags for stats.boxes */ @@ -2004,7 +2013,7 @@ do { \ #define VB_AGE_TEST_WITH_RETURN( dev_priv ) \ do { \ - struct drm_radeon_master_private *master_priv = file_priv->masterp->driver_priv;\ + struct drm_radeon_master_private *master_priv = file_priv->master->driver_priv; \ drm_radeon_sarea_t *sarea_priv = master_priv->sarea_priv; \ if ( sarea_priv->last_dispatch >= RADEON_MAX_VB_AGE ) { \ int __ret; \ diff --git a/sys/dev/drm2/radeon/radeon_fb.c b/sys/dev/drm2/radeon/radeon_fb.c index 7b976b661949..6ed52d975e47 100644 --- a/sys/dev/drm2/radeon/radeon_fb.c +++ b/sys/dev/drm2/radeon/radeon_fb.c @@ -219,7 +219,12 @@ static int radeonfb_create(struct radeon_fbdev *rfbdev, rbo = gem_to_radeon_bo(gobj); - info = malloc(sizeof(*info), DRM_MEM_KMS, M_WAITOK | M_ZERO); + /* okay we have an object now allocate the framebuffer */ + info = framebuffer_alloc(); + if (info == NULL) { + ret = -ENOMEM; + goto out_unref; + } ret = radeon_framebuffer_init(rdev->ddev, &rfbdev->rfb, &mode_cmd, gobj); if (ret) { @@ -235,14 +240,16 @@ static int radeonfb_create(struct radeon_fbdev *rfbdev, memset(rbo->kptr, 0x0, radeon_bo_size(rbo)); + drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth); + tmp = radeon_bo_gpu_offset(rbo) - rdev->mc.vram_start; info->fb_size = radeon_bo_size(rbo); info->fb_bpp = sizes->surface_bpp; - info->fb_width = sizes->surface_width; - info->fb_height = sizes->surface_height; info->fb_pbase = rdev->mc.aper_base + tmp; info->fb_vbase = (vm_offset_t)rbo->kptr; + drm_fb_helper_fill_var(info, &rfbdev->helper, sizes->fb_width, sizes->fb_height); + DRM_INFO("fb mappable at 0x%" PRIXPTR "\n", info->fb_pbase); DRM_INFO("vram apper at 0x%lX\n", (unsigned long)rdev->mc.aper_base); DRM_INFO("size %lu\n", (unsigned long)radeon_bo_size(rbo)); @@ -292,15 +299,12 @@ static int radeon_fbdev_destroy(struct drm_device *dev, struct radeon_fbdev *rfb if (rfbdev->helper.fbdev) { info = rfbdev->helper.fbdev; if (info->fb_fbd_dev != NULL) - device_delete_child(dev->device, info->fb_fbd_dev); - free(info->fb_priv, DRM_MEM_KMS); - free(info, DRM_MEM_KMS); + device_delete_child(dev->dev, info->fb_fbd_dev); + framebuffer_release(info); } if (rfb->obj) { - DRM_UNLOCK(dev); /* Work around lock recursion. dumbbell@ */ radeonfb_destroy_pinned_object(rfb->obj); - DRM_LOCK(dev); rfb->obj = NULL; } drm_fb_helper_fini(&rfbdev->helper); @@ -326,7 +330,7 @@ int radeon_fbdev_init(struct radeon_device *rdev) bpp_sel = 8; rfbdev = malloc(sizeof(struct radeon_fbdev), - DRM_MEM_DRIVER, M_WAITOK | M_ZERO); + DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); if (!rfbdev) return -ENOMEM; @@ -359,9 +363,9 @@ void radeon_fbdev_fini(struct radeon_device *rdev) void radeon_fbdev_set_suspend(struct radeon_device *rdev, int state) { -#ifdef DUMBBELL_WIP +#ifdef FREEBSD_WIP fb_set_suspend(rdev->mode_info.rfbdev->helper.fbdev, state); -#endif /* DUMBBELL_WIP */ +#endif /* FREEBSD_WIP */ } int radeon_fbdev_total_size(struct radeon_device *rdev) diff --git a/sys/dev/drm2/radeon/radeon_fence.c b/sys/dev/drm2/radeon/radeon_fence.c index 3b43a8c4a276..21c354115fc5 100644 --- a/sys/dev/drm2/radeon/radeon_fence.c +++ b/sys/dev/drm2/radeon/radeon_fence.c @@ -35,9 +35,9 @@ __FBSDID("$FreeBSD$"); #include <dev/drm2/drmP.h> #include "radeon_reg.h" #include "radeon.h" -#ifdef DUMBBELL_WIP +#ifdef FREEBSD_WIP #include "radeon_trace.h" -#endif /* DUMBBELL_WIP */ +#endif /* FREEBSD_WIP */ /* * Fences @@ -106,7 +106,7 @@ int radeon_fence_emit(struct radeon_device *rdev, int ring) { /* we are protected by the ring emission mutex */ - *fence = malloc(sizeof(struct radeon_fence), DRM_MEM_DRIVER, M_WAITOK); + *fence = malloc(sizeof(struct radeon_fence), DRM_MEM_DRIVER, M_NOWAIT); if ((*fence) == NULL) { return -ENOMEM; } @@ -155,7 +155,7 @@ void radeon_fence_process(struct radeon_device *rdev, int ring) * have temporarly set the last_seq not to the true real last * seq but to an older one. */ - last_seq = atomic_load_acq_64(&rdev->fence_drv[ring].last_seq); + last_seq = atomic64_read(&rdev->fence_drv[ring].last_seq); do { last_emitted = rdev->fence_drv[ring].sync_seq[ring]; seq = radeon_fence_read(rdev, ring); @@ -220,12 +220,12 @@ static void radeon_fence_destroy(struct radeon_fence *fence) static bool radeon_fence_seq_signaled(struct radeon_device *rdev, u64 seq, unsigned ring) { - if (atomic_load_acq_64(&rdev->fence_drv[ring].last_seq) >= seq) { + if (atomic64_read(&rdev->fence_drv[ring].last_seq) >= seq) { return true; } /* poll new last sequence at least once */ radeon_fence_process(rdev, ring); - if (atomic_load_acq_64(&rdev->fence_drv[ring].last_seq) >= seq) { + if (atomic64_read(&rdev->fence_drv[ring].last_seq) >= seq) { return true; } return false; @@ -281,7 +281,7 @@ static int radeon_fence_wait_seq(struct radeon_device *rdev, u64 target_seq, bool signaled, fence_queue_locked; int r; - while (target_seq > atomic_load_acq_64(&rdev->fence_drv[ring].last_seq)) { + while (target_seq > atomic64_read(&rdev->fence_drv[ring].last_seq)) { if (!rdev->ring[ring].ready) { return -EBUSY; } @@ -296,7 +296,7 @@ static int radeon_fence_wait_seq(struct radeon_device *rdev, u64 target_seq, */ timeout = 1; } - seq = atomic_load_acq_64(&rdev->fence_drv[ring].last_seq); + seq = atomic64_read(&rdev->fence_drv[ring].last_seq); /* Save current last activity valuee, used to check for GPU lockups */ last_activity = rdev->fence_drv[ring].last_activity; @@ -352,7 +352,7 @@ static int radeon_fence_wait_seq(struct radeon_device *rdev, u64 target_seq, #endif /* check if sequence value has changed since last_activity */ - if (seq != atomic_load_acq_64(&rdev->fence_drv[ring].last_seq)) { + if (seq != atomic64_read(&rdev->fence_drv[ring].last_seq)) { continue; } @@ -641,7 +641,7 @@ int radeon_fence_wait_next_locked(struct radeon_device *rdev, int ring) { uint64_t seq; - seq = atomic_load_acq_64(&rdev->fence_drv[ring].last_seq) + 1ULL; + seq = atomic64_read(&rdev->fence_drv[ring].last_seq) + 1ULL; if (seq >= rdev->fence_drv[ring].sync_seq[ring]) { /* nothing to wait for, last_seq is already the last emited fence */ @@ -728,7 +728,7 @@ unsigned radeon_fence_count_emitted(struct radeon_device *rdev, int ring) */ radeon_fence_process(rdev, ring); emitted = rdev->fence_drv[ring].sync_seq[ring] - - atomic_load_acq_64(&rdev->fence_drv[ring].last_seq); + - atomic64_read(&rdev->fence_drv[ring].last_seq); /* to avoid 32bits warp around */ if (emitted > 0x10000000) { emitted = 0x10000000; @@ -834,7 +834,7 @@ int radeon_fence_driver_start_ring(struct radeon_device *rdev, int ring) } rdev->fence_drv[ring].cpu_addr = &rdev->wb.wb[index/4]; rdev->fence_drv[ring].gpu_addr = rdev->wb.gpu_addr + index; - radeon_fence_write(rdev, atomic_load_acq_64(&rdev->fence_drv[ring].last_seq), ring); + radeon_fence_write(rdev, atomic64_read(&rdev->fence_drv[ring].last_seq), ring); rdev->fence_drv[ring].initialized = true; dev_info(rdev->dev, "fence driver on ring %d use gpu addr 0x%016jx and cpu addr 0x%p\n", ring, (uintmax_t)rdev->fence_drv[ring].gpu_addr, rdev->fence_drv[ring].cpu_addr); @@ -860,7 +860,7 @@ static void radeon_fence_driver_init_ring(struct radeon_device *rdev, int ring) rdev->fence_drv[ring].gpu_addr = 0; for (i = 0; i < RADEON_NUM_RINGS; ++i) rdev->fence_drv[ring].sync_seq[i] = 0; - atomic_store_rel_64(&rdev->fence_drv[ring].last_seq, 0); + atomic64_set(&rdev->fence_drv[ring].last_seq, 0); rdev->fence_drv[ring].last_activity = jiffies; rdev->fence_drv[ring].initialized = false; } @@ -959,7 +959,7 @@ static int radeon_debugfs_fence_info(struct seq_file *m, void *data) seq_printf(m, "--- ring %d ---\n", i); seq_printf(m, "Last signaled fence 0x%016llx\n", - (unsigned long long)atomic_load_acq_64(&rdev->fence_drv[i].last_seq)); + (unsigned long long)atomic64_read(&rdev->fence_drv[i].last_seq)); seq_printf(m, "Last emitted 0x%016llx\n", rdev->fence_drv[i].sync_seq[i]); diff --git a/sys/dev/drm2/radeon/radeon_gart.c b/sys/dev/drm2/radeon/radeon_gart.c index 36b4452b14b2..3dae6ae81cff 100644 --- a/sys/dev/drm2/radeon/radeon_gart.c +++ b/sys/dev/drm2/radeon/radeon_gart.c @@ -72,13 +72,13 @@ int radeon_gart_table_ram_alloc(struct radeon_device *rdev) drm_dma_handle_t *dmah; dmah = drm_pci_alloc(rdev->ddev, rdev->gart.table_size, - PAGE_SIZE, 0xFFFFFFFFUL); + PAGE_SIZE, BUS_SPACE_MAXADDR); if (dmah == NULL) { return -ENOMEM; } rdev->gart.dmah = dmah; rdev->gart.ptr = dmah->vaddr; -#if defined(__i386) || defined(__amd64) +#ifdef CONFIG_X86 if (rdev->family == CHIP_RS400 || rdev->family == CHIP_RS480 || rdev->family == CHIP_RS690 || rdev->family == CHIP_RS740) { pmap_change_attr((vm_offset_t)rdev->gart.ptr, @@ -104,7 +104,7 @@ void radeon_gart_table_ram_free(struct radeon_device *rdev) if (rdev->gart.ptr == NULL) { return; } -#if defined(__i386) || defined(__amd64) +#ifdef CONFIG_X86 if (rdev->family == CHIP_RS400 || rdev->family == CHIP_RS480 || rdev->family == CHIP_RS690 || rdev->family == CHIP_RS740) { pmap_change_attr((vm_offset_t)rdev->gart.ptr, @@ -361,14 +361,14 @@ int radeon_gart_init(struct radeon_device *rdev) rdev->gart.num_cpu_pages, rdev->gart.num_gpu_pages); /* Allocate pages table */ rdev->gart.pages = malloc(sizeof(void *) * rdev->gart.num_cpu_pages, - DRM_MEM_DRIVER, M_ZERO | M_WAITOK); + DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); if (rdev->gart.pages == NULL) { radeon_gart_fini(rdev); return -ENOMEM; } rdev->gart.pages_addr = malloc(sizeof(dma_addr_t) * rdev->gart.num_cpu_pages, - DRM_MEM_DRIVER, M_ZERO | M_WAITOK); + DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); if (rdev->gart.pages_addr == NULL) { radeon_gart_fini(rdev); return -ENOMEM; @@ -648,7 +648,7 @@ retry: memset(pd_addr, 0, pd_size); pts_size = radeon_vm_num_pdes(rdev) * sizeof(struct radeon_sa_bo *); - vm->page_tables = malloc(pts_size, DRM_MEM_DRIVER, M_ZERO | M_WAITOK); + vm->page_tables = malloc(pts_size, DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); if (vm->page_tables == NULL) { DRM_ERROR("Cannot allocate memory for page table array\n"); @@ -797,7 +797,7 @@ struct radeon_bo_va *radeon_vm_bo_add(struct radeon_device *rdev, struct radeon_bo_va *bo_va; bo_va = malloc(sizeof(struct radeon_bo_va), - DRM_MEM_DRIVER, M_ZERO | M_WAITOK); + DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); if (bo_va == NULL) { return NULL; } @@ -916,7 +916,12 @@ uint64_t radeon_vm_map_gart(struct radeon_device *rdev, uint64_t addr) result = rdev->gart.pages_addr[addr >> PAGE_SHIFT]; /* in case cpu page size != gpu page size*/ - result |= addr & (~PAGE_MASK); + /* + * FreeBSD port note: FreeBSD's PAGE_MASK is the inverse of + * Linux's one. That's why the test below doesn't inverse the + * constant. + */ + result |= addr & (PAGE_MASK); return result; } diff --git a/sys/dev/drm2/radeon/radeon_gem.c b/sys/dev/drm2/radeon/radeon_gem.c index e8975bd3f030..2a5510126498 100644 --- a/sys/dev/drm2/radeon/radeon_gem.c +++ b/sys/dev/drm2/radeon/radeon_gem.c @@ -46,10 +46,10 @@ void radeon_gem_object_free(struct drm_gem_object *gobj) struct radeon_bo *robj = gem_to_radeon_bo(gobj); if (robj) { -#ifdef DUMBBELL_WIP +#ifdef FREEBSD_WIP if (robj->gem_base.import_attach) drm_prime_gem_destroy(&robj->gem_base, robj->tbo.sg); -#endif /* DUMBBELL_WIP */ +#endif /* FREEBSD_WIP */ radeon_bo_unref(&robj); } } @@ -80,7 +80,7 @@ int radeon_gem_object_create(struct radeon_device *rdev, int size, retry: r = radeon_bo_create(rdev, size, alignment, kernel, initial_domain, NULL, &robj); if (r) { - if (r != -ERESTART) { + if (r != -ERESTARTSYS) { if (initial_domain == RADEON_GEM_DOMAIN_VRAM) { initial_domain |= RADEON_GEM_DOMAIN_GTT; goto retry; @@ -268,11 +268,12 @@ int radeon_gem_create_ioctl(struct drm_device *dev, void *data, args->initial_domain, false, false, &gobj); if (r) { + if (r == -ERESTARTSYS) + r = -EINTR; sx_sunlock(&rdev->exclusive_lock); r = radeon_gem_handle_lockup(rdev, r); return r; } - handle = 0; r = drm_gem_handle_create(filp, gobj, &handle); /* drop reference from allocate - handle holds it now */ drm_gem_object_unreference_unlocked(gobj); @@ -394,6 +395,8 @@ int radeon_gem_wait_idle_ioctl(struct drm_device *dev, void *data, if (rdev->asic->ioctl_wait_idle) robj->rdev->asic->ioctl_wait_idle(rdev, robj); drm_gem_object_unreference_unlocked(gobj); + if (r == -ERESTARTSYS) + r = -EINTR; r = radeon_gem_handle_lockup(rdev, r); return r; } @@ -467,7 +470,7 @@ int radeon_gem_va_ioctl(struct drm_device *dev, void *data, } if (args->offset < RADEON_VA_RESERVED_SIZE) { - dev_err(dev->device, + dev_err(dev->dev, "offset 0x%lX is in reserved area 0x%X\n", (unsigned long)args->offset, RADEON_VA_RESERVED_SIZE); @@ -481,13 +484,13 @@ int radeon_gem_va_ioctl(struct drm_device *dev, void *data, */ invalid_flags = RADEON_VM_PAGE_VALID | RADEON_VM_PAGE_SYSTEM; if ((args->flags & invalid_flags)) { - dev_err(dev->device, "invalid flags 0x%08X vs 0x%08X\n", + dev_err(dev->dev, "invalid flags 0x%08X vs 0x%08X\n", args->flags, invalid_flags); args->operation = RADEON_VA_RESULT_ERROR; return -EINVAL; } if (!(args->flags & RADEON_VM_PAGE_SNOOPED)) { - dev_err(dev->device, "only supported snooped mapping for now\n"); + dev_err(dev->dev, "only supported snooped mapping for now\n"); args->operation = RADEON_VA_RESULT_ERROR; return -EINVAL; } @@ -497,7 +500,7 @@ int radeon_gem_va_ioctl(struct drm_device *dev, void *data, case RADEON_VA_UNMAP: break; default: - dev_err(dev->device, "unsupported operation %d\n", + dev_err(dev->dev, "unsupported operation %d\n", args->operation); args->operation = RADEON_VA_RESULT_ERROR; return -EINVAL; @@ -567,7 +570,6 @@ int radeon_mode_dumb_create(struct drm_file *file_priv, if (r) return -ENOMEM; - handle = 0; r = drm_gem_handle_create(file_priv, gobj, &handle); /* drop reference from allocate - handle holds it now */ drm_gem_object_unreference_unlocked(gobj); diff --git a/sys/dev/drm2/radeon/radeon_i2c.c b/sys/dev/drm2/radeon/radeon_i2c.c index 917286a14c18..8a8a904b9652 100644 --- a/sys/dev/drm2/radeon/radeon_i2c.c +++ b/sys/dev/drm2/radeon/radeon_i2c.c @@ -449,7 +449,7 @@ static int r100_hw_i2c_xfer(struct radeon_i2c_chan *i2c, break; default: DRM_ERROR("gpio not supported with hw i2c\n"); - ret = EINVAL; + ret = -EINVAL; goto done; } break; @@ -464,7 +464,7 @@ static int r100_hw_i2c_xfer(struct radeon_i2c_chan *i2c, break; default: DRM_ERROR("gpio not supported with hw i2c\n"); - ret = EINVAL; + ret = -EINVAL; goto done; } break; @@ -483,7 +483,7 @@ static int r100_hw_i2c_xfer(struct radeon_i2c_chan *i2c, break; default: DRM_ERROR("gpio not supported with hw i2c\n"); - ret = EINVAL; + ret = -EINVAL; goto done; } break; @@ -499,7 +499,7 @@ static int r100_hw_i2c_xfer(struct radeon_i2c_chan *i2c, break; default: DRM_ERROR("gpio not supported with hw i2c\n"); - ret = EINVAL; + ret = -EINVAL; goto done; } break; @@ -523,13 +523,13 @@ static int r100_hw_i2c_xfer(struct radeon_i2c_chan *i2c, break; default: DRM_ERROR("gpio not supported with hw i2c\n"); - ret = EINVAL; + ret = -EINVAL; goto done; } break; default: DRM_ERROR("unsupported asic\n"); - ret = EINVAL; + ret = -EINVAL; goto done; break; } @@ -550,7 +550,7 @@ static int r100_hw_i2c_xfer(struct radeon_i2c_chan *i2c, (48 << RADEON_I2C_TIME_LIMIT_SHIFT))); WREG32(i2c_cntl_0, reg); for (k = 0; k < 32; k++) { - DRM_UDELAY(10); + udelay(10); tmp = RREG32(i2c_cntl_0); if (tmp & RADEON_I2C_GO) continue; @@ -560,7 +560,7 @@ static int r100_hw_i2c_xfer(struct radeon_i2c_chan *i2c, else { DRM_DEBUG("i2c write error 0x%08x\n", tmp); WREG32(i2c_cntl_0, tmp | RADEON_I2C_ABORT); - ret = EIO; + ret = -EIO; goto done; } } @@ -582,7 +582,7 @@ static int r100_hw_i2c_xfer(struct radeon_i2c_chan *i2c, (48 << RADEON_I2C_TIME_LIMIT_SHIFT))); WREG32(i2c_cntl_0, reg | RADEON_I2C_RECEIVE); for (k = 0; k < 32; k++) { - DRM_UDELAY(10); + udelay(10); tmp = RREG32(i2c_cntl_0); if (tmp & RADEON_I2C_GO) continue; @@ -592,7 +592,7 @@ static int r100_hw_i2c_xfer(struct radeon_i2c_chan *i2c, else { DRM_DEBUG("i2c read error 0x%08x\n", tmp); WREG32(i2c_cntl_0, tmp | RADEON_I2C_ABORT); - ret = EIO; + ret = -EIO; goto done; } } @@ -610,7 +610,7 @@ static int r100_hw_i2c_xfer(struct radeon_i2c_chan *i2c, (48 << RADEON_I2C_TIME_LIMIT_SHIFT))); WREG32(i2c_cntl_0, reg); for (k = 0; k < 32; k++) { - DRM_UDELAY(10); + udelay(10); tmp = RREG32(i2c_cntl_0); if (tmp & RADEON_I2C_GO) continue; @@ -620,7 +620,7 @@ static int r100_hw_i2c_xfer(struct radeon_i2c_chan *i2c, else { DRM_DEBUG("i2c write error 0x%08x\n", tmp); WREG32(i2c_cntl_0, tmp | RADEON_I2C_ABORT); - ret = EIO; + ret = -EIO; goto done; } } @@ -710,13 +710,13 @@ static int r500_hw_i2c_xfer(struct radeon_i2c_chan *i2c, WREG32(AVIVO_DC_I2C_ARBITRATION, AVIVO_DC_I2C_SW_WANTS_TO_USE_I2C); for (i = 0; i < 50; i++) { - DRM_UDELAY(1); + udelay(1); if (RREG32(AVIVO_DC_I2C_ARBITRATION) & AVIVO_DC_I2C_SW_CAN_USE_I2C) break; } if (i == 50) { DRM_ERROR("failed to get i2c bus\n"); - ret = EBUSY; + ret = -EBUSY; goto done; } @@ -733,7 +733,7 @@ static int r500_hw_i2c_xfer(struct radeon_i2c_chan *i2c, break; default: DRM_ERROR("gpio not supported with hw i2c\n"); - ret = EINVAL; + ret = -EINVAL; goto done; } @@ -744,7 +744,7 @@ static int r500_hw_i2c_xfer(struct radeon_i2c_chan *i2c, AVIVO_DC_I2C_NACK | AVIVO_DC_I2C_HALT)); WREG32(AVIVO_DC_I2C_RESET, AVIVO_DC_I2C_SOFT_RESET); - DRM_UDELAY(1); + udelay(1); WREG32(AVIVO_DC_I2C_RESET, 0); WREG32(AVIVO_DC_I2C_DATA, (p->slave << 1) & 0xff); @@ -757,7 +757,7 @@ static int r500_hw_i2c_xfer(struct radeon_i2c_chan *i2c, WREG32(AVIVO_DC_I2C_CONTROL1, reg); WREG32(AVIVO_DC_I2C_STATUS1, AVIVO_DC_I2C_GO); for (j = 0; j < 200; j++) { - DRM_UDELAY(50); + udelay(50); tmp = RREG32(AVIVO_DC_I2C_STATUS1); if (tmp & AVIVO_DC_I2C_GO) continue; @@ -767,7 +767,7 @@ static int r500_hw_i2c_xfer(struct radeon_i2c_chan *i2c, else { DRM_DEBUG("i2c write error 0x%08x\n", tmp); WREG32(AVIVO_DC_I2C_RESET, AVIVO_DC_I2C_ABORT); - ret = EIO; + ret = -EIO; goto done; } } @@ -788,7 +788,7 @@ static int r500_hw_i2c_xfer(struct radeon_i2c_chan *i2c, AVIVO_DC_I2C_NACK | AVIVO_DC_I2C_HALT)); WREG32(AVIVO_DC_I2C_RESET, AVIVO_DC_I2C_SOFT_RESET); - DRM_UDELAY(1); + udelay(1); WREG32(AVIVO_DC_I2C_RESET, 0); WREG32(AVIVO_DC_I2C_DATA, ((p->slave << 1) & 0xff) | 0x1); @@ -799,7 +799,7 @@ static int r500_hw_i2c_xfer(struct radeon_i2c_chan *i2c, WREG32(AVIVO_DC_I2C_CONTROL1, reg | AVIVO_DC_I2C_RECEIVE); WREG32(AVIVO_DC_I2C_STATUS1, AVIVO_DC_I2C_GO); for (j = 0; j < 200; j++) { - DRM_UDELAY(50); + udelay(50); tmp = RREG32(AVIVO_DC_I2C_STATUS1); if (tmp & AVIVO_DC_I2C_GO) continue; @@ -809,7 +809,7 @@ static int r500_hw_i2c_xfer(struct radeon_i2c_chan *i2c, else { DRM_DEBUG("i2c read error 0x%08x\n", tmp); WREG32(AVIVO_DC_I2C_RESET, AVIVO_DC_I2C_ABORT); - ret = EIO; + ret = -EIO; goto done; } } @@ -828,7 +828,7 @@ static int r500_hw_i2c_xfer(struct radeon_i2c_chan *i2c, AVIVO_DC_I2C_NACK | AVIVO_DC_I2C_HALT)); WREG32(AVIVO_DC_I2C_RESET, AVIVO_DC_I2C_SOFT_RESET); - DRM_UDELAY(1); + udelay(1); WREG32(AVIVO_DC_I2C_RESET, 0); WREG32(AVIVO_DC_I2C_DATA, (p->slave << 1) & 0xff); @@ -842,7 +842,7 @@ static int r500_hw_i2c_xfer(struct radeon_i2c_chan *i2c, WREG32(AVIVO_DC_I2C_CONTROL1, reg); WREG32(AVIVO_DC_I2C_STATUS1, AVIVO_DC_I2C_GO); for (j = 0; j < 200; j++) { - DRM_UDELAY(50); + udelay(50); tmp = RREG32(AVIVO_DC_I2C_STATUS1); if (tmp & AVIVO_DC_I2C_GO) continue; @@ -852,7 +852,7 @@ static int r500_hw_i2c_xfer(struct radeon_i2c_chan *i2c, else { DRM_DEBUG("i2c write error 0x%08x\n", tmp); WREG32(AVIVO_DC_I2C_RESET, AVIVO_DC_I2C_ABORT); - ret = EIO; + ret = -EIO; goto done; } } @@ -867,7 +867,7 @@ done: AVIVO_DC_I2C_NACK | AVIVO_DC_I2C_HALT)); WREG32(AVIVO_DC_I2C_RESET, AVIVO_DC_I2C_SOFT_RESET); - DRM_UDELAY(1); + udelay(1); WREG32(AVIVO_DC_I2C_RESET, 0); WREG32(AVIVO_DC_I2C_ARBITRATION, AVIVO_DC_I2C_SW_DONE_USING_I2C); @@ -953,11 +953,11 @@ static int radeon_hw_i2c_xfer(device_t dev, break; default: DRM_ERROR("i2c: unhandled radeon chip\n"); - ret = EIO; + ret = -EIO; break; } - return ret; + return -ret; } static int @@ -1043,7 +1043,7 @@ struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev, return NULL; i2c = malloc(sizeof(struct radeon_i2c_chan), - DRM_MEM_DRIVER, M_ZERO | M_WAITOK); + DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); if (i2c == NULL) return NULL; @@ -1063,7 +1063,7 @@ struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev, /* set the radeon hw i2c adapter */ snprintf(i2c->name, sizeof(i2c->name), "Radeon i2c hw bus %s", name); - iicbus_dev = device_add_child(dev->device, "radeon_hw_i2c", -1); + iicbus_dev = device_add_child(dev->dev, "radeon_hw_i2c", -1); if (iicbus_dev == NULL) { DRM_ERROR("Failed to create bridge for hw i2c %s\n", name); @@ -1076,14 +1076,14 @@ struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev, if (ret != 0) { DRM_ERROR("Attach failed for bridge for hw i2c %s\n", name); - device_delete_child(dev->device, iicbus_dev); + device_delete_child(dev->dev, iicbus_dev); goto out_free; } i2c->adapter = device_find_child(iicbus_dev, "iicbus", -1); if (i2c->adapter == NULL) { DRM_ERROR("hw i2c bridge doesn't have iicbus child\n"); - device_delete_child(dev->device, iicbus_dev); + device_delete_child(dev->dev, iicbus_dev); goto out_free; } } else if (rec->hw_capable && @@ -1092,7 +1092,7 @@ struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev, /* hw i2c using atom */ snprintf(i2c->name, sizeof(i2c->name), "Radeon i2c hw bus %s", name); - iicbus_dev = device_add_child(dev->device, "radeon_atom_hw_i2c", -1); + iicbus_dev = device_add_child(dev->dev, "radeon_atom_hw_i2c", -1); if (iicbus_dev == NULL) { DRM_ERROR("Failed to create bridge for hw i2c %s\n", name); @@ -1105,14 +1105,14 @@ struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev, if (ret != 0) { DRM_ERROR("Attach failed for bridge for hw i2c %s\n", name); - device_delete_child(dev->device, iicbus_dev); + device_delete_child(dev->dev, iicbus_dev); goto out_free; } i2c->adapter = device_find_child(iicbus_dev, "iicbus", -1); if (i2c->adapter == NULL) { DRM_ERROR("hw i2c bridge doesn't have iicbus child\n"); - device_delete_child(dev->device, iicbus_dev); + device_delete_child(dev->dev, iicbus_dev); goto out_free; } } else { @@ -1121,7 +1121,7 @@ struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev, /* set the radeon bit adapter */ snprintf(i2c->name, sizeof(i2c->name), "Radeon i2c bit bus %s", name); - iicbus_dev = device_add_child(dev->device, "radeon_iicbb", -1); + iicbus_dev = device_add_child(dev->dev, "radeon_iicbb", -1); if (iicbus_dev == NULL) { DRM_ERROR("Failed to create bridge for bb i2c %s\n", name); @@ -1134,14 +1134,14 @@ struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev, if (ret != 0) { DRM_ERROR("Attach failed for bridge for bb i2c %s\n", name); - device_delete_child(dev->device, iicbus_dev); + device_delete_child(dev->dev, iicbus_dev); goto out_free; } iicbb_dev = device_find_child(iicbus_dev, "iicbb", -1); if (iicbb_dev == NULL) { DRM_ERROR("bb i2c bridge doesn't have iicbb child\n"); - device_delete_child(dev->device, iicbus_dev); + device_delete_child(dev->dev, iicbus_dev); goto out_free; } @@ -1149,7 +1149,7 @@ struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev, if (i2c->adapter == NULL) { DRM_ERROR( "bbbus bridge doesn't have iicbus grandchild\n"); - device_delete_child(dev->device, iicbus_dev); + device_delete_child(dev->dev, iicbus_dev); goto out_free; } } @@ -1174,7 +1174,7 @@ struct radeon_i2c_chan *radeon_i2c_create_dp(struct drm_device *dev, int ret; i2c = malloc(sizeof(struct radeon_i2c_chan), - DRM_MEM_DRIVER, M_ZERO | M_WAITOK); + DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); if (i2c == NULL) return NULL; @@ -1182,7 +1182,7 @@ struct radeon_i2c_chan *radeon_i2c_create_dp(struct drm_device *dev, i2c->dev = dev; snprintf(i2c->name, sizeof(i2c->name), "Radeon aux bus %s", name); - ret = iic_dp_aux_add_bus(dev->device, i2c->name, + ret = iic_dp_aux_add_bus(dev->dev, i2c->name, radeon_dp_i2c_aux_ch, i2c, &i2c->iic_bus, &i2c->adapter); if (ret) { @@ -1205,7 +1205,7 @@ void radeon_i2c_destroy(struct radeon_i2c_chan *i2c) int ret; mtx_lock(&Giant); - ret = device_delete_child(i2c->dev->device, i2c->iic_bus); + ret = device_delete_child(i2c->dev->dev, i2c->iic_bus); mtx_unlock(&Giant); KASSERT(ret == 0, ("unable to detach iic bus %s: %d", i2c->name, ret)); diff --git a/sys/dev/drm2/radeon/radeon_ioc32.c b/sys/dev/drm2/radeon/radeon_ioc32.c index ee691be95e2a..89ec8d7390d2 100644 --- a/sys/dev/drm2/radeon/radeon_ioc32.c +++ b/sys/dev/drm2/radeon/radeon_ioc32.c @@ -291,6 +291,7 @@ static int compat_radeon_irq_emit(struct drm_device *dev, void *arg, } /* The two 64-bit arches where alignof(u64)==4 in 32-bit code */ +#if defined (CONFIG_X86_64) || defined(CONFIG_IA64) typedef struct drm_radeon_setparam32 { int param; u64 value; @@ -309,6 +310,9 @@ static int compat_radeon_cp_setparam(struct drm_device *dev, void *arg, return radeon_ioctls[DRM_IOCTL_RADEON_SETPARAM].func(dev, &request, file_priv); } +#else +#define compat_radeon_cp_setparam NULL +#endif /* X86_64 || IA64 */ struct drm_ioctl_desc radeon_compat_ioctls[] = { DRM_IOCTL_DEF(DRM_RADEON_CP_INIT, compat_radeon_cp_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), @@ -322,6 +326,6 @@ struct drm_ioctl_desc radeon_compat_ioctls[] = { DRM_IOCTL_DEF(DRM_RADEON_ALLOC, compat_radeon_mem_alloc, DRM_AUTH), DRM_IOCTL_DEF(DRM_RADEON_IRQ_EMIT, compat_radeon_irq_emit, DRM_AUTH) }; -int radeon_num_compat_ioctls = DRM_ARRAY_SIZE(radeon_compat_ioctls); +int radeon_num_compat_ioctls = ARRAY_SIZE(radeon_compat_ioctls); #endif diff --git a/sys/dev/drm2/radeon/radeon_irq_kms.c b/sys/dev/drm2/radeon/radeon_irq_kms.c index a679ed192e0e..280322f162e2 100644 --- a/sys/dev/drm2/radeon/radeon_irq_kms.c +++ b/sys/dev/drm2/radeon/radeon_irq_kms.c @@ -171,18 +171,14 @@ void radeon_driver_irq_uninstall_kms(struct drm_device *dev) * Returns true if MSIs should be enabled, false if MSIs * should not be enabled. */ -int radeon_msi_ok(struct drm_device *dev, unsigned long flags) +static bool radeon_msi_ok(struct radeon_device *rdev) { - int family; - - family = flags & RADEON_FAMILY_MASK; - /* RV370/RV380 was first asic with MSI support */ - if (family < CHIP_RV380) + if (rdev->family < CHIP_RV380) return false; /* MSIs don't work on AGP */ - if (drm_device_is_agp(dev)) + if (rdev->flags & RADEON_IS_AGP) return false; /* force MSI on */ @@ -193,42 +189,42 @@ int radeon_msi_ok(struct drm_device *dev, unsigned long flags) /* Quirks */ /* HP RS690 only seems to work with MSIs. */ - if ((dev->pci_device == 0x791f) && - (dev->pci_subvendor == 0x103c) && - (dev->pci_subdevice == 0x30c2)) + if ((rdev->ddev->pci_device == 0x791f) && + (rdev->ddev->pci_subvendor == 0x103c) && + (rdev->ddev->pci_subdevice == 0x30c2)) return true; /* Dell RS690 only seems to work with MSIs. */ - if ((dev->pci_device == 0x791f) && - (dev->pci_subvendor == 0x1028) && - (dev->pci_subdevice == 0x01fc)) + if ((rdev->ddev->pci_device == 0x791f) && + (rdev->ddev->pci_subvendor == 0x1028) && + (rdev->ddev->pci_subdevice == 0x01fc)) return true; /* Dell RS690 only seems to work with MSIs. */ - if ((dev->pci_device == 0x791f) && - (dev->pci_subvendor == 0x1028) && - (dev->pci_subdevice == 0x01fd)) + if ((rdev->ddev->pci_device == 0x791f) && + (rdev->ddev->pci_subvendor == 0x1028) && + (rdev->ddev->pci_subdevice == 0x01fd)) return true; /* Gateway RS690 only seems to work with MSIs. */ - if ((dev->pci_device == 0x791f) && - (dev->pci_subvendor == 0x107b) && - (dev->pci_subdevice == 0x0185)) + if ((rdev->ddev->pci_device == 0x791f) && + (rdev->ddev->pci_subvendor == 0x107b) && + (rdev->ddev->pci_subdevice == 0x0185)) return true; /* try and enable MSIs by default on all RS690s */ - if (family == CHIP_RS690) + if (rdev->family == CHIP_RS690) return true; /* RV515 seems to have MSI issues where it loses * MSI rearms occasionally. This leads to lockups and freezes. * disable it by default. */ - if (family == CHIP_RV515) + if (rdev->family == CHIP_RV515) return false; - if (flags & RADEON_IS_IGP) { + if (rdev->flags & RADEON_IS_IGP) { /* APUs work fine with MSIs */ - if (family >= CHIP_PALM) + if (rdev->family >= CHIP_PALM) return true; /* lots of IGPs have problems with MSIs */ return false; @@ -258,12 +254,17 @@ int radeon_irq_kms_init(struct radeon_device *rdev) return r; } /* enable msi */ - rdev->msi_enabled = rdev->ddev->msi_enabled; - + rdev->msi_enabled = 0; + + if (radeon_msi_ok(rdev)) { + int ret = drm_pci_enable_msi(rdev->ddev); + if (!ret) { + rdev->msi_enabled = 1; + dev_info(rdev->dev, "radeon: using MSI.\n"); + } + } rdev->irq.installed = true; - DRM_UNLOCK(rdev->ddev); r = drm_irq_install(rdev->ddev); - DRM_LOCK(rdev->ddev); if (r) { rdev->irq.installed = false; return r; @@ -285,6 +286,8 @@ void radeon_irq_kms_fini(struct radeon_device *rdev) if (rdev->irq.installed) { drm_irq_uninstall(rdev->ddev); rdev->irq.installed = false; + if (rdev->msi_enabled) + drm_pci_disable_msi(rdev->ddev); } taskqueue_drain(rdev->tq, &rdev->hotplug_work); } @@ -401,6 +404,9 @@ void radeon_irq_kms_enable_afmt(struct radeon_device *rdev, int block) { unsigned long irqflags; + if (!rdev->ddev->irq_enabled) + return; + DRM_SPINLOCK_IRQSAVE(&rdev->irq.lock, irqflags); rdev->irq.afmt[block] = true; radeon_irq_set(rdev); @@ -420,6 +426,9 @@ void radeon_irq_kms_disable_afmt(struct radeon_device *rdev, int block) { unsigned long irqflags; + if (!rdev->ddev->irq_enabled) + return; + DRM_SPINLOCK_IRQSAVE(&rdev->irq.lock, irqflags); rdev->irq.afmt[block] = false; radeon_irq_set(rdev); @@ -439,6 +448,9 @@ void radeon_irq_kms_enable_hpd(struct radeon_device *rdev, unsigned hpd_mask) unsigned long irqflags; int i; + if (!rdev->ddev->irq_enabled) + return; + DRM_SPINLOCK_IRQSAVE(&rdev->irq.lock, irqflags); for (i = 0; i < RADEON_MAX_HPD_PINS; ++i) rdev->irq.hpd[i] |= !!(hpd_mask & (1 << i)); @@ -459,6 +471,9 @@ void radeon_irq_kms_disable_hpd(struct radeon_device *rdev, unsigned hpd_mask) unsigned long irqflags; int i; + if (!rdev->ddev->irq_enabled) + return; + DRM_SPINLOCK_IRQSAVE(&rdev->irq.lock, irqflags); for (i = 0; i < RADEON_MAX_HPD_PINS; ++i) rdev->irq.hpd[i] &= !(hpd_mask & (1 << i)); diff --git a/sys/dev/drm2/radeon/radeon_irq_kms.h b/sys/dev/drm2/radeon/radeon_irq_kms.h index 6bfb98897793..431bdaa2a745 100644 --- a/sys/dev/drm2/radeon/radeon_irq_kms.h +++ b/sys/dev/drm2/radeon/radeon_irq_kms.h @@ -10,6 +10,4 @@ void radeon_driver_irq_preinstall_kms(struct drm_device *dev); int radeon_driver_irq_postinstall_kms(struct drm_device *dev); void radeon_driver_irq_uninstall_kms(struct drm_device *dev); -int radeon_msi_ok(struct drm_device *dev, unsigned long flags); - #endif /* !defined(__RADEON_IRQ_KMS_H__) */ diff --git a/sys/dev/drm2/radeon/radeon_kms.c b/sys/dev/drm2/radeon/radeon_kms.c index 8507d016e58e..29e19df6d698 100644 --- a/sys/dev/drm2/radeon/radeon_kms.c +++ b/sys/dev/drm2/radeon/radeon_kms.c @@ -52,9 +52,13 @@ int radeon_driver_unload_kms(struct drm_device *dev) if (rdev == NULL) return 0; + if (rdev->rmmio == NULL) + goto done_free; radeon_acpi_fini(rdev); radeon_modeset_fini(rdev); radeon_device_fini(rdev); + +done_free: free(rdev, DRM_MEM_DRIVER); dev->dev_private = NULL; return 0; @@ -78,17 +82,17 @@ int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags) struct radeon_device *rdev; int r, acpi_status; - rdev = malloc(sizeof(struct radeon_device), DRM_MEM_DRIVER, M_ZERO | M_WAITOK); + rdev = malloc(sizeof(struct radeon_device), DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); if (rdev == NULL) { return -ENOMEM; } dev->dev_private = (void *)rdev; /* update BUS flag */ - if (drm_device_is_agp(dev)) { + if (drm_pci_device_is_agp(dev)) { DRM_INFO("RADEON_IS_AGP\n"); flags |= RADEON_IS_AGP; - } else if (drm_device_is_pcie(dev)) { + } else if (drm_pci_device_is_pcie(dev)) { DRM_INFO("RADEON_IS_PCIE\n"); flags |= RADEON_IS_PCIE; } else { @@ -104,7 +108,7 @@ int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags) */ r = radeon_device_init(rdev, dev, flags); if (r) { - dev_err(dev->device, "Fatal error during GPU init\n"); + dev_err(dev->dev, "Fatal error during GPU init\n"); goto out; } @@ -114,7 +118,7 @@ int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags) */ r = radeon_modeset_init(rdev); if (r) - dev_err(dev->device, "Fatal error during modeset init\n"); + dev_err(dev->dev, "Fatal error during modeset init\n"); /* Call ACPI methods: require modeset init * but failure is not fatal @@ -122,7 +126,7 @@ int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags) if (!r) { acpi_status = radeon_acpi_init(rdev); if (acpi_status) - dev_dbg(dev->device, + dev_dbg(dev->dev, "Error during ACPI methods call\n"); } @@ -419,9 +423,9 @@ int radeon_driver_firstopen_kms(struct drm_device *dev) */ void radeon_driver_lastclose_kms(struct drm_device *dev) { -#ifdef DUMBBELL_WIP +#ifdef FREEBSD_WIP vga_switcheroo_process_delayed_switch(); -#endif /* DUMBBELL_WIP */ +#endif /* FREEBSD_WIP */ } /** @@ -445,7 +449,7 @@ int radeon_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv) struct radeon_bo_va *bo_va; int r; - fpriv = malloc(sizeof(*fpriv), DRM_MEM_DRIVER, M_ZERO | M_WAITOK); + fpriv = malloc(sizeof(*fpriv), DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); if (unlikely(!fpriv)) { return -ENOMEM; } @@ -724,4 +728,4 @@ struct drm_ioctl_desc radeon_ioctls_kms[] = { DRM_IOCTL_DEF_DRV(RADEON_GEM_BUSY, radeon_gem_busy_ioctl, DRM_AUTH|DRM_UNLOCKED), DRM_IOCTL_DEF_DRV(RADEON_GEM_VA, radeon_gem_va_ioctl, DRM_AUTH|DRM_UNLOCKED), }; -int radeon_max_kms_ioctl = DRM_ARRAY_SIZE(radeon_ioctls_kms); +int radeon_max_kms_ioctl = ARRAY_SIZE(radeon_ioctls_kms); diff --git a/sys/dev/drm2/radeon/radeon_legacy_crtc.c b/sys/dev/drm2/radeon/radeon_legacy_crtc.c index 54f755a6097a..282f2005bdc4 100644 --- a/sys/dev/drm2/radeon/radeon_legacy_crtc.c +++ b/sys/dev/drm2/radeon/radeon_legacy_crtc.c @@ -883,7 +883,7 @@ static void radeon_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) (unsigned)((pll_fb_post_div & RADEON_P2PLL_POST0_DIV_MASK) >> 16)); - DRM_MDELAY(50); /* Let the clock to lock */ + mdelay(50); /* Let the clock to lock */ WREG32_PLL_P(RADEON_PIXCLKS_CNTL, RADEON_PIX2CLK_SRC_SEL_P2PLLCLK, @@ -988,7 +988,7 @@ static void radeon_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) pll_fb_post_div & RADEON_PPLL_FB3_DIV_MASK, (pll_fb_post_div & RADEON_PPLL_POST3_DIV_MASK) >> 16); - DRM_MDELAY(50); /* Let the clock to lock */ + mdelay(50); /* Let the clock to lock */ WREG32_PLL_P(RADEON_VCLK_ECP_CNTL, RADEON_VCLK_SRC_SEL_PPLLCLK, diff --git a/sys/dev/drm2/radeon/radeon_legacy_encoders.c b/sys/dev/drm2/radeon/radeon_legacy_encoders.c index a4e6e284c3bd..d0db92f93fae 100644 --- a/sys/dev/drm2/radeon/radeon_legacy_encoders.c +++ b/sys/dev/drm2/radeon/radeon_legacy_encoders.c @@ -89,7 +89,7 @@ static void radeon_legacy_lvds_update(struct drm_encoder *encoder, int mode) lvds_pll_cntl = RREG32(RADEON_LVDS_PLL_CNTL); lvds_pll_cntl |= RADEON_LVDS_PLL_EN; WREG32(RADEON_LVDS_PLL_CNTL, lvds_pll_cntl); - DRM_MDELAY(1); + mdelay(1); lvds_pll_cntl = RREG32(RADEON_LVDS_PLL_CNTL); lvds_pll_cntl &= ~RADEON_LVDS_PLL_RESET; @@ -102,7 +102,7 @@ static void radeon_legacy_lvds_update(struct drm_encoder *encoder, int mode) (backlight_level << RADEON_LVDS_BL_MOD_LEVEL_SHIFT)); if (is_mac) lvds_gen_cntl |= RADEON_LVDS_BL_MOD_EN; - DRM_MDELAY(panel_pwr_delay); + mdelay(panel_pwr_delay); WREG32(RADEON_LVDS_GEN_CNTL, lvds_gen_cntl); break; case DRM_MODE_DPMS_STANDBY: @@ -119,10 +119,10 @@ static void radeon_legacy_lvds_update(struct drm_encoder *encoder, int mode) WREG32(RADEON_LVDS_GEN_CNTL, lvds_gen_cntl); lvds_gen_cntl &= ~(RADEON_LVDS_ON | RADEON_LVDS_BLON | RADEON_LVDS_EN | RADEON_LVDS_DIGON); } - DRM_MDELAY(panel_pwr_delay); + mdelay(panel_pwr_delay); WREG32(RADEON_LVDS_GEN_CNTL, lvds_gen_cntl); WREG32_PLL(RADEON_PIXCLKS_CNTL, pixclks_cntl); - DRM_MDELAY(panel_pwr_delay); + mdelay(panel_pwr_delay); break; } @@ -245,7 +245,7 @@ static void radeon_legacy_lvds_mode_set(struct drm_encoder *encoder, } static bool radeon_legacy_mode_fixup(struct drm_encoder *encoder, - struct drm_display_mode *mode, + const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); @@ -383,7 +383,7 @@ void radeon_legacy_backlight_init(struct radeon_encoder *radeon_encoder, #endif pdata = malloc(sizeof(struct radeon_backlight_privdata), - DRM_MEM_DRIVER, M_WAITOK); + DRM_MEM_DRIVER, M_NOWAIT); if (!pdata) { DRM_ERROR("Memory allocation failed\n"); goto error; @@ -693,7 +693,7 @@ static enum drm_connector_status radeon_legacy_primary_dac_detect(struct drm_enc WREG32(RADEON_DAC_MACRO_CNTL, tmp); - DRM_MDELAY(2); + mdelay(2); if (RREG32(RADEON_DAC_CNTL) & RADEON_DAC_CMP_OUTPUT) found = connector_status_connected; @@ -1338,7 +1338,7 @@ static bool r300_legacy_tv_detect(struct drm_encoder *encoder, (6 << RADEON_TV_DAC_DACADJ_SHIFT)); RREG32(RADEON_TV_DAC_CNTL); - DRM_MDELAY(4); + mdelay(4); WREG32(RADEON_TV_DAC_CNTL, RADEON_TV_DAC_NBLANK | @@ -1349,7 +1349,7 @@ static bool r300_legacy_tv_detect(struct drm_encoder *encoder, (6 << RADEON_TV_DAC_DACADJ_SHIFT)); RREG32(RADEON_TV_DAC_CNTL); - DRM_MDELAY(6); + mdelay(6); tmp = RREG32(RADEON_TV_DAC_CNTL); if ((tmp & RADEON_TV_DAC_GDACDET) != 0) { @@ -1416,7 +1416,7 @@ static bool radeon_legacy_tv_detect(struct drm_encoder *encoder, (0x109 << RADEON_TV_FORCE_DAC_DATA_SHIFT); WREG32(RADEON_TV_PRE_DAC_MUX_CNTL, tmp); - DRM_MDELAY(3); + mdelay(3); tmp = RREG32(RADEON_TV_DAC_CNTL); if (tmp & RADEON_TV_DAC_GDACDET) { found = true; @@ -1498,9 +1498,8 @@ static bool radeon_legacy_ext_dac_detect(struct drm_encoder *encoder, if (found) break; - DRM_MDELAY(1); if (!drm_can_sleep()) - DRM_MDELAY(1); + mdelay(1); else DRM_MSLEEP(1); } @@ -1642,7 +1641,7 @@ static enum drm_connector_status radeon_legacy_tv_dac_detect(struct drm_encoder tmp = dac_cntl2 | RADEON_DAC2_DAC2_CLK_SEL | RADEON_DAC2_CMP_EN; WREG32(RADEON_DAC_CNTL2, tmp); - DRM_MDELAY(10); + mdelay(10); if (ASIC_IS_R300(rdev)) { if (RREG32(RADEON_DAC_CNTL2) & RADEON_DAC2_CMP_OUT_B) @@ -1699,7 +1698,7 @@ static struct radeon_encoder_int_tmds *radeon_legacy_get_tmds_info(struct radeon bool ret; tmds = malloc(sizeof(struct radeon_encoder_int_tmds), - DRM_MEM_DRIVER, M_ZERO | M_WAITOK); + DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); if (!tmds) return NULL; @@ -1726,7 +1725,7 @@ static struct radeon_encoder_ext_tmds *radeon_legacy_get_ext_tmds_info(struct ra return NULL; tmds = malloc(sizeof(struct radeon_encoder_ext_tmds), - DRM_MEM_DRIVER, M_ZERO | M_WAITOK); + DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); if (!tmds) return NULL; @@ -1758,7 +1757,7 @@ radeon_add_legacy_encoder(struct drm_device *dev, uint32_t encoder_enum, uint32_ /* add a new one */ radeon_encoder = malloc(sizeof(struct radeon_encoder), - DRM_MEM_DRIVER, M_ZERO | M_WAITOK); + DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); if (!radeon_encoder) return; diff --git a/sys/dev/drm2/radeon/radeon_legacy_tv.c b/sys/dev/drm2/radeon/radeon_legacy_tv.c index 5311a48a56ec..c124a74eb02b 100644 --- a/sys/dev/drm2/radeon/radeon_legacy_tv.c +++ b/sys/dev/drm2/radeon/radeon_legacy_tv.c @@ -232,7 +232,7 @@ static const struct radeon_tv_mode_constants available_tv_modes[] = { }, }; -#define N_AVAILABLE_MODES DRM_ARRAY_SIZE(available_tv_modes) +#define N_AVAILABLE_MODES ARRAY_SIZE(available_tv_modes) static const struct radeon_tv_mode_constants *radeon_legacy_tv_get_std_mode(struct radeon_encoder *radeon_encoder, uint16_t *pll_ref_freq) @@ -647,7 +647,7 @@ void radeon_legacy_tv_mode_set(struct drm_encoder *encoder, if (flicker_removal < 3) flicker_removal = 3; - for (i = 0; i < DRM_ARRAY_SIZE(SLOPE_limit); ++i) { + for (i = 0; i < ARRAY_SIZE(SLOPE_limit); ++i) { if (flicker_removal == SLOPE_limit[i]) break; } diff --git a/sys/dev/drm2/radeon/radeon_mem.c b/sys/dev/drm2/radeon/radeon_mem.c index 9ff87911373f..b14c0cec7600 100644 --- a/sys/dev/drm2/radeon/radeon_mem.c +++ b/sys/dev/drm2/radeon/radeon_mem.c @@ -46,7 +46,7 @@ static struct mem_block *split_block(struct mem_block *p, int start, int size, /* Maybe cut off the start of an existing block */ if (start > p->start) { struct mem_block *newblock = malloc(sizeof(*newblock), - DRM_MEM_DRIVER, M_WAITOK); + DRM_MEM_DRIVER, M_NOWAIT); if (!newblock) goto out; newblock->start = start; @@ -63,7 +63,7 @@ static struct mem_block *split_block(struct mem_block *p, int start, int size, /* Maybe cut off the end of an existing block */ if (size < p->size) { struct mem_block *newblock = malloc(sizeof(*newblock), - DRM_MEM_DRIVER, M_WAITOK); + DRM_MEM_DRIVER, M_NOWAIT); if (!newblock) goto out; newblock->start = start + size; @@ -137,12 +137,12 @@ static void free_block(struct mem_block *p) static int init_heap(struct mem_block **heap, int start, int size) { struct mem_block *blocks = malloc(sizeof(*blocks), - DRM_MEM_DRIVER, M_WAITOK); + DRM_MEM_DRIVER, M_NOWAIT); if (!blocks) return -ENOMEM; - *heap = malloc(sizeof(**heap), DRM_MEM_DRIVER, M_ZERO | M_WAITOK); + *heap = malloc(sizeof(**heap), DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); if (!*heap) { free(blocks, DRM_MEM_DRIVER); return -ENOMEM; diff --git a/sys/dev/drm2/radeon/radeon_object.c b/sys/dev/drm2/radeon/radeon_object.c index 30d3d81c82ae..eadfe74e0e22 100644 --- a/sys/dev/drm2/radeon/radeon_object.c +++ b/sys/dev/drm2/radeon/radeon_object.c @@ -36,11 +36,15 @@ __FBSDID("$FreeBSD$"); #include <dev/drm2/drmP.h> #include <dev/drm2/radeon/radeon_drm.h> #include "radeon.h" -#ifdef DUMBBELL_WIP +#ifdef FREEBSD_WIP #include "radeon_trace.h" -#endif /* DUMBBELL_WIP */ +#endif /* FREEBSD_WIP */ +#ifdef FREEBSD_WIP /* FreeBSD: to please GCC 4.2. */ +int radeon_ttm_init(struct radeon_device *rdev); +void radeon_ttm_fini(struct radeon_device *rdev); +#endif static void radeon_bo_clear_surface_reg(struct radeon_bo *bo); /* @@ -135,7 +139,7 @@ int radeon_bo_create(struct radeon_device *rdev, sizeof(struct radeon_bo)); bo = malloc(sizeof(struct radeon_bo), - DRM_MEM_DRIVER, M_ZERO | M_WAITOK); + DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); if (bo == NULL) return -ENOMEM; r = drm_gem_object_init(rdev->ddev, &bo->gem_base, size); @@ -160,9 +164,9 @@ int radeon_bo_create(struct radeon_device *rdev, } *bo_ptr = bo; -#ifdef DUMBBELL_WIP +#ifdef FREEBSD_WIP trace_radeon_bo_create(bo); -#endif /* DUMBBELL_WIP */ +#endif /* FREEBSD_WIP */ return 0; } @@ -315,6 +319,7 @@ void radeon_bo_force_delete(struct radeon_device *rdev) } dev_err(rdev->dev, "Userspace still has active objects !\n"); list_for_each_entry_safe(bo, n, &rdev->gem.objects, list) { + DRM_LOCK(rdev->ddev); dev_err(rdev->dev, "%p %p %lu %lu force free\n", &bo->gem_base, bo, (unsigned long)bo->gem_base.size, *((unsigned long *)&bo->gem_base.refcount)); @@ -323,6 +328,7 @@ void radeon_bo_force_delete(struct radeon_device *rdev) sx_xunlock(&bo->rdev->gem.mutex); /* this should unref the ttm bo */ drm_gem_object_unreference(&bo->gem_base); + DRM_UNLOCK(rdev->ddev); } } @@ -388,13 +394,13 @@ int radeon_bo_list_validate(struct list_head *head) return 0; } -#ifdef DUMBBELL_WIP +#ifdef FREEBSD_WIP int radeon_bo_fbdev_mmap(struct radeon_bo *bo, struct vm_area_struct *vma) { return ttm_fbdev_mmap(vma, &bo->tbo); } -#endif /* DUMBBELL_WIP */ +#endif /* FREEBSD_WIP */ int radeon_bo_get_surface_reg(struct radeon_bo *bo) { diff --git a/sys/dev/drm2/radeon/radeon_object.h b/sys/dev/drm2/radeon/radeon_object.h index efb7149b8672..c115514cf8b8 100644 --- a/sys/dev/drm2/radeon/radeon_object.h +++ b/sys/dev/drm2/radeon/radeon_object.h @@ -139,10 +139,10 @@ extern void radeon_bo_fini(struct radeon_device *rdev); extern void radeon_bo_list_add_object(struct radeon_bo_list *lobj, struct list_head *head); extern int radeon_bo_list_validate(struct list_head *head); -#ifdef DUMBBELL_WIP +#ifdef FREEBSD_WIP extern int radeon_bo_fbdev_mmap(struct radeon_bo *bo, struct vm_area_struct *vma); -#endif /* DUMBBELL_WIP */ +#endif /* FREEBSD_WIP */ extern int radeon_bo_set_tiling_flags(struct radeon_bo *bo, u32 tiling_flags, u32 pitch); extern void radeon_bo_get_tiling_flags(struct radeon_bo *bo, diff --git a/sys/dev/drm2/radeon/radeon_pm.c b/sys/dev/drm2/radeon/radeon_pm.c index 0caa1b740247..18d800334be4 100644 --- a/sys/dev/drm2/radeon/radeon_pm.c +++ b/sys/dev/drm2/radeon/radeon_pm.c @@ -41,9 +41,9 @@ static const char *radeon_pm_state_type_name[5] = { "Performance", }; -#ifdef DUMBBELL_WIP +#ifdef FREEBSD_WIP static void radeon_dynpm_idle_work_handler(struct work_struct *work); -#endif /* DUMBBELL_WIP */ +#endif /* FREEBSD_WIP */ static int radeon_debugfs_pm_init(struct radeon_device *rdev); static bool radeon_pm_in_vbl(struct radeon_device *rdev); static bool radeon_pm_debug_check_in_vbl(struct radeon_device *rdev, bool finish); @@ -87,7 +87,7 @@ static void radeon_pm_update_profile(struct radeon_device *rdev) rdev->pm.profile_index = PM_PROFILE_DEFAULT_IDX; break; case PM_PROFILE_AUTO: -#ifdef DUMBBELL_WIP +#ifdef FREEBSD_WIP if (power_supply_is_system_supplied() > 0) { if (rdev->pm.active_crtc_count > 1) rdev->pm.profile_index = PM_PROFILE_HIGH_MH_IDX; @@ -99,7 +99,7 @@ static void radeon_pm_update_profile(struct radeon_device *rdev) else rdev->pm.profile_index = PM_PROFILE_MID_SH_IDX; } -#endif /* DUMBBELL_WIP */ +#endif /* FREEBSD_WIP */ break; case PM_PROFILE_LOW: if (rdev->pm.active_crtc_count > 1) @@ -151,11 +151,11 @@ static void radeon_sync_with_vblank(struct radeon_device *rdev) { if (rdev->pm.active_crtcs) { rdev->pm.vblank_sync = false; -#ifdef DUMBBELL_WIP +#ifdef FREEBSD_WIP wait_event_timeout( rdev->irq.vblank_queue, rdev->pm.vblank_sync, msecs_to_jiffies(RADEON_WAIT_VBLANK_TIMEOUT)); -#endif /* DUMBBELL_WIP */ +#endif /* FREEBSD_WIP */ } } @@ -176,7 +176,7 @@ static void radeon_set_power_state(struct radeon_device *rdev) /* starting with BTC, there is one state that is used for both * MH and SH. Difference is that we always use the high clock index for - * mclk. + * mclk and vddci. */ if ((rdev->pm.pm_method == PM_METHOD_PROFILE) && (rdev->family >= CHIP_BARTS) && @@ -248,7 +248,7 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev) (rdev->pm.requested_power_state_index == rdev->pm.current_power_state_index)) return; - //DRM_LOCK(rdev->ddev); XXX Recursion, already locked in drm_attach/drm_load -- dumbbell@ + DRM_LOCK(rdev->ddev); sx_xlock(&rdev->pm.mclk_lock); sx_xlock(&rdev->ring_lock); @@ -263,7 +263,7 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev) /* needs a GPU reset dont reset here */ sx_xunlock(&rdev->ring_lock); sx_xunlock(&rdev->pm.mclk_lock); - //DRM_UNLOCK(rdev->ddev); XXX Recursion, already locked in drm_attach/drm_load -- dumbbell@ + DRM_UNLOCK(rdev->ddev); return; } } @@ -299,7 +299,7 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev) sx_xunlock(&rdev->ring_lock); sx_xunlock(&rdev->pm.mclk_lock); - //DRM_UNLOCK(rdev->ddev); XXX Recursion, already locked in drm_attach/drm_load -- dumbbell@ + DRM_UNLOCK(rdev->ddev); } static void radeon_pm_print_states(struct radeon_device *rdev) @@ -336,7 +336,7 @@ static void radeon_pm_print_states(struct radeon_device *rdev) } } -#ifdef DUMBBELL_WIP +#ifdef FREEBSD_WIP static ssize_t radeon_get_pm_profile(struct device *dev, struct device_attribute *attr, char *buf) @@ -421,9 +421,9 @@ static ssize_t radeon_set_pm_method(struct device *dev, rdev->pm.dynpm_planned_action = DYNPM_ACTION_NONE; rdev->pm.pm_method = PM_METHOD_PROFILE; sx_xunlock(&rdev->pm.mutex); -#ifdef DUMBBELL_WIP +#ifdef FREEBSD_WIP cancel_delayed_work_sync(&rdev->pm.dynpm_idle_work); -#endif /* DUMBBELL_WIP */ +#endif /* FREEBSD_WIP */ } else { count = -EINVAL; goto fail; @@ -488,15 +488,15 @@ static struct attribute *hwmon_attributes[] = { static const struct attribute_group hwmon_attrgroup = { .attrs = hwmon_attributes, }; -#endif /* DUMBBELL_WIP */ +#endif /* FREEBSD_WIP */ static int radeon_hwmon_init(struct radeon_device *rdev) { int err = 0; -#ifdef DUMBBELL_WIP +#ifdef FREEBSD_WIP rdev->pm.int_hwmon_dev = NULL; -#endif /* DUMBBELL_WIP */ +#endif /* FREEBSD_WIP */ switch (rdev->pm.int_thermal_type) { case THERMAL_TYPE_RV6XX: @@ -508,7 +508,7 @@ static int radeon_hwmon_init(struct radeon_device *rdev) /* No support for TN yet */ if (rdev->family == CHIP_ARUBA) return err; -#ifdef DUMBBELL_WIP +#ifdef FREEBSD_WIP rdev->pm.int_hwmon_dev = hwmon_device_register(rdev->dev); if (IS_ERR(rdev->pm.int_hwmon_dev)) { err = PTR_ERR(rdev->pm.int_hwmon_dev); @@ -524,7 +524,7 @@ static int radeon_hwmon_init(struct radeon_device *rdev) "Unable to create hwmon sysfs file: %d\n", err); hwmon_device_unregister(rdev->dev); } -#endif /* DUMBBELL_WIP */ +#endif /* FREEBSD_WIP */ break; default: break; @@ -535,12 +535,12 @@ static int radeon_hwmon_init(struct radeon_device *rdev) static void radeon_hwmon_fini(struct radeon_device *rdev) { -#ifdef DUMBBELL_WIP +#ifdef FREEBSD_WIP if (rdev->pm.int_hwmon_dev) { sysfs_remove_group(&rdev->pm.int_hwmon_dev->kobj, &hwmon_attrgroup); hwmon_device_unregister(rdev->pm.int_hwmon_dev); } -#endif /* DUMBBELL_WIP */ +#endif /* FREEBSD_WIP */ } void radeon_pm_suspend(struct radeon_device *rdev) @@ -552,9 +552,9 @@ void radeon_pm_suspend(struct radeon_device *rdev) } sx_xunlock(&rdev->pm.mutex); -#ifdef DUMBBELL_WIP +#ifdef FREEBSD_WIP cancel_delayed_work_sync(&rdev->pm.dynpm_idle_work); -#endif /* DUMBBELL_WIP */ +#endif /* FREEBSD_WIP */ } void radeon_pm_resume(struct radeon_device *rdev) @@ -585,10 +585,10 @@ void radeon_pm_resume(struct radeon_device *rdev) if (rdev->pm.pm_method == PM_METHOD_DYNPM && rdev->pm.dynpm_state == DYNPM_STATE_SUSPENDED) { rdev->pm.dynpm_state = DYNPM_STATE_ACTIVE; -#ifdef DUMBBELL_WIP +#ifdef FREEBSD_WIP schedule_delayed_work(&rdev->pm.dynpm_idle_work, msecs_to_jiffies(RADEON_IDLE_LOOP_MS)); -#endif /* DUMBBELL_WIP */ +#endif /* FREEBSD_WIP */ } sx_xunlock(&rdev->pm.mutex); radeon_pm_compute_clocks(rdev); @@ -640,20 +640,20 @@ int radeon_pm_init(struct radeon_device *rdev) if (ret) return ret; -#ifdef DUMBBELL_WIP +#ifdef FREEBSD_WIP INIT_DELAYED_WORK(&rdev->pm.dynpm_idle_work, radeon_dynpm_idle_work_handler); -#endif /* DUMBBELL_WIP */ +#endif /* FREEBSD_WIP */ if (rdev->pm.num_power_states > 1) { /* where's the best place to put these? */ -#ifdef DUMBBELL_WIP +#ifdef FREEBSD_WIP ret = device_create_file(rdev->dev, &dev_attr_power_profile); -#endif /* DUMBBELL_WIP */ +#endif /* FREEBSD_WIP */ if (ret) DRM_ERROR("failed to create device file for power profile\n"); -#ifdef DUMBBELL_WIP +#ifdef FREEBSD_WIP ret = device_create_file(rdev->dev, &dev_attr_power_method); -#endif /* DUMBBELL_WIP */ +#endif /* FREEBSD_WIP */ if (ret) DRM_ERROR("failed to create device file for power method\n"); @@ -670,7 +670,6 @@ int radeon_pm_init(struct radeon_device *rdev) void radeon_pm_fini(struct radeon_device *rdev) { if (rdev->pm.num_power_states > 1) { - DRM_UNLOCK(rdev->ddev); /* Work around LOR. */ sx_xlock(&rdev->pm.mutex); if (rdev->pm.pm_method == PM_METHOD_PROFILE) { rdev->pm.profile = PM_PROFILE_DEFAULT; @@ -683,14 +682,13 @@ void radeon_pm_fini(struct radeon_device *rdev) radeon_pm_set_clocks(rdev); } sx_xunlock(&rdev->pm.mutex); - DRM_LOCK(rdev->ddev); -#ifdef DUMBBELL_WIP +#ifdef FREEBSD_WIP cancel_delayed_work_sync(&rdev->pm.dynpm_idle_work); device_remove_file(rdev->dev, &dev_attr_power_profile); device_remove_file(rdev->dev, &dev_attr_power_method); -#endif /* DUMBBELL_WIP */ +#endif /* FREEBSD_WIP */ } if (rdev->pm.power_state) { @@ -735,9 +733,9 @@ void radeon_pm_compute_clocks(struct radeon_device *rdev) if (rdev->pm.dynpm_state != DYNPM_STATE_DISABLED) { if (rdev->pm.active_crtc_count > 1) { if (rdev->pm.dynpm_state == DYNPM_STATE_ACTIVE) { -#ifdef DUMBBELL_WIP +#ifdef FREEBSD_WIP cancel_delayed_work(&rdev->pm.dynpm_idle_work); -#endif /* DUMBBELL_WIP */ +#endif /* FREEBSD_WIP */ rdev->pm.dynpm_state = DYNPM_STATE_PAUSED; rdev->pm.dynpm_planned_action = DYNPM_ACTION_DEFAULT; @@ -755,23 +753,23 @@ void radeon_pm_compute_clocks(struct radeon_device *rdev) radeon_pm_get_dynpm_state(rdev); radeon_pm_set_clocks(rdev); -#ifdef DUMBBELL_WIP +#ifdef FREEBSD_WIP schedule_delayed_work(&rdev->pm.dynpm_idle_work, msecs_to_jiffies(RADEON_IDLE_LOOP_MS)); -#endif /* DUMBBELL_WIP */ +#endif /* FREEBSD_WIP */ } else if (rdev->pm.dynpm_state == DYNPM_STATE_PAUSED) { rdev->pm.dynpm_state = DYNPM_STATE_ACTIVE; -#ifdef DUMBBELL_WIP +#ifdef FREEBSD_WIP schedule_delayed_work(&rdev->pm.dynpm_idle_work, msecs_to_jiffies(RADEON_IDLE_LOOP_MS)); -#endif /* DUMBBELL_WIP */ +#endif /* FREEBSD_WIP */ DRM_DEBUG_DRIVER("radeon: dynamic power management activated\n"); } } else { /* count == 0 */ if (rdev->pm.dynpm_state != DYNPM_STATE_MINIMUM) { -#ifdef DUMBBELL_WIP +#ifdef FREEBSD_WIP cancel_delayed_work(&rdev->pm.dynpm_idle_work); -#endif /* DUMBBELL_WIP */ +#endif /* FREEBSD_WIP */ rdev->pm.dynpm_state = DYNPM_STATE_MINIMUM; rdev->pm.dynpm_planned_action = DYNPM_ACTION_MINIMUM; @@ -816,7 +814,7 @@ static bool radeon_pm_debug_check_in_vbl(struct radeon_device *rdev, bool finish return in_vbl; } -#ifdef DUMBBELL_WIP +#ifdef FREEBSD_WIP static void radeon_dynpm_idle_work_handler(struct work_struct *work) { struct radeon_device *rdev; @@ -877,7 +875,7 @@ static void radeon_dynpm_idle_work_handler(struct work_struct *work) sx_xunlock(&rdev->pm.mutex); ttm_bo_unlock_delayed_workqueue(&rdev->mman.bdev, resched); } -#endif /* DUMBBELL_WIP */ +#endif /* FREEBSD_WIP */ /* * Debugfs info @@ -891,7 +889,11 @@ static int radeon_debugfs_pm_info(struct seq_file *m, void *data) struct radeon_device *rdev = dev->dev_private; seq_printf(m, "default engine clock: %u0 kHz\n", rdev->pm.default_sclk); - seq_printf(m, "current engine clock: %u0 kHz\n", radeon_get_engine_clock(rdev)); + /* radeon_get_engine_clock is not reliable on APUs so just print the current clock */ + if ((rdev->family >= CHIP_PALM) && (rdev->flags & RADEON_IS_IGP)) + seq_printf(m, "current engine clock: %u0 kHz\n", rdev->pm.current_sclk); + else + seq_printf(m, "current engine clock: %u0 kHz\n", radeon_get_engine_clock(rdev)); seq_printf(m, "default memory clock: %u0 kHz\n", rdev->pm.default_mclk); if (rdev->asic->pm.get_memory_clock) seq_printf(m, "current memory clock: %u0 kHz\n", radeon_get_memory_clock(rdev)); diff --git a/sys/dev/drm2/radeon/radeon_ring.c b/sys/dev/drm2/radeon/radeon_ring.c index 37d0adee8796..387182ac5273 100644 --- a/sys/dev/drm2/radeon/radeon_ring.c +++ b/sys/dev/drm2/radeon/radeon_ring.c @@ -36,7 +36,7 @@ __FBSDID("$FreeBSD$"); #include "radeon.h" #include "atom.h" -#ifdef DUMBBELL_WIP +#ifdef FREEBSD_WIP /* * IB * IBs (Indirect Buffers) and areas of GPU accessible memory where @@ -47,7 +47,7 @@ __FBSDID("$FreeBSD$"); * put in IBs for execution by the requested ring. */ static int radeon_debugfs_sa_init(struct radeon_device *rdev); -#endif /* DUMBBELL_WIP */ +#endif /* FREEBSD_WIP */ /** * radeon_ib_get - request an IB (Indirect Buffer) @@ -165,7 +165,8 @@ int radeon_ib_schedule(struct radeon_device *rdev, struct radeon_ib *ib, radeon_semaphore_free(rdev, &ib->semaphore, NULL); } /* if we can't remember our last VM flush then flush now! */ - if (ib->vm && !ib->vm->last_flush) { + /* XXX figure out why we have to flush for every IB */ + if (ib->vm /*&& !ib->vm->last_flush*/) { radeon_ring_vm_flush(rdev, ib->ring, ib->vm); } if (const_ib) { @@ -219,11 +220,11 @@ int radeon_ib_pool_init(struct radeon_device *rdev) } rdev->ib_pool_ready = true; -#ifdef DUMBBELL_WIP +#ifdef FREEBSD_WIP if (radeon_debugfs_sa_init(rdev)) { dev_err(rdev->dev, "failed to register debugfs file for SA\n"); } -#endif /* DUMBBELL_WIP */ +#endif /* FREEBSD_WIP */ return 0; } @@ -284,7 +285,7 @@ int radeon_ib_ring_tests(struct radeon_device *rdev) return 0; } -#ifdef DUMBBELL_WIP +#ifdef FREEBSD_WIP /* * Rings * Most engines on the GPU are fed via ring buffers. Ring @@ -299,9 +300,8 @@ int radeon_ib_ring_tests(struct radeon_device *rdev) * them until the pointers are equal again. */ static int radeon_debugfs_ring_init(struct radeon_device *rdev, struct radeon_ring *ring); -#endif /* DUMBBELL_WIP */ +#endif /* FREEBSD_WIP */ -#if defined(DRM_DEBUG_CODE) && DRM_DEBUG_CODE != 0 /** * radeon_ring_write - write a value to the ring * @@ -322,7 +322,6 @@ void radeon_ring_write(struct radeon_ring *ring, uint32_t v) ring->count_dw--; ring->ring_free_dw--; } -#endif /** * radeon_ring_supports_scratch_reg - check if the ring supports @@ -623,7 +622,7 @@ unsigned radeon_ring_backup(struct radeon_device *rdev, struct radeon_ring *ring } /* and then save the content of the ring */ - *data = malloc(size * sizeof(uint32_t), DRM_MEM_DRIVER, M_WAITOK); + *data = malloc(size * sizeof(uint32_t), DRM_MEM_DRIVER, M_NOWAIT); if (!*data) { sx_xunlock(&rdev->ring_lock); return 0; @@ -690,7 +689,7 @@ int radeon_ring_init(struct radeon_device *rdev, struct radeon_ring *ring, unsig u32 ptr_reg_shift, u32 ptr_reg_mask, u32 nop) { int r; - void *ring_ptr; + void *ring_ptr; /* FreeBSD: to please GCC 4.2. */ ring->ring_size = ring_size; ring->rptr_offs = rptr_offs; @@ -738,11 +737,11 @@ int radeon_ring_init(struct radeon_device *rdev, struct radeon_ring *ring, unsig ring->next_rptr_gpu_addr = rdev->wb.gpu_addr + index; ring->next_rptr_cpu_addr = &rdev->wb.wb[index/4]; } -#ifdef DUMBBELL_WIP +#ifdef FREEBSD_WIP if (radeon_debugfs_ring_init(rdev, ring)) { DRM_ERROR("Failed to register debugfs file for rings !\n"); } -#endif /* DUMBBELL_WIP */ +#endif /* FREEBSD_WIP */ radeon_ring_lockup_update(ring); return 0; } @@ -852,7 +851,7 @@ static struct drm_info_list radeon_debugfs_sa_list[] = { #endif -#ifdef DUMBBELL_WIP +#ifdef FREEBSD_WIP static int radeon_debugfs_ring_init(struct radeon_device *rdev, struct radeon_ring *ring) { #if defined(CONFIG_DEBUG_FS) @@ -881,4 +880,4 @@ static int radeon_debugfs_sa_init(struct radeon_device *rdev) return 0; #endif } -#endif /* DUMBBELL_WIP */ +#endif /* FREEBSD_WIP */ diff --git a/sys/dev/drm2/radeon/radeon_sa.c b/sys/dev/drm2/radeon/radeon_sa.c index 25695a42d9ef..929061276d04 100644 --- a/sys/dev/drm2/radeon/radeon_sa.c +++ b/sys/dev/drm2/radeon/radeon_sa.c @@ -327,7 +327,7 @@ int radeon_sa_bo_new(struct radeon_device *rdev, KASSERT(align <= RADEON_GPU_PAGE_SIZE, ("align > RADEON_GPU_PAGE_SIZE")); KASSERT(size <= sa_manager->size, ("size > sa_manager->size")); - *sa_bo = malloc(sizeof(struct radeon_sa_bo), DRM_MEM_DRIVER, M_WAITOK); + *sa_bo = malloc(sizeof(struct radeon_sa_bo), DRM_MEM_DRIVER, M_NOWAIT); if ((*sa_bo) == NULL) { return -ENOMEM; } diff --git a/sys/dev/drm2/radeon/radeon_semaphore.c b/sys/dev/drm2/radeon/radeon_semaphore.c index 717a94a482db..ecd09dda3c2b 100644 --- a/sys/dev/drm2/radeon/radeon_semaphore.c +++ b/sys/dev/drm2/radeon/radeon_semaphore.c @@ -41,7 +41,7 @@ int radeon_semaphore_create(struct radeon_device *rdev, int r; *semaphore = malloc(sizeof(struct radeon_semaphore), - DRM_MEM_DRIVER, M_WAITOK); + DRM_MEM_DRIVER, M_NOWAIT); if (*semaphore == NULL) { return -ENOMEM; } diff --git a/sys/dev/drm2/radeon/radeon_state.c b/sys/dev/drm2/radeon/radeon_state.c index 1716830f1904..d5aa9d1af620 100644 --- a/sys/dev/drm2/radeon/radeon_state.c +++ b/sys/dev/drm2/radeon/radeon_state.c @@ -1534,7 +1534,7 @@ static void radeon_cp_dispatch_vertex(struct drm_device * dev, drm_radeon_tcl_prim_t * prim) { drm_radeon_private_t *dev_priv = dev->dev_private; - struct drm_radeon_master_private *master_priv = file_priv->masterp->driver_priv; + struct drm_radeon_master_private *master_priv = file_priv->master->driver_priv; drm_radeon_sarea_t *sarea_priv = master_priv->sarea_priv; int offset = dev_priv->gart_buffers_offset + buf->offset + prim->start; int numverts = (int)prim->numverts; @@ -1916,7 +1916,7 @@ static int radeon_cp_dispatch_texture(struct drm_device * dev, ADVANCE_RING(); COMMIT_RING(); - radeon_cp_discard_buffer(dev, file_priv->masterp, buf); + radeon_cp_discard_buffer(dev, file_priv->master, buf); /* Update the input parameters for next time */ image->y += height; @@ -2156,7 +2156,7 @@ static int radeon_surface_free(struct drm_device *dev, void *data, struct drm_fi static int radeon_cp_clear(struct drm_device *dev, void *data, struct drm_file *file_priv) { drm_radeon_private_t *dev_priv = dev->dev_private; - struct drm_radeon_master_private *master_priv = file_priv->masterp->driver_priv; + struct drm_radeon_master_private *master_priv = file_priv->master->driver_priv; drm_radeon_sarea_t *sarea_priv = master_priv->sarea_priv; drm_radeon_clear_t *clear = data; drm_radeon_clear_rect_t depth_boxes[RADEON_NR_SAREA_CLIPRECTS]; @@ -2173,7 +2173,7 @@ static int radeon_cp_clear(struct drm_device *dev, void *data, struct drm_file * sarea_priv->nbox * sizeof(depth_boxes[0]))) return -EFAULT; - radeon_cp_dispatch_clear(dev, file_priv->masterp, clear, depth_boxes); + radeon_cp_dispatch_clear(dev, file_priv->master, clear, depth_boxes); COMMIT_RING(); return 0; @@ -2220,9 +2220,9 @@ static int radeon_cp_flip(struct drm_device *dev, void *data, struct drm_file *f RING_SPACE_TEST_WITH_RETURN(dev_priv); if (!dev_priv->page_flipping) - radeon_do_init_pageflip(dev, file_priv->masterp); + radeon_do_init_pageflip(dev, file_priv->master); - radeon_cp_dispatch_flip(dev, file_priv->masterp); + radeon_cp_dispatch_flip(dev, file_priv->master); COMMIT_RING(); return 0; @@ -2231,7 +2231,7 @@ static int radeon_cp_flip(struct drm_device *dev, void *data, struct drm_file *f static int radeon_cp_swap(struct drm_device *dev, void *data, struct drm_file *file_priv) { drm_radeon_private_t *dev_priv = dev->dev_private; - struct drm_radeon_master_private *master_priv = file_priv->masterp->driver_priv; + struct drm_radeon_master_private *master_priv = file_priv->master->driver_priv; drm_radeon_sarea_t *sarea_priv = master_priv->sarea_priv; DRM_DEBUG("\n"); @@ -2246,7 +2246,7 @@ static int radeon_cp_swap(struct drm_device *dev, void *data, struct drm_file *f if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600) r600_cp_dispatch_swap(dev, file_priv); else - radeon_cp_dispatch_swap(dev, file_priv->masterp); + radeon_cp_dispatch_swap(dev, file_priv->master); sarea_priv->ctx_owner = 0; COMMIT_RING(); @@ -2256,7 +2256,7 @@ static int radeon_cp_swap(struct drm_device *dev, void *data, struct drm_file *f static int radeon_cp_vertex(struct drm_device *dev, void *data, struct drm_file *file_priv) { drm_radeon_private_t *dev_priv = dev->dev_private; - struct drm_radeon_master_private *master_priv = file_priv->masterp->driver_priv; + struct drm_radeon_master_private *master_priv = file_priv->master->driver_priv; drm_radeon_sarea_t *sarea_priv; struct drm_device_dma *dma = dev->dma; struct drm_buf *buf; @@ -2325,7 +2325,7 @@ static int radeon_cp_vertex(struct drm_device *dev, void *data, struct drm_file } if (vertex->discard) { - radeon_cp_discard_buffer(dev, file_priv->masterp, buf); + radeon_cp_discard_buffer(dev, file_priv->master, buf); } COMMIT_RING(); @@ -2335,7 +2335,7 @@ static int radeon_cp_vertex(struct drm_device *dev, void *data, struct drm_file static int radeon_cp_indices(struct drm_device *dev, void *data, struct drm_file *file_priv) { drm_radeon_private_t *dev_priv = dev->dev_private; - struct drm_radeon_master_private *master_priv = file_priv->masterp->driver_priv; + struct drm_radeon_master_private *master_priv = file_priv->master->driver_priv; drm_radeon_sarea_t *sarea_priv; struct drm_device_dma *dma = dev->dma; struct drm_buf *buf; @@ -2414,9 +2414,9 @@ static int radeon_cp_indices(struct drm_device *dev, void *data, struct drm_file prim.numverts = RADEON_MAX_VB_VERTS; /* duh */ prim.vc_format = sarea_priv->vc_format; - radeon_cp_dispatch_indices(dev, file_priv->masterp, buf, &prim); + radeon_cp_dispatch_indices(dev, file_priv->master, buf, &prim); if (elts->discard) { - radeon_cp_discard_buffer(dev, file_priv->masterp, buf); + radeon_cp_discard_buffer(dev, file_priv->master, buf); } COMMIT_RING(); @@ -2532,7 +2532,7 @@ static int radeon_cp_indirect(struct drm_device *dev, void *data, struct drm_fil } if (indirect->discard) { - radeon_cp_discard_buffer(dev, file_priv->masterp, buf); + radeon_cp_discard_buffer(dev, file_priv->master, buf); } COMMIT_RING(); @@ -2542,7 +2542,7 @@ static int radeon_cp_indirect(struct drm_device *dev, void *data, struct drm_fil static int radeon_cp_vertex2(struct drm_device *dev, void *data, struct drm_file *file_priv) { drm_radeon_private_t *dev_priv = dev->dev_private; - struct drm_radeon_master_private *master_priv = file_priv->masterp->driver_priv; + struct drm_radeon_master_private *master_priv = file_priv->master->driver_priv; drm_radeon_sarea_t *sarea_priv; struct drm_device_dma *dma = dev->dma; struct drm_buf *buf; @@ -2614,7 +2614,7 @@ static int radeon_cp_vertex2(struct drm_device *dev, void *data, struct drm_file tclprim.offset = prim.numverts * 64; tclprim.numverts = RADEON_MAX_VB_VERTS; /* duh */ - radeon_cp_dispatch_indices(dev, file_priv->masterp, buf, &tclprim); + radeon_cp_dispatch_indices(dev, file_priv->master, buf, &tclprim); } else { tclprim.numverts = prim.numverts; tclprim.offset = 0; /* not used */ @@ -2627,7 +2627,7 @@ static int radeon_cp_vertex2(struct drm_device *dev, void *data, struct drm_file } if (vertex->discard) { - radeon_cp_discard_buffer(dev, file_priv->masterp, buf); + radeon_cp_discard_buffer(dev, file_priv->master, buf); } COMMIT_RING(); @@ -2965,7 +2965,7 @@ static int radeon_cp_cmdbuf(struct drm_device *dev, void *data, goto err; } - radeon_cp_discard_buffer(dev, file_priv->masterp, buf); + radeon_cp_discard_buffer(dev, file_priv->master, buf); break; case RADEON_CMD_PACKET3: @@ -3066,7 +3066,7 @@ static int radeon_cp_getparam(struct drm_device *dev, void *data, struct drm_fil case RADEON_PARAM_STATUS_HANDLE: value = dev_priv->ring_rptr_offset; break; -#ifndef __LP64__ +#if BITS_PER_LONG == 32 /* * This ioctl() doesn't work on 64-bit platforms because hw_lock is a * pointer which can't fit into an int-sized variable. According to @@ -3128,7 +3128,7 @@ static int radeon_cp_getparam(struct drm_device *dev, void *data, struct drm_fil static int radeon_cp_setparam(struct drm_device *dev, void *data, struct drm_file *file_priv) { drm_radeon_private_t *dev_priv = dev->dev_private; - struct drm_radeon_master_private *master_priv = file_priv->masterp->driver_priv; + struct drm_radeon_master_private *master_priv = file_priv->master->driver_priv; drm_radeon_setparam_t *sp = data; struct drm_radeon_driver_file_fields *radeon_priv; @@ -3206,7 +3206,7 @@ int radeon_driver_open(struct drm_device *dev, struct drm_file *file_priv) struct drm_radeon_driver_file_fields *radeon_priv; DRM_DEBUG("\n"); - radeon_priv = malloc(sizeof(*radeon_priv), DRM_MEM_DRIVER, M_WAITOK); + radeon_priv = malloc(sizeof(*radeon_priv), DRM_MEM_DRIVER, M_NOWAIT); if (!radeon_priv) return -ENOMEM; @@ -3259,4 +3259,4 @@ struct drm_ioctl_desc radeon_ioctls[] = { DRM_IOCTL_DEF_DRV(RADEON_CS, r600_cs_legacy_ioctl, DRM_AUTH) }; -int radeon_max_ioctl = DRM_ARRAY_SIZE(radeon_ioctls); +int radeon_max_ioctl = ARRAY_SIZE(radeon_ioctls); diff --git a/sys/dev/drm2/radeon/radeon_test.c b/sys/dev/drm2/radeon/radeon_test.c index 7774699332c1..94bb9f309a8c 100644 --- a/sys/dev/drm2/radeon/radeon_test.c +++ b/sys/dev/drm2/radeon/radeon_test.c @@ -70,7 +70,7 @@ static void radeon_do_test_moves(struct radeon_device *rdev, int flag) n -= rdev->ih.ring_size; n /= size; - gtt_obj = malloc(n * sizeof(*gtt_obj), DRM_MEM_DRIVER, M_ZERO | M_WAITOK); + gtt_obj = malloc(n * sizeof(*gtt_obj), DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); if (!gtt_obj) { DRM_ERROR("Failed to allocate %d pointers\n", n); r = 1; @@ -291,7 +291,7 @@ void radeon_test_ring_sync(struct radeon_device *rdev, } radeon_ring_unlock_commit(rdev, ringA); - DRM_MDELAY(1000); + mdelay(1000); if (radeon_fence_signaled(fence1)) { DRM_ERROR("Fence 1 signaled without waiting for semaphore.\n"); @@ -312,7 +312,7 @@ void radeon_test_ring_sync(struct radeon_device *rdev, goto out_cleanup; } - DRM_MDELAY(1000); + mdelay(1000); if (radeon_fence_signaled(fence2)) { DRM_ERROR("Fence 2 signaled without waiting for semaphore.\n"); @@ -390,7 +390,7 @@ static void radeon_test_ring_sync2(struct radeon_device *rdev, } radeon_ring_unlock_commit(rdev, ringB); - DRM_MDELAY(1000); + mdelay(1000); if (radeon_fence_signaled(fenceA)) { DRM_ERROR("Fence A signaled without waiting for semaphore.\n"); @@ -410,7 +410,7 @@ static void radeon_test_ring_sync2(struct radeon_device *rdev, radeon_ring_unlock_commit(rdev, ringC); for (i = 0; i < 30; ++i) { - DRM_MDELAY(100); + mdelay(100); sigA = radeon_fence_signaled(fenceA); sigB = radeon_fence_signaled(fenceB); if (sigA || sigB) @@ -435,7 +435,7 @@ static void radeon_test_ring_sync2(struct radeon_device *rdev, radeon_semaphore_emit_signal(rdev, ringC->idx, semaphore); radeon_ring_unlock_commit(rdev, ringC); - DRM_MDELAY(1000); + mdelay(1000); r = radeon_fence_wait(fenceA, false); if (r) { diff --git a/sys/dev/drm2/radeon/radeon_ttm.c b/sys/dev/drm2/radeon/radeon_ttm.c index f4ac1787bf5a..abfe774f77fb 100644 --- a/sys/dev/drm2/radeon/radeon_ttm.c +++ b/sys/dev/drm2/radeon/radeon_ttm.c @@ -561,13 +561,13 @@ static struct ttm_tt *radeon_ttm_tt_create(struct ttm_bo_device *bdev, rdev = radeon_get_rdev(bdev); #if __OS_HAS_AGP if (rdev->flags & RADEON_IS_AGP) { - return ttm_agp_tt_create(bdev, rdev->ddev->agp->agpdev, + return ttm_agp_tt_create(bdev, rdev->ddev->agp->bridge, size, page_flags, dummy_read_page); } #endif gtt = malloc(sizeof(struct radeon_ttm_tt), - DRM_MEM_DRIVER, M_WAITOK | M_ZERO); + DRM_MEM_DRIVER, M_NOWAIT | M_ZERO); if (gtt == NULL) { return NULL; } @@ -586,25 +586,21 @@ static int radeon_ttm_tt_populate(struct ttm_tt *ttm) struct radeon_ttm_tt *gtt = (void *)ttm; unsigned i; int r; -#ifdef DUMBBELL_WIP +#ifdef FREEBSD_WIP bool slave = !!(ttm->page_flags & TTM_PAGE_FLAG_SG); -#endif /* DUMBBELL_WIP */ +#endif /* FREEBSD_WIP */ if (ttm->state != tt_unpopulated) return 0; -#ifdef DUMBBELL_WIP - /* - * Maybe unneeded on FreeBSD. - * -- dumbbell@ - */ +#ifdef FREEBSD_WIP if (slave && ttm->sg) { drm_prime_sg_to_page_addr_arrays(ttm->sg, ttm->pages, gtt->ttm.dma_address, ttm->num_pages); ttm->state = tt_unbound; return 0; } -#endif /* DUMBBELL_WIP */ +#endif /* FREEBSD_WIP */ rdev = radeon_get_rdev(ttm->bdev); #if __OS_HAS_AGP @@ -626,7 +622,7 @@ static int radeon_ttm_tt_populate(struct ttm_tt *ttm) for (i = 0; i < ttm->num_pages; i++) { gtt->ttm.dma_address[i] = VM_PAGE_TO_PHYS(ttm->pages[i]); -#ifdef DUMBBELL_WIP +#ifdef FREEBSD_WIP gtt->ttm.dma_address[i] = pci_map_page(rdev->pdev, ttm->pages[i], 0, PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); @@ -639,7 +635,7 @@ static int radeon_ttm_tt_populate(struct ttm_tt *ttm) ttm_pool_unpopulate(ttm); return -EFAULT; } -#endif /* DUMBBELL_WIP */ +#endif /* FREEBSD_WIP */ } return 0; } @@ -672,10 +668,10 @@ static void radeon_ttm_tt_unpopulate(struct ttm_tt *ttm) for (i = 0; i < ttm->num_pages; i++) { if (gtt->ttm.dma_address[i]) { gtt->ttm.dma_address[i] = 0; -#ifdef DUMBBELL_WIP +#ifdef FREEBSD_WIP pci_unmap_page(rdev->pdev, gtt->ttm.dma_address[i], PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); -#endif /* DUMBBELL_WIP */ +#endif /* FREEBSD_WIP */ } } @@ -704,7 +700,7 @@ static struct ttm_bo_driver radeon_bo_driver = { int radeon_ttm_init(struct radeon_device *rdev) { - int r, r2; + int r; r = radeon_ttm_global_init(rdev); if (r) { @@ -750,12 +746,6 @@ int radeon_ttm_init(struct radeon_device *rdev) rdev->mc.gtt_size >> PAGE_SHIFT); if (r) { DRM_ERROR("Failed initializing GTT heap.\n"); - r2 = radeon_bo_reserve(rdev->stollen_vga_memory, false); - if (likely(r2 == 0)) { - radeon_bo_unpin(rdev->stollen_vga_memory); - radeon_bo_unreserve(rdev->stollen_vga_memory); - } - radeon_bo_unref(&rdev->stollen_vga_memory); return r; } DRM_INFO("radeon: %uM of GTT memory ready.\n", @@ -764,12 +754,6 @@ int radeon_ttm_init(struct radeon_device *rdev) r = radeon_ttm_debugfs_init(rdev); if (r) { DRM_ERROR("Failed to init debugfs\n"); - r2 = radeon_bo_reserve(rdev->stollen_vga_memory, false); - if (likely(r2 == 0)) { - radeon_bo_unpin(rdev->stollen_vga_memory); - radeon_bo_unreserve(rdev->stollen_vga_memory); - } - radeon_bo_unref(&rdev->stollen_vga_memory); return r; } return 0; @@ -812,7 +796,7 @@ void radeon_ttm_set_active_vram_size(struct radeon_device *rdev, u64 size) man->size = size >> PAGE_SHIFT; } -#ifdef DUMBBELL_WIP +#ifdef FREEBSD_WIP static struct vm_operations_struct radeon_ttm_vm_ops; static const struct vm_operations_struct *ttm_vm_ops = NULL; @@ -860,7 +844,7 @@ int radeon_mmap(struct file *filp, struct vm_area_struct *vma) vma->vm_ops = &radeon_ttm_vm_ops; return 0; } -#endif /* DUMBBELL_WIP */ +#endif /* FREEBSD_WIP */ #define RADEON_DEBUGFS_MEM_TYPES 2 diff --git a/sys/dev/drm2/radeon/rs400.c b/sys/dev/drm2/radeon/rs400.c index f9d638d013e5..714c36ba0f7e 100644 --- a/sys/dev/drm2/radeon/rs400.c +++ b/sys/dev/drm2/radeon/rs400.c @@ -173,12 +173,9 @@ int rs400_gart_enable(struct radeon_device *rdev) WREG32_MC(RS480_AGP_MODE_CNTL, (1 << RS480_REQ_TYPE_SNOOP_SHIFT) | RS480_REQ_TYPE_SNOOP_DIS); /* Disable AGP mode */ + /* FIXME: according to doc we should set HIDE_MMCFG_BAR=0, + * AGPMODE30=0 & AGP30ENHANCED=0 in NB_CNTL */ if ((rdev->family == CHIP_RS690) || (rdev->family == CHIP_RS740)) { - tmp = RREG32_MC(RS690_MC_NB_CNTL); - tmp &= ~(RS690_HIDE_MMCFG_BAR | - RS690_AGPMODE30 | - RS690_AGP30ENHANCED); - WREG32_MC(RS690_MC_NB_CNTL, tmp); WREG32_MC(RS480_MC_MISC_CNTL, (RS480_GART_INDEX_REG_EN | RS690_BLOCK_GFX_D3_EN)); } else { @@ -223,7 +220,7 @@ int rs400_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr) return -EINVAL; } - entry = (lower_32_bits(addr) & 0xfffff000) | + entry = (lower_32_bits(addr) & ~PAGE_MASK) | ((upper_32_bits(addr) & 0xff) << 4) | RS400_PTE_WRITEABLE | RS400_PTE_READABLE; entry = cpu_to_le32(entry); diff --git a/sys/dev/drm2/radeon/rs600.c b/sys/dev/drm2/radeon/rs600.c index 11edbdfc5df9..73d0d0cfdd30 100644 --- a/sys/dev/drm2/radeon/rs600.c +++ b/sys/dev/drm2/radeon/rs600.c @@ -48,6 +48,9 @@ __FBSDID("$FreeBSD$"); #include "rs600_reg_safe.h" static void rs600_gpu_init(struct radeon_device *rdev); +#ifdef FREEBSD_WIP /* FreeBSD: to please GCC 4.2. */ +int rs600_mc_wait_for_idle(struct radeon_device *rdev); +#endif static const u32 crtc_offsets[2] = { @@ -55,23 +58,59 @@ static const u32 crtc_offsets[2] = AVIVO_D2CRTC_H_TOTAL - AVIVO_D1CRTC_H_TOTAL }; +static bool avivo_is_in_vblank(struct radeon_device *rdev, int crtc) +{ + if (RREG32(AVIVO_D1CRTC_STATUS + crtc_offsets[crtc]) & AVIVO_D1CRTC_V_BLANK) + return true; + else + return false; +} + +static bool avivo_is_counter_moving(struct radeon_device *rdev, int crtc) +{ + u32 pos1, pos2; + + pos1 = RREG32(AVIVO_D1CRTC_STATUS_POSITION + crtc_offsets[crtc]); + pos2 = RREG32(AVIVO_D1CRTC_STATUS_POSITION + crtc_offsets[crtc]); + + if (pos1 != pos2) + return true; + else + return false; +} + +/** + * avivo_wait_for_vblank - vblank wait asic callback. + * + * @rdev: radeon_device pointer + * @crtc: crtc to wait for vblank on + * + * Wait for vblank on the requested crtc (r5xx-r7xx). + */ void avivo_wait_for_vblank(struct radeon_device *rdev, int crtc) { - int i; + unsigned i = 0; if (crtc >= rdev->num_crtc) return; - if (RREG32(AVIVO_D1CRTC_CONTROL + crtc_offsets[crtc]) & AVIVO_CRTC_EN) { - for (i = 0; i < rdev->usec_timeout; i++) { - if (!(RREG32(AVIVO_D1CRTC_STATUS + crtc_offsets[crtc]) & AVIVO_D1CRTC_V_BLANK)) + if (!(RREG32(AVIVO_D1CRTC_CONTROL + crtc_offsets[crtc]) & AVIVO_CRTC_EN)) + return; + + /* depending on when we hit vblank, we may be close to active; if so, + * wait for another frame. + */ + while (avivo_is_in_vblank(rdev, crtc)) { + if (i++ % 100 == 0) { + if (!avivo_is_counter_moving(rdev, crtc)) break; - DRM_UDELAY(1); } - for (i = 0; i < rdev->usec_timeout; i++) { - if (RREG32(AVIVO_D1CRTC_STATUS + crtc_offsets[crtc]) & AVIVO_D1CRTC_V_BLANK) + } + + while (!avivo_is_in_vblank(rdev, crtc)) { + if (i++ % 100 == 0) { + if (!avivo_is_counter_moving(rdev, crtc)) break; - DRM_UDELAY(1); } } } @@ -108,7 +147,7 @@ u32 rs600_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base) for (i = 0; i < rdev->usec_timeout; i++) { if (RREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset) & AVIVO_D1GRPH_SURFACE_UPDATE_PENDING) break; - DRM_UDELAY(1); + udelay(1); } DRM_DEBUG("Update pending now high. Unlocking vupdate_lock.\n"); @@ -137,7 +176,7 @@ void rs600_pm_misc(struct radeon_device *rdev) tmp &= ~(voltage->gpio.mask); WREG32(voltage->gpio.reg, tmp); if (voltage->delay) - DRM_UDELAY(voltage->delay); + udelay(voltage->delay); } else { tmp = RREG32(voltage->gpio.reg); if (voltage->active_high) @@ -146,7 +185,7 @@ void rs600_pm_misc(struct radeon_device *rdev) tmp |= voltage->gpio.mask; WREG32(voltage->gpio.reg, tmp); if (voltage->delay) - DRM_UDELAY(voltage->delay); + udelay(voltage->delay); } } else if (voltage->type == VOLTAGE_VDDC) radeon_atom_set_voltage(rdev, voltage->vddc_id, SET_VOLTAGE_TYPE_ASIC_VDDC); @@ -376,30 +415,30 @@ int rs600_asic_reset(struct radeon_device *rdev) pci_save_state(device_get_parent(rdev->dev)); /* disable bus mastering */ pci_disable_busmaster(rdev->dev); - DRM_MDELAY(1); + mdelay(1); /* reset GA+VAP */ WREG32(R_0000F0_RBBM_SOFT_RESET, S_0000F0_SOFT_RESET_VAP(1) | S_0000F0_SOFT_RESET_GA(1)); RREG32(R_0000F0_RBBM_SOFT_RESET); - DRM_MDELAY(500); + mdelay(500); WREG32(R_0000F0_RBBM_SOFT_RESET, 0); - DRM_MDELAY(1); + mdelay(1); status = RREG32(R_000E40_RBBM_STATUS); dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status); /* reset CP */ WREG32(R_0000F0_RBBM_SOFT_RESET, S_0000F0_SOFT_RESET_CP(1)); RREG32(R_0000F0_RBBM_SOFT_RESET); - DRM_MDELAY(500); + mdelay(500); WREG32(R_0000F0_RBBM_SOFT_RESET, 0); - DRM_MDELAY(1); + mdelay(1); status = RREG32(R_000E40_RBBM_STATUS); dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status); /* reset MC */ WREG32(R_0000F0_RBBM_SOFT_RESET, S_0000F0_SOFT_RESET_MC(1)); RREG32(R_0000F0_RBBM_SOFT_RESET); - DRM_MDELAY(500); + mdelay(500); WREG32(R_0000F0_RBBM_SOFT_RESET, 0); - DRM_MDELAY(1); + mdelay(1); status = RREG32(R_000E40_RBBM_STATUS); dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status); /* restore PCI & busmastering */ @@ -659,7 +698,7 @@ void rs600_irq_disable(struct radeon_device *rdev) WREG32(R_000040_GEN_INT_CNTL, 0); WREG32(R_006540_DxMODE_INT_MASK, 0); /* Wait and acknowledge irq */ - DRM_MDELAY(1); + mdelay(1); rs600_irq_ack(rdev); } @@ -751,7 +790,7 @@ int rs600_mc_wait_for_idle(struct radeon_device *rdev) for (i = 0; i < rdev->usec_timeout; i++) { if (G_000000_MC_IDLE(RREG32_MC(R_000000_MC_STATUS))) return 0; - DRM_UDELAY(1); + udelay(1); } return -1; } @@ -835,7 +874,7 @@ static void rs600_debugfs(struct radeon_device *rdev) void rs600_set_safe_registers(struct radeon_device *rdev) { rdev->config.r300.reg_safe_bm = rs600_reg_safe_bm; - rdev->config.r300.reg_safe_bm_size = DRM_ARRAY_SIZE(rs600_reg_safe_bm); + rdev->config.r300.reg_safe_bm_size = ARRAY_SIZE(rs600_reg_safe_bm); } static void rs600_mc_program(struct radeon_device *rdev) diff --git a/sys/dev/drm2/radeon/rs690.c b/sys/dev/drm2/radeon/rs690.c index dbf64d9e8edc..2ff048594d15 100644 --- a/sys/dev/drm2/radeon/rs690.c +++ b/sys/dev/drm2/radeon/rs690.c @@ -45,7 +45,7 @@ int rs690_mc_wait_for_idle(struct radeon_device *rdev) tmp = RREG32_MC(R_000090_MC_SYSTEM_STATUS); if (G_000090_MC_SYSTEM_IDLE(tmp)) return 0; - DRM_UDELAY(1); + udelay(1); } return -1; } diff --git a/sys/dev/drm2/radeon/rv515.c b/sys/dev/drm2/radeon/rv515.c index ba292deb0a1b..e41ba9ae0122 100644 --- a/sys/dev/drm2/radeon/rv515.c +++ b/sys/dev/drm2/radeon/rv515.c @@ -40,6 +40,9 @@ __FBSDID("$FreeBSD$"); static int rv515_debugfs_pipes_info_init(struct radeon_device *rdev); static int rv515_debugfs_ga_info_init(struct radeon_device *rdev); static void rv515_gpu_init(struct radeon_device *rdev); +#ifdef FREEBSD_WIP /* FreeBSD: to please GCC 4.2. */ +int rv515_mc_wait_for_idle(struct radeon_device *rdev); +#endif static const u32 crtc_offsets[2] = { @@ -304,16 +307,27 @@ void rv515_mc_stop(struct radeon_device *rdev, struct rv515_mc_save *save) tmp = RREG32(AVIVO_D1CRTC_CONTROL + crtc_offsets[i]); if (!(tmp & AVIVO_CRTC_DISP_READ_REQUEST_DISABLE)) { radeon_wait_for_vblank(rdev, i); + WREG32(AVIVO_D1CRTC_UPDATE_LOCK + crtc_offsets[i], 1); tmp |= AVIVO_CRTC_DISP_READ_REQUEST_DISABLE; WREG32(AVIVO_D1CRTC_CONTROL + crtc_offsets[i], tmp); + WREG32(AVIVO_D1CRTC_UPDATE_LOCK + crtc_offsets[i], 0); } /* wait for the next frame */ frame_count = radeon_get_vblank_counter(rdev, i); for (j = 0; j < rdev->usec_timeout; j++) { if (radeon_get_vblank_counter(rdev, i) != frame_count) break; - DRM_UDELAY(1); + udelay(1); } + + /* XXX this is a hack to avoid strange behavior with EFI on certain systems */ + WREG32(AVIVO_D1CRTC_UPDATE_LOCK + crtc_offsets[i], 1); + tmp = RREG32(AVIVO_D1CRTC_CONTROL + crtc_offsets[i]); + tmp &= ~AVIVO_CRTC_EN; + WREG32(AVIVO_D1CRTC_CONTROL + crtc_offsets[i], tmp); + WREG32(AVIVO_D1CRTC_UPDATE_LOCK + crtc_offsets[i], 0); + save->crtc_enabled[i] = false; + /* ***** */ } else { save->crtc_enabled[i] = false; } @@ -338,7 +352,23 @@ void rv515_mc_stop(struct radeon_device *rdev, struct rv515_mc_save *save) } } /* wait for the MC to settle */ - DRM_UDELAY(100); + udelay(100); + + /* lock double buffered regs */ + for (i = 0; i < rdev->num_crtc; i++) { + if (save->crtc_enabled[i]) { + tmp = RREG32(AVIVO_D1GRPH_UPDATE + crtc_offsets[i]); + if (!(tmp & AVIVO_D1GRPH_UPDATE_LOCK)) { + tmp |= AVIVO_D1GRPH_UPDATE_LOCK; + WREG32(AVIVO_D1GRPH_UPDATE + crtc_offsets[i], tmp); + } + tmp = RREG32(AVIVO_D1MODE_MASTER_UPDATE_LOCK + crtc_offsets[i]); + if (!(tmp & 1)) { + tmp |= 1; + WREG32(AVIVO_D1MODE_MASTER_UPDATE_LOCK + crtc_offsets[i], tmp); + } + } + } } void rv515_mc_resume(struct radeon_device *rdev, struct rv515_mc_save *save) @@ -349,7 +379,7 @@ void rv515_mc_resume(struct radeon_device *rdev, struct rv515_mc_save *save) /* update crtc base addresses */ for (i = 0; i < rdev->num_crtc; i++) { if (rdev->family >= CHIP_RV770) { - if (i == 1) { + if (i == 0) { WREG32(R700_D1GRPH_PRIMARY_SURFACE_ADDRESS_HIGH, upper_32_bits(rdev->mc.vram_start)); WREG32(R700_D1GRPH_SECONDARY_SURFACE_ADDRESS_HIGH, @@ -368,6 +398,33 @@ void rv515_mc_resume(struct radeon_device *rdev, struct rv515_mc_save *save) } WREG32(R_000310_VGA_MEMORY_BASE_ADDRESS, (u32)rdev->mc.vram_start); + /* unlock regs and wait for update */ + for (i = 0; i < rdev->num_crtc; i++) { + if (save->crtc_enabled[i]) { + tmp = RREG32(AVIVO_D1MODE_MASTER_UPDATE_MODE + crtc_offsets[i]); + if ((tmp & 0x3) != 0) { + tmp &= ~0x3; + WREG32(AVIVO_D1MODE_MASTER_UPDATE_MODE + crtc_offsets[i], tmp); + } + tmp = RREG32(AVIVO_D1GRPH_UPDATE + crtc_offsets[i]); + if (tmp & AVIVO_D1GRPH_UPDATE_LOCK) { + tmp &= ~AVIVO_D1GRPH_UPDATE_LOCK; + WREG32(AVIVO_D1GRPH_UPDATE + crtc_offsets[i], tmp); + } + tmp = RREG32(AVIVO_D1MODE_MASTER_UPDATE_LOCK + crtc_offsets[i]); + if (tmp & 1) { + tmp &= ~1; + WREG32(AVIVO_D1MODE_MASTER_UPDATE_LOCK + crtc_offsets[i], tmp); + } + for (j = 0; j < rdev->usec_timeout; j++) { + tmp = RREG32(AVIVO_D1GRPH_UPDATE + crtc_offsets[i]); + if ((tmp & AVIVO_D1GRPH_SURFACE_UPDATE_PENDING) == 0) + break; + udelay(1); + } + } + } + if (rdev->family >= CHIP_R600) { /* unblackout the MC */ if (rdev->family >= CHIP_RV770) @@ -393,13 +450,13 @@ void rv515_mc_resume(struct radeon_device *rdev, struct rv515_mc_save *save) for (j = 0; j < rdev->usec_timeout; j++) { if (radeon_get_vblank_counter(rdev, i) != frame_count) break; - DRM_UDELAY(1); + udelay(1); } } } /* Unlock vga access */ WREG32(R_000328_VGA_HDP_CONTROL, save->vga_hdp_control); - DRM_MDELAY(1); + mdelay(1); WREG32(R_000300_VGA_RENDER_CONTROL, save->vga_render_control); } @@ -540,7 +597,7 @@ int rv515_suspend(struct radeon_device *rdev) void rv515_set_safe_registers(struct radeon_device *rdev) { rdev->config.r300.reg_safe_bm = rv515_reg_safe_bm; - rdev->config.r300.reg_safe_bm_size = DRM_ARRAY_SIZE(rv515_reg_safe_bm); + rdev->config.r300.reg_safe_bm_size = ARRAY_SIZE(rv515_reg_safe_bm); } void rv515_fini(struct radeon_device *rdev) diff --git a/sys/dev/drm2/radeon/rv770.c b/sys/dev/drm2/radeon/rv770.c index 549ed90af8e1..4d6b67b1a636 100644 --- a/sys/dev/drm2/radeon/rv770.c +++ b/sys/dev/drm2/radeon/rv770.c @@ -41,6 +41,9 @@ __FBSDID("$FreeBSD$"); #define R700_PM4_UCODE_SIZE 1360 static void rv770_gpu_init(struct radeon_device *rdev); +#ifdef FREEBSD_WIP /* FreeBSD: to please GCC 4.2. */ +void rv770_fini(struct radeon_device *rdev); +#endif static void rv770_pcie_gen2_enable(struct radeon_device *rdev); u32 rv770_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base) @@ -70,7 +73,7 @@ u32 rv770_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base) for (i = 0; i < rdev->usec_timeout; i++) { if (RREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset) & AVIVO_D1GRPH_SURFACE_UPDATE_PENDING) break; - DRM_UDELAY(1); + udelay(1); } DRM_DEBUG("Update pending now high. Unlocking vupdate_lock.\n"); @@ -337,7 +340,7 @@ static int rv770_cp_load_microcode(struct radeon_device *rdev) /* Reset cp */ WREG32(GRBM_SOFT_RESET, SOFT_RESET_CP); RREG32(GRBM_SOFT_RESET); - DRM_MDELAY(15); + mdelay(15); WREG32(GRBM_SOFT_RESET, 0); fw_data = (const __be32 *)rdev->pfp_fw->data; diff --git a/sys/dev/drm2/radeon/si.c b/sys/dev/drm2/radeon/si.c index 0fdefd2a6b6d..8e18d8dcc787 100644 --- a/sys/dev/drm2/radeon/si.c +++ b/sys/dev/drm2/radeon/si.c @@ -39,6 +39,33 @@ __FBSDID("$FreeBSD$"); #define SI_RLC_UCODE_SIZE 2048 #define SI_MC_UCODE_SIZE 7769 +#ifdef __linux__ +MODULE_FIRMWARE("radeon/TAHITI_pfp.bin"); +MODULE_FIRMWARE("radeon/TAHITI_me.bin"); +MODULE_FIRMWARE("radeon/TAHITI_ce.bin"); +MODULE_FIRMWARE("radeon/TAHITI_mc.bin"); +MODULE_FIRMWARE("radeon/TAHITI_rlc.bin"); +MODULE_FIRMWARE("radeon/PITCAIRN_pfp.bin"); +MODULE_FIRMWARE("radeon/PITCAIRN_me.bin"); +MODULE_FIRMWARE("radeon/PITCAIRN_ce.bin"); +MODULE_FIRMWARE("radeon/PITCAIRN_mc.bin"); +MODULE_FIRMWARE("radeon/PITCAIRN_rlc.bin"); +MODULE_FIRMWARE("radeon/VERDE_pfp.bin"); +MODULE_FIRMWARE("radeon/VERDE_me.bin"); +MODULE_FIRMWARE("radeon/VERDE_ce.bin"); +MODULE_FIRMWARE("radeon/VERDE_mc.bin"); +MODULE_FIRMWARE("radeon/VERDE_rlc.bin"); +#endif + +#ifdef FREEBSD_WIP /* FreeBSD: to please GCC 4.2. */ +extern int r600_ih_ring_alloc(struct radeon_device *rdev); +extern void r600_ih_ring_fini(struct radeon_device *rdev); +extern void evergreen_fix_pci_max_read_req_size(struct radeon_device *rdev); +extern void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *save); +extern void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *save); +extern u32 evergreen_get_number_of_dram_channels(struct radeon_device *rdev); +#endif + /* get temperature in millidegrees */ int si_get_temp(struct radeon_device *rdev) { @@ -238,12 +265,12 @@ static int si_mc_load_microcode(struct radeon_device *rdev) for (i = 0; i < rdev->usec_timeout; i++) { if (RREG32(MC_SEQ_TRAIN_WAKEUP_CNTL) & TRAIN_DONE_D0) break; - DRM_UDELAY(1); + udelay(1); } for (i = 0; i < rdev->usec_timeout; i++) { if (RREG32(MC_SEQ_TRAIN_WAKEUP_CNTL) & TRAIN_DONE_D1) break; - DRM_UDELAY(1); + udelay(1); } if (running) @@ -1399,7 +1426,7 @@ static void si_select_se_sh(struct radeon_device *rdev, u32 data = INSTANCE_BROADCAST_WRITES; if ((se_num == 0xffffffff) && (sh_num == 0xffffffff)) - data = SH_BROADCAST_WRITES | SE_BROADCAST_WRITES; + data |= SH_BROADCAST_WRITES | SE_BROADCAST_WRITES; else if (se_num == 0xffffffff) data |= SE_BROADCAST_WRITES | SH_INDEX(sh_num); else if (sh_num == 0xffffffff) @@ -1684,6 +1711,7 @@ static void si_gpu_init(struct radeon_device *rdev) WREG32(GB_ADDR_CONFIG, gb_addr_config); WREG32(DMIF_ADDR_CONFIG, gb_addr_config); + WREG32(DMIF_ADDR_CALC, gb_addr_config); WREG32(HDP_ADDR_CONFIG, gb_addr_config); WREG32(DMA_TILING_CONFIG + DMA0_REGISTER_OFFSET, gb_addr_config); WREG32(DMA_TILING_CONFIG + DMA1_REGISTER_OFFSET, gb_addr_config); @@ -1747,7 +1775,7 @@ static void si_gpu_init(struct radeon_device *rdev) WREG32(PA_CL_ENHANCE, CLIP_VTX_REORDER_ENA | NUM_CLIP_SEQ(3)); - DRM_UDELAY(50); + udelay(50); } /* @@ -1867,7 +1895,7 @@ static void si_cp_enable(struct radeon_device *rdev, bool enable) rdev->ring[CAYMAN_RING_TYPE_CP1_INDEX].ready = false; rdev->ring[CAYMAN_RING_TYPE_CP2_INDEX].ready = false; } - DRM_UDELAY(50); + udelay(50); } static int si_cp_load_microcode(struct radeon_device *rdev) @@ -2009,7 +2037,7 @@ static int si_cp_resume(struct radeon_device *rdev) SOFT_RESET_SPI | SOFT_RESET_SX)); RREG32(GRBM_SOFT_RESET); - DRM_MDELAY(15); + mdelay(15); WREG32(GRBM_SOFT_RESET, 0); RREG32(GRBM_SOFT_RESET); @@ -2048,7 +2076,7 @@ static int si_cp_resume(struct radeon_device *rdev) WREG32(SCRATCH_UMSK, 0); } - DRM_MDELAY(1); + mdelay(1); WREG32(CP_RB0_CNTL, tmp); WREG32(CP_RB0_BASE, ring->gpu_addr >> 8); @@ -2074,7 +2102,7 @@ static int si_cp_resume(struct radeon_device *rdev) WREG32(CP_RB1_RPTR_ADDR, (rdev->wb.gpu_addr + RADEON_WB_CP1_RPTR_OFFSET) & 0xFFFFFFFC); WREG32(CP_RB1_RPTR_ADDR_HI, upper_32_bits(rdev->wb.gpu_addr + RADEON_WB_CP1_RPTR_OFFSET) & 0xFF); - DRM_MDELAY(1); + mdelay(1); WREG32(CP_RB1_CNTL, tmp); WREG32(CP_RB1_BASE, ring->gpu_addr >> 8); @@ -2100,7 +2128,7 @@ static int si_cp_resume(struct radeon_device *rdev) WREG32(CP_RB2_RPTR_ADDR, (rdev->wb.gpu_addr + RADEON_WB_CP2_RPTR_OFFSET) & 0xFFFFFFFC); WREG32(CP_RB2_RPTR_ADDR_HI, upper_32_bits(rdev->wb.gpu_addr + RADEON_WB_CP2_RPTR_OFFSET) & 0xFF); - DRM_MDELAY(1); + mdelay(1); WREG32(CP_RB2_CNTL, tmp); WREG32(CP_RB2_BASE, ring->gpu_addr >> 8); @@ -2190,7 +2218,7 @@ static void si_gpu_soft_reset_gfx(struct radeon_device *rdev) dev_info(rdev->dev, " GRBM_SOFT_RESET=0x%08X\n", grbm_reset); WREG32(GRBM_SOFT_RESET, grbm_reset); (void)RREG32(GRBM_SOFT_RESET); - DRM_UDELAY(50); + udelay(50); WREG32(GRBM_SOFT_RESET, 0); (void)RREG32(GRBM_SOFT_RESET); @@ -2229,7 +2257,7 @@ static void si_gpu_soft_reset_dma(struct radeon_device *rdev) /* Reset dma */ WREG32(SRBM_SOFT_RESET, SOFT_RESET_DMA | SOFT_RESET_DMA1); RREG32(SRBM_SOFT_RESET); - DRM_UDELAY(50); + udelay(50); WREG32(SRBM_SOFT_RESET, 0); dev_info(rdev->dev, " DMA_STATUS_REG = 0x%08X\n", @@ -2268,7 +2296,7 @@ static int si_gpu_soft_reset(struct radeon_device *rdev, u32 reset_mask) si_gpu_soft_reset_dma(rdev); /* Wait a little for things to settle down */ - DRM_UDELAY(50); + udelay(50); evergreen_mc_resume(rdev, &save); return 0; @@ -3645,7 +3673,7 @@ static void si_irq_disable(struct radeon_device *rdev) { si_disable_interrupts(rdev); /* Wait and acknowledge irq */ - DRM_MDELAY(1); + mdelay(1); si_irq_ack(rdev); si_disable_interrupt_state(rdev); } @@ -4257,6 +4285,7 @@ int si_resume(struct radeon_device *rdev) int si_suspend(struct radeon_device *rdev) { + radeon_vm_manager_fini(rdev); si_cp_enable(rdev, false); cayman_dma_stop(rdev); si_irq_suspend(rdev); diff --git a/sys/dev/drm2/radeon/si_blit_shaders.c b/sys/dev/drm2/radeon/si_blit_shaders.c index dc31fe307b37..483a93dec05f 100644 --- a/sys/dev/drm2/radeon/si_blit_shaders.c +++ b/sys/dev/drm2/radeon/si_blit_shaders.c @@ -251,4 +251,4 @@ const u32 si_default_state[] = 0x00000010, /* */ }; -const u32 si_default_size = DRM_ARRAY_SIZE(si_default_state); +const u32 si_default_size = ARRAY_SIZE(si_default_state); diff --git a/sys/dev/drm2/radeon/sid.h b/sys/dev/drm2/radeon/sid.h index 7aa21c1442ac..eaf95fb5218c 100644 --- a/sys/dev/drm2/radeon/sid.h +++ b/sys/dev/drm2/radeon/sid.h @@ -63,6 +63,8 @@ __FBSDID("$FreeBSD$"); #define DMIF_ADDR_CONFIG 0xBD4 +#define DMIF_ADDR_CALC 0xC00 + #define SRBM_STATUS 0xE50 #define SRBM_SOFT_RESET 0x0E60 diff --git a/sys/dev/drm2/ttm/ttm_bo.c b/sys/dev/drm2/ttm/ttm_bo.c index 748c96901d5a..64364d5607ea 100644 --- a/sys/dev/drm2/ttm/ttm_bo.c +++ b/sys/dev/drm2/ttm/ttm_bo.c @@ -148,7 +148,7 @@ ttm_bo_wait_unreserved_locked(struct ttm_buffer_object *bo, bool interruptible) } while (ttm_bo_is_reserved(bo)) { ret = -msleep(bo, &bo->glob->lru_lock, flags, wmsg, 0); - if (ret == -EINTR) + if (ret == -EINTR || ret == -ERESTART) ret = -ERESTARTSYS; if (ret != 0) break; @@ -816,7 +816,7 @@ static int ttm_bo_evict(struct ttm_buffer_object *bo, bool interruptible, mtx_unlock(&bdev->fence_lock); if (unlikely(ret != 0)) { - if (ret != -ERESTART) { + if (ret != -ERESTARTSYS) { printf("[TTM] Failed to expire sync object before buffer eviction\n"); } goto out; @@ -837,7 +837,7 @@ static int ttm_bo_evict(struct ttm_buffer_object *bo, bool interruptible, ret = ttm_bo_mem_space(bo, &placement, &evict_mem, interruptible, no_wait_gpu); if (ret) { - if (ret != -ERESTART) { + if (ret != -ERESTARTSYS) { printf("[TTM] Failed to find memory space for buffer 0x%p eviction\n", bo); ttm_bo_mem_space_debug(bo, &placement); @@ -848,7 +848,7 @@ static int ttm_bo_evict(struct ttm_buffer_object *bo, bool interruptible, ret = ttm_bo_handle_move_mem(bo, &evict_mem, true, interruptible, no_wait_gpu); if (ret) { - if (ret != -ERESTART) + if (ret != -ERESTARTSYS) printf("[TTM] Buffer eviction failed\n"); ttm_bo_mem_put(bo, &evict_mem); goto out; @@ -1096,10 +1096,10 @@ int ttm_bo_mem_space(struct ttm_buffer_object *bo, mem->placement = cur_flags; return 0; } - if (ret == -ERESTART) + if (ret == -ERESTARTSYS) has_erestartsys = true; } - ret = (has_erestartsys) ? -ERESTART : -ENOMEM; + ret = (has_erestartsys) ? -ERESTARTSYS : -ENOMEM; return ret; } diff --git a/sys/dev/drm2/ttm/ttm_bo_util.c b/sys/dev/drm2/ttm/ttm_bo_util.c index 177cc001c2c8..fbbaaf2029fa 100644 --- a/sys/dev/drm2/ttm/ttm_bo_util.c +++ b/sys/dev/drm2/ttm/ttm_bo_util.c @@ -439,7 +439,7 @@ ttm_buffer_object_transfer(struct ttm_buffer_object *bo, vm_memattr_t ttm_io_prot(uint32_t caching_flags) { -#if defined(__i386__) || defined(__amd64__) +#if defined(__i386__) || defined(__amd64__) || defined(__powerpc__) if (caching_flags & TTM_PL_FLAG_WC) return (VM_MEMATTR_WRITE_COMBINING); else diff --git a/sys/dev/drm2/ttm/ttm_bo_vm.c b/sys/dev/drm2/ttm/ttm_bo_vm.c index 7aa1ac0c428c..5d72d979681c 100644 --- a/sys/dev/drm2/ttm/ttm_bo_vm.c +++ b/sys/dev/drm2/ttm/ttm_bo_vm.c @@ -140,7 +140,7 @@ reserve: case 0: break; case -EBUSY: - case -ERESTART: + case -ERESTARTSYS: case -EINTR: kern_yield(0); goto reserve; @@ -339,22 +339,22 @@ ttm_bo_mmap_single(struct ttm_bo_device *bdev, vm_ooffset_t *offset, vm_size_t s if (unlikely(bo == NULL)) { printf("[TTM] Could not find buffer object to map\n"); - return (EINVAL); + return (-EINVAL); } driver = bo->bdev->driver; if (unlikely(!driver->verify_access)) { - ret = EPERM; + ret = -EPERM; goto out_unref; } - ret = -driver->verify_access(bo); + ret = driver->verify_access(bo); if (unlikely(ret != 0)) goto out_unref; vm_obj = cdev_pager_allocate(bo, OBJT_MGTDEVICE, &ttm_pager_ops, size, nprot, 0, curthread->td_ucred); if (vm_obj == NULL) { - ret = EINVAL; + ret = -EINVAL; goto out_unref; } /* diff --git a/sys/dev/drm2/ttm/ttm_lock.c b/sys/dev/drm2/ttm/ttm_lock.c index ae06565cf911..870877e59c9d 100644 --- a/sys/dev/drm2/ttm/ttm_lock.c +++ b/sys/dev/drm2/ttm/ttm_lock.c @@ -106,13 +106,13 @@ ttm_read_lock(struct ttm_lock *lock, bool interruptible) } mtx_lock(&lock->lock); while (!__ttm_read_lock(lock)) { - ret = msleep(lock, &lock->lock, flags, wmsg, 0); - if (ret == EINTR) - ret = ERESTARTSYS; + ret = -msleep(lock, &lock->lock, flags, wmsg, 0); + if (ret == -EINTR || ret == -ERESTART) + ret = -ERESTARTSYS; if (ret != 0) break; } - return (-ret); + return (ret); } static bool __ttm_read_trylock(struct ttm_lock *lock, bool *locked) @@ -152,9 +152,9 @@ int ttm_read_trylock(struct ttm_lock *lock, bool interruptible) } mtx_lock(&lock->lock); while (!__ttm_read_trylock(lock, &locked)) { - ret = msleep(lock, &lock->lock, flags, wmsg, 0); - if (ret == EINTR) - ret = ERESTARTSYS; + ret = -msleep(lock, &lock->lock, flags, wmsg, 0); + if (ret == -EINTR || ret == -ERESTART) + ret = -ERESTARTSYS; if (ret != 0) break; } @@ -207,9 +207,9 @@ ttm_write_lock(struct ttm_lock *lock, bool interruptible) mtx_lock(&lock->lock); /* XXXKIB: linux uses __ttm_read_lock for uninterruptible sleeps */ while (!__ttm_write_lock(lock)) { - ret = msleep(lock, &lock->lock, flags, wmsg, 0); - if (ret == EINTR) - ret = ERESTARTSYS; + ret = -msleep(lock, &lock->lock, flags, wmsg, 0); + if (ret == -EINTR || ret == -ERESTART) + ret = -ERESTARTSYS; if (interruptible && ret != 0) { lock->flags &= ~TTM_WRITE_LOCK_PENDING; wakeup(lock); @@ -218,7 +218,7 @@ ttm_write_lock(struct ttm_lock *lock, bool interruptible) } mtx_unlock(&lock->lock); - return (-ret); + return (ret); } void ttm_write_lock_downgrade(struct ttm_lock *lock) @@ -285,9 +285,9 @@ int ttm_vt_lock(struct ttm_lock *lock, } mtx_lock(&lock->lock); while (!__ttm_vt_lock(lock)) { - ret = msleep(lock, &lock->lock, flags, wmsg, 0); - if (ret == EINTR) - ret = ERESTARTSYS; + ret = -msleep(lock, &lock->lock, flags, wmsg, 0); + if (ret == -EINTR || ret == -ERESTART) + ret = -ERESTARTSYS; if (interruptible && ret != 0) { lock->flags &= ~TTM_VT_LOCK_PENDING; wakeup(lock); @@ -308,7 +308,7 @@ int ttm_vt_lock(struct ttm_lock *lock, else lock->vt_holder = tfile; - return (-ret); + return (ret); } int ttm_vt_unlock(struct ttm_lock *lock) diff --git a/sys/modules/Makefile b/sys/modules/Makefile index 96148e4ab0af..1d88622ca116 100644 --- a/sys/modules/Makefile +++ b/sys/modules/Makefile @@ -713,6 +713,8 @@ _wi= wi .endif .if ${MACHINE_ARCH} == "powerpc64" +_drm2= drm2 +_i2c= i2c .if ${MK_ZFS} != "no" || defined(ALL_MODULES) _zfs= zfs .endif diff --git a/sys/modules/drm2/Makefile b/sys/modules/drm2/Makefile index 8f4addd6283c..701d5dc5cc56 100644 --- a/sys/modules/drm2/Makefile +++ b/sys/modules/drm2/Makefile @@ -23,6 +23,13 @@ _radeonkmsfw= radeonkmsfw . endif .endif +.if ${MACHINE_CPUARCH} == "powerpc" +_radeonkms= radeonkms +. if ${MK_SOURCELESS_UCODE} != "no" +_radeonkmsfw= radeonkmsfw +. endif +.endif + SUBDIR = \ drm2 \ ${_i915kms} \ diff --git a/sys/modules/drm2/drm2/Makefile b/sys/modules/drm2/drm2/Makefile index 3bbccb51ce86..35bee2972091 100644 --- a/sys/modules/drm2/drm2/Makefile +++ b/sys/modules/drm2/drm2/Makefile @@ -13,7 +13,6 @@ SRCS = \ drm_dma.c \ drm_dp_helper.c \ drm_dp_iic_helper.c \ - drm_drawable.c \ drm_drv.c \ drm_edid.c \ drm_fb_helper.c \ @@ -31,10 +30,10 @@ SRCS = \ drm_modes.c \ drm_pci.c \ drm_scatter.c \ - drm_sman.c \ drm_stub.c \ drm_sysctl.c \ drm_vm.c \ + drm_os_freebsd.c \ ttm_agp_backend.c \ ttm_lock.c \ ttm_object.c \ @@ -49,11 +48,16 @@ SRCS = \ ati_pcigart.c #ttm_page_alloc_dma.c -.if ${MACHINE_CPUARCH} == "amd64" +.if ${MACHINE_CPUARCH} == "amd64" || ${MACHINE_ARCH} == "powerpc64" SRCS += drm_ioc32.c .endif SRCS +=device_if.h bus_if.h pci_if.h device_if.h iicbus_if.h opt_drm.h \ opt_vm.h opt_compat.h opt_syscons.h + +.if ${MACHINE_CPUARCH} == "powerpc" +CWARNFLAGS+=-Wno-cast-qual +.endif + .include <bsd.kmod.mk> diff --git a/sys/modules/drm2/radeonkms/Makefile b/sys/modules/drm2/radeonkms/Makefile index 1e674a748e96..0c101eadea58 100644 --- a/sys/modules/drm2/radeonkms/Makefile +++ b/sys/modules/drm2/radeonkms/Makefile @@ -15,11 +15,11 @@ SRCS = \ evergreen_reg_safe.h \ cayman_reg_safe.h SRCS += \ - radeon_acpi.c \ + ${radeon_acpi} \ radeon_agp.c \ radeon_asic.c \ radeon_atombios.c \ - radeon_atpx_handler.c \ + ${radeon_atpx_handler} \ radeon_benchmark.c \ radeon_bios.c \ radeon_clocks.c \ @@ -37,6 +37,7 @@ SRCS += \ radeon_gart.c \ radeon_gem.c \ radeon_i2c.c \ + ${radeon_ioc32} \ radeon_irq.c \ radeon_irq_kms.c \ radeon_kms.c \ @@ -86,8 +87,13 @@ SRCS += \ si.c \ si_blit_shaders.c -.if ${MACHINE_CPUARCH} == "amd64" -SRCS += radeon_ioc32.c +.if ${MACHINE_CPUARCH} == "amd64" || ${MACHINE_CPUARCH} == "i386" +radeon_acpi= radeon_acpi.c +#radeon_atpx_handler= radeon_atpx_handler.c +.endif + +.if ${MACHINE_CPUARCH} == "amd64" || ${MACHINE_ARCH} == "powerpc64" +radeon_ioc32= radeon_ioc32.c .endif #radeon_prime.c @@ -106,6 +112,10 @@ SRCS += \ iicbus_if.h \ pci_if.h -CFLAGS += -I${.CURDIR}/../../../dev/drm2/radeon - .include <bsd.kmod.mk> + +CFLAGS+= -I${.CURDIR}/../../../dev/drm2/radeon + +CWARNFLAGS.radeon_cp.c= -Wno-unused-value +CWARNFLAGS.r600_cp.c= -Wno-unused-value +CWARNFLAGS+= ${CWARNFLAGS.${.IMPSRC:T}} |