drm: Merge the drm and drm2 implementations
authorFrançois Tigeot <ftigeot@wolfpond.org>
Sun, 1 Sep 2013 19:38:11 +0000 (21:38 +0200)
committerFrançois Tigeot <ftigeot@wolfpond.org>
Sun, 1 Sep 2013 20:30:22 +0000 (22:30 +0200)
* Move the drm2 i915 driver to sys/dev/drm/i915kms

* The legacy i915 driver remains untouched

* Only sys/dev/drm/ shall remain

161 files changed:
sys/dev/Makefile
sys/dev/drm/Makefile
sys/dev/drm/ati_pcigart.c
sys/dev/drm/drm.h
sys/dev/drm/drm/Makefile
sys/dev/drm/drmP.h
sys/dev/drm/drm_agpsupport.c
sys/dev/drm/drm_atomic.h
sys/dev/drm/drm_auth.c
sys/dev/drm/drm_bufs.c
sys/dev/drm/drm_context.c
sys/dev/drm/drm_crtc.c [moved from sys/dev/drm2/drm_crtc.c with 99% similarity]
sys/dev/drm/drm_crtc.h [moved from sys/dev/drm2/drm_crtc.h with 99% similarity]
sys/dev/drm/drm_crtc_helper.c [moved from sys/dev/drm2/drm_crtc_helper.c with 99% similarity]
sys/dev/drm/drm_crtc_helper.h [moved from sys/dev/drm2/drm_crtc_helper.h with 100% similarity]
sys/dev/drm/drm_dma.c
sys/dev/drm/drm_dp_helper.h [moved from sys/dev/drm2/drm_dp_helper.h with 100% similarity]
sys/dev/drm/drm_dp_iic_helper.c [moved from sys/dev/drm2/drm_dp_iic_helper.c with 98% similarity]
sys/dev/drm/drm_drawable.c
sys/dev/drm/drm_drv.c
sys/dev/drm/drm_edid.c [moved from sys/dev/drm2/drm_edid.c with 99% similarity]
sys/dev/drm/drm_edid.h [moved from sys/dev/drm2/drm_edid.h with 99% similarity]
sys/dev/drm/drm_edid_modes.h [moved from sys/dev/drm2/drm_edid_modes.h with 99% similarity]
sys/dev/drm/drm_fb_helper.c [moved from sys/dev/drm2/drm_fb_helper.c with 99% similarity]
sys/dev/drm/drm_fb_helper.h [moved from sys/dev/drm2/drm_fb_helper.h with 100% similarity]
sys/dev/drm/drm_fops.c
sys/dev/drm/drm_fourcc.h [moved from sys/dev/drm2/drm_fourcc.h with 100% similarity]
sys/dev/drm/drm_gem.c [moved from sys/dev/drm2/drm_gem.c with 99% similarity]
sys/dev/drm/drm_gem_names.c [moved from sys/dev/drm2/drm_gem_names.c with 98% similarity]
sys/dev/drm/drm_gem_names.h [moved from sys/dev/drm2/drm_gem_names.h with 100% similarity]
sys/dev/drm/drm_global.c [moved from sys/dev/drm2/drm_global.c with 98% similarity]
sys/dev/drm/drm_global.h [moved from sys/dev/drm2/drm_global.h with 100% similarity]
sys/dev/drm/drm_hashtab.h
sys/dev/drm/drm_ioctl.c
sys/dev/drm/drm_irq.c
sys/dev/drm/drm_linux_list.h
sys/dev/drm/drm_linux_list_sort.c [moved from sys/dev/drm2/drm_linux_list_sort.c with 95% similarity]
sys/dev/drm/drm_lock.c
sys/dev/drm/drm_memory.c
sys/dev/drm/drm_mm.c
sys/dev/drm/drm_mm.h
sys/dev/drm/drm_mode.h [moved from sys/dev/drm2/drm_mode.h with 100% similarity]
sys/dev/drm/drm_modes.c [moved from sys/dev/drm2/drm_modes.c with 99% similarity]
sys/dev/drm/drm_pci.c
sys/dev/drm/drm_pciids.h
sys/dev/drm/drm_scatter.c
sys/dev/drm/drm_sman.c
sys/dev/drm/drm_stub.c [moved from sys/dev/drm2/drm_stub.c with 100% similarity]
sys/dev/drm/drm_sysctl.c
sys/dev/drm/drm_vm.c
sys/dev/drm/i915/i915_dma.c
sys/dev/drm/i915/i915_drv.c
sys/dev/drm/i915/i915_drv.h
sys/dev/drm/i915/i915_irq.c
sys/dev/drm/i915/i915_mem.c
sys/dev/drm/i915kms/Makefile [moved from sys/dev/drm2/i915/Makefile with 100% similarity]
sys/dev/drm/i915kms/i915_debug.c [moved from sys/dev/drm2/i915/i915_debug.c with 99% similarity]
sys/dev/drm/i915kms/i915_dma.c [moved from sys/dev/drm2/i915/i915_dma.c with 99% similarity]
sys/dev/drm/i915kms/i915_drm.h [moved from sys/dev/drm2/i915/i915_drm.h with 99% similarity]
sys/dev/drm/i915kms/i915_drv.c [moved from sys/dev/drm2/i915/i915_drv.c with 98% similarity]
sys/dev/drm/i915kms/i915_drv.h [moved from sys/dev/drm2/i915/i915_drv.h with 99% similarity]
sys/dev/drm/i915kms/i915_gem.c [moved from sys/dev/drm2/i915/i915_gem.c with 99% similarity]
sys/dev/drm/i915kms/i915_gem_evict.c [moved from sys/dev/drm2/i915/i915_gem_evict.c with 98% similarity]
sys/dev/drm/i915kms/i915_gem_execbuffer.c [moved from sys/dev/drm2/i915/i915_gem_execbuffer.c with 99% similarity]
sys/dev/drm/i915kms/i915_gem_gtt.c [moved from sys/dev/drm2/i915/i915_gem_gtt.c with 98% similarity]
sys/dev/drm/i915kms/i915_gem_tiling.c [moved from sys/dev/drm2/i915/i915_gem_tiling.c with 99% similarity]
sys/dev/drm/i915kms/i915_irq.c [moved from sys/dev/drm2/i915/i915_irq.c with 99% similarity]
sys/dev/drm/i915kms/i915_reg.h [moved from sys/dev/drm2/i915/i915_reg.h with 100% similarity]
sys/dev/drm/i915kms/i915_suspend.c [moved from sys/dev/drm2/i915/i915_suspend.c with 99% similarity]
sys/dev/drm/i915kms/intel_bios.c [moved from sys/dev/drm2/i915/intel_bios.c with 99% similarity]
sys/dev/drm/i915kms/intel_bios.h [moved from sys/dev/drm2/i915/intel_bios.h with 99% similarity]
sys/dev/drm/i915kms/intel_crt.c [moved from sys/dev/drm2/i915/intel_crt.c with 98% similarity]
sys/dev/drm/i915kms/intel_display.c [moved from sys/dev/drm2/i915/intel_display.c with 99% similarity]
sys/dev/drm/i915kms/intel_dp.c [moved from sys/dev/drm2/i915/intel_dp.c with 99% similarity]
sys/dev/drm/i915kms/intel_drv.h [moved from sys/dev/drm2/i915/intel_drv.h with 98% similarity]
sys/dev/drm/i915kms/intel_fb.c [moved from sys/dev/drm2/i915/intel_fb.c with 96% similarity]
sys/dev/drm/i915kms/intel_hdmi.c [moved from sys/dev/drm2/i915/intel_hdmi.c with 98% similarity]
sys/dev/drm/i915kms/intel_iic.c [moved from sys/dev/drm2/i915/intel_iic.c with 98% similarity]
sys/dev/drm/i915kms/intel_lvds.c [moved from sys/dev/drm2/i915/intel_lvds.c with 99% similarity]
sys/dev/drm/i915kms/intel_modes.c [moved from sys/dev/drm2/i915/intel_modes.c with 95% similarity]
sys/dev/drm/i915kms/intel_opregion.c [moved from sys/dev/drm2/i915/intel_opregion.c with 99% similarity]
sys/dev/drm/i915kms/intel_overlay.c [moved from sys/dev/drm2/i915/intel_overlay.c with 99% similarity]
sys/dev/drm/i915kms/intel_panel.c [moved from sys/dev/drm2/i915/intel_panel.c with 98% similarity]
sys/dev/drm/i915kms/intel_ringbuffer.c [moved from sys/dev/drm2/i915/intel_ringbuffer.c with 99% similarity]
sys/dev/drm/i915kms/intel_ringbuffer.h [moved from sys/dev/drm2/i915/intel_ringbuffer.h with 100% similarity]
sys/dev/drm/i915kms/intel_sdvo.c [moved from sys/dev/drm2/i915/intel_sdvo.c with 99% similarity]
sys/dev/drm/i915kms/intel_sdvo_regs.h [moved from sys/dev/drm2/i915/intel_sdvo_regs.h with 100% similarity]
sys/dev/drm/i915kms/intel_sprite.c [moved from sys/dev/drm2/i915/intel_sprite.c with 98% similarity]
sys/dev/drm/i915kms/intel_tv.c [moved from sys/dev/drm2/i915/intel_tv.c with 99% similarity]
sys/dev/drm/mach64/mach64_dma.c
sys/dev/drm/mach64/mach64_drv.c
sys/dev/drm/mach64/mach64_state.c
sys/dev/drm/mga/mga_dma.c
sys/dev/drm/mga/mga_drv.c
sys/dev/drm/r128/r128_cce.c
sys/dev/drm/r128/r128_drv.c
sys/dev/drm/r128/r128_state.c
sys/dev/drm/radeon/radeon_cp.c
sys/dev/drm/radeon/radeon_cs.c
sys/dev/drm/radeon/radeon_drv.c
sys/dev/drm/radeon/radeon_drv.h
sys/dev/drm/radeon/radeon_mem.c
sys/dev/drm/radeon/radeon_state.c
sys/dev/drm/savage/savage_bci.c
sys/dev/drm/savage/savage_drv.c
sys/dev/drm/savage/savage_state.c
sys/dev/drm/sis/sis_drv.c
sys/dev/drm/sis/sis_ds.c
sys/dev/drm/tdfx/tdfx_drv.c
sys/dev/drm/ttm/ttm_agp_backend.c [moved from sys/dev/drm2/ttm/ttm_agp_backend.c with 95% similarity]
sys/dev/drm/ttm/ttm_bo.c [moved from sys/dev/drm2/ttm/ttm_bo.c with 99% similarity]
sys/dev/drm/ttm/ttm_bo_api.h [moved from sys/dev/drm2/ttm/ttm_bo_api.h with 99% similarity]
sys/dev/drm/ttm/ttm_bo_driver.h [moved from sys/dev/drm2/ttm/ttm_bo_driver.h with 99% similarity]
sys/dev/drm/ttm/ttm_bo_manager.c [moved from sys/dev/drm2/ttm/ttm_bo_manager.c with 96% similarity]
sys/dev/drm/ttm/ttm_bo_util.c [moved from sys/dev/drm2/ttm/ttm_bo_util.c with 99% similarity]
sys/dev/drm/ttm/ttm_bo_vm.c [moved from sys/dev/drm2/ttm/ttm_bo_vm.c with 98% similarity]
sys/dev/drm/ttm/ttm_execbuf_util.c [moved from sys/dev/drm2/ttm/ttm_execbuf_util.c with 97% similarity]
sys/dev/drm/ttm/ttm_execbuf_util.h [moved from sys/dev/drm2/ttm/ttm_execbuf_util.h with 99% similarity]
sys/dev/drm/ttm/ttm_lock.c [moved from sys/dev/drm2/ttm/ttm_lock.c with 99% similarity]
sys/dev/drm/ttm/ttm_lock.h [moved from sys/dev/drm2/ttm/ttm_lock.h with 98% similarity]
sys/dev/drm/ttm/ttm_memory.c [moved from sys/dev/drm2/ttm/ttm_memory.c with 98% similarity]
sys/dev/drm/ttm/ttm_memory.h [moved from sys/dev/drm2/ttm/ttm_memory.h with 100% similarity]
sys/dev/drm/ttm/ttm_module.h [moved from sys/dev/drm2/ttm/ttm_module.h with 100% similarity]
sys/dev/drm/ttm/ttm_object.c [moved from sys/dev/drm2/ttm/ttm_object.c with 98% similarity]
sys/dev/drm/ttm/ttm_object.h [moved from sys/dev/drm2/ttm/ttm_object.h with 99% similarity]
sys/dev/drm/ttm/ttm_page_alloc.c [moved from sys/dev/drm2/ttm/ttm_page_alloc.c with 99% similarity]
sys/dev/drm/ttm/ttm_page_alloc.h [moved from sys/dev/drm2/ttm/ttm_page_alloc.h with 97% similarity]
sys/dev/drm/ttm/ttm_page_alloc_dma.c [moved from sys/dev/drm2/ttm/ttm_page_alloc_dma.c with 100% similarity]
sys/dev/drm/ttm/ttm_placement.h [moved from sys/dev/drm2/ttm/ttm_placement.h with 100% similarity]
sys/dev/drm/ttm/ttm_tt.c [moved from sys/dev/drm2/ttm/ttm_tt.c with 98% similarity]
sys/dev/drm2/Makefile [deleted file]
sys/dev/drm2/drm.h [deleted file]
sys/dev/drm2/drmP.h [deleted file]
sys/dev/drm2/drm_agpsupport.c [deleted file]
sys/dev/drm2/drm_atomic.h [deleted file]
sys/dev/drm2/drm_auth.c [deleted file]
sys/dev/drm2/drm_bufs.c [deleted file]
sys/dev/drm2/drm_context.c [deleted file]
sys/dev/drm2/drm_dma.c [deleted file]
sys/dev/drm2/drm_drawable.c [deleted file]
sys/dev/drm2/drm_drv.c [deleted file]
sys/dev/drm2/drm_fops.c [deleted file]
sys/dev/drm2/drm_hashtab.c [deleted file]
sys/dev/drm2/drm_hashtab.h [deleted file]
sys/dev/drm2/drm_internal.h [deleted file]
sys/dev/drm2/drm_ioctl.c [deleted file]
sys/dev/drm2/drm_irq.c [deleted file]
sys/dev/drm2/drm_linux_list.h [deleted file]
sys/dev/drm2/drm_lock.c [deleted file]
sys/dev/drm2/drm_memory.c [deleted file]
sys/dev/drm2/drm_mm.c [deleted file]
sys/dev/drm2/drm_mm.h [deleted file]
sys/dev/drm2/drm_pci.c [deleted file]
sys/dev/drm2/drm_pciids.h [deleted file]
sys/dev/drm2/drm_sarea.h [deleted file]
sys/dev/drm2/drm_scatter.c [deleted file]
sys/dev/drm2/drm_sman.c [deleted file]
sys/dev/drm2/drm_sman.h [deleted file]
sys/dev/drm2/drm_sysctl.c [deleted file]
sys/dev/drm2/drm_vm.c [deleted file]
sys/dev/drm2/drmn/Makefile [deleted file]

index 100613b..a32fdfc 100644 (file)
@@ -6,7 +6,6 @@ SUBDIR= \
        crypto \
        disk \
        drm \
-       drm2 \
        misc \
        netif \
        pccard \
index c3f0918..41133cc 100644 (file)
@@ -1,6 +1,6 @@
 # $DragonFly: src/sys/dev/drm/Makefile,v 1.3 2008/04/05 18:12:28 hasso Exp $
 
-SUBDIR = drm mach64 mga r128 radeon savage sis tdfx i915
+SUBDIR = drm mach64 mga r128 radeon savage sis tdfx i915 i915kms
 
 .include <bsd.obj.mk>
 
index 1a417c3..62b0c0b 100644 (file)
@@ -61,12 +61,12 @@ drm_ati_alloc_pcigart_table(struct drm_device *dev,
        struct drm_dma_handle *dmah;
        int flags, ret;
 
-       dmah = malloc(sizeof(struct drm_dma_handle), DRM_MEM_DMA,
+       dmah = kmalloc(sizeof(struct drm_dma_handle), DRM_MEM_DMA,
            M_ZERO | M_NOWAIT);
        if (dmah == NULL)
                return ENOMEM;
 
-       DRM_UNLOCK();
+       DRM_UNLOCK(dev);
        ret = bus_dma_tag_create(NULL, PAGE_SIZE, 0, /* tag, align, boundary */
            gart_info->table_mask, BUS_SPACE_MAXADDR, /* lowaddr, highaddr */
            NULL, NULL, /* filtfunc, filtfuncargs */
@@ -75,7 +75,7 @@ drm_ati_alloc_pcigart_table(struct drm_device *dev,
            0, /* flags */
            &dmah->tag);
        if (ret != 0) {
-               free(dmah, DRM_MEM_DMA);
+               kfree(dmah, DRM_MEM_DMA);
                return ENOMEM;
        }
 
@@ -87,10 +87,10 @@ drm_ati_alloc_pcigart_table(struct drm_device *dev,
        ret = bus_dmamem_alloc(dmah->tag, &dmah->vaddr, flags, &dmah->map);
        if (ret != 0) {
                bus_dma_tag_destroy(dmah->tag);
-               free(dmah, DRM_MEM_DMA);
+               kfree(dmah, DRM_MEM_DMA);
                return ENOMEM;
        }
-       DRM_LOCK();
+       DRM_LOCK(dev);
 
        ret = bus_dmamap_load(dmah->tag, dmah->map, dmah->vaddr,
            gart_info->table_size, drm_ati_alloc_pcigart_table_cb, dmah,
@@ -98,7 +98,7 @@ drm_ati_alloc_pcigart_table(struct drm_device *dev,
        if (ret != 0) {
                bus_dmamem_free(dmah->tag, dmah->vaddr, dmah->map);
                bus_dma_tag_destroy(dmah->tag);
-               free(dmah, DRM_MEM_DMA);
+               kfree(dmah, DRM_MEM_DMA);
                return ENOMEM;
        }
 
@@ -115,7 +115,7 @@ drm_ati_free_pcigart_table(struct drm_device *dev,
 
        bus_dmamem_free(dmah->tag, dmah->vaddr, dmah->map);
        bus_dma_tag_destroy(dmah->tag);
-       free(dmah, DRM_MEM_DMA);
+       kfree(dmah, DRM_MEM_DMA);
        gart_info->dmah = NULL;
 }
 
index 942a9ae..886d88d 100644 (file)
@@ -31,6 +31,8 @@
  * 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.
+ *
+ * $FreeBSD: src/sys/dev/drm2/drm.h,v 1.1 2012/05/22 11:07:44 kib Exp $
  */
 
 /**
@@ -95,6 +97,7 @@
 #if defined(__linux__) || defined(__NetBSD__)
 #define DRM_MAJOR       226
 #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 */
@@ -235,7 +238,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_TTM = 6
+       _DRM_GEM = 6              /**< GEM */
 };
 
 /**
@@ -521,15 +524,18 @@ 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 */
+       _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_NEXTONMISS = 0x10000000,    /**< If missed, wait for next vblank */
        _DRM_VBLANK_SECONDARY = 0x20000000,     /**< Secondary display controller */
        _DRM_VBLANK_SIGNAL = 0x40000000 /**< Send signal instead of blocking */
 };
+#define _DRM_VBLANK_HIGH_CRTC_SHIFT 1
 
 #define _DRM_VBLANK_TYPES_MASK (_DRM_VBLANK_ABSOLUTE | _DRM_VBLANK_RELATIVE)
-#define _DRM_VBLANK_FLAGS_MASK (_DRM_VBLANK_SIGNAL | _DRM_VBLANK_SECONDARY | \
-                               _DRM_VBLANK_NEXTONMISS)
+#define _DRM_VBLANK_FLAGS_MASK (_DRM_VBLANK_EVENT | _DRM_VBLANK_SIGNAL | \
+                               _DRM_VBLANK_SECONDARY | _DRM_VBLANK_NEXTONMISS)
 
 struct drm_wait_vblank_request {
        enum drm_vblank_seq_type type;
@@ -640,7 +646,6 @@ struct drm_set_version {
        int drm_dd_minor;
 };
 
-
 #define DRM_FENCE_FLAG_EMIT                0x00000001
 #define DRM_FENCE_FLAG_SHAREABLE           0x00000002
 /**
@@ -667,7 +672,7 @@ struct drm_fence_arg {
        unsigned int error;
        unsigned int sequence;
        unsigned int pad64;
-       uint64_t expand_pad[2]; /*Future expansion */
+       uint64_t expand_pad[2]; /* Future expansion */
 };
 
 /* Buffer permissions, referring to how the GPU uses the buffers.
@@ -983,6 +988,35 @@ struct drm_gem_open {
        uint64_t size;
 };
 
+struct drm_get_cap {
+       uint64_t capability;
+       uint64_t value;
+};
+
+struct drm_event {
+       uint32_t type;
+       uint32_t length;
+};
+
+#define DRM_EVENT_VBLANK 0x01
+#define DRM_EVENT_FLIP_COMPLETE 0x02
+
+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;
+};
+
+#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
+
+#include "drm_mode.h"
+
 /**
  * \name Ioctls Definitions
  */
@@ -1008,6 +1042,8 @@ struct drm_gem_open {
 #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)
 #define DRM_IOCTL_AUTH_MAGIC           DRM_IOW( 0x11, struct drm_auth)
 #define DRM_IOCTL_BLOCK                        DRM_IOWR(0x12, struct drm_block)
@@ -1025,6 +1061,9 @@ struct drm_gem_open {
 #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_SET_MASTER            DRM_IO(0x1e)
+#define DRM_IOCTL_DROP_MASTER           DRM_IO(0x1f)
+
 #define DRM_IOCTL_ADD_CTX              DRM_IOWR(0x20, struct drm_ctx)
 #define DRM_IOCTL_RM_CTX               DRM_IOWR(0x21, struct drm_ctx)
 #define DRM_IOCTL_MOD_CTX              DRM_IOW( 0x22, struct drm_ctx)
@@ -1039,6 +1078,8 @@ struct drm_gem_open {
 #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_AGP_ACQUIRE          DRM_IO(  0x30)
 #define DRM_IOCTL_AGP_RELEASE          DRM_IO(  0x31)
 #define DRM_IOCTL_AGP_ENABLE           DRM_IOW( 0x32, struct drm_agp_mode)
@@ -1055,6 +1096,34 @@ struct drm_gem_open {
 
 #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)
+#define DRM_IOCTL_MODE_SETCRTC         DRM_IOWR(0xA2, struct drm_mode_crtc)
+#define DRM_IOCTL_MODE_CURSOR          DRM_IOWR(0xA3, struct drm_mode_cursor)
+#define DRM_IOCTL_MODE_GETGAMMA                DRM_IOWR(0xA4, struct drm_mode_crtc_lut)
+#define DRM_IOCTL_MODE_SETGAMMA                DRM_IOWR(0xA5, struct drm_mode_crtc_lut)
+#define DRM_IOCTL_MODE_GETENCODER      DRM_IOWR(0xA6, struct drm_mode_get_encoder)
+#define DRM_IOCTL_MODE_GETCONNECTOR    DRM_IOWR(0xA7, struct drm_mode_get_connector)
+#define DRM_IOCTL_MODE_ATTACHMODE      DRM_IOWR(0xA8, struct drm_mode_mode_cmd)
+#define DRM_IOCTL_MODE_DETACHMODE      DRM_IOWR(0xA9, struct drm_mode_mode_cmd)
+
+#define DRM_IOCTL_MODE_GETPROPERTY     DRM_IOWR(0xAA, struct drm_mode_get_property)
+#define DRM_IOCTL_MODE_SETPROPERTY     DRM_IOWR(0xAB, struct drm_mode_connector_set_property)
+#define DRM_IOCTL_MODE_GETPROPBLOB     DRM_IOWR(0xAC, struct drm_mode_get_blob)
+#define DRM_IOCTL_MODE_GETFB           DRM_IOWR(0xAD, struct drm_mode_fb_cmd)
+#define DRM_IOCTL_MODE_ADDFB           DRM_IOWR(0xAE, struct drm_mode_fb_cmd)
+#define DRM_IOCTL_MODE_RMFB            DRM_IOWR(0xAF, unsigned int)
+#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_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_ADDFB2          DRM_IOWR(0xB8, struct drm_mode_fb_cmd2)
+
 #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)
index c9b651a..f557796 100644 (file)
@@ -1,41 +1,49 @@
-.PATH: ${.CURDIR}/..
+.PATH: ${.CURDIR}/.. ${.CURDIR}/../ttm
 KMOD   = drm
-SRCS    = \
+SRCS   = \
        ati_pcigart.c \
        drm_agpsupport.c \
        drm_auth.c \
        drm_bufs.c \
        drm_context.c \
+       drm_crtc.c \
+       drm_crtc_helper.c \
        drm_dma.c \
+       drm_dp_iic_helper.c \
        drm_drawable.c \
        drm_drv.c \
+       drm_edid.c \
+       drm_fb_helper.c \
        drm_fops.c \
+       drm_gem.c \
+       drm_gem_names.c \
+       drm_global.c \
        drm_hashtab.c \
        drm_ioctl.c \
        drm_irq.c \
+       drm_linux_list_sort.c \
        drm_lock.c \
        drm_memory.c \
        drm_mm.c \
+       drm_modes.c \
        drm_pci.c \
        drm_scatter.c \
        drm_sman.c \
+       drm_stub.c \
        drm_sysctl.c \
-       drm_vm.c
+       drm_vm.c \
+       ttm_lock.c \
+       ttm_object.c \
+       ttm_tt.c \
+       ttm_bo_util.c \
+       ttm_bo.c \
+       ttm_bo_manager.c \
+       ttm_execbuf_util.c \
+       ttm_memory.c \
+       ttm_page_alloc.c \
+       ttm_bo_vm.c
 
-SRCS   += device_if.h bus_if.h pci_if.h opt_drm.h
-CFLAGS += ${DEBUG_FLAGS} -I. -I..
-
-.if defined(DRM_DEBUG)
-DRM_DEBUG_OPT= "\#define DRM_DEBUG 1"
-.endif
-
-.if !defined(DRM_NOLINUX)
-DRM_LINUX_OPT= "\#define DRM_LINUX 1"
-.endif
-
-opt_drm.h:
-       touch ${.TARGET}
-       echo $(DRM_DEBUG_OPT) >> ${.TARGET}
-       echo $(DRM_LINUX_OPT) >> ${.TARGET}
+SRCS   += device_if.h bus_if.h pci_if.h device_if.h iicbus_if.h opt_drm.h \
+         opt_ktr.h opt_vm.h
 
 .include <bsd.kmod.mk>
index f674780..6e46b7a 100644 (file)
@@ -29,6 +29,7 @@
  *    Rickard E. (Rik) Faith <faith@valinux.com>
  *    Gareth Hughes <gareth@valinux.com>
  *
+ * $FreeBSD: head/sys/dev/drm2/drmP.h 248084 2013-03-09 02:32:23Z attilio $
  */
 
 #ifndef _DRM_P_H_
@@ -43,23 +44,28 @@ struct drm_file;
 #include <sys/queue.h>
 #include <sys/malloc.h>
 #include <sys/kernel.h>
+#include <sys/ktr.h>
 #include <sys/module.h>
 #include <sys/systm.h>
-#include <sys/conf.h>
+#include <sys/device.h>
 #include <sys/sglist.h>
 #include <sys/stat.h>
 #include <sys/priv.h>
 #include <sys/proc.h>
 #include <sys/lock.h>
+#include <sys/spinlock.h>
+#include <sys/spinlock2.h>
 #include <sys/fcntl.h>
 #include <sys/uio.h>
 #include <sys/filio.h>
 #include <sys/sysctl.h>
 #include <sys/bus.h>
+#include <sys/queue.h>
 #include <sys/signalvar.h>
-#include <sys/event.h>
-#include <sys/tree.h>
+#include <sys/poll.h>
+#include <sys/sbuf.h>
 #include <sys/taskqueue.h>
+#include <sys/tree.h>
 #include <vm/vm.h>
 #include <vm/pmap.h>
 #include <vm/vm_extern.h>
@@ -72,7 +78,9 @@ struct drm_file;
 #include <machine/param.h>
 #include <machine/pmap.h>
 #include <sys/resource.h>
+#if defined(__i386__) || defined(__amd64__)
 #include <machine/specialreg.h>
+#endif
 #include <machine/sysarch.h>
 #include <sys/endian.h>
 #if _BYTE_ORDER == _BIG_ENDIAN
@@ -84,36 +92,33 @@ struct drm_file;
 #include <sys/rman.h>
 #include <sys/memrange.h>
 #include <dev/agp/agpvar.h>
-#include <sys/device.h>
 #include <sys/agpio.h>
-#include <sys/spinlock.h>
-#include <sys/spinlock2.h>
+#include <sys/mutex.h>
 #include <bus/pci/pcivar.h>
 #include <bus/pci/pcireg.h>
-#include <sys/bus.h>
-
-#include "dev/drm/drm.h"
-#include "dev/drm/drm_linux_list.h"
-#include "dev/drm/drm_atomic.h"
-#include "dev/drm/drm_internal.h"
-
-#include <opt_drm.h>
+/* XXX: bool definition */
+#include <libprop/proplib.h>
+
+#include <dev/drm/drm.h>
+#include <dev/drm/drm_atomic.h>
+#include <dev/drm/drm_internal.h>
+#include <dev/drm/drm_linux_list.h>
+#include <dev/drm/drm_gem_names.h>
+#include <dev/drm/drm_mm.h>
+#include <dev/drm/drm_hashtab.h>
+
+#include "opt_drm.h"
 #ifdef DRM_DEBUG
 #undef DRM_DEBUG
 #define DRM_DEBUG_DEFAULT_ON 1
 #endif /* DRM_DEBUG */
 
-#if defined(DRM_LINUX) && DRM_LINUX && !defined(__x86_64__) && !defined(__DragonFly__) /* XXX */
-#include <sys/file.h>
-#include <machine/../linux/linux.h>
-#include <machine/../linux/linux_proto.h>
-#else
-/* Either it was defined when it shouldn't be (FreeBSD amd64) or it isn't
- * supported on this OS yet.
- */
+#define        DRM_DEBUGBITS_DEBUG             0x1
+#define        DRM_DEBUGBITS_KMS               0x2
+#define        DRM_DEBUGBITS_FAILED_IOCTL      0x4
+
 #undef DRM_LINUX
 #define DRM_LINUX 0
-#endif
 
 /* driver capabilities and requirements mask */
 #define DRIVER_USE_AGP     0x1
@@ -123,13 +128,29 @@ struct drm_file;
 #define DRIVER_SG          0x10
 #define DRIVER_HAVE_DMA    0x20
 #define DRIVER_HAVE_IRQ    0x40
-#define DRIVER_DMA_QUEUE   0x100
+#define DRIVER_IRQ_SHARED  0x80
+#define DRIVER_IRQ_VBL     0x100
+#define DRIVER_DMA_QUEUE   0x200
+#define DRIVER_FB_DMA      0x400
+#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 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);
@@ -146,6 +167,9 @@ 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)
 
@@ -169,21 +193,19 @@ MALLOC_DECLARE(DRM_MEM_HASHTAB);
 
 #define DRM_CURPROC            curthread
 #define DRM_STRUCTPROC         struct thread
-#define DRM_SPINTYPE           struct lock
-#define DRM_SPININIT(l,name)   lockinit(l, name, 0, LK_CANRECURSE)
-#define DRM_SPINUNINIT(l)      lockuninit(l)
-#define DRM_SPINLOCK(l)                lockmgr(l, LK_EXCLUSIVE|LK_RETRY|LK_CANRECURSE)
-#define DRM_SPINUNLOCK(u)      lockmgr(u, LK_RELEASE)
-#define DRM_SPINLOCK_IRQSAVE(l, irqflags) do {         \
-       DRM_SPINLOCK(l);                                \
-       (void)irqflags;                                 \
-} while (0)
-#define DRM_SPINUNLOCK_IRQRESTORE(u, irqflags) DRM_SPINUNLOCK(u)
-#define DRM_SPINLOCK_ASSERT(l)
-#define DRM_CURRENTPID         (curthread->td_proc ?   \
-                                curthread->td_proc->p_pid : -1)
-#define DRM_LOCK()             DRM_SPINLOCK(&dev->dev_lock)
-#define DRM_UNLOCK()           DRM_SPINUNLOCK(&dev->dev_lock)
+#define DRM_CURRENTPID         curthread->td_proc->p_pid
+#define DRM_LOCK(dev)          lockmgr(&(dev)->dev_struct_lock, LK_EXCLUSIVE);
+#define DRM_UNLOCK(dev)                lockmgr(&(dev)->dev_struct_lock, LK_RELEASE);
+#define        DRM_LOCK_SLEEP(dev, chan, flags, msg, timeout)                  \
+    (lksleep((chan), &(dev)->dev_struct_lock, (flags), (msg), (timeout)))
+#if defined(INVARIANTS)
+#define        DRM_LOCK_ASSERT(dev)    KKASSERT(lockstatus(&(dev)->dev_struct_lock, curthread) != 0);
+#define        DRM_UNLOCK_ASSERT(dev)  KKASSERT(lockstatus(&(dev)->dev_struct_lock, curthread) == 0);
+#else
+#define        DRM_LOCK_ASSERT(d)
+#define        DRM_UNLOCK_ASSERT(d)
+#endif
+
 #define DRM_SYSCTL_HANDLER_ARGS        (SYSCTL_HANDLER_ARGS)
 
 #define DRM_IRQ_ARGS           void *arg
@@ -192,6 +214,7 @@ typedef void                        irqreturn_t;
 #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) );})
@@ -211,12 +234,21 @@ enum {
 #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)
 
 typedef vm_paddr_t dma_addr_t;
-typedef u_int64_t u64;
-typedef u_int32_t u32;
-typedef u_int16_t u16;
-typedef u_int8_t u8;
+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.
@@ -230,20 +262,26 @@ typedef u_int8_t u8;
        *(volatile u_int8_t *)(((vm_offset_t)(map)->virtual) +          \
            (vm_offset_t)(offset))
 #define DRM_READ16(map, offset)                                                \
-       *(volatile u_int16_t *)(((vm_offset_t)(map)->virtual) +         \
-           (vm_offset_t)(offset))
+       le16toh(*(volatile u_int16_t *)(((vm_offset_t)(map)->virtual) + \
+           (vm_offset_t)(offset)))
 #define DRM_READ32(map, offset)                                                \
-       *(volatile u_int32_t *)(((vm_offset_t)(map)->virtual) +         \
-           (vm_offset_t)(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)) = val
+           (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)) = val
+           (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))
@@ -275,7 +313,7 @@ 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",              \
-                          __func__);                           \
+                          __FUNCTION__);                               \
                return EINVAL;                                          \
        }                                                               \
 } while (0)
@@ -283,42 +321,56 @@ do {                                                                      \
 /* Returns -errno to shared code */
 #define DRM_WAIT_ON( ret, queue, timeout, condition )          \
 for ( ret = 0 ; !ret && !(condition) ; ) {                     \
-       DRM_UNLOCK();                                           \
+       DRM_UNLOCK(dev);                                        \
        lwkt_serialize_enter(&dev->irq_lock);                   \
        if (!(condition)) {                                     \
             tsleep_interlock(&(queue), PCATCH);                        \
             lwkt_serialize_exit(&dev->irq_lock);               \
             ret = -tsleep(&(queue), PCATCH | PINTERLOCKED,     \
                          "drmwtq", (timeout));                 \
-       } else {                                                \
-               lwkt_serialize_exit(&dev->irq_lock);            \
-                                                             \
-       DRM_LOCK();                                             \
+        } else {                                                \
+                lwkt_serialize_exit(&dev->irq_lock);            \
+        }                                                      \
+       DRM_LOCK(dev);                                          \
 }
 
-#define printf kprintf
-#define snprintf ksnprintf
-#define sscanf ksscanf
-#define malloc kmalloc
-#define realloc        krealloc
-#define reallocf krealloc      /* XXX XXX XXX */
-
 __inline static void
-free(void *addr, struct malloc_type *type)
+vm_page_unhold_pages(vm_page_t *ma, int count)
 {
-       if (addr != NULL)
-               kfree(addr, type);
+       int i;
+
+       for (i = 0; i < count; i++)
+               vm_page_unhold(ma[i]);
 }
 
+vm_page_t
+vm_phys_fictitious_to_vm_page(vm_paddr_t pa);
+
+int
+vm_phys_fictitious_reg_range(vm_paddr_t start, vm_paddr_t end, int pat_mode);
+
+
 #define DRM_ERROR(fmt, ...) \
-       printf("error: [" DRM_NAME ":pid%d:%s] *ERROR* " fmt,           \
+       kprintf("error: [" DRM_NAME ":pid%d:%s] *ERROR* " fmt,          \
            DRM_CURRENTPID, __func__ , ##__VA_ARGS__)
 
-#define DRM_INFO(fmt, ...)  printf("info: [" DRM_NAME "] " fmt , ##__VA_ARGS__)
-       
+#define DRM_INFO(fmt, ...)  kprintf("info: [" DRM_NAME "] " fmt , ##__VA_ARGS__)
+
 #define DRM_DEBUG(fmt, ...) do {                                       \
-       if (drm_debug_flag)                                             \
-               printf("[" DRM_NAME ":pid%d:%s] " fmt, DRM_CURRENTPID,  \
+       if ((drm_debug_flag & DRM_DEBUGBITS_DEBUG) != 0)                \
+               kprintf("[" 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)                  \
+               kprintf("[" 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)                  \
+               kprintf("[" DRM_NAME ":KMS:pid%d:%s] " fmt, DRM_CURRENTPID,\
                        __func__ , ##__VA_ARGS__);                      \
 } while (0)
 
@@ -339,6 +391,9 @@ struct drm_msi_blacklist_entry
 #define DRM_AUTH       0x1
 #define DRM_MASTER     0x2
 #define DRM_ROOT_ONLY  0x4
+#define DRM_CONTROL_ALLOW 0x8
+#define DRM_UNLOCKED   0x10
+
 typedef struct drm_ioctl_desc {
        unsigned long cmd;
        int (*func)(struct drm_device *dev, void *data,
@@ -415,19 +470,37 @@ typedef struct drm_buf_entry {
        drm_freelist_t    freelist;
 } drm_buf_entry_t;
 
+/* Event queued up for userspace to read */
+struct drm_pending_event {
+       struct drm_event *event;
+       struct list_head link;
+       struct drm_file *file_priv;
+       pid_t pid; /* pid of requester, no guarantee it's valid by the time
+                     we deliver the event, for tracing only */
+       void (*destroy)(struct drm_pending_event *event);
+};
+
 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;
-       int               minor;
        pid_t             pid;
        uid_t             uid;
-       int               refs;
        drm_magic_t       magic;
        unsigned long     ioctl_count;
+
        void             *driver_priv;
+       struct drm_gem_names object_names;
+
+       int               is_master;
+       struct drm_master *masterp;
+
+       struct list_head  fbs;
+
+       struct list_head  event_list;
+       int               event_space;
 };
 
 typedef struct drm_lock_data {
@@ -521,6 +594,21 @@ 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
@@ -542,6 +630,67 @@ struct drm_ati_pcigart_info {
        struct drm_dma_handle *dmah; /* handle for ATI PCIGART table */
 };
 
+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_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 */
+
+       /** Related drm device */
+       struct drm_device *dev;
+
+       /** File representing the shmem storage: filp in Linux parlance */
+       vm_object_t vm_obj;
+
+       bool on_map;
+       struct drm_hash_item map_list;
+
+       /**
+        * Size of the object, in bytes.  Immutable over the object's
+        * lifetime.
+        */
+       size_t size;
+
+       /**
+        * Global name for this object, starts at 1. 0 means unnamed.
+        * Access is covered by the object_name_lock in the related drm_device
+        */
+       int name;
+
+       /**
+        * Memory domains. These monitor which caches contain read/write data
+        * related to the object. When transitioning from one set of domains
+        * to another, the driver is called to ensure that caches are suitably
+        * flushed and invalidated
+        */
+       uint32_t read_domains;
+       uint32_t write_domain;
+
+       /**
+        * While validating an exec operation, the
+        * new read/write domain values are computed here.
+        * They will be transferred to the above values
+        * at the point that any cache flushing occurs
+        */
+       uint32_t pending_read_domains;
+       uint32_t pending_write_domain;
+
+       void *driver_private;
+};
+
+#include "drm_crtc.h"
+
 #ifndef DMA_BIT_MASK
 #define DMA_BIT_MASK(n) (((n) == 64) ? ~0ULL : (1ULL<<(n)) - 1)
 #endif
@@ -575,9 +724,32 @@ struct drm_driver_info {
        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);
+
+       struct cdev_pager_ops *gem_pager_ops;
+
+       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);
+
+       int     (*sysctl_init)(struct drm_device *dev,
+                   struct sysctl_ctx_list *ctx, struct sysctl_oid *top);
+       void    (*sysctl_cleanup)(struct drm_device *dev);
 
        drm_pci_id_list_t *id_entry;    /* PCI ID, name, and chipset private */
 
@@ -609,6 +781,41 @@ struct drm_driver_info {
        u32 driver_features;
 };
 
+/**
+ * DRM minor structure. This structure represents a drm minor number.
+ */
+struct drm_minor {
+       int index;                      /**< Minor device number */
+       int type;                       /**< Control or render */
+       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;
+};
+
+/* mode specified on the command line */
+struct drm_cmdline_mode {
+       bool specified;
+       bool refresh_specified;
+       bool bpp_specified;
+       int xres, yres;
+       int bpp;
+       int refresh;
+       bool rb;
+       bool interlace;
+       bool cvt;
+       bool margins;
+       enum drm_connector_force force;
+};
+
+struct drm_pending_vblank_event {
+       struct drm_pending_event base;
+       int pipe;
+       struct drm_event_vblank event;
+};
+
 /* Length for the array of resource pointers for drm_get_resource_*. */
 #define DRM_MAX_PCI_RESOURCE   6
 
@@ -631,11 +838,11 @@ struct drm_device {
        int               flags;        /* Flags to open(2)                */
 
                                /* Locks */
-       DRM_SPINTYPE      vbl_lock;     /* protects vblank operations */
-       DRM_SPINTYPE      dma_lock;     /* protects dev->dma */
+       struct spinlock   dma_lock;     /* protects dev->dma */
        struct lwkt_serialize irq_lock; /* protects irq condition checks */
-       DRM_SPINTYPE      dev_lock;     /* protects everything else */
-       DRM_SPINTYPE      drw_lock;
+       struct lock       dev_lock;     /* protects everything else */
+       struct lock       dev_struct_lock;
+       struct spinlock   drw_lock;
 
                                /* Usage Counters */
        int               open_count;   /* Outstanding files open          */
@@ -682,16 +889,13 @@ struct drm_device {
        atomic_t          context_flag; /* Context swapping flag           */
        int               last_context; /* Last current context            */
 
-       int               vblank_disable_allowed;
-       struct callout    vblank_disable_timer;
-       u32               max_vblank_count;     /* size of vblank counter register */
-       struct drm_vblank_info *vblank;         /* per crtc vblank info */
        int               num_crtcs;
 
        struct sigio      *buf_sigio;   /* Processes waiting for SIGIO     */
 
                                /* Sysctl support */
        struct drm_sysctl_info *sysctl;
+       int               sysctl_node_idx;
 
        drm_agp_head_t    *agp;
        drm_sg_mem_t      *sg;  /* Scatter gather memory */
@@ -700,8 +904,44 @@ struct drm_device {
        unsigned int      agp_buffer_token;
        drm_local_map_t   *agp_buffer_map;
 
+       struct drm_minor *control;              /**< Control node for card */
+       struct drm_minor *primary;              /**< render type primary screen head */
+
+       void              *drm_ttm_bo;
+       struct unrhdr     *drw_unrhdr;
        /* RB tree of drawable infos */
        RB_HEAD(drawable_tree, bsd_drm_drawable_info) drw_head;
+
+       int vblank_disable_allowed;
+
+       atomic_t *_vblank_count;        /**< number of VBLANK interrupts (driver must alloc the right number of counters) */
+       struct timeval *_vblank_time;   /**< timestamp of current vblank_count (drivers must alloc right number of fields) */
+       struct lock vblank_time_lock;   /**< Protects vblank count and time updates during vblank enable/disable */
+       struct lock vbl_lock;
+       atomic_t *vblank_refcount;      /* number of users of vblank interruptsper crtc */
+       u32 *last_vblank;               /* protected by dev->vbl_lock, used */
+                                       /* for wraparound handling */
+       int *vblank_enabled;            /* so we don't call enable more than
+                                          once per disable */
+       int *vblank_inmodeset;          /* Display driver is setting mode */
+       u32 *last_vblank_wait;          /* Last vblank seqno waited per CRTC */
+       struct callout vblank_disable_callout;
+
+       u32 max_vblank_count;           /**< size of vblank counter register */
+
+       struct list_head vblank_event_list;
+       struct lock      event_lock;
+
+        struct drm_mode_config mode_config;    /**< Current mode config */
+
+       /* GEM part */
+       struct lock       object_name_lock;
+       struct drm_gem_names object_names;
+       void             *mm_private;
+
+       void *sysctl_private;
+       char busid_str[128];
+       int modesetting;
 };
 
 static __inline__ int drm_core_check_feature(struct drm_device *dev,
@@ -719,11 +959,51 @@ 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,
+};
+
+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 *);
+
 extern int     drm_debug_flag;
+extern int     drm_notyet_flag;
+extern unsigned int drm_vblank_offdelay;
+extern unsigned int drm_timestamp_precision;
 
 /* 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);
 int    drm_detach(device_t kdev);
 d_ioctl_t drm_ioctl;
 d_open_t drm_open;
@@ -731,8 +1011,14 @@ d_close_t drm_close;
 d_read_t drm_read;
 d_kqfilter_t drm_kqfilter;
 d_mmap_t drm_mmap;
+d_mmap_single_t drm_mmap_single;
 extern drm_local_map_t *drm_getsarea(struct drm_device *dev);
 
+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);
+
 /* File operations helpers (drm_fops.c) */
 extern int             drm_open_helper(struct cdev *kdev, int flags, int fmt,
                                         DRM_STRUCTPROC *p,
@@ -794,16 +1080,37 @@ irqreturn_t drm_irq_handler(DRM_IRQ_ARGS);
 void   drm_driver_irq_preinstall(struct drm_device *dev);
 void   drm_driver_irq_postinstall(struct drm_device *dev);
 void   drm_driver_irq_uninstall(struct drm_device *dev);
-void   drm_handle_vblank(struct drm_device *dev, int crtc);
-u32    drm_vblank_count(struct drm_device *dev, int crtc);
-int    drm_vblank_get(struct drm_device *dev, int crtc);
-void   drm_vblank_put(struct drm_device *dev, int crtc);
-void   drm_vblank_cleanup(struct drm_device *dev);
-int    drm_vblank_wait(struct drm_device *dev, unsigned int *vbl_seq);
-int    drm_vblank_init(struct drm_device *dev, int num_crtcs);
+
+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);
 
+extern int drm_vblank_init(struct drm_device *dev, int num_crtcs);
+extern int drm_wait_vblank(struct drm_device *dev, void *data,
+                          struct drm_file *filp);
+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 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);
+extern void drm_vblank_cleanup(struct drm_device *dev);
+extern u32 drm_get_last_vbltimestamp(struct drm_device *dev, int crtc,
+                                    struct timeval *tvblank, unsigned flags);
+extern 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);
+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);
+
 /* 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);
@@ -835,6 +1142,9 @@ int        drm_ati_pcigart_init(struct drm_device *dev,
 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);
+
 /* Locking IOCTL support (drm_drv.c) */
 int    drm_lock(struct drm_device *dev, void *data,
                 struct drm_file *file_priv);
@@ -858,6 +1168,8 @@ 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);
 
@@ -922,8 +1234,6 @@ int        drm_dma(struct drm_device *dev, void *data, struct drm_file *file_priv);
 /* IRQ support (drm_irq.c) */
 int    drm_control(struct drm_device *dev, void *data,
                    struct drm_file *file_priv);
-int    drm_wait_vblank(struct drm_device *dev, void *data,
-                       struct drm_file *file_priv);
 
 /* AGP/GART support (drm_agpsupport.c) */
 int    drm_agp_acquire_ioctl(struct drm_device *dev, void *data,
@@ -943,6 +1253,12 @@ int       drm_agp_unbind_ioctl(struct drm_device *dev, void *data,
 int    drm_agp_bind_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);
+
 /* Scatter Gather Support (drm_scatter.c) */
 int    drm_sg_alloc_ioctl(struct drm_device *dev, void *data,
                           struct drm_file *file_priv);
@@ -954,30 +1270,106 @@ 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);
 
+/* 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_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);
+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);
+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);
+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);
+
+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)
 {
-       return malloc(size, area, M_NOWAIT);
+       return kmalloc(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);
+       return kmalloc(size * nmemb, area, M_NOWAIT | M_ZERO);
 }
 
 static __inline__ void *
 drm_realloc(void *oldpt, size_t oldsize, size_t size,
     struct malloc_type *area)
 {
-       return reallocf(oldpt, size, area, M_NOWAIT);
+       void *res;
+       res = krealloc(oldpt, size, area, M_NOWAIT);
+       if (res == NULL && oldpt != NULL)
+               kfree(oldpt,area);
+       return res;
 }
 
 static __inline__ void
-drm_free(void *pt, size_t size, struct malloc_type *area)
+drm_free(void *pt, struct malloc_type *area)
 {
-       free(pt, area);
+       if (pt != NULL)
+               kfree(pt, area);
 }
 
 /* Inline replacements for DRM_IOREMAP macros */
@@ -1003,7 +1395,7 @@ drm_core_findmap(struct drm_device *dev, unsigned long offset)
 {
        drm_local_map_t *map;
 
-       DRM_SPINLOCK_ASSERT(&dev->dev_lock);
+       DRM_LOCK_ASSERT(dev);
        TAILQ_FOREACH(map, &dev->maplist, link) {
                if (offset == (unsigned long)map->handle)
                        return map;
@@ -1015,5 +1407,24 @@ static __inline__ void drm_core_dropmap(struct drm_map *map)
 {
 }
 
+#define KIB_NOTYET()                                                   \
+do {                                                                   \
+       if (drm_debug_flag && drm_notyet_flag)                          \
+               kprintf("NOTYET: %s at %s:%d\n", __func__, __FILE__, __LINE__); \
+} while (0)
+
+#define        KTR_DRM         KTR_DEV
+#define        KTR_DRM_REG     KTR_SPARE3
+
+
+/* FreeBSD compatibility macros */
+#define PROC_LOCK(p)
+#define PROC_UNLOCK(p)
+
+#define VM_OBJECT_RLOCK(object)                VM_OBJECT_LOCK(object)
+#define VM_OBJECT_RUNLOCK(object)      VM_OBJECT_UNLOCK(object)
+#define VM_OBJECT_WLOCK(object)                VM_OBJECT_LOCK(object)
+#define VM_OBJECT_WUNLOCK(object)      VM_OBJECT_UNLOCK(object)
+
 #endif /* __KERNEL__ */
 #endif /* _DRM_P_H_ */
index 66bc6a7..fe3a931 100644 (file)
@@ -26,6 +26,7 @@
  *    Rickard E. (Rik) Faith <faith@valinux.com>
  *    Gareth Hughes <gareth@valinux.com>
  *
+ * $FreeBSD: src/sys/dev/drm2/drm_agpsupport.c,v 1.1 2012/05/22 11:07:44 kib Exp $
  */
 
 /** @file drm_agpsupport.c
@@ -33,7 +34,7 @@
  * the DRM's AGP ioctls.
  */
 
-#include "dev/drm/drmP.h"
+#include <dev/drm/drmP.h>
 
 #include <dev/agp/agpreg.h>
 #include <bus/pci/pcireg.h>
@@ -173,18 +174,16 @@ int drm_agp_alloc(struct drm_device *dev, struct drm_agp_buffer *request)
        if (!dev->agp || !dev->agp->acquired)
                return EINVAL;
 
-       entry = malloc(sizeof(*entry), DRM_MEM_AGPLISTS, M_NOWAIT | M_ZERO);
+       entry = kmalloc(sizeof(*entry), DRM_MEM_AGPLISTS, M_NOWAIT | M_ZERO);
        if (entry == NULL)
                return ENOMEM;
 
        pages = (request->size + PAGE_SIZE - 1) / PAGE_SIZE;
        type = (u_int32_t) request->type;
 
-       DRM_UNLOCK();
        handle = drm_agp_allocate_memory(pages, type);
-       DRM_LOCK();
        if (handle == NULL) {
-               free(entry, DRM_MEM_AGPLISTS);
+               drm_free(entry, DRM_MEM_AGPLISTS);
                return ENOMEM;
        }
        
@@ -213,9 +212,7 @@ int drm_agp_alloc_ioctl(struct drm_device *dev, void *data,
 
        request = *(struct drm_agp_buffer *) data;
 
-       DRM_LOCK();
        retcode = drm_agp_alloc(dev, &request);
-       DRM_UNLOCK();
 
        *(struct drm_agp_buffer *) data = request;
 
@@ -245,9 +242,7 @@ int drm_agp_unbind(struct drm_device *dev, struct drm_agp_binding *request)
        if (entry == NULL || !entry->bound)
                return EINVAL;
 
-       DRM_UNLOCK();
        retcode = drm_agp_unbind_memory(entry->handle);
-       DRM_LOCK();
 
        if (retcode == 0)
                entry->bound = 0;
@@ -263,9 +258,7 @@ int drm_agp_unbind_ioctl(struct drm_device *dev, void *data,
 
        request = *(struct drm_agp_binding *) data;
 
-       DRM_LOCK();
        retcode = drm_agp_unbind(dev, &request);
-       DRM_UNLOCK();
 
        return retcode;
 }
@@ -279,7 +272,7 @@ int drm_agp_bind(struct drm_device *dev, struct drm_agp_binding *request)
        if (!dev->agp || !dev->agp->acquired)
                return EINVAL;
 
-       DRM_DEBUG("agp_bind, page_size=%x\n", PAGE_SIZE);
+       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)
@@ -287,9 +280,7 @@ int drm_agp_bind(struct drm_device *dev, struct drm_agp_binding *request)
 
        page = (request->offset + PAGE_SIZE - 1) / PAGE_SIZE;
 
-       DRM_UNLOCK();
        retcode = drm_agp_bind_memory(entry->handle, page);
-       DRM_LOCK();
        if (retcode == 0)
                entry->bound = dev->agp->base + (page << PAGE_SHIFT);
 
@@ -304,9 +295,7 @@ int drm_agp_bind_ioctl(struct drm_device *dev, void *data,
 
        request = *(struct drm_agp_binding *) data;
 
-       DRM_LOCK();
        retcode = drm_agp_bind(dev, &request);
-       DRM_UNLOCK();
 
        return retcode;
 }
@@ -329,13 +318,11 @@ int drm_agp_free(struct drm_device *dev, struct drm_agp_buffer *request)
        if (entry->next)
                entry->next->prev = entry->prev;
 
-       DRM_UNLOCK();
        if (entry->bound)
                drm_agp_unbind_memory(entry->handle);
        drm_agp_free_memory(entry->handle);
-       DRM_LOCK();
 
-       free(entry, DRM_MEM_AGPLISTS);
+       drm_free(entry, DRM_MEM_AGPLISTS);
 
        return 0;
 
@@ -349,9 +336,7 @@ int drm_agp_free_ioctl(struct drm_device *dev, void *data,
 
        request = *(struct drm_agp_buffer *) data;
 
-       DRM_LOCK();
        retcode = drm_agp_free(dev, &request);
-       DRM_UNLOCK();
 
        return retcode;
 }
@@ -369,7 +354,7 @@ drm_agp_head_t *drm_agp_init(void)
        DRM_DEBUG("agp_available = %d\n", agp_available);
 
        if (agp_available) {
-               head = malloc(sizeof(*head), DRM_MEM_AGPLISTS,
+               head = kmalloc(sizeof(*head), DRM_MEM_AGPLISTS,
                    M_NOWAIT | M_ZERO);
                if (head == NULL)
                        return NULL;
index 10576d5..bcd5958 100644 (file)
@@ -27,6 +27,8 @@
  * 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.
+ *
+ * $FreeBSD: src/sys/dev/drm2/drm_atomic.h,v 1.1 2012/05/22 11:07:44 kib Exp $
  */
 
 /* Many of these implementations are rather fake, but good enough. */
@@ -89,3 +91,5 @@ find_first_zero_bit(volatile void *p, int max)
        }
        return max;
 }
+
+#define        BITS_TO_LONGS(x) (howmany((x), NBBY * sizeof(long)))
index 303722c..cd952f2 100644 (file)
@@ -26,6 +26,7 @@
  *    Rickard E. (Rik) Faith <faith@valinux.com>
  *    Gareth Hughes <gareth@valinux.com>
  *
+ * $FreeBSD: src/sys/dev/drm2/drm_auth.c,v 1.1 2012/05/22 11:07:44 kib Exp $
  */
 
 /** @file drm_auth.c
@@ -48,7 +49,7 @@ static struct drm_file *drm_find_file(struct drm_device *dev, drm_magic_t magic)
        drm_magic_entry_t *pt;
        int hash = drm_hash_magic(magic);
 
-       DRM_SPINLOCK_ASSERT(&dev->dev_lock);
+       DRM_LOCK_ASSERT(dev);
 
        for (pt = dev->magiclist[hash].head; pt; pt = pt->next) {
                if (pt->magic == magic) {
@@ -71,10 +72,10 @@ static int drm_add_magic(struct drm_device *dev, struct drm_file *priv,
 
        DRM_DEBUG("%d\n", magic);
 
-       DRM_SPINLOCK_ASSERT(&dev->dev_lock);
+       DRM_LOCK_ASSERT(dev);
 
        hash = drm_hash_magic(magic);
-       entry = malloc(sizeof(*entry), DRM_MEM_MAGIC, M_ZERO | M_NOWAIT);
+       entry = kmalloc(sizeof(*entry), DRM_MEM_MAGIC, M_ZERO | M_NOWAIT);
        if (!entry)
                return ENOMEM;
        entry->magic = magic;
@@ -102,7 +103,7 @@ static int drm_remove_magic(struct drm_device *dev, drm_magic_t magic)
        drm_magic_entry_t *pt;
        int               hash;
 
-       DRM_SPINLOCK_ASSERT(&dev->dev_lock);
+       DRM_LOCK_ASSERT(dev);
 
        DRM_DEBUG("%d\n", magic);
        hash = drm_hash_magic(magic);
@@ -118,7 +119,7 @@ static int drm_remove_magic(struct drm_device *dev, drm_magic_t magic)
                        if (prev) {
                                prev->next = pt->next;
                        }
-                       free(pt, DRM_MEM_MAGIC);
+                       drm_free(pt, DRM_MEM_MAGIC);
                        return 0;
                }
        }
@@ -143,7 +144,7 @@ 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();
+               DRM_LOCK(dev);
                do {
                        int old = sequence;
 
@@ -154,7 +155,7 @@ int drm_getmagic(struct drm_device *dev, void *data, struct drm_file *file_priv)
                } while (drm_find_file(dev, auth->magic));
                file_priv->magic = auth->magic;
                drm_add_magic(dev, file_priv, auth->magic);
-               DRM_UNLOCK();
+               DRM_UNLOCK(dev);
        }
 
        DRM_DEBUG("%u\n", auth->magic);
@@ -173,15 +174,15 @@ int drm_authmagic(struct drm_device *dev, void *data,
 
        DRM_DEBUG("%u\n", auth->magic);
 
-       DRM_LOCK();
+       DRM_LOCK(dev);
        priv = drm_find_file(dev, auth->magic);
        if (priv != NULL) {
                priv->authenticated = 1;
                drm_remove_magic(dev, auth->magic);
-               DRM_UNLOCK();
+               DRM_UNLOCK(dev);
                return 0;
        } else {
-               DRM_UNLOCK();
+               DRM_UNLOCK(dev);
                return EINVAL;
        }
 }
index c1b73c7..c29dc6a 100644 (file)
  *    Rickard E. (Rik) Faith <faith@valinux.com>
  *    Gareth Hughes <gareth@valinux.com>
  *
+ * $FreeBSD: src/sys/dev/drm2/drm_bufs.c,v 1.1 2012/05/22 11:07:44 kib Exp $
  */
 
 /** @file drm_bufs.c
  * Implementation of the ioctls for setup of DRM mappings and DMA buffers.
  */
 
-#include "bus/pci/pcireg.h"
+#include <sys/conf.h>
+#include <bus/pci/pcireg.h>
 
 #include "dev/drm/drmP.h"
 
@@ -45,7 +47,7 @@ static int drm_alloc_resource(struct drm_device *dev, int resource)
        struct resource *res;
        int rid;
 
-       DRM_SPINLOCK_ASSERT(&dev->dev_lock);
+       DRM_LOCK_ASSERT(dev);
 
        if (resource >= DRM_MAX_PCI_RESOURCE) {
                DRM_ERROR("Resource %d too large\n", resource);
@@ -56,11 +58,11 @@ static int drm_alloc_resource(struct drm_device *dev, int resource)
                return 0;
        }
 
-       DRM_UNLOCK();
+       DRM_UNLOCK(dev);
        rid = PCIR_BAR(resource);
        res = bus_alloc_resource_any(dev->device, SYS_RES_MEMORY, &rid,
            RF_SHAREABLE);
-       DRM_LOCK();
+       DRM_LOCK(dev);
        if (res == NULL) {
                DRM_ERROR("Couldn't find resource 0x%x\n", resource);
                return 1;
@@ -119,10 +121,6 @@ int drm_addmap(struct drm_device * dev, unsigned long offset,
                    offset, size);
                return EINVAL;
        }
-       if (size == 0) {
-               DRM_ERROR("size is 0: 0x%lx/0x%lx\n", offset, size);
-               return EINVAL;
-       }
 
        DRM_DEBUG("offset = 0x%08lx, size = 0x%08lx, type = %d\n", offset,
            size, type);
@@ -142,14 +140,14 @@ int drm_addmap(struct drm_device * dev, unsigned long offset,
                        }
                }
        }
-       DRM_UNLOCK();
+       DRM_UNLOCK(dev);
 
        /* Allocate a new map structure, fill it in, and do any type-specific
         * initialization necessary.
         */
-       map = malloc(sizeof(*map), DRM_MEM_MAPS, M_ZERO | M_NOWAIT);
+       map = kmalloc(sizeof(*map), DRM_MEM_MAPS, M_ZERO | M_NOWAIT);
        if (!map) {
-               DRM_LOCK();
+               DRM_LOCK(dev);
                return ENOMEM;
        }
 
@@ -171,26 +169,26 @@ int drm_addmap(struct drm_device * dev, unsigned long offset,
                        map->mtrr = 1;
                break;
        case _DRM_SHM:
-               map->virtual = malloc(map->size, DRM_MEM_MAPS, M_NOWAIT);
+               map->virtual = kmalloc(map->size, DRM_MEM_MAPS, M_NOWAIT);
                DRM_DEBUG("%lu %d %p\n",
                    map->size, drm_order(map->size), map->virtual);
                if (!map->virtual) {
-                       free(map, DRM_MEM_MAPS);
-                       DRM_LOCK();
+                       drm_free(map, DRM_MEM_MAPS);
+                       DRM_LOCK(dev);
                        return ENOMEM;
                }
                map->offset = (unsigned long)map->virtual;
                if (map->flags & _DRM_CONTAINS_LOCK) {
                        /* Prevent a 2nd X Server from creating a 2nd lock */
-                       DRM_LOCK();
+                       DRM_LOCK(dev);
                        if (dev->lock.hw_lock != NULL) {
-                               DRM_UNLOCK();
-                               free(map->virtual, DRM_MEM_MAPS);
-                               free(map, DRM_MEM_MAPS);
+                               DRM_UNLOCK(dev);
+                               drm_free(map->virtual, DRM_MEM_MAPS);
+                               drm_free(map, DRM_MEM_MAPS);
                                return EBUSY;
                        }
                        dev->lock.hw_lock = map->virtual; /* Pointer to lock */
-                       DRM_UNLOCK();
+                       DRM_UNLOCK(dev);
                }
                break;
        case _DRM_AGP:
@@ -216,15 +214,15 @@ int drm_addmap(struct drm_device * dev, unsigned long offset,
                        }
                }
                if (!valid) {
-                       free(map, DRM_MEM_MAPS);
-                       DRM_LOCK();
+                       drm_free(map, DRM_MEM_MAPS);
+                       DRM_LOCK(dev);
                        return EACCES;
                }*/
                break;
        case _DRM_SCATTER_GATHER:
                if (!dev->sg) {
-                       free(map, DRM_MEM_MAPS);
-                       DRM_LOCK();
+                       drm_free(map, DRM_MEM_MAPS);
+                       DRM_LOCK(dev);
                        return EINVAL;
                }
                map->virtual = (void *)(dev->sg->vaddr + offset);
@@ -242,8 +240,8 @@ int drm_addmap(struct drm_device * dev, unsigned long offset,
                        align = PAGE_SIZE;
                map->dmah = drm_pci_alloc(dev, map->size, align, 0xfffffffful);
                if (map->dmah == NULL) {
-                       free(map, DRM_MEM_MAPS);
-                       DRM_LOCK();
+                       drm_free(map, DRM_MEM_MAPS);
+                       DRM_LOCK(dev);
                        return ENOMEM;
                }
                map->virtual = map->dmah->vaddr;
@@ -251,12 +249,12 @@ int drm_addmap(struct drm_device * dev, unsigned long offset,
                break;
        default:
                DRM_ERROR("Bad map type %d\n", map->type);
-               free(map, DRM_MEM_MAPS);
-               DRM_LOCK();
+               drm_free(map, DRM_MEM_MAPS);
+               DRM_LOCK(dev);
                return EINVAL;
        }
 
-       DRM_LOCK();
+       DRM_LOCK(dev);
        TAILQ_INSERT_TAIL(&dev->maplist, map, link);
 
 done:
@@ -283,10 +281,10 @@ int drm_addmap_ioctl(struct drm_device *dev, void *data,
        if (!DRM_SUSER(DRM_CURPROC) && request->type != _DRM_AGP)
                return EACCES;
 
-       DRM_LOCK();
+       DRM_LOCK(dev);
        err = drm_addmap(dev, request->offset, request->size, request->type,
            request->flags, &map);
-       DRM_UNLOCK();
+       DRM_UNLOCK(dev);
        if (err != 0)
                return err;
 
@@ -302,7 +300,7 @@ int drm_addmap_ioctl(struct drm_device *dev, void *data,
 
 void drm_rmmap(struct drm_device *dev, drm_local_map_t *map)
 {
-       DRM_SPINLOCK_ASSERT(&dev->dev_lock);
+       DRM_LOCK_ASSERT(dev);
 
        if (map == NULL)
                return;
@@ -316,7 +314,7 @@ void drm_rmmap(struct drm_device *dev, drm_local_map_t *map)
                /* FALLTHROUGH */
        case _DRM_FRAME_BUFFER:
                if (map->mtrr) {
-                       int retcode;
+                       int __unused retcode;
                        
                        retcode = drm_mtrr_del(0, map->offset, map->size,
                            DRM_MTRR_WC);
@@ -324,7 +322,7 @@ void drm_rmmap(struct drm_device *dev, drm_local_map_t *map)
                }
                break;
        case _DRM_SHM:
-               free(map->virtual, DRM_MEM_MAPS);
+               drm_free(map->virtual, DRM_MEM_MAPS);
                break;
        case _DRM_AGP:
        case _DRM_SCATTER_GATHER:
@@ -342,13 +340,13 @@ void drm_rmmap(struct drm_device *dev, drm_local_map_t *map)
                    map->bsr);
        }
 
-       DRM_UNLOCK();
+       DRM_UNLOCK(dev);
        if (map->handle)
                free_unr(dev->map_unrhdr, (unsigned long)map->handle >>
                    DRM_MAP_HANDLE_SHIFT);
-       DRM_LOCK();
+       DRM_LOCK(dev);
 
-       free(map, DRM_MEM_MAPS);
+       drm_free(map, DRM_MEM_MAPS);
 }
 
 /* Remove a map private from list and deallocate resources if the mapping
@@ -361,7 +359,7 @@ int drm_rmmap_ioctl(struct drm_device *dev, void *data,
        drm_local_map_t *map;
        struct drm_map *request = data;
 
-       DRM_LOCK();
+       DRM_LOCK(dev);
        TAILQ_FOREACH(map, &dev->maplist, link) {
                if (map->handle == request->handle &&
                    map->flags & _DRM_REMOVABLE)
@@ -370,13 +368,13 @@ int drm_rmmap_ioctl(struct drm_device *dev, void *data,
 
        /* No match found. */
        if (map == NULL) {
-               DRM_UNLOCK();
+               DRM_UNLOCK(dev);
                return EINVAL;
        }
 
        drm_rmmap(dev, map);
 
-       DRM_UNLOCK();
+       DRM_UNLOCK(dev);
 
        return 0;
 }
@@ -391,16 +389,16 @@ static void drm_cleanup_buf_error(struct drm_device *dev,
                for (i = 0; i < entry->seg_count; i++) {
                        drm_pci_free(dev, entry->seglist[i]);
                }
-               free(entry->seglist, DRM_MEM_SEGS);
+               drm_free(entry->seglist, DRM_MEM_SEGS);
 
                entry->seg_count = 0;
        }
 
        if (entry->buf_count) {
                for (i = 0; i < entry->buf_count; i++) {
-                       free(entry->buflist[i].dev_private, DRM_MEM_BUFS);
+                       drm_free(entry->buflist[i].dev_private, DRM_MEM_BUFS);
                }
-               free(entry->buflist, DRM_MEM_BUFS);
+               drm_free(entry->buflist, DRM_MEM_BUFS);
 
                entry->buf_count = 0;
        }
@@ -467,7 +465,7 @@ static int drm_do_addbufs_agp(struct drm_device *dev, struct drm_buf_desc *reque
 
        entry = &dma->bufs[order];
 
-       entry->buflist = malloc(count * sizeof(*entry->buflist), DRM_MEM_BUFS,
+       entry->buflist = kmalloc(count * sizeof(*entry->buflist), DRM_MEM_BUFS,
            M_NOWAIT | M_ZERO);
        if (!entry->buflist) {
                return ENOMEM;
@@ -493,7 +491,7 @@ static int drm_do_addbufs_agp(struct drm_device *dev, struct drm_buf_desc *reque
                buf->file_priv = NULL;
 
                buf->dev_priv_size = dev->driver->buf_priv_size;
-               buf->dev_private = malloc(buf->dev_priv_size, DRM_MEM_BUFS,
+               buf->dev_private = kmalloc(buf->dev_priv_size, DRM_MEM_BUFS,
                    M_NOWAIT | M_ZERO);
                if (buf->dev_private == NULL) {
                        /* Set count correctly so we free the proper amount. */
@@ -509,7 +507,7 @@ static int drm_do_addbufs_agp(struct drm_device *dev, struct drm_buf_desc *reque
 
        DRM_DEBUG("byte_count: %d\n", byte_count);
 
-       temp_buflist = realloc(dma->buflist,
+       temp_buflist = krealloc(dma->buflist,
            (dma->buf_count + entry->buf_count) * sizeof(*dma->buflist),
            DRM_MEM_BUFS, M_NOWAIT);
        if (temp_buflist == NULL) {
@@ -569,22 +567,22 @@ static int drm_do_addbufs_pci(struct drm_device *dev, struct drm_buf_desc *reque
 
        entry = &dma->bufs[order];
 
-       entry->buflist = malloc(count * sizeof(*entry->buflist), DRM_MEM_BUFS,
+       entry->buflist = kmalloc(count * sizeof(*entry->buflist), DRM_MEM_BUFS,
            M_NOWAIT | M_ZERO);
-       entry->seglist = malloc(count * sizeof(*entry->seglist), DRM_MEM_SEGS,
+       entry->seglist = kmalloc(count * sizeof(*entry->seglist), DRM_MEM_SEGS,
            M_NOWAIT | M_ZERO);
 
        /* Keep the original pagelist until we know all the allocations
         * have succeeded
         */
-       temp_pagelist = malloc((dma->page_count + (count << page_order)) *
+       temp_pagelist = kmalloc((dma->page_count + (count << page_order)) *
            sizeof(*dma->pagelist), DRM_MEM_PAGES, M_NOWAIT);
 
        if (entry->buflist == NULL || entry->seglist == NULL || 
            temp_pagelist == NULL) {
-               free(temp_pagelist, DRM_MEM_PAGES);
-               free(entry->seglist, DRM_MEM_SEGS);
-               free(entry->buflist, DRM_MEM_BUFS);
+               drm_free(temp_pagelist, DRM_MEM_PAGES);
+               drm_free(entry->seglist, DRM_MEM_SEGS);
+               drm_free(entry->buflist, DRM_MEM_BUFS);
                return ENOMEM;
        }
 
@@ -600,16 +598,16 @@ static int drm_do_addbufs_pci(struct drm_device *dev, struct drm_buf_desc *reque
        page_count = 0;
 
        while (entry->buf_count < count) {
-               DRM_SPINUNLOCK(&dev->dma_lock);
+               spin_unlock(&dev->dma_lock);
                drm_dma_handle_t *dmah = drm_pci_alloc(dev, size, alignment,
                    0xfffffffful);
-               DRM_SPINLOCK(&dev->dma_lock);
+               spin_lock(&dev->dma_lock);
                if (dmah == NULL) {
                        /* Set count correctly so we free the proper amount. */
                        entry->buf_count = count;
                        entry->seg_count = count;
                        drm_cleanup_buf_error(dev, entry);
-                       free(temp_pagelist, DRM_MEM_PAGES);
+                       drm_free(temp_pagelist, DRM_MEM_PAGES);
                        return ENOMEM;
                }
 
@@ -637,14 +635,14 @@ static int drm_do_addbufs_pci(struct drm_device *dev, struct drm_buf_desc *reque
                        buf->file_priv = NULL;
 
                        buf->dev_priv_size = dev->driver->buf_priv_size;
-                       buf->dev_private = malloc(buf->dev_priv_size,
+                       buf->dev_private = kmalloc(buf->dev_priv_size,
                            DRM_MEM_BUFS, M_NOWAIT | M_ZERO);
                        if (buf->dev_private == NULL) {
                                /* Set count correctly so we free the proper amount. */
                                entry->buf_count = count;
                                entry->seg_count = count;
                                drm_cleanup_buf_error(dev, entry);
-                               free(temp_pagelist, DRM_MEM_PAGES);
+                               drm_free(temp_pagelist, DRM_MEM_PAGES);
                                return ENOMEM;
                        }
 
@@ -654,13 +652,13 @@ static int drm_do_addbufs_pci(struct drm_device *dev, struct drm_buf_desc *reque
                byte_count += PAGE_SIZE << page_order;
        }
 
-       temp_buflist = realloc(dma->buflist,
+       temp_buflist = krealloc(dma->buflist,
            (dma->buf_count + entry->buf_count) * sizeof(*dma->buflist),
            DRM_MEM_BUFS, M_NOWAIT);
        if (temp_buflist == NULL) {
                /* Free the entry because it isn't valid */
                drm_cleanup_buf_error(dev, entry);
-               free(temp_pagelist, DRM_MEM_PAGES);
+               drm_free(temp_pagelist, DRM_MEM_PAGES);
                return ENOMEM;
        }
        dma->buflist = temp_buflist;
@@ -672,7 +670,7 @@ static int drm_do_addbufs_pci(struct drm_device *dev, struct drm_buf_desc *reque
        /* No allocations failed, so now we can replace the orginal pagelist
         * with the new one.
         */
-       free(dma->pagelist, DRM_MEM_PAGES);
+       drm_free(dma->pagelist, DRM_MEM_PAGES);
        dma->pagelist = temp_pagelist;
 
        dma->buf_count += entry->buf_count;
@@ -726,7 +724,7 @@ static int drm_do_addbufs_sg(struct drm_device *dev, struct drm_buf_desc *reques
 
        entry = &dma->bufs[order];
 
-       entry->buflist = malloc(count * sizeof(*entry->buflist), DRM_MEM_BUFS,
+       entry->buflist = kmalloc(count * sizeof(*entry->buflist), DRM_MEM_BUFS,
            M_NOWAIT | M_ZERO);
        if (entry->buflist == NULL)
                return ENOMEM;
@@ -751,7 +749,7 @@ static int drm_do_addbufs_sg(struct drm_device *dev, struct drm_buf_desc *reques
                buf->file_priv = NULL;
 
                buf->dev_priv_size = dev->driver->buf_priv_size;
-               buf->dev_private = malloc(buf->dev_priv_size, DRM_MEM_BUFS,
+               buf->dev_private = kmalloc(buf->dev_priv_size, DRM_MEM_BUFS,
                    M_NOWAIT | M_ZERO);
                if (buf->dev_private == NULL) {
                        /* Set count correctly so we free the proper amount. */
@@ -770,7 +768,7 @@ static int drm_do_addbufs_sg(struct drm_device *dev, struct drm_buf_desc *reques
 
        DRM_DEBUG("byte_count: %d\n", byte_count);
 
-       temp_buflist = realloc(dma->buflist,
+       temp_buflist = krealloc(dma->buflist,
            (dma->buf_count + entry->buf_count) * sizeof(*dma->buflist),
            DRM_MEM_BUFS, M_NOWAIT);
        if (temp_buflist == NULL) {
@@ -809,22 +807,22 @@ int drm_addbufs_agp(struct drm_device *dev, struct drm_buf_desc *request)
        if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER)
                return EINVAL;
 
-       DRM_SPINLOCK(&dev->dma_lock);
+       spin_lock(&dev->dma_lock);
 
        /* No more allocations after first buffer-using ioctl. */
        if (dev->buf_use != 0) {
-               DRM_SPINUNLOCK(&dev->dma_lock);
+               spin_unlock(&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);
+               spin_unlock(&dev->dma_lock);
                return ENOMEM;
        }
 
        ret = drm_do_addbufs_agp(dev, request);
 
-       DRM_SPINUNLOCK(&dev->dma_lock);
+       spin_unlock(&dev->dma_lock);
 
        return ret;
 }
@@ -843,22 +841,22 @@ int drm_addbufs_sg(struct drm_device *dev, struct drm_buf_desc *request)
        if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER)
                return EINVAL;
 
-       DRM_SPINLOCK(&dev->dma_lock);
+       spin_lock(&dev->dma_lock);
 
        /* No more allocations after first buffer-using ioctl. */
        if (dev->buf_use != 0) {
-               DRM_SPINUNLOCK(&dev->dma_lock);
+               spin_unlock(&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);
+               spin_unlock(&dev->dma_lock);
                return ENOMEM;
        }
 
        ret = drm_do_addbufs_sg(dev, request);
 
-       DRM_SPINUNLOCK(&dev->dma_lock);
+       spin_unlock(&dev->dma_lock);
 
        return ret;
 }
@@ -877,22 +875,22 @@ int drm_addbufs_pci(struct drm_device *dev, struct drm_buf_desc *request)
        if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER)
                return EINVAL;
 
-       DRM_SPINLOCK(&dev->dma_lock);
+       spin_lock(&dev->dma_lock);
 
        /* No more allocations after first buffer-using ioctl. */
        if (dev->buf_use != 0) {
-               DRM_SPINUNLOCK(&dev->dma_lock);
+               spin_unlock(&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);
+               spin_unlock(&dev->dma_lock);
                return ENOMEM;
        }
 
        ret = drm_do_addbufs_pci(dev, request);
 
-       DRM_SPINUNLOCK(&dev->dma_lock);
+       spin_unlock(&dev->dma_lock);
 
        return ret;
 }
@@ -920,9 +918,9 @@ int drm_infobufs(struct drm_device *dev, void *data, struct drm_file *file_priv)
        int count;
        int retcode = 0;
 
-       DRM_SPINLOCK(&dev->dma_lock);
+       spin_lock(&dev->dma_lock);
        ++dev->buf_use;         /* Can't allocate more after this call */
-       DRM_SPINUNLOCK(&dev->dma_lock);
+       spin_unlock(&dev->dma_lock);
 
        for (i = 0, count = 0; i < DRM_MAX_ORDER + 1; i++) {
                if (dma->bufs[i].buf_count)
@@ -977,16 +975,16 @@ int drm_markbufs(struct drm_device *dev, void *data, struct drm_file *file_priv)
                return EINVAL;
        }
 
-       DRM_SPINLOCK(&dev->dma_lock);
+       spin_lock(&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);
+               spin_unlock(&dev->dma_lock);
                return EINVAL;
        }
 
        dma->bufs[order].freelist.low_mark  = request->low_mark;
        dma->bufs[order].freelist.high_mark = request->high_mark;
-       DRM_SPINUNLOCK(&dev->dma_lock);
+       spin_unlock(&dev->dma_lock);
 
        return 0;
 }
@@ -1002,7 +1000,7 @@ int drm_freebufs(struct drm_device *dev, void *data, struct drm_file *file_priv)
 
        DRM_DEBUG("%d\n", request->count);
        
-       DRM_SPINLOCK(&dev->dma_lock);
+       spin_lock(&dev->dma_lock);
        for (i = 0; i < request->count; i++) {
                if (DRM_COPY_FROM_USER(&idx, &request->list[i], sizeof(idx))) {
                        retcode = EFAULT;
@@ -1023,7 +1021,7 @@ int drm_freebufs(struct drm_device *dev, void *data, struct drm_file *file_priv)
                }
                drm_free_buffer(dev, buf);
        }
-       DRM_SPINUNLOCK(&dev->dma_lock);
+       spin_unlock(&dev->dma_lock);
 
        return retcode;
 }
@@ -1043,9 +1041,9 @@ int drm_mapbufs(struct drm_device *dev, void *data, struct drm_file *file_priv)
 
        vms = DRM_CURPROC->td_proc->p_vmspace;
 
-       DRM_SPINLOCK(&dev->dma_lock);
+       spin_lock(&dev->dma_lock);
        dev->buf_use++;         /* Can't allocate more after this call */
-       DRM_SPINUNLOCK(&dev->dma_lock);
+       spin_unlock(&dev->dma_lock);
 
        if (request->count < dma->buf_count)
                goto done;
index 7bfa976..5df3c76 100644 (file)
@@ -26,6 +26,7 @@
  *    Rickard E. (Rik) Faith <faith@valinux.com>
  *    Gareth Hughes <gareth@valinux.com>
  *
+ * $FreeBSD: src/sys/dev/drm2/drm_context.c,v 1.1 2012/05/22 11:07:44 kib Exp $
  */
 
 /** @file drm_context.c
@@ -47,10 +48,10 @@ void drm_ctxbitmap_free(struct drm_device *dev, int ctx_handle)
                return;
        }
 
-       DRM_LOCK();
+       DRM_LOCK(dev);
        clear_bit(ctx_handle, dev->ctx_bitmap);
        dev->context_sareas[ctx_handle] = NULL;
-       DRM_UNLOCK();
+       DRM_UNLOCK(dev);
        return;
 }
 
@@ -61,10 +62,10 @@ int drm_ctxbitmap_next(struct drm_device *dev)
        if (dev->ctx_bitmap == NULL)
                return -1;
 
-       DRM_LOCK();
+       DRM_LOCK(dev);
        bit = find_first_zero_bit(dev->ctx_bitmap, DRM_MAX_CTXBITMAP);
        if (bit >= DRM_MAX_CTXBITMAP) {
-               DRM_UNLOCK();
+               DRM_UNLOCK(dev);
                return -1;
        }
 
@@ -74,20 +75,20 @@ int drm_ctxbitmap_next(struct drm_device *dev)
                drm_local_map_t **ctx_sareas;
                int max_ctx = (bit+1);
 
-               ctx_sareas = realloc(dev->context_sareas,
+               ctx_sareas = krealloc(dev->context_sareas,
                    max_ctx * sizeof(*dev->context_sareas),
                    DRM_MEM_SAREA, M_NOWAIT);
                if (ctx_sareas == NULL) {
                        clear_bit(bit, dev->ctx_bitmap);
                        DRM_DEBUG("failed to allocate bit : %d\n", bit);
-                       DRM_UNLOCK();
+                       DRM_UNLOCK(dev);
                        return -1;
                }
                dev->max_context = max_ctx;
                dev->context_sareas = ctx_sareas;
                dev->context_sareas[bit] = NULL;
        }
-       DRM_UNLOCK();
+       DRM_UNLOCK(dev);
        return bit;
 }
 
@@ -96,16 +97,16 @@ int drm_ctxbitmap_init(struct drm_device *dev)
        int i;
        int temp;
 
-       DRM_LOCK();
-       dev->ctx_bitmap = malloc(PAGE_SIZE, DRM_MEM_CTXBITMAP,
+       DRM_LOCK(dev);
+       dev->ctx_bitmap = kmalloc(PAGE_SIZE, DRM_MEM_CTXBITMAP,
            M_NOWAIT | M_ZERO);
        if (dev->ctx_bitmap == NULL) {
-               DRM_UNLOCK();
+               DRM_UNLOCK(dev);
                return ENOMEM;
        }
        dev->context_sareas = NULL;
        dev->max_context = -1;
-       DRM_UNLOCK();
+       DRM_UNLOCK(dev);
 
        for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) {
                temp = drm_ctxbitmap_next(dev);
@@ -117,11 +118,11 @@ int drm_ctxbitmap_init(struct drm_device *dev)
 
 void drm_ctxbitmap_cleanup(struct drm_device *dev)
 {
-       DRM_LOCK();
+       DRM_LOCK(dev);
        if (dev->context_sareas != NULL)
-               free(dev->context_sareas, DRM_MEM_SAREA);
-       free(dev->ctx_bitmap, DRM_MEM_CTXBITMAP);
-       DRM_UNLOCK();
+               drm_free(dev->context_sareas, DRM_MEM_SAREA);
+       drm_free(dev->ctx_bitmap, DRM_MEM_CTXBITMAP);
+       DRM_UNLOCK(dev);
 }
 
 /* ================================================================
@@ -134,15 +135,15 @@ int drm_getsareactx(struct drm_device *dev, void *data,
        struct drm_ctx_priv_map *request = data;
        drm_local_map_t *map;
 
-       DRM_LOCK();
+       DRM_LOCK(dev);
        if (dev->max_context < 0 ||
            request->ctx_id >= (unsigned) dev->max_context) {
-               DRM_UNLOCK();
+               DRM_UNLOCK(dev);
                return EINVAL;
        }
 
        map = dev->context_sareas[request->ctx_id];
-       DRM_UNLOCK();
+       DRM_UNLOCK(dev);
 
        request->handle = (void *)map->handle;
 
@@ -155,7 +156,7 @@ int drm_setsareactx(struct drm_device *dev, void *data,
        struct drm_ctx_priv_map *request = data;
        drm_local_map_t *map = NULL;
 
-       DRM_LOCK();
+       DRM_LOCK(dev);
        TAILQ_FOREACH(map, &dev->maplist, link) {
                if (map->handle == request->handle) {
                        if (dev->max_context < 0)
@@ -163,13 +164,13 @@ int drm_setsareactx(struct drm_device *dev, void *data,
                        if (request->ctx_id >= (unsigned) dev->max_context)
                                goto bad;
                        dev->context_sareas[request->ctx_id] = map;
-                       DRM_UNLOCK();
+                       DRM_UNLOCK(dev);
                        return 0;
                }
        }
 
 bad:
-       DRM_UNLOCK();
+       DRM_UNLOCK(dev);
        return EINVAL;
 }
 
@@ -247,9 +248,9 @@ int drm_addctx(struct drm_device *dev, void *data, struct drm_file *file_priv)
        }
 
        if (dev->driver->context_ctor && ctx->handle != DRM_KERNEL_CONTEXT) {
-               DRM_LOCK();
+               DRM_LOCK(dev);
                dev->driver->context_ctor(dev, ctx->handle);
-               DRM_UNLOCK();
+               DRM_UNLOCK(dev);
        }
 
        return 0;
@@ -297,9 +298,9 @@ int drm_rmctx(struct drm_device *dev, void *data, struct drm_file *file_priv)
        DRM_DEBUG("%d\n", ctx->handle);
        if (ctx->handle != DRM_KERNEL_CONTEXT) {
                if (dev->driver->context_dtor) {
-                       DRM_LOCK();
+                       DRM_LOCK(dev);
                        dev->driver->context_dtor(dev, ctx->handle);
-                       DRM_UNLOCK();
+                       DRM_UNLOCK(dev);
                }
 
                drm_ctxbitmap_free(dev, ctx->handle);
similarity index 99%
rename from sys/dev/drm2/drm_crtc.c
rename to sys/dev/drm/drm_crtc.c
index 742fed5..39d2818 100644 (file)
  * $FreeBSD: src/sys/dev/drm2/drm_crtc.c,v 1.1 2012/05/22 11:07:44 kib Exp $
  */
 
-#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 <dev/drm/drm.h>
+#include <dev/drm/drmP.h>
+#include <dev/drm/drm_crtc.h>
+#include <dev/drm/drm_edid.h>
+#include <dev/drm/drm_fourcc.h>
 #include <sys/limits.h>
 
 /* Avoid boilerplate.  I'm tired of typing. */
similarity index 99%
rename from sys/dev/drm2/drm_crtc.h
rename to sys/dev/drm/drm_crtc.h
index 4aaa3a0..a7f0fd9 100644 (file)
@@ -27,8 +27,8 @@
 #ifndef __DRM_CRTC_H__
 #define __DRM_CRTC_H__
 
-#include <dev/drm2/drm_gem_names.h>
-#include <dev/drm2/drm_fourcc.h>
+#include <dev/drm/drm_gem_names.h>
+#include <dev/drm/drm_fourcc.h>
 
 struct drm_device;
 struct drm_mode_set;
similarity index 99%
rename from sys/dev/drm2/drm_crtc_helper.c
rename to sys/dev/drm/drm_crtc_helper.c
index 3423ca1..a0af691 100644 (file)
 
 #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/drm/drmP.h>
+#include <dev/drm/drm_crtc.h>
+#include <dev/drm/drm_fourcc.h>
+#include <dev/drm/drm_crtc_helper.h>
+#include <dev/drm/drm_fb_helper.h>
 
 bool
 drm_fetch_cmdline_mode_from_kenv(struct drm_connector *connector,
index 0cc5f72..7bf8241 100644 (file)
@@ -26,6 +26,7 @@
  *    Rickard E. (Rik) Faith <faith@valinux.com>
  *    Gareth Hughes <gareth@valinux.com>
  *
+ * $FreeBSD: head/sys/dev/drm2/drm_dma.c 235783 2012-05-22 11:07:44Z kib $
  */
 
 /** @file drm_dma.c
 int drm_dma_setup(struct drm_device *dev)
 {
 
-       dev->dma = malloc(sizeof(*dev->dma), DRM_MEM_DRIVER, M_NOWAIT | M_ZERO);
+       dev->dma = kmalloc(sizeof(*dev->dma), DRM_MEM_DRIVER, M_NOWAIT | M_ZERO);
        if (dev->dma == NULL)
                return ENOMEM;
 
-       DRM_SPININIT(&dev->dma_lock, "drmdma");
+       spin_init(&dev->dma_lock);
 
        return 0;
 }
@@ -67,23 +68,23 @@ void drm_dma_takedown(struct drm_device *dev)
                        for (j = 0; j < dma->bufs[i].seg_count; j++) {
                                drm_pci_free(dev, dma->bufs[i].seglist[j]);
                        }
-                       free(dma->bufs[i].seglist, DRM_MEM_SEGS);
+                       drm_free(dma->bufs[i].seglist, DRM_MEM_SEGS);
                }
 
                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_free(dma->bufs[i].buflist[j].dev_private,
                                    DRM_MEM_BUFS);
                        }
-                       free(dma->bufs[i].buflist, DRM_MEM_BUFS);
+                       drm_free(dma->bufs[i].buflist, DRM_MEM_BUFS);
                }
        }
 
-       free(dma->buflist, DRM_MEM_BUFS);
-       free(dma->pagelist, DRM_MEM_PAGES);
-       free(dev->dma, DRM_MEM_DRIVER);
+       drm_free(dma->buflist, DRM_MEM_BUFS);
+       drm_free(dma->pagelist, DRM_MEM_PAGES);
+       drm_free(dev->dma, DRM_MEM_DRIVER);
        dev->dma = NULL;
-       DRM_SPINUNINIT(&dev->dma_lock);
+       spin_uninit(&dev->dma_lock);
 }
 
 
similarity index 98%
rename from sys/dev/drm2/drm_dp_iic_helper.c
rename to sys/dev/drm/drm_dp_iic_helper.c
index ad47cb4..39485df 100644 (file)
@@ -28,8 +28,8 @@
 #include <bus/iicbus/iic.h>
 #include "iicbus_if.h"
 #include <bus/iicbus/iiconf.h>
-#include <dev/drm2/drmP.h>
-#include <dev/drm2/drm_dp_helper.h>
+#include <dev/drm/drmP.h>
+#include <dev/drm/drm_dp_helper.h>
 
 static int
 iic_dp_aux_transaction(device_t idev, int mode, uint8_t write_byte,
@@ -282,5 +282,5 @@ static driver_t drm_iic_dp_aux_driver = {
        sizeof(struct iic_dp_aux_data)
 };
 static devclass_t drm_iic_dp_aux_devclass;
-DRIVER_MODULE_ORDERED(drm_iic_dp_aux, drmn, drm_iic_dp_aux_driver,
+DRIVER_MODULE_ORDERED(drm_iic_dp_aux, drm, drm_iic_dp_aux_driver,
     drm_iic_dp_aux_devclass, 0, 0, SI_ORDER_SECOND);
index 3ddd709..55fedfb 100644 (file)
@@ -26,6 +26,7 @@
  *    Rickard E. (Rik) Faith <faith@valinux.com>
  *    Gareth Hughes <gareth@valinux.com>
  *
+ * $FreeBSD: src/sys/dev/drm2/drm_drawable.c,v 1.1 2012/05/22 11:07:44 kib Exp $
  */
 
 /** @file drm_drawable.c
@@ -73,20 +74,16 @@ 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,
+       info = kmalloc(sizeof(struct bsd_drm_drawable_info), DRM_MEM_DRAWABLE,
            M_NOWAIT | M_ZERO);
        if (info == NULL)
                return ENOMEM;
 
-       /*
-        * XXX Only valid for sizeof(int) == sizeof(void *)
-        */
-       info->handle = (intptr_t)info;
-
-       DRM_SPINLOCK(&dev->drw_lock);
+       info->handle = alloc_unr(dev->drw_unrhdr);
+       spin_lock(&dev->drw_lock);
        RB_INSERT(drawable_tree, &dev->drw_head, info);
        draw->handle = info->handle;
-       DRM_SPINUNLOCK(&dev->drw_lock);
+       spin_unlock(&dev->drw_lock);
 
        DRM_DEBUG("%d\n", draw->handle);
 
@@ -98,17 +95,18 @@ 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);
+       spin_lock(&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(info->rects, DRM_MEM_DRAWABLE);
-               free(info, DRM_MEM_DRAWABLE);
+               spin_unlock(&dev->drw_lock);
+               free_unr(dev->drw_unrhdr, draw->handle);
+               drm_free(info->rects, DRM_MEM_DRAWABLE);
+               drm_free(info, DRM_MEM_DRAWABLE);
                return 0;
        } else {
-               DRM_SPINUNLOCK(&dev->drw_lock);
+               spin_unlock(&dev->drw_lock);
                return EINVAL;
        }
 }
@@ -126,21 +124,21 @@ int drm_update_draw(struct drm_device *dev, void *data,
 
        switch (update->type) {
        case DRM_DRAWABLE_CLIPRECTS:
-               DRM_SPINLOCK(&dev->drw_lock);
+               spin_lock(&dev->drw_lock);
                if (update->num != info->num_rects) {
-                       free(info->rects, DRM_MEM_DRAWABLE);
+                       drm_free(info->rects, DRM_MEM_DRAWABLE);
                        info->rects = NULL;
                        info->num_rects = 0;
                }
                if (update->num == 0) {
-                       DRM_SPINUNLOCK(&dev->drw_lock);
+                       spin_unlock(&dev->drw_lock);
                        return 0;
                }
                if (info->rects == NULL) {
-                       info->rects = malloc(sizeof(*info->rects) *
+                       info->rects = kmalloc(sizeof(*info->rects) *
                            update->num, DRM_MEM_DRAWABLE, M_NOWAIT);
                        if (info->rects == NULL) {
-                               DRM_SPINUNLOCK(&dev->drw_lock);
+                               spin_unlock(&dev->drw_lock);
                                return ENOMEM;
                        }
                        info->num_rects = update->num;
@@ -148,7 +146,7 @@ int drm_update_draw(struct drm_device *dev, void *data,
                /* 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);
+               spin_unlock(&dev->drw_lock);
                return ret;
        default:
                return EINVAL;
@@ -159,15 +157,17 @@ void drm_drawable_free_all(struct drm_device *dev)
 {
        struct bsd_drm_drawable_info *info, *next;
 
-       DRM_SPINLOCK(&dev->drw_lock);
+       spin_lock(&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, info);
-               DRM_SPINUNLOCK(&dev->drw_lock);
-               free(info->info.rects, DRM_MEM_DRAWABLE);
-               free(info, DRM_MEM_DRAWABLE);
-               DRM_SPINLOCK(&dev->drw_lock);
+               RB_REMOVE(drawable_tree, &dev->drw_head,
+                   (struct bsd_drm_drawable_info *)info);
+               spin_unlock(&dev->drw_lock);
+               free_unr(dev->drw_unrhdr, info->handle);
+               drm_free(info->info.rects, DRM_MEM_DRAWABLE);
+               drm_free(info, DRM_MEM_DRAWABLE);
+               spin_lock(&dev->drw_lock);
        }
-       DRM_SPINUNLOCK(&dev->drw_lock);
+       spin_unlock(&dev->drw_lock);
 }
index d4d9bd3..3b91cc8 100644 (file)
@@ -26,6 +26,7 @@
  *    Rickard E. (Rik) Faith <faith@valinux.com>
  *    Gareth Hughes <gareth@valinux.com>
  *
+ * $FreeBSD: head/sys/dev/drm2/drm_drv.c 247835 2013-03-05 09:49:34Z kib $
  */
 
 /** @file drm_drv.c
  * open/close, and ioctl dispatch.
  */
 
+#include <sys/devfs.h>
 #include <machine/limits.h>
+
 #include "dev/drm/drmP.h"
 #include "dev/drm/drm.h"
 #include "dev/drm/drm_sarea.h"
 
 #ifdef DRM_DEBUG_DEFAULT_ON
-int drm_debug_flag = 1;
+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. */
 
 static int drm_load(struct drm_device *dev);
 static void drm_unload(struct drm_device *dev);
@@ -52,9 +60,29 @@ static drm_pci_id_list_t *drm_find_description(int vendor, int device,
 #define DRIVER_SOFTC(unit) \
        ((struct drm_device *)devclass_get_softc(drm_devclass, unit))
 
+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 = {
+       "drm",
+       drm_modevent,
+       0
+}; 
+DECLARE_MODULE(drm, drm_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST);
 MODULE_VERSION(drm, 1);
 MODULE_DEPEND(drm, agp, 1, 1, 1);
 MODULE_DEPEND(drm, pci, 1, 1, 1);
+MODULE_DEPEND(drm, iicbus, 1, 1, 1);
 
 static drm_ioctl_desc_t                  drm_ioctls[256] = {
        DRM_IOCTL_DEF(DRM_IOCTL_VERSION, drm_version, 0),
@@ -64,6 +92,7 @@ static drm_ioctl_desc_t                 drm_ioctls[256] = {
        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_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_UNIQUE, drm_setunique, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
@@ -77,6 +106,9 @@ static drm_ioctl_desc_t                drm_ioctls[256] = {
        DRM_IOCTL_DEF(DRM_IOCTL_SET_SAREA_CTX, drm_setsareactx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
        DRM_IOCTL_DEF(DRM_IOCTL_GET_SAREA_CTX, drm_getsareactx, DRM_AUTH),
 
+       DRM_IOCTL_DEF(DRM_IOCTL_SET_MASTER, drm_setmaster_ioctl, DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_IOCTL_DROP_MASTER, drm_dropmaster_ioctl, DRM_ROOT_ONLY),
+
        DRM_IOCTL_DEF(DRM_IOCTL_ADD_CTX, drm_addctx, DRM_AUTH|DRM_ROOT_ONLY),
        DRM_IOCTL_DEF(DRM_IOCTL_RM_CTX, drm_rmctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
        DRM_IOCTL_DEF(DRM_IOCTL_MOD_CTX, drm_modctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
@@ -113,23 +145,57 @@ static drm_ioctl_desc_t             drm_ioctls[256] = {
 
        DRM_IOCTL_DEF(DRM_IOCTL_SG_ALLOC, drm_sg_alloc_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
        DRM_IOCTL_DEF(DRM_IOCTL_SG_FREE, drm_sg_free, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
-       DRM_IOCTL_DEF(DRM_IOCTL_WAIT_VBLANK, drm_wait_vblank, 0),
+       DRM_IOCTL_DEF(DRM_IOCTL_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_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_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_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_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_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_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_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),
 };
 
 static struct dev_ops drm_cdevsw = {
        { "drm", 0, D_TRACKCLOSE },
-       .d_open =       drm_open,
+       .d_open =       drm_open,
        .d_close =      drm_close,
-       .d_read =       drm_read,
-       .d_ioctl =      drm_ioctl,
+       .d_read =       drm_read,
+       .d_ioctl =      drm_ioctl,
        .d_kqfilter =   drm_kqfilter,
-       .d_mmap =       drm_mmap
+       .d_mmap =       drm_mmap,
+       .d_mmap_single = drm_mmap_single,
 };
 
 static int drm_msi = 1;        /* Enable by default. */
 TUNABLE_INT("hw.drm.msi", &drm_msi);
+SYSCTL_NODE(_hw, OID_AUTO, drm, CTLFLAG_RW, NULL, "DRM device");
+SYSCTL_INT(_hw_drm, OID_AUTO, msi, CTLFLAG_RD, &drm_msi, 1,
+    "Enable MSI interrupts for drm devices");
 
 static struct drm_msi_blacklist_entry drm_msi_blacklist[] = {
        {0x8086, 0x2772}, /* Intel i945G        */ \
@@ -160,8 +226,7 @@ int drm_probe(device_t kdev, drm_pci_id_list_t *idlist)
        vendor = pci_get_vendor(kdev);
        device = pci_get_device(kdev);
 
-       if (pci_get_class(kdev) != PCIC_DISPLAY
-           || pci_get_subclass(kdev) != PCIS_DISPLAY_VGA)
+       if (pci_get_class(kdev) != PCIC_DISPLAY)
                return ENXIO;
 
        id_entry = drm_find_description(vendor, device, idlist);
@@ -221,16 +286,18 @@ int drm_attach(device_t kdev, drm_pci_id_list_t *idlist)
                dev->irqr = bus_alloc_resource_any(dev->device, SYS_RES_IRQ,
                    &dev->irqrid, RF_SHAREABLE);
                if (!dev->irqr) {
-                       return ENOENT;
+                       return (ENOENT);
                }
 
                dev->irq = (int) rman_get_start(dev->irqr);
        }
 
-       DRM_SPININIT(&dev->dev_lock, "drmdev");
+       lockinit(&dev->dev_lock, "drmdev", 0, LK_CANRECURSE);
        lwkt_serialize_init(&dev->irq_lock);
-       DRM_SPININIT(&dev->vbl_lock, "drmvbl");
-       DRM_SPININIT(&dev->drw_lock, "drmdrw");
+       lockinit(&dev->vbl_lock, "drmvbl", 0, LK_CANRECURSE);
+       spin_init(&dev->drw_lock);
+       lockinit(&dev->event_lock, "drmev", 0, LK_CANRECURSE);
+       lockinit(&dev->dev_struct_lock, "drmslk", 0, LK_CANRECURSE);
 
        id_entry = drm_find_description(dev->pci_vendor,
            dev->pci_device, idlist);
@@ -244,20 +311,16 @@ 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;
+       return (0);
 }
 
 #ifndef DRM_DEV_NAME
@@ -286,7 +349,7 @@ static int drm_firstopen(struct drm_device *dev)
        drm_local_map_t *map;
        int i;
 
-       DRM_SPINLOCK_ASSERT(&dev->dev_lock);
+       DRM_LOCK_ASSERT(dev);
 
        /* prebuild the SAREA */
        i = drm_addmap(dev, 0, SAREA_MAX, _DRM_SHM,
@@ -311,7 +374,8 @@ static int drm_firstopen(struct drm_device *dev)
        }
 
        dev->lock.lock_queue = 0;
-       dev->irq_enabled = 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;
@@ -329,18 +393,18 @@ static int drm_lastclose(struct drm_device *dev)
        drm_local_map_t *map, *mapsave;
        int i;
 
-       DRM_SPINLOCK_ASSERT(&dev->dev_lock);
+       DRM_LOCK_ASSERT(dev);
 
        DRM_DEBUG("\n");
 
        if (dev->driver->lastclose != NULL)
                dev->driver->lastclose(dev);
 
-       if (dev->irq_enabled)
+       if (!drm_core_check_feature(dev, DRIVER_MODESET) && dev->irq_enabled)
                drm_irq_uninstall(dev);
 
        if (dev->unique) {
-               free(dev->unique, DRM_MEM_DRIVER);
+               drm_free(dev->unique, DRM_MEM_DRIVER);
                dev->unique = NULL;
                dev->unique_len = 0;
        }
@@ -348,14 +412,14 @@ static int drm_lastclose(struct drm_device *dev)
        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);
+                       drm_free(pt, DRM_MEM_MAGIC);
                }
                dev->magiclist[i].head = dev->magiclist[i].tail = NULL;
        }
 
-       DRM_UNLOCK();
+       DRM_UNLOCK(dev);
        drm_drawable_free_all(dev);
-       DRM_LOCK();
+       DRM_LOCK(dev);
 
        /* Clear AGP information */
        if (dev->agp) {
@@ -370,7 +434,7 @@ static int drm_lastclose(struct drm_device *dev)
                        if (entry->bound)
                                drm_agp_unbind_memory(entry->handle);
                        drm_agp_free_memory(entry->handle);
-                       free(entry, DRM_MEM_AGPLISTS);
+                       drm_free(entry, DRM_MEM_AGPLISTS);
                }
                dev->agp->memory = NULL;
 
@@ -429,16 +493,7 @@ static int drm_load(struct drm_device *dev)
        for (i = 0; i < DRM_ARRAY_SIZE(dev->counts); i++)
                atomic_set(&dev->counts[i], 0);
 
-       if (dev->driver->load != NULL) {
-               DRM_LOCK();
-               /* Shared code returns -errno. */
-               retcode = -dev->driver->load(dev,
-                   dev->id_entry->driver_private);
-               pci_enable_busmaster(dev->device);
-               DRM_UNLOCK();
-               if (retcode != 0)
-                       goto error;
-       }
+       INIT_LIST_HEAD(&dev->vblank_event_list);
 
        if (drm_core_has_AGP(dev)) {
                if (drm_device_is_agp(dev))
@@ -450,7 +505,7 @@ static int drm_load(struct drm_device *dev)
                        retcode = ENOMEM;
                        goto error;
                }
-               if (dev->agp != NULL) {
+               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;
@@ -463,6 +518,34 @@ static int drm_load(struct drm_device *dev)
                goto error;
        }
 
+       dev->drw_unrhdr = new_unrhdr(1, INT_MAX, NULL);
+       if (dev->drw_unrhdr == NULL) {
+               DRM_ERROR("Couldn't allocate drawable number allocator\n");
+               retcode = ENOMEM;
+               goto error;
+       }
+
+       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;
+               }
+       }
+
+       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 error;
+       }
+
        DRM_INFO("Initialized %s %d.%d.%d %s\n",
            dev->driver->name,
            dev->driver->major,
@@ -472,16 +555,21 @@ static int drm_load(struct drm_device *dev)
 
        return 0;
 
+error1:
+       delete_unrhdr(dev->drw_unrhdr);
 error:
        drm_sysctl_cleanup(dev);
-       DRM_LOCK();
+       DRM_LOCK(dev);
        drm_lastclose(dev);
-       DRM_UNLOCK();
-       destroy_dev(dev->devnode);
+       DRM_UNLOCK(dev);
+       if (dev->devnode != NULL)
+               destroy_dev(dev->devnode);
 
-       DRM_SPINUNINIT(&dev->drw_lock);
-       DRM_SPINUNINIT(&dev->vbl_lock);
-       DRM_SPINUNINIT(&dev->dev_lock);
+       spin_uninit(&dev->drw_lock);
+       lockuninit(&dev->vbl_lock);
+       lockuninit(&dev->dev_lock);
+       lockuninit(&dev->event_lock);
+       lockuninit(&dev->dev_struct_lock);
 
        return retcode;
 }
@@ -493,12 +581,16 @@ static void drm_unload(struct drm_device *dev)
        DRM_DEBUG("\n");
 
        drm_sysctl_cleanup(dev);
-       destroy_dev(dev->devnode);
+       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 retcode;
+               int __unused retcode;
 
                retcode = drm_mtrr_del(0, dev->agp->info.ai_aperture_base,
                    dev->agp->info.ai_aperture_size, DRM_MTRR_WC);
@@ -507,9 +599,9 @@ static void drm_unload(struct drm_device *dev)
 
        drm_vblank_cleanup(dev);
 
-       DRM_LOCK();
+       DRM_LOCK(dev);
        drm_lastclose(dev);
-       DRM_UNLOCK();
+       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
@@ -525,23 +617,29 @@ static void drm_unload(struct drm_device *dev)
        }
 
        if (dev->agp) {
-               free(dev->agp, DRM_MEM_AGPLISTS);
+               drm_free(dev->agp, DRM_MEM_AGPLISTS);
                dev->agp = NULL;
        }
 
        if (dev->driver->unload != NULL) {
-               DRM_LOCK();
+               DRM_LOCK(dev);
                dev->driver->unload(dev);
-               DRM_UNLOCK();
+               DRM_UNLOCK(dev);
        }
 
+       delete_unrhdr(dev->drw_unrhdr);
+       delete_unrhdr(dev->map_unrhdr);
+
        drm_mem_uninit();
 
-       pci_disable_busmaster(dev->device);
+       if (pci_disable_busmaster(dev->device))
+               DRM_ERROR("Request to disable bus-master failed.\n");
 
-       DRM_SPINUNINIT(&dev->drw_lock);
-       DRM_SPINUNINIT(&dev->vbl_lock);
-       DRM_SPINUNINIT(&dev->dev_lock);
+       spin_uninit(&dev->drw_lock);
+       lockuninit(&dev->vbl_lock);
+       lockuninit(&dev->dev_lock);
+       lockuninit(&dev->event_lock);
+       lockuninit(&dev->dev_struct_lock);
 }
 
 int drm_version(struct drm_device *dev, void *data, struct drm_file *file_priv)
@@ -569,31 +667,37 @@ int drm_version(struct drm_device *dev, void *data, struct drm_file *file_priv)
        return 0;
 }
 
-int drm_open(struct dev_open_args *ap)
+int
+/* drm_open(struct cdev *kdev, int flags, int fmt, DRM_STRUCTPROC *p) */
+drm_open(struct dev_open_args *ap)
 {
        struct cdev *kdev = ap->a_head.a_dev;
        int flags = ap->a_oflags;
        int fmt = 0;
        struct thread *p = curthread;
-       struct drm_device *dev = NULL;
-       int retcode = 0;
+       struct drm_device *dev;
+       int retcode;
 
        dev = DRIVER_SOFTC(minor(kdev));
+       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) {
+       if (retcode == 0) {
                atomic_inc(&dev->counts[_DRM_STAT_OPENS]);
-               DRM_LOCK();
+               DRM_LOCK(dev);
                device_busy(dev->device);
                if (!dev->open_count++)
                        retcode = drm_firstopen(dev);
-               DRM_UNLOCK();
+               DRM_UNLOCK(dev);
        }
 
-       return retcode;
+       DRM_DEBUG("return %d\n", retcode);
+
+       return (retcode);
 }
 
 int drm_close(struct dev_close_args *ap)
@@ -608,10 +712,7 @@ int drm_close(struct dev_close_args *ap)
 
        DRM_DEBUG("open_count = %d\n", dev->open_count);
 
-       DRM_LOCK();
-
-       if (--file_priv->refs != 0)
-               goto done;
+       DRM_LOCK(dev);
 
        if (dev->driver->preclose != NULL)
                dev->driver->preclose(dev, file_priv);
@@ -623,6 +724,9 @@ int drm_close(struct dev_close_args *ap)
        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",
@@ -654,11 +758,8 @@ int drm_close(struct dev_close_args *ap)
                                break;  /* Got lock */
                        }
                        /* Contention */
-                       tsleep_interlock((void *)&dev->lock.lock_queue, PCATCH);
-                       DRM_UNLOCK();
-                       retcode = tsleep((void *)&dev->lock.lock_queue,
-                                        PCATCH | PINTERLOCKED, "drmlk2", 0);
-                       DRM_LOCK();
+                       retcode = DRM_LOCK_SLEEP(dev, &dev->lock.lock_queue,
+                           PCATCH, "drmlk2", 0);
                        if (retcode)
                                break;
                }
@@ -677,19 +778,19 @@ int drm_close(struct dev_close_args *ap)
        if (dev->driver->postclose != NULL)
                dev->driver->postclose(dev, file_priv);
        TAILQ_REMOVE(&dev->files, file_priv, link);
-       free(file_priv, DRM_MEM_FILES);
+       drm_free(file_priv, DRM_MEM_FILES);
 
        /* ========================================================
         * End inline drm_release
         */
-done:
+
        atomic_inc(&dev->counts[_DRM_STAT_CLOSES]);
        device_unbusy(dev->device);
        if (--dev->open_count == 0) {
                retcode = drm_lastclose(dev);
        }
 
-       DRM_UNLOCK();
+       DRM_UNLOCK(dev);
 
        return (0);
 }
@@ -711,10 +812,6 @@ int drm_ioctl(struct dev_ioctl_args *ap)
        struct drm_file *file_priv;
 
        file_priv = drm_find_file_by_proc(dev, p);
-       if (!file_priv) {
-               DRM_ERROR("can't find authenticator\n");
-               return EINVAL;
-       }
 
        atomic_inc(&dev->counts[_DRM_STAT_IOCTLS]);
        ++file_priv->ioctl_count;
@@ -767,16 +864,25 @@ int drm_ioctl(struct dev_ioctl_args *ap)
                return EACCES;
 
        if (is_driver_ioctl) {
-               DRM_LOCK();
+               if ((ioctl->flags & DRM_UNLOCKED) == 0)
+                       DRM_LOCK(dev);
                /* shared code returns -errno */
                retcode = -func(dev, data, file_priv);
-               DRM_UNLOCK();
+               if ((ioctl->flags & DRM_UNLOCKED) == 0)
+                       DRM_UNLOCK(dev);
        } else {
                retcode = func(dev, data, file_priv);
        }
 
        if (retcode != 0)
                DRM_DEBUG("    returning %d\n", retcode);
+       if (retcode != 0 &&
+           (drm_debug_flag & DRM_DEBUGBITS_FAILED_IOCTL) != 0) {
+               kprintf(
+"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);
+       }
 
        return retcode;
 }
@@ -785,7 +891,7 @@ drm_local_map_t *drm_getsarea(struct drm_device *dev)
 {
        drm_local_map_t *map;
 
-       DRM_SPINLOCK_ASSERT(&dev->dev_lock);
+       DRM_LOCK_ASSERT(dev);
        TAILQ_FOREACH(map, &dev->maplist, link) {
                if (map->type == _DRM_SHM && (map->flags & _DRM_CONTAINS_LOCK))
                        return map;
@@ -794,6 +900,49 @@ drm_local_map_t *drm_getsarea(struct drm_device *dev)
        return NULL;
 }
 
+int
+drm_add_busid_modesetting(struct drm_device *dev, struct sysctl_ctx_list *ctx,
+    struct sysctl_oid *top)
+{
+       struct sysctl_oid *oid;
+
+       ksnprintf(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);
+}
+
+int
+drm_mmap_single(struct dev_mmap_single_args *ap)
+{
+       struct drm_device *dev;
+       struct cdev *kdev = ap->a_head.a_dev;
+       vm_ooffset_t *offset = ap->a_offset;
+       vm_size_t size = ap->a_size;
+       struct vm_object **obj_res = ap->a_object;
+       int nprot = ap->a_nprot;
+
+       dev = drm_get_device_from_kdev(kdev);
+       if ((dev->driver->driver_features & DRIVER_GEM) != 0) {
+               return (drm_gem_mmap_single(dev, offset, size, obj_res, nprot));
+       } else if (dev->drm_ttm_bo != NULL) {
+               return (ttm_bo_mmap_single(dev->drm_ttm_bo, offset, size,
+                   obj_res, nprot));
+       } else {
+               return (ENODEV);
+       }
+}
+
 #if DRM_LINUX
 
 #include <sys/sysproto.h>
@@ -833,3 +982,83 @@ drm_linux_ioctl(DRM_STRUCTPROC *p, struct linux_ioctl_args* args)
        return error;
 }
 #endif /* DRM_LINUX */
+
+/*
+ * Check if dmi_system_id structure matches system DMI data
+ */
+static bool
+dmi_found(const struct dmi_system_id *dsi)
+{
+       int i, slot;
+       bool found = false;
+       char *sys_vendor, *board_vendor, *product_name, *board_name;
+
+       sys_vendor = kgetenv("smbios.system.maker");
+       board_vendor = kgetenv("smbios.planar.maker");
+       product_name = kgetenv("smbios.system.product");
+       board_name = kgetenv("smbios.planar.product");
+
+       for (i = 0; i < NELEM(dsi->matches); i++) {
+               slot = dsi->matches[i].slot;
+               switch (slot) {
+               case DMI_NONE:
+                       break;
+               case DMI_SYS_VENDOR:
+                       if (sys_vendor != NULL &&
+                           !strcmp(sys_vendor, dsi->matches[i].substr))
+                               break;
+                       else
+                               goto done;
+               case DMI_BOARD_VENDOR:
+                       if (board_vendor != NULL &&
+                           !strcmp(board_vendor, dsi->matches[i].substr))
+                               break;
+                       else
+                               goto done;
+               case DMI_PRODUCT_NAME:
+                       if (product_name != NULL &&
+                           !strcmp(product_name, dsi->matches[i].substr))
+                               break;
+                       else
+                               goto done;
+               case DMI_BOARD_NAME:
+                       if (board_name != NULL &&
+                           !strcmp(board_name, dsi->matches[i].substr))
+                               break;
+                       else
+                               goto done;
+               default:
+                       goto done;
+               }
+       }
+       found = true;
+
+done:
+       if (sys_vendor != NULL)
+               kfreeenv(sys_vendor);
+       if (board_vendor != NULL)
+               kfreeenv(board_vendor);
+       if (product_name != NULL)
+               kfreeenv(product_name);
+       if (board_name != NULL)
+               kfreeenv(board_name);
+
+       return found;
+}
+
+bool
+dmi_check_system(const struct dmi_system_id *sysid)
+{
+       const struct dmi_system_id *dsi;
+       int num = 0;
+
+       for (dsi = sysid; dsi->matches[0].slot != 0 ; dsi++) {
+               if (dmi_found(dsi)) {
+                       num++;
+                       if (dsi->callback && dsi->callback(dsi))
+                               break;
+               }
+       }
+       return (num);
+}
+
similarity index 99%
rename from sys/dev/drm2/drm_edid.c
rename to sys/dev/drm/drm_edid.c
index 557563b..b202cf5 100644 (file)
@@ -30,9 +30,9 @@
  * $FreeBSD: head/sys/dev/drm2/drm_edid.c 249041 2013-04-03 08:27:35Z dumbbell $
  */
 
-#include <dev/drm2/drmP.h>
-#include <dev/drm2/drm_edid.h>
-#include <dev/drm2/drm_edid_modes.h>
+#include <dev/drm/drmP.h>
+#include <dev/drm/drm_edid.h>
+#include <dev/drm/drm_edid_modes.h>
 #include <bus/iicbus/iic.h>
 #include <bus/iicbus/iiconf.h>
 #include "iicbus_if.h"
similarity index 99%
rename from sys/dev/drm2/drm_edid.h
rename to sys/dev/drm/drm_edid.h
index f9a79f0..839e5ae 100644 (file)
@@ -26,7 +26,7 @@
 #define __DRM_EDID_H__
 
 #include <sys/types.h>
-#include <dev/drm2/drmP.h>
+#include <dev/drm/drmP.h>
 
 #define EDID_LENGTH 128
 #define DDC_ADDR 0x50
similarity index 99%
rename from sys/dev/drm2/drm_edid_modes.h
rename to sys/dev/drm/drm_edid_modes.h
index 4ab5641..e422af7 100644 (file)
@@ -25,8 +25,8 @@
  * $FreeBSD: src/sys/dev/drm2/drm_edid_modes.h,v 1.1 2012/05/22 11:07:44 kib Exp $
  */
 
-#include <dev/drm2/drmP.h>
-#include <dev/drm2/drm_edid.h>
+#include <dev/drm/drmP.h>
+#include <dev/drm/drm_edid.h>
 
 /*
  * Autogenerated from the DMT spec.
similarity index 99%
rename from sys/dev/drm2/drm_fb_helper.c
rename to sys/dev/drm/drm_fb_helper.c
index f61f0c5..897e085 100644 (file)
  * $FreeBSD: src/sys/dev/drm2/drm_fb_helper.c,v 1.1 2012/05/22 11:07:44 kib Exp $
  */
 
-#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>
+#include <dev/drm/drmP.h>
+#include <dev/drm/drm_crtc.h>
+#include <dev/drm/drm_fb_helper.h>
+#include <dev/drm/drm_crtc_helper.h>
 
 static DRM_LIST_HEAD(kernel_fb_helper_list);
 
index ae4a9e2..2d11fd0 100644 (file)
@@ -27,6 +27,7 @@
  *    Daryll Strauss <daryll@valinux.com>
  *    Gareth Hughes <gareth@valinux.com>
  *
+ * $FreeBSD: src/sys/dev/drm2/drm_fops.c,v 1.1 2012/05/22 11:07:44 kib Exp $
  */
 
 /** @file drm_fops.c
@@ -34,6 +35,9 @@
  * open of the DRM device.
  */
 
+#include <sys/types.h>
+#include <sys/conf.h>
+
 #include "dev/drm/drmP.h"
 
 struct drm_file *drm_find_file_by_proc(struct drm_device *dev, DRM_STRUCTPROC *p)
@@ -53,60 +57,130 @@ int drm_open_helper(struct cdev *kdev, int flags, int fmt, DRM_STRUCTPROC *p,
                    struct drm_device *dev)
 {
        struct drm_file *priv;
-       int m = minor(kdev);
        int retcode;
 
        if (flags & O_EXCL)
                return EBUSY; /* No exclusive opens */
        dev->flags = flags;
 
-       DRM_DEBUG("pid = %d, minor = %d\n", DRM_CURRENTPID, m);
-        DRM_LOCK();
+       DRM_DEBUG("pid = %d, device = %s\n", DRM_CURRENTPID, devtoname(kdev));
+       DRM_LOCK(dev);
+
         priv = drm_find_file_by_proc(dev, p);
         if (priv) {
-                priv->refs++;
-        } else {
-                priv = malloc(sizeof(*priv), DRM_MEM_FILES, M_NOWAIT | M_ZERO);
-                if (priv == NULL) {
-                        DRM_UNLOCK();
-                        return ENOMEM;
-                }
-                priv->uid               = p->td_proc->p_ucred->cr_svuid;
-                priv->pid               = p->td_proc->p_pid;
-                priv->refs              = 1;
-                priv->minor             = m;
-                priv->ioctl_count       = 0;
-
-                /* for compatibility root is always authenticated */
-                priv->authenticated     = DRM_SUSER(p);
-
-                if (dev->driver->open) {
-                        /* shared code returns -errno */
-                        retcode = -dev->driver->open(dev, priv);
-                        if (retcode != 0) {
-                                free(priv, DRM_MEM_FILES);
-                                DRM_UNLOCK();
-                                return retcode;
-                        }
-                }
-
-                /* first opener automatically becomes master */
-                priv->master = TAILQ_EMPTY(&dev->files);
-
-                TAILQ_INSERT_TAIL(&dev->files, priv, link);
+               goto priv_found;
+        }
+
+       priv = kmalloc(sizeof(*priv), DRM_MEM_FILES, M_NOWAIT | M_ZERO);
+       if (priv == NULL) {
+               return ENOMEM;
+       }
+       
+priv_found:
+
+       priv->dev               = dev;
+       priv->uid               = p->td_proc->p_ucred->cr_svuid;
+       priv->uid               = p->td_ucred->cr_svuid;
+       priv->pid               = p->td_proc->p_pid;
+       priv->ioctl_count       = 0;
+
+       /* for compatibility root is always authenticated */
+       priv->authenticated     = DRM_SUSER(p);
+
+       INIT_LIST_HEAD(&priv->fbs);
+       INIT_LIST_HEAD(&priv->event_list);
+       priv->event_space = 4096; /* set aside 4k for event buffer */
+
+       if (dev->driver->driver_features & DRIVER_GEM)
+               drm_gem_open(dev, priv);
+
+       if (dev->driver->open) {
+               /* shared code returns -errno */
+               retcode = -dev->driver->open(dev, priv);
+               if (retcode != 0) {
+                       drm_free(priv, DRM_MEM_FILES);
+                       DRM_UNLOCK(dev);
+                       return retcode;
+               }
        }
 
-       DRM_UNLOCK();
+       /* first opener automatically becomes master */
+       priv->master = TAILQ_EMPTY(&dev->files);
+
+       TAILQ_INSERT_TAIL(&dev->files, priv, link);
+       DRM_UNLOCK(dev);
        kdev->si_drv1 = dev;
        return 0;
 }
 
+static bool
+drm_dequeue_event(struct drm_device *dev, struct drm_file *file_priv,
+    struct uio *uio, struct drm_pending_event **out)
+{
+       struct drm_pending_event *e;
+
+       if (list_empty(&file_priv->event_list))
+               return (false);
+       e = list_first_entry(&file_priv->event_list,
+           struct drm_pending_event, link);
+       if (e->event->length > uio->uio_resid)
+               return (false);
+
+       file_priv->event_space += e->event->length;
+       list_del(&e->link);
+       *out = e;
+       return (true);
+}
+
+int
+drm_read(struct dev_read_args *ap)
+{
+       struct cdev *kdev = ap->a_head.a_dev;
+       struct uio *uio = ap->a_uio;
+       int ioflag = ap->a_ioflag;
+       struct drm_file *file_priv;
+       struct drm_device *dev;
+       struct drm_pending_event *e;
+       int error;
+
+       dev = drm_get_device_from_kdev(kdev);
+       file_priv = drm_find_file_by_proc(dev, curthread);
+
+       lockmgr(&dev->event_lock, LK_EXCLUSIVE);
+       while (list_empty(&file_priv->event_list)) {
+               if ((ioflag & O_NONBLOCK) != 0) {
+                       error = EAGAIN;
+                       goto out;
+               }
+               error = lksleep(&file_priv->event_space, &dev->event_lock,
+                  PCATCH, "drmrea", 0);
+              if (error != 0)
+                      goto out;
+       }
+       while (drm_dequeue_event(dev, file_priv, uio, &e)) {
+               lockmgr(&dev->event_lock, LK_RELEASE);
+               error = uiomove((caddr_t)e->event, e->event->length, uio);
+               e->destroy(e);
+               if (error != 0)
+                       return (error);
+               lockmgr(&dev->event_lock, LK_EXCLUSIVE);
+       }
+out:
+       lockmgr(&dev->event_lock, LK_RELEASE);
+       return (error);
+}
 
-/* The drm_read and drm_poll are stubs to prevent spurious errors
- * on older X Servers (4.3.0 and earlier) */
-int drm_read(struct dev_read_args *ap)
+void
+drm_event_wakeup(struct drm_pending_event *e)
 {
-       return 0;
+       struct drm_file *file_priv;
+       struct drm_device *dev;
+
+       file_priv = e->file_priv;
+       dev = file_priv->dev;
+       KKASSERT(lockstatus(&dev->event_lock, curthread) != 0);
+
+       wakeup(&file_priv->event_space);
 }
 
 static int
similarity index 99%
rename from sys/dev/drm2/drm_gem.c
rename to sys/dev/drm/drm_gem.c
index c6cc199..9108532 100644 (file)
@@ -41,9 +41,9 @@
 #include <vm/vm.h>
 #include <vm/vm_page.h>
 
-#include <dev/drm2/drmP.h>
-#include <dev/drm2/drm.h>
-#include <dev/drm2/drm_sarea.h>
+#include <dev/drm/drmP.h>
+#include <dev/drm/drm.h>
+#include <dev/drm/drm_sarea.h>
 
 /*
  * We make up offsets for buffer objects so we can recognize them at
similarity index 98%
rename from sys/dev/drm2/drm_gem_names.c
rename to sys/dev/drm/drm_gem_names.c
index 2780296..1f7f229 100644 (file)
@@ -36,8 +36,8 @@
 #include <sys/malloc.h>
 #include <sys/proc.h>
 
-#include <dev/drm2/drmP.h>
-#include <dev/drm2/drm_gem_names.h>
+#include <dev/drm/drmP.h>
+#include <dev/drm/drm_gem_names.h>
 
 MALLOC_DEFINE(M_GEM_NAMES, "gem_name", "Hash headers for the gem names");
 
similarity index 98%
rename from sys/dev/drm2/drm_global.c
rename to sys/dev/drm/drm_global.c
index df20cd2..e321a79 100644 (file)
@@ -29,8 +29,8 @@
  * $FreeBSD: head/sys/dev/drm2/drm_global.c 248060 2013-03-08 18:11:02Z dumbbell $
  */
 
-#include <dev/drm2/drmP.h>
-#include <dev/drm2/drm_global.h>
+#include <dev/drm/drmP.h>
+#include <dev/drm/drm_global.h>
 
 MALLOC_DEFINE(M_DRM_GLOBAL, "drm_global", "DRM Global Items");
 
index 2887187..8842b06 100644 (file)
@@ -24,7 +24,7 @@
  * USE OR OTHER DEALINGS IN THE SOFTWARE.
  *
  *
- * $FreeBSD: src/sys/dev/drm/drm_hashtab.h,v 1.1 2010/01/31 14:25:29 rnoland Exp $
+ * $FreeBSD: head/sys/dev/drm2/drm_hashtab.h 235783 2012-05-22 11:07:44Z kib $
  **************************************************************************/
 
 /*
@@ -46,7 +46,7 @@ struct drm_hash_item {
 
 struct drm_open_hash {
        LIST_HEAD(drm_hash_item_list, drm_hash_item) *table;
-       unsigned int  size;
+       unsigned int size;
        unsigned int order;
        unsigned long mask;
 };
index 8676040..e1db9ab 100644 (file)
@@ -26,6 +26,7 @@
  *    Rickard E. (Rik) Faith <faith@valinux.com>
  *    Gareth Hughes <gareth@valinux.com>
  *
+ * $FreeBSD: src/sys/dev/drm2/drm_ioctl.c,v 1.1 2012/05/22 11:07:44 kib Exp $
  */
 
 /** @file drm_ioctl.c
@@ -69,12 +70,12 @@ int drm_setunique(struct drm_device *dev, void *data,
        if (!u->unique_len || u->unique_len > 1024)
                return EINVAL;
 
-       busid = malloc(u->unique_len + 1, DRM_MEM_DRIVER, M_WAITOK);
+       busid = kmalloc(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);
+               drm_free(busid, DRM_MEM_DRIVER);
                return EFAULT;
        }
        busid[u->unique_len] = '\0';
@@ -82,9 +83,9 @@ int drm_setunique(struct drm_device *dev, void *data,
        /* Return error if the busid submitted doesn't match the device's actual
         * busid.
         */
-       ret = sscanf(busid, "PCI:%d:%d:%d", &bus, &slot, &func);
+       ret = ksscanf(busid, "PCI:%d:%d:%d", &bus, &slot, &func);
        if (ret != 3) {
-               free(busid, DRM_MEM_DRIVER);
+               drm_free(busid, DRM_MEM_DRIVER);
                return EINVAL;
        }
        domain = bus >> 8;
@@ -94,20 +95,20 @@ int drm_setunique(struct drm_device *dev, void *data,
            (bus != dev->pci_bus) ||
            (slot != dev->pci_slot) ||
            (func != dev->pci_func)) {
-               free(busid, DRM_MEM_DRIVER);
+               drm_free(busid, DRM_MEM_DRIVER);
                return EINVAL;
        }
 
        /* Actually set the device's busid now. */
-       DRM_LOCK();
+       DRM_LOCK(dev);
        if (dev->unique_len || dev->unique) {
-               DRM_UNLOCK();
+               DRM_UNLOCK(dev);
                return EBUSY;
        }
 
        dev->unique_len = u->unique_len;
        dev->unique = busid;
-       DRM_UNLOCK();
+       DRM_UNLOCK(dev);
 
        return 0;
 }
@@ -117,24 +118,24 @@ static int
 drm_set_busid(struct drm_device *dev)
 {
 
-       DRM_LOCK();
+       DRM_LOCK(dev);
 
        if (dev->unique != NULL) {
-               DRM_UNLOCK();
+               DRM_UNLOCK(dev);
                return EBUSY;
        }
 
        dev->unique_len = 20;
-       dev->unique = malloc(dev->unique_len + 1, DRM_MEM_DRIVER, M_NOWAIT);
+       dev->unique = kmalloc(dev->unique_len + 1, DRM_MEM_DRIVER, M_NOWAIT);
        if (dev->unique == NULL) {
-               DRM_UNLOCK();
+               DRM_UNLOCK(dev);
                return ENOMEM;
        }
 
-       snprintf(dev->unique, dev->unique_len, "pci:%04x:%02x:%02x.%1x",
+       ksnprintf(dev->unique, dev->unique_len, "pci:%04x:%02x:%02x.%1x",
            dev->pci_domain, dev->pci_bus, dev->pci_slot, dev->pci_func);
 
-       DRM_UNLOCK();
+       DRM_UNLOCK(dev);
 
        return 0;
 }
@@ -148,9 +149,9 @@ int drm_getmap(struct drm_device *dev, void *data, struct drm_file *file_priv)
 
        idx = map->offset;
 
-       DRM_LOCK();
+       DRM_LOCK(dev);
        if (idx < 0) {
-               DRM_UNLOCK();
+               DRM_UNLOCK(dev);
                return EINVAL;
        }
 
@@ -167,7 +168,7 @@ int drm_getmap(struct drm_device *dev, void *data, struct drm_file *file_priv)
                i++;
        }
 
-       DRM_UNLOCK();
+       DRM_UNLOCK(dev);
 
        if (mapinlist == NULL)
                return EINVAL;
@@ -184,7 +185,7 @@ int drm_getclient(struct drm_device *dev, void *data,
        int i = 0;
 
        idx = client->idx;
-       DRM_LOCK();
+       DRM_LOCK(dev);
        TAILQ_FOREACH(pt, &dev->files, link) {
                if (i == idx) {
                        client->auth  = pt->authenticated;
@@ -192,12 +193,12 @@ int drm_getclient(struct drm_device *dev, void *data,
                        client->uid   = pt->uid;
                        client->magic = pt->magic;
                        client->iocs  = pt->ioctl_count;
-                       DRM_UNLOCK();
+                       DRM_UNLOCK(dev);
                        return 0;
                }
                i++;
        }
-       DRM_UNLOCK();
+       DRM_UNLOCK(dev);
 
        return EINVAL;
 }
@@ -209,7 +210,7 @@ int drm_getstats(struct drm_device *dev, void *data, struct drm_file *file_priv)
 
        memset(stats, 0, sizeof(struct drm_stats));
        
-       DRM_LOCK();
+       DRM_LOCK(dev);
 
        for (i = 0; i < dev->counters; i++) {
                if (dev->types[i] == _DRM_STAT_LOCK)
@@ -222,11 +223,37 @@ int drm_getstats(struct drm_device *dev, void *data, struct drm_file *file_priv)
        
        stats->count = dev->counters;
 
-       DRM_UNLOCK();
+       DRM_UNLOCK(dev);
 
        return 0;
 }
 
+int drm_getcap(struct drm_device *dev, void *data, struct drm_file *file_priv)
+{
+       struct drm_get_cap *req = data;
+
+       req->value = 0;
+       switch (req->capability) {
+       case DRM_CAP_DUMB_BUFFER:
+               if (dev->driver->dumb_create)
+                       req->value = 1;
+               break;
+       case DRM_CAP_VBLANK_HIGH_CRTC:
+               req->value = 1;
+               break;
+       case DRM_CAP_DUMB_PREFERRED_DEPTH:
+               req->value = dev->mode_config.preferred_depth;
+               break;
+       case DRM_CAP_DUMB_PREFER_SHADOW:
+               req->value = dev->mode_config.prefer_shadow;
+               break;
+       default:
+               return EINVAL;
+       }
+       return 0;
+}
+
+
 #define DRM_IF_MAJOR   1
 #define DRM_IF_MINOR   2
 
@@ -246,6 +273,15 @@ int drm_setversion(struct drm_device *dev, void *data,
        sv->drm_dd_major = dev->driver->major;
        sv->drm_dd_minor = dev->driver->minor;
 
+       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) {
index bb53d28..75d0f34 100644 (file)
@@ -23,6 +23,7 @@
  * Authors:
  *    Eric Anholt <anholt@FreeBSD.org>
  *
+ * $FreeBSD: src/sys/dev/drm2/drm_irq.c,v 1.1 2012/05/22 11:07:44 kib Exp $
  */
 
 /** @file drm_irq.c
 #include "dev/drm/drmP.h"
 #include "dev/drm/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) ( \
+       (dev)->_vblank_time[(crtc) * DRM_VBLANKTIME_RBSIZE + \
+       ((count) % DRM_VBLANKTIME_RBSIZE)])
+
+/* Retry timestamp calculation up to 3 times to satisfy
+ * drm_timestamp_precision before giving up.
+ */
+#define DRM_TIMESTAMP_MAXRETRIES 3
+
+/* Threshold in nanoseconds for detection of redundant
+ * vblank irq in drm_handle_vblank(). 1 msec should be ok.
+ */
+#define DRM_REDUNDANT_VBLIRQ_THRESH_NS 1000000
+
 int drm_irq_by_busid(struct drm_device *dev, void *data,
                     struct drm_file *file_priv)
 {
@@ -52,105 +70,19 @@ int drm_irq_by_busid(struct drm_device *dev, void *data,
        return 0;
 }
 
-static void vblank_disable_fn(void *arg)
+int
+drm_irq_install(struct drm_device *dev)
 {
-       struct drm_device *dev = (struct drm_device *)arg;
-       int i;
-
-       DRM_SPINLOCK(&dev->vbl_lock);
-       
-       if (callout_pending(&dev->vblank_disable_timer)) {
-               /* callout was reset */
-               DRM_SPINUNLOCK(&dev->vbl_lock);
-               return;
-       }
-       if (!callout_active(&dev->vblank_disable_timer)) {
-               /* callout was stopped */
-               DRM_SPINUNLOCK(&dev->vbl_lock);
-               return;
-       }
-       callout_deactivate(&dev->vblank_disable_timer);
-
-       DRM_DEBUG("vblank_disable: %s\n", dev->vblank_disable_allowed ?
-               "allowed" : "denied");
-       if (!dev->vblank_disable_allowed) {
-               DRM_SPINUNLOCK(&dev->vbl_lock);
-               return;
-       }
-
-       for (i = 0; i < dev->num_crtcs; i++) {
-               if (dev->vblank[i].refcount == 0 &&
-                   dev->vblank[i].enabled && !dev->vblank[i].inmodeset) {
-                       DRM_DEBUG("disabling vblank on crtc %d\n", i);
-                       dev->vblank[i].last =
-                           dev->driver->get_vblank_counter(dev, i);
-                       dev->driver->disable_vblank(dev, i);
-                       dev->vblank[i].enabled = 0;
-               }
-       }
-       DRM_SPINUNLOCK(&dev->vbl_lock);
-}
-
-void drm_vblank_cleanup(struct drm_device *dev)
-{
-       /* Bail if the driver didn't call drm_vblank_init() */
-       if (dev->num_crtcs == 0)
-               return;
-
-       DRM_SPINLOCK(&dev->vbl_lock);
-       callout_stop(&dev->vblank_disable_timer);
-       DRM_SPINUNLOCK(&dev->vbl_lock);
-
-       vblank_disable_fn(dev);
-
-       free(dev->vblank, DRM_MEM_DRIVER);
-
-       dev->num_crtcs = 0;
-}
-
-int drm_vblank_init(struct drm_device *dev, int num_crtcs)
-{
-       int i, ret = ENOMEM;
-
-       callout_init(&dev->vblank_disable_timer);
-       dev->num_crtcs = num_crtcs;
-
-       dev->vblank = malloc(sizeof(struct drm_vblank_info) * num_crtcs,
-           DRM_MEM_DRIVER, M_NOWAIT | M_ZERO);
-       if (!dev->vblank)
-           goto err;
-
-       DRM_DEBUG("\n");
-
-       /* Zero per-crtc vblank stuff */
-       DRM_SPINLOCK(&dev->vbl_lock);
-       for (i = 0; i < num_crtcs; i++) {
-               DRM_INIT_WAITQUEUE(&dev->vblank[i].queue);
-               dev->vblank[i].refcount = 0;
-               atomic_store_rel_32(&dev->vblank[i].count, 0);
-       }
-       dev->vblank_disable_allowed = 0;
-       DRM_SPINUNLOCK(&dev->vbl_lock);
-
-       return 0;
-
-err:
-       drm_vblank_cleanup(dev);
-       return ret;
-}
-
-int drm_irq_install(struct drm_device *dev)
-{
-       int crtc, retcode;
+       int retcode;
 
        if (dev->irq == 0 || dev->dev_private == NULL)
-               return EINVAL;
+               return (EINVAL);
 
        DRM_DEBUG("irq=%d\n", dev->irq);
 
-       DRM_LOCK();
+       DRM_LOCK(dev);
        if (dev->irq_enabled) {
-               DRM_UNLOCK();
+               DRM_UNLOCK(dev);
                return EBUSY;
        }
        dev->irq_enabled = 1;
@@ -158,44 +90,33 @@ int drm_irq_install(struct drm_device *dev)
        dev->context_flag = 0;
 
        /* Before installing handler */
-       dev->driver->irq_preinstall(dev);
-       DRM_UNLOCK();
+       if (dev->driver->irq_preinstall)
+               dev->driver->irq_preinstall(dev);
+       DRM_UNLOCK(dev);
 
        /* Install handler */
        retcode = bus_setup_intr(dev->device, dev->irqr, INTR_MPSAFE,
-                                dev->driver->irq_handler, dev, &dev->irqh,
-                                &dev->irq_lock);
+           dev->driver->irq_handler, dev, &dev->irqh, &dev->irq_lock);
        if (retcode != 0)
                goto err;
 
        /* After installing handler */
-       DRM_LOCK();
-       dev->driver->irq_postinstall(dev);
-       DRM_UNLOCK();
-       if (dev->driver->enable_vblank) {
-               DRM_SPINLOCK(&dev->vbl_lock);
-               for( crtc = 0 ; crtc < dev->num_crtcs ; crtc++) {
-                       if (dev->driver->enable_vblank(dev, crtc) == 0) {
-                               dev->vblank[crtc].enabled = 1;
-                       }
-               }
-               callout_reset(&dev->vblank_disable_timer, 5 * DRM_HZ,
-                   (timeout_t *)vblank_disable_fn, (void *)dev);
-               DRM_SPINUNLOCK(&dev->vbl_lock);
-       }
+       DRM_LOCK(dev);
+       if (dev->driver->irq_postinstall)
+               dev->driver->irq_postinstall(dev);
+       DRM_UNLOCK(dev);
 
-       return 0;
+       return (0);
 err:
-       DRM_LOCK();
+       device_printf(dev->device, "Error setting interrupt: %d\n", retcode);
        dev->irq_enabled = 0;
-       DRM_UNLOCK();
 
-       return retcode;
+       return (retcode);
 }
 
 int drm_irq_uninstall(struct drm_device *dev)
 {
-       int crtc;
+       int i;
 
        if (!dev->irq_enabled)
                return EINVAL;
@@ -205,24 +126,25 @@ int drm_irq_uninstall(struct drm_device *dev)
        /*
        * Wake up any waiters so they don't hang.
        */
-       DRM_SPINLOCK(&dev->vbl_lock);
-       for (crtc = 0; crtc < dev->num_crtcs; crtc++) {
-               if (dev->vblank[crtc].enabled) {
-                       DRM_WAKEUP(&dev->vblank[crtc].queue);
-                       dev->vblank[crtc].last =
-                           dev->driver->get_vblank_counter(dev, crtc);
-                       dev->vblank[crtc].enabled = 0;
+       if (dev->num_crtcs) {
+               lockmgr(&dev->vbl_lock, LK_EXCLUSIVE);
+               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);
                }
+               lockmgr(&dev->vbl_lock, LK_RELEASE);
        }
-       DRM_SPINUNLOCK(&dev->vbl_lock);
 
        DRM_DEBUG("irq=%d\n", dev->irq);
 
-       dev->driver->irq_uninstall(dev);
+       if (dev->driver->irq_uninstall)
+               dev->driver->irq_uninstall(dev);
 
-       DRM_UNLOCK();
+       DRM_UNLOCK(dev);
        bus_teardown_intr(dev->device, dev->irqr, dev->irqh);
-       DRM_LOCK();
+       DRM_LOCK(dev);
 
        return 0;
 }
@@ -239,6 +161,8 @@ int drm_control(struct drm_device *dev, void *data, struct drm_file *file_priv)
                 */
                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;
@@ -246,23 +170,548 @@ int drm_control(struct drm_device *dev, void *data, struct drm_file *file_priv)
        case DRM_UNINST_HANDLER:
                if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
                        return 0;
-               DRM_LOCK();
+               if (drm_core_check_feature(dev, DRIVER_MODESET))
+                       return 0;
+               DRM_LOCK(dev);
                err = drm_irq_uninstall(dev);
-               DRM_UNLOCK();
+               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;
+       uint32_t 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);
+}
+
+/*
+ * Clear vblank timestamp buffer for a crtc.
+ */
+static void clear_vblank_timestamps(struct drm_device *dev, int crtc)
+{
+       memset(&dev->_vblank_time[crtc * DRM_VBLANKTIME_RBSIZE], 0,
+               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
+ * are preserved, even if there are any spurious vblank irq's after
+ * disable.
+ */
+static void vblank_disable_and_save(struct drm_device *dev, int crtc)
+{
+       u32 vblcount;
+       int64_t diff_ns;
+       int vblrc;
+       struct timeval tvblank;
+
+       /* Prevent vblank irq processing while disabling vblank irqs,
+        * so no updates of timestamps or count can happen after we've
+        * disabled. Needed to prevent races in case of delayed irq's.
+        */
+       lockmgr(&dev->vblank_time_lock, LK_EXCLUSIVE);
+
+       dev->driver->disable_vblank(dev, crtc);
+       dev->vblank_enabled[crtc] = 0;
+
+       /* No further vblank irq's will be processed after
+        * this point. Get current hardware vblank count and
+        * vblank timestamp, repeat until they are consistent.
+        *
+        * FIXME: There is still a race condition here and in
+        * drm_update_vblank_count() which can cause off-by-one
+        * reinitialization of software vblank counter. If gpu
+        * vblank counter doesn't increment exactly at the leading
+        * edge of a vblank interval, then we can lose 1 count if
+        * we happen to execute between start of vblank and the
+        * delayed gpu counter increment.
+        */
+       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));
+
+       /* Compute time difference to stored timestamp of last vblank
+        * as updated by last invocation of drm_handle_vblank() in vblank irq.
+        */
+       vblcount = atomic_read(&dev->_vblank_count[crtc]);
+       diff_ns = timeval_to_ns(&tvblank) -
+                 timeval_to_ns(&vblanktimestamp(dev, crtc, vblcount));
+
+       /* If there is at least 1 msec difference between the last stored
+        * timestamp and tvblank, then we are currently executing our
+        * disable inside a new vblank interval, the tvblank timestamp
+        * corresponds to this new vblank interval and the irq handler
+        * for this vblank didn't run yet and won't run due to our disable.
+        * Therefore we need to do the job of drm_handle_vblank() and
+        * increment the vblank counter by one to account for this vblank.
+        *
+        * Skip this step if there isn't any high precision timestamp
+        * available. In that case we can't account for this and just
+        * hope for the best.
+        */
+       if ((vblrc > 0) && (abs64(diff_ns) > 1000000)) {
+               atomic_inc(&dev->_vblank_count[crtc]);
+       }
+
+       /* Invalidate all timestamps while vblank irq's are off. */
+       clear_vblank_timestamps(dev, crtc);
+
+       lockmgr(&dev->vblank_time_lock, LK_RELEASE);
+}
+
+static void vblank_disable_fn(void * arg)
+{
+       struct drm_device *dev = (struct drm_device *)arg;
+       int i;
+
+       if (!dev->vblank_disable_allowed)
+               return;
+
+       for (i = 0; i < dev->num_crtcs; i++) {
+               lockmgr(&dev->vbl_lock, LK_EXCLUSIVE);
+               if (atomic_read(&dev->vblank_refcount[i]) == 0 &&
+                   dev->vblank_enabled[i]) {
+                       DRM_DEBUG("disabling vblank on crtc %d\n", i);
+                       vblank_disable_and_save(dev, i);
+               }
+               lockmgr(&dev->vbl_lock, LK_RELEASE);
+       }
+}
+
+void drm_vblank_cleanup(struct drm_device *dev)
+{
+       /* Bail if the driver didn't call drm_vblank_init() */
+       if (dev->num_crtcs == 0)
+               return;
+
+       callout_stop(&dev->vblank_disable_callout);
+
+       vblank_disable_fn(dev);
+
+       drm_free(dev->_vblank_count, DRM_MEM_VBLANK);
+       drm_free(dev->vblank_refcount, DRM_MEM_VBLANK);
+       drm_free(dev->vblank_enabled, DRM_MEM_VBLANK);
+       drm_free(dev->last_vblank, DRM_MEM_VBLANK);
+       drm_free(dev->last_vblank_wait, DRM_MEM_VBLANK);
+       drm_free(dev->vblank_inmodeset, DRM_MEM_VBLANK);
+       drm_free(dev->_vblank_time, DRM_MEM_VBLANK);
+
+       dev->num_crtcs = 0;
+}
+
+int drm_vblank_init(struct drm_device *dev, int num_crtcs)
+{
+       int i;
+
+       callout_init_mp(&dev->vblank_disable_callout);
+#if 0
+       mtx_init(&dev->vbl_lock, "drmvbl", NULL, MTX_DEF);
+#endif
+       lockinit(&dev->vblank_time_lock, "drmvtl", 0, LK_CANRECURSE);
+
+       dev->num_crtcs = num_crtcs;
+
+       dev->_vblank_count = kmalloc(sizeof(atomic_t) * num_crtcs,
+           DRM_MEM_VBLANK, M_WAITOK);
+       dev->vblank_refcount = kmalloc(sizeof(atomic_t) * num_crtcs,
+           DRM_MEM_VBLANK, M_WAITOK);
+       dev->vblank_enabled = kmalloc(num_crtcs * sizeof(int),
+           DRM_MEM_VBLANK, M_WAITOK | M_ZERO);
+       dev->last_vblank = kmalloc(num_crtcs * sizeof(u32),
+           DRM_MEM_VBLANK, M_WAITOK | M_ZERO);
+       dev->last_vblank_wait = kmalloc(num_crtcs * sizeof(u32),
+           DRM_MEM_VBLANK, M_WAITOK | M_ZERO);
+       dev->vblank_inmodeset = kmalloc(num_crtcs * sizeof(int),
+           DRM_MEM_VBLANK, M_WAITOK | M_ZERO);
+       dev->_vblank_time = kmalloc(num_crtcs * DRM_VBLANKTIME_RBSIZE *
+           sizeof(struct timeval), DRM_MEM_VBLANK, M_WAITOK | M_ZERO);
+       DRM_INFO("Supports vblank timestamp caching Rev 1 (10.10.2010).\n");
+
+       /* Driver specific high-precision vblank timestamping supported? */
+       if (dev->driver->get_vblank_timestamp)
+               DRM_INFO("Driver supports precise vblank timestamp query.\n");
+       else
+               DRM_INFO("No driver support for vblank timestamp query.\n");
+
+       /* Zero per-crtc vblank stuff */
+       for (i = 0; i < num_crtcs; i++) {
+               atomic_set(&dev->_vblank_count[i], 0);
+               atomic_set(&dev->vblank_refcount[i], 0);
+       }
+
+       dev->vblank_disable_allowed = 0;
+       return 0;
+}
+
+void
+drm_calc_timestamping_constants(struct drm_crtc *crtc)
+{
+       int64_t linedur_ns = 0, pixeldur_ns = 0, framedur_ns = 0;
+       uint64_t dotclock;
+
+       /* Dot clock in Hz: */
+       dotclock = (uint64_t) 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.
+        */
+       if (crtc->hwmode.flags & DRM_MODE_FLAG_INTERLACE)
+               dotclock *= 2;
+
+       /* Valid dotclock? */
+       if (dotclock > 0) {
+               /* Convert scanline length in pixels and video dot clock to
+                * 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;
+       } else
+               DRM_ERROR("crtc %d: Can't calculate constants, dotclock = 0!\n",
+                         crtc->base.id);
+
+       crtc->pixeldur_ns = pixeldur_ns;
+       crtc->linedur_ns  = linedur_ns;
+       crtc->framedur_ns = framedur_ns;
+
+       DRM_DEBUG("crtc %d: hwmode: htotal %d, vtotal %d, vdisplay %d\n",
+                 crtc->base.id, crtc->hwmode.crtc_htotal,
+                 crtc->hwmode.crtc_vtotal, crtc->hwmode.crtc_vdisplay);
+       DRM_DEBUG("crtc %d: clock %d kHz framedur %d linedur %d, pixeldur %d\n",
+                 crtc->base.id, (int) dotclock/1000, (int) framedur_ns,
+                 (int) linedur_ns, (int) pixeldur_ns);
+}
+
+/**
+ * drm_calc_vbltimestamp_from_scanoutpos - helper routine for kms
+ * drivers. Implements calculation of exact vblank timestamps from
+ * given drm_display_mode timings and current video scanout position
+ * of a crtc. This can be called from within get_vblank_timestamp()
+ * implementation of a kms driver to implement the actual timestamping.
+ *
+ * Should return timestamps conforming to the OML_sync_control OpenML
+ * extension specification. The timestamp corresponds to the end of
+ * the vblank interval, aka start of scanout of topmost-leftmost display
+ * pixel in the following video frame.
+ *
+ * Requires support for optional dev->driver->get_scanout_position()
+ * in kms driver, plus a bit of setup code to provide a drm_display_mode
+ * that corresponds to the true scanout timing.
+ *
+ * The current implementation only handles standard video modes. It
+ * returns as no operation if a doublescan or interlaced video mode is
+ * active. Higher level code is expected to handle this.
+ *
+ * @dev: DRM device.
+ * @crtc: Which crtc's vblank timestamp to retrieve.
+ * @max_error: Desired maximum allowable error in timestamps (nanosecs).
+ *             On return contains true maximum error of timestamp.
+ * @vblank_time: Pointer to struct timeval which should receive the timestamp.
+ * @flags: Flags to pass to driver:
+ *         0 = Default.
+ *         DRM_CALLED_FROM_VBLIRQ = If function is called from vbl irq handler.
+ * @refcrtc: drm_crtc* of crtc which defines scanout timing.
+ *
+ * Returns negative value on error, failure or if not supported in current
+ * video mode:
+ *
+ * -EINVAL   - Invalid crtc.
+ * -EAGAIN   - Temporary unavailable, e.g., called before initial modeset.
+ * -ENOTSUPP - Function not supported in current display mode.
+ * -EIO      - Failed, e.g., due to failed scanout position query.
+ *
+ * Returns or'ed positive status flags on success:
+ *
+ * DRM_VBLANKTIME_SCANOUTPOS_METHOD - Signal this method used for timestamping.
+ * 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)
+{
+       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;
+       bool invbl;
+
+       if (crtc < 0 || crtc >= dev->num_crtcs) {
+               DRM_ERROR("Invalid crtc %d\n", crtc);
+               return -EINVAL;
+       }
+
+       /* Scanout position query not supported? Should not happen. */
+       if (!dev->driver->get_scanout_position) {
+               DRM_ERROR("Called from driver w/o get_scanout_position()!?\n");
+               return -EIO;
+       }
+
+       mode = &refcrtc->hwmode;
+       vtotal = mode->crtc_vtotal;
+       vdisplay = mode->crtc_vdisplay;
+
+       /* Durations of frames, lines, pixels in nanoseconds. */
+       framedur_ns = refcrtc->framedur_ns;
+       linedur_ns  = refcrtc->linedur_ns;
+       pixeldur_ns = refcrtc->pixeldur_ns;
+
+       /* If mode timing undefined, just return as no-op:
+        * Happens during initial modesetting of a crtc.
+        */
+       if (vtotal <= 0 || vdisplay <= 0 || framedur_ns == 0) {
+               DRM_DEBUG("crtc %d: Noop due to uninitialized mode.\n", crtc);
+               return -EAGAIN;
+       }
+
+       /* Get current scanout position with system timestamp.
+        * Repeat query up to DRM_TIMESTAMP_MAXRETRIES times
+        * if single query takes longer than max_error nanoseconds.
+        *
+        * This guarantees a tight bound on maximum error if
+        * code gets preempted or delayed for some reason.
+        */
+       for (i = 0; i < DRM_TIMESTAMP_MAXRETRIES; i++) {
+               /* Disable preemption to make it very likely to
+                * succeed in the first iteration.
+                */
+               crit_enter();
+
+               /* Get system timestamp before query. */
+               getmicrouptime(&stime);
+
+               /* Get vertical and horizontal scanout pos. vpos, hpos. */
+               vbl_status = dev->driver->get_scanout_position(dev, crtc, &vpos, &hpos);
+
+               /* Get system timestamp after query. */
+               getmicrouptime(&raw_time);
+
+               crit_exit();
+
+               /* Return as no-op if scanout query unsupported or failed. */
+               if (!(vbl_status & DRM_SCANOUTPOS_VALID)) {
+                       DRM_DEBUG("crtc %d : scanoutpos query failed [%d].\n",
+                                 crtc, vbl_status);
+                       return -EIO;
+               }
+
+               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)
+                       break;
+       }
+
+       /* Noisy system timing? */
+       if (i == DRM_TIMESTAMP_MAXRETRIES) {
+               DRM_DEBUG("crtc %d: Noisy timestamp %d us > %d us [%d reps].\n",
+                         crtc, (int) duration_ns/1000, *max_error/1000, i);
+       }
+
+       /* Return upper bound of timestamp precision error. */
+       *max_error = (int) duration_ns;
+
+       /* Check if in vblank area:
+        * vpos is >=0 in video scanout area, but negative
+        * within vblank area, counting down the number of lines until
+        * start of scanout.
+        */
+       invbl = vbl_status & DRM_SCANOUTPOS_INVBL;
+
+       /* Convert scanout position into elapsed time at raw_time query
+        * 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;
+
+       /* Is vpos outside nominal vblank area, but less than
+        * 1/100 of a frame height away from start of vblank?
+        * If so, assume this isn't a massively delayed vblank
+        * interrupt, but a vblank interrupt that fired a few
+        * microseconds before true start of vblank. Compensate
+        * by adding a full frame duration to the final timestamp.
+        * Happens, e.g., on ATI R500, R600.
+        *
+        * We only do this if DRM_CALLED_FROM_VBLIRQ.
+        */
+       if ((flags & DRM_CALLED_FROM_VBLIRQ) && !invbl &&
+           ((vdisplay - vpos) < vtotal / 100)) {
+               delta_ns = delta_ns - framedur_ns;
+
+               /* Signal this correction as "applied". */
+               vbl_status |= 0x8;
+       }
+
+       /* Subtract time delta from raw timestamp to get final
+        * vblank_time timestamp for end of vblank.
+        */
+       *vblank_time = ns_to_timeval(timeval_to_ns(&raw_time) - delta_ns);
+
+       DRM_DEBUG("crtc %d : v %d p(%d,%d)@ %jd.%jd -> %jd.%jd [e %d us, %d rep]\n",
+                 crtc, (int)vbl_status, hpos, vpos, (uintmax_t)raw_time.tv_sec,
+                 (uintmax_t)raw_time.tv_usec, (uintmax_t)vblank_time->tv_sec,
+                 (uintmax_t)vblank_time->tv_usec, (int)duration_ns/1000, i);
+
+       vbl_status = DRM_VBLANKTIME_SCANOUTPOS_METHOD;
+       if (invbl)
+               vbl_status |= DRM_VBLANKTIME_INVBL;
+
+       return vbl_status;
+}
+
+/**
+ * drm_get_last_vbltimestamp - retrieve raw timestamp for the most recent
+ * vblank interval.
+ *
+ * @dev: DRM device
+ * @crtc: which crtc's vblank timestamp to retrieve
+ * @tvblank: Pointer to target struct timeval which should receive the timestamp
+ * @flags: Flags to pass to driver:
+ *         0 = Default.
+ *         DRM_CALLED_FROM_VBLIRQ = If function is called from vbl irq handler.
+ *
+ * Fetches the system timestamp corresponding to the time of the most recent
+ * vblank interval on specified crtc. May call into kms-driver to
+ * compute the timestamp with a high-precision GPU specific method.
+ *
+ * Returns zero if timestamp originates from uncorrected do_gettimeofday()
+ * call, i.e., it isn't very precisely locked to the true vblank.
+ *
+ * Returns non-zero if timestamp is considered to be very precise.
+ */
+u32 drm_get_last_vbltimestamp(struct drm_device *dev, int crtc,
+                             struct timeval *tvblank, unsigned flags)
+{
+       int ret = 0;
+
+       /* Define requested maximum error on timestamps (nanoseconds). */
+       int max_error = (int) drm_timestamp_precision * 1000;
+
+       /* Query driver if possible and precision timestamping enabled. */
+       if (dev->driver->get_vblank_timestamp && (max_error > 0)) {
+               ret = dev->driver->get_vblank_timestamp(dev, crtc, &max_error,
+                                                       tvblank, flags);
+               if (ret > 0)
+                       return (u32) ret;
+       }
+
+       /* GPU high precision timestamp query unsupported or failed.
+        * Return gettimeofday timestamp as best estimate.
+        */
+       microtime(tvblank);
+
+       return 0;
+}
+
+/**
+ * drm_vblank_count - retrieve "cooked" vblank counter value
+ * @dev: DRM device
+ * @crtc: which counter to retrieve
+ *
+ * Fetches the "cooked" vblank count value that represents the number of
+ * vblank events since the system was booted, including lost events due to
+ * modesetting activity.
+ */
 u32 drm_vblank_count(struct drm_device *dev, int crtc)
 {
-       return atomic_load_acq_32(&dev->vblank[crtc].count);
+       return atomic_read(&dev->_vblank_count[crtc]);
 }
 
+/**
+ * drm_vblank_count_and_time - retrieve "cooked" vblank counter value
+ * and the system timestamp corresponding to that vblank counter value.
+ *
+ * @dev: DRM device
+ * @crtc: which counter to retrieve
+ * @vblanktime: Pointer to struct timeval to receive the vblank timestamp.
+ *
+ * Fetches the "cooked" vblank count value that represents the number of
+ * vblank events since the system was booted, including lost events due to
+ * modesetting activity. Returns corresponding system timestamp of the time
+ * of the vblank interval that corresponds to the current value vblank counter
+ * value.
+ */
+u32 drm_vblank_count_and_time(struct drm_device *dev, int crtc,
+                             struct timeval *vblanktime)
+{
+       u32 cur_vblank;
+
+       /* Read timestamp from slot of _vblank_time ringbuffer
+        * that corresponds to current vblank count. Retry if
+        * count has incremented during readout. This works like
+        * a seqlock.
+        */
+       do {
+               cur_vblank = atomic_read(&dev->_vblank_count[crtc]);
+               *vblanktime = vblanktimestamp(dev, crtc, cur_vblank);
+               cpu_lfence();
+       } while (cur_vblank != atomic_read(&dev->_vblank_count[crtc]));
+
+       return cur_vblank;
+}
+
+/**
+ * drm_update_vblank_count - update the master vblank counter
+ * @dev: DRM device
+ * @crtc: counter to update
+ *
+ * Call back into the driver to update the appropriate vblank counter
+ * (specified by @crtc).  Deal with wraparound, if it occurred, and
+ * update the last read value so we can deal with wraparound on the next
+ * call if necessary.
+ *
+ * Only necessary when going from off->on, to account for frames we
+ * didn't get an interrupt for.
+ *
+ * Note: caller must hold dev->vbl_lock since this reads & writes
+ * device vblank fields.
+ */
 static void drm_update_vblank_count(struct drm_device *dev, int crtc)
 {
-       u32 cur_vblank, diff;
+       u32 cur_vblank, diff, tslot, rc;
+       struct timeval t_vblank;
 
        /*
         * Interrupts were disabled prior to this call, so deal with counter
@@ -270,68 +719,202 @@ static void drm_update_vblank_count(struct drm_device *dev, int crtc)
         * NOTE!  It's possible we lost a full dev->max_vblank_count events
         * here if the register is small or we had vblank interrupts off for
         * a long time.
+        *
+        * We repeat the hardware vblank counter & timestamp query until
+        * we get consistent results. This to prevent races between gpu
+        * updating its hardware counter while we are retrieving the
+        * corresponding vblank timestamp.
         */
-       cur_vblank = dev->driver->get_vblank_counter(dev, crtc);
-       diff = cur_vblank - dev->vblank[crtc].last;
-       if (cur_vblank < dev->vblank[crtc].last) {
+       do {
+               cur_vblank = dev->driver->get_vblank_counter(dev, crtc);
+               rc = drm_get_last_vbltimestamp(dev, crtc, &t_vblank, 0);
+       } while (cur_vblank != dev->driver->get_vblank_counter(dev, crtc));
+
+       /* Deal with counter wrap */
+       diff = cur_vblank - dev->last_vblank[crtc];
+       if (cur_vblank < dev->last_vblank[crtc]) {
                diff += dev->max_vblank_count;
 
-               DRM_DEBUG("vblank[%d].last=0x%x, cur_vblank=0x%x => diff=0x%x\n",
-                   crtc, dev->vblank[crtc].last, cur_vblank, diff);
+               DRM_DEBUG("last_vblank[%d]=0x%x, cur_vblank=0x%x => diff=0x%x\n",
+                         crtc, dev->last_vblank[crtc], cur_vblank, diff);
        }
 
        DRM_DEBUG("enabling vblank interrupts on crtc %d, missed %d\n",
-           crtc, diff);
+                 crtc, diff);
+
+       /* Reinitialize corresponding vblank timestamp if high-precision query
+        * available. Skip this step if query unsupported or failed. Will
+        * reinitialize delayed at next vblank interrupt in that case.
+        */
+       if (rc) {
+               tslot = atomic_read(&dev->_vblank_count[crtc]) + diff;
+               vblanktimestamp(dev, crtc, tslot) = t_vblank;
+       }
 
-       atomic_add_rel_32(&dev->vblank[crtc].count, diff);
+       atomic_add(diff, &dev->_vblank_count[crtc]);
 }
 
+/**
+ * drm_vblank_get - get a reference count on vblank events
+ * @dev: DRM device
+ * @crtc: which CRTC to own
+ *
+ * Acquire a reference count on vblank events to avoid having them disabled
+ * while in use.
+ *
+ * RETURNS
+ * Zero on success, nonzero on failure.
+ */
 int drm_vblank_get(struct drm_device *dev, int crtc)
 {
        int ret = 0;
 
-       /* Make sure that we are called with the lock held */
-       KKASSERT(lockstatus(&dev->vbl_lock, curthread) != 0);
-
+       lockmgr(&dev->vbl_lock, LK_EXCLUSIVE);
        /* Going from 0->1 means we have to enable interrupts again */
-       if (++dev->vblank[crtc].refcount == 1 &&
-           !dev->vblank[crtc].enabled) {
-               ret = dev->driver->enable_vblank(dev, crtc);
-               DRM_DEBUG("enabling vblank on crtc %d, ret: %d\n", crtc, ret);
-               if (ret)
-                       --dev->vblank[crtc].refcount;
-               else {
-                       dev->vblank[crtc].enabled = 1;
-                       drm_update_vblank_count(dev, crtc);
+       if (atomic_fetchadd_int(&dev->vblank_refcount[crtc], 1) == 0) {
+               lockmgr(&dev->vblank_time_lock, LK_EXCLUSIVE);
+               if (!dev->vblank_enabled[crtc]) {
+                       /* Enable vblank irqs under vblank_time_lock protection.
+                        * All vblank count & timestamp updates are held off
+                        * until we are done reinitializing master counter and
+                        * timestamps. Filtercode in drm_handle_vblank() will
+                        * prevent double-accounting of same vblank interval.
+                        */
+                       ret = -dev->driver->enable_vblank(dev, crtc);
+                       DRM_DEBUG("enabling vblank on crtc %d, ret: %d\n",
+                                 crtc, ret);
+                       if (ret)
+                               atomic_dec(&dev->vblank_refcount[crtc]);
+                       else {
+                               dev->vblank_enabled[crtc] = 1;
+                               drm_update_vblank_count(dev, crtc);
+                       }
+               }
+               lockmgr(&dev->vblank_time_lock, LK_RELEASE);
+       } else {
+               if (!dev->vblank_enabled[crtc]) {
+                       atomic_dec(&dev->vblank_refcount[crtc]);
+                       ret = EINVAL;
                }
        }
-
-       if (dev->vblank[crtc].enabled)
-               dev->vblank[crtc].last =
-                   dev->driver->get_vblank_counter(dev, crtc);
+       lockmgr(&dev->vbl_lock, LK_RELEASE);
 
        return ret;
 }
 
+/**
+ * drm_vblank_put - give up ownership of vblank events
+ * @dev: DRM device
+ * @crtc: which counter to give up
+ *
+ * Release ownership of a given vblank counter, turning off interrupts
+ * if possible. Disable interrupts after drm_vblank_offdelay milliseconds.
+ */
 void drm_vblank_put(struct drm_device *dev, int crtc)
 {
-       /* Make sure that we are called with the lock held */
-       KKASSERT(lockstatus(&dev->vbl_lock, curthread) != 0);
-
-       KASSERT(dev->vblank[crtc].refcount > 0,
-           ("invalid refcount"));
+       KASSERT(atomic_read(&dev->vblank_refcount[crtc]) != 0,
+           ("Too many drm_vblank_put for crtc %d", crtc));
 
        /* Last user schedules interrupt disable */
-       if (--dev->vblank[crtc].refcount == 0)
-           callout_reset(&dev->vblank_disable_timer, 5 * DRM_HZ,
-               (timeout_t *)vblank_disable_fn, (void *)dev);
+       if (atomic_fetchadd_int(&dev->vblank_refcount[crtc], -1) == 1 &&
+           (drm_vblank_offdelay > 0))
+               callout_reset(&dev->vblank_disable_callout,
+                   (drm_vblank_offdelay * DRM_HZ) / 1000,
+                   vblank_disable_fn, dev);
+}
+
+void drm_vblank_off(struct drm_device *dev, int crtc)
+{
+       struct drm_pending_vblank_event *e, *t;
+       struct timeval now;
+       unsigned int seq;
+
+       lockmgr(&dev->vbl_lock, LK_EXCLUSIVE);
+       vblank_disable_and_save(dev, crtc);
+       lockmgr(&dev->event_lock, LK_EXCLUSIVE);
+       wakeup(&dev->_vblank_count[crtc]);
+
+       /* Send any queued vblank events, lest the natives grow disquiet */
+       seq = drm_vblank_count_and_time(dev, crtc, &now);
+       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;
+               drm_vblank_put(dev, e->pipe);
+               list_move_tail(&e->base.link, &e->base.file_priv->event_list);
+               drm_event_wakeup(&e->base);
+       }
+
+       lockmgr(&dev->event_lock, LK_RELEASE);
+       lockmgr(&dev->vbl_lock, LK_RELEASE);
+}
+
+/**
+ * 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.
+ */
+void drm_vblank_pre_modeset(struct drm_device *dev, int crtc)
+{
+       /* vblank is not initialized (IRQ not installed ?) */
+       if (!dev->num_crtcs)
+               return;
+       /*
+        * To avoid all the problems that might happen if interrupts
+        * were enabled/disabled around or between these calls, we just
+        * have the kernel take a reference on the CRTC (just once though
+        * to avoid corrupting the count if multiple, mismatch calls occur),
+        * so that interrupts remain enabled in the interim.
+        */
+       if (!dev->vblank_inmodeset[crtc]) {
+               dev->vblank_inmodeset[crtc] = 0x1;
+               if (drm_vblank_get(dev, crtc) == 0)
+                       dev->vblank_inmodeset[crtc] |= 0x2;
+       }
 }
 
+void drm_vblank_post_modeset(struct drm_device *dev, int crtc)
+{
+
+       if (dev->vblank_inmodeset[crtc]) {
+               lockmgr(&dev->vbl_lock, LK_EXCLUSIVE);
+               dev->vblank_disable_allowed = 1;
+               lockmgr(&dev->vbl_lock, LK_RELEASE);
+
+               if (dev->vblank_inmodeset[crtc] & 0x2)
+                       drm_vblank_put(dev, crtc);
+
+               dev->vblank_inmodeset[crtc] = 0;
+       }
+}
+
+/**
+ * drm_modeset_ctl - handle vblank event counter changes across mode switch
+ * @DRM_IOCTL_ARGS: standard ioctl arguments
+ *
+ * Applications should call the %_DRM_PRE_MODESET and %_DRM_POST_MODESET
+ * ioctls around modesetting so that any lost vblank events are accounted for.
+ *
+ * Generally the counter will reset across mode sets.  If interrupts are
+ * enabled around this call, we don't have to do anything since the counter
+ * will have already been incremented.
+ */
 int drm_modeset_ctl(struct drm_device *dev, void *data,
                    struct drm_file *file_priv)
 {
        struct drm_modeset_ctl *modeset = data;
-       int crtc, ret = 0;
+       int ret = 0;
+       unsigned int crtc;
 
        /* If drm_vblank_init() hasn't been called yet, just no-op */
        if (!dev->num_crtcs)
@@ -339,41 +922,19 @@ int drm_modeset_ctl(struct drm_device *dev, void *data,
 
        crtc = modeset->crtc;
        if (crtc >= dev->num_crtcs) {
-               ret = EINVAL;
+               ret = -EINVAL;
                goto out;
        }
 
-       /*
-        * To avoid all the problems that might happen if interrupts
-        * were enabled/disabled around or between these calls, we just
-        * have the kernel take a reference on the CRTC (just once though
-        * to avoid corrupting the count if multiple, mismatch calls occur),
-        * so that interrupts remain enabled in the interim.
-        */
        switch (modeset->cmd) {
        case _DRM_PRE_MODESET:
-               DRM_DEBUG("pre-modeset, crtc %d\n", crtc);
-               DRM_SPINLOCK(&dev->vbl_lock);
-               if (!dev->vblank[crtc].inmodeset) {
-                       dev->vblank[crtc].inmodeset = 0x1;
-                       if (drm_vblank_get(dev, crtc) == 0)
-                               dev->vblank[crtc].inmodeset |= 0x2;
-               }
-               DRM_SPINUNLOCK(&dev->vbl_lock);
+               drm_vblank_pre_modeset(dev, crtc);
                break;
        case _DRM_POST_MODESET:
-               DRM_DEBUG("post-modeset, crtc %d\n", crtc);
-               DRM_SPINLOCK(&dev->vbl_lock);
-               if (dev->vblank[crtc].inmodeset) {
-                       if (dev->vblank[crtc].inmodeset & 0x2)
-                               drm_vblank_put(dev, crtc);
-                       dev->vblank[crtc].inmodeset = 0;
-               }
-               dev->vblank_disable_allowed = 1;
-               DRM_SPINUNLOCK(&dev->vbl_lock);
+               drm_vblank_post_modeset(dev, crtc);
                break;
        default:
-               ret = EINVAL;
+               ret = -EINVAL;
                break;
        }
 
@@ -381,35 +942,128 @@ out:
        return ret;
 }
 
-int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_priv)
+static void
+drm_vblank_event_destroy(struct drm_pending_event *e)
+{
+
+       drm_free(e, DRM_MEM_VBLANK);
+}
+
+static int drm_queue_vblank_event(struct drm_device *dev, int pipe,
+                                 union drm_wait_vblank *vblwait,
+                                 struct drm_file *file_priv)
+{
+       struct drm_pending_vblank_event *e;
+       struct timeval now;
+       unsigned int seq;
+       int ret;
+
+       e = kmalloc(sizeof *e, DRM_MEM_VBLANK, M_WAITOK | M_ZERO);
+
+       e->pipe = pipe;
+       e->base.pid = curproc->p_pid;
+       e->event.base.type = DRM_EVENT_VBLANK;
+       e->event.base.length = sizeof e->event;
+       e->event.user_data = vblwait->request.signal;
+       e->base.event = &e->event.base;
+       e->base.file_priv = file_priv;
+       e->base.destroy = drm_vblank_event_destroy;
+
+       lockmgr(&dev->event_lock, LK_EXCLUSIVE);
+
+       if (file_priv->event_space < sizeof e->event) {
+               ret = EBUSY;
+               goto err_unlock;
+       }
+
+       file_priv->event_space -= sizeof e->event;
+       seq = drm_vblank_count_and_time(dev, pipe, &now);
+
+       if ((vblwait->request.type & _DRM_VBLANK_NEXTONMISS) &&
+           (seq - vblwait->request.sequence) <= (1 << 23)) {
+               vblwait->request.sequence = seq + 1;
+               vblwait->reply.sequence = vblwait->request.sequence;
+       }
+
+       DRM_DEBUG("event on vblank count %d, current %d, crtc %d\n",
+                 vblwait->request.sequence, seq, 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);
+               vblwait->reply.sequence = seq;
+       } else {
+               /* drm_handle_vblank_events will call drm_vblank_put */
+               list_add_tail(&e->base.link, &dev->vblank_event_list);
+               vblwait->reply.sequence = vblwait->request.sequence;
+       }
+
+       lockmgr(&dev->event_lock, LK_RELEASE);
+
+       return 0;
+
+err_unlock:
+       lockmgr(&dev->event_lock, LK_RELEASE);
+       drm_free(e, DRM_MEM_VBLANK);
+       drm_vblank_put(dev, pipe);
+       return ret;
+}
+
+/**
+ * Wait for VBLANK.
+ *
+ * \param inode device inode.
+ * \param file_priv DRM file private.
+ * \param cmd command.
+ * \param data user argument, pointing to a drm_wait_vblank structure.
+ * \return zero on success or a negative number on failure.
+ *
+ * This function enables the vblank interrupt on the pipe requested, then
+ * sleeps waiting for the requested sequence number to occur, and drops
+ * the vblank interrupt refcount afterwards. (vblank irq disable follows that
+ * after a timeout with no further vblank waits scheduled).
+ */
+int drm_wait_vblank(struct drm_device *dev, void *data,
+                   struct drm_file *file_priv)
 {
        union drm_wait_vblank *vblwait = data;
-       unsigned int flags, seq, crtc;
        int ret = 0;
+       unsigned int flags, seq, crtc, high_crtc;
 
-       if (!dev->irq_enabled)
-               return EINVAL;
+       if (/*(!drm_dev_to_irq(dev)) || */(!dev->irq_enabled))
+               return (EINVAL);
+
+       if (vblwait->request.type & _DRM_VBLANK_SIGNAL)
+               return (EINVAL);
 
        if (vblwait->request.type &
-           ~(_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK)) {
+           ~(_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK |
+             _DRM_VBLANK_HIGH_CRTC_MASK)) {
                DRM_ERROR("Unsupported type value 0x%x, supported mask 0x%x\n",
-                   vblwait->request.type,
-                   (_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK));
-               return EINVAL;
+                         vblwait->request.type,
+                         (_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK |
+                          _DRM_VBLANK_HIGH_CRTC_MASK));
+               return (EINVAL);
        }
 
        flags = vblwait->request.type & _DRM_VBLANK_FLAGS_MASK;
-       crtc = flags & _DRM_VBLANK_SECONDARY ? 1 : 0;
-
+       high_crtc = (vblwait->request.type & _DRM_VBLANK_HIGH_CRTC_MASK);
+       if (high_crtc)
+               crtc = high_crtc >> _DRM_VBLANK_HIGH_CRTC_SHIFT;
+       else
+               crtc = flags & _DRM_VBLANK_SECONDARY ? 1 : 0;
        if (crtc >= dev->num_crtcs)
-               return EINVAL;
+               return (EINVAL);
 
-       DRM_SPINLOCK(&dev->vbl_lock);
        ret = drm_vblank_get(dev, crtc);
-       DRM_SPINUNLOCK(&dev->vbl_lock);
        if (ret) {
-               DRM_ERROR("failed to acquire vblank counter, %d\n", ret);
-               return ret;
+               DRM_DEBUG("failed to acquire vblank counter, %d\n", ret);
+               return (ret);
        }
        seq = drm_vblank_count(dev, crtc);
 
@@ -420,59 +1074,148 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_pr
        case _DRM_VBLANK_ABSOLUTE:
                break;
        default:
-               ret = EINVAL;
+               ret = (EINVAL);
                goto done;
        }
 
+       if (flags & _DRM_VBLANK_EVENT) {
+               /* must hold on to the vblank ref until the event fires
+                * drm_vblank_put will be called asynchronously
+                */
+               return drm_queue_vblank_event(dev, crtc, vblwait, file_priv);
+       }
+
        if ((flags & _DRM_VBLANK_NEXTONMISS) &&
            (seq - vblwait->request.sequence) <= (1<<23)) {
                vblwait->request.sequence = seq + 1;
        }
 
-       if (flags & _DRM_VBLANK_SIGNAL) {
-               /* There have never been any consumers */
-               ret = EINVAL;
-       } else {
-               DRM_DEBUG("waiting on vblank count %d, crtc %d\n",
-                   vblwait->request.sequence, crtc);
-               for ( ret = 0 ; !ret && !(((drm_vblank_count(dev, crtc) -
-                   vblwait->request.sequence) <= (1 << 23)) ||
-                   !dev->irq_enabled) ; ) {
-                       lwkt_serialize_enter(&dev->irq_lock);
-                       if (!(((drm_vblank_count(dev, crtc) -
-                           vblwait->request.sequence) <= (1 << 23)) ||
-                           !dev->irq_enabled))
-                               ret = zsleep(&dev->vblank[crtc].queue,
-                                   &dev->irq_lock, PCATCH, "vblwtq",
-                                   DRM_HZ);
-                       lwkt_serialize_exit(&dev->irq_lock);
-               }
-
-               if (ret != EINTR && ret != ERESTART) {
-                       struct timeval now;
-
-                       microtime(&now);
-                       vblwait->reply.tval_sec = now.tv_sec;
-                       vblwait->reply.tval_usec = now.tv_usec;
-                       vblwait->reply.sequence = drm_vblank_count(dev, crtc);
-                       DRM_DEBUG("returning %d to client, irq_enabled %d\n",
-                           vblwait->reply.sequence, dev->irq_enabled);
-               } else {
-                       DRM_DEBUG("vblank wait interrupted by signal\n");
-               }
+       dev->last_vblank_wait[crtc] = vblwait->request.sequence;
+       lockmgr(&dev->vblank_time_lock, LK_EXCLUSIVE);
+       while (((drm_vblank_count(dev, crtc) - vblwait->request.sequence) >
+           (1 << 23)) && dev->irq_enabled) {
+               /*
+                * The wakeups from the drm_irq_uninstall() and
+                * drm_vblank_off() may be lost there since vbl_lock
+                * is not held.  Then, the timeout will wake us; the 3
+                * seconds delay should not be a problem for
+                * application when crtc is disabled or irq
+                * uninstalled anyway.
+                */
+               ret = lksleep(&dev->_vblank_count[crtc], &dev->vblank_time_lock,
+                   PCATCH, "drmvbl", 3 * hz);
+               if (ret != 0)
+                       break;
+       }
+       lockmgr(&dev->vblank_time_lock, LK_RELEASE);
+       if (ret != EINTR) {
+               struct timeval now;
+               long reply_seq;
+
+               reply_seq = drm_vblank_count_and_time(dev, crtc, &now);
+               vblwait->reply.sequence = reply_seq;
+               vblwait->reply.tval_sec = now.tv_sec;
+               vblwait->reply.tval_usec = now.tv_usec;
        }
 
 done:
-       DRM_SPINLOCK(&dev->vbl_lock);
        drm_vblank_put(dev, crtc);
-       DRM_SPINUNLOCK(&dev->vbl_lock);
-
        return ret;
 }
 
-void drm_handle_vblank(struct drm_device *dev, int crtc)
+void drm_handle_vblank_events(struct drm_device *dev, int crtc)
 {
-       atomic_add_rel_32(&dev->vblank[crtc].count, 1);
-       DRM_WAKEUP(&dev->vblank[crtc].queue);
+       struct drm_pending_vblank_event *e, *t;
+       struct timeval now;
+       unsigned int seq;
+
+       seq = drm_vblank_count_and_time(dev, crtc, &now);
+
+       lockmgr(&dev->event_lock, LK_EXCLUSIVE);
+
+       list_for_each_entry_safe(e, t, &dev->vblank_event_list, base.link) {
+               if (e->pipe != crtc)
+                       continue;
+               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_vblank_put(dev, e->pipe);
+               list_move_tail(&e->base.link, &e->base.file_priv->event_list);
+               drm_event_wakeup(&e->base);
+       }
+
+       lockmgr(&dev->event_lock, LK_RELEASE);
 }
 
+/**
+ * drm_handle_vblank - handle a vblank event
+ * @dev: DRM device
+ * @crtc: where this event occurred
+ *
+ * Drivers should call this routine in their vblank interrupt handlers to
+ * update the vblank counter and send any signals that may be pending.
+ */
+bool drm_handle_vblank(struct drm_device *dev, int crtc)
+{
+       u32 vblcount;
+       int64_t diff_ns;
+       struct timeval tvblank;
+
+       if (!dev->num_crtcs)
+               return false;
+
+       /* Need timestamp lock to prevent concurrent execution with
+        * vblank enable/disable, as this would cause inconsistent
+        * or corrupted timestamps and vblank counts.
+        */
+       lockmgr(&dev->vblank_time_lock, LK_EXCLUSIVE);
+
+       /* Vblank irq handling disabled. Nothing to do. */
+       if (!dev->vblank_enabled[crtc]) {
+               lockmgr(&dev->vblank_time_lock, LK_RELEASE);
+               return false;
+       }
+
+       /* Fetch corresponding timestamp for this vblank interval from
+        * driver and store it in proper slot of timestamp ringbuffer.
+        */
+
+       /* Get current timestamp and count. */
+       vblcount = atomic_read(&dev->_vblank_count[crtc]);
+       drm_get_last_vbltimestamp(dev, crtc, &tvblank, DRM_CALLED_FROM_VBLIRQ);
+
+       /* Compute time difference to timestamp of last vblank */
+       diff_ns = timeval_to_ns(&tvblank) -
+                 timeval_to_ns(&vblanktimestamp(dev, crtc, vblcount));
+
+       /* Update vblank timestamp and count if at least
+        * DRM_REDUNDANT_VBLIRQ_THRESH_NS nanoseconds
+        * difference between last stored timestamp and current
+        * timestamp. A smaller difference means basically
+        * identical timestamps. Happens if this vblank has
+        * been already processed and this is a redundant call,
+        * e.g., due to spurious vblank interrupts. We need to
+        * ignore those for accounting.
+        */
+       if (abs64(diff_ns) > DRM_REDUNDANT_VBLIRQ_THRESH_NS) {
+               /* Store new timestamp in ringbuffer. */
+               vblanktimestamp(dev, crtc, vblcount + 1) = tvblank;
+
+               /* Increment cooked vblank count. This also atomically commits
+                * the timestamp computed above.
+                */
+               atomic_inc(&dev->_vblank_count[crtc]);
+       } else {
+               DRM_DEBUG("crtc %d: Redundant vblirq ignored. diff_ns = %d\n",
+                         crtc, (int) diff_ns);
+       }
+
+       wakeup(&dev->_vblank_count[crtc]);
+       drm_handle_vblank_events(dev, crtc);
+
+       lockmgr(&dev->vblank_time_lock, LK_RELEASE);
+       return true;
+}
index e5a478a..86fdfe7 100644 (file)
  * Authors:
  *    Eric Anholt <anholt@FreeBSD.org>
  *
+ * $FreeBSD: src/sys/dev/drm2/drm_linux_list.h,v 1.1 2012/05/22 11:07:44 kib Exp $
  */
 
-#include <sys/cdefs.h>
-
 #ifndef _DRM_LINUX_LIST_H_
 #define _DRM_LINUX_LIST_H_
 
@@ -47,8 +46,13 @@ INIT_LIST_HEAD(struct list_head *head) {
        (head)->prev = head;
 }
 
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define DRM_LIST_HEAD(name) \
+       struct list_head name = LIST_HEAD_INIT(name)
+
 static __inline__ int
-list_empty(struct list_head *head) {
+list_empty(const struct list_head *head) {
        return (head)->next == head;
 }
 
@@ -74,6 +78,28 @@ list_del(struct list_head *entry) {
        (entry)->prev->next = (entry)->next;
 }
 
+static inline void list_replace(struct list_head *old,
+                               struct list_head *new)
+{
+       new->next = old->next;
+       new->next->prev = new;
+       new->prev = old->prev;
+       new->prev->next = new;
+}
+
+static inline void list_move(struct list_head *list, struct list_head *head)
+{
+       list_del(list);
+       list_add(list, head);
+}
+
+static inline void list_move_tail(struct list_head *list,
+    struct list_head *head)
+{
+       list_del(list);
+       list_add_tail(list, head);
+}
+
 static __inline__ void
 list_del_init(struct list_head *entry) {
        (entry)->next->prev = (entry)->prev;
@@ -93,6 +119,16 @@ list_del_init(struct list_head *entry) {
        entry != head;                                          \
        entry = temp, temp = entry->next)
 
+#define list_for_each_entry(pos, head, member)                         \
+    for (pos = list_entry((head)->next, __typeof(*pos), member);       \
+       &pos->member != (head);                                         \
+       pos = list_entry(pos->member.next, __typeof(*pos), member))
+
+#define list_for_each_entry_continue_reverse(pos, head, member)         \
+        for (pos = list_entry(pos->member.prev, __typeof(*pos), member);  \
+             &pos->member != (head);                                   \
+             pos = list_entry(pos->member.prev, __typeof(*pos), member))
+
 /**
  * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
  * @pos:        the type * to use as a loop cursor.
@@ -106,4 +142,34 @@ list_del_init(struct list_head *entry) {
            &pos->member != (head);                                     \
            pos = n, n = list_entry(n->member.next, __typeof(*n), member))
 
+#define list_first_entry(ptr, type, member) \
+       list_entry((ptr)->next, type, member)
+
+
+static inline void
+__list_splice(const struct list_head *list, struct list_head *prev,
+    struct list_head *next)
+{
+       struct list_head *first = list->next;
+       struct list_head *last = list->prev;
+
+       first->prev = prev;
+       prev->next = first;
+
+       last->next = next;
+       next->prev = last;
+}
+
+static inline void
+list_splice(const struct list_head *list, struct list_head *head)
+{
+       if (list_empty(list))
+               return;
+
+       __list_splice(list, head, head->next);
+}
+
+void drm_list_sort(void *priv, struct list_head *head, int (*cmp)(void *priv,
+    struct list_head *a, struct list_head *b));
+
 #endif /* _DRM_LINUX_LIST_H_ */
similarity index 95%
rename from sys/dev/drm2/drm_linux_list_sort.c
rename to sys/dev/drm/drm_linux_list_sort.c
index 4d64da8..855a8eb 100644 (file)
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/sys/dev/drm2/drm_linux_list_sort.c,v 1.1 2012/05/22 11:07:44 kib Exp $
  */
 
-#include <dev/drm2/drmP.h>
-/* $FreeBSD: src/sys/dev/drm2/drm_linux_list_sort.c,v 1.1 2012/05/22 11:07:44 kib Exp $ */
+#include <dev/drm/drmP.h>
 
 struct drm_list_sort_thunk {
        int (*cmp)(void *, struct list_head *, struct list_head *);
index 4e71c21..89707bc 100644 (file)
@@ -26,6 +26,7 @@
  *    Rickard E. (Rik) Faith <faith@valinux.com>
  *    Gareth Hughes <gareth@valinux.com>
  *
+ * $FreeBSD: src/sys/dev/drm2/drm_lock.c,v 1.1 2012/05/22 11:07:44 kib Exp $
  */
 
 /** @file drm_lock.c
@@ -68,7 +69,7 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv)
            lock->context < 0)
                return EINVAL;
 
-       DRM_LOCK();
+       DRM_LOCK(dev);
        for (;;) {
                if (drm_lock_take(&dev->lock, lock->context)) {
                        dev->lock.file_priv = file_priv;
@@ -78,15 +79,12 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv)
                }
 
                /* Contention */
-               tsleep_interlock((void *)&dev->lock.lock_queue, PCATCH);
-               DRM_UNLOCK();
-               ret = tsleep((void *)&dev->lock.lock_queue,
-                            PCATCH | PINTERLOCKED, "drmlk2", 0);
-               DRM_LOCK();
+               ret = DRM_LOCK_SLEEP(dev, &dev->lock.lock_queue,
+                   PCATCH, "drmlk2", 0);
                if (ret != 0)
                        break;
        }
-       DRM_UNLOCK();
+       DRM_UNLOCK(dev);
 
        if (ret == ERESTART)
                DRM_DEBUG("restarting syscall\n");
@@ -122,13 +120,13 @@ int drm_unlock(struct drm_device *dev, void *data, struct drm_file *file_priv)
 
        atomic_inc(&dev->counts[_DRM_STAT_UNLOCKS]);
 
-       DRM_LOCK();
+       DRM_LOCK(dev);
        drm_lock_transfer(&dev->lock, DRM_KERNEL_CONTEXT);
 
        if (drm_lock_free(&dev->lock, DRM_KERNEL_CONTEXT)) {
                DRM_ERROR("\n");
        }
-       DRM_UNLOCK();
+       DRM_UNLOCK(dev);
 
        return 0;
 }
index 199059b..394c517 100644 (file)
@@ -1,7 +1,11 @@
 /*-
  *Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
  * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
- * All Rights Reserved.
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * Portions of this software were developed by Konstantin Belousov
+ * under sponsorship from the FreeBSD Foundation.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -26,6 +30,7 @@
  *    Rickard E. (Rik) Faith <faith@valinux.com>
  *    Gareth Hughes <gareth@valinux.com>
  *
+ * $FreeBSD: src/sys/dev/drm2/drm_memory.c,v 1.1 2012/05/22 11:07:44 kib Exp $
  */
 
 /** @file drm_memory.c
@@ -36,7 +41,7 @@
  * has been stripped out for now.
  */
 
-#include "dev/drm/drmP.h"
+#include <dev/drm/drmP.h>
 
 MALLOC_DEFINE(DRM_MEM_DMA, "drm_dma", "DRM DMA Data Structures");
 MALLOC_DEFINE(DRM_MEM_SAREA, "drm_sarea", "DRM SAREA Data Structures");
@@ -55,6 +60,7 @@ 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)
 {
@@ -67,7 +73,6 @@ void drm_mem_uninit(void)
 void *drm_ioremap_wc(struct drm_device *dev, drm_local_map_t *map)
 {
        return pmap_mapdev_attr(map->offset, map->size, VM_MEMATTR_WRITE_COMBINING);
-       return pmap_mapdev(map->offset, map->size);
 }
 
 void *drm_ioremap(struct drm_device *dev, drm_local_map_t *map)
@@ -107,3 +112,10 @@ drm_mtrr_del(int __unused handle, unsigned long offset, size_t size, int flags)
        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)
+{
+
+       pmap_invalidate_cache_pages(pages, num_pages);
+}
index 16e04cb..cabc637 100644 (file)
@@ -23,8 +23,7 @@
  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
  * USE OR OTHER DEALINGS IN THE SOFTWARE.
  *
- *
- * $FreeBSD: src/sys/dev/drm/drm_mm.c,v 1.1 2010/01/31 14:25:29 rnoland Exp $
+ * $FreeBSD: head/sys/dev/drm2/drm_mm.c 247833 2013-03-05 09:07:58Z kib $
  **************************************************************************/
 
 /*
 
 #define MM_UNUSED_TARGET 4
 
-unsigned long drm_mm_tail_space(struct drm_mm *mm)
-{
-       struct list_head *tail_node;
-       struct drm_mm_node *entry;
-
-       tail_node = mm->ml_entry.prev;
-       entry = list_entry(tail_node, struct drm_mm_node, ml_entry);
-       if (!entry->free)
-               return 0;
-
-       return entry->size;
-}
-
-int drm_mm_remove_space_from_tail(struct drm_mm *mm, unsigned long size)
-{
-       struct list_head *tail_node;
-       struct drm_mm_node *entry;
-
-       tail_node = mm->ml_entry.prev;
-       entry = list_entry(tail_node, struct drm_mm_node, ml_entry);
-       if (!entry->free)
-               return -ENOMEM;
-
-       if (entry->size <= size)
-               return -ENOMEM;
-
-       entry->size -= size;
-       return 0;
-}
-
 static struct drm_mm_node *drm_mm_kmalloc(struct drm_mm *mm, int atomic)
 {
        struct drm_mm_node *child;
 
-       if (atomic)
-               child = malloc(sizeof(*child), DRM_MEM_MM, M_NOWAIT);
-       else
-               child = malloc(sizeof(*child), DRM_MEM_MM, M_WAITOK);
+       child = kmalloc(sizeof(*child), DRM_MEM_MM, M_ZERO |
+           (atomic ? M_NOWAIT : M_WAITOK));
 
        if (unlikely(child == NULL)) {
-               DRM_SPINLOCK(&mm->unused_lock);
+               spin_lock(&mm->unused_spin);
                if (list_empty(&mm->unused_nodes))
                        child = NULL;
                else {
                        child =
                            list_entry(mm->unused_nodes.next,
-                                      struct drm_mm_node, fl_entry);
-                       list_del(&child->fl_entry);
+                                      struct drm_mm_node, node_list);
+                       list_del(&child->node_list);
                        --mm->num_unused;
                }
-               DRM_SPINUNLOCK(&mm->unused_lock);
+               spin_unlock(&mm->unused_spin);
        }
        return child;
 }
@@ -106,262 +73,525 @@ int drm_mm_pre_get(struct drm_mm *mm)
 {
        struct drm_mm_node *node;
 
-       DRM_SPINLOCK(&mm->unused_lock);
+       spin_lock(&mm->unused_spin);
        while (mm->num_unused < MM_UNUSED_TARGET) {
-               DRM_SPINUNLOCK(&mm->unused_lock);
-               node = malloc(sizeof(*node), DRM_MEM_MM, M_WAITOK);
-               DRM_SPINLOCK(&mm->unused_lock);
+               spin_unlock(&mm->unused_spin);
+               node = kmalloc(sizeof(*node), DRM_MEM_MM, M_WAITOK);
+               spin_lock(&mm->unused_spin);
 
                if (unlikely(node == NULL)) {
                        int ret = (mm->num_unused < 2) ? -ENOMEM : 0;
-                       DRM_SPINUNLOCK(&mm->unused_lock);
+                       spin_unlock(&mm->unused_spin);
                        return ret;
                }
                ++mm->num_unused;
-               list_add_tail(&node->fl_entry, &mm->unused_nodes);
+               list_add_tail(&node->node_list, &mm->unused_nodes);
        }
-       DRM_SPINUNLOCK(&mm->unused_lock);
+       spin_unlock(&mm->unused_spin);
        return 0;
 }
 
-static int drm_mm_create_tail_node(struct drm_mm *mm,
-                                  unsigned long start,
-                                  unsigned long size, int atomic)
+static inline unsigned long drm_mm_hole_node_start(struct drm_mm_node *hole_node)
 {
-       struct drm_mm_node *child;
-
-       child = drm_mm_kmalloc(mm, atomic);
-       if (unlikely(child == NULL))
-               return -ENOMEM;
-
-       child->free = 1;
-       child->size = size;
-       child->start = start;
-       child->mm = mm;
+       return hole_node->start + hole_node->size;
+}
 
-       list_add_tail(&child->ml_entry, &mm->ml_entry);
-       list_add_tail(&child->fl_entry, &mm->fl_entry);
+static inline unsigned long drm_mm_hole_node_end(struct drm_mm_node *hole_node)
+{
+       struct drm_mm_node *next_node =
+               list_entry(hole_node->node_list.next, struct drm_mm_node,
+                          node_list);
 
-       return 0;
+       return next_node->start;
 }
 
-int drm_mm_add_space_to_tail(struct drm_mm *mm, unsigned long size, int atomic)
+static void drm_mm_insert_helper(struct drm_mm_node *hole_node,
+                                struct drm_mm_node *node,
+                                unsigned long size, unsigned alignment)
 {
-       struct list_head *tail_node;
-       struct drm_mm_node *entry;
+       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);
+
+       KASSERT(hole_node->hole_follows && !node->allocated, ("hole_node"));
+
+       if (alignment)
+               tmp = hole_start % alignment;
+
+       if (!tmp) {
+               hole_node->hole_follows = 0;
+               list_del_init(&hole_node->hole_stack);
+       } else
+               wasted = alignment - tmp;
 
-       tail_node = mm->ml_entry.prev;
-       entry = list_entry(tail_node, struct drm_mm_node, ml_entry);
-       if (!entry->free) {
-               return drm_mm_create_tail_node(mm, entry->start + entry->size,
-                                              size, atomic);
+       node->start = hole_start + wasted;
+       node->size = size;
+       node->mm = mm;
+       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"));
+
+       if (node->start + node->size < hole_end) {
+               list_add(&node->hole_stack, &mm->hole_stack);
+               node->hole_follows = 1;
+       } else {
+               node->hole_follows = 0;
        }
-       entry->size += size;
-       return 0;
 }
 
-static struct drm_mm_node *drm_mm_split_at_start(struct drm_mm_node *parent,
-                                                unsigned long size,
-                                                int atomic)
+struct drm_mm_node *drm_mm_get_block_generic(struct drm_mm_node *hole_node,
+                                            unsigned long size,
+                                            unsigned alignment,
+                                            int atomic)
 {
-       struct drm_mm_node *child;
+       struct drm_mm_node *node;
 
-       child = drm_mm_kmalloc(parent->mm, atomic);
-       if (unlikely(child == NULL))
+       node = drm_mm_kmalloc(hole_node->mm, atomic);
+       if (unlikely(node == NULL))
                return NULL;
 
-       INIT_LIST_HEAD(&child->fl_entry);
+       drm_mm_insert_helper(hole_node, node, size, alignment);
 
-       child->free = 0;
-       child->size = size;
-       child->start = parent->start;
-       child->mm = parent->mm;
+       return node;
+}
 
-       list_add_tail(&child->ml_entry, &parent->ml_entry);
-       INIT_LIST_HEAD(&child->fl_entry);
+int drm_mm_insert_node(struct drm_mm *mm, struct drm_mm_node *node,
+                      unsigned long size, unsigned alignment)
+{
+       struct drm_mm_node *hole_node;
 
-       parent->size -= size;
-       parent->start += size;
-       return child;
-}
+       hole_node = drm_mm_search_free(mm, size, alignment, 0);
+       if (!hole_node)
+               return -ENOSPC;
 
+       drm_mm_insert_helper(hole_node, node, size, alignment);
 
-struct drm_mm_node *drm_mm_get_block_generic(struct drm_mm_node *node,
-                                            unsigned long size,
-                                            unsigned alignment,
-                                            int atomic)
+       return 0;
+}
+
+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 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);
 
-       struct drm_mm_node *align_splitoff = NULL;
-       unsigned tmp = 0;
+       KASSERT(hole_node->hole_follows && !node->allocated, ("hole_node"));
 
+       if (hole_start < start)
+               wasted += start - hole_start;
        if (alignment)
-               tmp = node->start % alignment;
+               tmp = (hole_start + wasted) % alignment;
 
-       if (tmp) {
-               align_splitoff =
-                   drm_mm_split_at_start(node, alignment - tmp, atomic);
-               if (unlikely(align_splitoff == NULL))
-                       return NULL;
+       if (tmp)
+               wasted += alignment - tmp;
+
+       if (!wasted) {
+               hole_node->hole_follows = 0;
+               list_del_init(&hole_node->hole_stack);
        }
 
-       if (node->size == size) {
-               list_del_init(&node->fl_entry);
-               node->free = 0;
+       node->start = hole_start + wasted;
+       node->size = size;
+       node->mm = mm;
+       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"));
+
+       if (node->start + node->size < hole_end) {
+               list_add(&node->hole_stack, &mm->hole_stack);
+               node->hole_follows = 1;
        } else {
-               node = drm_mm_split_at_start(node, size, atomic);
+               node->hole_follows = 0;
        }
+}
 
-       if (align_splitoff)
-               drm_mm_put_block(align_splitoff);
+struct drm_mm_node *drm_mm_get_block_range_generic(struct drm_mm_node *hole_node,
+                                               unsigned long size,
+                                               unsigned alignment,
+                                               unsigned long start,
+                                               unsigned long end,
+                                               int atomic)
+{
+       struct drm_mm_node *node;
+
+       node = drm_mm_kmalloc(hole_node->mm, atomic);
+       if (unlikely(node == NULL))
+               return NULL;
+
+       drm_mm_insert_helper_range(hole_node, node, size, alignment,
+                                  start, end);
 
        return node;
 }
 
+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)
+{
+       struct drm_mm_node *hole_node;
+
+       hole_node = drm_mm_search_free_in_range(mm, size, alignment,
+                                               start, end, 0);
+       if (!hole_node)
+               return -ENOSPC;
+
+       drm_mm_insert_helper_range(hole_node, node, size, alignment,
+                                  start, end);
+
+       return 0;
+}
+
+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"));
+
+       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"));
+               list_del(&node->hole_stack);
+       } else
+               KASSERT(drm_mm_hole_node_start(node)
+                      == drm_mm_hole_node_end(node), ("!hole_follows"));
+
+       if (!prev_node->hole_follows) {
+               prev_node->hole_follows = 1;
+               list_add(&prev_node->hole_stack, &mm->hole_stack);
+       } else
+               list_move(&prev_node->hole_stack, &mm->hole_stack);
+
+       list_del(&node->node_list);
+       node->allocated = 0;
+}
+
 /*
  * Put a block. Merge with the previous and / or next block if they are free.
  * Otherwise add to the free stack.
  */
 
-void drm_mm_put_block(struct drm_mm_node *cur)
+void drm_mm_put_block(struct drm_mm_node *node)
 {
+       struct drm_mm *mm = node->mm;
 
-       struct drm_mm *mm = cur->mm;
-       struct list_head *cur_head = &cur->ml_entry;
-       struct list_head *root_head = &mm->ml_entry;
-       struct drm_mm_node *prev_node = NULL;
-       struct drm_mm_node *next_node;
+       drm_mm_remove_node(node);
 
-       int merged = 0;
+       spin_lock(&mm->unused_spin);
+       if (mm->num_unused < MM_UNUSED_TARGET) {
+               list_add(&node->node_list, &mm->unused_nodes);
+               ++mm->num_unused;
+       } else
+               drm_free(node, DRM_MEM_MM);
+       spin_unlock(&mm->unused_spin);
+}
 
-       if (cur_head->prev != root_head) {
-               prev_node =
-                   list_entry(cur_head->prev, struct drm_mm_node, ml_entry);
-               if (prev_node->free) {
-                       prev_node->size += cur->size;
-                       merged = 1;
-               }
-       }
-       if (cur_head->next != root_head) {
-               next_node =
-                   list_entry(cur_head->next, struct drm_mm_node, ml_entry);
-               if (next_node->free) {
-                       if (merged) {
-                               prev_node->size += next_node->size;
-                               list_del(&next_node->ml_entry);
-                               list_del(&next_node->fl_entry);
-                               if (mm->num_unused < MM_UNUSED_TARGET) {
-                                       list_add(&next_node->fl_entry,
-                                                &mm->unused_nodes);
-                                       ++mm->num_unused;
-                               } else
-                                       free(next_node, DRM_MEM_MM);
-                       } else {
-                               next_node->size += cur->size;
-                               next_node->start = cur->start;
-                               merged = 1;
-                       }
-               }
+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 (!merged) {
-               cur->free = 1;
-               list_add(&cur->fl_entry, &mm->fl_entry);
-       } else {
-               list_del(&cur->ml_entry);
-               if (mm->num_unused < MM_UNUSED_TARGET) {
-                       list_add(&cur->fl_entry, &mm->unused_nodes);
-                       ++mm->num_unused;
-               } else
-                       free(cur, DRM_MEM_MM);
+
+       if (end >= start + size + wasted) {
+               return 1;
        }
+
+       return 0;
 }
 
+
 struct drm_mm_node *drm_mm_search_free(const struct drm_mm *mm,
                                       unsigned long size,
                                       unsigned alignment, int best_match)
 {
-       struct list_head *list;
-       const struct list_head *free_stack = &mm->fl_entry;
        struct drm_mm_node *entry;
        struct drm_mm_node *best;
        unsigned long best_size;
-       unsigned wasted;
 
        best = NULL;
        best_size = ~0UL;
 
-       list_for_each(list, free_stack) {
-               entry = list_entry(list, struct drm_mm_node, fl_entry);
-               wasted = 0;
-
-               if (entry->size < size)
+       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))
                        continue;
 
-               if (alignment) {
-                       register unsigned tmp = entry->start % alignment;
-                       if (tmp)
-                               wasted += alignment - tmp;
+               if (!best_match)
+                       return entry;
+
+               if (entry->size < best_size) {
+                       best = entry;
+                       best_size = entry->size;
                }
+       }
+
+       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)
+{
+       struct drm_mm_node *entry;
+       struct drm_mm_node *best;
+       unsigned long best_size;
+
+       KASSERT(!mm->scanned_blocks, ("scanned"));
+
+       best = NULL;
+       best_size = ~0UL;
+
+       list_for_each_entry(entry, &mm->hole_stack, hole_stack) {
+               unsigned long adj_start = drm_mm_hole_node_start(entry) < start ?
+                       start : drm_mm_hole_node_start(entry);
+               unsigned long adj_end = drm_mm_hole_node_end(entry) > end ?
+                       end : drm_mm_hole_node_end(entry);
 
-               if (entry->size >= size + wasted) {
-                       if (!best_match)
-                               return entry;
-                       if (size < best_size) {
-                               best = entry;
-                               best_size = entry->size;
-                       }
+               KASSERT(entry->hole_follows, ("hole_follows"));
+               if (!check_free_hole(adj_start, adj_end, size, alignment))
+                       continue;
+
+               if (!best_match)
+                       return entry;
+
+               if (entry->size < best_size) {
+                       best = entry;
+                       best_size = entry->size;
                }
        }
 
        return best;
 }
 
+void drm_mm_replace_node(struct drm_mm_node *old, struct drm_mm_node *new)
+{
+       list_replace(&old->node_list, &new->node_list);
+       list_replace(&old->hole_stack, &new->hole_stack);
+       new->hole_follows = old->hole_follows;
+       new->mm = old->mm;
+       new->start = old->start;
+       new->size = old->size;
+
+       old->allocated = 0;
+       new->allocated = 1;
+}
+
+void drm_mm_init_scan(struct drm_mm *mm, unsigned long size,
+                     unsigned alignment)
+{
+       mm->scan_alignment = alignment;
+       mm->scan_size = size;
+       mm->scanned_blocks = 0;
+       mm->scan_hit_start = 0;
+       mm->scan_hit_size = 0;
+       mm->scan_check_range = 0;
+       mm->prev_scanned_node = NULL;
+}
+
+void drm_mm_init_scan_with_range(struct drm_mm *mm, unsigned long size,
+                                unsigned alignment,
+                                unsigned long start,
+                                unsigned long end)
+{
+       mm->scan_alignment = alignment;
+       mm->scan_size = size;
+       mm->scanned_blocks = 0;
+       mm->scan_hit_start = 0;
+       mm->scan_hit_size = 0;
+       mm->scan_start = start;
+       mm->scan_end = end;
+       mm->scan_check_range = 1;
+       mm->prev_scanned_node = NULL;
+}
+
+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;
+
+       mm->scanned_blocks++;
+
+       KASSERT(!node->scanned_block, ("node->scanned_block"));
+       node->scanned_block = 1;
+
+       prev_node = list_entry(node->node_list.prev, struct drm_mm_node,
+                              node_list);
+
+       node->scanned_preceeds_hole = prev_node->hole_follows;
+       prev_node->hole_follows = 1;
+       list_del(&node->node_list);
+       node->node_list.prev = &prev_node->node_list;
+       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);
+       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 (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;
+
+               return 1;
+       }
+
+       return 0;
+}
+
+int drm_mm_scan_remove_block(struct drm_mm_node *node)
+{
+       struct drm_mm *mm = node->mm;
+       struct drm_mm_node *prev_node;
+
+       mm->scanned_blocks--;
+
+       KASSERT(node->scanned_block, ("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;
+}
+
 int drm_mm_clean(struct drm_mm * mm)
 {
-       struct list_head *head = &mm->ml_entry;
+       struct list_head *head = &mm->head_node.node_list;
 
        return (head->next->next == head);
 }
 
 int drm_mm_init(struct drm_mm * mm, unsigned long start, unsigned long size)
 {
-       INIT_LIST_HEAD(&mm->ml_entry);
-       INIT_LIST_HEAD(&mm->fl_entry);
+       INIT_LIST_HEAD(&mm->hole_stack);
        INIT_LIST_HEAD(&mm->unused_nodes);
        mm->num_unused = 0;
-       DRM_SPININIT(&mm->unused_lock, "drm_unused");
+       mm->scanned_blocks = 0;
+       spin_init(&mm->unused_spin);
+
+       INIT_LIST_HEAD(&mm->head_node.node_list);
+       INIT_LIST_HEAD(&mm->head_node.hole_stack);
+       mm->head_node.hole_follows = 1;
+       mm->head_node.scanned_block = 0;
+       mm->head_node.scanned_prev_free = 0;
+       mm->head_node.scanned_next_free = 0;
+       mm->head_node.mm = mm;
+       mm->head_node.start = start + size;
+       mm->head_node.size = start - mm->head_node.start;
+       list_add_tail(&mm->head_node.hole_stack, &mm->hole_stack);
 
-       /* XXX This could be non-atomic but gets called from a locked path */
-       return drm_mm_create_tail_node(mm, start, size, 1);
+       return 0;
 }
 
 void drm_mm_takedown(struct drm_mm * mm)
 {
-       struct list_head *bnode = mm->fl_entry.next;
-       struct drm_mm_node *entry;
-       struct drm_mm_node *next;
-
-       entry = list_entry(bnode, struct drm_mm_node, fl_entry);
+       struct drm_mm_node *entry, *next;
 
-       if (entry->ml_entry.next != &mm->ml_entry ||
-           entry->fl_entry.next != &mm->fl_entry) {
+       if (!list_empty(&mm->head_node.node_list)) {
                DRM_ERROR("Memory manager not clean. Delaying takedown\n");
                return;
        }
 
-       list_del(&entry->fl_entry);
-       list_del(&entry->ml_entry);
-       free(entry, DRM_MEM_MM);
-
-       DRM_SPINLOCK(&mm->unused_lock);
-       list_for_each_entry_safe(entry, next, &mm->unused_nodes, fl_entry) {
-               list_del(&entry->fl_entry);
-               free(entry, DRM_MEM_MM);
+       spin_lock(&mm->unused_spin);
+       list_for_each_entry_safe(entry, next, &mm->unused_nodes, node_list) {
+               list_del(&entry->node_list);
+               drm_free(entry, DRM_MEM_MM);
                --mm->num_unused;
        }
-       DRM_SPINUNLOCK(&mm->unused_lock);
+       spin_unlock(&mm->unused_spin);
 
-       DRM_SPINUNINIT(&mm->unused_lock);
+       spin_uninit(&mm->unused_spin);
 
        KASSERT(mm->num_unused == 0, ("num_unused != 0"));
 }
+
+void drm_mm_debug_table(struct drm_mm *mm, const char *prefix)
+{
+       struct drm_mm_node *entry;
+       unsigned long total_used = 0, total_free = 0, total = 0;
+       unsigned long hole_start, hole_end, hole_size;
+
+       hole_start = drm_mm_hole_node_start(&mm->head_node);
+       hole_end = drm_mm_hole_node_end(&mm->head_node);
+       hole_size = hole_end - hole_start;
+       if (hole_size)
+               kprintf("%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) {
+               kprintf("%s 0x%08lx-0x%08lx: %8lu: used\n",
+                       prefix, entry->start, entry->start + entry->size,
+                       entry->size);
+               total_used += entry->size;
+
+               if (entry->hole_follows) {
+                       hole_start = drm_mm_hole_node_start(entry);
+                       hole_end = drm_mm_hole_node_end(entry);
+                       hole_size = hole_end - hole_start;
+                       kprintf("%s 0x%08lx-0x%08lx: %8lu: free\n",
+                               prefix, hole_start, hole_end,
+                               hole_size);
+                       total_free += hole_size;
+               }
+       }
+       total = total_free + total_used;
+
+       kprintf("%s total: %lu, used %lu free %lu\n", prefix, total,
+               total_used, total_free);
+}
index 56bea22..9c3dbe0 100644 (file)
@@ -24,7 +24,7 @@
  * USE OR OTHER DEALINGS IN THE SOFTWARE.
  *
  *
- * $FreeBSD: src/sys/dev/drm/drm_mm.h,v 1.1 2010/01/31 14:25:29 rnoland Exp $
+ * $FreeBSD: head/sys/dev/drm2/drm_mm.h 247833 2013-03-05 09:07:58Z kib $
  **************************************************************************/
 
 /*
 #define _DRM_MM_H_
 
 #include "dev/drm/drm_linux_list.h"
+#include <stdbool.h>
 
 struct drm_mm_node {
-       struct list_head fl_entry;
-       struct list_head ml_entry;
-       int free;
+       struct list_head node_list;
+       struct list_head hole_stack;
+       unsigned hole_follows : 1;
+       unsigned scanned_block : 1;
+       unsigned scanned_prev_free : 1;
+       unsigned scanned_next_free : 1;
+       unsigned scanned_preceeds_hole : 1;
+       unsigned allocated : 1;
        unsigned long start;
        unsigned long size;
        struct drm_mm *mm;
@@ -48,13 +54,42 @@ struct drm_mm_node {
 };
 
 struct drm_mm {
-       struct list_head fl_entry;
-       struct list_head ml_entry;
+       struct list_head hole_stack;
+       struct drm_mm_node head_node;
        struct list_head unused_nodes;
        int num_unused;
-       DRM_SPINTYPE unused_lock;
+       struct spinlock unused_spin;
+       unsigned int scan_check_range : 1;
+       unsigned scan_alignment;
+       unsigned long scan_size;
+       unsigned long scan_hit_start;
+       unsigned scan_hit_size;
+       unsigned scanned_blocks;
+       unsigned long scan_start;
+       unsigned long scan_end;
+       struct drm_mm_node *prev_scanned_node;
 };
 
+static inline bool drm_mm_node_allocated(struct drm_mm_node *node)
+{
+       return node->allocated;
+}
+
+static inline bool drm_mm_initialized(struct drm_mm *mm)
+{
+       return (mm->hole_stack.next != NULL);
+}
+#define drm_mm_for_each_node(entry, mm) list_for_each_entry(entry, \
+                                               &(mm)->head_node.node_list, \
+                                               node_list)
+#define drm_mm_for_each_scanned_node_reverse(entry, n, mm) \
+       for (entry = (mm)->prev_scanned_node, \
+               next = entry ? list_entry(entry->node_list.next, \
+                       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)
+
 /*
  * Basic range manager support (drm_mm.c)
  */
@@ -62,6 +97,13 @@ extern struct drm_mm_node *drm_mm_get_block_generic(struct drm_mm_node *node,
                                                    unsigned long size,
                                                    unsigned alignment,
                                                    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 start,
+                                               unsigned long end,
+                                               int atomic);
 static inline struct drm_mm_node *drm_mm_get_block(struct drm_mm_node *parent,
                                                   unsigned long size,
                                                   unsigned alignment)
@@ -74,11 +116,46 @@ static inline struct drm_mm_node *drm_mm_get_block_atomic(struct drm_mm_node *pa
 {
        return drm_mm_get_block_generic(parent, size, alignment, 1);
 }
+static inline struct drm_mm_node *drm_mm_get_block_range(
+                                               struct drm_mm_node *parent,
+                                               unsigned long size,
+                                               unsigned alignment,
+                                               unsigned long start,
+                                               unsigned long end)
+{
+       return drm_mm_get_block_range_generic(parent, size, alignment,
+                                               start, end, 0);
+}
+static inline struct drm_mm_node *drm_mm_get_block_atomic_range(
+                                               struct drm_mm_node *parent,
+                                               unsigned long size,
+                                               unsigned alignment,
+                                               unsigned long start,
+                                               unsigned long end)
+{
+       return drm_mm_get_block_range_generic(parent, size, alignment,
+                                               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_in_range(struct drm_mm *mm,
+                                      struct drm_mm_node *node,
+                                      unsigned long size, unsigned alignment,
+                                      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(
+                                               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,
                       unsigned long size);
 extern void drm_mm_takedown(struct drm_mm *mm);
@@ -95,4 +172,15 @@ 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,
+                                unsigned alignment,
+                                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);
+
 #endif
similarity index 99%
rename from sys/dev/drm2/drm_modes.c
rename to sys/dev/drm/drm_modes.c
index 292a228..0b85e2e 100644 (file)
@@ -32,9 +32,9 @@
  * $FreeBSD: src/sys/dev/drm2/drm_modes.c,v 1.1 2012/05/22 11:07:44 kib Exp $
  */
 
-#include <dev/drm2/drmP.h>
-#include <dev/drm2/drm.h>
-#include <dev/drm2/drm_crtc.h>
+#include <dev/drm/drmP.h>
+#include <dev/drm/drm.h>
+#include <dev/drm/drm_crtc.h>
 
 #define        KHZ2PICOS(a)    (1000000000UL/(a))
 
index 104ed23..0daf8db 100644 (file)
@@ -19,6 +19,8 @@
  * AUTHOR 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.
+ *
+ * $FreeBSD: src/sys/dev/drm2/drm_pci.c,v 1.1 2012/05/22 11:07:44 kib Exp $
  */
 
 /**
@@ -64,7 +66,7 @@ drm_pci_alloc(struct drm_device *dev, size_t size,
                return NULL;
        }
 
-       dmah = malloc(sizeof(drm_dma_handle_t), DRM_MEM_DMA, M_ZERO | M_NOWAIT);
+       dmah = kmalloc(sizeof(drm_dma_handle_t), DRM_MEM_DMA, M_ZERO | M_NOWAIT);
        if (dmah == NULL)
                return NULL;
 
@@ -82,19 +84,18 @@ drm_pci_alloc(struct drm_device *dev, size_t size,
            maxaddr, BUS_SPACE_MAXADDR, /* lowaddr, highaddr */
            NULL, NULL, /* filtfunc, filtfuncargs */
            size, 1, size, /* maxsize, nsegs, maxsegsize */
-           0, /* flags */
+           0,          /* flags */
            &dmah->tag);
        if (ret != 0) {
-               free(dmah, DRM_MEM_DMA);
+               drm_free(dmah, DRM_MEM_DMA);
                return NULL;
        }
 
-       /* XXX BUS_DMA_NOCACHE */
        ret = bus_dmamem_alloc(dmah->tag, &dmah->vaddr,
-           BUS_DMA_WAITOK | BUS_DMA_ZERO, &dmah->map);
+           BUS_DMA_WAITOK | BUS_DMA_ZERO | BUS_DMA_NOCACHE, &dmah->map);
        if (ret != 0) {
                bus_dma_tag_destroy(dmah->tag);
-               free(dmah, DRM_MEM_DMA);
+               drm_free(dmah, DRM_MEM_DMA);
                return NULL;
        }
 
@@ -103,7 +104,7 @@ drm_pci_alloc(struct drm_device *dev, size_t size,
        if (ret != 0) {
                bus_dmamem_free(dmah->tag, dmah->vaddr, dmah->map);
                bus_dma_tag_destroy(dmah->tag);
-               free(dmah, DRM_MEM_DMA);
+               drm_free(dmah, DRM_MEM_DMA);
                return NULL;
        }
 
@@ -122,7 +123,7 @@ drm_pci_free(struct drm_device *dev, drm_dma_handle_t *dmah)
        bus_dmamem_free(dmah->tag, dmah->vaddr, dmah->map);
        bus_dma_tag_destroy(dmah->tag);
 
-       free(dmah, DRM_MEM_DMA);
+       drm_free(dmah, DRM_MEM_DMA);
 }
 
 /*@}*/
index 7327708..d4125b5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $FreeBSD: src/sys/dev/drm/drm_pciids.h,v 1.21 2010/03/13 11:51:18 rnoland Exp $
+ * $FreeBSD: head/sys/dev/drm2/drm_pciids.h 237411 2012-06-21 22:06:57Z emaste $
  */
 /*
    This file is auto-generated from the drm_pciids.txt in the DRM CVS
        {0x8086, 0x3577, CHIP_I8XX, "Intel i830M GMCH"}, \
        {0x8086, 0x2562, CHIP_I8XX, "Intel i845G GMCH"}, \
        {0x8086, 0x3582, CHIP_I8XX, "Intel i852GM/i855GM GMCH"}, \
+       {0x8086, 0x358e, CHIP_I8XX, "Intel i852GM/i855GM GMCH"}, \
        {0x8086, 0x2572, CHIP_I8XX, "Intel i865G GMCH"}, \
        {0x8086, 0x2582, CHIP_I9XX|CHIP_I915, "Intel i915G"}, \
        {0x8086, 0x258a, CHIP_I9XX|CHIP_I915, "Intel E7221 (i915)"}, \
        {0x8086, 0x2982, CHIP_I9XX|CHIP_I965, "Intel i965G"}, \
        {0x8086, 0x2992, CHIP_I9XX|CHIP_I965, "Intel i965Q"}, \
        {0x8086, 0x29A2, CHIP_I9XX|CHIP_I965, "Intel i965G"}, \
-       {0x8086, 0x2A02, CHIP_I9XX|CHIP_I965, "Intel i965GM"}, \
-       {0x8086, 0x2A12, CHIP_I9XX|CHIP_I965, "Intel i965GME/GLE"}, \
-       {0x8086, 0x29C2, CHIP_I9XX|CHIP_I915, "Intel G33"}, \
        {0x8086, 0x29B2, CHIP_I9XX|CHIP_I915, "Intel Q35"}, \
+       {0x8086, 0x29C2, CHIP_I9XX|CHIP_I915, "Intel G33"}, \
        {0x8086, 0x29D2, CHIP_I9XX|CHIP_I915, "Intel Q33"}, \
+       {0x8086, 0x2A02, CHIP_I9XX|CHIP_I965, "Intel i965GM"}, \
+       {0x8086, 0x2A12, CHIP_I9XX|CHIP_I965, "Intel i965GME/GLE"}, \
        {0x8086, 0x2A42, CHIP_I9XX|CHIP_I965, "Mobile Intel® GM45 Express Chipset"}, \
        {0x8086, 0x2E02, CHIP_I9XX|CHIP_I965, "Intel Eaglelake"}, \
-       {0x8086, 0xA001, CHIP_I9XX|CHIP_I965, "Intel Pineview"}, \
-       {0x8086, 0xA011, CHIP_I9XX|CHIP_I965, "Intel Pineview (M)"}, \
        {0x8086, 0x2E12, CHIP_I9XX|CHIP_I965, "Intel Q45/Q43"}, \
        {0x8086, 0x2E22, CHIP_I9XX|CHIP_I965, "Intel G45/G43"}, \
        {0x8086, 0x2E32, CHIP_I9XX|CHIP_I965, "Intel G41"}, \
+       {0x8086, 0x2e42, CHIP_I9XX|CHIP_I915, "Intel G43 ?"}, \
+       {0x8086, 0x2e92, CHIP_I9XX|CHIP_I915, "Intel G43 ?"}, \
+       {0x8086, 0x0042, CHIP_I9XX|CHIP_I915, "Intel IronLake"}, \
+       {0x8086, 0x0046, CHIP_I9XX|CHIP_I915, "Intel IronLake"}, \
+       {0x8086, 0x0102, CHIP_I9XX|CHIP_I915, "Intel SandyBridge"}, \
+       {0x8086, 0x0112, CHIP_I9XX|CHIP_I915, "Intel SandyBridge"}, \
+       {0x8086, 0x0122, CHIP_I9XX|CHIP_I915, "Intel SandyBridge"}, \
+       {0x8086, 0x0106, CHIP_I9XX|CHIP_I915, "Intel SandyBridge (M)"}, \
+       {0x8086, 0x0116, CHIP_I9XX|CHIP_I915, "Intel SandyBridge (M)"}, \
+       {0x8086, 0x0126, CHIP_I9XX|CHIP_I915, "Intel SandyBridge (M)"}, \
+       {0x8086, 0x010A, CHIP_I9XX|CHIP_I915, "Intel SandyBridge (M)"}, \
+       {0x8086, 0x0152, CHIP_I9XX|CHIP_I915, "Intel IvyBridge"}, \
+       {0x8086, 0x0162, CHIP_I9XX|CHIP_I915, "Intel IvyBridge"}, \
+       {0x8086, 0x0156, CHIP_I9XX|CHIP_I915, "Intel IvyBridge (M)"}, \
+       {0x8086, 0x0166, CHIP_I9XX|CHIP_I915, "Intel IvyBridge (M)"}, \
+       {0x8086, 0x015A, CHIP_I9XX|CHIP_I915, "Intel IvyBridge (S)"}, \
+       {0x8086, 0x016A, CHIP_I9XX|CHIP_I915, "Intel IvyBridge (S)"}, \
+       {0x8086, 0xA001, CHIP_I9XX|CHIP_I965, "Intel Pineview"}, \
+       {0x8086, 0xA011, CHIP_I9XX|CHIP_I965, "Intel Pineview (M)"}, \
        {0, 0, 0, NULL}
 
 #define imagine_PCI_IDS \
index 9c2f849..2e89d37 100644 (file)
  * 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.
+ *
+ * $FreeBSD: src/sys/dev/drm2/drm_scatter.c,v 1.1 2012/05/22 11:07:44 kib Exp $
  */
 
 /** @file drm_scatter.c
  * Allocation of memory for scatter-gather mappings by the graphics chip.
- *
  * The memory allocated here is then made into an aperture in the card
  * by mapping the pages into the GART.
  */
@@ -43,11 +44,11 @@ drm_sg_alloc(struct drm_device *dev, struct drm_scatter_gather *request)
 
        DRM_DEBUG("request size=%ld\n", request->size);
 
-       entry = malloc(sizeof(*entry), DRM_MEM_DRIVER, M_WAITOK | M_ZERO);
+       entry = kmalloc(sizeof(*entry), DRM_MEM_DRIVER, M_WAITOK | M_ZERO);
 
        size = round_page(request->size);
        entry->pages = OFF_TO_IDX(size);
-       entry->busaddr = malloc(entry->pages * sizeof(*entry->busaddr),
+       entry->busaddr = kmalloc(entry->pages * sizeof(*entry->busaddr),
            DRM_MEM_SGLISTS, M_WAITOK | M_ZERO);
 
        entry->vaddr = kmem_alloc_attr(&kernel_map, size, M_WAITOK | M_ZERO,
@@ -62,19 +63,20 @@ drm_sg_alloc(struct drm_device *dev, struct drm_scatter_gather *request)
                    vtophys(entry->vaddr + IDX_TO_OFF(pindex));
        }
 
-       DRM_LOCK();
+       DRM_LOCK(dev);
        if (dev->sg) {
-               DRM_UNLOCK();
+               DRM_UNLOCK(dev);
                drm_sg_cleanup(entry);
                return (EINVAL);
        }
        dev->sg = entry;
-       DRM_UNLOCK();
+       DRM_UNLOCK(dev);
 
        request->handle = entry->vaddr;
 
-       DRM_DEBUG("allocated %ju pages @ 0x%08zx, contents=%08lx\n",
-           entry->pages, entry->vaddr, *(unsigned long *)entry->vaddr);
+       DRM_DEBUG("allocated %ju pages @ 0x%08jx, contents=%08lx\n",
+           entry->pages, (uintmax_t)entry->vaddr,
+           *(unsigned long *)entry->vaddr);
 
        return (0);
 }
@@ -99,8 +101,8 @@ drm_sg_cleanup(struct drm_sg_mem *entry)
        if (entry->vaddr != 0)
                kmem_free(&kernel_map, entry->vaddr, IDX_TO_OFF(entry->pages));
 
-       free(entry->busaddr, DRM_MEM_SGLISTS);
-       free(entry, DRM_MEM_DRIVER);
+       drm_free(entry->busaddr, DRM_MEM_SGLISTS);
+       drm_free(entry, DRM_MEM_DRIVER);
 
        return;
 }
@@ -111,15 +113,15 @@ 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();
+       DRM_LOCK(dev);
        entry = dev->sg;
        dev->sg = NULL;
-       DRM_UNLOCK();
+       DRM_UNLOCK(dev);
 
        if (!entry || entry->vaddr != request->handle)
                return (EINVAL);
 
-       DRM_DEBUG("free 0x%zx\n", entry->vaddr);
+       DRM_DEBUG("free 0x%jx\n", (uintmax_t)entry->vaddr);
 
        drm_sg_cleanup(entry);
 
index 3117f4c..3b00f72 100644 (file)
@@ -24,7 +24,7 @@
  * of the Software.
  *
  *
- * $FreeBSD: src/sys/dev/drm/drm_sman.c,v 1.1 2010/01/31 14:25:29 rnoland Exp $
+ * $FreeBSD: src/sys/dev/drm2/drm_sman.c,v 1.1 2012/05/22 11:07:44 kib Exp $
  **************************************************************************/
 
 /*
@@ -52,8 +52,7 @@ 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);
+               drm_free(sman->mm, DRM_MEM_MM);
 }
 
 int
@@ -79,7 +78,7 @@ drm_sman_init(struct drm_sman * sman, unsigned int num_managers,
 
        drm_ht_remove(&sman->owner_hash_tab);
 out1:
-       drm_free(sman->mm, num_managers * sizeof(*sman->mm), DRM_MEM_MM);
+       drm_free(sman->mm, DRM_MEM_MM);
 out:
        return ret;
 }
@@ -110,7 +109,7 @@ 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);
+       drm_free(mm, DRM_MEM_MM);
 }
 
 static unsigned long drm_sman_mm_offset(void *private, void *ref)
@@ -130,7 +129,7 @@ drm_sman_set_range(struct drm_sman * sman, unsigned int manager,
        KASSERT(manager < sman->num_managers, ("Invalid manager"));
 
        sman_mm = &sman->mm[manager];
-       mm = malloc(sizeof(*mm), DRM_MEM_MM, M_NOWAIT | M_ZERO);
+       mm = kmalloc(sizeof(*mm), DRM_MEM_MM, M_NOWAIT | M_ZERO);
        if (!mm) {
                return -ENOMEM;
        }
@@ -138,7 +137,7 @@ drm_sman_set_range(struct drm_sman * sman, unsigned int manager,
        ret = drm_mm_init(mm, start, size);
 
        if (ret) {
-               drm_free(mm, sizeof(*mm), DRM_MEM_MM);
+               drm_free(mm, DRM_MEM_MM);
                return ret;
        }
 
@@ -173,7 +172,7 @@ static struct drm_owner_item *drm_sman_get_owner_item(struct drm_sman * sman,
                                      owner_hash);
        }
 
-       owner_item = malloc(sizeof(*owner_item), DRM_MEM_MM, M_NOWAIT | M_ZERO);
+       owner_item = kmalloc(sizeof(*owner_item), DRM_MEM_MM, M_NOWAIT | M_ZERO);
        if (!owner_item)
                goto out;
 
@@ -187,7 +186,7 @@ static struct drm_owner_item *drm_sman_get_owner_item(struct drm_sman * sman,
        return owner_item;
 
 out1:
-       drm_free(owner_item, sizeof(*owner_item), DRM_MEM_MM);
+       drm_free(owner_item, DRM_MEM_MM);
 out:
        return NULL;
 }
@@ -209,7 +208,7 @@ struct drm_memblock_item *drm_sman_alloc(struct drm_sman *sman, unsigned int man
                return NULL;
        }
 
-       memblock = malloc(sizeof(*memblock), DRM_MEM_MM, M_NOWAIT | M_ZERO);
+       memblock = kmalloc(sizeof(*memblock), DRM_MEM_MM, M_NOWAIT | M_ZERO);
        DRM_DEBUG("allocated mem_block %p\n", memblock);
        if (!memblock)
                goto out;
@@ -239,7 +238,7 @@ struct drm_memblock_item *drm_sman_alloc(struct drm_sman *sman, unsigned int man
 out2:
        drm_ht_remove_item(&sman->user_hash_tab, &memblock->user_hash);
 out1:
-       drm_free(memblock, sizeof(*memblock), DRM_MEM_MM);
+       drm_free(memblock, DRM_MEM_MM);
 out:
        sman_mm->free(sman_mm->private, tmp);
 
@@ -253,7