svn commit: r262988 - in stable/9/sys: dev/drm2 dev/drm2/ttm modules/drm2/drm2

Jean-Sebastien Pedron dumbbell at FreeBSD.org
Mon Mar 10 23:16:21 UTC 2014


Author: dumbbell
Date: Mon Mar 10 23:16:19 2014
New Revision: 262988
URL: http://svnweb.freebsd.org/changeset/base/262988

Log:
  MFC TTM, a memory manager used by video drivers
  
  This is the last step before the merge of the Radeon KMS driver. Other
  changes to TTM will be merged with radeonkms.
  
  The following revisions were merged in this single commit:
  
  r247835:
    Import the preliminary port of the TTM.
  
    The early commit is done to facilitate the off-tree work on the
    porting of the Radeon driver.
  
    Sponsored by:	The FreeBSD Foundation
    Debugged and tested by:	    dumbbell
    MFC after:	1 month
  
  r247848:
    Fix build with gcc, remove redundand declarations.
  
    Reported and tested by:	gjb
    MFC after:	1 month
  
  r247849:
    Fix build with gcc, do not use unnamed union.
  
    Reported and tested by:	gjb
    MFC after:	1 month
  
  r248060:
    drm: Fix a call to free(9) with an incorrect malloc type
  
    While here, the call to free(9) is moved to drm_global.c, near the
    initial malloc(9).
  
    Reviewed by:	Konstantin Belousov (kib@)
  
  r248657:
    drm/ttm: Fix TTM buffer object refcount
  
    This fixes memory leaks in the radeonkms driver.
  
    Reviewed by:	Konstantin Belousov (kib@)
    Tested by:	J.R. Oldroyd <jr at opal.com>
  
  r248661:
    drm/ttm: Explain why we don't need to acquire a ref in ttm_bo_vm_ctor()
  
  r248663:
    drm/ttm: Fix a typo: s/pTTM]/[TTM]/
  
  r248666:
    Do not call malloc(M_WAITOK) while bodev->fence_lock mutex is
    held. The ttm_buffer_object_transfer() does not need the mutex locked
    at all, except for the call to the driver sync_obj_ref() method.
  
    Reported and tested by:	dumbbell
    MFC after:   2 weeks
  
  r252864:
    Remove unneeded page lock around vm_page_insert().
  
    Submitted by:	alc
  
  r253710:
    MFgem r251960: re-check the mgt device object for the requested page
    after the object was relocked.
  
    Tested by:	dumbbell
    Sponsored by:	The FreeBSD Foundation
    MFC after:	1 week
  
  r254822:
    drm: In drm_mmap_single, try ttm_bo_mmap_single() before drm_gem_mmap_single()
  
    In drivers such as the Radeon driver, the DRIVER_GEM features flag is
    set but TTM is used to mmap buffer object.
  
  r254858:
    drm: Add missing bits to drmP.h, required by the Radeon driver
  
    Some of the FreeBSD-specific definitions are moved to drm_os_freebsd.h.
    But there's still work to do to clean it up and reduce the diff with
    Linux' drmP.h.
  
  r254860:
    drm: Update drm_atomic.h, now that projects/atomic64 is in HEAD
  
    Submitted by:	jkim@
  
  r254861:
    drm/ttm: Import Linux commit 63d0a4195560362e2e00a3ad38fc331d34e1da9b
  
    Author: Maarten Lankhorst <maarten.lankhorst at canonical.com>
    Date:   Tue Jan 15 14:56:37 2013 +0100
  
        drm/ttm: remove lru_lock around ttm_bo_reserve
  
        There should no longer be assumptions that reserve will always succeed
        with the lru lock held, so we can safely break the whole atomic
        reserve/lru thing. As a bonus this fixes most lockdep annotations for
        reservations.
  
        Signed-off-by: Maarten Lankhorst <maarten.lankhorst at canonical.com>
        Reviewed-by: Jerome Glisse <jglisse at redhat.com>
  
  r254862:
    drm/ttm: Import Linux commit 7a1863084c9d90ce4b67d645bf9b0f1612e68f62
  
    Author: Maarten Lankhorst <maarten.lankhorst at canonical.com>
    Date:   Tue Jan 15 14:56:48 2013 +0100
  
        drm/ttm: cleanup ttm_eu_reserve_buffers handling
  
        With the lru lock no longer required for protecting reservations we
        can just do a ttm_bo_reserve_nolru on -EBUSY, and handle all errors
        in a single path.
  
        Signed-off-by: Maarten Lankhorst <maarten.lankhorst at canonical.com>
        Reviewed-by: Jerome Glisse <jglisse at redhat.com>
  
  r254863:
    drm/ttm: Import Linux commit 5e45d7dfd74100d622f9cdc70bfd1f9fae1671de
  
    Author: Maarten Lankhorst <maarten.lankhorst at canonical.com>
    Date:   Tue Jan 15 14:57:05 2013 +0100
  
        drm/ttm: add ttm_bo_reserve_slowpath
  
        Instead of dropping everything, waiting for the bo to be unreserved
        and trying over, a better strategy would be to do a blocking wait.
  
        This can be mapped a lot better to a mutex_lock-like call.
  
        Signed-off-by: Maarten Lankhorst <maarten.lankhorst at canonical.com>
        Reviewed-by: Jerome Glisse <jglisse at redhat.com>
  
    Approved by:	kib@
  
  r254864:
    drm/ttm: Import Linux commit f2d476a110bc24fde008698ae9018c99e803e25c
  
    Author: Maarten Lankhorst <maarten.lankhorst at canonical.com>
    Date:   Tue Jan 15 14:57:10 2013 +0100
  
        drm/ttm: use ttm_bo_reserve_slowpath_nolru in ttm_eu_reserve_buffers, v2
  
        This requires re-use of the seqno, which increases fairness slightly.
        Instead of spinning with a new seqno every time we keep the current one,
        but still drop all other reservations we hold. Only when we succeed,
        we try to get back our other reservations again.
  
        This should increase fairness slightly as well.
  
        Changes since v1:
         - Increase val_seq before calling ttm_bo_reserve_slowpath_nolru and
  	 retrying to take all entries to prevent a race.
  
        Signed-off-by: Maarten Lankhorst <maarten.lankhorst at canonical.com>
        Reviewed-by: Jerome Glisse <jglisse at redhat.com>
  
    Approved by:	kib@
  
  r254865:
    drm/ttm: Import Linux commit cc4c0c4de3c775be22072ec3251f2e581b63d9a0
  
    Author: Maarten Lankhorst <maarten.lankhorst at canonical.com>
    Date:   Tue Jan 15 14:57:28 2013 +0100
  
        drm/ttm: unexport ttm_bo_wait_unreserved
  
        All legitimate users of this function outside ttm_bo.c are gone, now
        it's only an implementation detail.
  
        Signed-off-by: Maarten Lankhorst <maarten.lankhorst at canonical.com>
        Reviewed-by: Jerome Glisse <jglisse at redhat.com>
  
    Approved by:	kib@
  
  r254866:
    drm/ttm: Import Linux commit 630541863b29f88c7ab34e647758344e4cd1eafd
  
    Author: Dave Airlie <airlied at gmail.com>
    Date:   Wed Jan 16 14:25:44 2013 +1000
  
        ttm: don't destroy old mm_node on memcpy failure
  
        When we are using memcpy to move objects around, and we fail to memcpy
        due to lack of memory to populate or failure to finish the copy, we don't
        want to destroy the mm_node that has been copied into old_copy.
  
        While working on a new kms driver that uses memcpy, if I overallocated bo's
        up to the memory limits, and eviction failed, then machine would oops soon
        after due to having an active bo with an already freed drm_mm embedded in it,
        freeing it a second time didn't end well.
  
        Reviewed-by: Jerome Glisse <jglisse at redhat.com>
        Signed-off-by: Dave Airlie <airlied at redhat.com>
  
    Approved by:	kib@
  
  r254867:
    drm/ttm: Import Linux commit 014b34409fb2015f63663b6cafdf557fdf289628
  
    Author: Dave Airlie <airlied at gmail.com>
    Date:   Wed Jan 16 15:58:34 2013 +1000
  
        ttm: on move memory failure don't leave a node dangling
  
        if we have a move notify callback, when moving fails, we call move notify
        the opposite way around, however this ends up with *mem containing the mm_node
        from the bo, which means we double free it. This is a follow on to the previous
        fix.
  
        Reviewed-by: Jerome Glisse <jglisse at redhat.com>
        Signed-off-by: Dave Airlie <airlied at redhat.com>
  
    Approved by:	kib@
  
  r254868:
    drm/ttm: Import Linux commit ff7c60c580d9722f820d85c9c58ca55ecc1ee7c4
  
    Author: Daniel Vetter <daniel.vetter at ffwll.ch>
    Date:   Mon Jan 14 15:08:14 2013 +0100
  
        drm/ttm: fix fence locking in ttm_buffer_object_transfer, 2nd try
  
        This fixes up
  
        commit e8e89622ed361c46bf90ba4828e685a8b603f7e5
        Author: Daniel Vetter <daniel.vetter at ffwll.ch>
        Date:   Tue Dec 18 22:25:11 2012 +0100
  
  	  drm/ttm: fix fence locking in ttm_buffer_object_transfer
  
        which leaves behind a might_sleep in atomic context, since the
        fence_lock spinlock is held over a kmalloc(GFP_KERNEL) call. The fix
        is to revert the above commit and only take the lock where we need it,
        around the call to ->sync_obj_ref.
  
        v2: Fixup things noticed by Maarten Lankhorst:
        - Brown paper bag locking bug.
        - No need for kzalloc if we clear the entire thing on the next line.
        - check for bo->sync_obj (totally unlikely race, but still someone
  	else could have snuck in) and clear fbo->sync_obj if it's cleared
  	already.
  
        Reported-by: Dave Airlie <airlied at gmail.com>
        Cc: Jerome Glisse <jglisse at redhat.com>
        Cc: Maarten Lankhorst <maarten.lankhorst at canonical.com>
        Signed-off-by: Daniel Vetter <daniel.vetter at ffwll.ch>
        Signed-off-by: Dave Airlie <airlied at redhat.com>
  
    Approved by:	kib@
  
  r254870:
    drm/ttm: Make ttm_bo_wait() call uninterruptible in page fault handler
  
    This fixes a crash where a SIGLALRM, heavily used by X.Org, would
    interrupt the wait, causing the page fault to fail and the "Xorg"
    process to receive a SIGSEGV.
  
    Approved by:	kib@
  
  r254871:
    drm/ttm: Fix style errors
  
  r254873:
    drm/ttm: When removing a range of pages from a pool, remove all of them
  
    Submitted by:	Mark Kettenis and Jonathan Gray from OpenBSD
    Approved by:	kib@
  
  r254874:
    drm/ttm: Improve comment in ttm_bo_vm_ctor() about lack of ref acquisition
  
    Approved by:	kib@
  
  r254875:
    ttm: "to_page->valid = VM_PAGE_BITS_ALL" before vm_page_dirty(to_page)
  
    Approved by;	kib@
  
  r254876:
    drm/ttm: Fix unmap of buffer object
  
    Add a new ttm_bo_release_mmap() function to unmap pages in a
    vm_object_t. Pages are freed when the buffer object is later released.
  
    This function is called in ttm_bo_unmap_virtual_locked(), replacing
    Linux' unmap_mapping_range(). In particular this is called when a buffer
    object is about to be moved, so that its mapping is invalidated.
  
    However, we don't use this function in ttm_bo_vm_dtor(), because the
    vm_object_t is already marked as OBJ_DEAD and the pages will be
    unmapped.
  
    Approved by:	kib@
  
  r254877:
    drm/ttm: Fix style in ttm_bo_release_mmap()
  
  r254878:
    drm/ttm: Fix a reversed condition and add missing locks
  
    This allows to run OpenGL applications on at least two test machines
    with the Radeon driver.
  
    Approved by:	kib@
  
  r254879:
    drm/ttm: Remove unused VM_ALLOC_DMA32 define
  
  r254880:
    drm: Use the new drm_atomic.h, following the merge of projects/atomic64
  
    Submitted by:	jkim@
  
  r259612:
    ttm_bo_vm_lookup_rb: actually make use of the red-black tree
  
    Previously the code would just iterate over the whole tree as if it were
    just a list.
  
    Without this change I would observe X server becoming more and more
    jerky over time.
  
    MFC after:	5 days

Added:
  stable/9/sys/dev/drm2/drm_os_freebsd.h
     - copied unchanged from r254858, head/sys/dev/drm2/drm_os_freebsd.h
  stable/9/sys/dev/drm2/ttm/
     - copied from r247835, head/sys/dev/drm2/ttm/
Modified:
  stable/9/sys/dev/drm2/drmP.h
  stable/9/sys/dev/drm2/drm_atomic.h
  stable/9/sys/dev/drm2/drm_drv.c
  stable/9/sys/dev/drm2/drm_gem.c
  stable/9/sys/dev/drm2/drm_global.c
  stable/9/sys/dev/drm2/drm_irq.c
  stable/9/sys/dev/drm2/ttm/ttm_bo.c
  stable/9/sys/dev/drm2/ttm/ttm_bo_driver.h
  stable/9/sys/dev/drm2/ttm/ttm_bo_util.c
  stable/9/sys/dev/drm2/ttm/ttm_bo_vm.c
  stable/9/sys/dev/drm2/ttm/ttm_execbuf_util.c
  stable/9/sys/dev/drm2/ttm/ttm_lock.h
  stable/9/sys/dev/drm2/ttm/ttm_memory.c
  stable/9/sys/dev/drm2/ttm/ttm_page_alloc.c
  stable/9/sys/dev/drm2/ttm/ttm_tt.c
  stable/9/sys/modules/drm2/drm2/Makefile
Directory Properties:
  stable/9/sys/   (props changed)
  stable/9/sys/dev/   (props changed)
  stable/9/sys/modules/   (props changed)

Modified: stable/9/sys/dev/drm2/drmP.h
==============================================================================
--- stable/9/sys/dev/drm2/drmP.h	Mon Mar 10 22:52:32 2014	(r262987)
+++ stable/9/sys/dev/drm2/drmP.h	Mon Mar 10 23:16:19 2014	(r262988)
@@ -1,9 +1,15 @@
-/* drmP.h -- Private header for Direct Rendering Manager -*- linux-c -*-
- * Created: Mon Jan  4 10:05:05 1999 by faith at precisioninsight.com
+/**
+ * \file drmP.h
+ * Private header for Direct Rendering Manager
+ *
+ * \author Rickard E. (Rik) Faith <faith at valinux.com>
+ * \author Gareth Hughes <gareth at valinux.com>
  */
-/*-
+
+/*
  * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
  * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * Copyright (c) 2009-2010, Code Aurora Forum.
  * All rights reserved.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
@@ -24,11 +30,6 @@
  * 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 at valinux.com>
- *    Gareth Hughes <gareth at valinux.com>
- *
  */
 
 #include <sys/cdefs.h>
@@ -39,9 +40,6 @@ __FBSDID("$FreeBSD$");
 
 #if defined(_KERNEL) || defined(__KERNEL__)
 
-struct drm_device;
-struct drm_file;
-
 #include <sys/param.h>
 #include <sys/queue.h>
 #include <sys/malloc.h>
@@ -98,12 +96,19 @@ struct drm_file;
 #include <sys/bus.h>
 
 #include <dev/drm2/drm.h>
+#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_mm.h>
+
+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>
 
 #include "opt_compat.h"
 #include "opt_drm.h"
@@ -119,6 +124,10 @@ struct drm_file;
 #undef DRM_LINUX
 #define DRM_LINUX 0
 
+/***********************************************************************/
+/** \name DRM template customization defaults */
+/*@{*/
+
 /* driver capabilities and requirements mask */
 #define DRIVER_USE_AGP     0x1
 #define DRIVER_REQUIRE_AGP 0x2
@@ -134,8 +143,8 @@ struct drm_file;
 #define DRIVER_IRQ_VBL2    0x800
 #define DRIVER_GEM         0x1000
 #define DRIVER_MODESET     0x2000
-#define DRIVER_USE_PLATFORM_DEVICE  0x4000
-#define	DRIVER_LOCKLESS_IRQ 0x8000
+#define DRIVER_PRIME       0x4000
+#define DRIVER_LOCKLESS_IRQ 0x8000
 
 
 #define DRM_HASH_SIZE	      16 /* Size of key hash table		  */
@@ -176,7 +185,10 @@ SYSCTL_DECL(_hw_drm);
 
 #define DRM_MAX_CTXBITMAP (PAGE_SIZE * 8)
 
-				/* Internal types and structures */
+/***********************************************************************/
+/** \name Internal types and structures */
+/*@{*/
+
 #define DRM_ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
 #define DRM_MIN(a,b) ((a)<(b)?(a):(b))
 #define DRM_MAX(a,b) ((a)>(b)?(a):(b))
@@ -227,12 +239,6 @@ typedef void			irqreturn_t;
 #define IRQ_HANDLED		/* nothing */
 #define IRQ_NONE		/* nothing */
 
-#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) );})
-
 enum {
 	DRM_IS_NOT_AGP,
 	DRM_IS_AGP,
@@ -254,16 +260,6 @@ enum {
 #define	time_after_eq(a,b)	((long)(b) - (long)(a) <= 0)
 #define drm_msleep(x, msg)	pause((msg), ((int64_t)(x)) * hz / 1000)
 
-typedef vm_paddr_t dma_addr_t;
-typedef uint64_t u64;
-typedef uint32_t u32;
-typedef uint16_t u16;
-typedef uint8_t u8;
-typedef int64_t s64;
-typedef int32_t s32;
-typedef int16_t s16;
-typedef int8_t s8;
-
 /* DRM_READMEMORYBARRIER() prevents reordering of reads.
  * DRM_WRITEMEMORYBARRIER() prevents reordering of writes.
  * DRM_MEMORYBARRIER() prevents reordering of reads and writes.
@@ -311,16 +307,6 @@ typedef int8_t s8;
 #define DRM_GET_USER_UNCHECKED(val, uaddr)		\
 	((val) = fuword32(uaddr), 0)
 
-#define cpu_to_le32(x) htole32(x)
-#define le32_to_cpu(x) le32toh(x)
-
-#define DRM_HZ			hz
-#define DRM_UDELAY(udelay)	DELAY(udelay)
-#define DRM_MDELAY(msecs)	do { int loops = (msecs);		\
-	                          while (loops--) DELAY(1000);		\
-				} while (0)
-#define DRM_TIME_SLICE		(hz/20)  /* Time slice for GLXContexts	  */
-
 #define DRM_GET_PRIV_SAREA(_dev, _ctx, _map) do {	\
 	(_map) = (_dev)->context_sareas[_ctx];		\
 } while(0)
@@ -371,6 +357,18 @@ for ( ret = 0 ; !ret && !(condition) ; )
 			__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__);	\
+	}								\
+} while (0)
+
 typedef struct drm_pci_id_list
 {
 	int vendor;
@@ -386,7 +384,7 @@ struct drm_msi_blacklist_entry
 };
 
 #define DRM_AUTH	0x1
-#define DRM_MASTER	0x2
+#define	DRM_MASTER	0x2
 #define DRM_ROOT_ONLY	0x4
 #define DRM_CONTROL_ALLOW 0x8
 #define DRM_UNLOCKED	0x10
@@ -396,7 +394,9 @@ typedef struct drm_ioctl_desc {
 	int (*func)(struct drm_device *dev, void *data,
 		    struct drm_file *file_priv);
 	int flags;
+	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().
@@ -404,6 +404,9 @@ typedef struct drm_ioctl_desc {
 #define DRM_IOCTL_DEF(ioctl, func, flags) \
 	[DRM_IOCTL_NR(ioctl)] = {ioctl, func, flags}
 
+#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;
@@ -416,28 +419,30 @@ typedef struct drm_magic_head {
 } drm_magic_head_t;
 
 typedef struct drm_buf {
-	int		  idx;	       /* Index into master buflist	     */
-	int		  total;       /* Buffer size			     */
-	int		  order;       /* log-base-2(total)		     */
-	int		  used;	       /* Amount of buffer in use (for DMA)  */
-	unsigned long	  offset;      /* Byte offset (used internally)	     */
-	void		  *address;    /* Address of buffer		     */
-	unsigned long	  bus_address; /* Bus address of buffer		     */
-	struct drm_buf	  *next;       /* Kernel-only: used for free list    */
-	__volatile__ int  pending;     /* On hardware DMA queue		     */
-	struct drm_file   *file_priv;  /* Unique identifier of holding process */
-	int		  context;     /* Kernel queue for this buffer	     */
+	int idx;		       /**< Index into master buflist */
+	int total;		       /**< Buffer size */
+	int order;		       /**< log-base-2(total) */
+	int used;		       /**< Amount of buffer in use (for DMA) */
+	unsigned long offset;	       /**< Byte offset (used internally) */
+	void *address;		       /**< Address of buffer */
+	unsigned long bus_address;     /**< Bus address of buffer */
+	struct drm_buf *next;	       /**< Kernel-only: used for free list */
+	__volatile__ int waiting;      /**< On kernel DMA queue */
+	__volatile__ int pending;      /**< On hardware DMA queue */
+	struct drm_file *file_priv;    /**< Private of holding file descr */
+	int context;		       /**< Kernel queue for this buffer */
+	int while_locked;	       /**< Dispatch this buffer while locked */
 	enum {
-		DRM_LIST_NONE	 = 0,
-		DRM_LIST_FREE	 = 1,
-		DRM_LIST_WAIT	 = 2,
-		DRM_LIST_PEND	 = 3,
-		DRM_LIST_PRIO	 = 4,
+		DRM_LIST_NONE = 0,
+		DRM_LIST_FREE = 1,
+		DRM_LIST_WAIT = 2,
+		DRM_LIST_PEND = 3,
+		DRM_LIST_PRIO = 4,
 		DRM_LIST_RECLAIM = 5
-	}		  list;	       /* Which list we're on		     */
+	} list;			       /**< Which list we're on */
 
-	int		  dev_priv_size; /* Size of buffer private stoarge   */
-	void		  *dev_private;  /* Per-buffer private storage       */
+	int dev_priv_size;		 /**< Size of buffer private storage */
+	void *dev_private;		 /**< Per-buffer private storage */
 } drm_buf_t;
 
 typedef struct drm_freelist {
@@ -477,6 +482,14 @@ struct drm_pending_event {
 	void (*destroy)(struct drm_pending_event *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 */
+};
+
 typedef TAILQ_HEAD(drm_file_list, drm_file) drm_file_list_t;
 struct drm_file {
 	TAILQ_ENTRY(drm_file) link;
@@ -499,6 +512,8 @@ struct drm_file {
 	struct list_head  event_list;
 	int		  event_space;
 	struct selinfo	  event_poll;
+
+	struct drm_prime_file_private prime;
 };
 
 typedef struct drm_lock_data {
@@ -517,17 +532,21 @@ typedef struct drm_lock_data {
  * concurrently accessed, so no locking is needed.
  */
 typedef struct drm_device_dma {
-	drm_buf_entry_t	  bufs[DRM_MAX_ORDER+1];
-	int		  buf_count;
-	drm_buf_t	  **buflist;	/* Vector of pointers info bufs	   */
-	int		  seg_count;
-	int		  page_count;
-	unsigned long	  *pagelist;
-	unsigned long	  byte_count;
+
+	struct drm_buf_entry bufs[DRM_MAX_ORDER + 1];	/**< buffers, grouped by their size order */
+	int buf_count;			/**< total number of buffers */
+	struct drm_buf **buflist;		/**< Vector of pointers into drm_device_dma::bufs */
+	int seg_count;
+	int page_count;			/**< number of pages */
+	unsigned long *pagelist;	/**< page list */
+	unsigned long byte_count;
 	enum {
 		_DRM_DMA_USE_AGP = 0x01,
-		_DRM_DMA_USE_SG  = 0x02
+		_DRM_DMA_USE_SG = 0x02,
+		_DRM_DMA_USE_FB = 0x04,
+		_DRM_DMA_USE_PCI_RO = 0x08
 	} flags;
+
 } drm_device_dma_t;
 
 typedef struct drm_agp_mem {
@@ -592,28 +611,13 @@ struct drm_vblank_info {
 	int inmodeset;			/* Display driver is setting mode */
 };
 
-/* Size of ringbuffer for vblank timestamps. Just double-buffer
- * in initial implementation.
- */
-#define DRM_VBLANKTIME_RBSIZE 2
-
-/* Flags and return codes for get_vblank_timestamp() driver function. */
-#define DRM_CALLED_FROM_VBLIRQ 1
-#define DRM_VBLANKTIME_SCANOUTPOS_METHOD (1 << 0)
-#define DRM_VBLANKTIME_INVBL             (1 << 1)
-
-/* get_scanout_position() return flags */
-#define DRM_SCANOUTPOS_VALID        (1 << 0)
-#define DRM_SCANOUTPOS_INVBL        (1 << 1)
-#define DRM_SCANOUTPOS_ACCURATE     (1 << 2)
-
 /* location of GART table */
 #define DRM_ATI_GART_MAIN 1
 #define DRM_ATI_GART_FB   2
 
-#define DRM_ATI_GART_PCI  1
+#define DRM_ATI_GART_PCI 1
 #define DRM_ATI_GART_PCIE 2
-#define DRM_ATI_GART_IGP  3
+#define DRM_ATI_GART_IGP 3
 
 struct drm_ati_pcigart_info {
 	int gart_table_location;
@@ -685,10 +689,58 @@ struct drm_gem_object {
 	uint32_t pending_write_domain;
 
 	void *driver_private;
+
+#ifdef DUMBBELL_WIP
+	/* 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 */
 };
 
 #include "drm_crtc.h"
 
+/* per-master structure */
+struct drm_master {
+
+	u_int refcount; /* refcount for this master */
+
+	struct list_head head; /**< each minor contains a list of masters */
+	struct drm_minor *minor; /**< link back to minor we are a master for */
+
+	char *unique;			/**< Unique identifier: e.g., busid */
+	int unique_len;			/**< Length of unique field */
+	int unique_size;		/**< amount allocated */
+
+	int blocked;			/**< Blocked due to VC switch? */
+
+	/** \name Authentication */
+	/*@{ */
+	struct drm_open_hash magiclist;
+	struct list_head magicfree;
+	/*@} */
+
+	struct drm_lock_data lock;	/**< Information on hardware lock */
+
+	void *driver_priv; /**< Private structure for driver to use */
+};
+
+/* Size of ringbuffer for vblank timestamps. Just double-buffer
+ * in initial implementation.
+ */
+#define DRM_VBLANKTIME_RBSIZE 2
+
+/* Flags and return codes for get_vblank_timestamp() driver function. */
+#define DRM_CALLED_FROM_VBLIRQ 1
+#define DRM_VBLANKTIME_SCANOUTPOS_METHOD (1 << 0)
+#define DRM_VBLANKTIME_INVBL             (1 << 1)
+
+/* get_scanout_position() return flags */
+#define DRM_SCANOUTPOS_VALID        (1 << 0)
+#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
@@ -760,7 +812,7 @@ struct drm_driver_info {
 	 *
 	 * \param dev  DRM device handle
 	 *
-	 * \returns 
+	 * \returns
 	 * One of three values is returned depending on whether or not the
 	 * card is absolutely \b not AGP (return of 0), absolutely \b is AGP
 	 * (return of 1), or may or may not be AGP (return of 2).
@@ -815,6 +867,7 @@ struct drm_cmdline_mode {
 	enum drm_connector_force force;
 };
 
+
 struct drm_pending_vblank_event {
 	struct drm_pending_event base;
 	int pipe;
@@ -824,8 +877,9 @@ struct drm_pending_vblank_event {
 /* Length for the array of resource pointers for drm_get_resource_*. */
 #define DRM_MAX_PCI_RESOURCE	6
 
-/** 
- * DRM device functions structure
+/**
+ * DRM device structure. This structure represent a complete card that
+ * may contain multiple heads.
  */
 struct drm_device {
 	struct drm_driver_info *driver;
@@ -914,6 +968,7 @@ struct drm_device {
 	struct drm_minor *control;		/**< Control node for card */
 	struct drm_minor *primary;		/**< render type primary screen head */
 
+	void		  *drm_ttm_bdev;
 	struct unrhdr	  *drw_unrhdr;
 	/* RB tree of drawable infos */
 	RB_HEAD(drawable_tree, bsd_drm_drawable_info) drw_head;
@@ -948,8 +1003,14 @@ struct drm_device {
 	void *sysctl_private;
 	char busid_str[128];
 	int modesetting;
+
+	int switch_power_state;
 };
 
+#define DRM_SWITCH_POWER_ON 0
+#define DRM_SWITCH_POWER_OFF 1
+#define DRM_SWITCH_POWER_CHANGING 2
+
 static __inline__ int drm_core_check_feature(struct drm_device *dev,
 					     int feature)
 {
@@ -1030,6 +1091,41 @@ extern int		drm_open_helper(struct cdev 
 					 DRM_STRUCTPROC *p,
 					struct drm_device *dev);
 
+#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_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);
+
+#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);
+
+
+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);
+
+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);
@@ -1311,10 +1407,16 @@ void drm_gem_release(struct drm_device *
 
 int drm_gem_create_mmap_offset(struct drm_gem_object *obj);
 void drm_gem_free_mmap_offset(struct drm_gem_object *obj);
-int drm_gem_mmap_single(struct cdev *kdev, vm_ooffset_t *offset, vm_size_t size,
-    struct vm_object **obj_res, int nprot);
+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);
+
 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,
@@ -1402,36 +1504,13 @@ static __inline__ void drm_core_dropmap(
 {
 }
 
-#define KIB_NOTYET()							\
-do {									\
-	if (drm_debug_flag && drm_notyet_flag)				\
-		printf("NOTYET: %s at %s:%d\n", __func__, __FILE__, __LINE__); \
-} while (0)
-
-#define	KTR_DRM		KTR_DEV
-#define	KTR_DRM_REG	KTR_SPARE3
-
-/* Error codes conversion from Linux to FreeBSD. */
-/* XXXKIB what is the right code for EREMOTEIO on FreeBSD? */
-#define	EREMOTEIO	ENXIO
-#define	ERESTARTSYS	ERESTART
-
-#define	PCI_VENDOR_ID_APPLE		0x106b
-#define	PCI_VENDOR_ID_ASUSTEK		0x1043
-#define	PCI_VENDOR_ID_ATI		0x1002
-#define	PCI_VENDOR_ID_DELL		0x1028
-#define	PCI_VENDOR_ID_HP		0x103c
-#define	PCI_VENDOR_ID_IBM		0x1014
-#define	PCI_VENDOR_ID_INTEL		0x8086
-#define	PCI_VENDOR_ID_SERVERWORKS	0x1166
-#define	PCI_VENDOR_ID_SONY		0x104d
-#define	PCI_VENDOR_ID_VIA		0x1106
-
 #define DRM_PCIE_SPEED_25 1
 #define DRM_PCIE_SPEED_50 2
 #define DRM_PCIE_SPEED_80 4
 
 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_ */

Modified: stable/9/sys/dev/drm2/drm_atomic.h
==============================================================================
--- stable/9/sys/dev/drm2/drm_atomic.h	Mon Mar 10 22:52:32 2014	(r262987)
+++ stable/9/sys/dev/drm2/drm_atomic.h	Mon Mar 10 23:16:19 2014	(r262988)
@@ -32,62 +32,51 @@
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
-/* Many of these implementations are rather fake, but good enough. */
+typedef uint32_t	atomic_t;
+typedef uint64_t	atomic64_t;
 
-typedef u_int32_t atomic_t;
+#define	BITS_TO_LONGS(x)		howmany(x, sizeof(long) * NBBY)
 
-#define atomic_set(p, v)	(*(p) = (v))
-#define atomic_read(p)		(*(p))
-#define atomic_inc(p)		atomic_add_int(p, 1)
-#define atomic_dec(p)		atomic_subtract_int(p, 1)
-#define atomic_add(n, p)	atomic_add_int(p, n)
-#define atomic_sub(n, p)	atomic_subtract_int(p, n)
+#define	atomic_set(p, v)		atomic_store_rel_int(p, v)
+#define	atomic_read(p)			atomic_load_acq_int(p)
 
-static __inline atomic_t
-test_and_set_bit(int b, volatile void *p)
-{
-	int s = splhigh();
-	unsigned int m = 1<<b;
-	unsigned int r = *(volatile int *)p & m;
-	*(volatile int *)p |= m;
-	splx(s);
-	return r;
-}
-
-static __inline void
-clear_bit(int b, volatile void *p)
-{
-	atomic_clear_int(((volatile int *)p) + (b >> 5), 1 << (b & 0x1f));
-}
-
-static __inline void
-set_bit(int b, volatile void *p)
-{
-	atomic_set_int(((volatile int *)p) + (b >> 5), 1 << (b & 0x1f));
-}
-
-static __inline int
-test_bit(int b, volatile void *p)
-{
-	return ((volatile int *)p)[b >> 5] & (1 << (b & 0x1f));
-}
+#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)
+#define	atomic_dec(p)			atomic_sub(1, p)
+
+#define	atomic_add_return(v, p)		(atomic_fetchadd_int(p, v) + (v))
+#define	atomic_sub_return(v, p)		(atomic_fetchadd_int(p, -(v)) - (v))
+#define	atomic_inc_return(p)		atomic_add_return(1, p)
+#define	atomic_dec_return(p)		atomic_sub_return(1, p)
+
+#define	atomic_add_and_test(v, p)	(atomic_add_return(v, p) == 0)
+#define	atomic_sub_and_test(v, p)	(atomic_sub_return(v, p) == 0)
+#define	atomic_inc_and_test(p)		(atomic_inc_return(p) == 0)
+#define	atomic_dec_and_test(p)		(atomic_dec_return(p) == 0)
+
+#define	atomic_xchg(p, v)		atomic_swap_int(p, v)
+#define	atomic64_xchg(p, v)		atomic_swap_64(p, v)
+
+#define	clear_bit(b, p) \
+    atomic_clear_int((volatile u_int *)(p) + (b) / 32, 1 << (b) % 32)
+#define	set_bit(b, p) \
+    atomic_set_int((volatile u_int *)(p) + (b) / 32, 1 << (b) % 32)
+#define	test_bit(b, p) \
+    (atomic_load_acq_int((volatile u_int *)(p) + (b) / 32) & (1 << (b) % 32))
+#define	test_and_set_bit(b, p) \
+    atomic_testandset_int((volatile u_int *)(p) + (b) / 32, b)
 
 static __inline int
 find_first_zero_bit(volatile void *p, int max)
 {
-	int b;
-	volatile int *ptr = (volatile int *)p;
+	volatile int *np = p;
+	int i, n;
 
-	for (b = 0; b < max; b += 32) {
-		if (ptr[b >> 5] != ~0) {
-			for (;;) {
-				if ((ptr[b >> 5] & (1 << (b & 0x1f))) == 0)
-					return b;
-				b++;
-			}
-		}
+	for (i = 0; i < max / (NBBY * sizeof(int)); i++) {
+		n = ~np[i];
+		if (n != 0)
+			return (i * NBBY * sizeof(int) + ffs(n) - 1);
 	}
-	return max;
+	return (max);
 }
-
-#define	BITS_TO_LONGS(x) (howmany((x), NBBY * sizeof(long)))

Modified: stable/9/sys/dev/drm2/drm_drv.c
==============================================================================
--- stable/9/sys/dev/drm2/drm_drv.c	Mon Mar 10 22:52:32 2014	(r262987)
+++ stable/9/sys/dev/drm2/drm_drv.c	Mon Mar 10 23:16:19 2014	(r262988)
@@ -66,6 +66,8 @@ static int drm_load(struct drm_device *d
 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);
 
 static int
 drm_modevent(module_t mod, int type, void *data)
@@ -195,7 +197,7 @@ static struct cdevsw drm_cdevsw = {
 	.d_ioctl =	drm_ioctl,
 	.d_poll =	drm_poll,
 	.d_mmap =	drm_mmap,
-	.d_mmap_single = drm_gem_mmap_single,
+	.d_mmap_single = drm_mmap_single,
 	.d_name =	"drm",
 	.d_flags =	D_TRACKCLOSE
 };
@@ -990,6 +992,23 @@ drm_add_busid_modesetting(struct drm_dev
 	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);
+	}
+}
+
 #if DRM_LINUX
 
 #include <sys/sysproto.h>

Modified: stable/9/sys/dev/drm2/drm_gem.c
==============================================================================
--- stable/9/sys/dev/drm2/drm_gem.c	Mon Mar 10 22:52:32 2014	(r262987)
+++ stable/9/sys/dev/drm2/drm_gem.c	Mon Mar 10 23:16:19 2014	(r262988)
@@ -121,7 +121,7 @@ drm_gem_private_object_init(struct drm_d
 	obj->vm_obj = NULL;
 
 	obj->refcount = 1;
-	atomic_set(&obj->handle_count, 0);
+	atomic_store_rel_int(&obj->handle_count, 0);
 	obj->size = size;
 
 	return (0);
@@ -465,16 +465,12 @@ drm_gem_free_mmap_offset(struct drm_gem_
 }
 
 int
-drm_gem_mmap_single(struct cdev *kdev, vm_ooffset_t *offset, vm_size_t size,
+drm_gem_mmap_single(struct drm_device *dev, vm_ooffset_t *offset, vm_size_t size,
     struct vm_object **obj_res, int nprot)
 {
-	struct drm_device *dev;
 	struct drm_gem_object *gem_obj;
 	struct vm_object *vm_obj;
 
-	dev = drm_get_device_from_kdev(kdev);
-	if ((dev->driver->driver_features & DRIVER_GEM) == 0)
-		return (ENODEV);
 	DRM_LOCK(dev);
 	gem_obj = drm_gem_object_from_offset(dev, *offset);
 	if (gem_obj == NULL) {

Modified: stable/9/sys/dev/drm2/drm_global.c
==============================================================================
--- stable/9/sys/dev/drm2/drm_global.c	Mon Mar 10 22:52:32 2014	(r262987)
+++ stable/9/sys/dev/drm2/drm_global.c	Mon Mar 10 23:16:19 2014	(r262988)
@@ -104,6 +104,7 @@ void drm_global_item_unref(struct drm_gl
 	MPASS(ref->object == item->object);
 	if (--item->refcount == 0) {
 		ref->release(ref);
+		free(item->object, M_DRM_GLOBAL);
 		item->object = NULL;
 	}
 	sx_xunlock(&item->mutex);

Modified: stable/9/sys/dev/drm2/drm_irq.c
==============================================================================
--- stable/9/sys/dev/drm2/drm_irq.c	Mon Mar 10 22:52:32 2014	(r262987)
+++ stable/9/sys/dev/drm2/drm_irq.c	Mon Mar 10 23:16:19 2014	(r262988)
@@ -786,7 +786,7 @@ int drm_vblank_get(struct drm_device *de
 
 	mtx_lock(&dev->vbl_lock);
 	/* Going from 0->1 means we have to enable interrupts again */
-	if (atomic_fetchadd_int(&dev->vblank_refcount[crtc], 1) == 0) {
+	if (atomic_add_return(1, &dev->vblank_refcount[crtc]) == 1) {
 		mtx_lock(&dev->vblank_time_lock);
 		if (!dev->vblank_enabled[crtc]) {
 			/* Enable vblank irqs under vblank_time_lock protection.
@@ -831,7 +831,7 @@ void drm_vblank_put(struct drm_device *d
 	    ("Too many drm_vblank_put for crtc %d", crtc));
 
 	/* Last user schedules interrupt disable */
-	if (atomic_fetchadd_int(&dev->vblank_refcount[crtc], -1) == 1 &&
+	if (atomic_dec_and_test(&dev->vblank_refcount[crtc]) &&
 	    (drm_vblank_offdelay > 0))
 		callout_reset(&dev->vblank_disable_callout,
 		    (drm_vblank_offdelay * DRM_HZ) / 1000,

Copied: stable/9/sys/dev/drm2/drm_os_freebsd.h (from r254858, head/sys/dev/drm2/drm_os_freebsd.h)
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ stable/9/sys/dev/drm2/drm_os_freebsd.h	Mon Mar 10 23:16:19 2014	(r262988, copy of r254858, head/sys/dev/drm2/drm_os_freebsd.h)
@@ -0,0 +1,144 @@
+/**
+ * \file drm_os_freebsd.h
+ * OS abstraction macros.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#if _BYTE_ORDER == _BIG_ENDIAN
+#define	__BIG_ENDIAN 4321
+#else
+#define	__LITTLE_ENDIAN 1234
+#endif
+
+#define	cpu_to_le16(x)	htole16(x)
+#define	le16_to_cpu(x)	le16toh(x)
+#define	cpu_to_le32(x)	htole32(x)
+#define	le32_to_cpu(x)	le32toh(x)
+
+#define	cpu_to_be16(x)	htobe16(x)
+#define	be16_to_cpu(x)	be16toh(x)
+#define	cpu_to_be32(x)	htobe32(x)
+#define	be32_to_cpu(x)	be32toh(x)
+#define	be32_to_cpup(x)	be32toh(*x)
+
+typedef vm_paddr_t dma_addr_t;
+typedef uint64_t u64;
+typedef uint32_t u32;
+typedef uint16_t u16;
+typedef uint8_t u8;
+typedef int64_t s64;
+typedef int32_t s32;
+typedef int16_t s16;
+typedef int8_t s8;
+typedef int32_t __be32;
+
+#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);		\
+				  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	do_div(a, b)		((a) /= (b))
+#define	lower_32_bits(n)	((u32)(n))
+
+#define min_t(type, x, y) ({			\
+	type __min1 = (x);			\
+	type __min2 = (y);			\
+	__min1 < __min2 ? __min1 : __min2; })
+
+#define max_t(type, x, y) ({			\
+	type __max1 = (x);			\
+	type __max2 = (y);			\
+	__max1 > __max2 ? __max1 : __max2; })
+
+#define	memset_io(a, b, c)	memset((a), (b), (c))
+#define	memcpy_fromio(a, b, c)	memcpy((a), (b), (c))
+#define	memcpy_toio(a, b, c)	memcpy((a), (b), (c))
+
+/* XXXKIB what is the right code for the FreeBSD ? */
+/* kib@ used ENXIO here -- dumbbell@ */
+#define	EREMOTEIO	EIO
+#define	ERESTARTSYS	ERESTART
+
+#define	KTR_DRM		KTR_DEV
+#define	KTR_DRM_REG	KTR_SPARE3
+
+#define	PCI_VENDOR_ID_APPLE		0x106b
+#define	PCI_VENDOR_ID_ASUSTEK		0x1043
+#define	PCI_VENDOR_ID_ATI		0x1002
+#define	PCI_VENDOR_ID_DELL		0x1028
+#define	PCI_VENDOR_ID_HP		0x103c
+#define	PCI_VENDOR_ID_IBM		0x1014
+#define	PCI_VENDOR_ID_INTEL		0x8086
+#define	PCI_VENDOR_ID_SERVERWORKS	0x1166
+#define	PCI_VENDOR_ID_SONY		0x104d
+#define	PCI_VENDOR_ID_VIA		0x1106
+
+#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
+#define	hweight32(i)	bitcount32(i)
+
+static inline unsigned long
+roundup_pow_of_two(unsigned long x)
+{
+	return (1UL << flsl(x - 1));
+}
+
+/**
+ * ror32 - rotate a 32-bit value right
+ * @word: value to rotate
+ * @shift: bits to roll
+ *
+ * Source: include/linux/bitops.h
+ */
+static inline uint32_t ror32(uint32_t word, unsigned int shift)
+{
+	return (word >> shift) | (word << (32 - shift));
+}
+
+#define	IS_ALIGNED(x, y)	(((x) & ((y) - 1)) == 0)
+#define	get_unaligned(ptr)                                              \
+	({ __typeof__(*(ptr)) __tmp;                                    \
+	  memcpy(&__tmp, (ptr), sizeof(*(ptr))); __tmp; })
+
+#if _BYTE_ORDER == _LITTLE_ENDIAN
+/* Taken from linux/include/linux/unaligned/le_struct.h. */
+struct __una_u32 { u32 x; } __packed;
+
+static inline u32 __get_unaligned_cpu32(const void *p)
+{
+	const struct __una_u32 *ptr = (const struct __una_u32 *)p;
+	return ptr->x;
+}
+
+static inline u32 get_unaligned_le32(const void *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)
+{
+	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
+
+#define KIB_NOTYET()							\
+do {									\
+	if (drm_debug_flag && drm_notyet_flag)				\
+		printf("NOTYET: %s at %s:%d\n", __func__, __FILE__, __LINE__); \
+} while (0)

Modified: stable/9/sys/dev/drm2/ttm/ttm_bo.c
==============================================================================
--- head/sys/dev/drm2/ttm/ttm_bo.c	Tue Mar  5 09:49:34 2013	(r247835)
+++ stable/9/sys/dev/drm2/ttm/ttm_bo.c	Mon Mar 10 23:16:19 2014	(r262988)
@@ -131,7 +131,7 @@ static void ttm_bo_release_list(struct t
 	ttm_mem_global_free(bdev->glob->mem_glob, acc_size);
 }
 
-int
+static int
 ttm_bo_wait_unreserved_locked(struct ttm_buffer_object *bo, bool interruptible)
 {
 	const char *wmsg;
@@ -145,7 +145,7 @@ ttm_bo_wait_unreserved_locked(struct ttm
 		flags = 0;
 		wmsg = "ttbowu";
 	}
-	while (!ttm_bo_is_reserved(bo)) {
+	while (ttm_bo_is_reserved(bo)) {
 		ret = -msleep(bo, &bo->glob->lru_lock, flags, wmsg, 0);
 		if (ret != 0)
 			break;
@@ -196,13 +196,13 @@ int ttm_bo_del_from_lru(struct ttm_buffe
 	return put_count;
 }
 
-int ttm_bo_reserve_locked(struct ttm_buffer_object *bo,
+int ttm_bo_reserve_nolru(struct ttm_buffer_object *bo,
 			  bool interruptible,
 			  bool no_wait, bool use_sequence, uint32_t sequence)
 {
 	int ret;
 
-	while (unlikely(atomic_read(&bo->reserved) != 0)) {
+	while (unlikely(atomic_xchg(&bo->reserved, 1) != 0)) {
 		/**
 		 * Deadlock avoidance for multi-bo reserving.
 		 */
@@ -224,22 +224,35 @@ int ttm_bo_reserve_locked(struct ttm_buf
 			return -EBUSY;
 
 		ret = ttm_bo_wait_unreserved_locked(bo, interruptible);
+
 		if (unlikely(ret))
 			return ret;
 	}
 
-	atomic_set(&bo->reserved, 1);
 	if (use_sequence) {
+		bool wake_up = false;
 		/**
 		 * Wake up waiters that may need to recheck for deadlock,
 		 * if we decreased the sequence number.
 		 */
 		if (unlikely((bo->val_seq - sequence < (1 << 31))
 			     || !bo->seq_valid))
-			wakeup(bo);
+			wake_up = true;
 
+		/*
+		 * In the worst case with memory ordering these values can be
+		 * seen in the wrong order. However since we call wake_up_all
+		 * in that case, this will hopefully not pose a problem,
+		 * and the worst case would only cause someone to accidentally
+		 * hit -EAGAIN in ttm_bo_reserve when they see old value of
+		 * val_seq. However this would only happen if seq_valid was
+		 * written before val_seq was, and just means some slightly
+		 * increased cpu usage
+		 */
 		bo->val_seq = sequence;
 		bo->seq_valid = true;
+		if (wake_up)
+			wakeup(bo);
 	} else {
 		bo->seq_valid = false;
 	}
@@ -268,15 +281,67 @@ int ttm_bo_reserve(struct ttm_buffer_obj
 	int put_count = 0;
 	int ret;
 
-	mtx_lock(&glob->lru_lock);
-	ret = ttm_bo_reserve_locked(bo, interruptible, no_wait, use_sequence,
-				    sequence);
-	if (likely(ret == 0))
+	mtx_lock(&bo->glob->lru_lock);
+	ret = ttm_bo_reserve_nolru(bo, interruptible, no_wait, use_sequence,
+				   sequence);
+	if (likely(ret == 0)) {
 		put_count = ttm_bo_del_from_lru(bo);
-	mtx_unlock(&glob->lru_lock);
+		mtx_unlock(&glob->lru_lock);
+		ttm_bo_list_ref_sub(bo, put_count, true);
+	} else
+		mtx_unlock(&bo->glob->lru_lock);
 
-	ttm_bo_list_ref_sub(bo, put_count, true);
+	return ret;
+}
+
+int ttm_bo_reserve_slowpath_nolru(struct ttm_buffer_object *bo,
+				  bool interruptible, uint32_t sequence)
+{
+	bool wake_up = false;
+	int ret;
+
+	while (unlikely(atomic_xchg(&bo->reserved, 1) != 0)) {
+		if (bo->seq_valid && sequence == bo->val_seq) {
+			DRM_ERROR(
+			    "%s: bo->seq_valid && sequence == bo->val_seq",
+			    __func__);

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-all mailing list