Add missing drm_regman.c file.
authorThomas Hellstrom <thomas-at-tungstengraphics-dot-com>
Tue, 6 Nov 2007 08:36:25 +0000 (09:36 +0100)
committerThomas Hellstrom <thomas-at-tungstengraphics-dot-com>
Tue, 6 Nov 2007 08:36:29 +0000 (09:36 +0100)
linux-core/Makefile.kernel
linux-core/drm_regman.c [new file with mode: 0644]

index d1f3bb7..e7c280d 100644 (file)
@@ -13,7 +13,8 @@ drm-objs    := drm_auth.o drm_bufs.o drm_context.o drm_dma.o drm_drawable.o \
                drm_sysfs.o drm_pci.o drm_agpsupport.o drm_scatter.o \
                drm_memory_debug.o ati_pcigart.o drm_sman.o \
                drm_hashtab.o drm_mm.o drm_object.o drm_compat.o \
-               drm_fence.o drm_ttm.o drm_bo.o drm_bo_move.o drm_bo_lock.o
+               drm_fence.o drm_ttm.o drm_bo.o drm_bo_move.o drm_bo_lock.o \
+               drm_regman.o
 tdfx-objs   := tdfx_drv.o
 r128-objs   := r128_drv.o r128_cce.o r128_state.o r128_irq.o
 mga-objs    := mga_drv.o mga_dma.o mga_state.o mga_warp.o mga_irq.o
diff --git a/linux-core/drm_regman.c b/linux-core/drm_regman.c
new file mode 100644 (file)
index 0000000..f49a25c
--- /dev/null
@@ -0,0 +1,205 @@
+/**************************************************************************
+ * Copyright (c) 2007 Tungsten Graphics, Inc., Cedar Park, TX., USA
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+/*
+ * An allocate-fence manager implementation intended for sets of base-registers
+ * or tiling-registers.
+ */
+
+#include "drmP.h"
+
+/*
+ * Allocate a compatible register and put it on the unfenced list.
+ */
+
+int drm_regs_alloc(struct drm_reg_manager *manager,
+                  const void *data,
+                  uint32_t fence_class,
+                  uint32_t fence_type,
+                  int interruptible, int no_wait, struct drm_reg **reg)
+{
+       struct drm_reg *entry, *next_entry;
+       int ret;
+
+       *reg = NULL;
+
+       /*
+        * Search the unfenced list.
+        */
+
+       list_for_each_entry(entry, &manager->unfenced, head) {
+               if (manager->reg_reusable(entry, data)) {
+                       entry->new_fence_type |= fence_type;
+                       goto out;
+               }
+       }
+
+       /*
+        * Search the lru list.
+        */
+
+       list_for_each_entry_safe(entry, next_entry, &manager->lru, head) {
+               struct drm_fence_object *fence = entry->fence;
+               if (fence->fence_class == fence_class &&
+                   (entry->fence_type & fence_type) == entry->fence_type &&
+                   manager->reg_reusable(entry, data)) {
+                       list_del(&entry->head);
+                       entry->new_fence_type = fence_type;
+                       list_add_tail(&entry->head, &manager->unfenced);
+                       goto out;
+               }
+       }
+
+       /*
+        * Search the free list.
+        */
+
+       list_for_each_entry(entry, &manager->free, head) {
+               list_del(&entry->head);
+               entry->new_fence_type = fence_type;
+               list_add_tail(&entry->head, &manager->unfenced);
+               goto out;
+       }
+
+       if (no_wait)
+               return -EBUSY;
+
+       /*
+        * Go back to the lru list and try to expire fences.
+        */
+
+       list_for_each_entry_safe(entry, next_entry, &manager->lru, head) {
+               BUG_ON(!entry->fence);
+               ret = drm_fence_object_wait(entry->fence, 0, !interruptible,
+                                           entry->fence_type);
+               if (ret)
+                       return ret;
+
+               drm_fence_usage_deref_unlocked(&entry->fence);
+               list_del(&entry->head);
+               entry->new_fence_type = fence_type;
+               list_add_tail(&entry->head, &manager->unfenced);
+               goto out;
+       }
+
+       /*
+        * Oops. All registers are used up :(.
+        */
+
+       return -EBUSY;
+      out:
+       *reg = entry;
+       return 0;
+}
+
+EXPORT_SYMBOL(drm_regs_alloc);
+
+void drm_regs_fence(struct drm_reg_manager *manager,
+                   struct drm_fence_object *fence)
+{
+       struct drm_reg *entry;
+       struct drm_reg *next_entry;
+
+       if (!fence) {
+
+               /*
+                * Old fence (if any) is still valid.
+                * Put back on free and lru lists.
+                */
+
+               list_for_each_entry_safe_reverse(entry, next_entry,
+                                                &manager->unfenced, head) {
+                       list_del(&entry->head);
+                       list_add(&entry->head, (entry->fence) ?
+                                &manager->lru : &manager->free);
+               }
+       } else {
+
+               /*
+                * Fence with a new fence and put on lru list.
+                */
+
+               list_for_each_entry_safe(entry, next_entry, &manager->unfenced,
+                                        head) {
+                       list_del(&entry->head);
+                       if (entry->fence)
+                               drm_fence_usage_deref_unlocked(&entry->fence);
+                       drm_fence_reference_unlocked(&entry->fence, fence);
+
+                       entry->fence_type = entry->new_fence_type;
+                       BUG_ON((entry->fence_type & fence->type) !=
+                              entry->fence_type);
+
+                       list_add_tail(&entry->head, &manager->lru);
+               }
+       }
+}
+
+EXPORT_SYMBOL(drm_regs_fence);
+
+void drm_regs_free(struct drm_reg_manager *manager)
+{
+       struct drm_reg *entry;
+       struct drm_reg *next_entry;
+
+       drm_regs_fence(manager, NULL);
+
+       list_for_each_entry_safe(entry, next_entry, &manager->free, head) {
+               list_del(&entry->head);
+               manager->reg_destroy(entry);
+       }
+
+       list_for_each_entry_safe(entry, next_entry, &manager->lru, head) {
+
+               (void)drm_fence_object_wait(entry->fence, 1, 1,
+                                           entry->fence_type);
+               list_del(&entry->head);
+               drm_fence_usage_deref_unlocked(&entry->fence);
+               manager->reg_destroy(entry);
+       }
+}
+
+EXPORT_SYMBOL(drm_regs_free);
+
+void drm_regs_add(struct drm_reg_manager *manager, struct drm_reg *reg)
+{
+       reg->fence = NULL;
+       list_add_tail(&reg->head, &manager->free);
+}
+
+EXPORT_SYMBOL(drm_regs_add);
+
+void drm_regs_init(struct drm_reg_manager *manager,
+                  int (*reg_reusable) (const struct drm_reg *, const void *),
+                  void (*reg_destroy) (struct drm_reg *))
+{
+       INIT_LIST_HEAD(&manager->free);
+       INIT_LIST_HEAD(&manager->lru);
+       INIT_LIST_HEAD(&manager->unfenced);
+       manager->reg_reusable = reg_reusable;
+       manager->reg_destroy = reg_destroy;
+}
+
+EXPORT_SYMBOL(drm_regs_init);