rradeon_ms: rework fence code and bring radeon ms up to date
authorJerome Glisse <glisse@freedesktop.org>
Mon, 10 Mar 2008 22:35:07 +0000 (23:35 +0100)
committerJohn Doe <glisse@freedesktop.org>
Mon, 10 Mar 2008 22:35:07 +0000 (23:35 +0100)
linux-core/radeon_ms_drv.c
linux-core/radeon_ms_fb.c
shared-core/radeon_ms.h
shared-core/radeon_ms_drm.c
shared-core/radeon_ms_drm.h
shared-core/radeon_ms_exec.c
shared-core/radeon_ms_fence.c
shared-core/radeon_ms_irq.c

index d7b0eec..cf9699f 100644 (file)
@@ -28,7 +28,7 @@
 #include "drm_pciids.h"
 #include "radeon_ms.h"
 
-extern struct drm_fence_driver radeon_ms_fence_driver;
+extern struct drm_fence_driver r3xx_fence_driver;
 extern struct drm_bo_driver radeon_ms_bo_driver;
 extern struct drm_ioctl_desc radeon_ms_ioctls[];
 extern int radeon_ms_num_ioctls;
@@ -71,7 +71,7 @@ static struct drm_driver driver = {
        .set_version = NULL,
        .fb_probe = radeonfb_probe,
        .fb_remove = radeonfb_remove,
-       .fence_driver = &radeon_ms_fence_driver,
+       .fence_driver = &r3xx_fence_driver,
        .bo_driver = &radeon_ms_bo_driver,
        .major = DRIVER_MAJOR,
        .minor = DRIVER_MINOR,
index d7fb39e..a8fba71 100644 (file)
@@ -345,12 +345,11 @@ int radeonfb_probe(struct drm_device *dev, struct drm_crtc *crtc)
        DRM_INFO("[radeon_ms] fb physical start : 0x%lX\n", info->fix.smem_start);
        DRM_INFO("[radeon_ms] fb physical size  : %d\n", info->fix.smem_len);
 
-       ret = drm_mem_reg_ioremap(dev, &fb->bo->mem, &fb->virtual_base);
-       if (ret) {
-               DRM_ERROR("error mapping fb: %d\n", ret);
+       ret = drm_bo_kmap(fb->bo, 0, fb->bo->num_pages, &fb->kmap);
+       if (ret) {
+               DRM_ERROR("error mapping fb: %d\n", ret);
        }
-
-       info->screen_base = fb->virtual_base;
+       info->screen_base = fb->kmap.virtual;
        info->screen_size = info->fix.smem_len; /* FIXME */
        info->pseudo_palette = fb->pseudo_palette;
        info->var.xres_virtual = fb->width;
@@ -445,10 +444,10 @@ int radeonfb_remove(struct drm_device *dev, struct drm_crtc *crtc)
        
        if (info) {
                unregister_framebuffer(info);
-               framebuffer_release(info);
-               drm_mem_reg_iounmap(dev, &fb->bo->mem, fb->virtual_base);
+               drm_bo_kunmap(&fb->kmap);
                drm_bo_usage_deref_unlocked(&fb->bo);
                drm_framebuffer_destroy(fb);
+               framebuffer_release(info);
        }
        return 0;
 }
index 903de97..12c945f 100644 (file)
@@ -31,6 +31,7 @@
 #define __RADEON_MS_H__
 
 #include "radeon_ms_drv.h"
+#include "amd_r3xx_fence.h"
 #include "radeon_ms_reg.h"
 #include "radeon_ms_drm.h"
 #include "radeon_ms_rom.h"
@@ -328,6 +329,7 @@ struct drm_radeon_private {
        /* abstract asic specific structures */
        struct radeon_ms_rom        rom;
        struct radeon_ms_properties properties;
+       void                        *fence;
 };
 
 
@@ -425,15 +427,9 @@ int radeon_ms_execbuffer(struct drm_device *dev, void *data,
 int radeon_ms_family_init(struct drm_device *dev);
 
 /* radeon_ms_fence.c */
-int radeon_ms_fence_emit_sequence(struct drm_device *dev, uint32_t class,
-                                 uint32_t flags, uint32_t *sequence,
-                                 uint32_t *native_type);
-void radeon_ms_fence_handler(struct drm_device * dev);
-int radeon_ms_fence_has_irq(struct drm_device *dev, uint32_t class,
-                           uint32_t flags);
-int radeon_ms_fence_types(struct drm_buffer_object *bo,
-                         uint32_t * class, uint32_t * type);
-void radeon_ms_poke_flush(struct drm_device * dev, uint32_t class);
+void r3xx_fence_handler(struct drm_device * dev);
+int r3xx_fence_types(struct drm_buffer_object *bo,
+                    uint32_t * class, uint32_t * type);
 
 /* radeon_ms_fb.c */
 int radeonfb_probe(struct drm_device *dev, struct drm_crtc *crtc);
index 857182a..b9245d9 100644 (file)
@@ -43,24 +43,13 @@ static uint32_t radeon_ms_busy_prios[] = {
        DRM_BO_MEM_LOCAL,
 };
 
-struct drm_fence_driver radeon_ms_fence_driver = {
-       .num_classes = 1,
-       .wrap_diff = (1 << 30),
-       .flush_diff = (1 << 29),
-       .sequence_mask = 0xffffffffU,
-       .lazy_capable = 1,
-       .emit = radeon_ms_fence_emit_sequence,
-       .poke_flush = radeon_ms_poke_flush,
-       .has_irq = radeon_ms_fence_has_irq,
-};
-
 struct drm_bo_driver radeon_ms_bo_driver = {
        .mem_type_prio = radeon_ms_mem_prios,
        .mem_busy_prio = radeon_ms_busy_prios,
        .num_mem_type_prio = sizeof(radeon_ms_mem_prios)/sizeof(uint32_t),
        .num_mem_busy_prio = sizeof(radeon_ms_busy_prios)/sizeof(uint32_t),
        .create_ttm_backend_entry = radeon_ms_create_ttm_backend,
-       .fence_type = radeon_ms_fence_types,
+       .fence_type = r3xx_fence_types,
        .invalidate_caches = radeon_ms_invalidate_caches,
        .init_mem_type = radeon_ms_init_mem_type,
        .evict_flags = radeon_ms_evict_flags,
@@ -127,6 +116,13 @@ int radeon_ms_driver_load(struct drm_device *dev, unsigned long flags)
                return ret;
        }
 
+       dev_priv->fence = drm_alloc(sizeof(struct r3xx_fence), DRM_MEM_DRIVER);
+       if (dev_priv->fence == NULL) {
+               radeon_ms_driver_unload(dev);
+               return -ENOMEM;
+       }
+       memset(dev_priv->fence, 0, sizeof(struct r3xx_fence));
+
        /* we don't want userspace to be able to map this so don't use
         * drm_addmap */
        dev_priv->mmio.offset = drm_get_resource_start(dev, 2);
@@ -309,9 +305,11 @@ int radeon_ms_driver_unload(struct drm_device *dev)
                drm_core_ioremapfree(&dev_priv->vram, dev);
        }
        DRM_INFO("[radeon_ms] map released\n");
+       drm_free(dev_priv->fence, sizeof(struct r3xx_fence), DRM_MEM_DRIVER);
        drm_free(dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER);
        dev->dev_private = NULL;
 
+
        DRM_INFO("[radeon_ms] that's all the folks\n");
        return 0;
 }
index 842d533..39c050a 100644 (file)
 #ifndef __RADEON_MS_DRM_H__
 #define __RADEON_MS_DRM_H__
 
-/* fence definitions */
-/* The only fence class we support */
-#define DRM_RADEON_FENCE_CLASS_ACCEL 0
-/* Fence type that guarantees read-write flush */
-#define DRM_RADEON_FENCE_TYPE_RW 2
-/* cache flushes programmed just before the fence */
-#define DRM_RADEON_FENCE_FLAG_FLUSHED 0x01000000
+/* Fence
+ * We have only one fence class as we submit command through th
+ * same fifo so there is no need to synchronize buffer btw different
+ * cmd stream.
+ *
+ * Set DRM_RADEON_FENCE_FLAG_FLUSHED if you want a flush with
+ * emission of the fence
+ *
+ * For fence type we have the native DRM EXE type and the radeon RW
+ * type.
+ */
+#define DRM_RADEON_FENCE_CLASS_ACCEL           0
+#define DRM_RADEON_FENCE_TYPE_RW               2
+#define DRM_RADEON_FENCE_FLAG_FLUSHED          0x01000000
 
 /* radeon ms ioctl */
-#define DRM_RADEON_EXECBUFFER  0x00
+#define DRM_RADEON_EXECBUFFER                  0x00
 
 struct drm_radeon_execbuffer_arg {
        uint64_t    next;
index b2ce3cb..8e28b19 100644 (file)
@@ -223,7 +223,7 @@ int radeon_ms_execbuffer(struct drm_device *dev, void *data,
                        fence_arg->handle = fence->base.hash.key;
                        fence_arg->fence_class = fence->fence_class;
                        fence_arg->type = fence->type;
-                       fence_arg->signaled = fence->signaled;
+                       fence_arg->signaled = fence->signaled_types;
                        fence_arg->sequence = fence->sequence;
                }
        }
index 6fcf543..162d37d 100644 (file)
  *    Jerome Glisse <glisse@freedesktop.org>
  */
 #include "radeon_ms.h"
+#include "amd_r3xx_fence.h"
 
-static void radeon_ms_fence_flush(struct drm_device *dev)
+#define R3XX_FENCE_SEQUENCE_RW_FLUSH   0x80000000u
+
+static inline int r3xx_fence_emit_sequence(struct drm_device *dev,
+                                          struct drm_radeon_private *dev_priv,
+                                          uint32_t sequence)
 {
-       struct drm_radeon_private *dev_priv = dev->dev_private;
-       struct drm_fence_class_manager *fc = &dev->fm.fence_class[0];
-       uint32_t pending_flush_types = 0;
+       struct r3xx_fence *r3xx_fence = dev_priv->fence;
+       uint32_t cmd[2];
+       int i, r;
+
+       if (sequence & R3XX_FENCE_SEQUENCE_RW_FLUSH) {
+               r3xx_fence->sequence_last_flush =
+                       sequence & ~R3XX_FENCE_SEQUENCE_RW_FLUSH;
+               /* Ask flush for VERTEX & FRAGPROG pipeline
+                * have 3D idle  */
+               dev_priv->flush_cache(dev);
+       }
+       cmd[0] = CP_PACKET0(dev_priv->fence_reg, 0);
+       cmd[1] = sequence;
+       for (i = 0; i < dev_priv->usec_timeout; i++) {
+               r = radeon_ms_ring_emit(dev, cmd, 2);
+               if (!r) {
+                       dev_priv->irq_emit(dev);
+                       return 0;
+               }
+       }
+       return -EBUSY;
+}
+
+static inline uint32_t r3xx_fence_sequence(struct r3xx_fence *r3xx_fence)
+{
+       r3xx_fence->sequence += 1;
+       if (unlikely(r3xx_fence->sequence > 0x7fffffffu)) {
+               r3xx_fence->sequence = 1;
+       }
+       return r3xx_fence->sequence;
+}
+
+static inline void r3xx_fence_report(struct drm_device *dev,
+                                    struct drm_radeon_private *dev_priv,
+                                    struct r3xx_fence *r3xx_fence)
+{
+       uint32_t fence_types = DRM_FENCE_TYPE_EXE;
        uint32_t sequence;
 
        if (dev_priv == NULL) {
                return;
        }
-       pending_flush_types = fc->pending_flush |
-                             ((fc->pending_exe_flush) ?
-                               DRM_FENCE_TYPE_EXE : 0);
-       if (pending_flush_types) {
-               sequence = mmio_read(dev_priv, dev_priv->fence_reg);
-               drm_fence_handler(dev, 0, sequence, pending_flush_types, 0);
+       sequence = mmio_read(dev_priv, dev_priv->fence_reg);
+       if (sequence & R3XX_FENCE_SEQUENCE_RW_FLUSH) {
+               sequence &= ~R3XX_FENCE_SEQUENCE_RW_FLUSH;
+               fence_types |= DRM_RADEON_FENCE_TYPE_RW;
+               if (sequence == r3xx_fence->sequence_last_flush) {
+                       r3xx_fence->sequence_last_flush = 0;
+               }
        }
+       /* avoid to report already reported sequence */
+       if (sequence != r3xx_fence->sequence_last_reported) {
+               drm_fence_handler(dev, 0, sequence, fence_types, 0);
+               r3xx_fence->sequence_last_reported = sequence;
+       }
+}
+
+static void r3xx_fence_flush(struct drm_device *dev, uint32_t class)
+{
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+       struct r3xx_fence *r3xx_fence = dev_priv->fence;
+       uint32_t sequence;
+
+       sequence = r3xx_fence_sequence(r3xx_fence);
+       sequence |= R3XX_FENCE_SEQUENCE_RW_FLUSH;
+       r3xx_fence_emit_sequence(dev, dev_priv, sequence);
 }
 
-int radeon_ms_fence_emit_sequence(struct drm_device *dev, uint32_t class,
-                                 uint32_t flags, uint32_t *sequence,
-                                 uint32_t *native_type)
+static void r3xx_fence_poll(struct drm_device *dev, uint32_t fence_class,
+                           uint32_t waiting_types)
 {
        struct drm_radeon_private *dev_priv = dev->dev_private;
-       uint32_t fence_id, cmd[2], i, ret;
+       struct drm_fence_manager *fm = &dev->fm;
+       struct drm_fence_class_manager *fc = &fm->fence_class[fence_class];
+       struct r3xx_fence *r3xx_fence = dev_priv->fence;
+
+       if (unlikely(!dev_priv)) {
+               return;
+       }
+       /* if there is a RW flush pending then submit new sequence
+        * preceded by flush cmds */
+       if (fc->pending_flush & DRM_RADEON_FENCE_TYPE_RW) {
+               r3xx_fence_flush(dev, 0);
+               fc->pending_flush &= ~DRM_RADEON_FENCE_TYPE_RW;
+       }
+       r3xx_fence_report(dev, dev_priv, r3xx_fence);
+       return;
+}
+
+static int r3xx_fence_emit(struct drm_device *dev, uint32_t class,
+                          uint32_t flags, uint32_t *sequence,
+                          uint32_t *native_type)
+{
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+       struct r3xx_fence *r3xx_fence = dev_priv->fence;
+       uint32_t tmp;
 
        if (!dev_priv || dev_priv->cp_ready != 1) {
                return -EINVAL;
        }
-       fence_id = (++dev_priv->fence_id_last);
-       if (dev_priv->fence_id_last > 0x7FFFFFFF) {
-               fence_id = dev_priv->fence_id_last = 1;
-       }
-       *sequence = fence_id;
+       *sequence = tmp = r3xx_fence_sequence(r3xx_fence);
        *native_type = DRM_FENCE_TYPE_EXE;
        if (flags & DRM_RADEON_FENCE_FLAG_FLUSHED) {
                *native_type |= DRM_RADEON_FENCE_TYPE_RW;
-               dev_priv->flush_cache(dev);
+               tmp |= R3XX_FENCE_SEQUENCE_RW_FLUSH;
        }
-       cmd[0] = CP_PACKET0(dev_priv->fence_reg, 0);
-       cmd[1] = fence_id;
-       for (i = 0; i < dev_priv->usec_timeout; i++) {
-               ret = radeon_ms_ring_emit(dev, cmd, 2);
-               if (!ret) {
-                       dev_priv->irq_emit(dev);
+       return r3xx_fence_emit_sequence(dev, dev_priv, tmp);
+}
+
+static int r3xx_fence_has_irq(struct drm_device *dev,
+                             uint32_t class, uint32_t type)
+{
+       const uint32_t type_irq_mask = DRM_FENCE_TYPE_EXE |
+                                      DRM_RADEON_FENCE_TYPE_RW;
+       /*
+        * We have an irq for EXE & RW fence.
+        */
+       if (class == 0 && (type & type_irq_mask)) {
+               return 1;
+       }
+       return 0;
+}
+
+static uint32_t r3xx_fence_needed_flush(struct drm_fence_object *fence)
+{
+       struct drm_device *dev = fence->dev;
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+       struct r3xx_fence *r3xx_fence = dev_priv->fence;
+       struct drm_fence_driver *driver = dev->driver->fence_driver;
+       uint32_t flush_types, diff;
+       
+       flush_types = fence->waiting_types &    
+                     ~(DRM_FENCE_TYPE_EXE | fence->signaled_types);
+
+       if (flush_types == 0 || ((flush_types & ~fence->native_types) == 0)) {
+               return 0;
+       }
+       if (unlikely(dev_priv == NULL)) {
+               return 0;
+       }
+       if (r3xx_fence->sequence_last_flush) {
+               diff = (r3xx_fence->sequence_last_flush - fence->sequence) & 
+                      driver->sequence_mask;
+               if (diff < driver->wrap_diff) {
                        return 0;
                }
        }
-       return -EBUSY;
+       return flush_types;
 }
 
-void radeon_ms_fence_handler(struct drm_device * dev)
+static int r3xx_fence_wait(struct drm_fence_object *fence,
+                          int lazy, int interruptible, uint32_t mask)
 {
-       struct drm_radeon_private *dev_priv = dev->dev_private;
+       struct drm_device *dev = fence->dev;
        struct drm_fence_manager *fm = &dev->fm;
+       struct drm_fence_class_manager *fc = &fm->fence_class[0];
+       int r;
 
-       if (dev_priv == NULL) {
-               return;
+       drm_fence_object_flush(fence, mask);
+       if (likely(interruptible)) {
+               r = wait_event_interruptible_timeout(
+                       fc->fence_queue,
+                       drm_fence_object_signaled(fence, DRM_FENCE_TYPE_EXE), 
+                       3 * DRM_HZ);
+       } else {
+               r = wait_event_timeout(
+                       fc->fence_queue,
+                       drm_fence_object_signaled(fence, DRM_FENCE_TYPE_EXE), 
+                       3 * DRM_HZ);
+       }
+       if (unlikely(r == -ERESTARTSYS)) {
+               return -EAGAIN;
+       }
+       if (unlikely(r == 0)) {
+               return -EBUSY;
        }
 
-       write_lock(&fm->lock);
-       radeon_ms_fence_flush(dev);
-       write_unlock(&fm->lock);
-}
+       if (likely(mask == DRM_FENCE_TYPE_EXE || 
+                  drm_fence_object_signaled(fence, mask))) {
+               return 0;
+       }
 
-int radeon_ms_fence_has_irq(struct drm_device *dev, uint32_t class,
-                           uint32_t flags)
-{
        /*
-        * We have an irq that tells us when we have a new breadcrumb.
+        * Poll for sync flush completion.
         */
-       if (class == 0 && flags == DRM_FENCE_TYPE_EXE)
-               return 1;
-
-       return 0;
+       return drm_fence_wait_polling(fence, lazy, interruptible,
+                                     mask, 3 * DRM_HZ);
 }
 
-int radeon_ms_fence_types(struct drm_buffer_object *bo,
-                         uint32_t *class, uint32_t *type)
+struct drm_fence_driver r3xx_fence_driver = {
+       .num_classes = 1,
+       .wrap_diff = (1 << 29),
+       .flush_diff = (1 << 28),
+       .sequence_mask = 0x7fffffffU,
+       .has_irq = r3xx_fence_has_irq,
+       .emit = r3xx_fence_emit,
+       .flush = r3xx_fence_flush,
+       .poll = r3xx_fence_poll,
+       .needed_flush = r3xx_fence_needed_flush,
+       .wait = r3xx_fence_wait,
+};
+
+/* this are used by the buffer object code */
+int r3xx_fence_types(struct drm_buffer_object *bo,
+                    uint32_t *class, uint32_t *type)
 {
        *class = 0;
-       if (bo->mem.flags & (DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE))
-               *type = 3;
-       else
-               *type = 1;
+       if (bo->mem.flags & (DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE)) {
+               *type = DRM_FENCE_TYPE_EXE | DRM_RADEON_FENCE_TYPE_RW;
+       } else {
+               *type = DRM_FENCE_TYPE_EXE;
+       }
        return 0;
 }
 
-void radeon_ms_poke_flush(struct drm_device *dev, uint32_t class)
+/* this are used by the irq code */
+void r3xx_fence_handler(struct drm_device * dev)
 {
+       struct drm_radeon_private *dev_priv = dev->dev_private;
        struct drm_fence_manager *fm = &dev->fm;
-       unsigned long flags;
+       struct drm_fence_class_manager *fc = &fm->fence_class[0];
 
-       if (class != 0)
+       if (unlikely(dev_priv == NULL)) {
                return;
-       write_lock_irqsave(&fm->lock, flags);
-       radeon_ms_fence_flush(dev);
-       write_unlock_irqrestore(&fm->lock, flags);
+       }
+
+       write_lock(&fm->lock);
+       r3xx_fence_poll(dev, 0, fc->waiting_types);
+       write_unlock(&fm->lock);
 }
index 2f94118..5c68c90 100644 (file)
@@ -92,9 +92,9 @@ irqreturn_t radeon_ms_irq_handler(DRM_IRQ_ARGS)
 
        /* SW interrupt */
        if (GEN_INT_STATUS__SW_INT & status) {
-               radeon_ms_fence_handler(dev);
+               r3xx_fence_handler(dev);
        }
-       radeon_ms_fence_handler(dev);
+       r3xx_fence_handler(dev);
        return IRQ_HANDLED;
 }