Commit f7ea4a4b authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'drm-next' of git://git.kernel.org/pub/scm/linux/kernel/git/airlied/drm-2.6

* 'drm-next' of git://git.kernel.org/pub/scm/linux/kernel/git/airlied/drm-2.6: (44 commits)
  drm/i915: fix ioremap of a user address for non-root (CVE-2008-3831)
  drm: make CONFIG_DRM depend on CONFIG_SHMEM.
  radeon: fix PCI bus mastering support enables.
  radeon: add RS400 family support.
  drm/radeon: add support for RS740 IGP chipsets.
  i915: GM45 has GM965-style MCH setup.
  i915: Don't run retire work handler while suspended
  i915: Map status page cached for chips with GTT-based HWS location.
  i915: Fix up ring initialization to cover G45 oddities
  i915: Use non-reserved status page index for breadcrumb
  drm: Increment dev_priv->irq_received so i915_gem_interrupts count works.
  drm: kill drm_device->irq
  drm: wbinvd is cache coherent.
  i915: add missing return in error path.
  i915: fixup permissions on gem ioctls.
  drm: Clean up many sparse warnings in i915.
  drm: Use ioremap_wc in i915_driver instead of ioremap, since we always want WC.
  drm: G33-class hardware has a newer 965-style MCH (no DCC register).
  drm: Avoid oops in GEM execbuffers with bad arguments.
  DRM: Return -EBADF on bad object in flink, and return curent name if it exists.
  ...
parents 5564da7e 4b408939
...@@ -137,6 +137,7 @@ void *kmap_atomic_pfn(unsigned long pfn, enum km_type type) ...@@ -137,6 +137,7 @@ void *kmap_atomic_pfn(unsigned long pfn, enum km_type type)
return (void*) vaddr; return (void*) vaddr;
} }
EXPORT_SYMBOL_GPL(kmap_atomic_pfn); /* temporarily in use by i915 GEM until vmap */
struct page *kmap_atomic_to_page(void *ptr) struct page *kmap_atomic_to_page(void *ptr)
{ {
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
# #
menuconfig DRM menuconfig DRM
tristate "Direct Rendering Manager (XFree86 4.1.0 and higher DRI support)" tristate "Direct Rendering Manager (XFree86 4.1.0 and higher DRI support)"
depends on (AGP || AGP=n) && PCI && !EMULATED_CMPXCHG depends on (AGP || AGP=n) && PCI && !EMULATED_CMPXCHG && SHMEM
help help
Kernel-level support for the Direct Rendering Infrastructure (DRI) Kernel-level support for the Direct Rendering Infrastructure (DRI)
introduced in XFree86 4.0. If you say Y here, you need to select introduced in XFree86 4.0. If you say Y here, you need to select
...@@ -87,6 +87,7 @@ config DRM_MGA ...@@ -87,6 +87,7 @@ config DRM_MGA
config DRM_SIS config DRM_SIS
tristate "SiS video cards" tristate "SiS video cards"
depends on DRM && AGP depends on DRM && AGP
depends on FB_SIS || FB_SIS=n
help help
Choose this option if you have a SiS 630 or compatible video Choose this option if you have a SiS 630 or compatible video
chipset. If M is selected the module will be called sis. AGP chipset. If M is selected the module will be called sis. AGP
......
...@@ -4,8 +4,9 @@ ...@@ -4,8 +4,9 @@
ccflags-y := -Iinclude/drm ccflags-y := -Iinclude/drm
drm-y := drm_auth.o drm_bufs.o drm_context.o drm_dma.o drm_drawable.o \ drm-y := drm_auth.o drm_bufs.o drm_cache.o \
drm_drv.o drm_fops.o drm_ioctl.o drm_irq.o \ drm_context.o drm_dma.o drm_drawable.o \
drm_drv.o drm_fops.o drm_gem.o drm_ioctl.o drm_irq.o \
drm_lock.o drm_memory.o drm_proc.o drm_stub.o drm_vm.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_agpsupport.o drm_scatter.o ati_pcigart.o drm_pci.o \
drm_sysfs.o drm_hashtab.o drm_sman.o drm_mm.o drm_sysfs.o drm_hashtab.o drm_sman.o drm_mm.o
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include "drmP.h" #include "drmP.h"
#include <linux/module.h> #include <linux/module.h>
#include <asm/agp.h>
#if __OS_HAS_AGP #if __OS_HAS_AGP
...@@ -452,4 +453,53 @@ int drm_agp_unbind_memory(DRM_AGP_MEM * handle) ...@@ -452,4 +453,53 @@ int drm_agp_unbind_memory(DRM_AGP_MEM * handle)
return agp_unbind_memory(handle); return agp_unbind_memory(handle);
} }
#endif /* __OS_HAS_AGP */ /**
* Binds a collection of pages into AGP memory at the given offset, returning
* the AGP memory structure containing them.
*
* No reference is held on the pages during this time -- it is up to the
* caller to handle that.
*/
DRM_AGP_MEM *
drm_agp_bind_pages(struct drm_device *dev,
struct page **pages,
unsigned long num_pages,
uint32_t gtt_offset,
u32 type)
{
DRM_AGP_MEM *mem;
int ret, i;
DRM_DEBUG("\n");
mem = drm_agp_allocate_memory(dev->agp->bridge, num_pages,
type);
if (mem == NULL) {
DRM_ERROR("Failed to allocate memory for %ld pages\n",
num_pages);
return NULL;
}
for (i = 0; i < num_pages; i++)
mem->memory[i] = phys_to_gart(page_to_phys(pages[i]));
mem->page_count = num_pages;
mem->is_flushed = true;
ret = drm_agp_bind_memory(mem, gtt_offset / PAGE_SIZE);
if (ret != 0) {
DRM_ERROR("Failed to bind AGP memory: %d\n", ret);
agp_free_memory(mem);
return NULL;
}
return mem;
}
EXPORT_SYMBOL(drm_agp_bind_pages);
void drm_agp_chipset_flush(struct drm_device *dev)
{
agp_flush_chipset(dev->agp->bridge);
}
EXPORT_SYMBOL(drm_agp_chipset_flush);
#endif /* __OS_HAS_AGP */
/**************************************************************************
*
* Copyright (c) 2006-2007 Tungsten Graphics, Inc., Cedar Park, TX., USA
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* USE OR OTHER DEALINGS IN THE SOFTWARE.
*
**************************************************************************/
/*
* Authors: Thomas Hellström <thomas-at-tungstengraphics-dot-com>
*/
#include "drmP.h"
#if defined(CONFIG_X86)
static void
drm_clflush_page(struct page *page)
{
uint8_t *page_virtual;
unsigned int i;
if (unlikely(page == NULL))
return;
page_virtual = kmap_atomic(page, KM_USER0);
for (i = 0; i < PAGE_SIZE; i += boot_cpu_data.x86_clflush_size)
clflush(page_virtual + i);
kunmap_atomic(page_virtual, KM_USER0);
}
#endif
void
drm_clflush_pages(struct page *pages[], unsigned long num_pages)
{
#if defined(CONFIG_X86)
if (cpu_has_clflush) {
unsigned long i;
mb();
for (i = 0; i < num_pages; ++i)
drm_clflush_page(*pages++);
mb();
return;
}
wbinvd();
#endif
}
EXPORT_SYMBOL(drm_clflush_pages);
...@@ -116,7 +116,13 @@ static struct drm_ioctl_desc drm_ioctls[] = { ...@@ -116,7 +116,13 @@ static struct drm_ioctl_desc drm_ioctls[] = {
DRM_IOCTL_DEF(DRM_IOCTL_WAIT_VBLANK, drm_wait_vblank, 0), DRM_IOCTL_DEF(DRM_IOCTL_WAIT_VBLANK, drm_wait_vblank, 0),
DRM_IOCTL_DEF(DRM_IOCTL_MODESET_CTL, drm_modeset_ctl, 0),
DRM_IOCTL_DEF(DRM_IOCTL_UPDATE_DRAW, drm_update_drawable_info, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_UPDATE_DRAW, drm_update_drawable_info, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
DRM_IOCTL_DEF(DRM_IOCTL_GEM_CLOSE, drm_gem_close_ioctl, 0),
DRM_IOCTL_DEF(DRM_IOCTL_GEM_FLINK, drm_gem_flink_ioctl, DRM_AUTH),
DRM_IOCTL_DEF(DRM_IOCTL_GEM_OPEN, drm_gem_open_ioctl, DRM_AUTH),
}; };
#define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls ) #define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls )
......
...@@ -246,7 +246,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp, ...@@ -246,7 +246,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
memset(priv, 0, sizeof(*priv)); memset(priv, 0, sizeof(*priv));
filp->private_data = priv; filp->private_data = priv;
priv->filp = filp; priv->filp = filp;
priv->uid = current->euid; priv->uid = current_euid();
priv->pid = task_pid_nr(current); priv->pid = task_pid_nr(current);
priv->minor = idr_find(&drm_minors_idr, minor_id); priv->minor = idr_find(&drm_minors_idr, minor_id);
priv->ioctl_count = 0; priv->ioctl_count = 0;
...@@ -256,6 +256,9 @@ static int drm_open_helper(struct inode *inode, struct file *filp, ...@@ -256,6 +256,9 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
INIT_LIST_HEAD(&priv->lhead); INIT_LIST_HEAD(&priv->lhead);
if (dev->driver->driver_features & DRIVER_GEM)
drm_gem_open(dev, priv);
if (dev->driver->open) { if (dev->driver->open) {
ret = dev->driver->open(dev, priv); ret = dev->driver->open(dev, priv);
if (ret < 0) if (ret < 0)
...@@ -400,6 +403,9 @@ int drm_release(struct inode *inode, struct file *filp) ...@@ -400,6 +403,9 @@ int drm_release(struct inode *inode, struct file *filp)
dev->driver->reclaim_buffers(dev, file_priv); dev->driver->reclaim_buffers(dev, file_priv);
} }
if (dev->driver->driver_features & DRIVER_GEM)
drm_gem_release(dev, file_priv);
drm_fasync(-1, filp, 0); drm_fasync(-1, filp, 0);
mutex_lock(&dev->ctxlist_mutex); mutex_lock(&dev->ctxlist_mutex);
......
This diff is collapsed.
This diff is collapsed.
...@@ -133,6 +133,7 @@ int drm_free_agp(DRM_AGP_MEM * handle, int pages) ...@@ -133,6 +133,7 @@ int drm_free_agp(DRM_AGP_MEM * handle, int pages)
{ {
return drm_agp_free_memory(handle) ? 0 : -EINVAL; return drm_agp_free_memory(handle) ? 0 : -EINVAL;
} }
EXPORT_SYMBOL(drm_free_agp);
/** Wrapper around agp_bind_memory() */ /** Wrapper around agp_bind_memory() */
int drm_bind_agp(DRM_AGP_MEM * handle, unsigned int start) int drm_bind_agp(DRM_AGP_MEM * handle, unsigned int start)
...@@ -145,6 +146,7 @@ int drm_unbind_agp(DRM_AGP_MEM * handle) ...@@ -145,6 +146,7 @@ int drm_unbind_agp(DRM_AGP_MEM * handle)
{ {
return drm_agp_unbind_memory(handle); return drm_agp_unbind_memory(handle);
} }
EXPORT_SYMBOL(drm_unbind_agp);
#else /* __OS_HAS_AGP */ #else /* __OS_HAS_AGP */
static inline void *agp_remap(unsigned long offset, unsigned long size, static inline void *agp_remap(unsigned long offset, unsigned long size,
......
...@@ -169,6 +169,7 @@ struct drm_mm_node *drm_mm_get_block(struct drm_mm_node * parent, ...@@ -169,6 +169,7 @@ struct drm_mm_node *drm_mm_get_block(struct drm_mm_node * parent,
return child; return child;
} }
EXPORT_SYMBOL(drm_mm_get_block);
/* /*
* Put a block. Merge with the previous and / or next block if they are free. * Put a block. Merge with the previous and / or next block if they are free.
...@@ -217,6 +218,7 @@ void drm_mm_put_block(struct drm_mm_node * cur) ...@@ -217,6 +218,7 @@ void drm_mm_put_block(struct drm_mm_node * cur)
drm_free(cur, sizeof(*cur), DRM_MEM_MM); drm_free(cur, sizeof(*cur), DRM_MEM_MM);
} }
} }
EXPORT_SYMBOL(drm_mm_put_block);
struct drm_mm_node *drm_mm_search_free(const struct drm_mm * mm, struct drm_mm_node *drm_mm_search_free(const struct drm_mm * mm,
unsigned long size, unsigned long size,
...@@ -265,6 +267,7 @@ int drm_mm_clean(struct drm_mm * mm) ...@@ -265,6 +267,7 @@ int drm_mm_clean(struct drm_mm * mm)
return (head->next->next == head); return (head->next->next == head);
} }
EXPORT_SYMBOL(drm_mm_search_free);
int drm_mm_init(struct drm_mm * mm, unsigned long start, unsigned long size) int drm_mm_init(struct drm_mm * mm, unsigned long start, unsigned long size)
{ {
...@@ -273,7 +276,7 @@ int drm_mm_init(struct drm_mm * mm, unsigned long start, unsigned long size) ...@@ -273,7 +276,7 @@ int drm_mm_init(struct drm_mm * mm, unsigned long start, unsigned long size)
return drm_mm_create_tail_node(mm, start, size); return drm_mm_create_tail_node(mm, start, size);
} }
EXPORT_SYMBOL(drm_mm_init);
void drm_mm_takedown(struct drm_mm * mm) void drm_mm_takedown(struct drm_mm * mm)
{ {
......
...@@ -49,6 +49,10 @@ static int drm_queues_info(char *buf, char **start, off_t offset, ...@@ -49,6 +49,10 @@ static int drm_queues_info(char *buf, char **start, off_t offset,
int request, int *eof, void *data); int request, int *eof, void *data);
static int drm_bufs_info(char *buf, char **start, off_t offset, static int drm_bufs_info(char *buf, char **start, off_t offset,
int request, int *eof, void *data); int request, int *eof, void *data);
static int drm_gem_name_info(char *buf, char **start, off_t offset,
int request, int *eof, void *data);
static int drm_gem_object_info(char *buf, char **start, off_t offset,
int request, int *eof, void *data);
#if DRM_DEBUG_CODE #if DRM_DEBUG_CODE
static int drm_vma_info(char *buf, char **start, off_t offset, static int drm_vma_info(char *buf, char **start, off_t offset,
int request, int *eof, void *data); int request, int *eof, void *data);
...@@ -60,13 +64,16 @@ static int drm_vma_info(char *buf, char **start, off_t offset, ...@@ -60,13 +64,16 @@ static int drm_vma_info(char *buf, char **start, off_t offset,
static struct drm_proc_list { static struct drm_proc_list {
const char *name; /**< file name */ const char *name; /**< file name */
int (*f) (char *, char **, off_t, int, int *, void *); /**< proc callback*/ int (*f) (char *, char **, off_t, int, int *, void *); /**< proc callback*/
u32 driver_features; /**< Required driver features for this entry */
} drm_proc_list[] = { } drm_proc_list[] = {
{"name", drm_name_info}, {"name", drm_name_info, 0},
{"mem", drm_mem_info}, {"mem", drm_mem_info, 0},
{"vm", drm_vm_info}, {"vm", drm_vm_info, 0},
{"clients", drm_clients_info}, {"clients", drm_clients_info, 0},
{"queues", drm_queues_info}, {"queues", drm_queues_info, 0},
{"bufs", drm_bufs_info}, {"bufs", drm_bufs_info, 0},
{"gem_names", drm_gem_name_info, DRIVER_GEM},
{"gem_objects", drm_gem_object_info, DRIVER_GEM},
#if DRM_DEBUG_CODE #if DRM_DEBUG_CODE
{"vma", drm_vma_info}, {"vma", drm_vma_info},
#endif #endif
...@@ -90,8 +97,9 @@ static struct drm_proc_list { ...@@ -90,8 +97,9 @@ static struct drm_proc_list {
int drm_proc_init(struct drm_minor *minor, int minor_id, int drm_proc_init(struct drm_minor *minor, int minor_id,
struct proc_dir_entry *root) struct proc_dir_entry *root)
{ {
struct drm_device *dev = minor->dev;
struct proc_dir_entry *ent; struct proc_dir_entry *ent;
int i, j; int i, j, ret;
char name[64]; char name[64];
sprintf(name, "%d", minor_id); sprintf(name, "%d", minor_id);
...@@ -102,23 +110,42 @@ int drm_proc_init(struct drm_minor *minor, int minor_id, ...@@ -102,23 +110,42 @@ int drm_proc_init(struct drm_minor *minor, int minor_id,
} }
for (i = 0; i < DRM_PROC_ENTRIES; i++) { for (i = 0; i < DRM_PROC_ENTRIES; i++) {
u32 features = drm_proc_list[i].driver_features;
if (features != 0 &&
(dev->driver->driver_features & features) != features)
continue;
ent = create_proc_entry(drm_proc_list[i].name, ent = create_proc_entry(drm_proc_list[i].name,
S_IFREG | S_IRUGO, minor->dev_root); S_IFREG | S_IRUGO, minor->dev_root);
if (!ent) { if (!ent) {
DRM_ERROR("Cannot create /proc/dri/%s/%s\n", DRM_ERROR("Cannot create /proc/dri/%s/%s\n",
name, drm_proc_list[i].name); name, drm_proc_list[i].name);
for (j = 0; j < i; j++) ret = -1;
remove_proc_entry(drm_proc_list[i].name, goto fail;
minor->dev_root);
remove_proc_entry(name, root);
minor->dev_root = NULL;
return -1;
} }
ent->read_proc = drm_proc_list[i].f; ent->read_proc = drm_proc_list[i].f;
ent->data = minor; ent->data = minor;
} }
if (dev->driver->proc_init) {
ret = dev->driver->proc_init(minor);
if (ret) {
DRM_ERROR("DRM: Driver failed to initialize "
"/proc/dri.\n");
goto fail;
}
}
return 0; return 0;
fail:
for (j = 0; j < i; j++)
remove_proc_entry(drm_proc_list[i].name,
minor->dev_root);
remove_proc_entry(name, root);
minor->dev_root = NULL;
return ret;
} }
/** /**
...@@ -133,12 +160,16 @@ int drm_proc_init(struct drm_minor *minor, int minor_id, ...@@ -133,12 +160,16 @@ int drm_proc_init(struct drm_minor *minor, int minor_id,
*/ */
int drm_proc_cleanup(struct drm_minor *minor, struct proc_dir_entry *root) int drm_proc_cleanup(struct drm_minor *minor, struct proc_dir_entry *root)
{ {
struct drm_device *dev = minor->dev;
int i; int i;
char name[64]; char name[64];
if (!root || !minor->dev_root) if (!root || !minor->dev_root)
return 0; return 0;
if (dev->driver->proc_cleanup)
dev->driver->proc_cleanup(minor);
for (i = 0; i < DRM_PROC_ENTRIES; i++) for (i = 0; i < DRM_PROC_ENTRIES; i++)
remove_proc_entry(drm_proc_list[i].name, minor->dev_root); remove_proc_entry(drm_proc_list[i].name, minor->dev_root);
sprintf(name, "%d", minor->index); sprintf(name, "%d", minor->index);
...@@ -480,6 +511,84 @@ static int drm_clients_info(char *buf, char **start, off_t offset, ...@@ -480,6 +511,84 @@ static int drm_clients_info(char *buf, char **start, off_t offset,
return ret; return ret;
} }
struct drm_gem_name_info_data {
int len;
char *buf;
int eof;
};
static int drm_gem_one_name_info(int id, void *ptr, void *data)
{
struct drm_gem_object *obj = ptr;
struct drm_gem_name_info_data *nid = data;
DRM_INFO("name %d size %d\n", obj->name, obj->size);
if (nid->eof)
return 0;
nid->len += sprintf(&nid->buf[nid->len],
"%6d%9d%8d%9d\n",
obj->name, obj->size,
atomic_read(&obj->handlecount.refcount),
atomic_read(&obj->refcount.refcount));
if (nid->len > DRM_PROC_LIMIT) {
nid->eof = 1;
return 0;
}
return 0;
}
static int drm_gem_name_info(char *buf, char **start, off_t offset,
int request, int *eof, void *data)
{
struct drm_minor *minor = (struct drm_minor *) data;
struct drm_device *dev = minor->dev;
struct drm_gem_name_info_data nid;
if (offset > DRM_PROC_LIMIT) {
*eof = 1;
return 0;
}
nid.len = sprintf(buf, " name size handles refcount\n");
nid.buf = buf;
nid.eof = 0;
idr_for_each(&dev->object_name_idr, drm_gem_one_name_info, &nid);
*start = &buf[offset];
*eof = 0;
if (nid.len > request + offset)
return request;
*eof = 1;
return nid.len - offset;
}
static int drm_gem_object_info(char *buf, char **start, off_t offset,
int request, int *eof, void *data)
{
struct drm_minor *minor = (struct drm_minor *) data;
struct drm_device *dev = minor->dev;
int len = 0;
if (offset > DRM_PROC_LIMIT) {
*eof = 1;
return 0;
}
*start = &buf[offset];
*eof = 0;
DRM_PROC_PRINT("%d objects\n", atomic_read(&dev->object_count));
DRM_PROC_PRINT("%d object bytes\n", atomic_read(&dev->object_memory));
DRM_PROC_PRINT("%d pinned\n", atomic_read(&dev->pin_count));
DRM_PROC_PRINT("%d pin bytes\n", atomic_read(&dev->pin_memory));
DRM_PROC_PRINT("%d gtt bytes\n", atomic_read(&dev->gtt_memory));
DRM_PROC_PRINT("%d gtt total\n", dev->gtt_total);
if (len > request + offset)
return request;
*eof = 1;
return len - offset;
}
#if DRM_DEBUG_CODE #if DRM_DEBUG_CODE
static int drm__vma_info(char *buf, char **start, off_t offset, int request, static int drm__vma_info(char *buf, char **start, off_t offset, int request,
......
...@@ -107,7 +107,6 @@ static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev, ...@@ -107,7 +107,6 @@ static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev,
#ifdef __alpha__ #ifdef __alpha__
dev->hose = pdev->sysdata; dev->hose = pdev->sysdata;
#endif #endif
dev->irq = pdev->irq;
if (drm_ht_create(&dev->map_hash, 12)) { if (drm_ht_create(&dev->map_hash, 12)) {
return -ENOMEM; return -ENOMEM;
...@@ -152,6 +151,15 @@ static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev, ...@@ -152,6 +151,15 @@ static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev,
goto error_out_unreg; goto error_out_unreg;
} }
if (driver->driver_features & DRIVER_GEM) {
retcode = drm_gem_init(dev);
if (retcode) {
DRM_ERROR("Cannot initialize graphics execution "
"manager (GEM)\n");
goto error_out_unreg;
}
}
return 0; return 0;
error_out_unreg: error_out_unreg:
...@@ -317,6 +325,7 @@ int drm_put_dev(struct drm_device * dev) ...@@ -317,6 +325,7 @@ int drm_put_dev(struct drm_device * dev)
int drm_put_minor(struct drm_minor **minor_p) int drm_put_minor(struct drm_minor **minor_p)
{ {
struct drm_minor *minor = *minor_p; struct drm_minor *minor = *minor_p;
DRM_DEBUG("release secondary minor %d\n", minor->index); DRM_DEBUG("release secondary minor %d\n", minor->index);
if (minor->type == DRM_MINOR_LEGACY) if (minor->type == DRM_MINOR_LEGACY)
......
...@@ -184,7 +184,7 @@ int drm_sysfs_device_add(struct drm_minor *minor) ...@@ -184,7 +184,7 @@ int drm_sysfs_device_add(struct drm_minor *minor)
err_out_files: err_out_files:
if (i > 0) if (i > 0)
for (j = 0; j < i; j++) for (j = 0; j < i; j++)
device_remove_file(&minor->kdev, &device_attrs[i]); device_remove_file(&minor->kdev, &device_attrs[j]);
device_unregister(&minor->kdev); device_unregister(&minor->kdev);
err_out: err_out:
......
...@@ -3,7 +3,12 @@ ...@@ -3,7 +3,12 @@
# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
ccflags-y := -Iinclude/drm ccflags-y := -Iinclude/drm
i915-y := i915_drv.o i915_dma.o i915_irq.o i915_mem.o i915-y := i915_drv.o i915_dma.o i915_irq.o i915_mem.o i915_opregion.o \
i915_suspend.o \
i915_gem.o \
i915_gem_debug.o \
i915_gem_proc.o \
i915_gem_tiling.o
i915-$(CONFIG_COMPAT) += i915_ioc32.o i915-$(CONFIG_COMPAT) += i915_ioc32.o
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/*
* Copyright © 2008 Intel Corporation
*
* 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
* THE AUTHORS OR COPYRIGHT HOLDERS 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:
* Keith Packard <keithp@keithp.com>
*
*/
#include "drmP.h"
#include "drm.h"
#include "i915_drm.h"
#include "i915_drv.h"
#if WATCH_INACTIVE
void
i915_verify_inactive(struct drm_device *dev, char *file, int line)
{
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_gem_object *obj;
struct drm_i915_gem_object *obj_priv;
list_for_each_entry(obj_priv, &dev_priv->mm.inactive_list, list) {
obj = obj_priv->obj;
if (obj_priv->pin_count || obj_priv->active ||
(obj->write_domain & ~(I915_GEM_DOMAIN_CPU |
I915_GEM_DOMAIN_GTT)))
DRM_ERROR("inactive %p (p %d a %d w %x) %s:%d\n",
obj,
obj_priv->pin_count, obj_priv->active,
obj->write_domain, file, line);
}
}
#endif /* WATCH_INACTIVE */
#if WATCH_BUF | WATCH_EXEC | WATCH_PWRITE
static void
i915_gem_dump_page(struct page *page, uint32_t start, uint32_t end,
uint32_t bias, uint32_t mark)
{
uint32_t *mem = kmap_atomic(page, KM_USER0);
int i;
for (i = start; i < end; i += 4)
DRM_INFO("%08x: %08x%s\n",
(int) (bias + i), mem[i / 4],
(bias + i == mark) ? " ********" : "");
kunmap_atomic(mem, KM_USER0);
/* give syslog time to catch up */
msleep(1);
}
void
i915_gem_dump_object(struct drm_gem_object *obj, int len,
const char *where, uint32_t mark)
{
struct drm_i915_gem_object *obj_priv = obj->driver_private;
int page;
DRM_INFO("%s: object at offset %08x\n", where, obj_priv->gtt_offset);
for (page = 0; page < (len + PAGE_SIZE-1) / PAGE_SIZE; page++) {
int page_len, chunk, chunk_len;
page_len = len - page * PAGE_SIZE;
if (page_len > PAGE_SIZE)
page_len = PAGE_SIZE;
for (chunk = 0; chunk < page_len; chunk += 128) {
chunk_len = page_len - chunk;
if (chunk_len > 128)
chunk_len = 128;
i915_gem_dump_page(obj_priv->page_list[page],
chunk, chunk + chunk_len,
obj_priv->gtt_offset +
page * PAGE_SIZE,
mark);
}
}
}
#endif
#if WATCH_LRU
void
i915_dump_lru(struct drm_device *dev, const char *where)
{
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_gem_object *obj_priv;
DRM_INFO("active list %s {\n", where);
list_for_each_entry(obj_priv, &dev_priv->mm.active_list,
list)
{
DRM_INFO(" %p: %08x\n", obj_priv,
obj_priv->last_rendering_seqno);
}
DRM_INFO("}\n");
DRM_INFO("flushing list %s {\n", where);
list_for_each_entry(obj_priv, &dev_priv->mm.flushing_list,
list)
{
DRM_INFO(" %p: %08x\n", obj_priv,
obj_priv->last_rendering_seqno);
}
DRM_INFO("}\n");
DRM_INFO("inactive %s {\n", where);
list_for_each_entry(obj_priv, &dev_priv->mm.inactive_list, list) {
DRM_INFO(" %p: %08x\n", obj_priv,
obj_priv->last_rendering_seqno);
}
DRM_INFO("}\n");
}
#endif
#if WATCH_COHERENCY
void
i915_gem_object_check_coherency(struct drm_gem_object *obj, int handle)
{
struct drm_device *dev = obj->dev;
struct drm_i915_gem_object *obj_priv = obj->driver_private;
int page;
uint32_t *gtt_mapping;
uint32_t *backing_map = NULL;
int bad_count = 0;
DRM_INFO("%s: checking coherency of object %p@0x%08x (%d, %dkb):\n",
__func__, obj, obj_priv->gtt_offset, handle,
obj->size / 1024);
gtt_mapping = ioremap(dev->agp->base + obj_priv->gtt_offset,
obj->size);
if (gtt_mapping == NULL) {
DRM_ERROR("failed to map GTT space\n");
return;
}
for (page = 0; page < obj->size / PAGE_SIZE; page++) {
int i;
backing_map = kmap_atomic(obj_priv->page_list[page], KM_USER0);
if (backing_map == NULL) {
DRM_ERROR("failed to map backing page\n");
goto out;
}
for (i = 0; i < PAGE_SIZE / 4; i++) {
uint32_t cpuval = backing_map[i];
uint32_t gttval = readl(gtt_mapping +
page * 1024 + i);
if (cpuval != gttval) {
DRM_INFO("incoherent CPU vs GPU at 0x%08x: "
"0x%08x vs 0x%08x\n",
(int)(obj_priv->gtt_offset +
page * PAGE_SIZE + i * 4),
cpuval, gttval);
if (bad_count++ >= 8) {
DRM_INFO("...\n");
goto out;
}
}
}
kunmap_atomic(backing_map, KM_USER0);
backing_map = NULL;
}
out:
if (backing_map != NULL)
kunmap_atomic(backing_map, KM_USER0);
iounmap(gtt_mapping);
/* give syslog time to catch up */
msleep(1);
/* Directly flush the object, since we just loaded values with the CPU
* from the backing pages and we don't want to disturb the cache
* management that we're trying to observe.
*/
i915_gem_clflush_object(obj);
}
#endif
/*
* Copyright © 2008 Intel Corporation
*
* 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
* THE AUTHORS OR COPYRIGHT HOLDERS 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:
* Eric Anholt <eric@anholt.net>
* Keith Packard <keithp@keithp.com>
*
*/
#include "drmP.h"
#include "drm.h"
#include "i915_drm.h"
#include "i915_drv.h"
static int i915_gem_active_info(char *buf, char **start, off_t offset,
int request, int *eof, void *data)
{
struct drm_minor *minor = (struct drm_minor *) data;
struct drm_device *dev = minor->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_gem_object *obj_priv;
int len = 0;
if (offset > DRM_PROC_LIMIT) {
*eof = 1;
return 0;
}
*start = &buf[offset];
*eof = 0;
DRM_PROC_PRINT("Active:\n");
list_for_each_entry(obj_priv, &dev_priv->mm.active_list,
list)
{
struct drm_gem_object *obj = obj_priv->obj;
if (obj->name) {
DRM_PROC_PRINT(" %p(%d): %08x %08x %d\n",
obj, obj->name,
obj->read_domains, obj->write_domain,
obj_priv->last_rendering_seqno);
} else {
DRM_PROC_PRINT(" %p: %08x %08x %d\n",
obj,
obj->read_domains, obj->write_domain,
obj_priv->last_rendering_seqno);
}
}
if (len > request + offset)
return request;
*eof = 1;
return len - offset;
}
static int i915_gem_flushing_info(char *buf, char **start, off_t offset,
int request, int *eof, void *data)
{
struct drm_minor *minor = (struct drm_minor *) data;
struct drm_device *dev = minor->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_gem_object *obj_priv;
int len = 0;
if (offset > DRM_PROC_LIMIT) {
*eof = 1;
return 0;
}
*start = &buf[offset];
*eof = 0;
DRM_PROC_PRINT("Flushing:\n");
list_for_each_entry(obj_priv, &dev_priv->mm.flushing_list,
list)
{
struct drm_gem_object *obj = obj_priv->obj;
if (obj->name) {
DRM_PROC_PRINT(" %p(%d): %08x %08x %d\n",
obj, obj->name,
obj->read_domains, obj->write_domain,
obj_priv->last_rendering_seqno);
} else {
DRM_PROC_PRINT(" %p: %08x %08x %d\n", obj,
obj->read_domains, obj->write_domain,
obj_priv->last_rendering_seqno);
}
}
if (len > request + offset)
return request;
*eof = 1;
return len - offset;
}
static int i915_gem_inactive_info(char *buf, char **start, off_t offset,
int request, int *eof, void *data)
{
struct drm_minor *minor = (struct drm_minor *) data;
struct drm_device *dev = minor->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_gem_object *obj_priv;
int len = 0;
if (offset > DRM_PROC_LIMIT) {
*eof = 1;
return 0;
}
*start = &buf[offset];
*eof = 0;
DRM_PROC_PRINT("Inactive:\n");
list_for_each_entry(obj_priv, &dev_priv->mm.inactive_list,
list)
{
struct drm_gem_object *obj = obj_priv->obj;
if (obj->name) {
DRM_PROC_PRINT(" %p(%d): %08x %08x %d\n",
obj, obj->name,
obj->read_domains, obj->write_domain,
obj_priv->last_rendering_seqno);
} else {
DRM_PROC_PRINT(" %p: %08x %08x %d\n", obj,
obj->read_domains, obj->write_domain,
obj_priv->last_rendering_seqno);
}
}
if (len > request + offset)
return request;
*eof = 1;
return len - offset;
}
static int i915_gem_request_info(char *buf, char **start, off_t offset,
int request, int *eof, void *data)
{
struct drm_minor *minor = (struct drm_minor *) data;
struct drm_device *dev = minor->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_gem_request *gem_request;
int len = 0;
if (offset > DRM_PROC_LIMIT) {
*eof = 1;
return 0;
}
*start = &buf[offset];
*eof = 0;
DRM_PROC_PRINT("Request:\n");
list_for_each_entry(gem_request, &dev_priv->mm.request_list,
list)
{
DRM_PROC_PRINT(" %d @ %d %08x\n",
gem_request->seqno,
(int) (jiffies - gem_request->emitted_jiffies),
gem_request->flush_domains);
}
if (len > request + offset)
return request;
*eof = 1;
return len - offset;
}
static int i915_gem_seqno_info(char *buf, char **start, off_t offset,
int request, int *eof, void *data)
{
struct drm_minor *minor = (struct drm_minor *) data;
struct drm_device *dev = minor->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
int len = 0;
if (offset > DRM_PROC_LIMIT) {
*eof = 1;
return 0;
}
*start = &buf[offset];
*eof = 0;
DRM_PROC_PRINT("Current sequence: %d\n", i915_get_gem_seqno(dev));
DRM_PROC_PRINT("Waiter sequence: %d\n",
dev_priv->mm.waiting_gem_seqno);
DRM_PROC_PRINT("IRQ sequence: %d\n", dev_priv->mm.irq_gem_seqno);
if (len > request + offset)
return request;
*eof = 1;
return len - offset;
}
static int i915_interrupt_info(char *buf, char **start, off_t offset,
int request, int *eof, void *data)
{
struct drm_minor *minor = (struct drm_minor *) data;
struct drm_device *dev = minor->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
int len = 0;
if (offset > DRM_PROC_LIMIT) {
*eof = 1;
return 0;
}
*start = &buf[offset];
*eof = 0;
DRM_PROC_PRINT("Interrupt enable: %08x\n",
I915_READ(IER));
DRM_PROC_PRINT("Interrupt identity: %08x\n",
I915_READ(IIR));
DRM_PROC_PRINT("Interrupt mask: %08x\n",
I915_READ(IMR));
DRM_PROC_PRINT("Pipe A stat: %08x\n",
I915_READ(PIPEASTAT));
DRM_PROC_PRINT("Pipe B stat: %08x\n",
I915_READ(PIPEBSTAT));
DRM_PROC_PRINT("Interrupts received: %d\n",
atomic_read(&dev_priv->irq_received));
DRM_PROC_PRINT("Current sequence: %d\n",
i915_get_gem_seqno(dev));
DRM_PROC_PRINT("Waiter sequence: %d\n",
dev_priv->mm.waiting_gem_seqno);
DRM_PROC_PRINT("IRQ sequence: %d\n",
dev_priv->mm.irq_gem_seqno);
if (len > request + offset)
return request;
*eof = 1;
return len - offset;
}
static struct drm_proc_list {
/** file name */
const char *name;
/** proc callback*/
int (*f) (char *, char **, off_t, int, int *, void *);
} i915_gem_proc_list[] = {
{"i915_gem_active", i915_gem_active_info},
{"i915_gem_flushing", i915_gem_flushing_info},
{"i915_gem_inactive", i915_gem_inactive_info},
{"i915_gem_request", i915_gem_request_info},
{"i915_gem_seqno", i915_gem_seqno_info},
{"i915_gem_interrupt", i915_interrupt_info},
};
#define I915_GEM_PROC_ENTRIES ARRAY_SIZE(i915_gem_proc_list)
int i915_gem_proc_init(struct drm_minor *minor)
{
struct proc_dir_entry *ent;
int i, j;
for (i = 0; i < I915_GEM_PROC_ENTRIES; i++) {
ent = create_proc_entry(i915_gem_proc_list[i].name,
S_IFREG | S_IRUGO, minor->dev_root);
if (!ent) {
DRM_ERROR("Cannot create /proc/dri/.../%s\n",
i915_gem_proc_list[i].name);
for (j = 0; j < i; j++)
remove_proc_entry(i915_gem_proc_list[i].name,
minor->dev_root);
return -1;
}
ent->read_proc = i915_gem_proc_list[i].f;
ent->data = minor;
}
return 0;
}
void i915_gem_proc_cleanup(struct drm_minor *minor)
{
int i;
if (!minor->dev_root)
return;
for (i = 0; i < I915_GEM_PROC_ENTRIES; i++)
remove_proc_entry(i915_gem_proc_list[i].name, minor->dev_root);
}
/*
* Copyright © 2008 Intel Corporation
*
* 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
* THE AUTHORS OR COPYRIGHT HOLDERS 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:
* Eric Anholt <eric@anholt.net>
*
*/
#include "drmP.h"
#include "drm.h"
#include "i915_drm.h"
#include "i915_drv.h"
/** @file i915_gem_tiling.c
*
* Support for managing tiling state of buffer objects.
*
* The idea behind tiling is to increase cache hit rates by rearranging
* pixel data so that a group of pixel accesses are in the same cacheline.
* Performance improvement from doing this on the back/depth buffer are on
* the order of 30%.
*
* Intel architectures make this somewhat more complicated, though, by
* adjustments made to addressing of data when the memory is in interleaved
* mode (matched pairs of DIMMS) to improve memory bandwidth.
* For interleaved memory, the CPU sends every sequential 64 bytes
* to an alternate memory channel so it can get the bandwidth from both.
*
* The GPU also rearranges its accesses for increased bandwidth to interleaved
* memory, and it matches what the CPU does for non-tiled. However, when tiled
* it does it a little differently, since one walks addresses not just in the
* X direction but also Y. So, along with alternating channels when bit
* 6 of the address flips, it also alternates when other bits flip -- Bits 9
* (every 512 bytes, an X tile scanline) and 10 (every two X tile scanlines)
* are common to both the 915 and 965-class hardware.
*
* The CPU also sometimes XORs in higher bits as well, to improve
* bandwidth doing strided access like we do so frequently in graphics. This
* is called "Channel XOR Randomization" in the MCH documentation. The result
* is that the CPU is XORing in either bit 11 or bit 17 to bit 6 of its address
* decode.
*
* All of this bit 6 XORing has an effect on our memory management,
* as we need to make sure that the 3d driver can correctly address object
* contents.
*
* If we don't have interleaved memory, all tiling is safe and no swizzling is
* required.
*
* When bit 17 is XORed in, we simply refuse to tile at all. Bit
* 17 is not just a page offset, so as we page an objet out and back in,
* individual pages in it will have different bit 17 addresses, resulting in
* each 64 bytes being swapped with its neighbor!
*
* Otherwise, if interleaved, we have to tell the 3d driver what the address
* swizzling it needs to do is, since it's writing with the CPU to the pages
* (bit 6 and potentially bit 11 XORed in), and the GPU is reading from the
* pages (bit 6, 9, and 10 XORed in), resulting in a cumulative bit swizzling
* required by the CPU of XORing in bit 6, 9, 10, and potentially 11, in order
* to match what the GPU expects.
*/
/**
* Detects bit 6 swizzling of address lookup between IGD access and CPU
* access through main memory.
*/
void
i915_gem_detect_bit_6_swizzle(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
uint32_t swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN;
uint32_t swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN;
if (!IS_I9XX(dev)) {
/* As far as we know, the 865 doesn't have these bit 6
* swizzling issues.
*/
swizzle_x = I915_BIT_6_SWIZZLE_NONE;
swizzle_y = I915_BIT_6_SWIZZLE_NONE;
} else if ((!IS_I965G(dev) && !IS_G33(dev)) || IS_I965GM(dev) ||
IS_GM45(dev)) {
uint32_t dcc;
/* On 915-945 and GM965, channel interleave by the CPU is
* determined by DCC. The CPU will alternate based on bit 6
* in interleaved mode, and the GPU will then also alternate
* on bit 6, 9, and 10 for X, but the CPU may also optionally
* alternate based on bit 17 (XOR not disabled and XOR
* bit == 17).
*/
dcc = I915_READ(DCC);
switch (dcc & DCC_ADDRESSING_MODE_MASK) {
case DCC_ADDRESSING_MODE_SINGLE_CHANNEL:
case DCC_ADDRESSING_MODE_DUAL_CHANNEL_ASYMMETRIC:
swizzle_x = I915_BIT_6_SWIZZLE_NONE;
swizzle_y = I915_BIT_6_SWIZZLE_NONE;
break;
case DCC_ADDRESSING_MODE_DUAL_CHANNEL_INTERLEAVED:
if (IS_I915G(dev) || IS_I915GM(dev) ||
dcc & DCC_CHANNEL_XOR_DISABLE) {
swizzle_x = I915_BIT_6_SWIZZLE_9_10;
swizzle_y = I915_BIT_6_SWIZZLE_9;
} else if (IS_I965GM(dev) || IS_GM45(dev)) {
/* GM965 only does bit 11-based channel
* randomization
*/
swizzle_x = I915_BIT_6_SWIZZLE_9_10_11;
swizzle_y = I915_BIT_6_SWIZZLE_9_11;
} else {
/* Bit 17 or perhaps other swizzling */
swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN;
swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN;
}
break;
}
if (dcc == 0xffffffff) {
DRM_ERROR("Couldn't read from MCHBAR. "
"Disabling tiling.\n");
swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN;
swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN;
}
} else {
/* The 965, G33, and newer, have a very flexible memory
* configuration. It will enable dual-channel mode
* (interleaving) on as much memory as it can, and the GPU
* will additionally sometimes enable different bit 6
* swizzling for tiled objects from the CPU.
*
* Here's what I found on the G965:
* slot fill memory size swizzling
* 0A 0B 1A 1B 1-ch 2-ch
* 512 0 0 0 512 0 O
* 512 0 512 0 16 1008 X
* 512 0 0 512 16 1008 X
* 0 512 0 512 16 1008 X
* 1024 1024 1024 0 2048 1024 O
*
* We could probably detect this based on either the DRB
* matching, which was the case for the swizzling required in
* the table above, or from the 1-ch value being less than
* the minimum size of a rank.
*/
if (I915_READ16(C0DRB3) != I915_READ16(C1DRB3)) {
swizzle_x = I915_BIT_6_SWIZZLE_NONE;
swizzle_y = I915_BIT_6_SWIZZLE_NONE;
} else {
swizzle_x = I915_BIT_6_SWIZZLE_9_10;
swizzle_y = I915_BIT_6_SWIZZLE_9;
}
}
dev_priv->mm.bit_6_swizzle_x = swizzle_x;
dev_priv->mm.bit_6_swizzle_y = swizzle_y;
}
/**
* Sets the tiling mode of an object, returning the required swizzling of
* bit 6 of addresses in the object.
*/
int
i915_gem_set_tiling(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
struct drm_i915_gem_set_tiling *args = data;
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_gem_object *obj;
struct drm_i915_gem_object *obj_priv;
obj = drm_gem_object_lookup(dev, file_priv, args->handle);
if (obj == NULL)
return -EINVAL;
obj_priv = obj->driver_private;
mutex_lock(&dev->struct_mutex);
if (args->tiling_mode == I915_TILING_NONE) {
obj_priv->tiling_mode = I915_TILING_NONE;
args->swizzle_mode = I915_BIT_6_SWIZZLE_NONE;
} else {
if (args->tiling_mode == I915_TILING_X)
args->swizzle_mode = dev_priv->mm.bit_6_swizzle_x;
else
args->swizzle_mode = dev_priv->mm.bit_6_swizzle_y;
/* If we can't handle the swizzling, make it untiled. */
if (args->swizzle_mode == I915_BIT_6_SWIZZLE_UNKNOWN) {
args->tiling_mode = I915_TILING_NONE;
args->swizzle_mode = I915_BIT_6_SWIZZLE_NONE;
}
}
obj_priv->tiling_mode = args->tiling_mode;
mutex_unlock(&dev->struct_mutex);
drm_gem_object_unreference(obj);
return 0;
}
/**
* Returns the current tiling mode and required bit 6 swizzling for the object.
*/
int
i915_gem_get_tiling(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
struct drm_i915_gem_get_tiling *args = data;
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_gem_object *obj;
struct drm_i915_gem_object *obj_priv;
obj = drm_gem_object_lookup(dev, file_priv, args->handle);
if (obj == NULL)
return -EINVAL;
obj_priv = obj->driver_private;
mutex_lock(&dev->struct_mutex);
args->tiling_mode = obj_priv->tiling_mode;
switch (obj_priv->tiling_mode) {
case I915_TILING_X:
args->swizzle_mode = dev_priv->mm.bit_6_swizzle_x;
break;
case I915_TILING_Y:
args->swizzle_mode = dev_priv->mm.bit_6_swizzle_y;
break;
case I915_TILING_NONE:
args->swizzle_mode = I915_BIT_6_SWIZZLE_NONE;
break;
default:
DRM_ERROR("unknown tiling mode\n");
}
mutex_unlock(&dev->struct_mutex);
drm_gem_object_unreference(obj);
return 0;
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -45,15 +45,16 @@ static struct pci_device_id pciidlist[] = { ...@@ -45,15 +45,16 @@ static struct pci_device_id pciidlist[] = {
static struct drm_driver driver = { static struct drm_driver driver = {
.driver_features = .driver_features =
DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA |
DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED,
DRIVER_IRQ_VBL,
.dev_priv_size = sizeof(drm_mga_buf_priv_t), .dev_priv_size = sizeof(drm_mga_buf_priv_t),
.load = mga_driver_load, .load = mga_driver_load,
.unload = mga_driver_unload, .unload = mga_driver_unload,
.lastclose = mga_driver_lastclose, .lastclose = mga_driver_lastclose,
.dma_quiescent = mga_driver_dma_quiescent, .dma_quiescent = mga_driver_dma_quiescent,
.device_is_agp = mga_driver_device_is_agp, .device_is_agp = mga_driver_device_is_agp,
.vblank_wait = mga_driver_vblank_wait, .get_vblank_counter = mga_get_vblank_counter,
.enable_vblank = mga_enable_vblank,
.disable_vblank = mga_disable_vblank,
.irq_preinstall = mga_driver_irq_preinstall, .irq_preinstall = mga_driver_irq_preinstall,
.irq_postinstall = mga_driver_irq_postinstall, .irq_postinstall = mga_driver_irq_postinstall,
.irq_uninstall = mga_driver_irq_uninstall, .irq_uninstall = mga_driver_irq_uninstall,
...@@ -64,20 +65,20 @@ static struct drm_driver driver = { ...@@ -64,20 +65,20 @@ static struct drm_driver driver = {
.ioctls = mga_ioctls, .ioctls = mga_ioctls,
.dma_ioctl = mga_dma_buffers, .dma_ioctl = mga_dma_buffers,
.fops = { .fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.open = drm_open, .open = drm_open,
.release = drm_release, .release = drm_release,
.ioctl = drm_ioctl, .ioctl = drm_ioctl,
.mmap = drm_mmap, .mmap = drm_mmap,
.poll = drm_poll, .poll = drm_poll,
.fasync = drm_fasync, .fasync = drm_fasync,
#ifdef CONFIG_COMPAT #ifdef CONFIG_COMPAT
.compat_ioctl = mga_compat_ioctl, .compat_ioctl = mga_compat_ioctl,
#endif #endif
}, },
.pci_driver = { .pci_driver = {
.name = DRIVER_NAME, .name = DRIVER_NAME,
.id_table = pciidlist, .id_table = pciidlist,
}, },
.name = DRIVER_NAME, .name = DRIVER_NAME,
......
...@@ -120,6 +120,7 @@ typedef struct drm_mga_private { ...@@ -120,6 +120,7 @@ typedef struct drm_mga_private {
u32 clear_cmd; u32 clear_cmd;
u32 maccess; u32 maccess;
atomic_t vbl_received; /**< Number of vblanks received. */
wait_queue_head_t fence_queue; wait_queue_head_t fence_queue;
atomic_t last_fence_retired; atomic_t last_fence_retired;
u32 next_fence_to_post; u32 next_fence_to_post;
...@@ -181,11 +182,14 @@ extern int mga_warp_install_microcode(drm_mga_private_t * dev_priv); ...@@ -181,11 +182,14 @@ extern int mga_warp_install_microcode(drm_mga_private_t * dev_priv);
extern int mga_warp_init(drm_mga_private_t * dev_priv); extern int mga_warp_init(drm_mga_private_t * dev_priv);
/* mga_irq.c */ /* mga_irq.c */
extern int mga_enable_vblank(struct drm_device *dev, int crtc);
extern void mga_disable_vblank(struct drm_device *dev, int crtc);
extern u32 mga_get_vblank_counter(struct drm_device *dev, int crtc);
extern int mga_driver_fence_wait(struct drm_device * dev, unsigned int *sequence); extern int mga_driver_fence_wait(struct drm_device * dev, unsigned int *sequence);
extern int mga_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence); extern int mga_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence);
extern irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS); extern irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS);
extern void mga_driver_irq_preinstall(struct drm_device * dev); extern void mga_driver_irq_preinstall(struct drm_device * dev);
extern void mga_driver_irq_postinstall(struct drm_device * dev); extern int mga_driver_irq_postinstall(struct drm_device *dev);
extern void mga_driver_irq_uninstall(struct drm_device * dev); extern void mga_driver_irq_uninstall(struct drm_device * dev);
extern long mga_compat_ioctl(struct file *filp, unsigned int cmd, extern long mga_compat_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg); unsigned long arg);
......
/* mga_irq.c -- IRQ handling for radeon -*- linux-c -*- /* mga_irq.c -- IRQ handling for radeon -*- linux-c -*-
* */
/*
* Copyright (C) The Weather Channel, Inc. 2002. All Rights Reserved. * Copyright (C) The Weather Channel, Inc. 2002. All Rights Reserved.
* *
* The Weather Channel (TM) funded Tungsten Graphics to develop the * The Weather Channel (TM) funded Tungsten Graphics to develop the
...@@ -35,6 +36,18 @@ ...@@ -35,6 +36,18 @@
#include "mga_drm.h" #include "mga_drm.h"
#include "mga_drv.h" #include "mga_drv.h"
u32 mga_get_vblank_counter(struct drm_device *dev, int crtc)
{
const drm_mga_private_t *const dev_priv =
(drm_mga_private_t *) dev->dev_private;
if (crtc != 0)
return 0;
return atomic_read(&dev_priv->vbl_received);
}
irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS) irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS)
{ {
struct drm_device *dev = (struct drm_device *) arg; struct drm_device *dev = (struct drm_device *) arg;
...@@ -47,9 +60,8 @@ irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS) ...@@ -47,9 +60,8 @@ irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS)
/* VBLANK interrupt */ /* VBLANK interrupt */
if (status & MGA_VLINEPEN) { if (status & MGA_VLINEPEN) {
MGA_WRITE(MGA_ICLEAR, MGA_VLINEICLR); MGA_WRITE(MGA_ICLEAR, MGA_VLINEICLR);
atomic_inc(&dev->vbl_received); atomic_inc(&dev_priv->vbl_received);
DRM_WAKEUP(&dev->vbl_queue); drm_handle_vblank(dev, 0);
drm_vbl_send_signals(dev);
handled = 1; handled = 1;
} }
...@@ -58,6 +70,7 @@ irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS) ...@@ -58,6 +70,7 @@ irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS)
const u32 prim_start = MGA_READ(MGA_PRIMADDRESS); const u32 prim_start = MGA_READ(MGA_PRIMADDRESS);
const u32 prim_end = MGA_READ(MGA_PRIMEND); const u32 prim_end = MGA_READ(MGA_PRIMEND);
MGA_WRITE(MGA_ICLEAR, MGA_SOFTRAPICLR); MGA_WRITE(MGA_ICLEAR, MGA_SOFTRAPICLR);
/* In addition to clearing the interrupt-pending bit, we /* In addition to clearing the interrupt-pending bit, we
...@@ -72,28 +85,39 @@ irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS) ...@@ -72,28 +85,39 @@ irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS)
handled = 1; handled = 1;
} }
if (handled) { if (handled)
return IRQ_HANDLED; return IRQ_HANDLED;
}
return IRQ_NONE; return IRQ_NONE;
} }
int mga_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence) int mga_enable_vblank(struct drm_device *dev, int crtc)
{ {
unsigned int cur_vblank; drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
int ret = 0;
/* Assume that the user has missed the current sequence number if (crtc != 0) {
* by about a day rather than she wants to wait for years DRM_ERROR("tried to enable vblank on non-existent crtc %d\n",
* using vertical blanks... crtc);
*/ return 0;
DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ, }
(((cur_vblank = atomic_read(&dev->vbl_received))
- *sequence) <= (1 << 23)));
*sequence = cur_vblank; MGA_WRITE(MGA_IEN, MGA_VLINEIEN | MGA_SOFTRAPEN);
return 0;
}
return ret;
void mga_disable_vblank(struct drm_device *dev, int crtc)
{
if (crtc != 0) {
DRM_ERROR("tried to disable vblank on non-existent crtc %d\n",
crtc);
}
/* Do *NOT* disable the vertical refresh interrupt. MGA doesn't have
* a nice hardware counter that tracks the number of refreshes when
* the interrupt is disabled, and the kernel doesn't know the refresh
* rate to calculate an estimate.
*/
/* MGA_WRITE(MGA_IEN, MGA_VLINEIEN | MGA_SOFTRAPEN); */
} }
int mga_driver_fence_wait(struct drm_device * dev, unsigned int *sequence) int mga_driver_fence_wait(struct drm_device * dev, unsigned int *sequence)
...@@ -125,14 +149,22 @@ void mga_driver_irq_preinstall(struct drm_device * dev) ...@@ -125,14 +149,22 @@ void mga_driver_irq_preinstall(struct drm_device * dev)
MGA_WRITE(MGA_ICLEAR, ~0); MGA_WRITE(MGA_ICLEAR, ~0);
} }
void mga_driver_irq_postinstall(struct drm_device * dev) int mga_driver_irq_postinstall(struct drm_device *dev)
{ {
drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private; drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
int ret;
ret = drm_vblank_init(dev, 1);
if (ret)
return ret;
DRM_INIT_WAITQUEUE(&dev_priv->fence_queue); DRM_INIT_WAITQUEUE(&dev_priv->fence_queue);
/* Turn on vertical blank interrupt and soft trap interrupt. */ /* Turn on soft trap interrupt. Vertical blank interrupts are enabled
MGA_WRITE(MGA_IEN, MGA_VLINEIEN | MGA_SOFTRAPEN); * in mga_enable_vblank.
*/
MGA_WRITE(MGA_IEN, MGA_SOFTRAPEN);
return 0;
} }
void mga_driver_irq_uninstall(struct drm_device * dev) void mga_driver_irq_uninstall(struct drm_device * dev)
......
...@@ -1022,7 +1022,7 @@ static int mga_getparam(struct drm_device *dev, void *data, struct drm_file *fil ...@@ -1022,7 +1022,7 @@ static int mga_getparam(struct drm_device *dev, void *data, struct drm_file *fil
switch (param->param) { switch (param->param) {
case MGA_PARAM_IRQ_NR: case MGA_PARAM_IRQ_NR:
value = dev->irq; value = drm_dev_to_irq(dev);
break; break;
case MGA_PARAM_CARD_TYPE: case MGA_PARAM_CARD_TYPE:
value = dev_priv->chipset; value = dev_priv->chipset;
......
...@@ -43,12 +43,13 @@ static struct pci_device_id pciidlist[] = { ...@@ -43,12 +43,13 @@ static struct pci_device_id pciidlist[] = {
static struct drm_driver driver = { static struct drm_driver driver = {
.driver_features = .driver_features =
DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_SG | DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_SG |
DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED,
DRIVER_IRQ_VBL,
.dev_priv_size = sizeof(drm_r128_buf_priv_t), .dev_priv_size = sizeof(drm_r128_buf_priv_t),
.preclose = r128_driver_preclose, .preclose = r128_driver_preclose,
.lastclose = r128_driver_lastclose, .lastclose = r128_driver_lastclose,
.vblank_wait = r128_driver_vblank_wait, .get_vblank_counter = r128_get_vblank_counter,
.enable_vblank = r128_enable_vblank,
.disable_vblank = r128_disable_vblank,
.irq_preinstall = r128_driver_irq_preinstall, .irq_preinstall = r128_driver_irq_preinstall,
.irq_postinstall = r128_driver_irq_postinstall, .irq_postinstall = r128_driver_irq_postinstall,
.irq_uninstall = r128_driver_irq_uninstall, .irq_uninstall = r128_driver_irq_uninstall,
...@@ -59,21 +60,20 @@ static struct drm_driver driver = { ...@@ -59,21 +60,20 @@ static struct drm_driver driver = {
.ioctls = r128_ioctls, .ioctls = r128_ioctls,
.dma_ioctl = r128_cce_buffers, .dma_ioctl = r128_cce_buffers,
.fops = { .fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.open = drm_open, .open = drm_open,
.release = drm_release, .release = drm_release,
.ioctl = drm_ioctl, .ioctl = drm_ioctl,
.mmap = drm_mmap, .mmap = drm_mmap,
.poll = drm_poll, .poll = drm_poll,
.fasync = drm_fasync, .fasync = drm_fasync,
#ifdef CONFIG_COMPAT #ifdef CONFIG_COMPAT
.compat_ioctl = r128_compat_ioctl, .compat_ioctl = r128_compat_ioctl,
#endif #endif
}, },
.pci_driver = { .pci_driver = {
.name = DRIVER_NAME, .name = DRIVER_NAME,
.id_table = pciidlist, .id_table = pciidlist,
}, },
.name = DRIVER_NAME, .name = DRIVER_NAME,
...@@ -87,6 +87,7 @@ static struct drm_driver driver = { ...@@ -87,6 +87,7 @@ static struct drm_driver driver = {
static int __init r128_init(void) static int __init r128_init(void)
{ {
driver.num_ioctls = r128_max_ioctl; driver.num_ioctls = r128_max_ioctl;
return drm_init(&driver); return drm_init(&driver);
} }
......
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
* Rickard E. (Rik) Faith <faith@valinux.com> * Rickard E. (Rik) Faith <faith@valinux.com>
* Kevin E. Martin <martin@valinux.com> * Kevin E. Martin <martin@valinux.com>
* Gareth Hughes <gareth@valinux.com> * Gareth Hughes <gareth@valinux.com>
* Michel Dänzer <daenzerm@student.ethz.ch> * Michel Dzer <daenzerm@student.ethz.ch>
*/ */
#ifndef __R128_DRV_H__ #ifndef __R128_DRV_H__
...@@ -97,6 +97,8 @@ typedef struct drm_r128_private { ...@@ -97,6 +97,8 @@ typedef struct drm_r128_private {
u32 crtc_offset; u32 crtc_offset;
u32 crtc_offset_cntl; u32 crtc_offset_cntl;
atomic_t vbl_received;
u32 color_fmt; u32 color_fmt;
unsigned int front_offset; unsigned int front_offset;
unsigned int front_pitch; unsigned int front_pitch;
...@@ -149,11 +151,12 @@ extern int r128_wait_ring(drm_r128_private_t * dev_priv, int n); ...@@ -149,11 +151,12 @@ extern int r128_wait_ring(drm_r128_private_t * dev_priv, int n);
extern int r128_do_cce_idle(drm_r128_private_t * dev_priv); extern int r128_do_cce_idle(drm_r128_private_t * dev_priv);
extern int r128_do_cleanup_cce(struct drm_device * dev); extern int r128_do_cleanup_cce(struct drm_device * dev);
extern int r128_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence); extern int r128_enable_vblank(struct drm_device *dev, int crtc);
extern void r128_disable_vblank(struct drm_device *dev, int crtc);
extern u32 r128_get_vblank_counter(struct drm_device *dev, int crtc);
extern irqreturn_t r128_driver_irq_handler(DRM_IRQ_ARGS); extern irqreturn_t r128_driver_irq_handler(DRM_IRQ_ARGS);
extern void r128_driver_irq_preinstall(struct drm_device * dev); extern void r128_driver_irq_preinstall(struct drm_device * dev);
extern void r128_driver_irq_postinstall(struct drm_device * dev); extern int r128_driver_irq_postinstall(struct drm_device *dev);
extern void r128_driver_irq_uninstall(struct drm_device * dev); extern void r128_driver_irq_uninstall(struct drm_device * dev);
extern void r128_driver_lastclose(struct drm_device * dev); extern void r128_driver_lastclose(struct drm_device * dev);
extern void r128_driver_preclose(struct drm_device * dev, extern void r128_driver_preclose(struct drm_device * dev,
......
This diff is collapsed.
...@@ -1629,7 +1629,7 @@ static int r128_getparam(struct drm_device *dev, void *data, struct drm_file *fi ...@@ -1629,7 +1629,7 @@ static int r128_getparam(struct drm_device *dev, void *data, struct drm_file *fi
switch (param->param) { switch (param->param) {
case R128_PARAM_IRQ_NR: case R128_PARAM_IRQ_NR:
value = dev->irq; value = drm_dev_to_irq(dev);
break; break;
default: default:
return -EINVAL; return -EINVAL;
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -2997,7 +2997,7 @@ static int radeon_cp_getparam(struct drm_device *dev, void *data, struct drm_fil ...@@ -2997,7 +2997,7 @@ static int radeon_cp_getparam(struct drm_device *dev, void *data, struct drm_fil
value = GET_SCRATCH(2); value = GET_SCRATCH(2);
break; break;
case RADEON_PARAM_IRQ_NR: case RADEON_PARAM_IRQ_NR:
value = dev->irq; value = drm_dev_to_irq(dev);
break; break;
case RADEON_PARAM_GART_BASE: case RADEON_PARAM_GART_BASE:
value = dev_priv->gart_vm_start; value = dev_priv->gart_vm_start;
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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