Commit e823aff2 authored by Linus Torvalds's avatar Linus Torvalds

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
  ...
parents 77ed74da 3e14a286
......@@ -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,43 +65,29 @@ 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;
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
#error Unsupported long size. Neither 64 nor 32 bits.
#endif
hash += PAGE_SIZE;
map32_handle += PAGE_SIZE;
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);
}
#else
# define HandleID(x,dev) (unsigned int)(x)
#endif
/**
* 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)
......
/**************************************************************************
*
* 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 Hellstrm <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;
}
}
/**************************************************************************
*
* 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;
}
......
/**************************************************************************
*
* 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 Hellstrm <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);
......
/**************************************************************************
*
* 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 Hellstrm <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);
/**************************************************************************
*
* 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(&current->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;
......
/* 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;
}
/* 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__ */
/* 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>
*
**************************************************************************/
/*
* Authors:
* Thomas Hellstrm <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
#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];
#if defined(CONFIG_FB_SIS)
/* fb management via fb device */
static int add_alloc_set(int context, int type, unsigned int val)
{
int i, retval = 0;
#define SIS_MM_ALIGN_SHIFT 0
#define SIS_MM_ALIGN_MASK 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)
static void *sis_sman_mm_allocate(void *private, unsigned long size,
unsigned alignment)
{
int i, retval = 0;
struct sis_memreq req;
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;
req.size = size;
sis_malloc(&req);
if (req.size == 0)
return NULL;
else
return (void *)~req.offset;
}
/* fb management via fb device */
#if defined(__linux__) && defined(CONFIG_FB_SIS)
static int sis_fb_init(DRM_IOCTL_ARGS)
static void sis_sman_mm_free(void *private, void *ref)
{
return 0;
sis_free(~((unsigned long)ref));
}
static int sis_fb_alloc(DRM_IOCTL_ARGS)
static void sis_sman_mm_destroy(void *private)
{
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;
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;
;
}
static int sis_fb_free(DRM_IOCTL_ARGS)
static unsigned long sis_sman_mm_offset(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);
return ~((unsigned long)ref);
}
if (!del_alloc_set(fb.context, VIDEO_TYPE, fb.free))
retval = DRM_ERR(EINVAL);
sis_free(fb.free);
#else /* CONFIG_FB_SIS */
DRM_DEBUG("free fb, offset = 0x%lx\n", fb.free);
#define SIS_MM_ALIGN_SHIFT 4
#define SIS_MM_ALIGN_MASK ( (1 << SIS_MM_ALIGN_SHIFT) - 1)
return retval;
}
#endif /* CONFIG_FB_SIS */
#else
/* 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 (dev_priv->FBHeap != NULL)
return DRM_ERR(EINVAL);
if (ret) {
DRM_ERROR("VRAM memory manager initialisation error\n");
mutex_unlock(&dev->struct_mutex);
return ret;
}
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;
DRM_COPY_FROM_USER_IOCTL(mem, argp, sizeof(mem));
if (dev_priv == NULL || dev_priv->FBHeap == NULL)
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);
}
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);
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 {
fb.offset = 0;
fb.size = 0;
fb.free = 0;
mem.offset = 0;
mem.size = 0;
mem.free = 0;
retval = DRM_ERR(ENOMEM);
}
DRM_COPY_TO_USER_IOCTL(argp, fb, sizeof(fb));
DRM_COPY_TO_USER_IOCTL(argp, mem, sizeof(mem));
DRM_DEBUG("alloc fb, size = %d, offset = %d\n", fb.size, fb.offset);
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);
if (ret) {
DRM_ERROR("AGP memory manager initialisation error\n");
mutex_unlock(&dev->struct_mutex);
return ret;
}
dev_priv->AGPHeap = mmInit(agp.offset, 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;
}
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);
return sis_drm_alloc(dev, priv, data, AGP_TYPE);
}
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;
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;
}
} 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 NULL;
}
static int sis_ioctl_agp_free(DRM_IOCTL_ARGS)
int sis_idle(drm_device_t *dev)
{
DRM_DEVICE;
drm_sis_private_t *dev_priv = dev->dev_private;
drm_sis_mem_t agp;
if (dev_priv == NULL || dev_priv->AGPHeap == NULL)
return DRM_ERR(EINVAL);
uint32_t idle_reg;
unsigned long end;
int i;
DRM_COPY_FROM_USER_IOCTL(agp, (drm_sis_mem_t __user *) data,
sizeof(agp));
if (dev_priv->idle_fault)
return 0;
if (!mmBlockInHeap(dev_priv->AGPHeap, (PMemBlock) agp.free))
return DRM_ERR(EINVAL);
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 (dev_priv->chipset != SIS_CHIP_315)
return 0;
/*
* Timeout after 3 seconds. We cannot use DRM_WAIT_ON here
* because its polling frequency is too low.
*/
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));
}
mmFreeMem((PMemBlock) agp.free);
if (!del_alloc_set(agp.context, AGP_TYPE, agp.free))
return DRM_ERR(EINVAL);
if (time_after_eq(jiffies, end)) {
DRM_ERROR("Graphics engine idle timeout. "
"Disabling idle check\n");
dev_priv->idle_fault = 1;
}
DRM_DEBUG("free agp, free = 0x%lx\n", agp.free);
/*
* The caller never sees an error code. It gets trapped
* in libdrm.
*/
return 0;
}
int sis_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;
}
void sis_lastclose(struct drm_device *dev)
{
drm_sis_private_t *dev_priv = dev->dev_private;
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;
}
}
if (!dev_priv)
return;
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(&current->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(&current->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);
......
/*
* 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;
}
/*
* 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;
......
/*
* 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 Hellstrm <thomas-at-tungstengraphics-dot-com>
*/
#include "drmP.h"
#include "via_drm.h"
#include "via_drv.h"
#include "via_ds.h"
#include "via_mm.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];
#include "drm_sman.h"
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);
if (ret) {
DRM_ERROR("AGP memory manager initialisation error\n");
mutex_unlock(&dev->struct_mutex);
return ret;
}
AgpHeap = via_mmInit(agp.offset, agp.size);
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);
if (ret) {
DRM_ERROR("VRAM memory manager initialisation error\n");
mutex_unlock(&dev->struct_mutex);
return ret;
}
return 0;
}
dev_priv->vram_initialized = 1;
dev_priv->vram_offset = fb.offset;
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;
}
}
mutex_unlock(&dev->struct_mutex);
DRM_DEBUG("offset = %u, size = %u", fb.offset, fb.size);
return 0;
return 1;
}
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);
}
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;
}
} else {
fb.offset = 0;
fb.size = 0;
fb.free = 0;
retval = -1;
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);
}
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;
}
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 {
agp.offset = 0;
agp.size = 0;
agp.free = 0;
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 = 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)
{
drm_via_mm_t fb;
int retval = 0;
if (!FBHeap) {
return -1;
}
fb.free = mem->index;
fb.context = mem->context;
if (!fb.free) {
return -1;
}
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)
void via_reclaim_buffers_locked(drm_device_t * dev, struct file *filp)
{
drm_via_mm_t agp;
int retval = 0;
drm_via_private_t *dev_priv = dev->dev_private;
drm_file_t *priv = filp->private_data;
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;
mutex_lock(&dev->struct_mutex);
if (drm_sman_owner_clean(&dev_priv->sman, (unsigned long)priv)) {
mutex_unlock(&dev->struct_mutex);
return;
}
DRM_DEBUG("free agp, free = %ld\n", agp.free);
if (dev->driver->dma_quiescent) {
dev->driver->dma_quiescent(dev);
}
return retval;
drm_sman_owner_cleanup(&dev_priv->sman, (unsigned long)priv);
mutex_unlock(&dev->struct_mutex);
return;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment