Merge branch 'master' into xgi-0-0-1-local

Conflicts:

	linux-core/Makefile
	linux-core/Makefile.kernel
	shared-core/drm_pciids.txt
This commit is contained in:
Ian Romanick 2007-06-21 14:34:25 -07:00
commit 5347c99f0e
212 changed files with 16119 additions and 7637 deletions

105
.gitignore vendored
View file

@ -1,54 +1,55 @@
*-core/linux bsd-core/linux
*-core/drm.h bsd-core/drm.h
*-core/drm_sarea.h bsd-core/drm_sarea.h
*-core/i915_dma.c bsd-core/i915_dma.c
*-core/i915_drm.h bsd-core/i915_drm.h
*-core/i915_drv.h bsd-core/i915_drv.h
*-core/i915_irq.c bsd-core/i915_irq.c
*-core/i915_mem.c bsd-core/i915_mem.c
*-core/mach64_dma.c bsd-core/mach64_dma.c
*-core/mach64_drm.h bsd-core/mach64_drm.h
*-core/mach64_drv.h bsd-core/mach64_drv.h
*-core/mach64_irq.c bsd-core/mach64_irq.c
*-core/mach64_state.c bsd-core/mach64_state.c
*-core/mga_dma.c bsd-core/mga_dma.c
*-core/mga_drm.h bsd-core/mga_drm.h
*-core/mga_drv.h bsd-core/mga_drv.h
*-core/mga_irq.c bsd-core/mga_irq.c
*-core/mga_state.c bsd-core/mga_state.c
*-core/mga_ucode.h bsd-core/mga_ucode.h
*-core/mga_warp.c bsd-core/mga_warp.c
*-core/nv_drv.h bsd-core/nv_drv.h
*-core/r128_cce.c bsd-core/r128_cce.c
*-core/r128_drm.h bsd-core/r128_drm.h
*-core/r128_drv.h bsd-core/r128_drv.h
*-core/r128_irq.c bsd-core/r128_irq.c
*-core/r128_state.c bsd-core/r128_state.c
*-core/r300_cmdbuf.c bsd-core/r300_cmdbuf.c
*-core/r300_reg.h bsd-core/r300_reg.h
*-core/radeon_cp.c bsd-core/radeon_cp.c
*-core/radeon_drm.h bsd-core/radeon_drm.h
*-core/radeon_drv.h bsd-core/radeon_drv.h
*-core/radeon_irq.c bsd-core/radeon_irq.c
*-core/radeon_mem.c bsd-core/radeon_mem.c
*-core/radeon_state.c bsd-core/radeon_state.c
*-core/savage_bci.c bsd-core/savage_bci.c
*-core/savage_drm.h bsd-core/savage_drm.h
*-core/savage_drv.h bsd-core/savage_drv.h
*-core/savage_state.c bsd-core/savage_state.c
*-core/sis_drm.h bsd-core/sis_drm.h
*-core/sis_drv.h bsd-core/sis_drv.h
*-core/tdfx_drv.h bsd-core/tdfx_drv.h
*-core/via_3d_reg.h bsd-core/via_3d_reg.h
*-core/via_dma.c bsd-core/via_dma.c
*-core/via_drm.h bsd-core/via_drm.h
*-core/via_drv.c bsd-core/via_drv.c
*-core/via_drv.h bsd-core/via_drv.h
*-core/via_irq.c bsd-core/via_irq.c
*-core/via_map.c bsd-core/via_map.c
*-core/via_verifier.c bsd-core/via_verifier.c
*-core/via_verifier.h bsd-core/via_verifier.h
*-core/via_video.c bsd-core/via_video.c
*~
*.flags *.flags
*.ko *.ko
*.ko.cmd *.ko.cmd
@ -74,6 +75,7 @@ config.log
config.status config.status
config.sub config.sub
configure configure
cscope.*
depcomp depcomp
device_if.h device_if.h
drm.kld drm.kld
@ -81,6 +83,7 @@ drm_pciids.h
export_syms export_syms
i915.kld i915.kld
install-sh install-sh
libdrm/config.h.in
libdrm.pc libdrm.pc
libtool libtool
ltmain.sh ltmain.sh

71
README
View file

@ -1,4 +1,69 @@
By default, this will install into /usr/local. If you want to install this
libdrm to replace your system copy, say:
./configure --prefix=/usr --exec-prefix=/ DRM README file
There are two main parts to this package: the DRM client library/interface
(libdrm.so) and kernel/hardware-specific device modules (such as i915.ko).
Compiling
---------
By default, libdrm and the DRM header files will install into /usr/local/.
If you want to install this DRM to replace your system copy, say:
./configure --prefix=/usr --exec-prefix=/
Then,
make install
To build the device-specific kernel modules:
cd linux-core/
make
cp *.ko /lib/modules/VERSION/kernel/drivers/char/drm/
(where VERSION is your kernel version: uname -f)
Or,
cd bsd-core/
make
copy the kernel modules to the appropriate place
Tips & Trouble-shooting
-----------------------
1. You'll need kernel sources. If using Fedora Core 5, for example, you may
need to install RPMs such as:
kernel-smp-devel-2.6.15-1.2054_FC5.i686.rpm
kernel-devel-2.6.15-1.2054_FC5.i686.rpm
etc.
2. You may need to make a symlink from /lib/modules/VERSION/build to your
kernel sources in /usr/src/kernels/VERSION (where version is `uname -r`):
cd /lib/modules/VERSION
ln -s /usr/src/kernels/VERSION build
3. If you've build the kernel modules but they won't load because of an
error like this:
$ /sbin/modprobe drm
FATAL: Error inserting drm (/lib/modules/2.6.15-1.2054_FC5smp/kernel/drivers/char/drm/drm.ko): Invalid module format
And 'dmesg|tail' says:
drm: disagrees about version of symbol struct_module
Try recompiling your drm modules without the Module.symvers file.
That is rm the /usr/src/kernels/2.6.15-1.2054_FC5-smp-i686/Module.symvers
file (or rename it). Then do a 'make clean' before rebuilding your drm
modules.

View file

@ -69,4 +69,3 @@ drm_pciids.h: ${SHARED}/drm_pciids.txt
${SHAREDFILES}: ${SHAREDFILES}:
ln -sf ${SHARED}/$@ $@ ln -sf ${SHARED}/$@ $@

View file

@ -32,8 +32,6 @@
#include "drmP.h" #include "drmP.h"
#define ATI_PCIGART_PAGE_SIZE 4096 /* PCI GART page size */ #define ATI_PCIGART_PAGE_SIZE 4096 /* PCI GART page size */
#define ATI_MAX_PCIGART_PAGES 8192 /* 32 MB aperture, 4K pages */
#define ATI_PCIGART_TABLE_SIZE 32768
int drm_ati_pcigart_init(drm_device_t *dev, drm_ati_pcigart_info *gart_info) int drm_ati_pcigart_init(drm_device_t *dev, drm_ati_pcigart_info *gart_info)
{ {
@ -48,7 +46,7 @@ int drm_ati_pcigart_init(drm_device_t *dev, drm_ati_pcigart_info *gart_info)
if (gart_info->gart_table_location == DRM_ATI_GART_MAIN) { if (gart_info->gart_table_location == DRM_ATI_GART_MAIN) {
/* GART table in system memory */ /* GART table in system memory */
dev->sg->dmah = drm_pci_alloc(dev, ATI_PCIGART_TABLE_SIZE, 0, dev->sg->dmah = drm_pci_alloc(dev, gart_info->table_size, 0,
0xfffffffful); 0xfffffffful);
if (dev->sg->dmah == NULL) { if (dev->sg->dmah == NULL) {
DRM_ERROR("cannot allocate PCI GART table!\n"); DRM_ERROR("cannot allocate PCI GART table!\n");
@ -63,9 +61,9 @@ int drm_ati_pcigart_init(drm_device_t *dev, drm_ati_pcigart_info *gart_info)
pci_gart = gart_info->addr; pci_gart = gart_info->addr;
} }
pages = DRM_MIN(dev->sg->pages, ATI_MAX_PCIGART_PAGES); pages = DRM_MIN(dev->sg->pages, gart_info->table_size / sizeof(u32));
bzero(pci_gart, ATI_PCIGART_TABLE_SIZE); bzero(pci_gart, gart_info->table_size);
KASSERT(PAGE_SIZE >= ATI_PCIGART_PAGE_SIZE, ("page size too small")); KASSERT(PAGE_SIZE >= ATI_PCIGART_PAGE_SIZE, ("page size too small"));
@ -73,10 +71,17 @@ int drm_ati_pcigart_init(drm_device_t *dev, drm_ati_pcigart_info *gart_info)
page_base = (u32) dev->sg->busaddr[i]; page_base = (u32) dev->sg->busaddr[i];
for (j = 0; j < (PAGE_SIZE / ATI_PCIGART_PAGE_SIZE); j++) { for (j = 0; j < (PAGE_SIZE / ATI_PCIGART_PAGE_SIZE); j++) {
if (gart_info->is_pcie) switch(gart_info->gart_reg_if) {
*pci_gart = (cpu_to_le32(page_base) >> 8) | 0xc; case DRM_ATI_GART_IGP:
else *pci_gart = cpu_to_le32(page_base | 0xc);
break;
case DRM_ATI_GART_PCIE:
*pci_gart = cpu_to_le32((page_base >> 8) | 0xc);
break;
default:
*pci_gart = cpu_to_le32(page_base); *pci_gart = cpu_to_le32(page_base);
break;
}
pci_gart++; pci_gart++;
page_base += ATI_PCIGART_PAGE_SIZE; page_base += ATI_PCIGART_PAGE_SIZE;
} }

View file

@ -47,6 +47,9 @@ typedef struct drm_file drm_file_t;
#include <sys/systm.h> #include <sys/systm.h>
#include <sys/conf.h> #include <sys/conf.h>
#include <sys/stat.h> #include <sys/stat.h>
#if __FreeBSD_version >= 700000
#include <sys/priv.h>
#endif
#include <sys/proc.h> #include <sys/proc.h>
#include <sys/lock.h> #include <sys/lock.h>
#include <sys/fcntl.h> #include <sys/fcntl.h>
@ -230,7 +233,11 @@ enum {
#define PAGE_ALIGN(addr) round_page(addr) #define PAGE_ALIGN(addr) round_page(addr)
/* DRM_SUSER returns true if the user is superuser */ /* DRM_SUSER returns true if the user is superuser */
#if __FreeBSD_version >= 700000
#define DRM_SUSER(p) (priv_check(p, PRIV_DRIVER) == 0)
#else
#define DRM_SUSER(p) (suser(p) == 0) #define DRM_SUSER(p) (suser(p) == 0)
#endif
#define DRM_AGP_FIND_DEVICE() agp_find_device() #define DRM_AGP_FIND_DEVICE() agp_find_device()
#define DRM_MTRR_WC MDF_WRITECOMBINE #define DRM_MTRR_WC MDF_WRITECOMBINE
#define jiffies ticks #define jiffies ticks
@ -394,19 +401,6 @@ do { \
} \ } \
} while (0) } while (0)
#define DRM_GETSAREA() \
do { \
drm_local_map_t *map; \
DRM_SPINLOCK_ASSERT(&dev->dev_lock); \
TAILQ_FOREACH(map, &dev->maplist, link) { \
if (map->type == _DRM_SHM && \
map->flags & _DRM_CONTAINS_LOCK) { \
dev_priv->sarea = map; \
break; \
} \
} \
} while (0)
#if defined(__FreeBSD__) && __FreeBSD_version > 500000 #if defined(__FreeBSD__) && __FreeBSD_version > 500000
#define DRM_WAIT_ON( ret, queue, timeout, condition ) \ #define DRM_WAIT_ON( ret, queue, timeout, condition ) \
for ( ret = 0 ; !ret && !(condition) ; ) { \ for ( ret = 0 ; !ret && !(condition) ; ) { \
@ -627,12 +621,17 @@ typedef struct drm_vbl_sig {
#define DRM_ATI_GART_MAIN 1 #define DRM_ATI_GART_MAIN 1
#define DRM_ATI_GART_FB 2 #define DRM_ATI_GART_FB 2
#define DRM_ATI_GART_PCI 1
#define DRM_ATI_GART_PCIE 2
#define DRM_ATI_GART_IGP 3
typedef struct ati_pcigart_info { typedef struct ati_pcigart_info {
int gart_table_location; int gart_table_location;
int is_pcie; int gart_reg_if;
void *addr; void *addr;
dma_addr_t bus_addr; dma_addr_t bus_addr;
drm_local_map_t mapping; drm_local_map_t mapping;
int table_size;
} drm_ati_pcigart_info; } drm_ati_pcigart_info;
struct drm_driver_info { struct drm_driver_info {
@ -822,6 +821,7 @@ dev_type_read(drm_read);
dev_type_poll(drm_poll); dev_type_poll(drm_poll);
dev_type_mmap(drm_mmap); dev_type_mmap(drm_mmap);
#endif #endif
extern drm_local_map_t *drm_getsarea(drm_device_t *dev);
/* File operations helpers (drm_fops.c) */ /* File operations helpers (drm_fops.c) */
#ifdef __FreeBSD__ #ifdef __FreeBSD__

View file

@ -43,7 +43,7 @@ static int
drm_device_find_capability(drm_device_t *dev, int cap) drm_device_find_capability(drm_device_t *dev, int cap)
{ {
#ifdef __FreeBSD__ #ifdef __FreeBSD__
#if __FreeBSD_version >= 700010 #if __FreeBSD_version >= 602102
return (pci_find_extcap(dev->device, cap, NULL) == 0); return (pci_find_extcap(dev->device, cap, NULL) == 0);
#else #else

View file

@ -316,6 +316,9 @@ void drm_rmmap(drm_device_t *dev, drm_local_map_t *map)
case _DRM_CONSISTENT: case _DRM_CONSISTENT:
drm_pci_free(dev, map->dmah); drm_pci_free(dev, map->dmah);
break; break;
default:
DRM_ERROR("Bad map type %d\n", map->type);
break;
} }
if (map->bsr != NULL) { if (map->bsr != NULL) {

View file

@ -1 +0,0 @@
../shared-core/drm_drawable.c

51
bsd-core/drm_drawable.c Normal file
View file

@ -0,0 +1,51 @@
/* drm_drawable.h -- IOCTLs for drawables -*- linux-c -*-
* Created: Tue Feb 2 08:37:54 1999 by faith@valinux.com
*/
/*-
* Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
* Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
* 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
* VA LINUX SYSTEMS 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:
* Rickard E. (Rik) Faith <faith@valinux.com>
* Gareth Hughes <gareth@valinux.com>
*
*/
#include "drmP.h"
int drm_adddraw(DRM_IOCTL_ARGS)
{
drm_draw_t draw;
draw.handle = 0; /* NOOP */
DRM_DEBUG("%d\n", draw.handle);
DRM_COPY_TO_USER_IOCTL( (drm_draw_t *)data, draw, sizeof(draw) );
return 0;
}
int drm_rmdraw(DRM_IOCTL_ARGS)
{
return 0; /* NOOP */
}

View file

@ -912,6 +912,18 @@ int drm_ioctl(struct cdev *kdev, u_long cmd, caddr_t data, int flags,
return DRM_ERR(retcode); return DRM_ERR(retcode);
} }
drm_local_map_t *drm_getsarea(drm_device_t *dev)
{
drm_local_map_t *map;
DRM_SPINLOCK_ASSERT(&dev->dev_lock);
TAILQ_FOREACH(map, &dev->maplist, link) {
if (map->type == _DRM_SHM && (map->flags & _DRM_CONTAINS_LOCK))
return map;
}
return NULL;
}
#if DRM_LINUX #if DRM_LINUX

View file

@ -102,11 +102,13 @@ int drm_irq_install(drm_device_t *dev)
retcode = ENOENT; retcode = ENOENT;
goto err; goto err;
} }
#if __FreeBSD_version < 500000 #if __FreeBSD_version >= 700031
retcode = bus_setup_intr(dev->device, dev->irqr, INTR_TYPE_TTY, retcode = bus_setup_intr(dev->device, dev->irqr,
dev->irq_handler, dev, &dev->irqh); INTR_TYPE_TTY | INTR_MPSAFE,
NULL, drm_irq_handler_wrap, dev, &dev->irqh);
#else #else
retcode = bus_setup_intr(dev->device, dev->irqr, INTR_TYPE_TTY | INTR_MPSAFE, retcode = bus_setup_intr(dev->device, dev->irqr,
INTR_TYPE_TTY | INTR_MPSAFE,
drm_irq_handler_wrap, dev, &dev->irqh); drm_irq_handler_wrap, dev, &dev->irqh);
#endif #endif
if (retcode != 0) if (retcode != 0)

View file

@ -19,7 +19,7 @@
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
AC_PREREQ(2.57) AC_PREREQ(2.57)
AC_INIT([libdrm], 2.3.0, [dri-devel@lists.sourceforge.net], libdrm) AC_INIT([libdrm], 2.3.1, [dri-devel@lists.sourceforge.net], libdrm)
AC_CONFIG_SRCDIR([Makefile.am]) AC_CONFIG_SRCDIR([Makefile.am])
AM_INIT_AUTOMAKE([dist-bzip2]) AM_INIT_AUTOMAKE([dist-bzip2])

File diff suppressed because it is too large Load diff

View file

@ -31,8 +31,6 @@
* *
*/ */
/* $XFree86: xc/programs/Xserver/hw/xfree86/os-support/xf86drm.h,v 1.26 2003/08/16 19:26:37 dawes Exp $ */
#ifndef _XF86DRM_H_ #ifndef _XF86DRM_H_
#define _XF86DRM_H_ #define _XF86DRM_H_
@ -270,6 +268,7 @@ typedef struct _drmTextureRegion {
typedef enum { typedef enum {
DRM_VBLANK_ABSOLUTE = 0x0, /**< Wait for specific vblank sequence number */ DRM_VBLANK_ABSOLUTE = 0x0, /**< Wait for specific vblank sequence number */
DRM_VBLANK_RELATIVE = 0x1, /**< Wait for given number of vblanks */ DRM_VBLANK_RELATIVE = 0x1, /**< Wait for given number of vblanks */
DRM_VBLANK_FLIP = 0x8000000, /**< Scheduled buffer swap should flip */
DRM_VBLANK_NEXTONMISS = 0x10000000, /**< If missed, wait for next vblank */ DRM_VBLANK_NEXTONMISS = 0x10000000, /**< If missed, wait for next vblank */
DRM_VBLANK_SECONDARY = 0x20000000, /**< Secondary display controller */ DRM_VBLANK_SECONDARY = 0x20000000, /**< Secondary display controller */
DRM_VBLANK_SIGNAL = 0x40000000 /* Send signal instead of blocking */ DRM_VBLANK_SIGNAL = 0x40000000 /* Send signal instead of blocking */

View file

@ -25,8 +25,6 @@
* *
* Authors: Rickard E. (Rik) Faith <faith@valinux.com> * Authors: Rickard E. (Rik) Faith <faith@valinux.com>
* *
* $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/xf86drmHash.c,v 1.4 2001/03/21 18:08:54 dawes Exp $
*
* DESCRIPTION * DESCRIPTION
* *
* This file contains a straightforward implementation of a fixed-sized * This file contains a straightforward implementation of a fixed-sized
@ -70,25 +68,14 @@
* *
*/ */
#ifdef HAVE_XORG_CONFIG_H #include <stdio.h>
#include <xorg-config.h> #include <stdlib.h>
#endif
#define HASH_MAIN 0 #define HASH_MAIN 0
#if HASH_MAIN #if !HASH_MAIN
# include <stdio.h>
# include <stdlib.h>
#else
# include "drm.h" # include "drm.h"
# include "xf86drm.h" # include "xf86drm.h"
# ifdef XFree86LOADER
# include "xf86.h"
# include "xf86_ansic.h"
# else
# include <stdio.h>
# include <stdlib.h>
# endif
#endif #endif
#define HASH_MAGIC 0xdeadbeef #define HASH_MAGIC 0xdeadbeef

View file

@ -25,8 +25,6 @@
* *
* Authors: Rickard E. (Rik) Faith <faith@valinux.com> * Authors: Rickard E. (Rik) Faith <faith@valinux.com>
* *
* $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/xf86drmRandom.c,v 1.4 2000/06/17 00:03:34 martin Exp $
*
* DESCRIPTION * DESCRIPTION
* *
* This file contains a simple, straightforward implementation of the Park * This file contains a simple, straightforward implementation of the Park
@ -73,25 +71,14 @@
* *
*/ */
#ifdef HAVE_XORG_CONFIG_H #include <stdio.h>
#include <xorg-config.h> #include <stdlib.h>
#endif
#define RANDOM_MAIN 0 #define RANDOM_MAIN 0
#if RANDOM_MAIN #if !RANDOM_MAIN
# include <stdio.h>
# include <stdlib.h>
#else
# include "drm.h" # include "drm.h"
# include "xf86drm.h" # include "xf86drm.h"
# ifdef XFree86LOADER
# include "xf86.h"
# include "xf86_ansic.h"
# else
# include <stdio.h>
# include <stdlib.h>
# endif
#endif #endif
#define RANDOM_MAGIC 0xfeedbeef #define RANDOM_MAGIC 0xfeedbeef

View file

@ -25,8 +25,6 @@
* *
* Authors: Rickard E. (Rik) Faith <faith@valinux.com> * Authors: Rickard E. (Rik) Faith <faith@valinux.com>
* *
* $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/xf86drmSL.c,v 1.3 2000/06/17 00:03:34 martin Exp $
*
* DESCRIPTION * DESCRIPTION
* *
* This file contains a straightforward skip list implementation.n * This file contains a straightforward skip list implementation.n
@ -40,26 +38,16 @@
* *
*/ */
#ifdef HAVE_XORG_CONFIG_H #include <stdio.h>
#include <xorg-config.h> #include <stdlib.h>
#endif
#define SL_MAIN 0 #define SL_MAIN 0
#if SL_MAIN #if !SL_MAIN
# include <stdio.h>
# include <stdlib.h>
# include <sys/time.h>
#else
# include "drm.h" # include "drm.h"
# include "xf86drm.h" # include "xf86drm.h"
# ifdef XFree86LOADER #else
# include "xf86.h" # include <sys/time.h>
# include "xf86_ansic.h"
# else
# include <stdio.h>
# include <stdlib.h>
# endif
#endif #endif
#define SL_LIST_MAGIC 0xfacade00LU #define SL_LIST_MAGIC 0xfacade00LU

View file

@ -60,7 +60,7 @@ typedef struct _drmMMListHead
(__item)->next = (__item); \ (__item)->next = (__item); \
} while (0) } while (0)
#define DRMLISTADD(__item, __list) \ #define DRMLISTADD(__item, __list) \
do { \ do { \
(__item)->prev = (__list); \ (__item)->prev = (__list); \
(__item)->next = (__list)->next; \ (__item)->next = (__list)->next; \
@ -93,16 +93,18 @@ typedef struct _drmMMListHead
#define DRMLISTENTRY(__type, __item, __field) \ #define DRMLISTENTRY(__type, __item, __field) \
((__type *)(((char *) (__item)) - offsetof(__type, __field))) ((__type *)(((char *) (__item)) - offsetof(__type, __field)))
typedef struct _drmFence{ typedef struct _drmFence
unsigned handle; {
int class; unsigned handle;
unsigned type; int class;
unsigned flags; unsigned type;
unsigned signaled; unsigned flags;
unsigned pad[4]; /* for future expansion */ unsigned signaled;
unsigned pad[4]; /* for future expansion */
} drmFence; } drmFence;
typedef struct _drmBO{ typedef struct _drmBO
{
drm_bo_type_t type; drm_bo_type_t type;
unsigned handle; unsigned handle;
drm_u64_t mapHandle; drm_u64_t mapHandle;
@ -121,8 +123,8 @@ typedef struct _drmBO{
unsigned pad[8]; /* for future expansion */ unsigned pad[8]; /* for future expansion */
} drmBO; } drmBO;
typedef struct _drmBONode
typedef struct _drmBONode { {
drmMMListHead head; drmMMListHead head;
drmBO *buf; drmBO *buf;
drm_bo_arg_t bo_arg; drm_bo_arg_t bo_arg;
@ -138,22 +140,24 @@ typedef struct _drmBOList {
drmMMListHead free; drmMMListHead free;
} drmBOList; } drmBOList;
/* Fencing */
extern int drmFenceCreate(int fd, unsigned flags, int class, /*
unsigned type, * Fence functions.
drmFence *fence); */
extern int drmFenceDestroy(int fd, const drmFence *fence);
extern int drmFenceReference(int fd, unsigned handle, drmFence *fence); extern int drmFenceCreate(int fd, unsigned flags, int class,
extern int drmFenceUnreference(int fd, const drmFence *fence); unsigned type, drmFence *fence);
extern int drmFenceFlush(int fd, drmFence *fence, unsigned flush_type); extern int drmFenceDestroy(int fd, const drmFence *fence);
extern int drmFenceSignaled(int fd, drmFence *fence, extern int drmFenceReference(int fd, unsigned handle, drmFence *fence);
unsigned fenceType, int *signaled); extern int drmFenceUnreference(int fd, const drmFence *fence);
extern int drmFenceWait(int fd, unsigned flags, drmFence *fence, extern int drmFenceFlush(int fd, drmFence *fence, unsigned flush_type);
unsigned flush_type); extern int drmFenceSignaled(int fd, drmFence *fence,
extern int drmFenceEmit(int fd, unsigned flags, drmFence *fence, unsigned fenceType, int *signaled);
unsigned emit_type); extern int drmFenceWait(int fd, unsigned flags, drmFence *fence,
extern int drmFenceBuffers(int fd, unsigned flags, drmFence *fence); unsigned flush_type);
extern int drmFenceEmit(int fd, unsigned flags, drmFence *fence,
unsigned emit_type);
extern int drmFenceBuffers(int fd, unsigned flags, drmFence *fence);
/* /*

1
linux-core/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
Module*.symvers

View file

@ -53,22 +53,13 @@ choice
depends on DRM && AGP && AGP_INTEL depends on DRM && AGP && AGP_INTEL
optional optional
config DRM_I830
tristate "i830 driver"
help
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.
config DRM_I915 config DRM_I915
tristate "i915 driver" tristate "i915 driver"
help help
Choose this option if you have a system that has Intel 830M, 845G, 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 852GM, 855GM, 865G, 915G, 915GM, 945G, 945GM and 965G integrated
module will be called i915. AGP support is required for this driver graphics. If M is selected, the module will be called i915.
to work. This driver will eventually replace the I830 driver, when AGP support is required for this driver to work.
later release of X start to use the new DDX and DRI.
endchoice endchoice

View file

@ -58,12 +58,12 @@ endif
# Modules for all architectures # Modules for all architectures
MODULE_LIST := drm.o tdfx.o r128.o radeon.o mga.o sis.o savage.o via.o \ MODULE_LIST := drm.o tdfx.o r128.o radeon.o mga.o sis.o savage.o via.o \
mach64.o nv.o xgi.o mach64.o nv.o nouveau.o xgi.o
# Modules only for ix86 architectures # Modules only for ix86 architectures
ifneq (,$(findstring 86,$(MACHINE))) ifneq (,$(findstring 86,$(MACHINE)))
ARCHX86 := 1 ARCHX86 := 1
MODULE_LIST += i830.o i810.o i915.o MODULE_LIST += i810.o i915.o
endif endif
ifneq (,$(findstring sparc64,$(MACHINE))) ifneq (,$(findstring sparc64,$(MACHINE)))
@ -75,46 +75,31 @@ DRM_MODULES ?= $(MODULE_LIST)
# These definitions are for handling dependencies in the out of kernel build. # These definitions are for handling dependencies in the out of kernel build.
DRMSHARED = drm.h drm_sarea.h drm_drawable.c
DRMHEADERS = drmP.h drm_compat.h drm_os_linux.h drm.h drm_sarea.h DRMHEADERS = drmP.h drm_compat.h drm_os_linux.h drm.h drm_sarea.h
COREHEADERS = drm_core.h drm_sman.h drm_hashtab.h COREHEADERS = drm_core.h drm_sman.h drm_hashtab.h
TDFXHEADERS = tdfx_drv.h $(DRMHEADERS) TDFXHEADERS = tdfx_drv.h $(DRMHEADERS)
TDFXSHARED = tdfx_drv.h
R128HEADERS = r128_drv.h r128_drm.h $(DRMHEADERS) R128HEADERS = r128_drv.h r128_drm.h $(DRMHEADERS)
R128SHARED = r128_drv.h r128_drm.h r128_cce.c r128_state.c r128_irq.c
RADEONHEADERS = radeon_drv.h radeon_drm.h r300_reg.h $(DRMHEADERS) RADEONHEADERS = radeon_drv.h radeon_drm.h r300_reg.h $(DRMHEADERS)
RADEONSHARED = radeon_drv.h radeon_drm.h radeon_cp.c radeon_irq.c \
radeon_mem.c radeon_state.c r300_cmdbuf.c r300_reg.h
MGAHEADERS = mga_drv.h mga_drm.h mga_ucode.h $(DRMHEADERS) MGAHEADERS = mga_drv.h mga_drm.h mga_ucode.h $(DRMHEADERS)
MGASHARED = mga_dma.c mga_drm.h mga_drv.h mga_irq.c mga_state.c \
mga_ucode.h mga_warp.c
I810HEADERS = i810_drv.h i810_drm.h $(DRMHEADERS) I810HEADERS = i810_drv.h i810_drm.h $(DRMHEADERS)
I830HEADERS = i830_drv.h i830_drm.h $(DRMHEADERS)
I915HEADERS = i915_drv.h i915_drm.h $(DRMHEADERS) I915HEADERS = i915_drv.h i915_drm.h $(DRMHEADERS)
I915SHARED = i915_drv.h i915_drm.h i915_irq.c i915_mem.c i915_dma.c
SISHEADERS= sis_drv.h sis_drm.h drm_hashtab.h drm_sman.h $(DRMHEADERS) SISHEADERS= sis_drv.h sis_drm.h drm_hashtab.h drm_sman.h $(DRMHEADERS)
SISSHARED= sis_drv.h sis_drm.h
SAVAGEHEADERS= savage_drv.h savage_drm.h $(DRMHEADERS) SAVAGEHEADERS= savage_drv.h savage_drm.h $(DRMHEADERS)
SAVAGESHARED= savage_drv.h savage_drm.h savage_bci.c savage_state.c
VIAHEADERS = via_drm.h via_drv.h via_3d_reg.h via_verifier.h $(DRMHEADERS) VIAHEADERS = via_drm.h via_drv.h via_3d_reg.h via_verifier.h $(DRMHEADERS)
VIASHARED = via_drm.h via_drv.h via_3d_reg.h via_drv.c via_irq.c via_map.c \
via_dma.c via_verifier.c via_verifier.h via_video.c
MACH64HEADERS = mach64_drv.h mach64_drm.h $(DRMHEADERS) MACH64HEADERS = mach64_drv.h mach64_drm.h $(DRMHEADERS)
MACH64SHARED = mach64_drv.h mach64_drm.h mach64_dma.c \
mach64_irq.c mach64_state.c
NVHEADERS = nv_drv.h $(DRMHEADERS) NVHEADERS = nv_drv.h $(DRMHEADERS)
<<<<<<< HEAD:linux-core/Makefile
NVSHARED = nv_drv.h NVSHARED = nv_drv.h
XGIHEADERS = xgi_drv.h xgi_drm.h XGIHEADERS = xgi_drv.h xgi_drm.h
=======
>>>>>>> 40f6a696cb22ffa064f78198a7a241015d365967:linux-core/Makefile
FFBHEADERS = ffb_drv.h $(DRMHEADERS) FFBHEADERS = ffb_drv.h $(DRMHEADERS)
NOUVEAUHEADERS = nouveau_drv.h nouveau_drm.h nouveau_reg.h $(DRMHEADERS)
SHAREDSRC = $(DRMSHARED) $(MGASHARED) $(R128SHARED) $(RADEONSHARED) \
$(SISSHARED) $(TDFXSHARED) $(VIASHARED) $(MACH64SHARED) \
$(I915SHARED) $(SAVAGESHARED) $(NVSHARED)
PROGS = dristat drmstat PROGS = dristat drmstat
CLEANFILES = *.o *.ko $(PROGS) .depend .*.flags .*.d .*.cmd *.mod.c linux drm_pciids.h .tmp_versions CLEANFILES = *.o *.ko $(PROGS) .depend .*.flags .*.d .*.cmd *.mod.c drm_pciids.h .tmp_versions
# VERSION is not defined from the initial invocation. It is defined when # VERSION is not defined from the initial invocation. It is defined when
# this Makefile is invoked from the kernel's root Makefile. # this Makefile is invoked from the kernel's root Makefile.
@ -227,27 +212,13 @@ endif
SHAREDDIR := ../shared-core SHAREDDIR := ../shared-core
HASSHARED := $(shell if [ -d $(SHAREDDIR) ]; then echo y; fi) ifeq ($(shell if [ -d $(SHAREDDIR) ]; then echo y; fi),y)
includes:: drm_pciids.h
ifeq ($(HASSHARED),y)
includes:: $(SHAREDSRC) drm_pciids.h
drm_pciids.h: $(SHAREDDIR)/drm_pciids.txt drm_pciids.h: $(SHAREDDIR)/drm_pciids.txt
sh ../scripts/create_linux_pci_lists.sh < $(SHAREDDIR)/drm_pciids.txt sh ../scripts/create_linux_pci_lists.sh < $(SHAREDDIR)/drm_pciids.txt
$(SHAREDSRC):
@if [ -r $(SHAREDDIR)/$@ ]; then \
(rm -f $@; set -x; ln -s $(SHAREDDIR)/$@ $@); fi
CLEANFILES += $(SHAREDSRC)
endif endif
includes:: linux
linux:
rm -f linux
ln -s . linux
clean cleandir: clean cleandir:
rm -rf $(CLEANFILES) rm -rf $(CLEANFILES)
@ -271,15 +242,18 @@ dristat: dristat.c
drmstat: drmstat.c drmstat: drmstat.c
$(CC) $(PRGCFLAGS) $< -o $@ $(DRMSTATLIBS) $(CC) $(PRGCFLAGS) $< -o $@ $(DRMSTATLIBS)
install:
make -C $(LINUXDIR) $(GETCONFIG) SUBDIRS=`pwd` DRMSRCDIR=`pwd` modules_install
else else
# Check for kernel versions that we don't support. # Check for kernel versions that we don't support.
BELOW24 := $(shell if [ $(VERSION) -lt 2 -o $(PATCHLEVEL) -lt 4 ]; then \ BELOW26 := $(shell if [ $(VERSION) -lt 2 -o $(PATCHLEVEL) -lt 6 ]; then \
echo y; fi) echo y; fi)
ifeq ($(BELOW24),y) ifeq ($(BELOW26),y)
$(error Only 2.4.x and later kernels are supported \ $(error Only 2.6.x and later kernels are supported \
($(VERSION).$(PATCHLEVEL).$(SUBLEVEL))) ($(VERSION).$(PATCHLEVEL).$(SUBLEVEL)))
endif endif
@ -292,30 +266,6 @@ endif
# This needs to go before all other include paths. # This needs to go before all other include paths.
CC += -I$(DRMSRCDIR) CC += -I$(DRMSRCDIR)
# Check for Red Hat's 4-argument do_munmap().
DOMUNMAP := $(shell grep do_munmap $(LINUXDIR)/include/linux/mm.h | \
grep -c acct)
ifneq ($(DOMUNMAP),0)
EXTRA_CFLAGS += -DDO_MUNMAP_4_ARGS
endif
# Check for 5-argument remap_page_range() in RH9 kernel, and 2.5.x kernels
RPR := $(shell grep remap_page_range $(LINUXDIR)/include/linux/mm.h | \
grep -c vma)
ifneq ($(RPR),0)
EXTRA_CFLAGS += -DREMAP_PAGE_RANGE_5_ARGS
endif
# Check for 4-argument vmap() in some 2.5.x and 2.4.x kernels
VMAP := $(shell grep -A1 'vmap.*count,$$' $(LINUXDIR)/include/linux/vmalloc.h | \
grep -c prot)
ifneq ($(VMAP),0)
EXTRA_CFLAGS += -DVMAP_4_ARGS
endif
# Check for PAGE_AGP definition # Check for PAGE_AGP definition
PAGE_AGP := $(shell cat $(LINUXDIR)/include/asm/agp.h 2>/dev/null | \ PAGE_AGP := $(shell cat $(LINUXDIR)/include/asm/agp.h 2>/dev/null | \
grep -c PAGE_AGP) grep -c PAGE_AGP)
@ -324,7 +274,6 @@ ifneq ($(PAGE_AGP),0)
EXTRA_CFLAGS += -DHAVE_PAGE_AGP EXTRA_CFLAGS += -DHAVE_PAGE_AGP
endif endif
# Start with all modules turned off. # Start with all modules turned off.
CONFIG_DRM_GAMMA := n CONFIG_DRM_GAMMA := n
CONFIG_DRM_TDFX := n CONFIG_DRM_TDFX := n
@ -332,7 +281,6 @@ CONFIG_DRM_MGA := n
CONFIG_DRM_I810 := n CONFIG_DRM_I810 := n
CONFIG_DRM_R128 := n CONFIG_DRM_R128 := n
CONFIG_DRM_RADEON := n CONFIG_DRM_RADEON := n
CONFIG_DRM_I830 := n
CONFIG_DRM_I915 := n CONFIG_DRM_I915 := n
CONFIG_DRM_SIS := n CONFIG_DRM_SIS := n
CONFIG_DRM_FFB := n CONFIG_DRM_FFB := n
@ -340,7 +288,11 @@ CONFIG_DRM_SAVAGE := n
CONFIG_DRM_VIA := n CONFIG_DRM_VIA := n
CONFIG_DRM_MACH64 := n CONFIG_DRM_MACH64 := n
CONFIG_DRM_NV := n CONFIG_DRM_NV := n
<<<<<<< HEAD:linux-core/Makefile
CONFIG_DRM_XGI := n CONFIG_DRM_XGI := n
=======
CONFIG_DRM_NOUVEAU := n
>>>>>>> 40f6a696cb22ffa064f78198a7a241015d365967:linux-core/Makefile
# Enable module builds for the modules requested/supported. # Enable module builds for the modules requested/supported.
@ -374,8 +326,13 @@ endif
ifneq (,$(findstring nv,$(DRM_MODULES))) ifneq (,$(findstring nv,$(DRM_MODULES)))
CONFIG_DRM_NV := m CONFIG_DRM_NV := m
endif endif
<<<<<<< HEAD:linux-core/Makefile
ifneq (,$(findstring xgi,$(DRM_MODULES))) ifneq (,$(findstring xgi,$(DRM_MODULES)))
CONFIG_DRM_XGI := m CONFIG_DRM_XGI := m
=======
ifneq (,$(findstring nouveau,$(DRM_MODULES)))
CONFIG_DRM_NOUVEAU := m
>>>>>>> 40f6a696cb22ffa064f78198a7a241015d365967:linux-core/Makefile
endif endif
# These require AGP support # These require AGP support
@ -383,9 +340,6 @@ endif
ifneq (,$(findstring i810,$(DRM_MODULES))) ifneq (,$(findstring i810,$(DRM_MODULES)))
CONFIG_DRM_I810 := m CONFIG_DRM_I810 := m
endif endif
ifneq (,$(findstring i830,$(DRM_MODULES)))
CONFIG_DRM_I830 := m
endif
ifneq (,$(findstring i915,$(DRM_MODULES))) ifneq (,$(findstring i915,$(DRM_MODULES)))
CONFIG_DRM_I915 := m CONFIG_DRM_I915 := m
endif endif
@ -398,7 +352,6 @@ $(tdfx-objs): $(TDFXHEADERS)
$(r128-objs): $(R128HEADERS) $(r128-objs): $(R128HEADERS)
$(mga-objs): $(MGAHEADERS) $(mga-objs): $(MGAHEADERS)
$(i810-objs): $(I810HEADERS) $(i810-objs): $(I810HEADERS)
$(i830-objs): $(I830HEADERS)
$(i915-objs): $(I915HEADERS) $(i915-objs): $(I915HEADERS)
$(radeon-objs): $(RADEONHEADERS) $(radeon-objs): $(RADEONHEADERS)
$(sis-objs): $(SISHEADERS) $(sis-objs): $(SISHEADERS)
@ -407,7 +360,11 @@ $(savage-objs): $(SAVAGEHEADERS)
$(via-objs): $(VIAHEADERS) $(via-objs): $(VIAHEADERS)
$(mach64-objs): $(MACH64HEADERS) $(mach64-objs): $(MACH64HEADERS)
$(nv-objs): $(NVHEADERS) $(nv-objs): $(NVHEADERS)
<<<<<<< HEAD:linux-core/Makefile
$(xgi-objs): $(XGIHEADERS) $(xgi-objs): $(XGIHEADERS)
=======
$(nouveau-objs): $(NOUVEAUHEADERS)
>>>>>>> 40f6a696cb22ffa064f78198a7a241015d365967:linux-core/Makefile
endif endif

View file

@ -13,21 +13,27 @@ drm-objs := drm_auth.o drm_bufs.o drm_context.o drm_dma.o drm_drawable.o \
drm_sysfs.o drm_pci.o drm_agpsupport.o drm_scatter.o \ drm_sysfs.o drm_pci.o drm_agpsupport.o drm_scatter.o \
drm_memory_debug.o ati_pcigart.o drm_sman.o \ drm_memory_debug.o ati_pcigart.o drm_sman.o \
drm_hashtab.o drm_mm.o drm_object.o drm_compat.o \ drm_hashtab.o drm_mm.o drm_object.o drm_compat.o \
drm_fence.o drm_ttm.o drm_bo.o drm_fence.o drm_ttm.o drm_bo.o drm_bo_move.o
tdfx-objs := tdfx_drv.o tdfx-objs := tdfx_drv.o
r128-objs := r128_drv.o r128_cce.o r128_state.o r128_irq.o r128-objs := r128_drv.o r128_cce.o r128_state.o r128_irq.o
mga-objs := mga_drv.o mga_dma.o mga_state.o mga_warp.o mga_irq.o mga-objs := mga_drv.o mga_dma.o mga_state.o mga_warp.o mga_irq.o
i810-objs := i810_drv.o i810_dma.o i810-objs := i810_drv.o i810_dma.o
i830-objs := i830_drv.o i830_dma.o i830_irq.o
i915-objs := i915_drv.o i915_dma.o i915_irq.o i915_mem.o i915_fence.o \ i915-objs := i915_drv.o i915_dma.o i915_irq.o i915_mem.o i915_fence.o \
i915_buffer.o i915_buffer.o
nouveau-objs := nouveau_drv.o nouveau_state.o nouveau_fifo.o nouveau_mem.o \
nouveau_object.o nouveau_irq.o \
nv04_timer.o \
nv04_mc.o nv40_mc.o \
nv04_fb.o nv10_fb.o nv40_fb.o \
nv04_graph.o nv10_graph.o nv20_graph.o nv30_graph.o \
nv40_graph.o
radeon-objs := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o r300_cmdbuf.o radeon-objs := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o r300_cmdbuf.o
sis-objs := sis_drv.o sis_mm.o sis-objs := sis_drv.o sis_mm.o
ffb-objs := ffb_drv.o ffb_context.o ffb-objs := ffb_drv.o ffb_context.o
savage-objs := savage_drv.o savage_bci.o savage_state.o savage-objs := savage_drv.o savage_bci.o savage_state.o
via-objs := via_irq.o via_drv.o via_map.o via_mm.o via_dma.o via_verifier.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 via_video.o via_dmablit.o via_fence.o via_buffer.o
mach64-objs := mach64_drv.o mach64_dma.o mach64_irq.o mach64_state.o mach64-objs := mach64_drv.o mach64_dma.o mach64_irq.o mach64_state.o
nv-objs := nv_drv.o nv-objs := nv_drv.o
xgi-objs := xgi_drv.o xgi_mm.o xgi-objs := xgi_drv.o xgi_mm.o
@ -37,6 +43,7 @@ radeon-objs += radeon_ioc32.o
mga-objs += mga_ioc32.o mga-objs += mga_ioc32.o
r128-objs += r128_ioc32.o r128-objs += r128_ioc32.o
i915-objs += i915_ioc32.o i915-objs += i915_ioc32.o
nouveau-objs += nouveau_ioc32.o
endif endif
obj-m += drm.o obj-m += drm.o
@ -45,7 +52,6 @@ obj-$(CONFIG_DRM_R128) += r128.o
obj-$(CONFIG_DRM_RADEON)+= radeon.o obj-$(CONFIG_DRM_RADEON)+= radeon.o
obj-$(CONFIG_DRM_MGA) += mga.o obj-$(CONFIG_DRM_MGA) += mga.o
obj-$(CONFIG_DRM_I810) += i810.o obj-$(CONFIG_DRM_I810) += i810.o
obj-$(CONFIG_DRM_I830) += i830.o
obj-$(CONFIG_DRM_I915) += i915.o obj-$(CONFIG_DRM_I915) += i915.o
obj-$(CONFIG_DRM_SIS) += sis.o obj-$(CONFIG_DRM_SIS) += sis.o
obj-$(CONFIG_DRM_FFB) += ffb.o obj-$(CONFIG_DRM_FFB) += ffb.o
@ -53,4 +59,5 @@ obj-$(CONFIG_DRM_SAVAGE)+= savage.o
obj-$(CONFIG_DRM_VIA) += via.o obj-$(CONFIG_DRM_VIA) += via.o
obj-$(CONFIG_DRM_MACH64)+= mach64.o obj-$(CONFIG_DRM_MACH64)+= mach64.o
obj-$(CONFIG_DRM_NV) += nv.o obj-$(CONFIG_DRM_NV) += nv.o
obj-$(CONFIG_DRM_NOUVEAU) += nouveau.o
obj-$(CONFIG_DRM_XGI) += xgi.o obj-$(CONFIG_DRM_XGI) += xgi.o

View file

@ -1,6 +1,6 @@
************************************************************ ************************************************************
* For the very latest on DRI development, please see: * * For the very latest on DRI development, please see: *
* http://dri.sourceforge.net/ * * http://dri.freedesktop.org/ *
************************************************************ ************************************************************
The Direct Rendering Manager (drm) is a device-independent kernel-level The Direct Rendering Manager (drm) is a device-independent kernel-level
@ -23,24 +23,3 @@ ways:
4. The DRM is extensible via the use of small device-specific modules 4. The DRM is extensible via the use of small device-specific modules
that rely extensively on the API exported by the DRM module. that rely extensively on the API exported by the DRM module.
Documentation on the DRI is available from:
http://precisioninsight.com/piinsights.html
For specific information about kernel-level support, see:
The Direct Rendering Manager, Kernel Support for the Direct Rendering
Infrastructure
http://precisioninsight.com/dr/drm.html
Hardware Locking for the Direct Rendering Infrastructure
http://precisioninsight.com/dr/locking.html
A Security Analysis of the Direct Rendering Infrastructure
http://precisioninsight.com/dr/security.html
************************************************************
* For the very latest on DRI development, please see: *
* http://dri.sourceforge.net/ *
************************************************************

View file

@ -33,41 +33,25 @@
#include "drmP.h" #include "drmP.h"
#if PAGE_SIZE == 65536
# define ATI_PCIGART_TABLE_ORDER 0
# define ATI_PCIGART_TABLE_PAGES (1 << 0)
#elif PAGE_SIZE == 16384
# define ATI_PCIGART_TABLE_ORDER 1
# define ATI_PCIGART_TABLE_PAGES (1 << 1)
#elif PAGE_SIZE == 8192
# define ATI_PCIGART_TABLE_ORDER 2
# define ATI_PCIGART_TABLE_PAGES (1 << 2)
#elif PAGE_SIZE == 4096
# define ATI_PCIGART_TABLE_ORDER 3
# define ATI_PCIGART_TABLE_PAGES (1 << 3)
#else
# error - PAGE_SIZE not 64K, 16K, 8K or 4K
#endif
# define ATI_MAX_PCIGART_PAGES 8192 /**< 32 MB aperture, 4K pages */
# define ATI_PCIGART_PAGE_SIZE 4096 /**< PCI GART page size */ # define ATI_PCIGART_PAGE_SIZE 4096 /**< PCI GART page size */
static void *drm_ati_alloc_pcigart_table(void) static void *drm_ati_alloc_pcigart_table(int order)
{ {
unsigned long address; unsigned long address;
struct page *page; struct page *page;
int i; int i;
DRM_DEBUG("%s\n", __FUNCTION__);
DRM_DEBUG("%s: alloc %d order\n", __FUNCTION__, order);
address = __get_free_pages(GFP_KERNEL | __GFP_COMP, address = __get_free_pages(GFP_KERNEL | __GFP_COMP,
ATI_PCIGART_TABLE_ORDER); order);
if (address == 0UL) { if (address == 0UL) {
return NULL; return NULL;
} }
page = virt_to_page(address); page = virt_to_page(address);
for (i = 0; i < ATI_PCIGART_TABLE_PAGES; i++, page++) { for (i = 0; i < order; i++, page++) {
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15) #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)
get_page(page); get_page(page);
#endif #endif
@ -78,22 +62,23 @@ static void *drm_ati_alloc_pcigart_table(void)
return (void *)address; return (void *)address;
} }
static void drm_ati_free_pcigart_table(void *address) static void drm_ati_free_pcigart_table(void *address, int order)
{ {
struct page *page; struct page *page;
int i; int i;
int num_pages = 1 << order;
DRM_DEBUG("%s\n", __FUNCTION__); DRM_DEBUG("%s\n", __FUNCTION__);
page = virt_to_page((unsigned long)address); page = virt_to_page((unsigned long)address);
for (i = 0; i < ATI_PCIGART_TABLE_PAGES; i++, page++) { for (i = 0; i < num_pages; i++, page++) {
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15) #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)
__put_page(page); __put_page(page);
#endif #endif
ClearPageReserved(page); ClearPageReserved(page);
} }
free_pages((unsigned long)address, ATI_PCIGART_TABLE_ORDER); free_pages((unsigned long)address, order);
} }
int drm_ati_pcigart_cleanup(drm_device_t *dev, drm_ati_pcigart_info *gart_info) int drm_ati_pcigart_cleanup(drm_device_t *dev, drm_ati_pcigart_info *gart_info)
@ -101,6 +86,8 @@ int drm_ati_pcigart_cleanup(drm_device_t *dev, drm_ati_pcigart_info *gart_info)
drm_sg_mem_t *entry = dev->sg; drm_sg_mem_t *entry = dev->sg;
unsigned long pages; unsigned long pages;
int i; int i;
int order;
int num_pages, max_pages;
/* we need to support large memory configurations */ /* we need to support large memory configurations */
if (!entry) { if (!entry) {
@ -108,15 +95,19 @@ int drm_ati_pcigart_cleanup(drm_device_t *dev, drm_ati_pcigart_info *gart_info)
return 0; return 0;
} }
order = drm_order((gart_info->table_size + (PAGE_SIZE-1)) / PAGE_SIZE);
num_pages = 1 << order;
if (gart_info->bus_addr) { if (gart_info->bus_addr) {
if (gart_info->gart_table_location == DRM_ATI_GART_MAIN) { if (gart_info->gart_table_location == DRM_ATI_GART_MAIN) {
pci_unmap_single(dev->pdev, gart_info->bus_addr, pci_unmap_single(dev->pdev, gart_info->bus_addr,
ATI_PCIGART_TABLE_PAGES * PAGE_SIZE, num_pages * PAGE_SIZE,
PCI_DMA_TODEVICE); PCI_DMA_TODEVICE);
} }
pages = (entry->pages <= ATI_MAX_PCIGART_PAGES) max_pages = (gart_info->table_size / sizeof(u32));
? entry->pages : ATI_MAX_PCIGART_PAGES; pages = (entry->pages <= max_pages)
? entry->pages : max_pages;
for (i = 0; i < pages; i++) { for (i = 0; i < pages; i++) {
if (!entry->busaddr[i]) if (!entry->busaddr[i])
@ -132,7 +123,8 @@ int drm_ati_pcigart_cleanup(drm_device_t *dev, drm_ati_pcigart_info *gart_info)
if (gart_info->gart_table_location == DRM_ATI_GART_MAIN if (gart_info->gart_table_location == DRM_ATI_GART_MAIN
&& gart_info->addr) { && gart_info->addr) {
drm_ati_free_pcigart_table(gart_info->addr);
drm_ati_free_pcigart_table(gart_info->addr, order);
gart_info->addr = NULL; gart_info->addr = NULL;
} }
@ -147,6 +139,9 @@ int drm_ati_pcigart_init(drm_device_t *dev, drm_ati_pcigart_info *gart_info)
unsigned long pages; unsigned long pages;
u32 *pci_gart, page_base, bus_address = 0; u32 *pci_gart, page_base, bus_address = 0;
int i, j, ret = 0; int i, j, ret = 0;
int order;
int max_pages;
int num_pages;
if (!entry) { if (!entry) {
DRM_ERROR("no scatter/gather memory!\n"); DRM_ERROR("no scatter/gather memory!\n");
@ -156,7 +151,10 @@ int drm_ati_pcigart_init(drm_device_t *dev, drm_ati_pcigart_info *gart_info)
if (gart_info->gart_table_location == DRM_ATI_GART_MAIN) { if (gart_info->gart_table_location == DRM_ATI_GART_MAIN) {
DRM_DEBUG("PCI: no table in VRAM: using normal RAM\n"); DRM_DEBUG("PCI: no table in VRAM: using normal RAM\n");
address = drm_ati_alloc_pcigart_table(); order = drm_order((gart_info->table_size +
(PAGE_SIZE-1)) / PAGE_SIZE);
num_pages = 1 << order;
address = drm_ati_alloc_pcigart_table(order);
if (!address) { if (!address) {
DRM_ERROR("cannot allocate PCI GART page!\n"); DRM_ERROR("cannot allocate PCI GART page!\n");
goto done; goto done;
@ -168,11 +166,13 @@ int drm_ati_pcigart_init(drm_device_t *dev, drm_ati_pcigart_info *gart_info)
} }
bus_address = pci_map_single(dev->pdev, address, bus_address = pci_map_single(dev->pdev, address,
ATI_PCIGART_TABLE_PAGES * num_pages * PAGE_SIZE,
PAGE_SIZE, PCI_DMA_TODEVICE); PCI_DMA_TODEVICE);
if (bus_address == 0) { if (bus_address == 0) {
DRM_ERROR("unable to map PCIGART pages!\n"); DRM_ERROR("unable to map PCIGART pages!\n");
drm_ati_free_pcigart_table(address); order = drm_order((gart_info->table_size +
(PAGE_SIZE-1)) / PAGE_SIZE);
drm_ati_free_pcigart_table(address, order);
address = NULL; address = NULL;
goto done; goto done;
} }
@ -185,10 +185,11 @@ int drm_ati_pcigart_init(drm_device_t *dev, drm_ati_pcigart_info *gart_info)
pci_gart = (u32 *) address; pci_gart = (u32 *) address;
pages = (entry->pages <= ATI_MAX_PCIGART_PAGES) max_pages = (gart_info->table_size / sizeof(u32));
? entry->pages : ATI_MAX_PCIGART_PAGES; pages = (entry->pages <= max_pages)
? entry->pages : max_pages;
memset(pci_gart, 0, ATI_MAX_PCIGART_PAGES * sizeof(u32)); memset(pci_gart, 0, max_pages * sizeof(u32));
for (i = 0; i < pages; i++) { for (i = 0; i < pages; i++) {
/* we need to support large memory configurations */ /* we need to support large memory configurations */
@ -206,10 +207,18 @@ int drm_ati_pcigart_init(drm_device_t *dev, drm_ati_pcigart_info *gart_info)
page_base = (u32) entry->busaddr[i]; page_base = (u32) entry->busaddr[i];
for (j = 0; j < (PAGE_SIZE / ATI_PCIGART_PAGE_SIZE); j++) { for (j = 0; j < (PAGE_SIZE / ATI_PCIGART_PAGE_SIZE); j++) {
if (gart_info->is_pcie) switch(gart_info->gart_reg_if) {
case DRM_ATI_GART_IGP:
*pci_gart = cpu_to_le32((page_base) | 0xc);
break;
case DRM_ATI_GART_PCIE:
*pci_gart = cpu_to_le32((page_base >> 8) | 0xc); *pci_gart = cpu_to_le32((page_base >> 8) | 0xc);
else break;
default:
case DRM_ATI_GART_PCI:
*pci_gart = cpu_to_le32(page_base); *pci_gart = cpu_to_le32(page_base);
break;
}
pci_gart++; pci_gart++;
page_base += ATI_PCIGART_PAGE_SIZE; page_base += ATI_PCIGART_PAGE_SIZE;
} }

1
linux-core/drm.h Symbolic link
View file

@ -0,0 +1 @@
../shared-core/drm.h

View file

@ -67,23 +67,16 @@
#include <asm/mtrr.h> #include <asm/mtrr.h>
#endif #endif
#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE) #if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE)
#include <asm/agp.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/agp_backend.h> #include <linux/agp_backend.h>
#endif #endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,41)
#define HAS_WORKQUEUE 0
#else
#define HAS_WORKQUEUE 1
#endif
#if !HAS_WORKQUEUE
#include <linux/tqueue.h>
#else
#include <linux/workqueue.h> #include <linux/workqueue.h>
#endif
#include <linux/poll.h> #include <linux/poll.h>
#include <asm/pgalloc.h> #include <asm/pgalloc.h>
#include "drm.h" #include "drm.h"
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/idr.h>
#define __OS_HAS_AGP (defined(CONFIG_AGP) || (defined(CONFIG_AGP_MODULE) && defined(MODULE))) #define __OS_HAS_AGP (defined(CONFIG_AGP) || (defined(CONFIG_AGP_MODULE) && defined(MODULE)))
#define __OS_HAS_MTRR (defined(CONFIG_MTRR)) #define __OS_HAS_MTRR (defined(CONFIG_MTRR))
@ -308,19 +301,14 @@ typedef struct drm_devstate {
} drm_devstate_t; } drm_devstate_t;
typedef struct drm_magic_entry { typedef struct drm_magic_entry {
drm_hash_item_t hash_item;
struct list_head head; struct list_head head;
drm_hash_item_t hash_item;
struct drm_file *priv; struct drm_file *priv;
} drm_magic_entry_t; } drm_magic_entry_t;
typedef struct drm_magic_head {
struct drm_magic_entry *head;
struct drm_magic_entry *tail;
} drm_magic_head_t;
typedef struct drm_vma_entry { typedef struct drm_vma_entry {
struct list_head head;
struct vm_area_struct *vma; struct vm_area_struct *vma;
struct drm_vma_entry *next;
pid_t pid; pid_t pid;
} drm_vma_entry_t; } drm_vma_entry_t;
@ -419,23 +407,22 @@ typedef struct drm_file {
uid_t uid; uid_t uid;
drm_magic_t magic; drm_magic_t magic;
unsigned long ioctl_count; unsigned long ioctl_count;
struct drm_file *next; struct list_head lhead;
struct drm_file *prev;
struct drm_head *head; struct drm_head *head;
int remove_auth_on_close; int remove_auth_on_close;
unsigned long lock_count; unsigned long lock_count;
/* /*
* The user object hash table is global and resides in the * The user object hash table is global and resides in the
* drm_device structure. We protect the lists and hash tables with the * drm_device structure. We protect the lists and hash tables with the
* device struct_mutex. A bit coarse-grained but probably the best * device struct_mutex. A bit coarse-grained but probably the best
* option. * option.
*/ */
struct list_head refd_objects; struct list_head refd_objects;
struct list_head user_objects; struct list_head user_objects;
drm_open_hash_t refd_object_hash[_DRM_NO_REF_TYPES]; drm_open_hash_t refd_object_hash[_DRM_NO_REF_TYPES];
void *driver_priv; void *driver_priv;
} drm_file_t; } drm_file_t;
@ -466,6 +453,10 @@ typedef struct drm_lock_data {
struct file *filp; /**< File descr of lock holder (0=kernel) */ struct file *filp; /**< File descr of lock holder (0=kernel) */
wait_queue_head_t lock_queue; /**< Queue of blocked processes */ wait_queue_head_t lock_queue; /**< Queue of blocked processes */
unsigned long lock_time; /**< Time of last lock in jiffies */ unsigned long lock_time; /**< Time of last lock in jiffies */
spinlock_t spinlock;
uint32_t kernel_waiters;
uint32_t user_waiters;
int idle_has_lock;
} drm_lock_data_t; } drm_lock_data_t;
/** /**
@ -497,8 +488,7 @@ typedef struct drm_agp_mem {
DRM_AGP_MEM *memory; DRM_AGP_MEM *memory;
unsigned long bound; /**< address */ unsigned long bound; /**< address */
int pages; int pages;
struct drm_agp_mem *prev; /**< previous entry */ struct list_head head;
struct drm_agp_mem *next; /**< next entry */
} drm_agp_mem_t; } drm_agp_mem_t;
/** /**
@ -508,7 +498,7 @@ typedef struct drm_agp_mem {
*/ */
typedef struct drm_agp_head { typedef struct drm_agp_head {
DRM_AGP_KERN agp_info; /**< AGP device information */ DRM_AGP_KERN agp_info; /**< AGP device information */
drm_agp_mem_t *memory; /**< memory entries */ struct list_head memory;
unsigned long mode; /**< AGP mode */ unsigned long mode; /**< AGP mode */
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,11) #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,11)
struct agp_bridge_data *bridge; struct agp_bridge_data *bridge;
@ -538,7 +528,7 @@ typedef struct drm_sigdata {
} drm_sigdata_t; } drm_sigdata_t;
/* /*
* Generic memory manager structs * Generic memory manager structs
*/ */
@ -548,12 +538,13 @@ typedef struct drm_mm_node {
int free; int free;
unsigned long start; unsigned long start;
unsigned long size; unsigned long size;
struct drm_mm *mm; struct drm_mm *mm;
void *private; void *private;
} drm_mm_node_t; } drm_mm_node_t;
typedef struct drm_mm { typedef struct drm_mm {
drm_mm_node_t root_node; struct list_head fl_entry;
struct list_head ml_entry;
} drm_mm_t; } drm_mm_t;
@ -565,7 +556,7 @@ typedef struct drm_map_list {
drm_hash_item_t hash; drm_hash_item_t hash;
drm_map_t *map; /**< mapping */ drm_map_t *map; /**< mapping */
drm_u64_t user_token; drm_u64_t user_token;
drm_mm_node_t *file_offset_node; drm_mm_node_t *file_offset_node;
} drm_map_list_t; } drm_map_list_t;
typedef drm_map_t drm_local_map_t; typedef drm_map_t drm_local_map_t;
@ -579,6 +570,10 @@ typedef struct drm_ctx_list {
drm_file_t *tag; /**< associated fd private data */ drm_file_t *tag; /**< associated fd private data */
} drm_ctx_list_t; } drm_ctx_list_t;
struct drm_ctx_sarea_list {
drm_map_t *map;
};
typedef struct drm_vbl_sig { typedef struct drm_vbl_sig {
struct list_head head; struct list_head head;
unsigned int sequence; unsigned int sequence;
@ -590,86 +585,24 @@ typedef struct drm_vbl_sig {
#define DRM_ATI_GART_MAIN 1 #define DRM_ATI_GART_MAIN 1
#define DRM_ATI_GART_FB 2 #define DRM_ATI_GART_FB 2
#define DRM_ATI_GART_PCI 1
#define DRM_ATI_GART_PCIE 2
#define DRM_ATI_GART_IGP 3
typedef struct ati_pcigart_info { typedef struct ati_pcigart_info {
int gart_table_location; int gart_table_location;
int is_pcie; int gart_reg_if;
void *addr; void *addr;
dma_addr_t bus_addr; dma_addr_t bus_addr;
drm_local_map_t mapping; drm_local_map_t mapping;
int table_size;
} drm_ati_pcigart_info; } drm_ati_pcigart_info;
/* struct drm_drawable_list {
* User space objects and their references. drm_drawable_info_t info;
*/ };
#define drm_user_object_entry(_ptr, _type, _member) container_of(_ptr, _type, _member)
typedef enum {
drm_fence_type,
drm_buffer_type,
drm_ttm_type
/*
* Add other user space object types here.
*/
} drm_object_type_t;
/*
* A user object is a structure that helps the drm give out user handles
* to kernel internal objects and to keep track of these objects so that
* they can be destroyed, for example when the user space process exits.
* Designed to be accessible using a user space 32-bit handle.
*/
typedef struct drm_user_object{
drm_hash_item_t hash;
struct list_head list;
drm_object_type_t type;
atomic_t refcount;
int shareable;
drm_file_t *owner;
void (*ref_struct_locked) (drm_file_t *priv, struct drm_user_object *obj,
drm_ref_t ref_action);
void (*unref)(drm_file_t *priv, struct drm_user_object *obj,
drm_ref_t unref_action);
void (*remove)(drm_file_t *priv, struct drm_user_object *obj);
} drm_user_object_t;
/*
* A ref object is a structure which is used to
* keep track of references to user objects and to keep track of these
* references so that they can be destroyed for example when the user space
* process exits. Designed to be accessible using a pointer to the _user_ object.
*/
typedef struct drm_ref_object {
drm_hash_item_t hash;
struct list_head list;
atomic_t refcount;
drm_ref_t unref_action;
} drm_ref_object_t;
#include "drm_ttm.h"
/*
* buffer object driver
*/
typedef struct drm_bo_driver{
int cached[DRM_BO_MEM_TYPES];
drm_local_map_t *iomap[DRM_BO_MEM_TYPES];
drm_ttm_backend_t *(*create_ttm_backend_entry)
(struct drm_device *dev);
int (*fence_type)(uint32_t flags, uint32_t *class, uint32_t *type);
int (*invalidate_caches)(struct drm_device *dev, uint32_t flags);
} drm_bo_driver_t;
#include "drm_objects.h"
/** /**
* DRM driver structure. This structure represent the common code for * DRM driver structure. This structure represent the common code for
@ -719,13 +652,15 @@ struct drm_driver {
void (*reclaim_buffers) (struct drm_device *dev, struct file * filp); void (*reclaim_buffers) (struct drm_device *dev, struct file * filp);
void (*reclaim_buffers_locked) (struct drm_device *dev, void (*reclaim_buffers_locked) (struct drm_device *dev,
struct file * filp); struct file * filp);
void (*reclaim_buffers_idlelocked) (struct drm_device *dev,
struct file * filp);
unsigned long (*get_map_ofs) (drm_map_t * map); unsigned long (*get_map_ofs) (drm_map_t * map);
unsigned long (*get_reg_ofs) (struct drm_device * dev); unsigned long (*get_reg_ofs) (struct drm_device * dev);
void (*set_version) (struct drm_device * dev, drm_set_version_t * sv); void (*set_version) (struct drm_device * dev, drm_set_version_t * sv);
struct drm_fence_driver *fence_driver; struct drm_fence_driver *fence_driver;
struct drm_bo_driver *bo_driver; struct drm_bo_driver *bo_driver;
int major; int major;
int minor; int minor;
int patchlevel; int patchlevel;
@ -755,70 +690,6 @@ typedef struct drm_head {
struct class_device *dev_class; struct class_device *dev_class;
} drm_head_t; } drm_head_t;
typedef struct drm_cache {
/*
* Memory caches
*/
kmem_cache_t *mm;
kmem_cache_t *fence_object;
} drm_cache_t;
typedef struct drm_fence_driver{
int no_types;
uint32_t wrap_diff;
uint32_t flush_diff;
uint32_t sequence_mask;
int lazy_capable;
int (*emit) (struct drm_device *dev, uint32_t flags,
uint32_t *breadcrumb,
uint32_t *native_type);
void (*poke_flush) (struct drm_device *dev);
} drm_fence_driver_t;
#define _DRM_FENCE_TYPE_EXE 0x00
typedef struct drm_fence_manager{
int initialized;
rwlock_t lock;
/*
* The list below should be maintained in sequence order and
* access is protected by the above spinlock.
*/
struct list_head ring;
struct list_head *fence_types[32];
volatile uint32_t pending_flush;
wait_queue_head_t fence_queue;
int pending_exe_flush;
uint32_t last_exe_flush;
uint32_t exe_flush_sequence;
atomic_t count;
} drm_fence_manager_t;
typedef struct drm_buffer_manager{
struct mutex init_mutex;
int nice_mode;
int initialized;
drm_file_t *last_to_validate;
int has_type[DRM_BO_MEM_TYPES];
int use_type[DRM_BO_MEM_TYPES];
drm_mm_t manager[DRM_BO_MEM_TYPES];
struct list_head lru[DRM_BO_MEM_TYPES];
struct list_head pinned[DRM_BO_MEM_TYPES];
struct list_head unfenced;
struct list_head ddestroy;
struct work_struct wq;
uint32_t fence_type;
unsigned long cur_pages;
atomic_t count;
} drm_buffer_manager_t;
/** /**
* DRM device structure. This structure represent a complete card that * DRM device structure. This structure represent a complete card that
@ -856,32 +727,30 @@ typedef struct drm_device {
/** \name Authentication */ /** \name Authentication */
/*@{ */ /*@{ */
drm_file_t *file_first; /**< file list head */ struct list_head filelist;
drm_file_t *file_last; /**< file list tail */
drm_open_hash_t magiclist; drm_open_hash_t magiclist;
struct list_head magicfree; struct list_head magicfree;
/*@} */ /*@} */
/** \name Memory management */ /** \name Memory management */
/*@{ */ /*@{ */
drm_map_list_t *maplist; /**< Linked list of regions */ struct list_head maplist; /**< Linked list of regions */
int map_count; /**< Number of mappable regions */ int map_count; /**< Number of mappable regions */
drm_open_hash_t map_hash; /**< User token hash table for maps */ drm_open_hash_t map_hash; /**< User token hash table for maps */
drm_mm_t offset_manager; /**< User token manager */ drm_mm_t offset_manager; /**< User token manager */
drm_open_hash_t object_hash; /**< User token hash table for objects */ drm_open_hash_t object_hash; /**< User token hash table for objects */
struct address_space *dev_mapping; /**< For unmap_mapping_range() */ struct address_space *dev_mapping; /**< For unmap_mapping_range() */
struct page *ttm_dummy_page; struct page *ttm_dummy_page;
/** \name Context handle management */ /** \name Context handle management */
/*@{ */ /*@{ */
drm_ctx_list_t *ctxlist; /**< Linked list of context handles */ struct list_head ctxlist; /**< Linked list of context handles */
int ctx_count; /**< Number of context handles */ int ctx_count; /**< Number of context handles */
struct mutex ctxlist_mutex; /**< For ctxlist */ struct mutex ctxlist_mutex; /**< For ctxlist */
drm_map_t **context_sareas; /**< per-context SAREA's */ struct idr ctx_idr;
int max_context;
drm_vma_entry_t *vmalist; /**< List of vmas (for debugging) */ struct list_head vmalist; /**< List of vmas (for debugging) */
drm_lock_data_t lock; /**< Information on hardware lock */ drm_lock_data_t lock; /**< Information on hardware lock */
/*@} */ /*@} */
@ -908,11 +777,8 @@ typedef struct drm_device {
unsigned long last_switch; /**< jiffies at last context switch */ unsigned long last_switch; /**< jiffies at last context switch */
/*@} */ /*@} */
#if !HAS_WORKQUEUE
struct tq_struct tq;
#else
struct work_struct work; struct work_struct work;
#endif
/** \name VBLANK IRQ support */ /** \name VBLANK IRQ support */
/*@{ */ /*@{ */
@ -920,8 +786,8 @@ typedef struct drm_device {
atomic_t vbl_received; atomic_t vbl_received;
atomic_t vbl_received2; /**< number of secondary VBLANK interrupts */ atomic_t vbl_received2; /**< number of secondary VBLANK interrupts */
spinlock_t vbl_lock; spinlock_t vbl_lock;
drm_vbl_sig_t vbl_sigs; /**< signal list to send on VBLANK */ struct list_head vbl_sigs; /**< signal list to send on VBLANK */
drm_vbl_sig_t vbl_sigs2; /**< signals to send on secondary VBLANK */ struct list_head vbl_sigs2; /**< signals to send on secondary VBLANK */
unsigned int vbl_pending; unsigned int vbl_pending;
spinlock_t tasklet_lock; /**< For drm_locked_tasklet */ spinlock_t tasklet_lock; /**< For drm_locked_tasklet */
void (*locked_tasklet_func)(struct drm_device *dev); void (*locked_tasklet_func)(struct drm_device *dev);
@ -940,14 +806,9 @@ typedef struct drm_device {
int pci_vendor; /**< PCI vendor id */ int pci_vendor; /**< PCI vendor id */
int pci_device; /**< PCI device id */ int pci_device; /**< PCI device id */
#ifdef __alpha__ #ifdef __alpha__
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,3)
struct pci_controler *hose;
#else
struct pci_controller *hose; struct pci_controller *hose;
#endif
#endif #endif
drm_sg_mem_t *sg; /**< Scatter gather memory */ drm_sg_mem_t *sg; /**< Scatter gather memory */
unsigned long *ctx_bitmap; /**< context bitmap */
void *dev_private; /**< device private data */ void *dev_private; /**< device private data */
drm_sigdata_t sigdata; /**< For block_all_signals */ drm_sigdata_t sigdata; /**< For block_all_signals */
sigset_t sigmask; sigset_t sigmask;
@ -959,85 +820,23 @@ typedef struct drm_device {
drm_fence_manager_t fm; drm_fence_manager_t fm;
drm_buffer_manager_t bm; drm_buffer_manager_t bm;
/** \name Drawable information */ /** \name Drawable information */
/*@{ */ /*@{ */
spinlock_t drw_lock; spinlock_t drw_lock;
unsigned int drw_bitfield_length; struct idr drw_idr;
u32 *drw_bitfield;
unsigned int drw_info_length;
drm_drawable_info_t **drw_info;
/*@} */ /*@} */
} drm_device_t; } drm_device_t;
#if __OS_HAS_AGP #if __OS_HAS_AGP
typedef struct drm_agp_ttm_priv { typedef struct drm_agp_ttm_backend {
drm_ttm_backend_t backend;
DRM_AGP_MEM *mem; DRM_AGP_MEM *mem;
struct agp_bridge_data *bridge; struct agp_bridge_data *bridge;
unsigned alloc_type;
unsigned cached_type;
unsigned uncached_type;
int populated; int populated;
} drm_agp_ttm_priv; } drm_agp_ttm_backend_t;
#endif #endif
typedef struct drm_fence_object{
drm_user_object_t base;
atomic_t usage;
/*
* The below three fields are protected by the fence manager spinlock.
*/
struct list_head ring;
int class;
uint32_t native_type;
uint32_t type;
uint32_t signaled;
uint32_t sequence;
uint32_t flush_mask;
uint32_t submitted_flush;
} drm_fence_object_t;
typedef struct drm_buffer_object{
drm_device_t *dev;
drm_user_object_t base;
/*
* If there is a possibility that the usage variable is zero,
* then dev->struct_mutext should be locked before incrementing it.
*/
atomic_t usage;
drm_ttm_object_t *ttm_object;
drm_ttm_t *ttm;
unsigned long num_pages;
unsigned long buffer_start;
drm_bo_type_t type;
unsigned long offset;
uint32_t page_alignment;
atomic_t mapped;
uint32_t flags;
uint32_t mask;
drm_mm_node_t *node_ttm; /* MM node for on-card RAM */
drm_mm_node_t *node_card; /* MM node for ttm*/
struct list_head lru_ttm; /* LRU for the ttm pages*/
struct list_head lru_card; /* For memory types with on-card RAM */
struct list_head ddestroy;
uint32_t fence_type;
uint32_t fence_class;
drm_fence_object_t *fence;
uint32_t priv_flags;
wait_queue_head_t event_queue;
struct mutex mutex;
} drm_buffer_object_t;
#define _DRM_BO_FLAG_UNFENCED 0x00000001
#define _DRM_BO_FLAG_EVICTED 0x00000002
static __inline__ int drm_core_check_feature(struct drm_device *dev, static __inline__ int drm_core_check_feature(struct drm_device *dev,
int feature) int feature)
@ -1046,7 +845,7 @@ static __inline__ int drm_core_check_feature(struct drm_device *dev,
} }
#ifdef __alpha__ #ifdef __alpha__
#define drm_get_pci_domain(dev) dev->hose->bus->number #define drm_get_pci_domain(dev) dev->hose->index
#else #else
#define drm_get_pci_domain(dev) 0 #define drm_get_pci_domain(dev) 0
#endif #endif
@ -1094,6 +893,7 @@ static inline int drm_mtrr_del(int handle, unsigned long offset,
} }
#define drm_core_has_MTRR(dev) (0) #define drm_core_has_MTRR(dev) (0)
#define DRM_MTRR_WC 0
#endif #endif
@ -1145,9 +945,10 @@ extern void drm_free_memctl(size_t size);
extern int drm_alloc_memctl(size_t size); extern int drm_alloc_memctl(size_t size);
extern void drm_query_memctl(drm_u64_t *cur_used, extern void drm_query_memctl(drm_u64_t *cur_used,
drm_u64_t *low_threshold, drm_u64_t *low_threshold,
drm_u64_t *high_threshold); drm_u64_t *high_threshold);
extern void drm_init_memctl(size_t low_threshold, extern void drm_init_memctl(size_t low_threshold,
size_t high_threshold); size_t high_threshold,
size_t unit_size);
/* Misc. IOCTL support (drm_ioctl.h) */ /* Misc. IOCTL support (drm_ioctl.h) */
extern int drm_irq_by_busid(struct inode *inode, struct file *filp, extern int drm_irq_by_busid(struct inode *inode, struct file *filp,
@ -1201,6 +1002,7 @@ extern int drm_update_drawable_info(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg); unsigned int cmd, unsigned long arg);
extern drm_drawable_info_t *drm_get_drawable_info(drm_device_t *dev, extern drm_drawable_info_t *drm_get_drawable_info(drm_device_t *dev,
drm_drawable_t id); drm_drawable_t id);
extern void drm_drawable_free_all(drm_device_t *dev);
/* Authentication IOCTL support (drm_auth.h) */ /* Authentication IOCTL support (drm_auth.h) */
extern int drm_getmagic(struct inode *inode, struct file *filp, extern int drm_getmagic(struct inode *inode, struct file *filp,
@ -1213,12 +1015,14 @@ extern int drm_lock(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg); unsigned int cmd, unsigned long arg);
extern int drm_unlock(struct inode *inode, struct file *filp, extern int drm_unlock(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg); unsigned int cmd, unsigned long arg);
extern int drm_lock_take(__volatile__ unsigned int *lock, unsigned int context); extern int drm_lock_take(drm_lock_data_t *lock_data, unsigned int context);
extern int drm_lock_free(drm_device_t * dev, extern int drm_lock_free(drm_lock_data_t *lock_data, unsigned int context);
__volatile__ unsigned int *lock, unsigned int context); extern void drm_idlelock_take(drm_lock_data_t *lock_data);
extern void drm_idlelock_release(drm_lock_data_t *lock_data);
/* /*
* These are exported to drivers so that they can implement fencing using * These are exported to drivers so that they can implement fencing using
* DMA quiscent + idle. DMA quiescent usually requires the hardware lock. * DMA quiscent + idle. DMA quiescent usually requires the hardware lock.
*/ */
extern int drm_i_have_hw_lock(struct file *filp); extern int drm_i_have_hw_lock(struct file *filp);
@ -1308,8 +1112,7 @@ extern DRM_AGP_MEM *drm_agp_allocate_memory(struct agp_bridge_data *bridge, size
extern int drm_agp_free_memory(DRM_AGP_MEM * handle); extern int drm_agp_free_memory(DRM_AGP_MEM * handle);
extern int drm_agp_bind_memory(DRM_AGP_MEM * handle, off_t start); extern int drm_agp_bind_memory(DRM_AGP_MEM * handle, off_t start);
extern int drm_agp_unbind_memory(DRM_AGP_MEM * handle); extern int drm_agp_unbind_memory(DRM_AGP_MEM * handle);
extern drm_ttm_backend_t *drm_agp_init_ttm(struct drm_device *dev, extern drm_ttm_backend_t *drm_agp_init_ttm(struct drm_device *dev);
drm_ttm_backend_t *backend);
/* Stub support (drm_stub.h) */ /* Stub support (drm_stub.h) */
extern int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent, extern int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
struct drm_driver *driver); struct drm_driver *driver);
@ -1318,10 +1121,11 @@ extern int drm_put_head(drm_head_t * head);
extern unsigned int drm_debug; /* 1 to enable debug output */ extern unsigned int drm_debug; /* 1 to enable debug output */
extern unsigned int drm_cards_limit; extern unsigned int drm_cards_limit;
extern drm_head_t **drm_heads; extern drm_head_t **drm_heads;
extern drm_cache_t drm_cache;
extern struct drm_sysfs_class *drm_class; extern struct drm_sysfs_class *drm_class;
extern struct proc_dir_entry *drm_proc_root; extern struct proc_dir_entry *drm_proc_root;
extern drm_local_map_t *drm_getsarea(struct drm_device *dev);
/* Proc support (drm_proc.h) */ /* Proc support (drm_proc.h) */
extern int drm_proc_init(drm_device_t * dev, extern int drm_proc_init(drm_device_t * dev,
int minor, int minor,
@ -1356,14 +1160,14 @@ extern struct class_device *drm_sysfs_device_add(struct drm_sysfs_class *cs,
drm_head_t * head); drm_head_t * head);
extern void drm_sysfs_device_remove(struct class_device *class_dev); extern void drm_sysfs_device_remove(struct class_device *class_dev);
/* /*
* Basic memory manager support (drm_mm.c) * Basic memory manager support (drm_mm.c)
*/ */
extern drm_mm_node_t * drm_mm_get_block(drm_mm_node_t * parent, unsigned long size, extern drm_mm_node_t * drm_mm_get_block(drm_mm_node_t * parent, unsigned long size,
unsigned alignment); unsigned alignment);
extern void drm_mm_put_block(drm_mm_node_t *cur); extern void drm_mm_put_block(drm_mm_node_t *cur);
extern drm_mm_node_t *drm_mm_search_free(const drm_mm_t *mm, unsigned long size, extern drm_mm_node_t *drm_mm_search_free(const drm_mm_t *mm, unsigned long size,
unsigned alignment, int best_match); unsigned alignment, int best_match);
extern int drm_mm_init(drm_mm_t *mm, unsigned long start, unsigned long size); extern int drm_mm_init(drm_mm_t *mm, unsigned long start, unsigned long size);
extern void drm_mm_takedown(drm_mm_t *mm); extern void drm_mm_takedown(drm_mm_t *mm);
@ -1376,134 +1180,15 @@ static inline drm_mm_t *drm_get_mm(drm_mm_node_t *block)
{ {
return block->mm; return block->mm;
} }
/* extern void drm_core_ioremap(struct drm_map *map, struct drm_device *dev);
* User space object bookkeeping (drm_object.c) extern void drm_core_ioremapfree(struct drm_map *map, struct drm_device *dev);
*/
/*
* Must be called with the struct_mutex held.
*/
extern int drm_add_user_object(drm_file_t *priv, drm_user_object_t *item,
/*
* Must be called with the struct_mutex held.
*/
int shareable);
extern drm_user_object_t *drm_lookup_user_object(drm_file_t *priv, uint32_t key);
/*
* Must be called with the struct_mutex held.
* If "item" has been obtained by a call to drm_lookup_user_object. You may not
* release the struct_mutex before calling drm_remove_ref_object.
* This function may temporarily release the struct_mutex.
*/
extern int drm_remove_user_object(drm_file_t *priv, drm_user_object_t *item);
/*
* Must be called with the struct_mutex held. May temporarily release it.
*/
extern int drm_add_ref_object(drm_file_t *priv, drm_user_object_t *referenced_object,
drm_ref_t ref_action);
/*
* Must be called with the struct_mutex held.
*/
drm_ref_object_t *drm_lookup_ref_object(drm_file_t *priv,
drm_user_object_t *referenced_object,
drm_ref_t ref_action);
/*
* Must be called with the struct_mutex held.
* If "item" has been obtained by a call to drm_lookup_ref_object. You may not
* release the struct_mutex before calling drm_remove_ref_object.
* This function may temporarily release the struct_mutex.
*/
extern void drm_remove_ref_object(drm_file_t *priv, drm_ref_object_t *item);
extern int drm_user_object_ref(drm_file_t *priv, uint32_t user_token, drm_object_type_t type,
drm_user_object_t **object);
extern int drm_user_object_unref(drm_file_t *priv, uint32_t user_token, drm_object_type_t type);
/*
* fence objects (drm_fence.c)
*/
extern void drm_fence_handler(drm_device_t *dev, uint32_t breadcrumb, uint32_t type);
extern void drm_fence_manager_init(drm_device_t *dev);
extern void drm_fence_manager_takedown(drm_device_t *dev);
extern void drm_fence_flush_old(drm_device_t *dev, uint32_t sequence);
extern int drm_fence_object_flush(drm_device_t * dev,
volatile drm_fence_object_t * fence,
uint32_t type);
extern int drm_fence_object_signaled(volatile drm_fence_object_t * fence,
uint32_t type);
extern void drm_fence_usage_deref_locked(drm_device_t * dev,
drm_fence_object_t * fence);
extern void drm_fence_usage_deref_unlocked(drm_device_t * dev,
drm_fence_object_t * fence);
extern int drm_fence_object_wait(drm_device_t * dev,
volatile drm_fence_object_t * fence,
int lazy, int ignore_signals, uint32_t mask);
extern int drm_fence_object_create(drm_device_t *dev, uint32_t type,
uint32_t fence_flags,
drm_fence_object_t **c_fence);
extern int drm_fence_add_user_object(drm_file_t *priv,
drm_fence_object_t *fence,
int shareable);
extern int drm_fence_ioctl(DRM_IOCTL_ARGS);
/*
* buffer objects (drm_bo.c)
*/
extern int drm_bo_ioctl(DRM_IOCTL_ARGS);
extern int drm_mm_init_ioctl(DRM_IOCTL_ARGS);
extern int drm_bo_driver_finish(drm_device_t *dev);
extern int drm_bo_driver_init(drm_device_t *dev);
extern int drm_fence_buffer_objects(drm_file_t * priv,
struct list_head *list,
uint32_t fence_flags,
drm_fence_object_t *fence,
drm_fence_object_t **used_fence);
/* Inline replacements for DRM_IOREMAP macros */
static __inline__ void drm_core_ioremap(struct drm_map *map,
struct drm_device *dev)
{
map->handle = drm_ioremap(map->offset, map->size, dev);
}
static __inline__ void drm_core_ioremap_nocache(struct drm_map *map,
struct drm_device *dev)
{
map->handle = drm_ioremap_nocache(map->offset, map->size, dev);
}
static __inline__ void drm_core_ioremapfree(struct drm_map *map,
struct drm_device *dev)
{
if (map->handle && map->size)
drm_ioremapfree(map->handle, map->size, dev);
}
static __inline__ struct drm_map *drm_core_findmap(struct drm_device *dev, static __inline__ struct drm_map *drm_core_findmap(struct drm_device *dev,
unsigned int token) unsigned int token)
{ {
drm_map_list_t *_entry; drm_map_list_t *_entry;
list_for_each_entry(_entry, &dev->maplist->head, head) list_for_each_entry(_entry, &dev->maplist, head)
if (_entry->user_token == token) if (_entry->user_token == token)
return _entry->map; return _entry->map;
return NULL; return NULL;
@ -1513,7 +1198,7 @@ static __inline__ int drm_device_is_agp(drm_device_t *dev)
{ {
if ( dev->driver->device_is_agp != NULL ) { if ( dev->driver->device_is_agp != NULL ) {
int err = (*dev->driver->device_is_agp)( dev ); int err = (*dev->driver->device_is_agp)( dev );
if (err != 2) { if (err != 2) {
return err; return err;
} }
@ -1581,25 +1266,6 @@ static inline void drm_ctl_free(void *pt, size_t size, int area)
drm_free_memctl(size); drm_free_memctl(size);
} }
static inline void *drm_ctl_cache_alloc(kmem_cache_t *cache, size_t size,
int flags)
{
void *ret;
if (drm_alloc_memctl(size))
return NULL;
ret = kmem_cache_alloc(cache, flags);
if (!ret)
drm_free_memctl(size);
return ret;
}
static inline void drm_ctl_cache_free(kmem_cache_t *cache, size_t size,
void *obj)
{
kmem_cache_free(cache, obj);
drm_free_memctl(size);
}
/*@}*/ /*@}*/
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */

View file

@ -106,10 +106,6 @@ int drm_agp_acquire(drm_device_t * dev)
return -ENODEV; return -ENODEV;
if (dev->agp->acquired) if (dev->agp->acquired)
return -EBUSY; return -EBUSY;
#ifndef VMAP_4_ARGS
if (dev->agp->cant_use_aperture)
return -EINVAL;
#endif
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,11) #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,11)
if ((retcode = agp_backend_acquire())) if ((retcode = agp_backend_acquire()))
return retcode; return retcode;
@ -253,11 +249,7 @@ int drm_agp_alloc(drm_device_t *dev, drm_agp_buffer_t *request)
entry->memory = memory; entry->memory = memory;
entry->bound = 0; entry->bound = 0;
entry->pages = pages; entry->pages = pages;
entry->prev = NULL; list_add(&entry->head, &dev->agp->memory);
entry->next = dev->agp->memory;
if (dev->agp->memory)
dev->agp->memory->prev = entry;
dev->agp->memory = entry;
request->handle = entry->handle; request->handle = entry->handle;
request->physical = memory->physical; request->physical = memory->physical;
@ -284,10 +276,12 @@ int drm_agp_alloc_ioctl(struct inode *inode, struct file *filp,
return err; return err;
if (copy_to_user(argp, &request, sizeof(request))) { if (copy_to_user(argp, &request, sizeof(request))) {
drm_agp_mem_t *entry = dev->agp->memory; drm_agp_mem_t *entry;
list_for_each_entry(entry, &dev->agp->memory, head) {
dev->agp->memory = entry->next; if (entry->handle == request.handle)
dev->agp->memory->prev = NULL; break;
}
list_del(&entry->head);
drm_free_agp(entry->memory, entry->pages); drm_free_agp(entry->memory, entry->pages);
drm_free(entry, sizeof(*entry), DRM_MEM_AGPLISTS); drm_free(entry, sizeof(*entry), DRM_MEM_AGPLISTS);
return -EFAULT; return -EFAULT;
@ -310,7 +304,7 @@ static drm_agp_mem_t *drm_agp_lookup_entry(drm_device_t * dev,
{ {
drm_agp_mem_t *entry; drm_agp_mem_t *entry;
for (entry = dev->agp->memory; entry; entry = entry->next) { list_for_each_entry(entry, &dev->agp->memory, head) {
if (entry->handle == handle) if (entry->handle == handle)
return entry; return entry;
} }
@ -439,13 +433,7 @@ int drm_agp_free(drm_device_t *dev, drm_agp_buffer_t *request)
if (entry->bound) if (entry->bound)
drm_unbind_agp(entry->memory); drm_unbind_agp(entry->memory);
if (entry->prev) list_del(&entry->head);
entry->prev->next = entry->next;
else
dev->agp->memory = entry->next;
if (entry->next)
entry->next->prev = entry->prev;
drm_free_agp(entry->memory, entry->pages); drm_free_agp(entry->memory, entry->pages);
drm_free(entry, sizeof(*entry), DRM_MEM_AGPLISTS); drm_free(entry, sizeof(*entry), DRM_MEM_AGPLISTS);
@ -506,7 +494,7 @@ drm_agp_head_t *drm_agp_init(drm_device_t *dev)
drm_free(head, sizeof(*head), DRM_MEM_AGPLISTS); drm_free(head, sizeof(*head), DRM_MEM_AGPLISTS);
return NULL; return NULL;
} }
head->memory = NULL; INIT_LIST_HEAD(&head->memory);
head->cant_use_aperture = head->agp_info.cant_use_aperture; head->cant_use_aperture = head->agp_info.cant_use_aperture;
head->page_mask = head->agp_info.page_mask; head->page_mask = head->agp_info.page_mask;
return head; return head;
@ -563,16 +551,19 @@ int drm_agp_unbind_memory(DRM_AGP_MEM * handle)
#define AGP_USER_MEMORY (AGP_USER_TYPES) #define AGP_USER_MEMORY (AGP_USER_TYPES)
#define AGP_USER_CACHED_MEMORY (AGP_USER_TYPES + 1) #define AGP_USER_CACHED_MEMORY (AGP_USER_TYPES + 1)
#endif #endif
#define AGP_REQUIRED_MAJOR 0
#define AGP_REQUIRED_MINOR 102
static int drm_agp_needs_unbind_cache_adjust(drm_ttm_backend_t *backend) { static int drm_agp_needs_unbind_cache_adjust(drm_ttm_backend_t *backend) {
return ((backend->flags & DRM_BE_FLAG_BOUND_CACHED) ? 0 : 1); return ((backend->flags & DRM_BE_FLAG_BOUND_CACHED) ? 0 : 1);
} }
static int drm_agp_populate(drm_ttm_backend_t *backend, unsigned long num_pages, static int drm_agp_populate(drm_ttm_backend_t *backend, unsigned long num_pages,
struct page **pages) { struct page **pages) {
drm_agp_ttm_priv *agp_priv = (drm_agp_ttm_priv *) backend->private; drm_agp_ttm_backend_t *agp_be =
container_of(backend, drm_agp_ttm_backend_t, backend);
struct page **cur_page, **last_page = pages + num_pages; struct page **cur_page, **last_page = pages + num_pages;
DRM_AGP_MEM *mem; DRM_AGP_MEM *mem;
@ -581,9 +572,9 @@ static int drm_agp_populate(drm_ttm_backend_t *backend, unsigned long num_pages,
DRM_DEBUG("drm_agp_populate_ttm\n"); DRM_DEBUG("drm_agp_populate_ttm\n");
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,11) #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,11)
mem = drm_agp_allocate_memory(num_pages, agp_priv->alloc_type); mem = drm_agp_allocate_memory(num_pages, AGP_USER_MEMORY);
#else #else
mem = drm_agp_allocate_memory(agp_priv->bridge, num_pages, agp_priv->alloc_type); mem = drm_agp_allocate_memory(agp_be->bridge, num_pages, AGP_USER_MEMORY);
#endif #endif
if (!mem) { if (!mem) {
drm_free_memctl(num_pages *sizeof(void *)); drm_free_memctl(num_pages *sizeof(void *));
@ -595,118 +586,122 @@ static int drm_agp_populate(drm_ttm_backend_t *backend, unsigned long num_pages,
for (cur_page = pages; cur_page < last_page; ++cur_page) { for (cur_page = pages; cur_page < last_page; ++cur_page) {
mem->memory[mem->page_count++] = phys_to_gart(page_to_phys(*cur_page)); mem->memory[mem->page_count++] = phys_to_gart(page_to_phys(*cur_page));
} }
agp_priv->mem = mem; agp_be->mem = mem;
return 0; return 0;
} }
static int drm_agp_bind_ttm(drm_ttm_backend_t *backend, static int drm_agp_bind_ttm(drm_ttm_backend_t *backend,
unsigned long offset, unsigned long offset,
int cached) int cached)
{ {
drm_agp_ttm_priv *agp_priv = (drm_agp_ttm_priv *) backend->private; drm_agp_ttm_backend_t *agp_be =
DRM_AGP_MEM *mem = agp_priv->mem; container_of(backend, drm_agp_ttm_backend_t, backend);
DRM_AGP_MEM *mem = agp_be->mem;
int ret; int ret;
DRM_DEBUG("drm_agp_bind_ttm\n"); DRM_DEBUG("drm_agp_bind_ttm\n");
DRM_MASK_VAL(backend->flags, DRM_BE_FLAG_BOUND_CACHED,
(cached) ? DRM_BE_FLAG_BOUND_CACHED : 0);
mem->is_flushed = TRUE; mem->is_flushed = TRUE;
mem->type = (cached) ? agp_priv->cached_type : agp_priv->uncached_type; mem->type = (cached) ? AGP_USER_CACHED_MEMORY :
AGP_USER_MEMORY;
ret = drm_agp_bind_memory(mem, offset); ret = drm_agp_bind_memory(mem, offset);
if (ret) { if (ret) {
DRM_ERROR("AGP Bind memory failed\n"); DRM_ERROR("AGP Bind memory failed\n");
} }
DRM_FLAG_MASKED(backend->flags, (cached) ? DRM_BE_FLAG_BOUND_CACHED : 0,
DRM_BE_FLAG_BOUND_CACHED);
return ret; return ret;
} }
static int drm_agp_unbind_ttm(drm_ttm_backend_t *backend) { static int drm_agp_unbind_ttm(drm_ttm_backend_t *backend) {
drm_agp_ttm_priv *agp_priv = (drm_agp_ttm_priv *) backend->private; drm_agp_ttm_backend_t *agp_be =
container_of(backend, drm_agp_ttm_backend_t, backend);
DRM_DEBUG("drm_agp_unbind_ttm\n"); DRM_DEBUG("drm_agp_unbind_ttm\n");
if (agp_priv->mem->is_bound) if (agp_be->mem->is_bound)
return drm_agp_unbind_memory(agp_priv->mem); return drm_agp_unbind_memory(agp_be->mem);
else else
return 0; return 0;
} }
static void drm_agp_clear_ttm(drm_ttm_backend_t *backend) { static void drm_agp_clear_ttm(drm_ttm_backend_t *backend) {
drm_agp_ttm_priv *agp_priv = (drm_agp_ttm_priv *) backend->private; drm_agp_ttm_backend_t *agp_be =
DRM_AGP_MEM *mem = agp_priv->mem; container_of(backend, drm_agp_ttm_backend_t, backend);
DRM_AGP_MEM *mem = agp_be->mem;
DRM_DEBUG("drm_agp_clear_ttm\n"); DRM_DEBUG("drm_agp_clear_ttm\n");
if (mem) { if (mem) {
unsigned long num_pages = mem->page_count; unsigned long num_pages = mem->page_count;
backend->unbind(backend); backend->func->unbind(backend);
agp_free_memory(mem); agp_free_memory(mem);
drm_free_memctl(num_pages *sizeof(void *)); drm_free_memctl(num_pages *sizeof(void *));
} }
agp_be->mem = NULL;
agp_priv->mem = NULL;
} }
static void drm_agp_destroy_ttm(drm_ttm_backend_t *backend) { static void drm_agp_destroy_ttm(drm_ttm_backend_t *backend) {
drm_agp_ttm_priv *agp_priv; drm_agp_ttm_backend_t *agp_be;
if (backend) { if (backend) {
DRM_DEBUG("drm_agp_destroy_ttm\n"); DRM_DEBUG("drm_agp_destroy_ttm\n");
agp_priv = (drm_agp_ttm_priv *) backend->private; agp_be = container_of(backend, drm_agp_ttm_backend_t, backend);
if (agp_priv) { if (agp_be) {
if (agp_priv->mem) { if (agp_be->mem) {
backend->clear(backend); backend->func->clear(backend);
} }
drm_ctl_free(agp_priv, sizeof(*agp_priv), DRM_MEM_MAPPINGS); drm_ctl_free(agp_be, sizeof(*agp_be), DRM_MEM_TTM);
backend->private = NULL;
}
if (backend->flags & DRM_BE_FLAG_NEEDS_FREE) {
drm_ctl_free(backend, sizeof(*backend), DRM_MEM_MAPPINGS);
} }
} }
} }
drm_ttm_backend_t *drm_agp_init_ttm(struct drm_device *dev, static drm_ttm_backend_func_t agp_ttm_backend =
drm_ttm_backend_t *backend) {
.needs_ub_cache_adjust = drm_agp_needs_unbind_cache_adjust,
.populate = drm_agp_populate,
.clear = drm_agp_clear_ttm,
.bind = drm_agp_bind_ttm,
.unbind = drm_agp_unbind_ttm,
.destroy = drm_agp_destroy_ttm,
};
drm_ttm_backend_t *drm_agp_init_ttm(struct drm_device *dev)
{ {
drm_ttm_backend_t *agp_be; drm_agp_ttm_backend_t *agp_be;
drm_agp_ttm_priv *agp_priv; struct agp_kern_info *info;
agp_be = (backend != NULL) ? backend: if (!dev->agp) {
drm_ctl_calloc(1, sizeof(*agp_be), DRM_MEM_MAPPINGS); DRM_ERROR("AGP is not initialized.\n");
if (!agp_be)
return NULL;
agp_priv = drm_ctl_calloc(1, sizeof(*agp_priv), DRM_MEM_MAPPINGS);
if (!agp_priv) {
drm_ctl_free(agp_be, sizeof(*agp_be), DRM_MEM_MAPPINGS);
return NULL; return NULL;
} }
info = &dev->agp->agp_info;
if (info->version.major != AGP_REQUIRED_MAJOR ||
info->version.minor < AGP_REQUIRED_MINOR) {
DRM_ERROR("Wrong agpgart version %d.%d\n"
"\tYou need at least version %d.%d.\n",
info->version.major,
info->version.minor,
AGP_REQUIRED_MAJOR,
AGP_REQUIRED_MINOR);
return NULL;
}
agp_priv->mem = NULL; agp_be = drm_ctl_calloc(1, sizeof(*agp_be), DRM_MEM_TTM);
agp_priv->alloc_type = AGP_USER_MEMORY; if (!agp_be)
agp_priv->cached_type = AGP_USER_CACHED_MEMORY; return NULL;
agp_priv->uncached_type = AGP_USER_MEMORY;
agp_priv->bridge = dev->agp->bridge; agp_be->mem = NULL;
agp_priv->populated = FALSE;
agp_be->aperture_base = dev->agp->agp_info.aper_base; agp_be->bridge = dev->agp->bridge;
agp_be->private = (void *) agp_priv; agp_be->populated = FALSE;
agp_be->needs_ub_cache_adjust = drm_agp_needs_unbind_cache_adjust; agp_be->backend.func = &agp_ttm_backend;
agp_be->populate = drm_agp_populate; agp_be->backend.mem_type = DRM_BO_MEM_TT;
agp_be->clear = drm_agp_clear_ttm;
agp_be->bind = drm_agp_bind_ttm; return &agp_be->backend;
agp_be->unbind = drm_agp_unbind_ttm;
agp_be->destroy = drm_agp_destroy_ttm;
DRM_MASK_VAL(agp_be->flags, DRM_BE_FLAG_NEEDS_FREE,
(backend == NULL) ? DRM_BE_FLAG_NEEDS_FREE : 0);
DRM_MASK_VAL(agp_be->flags, DRM_BE_FLAG_CBA,
(dev->agp->cant_use_aperture) ? DRM_BE_FLAG_CBA : 0);
agp_be->drm_map_type = _DRM_AGP;
return agp_be;
} }
EXPORT_SYMBOL(drm_agp_init_ttm); EXPORT_SYMBOL(drm_agp_init_ttm);

File diff suppressed because it is too large Load diff

411
linux-core/drm_bo_move.c Normal file
View file

@ -0,0 +1,411 @@
/**************************************************************************
*
* Copyright (c) 2007 Tungsten Graphics, Inc., Cedar Park, TX., USA
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* USE OR OTHER DEALINGS IN THE SOFTWARE.
*
**************************************************************************/
/*
* Authors: Thomas Hellström <thomas-at-tungstengraphics-dot-com>
*/
#include "drmP.h"
/**
* Free the old memory node unless it's a pinned region and we
* have not been requested to free also pinned regions.
*/
static void drm_bo_free_old_node(drm_buffer_object_t * bo)
{
drm_bo_mem_reg_t *old_mem = &bo->mem;
if (old_mem->mm_node && (old_mem->mm_node != bo->pinned_node)) {
mutex_lock(&bo->dev->struct_mutex);
drm_mm_put_block(old_mem->mm_node);
old_mem->mm_node = NULL;
mutex_unlock(&bo->dev->struct_mutex);
}
old_mem->mm_node = NULL;
}
int drm_bo_move_ttm(drm_buffer_object_t * bo,
int evict, int no_wait, drm_bo_mem_reg_t * new_mem)
{
drm_ttm_t *ttm = bo->ttm;
drm_bo_mem_reg_t *old_mem = &bo->mem;
uint32_t save_flags = old_mem->flags;
uint32_t save_mask = old_mem->mask;
int ret;
if (old_mem->mem_type == DRM_BO_MEM_TT) {
if (evict)
drm_ttm_evict(ttm);
else
drm_ttm_unbind(ttm);
drm_bo_free_old_node(bo);
DRM_FLAG_MASKED(old_mem->flags,
DRM_BO_FLAG_CACHED | DRM_BO_FLAG_MAPPABLE |
DRM_BO_FLAG_MEM_LOCAL, DRM_BO_MASK_MEMTYPE);
old_mem->mem_type = DRM_BO_MEM_LOCAL;
save_flags = old_mem->flags;
}
if (new_mem->mem_type != DRM_BO_MEM_LOCAL) {
ret = drm_bind_ttm(ttm,
new_mem->flags & DRM_BO_FLAG_CACHED,
new_mem->mm_node->start);
if (ret)
return ret;
}
*old_mem = *new_mem;
new_mem->mm_node = NULL;
old_mem->mask = save_mask;
DRM_FLAG_MASKED(save_flags, new_mem->flags, DRM_BO_MASK_MEMTYPE);
return 0;
}
EXPORT_SYMBOL(drm_bo_move_ttm);
/**
* \c Return a kernel virtual address to the buffer object PCI memory.
*
* \param bo The buffer object.
* \return Failure indication.
*
* Returns -EINVAL if the buffer object is currently not mappable.
* Returns -ENOMEM if the ioremap operation failed.
* Otherwise returns zero.
*
* After a successfull call, bo->iomap contains the virtual address, or NULL
* if the buffer object content is not accessible through PCI space.
* Call bo->mutex locked.
*/
int drm_mem_reg_ioremap(drm_device_t * dev, drm_bo_mem_reg_t * mem,
void **virtual)
{
drm_buffer_manager_t *bm = &dev->bm;
drm_mem_type_manager_t *man = &bm->man[mem->mem_type];
unsigned long bus_offset;
unsigned long bus_size;
unsigned long bus_base;
int ret;
void *addr;
*virtual = NULL;
ret = drm_bo_pci_offset(dev, mem, &bus_base, &bus_offset, &bus_size);
if (ret || bus_size == 0)
return ret;
if (!(man->flags & _DRM_FLAG_NEEDS_IOREMAP))
addr = (void *)(((u8 *) man->io_addr) + bus_offset);
else {
addr = ioremap_nocache(bus_base + bus_offset, bus_size);
if (!addr)
return -ENOMEM;
}
*virtual = addr;
return 0;
}
/**
* \c Unmap mapping obtained using drm_bo_ioremap
*
* \param bo The buffer object.
*
* Call bo->mutex locked.
*/
void drm_mem_reg_iounmap(drm_device_t * dev, drm_bo_mem_reg_t * mem,
void *virtual)
{
drm_buffer_manager_t *bm;
drm_mem_type_manager_t *man;
bm = &dev->bm;
man = &bm->man[mem->mem_type];
if (virtual && (man->flags & _DRM_FLAG_NEEDS_IOREMAP)) {
iounmap(virtual);
}
}
static int drm_copy_io_page(void *dst, void *src, unsigned long page)
{
uint32_t *dstP =
(uint32_t *) ((unsigned long)dst + (page << PAGE_SHIFT));
uint32_t *srcP =
(uint32_t *) ((unsigned long)src + (page << PAGE_SHIFT));
int i;
for (i = 0; i < PAGE_SIZE / sizeof(uint32_t); ++i)
iowrite32(ioread32(srcP++), dstP++);
return 0;
}
static int drm_copy_io_ttm_page(drm_ttm_t * ttm, void *src, unsigned long page)
{
struct page *d = drm_ttm_get_page(ttm, page);
void *dst;
if (!d)
return -ENOMEM;
src = (void *)((unsigned long)src + (page << PAGE_SHIFT));
dst = kmap(d);
if (!dst)
return -ENOMEM;
memcpy_fromio(dst, src, PAGE_SIZE);
kunmap(d);
return 0;
}
static int drm_copy_ttm_io_page(drm_ttm_t * ttm, void *dst, unsigned long page)
{
struct page *s = drm_ttm_get_page(ttm, page);
void *src;
if (!s)
return -ENOMEM;
dst = (void *)((unsigned long)dst + (page << PAGE_SHIFT));
src = kmap(s);
if (!src)
return -ENOMEM;
memcpy_toio(dst, src, PAGE_SIZE);
kunmap(s);
return 0;
}
int drm_bo_move_memcpy(drm_buffer_object_t * bo,
int evict, int no_wait, drm_bo_mem_reg_t * new_mem)
{
drm_device_t *dev = bo->dev;
drm_mem_type_manager_t *man = &dev->bm.man[new_mem->mem_type];
drm_ttm_t *ttm = bo->ttm;
drm_bo_mem_reg_t *old_mem = &bo->mem;
drm_bo_mem_reg_t old_copy = *old_mem;
void *old_iomap;
void *new_iomap;
int ret;
uint32_t save_flags = old_mem->flags;
uint32_t save_mask = old_mem->mask;
unsigned long i;
unsigned long page;
unsigned long add = 0;
int dir;
ret = drm_mem_reg_ioremap(dev, old_mem, &old_iomap);
if (ret)
return ret;
ret = drm_mem_reg_ioremap(dev, new_mem, &new_iomap);
if (ret)
goto out;
if (old_iomap == NULL && new_iomap == NULL)
goto out2;
if (old_iomap == NULL && ttm == NULL)
goto out2;
add = 0;
dir = 1;
if ((old_mem->mem_type == new_mem->mem_type) &&
(new_mem->mm_node->start <
old_mem->mm_node->start + old_mem->mm_node->size)) {
dir = -1;
add = new_mem->num_pages - 1;
}
for (i = 0; i < new_mem->num_pages; ++i) {
page = i * dir + add;
if (old_iomap == NULL)
ret = drm_copy_ttm_io_page(ttm, new_iomap, page);
else if (new_iomap == NULL)
ret = drm_copy_io_ttm_page(ttm, old_iomap, page);
else
ret = drm_copy_io_page(new_iomap, old_iomap, page);
if (ret)
goto out1;
}
mb();
out2:
drm_bo_free_old_node(bo);
*old_mem = *new_mem;
new_mem->mm_node = NULL;
old_mem->mask = save_mask;
DRM_FLAG_MASKED(save_flags, new_mem->flags, DRM_BO_MASK_MEMTYPE);
if ((man->flags & _DRM_FLAG_MEMTYPE_FIXED) && (ttm != NULL)) {
drm_ttm_unbind(ttm);
drm_destroy_ttm(ttm);
bo->ttm = NULL;
}
out1:
drm_mem_reg_iounmap(dev, new_mem, new_iomap);
out:
drm_mem_reg_iounmap(dev, &old_copy, old_iomap);
return ret;
}
EXPORT_SYMBOL(drm_bo_move_memcpy);
/*
* Transfer a buffer object's memory and LRU status to a newly
* created object. User-space references remains with the old
* object. Call bo->mutex locked.
*/
int drm_buffer_object_transfer(drm_buffer_object_t * bo,
drm_buffer_object_t ** new_obj)
{
drm_buffer_object_t *fbo;
drm_device_t *dev = bo->dev;
drm_buffer_manager_t *bm = &dev->bm;
fbo = drm_ctl_calloc(1, sizeof(*fbo), DRM_MEM_BUFOBJ);
if (!fbo)
return -ENOMEM;
*fbo = *bo;
mutex_init(&fbo->mutex);
mutex_lock(&fbo->mutex);
mutex_lock(&dev->struct_mutex);
DRM_INIT_WAITQUEUE(&bo->event_queue);
INIT_LIST_HEAD(&fbo->ddestroy);
INIT_LIST_HEAD(&fbo->lru);
INIT_LIST_HEAD(&fbo->pinned_lru);
#ifdef DRM_ODD_MM_COMPAT
INIT_LIST_HEAD(&fbo->vma_list);
INIT_LIST_HEAD(&fbo->p_mm_list);
#endif
atomic_inc(&bo->fence->usage);
fbo->pinned_node = NULL;
fbo->mem.mm_node->private = (void *)fbo;
atomic_set(&fbo->usage, 1);
atomic_inc(&bm->count);
mutex_unlock(&dev->struct_mutex);
mutex_unlock(&fbo->mutex);
*new_obj = fbo;
return 0;
}
/*
* Since move is underway, we need to block signals in this function.
* We cannot restart until it has finished.
*/
int drm_bo_move_accel_cleanup(drm_buffer_object_t * bo,
int evict,
int no_wait,
uint32_t fence_class,
uint32_t fence_type,
uint32_t fence_flags, drm_bo_mem_reg_t * new_mem)
{
drm_device_t *dev = bo->dev;
drm_mem_type_manager_t *man = &dev->bm.man[new_mem->mem_type];
drm_bo_mem_reg_t *old_mem = &bo->mem;
int ret;
uint32_t save_flags = old_mem->flags;
uint32_t save_mask = old_mem->mask;
drm_buffer_object_t *old_obj;
if (bo->fence)
drm_fence_usage_deref_unlocked(dev, bo->fence);
ret = drm_fence_object_create(dev, fence_class, fence_type,
fence_flags | DRM_FENCE_FLAG_EMIT,
&bo->fence);
if (ret)
return ret;
#ifdef DRM_ODD_MM_COMPAT
/*
* In this mode, we don't allow pipelining a copy blit,
* since the buffer will be accessible from user space
* the moment we return and rebuild the page tables.
*
* With normal vm operation, page tables are rebuilt
* on demand using fault(), which waits for buffer idle.
*/
if (1)
#else
if (evict || ((bo->mem.mm_node == bo->pinned_node) &&
bo->mem.mm_node != NULL))
#endif
{
ret = drm_bo_wait(bo, 0, 1, 0);
if (ret)
return ret;
drm_bo_free_old_node(bo);
if ((man->flags & _DRM_FLAG_MEMTYPE_FIXED) && (bo->ttm != NULL)) {
drm_ttm_unbind(bo->ttm);
drm_destroy_ttm(bo->ttm);
bo->ttm = NULL;
}
} else {
/* This should help pipeline ordinary buffer moves.
*
* Hang old buffer memory on a new buffer object,
* and leave it to be released when the GPU
* operation has completed.
*/
ret = drm_buffer_object_transfer(bo, &old_obj);
if (ret)
return ret;
if (!(man->flags & _DRM_FLAG_MEMTYPE_FIXED))
old_obj->ttm = NULL;
else
bo->ttm = NULL;
mutex_lock(&dev->struct_mutex);
list_del_init(&old_obj->lru);
DRM_FLAG_MASKED(bo->priv_flags, 0, _DRM_BO_FLAG_UNFENCED);
drm_bo_add_to_lru(old_obj);
drm_bo_usage_deref_locked(old_obj);
mutex_unlock(&dev->struct_mutex);
}
*old_mem = *new_mem;
new_mem->mm_node = NULL;
old_mem->mask = save_mask;
DRM_FLAG_MASKED(save_flags, new_mem->flags, DRM_BO_MASK_MEMTYPE);
return 0;
}
EXPORT_SYMBOL(drm_bo_move_accel_cleanup);

View file

@ -51,10 +51,8 @@ EXPORT_SYMBOL(drm_get_resource_len);
static drm_map_list_t *drm_find_matching_map(drm_device_t *dev, static drm_map_list_t *drm_find_matching_map(drm_device_t *dev,
drm_local_map_t *map) drm_local_map_t *map)
{ {
struct list_head *list; drm_map_list_t *entry;
list_for_each_entry(entry, &dev->maplist, head) {
list_for_each(list, &dev->maplist->head) {
drm_map_list_t *entry = list_entry(list, drm_map_list_t, head);
if (entry->map && map->type == entry->map->type && if (entry->map && map->type == entry->map->type &&
((entry->map->offset == map->offset) || ((entry->map->offset == map->offset) ||
(map->type == _DRM_SHM && map->flags==_DRM_CONTAINS_LOCK))) { (map->type == _DRM_SHM && map->flags==_DRM_CONTAINS_LOCK))) {
@ -179,7 +177,7 @@ static int drm_addmap_core(drm_device_t * dev, unsigned int offset,
} }
} }
if (map->type == _DRM_REGISTERS) if (map->type == _DRM_REGISTERS)
map->handle = drm_ioremap(map->offset, map->size, dev); map->handle = ioremap(map->offset, map->size);
break; break;
case _DRM_SHM: case _DRM_SHM:
list = drm_find_matching_map(dev, map); list = drm_find_matching_map(dev, map);
@ -195,7 +193,7 @@ static int drm_addmap_core(drm_device_t * dev, unsigned int offset,
*maplist = list; *maplist = list;
return 0; return 0;
} }
map->handle = vmalloc_32(map->size); map->handle = vmalloc_user(map->size);
DRM_DEBUG("%lu %d %p\n", DRM_DEBUG("%lu %d %p\n",
map->size, drm_order(map->size), map->handle); map->size, drm_order(map->size), map->handle);
if (!map->handle) { if (!map->handle) {
@ -237,14 +235,14 @@ static int drm_addmap_core(drm_device_t * dev, unsigned int offset,
* skipped and we double check that dev->agp->memory is * skipped and we double check that dev->agp->memory is
* actually set as well as being invalid before EPERM'ing * actually set as well as being invalid before EPERM'ing
*/ */
for (entry = dev->agp->memory; entry; entry = entry->next) { list_for_each_entry(entry, &dev->agp->memory, head) {
if ((map->offset >= entry->bound) && if ((map->offset >= entry->bound) &&
(map->offset + map->size <= entry->bound + entry->pages * PAGE_SIZE)) { (map->offset + map->size <= entry->bound + entry->pages * PAGE_SIZE)) {
valid = 1; valid = 1;
break; break;
} }
} }
if (dev->agp->memory && !valid) { if (!list_empty(&dev->agp->memory) && !valid) {
drm_free(map, sizeof(*map), DRM_MEM_MAPS); drm_free(map, sizeof(*map), DRM_MEM_MAPS);
return -EPERM; return -EPERM;
} }
@ -279,6 +277,8 @@ static int drm_addmap_core(drm_device_t * dev, unsigned int offset,
list = drm_alloc(sizeof(*list), DRM_MEM_MAPS); list = drm_alloc(sizeof(*list), DRM_MEM_MAPS);
if (!list) { if (!list) {
if (map->type == _DRM_REGISTERS)
iounmap(map->handle);
drm_free(map, sizeof(*map), DRM_MEM_MAPS); drm_free(map, sizeof(*map), DRM_MEM_MAPS);
return -EINVAL; return -EINVAL;
} }
@ -286,7 +286,7 @@ static int drm_addmap_core(drm_device_t * dev, unsigned int offset,
list->map = map; list->map = map;
mutex_lock(&dev->struct_mutex); mutex_lock(&dev->struct_mutex);
list_add(&list->head, &dev->maplist->head); list_add(&list->head, &dev->maplist);
/* Assign a 32-bit handle */ /* Assign a 32-bit handle */
@ -295,6 +295,8 @@ static int drm_addmap_core(drm_device_t * dev, unsigned int offset,
ret = drm_map_handle(dev, &list->hash, user_token, 0); ret = drm_map_handle(dev, &list->hash, user_token, 0);
if (ret) { if (ret) {
if (map->type == _DRM_REGISTERS)
iounmap(map->handle);
drm_free(map, sizeof(*map), DRM_MEM_MAPS); drm_free(map, sizeof(*map), DRM_MEM_MAPS);
drm_free(list, sizeof(*list), DRM_MEM_MAPS); drm_free(list, sizeof(*list), DRM_MEM_MAPS);
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
@ -376,33 +378,32 @@ int drm_addmap_ioctl(struct inode *inode, struct file *filp,
*/ */
int drm_rmmap_locked(drm_device_t *dev, drm_local_map_t *map) int drm_rmmap_locked(drm_device_t *dev, drm_local_map_t *map)
{ {
struct list_head *list; drm_map_list_t *r_list = NULL, *list_t;
drm_map_list_t *r_list = NULL;
drm_dma_handle_t dmah; drm_dma_handle_t dmah;
int found = 0;
/* Find the list entry for the map and remove it */ /* Find the list entry for the map and remove it */
list_for_each(list, &dev->maplist->head) { list_for_each_entry_safe(r_list, list_t, &dev->maplist, head) {
r_list = list_entry(list, drm_map_list_t, head);
if (r_list->map == map) { if (r_list->map == map) {
list_del(list); list_del(&r_list->head);
drm_ht_remove_key(&dev->map_hash, drm_ht_remove_key(&dev->map_hash,
r_list->user_token >> PAGE_SHIFT); r_list->user_token >> PAGE_SHIFT);
drm_free(list, sizeof(*list), DRM_MEM_MAPS); drm_free(r_list, sizeof(*r_list), DRM_MEM_MAPS);
found = 1;
break; break;
} }
} }
if (!found) {
return -EINVAL;
}
/* List has wrapped around to the head pointer, or it's empty and we /* List has wrapped around to the head pointer, or it's empty and we
* didn't find anything. * didn't find anything.
*/ */
if (list == (&dev->maplist->head)) {
return -EINVAL;
}
switch (map->type) { switch (map->type) {
case _DRM_REGISTERS: case _DRM_REGISTERS:
drm_ioremapfree(map->handle, map->size, dev); iounmap(map->handle);
/* FALLTHROUGH */ /* FALLTHROUGH */
case _DRM_FRAME_BUFFER: case _DRM_FRAME_BUFFER:
if (drm_core_has_MTRR(dev) && map->mtrr >= 0) { if (drm_core_has_MTRR(dev) && map->mtrr >= 0) {
@ -460,7 +461,7 @@ int drm_rmmap_ioctl(struct inode *inode, struct file *filp,
drm_device_t *dev = priv->head->dev; drm_device_t *dev = priv->head->dev;
drm_map_t request; drm_map_t request;
drm_local_map_t *map = NULL; drm_local_map_t *map = NULL;
struct list_head *list; drm_map_list_t *r_list;
int ret; int ret;
if (copy_from_user(&request, (drm_map_t __user *) arg, sizeof(request))) { if (copy_from_user(&request, (drm_map_t __user *) arg, sizeof(request))) {
@ -468,9 +469,7 @@ int drm_rmmap_ioctl(struct inode *inode, struct file *filp,
} }
mutex_lock(&dev->struct_mutex); mutex_lock(&dev->struct_mutex);
list_for_each(list, &dev->maplist->head) { list_for_each_entry(r_list, &dev->maplist, head) {
drm_map_list_t *r_list = list_entry(list, drm_map_list_t, head);
if (r_list->map && if (r_list->map &&
r_list->user_token == (unsigned long)request.handle && r_list->user_token == (unsigned long)request.handle &&
r_list->map->flags & _DRM_REMOVABLE) { r_list->map->flags & _DRM_REMOVABLE) {
@ -482,7 +481,7 @@ int drm_rmmap_ioctl(struct inode *inode, struct file *filp,
/* List has wrapped around to the head pointer, or its empty we didn't /* List has wrapped around to the head pointer, or its empty we didn't
* find anything. * find anything.
*/ */
if (list == (&dev->maplist->head)) { if (list_empty(&dev->maplist) || !map) {
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
return -EINVAL; return -EINVAL;
} }
@ -606,14 +605,14 @@ int drm_addbufs_agp(drm_device_t * dev, drm_buf_desc_t * request)
/* Make sure buffers are located in AGP memory that we own */ /* Make sure buffers are located in AGP memory that we own */
valid = 0; valid = 0;
for (agp_entry = dev->agp->memory; agp_entry; agp_entry = agp_entry->next) { list_for_each_entry(agp_entry, &dev->agp->memory, head) {
if ((agp_offset >= agp_entry->bound) && if ((agp_offset >= agp_entry->bound) &&
(agp_offset + total * count <= agp_entry->bound + agp_entry->pages * PAGE_SIZE)) { (agp_offset + total * count <= agp_entry->bound + agp_entry->pages * PAGE_SIZE)) {
valid = 1; valid = 1;
break; break;
} }
} }
if (dev->agp->memory && !valid) { if (!list_empty(&dev->agp->memory) && !valid) {
DRM_DEBUG("zone invalid\n"); DRM_DEBUG("zone invalid\n");
return -EINVAL; return -EINVAL;
} }

View file

@ -79,54 +79,14 @@ pgprot_t vm_get_page_prot(unsigned long vm_flags)
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)) #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15))
/* /*
* vm code for kernels below 2,6,15 in which version a major vm write * vm code for kernels below 2.6.15 in which version a major vm write
* occured. This implement a simple straightforward * occured. This implement a simple straightforward
* version similar to what's going to be * version similar to what's going to be
* in kernel 2.6.20+? * in kernel 2.6.19+
* Kernels below 2.6.15 use nopage whereas 2.6.19 and upwards use
* nopfn.
*/ */
static int drm_pte_is_clear(struct vm_area_struct *vma,
unsigned long addr)
{
struct mm_struct *mm = vma->vm_mm;
int ret = 1;
pte_t *pte;
pmd_t *pmd;
pud_t *pud;
pgd_t *pgd;
spin_lock(&mm->page_table_lock);
pgd = pgd_offset(mm, addr);
if (pgd_none(*pgd))
goto unlock;
pud = pud_offset(pgd, addr);
if (pud_none(*pud))
goto unlock;
pmd = pmd_offset(pud, addr);
if (pmd_none(*pmd))
goto unlock;
pte = pte_offset_map(pmd, addr);
if (!pte)
goto unlock;
ret = pte_none(*pte);
pte_unmap(pte);
unlock:
spin_unlock(&mm->page_table_lock);
return ret;
}
int vm_insert_pfn(struct vm_area_struct *vma, unsigned long addr,
unsigned long pfn, pgprot_t pgprot)
{
int ret;
if (!drm_pte_is_clear(vma, addr))
return -EBUSY;
ret = io_remap_pfn_range(vma, addr, pfn, PAGE_SIZE, pgprot);
return ret;
}
static struct { static struct {
spinlock_t lock; spinlock_t lock;
struct page *dummy_page; struct page *dummy_page;
@ -134,6 +94,11 @@ static struct {
} drm_np_retry = } drm_np_retry =
{SPIN_LOCK_UNLOCKED, NOPAGE_OOM, ATOMIC_INIT(0)}; {SPIN_LOCK_UNLOCKED, NOPAGE_OOM, ATOMIC_INIT(0)};
static struct page *drm_bo_vm_fault(struct vm_area_struct *vma,
struct fault_data *data);
struct page * get_nopage_retry(void) struct page * get_nopage_retry(void)
{ {
if (atomic_read(&drm_np_retry.present) == 0) { if (atomic_read(&drm_np_retry.present) == 0) {
@ -160,7 +125,7 @@ void free_nopage_retry(void)
} }
} }
struct page *drm_vm_ttm_nopage(struct vm_area_struct *vma, struct page *drm_bo_vm_nopage(struct vm_area_struct *vma,
unsigned long address, unsigned long address,
int *type) int *type)
{ {
@ -171,7 +136,7 @@ struct page *drm_vm_ttm_nopage(struct vm_area_struct *vma,
data.address = address; data.address = address;
data.vma = vma; data.vma = vma;
drm_vm_ttm_fault(vma, &data); drm_bo_vm_fault(vma, &data);
switch (data.type) { switch (data.type) {
case VM_FAULT_OOM: case VM_FAULT_OOM:
return NOPAGE_OOM; return NOPAGE_OOM;
@ -186,10 +151,179 @@ struct page *drm_vm_ttm_nopage(struct vm_area_struct *vma,
#endif #endif
#if !defined(DRM_FULL_MM_COMPAT) && \
((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)) || \
(LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)))
static int drm_pte_is_clear(struct vm_area_struct *vma,
unsigned long addr)
{
struct mm_struct *mm = vma->vm_mm;
int ret = 1;
pte_t *pte;
pmd_t *pmd;
pud_t *pud;
pgd_t *pgd;
spin_lock(&mm->page_table_lock);
pgd = pgd_offset(mm, addr);
if (pgd_none(*pgd))
goto unlock;
pud = pud_offset(pgd, addr);
if (pud_none(*pud))
goto unlock;
pmd = pmd_offset(pud, addr);
if (pmd_none(*pmd))
goto unlock;
pte = pte_offset_map(pmd, addr);
if (!pte)
goto unlock;
ret = pte_none(*pte);
pte_unmap(pte);
unlock:
spin_unlock(&mm->page_table_lock);
return ret;
}
static int vm_insert_pfn(struct vm_area_struct *vma, unsigned long addr,
unsigned long pfn)
{
int ret;
if (!drm_pte_is_clear(vma, addr))
return -EBUSY;
ret = io_remap_pfn_range(vma, addr, pfn, PAGE_SIZE, vma->vm_page_prot);
return ret;
}
static struct page *drm_bo_vm_fault(struct vm_area_struct *vma,
struct fault_data *data)
{
unsigned long address = data->address;
drm_buffer_object_t *bo = (drm_buffer_object_t *) vma->vm_private_data;
unsigned long page_offset;
struct page *page = NULL;
drm_ttm_t *ttm;
drm_device_t *dev;
unsigned long pfn;
int err;
unsigned long bus_base;
unsigned long bus_offset;
unsigned long bus_size;
mutex_lock(&bo->mutex);
err = drm_bo_wait(bo, 0, 1, 0);
if (err) {
data->type = (err == -EAGAIN) ?
VM_FAULT_MINOR : VM_FAULT_SIGBUS;
goto out_unlock;
}
/*
* If buffer happens to be in a non-mappable location,
* move it to a mappable.
*/
if (!(bo->mem.flags & DRM_BO_FLAG_MAPPABLE)) {
unsigned long _end = jiffies + 3*DRM_HZ;
uint32_t new_mask = bo->mem.mask |
DRM_BO_FLAG_MAPPABLE |
DRM_BO_FLAG_FORCE_MAPPABLE;
do {
err = drm_bo_move_buffer(bo, new_mask, 0, 0);
} while((err == -EAGAIN) && !time_after_eq(jiffies, _end));
if (err) {
DRM_ERROR("Timeout moving buffer to mappable location.\n");
data->type = VM_FAULT_SIGBUS;
goto out_unlock;
}
}
if (address > vma->vm_end) {
data->type = VM_FAULT_SIGBUS;
goto out_unlock;
}
dev = bo->dev;
err = drm_bo_pci_offset(dev, &bo->mem, &bus_base, &bus_offset,
&bus_size);
if (err) {
data->type = VM_FAULT_SIGBUS;
goto out_unlock;
}
page_offset = (address - vma->vm_start) >> PAGE_SHIFT;
if (bus_size) {
drm_mem_type_manager_t *man = &dev->bm.man[bo->mem.mem_type];
pfn = ((bus_base + bus_offset) >> PAGE_SHIFT) + page_offset;
vma->vm_page_prot = drm_io_prot(man->drm_bus_maptype, vma);
} else {
ttm = bo->ttm;
drm_ttm_fixup_caching(ttm);
page = drm_ttm_get_page(ttm, page_offset);
if (!page) {
data->type = VM_FAULT_OOM;
goto out_unlock;
}
pfn = page_to_pfn(page);
vma->vm_page_prot = (bo->mem.flags & DRM_BO_FLAG_CACHED) ?
vm_get_page_prot(vma->vm_flags) :
drm_io_prot(_DRM_TTM, vma);
}
err = vm_insert_pfn(vma, address, pfn);
if (!err || err == -EBUSY)
data->type = VM_FAULT_MINOR;
else
data->type = VM_FAULT_OOM;
out_unlock:
mutex_unlock(&bo->mutex);
return NULL;
}
#endif
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)) && \
!defined(DRM_FULL_MM_COMPAT)
/**
*/
unsigned long drm_bo_vm_nopfn(struct vm_area_struct * vma,
unsigned long address)
{
struct fault_data data;
data.address = address;
(void) drm_bo_vm_fault(vma, &data);
if (data.type == VM_FAULT_OOM)
return NOPFN_OOM;
else if (data.type == VM_FAULT_SIGBUS)
return NOPFN_SIGBUS;
/*
* pfn already set.
*/
return 0;
}
#endif
#ifdef DRM_ODD_MM_COMPAT #ifdef DRM_ODD_MM_COMPAT
/* /*
* VM compatibility code for 2.6.15-2.6.19(?). This code implements a complicated * VM compatibility code for 2.6.15-2.6.18. This code implements a complicated
* workaround for a single BUG statement in do_no_page in these versions. The * workaround for a single BUG statement in do_no_page in these versions. The
* tricky thing is that we need to take the mmap_sem in exclusive mode for _all_ * tricky thing is that we need to take the mmap_sem in exclusive mode for _all_
* vmas mapping the ttm, before dev->struct_mutex is taken. The way we do this is to * vmas mapping the ttm, before dev->struct_mutex is taken. The way we do this is to
@ -212,108 +346,100 @@ typedef struct vma_entry {
} vma_entry_t; } vma_entry_t;
struct page *drm_vm_ttm_nopage(struct vm_area_struct *vma, struct page *drm_bo_vm_nopage(struct vm_area_struct *vma,
unsigned long address, unsigned long address,
int *type) int *type)
{ {
drm_local_map_t *map = (drm_local_map_t *) vma->vm_private_data; drm_buffer_object_t *bo = (drm_buffer_object_t *) vma->vm_private_data;
unsigned long page_offset; unsigned long page_offset;
struct page *page; struct page *page;
drm_ttm_t *ttm; drm_ttm_t *ttm;
drm_buffer_manager_t *bm;
drm_device_t *dev; drm_device_t *dev;
/* mutex_lock(&bo->mutex);
* FIXME: Check can't map aperture flag.
*/
if (type) if (type)
*type = VM_FAULT_MINOR; *type = VM_FAULT_MINOR;
if (!map) if (address > vma->vm_end) {
return NOPAGE_OOM; page = NOPAGE_SIGBUS;
goto out_unlock;
}
dev = bo->dev;
if (address > vma->vm_end) if (drm_mem_reg_is_pci(dev, &bo->mem)) {
return NOPAGE_SIGBUS; DRM_ERROR("Invalid compat nopage.\n");
page = NOPAGE_SIGBUS;
goto out_unlock;
}
ttm = (drm_ttm_t *) map->offset; ttm = bo->ttm;
dev = ttm->dev; drm_ttm_fixup_caching(ttm);
mutex_lock(&dev->struct_mutex);
drm_fixup_ttm_caching(ttm);
BUG_ON(ttm->page_flags & DRM_TTM_PAGE_UNCACHED);
bm = &dev->bm;
page_offset = (address - vma->vm_start) >> PAGE_SHIFT; page_offset = (address - vma->vm_start) >> PAGE_SHIFT;
page = ttm->pages[page_offset]; page = drm_ttm_get_page(ttm, page_offset);
if (!page) { if (!page) {
if (drm_alloc_memctl(PAGE_SIZE)) { page = NOPAGE_OOM;
page = NOPAGE_OOM; goto out_unlock;
goto out;
}
page = ttm->pages[page_offset] = drm_alloc_gatt_pages(0);
if (!page) {
drm_free_memctl(PAGE_SIZE);
page = NOPAGE_OOM;
goto out;
}
++bm->cur_pages;
SetPageLocked(page);
} }
get_page(page); get_page(page);
out: out_unlock:
mutex_unlock(&dev->struct_mutex); mutex_unlock(&bo->mutex);
return page; return page;
} }
int drm_ttm_map_bound(struct vm_area_struct *vma) int drm_bo_map_bound(struct vm_area_struct *vma)
{ {
drm_local_map_t *map = (drm_local_map_t *)vma->vm_private_data; drm_buffer_object_t *bo = (drm_buffer_object_t *)vma->vm_private_data;
drm_ttm_t *ttm = (drm_ttm_t *) map->offset;
int ret = 0; int ret = 0;
unsigned long bus_base;
unsigned long bus_offset;
unsigned long bus_size;
ret = drm_bo_pci_offset(bo->dev, &bo->mem, &bus_base,
&bus_offset, &bus_size);
BUG_ON(ret);
if (ttm->page_flags & DRM_TTM_PAGE_UNCACHED) { if (bus_size) {
unsigned long pfn = ttm->aper_offset + drm_mem_type_manager_t *man = &bo->dev->bm.man[bo->mem.mem_type];
(ttm->be->aperture_base >> PAGE_SHIFT); unsigned long pfn = (bus_base + bus_offset) >> PAGE_SHIFT;
pgprot_t pgprot = drm_io_prot(ttm->be->drm_map_type, vma); pgprot_t pgprot = drm_io_prot(man->drm_bus_maptype, vma);
ret = io_remap_pfn_range(vma, vma->vm_start, pfn, ret = io_remap_pfn_range(vma, vma->vm_start, pfn,
vma->vm_end - vma->vm_start, vma->vm_end - vma->vm_start,
pgprot); pgprot);
} }
return ret; return ret;
} }
int drm_ttm_add_vma(drm_ttm_t * ttm, struct vm_area_struct *vma) int drm_bo_add_vma(drm_buffer_object_t * bo, struct vm_area_struct *vma)
{ {
p_mm_entry_t *entry, *n_entry; p_mm_entry_t *entry, *n_entry;
vma_entry_t *v_entry; vma_entry_t *v_entry;
drm_local_map_t *map = (drm_local_map_t *)
vma->vm_private_data;
struct mm_struct *mm = vma->vm_mm; struct mm_struct *mm = vma->vm_mm;
v_entry = drm_ctl_alloc(sizeof(*v_entry), DRM_MEM_TTM); v_entry = drm_ctl_alloc(sizeof(*v_entry), DRM_MEM_BUFOBJ);
if (!v_entry) { if (!v_entry) {
DRM_ERROR("Allocation of vma pointer entry failed\n"); DRM_ERROR("Allocation of vma pointer entry failed\n");
return -ENOMEM; return -ENOMEM;
} }
v_entry->vma = vma; v_entry->vma = vma;
map->handle = (void *) v_entry;
list_add_tail(&v_entry->head, &ttm->vma_list);
list_for_each_entry(entry, &ttm->p_mm_list, head) { list_add_tail(&v_entry->head, &bo->vma_list);
list_for_each_entry(entry, &bo->p_mm_list, head) {
if (mm == entry->mm) { if (mm == entry->mm) {
atomic_inc(&entry->refcount); atomic_inc(&entry->refcount);
return 0; return 0;
} else if ((unsigned long)mm < (unsigned long)entry->mm) ; } else if ((unsigned long)mm < (unsigned long)entry->mm) ;
} }
n_entry = drm_ctl_alloc(sizeof(*n_entry), DRM_MEM_TTM); n_entry = drm_ctl_alloc(sizeof(*n_entry), DRM_MEM_BUFOBJ);
if (!n_entry) { if (!n_entry) {
DRM_ERROR("Allocation of process mm pointer entry failed\n"); DRM_ERROR("Allocation of process mm pointer entry failed\n");
return -ENOMEM; return -ENOMEM;
@ -327,29 +453,29 @@ int drm_ttm_add_vma(drm_ttm_t * ttm, struct vm_area_struct *vma)
return 0; return 0;
} }
void drm_ttm_delete_vma(drm_ttm_t * ttm, struct vm_area_struct *vma) void drm_bo_delete_vma(drm_buffer_object_t * bo, struct vm_area_struct *vma)
{ {
p_mm_entry_t *entry, *n; p_mm_entry_t *entry, *n;
vma_entry_t *v_entry, *v_n; vma_entry_t *v_entry, *v_n;
int found = 0; int found = 0;
struct mm_struct *mm = vma->vm_mm; struct mm_struct *mm = vma->vm_mm;
list_for_each_entry_safe(v_entry, v_n, &ttm->vma_list, head) { list_for_each_entry_safe(v_entry, v_n, &bo->vma_list, head) {
if (v_entry->vma == vma) { if (v_entry->vma == vma) {
found = 1; found = 1;
list_del(&v_entry->head); list_del(&v_entry->head);
drm_ctl_free(v_entry, sizeof(*v_entry), DRM_MEM_TTM); drm_ctl_free(v_entry, sizeof(*v_entry), DRM_MEM_BUFOBJ);
break; break;
} }
} }
BUG_ON(!found); BUG_ON(!found);
list_for_each_entry_safe(entry, n, &ttm->p_mm_list, head) { list_for_each_entry_safe(entry, n, &bo->p_mm_list, head) {
if (mm == entry->mm) { if (mm == entry->mm) {
if (atomic_add_negative(-1, &entry->refcount)) { if (atomic_add_negative(-1, &entry->refcount)) {
list_del(&entry->head); list_del(&entry->head);
BUG_ON(entry->locked); BUG_ON(entry->locked);
drm_ctl_free(entry, sizeof(*entry), DRM_MEM_TTM); drm_ctl_free(entry, sizeof(*entry), DRM_MEM_BUFOBJ);
} }
return; return;
} }
@ -359,12 +485,12 @@ void drm_ttm_delete_vma(drm_ttm_t * ttm, struct vm_area_struct *vma)
int drm_ttm_lock_mm(drm_ttm_t * ttm) int drm_bo_lock_kmm(drm_buffer_object_t * bo)
{ {
p_mm_entry_t *entry; p_mm_entry_t *entry;
int lock_ok = 1; int lock_ok = 1;
list_for_each_entry(entry, &ttm->p_mm_list, head) { list_for_each_entry(entry, &bo->p_mm_list, head) {
BUG_ON(entry->locked); BUG_ON(entry->locked);
if (!down_write_trylock(&entry->mm->mmap_sem)) { if (!down_write_trylock(&entry->mm->mmap_sem)) {
lock_ok = 0; lock_ok = 0;
@ -376,7 +502,7 @@ int drm_ttm_lock_mm(drm_ttm_t * ttm)
if (lock_ok) if (lock_ok)
return 0; return 0;
list_for_each_entry(entry, &ttm->p_mm_list, head) { list_for_each_entry(entry, &bo->p_mm_list, head) {
if (!entry->locked) if (!entry->locked)
break; break;
up_write(&entry->mm->mmap_sem); up_write(&entry->mm->mmap_sem);
@ -391,44 +517,164 @@ int drm_ttm_lock_mm(drm_ttm_t * ttm)
return -EAGAIN; return -EAGAIN;
} }
void drm_ttm_unlock_mm(drm_ttm_t * ttm) void drm_bo_unlock_kmm(drm_buffer_object_t * bo)
{ {
p_mm_entry_t *entry; p_mm_entry_t *entry;
list_for_each_entry(entry, &ttm->p_mm_list, head) { list_for_each_entry(entry, &bo->p_mm_list, head) {
BUG_ON(!entry->locked); BUG_ON(!entry->locked);
up_write(&entry->mm->mmap_sem); up_write(&entry->mm->mmap_sem);
entry->locked = 0; entry->locked = 0;
} }
} }
int drm_ttm_remap_bound(drm_ttm_t *ttm) int drm_bo_remap_bound(drm_buffer_object_t *bo)
{ {
vma_entry_t *v_entry; vma_entry_t *v_entry;
int ret = 0; int ret = 0;
list_for_each_entry(v_entry, &ttm->vma_list, head) { if (drm_mem_reg_is_pci(bo->dev, &bo->mem)) {
ret = drm_ttm_map_bound(v_entry->vma); list_for_each_entry(v_entry, &bo->vma_list, head) {
if (ret) ret = drm_bo_map_bound(v_entry->vma);
break; if (ret)
break;
}
} }
drm_ttm_unlock_mm(ttm);
return ret; return ret;
} }
void drm_ttm_finish_unmap(drm_ttm_t *ttm) void drm_bo_finish_unmap(drm_buffer_object_t *bo)
{ {
vma_entry_t *v_entry; vma_entry_t *v_entry;
if (!(ttm->page_flags & DRM_TTM_PAGE_UNCACHED))
return;
list_for_each_entry(v_entry, &ttm->vma_list, head) { list_for_each_entry(v_entry, &bo->vma_list, head) {
v_entry->vma->vm_flags &= ~VM_PFNMAP; v_entry->vma->vm_flags &= ~VM_PFNMAP;
} }
drm_ttm_unlock_mm(ttm);
} }
#endif #endif
#ifdef DRM_IDR_COMPAT_FN
/* only called when idp->lock is held */
static void __free_layer(struct idr *idp, struct idr_layer *p)
{
p->ary[0] = idp->id_free;
idp->id_free = p;
idp->id_free_cnt++;
}
static void free_layer(struct idr *idp, struct idr_layer *p)
{
unsigned long flags;
/*
* Depends on the return element being zeroed.
*/
spin_lock_irqsave(&idp->lock, flags);
__free_layer(idp, p);
spin_unlock_irqrestore(&idp->lock, flags);
}
/**
* idr_for_each - iterate through all stored pointers
* @idp: idr handle
* @fn: function to be called for each pointer
* @data: data passed back to callback function
*
* Iterate over the pointers registered with the given idr. The
* callback function will be called for each pointer currently
* registered, passing the id, the pointer and the data pointer passed
* to this function. It is not safe to modify the idr tree while in
* the callback, so functions such as idr_get_new and idr_remove are
* not allowed.
*
* We check the return of @fn each time. If it returns anything other
* than 0, we break out and return that value.
*
* The caller must serialize idr_find() vs idr_get_new() and idr_remove().
*/
int idr_for_each(struct idr *idp,
int (*fn)(int id, void *p, void *data), void *data)
{
int n, id, max, error = 0;
struct idr_layer *p;
struct idr_layer *pa[MAX_LEVEL];
struct idr_layer **paa = &pa[0];
n = idp->layers * IDR_BITS;
p = idp->top;
max = 1 << n;
id = 0;
while (id < max) {
while (n > 0 && p) {
n -= IDR_BITS;
*paa++ = p;
p = p->ary[(id >> n) & IDR_MASK];
}
if (p) {
error = fn(id, (void *)p, data);
if (error)
break;
}
id += 1 << n;
while (n < fls(id)) {
n += IDR_BITS;
p = *--paa;
}
}
return error;
}
EXPORT_SYMBOL(idr_for_each);
/**
* idr_remove_all - remove all ids from the given idr tree
* @idp: idr handle
*
* idr_destroy() only frees up unused, cached idp_layers, but this
* function will remove all id mappings and leave all idp_layers
* unused.
*
* A typical clean-up sequence for objects stored in an idr tree, will
* use idr_for_each() to free all objects, if necessay, then
* idr_remove_all() to remove all ids, and idr_destroy() to free
* up the cached idr_layers.
*/
void idr_remove_all(struct idr *idp)
{
int n, id, max, error = 0;
struct idr_layer *p;
struct idr_layer *pa[MAX_LEVEL];
struct idr_layer **paa = &pa[0];
n = idp->layers * IDR_BITS;
p = idp->top;
max = 1 << n;
id = 0;
while (id < max && !error) {
while (n > IDR_BITS && p) {
n -= IDR_BITS;
*paa++ = p;
p = p->ary[(id >> n) & IDR_MASK];
}
id += 1 << n;
while (n < fls(id)) {
if (p) {
memset(p, 0, sizeof *p);
free_layer(idp, p);
}
n += IDR_BITS;
p = *--paa;
}
}
idp->top = NULL;
idp->layers = 0;
}
EXPORT_SYMBOL(idr_remove_all);
#endif

View file

@ -31,7 +31,6 @@
* OTHER DEALINGS IN THE SOFTWARE. * OTHER DEALINGS IN THE SOFTWARE.
*/ */
#include <asm/agp.h>
#ifndef _DRM_COMPAT_H_ #ifndef _DRM_COMPAT_H_
#define _DRM_COMPAT_H_ #define _DRM_COMPAT_H_
@ -57,6 +56,12 @@
#define module_param(name, type, perm) #define module_param(name, type, perm)
#endif #endif
/* older kernels had different irq args */
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19))
#undef DRM_IRQ_ARGS
#define DRM_IRQ_ARGS int irq, void *arg, struct pt_regs *regs
#endif
#ifndef list_for_each_safe #ifndef list_for_each_safe
#define list_for_each_safe(pos, n, head) \ #define list_for_each_safe(pos, n, head) \
for (pos = (head)->next, n = pos->next; pos != (head); \ for (pos = (head)->next, n = pos->next; pos != (head); \
@ -80,92 +85,6 @@
pos = n, n = list_entry(n->member.next, typeof(*n), member)) pos = n, n = list_entry(n->member.next, typeof(*n), member))
#endif #endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,19)
static inline struct page *vmalloc_to_page(void *vmalloc_addr)
{
unsigned long addr = (unsigned long)vmalloc_addr;
struct page *page = NULL;
pgd_t *pgd = pgd_offset_k(addr);
pmd_t *pmd;
pte_t *ptep, pte;
if (!pgd_none(*pgd)) {
pmd = pmd_offset(pgd, addr);
if (!pmd_none(*pmd)) {
preempt_disable();
ptep = pte_offset_map(pmd, addr);
pte = *ptep;
if (pte_present(pte))
page = pte_page(pte);
pte_unmap(ptep);
preempt_enable();
}
}
return page;
}
#endif
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,4,2)
#define down_write down
#define up_write up
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
#define DRM_PCI_DEV(pdev) &pdev->dev
#else
#define DRM_PCI_DEV(pdev) NULL
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
static inline unsigned iminor(struct inode *inode)
{
return MINOR(inode->i_rdev);
}
#define old_encode_dev(x) (x)
struct drm_sysfs_class;
struct class_simple;
struct device;
#define pci_dev_put(x) do {} while (0)
#define pci_get_subsys pci_find_subsys
static inline struct class_device *DRM(sysfs_device_add) (struct drm_sysfs_class
* cs, dev_t dev,
struct device *
device,
const char *fmt,
...) {
return NULL;
}
static inline void DRM(sysfs_device_remove) (dev_t dev) {
}
static inline void DRM(sysfs_destroy) (struct drm_sysfs_class * cs) {
}
static inline struct drm_sysfs_class *DRM(sysfs_create) (struct module * owner,
char *name) {
return NULL;
}
#ifndef pci_pretty_name
#define pci_pretty_name(x) x->name
#endif
struct drm_device;
static inline int radeon_create_i2c_busses(struct drm_device *dev)
{
return 0;
};
static inline void radeon_delete_i2c_busses(struct drm_device *dev)
{
};
#endif
#ifndef __user #ifndef __user
#define __user #define __user
#endif #endif
@ -178,22 +97,29 @@ static inline void radeon_delete_i2c_busses(struct drm_device *dev)
#define __GFP_COMP 0 #define __GFP_COMP 0
#endif #endif
#ifndef REMAP_PAGE_RANGE_5_ARGS #if !defined(IRQF_SHARED)
#define DRM_RPR_ARG(vma) #define IRQF_SHARED SA_SHIRQ
#else
#define DRM_RPR_ARG(vma) vma,
#endif #endif
#define VM_OFFSET(vma) ((vma)->vm_pgoff << PAGE_SHIFT)
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10) #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
static inline int remap_pfn_range(struct vm_area_struct *vma, unsigned long from, unsigned long pfn, unsigned long size, pgprot_t pgprot) static inline int remap_pfn_range(struct vm_area_struct *vma, unsigned long from, unsigned long pfn, unsigned long size, pgprot_t pgprot)
{ {
return remap_page_range(DRM_RPR_ARG(vma) from, return remap_page_range(vma, from,
pfn << PAGE_SHIFT, pfn << PAGE_SHIFT,
size, size,
pgprot); pgprot);
} }
static __inline__ void *kcalloc(size_t nmemb, size_t size, int flags)
{
void *addr;
addr = kmalloc(size * nmemb, flags);
if (addr != NULL)
memset((void *)addr, 0, size * nmemb);
return addr;
}
#endif #endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16) #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16)
@ -215,10 +141,6 @@ static inline int remap_pfn_range(struct vm_area_struct *vma, unsigned long from
#define __x86_64__ #define __x86_64__
#endif #endif
#ifndef pci_pretty_name
#define pci_pretty_name(dev) ""
#endif
/* sysfs __ATTR macro */ /* sysfs __ATTR macro */
#ifndef __ATTR #ifndef __ATTR
#define __ATTR(_name,_mode,_show,_store) { \ #define __ATTR(_name,_mode,_show,_store) { \
@ -228,14 +150,31 @@ static inline int remap_pfn_range(struct vm_area_struct *vma, unsigned long from
} }
#endif #endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
#define vmalloc_user(_size) ({void * tmp = vmalloc(_size); \
if (tmp) memset(tmp, 0, size); \
(tmp);})
#endif
#ifndef list_for_each_entry_safe_reverse
#define list_for_each_entry_safe_reverse(pos, n, head, member) \
for (pos = list_entry((head)->prev, typeof(*pos), member), \
n = list_entry(pos->member.prev, typeof(*pos), member); \
&pos->member != (head); \
pos = n, n = list_entry(n->member.prev, typeof(*n), member))
#endif
#include <linux/mm.h> #include <linux/mm.h>
#include <asm/page.h> #include <asm/page.h>
#if ((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)) && \ #if ((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)) && \
(LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15))) (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15)))
#define DRM_ODD_MM_COMPAT #define DRM_ODD_MM_COMPAT
#endif #endif
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21))
#define DRM_FULL_MM_COMPAT
#endif
/* /*
@ -253,16 +192,9 @@ extern void drm_clear_vma(struct vm_area_struct *vma,
extern pgprot_t vm_get_page_prot(unsigned long vm_flags); extern pgprot_t vm_get_page_prot(unsigned long vm_flags);
/* #ifndef GFP_DMA32
* These are similar to the current kernel gatt pages allocator, only that we #define GFP_DMA32 0
* want a struct page pointer instead of a virtual address. This allows for pages #endif
* that are not in the kernel linear map.
*/
#define drm_alloc_gatt_pages(order) ({ \
void *_virt = alloc_gatt_pages(order); \
((_virt) ? virt_to_page(_virt) : NULL);})
#define drm_free_gatt_pages(pages, order) free_gatt_pages(page_address(pages), order)
#if defined(CONFIG_X86) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)) #if defined(CONFIG_X86) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15))
@ -280,18 +212,14 @@ extern int drm_map_page_into_agp(struct page *page);
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)) #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15))
extern struct page *get_nopage_retry(void); extern struct page *get_nopage_retry(void);
extern void free_nopage_retry(void); extern void free_nopage_retry(void);
struct fault_data;
extern struct page *drm_vm_ttm_fault(struct vm_area_struct *vma,
struct fault_data *data);
#define NOPAGE_REFAULT get_nopage_retry() #define NOPAGE_REFAULT get_nopage_retry()
#endif #endif
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)) #ifndef DRM_FULL_MM_COMPAT
/* /*
* Hopefully, real NOPAGE_RETRY functionality will be in 2.6.19.
* For now, just return a dummy page that we've allocated out of * For now, just return a dummy page that we've allocated out of
* static space. The page will be put by do_nopage() since we've already * static space. The page will be put by do_nopage() since we've already
* filled out the pte. * filled out the pte.
@ -306,19 +234,20 @@ struct fault_data {
int type; int type;
}; };
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19))
extern int vm_insert_pfn(struct vm_area_struct *vma, unsigned long addr, extern struct page *drm_bo_vm_nopage(struct vm_area_struct *vma,
unsigned long pfn, pgprot_t pgprot); unsigned long address,
int *type);
extern struct page *drm_vm_ttm_nopage(struct vm_area_struct *vma, #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)) && \
unsigned long address, !defined(DRM_FULL_MM_COMPAT)
int *type); extern unsigned long drm_bo_vm_nopfn(struct vm_area_struct *vma,
unsigned long address);
#endif #endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)) */
#endif /* ndef DRM_FULL_MM_COMPAT */
#ifdef DRM_ODD_MM_COMPAT #ifdef DRM_ODD_MM_COMPAT
struct drm_ttm; struct drm_buffer_object;
/* /*
@ -326,14 +255,14 @@ struct drm_ttm;
* process mm pointer to the ttm mm list. Needs the ttm mutex. * process mm pointer to the ttm mm list. Needs the ttm mutex.
*/ */
extern int drm_ttm_add_vma(struct drm_ttm * ttm, extern int drm_bo_add_vma(struct drm_buffer_object * bo,
struct vm_area_struct *vma); struct vm_area_struct *vma);
/* /*
* Delete a vma and the corresponding mm pointer from the * Delete a vma and the corresponding mm pointer from the
* ttm lists. Needs the ttm mutex. * ttm lists. Needs the ttm mutex.
*/ */
extern void drm_ttm_delete_vma(struct drm_ttm * ttm, extern void drm_bo_delete_vma(struct drm_buffer_object * bo,
struct vm_area_struct *vma); struct vm_area_struct *vma);
/* /*
* Attempts to lock all relevant mmap_sems for a ttm, while * Attempts to lock all relevant mmap_sems for a ttm, while
@ -342,12 +271,12 @@ extern void drm_ttm_delete_vma(struct drm_ttm * ttm,
* schedule() and try again. * schedule() and try again.
*/ */
extern int drm_ttm_lock_mm(struct drm_ttm * ttm); extern int drm_bo_lock_kmm(struct drm_buffer_object * bo);
/* /*
* Unlock all relevant mmap_sems for a ttm. * Unlock all relevant mmap_sems for a ttm.
*/ */
extern void drm_ttm_unlock_mm(struct drm_ttm * ttm); extern void drm_bo_unlock_kmm(struct drm_buffer_object * bo);
/* /*
* If the ttm was bound to the aperture, this function shall be called * If the ttm was bound to the aperture, this function shall be called
@ -357,7 +286,7 @@ extern void drm_ttm_unlock_mm(struct drm_ttm * ttm);
* releases the mmap_sems for this ttm. * releases the mmap_sems for this ttm.
*/ */
extern void drm_ttm_finish_unmap(struct drm_ttm *ttm); extern void drm_bo_finish_unmap(struct drm_buffer_object *bo);
/* /*
* Remap all vmas of this ttm using io_remap_pfn_range. We cannot * Remap all vmas of this ttm using io_remap_pfn_range. We cannot
@ -366,14 +295,23 @@ extern void drm_ttm_finish_unmap(struct drm_ttm *ttm);
* releases the mmap_sems for this ttm. * releases the mmap_sems for this ttm.
*/ */
extern int drm_ttm_remap_bound(struct drm_ttm *ttm); extern int drm_bo_remap_bound(struct drm_buffer_object *bo);
/* /*
* Remap a vma for a bound ttm. Call with the ttm mutex held and * Remap a vma for a bound ttm. Call with the ttm mutex held and
* the relevant mmap_sem locked. * the relevant mmap_sem locked.
*/ */
extern int drm_ttm_map_bound(struct vm_area_struct *vma); extern int drm_bo_map_bound(struct vm_area_struct *vma);
#endif #endif
/* fixme when functions are upstreamed */
#define DRM_IDR_COMPAT_FN
#ifdef DRM_IDR_COMPAT_FN
int idr_for_each(struct idr *idp,
int (*fn)(int id, void *p, void *data), void *data);
void idr_remove_all(struct idr *idp);
#endif
#endif #endif

View file

@ -53,25 +53,21 @@
* \param ctx_handle context handle. * \param ctx_handle context handle.
* *
* Clears the bit specified by \p ctx_handle in drm_device::ctx_bitmap and the entry * Clears the bit specified by \p ctx_handle in drm_device::ctx_bitmap and the entry
* in drm_device::context_sareas, while holding the drm_device::struct_mutex * in drm_device::ctx_idr, while holding the drm_device::struct_mutex
* lock. * lock.
*/ */
void drm_ctxbitmap_free(drm_device_t * dev, int ctx_handle) void drm_ctxbitmap_free(drm_device_t * dev, int ctx_handle)
{ {
if (ctx_handle < 0) struct drm_ctx_sarea_list *ctx;
goto failed;
if (!dev->ctx_bitmap)
goto failed;
if (ctx_handle < DRM_MAX_CTXBITMAP) { mutex_lock(&dev->struct_mutex);
mutex_lock(&dev->struct_mutex); ctx = idr_find(&dev->ctx_idr, ctx_handle);
clear_bit(ctx_handle, dev->ctx_bitmap); if (ctx) {
dev->context_sareas[ctx_handle] = NULL; idr_remove(&dev->ctx_idr, ctx_handle);
mutex_unlock(&dev->struct_mutex); drm_free(ctx, sizeof(struct drm_ctx_sarea_list), DRM_MEM_CTXLIST);
return; } else
} DRM_ERROR("Attempt to free invalid context handle: %d\n", ctx_handle);
failed: mutex_unlock(&dev->struct_mutex);
DRM_ERROR("Attempt to free invalid context handle: %d\n", ctx_handle);
return; return;
} }
@ -81,62 +77,34 @@ void drm_ctxbitmap_free(drm_device_t * dev, int ctx_handle)
* \param dev DRM device. * \param dev DRM device.
* \return (non-negative) context handle on success or a negative number on failure. * \return (non-negative) context handle on success or a negative number on failure.
* *
* Find the first zero bit in drm_device::ctx_bitmap and (re)allocates * Allocate a new idr from drm_device::ctx_idr while holding the
* drm_device::context_sareas to accommodate the new entry while holding the
* drm_device::struct_mutex lock. * drm_device::struct_mutex lock.
*/ */
static int drm_ctxbitmap_next(drm_device_t * dev) static int drm_ctxbitmap_next(drm_device_t * dev)
{ {
int bit; int new_id;
int ret;
struct drm_ctx_sarea_list *new_ctx;
if (!dev->ctx_bitmap) new_ctx = drm_calloc(1, sizeof(struct drm_ctx_sarea_list), DRM_MEM_CTXLIST);
if (!new_ctx)
return -1; return -1;
mutex_lock(&dev->struct_mutex); again:
bit = find_first_zero_bit(dev->ctx_bitmap, DRM_MAX_CTXBITMAP); if (idr_pre_get(&dev->ctx_idr, GFP_KERNEL) == 0) {
if (bit < DRM_MAX_CTXBITMAP) { DRM_ERROR("Out of memory expanding drawable idr\n");
set_bit(bit, dev->ctx_bitmap); drm_free(new_ctx, sizeof(struct drm_ctx_sarea_list), DRM_MEM_CTXLIST);
DRM_DEBUG("drm_ctxbitmap_next bit : %d\n", bit); return -ENOMEM;
if ((bit + 1) > dev->max_context) {
dev->max_context = (bit + 1);
if (dev->context_sareas) {
drm_map_t **ctx_sareas;
ctx_sareas = drm_realloc(dev->context_sareas,
(dev->max_context -
1) *
sizeof(*dev->
context_sareas),
dev->max_context *
sizeof(*dev->
context_sareas),
DRM_MEM_MAPS);
if (!ctx_sareas) {
clear_bit(bit, dev->ctx_bitmap);
mutex_unlock(&dev->struct_mutex);
return -1;
}
dev->context_sareas = ctx_sareas;
dev->context_sareas[bit] = NULL;
} else {
/* max_context == 1 at this point */
dev->context_sareas =
drm_alloc(dev->max_context *
sizeof(*dev->context_sareas),
DRM_MEM_MAPS);
if (!dev->context_sareas) {
clear_bit(bit, dev->ctx_bitmap);
mutex_unlock(&dev->struct_mutex);
return -1;
}
dev->context_sareas[bit] = NULL;
}
}
mutex_unlock(&dev->struct_mutex);
return bit;
} }
mutex_lock(&dev->struct_mutex);
ret = idr_get_new_above(&dev->ctx_idr, new_ctx, DRM_RESERVED_CONTEXTS, &new_id);
if (ret == -EAGAIN) {
mutex_unlock(&dev->struct_mutex);
goto again;
}
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
return -1; return new_id;
} }
/** /**
@ -144,31 +112,20 @@ static int drm_ctxbitmap_next(drm_device_t * dev)
* *
* \param dev DRM device. * \param dev DRM device.
* *
* Allocates and initialize drm_device::ctx_bitmap and drm_device::context_sareas, while holding * Initialise the drm_device::ctx_idr
* the drm_device::struct_mutex lock.
*/ */
int drm_ctxbitmap_init(drm_device_t * dev) int drm_ctxbitmap_init(drm_device_t * dev)
{ {
int i; idr_init(&dev->ctx_idr);
int temp; return 0;
}
mutex_lock(&dev->struct_mutex);
dev->ctx_bitmap = (unsigned long *)drm_alloc(PAGE_SIZE,
DRM_MEM_CTXBITMAP);
if (dev->ctx_bitmap == NULL) {
mutex_unlock(&dev->struct_mutex);
return -ENOMEM;
}
memset((void *)dev->ctx_bitmap, 0, PAGE_SIZE);
dev->context_sareas = NULL;
dev->max_context = -1;
mutex_unlock(&dev->struct_mutex);
for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) {
temp = drm_ctxbitmap_next(dev);
DRM_DEBUG("drm_ctxbitmap_init : %d\n", temp);
}
static int drm_ctx_sarea_free(int id, void *p, void *data)
{
struct drm_ctx_sarea_list *ctx_entry = p;
drm_free(ctx_entry, sizeof(struct drm_ctx_sarea_list), DRM_MEM_CTXLIST);
return 0; return 0;
} }
@ -177,17 +134,14 @@ int drm_ctxbitmap_init(drm_device_t * dev)
* *
* \param dev DRM device. * \param dev DRM device.
* *
* Frees drm_device::ctx_bitmap and drm_device::context_sareas, while holding * Free all idr members using drm_ctx_sarea_free helper function
* the drm_device::struct_mutex lock. * while holding the drm_device::struct_mutex lock.
*/ */
void drm_ctxbitmap_cleanup(drm_device_t * dev) void drm_ctxbitmap_cleanup(drm_device_t * dev)
{ {
mutex_lock(&dev->struct_mutex); mutex_lock(&dev->struct_mutex);
if (dev->context_sareas) idr_for_each(&dev->ctx_idr, drm_ctx_sarea_free, NULL);
drm_free(dev->context_sareas, idr_remove_all(&dev->ctx_idr);
sizeof(*dev->context_sareas) *
dev->max_context, DRM_MEM_MAPS);
drm_free((void *)dev->ctx_bitmap, PAGE_SIZE, DRM_MEM_CTXBITMAP);
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
} }
@ -206,7 +160,7 @@ void drm_ctxbitmap_cleanup(drm_device_t * dev)
* \param arg user argument pointing to a drm_ctx_priv_map structure. * \param arg user argument pointing to a drm_ctx_priv_map structure.
* \return zero on success or a negative number on failure. * \return zero on success or a negative number on failure.
* *
* Gets the map from drm_device::context_sareas with the handle specified and * Gets the map from drm_device::ctx_idr with the handle specified and
* returns its handle. * returns its handle.
*/ */
int drm_getsareactx(struct inode *inode, struct file *filp, int drm_getsareactx(struct inode *inode, struct file *filp,
@ -218,22 +172,24 @@ int drm_getsareactx(struct inode *inode, struct file *filp,
drm_ctx_priv_map_t request; drm_ctx_priv_map_t request;
drm_map_t *map; drm_map_t *map;
drm_map_list_t *_entry; drm_map_list_t *_entry;
struct drm_ctx_sarea_list *ctx_sarea;
if (copy_from_user(&request, argp, sizeof(request))) if (copy_from_user(&request, argp, sizeof(request)))
return -EFAULT; return -EFAULT;
mutex_lock(&dev->struct_mutex); mutex_lock(&dev->struct_mutex);
if (dev->max_context < 0
|| request.ctx_id >= (unsigned)dev->max_context) { ctx_sarea = idr_find(&dev->ctx_idr, request.ctx_id);
if (!ctx_sarea) {
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
return -EINVAL; return -EINVAL;
} }
map = ctx_sarea->map;
map = dev->context_sareas[request.ctx_id];
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
request.handle = NULL; request.handle = NULL;
list_for_each_entry(_entry, &dev->maplist->head,head) { list_for_each_entry(_entry, &dev->maplist, head) {
if (_entry->map == map) { if (_entry->map == map) {
request.handle = request.handle =
(void *)(unsigned long)_entry->user_token; (void *)(unsigned long)_entry->user_token;
@ -258,7 +214,7 @@ int drm_getsareactx(struct inode *inode, struct file *filp,
* \return zero on success or a negative number on failure. * \return zero on success or a negative number on failure.
* *
* Searches the mapping specified in \p arg and update the entry in * Searches the mapping specified in \p arg and update the entry in
* drm_device::context_sareas with it. * drm_device::ctx_idr with it.
*/ */
int drm_setsareactx(struct inode *inode, struct file *filp, int drm_setsareactx(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg) unsigned int cmd, unsigned long arg)
@ -268,15 +224,14 @@ int drm_setsareactx(struct inode *inode, struct file *filp,
drm_ctx_priv_map_t request; drm_ctx_priv_map_t request;
drm_map_t *map = NULL; drm_map_t *map = NULL;
drm_map_list_t *r_list = NULL; drm_map_list_t *r_list = NULL;
struct list_head *list; struct drm_ctx_sarea_list *ctx_sarea;
if (copy_from_user(&request, if (copy_from_user(&request,
(drm_ctx_priv_map_t __user *) arg, sizeof(request))) (drm_ctx_priv_map_t __user *) arg, sizeof(request)))
return -EFAULT; return -EFAULT;
mutex_lock(&dev->struct_mutex); mutex_lock(&dev->struct_mutex);
list_for_each(list, &dev->maplist->head) { list_for_each_entry(r_list, &dev->maplist, head) {
r_list = list_entry(list, drm_map_list_t, head);
if (r_list->map if (r_list->map
&& r_list->user_token == (unsigned long) request.handle) && r_list->user_token == (unsigned long) request.handle)
goto found; goto found;
@ -289,11 +244,14 @@ int drm_setsareactx(struct inode *inode, struct file *filp,
map = r_list->map; map = r_list->map;
if (!map) if (!map)
goto bad; goto bad;
if (dev->max_context < 0)
mutex_lock(&dev->struct_mutex);
ctx_sarea = idr_find(&dev->ctx_idr, request.ctx_id);
if (!ctx_sarea)
goto bad; goto bad;
if (request.ctx_id >= (unsigned)dev->max_context)
goto bad; ctx_sarea->map = map;
dev->context_sareas[request.ctx_id] = map;
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
return 0; return 0;
} }
@ -449,7 +407,7 @@ int drm_addctx(struct inode *inode, struct file *filp,
ctx_entry->tag = priv; ctx_entry->tag = priv;
mutex_lock(&dev->ctxlist_mutex); mutex_lock(&dev->ctxlist_mutex);
list_add(&ctx_entry->head, &dev->ctxlist->head); list_add(&ctx_entry->head, &dev->ctxlist);
++dev->ctx_count; ++dev->ctx_count;
mutex_unlock(&dev->ctxlist_mutex); mutex_unlock(&dev->ctxlist_mutex);
@ -575,10 +533,10 @@ int drm_rmctx(struct inode *inode, struct file *filp,
} }
mutex_lock(&dev->ctxlist_mutex); mutex_lock(&dev->ctxlist_mutex);
if (!list_empty(&dev->ctxlist->head)) { if (!list_empty(&dev->ctxlist)) {
drm_ctx_list_t *pos, *n; drm_ctx_list_t *pos, *n;
list_for_each_entry_safe(pos, n, &dev->ctxlist->head, head) { list_for_each_entry_safe(pos, n, &dev->ctxlist, head) {
if (pos->handle == ctx.handle) { if (pos->handle == ctx.handle) {
list_del(&pos->head); list_del(&pos->head);
drm_free(pos, sizeof(*pos), DRM_MEM_CTXLIST); drm_free(pos, sizeof(*pos), DRM_MEM_CTXLIST);

212
linux-core/drm_drawable.c Normal file
View file

@ -0,0 +1,212 @@
/**
* \file drm_drawable.c
* IOCTLs for drawables
*
* \author Rickard E. (Rik) Faith <faith@valinux.com>
* \author Gareth Hughes <gareth@valinux.com>
* \author Michel Dänzer <michel@tungstengraphics.com>
*/
/*
* Created: Tue Feb 2 08:37:54 1999 by faith@valinux.com
*
* Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
* Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
* Copyright 2006 Tungsten Graphics, Inc., Bismarck, North Dakota.
* 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
* VA LINUX SYSTEMS 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"
/**
* Allocate drawable ID and memory to store information about it.
*/
int drm_adddraw(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
unsigned long irqflags;
struct drm_drawable_list *draw_info;
drm_draw_t draw;
int new_id = 0;
int ret;
draw_info = drm_calloc(1, sizeof(struct drm_drawable_list), DRM_MEM_BUFS);
if (!draw_info)
return -ENOMEM;
again:
if (idr_pre_get(&dev->drw_idr, GFP_KERNEL) == 0) {
DRM_ERROR("Out of memory expanding drawable idr\n");
drm_free(draw_info, sizeof(struct drm_drawable_list), DRM_MEM_BUFS);
return -ENOMEM;
}
spin_lock_irqsave(&dev->drw_lock, irqflags);
ret = idr_get_new_above(&dev->drw_idr, draw_info, 1, &new_id);
if (ret == -EAGAIN) {
spin_unlock_irqrestore(&dev->drw_lock, irqflags);
goto again;
}
spin_unlock_irqrestore(&dev->drw_lock, irqflags);
draw.handle = new_id;
DRM_DEBUG("%d\n", draw.handle);
DRM_COPY_TO_USER_IOCTL((drm_draw_t __user *)data, draw, sizeof(draw));
return 0;
}
/**
* Free drawable ID and memory to store information about it.
*/
int drm_rmdraw(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_draw_t draw;
unsigned long irqflags;
struct drm_drawable_list *draw_info;
DRM_COPY_FROM_USER_IOCTL(draw, (drm_draw_t __user *) data,
sizeof(draw));
draw_info = idr_find(&dev->drw_idr, draw.handle);
if (!draw_info) {
DRM_DEBUG("No such drawable %d\n", draw.handle);
return -EINVAL;
}
spin_lock_irqsave(&dev->drw_lock, irqflags);
idr_remove(&dev->drw_idr, draw.handle);
drm_free(draw_info, sizeof(struct drm_drawable_list), DRM_MEM_BUFS);
spin_unlock_irqrestore(&dev->drw_lock, irqflags);
DRM_DEBUG("%d\n", draw.handle);
return 0;
}
int drm_update_drawable_info(DRM_IOCTL_ARGS) {
DRM_DEVICE;
drm_update_draw_t update;
unsigned long irqflags;
drm_drawable_info_t *info;
drm_clip_rect_t *rects;
struct drm_drawable_list *draw_info;
int err;
DRM_COPY_FROM_USER_IOCTL(update, (drm_update_draw_t __user *) data,
sizeof(update));
draw_info = idr_find(&dev->drw_idr, update.handle);
if (!draw_info) {
DRM_ERROR("No such drawable %d\n", update.handle);
return DRM_ERR(EINVAL);
}
info = &draw_info->info;
switch (update.type) {
case DRM_DRAWABLE_CLIPRECTS:
if (update.num != info->num_rects) {
rects = drm_alloc(update.num * sizeof(drm_clip_rect_t),
DRM_MEM_BUFS);
} else
rects = info->rects;
if (update.num && !rects) {
DRM_ERROR("Failed to allocate cliprect memory\n");
err = DRM_ERR(ENOMEM);
goto error;
}
if (update.num && DRM_COPY_FROM_USER(rects,
(drm_clip_rect_t __user *)
(unsigned long)update.data,
update.num *
sizeof(*rects))) {
DRM_ERROR("Failed to copy cliprects from userspace\n");
err = DRM_ERR(EFAULT);
goto error;
}
spin_lock_irqsave(&dev->drw_lock, irqflags);
if (rects != info->rects) {
drm_free(info->rects, info->num_rects *
sizeof(drm_clip_rect_t), DRM_MEM_BUFS);
}
info->rects = rects;
info->num_rects = update.num;
spin_unlock_irqrestore(&dev->drw_lock, irqflags);
DRM_DEBUG("Updated %d cliprects for drawable %d\n",
info->num_rects, update.handle);
break;
default:
DRM_ERROR("Invalid update type %d\n", update.type);
return DRM_ERR(EINVAL);
}
return 0;
error:
if (rects != info->rects)
drm_free(rects, update.num * sizeof(drm_clip_rect_t),
DRM_MEM_BUFS);
return err;
}
/**
* Caller must hold the drawable spinlock!
*/
drm_drawable_info_t *drm_get_drawable_info(drm_device_t *dev, drm_drawable_t id) {
struct drm_drawable_list *draw_info;
draw_info = idr_find(&dev->drw_idr, id);
if (!draw_info) {
DRM_DEBUG("No such drawable %d\n", id);
return NULL;
}
return &draw_info->info;
}
EXPORT_SYMBOL(drm_get_drawable_info);
static int drm_drawable_free(int idr, void *p, void *data)
{
struct drm_drawable_list *drw_entry = p;
drm_free(drw_entry->info.rects, drw_entry->info.num_rects *
sizeof(drm_clip_rect_t), DRM_MEM_BUFS);
drm_free(drw_entry, sizeof(struct drm_drawable_list), DRM_MEM_BUFS);
return 0;
}
void drm_drawable_free_all(drm_device_t *dev)
{
idr_for_each(&dev->drw_idr, drm_drawable_free, NULL);
idr_remove_all(&dev->drw_idr);
}

View file

@ -15,8 +15,6 @@
* #define DRIVER_DESC "Matrox G200/G400" * #define DRIVER_DESC "Matrox G200/G400"
* #define DRIVER_DATE "20001127" * #define DRIVER_DATE "20001127"
* *
* #define DRIVER_IOCTL_COUNT DRM_ARRAY_SIZE( mga_ioctls )
*
* #define drm_x mga_##x * #define drm_x mga_##x
* \endcode * \endcode
*/ */
@ -127,7 +125,7 @@ static drm_ioctl_desc_t drm_ioctls[] = {
[DRM_IOCTL_NR(DRM_IOCTL_UPDATE_DRAW)] = {drm_update_drawable_info, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, [DRM_IOCTL_NR(DRM_IOCTL_UPDATE_DRAW)] = {drm_update_drawable_info, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
}; };
#define DRIVER_IOCTL_COUNT ARRAY_SIZE( drm_ioctls ) #define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls )
/** /**
@ -142,16 +140,17 @@ static drm_ioctl_desc_t drm_ioctls[] = {
int drm_lastclose(drm_device_t * dev) int drm_lastclose(drm_device_t * dev)
{ {
drm_magic_entry_t *pt, *next; drm_magic_entry_t *pt, *next;
drm_map_list_t *r_list; drm_map_list_t *r_list, *list_t;
drm_vma_entry_t *vma, *vma_next; drm_vma_entry_t *vma, *vma_temp;
int i; int i;
DRM_DEBUG("\n"); DRM_DEBUG("\n");
if (drm_bo_driver_finish(dev)) { /*
DRM_ERROR("DRM memory manager still busy. " * We can't do much about this function failing.
"System is unstable. Please reboot.\n"); */
}
drm_bo_driver_finish(dev);
if (dev->driver->lastclose) if (dev->driver->lastclose)
dev->driver->lastclose(dev); dev->driver->lastclose(dev);
@ -167,18 +166,9 @@ int drm_lastclose(drm_device_t * dev)
drm_irq_uninstall(dev); drm_irq_uninstall(dev);
/* Free drawable information memory */ /* Free drawable information memory */
for (i = 0; i < dev->drw_bitfield_length / sizeof(*dev->drw_bitfield);
i++) {
drm_drawable_info_t *info = drm_get_drawable_info(dev, i);
if (info) {
drm_free(info->rects, info->num_rects *
sizeof(drm_clip_rect_t), DRM_MEM_BUFS);
drm_free(info, sizeof(*info), DRM_MEM_BUFS);
}
}
mutex_lock(&dev->struct_mutex); mutex_lock(&dev->struct_mutex);
drm_drawable_free_all(dev);
del_timer(&dev->timer); del_timer(&dev->timer);
if (dev->unique) { if (dev->unique) {
@ -199,19 +189,17 @@ int drm_lastclose(drm_device_t * dev)
/* Clear AGP information */ /* Clear AGP information */
if (drm_core_has_AGP(dev) && dev->agp) { if (drm_core_has_AGP(dev) && dev->agp) {
drm_agp_mem_t *entry; drm_agp_mem_t *entry, *tempe;
drm_agp_mem_t *nexte;
/* Remove AGP resources, but leave dev->agp /* Remove AGP resources, but leave dev->agp
intact until drv_cleanup is called. */ intact until drv_cleanup is called. */
for (entry = dev->agp->memory; entry; entry = nexte) { list_for_each_entry_safe(entry, tempe, &dev->agp->memory, head) {
nexte = entry->next;
if (entry->bound) if (entry->bound)
drm_unbind_agp(entry->memory); drm_unbind_agp(entry->memory);
drm_free_agp(entry->memory, entry->pages); drm_free_agp(entry->memory, entry->pages);
drm_free(entry, sizeof(*entry), DRM_MEM_AGPLISTS); drm_free(entry, sizeof(*entry), DRM_MEM_AGPLISTS);
} }
dev->agp->memory = NULL; INIT_LIST_HEAD(&dev->agp->memory);
if (dev->agp->acquired) if (dev->agp->acquired)
drm_agp_release(dev); drm_agp_release(dev);
@ -225,20 +213,14 @@ int drm_lastclose(drm_device_t * dev)
} }
/* Clear vma list (only built for debugging) */ /* Clear vma list (only built for debugging) */
if (dev->vmalist) { list_for_each_entry_safe(vma, vma_temp, &dev->vmalist, head) {
for (vma = dev->vmalist; vma; vma = vma_next) { list_del(&vma->head);
vma_next = vma->next; drm_ctl_free(vma, sizeof(*vma), DRM_MEM_VMAS);
drm_ctl_free(vma, sizeof(*vma), DRM_MEM_VMAS);
}
dev->vmalist = NULL;
} }
if (dev->maplist) { list_for_each_entry_safe(r_list, list_t, &dev->maplist, head) {
while (!list_empty(&dev->maplist->head)) { drm_rmmap_locked(dev, r_list->map);
struct list_head *list = dev->maplist->head.next; r_list = NULL;
r_list = list_entry(list, drm_map_list_t, head);
drm_rmmap_locked(dev, r_list->map);
}
} }
if (drm_core_check_feature(dev, DRIVER_DMA_QUEUE) && dev->queuelist) { if (drm_core_check_feature(dev, DRIVER_DMA_QUEUE) && dev->queuelist) {
@ -373,13 +355,9 @@ static void drm_cleanup(drm_device_t * dev)
drm_lastclose(dev); drm_lastclose(dev);
drm_fence_manager_takedown(dev); drm_fence_manager_takedown(dev);
if (dev->maplist) { drm_ht_remove(&dev->map_hash);
drm_free(dev->maplist, sizeof(*dev->maplist), DRM_MEM_MAPS); drm_mm_takedown(&dev->offset_manager);
dev->maplist = NULL; drm_ht_remove(&dev->object_hash);
drm_ht_remove(&dev->map_hash);
drm_mm_takedown(&dev->offset_manager);
drm_ht_remove(&dev->object_hash);
}
if (!drm_fb_loaded) if (!drm_fb_loaded)
pci_disable_device(dev->pdev); pci_disable_device(dev->pdev);
@ -441,67 +419,37 @@ void drm_exit(struct drm_driver *driver)
EXPORT_SYMBOL(drm_exit); EXPORT_SYMBOL(drm_exit);
/** File operations structure */ /** File operations structure */
static struct file_operations drm_stub_fops = { static const struct file_operations drm_stub_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.open = drm_stub_open .open = drm_stub_open
}; };
static int drm_create_memory_caches(void)
{
drm_cache.mm = kmem_cache_create("drm_mm_node_t",
sizeof(drm_mm_node_t),
0,
SLAB_HWCACHE_ALIGN,
NULL,NULL);
if (!drm_cache.mm)
return -ENOMEM;
drm_cache.fence_object= kmem_cache_create("drm_fence_object_t",
sizeof(drm_fence_object_t),
0,
SLAB_HWCACHE_ALIGN,
NULL,NULL);
if (!drm_cache.fence_object)
return -ENOMEM;
return 0;
}
static void drm_free_mem_cache(kmem_cache_t *cache,
const char *name)
{
if (!cache)
return;
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19))
if (kmem_cache_destroy(cache)) {
DRM_ERROR("Warning! DRM is leaking %s memory.\n",
name);
}
#else
kmem_cache_destroy(cache);
#endif
}
static void drm_free_memory_caches(void )
{
drm_free_mem_cache(drm_cache.fence_object, "fence object");
drm_cache.fence_object = NULL;
drm_free_mem_cache(drm_cache.mm, "memory manager block");
drm_cache.mm = NULL;
}
static int __init drm_core_init(void) static int __init drm_core_init(void)
{ {
int ret; int ret;
struct sysinfo si; struct sysinfo si;
unsigned long avail_memctl_mem;
unsigned long max_memctl_mem;
si_meminfo(&si); si_meminfo(&si);
drm_init_memctl(si.totalram/2, si.totalram*3/4);
ret = drm_create_memory_caches(); /*
if (ret) * AGP only allows low / DMA32 memory ATM.
goto err_p1; */
avail_memctl_mem = si.totalram - si.totalhigh;
/*
* Avoid overflows
*/
max_memctl_mem = 1UL << (32 - PAGE_SHIFT);
max_memctl_mem = (max_memctl_mem / si.mem_unit) * PAGE_SIZE;
if (avail_memctl_mem >= max_memctl_mem)
avail_memctl_mem = max_memctl_mem;
drm_init_memctl(avail_memctl_mem/2, avail_memctl_mem*3/4, si.mem_unit);
ret = -ENOMEM; ret = -ENOMEM;
drm_cards_limit = drm_cards_limit =
@ -539,13 +487,11 @@ err_p2:
unregister_chrdev(DRM_MAJOR, "drm"); unregister_chrdev(DRM_MAJOR, "drm");
drm_free(drm_heads, sizeof(*drm_heads) * drm_cards_limit, DRM_MEM_STUB); drm_free(drm_heads, sizeof(*drm_heads) * drm_cards_limit, DRM_MEM_STUB);
err_p1: err_p1:
drm_free_memory_caches();
return ret; return ret;
} }
static void __exit drm_core_exit(void) static void __exit drm_core_exit(void)
{ {
drm_free_memory_caches();
remove_proc_entry("dri", NULL); remove_proc_entry("dri", NULL);
drm_sysfs_destroy(drm_class); drm_sysfs_destroy(drm_class);
@ -622,21 +568,20 @@ int drm_ioctl(struct inode *inode, struct file *filp,
current->pid, cmd, nr, (long)old_encode_dev(priv->head->device), current->pid, cmd, nr, (long)old_encode_dev(priv->head->device),
priv->authenticated); priv->authenticated);
if (nr >= DRIVER_IOCTL_COUNT && if ((nr >= DRM_CORE_IOCTL_COUNT) &&
(nr < DRM_COMMAND_BASE || nr >= DRM_COMMAND_END)) ((nr < DRM_COMMAND_BASE) || (nr >= DRM_COMMAND_END)))
goto err_i1; goto err_i1;
if ((nr >= DRM_COMMAND_BASE) && (nr < DRM_COMMAND_END) if ((nr >= DRM_COMMAND_BASE) && (nr < DRM_COMMAND_END)
&& (nr < DRM_COMMAND_BASE + dev->driver->num_ioctls)) && (nr < DRM_COMMAND_BASE + dev->driver->num_ioctls))
ioctl = &dev->driver->ioctls[nr - DRM_COMMAND_BASE]; ioctl = &dev->driver->ioctls[nr - DRM_COMMAND_BASE];
else if (nr >= DRM_COMMAND_END || nr < DRM_COMMAND_BASE) else if ((nr >= DRM_COMMAND_END) || (nr < DRM_COMMAND_BASE))
ioctl = &drm_ioctls[nr]; ioctl = &drm_ioctls[nr];
else else
goto err_i1; goto err_i1;
func = ioctl->func; func = ioctl->func;
if ((nr == DRM_IOCTL_NR(DRM_IOCTL_DMA)) && dev->driver->dma_ioctl) /* Local override? */ /* is there a local override? */
if ((nr == DRM_IOCTL_NR(DRM_IOCTL_DMA)) && dev->driver->dma_ioctl)
func = dev->driver->dma_ioctl; func = dev->driver->dma_ioctl;
if (!func) { if (!func) {
@ -656,3 +601,17 @@ err_i1:
return retcode; return retcode;
} }
EXPORT_SYMBOL(drm_ioctl); EXPORT_SYMBOL(drm_ioctl);
drm_local_map_t *drm_getsarea(struct drm_device *dev)
{
drm_map_list_t *entry;
list_for_each_entry(entry, &dev->maplist, head) {
if (entry->map && entry->map->type == _DRM_SHM &&
(entry->map->flags & _DRM_CONTAINS_LOCK)) {
return entry->map;
}
}
return NULL;
}
EXPORT_SYMBOL(drm_getsarea);

View file

@ -1,8 +1,8 @@
/************************************************************************** /**************************************************************************
* *
* Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA * Copyright (c) 2006-2007 Tungsten Graphics, Inc., Cedar Park, TX., USA
* All Rights Reserved. * All Rights Reserved.
* *
* Permission is hereby granted, free of charge, to any person obtaining a * Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the * copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including * "Software"), to deal in the Software without restriction, including
@ -10,20 +10,19 @@
* distribute, sub license, and/or sell copies of the Software, and to * 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 * permit persons to whom the Software is furnished to do so, subject to
* the following conditions: * 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 * The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions * next paragraph) shall be included in all copies or substantial portions
* of the Software. * 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> * Authors: Thomas Hellström <thomas-at-tungstengraphics-dot-com>
@ -35,21 +34,40 @@
* Typically called by the IRQ handler. * Typically called by the IRQ handler.
*/ */
void drm_fence_handler(drm_device_t * dev, uint32_t sequence, uint32_t type) void drm_fence_handler(drm_device_t * dev, uint32_t class,
uint32_t sequence, uint32_t type)
{ {
int wake = 0; int wake = 0;
uint32_t diff; uint32_t diff;
uint32_t relevant; uint32_t relevant;
drm_fence_manager_t *fm = &dev->fm; drm_fence_manager_t *fm = &dev->fm;
drm_fence_class_manager_t *fc = &fm->class[class];
drm_fence_driver_t *driver = dev->driver->fence_driver; drm_fence_driver_t *driver = dev->driver->fence_driver;
struct list_head *list, *prev; struct list_head *head;
drm_fence_object_t *fence; drm_fence_object_t *fence, *next;
int found = 0; int found = 0;
int is_exe = (type & DRM_FENCE_TYPE_EXE);
int ge_last_exe;
if (list_empty(&fm->ring)) diff = (sequence - fc->exe_flush_sequence) & driver->sequence_mask;
if (fc->pending_exe_flush && is_exe && diff < driver->wrap_diff)
fc->pending_exe_flush = 0;
diff = (sequence - fc->last_exe_flush) & driver->sequence_mask;
ge_last_exe = diff < driver->wrap_diff;
if (ge_last_exe)
fc->pending_flush &= ~type;
if (is_exe && ge_last_exe) {
fc->last_exe_flush = sequence;
}
if (list_empty(&fc->ring))
return; return;
list_for_each_entry(fence, &fm->ring, ring) { list_for_each_entry(fence, &fc->ring, ring) {
diff = (sequence - fence->sequence) & driver->sequence_mask; diff = (sequence - fence->sequence) & driver->sequence_mask;
if (diff > driver->wrap_diff) { if (diff > driver->wrap_diff) {
found = 1; found = 1;
@ -57,11 +75,11 @@ void drm_fence_handler(drm_device_t * dev, uint32_t sequence, uint32_t type)
} }
} }
list = (found) ? fence->ring.prev : fm->ring.prev; head = (found) ? &fence->ring : &fc->ring;
prev = list->prev;
for (; list != &fm->ring; list = prev, prev = list->prev) { list_for_each_entry_safe_reverse(fence, next, head, ring) {
fence = list_entry(list, drm_fence_object_t, ring); if (&fence->ring == &fc->ring)
break;
type |= fence->native_type; type |= fence->native_type;
relevant = type & fence->type; relevant = type & fence->type;
@ -78,7 +96,7 @@ void drm_fence_handler(drm_device_t * dev, uint32_t sequence, uint32_t type)
~(fence->signaled | fence->submitted_flush); ~(fence->signaled | fence->submitted_flush);
if (relevant) { if (relevant) {
fm->pending_flush |= relevant; fc->pending_flush |= relevant;
fence->submitted_flush = fence->flush_mask; fence->submitted_flush = fence->flush_mask;
} }
@ -87,11 +105,10 @@ void drm_fence_handler(drm_device_t * dev, uint32_t sequence, uint32_t type)
fence->base.hash.key); fence->base.hash.key);
list_del_init(&fence->ring); list_del_init(&fence->ring);
} }
} }
if (wake) { if (wake) {
DRM_WAKEUP(&fm->fence_queue); DRM_WAKEUP(&fc->fence_queue);
} }
} }
@ -112,13 +129,15 @@ void drm_fence_usage_deref_locked(drm_device_t * dev,
{ {
drm_fence_manager_t *fm = &dev->fm; drm_fence_manager_t *fm = &dev->fm;
DRM_ASSERT_LOCKED(&dev->struct_mutex);
if (atomic_dec_and_test(&fence->usage)) { if (atomic_dec_and_test(&fence->usage)) {
drm_fence_unring(dev, &fence->ring); drm_fence_unring(dev, &fence->ring);
DRM_DEBUG("Destroyed a fence object 0x%08lx\n", DRM_DEBUG("Destroyed a fence object 0x%08lx\n",
fence->base.hash.key); fence->base.hash.key);
atomic_dec(&fm->count); atomic_dec(&fm->count);
drm_ctl_cache_free(drm_cache.fence_object, sizeof(*fence), BUG_ON(!list_empty(&fence->base.list));
fence); drm_ctl_free(fence, sizeof(*fence), DRM_MEM_FENCE);
} }
} }
@ -132,8 +151,8 @@ void drm_fence_usage_deref_unlocked(drm_device_t * dev,
if (atomic_read(&fence->usage) == 0) { if (atomic_read(&fence->usage) == 0) {
drm_fence_unring(dev, &fence->ring); drm_fence_unring(dev, &fence->ring);
atomic_dec(&fm->count); atomic_dec(&fm->count);
drm_ctl_cache_free(drm_cache.fence_object, BUG_ON(!list_empty(&fence->base.list));
sizeof(*fence), fence); drm_ctl_free(fence, sizeof(*fence), DRM_MEM_FENCE);
} }
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
} }
@ -149,7 +168,7 @@ static void drm_fence_object_destroy(drm_file_t * priv,
drm_fence_usage_deref_locked(dev, fence); drm_fence_usage_deref_locked(dev, fence);
} }
static int fence_signaled(drm_device_t * dev, volatile int drm_fence_object_signaled(drm_device_t * dev,
drm_fence_object_t * fence, drm_fence_object_t * fence,
uint32_t mask, int poke_flush) uint32_t mask, int poke_flush)
{ {
@ -159,7 +178,7 @@ static int fence_signaled(drm_device_t * dev, volatile
drm_fence_driver_t *driver = dev->driver->fence_driver; drm_fence_driver_t *driver = dev->driver->fence_driver;
if (poke_flush) if (poke_flush)
driver->poke_flush(dev); driver->poke_flush(dev, fence->class);
read_lock_irqsave(&fm->lock, flags); read_lock_irqsave(&fm->lock, flags);
signaled = signaled =
(fence->type & mask & fence->signaled) == (fence->type & mask); (fence->type & mask & fence->signaled) == (fence->type & mask);
@ -168,52 +187,29 @@ static int fence_signaled(drm_device_t * dev, volatile
return signaled; return signaled;
} }
static void drm_fence_flush_exe(drm_fence_manager_t * fm, static void drm_fence_flush_exe(drm_fence_class_manager_t * fc,
drm_fence_driver_t * driver, uint32_t sequence) drm_fence_driver_t * driver, uint32_t sequence)
{ {
uint32_t diff; uint32_t diff;
if (!fm->pending_exe_flush) { if (!fc->pending_exe_flush) {
volatile struct list_head *list; fc->exe_flush_sequence = sequence;
fc->pending_exe_flush = 1;
/*
* Last_exe_flush is invalid. Find oldest sequence.
*/
/* list = fm->fence_types[_DRM_FENCE_TYPE_EXE];*/
list = &fm->ring;
if (list->next == &fm->ring) {
return;
} else {
drm_fence_object_t *fence =
list_entry(list->next, drm_fence_object_t, ring);
fm->last_exe_flush = (fence->sequence - 1) &
driver->sequence_mask;
}
diff = (sequence - fm->last_exe_flush) & driver->sequence_mask;
if (diff >= driver->wrap_diff)
return;
fm->exe_flush_sequence = sequence;
fm->pending_exe_flush = 1;
} else { } else {
diff = diff =
(sequence - fm->exe_flush_sequence) & driver->sequence_mask; (sequence - fc->exe_flush_sequence) & driver->sequence_mask;
if (diff < driver->wrap_diff) { if (diff < driver->wrap_diff) {
fm->exe_flush_sequence = sequence; fc->exe_flush_sequence = sequence;
} }
} }
} }
int drm_fence_object_signaled(volatile drm_fence_object_t * fence,
uint32_t type)
{
return ((fence->signaled & type) == type);
}
int drm_fence_object_flush(drm_device_t * dev, int drm_fence_object_flush(drm_device_t * dev,
volatile drm_fence_object_t * fence, uint32_t type) drm_fence_object_t * fence,
uint32_t type)
{ {
drm_fence_manager_t *fm = &dev->fm; drm_fence_manager_t *fm = &dev->fm;
drm_fence_class_manager_t *fc = &fm->class[fence->class];
drm_fence_driver_t *driver = dev->driver->fence_driver; drm_fence_driver_t *driver = dev->driver->fence_driver;
unsigned long flags; unsigned long flags;
@ -228,16 +224,16 @@ int drm_fence_object_flush(drm_device_t * dev,
if (fence->submitted_flush == fence->signaled) { if (fence->submitted_flush == fence->signaled) {
if ((fence->type & DRM_FENCE_TYPE_EXE) && if ((fence->type & DRM_FENCE_TYPE_EXE) &&
!(fence->submitted_flush & DRM_FENCE_TYPE_EXE)) { !(fence->submitted_flush & DRM_FENCE_TYPE_EXE)) {
drm_fence_flush_exe(fm, driver, fence->sequence); drm_fence_flush_exe(fc, driver, fence->sequence);
fence->submitted_flush |= DRM_FENCE_TYPE_EXE; fence->submitted_flush |= DRM_FENCE_TYPE_EXE;
} else { } else {
fm->pending_flush |= (fence->flush_mask & fc->pending_flush |= (fence->flush_mask &
~fence->submitted_flush); ~fence->submitted_flush);
fence->submitted_flush = fence->flush_mask; fence->submitted_flush = fence->flush_mask;
} }
} }
write_unlock_irqrestore(&fm->lock, flags); write_unlock_irqrestore(&fm->lock, flags);
driver->poke_flush(dev); driver->poke_flush(dev, fence->class);
return 0; return 0;
} }
@ -246,24 +242,35 @@ int drm_fence_object_flush(drm_device_t * dev,
* wrapped around and reused. * wrapped around and reused.
*/ */
void drm_fence_flush_old(drm_device_t * dev, uint32_t sequence) void drm_fence_flush_old(drm_device_t * dev, uint32_t class, uint32_t sequence)
{ {
drm_fence_manager_t *fm = &dev->fm; drm_fence_manager_t *fm = &dev->fm;
drm_fence_class_manager_t *fc = &fm->class[class];
drm_fence_driver_t *driver = dev->driver->fence_driver; drm_fence_driver_t *driver = dev->driver->fence_driver;
uint32_t old_sequence; uint32_t old_sequence;
unsigned long flags; unsigned long flags;
drm_fence_object_t *fence; drm_fence_object_t *fence;
uint32_t diff; uint32_t diff;
write_lock_irqsave(&fm->lock, flags);
old_sequence = (sequence - driver->flush_diff) & driver->sequence_mask;
diff = (old_sequence - fc->last_exe_flush) & driver->sequence_mask;
if ((diff < driver->wrap_diff) && !fc->pending_exe_flush) {
fc->pending_exe_flush = 1;
fc->exe_flush_sequence = sequence - (driver->flush_diff / 2);
}
write_unlock_irqrestore(&fm->lock, flags);
mutex_lock(&dev->struct_mutex); mutex_lock(&dev->struct_mutex);
read_lock_irqsave(&fm->lock, flags); read_lock_irqsave(&fm->lock, flags);
if (fm->ring.next == &fm->ring) {
if (list_empty(&fc->ring)) {
read_unlock_irqrestore(&fm->lock, flags); read_unlock_irqrestore(&fm->lock, flags);
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
return; return;
} }
old_sequence = (sequence - driver->flush_diff) & driver->sequence_mask; fence = list_entry(fc->ring.next, drm_fence_object_t, ring);
fence = list_entry(fm->ring.next, drm_fence_object_t, ring);
atomic_inc(&fence->usage); atomic_inc(&fence->usage);
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
diff = (old_sequence - fence->sequence) & driver->sequence_mask; diff = (old_sequence - fence->sequence) & driver->sequence_mask;
@ -276,11 +283,44 @@ void drm_fence_flush_old(drm_device_t * dev, uint32_t sequence)
EXPORT_SYMBOL(drm_fence_flush_old); EXPORT_SYMBOL(drm_fence_flush_old);
int drm_fence_object_wait(drm_device_t * dev, static int drm_fence_lazy_wait(drm_device_t *dev,
volatile drm_fence_object_t * fence, drm_fence_object_t *fence,
int lazy, int ignore_signals, uint32_t mask) int ignore_signals,
uint32_t mask)
{ {
drm_fence_manager_t *fm = &dev->fm; drm_fence_manager_t *fm = &dev->fm;
drm_fence_class_manager_t *fc = &fm->class[fence->class];
int signaled;
unsigned long _end = jiffies + 3*DRM_HZ;
int ret = 0;
do {
DRM_WAIT_ON(ret, fc->fence_queue, 3 * DRM_HZ,
(signaled = drm_fence_object_signaled(dev, fence, mask, 1)));
if (signaled)
return 0;
if (time_after_eq(jiffies, _end))
break;
} while (ret == -EINTR && ignore_signals);
if (drm_fence_object_signaled(dev, fence, mask, 0))
return 0;
if (time_after_eq(jiffies, _end))
ret = -EBUSY;
if (ret) {
if (ret == -EBUSY) {
DRM_ERROR("Fence timeout. "
"GPU lockup or fence driver was "
"taken down.\n");
}
return ((ret == -EINTR) ? -EAGAIN : ret);
}
return 0;
}
int drm_fence_object_wait(drm_device_t * dev,
drm_fence_object_t * fence,
int lazy, int ignore_signals, uint32_t mask)
{
drm_fence_driver_t *driver = dev->driver->fence_driver; drm_fence_driver_t *driver = dev->driver->fence_driver;
int ret = 0; int ret = 0;
unsigned long _end; unsigned long _end;
@ -292,7 +332,7 @@ int drm_fence_object_wait(drm_device_t * dev,
return -EINVAL; return -EINVAL;
} }
if (fence_signaled(dev, fence, mask, 0)) if (drm_fence_object_signaled(dev, fence, mask, 0))
return 0; return 0;
_end = jiffies + 3 * DRM_HZ; _end = jiffies + 3 * DRM_HZ;
@ -301,44 +341,29 @@ int drm_fence_object_wait(drm_device_t * dev,
if (lazy && driver->lazy_capable) { if (lazy && driver->lazy_capable) {
do { ret = drm_fence_lazy_wait(dev, fence, ignore_signals, mask);
DRM_WAIT_ON(ret, fm->fence_queue, 3 * DRM_HZ,
fence_signaled(dev, fence, mask, 1));
if (time_after_eq(jiffies, _end))
break;
} while (ret == -EINTR && ignore_signals);
if (time_after_eq(jiffies, _end) && (ret != 0))
ret = -EBUSY;
if (ret) {
if (ret == -EBUSY) {
DRM_ERROR("Fence timeout. "
"GPU lockup or fence driver was "
"taken down.\n");
}
return ((ret == -EINTR) ? -EAGAIN : ret);
}
} else if ((fence->class == 0) && (mask & DRM_FENCE_TYPE_EXE) &&
driver->lazy_capable) {
/*
* We use IRQ wait for EXE fence if available to gain
* CPU in some cases.
*/
do {
DRM_WAIT_ON(ret, fm->fence_queue, 3 * DRM_HZ,
fence_signaled(dev, fence,
DRM_FENCE_TYPE_EXE, 1));
if (time_after_eq(jiffies, _end))
break;
} while (ret == -EINTR && ignore_signals);
if (time_after_eq(jiffies, _end) && (ret != 0))
ret = -EBUSY;
if (ret) if (ret)
return ((ret == -EINTR) ? -EAGAIN : ret); return ret;
}
if (fence_signaled(dev, fence, mask, 0)) } else {
if (driver->has_irq(dev, fence->class,
DRM_FENCE_TYPE_EXE)) {
ret = drm_fence_lazy_wait(dev, fence, ignore_signals,
DRM_FENCE_TYPE_EXE);
if (ret)
return ret;
}
if (driver->has_irq(dev, fence->class,
mask & ~DRM_FENCE_TYPE_EXE)) {
ret = drm_fence_lazy_wait(dev, fence, ignore_signals,
mask);
if (ret)
return ret;
}
}
if (drm_fence_object_signaled(dev, fence, mask, 0))
return 0; return 0;
/* /*
@ -350,7 +375,7 @@ int drm_fence_object_wait(drm_device_t * dev,
#endif #endif
do { do {
schedule(); schedule();
signaled = fence_signaled(dev, fence, mask, 1); signaled = drm_fence_object_signaled(dev, fence, mask, 1);
} while (!signaled && !time_after_eq(jiffies, _end)); } while (!signaled && !time_after_eq(jiffies, _end));
if (!signaled) if (!signaled)
@ -360,33 +385,38 @@ int drm_fence_object_wait(drm_device_t * dev,
} }
int drm_fence_object_emit(drm_device_t * dev, drm_fence_object_t * fence, int drm_fence_object_emit(drm_device_t * dev, drm_fence_object_t * fence,
uint32_t fence_flags, uint32_t type) uint32_t fence_flags, uint32_t class, uint32_t type)
{ {
drm_fence_manager_t *fm = &dev->fm; drm_fence_manager_t *fm = &dev->fm;
drm_fence_driver_t *driver = dev->driver->fence_driver; drm_fence_driver_t *driver = dev->driver->fence_driver;
drm_fence_class_manager_t *fc = &fm->class[fence->class];
unsigned long flags; unsigned long flags;
uint32_t sequence; uint32_t sequence;
uint32_t native_type; uint32_t native_type;
int ret; int ret;
drm_fence_unring(dev, &fence->ring); drm_fence_unring(dev, &fence->ring);
ret = driver->emit(dev, fence_flags, &sequence, &native_type); ret = driver->emit(dev, class, fence_flags, &sequence, &native_type);
if (ret) if (ret)
return ret; return ret;
write_lock_irqsave(&fm->lock, flags); write_lock_irqsave(&fm->lock, flags);
fence->class = class;
fence->type = type; fence->type = type;
fence->flush_mask = 0x00; fence->flush_mask = 0x00;
fence->submitted_flush = 0x00; fence->submitted_flush = 0x00;
fence->signaled = 0x00; fence->signaled = 0x00;
fence->sequence = sequence; fence->sequence = sequence;
fence->native_type = native_type; fence->native_type = native_type;
list_add_tail(&fence->ring, &fm->ring); if (list_empty(&fc->ring))
fc->last_exe_flush = sequence - 1;
list_add_tail(&fence->ring, &fc->ring);
write_unlock_irqrestore(&fm->lock, flags); write_unlock_irqrestore(&fm->lock, flags);
return 0; return 0;
} }
static int drm_fence_object_init(drm_device_t * dev, uint32_t type, static int drm_fence_object_init(drm_device_t * dev, uint32_t class,
uint32_t type,
uint32_t fence_flags, uint32_t fence_flags,
drm_fence_object_t * fence) drm_fence_object_t * fence)
{ {
@ -400,7 +430,7 @@ static int drm_fence_object_init(drm_device_t * dev, uint32_t type,
write_lock_irqsave(&fm->lock, flags); write_lock_irqsave(&fm->lock, flags);
INIT_LIST_HEAD(&fence->ring); INIT_LIST_HEAD(&fence->ring);
fence->class = 0; fence->class = class;
fence->type = type; fence->type = type;
fence->flush_mask = 0; fence->flush_mask = 0;
fence->submitted_flush = 0; fence->submitted_flush = 0;
@ -408,7 +438,8 @@ static int drm_fence_object_init(drm_device_t * dev, uint32_t type,
fence->sequence = 0; fence->sequence = 0;
write_unlock_irqrestore(&fm->lock, flags); write_unlock_irqrestore(&fm->lock, flags);
if (fence_flags & DRM_FENCE_FLAG_EMIT) { if (fence_flags & DRM_FENCE_FLAG_EMIT) {
ret = drm_fence_object_emit(dev, fence, fence_flags, type); ret = drm_fence_object_emit(dev, fence, fence_flags,
fence->class, type);
} }
return ret; return ret;
} }
@ -421,29 +452,29 @@ int drm_fence_add_user_object(drm_file_t * priv, drm_fence_object_t * fence,
mutex_lock(&dev->struct_mutex); mutex_lock(&dev->struct_mutex);
ret = drm_add_user_object(priv, &fence->base, shareable); ret = drm_add_user_object(priv, &fence->base, shareable);
mutex_unlock(&dev->struct_mutex);
if (ret) if (ret)
return ret; goto out;
atomic_inc(&fence->usage);
fence->base.type = drm_fence_type; fence->base.type = drm_fence_type;
fence->base.remove = &drm_fence_object_destroy; fence->base.remove = &drm_fence_object_destroy;
DRM_DEBUG("Fence 0x%08lx created\n", fence->base.hash.key); DRM_DEBUG("Fence 0x%08lx created\n", fence->base.hash.key);
return 0; out:
mutex_unlock(&dev->struct_mutex);
return ret;
} }
EXPORT_SYMBOL(drm_fence_add_user_object); EXPORT_SYMBOL(drm_fence_add_user_object);
int drm_fence_object_create(drm_device_t * dev, uint32_t type, int drm_fence_object_create(drm_device_t * dev, uint32_t class, uint32_t type,
unsigned flags, drm_fence_object_t ** c_fence) unsigned flags, drm_fence_object_t ** c_fence)
{ {
drm_fence_object_t *fence; drm_fence_object_t *fence;
int ret; int ret;
drm_fence_manager_t *fm = &dev->fm; drm_fence_manager_t *fm = &dev->fm;
fence = drm_ctl_cache_alloc(drm_cache.fence_object, fence = drm_ctl_calloc(1, sizeof(*fence), DRM_MEM_FENCE);
sizeof(*fence), GFP_KERNEL);
if (!fence) if (!fence)
return -ENOMEM; return -ENOMEM;
ret = drm_fence_object_init(dev, type, flags, fence); ret = drm_fence_object_init(dev, class, type, flags, fence);
if (ret) { if (ret) {
drm_fence_usage_deref_unlocked(dev, fence); drm_fence_usage_deref_unlocked(dev, fence);
return ret; return ret;
@ -459,22 +490,30 @@ EXPORT_SYMBOL(drm_fence_object_create);
void drm_fence_manager_init(drm_device_t * dev) void drm_fence_manager_init(drm_device_t * dev)
{ {
drm_fence_manager_t *fm = &dev->fm; drm_fence_manager_t *fm = &dev->fm;
drm_fence_class_manager_t *class;
drm_fence_driver_t *fed = dev->driver->fence_driver; drm_fence_driver_t *fed = dev->driver->fence_driver;
int i; int i;
fm->lock = RW_LOCK_UNLOCKED; rwlock_init(&fm->lock);
write_lock(&fm->lock); write_lock(&fm->lock);
INIT_LIST_HEAD(&fm->ring);
fm->pending_flush = 0;
DRM_INIT_WAITQUEUE(&fm->fence_queue);
fm->initialized = 0; fm->initialized = 0;
if (fed) { if (!fed)
fm->initialized = 1; goto out_unlock;
atomic_set(&fm->count, 0);
for (i = 0; i < fed->no_types; ++i) { fm->initialized = 1;
fm->fence_types[i] = &fm->ring; fm->num_classes = fed->num_classes;
} BUG_ON(fm->num_classes > _DRM_FENCE_CLASSES);
for (i=0; i<fm->num_classes; ++i) {
class = &fm->class[i];
INIT_LIST_HEAD(&class->ring);
class->pending_flush = 0;
DRM_INIT_WAITQUEUE(&class->fence_queue);
} }
atomic_set(&fm->count, 0);
out_unlock:
write_unlock(&fm->lock); write_unlock(&fm->lock);
} }
@ -521,7 +560,8 @@ int drm_fence_ioctl(DRM_IOCTL_ARGS)
case drm_fence_create: case drm_fence_create:
if (arg.flags & DRM_FENCE_FLAG_EMIT) if (arg.flags & DRM_FENCE_FLAG_EMIT)
LOCK_TEST_WITH_RETURN(dev, filp); LOCK_TEST_WITH_RETURN(dev, filp);
ret = drm_fence_object_create(dev, arg.type, arg.flags, &fence); ret = drm_fence_object_create(dev, arg.class,
arg.type, arg.flags, &fence);
if (ret) if (ret)
return ret; return ret;
ret = drm_fence_add_user_object(priv, fence, ret = drm_fence_add_user_object(priv, fence,
@ -531,13 +571,8 @@ int drm_fence_ioctl(DRM_IOCTL_ARGS)
drm_fence_usage_deref_unlocked(dev, fence); drm_fence_usage_deref_unlocked(dev, fence);
return ret; return ret;
} }
/*
* usage > 0. No need to lock dev->struct_mutex;
*/
atomic_inc(&fence->usage);
arg.handle = fence->base.hash.key; arg.handle = fence->base.hash.key;
break; break;
case drm_fence_destroy: case drm_fence_destroy:
mutex_lock(&dev->struct_mutex); mutex_lock(&dev->struct_mutex);
@ -584,7 +619,8 @@ int drm_fence_ioctl(DRM_IOCTL_ARGS)
fence = drm_lookup_fence_object(priv, arg.handle); fence = drm_lookup_fence_object(priv, arg.handle);
if (!fence) if (!fence)
return -EINVAL; return -EINVAL;
ret = drm_fence_object_emit(dev, fence, arg.flags, arg.type); ret = drm_fence_object_emit(dev, fence, arg.flags, arg.class,
arg.type);
break; break;
case drm_fence_buffers: case drm_fence_buffers:
if (!dev->bm.initialized) { if (!dev->bm.initialized) {
@ -601,7 +637,6 @@ int drm_fence_ioctl(DRM_IOCTL_ARGS)
DRM_FENCE_FLAG_SHAREABLE); DRM_FENCE_FLAG_SHAREABLE);
if (ret) if (ret)
return ret; return ret;
atomic_inc(&fence->usage);
arg.handle = fence->base.hash.key; arg.handle = fence->base.hash.key;
break; break;
default: default:

View file

@ -46,7 +46,7 @@ static int drm_setup(drm_device_t * dev)
drm_local_map_t *map; drm_local_map_t *map;
int i; int i;
int ret; int ret;
int sareapage;
if (dev->driver->firstopen) { if (dev->driver->firstopen) {
ret = dev->driver->firstopen(dev); ret = dev->driver->firstopen(dev);
@ -57,8 +57,8 @@ static int drm_setup(drm_device_t * dev)
dev->magicfree.next = NULL; dev->magicfree.next = NULL;
/* prebuild the SAREA */ /* prebuild the SAREA */
sareapage = max(SAREA_MAX, PAGE_SIZE);
i = drm_addmap(dev, 0, SAREA_MAX, _DRM_SHM, _DRM_CONTAINS_LOCK, &map); i = drm_addmap(dev, 0, sareapage, _DRM_SHM, _DRM_CONTAINS_LOCK, &map);
if (i != 0) if (i != 0)
return i; return i;
@ -79,13 +79,6 @@ static int drm_setup(drm_device_t * dev)
drm_ht_create(&dev->magiclist, DRM_MAGIC_HASH_ORDER); drm_ht_create(&dev->magiclist, DRM_MAGIC_HASH_ORDER);
INIT_LIST_HEAD(&dev->magicfree); INIT_LIST_HEAD(&dev->magicfree);
dev->ctxlist = drm_alloc(sizeof(*dev->ctxlist), DRM_MEM_CTXLIST);
if (dev->ctxlist == NULL)
return -ENOMEM;
memset(dev->ctxlist, 0, sizeof(*dev->ctxlist));
INIT_LIST_HEAD(&dev->ctxlist->head);
dev->vmalist = NULL;
dev->sigdata.lock = NULL; dev->sigdata.lock = NULL;
init_waitqueue_head(&dev->lock.lock_queue); init_waitqueue_head(&dev->lock.lock_queue);
dev->queue_count = 0; dev->queue_count = 0;
@ -154,12 +147,15 @@ int drm_open(struct inode *inode, struct file *filp)
spin_lock(&dev->count_lock); spin_lock(&dev->count_lock);
if (!dev->open_count++) { if (!dev->open_count++) {
spin_unlock(&dev->count_lock); spin_unlock(&dev->count_lock);
return drm_setup(dev); retcode = drm_setup(dev);
goto out;
} }
spin_unlock(&dev->count_lock); spin_unlock(&dev->count_lock);
} }
out:
mutex_lock(&dev->struct_mutex); mutex_lock(&dev->struct_mutex);
BUG_ON((dev->dev_mapping != NULL) && BUG_ON((dev->dev_mapping != NULL) &&
(dev->dev_mapping != inode->i_mapping)); (dev->dev_mapping != inode->i_mapping));
if (dev->dev_mapping == NULL) if (dev->dev_mapping == NULL)
dev->dev_mapping = inode->i_mapping; dev->dev_mapping = inode->i_mapping;
@ -265,6 +261,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
priv->authenticated = capable(CAP_SYS_ADMIN); priv->authenticated = capable(CAP_SYS_ADMIN);
priv->lock_count = 0; priv->lock_count = 0;
INIT_LIST_HEAD(&priv->lhead);
INIT_LIST_HEAD(&priv->user_objects); INIT_LIST_HEAD(&priv->user_objects);
INIT_LIST_HEAD(&priv->refd_objects); INIT_LIST_HEAD(&priv->refd_objects);
@ -288,19 +285,10 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
} }
mutex_lock(&dev->struct_mutex); mutex_lock(&dev->struct_mutex);
if (!dev->file_last) { if (list_empty(&dev->filelist))
priv->next = NULL;
priv->prev = NULL;
dev->file_first = priv;
dev->file_last = priv;
/* first opener automatically becomes master */
priv->master = 1; priv->master = 1;
} else {
priv->next = NULL; list_add(&priv->lhead, &dev->filelist);
priv->prev = dev->file_last;
dev->file_last->next = priv;
dev->file_last = priv;
}
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
#ifdef __alpha__ #ifdef __alpha__
@ -355,42 +343,34 @@ static void drm_object_release(struct file *filp) {
/* /*
* Free leftover ref objects created by me. Note that we cannot use * Free leftover ref objects created by me. Note that we cannot use
* list_for_each() here, as the struct_mutex may be temporarily released * list_for_each() here, as the struct_mutex may be temporarily released
* by the remove_() functions, and thus the lists may be altered. * by the remove_() functions, and thus the lists may be altered.
* Also, a drm_remove_ref_object() will not remove it * Also, a drm_remove_ref_object() will not remove it
* from the list unless its refcount is 1. * from the list unless its refcount is 1.
*/ */
head = &priv->refd_objects; head = &priv->refd_objects;
while (head->next != head) { while (head->next != head) {
ref_object = list_entry(head->next, drm_ref_object_t, list); ref_object = list_entry(head->next, drm_ref_object_t, list);
drm_remove_ref_object(priv, ref_object); drm_remove_ref_object(priv, ref_object);
head = &priv->refd_objects; head = &priv->refd_objects;
} }
/* /*
* Free leftover user objects created by me. * Free leftover user objects created by me.
*/ */
head = &priv->user_objects; head = &priv->user_objects;
while (head->next != head) { while (head->next != head) {
user_object = list_entry(head->next, drm_user_object_t, list); user_object = list_entry(head->next, drm_user_object_t, list);
drm_remove_user_object(priv, user_object); drm_remove_user_object(priv, user_object);
head = &priv->user_objects; head = &priv->user_objects;
} }
for(i=0; i<_DRM_NO_REF_TYPES; ++i) { for(i=0; i<_DRM_NO_REF_TYPES; ++i) {
drm_ht_remove(&priv->refd_object_hash[i]); drm_ht_remove(&priv->refd_object_hash[i]);
} }
} }
/** /**
* Release file. * Release file.
@ -426,39 +406,52 @@ int drm_release(struct inode *inode, struct file *filp)
current->pid, (long)old_encode_dev(priv->head->device), current->pid, (long)old_encode_dev(priv->head->device),
dev->open_count); dev->open_count);
if (dev->driver->reclaim_buffers_locked) { if (dev->driver->reclaim_buffers_locked && dev->lock.hw_lock) {
unsigned long _end = jiffies + DRM_HZ*3; if (drm_i_have_hw_lock(filp)) {
do {
retcode = drm_kernel_take_hw_lock(filp);
} while(retcode && !time_after_eq(jiffies,_end));
if (!retcode) {
dev->driver->reclaim_buffers_locked(dev, filp); dev->driver->reclaim_buffers_locked(dev, filp);
drm_lock_free(dev, &dev->lock.hw_lock->lock,
_DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
} else { } else {
unsigned long _end=jiffies + 3*DRM_HZ;
int locked = 0;
drm_idlelock_take(&dev->lock);
/* /*
* FIXME: This is not a good solution. We should perhaps associate the * Wait for a while.
* DRM lock with a process context, and check whether the current process
* holds the lock. Then we can run reclaim buffers locked anyway.
*/ */
DRM_ERROR("Reclaim buffers locked deadlock.\n"); do{
DRM_ERROR("This is probably a single thread having multiple\n"); spin_lock(&dev->lock.spinlock);
DRM_ERROR("DRM file descriptors open either dying or " locked = dev->lock.idle_has_lock;
"closing file descriptors\n"); spin_unlock(&dev->lock.spinlock);
DRM_ERROR("while having the lock. I will not reclaim buffers.\n"); if (locked)
DRM_ERROR("Locking context is 0x%08x\n", break;
_DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); schedule();
} while (!time_after_eq(jiffies, _end));
if (!locked) {
DRM_ERROR("reclaim_buffers_locked() deadlock. Please rework this\n"
"\tdriver to use reclaim_buffers_idlelocked() instead.\n"
"\tI will go on reclaiming the buffers anyway.\n");
}
dev->driver->reclaim_buffers_locked(dev, filp);
drm_idlelock_release(&dev->lock);
} }
} else if (drm_i_have_hw_lock(filp)) { }
if (dev->driver->reclaim_buffers_idlelocked && dev->lock.hw_lock) {
drm_idlelock_take(&dev->lock);
dev->driver->reclaim_buffers_idlelocked(dev, filp);
drm_idlelock_release(&dev->lock);
}
if (drm_i_have_hw_lock(filp)) {
DRM_DEBUG("File %p released, freeing lock for context %d\n", DRM_DEBUG("File %p released, freeing lock for context %d\n",
filp, _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); filp, _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
drm_lock_free(dev, &dev->lock.hw_lock->lock, drm_lock_free(&dev->lock,
_DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
} }
@ -472,10 +465,10 @@ int drm_release(struct inode *inode, struct file *filp)
mutex_lock(&dev->ctxlist_mutex); mutex_lock(&dev->ctxlist_mutex);
if (dev->ctxlist && (!list_empty(&dev->ctxlist->head))) { if (!list_empty(&dev->ctxlist)) {
drm_ctx_list_t *pos, *n; drm_ctx_list_t *pos, *n;
list_for_each_entry_safe(pos, n, &dev->ctxlist->head, head) { list_for_each_entry_safe(pos, n, &dev->ctxlist, head) {
if (pos->tag == priv && if (pos->tag == priv &&
pos->handle != DRM_KERNEL_CONTEXT) { pos->handle != DRM_KERNEL_CONTEXT) {
if (dev->driver->context_dtor) if (dev->driver->context_dtor)
@ -495,22 +488,12 @@ int drm_release(struct inode *inode, struct file *filp)
mutex_lock(&dev->struct_mutex); mutex_lock(&dev->struct_mutex);
drm_object_release(filp); drm_object_release(filp);
if (priv->remove_auth_on_close == 1) { if (priv->remove_auth_on_close == 1) {
drm_file_t *temp = dev->file_first; drm_file_t *temp;
while (temp) {
list_for_each_entry(temp, &dev->filelist, lhead)
temp->authenticated = 0; temp->authenticated = 0;
temp = temp->next;
}
}
if (priv->prev) {
priv->prev->next = priv->next;
} else {
dev->file_first = priv->next;
}
if (priv->next) {
priv->next->prev = priv->prev;
} else {
dev->file_last = priv->prev;
} }
list_del(&priv->lhead);
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
if (dev->driver->postclose) if (dev->driver->postclose)
@ -550,7 +533,7 @@ EXPORT_SYMBOL(drm_release);
* to set a newer interface version to avoid breaking older Xservers. * to set a newer interface version to avoid breaking older Xservers.
* Without fixing the Xserver you get: "WaitForSomething(): select: errno=22" * Without fixing the Xserver you get: "WaitForSomething(): select: errno=22"
* http://freedesktop.org/bugzilla/show_bug.cgi?id=1505 if you try * http://freedesktop.org/bugzilla/show_bug.cgi?id=1505 if you try
* to return the correct response. * to return the correct response.
*/ */
unsigned int drm_poll(struct file *filp, struct poll_table_struct *wait) unsigned int drm_poll(struct file *filp, struct poll_table_struct *wait)
{ {

View file

@ -28,7 +28,6 @@
* IN THE SOFTWARE. * IN THE SOFTWARE.
*/ */
#include <linux/compat.h> #include <linux/compat.h>
#include <linux/ioctl32.h>
#include "drmP.h" #include "drmP.h"
#include "drm_core.h" #include "drm_core.h"

View file

@ -138,12 +138,12 @@ static int drm_set_busid(drm_device_t * dev)
{ {
int len; int len;
if (dev->unique != NULL) if (dev->unique != NULL)
return EBUSY; return -EBUSY;
dev->unique_len = 40; dev->unique_len = 40;
dev->unique = drm_alloc(dev->unique_len + 1, DRM_MEM_DRIVER); dev->unique = drm_alloc(dev->unique_len + 1, DRM_MEM_DRIVER);
if (dev->unique == NULL) if (dev->unique == NULL)
return ENOMEM; return -ENOMEM;
len = snprintf(dev->unique, dev->unique_len, "pci:%04x:%02x:%02x.%d", len = snprintf(dev->unique, dev->unique_len, "pci:%04x:%02x:%02x.%d",
drm_get_pci_domain(dev), drm_get_pci_domain(dev),
@ -156,7 +156,7 @@ static int drm_set_busid(drm_device_t * dev)
dev->devname = drm_alloc(strlen(dev->driver->pci_driver.name) + dev->unique_len + 2, dev->devname = drm_alloc(strlen(dev->driver->pci_driver.name) + dev->unique_len + 2,
DRM_MEM_DRIVER); DRM_MEM_DRIVER);
if (dev->devname == NULL) if (dev->devname == NULL)
return ENOMEM; return -ENOMEM;
sprintf(dev->devname, "%s@%s", dev->driver->pci_driver.name, dev->unique); sprintf(dev->devname, "%s@%s", dev->driver->pci_driver.name, dev->unique);
@ -199,7 +199,7 @@ int drm_getmap(struct inode *inode, struct file *filp,
} }
i = 0; i = 0;
list_for_each(list, &dev->maplist->head) { list_for_each(list, &dev->maplist) {
if (i == idx) { if (i == idx) {
r_list = list_entry(list, drm_map_list_t, head); r_list = list_entry(list, drm_map_list_t, head);
break; break;
@ -252,12 +252,18 @@ int drm_getclient(struct inode *inode, struct file *filp,
return -EFAULT; return -EFAULT;
idx = client.idx; idx = client.idx;
mutex_lock(&dev->struct_mutex); mutex_lock(&dev->struct_mutex);
for (i = 0, pt = dev->file_first; i < idx && pt; i++, pt = pt->next) ;
if (list_empty(&dev->filelist)) {
if (!pt) {
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
return -EINVAL; return -EINVAL;
} }
i = 0;
list_for_each_entry(pt, &dev->filelist, lhead) {
if (i++ >= idx)
break;
}
client.auth = pt->authenticated; client.auth = pt->authenticated;
client.pid = pt->pid; client.pid = pt->pid;
client.uid = pt->uid; client.uid = pt->uid;
@ -337,13 +343,13 @@ int drm_setversion(DRM_IOCTL_ARGS)
retv.drm_dd_major = dev->driver->major; retv.drm_dd_major = dev->driver->major;
retv.drm_dd_minor = dev->driver->minor; retv.drm_dd_minor = dev->driver->minor;
if (copy_to_user(argp, &retv, sizeof(sv))) if (copy_to_user(argp, &retv, sizeof(retv)))
return -EFAULT; return -EFAULT;
if (sv.drm_di_major != -1) { if (sv.drm_di_major != -1) {
if (sv.drm_di_major != DRM_IF_MAJOR || if (sv.drm_di_major != DRM_IF_MAJOR ||
sv.drm_di_minor < 0 || sv.drm_di_minor > DRM_IF_MINOR) 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); if_version = DRM_IF_VERSION(sv.drm_di_major, sv.drm_di_minor);
dev->if_version = max(if_version, dev->if_version); dev->if_version = max(if_version, dev->if_version);
if (sv.drm_di_minor >= 1) { if (sv.drm_di_minor >= 1) {
@ -357,7 +363,7 @@ int drm_setversion(DRM_IOCTL_ARGS)
if (sv.drm_dd_major != -1) { if (sv.drm_dd_major != -1) {
if (sv.drm_dd_major != dev->driver->major || if (sv.drm_dd_major != dev->driver->major ||
sv.drm_dd_minor < 0 || sv.drm_dd_minor > dev->driver->minor) sv.drm_dd_minor < 0 || sv.drm_dd_minor > dev->driver->minor)
return EINVAL; return -EINVAL;
if (dev->driver->set_version) if (dev->driver->set_version)
dev->driver->set_version(dev, &sv); dev->driver->set_version(dev, &sv);

View file

@ -118,10 +118,9 @@ static int drm_irq_install(drm_device_t * dev)
init_waitqueue_head(&dev->vbl_queue); init_waitqueue_head(&dev->vbl_queue);
spin_lock_init(&dev->vbl_lock); spin_lock_init(&dev->vbl_lock);
spin_lock_init(&dev->tasklet_lock);
INIT_LIST_HEAD(&dev->vbl_sigs.head); INIT_LIST_HEAD(&dev->vbl_sigs);
INIT_LIST_HEAD(&dev->vbl_sigs2.head); INIT_LIST_HEAD(&dev->vbl_sigs2);
dev->vbl_pending = 0; dev->vbl_pending = 0;
} }
@ -131,7 +130,7 @@ static int drm_irq_install(drm_device_t * dev)
/* Install handler */ /* Install handler */
if (drm_core_check_feature(dev, DRIVER_IRQ_SHARED)) if (drm_core_check_feature(dev, DRIVER_IRQ_SHARED))
sh_flags = SA_SHIRQ; sh_flags = IRQF_SHARED;
ret = request_irq(dev->irq, dev->driver->irq_handler, ret = request_irq(dev->irq, dev->driver->irq_handler,
sh_flags, dev->devname, dev); sh_flags, dev->devname, dev);
@ -291,7 +290,7 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
if (flags & _DRM_VBLANK_SIGNAL) { if (flags & _DRM_VBLANK_SIGNAL) {
unsigned long irqflags; unsigned long irqflags;
drm_vbl_sig_t *vbl_sigs = (flags & _DRM_VBLANK_SECONDARY) struct list_head *vbl_sigs = (flags & _DRM_VBLANK_SECONDARY)
? &dev->vbl_sigs2 : &dev->vbl_sigs; ? &dev->vbl_sigs2 : &dev->vbl_sigs;
drm_vbl_sig_t *vbl_sig; drm_vbl_sig_t *vbl_sig;
@ -301,7 +300,7 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
* for the same vblank sequence number; nothing to be done in * for the same vblank sequence number; nothing to be done in
* that case * that case
*/ */
list_for_each_entry(vbl_sig, &vbl_sigs->head, head) { list_for_each_entry(vbl_sig, vbl_sigs, head) {
if (vbl_sig->sequence == vblwait.request.sequence if (vbl_sig->sequence == vblwait.request.sequence
&& vbl_sig->info.si_signo == vblwait.request.signal && vbl_sig->info.si_signo == vblwait.request.signal
&& vbl_sig->task == current) { && vbl_sig->task == current) {
@ -335,7 +334,7 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
spin_lock_irqsave(&dev->vbl_lock, irqflags); spin_lock_irqsave(&dev->vbl_lock, irqflags);
list_add_tail((struct list_head *)vbl_sig, &vbl_sigs->head); list_add_tail(&vbl_sig->head, vbl_sigs);
spin_unlock_irqrestore(&dev->vbl_lock, irqflags); spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
@ -378,20 +377,18 @@ void drm_vbl_send_signals(drm_device_t * dev)
spin_lock_irqsave(&dev->vbl_lock, flags); spin_lock_irqsave(&dev->vbl_lock, flags);
for (i = 0; i < 2; i++) { for (i = 0; i < 2; i++) {
struct list_head *list, *tmp; drm_vbl_sig_t *vbl_sig, *tmp;
drm_vbl_sig_t *vbl_sig; struct list_head *vbl_sigs = i ? &dev->vbl_sigs2 : &dev->vbl_sigs;
drm_vbl_sig_t *vbl_sigs = i ? &dev->vbl_sigs2 : &dev->vbl_sigs;
unsigned int vbl_seq = atomic_read(i ? &dev->vbl_received2 : unsigned int vbl_seq = atomic_read(i ? &dev->vbl_received2 :
&dev->vbl_received); &dev->vbl_received);
list_for_each_safe(list, tmp, &vbl_sigs->head) { list_for_each_entry_safe(vbl_sig, tmp, vbl_sigs, head) {
vbl_sig = list_entry(list, drm_vbl_sig_t, head);
if ((vbl_seq - vbl_sig->sequence) <= (1 << 23)) { if ((vbl_seq - vbl_sig->sequence) <= (1 << 23)) {
vbl_sig->info.si_code = vbl_seq; vbl_sig->info.si_code = vbl_seq;
send_sig_info(vbl_sig->info.si_signo, send_sig_info(vbl_sig->info.si_signo,
&vbl_sig->info, vbl_sig->task); &vbl_sig->info, vbl_sig->task);
list_del(list); list_del(&vbl_sig->head);
drm_free(vbl_sig, sizeof(*vbl_sig), drm_free(vbl_sig, sizeof(*vbl_sig),
DRM_MEM_DRIVER); DRM_MEM_DRIVER);
@ -422,7 +419,7 @@ static void drm_locked_tasklet_func(unsigned long data)
spin_lock_irqsave(&dev->tasklet_lock, irqflags); spin_lock_irqsave(&dev->tasklet_lock, irqflags);
if (!dev->locked_tasklet_func || if (!dev->locked_tasklet_func ||
!drm_lock_take(&dev->lock.hw_lock->lock, !drm_lock_take(&dev->lock,
DRM_KERNEL_CONTEXT)) { DRM_KERNEL_CONTEXT)) {
spin_unlock_irqrestore(&dev->tasklet_lock, irqflags); spin_unlock_irqrestore(&dev->tasklet_lock, irqflags);
return; return;
@ -433,7 +430,7 @@ static void drm_locked_tasklet_func(unsigned long data)
dev->locked_tasklet_func(dev); dev->locked_tasklet_func(dev);
drm_lock_free(dev, &dev->lock.hw_lock->lock, drm_lock_free(&dev->lock,
DRM_KERNEL_CONTEXT); DRM_KERNEL_CONTEXT);
dev->locked_tasklet_func = NULL; dev->locked_tasklet_func = NULL;

View file

@ -35,12 +35,6 @@
#include "drmP.h" #include "drmP.h"
#if 0
static int drm_lock_transfer(drm_device_t * dev,
__volatile__ unsigned int *lock,
unsigned int context);
#endif
static int drm_notifier(void *priv); static int drm_notifier(void *priv);
/** /**
@ -83,6 +77,9 @@ int drm_lock(struct inode *inode, struct file *filp,
return -EINVAL; return -EINVAL;
add_wait_queue(&dev->lock.lock_queue, &entry); add_wait_queue(&dev->lock.lock_queue, &entry);
spin_lock(&dev->lock.spinlock);
dev->lock.user_waiters++;
spin_unlock(&dev->lock.spinlock);
for (;;) { for (;;) {
__set_current_state(TASK_INTERRUPTIBLE); __set_current_state(TASK_INTERRUPTIBLE);
if (!dev->lock.hw_lock) { if (!dev->lock.hw_lock) {
@ -90,7 +87,7 @@ int drm_lock(struct inode *inode, struct file *filp,
ret = -EINTR; ret = -EINTR;
break; break;
} }
if (drm_lock_take(&dev->lock.hw_lock->lock, lock.context)) { if (drm_lock_take(&dev->lock, lock.context)) {
dev->lock.filp = filp; dev->lock.filp = filp;
dev->lock.lock_time = jiffies; dev->lock.lock_time = jiffies;
atomic_inc(&dev->counts[_DRM_STAT_LOCKS]); atomic_inc(&dev->counts[_DRM_STAT_LOCKS]);
@ -104,6 +101,9 @@ int drm_lock(struct inode *inode, struct file *filp,
break; break;
} }
} }
spin_lock(&dev->lock.spinlock);
dev->lock.user_waiters--;
spin_unlock(&dev->lock.spinlock);
__set_current_state(TASK_RUNNING); __set_current_state(TASK_RUNNING);
remove_wait_queue(&dev->lock.lock_queue, &entry); remove_wait_queue(&dev->lock.lock_queue, &entry);
@ -184,8 +184,7 @@ int drm_unlock(struct inode *inode, struct file *filp,
if (dev->driver->kernel_context_switch_unlock) if (dev->driver->kernel_context_switch_unlock)
dev->driver->kernel_context_switch_unlock(dev); dev->driver->kernel_context_switch_unlock(dev);
else { else {
if (drm_lock_free(dev, &dev->lock.hw_lock->lock, if (drm_lock_free(&dev->lock,lock.context)) {
lock.context)) {
/* FIXME: Should really bail out here. */ /* FIXME: Should really bail out here. */
} }
} }
@ -203,18 +202,26 @@ int drm_unlock(struct inode *inode, struct file *filp,
* *
* Attempt to mark the lock as held by the given context, via the \p cmpxchg instruction. * Attempt to mark the lock as held by the given context, via the \p cmpxchg instruction.
*/ */
int drm_lock_take(__volatile__ unsigned int *lock, unsigned int context) int drm_lock_take(drm_lock_data_t *lock_data,
unsigned int context)
{ {
unsigned int old, new, prev; unsigned int old, new, prev;
volatile unsigned int *lock = &lock_data->hw_lock->lock;
spin_lock(&lock_data->spinlock);
do { do {
old = *lock; old = *lock;
if (old & _DRM_LOCK_HELD) if (old & _DRM_LOCK_HELD)
new = old | _DRM_LOCK_CONT; new = old | _DRM_LOCK_CONT;
else else {
new = context | _DRM_LOCK_HELD | _DRM_LOCK_CONT; new = context | _DRM_LOCK_HELD |
((lock_data->user_waiters + lock_data->kernel_waiters > 1) ?
_DRM_LOCK_CONT : 0);
}
prev = cmpxchg(lock, old, new); prev = cmpxchg(lock, old, new);
} while (prev != old); } while (prev != old);
spin_unlock(&lock_data->spinlock);
if (_DRM_LOCKING_CONTEXT(old) == context) { if (_DRM_LOCKING_CONTEXT(old) == context) {
if (old & _DRM_LOCK_HELD) { if (old & _DRM_LOCK_HELD) {
if (context != DRM_KERNEL_CONTEXT) { if (context != DRM_KERNEL_CONTEXT) {
@ -224,14 +231,15 @@ int drm_lock_take(__volatile__ unsigned int *lock, unsigned int context)
return 0; return 0;
} }
} }
if (new == (context | _DRM_LOCK_HELD | _DRM_LOCK_CONT)) {
if ((_DRM_LOCKING_CONTEXT(new)) == context && (new & _DRM_LOCK_HELD)) {
/* Have lock */ /* Have lock */
return 1; return 1;
} }
return 0; return 0;
} }
#if 0
/** /**
* This takes a lock forcibly and hands it to context. Should ONLY be used * This takes a lock forcibly and hands it to context. Should ONLY be used
* inside *_unlock to give lock to kernel before calling *_dma_schedule. * inside *_unlock to give lock to kernel before calling *_dma_schedule.
@ -244,13 +252,13 @@ int drm_lock_take(__volatile__ unsigned int *lock, unsigned int context)
* Resets the lock file pointer. * Resets the lock file pointer.
* Marks the lock as held by the given context, via the \p cmpxchg instruction. * Marks the lock as held by the given context, via the \p cmpxchg instruction.
*/ */
static int drm_lock_transfer(drm_device_t * dev, static int drm_lock_transfer(drm_lock_data_t *lock_data,
__volatile__ unsigned int *lock,
unsigned int context) unsigned int context)
{ {
unsigned int old, new, prev; unsigned int old, new, prev;
volatile unsigned int *lock = &lock_data->hw_lock->lock;
dev->lock.filp = NULL; lock_data->filp = NULL;
do { do {
old = *lock; old = *lock;
new = context | _DRM_LOCK_HELD; new = context | _DRM_LOCK_HELD;
@ -258,7 +266,6 @@ static int drm_lock_transfer(drm_device_t * dev,
} while (prev != old); } while (prev != old);
return 1; return 1;
} }
#endif
/** /**
* Free lock. * Free lock.
@ -271,10 +278,19 @@ static int drm_lock_transfer(drm_device_t * dev,
* Marks the lock as not held, via the \p cmpxchg instruction. Wakes any task * Marks the lock as not held, via the \p cmpxchg instruction. Wakes any task
* waiting on the lock queue. * waiting on the lock queue.
*/ */
int drm_lock_free(drm_device_t * dev, int drm_lock_free(drm_lock_data_t *lock_data, unsigned int context)
__volatile__ unsigned int *lock, unsigned int context)
{ {
unsigned int old, new, prev; unsigned int old, new, prev;
volatile unsigned int *lock = &lock_data->hw_lock->lock;
spin_lock(&lock_data->spinlock);
if (lock_data->kernel_waiters != 0) {
drm_lock_transfer(lock_data, 0);
lock_data->idle_has_lock = 1;
spin_unlock(&lock_data->spinlock);
return 1;
}
spin_unlock(&lock_data->spinlock);
do { do {
old = *lock; old = *lock;
@ -287,7 +303,7 @@ int drm_lock_free(drm_device_t * dev,
context, _DRM_LOCKING_CONTEXT(old)); context, _DRM_LOCKING_CONTEXT(old));
return 1; return 1;
} }
wake_up_interruptible(&dev->lock.lock_queue); wake_up_interruptible(&lock_data->lock_queue);
return 0; return 0;
} }
@ -322,11 +338,59 @@ static int drm_notifier(void *priv)
return 0; return 0;
} }
/* /**
* Can be used by drivers to take the hardware lock if necessary. * This function returns immediately and takes the hw lock
* (Waiting for idle before reclaiming buffers etc.) * with the kernel context if it is free, otherwise it gets the highest priority when and if
* it is eventually released.
*
* This guarantees that the kernel will _eventually_ have the lock _unless_ it is held
* by a blocked process. (In the latter case an explicit wait for the hardware lock would cause
* a deadlock, which is why the "idlelock" was invented).
*
* This should be sufficient to wait for GPU idle without
* having to worry about starvation.
*/ */
void drm_idlelock_take(drm_lock_data_t *lock_data)
{
int ret = 0;
spin_lock(&lock_data->spinlock);
lock_data->kernel_waiters++;
if (!lock_data->idle_has_lock) {
spin_unlock(&lock_data->spinlock);
ret = drm_lock_take(lock_data, DRM_KERNEL_CONTEXT);
spin_lock(&lock_data->spinlock);
if (ret == 1)
lock_data->idle_has_lock = 1;
}
spin_unlock(&lock_data->spinlock);
}
EXPORT_SYMBOL(drm_idlelock_take);
void drm_idlelock_release(drm_lock_data_t *lock_data)
{
unsigned int old, prev;
volatile unsigned int *lock = &lock_data->hw_lock->lock;
spin_lock(&lock_data->spinlock);
if (--lock_data->kernel_waiters == 0) {
if (lock_data->idle_has_lock) {
do {
old = *lock;
prev = cmpxchg(lock, old, DRM_KERNEL_CONTEXT);
} while (prev != old);
wake_up_interruptible(&lock_data->lock_queue);
lock_data->idle_has_lock = 0;
}
}
spin_unlock(&lock_data->spinlock);
}
EXPORT_SYMBOL(drm_idlelock_release);
int drm_i_have_hw_lock(struct file *filp) int drm_i_have_hw_lock(struct file *filp)
{ {
DRM_DEVICE; DRM_DEVICE;
@ -337,50 +401,3 @@ int drm_i_have_hw_lock(struct file *filp)
} }
EXPORT_SYMBOL(drm_i_have_hw_lock); EXPORT_SYMBOL(drm_i_have_hw_lock);
int drm_kernel_take_hw_lock(struct file *filp)
{
DRM_DEVICE;
int ret = 0;
unsigned long _end = jiffies + 3*DRM_HZ;
if (!drm_i_have_hw_lock(filp)) {
DECLARE_WAITQUEUE(entry, current);
add_wait_queue(&dev->lock.lock_queue, &entry);
for (;;) {
__set_current_state(TASK_INTERRUPTIBLE);
if (!dev->lock.hw_lock) {
/* Device has been unregistered */
ret = -EINTR;
break;
}
if (drm_lock_take(&dev->lock.hw_lock->lock,
DRM_KERNEL_CONTEXT)) {
dev->lock.filp = filp;
dev->lock.lock_time = jiffies;
atomic_inc(&dev->counts[_DRM_STAT_LOCKS]);
break; /* Got lock */
}
/* Contention */
if (time_after_eq(jiffies,_end)) {
ret = -EBUSY;
break;
}
schedule_timeout(1);
if (signal_pending(current)) {
ret = -ERESTARTSYS;
break;
}
}
__set_current_state(TASK_RUNNING);
remove_wait_queue(&dev->lock.lock_queue, &entry);
}
return ret;
}
EXPORT_SYMBOL(drm_kernel_take_hw_lock);

View file

@ -47,7 +47,7 @@ static struct {
static inline size_t drm_size_align(size_t size) { static inline size_t drm_size_align(size_t size) {
register size_t tmpSize = 4; size_t tmpSize = 4;
if (size > PAGE_SIZE) if (size > PAGE_SIZE)
return PAGE_ALIGN(size); return PAGE_ALIGN(size);
@ -61,17 +61,17 @@ int drm_alloc_memctl(size_t size)
{ {
int ret; int ret;
unsigned long a_size = drm_size_align(size); unsigned long a_size = drm_size_align(size);
spin_lock(&drm_memctl.lock); spin_lock(&drm_memctl.lock);
ret = ((drm_memctl.cur_used + a_size) > drm_memctl.high_threshold) ? ret = ((drm_memctl.cur_used + a_size) > drm_memctl.high_threshold) ?
-ENOMEM : 0; -ENOMEM : 0;
if (!ret) if (!ret)
drm_memctl.cur_used += a_size; drm_memctl.cur_used += a_size;
spin_unlock(&drm_memctl.lock); spin_unlock(&drm_memctl.lock);
return ret; return ret;
} }
EXPORT_SYMBOL(drm_alloc_memctl); EXPORT_SYMBOL(drm_alloc_memctl);
void drm_free_memctl(size_t size) void drm_free_memctl(size_t size)
{ {
unsigned long a_size = drm_size_align(size); unsigned long a_size = drm_size_align(size);
@ -84,23 +84,24 @@ EXPORT_SYMBOL(drm_free_memctl);
void drm_query_memctl(drm_u64_t *cur_used, void drm_query_memctl(drm_u64_t *cur_used,
drm_u64_t *low_threshold, drm_u64_t *low_threshold,
drm_u64_t *high_threshold) drm_u64_t *high_threshold)
{ {
spin_lock(&drm_memctl.lock); spin_lock(&drm_memctl.lock);
*cur_used = drm_memctl.cur_used; *cur_used = drm_memctl.cur_used;
*low_threshold = drm_memctl.low_threshold; *low_threshold = drm_memctl.low_threshold;
*high_threshold = drm_memctl.high_threshold; *high_threshold = drm_memctl.high_threshold;
spin_unlock(&drm_memctl.lock); spin_unlock(&drm_memctl.lock);
} }
EXPORT_SYMBOL(drm_query_memctl); EXPORT_SYMBOL(drm_query_memctl);
void drm_init_memctl(size_t p_low_threshold, void drm_init_memctl(size_t p_low_threshold,
size_t p_high_threshold) size_t p_high_threshold,
size_t unit_size)
{ {
spin_lock(&drm_memctl.lock); spin_lock(&drm_memctl.lock);
drm_memctl.cur_used = 0; drm_memctl.cur_used = 0;
drm_memctl.low_threshold = p_low_threshold << PAGE_SHIFT; drm_memctl.low_threshold = p_low_threshold * unit_size;
drm_memctl.high_threshold = p_high_threshold << PAGE_SHIFT; drm_memctl.high_threshold = p_high_threshold * unit_size;
spin_unlock(&drm_memctl.lock); spin_unlock(&drm_memctl.lock);
} }
@ -134,13 +135,7 @@ int drm_mem_info(char *buf, char **start, off_t offset,
/** Wrapper around kmalloc() */ /** Wrapper around kmalloc() */
void *drm_calloc(size_t nmemb, size_t size, int area) void *drm_calloc(size_t nmemb, size_t size, int area)
{ {
void *addr; return kcalloc(nmemb, size, GFP_KERNEL);
addr = kmalloc(size * nmemb, GFP_KERNEL);
if (addr != NULL)
memset((void *)addr, 0, size * nmemb);
return addr;
} }
EXPORT_SYMBOL(drm_calloc); EXPORT_SYMBOL(drm_calloc);
@ -218,6 +213,49 @@ void drm_free_pages(unsigned long address, int order, int area)
} }
#if __OS_HAS_AGP #if __OS_HAS_AGP
static void *agp_remap(unsigned long offset, unsigned long size,
drm_device_t * dev)
{
unsigned long *phys_addr_map, i, num_pages =
PAGE_ALIGN(size) / PAGE_SIZE;
struct drm_agp_mem *agpmem;
struct page **page_map;
void *addr;
size = PAGE_ALIGN(size);
#ifdef __alpha__
offset -= dev->hose->mem_space->start;
#endif
list_for_each_entry(agpmem, &dev->agp->memory, head)
if (agpmem->bound <= offset
&& (agpmem->bound + (agpmem->pages << PAGE_SHIFT)) >=
(offset + size))
break;
if (!agpmem)
return NULL;
/*
* OK, we're mapping AGP space on a chipset/platform on which memory accesses by
* the CPU do not get remapped by the GART. We fix this by using the kernel's
* page-table instead (that's probably faster anyhow...).
*/
/* note: use vmalloc() because num_pages could be large... */
page_map = vmalloc(num_pages * sizeof(struct page *));
if (!page_map)
return NULL;
phys_addr_map =
agpmem->memory->memory + (offset - agpmem->bound) / PAGE_SIZE;
for (i = 0; i < num_pages; ++i)
page_map[i] = pfn_to_page(phys_addr_map[i] >> PAGE_SHIFT);
addr = vmap(page_map, num_pages, VM_IOREMAP, PAGE_AGP);
vfree(page_map);
return addr;
}
/** Wrapper around agp_allocate_memory() */ /** Wrapper around agp_allocate_memory() */
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,11) #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,11)
DRM_AGP_MEM *drm_alloc_agp(drm_device_t *dev, int pages, u32 type) DRM_AGP_MEM *drm_alloc_agp(drm_device_t *dev, int pages, u32 type)
@ -248,5 +286,36 @@ int drm_unbind_agp(DRM_AGP_MEM * handle)
{ {
return drm_agp_unbind_memory(handle); return drm_agp_unbind_memory(handle);
} }
#else /* __OS_HAS_AGP*/
static void *agp_remap(unsigned long offset, unsigned long size,
drm_device_t * dev)
{
return NULL;
}
#endif /* agp */ #endif /* agp */
#endif /* debug_memory */ #endif /* debug_memory */
void drm_core_ioremap(struct drm_map *map, struct drm_device *dev)
{
if (drm_core_has_AGP(dev) &&
dev->agp && dev->agp->cant_use_aperture && map->type == _DRM_AGP)
map->handle = agp_remap(map->offset, map->size, dev);
else
map->handle = ioremap(map->offset, map->size);
}
EXPORT_SYMBOL_GPL(drm_core_ioremap);
void drm_core_ioremapfree(struct drm_map *map, struct drm_device *dev)
{
if (!map->handle || !map->size)
return;
if (drm_core_has_AGP(dev) &&
dev->agp && dev->agp->cant_use_aperture && map->type == _DRM_AGP)
vunmap(map->handle);
else
iounmap(map->handle);
}
EXPORT_SYMBOL_GPL(drm_core_ioremapfree);

View file

@ -43,7 +43,7 @@
*/ */
/* Need the 4-argument version of vmap(). */ /* Need the 4-argument version of vmap(). */
#if __OS_HAS_AGP && defined(VMAP_4_ARGS) #if __OS_HAS_AGP
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
@ -57,177 +57,6 @@
# endif # endif
#endif #endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
#ifndef pte_offset_kernel
# define pte_offset_kernel(dir, address) pte_offset(dir, address)
#endif
#ifndef pte_pfn
# define pte_pfn(pte) (pte_page(pte) - mem_map)
#endif
#ifndef pfn_to_page
# define pfn_to_page(pfn) (mem_map + (pfn))
#endif
#endif
/*
* Find the drm_map that covers the range [offset, offset+size).
*/
static inline drm_map_t *drm_lookup_map(unsigned long offset,
unsigned long size, drm_device_t * dev)
{
struct list_head *list;
drm_map_list_t *r_list;
drm_map_t *map;
list_for_each(list, &dev->maplist->head) {
r_list = (drm_map_list_t *) list;
map = r_list->map;
if (!map)
continue;
if (map->offset <= offset
&& (offset + size) <= (map->offset + map->size))
return map;
}
return NULL;
}
static inline void *agp_remap(unsigned long offset, unsigned long size,
drm_device_t * dev)
{
unsigned long *phys_addr_map, i, num_pages =
PAGE_ALIGN(size) / PAGE_SIZE;
struct drm_agp_mem *agpmem;
struct page **page_map;
void *addr;
size = PAGE_ALIGN(size);
#ifdef __alpha__
offset -= dev->hose->mem_space->start;
#endif
for (agpmem = dev->agp->memory; agpmem; agpmem = agpmem->next)
if (agpmem->bound <= offset
&& (agpmem->bound + (agpmem->pages << PAGE_SHIFT)) >=
(offset + size))
break;
if (!agpmem)
return NULL;
/*
* OK, we're mapping AGP space on a chipset/platform on which memory accesses by
* the CPU do not get remapped by the GART. We fix this by using the kernel's
* page-table instead (that's probably faster anyhow...).
*/
/* note: use vmalloc() because num_pages could be large... */
page_map = vmalloc(num_pages * sizeof(struct page *));
if (!page_map)
return NULL;
phys_addr_map =
agpmem->memory->memory + (offset - agpmem->bound) / PAGE_SIZE;
for (i = 0; i < num_pages; ++i)
page_map[i] = pfn_to_page(phys_addr_map[i] >> PAGE_SHIFT);
addr = vmap(page_map, num_pages, VM_IOREMAP, PAGE_AGP);
vfree(page_map);
return addr;
}
static inline unsigned long drm_follow_page(void *vaddr)
{
pgd_t *pgd = pgd_offset_k((unsigned long) vaddr);
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,10)
pmd_t *pmd = pmd_offset(pgd, (unsigned long)vaddr);
#else
pud_t *pud = pud_offset(pgd, (unsigned long) vaddr);
pmd_t *pmd = pmd_offset(pud, (unsigned long) vaddr);
#endif
pte_t *ptep = pte_offset_kernel(pmd, (unsigned long) vaddr);
return pte_pfn(*ptep) << PAGE_SHIFT;
}
#else /* __OS_HAS_AGP */ #else /* __OS_HAS_AGP */
static inline drm_map_t *drm_lookup_map(unsigned long offset,
unsigned long size, drm_device_t * dev)
{
return NULL;
}
static inline void *agp_remap(unsigned long offset, unsigned long size,
drm_device_t * dev)
{
return NULL;
}
static inline unsigned long drm_follow_page(void *vaddr)
{
return 0;
}
#endif
#ifndef DEBUG_MEMORY
static inline void *drm_ioremap(unsigned long offset, unsigned long size,
drm_device_t * dev)
{
#if defined(VMAP_4_ARGS)
if (drm_core_has_AGP(dev) && dev->agp && dev->agp->cant_use_aperture) {
drm_map_t *map = drm_lookup_map(offset, size, dev);
if (map && map->type == _DRM_AGP)
return agp_remap(offset, size, dev);
}
#endif
return ioremap(offset, size);
}
static inline void *drm_ioremap_nocache(unsigned long offset,
unsigned long size, drm_device_t * dev)
{
#if defined(VMAP_4_ARGS)
if (drm_core_has_AGP(dev) && dev->agp && dev->agp->cant_use_aperture) {
drm_map_t *map = drm_lookup_map(offset, size, dev);
if (map && map->type == _DRM_AGP)
return agp_remap(offset, size, dev);
}
#endif
return ioremap_nocache(offset, size);
}
static inline void drm_ioremapfree(void *pt, unsigned long size,
drm_device_t * dev)
{
#if defined(VMAP_4_ARGS)
/*
* This is a bit ugly. It would be much cleaner if the DRM API would use separate
* routines for handling mappings in the AGP space. Hopefully this can be done in
* a future revision of the interface...
*/
if (drm_core_has_AGP(dev) && dev->agp && dev->agp->cant_use_aperture
&& ((unsigned long)pt >= VMALLOC_START
&& (unsigned long)pt < VMALLOC_END)) {
unsigned long offset;
drm_map_t *map;
offset = drm_follow_page(pt) | ((unsigned long)pt & ~PAGE_MASK);
map = drm_lookup_map(offset, size, dev);
if (map && map->type == _DRM_AGP) {
vunmap(pt);
return;
}
}
#endif
iounmap(pt);
}
#else
extern void *drm_ioremap(unsigned long offset, unsigned long size,
drm_device_t * dev);
extern void *drm_ioremap_nocache(unsigned long offset,
unsigned long size, drm_device_t * dev);
extern void drm_ioremapfree(void *pt, unsigned long size,
drm_device_t * dev);
#endif #endif

View file

@ -289,79 +289,6 @@ void drm_free_pages(unsigned long address, int order, int area)
} }
} }
void *drm_ioremap(unsigned long offset, unsigned long size, drm_device_t * dev)
{
void *pt;
if (!size) {
DRM_MEM_ERROR(DRM_MEM_MAPPINGS,
"Mapping 0 bytes at 0x%08lx\n", offset);
return NULL;
}
if (!(pt = drm_ioremap(offset, size, dev))) {
spin_lock(&drm_mem_lock);
++drm_mem_stats[DRM_MEM_MAPPINGS].fail_count;
spin_unlock(&drm_mem_lock);
return NULL;
}
spin_lock(&drm_mem_lock);
++drm_mem_stats[DRM_MEM_MAPPINGS].succeed_count;
drm_mem_stats[DRM_MEM_MAPPINGS].bytes_allocated += size;
spin_unlock(&drm_mem_lock);
return pt;
}
EXPORT_SYMBOL(drm_ioremap);
void *drm_ioremap_nocache(unsigned long offset, unsigned long size,
drm_device_t * dev)
{
void *pt;
if (!size) {
DRM_MEM_ERROR(DRM_MEM_MAPPINGS,
"Mapping 0 bytes at 0x%08lx\n", offset);
return NULL;
}
if (!(pt = drm_ioremap_nocache(offset, size, dev))) {
spin_lock(&drm_mem_lock);
++drm_mem_stats[DRM_MEM_MAPPINGS].fail_count;
spin_unlock(&drm_mem_lock);
return NULL;
}
spin_lock(&drm_mem_lock);
++drm_mem_stats[DRM_MEM_MAPPINGS].succeed_count;
drm_mem_stats[DRM_MEM_MAPPINGS].bytes_allocated += size;
spin_unlock(&drm_mem_lock);
return pt;
}
EXPORT_SYMBOL(drm_ioremap_nocache);
void drm_ioremapfree(void *pt, unsigned long size, drm_device_t * dev)
{
int alloc_count;
int free_count;
if (!pt)
DRM_MEM_ERROR(DRM_MEM_MAPPINGS,
"Attempt to free NULL pointer\n");
else
drm_ioremapfree(pt, size, dev);
spin_lock(&drm_mem_lock);
drm_mem_stats[DRM_MEM_MAPPINGS].bytes_freed += size;
free_count = ++drm_mem_stats[DRM_MEM_MAPPINGS].free_count;
alloc_count = drm_mem_stats[DRM_MEM_MAPPINGS].succeed_count;
spin_unlock(&drm_mem_lock);
if (free_count > alloc_count) {
DRM_MEM_ERROR(DRM_MEM_MAPPINGS,
"Excess frees: %d frees, %d allocs\n",
free_count, alloc_count);
}
}
EXPORT_SYMBOL(drm_ioremapfree);
#if __OS_HAS_AGP #if __OS_HAS_AGP
DRM_AGP_MEM *drm_alloc_agp(drm_device_t *dev, int pages, u32 type) DRM_AGP_MEM *drm_alloc_agp(drm_device_t *dev, int pages, u32 type)

View file

@ -275,74 +275,6 @@ void drm_free_pages (unsigned long address, int order, int area) {
} }
} }
void *drm_ioremap (unsigned long offset, unsigned long size,
drm_device_t * dev) {
void *pt;
if (!size) {
DRM_MEM_ERROR(DRM_MEM_MAPPINGS,
"Mapping 0 bytes at 0x%08lx\n", offset);
return NULL;
}
if (!(pt = drm_ioremap(offset, size, dev))) {
spin_lock(&drm_mem_lock);
++drm_mem_stats[DRM_MEM_MAPPINGS].fail_count;
spin_unlock(&drm_mem_lock);
return NULL;
}
spin_lock(&drm_mem_lock);
++drm_mem_stats[DRM_MEM_MAPPINGS].succeed_count;
drm_mem_stats[DRM_MEM_MAPPINGS].bytes_allocated += size;
spin_unlock(&drm_mem_lock);
return pt;
}
void *drm_ioremap_nocache (unsigned long offset, unsigned long size,
drm_device_t * dev) {
void *pt;
if (!size) {
DRM_MEM_ERROR(DRM_MEM_MAPPINGS,
"Mapping 0 bytes at 0x%08lx\n", offset);
return NULL;
}
if (!(pt = drm_ioremap_nocache(offset, size, dev))) {
spin_lock(&drm_mem_lock);
++drm_mem_stats[DRM_MEM_MAPPINGS].fail_count;
spin_unlock(&drm_mem_lock);
return NULL;
}
spin_lock(&drm_mem_lock);
++drm_mem_stats[DRM_MEM_MAPPINGS].succeed_count;
drm_mem_stats[DRM_MEM_MAPPINGS].bytes_allocated += size;
spin_unlock(&drm_mem_lock);
return pt;
}
void drm_ioremapfree (void *pt, unsigned long size, drm_device_t * dev) {
int alloc_count;
int free_count;
if (!pt)
DRM_MEM_ERROR(DRM_MEM_MAPPINGS,
"Attempt to free NULL pointer\n");
else
drm_ioremapfree(pt, size, dev);
spin_lock(&drm_mem_lock);
drm_mem_stats[DRM_MEM_MAPPINGS].bytes_freed += size;
free_count = ++drm_mem_stats[DRM_MEM_MAPPINGS].free_count;
alloc_count = drm_mem_stats[DRM_MEM_MAPPINGS].succeed_count;
spin_unlock(&drm_mem_lock);
if (free_count > alloc_count) {
DRM_MEM_ERROR(DRM_MEM_MAPPINGS,
"Excess frees: %d frees, %d allocs\n",
free_count, alloc_count);
}
}
#if __OS_HAS_AGP #if __OS_HAS_AGP
DRM_AGP_MEM *drm_alloc_agp (drm_device_t *dev, int pages, u32 type) { DRM_AGP_MEM *drm_alloc_agp (drm_device_t *dev, int pages, u32 type) {

View file

@ -49,11 +49,11 @@ unsigned long drm_mm_tail_space(drm_mm_t *mm)
struct list_head *tail_node; struct list_head *tail_node;
drm_mm_node_t *entry; drm_mm_node_t *entry;
tail_node = mm->root_node.ml_entry.prev; tail_node = mm->ml_entry.prev;
entry = list_entry(tail_node, drm_mm_node_t, ml_entry); entry = list_entry(tail_node, drm_mm_node_t, ml_entry);
if (!entry->free) if (!entry->free)
return 0; return 0;
return entry->size; return entry->size;
} }
@ -62,11 +62,11 @@ int drm_mm_remove_space_from_tail(drm_mm_t *mm, unsigned long size)
struct list_head *tail_node; struct list_head *tail_node;
drm_mm_node_t *entry; drm_mm_node_t *entry;
tail_node = mm->root_node.ml_entry.prev; tail_node = mm->ml_entry.prev;
entry = list_entry(tail_node, drm_mm_node_t, ml_entry); entry = list_entry(tail_node, drm_mm_node_t, ml_entry);
if (!entry->free) if (!entry->free)
return -ENOMEM; return -ENOMEM;
if (entry->size <= size) if (entry->size <= size)
return -ENOMEM; return -ENOMEM;
@ -80,10 +80,9 @@ static int drm_mm_create_tail_node(drm_mm_t *mm,
unsigned long size) unsigned long size)
{ {
drm_mm_node_t *child; drm_mm_node_t *child;
child = (drm_mm_node_t *) child = (drm_mm_node_t *)
drm_ctl_cache_alloc(drm_cache.mm, sizeof(*child), drm_ctl_alloc(sizeof(*child), DRM_MEM_MM);
GFP_KERNEL);
if (!child) if (!child)
return -ENOMEM; return -ENOMEM;
@ -92,19 +91,19 @@ static int drm_mm_create_tail_node(drm_mm_t *mm,
child->start = start; child->start = start;
child->mm = mm; child->mm = mm;
list_add_tail(&child->ml_entry, &mm->root_node.ml_entry); list_add_tail(&child->ml_entry, &mm->ml_entry);
list_add_tail(&child->fl_entry, &mm->root_node.fl_entry); list_add_tail(&child->fl_entry, &mm->fl_entry);
return 0; return 0;
} }
int drm_mm_add_space_to_tail(drm_mm_t *mm, unsigned long size) int drm_mm_add_space_to_tail(drm_mm_t *mm, unsigned long size)
{ {
struct list_head *tail_node; struct list_head *tail_node;
drm_mm_node_t *entry; drm_mm_node_t *entry;
tail_node = mm->root_node.ml_entry.prev; tail_node = mm->ml_entry.prev;
entry = list_entry(tail_node, drm_mm_node_t, ml_entry); entry = list_entry(tail_node, drm_mm_node_t, ml_entry);
if (!entry->free) { if (!entry->free) {
return drm_mm_create_tail_node(mm, entry->start + entry->size, size); return drm_mm_create_tail_node(mm, entry->start + entry->size, size);
@ -112,15 +111,14 @@ int drm_mm_add_space_to_tail(drm_mm_t *mm, unsigned long size)
entry->size += size; entry->size += size;
return 0; return 0;
} }
static drm_mm_node_t *drm_mm_split_at_start(drm_mm_node_t *parent, static drm_mm_node_t *drm_mm_split_at_start(drm_mm_node_t *parent,
unsigned long size) unsigned long size)
{ {
drm_mm_node_t *child; drm_mm_node_t *child;
child = (drm_mm_node_t *) child = (drm_mm_node_t *)
drm_ctl_cache_alloc(drm_cache.mm, sizeof(*child), drm_ctl_alloc(sizeof(*child), DRM_MEM_MM);
GFP_KERNEL);
if (!child) if (!child)
return NULL; return NULL;
@ -138,8 +136,6 @@ static drm_mm_node_t *drm_mm_split_at_start(drm_mm_node_t *parent,
parent->start += size; parent->start += size;
return child; return child;
} }
drm_mm_node_t *drm_mm_get_block(drm_mm_node_t * parent, drm_mm_node_t *drm_mm_get_block(drm_mm_node_t * parent,
unsigned long size, unsigned alignment) unsigned long size, unsigned alignment)
@ -150,26 +146,22 @@ drm_mm_node_t *drm_mm_get_block(drm_mm_node_t * parent,
unsigned tmp = 0; unsigned tmp = 0;
if (alignment) if (alignment)
tmp = size % alignment; tmp = parent->start % alignment;
if (tmp) { if (tmp) {
align_splitoff = drm_mm_split_at_start(parent, alignment - tmp); align_splitoff = drm_mm_split_at_start(parent, alignment - tmp);
if (!align_splitoff) if (!align_splitoff)
return NULL; return NULL;
} }
if (parent->size == size) { if (parent->size == size) {
list_del_init(&parent->fl_entry); list_del_init(&parent->fl_entry);
parent->free = 0; parent->free = 0;
return parent; return parent;
} else { } else {
child = drm_mm_split_at_start(parent, size); child = drm_mm_split_at_start(parent, size);
if (!child) {
if (align_splitoff)
drm_mm_put_block(align_splitoff);
return NULL;
}
} }
if (align_splitoff) if (align_splitoff)
drm_mm_put_block(align_splitoff); drm_mm_put_block(align_splitoff);
@ -185,9 +177,8 @@ void drm_mm_put_block(drm_mm_node_t * cur)
{ {
drm_mm_t *mm = cur->mm; drm_mm_t *mm = cur->mm;
drm_mm_node_t *list_root = &mm->root_node;
struct list_head *cur_head = &cur->ml_entry; struct list_head *cur_head = &cur->ml_entry;
struct list_head *root_head = &list_root->ml_entry; struct list_head *root_head = &mm->ml_entry;
drm_mm_node_t *prev_node = NULL; drm_mm_node_t *prev_node = NULL;
drm_mm_node_t *next_node; drm_mm_node_t *next_node;
@ -207,9 +198,8 @@ void drm_mm_put_block(drm_mm_node_t * cur)
prev_node->size += next_node->size; prev_node->size += next_node->size;
list_del(&next_node->ml_entry); list_del(&next_node->ml_entry);
list_del(&next_node->fl_entry); list_del(&next_node->fl_entry);
drm_ctl_cache_free(drm_cache.mm, drm_ctl_free(next_node, sizeof(*next_node),
sizeof(*next_node), DRM_MEM_MM);
next_node);
} else { } else {
next_node->size += cur->size; next_node->size += cur->size;
next_node->start = cur->start; next_node->start = cur->start;
@ -219,19 +209,20 @@ void drm_mm_put_block(drm_mm_node_t * cur)
} }
if (!merged) { if (!merged) {
cur->free = 1; cur->free = 1;
list_add(&cur->fl_entry, &list_root->fl_entry); list_add(&cur->fl_entry, &mm->fl_entry);
} else { } else {
list_del(&cur->ml_entry); list_del(&cur->ml_entry);
drm_ctl_cache_free(drm_cache.mm, sizeof(*cur), cur); drm_ctl_free(cur, sizeof(*cur), DRM_MEM_MM);
} }
} }
EXPORT_SYMBOL(drm_mm_put_block);
drm_mm_node_t *drm_mm_search_free(const drm_mm_t * mm, drm_mm_node_t *drm_mm_search_free(const drm_mm_t * mm,
unsigned long size, unsigned long size,
unsigned alignment, int best_match) unsigned alignment, int best_match)
{ {
struct list_head *list; struct list_head *list;
const struct list_head *free_stack = &mm->root_node.fl_entry; const struct list_head *free_stack = &mm->fl_entry;
drm_mm_node_t *entry; drm_mm_node_t *entry;
drm_mm_node_t *best; drm_mm_node_t *best;
unsigned long best_size; unsigned long best_size;
@ -244,8 +235,11 @@ drm_mm_node_t *drm_mm_search_free(const drm_mm_t * mm,
entry = list_entry(list, drm_mm_node_t, fl_entry); entry = list_entry(list, drm_mm_node_t, fl_entry);
wasted = 0; wasted = 0;
if (entry->size < size)
continue;
if (alignment) { if (alignment) {
register unsigned tmp = size % alignment; register unsigned tmp = entry->start % alignment;
if (tmp) if (tmp)
wasted += alignment - tmp; wasted += alignment - tmp;
} }
@ -266,15 +260,15 @@ drm_mm_node_t *drm_mm_search_free(const drm_mm_t * mm,
int drm_mm_clean(drm_mm_t * mm) int drm_mm_clean(drm_mm_t * mm)
{ {
struct list_head *head = &mm->root_node.ml_entry; struct list_head *head = &mm->ml_entry;
return (head->next->next == head); return (head->next->next == head);
} }
int drm_mm_init(drm_mm_t * mm, unsigned long start, unsigned long size) int drm_mm_init(drm_mm_t * mm, unsigned long start, unsigned long size)
{ {
INIT_LIST_HEAD(&mm->root_node.ml_entry); INIT_LIST_HEAD(&mm->ml_entry);
INIT_LIST_HEAD(&mm->root_node.fl_entry); INIT_LIST_HEAD(&mm->fl_entry);
return drm_mm_create_tail_node(mm, start, size); return drm_mm_create_tail_node(mm, start, size);
} }
@ -283,20 +277,20 @@ EXPORT_SYMBOL(drm_mm_init);
void drm_mm_takedown(drm_mm_t * mm) void drm_mm_takedown(drm_mm_t * mm)
{ {
struct list_head *bnode = mm->root_node.fl_entry.next; struct list_head *bnode = mm->fl_entry.next;
drm_mm_node_t *entry; drm_mm_node_t *entry;
entry = list_entry(bnode, drm_mm_node_t, fl_entry); entry = list_entry(bnode, drm_mm_node_t, fl_entry);
if (entry->ml_entry.next != &mm->root_node.ml_entry || if (entry->ml_entry.next != &mm->ml_entry ||
entry->fl_entry.next != &mm->root_node.fl_entry) { entry->fl_entry.next != &mm->fl_entry) {
DRM_ERROR("Memory manager not clean. Delaying takedown\n"); DRM_ERROR("Memory manager not clean. Delaying takedown\n");
return; return;
} }
list_del(&entry->fl_entry); list_del(&entry->fl_entry);
list_del(&entry->ml_entry); list_del(&entry->ml_entry);
drm_ctl_cache_free(drm_cache.mm, sizeof(*entry), entry); drm_ctl_free(entry, sizeof(*entry), DRM_MEM_MM);
} }
EXPORT_SYMBOL(drm_mm_takedown); EXPORT_SYMBOL(drm_mm_takedown);

View file

@ -1,8 +1,8 @@
/************************************************************************** /**************************************************************************
* *
* Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA * Copyright (c) 2006-2007 Tungsten Graphics, Inc., Cedar Park, TX., USA
* All Rights Reserved. * All Rights Reserved.
* *
* Permission is hereby granted, free of charge, to any person obtaining a * Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the * copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including * "Software"), to deal in the Software without restriction, including
@ -10,21 +10,23 @@
* distribute, sub license, and/or sell copies of the Software, and to * 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 * permit persons to whom the Software is furnished to do so, subject to
* the following conditions: * 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 * The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions * next paragraph) shall be included in all copies or substantial portions
* of the Software. * of the Software.
* *
* * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* USE OR OTHER DEALINGS IN THE SOFTWARE.
*
**************************************************************************/ **************************************************************************/
/*
* Authors: Thomas Hellström <thomas-at-tungstengraphics-dot-com>
*/
#include "drmP.h" #include "drmP.h"
@ -34,6 +36,8 @@ int drm_add_user_object(drm_file_t * priv, drm_user_object_t * item,
drm_device_t *dev = priv->head->dev; drm_device_t *dev = priv->head->dev;
int ret; int ret;
DRM_ASSERT_LOCKED(&dev->struct_mutex);
atomic_set(&item->refcount, 1); atomic_set(&item->refcount, 1);
item->shareable = shareable; item->shareable = shareable;
item->owner = priv; item->owner = priv;
@ -54,6 +58,8 @@ drm_user_object_t *drm_lookup_user_object(drm_file_t * priv, uint32_t key)
int ret; int ret;
drm_user_object_t *item; drm_user_object_t *item;
DRM_ASSERT_LOCKED(&dev->struct_mutex);
ret = drm_ht_find_item(&dev->object_hash, key, &hash); ret = drm_ht_find_item(&dev->object_hash, key, &hash);
if (ret) { if (ret) {
return NULL; return NULL;
@ -86,6 +92,8 @@ static void drm_deref_user_object(drm_file_t * priv, drm_user_object_t * item)
int drm_remove_user_object(drm_file_t * priv, drm_user_object_t * item) int drm_remove_user_object(drm_file_t * priv, drm_user_object_t * item)
{ {
DRM_ASSERT_LOCKED(&priv->head->dev->struct_mutex);
if (item->owner != priv) { if (item->owner != priv) {
DRM_ERROR("Cannot destroy object not owned by you.\n"); DRM_ERROR("Cannot destroy object not owned by you.\n");
return -EINVAL; return -EINVAL;
@ -123,6 +131,7 @@ int drm_add_ref_object(drm_file_t * priv, drm_user_object_t * referenced_object,
drm_ref_object_t *item; drm_ref_object_t *item;
drm_open_hash_t *ht = &priv->refd_object_hash[ref_action]; drm_open_hash_t *ht = &priv->refd_object_hash[ref_action];
DRM_ASSERT_LOCKED(&priv->head->dev->struct_mutex);
if (!referenced_object->shareable && priv != referenced_object->owner) { if (!referenced_object->shareable && priv != referenced_object->owner) {
DRM_ERROR("Not allowed to reference this object\n"); DRM_ERROR("Not allowed to reference this object\n");
return -EINVAL; return -EINVAL;
@ -179,6 +188,7 @@ drm_ref_object_t *drm_lookup_ref_object(drm_file_t * priv,
drm_hash_item_t *hash; drm_hash_item_t *hash;
int ret; int ret;
DRM_ASSERT_LOCKED(&priv->head->dev->struct_mutex);
ret = drm_ht_find_item(&priv->refd_object_hash[ref_action], ret = drm_ht_find_item(&priv->refd_object_hash[ref_action],
(unsigned long)referenced_object, &hash); (unsigned long)referenced_object, &hash);
if (ret) if (ret)
@ -211,6 +221,7 @@ void drm_remove_ref_object(drm_file_t * priv, drm_ref_object_t * item)
drm_open_hash_t *ht = &priv->refd_object_hash[item->unref_action]; drm_open_hash_t *ht = &priv->refd_object_hash[item->unref_action];
drm_ref_t unref_action; drm_ref_t unref_action;
DRM_ASSERT_LOCKED(&priv->head->dev->struct_mutex);
unref_action = item->unref_action; unref_action = item->unref_action;
if (atomic_dec_and_test(&item->refcount)) { if (atomic_dec_and_test(&item->refcount)) {
ret = drm_ht_remove_item(ht, &item->hash); ret = drm_ht_remove_item(ht, &item->hash);
@ -238,11 +249,17 @@ int drm_user_object_ref(drm_file_t * priv, uint32_t user_token,
{ {
drm_device_t *dev = priv->head->dev; drm_device_t *dev = priv->head->dev;
drm_user_object_t *uo; drm_user_object_t *uo;
drm_hash_item_t *hash;
int ret; int ret;
mutex_lock(&dev->struct_mutex); mutex_lock(&dev->struct_mutex);
uo = drm_lookup_user_object(priv, user_token); ret = drm_ht_find_item(&dev->object_hash, user_token, &hash);
if (!uo || (uo->type != type)) { if (ret) {
DRM_ERROR("Could not find user object to reference.\n");
goto out_err;
}
uo = drm_hash_entry(hash, drm_user_object_t, hash);
if (uo->type != type) {
ret = -EINVAL; ret = -EINVAL;
goto out_err; goto out_err;
} }
@ -251,7 +268,6 @@ int drm_user_object_ref(drm_file_t * priv, uint32_t user_token,
goto out_err; goto out_err;
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
*object = uo; *object = uo;
DRM_ERROR("Referenced an object\n");
return 0; return 0;
out_err: out_err:
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
@ -279,7 +295,6 @@ int drm_user_object_unref(drm_file_t * priv, uint32_t user_token,
} }
drm_remove_ref_object(priv, ro); drm_remove_ref_object(priv, ro);
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
DRM_ERROR("Unreferenced an object\n");
return 0; return 0;
out_err: out_err:
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);

484
linux-core/drm_objects.h Normal file
View file

@ -0,0 +1,484 @@
/**************************************************************************
*
* 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>
*/
#ifndef _DRM_OBJECTS_H
#define _DRM_OBJECTS_H
struct drm_device;
/***************************************************
* User space objects. (drm_object.c)
*/
#define drm_user_object_entry(_ptr, _type, _member) container_of(_ptr, _type, _member)
typedef enum {
drm_fence_type,
drm_buffer_type,
drm_ttm_type
/*
* Add other user space object types here.
*/
} drm_object_type_t;
/*
* A user object is a structure that helps the drm give out user handles
* to kernel internal objects and to keep track of these objects so that
* they can be destroyed, for example when the user space process exits.
* Designed to be accessible using a user space 32-bit handle.
*/
typedef struct drm_user_object {
drm_hash_item_t hash;
struct list_head list;
drm_object_type_t type;
atomic_t refcount;
int shareable;
drm_file_t *owner;
void (*ref_struct_locked) (drm_file_t * priv,
struct drm_user_object * obj,
drm_ref_t ref_action);
void (*unref) (drm_file_t * priv, struct drm_user_object * obj,
drm_ref_t unref_action);
void (*remove) (drm_file_t * priv, struct drm_user_object * obj);
} drm_user_object_t;
/*
* A ref object is a structure which is used to
* keep track of references to user objects and to keep track of these
* references so that they can be destroyed for example when the user space
* process exits. Designed to be accessible using a pointer to the _user_ object.
*/
typedef struct drm_ref_object {
drm_hash_item_t hash;
struct list_head list;
atomic_t refcount;
drm_ref_t unref_action;
} drm_ref_object_t;
/**
* Must be called with the struct_mutex held.
*/
extern int drm_add_user_object(drm_file_t * priv, drm_user_object_t * item,
int shareable);
/**
* Must be called with the struct_mutex held.
*/
extern drm_user_object_t *drm_lookup_user_object(drm_file_t * priv,
uint32_t key);
/*
* Must be called with the struct_mutex held.
* If "item" has been obtained by a call to drm_lookup_user_object. You may not
* release the struct_mutex before calling drm_remove_ref_object.
* This function may temporarily release the struct_mutex.
*/
extern int drm_remove_user_object(drm_file_t * priv, drm_user_object_t * item);
/*
* Must be called with the struct_mutex held. May temporarily release it.
*/
extern int drm_add_ref_object(drm_file_t * priv,
drm_user_object_t * referenced_object,
drm_ref_t ref_action);
/*
* Must be called with the struct_mutex held.
*/
drm_ref_object_t *drm_lookup_ref_object(drm_file_t * priv,
drm_user_object_t * referenced_object,
drm_ref_t ref_action);
/*
* Must be called with the struct_mutex held.
* If "item" has been obtained by a call to drm_lookup_ref_object. You may not
* release the struct_mutex before calling drm_remove_ref_object.
* This function may temporarily release the struct_mutex.
*/
extern void drm_remove_ref_object(drm_file_t * priv, drm_ref_object_t * item);
extern int drm_user_object_ref(drm_file_t * priv, uint32_t user_token,
drm_object_type_t type,
drm_user_object_t ** object);
extern int drm_user_object_unref(drm_file_t * priv, uint32_t user_token,
drm_object_type_t type);
/***************************************************
* Fence objects. (drm_fence.c)
*/
typedef struct drm_fence_object {
drm_user_object_t base;
atomic_t usage;
/*
* The below three fields are protected by the fence manager spinlock.
*/
struct list_head ring;
int class;
uint32_t native_type;
uint32_t type;
uint32_t signaled;
uint32_t sequence;
uint32_t flush_mask;
uint32_t submitted_flush;
} drm_fence_object_t;
#define _DRM_FENCE_CLASSES 8
#define _DRM_FENCE_TYPE_EXE 0x00
typedef struct drm_fence_class_manager {
struct list_head ring;
uint32_t pending_flush;
wait_queue_head_t fence_queue;
int pending_exe_flush;
uint32_t last_exe_flush;
uint32_t exe_flush_sequence;
} drm_fence_class_manager_t;
typedef struct drm_fence_manager {
int initialized;
rwlock_t lock;
drm_fence_class_manager_t class[_DRM_FENCE_CLASSES];
uint32_t num_classes;
atomic_t count;
} drm_fence_manager_t;
typedef struct drm_fence_driver {
uint32_t num_classes;
uint32_t wrap_diff;
uint32_t flush_diff;
uint32_t sequence_mask;
int lazy_capable;
int (*has_irq) (struct drm_device * dev, uint32_t class,
uint32_t flags);
int (*emit) (struct drm_device * dev, uint32_t class, uint32_t flags,
uint32_t * breadcrumb, uint32_t * native_type);
void (*poke_flush) (struct drm_device * dev, uint32_t class);
} drm_fence_driver_t;
extern void drm_fence_handler(struct drm_device *dev, uint32_t class,
uint32_t sequence, uint32_t type);
extern void drm_fence_manager_init(struct drm_device *dev);
extern void drm_fence_manager_takedown(struct drm_device *dev);
extern void drm_fence_flush_old(struct drm_device *dev, uint32_t class,
uint32_t sequence);
extern int drm_fence_object_flush(struct drm_device *dev,
drm_fence_object_t * fence, uint32_t type);
extern int drm_fence_object_signaled(struct drm_device *dev,
drm_fence_object_t * fence,
uint32_t type, int flush);
extern void drm_fence_usage_deref_locked(struct drm_device *dev,
drm_fence_object_t * fence);
extern void drm_fence_usage_deref_unlocked(struct drm_device *dev,
drm_fence_object_t * fence);
extern int drm_fence_object_wait(struct drm_device *dev,
drm_fence_object_t * fence,
int lazy, int ignore_signals, uint32_t mask);
extern int drm_fence_object_create(struct drm_device *dev, uint32_t type,
uint32_t fence_flags, uint32_t class,
drm_fence_object_t ** c_fence);
extern int drm_fence_add_user_object(drm_file_t * priv,
drm_fence_object_t * fence, int shareable);
extern int drm_fence_ioctl(DRM_IOCTL_ARGS);
/**************************************************
*TTMs
*/
/*
* The ttm backend GTT interface. (In our case AGP).
* Any similar type of device (PCIE?)
* needs only to implement these functions to be usable with the "TTM" interface.
* The AGP backend implementation lives in drm_agpsupport.c
* basically maps these calls to available functions in agpgart.
* Each drm device driver gets an
* additional function pointer that creates these types,
* so that the device can choose the correct aperture.
* (Multiple AGP apertures, etc.)
* Most device drivers will let this point to the standard AGP implementation.
*/
#define DRM_BE_FLAG_NEEDS_FREE 0x00000001
#define DRM_BE_FLAG_BOUND_CACHED 0x00000002
struct drm_ttm_backend;
typedef struct drm_ttm_backend_func {
int (*needs_ub_cache_adjust) (struct drm_ttm_backend * backend);
int (*populate) (struct drm_ttm_backend * backend,
unsigned long num_pages, struct page ** pages);
void (*clear) (struct drm_ttm_backend * backend);
int (*bind) (struct drm_ttm_backend * backend,
unsigned long offset, int cached);
int (*unbind) (struct drm_ttm_backend * backend);
void (*destroy) (struct drm_ttm_backend * backend);
} drm_ttm_backend_func_t;
typedef struct drm_ttm_backend {
uint32_t flags;
int mem_type;
drm_ttm_backend_func_t *func;
} drm_ttm_backend_t;
typedef struct drm_ttm {
struct page **pages;
uint32_t page_flags;
unsigned long num_pages;
unsigned long aper_offset;
atomic_t vma_count;
struct drm_device *dev;
int destroy;
uint32_t mapping_offset;
drm_ttm_backend_t *be;
enum {
ttm_bound,
ttm_evicted,
ttm_unbound,
ttm_unpopulated,
} state;
} drm_ttm_t;
extern drm_ttm_t *drm_ttm_init(struct drm_device *dev, unsigned long size);
extern int drm_bind_ttm(drm_ttm_t * ttm, int cached, unsigned long aper_offset);
extern void drm_ttm_unbind(drm_ttm_t * ttm);
extern void drm_ttm_evict(drm_ttm_t * ttm);
extern void drm_ttm_fixup_caching(drm_ttm_t * ttm);
extern struct page *drm_ttm_get_page(drm_ttm_t * ttm, int index);
/*
* Destroy a ttm. The user normally calls drmRmMap or a similar IOCTL to do this,
* which calls this function iff there are no vmas referencing it anymore. Otherwise it is called
* when the last vma exits.
*/
extern int drm_destroy_ttm(drm_ttm_t * ttm);
#define DRM_FLAG_MASKED(_old, _new, _mask) {\
(_old) ^= (((_old) ^ (_new)) & (_mask)); \
}
#define DRM_TTM_MASK_FLAGS ((1 << PAGE_SHIFT) - 1)
#define DRM_TTM_MASK_PFN (0xFFFFFFFFU - DRM_TTM_MASK_FLAGS)
/*
* Page flags.
*/
#define DRM_TTM_PAGE_UNCACHED 0x01
#define DRM_TTM_PAGE_USED 0x02
#define DRM_TTM_PAGE_BOUND 0x04
#define DRM_TTM_PAGE_PRESENT 0x08
#define DRM_TTM_PAGE_VMALLOC 0x10
/***************************************************
* Buffer objects. (drm_bo.c, drm_bo_move.c)
*/
typedef struct drm_bo_mem_reg {
drm_mm_node_t *mm_node;
unsigned long size;
unsigned long num_pages;
uint32_t page_alignment;
uint32_t mem_type;
uint32_t flags;
uint32_t mask;
} drm_bo_mem_reg_t;
typedef struct drm_buffer_object {
struct drm_device *dev;
drm_user_object_t base;
/*
* If there is a possibility that the usage variable is zero,
* then dev->struct_mutext should be locked before incrementing it.
*/
atomic_t usage;
unsigned long buffer_start;
drm_bo_type_t type;
unsigned long offset;
atomic_t mapped;
drm_bo_mem_reg_t mem;
struct list_head lru;
struct list_head ddestroy;
uint32_t fence_type;
uint32_t fence_class;
drm_fence_object_t *fence;
uint32_t priv_flags;
wait_queue_head_t event_queue;
struct mutex mutex;
/* For pinned buffers */
drm_mm_node_t *pinned_node;
uint32_t pinned_mem_type;
struct list_head pinned_lru;
/* For vm */
drm_ttm_t *ttm;
drm_map_list_t map_list;
uint32_t memory_type;
unsigned long bus_offset;
uint32_t vm_flags;
void *iomap;
#ifdef DRM_ODD_MM_COMPAT
/* dev->struct_mutex only protected. */
struct list_head vma_list;
struct list_head p_mm_list;
#endif
} drm_buffer_object_t;
#define _DRM_BO_FLAG_UNFENCED 0x00000001
#define _DRM_BO_FLAG_EVICTED 0x00000002
typedef struct drm_mem_type_manager {
int has_type;
int use_type;
drm_mm_t manager;
struct list_head lru;
struct list_head pinned;
uint32_t flags;
uint32_t drm_bus_maptype;
unsigned long io_offset;
unsigned long io_size;
void *io_addr;
} drm_mem_type_manager_t;
#define _DRM_FLAG_MEMTYPE_FIXED 0x00000001 /* Fixed (on-card) PCI memory */
#define _DRM_FLAG_MEMTYPE_MAPPABLE 0x00000002 /* Memory mappable */
#define _DRM_FLAG_MEMTYPE_CACHED 0x00000004 /* Cached binding */
#define _DRM_FLAG_NEEDS_IOREMAP 0x00000008 /* Fixed memory needs ioremap
before kernel access. */
#define _DRM_FLAG_MEMTYPE_CMA 0x00000010 /* Can't map aperture */
#define _DRM_FLAG_MEMTYPE_CSELECT 0x00000020 /* Select caching */
typedef struct drm_buffer_manager {
struct mutex init_mutex;
struct mutex evict_mutex;
int nice_mode;
int initialized;
drm_file_t *last_to_validate;
drm_mem_type_manager_t man[DRM_BO_MEM_TYPES];
struct list_head unfenced;
struct list_head ddestroy;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
struct work_struct wq;
#else
struct delayed_work wq;
#endif
uint32_t fence_type;
unsigned long cur_pages;
atomic_t count;
} drm_buffer_manager_t;
typedef struct drm_bo_driver {
const uint32_t *mem_type_prio;
const uint32_t *mem_busy_prio;
uint32_t num_mem_type_prio;
uint32_t num_mem_busy_prio;
drm_ttm_backend_t *(*create_ttm_backend_entry)
(struct drm_device * dev);
int (*fence_type) (struct drm_buffer_object *bo, uint32_t * class, uint32_t * type);
int (*invalidate_caches) (struct drm_device * dev, uint32_t flags);
int (*init_mem_type) (struct drm_device * dev, uint32_t type,
drm_mem_type_manager_t * man);
uint32_t(*evict_mask) (struct drm_buffer_object *bo);
int (*move) (struct drm_buffer_object * bo,
int evict, int no_wait, struct drm_bo_mem_reg * new_mem);
} drm_bo_driver_t;
/*
* buffer objects (drm_bo.c)
*/
extern int drm_bo_ioctl(DRM_IOCTL_ARGS);
extern int drm_mm_init_ioctl(DRM_IOCTL_ARGS);
extern int drm_bo_driver_finish(struct drm_device *dev);
extern int drm_bo_driver_init(struct drm_device *dev);
extern int drm_bo_pci_offset(struct drm_device *dev,
drm_bo_mem_reg_t * mem,
unsigned long *bus_base,
unsigned long *bus_offset,
unsigned long *bus_size);
extern int drm_mem_reg_is_pci(struct drm_device *dev, drm_bo_mem_reg_t * mem);
extern void drm_bo_usage_deref_locked(drm_buffer_object_t * bo);
extern int drm_fence_buffer_objects(drm_file_t * priv,
struct list_head *list,
uint32_t fence_flags,
drm_fence_object_t * fence,
drm_fence_object_t ** used_fence);
extern void drm_bo_add_to_lru(drm_buffer_object_t * bo);
extern int drm_bo_wait(drm_buffer_object_t * bo, int lazy, int ignore_signals,
int no_wait);
extern int drm_bo_mem_space(drm_buffer_object_t * bo,
drm_bo_mem_reg_t * mem, int no_wait);
extern int drm_bo_move_buffer(drm_buffer_object_t * bo, uint32_t new_mem_flags,
int no_wait, int move_unfenced);
/*
* Buffer object memory move helpers.
* drm_bo_move.c
*/
extern int drm_bo_move_ttm(drm_buffer_object_t * bo,
int evict, int no_wait, drm_bo_mem_reg_t * new_mem);
extern int drm_bo_move_memcpy(drm_buffer_object_t * bo,
int evict,
int no_wait, drm_bo_mem_reg_t * new_mem);
extern int drm_bo_move_accel_cleanup(drm_buffer_object_t * bo,
int evict,
int no_wait,
uint32_t fence_class,
uint32_t fence_type,
uint32_t fence_flags,
drm_bo_mem_reg_t * new_mem);
#ifdef CONFIG_DEBUG_MUTEXES
#define DRM_ASSERT_LOCKED(_mutex) \
BUG_ON(!mutex_is_locked(_mutex) || \
((_mutex)->owner != current_thread_info()))
#else
#define DRM_ASSERT_LOCKED(_mutex)
#endif
#endif

View file

@ -56,7 +56,7 @@
drm_device_t *dev = priv->head->dev drm_device_t *dev = priv->head->dev
/** IRQ handler arguments and return type and values */ /** IRQ handler arguments and return type and values */
#define DRM_IRQ_ARGS int irq, void *arg, struct pt_regs *regs #define DRM_IRQ_ARGS int irq, void *arg
/** backwards compatibility with old irq return values */ /** backwards compatibility with old irq return values */
#ifndef IRQ_HANDLED #ifndef IRQ_HANDLED
typedef void irqreturn_t; typedef void irqreturn_t;
@ -66,13 +66,8 @@ typedef void irqreturn_t;
/** AGP types */ /** AGP types */
#if __OS_HAS_AGP #if __OS_HAS_AGP
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,70)
#define DRM_AGP_MEM agp_memory
#define DRM_AGP_KERN agp_kern_info
#else
#define DRM_AGP_MEM struct agp_memory #define DRM_AGP_MEM struct agp_memory
#define DRM_AGP_KERN struct agp_kern_info #define DRM_AGP_KERN struct agp_kern_info
#endif
#else #else
/* define some dummy types for non AGP supporting kernels */ /* define some dummy types for non AGP supporting kernels */
struct no_agp_kern { struct no_agp_kern {
@ -98,9 +93,6 @@ static __inline__ int mtrr_del(int reg, unsigned long base, unsigned long size)
#define MTRR_TYPE_WRCOMB 1 #define MTRR_TYPE_WRCOMB 1
#endif #endif
/** Task queue handler arguments */
#define DRM_TASKQUEUE_ARGS void *arg
/** For data going into the kernel through the ioctl argument */ /** For data going into the kernel through the ioctl argument */
#define DRM_COPY_FROM_USER_IOCTL(arg1, arg2, arg3) \ #define DRM_COPY_FROM_USER_IOCTL(arg1, arg2, arg3) \
if ( copy_from_user(&arg1, arg2, arg3) ) \ if ( copy_from_user(&arg1, arg2, arg3) ) \
@ -127,24 +119,6 @@ static __inline__ int mtrr_del(int reg, unsigned long base, unsigned long size)
#define DRM_GET_PRIV_WITH_RETURN(_priv, _filp) _priv = _filp->private_data #define DRM_GET_PRIV_WITH_RETURN(_priv, _filp) _priv = _filp->private_data
/**
* Get the pointer to the SAREA.
*
* Searches the SAREA on the mapping lists and points drm_device::sarea to it.
*/
#define DRM_GETSAREA() \
do { \
drm_map_list_t *entry; \
list_for_each_entry( entry, &dev->maplist->head, head ) { \
if ( entry->map && \
entry->map->type == _DRM_SHM && \
(entry->map->flags & _DRM_CONTAINS_LOCK) ) { \
dev_priv->sarea = entry->map; \
break; \
} \
} \
} while (0)
#define DRM_HZ HZ #define DRM_HZ HZ
#define DRM_WAIT_ON( ret, queue, timeout, condition ) \ #define DRM_WAIT_ON( ret, queue, timeout, condition ) \

View file

@ -51,10 +51,8 @@ drm_dma_handle_t *drm_pci_alloc(drm_device_t * dev, size_t size, size_t align,
dma_addr_t maxaddr) dma_addr_t maxaddr)
{ {
drm_dma_handle_t *dmah; drm_dma_handle_t *dmah;
#if 1
unsigned long addr; unsigned long addr;
size_t sz; size_t sz;
#endif
#ifdef DRM_DEBUG_MEMORY #ifdef DRM_DEBUG_MEMORY
int area = DRM_MEM_DMA; int area = DRM_MEM_DMA;

View file

@ -75,7 +75,7 @@ static struct drm_proc_list {
#endif #endif
}; };
#define DRM_PROC_ENTRIES (sizeof(drm_proc_list)/sizeof(drm_proc_list[0])) #define DRM_PROC_ENTRIES ARRAY_SIZE(drm_proc_list)
/** /**
* Initialize the DRI proc filesystem for a device. * Initialize the DRI proc filesystem for a device.
@ -211,7 +211,6 @@ static int drm__vm_info(char *buf, char **start, off_t offset, int request,
int len = 0; int len = 0;
drm_map_t *map; drm_map_t *map;
drm_map_list_t *r_list; drm_map_list_t *r_list;
struct list_head *list;
/* Hardcoded from _DRM_FRAME_BUFFER, /* Hardcoded from _DRM_FRAME_BUFFER,
_DRM_REGISTERS, _DRM_SHM, _DRM_AGP, _DRM_REGISTERS, _DRM_SHM, _DRM_AGP,
@ -231,9 +230,7 @@ static int drm__vm_info(char *buf, char **start, off_t offset, int request,
DRM_PROC_PRINT("slot offset size type flags " DRM_PROC_PRINT("slot offset size type flags "
"address mtrr\n\n"); "address mtrr\n\n");
i = 0; i = 0;
if (dev->maplist != NULL) list_for_each_entry(r_list, &dev->maplist, head) {
list_for_each(list, &dev->maplist->head) {
r_list = list_entry(list, drm_map_list_t, head);
map = r_list->map; map = r_list->map;
if (!map) if (!map)
continue; continue;
@ -242,10 +239,10 @@ static int drm__vm_info(char *buf, char **start, off_t offset, int request,
else else
type = types[map->type]; type = types[map->type];
DRM_PROC_PRINT("%4d 0x%08lx 0x%08lx %4.4s 0x%02x 0x%08lx ", DRM_PROC_PRINT("%4d 0x%08lx 0x%08lx %4.4s 0x%02x 0x%08lx ",
i, i,
map->offset, map->offset,
map->size, type, map->flags, map->size, type, map->flags,
(unsigned long) r_list->user_token); (unsigned long) r_list->user_token);
if (map->mtrr < 0) { if (map->mtrr < 0) {
DRM_PROC_PRINT("none\n"); DRM_PROC_PRINT("none\n");
@ -253,7 +250,7 @@ static int drm__vm_info(char *buf, char **start, off_t offset, int request,
DRM_PROC_PRINT("%4d\n", map->mtrr); DRM_PROC_PRINT("%4d\n", map->mtrr);
} }
i++; i++;
} }
if (len > request + offset) if (len > request + offset)
return request; return request;
@ -438,7 +435,7 @@ static int drm__objects_info(char *buf, char **start, off_t offset, int request,
drm_device_t *dev = (drm_device_t *) data; drm_device_t *dev = (drm_device_t *) data;
int len = 0; int len = 0;
drm_buffer_manager_t *bm = &dev->bm; drm_buffer_manager_t *bm = &dev->bm;
drm_fence_manager_t *fm = &dev->fm; drm_fence_manager_t *fm = &dev->fm;
drm_u64_t used_mem; drm_u64_t used_mem;
drm_u64_t low_mem; drm_u64_t low_mem;
drm_u64_t high_mem; drm_u64_t high_mem;
@ -451,34 +448,38 @@ static int drm__objects_info(char *buf, char **start, off_t offset, int request,
*start = &buf[offset]; *start = &buf[offset];
*eof = 0; *eof = 0;
DRM_PROC_PRINT("Object accounting:\n\n");
if (fm->initialized) { if (fm->initialized) {
DRM_PROC_PRINT("Number of active fence objects: %d.\n\n", DRM_PROC_PRINT("Number of active fence objects: %d.\n",
atomic_read(&fm->count)); atomic_read(&fm->count));
} else { } else {
DRM_PROC_PRINT("Fence objects are not supported by this driver\n\n"); DRM_PROC_PRINT("Fence objects are not supported by this driver\n");
} }
if (bm->initialized) { if (bm->initialized) {
DRM_PROC_PRINT("Number of active buffer objects: %d.\n\n", DRM_PROC_PRINT("Number of active buffer objects: %d.\n\n",
atomic_read(&bm->count)); atomic_read(&bm->count));
}
DRM_PROC_PRINT("Memory accounting:\n\n");
if (bm->initialized) {
DRM_PROC_PRINT("Number of locked GATT pages: %lu.\n", bm->cur_pages); DRM_PROC_PRINT("Number of locked GATT pages: %lu.\n", bm->cur_pages);
} else { } else {
DRM_PROC_PRINT("Buffer objects are not supported by this driver.\n\n"); DRM_PROC_PRINT("Buffer objects are not supported by this driver.\n");
} }
drm_query_memctl(&used_mem, &low_mem, &high_mem); drm_query_memctl(&used_mem, &low_mem, &high_mem);
if (used_mem > 16*PAGE_SIZE) { if (used_mem > 16*PAGE_SIZE) {
DRM_PROC_PRINT("Used object memory is %lu pages.\n", DRM_PROC_PRINT("Used object memory is %lu pages.\n",
(unsigned long) (used_mem >> PAGE_SHIFT)); (unsigned long) (used_mem >> PAGE_SHIFT));
} else { } else {
DRM_PROC_PRINT("Used object memory is %lu bytes.\n", DRM_PROC_PRINT("Used object memory is %lu bytes.\n",
(unsigned long) used_mem); (unsigned long) used_mem);
} }
DRM_PROC_PRINT("Soft object memory usage threshold is %lu pages.\n", DRM_PROC_PRINT("Soft object memory usage threshold is %lu pages.\n",
(unsigned long) (low_mem >> PAGE_SHIFT)); (unsigned long) (low_mem >> PAGE_SHIFT));
DRM_PROC_PRINT("Hard object memory usage threshold is %lu pages.\n", DRM_PROC_PRINT("Hard object memory usage threshold is %lu pages.\n",
(unsigned long) (high_mem >> PAGE_SHIFT)); (unsigned long) (high_mem >> PAGE_SHIFT));
DRM_PROC_PRINT("\n"); DRM_PROC_PRINT("\n");
@ -531,7 +532,7 @@ static int drm__clients_info(char *buf, char **start, off_t offset,
*eof = 0; *eof = 0;
DRM_PROC_PRINT("a dev pid uid magic ioctls\n\n"); DRM_PROC_PRINT("a dev pid uid magic ioctls\n\n");
for (priv = dev->file_first; priv; priv = priv->next) { list_for_each_entry(priv, &dev->filelist, lhead) {
DRM_PROC_PRINT("%c %3d %5d %5d %10u %10lu\n", DRM_PROC_PRINT("%c %3d %5d %5d %10u %10lu\n",
priv->authenticated ? 'y' : 'n', priv->authenticated ? 'y' : 'n',
priv->minor, priv->minor,
@ -584,7 +585,7 @@ static int drm__vma_info(char *buf, char **start, off_t offset, int request,
DRM_PROC_PRINT("vma use count: %d, high_memory = %p, 0x%08lx\n", DRM_PROC_PRINT("vma use count: %d, high_memory = %p, 0x%08lx\n",
atomic_read(&dev->vma_count), atomic_read(&dev->vma_count),
high_memory, virt_to_phys(high_memory)); high_memory, virt_to_phys(high_memory));
for (pt = dev->vmalist; pt; pt = pt->next) { list_for_each_entry(pt, &dev->vmalist, head) {
if (!(vma = pt->vma)) if (!(vma = pt->vma))
continue; continue;
DRM_PROC_PRINT("\n%5d 0x%08lx-0x%08lx %c%c%c%c%c%c 0x%08lx000", DRM_PROC_PRINT("\n%5d 0x%08lx-0x%08lx %c%c%c%c%c%c 0x%08lx000",

1
linux-core/drm_sarea.h Symbolic link
View file

@ -0,0 +1 @@
../shared-core/drm_sarea.h

View file

@ -161,6 +161,7 @@ drm_sman_set_manager(drm_sman_t * sman, unsigned int manager,
return 0; return 0;
} }
EXPORT_SYMBOL(drm_sman_set_manager);
static drm_owner_item_t *drm_sman_get_owner_item(drm_sman_t * sman, static drm_owner_item_t *drm_sman_get_owner_item(drm_sman_t * sman,
unsigned long owner) unsigned long owner)

View file

@ -47,32 +47,36 @@ MODULE_LICENSE("GPL and additional rights");
MODULE_PARM_DESC(cards_limit, "Maximum number of graphics cards"); MODULE_PARM_DESC(cards_limit, "Maximum number of graphics cards");
MODULE_PARM_DESC(debug, "Enable debug output"); MODULE_PARM_DESC(debug, "Enable debug output");
module_param_named(cards_limit, drm_cards_limit, int, S_IRUGO); module_param_named(cards_limit, drm_cards_limit, int, 0444);
module_param_named(debug, drm_debug, int, S_IRUGO|S_IWUGO); module_param_named(debug, drm_debug, int, 0600);
drm_head_t **drm_heads; drm_head_t **drm_heads;
struct drm_sysfs_class *drm_class; struct drm_sysfs_class *drm_class;
struct proc_dir_entry *drm_proc_root; struct proc_dir_entry *drm_proc_root;
drm_cache_t drm_cache =
{ .mm = NULL,
.fence_object = NULL
};
static int drm_fill_in_dev(drm_device_t * dev, struct pci_dev *pdev, static int drm_fill_in_dev(drm_device_t * dev, struct pci_dev *pdev,
const struct pci_device_id *ent, const struct pci_device_id *ent,
struct drm_driver *driver) struct drm_driver *driver)
{ {
int retcode; int retcode;
INIT_LIST_HEAD(&dev->filelist);
INIT_LIST_HEAD(&dev->ctxlist);
INIT_LIST_HEAD(&dev->vmalist);
INIT_LIST_HEAD(&dev->maplist);
spin_lock_init(&dev->count_lock); spin_lock_init(&dev->count_lock);
spin_lock_init(&dev->drw_lock); spin_lock_init(&dev->drw_lock);
spin_lock_init(&dev->tasklet_lock); spin_lock_init(&dev->tasklet_lock);
spin_lock_init(&dev->lock.spinlock);
init_timer(&dev->timer); init_timer(&dev->timer);
mutex_init(&dev->struct_mutex); mutex_init(&dev->struct_mutex);
mutex_init(&dev->ctxlist_mutex); mutex_init(&dev->ctxlist_mutex);
mutex_init(&dev->bm.init_mutex); mutex_init(&dev->bm.init_mutex);
mutex_init(&dev->bm.evict_mutex);
idr_init(&dev->drw_idr);
dev->pdev = pdev; dev->pdev = pdev;
dev->pci_device = pdev->device; dev->pci_device = pdev->device;
dev->pci_vendor = pdev->vendor; dev->pci_vendor = pdev->vendor;
@ -83,28 +87,20 @@ static int drm_fill_in_dev(drm_device_t * dev, struct pci_dev *pdev,
dev->irq = pdev->irq; dev->irq = pdev->irq;
if (drm_ht_create(&dev->map_hash, DRM_MAP_HASH_ORDER)) { if (drm_ht_create(&dev->map_hash, DRM_MAP_HASH_ORDER)) {
drm_free(dev->maplist, sizeof(*dev->maplist), DRM_MEM_MAPS);
return -ENOMEM; return -ENOMEM;
} }
if (drm_mm_init(&dev->offset_manager, DRM_FILE_PAGE_OFFSET_START, if (drm_mm_init(&dev->offset_manager, DRM_FILE_PAGE_OFFSET_START,
DRM_FILE_PAGE_OFFSET_SIZE)) { DRM_FILE_PAGE_OFFSET_SIZE)) {
drm_free(dev->maplist, sizeof(*dev->maplist), DRM_MEM_MAPS);
drm_ht_remove(&dev->map_hash); drm_ht_remove(&dev->map_hash);
return -ENOMEM; return -ENOMEM;
} }
if (drm_ht_create(&dev->object_hash, DRM_OBJECT_HASH_ORDER)) { if (drm_ht_create(&dev->object_hash, DRM_OBJECT_HASH_ORDER)) {
drm_free(dev->maplist, sizeof(*dev->maplist), DRM_MEM_MAPS);
drm_ht_remove(&dev->map_hash); drm_ht_remove(&dev->map_hash);
drm_mm_takedown(&dev->offset_manager); drm_mm_takedown(&dev->offset_manager);
return -ENOMEM; return -ENOMEM;
} }
dev->maplist = drm_calloc(1, sizeof(*dev->maplist), DRM_MEM_MAPS);
if (dev->maplist == NULL)
return -ENOMEM;
INIT_LIST_HEAD(&dev->maplist->head);
/* the DRM has 6 counters */ /* the DRM has 6 counters */
dev->counters = 6; dev->counters = 6;
dev->types[0] = _DRM_STAT_LOCK; dev->types[0] = _DRM_STAT_LOCK;
@ -249,9 +245,9 @@ int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
if ((ret = drm_get_head(dev, &dev->primary))) if ((ret = drm_get_head(dev, &dev->primary)))
goto err_g1; goto err_g1;
DRM_INFO("Initialized %s %d.%d.%d %s on minor %d: %s\n", DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n",
driver->name, driver->major, driver->minor, driver->patchlevel, driver->name, driver->major, driver->minor, driver->patchlevel,
driver->date, dev->primary.minor, pci_pretty_name(dev->pdev)); driver->date, dev->primary.minor);
return 0; return 0;

View file

@ -162,7 +162,7 @@ struct class_device *drm_sysfs_device_add(struct drm_sysfs_class *cs,
memset(s_dev, 0x00, sizeof(*s_dev)); memset(s_dev, 0x00, sizeof(*s_dev));
s_dev->dev = MKDEV(DRM_MAJOR, head->minor); s_dev->dev = MKDEV(DRM_MAJOR, head->minor);
s_dev->class_dev.dev = DRM_PCI_DEV(head->dev->pdev); s_dev->class_dev.dev = &head->dev->pdev->dev;
s_dev->class_dev.class = &cs->class; s_dev->class_dev.class = &cs->class;
snprintf(s_dev->class_dev.class_id, BUS_ID_SIZE, "card%d", head->minor); snprintf(s_dev->class_dev.class_id, BUS_ID_SIZE, "card%d", head->minor);

View file

@ -1,8 +1,8 @@
/************************************************************************** /**************************************************************************
* *
* Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA * Copyright (c) 2006-2007 Tungsten Graphics, Inc., Cedar Park, TX., USA
* All Rights Reserved. * All Rights Reserved.
* *
* Permission is hereby granted, free of charge, to any person obtaining a * Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the * copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including * "Software"), to deal in the Software without restriction, including
@ -10,21 +10,23 @@
* distribute, sub license, and/or sell copies of the Software, and to * 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 * permit persons to whom the Software is furnished to do so, subject to
* the following conditions: * 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 * The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions * next paragraph) shall be included in all copies or substantial portions
* of the Software. * of the Software.
* *
* * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* USE OR OTHER DEALINGS IN THE SOFTWARE.
*
**************************************************************************/ **************************************************************************/
/*
* Authors: Thomas Hellström <thomas-at-tungstengraphics-dot-com>
*/
#include "drmP.h" #include "drmP.h"
@ -33,72 +35,73 @@ static void drm_ttm_ipi_handler(void *null)
flush_agp_cache(); flush_agp_cache();
} }
static void drm_ttm_cache_flush(void) static void drm_ttm_cache_flush(void)
{ {
if (on_each_cpu(drm_ttm_ipi_handler, NULL, 1, 1) != 0) if (on_each_cpu(drm_ttm_ipi_handler, NULL, 1, 1) != 0)
DRM_ERROR("Timed out waiting for drm cache flush.\n"); DRM_ERROR("Timed out waiting for drm cache flush.\n");
} }
/* /*
* Use kmalloc if possible. Otherwise fall back to vmalloc. * Use kmalloc if possible. Otherwise fall back to vmalloc.
*/ */
static void *ttm_alloc(unsigned long size, int type) static void ttm_alloc_pages(drm_ttm_t * ttm)
{ {
void *ret = NULL; unsigned long size = ttm->num_pages * sizeof(*ttm->pages);
ttm->pages = NULL;
if (drm_alloc_memctl(size)) if (drm_alloc_memctl(size))
return NULL; return;
if (size <= PAGE_SIZE) { if (size <= PAGE_SIZE) {
ret = drm_alloc(size, type); ttm->pages = drm_calloc(1, size, DRM_MEM_TTM);
} }
if (!ret) { if (!ttm->pages) {
ret = vmalloc(size); ttm->pages = vmalloc_user(size);
if (ttm->pages)
ttm->page_flags |= DRM_TTM_PAGE_VMALLOC;
} }
if (!ret) { if (!ttm->pages) {
drm_free_memctl(size); drm_free_memctl(size);
} }
return ret;
} }
static void ttm_free(void *pointer, unsigned long size, int type) static void ttm_free_pages(drm_ttm_t * ttm)
{ {
unsigned long size = ttm->num_pages * sizeof(*ttm->pages);
if ((unsigned long)pointer >= VMALLOC_START && if (ttm->page_flags & DRM_TTM_PAGE_VMALLOC) {
(unsigned long)pointer <= VMALLOC_END) { vfree(ttm->pages);
vfree(pointer); ttm->page_flags &= ~DRM_TTM_PAGE_VMALLOC;
} else { } else {
drm_free(pointer, size, type); drm_free(ttm->pages, size, DRM_MEM_TTM);
} }
drm_free_memctl(size); drm_free_memctl(size);
ttm->pages = NULL;
} }
/* static struct page *drm_ttm_alloc_page(void)
* Unmap all vma pages from vmas mapping this ttm.
*/
static int unmap_vma_pages(drm_ttm_t * ttm)
{ {
drm_device_t *dev = ttm->dev; struct page *page;
loff_t offset = ((loff_t) ttm->mapping_offset) << PAGE_SHIFT;
loff_t holelen = ((loff_t) ttm->num_pages) << PAGE_SHIFT;
#ifdef DRM_ODD_MM_COMPAT if (drm_alloc_memctl(PAGE_SIZE)) {
int ret; return NULL;
ret = drm_ttm_lock_mm(ttm); }
if (ret) page = alloc_page(GFP_KERNEL | __GFP_ZERO | GFP_DMA32);
return ret; if (!page) {
drm_free_memctl(PAGE_SIZE);
return NULL;
}
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15))
SetPageLocked(page);
#else
SetPageReserved(page);
#endif #endif
unmap_mapping_range(dev->dev_mapping, offset, holelen, 1); return page;
#ifdef DRM_ODD_MM_COMPAT
drm_ttm_finish_unmap(ttm);
#endif
return 0;
} }
/* /*
* Change caching policy for the linear kernel map * Change caching policy for the linear kernel map
* for range of pages in a ttm. * for range of pages in a ttm.
*/ */
@ -111,7 +114,7 @@ static int drm_set_caching(drm_ttm_t * ttm, int noncached)
if ((ttm->page_flags & DRM_TTM_PAGE_UNCACHED) == noncached) if ((ttm->page_flags & DRM_TTM_PAGE_UNCACHED) == noncached)
return 0; return 0;
if (noncached) if (noncached)
drm_ttm_cache_flush(); drm_ttm_cache_flush();
for (i = 0; i < ttm->num_pages; ++i) { for (i = 0; i < ttm->num_pages; ++i) {
@ -130,7 +133,7 @@ static int drm_set_caching(drm_ttm_t * ttm, int noncached)
if (do_tlbflush) if (do_tlbflush)
flush_agp_mappings(); flush_agp_mappings();
DRM_MASK_VAL(ttm->page_flags, DRM_TTM_PAGE_UNCACHED, noncached); DRM_FLAG_MASKED(ttm->page_flags, noncached, DRM_TTM_PAGE_UNCACHED);
return 0; return 0;
} }
@ -149,21 +152,9 @@ int drm_destroy_ttm(drm_ttm_t * ttm)
if (!ttm) if (!ttm)
return 0; return 0;
if (atomic_read(&ttm->vma_count) > 0) {
ttm->destroy = 1;
DRM_ERROR("VMAs are still alive. Skipping destruction.\n");
return -EBUSY;
}
DRM_DEBUG("Destroying a ttm\n");
#ifdef DRM_TTM_ODD_COMPAT
BUG_ON(!list_empty(&ttm->vma_list));
BUG_ON(!list_empty(&ttm->p_mm_list));
#endif
be = ttm->be; be = ttm->be;
if (be) { if (be) {
be->destroy(be); be->func->destroy(be);
ttm->be = NULL; ttm->be = NULL;
} }
@ -188,58 +179,50 @@ int drm_destroy_ttm(drm_ttm_t * ttm)
DRM_ERROR("Erroneous map count. " DRM_ERROR("Erroneous map count. "
"Leaking page mappings.\n"); "Leaking page mappings.\n");
} }
__free_page(*cur_page);
/*
* End debugging.
*/
drm_free_gatt_pages(*cur_page, 0);
drm_free_memctl(PAGE_SIZE); drm_free_memctl(PAGE_SIZE);
--bm->cur_pages; --bm->cur_pages;
} }
} }
ttm_free(ttm->pages, ttm->num_pages * sizeof(*ttm->pages), ttm_free_pages(ttm);
DRM_MEM_TTM);
ttm->pages = NULL;
} }
drm_ctl_free(ttm, sizeof(*ttm), DRM_MEM_TTM); drm_ctl_free(ttm, sizeof(*ttm), DRM_MEM_TTM);
return 0; return 0;
} }
struct page *drm_ttm_get_page(drm_ttm_t * ttm, int index)
{
struct page *p;
drm_buffer_manager_t *bm = &ttm->dev->bm;
p = ttm->pages[index];
if (!p) {
p = drm_ttm_alloc_page();
if (!p)
return NULL;
ttm->pages[index] = p;
++bm->cur_pages;
}
return p;
}
static int drm_ttm_populate(drm_ttm_t * ttm) static int drm_ttm_populate(drm_ttm_t * ttm)
{ {
struct page *page; struct page *page;
unsigned long i; unsigned long i;
drm_buffer_manager_t *bm;
drm_ttm_backend_t *be; drm_ttm_backend_t *be;
if (ttm->state != ttm_unpopulated) if (ttm->state != ttm_unpopulated)
return 0; return 0;
bm = &ttm->dev->bm;
be = ttm->be; be = ttm->be;
for (i = 0; i < ttm->num_pages; ++i) { for (i = 0; i < ttm->num_pages; ++i) {
page = ttm->pages[i]; page = drm_ttm_get_page(ttm, i);
if (!page) { if (!page)
if (drm_alloc_memctl(PAGE_SIZE)) { return -ENOMEM;
return -ENOMEM;
}
page = drm_alloc_gatt_pages(0);
if (!page) {
drm_free_memctl(PAGE_SIZE);
return -ENOMEM;
}
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15))
SetPageLocked(page);
#else
SetPageReserved(page);
#endif
ttm->pages[i] = page;
++bm->cur_pages;
}
} }
be->populate(be, ttm->num_pages, ttm->pages); be->func->populate(be, ttm->num_pages, ttm->pages);
ttm->state = ttm_unbound; ttm->state = ttm_unbound;
return 0; return 0;
} }
@ -248,7 +231,7 @@ static int drm_ttm_populate(drm_ttm_t * ttm)
* Initialize a ttm. * Initialize a ttm.
*/ */
static drm_ttm_t *drm_init_ttm(struct drm_device *dev, unsigned long size) drm_ttm_t *drm_ttm_init(struct drm_device * dev, unsigned long size)
{ {
drm_bo_driver_t *bo_driver = dev->driver->bo_driver; drm_bo_driver_t *bo_driver = dev->driver->bo_driver;
drm_ttm_t *ttm; drm_ttm_t *ttm;
@ -260,11 +243,6 @@ static drm_ttm_t *drm_init_ttm(struct drm_device *dev, unsigned long size)
if (!ttm) if (!ttm)
return NULL; return NULL;
#ifdef DRM_ODD_MM_COMPAT
INIT_LIST_HEAD(&ttm->p_mm_list);
INIT_LIST_HEAD(&ttm->vma_list);
#endif
ttm->dev = dev; ttm->dev = dev;
atomic_set(&ttm->vma_count, 0); atomic_set(&ttm->vma_count, 0);
@ -277,14 +255,12 @@ static drm_ttm_t *drm_init_ttm(struct drm_device *dev, unsigned long size)
* Account also for AGP module memory usage. * Account also for AGP module memory usage.
*/ */
ttm->pages = ttm_alloc(ttm->num_pages * sizeof(*ttm->pages), ttm_alloc_pages(ttm);
DRM_MEM_TTM);
if (!ttm->pages) { if (!ttm->pages) {
drm_destroy_ttm(ttm); drm_destroy_ttm(ttm);
DRM_ERROR("Failed allocating page table\n"); DRM_ERROR("Failed allocating page table\n");
return NULL; return NULL;
} }
memset(ttm->pages, 0, ttm->num_pages * sizeof(*ttm->pages));
ttm->be = bo_driver->create_ttm_backend_entry(dev); ttm->be = bo_driver->create_ttm_backend_entry(dev);
if (!ttm->be) { if (!ttm->be) {
drm_destroy_ttm(ttm); drm_destroy_ttm(ttm);
@ -299,52 +275,37 @@ static drm_ttm_t *drm_init_ttm(struct drm_device *dev, unsigned long size)
* Unbind a ttm region from the aperture. * Unbind a ttm region from the aperture.
*/ */
int drm_evict_ttm(drm_ttm_t * ttm) void drm_ttm_evict(drm_ttm_t * ttm)
{ {
drm_ttm_backend_t *be = ttm->be; drm_ttm_backend_t *be = ttm->be;
int ret; int ret;
switch (ttm->state) { if (ttm->state == ttm_bound) {
case ttm_bound: ret = be->func->unbind(be);
if (be->needs_ub_cache_adjust(be)) { BUG_ON(ret);
ret = unmap_vma_pages(ttm);
if (ret) {
return ret;
}
}
be->unbind(be);
break;
default:
break;
} }
ttm->state = ttm_evicted; ttm->state = ttm_evicted;
return 0;
} }
void drm_fixup_ttm_caching(drm_ttm_t * ttm) void drm_ttm_fixup_caching(drm_ttm_t * ttm)
{ {
if (ttm->state == ttm_evicted) { if (ttm->state == ttm_evicted) {
drm_ttm_backend_t *be = ttm->be; drm_ttm_backend_t *be = ttm->be;
if (be->needs_ub_cache_adjust(be)) { if (be->func->needs_ub_cache_adjust(be)) {
drm_set_caching(ttm, 0); drm_set_caching(ttm, 0);
} }
ttm->state = ttm_unbound; ttm->state = ttm_unbound;
} }
} }
int drm_unbind_ttm(drm_ttm_t * ttm) void drm_ttm_unbind(drm_ttm_t * ttm)
{ {
int ret = 0;
if (ttm->state == ttm_bound) if (ttm->state == ttm_bound)
ret = drm_evict_ttm(ttm); drm_ttm_evict(ttm);
if (ret) drm_ttm_fixup_caching(ttm);
return ret;
drm_fixup_ttm_caching(ttm);
return 0;
} }
int drm_bind_ttm(drm_ttm_t * ttm, int cached, unsigned long aper_offset) int drm_bind_ttm(drm_ttm_t * ttm, int cached, unsigned long aper_offset)
@ -363,26 +324,13 @@ int drm_bind_ttm(drm_ttm_t * ttm, int cached, unsigned long aper_offset)
ret = drm_ttm_populate(ttm); ret = drm_ttm_populate(ttm);
if (ret) if (ret)
return ret; return ret;
if (ttm->state == ttm_unbound && !cached) {
ret = unmap_vma_pages(ttm);
if (ret)
return ret;
if (ttm->state == ttm_unbound && !cached) {
drm_set_caching(ttm, DRM_TTM_PAGE_UNCACHED); drm_set_caching(ttm, DRM_TTM_PAGE_UNCACHED);
} }
#ifdef DRM_ODD_MM_COMPAT
else if (ttm->state == ttm_evicted && !cached) { if ((ret = be->func->bind(be, aper_offset, cached))) {
ret = drm_ttm_lock_mm(ttm);
if (ret)
return ret;
}
#endif
if ((ret = be->bind(be, aper_offset, cached))) {
ttm->state = ttm_evicted; ttm->state = ttm_evicted;
#ifdef DRM_ODD_MM_COMPAT
if (be->needs_ub_cache_adjust(be))
drm_ttm_unlock_mm(ttm);
#endif
DRM_ERROR("Couldn't bind backend.\n"); DRM_ERROR("Couldn't bind backend.\n");
return ret; return ret;
} }
@ -390,130 +338,7 @@ int drm_bind_ttm(drm_ttm_t * ttm, int cached, unsigned long aper_offset)
ttm->aper_offset = aper_offset; ttm->aper_offset = aper_offset;
ttm->state = ttm_bound; ttm->state = ttm_bound;
#ifdef DRM_ODD_MM_COMPAT
if (be->needs_ub_cache_adjust(be)) {
ret = drm_ttm_remap_bound(ttm);
if (ret)
return ret;
}
#endif
return 0; return 0;
} }
/* EXPORT_SYMBOL(drm_bind_ttm);
* dev->struct_mutex locked.
*/
static void drm_ttm_object_remove(drm_device_t * dev, drm_ttm_object_t * object)
{
drm_map_list_t *list = &object->map_list;
drm_local_map_t *map;
if (list->user_token)
drm_ht_remove_item(&dev->map_hash, &list->hash);
if (list->file_offset_node) {
drm_mm_put_block(list->file_offset_node);
list->file_offset_node = NULL;
}
map = list->map;
if (map) {
drm_ttm_t *ttm = (drm_ttm_t *) map->offset;
if (ttm) {
if (drm_destroy_ttm(ttm) != -EBUSY) {
drm_ctl_free(map, sizeof(*map), DRM_MEM_TTM);
}
} else {
drm_ctl_free(map, sizeof(*map), DRM_MEM_TTM);
}
}
drm_ctl_free(object, sizeof(*object), DRM_MEM_TTM);
}
void drm_ttm_object_deref_locked(drm_device_t * dev, drm_ttm_object_t * to)
{
if (atomic_dec_and_test(&to->usage)) {
drm_ttm_object_remove(dev, to);
}
}
void drm_ttm_object_deref_unlocked(drm_device_t * dev, drm_ttm_object_t * to)
{
if (atomic_dec_and_test(&to->usage)) {
mutex_lock(&dev->struct_mutex);
if (atomic_read(&to->usage) == 0)
drm_ttm_object_remove(dev, to);
mutex_unlock(&dev->struct_mutex);
}
}
/*
* Create a ttm and add it to the drm book-keeping.
* dev->struct_mutex locked.
*/
int drm_ttm_object_create(drm_device_t * dev, unsigned long size,
uint32_t flags, drm_ttm_object_t ** ttm_object)
{
drm_ttm_object_t *object;
drm_map_list_t *list;
drm_local_map_t *map;
drm_ttm_t *ttm;
object = drm_ctl_calloc(1, sizeof(*object), DRM_MEM_TTM);
if (!object)
return -ENOMEM;
object->flags = flags;
list = &object->map_list;
list->map = drm_ctl_calloc(1, sizeof(*map), DRM_MEM_TTM);
if (!list->map) {
drm_ttm_object_remove(dev, object);
return -ENOMEM;
}
map = list->map;
ttm = drm_init_ttm(dev, size);
if (!ttm) {
DRM_ERROR("Could not create ttm\n");
drm_ttm_object_remove(dev, object);
return -ENOMEM;
}
map->offset = (unsigned long)ttm;
map->type = _DRM_TTM;
map->flags = _DRM_REMOVABLE;
map->size = ttm->num_pages * PAGE_SIZE;
map->handle = (void *)object;
/*
* Add a one-page "hole" to the block size to avoid the mm subsystem
* merging vmas.
* FIXME: Is this really needed?
*/
list->file_offset_node = drm_mm_search_free(&dev->offset_manager,
ttm->num_pages + 1, 0, 0);
if (!list->file_offset_node) {
drm_ttm_object_remove(dev, object);
return -ENOMEM;
}
list->file_offset_node = drm_mm_get_block(list->file_offset_node,
ttm->num_pages + 1, 0);
list->hash.key = list->file_offset_node->start;
if (drm_ht_insert_item(&dev->map_hash, &list->hash)) {
drm_ttm_object_remove(dev, object);
return -ENOMEM;
}
list->user_token = ((drm_u64_t) list->hash.key) << PAGE_SHIFT;
ttm->mapping_offset = list->hash.key;
atomic_set(&object->usage, 1);
*ttm_object = object;
return 0;
}

View file

@ -1,145 +0,0 @@
/**************************************************************************
*
* 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.
*
*
**************************************************************************/
/*
* Authors: Thomas Hellström <thomas-at-tungstengraphics-dot-com>
*/
#ifndef _DRM_TTM_H
#define _DRM_TTM_H
#define DRM_HAS_TTM
/*
* The backend GART interface. (In our case AGP). Any similar type of device (PCIE?)
* needs only to implement these functions to be usable with the "TTM" interface.
* The AGP backend implementation lives in drm_agpsupport.c
* basically maps these calls to available functions in agpgart. Each drm device driver gets an
* additional function pointer that creates these types,
* so that the device can choose the correct aperture.
* (Multiple AGP apertures, etc.)
* Most device drivers will let this point to the standard AGP implementation.
*/
#define DRM_BE_FLAG_NEEDS_FREE 0x00000001
#define DRM_BE_FLAG_BOUND_CACHED 0x00000002
#define DRM_BE_FLAG_CBA 0x00000004
typedef struct drm_ttm_backend {
unsigned long aperture_base;
void *private;
uint32_t flags;
uint32_t drm_map_type;
int (*needs_ub_cache_adjust) (struct drm_ttm_backend * backend);
int (*populate) (struct drm_ttm_backend * backend,
unsigned long num_pages, struct page ** pages);
void (*clear) (struct drm_ttm_backend * backend);
int (*bind) (struct drm_ttm_backend * backend,
unsigned long offset, int cached);
int (*unbind) (struct drm_ttm_backend * backend);
void (*destroy) (struct drm_ttm_backend * backend);
} drm_ttm_backend_t;
typedef struct drm_ttm {
struct page **pages;
uint32_t page_flags;
unsigned long num_pages;
unsigned long aper_offset;
atomic_t vma_count;
struct drm_device *dev;
int destroy;
uint32_t mapping_offset;
drm_ttm_backend_t *be;
enum {
ttm_bound,
ttm_evicted,
ttm_unbound,
ttm_unpopulated,
} state;
#ifdef DRM_ODD_MM_COMPAT
struct list_head vma_list;
struct list_head p_mm_list;
#endif
} drm_ttm_t;
typedef struct drm_ttm_object {
atomic_t usage;
uint32_t flags;
drm_map_list_t map_list;
} drm_ttm_object_t;
extern int drm_ttm_object_create(struct drm_device *dev, unsigned long size,
uint32_t flags,
drm_ttm_object_t ** ttm_object);
extern void drm_ttm_object_deref_locked(struct drm_device *dev,
drm_ttm_object_t * to);
extern void drm_ttm_object_deref_unlocked(struct drm_device *dev,
drm_ttm_object_t * to);
extern drm_ttm_object_t *drm_lookup_ttm_object(drm_file_t * priv,
uint32_t handle,
int check_owner);
extern int drm_bind_ttm(drm_ttm_t * ttm, int cached, unsigned long aper_offset);
extern int drm_unbind_ttm(drm_ttm_t * ttm);
/*
* Evict a ttm region. Keeps Aperture caching policy.
*/
extern int drm_evict_ttm(drm_ttm_t * ttm);
extern void drm_fixup_ttm_caching(drm_ttm_t * ttm);
/*
* Destroy a ttm. The user normally calls drmRmMap or a similar IOCTL to do this,
* which calls this function iff there are no vmas referencing it anymore. Otherwise it is called
* when the last vma exits.
*/
extern int drm_destroy_ttm(drm_ttm_t * ttm);
extern int drm_ttm_ioctl(DRM_IOCTL_ARGS);
static __inline__ drm_ttm_t *drm_ttm_from_object(drm_ttm_object_t * to)
{
return (drm_ttm_t *) to->map_list.map->offset;
}
#define DRM_MASK_VAL(dest, mask, val) \
(dest) = ((dest) & ~(mask)) | ((val) & (mask));
#define DRM_TTM_MASK_FLAGS ((1 << PAGE_SHIFT) - 1)
#define DRM_TTM_MASK_PFN (0xFFFFFFFFU - DRM_TTM_MASK_FLAGS)
/*
* Page flags.
*/
#define DRM_TTM_PAGE_UNCACHED 0x01
#define DRM_TTM_PAGE_USED 0x02
#define DRM_TTM_PAGE_BOUND 0x04
#define DRM_TTM_PAGE_PRESENT 0x08
#endif

View file

@ -41,9 +41,9 @@
static void drm_vm_open(struct vm_area_struct *vma); static void drm_vm_open(struct vm_area_struct *vma);
static void drm_vm_close(struct vm_area_struct *vma); static void drm_vm_close(struct vm_area_struct *vma);
static void drm_vm_ttm_close(struct vm_area_struct *vma); static int drm_bo_mmap_locked(struct vm_area_struct *vma,
static int drm_vm_ttm_open(struct vm_area_struct *vma); struct file *filp,
static void drm_vm_ttm_open_wrapper(struct vm_area_struct *vma); drm_local_map_t *map);
pgprot_t drm_io_prot(uint32_t map_type, struct vm_area_struct *vma) pgprot_t drm_io_prot(uint32_t map_type, struct vm_area_struct *vma)
@ -122,7 +122,7 @@ static __inline__ struct page *drm_do_vm_nopage(struct vm_area_struct *vma,
/* /*
* It's AGP memory - find the real physical page to map * It's AGP memory - find the real physical page to map
*/ */
for (agpmem = dev->agp->memory; agpmem; agpmem = agpmem->next) { list_for_each_entry(agpmem, &dev->agp->memory, head) {
if (agpmem->bound <= baddr && if (agpmem->bound <= baddr &&
agpmem->bound + agpmem->pages * PAGE_SIZE > baddr) agpmem->bound + agpmem->pages * PAGE_SIZE > baddr)
break; break;
@ -159,95 +159,6 @@ static __inline__ struct page *drm_do_vm_nopage(struct vm_area_struct *vma,
} }
#endif /* __OS_HAS_AGP */ #endif /* __OS_HAS_AGP */
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) || \
LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15))
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20))
static
#endif
struct page *drm_vm_ttm_fault(struct vm_area_struct *vma,
struct fault_data *data)
{
unsigned long address = data->address;
drm_local_map_t *map = (drm_local_map_t *) vma->vm_private_data;
unsigned long page_offset;
struct page *page;
drm_ttm_t *ttm;
drm_buffer_manager_t *bm;
drm_device_t *dev;
unsigned long pfn;
int err;
pgprot_t pgprot;
if (!map) {
data->type = VM_FAULT_OOM;
return NULL;
}
if (address > vma->vm_end) {
data->type = VM_FAULT_SIGBUS;
return NULL;
}
ttm = (drm_ttm_t *) map->offset;
dev = ttm->dev;
/*
* Perhaps retry here?
*/
mutex_lock(&dev->struct_mutex);
drm_fixup_ttm_caching(ttm);
bm = &dev->bm;
page_offset = (address - vma->vm_start) >> PAGE_SHIFT;
page = ttm->pages[page_offset];
if (!page) {
if (drm_alloc_memctl(PAGE_SIZE)) {
data->type = VM_FAULT_OOM;
goto out;
}
page = ttm->pages[page_offset] = drm_alloc_gatt_pages(0);
if (!page) {
drm_free_memctl(PAGE_SIZE);
data->type = VM_FAULT_OOM;
goto out;
}
++bm->cur_pages;
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15))
SetPageLocked(page);
#else
SetPageReserved(page);
#endif
}
if (ttm->page_flags & DRM_TTM_PAGE_UNCACHED) {
/*
* FIXME: Check can't map aperture flag.
*/
pfn = ttm->aper_offset + page_offset +
(ttm->be->aperture_base >> PAGE_SHIFT);
pgprot = drm_io_prot(ttm->be->drm_map_type, vma);
} else {
pfn = page_to_pfn(page);
pgprot = vma->vm_page_prot;
}
err = vm_insert_pfn(vma, address, pfn, pgprot);
if (!err || err == -EBUSY)
data->type = VM_FAULT_MINOR;
else
data->type = VM_FAULT_OOM;
out:
mutex_unlock(&dev->struct_mutex);
return NULL;
}
#endif
/** /**
* \c nopage method for shared virtual memory. * \c nopage method for shared virtual memory.
* *
@ -269,13 +180,13 @@ static __inline__ struct page *drm_do_vm_shm_nopage(struct vm_area_struct *vma,
if (address > vma->vm_end) if (address > vma->vm_end)
return NOPAGE_SIGBUS; /* Disallow mremap */ return NOPAGE_SIGBUS; /* Disallow mremap */
if (!map) if (!map)
return NOPAGE_OOM; /* Nothing allocated */ return NOPAGE_SIGBUS; /* Nothing allocated */
offset = address - vma->vm_start; offset = address - vma->vm_start;
i = (unsigned long)map->handle + offset; i = (unsigned long)map->handle + offset;
page = vmalloc_to_page((void *)i); page = vmalloc_to_page((void *)i);
if (!page) if (!page)
return NOPAGE_OOM; return NOPAGE_SIGBUS;
get_page(page); get_page(page);
DRM_DEBUG("shm_nopage 0x%lx\n", address); DRM_DEBUG("shm_nopage 0x%lx\n", address);
@ -294,10 +205,9 @@ static void drm_vm_shm_close(struct vm_area_struct *vma)
{ {
drm_file_t *priv = vma->vm_file->private_data; drm_file_t *priv = vma->vm_file->private_data;
drm_device_t *dev = priv->head->dev; drm_device_t *dev = priv->head->dev;
drm_vma_entry_t *pt, *prev, *next; drm_vma_entry_t *pt, *temp;
drm_map_t *map; drm_map_t *map;
drm_map_list_t *r_list; drm_map_list_t *r_list;
struct list_head *list;
int found_maps = 0; int found_maps = 0;
DRM_DEBUG("0x%08lx,0x%08lx\n", DRM_DEBUG("0x%08lx,0x%08lx\n",
@ -307,19 +217,12 @@ static void drm_vm_shm_close(struct vm_area_struct *vma)
map = vma->vm_private_data; map = vma->vm_private_data;
mutex_lock(&dev->struct_mutex); mutex_lock(&dev->struct_mutex);
for (pt = dev->vmalist, prev = NULL; pt; pt = next) { list_for_each_entry_safe(pt, temp, &dev->vmalist, head) {
next = pt->next;
if (pt->vma->vm_private_data == map) if (pt->vma->vm_private_data == map)
found_maps++; found_maps++;
if (pt->vma == vma) { if (pt->vma == vma) {
if (prev) { list_del(&pt->head);
prev->next = pt->next;
} else {
dev->vmalist = pt->next;
}
drm_ctl_free(pt, sizeof(*pt), DRM_MEM_VMAS); drm_ctl_free(pt, sizeof(*pt), DRM_MEM_VMAS);
} else {
prev = pt;
} }
} }
/* We were the only map that was found */ /* We were the only map that was found */
@ -328,9 +231,7 @@ static void drm_vm_shm_close(struct vm_area_struct *vma)
* we delete this mappings information. * we delete this mappings information.
*/ */
found_maps = 0; found_maps = 0;
list = &dev->maplist->head; list_for_each_entry(r_list, &dev->maplist, head) {
list_for_each(list, &dev->maplist->head) {
r_list = list_entry(list, drm_map_list_t, head);
if (r_list->map == map) if (r_list->map == map)
found_maps++; found_maps++;
} }
@ -348,7 +249,7 @@ static void drm_vm_shm_close(struct vm_area_struct *vma)
map->size); map->size);
DRM_DEBUG("mtrr_del = %d\n", retcode); DRM_DEBUG("mtrr_del = %d\n", retcode);
} }
drm_ioremapfree(map->handle, map->size, dev); iounmap(map->handle);
break; break;
case _DRM_SHM: case _DRM_SHM:
vfree(map->handle); vfree(map->handle);
@ -396,7 +297,7 @@ static __inline__ struct page *drm_do_vm_dma_nopage(struct vm_area_struct *vma,
if (address > vma->vm_end) if (address > vma->vm_end)
return NOPAGE_SIGBUS; /* Disallow mremap */ return NOPAGE_SIGBUS; /* Disallow mremap */
if (!dma->pagelist) if (!dma->pagelist)
return NOPAGE_OOM; /* Nothing allocated */ return NOPAGE_SIGBUS; /* Nothing allocated */
offset = address - vma->vm_start; /* vm_[pg]off[set] should be 0 */ offset = address - vma->vm_start; /* vm_[pg]off[set] should be 0 */
page_nr = offset >> PAGE_SHIFT; page_nr = offset >> PAGE_SHIFT;
@ -435,7 +336,7 @@ static __inline__ struct page *drm_do_vm_sg_nopage(struct vm_area_struct *vma,
if (address > vma->vm_end) if (address > vma->vm_end)
return NOPAGE_SIGBUS; /* Disallow mremap */ return NOPAGE_SIGBUS; /* Disallow mremap */
if (!entry->pagelist) if (!entry->pagelist)
return NOPAGE_OOM; /* Nothing allocated */ return NOPAGE_SIGBUS; /* Nothing allocated */
offset = address - vma->vm_start; offset = address - vma->vm_start;
map_offset = map->offset - (unsigned long)dev->sg->virtual; map_offset = map->offset - (unsigned long)dev->sg->virtual;
@ -446,8 +347,6 @@ static __inline__ struct page *drm_do_vm_sg_nopage(struct vm_area_struct *vma,
return page; return page;
} }
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0)
static struct page *drm_vm_nopage(struct vm_area_struct *vma, static struct page *drm_vm_nopage(struct vm_area_struct *vma,
unsigned long address, int *type) unsigned long address, int *type)
{ {
@ -481,34 +380,6 @@ static struct page *drm_vm_sg_nopage(struct vm_area_struct *vma,
} }
#else /* LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,0) */
static struct page *drm_vm_nopage(struct vm_area_struct *vma,
unsigned long address, int unused)
{
return drm_do_vm_nopage(vma, address);
}
static struct page *drm_vm_shm_nopage(struct vm_area_struct *vma,
unsigned long address, int unused)
{
return drm_do_vm_shm_nopage(vma, address);
}
static struct page *drm_vm_dma_nopage(struct vm_area_struct *vma,
unsigned long address, int unused)
{
return drm_do_vm_dma_nopage(vma, address);
}
static struct page *drm_vm_sg_nopage(struct vm_area_struct *vma,
unsigned long address, int unused)
{
return drm_do_vm_sg_nopage(vma, address);
}
#endif
/** AGP virtual memory operations */ /** AGP virtual memory operations */
static struct vm_operations_struct drm_vm_ops = { static struct vm_operations_struct drm_vm_ops = {
.nopage = drm_vm_nopage, .nopage = drm_vm_nopage,
@ -537,20 +408,6 @@ static struct vm_operations_struct drm_vm_sg_ops = {
.close = drm_vm_close, .close = drm_vm_close,
}; };
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20))
static struct vm_operations_struct drm_vm_ttm_ops = {
.nopage = drm_vm_ttm_nopage,
.open = drm_vm_ttm_open_wrapper,
.close = drm_vm_ttm_close,
};
#else
static struct vm_operations_struct drm_vm_ttm_ops = {
.fault = drm_vm_ttm_fault,
.open = drm_vm_ttm_open_wrapper,
.close = drm_vm_ttm_close,
};
#endif
/** /**
* \c open method for shared virtual memory. * \c open method for shared virtual memory.
* *
@ -559,7 +416,7 @@ static struct vm_operations_struct drm_vm_ttm_ops = {
* Create a new drm_vma_entry structure as the \p vma private data entry and * Create a new drm_vma_entry structure as the \p vma private data entry and
* add it to drm_device::vmalist. * add it to drm_device::vmalist.
*/ */
static void drm_vm_open(struct vm_area_struct *vma) static void drm_vm_open_locked(struct vm_area_struct *vma)
{ {
drm_file_t *priv = vma->vm_file->private_data; drm_file_t *priv = vma->vm_file->private_data;
drm_device_t *dev = priv->head->dev; drm_device_t *dev = priv->head->dev;
@ -571,36 +428,20 @@ static void drm_vm_open(struct vm_area_struct *vma)
vma_entry = drm_ctl_alloc(sizeof(*vma_entry), DRM_MEM_VMAS); vma_entry = drm_ctl_alloc(sizeof(*vma_entry), DRM_MEM_VMAS);
if (vma_entry) { if (vma_entry) {
mutex_lock(&dev->struct_mutex);
vma_entry->vma = vma; vma_entry->vma = vma;
vma_entry->next = dev->vmalist;
vma_entry->pid = current->pid; vma_entry->pid = current->pid;
dev->vmalist = vma_entry; list_add(&vma_entry->head, &dev->vmalist);
mutex_unlock(&dev->struct_mutex);
} }
} }
static int drm_vm_ttm_open(struct vm_area_struct *vma) { static void drm_vm_open(struct vm_area_struct *vma)
{
drm_local_map_t *map = (drm_local_map_t *)vma->vm_private_data;
drm_ttm_t *ttm;
drm_file_t *priv = vma->vm_file->private_data; drm_file_t *priv = vma->vm_file->private_data;
drm_device_t *dev = priv->head->dev; drm_device_t *dev = priv->head->dev;
drm_vm_open(vma);
mutex_lock(&dev->struct_mutex); mutex_lock(&dev->struct_mutex);
ttm = (drm_ttm_t *) map->offset; drm_vm_open_locked(vma);
atomic_inc(&ttm->vma_count);
#ifdef DRM_ODD_MM_COMPAT
drm_ttm_add_vma(ttm, vma);
#endif
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
return 0;
}
static void drm_vm_ttm_open_wrapper(struct vm_area_struct *vma)
{
drm_vm_ttm_open(vma);
} }
/** /**
@ -615,20 +456,16 @@ static void drm_vm_close(struct vm_area_struct *vma)
{ {
drm_file_t *priv = vma->vm_file->private_data; drm_file_t *priv = vma->vm_file->private_data;
drm_device_t *dev = priv->head->dev; drm_device_t *dev = priv->head->dev;
drm_vma_entry_t *pt, *prev; drm_vma_entry_t *pt, *temp;
DRM_DEBUG("0x%08lx,0x%08lx\n", DRM_DEBUG("0x%08lx,0x%08lx\n",
vma->vm_start, vma->vm_end - vma->vm_start); vma->vm_start, vma->vm_end - vma->vm_start);
atomic_dec(&dev->vma_count); atomic_dec(&dev->vma_count);
mutex_lock(&dev->struct_mutex); mutex_lock(&dev->struct_mutex);
for (pt = dev->vmalist, prev = NULL; pt; prev = pt, pt = pt->next) { list_for_each_entry_safe(pt, temp, &dev->vmalist, head) {
if (pt->vma == vma) { if (pt->vma == vma) {
if (prev) { list_del(&pt->head);
prev->next = pt->next;
} else {
dev->vmalist = pt->next;
}
drm_ctl_free(pt, sizeof(*pt), DRM_MEM_VMAS); drm_ctl_free(pt, sizeof(*pt), DRM_MEM_VMAS);
break; break;
} }
@ -637,34 +474,6 @@ static void drm_vm_close(struct vm_area_struct *vma)
} }
static void drm_vm_ttm_close(struct vm_area_struct *vma)
{
drm_local_map_t *map = (drm_local_map_t *) vma->vm_private_data;
drm_ttm_t *ttm;
drm_device_t *dev;
int ret;
drm_vm_close(vma);
if (map) {
ttm = (drm_ttm_t *) map->offset;
dev = ttm->dev;
mutex_lock(&dev->struct_mutex);
#ifdef DRM_ODD_MM_COMPAT
drm_ttm_delete_vma(ttm, vma);
#endif
if (atomic_dec_and_test(&ttm->vma_count)) {
if (ttm->destroy) {
ret = drm_destroy_ttm(ttm);
BUG_ON(ret);
drm_ctl_free(map, sizeof(*map), DRM_MEM_TTM);
}
}
mutex_unlock(&dev->struct_mutex);
}
return;
}
/** /**
* mmap DMA memory. * mmap DMA memory.
* *
@ -682,7 +491,6 @@ static int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma)
drm_device_dma_t *dma; drm_device_dma_t *dma;
unsigned long length = vma->vm_end - vma->vm_start; unsigned long length = vma->vm_end - vma->vm_start;
lock_kernel();
dev = priv->head->dev; dev = priv->head->dev;
dma = dev->dma; dma = dev->dma;
DRM_DEBUG("start = 0x%lx, end = 0x%lx, page offset = 0x%lx\n", DRM_DEBUG("start = 0x%lx, end = 0x%lx, page offset = 0x%lx\n",
@ -690,13 +498,10 @@ static int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma)
/* Length must match exact page count */ /* Length must match exact page count */
if (!dma || (length >> PAGE_SHIFT) != dma->page_count) { if (!dma || (length >> PAGE_SHIFT) != dma->page_count) {
unlock_kernel();
return -EINVAL; return -EINVAL;
} }
unlock_kernel();
if (!capable(CAP_SYS_ADMIN) && if (!capable(CAP_SYS_ADMIN) && (dma->flags & _DRM_DMA_USE_PCI_RO)) {
(dma->flags & _DRM_DMA_USE_PCI_RO)) {
vma->vm_flags &= ~(VM_WRITE | VM_MAYWRITE); vma->vm_flags &= ~(VM_WRITE | VM_MAYWRITE);
#if defined(__i386__) || defined(__x86_64__) #if defined(__i386__) || defined(__x86_64__)
pgprot_val(vma->vm_page_prot) &= ~_PAGE_RW; pgprot_val(vma->vm_page_prot) &= ~_PAGE_RW;
@ -712,15 +517,10 @@ static int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma)
} }
vma->vm_ops = &drm_vm_dma_ops; vma->vm_ops = &drm_vm_dma_ops;
#if LINUX_VERSION_CODE <= 0x02040e /* KERNEL_VERSION(2,4,14) */
vma->vm_flags |= VM_LOCKED | VM_SHM; /* Don't swap */
#else
vma->vm_flags |= VM_RESERVED; /* Don't swap */ vma->vm_flags |= VM_RESERVED; /* Don't swap */
#endif
vma->vm_file = filp; /* Needed for drm_vm_open() */ vma->vm_file = filp; /* Needed for drm_vm_open() */
drm_vm_open(vma); drm_vm_open_locked(vma);
return 0; return 0;
} }
@ -753,7 +553,7 @@ EXPORT_SYMBOL(drm_core_get_reg_ofs);
* according to the mapping type and remaps the pages. Finally sets the file * according to the mapping type and remaps the pages. Finally sets the file
* pointer and calls vm_open(). * pointer and calls vm_open().
*/ */
int drm_mmap(struct file *filp, struct vm_area_struct *vma) static int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma)
{ {
drm_file_t *priv = filp->private_data; drm_file_t *priv = filp->private_data;
drm_device_t *dev = priv->head->dev; drm_device_t *dev = priv->head->dev;
@ -771,6 +571,7 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma)
* the AGP mapped at physical address 0 * the AGP mapped at physical address 0
* --BenH. * --BenH.
*/ */
if (!vma->vm_pgoff if (!vma->vm_pgoff
#if __OS_HAS_AGP #if __OS_HAS_AGP
&& (!dev->agp && (!dev->agp
@ -779,13 +580,12 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma)
) )
return drm_mmap_dma(filp, vma); return drm_mmap_dma(filp, vma);
if (drm_ht_find_item(&dev->map_hash, vma->vm_pgoff , &hash)) { if (drm_ht_find_item(&dev->map_hash, vma->vm_pgoff, &hash)) {
DRM_ERROR("Could not find map\n"); DRM_ERROR("Could not find map\n");
return -EINVAL; return -EINVAL;
} }
map = drm_hash_entry(hash,drm_map_list_t, hash)->map; map = drm_hash_entry(hash, drm_map_list_t, hash)->map;
if (!map || ((map->flags & _DRM_RESTRICTED) && !capable(CAP_SYS_ADMIN))) if (!map || ((map->flags & _DRM_RESTRICTED) && !capable(CAP_SYS_ADMIN)))
return -EPERM; return -EPERM;
@ -829,16 +629,12 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma)
vma->vm_flags |= VM_IO; /* not in core dump */ vma->vm_flags |= VM_IO; /* not in core dump */
vma->vm_page_prot = drm_io_prot(map->type, vma); vma->vm_page_prot = drm_io_prot(map->type, vma);
#ifdef __sparc__ #ifdef __sparc__
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
#endif
if (io_remap_pfn_range(vma, vma->vm_start, if (io_remap_pfn_range(vma, vma->vm_start,
(map->offset + offset) >>PAGE_SHIFT, (map->offset + offset) >> PAGE_SHIFT,
vma->vm_end - vma->vm_start, vma->vm_end - vma->vm_start,
vma->vm_page_prot)) vma->vm_page_prot))
#else
if (remap_pfn_range(vma, vma->vm_start,
(map->offset + offset) >> PAGE_SHIFT,
vma->vm_end - vma->vm_start,
vma->vm_page_prot))
#endif
return -EAGAIN; return -EAGAIN;
DRM_DEBUG(" Type = %d; start = 0x%lx, end = 0x%lx," DRM_DEBUG(" Type = %d; start = 0x%lx, end = 0x%lx,"
" offset = 0x%lx\n", " offset = 0x%lx\n",
@ -859,46 +655,234 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma)
vma->vm_private_data = (void *)map; vma->vm_private_data = (void *)map;
/* Don't let this area swap. Change when /* Don't let this area swap. Change when
DRM_KERNEL advisory is supported. */ DRM_KERNEL advisory is supported. */
#if LINUX_VERSION_CODE <= 0x02040e /* KERNEL_VERSION(2,4,14) */
vma->vm_flags |= VM_LOCKED;
#else
vma->vm_flags |= VM_RESERVED; vma->vm_flags |= VM_RESERVED;
#endif
break; break;
case _DRM_SCATTER_GATHER: case _DRM_SCATTER_GATHER:
vma->vm_ops = &drm_vm_sg_ops; vma->vm_ops = &drm_vm_sg_ops;
vma->vm_private_data = (void *)map; vma->vm_private_data = (void *)map;
#if LINUX_VERSION_CODE <= 0x02040e /* KERNEL_VERSION(2,4,14) */
vma->vm_flags |= VM_LOCKED;
#else
vma->vm_flags |= VM_RESERVED; vma->vm_flags |= VM_RESERVED;
#endif
break; break;
case _DRM_TTM: { case _DRM_TTM:
vma->vm_ops = &drm_vm_ttm_ops; return drm_bo_mmap_locked(vma, filp, map);
vma->vm_private_data = (void *) map;
vma->vm_file = filp;
vma->vm_flags |= VM_RESERVED | VM_IO;
#ifdef DRM_ODD_MM_COMPAT
mutex_lock(&dev->struct_mutex);
drm_ttm_map_bound(vma);
mutex_unlock(&dev->struct_mutex);
#endif
if (drm_vm_ttm_open(vma))
return -EAGAIN;
return 0;
}
default: default:
return -EINVAL; /* This should never happen. */ return -EINVAL; /* This should never happen. */
} }
#if LINUX_VERSION_CODE <= 0x02040e /* KERNEL_VERSION(2,4,14) */
vma->vm_flags |= VM_LOCKED | VM_SHM; /* Don't swap */
#else
vma->vm_flags |= VM_RESERVED; /* Don't swap */ vma->vm_flags |= VM_RESERVED; /* Don't swap */
#endif
vma->vm_file = filp; /* Needed for drm_vm_open() */ vma->vm_file = filp; /* Needed for drm_vm_open() */
drm_vm_open(vma); drm_vm_open_locked(vma);
return 0; return 0;
} }
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;
int ret;
mutex_lock(&dev->struct_mutex);
ret = drm_mmap_locked(filp, vma);
mutex_unlock(&dev->struct_mutex);
return ret;
}
EXPORT_SYMBOL(drm_mmap); EXPORT_SYMBOL(drm_mmap);
/**
* buffer object vm functions.
*/
/**
* \c Pagefault method for buffer objects.
*
* \param vma Virtual memory area.
* \param address File offset.
* \return Error or refault. The pfn is manually inserted.
*
* It's important that pfns are inserted while holding the bo->mutex lock.
* otherwise we might race with unmap_mapping_range() which is always
* called with the bo->mutex lock held.
*
* We're modifying the page attribute bits of the vma->vm_page_prot field,
* without holding the mmap_sem in write mode. Only in read mode.
* These bits are not used by the mm subsystem code, and we consider them
* protected by the bo->mutex lock.
*/
#ifdef DRM_FULL_MM_COMPAT
static unsigned long drm_bo_vm_nopfn(struct vm_area_struct *vma,
unsigned long address)
{
drm_buffer_object_t *bo = (drm_buffer_object_t *) vma->vm_private_data;
unsigned long page_offset;
struct page *page = NULL;
drm_ttm_t *ttm;
drm_device_t *dev;
unsigned long pfn;
int err;
unsigned long bus_base;
unsigned long bus_offset;
unsigned long bus_size;
unsigned long ret = NOPFN_REFAULT;
if (address > vma->vm_end)
return NOPFN_SIGBUS;
err = mutex_lock_interruptible(&bo->mutex);
if (err)
return NOPFN_REFAULT;
err = drm_bo_wait(bo, 0, 0, 0);
if (err) {
ret = (err != -EAGAIN) ? NOPFN_SIGBUS : NOPFN_REFAULT;
goto out_unlock;
}
/*
* If buffer happens to be in a non-mappable location,
* move it to a mappable.
*/
if (!(bo->mem.flags & DRM_BO_FLAG_MAPPABLE)) {
uint32_t new_mask = bo->mem.mask |
DRM_BO_FLAG_MAPPABLE |
DRM_BO_FLAG_FORCE_MAPPABLE;
err = drm_bo_move_buffer(bo, new_mask, 0, 0);
if (err) {
ret = (err != -EAGAIN) ? NOPFN_SIGBUS : NOPFN_REFAULT;
goto out_unlock;
}
}
dev = bo->dev;
err = drm_bo_pci_offset(dev, &bo->mem, &bus_base, &bus_offset,
&bus_size);
if (err) {
ret = NOPFN_SIGBUS;
goto out_unlock;
}
page_offset = (address - vma->vm_start) >> PAGE_SHIFT;
if (bus_size) {
drm_mem_type_manager_t *man = &dev->bm.man[bo->mem.mem_type];
pfn = ((bus_base + bus_offset) >> PAGE_SHIFT) + page_offset;
vma->vm_page_prot = drm_io_prot(man->drm_bus_maptype, vma);
} else {
ttm = bo->ttm;
drm_ttm_fixup_caching(ttm);
page = drm_ttm_get_page(ttm, page_offset);
if (!page) {
ret = NOPFN_OOM;
goto out_unlock;
}
pfn = page_to_pfn(page);
vma->vm_page_prot = (bo->mem.flags & DRM_BO_FLAG_CACHED) ?
vm_get_page_prot(vma->vm_flags) :
drm_io_prot(_DRM_TTM, vma);
}
err = vm_insert_pfn(vma, address, pfn);
if (err) {
ret = (err != -EAGAIN) ? NOPFN_OOM : NOPFN_REFAULT;
goto out_unlock;
}
out_unlock:
mutex_unlock(&bo->mutex);
return ret;
}
#endif
static void drm_bo_vm_open_locked(struct vm_area_struct *vma)
{
drm_buffer_object_t *bo = (drm_buffer_object_t *) vma->vm_private_data;
drm_vm_open_locked(vma);
atomic_inc(&bo->usage);
#ifdef DRM_ODD_MM_COMPAT
drm_bo_add_vma(bo, vma);
#endif
}
/**
* \c vma open method for buffer objects.
*
* \param vma virtual memory area.
*/
static void drm_bo_vm_open(struct vm_area_struct *vma)
{
drm_buffer_object_t *bo = (drm_buffer_object_t *) vma->vm_private_data;
drm_device_t *dev = bo->dev;
mutex_lock(&dev->struct_mutex);
drm_bo_vm_open_locked(vma);
mutex_unlock(&dev->struct_mutex);
}
/**
* \c vma close method for buffer objects.
*
* \param vma virtual memory area.
*/
static void drm_bo_vm_close(struct vm_area_struct *vma)
{
drm_buffer_object_t *bo = (drm_buffer_object_t *) vma->vm_private_data;
drm_device_t *dev = bo->dev;
drm_vm_close(vma);
if (bo) {
mutex_lock(&dev->struct_mutex);
#ifdef DRM_ODD_MM_COMPAT
drm_bo_delete_vma(bo, vma);
#endif
drm_bo_usage_deref_locked(bo);
mutex_unlock(&dev->struct_mutex);
}
return;
}
static struct vm_operations_struct drm_bo_vm_ops = {
#ifdef DRM_FULL_MM_COMPAT
.nopfn = drm_bo_vm_nopfn,
#else
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19))
.nopfn = drm_bo_vm_nopfn,
#else
.nopage = drm_bo_vm_nopage,
#endif
#endif
.open = drm_bo_vm_open,
.close = drm_bo_vm_close,
};
/**
* mmap buffer object memory.
*
* \param vma virtual memory area.
* \param filp file pointer.
* \param map The buffer object drm map.
* \return zero on success or a negative number on failure.
*/
int drm_bo_mmap_locked(struct vm_area_struct *vma,
struct file *filp,
drm_local_map_t *map)
{
vma->vm_ops = &drm_bo_vm_ops;
vma->vm_private_data = map->handle;
vma->vm_file = filp;
vma->vm_flags |= VM_RESERVED | VM_IO;
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19))
vma->vm_flags |= VM_PFNMAP;
#endif
drm_bo_vm_open_locked(vma);
#ifdef DRM_ODD_MM_COMPAT
drm_bo_map_bound(vma);
#endif
return 0;
}

View file

@ -39,12 +39,6 @@
#include "i810_drm.h" #include "i810_drm.h"
#include "i810_drv.h" #include "i810_drv.h"
#ifdef DO_MUNMAP_4_ARGS
#define DO_MUNMAP(m, a, l) do_munmap(m, a, l, 1)
#else
#define DO_MUNMAP(m, a, l) do_munmap(m, a, l)
#endif
#define I810_BUF_FREE 2 #define I810_BUF_FREE 2
#define I810_BUF_CLIENT 1 #define I810_BUF_CLIENT 1
#define I810_BUF_HARDWARE 0 #define I810_BUF_HARDWARE 0
@ -131,13 +125,13 @@ static int i810_mmap_buffers(struct file *filp, struct vm_area_struct *vma)
unlock_kernel(); unlock_kernel();
if (io_remap_pfn_range(vma, vma->vm_start, 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)) vma->vm_end - vma->vm_start, vma->vm_page_prot))
return -EAGAIN; return -EAGAIN;
return 0; return 0;
} }
static struct file_operations i810_buffer_fops = { static const struct file_operations i810_buffer_fops = {
.open = drm_open, .open = drm_open,
.release = drm_release, .release = drm_release,
.ioctl = drm_ioctl, .ioctl = drm_ioctl,
@ -186,7 +180,7 @@ static int i810_unmap_buffer(drm_buf_t * buf)
return -EINVAL; return -EINVAL;
down_write(&current->mm->mmap_sem); down_write(&current->mm->mmap_sem);
retcode = DO_MUNMAP(current->mm, retcode = do_munmap(current->mm,
(unsigned long)buf_priv->virtual, (unsigned long)buf_priv->virtual,
(size_t) buf->total); (size_t) buf->total);
up_write(&current->mm->mmap_sem); up_write(&current->mm->mmap_sem);
@ -244,8 +238,7 @@ static int i810_dma_cleanup(drm_device_t * dev)
(drm_i810_private_t *) dev->dev_private; (drm_i810_private_t *) dev->dev_private;
if (dev_priv->ring.virtual_start) { if (dev_priv->ring.virtual_start) {
drm_ioremapfree((void *)dev_priv->ring.virtual_start, drm_core_ioremapfree(&dev_priv->ring.map, dev);
dev_priv->ring.Size, dev);
} }
if (dev_priv->hw_status_page) { if (dev_priv->hw_status_page) {
pci_free_consistent(dev->pdev, PAGE_SIZE, pci_free_consistent(dev->pdev, PAGE_SIZE,
@ -261,9 +254,9 @@ static int i810_dma_cleanup(drm_device_t * dev)
for (i = 0; i < dma->buf_count; i++) { for (i = 0; i < dma->buf_count; i++) {
drm_buf_t *buf = dma->buflist[i]; drm_buf_t *buf = dma->buflist[i];
drm_i810_buf_priv_t *buf_priv = buf->dev_private; drm_i810_buf_priv_t *buf_priv = buf->dev_private;
if (buf_priv->kernel_virtual && buf->total) if (buf_priv->kernel_virtual && buf->total)
drm_ioremapfree(buf_priv->kernel_virtual, drm_core_ioremapfree(&buf_priv->map, dev);
buf->total, dev);
} }
} }
return 0; return 0;
@ -336,8 +329,15 @@ static int i810_freelist_init(drm_device_t * dev, drm_i810_private_t * dev_priv)
*buf_priv->in_use = I810_BUF_FREE; *buf_priv->in_use = I810_BUF_FREE;
buf_priv->kernel_virtual = drm_ioremap(buf->bus_address, buf_priv->map.offset = buf->bus_address;
buf->total, dev); buf_priv->map.size = buf->total;
buf_priv->map.type = _DRM_AGP;
buf_priv->map.flags = 0;
buf_priv->map.mtrr = 0;
drm_core_ioremap(&buf_priv->map, dev);
buf_priv->kernel_virtual = buf_priv->map.handle;
} }
return 0; return 0;
} }
@ -346,12 +346,10 @@ static int i810_dma_initialize(drm_device_t * dev,
drm_i810_private_t * dev_priv, drm_i810_private_t * dev_priv,
drm_i810_init_t * init) drm_i810_init_t * init)
{ {
struct list_head *list; drm_map_list_t *r_list;
memset(dev_priv, 0, sizeof(drm_i810_private_t)); memset(dev_priv, 0, sizeof(drm_i810_private_t));
list_for_each(list, &dev->maplist->head) { list_for_each_entry(r_list, &dev->maplist, head) {
drm_map_list_t *r_list = list_entry(list, drm_map_list_t, head);
if (r_list->map && if (r_list->map &&
r_list->map->type == _DRM_SHM && r_list->map->type == _DRM_SHM &&
r_list->map->flags & _DRM_CONTAINS_LOCK) { r_list->map->flags & _DRM_CONTAINS_LOCK) {
@ -388,18 +386,24 @@ static int i810_dma_initialize(drm_device_t * dev,
dev_priv->ring.End = init->ring_end; dev_priv->ring.End = init->ring_end;
dev_priv->ring.Size = init->ring_size; dev_priv->ring.Size = init->ring_size;
dev_priv->ring.virtual_start = drm_ioremap(dev->agp->base + dev_priv->ring.map.offset = dev->agp->base + init->ring_start;
init->ring_start, dev_priv->ring.map.size = init->ring_size;
init->ring_size, dev); dev_priv->ring.map.type = _DRM_AGP;
dev_priv->ring.map.flags = 0;
dev_priv->ring.map.mtrr = 0;
if (dev_priv->ring.virtual_start == NULL) { drm_core_ioremap(&dev_priv->ring.map, dev);
if (dev_priv->ring.map.handle == NULL) {
dev->dev_private = (void *)dev_priv; dev->dev_private = (void *)dev_priv;
i810_dma_cleanup(dev); i810_dma_cleanup(dev);
DRM_ERROR("can not ioremap virtual address for" DRM_ERROR("can not ioremap virtual address for"
" ring buffer\n"); " ring buffer\n");
return -ENOMEM; return DRM_ERR(ENOMEM);
} }
dev_priv->ring.virtual_start = dev_priv->ring.map.handle;
dev_priv->ring.tail_mask = dev_priv->ring.Size - 1; dev_priv->ring.tail_mask = dev_priv->ring.Size - 1;
dev_priv->w = init->w; dev_priv->w = init->w;

View file

@ -61,6 +61,7 @@ typedef struct drm_i810_buf_priv {
int currently_mapped; int currently_mapped;
void *virtual; void *virtual;
void *kernel_virtual; void *kernel_virtual;
drm_local_map_t map;
} drm_i810_buf_priv_t; } drm_i810_buf_priv_t;
typedef struct _drm_i810_ring_buffer { typedef struct _drm_i810_ring_buffer {
@ -72,6 +73,7 @@ typedef struct _drm_i810_ring_buffer {
int head; int head;
int tail; int tail;
int space; int space;
drm_local_map_t map;
} drm_i810_ring_buffer_t; } drm_i810_ring_buffer_t;
typedef struct drm_i810_private { typedef struct drm_i810_private {

File diff suppressed because it is too large Load diff

View file

@ -1,342 +0,0 @@
#ifndef _I830_DRM_H_
#define _I830_DRM_H_
/* WARNING: These defines must be the same as what the Xserver uses.
* if you change them, you must change the defines in the Xserver.
*
* KW: Actually, you can't ever change them because doing so would
* break backwards compatibility.
*/
#ifndef _I830_DEFINES_
#define _I830_DEFINES_
#define I830_DMA_BUF_ORDER 12
#define I830_DMA_BUF_SZ (1<<I830_DMA_BUF_ORDER)
#define I830_DMA_BUF_NR 256
#define I830_NR_SAREA_CLIPRECTS 8
/* Each region is a minimum of 64k, and there are at most 64 of them.
*/
#define I830_NR_TEX_REGIONS 64
#define I830_LOG_MIN_TEX_REGION_SIZE 16
/* KW: These aren't correct but someone set them to two and then
* released the module. Now we can't change them as doing so would
* break backwards compatibility.
*/
#define I830_TEXTURE_COUNT 2
#define I830_TEXBLEND_COUNT I830_TEXTURE_COUNT
#define I830_TEXBLEND_SIZE 12 /* (4 args + op) * 2 + COLOR_FACTOR */
#define I830_UPLOAD_CTX 0x1
#define I830_UPLOAD_BUFFERS 0x2
#define I830_UPLOAD_CLIPRECTS 0x4
#define I830_UPLOAD_TEX0_IMAGE 0x100 /* handled clientside */
#define I830_UPLOAD_TEX0_CUBE 0x200 /* handled clientside */
#define I830_UPLOAD_TEX1_IMAGE 0x400 /* handled clientside */
#define I830_UPLOAD_TEX1_CUBE 0x800 /* handled clientside */
#define I830_UPLOAD_TEX2_IMAGE 0x1000 /* handled clientside */
#define I830_UPLOAD_TEX2_CUBE 0x2000 /* handled clientside */
#define I830_UPLOAD_TEX3_IMAGE 0x4000 /* handled clientside */
#define I830_UPLOAD_TEX3_CUBE 0x8000 /* handled clientside */
#define I830_UPLOAD_TEX_N_IMAGE(n) (0x100 << (n * 2))
#define I830_UPLOAD_TEX_N_CUBE(n) (0x200 << (n * 2))
#define I830_UPLOAD_TEXIMAGE_MASK 0xff00
#define I830_UPLOAD_TEX0 0x10000
#define I830_UPLOAD_TEX1 0x20000
#define I830_UPLOAD_TEX2 0x40000
#define I830_UPLOAD_TEX3 0x80000
#define I830_UPLOAD_TEX_N(n) (0x10000 << (n))
#define I830_UPLOAD_TEX_MASK 0xf0000
#define I830_UPLOAD_TEXBLEND0 0x100000
#define I830_UPLOAD_TEXBLEND1 0x200000
#define I830_UPLOAD_TEXBLEND2 0x400000
#define I830_UPLOAD_TEXBLEND3 0x800000
#define I830_UPLOAD_TEXBLEND_N(n) (0x100000 << (n))
#define I830_UPLOAD_TEXBLEND_MASK 0xf00000
#define I830_UPLOAD_TEX_PALETTE_N(n) (0x1000000 << (n))
#define I830_UPLOAD_TEX_PALETTE_SHARED 0x4000000
#define I830_UPLOAD_STIPPLE 0x8000000
/* Indices into buf.Setup where various bits of state are mirrored per
* context and per buffer. These can be fired at the card as a unit,
* or in a piecewise fashion as required.
*/
/* Destbuffer state
* - backbuffer linear offset and pitch -- invarient in the current dri
* - zbuffer linear offset and pitch -- also invarient
* - drawing origin in back and depth buffers.
*
* Keep the depth/back buffer state here to accommodate private buffers
* in the future.
*/
#define I830_DESTREG_CBUFADDR 0
#define I830_DESTREG_DBUFADDR 1
#define I830_DESTREG_DV0 2
#define I830_DESTREG_DV1 3
#define I830_DESTREG_SENABLE 4
#define I830_DESTREG_SR0 5
#define I830_DESTREG_SR1 6
#define I830_DESTREG_SR2 7
#define I830_DESTREG_DR0 8
#define I830_DESTREG_DR1 9
#define I830_DESTREG_DR2 10
#define I830_DESTREG_DR3 11
#define I830_DESTREG_DR4 12
#define I830_DEST_SETUP_SIZE 13
/* Context state
*/
#define I830_CTXREG_STATE1 0
#define I830_CTXREG_STATE2 1
#define I830_CTXREG_STATE3 2
#define I830_CTXREG_STATE4 3
#define I830_CTXREG_STATE5 4
#define I830_CTXREG_IALPHAB 5
#define I830_CTXREG_STENCILTST 6
#define I830_CTXREG_ENABLES_1 7
#define I830_CTXREG_ENABLES_2 8
#define I830_CTXREG_AA 9
#define I830_CTXREG_FOGCOLOR 10
#define I830_CTXREG_BLENDCOLR0 11
#define I830_CTXREG_BLENDCOLR 12 /* Dword 1 of 2 dword command */
#define I830_CTXREG_VF 13
#define I830_CTXREG_VF2 14
#define I830_CTXREG_MCSB0 15
#define I830_CTXREG_MCSB1 16
#define I830_CTX_SETUP_SIZE 17
/* 1.3: Stipple state
*/
#define I830_STPREG_ST0 0
#define I830_STPREG_ST1 1
#define I830_STP_SETUP_SIZE 2
/* Texture state (per tex unit)
*/
#define I830_TEXREG_MI0 0 /* GFX_OP_MAP_INFO (6 dwords) */
#define I830_TEXREG_MI1 1
#define I830_TEXREG_MI2 2
#define I830_TEXREG_MI3 3
#define I830_TEXREG_MI4 4
#define I830_TEXREG_MI5 5
#define I830_TEXREG_MF 6 /* GFX_OP_MAP_FILTER */
#define I830_TEXREG_MLC 7 /* GFX_OP_MAP_LOD_CTL */
#define I830_TEXREG_MLL 8 /* GFX_OP_MAP_LOD_LIMITS */
#define I830_TEXREG_MCS 9 /* GFX_OP_MAP_COORD_SETS */
#define I830_TEX_SETUP_SIZE 10
#define I830_TEXREG_TM0LI 0 /* load immediate 2 texture map n */
#define I830_TEXREG_TM0S0 1
#define I830_TEXREG_TM0S1 2
#define I830_TEXREG_TM0S2 3
#define I830_TEXREG_TM0S3 4
#define I830_TEXREG_TM0S4 5
#define I830_TEXREG_NOP0 6 /* noop */
#define I830_TEXREG_NOP1 7 /* noop */
#define I830_TEXREG_NOP2 8 /* noop */
#define __I830_TEXREG_MCS 9 /* GFX_OP_MAP_COORD_SETS -- shared */
#define __I830_TEX_SETUP_SIZE 10
#define I830_FRONT 0x1
#define I830_BACK 0x2
#define I830_DEPTH 0x4
#endif /* _I830_DEFINES_ */
typedef struct _drm_i830_init {
enum {
I830_INIT_DMA = 0x01,
I830_CLEANUP_DMA = 0x02
} func;
unsigned int mmio_offset;
unsigned int buffers_offset;
int sarea_priv_offset;
unsigned int ring_start;
unsigned int ring_end;
unsigned int ring_size;
unsigned int front_offset;
unsigned int back_offset;
unsigned int depth_offset;
unsigned int w;
unsigned int h;
unsigned int pitch;
unsigned int pitch_bits;
unsigned int back_pitch;
unsigned int depth_pitch;
unsigned int cpp;
} drm_i830_init_t;
/* Warning: If you change the SAREA structure you must change the Xserver
* structure as well */
typedef struct _drm_i830_tex_region {
unsigned char next, prev; /* indices to form a circular LRU */
unsigned char in_use; /* owned by a client, or free? */
int age; /* tracked by clients to update local LRU's */
} drm_i830_tex_region_t;
typedef struct _drm_i830_sarea {
unsigned int ContextState[I830_CTX_SETUP_SIZE];
unsigned int BufferState[I830_DEST_SETUP_SIZE];
unsigned int TexState[I830_TEXTURE_COUNT][I830_TEX_SETUP_SIZE];
unsigned int TexBlendState[I830_TEXBLEND_COUNT][I830_TEXBLEND_SIZE];
unsigned int TexBlendStateWordsUsed[I830_TEXBLEND_COUNT];
unsigned int Palette[2][256];
unsigned int dirty;
unsigned int nbox;
drm_clip_rect_t boxes[I830_NR_SAREA_CLIPRECTS];
/* Maintain an LRU of contiguous regions of texture space. If
* you think you own a region of texture memory, and it has an
* age different to the one you set, then you are mistaken and
* it has been stolen by another client. If global texAge
* hasn't changed, there is no need to walk the list.
*
* These regions can be used as a proxy for the fine-grained
* texture information of other clients - by maintaining them
* in the same lru which is used to age their own textures,
* clients have an approximate lru for the whole of global
* texture space, and can make informed decisions as to which
* areas to kick out. There is no need to choose whether to
* kick out your own texture or someone else's - simply eject
* them all in LRU order.
*/
drm_i830_tex_region_t texList[I830_NR_TEX_REGIONS + 1];
/* Last elt is sentinal */
int texAge; /* last time texture was uploaded */
int last_enqueue; /* last time a buffer was enqueued */
int last_dispatch; /* age of the most recently dispatched buffer */
int last_quiescent; /* */
int ctxOwner; /* last context to upload state */
int vertex_prim;
int pf_enabled; /* is pageflipping allowed? */
int pf_active;
int pf_current_page; /* which buffer is being displayed? */
int perf_boxes; /* performance boxes to be displayed */
/* Here's the state for texunits 2,3:
*/
unsigned int TexState2[I830_TEX_SETUP_SIZE];
unsigned int TexBlendState2[I830_TEXBLEND_SIZE];
unsigned int TexBlendStateWordsUsed2;
unsigned int TexState3[I830_TEX_SETUP_SIZE];
unsigned int TexBlendState3[I830_TEXBLEND_SIZE];
unsigned int TexBlendStateWordsUsed3;
unsigned int StippleState[I830_STP_SETUP_SIZE];
} drm_i830_sarea_t;
/* Flags for perf_boxes
*/
#define I830_BOX_RING_EMPTY 0x1 /* populated by kernel */
#define I830_BOX_FLIP 0x2 /* populated by kernel */
#define I830_BOX_WAIT 0x4 /* populated by kernel & client */
#define I830_BOX_TEXTURE_LOAD 0x8 /* populated by kernel */
#define I830_BOX_LOST_CONTEXT 0x10 /* populated by client */
/* I830 specific ioctls
* The device specific ioctl range is 0x40 to 0x79.
*/
#define DRM_I830_INIT 0x00
#define DRM_I830_VERTEX 0x01
#define DRM_I830_CLEAR 0x02
#define DRM_I830_FLUSH 0x03
#define DRM_I830_GETAGE 0x04
#define DRM_I830_GETBUF 0x05
#define DRM_I830_SWAP 0x06
#define DRM_I830_COPY 0x07
#define DRM_I830_DOCOPY 0x08
#define DRM_I830_FLIP 0x09
#define DRM_I830_IRQ_EMIT 0x0a
#define DRM_I830_IRQ_WAIT 0x0b
#define DRM_I830_GETPARAM 0x0c
#define DRM_I830_SETPARAM 0x0d
#define DRM_IOCTL_I830_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_IOCTL_I830_INIT, drm_i830_init_t)
#define DRM_IOCTL_I830_VERTEX DRM_IOW( DRM_COMMAND_BASE + DRM_IOCTL_I830_VERTEX, drm_i830_vertex_t)
#define DRM_IOCTL_I830_CLEAR DRM_IOW( DRM_COMMAND_BASE + DRM_IOCTL_I830_CLEAR, drm_i830_clear_t)
#define DRM_IOCTL_I830_FLUSH DRM_IO ( DRM_COMMAND_BASE + DRM_IOCTL_I830_FLUSH)
#define DRM_IOCTL_I830_GETAGE DRM_IO ( DRM_COMMAND_BASE + DRM_IOCTL_I830_GETAGE)
#define DRM_IOCTL_I830_GETBUF DRM_IOWR(DRM_COMMAND_BASE + DRM_IOCTL_I830_GETBUF, drm_i830_dma_t)
#define DRM_IOCTL_I830_SWAP DRM_IO ( DRM_COMMAND_BASE + DRM_IOCTL_I830_SWAP)
#define DRM_IOCTL_I830_COPY DRM_IOW( DRM_COMMAND_BASE + DRM_IOCTL_I830_COPY, drm_i830_copy_t)
#define DRM_IOCTL_I830_DOCOPY DRM_IO ( DRM_COMMAND_BASE + DRM_IOCTL_I830_DOCOPY)
#define DRM_IOCTL_I830_FLIP DRM_IO ( DRM_COMMAND_BASE + DRM_IOCTL_I830_FLIP)
#define DRM_IOCTL_I830_IRQ_EMIT DRM_IOWR(DRM_COMMAND_BASE + DRM_IOCTL_I830_IRQ_EMIT, drm_i830_irq_emit_t)
#define DRM_IOCTL_I830_IRQ_WAIT DRM_IOW( DRM_COMMAND_BASE + DRM_IOCTL_I830_IRQ_WAIT, drm_i830_irq_wait_t)
#define DRM_IOCTL_I830_GETPARAM DRM_IOWR(DRM_COMMAND_BASE + DRM_IOCTL_I830_GETPARAM, drm_i830_getparam_t)
#define DRM_IOCTL_I830_SETPARAM DRM_IOWR(DRM_COMMAND_BASE + DRM_IOCTL_I830_SETPARAM, drm_i830_setparam_t)
typedef struct _drm_i830_clear {
int clear_color;
int clear_depth;
int flags;
unsigned int clear_colormask;
unsigned int clear_depthmask;
} drm_i830_clear_t;
/* These may be placeholders if we have more cliprects than
* I830_NR_SAREA_CLIPRECTS. In that case, the client sets discard to
* false, indicating that the buffer will be dispatched again with a
* new set of cliprects.
*/
typedef struct _drm_i830_vertex {
int idx; /* buffer index */
int used; /* nr bytes in use */
int discard; /* client is finished with the buffer? */
} drm_i830_vertex_t;
typedef struct _drm_i830_copy_t {
int idx; /* buffer index */
int used; /* nr bytes in use */
void __user *address; /* Address to copy from */
} drm_i830_copy_t;
typedef struct drm_i830_dma {
void __user *virtual;
int request_idx;
int request_size;
int granted;
} drm_i830_dma_t;
/* 1.3: Userspace can request & wait on irq's:
*/
typedef struct drm_i830_irq_emit {
int __user *irq_seq;
} drm_i830_irq_emit_t;
typedef struct drm_i830_irq_wait {
int irq_seq;
} drm_i830_irq_wait_t;
/* 1.3: New ioctl to query kernel params:
*/
#define I830_PARAM_IRQ_ACTIVE 1
typedef struct drm_i830_getparam {
int param;
int __user *value;
} drm_i830_getparam_t;
/* 1.3: New ioctl to set kernel params:
*/
#define I830_SETPARAM_USE_MI_BATCHBUFFER_START 1
typedef struct drm_i830_setparam {
int param;
int value;
} drm_i830_setparam_t;
#endif /* _I830_DRM_H_ */

View file

@ -1,290 +0,0 @@
/* i830_drv.h -- Private header for the I830 driver -*- linux-c -*-
* Created: Mon Dec 13 01:50:01 1999 by jhartmann@precisioninsight.com
*
* Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
* Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
* 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: Rickard E. (Rik) Faith <faith@valinux.com>
* Jeff Hartmann <jhartmann@valinux.com>
*
*/
#ifndef _I830_DRV_H_
#define _I830_DRV_H_
/* General customization:
*/
#define DRIVER_AUTHOR "VA Linux Systems Inc."
#define DRIVER_NAME "i830"
#define DRIVER_DESC "Intel 830M"
#define DRIVER_DATE "20021108"
/* Interface history:
*
* 1.1: Original.
* 1.2: ?
* 1.3: New irq emit/wait ioctls.
* New pageflip ioctl.
* New getparam ioctl.
* State for texunits 3&4 in sarea.
* New (alternative) layout for texture state.
*/
#define DRIVER_MAJOR 1
#define DRIVER_MINOR 3
#define DRIVER_PATCHLEVEL 2
/* Driver will work either way: IRQ's save cpu time when waiting for
* the card, but are subject to subtle interactions between bios,
* hardware and the driver.
*/
/* XXX: Add vblank support? */
#define USE_IRQS 0
typedef struct drm_i830_buf_priv {
u32 *in_use;
int my_use_idx;
int currently_mapped;
void __user *virtual;
void *kernel_virtual;
} drm_i830_buf_priv_t;
typedef struct _drm_i830_ring_buffer {
int tail_mask;
unsigned long Start;
unsigned long End;
unsigned long Size;
u8 *virtual_start;
int head;
int tail;
int space;
} drm_i830_ring_buffer_t;
typedef struct drm_i830_private {
drm_map_t *sarea_map;
drm_map_t *mmio_map;
drm_i830_sarea_t *sarea_priv;
drm_i830_ring_buffer_t ring;
void *hw_status_page;
unsigned long counter;
dma_addr_t dma_status_page;
drm_buf_t *mmap_buffer;
u32 front_di1, back_di1, zi1;
int back_offset;
int depth_offset;
int front_offset;
int w, h;
int pitch;
int back_pitch;
int depth_pitch;
unsigned int cpp;
int do_boxes;
int dma_used;
int current_page;
int page_flipping;
wait_queue_head_t irq_queue;
atomic_t irq_received;
atomic_t irq_emitted;
int use_mi_batchbuffer_start;
} drm_i830_private_t;
extern drm_ioctl_desc_t i830_ioctls[];
extern int i830_max_ioctl;
/* i830_irq.c */
extern int i830_irq_emit(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
extern int i830_irq_wait(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
extern irqreturn_t i830_driver_irq_handler(DRM_IRQ_ARGS);
extern void i830_driver_irq_preinstall(drm_device_t * dev);
extern void i830_driver_irq_postinstall(drm_device_t * dev);
extern void i830_driver_irq_uninstall(drm_device_t * dev);
extern int i830_driver_load(struct drm_device *, unsigned long flags);
extern void i830_driver_preclose(drm_device_t * dev, DRMFILE filp);
extern void i830_driver_lastclose(drm_device_t * dev);
extern void i830_driver_reclaim_buffers_locked(drm_device_t * dev,
struct file *filp);
extern int i830_driver_dma_quiescent(drm_device_t * dev);
extern int i830_driver_device_is_agp(drm_device_t * dev);
#define I830_READ(reg) DRM_READ32(dev_priv->mmio_map, reg)
#define I830_WRITE(reg,val) DRM_WRITE32(dev_priv->mmio_map, reg, val)
#define I830_READ16(reg) DRM_READ16(dev_priv->mmio_map, reg)
#define I830_WRITE16(reg,val) DRM_WRITE16(dev_priv->mmio_map, reg, val)
#define I830_VERBOSE 0
#define RING_LOCALS unsigned int outring, ringmask, outcount; \
volatile char *virt;
#define BEGIN_LP_RING(n) do { \
if (I830_VERBOSE) \
printk("BEGIN_LP_RING(%d) in %s\n", \
n, __FUNCTION__); \
if (dev_priv->ring.space < n*4) \
i830_wait_ring(dev, n*4, __FUNCTION__); \
outcount = 0; \
outring = dev_priv->ring.tail; \
ringmask = dev_priv->ring.tail_mask; \
virt = dev_priv->ring.virtual_start; \
} while (0)
#define OUT_RING(n) do { \
if (I830_VERBOSE) printk(" OUT_RING %x\n", (int)(n)); \
*(volatile unsigned int *)(virt + outring) = n; \
outcount++; \
outring += 4; \
outring &= ringmask; \
} while (0)
#define ADVANCE_LP_RING() do { \
if (I830_VERBOSE) printk("ADVANCE_LP_RING %x\n", outring); \
dev_priv->ring.tail = outring; \
dev_priv->ring.space -= outcount * 4; \
I830_WRITE(LP_RING + RING_TAIL, outring); \
} while(0)
extern int i830_wait_ring(drm_device_t * dev, int n, const char *caller);
#define GFX_OP_USER_INTERRUPT ((0<<29)|(2<<23))
#define GFX_OP_BREAKPOINT_INTERRUPT ((0<<29)|(1<<23))
#define CMD_REPORT_HEAD (7<<23)
#define CMD_STORE_DWORD_IDX ((0x21<<23) | 0x1)
#define CMD_OP_BATCH_BUFFER ((0x0<<29)|(0x30<<23)|0x1)
#define STATE3D_LOAD_STATE_IMMEDIATE_2 ((0x3<<29)|(0x1d<<24)|(0x03<<16))
#define LOAD_TEXTURE_MAP0 (1<<11)
#define INST_PARSER_CLIENT 0x00000000
#define INST_OP_FLUSH 0x02000000
#define INST_FLUSH_MAP_CACHE 0x00000001
#define BB1_START_ADDR_MASK (~0x7)
#define BB1_PROTECTED (1<<0)
#define BB1_UNPROTECTED (0<<0)
#define BB2_END_ADDR_MASK (~0x7)
#define I830REG_HWSTAM 0x02098
#define I830REG_INT_IDENTITY_R 0x020a4
#define I830REG_INT_MASK_R 0x020a8
#define I830REG_INT_ENABLE_R 0x020a0
#define I830_IRQ_RESERVED ((1<<13)|(3<<2))
#define LP_RING 0x2030
#define HP_RING 0x2040
#define RING_TAIL 0x00
#define TAIL_ADDR 0x001FFFF8
#define RING_HEAD 0x04
#define HEAD_WRAP_COUNT 0xFFE00000
#define HEAD_WRAP_ONE 0x00200000
#define HEAD_ADDR 0x001FFFFC
#define RING_START 0x08
#define START_ADDR 0x0xFFFFF000
#define RING_LEN 0x0C
#define RING_NR_PAGES 0x001FF000
#define RING_REPORT_MASK 0x00000006
#define RING_REPORT_64K 0x00000002
#define RING_REPORT_128K 0x00000004
#define RING_NO_REPORT 0x00000000
#define RING_VALID_MASK 0x00000001
#define RING_VALID 0x00000001
#define RING_INVALID 0x00000000
#define GFX_OP_SCISSOR ((0x3<<29)|(0x1c<<24)|(0x10<<19))
#define SC_UPDATE_SCISSOR (0x1<<1)
#define SC_ENABLE_MASK (0x1<<0)
#define SC_ENABLE (0x1<<0)
#define GFX_OP_SCISSOR_INFO ((0x3<<29)|(0x1d<<24)|(0x81<<16)|(0x1))
#define SCI_YMIN_MASK (0xffff<<16)
#define SCI_XMIN_MASK (0xffff<<0)
#define SCI_YMAX_MASK (0xffff<<16)
#define SCI_XMAX_MASK (0xffff<<0)
#define GFX_OP_SCISSOR_ENABLE ((0x3<<29)|(0x1c<<24)|(0x10<<19))
#define GFX_OP_SCISSOR_RECT ((0x3<<29)|(0x1d<<24)|(0x81<<16)|1)
#define GFX_OP_COLOR_FACTOR ((0x3<<29)|(0x1d<<24)|(0x1<<16)|0x0)
#define GFX_OP_STIPPLE ((0x3<<29)|(0x1d<<24)|(0x83<<16))
#define GFX_OP_MAP_INFO ((0x3<<29)|(0x1d<<24)|0x4)
#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_PRIMITIVE ((0x3<<29)|(0x1f<<24))
#define CMD_OP_DESTBUFFER_INFO ((0x3<<29)|(0x1d<<24)|(0x8e<<16)|1)
#define CMD_OP_DISPLAYBUFFER_INFO ((0x0<<29)|(0x14<<23)|2)
#define ASYNC_FLIP (1<<22)
#define CMD_3D (0x3<<29)
#define STATE3D_CONST_BLEND_COLOR_CMD (CMD_3D|(0x1d<<24)|(0x88<<16))
#define STATE3D_MAP_COORD_SETBIND_CMD (CMD_3D|(0x1d<<24)|(0x02<<16))
#define BR00_BITBLT_CLIENT 0x40000000
#define BR00_OP_COLOR_BLT 0x10000000
#define BR00_OP_SRC_COPY_BLT 0x10C00000
#define BR13_SOLID_PATTERN 0x80000000
#define BUF_3D_ID_COLOR_BACK (0x3<<24)
#define BUF_3D_ID_DEPTH (0x7<<24)
#define BUF_3D_USE_FENCE (1<<23)
#define BUF_3D_PITCH(x) (((x)/4)<<2)
#define CMD_OP_MAP_PALETTE_LOAD ((3<<29)|(0x1d<<24)|(0x82<<16)|255)
#define MAP_PALETTE_NUM(x) ((x<<8) & (1<<8))
#define MAP_PALETTE_BOTH (1<<11)
#define XY_COLOR_BLT_CMD ((2<<29)|(0x50<<22)|0x4)
#define XY_COLOR_BLT_WRITE_ALPHA (1<<21)
#define XY_COLOR_BLT_WRITE_RGB (1<<20)
#define XY_SRC_COPY_BLT_CMD ((2<<29)|(0x53<<22)|6)
#define XY_SRC_COPY_BLT_WRITE_ALPHA (1<<21)
#define XY_SRC_COPY_BLT_WRITE_RGB (1<<20)
#define MI_BATCH_BUFFER ((0x30<<23)|1)
#define MI_BATCH_BUFFER_START (0x31<<23)
#define MI_BATCH_BUFFER_END (0xA<<23)
#define MI_BATCH_NON_SECURE (1)
#define MI_WAIT_FOR_EVENT ((0x3<<23))
#define MI_WAIT_FOR_PLANE_A_FLIP (1<<2)
#define MI_WAIT_FOR_PLANE_A_SCANLINES (1<<1)
#define MI_LOAD_SCAN_LINES_INCL ((0x12<<23))
#endif

View file

@ -1,198 +0,0 @@
/* i830_dma.c -- DMA support for the I830 -*- linux-c -*-
*
* Copyright 2002 Tungsten Graphics, Inc.
* 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
* TUNGSTEN 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.
*
* Authors: Keith Whitwell <keith@tungstengraphics.com>
*
*/
#include "drmP.h"
#include "drm.h"
#include "i830_drm.h"
#include "i830_drv.h"
#include <linux/interrupt.h> /* For task queue support */
#include <linux/delay.h>
irqreturn_t i830_driver_irq_handler(DRM_IRQ_ARGS)
{
drm_device_t *dev = (drm_device_t *) arg;
drm_i830_private_t *dev_priv = (drm_i830_private_t *) dev->dev_private;
u16 temp;
temp = I830_READ16(I830REG_INT_IDENTITY_R);
DRM_DEBUG("%x\n", temp);
if (!(temp & 2))
return IRQ_NONE;
I830_WRITE16(I830REG_INT_IDENTITY_R, temp);
atomic_inc(&dev_priv->irq_received);
wake_up_interruptible(&dev_priv->irq_queue);
return IRQ_HANDLED;
}
static int i830_emit_irq(drm_device_t * dev)
{
drm_i830_private_t *dev_priv = dev->dev_private;
RING_LOCALS;
DRM_DEBUG("%s\n", __FUNCTION__);
atomic_inc(&dev_priv->irq_emitted);
BEGIN_LP_RING(2);
OUT_RING(0);
OUT_RING(GFX_OP_USER_INTERRUPT);
ADVANCE_LP_RING();
return atomic_read(&dev_priv->irq_emitted);
}
static int i830_wait_irq(drm_device_t * dev, int irq_nr)
{
drm_i830_private_t *dev_priv = (drm_i830_private_t *) dev->dev_private;
DECLARE_WAITQUEUE(entry, current);
unsigned long end = jiffies + HZ * 3;
int ret = 0;
DRM_DEBUG("%s\n", __FUNCTION__);
if (atomic_read(&dev_priv->irq_received) >= irq_nr)
return 0;
dev_priv->sarea_priv->perf_boxes |= I830_BOX_WAIT;
add_wait_queue(&dev_priv->irq_queue, &entry);
for (;;) {
__set_current_state(TASK_INTERRUPTIBLE);
if (atomic_read(&dev_priv->irq_received) >= irq_nr)
break;
if ((signed)(end - jiffies) <= 0) {
DRM_ERROR("timeout iir %x imr %x ier %x hwstam %x\n",
I830_READ16(I830REG_INT_IDENTITY_R),
I830_READ16(I830REG_INT_MASK_R),
I830_READ16(I830REG_INT_ENABLE_R),
I830_READ16(I830REG_HWSTAM));
ret = -EBUSY; /* Lockup? Missed irq? */
break;
}
schedule_timeout(HZ * 3);
if (signal_pending(current)) {
ret = -EINTR;
break;
}
}
__set_current_state(TASK_RUNNING);
remove_wait_queue(&dev_priv->irq_queue, &entry);
return ret;
}
/* Needs the lock as it touches the ring.
*/
int i830_irq_emit(struct inode *inode, struct file *filp, unsigned int cmd,
unsigned long arg)
{
drm_file_t *priv = filp->private_data;
drm_device_t *dev = priv->head->dev;
drm_i830_private_t *dev_priv = dev->dev_private;
drm_i830_irq_emit_t emit;
int result;
LOCK_TEST_WITH_RETURN(dev, filp);
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
return -EINVAL;
}
if (copy_from_user
(&emit, (drm_i830_irq_emit_t __user *) arg, sizeof(emit)))
return -EFAULT;
result = i830_emit_irq(dev);
if (copy_to_user(emit.irq_seq, &result, sizeof(int))) {
DRM_ERROR("copy_to_user\n");
return -EFAULT;
}
return 0;
}
/* Doesn't need the hardware lock.
*/
int i830_irq_wait(struct inode *inode, struct file *filp, unsigned int cmd,
unsigned long arg)
{
drm_file_t *priv = filp->private_data;
drm_device_t *dev = priv->head->dev;
drm_i830_private_t *dev_priv = dev->dev_private;
drm_i830_irq_wait_t irqwait;
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
return -EINVAL;
}
if (copy_from_user(&irqwait, (drm_i830_irq_wait_t __user *) arg,
sizeof(irqwait)))
return -EFAULT;
return i830_wait_irq(dev, irqwait.irq_seq);
}
/* drm_dma.h hooks
*/
void i830_driver_irq_preinstall(drm_device_t * dev)
{
drm_i830_private_t *dev_priv = (drm_i830_private_t *) dev->dev_private;
I830_WRITE16(I830REG_HWSTAM, 0xffff);
I830_WRITE16(I830REG_INT_MASK_R, 0x0);
I830_WRITE16(I830REG_INT_ENABLE_R, 0x0);
atomic_set(&dev_priv->irq_received, 0);
atomic_set(&dev_priv->irq_emitted, 0);
init_waitqueue_head(&dev_priv->irq_queue);
}
void i830_driver_irq_postinstall(drm_device_t * dev)
{
drm_i830_private_t *dev_priv = (drm_i830_private_t *) dev->dev_private;
I830_WRITE16(I830REG_INT_ENABLE_R, 0x2);
}
void i830_driver_irq_uninstall(drm_device_t * dev)
{
drm_i830_private_t *dev_priv = (drm_i830_private_t *) dev->dev_private;
if (!dev_priv)
return;
I830_WRITE16(I830REG_INT_MASK_R, 0xffff);
I830_WRITE16(I830REG_INT_ENABLE_R, 0x0);
}

View file

@ -33,16 +33,15 @@
#include "i915_drm.h" #include "i915_drm.h"
#include "i915_drv.h" #include "i915_drv.h"
drm_ttm_backend_t *i915_create_ttm_backend_entry(drm_device_t * dev) drm_ttm_backend_t *i915_create_ttm_backend_entry(drm_device_t * dev)
{ {
return drm_agp_init_ttm(dev, NULL); return drm_agp_init_ttm(dev);
} }
int i915_fence_types(uint32_t buffer_flags, uint32_t * class, uint32_t * type) int i915_fence_types(drm_buffer_object_t *bo, uint32_t * class, uint32_t * type)
{ {
*class = 0; *class = 0;
if (buffer_flags & (DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE)) if (bo->mem.flags & (DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE))
*type = 3; *type = 3;
else else
*type = 1; *type = 1;
@ -64,3 +63,173 @@ int i915_invalidate_caches(drm_device_t * dev, uint32_t flags)
return i915_emit_mi_flush(dev, flush_cmd); return i915_emit_mi_flush(dev, flush_cmd);
} }
int i915_init_mem_type(drm_device_t * dev, uint32_t type,
drm_mem_type_manager_t * man)
{
switch (type) {
case DRM_BO_MEM_LOCAL:
man->flags = _DRM_FLAG_MEMTYPE_MAPPABLE |
_DRM_FLAG_MEMTYPE_CACHED;
man->drm_bus_maptype = 0;
break;
case DRM_BO_MEM_TT:
if (!(drm_core_has_AGP(dev) && dev->agp)) {
DRM_ERROR("AGP is not enabled for memory type %u\n",
(unsigned)type);
return -EINVAL;
}
man->io_offset = dev->agp->agp_info.aper_base;
man->io_size = dev->agp->agp_info.aper_size * 1024 * 1024;
man->io_addr = NULL;
man->flags = _DRM_FLAG_MEMTYPE_MAPPABLE |
_DRM_FLAG_MEMTYPE_CSELECT | _DRM_FLAG_NEEDS_IOREMAP;
man->drm_bus_maptype = _DRM_AGP;
break;
case DRM_BO_MEM_PRIV0:
if (!(drm_core_has_AGP(dev) && dev->agp)) {
DRM_ERROR("AGP is not enabled for memory type %u\n",
(unsigned)type);
return -EINVAL;
}
man->io_offset = dev->agp->agp_info.aper_base;
man->io_size = dev->agp->agp_info.aper_size * 1024 * 1024;
man->io_addr = NULL;
man->flags = _DRM_FLAG_MEMTYPE_MAPPABLE |
_DRM_FLAG_MEMTYPE_FIXED | _DRM_FLAG_NEEDS_IOREMAP;
man->drm_bus_maptype = _DRM_AGP;
break;
default:
DRM_ERROR("Unsupported memory type %u\n", (unsigned)type);
return -EINVAL;
}
return 0;
}
uint32_t i915_evict_mask(drm_buffer_object_t *bo)
{
switch (bo->mem.mem_type) {
case DRM_BO_MEM_LOCAL:
case DRM_BO_MEM_TT:
return DRM_BO_FLAG_MEM_LOCAL;
default:
return DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_CACHED;
}
}
static void i915_emit_copy_blit(drm_device_t * dev,
uint32_t src_offset,
uint32_t dst_offset,
uint32_t pages, int direction)
{
uint32_t cur_pages;
uint32_t stride = PAGE_SIZE;
drm_i915_private_t *dev_priv = dev->dev_private;
RING_LOCALS;
if (!dev_priv)
return;
i915_kernel_lost_context(dev);
while (pages > 0) {
cur_pages = pages;
if (cur_pages > 2048)
cur_pages = 2048;
pages -= cur_pages;
BEGIN_LP_RING(6);
OUT_RING(SRC_COPY_BLT_CMD | XY_SRC_COPY_BLT_WRITE_ALPHA |
XY_SRC_COPY_BLT_WRITE_RGB);
OUT_RING((stride & 0xffff) | (0xcc << 16) | (1 << 24) |
(1 << 25) | (direction ? (1 << 30) : 0));
OUT_RING((cur_pages << 16) | PAGE_SIZE);
OUT_RING(dst_offset);
OUT_RING(stride & 0xffff);
OUT_RING(src_offset);
ADVANCE_LP_RING();
}
return;
}
static int i915_move_blit(drm_buffer_object_t * bo,
int evict, int no_wait, drm_bo_mem_reg_t * new_mem)
{
drm_bo_mem_reg_t *old_mem = &bo->mem;
int dir = 0;
if ((old_mem->mem_type == new_mem->mem_type) &&
(new_mem->mm_node->start <
old_mem->mm_node->start + old_mem->mm_node->size)) {
dir = 1;
}
i915_emit_copy_blit(bo->dev,
old_mem->mm_node->start << PAGE_SHIFT,
new_mem->mm_node->start << PAGE_SHIFT,
new_mem->num_pages, dir);
i915_emit_mi_flush(bo->dev, MI_READ_FLUSH | MI_EXE_FLUSH);
return drm_bo_move_accel_cleanup(bo, evict, no_wait, 0,
DRM_FENCE_TYPE_EXE |
DRM_I915_FENCE_TYPE_RW,
DRM_I915_FENCE_FLAG_FLUSHED, new_mem);
}
/*
* Flip destination ttm into cached-coherent AGP,
* then blit and subsequently move out again.
*/
static int i915_move_flip(drm_buffer_object_t * bo,
int evict, int no_wait, drm_bo_mem_reg_t * new_mem)
{
drm_device_t *dev = bo->dev;
drm_bo_mem_reg_t tmp_mem;
int ret;
tmp_mem = *new_mem;
tmp_mem.mm_node = NULL;
tmp_mem.mask = DRM_BO_FLAG_MEM_TT |
DRM_BO_FLAG_CACHED | DRM_BO_FLAG_FORCE_CACHING;
ret = drm_bo_mem_space(bo, &tmp_mem, no_wait);
if (ret)
return ret;
ret = drm_bind_ttm(bo->ttm, 1, tmp_mem.mm_node->start);
if (ret)
goto out_cleanup;
ret = i915_move_blit(bo, 1, no_wait, &tmp_mem);
if (ret)
goto out_cleanup;
ret = drm_bo_move_ttm(bo, evict, no_wait, new_mem);
out_cleanup:
if (tmp_mem.mm_node) {
mutex_lock(&dev->struct_mutex);
if (tmp_mem.mm_node != bo->pinned_node)
drm_mm_put_block(tmp_mem.mm_node);
tmp_mem.mm_node = NULL;
mutex_unlock(&dev->struct_mutex);
}
return ret;
}
int i915_move(drm_buffer_object_t * bo,
int evict, int no_wait, drm_bo_mem_reg_t * new_mem)
{
drm_bo_mem_reg_t *old_mem = &bo->mem;
if (old_mem->mem_type == DRM_BO_MEM_LOCAL) {
return drm_bo_move_memcpy(bo, evict, no_wait, new_mem);
} else if (new_mem->mem_type == DRM_BO_MEM_LOCAL) {
if (i915_move_flip(bo, evict, no_wait, new_mem))
return drm_bo_move_memcpy(bo, evict, no_wait, new_mem);
} else {
if (i915_move_blit(bo, evict, no_wait, new_mem))
return drm_bo_move_memcpy(bo, evict, no_wait, new_mem);
}
return 0;
}

1
linux-core/i915_dma.c Symbolic link
View file

@ -0,0 +1 @@
../shared-core/i915_dma.c

1
linux-core/i915_drm.h Symbolic link
View file

@ -0,0 +1 @@
../shared-core/i915_drm.h

View file

@ -40,22 +40,32 @@ static struct pci_device_id pciidlist[] = {
#ifdef I915_HAVE_FENCE #ifdef I915_HAVE_FENCE
static drm_fence_driver_t i915_fence_driver = { static drm_fence_driver_t i915_fence_driver = {
.no_types = 2, .num_classes = 1,
.wrap_diff = (1 << 30), .wrap_diff = (1U << (BREADCRUMB_BITS - 1)),
.flush_diff = (1 << 29), .flush_diff = (1U << (BREADCRUMB_BITS - 2)),
.sequence_mask = 0xffffffffU, .sequence_mask = BREADCRUMB_MASK,
.lazy_capable = 1, .lazy_capable = 1,
.emit = i915_fence_emit_sequence, .emit = i915_fence_emit_sequence,
.poke_flush = i915_poke_flush, .poke_flush = i915_poke_flush,
.has_irq = i915_fence_has_irq,
}; };
#endif #endif
#ifdef I915_HAVE_BUFFER #ifdef I915_HAVE_BUFFER
static uint32_t i915_mem_prios[] = {DRM_BO_MEM_PRIV0, DRM_BO_MEM_TT, DRM_BO_MEM_LOCAL};
static uint32_t i915_busy_prios[] = {DRM_BO_MEM_TT, DRM_BO_MEM_PRIV0, DRM_BO_MEM_LOCAL};
static drm_bo_driver_t i915_bo_driver = { static drm_bo_driver_t i915_bo_driver = {
.iomap = {NULL, NULL}, .mem_type_prio = i915_mem_prios,
.cached = {1, 1}, .mem_busy_prio = i915_busy_prios,
.num_mem_type_prio = sizeof(i915_mem_prios)/sizeof(uint32_t),
.num_mem_busy_prio = sizeof(i915_busy_prios)/sizeof(uint32_t),
.create_ttm_backend_entry = i915_create_ttm_backend_entry, .create_ttm_backend_entry = i915_create_ttm_backend_entry,
.fence_type = i915_fence_types, .fence_type = i915_fence_types,
.invalidate_caches = i915_invalidate_caches .invalidate_caches = i915_invalidate_caches,
.init_mem_type = i915_init_mem_type,
.evict_mask = i915_evict_mask,
.move = i915_move,
}; };
#endif #endif
@ -69,6 +79,7 @@ static struct drm_driver driver = {
DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL |
DRIVER_IRQ_VBL2, DRIVER_IRQ_VBL2,
.load = i915_driver_load, .load = i915_driver_load,
.firstopen = i915_driver_firstopen,
.lastclose = i915_driver_lastclose, .lastclose = i915_driver_lastclose,
.preclose = i915_driver_preclose, .preclose = i915_driver_preclose,
.device_is_agp = i915_driver_device_is_agp, .device_is_agp = i915_driver_device_is_agp,

1
linux-core/i915_drv.h Symbolic link
View file

@ -0,0 +1 @@
../shared-core/i915_drv.h

View file

@ -42,36 +42,34 @@ static void i915_perform_flush(drm_device_t * dev)
{ {
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
drm_fence_manager_t *fm = &dev->fm; drm_fence_manager_t *fm = &dev->fm;
drm_fence_class_manager_t *fc = &fm->class[0];
drm_fence_driver_t *driver = dev->driver->fence_driver; drm_fence_driver_t *driver = dev->driver->fence_driver;
uint32_t flush_flags = 0; uint32_t flush_flags = 0;
uint32_t flush_sequence = 0; uint32_t flush_sequence = 0;
uint32_t i_status; uint32_t i_status;
uint32_t diff; uint32_t diff;
uint32_t sequence; uint32_t sequence;
int rwflush;
if (!dev_priv) if (!dev_priv)
return; return;
if (fm->pending_exe_flush) { if (fc->pending_exe_flush) {
sequence = READ_BREADCRUMB(dev_priv); sequence = READ_BREADCRUMB(dev_priv);
/* /*
* First update fences with the current breadcrumb. * First update fences with the current breadcrumb.
*/ */
diff = sequence - fm->last_exe_flush; diff = (sequence - fc->last_exe_flush) & BREADCRUMB_MASK;
if (diff < driver->wrap_diff && diff != 0) { if (diff < driver->wrap_diff && diff != 0) {
drm_fence_handler(dev, sequence, DRM_FENCE_TYPE_EXE); drm_fence_handler(dev, 0, sequence, DRM_FENCE_TYPE_EXE);
} }
diff = sequence - fm->exe_flush_sequence; if (dev_priv->fence_irq_on && !fc->pending_exe_flush) {
if (diff < driver->wrap_diff) { i915_user_irq_off(dev_priv);
fm->pending_exe_flush = 0; dev_priv->fence_irq_on = 0;
if (dev_priv->fence_irq_on) { } else if (!dev_priv->fence_irq_on && fc->pending_exe_flush) {
i915_user_irq_off(dev_priv);
dev_priv->fence_irq_on = 0;
}
} else if (!dev_priv->fence_irq_on) {
i915_user_irq_on(dev_priv); i915_user_irq_on(dev_priv);
dev_priv->fence_irq_on = 1; dev_priv->fence_irq_on = 1;
} }
@ -84,17 +82,18 @@ static void i915_perform_flush(drm_device_t * dev)
flush_flags = dev_priv->flush_flags; flush_flags = dev_priv->flush_flags;
flush_sequence = dev_priv->flush_sequence; flush_sequence = dev_priv->flush_sequence;
dev_priv->flush_pending = 0; dev_priv->flush_pending = 0;
drm_fence_handler(dev, flush_sequence, flush_flags); drm_fence_handler(dev, 0, flush_sequence, flush_flags);
} }
} }
if (fm->pending_flush && !dev_priv->flush_pending) { rwflush = fc->pending_flush & DRM_I915_FENCE_TYPE_RW;
if (rwflush && !dev_priv->flush_pending) {
dev_priv->flush_sequence = (uint32_t) READ_BREADCRUMB(dev_priv); dev_priv->flush_sequence = (uint32_t) READ_BREADCRUMB(dev_priv);
dev_priv->flush_flags = fm->pending_flush; dev_priv->flush_flags = fc->pending_flush;
dev_priv->saved_flush_status = READ_HWSP(dev_priv, 0); dev_priv->saved_flush_status = READ_HWSP(dev_priv, 0);
I915_WRITE(I915REG_INSTPM, (1 << 5) | (1 << 21)); I915_WRITE(I915REG_INSTPM, (1 << 5) | (1 << 21));
dev_priv->flush_pending = 1; dev_priv->flush_pending = 1;
fm->pending_flush = 0; fc->pending_flush &= ~DRM_I915_FENCE_TYPE_RW;
} }
if (dev_priv->flush_pending) { if (dev_priv->flush_pending) {
@ -104,13 +103,13 @@ static void i915_perform_flush(drm_device_t * dev)
flush_flags = dev_priv->flush_flags; flush_flags = dev_priv->flush_flags;
flush_sequence = dev_priv->flush_sequence; flush_sequence = dev_priv->flush_sequence;
dev_priv->flush_pending = 0; dev_priv->flush_pending = 0;
drm_fence_handler(dev, flush_sequence, flush_flags); drm_fence_handler(dev, 0, flush_sequence, flush_flags);
} }
} }
} }
void i915_poke_flush(drm_device_t * dev) void i915_poke_flush(drm_device_t * dev, uint32_t class)
{ {
drm_fence_manager_t *fm = &dev->fm; drm_fence_manager_t *fm = &dev->fm;
unsigned long flags; unsigned long flags;
@ -120,7 +119,7 @@ void i915_poke_flush(drm_device_t * dev)
write_unlock_irqrestore(&fm->lock, flags); write_unlock_irqrestore(&fm->lock, flags);
} }
int i915_fence_emit_sequence(drm_device_t * dev, uint32_t flags, int i915_fence_emit_sequence(drm_device_t * dev, uint32_t class, uint32_t flags,
uint32_t * sequence, uint32_t * native_type) uint32_t * sequence, uint32_t * native_type)
{ {
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
@ -144,3 +143,15 @@ void i915_fence_handler(drm_device_t * dev)
i915_perform_flush(dev); i915_perform_flush(dev);
write_unlock(&fm->lock); write_unlock(&fm->lock);
} }
int i915_fence_has_irq(drm_device_t *dev, uint32_t class, uint32_t flags)
{
/*
* We have an irq that tells us when we have a new breadcrumb.
*/
if (class == 0 && flags == DRM_FENCE_TYPE_EXE)
return 1;
return 0;
}

View file

@ -30,7 +30,6 @@
* IN THE SOFTWARE. * IN THE SOFTWARE.
*/ */
#include <linux/compat.h> #include <linux/compat.h>
#include <linux/ioctl32.h>
#include "drmP.h" #include "drmP.h"
#include "drm.h" #include "drm.h"

1
linux-core/i915_irq.c Symbolic link
View file

@ -0,0 +1 @@
../shared-core/i915_irq.c

1
linux-core/i915_mem.c Symbolic link
View file

@ -0,0 +1 @@
../shared-core/i915_mem.c

1
linux-core/linux Symbolic link
View file

@ -0,0 +1 @@
.

1
linux-core/mach64_dma.c Symbolic link
View file

@ -0,0 +1 @@
../shared-core/mach64_dma.c

1
linux-core/mach64_drm.h Symbolic link
View file

@ -0,0 +1 @@
../shared-core/mach64_drm.h

1
linux-core/mach64_drv.h Symbolic link
View file

@ -0,0 +1 @@
../shared-core/mach64_drv.h

1
linux-core/mach64_irq.c Symbolic link
View file

@ -0,0 +1 @@
../shared-core/mach64_irq.c

1
linux-core/mach64_state.c Symbolic link
View file

@ -0,0 +1 @@
../shared-core/mach64_state.c

1
linux-core/mga_dma.c Symbolic link
View file

@ -0,0 +1 @@
../shared-core/mga_dma.c

1
linux-core/mga_drm.h Symbolic link
View file

@ -0,0 +1 @@
../shared-core/mga_drm.h

1
linux-core/mga_drv.h Symbolic link
View file

@ -0,0 +1 @@
../shared-core/mga_drv.h

View file

@ -32,7 +32,6 @@
* IN THE SOFTWARE. * IN THE SOFTWARE.
*/ */
#include <linux/compat.h> #include <linux/compat.h>
#include <linux/ioctl32.h>
#include "drmP.h" #include "drmP.h"
#include "drm.h" #include "drm.h"

1
linux-core/mga_irq.c Symbolic link
View file

@ -0,0 +1 @@
../shared-core/mga_irq.c

1
linux-core/mga_state.c Symbolic link
View file

@ -0,0 +1 @@
../shared-core/mga_state.c

1
linux-core/mga_ucode.h Symbolic link
View file

@ -0,0 +1 @@
../shared-core/mga_ucode.h

1
linux-core/mga_warp.c Symbolic link
View file

@ -0,0 +1 @@
../shared-core/mga_warp.c

1
linux-core/nouveau_drm.h Symbolic link
View file

@ -0,0 +1 @@
../shared-core/nouveau_drm.h

View file

@ -1,8 +1,5 @@
/* i830_drv.c -- I810 driver -*- linux-c -*- /*
* Created: Mon Dec 13 01:56:22 1999 by jhartmann@precisioninsight.com * Copyright 2005 Stephane Marchesin.
*
* Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
* Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
* All Rights Reserved. * All Rights Reserved.
* *
* Permission is hereby granted, free of charge, to any person obtaining a * Permission is hereby granted, free of charge, to any person obtaining a
@ -23,51 +20,39 @@
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * 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 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE. * OTHER DEALINGS IN THE SOFTWARE.
*
* Authors:
* Rickard E. (Rik) Faith <faith@valinux.com>
* Jeff Hartmann <jhartmann@valinux.com>
* Gareth Hughes <gareth@valinux.com>
* Abraham vd Merwe <abraham@2d3d.co.za>
* Keith Whitwell <keith@tungstengraphics.com>
*/ */
#include "drmP.h" #include "drmP.h"
#include "drm.h" #include "drm.h"
#include "i830_drm.h" #include "nouveau_drv.h"
#include "i830_drv.h"
#include "drm_pciids.h" #include "drm_pciids.h"
static struct pci_device_id pciidlist[] = { static struct pci_device_id pciidlist[] = {
i830_PCI_IDS nouveau_PCI_IDS
}; };
extern drm_ioctl_desc_t nouveau_ioctls[];
extern int nouveau_max_ioctl;
static int probe(struct pci_dev *pdev, const struct pci_device_id *ent); static int probe(struct pci_dev *pdev, const struct pci_device_id *ent);
static struct drm_driver driver = { static struct drm_driver driver = {
.driver_features = .driver_features =
DRIVER_USE_AGP | DRIVER_REQUIRE_AGP | DRIVER_USE_MTRR | DRIVER_USE_AGP | DRIVER_PCI_DMA | DRIVER_SG |
DRIVER_HAVE_DMA | DRIVER_DMA_QUEUE, DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED,
#if USE_IRQS .load = nouveau_load,
.driver_features |= DRIVER_HAVE_IRQ | DRIVER_SHARED_IRQ, .firstopen = nouveau_firstopen,
#endif .lastclose = nouveau_lastclose,
.dev_priv_size = sizeof(drm_i830_buf_priv_t), .unload = nouveau_unload,
.load = i830_driver_load, .preclose = nouveau_preclose,
.lastclose = i830_driver_lastclose, .irq_preinstall = nouveau_irq_preinstall,
.preclose = i830_driver_preclose, .irq_postinstall = nouveau_irq_postinstall,
.device_is_agp = i830_driver_device_is_agp, .irq_uninstall = nouveau_irq_uninstall,
.reclaim_buffers_locked = i830_driver_reclaim_buffers_locked, .irq_handler = nouveau_irq_handler,
.dma_quiescent = i830_driver_dma_quiescent, .reclaim_buffers = drm_core_reclaim_buffers,
.get_map_ofs = drm_core_get_map_ofs, .get_map_ofs = drm_core_get_map_ofs,
.get_reg_ofs = drm_core_get_reg_ofs, .get_reg_ofs = drm_core_get_reg_ofs,
#if USE_IRQS .ioctls = nouveau_ioctls,
.irq_preinstall = i830_driver_irq_preinstall,
.irq_postinstall = i830_driver_irq_postinstall,
.irq_uninstall = i830_driver_irq_uninstall,
.irq_handler = i830_driver_irq_handler,
#endif
.ioctls = i830_ioctls,
.fops = { .fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.open = drm_open, .open = drm_open,
@ -76,7 +61,10 @@ static struct drm_driver driver = {
.mmap = drm_mmap, .mmap = drm_mmap,
.poll = drm_poll, .poll = drm_poll,
.fasync = drm_fasync, .fasync = drm_fasync,
}, #if defined(CONFIG_COMPAT) && LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9)
.compat_ioctl = nouveau_compat_ioctl,
#endif
},
.pci_driver = { .pci_driver = {
.name = DRIVER_NAME, .name = DRIVER_NAME,
.id_table = pciidlist, .id_table = pciidlist,
@ -97,20 +85,19 @@ static int probe(struct pci_dev *pdev, const struct pci_device_id *ent)
return drm_get_dev(pdev, ent, &driver); return drm_get_dev(pdev, ent, &driver);
} }
static int __init nouveau_init(void)
static int __init i830_init(void)
{ {
driver.num_ioctls = i830_max_ioctl; driver.num_ioctls = nouveau_max_ioctl;
return drm_init(&driver, pciidlist); return drm_init(&driver, pciidlist);
} }
static void __exit i830_exit(void) static void __exit nouveau_exit(void)
{ {
drm_exit(&driver); drm_exit(&driver);
} }
module_init(i830_init); module_init(nouveau_init);
module_exit(i830_exit); module_exit(nouveau_exit);
MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC); MODULE_DESCRIPTION(DRIVER_DESC);

1
linux-core/nouveau_drv.h Symbolic link
View file

@ -0,0 +1 @@
../shared-core/nouveau_drv.h

1
linux-core/nouveau_fifo.c Symbolic link
View file

@ -0,0 +1 @@
../shared-core/nouveau_fifo.c

View file

@ -0,0 +1,72 @@
/**
* \file mga_ioc32.c
*
* 32-bit ioctl compatibility routines for the MGA DRM.
*
* \author Dave Airlie <airlied@linux.ie> with code from patches by Egbert Eich
*
*
* Copyright (C) Paul Mackerras 2005
* Copyright (C) Egbert Eich 2003,2004
* Copyright (C) Dave Airlie 2005
* 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
* THE AUTHOR 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 <linux/compat.h>
#include "drmP.h"
#include "drm.h"
#include "nouveau_drm.h"
/**
* Called whenever a 32-bit process running under a 64-bit kernel
* performs an ioctl on /dev/dri/card<n>.
*
* \param filp file pointer.
* \param cmd command.
* \param arg user argument.
* \return zero on success or negative number on failure.
*/
long nouveau_compat_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg)
{
unsigned int nr = DRM_IOCTL_NR(cmd);
drm_ioctl_compat_t *fn = NULL;
int ret;
if (nr < DRM_COMMAND_BASE)
return drm_compat_ioctl(filp, cmd, arg);
#if 0
if (nr < DRM_COMMAND_BASE + DRM_ARRAY_SIZE(mga_compat_ioctls))
fn = nouveau_compat_ioctls[nr - DRM_COMMAND_BASE];
#endif
lock_kernel(); /* XXX for now */
if (fn != NULL)
ret = (*fn)(filp, cmd, arg);
else
ret = drm_ioctl(filp->f_dentry->d_inode, filp, cmd, arg);
unlock_kernel();
return ret;
}

1
linux-core/nouveau_irq.c Symbolic link
View file

@ -0,0 +1 @@
../shared-core/nouveau_irq.c

1
linux-core/nouveau_mem.c Symbolic link
View file

@ -0,0 +1 @@
../shared-core/nouveau_mem.c

1
linux-core/nouveau_object.c Symbolic link
View file

@ -0,0 +1 @@
../shared-core/nouveau_object.c

1
linux-core/nouveau_reg.h Symbolic link
View file

@ -0,0 +1 @@
../shared-core/nouveau_reg.h

1
linux-core/nouveau_state.c Symbolic link
View file

@ -0,0 +1 @@
../shared-core/nouveau_state.c

1
linux-core/nv04_fb.c Symbolic link
View file

@ -0,0 +1 @@
../shared-core/nv04_fb.c

1
linux-core/nv04_graph.c Symbolic link
View file

@ -0,0 +1 @@
../shared-core/nv04_graph.c

1
linux-core/nv04_mc.c Symbolic link
View file

@ -0,0 +1 @@
../shared-core/nv04_mc.c

Some files were not shown because too many files have changed in this diff Show more