mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-12 05:48:40 +00:00
Merge branch 'drm-patches' of git://git.kernel.org/pub/scm/linux/kernel/git/airlied/drm-2.6
* 'drm-patches' of git://git.kernel.org/pub/scm/linux/kernel/git/airlied/drm-2.6: (36 commits) drm: Use register writes instead of BITBLT_MULTI packets for buffer swap blits drm: use radeon specific names for radeon flags drm: add device/vendor id to drm_device_t for compat with FreeBSD drivers drm: allow multiple addMaps with the same 32-bit map offsset. drm: fd.o Bug #7595: Avoid u32 overflows in radeon_check_and_fixup_offset(). drm: Fix hashtab implementation leaking illegal error codes to user space. drm: domain changes broke ppc r200 drm: fixup setversion return codes.. drm: fixup i915 error codes drm: realign sosme radeon code with drm git tree drm: realign via driver with drm git tree drm: remove hash tables on drm exit drm: cleanups drm: i810_dma.c: fix pointer arithmetic for 64-bit target drm: avoid kernel oops in some error paths calling drm_lastclose drm: allow detection of new VIA chipsets drm: fix i965 build bug drm: remove FALSE/TRUE that snuck in with simple memory manager changes. drm: Add support for Intel i965G chipsets. drm: add better explanation for i830/i915 ...
This commit is contained in:
commit
e823aff2d6
42 changed files with 1890 additions and 1784 deletions
|
@ -60,7 +60,9 @@ config DRM_I830
|
|||
Choose this option if you have a system that has Intel 830M, 845G,
|
||||
852GM, 855GM or 865G integrated graphics. If M is selected, the
|
||||
module will be called i830. AGP support is required for this driver
|
||||
to work. This driver will eventually be replaced by the i915 one.
|
||||
to work. This driver is used by the older X releases X.org 6.7 and
|
||||
XFree86 4.3. If unsure, build this and i915 as modules and the X server
|
||||
will load the correct one.
|
||||
|
||||
config DRM_I915
|
||||
tristate "i915 driver"
|
||||
|
@ -68,8 +70,9 @@ config DRM_I915
|
|||
Choose this option if you have a system that has Intel 830M, 845G,
|
||||
852GM, 855GM 865G or 915G integrated graphics. If M is selected, the
|
||||
module will be called i915. AGP support is required for this driver
|
||||
to work. This driver will eventually replace the I830 driver, when
|
||||
later release of X start to use the new DDX and DRI.
|
||||
to work. This driver is used by the Intel driver in X.org 6.8 and
|
||||
XFree86 4.4 and above. If unsure, build this and i830 as modules and
|
||||
the X server will load the correct one.
|
||||
|
||||
endchoice
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ 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_agpsupport.o drm_scatter.o ati_pcigart.o drm_pci.o \
|
||||
drm_sysfs.o
|
||||
drm_sysfs.o drm_hashtab.o drm_sman.o drm_mm.o
|
||||
|
||||
tdfx-objs := tdfx_drv.o
|
||||
r128-objs := r128_drv.o r128_cce.o r128_state.o r128_irq.o
|
||||
|
@ -16,9 +16,9 @@ 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
|
||||
ffb-objs := ffb_drv.o ffb_context.o
|
||||
sis-objs := sis_drv.o sis_ds.o sis_mm.o
|
||||
sis-objs := sis_drv.o sis_mm.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
|
||||
|
||||
ifeq ($(CONFIG_COMPAT),y)
|
||||
drm-objs += drm_ioc32.o
|
||||
|
|
|
@ -79,6 +79,7 @@
|
|||
#define __OS_HAS_MTRR (defined(CONFIG_MTRR))
|
||||
|
||||
#include "drm_os_linux.h"
|
||||
#include "drm_hashtab.h"
|
||||
|
||||
/***********************************************************************/
|
||||
/** \name DRM template customization defaults */
|
||||
|
@ -104,7 +105,7 @@
|
|||
#define DRM_DEBUG_CODE 2 /**< Include debugging code if > 1, then
|
||||
also include looping detection. */
|
||||
|
||||
#define DRM_HASH_SIZE 16 /**< Size of key hash table. Must be power of 2. */
|
||||
#define DRM_MAGIC_HASH_ORDER 4 /**< Size of key hash table. Must be power of 2. */
|
||||
#define DRM_KERNEL_CONTEXT 0 /**< Change drm_resctx if changed */
|
||||
#define DRM_RESERVED_CONTEXTS 1 /**< Change drm_resctx if changed */
|
||||
#define DRM_LOOPING_LIMIT 5000000
|
||||
|
@ -134,19 +135,12 @@
|
|||
#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)
|
||||
|
||||
/*@}*/
|
||||
|
||||
/***********************************************************************/
|
||||
/** \name Backward compatibility section */
|
||||
/*@{*/
|
||||
|
||||
#define DRM_RPR_ARG(vma) vma,
|
||||
|
||||
#define VM_OFFSET(vma) ((vma)->vm_pgoff << PAGE_SHIFT)
|
||||
#define DRM_MAP_HASH_OFFSET 0x10000000
|
||||
|
||||
/*@}*/
|
||||
|
||||
|
@ -211,8 +205,6 @@
|
|||
/*@{*/
|
||||
|
||||
#define DRM_ARRAY_SIZE(x) ARRAY_SIZE(x)
|
||||
#define DRM_MIN(a,b) min(a,b)
|
||||
#define DRM_MAX(a,b) max(a,b)
|
||||
|
||||
#define DRM_LEFTCOUNT(x) (((x)->rp + (x)->count - (x)->wp) % ((x)->count + 1))
|
||||
#define DRM_BUFCOUNT(x) ((x)->count - DRM_LEFTCOUNT(x))
|
||||
|
@ -286,7 +278,8 @@ typedef struct drm_devstate {
|
|||
} drm_devstate_t;
|
||||
|
||||
typedef struct drm_magic_entry {
|
||||
drm_magic_t magic;
|
||||
drm_hash_item_t hash_item;
|
||||
struct list_head head;
|
||||
struct drm_file *priv;
|
||||
struct drm_magic_entry *next;
|
||||
} drm_magic_entry_t;
|
||||
|
@ -493,6 +486,7 @@ typedef struct drm_sigdata {
|
|||
*/
|
||||
typedef struct drm_map_list {
|
||||
struct list_head head; /**< list head */
|
||||
drm_hash_item_t hash;
|
||||
drm_map_t *map; /**< mapping */
|
||||
unsigned int user_token;
|
||||
} drm_map_list_t;
|
||||
|
@ -527,6 +521,22 @@ 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
|
||||
|
@ -646,13 +656,15 @@ typedef struct drm_device {
|
|||
/*@{ */
|
||||
drm_file_t *file_first; /**< file list head */
|
||||
drm_file_t *file_last; /**< file list tail */
|
||||
drm_magic_head_t magiclist[DRM_HASH_SIZE]; /**< magic hash table */
|
||||
drm_open_hash_t magiclist; /**< magic hash table */
|
||||
struct list_head magicfree;
|
||||
/*@} */
|
||||
|
||||
/** \name Memory management */
|
||||
/*@{ */
|
||||
drm_map_list_t *maplist; /**< Linked list of regions */
|
||||
int map_count; /**< Number of mappable regions */
|
||||
drm_open_hash_t map_hash; /**< User token hash table for maps */
|
||||
|
||||
/** \name Context handle management */
|
||||
/*@{ */
|
||||
|
@ -711,10 +723,8 @@ typedef struct drm_device {
|
|||
drm_agp_head_t *agp; /**< AGP data */
|
||||
|
||||
struct pci_dev *pdev; /**< PCI device structure */
|
||||
int pci_domain; /**< PCI bus domain number */
|
||||
int pci_bus; /**< PCI bus number */
|
||||
int pci_slot; /**< PCI slot number */
|
||||
int pci_func; /**< PCI function number */
|
||||
int pci_vendor; /**< PCI vendor id */
|
||||
int pci_device; /**< PCI device id */
|
||||
#ifdef __alpha__
|
||||
struct pci_controller *hose;
|
||||
#endif
|
||||
|
@ -736,6 +746,12 @@ static __inline__ int drm_core_check_feature(struct drm_device *dev,
|
|||
return ((dev->driver->driver_features & feature) ? 1 : 0);
|
||||
}
|
||||
|
||||
#ifdef __alpha__
|
||||
#define drm_get_pci_domain(dev) dev->hose->bus->number
|
||||
#else
|
||||
#define drm_get_pci_domain(dev) 0
|
||||
#endif
|
||||
|
||||
#if __OS_HAS_AGP
|
||||
static inline int drm_core_has_AGP(struct drm_device *dev)
|
||||
{
|
||||
|
@ -1011,6 +1027,18 @@ extern struct class_device *drm_sysfs_device_add(struct 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)
|
||||
|
|
|
@ -35,20 +35,6 @@
|
|||
|
||||
#include "drmP.h"
|
||||
|
||||
/**
|
||||
* Generate a hash key from a magic.
|
||||
*
|
||||
* \param magic magic.
|
||||
* \return hash key.
|
||||
*
|
||||
* The key is the modulus of the hash table size, #DRM_HASH_SIZE, which must be
|
||||
* a power of 2.
|
||||
*/
|
||||
static int drm_hash_magic(drm_magic_t magic)
|
||||
{
|
||||
return magic & (DRM_HASH_SIZE - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the file with the given magic number.
|
||||
*
|
||||
|
@ -63,14 +49,12 @@ static drm_file_t *drm_find_file(drm_device_t * dev, drm_magic_t magic)
|
|||
{
|
||||
drm_file_t *retval = NULL;
|
||||
drm_magic_entry_t *pt;
|
||||
int hash = drm_hash_magic(magic);
|
||||
drm_hash_item_t *hash;
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
for (pt = dev->magiclist[hash].head; pt; pt = pt->next) {
|
||||
if (pt->magic == magic) {
|
||||
retval = pt->priv;
|
||||
break;
|
||||
}
|
||||
if (!drm_ht_find_item(&dev->magiclist, (unsigned long)magic, &hash)) {
|
||||
pt = drm_hash_entry(hash, drm_magic_entry_t, hash_item);
|
||||
retval = pt->priv;
|
||||
}
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return retval;
|
||||
|
@ -90,28 +74,20 @@ static drm_file_t *drm_find_file(drm_device_t * dev, drm_magic_t magic)
|
|||
static int drm_add_magic(drm_device_t * dev, drm_file_t * priv,
|
||||
drm_magic_t magic)
|
||||
{
|
||||
int hash;
|
||||
drm_magic_entry_t *entry;
|
||||
|
||||
DRM_DEBUG("%d\n", magic);
|
||||
|
||||
hash = drm_hash_magic(magic);
|
||||
entry = drm_alloc(sizeof(*entry), DRM_MEM_MAGIC);
|
||||
if (!entry)
|
||||
return -ENOMEM;
|
||||
memset(entry, 0, sizeof(*entry));
|
||||
entry->magic = magic;
|
||||
entry->priv = priv;
|
||||
entry->next = NULL;
|
||||
|
||||
entry->hash_item.key = (unsigned long)magic;
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
if (dev->magiclist[hash].tail) {
|
||||
dev->magiclist[hash].tail->next = entry;
|
||||
dev->magiclist[hash].tail = entry;
|
||||
} else {
|
||||
dev->magiclist[hash].head = entry;
|
||||
dev->magiclist[hash].tail = entry;
|
||||
}
|
||||
drm_ht_insert_item(&dev->magiclist, &entry->hash_item);
|
||||
list_add_tail(&entry->head, &dev->magicfree);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
return 0;
|
||||
|
@ -128,34 +104,24 @@ static int drm_add_magic(drm_device_t * dev, drm_file_t * priv,
|
|||
*/
|
||||
static int drm_remove_magic(drm_device_t * dev, drm_magic_t magic)
|
||||
{
|
||||
drm_magic_entry_t *prev = NULL;
|
||||
drm_magic_entry_t *pt;
|
||||
int hash;
|
||||
drm_hash_item_t *hash;
|
||||
|
||||
DRM_DEBUG("%d\n", magic);
|
||||
hash = drm_hash_magic(magic);
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
for (pt = dev->magiclist[hash].head; pt; prev = pt, pt = pt->next) {
|
||||
if (pt->magic == magic) {
|
||||
if (dev->magiclist[hash].head == pt) {
|
||||
dev->magiclist[hash].head = pt->next;
|
||||
}
|
||||
if (dev->magiclist[hash].tail == pt) {
|
||||
dev->magiclist[hash].tail = prev;
|
||||
}
|
||||
if (prev) {
|
||||
prev->next = pt->next;
|
||||
}
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return 0;
|
||||
}
|
||||
if (drm_ht_find_item(&dev->magiclist, (unsigned long)magic, &hash)) {
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return -EINVAL;
|
||||
}
|
||||
pt = drm_hash_entry(hash, drm_magic_entry_t, hash_item);
|
||||
drm_ht_remove_item(&dev->magiclist, hash);
|
||||
list_del(&pt->head);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
drm_free(pt, sizeof(*pt), DRM_MEM_MAGIC);
|
||||
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -65,44 +65,30 @@ static drm_map_list_t *drm_find_matching_map(drm_device_t *dev,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Used to allocate 32-bit handles for mappings.
|
||||
*/
|
||||
#define START_RANGE 0x10000000
|
||||
#define END_RANGE 0x40000000
|
||||
|
||||
#ifdef _LP64
|
||||
static __inline__ unsigned int HandleID(unsigned long lhandle,
|
||||
drm_device_t *dev)
|
||||
static int drm_map_handle(drm_device_t *dev, drm_hash_item_t *hash,
|
||||
unsigned long user_token, int hashed_handle)
|
||||
{
|
||||
static unsigned int map32_handle = START_RANGE;
|
||||
unsigned int hash;
|
||||
|
||||
if (lhandle & 0xffffffff00000000) {
|
||||
hash = map32_handle;
|
||||
map32_handle += PAGE_SIZE;
|
||||
if (map32_handle > END_RANGE)
|
||||
map32_handle = START_RANGE;
|
||||
} else
|
||||
hash = lhandle;
|
||||
|
||||
while (1) {
|
||||
drm_map_list_t *_entry;
|
||||
list_for_each_entry(_entry, &dev->maplist->head, head) {
|
||||
if (_entry->user_token == hash)
|
||||
break;
|
||||
}
|
||||
if (&_entry->head == &dev->maplist->head)
|
||||
return hash;
|
||||
|
||||
hash += PAGE_SIZE;
|
||||
map32_handle += PAGE_SIZE;
|
||||
}
|
||||
}
|
||||
int use_hashed_handle;
|
||||
#if (BITS_PER_LONG == 64)
|
||||
use_hashed_handle = ((user_token & 0xFFFFFFFF00000000UL) || hashed_handle);
|
||||
#elif (BITS_PER_LONG == 32)
|
||||
use_hashed_handle = hashed_handle;
|
||||
#else
|
||||
# define HandleID(x,dev) (unsigned int)(x)
|
||||
#error Unsupported long size. Neither 64 nor 32 bits.
|
||||
#endif
|
||||
|
||||
if (!use_hashed_handle) {
|
||||
int ret;
|
||||
hash->key = user_token;
|
||||
ret = drm_ht_insert_item(&dev->map_hash, hash);
|
||||
if (ret != -EINVAL)
|
||||
return ret;
|
||||
}
|
||||
return drm_ht_just_insert_please(&dev->map_hash, hash,
|
||||
user_token, 32 - PAGE_SHIFT - 3,
|
||||
PAGE_SHIFT, DRM_MAP_HASH_OFFSET);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ioctl to specify a range of memory that is available for mapping by a non-root process.
|
||||
*
|
||||
|
@ -123,6 +109,8 @@ static int drm_addmap_core(drm_device_t * dev, unsigned int offset,
|
|||
drm_map_t *map;
|
||||
drm_map_list_t *list;
|
||||
drm_dma_handle_t *dmah;
|
||||
unsigned long user_token;
|
||||
int ret;
|
||||
|
||||
map = drm_alloc(sizeof(*map), DRM_MEM_MAPS);
|
||||
if (!map)
|
||||
|
@ -257,11 +245,20 @@ static int drm_addmap_core(drm_device_t * dev, unsigned int offset,
|
|||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
list_add(&list->head, &dev->maplist->head);
|
||||
|
||||
/* Assign a 32-bit handle */
|
||||
/* We do it here so that dev->struct_mutex protects the increment */
|
||||
list->user_token = HandleID(map->type == _DRM_SHM
|
||||
? (unsigned long)map->handle
|
||||
: map->offset, dev);
|
||||
user_token = (map->type == _DRM_SHM) ? (unsigned long)map->handle :
|
||||
map->offset;
|
||||
ret = drm_map_handle(dev, &list->hash, user_token, 0);
|
||||
if (ret) {
|
||||
drm_free(map, sizeof(*map), DRM_MEM_MAPS);
|
||||
drm_free(list, sizeof(*list), DRM_MEM_MAPS);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
list->user_token = list->hash.key;
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
*maplist = list;
|
||||
|
@ -346,6 +343,7 @@ int drm_rmmap_locked(drm_device_t *dev, drm_local_map_t *map)
|
|||
|
||||
if (r_list->map == map) {
|
||||
list_del(list);
|
||||
drm_ht_remove_key(&dev->map_hash, r_list->user_token);
|
||||
drm_free(list, sizeof(*list), DRM_MEM_MAPS);
|
||||
break;
|
||||
}
|
||||
|
@ -441,8 +439,10 @@ int drm_rmmap_ioctl(struct inode *inode, struct file *filp,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!map)
|
||||
if (!map) {
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Register and framebuffer maps are permanent */
|
||||
if ((map->type == _DRM_REGISTERS) || (map->type == _DRM_FRAME_BUFFER)) {
|
||||
|
|
|
@ -118,7 +118,7 @@ static drm_ioctl_desc_t drm_ioctls[] = {
|
|||
[DRM_IOCTL_NR(DRM_IOCTL_WAIT_VBLANK)] = {drm_wait_vblank, 0},
|
||||
};
|
||||
|
||||
#define DRIVER_IOCTL_COUNT DRM_ARRAY_SIZE( drm_ioctls )
|
||||
#define DRIVER_IOCTL_COUNT ARRAY_SIZE( drm_ioctls )
|
||||
|
||||
/**
|
||||
* Take down the DRM device.
|
||||
|
@ -155,12 +155,13 @@ int drm_lastclose(drm_device_t * dev)
|
|||
del_timer(&dev->timer);
|
||||
|
||||
/* Clear pid list */
|
||||
for (i = 0; i < DRM_HASH_SIZE; i++) {
|
||||
for (pt = dev->magiclist[i].head; pt; pt = next) {
|
||||
next = pt->next;
|
||||
if (dev->magicfree.next) {
|
||||
list_for_each_entry_safe(pt, next, &dev->magicfree, head) {
|
||||
list_del(&pt->head);
|
||||
drm_ht_remove_item(&dev->magiclist, &pt->hash_item);
|
||||
drm_free(pt, sizeof(*pt), DRM_MEM_MAGIC);
|
||||
}
|
||||
dev->magiclist[i].head = dev->magiclist[i].tail = NULL;
|
||||
drm_ht_remove(&dev->magiclist);
|
||||
}
|
||||
|
||||
/* Clear AGP information */
|
||||
|
@ -299,6 +300,7 @@ static void drm_cleanup(drm_device_t * dev)
|
|||
if (dev->maplist) {
|
||||
drm_free(dev->maplist, sizeof(*dev->maplist), DRM_MEM_MAPS);
|
||||
dev->maplist = NULL;
|
||||
drm_ht_remove(&dev->map_hash);
|
||||
}
|
||||
|
||||
drm_ctxbitmap_cleanup(dev);
|
||||
|
|
|
@ -53,6 +53,8 @@ static int drm_setup(drm_device_t * dev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
dev->magicfree.next = NULL;
|
||||
|
||||
/* prebuild the SAREA */
|
||||
i = drm_addmap(dev, 0, SAREA_MAX, _DRM_SHM, _DRM_CONTAINS_LOCK, &map);
|
||||
if (i != 0)
|
||||
|
@ -69,13 +71,11 @@ static int drm_setup(drm_device_t * dev)
|
|||
return i;
|
||||
}
|
||||
|
||||
for (i = 0; i < DRM_ARRAY_SIZE(dev->counts); i++)
|
||||
for (i = 0; i < ARRAY_SIZE(dev->counts); i++)
|
||||
atomic_set(&dev->counts[i], 0);
|
||||
|
||||
for (i = 0; i < DRM_HASH_SIZE; i++) {
|
||||
dev->magiclist[i].head = NULL;
|
||||
dev->magiclist[i].tail = NULL;
|
||||
}
|
||||
drm_ht_create(&dev->magiclist, DRM_MAGIC_HASH_ORDER);
|
||||
INIT_LIST_HEAD(&dev->magicfree);
|
||||
|
||||
dev->ctxlist = drm_alloc(sizeof(*dev->ctxlist), DRM_MEM_CTXLIST);
|
||||
if (dev->ctxlist == NULL)
|
||||
|
|
190
drivers/char/drm/drm_hashtab.c
Normal file
190
drivers/char/drm/drm_hashtab.c
Normal file
|
@ -0,0 +1,190 @@
|
|||
/**************************************************************************
|
||||
*
|
||||
* 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 -EINVAL;
|
||||
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 shift,
|
||||
unsigned long add)
|
||||
{
|
||||
int ret;
|
||||
unsigned long mask = (1 << bits) - 1;
|
||||
unsigned long first, unshifted_key;
|
||||
|
||||
unshifted_key = hash_long(seed, bits);
|
||||
first = unshifted_key;
|
||||
do {
|
||||
item->key = (unshifted_key << shift) + add;
|
||||
ret = drm_ht_insert_item(ht, item);
|
||||
if (ret)
|
||||
unshifted_key = (unshifted_key + 1) & mask;
|
||||
} while(ret && (unshifted_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 -EINVAL;
|
||||
|
||||
*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 -EINVAL;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
67
drivers/char/drm/drm_hashtab.h
Normal file
67
drivers/char/drm/drm_hashtab.h
Normal file
|
@ -0,0 +1,67 @@
|
|||
/**************************************************************************
|
||||
*
|
||||
* 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
|
||||
|
||||
#define drm_hash_entry(_ptr, _type, _member) container_of(_ptr, _type, _member)
|
||||
|
||||
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, int shift,
|
||||
unsigned long add);
|
||||
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
|
||||
|
|
@ -1051,7 +1051,7 @@ long drm_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
|||
drm_ioctl_compat_t *fn;
|
||||
int ret;
|
||||
|
||||
if (nr >= DRM_ARRAY_SIZE(drm_compat_ioctls))
|
||||
if (nr >= ARRAY_SIZE(drm_compat_ioctls))
|
||||
return -ENOTTY;
|
||||
|
||||
fn = drm_compat_ioctls[nr];
|
||||
|
|
|
@ -127,9 +127,10 @@ int drm_setunique(struct inode *inode, struct file *filp,
|
|||
domain = bus >> 8;
|
||||
bus &= 0xff;
|
||||
|
||||
if ((domain != dev->pci_domain) ||
|
||||
(bus != dev->pci_bus) ||
|
||||
(slot != dev->pci_slot) || (func != dev->pci_func))
|
||||
if ((domain != drm_get_pci_domain(dev)) ||
|
||||
(bus != dev->pdev->bus->number) ||
|
||||
(slot != PCI_SLOT(dev->pdev->devfn)) ||
|
||||
(func != PCI_FUNC(dev->pdev->devfn)))
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
|
@ -140,15 +141,17 @@ static int drm_set_busid(drm_device_t * dev)
|
|||
int len;
|
||||
|
||||
if (dev->unique != NULL)
|
||||
return EBUSY;
|
||||
return 0;
|
||||
|
||||
dev->unique_len = 40;
|
||||
dev->unique = drm_alloc(dev->unique_len + 1, DRM_MEM_DRIVER);
|
||||
if (dev->unique == NULL)
|
||||
return ENOMEM;
|
||||
return -ENOMEM;
|
||||
|
||||
len = snprintf(dev->unique, dev->unique_len, "pci:%04x:%02x:%02x.%d",
|
||||
dev->pci_domain, dev->pci_bus, dev->pci_slot, dev->pci_func);
|
||||
drm_get_pci_domain(dev), dev->pdev->bus->number,
|
||||
PCI_SLOT(dev->pdev->devfn),
|
||||
PCI_FUNC(dev->pdev->devfn));
|
||||
|
||||
if (len > dev->unique_len)
|
||||
DRM_ERROR("Unique buffer overflowed\n");
|
||||
|
@ -157,7 +160,7 @@ static int drm_set_busid(drm_device_t * dev)
|
|||
drm_alloc(strlen(dev->driver->pci_driver.name) + dev->unique_len +
|
||||
2, DRM_MEM_DRIVER);
|
||||
if (dev->devname == NULL)
|
||||
return ENOMEM;
|
||||
return -ENOMEM;
|
||||
|
||||
sprintf(dev->devname, "%s@%s", dev->driver->pci_driver.name,
|
||||
dev->unique);
|
||||
|
@ -330,27 +333,32 @@ int drm_setversion(DRM_IOCTL_ARGS)
|
|||
drm_set_version_t retv;
|
||||
int if_version;
|
||||
drm_set_version_t __user *argp = (void __user *)data;
|
||||
int ret;
|
||||
|
||||
DRM_COPY_FROM_USER_IOCTL(sv, argp, sizeof(sv));
|
||||
if (copy_from_user(&sv, argp, sizeof(sv)))
|
||||
return -EFAULT;
|
||||
|
||||
retv.drm_di_major = DRM_IF_MAJOR;
|
||||
retv.drm_di_minor = DRM_IF_MINOR;
|
||||
retv.drm_dd_major = dev->driver->major;
|
||||
retv.drm_dd_minor = dev->driver->minor;
|
||||
|
||||
DRM_COPY_TO_USER_IOCTL(argp, retv, sizeof(sv));
|
||||
if (copy_to_user(argp, &retv, sizeof(retv)))
|
||||
return -EFAULT;
|
||||
|
||||
if (sv.drm_di_major != -1) {
|
||||
if (sv.drm_di_major != DRM_IF_MAJOR ||
|
||||
sv.drm_di_minor < 0 || sv.drm_di_minor > DRM_IF_MINOR)
|
||||
return EINVAL;
|
||||
return -EINVAL;
|
||||
if_version = DRM_IF_VERSION(sv.drm_di_major, sv.drm_di_minor);
|
||||
dev->if_version = DRM_MAX(if_version, dev->if_version);
|
||||
dev->if_version = max(if_version, dev->if_version);
|
||||
if (sv.drm_di_minor >= 1) {
|
||||
/*
|
||||
* Version 1.1 includes tying of DRM to specific device
|
||||
*/
|
||||
drm_set_busid(dev);
|
||||
ret = drm_set_busid(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -358,7 +366,7 @@ int drm_setversion(DRM_IOCTL_ARGS)
|
|||
if (sv.drm_dd_major != dev->driver->major ||
|
||||
sv.drm_dd_minor < 0
|
||||
|| sv.drm_dd_minor > dev->driver->minor)
|
||||
return EINVAL;
|
||||
return -EINVAL;
|
||||
|
||||
if (dev->driver->set_version)
|
||||
dev->driver->set_version(dev, &sv);
|
||||
|
|
|
@ -64,9 +64,9 @@ int drm_irq_by_busid(struct inode *inode, struct file *filp,
|
|||
if (copy_from_user(&p, argp, sizeof(p)))
|
||||
return -EFAULT;
|
||||
|
||||
if ((p.busnum >> 8) != dev->pci_domain ||
|
||||
(p.busnum & 0xff) != dev->pci_bus ||
|
||||
p.devnum != dev->pci_slot || p.funcnum != dev->pci_func)
|
||||
if ((p.busnum >> 8) != drm_get_pci_domain(dev) ||
|
||||
(p.busnum & 0xff) != dev->pdev->bus->number ||
|
||||
p.devnum != PCI_SLOT(dev->pdev->devfn) || p.funcnum != PCI_FUNC(dev->pdev->devfn))
|
||||
return -EINVAL;
|
||||
|
||||
p.irq = dev->irq;
|
||||
|
@ -255,7 +255,8 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
|
|||
if (!dev->irq)
|
||||
return -EINVAL;
|
||||
|
||||
DRM_COPY_FROM_USER_IOCTL(vblwait, argp, sizeof(vblwait));
|
||||
if (copy_from_user(&vblwait, argp, sizeof(vblwait)))
|
||||
return -EFAULT;
|
||||
|
||||
switch (vblwait.request.type & ~_DRM_VBLANK_FLAGS_MASK) {
|
||||
case _DRM_VBLANK_RELATIVE:
|
||||
|
@ -329,7 +330,8 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
|
|||
}
|
||||
|
||||
done:
|
||||
DRM_COPY_TO_USER_IOCTL(argp, vblwait, sizeof(vblwait));
|
||||
if (copy_to_user(argp, &vblwait, sizeof(vblwait)))
|
||||
return -EFAULT;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
201
drivers/char/drm/drm_mm.c
Normal file
201
drivers/char/drm/drm_mm.c
Normal file
|
@ -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 = 0;
|
||||
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 = 0;
|
||||
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 = 0;
|
||||
|
||||
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 = 1;
|
||||
}
|
||||
}
|
||||
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 = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!merged) {
|
||||
cur->free = 1;
|
||||
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 = 1;
|
||||
|
||||
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);
|
|
@ -3,13 +3,13 @@
|
|||
Please contact dri-devel@lists.sf.net to add new cards to this list
|
||||
*/
|
||||
#define radeon_PCI_IDS \
|
||||
{0x1002, 0x3150, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_IS_MOBILITY}, \
|
||||
{0x1002, 0x3152, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
|
||||
{0x1002, 0x3154, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
|
||||
{0x1002, 0x3E50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_NEW_MEMMAP}, \
|
||||
{0x1002, 0x3E54, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_NEW_MEMMAP}, \
|
||||
{0x1002, 0x4136, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS100|CHIP_IS_IGP}, \
|
||||
{0x1002, 0x4137, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|CHIP_IS_IGP}, \
|
||||
{0x1002, 0x3150, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY}, \
|
||||
{0x1002, 0x3152, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x3154, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x3E50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x3E54, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x4136, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS100|RADEON_IS_IGP}, \
|
||||
{0x1002, 0x4137, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|RADEON_IS_IGP}, \
|
||||
{0x1002, 0x4144, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
|
||||
{0x1002, 0x4145, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
|
||||
{0x1002, 0x4146, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
|
||||
|
@ -25,35 +25,35 @@
|
|||
{0x1002, 0x4154, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \
|
||||
{0x1002, 0x4155, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \
|
||||
{0x1002, 0x4156, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \
|
||||
{0x1002, 0x4237, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|CHIP_IS_IGP}, \
|
||||
{0x1002, 0x4237, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|RADEON_IS_IGP}, \
|
||||
{0x1002, 0x4242, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
|
||||
{0x1002, 0x4243, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
|
||||
{0x1002, 0x4336, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS100|CHIP_IS_IGP|CHIP_IS_MOBILITY}, \
|
||||
{0x1002, 0x4337, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|CHIP_IS_IGP|CHIP_IS_MOBILITY}, \
|
||||
{0x1002, 0x4437, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|CHIP_IS_IGP|CHIP_IS_MOBILITY}, \
|
||||
{0x1002, 0x4336, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS100|RADEON_IS_IGP|RADEON_IS_MOBILITY}, \
|
||||
{0x1002, 0x4337, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|RADEON_IS_IGP|RADEON_IS_MOBILITY}, \
|
||||
{0x1002, 0x4437, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|RADEON_IS_IGP|RADEON_IS_MOBILITY}, \
|
||||
{0x1002, 0x4966, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250}, \
|
||||
{0x1002, 0x4967, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250}, \
|
||||
{0x1002, 0x4A48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
|
||||
{0x1002, 0x4A49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
|
||||
{0x1002, 0x4A4A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
|
||||
{0x1002, 0x4A4B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
|
||||
{0x1002, 0x4A4C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
|
||||
{0x1002, 0x4A4D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
|
||||
{0x1002, 0x4A4E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
|
||||
{0x1002, 0x4A4F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
|
||||
{0x1002, 0x4A50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
|
||||
{0x1002, 0x4A54, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
|
||||
{0x1002, 0x4B49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
|
||||
{0x1002, 0x4B4A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
|
||||
{0x1002, 0x4B4B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
|
||||
{0x1002, 0x4B4C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
|
||||
{0x1002, 0x4C57, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV200|CHIP_IS_MOBILITY}, \
|
||||
{0x1002, 0x4C58, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV200|CHIP_IS_MOBILITY}, \
|
||||
{0x1002, 0x4C59, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100|CHIP_IS_MOBILITY}, \
|
||||
{0x1002, 0x4C5A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100|CHIP_IS_MOBILITY}, \
|
||||
{0x1002, 0x4C64, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250|CHIP_IS_MOBILITY}, \
|
||||
{0x1002, 0x4C66, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250|CHIP_IS_MOBILITY}, \
|
||||
{0x1002, 0x4C67, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250|CHIP_IS_MOBILITY}, \
|
||||
{0x1002, 0x4A48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x4A49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x4A4A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x4A4B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x4A4C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x4A4D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x4A4E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x4A4F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x4A50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x4A54, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x4B49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x4B4A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x4B4B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x4B4C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x4C57, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV200|RADEON_IS_MOBILITY}, \
|
||||
{0x1002, 0x4C58, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV200|RADEON_IS_MOBILITY}, \
|
||||
{0x1002, 0x4C59, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100|RADEON_IS_MOBILITY}, \
|
||||
{0x1002, 0x4C5A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100|RADEON_IS_MOBILITY}, \
|
||||
{0x1002, 0x4C64, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250|RADEON_IS_MOBILITY}, \
|
||||
{0x1002, 0x4C66, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250|RADEON_IS_MOBILITY}, \
|
||||
{0x1002, 0x4C67, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250|RADEON_IS_MOBILITY}, \
|
||||
{0x1002, 0x4E44, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
|
||||
{0x1002, 0x4E45, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
|
||||
{0x1002, 0x4E46, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
|
||||
|
@ -62,16 +62,16 @@
|
|||
{0x1002, 0x4E49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \
|
||||
{0x1002, 0x4E4A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \
|
||||
{0x1002, 0x4E4B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \
|
||||
{0x1002, 0x4E50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|CHIP_IS_MOBILITY}, \
|
||||
{0x1002, 0x4E51, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|CHIP_IS_MOBILITY}, \
|
||||
{0x1002, 0x4E52, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|CHIP_IS_MOBILITY}, \
|
||||
{0x1002, 0x4E53, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|CHIP_IS_MOBILITY}, \
|
||||
{0x1002, 0x4E54, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|CHIP_IS_MOBILITY}, \
|
||||
{0x1002, 0x4E56, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|CHIP_IS_MOBILITY}, \
|
||||
{0x1002, 0x5144, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|CHIP_SINGLE_CRTC}, \
|
||||
{0x1002, 0x5145, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|CHIP_SINGLE_CRTC}, \
|
||||
{0x1002, 0x5146, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|CHIP_SINGLE_CRTC}, \
|
||||
{0x1002, 0x5147, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|CHIP_SINGLE_CRTC}, \
|
||||
{0x1002, 0x4E50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|RADEON_IS_MOBILITY}, \
|
||||
{0x1002, 0x4E51, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|RADEON_IS_MOBILITY}, \
|
||||
{0x1002, 0x4E52, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|RADEON_IS_MOBILITY}, \
|
||||
{0x1002, 0x4E53, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|RADEON_IS_MOBILITY}, \
|
||||
{0x1002, 0x4E54, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|RADEON_IS_MOBILITY}, \
|
||||
{0x1002, 0x4E56, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|RADEON_IS_MOBILITY}, \
|
||||
{0x1002, 0x5144, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|RADEON_SINGLE_CRTC}, \
|
||||
{0x1002, 0x5145, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|RADEON_SINGLE_CRTC}, \
|
||||
{0x1002, 0x5146, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|RADEON_SINGLE_CRTC}, \
|
||||
{0x1002, 0x5147, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|RADEON_SINGLE_CRTC}, \
|
||||
{0x1002, 0x5148, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
|
||||
{0x1002, 0x514C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
|
||||
{0x1002, 0x514D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
|
||||
|
@ -80,59 +80,59 @@
|
|||
{0x1002, 0x5159, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100}, \
|
||||
{0x1002, 0x515A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100}, \
|
||||
{0x1002, 0x515E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100}, \
|
||||
{0x1002, 0x5460, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_IS_MOBILITY}, \
|
||||
{0x1002, 0x5462, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_IS_MOBILITY}, \
|
||||
{0x1002, 0x5464, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_IS_MOBILITY}, \
|
||||
{0x1002, 0x5548, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5549, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
|
||||
{0x1002, 0x554A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
|
||||
{0x1002, 0x554B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
|
||||
{0x1002, 0x554C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
|
||||
{0x1002, 0x554D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
|
||||
{0x1002, 0x554E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
|
||||
{0x1002, 0x554F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5550, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5551, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5552, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5554, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
|
||||
{0x1002, 0x564A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
|
||||
{0x1002, 0x564B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
|
||||
{0x1002, 0x564F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5652, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5653, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5834, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|CHIP_IS_IGP}, \
|
||||
{0x1002, 0x5835, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|CHIP_IS_IGP|CHIP_IS_MOBILITY}, \
|
||||
{0x1002, 0x5460, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY}, \
|
||||
{0x1002, 0x5462, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY}, \
|
||||
{0x1002, 0x5464, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY}, \
|
||||
{0x1002, 0x5548, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5549, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x554A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x554B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x554C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x554D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x554E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x554F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5550, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5551, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5552, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5554, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x564A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x564B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x564F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5652, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5653, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5834, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|RADEON_IS_IGP}, \
|
||||
{0x1002, 0x5835, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|RADEON_IS_IGP|RADEON_IS_MOBILITY}, \
|
||||
{0x1002, 0x5960, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
|
||||
{0x1002, 0x5961, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
|
||||
{0x1002, 0x5962, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
|
||||
{0x1002, 0x5964, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
|
||||
{0x1002, 0x5965, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
|
||||
{0x1002, 0x5969, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100}, \
|
||||
{0x1002, 0x5b60, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5b62, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5b63, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5b64, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5b65, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5c61, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280|CHIP_IS_MOBILITY}, \
|
||||
{0x1002, 0x5c63, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280|CHIP_IS_MOBILITY}, \
|
||||
{0x1002, 0x5d48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5d49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5d4a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5d4c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5d4d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5d4e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5d4f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5d50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5d52, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5d57, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5e48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5e4a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5e4b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5e4c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5e4d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5e4f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_NEW_MEMMAP}, \
|
||||
{0x1002, 0x7834, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|CHIP_IS_IGP|CHIP_NEW_MEMMAP}, \
|
||||
{0x1002, 0x7835, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|CHIP_IS_IGP|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5b60, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5b62, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5b63, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5b64, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5b65, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5c61, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280|RADEON_IS_MOBILITY}, \
|
||||
{0x1002, 0x5c63, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280|RADEON_IS_MOBILITY}, \
|
||||
{0x1002, 0x5d48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5d49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5d4a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5d4c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5d4d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5d4e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5d4f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5d50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5d52, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5d57, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5e48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5e4a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5e4b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5e4c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5e4d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5e4f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x7834, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|RADEON_IS_IGP|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x7835, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
|
||||
{0, 0, 0}
|
||||
|
||||
#define r128_PCI_IDS \
|
||||
|
@ -209,6 +209,7 @@
|
|||
{0x1039, 0x0300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x1039, 0x5300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x1039, 0x6300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x1039, 0x6330, PCI_ANY_ID, PCI_ANY_ID, 0, 0, SIS_CHIP_315}, \
|
||||
{0x1039, 0x7300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0, 0, 0}
|
||||
|
||||
|
@ -227,6 +228,10 @@
|
|||
{0x1106, 0x3122, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x1106, 0x7205, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x1106, 0x3108, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x1106, 0x3304, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x1106, 0x3157, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x1106, 0x3344, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x1106, 0x7204, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0, 0, 0}
|
||||
|
||||
#define i810_PCI_IDS \
|
||||
|
@ -285,5 +290,9 @@
|
|||
{0x8086, 0x2592, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x8086, 0x2772, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x8086, 0x27a2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x8086, 0x2972, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x8086, 0x2982, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x8086, 0x2992, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x8086, 0x29a2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0, 0, 0}
|
||||
|
||||
|
|
|
@ -510,7 +510,7 @@ static int drm__vma_info(char *buf, char **start, off_t offset, int request,
|
|||
vma->vm_flags & VM_MAYSHARE ? 's' : 'p',
|
||||
vma->vm_flags & VM_LOCKED ? 'l' : '-',
|
||||
vma->vm_flags & VM_IO ? 'i' : '-',
|
||||
VM_OFFSET(vma));
|
||||
vma->vm_pgoff << PAGE_SHIFT);
|
||||
|
||||
#if defined(__i386__)
|
||||
pgprot = pgprot_val(vma->vm_page_prot);
|
||||
|
|
352
drivers/char/drm/drm_sman.c
Normal file
352
drivers/char/drm/drm_sman.c
Normal file
|
@ -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, 1);
|
||||
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);
|
||||
}
|
||||
|
||||
static 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 drm_hash_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, 0, 0))
|
||||
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 = drm_hash_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 = drm_hash_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 = drm_hash_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);
|
176
drivers/char/drm/drm_sman.h
Normal file
176
drivers/char/drm/drm_sman.h
Normal file
|
@ -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 1 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
|
|
@ -65,22 +65,22 @@ static int drm_fill_in_dev(drm_device_t * dev, struct pci_dev *pdev,
|
|||
mutex_init(&dev->ctxlist_mutex);
|
||||
|
||||
dev->pdev = pdev;
|
||||
dev->pci_device = pdev->device;
|
||||
dev->pci_vendor = pdev->vendor;
|
||||
|
||||
#ifdef __alpha__
|
||||
dev->hose = pdev->sysdata;
|
||||
dev->pci_domain = dev->hose->bus->number;
|
||||
#else
|
||||
dev->pci_domain = 0;
|
||||
#endif
|
||||
dev->pci_bus = pdev->bus->number;
|
||||
dev->pci_slot = PCI_SLOT(pdev->devfn);
|
||||
dev->pci_func = PCI_FUNC(pdev->devfn);
|
||||
dev->irq = pdev->irq;
|
||||
|
||||
dev->maplist = drm_calloc(1, sizeof(*dev->maplist), DRM_MEM_MAPS);
|
||||
if (dev->maplist == NULL)
|
||||
return -ENOMEM;
|
||||
INIT_LIST_HEAD(&dev->maplist->head);
|
||||
if (drm_ht_create(&dev->map_hash, 12)) {
|
||||
drm_free(dev->maplist, sizeof(*dev->maplist), DRM_MEM_MAPS);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* the DRM has 6 basic counters */
|
||||
dev->counters = 6;
|
||||
|
|
|
@ -59,7 +59,7 @@ static __inline__ struct page *drm_do_vm_nopage(struct vm_area_struct *vma,
|
|||
drm_device_t *dev = priv->head->dev;
|
||||
drm_map_t *map = NULL;
|
||||
drm_map_list_t *r_list;
|
||||
struct list_head *list;
|
||||
drm_hash_item_t *hash;
|
||||
|
||||
/*
|
||||
* Find the right map
|
||||
|
@ -70,14 +70,11 @@ static __inline__ struct page *drm_do_vm_nopage(struct vm_area_struct *vma,
|
|||
if (!dev->agp || !dev->agp->cant_use_aperture)
|
||||
goto vm_nopage_error;
|
||||
|
||||
list_for_each(list, &dev->maplist->head) {
|
||||
r_list = list_entry(list, drm_map_list_t, head);
|
||||
map = r_list->map;
|
||||
if (!map)
|
||||
continue;
|
||||
if (r_list->user_token == VM_OFFSET(vma))
|
||||
break;
|
||||
}
|
||||
if (drm_ht_find_item(&dev->map_hash, vma->vm_pgoff << PAGE_SHIFT, &hash))
|
||||
goto vm_nopage_error;
|
||||
|
||||
r_list = drm_hash_entry(hash, drm_map_list_t, hash);
|
||||
map = r_list->map;
|
||||
|
||||
if (map && map->type == _DRM_AGP) {
|
||||
unsigned long offset = address - vma->vm_start;
|
||||
|
@ -467,7 +464,7 @@ static int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma)
|
|||
dev = priv->head->dev;
|
||||
dma = dev->dma;
|
||||
DRM_DEBUG("start = 0x%lx, end = 0x%lx, offset = 0x%lx\n",
|
||||
vma->vm_start, vma->vm_end, VM_OFFSET(vma));
|
||||
vma->vm_start, vma->vm_end, vma->vm_pgoff << PAGE_SHIFT);
|
||||
|
||||
/* Length must match exact page count */
|
||||
if (!dma || (length >> PAGE_SHIFT) != dma->page_count) {
|
||||
|
@ -521,12 +518,11 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma)
|
|||
drm_file_t *priv = filp->private_data;
|
||||
drm_device_t *dev = priv->head->dev;
|
||||
drm_map_t *map = NULL;
|
||||
drm_map_list_t *r_list;
|
||||
unsigned long offset = 0;
|
||||
struct list_head *list;
|
||||
drm_hash_item_t *hash;
|
||||
|
||||
DRM_DEBUG("start = 0x%lx, end = 0x%lx, offset = 0x%lx\n",
|
||||
vma->vm_start, vma->vm_end, VM_OFFSET(vma));
|
||||
vma->vm_start, vma->vm_end, vma->vm_pgoff << PAGE_SHIFT);
|
||||
|
||||
if (!priv->authenticated)
|
||||
return -EACCES;
|
||||
|
@ -535,7 +531,7 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma)
|
|||
* the AGP mapped at physical address 0
|
||||
* --BenH.
|
||||
*/
|
||||
if (!VM_OFFSET(vma)
|
||||
if (!(vma->vm_pgoff << PAGE_SHIFT)
|
||||
#if __OS_HAS_AGP
|
||||
&& (!dev->agp
|
||||
|| dev->agp->agp_info.device->vendor != PCI_VENDOR_ID_APPLE)
|
||||
|
@ -543,23 +539,12 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma)
|
|||
)
|
||||
return drm_mmap_dma(filp, vma);
|
||||
|
||||
/* A sequential search of a linked list is
|
||||
fine here because: 1) there will only be
|
||||
about 5-10 entries in the list and, 2) a
|
||||
DRI client only has to do this mapping
|
||||
once, so it doesn't have to be optimized
|
||||
for performance, even if the list was a
|
||||
bit longer. */
|
||||
list_for_each(list, &dev->maplist->head) {
|
||||
|
||||
r_list = list_entry(list, drm_map_list_t, head);
|
||||
map = r_list->map;
|
||||
if (!map)
|
||||
continue;
|
||||
if (r_list->user_token == VM_OFFSET(vma))
|
||||
break;
|
||||
if (drm_ht_find_item(&dev->map_hash, vma->vm_pgoff << PAGE_SHIFT, &hash)) {
|
||||
DRM_ERROR("Could not find map\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
map = drm_hash_entry(hash, drm_map_list_t, hash)->map;
|
||||
if (!map || ((map->flags & _DRM_RESTRICTED) && !capable(CAP_SYS_ADMIN)))
|
||||
return -EPERM;
|
||||
|
||||
|
@ -620,7 +605,7 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma)
|
|||
offset = dev->driver->get_reg_ofs(dev);
|
||||
#ifdef __sparc__
|
||||
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
|
||||
if (io_remap_pfn_range(DRM_RPR_ARG(vma) vma->vm_start,
|
||||
if (io_remap_pfn_range(vma, vma->vm_start,
|
||||
(map->offset + offset) >> PAGE_SHIFT,
|
||||
vma->vm_end - vma->vm_start,
|
||||
vma->vm_page_prot))
|
||||
|
|
|
@ -106,7 +106,7 @@ static int i810_mmap_buffers(struct file *filp, struct vm_area_struct *vma)
|
|||
unlock_kernel();
|
||||
|
||||
if (io_remap_pfn_range(vma, vma->vm_start,
|
||||
VM_OFFSET(vma) >> PAGE_SHIFT,
|
||||
vma->vm_pgoff,
|
||||
vma->vm_end - vma->vm_start, vma->vm_page_prot))
|
||||
return -EAGAIN;
|
||||
return 0;
|
||||
|
@ -141,10 +141,10 @@ static int i810_map_buffer(drm_buf_t * buf, struct file *filp)
|
|||
MAP_SHARED, buf->bus_address);
|
||||
dev_priv->mmap_buffer = NULL;
|
||||
filp->f_op = old_fops;
|
||||
if ((unsigned long)buf_priv->virtual > -1024UL) {
|
||||
if (IS_ERR(buf_priv->virtual)) {
|
||||
/* Real error */
|
||||
DRM_ERROR("mmap error\n");
|
||||
retcode = (signed int)buf_priv->virtual;
|
||||
retcode = PTR_ERR(buf_priv->virtual);
|
||||
buf_priv->virtual = NULL;
|
||||
}
|
||||
up_write(¤t->mm->mmap_sem);
|
||||
|
@ -808,7 +808,7 @@ static void i810_dma_dispatch_vertex(drm_device_t * dev,
|
|||
((GFX_OP_PRIMITIVE | prim | ((used / 4) - 2)));
|
||||
|
||||
if (used & 4) {
|
||||
*(u32 *) ((u32) buf_priv->kernel_virtual + used) = 0;
|
||||
*(u32 *) ((char *) buf_priv->kernel_virtual + used) = 0;
|
||||
used += 4;
|
||||
}
|
||||
|
||||
|
@ -1166,7 +1166,7 @@ static void i810_dma_dispatch_mc(drm_device_t * dev, drm_buf_t * buf, int used,
|
|||
|
||||
if (buf_priv->currently_mapped == I810_BUF_MAPPED) {
|
||||
if (used & 4) {
|
||||
*(u32 *) ((u32) buf_priv->virtual + used) = 0;
|
||||
*(u32 *) ((char *) buf_priv->virtual + used) = 0;
|
||||
used += 4;
|
||||
}
|
||||
|
||||
|
|
|
@ -108,7 +108,7 @@ static int i830_mmap_buffers(struct file *filp, struct vm_area_struct *vma)
|
|||
unlock_kernel();
|
||||
|
||||
if (io_remap_pfn_range(vma, vma->vm_start,
|
||||
VM_OFFSET(vma) >> PAGE_SHIFT,
|
||||
vma->vm_pgoff,
|
||||
vma->vm_end - vma->vm_start, vma->vm_page_prot))
|
||||
return -EAGAIN;
|
||||
return 0;
|
||||
|
@ -146,7 +146,7 @@ static int i830_map_buffer(drm_buf_t * buf, struct file *filp)
|
|||
if (IS_ERR((void *)virtual)) { /* ugh */
|
||||
/* Real error */
|
||||
DRM_ERROR("mmap error\n");
|
||||
retcode = virtual;
|
||||
retcode = PTR_ERR((void *)virtual);
|
||||
buf_priv->virtual = NULL;
|
||||
} else {
|
||||
buf_priv->virtual = (void __user *)virtual;
|
||||
|
|
|
@ -31,6 +31,11 @@
|
|||
#include "i915_drm.h"
|
||||
#include "i915_drv.h"
|
||||
|
||||
#define IS_I965G(dev) (dev->pci_device == 0x2972 || \
|
||||
dev->pci_device == 0x2982 || \
|
||||
dev->pci_device == 0x2992 || \
|
||||
dev->pci_device == 0x29A2)
|
||||
|
||||
/* Really want an OS-independent resettable timer. Would like to have
|
||||
* this loop run for (eg) 3 sec, but have the timer reset every time
|
||||
* the head pointer changes, so that EBUSY only happens if the ring
|
||||
|
@ -255,7 +260,7 @@ static int i915_dma_init(DRM_IOCTL_ARGS)
|
|||
retcode = i915_dma_resume(dev);
|
||||
break;
|
||||
default:
|
||||
retcode = -EINVAL;
|
||||
retcode = DRM_ERR(EINVAL);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -347,7 +352,7 @@ static int i915_emit_cmds(drm_device_t * dev, int __user * buffer, int dwords)
|
|||
if ((dwords+1) * sizeof(int) >= dev_priv->ring.Size - 8)
|
||||
return DRM_ERR(EINVAL);
|
||||
|
||||
BEGIN_LP_RING(((dwords+1)&~1));
|
||||
BEGIN_LP_RING((dwords+1)&~1);
|
||||
|
||||
for (i = 0; i < dwords;) {
|
||||
int cmd, sz;
|
||||
|
@ -386,7 +391,7 @@ static int i915_emit_box(drm_device_t * dev,
|
|||
RING_LOCALS;
|
||||
|
||||
if (DRM_COPY_FROM_USER_UNCHECKED(&box, &boxes[i], sizeof(box))) {
|
||||
return EFAULT;
|
||||
return DRM_ERR(EFAULT);
|
||||
}
|
||||
|
||||
if (box.y2 <= box.y1 || box.x2 <= box.x1 || box.y2 <= 0 || box.x2 <= 0) {
|
||||
|
@ -395,24 +400,40 @@ static int i915_emit_box(drm_device_t * dev,
|
|||
return DRM_ERR(EINVAL);
|
||||
}
|
||||
|
||||
BEGIN_LP_RING(6);
|
||||
OUT_RING(GFX_OP_DRAWRECT_INFO);
|
||||
OUT_RING(DR1);
|
||||
OUT_RING((box.x1 & 0xffff) | (box.y1 << 16));
|
||||
OUT_RING(((box.x2 - 1) & 0xffff) | ((box.y2 - 1) << 16));
|
||||
OUT_RING(DR4);
|
||||
OUT_RING(0);
|
||||
ADVANCE_LP_RING();
|
||||
if (IS_I965G(dev)) {
|
||||
BEGIN_LP_RING(4);
|
||||
OUT_RING(GFX_OP_DRAWRECT_INFO_I965);
|
||||
OUT_RING((box.x1 & 0xffff) | (box.y1 << 16));
|
||||
OUT_RING(((box.x2 - 1) & 0xffff) | ((box.y2 - 1) << 16));
|
||||
OUT_RING(DR4);
|
||||
ADVANCE_LP_RING();
|
||||
} else {
|
||||
BEGIN_LP_RING(6);
|
||||
OUT_RING(GFX_OP_DRAWRECT_INFO);
|
||||
OUT_RING(DR1);
|
||||
OUT_RING((box.x1 & 0xffff) | (box.y1 << 16));
|
||||
OUT_RING(((box.x2 - 1) & 0xffff) | ((box.y2 - 1) << 16));
|
||||
OUT_RING(DR4);
|
||||
OUT_RING(0);
|
||||
ADVANCE_LP_RING();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* XXX: Emitting the counter should really be moved to part of the IRQ
|
||||
* emit. For now, do it in both places:
|
||||
*/
|
||||
|
||||
static void i915_emit_breadcrumb(drm_device_t *dev)
|
||||
{
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
RING_LOCALS;
|
||||
|
||||
dev_priv->sarea_priv->last_enqueue = dev_priv->counter++;
|
||||
dev_priv->sarea_priv->last_enqueue = ++dev_priv->counter;
|
||||
|
||||
if (dev_priv->counter > 0x7FFFFFFFUL)
|
||||
dev_priv->sarea_priv->last_enqueue = dev_priv->counter = 1;
|
||||
|
||||
BEGIN_LP_RING(4);
|
||||
OUT_RING(CMD_STORE_DWORD_IDX);
|
||||
|
|
|
@ -98,6 +98,12 @@ typedef struct _drm_i915_sarea {
|
|||
int rotated_size;
|
||||
int rotated_pitch;
|
||||
int virtualX, virtualY;
|
||||
|
||||
unsigned int front_tiled;
|
||||
unsigned int back_tiled;
|
||||
unsigned int depth_tiled;
|
||||
unsigned int rotated_tiled;
|
||||
unsigned int rotated2_tiled;
|
||||
} drm_i915_sarea_t;
|
||||
|
||||
/* Flags for perf_boxes
|
||||
|
|
|
@ -146,9 +146,9 @@ extern void i915_mem_release(drm_device_t * dev,
|
|||
#define BEGIN_LP_RING(n) do { \
|
||||
if (I915_VERBOSE) \
|
||||
DRM_DEBUG("BEGIN_LP_RING(%d) in %s\n", \
|
||||
n, __FUNCTION__); \
|
||||
if (dev_priv->ring.space < n*4) \
|
||||
i915_wait_ring(dev, n*4, __FUNCTION__); \
|
||||
(n), __FUNCTION__); \
|
||||
if (dev_priv->ring.space < (n)*4) \
|
||||
i915_wait_ring(dev, (n)*4, __FUNCTION__); \
|
||||
outcount = 0; \
|
||||
outring = dev_priv->ring.tail; \
|
||||
ringmask = dev_priv->ring.tail_mask; \
|
||||
|
@ -157,7 +157,7 @@ extern void i915_mem_release(drm_device_t * dev,
|
|||
|
||||
#define OUT_RING(n) do { \
|
||||
if (I915_VERBOSE) DRM_DEBUG(" OUT_RING %x\n", (int)(n)); \
|
||||
*(volatile unsigned int *)(virt + outring) = n; \
|
||||
*(volatile unsigned int *)(virt + outring) = (n); \
|
||||
outcount++; \
|
||||
outring += 4; \
|
||||
outring &= ringmask; \
|
||||
|
@ -254,6 +254,8 @@ extern int i915_wait_ring(drm_device_t * dev, int n, const char *caller);
|
|||
#define GFX_OP_DESTBUFFER_VARS ((0x3<<29)|(0x1d<<24)|(0x85<<16)|0x0)
|
||||
#define GFX_OP_DRAWRECT_INFO ((0x3<<29)|(0x1d<<24)|(0x80<<16)|(0x3))
|
||||
|
||||
#define GFX_OP_DRAWRECT_INFO_I965 ((0x7900<<16)|0x2)
|
||||
|
||||
#define MI_BATCH_BUFFER ((0x30<<23)|1)
|
||||
#define MI_BATCH_BUFFER_START (0x31<<23)
|
||||
#define MI_BATCH_BUFFER_END (0xA<<23)
|
||||
|
|
|
@ -71,21 +71,27 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
|
|||
static int i915_emit_irq(drm_device_t * dev)
|
||||
{
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
u32 ret;
|
||||
RING_LOCALS;
|
||||
|
||||
i915_kernel_lost_context(dev);
|
||||
|
||||
DRM_DEBUG("%s\n", __FUNCTION__);
|
||||
|
||||
ret = dev_priv->counter;
|
||||
dev_priv->sarea_priv->last_enqueue = ++dev_priv->counter;
|
||||
|
||||
BEGIN_LP_RING(2);
|
||||
if (dev_priv->counter > 0x7FFFFFFFUL)
|
||||
dev_priv->sarea_priv->last_enqueue = dev_priv->counter = 1;
|
||||
|
||||
BEGIN_LP_RING(6);
|
||||
OUT_RING(CMD_STORE_DWORD_IDX);
|
||||
OUT_RING(20);
|
||||
OUT_RING(dev_priv->counter);
|
||||
OUT_RING(0);
|
||||
OUT_RING(0);
|
||||
OUT_RING(GFX_OP_USER_INTERRUPT);
|
||||
ADVANCE_LP_RING();
|
||||
|
||||
return ret;
|
||||
|
||||
return dev_priv->counter;
|
||||
}
|
||||
|
||||
static int i915_wait_irq(drm_device_t * dev, int irq_nr)
|
||||
|
|
|
@ -864,13 +864,13 @@ static int radeon_do_pixcache_flush(drm_radeon_private_t * dev_priv)
|
|||
|
||||
dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;
|
||||
|
||||
tmp = RADEON_READ(RADEON_RB2D_DSTCACHE_CTLSTAT);
|
||||
tmp |= RADEON_RB2D_DC_FLUSH_ALL;
|
||||
RADEON_WRITE(RADEON_RB2D_DSTCACHE_CTLSTAT, tmp);
|
||||
tmp = RADEON_READ(RADEON_RB3D_DSTCACHE_CTLSTAT);
|
||||
tmp |= RADEON_RB3D_DC_FLUSH_ALL;
|
||||
RADEON_WRITE(RADEON_RB3D_DSTCACHE_CTLSTAT, tmp);
|
||||
|
||||
for (i = 0; i < dev_priv->usec_timeout; i++) {
|
||||
if (!(RADEON_READ(RADEON_RB2D_DSTCACHE_CTLSTAT)
|
||||
& RADEON_RB2D_DC_BUSY)) {
|
||||
if (!(RADEON_READ(RADEON_RB3D_DSTCACHE_CTLSTAT)
|
||||
& RADEON_RB3D_DC_BUSY)) {
|
||||
return 0;
|
||||
}
|
||||
DRM_UDELAY(1);
|
||||
|
@ -1130,7 +1130,7 @@ static void radeon_cp_init_ring_buffer(drm_device_t * dev,
|
|||
| (dev_priv->fb_location >> 16));
|
||||
|
||||
#if __OS_HAS_AGP
|
||||
if (dev_priv->flags & CHIP_IS_AGP) {
|
||||
if (dev_priv->flags & RADEON_IS_AGP) {
|
||||
RADEON_WRITE(RADEON_AGP_BASE, (unsigned int)dev->agp->base);
|
||||
RADEON_WRITE(RADEON_MC_AGP_LOCATION,
|
||||
(((dev_priv->gart_vm_start - 1 +
|
||||
|
@ -1158,7 +1158,7 @@ static void radeon_cp_init_ring_buffer(drm_device_t * dev,
|
|||
dev_priv->ring.tail = cur_read_ptr;
|
||||
|
||||
#if __OS_HAS_AGP
|
||||
if (dev_priv->flags & CHIP_IS_AGP) {
|
||||
if (dev_priv->flags & RADEON_IS_AGP) {
|
||||
RADEON_WRITE(RADEON_CP_RB_RPTR_ADDR,
|
||||
dev_priv->ring_rptr->offset
|
||||
- dev->agp->base + dev_priv->gart_vm_start);
|
||||
|
@ -1258,6 +1258,13 @@ static void radeon_test_writeback(drm_radeon_private_t * dev_priv)
|
|||
dev_priv->writeback_works = 0;
|
||||
DRM_INFO("writeback forced off\n");
|
||||
}
|
||||
|
||||
if (!dev_priv->writeback_works) {
|
||||
/* Disable writeback to avoid unnecessary bus master transfer */
|
||||
RADEON_WRITE(RADEON_CP_RB_CNTL, RADEON_READ(RADEON_CP_RB_CNTL) |
|
||||
RADEON_RB_NO_UPDATE);
|
||||
RADEON_WRITE(RADEON_SCRATCH_UMSK, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Enable or disable PCI-E GART on the chip */
|
||||
|
@ -1295,7 +1302,7 @@ static void radeon_set_pcigart(drm_radeon_private_t * dev_priv, int on)
|
|||
{
|
||||
u32 tmp;
|
||||
|
||||
if (dev_priv->flags & CHIP_IS_PCIE) {
|
||||
if (dev_priv->flags & RADEON_IS_PCIE) {
|
||||
radeon_set_pciegart(dev_priv, on);
|
||||
return;
|
||||
}
|
||||
|
@ -1333,20 +1340,22 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init)
|
|||
DRM_DEBUG("\n");
|
||||
|
||||
/* if we require new memory map but we don't have it fail */
|
||||
if ((dev_priv->flags & CHIP_NEW_MEMMAP) && !dev_priv->new_memmap)
|
||||
{
|
||||
DRM_ERROR("Cannot initialise DRM on this card\nThis card requires a new X.org DDX\n");
|
||||
if ((dev_priv->flags & RADEON_NEW_MEMMAP) && !dev_priv->new_memmap) {
|
||||
DRM_ERROR("Cannot initialise DRM on this card\nThis card requires a new X.org DDX for 3D\n");
|
||||
radeon_do_cleanup_cp(dev);
|
||||
return DRM_ERR(EINVAL);
|
||||
}
|
||||
|
||||
if (init->is_pci && (dev_priv->flags & CHIP_IS_AGP))
|
||||
{
|
||||
if (init->is_pci && (dev_priv->flags & RADEON_IS_AGP)) {
|
||||
DRM_DEBUG("Forcing AGP card to PCI mode\n");
|
||||
dev_priv->flags &= ~CHIP_IS_AGP;
|
||||
dev_priv->flags &= ~RADEON_IS_AGP;
|
||||
} else if (!(dev_priv->flags & (RADEON_IS_AGP | RADEON_IS_PCI | RADEON_IS_PCIE))
|
||||
&& !init->is_pci) {
|
||||
DRM_DEBUG("Restoring AGP flag\n");
|
||||
dev_priv->flags |= RADEON_IS_AGP;
|
||||
}
|
||||
|
||||
if ((!(dev_priv->flags & CHIP_IS_AGP)) && !dev->sg) {
|
||||
if ((!(dev_priv->flags & RADEON_IS_AGP)) && !dev->sg) {
|
||||
DRM_ERROR("PCI GART memory not allocated!\n");
|
||||
radeon_do_cleanup_cp(dev);
|
||||
return DRM_ERR(EINVAL);
|
||||
|
@ -1489,7 +1498,7 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init)
|
|||
init->sarea_priv_offset);
|
||||
|
||||
#if __OS_HAS_AGP
|
||||
if (dev_priv->flags & CHIP_IS_AGP) {
|
||||
if (dev_priv->flags & RADEON_IS_AGP) {
|
||||
drm_core_ioremap(dev_priv->cp_ring, dev);
|
||||
drm_core_ioremap(dev_priv->ring_rptr, dev);
|
||||
drm_core_ioremap(dev->agp_buffer_map, dev);
|
||||
|
@ -1548,7 +1557,7 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init)
|
|||
* align it down.
|
||||
*/
|
||||
#if __OS_HAS_AGP
|
||||
if (dev_priv->flags & CHIP_IS_AGP) {
|
||||
if (dev_priv->flags & RADEON_IS_AGP) {
|
||||
base = dev->agp->base;
|
||||
/* Check if valid */
|
||||
if ((base + dev_priv->gart_size) > dev_priv->fb_location &&
|
||||
|
@ -1578,7 +1587,7 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init)
|
|||
}
|
||||
|
||||
#if __OS_HAS_AGP
|
||||
if (dev_priv->flags & CHIP_IS_AGP)
|
||||
if (dev_priv->flags & RADEON_IS_AGP)
|
||||
dev_priv->gart_buffers_offset = (dev->agp_buffer_map->offset
|
||||
- dev->agp->base
|
||||
+ dev_priv->gart_vm_start);
|
||||
|
@ -1604,7 +1613,7 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init)
|
|||
dev_priv->ring.high_mark = RADEON_RING_HIGH_MARK;
|
||||
|
||||
#if __OS_HAS_AGP
|
||||
if (dev_priv->flags & CHIP_IS_AGP) {
|
||||
if (dev_priv->flags & RADEON_IS_AGP) {
|
||||
/* Turn off PCI GART */
|
||||
radeon_set_pcigart(dev_priv, 0);
|
||||
} else
|
||||
|
@ -1624,7 +1633,7 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init)
|
|||
dev_priv->gart_info.mapping.handle;
|
||||
|
||||
dev_priv->gart_info.is_pcie =
|
||||
!!(dev_priv->flags & CHIP_IS_PCIE);
|
||||
!!(dev_priv->flags & RADEON_IS_PCIE);
|
||||
dev_priv->gart_info.gart_table_location =
|
||||
DRM_ATI_GART_FB;
|
||||
|
||||
|
@ -1636,7 +1645,7 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init)
|
|||
DRM_ATI_GART_MAIN;
|
||||
dev_priv->gart_info.addr = NULL;
|
||||
dev_priv->gart_info.bus_addr = 0;
|
||||
if (dev_priv->flags & CHIP_IS_PCIE) {
|
||||
if (dev_priv->flags & RADEON_IS_PCIE) {
|
||||
DRM_ERROR
|
||||
("Cannot use PCI Express without GART in FB memory\n");
|
||||
radeon_do_cleanup_cp(dev);
|
||||
|
@ -1678,7 +1687,7 @@ static int radeon_do_cleanup_cp(drm_device_t * dev)
|
|||
drm_irq_uninstall(dev);
|
||||
|
||||
#if __OS_HAS_AGP
|
||||
if (dev_priv->flags & CHIP_IS_AGP) {
|
||||
if (dev_priv->flags & RADEON_IS_AGP) {
|
||||
if (dev_priv->cp_ring != NULL) {
|
||||
drm_core_ioremapfree(dev_priv->cp_ring, dev);
|
||||
dev_priv->cp_ring = NULL;
|
||||
|
@ -1733,7 +1742,7 @@ static int radeon_do_resume_cp(drm_device_t * dev)
|
|||
DRM_DEBUG("Starting radeon_do_resume_cp()\n");
|
||||
|
||||
#if __OS_HAS_AGP
|
||||
if (dev_priv->flags & CHIP_IS_AGP) {
|
||||
if (dev_priv->flags & RADEON_IS_AGP) {
|
||||
/* Turn off PCI GART */
|
||||
radeon_set_pcigart(dev_priv, 0);
|
||||
} else
|
||||
|
@ -2177,13 +2186,15 @@ int radeon_driver_load(struct drm_device *dev, unsigned long flags)
|
|||
dev->dev_private = (void *)dev_priv;
|
||||
dev_priv->flags = flags;
|
||||
|
||||
switch (flags & CHIP_FAMILY_MASK) {
|
||||
switch (flags & RADEON_FAMILY_MASK) {
|
||||
case CHIP_R100:
|
||||
case CHIP_RV200:
|
||||
case CHIP_R200:
|
||||
case CHIP_R300:
|
||||
case CHIP_R350:
|
||||
case CHIP_R420:
|
||||
dev_priv->flags |= CHIP_HAS_HIERZ;
|
||||
case CHIP_RV410:
|
||||
dev_priv->flags |= RADEON_HAS_HIERZ;
|
||||
break;
|
||||
default:
|
||||
/* all other chips have no hierarchical z buffer */
|
||||
|
@ -2191,13 +2202,14 @@ int radeon_driver_load(struct drm_device *dev, unsigned long flags)
|
|||
}
|
||||
|
||||
if (drm_device_is_agp(dev))
|
||||
dev_priv->flags |= CHIP_IS_AGP;
|
||||
|
||||
if (drm_device_is_pcie(dev))
|
||||
dev_priv->flags |= CHIP_IS_PCIE;
|
||||
dev_priv->flags |= RADEON_IS_AGP;
|
||||
else if (drm_device_is_pcie(dev))
|
||||
dev_priv->flags |= RADEON_IS_PCIE;
|
||||
else
|
||||
dev_priv->flags |= RADEON_IS_PCI;
|
||||
|
||||
DRM_DEBUG("%s card detected\n",
|
||||
((dev_priv->flags & CHIP_IS_AGP) ? "AGP" : (((dev_priv->flags & CHIP_IS_PCIE) ? "PCIE" : "PCI"))));
|
||||
((dev_priv->flags & RADEON_IS_AGP) ? "AGP" : (((dev_priv->flags & RADEON_IS_PCIE) ? "PCIE" : "PCI"))));
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@ module_param_named(no_wb, radeon_no_wb, int, 0444);
|
|||
static int dri_library_name(struct drm_device *dev, char *buf)
|
||||
{
|
||||
drm_radeon_private_t *dev_priv = dev->dev_private;
|
||||
int family = dev_priv->flags & CHIP_FAMILY_MASK;
|
||||
int family = dev_priv->flags & RADEON_FAMILY_MASK;
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%s\n",
|
||||
(family < CHIP_R200) ? "radeon" :
|
||||
|
|
|
@ -133,15 +133,16 @@ enum radeon_cp_microcode_version {
|
|||
* Chip flags
|
||||
*/
|
||||
enum radeon_chip_flags {
|
||||
CHIP_FAMILY_MASK = 0x0000ffffUL,
|
||||
CHIP_FLAGS_MASK = 0xffff0000UL,
|
||||
CHIP_IS_MOBILITY = 0x00010000UL,
|
||||
CHIP_IS_IGP = 0x00020000UL,
|
||||
CHIP_SINGLE_CRTC = 0x00040000UL,
|
||||
CHIP_IS_AGP = 0x00080000UL,
|
||||
CHIP_HAS_HIERZ = 0x00100000UL,
|
||||
CHIP_IS_PCIE = 0x00200000UL,
|
||||
CHIP_NEW_MEMMAP = 0x00400000UL,
|
||||
RADEON_FAMILY_MASK = 0x0000ffffUL,
|
||||
RADEON_FLAGS_MASK = 0xffff0000UL,
|
||||
RADEON_IS_MOBILITY = 0x00010000UL,
|
||||
RADEON_IS_IGP = 0x00020000UL,
|
||||
RADEON_SINGLE_CRTC = 0x00040000UL,
|
||||
RADEON_IS_AGP = 0x00080000UL,
|
||||
RADEON_HAS_HIERZ = 0x00100000UL,
|
||||
RADEON_IS_PCIE = 0x00200000UL,
|
||||
RADEON_NEW_MEMMAP = 0x00400000UL,
|
||||
RADEON_IS_PCI = 0x00800000UL,
|
||||
};
|
||||
|
||||
#define GET_RING_HEAD(dev_priv) (dev_priv->writeback_works ? \
|
||||
|
@ -424,6 +425,8 @@ extern int r300_do_cp_cmdbuf(drm_device_t * dev, DRMFILE filp,
|
|||
#define RADEON_RB3D_COLOROFFSET 0x1c40
|
||||
#define RADEON_RB3D_COLORPITCH 0x1c48
|
||||
|
||||
#define RADEON_SRC_X_Y 0x1590
|
||||
|
||||
#define RADEON_DP_GUI_MASTER_CNTL 0x146c
|
||||
# define RADEON_GMC_SRC_PITCH_OFFSET_CNTL (1 << 0)
|
||||
# define RADEON_GMC_DST_PITCH_OFFSET_CNTL (1 << 1)
|
||||
|
@ -441,6 +444,7 @@ extern int r300_do_cp_cmdbuf(drm_device_t * dev, DRMFILE filp,
|
|||
# define RADEON_ROP3_S 0x00cc0000
|
||||
# define RADEON_ROP3_P 0x00f00000
|
||||
#define RADEON_DP_WRITE_MASK 0x16cc
|
||||
#define RADEON_SRC_PITCH_OFFSET 0x1428
|
||||
#define RADEON_DST_PITCH_OFFSET 0x142c
|
||||
#define RADEON_DST_PITCH_OFFSET_C 0x1c80
|
||||
# define RADEON_DST_TILE_LINEAR (0 << 30)
|
||||
|
@ -545,6 +549,11 @@ extern int r300_do_cp_cmdbuf(drm_device_t * dev, DRMFILE filp,
|
|||
# define RADEON_RB3D_ZC_FREE (1 << 2)
|
||||
# define RADEON_RB3D_ZC_FLUSH_ALL 0x5
|
||||
# define RADEON_RB3D_ZC_BUSY (1 << 31)
|
||||
#define RADEON_RB3D_DSTCACHE_CTLSTAT 0x325c
|
||||
# define RADEON_RB3D_DC_FLUSH (3 << 0)
|
||||
# define RADEON_RB3D_DC_FREE (3 << 2)
|
||||
# define RADEON_RB3D_DC_FLUSH_ALL 0xf
|
||||
# define RADEON_RB3D_DC_BUSY (1 << 31)
|
||||
#define RADEON_RB3D_ZSTENCILCNTL 0x1c2c
|
||||
# define RADEON_Z_TEST_MASK (7 << 4)
|
||||
# define RADEON_Z_TEST_ALWAYS (7 << 4)
|
||||
|
@ -681,6 +690,7 @@ extern int r300_do_cp_cmdbuf(drm_device_t * dev, DRMFILE filp,
|
|||
#define RADEON_CP_RB_BASE 0x0700
|
||||
#define RADEON_CP_RB_CNTL 0x0704
|
||||
# define RADEON_BUF_SWAP_32BIT (2 << 16)
|
||||
# define RADEON_RB_NO_UPDATE (1 << 27)
|
||||
#define RADEON_CP_RB_RPTR_ADDR 0x070c
|
||||
#define RADEON_CP_RB_RPTR 0x0710
|
||||
#define RADEON_CP_RB_WPTR 0x0714
|
||||
|
@ -986,13 +996,13 @@ do { \
|
|||
} while (0)
|
||||
|
||||
#define RADEON_FLUSH_CACHE() do { \
|
||||
OUT_RING( CP_PACKET0( RADEON_RB2D_DSTCACHE_CTLSTAT, 0 ) ); \
|
||||
OUT_RING( RADEON_RB2D_DC_FLUSH ); \
|
||||
OUT_RING( CP_PACKET0( RADEON_RB3D_DSTCACHE_CTLSTAT, 0 ) ); \
|
||||
OUT_RING( RADEON_RB3D_DC_FLUSH ); \
|
||||
} while (0)
|
||||
|
||||
#define RADEON_PURGE_CACHE() do { \
|
||||
OUT_RING( CP_PACKET0( RADEON_RB2D_DSTCACHE_CTLSTAT, 0 ) ); \
|
||||
OUT_RING( RADEON_RB2D_DC_FLUSH_ALL ); \
|
||||
OUT_RING( CP_PACKET0( RADEON_RB3D_DSTCACHE_CTLSTAT, 0 ) ); \
|
||||
OUT_RING( RADEON_RB3D_DC_FLUSH_ALL ); \
|
||||
} while (0)
|
||||
|
||||
#define RADEON_FLUSH_ZCACHE() do { \
|
||||
|
|
|
@ -42,7 +42,11 @@ static __inline__ int radeon_check_and_fixup_offset(drm_radeon_private_t *
|
|||
drm_file_t * filp_priv,
|
||||
u32 *offset)
|
||||
{
|
||||
u32 off = *offset;
|
||||
u64 off = *offset;
|
||||
u32 fb_start = dev_priv->fb_location;
|
||||
u32 fb_end = fb_start + dev_priv->fb_size - 1;
|
||||
u32 gart_start = dev_priv->gart_vm_start;
|
||||
u32 gart_end = gart_start + dev_priv->gart_size - 1;
|
||||
struct drm_radeon_driver_file_fields *radeon_priv;
|
||||
|
||||
/* Hrm ... the story of the offset ... So this function converts
|
||||
|
@ -62,10 +66,8 @@ static __inline__ int radeon_check_and_fixup_offset(drm_radeon_private_t *
|
|||
/* First, the best case, the offset already lands in either the
|
||||
* framebuffer or the GART mapped space
|
||||
*/
|
||||
if ((off >= dev_priv->fb_location &&
|
||||
off < (dev_priv->fb_location + dev_priv->fb_size)) ||
|
||||
(off >= dev_priv->gart_vm_start &&
|
||||
off < (dev_priv->gart_vm_start + dev_priv->gart_size)))
|
||||
if ((off >= fb_start && off <= fb_end) ||
|
||||
(off >= gart_start && off <= gart_end))
|
||||
return 0;
|
||||
|
||||
/* Ok, that didn't happen... now check if we have a zero based
|
||||
|
@ -78,16 +80,13 @@ static __inline__ int radeon_check_and_fixup_offset(drm_radeon_private_t *
|
|||
}
|
||||
|
||||
/* Finally, assume we aimed at a GART offset if beyond the fb */
|
||||
if (off > (dev_priv->fb_location + dev_priv->fb_size))
|
||||
off = off - (dev_priv->fb_location + dev_priv->fb_size) +
|
||||
dev_priv->gart_vm_start;
|
||||
if (off > fb_end)
|
||||
off = off - fb_end - 1 + gart_start;
|
||||
|
||||
/* Now recheck and fail if out of bounds */
|
||||
if ((off >= dev_priv->fb_location &&
|
||||
off < (dev_priv->fb_location + dev_priv->fb_size)) ||
|
||||
(off >= dev_priv->gart_vm_start &&
|
||||
off < (dev_priv->gart_vm_start + dev_priv->gart_size))) {
|
||||
DRM_DEBUG("offset fixed up to 0x%x\n", off);
|
||||
if ((off >= fb_start && off <= fb_end) ||
|
||||
(off >= gart_start && off <= gart_end)) {
|
||||
DRM_DEBUG("offset fixed up to 0x%x\n", (unsigned int)off);
|
||||
*offset = off;
|
||||
return 0;
|
||||
}
|
||||
|
@ -869,7 +868,7 @@ static void radeon_cp_dispatch_clear(drm_device_t * dev,
|
|||
*/
|
||||
dev_priv->sarea_priv->ctx_owner = 0;
|
||||
|
||||
if ((dev_priv->flags & CHIP_HAS_HIERZ)
|
||||
if ((dev_priv->flags & RADEON_HAS_HIERZ)
|
||||
&& (flags & RADEON_USE_HIERZ)) {
|
||||
/* FIXME : reverse engineer that for Rx00 cards */
|
||||
/* FIXME : the mask supposedly contains low-res z values. So can't set
|
||||
|
@ -914,7 +913,7 @@ static void radeon_cp_dispatch_clear(drm_device_t * dev,
|
|||
for (i = 0; i < nbox; i++) {
|
||||
int tileoffset, nrtilesx, nrtilesy, j;
|
||||
/* it looks like r200 needs rv-style clears, at least if hierz is not enabled? */
|
||||
if ((dev_priv->flags & CHIP_HAS_HIERZ)
|
||||
if ((dev_priv->flags & RADEON_HAS_HIERZ)
|
||||
&& !(dev_priv->microcode_version == UCODE_R200)) {
|
||||
/* FIXME : figure this out for r200 (when hierz is enabled). Or
|
||||
maybe r200 actually doesn't need to put the low-res z value into
|
||||
|
@ -998,7 +997,7 @@ static void radeon_cp_dispatch_clear(drm_device_t * dev,
|
|||
}
|
||||
|
||||
/* TODO don't always clear all hi-level z tiles */
|
||||
if ((dev_priv->flags & CHIP_HAS_HIERZ)
|
||||
if ((dev_priv->flags & RADEON_HAS_HIERZ)
|
||||
&& (dev_priv->microcode_version == UCODE_R200)
|
||||
&& (flags & RADEON_USE_HIERZ))
|
||||
/* r100 and cards without hierarchical z-buffer have no high-level z-buffer */
|
||||
|
@ -1270,9 +1269,9 @@ static void radeon_cp_dispatch_swap(drm_device_t * dev)
|
|||
|
||||
DRM_DEBUG("dispatch swap %d,%d-%d,%d\n", x, y, w, h);
|
||||
|
||||
BEGIN_RING(7);
|
||||
BEGIN_RING(9);
|
||||
|
||||
OUT_RING(CP_PACKET3(RADEON_CNTL_BITBLT_MULTI, 5));
|
||||
OUT_RING(CP_PACKET0(RADEON_DP_GUI_MASTER_CNTL, 0));
|
||||
OUT_RING(RADEON_GMC_SRC_PITCH_OFFSET_CNTL |
|
||||
RADEON_GMC_DST_PITCH_OFFSET_CNTL |
|
||||
RADEON_GMC_BRUSH_NONE |
|
||||
|
@ -1284,6 +1283,7 @@ static void radeon_cp_dispatch_swap(drm_device_t * dev)
|
|||
|
||||
/* Make this work even if front & back are flipped:
|
||||
*/
|
||||
OUT_RING(CP_PACKET0(RADEON_SRC_PITCH_OFFSET, 1));
|
||||
if (dev_priv->current_page == 0) {
|
||||
OUT_RING(dev_priv->back_pitch_offset);
|
||||
OUT_RING(dev_priv->front_pitch_offset);
|
||||
|
@ -1292,6 +1292,7 @@ static void radeon_cp_dispatch_swap(drm_device_t * dev)
|
|||
OUT_RING(dev_priv->back_pitch_offset);
|
||||
}
|
||||
|
||||
OUT_RING(CP_PACKET0(RADEON_SRC_X_Y, 2));
|
||||
OUT_RING((x << 16) | y);
|
||||
OUT_RING((x << 16) | y);
|
||||
OUT_RING((w << 16) | h);
|
||||
|
@ -2987,16 +2988,21 @@ static int radeon_cp_getparam(DRM_IOCTL_ARGS)
|
|||
case RADEON_PARAM_GART_TEX_HANDLE:
|
||||
value = dev_priv->gart_textures_offset;
|
||||
break;
|
||||
|
||||
case RADEON_PARAM_SCRATCH_OFFSET:
|
||||
if (!dev_priv->writeback_works)
|
||||
return DRM_ERR(EINVAL);
|
||||
value = RADEON_SCRATCH_REG_OFFSET;
|
||||
break;
|
||||
case RADEON_PARAM_CARD_TYPE:
|
||||
if (dev_priv->flags & CHIP_IS_PCIE)
|
||||
if (dev_priv->flags & RADEON_IS_PCIE)
|
||||
value = RADEON_CARD_PCIE;
|
||||
else if (dev_priv->flags & CHIP_IS_AGP)
|
||||
else if (dev_priv->flags & RADEON_IS_AGP)
|
||||
value = RADEON_CARD_AGP;
|
||||
else
|
||||
value = RADEON_CARD_PCI;
|
||||
break;
|
||||
default:
|
||||
DRM_DEBUG("Invalid parameter %d\n", param.param);
|
||||
return DRM_ERR(EINVAL);
|
||||
}
|
||||
|
||||
|
|
|
@ -35,11 +35,44 @@ static struct pci_device_id pciidlist[] = {
|
|||
sisdrv_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 struct drm_driver driver = {
|
||||
.driver_features = DRIVER_USE_AGP | DRIVER_USE_MTRR,
|
||||
.context_ctor = sis_init_context,
|
||||
.context_dtor = sis_final_context,
|
||||
.reclaim_buffers = drm_core_reclaim_buffers,
|
||||
.load = sis_driver_load,
|
||||
.unload = sis_driver_unload,
|
||||
.context_dtor = NULL,
|
||||
.dma_quiescent = sis_idle,
|
||||
.reclaim_buffers = NULL,
|
||||
.reclaim_buffers_locked = sis_reclaim_buffers_locked,
|
||||
.lastclose = sis_lastclose,
|
||||
.get_map_ofs = drm_core_get_map_ofs,
|
||||
.get_reg_ofs = drm_core_get_reg_ofs,
|
||||
.ioctls = sis_ioctls,
|
||||
|
|
|
@ -31,23 +31,39 @@
|
|||
/* General customization:
|
||||
*/
|
||||
|
||||
#define DRIVER_AUTHOR "SIS"
|
||||
#define DRIVER_AUTHOR "SIS, Tungsten Graphics"
|
||||
#define DRIVER_NAME "sis"
|
||||
#define DRIVER_DESC "SIS 300/630/540"
|
||||
#define DRIVER_DATE "20030826"
|
||||
#define DRIVER_DATE "20060704"
|
||||
#define DRIVER_MAJOR 1
|
||||
#define DRIVER_MINOR 1
|
||||
#define DRIVER_PATCHLEVEL 0
|
||||
#define DRIVER_MINOR 2
|
||||
#define DRIVER_PATCHLEVEL 1
|
||||
|
||||
#include "sis_ds.h"
|
||||
enum sis_family {
|
||||
SIS_OTHER = 0,
|
||||
SIS_CHIP_315 = 1,
|
||||
};
|
||||
|
||||
#include "drm_sman.h"
|
||||
|
||||
#define SIS_BASE (dev_priv->mmio)
|
||||
#define SIS_READ(reg) DRM_READ32(SIS_BASE, reg);
|
||||
#define SIS_WRITE(reg, val) DRM_WRITE32(SIS_BASE, reg, val);
|
||||
|
||||
typedef struct drm_sis_private {
|
||||
memHeap_t *AGPHeap;
|
||||
memHeap_t *FBHeap;
|
||||
drm_local_map_t *mmio;
|
||||
unsigned int idle_fault;
|
||||
drm_sman_t sman;
|
||||
unsigned int chipset;
|
||||
int vram_initialized;
|
||||
int agp_initialized;
|
||||
unsigned long vram_offset;
|
||||
unsigned long agp_offset;
|
||||
} drm_sis_private_t;
|
||||
|
||||
extern int sis_init_context(drm_device_t * dev, int context);
|
||||
extern int sis_final_context(drm_device_t * dev, int context);
|
||||
extern int sis_idle(drm_device_t *dev);
|
||||
extern void sis_reclaim_buffers_locked(drm_device_t *dev, struct file *filp);
|
||||
extern void sis_lastclose(drm_device_t *dev);
|
||||
|
||||
extern drm_ioctl_desc_t sis_ioctls[];
|
||||
extern int sis_max_ioctl;
|
||||
|
|
|
@ -1,299 +0,0 @@
|
|||
/* sis_ds.c -- Private header for Direct Rendering Manager -*- linux-c -*-
|
||||
* Created: Mon Jan 4 10:05:05 1999 by sclin@sis.com.tw
|
||||
*
|
||||
* Copyright 2000 Silicon Integrated Systems Corp, Inc., HsinChu, Taiwan.
|
||||
* 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, sublicense,
|
||||
* 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 NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* PRECISION INSIGHT 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:
|
||||
* Sung-Ching Lin <sclin@sis.com.tw>
|
||||
*
|
||||
*/
|
||||
|
||||
#include "drmP.h"
|
||||
#include "drm.h"
|
||||
#include "sis_ds.h"
|
||||
|
||||
/* Set Data Structure, not check repeated value
|
||||
* temporarily used
|
||||
*/
|
||||
|
||||
set_t *setInit(void)
|
||||
{
|
||||
int i;
|
||||
set_t *set;
|
||||
|
||||
set = (set_t *) drm_alloc(sizeof(set_t), DRM_MEM_DRIVER);
|
||||
if (set != NULL) {
|
||||
for (i = 0; i < SET_SIZE; i++) {
|
||||
set->list[i].free_next = i + 1;
|
||||
set->list[i].alloc_next = -1;
|
||||
}
|
||||
set->list[SET_SIZE - 1].free_next = -1;
|
||||
set->free = 0;
|
||||
set->alloc = -1;
|
||||
set->trace = -1;
|
||||
}
|
||||
return set;
|
||||
}
|
||||
|
||||
int setAdd(set_t * set, ITEM_TYPE item)
|
||||
{
|
||||
int free = set->free;
|
||||
|
||||
if (free != -1) {
|
||||
set->list[free].val = item;
|
||||
set->free = set->list[free].free_next;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
set->list[free].alloc_next = set->alloc;
|
||||
set->alloc = free;
|
||||
set->list[free].free_next = -1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int setDel(set_t * set, ITEM_TYPE item)
|
||||
{
|
||||
int alloc = set->alloc;
|
||||
int prev = -1;
|
||||
|
||||
while (alloc != -1) {
|
||||
if (set->list[alloc].val == item) {
|
||||
if (prev != -1)
|
||||
set->list[prev].alloc_next =
|
||||
set->list[alloc].alloc_next;
|
||||
else
|
||||
set->alloc = set->list[alloc].alloc_next;
|
||||
break;
|
||||
}
|
||||
prev = alloc;
|
||||
alloc = set->list[alloc].alloc_next;
|
||||
}
|
||||
|
||||
if (alloc == -1)
|
||||
return 0;
|
||||
|
||||
set->list[alloc].free_next = set->free;
|
||||
set->free = alloc;
|
||||
set->list[alloc].alloc_next = -1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* setFirst -> setAdd -> setNext is wrong */
|
||||
|
||||
int setFirst(set_t * set, ITEM_TYPE * item)
|
||||
{
|
||||
if (set->alloc == -1)
|
||||
return 0;
|
||||
|
||||
*item = set->list[set->alloc].val;
|
||||
set->trace = set->list[set->alloc].alloc_next;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int setNext(set_t * set, ITEM_TYPE * item)
|
||||
{
|
||||
if (set->trace == -1)
|
||||
return 0;
|
||||
|
||||
*item = set->list[set->trace].val;
|
||||
set->trace = set->list[set->trace].alloc_next;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int setDestroy(set_t * set)
|
||||
{
|
||||
drm_free(set, sizeof(set_t), DRM_MEM_DRIVER);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* GLX Hardware Device Driver common code
|
||||
* Copyright (C) 1999 Wittawat Yamwong
|
||||
*
|
||||
* 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, sublicense,
|
||||
* 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 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 NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* WITTAWAT YAMWONG, OR ANY OTHER CONTRIBUTORS 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#define ISFREE(bptr) ((bptr)->free)
|
||||
|
||||
memHeap_t *mmInit(int ofs, int size)
|
||||
{
|
||||
PMemBlock blocks;
|
||||
|
||||
if (size <= 0)
|
||||
return NULL;
|
||||
|
||||
blocks = (TMemBlock *) drm_calloc(1, sizeof(TMemBlock), DRM_MEM_DRIVER);
|
||||
if (blocks != NULL) {
|
||||
blocks->ofs = ofs;
|
||||
blocks->size = size;
|
||||
blocks->free = 1;
|
||||
return (memHeap_t *) blocks;
|
||||
} else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Checks if a pointer 'b' is part of the heap 'heap' */
|
||||
int mmBlockInHeap(memHeap_t * heap, PMemBlock b)
|
||||
{
|
||||
TMemBlock *p;
|
||||
|
||||
if (heap == NULL || b == NULL)
|
||||
return 0;
|
||||
|
||||
p = heap;
|
||||
while (p != NULL && p != b) {
|
||||
p = p->next;
|
||||
}
|
||||
if (p == b)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static TMemBlock *SliceBlock(TMemBlock * p,
|
||||
int startofs, int size,
|
||||
int reserved, int alignment)
|
||||
{
|
||||
TMemBlock *newblock;
|
||||
|
||||
/* break left */
|
||||
if (startofs > p->ofs) {
|
||||
newblock = (TMemBlock *) drm_calloc(1, sizeof(TMemBlock),
|
||||
DRM_MEM_DRIVER);
|
||||
newblock->ofs = startofs;
|
||||
newblock->size = p->size - (startofs - p->ofs);
|
||||
newblock->free = 1;
|
||||
newblock->next = p->next;
|
||||
p->size -= newblock->size;
|
||||
p->next = newblock;
|
||||
p = newblock;
|
||||
}
|
||||
|
||||
/* break right */
|
||||
if (size < p->size) {
|
||||
newblock = (TMemBlock *) drm_calloc(1, sizeof(TMemBlock),
|
||||
DRM_MEM_DRIVER);
|
||||
newblock->ofs = startofs + size;
|
||||
newblock->size = p->size - size;
|
||||
newblock->free = 1;
|
||||
newblock->next = p->next;
|
||||
p->size = size;
|
||||
p->next = newblock;
|
||||
}
|
||||
|
||||
/* p = middle block */
|
||||
p->align = alignment;
|
||||
p->free = 0;
|
||||
p->reserved = reserved;
|
||||
return p;
|
||||
}
|
||||
|
||||
PMemBlock mmAllocMem(memHeap_t * heap, int size, int align2, int startSearch)
|
||||
{
|
||||
int mask, startofs, endofs;
|
||||
TMemBlock *p;
|
||||
|
||||
if (heap == NULL || align2 < 0 || size <= 0)
|
||||
return NULL;
|
||||
|
||||
mask = (1 << align2) - 1;
|
||||
startofs = 0;
|
||||
p = (TMemBlock *) heap;
|
||||
while (p != NULL) {
|
||||
if (ISFREE(p)) {
|
||||
startofs = (p->ofs + mask) & ~mask;
|
||||
if (startofs < startSearch) {
|
||||
startofs = startSearch;
|
||||
}
|
||||
endofs = startofs + size;
|
||||
if (endofs <= (p->ofs + p->size))
|
||||
break;
|
||||
}
|
||||
p = p->next;
|
||||
}
|
||||
if (p == NULL)
|
||||
return NULL;
|
||||
p = SliceBlock(p, startofs, size, 0, mask + 1);
|
||||
p->heap = heap;
|
||||
return p;
|
||||
}
|
||||
|
||||
static __inline__ int Join2Blocks(TMemBlock * p)
|
||||
{
|
||||
if (p->free && p->next && p->next->free) {
|
||||
TMemBlock *q = p->next;
|
||||
p->size += q->size;
|
||||
p->next = q->next;
|
||||
drm_free(q, sizeof(TMemBlock), DRM_MEM_DRIVER);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mmFreeMem(PMemBlock b)
|
||||
{
|
||||
TMemBlock *p, *prev;
|
||||
|
||||
if (b == NULL)
|
||||
return 0;
|
||||
if (b->heap == NULL)
|
||||
return -1;
|
||||
|
||||
p = b->heap;
|
||||
prev = NULL;
|
||||
while (p != NULL && p != b) {
|
||||
prev = p;
|
||||
p = p->next;
|
||||
}
|
||||
if (p == NULL || p->free || p->reserved)
|
||||
return -1;
|
||||
|
||||
p->free = 1;
|
||||
Join2Blocks(p);
|
||||
if (prev)
|
||||
Join2Blocks(prev);
|
||||
return 0;
|
||||
}
|
|
@ -1,146 +0,0 @@
|
|||
/* sis_ds.h -- Private header for Direct Rendering Manager -*- linux-c -*-
|
||||
* Created: Mon Jan 4 10:05:05 1999 by sclin@sis.com.tw
|
||||
*/
|
||||
/*
|
||||
* Copyright 2000 Silicon Integrated Systems Corp, Inc., HsinChu, Taiwan.
|
||||
* 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, sublicense,
|
||||
* 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 NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* PRECISION INSIGHT 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:
|
||||
* Sung-Ching Lin <sclin@sis.com.tw>
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __SIS_DS_H__
|
||||
#define __SIS_DS_H__
|
||||
|
||||
/* Set Data Structure */
|
||||
|
||||
#define SET_SIZE 5000
|
||||
|
||||
typedef unsigned long ITEM_TYPE;
|
||||
|
||||
typedef struct {
|
||||
ITEM_TYPE val;
|
||||
int alloc_next, free_next;
|
||||
} list_item_t;
|
||||
|
||||
typedef struct {
|
||||
int alloc;
|
||||
int free;
|
||||
int trace;
|
||||
list_item_t list[SET_SIZE];
|
||||
} set_t;
|
||||
|
||||
set_t *setInit(void);
|
||||
int setAdd(set_t * set, ITEM_TYPE item);
|
||||
int setDel(set_t * set, ITEM_TYPE item);
|
||||
int setFirst(set_t * set, ITEM_TYPE * item);
|
||||
int setNext(set_t * set, ITEM_TYPE * item);
|
||||
int setDestroy(set_t * set);
|
||||
|
||||
/*
|
||||
* GLX Hardware Device Driver common code
|
||||
* Copyright (C) 1999 Wittawat Yamwong
|
||||
*
|
||||
* 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, sublicense,
|
||||
* 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 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 NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* WITTAWAT YAMWONG, OR ANY OTHER CONTRIBUTORS 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.
|
||||
*
|
||||
*/
|
||||
|
||||
struct mem_block_t {
|
||||
struct mem_block_t *next;
|
||||
struct mem_block_t *heap;
|
||||
int ofs, size;
|
||||
int align;
|
||||
unsigned int free:1;
|
||||
unsigned int reserved:1;
|
||||
};
|
||||
typedef struct mem_block_t TMemBlock;
|
||||
typedef struct mem_block_t *PMemBlock;
|
||||
|
||||
/* a heap is just the first block in a chain */
|
||||
typedef struct mem_block_t memHeap_t;
|
||||
|
||||
static __inline__ int mmBlockSize(PMemBlock b)
|
||||
{
|
||||
return b->size;
|
||||
}
|
||||
|
||||
static __inline__ int mmOffset(PMemBlock b)
|
||||
{
|
||||
return b->ofs;
|
||||
}
|
||||
|
||||
static __inline__ void mmMarkReserved(PMemBlock b)
|
||||
{
|
||||
b->reserved = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* input: total size in bytes
|
||||
* return: a heap pointer if OK, NULL if error
|
||||
*/
|
||||
memHeap_t *mmInit(int ofs, int size);
|
||||
|
||||
/*
|
||||
* Allocate 'size' bytes with 2^align2 bytes alignment,
|
||||
* restrict the search to free memory after 'startSearch'
|
||||
* depth and back buffers should be in different 4mb banks
|
||||
* to get better page hits if possible
|
||||
* input: size = size of block
|
||||
* align2 = 2^align2 bytes alignment
|
||||
* startSearch = linear offset from start of heap to begin search
|
||||
* return: pointer to the allocated block, 0 if error
|
||||
*/
|
||||
PMemBlock mmAllocMem(memHeap_t * heap, int size, int align2, int startSearch);
|
||||
|
||||
/*
|
||||
* Returns 1 if the block 'b' is part of the heap 'heap'
|
||||
*/
|
||||
int mmBlockInHeap(PMemBlock heap, PMemBlock b);
|
||||
|
||||
/*
|
||||
* Free block starts at offset
|
||||
* input: pointer to a block
|
||||
* return: 0 if OK, -1 if error
|
||||
*/
|
||||
int mmFreeMem(PMemBlock b);
|
||||
|
||||
/* For debuging purpose. */
|
||||
void mmDumpMemInfo(memHeap_t * mmInit);
|
||||
|
||||
#endif /* __SIS_DS_H__ */
|
|
@ -1,414 +1,348 @@
|
|||
/* sis_mm.c -- Private header for Direct Rendering Manager -*- linux-c -*-
|
||||
* Created: Mon Jan 4 10:05:05 1999 by sclin@sis.com.tw
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright 2000 Silicon Integrated Systems Corp, Inc., HsinChu, Taiwan.
|
||||
* All rights reserved.
|
||||
* 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, sublicense,
|
||||
* 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:
|
||||
* 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 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 NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* PRECISION INSIGHT 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.
|
||||
* 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:
|
||||
* Sung-Ching Lin <sclin@sis.com.tw>
|
||||
*
|
||||
* Thomas Hellström <thomas-at-tungstengraphics-dot-com>
|
||||
*/
|
||||
|
||||
#include "drmP.h"
|
||||
#include "sis_drm.h"
|
||||
#include "sis_drv.h"
|
||||
#include "sis_ds.h"
|
||||
#if defined(__linux__) && defined(CONFIG_FB_SIS)
|
||||
#include <video/sisfb.h>
|
||||
#endif
|
||||
|
||||
#define MAX_CONTEXT 100
|
||||
#include <video/sisfb.h>
|
||||
|
||||
#define VIDEO_TYPE 0
|
||||
#define AGP_TYPE 1
|
||||
|
||||
typedef struct {
|
||||
int used;
|
||||
int context;
|
||||
set_t *sets[2]; /* 0 for video, 1 for AGP */
|
||||
} sis_context_t;
|
||||
|
||||
static sis_context_t global_ppriv[MAX_CONTEXT];
|
||||
|
||||
static int add_alloc_set(int context, int type, unsigned int val)
|
||||
{
|
||||
int i, retval = 0;
|
||||
|
||||
for (i = 0; i < MAX_CONTEXT; i++) {
|
||||
if (global_ppriv[i].used && global_ppriv[i].context == context) {
|
||||
retval = setAdd(global_ppriv[i].sets[type], val);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int del_alloc_set(int context, int type, unsigned int val)
|
||||
{
|
||||
int i, retval = 0;
|
||||
|
||||
for (i = 0; i < MAX_CONTEXT; i++) {
|
||||
if (global_ppriv[i].used && global_ppriv[i].context == context) {
|
||||
retval = setDel(global_ppriv[i].sets[type], val);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_FB_SIS)
|
||||
/* fb management via fb device */
|
||||
#if defined(__linux__) && defined(CONFIG_FB_SIS)
|
||||
|
||||
static int sis_fb_init(DRM_IOCTL_ARGS)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#define SIS_MM_ALIGN_SHIFT 0
|
||||
#define SIS_MM_ALIGN_MASK 0
|
||||
|
||||
static int sis_fb_alloc(DRM_IOCTL_ARGS)
|
||||
static void *sis_sman_mm_allocate(void *private, unsigned long size,
|
||||
unsigned alignment)
|
||||
{
|
||||
drm_sis_mem_t fb;
|
||||
struct sis_memreq req;
|
||||
drm_sis_mem_t __user *argp = (drm_sis_mem_t __user *)data;
|
||||
int retval = 0;
|
||||
|
||||
DRM_COPY_FROM_USER_IOCTL(fb, argp, sizeof(fb));
|
||||
|
||||
req.size = fb.size;
|
||||
req.size = size;
|
||||
sis_malloc(&req);
|
||||
if (req.offset) {
|
||||
/* TODO */
|
||||
fb.offset = req.offset;
|
||||
fb.free = req.offset;
|
||||
if (!add_alloc_set(fb.context, VIDEO_TYPE, fb.free)) {
|
||||
DRM_DEBUG("adding to allocation set fails\n");
|
||||
sis_free(req.offset);
|
||||
retval = DRM_ERR(EINVAL);
|
||||
}
|
||||
} else {
|
||||
fb.offset = 0;
|
||||
fb.size = 0;
|
||||
fb.free = 0;
|
||||
}
|
||||
|
||||
DRM_COPY_TO_USER_IOCTL(argp, fb, sizeof(fb));
|
||||
|
||||
DRM_DEBUG("alloc fb, size = %d, offset = %d\n", fb.size, req.offset);
|
||||
|
||||
return retval;
|
||||
if (req.size == 0)
|
||||
return NULL;
|
||||
else
|
||||
return (void *)~req.offset;
|
||||
}
|
||||
|
||||
static int sis_fb_free(DRM_IOCTL_ARGS)
|
||||
static void sis_sman_mm_free(void *private, void *ref)
|
||||
{
|
||||
drm_sis_mem_t fb;
|
||||
int retval = 0;
|
||||
|
||||
DRM_COPY_FROM_USER_IOCTL(fb, (drm_sis_mem_t __user *) data, sizeof(fb));
|
||||
|
||||
if (!fb.free)
|
||||
return DRM_ERR(EINVAL);
|
||||
|
||||
if (!del_alloc_set(fb.context, VIDEO_TYPE, fb.free))
|
||||
retval = DRM_ERR(EINVAL);
|
||||
sis_free(fb.free);
|
||||
|
||||
DRM_DEBUG("free fb, offset = 0x%lx\n", fb.free);
|
||||
|
||||
return retval;
|
||||
sis_free(~((unsigned long)ref));
|
||||
}
|
||||
|
||||
#else
|
||||
static void sis_sman_mm_destroy(void *private)
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
static unsigned long sis_sman_mm_offset(void *private, void *ref)
|
||||
{
|
||||
return ~((unsigned long)ref);
|
||||
}
|
||||
|
||||
#else /* CONFIG_FB_SIS */
|
||||
|
||||
#define SIS_MM_ALIGN_SHIFT 4
|
||||
#define SIS_MM_ALIGN_MASK ( (1 << SIS_MM_ALIGN_SHIFT) - 1)
|
||||
|
||||
#endif /* CONFIG_FB_SIS */
|
||||
|
||||
/* Called by the X Server to initialize the FB heap. Allocations will fail
|
||||
* unless this is called. Offset is the beginning of the heap from the
|
||||
* framebuffer offset (MaxXFBMem in XFree86).
|
||||
*
|
||||
* Memory layout according to Thomas Winischofer:
|
||||
* |------------------|DDDDDDDDDDDDDDDDDDDDDDDDDDDDD|HHHH|CCCCCCCCCCC|
|
||||
*
|
||||
* X driver/sisfb HW- Command-
|
||||
* framebuffer memory DRI heap Cursor queue
|
||||
*/
|
||||
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));
|
||||
|
||||
if (dev_priv == NULL) {
|
||||
dev->dev_private = drm_calloc(1, sizeof(drm_sis_private_t),
|
||||
DRM_MEM_DRIVER);
|
||||
dev_priv = dev->dev_private;
|
||||
if (dev_priv == NULL)
|
||||
return ENOMEM;
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
#if 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");
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (dev_priv->FBHeap != NULL)
|
||||
return DRM_ERR(EINVAL);
|
||||
|
||||
dev_priv->FBHeap = mmInit(fb.offset, fb.size);
|
||||
dev_priv->vram_initialized = 1;
|
||||
dev_priv->vram_offset = fb.offset;
|
||||
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
DRM_DEBUG("offset = %u, size = %u", fb.offset, fb.size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sis_fb_alloc(DRM_IOCTL_ARGS)
|
||||
static int sis_drm_alloc(drm_device_t * dev, drm_file_t * priv,
|
||||
unsigned long data, int pool)
|
||||
{
|
||||
DRM_DEVICE;
|
||||
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 fb;
|
||||
PMemBlock block;
|
||||
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;
|
||||
|
||||
if (dev_priv == NULL || dev_priv->FBHeap == NULL)
|
||||
DRM_COPY_FROM_USER_IOCTL(mem, argp, sizeof(mem));
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
|
||||
if (0 == ((pool == 0) ? dev_priv->vram_initialized :
|
||||
dev_priv->agp_initialized)) {
|
||||
DRM_ERROR
|
||||
("Attempt to allocate from uninitialized memory manager.\n");
|
||||
return DRM_ERR(EINVAL);
|
||||
|
||||
DRM_COPY_FROM_USER_IOCTL(fb, argp, sizeof(fb));
|
||||
|
||||
block = mmAllocMem(dev_priv->FBHeap, fb.size, 0, 0);
|
||||
if (block) {
|
||||
/* TODO */
|
||||
fb.offset = block->ofs;
|
||||
fb.free = (unsigned long)block;
|
||||
if (!add_alloc_set(fb.context, VIDEO_TYPE, fb.free)) {
|
||||
DRM_DEBUG("adding to allocation set fails\n");
|
||||
mmFreeMem((PMemBlock) fb.free);
|
||||
retval = DRM_ERR(EINVAL);
|
||||
}
|
||||
} else {
|
||||
fb.offset = 0;
|
||||
fb.size = 0;
|
||||
fb.free = 0;
|
||||
}
|
||||
|
||||
DRM_COPY_TO_USER_IOCTL(argp, fb, sizeof(fb));
|
||||
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);
|
||||
|
||||
DRM_DEBUG("alloc fb, size = %d, offset = %d\n", fb.size, fb.offset);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
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_fb_free(DRM_IOCTL_ARGS)
|
||||
static int sis_drm_free(DRM_IOCTL_ARGS)
|
||||
{
|
||||
DRM_DEVICE;
|
||||
drm_sis_private_t *dev_priv = dev->dev_private;
|
||||
drm_sis_mem_t fb;
|
||||
drm_sis_mem_t mem;
|
||||
int ret;
|
||||
|
||||
if (dev_priv == NULL || dev_priv->FBHeap == NULL)
|
||||
return DRM_ERR(EINVAL);
|
||||
DRM_COPY_FROM_USER_IOCTL(mem, (drm_sis_mem_t __user *) data,
|
||||
sizeof(mem));
|
||||
|
||||
DRM_COPY_FROM_USER_IOCTL(fb, (drm_sis_mem_t __user *) data, sizeof(fb));
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
ret = drm_sman_free_key(&dev_priv->sman, mem.free);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
DRM_DEBUG("free = 0x%lx\n", mem.free);
|
||||
|
||||
if (!mmBlockInHeap(dev_priv->FBHeap, (PMemBlock) fb.free))
|
||||
return DRM_ERR(EINVAL);
|
||||
|
||||
if (!del_alloc_set(fb.context, VIDEO_TYPE, fb.free))
|
||||
return DRM_ERR(EINVAL);
|
||||
mmFreeMem((PMemBlock) fb.free);
|
||||
|
||||
DRM_DEBUG("free fb, free = 0x%lx\n", fb.free);
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* agp memory management */
|
||||
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;
|
||||
|
||||
if (dev_priv == NULL) {
|
||||
dev->dev_private = drm_calloc(1, sizeof(drm_sis_private_t),
|
||||
DRM_MEM_DRIVER);
|
||||
dev_priv = dev->dev_private;
|
||||
if (dev_priv == NULL)
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
if (dev_priv->AGPHeap != NULL)
|
||||
return DRM_ERR(EINVAL);
|
||||
int ret;
|
||||
dev_priv = dev->dev_private;
|
||||
|
||||
DRM_COPY_FROM_USER_IOCTL(agp, (drm_sis_agp_t __user *) data,
|
||||
sizeof(agp));
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
ret = drm_sman_set_range(&dev_priv->sman, AGP_TYPE, 0,
|
||||
agp.size >> SIS_MM_ALIGN_SHIFT);
|
||||
|
||||
dev_priv->AGPHeap = mmInit(agp.offset, agp.size);
|
||||
if (ret) {
|
||||
DRM_ERROR("AGP memory manager initialisation error\n");
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
dev_priv->agp_initialized = 1;
|
||||
dev_priv->agp_offset = agp.offset;
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
DRM_DEBUG("offset = %u, size = %u", agp.offset, agp.size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sis_ioctl_agp_alloc(DRM_IOCTL_ARGS)
|
||||
{
|
||||
DRM_DEVICE;
|
||||
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 agp;
|
||||
PMemBlock block;
|
||||
int retval = 0;
|
||||
|
||||
if (dev_priv == NULL || dev_priv->AGPHeap == NULL)
|
||||
return DRM_ERR(EINVAL);
|
||||
|
||||
DRM_COPY_FROM_USER_IOCTL(agp, argp, sizeof(agp));
|
||||
|
||||
block = mmAllocMem(dev_priv->AGPHeap, agp.size, 0, 0);
|
||||
if (block) {
|
||||
/* TODO */
|
||||
agp.offset = block->ofs;
|
||||
agp.free = (unsigned long)block;
|
||||
if (!add_alloc_set(agp.context, AGP_TYPE, agp.free)) {
|
||||
DRM_DEBUG("adding to allocation set fails\n");
|
||||
mmFreeMem((PMemBlock) agp.free);
|
||||
retval = -1;
|
||||
}
|
||||
} else {
|
||||
agp.offset = 0;
|
||||
agp.size = 0;
|
||||
agp.free = 0;
|
||||
}
|
||||
|
||||
DRM_COPY_TO_USER_IOCTL(argp, agp, sizeof(agp));
|
||||
|
||||
DRM_DEBUG("alloc agp, size = %d, offset = %d\n", agp.size, agp.offset);
|
||||
|
||||
return retval;
|
||||
return sis_drm_alloc(dev, priv, data, AGP_TYPE);
|
||||
}
|
||||
|
||||
static int sis_ioctl_agp_free(DRM_IOCTL_ARGS)
|
||||
static drm_local_map_t *sis_reg_init(drm_device_t *dev)
|
||||
{
|
||||
drm_map_list_t *entry;
|
||||
drm_local_map_t *map;
|
||||
|
||||
list_for_each_entry(entry, &dev->maplist->head, head) {
|
||||
map = entry->map;
|
||||
if (!map)
|
||||
continue;
|
||||
if (map->type == _DRM_REGISTERS) {
|
||||
return map;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int sis_idle(drm_device_t *dev)
|
||||
{
|
||||
DRM_DEVICE;
|
||||
drm_sis_private_t *dev_priv = dev->dev_private;
|
||||
drm_sis_mem_t agp;
|
||||
uint32_t idle_reg;
|
||||
unsigned long end;
|
||||
int i;
|
||||
|
||||
if (dev_priv == NULL || dev_priv->AGPHeap == NULL)
|
||||
return DRM_ERR(EINVAL);
|
||||
if (dev_priv->idle_fault)
|
||||
return 0;
|
||||
|
||||
DRM_COPY_FROM_USER_IOCTL(agp, (drm_sis_mem_t __user *) data,
|
||||
sizeof(agp));
|
||||
if (dev_priv->mmio == NULL) {
|
||||
dev_priv->mmio = sis_reg_init(dev);
|
||||
if (dev_priv->mmio == NULL) {
|
||||
DRM_ERROR("Could not find register map.\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Implement a device switch here if needed
|
||||
*/
|
||||
|
||||
if (!mmBlockInHeap(dev_priv->AGPHeap, (PMemBlock) agp.free))
|
||||
return DRM_ERR(EINVAL);
|
||||
if (dev_priv->chipset != SIS_CHIP_315)
|
||||
return 0;
|
||||
|
||||
mmFreeMem((PMemBlock) agp.free);
|
||||
if (!del_alloc_set(agp.context, AGP_TYPE, agp.free))
|
||||
return DRM_ERR(EINVAL);
|
||||
/*
|
||||
* Timeout after 3 seconds. We cannot use DRM_WAIT_ON here
|
||||
* because its polling frequency is too low.
|
||||
*/
|
||||
|
||||
DRM_DEBUG("free agp, free = 0x%lx\n", agp.free);
|
||||
end = jiffies + (DRM_HZ * 3);
|
||||
|
||||
for (i=0; i<4; ++i) {
|
||||
do {
|
||||
idle_reg = SIS_READ(0x85cc);
|
||||
} while ( !time_after_eq(jiffies, end) &&
|
||||
((idle_reg & 0x80000000) != 0x80000000));
|
||||
}
|
||||
|
||||
if (time_after_eq(jiffies, end)) {
|
||||
DRM_ERROR("Graphics engine idle timeout. "
|
||||
"Disabling idle check\n");
|
||||
dev_priv->idle_fault = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* The caller never sees an error code. It gets trapped
|
||||
* in libdrm.
|
||||
*/
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sis_init_context(struct drm_device *dev, int context)
|
||||
|
||||
void sis_lastclose(struct drm_device *dev)
|
||||
{
|
||||
int i;
|
||||
drm_sis_private_t *dev_priv = dev->dev_private;
|
||||
|
||||
for (i = 0; i < MAX_CONTEXT; i++) {
|
||||
if (global_ppriv[i].used &&
|
||||
(global_ppriv[i].context == context))
|
||||
break;
|
||||
}
|
||||
if (!dev_priv)
|
||||
return;
|
||||
|
||||
if (i >= MAX_CONTEXT) {
|
||||
for (i = 0; i < MAX_CONTEXT; i++) {
|
||||
if (!global_ppriv[i].used) {
|
||||
global_ppriv[i].context = context;
|
||||
global_ppriv[i].used = 1;
|
||||
global_ppriv[i].sets[0] = setInit();
|
||||
global_ppriv[i].sets[1] = setInit();
|
||||
DRM_DEBUG("init allocation set, socket=%d, "
|
||||
"context = %d\n", i, context);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ((i >= MAX_CONTEXT) || (global_ppriv[i].sets[0] == NULL) ||
|
||||
(global_ppriv[i].sets[1] == NULL)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
drm_sman_cleanup(&dev_priv->sman);
|
||||
dev_priv->vram_initialized = 0;
|
||||
dev_priv->agp_initialized = 0;
|
||||
dev_priv->mmio = NULL;
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
}
|
||||
|
||||
int sis_final_context(struct drm_device *dev, int context)
|
||||
void sis_reclaim_buffers_locked(drm_device_t * dev, struct file *filp)
|
||||
{
|
||||
int i;
|
||||
drm_sis_private_t *dev_priv = dev->dev_private;
|
||||
drm_file_t *priv = filp->private_data;
|
||||
|
||||
for (i = 0; i < MAX_CONTEXT; i++) {
|
||||
if (global_ppriv[i].used &&
|
||||
(global_ppriv[i].context == context))
|
||||
break;
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
if (drm_sman_owner_clean(&dev_priv->sman, (unsigned long)priv)) {
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
if (i < MAX_CONTEXT) {
|
||||
set_t *set;
|
||||
ITEM_TYPE item;
|
||||
int retval;
|
||||
|
||||
DRM_DEBUG("find socket %d, context = %d\n", i, context);
|
||||
|
||||
/* Video Memory */
|
||||
set = global_ppriv[i].sets[0];
|
||||
retval = setFirst(set, &item);
|
||||
while (retval) {
|
||||
DRM_DEBUG("free video memory 0x%lx\n", item);
|
||||
#if defined(__linux__) && defined(CONFIG_FB_SIS)
|
||||
sis_free(item);
|
||||
#else
|
||||
mmFreeMem((PMemBlock) item);
|
||||
#endif
|
||||
retval = setNext(set, &item);
|
||||
}
|
||||
setDestroy(set);
|
||||
|
||||
/* AGP Memory */
|
||||
set = global_ppriv[i].sets[1];
|
||||
retval = setFirst(set, &item);
|
||||
while (retval) {
|
||||
DRM_DEBUG("free agp memory 0x%lx\n", item);
|
||||
mmFreeMem((PMemBlock) item);
|
||||
retval = setNext(set, &item);
|
||||
}
|
||||
setDestroy(set);
|
||||
|
||||
global_ppriv[i].used = 0;
|
||||
if (dev->driver->dma_quiescent) {
|
||||
dev->driver->dma_quiescent(dev);
|
||||
}
|
||||
|
||||
return 1;
|
||||
drm_sman_owner_cleanup(&dev_priv->sman, (unsigned long)priv);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
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_fb_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_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_ioctl_agp_free, DRM_AUTH},
|
||||
[DRM_IOCTL_NR(DRM_SIS_FB_INIT)] = {sis_fb_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}
|
||||
[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);
|
||||
|
|
|
@ -41,9 +41,9 @@
|
|||
|
||||
#include <linux/pagemap.h>
|
||||
|
||||
#define VIA_PGDN(x) (((unsigned long)(x)) & PAGE_MASK)
|
||||
#define VIA_PGOFF(x) (((unsigned long)(x)) & ~PAGE_MASK)
|
||||
#define VIA_PFN(x) ((unsigned long)(x) >> PAGE_SHIFT)
|
||||
#define VIA_PGDN(x) (((unsigned long)(x)) & PAGE_MASK)
|
||||
#define VIA_PGOFF(x) (((unsigned long)(x)) & ~PAGE_MASK)
|
||||
#define VIA_PFN(x) ((unsigned long)(x) >> PAGE_SHIFT)
|
||||
|
||||
typedef struct _drm_via_descriptor {
|
||||
uint32_t mem_addr;
|
||||
|
@ -121,19 +121,19 @@ via_map_blit_for_device(struct pci_dev *pdev,
|
|||
|
||||
while (line_len > 0) {
|
||||
|
||||
remaining_len = min(PAGE_SIZE-VIA_PGOFF(cur_mem), line_len);
|
||||
remaining_len = min(PAGE_SIZE-VIA_PGOFF(cur_mem), line_len);
|
||||
line_len -= remaining_len;
|
||||
|
||||
if (mode == 1) {
|
||||
desc_ptr->mem_addr =
|
||||
desc_ptr->mem_addr =
|
||||
dma_map_page(&pdev->dev,
|
||||
vsg->pages[VIA_PFN(cur_mem) -
|
||||
VIA_PFN(first_addr)],
|
||||
VIA_PGOFF(cur_mem), remaining_len,
|
||||
vsg->direction);
|
||||
desc_ptr->dev_addr = cur_fb;
|
||||
desc_ptr->dev_addr = cur_fb;
|
||||
|
||||
desc_ptr->size = remaining_len;
|
||||
desc_ptr->size = remaining_len;
|
||||
desc_ptr->next = (uint32_t) next;
|
||||
next = dma_map_single(&pdev->dev, desc_ptr, sizeof(*desc_ptr),
|
||||
DMA_TO_DEVICE);
|
||||
|
@ -162,7 +162,7 @@ via_map_blit_for_device(struct pci_dev *pdev,
|
|||
|
||||
/*
|
||||
* Function that frees up all resources for a blit. It is usable even if the
|
||||
* blit info has only be partially built as long as the status enum is consistent
|
||||
* blit info has only been partially built as long as the status enum is consistent
|
||||
* with the actual status of the used resources.
|
||||
*/
|
||||
|
||||
|
@ -238,8 +238,11 @@ via_lock_all_dma_pages(drm_via_sg_info_t *vsg, drm_via_dmablit_t *xfer)
|
|||
return DRM_ERR(ENOMEM);
|
||||
memset(vsg->pages, 0, sizeof(struct page *) * vsg->num_pages);
|
||||
down_read(¤t->mm->mmap_sem);
|
||||
ret = get_user_pages(current, current->mm, (unsigned long) xfer->mem_addr,
|
||||
vsg->num_pages, vsg->direction, 0, vsg->pages, NULL);
|
||||
ret = get_user_pages(current, current->mm,
|
||||
(unsigned long)xfer->mem_addr,
|
||||
vsg->num_pages,
|
||||
(vsg->direction == DMA_FROM_DEVICE),
|
||||
0, vsg->pages, NULL);
|
||||
|
||||
up_read(¤t->mm->mmap_sem);
|
||||
if (ret != vsg->num_pages) {
|
||||
|
@ -475,9 +478,15 @@ via_dmablit_timer(unsigned long data)
|
|||
if (!timer_pending(&blitq->poll_timer)) {
|
||||
blitq->poll_timer.expires = jiffies+1;
|
||||
add_timer(&blitq->poll_timer);
|
||||
}
|
||||
via_dmablit_handler(dev, engine, 0);
|
||||
|
||||
/*
|
||||
* Rerun handler to delete timer if engines are off, and
|
||||
* to shorten abort latency. This is a little nasty.
|
||||
*/
|
||||
|
||||
via_dmablit_handler(dev, engine, 0);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -597,15 +606,27 @@ via_build_sg_info(drm_device_t *dev, drm_via_sg_info_t *vsg, drm_via_dmablit_t *
|
|||
* (Not a big limitation anyway.)
|
||||
*/
|
||||
|
||||
if (((xfer->mem_stride - xfer->line_length) >= PAGE_SIZE) ||
|
||||
(xfer->mem_stride > 2048*4)) {
|
||||
if ((xfer->mem_stride - xfer->line_length) >= PAGE_SIZE) {
|
||||
DRM_ERROR("Too large system memory stride. Stride: %d, "
|
||||
"Length: %d\n", xfer->mem_stride, xfer->line_length);
|
||||
return DRM_ERR(EINVAL);
|
||||
}
|
||||
|
||||
if (xfer->num_lines > 2048) {
|
||||
DRM_ERROR("Too many PCI DMA bitblt lines.\n");
|
||||
if ((xfer->mem_stride == xfer->line_length) &&
|
||||
(xfer->fb_stride == xfer->line_length)) {
|
||||
xfer->mem_stride *= xfer->num_lines;
|
||||
xfer->line_length = xfer->mem_stride;
|
||||
xfer->fb_stride = xfer->mem_stride;
|
||||
xfer->num_lines = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Don't lock an arbitrary large number of pages, since that causes a
|
||||
* DOS security hole.
|
||||
*/
|
||||
|
||||
if (xfer->num_lines > 2048 || (xfer->num_lines*xfer->mem_stride > (2048*2048*4))) {
|
||||
DRM_ERROR("Too large PCI DMA bitblt.\n");
|
||||
return DRM_ERR(EINVAL);
|
||||
}
|
||||
|
||||
|
@ -628,16 +649,17 @@ via_build_sg_info(drm_device_t *dev, drm_via_sg_info_t *vsg, drm_via_dmablit_t *
|
|||
|
||||
#ifdef VIA_BUGFREE
|
||||
if ((((unsigned long)xfer->mem_addr & 3) != ((unsigned long)xfer->fb_addr & 3)) ||
|
||||
((xfer->mem_stride & 3) != (xfer->fb_stride & 3))) {
|
||||
((xfer->num_lines > 1) && ((xfer->mem_stride & 3) != (xfer->fb_stride & 3)))) {
|
||||
DRM_ERROR("Invalid DRM bitblt alignment.\n");
|
||||
return DRM_ERR(EINVAL);
|
||||
return DRM_ERR(EINVAL);
|
||||
}
|
||||
#else
|
||||
if ((((unsigned long)xfer->mem_addr & 15) ||
|
||||
((unsigned long)xfer->fb_addr & 3)) || (xfer->mem_stride & 15) ||
|
||||
(xfer->fb_stride & 3)) {
|
||||
((unsigned long)xfer->fb_addr & 3)) ||
|
||||
((xfer->num_lines > 1) &&
|
||||
((xfer->mem_stride & 15) || (xfer->fb_stride & 3)))) {
|
||||
DRM_ERROR("Invalid DRM bitblt alignment.\n");
|
||||
return DRM_ERR(EINVAL);
|
||||
return DRM_ERR(EINVAL);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -715,7 +737,7 @@ via_dmablit(drm_device_t *dev, drm_via_dmablit_t *xfer)
|
|||
drm_via_private_t *dev_priv = (drm_via_private_t *)dev->dev_private;
|
||||
drm_via_sg_info_t *vsg;
|
||||
drm_via_blitq_t *blitq;
|
||||
int ret;
|
||||
int ret;
|
||||
int engine;
|
||||
unsigned long irqsave;
|
||||
|
||||
|
@ -756,7 +778,7 @@ via_dmablit(drm_device_t *dev, drm_via_dmablit_t *xfer)
|
|||
|
||||
/*
|
||||
* Sync on a previously submitted blit. Note that the X server use signals extensively, and
|
||||
* that there is a very big proability that this IOCTL will be interrupted by a signal. In that
|
||||
* that there is a very big probability that this IOCTL will be interrupted by a signal. In that
|
||||
* case it returns with -EAGAIN for the signal to be delivered.
|
||||
* The caller should then reissue the IOCTL. This is similar to what is being done for drmGetLock().
|
||||
*/
|
||||
|
|
|
@ -250,6 +250,12 @@ typedef struct drm_via_blitsync {
|
|||
unsigned engine;
|
||||
} drm_via_blitsync_t;
|
||||
|
||||
/* - * Below,"flags" is currently unused but will be used for possible future
|
||||
* extensions like kernel space bounce buffers for bad alignments and
|
||||
* blit engine busy-wait polling for better latency in the absence of
|
||||
* interrupts.
|
||||
*/
|
||||
|
||||
typedef struct drm_via_dmablit {
|
||||
uint32_t num_lines;
|
||||
uint32_t line_length;
|
||||
|
@ -260,7 +266,7 @@ typedef struct drm_via_dmablit {
|
|||
unsigned char *mem_addr;
|
||||
uint32_t mem_stride;
|
||||
|
||||
int bounce_buffer;
|
||||
uint32_t flags;
|
||||
int to_fb;
|
||||
|
||||
drm_via_blitsync_t sync;
|
||||
|
|
|
@ -43,7 +43,6 @@ static struct drm_driver driver = {
|
|||
DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL,
|
||||
.load = via_driver_load,
|
||||
.unload = via_driver_unload,
|
||||
.context_ctor = via_init_context,
|
||||
.context_dtor = via_final_context,
|
||||
.vblank_wait = via_driver_vblank_wait,
|
||||
.irq_preinstall = via_driver_irq_preinstall,
|
||||
|
@ -53,6 +52,8 @@ static struct drm_driver driver = {
|
|||
.dma_quiescent = via_driver_dma_quiescent,
|
||||
.dri_library_name = dri_library_name,
|
||||
.reclaim_buffers = drm_core_reclaim_buffers,
|
||||
.reclaim_buffers_locked = via_reclaim_buffers_locked,
|
||||
.lastclose = via_lastclose,
|
||||
.get_map_ofs = drm_core_get_map_ofs,
|
||||
.get_reg_ofs = drm_core_get_reg_ofs,
|
||||
.ioctls = via_ioctls,
|
||||
|
|
|
@ -24,15 +24,16 @@
|
|||
#ifndef _VIA_DRV_H_
|
||||
#define _VIA_DRV_H_
|
||||
|
||||
#include "drm_sman.h"
|
||||
#define DRIVER_AUTHOR "Various"
|
||||
|
||||
#define DRIVER_NAME "via"
|
||||
#define DRIVER_DESC "VIA Unichrome / Pro"
|
||||
#define DRIVER_DATE "20051116"
|
||||
#define DRIVER_DATE "20060529"
|
||||
|
||||
#define DRIVER_MAJOR 2
|
||||
#define DRIVER_MINOR 7
|
||||
#define DRIVER_PATCHLEVEL 4
|
||||
#define DRIVER_MINOR 10
|
||||
#define DRIVER_PATCHLEVEL 0
|
||||
|
||||
#include "via_verifier.h"
|
||||
|
||||
|
@ -85,6 +86,12 @@ typedef struct drm_via_private {
|
|||
uint32_t irq_enable_mask;
|
||||
uint32_t irq_pending_mask;
|
||||
int *irq_map;
|
||||
unsigned int idle_fault;
|
||||
drm_sman_t sman;
|
||||
int vram_initialized;
|
||||
int agp_initialized;
|
||||
unsigned long vram_offset;
|
||||
unsigned long agp_offset;
|
||||
drm_via_blitq_t blit_queues[VIA_NUM_BLIT_ENGINES];
|
||||
} drm_via_private_t;
|
||||
|
||||
|
@ -135,6 +142,9 @@ extern void via_init_futex(drm_via_private_t * dev_priv);
|
|||
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 void via_reclaim_buffers_locked(drm_device_t *dev, struct file *filp);
|
||||
extern void via_lastclose(drm_device_t *dev);
|
||||
|
||||
extern void via_dmablit_handler(drm_device_t *dev, int engine, int from_irq);
|
||||
extern void via_init_dmablit(drm_device_t *dev);
|
||||
|
||||
|
|
|
@ -1,273 +0,0 @@
|
|||
/*
|
||||
* Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
|
||||
* Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved.
|
||||
* Copyright 2000 Silicon Integrated Systems Corp, Inc., HsinChu, Taiwan.
|
||||
*
|
||||
* 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
|
||||
* VIA, S3 GRAPHICS, 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.
|
||||
*/
|
||||
#include "drmP.h"
|
||||
|
||||
#include "via_ds.h"
|
||||
extern unsigned int VIA_DEBUG;
|
||||
|
||||
set_t *via_setInit(void)
|
||||
{
|
||||
int i;
|
||||
set_t *set;
|
||||
set = (set_t *) drm_alloc(sizeof(set_t), DRM_MEM_DRIVER);
|
||||
for (i = 0; i < SET_SIZE; i++) {
|
||||
set->list[i].free_next = i + 1;
|
||||
set->list[i].alloc_next = -1;
|
||||
}
|
||||
set->list[SET_SIZE - 1].free_next = -1;
|
||||
set->free = 0;
|
||||
set->alloc = -1;
|
||||
set->trace = -1;
|
||||
return set;
|
||||
}
|
||||
|
||||
int via_setAdd(set_t * set, ITEM_TYPE item)
|
||||
{
|
||||
int free = set->free;
|
||||
if (free != -1) {
|
||||
set->list[free].val = item;
|
||||
set->free = set->list[free].free_next;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
set->list[free].alloc_next = set->alloc;
|
||||
set->alloc = free;
|
||||
set->list[free].free_next = -1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int via_setDel(set_t * set, ITEM_TYPE item)
|
||||
{
|
||||
int alloc = set->alloc;
|
||||
int prev = -1;
|
||||
|
||||
while (alloc != -1) {
|
||||
if (set->list[alloc].val == item) {
|
||||
if (prev != -1)
|
||||
set->list[prev].alloc_next =
|
||||
set->list[alloc].alloc_next;
|
||||
else
|
||||
set->alloc = set->list[alloc].alloc_next;
|
||||
break;
|
||||
}
|
||||
prev = alloc;
|
||||
alloc = set->list[alloc].alloc_next;
|
||||
}
|
||||
|
||||
if (alloc == -1)
|
||||
return 0;
|
||||
|
||||
set->list[alloc].free_next = set->free;
|
||||
set->free = alloc;
|
||||
set->list[alloc].alloc_next = -1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* setFirst -> setAdd -> setNext is wrong */
|
||||
|
||||
int via_setFirst(set_t * set, ITEM_TYPE * item)
|
||||
{
|
||||
if (set->alloc == -1)
|
||||
return 0;
|
||||
|
||||
*item = set->list[set->alloc].val;
|
||||
set->trace = set->list[set->alloc].alloc_next;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int via_setNext(set_t * set, ITEM_TYPE * item)
|
||||
{
|
||||
if (set->trace == -1)
|
||||
return 0;
|
||||
|
||||
*item = set->list[set->trace].val;
|
||||
set->trace = set->list[set->trace].alloc_next;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int via_setDestroy(set_t * set)
|
||||
{
|
||||
drm_free(set, sizeof(set_t), DRM_MEM_DRIVER);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define ISFREE(bptr) ((bptr)->free)
|
||||
|
||||
#define fprintf(fmt, arg...) do{}while(0)
|
||||
|
||||
memHeap_t *via_mmInit(int ofs, int size)
|
||||
{
|
||||
PMemBlock blocks;
|
||||
|
||||
if (size <= 0)
|
||||
return NULL;
|
||||
|
||||
blocks = (TMemBlock *) drm_calloc(1, sizeof(TMemBlock), DRM_MEM_DRIVER);
|
||||
|
||||
if (blocks) {
|
||||
blocks->ofs = ofs;
|
||||
blocks->size = size;
|
||||
blocks->free = 1;
|
||||
return (memHeap_t *) blocks;
|
||||
} else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static TMemBlock *SliceBlock(TMemBlock * p,
|
||||
int startofs, int size,
|
||||
int reserved, int alignment)
|
||||
{
|
||||
TMemBlock *newblock;
|
||||
|
||||
/* break left */
|
||||
if (startofs > p->ofs) {
|
||||
newblock =
|
||||
(TMemBlock *) drm_calloc(1, sizeof(TMemBlock),
|
||||
DRM_MEM_DRIVER);
|
||||
newblock->ofs = startofs;
|
||||
newblock->size = p->size - (startofs - p->ofs);
|
||||
newblock->free = 1;
|
||||
newblock->next = p->next;
|
||||
p->size -= newblock->size;
|
||||
p->next = newblock;
|
||||
p = newblock;
|
||||
}
|
||||
|
||||
/* break right */
|
||||
if (size < p->size) {
|
||||
newblock =
|
||||
(TMemBlock *) drm_calloc(1, sizeof(TMemBlock),
|
||||
DRM_MEM_DRIVER);
|
||||
newblock->ofs = startofs + size;
|
||||
newblock->size = p->size - size;
|
||||
newblock->free = 1;
|
||||
newblock->next = p->next;
|
||||
p->size = size;
|
||||
p->next = newblock;
|
||||
}
|
||||
|
||||
/* p = middle block */
|
||||
p->align = alignment;
|
||||
p->free = 0;
|
||||
p->reserved = reserved;
|
||||
return p;
|
||||
}
|
||||
|
||||
PMemBlock via_mmAllocMem(memHeap_t * heap, int size, int align2,
|
||||
int startSearch)
|
||||
{
|
||||
int mask, startofs, endofs;
|
||||
TMemBlock *p;
|
||||
|
||||
if (!heap || align2 < 0 || size <= 0)
|
||||
return NULL;
|
||||
|
||||
mask = (1 << align2) - 1;
|
||||
startofs = 0;
|
||||
p = (TMemBlock *) heap;
|
||||
|
||||
while (p) {
|
||||
if (ISFREE(p)) {
|
||||
startofs = (p->ofs + mask) & ~mask;
|
||||
|
||||
if (startofs < startSearch)
|
||||
startofs = startSearch;
|
||||
|
||||
endofs = startofs + size;
|
||||
|
||||
if (endofs <= (p->ofs + p->size))
|
||||
break;
|
||||
}
|
||||
|
||||
p = p->next;
|
||||
}
|
||||
|
||||
if (!p)
|
||||
return NULL;
|
||||
|
||||
p = SliceBlock(p, startofs, size, 0, mask + 1);
|
||||
p->heap = heap;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
static __inline__ int Join2Blocks(TMemBlock * p)
|
||||
{
|
||||
if (p->free && p->next && p->next->free) {
|
||||
TMemBlock *q = p->next;
|
||||
p->size += q->size;
|
||||
p->next = q->next;
|
||||
drm_free(q, sizeof(TMemBlock), DRM_MEM_DRIVER);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int via_mmFreeMem(PMemBlock b)
|
||||
{
|
||||
TMemBlock *p, *prev;
|
||||
|
||||
if (!b)
|
||||
return 0;
|
||||
|
||||
if (!b->heap) {
|
||||
fprintf(stderr, "no heap\n");
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
p = b->heap;
|
||||
prev = NULL;
|
||||
|
||||
while (p && p != b) {
|
||||
prev = p;
|
||||
p = p->next;
|
||||
}
|
||||
|
||||
if (!p || p->free || p->reserved) {
|
||||
if (!p)
|
||||
fprintf(stderr, "block not found in heap\n");
|
||||
else if (p->free)
|
||||
fprintf(stderr, "block already free\n");
|
||||
else
|
||||
fprintf(stderr, "block is reserved\n");
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
p->free = 1;
|
||||
Join2Blocks(p);
|
||||
|
||||
if (prev)
|
||||
Join2Blocks(prev);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,104 +0,0 @@
|
|||
/*
|
||||
* Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
|
||||
* Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved.
|
||||
* Copyright 2000 Silicon Integrated Systems Corp, Inc., HsinChu, Taiwan.
|
||||
* 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
|
||||
* VIA, S3 GRAPHICS, 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.
|
||||
*/
|
||||
#ifndef _via_ds_h_
|
||||
#define _via_ds_h_
|
||||
|
||||
#include "drmP.h"
|
||||
|
||||
/* Set Data Structure */
|
||||
#define SET_SIZE 5000
|
||||
typedef unsigned long ITEM_TYPE;
|
||||
|
||||
typedef struct {
|
||||
ITEM_TYPE val;
|
||||
int alloc_next, free_next;
|
||||
} list_item_t;
|
||||
|
||||
typedef struct {
|
||||
int alloc;
|
||||
int free;
|
||||
int trace;
|
||||
list_item_t list[SET_SIZE];
|
||||
} set_t;
|
||||
|
||||
set_t *via_setInit(void);
|
||||
int via_setAdd(set_t * set, ITEM_TYPE item);
|
||||
int via_setDel(set_t * set, ITEM_TYPE item);
|
||||
int via_setFirst(set_t * set, ITEM_TYPE * item);
|
||||
int via_setNext(set_t * set, ITEM_TYPE * item);
|
||||
int via_setDestroy(set_t * set);
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef MM_INC
|
||||
#define MM_INC
|
||||
|
||||
struct mem_block_t {
|
||||
struct mem_block_t *next;
|
||||
struct mem_block_t *heap;
|
||||
int ofs, size;
|
||||
int align;
|
||||
unsigned int free:1;
|
||||
unsigned int reserved:1;
|
||||
};
|
||||
typedef struct mem_block_t TMemBlock;
|
||||
typedef struct mem_block_t *PMemBlock;
|
||||
|
||||
/* a heap is just the first block in a chain */
|
||||
typedef struct mem_block_t memHeap_t;
|
||||
|
||||
static __inline__ int mmBlockSize(PMemBlock b)
|
||||
{
|
||||
return b->size;
|
||||
}
|
||||
|
||||
static __inline__ int mmOffset(PMemBlock b)
|
||||
{
|
||||
return b->ofs;
|
||||
}
|
||||
|
||||
static __inline__ void mmMarkReserved(PMemBlock b)
|
||||
{
|
||||
b->reserved = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* input: total size in bytes
|
||||
* return: a heap pointer if OK, NULL if error
|
||||
*/
|
||||
memHeap_t *via_mmInit(int ofs, int size);
|
||||
|
||||
PMemBlock via_mmAllocMem(memHeap_t * heap, int size, int align2,
|
||||
int startSearch);
|
||||
|
||||
/*
|
||||
* Free block starts at offset
|
||||
* input: pointer to a block
|
||||
* return: 0 if OK, -1 if error
|
||||
*/
|
||||
int via_mmFreeMem(PMemBlock b);
|
||||
|
||||
#endif
|
|
@ -98,6 +98,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)
|
||||
|
@ -108,13 +109,19 @@ 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;
|
||||
ret = drm_sman_init(&dev_priv->sman, 2, 12, 8);
|
||||
if (ret) {
|
||||
drm_free(dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int via_driver_unload(drm_device_t *dev)
|
||||
{
|
||||
drm_via_private_t *dev_priv = dev->dev_private;
|
||||
|
||||
drm_sman_takedown(&dev_priv->sman);
|
||||
|
||||
drm_free(dev_priv, sizeof(drm_via_private_t), DRM_MEM_DRIVER);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
|
||||
* Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved.
|
||||
* 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"),
|
||||
|
@ -16,347 +16,194 @@
|
|||
* 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
|
||||
* VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* 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 "via_ds.h"
|
||||
#include "via_mm.h"
|
||||
#include "drm_sman.h"
|
||||
|
||||
#define MAX_CONTEXT 100
|
||||
|
||||
typedef struct {
|
||||
int used;
|
||||
int context;
|
||||
set_t *sets[2]; /* 0 for frame buffer, 1 for AGP , 2 for System */
|
||||
} via_context_t;
|
||||
|
||||
static via_context_t global_ppriv[MAX_CONTEXT];
|
||||
|
||||
static int via_agp_alloc(drm_via_mem_t * mem);
|
||||
static int via_agp_free(drm_via_mem_t * mem);
|
||||
static int via_fb_alloc(drm_via_mem_t * mem);
|
||||
static int via_fb_free(drm_via_mem_t * mem);
|
||||
|
||||
static int add_alloc_set(int context, int type, unsigned long val)
|
||||
{
|
||||
int i, retval = 0;
|
||||
|
||||
for (i = 0; i < MAX_CONTEXT; i++) {
|
||||
if (global_ppriv[i].used && global_ppriv[i].context == context) {
|
||||
retval = via_setAdd(global_ppriv[i].sets[type], val);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int del_alloc_set(int context, int type, unsigned long val)
|
||||
{
|
||||
int i, retval = 0;
|
||||
|
||||
for (i = 0; i < MAX_CONTEXT; i++)
|
||||
if (global_ppriv[i].used && global_ppriv[i].context == context) {
|
||||
retval = via_setDel(global_ppriv[i].sets[type], val);
|
||||
break;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* agp memory management */
|
||||
static memHeap_t *AgpHeap = NULL;
|
||||
#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));
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
ret = drm_sman_set_range(&dev_priv->sman, VIA_MEM_AGP, 0,
|
||||
agp.size >> VIA_MM_ALIGN_SHIFT);
|
||||
|
||||
AgpHeap = via_mmInit(agp.offset, agp.size);
|
||||
if (ret) {
|
||||
DRM_ERROR("AGP memory manager initialisation error\n");
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
DRM_DEBUG("offset = %lu, size = %lu", (unsigned long)agp.offset,
|
||||
(unsigned long)agp.size);
|
||||
dev_priv->agp_initialized = 1;
|
||||
dev_priv->agp_offset = agp.offset;
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
DRM_DEBUG("offset = %u, size = %u", agp.offset, agp.size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* fb memory management */
|
||||
static memHeap_t *FBHeap = NULL;
|
||||
|
||||
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));
|
||||
|
||||
FBHeap = via_mmInit(fb.offset, fb.size);
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
ret = drm_sman_set_range(&dev_priv->sman, VIA_MEM_VIDEO, 0,
|
||||
fb.size >> VIA_MM_ALIGN_SHIFT);
|
||||
|
||||
DRM_DEBUG("offset = %lu, size = %lu", (unsigned long)fb.offset,
|
||||
(unsigned long)fb.size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int via_init_context(struct drm_device *dev, int context)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_CONTEXT; i++)
|
||||
if (global_ppriv[i].used &&
|
||||
(global_ppriv[i].context == context))
|
||||
break;
|
||||
|
||||
if (i >= MAX_CONTEXT) {
|
||||
for (i = 0; i < MAX_CONTEXT; i++) {
|
||||
if (!global_ppriv[i].used) {
|
||||
global_ppriv[i].context = context;
|
||||
global_ppriv[i].used = 1;
|
||||
global_ppriv[i].sets[0] = via_setInit();
|
||||
global_ppriv[i].sets[1] = via_setInit();
|
||||
DRM_DEBUG("init allocation set, socket=%d,"
|
||||
" context = %d\n", i, context);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ((i >= MAX_CONTEXT) || (global_ppriv[i].sets[0] == NULL) ||
|
||||
(global_ppriv[i].sets[1] == NULL)) {
|
||||
return 0;
|
||||
}
|
||||
if (ret) {
|
||||
DRM_ERROR("VRAM memory manager initialisation error\n");
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 1;
|
||||
dev_priv->vram_initialized = 1;
|
||||
dev_priv->vram_offset = fb.offset;
|
||||
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
DRM_DEBUG("offset = %u, size = %u", fb.offset, fb.size);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int via_final_context(struct drm_device *dev, int context)
|
||||
{
|
||||
int i;
|
||||
drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
|
||||
|
||||
for (i = 0; i < MAX_CONTEXT; i++)
|
||||
if (global_ppriv[i].used &&
|
||||
(global_ppriv[i].context == context))
|
||||
break;
|
||||
|
||||
if (i < MAX_CONTEXT) {
|
||||
set_t *set;
|
||||
ITEM_TYPE item;
|
||||
int retval;
|
||||
|
||||
DRM_DEBUG("find socket %d, context = %d\n", i, context);
|
||||
|
||||
/* Video Memory */
|
||||
set = global_ppriv[i].sets[0];
|
||||
retval = via_setFirst(set, &item);
|
||||
while (retval) {
|
||||
DRM_DEBUG("free video memory 0x%lx\n", item);
|
||||
via_mmFreeMem((PMemBlock) item);
|
||||
retval = via_setNext(set, &item);
|
||||
}
|
||||
via_setDestroy(set);
|
||||
|
||||
/* AGP Memory */
|
||||
set = global_ppriv[i].sets[1];
|
||||
retval = via_setFirst(set, &item);
|
||||
while (retval) {
|
||||
DRM_DEBUG("free agp memory 0x%lx\n", item);
|
||||
via_mmFreeMem((PMemBlock) item);
|
||||
retval = via_setNext(set, &item);
|
||||
}
|
||||
via_setDestroy(set);
|
||||
global_ppriv[i].used = 0;
|
||||
}
|
||||
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);
|
||||
}
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void via_lastclose(struct drm_device *dev)
|
||||
{
|
||||
drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
|
||||
|
||||
if (!dev_priv)
|
||||
return;
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
drm_sman_cleanup(&dev_priv->sman);
|
||||
dev_priv->vram_initialized = 0;
|
||||
dev_priv->agp_initialized = 0;
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
}
|
||||
|
||||
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;
|
||||
unsigned long tmpSize;
|
||||
|
||||
DRM_COPY_FROM_USER_IOCTL(mem, (drm_via_mem_t __user *) data,
|
||||
sizeof(mem));
|
||||
|
||||
switch (mem.type) {
|
||||
case VIA_MEM_VIDEO:
|
||||
if (via_fb_alloc(&mem) < 0)
|
||||
return -EFAULT;
|
||||
DRM_COPY_TO_USER_IOCTL((drm_via_mem_t __user *) data, mem,
|
||||
sizeof(mem));
|
||||
return 0;
|
||||
case VIA_MEM_AGP:
|
||||
if (via_agp_alloc(&mem) < 0)
|
||||
return -EFAULT;
|
||||
DRM_COPY_TO_USER_IOCTL((drm_via_mem_t __user *) data, mem,
|
||||
sizeof(mem));
|
||||
return 0;
|
||||
if (mem.type > VIA_MEM_AGP) {
|
||||
DRM_ERROR("Unknown memory type allocation\n");
|
||||
return DRM_ERR(EINVAL);
|
||||
}
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
if (0 == ((mem.type == VIA_MEM_VIDEO) ? dev_priv->vram_initialized :
|
||||
dev_priv->agp_initialized)) {
|
||||
DRM_ERROR
|
||||
("Attempt to allocate from uninitialized memory manager.\n");
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return DRM_ERR(EINVAL);
|
||||
}
|
||||
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
static int via_fb_alloc(drm_via_mem_t * mem)
|
||||
{
|
||||
drm_via_mm_t fb;
|
||||
PMemBlock block;
|
||||
int retval = 0;
|
||||
|
||||
if (!FBHeap)
|
||||
return -1;
|
||||
|
||||
fb.size = mem->size;
|
||||
fb.context = mem->context;
|
||||
|
||||
block = via_mmAllocMem(FBHeap, fb.size, 5, 0);
|
||||
if (block) {
|
||||
fb.offset = block->ofs;
|
||||
fb.free = (unsigned long)block;
|
||||
if (!add_alloc_set(fb.context, VIA_MEM_VIDEO, fb.free)) {
|
||||
DRM_DEBUG("adding to allocation set fails\n");
|
||||
via_mmFreeMem((PMemBlock) fb.free);
|
||||
retval = -1;
|
||||
}
|
||||
tmpSize = (mem.size + VIA_MM_ALIGN_MASK) >> VIA_MM_ALIGN_SHIFT;
|
||||
item = drm_sman_alloc(&dev_priv->sman, mem.type, tmpSize, 0,
|
||||
(unsigned long)priv);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
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;
|
||||
} else {
|
||||
fb.offset = 0;
|
||||
fb.size = 0;
|
||||
fb.free = 0;
|
||||
retval = -1;
|
||||
mem.offset = 0;
|
||||
mem.size = 0;
|
||||
mem.index = 0;
|
||||
DRM_DEBUG("Video memory allocation failed\n");
|
||||
retval = DRM_ERR(ENOMEM);
|
||||
}
|
||||
DRM_COPY_TO_USER_IOCTL((drm_via_mem_t __user *) data, mem, sizeof(mem));
|
||||
|
||||
mem->offset = fb.offset;
|
||||
mem->index = fb.free;
|
||||
|
||||
DRM_DEBUG("alloc fb, size = %d, offset = %d\n", fb.size,
|
||||
(int)fb.offset);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int via_agp_alloc(drm_via_mem_t * mem)
|
||||
{
|
||||
drm_via_mm_t agp;
|
||||
PMemBlock block;
|
||||
int retval = 0;
|
||||
|
||||
if (!AgpHeap)
|
||||
return -1;
|
||||
|
||||
agp.size = mem->size;
|
||||
agp.context = mem->context;
|
||||
|
||||
block = via_mmAllocMem(AgpHeap, agp.size, 5, 0);
|
||||
if (block) {
|
||||
agp.offset = block->ofs;
|
||||
agp.free = (unsigned long)block;
|
||||
if (!add_alloc_set(agp.context, VIA_MEM_AGP, agp.free)) {
|
||||
DRM_DEBUG("adding to allocation set fails\n");
|
||||
via_mmFreeMem((PMemBlock) agp.free);
|
||||
retval = -1;
|
||||
}
|
||||
} else {
|
||||
agp.offset = 0;
|
||||
agp.size = 0;
|
||||
agp.free = 0;
|
||||
}
|
||||
|
||||
mem->offset = agp.offset;
|
||||
mem->index = agp.free;
|
||||
|
||||
DRM_DEBUG("alloc agp, size = %d, offset = %d\n", agp.size,
|
||||
(unsigned int)agp.offset);
|
||||
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));
|
||||
|
||||
switch (mem.type) {
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
ret = drm_sman_free_key(&dev_priv->sman, mem.index);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
DRM_DEBUG("free = 0x%lx\n", mem.index);
|
||||
|
||||
case VIA_MEM_VIDEO:
|
||||
if (via_fb_free(&mem) == 0)
|
||||
return 0;
|
||||
break;
|
||||
case VIA_MEM_AGP:
|
||||
if (via_agp_free(&mem) == 0)
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return -EFAULT;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int via_fb_free(drm_via_mem_t * mem)
|
||||
|
||||
void via_reclaim_buffers_locked(drm_device_t * dev, struct file *filp)
|
||||
{
|
||||
drm_via_mm_t fb;
|
||||
int retval = 0;
|
||||
drm_via_private_t *dev_priv = dev->dev_private;
|
||||
drm_file_t *priv = filp->private_data;
|
||||
|
||||
if (!FBHeap) {
|
||||
return -1;
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
if (drm_sman_owner_clean(&dev_priv->sman, (unsigned long)priv)) {
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
fb.free = mem->index;
|
||||
fb.context = mem->context;
|
||||
|
||||
if (!fb.free) {
|
||||
return -1;
|
||||
|
||||
if (dev->driver->dma_quiescent) {
|
||||
dev->driver->dma_quiescent(dev);
|
||||
}
|
||||
|
||||
via_mmFreeMem((PMemBlock) fb.free);
|
||||
|
||||
if (!del_alloc_set(fb.context, VIA_MEM_VIDEO, fb.free)) {
|
||||
retval = -1;
|
||||
}
|
||||
|
||||
DRM_DEBUG("free fb, free = %ld\n", fb.free);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int via_agp_free(drm_via_mem_t * mem)
|
||||
{
|
||||
drm_via_mm_t agp;
|
||||
|
||||
int retval = 0;
|
||||
|
||||
agp.free = mem->index;
|
||||
agp.context = mem->context;
|
||||
|
||||
if (!agp.free)
|
||||
return -1;
|
||||
|
||||
via_mmFreeMem((PMemBlock) agp.free);
|
||||
|
||||
if (!del_alloc_set(agp.context, VIA_MEM_AGP, agp.free)) {
|
||||
retval = -1;
|
||||
}
|
||||
|
||||
DRM_DEBUG("free agp, free = %ld\n", agp.free);
|
||||
|
||||
return retval;
|
||||
drm_sman_owner_cleanup(&dev_priv->sman, (unsigned long)priv);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue