Merge in the drm-sman-branch
authorThomas Hellstrom <thomas@tungstengraphics.com>
Tue, 6 Jun 2006 14:19:00 +0000 (14:19 +0000)
committerThomas Hellstrom <thomas@tungstengraphics.com>
Tue, 6 Jun 2006 14:19:00 +0000 (14:19 +0000)
16 files changed:
linux-core/Makefile
linux-core/Makefile.kernel
linux-core/drmP.h
linux-core/drm_hashtab.c [new file with mode: 0644]
linux-core/drm_hashtab.h [new file with mode: 0644]
linux-core/drm_mm.c [new file with mode: 0644]
linux-core/drm_sman.c [new file with mode: 0644]
linux-core/drm_sman.h [new file with mode: 0644]
linux-core/sis_drv.c
linux-core/sis_mm.c [new file with mode: 0644]
linux-core/via_mm.c [new file with mode: 0644]
shared-core/sis_drv.h
shared-core/via_drm.h
shared-core/via_drv.c
shared-core/via_drv.h
shared-core/via_map.c

index 9bb578c..32828d2 100644 (file)
@@ -77,7 +77,7 @@ DRM_MODULES ?= $(MODULE_LIST)
 
 DRMSHARED =     drm.h drm_sarea.h
 DRMHEADERS =    drmP.h drm_compat.h drm_os_linux.h $(DRMSHARED)
-COREHEADERS =   drm_core.h 
+COREHEADERS =   drm_core.h drm_sman.h drm_hashtab.h 
 
 TDFXHEADERS =   tdfx_drv.h $(DRMHEADERS)
 TDFXSHARED =    tdfx_drv.h
@@ -93,15 +93,13 @@ I810HEADERS =   i810_drv.h i810_drm.h $(DRMHEADERS)
 I830HEADERS =   i830_drv.h i830_drm.h $(DRMHEADERS)
 I915HEADERS =   i915_drv.h i915_drm.h $(DRMHEADERS)
 I915SHARED  =   i915_drv.h i915_drm.h i915_irq.c i915_mem.c i915_dma.c
-SISHEADERS=     sis_drv.h sis_drm.h $(DRMHEADERS)
-SISSHARED=      sis_drv.h sis_drm.h sis_ds.c sis_ds.h sis_mm.c
+SISHEADERS=     sis_drv.h sis_drm.h drm_hashtab.h drm_sman.h $(DRMHEADERS)
+SISSHARED=      sis_drv.h sis_drm.h
 SAVAGEHEADERS=  savage_drv.h savage_drm.h $(DRMHEADERS)
 SAVAGESHARED=  savage_drv.h savage_drm.h savage_bci.c savage_state.c
-VIAHEADERS =   via_drm.h via_drv.h via_mm.h via_ds.h \
-               via_3d_reg.h via_verifier.h $(DRMHEADERS)
-VIASHARED      = via_drm.h via_drv.h via_mm.h via_ds.h \
-               via_3d_reg.h via_drv.c via_ds.c via_irq.c via_map.c \
-               via_mm.c via_dma.c via_verifier.c via_verifier.h via_video.c
+VIAHEADERS =   via_drm.h via_drv.h via_3d_reg.h via_verifier.h $(DRMHEADERS)
+VIASHARED      = via_drm.h via_drv.h via_3d_reg.h via_drv.c via_irq.c via_map.c \
+               via_dma.c via_verifier.c via_verifier.h via_video.c
 MACH64HEADERS = mach64_drv.h mach64_drm.h $(DRMHEADERS)
 MACH64SHARED =         mach64_drv.h mach64_drm.h mach64_dma.c \
                mach64_irq.c mach64_state.c
index d63aabb..211e5b0 100644 (file)
@@ -11,7 +11,8 @@ drm-objs    := drm_auth.o drm_bufs.o drm_context.o drm_dma.o drm_drawable.o \
                drm_drv.o drm_fops.o drm_ioctl.o drm_irq.o \
                drm_lock.o drm_memory.o drm_proc.o drm_stub.o drm_vm.o \
                drm_sysfs.o drm_pci.o drm_agpsupport.o drm_scatter.o \
-               drm_memory_debug.o ati_pcigart.o
+               drm_memory_debug.o ati_pcigart.o drm_sman.o \
+               drm_hashtab.o drm_mm.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
@@ -19,11 +20,11 @@ i810-objs   := i810_drv.o i810_dma.o
 i830-objs   := i830_drv.o i830_dma.o i830_irq.o
 i915-objs   := i915_drv.o i915_dma.o i915_irq.o i915_mem.o
 radeon-objs := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o r300_cmdbuf.o
-sis-objs    := sis_drv.o sis_ds.o sis_mm.o
+sis-objs    := sis_drv.o sis_mm.o
 ffb-objs    := ffb_drv.o ffb_context.o
 savage-objs := savage_drv.o savage_bci.o savage_state.o
-via-objs    := via_irq.o via_drv.o via_ds.o via_map.o via_mm.o via_dma.o via_verifier.o \
-               via_video.o via_dmablit.o
+via-objs    := via_irq.o via_drv.o via_map.o via_mm.o via_dma.o via_verifier.o \
+               via_video.o via_dmablit.o 
 mach64-objs := mach64_drv.o mach64_dma.o mach64_irq.o mach64_state.o 
 nv-objs := nv_drv.o
 
index b2295b9..ec72ebc 100644 (file)
 #define DRM_MEM_CTXBITMAP 18
 #define DRM_MEM_STUB      19
 #define DRM_MEM_SGLISTS   20
-#define DRM_MEM_CTXLIST  21
+#define DRM_MEM_CTXLIST   21
+#define DRM_MEM_MM        22
+#define DRM_MEM_HASHTAB   23
 
 #define DRM_MAX_CTXBITMAP (PAGE_SIZE * 8)
 
@@ -533,6 +535,24 @@ typedef struct ati_pcigart_info {
        drm_local_map_t mapping;
 } drm_ati_pcigart_info;
 
+/* 
+ * Generic memory manager structs
+ */
+
+typedef struct drm_mm_node {
+       struct list_head fl_entry;
+       struct list_head ml_entry;
+       int free;
+       unsigned long start;
+       unsigned long size;
+       void *private;
+} drm_mm_node_t;
+
+typedef struct drm_mm {
+       drm_mm_node_t root_node;
+} drm_mm_t;
+
+
 /**
  * DRM driver structure. This structure represent the common code for
  * a family of cards. There will one drm_device for each card present
@@ -1017,6 +1037,19 @@ extern struct class_device *drm_sysfs_device_add(struct drm_sysfs_class *cs,
                                                 drm_head_t * head);
 extern void drm_sysfs_device_remove(struct class_device *class_dev);
 
+/* 
+ * Basic memory manager support (drm_mm.c) 
+ */
+
+extern drm_mm_node_t * drm_mm_get_block(drm_mm_node_t * parent, unsigned long size,
+                                              unsigned alignment);
+extern void drm_mm_put_block(drm_mm_t *mm, drm_mm_node_t *cur);
+extern drm_mm_node_t *drm_mm_search_free(const drm_mm_t *mm, unsigned long size, 
+                                               unsigned alignment, int best_match);
+extern int drm_mm_init(drm_mm_t *mm, unsigned long start, unsigned long size);
+extern void drm_mm_takedown(drm_mm_t *mm);
+
+
 /* Inline replacements for DRM_IOREMAP macros */
 static __inline__ void drm_core_ioremap(struct drm_map *map,
                                        struct drm_device *dev)
diff --git a/linux-core/drm_hashtab.c b/linux-core/drm_hashtab.c
new file mode 100644 (file)
index 0000000..3be781d
--- /dev/null
@@ -0,0 +1,194 @@
+/**************************************************************************
+ * 
+ * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND. USA.
+ * All Rights Reserved.
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * 
+ **************************************************************************/
+/*
+ * Simple open hash tab implementation.
+ *
+ * Authors:
+ * Thomas Hellström <thomas-at-tungstengraphics-dot-com>
+ */
+
+#include "drmP.h"
+#include "drm_hashtab.h"
+#include <linux/hash.h>
+
+int
+drm_ht_create(drm_open_hash_t *ht, unsigned int order)
+{
+        unsigned int i;
+
+        ht->size = 1 << order;
+        ht->order = order;
+        ht->fill = 0;
+        ht->table = vmalloc(ht->size*sizeof(*ht->table));
+        if (!ht->table) {
+                DRM_ERROR("Out of memory for hash table\n");
+                return -ENOMEM;
+        }
+        for (i=0; i< ht->size; ++i) {
+                INIT_HLIST_HEAD(&ht->table[i]);
+        }
+        return 0;
+}
+
+void
+drm_ht_verbose_list(drm_open_hash_t *ht, unsigned long key)
+{
+        drm_hash_item_t *entry;
+        struct hlist_head *h_list;
+        struct hlist_node *list;
+        unsigned int hashed_key;
+        int count = 0;
+
+        hashed_key = hash_long(key, ht->order);
+        DRM_DEBUG("Key is 0x%08lx, Hashed key is 0x%08x\n", key, hashed_key);
+        h_list = &ht->table[hashed_key];
+        hlist_for_each(list, h_list) {
+                entry = hlist_entry(list, drm_hash_item_t, head);
+                DRM_DEBUG("count %d, key: 0x%08lx\n", count++, entry->key);
+        }
+}
+
+static struct hlist_node
+*drm_ht_find_key(drm_open_hash_t *ht, unsigned long key)
+{
+        drm_hash_item_t *entry;
+        struct hlist_head *h_list;
+        struct hlist_node *list;
+        unsigned int hashed_key;
+
+        hashed_key = hash_long(key, ht->order);
+        h_list = &ht->table[hashed_key];
+        hlist_for_each(list, h_list) {
+                entry = hlist_entry(list, drm_hash_item_t, head);
+                if (entry->key == key)
+                        return list;
+                if (entry->key > key)
+                        break;
+        }
+        return NULL;
+}
+        
+
+int
+drm_ht_insert_item(drm_open_hash_t *ht, drm_hash_item_t *item)
+{
+        drm_hash_item_t *entry;
+        struct hlist_head *h_list;
+        struct hlist_node *list, *parent;
+        unsigned int hashed_key;
+        unsigned long key = item->key;
+
+        hashed_key = hash_long(key, ht->order);
+        h_list = &ht->table[hashed_key];
+        parent = NULL;
+        hlist_for_each(list, h_list) {
+                entry = hlist_entry(list, drm_hash_item_t, head);
+                if (entry->key == key) 
+                        return -1;
+                if (entry->key > key)
+                        break;
+                parent = list;
+        }
+        if (parent) {
+                hlist_add_after(parent, &item->head);
+        } else {
+                hlist_add_head(&item->head, h_list);
+        }
+        return 0;
+}
+
+/*
+ * Just insert an item and return any "bits" bit key that hasn't been used before.
+ */
+
+int
+drm_ht_just_insert_please(drm_open_hash_t *ht, drm_hash_item_t *item,
+                          unsigned long seed, int bits)
+{
+        int ret;
+        unsigned long mask = (1 << bits) - 1;
+        unsigned long first;
+
+        item->key = hash_long(seed, bits);
+        first = item->key;
+        do{
+                ret = drm_ht_insert_item(ht, item);
+                if (ret)
+                        item->key = (item->key + 1) & mask; 
+        } while(ret && (item->key != first));
+
+        if (ret) {
+                DRM_ERROR("Available key bit space exhausted\n");
+                return -EINVAL;
+        }
+        return 0;
+}
+        
+int
+drm_ht_find_item(drm_open_hash_t *ht, unsigned long key, drm_hash_item_t **item) 
+{
+        struct hlist_node *list;
+
+        list = drm_ht_find_key(ht, key);
+        if (!list) 
+                return -1;
+
+        *item = hlist_entry(list, drm_hash_item_t, head);
+        return 0;
+}
+             
+int 
+drm_ht_remove_key(drm_open_hash_t *ht, unsigned long key)
+{
+        struct hlist_node *list;
+        
+        list = drm_ht_find_key(ht, key);
+        if (list) {
+                hlist_del_init(list);
+                ht->fill--;
+                return 0;
+        }
+        return -1;
+}
+
+int 
+drm_ht_remove_item(drm_open_hash_t *ht, drm_hash_item_t *item)
+{
+        hlist_del_init(&item->head);
+        ht->fill--;
+        return 0;
+}
+
+void drm_ht_remove(drm_open_hash_t *ht)
+{
+        if (ht->table) {
+                vfree(ht->table);
+                ht->table = NULL;
+        }
+} 
+
diff --git a/linux-core/drm_hashtab.h b/linux-core/drm_hashtab.h
new file mode 100644 (file)
index 0000000..7f457e7
--- /dev/null
@@ -0,0 +1,64 @@
+/**************************************************************************
+ * 
+ * Copyright 2006 Tungsten Graphics, Inc., Bismack, ND. USA.
+ * All Rights Reserved.
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * 
+ **************************************************************************/
+/*
+ * Simple open hash tab implementation.
+ *
+ * Authors:
+ * Thomas Hellström <thomas-at-tungstengraphics-dot-com>
+ */
+
+#ifndef DRM_HASHTAB_H
+#define DRM_HASHTAB_H
+
+typedef struct drm_hash_item{
+        struct hlist_node head;
+        unsigned long key;
+} drm_hash_item_t;
+
+typedef struct drm_open_hash{
+        unsigned int size;
+        unsigned int order;
+        unsigned int fill;
+        struct hlist_head *table;
+} drm_open_hash_t;
+
+
+extern int drm_ht_create(drm_open_hash_t *ht, unsigned int order);
+extern int drm_ht_insert_item(drm_open_hash_t *ht, drm_hash_item_t *item);
+extern int drm_ht_just_insert_please(drm_open_hash_t *ht, drm_hash_item_t *item,
+                              unsigned long seed, int bits);
+extern int drm_ht_find_item(drm_open_hash_t *ht, unsigned long key, drm_hash_item_t **item);
+
+extern void drm_ht_verbose_list(drm_open_hash_t *ht, unsigned long key);
+extern int drm_ht_remove_key(drm_open_hash_t *ht, unsigned long key);
+extern int drm_ht_remove_item(drm_open_hash_t *ht, drm_hash_item_t *item);
+extern void drm_ht_remove(drm_open_hash_t *ht);
+
+
+#endif
+
diff --git a/linux-core/drm_mm.c b/linux-core/drm_mm.c
new file mode 100644 (file)
index 0000000..a93760f
--- /dev/null
@@ -0,0 +1,201 @@
+/**************************************************************************
+ * 
+ * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA.
+ * All Rights Reserved.
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * 
+ **************************************************************************/
+
+/*
+ * Generic simple memory manager implementation. Intended to be used as a base
+ * class implementation for more advanced memory managers. 
+ *
+ * Note that the algorithm used is quite simple and there might be substantial
+ * performance gains if a smarter free list is implemented. Currently it is just an
+ * unordered stack of free regions. This could easily be improved if an RB-tree
+ * is used instead. At least if we expect heavy fragmentation.
+ *
+ * Aligned allocations can also see improvement.
+ *
+ * Authors:
+ * Thomas Hellström <thomas-at-tungstengraphics-dot-com>
+ */
+
+#include "drmP.h"
+
+drm_mm_node_t *drm_mm_get_block(drm_mm_node_t * parent,
+                               unsigned long size, unsigned alignment)
+{
+
+       drm_mm_node_t *child;
+
+       if (alignment)
+               size += alignment - 1;
+
+       if (parent->size == size) {
+               list_del_init(&parent->fl_entry);
+               parent->free = FALSE;
+               return parent;
+       } else {
+               child = (drm_mm_node_t *) drm_alloc(sizeof(*child), DRM_MEM_MM);
+               if (!child)
+                       return NULL;
+
+               INIT_LIST_HEAD(&child->ml_entry);
+               INIT_LIST_HEAD(&child->fl_entry);
+
+               child->free = FALSE;
+               child->size = size;
+               child->start = parent->start;
+
+               list_add_tail(&child->ml_entry, &parent->ml_entry);
+               parent->size -= size;
+               parent->start += size;
+       }
+       return child;
+}
+
+/*
+ * 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(drm_mm_t * mm, drm_mm_node_t * cur)
+{
+
+       drm_mm_node_t *list_root = &mm->root_node;
+       struct list_head *cur_head = &cur->ml_entry;
+       struct list_head *root_head = &list_root->ml_entry;
+       drm_mm_node_t *prev_node = NULL;
+       drm_mm_node_t *next_node;
+
+       int merged = FALSE;
+
+       if (cur_head->prev != root_head) {
+               prev_node = list_entry(cur_head->prev, drm_mm_node_t, ml_entry);
+               if (prev_node->free) {
+                       prev_node->size += cur->size;
+                       merged = TRUE;
+               }
+       }
+       if (cur_head->next != root_head) {
+               next_node = list_entry(cur_head->next, drm_mm_node_t, 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);
+                               drm_free(next_node, sizeof(*next_node),
+                                        DRM_MEM_MM);
+                       } else {
+                               next_node->size += cur->size;
+                               next_node->start = cur->start;
+                               merged = TRUE;
+                       }
+               }
+       }
+       if (!merged) {
+               cur->free = TRUE;
+               list_add(&cur->fl_entry, &list_root->fl_entry);
+       } else {
+               list_del(&cur->ml_entry);
+               drm_free(cur, sizeof(*cur), DRM_MEM_MM);
+       }
+}
+
+drm_mm_node_t *drm_mm_search_free(const drm_mm_t * mm,
+                                 unsigned long size,
+                                 unsigned alignment, int best_match)
+{
+       struct list_head *list;
+       const struct list_head *free_stack = &mm->root_node.fl_entry;
+       drm_mm_node_t *entry;
+       drm_mm_node_t *best;
+       unsigned long best_size;
+
+       best = NULL;
+       best_size = ~0UL;
+
+       if (alignment)
+               size += alignment - 1;
+
+       list_for_each(list, free_stack) {
+               entry = list_entry(list, drm_mm_node_t, fl_entry);
+               if (entry->size >= size) {
+                       if (!best_match)
+                               return entry;
+                       if (size < best_size) {
+                               best = entry;
+                               best_size = entry->size;
+                       }
+               }
+       }
+
+       return best;
+}
+
+int drm_mm_init(drm_mm_t * mm, unsigned long start, unsigned long size)
+{
+       drm_mm_node_t *child;
+
+       INIT_LIST_HEAD(&mm->root_node.ml_entry);
+       INIT_LIST_HEAD(&mm->root_node.fl_entry);
+       child = (drm_mm_node_t *) drm_alloc(sizeof(*child), DRM_MEM_MM);
+       if (!child)
+               return -ENOMEM;
+
+       INIT_LIST_HEAD(&child->ml_entry);
+       INIT_LIST_HEAD(&child->fl_entry);
+
+       child->start = start;
+       child->size = size;
+       child->free = TRUE;
+
+       list_add(&child->fl_entry, &mm->root_node.fl_entry);
+       list_add(&child->ml_entry, &mm->root_node.ml_entry);
+
+       return 0;
+}
+
+EXPORT_SYMBOL(drm_mm_init);
+
+void drm_mm_takedown(drm_mm_t * mm)
+{
+       struct list_head *bnode = mm->root_node.fl_entry.next;
+       drm_mm_node_t *entry;
+
+       entry = list_entry(bnode, drm_mm_node_t, fl_entry);
+
+       if (entry->ml_entry.next != &mm->root_node.ml_entry ||
+           entry->fl_entry.next != &mm->root_node.fl_entry) {
+               DRM_ERROR("Memory manager not clean. Delaying takedown\n");
+               return;
+       }
+
+       list_del(&entry->fl_entry);
+       list_del(&entry->ml_entry);
+
+       drm_free(entry, sizeof(*entry), DRM_MEM_MM);
+}
+
+EXPORT_SYMBOL(drm_mm_takedown);
diff --git a/linux-core/drm_sman.c b/linux-core/drm_sman.c
new file mode 100644 (file)
index 0000000..9655793
--- /dev/null
@@ -0,0 +1,352 @@
+/**************************************************************************
+ * 
+ * Copyright 2006 Tungsten Graphics, Inc., Bismarck., ND., USA.
+ * All Rights Reserved.
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ * 
+ * 
+ **************************************************************************/
+/*
+ * Simple memory manager interface that keeps track on allocate regions on a
+ * per "owner" basis. All regions associated with an "owner" can be released
+ * with a simple call. Typically if the "owner" exists. The owner is any 
+ * "unsigned long" identifier. Can typically be a pointer to a file private
+ * struct or a context identifier.
+ *
+ * Authors:
+ * Thomas Hellström <thomas-at-tungstengraphics-dot-com>
+ */
+
+#include "drm_sman.h"
+
+typedef struct drm_owner_item {
+       drm_hash_item_t owner_hash;
+       struct list_head sman_list;
+       struct list_head mem_blocks;
+} drm_owner_item_t;
+
+void drm_sman_takedown(drm_sman_t * 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);
+}
+
+EXPORT_SYMBOL(drm_sman_takedown);
+
+int
+drm_sman_init(drm_sman_t * sman, unsigned int num_managers,
+             unsigned int user_order, unsigned int owner_order)
+{
+       int ret = 0;
+
+       sman->mm = (drm_sman_mm_t *) drm_calloc(num_managers, sizeof(*sman->mm),
+                                               DRM_MEM_MM);
+       if (!sman->mm) {
+               ret = -ENOMEM;
+               goto out;
+       }
+       sman->num_managers = num_managers;
+       INIT_LIST_HEAD(&sman->owner_items);
+       ret = drm_ht_create(&sman->owner_hash_tab, owner_order);
+       if (ret)
+               goto out1;
+       ret = drm_ht_create(&sman->user_hash_tab, user_order);
+       if (!ret)
+               goto out;
+
+       drm_ht_remove(&sman->owner_hash_tab);
+      out1:
+       drm_free(sman->mm, num_managers * sizeof(*sman->mm), DRM_MEM_MM);
+      out:
+       return ret;
+}
+
+EXPORT_SYMBOL(drm_sman_init);
+
+static void *drm_sman_mm_allocate(void *private, unsigned long size,
+                                 unsigned alignment)
+{
+       drm_mm_t *mm = (drm_mm_t *) private;
+       drm_mm_node_t *tmp;
+
+       tmp = drm_mm_search_free(mm, size, alignment, TRUE);
+       if (!tmp) {
+               return NULL;
+       }
+       tmp = drm_mm_get_block(tmp, size, alignment);
+       return tmp;
+}
+
+static void drm_sman_mm_free(void *private, void *ref)
+{
+       drm_mm_t *mm = (drm_mm_t *) private;
+       drm_mm_node_t *node = (drm_mm_node_t *) ref;
+
+       drm_mm_put_block(mm, node);
+}
+
+static void drm_sman_mm_destroy(void *private)
+{
+       drm_mm_t *mm = (drm_mm_t *) private;
+       drm_mm_takedown(mm);
+       drm_free(mm, sizeof(*mm), DRM_MEM_MM);
+}
+
+unsigned long drm_sman_mm_offset(void *private, void *ref)
+{
+       drm_mm_node_t *node = (drm_mm_node_t *) ref;
+       return node->start;
+}
+
+int
+drm_sman_set_range(drm_sman_t * sman, unsigned int manager,
+                  unsigned long start, unsigned long size)
+{
+       drm_sman_mm_t *sman_mm;
+       drm_mm_t *mm;
+       int ret;
+
+       BUG_ON(manager >= sman->num_managers);
+
+       sman_mm = &sman->mm[manager];
+       mm = drm_calloc(1, sizeof(*mm), DRM_MEM_MM);
+       if (!mm) {
+               return -ENOMEM;
+       }
+       sman_mm->private = mm;
+       ret = drm_mm_init(mm, start, size);
+
+       if (ret) {
+               drm_free(mm, sizeof(*mm), DRM_MEM_MM);
+               return ret;
+       }
+
+       sman_mm->allocate = drm_sman_mm_allocate;
+       sman_mm->free = drm_sman_mm_free;
+       sman_mm->destroy = drm_sman_mm_destroy;
+       sman_mm->offset = drm_sman_mm_offset;
+
+       return 0;
+}
+
+EXPORT_SYMBOL(drm_sman_set_range);
+
+int
+drm_sman_set_manager(drm_sman_t * sman, unsigned int manager,
+                    drm_sman_mm_t * allocator)
+{
+       BUG_ON(manager >= sman->num_managers);
+       sman->mm[manager] = *allocator;
+
+       return 0;
+}
+
+static drm_owner_item_t
+    * drm_sman_get_owner_item(drm_sman_t * sman, unsigned long owner)
+{
+       int ret;
+       drm_hash_item_t *owner_hash_item;
+       drm_owner_item_t *owner_item;
+
+       ret = drm_ht_find_item(&sman->owner_hash_tab, owner, &owner_hash_item);
+       if (!ret) {
+               return list_entry(owner_hash_item, drm_owner_item_t,
+                                 owner_hash);
+       }
+
+       owner_item = drm_calloc(1, sizeof(*owner_item), DRM_MEM_MM);
+       if (!owner_item)
+               goto out;
+
+       INIT_LIST_HEAD(&owner_item->mem_blocks);
+       owner_item->owner_hash.key = owner;
+       if (drm_ht_insert_item(&sman->owner_hash_tab, &owner_item->owner_hash))
+               goto out1;
+
+       list_add_tail(&owner_item->sman_list, &sman->owner_items);
+       return owner_item;
+
+      out1:
+       drm_free(owner_item, sizeof(*owner_item), DRM_MEM_MM);
+      out:
+       return NULL;
+}
+
+drm_memblock_item_t *drm_sman_alloc(drm_sman_t * sman, unsigned int manager,
+                                   unsigned long size, unsigned alignment,
+                                   unsigned long owner)
+{
+       void *tmp;
+       drm_sman_mm_t *sman_mm;
+       drm_owner_item_t *owner_item;
+       drm_memblock_item_t *memblock;
+
+       BUG_ON(manager >= sman->num_managers);
+
+       sman_mm = &sman->mm[manager];
+       tmp = sman_mm->allocate(sman_mm->private, size, alignment);
+
+       if (!tmp) {
+               return NULL;
+       }
+
+       memblock = drm_calloc(1, sizeof(*memblock), DRM_MEM_MM);
+
+       if (!memblock)
+               goto out;
+
+       memblock->mm_info = tmp;
+       memblock->mm = sman_mm;
+       memblock->sman = sman;
+
+       if (drm_ht_just_insert_please
+           (&sman->user_hash_tab, &memblock->user_hash,
+            (unsigned long)memblock, 32))
+               goto out1;
+
+       owner_item = drm_sman_get_owner_item(sman, owner);
+       if (!owner_item)
+               goto out2;
+
+       list_add_tail(&memblock->owner_list, &owner_item->mem_blocks);
+
+       return memblock;
+
+      out2:
+       drm_ht_remove_item(&sman->user_hash_tab, &memblock->user_hash);
+      out1:
+       drm_free(memblock, sizeof(*memblock), DRM_MEM_MM);
+      out:
+       sman_mm->free(sman_mm->private, tmp);
+
+       return NULL;
+}
+
+EXPORT_SYMBOL(drm_sman_alloc);
+
+static void drm_sman_free(drm_memblock_item_t * item)
+{
+       drm_sman_t *sman = item->sman;
+
+       list_del(&item->owner_list);
+       drm_ht_remove_item(&sman->user_hash_tab, &item->user_hash);
+       item->mm->free(item->mm->private, item->mm_info);
+       drm_free(item, sizeof(*item), DRM_MEM_MM);
+}
+
+int drm_sman_free_key(drm_sman_t * sman, unsigned int key)
+{
+       drm_hash_item_t *hash_item;
+       drm_memblock_item_t *memblock_item;
+
+       if (drm_ht_find_item(&sman->user_hash_tab, key, &hash_item))
+               return -EINVAL;
+
+       memblock_item = list_entry(hash_item, drm_memblock_item_t, user_hash);
+       drm_sman_free(memblock_item);
+       return 0;
+}
+
+EXPORT_SYMBOL(drm_sman_free_key);
+
+static void
+drm_sman_remove_owner(drm_sman_t * sman, drm_owner_item_t * owner_item)
+{
+       list_del(&owner_item->sman_list);
+       drm_ht_remove_item(&sman->owner_hash_tab, &owner_item->owner_hash);
+       drm_free(owner_item, sizeof(*owner_item), DRM_MEM_MM);
+}
+
+int drm_sman_owner_clean(drm_sman_t * sman, unsigned long owner)
+{
+
+       drm_hash_item_t *hash_item;
+       drm_owner_item_t *owner_item;
+
+       if (drm_ht_find_item(&sman->owner_hash_tab, owner, &hash_item)) {
+               return -1;
+       }
+
+       owner_item = list_entry(hash_item, drm_owner_item_t, owner_hash);
+       if (owner_item->mem_blocks.next == &owner_item->mem_blocks) {
+               drm_sman_remove_owner(sman, owner_item);
+               return -1;
+       }
+
+       return 0;
+}
+
+EXPORT_SYMBOL(drm_sman_owner_clean);
+
+static void
+drm_sman_do_owner_cleanup(drm_sman_t * sman, drm_owner_item_t * owner_item)
+{
+       drm_memblock_item_t *entry, *next;
+
+       list_for_each_entry_safe(entry, next, &owner_item->mem_blocks,
+                                owner_list) {
+               drm_sman_free(entry);
+       }
+       drm_sman_remove_owner(sman, owner_item);
+}
+
+void drm_sman_owner_cleanup(drm_sman_t * sman, unsigned long owner)
+{
+
+       drm_hash_item_t *hash_item;
+       drm_owner_item_t *owner_item;
+
+       if (drm_ht_find_item(&sman->owner_hash_tab, owner, &hash_item)) {
+
+               return;
+       }
+
+       owner_item = list_entry(hash_item, drm_owner_item_t, owner_hash);
+       drm_sman_do_owner_cleanup(sman, owner_item);
+}
+
+EXPORT_SYMBOL(drm_sman_owner_cleanup);
+
+void drm_sman_cleanup(drm_sman_t * sman)
+{
+       drm_owner_item_t *entry, *next;
+       unsigned int i;
+       drm_sman_mm_t *sman_mm;
+
+       list_for_each_entry_safe(entry, next, &sman->owner_items, sman_list) {
+               drm_sman_do_owner_cleanup(sman, entry);
+       }
+       if (sman->mm) {
+               for (i = 0; i < sman->num_managers; ++i) {
+                       sman_mm = &sman->mm[i];
+                       if (sman_mm->private) {
+                               sman_mm->destroy(sman_mm->private);
+                               sman_mm->private = NULL;
+                       }
+               }
+       }
+}
+
+EXPORT_SYMBOL(drm_sman_cleanup);
diff --git a/linux-core/drm_sman.h b/linux-core/drm_sman.h
new file mode 100644 (file)
index 0000000..7e537d9
--- /dev/null
@@ -0,0 +1,176 @@
+/**************************************************************************
+ * 
+ * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA.
+ * All Rights Reserved.
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * 
+ **************************************************************************/
+/*
+ * Simple memory MANager interface that keeps track on allocate regions on a
+ * per "owner" basis. All regions associated with an "owner" can be released
+ * with a simple call. Typically if the "owner" exists. The owner is any 
+ * "unsigned long" identifier. Can typically be a pointer to a file private
+ * struct or a context identifier.
+ *
+ * Authors:
+ * Thomas Hellström <thomas-at-tungstengraphics-dot-com>
+ */
+
+#ifndef DRM_SMAN_H
+#define DRM_SMAN_H
+
+#include "drmP.h"
+#include "drm_hashtab.h"
+
+/*
+ * A class that is an abstration of a simple memory allocator.
+ * The sman implementation provides a default such allocator 
+ * using the drm_mm.c implementation. But the user can replace it.
+ * See the SiS implementation, which may use the SiS FB kernel module
+ * for memory management.
+ */
+
+typedef struct drm_sman_mm {
+       /* private info. If allocated, needs to be destroyed by the destroy 
+          function */
+       void *private;
+
+       /* Allocate a memory block with given size and alignment. 
+          Return an opaque reference to the memory block */
+
+       void *(*allocate) (void *private, unsigned long size,
+                          unsigned alignment);
+
+       /* Free a memory block. "ref" is the opaque reference that we got from
+          the "alloc" function */
+
+       void (*free) (void *private, void *ref);
+
+       /* Free all resources associated with this allocator */
+
+       void (*destroy) (void *private);
+
+       /* Return a memory offset from the opaque reference returned from the
+          "alloc" function */
+
+       unsigned long (*offset) (void *private, void *ref);
+} drm_sman_mm_t;
+
+typedef struct drm_memblock_item {
+       struct list_head owner_list;
+       drm_hash_item_t user_hash;
+       void *mm_info;
+       drm_sman_mm_t *mm;
+       struct drm_sman *sman;
+} drm_memblock_item_t;
+
+typedef struct drm_sman {
+       drm_sman_mm_t *mm;
+       int num_managers;
+       drm_open_hash_t owner_hash_tab;
+       drm_open_hash_t user_hash_tab;
+       struct list_head owner_items;
+} drm_sman_t;
+
+/*
+ * Take down a memory manager. This function should only be called after a
+ * successful init and after a call to drm_sman_cleanup.
+ */
+
+extern void drm_sman_takedown(drm_sman_t * sman);
+
+/*
+ * Allocate structures for a manager. 
+ * num_managers are the number of memory pools to manage. (VRAM, AGP, ....) 
+ * user_order is the log2 of the number of buckets in the user hash table.
+ *            set this to approximately log2 of the max number of memory regions 
+ *            that will be allocated for _all_ pools together.
+ * owner_order is the log2 of the number of buckets in the owner hash table.
+ *            set this to approximately log2 of 
+ *            the number of client file connections that will
+ *            be using the manager.
+ *
+ */
+
+extern int drm_sman_init(drm_sman_t * sman, unsigned int num_managers,
+                        unsigned int user_order, unsigned int owner_order);
+
+/*
+ * Initialize a drm_mm.c allocator. Should be called only once for each
+ * manager unless a customized allogator is used.
+ */
+
+extern int drm_sman_set_range(drm_sman_t * sman, unsigned int manager,
+                             unsigned long start, unsigned long size);
+
+/*
+ * Initialize a customized allocator for one of the managers.
+ * (See the SiS module). The object pointed to by "allocator" is copied,
+ * so it can be destroyed after this call.
+ */
+
+extern int drm_sman_set_manager(drm_sman_t * sman, unsigned int mananger,
+                               drm_sman_mm_t * allocator);
+
+/*
+ * Allocate a memory block. Aligment is not implemented yet.
+ */
+
+extern drm_memblock_item_t *drm_sman_alloc(drm_sman_t * sman,
+                                          unsigned int manager,
+                                          unsigned long size,
+                                          unsigned alignment,
+                                          unsigned long owner);
+/*
+ * Free a memory block identified by its user hash key.
+ */
+
+extern int drm_sman_free_key(drm_sman_t * sman, unsigned int key);
+
+/*
+ * returns TRUE iff there are no stale memory blocks associated with this owner.
+ * Typically called to determine if we need to idle the hardware and call
+ * drm_sman_owner_cleanup. If there are no stale memory blocks, it removes all 
+ * resources associated with owner.
+ */
+
+extern int drm_sman_owner_clean(drm_sman_t * sman, unsigned long owner);
+
+/*
+ * Frees all stale memory blocks associated with this owner. Note that this 
+ * requires that the hardware is finished with all blocks, so the graphics engine
+ * should be idled before this call is made. This function also frees 
+ * any resources associated with "owner" and should be called when owner
+ * is not going to be referenced anymore.
+ */
+
+extern void drm_sman_owner_cleanup(drm_sman_t * sman, unsigned long owner);
+
+/*
+ * Frees all stale memory blocks associated with the memory manager.
+ * See idling above.
+ */
+
+extern void drm_sman_cleanup(drm_sman_t * sman);
+
+#endif
index 96c143a..5d55357 100644 (file)
@@ -36,12 +36,44 @@ static struct pci_device_id pciidlist[] = {
        sis_PCI_IDS
 };
 
+
+static int sis_driver_load(drm_device_t *dev, unsigned long chipset)
+{
+       drm_sis_private_t *dev_priv;
+        int ret;
+
+       dev_priv = drm_calloc(1, sizeof(drm_sis_private_t), DRM_MEM_DRIVER);
+       if (dev_priv == NULL)
+               return DRM_ERR(ENOMEM);
+
+       dev->dev_private = (void *)dev_priv;
+        dev_priv->chipset = chipset;
+        ret = drm_sman_init(&dev_priv->sman, 2, 12, 8);
+       if (ret) {
+               drm_free(dev_priv, sizeof(dev_priv), DRM_MEM_DRIVER);
+       }
+
+       return ret;
+}
+
+static int sis_driver_unload(drm_device_t *dev)
+{
+       drm_sis_private_t *dev_priv = dev->dev_private;
+
+        drm_sman_takedown(&dev_priv->sman);
+       drm_free(dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER);
+
+       return 0;
+}
+
+
 static int probe(struct pci_dev *pdev, const struct pci_device_id *ent);
 static struct drm_driver driver = {
        .driver_features = DRIVER_USE_AGP | DRIVER_USE_MTRR,
-       .context_ctor = sis_init_context,
+        .load = sis_driver_load,
+        .unload = sis_driver_unload,
        .context_dtor = sis_final_context,
-       .reclaim_buffers = drm_core_reclaim_buffers,
+       .reclaim_buffers = NULL,
        .get_map_ofs = drm_core_get_map_ofs,
        .get_reg_ofs = drm_core_get_reg_ofs,
        .ioctls = sis_ioctls,
diff --git a/linux-core/sis_mm.c b/linux-core/sis_mm.c
new file mode 100644 (file)
index 0000000..ee92453
--- /dev/null
@@ -0,0 +1,286 @@
+/**************************************************************************
+ * 
+ * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA.
+ * All Rights Reserved.
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * 
+ **************************************************************************/
+
+/*
+ * Authors:
+ *    Thomas Hellström <thomas-at-tungstengraphics-dot-com>
+ */
+
+#include "drmP.h"
+#include "sis_drm.h"
+#include "sis_drv.h"
+
+#if defined(__linux__)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+#include <video/sisfb.h>
+#else
+#include <linux/sisfb.h>
+#endif
+#endif
+
+#define VIDEO_TYPE 0
+#define AGP_TYPE 1
+
+#define SIS_MM_ALIGN_SHIFT 4
+#define SIS_MM_ALIGN_MASK ( (1 << SIS_MM_ALIGN_SHIFT) - 1)
+
+#if defined(__linux__) && defined(CONFIG_FB_SIS)
+/* fb management via fb device */
+
+#define SIS_MM_ALIGN_SHIFT 0
+#define SIS_MM_ALIGN_MASK 0
+
+static void *sis_sman_mm_allocate(void *private, unsigned long size,
+                                 unsigned alignment)
+{
+       struct sis_memreq req;
+
+       req.size = size;
+       sis_malloc(&req);
+       if (req.size == 0)
+               return NULL;
+       else
+               return (void *)~req.offset;
+}
+
+static void sis_sman_mm_free(void *private, void *ref)
+{
+       sis_free(~((unsigned long)ref));
+}
+
+static void sis_sman_mm_destroy(void *private)
+{
+       ;
+}
+
+unsigned long sis_sman_mm_offset(void *private, void *ref)
+{
+       return ~((unsigned long)ref);
+}
+
+#endif
+
+static int sis_fb_init(DRM_IOCTL_ARGS)
+{
+       DRM_DEVICE;
+       drm_sis_private_t *dev_priv = dev->dev_private;
+       drm_sis_fb_t fb;
+       int ret;
+
+       DRM_COPY_FROM_USER_IOCTL(fb, (drm_sis_fb_t __user *) data, sizeof(fb));
+
+       down(&dev->struct_sem);
+#if defined(__linux__) && defined(CONFIG_FB_SIS)
+       {
+               drm_sman_mm_t sman_mm;
+               sman_mm.private = (void *)0xFFFFFFFF;
+               sman_mm.allocate = sis_sman_mm_allocate;
+               sman_mm.free = sis_sman_mm_free;
+               sman_mm.destroy = sis_sman_mm_destroy;
+               sman_mm.offset = sis_sman_mm_offset;
+               ret =
+                   drm_sman_set_manager(&dev_priv->sman, VIDEO_TYPE, &sman_mm);
+       }
+#else
+       ret = drm_sman_set_range(&dev_priv->sman, VIDEO_TYPE, 0,
+                                fb.size >> SIS_MM_ALIGN_SHIFT);
+#endif
+
+       if (ret) {
+               DRM_ERROR("VRAM memory manager initialisation error\n");
+               up(&dev->struct_sem);
+               return ret;
+       }
+
+       dev_priv->vram_initialized = TRUE;
+       dev_priv->vram_offset = fb.offset;
+
+       up(&dev->struct_sem);
+       DRM_DEBUG("offset = %u, size = %u", fb.offset, fb.size);
+
+       return 0;
+}
+
+static int sis_drm_alloc(drm_device_t * dev, drm_file_t * priv,
+                        unsigned long data, int pool)
+{
+       drm_sis_private_t *dev_priv = dev->dev_private;
+       drm_sis_mem_t __user *argp = (drm_sis_mem_t __user *) data;
+       drm_sis_mem_t mem;
+       int retval = 0;
+       drm_memblock_item_t *item;
+
+       DRM_COPY_FROM_USER_IOCTL(mem, argp, sizeof(mem));
+
+       down(&dev->struct_sem);
+
+       if (FALSE == ((pool == 0) ? dev_priv->vram_initialized :
+                     dev_priv->agp_initialized)) {
+               DRM_ERROR
+                   ("Attempt to allocate from uninitialized memory manager.\n");
+               return DRM_ERR(EINVAL);
+       }
+
+       mem.size = (mem.size + SIS_MM_ALIGN_MASK) >> SIS_MM_ALIGN_SHIFT;
+       item = drm_sman_alloc(&dev_priv->sman, pool, mem.size, 0,
+                             (unsigned long)priv);
+
+       up(&dev->struct_sem);
+       if (item) {
+               mem.offset = ((pool == 0) ?
+                             dev_priv->vram_offset : dev_priv->agp_offset) +
+                   (item->mm->
+                    offset(item->mm, item->mm_info) << SIS_MM_ALIGN_SHIFT);
+               mem.free = item->user_hash.key;
+               mem.size = mem.size << SIS_MM_ALIGN_SHIFT;
+       } else {
+               mem.offset = 0;
+               mem.size = 0;
+               mem.free = 0;
+               retval = DRM_ERR(ENOMEM);
+       }
+
+       DRM_COPY_TO_USER_IOCTL(argp, mem, sizeof(mem));
+
+       DRM_DEBUG("alloc %d, size = %d, offset = %d\n", pool, mem.size,
+                 mem.offset);
+
+       return retval;
+}
+
+static int sis_drm_free(DRM_IOCTL_ARGS)
+{
+       DRM_DEVICE;
+       drm_sis_private_t *dev_priv = dev->dev_private;
+       drm_sis_mem_t mem;
+       int ret;
+
+       DRM_COPY_FROM_USER_IOCTL(mem, (drm_sis_mem_t __user *) data,
+                                sizeof(mem));
+
+       down(&dev->struct_sem);
+       ret = drm_sman_free_key(&dev_priv->sman, mem.free);
+       up(&dev->struct_sem);
+       DRM_DEBUG("free = 0x%lx\n", mem.free);
+
+       return ret;
+}
+
+static int sis_fb_alloc(DRM_IOCTL_ARGS)
+{
+       DRM_DEVICE;
+       return sis_drm_alloc(dev, priv, data, VIDEO_TYPE);
+}
+
+static int sis_ioctl_agp_init(DRM_IOCTL_ARGS)
+{
+       DRM_DEVICE;
+       drm_sis_private_t *dev_priv = dev->dev_private;
+       drm_sis_agp_t agp;
+       int ret;
+       dev_priv = dev->dev_private;
+
+       DRM_COPY_FROM_USER_IOCTL(agp, (drm_sis_agp_t __user *) data,
+                                sizeof(agp));
+       down(&dev->struct_sem);
+       ret = drm_sman_set_range(&dev_priv->sman, AGP_TYPE, 0,
+                                agp.size >> SIS_MM_ALIGN_SHIFT);
+
+       if (ret) {
+               DRM_ERROR("AGP memory manager initialisation error\n");
+               up(&dev->struct_sem);
+               return ret;
+       }
+
+       dev_priv->agp_initialized = TRUE;
+       dev_priv->agp_offset = agp.offset;
+       up(&dev->struct_sem);
+
+       DRM_DEBUG("offset = %u, size = %u", agp.offset, agp.size);
+       return 0;
+}
+
+static int sis_ioctl_agp_alloc(DRM_IOCTL_ARGS)
+{
+       DRM_DEVICE;
+
+       return sis_drm_alloc(dev, priv, data, AGP_TYPE);
+}
+
+int sis_final_context(struct drm_device *dev, int context)
+{
+       if (dev->ctx_count == 1 && dev->dev_private) {
+               drm_sis_private_t *dev_priv = dev->dev_private;
+
+               DRM_DEBUG("Last Context\n");
+               down(&dev->struct_sem);
+               drm_sman_cleanup(&dev_priv->sman);
+               dev_priv->vram_initialized = FALSE;
+               dev_priv->agp_initialized = FALSE;
+               up(&dev->struct_sem);
+       }
+       return 1;
+}
+
+void sis_reclaim_buffers_locked(drm_device_t * dev, struct file *filp)
+{
+       drm_sis_private_t *dev_priv = dev->dev_private;
+       drm_file_t *priv = filp->private_data;
+
+       down(&dev->struct_sem);
+       if (drm_sman_owner_clean(&dev_priv->sman, (unsigned long)priv)) {
+               up(&dev->struct_sem);
+               return;
+       }
+
+       if (dev->driver->dma_quiescent) {
+               dev->driver->dma_quiescent(dev);
+       }
+
+       drm_sman_owner_cleanup(&dev_priv->sman, (unsigned long)priv);
+       up(&dev->struct_sem);
+       return;
+}
+
+drm_ioctl_desc_t sis_ioctls[] = {
+       [DRM_IOCTL_NR(DRM_SIS_FB_ALLOC)] = {sis_fb_alloc, DRM_AUTH}
+       ,
+       [DRM_IOCTL_NR(DRM_SIS_FB_FREE)] = {sis_drm_free, DRM_AUTH}
+       ,
+       [DRM_IOCTL_NR(DRM_SIS_AGP_INIT)] =
+           {sis_ioctl_agp_init, DRM_AUTH | DRM_MASTER | DRM_ROOT_ONLY}
+       ,
+       [DRM_IOCTL_NR(DRM_SIS_AGP_ALLOC)] = {sis_ioctl_agp_alloc, DRM_AUTH}
+       ,
+       [DRM_IOCTL_NR(DRM_SIS_AGP_FREE)] = {sis_drm_free, DRM_AUTH}
+       ,
+       [DRM_IOCTL_NR(DRM_SIS_FB_INIT)] =
+           {sis_fb_init, DRM_AUTH | DRM_MASTER | DRM_ROOT_ONLY}
+};
+
+int sis_max_ioctl = DRM_ARRAY_SIZE(sis_ioctls);
diff --git a/linux-core/via_mm.c b/linux-core/via_mm.c
new file mode 100644 (file)
index 0000000..2881a1d
--- /dev/null
@@ -0,0 +1,203 @@
+/*
+ * Copyright 2006 Tungsten Graphics Inc., Bismarck, ND., USA.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+/*
+ * Authors: Thomas Hellström <thomas-at-tungstengraphics-dot-com>
+ */
+
+#include "drmP.h"
+#include "via_drm.h"
+#include "via_drv.h"
+#include "drm_sman.h"
+
+#define VIA_MM_ALIGN_SHIFT 4
+#define VIA_MM_ALIGN_MASK ( (1 << VIA_MM_ALIGN_SHIFT) - 1)
+
+int via_agp_init(DRM_IOCTL_ARGS)
+{
+       DRM_DEVICE;
+       drm_via_agp_t agp;
+       drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
+       int ret;
+
+       DRM_COPY_FROM_USER_IOCTL(agp, (drm_via_agp_t __user *) data,
+                                sizeof(agp));
+       down(&dev->struct_sem);
+       ret = drm_sman_set_range(&dev_priv->sman, VIA_MEM_AGP, 0,
+                                agp.size >> VIA_MM_ALIGN_SHIFT);
+
+       if (ret) {
+               DRM_ERROR("AGP memory manager initialisation error\n");
+               up(&dev->struct_sem);
+               return ret;
+       }
+
+       dev_priv->agp_initialized = TRUE;
+       dev_priv->agp_offset = agp.offset;
+       up(&dev->struct_sem);
+
+       DRM_DEBUG("offset = %u, size = %u", agp.offset, agp.size);
+       return 0;
+}
+
+int via_fb_init(DRM_IOCTL_ARGS)
+{
+       DRM_DEVICE;
+       drm_via_fb_t fb;
+       drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
+       int ret;
+
+       DRM_COPY_FROM_USER_IOCTL(fb, (drm_via_fb_t __user *) data, sizeof(fb));
+
+       down(&dev->struct_sem);
+       ret = drm_sman_set_range(&dev_priv->sman, VIA_MEM_VIDEO, 0,
+                                fb.size >> VIA_MM_ALIGN_SHIFT);
+
+       if (ret) {
+               DRM_ERROR("VRAM memory manager initialisation error\n");
+               up(&dev->struct_sem);
+               return ret;
+       }
+
+       dev_priv->vram_initialized = TRUE;
+       dev_priv->vram_offset = fb.offset;
+
+       up(&dev->struct_sem);
+       DRM_DEBUG("offset = %u, size = %u", fb.offset, fb.size);
+
+       return 0;
+
+}
+
+int via_final_context(struct drm_device *dev, int context)
+{
+       drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
+
+       via_release_futex(dev_priv, context);
+
+#if defined(__linux__)
+       /* Linux specific until context tracking code gets ported to BSD */
+       /* Last context, perform cleanup */
+       if (dev->ctx_count == 1 && dev->dev_private) {
+               DRM_DEBUG("Last Context\n");
+               if (dev->irq)
+                       drm_irq_uninstall(dev);
+               via_cleanup_futex(dev_priv);
+               via_do_cleanup_map(dev);
+
+               down(&dev->struct_sem);
+               drm_sman_cleanup(&dev_priv->sman);
+               dev_priv->vram_initialized = FALSE;
+               dev_priv->agp_initialized = FALSE;
+               up(&dev->struct_sem);
+       }
+#endif
+
+       return 1;
+}
+
+int via_mem_alloc(DRM_IOCTL_ARGS)
+{
+       DRM_DEVICE;
+
+       drm_via_mem_t mem;
+       int retval = 0;
+       drm_memblock_item_t *item;
+       drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
+
+       DRM_COPY_FROM_USER_IOCTL(mem, (drm_via_mem_t __user *) data,
+                                sizeof(mem));
+
+       if (mem.type > VIA_MEM_AGP) {
+               DRM_ERROR("Unknown memory type allocation\n");
+               return DRM_ERR(EINVAL);
+       }
+       down(&dev->struct_sem);
+       if (FALSE == ((mem.type == VIA_MEM_VIDEO) ? dev_priv->vram_initialized :
+                     dev_priv->agp_initialized)) {
+               DRM_ERROR
+                   ("Attempt to allocate from uninitialized memory manager.\n");
+               up(&dev->struct_sem);
+               return DRM_ERR(EINVAL);
+       }
+
+       mem.size = (mem.size + VIA_MM_ALIGN_MASK) >> VIA_MM_ALIGN_SHIFT;
+       item = drm_sman_alloc(&dev_priv->sman, mem.type, mem.size, 0,
+                             (unsigned long)priv);
+       up(&dev->struct_sem);
+       if (item) {
+               mem.offset = ((mem.type == VIA_MEM_VIDEO) ?
+                             dev_priv->vram_offset : dev_priv->agp_offset) +
+                   (item->mm->
+                    offset(item->mm, item->mm_info) << VIA_MM_ALIGN_SHIFT);
+               mem.index = item->user_hash.key;
+               mem.size = mem.size << VIA_MM_ALIGN_SHIFT;
+       } else {
+               mem.offset = 0;
+               mem.size = 0;
+               mem.index = 0;
+               DRM_ERROR("Video memory allocation failed\n");
+               retval = DRM_ERR(ENOMEM);
+       }
+       DRM_COPY_TO_USER_IOCTL((drm_via_mem_t __user *) data, mem, sizeof(mem));
+
+       return retval;
+}
+
+int via_mem_free(DRM_IOCTL_ARGS)
+{
+       DRM_DEVICE;
+       drm_via_private_t *dev_priv = dev->dev_private;
+       drm_via_mem_t mem;
+       int ret;
+
+       DRM_COPY_FROM_USER_IOCTL(mem, (drm_via_mem_t __user *) data,
+                                sizeof(mem));
+
+       down(&dev->struct_sem);
+       ret = drm_sman_free_key(&dev_priv->sman, mem.index);
+       up(&dev->struct_sem);
+       DRM_DEBUG("free = 0x%lx\n", mem.index);
+
+       return ret;
+}
+
+void via_reclaim_buffers_locked(drm_device_t * dev, struct file *filp)
+{
+       drm_via_private_t *dev_priv = dev->dev_private;
+       drm_file_t *priv = filp->private_data;
+
+       down(&dev->struct_sem);
+       if (drm_sman_owner_clean(&dev_priv->sman, (unsigned long)priv)) {
+               up(&dev->struct_sem);
+               return;
+       }
+
+       if (dev->driver->dma_quiescent) {
+               dev->driver->dma_quiescent(dev);
+       }
+
+       drm_sman_owner_cleanup(&dev_priv->sman, (unsigned long)priv);
+       up(&dev->struct_sem);
+       return;
+}
index e218e52..037bc49 100644 (file)
 #define DRIVER_AUTHOR          "SIS"
 #define DRIVER_NAME            "sis"
 #define DRIVER_DESC            "SIS 300/630/540"
-#define DRIVER_DATE            "20030826"
+#define DRIVER_DATE            "20060529"
 #define DRIVER_MAJOR           1
-#define DRIVER_MINOR           1
+#define DRIVER_MINOR           2
 #define DRIVER_PATCHLEVEL      0
 
+#if defined(__linux__)
+#define SIS_HAVE_CORE_MM
+#endif
+
+#ifdef SIS_HAVE_CORE_MM
+
+#include "drm_sman.h"
+typedef struct drm_sis_private {
+        drm_local_map_t *mmio;
+        unsigned idle_fault;
+        drm_sman_t sman;
+        unsigned long chipset;
+        int vram_initialized;
+        int agp_initialized;
+        unsigned long vram_offset;
+        unsigned long agp_offset;
+} drm_sis_private_t;
+
+extern void sis_reclaim_buffers_locked(drm_device_t *dev, struct file *filp);
+
+#else
 #include "sis_ds.h"
 
 typedef struct drm_sis_private {
@@ -47,6 +68,10 @@ typedef struct drm_sis_private {
 } drm_sis_private_t;
 
 extern int sis_init_context(drm_device_t * dev, int context);
+
+#endif
+
+
 extern int sis_final_context(drm_device_t * dev, int context);
 
 extern drm_ioctl_desc_t sis_ioctls[];
index dbaf857..4be7e24 100644 (file)
  * backwards incompatibilities, (which should be avoided whenever possible).
  */
 
-#define VIA_DRM_DRIVER_DATE            "20060111"
+#define VIA_DRM_DRIVER_DATE            "20060528"
 
 #define VIA_DRM_DRIVER_MAJOR           2
-#define VIA_DRM_DRIVER_MINOR           9
-#define VIA_DRM_DRIVER_PATCHLEVEL      1
+#define VIA_DRM_DRIVER_MINOR           10
+#define VIA_DRM_DRIVER_PATCHLEVEL      0
 #define VIA_DRM_DRIVER_VERSION          (((VIA_DRM_DRIVER_MAJOR) << 16) | (VIA_DRM_DRIVER_MINOR))
 
 #define VIA_NR_SAREA_CLIPRECTS                 8
index 2dc72ec..a7509cf 100644 (file)
@@ -46,7 +46,9 @@ static struct drm_driver driver = {
            DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL,
        .load = via_driver_load,
        .unload = via_driver_unload,
+#ifndef VIA_HAVE_CORE_MM
        .context_ctor = via_init_context,
+#endif
        .context_dtor = via_final_context,
        .vblank_wait = via_driver_vblank_wait,
        .irq_preinstall = via_driver_irq_preinstall,
@@ -56,6 +58,9 @@ static struct drm_driver driver = {
        .dma_quiescent = via_driver_dma_quiescent,
        .dri_library_name = dri_library_name,
        .reclaim_buffers = drm_core_reclaim_buffers,
+#ifdef VIA_HAVE_CORE_MM
+       .reclaim_buffers_locked = via_reclaim_buffers_locked,
+#endif
        .get_map_ofs = drm_core_get_map_ofs,
        .get_reg_ofs = drm_core_get_reg_ofs,
        .ioctls = via_ioctls,
index 0e29815..2e9e10c 100644 (file)
@@ -24,6 +24,7 @@
 #ifndef _VIA_DRV_H_
 #define _VIA_DRV_H_
 
+#include "drm_sman.h"
 #define DRIVER_AUTHOR  "Various"
 
 #define DRIVER_NAME            "via"
@@ -39,6 +40,7 @@
  * the DMA blit code has been implemented for FreeBSD.
  */
 #define VIA_HAVE_DMABLIT 1
+#define VIA_HAVE_CORE_MM 1
 #endif
 
 #define VIA_PCI_BUF_SIZE 60000
@@ -88,6 +90,15 @@ typedef struct drm_via_private {
        uint32_t irq_enable_mask; 
        uint32_t irq_pending_mask;      
        int *irq_map;
+        /* Memory manager stuff */
+#ifdef VIA_HAVE_CORE_MM
+       unsigned idle_fault;
+       drm_sman_t sman;
+       int vram_initialized;
+       int agp_initialized;
+        unsigned long vram_offset;
+        unsigned long agp_offset;
+#endif
 #ifdef VIA_HAVE_DMABLIT
        drm_via_blitq_t blit_queues[VIA_NUM_BLIT_ENGINES];
 #endif
@@ -121,7 +132,6 @@ extern int via_dma_blit( DRM_IOCTL_ARGS );
 
 extern int via_driver_load(drm_device_t *dev, unsigned long chipset);
 extern int via_driver_unload(drm_device_t *dev);
-extern int via_init_context(drm_device_t * dev, int context);
 extern int via_final_context(drm_device_t * dev, int context);
 
 extern int via_do_cleanup_map(drm_device_t * dev);
@@ -140,6 +150,13 @@ extern void via_cleanup_futex(drm_via_private_t *dev_priv);
 extern void via_release_futex(drm_via_private_t *dev_priv, int context);
 extern int via_driver_irq_wait(drm_device_t * dev, unsigned int irq,
                               int force_sequence, unsigned int *sequence);
+
+#ifdef VIA_HAVE_CORE_MM
+extern void via_reclaim_buffers_locked(drm_device_t *dev, struct file *filp);
+#else
+extern int via_init_context(drm_device_t * dev, int context);
+#endif
+
 #ifdef VIA_HAVE_DMABLIT
 extern void via_dmablit_handler(drm_device_t *dev, int engine, int from_irq);
 extern void via_init_dmablit(drm_device_t *dev);
index 2b653d7..71967d6 100644 (file)
@@ -99,6 +99,7 @@ int via_map_init(DRM_IOCTL_ARGS)
 int via_driver_load(drm_device_t *dev, unsigned long chipset)
 {
        drm_via_private_t *dev_priv;
+       int ret = 0;
 
        dev_priv = drm_calloc(1, sizeof(drm_via_private_t), DRM_MEM_DRIVER);
        if (dev_priv == NULL)
@@ -109,13 +110,22 @@ int via_driver_load(drm_device_t *dev, unsigned long chipset)
        if (chipset == VIA_PRO_GROUP_A)
                dev_priv->pro_group_a = 1;
 
-       return 0;
+#ifdef VIA_HAVE_CORE_MM
+       ret = drm_sman_init(&dev_priv->sman, 2, 12, 8);
+       if (ret) {
+               drm_free(dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER);
+       }
+#endif
+       return ret;
 }
 
 int via_driver_unload(drm_device_t *dev)
 {
        drm_via_private_t *dev_priv = dev->dev_private;
 
+#ifdef VIA_HAVE_CORE_MM
+       drm_sman_takedown(&dev_priv->sman);
+#endif
        drm_free(dev_priv, sizeof(drm_via_private_t), DRM_MEM_DRIVER);
 
        return 0;