Import DRM drivers, brought into shape by Yorick Hardy, posted to tech-x11.

Minor modifications by me:
-use an mi device major number
-(coarsly) divided into pci card specific and less specific parts, moved
 the latter to dev/drm
-renamed autoconf attributes to reflect this
Todo:
-adapt all card frontends but i915 to drm include file location
-review the mtrr change
-make the change to agp_i810.c coexist with the fix for buggy VESA
 BIOSes which is commented out temporarily
-RCS IDs etc style stuff
-LKM support (rescan support for vga)
-test
This commit is contained in:
drochner 2007-03-20 18:05:25 +00:00
parent f8ef9d1431
commit 2d9e04fc35
78 changed files with 48963 additions and 13 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: mtrr_i686.c,v 1.8 2006/11/16 01:32:39 christos Exp $ */
/* $NetBSD: mtrr_i686.c,v 1.9 2007/03/20 18:05:25 drochner Exp $ */
/*-
* Copyright (c) 2000 The NetBSD Foundation, Inc.
@ -37,7 +37,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: mtrr_i686.c,v 1.8 2006/11/16 01:32:39 christos Exp $");
__KERNEL_RCSID(0, "$NetBSD: mtrr_i686.c,v 1.9 2007/03/20 18:05:25 drochner Exp $");
#include "opt_multiprocessor.h"
@ -598,7 +598,8 @@ i686_mtrr_setone(struct mtrr *mtrrp, struct proc *p)
curhigh = curlow + mtrr_var[i].len;
if (low == curlow && high == curhigh &&
(!(mtrr_var[i].flags & MTRR_PRIVATE) ||
mtrr_var[i].owner == p->p_pid)) {
((mtrrp->flags & MTRR_PRIVATE) && (p != NULL) &&
(mtrr_var[i].owner == p->p_pid)))) {
freep = &mtrr_var[i];
break;
}
@ -606,7 +607,8 @@ i686_mtrr_setone(struct mtrr *mtrrp, struct proc *p)
(low >= curlow && low < curhigh)) &&
((mtrr_var[i].type != mtrrp->type) ||
((mtrr_var[i].flags & MTRR_PRIVATE) &&
mtrr_var[i].owner != p->p_pid))) {
(!(mtrrp->flags & MTRR_PRIVATE) || (p == NULL) ||
(mtrr_var[i].owner != p->p_pid))))) {
return EBUSY;
}
}
@ -614,7 +616,7 @@ i686_mtrr_setone(struct mtrr *mtrrp, struct proc *p)
return EBUSY;
mtrrp->flags &= ~MTRR_CANTSET;
*freep = *mtrrp;
freep->owner = mtrrp->flags & MTRR_PRIVATE ? p->p_pid : 0;
freep->owner = (mtrrp->flags & MTRR_PRIVATE) ? p->p_pid : 0;
return 0;
}

View File

@ -1,4 +1,4 @@
# $NetBSD: files,v 1.835 2007/03/17 06:41:36 dyoung Exp $
# $NetBSD: files,v 1.836 2007/03/20 18:05:25 drochner Exp $
# @(#)files.newconf 7.5 (Berkeley) 5/10/93
@ -963,6 +963,10 @@ file dev/ic/acpipmtimer.c acpipmtimer
device hpet
file dev/ic/hpet.c hpet needs-flag
# DRM - Direct Rendering Infrastructure: dev/drm
define drm {}
include dev/drm/files.drm
# Definitions for wscons
# device attributes: display, display with emulator, keyboard, and mouse
#
@ -990,7 +994,7 @@ defparam opt_vga.h VGA_CONSOLE_SCREENTYPE
defflag opt_vga.h VGA_CONSOLE_ATI_BROKEN_FONTSEL
defflag opt_vga.h VGA_RASTERCONSOLE
defflag opt_vga.h VGA_RESET
device vga: wsemuldisplaydev, pcdisplayops
device vga: wsemuldisplaydev, pcdisplayops, drm
file dev/ic/vga.c vga & !vga_rasterconsole needs-flag
file dev/ic/vga_raster.c vga_rasterconsole needs-flag
file dev/ic/vga_subr.c vga | vga_rasterconsole

713
sys/dev/drm/drm.h Normal file
View File

@ -0,0 +1,713 @@
/**
* \file drm.h
* Header for the Direct Rendering Manager
*
* \author Rickard E. (Rik) Faith <faith@valinux.com>
*
* \par Acknowledgments:
* Dec 1999, Richard Henderson <rth@twiddle.net>, move to generic \c cmpxchg.
*/
/*-
* 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.
*/
#include <sys/cdefs.h>
/*
__FBSDID("$FreeBSD: src/sys/dev/drm/drm.h,v 1.12 2006/05/17 06:36:28 anholt Exp $");
*/
/**
* \mainpage
*
* The Direct Rendering Manager (DRM) is a device-independent kernel-level
* device driver that provides support for the XFree86 Direct Rendering
* Infrastructure (DRI).
*
* The DRM supports the Direct Rendering Infrastructure (DRI) in four major
* ways:
* -# The DRM provides synchronized access to the graphics hardware via
* the use of an optimized two-tiered lock.
* -# The DRM enforces the DRI security policy for access to the graphics
* hardware by only allowing authenticated X11 clients access to
* restricted regions of memory.
* -# The DRM provides a generic DMA engine, complete with multiple
* queues and the ability to detect the need for an OpenGL context
* switch.
* -# The DRM is extensible via the use of small device-specific modules
* that rely extensively on the API exported by the DRM module.
*
*/
#ifndef _DRM_H_
#define _DRM_H_
#ifndef __user
#define __user
#endif
#ifdef __GNUC__
# define DEPRECATED __attribute__ ((deprecated))
#else
# define DEPRECATED
#endif
#if defined(__linux__)
#if defined(__KERNEL__)
#include <linux/config.h>
#endif
#include <asm/ioctl.h> /* For _IO* macros */
#define DRM_IOCTL_NR(n) _IOC_NR(n)
#define DRM_IOC_VOID _IOC_NONE
#define DRM_IOC_READ _IOC_READ
#define DRM_IOC_WRITE _IOC_WRITE
#define DRM_IOC_READWRITE _IOC_READ|_IOC_WRITE
#define DRM_IOC(dir, group, nr, size) _IOC(dir, group, nr, size)
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
#if (defined(__FreeBSD__) || defined(__FreeBSD_kernel__)) && defined(IN_MODULE)
/* Prevent name collision when including sys/ioccom.h */
#undef ioctl
#include <sys/ioccom.h>
#define ioctl(a,b,c) xf86ioctl(a,b,c)
#else
#include <sys/ioccom.h>
#endif /* __FreeBSD__ && xf86ioctl */
#define DRM_IOCTL_NR(n) ((n) & 0xff)
#define DRM_IOC_VOID IOC_VOID
#define DRM_IOC_READ IOC_OUT
#define DRM_IOC_WRITE IOC_IN
#define DRM_IOC_READWRITE IOC_INOUT
#define DRM_IOC(dir, group, nr, size) _IOC(dir, group, nr, size)
#endif
#define XFREE86_VERSION(major,minor,patch,snap) \
((major << 16) | (minor << 8) | patch)
#ifndef CONFIG_XFREE86_VERSION
#define CONFIG_XFREE86_VERSION XFREE86_VERSION(4,1,0,0)
#endif
#if CONFIG_XFREE86_VERSION < XFREE86_VERSION(4,1,0,0)
#define DRM_PROC_DEVICES "/proc/devices"
#define DRM_PROC_MISC "/proc/misc"
#define DRM_PROC_DRM "/proc/drm"
#define DRM_DEV_DRM "/dev/drm"
#define DRM_DEV_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP)
#define DRM_DEV_UID 0
#define DRM_DEV_GID 0
#endif
#if CONFIG_XFREE86_VERSION >= XFREE86_VERSION(4,1,0,0)
#ifdef __OpenBSD__
#define DRM_MAJOR 81
#endif
#if defined(__linux__) || defined(__NetBSD__)
#define DRM_MAJOR 226
#endif
#define DRM_MAX_MINOR 15
#endif
#define DRM_NAME "drm" /**< Name in kernel, /dev, and /proc */
#define DRM_MIN_ORDER 5 /**< At least 2^5 bytes = 32 bytes */
#define DRM_MAX_ORDER 22 /**< Up to 2^22 bytes = 4MB */
#define DRM_RAM_PERCENT 10 /**< How much system ram can we lock? */
#define _DRM_LOCK_HELD 0x80000000U /**< Hardware lock is held */
#define _DRM_LOCK_CONT 0x40000000U /**< Hardware lock is contended */
#define _DRM_LOCK_IS_HELD(lock) ((lock) & _DRM_LOCK_HELD)
#define _DRM_LOCK_IS_CONT(lock) ((lock) & _DRM_LOCK_CONT)
#define _DRM_LOCKING_CONTEXT(lock) ((lock) & ~(_DRM_LOCK_HELD|_DRM_LOCK_CONT))
#if defined(__linux__)
typedef unsigned int drm_handle_t;
#else
typedef unsigned long drm_handle_t; /**< To mapped regions */
#endif
typedef unsigned int drm_context_t; /**< GLXContext handle */
typedef unsigned int drm_drawable_t;
typedef unsigned int drm_magic_t; /**< Magic for authentication */
/**
* Cliprect.
*
* \warning If you change this structure, make sure you change
* XF86DRIClipRectRec in the server as well
*
* \note KW: Actually it's illegal to change either for
* backwards-compatibility reasons.
*/
typedef struct drm_clip_rect {
unsigned short x1;
unsigned short y1;
unsigned short x2;
unsigned short y2;
} drm_clip_rect_t;
/**
* Texture region,
*/
typedef struct drm_tex_region {
unsigned char next;
unsigned char prev;
unsigned char in_use;
unsigned char padding;
unsigned int age;
} drm_tex_region_t;
/**
* Hardware lock.
*
* The lock structure is a simple cache-line aligned integer. To avoid
* processor bus contention on a multiprocessor system, there should not be any
* other data stored in the same cache line.
*/
typedef struct drm_hw_lock {
__volatile__ unsigned int lock; /**< lock variable */
char padding[60]; /**< Pad to cache line */
} drm_hw_lock_t;
/* This is beyond ugly, and only works on GCC. However, it allows me to use
* drm.h in places (i.e., in the X-server) where I can't use size_t. The real
* fix is to use uint32_t instead of size_t, but that fix will break existing
* LP64 (i.e., PowerPC64, SPARC64, IA-64, Alpha, etc.) systems. That *will*
* eventually happen, though. I chose 'unsigned long' to be the fallback type
* because that works on all the platforms I know about. Hopefully, the
* real fix will happen before that bites us.
*/
#ifdef __SIZE_TYPE__
# define DRM_SIZE_T __SIZE_TYPE__
#else
# warning "__SIZE_TYPE__ not defined. Assuming sizeof(size_t) == sizeof(unsigned long)!"
# define DRM_SIZE_T unsigned long
#endif
/**
* DRM_IOCTL_VERSION ioctl argument type.
*
* \sa drmGetVersion().
*/
typedef struct drm_version {
int version_major; /**< Major version */
int version_minor; /**< Minor version */
int version_patchlevel; /**< Patch level */
DRM_SIZE_T name_len; /**< Length of name buffer */
char __user *name; /**< Name of driver */
DRM_SIZE_T date_len; /**< Length of date buffer */
char __user *date; /**< User-space buffer to hold date */
DRM_SIZE_T desc_len; /**< Length of desc buffer */
char __user *desc; /**< User-space buffer to hold desc */
} drm_version_t;
/**
* DRM_IOCTL_GET_UNIQUE ioctl argument type.
*
* \sa drmGetBusid() and drmSetBusId().
*/
typedef struct drm_unique {
DRM_SIZE_T unique_len; /**< Length of unique */
char __user *unique; /**< Unique name for driver instantiation */
} drm_unique_t;
#undef DRM_SIZE_T
typedef struct drm_list {
int count; /**< Length of user-space structures */
drm_version_t __user *version;
} drm_list_t;
typedef struct drm_block {
int unused;
} drm_block_t;
/**
* DRM_IOCTL_CONTROL ioctl argument type.
*
* \sa drmCtlInstHandler() and drmCtlUninstHandler().
*/
typedef struct drm_control {
enum {
DRM_ADD_COMMAND,
DRM_RM_COMMAND,
DRM_INST_HANDLER,
DRM_UNINST_HANDLER
} func;
int irq;
} drm_control_t;
/**
* Type of memory to map.
*/
typedef enum drm_map_type {
_DRM_FRAME_BUFFER = 0, /**< WC (no caching), no core dump */
_DRM_REGISTERS = 1, /**< no caching, no core dump */
_DRM_SHM = 2, /**< shared, cached */
_DRM_AGP = 3, /**< AGP/GART */
_DRM_SCATTER_GATHER = 4, /**< Scatter/gather memory for PCI DMA */
_DRM_CONSISTENT = 5 /**< Consistent memory for PCI DMA */
} drm_map_type_t;
/**
* Memory mapping flags.
*/
typedef enum drm_map_flags {
_DRM_RESTRICTED = 0x01, /**< Cannot be mapped to user-virtual */
_DRM_READ_ONLY = 0x02,
_DRM_LOCKED = 0x04, /**< shared, cached, locked */
_DRM_KERNEL = 0x08, /**< kernel requires access */
_DRM_WRITE_COMBINING = 0x10, /**< use write-combining if available */
_DRM_CONTAINS_LOCK = 0x20, /**< SHM page that contains lock */
_DRM_REMOVABLE = 0x40 /**< Removable mapping */
} drm_map_flags_t;
typedef struct drm_ctx_priv_map {
unsigned int ctx_id; /**< Context requesting private mapping */
void *handle; /**< Handle of map */
} drm_ctx_priv_map_t;
/**
* DRM_IOCTL_GET_MAP, DRM_IOCTL_ADD_MAP and DRM_IOCTL_RM_MAP ioctls
* argument type.
*
* \sa drmAddMap().
*/
typedef struct drm_map {
unsigned long offset; /**< Requested physical address (0 for SAREA)*/
unsigned long size; /**< Requested physical size (bytes) */
drm_map_type_t type; /**< Type of memory to map */
drm_map_flags_t flags; /**< Flags */
void *handle; /**< User-space: "Handle" to pass to mmap() */
/**< Kernel-space: kernel-virtual address */
int mtrr; /**< MTRR slot used */
/* Private data */
} drm_map_t;
/**
* DRM_IOCTL_GET_CLIENT ioctl argument type.
*/
typedef struct drm_client {
int idx; /**< Which client desired? */
int auth; /**< Is client authenticated? */
unsigned long pid; /**< Process ID */
unsigned long uid; /**< User ID */
unsigned long magic; /**< Magic */
unsigned long iocs; /**< Ioctl count */
} drm_client_t;
typedef enum {
_DRM_STAT_LOCK,
_DRM_STAT_OPENS,
_DRM_STAT_CLOSES,
_DRM_STAT_IOCTLS,
_DRM_STAT_LOCKS,
_DRM_STAT_UNLOCKS,
_DRM_STAT_VALUE, /**< Generic value */
_DRM_STAT_BYTE, /**< Generic byte counter (1024bytes/K) */
_DRM_STAT_COUNT, /**< Generic non-byte counter (1000/k) */
_DRM_STAT_IRQ, /**< IRQ */
_DRM_STAT_PRIMARY, /**< Primary DMA bytes */
_DRM_STAT_SECONDARY, /**< Secondary DMA bytes */
_DRM_STAT_DMA, /**< DMA */
_DRM_STAT_SPECIAL, /**< Special DMA (e.g., priority or polled) */
_DRM_STAT_MISSED /**< Missed DMA opportunity */
/* Add to the *END* of the list */
} drm_stat_type_t;
/**
* DRM_IOCTL_GET_STATS ioctl argument type.
*/
typedef struct drm_stats {
unsigned long count;
struct {
unsigned long value;
drm_stat_type_t type;
} data[15];
} drm_stats_t;
/**
* Hardware locking flags.
*/
typedef enum drm_lock_flags {
_DRM_LOCK_READY = 0x01, /**< Wait until hardware is ready for DMA */
_DRM_LOCK_QUIESCENT = 0x02, /**< Wait until hardware quiescent */
_DRM_LOCK_FLUSH = 0x04, /**< Flush this context's DMA queue first */
_DRM_LOCK_FLUSH_ALL = 0x08, /**< Flush all DMA queues first */
/* These *HALT* flags aren't supported yet
-- they will be used to support the
full-screen DGA-like mode. */
_DRM_HALT_ALL_QUEUES = 0x10, /**< Halt all current and future queues */
_DRM_HALT_CUR_QUEUES = 0x20 /**< Halt all current queues */
} drm_lock_flags_t;
/**
* DRM_IOCTL_LOCK, DRM_IOCTL_UNLOCK and DRM_IOCTL_FINISH ioctl argument type.
*
* \sa drmGetLock() and drmUnlock().
*/
typedef struct drm_lock {
int context;
drm_lock_flags_t flags;
} drm_lock_t;
/**
* DMA flags
*
* \warning
* These values \e must match xf86drm.h.
*
* \sa drm_dma.
*/
typedef enum drm_dma_flags {
/* Flags for DMA buffer dispatch */
_DRM_DMA_BLOCK = 0x01, /**<
* Block until buffer dispatched.
*
* \note The buffer may not yet have
* been processed by the hardware --
* getting a hardware lock with the
* hardware quiescent will ensure
* that the buffer has been
* processed.
*/
_DRM_DMA_WHILE_LOCKED = 0x02, /**< Dispatch while lock held */
_DRM_DMA_PRIORITY = 0x04, /**< High priority dispatch */
/* Flags for DMA buffer request */
_DRM_DMA_WAIT = 0x10, /**< Wait for free buffers */
_DRM_DMA_SMALLER_OK = 0x20, /**< Smaller-than-requested buffers OK */
_DRM_DMA_LARGER_OK = 0x40 /**< Larger-than-requested buffers OK */
} drm_dma_flags_t;
/**
* DRM_IOCTL_ADD_BUFS and DRM_IOCTL_MARK_BUFS ioctl argument type.
*
* \sa drmAddBufs().
*/
typedef struct drm_buf_desc {
int count; /**< Number of buffers of this size */
int size; /**< Size in bytes */
int low_mark; /**< Low water mark */
int high_mark; /**< High water mark */
enum {
_DRM_PAGE_ALIGN = 0x01, /**< Align on page boundaries for DMA */
_DRM_AGP_BUFFER = 0x02, /**< Buffer is in AGP space */
_DRM_SG_BUFFER = 0x04, /**< Scatter/gather memory buffer */
_DRM_FB_BUFFER = 0x08 /**< Buffer is in frame buffer */
} flags;
unsigned long agp_start; /**<
* Start address of where the AGP buffers are
* in the AGP aperture
*/
} drm_buf_desc_t;
/**
* DRM_IOCTL_INFO_BUFS ioctl argument type.
*/
typedef struct drm_buf_info {
int count; /**< Number of buffers described in list */
drm_buf_desc_t __user *list; /**< List of buffer descriptions */
} drm_buf_info_t;
/**
* DRM_IOCTL_FREE_BUFS ioctl argument type.
*/
typedef struct drm_buf_free {
int count;
int __user *list;
} drm_buf_free_t;
/**
* Buffer information
*
* \sa drm_buf_map.
*/
typedef struct drm_buf_pub {
int idx; /**< Index into the master buffer list */
int total; /**< Buffer size */
int used; /**< Amount of buffer in use (for DMA) */
void __user *address; /**< Address of buffer */
} drm_buf_pub_t;
/**
* DRM_IOCTL_MAP_BUFS ioctl argument type.
*/
typedef struct drm_buf_map {
int count; /**< Length of the buffer list */
#if defined(__cplusplus)
void __user *c_virtual;
#else
void __user *virtual; /**< Mmap'd area in user-virtual */
#endif
drm_buf_pub_t __user *list; /**< Buffer information */
} drm_buf_map_t;
/**
* DRM_IOCTL_DMA ioctl argument type.
*
* Indices here refer to the offset into the buffer list in drm_buf_get.
*
* \sa drmDMA().
*/
typedef struct drm_dma {
int context; /**< Context handle */
int send_count; /**< Number of buffers to send */
int __user *send_indices; /**< List of handles to buffers */
int __user *send_sizes; /**< Lengths of data to send */
drm_dma_flags_t flags; /**< Flags */
int request_count; /**< Number of buffers requested */
int request_size; /**< Desired size for buffers */
int __user *request_indices; /**< Buffer information */
int __user *request_sizes;
int granted_count; /**< Number of buffers granted */
} drm_dma_t;
typedef enum {
_DRM_CONTEXT_PRESERVED = 0x01,
_DRM_CONTEXT_2DONLY = 0x02
} drm_ctx_flags_t;
/**
* DRM_IOCTL_ADD_CTX ioctl argument type.
*
* \sa drmCreateContext() and drmDestroyContext().
*/
typedef struct drm_ctx {
drm_context_t handle;
drm_ctx_flags_t flags;
} drm_ctx_t;
/**
* DRM_IOCTL_RES_CTX ioctl argument type.
*/
typedef struct drm_ctx_res {
int count;
drm_ctx_t __user *contexts;
} drm_ctx_res_t;
/**
* DRM_IOCTL_ADD_DRAW and DRM_IOCTL_RM_DRAW ioctl argument type.
*/
typedef struct drm_draw {
drm_drawable_t handle;
} drm_draw_t;
/**
* DRM_IOCTL_GET_MAGIC and DRM_IOCTL_AUTH_MAGIC ioctl argument type.
*/
typedef struct drm_auth {
drm_magic_t magic;
} drm_auth_t;
/**
* DRM_IOCTL_IRQ_BUSID ioctl argument type.
*
* \sa drmGetInterruptFromBusID().
*/
typedef struct drm_irq_busid {
int irq; /**< IRQ number */
int busnum; /**< bus number */
int devnum; /**< device number */
int funcnum; /**< function number */
} drm_irq_busid_t;
typedef enum {
_DRM_VBLANK_ABSOLUTE = 0x0, /**< Wait for specific vblank sequence number */
_DRM_VBLANK_RELATIVE = 0x1, /**< Wait for given number of vblanks */
_DRM_VBLANK_SIGNAL = 0x40000000 /**< Send signal instead of blocking */
} drm_vblank_seq_type_t;
#define _DRM_VBLANK_FLAGS_MASK _DRM_VBLANK_SIGNAL
struct drm_wait_vblank_request {
drm_vblank_seq_type_t type;
unsigned int sequence;
unsigned long signal;
};
struct drm_wait_vblank_reply {
drm_vblank_seq_type_t type;
unsigned int sequence;
long tval_sec;
long tval_usec;
};
/**
* DRM_IOCTL_WAIT_VBLANK ioctl argument type.
*
* \sa drmWaitVBlank().
*/
typedef union drm_wait_vblank {
struct drm_wait_vblank_request request;
struct drm_wait_vblank_reply reply;
} drm_wait_vblank_t;
/**
* DRM_IOCTL_AGP_ENABLE ioctl argument type.
*
* \sa drmAgpEnable().
*/
typedef struct drm_agp_mode {
unsigned long mode; /**< AGP mode */
} drm_agp_mode_t;
/**
* DRM_IOCTL_AGP_ALLOC and DRM_IOCTL_AGP_FREE ioctls argument type.
*
* \sa drmAgpAlloc() and drmAgpFree().
*/
typedef struct drm_agp_buffer {
unsigned long size; /**< In bytes -- will round to page boundary */
unsigned long handle; /**< Used for binding / unbinding */
unsigned long type; /**< Type of memory to allocate */
unsigned long physical; /**< Physical used by i810 */
} drm_agp_buffer_t;
/**
* DRM_IOCTL_AGP_BIND and DRM_IOCTL_AGP_UNBIND ioctls argument type.
*
* \sa drmAgpBind() and drmAgpUnbind().
*/
typedef struct drm_agp_binding {
unsigned long handle; /**< From drm_agp_buffer */
unsigned long offset; /**< In bytes -- will round to page boundary */
} drm_agp_binding_t;
/**
* DRM_IOCTL_AGP_INFO ioctl argument type.
*
* \sa drmAgpVersionMajor(), drmAgpVersionMinor(), drmAgpGetMode(),
* drmAgpBase(), drmAgpSize(), drmAgpMemoryUsed(), drmAgpMemoryAvail(),
* drmAgpVendorId() and drmAgpDeviceId().
*/
typedef struct drm_agp_info {
int agp_version_major;
int agp_version_minor;
unsigned long mode;
unsigned long aperture_base; /**< physical address */
unsigned long aperture_size; /**< bytes */
unsigned long memory_allowed; /**< bytes */
unsigned long memory_used;
/** \name PCI information */
/*@{ */
unsigned short id_vendor;
unsigned short id_device;
/*@} */
} drm_agp_info_t;
/**
* DRM_IOCTL_SG_ALLOC ioctl argument type.
*/
typedef struct drm_scatter_gather {
unsigned long size; /**< In bytes -- will round to page boundary */
unsigned long handle; /**< Used for mapping / unmapping */
} drm_scatter_gather_t;
/**
* DRM_IOCTL_SET_VERSION ioctl argument type.
*/
typedef struct drm_set_version {
int drm_di_major;
int drm_di_minor;
int drm_dd_major;
int drm_dd_minor;
} drm_set_version_t;
/**
* \name Ioctls Definitions
*/
/*@{*/
#define DRM_IOCTL_BASE 'd'
#define DRM_IO(nr) _IO(DRM_IOCTL_BASE,nr)
#define DRM_IOR(nr,type) _IOR(DRM_IOCTL_BASE,nr,type)
#define DRM_IOW(nr,type) _IOW(DRM_IOCTL_BASE,nr,type)
#define DRM_IOWR(nr,type) _IOWR(DRM_IOCTL_BASE,nr,type)
#define DRM_IOCTL_VERSION DRM_IOWR(0x00, drm_version_t)
#define DRM_IOCTL_GET_UNIQUE DRM_IOWR(0x01, drm_unique_t)
#define DRM_IOCTL_GET_MAGIC DRM_IOR( 0x02, drm_auth_t)
#define DRM_IOCTL_IRQ_BUSID DRM_IOWR(0x03, drm_irq_busid_t)
#define DRM_IOCTL_GET_MAP DRM_IOWR(0x04, drm_map_t)
#define DRM_IOCTL_GET_CLIENT DRM_IOWR(0x05, drm_client_t)
#define DRM_IOCTL_GET_STATS DRM_IOR( 0x06, drm_stats_t)
#define DRM_IOCTL_SET_VERSION DRM_IOWR(0x07, drm_set_version_t)
#define DRM_IOCTL_SET_UNIQUE DRM_IOW( 0x10, drm_unique_t)
#define DRM_IOCTL_AUTH_MAGIC DRM_IOW( 0x11, drm_auth_t)
#define DRM_IOCTL_BLOCK DRM_IOWR(0x12, drm_block_t)
#define DRM_IOCTL_UNBLOCK DRM_IOWR(0x13, drm_block_t)
#define DRM_IOCTL_CONTROL DRM_IOW( 0x14, drm_control_t)
#define DRM_IOCTL_ADD_MAP DRM_IOWR(0x15, drm_map_t)
#define DRM_IOCTL_ADD_BUFS DRM_IOWR(0x16, drm_buf_desc_t)
#define DRM_IOCTL_MARK_BUFS DRM_IOW( 0x17, drm_buf_desc_t)
#define DRM_IOCTL_INFO_BUFS DRM_IOWR(0x18, drm_buf_info_t)
#define DRM_IOCTL_MAP_BUFS DRM_IOWR(0x19, drm_buf_map_t)
#define DRM_IOCTL_FREE_BUFS DRM_IOW( 0x1a, drm_buf_free_t)
#define DRM_IOCTL_RM_MAP DRM_IOW( 0x1b, drm_map_t)
#define DRM_IOCTL_SET_SAREA_CTX DRM_IOW( 0x1c, drm_ctx_priv_map_t)
#define DRM_IOCTL_GET_SAREA_CTX DRM_IOWR(0x1d, drm_ctx_priv_map_t)
#define DRM_IOCTL_ADD_CTX DRM_IOWR(0x20, drm_ctx_t)
#define DRM_IOCTL_RM_CTX DRM_IOWR(0x21, drm_ctx_t)
#define DRM_IOCTL_MOD_CTX DRM_IOW( 0x22, drm_ctx_t)
#define DRM_IOCTL_GET_CTX DRM_IOWR(0x23, drm_ctx_t)
#define DRM_IOCTL_SWITCH_CTX DRM_IOW( 0x24, drm_ctx_t)
#define DRM_IOCTL_NEW_CTX DRM_IOW( 0x25, drm_ctx_t)
#define DRM_IOCTL_RES_CTX DRM_IOWR(0x26, drm_ctx_res_t)
#define DRM_IOCTL_ADD_DRAW DRM_IOWR(0x27, drm_draw_t)
#define DRM_IOCTL_RM_DRAW DRM_IOWR(0x28, drm_draw_t)
#define DRM_IOCTL_DMA DRM_IOWR(0x29, drm_dma_t)
#define DRM_IOCTL_LOCK DRM_IOW( 0x2a, drm_lock_t)
#define DRM_IOCTL_UNLOCK DRM_IOW( 0x2b, drm_lock_t)
#define DRM_IOCTL_FINISH DRM_IOW( 0x2c, drm_lock_t)
#define DRM_IOCTL_AGP_ACQUIRE DRM_IO( 0x30)
#define DRM_IOCTL_AGP_RELEASE DRM_IO( 0x31)
#define DRM_IOCTL_AGP_ENABLE DRM_IOW( 0x32, drm_agp_mode_t)
#define DRM_IOCTL_AGP_INFO DRM_IOR( 0x33, drm_agp_info_t)
#define DRM_IOCTL_AGP_ALLOC DRM_IOWR(0x34, drm_agp_buffer_t)
#define DRM_IOCTL_AGP_FREE DRM_IOW( 0x35, drm_agp_buffer_t)
#define DRM_IOCTL_AGP_BIND DRM_IOW( 0x36, drm_agp_binding_t)
#define DRM_IOCTL_AGP_UNBIND DRM_IOW( 0x37, drm_agp_binding_t)
#define DRM_IOCTL_SG_ALLOC DRM_IOW( 0x38, drm_scatter_gather_t)
#define DRM_IOCTL_SG_FREE DRM_IOW( 0x39, drm_scatter_gather_t)
#define DRM_IOCTL_WAIT_VBLANK DRM_IOWR(0x3a, drm_wait_vblank_t)
/*@}*/
/**
* Device specific ioctls should only be in their respective headers
* The device specific ioctl range is from 0x40 to 0x79.
*
* \sa drmCommandNone(), drmCommandRead(), drmCommandWrite(), and
* drmCommandReadWrite().
*/
#define DRM_COMMAND_BASE 0x40
#endif

1111
sys/dev/drm/drmP.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,474 @@
/* drm_agpsupport.h -- DRM support for AGP/GART backend -*- linux-c -*-
* Created: Mon Dec 13 09:56:45 1999 by faith@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
* 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.
*
* Author:
* Rickard E. (Rik) Faith <faith@valinux.com>
* Gareth Hughes <gareth@valinux.com>
*
*/
#include <sys/cdefs.h>
/*
__FBSDID("$FreeBSD: src/sys/dev/drm/drm_agpsupport.c,v 1.5 2006/04/09 20:45:44 anholt Exp $");
*/
#include "drmP.h"
#ifdef __FreeBSD__
#include <pci/agpreg.h>
#include <dev/pci/pcireg.h>
#endif
/* Returns 1 if AGP or 0 if not. */
static int
drm_device_find_capability(drm_device_t *dev, int cap)
{
#ifdef __FreeBSD__
#if __FreeBSD_version >= 700010
return (pci_find_extcap(dev->device, cap, NULL) == 0);
#else
/* Code taken from agp.c. IWBNI that was a public interface. */
u_int32_t status;
u_int8_t ptr, next;
/*
* Check the CAP_LIST bit of the PCI status register first.
*/
status = pci_read_config(dev->device, PCIR_STATUS, 2);
if (!(status & 0x10))
return 0;
/*
* Traverse the capabilities list.
*/
for (ptr = pci_read_config(dev->device, AGP_CAPPTR, 1);
ptr != 0;
ptr = next) {
u_int32_t capid = pci_read_config(dev->device, ptr, 4);
next = AGP_CAPID_GET_NEXT_PTR(capid);
/*
* If this capability entry ID is cap, then we are done.
*/
if (AGP_CAPID_GET_CAP_ID(capid) == cap)
return 1;
}
return 0;
#endif
#else
#ifdef __NetBSD__
return pci_get_capability(dev->pa.pa_pc, dev->pa.pa_tag, cap,
NULL, NULL);
#endif
/* XXX: fill me in for non-FreeBSD */
return 1;
#endif
}
int drm_device_is_agp(drm_device_t *dev)
{
if (dev->driver.device_is_agp != NULL) {
int ret;
/* device_is_agp returns a tristate, 0 = not AGP, 1 = definitely
* AGP, 2 = fall back to PCI capability
*/
ret = (*dev->driver.device_is_agp)(dev);
if (ret != DRM_MIGHT_BE_AGP)
return ret;
}
return (drm_device_find_capability(dev, PCIY_AGP));
}
int drm_device_is_pcie(drm_device_t *dev)
{
return (drm_device_find_capability(dev, PCIY_EXPRESS));
}
int drm_agp_info(drm_device_t * dev, drm_agp_info_t *info)
{
struct agp_info *kern;
if (!dev->agp || !dev->agp->acquired)
return EINVAL;
kern = &dev->agp->info;
agp_get_info(dev->agp->agpdev, kern);
info->agp_version_major = 1;
info->agp_version_minor = 0;
info->mode = kern->ai_mode;
info->aperture_base = kern->ai_aperture_base;
info->aperture_size = kern->ai_aperture_size;
info->memory_allowed = kern->ai_memory_allowed;
info->memory_used = kern->ai_memory_used;
info->id_vendor = kern->ai_devid & 0xffff;
info->id_device = kern->ai_devid >> 16;
return 0;
}
int drm_agp_info_ioctl(DRM_IOCTL_ARGS)
{
int err;
drm_agp_info_t info;
DRM_DEVICE;
err = drm_agp_info(dev, &info);
if (err != 0)
return err;
*(drm_agp_info_t *) data = info;
return 0;
}
int drm_agp_acquire_ioctl(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
return drm_agp_acquire(dev);
}
int drm_agp_acquire(drm_device_t *dev)
{
int retcode;
if (!dev->agp || dev->agp->acquired)
return EINVAL;
retcode = agp_acquire(dev->agp->agpdev);
if (retcode)
return retcode;
dev->agp->acquired = 1;
return 0;
}
int drm_agp_release_ioctl(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
return drm_agp_release(dev);
}
int drm_agp_release(drm_device_t * dev)
{
if (!dev->agp || !dev->agp->acquired)
return EINVAL;
agp_release(dev->agp->agpdev);
dev->agp->acquired = 0;
return 0;
}
int drm_agp_enable(drm_device_t *dev, drm_agp_mode_t mode)
{
if (!dev->agp || !dev->agp->acquired)
return EINVAL;
dev->agp->mode = mode.mode;
agp_enable(dev->agp->agpdev, mode.mode);
dev->agp->base = dev->agp->info.ai_aperture_base;
dev->agp->enabled = 1;
return 0;
}
int drm_agp_enable_ioctl(DRM_IOCTL_ARGS)
{
drm_agp_mode_t mode;
DRM_DEVICE;
mode = *(drm_agp_mode_t *) data;
return drm_agp_enable(dev, mode);
}
int drm_agp_alloc(drm_device_t *dev, drm_agp_buffer_t *request)
{
drm_agp_mem_t *entry;
void *handle;
unsigned long pages;
u_int32_t type;
struct agp_memory_info info;
if (!dev->agp || !dev->agp->acquired)
return EINVAL;
entry = malloc(sizeof(*entry), M_DRM, M_NOWAIT | M_ZERO);
if (entry == NULL)
return ENOMEM;
pages = (request->size + PAGE_SIZE - 1) / PAGE_SIZE;
type = (u_int32_t) request->type;
DRM_UNLOCK();
handle = drm_agp_allocate_memory(pages, type);
DRM_LOCK();
if (handle == NULL) {
free(entry, M_DRM);
return ENOMEM;
}
entry->handle = handle;
entry->bound = 0;
entry->pages = pages;
entry->prev = NULL;
entry->next = dev->agp->memory;
if (dev->agp->memory)
dev->agp->memory->prev = entry;
dev->agp->memory = entry;
agp_memory_info(dev->agp->agpdev, entry->handle, &info);
request->handle = (unsigned long) entry->handle;
request->physical = info.ami_physical;
return 0;
}
int drm_agp_alloc_ioctl(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_agp_buffer_t request;
int retcode;
request = *(drm_agp_buffer_t *) data;
DRM_LOCK();
retcode = drm_agp_alloc(dev, &request);
DRM_UNLOCK();
*(drm_agp_buffer_t *) data = request;
return retcode;
}
static drm_agp_mem_t * drm_agp_lookup_entry(drm_device_t *dev, void *handle)
{
drm_agp_mem_t *entry;
for (entry = dev->agp->memory; entry; entry = entry->next) {
if (entry->handle == handle) return entry;
}
return NULL;
}
int drm_agp_unbind(drm_device_t *dev, drm_agp_binding_t *request)
{
drm_agp_mem_t *entry;
int retcode;
if (!dev->agp || !dev->agp->acquired)
return EINVAL;
entry = drm_agp_lookup_entry(dev, (void *)request->handle);
if (entry == NULL || !entry->bound)
return EINVAL;
DRM_UNLOCK();
retcode = drm_agp_unbind_memory(entry->handle);
DRM_LOCK();
if (retcode == 0)
entry->bound = 0;
return retcode;
}
int drm_agp_unbind_ioctl(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_agp_binding_t request;
int retcode;
request = *(drm_agp_binding_t *) data;
DRM_LOCK();
retcode = drm_agp_unbind(dev, &request);
DRM_UNLOCK();
return retcode;
}
int drm_agp_bind(drm_device_t *dev, drm_agp_binding_t *request)
{
drm_agp_mem_t *entry;
int retcode;
int page;
if (!dev->agp || !dev->agp->acquired)
return EINVAL;
DRM_DEBUG("agp_bind, page_size=%x\n", PAGE_SIZE);
entry = drm_agp_lookup_entry(dev, (void *)request->handle);
if (entry == NULL || entry->bound)
return EINVAL;
page = (request->offset + PAGE_SIZE - 1) / PAGE_SIZE;
DRM_UNLOCK();
retcode = drm_agp_bind_memory(entry->handle, page);
DRM_LOCK();
if (retcode == 0)
entry->bound = dev->agp->base + (page << PAGE_SHIFT);
return retcode;
}
int drm_agp_bind_ioctl(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_agp_binding_t request;
int retcode;
request = *(drm_agp_binding_t *) data;
DRM_LOCK();
retcode = drm_agp_bind(dev, &request);
DRM_UNLOCK();
return retcode;
}
int drm_agp_free(drm_device_t *dev, drm_agp_buffer_t *request)
{
drm_agp_mem_t *entry;
if (!dev->agp || !dev->agp->acquired)
return EINVAL;
entry = drm_agp_lookup_entry(dev, (void*)request->handle);
if (entry == NULL)
return EINVAL;
if (entry->prev)
entry->prev->next = entry->next;
else
dev->agp->memory = entry->next;
if (entry->next)
entry->next->prev = entry->prev;
DRM_UNLOCK();
if (entry->bound)
drm_agp_unbind_memory(entry->handle);
drm_agp_free_memory(entry->handle);
DRM_LOCK();
free(entry, M_DRM);
return 0;
}
int drm_agp_free_ioctl(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_agp_buffer_t request;
int retcode;
request = *(drm_agp_buffer_t *) data;
DRM_LOCK();
retcode = drm_agp_free(dev, &request);
DRM_UNLOCK();
return retcode;
}
drm_agp_head_t *drm_agp_init(void)
{
device_t agpdev;
drm_agp_head_t *head = NULL;
int agp_available = 1;
agpdev = DRM_AGP_FIND_DEVICE();
if (!agpdev)
agp_available = 0;
DRM_DEBUG("agp_available = %d\n", agp_available);
if (agp_available) {
head = malloc(sizeof(*head), M_DRM, M_NOWAIT | M_ZERO);
if (head == NULL)
return NULL;
head->agpdev = agpdev;
agp_get_info(agpdev, &head->info);
head->memory = NULL;
DRM_INFO("AGP at 0x%08lx %dMB\n",
(long)head->info.ai_aperture_base,
(int)(head->info.ai_aperture_size >> 20));
}
return head;
}
void *drm_agp_allocate_memory(size_t pages, u32 type)
{
device_t agpdev;
agpdev = DRM_AGP_FIND_DEVICE();
if (!agpdev)
return NULL;
return agp_alloc_memory(agpdev, type, pages << AGP_PAGE_SHIFT);
}
int drm_agp_free_memory(void *handle)
{
device_t agpdev;
agpdev = DRM_AGP_FIND_DEVICE();
if (!agpdev || !handle)
return 0;
agp_free_memory(agpdev, handle);
return 1;
}
int drm_agp_bind_memory(void *handle, off_t start)
{
device_t agpdev;
agpdev = DRM_AGP_FIND_DEVICE();
if (!agpdev || !handle)
return EINVAL;
return agp_bind_memory(agpdev, handle, start * PAGE_SIZE);
}
int drm_agp_unbind_memory(void *handle)
{
device_t agpdev;
agpdev = DRM_AGP_FIND_DEVICE();
if (!agpdev || !handle)
return EINVAL;
return agp_unbind_memory(agpdev, handle);
}

146
sys/dev/drm/drm_atomic.h Normal file
View File

@ -0,0 +1,146 @@
/**
* \file drm_atomic.h
* Atomic operations used in the DRM which may or may not be provided by the OS.
*
* \author Eric Anholt <anholt@FreeBSD.org>
*/
/*-
* Copyright 2004 Eric Anholt
* 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 <sys/cdefs.h>
/*
__FBSDID("$FreeBSD: src/sys/dev/drm/drm_atomic.h,v 1.2 2005/11/28 23:13:52 anholt Exp $");
*/
/* Many of these implementations are rather fake, but good enough. */
typedef u_int32_t atomic_t;
#ifdef __FreeBSD__
#define atomic_set(p, v) (*(p) = (v))
#define atomic_read(p) (*(p))
#define atomic_inc(p) atomic_add_int(p, 1)
#define atomic_dec(p) atomic_subtract_int(p, 1)
#define atomic_add(n, p) atomic_add_int(p, n)
#define atomic_sub(n, p) atomic_subtract_int(p, n)
#else /* __FreeBSD__ */
/* FIXME */
#define atomic_set(p, v) (*(p) = (v))
#define atomic_read(p) (*(p))
#define atomic_inc(p) (*(p) += 1)
#define atomic_dec(p) (*(p) -= 1)
#define atomic_add(n, p) (*(p) += (n))
#define atomic_sub(n, p) (*(p) -= (n))
/* FIXME */
#define atomic_add_int(p, v) *(p) += v
#define atomic_subtract_int(p, v) *(p) -= v
#define atomic_set_int(p, bits) *(p) |= (bits)
#define atomic_clear_int(p, bits) *(p) &= ~(bits)
#endif /* !__FreeBSD__ */
#if !defined(__FreeBSD_version) || (__FreeBSD_version < 500000)
#if defined(__i386__)
/* The extra atomic functions from 5.0 haven't been merged to 4.x */
static __inline int
atomic_cmpset_int(volatile u_int *dst, u_int exp, u_int src)
{
int res = exp;
__asm __volatile (
" lock ; "
" cmpxchgl %1,%2 ; "
" setz %%al ; "
" movzbl %%al,%0 ; "
"1: "
"# atomic_cmpset_int"
: "+a" (res) /* 0 (result) */
: "r" (src), /* 1 */
"m" (*(dst)) /* 2 */
: "memory");
return (res);
}
#else /* __i386__ */
static __inline int
atomic_cmpset_int(__volatile__ int *dst, int old, int new)
{
int s = splhigh();
if (*dst==old) {
*dst = new;
splx(s);
return 1;
}
splx(s);
return 0;
}
#endif /* !__i386__ */
#endif /* !__FreeBSD_version || __FreeBSD_version < 500000 */
static __inline atomic_t
test_and_set_bit(int b, volatile void *p)
{
int s = splhigh();
unsigned int m = 1<<b;
unsigned int r = *(volatile int *)p & m;
*(volatile int *)p |= m;
splx(s);
return r;
}
static __inline void
clear_bit(int b, volatile void *p)
{
atomic_clear_int(((volatile int *)p) + (b >> 5), 1 << (b & 0x1f));
}
static __inline void
set_bit(int b, volatile void *p)
{
atomic_set_int(((volatile int *)p) + (b >> 5), 1 << (b & 0x1f));
}
static __inline int
test_bit(int b, volatile void *p)
{
return ((volatile int *)p)[b >> 5] & (1 << (b & 0x1f));
}
static __inline int
find_first_zero_bit(volatile void *p, int maxbit)
{
int b;
volatile int *ptr = (volatile int *)p;
for (b = 0; b < maxbit; b += 32) {
if (ptr[b >> 5] != ~0) {
for (;;) {
if ((ptr[b >> 5] & (1 << (b & 0x1f))) == 0)
return b;
b++;
}
}
}
return maxbit;
}

181
sys/dev/drm/drm_auth.c Normal file
View File

@ -0,0 +1,181 @@
/* drm_auth.h -- IOCTLs for authentication -*- 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 <sys/cdefs.h>
/*
__FBSDID("$FreeBSD: src/sys/dev/drm/drm_auth.c,v 1.2 2005/11/28 23:13:52 anholt Exp $");
*/
#include "drmP.h"
static int drm_hash_magic(drm_magic_t magic)
{
return magic & (DRM_HASH_SIZE-1);
}
static drm_file_t *drm_find_file(drm_device_t *dev, drm_magic_t magic)
{
drm_file_t *retval = NULL;
drm_magic_entry_t *pt;
int hash;
hash = drm_hash_magic(magic);
DRM_LOCK();
for (pt = dev->magiclist[hash].head; pt; pt = pt->next) {
if (pt->magic == magic) {
retval = pt->priv;
break;
}
}
DRM_UNLOCK();
return retval;
}
static int drm_add_magic(drm_device_t *dev, drm_file_t *priv, drm_magic_t magic)
{
int hash;
drm_magic_entry_t *entry;
DRM_DEBUG("%d\n", magic);
hash = drm_hash_magic(magic);
entry = malloc(sizeof(*entry), M_DRM, M_ZERO | M_NOWAIT);
if (!entry) return DRM_ERR(ENOMEM);
entry->magic = magic;
entry->priv = priv;
entry->next = NULL;
DRM_LOCK();
if (dev->magiclist[hash].tail) {
dev->magiclist[hash].tail->next = entry;
dev->magiclist[hash].tail = entry;
} else {
dev->magiclist[hash].head = entry;
dev->magiclist[hash].tail = entry;
}
DRM_UNLOCK();
return 0;
}
static int drm_remove_magic(drm_device_t *dev, drm_magic_t magic)
{
drm_magic_entry_t *prev = NULL;
drm_magic_entry_t *pt;
int hash;
DRM_DEBUG("%d\n", magic);
hash = drm_hash_magic(magic);
DRM_LOCK();
for (pt = dev->magiclist[hash].head; pt; prev = pt, pt = pt->next) {
if (pt->magic == magic) {
if (dev->magiclist[hash].head == pt) {
dev->magiclist[hash].head = pt->next;
}
if (dev->magiclist[hash].tail == pt) {
dev->magiclist[hash].tail = prev;
}
if (prev) {
prev->next = pt->next;
}
DRM_UNLOCK();
return 0;
}
}
DRM_UNLOCK();
free(pt, M_DRM);
return DRM_ERR(EINVAL);
}
int drm_getmagic(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
static drm_magic_t sequence = 0;
drm_auth_t auth;
drm_file_t *priv;
DRM_LOCK();
#ifdef __FreeBSD__
priv = drm_find_file_by_proc(dev, p);
#elif defined(__NetBSD__)
priv = drm_find_file_by_proc(dev, p->l_proc);
#endif
DRM_UNLOCK();
if (priv == NULL) {
DRM_ERROR("can't find authenticator\n");
return EINVAL;
}
/* Find unique magic */
if (priv->magic) {
auth.magic = priv->magic;
} else {
do {
int old = sequence;
auth.magic = old+1;
if (!atomic_cmpset_int(&sequence, old, auth.magic))
continue;
} while (drm_find_file(dev, auth.magic));
priv->magic = auth.magic;
drm_add_magic(dev, priv, auth.magic);
}
DRM_DEBUG("%u\n", auth.magic);
DRM_COPY_TO_USER_IOCTL((drm_auth_t *)data, auth, sizeof(auth));
return 0;
}
int drm_authmagic(DRM_IOCTL_ARGS)
{
drm_auth_t auth;
drm_file_t *file;
DRM_DEVICE;
DRM_COPY_FROM_USER_IOCTL(auth, (drm_auth_t *)data, sizeof(auth));
DRM_DEBUG("%u\n", auth.magic);
if ((file = drm_find_file(dev, auth.magic))) {
file->authenticated = 1;
drm_remove_magic(dev, auth.magic);
return 0;
}
return DRM_ERR(EINVAL);
}

1156
sys/dev/drm/drm_bufs.c Normal file

File diff suppressed because it is too large Load Diff

350
sys/dev/drm/drm_context.c Normal file
View File

@ -0,0 +1,350 @@
/* drm_context.h -- IOCTLs for generic contexts -*- linux-c -*-
* Created: Fri Nov 24 18:31:37 2000 by gareth@valinux.com
*/
/*-
* Copyright 1999, 2000 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 <sys/cdefs.h>
/*
__FBSDID("$FreeBSD: src/sys/dev/drm/drm_context.c,v 1.2 2005/11/28 23:13:52 anholt Exp $");
*/
#include "drmP.h"
/* ================================================================
* Context bitmap support
*/
void drm_ctxbitmap_free(drm_device_t *dev, int ctx_handle)
{
if (ctx_handle < 0 || ctx_handle >= DRM_MAX_CTXBITMAP ||
dev->ctx_bitmap == NULL) {
DRM_ERROR("Attempt to free invalid context handle: %d\n",
ctx_handle);
return;
}
DRM_LOCK();
clear_bit(ctx_handle, dev->ctx_bitmap);
dev->context_sareas[ctx_handle] = NULL;
DRM_UNLOCK();
return;
}
int drm_ctxbitmap_next(drm_device_t *dev)
{
int bit;
if (dev->ctx_bitmap == NULL)
return -1;
DRM_LOCK();
bit = find_first_zero_bit( dev->ctx_bitmap, DRM_MAX_CTXBITMAP );
if (bit >= DRM_MAX_CTXBITMAP) {
DRM_UNLOCK();
return -1;
}
set_bit(bit, dev->ctx_bitmap);
DRM_DEBUG("drm_ctxbitmap_next bit : %d\n", bit);
if ((bit+1) > dev->max_context) {
dev->max_context = (bit+1);
if (dev->context_sareas != NULL) {
drm_local_map_t **ctx_sareas;
ctx_sareas = realloc(dev->context_sareas,
dev->max_context * sizeof(*dev->context_sareas),
M_DRM, M_NOWAIT);
if (ctx_sareas == NULL) {
clear_bit(bit, dev->ctx_bitmap);
DRM_UNLOCK();
return -1;
}
dev->context_sareas = ctx_sareas;
dev->context_sareas[bit] = NULL;
} else {
/* max_context == 1 at this point */
dev->context_sareas = malloc(dev->max_context *
sizeof(*dev->context_sareas), M_DRM, M_NOWAIT);
if (dev->context_sareas == NULL) {
clear_bit(bit, dev->ctx_bitmap);
DRM_UNLOCK();
return -1;
}
dev->context_sareas[bit] = NULL;
}
}
DRM_UNLOCK();
return bit;
}
int drm_ctxbitmap_init(drm_device_t *dev)
{
int i;
int temp;
DRM_LOCK();
dev->ctx_bitmap = malloc(PAGE_SIZE, M_DRM, M_NOWAIT | M_ZERO);
if ( dev->ctx_bitmap == NULL ) {
DRM_UNLOCK();
return DRM_ERR(ENOMEM);
}
dev->context_sareas = NULL;
dev->max_context = -1;
DRM_UNLOCK();
for ( i = 0 ; i < DRM_RESERVED_CONTEXTS ; i++ ) {
temp = drm_ctxbitmap_next(dev);
DRM_DEBUG( "drm_ctxbitmap_init : %d\n", temp );
}
return 0;
}
void drm_ctxbitmap_cleanup(drm_device_t *dev)
{
DRM_LOCK();
if (dev->context_sareas != NULL)
free(dev->context_sareas, M_DRM);
free(dev->ctx_bitmap, M_DRM);
DRM_UNLOCK();
}
/* ================================================================
* Per Context SAREA Support
*/
int drm_getsareactx( DRM_IOCTL_ARGS )
{
DRM_DEVICE;
drm_ctx_priv_map_t request;
drm_local_map_t *map;
DRM_COPY_FROM_USER_IOCTL( request, (drm_ctx_priv_map_t *)data,
sizeof(request) );
DRM_LOCK();
if (dev->max_context < 0 || request.ctx_id >= (unsigned) dev->max_context) {
DRM_UNLOCK();
return DRM_ERR(EINVAL);
}
map = dev->context_sareas[request.ctx_id];
DRM_UNLOCK();
request.handle = map->handle;
DRM_COPY_TO_USER_IOCTL( (drm_ctx_priv_map_t *)data, request, sizeof(request) );
return 0;
}
int drm_setsareactx( DRM_IOCTL_ARGS )
{
DRM_DEVICE;
drm_ctx_priv_map_t request;
drm_local_map_t *map = NULL;
DRM_COPY_FROM_USER_IOCTL( request, (drm_ctx_priv_map_t *)data,
sizeof(request) );
DRM_LOCK();
TAILQ_FOREACH(map, &dev->maplist, link) {
if (map->handle == request.handle) {
if (dev->max_context < 0)
goto bad;
if (request.ctx_id >= (unsigned) dev->max_context)
goto bad;
dev->context_sareas[request.ctx_id] = map;
DRM_UNLOCK();
return 0;
}
}
bad:
DRM_UNLOCK();
return DRM_ERR(EINVAL);
}
/* ================================================================
* The actual DRM context handling routines
*/
int drm_context_switch(drm_device_t *dev, int old, int new)
{
if ( test_and_set_bit( 0, &dev->context_flag ) ) {
DRM_ERROR( "Reentering -- FIXME\n" );
return DRM_ERR(EBUSY);
}
DRM_DEBUG( "Context switch from %d to %d\n", old, new );
if ( new == dev->last_context ) {
clear_bit( 0, &dev->context_flag );
return 0;
}
return 0;
}
int drm_context_switch_complete(drm_device_t *dev, int new)
{
dev->last_context = new; /* PRE/POST: This is the _only_ writer. */
if ( !_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) ) {
DRM_ERROR( "Lock isn't held after context switch\n" );
}
/* If a context switch is ever initiated
when the kernel holds the lock, release
that lock here. */
clear_bit( 0, &dev->context_flag );
return 0;
}
int drm_resctx(DRM_IOCTL_ARGS)
{
drm_ctx_res_t res;
drm_ctx_t ctx;
int i;
DRM_COPY_FROM_USER_IOCTL( res, (drm_ctx_res_t *)data, sizeof(res) );
if ( res.count >= DRM_RESERVED_CONTEXTS ) {
bzero(&ctx, sizeof(ctx));
for ( i = 0 ; i < DRM_RESERVED_CONTEXTS ; i++ ) {
ctx.handle = i;
if ( DRM_COPY_TO_USER( &res.contexts[i],
&ctx, sizeof(ctx) ) )
return DRM_ERR(EFAULT);
}
}
res.count = DRM_RESERVED_CONTEXTS;
DRM_COPY_TO_USER_IOCTL( (drm_ctx_res_t *)data, res, sizeof(res) );
return 0;
}
int drm_addctx(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_ctx_t ctx;
DRM_COPY_FROM_USER_IOCTL( ctx, (drm_ctx_t *)data, sizeof(ctx) );
ctx.handle = drm_ctxbitmap_next(dev);
if ( ctx.handle == DRM_KERNEL_CONTEXT ) {
/* Skip kernel's context and get a new one. */
ctx.handle = drm_ctxbitmap_next(dev);
}
DRM_DEBUG( "%d\n", ctx.handle );
if ( ctx.handle == -1 ) {
DRM_DEBUG( "Not enough free contexts.\n" );
/* Should this return -EBUSY instead? */
return DRM_ERR(ENOMEM);
}
if (dev->driver.context_ctor && ctx.handle != DRM_KERNEL_CONTEXT) {
DRM_LOCK();
dev->driver.context_ctor(dev, ctx.handle);
DRM_UNLOCK();
}
DRM_COPY_TO_USER_IOCTL( (drm_ctx_t *)data, ctx, sizeof(ctx) );
return 0;
}
int drm_modctx(DRM_IOCTL_ARGS)
{
/* This does nothing */
return 0;
}
int drm_getctx(DRM_IOCTL_ARGS)
{
drm_ctx_t ctx;
DRM_COPY_FROM_USER_IOCTL( ctx, (drm_ctx_t *)data, sizeof(ctx) );
/* This is 0, because we don't handle any context flags */
ctx.flags = 0;
DRM_COPY_TO_USER_IOCTL( (drm_ctx_t *)data, ctx, sizeof(ctx) );
return 0;
}
int drm_switchctx(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_ctx_t ctx;
DRM_COPY_FROM_USER_IOCTL( ctx, (drm_ctx_t *)data, sizeof(ctx) );
DRM_DEBUG( "%d\n", ctx.handle );
return drm_context_switch(dev, dev->last_context, ctx.handle);
}
int drm_newctx(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_ctx_t ctx;
DRM_COPY_FROM_USER_IOCTL( ctx, (drm_ctx_t *)data, sizeof(ctx) );
DRM_DEBUG( "%d\n", ctx.handle );
drm_context_switch_complete(dev, ctx.handle);
return 0;
}
int drm_rmctx(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_ctx_t ctx;
DRM_COPY_FROM_USER_IOCTL( ctx, (drm_ctx_t *)data, sizeof(ctx) );
DRM_DEBUG( "%d\n", ctx.handle );
if ( ctx.handle != DRM_KERNEL_CONTEXT ) {
if (dev->driver.context_dtor) {
DRM_LOCK();
dev->driver.context_dtor(dev, ctx.handle);
DRM_UNLOCK();
}
drm_ctxbitmap_free(dev, ctx.handle);
}
return 0;
}

135
sys/dev/drm/drm_dma.c Normal file
View File

@ -0,0 +1,135 @@
/* drm_dma.c -- DMA IOCTL and function support -*- linux-c -*-
* Created: Fri Mar 19 14:30:16 1999 by faith@valinux.com
*/
/*-
* Copyright 1999, 2000 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 <sys/cdefs.h>
/*
__FBSDID("$FreeBSD: src/sys/dev/drm/drm_dma.c,v 1.2 2005/11/28 23:13:52 anholt Exp $");
*/
#include "drmP.h"
int drm_dma_setup(drm_device_t *dev)
{
dev->dma = malloc(sizeof(*dev->dma), M_DRM, M_NOWAIT | M_ZERO);
if (dev->dma == NULL)
return DRM_ERR(ENOMEM);
DRM_SPININIT(dev->dma_lock, "drmdma");
return 0;
}
void drm_dma_takedown(drm_device_t *dev)
{
drm_device_dma_t *dma = dev->dma;
int i, j;
if (dma == NULL)
return;
/* Clear dma buffers */
for (i = 0; i <= DRM_MAX_ORDER; i++) {
if (dma->bufs[i].seg_count) {
DRM_DEBUG("order %d: buf_count = %d,"
" seg_count = %d\n",
i,
dma->bufs[i].buf_count,
dma->bufs[i].seg_count);
for (j = 0; j < dma->bufs[i].seg_count; j++) {
drm_pci_free(dev, dma->bufs[i].seglist[j]);
}
free(dma->bufs[i].seglist, M_DRM);
}
if (dma->bufs[i].buf_count) {
for (j = 0; j < dma->bufs[i].buf_count; j++) {
free(dma->bufs[i].buflist[j].dev_private,
M_DRM);
}
free(dma->bufs[i].buflist, M_DRM);
}
}
free(dma->buflist, M_DRM);
free(dma->pagelist, M_DRM);
free(dev->dma, M_DRM);
dev->dma = NULL;
DRM_SPINUNINIT(dev->dma_lock);
}
void drm_free_buffer(drm_device_t *dev, drm_buf_t *buf)
{
if (!buf) return;
buf->pending = 0;
buf->filp = NULL;
buf->used = 0;
}
void drm_reclaim_buffers(drm_device_t *dev, DRMFILE filp)
{
drm_device_dma_t *dma = dev->dma;
int i;
if (!dma) return;
for (i = 0; i < dma->buf_count; i++) {
if (dma->buflist[i]->filp == filp) {
switch (dma->buflist[i]->list) {
case DRM_LIST_NONE:
drm_free_buffer(dev, dma->buflist[i]);
break;
case DRM_LIST_WAIT:
dma->buflist[i]->list = DRM_LIST_RECLAIM;
break;
default:
/* Buffer already on hardware. */
break;
}
}
}
}
/* Call into the driver-specific DMA handler */
int drm_dma(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
if (dev->driver.dma_ioctl) {
return dev->driver.dma_ioctl(kdev, cmd, data, flags, p, filp);
} else {
DRM_DEBUG("DMA ioctl on driver with no dma handler\n");
return EINVAL;
}
}

View File

@ -0,0 +1,56 @@
/* 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 <sys/cdefs.h>
/*
__FBSDID("$FreeBSD: src/sys/dev/drm/drm_drawable.c,v 1.2 2005/11/28 23:13:52 anholt Exp $");
*/
#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 */
}

1056
sys/dev/drm/drm_drv.c Normal file

File diff suppressed because it is too large Load Diff

139
sys/dev/drm/drm_fops.c Normal file
View File

@ -0,0 +1,139 @@
/* drm_fops.h -- File operations for DRM -*- linux-c -*-
* Created: Mon Jan 4 08:58:31 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>
* Daryll Strauss <daryll@valinux.com>
* Gareth Hughes <gareth@valinux.com>
*
*/
#include <sys/cdefs.h>
/*
__FBSDID("$FreeBSD: src/sys/dev/drm/drm_fops.c,v 1.2 2005/11/28 23:13:52 anholt Exp $");
*/
#include "drmP.h"
drm_file_t *drm_find_file_by_proc(drm_device_t *dev, DRM_STRUCTPROC *p)
{
#if __FreeBSD_version >= 500021
uid_t uid = p->td_ucred->cr_svuid;
pid_t pid = p->td_proc->p_pid;
#elif defined(__NetBSD__)
uid_t uid = kauth_cred_getsvuid(p->p_cred);
pid_t pid = p->p_pid;
#else
uid_t uid = p->p_cred->p_svuid;
pid_t pid = p->p_pid;
#endif
drm_file_t *priv;
DRM_SPINLOCK_ASSERT(&dev->dev_lock);
TAILQ_FOREACH(priv, &dev->files, link)
if (priv->pid == pid && priv->uid == uid)
return priv;
return NULL;
}
/* drm_open_helper is called whenever a process opens /dev/drm. */
int drm_open_helper(DRM_CDEV kdev, int flags, int fmt, DRM_STRUCTPROC *p,
drm_device_t *dev)
{
int m = minor(kdev);
drm_file_t *priv;
int retcode;
if (flags & O_EXCL)
return EBUSY; /* No exclusive opens */
dev->flags = flags;
DRM_DEBUG("pid = %d, minor = %d\n", DRM_CURRENTPID, m);
DRM_LOCK();
priv = drm_find_file_by_proc(dev, p);
if (priv) {
priv->refs++;
} else {
priv = malloc(sizeof(*priv), M_DRM, M_NOWAIT | M_ZERO);
if (priv == NULL) {
DRM_UNLOCK();
return DRM_ERR(ENOMEM);
}
#if __FreeBSD_version >= 500000
priv->uid = p->td_ucred->cr_svuid;
priv->pid = p->td_proc->p_pid;
#elif defined(__NetBSD__)
priv->uid = kauth_cred_getsvuid(p->p_cred);
priv->pid = p->p_pid;
#else
priv->uid = p->p_cred->p_svuid;
priv->pid = p->p_pid;
#endif
priv->refs = 1;
priv->minor = m;
priv->ioctl_count = 0;
/* for compatibility root is always authenticated */
priv->authenticated = DRM_SUSER(p);
if (dev->driver.open) {
retcode = dev->driver.open(dev, priv);
if (retcode != 0) {
free(priv, M_DRM);
DRM_UNLOCK();
return retcode;
}
}
/* first opener automatically becomes master */
priv->master = TAILQ_EMPTY(&dev->files);
TAILQ_INSERT_TAIL(&dev->files, priv, link);
}
DRM_UNLOCK();
#ifdef __FreeBSD__
kdev->si_drv1 = dev;
#endif
return 0;
}
/* The drm_read and drm_poll are stubs to prevent spurious errors
* on older X Servers (4.3.0 and earlier) */
int drm_read(DRM_CDEV kdev, struct uio *uio, int ioflag)
{
return 0;
}
int drm_poll(DRM_CDEV kdev, int events, DRM_STRUCTCDEVPROC *p)
{
return 0;
}

306
sys/dev/drm/drm_ioctl.c Normal file
View File

@ -0,0 +1,306 @@
/* drm_ioctl.h -- IOCTL processing for DRM -*- linux-c -*-
* Created: Fri Jan 8 09:01:26 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 <sys/cdefs.h>
/*
__FBSDID("$FreeBSD: src/sys/dev/drm/drm_ioctl.c,v 1.2 2005/11/28 23:13:52 anholt Exp $");
*/
#include "drmP.h"
/*
* Beginning in revision 1.1 of the DRM interface, getunique will return
* a unique in the form pci:oooo:bb:dd.f (o=domain, b=bus, d=device, f=function)
* before setunique has been called. The format for the bus-specific part of
* the unique is not defined for any other bus.
*/
int drm_getunique(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_unique_t u;
DRM_COPY_FROM_USER_IOCTL( u, (drm_unique_t *)data, sizeof(u) );
if (u.unique_len >= dev->unique_len) {
if (DRM_COPY_TO_USER(u.unique, dev->unique, dev->unique_len))
return DRM_ERR(EFAULT);
}
u.unique_len = dev->unique_len;
DRM_COPY_TO_USER_IOCTL( (drm_unique_t *)data, u, sizeof(u) );
return 0;
}
/* Deprecated in DRM version 1.1, and will return EBUSY when setversion has
* requested version 1.1 or greater.
*/
int drm_setunique(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_unique_t u;
int domain = 0, bus = 0, slot = 0, func = 0, ret = 0;
char *busid;
#ifdef __NetBSD__
return EOPNOTSUPP;
#endif
DRM_COPY_FROM_USER_IOCTL( u, (drm_unique_t *)data, sizeof(u) );
/* Check and copy in the submitted Bus ID */
if (!u.unique_len || u.unique_len > 1024)
return DRM_ERR(EINVAL);
busid = malloc(u.unique_len + 1, M_DRM, M_WAITOK);
if (busid == NULL)
return DRM_ERR(ENOMEM);
if (DRM_COPY_FROM_USER(busid, u.unique, u.unique_len)) {
free(busid, M_DRM);
return DRM_ERR(EFAULT);
}
busid[u.unique_len] = '\0';
/* Return error if the busid submitted doesn't match the device's actual
* busid.
*/
#ifdef __FreeBSD__
ret = sscanf(busid, "PCI:%d:%d:%d", &bus, &slot, &func);
#endif
if (ret != 3) {
free(busid, M_DRM);
return DRM_ERR(EINVAL);
}
domain = bus >> 8;
bus &= 0xff;
if ((domain != dev->pci_domain) ||
(bus != dev->pci_bus) ||
(slot != dev->pci_slot) ||
(func != dev->pci_func)) {
free(busid, M_DRM);
return DRM_ERR(EINVAL);
}
/* Actually set the device's busid now. */
DRM_LOCK();
if (dev->unique_len || dev->unique) {
DRM_UNLOCK();
return DRM_ERR(EBUSY);
}
dev->unique_len = u.unique_len;
dev->unique = busid;
DRM_UNLOCK();
return 0;
}
static int
drm_set_busid(drm_device_t *dev)
{
DRM_LOCK();
if (dev->unique != NULL) {
DRM_UNLOCK();
return EBUSY;
}
dev->unique_len = 20;
dev->unique = malloc(dev->unique_len + 1, M_DRM, M_NOWAIT);
if (dev->unique == NULL) {
DRM_UNLOCK();
return ENOMEM;
}
snprintf(dev->unique, dev->unique_len, "pci:%04x:%02x:%02x.%1x",
dev->pci_domain, dev->pci_bus, dev->pci_slot, dev->pci_func);
DRM_UNLOCK();
return 0;
}
int drm_getmap(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_map_t map;
drm_local_map_t *mapinlist;
int idx;
int i = 0;
DRM_COPY_FROM_USER_IOCTL( map, (drm_map_t *)data, sizeof(map) );
idx = map.offset;
DRM_LOCK();
if (idx < 0) {
DRM_UNLOCK();
return DRM_ERR(EINVAL);
}
TAILQ_FOREACH(mapinlist, &dev->maplist, link) {
if (i==idx) {
map.offset = mapinlist->offset;
map.size = mapinlist->size;
map.type = mapinlist->type;
map.flags = mapinlist->flags;
map.handle = mapinlist->handle;
map.mtrr = mapinlist->mtrr;
break;
}
i++;
}
DRM_UNLOCK();
if (mapinlist == NULL)
return EINVAL;
DRM_COPY_TO_USER_IOCTL( (drm_map_t *)data, map, sizeof(map) );
return 0;
}
int drm_getclient(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_client_t client;
drm_file_t *pt;
int idx;
int i = 0;
DRM_COPY_FROM_USER_IOCTL( client, (drm_client_t *)data, sizeof(client) );
idx = client.idx;
DRM_LOCK();
TAILQ_FOREACH(pt, &dev->files, link) {
if (i==idx)
{
client.auth = pt->authenticated;
client.pid = pt->pid;
client.uid = pt->uid;
client.magic = pt->magic;
client.iocs = pt->ioctl_count;
DRM_UNLOCK();
*(drm_client_t *)data = client;
return 0;
}
i++;
}
DRM_UNLOCK();
DRM_COPY_TO_USER_IOCTL( (drm_client_t *)data, client, sizeof(client) );
return 0;
}
int drm_getstats(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_stats_t stats;
int i;
memset(&stats, 0, sizeof(stats));
DRM_LOCK();
for (i = 0; i < dev->counters; i++) {
if (dev->types[i] == _DRM_STAT_LOCK)
stats.data[i].value
= (dev->lock.hw_lock
? dev->lock.hw_lock->lock : 0);
else
stats.data[i].value = atomic_read(&dev->counts[i]);
stats.data[i].type = dev->types[i];
}
stats.count = dev->counters;
DRM_UNLOCK();
DRM_COPY_TO_USER_IOCTL( (drm_stats_t *)data, stats, sizeof(stats) );
return 0;
}
#define DRM_IF_MAJOR 1
#define DRM_IF_MINOR 2
int drm_setversion(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_set_version_t sv;
drm_set_version_t retv;
int if_version;
DRM_COPY_FROM_USER_IOCTL(sv, (drm_set_version_t *)data, sizeof(sv));
retv.drm_di_major = DRM_IF_MAJOR;
retv.drm_di_minor = DRM_IF_MINOR;
retv.drm_dd_major = dev->driver.major;
retv.drm_dd_minor = dev->driver.minor;
DRM_COPY_TO_USER_IOCTL((drm_set_version_t *)data, retv, sizeof(sv));
if (sv.drm_di_major != -1) {
if (sv.drm_di_major != DRM_IF_MAJOR ||
sv.drm_di_minor < 0 || sv.drm_di_minor > DRM_IF_MINOR)
return EINVAL;
if_version = DRM_IF_VERSION(sv.drm_di_major, sv.drm_dd_minor);
dev->if_version = DRM_MAX(if_version, dev->if_version);
if (sv.drm_di_minor >= 1) {
/*
* Version 1.1 includes tying of DRM to specific device
*/
drm_set_busid(dev);
}
}
if (sv.drm_dd_major != -1) {
if (sv.drm_dd_major != dev->driver.major ||
sv.drm_dd_minor < 0 || sv.drm_dd_minor > dev->driver.minor)
return EINVAL;
}
return 0;
}
int drm_noop(DRM_IOCTL_ARGS)
{
DRM_DEBUG("\n");
return 0;
}

314
sys/dev/drm/drm_irq.c Normal file
View File

@ -0,0 +1,314 @@
/* drm_irq.c -- IRQ IOCTL and function support
* Created: Fri Oct 18 2003 by anholt@FreeBSD.org
*/
/*-
* Copyright 2003 Eric Anholt
* 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
* ERIC ANHOLT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* Authors:
* Eric Anholt <anholt@FreeBSD.org>
*
*/
#include <sys/cdefs.h>
/*
__FBSDID("$FreeBSD: src/sys/dev/drm/drm_irq.c,v 1.2 2005/11/28 23:13:52 anholt Exp $");
*/
#include "drmP.h"
#include "drm.h"
int drm_irq_by_busid(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_irq_busid_t irq;
DRM_COPY_FROM_USER_IOCTL(irq, (drm_irq_busid_t *)data, sizeof(irq));
if ((irq.busnum >> 8) != dev->pci_domain ||
(irq.busnum & 0xff) != dev->pci_bus ||
irq.devnum != dev->pci_slot ||
irq.funcnum != dev->pci_func)
return EINVAL;
irq.irq = dev->irq;
DRM_DEBUG("%d:%d:%d => IRQ %d\n",
irq.busnum, irq.devnum, irq.funcnum, irq.irq);
DRM_COPY_TO_USER_IOCTL( (drm_irq_busid_t *)data, irq, sizeof(irq) );
return 0;
}
#if defined(__FreeBSD__) && __FreeBSD_version >= 500000
static irqreturn_t
drm_irq_handler_wrap(DRM_IRQ_ARGS)
{
drm_device_t *dev = (drm_device_t *)arg;
DRM_SPINLOCK(&dev->irq_lock);
dev->driver.irq_handler(arg);
DRM_SPINUNLOCK(&dev->irq_lock);
}
#endif
#ifdef __NetBSD__
static irqreturn_t
drm_irq_handler_wrap(DRM_IRQ_ARGS)
{
int s;
irqreturn_t ret;
drm_device_t *dev = (drm_device_t *)arg;
s = spldrm();
DRM_SPINLOCK(&dev->irq_lock);
ret = dev->driver.irq_handler(arg);
DRM_SPINUNLOCK(&dev->irq_lock);
splx(s);
return ret;
}
#endif
int drm_irq_install(drm_device_t *dev)
{
int retcode;
#ifdef __NetBSD__
pci_intr_handle_t ih;
#endif
if (dev->irq == 0 || dev->dev_private == NULL)
return DRM_ERR(EINVAL);
DRM_DEBUG( "%s: irq=%d\n", __FUNCTION__, dev->irq );
DRM_LOCK();
if (dev->irq_enabled) {
DRM_UNLOCK();
return DRM_ERR(EBUSY);
}
dev->irq_enabled = 1;
dev->context_flag = 0;
DRM_SPININIT(dev->irq_lock, "DRM IRQ lock");
/* Before installing handler */
dev->driver.irq_preinstall(dev);
DRM_UNLOCK();
/* Install handler */
#ifdef __FreeBSD__
dev->irqrid = 0;
dev->irqr = bus_alloc_resource_any(dev->device, SYS_RES_IRQ,
&dev->irqrid, RF_SHAREABLE);
if (!dev->irqr) {
retcode = ENOENT;
goto err;
}
#if __FreeBSD_version < 500000
retcode = bus_setup_intr(dev->device, dev->irqr, INTR_TYPE_TTY,
dev->irq_handler, dev, &dev->irqh);
#else
retcode = bus_setup_intr(dev->device, dev->irqr, INTR_TYPE_TTY | INTR_MPSAFE,
drm_irq_handler_wrap, dev, &dev->irqh);
#endif
if (retcode != 0)
goto err;
#elif defined(__NetBSD__) || defined(__OpenBSD__)
if (pci_intr_map(&dev->pa, &ih) != 0) {
retcode = ENOENT;
goto err;
}
dev->irqh = pci_intr_establish(&dev->pa.pa_pc, ih, IPL_TTY,
drm_irq_handler_wrap, dev);
if (!dev->irqh) {
retcode = ENOENT;
goto err;
}
printf("dri irq ok\n");
#endif
/* After installing handler */
DRM_LOCK();
dev->driver.irq_postinstall(dev);
DRM_UNLOCK();
return 0;
err:
DRM_LOCK();
dev->irq_enabled = 0;
#ifdef ___FreeBSD__
if (dev->irqrid != 0) {
bus_release_resource(dev->device, SYS_RES_IRQ, dev->irqrid,
dev->irqr);
dev->irqrid = 0;
}
#endif
DRM_SPINUNINIT(dev->irq_lock);
DRM_UNLOCK();
return retcode;
}
int drm_irq_uninstall(drm_device_t *dev)
{
#ifdef __FreeBSD__
int irqrid;
#endif
if (!dev->irq_enabled)
return DRM_ERR(EINVAL);
dev->irq_enabled = 0;
#ifdef __FreeBSD__
irqrid = dev->irqrid;
dev->irqrid = 0;
#endif
DRM_DEBUG( "%s: irq=%d\n", __FUNCTION__, dev->irq );
dev->driver.irq_uninstall(dev);
#ifdef __FreeBSD__
DRM_UNLOCK();
bus_teardown_intr(dev->device, dev->irqr, dev->irqh);
bus_release_resource(dev->device, SYS_RES_IRQ, irqrid, dev->irqr);
DRM_LOCK();
#elif defined(__NetBSD__) || defined(__OpenBSD__)
pci_intr_disestablish(&dev->pa.pa_pc, dev->irqh);
#endif
DRM_SPINUNINIT(dev->irq_lock);
return 0;
}
int drm_control(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_control_t ctl;
int err;
DRM_COPY_FROM_USER_IOCTL( ctl, (drm_control_t *) data, sizeof(ctl) );
switch ( ctl.func ) {
case DRM_INST_HANDLER:
/* Handle drivers whose DRM used to require IRQ setup but the
* no longer does.
*/
if (!dev->driver.use_irq)
return 0;
if (dev->if_version < DRM_IF_VERSION(1, 2) &&
ctl.irq != dev->irq)
return DRM_ERR(EINVAL);
return drm_irq_install(dev);
case DRM_UNINST_HANDLER:
if (!dev->driver.use_irq)
return 0;
DRM_LOCK();
err = drm_irq_uninstall(dev);
DRM_UNLOCK();
return err;
default:
return DRM_ERR(EINVAL);
}
}
int drm_wait_vblank(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_wait_vblank_t vblwait;
struct timeval now;
int ret;
if (!dev->irq_enabled)
return DRM_ERR(EINVAL);
DRM_COPY_FROM_USER_IOCTL( vblwait, (drm_wait_vblank_t *)data,
sizeof(vblwait) );
if (vblwait.request.type & _DRM_VBLANK_RELATIVE) {
vblwait.request.sequence += atomic_read(&dev->vbl_received);
vblwait.request.type &= ~_DRM_VBLANK_RELATIVE;
}
flags = vblwait.request.type & _DRM_VBLANK_FLAGS_MASK;
if (flags & _DRM_VBLANK_SIGNAL) {
#if 0 /* disabled */
drm_vbl_sig_t *vbl_sig = malloc(sizeof(drm_vbl_sig_t), M_DRM,
M_NOWAIT | M_ZERO);
if (vbl_sig == NULL)
return ENOMEM;
vbl_sig->sequence = vblwait.request.sequence;
vbl_sig->signo = vblwait.request.signal;
vbl_sig->pid = DRM_CURRENTPID;
vblwait.reply.sequence = atomic_read(&dev->vbl_received);
DRM_SPINLOCK(&dev->irq_lock);
TAILQ_INSERT_HEAD(&dev->vbl_sig_list, vbl_sig, link);
DRM_SPINUNLOCK(&dev->irq_lock);
ret = 0;
#endif
ret = EINVAL;
} else {
DRM_LOCK();
ret = dev->driver.vblank_wait(dev, &vblwait.request.sequence);
DRM_UNLOCK();
microtime(&now);
vblwait.reply.tval_sec = now.tv_sec;
vblwait.reply.tval_usec = now.tv_usec;
}
DRM_COPY_TO_USER_IOCTL( (drm_wait_vblank_t *)data, vblwait,
sizeof(vblwait) );
return ret;
}
void drm_vbl_send_signals(drm_device_t *dev)
{
}
#if 0 /* disabled */
void drm_vbl_send_signals( drm_device_t *dev )
{
drm_vbl_sig_t *vbl_sig;
unsigned int vbl_seq = atomic_read( &dev->vbl_received );
struct proc *p;
vbl_sig = TAILQ_FIRST(&dev->vbl_sig_list);
while (vbl_sig != NULL) {
drm_vbl_sig_t *next = TAILQ_NEXT(vbl_sig, link);
if ( ( vbl_seq - vbl_sig->sequence ) <= (1<<23) ) {
p = pfind(vbl_sig->pid);
if (p != NULL)
psignal(p, vbl_sig->signo);
TAILQ_REMOVE(&dev->vbl_sig_list, vbl_sig, link);
DRM_FREE(vbl_sig,sizeof(*vbl_sig));
}
vbl_sig = next;
}
}
#endif

View File

@ -0,0 +1,76 @@
/* drm_linux_list.h -- linux list functions for the BSDs.
* Created: Mon Apr 7 14:30:16 1999 by anholt@FreeBSD.org
*/
/*-
* Copyright 2003 Eric Anholt
* 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:
* Eric Anholt <anholt@FreeBSD.org>
*
*/
#include <sys/cdefs.h>
/*
__FBSDID("$FreeBSD: src/sys/dev/drm/drm_linux_list.h,v 1.4 2005/11/28 23:13:52 anholt Exp $");
*/
struct list_head {
struct list_head *next, *prev;
};
/* Cheat, assume the list_head is at the start of the struct */
#define list_entry(entry, type, member) (type *)(entry)
static __inline__ void
INIT_LIST_HEAD(struct list_head *head) {
(head)->next = head;
(head)->prev = head;
}
static __inline__ int
list_empty(struct list_head *head) {
return (head)->next == head;
}
static __inline__ void
list_add_tail(struct list_head *entry, struct list_head *head) {
(entry)->prev = (head)->prev;
(entry)->next = head;
(head)->prev->next = entry;
(head)->prev = entry;
}
static __inline__ void
list_del(struct list_head *entry) {
(entry)->next->prev = (entry)->prev;
(entry)->prev->next = (entry)->next;
}
#define list_for_each(entry, head) \
for (entry = (head)->next; entry != head; entry = (entry)->next)
#define list_for_each_safe(entry, temp, head) \
for (entry = (head)->next, temp = (entry)->next; \
temp != head; \
entry = temp, temp = temp->next)

182
sys/dev/drm/drm_lock.c Normal file
View File

@ -0,0 +1,182 @@
/* lock.c -- IOCTLs for locking -*- 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 <sys/cdefs.h>
/*
__FBSDID("$FreeBSD: src/sys/dev/drm/drm_lock.c,v 1.2 2005/11/28 23:13:52 anholt Exp $");
*/
#include "drmP.h"
int drm_lock_take(__volatile__ unsigned int *lock, unsigned int context)
{
unsigned int old, new;
do {
old = *lock;
if (old & _DRM_LOCK_HELD) new = old | _DRM_LOCK_CONT;
else new = context | _DRM_LOCK_HELD;
} while (!atomic_cmpset_int(lock, old, new));
if (_DRM_LOCKING_CONTEXT(old) == context) {
if (old & _DRM_LOCK_HELD) {
if (context != DRM_KERNEL_CONTEXT) {
DRM_ERROR("%d holds heavyweight lock\n",
context);
}
return 0;
}
}
if (new == (context | _DRM_LOCK_HELD)) {
/* Have lock */
return 1;
}
return 0;
}
/* 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. */
int drm_lock_transfer(drm_device_t *dev,
__volatile__ unsigned int *lock, unsigned int context)
{
unsigned int old, new;
dev->lock.filp = NULL;
do {
old = *lock;
new = context | _DRM_LOCK_HELD;
} while (!atomic_cmpset_int(lock, old, new));
return 1;
}
int drm_lock_free(drm_device_t *dev,
__volatile__ unsigned int *lock, unsigned int context)
{
unsigned int old, new;
dev->lock.filp = NULL;
do {
old = *lock;
new = 0;
} while (!atomic_cmpset_int(lock, old, new));
if (_DRM_LOCK_IS_HELD(old) && _DRM_LOCKING_CONTEXT(old) != context) {
DRM_ERROR("%d freed heavyweight lock held by %d\n",
context, _DRM_LOCKING_CONTEXT(old));
return 1;
}
DRM_WAKEUP_INT((void *)&dev->lock.lock_queue);
return 0;
}
int drm_lock(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_lock_t lock;
int ret = 0;
DRM_COPY_FROM_USER_IOCTL(lock, (drm_lock_t *)data, sizeof(lock));
if (lock.context == DRM_KERNEL_CONTEXT) {
DRM_ERROR("Process %d using kernel context %d\n",
DRM_CURRENTPID, lock.context);
return EINVAL;
}
DRM_DEBUG("%d (pid %d) requests lock (0x%08x), flags = 0x%08x\n",
lock.context, DRM_CURRENTPID, dev->lock.hw_lock->lock, lock.flags);
if (dev->driver.use_dma_queue && lock.context < 0)
return EINVAL;
DRM_LOCK();
for (;;) {
if (drm_lock_take(&dev->lock.hw_lock->lock, lock.context)) {
dev->lock.filp = (void *)(uintptr_t)DRM_CURRENTPID;
dev->lock.lock_time = jiffies;
atomic_inc(&dev->counts[_DRM_STAT_LOCKS]);
break; /* Got lock */
}
/* Contention */
#if defined(__FreeBSD__) && __FreeBSD_version > 500000
ret = msleep((void *)&dev->lock.lock_queue, &dev->dev_lock,
PZERO | PCATCH, "drmlk2", 0);
#else
ret = ltsleep((void *)&dev->lock.lock_queue, PZERO | PCATCH,
"drmlk2", 0, &dev->dev_lock);
#endif
if (ret != 0)
break;
}
DRM_UNLOCK();
DRM_DEBUG("%d %s\n", lock.context, ret ? "interrupted" : "has lock");
if (ret != 0)
return ret;
/* XXX: Add signal blocking here */
if (dev->driver.dma_quiescent != NULL &&
(lock.flags & _DRM_LOCK_QUIESCENT))
dev->driver.dma_quiescent(dev);
return 0;
}
int drm_unlock(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_lock_t lock;
DRM_COPY_FROM_USER_IOCTL(lock, (drm_lock_t *)data, sizeof(lock));
if (lock.context == DRM_KERNEL_CONTEXT) {
DRM_ERROR("Process %d using kernel context %d\n",
DRM_CURRENTPID, lock.context);
return EINVAL;
}
atomic_inc(&dev->counts[_DRM_STAT_UNLOCKS]);
DRM_LOCK();
drm_lock_transfer(dev, &dev->lock.hw_lock->lock, DRM_KERNEL_CONTEXT);
if (drm_lock_free(dev, &dev->lock.hw_lock->lock, DRM_KERNEL_CONTEXT)) {
DRM_ERROR("\n");
}
DRM_UNLOCK();
return 0;
}

202
sys/dev/drm/drm_memory.c Normal file
View File

@ -0,0 +1,202 @@
/* drm_memory.h -- Memory management wrappers for DRM -*- linux-c -*-
* Created: Thu Feb 4 14:00:34 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 <sys/cdefs.h>
/*
__FBSDID("$FreeBSD: src/sys/dev/drm/drm_memory.c,v 1.2 2005/11/28 23:13:52 anholt Exp $");
*/
#include "drmP.h"
MALLOC_DEFINE(M_DRM, "drm", "DRM Data Structures");
void drm_mem_init(void)
{
#if defined(__NetBSD__) || defined(__OpenBSD__)
/*
malloc_type_attach(M_DRM);
*/
#endif
}
void drm_mem_uninit(void)
{
}
void *drm_alloc(size_t size, int area)
{
return malloc(size, M_DRM, M_NOWAIT);
}
void *drm_calloc(size_t nmemb, size_t size, int area)
{
return malloc(size * nmemb, M_DRM, M_NOWAIT | M_ZERO);
}
void *drm_realloc(void *oldpt, size_t oldsize, size_t size, int area)
{
void *pt;
pt = malloc(size, M_DRM, M_NOWAIT);
if (pt == NULL)
return NULL;
if (oldpt && oldsize) {
memcpy(pt, oldpt, oldsize);
free(oldpt, M_DRM);
}
return pt;
}
void drm_free(void *pt, size_t size, int area)
{
free(pt, M_DRM);
}
void *drm_ioremap(drm_device_t *dev, drm_local_map_t *map)
{
#ifdef __FreeBSD__
return pmap_mapdev(map->offset, map->size);
#elif defined(__NetBSD__) || defined(__OpenBSD__)
int i, reg, reason;
for(i = 0; i<DRM_MAX_PCI_RESOURCE; i++) {
reg = PCI_MAPREG_START + i*4;
if (dev->pci_map_data[i].maptype == PCI_MAPREG_TYPE_MEM &&
dev->pci_map_data[i].base == map->offset &&
dev->pci_map_data[i].size >= map->size)
{
map->bst = dev->pa.pa_memt;
map->cnt = &(dev->pci_map_data[i].mapped);
map->mapsize = dev->pci_map_data[i].size;
dev->pci_map_data[i].mapped++;
if (dev->pci_map_data[i].mapped > 1)
{
map->bsh = dev->pci_map_data[i].bsh;
return dev->pci_map_data[i].vaddr;
}
if ((reason = bus_space_map(map->bst, map->offset,
dev->pci_map_data[i].size,
dev->pci_map_data[i].flags, &map->bsh)))
{
dev->pci_map_data[i].mapped--;
DRM_DEBUG("ioremap: failed to map (%d)\n",
reason);
return NULL;
}
dev->pci_map_data[i].bsh = map->bsh;
dev->pci_map_data[i].vaddr =
bus_space_vaddr(map->bst, map->bsh);
DRM_DEBUG("ioremap mem found: %p\n",
dev->pci_map_data[i].vaddr);
return dev->pci_map_data[i].vaddr;
}
}
DRM_DEBUG("drm_ioremap failed: offset=%lx size=%lu\n",
map->offset, map->size);
return NULL;
#endif
}
void drm_ioremapfree(drm_local_map_t *map)
{
#ifdef __FreeBSD__
pmap_unmapdev((vm_offset_t) map->handle, map->size);
#elif defined(__NetBSD__) || defined(__OpenBSD__)
if (map->cnt == NULL) {
DRM_INFO("drm_ioremapfree called for unknown map\n");
return;
}
if (*(map->cnt) > 0) {
(*(map->cnt))--;
if(*(map->cnt) == 0)
bus_space_unmap(map->bst, map->bsh, map->mapsize);
}
#endif
}
#ifdef __FreeBSD__
int
drm_mtrr_add(unsigned long offset, size_t size, int flags)
{
int act;
struct mem_range_desc mrdesc;
mrdesc.mr_base = offset;
mrdesc.mr_len = size;
mrdesc.mr_flags = flags;
act = MEMRANGE_SET_UPDATE;
strlcpy(mrdesc.mr_owner, "drm", sizeof(mrdesc.mr_owner));
return mem_range_attr_set(&mrdesc, &act);
}
int
drm_mtrr_del(int __unused handle, unsigned long offset, size_t size, int flags)
{
int act;
struct mem_range_desc mrdesc;
mrdesc.mr_base = offset;
mrdesc.mr_len = size;
mrdesc.mr_flags = flags;
act = MEMRANGE_SET_REMOVE;
strlcpy(mrdesc.mr_owner, "drm", sizeof(mrdesc.mr_owner));
return mem_range_attr_set(&mrdesc, &act);
}
#elif defined(__NetBSD__) || defined(__OpenBSD__)
int
drm_mtrr_add(unsigned long offset, size_t size, int flags)
{
struct mtrr mtrrmap;
int one = 1;
DRM_DEBUG("offset=%lx size=%ld\n", (long)offset, (long)size);
mtrrmap.base = offset;
mtrrmap.len = size;
mtrrmap.type = flags;
mtrrmap.flags = MTRR_VALID;
return mtrr_set(&mtrrmap, &one, NULL, MTRR_GETSET_KERNEL);
}
int
drm_mtrr_del(int __unused handle, unsigned long offset, size_t size, int flags)
{
struct mtrr mtrrmap;
int one = 1;
DRM_DEBUG("offset=%lx size=%ld\n", (long)offset, (long)size);
mtrrmap.base = offset;
mtrrmap.len = size;
mtrrmap.type = flags;
mtrrmap.flags = 0;
return mtrr_set(&mtrrmap, &one, NULL, MTRR_GETSET_KERNEL);
}
#endif

155
sys/dev/drm/drm_pci.c Normal file
View File

@ -0,0 +1,155 @@
/**
* \file drm_pci.h
* \brief PCI consistent, DMA-accessible memory functions.
*
* \author Eric Anholt <anholt@FreeBSD.org>
*/
/*-
* Copyright 2003 Eric Anholt.
* 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 <sys/cdefs.h>
/*
__FBSDID("$FreeBSD: src/sys/dev/drm/drm_pci.c,v 1.2 2005/11/28 23:13:52 anholt Exp $");
*/
#include "drmP.h"
/**********************************************************************/
/** \name PCI memory */
/*@{*/
#if defined(__FreeBSD__)
static void
drm_pci_busdma_callback(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
{
drm_dma_handle_t *dmah = arg;
if (error != 0)
return;
KASSERT(nsegs == 1, ("drm_pci_busdma_callback: bad dma segment count"));
dmah->busaddr = segs[0].ds_addr;
}
#endif
/**
* \brief Allocate a physically contiguous DMA-accessible consistent
* memory block.
*/
drm_dma_handle_t *
drm_pci_alloc(drm_device_t *dev, size_t size, size_t align, dma_addr_t maxaddr)
{
drm_dma_handle_t *dmah;
int ret;
#ifdef __NetBSD__
int nsegs;
#endif
/* Need power-of-two alignment, so fail the allocation if it isn't. */
if ((align & (align - 1)) != 0) {
DRM_ERROR("drm_pci_alloc with non-power-of-two alignment %d\n",
(int)align);
return NULL;
}
dmah = malloc(sizeof(drm_dma_handle_t), M_DRM, M_ZERO | M_NOWAIT);
if (dmah == NULL)
return NULL;
#ifdef __FreeBSD__
ret = bus_dma_tag_create(NULL, align, 0, /* tag, align, boundary */
maxaddr, BUS_SPACE_MAXADDR, /* lowaddr, highaddr */
NULL, NULL, /* filtfunc, filtfuncargs */
size, 1, size, /* maxsize, nsegs, maxsegsize */
BUS_DMA_ALLOCNOW, NULL, NULL, /* flags, lockfunc, lockfuncargs */
&dmah->tag);
if (ret != 0) {
free(dmah, M_DRM);
return NULL;
}
ret = bus_dmamem_alloc(dmah->tag, &dmah->vaddr, BUS_DMA_NOWAIT,
&dmah->map);
if (ret != 0) {
bus_dma_tag_destroy(dmah->tag);
free(dmah, M_DRM);
return NULL;
}
ret = bus_dmamap_load(dmah->tag, dmah->map, dmah->vaddr, size,
drm_pci_busdma_callback, dmah, 0);
if (ret != 0) {
bus_dmamem_free(dmah->tag, dmah->vaddr, dmah->map);
bus_dma_tag_destroy(dmah->tag);
free(dmah, M_DRM);
return NULL;
}
#elif defined(__NetBSD__)
ret = bus_dmamem_alloc(dev->pa.pa_dmat, size, align, PAGE_SIZE,
&dmah->seg, 1, &nsegs, BUS_DMA_NOWAIT);
if (ret != 0) {
free(dmah, M_DRM);
return NULL;
}
if(nsegs != 1) {
bus_dmamem_free(dev->pa.pa_dmat, &dmah->seg, nsegs);
free(dmah, M_DRM);
return NULL;
}
ret = bus_dmamem_map(dev->pa.pa_dmat, &dmah->seg, 1, size, &dmah->addr,
BUS_DMA_NOWAIT);
if (ret != 0) {
bus_dmamem_free(dev->pa.pa_dmat, &dmah->seg, 1);
free(dmah, M_DRM);
return NULL;
}
dmah->busaddr = dmah->seg.ds_addr;
dmah->vaddr = dmah->addr;
#endif
return dmah;
}
/**
* \brief Free a DMA-accessible consistent memory block.
*/
void
drm_pci_free(drm_device_t *dev, drm_dma_handle_t *dmah)
{
if (dmah == NULL)
return;
#if defined(__FreeBSD__)
bus_dmamem_free(dmah->tag, dmah->vaddr, dmah->map);
bus_dma_tag_destroy(dmah->tag);
#elif defined(__NetBSD__)
bus_dmamem_free(dev->pa.pa_dmat, &dmah->seg, 1);
#endif
free(dmah, M_DRM);
}
/*@}*/

83
sys/dev/drm/drm_sarea.h Normal file
View File

@ -0,0 +1,83 @@
/**
* \file drm_sarea.h
* \brief SAREA definitions
*
* \author Michel D<EFBFBD>zer <michel@daenzer.net>
*/
/*-
* Copyright 2002 Tungsten Graphics, Inc., Cedar Park, Texas.
* 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.
*/
#include <sys/cdefs.h>
/*
__FBSDID("$FreeBSD: src/sys/dev/drm/drm_sarea.h,v 1.6 2005/11/28 23:13:52 anholt Exp $");
*/
#ifndef _DRM_SAREA_H_
#define _DRM_SAREA_H_
#include "drm.h"
/* SAREA area needs to be at least a page */
#if defined(__alpha__)
#define SAREA_MAX 0x2000
#elif defined(__ia64__)
#define SAREA_MAX 0x10000 /* 64kB */
#else
/* Intel 830M driver needs at least 8k SAREA */
#define SAREA_MAX 0x2000
#endif
/** Maximum number of drawables in the SAREA */
#define SAREA_MAX_DRAWABLES 256
#define SAREA_DRAWABLE_CLAIMED_ENTRY 0x80000000
/** SAREA drawable */
typedef struct drm_sarea_drawable {
unsigned int stamp;
unsigned int flags;
} drm_sarea_drawable_t;
/** SAREA frame */
typedef struct drm_sarea_frame {
unsigned int x;
unsigned int y;
unsigned int width;
unsigned int height;
unsigned int fullscreen;
} drm_sarea_frame_t;
/** SAREA */
typedef struct drm_sarea {
/** first thing is always the DRM locking structure */
drm_hw_lock_t lock;
/** \todo Use readers/writer lock for drm_sarea::drawable_lock */
drm_hw_lock_t drawable_lock;
drm_sarea_drawable_t drawableTable[SAREA_MAX_DRAWABLES]; /**< drawables */
drm_sarea_frame_t frame; /**< frame */
drm_context_t dummy_context;
} drm_sarea_t;
#endif /* _DRM_SAREA_H_ */

134
sys/dev/drm/drm_scatter.c Normal file
View File

@ -0,0 +1,134 @@
/* drm_scatter.h -- IOCTLs to manage scatter/gather memory -*- linux-c -*-
* Created: Mon Dec 18 23:20:54 2000 by gareth@valinux.com */
/*-
* 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:
* Gareth Hughes <gareth@valinux.com>
* Eric Anholt <anholt@FreeBSD.org>
*
*/
#include <sys/cdefs.h>
/*
__FBSDID("$FreeBSD: src/sys/dev/drm/drm_scatter.c,v 1.3 2006/05/17 06:29:36 anholt Exp $");
*/
#include "drmP.h"
#define DEBUG_SCATTER 0
void drm_sg_cleanup(drm_sg_mem_t *entry)
{
free((void *)entry->handle, M_DRM);
free(entry->busaddr, M_DRM);
free(entry, M_DRM);
}
int drm_sg_alloc(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_scatter_gather_t request;
drm_sg_mem_t *entry;
unsigned long pages;
int i;
DRM_DEBUG( "%s\n", __FUNCTION__ );
if ( dev->sg )
return EINVAL;
DRM_COPY_FROM_USER_IOCTL(request, (drm_scatter_gather_t *)data,
sizeof(request) );
entry = malloc(sizeof(*entry), M_DRM, M_WAITOK | M_ZERO);
if ( !entry )
return ENOMEM;
pages = round_page(request.size) / PAGE_SIZE;
DRM_DEBUG( "sg size=%ld pages=%ld\n", request.size, pages );
entry->pages = pages;
entry->busaddr = malloc(pages * sizeof(*entry->busaddr), M_DRM,
M_WAITOK | M_ZERO);
if ( !entry->busaddr ) {
drm_sg_cleanup(entry);
return ENOMEM;
}
entry->handle = (long)malloc(pages << PAGE_SHIFT, M_DRM,
M_WAITOK | M_ZERO);
if (entry->handle == 0) {
drm_sg_cleanup(entry);
return ENOMEM;
}
for (i = 0; i < pages; i++) {
entry->busaddr[i] = vtophys(entry->handle + i * PAGE_SIZE);
}
DRM_DEBUG( "sg alloc handle = %08lx\n", entry->handle );
entry->virtual = (void *)entry->handle;
request.handle = entry->handle;
DRM_COPY_TO_USER_IOCTL( (drm_scatter_gather_t *)data,
request,
sizeof(request) );
DRM_LOCK();
if (dev->sg) {
DRM_UNLOCK();
drm_sg_cleanup(entry);
return EINVAL;
}
dev->sg = entry;
DRM_UNLOCK();
return 0;
}
int drm_sg_free(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_scatter_gather_t request;
drm_sg_mem_t *entry;
DRM_COPY_FROM_USER_IOCTL( request, (drm_scatter_gather_t *)data,
sizeof(request) );
DRM_LOCK();
entry = dev->sg;
dev->sg = NULL;
DRM_UNLOCK();
if ( !entry || entry->handle != request.handle )
return EINVAL;
DRM_DEBUG( "sg free virtual = 0x%lx\n", entry->handle );
drm_sg_cleanup(entry);
return 0;
}

409
sys/dev/drm/drm_sysctl.c Normal file
View File

@ -0,0 +1,409 @@
/*-
* Copyright 2003 Eric Anholt
* 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
* ERIC ANHOLT 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 <sys/cdefs.h>
/*
__FBSDID("$FreeBSD: src/sys/dev/drm/drm_sysctl.c,v 1.2 2005/11/28 23:13:53 anholt Exp $");
*/
#include "drmP.h"
#include "drm.h"
#include <sys/sysctl.h>
static int drm_name_info DRM_SYSCTL_HANDLER_ARGS;
static int drm_vm_info DRM_SYSCTL_HANDLER_ARGS;
static int drm_clients_info DRM_SYSCTL_HANDLER_ARGS;
static int drm_bufs_info DRM_SYSCTL_HANDLER_ARGS;
struct drm_sysctl_list {
const char *name;
int (*f) DRM_SYSCTL_HANDLER_ARGS;
} drm_sysctl_list[] = {
{"name", drm_name_info},
{"vm", drm_vm_info},
{"clients", drm_clients_info},
{"bufs", drm_bufs_info},
};
#define DRM_SYSCTL_ENTRIES (sizeof(drm_sysctl_list)/sizeof(drm_sysctl_list[0]))
struct drm_sysctl_info {
#ifdef __FreeBSD__
struct sysctl_ctx_list ctx;
#elif defined __NetBSD__
const struct sysctlnode *dri, *dri_card, *dri_debug;
const struct sysctlnode *dri_rest[DRM_SYSCTL_ENTRIES];
#endif
char name[7];
};
int drm_sysctl_init(drm_device_t *dev)
{
struct drm_sysctl_info *info;
#ifdef __FreeBSD__
struct sysctl_oid *oid;
struct sysctl_oid *top, *drioid;
#endif
int i;
info = malloc(sizeof *info, M_DRM, M_WAITOK | M_ZERO);
if ( !info )
return 1;
dev->sysctl = info;
#ifdef __FreeBSD__
/* Add the sysctl node for DRI if it doesn't already exist */
drioid = SYSCTL_ADD_NODE( &info->ctx, &sysctl__hw_children, OID_AUTO, "dri", CTLFLAG_RW, NULL, "DRI Graphics");
if (!drioid)
return 1;
/* Find the next free slot under hw.dri */
i = 0;
SLIST_FOREACH(oid, SYSCTL_CHILDREN(drioid), oid_link) {
if (i <= oid->oid_arg2)
i = oid->oid_arg2 + 1;
}
if (i>9)
return 1;
/* Add the hw.dri.x for our device */
info->name[0] = '0' + i;
info->name[1] = 0;
top = SYSCTL_ADD_NODE( &info->ctx, SYSCTL_CHILDREN(drioid), OID_AUTO, info->name, CTLFLAG_RW, NULL, NULL);
if (!top)
return 1;
for (i = 0; i < DRM_SYSCTL_ENTRIES; i++) {
oid = SYSCTL_ADD_OID(&info->ctx,
SYSCTL_CHILDREN(top),
OID_AUTO,
drm_sysctl_list[i].name,
CTLTYPE_INT | CTLFLAG_RD,
dev,
0,
drm_sysctl_list[i].f,
"A",
NULL);
if (!oid)
return 1;
}
SYSCTL_ADD_INT(&info->ctx, SYSCTL_CHILDREN(top), OID_AUTO, "debug",
CTLFLAG_RW, &drm_debug_flag, sizeof(drm_debug_flag),
"Enable debugging output");
#elif defined(__NetBSD__)
sysctl_createv(NULL, 0, NULL, &info->dri,
CTLFLAG_READWRITE, CTLTYPE_NODE,
"dri", SYSCTL_DESCR("DRI Graphics"), NULL, 0, NULL, 0,
CTL_HW, CTL_CREATE);
snprintf(info->name, 7, "card%d", dev->unit);
sysctl_createv(NULL, 0, NULL, &info->dri_card,
CTLFLAG_READWRITE, CTLTYPE_NODE,
info->name, NULL, NULL, 0, NULL, 0,
CTL_HW, info->dri->sysctl_num, CTL_CREATE);
for (i = 0; i < DRM_SYSCTL_ENTRIES; i++)
sysctl_createv(NULL, 0, NULL, &(info->dri_rest[i]),
CTLFLAG_READONLY, CTLTYPE_STRING,
drm_sysctl_list[i].name, NULL,
drm_sysctl_list[i].f, 0, dev,
sizeof(drm_device_t*),
CTL_HW,
info->dri->sysctl_num,
info->dri_card->sysctl_num, CTL_CREATE);
sysctl_createv(NULL, 0, NULL, &info->dri_debug,
CTLFLAG_READWRITE, CTLTYPE_INT,
"debug", SYSCTL_DESCR("Enable debugging output"),
NULL, 0,
&drm_debug_flag, sizeof(drm_debug_flag),
CTL_HW, info->dri->sysctl_num, CTL_CREATE);
#endif
return 0;
}
int drm_sysctl_cleanup(drm_device_t *dev)
{
#ifdef __FreeBSD__
int error;
error = sysctl_ctx_free( &dev->sysctl->ctx );
#elif defined(__NetBSD__)
int i, error = 0;
sysctl_destroyv(NULL, CTL_HW, dev->sysctl->dri->sysctl_num,
dev->sysctl->dri_debug->sysctl_num,
CTL_DESTROY);
for (i = 0; i < DRM_SYSCTL_ENTRIES; i++)
sysctl_destroyv(NULL, CTL_HW, dev->sysctl->dri->sysctl_num,
dev->sysctl->dri_card->sysctl_num,
dev->sysctl->dri_rest[i]->sysctl_num,
CTL_DESTROY);
sysctl_destroyv(NULL, CTL_HW, dev->sysctl->dri->sysctl_num,
dev->sysctl->dri_card->sysctl_num,
CTL_DESTROY);
sysctl_destroyv(NULL, CTL_HW, dev->sysctl->dri->sysctl_num, CTL_DESTROY);
#endif
free(dev->sysctl, M_DRM);
dev->sysctl = NULL;
return error;
}
#ifdef __NetBSD__
#define SYSCTL_OUT(x, y, z) \
(len+=z,(len<*oldlenp)?(strcat((char*)oldp, y),0):EOVERFLOW)
#endif
#define DRM_SYSCTL_PRINT(fmt, arg...) \
do { \
snprintf(buf, sizeof(buf), fmt, ##arg); \
retcode = SYSCTL_OUT(req, buf, strlen(buf)); \
if (retcode) \
goto done; \
} while (0)
static int drm_name_info DRM_SYSCTL_HANDLER_ARGS
{
#ifdef __FreeBSD__
drm_device_t *dev = arg1;
#elif defined(__NetBSD__)
int len = 0;
drm_device_t *dev = rnode->sysctl_data;
#endif
char buf[128];
int retcode;
int hasunique = 0;
#ifdef __NetBSD__
if(oldp == NULL) return EINVAL;
*((char*)oldp) = '\0';
#endif
#ifdef __FreeBSD__
DRM_SYSCTL_PRINT("%s 0x%x", dev->driver.name, dev2udev(dev->devnode));
#elif defined(__NetBSD__)
DRM_SYSCTL_PRINT("%s", dev->driver.name);
#endif
DRM_LOCK();
if (dev->unique) {
snprintf(buf, sizeof(buf), " %s", dev->unique);
hasunique = 1;
}
DRM_UNLOCK();
if (hasunique)
SYSCTL_OUT(req, buf, strlen(buf));
SYSCTL_OUT(req, "", 1);
done:
return retcode;
}
static int drm_vm_info DRM_SYSCTL_HANDLER_ARGS
{
#ifdef __FreeBSD__
drm_device_t *dev = arg1;
#elif defined(__NetBSD__)
int len = 0;
drm_device_t *dev = rnode->sysctl_data;
#endif
drm_local_map_t *map, *tempmaps;
const char *types[] = { "FB", "REG", "SHM", "AGP", "SG" };
const char *type, *yesno;
int i, mapcount;
char buf[128];
int retcode;
#ifdef __NetBSD__
if(oldp == NULL) return EINVAL;
*((char*)oldp) = '\0';
#endif
/* We can't hold the lock while doing SYSCTL_OUTs, so allocate a
* temporary copy of all the map entries and then SYSCTL_OUT that.
*/
DRM_LOCK();
mapcount = 0;
TAILQ_FOREACH(map, &dev->maplist, link)
mapcount++;
tempmaps = malloc(sizeof(drm_local_map_t) * mapcount, M_DRM, M_NOWAIT);
if (tempmaps == NULL) {
DRM_UNLOCK();
return ENOMEM;
}
i = 0;
TAILQ_FOREACH(map, &dev->maplist, link)
tempmaps[i++] = *map;
DRM_UNLOCK();
DRM_SYSCTL_PRINT("\nslot offset size type flags "
"address mtrr\n");
for (i = 0; i < mapcount; i++) {
map = &tempmaps[i];
if (/* map->type < 0 || */ map->type > 4)
type = "??";
else
type = types[map->type];
if (!map->mtrr)
yesno = "no";
else
yesno = "yes";
DRM_SYSCTL_PRINT(
"%4d 0x%08lx 0x%08lx %4.4s 0x%02x 0x%08lx %s\n", i,
map->offset, map->size, type, map->flags,
(unsigned long)map->handle, yesno);
}
SYSCTL_OUT(req, "", 1);
done:
free(tempmaps, M_DRM);
return retcode;
}
static int drm_bufs_info DRM_SYSCTL_HANDLER_ARGS
{
#ifdef __FreeBSD__
drm_device_t *dev = arg1;
#elif defined(__NetBSD__)
int len = 0;
drm_device_t *dev = rnode->sysctl_data;
#endif
drm_device_dma_t *dma = dev->dma;
drm_device_dma_t tempdma;
int *templists;
int i;
char buf[128];
int retcode;
#ifdef __NetBSD__
if(oldp == NULL) return EINVAL;
*((char*)oldp) = '\0';
#endif
/* We can't hold the locks around DRM_SYSCTL_PRINT, so make a temporary
* copy of the whole structure and the relevant data from buflist.
*/
DRM_LOCK();
if (dma == NULL) {
DRM_UNLOCK();
return 0;
}
DRM_SPINLOCK(&dev->dma_lock);
tempdma = *dma;
templists = malloc(sizeof(int) * dma->buf_count, M_DRM, M_NOWAIT);
for (i = 0; i < dma->buf_count; i++)
templists[i] = dma->buflist[i]->list;
dma = &tempdma;
DRM_SPINUNLOCK(&dev->dma_lock);
DRM_UNLOCK();
DRM_SYSCTL_PRINT("\n o size count free segs pages kB\n");
for (i = 0; i <= DRM_MAX_ORDER; i++) {
if (dma->bufs[i].buf_count)
DRM_SYSCTL_PRINT("%2d %8d %5d %5d %5d %5d %5d\n",
i,
dma->bufs[i].buf_size,
dma->bufs[i].buf_count,
atomic_read(&dma->bufs[i]
.freelist.count),
dma->bufs[i].seg_count,
dma->bufs[i].seg_count
*(1 << dma->bufs[i].page_order),
(dma->bufs[i].seg_count
* (1 << dma->bufs[i].page_order))
* PAGE_SIZE / 1024);
}
DRM_SYSCTL_PRINT("\n");
for (i = 0; i < dma->buf_count; i++) {
if (i && !(i%32)) DRM_SYSCTL_PRINT("\n");
DRM_SYSCTL_PRINT(" %d", templists[i]);
}
DRM_SYSCTL_PRINT("\n");
SYSCTL_OUT(req, "", 1);
done:
free(templists, M_DRM);
return retcode;
}
static int drm_clients_info DRM_SYSCTL_HANDLER_ARGS
{
#ifdef __FreeBSD__
drm_device_t *dev = arg1;
#elif defined(__NetBSD__)
int len = 0;
drm_device_t *dev = rnode->sysctl_data;
#endif
drm_file_t *priv, *tempprivs;
char buf[128];
int retcode;
int privcount, i;
#ifdef __NetBSD__
if(oldp == NULL) return EINVAL;
*((char*)oldp) = '\0';
#endif
DRM_LOCK();
privcount = 0;
TAILQ_FOREACH(priv, &dev->files, link)
privcount++;
tempprivs = malloc(sizeof(drm_file_t) * privcount, M_DRM, M_NOWAIT);
if (tempprivs == NULL) {
DRM_UNLOCK();
return ENOMEM;
}
i = 0;
TAILQ_FOREACH(priv, &dev->files, link)
tempprivs[i++] = *priv;
DRM_UNLOCK();
DRM_SYSCTL_PRINT("\na dev pid uid magic ioctls\n");
for (i = 0; i < privcount; i++) {
priv = &tempprivs[i];
DRM_SYSCTL_PRINT("%c %3d %5d %5d %10u %10lu\n",
priv->authenticated ? 'y' : 'n',
priv->minor,
priv->pid,
priv->uid,
priv->magic,
priv->ioctl_count);
}
SYSCTL_OUT(req, "", 1);
done:
free(tempprivs, M_DRM);
return retcode;
}

140
sys/dev/drm/drm_vm.c Normal file
View File

@ -0,0 +1,140 @@
/*-
* Copyright 2003 Eric Anholt
* 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
* ERIC ANHOLT 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 <sys/cdefs.h>
/*
__FBSDID("$FreeBSD: src/sys/dev/drm/drm_vm.c,v 1.2 2005/11/28 23:13:53 anholt Exp $");
*/
#include "drmP.h"
#include "drm.h"
#if defined(__FreeBSD__) && __FreeBSD_version >= 500102
int drm_mmap(struct cdev *kdev, vm_offset_t offset, vm_paddr_t *paddr,
int prot)
#elif defined(__FreeBSD__)
int drm_mmap(dev_t kdev, vm_offset_t offset, int prot)
#elif defined(__NetBSD__) || defined(__OpenBSD__)
paddr_t drm_mmap(dev_t kdev, off_t offset, int prot)
#endif
{
DRM_DEVICE;
drm_local_map_t *map;
drm_file_t *priv;
drm_map_type_t type;
#ifdef __FreeBSD__
vm_paddr_t phys;
#else
paddr_t phys;
#endif
DRM_LOCK();
priv = drm_find_file_by_proc(dev, DRM_CURPROC);
DRM_UNLOCK();
if (priv == NULL) {
DRM_ERROR("can't find authenticator\n");
return EINVAL;
}
if (!priv->authenticated)
return DRM_ERR(EACCES);
if (dev->dma && offset >= 0 && offset < ptoa(dev->dma->page_count)) {
drm_device_dma_t *dma = dev->dma;
DRM_SPINLOCK(&dev->dma_lock);
if (dma->pagelist != NULL) {
unsigned long page = offset >> PAGE_SHIFT;
unsigned long pphys = dma->pagelist[page];
#if defined(__FreeBSD__) && __FreeBSD_version >= 500102
*paddr = phys;
DRM_SPINUNLOCK(&dev->dma_lock);
return 0;
#else
return atop(pphys);
#endif
} else {
DRM_SPINUNLOCK(&dev->dma_lock);
return -1;
}
DRM_SPINUNLOCK(&dev->dma_lock);
}
/* A sequential search of a linked list is
fine here because: 1) there will only be
about 5-10 entries in the list and, 2) a
DRI client only has to do this mapping
once, so it doesn't have to be optimized
for performance, even if the list was a
bit longer. */
DRM_LOCK();
TAILQ_FOREACH(map, &dev->maplist, link) {
if (offset >= map->offset && offset < map->offset + map->size)
break;
}
if (map == NULL) {
DRM_UNLOCK();
DRM_DEBUG("can't find map\n");
return -1;
}
if (((map->flags&_DRM_RESTRICTED) && !DRM_SUSER(DRM_CURPROC))) {
DRM_UNLOCK();
DRM_DEBUG("restricted map\n");
return -1;
}
type = map->type;
DRM_UNLOCK();
switch (type) {
case _DRM_FRAME_BUFFER:
case _DRM_REGISTERS:
case _DRM_AGP:
phys = offset;
break;
case _DRM_CONSISTENT:
#ifdef __FreeBSD__
phys = vtophys((char *)map->handle + (offset - map->offset));
#else
phys = vtophys((paddr_t)map->handle + (offset - map->offset));
#endif
break;
case _DRM_SCATTER_GATHER:
case _DRM_SHM:
phys = vtophys(offset);
break;
default:
DRM_ERROR("bad map type %d\n", type);
return -1; /* This should never happen. */
}
#if defined(__FreeBSD__) && __FreeBSD_version >= 500102
*paddr = phys;
return 0;
#else
return atop(phys);
#endif
}

21
sys/dev/drm/files.drm Normal file
View File

@ -0,0 +1,21 @@
# $NetBSD: files.drm,v 1.1 2007/03/20 18:05:31 drochner Exp $
# direct rendering modules
define drmbase
defflag opt_drm.h DRM_DEBUG
file dev/drm/drm_agpsupport.c drmbase
file dev/drm/drm_auth.c drmbase
file dev/drm/drm_bufs.c drmbase
file dev/drm/drm_context.c drmbase
file dev/drm/drm_dma.c drmbase
file dev/drm/drm_drawable.c drmbase
file dev/drm/drm_drv.c drmbase
file dev/drm/drm_fops.c drmbase
file dev/drm/drm_ioctl.c drmbase
file dev/drm/drm_irq.c drmbase
file dev/drm/drm_lock.c drmbase
file dev/drm/drm_memory.c drmbase
file dev/drm/drm_pci.c drmbase
file dev/drm/drm_scatter.c drmbase
file dev/drm/drm_sysctl.c drmbase
file dev/drm/drm_vm.c drmbase

View File

@ -1,4 +1,4 @@
/* $NetBSD: agp_i810.c,v 1.36 2007/03/04 06:02:15 christos Exp $ */
/* $NetBSD: agp_i810.c,v 1.37 2007/03/20 18:05:31 drochner Exp $ */
/*-
* Copyright (c) 2000 Doug Rabson
@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: agp_i810.c,v 1.36 2007/03/04 06:02:15 christos Exp $");
__KERNEL_RCSID(0, "$NetBSD: agp_i810.c,v 1.37 2007/03/20 18:05:31 drochner Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -155,6 +155,7 @@ agp_i810_attach(struct device *parent, struct device *self, void *aux)
struct agp_i810_softc *isc;
struct agp_gatt *gatt;
int error, apbase;
bus_size_t mmadrsize;
isc = malloc(sizeof *isc, M_AGP, M_NOWAIT|M_ZERO);
if (isc == NULL) {
@ -217,6 +218,9 @@ agp_i810_attach(struct device *parent, struct device *self, void *aux)
}
if (isc->chiptype == CHIP_I915) {
pci_mapreg_info(isc->vga_pa.pa_pc, isc->vga_pa.pa_tag,
AGP_I915_MMADR, PCI_MAPREG_TYPE_MEM, NULL,
&mmadrsize, NULL);
error = pci_mapreg_map(&isc->vga_pa, AGP_I915_MMADR,
PCI_MAPREG_TYPE_MEM, 0, &isc->bst, &isc->bsh, NULL, NULL);
if (error != 0) {
@ -407,6 +411,12 @@ agp_i810_attach(struct device *parent, struct device *self, void *aux)
printf("%s: WARNING: unable to establish PCI power hook\n",
sc->as_dev.dv_xname);
/*
* another device (drm) may need access to this region
* we do not need it anymore
*/
bus_space_unmap(isc->bst, isc->bsh, mmadrsize);
return 0;
}
@ -713,6 +723,8 @@ agp_i810_bind_memory(struct agp_softc *sc, struct agp_memory *mem,
* to the GTT through the MMIO window.
* Until the issue is solved, simply restore it.
*/
#if 0
regval = bus_space_read_4(isc->bst, isc->bsh, AGP_I810_PGTBL_CTL);
if (regval != (isc->gatt->ag_physical | 1)) {
printf("agp_i810_bind_memory: PGTBL_CTL is 0x%x - fixing\n",
@ -720,6 +732,8 @@ agp_i810_bind_memory(struct agp_softc *sc, struct agp_memory *mem,
bus_space_write_4(isc->bst, isc->bsh, AGP_I810_PGTBL_CTL,
isc->gatt->ag_physical | 1);
}
#endif
regval = 0;
if (mem->am_type == 2) {
WRITEGTT(offset, mem->am_physical | 1);

View File

@ -0,0 +1,109 @@
/* ati_pcigart.h -- ATI PCI GART support -*- linux-c -*-
* Created: Wed Dec 13 21:52:19 2000 by gareth@valinux.com
*/
/*-
* 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:
* Gareth Hughes <gareth@valinux.com>
*
*/
#include <sys/cdefs.h>
/*
__FBSDID("$FreeBSD: src/sys/dev/drm/ati_pcigart.c,v 1.3 2005/11/28 23:13:52 anholt Exp $");
*/
#include "drmP.h"
#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)
{
unsigned long pages;
u32 *pci_gart = NULL, page_base;
int i, j;
if (dev->sg == NULL) {
DRM_ERROR( "no scatter/gather memory!\n" );
return 0;
}
if (gart_info->gart_table_location == DRM_ATI_GART_MAIN) {
/* GART table in system memory */
dev->sg->dmah = drm_pci_alloc(dev, ATI_PCIGART_TABLE_SIZE, 0,
0xfffffffful);
if (dev->sg->dmah == NULL) {
DRM_ERROR("cannot allocate PCI GART table!\n");
return 0;
}
gart_info->addr = (void *)dev->sg->dmah->vaddr;
gart_info->bus_addr = dev->sg->dmah->busaddr;
pci_gart = (u32 *)dev->sg->dmah->vaddr;
} else {
/* GART table in framebuffer memory */
pci_gart = gart_info->addr;
}
pages = DRM_MIN(dev->sg->pages, ATI_MAX_PCIGART_PAGES);
bzero(pci_gart, ATI_PCIGART_TABLE_SIZE);
#ifdef __FreeBSD__
KASSERT(PAGE_SIZE >= ATI_PCIGART_PAGE_SIZE, ("page size too small"));
#elif defined(__NetBSD__)
KASSERT(PAGE_SIZE >= ATI_PCIGART_PAGE_SIZE);
#endif
for ( i = 0 ; i < pages ; i++ ) {
page_base = (u32) dev->sg->busaddr[i];
for (j = 0; j < (PAGE_SIZE / ATI_PCIGART_PAGE_SIZE); j++) {
if (gart_info->is_pcie)
*pci_gart = (cpu_to_le32(page_base) >> 8) | 0xc;
else
*pci_gart = cpu_to_le32(page_base);
pci_gart++;
page_base += ATI_PCIGART_PAGE_SIZE;
}
}
DRM_MEMORYBARRIER();
return 1;
}
int drm_ati_pcigart_cleanup(drm_device_t *dev, drm_ati_pcigart_info *gart_info)
{
if (dev->sg == NULL) {
DRM_ERROR( "no scatter/gather memory!\n" );
return 0;
}
drm_pci_free(dev, dev->sg->dmah);
return 1;
}

View File

@ -0,0 +1,484 @@
/*
* $FreeBSD: src/sys/dev/drm/drm_pciids.h,v 1.7 2006/09/07 23:04:47 anholt Exp $
*/
/*
This file is auto-generated from the drm_pciids.txt in the DRM CVS
Please contact dri-devel@lists.sf.net to add new cards to this list
*/
#define radeon_PCI_IDS \
{0x1002, 0x3150, CHIP_RV380|CHIP_IS_MOBILITY, "ATI Radeon Mobility X600 M24"}, \
{0x1002, 0x3152, CHIP_RV380|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP, "ATI Radeon Mobility X300 M24"}, \
{0x1002, 0x3154, CHIP_RV380|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP, "ATI FireGL M24 GL"}, \
{0x1002, 0x3E50, CHIP_RV380|CHIP_NEW_MEMMAP, "ATI Radeon RV380 X600"}, \
{0x1002, 0x3E54, CHIP_RV380|CHIP_NEW_MEMMAP, "ATI FireGL V3200 RV380"}, \
{0x1002, 0x4136, CHIP_RS100|CHIP_IS_IGP, "ATI Radeon RS100 IGP 320"}, \
{0x1002, 0x4137, CHIP_RS200|CHIP_IS_IGP, "ATI Radeon RS200 IGP 340"}, \
{0x1002, 0x4144, CHIP_R300, "ATI Radeon AD 9500"}, \
{0x1002, 0x4145, CHIP_R300, "ATI Radeon AE 9700 Pro"}, \
{0x1002, 0x4146, CHIP_R300, "ATI Radeon AF R300 9600TX"}, \
{0x1002, 0x4147, CHIP_R300, "ATI FireGL AG Z1"}, \
{0x1002, 0x4148, CHIP_R350, "ATI Radeon AH 9800 SE"}, \
{0x1002, 0x4149, CHIP_R350, "ATI Radeon AI 9800"}, \
{0x1002, 0x414A, CHIP_R350, "ATI Radeon AJ 9800"}, \
{0x1002, 0x414B, CHIP_R350, "ATI FireGL AK X2"}, \
{0x1002, 0x4150, CHIP_RV350, "ATI Radeon AP 9600"}, \
{0x1002, 0x4151, CHIP_RV350, "ATI Radeon AQ 9600 SE"}, \
{0x1002, 0x4152, CHIP_RV350, "ATI Radeon AR 9600 XT"}, \
{0x1002, 0x4153, CHIP_RV350, "ATI Radeon AS 9550"}, \
{0x1002, 0x4154, CHIP_RV350, "ATI FireGL AT T2"}, \
{0x1002, 0x4155, CHIP_RV350, "ATI Radeon 9650"}, \
{0x1002, 0x4156, CHIP_RV350, "ATI FireGL AV RV360 T2"}, \
{0x1002, 0x4237, CHIP_RS200|CHIP_IS_IGP, "ATI Radeon RS250 IGP"}, \
{0x1002, 0x4242, CHIP_R200, "ATI Radeon BB R200 AIW 8500DV"}, \
{0x1002, 0x4243, CHIP_R200, "ATI Radeon BC R200"}, \
{0x1002, 0x4336, CHIP_RS100|CHIP_IS_IGP|CHIP_IS_MOBILITY, "ATI Radeon RS100 Mobility U1"}, \
{0x1002, 0x4337, CHIP_RS200|CHIP_IS_IGP|CHIP_IS_MOBILITY, "ATI Radeon RS200 Mobility IGP 340M"}, \
{0x1002, 0x4437, CHIP_RS200|CHIP_IS_IGP|CHIP_IS_MOBILITY, "ATI Radeon RS250 Mobility IGP"}, \
{0x1002, 0x4966, CHIP_RV250, "ATI Radeon If RV250 9000"}, \
{0x1002, 0x4967, CHIP_RV250, "ATI Radeon Ig RV250 9000"}, \
{0x1002, 0x4A48, CHIP_R420|CHIP_NEW_MEMMAP, "ATI Radeon JH R420 X800"}, \
{0x1002, 0x4A49, CHIP_R420|CHIP_NEW_MEMMAP, "ATI Radeon JI R420 X800 Pro"}, \
{0x1002, 0x4A4A, CHIP_R420|CHIP_NEW_MEMMAP, "ATI Radeon JJ R420 X800 SE"}, \
{0x1002, 0x4A4B, CHIP_R420|CHIP_NEW_MEMMAP, "ATI Radeon JK R420 X800 XT"}, \
{0x1002, 0x4A4C, CHIP_R420|CHIP_NEW_MEMMAP, "ATI Radeon JL R420 X800"}, \
{0x1002, 0x4A4D, CHIP_R420|CHIP_NEW_MEMMAP, "ATI FireGL JM X3-256"}, \
{0x1002, 0x4A4E, CHIP_R420|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP, "ATI Radeon JN R420 Mobility M18"}, \
{0x1002, 0x4A4F, CHIP_R420|CHIP_NEW_MEMMAP, "ATI Radeon JO R420 X800 SE"}, \
{0x1002, 0x4A50, CHIP_R420|CHIP_NEW_MEMMAP, "ATI Radeon JP R420 X800 XT PE"}, \
{0x1002, 0x4A54, CHIP_R420|CHIP_NEW_MEMMAP, "ATI Radeon JT R420 AIW X800 VE"}, \
{0x1002, 0x4B49, CHIP_R420|CHIP_NEW_MEMMAP, "ATI Radeon R481 X850 XT"}, \
{0x1002, 0x4B4A, CHIP_R420|CHIP_NEW_MEMMAP, "ATI Radeon R481 X850 SE"}, \
{0x1002, 0x4B4B, CHIP_R420|CHIP_NEW_MEMMAP, "ATI Radeon R481 X850 Pro"}, \
{0x1002, 0x4B4C, CHIP_R420|CHIP_NEW_MEMMAP, "ATI Radeon R481 X850 XT PE"}, \
{0x1002, 0x4C57, CHIP_RV200|CHIP_IS_MOBILITY, "ATI Radeon LW RV200 Mobility 7500 M7"}, \
{0x1002, 0x4C58, CHIP_RV200|CHIP_IS_MOBILITY, "ATI Radeon LX RV200 Mobility FireGL 7800 M7"}, \
{0x1002, 0x4C59, CHIP_RV100|CHIP_IS_MOBILITY, "ATI Radeon LY RV100 Mobility M6"}, \
{0x1002, 0x4C5A, CHIP_RV100|CHIP_IS_MOBILITY, "ATI Radeon LZ RV100 Mobility M6"}, \
{0x1002, 0x4C64, CHIP_RV250|CHIP_IS_MOBILITY, "ATI Radeon Ld RV250 Mobility 9000 M9"}, \
{0x1002, 0x4C66, CHIP_RV250, "ATI Radeon Lf RV250 Mobility 9000 M9 / FireMV 2400 PCI"}, \
{0x1002, 0x4C67, CHIP_RV250|CHIP_IS_MOBILITY, "ATI Radeon Lg RV250 Mobility 9000 M9"}, \
{0x1002, 0x4E44, CHIP_R300, "ATI Radeon ND R300 9700 Pro"}, \
{0x1002, 0x4E45, CHIP_R300, "ATI Radeon NE R300 9500 Pro / 9700"}, \
{0x1002, 0x4E46, CHIP_R300, "ATI Radeon NF R300 9600TX"}, \
{0x1002, 0x4E47, CHIP_R300, "ATI Radeon NG R300 FireGL X1"}, \
{0x1002, 0x4E48, CHIP_R350, "ATI Radeon NH R350 9800 Pro"}, \
{0x1002, 0x4E49, CHIP_R350, "ATI Radeon NI R350 9800"}, \
{0x1002, 0x4E4A, CHIP_R350, "ATI Radeon NJ R360 9800 XT"}, \
{0x1002, 0x4E4B, CHIP_R350, "ATI FireGL NK X2"}, \
{0x1002, 0x4E50, CHIP_RV350|CHIP_IS_MOBILITY, "ATI Radeon RV350 Mobility 9600 M10 NP"}, \
{0x1002, 0x4E51, CHIP_RV350|CHIP_IS_MOBILITY, "ATI Radeon RV350 Mobility 9600 M10 NQ"}, \
{0x1002, 0x4E52, CHIP_RV350|CHIP_IS_MOBILITY, "ATI Radeon RV350 Mobility 9600 M11 NR"}, \
{0x1002, 0x4E53, CHIP_RV350|CHIP_IS_MOBILITY, "ATI Radeon RV350 Mobility 9600 M10 NS"}, \
{0x1002, 0x4E54, CHIP_RV350|CHIP_IS_MOBILITY, "ATI FireGL T2/T2e"}, \
{0x1002, 0x4E56, CHIP_RV350|CHIP_IS_MOBILITY, "ATI Radeon Mobility 9550"}, \
{0x1002, 0x5144, CHIP_R100|CHIP_SINGLE_CRTC, "ATI Radeon QD R100"}, \
{0x1002, 0x5145, CHIP_R100|CHIP_SINGLE_CRTC, "ATI Radeon QE R100"}, \
{0x1002, 0x5146, CHIP_R100|CHIP_SINGLE_CRTC, "ATI Radeon QF R100"}, \
{0x1002, 0x5147, CHIP_R100|CHIP_SINGLE_CRTC, "ATI Radeon QG R100"}, \
{0x1002, 0x5148, CHIP_R200, "ATI Radeon QH R200 8500"}, \
{0x1002, 0x514C, CHIP_R200, "ATI Radeon QL R200 8500 LE"}, \
{0x1002, 0x514D, CHIP_R200, "ATI Radeon QM R200 9100"}, \
{0x1002, 0x5157, CHIP_RV200, "ATI Radeon QW RV200 7500"}, \
{0x1002, 0x5158, CHIP_RV200, "ATI Radeon QX RV200 7500"}, \
{0x1002, 0x5159, CHIP_RV100, "ATI Radeon QY RV100 7000/VE"}, \
{0x1002, 0x515A, CHIP_RV100, "ATI Radeon QZ RV100 7000/VE"}, \
{0x1002, 0x515E, CHIP_RV100, "ATI ES1000 RN50"}, \
{0x1002, 0x5460, CHIP_RV380|CHIP_IS_MOBILITY, "ATI Radeon Mobility X300 M22"}, \
{0x1002, 0x5462, CHIP_RV380|CHIP_IS_MOBILITY, "ATI Radeon Mobility X600 SE M24C"}, \
{0x1002, 0x5464, CHIP_RV380|CHIP_IS_MOBILITY, "ATI FireGL M22 GL 5464"}, \
{0x1002, 0x5548, CHIP_R420|CHIP_NEW_MEMMAP, "ATI Radeon R423 X800"}, \
{0x1002, 0x5549, CHIP_R420|CHIP_NEW_MEMMAP, "ATI Radeon R423 X800 Pro"}, \
{0x1002, 0x554A, CHIP_R420|CHIP_NEW_MEMMAP, "ATI Radeon R423 X800 XT PE"}, \
{0x1002, 0x554B, CHIP_R420|CHIP_NEW_MEMMAP, "ATI Radeon R423 X800 SE"}, \
{0x1002, 0x554C, CHIP_R420|CHIP_NEW_MEMMAP, "ATI Radeon R430 X800 XTP"}, \
{0x1002, 0x554D, CHIP_R420|CHIP_NEW_MEMMAP, "ATI Radeon R430 X800 XL"}, \
{0x1002, 0x554E, CHIP_R420|CHIP_NEW_MEMMAP, "ATI Radeon R430 X800 SE"}, \
{0x1002, 0x554F, CHIP_R420|CHIP_NEW_MEMMAP, "ATI Radeon R430 X800"}, \
{0x1002, 0x5550, CHIP_R420|CHIP_NEW_MEMMAP, "ATI FireGL V7100 R423"}, \
{0x1002, 0x5551, CHIP_R420|CHIP_NEW_MEMMAP, "ATI FireGL V5100 R423 UQ"}, \
{0x1002, 0x5552, CHIP_R420|CHIP_NEW_MEMMAP, "ATI FireGL unknown R423 UR"}, \
{0x1002, 0x5554, CHIP_R420|CHIP_NEW_MEMMAP, "ATI FireGL unknown R423 UT"}, \
{0x1002, 0x564A, CHIP_RV410|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP, "ATI Mobility FireGL V5000 M26"}, \
{0x1002, 0x564B, CHIP_RV410|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP, "ATI Mobility FireGL V5000 M26"}, \
{0x1002, 0x564F, CHIP_RV410|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP, "ATI Radeon Mobility X700 XL M26"}, \
{0x1002, 0x5652, CHIP_RV410|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP, "ATI Radeon Mobility X700 M26"}, \
{0x1002, 0x5653, CHIP_RV410|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP, "ATI Radeon Mobility X700 M26"}, \
{0x1002, 0x5834, CHIP_RS300|CHIP_IS_IGP, "ATI Radeon RS300 9100 IGP"}, \
{0x1002, 0x5835, CHIP_RS300|CHIP_IS_IGP|CHIP_IS_MOBILITY, "ATI Radeon RS300 Mobility IGP"}, \
{0x1002, 0x5960, CHIP_RV280, "ATI Radeon RV280 9250"}, \
{0x1002, 0x5961, CHIP_RV280, "ATI Radeon RV280 9200"}, \
{0x1002, 0x5962, CHIP_RV280, "ATI Radeon RV280 9200"}, \
{0x1002, 0x5964, CHIP_RV280, "ATI Radeon RV280 9200 SE"}, \
{0x1002, 0x5965, CHIP_RV280, "ATI FireMV 2200 PCI"}, \
{0x1002, 0x5969, CHIP_RV100, "ATI ES1000 RN50"}, \
{0x1002, 0x5b60, CHIP_RV380|CHIP_NEW_MEMMAP, "ATI Radeon RV370 X300 SE"}, \
{0x1002, 0x5b62, CHIP_RV380|CHIP_NEW_MEMMAP, "ATI Radeon RV370 X600 Pro"}, \
{0x1002, 0x5b63, CHIP_RV380|CHIP_NEW_MEMMAP, "ATI Radeon RV370 X550"}, \
{0x1002, 0x5b64, CHIP_RV380|CHIP_NEW_MEMMAP, "ATI FireGL V3100 (RV370) 5B64"}, \
{0x1002, 0x5b65, CHIP_RV380|CHIP_NEW_MEMMAP, "ATI FireMV 2200 PCIE (RV370) 5B65"}, \
{0x1002, 0x5c61, CHIP_RV280|CHIP_IS_MOBILITY, "ATI Radeon RV280 Mobility"}, \
{0x1002, 0x5c63, CHIP_RV280|CHIP_IS_MOBILITY, "ATI Radeon RV280 Mobility"}, \
{0x1002, 0x5d48, CHIP_R420|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP, "ATI Mobility Radeon X800 XT M28"}, \
{0x1002, 0x5d49, CHIP_R420|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP, "ATI Mobility FireGL V5100 M28"}, \
{0x1002, 0x5d4a, CHIP_R420|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP, "ATI Mobility Radeon X800 M28"}, \
{0x1002, 0x5d4c, CHIP_R420|CHIP_NEW_MEMMAP, "ATI Radeon R480 X850"}, \
{0x1002, 0x5d4d, CHIP_R420|CHIP_NEW_MEMMAP, "ATI Radeon R480 X850 XT PE"}, \
{0x1002, 0x5d4e, CHIP_R420|CHIP_NEW_MEMMAP, "ATI Radeon R480 X850 SE"}, \
{0x1002, 0x5d4f, CHIP_R420|CHIP_NEW_MEMMAP, "ATI Radeon R480 X850 Pro"}, \
{0x1002, 0x5d50, CHIP_R420|CHIP_NEW_MEMMAP, "ATI unknown Radeon / FireGL R480"}, \
{0x1002, 0x5d52, CHIP_R420|CHIP_NEW_MEMMAP, "ATI Radeon R480 X850 XT"}, \
{0x1002, 0x5d57, CHIP_R420|CHIP_NEW_MEMMAP, "ATI Radeon R423 X800 XT"}, \
{0x1002, 0x5e48, CHIP_RV410|CHIP_NEW_MEMMAP, "ATI FireGL V5000 RV410"}, \
{0x1002, 0x5e4a, CHIP_RV410|CHIP_NEW_MEMMAP, "ATI Radeon RV410 X700 XT"}, \
{0x1002, 0x5e4b, CHIP_RV410|CHIP_NEW_MEMMAP, "ATI Radeon RV410 X700 Pro"}, \
{0x1002, 0x5e4c, CHIP_RV410|CHIP_NEW_MEMMAP, "ATI Radeon RV410 X700 SE"}, \
{0x1002, 0x5e4d, CHIP_RV410|CHIP_NEW_MEMMAP, "ATI Radeon RV410 X700"}, \
{0x1002, 0x5e4f, CHIP_RV410|CHIP_NEW_MEMMAP, "ATI Radeon RV410 X700 SE"}, \
{0x1002, 0x7834, CHIP_RS300|CHIP_IS_IGP|CHIP_NEW_MEMMAP, "ATI Radeon RS350 9000/9100 IGP"}, \
{0x1002, 0x7835, CHIP_RS300|CHIP_IS_IGP|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP, "ATI Radeon RS350 Mobility IGP"}, \
{0, 0, 0, NULL}
#define r128_PCI_IDS \
{0x1002, 0x4c45, 0, "ATI Rage 128 Mobility LE (PCI)"}, \
{0x1002, 0x4c46, 0, "ATI Rage 128 Mobility LF (AGP)"}, \
{0x1002, 0x4d46, 0, "ATI Rage 128 Mobility MF (AGP)"}, \
{0x1002, 0x4d4c, 0, "ATI Rage 128 Mobility ML (AGP)"}, \
{0x1002, 0x5041, 0, "ATI Rage 128 Pro PA (PCI)"}, \
{0x1002, 0x5042, 0, "ATI Rage 128 Pro PB (AGP)"}, \
{0x1002, 0x5043, 0, "ATI Rage 128 Pro PC (AGP)"}, \
{0x1002, 0x5044, 0, "ATI Rage 128 Pro PD (PCI)"}, \
{0x1002, 0x5045, 0, "ATI Rage 128 Pro PE (AGP)"}, \
{0x1002, 0x5046, 0, "ATI Rage 128 Pro PF (AGP)"}, \
{0x1002, 0x5047, 0, "ATI Rage 128 Pro PG (PCI)"}, \
{0x1002, 0x5048, 0, "ATI Rage 128 Pro PH (AGP)"}, \
{0x1002, 0x5049, 0, "ATI Rage 128 Pro PI (AGP)"}, \
{0x1002, 0x504A, 0, "ATI Rage 128 Pro PJ (PCI)"}, \
{0x1002, 0x504B, 0, "ATI Rage 128 Pro PK (AGP)"}, \
{0x1002, 0x504C, 0, "ATI Rage 128 Pro PL (AGP)"}, \
{0x1002, 0x504D, 0, "ATI Rage 128 Pro PM (PCI)"}, \
{0x1002, 0x504E, 0, "ATI Rage 128 Pro PN (AGP)"}, \
{0x1002, 0x504F, 0, "ATI Rage 128 Pro PO (AGP)"}, \
{0x1002, 0x5050, 0, "ATI Rage 128 Pro PP (PCI)"}, \
{0x1002, 0x5051, 0, "ATI Rage 128 Pro PQ (AGP)"}, \
{0x1002, 0x5052, 0, "ATI Rage 128 Pro PR (PCI)"}, \
{0x1002, 0x5053, 0, "ATI Rage 128 Pro PS (PCI)"}, \
{0x1002, 0x5054, 0, "ATI Rage 128 Pro PT (AGP)"}, \
{0x1002, 0x5055, 0, "ATI Rage 128 Pro PU (AGP)"}, \
{0x1002, 0x5056, 0, "ATI Rage 128 Pro PV (PCI)"}, \
{0x1002, 0x5057, 0, "ATI Rage 128 Pro PW (AGP)"}, \
{0x1002, 0x5058, 0, "ATI Rage 128 Pro PX (AGP)"}, \
{0x1002, 0x5245, 0, "ATI Rage 128 RE (PCI)"}, \
{0x1002, 0x5246, 0, "ATI Rage 128 RF (AGP)"}, \
{0x1002, 0x5247, 0, "ATI Rage 128 RG (AGP)"}, \
{0x1002, 0x524b, 0, "ATI Rage 128 RK (PCI)"}, \
{0x1002, 0x524c, 0, "ATI Rage 128 RL (AGP)"}, \
{0x1002, 0x534d, 0, "ATI Rage 128 SM (AGP)"}, \
{0x1002, 0x5446, 0, "ATI Rage 128 Pro Ultra TF (AGP)"}, \
{0x1002, 0x544C, 0, "ATI Rage 128 Pro Ultra TL (AGP)"}, \
{0x1002, 0x5452, 0, "ATI Rage 128 Pro Ultra TR (AGP)"}, \
{0, 0, 0, NULL}
#define mga_PCI_IDS \
{0x102b, 0x0520, MGA_CARD_TYPE_G200, "Matrox G200 (PCI)"}, \
{0x102b, 0x0521, MGA_CARD_TYPE_G200, "Matrox G200 (AGP)"}, \
{0x102b, 0x0525, MGA_CARD_TYPE_G400, "Matrox G400/G450 (AGP)"}, \
{0x102b, 0x2527, MGA_CARD_TYPE_G550, "Matrox G550 (AGP)"}, \
{0, 0, 0, NULL}
#define mach64_PCI_IDS \
{0x1002, 0x4749, 0, "3D Rage Pro"}, \
{0x1002, 0x4750, 0, "3D Rage Pro 215GP"}, \
{0x1002, 0x4751, 0, "3D Rage Pro 215GQ"}, \
{0x1002, 0x4742, 0, "3D Rage Pro AGP 1X/2X"}, \
{0x1002, 0x4744, 0, "3D Rage Pro AGP 1X"}, \
{0x1002, 0x4c49, 0, "3D Rage LT Pro"}, \
{0x1002, 0x4c50, 0, "3D Rage LT Pro"}, \
{0x1002, 0x4c51, 0, "3D Rage LT Pro"}, \
{0x1002, 0x4c42, 0, "3D Rage LT Pro AGP-133"}, \
{0x1002, 0x4c44, 0, "3D Rage LT Pro AGP-66"}, \
{0x1002, 0x474c, 0, "Rage XC"}, \
{0x1002, 0x474f, 0, "Rage XL"}, \
{0x1002, 0x4752, 0, "Rage XL"}, \
{0x1002, 0x4753, 0, "Rage XC"}, \
{0x1002, 0x474d, 0, "Rage XL AGP 2X"}, \
{0x1002, 0x474e, 0, "Rage XC AGP"}, \
{0x1002, 0x4c52, 0, "Rage Mobility P/M"}, \
{0x1002, 0x4c53, 0, "Rage Mobility L"}, \
{0x1002, 0x4c4d, 0, "Rage Mobility P/M AGP 2X"}, \
{0x1002, 0x4c4e, 0, "Rage Mobility L AGP 2X"}, \
{0, 0, 0, NULL}
#define sis_PCI_IDS \
{0x1039, 0x0300, 0, "SiS 300/305"}, \
{0x1039, 0x5300, 0, "SiS 540"}, \
{0x1039, 0x6300, 0, "SiS 630"}, \
{0x1039, 0x7300, 0, "SiS 730"}, \
{0, 0, 0, NULL}
#define tdfx_PCI_IDS \
{0x121a, 0x0003, 0, "3dfx Voodoo Banshee"}, \
{0x121a, 0x0004, 0, "3dfx Voodoo3 2000"}, \
{0x121a, 0x0005, 0, "3dfx Voodoo3 3000"}, \
{0x121a, 0x0007, 0, "3dfx Voodoo4 4500"}, \
{0x121a, 0x0009, 0, "3dfx Voodoo5 5500"}, \
{0x121a, 0x000b, 0, "3dfx Voodoo4 4200"}, \
{0, 0, 0, NULL}
#define viadrv_PCI_IDS \
{0x1106, 0x3022, 0, "VIA CLE266 3022"}, \
{0x1106, 0x3118, VIA_PRO_GROUP_A, "VIA CN400 / PM8X0"}, \
{0x1106, 0x3122, 0, "VIA CLE266"}, \
{0x1106, 0x7205, 0, "VIA KM400"}, \
{0x1106, 0x3108, 0, "VIA K8M800"}, \
{0x1106, 0x3344, 0, "VIA P4VM800PRO"}, \
{0, 0, 0, NULL}
#define i810_PCI_IDS \
{0x8086, 0x7121, 0, "Intel i810 GMCH"}, \
{0x8086, 0x7123, 0, "Intel i810-DC100 GMCH"}, \
{0x8086, 0x7125, 0, "Intel i810E GMCH"}, \
{0x8086, 0x1132, 0, "Intel i815 GMCH"}, \
{0, 0, 0, NULL}
#define i830_PCI_IDS \
{0x8086, 0x3577, 0, "Intel i830M GMCH"}, \
{0x8086, 0x2562, 0, "Intel i845G GMCH"}, \
{0x8086, 0x3582, 0, "Intel i852GM/i855GM GMCH"}, \
{0x8086, 0x2572, 0, "Intel i865G GMCH"}, \
{0, 0, 0, NULL}
#define gamma_PCI_IDS \
{0x3d3d, 0x0008, 0, "3DLabs GLINT Gamma G1"}, \
{0, 0, 0, NULL}
#define savage_PCI_IDS \
{0x5333, 0x8a20, S3_SAVAGE3D, "Savage 3D"}, \
{0x5333, 0x8a21, S3_SAVAGE3D, "Savage 3D/MV"}, \
{0x5333, 0x8a22, S3_SAVAGE4, "Savage4"}, \
{0x5333, 0x8a23, S3_SAVAGE4, "Savage4"}, \
{0x5333, 0x8c10, S3_SAVAGE_MX, "Savage/MX-MV"}, \
{0x5333, 0x8c11, S3_SAVAGE_MX, "Savage/MX"}, \
{0x5333, 0x8c12, S3_SAVAGE_MX, "Savage/IX-MV"}, \
{0x5333, 0x8c13, S3_SAVAGE_MX, "Savage/IX"}, \
{0x5333, 0x8c22, S3_SUPERSAVAGE, "SuperSavage MX/128"}, \
{0x5333, 0x8c24, S3_SUPERSAVAGE, "SuperSavage MX/64"}, \
{0x5333, 0x8c26, S3_SUPERSAVAGE, "SuperSavage MX/64C"}, \
{0x5333, 0x8c2a, S3_SUPERSAVAGE, "SuperSavage IX/128 SDR"}, \
{0x5333, 0x8c2b, S3_SUPERSAVAGE, "SuperSavage IX/128 DDR"}, \
{0x5333, 0x8c2c, S3_SUPERSAVAGE, "SuperSavage IX/64 SDR"}, \
{0x5333, 0x8c2d, S3_SUPERSAVAGE, "SuperSavage IX/64 DDR"}, \
{0x5333, 0x8c2e, S3_SUPERSAVAGE, "SuperSavage IX/C SDR"}, \
{0x5333, 0x8c2f, S3_SUPERSAVAGE, "SuperSavage IX/C DDR"}, \
{0x5333, 0x8a25, S3_PROSAVAGE, "ProSavage PM133"}, \
{0x5333, 0x8a26, S3_PROSAVAGE, "ProSavage KM133"}, \
{0x5333, 0x8d01, S3_TWISTER, "ProSavage Twister PN133"}, \
{0x5333, 0x8d02, S3_TWISTER, "ProSavage Twister KN133"}, \
{0x5333, 0x8d03, S3_PROSAVAGEDDR, "ProSavage DDR"}, \
{0x5333, 0x8d04, S3_PROSAVAGEDDR, "ProSavage DDR-K"}, \
{0, 0, 0, NULL}
#define ffb_PCI_IDS \
{0, 0, 0, NULL}
#define i915_PCI_IDS \
{0x8086, 0x3577, 0, "Intel i830M GMCH"}, \
{0x8086, 0x2562, 0, "Intel i845G GMCH"}, \
{0x8086, 0x3582, 0, "Intel i852GM/i855GM GMCH"}, \
{0x8086, 0x2572, 0, "Intel i865G GMCH"}, \
{0x8086, 0x2582, 0, "Intel i915G"}, \
{0x8086, 0x2592, 0, "Intel i915GM"}, \
{0x8086, 0x2772, 0, "Intel i945G"}, \
{0x8086, 0x27A2, 0, "Intel i945GM"}, \
{0x8086, 0x2972, 0, "Intel i946GZ"}, \
{0x8086, 0x2982, 0, "Intel i965G"}, \
{0x8086, 0x2992, 0, "Intel i965Q"}, \
{0x8086, 0x29A2, 0, "Intel i965G"}, \
{0, 0, 0, NULL}
#define imagine_PCI_IDS \
{0x105d, 0x2309, IMAGINE_128, "Imagine 128"}, \
{0x105d, 0x2339, IMAGINE_128_2, "Imagine 128-II"}, \
{0x105d, 0x493d, IMAGINE_T2R, "Ticket to Ride"}, \
{0x105d, 0x5348, IMAGINE_REV4, "Revolution IV"}, \
{0, 0, 0, NULL}
#define nv_PCI_IDS \
{0x10DE, 0x0020, NV04, "NVidia RIVA TNT"}, \
{0x10DE, 0x0028, NV04, "NVidia RIVA TNT2"}, \
{0x10DE, 0x002A, NV04, "NVidia Unknown TNT2"}, \
{0x10DE, 0x002C, NV04, "NVidia Vanta"}, \
{0x10DE, 0x0029, NV04, "NVidia RIVA TNT2 Ultra"}, \
{0x10DE, 0x002D, NV04, "NVidia RIVA TNT2 Model 64"}, \
{0x10DE, 0x00A0, NV04, "NVidia Aladdin TNT2"}, \
{0x10DE, 0x0100, NV10, "NVidia GeForce 256"}, \
{0x10DE, 0x0101, NV10, "NVidia GeForce DDR"}, \
{0x10DE, 0x0103, NV10, "NVidia Quadro"}, \
{0x10DE, 0x0110, NV10, "NVidia GeForce2 MX/MX 400"}, \
{0x10DE, 0x0111, NV10, "NVidia GeForce2 MX 100/200"}, \
{0x10DE, 0x0112, NV10, "NVidia GeForce2 Go"}, \
{0x10DE, 0x0113, NV10, "NVidia Quadro2 MXR/EX/Go"}, \
{0x10DE, 0x0150, NV10, "NVidia GeForce2 GTS"}, \
{0x10DE, 0x0151, NV10, "NVidia GeForce2 Ti"}, \
{0x10DE, 0x0152, NV10, "NVidia GeForce2 Ultra"}, \
{0x10DE, 0x0153, NV10, "NVidia Quadro2 Pro"}, \
{0x10DE, 0x0170, NV10, "NVidia GeForce4 MX 460"}, \
{0x10DE, 0x0171, NV10, "NVidia GeForce4 MX 440"}, \
{0x10DE, 0x0172, NV10, "NVidia GeForce4 MX 420"}, \
{0x10DE, 0x0173, NV10, "NVidia GeForce4 MX 440-SE"}, \
{0x10DE, 0x0174, NV10, "NVidia GeForce4 440 Go"}, \
{0x10DE, 0x0175, NV10, "NVidia GeForce4 420 Go"}, \
{0x10DE, 0x0176, NV10, "NVidia GeForce4 420 Go 32M"}, \
{0x10DE, 0x0177, NV10, "NVidia GeForce4 460 Go"}, \
{0x10DE, 0x0178, NV10, "NVidia Quadro4 550 XGL"}, \
{0x10DE, 0x0179, NV10, "NVidia GeForce4"}, \
{0x10DE, 0x017A, NV10, "NVidia Quadro4 NVS"}, \
{0x10DE, 0x017C, NV10, "NVidia Quadro4 500 GoGL"}, \
{0x10DE, 0x017D, NV10, "NVidia GeForce4 410 Go 16M"}, \
{0x10DE, 0x0181, NV10, "NVidia GeForce4 MX 440 with AGP8X"}, \
{0x10DE, 0x0182, NV10, "NVidia GeForce4 MX 440SE with AGP8X"}, \
{0x10DE, 0x0183, NV10, "NVidia GeForce4 MX 420 with AGP8X"}, \
{0x10DE, 0x0185, NV10, "NVidia GeForce4 MX 4000"}, \
{0x10DE, 0x0186, NV10, "NVidia GeForce4 448 Go"}, \
{0x10DE, 0x0187, NV10, "NVidia GeForce4 488 Go"}, \
{0x10DE, 0x0188, NV10, "NVidia Quadro4 580 XGL"}, \
{0x10DE, 0x0189, NV10, "NVidia GeForce4 MX with AGP8X (Mac)"}, \
{0x10DE, 0x018A, NV10, "NVidia Quadro4 280 NVS"}, \
{0x10DE, 0x018B, NV10, "NVidia Quadro4 380 XGL"}, \
{0x10DE, 0x018C, NV10, "NVidia Quadro NVS 50 PCI"}, \
{0x10DE, 0x018D, NV10, "NVidia GeForce4 448 Go"}, \
{0x10DE, 0x01A0, NV10, "NVidia GeForce2 Integrated GPU"}, \
{0x10DE, 0x01F0, NV10, "NVidia GeForce4 MX Integrated GPU"}, \
{0x10DE, 0x0200, NV20, "NVidia GeForce3"}, \
{0x10DE, 0x0201, NV20, "NVidia GeForce3 Ti 200"}, \
{0x10DE, 0x0202, NV20, "NVidia GeForce3 Ti 500"}, \
{0x10DE, 0x0203, NV20, "NVidia Quadro DCC"}, \
{0x10DE, 0x0250, NV20, "NVidia GeForce4 Ti 4600"}, \
{0x10DE, 0x0251, NV20, "NVidia GeForce4 Ti 4400"}, \
{0x10DE, 0x0252, NV20, "NVidia 0x0252"}, \
{0x10DE, 0x0253, NV20, "NVidia GeForce4 Ti 4200"}, \
{0x10DE, 0x0258, NV20, "NVidia Quadro4 900 XGL"}, \
{0x10DE, 0x0259, NV20, "NVidia Quadro4 750 XGL"}, \
{0x10DE, 0x025B, NV20, "NVidia Quadro4 700 XGL"}, \
{0x10DE, 0x0280, NV20, "NVidia GeForce4 Ti 4800"}, \
{0x10DE, 0x0281, NV20, "NVidia GeForce4 Ti 4200 with AGP8X"}, \
{0x10DE, 0x0282, NV20, "NVidia GeForce4 Ti 4800 SE"}, \
{0x10DE, 0x0286, NV20, "NVidia GeForce4 4200 Go"}, \
{0x10DE, 0x028C, NV20, "NVidia Quadro4 700 GoGL"}, \
{0x10DE, 0x0288, NV20, "NVidia Quadro4 980 XGL"}, \
{0x10DE, 0x0289, NV20, "NVidia Quadro4 780 XGL"}, \
{0x10DE, 0x0301, NV30, "NVidia GeForce FX 5800 Ultra"}, \
{0x10DE, 0x0302, NV30, "NVidia GeForce FX 5800"}, \
{0x10DE, 0x0308, NV30, "NVidia Quadro FX 2000"}, \
{0x10DE, 0x0309, NV30, "NVidia Quadro FX 1000"}, \
{0x10DE, 0x0311, NV30, "NVidia GeForce FX 5600 Ultra"}, \
{0x10DE, 0x0312, NV30, "NVidia GeForce FX 5600"}, \
{0x10DE, 0x0313, NV30, "NVidia 0x0313"},}, \
{0x10DE, 0x0314, NV30, "NVidia GeForce FX 5600SE"}, \
{0x10DE, 0x0316, NV30, "NVidia 0x0316"}, \
{0x10DE, 0x0317, NV30, "NVidia 0x0317"}, \
{0x10DE, 0x031A, NV30, "NVidia GeForce FX Go5600"}, \
{0x10DE, 0x031B, NV30, "NVidia GeForce FX Go5650"}, \
{0x10DE, 0x031C, NV30, "NVidia Quadro FX Go700"}, \
{0x10DE, 0x031D, NV30, "NVidia 0x031D"}, \
{0x10DE, 0x031E, NV30, "NVidia 0x031E"}, \
{0x10DE, 0x031F, NV30, "NVidia 0x031F"}, \
{0x10DE, 0x0320, NV30, "NVidia GeForce FX 5200"}, \
{0x10DE, 0x0321, NV30, "NVidia GeForce FX 5200 Ultra"}, \
{0x10DE, 0x0322, NV30, "NVidia GeForce FX 5200"}, \
{0x10DE, 0x0323, NV30, "NVidia GeForce FX 5200SE"}, \
{0x10DE, 0x0324, NV30, "NVidia GeForce FX Go5200"}, \
{0x10DE, 0x0325, NV30, "NVidia GeForce FX Go5250"}, \
{0x10DE, 0x0326, NV30, "NVidia GeForce FX 5500"}, \
{0x10DE, 0x0327, NV30, "NVidia GeForce FX 5100"}, \
{0x10DE, 0x0328, NV30, "NVidia GeForce FX Go5200 32M/64M"}, \
{0x10DE, 0x0329, NV30, "NVidia GeForce FX 5200 (Mac)"}, \
{0x10DE, 0x032A, NV30, "NVidia Quadro NVS 280 PCI"}, \
{0x10DE, 0x032B, NV30, "NVidia Quadro FX 500/600 PCI"}, \
{0x10DE, 0x032C, NV30, "NVidia GeForce FX Go53xx Series"}, \
{0x10DE, 0x032D, NV30, "NVidia GeForce FX Go5100"}, \
{0x10DE, 0x032F, NV30, "NVidia 0x032F"}, \
{0x10DE, 0x0330, NV30, "NVidia GeForce FX 5900 Ultra"}, \
{0x10DE, 0x0331, NV30, "NVidia GeForce FX 5900"}, \
{0x10DE, 0x0332, NV30, "NVidia GeForce FX 5900XT"}, \
{0x10DE, 0x0333, NV30, "NVidia GeForce FX 5950 Ultra"}, \
{0x10DE, 0x033F, NV30, "NVidia Quadro FX 700"}, \
{0x10DE, 0x0334, NV30, "NVidia GeForce FX 5900ZT"}, \
{0x10DE, 0x0338, NV30, "NVidia Quadro FX 3000"}, \
{0x10DE, 0x0341, NV30, "NVidia GeForce FX 5700 Ultra"}, \
{0x10DE, 0x0342, NV30, "NVidia GeForce FX 5700"}, \
{0x10DE, 0x0343, NV30, "NVidia GeForce FX 5700LE"}, \
{0x10DE, 0x0344, NV30, "NVidia GeForce FX 5700VE"}, \
{0x10DE, 0x0345, NV30, "NVidia 0x0345"}, \
{0x10DE, 0x0347, NV30, "NVidia GeForce FX Go5700"}, \
{0x10DE, 0x0348, NV30, "NVidia GeForce FX Go5700"}, \
{0x10DE, 0x0349, NV30, "NVidia 0x0349"}, \
{0x10DE, 0x034B, NV30, "NVidia 0x034B"}, \
{0x10DE, 0x034C, NV30, "NVidia Quadro FX Go1000"}, \
{0x10DE, 0x034E, NV30, "NVidia Quadro FX 1100"}, \
{0x10DE, 0x034F, NV30, "NVidia 0x034F"}, \
{0x10DE, 0x0040, NV40, "NVidia GeForce 6800 Ultra"}, \
{0x10DE, 0x0041, NV40, "NVidia GeForce 6800"}, \
{0x10DE, 0x0042, NV40, "NVidia GeForce 6800 LE"}, \
{0x10DE, 0x0043, NV40, "NVidia 0x0043"}, \
{0x10DE, 0x0045, NV40, "NVidia GeForce 6800 GT"}, \
{0x10DE, 0x0046, NV40, "NVidia GeForce 6800 GT"}, \
{0x10DE, 0x0049, NV40, "NVidia 0x0049"}, \
{0x10DE, 0x004E, NV40, "NVidia Quadro FX 4000"}, \
{0x10DE, 0x00C0, NV40, "NVidia 0x00C0"}, \
{0x10DE, 0x00C1, NV40, "NVidia GeForce 6800"}, \
{0x10DE, 0x00C2, NV40, "NVidia GeForce 6800 LE"}, \
{0x10DE, 0x00C8, NV40, "NVidia GeForce Go 6800"}, \
{0x10DE, 0x00C9, NV40, "NVidia GeForce Go 6800 Ultra"}, \
{0x10DE, 0x00CC, NV40, "NVidia Quadro FX Go1400"}, \
{0x10DE, 0x00CD, NV40, "NVidia Quadro FX 3450/4000 SDI"}, \
{0x10DE, 0x00CE, NV40, "NVidia Quadro FX 1400"}, \
{0x10de, 0x00f0, NV40, "Nvidia GeForce 6600 GT"}, \
{0x10de, 0x00f1, NV40, "Nvidia GeForce 6600 GT"}, \
{0x10DE, 0x0140, NV40, "NVidia GeForce 6600 GT"}, \
{0x10DE, 0x0141, NV40, "NVidia GeForce 6600"}, \
{0x10DE, 0x0142, NV40, "NVidia GeForce 6600 LE"}, \
{0x10DE, 0x0143, NV40, "NVidia 0x0143"}, \
{0x10DE, 0x0144, NV40, "NVidia GeForce Go 6600"}, \
{0x10DE, 0x0145, NV40, "NVidia GeForce 6610 XL"}, \
{0x10DE, 0x0146, NV40, "NVidia GeForce Go 6600 TE/6200 TE"}, \
{0x10DE, 0x0147, NV40, "NVidia GeForce 6700 XL"}, \
{0x10DE, 0x0148, NV40, "NVidia GeForce Go 6600"}, \
{0x10DE, 0x0149, NV40, "NVidia GeForce Go 6600 GT"}, \
{0x10DE, 0x014B, NV40, "NVidia 0x014B"}, \
{0x10DE, 0x014C, NV40, "NVidia 0x014C"}, \
{0x10DE, 0x014D, NV40, "NVidia 0x014D"}, \
{0x10DE, 0x014E, NV40, "NVidia Quadro FX 540"}, \
{0x10DE, 0x014F, NV40, "NVidia GeForce 6200"}, \
{0x10DE, 0x0160, NV40, "NVidia 0x0160"}, \
{0x10DE, 0x0161, NV40, "NVidia GeForce 6200 TurboCache(TM)"}, \
{0x10DE, 0x0162, NV40, "NVidia GeForce 6200SE TurboCache(TM)"}, \
{0x10DE, 0x0163, NV40, "NVidia 0x0163"}, \
{0x10DE, 0x0164, NV40, "NVidia GeForce Go 6200"}, \
{0x10DE, 0x0165, NV40, "NVidia Quadro NVS 285"}, \
{0x10DE, 0x0166, NV40, "NVidia GeForce Go 6400"}, \
{0x10DE, 0x0167, NV40, "NVidia GeForce Go 6200"}, \
{0x10DE, 0x0168, NV40, "NVidia GeForce Go 6400"}, \
{0x10DE, 0x0169, NV40, "NVidia 0x0169"}, \
{0x10DE, 0x016B, NV40, "NVidia 0x016B"}, \
{0x10DE, 0x016C, NV40, "NVidia 0x016C"}, \
{0x10DE, 0x016D, NV40, "NVidia 0x016D"}, \
{0x10DE, 0x016E, NV40, "NVidia 0x016E"}, \
{0x10DE, 0x0210, NV40, "NVidia 0x0210"}, \
{0x10DE, 0x0211, NV40, "NVidia GeForce 6800"}, \
{0x10DE, 0x0212, NV40, "NVidia GeForce 6800 LE"}, \
{0x10DE, 0x0215, NV40, "NVidia GeForce 6800 GT"}, \
{0x10DE, 0x0220, NV40, "NVidia 0x0220"}, \
{0x10DE, 0x0221, NV40, "NVidia GeForce 6200"}, \
{0x10DE, 0x0222, NV40, "NVidia 0x0222"}, \
{0x10DE, 0x0228, NV40, "NVidia 0x0228"}, \
{0x10DE, 0x0090, NV40, "NVidia 0x0090"}, \
{0x10DE, 0x0091, NV40, "NVidia GeForce 7800 GTX"}, \
{0x10DE, 0x0092, NV40, "NVidia 0x0092"}, \
{0x10DE, 0x0093, NV40, "NVidia 0x0093"}, \
{0x10DE, 0x0094, NV40, "NVidia 0x0094"}, \
{0x10DE, 0x0098, NV40, "NVidia 0x0098"}, \
{0x10DE, 0x0099, NV40, "NVidia GeForce Go 7800 GTX"}, \
{0x10DE, 0x009C, NV40, "NVidia 0x009C"}, \
{0x10DE, 0x009D, NV40, "NVidia Quadro FX 4500"}, \
{0x10DE, 0x009E, NV40, "NVidia 0x009E"}, \
{0, 0, 0, NULL}

823
sys/dev/pci/drm/i915_dma.c Normal file
View File

@ -0,0 +1,823 @@
/* i915_dma.c -- DMA support for the I915 -*- linux-c -*-
*/
/*-
* Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
* 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 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.
*
*/
#include <sys/cdefs.h>
/*
__FBSDID("$FreeBSD: src/sys/dev/drm/i915_dma.c,v 1.4 2006/09/07 23:04:47 anholt Exp $");
*/
#include <dev/drm/drmP.h>
#include <dev/drm/drm.h>
#include "i915_drm.h"
#include "i915_drv.h"
#define IS_I965G(dev) (dev->pci_device == 0x2972 || \
dev->pci_device == 0x2982 || \
dev->pci_device == 0x2992 || \
dev->pci_device == 0x29A2)
/* Really want an OS-independent resettable timer. Would like to have
* this loop run for (eg) 3 sec, but have the timer reset every time
* the head pointer changes, so that EBUSY only happens if the ring
* actually stalls for (eg) 3 seconds.
*/
int i915_wait_ring(drm_device_t * dev, int n, const char *caller)
{
drm_i915_private_t *dev_priv = dev->dev_private;
drm_i915_ring_buffer_t *ring = &(dev_priv->ring);
u32 last_head = I915_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
int i;
for (i = 0; i < 10000; i++) {
ring->head = I915_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
ring->space = ring->head - (ring->tail + 8);
if (ring->space < 0)
ring->space += ring->Size;
if (ring->space >= n)
return 0;
dev_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT;
if (ring->head != last_head)
i = 0;
last_head = ring->head;
}
return DRM_ERR(EBUSY);
}
void i915_kernel_lost_context(drm_device_t * dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
drm_i915_ring_buffer_t *ring = &(dev_priv->ring);
ring->head = I915_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
ring->tail = I915_READ(LP_RING + RING_TAIL) & TAIL_ADDR;
ring->space = ring->head - (ring->tail + 8);
if (ring->space < 0)
ring->space += ring->Size;
if (ring->head == ring->tail)
dev_priv->sarea_priv->perf_boxes |= I915_BOX_RING_EMPTY;
}
static int i915_dma_cleanup(drm_device_t * dev)
{
/* Make sure interrupts are disabled here because the uninstall ioctl
* may not have been called from userspace and after dev_private
* is freed, it's too late.
*/
if (dev->irq)
drm_irq_uninstall(dev);
if (dev->dev_private) {
drm_i915_private_t *dev_priv =
(drm_i915_private_t *) dev->dev_private;
if (dev_priv->ring.virtual_start) {
drm_core_ioremapfree(&dev_priv->ring.map, dev);
}
if (dev_priv->status_page_dmah) {
drm_pci_free(dev, dev_priv->status_page_dmah);
/* Need to rewrite hardware status page */
I915_WRITE(0x02080, 0x1ffff000);
}
drm_free(dev->dev_private, sizeof(drm_i915_private_t),
DRM_MEM_DRIVER);
dev->dev_private = NULL;
}
return 0;
}
static int i915_initialize(drm_device_t * dev,
drm_i915_private_t * dev_priv,
drm_i915_init_t * init)
{
memset(dev_priv, 0, sizeof(drm_i915_private_t));
DRM_GETSAREA();
if (!dev_priv->sarea) {
DRM_ERROR("can not find sarea!\n");
dev->dev_private = (void *)dev_priv;
i915_dma_cleanup(dev);
return DRM_ERR(EINVAL);
}
dev_priv->mmio_map = drm_core_findmap(dev, init->mmio_offset);
if (!dev_priv->mmio_map) {
dev->dev_private = (void *)dev_priv;
i915_dma_cleanup(dev);
DRM_ERROR("can not find mmio map!\n");
return DRM_ERR(EINVAL);
}
dev_priv->sarea_priv = (drm_i915_sarea_t *)
((u8 *) dev_priv->sarea->handle + init->sarea_priv_offset);
dev_priv->ring.Start = init->ring_start;
dev_priv->ring.End = init->ring_end;
dev_priv->ring.Size = init->ring_size;
dev_priv->ring.tail_mask = dev_priv->ring.Size - 1;
dev_priv->ring.map.offset = init->ring_start;
dev_priv->ring.map.size = init->ring_size;
dev_priv->ring.map.type = 0;
dev_priv->ring.map.flags = 0;
dev_priv->ring.map.mtrr = 0;
drm_core_ioremap(&dev_priv->ring.map, dev);
if (dev_priv->ring.map.handle == NULL) {
dev->dev_private = (void *)dev_priv;
i915_dma_cleanup(dev);
DRM_ERROR("can not ioremap virtual address for"
" ring buffer\n");
return DRM_ERR(ENOMEM);
}
dev_priv->ring.virtual_start = dev_priv->ring.map.handle;
dev_priv->back_offset = init->back_offset;
dev_priv->front_offset = init->front_offset;
dev_priv->current_page = 0;
dev_priv->sarea_priv->pf_current_page = dev_priv->current_page;
/* We are using separate values as placeholders for mechanisms for
* private backbuffer/depthbuffer usage.
*/
dev_priv->use_mi_batchbuffer_start = 0;
/* Allow hardware batchbuffers unless told otherwise.
*/
dev_priv->allow_batchbuffer = 1;
/* Program Hardware Status Page */
dev_priv->status_page_dmah = drm_pci_alloc(dev, PAGE_SIZE, PAGE_SIZE,
0xffffffff);
if (!dev_priv->status_page_dmah) {
dev->dev_private = (void *)dev_priv;
i915_dma_cleanup(dev);
DRM_ERROR("Can not allocate hardware status page\n");
return DRM_ERR(ENOMEM);
}
dev_priv->hw_status_page = dev_priv->status_page_dmah->vaddr;
dev_priv->dma_status_page = dev_priv->status_page_dmah->busaddr;
memset(dev_priv->hw_status_page, 0, PAGE_SIZE);
DRM_DEBUG("hw status page @ %p\n", dev_priv->hw_status_page);
I915_WRITE(0x02080, dev_priv->dma_status_page);
DRM_DEBUG("Enabled hardware status page\n");
dev->dev_private = (void *)dev_priv;
return 0;
}
static int i915_dma_resume(drm_device_t * dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
DRM_DEBUG("%s\n", __FUNCTION__);
if (!dev_priv->sarea) {
DRM_ERROR("can not find sarea!\n");
return DRM_ERR(EINVAL);
}
if (!dev_priv->mmio_map) {
DRM_ERROR("can not find mmio map!\n");
return DRM_ERR(EINVAL);
}
if (dev_priv->ring.map.handle == NULL) {
DRM_ERROR("can not ioremap virtual address for"
" ring buffer\n");
return DRM_ERR(ENOMEM);
}
/* Program Hardware Status Page */
if (!dev_priv->hw_status_page) {
DRM_ERROR("Can not find hardware status page\n");
return DRM_ERR(EINVAL);
}
DRM_DEBUG("hw status page @ %p\n", dev_priv->hw_status_page);
I915_WRITE(0x02080, dev_priv->dma_status_page);
DRM_DEBUG("Enabled hardware status page\n");
return 0;
}
static int i915_dma_init(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_i915_private_t *dev_priv;
drm_i915_init_t init;
int retcode = 0;
DRM_COPY_FROM_USER_IOCTL(init, (drm_i915_init_t __user *) data,
sizeof(init));
switch (init.func) {
case I915_INIT_DMA:
dev_priv = drm_alloc(sizeof(drm_i915_private_t),
DRM_MEM_DRIVER);
if (dev_priv == NULL)
return DRM_ERR(ENOMEM);
retcode = i915_initialize(dev, dev_priv, &init);
break;
case I915_CLEANUP_DMA:
retcode = i915_dma_cleanup(dev);
break;
case I915_RESUME_DMA:
retcode = i915_dma_resume(dev);
break;
default:
retcode = -EINVAL;
break;
}
return retcode;
}
/* Implement basically the same security restrictions as hardware does
* for MI_BATCH_NON_SECURE. These can be made stricter at any time.
*
* Most of the calculations below involve calculating the size of a
* particular instruction. It's important to get the size right as
* that tells us where the next instruction to check is. Any illegal
* instruction detected will be given a size of zero, which is a
* signal to abort the rest of the buffer.
*/
static int do_validate_cmd(int cmd)
{
switch (((cmd >> 29) & 0x7)) {
case 0x0:
switch ((cmd >> 23) & 0x3f) {
case 0x0:
return 1; /* MI_NOOP */
case 0x4:
return 1; /* MI_FLUSH */
default:
return 0; /* disallow everything else */
}
break;
case 0x1:
return 0; /* reserved */
case 0x2:
return (cmd & 0xff) + 2; /* 2d commands */
case 0x3:
if (((cmd >> 24) & 0x1f) <= 0x18)
return 1;
switch ((cmd >> 24) & 0x1f) {
case 0x1c:
return 1;
case 0x1d:
switch ((cmd >> 16) & 0xff) {
case 0x3:
return (cmd & 0x1f) + 2;
case 0x4:
return (cmd & 0xf) + 2;
default:
return (cmd & 0xffff) + 2;
}
case 0x1e:
if (cmd & (1 << 23))
return (cmd & 0xffff) + 1;
else
return 1;
case 0x1f:
if ((cmd & (1 << 23)) == 0) /* inline vertices */
return (cmd & 0x1ffff) + 2;
else if (cmd & (1 << 17)) /* indirect random */
if ((cmd & 0xffff) == 0)
return 0; /* unknown length, too hard */
else
return (((cmd & 0xffff) + 1) / 2) + 1;
else
return 2; /* indirect sequential */
default:
return 0;
}
default:
return 0;
}
return 0;
}
static int validate_cmd(int cmd)
{
int ret = do_validate_cmd(cmd);
/* printk("validate_cmd( %x ): %d\n", cmd, ret); */
return ret;
}
static int i915_emit_cmds(drm_device_t * dev, int __user * buffer, int dwords)
{
drm_i915_private_t *dev_priv = dev->dev_private;
int i;
RING_LOCALS;
if ((dwords+1) * sizeof(int) >= dev_priv->ring.Size - 8)
return DRM_ERR(EINVAL);
BEGIN_LP_RING((dwords+1)&~1);
for (i = 0; i < dwords;) {
int cmd, sz;
if (DRM_COPY_FROM_USER_UNCHECKED(&cmd, &buffer[i], sizeof(cmd))) {
return DRM_ERR(EINVAL);
}
if ((sz = validate_cmd(cmd)) == 0 || i + sz > dwords)
return DRM_ERR(EINVAL);
OUT_RING(cmd);
while (++i, --sz) {
if (DRM_COPY_FROM_USER_UNCHECKED(&cmd, &buffer[i],
sizeof(cmd))) {
return DRM_ERR(EINVAL);
}
OUT_RING(cmd);
}
}
if (dwords & 1)
OUT_RING(0);
ADVANCE_LP_RING();
return 0;
}
static int i915_emit_box(drm_device_t * dev,
drm_clip_rect_t __user * boxes,
int i, int DR1, int DR4)
{
drm_i915_private_t *dev_priv = dev->dev_private;
drm_clip_rect_t box;
RING_LOCALS;
if (DRM_COPY_FROM_USER_UNCHECKED(&box, &boxes[i], sizeof(box))) {
return EFAULT;
}
if (box.y2 <= box.y1 || box.x2 <= box.x1 || box.y2 <= 0 || box.x2 <= 0) {
DRM_ERROR("Bad box %d,%d..%d,%d\n",
box.x1, box.y1, box.x2, box.y2);
return DRM_ERR(EINVAL);
}
if (IS_I965G(dev)) {
BEGIN_LP_RING(4);
OUT_RING(GFX_OP_DRAWRECT_INFO_I965);
OUT_RING((box.x1 & 0xffff) | (box.y1 << 16));
OUT_RING(((box.x2 - 1) & 0xffff) | ((box.y2 - 1) << 16));
OUT_RING(DR4);
ADVANCE_LP_RING();
} else {
BEGIN_LP_RING(6);
OUT_RING(GFX_OP_DRAWRECT_INFO);
OUT_RING(DR1);
OUT_RING((box.x1 & 0xffff) | (box.y1 << 16));
OUT_RING(((box.x2 - 1) & 0xffff) | ((box.y2 - 1) << 16));
OUT_RING(DR4);
OUT_RING(0);
ADVANCE_LP_RING();
}
return 0;
}
/* XXX: Emitting the counter should really be moved to part of the IRQ
* emit. For now, do it in both places:
*/
static void i915_emit_breadcrumb(drm_device_t *dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
RING_LOCALS;
dev_priv->sarea_priv->last_enqueue = ++dev_priv->counter;
if (dev_priv->counter > 0x7FFFFFFFUL)
dev_priv->sarea_priv->last_enqueue = dev_priv->counter = 1;
BEGIN_LP_RING(4);
OUT_RING(CMD_STORE_DWORD_IDX);
OUT_RING(20);
OUT_RING(dev_priv->counter);
OUT_RING(0);
ADVANCE_LP_RING();
}
static int i915_dispatch_cmdbuffer(drm_device_t * dev,
drm_i915_cmdbuffer_t * cmd)
{
int nbox = cmd->num_cliprects;
int i = 0, count, ret;
if (cmd->sz & 0x3) {
DRM_ERROR("alignment");
return DRM_ERR(EINVAL);
}
i915_kernel_lost_context(dev);
count = nbox ? nbox : 1;
for (i = 0; i < count; i++) {
if (i < nbox) {
ret = i915_emit_box(dev, cmd->cliprects, i,
cmd->DR1, cmd->DR4);
if (ret)
return ret;
}
ret = i915_emit_cmds(dev, (int __user *)cmd->buf, cmd->sz / 4);
if (ret)
return ret;
}
i915_emit_breadcrumb( dev );
return 0;
}
static int i915_dispatch_batchbuffer(drm_device_t * dev,
drm_i915_batchbuffer_t * batch)
{
drm_i915_private_t *dev_priv = dev->dev_private;
drm_clip_rect_t __user *boxes = batch->cliprects;
int nbox = batch->num_cliprects;
int i = 0, count;
RING_LOCALS;
if ((batch->start | batch->used) & 0x7) {
DRM_ERROR("alignment");
return DRM_ERR(EINVAL);
}
i915_kernel_lost_context(dev);
count = nbox ? nbox : 1;
for (i = 0; i < count; i++) {
if (i < nbox) {
int ret = i915_emit_box(dev, boxes, i,
batch->DR1, batch->DR4);
if (ret)
return ret;
}
if (dev_priv->use_mi_batchbuffer_start) {
BEGIN_LP_RING(2);
OUT_RING(MI_BATCH_BUFFER_START | (2 << 6));
OUT_RING(batch->start | MI_BATCH_NON_SECURE);
ADVANCE_LP_RING();
} else {
BEGIN_LP_RING(4);
OUT_RING(MI_BATCH_BUFFER);
OUT_RING(batch->start | MI_BATCH_NON_SECURE);
OUT_RING(batch->start + batch->used - 4);
OUT_RING(0);
ADVANCE_LP_RING();
}
}
i915_emit_breadcrumb( dev );
return 0;
}
static int i915_dispatch_flip(drm_device_t * dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
RING_LOCALS;
DRM_DEBUG("%s: page=%d pfCurrentPage=%d\n",
__FUNCTION__,
dev_priv->current_page,
dev_priv->sarea_priv->pf_current_page);
i915_kernel_lost_context(dev);
BEGIN_LP_RING(2);
OUT_RING(INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE);
OUT_RING(0);
ADVANCE_LP_RING();
BEGIN_LP_RING(6);
OUT_RING(CMD_OP_DISPLAYBUFFER_INFO | ASYNC_FLIP);
OUT_RING(0);
if (dev_priv->current_page == 0) {
OUT_RING(dev_priv->back_offset);
dev_priv->current_page = 1;
} else {
OUT_RING(dev_priv->front_offset);
dev_priv->current_page = 0;
}
OUT_RING(0);
ADVANCE_LP_RING();
BEGIN_LP_RING(2);
OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_PLANE_A_FLIP);
OUT_RING(0);
ADVANCE_LP_RING();
dev_priv->sarea_priv->last_enqueue = dev_priv->counter++;
BEGIN_LP_RING(4);
OUT_RING(CMD_STORE_DWORD_IDX);
OUT_RING(20);
OUT_RING(dev_priv->counter);
OUT_RING(0);
ADVANCE_LP_RING();
dev_priv->sarea_priv->pf_current_page = dev_priv->current_page;
return 0;
}
static int i915_quiescent(drm_device_t * dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
i915_kernel_lost_context(dev);
return i915_wait_ring(dev, dev_priv->ring.Size - 8, __FUNCTION__);
}
static int i915_flush_ioctl(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
LOCK_TEST_WITH_RETURN(dev, filp);
return i915_quiescent(dev);
}
static int i915_batchbuffer(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
u32 *hw_status = dev_priv->hw_status_page;
drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *)
dev_priv->sarea_priv;
drm_i915_batchbuffer_t batch;
int ret;
if (!dev_priv->allow_batchbuffer) {
DRM_ERROR("Batchbuffer ioctl disabled\n");
return DRM_ERR(EINVAL);
}
DRM_COPY_FROM_USER_IOCTL(batch, (drm_i915_batchbuffer_t __user *) data,
sizeof(batch));
DRM_DEBUG("i915 batchbuffer, start %x used %d cliprects %d\n",
batch.start, batch.used, batch.num_cliprects);
LOCK_TEST_WITH_RETURN(dev, filp);
if (batch.num_cliprects && DRM_VERIFYAREA_READ(batch.cliprects,
batch.num_cliprects *
sizeof(drm_clip_rect_t)))
return DRM_ERR(EFAULT);
ret = i915_dispatch_batchbuffer(dev, &batch);
sarea_priv->last_dispatch = (int)hw_status[5];
return ret;
}
static int i915_cmdbuffer(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
u32 *hw_status = dev_priv->hw_status_page;
drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *)
dev_priv->sarea_priv;
drm_i915_cmdbuffer_t cmdbuf;
int ret;
DRM_COPY_FROM_USER_IOCTL(cmdbuf, (drm_i915_cmdbuffer_t __user *) data,
sizeof(cmdbuf));
DRM_DEBUG("i915 cmdbuffer, buf %p sz %d cliprects %d\n",
cmdbuf.buf, cmdbuf.sz, cmdbuf.num_cliprects);
LOCK_TEST_WITH_RETURN(dev, filp);
if (cmdbuf.num_cliprects &&
DRM_VERIFYAREA_READ(cmdbuf.cliprects,
cmdbuf.num_cliprects *
sizeof(drm_clip_rect_t))) {
DRM_ERROR("Fault accessing cliprects\n");
return DRM_ERR(EFAULT);
}
ret = i915_dispatch_cmdbuffer(dev, &cmdbuf);
if (ret) {
DRM_ERROR("i915_dispatch_cmdbuffer failed\n");
return ret;
}
sarea_priv->last_dispatch = (int)hw_status[5];
return 0;
}
static int i915_do_cleanup_pageflip(drm_device_t * dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
DRM_DEBUG("%s\n", __FUNCTION__);
if (dev_priv->current_page != 0)
i915_dispatch_flip(dev);
return 0;
}
static int i915_flip_bufs(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
DRM_DEBUG("%s\n", __FUNCTION__);
LOCK_TEST_WITH_RETURN(dev, filp);
return i915_dispatch_flip(dev);
}
static int i915_getparam(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_i915_private_t *dev_priv = dev->dev_private;
drm_i915_getparam_t param;
int value;
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
return DRM_ERR(EINVAL);
}
DRM_COPY_FROM_USER_IOCTL(param, (drm_i915_getparam_t __user *) data,
sizeof(param));
switch (param.param) {
case I915_PARAM_IRQ_ACTIVE:
value = dev->irq ? 1 : 0;
break;
case I915_PARAM_ALLOW_BATCHBUFFER:
value = dev_priv->allow_batchbuffer ? 1 : 0;
break;
case I915_PARAM_LAST_DISPATCH:
value = READ_BREADCRUMB(dev_priv);
break;
default:
DRM_ERROR("Unknown parameter %d\n", param.param);
return DRM_ERR(EINVAL);
}
if (DRM_COPY_TO_USER(param.value, &value, sizeof(int))) {
DRM_ERROR("DRM_COPY_TO_USER failed\n");
return DRM_ERR(EFAULT);
}
return 0;
}
static int i915_setparam(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_i915_private_t *dev_priv = dev->dev_private;
drm_i915_setparam_t param;
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
return DRM_ERR(EINVAL);
}
DRM_COPY_FROM_USER_IOCTL(param, (drm_i915_setparam_t __user *) data,
sizeof(param));
switch (param.param) {
case I915_SETPARAM_USE_MI_BATCHBUFFER_START:
dev_priv->use_mi_batchbuffer_start = param.value;
break;
case I915_SETPARAM_TEX_LRU_LOG_GRANULARITY:
dev_priv->tex_lru_log_granularity = param.value;
break;
case I915_SETPARAM_ALLOW_BATCHBUFFER:
dev_priv->allow_batchbuffer = param.value;
break;
default:
DRM_ERROR("unknown parameter %d\n", param.param);
return DRM_ERR(EINVAL);
}
return 0;
}
int i915_driver_load(drm_device_t *dev, unsigned long flags)
{
/* i915 has 4 more counters */
dev->counters += 4;
dev->types[6] = _DRM_STAT_IRQ;
dev->types[7] = _DRM_STAT_PRIMARY;
dev->types[8] = _DRM_STAT_SECONDARY;
dev->types[9] = _DRM_STAT_DMA;
return 0;
}
void i915_driver_lastclose(drm_device_t * dev)
{
if (dev->dev_private) {
drm_i915_private_t *dev_priv = dev->dev_private;
i915_mem_takedown(&(dev_priv->agp_heap));
}
i915_dma_cleanup(dev);
}
void i915_driver_preclose(drm_device_t * dev, DRMFILE filp)
{
if (dev->dev_private) {
drm_i915_private_t *dev_priv = dev->dev_private;
if (dev_priv->page_flipping) {
i915_do_cleanup_pageflip(dev);
}
i915_mem_release(dev, filp, dev_priv->agp_heap);
}
}
drm_ioctl_desc_t i915_ioctls[] = {
[DRM_IOCTL_NR(DRM_I915_INIT)] = {i915_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
[DRM_IOCTL_NR(DRM_I915_FLUSH)] = {i915_flush_ioctl, DRM_AUTH},
[DRM_IOCTL_NR(DRM_I915_FLIP)] = {i915_flip_bufs, DRM_AUTH},
[DRM_IOCTL_NR(DRM_I915_BATCHBUFFER)] = {i915_batchbuffer, DRM_AUTH},
[DRM_IOCTL_NR(DRM_I915_IRQ_EMIT)] = {i915_irq_emit, DRM_AUTH},
[DRM_IOCTL_NR(DRM_I915_IRQ_WAIT)] = {i915_irq_wait, DRM_AUTH},
[DRM_IOCTL_NR(DRM_I915_GETPARAM)] = {i915_getparam, DRM_AUTH},
[DRM_IOCTL_NR(DRM_I915_SETPARAM)] = {i915_setparam, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
[DRM_IOCTL_NR(DRM_I915_ALLOC)] = {i915_mem_alloc, DRM_AUTH},
[DRM_IOCTL_NR(DRM_I915_FREE)] = {i915_mem_free, DRM_AUTH},
[DRM_IOCTL_NR(DRM_I915_INIT_HEAP)] = {i915_mem_init_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
[DRM_IOCTL_NR(DRM_I915_CMDBUFFER)] = {i915_cmdbuffer, DRM_AUTH},
[DRM_IOCTL_NR(DRM_I915_DESTROY_HEAP)] = { i915_mem_destroy_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY },
[DRM_IOCTL_NR(DRM_I915_SET_VBLANK_PIPE)] = { i915_vblank_pipe_set, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY },
[DRM_IOCTL_NR(DRM_I915_GET_VBLANK_PIPE)] = { i915_vblank_pipe_get, DRM_AUTH },
};
int i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls);
/**
* Determine if the device really is AGP or not.
*
* All Intel graphics chipsets are treated as AGP, even if they are really
* PCI-e.
*
* \param dev The device to be tested.
*
* \returns
* A value of 1 is always retured to indictate every i9x5 is AGP.
*/
int i915_driver_device_is_agp(drm_device_t * dev)
{
return 1;
}

252
sys/dev/pci/drm/i915_drm.h Normal file
View File

@ -0,0 +1,252 @@
/*-
* Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
* 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 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.
*
*/
#include <sys/cdefs.h>
/*
__FBSDID("$FreeBSD: src/sys/dev/drm/i915_drm.h,v 1.4 2006/09/07 23:04:47 anholt Exp $");
*/
#ifndef _I915_DRM_H_
#define _I915_DRM_H_
/* Please note that modifications to all structs defined here are
* subject to backwards-compatibility constraints.
*/
#include <dev/drm/drm.h>
/* Each region is a minimum of 16k, and there are at most 255 of them.
*/
#define I915_NR_TEX_REGIONS 255 /* table size 2k - maximum due to use
* of chars for next/prev indices */
#define I915_LOG_MIN_TEX_REGION_SIZE 14
typedef struct _drm_i915_init {
enum {
I915_INIT_DMA = 0x01,
I915_CLEANUP_DMA = 0x02,
I915_RESUME_DMA = 0x03
} func;
unsigned int mmio_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;
unsigned int chipset;
} drm_i915_init_t;
typedef struct _drm_i915_sarea {
drm_tex_region_t texList[I915_NR_TEX_REGIONS + 1];
int last_upload; /* 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 ctxOwner; /* last context to upload state */
int texAge;
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 */
int width, height; /* screen size in pixels */
drm_handle_t front_handle;
int front_offset;
int front_size;
drm_handle_t back_handle;
int back_offset;
int back_size;
drm_handle_t depth_handle;
int depth_offset;
int depth_size;
drm_handle_t tex_handle;
int tex_offset;
int tex_size;
int log_tex_granularity;
int pitch;
int rotation; /* 0, 90, 180 or 270 */
int rotated_offset;
int rotated_size;
int rotated_pitch;
int virtualX, virtualY;
unsigned int front_tiled;
unsigned int back_tiled;
unsigned int depth_tiled;
unsigned int rotated_tiled;
unsigned int rotated2_tiled;
} drm_i915_sarea_t;
/* Flags for perf_boxes
*/
#define I915_BOX_RING_EMPTY 0x1
#define I915_BOX_FLIP 0x2
#define I915_BOX_WAIT 0x4
#define I915_BOX_TEXTURE_LOAD 0x8
#define I915_BOX_LOST_CONTEXT 0x10
/* I915 specific ioctls
* The device specific ioctl range is 0x40 to 0x79.
*/
#define DRM_I915_INIT 0x00
#define DRM_I915_FLUSH 0x01
#define DRM_I915_FLIP 0x02
#define DRM_I915_BATCHBUFFER 0x03
#define DRM_I915_IRQ_EMIT 0x04
#define DRM_I915_IRQ_WAIT 0x05
#define DRM_I915_GETPARAM 0x06
#define DRM_I915_SETPARAM 0x07
#define DRM_I915_ALLOC 0x08
#define DRM_I915_FREE 0x09
#define DRM_I915_INIT_HEAP 0x0a
#define DRM_I915_CMDBUFFER 0x0b
#define DRM_I915_DESTROY_HEAP 0x0c
#define DRM_I915_SET_VBLANK_PIPE 0x0d
#define DRM_I915_GET_VBLANK_PIPE 0x0e
#define DRM_IOCTL_I915_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t)
#define DRM_IOCTL_I915_FLUSH DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLUSH)
#define DRM_IOCTL_I915_FLIP DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLIP)
#define DRM_IOCTL_I915_BATCHBUFFER DRM_IOW( DRM_COMMAND_BASE + DRM_I915_BATCHBUFFER, drm_i915_batchbuffer_t)
#define DRM_IOCTL_I915_IRQ_EMIT DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_IRQ_EMIT, drm_i915_irq_emit_t)
#define DRM_IOCTL_I915_IRQ_WAIT DRM_IOW( DRM_COMMAND_BASE + DRM_I915_IRQ_WAIT, drm_i915_irq_wait_t)
#define DRM_IOCTL_I915_GETPARAM DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GETPARAM, drm_i915_getparam_t)
#define DRM_IOCTL_I915_SETPARAM DRM_IOW( DRM_COMMAND_BASE + DRM_I915_SETPARAM, drm_i915_setparam_t)
#define DRM_IOCTL_I915_ALLOC DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_ALLOC, drm_i915_mem_alloc_t)
#define DRM_IOCTL_I915_FREE DRM_IOW( DRM_COMMAND_BASE + DRM_I915_FREE, drm_i915_mem_free_t)
#define DRM_IOCTL_I915_INIT_HEAP DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT_HEAP, drm_i915_mem_init_heap_t)
#define DRM_IOCTL_I915_CMDBUFFER DRM_IOW( DRM_COMMAND_BASE + DRM_I915_CMDBUFFER, drm_i915_cmdbuffer_t)
#define DRM_IOCTL_I915_DESTROY_HEAP DRM_IOW( DRM_COMMAND_BASE + DRM_I915_DESTROY_HEAP, drm_i915_mem_destroy_heap_t)
#define DRM_IOCTL_I915_SET_VBLANK_PIPE DRM_IOW( DRM_COMMAND_BASE + DRM_I915_SET_VBLANK_PIPE, drm_i915_vblank_pipe_t)
#define DRM_IOCTL_I915_GET_VBLANK_PIPE DRM_IOR( DRM_COMMAND_BASE + DRM_I915_GET_VBLANK_PIPE, drm_i915_vblank_pipe_t)
/* Allow drivers to submit batchbuffers directly to hardware, relying
* on the security mechanisms provided by hardware.
*/
typedef struct _drm_i915_batchbuffer {
int start; /* agp offset */
int used; /* nr bytes in use */
int DR1; /* hw flags for GFX_OP_DRAWRECT_INFO */
int DR4; /* window origin for GFX_OP_DRAWRECT_INFO */
int num_cliprects; /* mulitpass with multiple cliprects? */
drm_clip_rect_t __user *cliprects; /* pointer to userspace cliprects */
} drm_i915_batchbuffer_t;
/* As above, but pass a pointer to userspace buffer which can be
* validated by the kernel prior to sending to hardware.
*/
typedef struct _drm_i915_cmdbuffer {
char __user *buf; /* pointer to userspace command buffer */
int sz; /* nr bytes in buf */
int DR1; /* hw flags for GFX_OP_DRAWRECT_INFO */
int DR4; /* window origin for GFX_OP_DRAWRECT_INFO */
int num_cliprects; /* mulitpass with multiple cliprects? */
drm_clip_rect_t __user *cliprects; /* pointer to userspace cliprects */
} drm_i915_cmdbuffer_t;
/* Userspace can request & wait on irq's:
*/
typedef struct drm_i915_irq_emit {
int __user *irq_seq;
} drm_i915_irq_emit_t;
typedef struct drm_i915_irq_wait {
int irq_seq;
} drm_i915_irq_wait_t;
/* Ioctl to query kernel params:
*/
#define I915_PARAM_IRQ_ACTIVE 1
#define I915_PARAM_ALLOW_BATCHBUFFER 2
#define I915_PARAM_LAST_DISPATCH 3
typedef struct drm_i915_getparam {
int param;
int __user *value;
} drm_i915_getparam_t;
/* Ioctl to set kernel params:
*/
#define I915_SETPARAM_USE_MI_BATCHBUFFER_START 1
#define I915_SETPARAM_TEX_LRU_LOG_GRANULARITY 2
#define I915_SETPARAM_ALLOW_BATCHBUFFER 3
typedef struct drm_i915_setparam {
int param;
int value;
} drm_i915_setparam_t;
/* A memory manager for regions of shared memory:
*/
#define I915_MEM_REGION_AGP 1
typedef struct drm_i915_mem_alloc {
int region;
int alignment;
int size;
int __user *region_offset; /* offset from start of fb or agp */
} drm_i915_mem_alloc_t;
typedef struct drm_i915_mem_free {
int region;
int region_offset;
} drm_i915_mem_free_t;
typedef struct drm_i915_mem_init_heap {
int region;
int size;
int start;
} drm_i915_mem_init_heap_t;
/* Allow memory manager to be torn down and re-initialized (eg on
* rotate):
*/
typedef struct drm_i915_mem_destroy_heap {
int region;
} drm_i915_mem_destroy_heap_t;
/* Allow X server to configure which pipes to monitor for vblank signals
*/
#define DRM_I915_VBLANK_PIPE_A 1
#define DRM_I915_VBLANK_PIPE_B 2
typedef struct drm_i915_vblank_pipe {
int pipe;
} drm_i915_vblank_pipe_t;
#endif /* _I915_DRM_H_ */

145
sys/dev/pci/drm/i915_drv.c Normal file
View File

@ -0,0 +1,145 @@
/* i915_drv.c -- ATI Radeon driver -*- linux-c -*-
* Created: Wed Feb 14 17:10:04 2001 by gareth@valinux.com
*/
/*-
* 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:
* Gareth Hughes <gareth@valinux.com>
*
*/
#include <sys/cdefs.h>
/*
__FBSDID("$FreeBSD: src/sys/dev/drm/i915_drv.c,v 1.5 2006/05/17 06:36:28 anholt Exp $");
*/
#include <dev/drm/drmP.h>
#include <dev/drm/drm.h>
#include "i915_drm.h"
#include "i915_drv.h"
#include "drm_pciids.h"
/* drv_PCI_IDs comes from drm_pciids.h, generated from drm_pciids.txt. */
static drm_pci_id_list_t i915_pciidlist[] = {
i915_PCI_IDS
};
static void i915_configure(drm_device_t *dev)
{
dev->driver.buf_priv_size = 1; /* No dev_priv */
dev->driver.load = i915_driver_load;
dev->driver.preclose = i915_driver_preclose;
dev->driver.lastclose = i915_driver_lastclose;
dev->driver.device_is_agp = i915_driver_device_is_agp,
dev->driver.vblank_wait = i915_driver_vblank_wait;
dev->driver.irq_preinstall = i915_driver_irq_preinstall;
dev->driver.irq_postinstall = i915_driver_irq_postinstall;
dev->driver.irq_uninstall = i915_driver_irq_uninstall;
dev->driver.irq_handler = i915_driver_irq_handler;
dev->driver.ioctls = i915_ioctls;
dev->driver.max_ioctl = i915_max_ioctl;
dev->driver.name = DRIVER_NAME;
dev->driver.desc = DRIVER_DESC;
dev->driver.date = DRIVER_DATE;
dev->driver.major = DRIVER_MAJOR;
dev->driver.minor = DRIVER_MINOR;
dev->driver.patchlevel = DRIVER_PATCHLEVEL;
dev->driver.use_agp = 1;
dev->driver.require_agp = 1;
dev->driver.use_mtrr = 1;
dev->driver.use_irq = 1;
dev->driver.use_vbl_irq = 1;
}
#ifdef __FreeBSD__
static int
i915_probe(device_t dev)
{
return drm_probe(dev, i915_pciidlist);
}
static int
i915_attach(device_t nbdev)
{
drm_device_t *dev = device_get_softc(nbdev);
bzero(dev, sizeof(drm_device_t));
i915_configure(dev);
return drm_attach(nbdev, i915_pciidlist);
}
static device_method_t i915_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, i915_probe),
DEVMETHOD(device_attach, i915_attach),
DEVMETHOD(device_detach, drm_detach),
{ 0, 0 }
};
static driver_t i915_driver = {
#if __FreeBSD_version >= 700010
"drm",
#else
"drmsub",
#endif
i915_methods,
sizeof(drm_device_t)
};
extern devclass_t drm_devclass;
#if __FreeBSD_version >= 700010
DRIVER_MODULE(i915, vgapci, i915_driver, drm_devclass, 0, 0);
#else
DRIVER_MODULE(i915, agp, i915_driver, drm_devclass, 0, 0);
#endif
MODULE_DEPEND(i915, drm, 1, 1, 1);
#elif defined(__NetBSD__) || defined(__OpenBSD__)
static int
i915drm_probe(struct device *parent, struct cfdata *match, void *aux)
{
struct pci_attach_args *pa = aux;
return drm_probe(pa, i915_pciidlist);
}
static void
i915drm_attach(struct device *parent, struct device *self, void *aux)
{
struct pci_attach_args *pa = aux;
drm_device_t *dev = (drm_device_t *)self;
i915_configure(dev);
drm_attach(self, pa, i915_pciidlist);
}
CFATTACH_DECL(i915drm, sizeof(drm_device_t), i915drm_probe, i915drm_attach,
drm_detach, drm_activate);
#endif

282
sys/dev/pci/drm/i915_drv.h Normal file
View File

@ -0,0 +1,282 @@
/* i915_drv.h -- Private header for the I915 driver -*- linux-c -*-
*/
/*
*
* Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
* 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 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.
*
*/
#include <sys/cdefs.h>
/*
__FBSDID("$FreeBSD: src/sys/dev/drm/i915_drv.h,v 1.4 2006/09/07 23:04:47 anholt Exp $");
*/
#ifndef _I915_DRV_H_
#define _I915_DRV_H_
/* General customization:
*/
#define DRIVER_AUTHOR "Tungsten Graphics, Inc."
#define DRIVER_NAME "i915"
#define DRIVER_DESC "Intel Graphics"
#define DRIVER_DATE "20060119"
/* Interface history:
*
* 1.1: Original.
* 1.2: Add Power Management
* 1.3: Add vblank support
* 1.4: Fix cmdbuffer path, add heap destroy
* 1.5: Add vblank pipe configuration
*/
#define DRIVER_MAJOR 1
#define DRIVER_MINOR 5
#define DRIVER_PATCHLEVEL 0
typedef struct _drm_i915_ring_buffer {
int tail_mask;
unsigned long Start;
unsigned long End;
unsigned long Size;
u8 *virtual_start;
int head;
int tail;
int space;
drm_local_map_t map;
} drm_i915_ring_buffer_t;
struct mem_block {
struct mem_block *next;
struct mem_block *prev;
int start;
int size;
DRMFILE filp; /* 0: free, -1: heap, other: real files */
};
typedef struct drm_i915_private {
drm_local_map_t *sarea;
drm_local_map_t *mmio_map;
drm_i915_sarea_t *sarea_priv;
drm_i915_ring_buffer_t ring;
drm_dma_handle_t *status_page_dmah;
void *hw_status_page;
dma_addr_t dma_status_page;
unsigned long counter;
int back_offset;
int front_offset;
int current_page;
int page_flipping;
int use_mi_batchbuffer_start;
wait_queue_head_t irq_queue;
atomic_t irq_received;
atomic_t irq_emitted;
int tex_lru_log_granularity;
int allow_batchbuffer;
struct mem_block *agp_heap;
unsigned int sr01, adpa, ppcr, dvob, dvoc, lvds;
int vblank_pipe;
} drm_i915_private_t;
extern drm_ioctl_desc_t i915_ioctls[];
extern int i915_max_ioctl;
/* i915_dma.c */
extern void i915_kernel_lost_context(drm_device_t * dev);
extern int i915_driver_load(struct drm_device *, unsigned long flags);
extern void i915_driver_lastclose(drm_device_t * dev);
extern void i915_driver_preclose(drm_device_t * dev, DRMFILE filp);
extern int i915_driver_device_is_agp(drm_device_t * dev);
extern long i915_compat_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg);
/* i915_irq.c */
extern int i915_irq_emit(DRM_IOCTL_ARGS);
extern int i915_irq_wait(DRM_IOCTL_ARGS);
extern int i915_driver_vblank_wait(drm_device_t *dev, unsigned int *sequence);
extern irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS);
extern void i915_driver_irq_preinstall(drm_device_t * dev);
extern void i915_driver_irq_postinstall(drm_device_t * dev);
extern void i915_driver_irq_uninstall(drm_device_t * dev);
extern int i915_vblank_pipe_set(DRM_IOCTL_ARGS);
extern int i915_vblank_pipe_get(DRM_IOCTL_ARGS);
/* i915_mem.c */
extern int i915_mem_alloc(DRM_IOCTL_ARGS);
extern int i915_mem_free(DRM_IOCTL_ARGS);
extern int i915_mem_init_heap(DRM_IOCTL_ARGS);
extern int i915_mem_destroy_heap(DRM_IOCTL_ARGS);
extern void i915_mem_takedown(struct mem_block **heap);
extern void i915_mem_release(drm_device_t * dev,
DRMFILE filp, struct mem_block *heap);
#define I915_READ(reg) DRM_READ32(dev_priv->mmio_map, (reg))
#define I915_WRITE(reg,val) DRM_WRITE32(dev_priv->mmio_map, (reg), (val))
#define I915_READ16(reg) DRM_READ16(dev_priv->mmio_map, (reg))
#define I915_WRITE16(reg,val) DRM_WRITE16(dev_priv->mmio_map, (reg), (val))
#define I915_VERBOSE 0
#define RING_LOCALS unsigned int outring, ringmask, outcount; \
volatile char *virt;
#define BEGIN_LP_RING(n) do { \
if (I915_VERBOSE) \
DRM_DEBUG("BEGIN_LP_RING(%d) in %s\n", \
(n), __FUNCTION__); \
if (dev_priv->ring.space < (n)*4) \
i915_wait_ring(dev, (n)*4, __FUNCTION__); \
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 (I915_VERBOSE) DRM_DEBUG(" 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 (I915_VERBOSE) DRM_DEBUG("ADVANCE_LP_RING %x\n", outring); \
dev_priv->ring.tail = outring; \
dev_priv->ring.space -= outcount * 4; \
I915_WRITE(LP_RING + RING_TAIL, outring); \
} while(0)
extern int i915_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 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 I915REG_HWSTAM 0x02098
#define I915REG_INT_IDENTITY_R 0x020a4
#define I915REG_INT_MASK_R 0x020a8
#define I915REG_INT_ENABLE_R 0x020a0
#define SRX_INDEX 0x3c4
#define SRX_DATA 0x3c5
#define SR01 1
#define SR01_SCREEN_OFF (1<<5)
#define PPCR 0x61204
#define PPCR_ON (1<<0)
#define DVOB 0x61140
#define DVOB_ON (1<<31)
#define DVOC 0x61160
#define DVOC_ON (1<<31)
#define LVDS 0x61180
#define LVDS_ON (1<<31)
#define ADPA 0x61100
#define ADPA_DPMS_MASK (~(3<<10))
#define ADPA_DPMS_ON (0<<10)
#define ADPA_DPMS_SUSPEND (1<<10)
#define ADPA_DPMS_STANDBY (2<<10)
#define ADPA_DPMS_OFF (3<<10)
#define NOPID 0x2094
#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_DRAWRECT_INFO_I965 ((0x7900<<16)|0x2)
#define MI_BATCH_BUFFER ((0x30<<23)|1)
#define MI_BATCH_BUFFER_START (0x31<<23)
#define MI_BATCH_BUFFER_END (0xA<<23)
#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))
#define CMD_OP_DISPLAYBUFFER_INFO ((0x0<<29)|(0x14<<23)|2)
#define ASYNC_FLIP (1<<22)
#define CMD_OP_DESTBUFFER_INFO ((0x3<<29)|(0x1d<<24)|(0x8e<<16)|1)
#define READ_BREADCRUMB(dev_priv) (((u32*)(dev_priv->hw_status_page))[5])
#endif

296
sys/dev/pci/drm/i915_irq.c Normal file
View File

@ -0,0 +1,296 @@
/* i915_irq.c -- IRQ support for the I915 -*- linux-c -*-
*/
/*-
* Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
* 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 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.
*
*/
#include <sys/cdefs.h>
/*
__FBSDID("$FreeBSD: src/sys/dev/drm/i915_irq.c,v 1.4 2006/09/07 23:04:47 anholt Exp $");
*/
#include <dev/drm/drmP.h>
#include <dev/drm/drm.h>
#include "i915_drm.h"
#include "i915_drv.h"
#define USER_INT_FLAG (1<<1)
#define VSYNC_PIPEB_FLAG (1<<5)
#define VSYNC_PIPEA_FLAG (1<<7)
#define MAX_NOPID ((u32)~0)
irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
{
drm_device_t *dev = (drm_device_t *) arg;
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
u16 temp;
temp = I915_READ16(I915REG_INT_IDENTITY_R);
temp &= (USER_INT_FLAG | VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG);
/*
DRM_DEBUG("%s flag=%08x\n", __FUNCTION__, (int)temp);
*/
if (temp == 0)
return IRQ_NONE;
I915_WRITE16(I915REG_INT_IDENTITY_R, temp);
dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
if (temp & USER_INT_FLAG)
DRM_WAKEUP(&dev_priv->irq_queue);
if (temp & (VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG)) {
atomic_inc(&dev->vbl_received);
DRM_WAKEUP(&dev->vbl_queue);
drm_vbl_send_signals(dev);
}
return IRQ_HANDLED;
}
static int i915_emit_irq(drm_device_t * dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
RING_LOCALS;
i915_kernel_lost_context(dev);
DRM_DEBUG("%s\n", __FUNCTION__);
dev_priv->sarea_priv->last_enqueue = ++dev_priv->counter;
if (dev_priv->counter > 0x7FFFFFFFUL)
dev_priv->sarea_priv->last_enqueue = dev_priv->counter = 1;
BEGIN_LP_RING(6);
OUT_RING(CMD_STORE_DWORD_IDX);
OUT_RING(20);
OUT_RING(dev_priv->counter);
OUT_RING(0);
OUT_RING(0);
OUT_RING(GFX_OP_USER_INTERRUPT);
ADVANCE_LP_RING();
return dev_priv->counter;
}
static int i915_wait_irq(drm_device_t * dev, int irq_nr)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
int ret = 0;
DRM_DEBUG("%s irq_nr=%d breadcrumb=%d\n", __FUNCTION__, irq_nr,
(int)READ_BREADCRUMB(dev_priv));
if (READ_BREADCRUMB(dev_priv) >= irq_nr)
return 0;
dev_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT;
DRM_WAIT_ON(ret, dev_priv->irq_queue, 3 * DRM_HZ,
READ_BREADCRUMB(dev_priv) >= irq_nr);
if (ret == DRM_ERR(EBUSY)) {
DRM_ERROR("%s: EBUSY -- rec: %d emitted: %d\n",
__FUNCTION__,
(int)READ_BREADCRUMB(dev_priv), (int)dev_priv->counter);
}
dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
return ret;
}
int i915_driver_vblank_wait(drm_device_t *dev, unsigned int *sequence)
{
drm_i915_private_t *dev_priv = dev->dev_private;
unsigned int cur_vblank;
int ret = 0;
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
return DRM_ERR(EINVAL);
}
DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
(((cur_vblank = atomic_read(&dev->vbl_received))
- *sequence) <= (1<<23)));
*sequence = cur_vblank;
return ret;
}
/* Needs the lock as it touches the ring.
*/
int i915_irq_emit(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_i915_private_t *dev_priv = dev->dev_private;
drm_i915_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 DRM_ERR(EINVAL);
}
DRM_COPY_FROM_USER_IOCTL(emit, (drm_i915_irq_emit_t __user *) data,
sizeof(emit));
result = i915_emit_irq(dev);
if (DRM_COPY_TO_USER(emit.irq_seq, &result, sizeof(int))) {
DRM_ERROR("copy_to_user\n");
return DRM_ERR(EFAULT);
}
return 0;
}
/* Doesn't need the hardware lock.
*/
int i915_irq_wait(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_i915_private_t *dev_priv = dev->dev_private;
drm_i915_irq_wait_t irqwait;
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
return DRM_ERR(EINVAL);
}
DRM_COPY_FROM_USER_IOCTL(irqwait, (drm_i915_irq_wait_t __user *) data,
sizeof(irqwait));
return i915_wait_irq(dev, irqwait.irq_seq);
}
static int i915_enable_interrupt (drm_device_t *dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
u16 flag;
flag = 0;
if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_A)
flag |= VSYNC_PIPEA_FLAG;
if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_B)
flag |= VSYNC_PIPEB_FLAG;
if (dev_priv->vblank_pipe & ~(DRM_I915_VBLANK_PIPE_A|DRM_I915_VBLANK_PIPE_B)) {
DRM_ERROR("%s called with invalid pipe 0x%x\n",
__FUNCTION__, dev_priv->vblank_pipe);
return DRM_ERR(EINVAL);
}
I915_WRITE16(I915REG_INT_ENABLE_R, USER_INT_FLAG | flag);
return 0;
}
/* Set the vblank monitor pipe
*/
int i915_vblank_pipe_set(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_i915_private_t *dev_priv = dev->dev_private;
drm_i915_vblank_pipe_t pipe;
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
return DRM_ERR(EINVAL);
}
DRM_COPY_FROM_USER_IOCTL(pipe, (drm_i915_vblank_pipe_t __user *) data,
sizeof(pipe));
dev_priv->vblank_pipe = pipe.pipe;
return i915_enable_interrupt (dev);
}
int i915_vblank_pipe_get(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_i915_private_t *dev_priv = dev->dev_private;
drm_i915_vblank_pipe_t pipe;
u16 flag;
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
return DRM_ERR(EINVAL);
}
flag = I915_READ(I915REG_INT_ENABLE_R);
pipe.pipe = 0;
if (flag & VSYNC_PIPEA_FLAG)
pipe.pipe |= DRM_I915_VBLANK_PIPE_A;
if (flag & VSYNC_PIPEB_FLAG)
pipe.pipe |= DRM_I915_VBLANK_PIPE_B;
DRM_COPY_TO_USER_IOCTL((drm_i915_vblank_pipe_t __user *) data, pipe,
sizeof(pipe));
return 0;
}
/* drm_dma.h hooks
*/
void i915_driver_irq_preinstall(drm_device_t * dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
I915_WRITE16(I915REG_HWSTAM, 0xfffe);
I915_WRITE16(I915REG_INT_MASK_R, 0x0);
I915_WRITE16(I915REG_INT_ENABLE_R, 0x0);
}
void i915_driver_irq_postinstall(drm_device_t * dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
i915_enable_interrupt(dev);
DRM_INIT_WAITQUEUE(&dev_priv->irq_queue);
}
void i915_driver_irq_uninstall(drm_device_t * dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
u16 temp;
if (!dev_priv)
return;
I915_WRITE16(I915REG_HWSTAM, 0xffff);
I915_WRITE16(I915REG_INT_MASK_R, 0xffff);
I915_WRITE16(I915REG_INT_ENABLE_R, 0x0);
temp = I915_READ16(I915REG_INT_IDENTITY_R);
I915_WRITE16(I915REG_INT_IDENTITY_R, temp);
}

402
sys/dev/pci/drm/i915_mem.c Normal file
View File

@ -0,0 +1,402 @@
/* i915_mem.c -- Simple agp/fb memory manager for i915 -*- linux-c -*-
*/
/*-
* Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
* 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 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.
*
*/
#include <sys/cdefs.h>
/*
__FBSDID("$FreeBSD: src/sys/dev/drm/i915_mem.c,v 1.3 2006/04/09 20:45:45 anholt Exp $");
*/
#include <dev/drm/drmP.h>
#include <dev/drm/drm.h>
#include "i915_drm.h"
#include "i915_drv.h"
/* This memory manager is integrated into the global/local lru
* mechanisms used by the clients. Specifically, it operates by
* setting the 'in_use' fields of the global LRU to indicate whether
* this region is privately allocated to a client.
*
* This does require the client to actually respect that field.
*
* Currently no effort is made to allocate 'private' memory in any
* clever way - the LRU information isn't used to determine which
* block to allocate, and the ring is drained prior to allocations --
* in other words allocation is expensive.
*/
static void mark_block(drm_device_t * dev, struct mem_block *p, int in_use)
{
drm_i915_private_t *dev_priv = dev->dev_private;
drm_i915_sarea_t *sarea_priv = dev_priv->sarea_priv;
drm_tex_region_t *list;
unsigned shift, nr;
unsigned start;
unsigned end;
unsigned i;
int age;
shift = dev_priv->tex_lru_log_granularity;
nr = I915_NR_TEX_REGIONS;
start = p->start >> shift;
end = (p->start + p->size - 1) >> shift;
age = ++sarea_priv->texAge;
list = sarea_priv->texList;
/* Mark the regions with the new flag and update their age. Move
* them to head of list to preserve LRU semantics.
*/
for (i = start; i <= end; i++) {
list[i].in_use = in_use;
list[i].age = age;
/* remove_from_list(i)
*/
list[(unsigned)list[i].next].prev = list[i].prev;
list[(unsigned)list[i].prev].next = list[i].next;
/* insert_at_head(list, i)
*/
list[i].prev = nr;
list[i].next = list[nr].next;
list[(unsigned)list[nr].next].prev = i;
list[nr].next = i;
}
}
/* Very simple allocator for agp memory, working on a static range
* already mapped into each client's address space.
*/
static struct mem_block *split_block(struct mem_block *p, int start, int size,
DRMFILE filp)
{
/* Maybe cut off the start of an existing block */
if (start > p->start) {
struct mem_block *newblock =
drm_alloc(sizeof(*newblock), DRM_MEM_BUFLISTS);
if (!newblock)
goto out;
newblock->start = start;
newblock->size = p->size - (start - p->start);
newblock->filp = NULL;
newblock->next = p->next;
newblock->prev = p;
p->next->prev = newblock;
p->next = newblock;
p->size -= newblock->size;
p = newblock;
}
/* Maybe cut off the end of an existing block */
if (size < p->size) {
struct mem_block *newblock =
drm_alloc(sizeof(*newblock), DRM_MEM_BUFLISTS);
if (!newblock)
goto out;
newblock->start = start + size;
newblock->size = p->size - size;
newblock->filp = NULL;
newblock->next = p->next;
newblock->prev = p;
p->next->prev = newblock;
p->next = newblock;
p->size = size;
}
out:
/* Our block is in the middle */
p->filp = filp;
return p;
}
static struct mem_block *alloc_block(struct mem_block *heap, int size,
int align2, DRMFILE filp)
{
struct mem_block *p;
int mask = (1 << align2) - 1;
for (p = heap->next; p != heap; p = p->next) {
int start = (p->start + mask) & ~mask;
if (p->filp == NULL && start + size <= p->start + p->size)
return split_block(p, start, size, filp);
}
return NULL;
}
static struct mem_block *find_block(struct mem_block *heap, int start)
{
struct mem_block *p;
for (p = heap->next; p != heap; p = p->next)
if (p->start == start)
return p;
return NULL;
}
static void free_block(struct mem_block *p)
{
p->filp = NULL;
/* Assumes a single contiguous range. Needs a special filp in
* 'heap' to stop it being subsumed.
*/
if (p->next->filp == NULL) {
struct mem_block *q = p->next;
p->size += q->size;
p->next = q->next;
p->next->prev = p;
drm_free(q, sizeof(*q), DRM_MEM_BUFLISTS);
}
if (p->prev->filp == NULL) {
struct mem_block *q = p->prev;
q->size += p->size;
q->next = p->next;
q->next->prev = q;
drm_free(p, sizeof(*q), DRM_MEM_BUFLISTS);
}
}
/* Initialize. How to check for an uninitialized heap?
*/
static int init_heap(struct mem_block **heap, int start, int size)
{
struct mem_block *blocks = drm_alloc(sizeof(*blocks), DRM_MEM_BUFLISTS);
if (!blocks)
return -ENOMEM;
*heap = drm_alloc(sizeof(**heap), DRM_MEM_BUFLISTS);
if (!*heap) {
drm_free(blocks, sizeof(*blocks), DRM_MEM_BUFLISTS);
return -ENOMEM;
}
blocks->start = start;
blocks->size = size;
blocks->filp = NULL;
blocks->next = blocks->prev = *heap;
memset(*heap, 0, sizeof(**heap));
(*heap)->filp = (DRMFILE) - 1;
(*heap)->next = (*heap)->prev = blocks;
return 0;
}
/* Free all blocks associated with the releasing file.
*/
void i915_mem_release(drm_device_t * dev, DRMFILE filp, struct mem_block *heap)
{
struct mem_block *p;
if (!heap || !heap->next)
return;
for (p = heap->next; p != heap; p = p->next) {
if (p->filp == filp) {
p->filp = NULL;
mark_block(dev, p, 0);
}
}
/* Assumes a single contiguous range. Needs a special filp in
* 'heap' to stop it being subsumed.
*/
for (p = heap->next; p != heap; p = p->next) {
while (p->filp == NULL && p->next->filp == NULL) {
struct mem_block *q = p->next;
p->size += q->size;
p->next = q->next;
p->next->prev = p;
drm_free(q, sizeof(*q), DRM_MEM_BUFLISTS);
}
}
}
/* Shutdown.
*/
void i915_mem_takedown(struct mem_block **heap)
{
struct mem_block *p;
if (!*heap)
return;
for (p = (*heap)->next; p != *heap;) {
struct mem_block *q = p;
p = p->next;
drm_free(q, sizeof(*q), DRM_MEM_BUFLISTS);
}
drm_free(*heap, sizeof(**heap), DRM_MEM_BUFLISTS);
*heap = NULL;
}
static struct mem_block **get_heap(drm_i915_private_t * dev_priv, int region)
{
switch (region) {
case I915_MEM_REGION_AGP:
return &dev_priv->agp_heap;
default:
return NULL;
}
}
/* IOCTL HANDLERS */
int i915_mem_alloc(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_i915_private_t *dev_priv = dev->dev_private;
drm_i915_mem_alloc_t alloc;
struct mem_block *block, **heap;
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
return DRM_ERR(EINVAL);
}
DRM_COPY_FROM_USER_IOCTL(alloc, (drm_i915_mem_alloc_t __user *) data,
sizeof(alloc));
heap = get_heap(dev_priv, alloc.region);
if (!heap || !*heap)
return DRM_ERR(EFAULT);
/* Make things easier on ourselves: all allocations at least
* 4k aligned.
*/
if (alloc.alignment < 12)
alloc.alignment = 12;
block = alloc_block(*heap, alloc.size, alloc.alignment, filp);
if (!block)
return DRM_ERR(ENOMEM);
mark_block(dev, block, 1);
if (DRM_COPY_TO_USER(alloc.region_offset, &block->start, sizeof(int))) {
DRM_ERROR("copy_to_user\n");
return DRM_ERR(EFAULT);
}
return 0;
}
int i915_mem_free(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_i915_private_t *dev_priv = dev->dev_private;
drm_i915_mem_free_t memfree;
struct mem_block *block, **heap;
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
return DRM_ERR(EINVAL);
}
DRM_COPY_FROM_USER_IOCTL(memfree, (drm_i915_mem_free_t __user *) data,
sizeof(memfree));
heap = get_heap(dev_priv, memfree.region);
if (!heap || !*heap)
return DRM_ERR(EFAULT);
block = find_block(*heap, memfree.region_offset);
if (!block)
return DRM_ERR(EFAULT);
if (block->filp != filp)
return DRM_ERR(EPERM);
mark_block(dev, block, 0);
free_block(block);
return 0;
}
int i915_mem_init_heap(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_i915_private_t *dev_priv = dev->dev_private;
drm_i915_mem_init_heap_t initheap;
struct mem_block **heap;
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
return DRM_ERR(EINVAL);
}
DRM_COPY_FROM_USER_IOCTL(initheap,
(drm_i915_mem_init_heap_t __user *) data,
sizeof(initheap));
heap = get_heap(dev_priv, initheap.region);
if (!heap)
return DRM_ERR(EFAULT);
if (*heap) {
DRM_ERROR("heap already initialized?");
return DRM_ERR(EFAULT);
}
return init_heap(heap, initheap.start, initheap.size);
}
int i915_mem_destroy_heap( DRM_IOCTL_ARGS )
{
DRM_DEVICE;
drm_i915_private_t *dev_priv = dev->dev_private;
drm_i915_mem_destroy_heap_t destroyheap;
struct mem_block **heap;
if ( !dev_priv ) {
DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ );
return DRM_ERR(EINVAL);
}
DRM_COPY_FROM_USER_IOCTL( destroyheap, (drm_i915_mem_destroy_heap_t *)data,
sizeof(destroyheap) );
heap = get_heap( dev_priv, destroyheap.region );
if (!heap) {
DRM_ERROR("get_heap failed");
return DRM_ERR(EFAULT);
}
if (!*heap) {
DRM_ERROR("heap not initialized?");
return DRM_ERR(EFAULT);
}
i915_mem_takedown( heap );
return 0;
}

1532
sys/dev/pci/drm/mach64_dma.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,261 @@
/* mach64_drm.h -- Public header for the mach64 driver -*- linux-c -*-
* Created: Thu Nov 30 20:04:32 2000 by gareth@valinux.com
*/
/*-
* Copyright 2000 Gareth Hughes
* Copyright 2002 Frank C. Earl
* Copyright 2002-2003 Leif Delgass
* 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 COPYRIGHT OWNER(S) 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:
* Gareth Hughes <gareth@valinux.com>
* Frank C. Earl <fearl@airmail.net>
* Leif Delgass <ldelgass@retinalburn.net>
*/
#include <sys/cdefs.h>
/*
__FBSDID("$FreeBSD: src/sys/dev/drm/mach64_drm.h,v 1.3 2006/09/07 23:04:47 anholt Exp $");
*/
#ifndef __MACH64_DRM_H__
#define __MACH64_DRM_H__
/* WARNING: If you change any of these defines, make sure to change the
* defines in the Xserver file (mach64_sarea.h)
*/
#ifndef __MACH64_SAREA_DEFINES__
#define __MACH64_SAREA_DEFINES__
/* What needs to be changed for the current vertex buffer?
* GH: We're going to be pedantic about this. We want the card to do as
* little as possible, so let's avoid having it fetch a whole bunch of
* register values that don't change all that often, if at all.
*/
#define MACH64_UPLOAD_DST_OFF_PITCH 0x0001
#define MACH64_UPLOAD_Z_OFF_PITCH 0x0002
#define MACH64_UPLOAD_Z_ALPHA_CNTL 0x0004
#define MACH64_UPLOAD_SCALE_3D_CNTL 0x0008
#define MACH64_UPLOAD_DP_FOG_CLR 0x0010
#define MACH64_UPLOAD_DP_WRITE_MASK 0x0020
#define MACH64_UPLOAD_DP_PIX_WIDTH 0x0040
#define MACH64_UPLOAD_SETUP_CNTL 0x0080
#define MACH64_UPLOAD_MISC 0x0100
#define MACH64_UPLOAD_TEXTURE 0x0200
#define MACH64_UPLOAD_TEX0IMAGE 0x0400
#define MACH64_UPLOAD_TEX1IMAGE 0x0800
#define MACH64_UPLOAD_CLIPRECTS 0x1000 /* handled client-side */
#define MACH64_UPLOAD_CONTEXT 0x00ff
#define MACH64_UPLOAD_ALL 0x1fff
/* DMA buffer size
*/
#define MACH64_BUFFER_SIZE 16384
/* Max number of swaps allowed on the ring
* before the client must wait
*/
#define MACH64_MAX_QUEUED_FRAMES 3U
/* Byte offsets for host blit buffer data
*/
#define MACH64_HOSTDATA_BLIT_OFFSET 104
/* Keep these small for testing.
*/
#define MACH64_NR_SAREA_CLIPRECTS 8
#define MACH64_CARD_HEAP 0
#define MACH64_AGP_HEAP 1
#define MACH64_NR_TEX_HEAPS 2
#define MACH64_NR_TEX_REGIONS 64
#define MACH64_LOG_TEX_GRANULARITY 16
#define MACH64_TEX_MAXLEVELS 1
#define MACH64_NR_CONTEXT_REGS 15
#define MACH64_NR_TEXTURE_REGS 4
#endif /* __MACH64_SAREA_DEFINES__ */
typedef struct {
unsigned int dst_off_pitch;
unsigned int z_off_pitch;
unsigned int z_cntl;
unsigned int alpha_tst_cntl;
unsigned int scale_3d_cntl;
unsigned int sc_left_right;
unsigned int sc_top_bottom;
unsigned int dp_fog_clr;
unsigned int dp_write_mask;
unsigned int dp_pix_width;
unsigned int dp_mix;
unsigned int dp_src;
unsigned int clr_cmp_cntl;
unsigned int gui_traj_cntl;
unsigned int setup_cntl;
unsigned int tex_size_pitch;
unsigned int tex_cntl;
unsigned int secondary_tex_off;
unsigned int tex_offset;
} drm_mach64_context_regs_t;
typedef struct drm_mach64_sarea {
/* The channel for communication of state information to the kernel
* on firing a vertex dma buffer.
*/
drm_mach64_context_regs_t context_state;
unsigned int dirty;
unsigned int vertsize;
/* The current cliprects, or a subset thereof.
*/
drm_clip_rect_t boxes[MACH64_NR_SAREA_CLIPRECTS];
unsigned int nbox;
/* Counters for client-side throttling of rendering clients.
*/
unsigned int frames_queued;
/* Texture memory LRU.
*/
drm_tex_region_t tex_list[MACH64_NR_TEX_HEAPS][MACH64_NR_TEX_REGIONS +
1];
unsigned int tex_age[MACH64_NR_TEX_HEAPS];
int ctx_owner;
} drm_mach64_sarea_t;
/* WARNING: If you change any of these defines, make sure to change the
* defines in the Xserver file (mach64_common.h)
*/
/* Mach64 specific ioctls
* The device specific ioctl range is 0x40 to 0x79.
*/
#define DRM_MACH64_INIT 0x00
#define DRM_MACH64_IDLE 0x01
#define DRM_MACH64_RESET 0x02
#define DRM_MACH64_SWAP 0x03
#define DRM_MACH64_CLEAR 0x04
#define DRM_MACH64_VERTEX 0x05
#define DRM_MACH64_BLIT 0x06
#define DRM_MACH64_FLUSH 0x07
#define DRM_MACH64_GETPARAM 0x08
#define DRM_IOCTL_MACH64_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_MACH64_INIT, drm_mach64_init_t)
#define DRM_IOCTL_MACH64_IDLE DRM_IO( DRM_COMMAND_BASE + DRM_MACH64_IDLE )
#define DRM_IOCTL_MACH64_RESET DRM_IO( DRM_COMMAND_BASE + DRM_MACH64_RESET )
#define DRM_IOCTL_MACH64_SWAP DRM_IO( DRM_COMMAND_BASE + DRM_MACH64_SWAP )
#define DRM_IOCTL_MACH64_CLEAR DRM_IOW( DRM_COMMAND_BASE + DRM_MACH64_CLEAR, drm_mach64_clear_t)
#define DRM_IOCTL_MACH64_VERTEX DRM_IOW( DRM_COMMAND_BASE + DRM_MACH64_VERTEX, drm_mach64_vertex_t)
#define DRM_IOCTL_MACH64_BLIT DRM_IOW( DRM_COMMAND_BASE + DRM_MACH64_BLIT, drm_mach64_blit_t)
#define DRM_IOCTL_MACH64_FLUSH DRM_IO( DRM_COMMAND_BASE + DRM_MACH64_FLUSH )
#define DRM_IOCTL_MACH64_GETPARAM DRM_IOWR( DRM_COMMAND_BASE + DRM_MACH64_GETPARAM, drm_mach64_getparam_t)
/* Buffer flags for clears
*/
#define MACH64_FRONT 0x1
#define MACH64_BACK 0x2
#define MACH64_DEPTH 0x4
/* Primitive types for vertex buffers
*/
#define MACH64_PRIM_POINTS 0x00000000
#define MACH64_PRIM_LINES 0x00000001
#define MACH64_PRIM_LINE_LOOP 0x00000002
#define MACH64_PRIM_LINE_STRIP 0x00000003
#define MACH64_PRIM_TRIANGLES 0x00000004
#define MACH64_PRIM_TRIANGLE_STRIP 0x00000005
#define MACH64_PRIM_TRIANGLE_FAN 0x00000006
#define MACH64_PRIM_QUADS 0x00000007
#define MACH64_PRIM_QUAD_STRIP 0x00000008
#define MACH64_PRIM_POLYGON 0x00000009
typedef enum _drm_mach64_dma_mode_t {
MACH64_MODE_DMA_ASYNC,
MACH64_MODE_DMA_SYNC,
MACH64_MODE_MMIO
} drm_mach64_dma_mode_t;
typedef struct drm_mach64_init {
enum {
DRM_MACH64_INIT_DMA = 0x01,
DRM_MACH64_CLEANUP_DMA = 0x02
} func;
unsigned long sarea_priv_offset;
int is_pci;
drm_mach64_dma_mode_t dma_mode;
unsigned int fb_bpp;
unsigned int front_offset, front_pitch;
unsigned int back_offset, back_pitch;
unsigned int depth_bpp;
unsigned int depth_offset, depth_pitch;
unsigned long fb_offset;
unsigned long mmio_offset;
unsigned long ring_offset;
unsigned long buffers_offset;
unsigned long agp_textures_offset;
} drm_mach64_init_t;
typedef struct drm_mach64_clear {
unsigned int flags;
int x, y, w, h;
unsigned int clear_color;
unsigned int clear_depth;
} drm_mach64_clear_t;
typedef struct drm_mach64_vertex {
int prim;
void *buf; /* Address of vertex buffer */
unsigned long used; /* Number of bytes in buffer */
int discard; /* Client finished with buffer? */
} drm_mach64_vertex_t;
typedef struct drm_mach64_blit {
int idx;
int pitch;
int offset;
int format;
unsigned short x, y;
unsigned short width, height;
} drm_mach64_blit_t;
typedef struct drm_mach64_getparam {
enum {
MACH64_PARAM_FRAMES_QUEUED = 0x01,
MACH64_PARAM_IRQ_NR = 0x02
} param;
void *value;
} drm_mach64_getparam_t;
#endif

View File

@ -0,0 +1,142 @@
/* mach64_drv.c -- ATI Rage 128 driver -*- linux-c -*-
* Created: Mon Dec 13 09:47:27 1999 by faith@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
* 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 <sys/cdefs.h>
/*
__FBSDID("$FreeBSD: src/sys/dev/drm/mach64_drv.c,v 1.3 2005/12/20 22:44:36 jhb Exp $");
*/
#include <sys/types.h>
#include "drmP.h"
#include "drm.h"
#include "mach64_drm.h"
#include "mach64_drv.h"
#include "drm_pciids.h"
/* drv_PCI_IDs comes from drm_pciids.h, generated from drm_pciids.txt. */
static drm_pci_id_list_t mach64_pciidlist[] = {
mach64_PCI_IDS
};
static void mach64_configure(drm_device_t *dev)
{
dev->driver.buf_priv_size = 1; /* No dev_priv */
dev->driver.lastclose = mach64_driver_lastclose;
dev->driver.vblank_wait = mach64_driver_vblank_wait;
dev->driver.irq_preinstall = mach64_driver_irq_preinstall;
dev->driver.irq_postinstall = mach64_driver_irq_postinstall;
dev->driver.irq_uninstall = mach64_driver_irq_uninstall;
dev->driver.irq_handler = mach64_driver_irq_handler;
dev->driver.dma_ioctl = mach64_dma_buffers;
dev->driver.ioctls = mach64_ioctls;
dev->driver.max_ioctl = mach64_max_ioctl;
dev->driver.name = DRIVER_NAME;
dev->driver.desc = DRIVER_DESC;
dev->driver.date = DRIVER_DATE;
dev->driver.major = DRIVER_MAJOR;
dev->driver.minor = DRIVER_MINOR;
dev->driver.patchlevel = DRIVER_PATCHLEVEL;
dev->driver.use_agp = 1;
dev->driver.use_mtrr = 1;
dev->driver.use_pci_dma = 1;
dev->driver.use_dma = 1;
dev->driver.use_irq = 1;
dev->driver.use_vbl_irq = 1;
}
#ifdef __FreeBSD__
static int
mach64_probe(device_t dev)
{
return drm_probe(dev, mach64_pciidlist);
}
static int
mach64_attach(device_t nbdev)
{
drm_device_t *dev = device_get_softc(nbdev);
bzero(dev, sizeof(drm_device_t));
mach64_configure(dev);
return drm_attach(nbdev, mach64_pciidlist);
}
static device_method_t mach64_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, mach64_probe),
DEVMETHOD(device_attach, mach64_attach),
DEVMETHOD(device_detach, drm_detach),
{ 0, 0 }
};
static driver_t mach64_driver = {
"drm",
mach64_methods,
sizeof(drm_device_t)
};
extern devclass_t drm_devclass;
#if __FreeBSD_version >= 700010
DRIVER_MODULE(mach64, vgapci, mach64_driver, drm_devclass, 0, 0);
#else
DRIVER_MODULE(mach64, pci, mach64_driver, drm_devclass, 0, 0);
#endif
MODULE_DEPEND(mach64, drm, 1, 1, 1);
#elif defined(__NetBSD__) || defined(__OpenBSD__)
static int
mach64drm_probe(struct device *parent, struct cfdata *match, void *aux)
{
struct pci_attach_args *pa = aux;
return drm_probe(pa, mach64_pciidlist);
}
static void
mach64drm_attach(struct device *parent, struct device *self, void *aux)
{
struct pci_attach_args *pa = aux;
drm_device_t *dev = (drm_device_t *)self;
mach64_configure(dev);
return drm_attach(self, pa, mach64_pciidlist);
}
CFATTACH_DECL(mach64drm, sizeof(drm_device_t), mach64drm_probe, mach64drm_attach,
drm_detach, drm_activate);
#endif

1052
sys/dev/pci/drm/mach64_drv.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,141 @@
/* mach64_irq.c -- IRQ handling for ATI Mach64 -*- linux-c -*-
* Created: Tue Feb 25, 2003 by Leif Delgass, based on radeon_irq.c/r128_irq.c
*/
/*-
* Copyright (C) The Weather Channel, Inc. 2002.
* Copyright 2003 Leif Delgass
* All Rights Reserved.
*
* The Weather Channel (TM) funded Tungsten Graphics to develop the
* initial release of the Radeon 8500 driver under the XFree86 license.
* This notice must be preserved.
*
* 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 COPYRIGHT OWNER(S) 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>
* Eric Anholt <anholt@FreeBSD.org>
* Leif Delgass <ldelgass@retinalburn.net>
*/
#include <sys/cdefs.h>
/*
__FBSDID("$FreeBSD: src/sys/dev/drm/mach64_irq.c,v 1.2 2005/11/28 23:13:53 anholt Exp $");
*/
#include "drmP.h"
#include "drm.h"
#include "mach64_drm.h"
#include "mach64_drv.h"
irqreturn_t mach64_driver_irq_handler(DRM_IRQ_ARGS)
{
drm_device_t *dev = (drm_device_t *) arg;
drm_mach64_private_t *dev_priv =
(drm_mach64_private_t *) dev->dev_private;
int status;
status = MACH64_READ(MACH64_CRTC_INT_CNTL);
/* VBLANK interrupt */
if (status & MACH64_CRTC_VBLANK_INT) {
/* Mask off all interrupt ack bits before setting the ack bit, since
* there may be other handlers outside the DRM.
*
* NOTE: On mach64, you need to keep the enable bits set when doing
* the ack, despite what the docs say about not acking and enabling
* in a single write.
*/
MACH64_WRITE(MACH64_CRTC_INT_CNTL,
(status & ~MACH64_CRTC_INT_ACKS)
| MACH64_CRTC_VBLANK_INT);
atomic_inc(&dev->vbl_received);
DRM_WAKEUP(&dev->vbl_queue);
drm_vbl_send_signals(dev);
return IRQ_HANDLED;
}
return IRQ_NONE;
}
int mach64_driver_vblank_wait(drm_device_t * dev, unsigned int *sequence)
{
unsigned int cur_vblank;
int ret = 0;
/* Assume that the user has missed the current sequence number
* by about a day rather than she wants to wait for years
* using vertical blanks...
*/
DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
(((cur_vblank = atomic_read(&dev->vbl_received))
- *sequence) <= (1 << 23)));
*sequence = cur_vblank;
return ret;
}
/* drm_dma.h hooks
*/
void mach64_driver_irq_preinstall(drm_device_t * dev)
{
drm_mach64_private_t *dev_priv =
(drm_mach64_private_t *) dev->dev_private;
u32 status = MACH64_READ(MACH64_CRTC_INT_CNTL);
DRM_DEBUG("before install CRTC_INT_CTNL: 0x%08x\n", status);
/* Disable and clear VBLANK interrupt */
MACH64_WRITE(MACH64_CRTC_INT_CNTL, (status & ~MACH64_CRTC_VBLANK_INT_EN)
| MACH64_CRTC_VBLANK_INT);
}
void mach64_driver_irq_postinstall(drm_device_t * dev)
{
drm_mach64_private_t *dev_priv =
(drm_mach64_private_t *) dev->dev_private;
/* Turn on VBLANK interrupt */
MACH64_WRITE(MACH64_CRTC_INT_CNTL, MACH64_READ(MACH64_CRTC_INT_CNTL)
| MACH64_CRTC_VBLANK_INT_EN);
DRM_DEBUG("after install CRTC_INT_CTNL: 0x%08x\n",
MACH64_READ(MACH64_CRTC_INT_CNTL));
}
void mach64_driver_irq_uninstall(drm_device_t * dev)
{
drm_mach64_private_t *dev_priv =
(drm_mach64_private_t *) dev->dev_private;
if (!dev_priv)
return;
/* Disable and clear VBLANK interrupt */
MACH64_WRITE(MACH64_CRTC_INT_CNTL,
(MACH64_READ(MACH64_CRTC_INT_CNTL) &
~MACH64_CRTC_VBLANK_INT_EN)
| MACH64_CRTC_VBLANK_INT);
DRM_DEBUG("after uninstall CRTC_INT_CTNL: 0x%08x\n",
MACH64_READ(MACH64_CRTC_INT_CNTL));
}

View File

@ -0,0 +1,923 @@
/* mach64_state.c -- State support for mach64 (Rage Pro) driver -*- linux-c -*-
* Created: Sun Dec 03 19:20:26 2000 by gareth@valinux.com
*/
/*-
* Copyright 2000 Gareth Hughes
* Copyright 2002-2003 Leif Delgass
* 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 COPYRIGHT OWNER(S) 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:
* Gareth Hughes <gareth@valinux.com>
* Leif Delgass <ldelgass@retinalburn.net>
* Jos<EFBFBD>Fonseca <j_r_fonseca@yahoo.co.uk>
*/
#include <sys/cdefs.h>
/*
__FBSDID("$FreeBSD: src/sys/dev/drm/mach64_state.c,v 1.2 2005/11/28 23:13:53 anholt Exp $");
*/
#include "drmP.h"
#include "drm.h"
#include "mach64_drm.h"
#include "mach64_drv.h"
/* Interface history:
*
* 1.0 - Initial mach64 DRM
*
*/
drm_ioctl_desc_t mach64_ioctls[] = {
[DRM_IOCTL_NR(DRM_MACH64_INIT)] = {mach64_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
[DRM_IOCTL_NR(DRM_MACH64_CLEAR)] = {mach64_dma_clear, DRM_AUTH},
[DRM_IOCTL_NR(DRM_MACH64_SWAP)] = {mach64_dma_swap, DRM_AUTH},
[DRM_IOCTL_NR(DRM_MACH64_IDLE)] = {mach64_dma_idle, DRM_AUTH},
[DRM_IOCTL_NR(DRM_MACH64_RESET)] = {mach64_engine_reset, DRM_AUTH},
[DRM_IOCTL_NR(DRM_MACH64_VERTEX)] = {mach64_dma_vertex, DRM_AUTH},
[DRM_IOCTL_NR(DRM_MACH64_BLIT)] = {mach64_dma_blit, DRM_AUTH},
[DRM_IOCTL_NR(DRM_MACH64_FLUSH)] = {mach64_dma_flush, DRM_AUTH},
[DRM_IOCTL_NR(DRM_MACH64_GETPARAM)] = {mach64_get_param, DRM_AUTH},
};
int mach64_max_ioctl = DRM_ARRAY_SIZE(mach64_ioctls);
/* ================================================================
* DMA hardware state programming functions
*/
static void mach64_print_dirty(const char *msg, unsigned int flags)
{
DRM_DEBUG("%s: (0x%x) %s%s%s%s%s%s%s%s%s%s%s%s\n",
msg,
flags,
(flags & MACH64_UPLOAD_DST_OFF_PITCH) ? "dst_off_pitch, " :
"",
(flags & MACH64_UPLOAD_Z_ALPHA_CNTL) ? "z_alpha_cntl, " : "",
(flags & MACH64_UPLOAD_SCALE_3D_CNTL) ? "scale_3d_cntl, " :
"", (flags & MACH64_UPLOAD_DP_FOG_CLR) ? "dp_fog_clr, " : "",
(flags & MACH64_UPLOAD_DP_WRITE_MASK) ? "dp_write_mask, " :
"",
(flags & MACH64_UPLOAD_DP_PIX_WIDTH) ? "dp_pix_width, " : "",
(flags & MACH64_UPLOAD_SETUP_CNTL) ? "setup_cntl, " : "",
(flags & MACH64_UPLOAD_MISC) ? "misc, " : "",
(flags & MACH64_UPLOAD_TEXTURE) ? "texture, " : "",
(flags & MACH64_UPLOAD_TEX0IMAGE) ? "tex0 image, " : "",
(flags & MACH64_UPLOAD_TEX1IMAGE) ? "tex1 image, " : "",
(flags & MACH64_UPLOAD_CLIPRECTS) ? "cliprects, " : "");
}
/* Mach64 doesn't have hardware cliprects, just one hardware scissor,
* so the GL scissor is intersected with each cliprect here
*/
/* This function returns 0 on success, 1 for no intersection, and
* negative for an error
*/
static int mach64_emit_cliprect(DRMFILE filp, drm_mach64_private_t * dev_priv,
drm_clip_rect_t * box)
{
u32 sc_left_right, sc_top_bottom;
drm_clip_rect_t scissor;
drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv;
drm_mach64_context_regs_t *regs = &sarea_priv->context_state;
DMALOCALS;
DRM_DEBUG("%s: box=%p\n", __FUNCTION__, box);
/* Get GL scissor */
/* FIXME: store scissor in SAREA as a cliprect instead of in
* hardware format, or do intersection client-side
*/
scissor.x1 = regs->sc_left_right & 0xffff;
scissor.x2 = (regs->sc_left_right & 0xffff0000) >> 16;
scissor.y1 = regs->sc_top_bottom & 0xffff;
scissor.y2 = (regs->sc_top_bottom & 0xffff0000) >> 16;
/* Intersect GL scissor with cliprect */
if (box->x1 > scissor.x1)
scissor.x1 = box->x1;
if (box->y1 > scissor.y1)
scissor.y1 = box->y1;
if (box->x2 < scissor.x2)
scissor.x2 = box->x2;
if (box->y2 < scissor.y2)
scissor.y2 = box->y2;
/* positive return means skip */
if (scissor.x1 >= scissor.x2)
return 1;
if (scissor.y1 >= scissor.y2)
return 1;
DMAGETPTR(filp, dev_priv, 2); /* returns on failure to get buffer */
sc_left_right = ((scissor.x1 << 0) | (scissor.x2 << 16));
sc_top_bottom = ((scissor.y1 << 0) | (scissor.y2 << 16));
DMAOUTREG(MACH64_SC_LEFT_RIGHT, sc_left_right);
DMAOUTREG(MACH64_SC_TOP_BOTTOM, sc_top_bottom);
DMAADVANCE(dev_priv, 1);
return 0;
}
static __inline__ int mach64_emit_state(DRMFILE filp,
drm_mach64_private_t * dev_priv)
{
drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv;
drm_mach64_context_regs_t *regs = &sarea_priv->context_state;
unsigned int dirty = sarea_priv->dirty;
u32 offset = ((regs->tex_size_pitch & 0xf0) >> 2);
DMALOCALS;
if (MACH64_VERBOSE) {
mach64_print_dirty(__FUNCTION__, dirty);
} else {
DRM_DEBUG("%s: dirty=0x%08x\n", __FUNCTION__, dirty);
}
DMAGETPTR(filp, dev_priv, 17); /* returns on failure to get buffer */
if (dirty & MACH64_UPLOAD_MISC) {
DMAOUTREG(MACH64_DP_MIX, regs->dp_mix);
DMAOUTREG(MACH64_DP_SRC, regs->dp_src);
DMAOUTREG(MACH64_CLR_CMP_CNTL, regs->clr_cmp_cntl);
DMAOUTREG(MACH64_GUI_TRAJ_CNTL, regs->gui_traj_cntl);
sarea_priv->dirty &= ~MACH64_UPLOAD_MISC;
}
if (dirty & MACH64_UPLOAD_DST_OFF_PITCH) {
DMAOUTREG(MACH64_DST_OFF_PITCH, regs->dst_off_pitch);
sarea_priv->dirty &= ~MACH64_UPLOAD_DST_OFF_PITCH;
}
if (dirty & MACH64_UPLOAD_Z_OFF_PITCH) {
DMAOUTREG(MACH64_Z_OFF_PITCH, regs->z_off_pitch);
sarea_priv->dirty &= ~MACH64_UPLOAD_Z_OFF_PITCH;
}
if (dirty & MACH64_UPLOAD_Z_ALPHA_CNTL) {
DMAOUTREG(MACH64_Z_CNTL, regs->z_cntl);
DMAOUTREG(MACH64_ALPHA_TST_CNTL, regs->alpha_tst_cntl);
sarea_priv->dirty &= ~MACH64_UPLOAD_Z_ALPHA_CNTL;
}
if (dirty & MACH64_UPLOAD_SCALE_3D_CNTL) {
DMAOUTREG(MACH64_SCALE_3D_CNTL, regs->scale_3d_cntl);
sarea_priv->dirty &= ~MACH64_UPLOAD_SCALE_3D_CNTL;
}
if (dirty & MACH64_UPLOAD_DP_FOG_CLR) {
DMAOUTREG(MACH64_DP_FOG_CLR, regs->dp_fog_clr);
sarea_priv->dirty &= ~MACH64_UPLOAD_DP_FOG_CLR;
}
if (dirty & MACH64_UPLOAD_DP_WRITE_MASK) {
DMAOUTREG(MACH64_DP_WRITE_MASK, regs->dp_write_mask);
sarea_priv->dirty &= ~MACH64_UPLOAD_DP_WRITE_MASK;
}
if (dirty & MACH64_UPLOAD_DP_PIX_WIDTH) {
DMAOUTREG(MACH64_DP_PIX_WIDTH, regs->dp_pix_width);
sarea_priv->dirty &= ~MACH64_UPLOAD_DP_PIX_WIDTH;
}
if (dirty & MACH64_UPLOAD_SETUP_CNTL) {
DMAOUTREG(MACH64_SETUP_CNTL, regs->setup_cntl);
sarea_priv->dirty &= ~MACH64_UPLOAD_SETUP_CNTL;
}
if (dirty & MACH64_UPLOAD_TEXTURE) {
DMAOUTREG(MACH64_TEX_SIZE_PITCH, regs->tex_size_pitch);
DMAOUTREG(MACH64_TEX_CNTL, regs->tex_cntl);
DMAOUTREG(MACH64_SECONDARY_TEX_OFF, regs->secondary_tex_off);
DMAOUTREG(MACH64_TEX_0_OFF + offset, regs->tex_offset);
sarea_priv->dirty &= ~MACH64_UPLOAD_TEXTURE;
}
DMAADVANCE(dev_priv, 1);
sarea_priv->dirty &= MACH64_UPLOAD_CLIPRECTS;
return 0;
}
/* ================================================================
* DMA command dispatch functions
*/
static int mach64_dma_dispatch_clear(DRMFILE filp, drm_device_t * dev,
unsigned int flags,
int cx, int cy, int cw, int ch,
unsigned int clear_color,
unsigned int clear_depth)
{
drm_mach64_private_t *dev_priv = dev->dev_private;
drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv;
drm_mach64_context_regs_t *ctx = &sarea_priv->context_state;
int nbox = sarea_priv->nbox;
drm_clip_rect_t *pbox = sarea_priv->boxes;
u32 fb_bpp, depth_bpp;
int i;
DMALOCALS;
DRM_DEBUG("%s\n", __FUNCTION__);
switch (dev_priv->fb_bpp) {
case 16:
fb_bpp = MACH64_DATATYPE_RGB565;
break;
case 32:
fb_bpp = MACH64_DATATYPE_ARGB8888;
break;
default:
return DRM_ERR(EINVAL);
}
switch (dev_priv->depth_bpp) {
case 16:
depth_bpp = MACH64_DATATYPE_RGB565;
break;
case 24:
case 32:
depth_bpp = MACH64_DATATYPE_ARGB8888;
break;
default:
return DRM_ERR(EINVAL);
}
if (!nbox)
return 0;
DMAGETPTR(filp, dev_priv, nbox * 31); /* returns on failure to get buffer */
for (i = 0; i < nbox; i++) {
int x = pbox[i].x1;
int y = pbox[i].y1;
int w = pbox[i].x2 - x;
int h = pbox[i].y2 - y;
DRM_DEBUG("dispatch clear %d,%d-%d,%d flags 0x%x\n",
pbox[i].x1, pbox[i].y1,
pbox[i].x2, pbox[i].y2, flags);
if (flags & (MACH64_FRONT | MACH64_BACK)) {
/* Setup for color buffer clears
*/
DMAOUTREG(MACH64_Z_CNTL, 0);
DMAOUTREG(MACH64_SCALE_3D_CNTL, 0);
DMAOUTREG(MACH64_SC_LEFT_RIGHT, ctx->sc_left_right);
DMAOUTREG(MACH64_SC_TOP_BOTTOM, ctx->sc_top_bottom);
DMAOUTREG(MACH64_CLR_CMP_CNTL, 0);
DMAOUTREG(MACH64_GUI_TRAJ_CNTL,
(MACH64_DST_X_LEFT_TO_RIGHT |
MACH64_DST_Y_TOP_TO_BOTTOM));
DMAOUTREG(MACH64_DP_PIX_WIDTH, ((fb_bpp << 0) |
(fb_bpp << 4) |
(fb_bpp << 8) |
(fb_bpp << 16) |
(fb_bpp << 28)));
DMAOUTREG(MACH64_DP_FRGD_CLR, clear_color);
DMAOUTREG(MACH64_DP_WRITE_MASK, ctx->dp_write_mask);
DMAOUTREG(MACH64_DP_MIX, (MACH64_BKGD_MIX_D |
MACH64_FRGD_MIX_S));
DMAOUTREG(MACH64_DP_SRC, (MACH64_BKGD_SRC_FRGD_CLR |
MACH64_FRGD_SRC_FRGD_CLR |
MACH64_MONO_SRC_ONE));
}
if (flags & MACH64_FRONT) {
DMAOUTREG(MACH64_DST_OFF_PITCH,
dev_priv->front_offset_pitch);
DMAOUTREG(MACH64_DST_X_Y, (y << 16) | x);
DMAOUTREG(MACH64_DST_WIDTH_HEIGHT, (h << 16) | w);
}
if (flags & MACH64_BACK) {
DMAOUTREG(MACH64_DST_OFF_PITCH,
dev_priv->back_offset_pitch);
DMAOUTREG(MACH64_DST_X_Y, (y << 16) | x);
DMAOUTREG(MACH64_DST_WIDTH_HEIGHT, (h << 16) | w);
}
if (flags & MACH64_DEPTH) {
/* Setup for depth buffer clear
*/
DMAOUTREG(MACH64_Z_CNTL, 0);
DMAOUTREG(MACH64_SCALE_3D_CNTL, 0);
DMAOUTREG(MACH64_SC_LEFT_RIGHT, ctx->sc_left_right);
DMAOUTREG(MACH64_SC_TOP_BOTTOM, ctx->sc_top_bottom);
DMAOUTREG(MACH64_CLR_CMP_CNTL, 0);
DMAOUTREG(MACH64_GUI_TRAJ_CNTL,
(MACH64_DST_X_LEFT_TO_RIGHT |
MACH64_DST_Y_TOP_TO_BOTTOM));
DMAOUTREG(MACH64_DP_PIX_WIDTH, ((depth_bpp << 0) |
(depth_bpp << 4) |
(depth_bpp << 8) |
(depth_bpp << 16) |
(depth_bpp << 28)));
DMAOUTREG(MACH64_DP_FRGD_CLR, clear_depth);
DMAOUTREG(MACH64_DP_WRITE_MASK, 0xffffffff);
DMAOUTREG(MACH64_DP_MIX, (MACH64_BKGD_MIX_D |
MACH64_FRGD_MIX_S));
DMAOUTREG(MACH64_DP_SRC, (MACH64_BKGD_SRC_FRGD_CLR |
MACH64_FRGD_SRC_FRGD_CLR |
MACH64_MONO_SRC_ONE));
DMAOUTREG(MACH64_DST_OFF_PITCH,
dev_priv->depth_offset_pitch);
DMAOUTREG(MACH64_DST_X_Y, (y << 16) | x);
DMAOUTREG(MACH64_DST_WIDTH_HEIGHT, (h << 16) | w);
}
}
DMAADVANCE(dev_priv, 1);
return 0;
}
static int mach64_dma_dispatch_swap(DRMFILE filp, drm_device_t * dev)
{
drm_mach64_private_t *dev_priv = dev->dev_private;
drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv;
int nbox = sarea_priv->nbox;
drm_clip_rect_t *pbox = sarea_priv->boxes;
u32 fb_bpp;
int i;
DMALOCALS;
DRM_DEBUG("%s\n", __FUNCTION__);
switch (dev_priv->fb_bpp) {
case 16:
fb_bpp = MACH64_DATATYPE_RGB565;
break;
case 32:
default:
fb_bpp = MACH64_DATATYPE_ARGB8888;
break;
}
if (!nbox)
return 0;
DMAGETPTR(filp, dev_priv, 13 + nbox * 4); /* returns on failure to get buffer */
DMAOUTREG(MACH64_Z_CNTL, 0);
DMAOUTREG(MACH64_SCALE_3D_CNTL, 0);
DMAOUTREG(MACH64_SC_LEFT_RIGHT, 0 | (8191 << 16)); /* no scissor */
DMAOUTREG(MACH64_SC_TOP_BOTTOM, 0 | (16383 << 16));
DMAOUTREG(MACH64_CLR_CMP_CNTL, 0);
DMAOUTREG(MACH64_GUI_TRAJ_CNTL, (MACH64_DST_X_LEFT_TO_RIGHT |
MACH64_DST_Y_TOP_TO_BOTTOM));
DMAOUTREG(MACH64_DP_PIX_WIDTH, ((fb_bpp << 0) |
(fb_bpp << 4) |
(fb_bpp << 8) |
(fb_bpp << 16) | (fb_bpp << 28)));
DMAOUTREG(MACH64_DP_WRITE_MASK, 0xffffffff);
DMAOUTREG(MACH64_DP_MIX, (MACH64_BKGD_MIX_D | MACH64_FRGD_MIX_S));
DMAOUTREG(MACH64_DP_SRC, (MACH64_BKGD_SRC_BKGD_CLR |
MACH64_FRGD_SRC_BLIT | MACH64_MONO_SRC_ONE));
DMAOUTREG(MACH64_SRC_OFF_PITCH, dev_priv->back_offset_pitch);
DMAOUTREG(MACH64_DST_OFF_PITCH, dev_priv->front_offset_pitch);
for (i = 0; i < nbox; i++) {
int x = pbox[i].x1;
int y = pbox[i].y1;
int w = pbox[i].x2 - x;
int h = pbox[i].y2 - y;
DRM_DEBUG("dispatch swap %d,%d-%d,%d\n",
pbox[i].x1, pbox[i].y1, pbox[i].x2, pbox[i].y2);
DMAOUTREG(MACH64_SRC_WIDTH1, w);
DMAOUTREG(MACH64_SRC_Y_X, (x << 16) | y);
DMAOUTREG(MACH64_DST_Y_X, (x << 16) | y);
DMAOUTREG(MACH64_DST_WIDTH_HEIGHT, (h << 16) | w);
}
DMAADVANCE(dev_priv, 1);
if (dev_priv->driver_mode == MACH64_MODE_DMA_ASYNC) {
for (i = 0; i < MACH64_MAX_QUEUED_FRAMES - 1; i++) {
dev_priv->frame_ofs[i] = dev_priv->frame_ofs[i + 1];
}
dev_priv->frame_ofs[i] = GETRINGOFFSET();
dev_priv->sarea_priv->frames_queued++;
}
return 0;
}
static int mach64_do_get_frames_queued(drm_mach64_private_t * dev_priv)
{
drm_mach64_descriptor_ring_t *ring = &dev_priv->ring;
drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv;
int i, start;
u32 head, tail, ofs;
DRM_DEBUG("%s\n", __FUNCTION__);
if (sarea_priv->frames_queued == 0)
return 0;
tail = ring->tail;
mach64_ring_tick(dev_priv, ring);
head = ring->head;
start = (MACH64_MAX_QUEUED_FRAMES -
DRM_MIN(MACH64_MAX_QUEUED_FRAMES, sarea_priv->frames_queued));
if (head == tail) {
sarea_priv->frames_queued = 0;
for (i = start; i < MACH64_MAX_QUEUED_FRAMES; i++) {
dev_priv->frame_ofs[i] = ~0;
}
return 0;
}
for (i = start; i < MACH64_MAX_QUEUED_FRAMES; i++) {
ofs = dev_priv->frame_ofs[i];
DRM_DEBUG("frame_ofs[%d] ofs: %d\n", i, ofs);
if (ofs == ~0 ||
(head < tail && (ofs < head || ofs >= tail)) ||
(head > tail && (ofs < head && ofs >= tail))) {
sarea_priv->frames_queued =
(MACH64_MAX_QUEUED_FRAMES - 1) - i;
dev_priv->frame_ofs[i] = ~0;
}
}
return sarea_priv->frames_queued;
}
/* Copy and verify a client submited buffer.
* FIXME: Make an assembly optimized version
*/
static __inline__ int copy_and_verify_from_user(u32 *to,
const u32 __user *ufrom,
unsigned long bytes)
{
unsigned long n = bytes; /* dwords remaining in buffer */
u32 *from, *orig_from;
from = drm_alloc(bytes, DRM_MEM_DRIVER);
if (from == NULL)
return ENOMEM;
if (DRM_COPY_FROM_USER(from, ufrom, bytes)) {
drm_free(from, bytes, DRM_MEM_DRIVER);
return DRM_ERR(EFAULT);
}
orig_from = from; /* we'll be modifying the "from" ptr, so save it */
n >>= 2;
while (n > 1) {
u32 data, reg, count;
data = *from++;
n--;
reg = le32_to_cpu(data);
count = (reg >> 16) + 1;
if (count <= n) {
n -= count;
reg &= 0xffff;
/* This is an exact match of Mach64's Setup Engine registers,
* excluding SETUP_CNTL (1_C1).
*/
if ((reg >= 0x0190 && reg < 0x01c1) ||
(reg >= 0x01ca && reg <= 0x01cf)) {
*to++ = data;
memcpy(to, from, count << 2);
from += count;
to += count;
} else {
DRM_ERROR("%s: Got bad command: 0x%04x\n",
__FUNCTION__, reg);
drm_free(orig_from, bytes, DRM_MEM_DRIVER);
return DRM_ERR(EACCES);
}
} else {
DRM_ERROR
("%s: Got bad command count(=%u) dwords remaining=%lu\n",
__FUNCTION__, count, n);
drm_free(orig_from, bytes, DRM_MEM_DRIVER);
return DRM_ERR(EINVAL);
}
}
drm_free(orig_from, bytes, DRM_MEM_DRIVER);
if (n == 0)
return 0;
else {
DRM_ERROR("%s: Bad buf->used(=%lu)\n", __FUNCTION__, bytes);
return DRM_ERR(EINVAL);
}
}
static int mach64_dma_dispatch_vertex(DRMFILE filp, drm_device_t * dev,
int prim, void *buf, unsigned long used,
int discard)
{
drm_mach64_private_t *dev_priv = dev->dev_private;
drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv;
drm_buf_t *copy_buf;
int done = 0;
int verify_ret = 0;
DMALOCALS;
DRM_DEBUG("%s: buf=%p used=%lu nbox=%d\n",
__FUNCTION__, buf, used, sarea_priv->nbox);
if (used) {
int ret = 0;
int i = 0;
copy_buf = mach64_freelist_get(dev_priv);
if (copy_buf == NULL) {
DRM_ERROR("%s: couldn't get buffer in DMAGETPTR\n",
__FUNCTION__);
return DRM_ERR(EAGAIN);
}
if ((verify_ret =
copy_and_verify_from_user(GETBUFPTR(copy_buf), buf,
used)) == 0) {
copy_buf->used = used;
DMASETPTR(copy_buf);
if (sarea_priv->dirty & ~MACH64_UPLOAD_CLIPRECTS) {
ret = mach64_emit_state(filp, dev_priv);
if (ret < 0)
return ret;
}
do {
/* Emit the next cliprect */
if (i < sarea_priv->nbox) {
ret =
mach64_emit_cliprect(filp, dev_priv,
&sarea_priv->
boxes[i]);
if (ret < 0) {
/* failed to get buffer */
return ret;
} else if (ret != 0) {
/* null intersection with scissor */
continue;
}
}
if ((i >= sarea_priv->nbox - 1))
done = 1;
/* Add the buffer to the DMA queue */
DMAADVANCE(dev_priv, done);
} while (++i < sarea_priv->nbox);
}
if (copy_buf->pending && !done) {
DMADISCARDBUF();
} else if (!done) {
/* This buffer wasn't used (no cliprects or verify failed), so place it back
* on the free list
*/
struct list_head *ptr;
drm_mach64_freelist_t *entry;
#if MACH64_EXTRA_CHECKING
list_for_each(ptr, &dev_priv->pending) {
entry =
list_entry(ptr, drm_mach64_freelist_t,
list);
if (copy_buf == entry->buf) {
DRM_ERROR
("%s: Trying to release a pending buf\n",
__FUNCTION__);
return DRM_ERR(EFAULT);
}
}
#endif
ptr = dev_priv->placeholders.next;
entry = list_entry(ptr, drm_mach64_freelist_t, list);
copy_buf->pending = 0;
copy_buf->used = 0;
entry->buf = copy_buf;
entry->discard = 1;
list_del(ptr);
list_add_tail(ptr, &dev_priv->free_list);
}
}
sarea_priv->dirty &= ~MACH64_UPLOAD_CLIPRECTS;
sarea_priv->nbox = 0;
return verify_ret;
}
static int mach64_dma_dispatch_blit(DRMFILE filp, drm_device_t * dev,
drm_mach64_blit_t * blit)
{
drm_mach64_private_t *dev_priv = dev->dev_private;
drm_device_dma_t *dma = dev->dma;
int dword_shift, dwords;
drm_buf_t *buf;
DMALOCALS;
/* The compiler won't optimize away a division by a variable,
* even if the only legal values are powers of two. Thus, we'll
* use a shift instead.
*/
switch (blit->format) {
case MACH64_DATATYPE_ARGB8888:
dword_shift = 0;
break;
case MACH64_DATATYPE_ARGB1555:
case MACH64_DATATYPE_RGB565:
case MACH64_DATATYPE_VYUY422:
case MACH64_DATATYPE_YVYU422:
case MACH64_DATATYPE_ARGB4444:
dword_shift = 1;
break;
case MACH64_DATATYPE_CI8:
case MACH64_DATATYPE_RGB8:
dword_shift = 2;
break;
default:
DRM_ERROR("invalid blit format %d\n", blit->format);
return DRM_ERR(EINVAL);
}
/* Dispatch the blit buffer.
*/
buf = dma->buflist[blit->idx];
if (buf->filp != filp) {
DRM_ERROR("process %d (filp %p) using buffer with filp %p\n",
DRM_CURRENTPID, filp, buf->filp);
return DRM_ERR(EINVAL);
}
if (buf->pending) {
DRM_ERROR("sending pending buffer %d\n", blit->idx);
return DRM_ERR(EINVAL);
}
/* Set buf->used to the bytes of blit data based on the blit dimensions
* and verify the size. When the setup is emitted to the buffer with
* the DMA* macros below, buf->used is incremented to include the bytes
* used for setup as well as the blit data.
*/
dwords = (blit->width * blit->height) >> dword_shift;
buf->used = dwords << 2;
if (buf->used <= 0 ||
buf->used > MACH64_BUFFER_SIZE - MACH64_HOSTDATA_BLIT_OFFSET) {
DRM_ERROR("Invalid blit size: %d bytes\n", buf->used);
return DRM_ERR(EINVAL);
}
/* FIXME: Use a last buffer flag and reduce the state emitted for subsequent,
* continuation buffers?
*/
/* Blit via BM_HOSTDATA (gui-master) - like HOST_DATA[0-15], but doesn't require
* a register command every 16 dwords. State setup is added at the start of the
* buffer -- the client leaves space for this based on MACH64_HOSTDATA_BLIT_OFFSET
*/
DMASETPTR(buf);
DMAOUTREG(MACH64_Z_CNTL, 0);
DMAOUTREG(MACH64_SCALE_3D_CNTL, 0);
DMAOUTREG(MACH64_SC_LEFT_RIGHT, 0 | (8191 << 16)); /* no scissor */
DMAOUTREG(MACH64_SC_TOP_BOTTOM, 0 | (16383 << 16));
DMAOUTREG(MACH64_CLR_CMP_CNTL, 0); /* disable */
DMAOUTREG(MACH64_GUI_TRAJ_CNTL,
MACH64_DST_X_LEFT_TO_RIGHT | MACH64_DST_Y_TOP_TO_BOTTOM);
DMAOUTREG(MACH64_DP_PIX_WIDTH, (blit->format << 0) /* dst pix width */
|(blit->format << 4) /* composite pix width */
|(blit->format << 8) /* src pix width */
|(blit->format << 16) /* host data pix width */
|(blit->format << 28) /* scaler/3D pix width */
);
DMAOUTREG(MACH64_DP_WRITE_MASK, 0xffffffff); /* enable all planes */
DMAOUTREG(MACH64_DP_MIX, MACH64_BKGD_MIX_D | MACH64_FRGD_MIX_S);
DMAOUTREG(MACH64_DP_SRC,
MACH64_BKGD_SRC_BKGD_CLR
| MACH64_FRGD_SRC_HOST | MACH64_MONO_SRC_ONE);
DMAOUTREG(MACH64_DST_OFF_PITCH,
(blit->pitch << 22) | (blit->offset >> 3));
DMAOUTREG(MACH64_DST_X_Y, (blit->y << 16) | blit->x);
DMAOUTREG(MACH64_DST_WIDTH_HEIGHT, (blit->height << 16) | blit->width);
DRM_DEBUG("%s: %d bytes\n", __FUNCTION__, buf->used);
/* Add the buffer to the queue */
DMAADVANCEHOSTDATA(dev_priv);
return 0;
}
/* ================================================================
* IOCTL functions
*/
int mach64_dma_clear(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_mach64_private_t *dev_priv = dev->dev_private;
drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv;
drm_mach64_clear_t clear;
int ret;
DRM_DEBUG("%s: pid=%d\n", __FUNCTION__, DRM_CURRENTPID);
LOCK_TEST_WITH_RETURN(dev, filp);
DRM_COPY_FROM_USER_IOCTL(clear, (drm_mach64_clear_t *) data,
sizeof(clear));
if (sarea_priv->nbox > MACH64_NR_SAREA_CLIPRECTS)
sarea_priv->nbox = MACH64_NR_SAREA_CLIPRECTS;
ret = mach64_dma_dispatch_clear(filp, dev, clear.flags,
clear.x, clear.y, clear.w, clear.h,
clear.clear_color, clear.clear_depth);
/* Make sure we restore the 3D state next time.
*/
sarea_priv->dirty |= (MACH64_UPLOAD_CONTEXT | MACH64_UPLOAD_MISC);
return ret;
}
int mach64_dma_swap(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_mach64_private_t *dev_priv = dev->dev_private;
drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv;
int ret;
DRM_DEBUG("%s: pid=%d\n", __FUNCTION__, DRM_CURRENTPID);
LOCK_TEST_WITH_RETURN(dev, filp);
if (sarea_priv->nbox > MACH64_NR_SAREA_CLIPRECTS)
sarea_priv->nbox = MACH64_NR_SAREA_CLIPRECTS;
ret = mach64_dma_dispatch_swap(filp, dev);
/* Make sure we restore the 3D state next time.
*/
sarea_priv->dirty |= (MACH64_UPLOAD_CONTEXT | MACH64_UPLOAD_MISC);
return ret;
}
int mach64_dma_vertex(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_mach64_private_t *dev_priv = dev->dev_private;
drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv;
drm_mach64_vertex_t vertex;
LOCK_TEST_WITH_RETURN(dev, filp);
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
return DRM_ERR(EINVAL);
}
DRM_COPY_FROM_USER_IOCTL(vertex, (drm_mach64_vertex_t *) data,
sizeof(vertex));
DRM_DEBUG("%s: pid=%d buf=%p used=%lu discard=%d\n",
__FUNCTION__, DRM_CURRENTPID,
vertex.buf, vertex.used, vertex.discard);
if (vertex.prim < 0 || vertex.prim > MACH64_PRIM_POLYGON) {
DRM_ERROR("buffer prim %d\n", vertex.prim);
return DRM_ERR(EINVAL);
}
if (vertex.used > MACH64_BUFFER_SIZE || (vertex.used & 3) != 0) {
DRM_ERROR("Invalid vertex buffer size: %lu bytes\n",
vertex.used);
return DRM_ERR(EINVAL);
}
if (sarea_priv->nbox > MACH64_NR_SAREA_CLIPRECTS)
sarea_priv->nbox = MACH64_NR_SAREA_CLIPRECTS;
return mach64_dma_dispatch_vertex(filp, dev, vertex.prim, vertex.buf,
vertex.used, vertex.discard);
}
int mach64_dma_blit(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_device_dma_t *dma = dev->dma;
drm_mach64_private_t *dev_priv = dev->dev_private;
drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv;
drm_mach64_blit_t blit;
int ret;
LOCK_TEST_WITH_RETURN(dev, filp);
DRM_COPY_FROM_USER_IOCTL(blit, (drm_mach64_blit_t *) data,
sizeof(blit));
DRM_DEBUG("%s: pid=%d index=%d\n",
__FUNCTION__, DRM_CURRENTPID, blit.idx);
if (blit.idx < 0 || blit.idx >= dma->buf_count) {
DRM_ERROR("buffer index %d (of %d max)\n",
blit.idx, dma->buf_count - 1);
return DRM_ERR(EINVAL);
}
ret = mach64_dma_dispatch_blit(filp, dev, &blit);
/* Make sure we restore the 3D state next time.
*/
sarea_priv->dirty |= (MACH64_UPLOAD_CONTEXT |
MACH64_UPLOAD_MISC | MACH64_UPLOAD_CLIPRECTS);
return ret;
}
int mach64_get_param(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_mach64_private_t *dev_priv = dev->dev_private;
drm_mach64_getparam_t param;
int value;
DRM_DEBUG("%s\n", __FUNCTION__);
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
return DRM_ERR(EINVAL);
}
DRM_COPY_FROM_USER_IOCTL(param, (drm_mach64_getparam_t *) data,
sizeof(param));
switch (param.param) {
case MACH64_PARAM_FRAMES_QUEUED:
/* Needs lock since it calls mach64_ring_tick() */
LOCK_TEST_WITH_RETURN(dev, filp);
value = mach64_do_get_frames_queued(dev_priv);
break;
case MACH64_PARAM_IRQ_NR:
value = dev->irq;
break;
default:
return DRM_ERR(EINVAL);
}
if (DRM_COPY_TO_USER(param.value, &value, sizeof(int))) {
DRM_ERROR("copy_to_user\n");
return DRM_ERR(EFAULT);
}
return 0;
}

1187
sys/dev/pci/drm/mga_dma.c Normal file

File diff suppressed because it is too large Load Diff

430
sys/dev/pci/drm/mga_drm.h Normal file
View File

@ -0,0 +1,430 @@
/* mga_drm.h -- Public header for the Matrox g200/g400 driver -*- linux-c -*-
* Created: Tue Jan 25 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
* 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:
* Jeff Hartmann <jhartmann@valinux.com>
* Keith Whitwell <keith@tungstengraphics.com>
*
* Rewritten by:
* Gareth Hughes <gareth@valinux.com>
*/
#include <sys/cdefs.h>
/*
__FBSDID("$FreeBSD: src/sys/dev/drm/mga_drm.h,v 1.7 2005/11/28 23:13:53 anholt Exp $");
*/
#ifndef __MGA_DRM_H__
#define __MGA_DRM_H__
/* WARNING: If you change any of these defines, make sure to change the
* defines in the Xserver file (mga_sarea.h)
*/
#ifndef __MGA_SAREA_DEFINES__
#define __MGA_SAREA_DEFINES__
/* WARP pipe flags
*/
#define MGA_F 0x1 /* fog */
#define MGA_A 0x2 /* alpha */
#define MGA_S 0x4 /* specular */
#define MGA_T2 0x8 /* multitexture */
#define MGA_WARP_TGZ 0
#define MGA_WARP_TGZF (MGA_F)
#define MGA_WARP_TGZA (MGA_A)
#define MGA_WARP_TGZAF (MGA_F|MGA_A)
#define MGA_WARP_TGZS (MGA_S)
#define MGA_WARP_TGZSF (MGA_S|MGA_F)
#define MGA_WARP_TGZSA (MGA_S|MGA_A)
#define MGA_WARP_TGZSAF (MGA_S|MGA_F|MGA_A)
#define MGA_WARP_T2GZ (MGA_T2)
#define MGA_WARP_T2GZF (MGA_T2|MGA_F)
#define MGA_WARP_T2GZA (MGA_T2|MGA_A)
#define MGA_WARP_T2GZAF (MGA_T2|MGA_A|MGA_F)
#define MGA_WARP_T2GZS (MGA_T2|MGA_S)
#define MGA_WARP_T2GZSF (MGA_T2|MGA_S|MGA_F)
#define MGA_WARP_T2GZSA (MGA_T2|MGA_S|MGA_A)
#define MGA_WARP_T2GZSAF (MGA_T2|MGA_S|MGA_F|MGA_A)
#define MGA_MAX_G200_PIPES 8 /* no multitex */
#define MGA_MAX_G400_PIPES 16
#define MGA_MAX_WARP_PIPES MGA_MAX_G400_PIPES
#define MGA_WARP_UCODE_SIZE 32768 /* in bytes */
#define MGA_CARD_TYPE_G200 1
#define MGA_CARD_TYPE_G400 2
#define MGA_CARD_TYPE_G450 3 /* not currently used */
#define MGA_CARD_TYPE_G550 4
#define MGA_FRONT 0x1
#define MGA_BACK 0x2
#define MGA_DEPTH 0x4
/* What needs to be changed for the current vertex dma buffer?
*/
#define MGA_UPLOAD_CONTEXT 0x1
#define MGA_UPLOAD_TEX0 0x2
#define MGA_UPLOAD_TEX1 0x4
#define MGA_UPLOAD_PIPE 0x8
#define MGA_UPLOAD_TEX0IMAGE 0x10 /* handled client-side */
#define MGA_UPLOAD_TEX1IMAGE 0x20 /* handled client-side */
#define MGA_UPLOAD_2D 0x40
#define MGA_WAIT_AGE 0x80 /* handled client-side */
#define MGA_UPLOAD_CLIPRECTS 0x100 /* handled client-side */
#if 0
#define MGA_DMA_FLUSH 0x200 /* set when someone gets the lock
quiescent */
#endif
/* 32 buffers of 64k each, total 2 meg.
*/
#define MGA_BUFFER_SIZE (1 << 16)
#define MGA_NUM_BUFFERS 128
/* Keep these small for testing.
*/
#define MGA_NR_SAREA_CLIPRECTS 8
/* 2 heaps (1 for card, 1 for agp), each divided into upto 128
* regions, subject to a minimum region size of (1<<16) == 64k.
*
* Clients may subdivide regions internally, but when sharing between
* clients, the region size is the minimum granularity.
*/
#define MGA_CARD_HEAP 0
#define MGA_AGP_HEAP 1
#define MGA_NR_TEX_HEAPS 2
#define MGA_NR_TEX_REGIONS 16
#define MGA_LOG_MIN_TEX_REGION_SIZE 16
#define DRM_MGA_IDLE_RETRY 2048
#endif /* __MGA_SAREA_DEFINES__ */
/* Setup registers for 3D context
*/
typedef struct {
unsigned int dstorg;
unsigned int maccess;
unsigned int plnwt;
unsigned int dwgctl;
unsigned int alphactrl;
unsigned int fogcolor;
unsigned int wflag;
unsigned int tdualstage0;
unsigned int tdualstage1;
unsigned int fcol;
unsigned int stencil;
unsigned int stencilctl;
} drm_mga_context_regs_t;
/* Setup registers for 2D, X server
*/
typedef struct {
unsigned int pitch;
} drm_mga_server_regs_t;
/* Setup registers for each texture unit
*/
typedef struct {
unsigned int texctl;
unsigned int texctl2;
unsigned int texfilter;
unsigned int texbordercol;
unsigned int texorg;
unsigned int texwidth;
unsigned int texheight;
unsigned int texorg1;
unsigned int texorg2;
unsigned int texorg3;
unsigned int texorg4;
} drm_mga_texture_regs_t;
/* General aging mechanism
*/
typedef struct {
unsigned int head; /* Position of head pointer */
unsigned int wrap; /* Primary DMA wrap count */
} drm_mga_age_t;
typedef struct _drm_mga_sarea {
/* The channel for communication of state information to the kernel
* on firing a vertex dma buffer.
*/
drm_mga_context_regs_t context_state;
drm_mga_server_regs_t server_state;
drm_mga_texture_regs_t tex_state[2];
unsigned int warp_pipe;
unsigned int dirty;
unsigned int vertsize;
/* The current cliprects, or a subset thereof.
*/
drm_clip_rect_t boxes[MGA_NR_SAREA_CLIPRECTS];
unsigned int nbox;
/* Information about the most recently used 3d drawable. The
* client fills in the req_* fields, the server fills in the
* exported_ fields and puts the cliprects into boxes, above.
*
* The client clears the exported_drawable field before
* clobbering the boxes data.
*/
unsigned int req_drawable; /* the X drawable id */
unsigned int req_draw_buffer; /* MGA_FRONT or MGA_BACK */
unsigned int exported_drawable;
unsigned int exported_index;
unsigned int exported_stamp;
unsigned int exported_buffers;
unsigned int exported_nfront;
unsigned int exported_nback;
int exported_back_x, exported_front_x, exported_w;
int exported_back_y, exported_front_y, exported_h;
drm_clip_rect_t exported_boxes[MGA_NR_SAREA_CLIPRECTS];
/* Counters for aging textures and for client-side throttling.
*/
unsigned int status[4];
unsigned int last_wrap;
drm_mga_age_t last_frame;
unsigned int last_enqueue; /* last time a buffer was enqueued */
unsigned int last_dispatch; /* age of the most recently dispatched buffer */
unsigned int last_quiescent; /* */
/* LRU lists for texture memory in agp space and on the card.
*/
drm_tex_region_t texList[MGA_NR_TEX_HEAPS][MGA_NR_TEX_REGIONS + 1];
unsigned int texAge[MGA_NR_TEX_HEAPS];
/* Mechanism to validate card state.
*/
int ctxOwner;
} drm_mga_sarea_t;
/* MGA specific ioctls
* The device specific ioctl range is 0x40 to 0x79.
*/
#define DRM_MGA_INIT 0x00
#define DRM_MGA_FLUSH 0x01
#define DRM_MGA_RESET 0x02
#define DRM_MGA_SWAP 0x03
#define DRM_MGA_CLEAR 0x04
#define DRM_MGA_VERTEX 0x05
#define DRM_MGA_INDICES 0x06
#define DRM_MGA_ILOAD 0x07
#define DRM_MGA_BLIT 0x08
#define DRM_MGA_GETPARAM 0x09
/* 3.2:
* ioctls for operating on fences.
*/
#define DRM_MGA_SET_FENCE 0x0a
#define DRM_MGA_WAIT_FENCE 0x0b
#define DRM_MGA_DMA_BOOTSTRAP 0x0c
#define DRM_IOCTL_MGA_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_MGA_INIT, drm_mga_init_t)
#define DRM_IOCTL_MGA_FLUSH DRM_IOW( DRM_COMMAND_BASE + DRM_MGA_FLUSH, drm_lock_t)
#define DRM_IOCTL_MGA_RESET DRM_IO( DRM_COMMAND_BASE + DRM_MGA_RESET)
#define DRM_IOCTL_MGA_SWAP DRM_IO( DRM_COMMAND_BASE + DRM_MGA_SWAP)
#define DRM_IOCTL_MGA_CLEAR DRM_IOW( DRM_COMMAND_BASE + DRM_MGA_CLEAR, drm_mga_clear_t)
#define DRM_IOCTL_MGA_VERTEX DRM_IOW( DRM_COMMAND_BASE + DRM_MGA_VERTEX, drm_mga_vertex_t)
#define DRM_IOCTL_MGA_INDICES DRM_IOW( DRM_COMMAND_BASE + DRM_MGA_INDICES, drm_mga_indices_t)
#define DRM_IOCTL_MGA_ILOAD DRM_IOW( DRM_COMMAND_BASE + DRM_MGA_ILOAD, drm_mga_iload_t)
#define DRM_IOCTL_MGA_BLIT DRM_IOW( DRM_COMMAND_BASE + DRM_MGA_BLIT, drm_mga_blit_t)
#define DRM_IOCTL_MGA_GETPARAM DRM_IOWR(DRM_COMMAND_BASE + DRM_MGA_GETPARAM, drm_mga_getparam_t)
#define DRM_IOCTL_MGA_SET_FENCE DRM_IOW( DRM_COMMAND_BASE + DRM_MGA_SET_FENCE, uint32_t)
#define DRM_IOCTL_MGA_WAIT_FENCE DRM_IOWR(DRM_COMMAND_BASE + DRM_MGA_WAIT_FENCE, uint32_t)
#define DRM_IOCTL_MGA_DMA_BOOTSTRAP DRM_IOWR(DRM_COMMAND_BASE + DRM_MGA_DMA_BOOTSTRAP, drm_mga_dma_bootstrap_t)
typedef struct _drm_mga_warp_index {
int installed;
unsigned long phys_addr;
int size;
} drm_mga_warp_index_t;
typedef struct drm_mga_init {
enum {
MGA_INIT_DMA = 0x01,
MGA_CLEANUP_DMA = 0x02
} func;
unsigned long sarea_priv_offset;
int chipset;
int sgram;
unsigned int maccess;
unsigned int fb_cpp;
unsigned int front_offset, front_pitch;
unsigned int back_offset, back_pitch;
unsigned int depth_cpp;
unsigned int depth_offset, depth_pitch;
unsigned int texture_offset[MGA_NR_TEX_HEAPS];
unsigned int texture_size[MGA_NR_TEX_HEAPS];
unsigned long fb_offset;
unsigned long mmio_offset;
unsigned long status_offset;
unsigned long warp_offset;
unsigned long primary_offset;
unsigned long buffers_offset;
} drm_mga_init_t;
typedef struct drm_mga_dma_bootstrap {
/**
* \name AGP texture region
*
* On return from the DRM_MGA_DMA_BOOTSTRAP ioctl, these fields will
* be filled in with the actual AGP texture settings.
*
* \warning
* If these fields are non-zero, but dma_mga_dma_bootstrap::agp_mode
* is zero, it means that PCI memory (most likely through the use of
* an IOMMU) is being used for "AGP" textures.
*/
/*@{*/
unsigned long texture_handle; /**< Handle used to map AGP textures. */
uint32_t texture_size; /**< Size of the AGP texture region. */
/*@}*/
/**
* Requested size of the primary DMA region.
*
* On return from the DRM_MGA_DMA_BOOTSTRAP ioctl, this field will be
* filled in with the actual AGP mode. If AGP was not available
*/
uint32_t primary_size;
/**
* Requested number of secondary DMA buffers.
*
* On return from the DRM_MGA_DMA_BOOTSTRAP ioctl, this field will be
* filled in with the actual number of secondary DMA buffers
* allocated. Particularly when PCI DMA is used, this may be
* (subtantially) less than the number requested.
*/
uint32_t secondary_bin_count;
/**
* Requested size of each secondary DMA buffer.
*
* While the kernel \b is free to reduce
* dma_mga_dma_bootstrap::secondary_bin_count, it is \b not allowed
* to reduce dma_mga_dma_bootstrap::secondary_bin_size.
*/
uint32_t secondary_bin_size;
/**
* Bit-wise mask of AGPSTAT2_* values. Currently only \c AGPSTAT2_1X,
* \c AGPSTAT2_2X, and \c AGPSTAT2_4X are supported. If this value is
* zero, it means that PCI DMA should be used, even if AGP is
* possible.
*
* On return from the DRM_MGA_DMA_BOOTSTRAP ioctl, this field will be
* filled in with the actual AGP mode. If AGP was not available
* (i.e., PCI DMA was used), this value will be zero.
*/
uint32_t agp_mode;
/**
* Desired AGP GART size, measured in megabytes.
*/
uint8_t agp_size;
} drm_mga_dma_bootstrap_t;
typedef struct drm_mga_clear {
unsigned int flags;
unsigned int clear_color;
unsigned int clear_depth;
unsigned int color_mask;
unsigned int depth_mask;
} drm_mga_clear_t;
typedef struct drm_mga_vertex {
int idx; /* buffer to queue */
int used; /* bytes in use */
int discard; /* client finished with buffer? */
} drm_mga_vertex_t;
typedef struct drm_mga_indices {
int idx; /* buffer to queue */
unsigned int start;
unsigned int end;
int discard; /* client finished with buffer? */
} drm_mga_indices_t;
typedef struct drm_mga_iload {
int idx;
unsigned int dstorg;
unsigned int length;
} drm_mga_iload_t;
typedef struct _drm_mga_blit {
unsigned int planemask;
unsigned int srcorg;
unsigned int dstorg;
int src_pitch, dst_pitch;
int delta_sx, delta_sy;
int delta_dx, delta_dy;
int height, ydir; /* flip image vertically */
int source_pitch, dest_pitch;
} drm_mga_blit_t;
/* 3.1: An ioctl to get parameters that aren't available to the 3d
* client any other way.
*/
#define MGA_PARAM_IRQ_NR 1
/* 3.2: Query the actual card type. The DDX only distinguishes between
* G200 chips and non-G200 chips, which it calls G400. It turns out that
* there are some very sublte differences between the G4x0 chips and the G550
* chips. Using this parameter query, a client-side driver can detect the
* difference between a G4x0 and a G550.
*/
#define MGA_PARAM_CARD_TYPE 2
typedef struct drm_mga_getparam {
int param;
void __user *value;
} drm_mga_getparam_t;
#endif

197
sys/dev/pci/drm/mga_drv.c Normal file
View File

@ -0,0 +1,197 @@
/* mga_drv.c -- Matrox G200/G400 driver -*- linux-c -*-
* Created: Mon Dec 13 01:56:22 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
* 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 <sys/cdefs.h>
/*
__FBSDID("$FreeBSD: src/sys/dev/drm/mga_drv.c,v 1.12 2006/05/17 06:36:28 anholt Exp $");
*/
#include "drmP.h"
#include "drm.h"
#include "mga_drm.h"
#include "mga_drv.h"
#include "drm_pciids.h"
/* drv_PCI_IDs comes from drm_pciids.h, generated from drm_pciids.txt. */
static drm_pci_id_list_t mga_pciidlist[] = {
mga_PCI_IDS
};
/**
* Determine if the device really is AGP or not.
*
* In addition to the usual tests performed by \c drm_device_is_agp, this
* function detects PCI G450 cards that appear to the system exactly like
* AGP G450 cards.
*
* \param dev The device to be tested.
*
* \returns
* If the device is a PCI G450, zero is returned. Otherwise non-zero is
* returned.
*
* \bug
* This function needs to be filled in! The implementation in
* linux-core/mga_drv.c shows what needs to be done.
*/
static int mga_driver_device_is_agp(drm_device_t * dev)
{
#ifdef __FreeBSD__
device_t bus;
#endif
/* There are PCI versions of the G450. These cards have the
* same PCI ID as the AGP G450, but have an additional PCI-to-PCI
* bridge chip. We detect these cards, which are not currently
* supported by this driver, by looking at the device ID of the
* bus the "card" is on. If vendor is 0x3388 (Hint Corp) and the
* device is 0x0021 (HB6 Universal PCI-PCI bridge), we reject the
* device.
*/
#ifdef __FreeBSD__
#if __FreeBSD_version >= 700010
bus = device_get_parent(device_get_parent(dev->device));
#else
bus = device_get_parent(dev->device);
#endif
if (pci_get_device(dev->device) == 0x0525 &&
pci_get_vendor(bus) == 0x3388 &&
pci_get_device(bus) == 0x0021)
return DRM_IS_NOT_AGP;
else
return DRM_MIGHT_BE_AGP;
#endif
#ifdef __NetBSD__
/* FIX THIS */
return DRM_MIGHT_BE_AGP;
#endif
}
static void mga_configure(drm_device_t *dev)
{
dev->driver.buf_priv_size = sizeof(drm_mga_buf_priv_t);
dev->driver.load = mga_driver_load;
dev->driver.unload = mga_driver_unload;
dev->driver.lastclose = mga_driver_lastclose;
dev->driver.vblank_wait = mga_driver_vblank_wait;
dev->driver.irq_preinstall = mga_driver_irq_preinstall;
dev->driver.irq_postinstall = mga_driver_irq_postinstall;
dev->driver.irq_uninstall = mga_driver_irq_uninstall;
dev->driver.irq_handler = mga_driver_irq_handler;
dev->driver.dma_ioctl = mga_dma_buffers;
dev->driver.dma_quiescent = mga_driver_dma_quiescent;
dev->driver.device_is_agp = mga_driver_device_is_agp;
dev->driver.ioctls = mga_ioctls;
dev->driver.max_ioctl = mga_max_ioctl;
dev->driver.name = DRIVER_NAME;
dev->driver.desc = DRIVER_DESC;
dev->driver.date = DRIVER_DATE;
dev->driver.major = DRIVER_MAJOR;
dev->driver.minor = DRIVER_MINOR;
dev->driver.patchlevel = DRIVER_PATCHLEVEL;
dev->driver.use_agp = 1;
dev->driver.require_agp = 1;
dev->driver.use_mtrr = 1;
dev->driver.use_dma = 1;
dev->driver.use_irq = 1;
dev->driver.use_vbl_irq = 1;
}
#ifdef __FreeBSD__
static int
mga_probe(device_t dev)
{
return drm_probe(dev, mga_pciidlist);
}
static int
mga_attach(device_t nbdev)
{
drm_device_t *dev = device_get_softc(nbdev);
bzero(dev, sizeof(drm_device_t));
mga_configure(dev);
return drm_attach(nbdev, mga_pciidlist);
}
static device_method_t mga_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, mga_probe),
DEVMETHOD(device_attach, mga_attach),
DEVMETHOD(device_detach, drm_detach),
{ 0, 0 }
};
static driver_t mga_driver = {
"drm",
mga_methods,
sizeof(drm_device_t)
};
extern devclass_t drm_devclass;
#if __FreeBSD_version >= 700010
DRIVER_MODULE(mga, vgapci, mga_driver, drm_devclass, 0, 0);
#else
DRIVER_MODULE(mga, pci, mga_driver, drm_devclass, 0, 0);
#endif
MODULE_DEPEND(mga, drm, 1, 1, 1);
#elif defined(__NetBSD__) || defined(__OpenBSD__)
static int
mgadrm_probe(struct device *parent, struct cfdata *match, void *aux)
{
struct pci_attach_args *pa = aux;
return drm_probe(pa, mga_pciidlist);
}
static void
mgadrm_attach(struct device *parent, struct device *self, void *aux)
{
struct pci_attach_args *pa = aux;
drm_device_t *dev = (drm_device_t *)self;
mga_configure(dev);
return drm_attach(self, pa, mga_pciidlist);
}
CFATTACH_DECL(mgadrm, sizeof(drm_device_t), mgadrm_probe, mgadrm_attach,
drm_detach, drm_activate);
#endif

688
sys/dev/pci/drm/mga_drv.h Normal file
View File

@ -0,0 +1,688 @@
/* mga_drv.h -- Private header for the Matrox G200/G400 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
* 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:
* Gareth Hughes <gareth@valinux.com>
*/
#include <sys/cdefs.h>
/*
__FBSDID("$FreeBSD: src/sys/dev/drm/mga_drv.h,v 1.11 2006/04/09 20:45:45 anholt Exp $");
*/
#ifndef __MGA_DRV_H__
#define __MGA_DRV_H__
/* General customization:
*/
#define DRIVER_AUTHOR "Gareth Hughes, VA Linux Systems Inc."
#define DRIVER_NAME "mga"
#define DRIVER_DESC "Matrox G200/G400"
#define DRIVER_DATE "20060319"
#define DRIVER_MAJOR 3
#define DRIVER_MINOR 2
#define DRIVER_PATCHLEVEL 2
typedef struct drm_mga_primary_buffer {
u8 *start;
u8 *end;
int size;
u32 tail;
int space;
volatile long wrapped;
volatile u32 *status;
u32 last_flush;
u32 last_wrap;
u32 high_mark;
} drm_mga_primary_buffer_t;
typedef struct drm_mga_freelist {
struct drm_mga_freelist *next;
struct drm_mga_freelist *prev;
drm_mga_age_t age;
drm_buf_t *buf;
} drm_mga_freelist_t;
typedef struct {
drm_mga_freelist_t *list_entry;
int discard;
int dispatched;
} drm_mga_buf_priv_t;
typedef struct drm_mga_private {
drm_mga_primary_buffer_t prim;
drm_mga_sarea_t *sarea_priv;
drm_mga_freelist_t *head;
drm_mga_freelist_t *tail;
unsigned int warp_pipe;
unsigned long warp_pipe_phys[MGA_MAX_WARP_PIPES];
int chipset;
int usec_timeout;
/**
* If set, the new DMA initialization sequence was used. This is
* primarilly used to select how the driver should uninitialized its
* internal DMA structures.
*/
int used_new_dma_init;
/**
* If AGP memory is used for DMA buffers, this will be the value
* \c MGA_PAGPXFER. Otherwise, it will be zero (for a PCI transfer).
*/
u32 dma_access;
/**
* If AGP memory is used for DMA buffers, this will be the value
* \c MGA_WAGP_ENABLE. Otherwise, it will be zero (for a PCI
* transfer).
*/
u32 wagp_enable;
/**
* \name MMIO region parameters.
*
* \sa drm_mga_private_t::mmio
*/
/*@{*/
u32 mmio_base; /**< Bus address of base of MMIO. */
u32 mmio_size; /**< Size of the MMIO region. */
/*@}*/
u32 clear_cmd;
u32 maccess;
wait_queue_head_t fence_queue;
atomic_t last_fence_retired;
u32 next_fence_to_post;
unsigned int fb_cpp;
unsigned int front_offset;
unsigned int front_pitch;
unsigned int back_offset;
unsigned int back_pitch;
unsigned int depth_cpp;
unsigned int depth_offset;
unsigned int depth_pitch;
unsigned int texture_offset;
unsigned int texture_size;
drm_local_map_t *sarea;
drm_local_map_t *mmio;
drm_local_map_t *status;
drm_local_map_t *warp;
drm_local_map_t *primary;
drm_local_map_t *agp_textures;
unsigned long agp_handle;
unsigned int agp_size;
} drm_mga_private_t;
extern drm_ioctl_desc_t mga_ioctls[];
extern int mga_max_ioctl;
/* mga_dma.c */
extern int mga_dma_bootstrap(DRM_IOCTL_ARGS);
extern int mga_dma_init(DRM_IOCTL_ARGS);
extern int mga_dma_flush(DRM_IOCTL_ARGS);
extern int mga_dma_reset(DRM_IOCTL_ARGS);
extern int mga_dma_buffers(DRM_IOCTL_ARGS);
extern int mga_driver_load(drm_device_t *dev, unsigned long flags);
extern int mga_driver_unload(drm_device_t * dev);
extern void mga_driver_lastclose(drm_device_t * dev);
extern int mga_driver_dma_quiescent(drm_device_t * dev);
extern int mga_do_wait_for_idle(drm_mga_private_t * dev_priv);
extern void mga_do_dma_flush(drm_mga_private_t * dev_priv);
extern void mga_do_dma_wrap_start(drm_mga_private_t * dev_priv);
extern void mga_do_dma_wrap_end(drm_mga_private_t * dev_priv);
extern int mga_freelist_put(drm_device_t * dev, drm_buf_t * buf);
/* mga_warp.c */
extern unsigned int mga_warp_microcode_size(const drm_mga_private_t * dev_priv);
extern int mga_warp_install_microcode(drm_mga_private_t * dev_priv);
extern int mga_warp_init(drm_mga_private_t * dev_priv);
/* mga_irq.c */
extern int mga_driver_fence_wait(drm_device_t * dev, unsigned int *sequence);
extern int mga_driver_vblank_wait(drm_device_t * dev, unsigned int *sequence);
extern irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS);
extern void mga_driver_irq_preinstall(drm_device_t * dev);
extern void mga_driver_irq_postinstall(drm_device_t * dev);
extern void mga_driver_irq_uninstall(drm_device_t * dev);
extern long mga_compat_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg);
#define mga_flush_write_combine() DRM_WRITEMEMORYBARRIER()
#if defined(__linux__) && defined(__alpha__)
#define MGA_BASE( reg ) ((unsigned long)(dev_priv->mmio->handle))
#define MGA_ADDR( reg ) (MGA_BASE(reg) + reg)
#define MGA_DEREF( reg ) *(volatile u32 *)MGA_ADDR( reg )
#define MGA_DEREF8( reg ) *(volatile u8 *)MGA_ADDR( reg )
#define MGA_READ( reg ) (_MGA_READ((u32 *)MGA_ADDR(reg)))
#define MGA_READ8( reg ) (_MGA_READ((u8 *)MGA_ADDR(reg)))
#define MGA_WRITE( reg, val ) do { DRM_WRITEMEMORYBARRIER(); MGA_DEREF( reg ) = val; } while (0)
#define MGA_WRITE8( reg, val ) do { DRM_WRITEMEMORYBARRIER(); MGA_DEREF8( reg ) = val; } while (0)
static inline u32 _MGA_READ(u32 * addr)
{
DRM_MEMORYBARRIER();
return *(volatile u32 *)addr;
}
#else
#define MGA_READ8( reg ) DRM_READ8(dev_priv->mmio, (reg))
#define MGA_READ( reg ) DRM_READ32(dev_priv->mmio, (reg))
#define MGA_WRITE8( reg, val ) DRM_WRITE8(dev_priv->mmio, (reg), (val))
#define MGA_WRITE( reg, val ) DRM_WRITE32(dev_priv->mmio, (reg), (val))
#endif
#define DWGREG0 0x1c00
#define DWGREG0_END 0x1dff
#define DWGREG1 0x2c00
#define DWGREG1_END 0x2dff
#define ISREG0(r) (r >= DWGREG0 && r <= DWGREG0_END)
#define DMAREG0(r) (u8)((r - DWGREG0) >> 2)
#define DMAREG1(r) (u8)(((r - DWGREG1) >> 2) | 0x80)
#define DMAREG(r) (ISREG0(r) ? DMAREG0(r) : DMAREG1(r))
/* ================================================================
* Helper macross...
*/
#define MGA_EMIT_STATE( dev_priv, dirty ) \
do { \
if ( (dirty) & ~MGA_UPLOAD_CLIPRECTS ) { \
if ( dev_priv->chipset >= MGA_CARD_TYPE_G400 ) { \
mga_g400_emit_state( dev_priv ); \
} else { \
mga_g200_emit_state( dev_priv ); \
} \
} \
} while (0)
#define WRAP_TEST_WITH_RETURN( dev_priv ) \
do { \
if ( test_bit( 0, &dev_priv->prim.wrapped ) ) { \
if ( mga_is_idle( dev_priv ) ) { \
mga_do_dma_wrap_end( dev_priv ); \
} else if ( dev_priv->prim.space < \
dev_priv->prim.high_mark ) { \
if ( MGA_DMA_DEBUG ) \
DRM_INFO( "%s: wrap...\n", __FUNCTION__ ); \
return DRM_ERR(EBUSY); \
} \
} \
} while (0)
#define WRAP_WAIT_WITH_RETURN( dev_priv ) \
do { \
if ( test_bit( 0, &dev_priv->prim.wrapped ) ) { \
if ( mga_do_wait_for_idle( dev_priv ) < 0 ) { \
if ( MGA_DMA_DEBUG ) \
DRM_INFO( "%s: wrap...\n", __FUNCTION__ ); \
return DRM_ERR(EBUSY); \
} \
mga_do_dma_wrap_end( dev_priv ); \
} \
} while (0)
/* ================================================================
* Primary DMA command stream
*/
#define MGA_VERBOSE 0
#define DMA_LOCALS unsigned int write; volatile u8 *prim;
#define DMA_BLOCK_SIZE (5 * sizeof(u32))
#define BEGIN_DMA( n ) \
do { \
if ( MGA_VERBOSE ) { \
DRM_INFO( "BEGIN_DMA( %d ) in %s\n", \
(n), __FUNCTION__ ); \
DRM_INFO( " space=0x%x req=0x%Zx\n", \
dev_priv->prim.space, (n) * DMA_BLOCK_SIZE ); \
} \
prim = dev_priv->prim.start; \
write = dev_priv->prim.tail; \
} while (0)
#define BEGIN_DMA_WRAP() \
do { \
if ( MGA_VERBOSE ) { \
DRM_INFO( "BEGIN_DMA() in %s\n", __FUNCTION__ ); \
DRM_INFO( " space=0x%x\n", dev_priv->prim.space ); \
} \
prim = dev_priv->prim.start; \
write = dev_priv->prim.tail; \
} while (0)
#define ADVANCE_DMA() \
do { \
dev_priv->prim.tail = write; \
if ( MGA_VERBOSE ) { \
DRM_INFO( "ADVANCE_DMA() tail=0x%05x sp=0x%x\n", \
write, dev_priv->prim.space ); \
} \
} while (0)
#define FLUSH_DMA() \
do { \
if ( 0 ) { \
DRM_INFO( "%s:\n", __FUNCTION__ ); \
DRM_INFO( " tail=0x%06x head=0x%06lx\n", \
dev_priv->prim.tail, \
MGA_READ( MGA_PRIMADDRESS ) - \
dev_priv->primary->offset ); \
} \
if ( !test_bit( 0, &dev_priv->prim.wrapped ) ) { \
if ( dev_priv->prim.space < \
dev_priv->prim.high_mark ) { \
mga_do_dma_wrap_start( dev_priv ); \
} else { \
mga_do_dma_flush( dev_priv ); \
} \
} \
} while (0)
/* Never use this, always use DMA_BLOCK(...) for primary DMA output.
*/
#define DMA_WRITE( offset, val ) \
do { \
if ( MGA_VERBOSE ) { \
DRM_INFO( " DMA_WRITE( 0x%08x ) at 0x%04Zx\n", \
(u32)(val), write + (offset) * sizeof(u32) ); \
} \
*(volatile u32 *)(prim + write + (offset) * sizeof(u32)) = val; \
} while (0)
#define DMA_BLOCK( reg0, val0, reg1, val1, reg2, val2, reg3, val3 ) \
do { \
DMA_WRITE( 0, ((DMAREG( reg0 ) << 0) | \
(DMAREG( reg1 ) << 8) | \
(DMAREG( reg2 ) << 16) | \
(DMAREG( reg3 ) << 24)) ); \
DMA_WRITE( 1, val0 ); \
DMA_WRITE( 2, val1 ); \
DMA_WRITE( 3, val2 ); \
DMA_WRITE( 4, val3 ); \
write += DMA_BLOCK_SIZE; \
} while (0)
/* Buffer aging via primary DMA stream head pointer.
*/
#define SET_AGE( age, h, w ) \
do { \
(age)->head = h; \
(age)->wrap = w; \
} while (0)
#define TEST_AGE( age, h, w ) ( (age)->wrap < w || \
( (age)->wrap == w && \
(age)->head < h ) )
#define AGE_BUFFER( buf_priv ) \
do { \
drm_mga_freelist_t *entry = (buf_priv)->list_entry; \
if ( (buf_priv)->dispatched ) { \
entry->age.head = (dev_priv->prim.tail + \
dev_priv->primary->offset); \
entry->age.wrap = dev_priv->sarea_priv->last_wrap; \
} else { \
entry->age.head = 0; \
entry->age.wrap = 0; \
} \
} while (0)
#define MGA_ENGINE_IDLE_MASK (MGA_SOFTRAPEN | \
MGA_DWGENGSTS | \
MGA_ENDPRDMASTS)
#define MGA_DMA_IDLE_MASK (MGA_SOFTRAPEN | \
MGA_ENDPRDMASTS)
#define MGA_DMA_DEBUG 0
/* A reduced set of the mga registers.
*/
#define MGA_CRTC_INDEX 0x1fd4
#define MGA_CRTC_DATA 0x1fd5
/* CRTC11 */
#define MGA_VINTCLR (1 << 4)
#define MGA_VINTEN (1 << 5)
#define MGA_ALPHACTRL 0x2c7c
#define MGA_AR0 0x1c60
#define MGA_AR1 0x1c64
#define MGA_AR2 0x1c68
#define MGA_AR3 0x1c6c
#define MGA_AR4 0x1c70
#define MGA_AR5 0x1c74
#define MGA_AR6 0x1c78
#define MGA_CXBNDRY 0x1c80
#define MGA_CXLEFT 0x1ca0
#define MGA_CXRIGHT 0x1ca4
#define MGA_DMAPAD 0x1c54
#define MGA_DSTORG 0x2cb8
#define MGA_DWGCTL 0x1c00
# define MGA_OPCOD_MASK (15 << 0)
# define MGA_OPCOD_TRAP (4 << 0)
# define MGA_OPCOD_TEXTURE_TRAP (6 << 0)
# define MGA_OPCOD_BITBLT (8 << 0)
# define MGA_OPCOD_ILOAD (9 << 0)
# define MGA_ATYPE_MASK (7 << 4)
# define MGA_ATYPE_RPL (0 << 4)
# define MGA_ATYPE_RSTR (1 << 4)
# define MGA_ATYPE_ZI (3 << 4)
# define MGA_ATYPE_BLK (4 << 4)
# define MGA_ATYPE_I (7 << 4)
# define MGA_LINEAR (1 << 7)
# define MGA_ZMODE_MASK (7 << 8)
# define MGA_ZMODE_NOZCMP (0 << 8)
# define MGA_ZMODE_ZE (2 << 8)
# define MGA_ZMODE_ZNE (3 << 8)
# define MGA_ZMODE_ZLT (4 << 8)
# define MGA_ZMODE_ZLTE (5 << 8)
# define MGA_ZMODE_ZGT (6 << 8)
# define MGA_ZMODE_ZGTE (7 << 8)
# define MGA_SOLID (1 << 11)
# define MGA_ARZERO (1 << 12)
# define MGA_SGNZERO (1 << 13)
# define MGA_SHIFTZERO (1 << 14)
# define MGA_BOP_MASK (15 << 16)
# define MGA_BOP_ZERO (0 << 16)
# define MGA_BOP_DST (10 << 16)
# define MGA_BOP_SRC (12 << 16)
# define MGA_BOP_ONE (15 << 16)
# define MGA_TRANS_SHIFT 20
# define MGA_TRANS_MASK (15 << 20)
# define MGA_BLTMOD_MASK (15 << 25)
# define MGA_BLTMOD_BMONOLEF (0 << 25)
# define MGA_BLTMOD_BMONOWF (4 << 25)
# define MGA_BLTMOD_PLAN (1 << 25)
# define MGA_BLTMOD_BFCOL (2 << 25)
# define MGA_BLTMOD_BU32BGR (3 << 25)
# define MGA_BLTMOD_BU32RGB (7 << 25)
# define MGA_BLTMOD_BU24BGR (11 << 25)
# define MGA_BLTMOD_BU24RGB (15 << 25)
# define MGA_PATTERN (1 << 29)
# define MGA_TRANSC (1 << 30)
# define MGA_CLIPDIS (1 << 31)
#define MGA_DWGSYNC 0x2c4c
#define MGA_FCOL 0x1c24
#define MGA_FIFOSTATUS 0x1e10
#define MGA_FOGCOL 0x1cf4
#define MGA_FXBNDRY 0x1c84
#define MGA_FXLEFT 0x1ca8
#define MGA_FXRIGHT 0x1cac
#define MGA_ICLEAR 0x1e18
# define MGA_SOFTRAPICLR (1 << 0)
# define MGA_VLINEICLR (1 << 5)
#define MGA_IEN 0x1e1c
# define MGA_SOFTRAPIEN (1 << 0)
# define MGA_VLINEIEN (1 << 5)
#define MGA_LEN 0x1c5c
#define MGA_MACCESS 0x1c04
#define MGA_PITCH 0x1c8c
#define MGA_PLNWT 0x1c1c
#define MGA_PRIMADDRESS 0x1e58
# define MGA_DMA_GENERAL (0 << 0)
# define MGA_DMA_BLIT (1 << 0)
# define MGA_DMA_VECTOR (2 << 0)
# define MGA_DMA_VERTEX (3 << 0)
#define MGA_PRIMEND 0x1e5c
# define MGA_PRIMNOSTART (1 << 0)
# define MGA_PAGPXFER (1 << 1)
#define MGA_PRIMPTR 0x1e50
# define MGA_PRIMPTREN0 (1 << 0)
# define MGA_PRIMPTREN1 (1 << 1)
#define MGA_RST 0x1e40
# define MGA_SOFTRESET (1 << 0)
# define MGA_SOFTEXTRST (1 << 1)
#define MGA_SECADDRESS 0x2c40
#define MGA_SECEND 0x2c44
#define MGA_SETUPADDRESS 0x2cd0
#define MGA_SETUPEND 0x2cd4
#define MGA_SGN 0x1c58
#define MGA_SOFTRAP 0x2c48
#define MGA_SRCORG 0x2cb4
# define MGA_SRMMAP_MASK (1 << 0)
# define MGA_SRCMAP_FB (0 << 0)
# define MGA_SRCMAP_SYSMEM (1 << 0)
# define MGA_SRCACC_MASK (1 << 1)
# define MGA_SRCACC_PCI (0 << 1)
# define MGA_SRCACC_AGP (1 << 1)
#define MGA_STATUS 0x1e14
# define MGA_SOFTRAPEN (1 << 0)
# define MGA_VSYNCPEN (1 << 4)
# define MGA_VLINEPEN (1 << 5)
# define MGA_DWGENGSTS (1 << 16)
# define MGA_ENDPRDMASTS (1 << 17)
#define MGA_STENCIL 0x2cc8
#define MGA_STENCILCTL 0x2ccc
#define MGA_TDUALSTAGE0 0x2cf8
#define MGA_TDUALSTAGE1 0x2cfc
#define MGA_TEXBORDERCOL 0x2c5c
#define MGA_TEXCTL 0x2c30
#define MGA_TEXCTL2 0x2c3c
# define MGA_DUALTEX (1 << 7)
# define MGA_G400_TC2_MAGIC (1 << 15)
# define MGA_MAP1_ENABLE (1 << 31)
#define MGA_TEXFILTER 0x2c58
#define MGA_TEXHEIGHT 0x2c2c
#define MGA_TEXORG 0x2c24
# define MGA_TEXORGMAP_MASK (1 << 0)
# define MGA_TEXORGMAP_FB (0 << 0)
# define MGA_TEXORGMAP_SYSMEM (1 << 0)
# define MGA_TEXORGACC_MASK (1 << 1)
# define MGA_TEXORGACC_PCI (0 << 1)
# define MGA_TEXORGACC_AGP (1 << 1)
#define MGA_TEXORG1 0x2ca4
#define MGA_TEXORG2 0x2ca8
#define MGA_TEXORG3 0x2cac
#define MGA_TEXORG4 0x2cb0
#define MGA_TEXTRANS 0x2c34
#define MGA_TEXTRANSHIGH 0x2c38
#define MGA_TEXWIDTH 0x2c28
#define MGA_WACCEPTSEQ 0x1dd4
#define MGA_WCODEADDR 0x1e6c
#define MGA_WFLAG 0x1dc4
#define MGA_WFLAG1 0x1de0
#define MGA_WFLAGNB 0x1e64
#define MGA_WFLAGNB1 0x1e08
#define MGA_WGETMSB 0x1dc8
#define MGA_WIADDR 0x1dc0
#define MGA_WIADDR2 0x1dd8
# define MGA_WMODE_SUSPEND (0 << 0)
# define MGA_WMODE_RESUME (1 << 0)
# define MGA_WMODE_JUMP (2 << 0)
# define MGA_WMODE_START (3 << 0)
# define MGA_WAGP_ENABLE (1 << 2)
#define MGA_WMISC 0x1e70
# define MGA_WUCODECACHE_ENABLE (1 << 0)
# define MGA_WMASTER_ENABLE (1 << 1)
# define MGA_WCACHEFLUSH_ENABLE (1 << 3)
#define MGA_WVRTXSZ 0x1dcc
#define MGA_YBOT 0x1c9c
#define MGA_YDST 0x1c90
#define MGA_YDSTLEN 0x1c88
#define MGA_YDSTORG 0x1c94
#define MGA_YTOP 0x1c98
#define MGA_ZORG 0x1c0c
/* This finishes the current batch of commands
*/
#define MGA_EXEC 0x0100
/* AGP PLL encoding (for G200 only).
*/
#define MGA_AGP_PLL 0x1e4c
# define MGA_AGP2XPLL_DISABLE (0 << 0)
# define MGA_AGP2XPLL_ENABLE (1 << 0)
/* Warp registers
*/
#define MGA_WR0 0x2d00
#define MGA_WR1 0x2d04
#define MGA_WR2 0x2d08
#define MGA_WR3 0x2d0c
#define MGA_WR4 0x2d10
#define MGA_WR5 0x2d14
#define MGA_WR6 0x2d18
#define MGA_WR7 0x2d1c
#define MGA_WR8 0x2d20
#define MGA_WR9 0x2d24
#define MGA_WR10 0x2d28
#define MGA_WR11 0x2d2c
#define MGA_WR12 0x2d30
#define MGA_WR13 0x2d34
#define MGA_WR14 0x2d38
#define MGA_WR15 0x2d3c
#define MGA_WR16 0x2d40
#define MGA_WR17 0x2d44
#define MGA_WR18 0x2d48
#define MGA_WR19 0x2d4c
#define MGA_WR20 0x2d50
#define MGA_WR21 0x2d54
#define MGA_WR22 0x2d58
#define MGA_WR23 0x2d5c
#define MGA_WR24 0x2d60
#define MGA_WR25 0x2d64
#define MGA_WR26 0x2d68
#define MGA_WR27 0x2d6c
#define MGA_WR28 0x2d70
#define MGA_WR29 0x2d74
#define MGA_WR30 0x2d78
#define MGA_WR31 0x2d7c
#define MGA_WR32 0x2d80
#define MGA_WR33 0x2d84
#define MGA_WR34 0x2d88
#define MGA_WR35 0x2d8c
#define MGA_WR36 0x2d90
#define MGA_WR37 0x2d94
#define MGA_WR38 0x2d98
#define MGA_WR39 0x2d9c
#define MGA_WR40 0x2da0
#define MGA_WR41 0x2da4
#define MGA_WR42 0x2da8
#define MGA_WR43 0x2dac
#define MGA_WR44 0x2db0
#define MGA_WR45 0x2db4
#define MGA_WR46 0x2db8
#define MGA_WR47 0x2dbc
#define MGA_WR48 0x2dc0
#define MGA_WR49 0x2dc4
#define MGA_WR50 0x2dc8
#define MGA_WR51 0x2dcc
#define MGA_WR52 0x2dd0
#define MGA_WR53 0x2dd4
#define MGA_WR54 0x2dd8
#define MGA_WR55 0x2ddc
#define MGA_WR56 0x2de0
#define MGA_WR57 0x2de4
#define MGA_WR58 0x2de8
#define MGA_WR59 0x2dec
#define MGA_WR60 0x2df0
#define MGA_WR61 0x2df4
#define MGA_WR62 0x2df8
#define MGA_WR63 0x2dfc
# define MGA_G400_WR_MAGIC (1 << 6)
# define MGA_G400_WR56_MAGIC 0x46480000 /* 12800.0f */
#define MGA_ILOAD_ALIGN 64
#define MGA_ILOAD_MASK (MGA_ILOAD_ALIGN - 1)
#define MGA_DWGCTL_FLUSH (MGA_OPCOD_TEXTURE_TRAP | \
MGA_ATYPE_I | \
MGA_ZMODE_NOZCMP | \
MGA_ARZERO | \
MGA_SGNZERO | \
MGA_BOP_SRC | \
(15 << MGA_TRANS_SHIFT))
#define MGA_DWGCTL_CLEAR (MGA_OPCOD_TRAP | \
MGA_ZMODE_NOZCMP | \
MGA_SOLID | \
MGA_ARZERO | \
MGA_SGNZERO | \
MGA_SHIFTZERO | \
MGA_BOP_SRC | \
(0 << MGA_TRANS_SHIFT) | \
MGA_BLTMOD_BMONOLEF | \
MGA_TRANSC | \
MGA_CLIPDIS)
#define MGA_DWGCTL_COPY (MGA_OPCOD_BITBLT | \
MGA_ATYPE_RPL | \
MGA_SGNZERO | \
MGA_SHIFTZERO | \
MGA_BOP_SRC | \
(0 << MGA_TRANS_SHIFT) | \
MGA_BLTMOD_BFCOL | \
MGA_CLIPDIS)
/* Simple idle test.
*/
static __inline__ int mga_is_idle(drm_mga_private_t * dev_priv)
{
u32 status = MGA_READ(MGA_STATUS) & MGA_ENGINE_IDLE_MASK;
return (status == MGA_ENDPRDMASTS);
}
#endif

155
sys/dev/pci/drm/mga_irq.c Normal file
View File

@ -0,0 +1,155 @@
/* mga_irq.c -- IRQ handling for radeon -*- linux-c -*-
*/
/*-
* Copyright (C) The Weather Channel, Inc. 2002. All Rights Reserved.
*
* The Weather Channel (TM) funded Tungsten Graphics to develop the
* initial release of the Radeon 8500 driver under the XFree86 license.
* This notice must be preserved.
*
* 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:
* Keith Whitwell <keith@tungstengraphics.com>
* Eric Anholt <anholt@FreeBSD.org>
*/
#include <sys/cdefs.h>
/*
__FBSDID("$FreeBSD: src/sys/dev/drm/mga_irq.c,v 1.6 2005/11/28 23:13:53 anholt Exp $");
*/
#include "drmP.h"
#include "drm.h"
#include "mga_drm.h"
#include "mga_drv.h"
irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS)
{
drm_device_t *dev = (drm_device_t *) arg;
drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
int status;
int handled = 0;
status = MGA_READ(MGA_STATUS);
/* VBLANK interrupt */
if (status & MGA_VLINEPEN) {
MGA_WRITE(MGA_ICLEAR, MGA_VLINEICLR);
atomic_inc(&dev->vbl_received);
DRM_WAKEUP(&dev->vbl_queue);
drm_vbl_send_signals(dev);
handled = 1;
}
/* SOFTRAP interrupt */
if (status & MGA_SOFTRAPEN) {
const u32 prim_start = MGA_READ(MGA_PRIMADDRESS);
const u32 prim_end = MGA_READ(MGA_PRIMEND);
MGA_WRITE(MGA_ICLEAR, MGA_SOFTRAPICLR);
/* In addition to clearing the interrupt-pending bit, we
* have to write to MGA_PRIMEND to re-start the DMA operation.
*/
if ( (prim_start & ~0x03) != (prim_end & ~0x03) ) {
MGA_WRITE(MGA_PRIMEND, prim_end);
}
atomic_inc(&dev_priv->last_fence_retired);
DRM_WAKEUP(&dev_priv->fence_queue);
handled = 1;
}
if ( handled ) {
return IRQ_HANDLED;
}
return IRQ_NONE;
}
int mga_driver_vblank_wait(drm_device_t * dev, unsigned int *sequence)
{
unsigned int cur_vblank;
int ret = 0;
/* Assume that the user has missed the current sequence number
* by about a day rather than she wants to wait for years
* using vertical blanks...
*/
DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
(((cur_vblank = atomic_read(&dev->vbl_received))
- *sequence) <= (1 << 23)));
*sequence = cur_vblank;
return ret;
}
int mga_driver_fence_wait(drm_device_t * dev, unsigned int *sequence)
{
drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
unsigned int cur_fence;
int ret = 0;
/* Assume that the user has missed the current sequence number
* by about a day rather than she wants to wait for years
* using fences.
*/
DRM_WAIT_ON(ret, dev_priv->fence_queue, 3 * DRM_HZ,
(((cur_fence = atomic_read(&dev_priv->last_fence_retired))
- *sequence) <= (1 << 23)));
*sequence = cur_fence;
return ret;
}
void mga_driver_irq_preinstall(drm_device_t * dev)
{
drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
/* Disable *all* interrupts */
MGA_WRITE(MGA_IEN, 0);
/* Clear bits if they're already high */
MGA_WRITE(MGA_ICLEAR, ~0);
}
void mga_driver_irq_postinstall(drm_device_t * dev)
{
drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
DRM_INIT_WAITQUEUE( &dev_priv->fence_queue );
/* Turn on vertical blank interrupt and soft trap interrupt. */
MGA_WRITE(MGA_IEN, MGA_VLINEIEN | MGA_SOFTRAPEN);
}
void mga_driver_irq_uninstall(drm_device_t * dev)
{
drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
if (!dev_priv)
return;
/* Disable *all* interrupts */
MGA_WRITE(MGA_IEN, 0);
dev->irq_enabled = 0;
}

1183
sys/dev/pci/drm/mga_state.c Normal file

File diff suppressed because it is too large Load Diff

11650
sys/dev/pci/drm/mga_ucode.h Normal file

File diff suppressed because it is too large Load Diff

203
sys/dev/pci/drm/mga_warp.c Normal file
View File

@ -0,0 +1,203 @@
/* mga_warp.c -- Matrox G200/G400 WARP engine management -*- linux-c -*-
* Created: Thu Jan 11 21:29:32 2001 by gareth@valinux.com
*/
/*-
* 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:
* Gareth Hughes <gareth@valinux.com>
*/
#include <sys/cdefs.h>
/*
__FBSDID("$FreeBSD: src/sys/dev/drm/mga_warp.c,v 1.8 2005/11/28 23:13:53 anholt Exp $");
*/
#include "drmP.h"
#include "drm.h"
#include "mga_drm.h"
#include "mga_drv.h"
#include "mga_ucode.h"
#define MGA_WARP_CODE_ALIGN 256 /* in bytes */
#define WARP_UCODE_SIZE( which ) \
((sizeof(which) / MGA_WARP_CODE_ALIGN + 1) * MGA_WARP_CODE_ALIGN)
#define WARP_UCODE_INSTALL( which, where ) \
do { \
DRM_DEBUG( " pcbase = 0x%08lx vcbase = %p\n", pcbase, vcbase );\
dev_priv->warp_pipe_phys[where] = pcbase; \
memcpy( vcbase, which, sizeof(which) ); \
pcbase += WARP_UCODE_SIZE( which ); \
vcbase += WARP_UCODE_SIZE( which ); \
} while (0)
static const unsigned int mga_warp_g400_microcode_size =
(WARP_UCODE_SIZE(warp_g400_tgz) +
WARP_UCODE_SIZE(warp_g400_tgza) +
WARP_UCODE_SIZE(warp_g400_tgzaf) +
WARP_UCODE_SIZE(warp_g400_tgzf) +
WARP_UCODE_SIZE(warp_g400_tgzs) +
WARP_UCODE_SIZE(warp_g400_tgzsa) +
WARP_UCODE_SIZE(warp_g400_tgzsaf) +
WARP_UCODE_SIZE(warp_g400_tgzsf) +
WARP_UCODE_SIZE(warp_g400_t2gz) +
WARP_UCODE_SIZE(warp_g400_t2gza) +
WARP_UCODE_SIZE(warp_g400_t2gzaf) +
WARP_UCODE_SIZE(warp_g400_t2gzf) +
WARP_UCODE_SIZE(warp_g400_t2gzs) +
WARP_UCODE_SIZE(warp_g400_t2gzsa) +
WARP_UCODE_SIZE(warp_g400_t2gzsaf) +
WARP_UCODE_SIZE(warp_g400_t2gzsf));
static const unsigned int mga_warp_g200_microcode_size =
(WARP_UCODE_SIZE(warp_g200_tgz) +
WARP_UCODE_SIZE(warp_g200_tgza) +
WARP_UCODE_SIZE(warp_g200_tgzaf) +
WARP_UCODE_SIZE(warp_g200_tgzf) +
WARP_UCODE_SIZE(warp_g200_tgzs) +
WARP_UCODE_SIZE(warp_g200_tgzsa) +
WARP_UCODE_SIZE(warp_g200_tgzsaf) +
WARP_UCODE_SIZE(warp_g200_tgzsf));
unsigned int mga_warp_microcode_size(const drm_mga_private_t * dev_priv)
{
switch (dev_priv->chipset) {
case MGA_CARD_TYPE_G400:
case MGA_CARD_TYPE_G550:
return PAGE_ALIGN(mga_warp_g400_microcode_size);
case MGA_CARD_TYPE_G200:
return PAGE_ALIGN(mga_warp_g200_microcode_size);
default:
DRM_ERROR("Unknown chipset value: 0x%x\n", dev_priv->chipset);
return 0;
}
}
static int mga_warp_install_g400_microcode(drm_mga_private_t * dev_priv)
{
unsigned char *vcbase = dev_priv->warp->handle;
unsigned long pcbase = dev_priv->warp->offset;
memset(dev_priv->warp_pipe_phys, 0, sizeof(dev_priv->warp_pipe_phys));
WARP_UCODE_INSTALL(warp_g400_tgz, MGA_WARP_TGZ);
WARP_UCODE_INSTALL(warp_g400_tgzf, MGA_WARP_TGZF);
WARP_UCODE_INSTALL(warp_g400_tgza, MGA_WARP_TGZA);
WARP_UCODE_INSTALL(warp_g400_tgzaf, MGA_WARP_TGZAF);
WARP_UCODE_INSTALL(warp_g400_tgzs, MGA_WARP_TGZS);
WARP_UCODE_INSTALL(warp_g400_tgzsf, MGA_WARP_TGZSF);
WARP_UCODE_INSTALL(warp_g400_tgzsa, MGA_WARP_TGZSA);
WARP_UCODE_INSTALL(warp_g400_tgzsaf, MGA_WARP_TGZSAF);
WARP_UCODE_INSTALL(warp_g400_t2gz, MGA_WARP_T2GZ);
WARP_UCODE_INSTALL(warp_g400_t2gzf, MGA_WARP_T2GZF);
WARP_UCODE_INSTALL(warp_g400_t2gza, MGA_WARP_T2GZA);
WARP_UCODE_INSTALL(warp_g400_t2gzaf, MGA_WARP_T2GZAF);
WARP_UCODE_INSTALL(warp_g400_t2gzs, MGA_WARP_T2GZS);
WARP_UCODE_INSTALL(warp_g400_t2gzsf, MGA_WARP_T2GZSF);
WARP_UCODE_INSTALL(warp_g400_t2gzsa, MGA_WARP_T2GZSA);
WARP_UCODE_INSTALL(warp_g400_t2gzsaf, MGA_WARP_T2GZSAF);
return 0;
}
static int mga_warp_install_g200_microcode(drm_mga_private_t * dev_priv)
{
unsigned char *vcbase = dev_priv->warp->handle;
unsigned long pcbase = dev_priv->warp->offset;
memset(dev_priv->warp_pipe_phys, 0, sizeof(dev_priv->warp_pipe_phys));
WARP_UCODE_INSTALL(warp_g200_tgz, MGA_WARP_TGZ);
WARP_UCODE_INSTALL(warp_g200_tgzf, MGA_WARP_TGZF);
WARP_UCODE_INSTALL(warp_g200_tgza, MGA_WARP_TGZA);
WARP_UCODE_INSTALL(warp_g200_tgzaf, MGA_WARP_TGZAF);
WARP_UCODE_INSTALL(warp_g200_tgzs, MGA_WARP_TGZS);
WARP_UCODE_INSTALL(warp_g200_tgzsf, MGA_WARP_TGZSF);
WARP_UCODE_INSTALL(warp_g200_tgzsa, MGA_WARP_TGZSA);
WARP_UCODE_INSTALL(warp_g200_tgzsaf, MGA_WARP_TGZSAF);
return 0;
}
int mga_warp_install_microcode(drm_mga_private_t * dev_priv)
{
const unsigned int size = mga_warp_microcode_size(dev_priv);
DRM_DEBUG("MGA ucode size = %d bytes\n", size);
if (size > dev_priv->warp->size) {
DRM_ERROR("microcode too large! (%u > %lu)\n",
size, dev_priv->warp->size);
return DRM_ERR(ENOMEM);
}
switch (dev_priv->chipset) {
case MGA_CARD_TYPE_G400:
case MGA_CARD_TYPE_G550:
return mga_warp_install_g400_microcode(dev_priv);
case MGA_CARD_TYPE_G200:
return mga_warp_install_g200_microcode(dev_priv);
default:
return DRM_ERR(EINVAL);
}
}
#define WMISC_EXPECTED (MGA_WUCODECACHE_ENABLE | MGA_WMASTER_ENABLE)
int mga_warp_init(drm_mga_private_t * dev_priv)
{
u32 wmisc;
/* FIXME: Get rid of these damned magic numbers...
*/
switch (dev_priv->chipset) {
case MGA_CARD_TYPE_G400:
case MGA_CARD_TYPE_G550:
MGA_WRITE(MGA_WIADDR2, MGA_WMODE_SUSPEND);
MGA_WRITE(MGA_WGETMSB, 0x00000E00);
MGA_WRITE(MGA_WVRTXSZ, 0x00001807);
MGA_WRITE(MGA_WACCEPTSEQ, 0x18000000);
break;
case MGA_CARD_TYPE_G200:
MGA_WRITE(MGA_WIADDR, MGA_WMODE_SUSPEND);
MGA_WRITE(MGA_WGETMSB, 0x1606);
MGA_WRITE(MGA_WVRTXSZ, 7);
break;
default:
return DRM_ERR(EINVAL);
}
MGA_WRITE(MGA_WMISC, (MGA_WUCODECACHE_ENABLE |
MGA_WMASTER_ENABLE | MGA_WCACHEFLUSH_ENABLE));
wmisc = MGA_READ(MGA_WMISC);
if (wmisc != WMISC_EXPECTED) {
DRM_ERROR("WARP engine config failed! 0x%x != 0x%x\n",
wmisc, WMISC_EXPECTED);
return DRM_ERR(EINVAL);
}
return 0;
}

953
sys/dev/pci/drm/r128_cce.c Normal file
View File

@ -0,0 +1,953 @@
/* r128_cce.c -- ATI Rage 128 driver -*- linux-c -*-
* Created: Wed Apr 5 19:24:19 2000 by kevin@precisioninsight.com
*/
/*-
* Copyright 2000 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:
* Gareth Hughes <gareth@valinux.com>
*/
#include <sys/cdefs.h>
/*
__FBSDID("$FreeBSD: src/sys/dev/drm/r128_cce.c,v 1.14 2005/11/28 23:13:53 anholt Exp $");
*/
#include "drmP.h"
#include "drm.h"
#include "r128_drm.h"
#include "r128_drv.h"
#define R128_FIFO_DEBUG 0
/* CCE microcode (from ATI) */
static u32 r128_cce_microcode[] = {
0, 276838400, 0, 268449792, 2, 142, 2, 145, 0, 1076765731, 0,
1617039951, 0, 774592877, 0, 1987540286, 0, 2307490946U, 0,
599558925, 0, 589505315, 0, 596487092, 0, 589505315, 1,
11544576, 1, 206848, 1, 311296, 1, 198656, 2, 912273422, 11,
262144, 0, 0, 1, 33559837, 1, 7438, 1, 14809, 1, 6615, 12, 28,
1, 6614, 12, 28, 2, 23, 11, 18874368, 0, 16790922, 1, 409600, 9,
30, 1, 147854772, 16, 420483072, 3, 8192, 0, 10240, 1, 198656,
1, 15630, 1, 51200, 10, 34858, 9, 42, 1, 33559823, 2, 10276, 1,
15717, 1, 15718, 2, 43, 1, 15936948, 1, 570480831, 1, 14715071,
12, 322123831, 1, 33953125, 12, 55, 1, 33559908, 1, 15718, 2,
46, 4, 2099258, 1, 526336, 1, 442623, 4, 4194365, 1, 509952, 1,
459007, 3, 0, 12, 92, 2, 46, 12, 176, 1, 15734, 1, 206848, 1,
18432, 1, 133120, 1, 100670734, 1, 149504, 1, 165888, 1,
15975928, 1, 1048576, 6, 3145806, 1, 15715, 16, 2150645232U, 2,
268449859, 2, 10307, 12, 176, 1, 15734, 1, 15735, 1, 15630, 1,
15631, 1, 5253120, 6, 3145810, 16, 2150645232U, 1, 15864, 2, 82,
1, 343310, 1, 1064207, 2, 3145813, 1, 15728, 1, 7817, 1, 15729,
3, 15730, 12, 92, 2, 98, 1, 16168, 1, 16167, 1, 16002, 1, 16008,
1, 15974, 1, 15975, 1, 15990, 1, 15976, 1, 15977, 1, 15980, 0,
15981, 1, 10240, 1, 5253120, 1, 15720, 1, 198656, 6, 110, 1,
180224, 1, 103824738, 2, 112, 2, 3145839, 0, 536885440, 1,
114880, 14, 125, 12, 206975, 1, 33559995, 12, 198784, 0,
33570236, 1, 15803, 0, 15804, 3, 294912, 1, 294912, 3, 442370,
1, 11544576, 0, 811612160, 1, 12593152, 1, 11536384, 1,
14024704, 7, 310382726, 0, 10240, 1, 14796, 1, 14797, 1, 14793,
1, 14794, 0, 14795, 1, 268679168, 1, 9437184, 1, 268449792, 1,
198656, 1, 9452827, 1, 1075854602, 1, 1075854603, 1, 557056, 1,
114880, 14, 159, 12, 198784, 1, 1109409213, 12, 198783, 1,
1107312059, 12, 198784, 1, 1109409212, 2, 162, 1, 1075854781, 1,
1073757627, 1, 1075854780, 1, 540672, 1, 10485760, 6, 3145894,
16, 274741248, 9, 168, 3, 4194304, 3, 4209949, 0, 0, 0, 256, 14,
174, 1, 114857, 1, 33560007, 12, 176, 0, 10240, 1, 114858, 1,
33560018, 1, 114857, 3, 33560007, 1, 16008, 1, 114874, 1,
33560360, 1, 114875, 1, 33560154, 0, 15963, 0, 256, 0, 4096, 1,
409611, 9, 188, 0, 10240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
static int R128_READ_PLL(drm_device_t * dev, int addr)
{
drm_r128_private_t *dev_priv = dev->dev_private;
R128_WRITE8(R128_CLOCK_CNTL_INDEX, addr & 0x1f);
return R128_READ(R128_CLOCK_CNTL_DATA);
}
#if R128_FIFO_DEBUG
static void r128_status(drm_r128_private_t * dev_priv)
{
printk("GUI_STAT = 0x%08x\n",
(unsigned int)R128_READ(R128_GUI_STAT));
printk("PM4_STAT = 0x%08x\n",
(unsigned int)R128_READ(R128_PM4_STAT));
printk("PM4_BUFFER_DL_WPTR = 0x%08x\n",
(unsigned int)R128_READ(R128_PM4_BUFFER_DL_WPTR));
printk("PM4_BUFFER_DL_RPTR = 0x%08x\n",
(unsigned int)R128_READ(R128_PM4_BUFFER_DL_RPTR));
printk("PM4_MICRO_CNTL = 0x%08x\n",
(unsigned int)R128_READ(R128_PM4_MICRO_CNTL));
printk("PM4_BUFFER_CNTL = 0x%08x\n",
(unsigned int)R128_READ(R128_PM4_BUFFER_CNTL));
}
#endif
/* ================================================================
* Engine, FIFO control
*/
static int r128_do_pixcache_flush(drm_r128_private_t * dev_priv)
{
u32 tmp;
int i;
tmp = R128_READ(R128_PC_NGUI_CTLSTAT) | R128_PC_FLUSH_ALL;
R128_WRITE(R128_PC_NGUI_CTLSTAT, tmp);
for (i = 0; i < dev_priv->usec_timeout; i++) {
if (!(R128_READ(R128_PC_NGUI_CTLSTAT) & R128_PC_BUSY)) {
return 0;
}
DRM_UDELAY(1);
}
#if R128_FIFO_DEBUG
DRM_ERROR("failed!\n");
#endif
return DRM_ERR(EBUSY);
}
static int r128_do_wait_for_fifo(drm_r128_private_t * dev_priv, int entries)
{
int i;
for (i = 0; i < dev_priv->usec_timeout; i++) {
int slots = R128_READ(R128_GUI_STAT) & R128_GUI_FIFOCNT_MASK;
if (slots >= entries)
return 0;
DRM_UDELAY(1);
}
#if R128_FIFO_DEBUG
DRM_ERROR("failed!\n");
#endif
return DRM_ERR(EBUSY);
}
static int r128_do_wait_for_idle(drm_r128_private_t * dev_priv)
{
int i, ret;
ret = r128_do_wait_for_fifo(dev_priv, 64);
if (ret)
return ret;
for (i = 0; i < dev_priv->usec_timeout; i++) {
if (!(R128_READ(R128_GUI_STAT) & R128_GUI_ACTIVE)) {
r128_do_pixcache_flush(dev_priv);
return 0;
}
DRM_UDELAY(1);
}
#if R128_FIFO_DEBUG
DRM_ERROR("failed!\n");
#endif
return DRM_ERR(EBUSY);
}
/* ================================================================
* CCE control, initialization
*/
/* Load the microcode for the CCE */
static void r128_cce_load_microcode(drm_r128_private_t * dev_priv)
{
int i;
DRM_DEBUG("\n");
r128_do_wait_for_idle(dev_priv);
R128_WRITE(R128_PM4_MICROCODE_ADDR, 0);
for (i = 0; i < 256; i++) {
R128_WRITE(R128_PM4_MICROCODE_DATAH, r128_cce_microcode[i * 2]);
R128_WRITE(R128_PM4_MICROCODE_DATAL,
r128_cce_microcode[i * 2 + 1]);
}
}
/* Flush any pending commands to the CCE. This should only be used just
* prior to a wait for idle, as it informs the engine that the command
* stream is ending.
*/
static void r128_do_cce_flush(drm_r128_private_t * dev_priv)
{
u32 tmp;
tmp = R128_READ(R128_PM4_BUFFER_DL_WPTR) | R128_PM4_BUFFER_DL_DONE;
R128_WRITE(R128_PM4_BUFFER_DL_WPTR, tmp);
}
/* Wait for the CCE to go idle.
*/
int r128_do_cce_idle(drm_r128_private_t * dev_priv)
{
int i;
for (i = 0; i < dev_priv->usec_timeout; i++) {
if (GET_RING_HEAD(dev_priv) == dev_priv->ring.tail) {
int pm4stat = R128_READ(R128_PM4_STAT);
if (((pm4stat & R128_PM4_FIFOCNT_MASK) >=
dev_priv->cce_fifo_size) &&
!(pm4stat & (R128_PM4_BUSY |
R128_PM4_GUI_ACTIVE))) {
return r128_do_pixcache_flush(dev_priv);
}
}
DRM_UDELAY(1);
}
#if R128_FIFO_DEBUG
DRM_ERROR("failed!\n");
r128_status(dev_priv);
#endif
return DRM_ERR(EBUSY);
}
/* Start the Concurrent Command Engine.
*/
static void r128_do_cce_start(drm_r128_private_t * dev_priv)
{
r128_do_wait_for_idle(dev_priv);
R128_WRITE(R128_PM4_BUFFER_CNTL,
dev_priv->cce_mode | dev_priv->ring.size_l2qw
| R128_PM4_BUFFER_CNTL_NOUPDATE);
R128_READ(R128_PM4_BUFFER_ADDR); /* as per the sample code */
R128_WRITE(R128_PM4_MICRO_CNTL, R128_PM4_MICRO_FREERUN);
dev_priv->cce_running = 1;
}
/* Reset the Concurrent Command Engine. This will not flush any pending
* commands, so you must wait for the CCE command stream to complete
* before calling this routine.
*/
static void r128_do_cce_reset(drm_r128_private_t * dev_priv)
{
R128_WRITE(R128_PM4_BUFFER_DL_WPTR, 0);
R128_WRITE(R128_PM4_BUFFER_DL_RPTR, 0);
dev_priv->ring.tail = 0;
}
/* Stop the Concurrent Command Engine. This will not flush any pending
* commands, so you must flush the command stream and wait for the CCE
* to go idle before calling this routine.
*/
static void r128_do_cce_stop(drm_r128_private_t * dev_priv)
{
R128_WRITE(R128_PM4_MICRO_CNTL, 0);
R128_WRITE(R128_PM4_BUFFER_CNTL,
R128_PM4_NONPM4 | R128_PM4_BUFFER_CNTL_NOUPDATE);
dev_priv->cce_running = 0;
}
/* Reset the engine. This will stop the CCE if it is running.
*/
static int r128_do_engine_reset(drm_device_t * dev)
{
drm_r128_private_t *dev_priv = dev->dev_private;
u32 clock_cntl_index, mclk_cntl, gen_reset_cntl;
r128_do_pixcache_flush(dev_priv);
clock_cntl_index = R128_READ(R128_CLOCK_CNTL_INDEX);
mclk_cntl = R128_READ_PLL(dev, R128_MCLK_CNTL);
R128_WRITE_PLL(R128_MCLK_CNTL,
mclk_cntl | R128_FORCE_GCP | R128_FORCE_PIPE3D_CP);
gen_reset_cntl = R128_READ(R128_GEN_RESET_CNTL);
/* Taken from the sample code - do not change */
R128_WRITE(R128_GEN_RESET_CNTL, gen_reset_cntl | R128_SOFT_RESET_GUI);
R128_READ(R128_GEN_RESET_CNTL);
R128_WRITE(R128_GEN_RESET_CNTL, gen_reset_cntl & ~R128_SOFT_RESET_GUI);
R128_READ(R128_GEN_RESET_CNTL);
R128_WRITE_PLL(R128_MCLK_CNTL, mclk_cntl);
R128_WRITE(R128_CLOCK_CNTL_INDEX, clock_cntl_index);
R128_WRITE(R128_GEN_RESET_CNTL, gen_reset_cntl);
/* Reset the CCE ring */
r128_do_cce_reset(dev_priv);
/* The CCE is no longer running after an engine reset */
dev_priv->cce_running = 0;
/* Reset any pending vertex, indirect buffers */
r128_freelist_reset(dev);
return 0;
}
static void r128_cce_init_ring_buffer(drm_device_t * dev,
drm_r128_private_t * dev_priv)
{
u32 ring_start;
u32 tmp;
DRM_DEBUG("\n");
/* The manual (p. 2) says this address is in "VM space". This
* means it's an offset from the start of AGP space.
*/
#if __OS_HAS_AGP
if (!dev_priv->is_pci)
ring_start = dev_priv->cce_ring->offset - dev->agp->base;
else
#endif
ring_start = dev_priv->cce_ring->offset -
(unsigned long)dev->sg->virtual;
R128_WRITE(R128_PM4_BUFFER_OFFSET, ring_start | R128_AGP_OFFSET);
R128_WRITE(R128_PM4_BUFFER_DL_WPTR, 0);
R128_WRITE(R128_PM4_BUFFER_DL_RPTR, 0);
/* Set watermark control */
R128_WRITE(R128_PM4_BUFFER_WM_CNTL,
((R128_WATERMARK_L / 4) << R128_WMA_SHIFT)
| ((R128_WATERMARK_M / 4) << R128_WMB_SHIFT)
| ((R128_WATERMARK_N / 4) << R128_WMC_SHIFT)
| ((R128_WATERMARK_K / 64) << R128_WB_WM_SHIFT));
/* Force read. Why? Because it's in the examples... */
R128_READ(R128_PM4_BUFFER_ADDR);
/* Turn on bus mastering */
tmp = R128_READ(R128_BUS_CNTL) & ~R128_BUS_MASTER_DIS;
R128_WRITE(R128_BUS_CNTL, tmp);
}
static int r128_do_init_cce(drm_device_t * dev, drm_r128_init_t * init)
{
drm_r128_private_t *dev_priv;
DRM_DEBUG("\n");
dev_priv = drm_alloc(sizeof(drm_r128_private_t), DRM_MEM_DRIVER);
if (dev_priv == NULL)
return DRM_ERR(ENOMEM);
memset(dev_priv, 0, sizeof(drm_r128_private_t));
dev_priv->is_pci = init->is_pci;
if (dev_priv->is_pci && !dev->sg) {
DRM_ERROR("PCI GART memory not allocated!\n");
dev->dev_private = (void *)dev_priv;
r128_do_cleanup_cce(dev);
return DRM_ERR(EINVAL);
}
dev_priv->usec_timeout = init->usec_timeout;
if (dev_priv->usec_timeout < 1 ||
dev_priv->usec_timeout > R128_MAX_USEC_TIMEOUT) {
DRM_DEBUG("TIMEOUT problem!\n");
dev->dev_private = (void *)dev_priv;
r128_do_cleanup_cce(dev);
return DRM_ERR(EINVAL);
}
dev_priv->cce_mode = init->cce_mode;
/* GH: Simple idle check.
*/
atomic_set(&dev_priv->idle_count, 0);
/* We don't support anything other than bus-mastering ring mode,
* but the ring can be in either AGP or PCI space for the ring
* read pointer.
*/
if ((init->cce_mode != R128_PM4_192BM) &&
(init->cce_mode != R128_PM4_128BM_64INDBM) &&
(init->cce_mode != R128_PM4_64BM_128INDBM) &&
(init->cce_mode != R128_PM4_64BM_64VCBM_64INDBM)) {
DRM_DEBUG("Bad cce_mode!\n");
dev->dev_private = (void *)dev_priv;
r128_do_cleanup_cce(dev);
return DRM_ERR(EINVAL);
}
switch (init->cce_mode) {
case R128_PM4_NONPM4:
dev_priv->cce_fifo_size = 0;
break;
case R128_PM4_192PIO:
case R128_PM4_192BM:
dev_priv->cce_fifo_size = 192;
break;
case R128_PM4_128PIO_64INDBM:
case R128_PM4_128BM_64INDBM:
dev_priv->cce_fifo_size = 128;
break;
case R128_PM4_64PIO_128INDBM:
case R128_PM4_64BM_128INDBM:
case R128_PM4_64PIO_64VCBM_64INDBM:
case R128_PM4_64BM_64VCBM_64INDBM:
case R128_PM4_64PIO_64VCPIO_64INDPIO:
dev_priv->cce_fifo_size = 64;
break;
}
switch (init->fb_bpp) {
case 16:
dev_priv->color_fmt = R128_DATATYPE_RGB565;
break;
case 32:
default:
dev_priv->color_fmt = R128_DATATYPE_ARGB8888;
break;
}
dev_priv->front_offset = init->front_offset;
dev_priv->front_pitch = init->front_pitch;
dev_priv->back_offset = init->back_offset;
dev_priv->back_pitch = init->back_pitch;
switch (init->depth_bpp) {
case 16:
dev_priv->depth_fmt = R128_DATATYPE_RGB565;
break;
case 24:
case 32:
default:
dev_priv->depth_fmt = R128_DATATYPE_ARGB8888;
break;
}
dev_priv->depth_offset = init->depth_offset;
dev_priv->depth_pitch = init->depth_pitch;
dev_priv->span_offset = init->span_offset;
dev_priv->front_pitch_offset_c = (((dev_priv->front_pitch / 8) << 21) |
(dev_priv->front_offset >> 5));
dev_priv->back_pitch_offset_c = (((dev_priv->back_pitch / 8) << 21) |
(dev_priv->back_offset >> 5));
dev_priv->depth_pitch_offset_c = (((dev_priv->depth_pitch / 8) << 21) |
(dev_priv->depth_offset >> 5) |
R128_DST_TILE);
dev_priv->span_pitch_offset_c = (((dev_priv->depth_pitch / 8) << 21) |
(dev_priv->span_offset >> 5));
DRM_GETSAREA();
if (!dev_priv->sarea) {
DRM_ERROR("could not find sarea!\n");
dev->dev_private = (void *)dev_priv;
r128_do_cleanup_cce(dev);
return DRM_ERR(EINVAL);
}
dev_priv->mmio = drm_core_findmap(dev, init->mmio_offset);
if (!dev_priv->mmio) {
DRM_ERROR("could not find mmio region!\n");
dev->dev_private = (void *)dev_priv;
r128_do_cleanup_cce(dev);
return DRM_ERR(EINVAL);
}
dev_priv->cce_ring = drm_core_findmap(dev, init->ring_offset);
if (!dev_priv->cce_ring) {
DRM_ERROR("could not find cce ring region!\n");
dev->dev_private = (void *)dev_priv;
r128_do_cleanup_cce(dev);
return DRM_ERR(EINVAL);
}
dev_priv->ring_rptr = drm_core_findmap(dev, init->ring_rptr_offset);
if (!dev_priv->ring_rptr) {
DRM_ERROR("could not find ring read pointer!\n");
dev->dev_private = (void *)dev_priv;
r128_do_cleanup_cce(dev);
return DRM_ERR(EINVAL);
}
dev->agp_buffer_token = init->buffers_offset;
dev->agp_buffer_map = drm_core_findmap(dev, init->buffers_offset);
if (!dev->agp_buffer_map) {
DRM_ERROR("could not find dma buffer region!\n");
dev->dev_private = (void *)dev_priv;
r128_do_cleanup_cce(dev);
return DRM_ERR(EINVAL);
}
if (!dev_priv->is_pci) {
dev_priv->agp_textures =
drm_core_findmap(dev, init->agp_textures_offset);
if (!dev_priv->agp_textures) {
DRM_ERROR("could not find agp texture region!\n");
dev->dev_private = (void *)dev_priv;
r128_do_cleanup_cce(dev);
return DRM_ERR(EINVAL);
}
}
dev_priv->sarea_priv =
(drm_r128_sarea_t *) ((u8 *) dev_priv->sarea->handle +
init->sarea_priv_offset);
#if __OS_HAS_AGP
if (!dev_priv->is_pci) {
drm_core_ioremap(dev_priv->cce_ring, dev);
drm_core_ioremap(dev_priv->ring_rptr, dev);
drm_core_ioremap(dev->agp_buffer_map, dev);
if (!dev_priv->cce_ring->handle ||
!dev_priv->ring_rptr->handle ||
!dev->agp_buffer_map->handle) {
DRM_ERROR("Could not ioremap agp regions!\n");
dev->dev_private = (void *)dev_priv;
r128_do_cleanup_cce(dev);
return DRM_ERR(ENOMEM);
}
} else
#endif
{
dev_priv->cce_ring->handle = (void *)dev_priv->cce_ring->offset;
dev_priv->ring_rptr->handle =
(void *)dev_priv->ring_rptr->offset;
dev->agp_buffer_map->handle =
(void *)dev->agp_buffer_map->offset;
}
#if __OS_HAS_AGP
if (!dev_priv->is_pci)
dev_priv->cce_buffers_offset = dev->agp->base;
else
#endif
dev_priv->cce_buffers_offset = (unsigned long)dev->sg->virtual;
dev_priv->ring.start = (u32 *) dev_priv->cce_ring->handle;
dev_priv->ring.end = ((u32 *) dev_priv->cce_ring->handle
+ init->ring_size / sizeof(u32));
dev_priv->ring.size = init->ring_size;
dev_priv->ring.size_l2qw = drm_order(init->ring_size / 8);
dev_priv->ring.tail_mask = (dev_priv->ring.size / sizeof(u32)) - 1;
dev_priv->ring.high_mark = 128;
dev_priv->sarea_priv->last_frame = 0;
R128_WRITE(R128_LAST_FRAME_REG, dev_priv->sarea_priv->last_frame);
dev_priv->sarea_priv->last_dispatch = 0;
R128_WRITE(R128_LAST_DISPATCH_REG, dev_priv->sarea_priv->last_dispatch);
#if __OS_HAS_AGP
if (dev_priv->is_pci) {
#endif
dev_priv->gart_info.gart_table_location = DRM_ATI_GART_MAIN;
dev_priv->gart_info.addr = NULL;
dev_priv->gart_info.bus_addr = 0;
dev_priv->gart_info.is_pcie = 0;
if (!drm_ati_pcigart_init(dev, &dev_priv->gart_info)) {
DRM_ERROR("failed to init PCI GART!\n");
dev->dev_private = (void *)dev_priv;
r128_do_cleanup_cce(dev);
return DRM_ERR(ENOMEM);
}
R128_WRITE(R128_PCI_GART_PAGE, dev_priv->gart_info.bus_addr);
#if __OS_HAS_AGP
}
#endif
r128_cce_init_ring_buffer(dev, dev_priv);
r128_cce_load_microcode(dev_priv);
dev->dev_private = (void *)dev_priv;
r128_do_engine_reset(dev);
return 0;
}
int r128_do_cleanup_cce(drm_device_t * dev)
{
/* Make sure interrupts are disabled here because the uninstall ioctl
* may not have been called from userspace and after dev_private
* is freed, it's too late.
*/
if (dev->irq_enabled)
drm_irq_uninstall(dev);
if (dev->dev_private) {
drm_r128_private_t *dev_priv = dev->dev_private;
#if __OS_HAS_AGP
if (!dev_priv->is_pci) {
if (dev_priv->cce_ring != NULL)
drm_core_ioremapfree(dev_priv->cce_ring, dev);
if (dev_priv->ring_rptr != NULL)
drm_core_ioremapfree(dev_priv->ring_rptr, dev);
if (dev->agp_buffer_map != NULL) {
drm_core_ioremapfree(dev->agp_buffer_map, dev);
dev->agp_buffer_map = NULL;
}
} else
#endif
{
if (dev_priv->gart_info.bus_addr)
if (!drm_ati_pcigart_cleanup(dev, &dev_priv->gart_info))
DRM_ERROR("failed to cleanup PCI GART!\n");
}
drm_free(dev->dev_private, sizeof(drm_r128_private_t),
DRM_MEM_DRIVER);
dev->dev_private = NULL;
}
return 0;
}
int r128_cce_init(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_r128_init_t init;
DRM_DEBUG("\n");
LOCK_TEST_WITH_RETURN(dev, filp);
DRM_COPY_FROM_USER_IOCTL(init, (drm_r128_init_t __user *) data,
sizeof(init));
switch (init.func) {
case R128_INIT_CCE:
return r128_do_init_cce(dev, &init);
case R128_CLEANUP_CCE:
return r128_do_cleanup_cce(dev);
}
return DRM_ERR(EINVAL);
}
int r128_cce_start(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_r128_private_t *dev_priv = dev->dev_private;
DRM_DEBUG("\n");
LOCK_TEST_WITH_RETURN(dev, filp);
if (dev_priv->cce_running || dev_priv->cce_mode == R128_PM4_NONPM4) {
DRM_DEBUG("%s while CCE running\n", __FUNCTION__);
return 0;
}
r128_do_cce_start(dev_priv);
return 0;
}
/* Stop the CCE. The engine must have been idled before calling this
* routine.
*/
int r128_cce_stop(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_r128_private_t *dev_priv = dev->dev_private;
drm_r128_cce_stop_t stop;
int ret;
DRM_DEBUG("\n");
LOCK_TEST_WITH_RETURN(dev, filp);
DRM_COPY_FROM_USER_IOCTL(stop, (drm_r128_cce_stop_t __user *) data,
sizeof(stop));
/* Flush any pending CCE commands. This ensures any outstanding
* commands are exectuted by the engine before we turn it off.
*/
if (stop.flush) {
r128_do_cce_flush(dev_priv);
}
/* If we fail to make the engine go idle, we return an error
* code so that the DRM ioctl wrapper can try again.
*/
if (stop.idle) {
ret = r128_do_cce_idle(dev_priv);
if (ret)
return ret;
}
/* Finally, we can turn off the CCE. If the engine isn't idle,
* we will get some dropped triangles as they won't be fully
* rendered before the CCE is shut down.
*/
r128_do_cce_stop(dev_priv);
/* Reset the engine */
r128_do_engine_reset(dev);
return 0;
}
/* Just reset the CCE ring. Called as part of an X Server engine reset.
*/
int r128_cce_reset(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_r128_private_t *dev_priv = dev->dev_private;
DRM_DEBUG("\n");
LOCK_TEST_WITH_RETURN(dev, filp);
if (!dev_priv) {
DRM_DEBUG("%s called before init done\n", __FUNCTION__);
return DRM_ERR(EINVAL);
}
r128_do_cce_reset(dev_priv);
/* The CCE is no longer running after an engine reset */
dev_priv->cce_running = 0;
return 0;
}
int r128_cce_idle(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_r128_private_t *dev_priv = dev->dev_private;
DRM_DEBUG("\n");
LOCK_TEST_WITH_RETURN(dev, filp);
if (dev_priv->cce_running) {
r128_do_cce_flush(dev_priv);
}
return r128_do_cce_idle(dev_priv);
}
int r128_engine_reset(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
DRM_DEBUG("\n");
LOCK_TEST_WITH_RETURN(dev, filp);
return r128_do_engine_reset(dev);
}
int r128_fullscreen(DRM_IOCTL_ARGS)
{
return DRM_ERR(EINVAL);
}
/* ================================================================
* Freelist management
*/
#define R128_BUFFER_USED 0xffffffff
#define R128_BUFFER_FREE 0
#if 0
static int r128_freelist_init(drm_device_t * dev)
{
drm_device_dma_t *dma = dev->dma;
drm_r128_private_t *dev_priv = dev->dev_private;
drm_buf_t *buf;
drm_r128_buf_priv_t *buf_priv;
drm_r128_freelist_t *entry;
int i;
dev_priv->head = drm_alloc(sizeof(drm_r128_freelist_t), DRM_MEM_DRIVER);
if (dev_priv->head == NULL)
return DRM_ERR(ENOMEM);
memset(dev_priv->head, 0, sizeof(drm_r128_freelist_t));
dev_priv->head->age = R128_BUFFER_USED;
for (i = 0; i < dma->buf_count; i++) {
buf = dma->buflist[i];
buf_priv = buf->dev_private;
entry = drm_alloc(sizeof(drm_r128_freelist_t), DRM_MEM_DRIVER);
if (!entry)
return DRM_ERR(ENOMEM);
entry->age = R128_BUFFER_FREE;
entry->buf = buf;
entry->prev = dev_priv->head;
entry->next = dev_priv->head->next;
if (!entry->next)
dev_priv->tail = entry;
buf_priv->discard = 0;
buf_priv->dispatched = 0;
buf_priv->list_entry = entry;
dev_priv->head->next = entry;
if (dev_priv->head->next)
dev_priv->head->next->prev = entry;
}
return 0;
}
#endif
static drm_buf_t *r128_freelist_get(drm_device_t * dev)
{
drm_device_dma_t *dma = dev->dma;
drm_r128_private_t *dev_priv = dev->dev_private;
drm_r128_buf_priv_t *buf_priv;
drm_buf_t *buf;
int i, t;
/* FIXME: Optimize -- use freelist code */
for (i = 0; i < dma->buf_count; i++) {
buf = dma->buflist[i];
buf_priv = buf->dev_private;
if (buf->filp == 0)
return buf;
}
for (t = 0; t < dev_priv->usec_timeout; t++) {
u32 done_age = R128_READ(R128_LAST_DISPATCH_REG);
for (i = 0; i < dma->buf_count; i++) {
buf = dma->buflist[i];
buf_priv = buf->dev_private;
if (buf->pending && buf_priv->age <= done_age) {
/* The buffer has been processed, so it
* can now be used.
*/
buf->pending = 0;
return buf;
}
}
DRM_UDELAY(1);
}
DRM_DEBUG("returning NULL!\n");
return NULL;
}
void r128_freelist_reset(drm_device_t * dev)
{
drm_device_dma_t *dma = dev->dma;
int i;
for (i = 0; i < dma->buf_count; i++) {
drm_buf_t *buf = dma->buflist[i];
drm_r128_buf_priv_t *buf_priv = buf->dev_private;
buf_priv->age = 0;
}
}
/* ================================================================
* CCE command submission
*/
int r128_wait_ring(drm_r128_private_t * dev_priv, int n)
{
drm_r128_ring_buffer_t *ring = &dev_priv->ring;
int i;
for (i = 0; i < dev_priv->usec_timeout; i++) {
r128_update_ring_snapshot(dev_priv);
if (ring->space >= n)
return 0;
DRM_UDELAY(1);
}
/* FIXME: This is being ignored... */
DRM_ERROR("failed!\n");
return DRM_ERR(EBUSY);
}
static int r128_cce_get_buffers(DRMFILE filp, drm_device_t * dev, drm_dma_t * d)
{
int i;
drm_buf_t *buf;
for (i = d->granted_count; i < d->request_count; i++) {
buf = r128_freelist_get(dev);
if (!buf)
return DRM_ERR(EAGAIN);
buf->filp = filp;
if (DRM_COPY_TO_USER(&d->request_indices[i], &buf->idx,
sizeof(buf->idx)))
return DRM_ERR(EFAULT);
if (DRM_COPY_TO_USER(&d->request_sizes[i], &buf->total,
sizeof(buf->total)))
return DRM_ERR(EFAULT);
d->granted_count++;
}
return 0;
}
int r128_cce_buffers(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_device_dma_t *dma = dev->dma;
int ret = 0;
drm_dma_t __user *argp = (void __user *)data;
drm_dma_t d;
LOCK_TEST_WITH_RETURN(dev, filp);
DRM_COPY_FROM_USER_IOCTL(d, argp, sizeof(d));
/* Please don't send us buffers.
*/
if (d.send_count != 0) {
DRM_ERROR("Process %d trying to send %d buffers via drmDMA\n",
DRM_CURRENTPID, d.send_count);
return DRM_ERR(EINVAL);
}
/* We'll send you buffers.
*/
if (d.request_count < 0 || d.request_count > dma->buf_count) {
DRM_ERROR("Process %d trying to get %d buffers (of %d max)\n",
DRM_CURRENTPID, d.request_count, dma->buf_count);
return DRM_ERR(EINVAL);
}
d.granted_count = 0;
if (d.request_count) {
ret = r128_cce_get_buffers(filp, dev, &d);
}
DRM_COPY_TO_USER_IOCTL(argp, d, sizeof(d));
return ret;
}

349
sys/dev/pci/drm/r128_drm.h Normal file
View File

@ -0,0 +1,349 @@
/* r128_drm.h -- Public header for the r128 driver -*- linux-c -*-
* Created: Wed Apr 5 19:24:19 2000 by kevin@precisioninsight.com
*/
/*-
* Copyright 2000 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:
* Gareth Hughes <gareth@valinux.com>
* Kevin E. Martin <martin@valinux.com>
*/
#include <sys/cdefs.h>
/*
__FBSDID("$FreeBSD: src/sys/dev/drm/r128_drm.h,v 1.8 2005/11/28 23:13:53 anholt Exp $");
*/
#ifndef __R128_DRM_H__
#define __R128_DRM_H__
/* WARNING: If you change any of these defines, make sure to change the
* defines in the X server file (r128_sarea.h)
*/
#ifndef __R128_SAREA_DEFINES__
#define __R128_SAREA_DEFINES__
/* What needs to be changed for the current vertex buffer?
*/
#define R128_UPLOAD_CONTEXT 0x001
#define R128_UPLOAD_SETUP 0x002
#define R128_UPLOAD_TEX0 0x004
#define R128_UPLOAD_TEX1 0x008
#define R128_UPLOAD_TEX0IMAGES 0x010
#define R128_UPLOAD_TEX1IMAGES 0x020
#define R128_UPLOAD_CORE 0x040
#define R128_UPLOAD_MASKS 0x080
#define R128_UPLOAD_WINDOW 0x100
#define R128_UPLOAD_CLIPRECTS 0x200 /* handled client-side */
#define R128_REQUIRE_QUIESCENCE 0x400
#define R128_UPLOAD_ALL 0x7ff
#define R128_FRONT 0x1
#define R128_BACK 0x2
#define R128_DEPTH 0x4
/* Primitive types
*/
#define R128_POINTS 0x1
#define R128_LINES 0x2
#define R128_LINE_STRIP 0x3
#define R128_TRIANGLES 0x4
#define R128_TRIANGLE_FAN 0x5
#define R128_TRIANGLE_STRIP 0x6
/* Vertex/indirect buffer size
*/
#define R128_BUFFER_SIZE 16384
/* Byte offsets for indirect buffer data
*/
#define R128_INDEX_PRIM_OFFSET 20
#define R128_HOSTDATA_BLIT_OFFSET 32
/* Keep these small for testing.
*/
#define R128_NR_SAREA_CLIPRECTS 12
/* There are 2 heaps (local/AGP). Each region within a heap is a
* minimum of 64k, and there are at most 64 of them per heap.
*/
#define R128_LOCAL_TEX_HEAP 0
#define R128_AGP_TEX_HEAP 1
#define R128_NR_TEX_HEAPS 2
#define R128_NR_TEX_REGIONS 64
#define R128_LOG_TEX_GRANULARITY 16
#define R128_NR_CONTEXT_REGS 12
#define R128_MAX_TEXTURE_LEVELS 11
#define R128_MAX_TEXTURE_UNITS 2
#endif /* __R128_SAREA_DEFINES__ */
typedef struct {
/* Context state - can be written in one large chunk */
unsigned int dst_pitch_offset_c;
unsigned int dp_gui_master_cntl_c;
unsigned int sc_top_left_c;
unsigned int sc_bottom_right_c;
unsigned int z_offset_c;
unsigned int z_pitch_c;
unsigned int z_sten_cntl_c;
unsigned int tex_cntl_c;
unsigned int misc_3d_state_cntl_reg;
unsigned int texture_clr_cmp_clr_c;
unsigned int texture_clr_cmp_msk_c;
unsigned int fog_color_c;
/* Texture state */
unsigned int tex_size_pitch_c;
unsigned int constant_color_c;
/* Setup state */
unsigned int pm4_vc_fpu_setup;
unsigned int setup_cntl;
/* Mask state */
unsigned int dp_write_mask;
unsigned int sten_ref_mask_c;
unsigned int plane_3d_mask_c;
/* Window state */
unsigned int window_xy_offset;
/* Core state */
unsigned int scale_3d_cntl;
} drm_r128_context_regs_t;
/* Setup registers for each texture unit
*/
typedef struct {
unsigned int tex_cntl;
unsigned int tex_combine_cntl;
unsigned int tex_size_pitch;
unsigned int tex_offset[R128_MAX_TEXTURE_LEVELS];
unsigned int tex_border_color;
} drm_r128_texture_regs_t;
typedef struct drm_r128_sarea {
/* The channel for communication of state information to the kernel
* on firing a vertex buffer.
*/
drm_r128_context_regs_t context_state;
drm_r128_texture_regs_t tex_state[R128_MAX_TEXTURE_UNITS];
unsigned int dirty;
unsigned int vertsize;
unsigned int vc_format;
/* The current cliprects, or a subset thereof.
*/
drm_clip_rect_t boxes[R128_NR_SAREA_CLIPRECTS];
unsigned int nbox;
/* Counters for client-side throttling of rendering clients.
*/
unsigned int last_frame;
unsigned int last_dispatch;
drm_tex_region_t tex_list[R128_NR_TEX_HEAPS][R128_NR_TEX_REGIONS + 1];
unsigned int tex_age[R128_NR_TEX_HEAPS];
int ctx_owner;
int pfAllowPageFlip; /* number of 3d windows (0,1,2 or more) */
int pfCurrentPage; /* which buffer is being displayed? */
} drm_r128_sarea_t;
/* WARNING: If you change any of these defines, make sure to change the
* defines in the Xserver file (xf86drmR128.h)
*/
/* Rage 128 specific ioctls
* The device specific ioctl range is 0x40 to 0x79.
*/
#define DRM_R128_INIT 0x00
#define DRM_R128_CCE_START 0x01
#define DRM_R128_CCE_STOP 0x02
#define DRM_R128_CCE_RESET 0x03
#define DRM_R128_CCE_IDLE 0x04
/* 0x05 not used */
#define DRM_R128_RESET 0x06
#define DRM_R128_SWAP 0x07
#define DRM_R128_CLEAR 0x08
#define DRM_R128_VERTEX 0x09
#define DRM_R128_INDICES 0x0a
#define DRM_R128_BLIT 0x0b
#define DRM_R128_DEPTH 0x0c
#define DRM_R128_STIPPLE 0x0d
/* 0x0e not used */
#define DRM_R128_INDIRECT 0x0f
#define DRM_R128_FULLSCREEN 0x10
#define DRM_R128_CLEAR2 0x11
#define DRM_R128_GETPARAM 0x12
#define DRM_R128_FLIP 0x13
#define DRM_IOCTL_R128_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_R128_INIT, drm_r128_init_t)
#define DRM_IOCTL_R128_CCE_START DRM_IO( DRM_COMMAND_BASE + DRM_R128_CCE_START)
#define DRM_IOCTL_R128_CCE_STOP DRM_IOW( DRM_COMMAND_BASE + DRM_R128_CCE_STOP, drm_r128_cce_stop_t)
#define DRM_IOCTL_R128_CCE_RESET DRM_IO( DRM_COMMAND_BASE + DRM_R128_CCE_RESET)
#define DRM_IOCTL_R128_CCE_IDLE DRM_IO( DRM_COMMAND_BASE + DRM_R128_CCE_IDLE)
/* 0x05 not used */
#define DRM_IOCTL_R128_RESET DRM_IO( DRM_COMMAND_BASE + DRM_R128_RESET)
#define DRM_IOCTL_R128_SWAP DRM_IO( DRM_COMMAND_BASE + DRM_R128_SWAP)
#define DRM_IOCTL_R128_CLEAR DRM_IOW( DRM_COMMAND_BASE + DRM_R128_CLEAR, drm_r128_clear_t)
#define DRM_IOCTL_R128_VERTEX DRM_IOW( DRM_COMMAND_BASE + DRM_R128_VERTEX, drm_r128_vertex_t)
#define DRM_IOCTL_R128_INDICES DRM_IOW( DRM_COMMAND_BASE + DRM_R128_INDICES, drm_r128_indices_t)
#define DRM_IOCTL_R128_BLIT DRM_IOW( DRM_COMMAND_BASE + DRM_R128_BLIT, drm_r128_blit_t)
#define DRM_IOCTL_R128_DEPTH DRM_IOW( DRM_COMMAND_BASE + DRM_R128_DEPTH, drm_r128_depth_t)
#define DRM_IOCTL_R128_STIPPLE DRM_IOW( DRM_COMMAND_BASE + DRM_R128_STIPPLE, drm_r128_stipple_t)
/* 0x0e not used */
#define DRM_IOCTL_R128_INDIRECT DRM_IOWR(DRM_COMMAND_BASE + DRM_R128_INDIRECT, drm_r128_indirect_t)
#define DRM_IOCTL_R128_FULLSCREEN DRM_IOW( DRM_COMMAND_BASE + DRM_R128_FULLSCREEN, drm_r128_fullscreen_t)
#define DRM_IOCTL_R128_CLEAR2 DRM_IOW( DRM_COMMAND_BASE + DRM_R128_CLEAR2, drm_r128_clear2_t)
#define DRM_IOCTL_R128_GETPARAM DRM_IOWR( DRM_COMMAND_BASE + DRM_R128_GETPARAM, drm_r128_getparam_t)
#define DRM_IOCTL_R128_FLIP DRM_IO( DRM_COMMAND_BASE + DRM_R128_FLIP)
typedef struct drm_r128_init {
enum {
R128_INIT_CCE = 0x01,
R128_CLEANUP_CCE = 0x02
} func;
#if CONFIG_XFREE86_VERSION < XFREE86_VERSION(4,1,0,0)
int sarea_priv_offset;
#else
unsigned long sarea_priv_offset;
#endif
int is_pci;
int cce_mode;
int cce_secure;
int ring_size;
int usec_timeout;
unsigned int fb_bpp;
unsigned int front_offset, front_pitch;
unsigned int back_offset, back_pitch;
unsigned int depth_bpp;
unsigned int depth_offset, depth_pitch;
unsigned int span_offset;
#if CONFIG_XFREE86_VERSION < XFREE86_VERSION(4,1,0,0)
unsigned int fb_offset;
unsigned int mmio_offset;
unsigned int ring_offset;
unsigned int ring_rptr_offset;
unsigned int buffers_offset;
unsigned int agp_textures_offset;
#else
unsigned long fb_offset;
unsigned long mmio_offset;
unsigned long ring_offset;
unsigned long ring_rptr_offset;
unsigned long buffers_offset;
unsigned long agp_textures_offset;
#endif
} drm_r128_init_t;
typedef struct drm_r128_cce_stop {
int flush;
int idle;
} drm_r128_cce_stop_t;
typedef struct drm_r128_clear {
unsigned int flags;
#if CONFIG_XFREE86_VERSION < XFREE86_VERSION(4,1,0,0)
int x, y, w, h;
#endif
unsigned int clear_color;
unsigned int clear_depth;
#if CONFIG_XFREE86_VERSION >= XFREE86_VERSION(4,1,0,0)
unsigned int color_mask;
unsigned int depth_mask;
#endif
} drm_r128_clear_t;
typedef struct drm_r128_vertex {
int prim;
int idx; /* Index of vertex buffer */
int count; /* Number of vertices in buffer */
int discard; /* Client finished with buffer? */
} drm_r128_vertex_t;
typedef struct drm_r128_indices {
int prim;
int idx;
int start;
int end;
int discard; /* Client finished with buffer? */
} drm_r128_indices_t;
typedef struct drm_r128_blit {
int idx;
int pitch;
int offset;
int format;
unsigned short x, y;
unsigned short width, height;
} drm_r128_blit_t;
typedef struct drm_r128_depth {
enum {
R128_WRITE_SPAN = 0x01,
R128_WRITE_PIXELS = 0x02,
R128_READ_SPAN = 0x03,
R128_READ_PIXELS = 0x04
} func;
int n;
int __user *x;
int __user *y;
unsigned int __user *buffer;
unsigned char __user *mask;
} drm_r128_depth_t;
typedef struct drm_r128_stipple {
unsigned int __user *mask;
} drm_r128_stipple_t;
typedef struct drm_r128_indirect {
int idx;
int start;
int end;
int discard;
} drm_r128_indirect_t;
typedef struct drm_r128_fullscreen {
enum {
R128_INIT_FULLSCREEN = 0x01,
R128_CLEANUP_FULLSCREEN = 0x02
} func;
} drm_r128_fullscreen_t;
/* 2.3: An ioctl to get parameters that aren't available to the 3d
* client any other way.
*/
#define R128_PARAM_IRQ_NR 1
typedef struct drm_r128_getparam {
int param;
void __user *value;
} drm_r128_getparam_t;
#endif

143
sys/dev/pci/drm/r128_drv.c Normal file
View File

@ -0,0 +1,143 @@
/* r128_drv.c -- ATI Rage 128 driver -*- linux-c -*-
* Created: Mon Dec 13 09:47:27 1999 by faith@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
* 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 <sys/cdefs.h>
/*
__FBSDID("$FreeBSD: src/sys/dev/drm/r128_drv.c,v 1.11 2005/12/20 22:44:36 jhb Exp $");
*/
#include "drmP.h"
#include "drm.h"
#include "r128_drm.h"
#include "r128_drv.h"
#include "drm_pciids.h"
/* drv_PCI_IDs comes from drm_pciids.h, generated from drm_pciids.txt. */
static drm_pci_id_list_t r128_pciidlist[] = {
r128_PCI_IDS
};
static void r128_configure(drm_device_t *dev)
{
dev->driver.buf_priv_size = sizeof(drm_r128_buf_priv_t);
dev->driver.preclose = r128_driver_preclose;
dev->driver.lastclose = r128_driver_lastclose;
dev->driver.vblank_wait = r128_driver_vblank_wait;
dev->driver.irq_preinstall = r128_driver_irq_preinstall;
dev->driver.irq_postinstall = r128_driver_irq_postinstall;
dev->driver.irq_uninstall = r128_driver_irq_uninstall;
dev->driver.irq_handler = r128_driver_irq_handler;
dev->driver.dma_ioctl = r128_cce_buffers;
dev->driver.ioctls = r128_ioctls;
dev->driver.max_ioctl = r128_max_ioctl;
dev->driver.name = DRIVER_NAME;
dev->driver.desc = DRIVER_DESC;
dev->driver.date = DRIVER_DATE;
dev->driver.major = DRIVER_MAJOR;
dev->driver.minor = DRIVER_MINOR;
dev->driver.patchlevel = DRIVER_PATCHLEVEL;
dev->driver.use_agp = 1;
dev->driver.use_mtrr = 1;
dev->driver.use_pci_dma = 1;
dev->driver.use_sg = 1;
dev->driver.use_dma = 1;
dev->driver.use_irq = 1;
dev->driver.use_vbl_irq = 1;
}
#ifdef __FreeBSD__
static int
r128_probe(device_t dev)
{
return drm_probe(dev, r128_pciidlist);
}
static int
r128_attach(device_t nbdev)
{
drm_device_t *dev = device_get_softc(nbdev);
bzero(dev, sizeof(drm_device_t));
r128_configure(dev);
return drm_attach(nbdev, r128_pciidlist);
}
static device_method_t r128_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, r128_probe),
DEVMETHOD(device_attach, r128_attach),
DEVMETHOD(device_detach, drm_detach),
{ 0, 0 }
};
static driver_t r128_driver = {
"drm",
r128_methods,
sizeof(drm_device_t)
};
extern devclass_t drm_devclass;
#if __FreeBSD_version >= 700010
DRIVER_MODULE(r128, vgapci, r128_driver, drm_devclass, 0, 0);
#else
DRIVER_MODULE(r128, pci, r128_driver, drm_devclass, 0, 0);
#endif
MODULE_DEPEND(r128, drm, 1, 1, 1);
#elif defined(__NetBSD__) || defined(__OpenBSD__)
static int
r128drm_probe(struct device *parent, struct cfdata *match, void *aux)
{
struct pci_attach_args *pa = aux;
return drm_probe(pa, r128_pciidlist);
}
static void
r128drm_attach(struct device *parent, struct device *self, void *aux)
{
struct pci_attach_args *pa = aux;
drm_device_t *dev = (drm_device_t *)self;
r128_configure(dev);
return drm_attach(self, pa, r128_pciidlist);
}
CFATTACH_DECL(r128drm, sizeof(drm_device_t), r128drm_probe, r128drm_attach,
drm_detach, drm_activate);
#endif

525
sys/dev/pci/drm/r128_drv.h Normal file
View File

@ -0,0 +1,525 @@
/* r128_drv.h -- Private header for r128 driver -*- linux-c -*-
* Created: Mon Dec 13 09:51:11 1999 by faith@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>
* Kevin E. Martin <martin@valinux.com>
* Gareth Hughes <gareth@valinux.com>
* Michel D<EFBFBD>zer <daenzerm@student.ethz.ch>
*/
#include <sys/cdefs.h>
/*
__FBSDID("$FreeBSD: src/sys/dev/drm/r128_drv.h,v 1.11 2005/11/28 23:13:53 anholt Exp $");
*/
#ifndef __R128_DRV_H__
#define __R128_DRV_H__
/* General customization:
*/
#define DRIVER_AUTHOR "Gareth Hughes, VA Linux Systems Inc."
#define DRIVER_NAME "r128"
#define DRIVER_DESC "ATI Rage 128"
#define DRIVER_DATE "20030725"
/* Interface history:
*
* ?? - ??
* 2.4 - Add support for ycbcr textures (no new ioctls)
* 2.5 - Add FLIP ioctl, disable FULLSCREEN.
*/
#define DRIVER_MAJOR 2
#define DRIVER_MINOR 5
#define DRIVER_PATCHLEVEL 0
#define GET_RING_HEAD(dev_priv) R128_READ( R128_PM4_BUFFER_DL_RPTR )
typedef struct drm_r128_freelist {
unsigned int age;
drm_buf_t *buf;
struct drm_r128_freelist *next;
struct drm_r128_freelist *prev;
} drm_r128_freelist_t;
typedef struct drm_r128_ring_buffer {
u32 *start;
u32 *end;
int size;
int size_l2qw;
u32 tail;
u32 tail_mask;
int space;
int high_mark;
} drm_r128_ring_buffer_t;
typedef struct drm_r128_private {
drm_r128_ring_buffer_t ring;
drm_r128_sarea_t *sarea_priv;
int cce_mode;
int cce_fifo_size;
int cce_running;
drm_r128_freelist_t *head;
drm_r128_freelist_t *tail;
int usec_timeout;
int is_pci;
unsigned long cce_buffers_offset;
atomic_t idle_count;
int page_flipping;
int current_page;
u32 crtc_offset;
u32 crtc_offset_cntl;
u32 color_fmt;
unsigned int front_offset;
unsigned int front_pitch;
unsigned int back_offset;
unsigned int back_pitch;
u32 depth_fmt;
unsigned int depth_offset;
unsigned int depth_pitch;
unsigned int span_offset;
u32 front_pitch_offset_c;
u32 back_pitch_offset_c;
u32 depth_pitch_offset_c;
u32 span_pitch_offset_c;
drm_local_map_t *sarea;
drm_local_map_t *mmio;
drm_local_map_t *cce_ring;
drm_local_map_t *ring_rptr;
drm_local_map_t *agp_textures;
drm_ati_pcigart_info gart_info;
} drm_r128_private_t;
typedef struct drm_r128_buf_priv {
u32 age;
int prim;
int discard;
int dispatched;
drm_r128_freelist_t *list_entry;
} drm_r128_buf_priv_t;
extern drm_ioctl_desc_t r128_ioctls[];
extern int r128_max_ioctl;
/* r128_cce.c */
extern int r128_cce_init(DRM_IOCTL_ARGS);
extern int r128_cce_start(DRM_IOCTL_ARGS);
extern int r128_cce_stop(DRM_IOCTL_ARGS);
extern int r128_cce_reset(DRM_IOCTL_ARGS);
extern int r128_cce_idle(DRM_IOCTL_ARGS);
extern int r128_engine_reset(DRM_IOCTL_ARGS);
extern int r128_fullscreen(DRM_IOCTL_ARGS);
extern int r128_cce_buffers(DRM_IOCTL_ARGS);
extern void r128_freelist_reset(drm_device_t * dev);
extern int r128_wait_ring(drm_r128_private_t * dev_priv, int n);
extern int r128_do_cce_idle(drm_r128_private_t * dev_priv);
extern int r128_do_cleanup_cce(drm_device_t * dev);
extern int r128_driver_vblank_wait(drm_device_t * dev, unsigned int *sequence);
extern irqreturn_t r128_driver_irq_handler(DRM_IRQ_ARGS);
extern void r128_driver_irq_preinstall(drm_device_t * dev);
extern void r128_driver_irq_postinstall(drm_device_t * dev);
extern void r128_driver_irq_uninstall(drm_device_t * dev);
extern void r128_driver_lastclose(drm_device_t * dev);
extern void r128_driver_preclose(drm_device_t * dev, DRMFILE filp);
extern long r128_compat_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg);
/* Register definitions, register access macros and drmAddMap constants
* for Rage 128 kernel driver.
*/
#define R128_AUX_SC_CNTL 0x1660
# define R128_AUX1_SC_EN (1 << 0)
# define R128_AUX1_SC_MODE_OR (0 << 1)
# define R128_AUX1_SC_MODE_NAND (1 << 1)
# define R128_AUX2_SC_EN (1 << 2)
# define R128_AUX2_SC_MODE_OR (0 << 3)
# define R128_AUX2_SC_MODE_NAND (1 << 3)
# define R128_AUX3_SC_EN (1 << 4)
# define R128_AUX3_SC_MODE_OR (0 << 5)
# define R128_AUX3_SC_MODE_NAND (1 << 5)
#define R128_AUX1_SC_LEFT 0x1664
#define R128_AUX1_SC_RIGHT 0x1668
#define R128_AUX1_SC_TOP 0x166c
#define R128_AUX1_SC_BOTTOM 0x1670
#define R128_AUX2_SC_LEFT 0x1674
#define R128_AUX2_SC_RIGHT 0x1678
#define R128_AUX2_SC_TOP 0x167c
#define R128_AUX2_SC_BOTTOM 0x1680
#define R128_AUX3_SC_LEFT 0x1684
#define R128_AUX3_SC_RIGHT 0x1688
#define R128_AUX3_SC_TOP 0x168c
#define R128_AUX3_SC_BOTTOM 0x1690
#define R128_BRUSH_DATA0 0x1480
#define R128_BUS_CNTL 0x0030
# define R128_BUS_MASTER_DIS (1 << 6)
#define R128_CLOCK_CNTL_INDEX 0x0008
#define R128_CLOCK_CNTL_DATA 0x000c
# define R128_PLL_WR_EN (1 << 7)
#define R128_CONSTANT_COLOR_C 0x1d34
#define R128_CRTC_OFFSET 0x0224
#define R128_CRTC_OFFSET_CNTL 0x0228
# define R128_CRTC_OFFSET_FLIP_CNTL (1 << 16)
#define R128_DP_GUI_MASTER_CNTL 0x146c
# define R128_GMC_SRC_PITCH_OFFSET_CNTL (1 << 0)
# define R128_GMC_DST_PITCH_OFFSET_CNTL (1 << 1)
# define R128_GMC_BRUSH_SOLID_COLOR (13 << 4)
# define R128_GMC_BRUSH_NONE (15 << 4)
# define R128_GMC_DST_16BPP (4 << 8)
# define R128_GMC_DST_24BPP (5 << 8)
# define R128_GMC_DST_32BPP (6 << 8)
# define R128_GMC_DST_DATATYPE_SHIFT 8
# define R128_GMC_SRC_DATATYPE_COLOR (3 << 12)
# define R128_DP_SRC_SOURCE_MEMORY (2 << 24)
# define R128_DP_SRC_SOURCE_HOST_DATA (3 << 24)
# define R128_GMC_CLR_CMP_CNTL_DIS (1 << 28)
# define R128_GMC_AUX_CLIP_DIS (1 << 29)
# define R128_GMC_WR_MSK_DIS (1 << 30)
# define R128_ROP3_S 0x00cc0000
# define R128_ROP3_P 0x00f00000
#define R128_DP_WRITE_MASK 0x16cc
#define R128_DST_PITCH_OFFSET_C 0x1c80
# define R128_DST_TILE (1 << 31)
#define R128_GEN_INT_CNTL 0x0040
# define R128_CRTC_VBLANK_INT_EN (1 << 0)
#define R128_GEN_INT_STATUS 0x0044
# define R128_CRTC_VBLANK_INT (1 << 0)
# define R128_CRTC_VBLANK_INT_AK (1 << 0)
#define R128_GEN_RESET_CNTL 0x00f0
# define R128_SOFT_RESET_GUI (1 << 0)
#define R128_GUI_SCRATCH_REG0 0x15e0
#define R128_GUI_SCRATCH_REG1 0x15e4
#define R128_GUI_SCRATCH_REG2 0x15e8
#define R128_GUI_SCRATCH_REG3 0x15ec
#define R128_GUI_SCRATCH_REG4 0x15f0
#define R128_GUI_SCRATCH_REG5 0x15f4
#define R128_GUI_STAT 0x1740
# define R128_GUI_FIFOCNT_MASK 0x0fff
# define R128_GUI_ACTIVE (1 << 31)
#define R128_MCLK_CNTL 0x000f
# define R128_FORCE_GCP (1 << 16)
# define R128_FORCE_PIPE3D_CP (1 << 17)
# define R128_FORCE_RCP (1 << 18)
#define R128_PC_GUI_CTLSTAT 0x1748
#define R128_PC_NGUI_CTLSTAT 0x0184
# define R128_PC_FLUSH_GUI (3 << 0)
# define R128_PC_RI_GUI (1 << 2)
# define R128_PC_FLUSH_ALL 0x00ff
# define R128_PC_BUSY (1 << 31)
#define R128_PCI_GART_PAGE 0x017c
#define R128_PRIM_TEX_CNTL_C 0x1cb0
#define R128_SCALE_3D_CNTL 0x1a00
#define R128_SEC_TEX_CNTL_C 0x1d00
#define R128_SEC_TEXTURE_BORDER_COLOR_C 0x1d3c
#define R128_SETUP_CNTL 0x1bc4
#define R128_STEN_REF_MASK_C 0x1d40
#define R128_TEX_CNTL_C 0x1c9c
# define R128_TEX_CACHE_FLUSH (1 << 23)
#define R128_WAIT_UNTIL 0x1720
# define R128_EVENT_CRTC_OFFSET (1 << 0)
#define R128_WINDOW_XY_OFFSET 0x1bcc
/* CCE registers
*/
#define R128_PM4_BUFFER_OFFSET 0x0700
#define R128_PM4_BUFFER_CNTL 0x0704
# define R128_PM4_MASK (15 << 28)
# define R128_PM4_NONPM4 (0 << 28)
# define R128_PM4_192PIO (1 << 28)
# define R128_PM4_192BM (2 << 28)
# define R128_PM4_128PIO_64INDBM (3 << 28)
# define R128_PM4_128BM_64INDBM (4 << 28)
# define R128_PM4_64PIO_128INDBM (5 << 28)
# define R128_PM4_64BM_128INDBM (6 << 28)
# define R128_PM4_64PIO_64VCBM_64INDBM (7 << 28)
# define R128_PM4_64BM_64VCBM_64INDBM (8 << 28)
# define R128_PM4_64PIO_64VCPIO_64INDPIO (15 << 28)
# define R128_PM4_BUFFER_CNTL_NOUPDATE (1 << 27)
#define R128_PM4_BUFFER_WM_CNTL 0x0708
# define R128_WMA_SHIFT 0
# define R128_WMB_SHIFT 8
# define R128_WMC_SHIFT 16
# define R128_WB_WM_SHIFT 24
#define R128_PM4_BUFFER_DL_RPTR_ADDR 0x070c
#define R128_PM4_BUFFER_DL_RPTR 0x0710
#define R128_PM4_BUFFER_DL_WPTR 0x0714
# define R128_PM4_BUFFER_DL_DONE (1 << 31)
#define R128_PM4_VC_FPU_SETUP 0x071c
#define R128_PM4_IW_INDOFF 0x0738
#define R128_PM4_IW_INDSIZE 0x073c
#define R128_PM4_STAT 0x07b8
# define R128_PM4_FIFOCNT_MASK 0x0fff
# define R128_PM4_BUSY (1 << 16)
# define R128_PM4_GUI_ACTIVE (1 << 31)
#define R128_PM4_MICROCODE_ADDR 0x07d4
#define R128_PM4_MICROCODE_RADDR 0x07d8
#define R128_PM4_MICROCODE_DATAH 0x07dc
#define R128_PM4_MICROCODE_DATAL 0x07e0
#define R128_PM4_BUFFER_ADDR 0x07f0
#define R128_PM4_MICRO_CNTL 0x07fc
# define R128_PM4_MICRO_FREERUN (1 << 30)
#define R128_PM4_FIFO_DATA_EVEN 0x1000
#define R128_PM4_FIFO_DATA_ODD 0x1004
/* CCE command packets
*/
#define R128_CCE_PACKET0 0x00000000
#define R128_CCE_PACKET1 0x40000000
#define R128_CCE_PACKET2 0x80000000
#define R128_CCE_PACKET3 0xC0000000
# define R128_CNTL_HOSTDATA_BLT 0x00009400
# define R128_CNTL_PAINT_MULTI 0x00009A00
# define R128_CNTL_BITBLT_MULTI 0x00009B00
# define R128_3D_RNDR_GEN_INDX_PRIM 0x00002300
#define R128_CCE_PACKET_MASK 0xC0000000
#define R128_CCE_PACKET_COUNT_MASK 0x3fff0000
#define R128_CCE_PACKET0_REG_MASK 0x000007ff
#define R128_CCE_PACKET1_REG0_MASK 0x000007ff
#define R128_CCE_PACKET1_REG1_MASK 0x003ff800
#define R128_CCE_VC_CNTL_PRIM_TYPE_NONE 0x00000000
#define R128_CCE_VC_CNTL_PRIM_TYPE_POINT 0x00000001
#define R128_CCE_VC_CNTL_PRIM_TYPE_LINE 0x00000002
#define R128_CCE_VC_CNTL_PRIM_TYPE_POLY_LINE 0x00000003
#define R128_CCE_VC_CNTL_PRIM_TYPE_TRI_LIST 0x00000004
#define R128_CCE_VC_CNTL_PRIM_TYPE_TRI_FAN 0x00000005
#define R128_CCE_VC_CNTL_PRIM_TYPE_TRI_STRIP 0x00000006
#define R128_CCE_VC_CNTL_PRIM_TYPE_TRI_TYPE2 0x00000007
#define R128_CCE_VC_CNTL_PRIM_WALK_IND 0x00000010
#define R128_CCE_VC_CNTL_PRIM_WALK_LIST 0x00000020
#define R128_CCE_VC_CNTL_PRIM_WALK_RING 0x00000030
#define R128_CCE_VC_CNTL_NUM_SHIFT 16
#define R128_DATATYPE_VQ 0
#define R128_DATATYPE_CI4 1
#define R128_DATATYPE_CI8 2
#define R128_DATATYPE_ARGB1555 3
#define R128_DATATYPE_RGB565 4
#define R128_DATATYPE_RGB888 5
#define R128_DATATYPE_ARGB8888 6
#define R128_DATATYPE_RGB332 7
#define R128_DATATYPE_Y8 8
#define R128_DATATYPE_RGB8 9
#define R128_DATATYPE_CI16 10
#define R128_DATATYPE_YVYU422 11
#define R128_DATATYPE_VYUY422 12
#define R128_DATATYPE_AYUV444 14
#define R128_DATATYPE_ARGB4444 15
/* Constants */
#define R128_AGP_OFFSET 0x02000000
#define R128_WATERMARK_L 16
#define R128_WATERMARK_M 8
#define R128_WATERMARK_N 8
#define R128_WATERMARK_K 128
#define R128_MAX_USEC_TIMEOUT 100000 /* 100 ms */
#define R128_LAST_FRAME_REG R128_GUI_SCRATCH_REG0
#define R128_LAST_DISPATCH_REG R128_GUI_SCRATCH_REG1
#define R128_MAX_VB_AGE 0x7fffffff
#define R128_MAX_VB_VERTS (0xffff)
#define R128_RING_HIGH_MARK 128
#define R128_PERFORMANCE_BOXES 0
#define R128_READ(reg) DRM_READ32( dev_priv->mmio, (reg) )
#define R128_WRITE(reg,val) DRM_WRITE32( dev_priv->mmio, (reg), (val) )
#define R128_READ8(reg) DRM_READ8( dev_priv->mmio, (reg) )
#define R128_WRITE8(reg,val) DRM_WRITE8( dev_priv->mmio, (reg), (val) )
#define R128_WRITE_PLL(addr,val) \
do { \
R128_WRITE8(R128_CLOCK_CNTL_INDEX, \
((addr) & 0x1f) | R128_PLL_WR_EN); \
R128_WRITE(R128_CLOCK_CNTL_DATA, (val)); \
} while (0)
#define CCE_PACKET0( reg, n ) (R128_CCE_PACKET0 | \
((n) << 16) | ((reg) >> 2))
#define CCE_PACKET1( reg0, reg1 ) (R128_CCE_PACKET1 | \
(((reg1) >> 2) << 11) | ((reg0) >> 2))
#define CCE_PACKET2() (R128_CCE_PACKET2)
#define CCE_PACKET3( pkt, n ) (R128_CCE_PACKET3 | \
(pkt) | ((n) << 16))
static __inline__ void r128_update_ring_snapshot(drm_r128_private_t * dev_priv)
{
drm_r128_ring_buffer_t *ring = &dev_priv->ring;
ring->space = (GET_RING_HEAD(dev_priv) - ring->tail) * sizeof(u32);
if (ring->space <= 0)
ring->space += ring->size;
}
/* ================================================================
* Misc helper macros
*/
#define RING_SPACE_TEST_WITH_RETURN( dev_priv ) \
do { \
drm_r128_ring_buffer_t *ring = &dev_priv->ring; int i; \
if ( ring->space < ring->high_mark ) { \
for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) { \
r128_update_ring_snapshot( dev_priv ); \
if ( ring->space >= ring->high_mark ) \
goto __ring_space_done; \
DRM_UDELAY(1); \
} \
DRM_ERROR( "ring space check failed!\n" ); \
return DRM_ERR(EBUSY); \
} \
__ring_space_done: \
; \
} while (0)
#define VB_AGE_TEST_WITH_RETURN( dev_priv ) \
do { \
drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv; \
if ( sarea_priv->last_dispatch >= R128_MAX_VB_AGE ) { \
int __ret = r128_do_cce_idle( dev_priv ); \
if ( __ret ) return __ret; \
sarea_priv->last_dispatch = 0; \
r128_freelist_reset( dev ); \
} \
} while (0)
#define R128_WAIT_UNTIL_PAGE_FLIPPED() do { \
OUT_RING( CCE_PACKET0( R128_WAIT_UNTIL, 0 ) ); \
OUT_RING( R128_EVENT_CRTC_OFFSET ); \
} while (0)
/* ================================================================
* Ring control
*/
#define R128_VERBOSE 0
#define RING_LOCALS \
int write, _nr; unsigned int tail_mask; volatile u32 *ring;
#define BEGIN_RING( n ) do { \
if ( R128_VERBOSE ) { \
DRM_INFO( "BEGIN_RING( %d ) in %s\n", \
(n), __FUNCTION__ ); \
} \
if ( dev_priv->ring.space <= (n) * sizeof(u32) ) { \
COMMIT_RING(); \
r128_wait_ring( dev_priv, (n) * sizeof(u32) ); \
} \
_nr = n; dev_priv->ring.space -= (n) * sizeof(u32); \
ring = dev_priv->ring.start; \
write = dev_priv->ring.tail; \
tail_mask = dev_priv->ring.tail_mask; \
} while (0)
/* You can set this to zero if you want. If the card locks up, you'll
* need to keep this set. It works around a bug in early revs of the
* Rage 128 chipset, where the CCE would read 32 dwords past the end of
* the ring buffer before wrapping around.
*/
#define R128_BROKEN_CCE 1
#define ADVANCE_RING() do { \
if ( R128_VERBOSE ) { \
DRM_INFO( "ADVANCE_RING() wr=0x%06x tail=0x%06x\n", \
write, dev_priv->ring.tail ); \
} \
if ( R128_BROKEN_CCE && write < 32 ) { \
memcpy( dev_priv->ring.end, \
dev_priv->ring.start, \
write * sizeof(u32) ); \
} \
if (((dev_priv->ring.tail + _nr) & tail_mask) != write) { \
DRM_ERROR( \
"ADVANCE_RING(): mismatch: nr: %x write: %x line: %d\n", \
((dev_priv->ring.tail + _nr) & tail_mask), \
write, __LINE__); \
} else \
dev_priv->ring.tail = write; \
} while (0)
#define COMMIT_RING() do { \
if ( R128_VERBOSE ) { \
DRM_INFO( "COMMIT_RING() tail=0x%06x\n", \
dev_priv->ring.tail ); \
} \
DRM_MEMORYBARRIER(); \
R128_WRITE( R128_PM4_BUFFER_DL_WPTR, dev_priv->ring.tail ); \
R128_READ( R128_PM4_BUFFER_DL_WPTR ); \
} while (0)
#define OUT_RING( x ) do { \
if ( R128_VERBOSE ) { \
DRM_INFO( " OUT_RING( 0x%08x ) at 0x%x\n", \
(unsigned int)(x), write ); \
} \
ring[write++] = cpu_to_le32( x ); \
write &= tail_mask; \
} while (0)
#endif /* __R128_DRV_H__ */

107
sys/dev/pci/drm/r128_irq.c Normal file
View File

@ -0,0 +1,107 @@
/* r128_irq.c -- IRQ handling for radeon -*- linux-c -*-
*/
/*-
* Copyright (C) The Weather Channel, Inc. 2002. All Rights Reserved.
*
* The Weather Channel (TM) funded Tungsten Graphics to develop the
* initial release of the Radeon 8500 driver under the XFree86 license.
* This notice must be preserved.
*
* 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:
* Keith Whitwell <keith@tungstengraphics.com>
* Eric Anholt <anholt@FreeBSD.org>
*/
#include <sys/cdefs.h>
/*
__FBSDID("$FreeBSD: src/sys/dev/drm/r128_irq.c,v 1.6 2005/11/28 23:13:53 anholt Exp $");
*/
#include "drmP.h"
#include "drm.h"
#include "r128_drm.h"
#include "r128_drv.h"
irqreturn_t r128_driver_irq_handler(DRM_IRQ_ARGS)
{
drm_device_t *dev = (drm_device_t *) arg;
drm_r128_private_t *dev_priv = (drm_r128_private_t *) dev->dev_private;
int status;
status = R128_READ(R128_GEN_INT_STATUS);
/* VBLANK interrupt */
if (status & R128_CRTC_VBLANK_INT) {
R128_WRITE(R128_GEN_INT_STATUS, R128_CRTC_VBLANK_INT_AK);
atomic_inc(&dev->vbl_received);
DRM_WAKEUP(&dev->vbl_queue);
drm_vbl_send_signals(dev);
return IRQ_HANDLED;
}
return IRQ_NONE;
}
int r128_driver_vblank_wait(drm_device_t * dev, unsigned int *sequence)
{
unsigned int cur_vblank;
int ret = 0;
/* Assume that the user has missed the current sequence number
* by about a day rather than she wants to wait for years
* using vertical blanks...
*/
DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
(((cur_vblank = atomic_read(&dev->vbl_received))
- *sequence) <= (1 << 23)));
*sequence = cur_vblank;
return ret;
}
void r128_driver_irq_preinstall(drm_device_t * dev)
{
drm_r128_private_t *dev_priv = (drm_r128_private_t *) dev->dev_private;
/* Disable *all* interrupts */
R128_WRITE(R128_GEN_INT_CNTL, 0);
/* Clear vblank bit if it's already high */
R128_WRITE(R128_GEN_INT_STATUS, R128_CRTC_VBLANK_INT_AK);
}
void r128_driver_irq_postinstall(drm_device_t * dev)
{
drm_r128_private_t *dev_priv = (drm_r128_private_t *) dev->dev_private;
/* Turn on VBL interrupt */
R128_WRITE(R128_GEN_INT_CNTL, R128_CRTC_VBLANK_INT_EN);
}
void r128_driver_irq_uninstall(drm_device_t * dev)
{
drm_r128_private_t *dev_priv = (drm_r128_private_t *) dev->dev_private;
if (!dev_priv)
return;
/* Disable *all* interrupts */
R128_WRITE(R128_GEN_INT_CNTL, 0);
}

1718
sys/dev/pci/drm/r128_state.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,947 @@
/* r300_cmdbuf.c -- Command buffer emission for R300 -*- linux-c -*-
*
* Copyright (C) The Weather Channel, Inc. 2002.
* Copyright (C) 2004 Nicolai Haehnle.
* All Rights Reserved.
*
* The Weather Channel (TM) funded Tungsten Graphics to develop the
* initial release of the Radeon 8500 driver under the XFree86 license.
* This notice must be preserved.
*
* 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:
* Nicolai Haehnle <prefect_@gmx.net>
*/
#include <sys/cdefs.h>
/*
__FBSDID("$FreeBSD: src/sys/dev/drm/r300_cmdbuf.c,v 1.5 2006/05/17 06:36:28 anholt Exp $");
*/
#include "drmP.h"
#include "drm.h"
#include "radeon_drm.h"
#include "radeon_drv.h"
#include "r300_reg.h"
#define R300_SIMULTANEOUS_CLIPRECTS 4
/* Values for R300_RE_CLIPRECT_CNTL depending on the number of cliprects
*/
static const int r300_cliprect_cntl[4] = {
0xAAAA,
0xEEEE,
0xFEFE,
0xFFFE
};
/**
* Emit up to R300_SIMULTANEOUS_CLIPRECTS cliprects from the given command
* buffer, starting with index n.
*/
static int r300_emit_cliprects(drm_radeon_private_t *dev_priv,
drm_radeon_kcmd_buffer_t *cmdbuf, int n)
{
drm_clip_rect_t box;
int nr;
int i;
RING_LOCALS;
nr = cmdbuf->nbox - n;
if (nr > R300_SIMULTANEOUS_CLIPRECTS)
nr = R300_SIMULTANEOUS_CLIPRECTS;
DRM_DEBUG("%i cliprects\n", nr);
if (nr) {
BEGIN_RING(6 + nr * 2);
OUT_RING(CP_PACKET0(R300_RE_CLIPRECT_TL_0, nr * 2 - 1));
for (i = 0; i < nr; ++i) {
if (DRM_COPY_FROM_USER_UNCHECKED
(&box, &cmdbuf->boxes[n + i], sizeof(box))) {
DRM_ERROR("copy cliprect faulted\n");
return DRM_ERR(EFAULT);
}
box.x1 =
(box.x1 +
R300_CLIPRECT_OFFSET) & R300_CLIPRECT_MASK;
box.y1 =
(box.y1 +
R300_CLIPRECT_OFFSET) & R300_CLIPRECT_MASK;
box.x2 =
(box.x2 +
R300_CLIPRECT_OFFSET) & R300_CLIPRECT_MASK;
box.y2 =
(box.y2 +
R300_CLIPRECT_OFFSET) & R300_CLIPRECT_MASK;
OUT_RING((box.x1 << R300_CLIPRECT_X_SHIFT) |
(box.y1 << R300_CLIPRECT_Y_SHIFT));
OUT_RING((box.x2 << R300_CLIPRECT_X_SHIFT) |
(box.y2 << R300_CLIPRECT_Y_SHIFT));
}
OUT_RING_REG(R300_RE_CLIPRECT_CNTL, r300_cliprect_cntl[nr - 1]);
/* TODO/SECURITY: Force scissors to a safe value, otherwise the
* client might be able to trample over memory.
* The impact should be very limited, but I'd rather be safe than
* sorry.
*/
OUT_RING(CP_PACKET0(R300_RE_SCISSORS_TL, 1));
OUT_RING(0);
OUT_RING(R300_SCISSORS_X_MASK | R300_SCISSORS_Y_MASK);
ADVANCE_RING();
} else {
/* Why we allow zero cliprect rendering:
* There are some commands in a command buffer that must be submitted
* even when there are no cliprects, e.g. DMA buffer discard
* or state setting (though state setting could be avoided by
* simulating a loss of context).
*
* Now since the cmdbuf interface is so chaotic right now (and is
* bound to remain that way for a bit until things settle down),
* it is basically impossible to filter out the commands that are
* necessary and those that aren't.
*
* So I choose the safe way and don't do any filtering at all;
* instead, I simply set up the engine so that all rendering
* can't produce any fragments.
*/
BEGIN_RING(2);
OUT_RING_REG(R300_RE_CLIPRECT_CNTL, 0);
ADVANCE_RING();
}
return 0;
}
static u8 r300_reg_flags[0x10000 >> 2];
void r300_init_reg_flags(void)
{
int i;
memset(r300_reg_flags, 0, 0x10000 >> 2);
#define ADD_RANGE_MARK(reg, count,mark) \
for(i=((reg)>>2);i<((reg)>>2)+(count);i++)\
r300_reg_flags[i]|=(mark);
#define MARK_SAFE 1
#define MARK_CHECK_OFFSET 2
#define ADD_RANGE(reg, count) ADD_RANGE_MARK(reg, count, MARK_SAFE)
/* these match cmducs() command in r300_driver/r300/r300_cmdbuf.c */
ADD_RANGE(R300_SE_VPORT_XSCALE, 6);
ADD_RANGE(0x2080, 1);
ADD_RANGE(R300_SE_VTE_CNTL, 2);
ADD_RANGE(0x2134, 2);
ADD_RANGE(0x2140, 1);
ADD_RANGE(R300_VAP_INPUT_CNTL_0, 2);
ADD_RANGE(0x21DC, 1);
ADD_RANGE(0x221C, 1);
ADD_RANGE(0x2220, 4);
ADD_RANGE(0x2288, 1);
ADD_RANGE(R300_VAP_OUTPUT_VTX_FMT_0, 2);
ADD_RANGE(R300_VAP_PVS_CNTL_1, 3);
ADD_RANGE(R300_GB_ENABLE, 1);
ADD_RANGE(R300_GB_MSPOS0, 5);
ADD_RANGE(R300_TX_CNTL, 1);
ADD_RANGE(R300_TX_ENABLE, 1);
ADD_RANGE(0x4200, 4);
ADD_RANGE(0x4214, 1);
ADD_RANGE(R300_RE_POINTSIZE, 1);
ADD_RANGE(0x4230, 3);
ADD_RANGE(R300_RE_LINE_CNT, 1);
ADD_RANGE(0x4238, 1);
ADD_RANGE(0x4260, 3);
ADD_RANGE(0x4274, 4);
ADD_RANGE(0x4288, 5);
ADD_RANGE(0x42A0, 1);
ADD_RANGE(R300_RE_ZBIAS_T_FACTOR, 4);
ADD_RANGE(0x42B4, 1);
ADD_RANGE(R300_RE_CULL_CNTL, 1);
ADD_RANGE(0x42C0, 2);
ADD_RANGE(R300_RS_CNTL_0, 2);
ADD_RANGE(R300_RS_INTERP_0, 8);
ADD_RANGE(R300_RS_ROUTE_0, 8);
ADD_RANGE(0x43A4, 2);
ADD_RANGE(0x43E8, 1);
ADD_RANGE(R300_PFS_CNTL_0, 3);
ADD_RANGE(R300_PFS_NODE_0, 4);
ADD_RANGE(R300_PFS_TEXI_0, 64);
ADD_RANGE(0x46A4, 5);
ADD_RANGE(R300_PFS_INSTR0_0, 64);
ADD_RANGE(R300_PFS_INSTR1_0, 64);
ADD_RANGE(R300_PFS_INSTR2_0, 64);
ADD_RANGE(R300_PFS_INSTR3_0, 64);
ADD_RANGE(0x4BC0, 1);
ADD_RANGE(0x4BC8, 3);
ADD_RANGE(R300_PP_ALPHA_TEST, 2);
ADD_RANGE(0x4BD8, 1);
ADD_RANGE(R300_PFS_PARAM_0_X, 64);
ADD_RANGE(0x4E00, 1);
ADD_RANGE(R300_RB3D_CBLEND, 2);
ADD_RANGE(R300_RB3D_COLORMASK, 1);
ADD_RANGE(0x4E10, 3);
ADD_RANGE_MARK(R300_RB3D_COLOROFFSET0, 1, MARK_CHECK_OFFSET); /* check offset */
ADD_RANGE(R300_RB3D_COLORPITCH0, 1);
ADD_RANGE(0x4E50, 9);
ADD_RANGE(0x4E88, 1);
ADD_RANGE(0x4EA0, 2);
ADD_RANGE(R300_RB3D_ZSTENCIL_CNTL_0, 3);
ADD_RANGE(0x4F10, 4);
ADD_RANGE_MARK(R300_RB3D_DEPTHOFFSET, 1, MARK_CHECK_OFFSET); /* check offset */
ADD_RANGE(R300_RB3D_DEPTHPITCH, 1);
ADD_RANGE(0x4F28, 1);
ADD_RANGE(0x4F30, 2);
ADD_RANGE(0x4F44, 1);
ADD_RANGE(0x4F54, 1);
ADD_RANGE(R300_TX_FILTER_0, 16);
ADD_RANGE(R300_TX_FILTER1_0, 16);
ADD_RANGE(R300_TX_SIZE_0, 16);
ADD_RANGE(R300_TX_FORMAT_0, 16);
ADD_RANGE(R300_TX_PITCH_0, 16);
/* Texture offset is dangerous and needs more checking */
ADD_RANGE_MARK(R300_TX_OFFSET_0, 16, MARK_CHECK_OFFSET);
ADD_RANGE(R300_TX_CHROMA_KEY_0, 16);
ADD_RANGE(R300_TX_BORDER_COLOR_0, 16);
/* Sporadic registers used as primitives are emitted */
ADD_RANGE(0x4f18, 1);
ADD_RANGE(R300_RB3D_DSTCACHE_CTLSTAT, 1);
ADD_RANGE(R300_VAP_INPUT_ROUTE_0_0, 8);
ADD_RANGE(R300_VAP_INPUT_ROUTE_1_0, 8);
}
static __inline__ int r300_check_range(unsigned reg, int count)
{
int i;
if (reg & ~0xffff)
return -1;
for (i = (reg >> 2); i < (reg >> 2) + count; i++)
if (r300_reg_flags[i] != MARK_SAFE)
return 1;
return 0;
}
/*
* we expect offsets passed to the framebuffer to be either within video
* memory or within AGP space
*/
static __inline__ int r300_check_offset(drm_radeon_private_t *dev_priv,
u32 offset)
{
/* we realy want to check against end of video aperture
but this value is not being kept.
This code is correct for now (does the same thing as the
code that sets MC_FB_LOCATION) in radeon_cp.c */
if (offset >= dev_priv->fb_location &&
offset < (dev_priv->fb_location + dev_priv->fb_size))
return 0;
if (offset >= dev_priv->gart_vm_start &&
offset < (dev_priv->gart_vm_start + dev_priv->gart_size))
return 0;
return 1;
}
static __inline__ int r300_emit_carefully_checked_packet0(drm_radeon_private_t *
dev_priv,
drm_radeon_kcmd_buffer_t
* cmdbuf,
drm_r300_cmd_header_t
header)
{
int reg;
int sz;
int i;
int values[64];
RING_LOCALS;
sz = header.packet0.count;
reg = (header.packet0.reghi << 8) | header.packet0.reglo;
if ((sz > 64) || (sz < 0)) {
DRM_ERROR
("Cannot emit more than 64 values at a time (reg=%04x sz=%d)\n",
reg, sz);
return DRM_ERR(EINVAL);
}
for (i = 0; i < sz; i++) {
values[i] = ((int *)cmdbuf->buf)[i];
switch (r300_reg_flags[(reg >> 2) + i]) {
case MARK_SAFE:
break;
case MARK_CHECK_OFFSET:
if (r300_check_offset(dev_priv, (u32) values[i])) {
DRM_ERROR
("Offset failed range check (reg=%04x sz=%d)\n",
reg, sz);
return DRM_ERR(EINVAL);
}
break;
default:
DRM_ERROR("Register %04x failed check as flag=%02x\n",
reg + i * 4, r300_reg_flags[(reg >> 2) + i]);
return DRM_ERR(EINVAL);
}
}
BEGIN_RING(1 + sz);
OUT_RING(CP_PACKET0(reg, sz - 1));
OUT_RING_TABLE(values, sz);
ADVANCE_RING();
cmdbuf->buf += sz * 4;
cmdbuf->bufsz -= sz * 4;
return 0;
}
/**
* Emits a packet0 setting arbitrary registers.
* Called by r300_do_cp_cmdbuf.
*
* Note that checks are performed on contents and addresses of the registers
*/
static __inline__ int r300_emit_packet0(drm_radeon_private_t *dev_priv,
drm_radeon_kcmd_buffer_t *cmdbuf,
drm_r300_cmd_header_t header)
{
int reg;
int sz;
RING_LOCALS;
sz = header.packet0.count;
reg = (header.packet0.reghi << 8) | header.packet0.reglo;
if (!sz)
return 0;
if (sz * 4 > cmdbuf->bufsz)
return DRM_ERR(EINVAL);
if (reg + sz * 4 >= 0x10000) {
DRM_ERROR("No such registers in hardware reg=%04x sz=%d\n", reg,
sz);
return DRM_ERR(EINVAL);
}
if (r300_check_range(reg, sz)) {
/* go and check everything */
return r300_emit_carefully_checked_packet0(dev_priv, cmdbuf,
header);
}
/* the rest of the data is safe to emit, whatever the values the user passed */
BEGIN_RING(1 + sz);
OUT_RING(CP_PACKET0(reg, sz - 1));
OUT_RING_TABLE((int *)cmdbuf->buf, sz);
ADVANCE_RING();
cmdbuf->buf += sz * 4;
cmdbuf->bufsz -= sz * 4;
return 0;
}
/**
* Uploads user-supplied vertex program instructions or parameters onto
* the graphics card.
* Called by r300_do_cp_cmdbuf.
*/
static __inline__ int r300_emit_vpu(drm_radeon_private_t *dev_priv,
drm_radeon_kcmd_buffer_t *cmdbuf,
drm_r300_cmd_header_t header)
{
int sz;
int addr;
RING_LOCALS;
sz = header.vpu.count;
addr = (header.vpu.adrhi << 8) | header.vpu.adrlo;
if (!sz)
return 0;
if (sz * 16 > cmdbuf->bufsz)
return DRM_ERR(EINVAL);
BEGIN_RING(5 + sz * 4);
/* Wait for VAP to come to senses.. */
/* there is no need to emit it multiple times, (only once before VAP is programmed,
but this optimization is for later */
OUT_RING_REG(R300_VAP_PVS_WAITIDLE, 0);
OUT_RING_REG(R300_VAP_PVS_UPLOAD_ADDRESS, addr);
OUT_RING(CP_PACKET0_TABLE(R300_VAP_PVS_UPLOAD_DATA, sz * 4 - 1));
OUT_RING_TABLE((int *)cmdbuf->buf, sz * 4);
ADVANCE_RING();
cmdbuf->buf += sz * 16;
cmdbuf->bufsz -= sz * 16;
return 0;
}
/**
* Emit a clear packet from userspace.
* Called by r300_emit_packet3.
*/
static __inline__ int r300_emit_clear(drm_radeon_private_t *dev_priv,
drm_radeon_kcmd_buffer_t *cmdbuf)
{
RING_LOCALS;
if (8 * 4 > cmdbuf->bufsz)
return DRM_ERR(EINVAL);
BEGIN_RING(10);
OUT_RING(CP_PACKET3(R200_3D_DRAW_IMMD_2, 8));
OUT_RING(R300_PRIM_TYPE_POINT | R300_PRIM_WALK_RING |
(1 << R300_PRIM_NUM_VERTICES_SHIFT));
OUT_RING_TABLE((int *)cmdbuf->buf, 8);
ADVANCE_RING();
cmdbuf->buf += 8 * 4;
cmdbuf->bufsz -= 8 * 4;
return 0;
}
static __inline__ int r300_emit_3d_load_vbpntr(drm_radeon_private_t *dev_priv,
drm_radeon_kcmd_buffer_t *cmdbuf,
u32 header)
{
int count, i, k;
#define MAX_ARRAY_PACKET 64
u32 payload[MAX_ARRAY_PACKET];
u32 narrays;
RING_LOCALS;
count = (header >> 16) & 0x3fff;
if ((count + 1) > MAX_ARRAY_PACKET) {
DRM_ERROR("Too large payload in 3D_LOAD_VBPNTR (count=%d)\n",
count);
return DRM_ERR(EINVAL);
}
memset(payload, 0, MAX_ARRAY_PACKET * 4);
memcpy(payload, cmdbuf->buf + 4, (count + 1) * 4);
/* carefully check packet contents */
narrays = payload[0];
k = 0;
i = 1;
while ((k < narrays) && (i < (count + 1))) {
i++; /* skip attribute field */
if (r300_check_offset(dev_priv, payload[i])) {
DRM_ERROR
("Offset failed range check (k=%d i=%d) while processing 3D_LOAD_VBPNTR packet.\n",
k, i);
return DRM_ERR(EINVAL);
}
k++;
i++;
if (k == narrays)
break;
/* have one more to process, they come in pairs */
if (r300_check_offset(dev_priv, payload[i])) {
DRM_ERROR
("Offset failed range check (k=%d i=%d) while processing 3D_LOAD_VBPNTR packet.\n",
k, i);
return DRM_ERR(EINVAL);
}
k++;
i++;
}
/* do the counts match what we expect ? */
if ((k != narrays) || (i != (count + 1))) {
DRM_ERROR
("Malformed 3D_LOAD_VBPNTR packet (k=%d i=%d narrays=%d count+1=%d).\n",
k, i, narrays, count + 1);
return DRM_ERR(EINVAL);
}
/* all clear, output packet */
BEGIN_RING(count + 2);
OUT_RING(header);
OUT_RING_TABLE(payload, count + 1);
ADVANCE_RING();
cmdbuf->buf += (count + 2) * 4;
cmdbuf->bufsz -= (count + 2) * 4;
return 0;
}
static __inline__ int r300_emit_bitblt_multi(drm_radeon_private_t *dev_priv,
drm_radeon_kcmd_buffer_t *cmdbuf)
{
u32 *cmd = (u32 *) cmdbuf->buf;
int count, ret;
RING_LOCALS;
count=(cmd[0]>>16) & 0x3fff;
if (cmd[0] & 0x8000) {
u32 offset;
if (cmd[1] & (RADEON_GMC_SRC_PITCH_OFFSET_CNTL
| RADEON_GMC_DST_PITCH_OFFSET_CNTL)) {
offset = cmd[2] << 10;
ret = r300_check_offset(dev_priv, offset);
if (ret) {
DRM_ERROR("Invalid bitblt first offset is %08X\n", offset);
return DRM_ERR(EINVAL);
}
}
if ((cmd[1] & RADEON_GMC_SRC_PITCH_OFFSET_CNTL) &&
(cmd[1] & RADEON_GMC_DST_PITCH_OFFSET_CNTL)) {
offset = cmd[3] << 10;
ret = r300_check_offset(dev_priv, offset);
if (ret) {
DRM_ERROR("Invalid bitblt second offset is %08X\n", offset);
return DRM_ERR(EINVAL);
}
}
}
BEGIN_RING(count+2);
OUT_RING(cmd[0]);
OUT_RING_TABLE((int *)(cmdbuf->buf + 4), count + 1);
ADVANCE_RING();
cmdbuf->buf += (count+2)*4;
cmdbuf->bufsz -= (count+2)*4;
return 0;
}
static __inline__ int r300_emit_raw_packet3(drm_radeon_private_t *dev_priv,
drm_radeon_kcmd_buffer_t *cmdbuf)
{
u32 header;
int count;
RING_LOCALS;
if (4 > cmdbuf->bufsz)
return DRM_ERR(EINVAL);
/* Fixme !! This simply emits a packet without much checking.
We need to be smarter. */
/* obtain first word - actual packet3 header */
header = *(u32 *) cmdbuf->buf;
/* Is it packet 3 ? */
if ((header >> 30) != 0x3) {
DRM_ERROR("Not a packet3 header (0x%08x)\n", header);
return DRM_ERR(EINVAL);
}
count = (header >> 16) & 0x3fff;
/* Check again now that we know how much data to expect */
if ((count + 2) * 4 > cmdbuf->bufsz) {
DRM_ERROR
("Expected packet3 of length %d but have only %d bytes left\n",
(count + 2) * 4, cmdbuf->bufsz);
return DRM_ERR(EINVAL);
}
/* Is it a packet type we know about ? */
switch (header & 0xff00) {
case RADEON_3D_LOAD_VBPNTR: /* load vertex array pointers */
return r300_emit_3d_load_vbpntr(dev_priv, cmdbuf, header);
case RADEON_CNTL_BITBLT_MULTI:
return r300_emit_bitblt_multi(dev_priv, cmdbuf);
case RADEON_CP_3D_DRAW_IMMD_2: /* triggers drawing using in-packet vertex data */
case RADEON_CP_3D_DRAW_VBUF_2: /* triggers drawing of vertex buffers setup elsewhere */
case RADEON_CP_3D_DRAW_INDX_2: /* triggers drawing using indices to vertex buffer */
case RADEON_CP_INDX_BUFFER: /* DRAW_INDX_2 without INDX_BUFFER seems to lock up the gpu */
case RADEON_WAIT_FOR_IDLE:
case RADEON_CP_NOP:
/* these packets are safe */
break;
default:
DRM_ERROR("Unknown packet3 header (0x%08x)\n", header);
return DRM_ERR(EINVAL);
}
BEGIN_RING(count + 2);
OUT_RING(header);
OUT_RING_TABLE((int *)(cmdbuf->buf + 4), count + 1);
ADVANCE_RING();
cmdbuf->buf += (count + 2) * 4;
cmdbuf->bufsz -= (count + 2) * 4;
return 0;
}
/**
* Emit a rendering packet3 from userspace.
* Called by r300_do_cp_cmdbuf.
*/
static __inline__ int r300_emit_packet3(drm_radeon_private_t *dev_priv,
drm_radeon_kcmd_buffer_t *cmdbuf,
drm_r300_cmd_header_t header)
{
int n;
int ret;
char *orig_buf = cmdbuf->buf;
int orig_bufsz = cmdbuf->bufsz;
/* This is a do-while-loop so that we run the interior at least once,
* even if cmdbuf->nbox is 0. Compare r300_emit_cliprects for rationale.
*/
n = 0;
do {
if (cmdbuf->nbox > R300_SIMULTANEOUS_CLIPRECTS) {
ret = r300_emit_cliprects(dev_priv, cmdbuf, n);
if (ret)
return ret;
cmdbuf->buf = orig_buf;
cmdbuf->bufsz = orig_bufsz;
}
switch (header.packet3.packet) {
case R300_CMD_PACKET3_CLEAR:
DRM_DEBUG("R300_CMD_PACKET3_CLEAR\n");
ret = r300_emit_clear(dev_priv, cmdbuf);
if (ret) {
DRM_ERROR("r300_emit_clear failed\n");
return ret;
}
break;
case R300_CMD_PACKET3_RAW:
DRM_DEBUG("R300_CMD_PACKET3_RAW\n");
ret = r300_emit_raw_packet3(dev_priv, cmdbuf);
if (ret) {
DRM_ERROR("r300_emit_raw_packet3 failed\n");
return ret;
}
break;
default:
DRM_ERROR("bad packet3 type %i at %p\n",
header.packet3.packet,
cmdbuf->buf - sizeof(header));
return DRM_ERR(EINVAL);
}
n += R300_SIMULTANEOUS_CLIPRECTS;
} while (n < cmdbuf->nbox);
return 0;
}
/* Some of the R300 chips seem to be extremely touchy about the two registers
* that are configured in r300_pacify.
* Among the worst offenders seems to be the R300 ND (0x4E44): When userspace
* sends a command buffer that contains only state setting commands and a
* vertex program/parameter upload sequence, this will eventually lead to a
* lockup, unless the sequence is bracketed by calls to r300_pacify.
* So we should take great care to *always* call r300_pacify before
* *anything* 3D related, and again afterwards. This is what the
* call bracket in r300_do_cp_cmdbuf is for.
*/
/**
* Emit the sequence to pacify R300.
*/
static __inline__ void r300_pacify(drm_radeon_private_t *dev_priv)
{
RING_LOCALS;
BEGIN_RING(6);
OUT_RING(CP_PACKET0(R300_RB3D_DSTCACHE_CTLSTAT, 0));
OUT_RING(0xa);
OUT_RING(CP_PACKET0(0x4f18, 0));
OUT_RING(0x3);
OUT_RING(CP_PACKET3(RADEON_CP_NOP, 0));
OUT_RING(0x0);
ADVANCE_RING();
}
/**
* Called by r300_do_cp_cmdbuf to update the internal buffer age and state.
* The actual age emit is done by r300_do_cp_cmdbuf, which is why you must
* be careful about how this function is called.
*/
static void r300_discard_buffer(drm_device_t * dev, drm_buf_t * buf)
{
drm_radeon_private_t *dev_priv = dev->dev_private;
drm_radeon_buf_priv_t *buf_priv = buf->dev_private;
buf_priv->age = ++dev_priv->sarea_priv->last_dispatch;
buf->pending = 1;
buf->used = 0;
}
static int r300_scratch(drm_radeon_private_t *dev_priv,
drm_radeon_kcmd_buffer_t *cmdbuf,
drm_r300_cmd_header_t header)
{
u32 *ref_age_base;
u32 i, buf_idx, h_pending;
RING_LOCALS;
if (cmdbuf->bufsz < sizeof(uint64_t) + header.scratch.n_bufs * sizeof(buf_idx) ) {
return DRM_ERR(EINVAL);
}
if (header.scratch.reg >= 5) {
return DRM_ERR(EINVAL);
}
dev_priv->scratch_ages[header.scratch.reg] ++;
ref_age_base = (u32 *)(unsigned long)*((uint64_t *)cmdbuf->buf);
cmdbuf->buf += sizeof(uint64_t);
cmdbuf->bufsz -= sizeof(uint64_t);
for (i=0; i < header.scratch.n_bufs; i++) {
buf_idx = *(u32 *)cmdbuf->buf;
buf_idx *= 2; /* 8 bytes per buf */
if (DRM_COPY_TO_USER(ref_age_base + buf_idx, &dev_priv->scratch_ages[header.scratch.reg], sizeof(u32))) {
return DRM_ERR(EINVAL);
}
if (DRM_COPY_FROM_USER(&h_pending, ref_age_base + buf_idx + 1, sizeof(u32))) {
return DRM_ERR(EINVAL);
}
if (h_pending == 0) {
return DRM_ERR(EINVAL);
}
h_pending--;
if (DRM_COPY_TO_USER(ref_age_base + buf_idx + 1, &h_pending, sizeof(u32))) {
return DRM_ERR(EINVAL);
}
cmdbuf->buf += sizeof(buf_idx);
cmdbuf->bufsz -= sizeof(buf_idx);
}
BEGIN_RING(2);
OUT_RING( CP_PACKET0( RADEON_SCRATCH_REG0 + header.scratch.reg * 4, 0 ) );
OUT_RING( dev_priv->scratch_ages[header.scratch.reg] );
ADVANCE_RING();
return 0;
}
/**
* Parses and validates a user-supplied command buffer and emits appropriate
* commands on the DMA ring buffer.
* Called by the ioctl handler function radeon_cp_cmdbuf.
*/
int r300_do_cp_cmdbuf(drm_device_t *dev,
DRMFILE filp,
drm_file_t *filp_priv,
drm_radeon_kcmd_buffer_t *cmdbuf)
{
drm_radeon_private_t *dev_priv = dev->dev_private;
drm_device_dma_t *dma = dev->dma;
drm_buf_t *buf = NULL;
int emit_dispatch_age = 0;
int ret = 0;
DRM_DEBUG("\n");
/* See the comment above r300_emit_begin3d for why this call must be here,
* and what the cleanup gotos are for. */
r300_pacify(dev_priv);
if (cmdbuf->nbox <= R300_SIMULTANEOUS_CLIPRECTS) {
ret = r300_emit_cliprects(dev_priv, cmdbuf, 0);
if (ret)
goto cleanup;
}
while (cmdbuf->bufsz >= sizeof(drm_r300_cmd_header_t)) {
int idx;
drm_r300_cmd_header_t header;
header.u = *(unsigned int *)cmdbuf->buf;
cmdbuf->buf += sizeof(header);
cmdbuf->bufsz -= sizeof(header);
switch (header.header.cmd_type) {
case R300_CMD_PACKET0:
DRM_DEBUG("R300_CMD_PACKET0\n");
ret = r300_emit_packet0(dev_priv, cmdbuf, header);
if (ret) {
DRM_ERROR("r300_emit_packet0 failed\n");
goto cleanup;
}
break;
case R300_CMD_VPU:
DRM_DEBUG("R300_CMD_VPU\n");
ret = r300_emit_vpu(dev_priv, cmdbuf, header);
if (ret) {
DRM_ERROR("r300_emit_vpu failed\n");
goto cleanup;
}
break;
case R300_CMD_PACKET3:
DRM_DEBUG("R300_CMD_PACKET3\n");
ret = r300_emit_packet3(dev_priv, cmdbuf, header);
if (ret) {
DRM_ERROR("r300_emit_packet3 failed\n");
goto cleanup;
}
break;
case R300_CMD_END3D:
DRM_DEBUG("R300_CMD_END3D\n");
/* TODO:
Ideally userspace driver should not need to issue this call,
i.e. the drm driver should issue it automatically and prevent
lockups.
In practice, we do not understand why this call is needed and what
it does (except for some vague guesses that it has to do with cache
coherence) and so the user space driver does it.
Once we are sure which uses prevent lockups the code could be moved
into the kernel and the userspace driver will not
need to use this command.
Note that issuing this command does not hurt anything
except, possibly, performance */
r300_pacify(dev_priv);
break;
case R300_CMD_CP_DELAY:
/* simple enough, we can do it here */
DRM_DEBUG("R300_CMD_CP_DELAY\n");
{
int i;
RING_LOCALS;
BEGIN_RING(header.delay.count);
for (i = 0; i < header.delay.count; i++)
OUT_RING(RADEON_CP_PACKET2);
ADVANCE_RING();
}
break;
case R300_CMD_DMA_DISCARD:
DRM_DEBUG("RADEON_CMD_DMA_DISCARD\n");
idx = header.dma.buf_idx;
if (idx < 0 || idx >= dma->buf_count) {
DRM_ERROR("buffer index %d (of %d max)\n",
idx, dma->buf_count - 1);
ret = DRM_ERR(EINVAL);
goto cleanup;
}
buf = dma->buflist[idx];
if (buf->filp != filp || buf->pending) {
DRM_ERROR("bad buffer %p %p %d\n",
buf->filp, filp, buf->pending);
ret = DRM_ERR(EINVAL);
goto cleanup;
}
emit_dispatch_age = 1;
r300_discard_buffer(dev, buf);
break;
case R300_CMD_WAIT:
/* simple enough, we can do it here */
DRM_DEBUG("R300_CMD_WAIT\n");
if (header.wait.flags == 0)
break; /* nothing to do */
{
RING_LOCALS;
BEGIN_RING(2);
OUT_RING(CP_PACKET0(RADEON_WAIT_UNTIL, 0));
OUT_RING((header.wait.flags & 0xf) << 14);
ADVANCE_RING();
}
break;
case R300_CMD_SCRATCH:
DRM_DEBUG("R300_CMD_SCRATCH\n");
ret = r300_scratch(dev_priv, cmdbuf, header);
if (ret) {
DRM_ERROR("r300_scratch failed\n");
goto cleanup;
}
break;
default:
DRM_ERROR("bad cmd_type %i at %p\n",
header.header.cmd_type,
cmdbuf->buf - sizeof(header));
ret = DRM_ERR(EINVAL);
goto cleanup;
}
}
DRM_DEBUG("END\n");
cleanup:
r300_pacify(dev_priv);
/* We emit the vertex buffer age here, outside the pacifier "brackets"
* for two reasons:
* (1) This may coalesce multiple age emissions into a single one and
* (2) more importantly, some chips lock up hard when scratch registers
* are written inside the pacifier bracket.
*/
if (emit_dispatch_age) {
RING_LOCALS;
/* Emit the vertex buffer age */
BEGIN_RING(2);
RADEON_DISPATCH_AGE(dev_priv->sarea_priv->last_dispatch);
ADVANCE_RING();
}
COMMIT_RING();
return ret;
}

1446
sys/dev/pci/drm/r300_reg.h Normal file

File diff suppressed because it is too large Load Diff

2263
sys/dev/pci/drm/radeon_cp.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,730 @@
/* radeon_drm.h -- Public header for the radeon driver -*- linux-c -*-
*
* Copyright 2000 Precision Insight, Inc., Cedar Park, Texas.
* Copyright 2000 VA Linux Systems, Inc., Fremont, California.
* Copyright 2002 Tungsten Graphics, Inc., Cedar Park, Texas.
* 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:
* Kevin E. Martin <martin@valinux.com>
* Gareth Hughes <gareth@valinux.com>
* Keith Whitwell <keith@tungstengraphics.com>
*/
#include <sys/cdefs.h>
/*
__FBSDID("$FreeBSD: src/sys/dev/drm/radeon_drm.h,v 1.14 2006/09/07 23:04:47 anholt Exp $");
*/
#ifndef __RADEON_DRM_H__
#define __RADEON_DRM_H__
/* WARNING: If you change any of these defines, make sure to change the
* defines in the X server file (radeon_sarea.h)
*/
#ifndef __RADEON_SAREA_DEFINES__
#define __RADEON_SAREA_DEFINES__
/* Old style state flags, required for sarea interface (1.1 and 1.2
* clears) and 1.2 drm_vertex2 ioctl.
*/
#define RADEON_UPLOAD_CONTEXT 0x00000001
#define RADEON_UPLOAD_VERTFMT 0x00000002
#define RADEON_UPLOAD_LINE 0x00000004
#define RADEON_UPLOAD_BUMPMAP 0x00000008
#define RADEON_UPLOAD_MASKS 0x00000010
#define RADEON_UPLOAD_VIEWPORT 0x00000020
#define RADEON_UPLOAD_SETUP 0x00000040
#define RADEON_UPLOAD_TCL 0x00000080
#define RADEON_UPLOAD_MISC 0x00000100
#define RADEON_UPLOAD_TEX0 0x00000200
#define RADEON_UPLOAD_TEX1 0x00000400
#define RADEON_UPLOAD_TEX2 0x00000800
#define RADEON_UPLOAD_TEX0IMAGES 0x00001000
#define RADEON_UPLOAD_TEX1IMAGES 0x00002000
#define RADEON_UPLOAD_TEX2IMAGES 0x00004000
#define RADEON_UPLOAD_CLIPRECTS 0x00008000 /* handled client-side */
#define RADEON_REQUIRE_QUIESCENCE 0x00010000
#define RADEON_UPLOAD_ZBIAS 0x00020000 /* version 1.2 and newer */
#define RADEON_UPLOAD_ALL 0x003effff
#define RADEON_UPLOAD_CONTEXT_ALL 0x003e01ff
/* New style per-packet identifiers for use in cmd_buffer ioctl with
* the RADEON_EMIT_PACKET command. Comments relate new packets to old
* state bits and the packet size:
*/
#define RADEON_EMIT_PP_MISC 0 /* context/7 */
#define RADEON_EMIT_PP_CNTL 1 /* context/3 */
#define RADEON_EMIT_RB3D_COLORPITCH 2 /* context/1 */
#define RADEON_EMIT_RE_LINE_PATTERN 3 /* line/2 */
#define RADEON_EMIT_SE_LINE_WIDTH 4 /* line/1 */
#define RADEON_EMIT_PP_LUM_MATRIX 5 /* bumpmap/1 */
#define RADEON_EMIT_PP_ROT_MATRIX_0 6 /* bumpmap/2 */
#define RADEON_EMIT_RB3D_STENCILREFMASK 7 /* masks/3 */
#define RADEON_EMIT_SE_VPORT_XSCALE 8 /* viewport/6 */
#define RADEON_EMIT_SE_CNTL 9 /* setup/2 */
#define RADEON_EMIT_SE_CNTL_STATUS 10 /* setup/1 */
#define RADEON_EMIT_RE_MISC 11 /* misc/1 */
#define RADEON_EMIT_PP_TXFILTER_0 12 /* tex0/6 */
#define RADEON_EMIT_PP_BORDER_COLOR_0 13 /* tex0/1 */
#define RADEON_EMIT_PP_TXFILTER_1 14 /* tex1/6 */
#define RADEON_EMIT_PP_BORDER_COLOR_1 15 /* tex1/1 */
#define RADEON_EMIT_PP_TXFILTER_2 16 /* tex2/6 */
#define RADEON_EMIT_PP_BORDER_COLOR_2 17 /* tex2/1 */
#define RADEON_EMIT_SE_ZBIAS_FACTOR 18 /* zbias/2 */
#define RADEON_EMIT_SE_TCL_OUTPUT_VTX_FMT 19 /* tcl/11 */
#define RADEON_EMIT_SE_TCL_MATERIAL_EMMISSIVE_RED 20 /* material/17 */
#define R200_EMIT_PP_TXCBLEND_0 21 /* tex0/4 */
#define R200_EMIT_PP_TXCBLEND_1 22 /* tex1/4 */
#define R200_EMIT_PP_TXCBLEND_2 23 /* tex2/4 */
#define R200_EMIT_PP_TXCBLEND_3 24 /* tex3/4 */
#define R200_EMIT_PP_TXCBLEND_4 25 /* tex4/4 */
#define R200_EMIT_PP_TXCBLEND_5 26 /* tex5/4 */
#define R200_EMIT_PP_TXCBLEND_6 27 /* /4 */
#define R200_EMIT_PP_TXCBLEND_7 28 /* /4 */
#define R200_EMIT_TCL_LIGHT_MODEL_CTL_0 29 /* tcl/7 */
#define R200_EMIT_TFACTOR_0 30 /* tf/7 */
#define R200_EMIT_VTX_FMT_0 31 /* vtx/5 */
#define R200_EMIT_VAP_CTL 32 /* vap/1 */
#define R200_EMIT_MATRIX_SELECT_0 33 /* msl/5 */
#define R200_EMIT_TEX_PROC_CTL_2 34 /* tcg/5 */
#define R200_EMIT_TCL_UCP_VERT_BLEND_CTL 35 /* tcl/1 */
#define R200_EMIT_PP_TXFILTER_0 36 /* tex0/6 */
#define R200_EMIT_PP_TXFILTER_1 37 /* tex1/6 */
#define R200_EMIT_PP_TXFILTER_2 38 /* tex2/6 */
#define R200_EMIT_PP_TXFILTER_3 39 /* tex3/6 */
#define R200_EMIT_PP_TXFILTER_4 40 /* tex4/6 */
#define R200_EMIT_PP_TXFILTER_5 41 /* tex5/6 */
#define R200_EMIT_PP_TXOFFSET_0 42 /* tex0/1 */
#define R200_EMIT_PP_TXOFFSET_1 43 /* tex1/1 */
#define R200_EMIT_PP_TXOFFSET_2 44 /* tex2/1 */
#define R200_EMIT_PP_TXOFFSET_3 45 /* tex3/1 */
#define R200_EMIT_PP_TXOFFSET_4 46 /* tex4/1 */
#define R200_EMIT_PP_TXOFFSET_5 47 /* tex5/1 */
#define R200_EMIT_VTE_CNTL 48 /* vte/1 */
#define R200_EMIT_OUTPUT_VTX_COMP_SEL 49 /* vtx/1 */
#define R200_EMIT_PP_TAM_DEBUG3 50 /* tam/1 */
#define R200_EMIT_PP_CNTL_X 51 /* cst/1 */
#define R200_EMIT_RB3D_DEPTHXY_OFFSET 52 /* cst/1 */
#define R200_EMIT_RE_AUX_SCISSOR_CNTL 53 /* cst/1 */
#define R200_EMIT_RE_SCISSOR_TL_0 54 /* cst/2 */
#define R200_EMIT_RE_SCISSOR_TL_1 55 /* cst/2 */
#define R200_EMIT_RE_SCISSOR_TL_2 56 /* cst/2 */
#define R200_EMIT_SE_VAP_CNTL_STATUS 57 /* cst/1 */
#define R200_EMIT_SE_VTX_STATE_CNTL 58 /* cst/1 */
#define R200_EMIT_RE_POINTSIZE 59 /* cst/1 */
#define R200_EMIT_TCL_INPUT_VTX_VECTOR_ADDR_0 60 /* cst/4 */
#define R200_EMIT_PP_CUBIC_FACES_0 61
#define R200_EMIT_PP_CUBIC_OFFSETS_0 62
#define R200_EMIT_PP_CUBIC_FACES_1 63
#define R200_EMIT_PP_CUBIC_OFFSETS_1 64
#define R200_EMIT_PP_CUBIC_FACES_2 65
#define R200_EMIT_PP_CUBIC_OFFSETS_2 66
#define R200_EMIT_PP_CUBIC_FACES_3 67
#define R200_EMIT_PP_CUBIC_OFFSETS_3 68
#define R200_EMIT_PP_CUBIC_FACES_4 69
#define R200_EMIT_PP_CUBIC_OFFSETS_4 70
#define R200_EMIT_PP_CUBIC_FACES_5 71
#define R200_EMIT_PP_CUBIC_OFFSETS_5 72
#define RADEON_EMIT_PP_TEX_SIZE_0 73
#define RADEON_EMIT_PP_TEX_SIZE_1 74
#define RADEON_EMIT_PP_TEX_SIZE_2 75
#define R200_EMIT_RB3D_BLENDCOLOR 76
#define R200_EMIT_TCL_POINT_SPRITE_CNTL 77
#define RADEON_EMIT_PP_CUBIC_FACES_0 78
#define RADEON_EMIT_PP_CUBIC_OFFSETS_T0 79
#define RADEON_EMIT_PP_CUBIC_FACES_1 80
#define RADEON_EMIT_PP_CUBIC_OFFSETS_T1 81
#define RADEON_EMIT_PP_CUBIC_FACES_2 82
#define RADEON_EMIT_PP_CUBIC_OFFSETS_T2 83
#define R200_EMIT_PP_TRI_PERF_CNTL 84
#define R200_EMIT_PP_AFS_0 85
#define R200_EMIT_PP_AFS_1 86
#define R200_EMIT_ATF_TFACTOR 87
#define R200_EMIT_PP_TXCTLALL_0 88
#define R200_EMIT_PP_TXCTLALL_1 89
#define R200_EMIT_PP_TXCTLALL_2 90
#define R200_EMIT_PP_TXCTLALL_3 91
#define R200_EMIT_PP_TXCTLALL_4 92
#define R200_EMIT_PP_TXCTLALL_5 93
#define R200_EMIT_VAP_PVS_CNTL 94
#define RADEON_MAX_STATE_PACKETS 95
/* Commands understood by cmd_buffer ioctl. More can be added but
* obviously these can't be removed or changed:
*/
#define RADEON_CMD_PACKET 1 /* emit one of the register packets above */
#define RADEON_CMD_SCALARS 2 /* emit scalar data */
#define RADEON_CMD_VECTORS 3 /* emit vector data */
#define RADEON_CMD_DMA_DISCARD 4 /* discard current dma buf */
#define RADEON_CMD_PACKET3 5 /* emit hw packet */
#define RADEON_CMD_PACKET3_CLIP 6 /* emit hw packet wrapped in cliprects */
#define RADEON_CMD_SCALARS2 7 /* r200 stopgap */
#define RADEON_CMD_WAIT 8 /* emit hw wait commands -- note:
* doesn't make the cpu wait, just
* the graphics hardware */
#define RADEON_CMD_VECLINEAR 9 /* another r200 stopgap */
typedef union {
int i;
struct {
unsigned char cmd_type, pad0, pad1, pad2;
} header;
struct {
unsigned char cmd_type, packet_id, pad0, pad1;
} packet;
struct {
unsigned char cmd_type, offset, stride, count;
} scalars;
struct {
unsigned char cmd_type, offset, stride, count;
} vectors;
struct {
unsigned char cmd_type, addr_lo, addr_hi, count;
} veclinear;
struct {
unsigned char cmd_type, buf_idx, pad0, pad1;
} dma;
struct {
unsigned char cmd_type, flags, pad0, pad1;
} wait;
} drm_radeon_cmd_header_t;
#define RADEON_WAIT_2D 0x1
#define RADEON_WAIT_3D 0x2
/* Allowed parameters for R300_CMD_PACKET3
*/
#define R300_CMD_PACKET3_CLEAR 0
#define R300_CMD_PACKET3_RAW 1
/* Commands understood by cmd_buffer ioctl for R300.
* The interface has not been stabilized, so some of these may be removed
* and eventually reordered before stabilization.
*/
#define R300_CMD_PACKET0 1
#define R300_CMD_VPU 2 /* emit vertex program upload */
#define R300_CMD_PACKET3 3 /* emit a packet3 */
#define R300_CMD_END3D 4 /* emit sequence ending 3d rendering */
#define R300_CMD_CP_DELAY 5
#define R300_CMD_DMA_DISCARD 6
#define R300_CMD_WAIT 7
# define R300_WAIT_2D 0x1
# define R300_WAIT_3D 0x2
# define R300_WAIT_2D_CLEAN 0x3
# define R300_WAIT_3D_CLEAN 0x4
#define R300_CMD_SCRATCH 8
typedef union {
unsigned int u;
struct {
unsigned char cmd_type, pad0, pad1, pad2;
} header;
struct {
unsigned char cmd_type, count, reglo, reghi;
} packet0;
struct {
unsigned char cmd_type, count, adrlo, adrhi;
} vpu;
struct {
unsigned char cmd_type, packet, pad0, pad1;
} packet3;
struct {
unsigned char cmd_type, packet;
unsigned short count; /* amount of packet2 to emit */
} delay;
struct {
unsigned char cmd_type, buf_idx, pad0, pad1;
} dma;
struct {
unsigned char cmd_type, flags, pad0, pad1;
} wait;
struct {
unsigned char cmd_type, reg, n_bufs, flags;
} scratch;
} drm_r300_cmd_header_t;
#define RADEON_FRONT 0x1
#define RADEON_BACK 0x2
#define RADEON_DEPTH 0x4
#define RADEON_STENCIL 0x8
#define RADEON_CLEAR_FASTZ 0x80000000
#define RADEON_USE_HIERZ 0x40000000
#define RADEON_USE_COMP_ZBUF 0x20000000
/* Primitive types
*/
#define RADEON_POINTS 0x1
#define RADEON_LINES 0x2
#define RADEON_LINE_STRIP 0x3
#define RADEON_TRIANGLES 0x4
#define RADEON_TRIANGLE_FAN 0x5
#define RADEON_TRIANGLE_STRIP 0x6
/* Vertex/indirect buffer size
*/
#define RADEON_BUFFER_SIZE 65536
/* Byte offsets for indirect buffer data
*/
#define RADEON_INDEX_PRIM_OFFSET 20
#define RADEON_SCRATCH_REG_OFFSET 32
#define RADEON_NR_SAREA_CLIPRECTS 12
/* There are 2 heaps (local/GART). Each region within a heap is a
* minimum of 64k, and there are at most 64 of them per heap.
*/
#define RADEON_LOCAL_TEX_HEAP 0
#define RADEON_GART_TEX_HEAP 1
#define RADEON_NR_TEX_HEAPS 2
#define RADEON_NR_TEX_REGIONS 64
#define RADEON_LOG_TEX_GRANULARITY 16
#define RADEON_MAX_TEXTURE_LEVELS 12
#define RADEON_MAX_TEXTURE_UNITS 3
#define RADEON_MAX_SURFACES 8
/* Blits have strict offset rules. All blit offset must be aligned on
* a 1K-byte boundary.
*/
#define RADEON_OFFSET_SHIFT 10
#define RADEON_OFFSET_ALIGN (1 << RADEON_OFFSET_SHIFT)
#define RADEON_OFFSET_MASK (RADEON_OFFSET_ALIGN - 1)
#endif /* __RADEON_SAREA_DEFINES__ */
typedef struct {
unsigned int red;
unsigned int green;
unsigned int blue;
unsigned int alpha;
} radeon_color_regs_t;
typedef struct {
/* Context state */
unsigned int pp_misc; /* 0x1c14 */
unsigned int pp_fog_color;
unsigned int re_solid_color;
unsigned int rb3d_blendcntl;
unsigned int rb3d_depthoffset;
unsigned int rb3d_depthpitch;
unsigned int rb3d_zstencilcntl;
unsigned int pp_cntl; /* 0x1c38 */
unsigned int rb3d_cntl;
unsigned int rb3d_coloroffset;
unsigned int re_width_height;
unsigned int rb3d_colorpitch;
unsigned int se_cntl;
/* Vertex format state */
unsigned int se_coord_fmt; /* 0x1c50 */
/* Line state */
unsigned int re_line_pattern; /* 0x1cd0 */
unsigned int re_line_state;
unsigned int se_line_width; /* 0x1db8 */
/* Bumpmap state */
unsigned int pp_lum_matrix; /* 0x1d00 */
unsigned int pp_rot_matrix_0; /* 0x1d58 */
unsigned int pp_rot_matrix_1;
/* Mask state */
unsigned int rb3d_stencilrefmask; /* 0x1d7c */
unsigned int rb3d_ropcntl;
unsigned int rb3d_planemask;
/* Viewport state */
unsigned int se_vport_xscale; /* 0x1d98 */
unsigned int se_vport_xoffset;
unsigned int se_vport_yscale;
unsigned int se_vport_yoffset;
unsigned int se_vport_zscale;
unsigned int se_vport_zoffset;
/* Setup state */
unsigned int se_cntl_status; /* 0x2140 */
/* Misc state */
unsigned int re_top_left; /* 0x26c0 */
unsigned int re_misc;
} drm_radeon_context_regs_t;
typedef struct {
/* Zbias state */
unsigned int se_zbias_factor; /* 0x1dac */
unsigned int se_zbias_constant;
} drm_radeon_context2_regs_t;
/* Setup registers for each texture unit
*/
typedef struct {
unsigned int pp_txfilter;
unsigned int pp_txformat;
unsigned int pp_txoffset;
unsigned int pp_txcblend;
unsigned int pp_txablend;
unsigned int pp_tfactor;
unsigned int pp_border_color;
} drm_radeon_texture_regs_t;
typedef struct {
unsigned int start;
unsigned int finish;
unsigned int prim:8;
unsigned int stateidx:8;
unsigned int numverts:16; /* overloaded as offset/64 for elt prims */
unsigned int vc_format; /* vertex format */
} drm_radeon_prim_t;
typedef struct {
drm_radeon_context_regs_t context;
drm_radeon_texture_regs_t tex[RADEON_MAX_TEXTURE_UNITS];
drm_radeon_context2_regs_t context2;
unsigned int dirty;
} drm_radeon_state_t;
typedef struct {
/* The channel for communication of state information to the
* kernel on firing a vertex buffer with either of the
* obsoleted vertex/index ioctls.
*/
drm_radeon_context_regs_t context_state;
drm_radeon_texture_regs_t tex_state[RADEON_MAX_TEXTURE_UNITS];
unsigned int dirty;
unsigned int vertsize;
unsigned int vc_format;
/* The current cliprects, or a subset thereof.
*/
drm_clip_rect_t boxes[RADEON_NR_SAREA_CLIPRECTS];
unsigned int nbox;
/* Counters for client-side throttling of rendering clients.
*/
unsigned int last_frame;
unsigned int last_dispatch;
unsigned int last_clear;
drm_tex_region_t tex_list[RADEON_NR_TEX_HEAPS][RADEON_NR_TEX_REGIONS +
1];
unsigned int tex_age[RADEON_NR_TEX_HEAPS];
int ctx_owner;
int pfState; /* number of 3d windows (0,1,2ormore) */
int pfCurrentPage; /* which buffer is being displayed? */
int crtc2_base; /* CRTC2 frame offset */
int tiling_enabled; /* set by drm, read by 2d + 3d clients */
} drm_radeon_sarea_t;
/* WARNING: If you change any of these defines, make sure to change the
* defines in the Xserver file (xf86drmRadeon.h)
*
* KW: actually it's illegal to change any of this (backwards compatibility).
*/
/* Radeon specific ioctls
* The device specific ioctl range is 0x40 to 0x79.
*/
#define DRM_RADEON_CP_INIT 0x00
#define DRM_RADEON_CP_START 0x01
#define DRM_RADEON_CP_STOP 0x02
#define DRM_RADEON_CP_RESET 0x03
#define DRM_RADEON_CP_IDLE 0x04
#define DRM_RADEON_RESET 0x05
#define DRM_RADEON_FULLSCREEN 0x06
#define DRM_RADEON_SWAP 0x07
#define DRM_RADEON_CLEAR 0x08
#define DRM_RADEON_VERTEX 0x09
#define DRM_RADEON_INDICES 0x0A
#define DRM_RADEON_NOT_USED
#define DRM_RADEON_STIPPLE 0x0C
#define DRM_RADEON_INDIRECT 0x0D
#define DRM_RADEON_TEXTURE 0x0E
#define DRM_RADEON_VERTEX2 0x0F
#define DRM_RADEON_CMDBUF 0x10
#define DRM_RADEON_GETPARAM 0x11
#define DRM_RADEON_FLIP 0x12
#define DRM_RADEON_ALLOC 0x13
#define DRM_RADEON_FREE 0x14
#define DRM_RADEON_INIT_HEAP 0x15
#define DRM_RADEON_IRQ_EMIT 0x16
#define DRM_RADEON_IRQ_WAIT 0x17
#define DRM_RADEON_CP_RESUME 0x18
#define DRM_RADEON_SETPARAM 0x19
#define DRM_RADEON_SURF_ALLOC 0x1a
#define DRM_RADEON_SURF_FREE 0x1b
#define DRM_IOCTL_RADEON_CP_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_RADEON_CP_INIT, drm_radeon_init_t)
#define DRM_IOCTL_RADEON_CP_START DRM_IO( DRM_COMMAND_BASE + DRM_RADEON_CP_START)
#define DRM_IOCTL_RADEON_CP_STOP DRM_IOW( DRM_COMMAND_BASE + DRM_RADEON_CP_STOP, drm_radeon_cp_stop_t)
#define DRM_IOCTL_RADEON_CP_RESET DRM_IO( DRM_COMMAND_BASE + DRM_RADEON_CP_RESET)
#define DRM_IOCTL_RADEON_CP_IDLE DRM_IO( DRM_COMMAND_BASE + DRM_RADEON_CP_IDLE)
#define DRM_IOCTL_RADEON_RESET DRM_IO( DRM_COMMAND_BASE + DRM_RADEON_RESET)
#define DRM_IOCTL_RADEON_FULLSCREEN DRM_IOW( DRM_COMMAND_BASE + DRM_RADEON_FULLSCREEN, drm_radeon_fullscreen_t)
#define DRM_IOCTL_RADEON_SWAP DRM_IO( DRM_COMMAND_BASE + DRM_RADEON_SWAP)
#define DRM_IOCTL_RADEON_CLEAR DRM_IOW( DRM_COMMAND_BASE + DRM_RADEON_CLEAR, drm_radeon_clear_t)
#define DRM_IOCTL_RADEON_VERTEX DRM_IOW( DRM_COMMAND_BASE + DRM_RADEON_VERTEX, drm_radeon_vertex_t)
#define DRM_IOCTL_RADEON_INDICES DRM_IOW( DRM_COMMAND_BASE + DRM_RADEON_INDICES, drm_radeon_indices_t)
#define DRM_IOCTL_RADEON_STIPPLE DRM_IOW( DRM_COMMAND_BASE + DRM_RADEON_STIPPLE, drm_radeon_stipple_t)
#define DRM_IOCTL_RADEON_INDIRECT DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_INDIRECT, drm_radeon_indirect_t)
#define DRM_IOCTL_RADEON_TEXTURE DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_TEXTURE, drm_radeon_texture_t)
#define DRM_IOCTL_RADEON_VERTEX2 DRM_IOW( DRM_COMMAND_BASE + DRM_RADEON_VERTEX2, drm_radeon_vertex2_t)
#define DRM_IOCTL_RADEON_CMDBUF DRM_IOW( DRM_COMMAND_BASE + DRM_RADEON_CMDBUF, drm_radeon_cmd_buffer_t)
#define DRM_IOCTL_RADEON_GETPARAM DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GETPARAM, drm_radeon_getparam_t)
#define DRM_IOCTL_RADEON_FLIP DRM_IO( DRM_COMMAND_BASE + DRM_RADEON_FLIP)
#define DRM_IOCTL_RADEON_ALLOC DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_ALLOC, drm_radeon_mem_alloc_t)
#define DRM_IOCTL_RADEON_FREE DRM_IOW( DRM_COMMAND_BASE + DRM_RADEON_FREE, drm_radeon_mem_free_t)
#define DRM_IOCTL_RADEON_INIT_HEAP DRM_IOW( DRM_COMMAND_BASE + DRM_RADEON_INIT_HEAP, drm_radeon_mem_init_heap_t)
#define DRM_IOCTL_RADEON_IRQ_EMIT DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_IRQ_EMIT, drm_radeon_irq_emit_t)
#define DRM_IOCTL_RADEON_IRQ_WAIT DRM_IOW( DRM_COMMAND_BASE + DRM_RADEON_IRQ_WAIT, drm_radeon_irq_wait_t)
#define DRM_IOCTL_RADEON_CP_RESUME DRM_IO( DRM_COMMAND_BASE + DRM_RADEON_CP_RESUME)
#define DRM_IOCTL_RADEON_SETPARAM DRM_IOW( DRM_COMMAND_BASE + DRM_RADEON_SETPARAM, drm_radeon_setparam_t)
#define DRM_IOCTL_RADEON_SURF_ALLOC DRM_IOW( DRM_COMMAND_BASE + DRM_RADEON_SURF_ALLOC, drm_radeon_surface_alloc_t)
#define DRM_IOCTL_RADEON_SURF_FREE DRM_IOW( DRM_COMMAND_BASE + DRM_RADEON_SURF_FREE, drm_radeon_surface_free_t)
typedef struct drm_radeon_init {
enum {
RADEON_INIT_CP = 0x01,
RADEON_CLEANUP_CP = 0x02,
RADEON_INIT_R200_CP = 0x03,
RADEON_INIT_R300_CP = 0x04
} func;
unsigned long sarea_priv_offset;
int is_pci; /* for overriding only */
int cp_mode;
int gart_size;
int ring_size;
int usec_timeout;
unsigned int fb_bpp;
unsigned int front_offset, front_pitch;
unsigned int back_offset, back_pitch;
unsigned int depth_bpp;
unsigned int depth_offset, depth_pitch;
unsigned long fb_offset DEPRECATED; /* deprecated, driver asks hardware */
unsigned long mmio_offset DEPRECATED; /* deprecated, driver asks hardware */
unsigned long ring_offset;
unsigned long ring_rptr_offset;
unsigned long buffers_offset;
unsigned long gart_textures_offset;
} drm_radeon_init_t;
typedef struct drm_radeon_cp_stop {
int flush;
int idle;
} drm_radeon_cp_stop_t;
typedef struct drm_radeon_fullscreen {
enum {
RADEON_INIT_FULLSCREEN = 0x01,
RADEON_CLEANUP_FULLSCREEN = 0x02
} func;
} drm_radeon_fullscreen_t;
#define CLEAR_X1 0
#define CLEAR_Y1 1
#define CLEAR_X2 2
#define CLEAR_Y2 3
#define CLEAR_DEPTH 4
typedef union drm_radeon_clear_rect {
float f[5];
unsigned int ui[5];
} drm_radeon_clear_rect_t;
typedef struct drm_radeon_clear {
unsigned int flags;
unsigned int clear_color;
unsigned int clear_depth;
unsigned int color_mask;
unsigned int depth_mask; /* misnamed field: should be stencil */
drm_radeon_clear_rect_t __user *depth_boxes;
} drm_radeon_clear_t;
typedef struct drm_radeon_vertex {
int prim;
int idx; /* Index of vertex buffer */
int count; /* Number of vertices in buffer */
int discard; /* Client finished with buffer? */
} drm_radeon_vertex_t;
typedef struct drm_radeon_indices {
int prim;
int idx;
int start;
int end;
int discard; /* Client finished with buffer? */
} drm_radeon_indices_t;
/* v1.2 - obsoletes drm_radeon_vertex and drm_radeon_indices
* - allows multiple primitives and state changes in a single ioctl
* - supports driver change to emit native primitives
*/
typedef struct drm_radeon_vertex2 {
int idx; /* Index of vertex buffer */
int discard; /* Client finished with buffer? */
int nr_states;
drm_radeon_state_t __user *state;
int nr_prims;
drm_radeon_prim_t __user *prim;
} drm_radeon_vertex2_t;
/* v1.3 - obsoletes drm_radeon_vertex2
* - allows arbitarily large cliprect list
* - allows updating of tcl packet, vector and scalar state
* - allows memory-efficient description of state updates
* - allows state to be emitted without a primitive
* (for clears, ctx switches)
* - allows more than one dma buffer to be referenced per ioctl
* - supports tcl driver
* - may be extended in future versions with new cmd types, packets
*/
typedef struct drm_radeon_cmd_buffer {
int bufsz;
char __user *buf;
int nbox;
drm_clip_rect_t __user *boxes;
} drm_radeon_cmd_buffer_t;
typedef struct drm_radeon_tex_image {
unsigned int x, y; /* Blit coordinates */
unsigned int width, height;
const void __user *data;
} drm_radeon_tex_image_t;
typedef struct drm_radeon_texture {
unsigned int offset;
int pitch;
int format;
int width; /* Texture image coordinates */
int height;
drm_radeon_tex_image_t __user *image;
} drm_radeon_texture_t;
typedef struct drm_radeon_stipple {
unsigned int __user *mask;
} drm_radeon_stipple_t;
typedef struct drm_radeon_indirect {
int idx;
int start;
int end;
int discard;
} drm_radeon_indirect_t;
/* enum for card type parameters */
#define RADEON_CARD_PCI 0
#define RADEON_CARD_AGP 1
#define RADEON_CARD_PCIE 2
/* 1.3: An ioctl to get parameters that aren't available to the 3d
* client any other way.
*/
#define RADEON_PARAM_GART_BUFFER_OFFSET 1 /* card offset of 1st GART buffer */
#define RADEON_PARAM_LAST_FRAME 2
#define RADEON_PARAM_LAST_DISPATCH 3
#define RADEON_PARAM_LAST_CLEAR 4
/* Added with DRM version 1.6. */
#define RADEON_PARAM_IRQ_NR 5
#define RADEON_PARAM_GART_BASE 6 /* card offset of GART base */
/* Added with DRM version 1.8. */
#define RADEON_PARAM_REGISTER_HANDLE 7 /* for drmMap() */
#define RADEON_PARAM_STATUS_HANDLE 8
#define RADEON_PARAM_SAREA_HANDLE 9
#define RADEON_PARAM_GART_TEX_HANDLE 10
#define RADEON_PARAM_SCRATCH_OFFSET 11
#define RADEON_PARAM_CARD_TYPE 12
typedef struct drm_radeon_getparam {
int param;
void __user *value;
} drm_radeon_getparam_t;
/* 1.6: Set up a memory manager for regions of shared memory:
*/
#define RADEON_MEM_REGION_GART 1
#define RADEON_MEM_REGION_FB 2
typedef struct drm_radeon_mem_alloc {
int region;
int alignment;
int size;
int __user *region_offset; /* offset from start of fb or GART */
} drm_radeon_mem_alloc_t;
typedef struct drm_radeon_mem_free {
int region;
int region_offset;
} drm_radeon_mem_free_t;
typedef struct drm_radeon_mem_init_heap {
int region;
int size;
int start;
} drm_radeon_mem_init_heap_t;
/* 1.6: Userspace can request & wait on irq's:
*/
typedef struct drm_radeon_irq_emit {
int __user *irq_seq;
} drm_radeon_irq_emit_t;
typedef struct drm_radeon_irq_wait {
int irq_seq;
} drm_radeon_irq_wait_t;
/* 1.10: Clients tell the DRM where they think the framebuffer is located in
* the card's address space, via a new generic ioctl to set parameters
*/
typedef struct drm_radeon_setparam {
unsigned int param;
int64_t value;
} drm_radeon_setparam_t;
#define RADEON_SETPARAM_FB_LOCATION 1 /* determined framebuffer location */
#define RADEON_SETPARAM_SWITCH_TILING 2 /* enable/disable color tiling */
#define RADEON_SETPARAM_PCIGART_LOCATION 3 /* PCI Gart Location */
#define RADEON_SETPARAM_NEW_MEMMAP 4 /* Use new memory map */
/* 1.14: Clients can allocate/free a surface
*/
typedef struct drm_radeon_surface_alloc {
unsigned int address;
unsigned int size;
unsigned int flags;
} drm_radeon_surface_alloc_t;
typedef struct drm_radeon_surface_free {
unsigned int address;
} drm_radeon_surface_free_t;
#endif

View File

@ -0,0 +1,148 @@
/* radeon_drv.c -- ATI Radeon driver -*- linux-c -*-
* Created: Wed Feb 14 17:10:04 2001 by gareth@valinux.com
*/
/*-
* 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:
* Gareth Hughes <gareth@valinux.com>
*
*/
#include <sys/cdefs.h>
/*
__FBSDID("$FreeBSD: src/sys/dev/drm/radeon_drv.c,v 1.14 2005/12/20 22:44:36 jhb Exp $");
*/
#include "drmP.h"
#include "drm.h"
#include "radeon_drm.h"
#include "radeon_drv.h"
#include "drm_pciids.h"
int radeon_no_wb;
/* drv_PCI_IDs comes from drm_pciids.h, generated from drm_pciids.txt. */
static drm_pci_id_list_t radeon_pciidlist[] = {
radeon_PCI_IDS
};
static void radeon_configure(drm_device_t *dev)
{
dev->driver.buf_priv_size = sizeof(drm_radeon_buf_priv_t);
dev->driver.load = radeon_driver_load;
dev->driver.unload = radeon_driver_unload;
dev->driver.firstopen = radeon_driver_firstopen;
dev->driver.open = radeon_driver_open;
dev->driver.preclose = radeon_driver_preclose;
dev->driver.postclose = radeon_driver_postclose;
dev->driver.lastclose = radeon_driver_lastclose;
dev->driver.vblank_wait = radeon_driver_vblank_wait;
dev->driver.irq_preinstall = radeon_driver_irq_preinstall;
dev->driver.irq_postinstall = radeon_driver_irq_postinstall;
dev->driver.irq_uninstall = radeon_driver_irq_uninstall;
dev->driver.irq_handler = radeon_driver_irq_handler;
dev->driver.dma_ioctl = radeon_cp_buffers;
dev->driver.ioctls = radeon_ioctls;
dev->driver.max_ioctl = radeon_max_ioctl;
dev->driver.name = DRIVER_NAME;
dev->driver.desc = DRIVER_DESC;
dev->driver.date = DRIVER_DATE;
dev->driver.major = DRIVER_MAJOR;
dev->driver.minor = DRIVER_MINOR;
dev->driver.patchlevel = DRIVER_PATCHLEVEL;
dev->driver.use_agp = 1;
dev->driver.use_mtrr = 1;
dev->driver.use_pci_dma = 1;
dev->driver.use_sg = 1;
dev->driver.use_dma = 1;
dev->driver.use_irq = 1;
dev->driver.use_vbl_irq = 1;
}
#ifdef __FreeBSD__
static int
radeon_probe(device_t dev)
{
return drm_probe(dev, radeon_pciidlist);
}
static int
radeon_attach(device_t nbdev)
{
drm_device_t *dev = device_get_softc(nbdev);
bzero(dev, sizeof(drm_device_t));
radeon_configure(dev);
return drm_attach(nbdev, radeon_pciidlist);
}
static device_method_t radeon_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, radeon_probe),
DEVMETHOD(device_attach, radeon_attach),
DEVMETHOD(device_detach, drm_detach),
{ 0, 0 }
};
static driver_t radeon_driver = {
"drm",
radeon_methods,
sizeof(drm_device_t)
};
extern devclass_t drm_devclass;
#if __FreeBSD_version >= 700010
DRIVER_MODULE(radeon, vgapci, radeon_driver, drm_devclass, 0, 0);
#else
DRIVER_MODULE(radeon, pci, radeon_driver, drm_devclass, 0, 0);
#endif
MODULE_DEPEND(radeon, drm, 1, 1, 1);
#elif defined(__NetBSD__) || defined(__OpenBSD__)
static int
radeondrm_probe(struct device *parent, struct cfdata *match, void *aux)
{
struct pci_attach_args *pa = aux;
return drm_probe(pa, radeon_pciidlist);
}
static void
radeondrm_attach(struct device *parent, struct device *self, void *aux)
{
struct pci_attach_args *pa = aux;
drm_device_t *dev = (drm_device_t *)self;
radeon_configure(dev);
return drm_attach(self, pa, radeon_pciidlist);
}
CFATTACH_DECL(radeondrm, sizeof(drm_device_t), radeondrm_probe, radeondrm_attach,
drm_detach, drm_activate);
#endif

1172
sys/dev/pci/drm/radeon_drv.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,249 @@
/* radeon_irq.c -- IRQ handling for radeon -*- linux-c -*- */
/*-
* Copyright (C) The Weather Channel, Inc. 2002. All Rights Reserved.
*
* The Weather Channel (TM) funded Tungsten Graphics to develop the
* initial release of the Radeon 8500 driver under the XFree86 license.
* This notice must be preserved.
*
* 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:
* Keith Whitwell <keith@tungstengraphics.com>
* Michel D<EFBFBD>zer <michel@daenzer.net>
*/
#include <sys/cdefs.h>
/*
__FBSDID("$FreeBSD: src/sys/dev/drm/radeon_irq.c,v 1.7 2005/11/28 23:13:54 anholt Exp $");
*/
#include "drmP.h"
#include "drm.h"
#include "radeon_drm.h"
#include "radeon_drv.h"
static __inline__ u32 radeon_acknowledge_irqs(drm_radeon_private_t * dev_priv,
u32 mask)
{
u32 irqs = RADEON_READ(RADEON_GEN_INT_STATUS) & mask;
if (irqs)
RADEON_WRITE(RADEON_GEN_INT_STATUS, irqs);
return irqs;
}
/* Interrupts - Used for device synchronization and flushing in the
* following circumstances:
*
* - Exclusive FB access with hw idle:
* - Wait for GUI Idle (?) interrupt, then do normal flush.
*
* - Frame throttling, NV_fence:
* - Drop marker irq's into command stream ahead of time.
* - Wait on irq's with lock *not held*
* - Check each for termination condition
*
* - Internally in cp_getbuffer, etc:
* - as above, but wait with lock held???
*
* NOTE: These functions are misleadingly named -- the irq's aren't
* tied to dma at all, this is just a hangover from dri prehistory.
*/
irqreturn_t radeon_driver_irq_handler(DRM_IRQ_ARGS)
{
drm_device_t *dev = (drm_device_t *) arg;
drm_radeon_private_t *dev_priv =
(drm_radeon_private_t *) dev->dev_private;
u32 stat;
/* Only consider the bits we're interested in - others could be used
* outside the DRM
*/
stat = radeon_acknowledge_irqs(dev_priv, (RADEON_SW_INT_TEST_ACK |
RADEON_CRTC_VBLANK_STAT));
if (!stat)
return IRQ_NONE;
/* SW interrupt */
if (stat & RADEON_SW_INT_TEST) {
DRM_WAKEUP(&dev_priv->swi_queue);
}
/* VBLANK interrupt */
if (stat & RADEON_CRTC_VBLANK_STAT) {
atomic_inc(&dev->vbl_received);
DRM_WAKEUP(&dev->vbl_queue);
drm_vbl_send_signals(dev);
}
return IRQ_HANDLED;
}
static int radeon_emit_irq(drm_device_t * dev)
{
drm_radeon_private_t *dev_priv = dev->dev_private;
unsigned int ret;
RING_LOCALS;
atomic_inc(&dev_priv->swi_emitted);
ret = atomic_read(&dev_priv->swi_emitted);
BEGIN_RING(4);
OUT_RING_REG(RADEON_LAST_SWI_REG, ret);
OUT_RING_REG(RADEON_GEN_INT_STATUS, RADEON_SW_INT_FIRE);
ADVANCE_RING();
COMMIT_RING();
return ret;
}
static int radeon_wait_irq(drm_device_t * dev, int swi_nr)
{
drm_radeon_private_t *dev_priv =
(drm_radeon_private_t *) dev->dev_private;
int ret = 0;
if (RADEON_READ(RADEON_LAST_SWI_REG) >= swi_nr)
return 0;
dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;
DRM_WAIT_ON(ret, dev_priv->swi_queue, 3 * DRM_HZ,
RADEON_READ(RADEON_LAST_SWI_REG) >= swi_nr);
return ret;
}
int radeon_driver_vblank_wait(drm_device_t * dev, unsigned int *sequence)
{
drm_radeon_private_t *dev_priv =
(drm_radeon_private_t *) dev->dev_private;
unsigned int cur_vblank;
int ret = 0;
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
return DRM_ERR(EINVAL);
}
radeon_acknowledge_irqs(dev_priv, RADEON_CRTC_VBLANK_STAT);
dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;
/* Assume that the user has missed the current sequence number
* by about a day rather than she wants to wait for years
* using vertical blanks...
*/
DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
(((cur_vblank = atomic_read(&dev->vbl_received))
- *sequence) <= (1 << 23)));
*sequence = cur_vblank;
return ret;
}
/* Needs the lock as it touches the ring.
*/
int radeon_irq_emit(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_radeon_private_t *dev_priv = dev->dev_private;
drm_radeon_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 DRM_ERR(EINVAL);
}
DRM_COPY_FROM_USER_IOCTL(emit, (drm_radeon_irq_emit_t __user *) data,
sizeof(emit));
result = radeon_emit_irq(dev);
if (DRM_COPY_TO_USER(emit.irq_seq, &result, sizeof(int))) {
DRM_ERROR("copy_to_user\n");
return DRM_ERR(EFAULT);
}
return 0;
}
/* Doesn't need the hardware lock.
*/
int radeon_irq_wait(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_radeon_private_t *dev_priv = dev->dev_private;
drm_radeon_irq_wait_t irqwait;
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
return DRM_ERR(EINVAL);
}
DRM_COPY_FROM_USER_IOCTL(irqwait, (drm_radeon_irq_wait_t __user *) data,
sizeof(irqwait));
return radeon_wait_irq(dev, irqwait.irq_seq);
}
/* drm_dma.h hooks
*/
void radeon_driver_irq_preinstall(drm_device_t * dev)
{
drm_radeon_private_t *dev_priv =
(drm_radeon_private_t *) dev->dev_private;
/* Disable *all* interrupts */
RADEON_WRITE(RADEON_GEN_INT_CNTL, 0);
/* Clear bits if they're already high */
radeon_acknowledge_irqs(dev_priv, (RADEON_SW_INT_TEST_ACK |
RADEON_CRTC_VBLANK_STAT));
}
void radeon_driver_irq_postinstall(drm_device_t * dev)
{
drm_radeon_private_t *dev_priv =
(drm_radeon_private_t *) dev->dev_private;
atomic_set(&dev_priv->swi_emitted, 0);
DRM_INIT_WAITQUEUE(&dev_priv->swi_queue);
/* Turn on SW and VBL ints */
RADEON_WRITE(RADEON_GEN_INT_CNTL,
RADEON_CRTC_VBLANK_MASK | RADEON_SW_INT_ENABLE);
}
void radeon_driver_irq_uninstall(drm_device_t * dev)
{
drm_radeon_private_t *dev_priv =
(drm_radeon_private_t *) dev->dev_private;
if (!dev_priv)
return;
/* Disable *all* interrupts */
RADEON_WRITE(RADEON_GEN_INT_CNTL, 0);
}

View File

@ -0,0 +1,319 @@
/* radeon_mem.c -- Simple GART/fb memory manager for radeon -*- linux-c -*- */
/*-
* Copyright (C) The Weather Channel, Inc. 2002. All Rights Reserved.
*
* The Weather Channel (TM) funded Tungsten Graphics to develop the
* initial release of the Radeon 8500 driver under the XFree86 license.
* This notice must be preserved.
*
* 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:
* Keith Whitwell <keith@tungstengraphics.com>
*/
#include <sys/cdefs.h>
/*
__FBSDID("$FreeBSD: src/sys/dev/drm/radeon_mem.c,v 1.8 2005/11/28 23:13:54 anholt Exp $");
*/
#include "drmP.h"
#include "drm.h"
#include "radeon_drm.h"
#include "radeon_drv.h"
/* Very simple allocator for GART memory, working on a static range
* already mapped into each client's address space.
*/
static struct mem_block *split_block(struct mem_block *p, int start, int size,
DRMFILE filp)
{
/* Maybe cut off the start of an existing block */
if (start > p->start) {
struct mem_block *newblock =
drm_alloc(sizeof(*newblock), DRM_MEM_BUFS);
if (!newblock)
goto out;
newblock->start = start;
newblock->size = p->size - (start - p->start);
newblock->filp = NULL;
newblock->next = p->next;
newblock->prev = p;
p->next->prev = newblock;
p->next = newblock;
p->size -= newblock->size;
p = newblock;
}
/* Maybe cut off the end of an existing block */
if (size < p->size) {
struct mem_block *newblock =
drm_alloc(sizeof(*newblock), DRM_MEM_BUFS);
if (!newblock)
goto out;
newblock->start = start + size;
newblock->size = p->size - size;
newblock->filp = NULL;
newblock->next = p->next;
newblock->prev = p;
p->next->prev = newblock;
p->next = newblock;
p->size = size;
}
out:
/* Our block is in the middle */
p->filp = filp;
return p;
}
static struct mem_block *alloc_block(struct mem_block *heap, int size,
int align2, DRMFILE filp)
{
struct mem_block *p;
int mask = (1 << align2) - 1;
list_for_each(p, heap) {
int start = (p->start + mask) & ~mask;
if (p->filp == 0 && start + size <= p->start + p->size)
return split_block(p, start, size, filp);
}
return NULL;
}
static struct mem_block *find_block(struct mem_block *heap, int start)
{
struct mem_block *p;
list_for_each(p, heap)
if (p->start == start)
return p;
return NULL;
}
static void free_block(struct mem_block *p)
{
p->filp = NULL;
/* Assumes a single contiguous range. Needs a special filp in
* 'heap' to stop it being subsumed.
*/
if (p->next->filp == 0) {
struct mem_block *q = p->next;
p->size += q->size;
p->next = q->next;
p->next->prev = p;
drm_free(q, sizeof(*q), DRM_MEM_BUFS);
}
if (p->prev->filp == 0) {
struct mem_block *q = p->prev;
q->size += p->size;
q->next = p->next;
q->next->prev = q;
drm_free(p, sizeof(*q), DRM_MEM_BUFS);
}
}
/* Initialize. How to check for an uninitialized heap?
*/
static int init_heap(struct mem_block **heap, int start, int size)
{
struct mem_block *blocks = drm_alloc(sizeof(*blocks), DRM_MEM_BUFS);
if (!blocks)
return DRM_ERR(ENOMEM);
*heap = drm_alloc(sizeof(**heap), DRM_MEM_BUFS);
if (!*heap) {
drm_free(blocks, sizeof(*blocks), DRM_MEM_BUFS);
return DRM_ERR(ENOMEM);
}
blocks->start = start;
blocks->size = size;
blocks->filp = NULL;
blocks->next = blocks->prev = *heap;
memset(*heap, 0, sizeof(**heap));
(*heap)->filp = (DRMFILE) - 1;
(*heap)->next = (*heap)->prev = blocks;
return 0;
}
/* Free all blocks associated with the releasing file.
*/
void radeon_mem_release(DRMFILE filp, struct mem_block *heap)
{
struct mem_block *p;
if (!heap || !heap->next)
return;
list_for_each(p, heap) {
if (p->filp == filp)
p->filp = NULL;
}
/* Assumes a single contiguous range. Needs a special filp in
* 'heap' to stop it being subsumed.
*/
list_for_each(p, heap) {
while (p->filp == 0 && p->next->filp == 0) {
struct mem_block *q = p->next;
p->size += q->size;
p->next = q->next;
p->next->prev = p;
drm_free(q, sizeof(*q), DRM_MEM_DRIVER);
}
}
}
/* Shutdown.
*/
void radeon_mem_takedown(struct mem_block **heap)
{
struct mem_block *p;
if (!*heap)
return;
for (p = (*heap)->next; p != *heap;) {
struct mem_block *q = p;
p = p->next;
drm_free(q, sizeof(*q), DRM_MEM_DRIVER);
}
drm_free(*heap, sizeof(**heap), DRM_MEM_DRIVER);
*heap = NULL;
}
/* IOCTL HANDLERS */
static struct mem_block **get_heap(drm_radeon_private_t * dev_priv, int region)
{
switch (region) {
case RADEON_MEM_REGION_GART:
return &dev_priv->gart_heap;
case RADEON_MEM_REGION_FB:
return &dev_priv->fb_heap;
default:
return NULL;
}
}
int radeon_mem_alloc(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_radeon_private_t *dev_priv = dev->dev_private;
drm_radeon_mem_alloc_t alloc;
struct mem_block *block, **heap;
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
return DRM_ERR(EINVAL);
}
DRM_COPY_FROM_USER_IOCTL(alloc, (drm_radeon_mem_alloc_t __user *) data,
sizeof(alloc));
heap = get_heap(dev_priv, alloc.region);
if (!heap || !*heap)
return DRM_ERR(EFAULT);
/* Make things easier on ourselves: all allocations at least
* 4k aligned.
*/
if (alloc.alignment < 12)
alloc.alignment = 12;
block = alloc_block(*heap, alloc.size, alloc.alignment, filp);
if (!block)
return DRM_ERR(ENOMEM);
if (DRM_COPY_TO_USER(alloc.region_offset, &block->start, sizeof(int))) {
DRM_ERROR("copy_to_user\n");
return DRM_ERR(EFAULT);
}
return 0;
}
int radeon_mem_free(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_radeon_private_t *dev_priv = dev->dev_private;
drm_radeon_mem_free_t memfree;
struct mem_block *block, **heap;
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
return DRM_ERR(EINVAL);
}
DRM_COPY_FROM_USER_IOCTL(memfree, (drm_radeon_mem_free_t __user *) data,
sizeof(memfree));
heap = get_heap(dev_priv, memfree.region);
if (!heap || !*heap)
return DRM_ERR(EFAULT);
block = find_block(*heap, memfree.region_offset);
if (!block)
return DRM_ERR(EFAULT);
if (block->filp != filp)
return DRM_ERR(EPERM);
free_block(block);
return 0;
}
int radeon_mem_init_heap(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_radeon_private_t *dev_priv = dev->dev_private;
drm_radeon_mem_init_heap_t initheap;
struct mem_block **heap;
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
return DRM_ERR(EINVAL);
}
DRM_COPY_FROM_USER_IOCTL(initheap,
(drm_radeon_mem_init_heap_t __user *) data,
sizeof(initheap));
heap = get_heap(dev_priv, initheap.region);
if (!heap)
return DRM_ERR(EFAULT);
if (*heap) {
DRM_ERROR("heap already initialized?");
return DRM_ERR(EFAULT);
}
return init_heap(heap, initheap.start, initheap.size);
}

File diff suppressed because it is too large Load Diff

1113
sys/dev/pci/drm/savage_bci.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,214 @@
/* savage_drm.h -- Public header for the savage driver
*
* Copyright 2004 Felix Kuehling
* 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 FELIX KUEHLING 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 <sys/cdefs.h>
/*
__FBSDID("$FreeBSD: src/sys/dev/drm/savage_drm.h,v 1.2 2005/11/28 23:13:55 anholt Exp $");
*/
#ifndef __SAVAGE_DRM_H__
#define __SAVAGE_DRM_H__
#ifndef __SAVAGE_SAREA_DEFINES__
#define __SAVAGE_SAREA_DEFINES__
/* 2 heaps (1 for card, 1 for agp), each divided into upto 128
* regions, subject to a minimum region size of (1<<16) == 64k.
*
* Clients may subdivide regions internally, but when sharing between
* clients, the region size is the minimum granularity.
*/
#define SAVAGE_CARD_HEAP 0
#define SAVAGE_AGP_HEAP 1
#define SAVAGE_NR_TEX_HEAPS 2
#define SAVAGE_NR_TEX_REGIONS 16
#define SAVAGE_LOG_MIN_TEX_REGION_SIZE 16
#endif /* __SAVAGE_SAREA_DEFINES__ */
typedef struct _drm_savage_sarea {
/* LRU lists for texture memory in agp space and on the card.
*/
drm_tex_region_t texList[SAVAGE_NR_TEX_HEAPS][SAVAGE_NR_TEX_REGIONS+1];
unsigned int texAge[SAVAGE_NR_TEX_HEAPS];
/* Mechanism to validate card state.
*/
int ctxOwner;
} drm_savage_sarea_t, *drm_savage_sarea_ptr;
/* Savage-specific ioctls
*/
#define DRM_SAVAGE_BCI_INIT 0x00
#define DRM_SAVAGE_BCI_CMDBUF 0x01
#define DRM_SAVAGE_BCI_EVENT_EMIT 0x02
#define DRM_SAVAGE_BCI_EVENT_WAIT 0x03
#define DRM_IOCTL_SAVAGE_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_SAVAGE_BCI_INIT, drm_savage_init_t)
#define DRM_IOCTL_SAVAGE_CMDBUF DRM_IOW( DRM_COMMAND_BASE + DRM_SAVAGE_BCI_CMDBUF, drm_savage_cmdbuf_t)
#define DRM_IOCTL_SAVAGE_EVENT_EMIT DRM_IOWR(DRM_COMMAND_BASE + DRM_SAVAGE_BCI_EVENT_EMIT, drm_savage_event_emit_t)
#define DRM_IOCTL_SAVAGE_EVENT_WAIT DRM_IOW( DRM_COMMAND_BASE + DRM_SAVAGE_BCI_EVENT_WAIT, drm_savage_event_wait_t)
#define SAVAGE_DMA_PCI 1
#define SAVAGE_DMA_AGP 3
typedef struct drm_savage_init {
enum {
SAVAGE_INIT_BCI = 1,
SAVAGE_CLEANUP_BCI = 2
} func;
unsigned int sarea_priv_offset;
/* some parameters */
unsigned int cob_size;
unsigned int bci_threshold_lo, bci_threshold_hi;
unsigned int dma_type;
/* frame buffer layout */
unsigned int fb_bpp;
unsigned int front_offset, front_pitch;
unsigned int back_offset, back_pitch;
unsigned int depth_bpp;
unsigned int depth_offset, depth_pitch;
/* local textures */
unsigned int texture_offset;
unsigned int texture_size;
/* physical locations of non-permanent maps */
unsigned long status_offset;
unsigned long buffers_offset;
unsigned long agp_textures_offset;
unsigned long cmd_dma_offset;
} drm_savage_init_t;
typedef union drm_savage_cmd_header drm_savage_cmd_header_t;
typedef struct drm_savage_cmdbuf {
/* command buffer in client's address space */
drm_savage_cmd_header_t __user *cmd_addr;
unsigned int size; /* size of the command buffer in 64bit units */
unsigned int dma_idx; /* DMA buffer index to use */
int discard; /* discard DMA buffer when done */
/* vertex buffer in client's address space */
unsigned int __user *vb_addr;
unsigned int vb_size; /* size of client vertex buffer in bytes */
unsigned int vb_stride; /* stride of vertices in 32bit words */
/* boxes in client's address space */
drm_clip_rect_t __user *box_addr;
unsigned int nbox; /* number of clipping boxes */
} drm_savage_cmdbuf_t;
#define SAVAGE_WAIT_2D 0x1 /* wait for 2D idle before updating event tag */
#define SAVAGE_WAIT_3D 0x2 /* wait for 3D idle before updating event tag */
#define SAVAGE_WAIT_IRQ 0x4 /* emit or wait for IRQ, not implemented yet */
typedef struct drm_savage_event {
unsigned int count;
unsigned int flags;
} drm_savage_event_emit_t, drm_savage_event_wait_t;
/* Commands for the cmdbuf ioctl
*/
#define SAVAGE_CMD_STATE 0 /* a range of state registers */
#define SAVAGE_CMD_DMA_PRIM 1 /* vertices from DMA buffer */
#define SAVAGE_CMD_VB_PRIM 2 /* vertices from client vertex buffer */
#define SAVAGE_CMD_DMA_IDX 3 /* indexed vertices from DMA buffer */
#define SAVAGE_CMD_VB_IDX 4 /* indexed vertices client vertex buffer */
#define SAVAGE_CMD_CLEAR 5 /* clear buffers */
#define SAVAGE_CMD_SWAP 6 /* swap buffers */
/* Primitive types
*/
#define SAVAGE_PRIM_TRILIST 0 /* triangle list */
#define SAVAGE_PRIM_TRISTRIP 1 /* triangle strip */
#define SAVAGE_PRIM_TRIFAN 2 /* triangle fan */
#define SAVAGE_PRIM_TRILIST_201 3 /* reorder verts for correct flat
* shading on s3d */
/* Skip flags (vertex format)
*/
#define SAVAGE_SKIP_Z 0x01
#define SAVAGE_SKIP_W 0x02
#define SAVAGE_SKIP_C0 0x04
#define SAVAGE_SKIP_C1 0x08
#define SAVAGE_SKIP_S0 0x10
#define SAVAGE_SKIP_T0 0x20
#define SAVAGE_SKIP_ST0 0x30
#define SAVAGE_SKIP_S1 0x40
#define SAVAGE_SKIP_T1 0x80
#define SAVAGE_SKIP_ST1 0xc0
#define SAVAGE_SKIP_ALL_S3D 0x3f
#define SAVAGE_SKIP_ALL_S4 0xff
/* Buffer names for clear command
*/
#define SAVAGE_FRONT 0x1
#define SAVAGE_BACK 0x2
#define SAVAGE_DEPTH 0x4
/* 64-bit command header
*/
union drm_savage_cmd_header {
struct {
unsigned char cmd; /* command */
unsigned char pad0;
unsigned short pad1;
unsigned short pad2;
unsigned short pad3;
} cmd; /* generic */
struct {
unsigned char cmd;
unsigned char global; /* need idle engine? */
unsigned short count; /* number of consecutive registers */
unsigned short start; /* first register */
unsigned short pad3;
} state; /* SAVAGE_CMD_STATE */
struct {
unsigned char cmd;
unsigned char prim; /* primitive type */
unsigned short skip; /* vertex format (skip flags) */
unsigned short count; /* number of vertices */
unsigned short start; /* first vertex in DMA/vertex buffer */
} prim; /* SAVAGE_CMD_DMA_PRIM, SAVAGE_CMD_VB_PRIM */
struct {
unsigned char cmd;
unsigned char prim;
unsigned short skip;
unsigned short count; /* number of indices that follow */
unsigned short pad3;
} idx; /* SAVAGE_CMD_DMA_IDX, SAVAGE_CMD_VB_IDX */
struct {
unsigned char cmd;
unsigned char pad0;
unsigned short pad1;
unsigned int flags;
} clear0; /* SAVAGE_CMD_CLEAR */
struct {
unsigned int mask;
unsigned int value;
} clear1; /* SAVAGE_CMD_CLEAR data */
};
#endif

View File

@ -0,0 +1,133 @@
/* savage_drv.c -- Savage DRI driver
*/
/*-
* Copyright 2005 Eric Anholt
* 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
* ERIC ANHOLT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* Authors:
* Eric Anholt <anholt@FreeBSD.org>
*/
#include <sys/cdefs.h>
/*
__FBSDID("$FreeBSD: src/sys/dev/drm/savage_drv.c,v 1.3 2005/12/20 22:44:36 jhb Exp $");
*/
#include "drmP.h"
#include "drm.h"
#include "savage_drm.h"
#include "savage_drv.h"
#include "drm_pciids.h"
/* drv_PCI_IDs comes from drm_pciids.h, generated from drm_pciids.txt. */
static drm_pci_id_list_t savage_pciidlist[] = {
savage_PCI_IDS
};
static void savage_configure(drm_device_t *dev)
{
dev->driver.buf_priv_size = sizeof(drm_savage_buf_priv_t);
dev->driver.load = savage_driver_load;
dev->driver.firstopen = savage_driver_firstopen;
dev->driver.lastclose = savage_driver_lastclose;
dev->driver.unload = savage_driver_unload;
dev->driver.reclaim_buffers_locked = savage_reclaim_buffers;
dev->driver.dma_ioctl = savage_bci_buffers;
dev->driver.ioctls = savage_ioctls;
dev->driver.max_ioctl = savage_max_ioctl;
dev->driver.name = DRIVER_NAME;
dev->driver.desc = DRIVER_DESC;
dev->driver.date = DRIVER_DATE;
dev->driver.major = DRIVER_MAJOR;
dev->driver.minor = DRIVER_MINOR;
dev->driver.patchlevel = DRIVER_PATCHLEVEL;
dev->driver.use_agp = 1;
dev->driver.use_mtrr = 1;
dev->driver.use_pci_dma = 1;
dev->driver.use_dma = 1;
}
#ifdef __FreeBSD__
static int
savage_probe(device_t dev)
{
return drm_probe(dev, savage_pciidlist);
}
static int
savage_attach(device_t nbdev)
{
drm_device_t *dev = device_get_softc(nbdev);
bzero(dev, sizeof(drm_device_t));
savage_configure(dev);
return drm_attach(nbdev, savage_pciidlist);
}
static device_method_t savage_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, savage_probe),
DEVMETHOD(device_attach, savage_attach),
DEVMETHOD(device_detach, drm_detach),
{ 0, 0 }
};
static driver_t savage_driver = {
"drm",
savage_methods,
sizeof(drm_device_t)
};
extern devclass_t drm_devclass;
#if __FreeBSD_version >= 700010
DRIVER_MODULE(savage, vgapci, savage_driver, drm_devclass, 0, 0);
#else
DRIVER_MODULE(savage, pci, savage_driver, drm_devclass, 0, 0);
#endif
MODULE_DEPEND(savage, drm, 1, 1, 1);
#elif defined(__NetBSD__) || defined(__OpenBSD__)
static int
savagedrm_probe(struct device *parent, struct cfdata *match, void *aux)
{
struct pci_attach_args *pa = aux;
return drm_probe(pa, savage_pciidlist);
}
static void
savagedrm_attach(struct device *parent, struct device *self, void *aux)
{
struct pci_attach_args *pa = aux;
drm_device_t *dev = (drm_device_t *)self;
savage_configure(dev);
return drm_attach(self, pa, savage_pciidlist);
}
CFATTACH_DECL(savagedrm, sizeof(drm_device_t), savagedrm_probe, savagedrm_attach,
drm_detach, drm_activate);
#endif

View File

@ -0,0 +1,580 @@
/* savage_drv.h -- Private header for the savage driver */
/*-
* Copyright 2004 Felix Kuehling
* 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 FELIX KUEHLING 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 <sys/cdefs.h>
/*
__FBSDID("$FreeBSD: src/sys/dev/drm/savage_drv.h,v 1.2 2005/11/28 23:13:55 anholt Exp $");
*/
#ifndef __SAVAGE_DRV_H__
#define __SAVAGE_DRV_H__
#define DRIVER_AUTHOR "Felix Kuehling"
#define DRIVER_NAME "savage"
#define DRIVER_DESC "Savage3D/MX/IX, Savage4, SuperSavage, Twister, ProSavage[DDR]"
#define DRIVER_DATE "20050313"
#define DRIVER_MAJOR 2
#define DRIVER_MINOR 4
#define DRIVER_PATCHLEVEL 1
/* Interface history:
*
* 1.x The DRM driver from the VIA/S3 code drop, basically a dummy
* 2.0 The first real DRM
* 2.1 Scissors registers managed by the DRM, 3D operations clipped by
* cliprects of the cmdbuf ioctl
* 2.2 Implemented SAVAGE_CMD_DMA_IDX and SAVAGE_CMD_VB_IDX
* 2.3 Event counters used by BCI_EVENT_EMIT/WAIT ioctls are now 32 bits
* wide and thus very long lived (unlikely to ever wrap). The size
* in the struct was 32 bits before, but only 16 bits were used
* 2.4 Implemented command DMA. Now drm_savage_init_t.cmd_dma_offset is
* actually used
*/
typedef struct drm_savage_age {
uint16_t event;
unsigned int wrap;
} drm_savage_age_t;
typedef struct drm_savage_buf_priv {
struct drm_savage_buf_priv *next;
struct drm_savage_buf_priv *prev;
drm_savage_age_t age;
drm_buf_t *buf;
} drm_savage_buf_priv_t;
typedef struct drm_savage_dma_page {
drm_savage_age_t age;
unsigned int used, flushed;
} drm_savage_dma_page_t;
#define SAVAGE_DMA_PAGE_SIZE 1024 /* in dwords */
/* Fake DMA buffer size in bytes. 4 pages. Allows a maximum command
* size of 16kbytes or 4k entries. Minimum requirement would be
* 10kbytes for 255 40-byte vertices in one drawing command. */
#define SAVAGE_FAKE_DMA_SIZE (SAVAGE_DMA_PAGE_SIZE*4*4)
/* interesting bits of hardware state that are saved in dev_priv */
typedef union {
struct drm_savage_common_state {
uint32_t vbaddr;
} common;
struct {
unsigned char pad[sizeof(struct drm_savage_common_state)];
uint32_t texctrl, texaddr;
uint32_t scstart, new_scstart;
uint32_t scend, new_scend;
} s3d;
struct {
unsigned char pad[sizeof(struct drm_savage_common_state)];
uint32_t texdescr, texaddr0, texaddr1;
uint32_t drawctrl0, new_drawctrl0;
uint32_t drawctrl1, new_drawctrl1;
} s4;
} drm_savage_state_t;
/* these chip tags should match the ones in the 2D driver in savage_regs.h. */
enum savage_family {
S3_UNKNOWN = 0,
S3_SAVAGE3D,
S3_SAVAGE_MX,
S3_SAVAGE4,
S3_PROSAVAGE,
S3_TWISTER,
S3_PROSAVAGEDDR,
S3_SUPERSAVAGE,
S3_SAVAGE2000,
S3_LAST
};
extern drm_ioctl_desc_t savage_ioctls[];
extern int savage_max_ioctl;
#define S3_SAVAGE3D_SERIES(chip) ((chip>=S3_SAVAGE3D) && (chip<=S3_SAVAGE_MX))
#define S3_SAVAGE4_SERIES(chip) ((chip==S3_SAVAGE4) \
|| (chip==S3_PROSAVAGE) \
|| (chip==S3_TWISTER) \
|| (chip==S3_PROSAVAGEDDR))
#define S3_SAVAGE_MOBILE_SERIES(chip) ((chip==S3_SAVAGE_MX) || (chip==S3_SUPERSAVAGE))
#define S3_SAVAGE_SERIES(chip) ((chip>=S3_SAVAGE3D) && (chip<=S3_SAVAGE2000))
#define S3_MOBILE_TWISTER_SERIES(chip) ((chip==S3_TWISTER) \
||(chip==S3_PROSAVAGEDDR))
/* flags */
#define SAVAGE_IS_AGP 1
typedef struct drm_savage_private {
drm_savage_sarea_t *sarea_priv;
drm_savage_buf_priv_t head, tail;
/* who am I? */
enum savage_family chipset;
unsigned int cob_size;
unsigned int bci_threshold_lo, bci_threshold_hi;
unsigned int dma_type;
/* frame buffer layout */
unsigned int fb_bpp;
unsigned int front_offset, front_pitch;
unsigned int back_offset, back_pitch;
unsigned int depth_bpp;
unsigned int depth_offset, depth_pitch;
/* bitmap descriptors for swap and clear */
unsigned int front_bd, back_bd, depth_bd;
/* local textures */
unsigned int texture_offset;
unsigned int texture_size;
/* memory regions in physical memory */
drm_local_map_t *sarea;
drm_local_map_t *mmio;
drm_local_map_t *fb;
drm_local_map_t *aperture;
drm_local_map_t *status;
drm_local_map_t *agp_textures;
drm_local_map_t *cmd_dma;
drm_local_map_t fake_dma;
struct {
int handle;
unsigned long base, size;
} mtrr[3];
/* BCI and status-related stuff */
volatile uint32_t *status_ptr, *bci_ptr;
uint32_t status_used_mask;
uint16_t event_counter;
unsigned int event_wrap;
/* Savage4 command DMA */
drm_savage_dma_page_t *dma_pages;
unsigned int nr_dma_pages, first_dma_page, current_dma_page;
drm_savage_age_t last_dma_age;
/* saved hw state for global/local check on S3D */
uint32_t hw_draw_ctrl, hw_zbuf_ctrl;
/* and for scissors (global, so don't emit if not changed) */
uint32_t hw_scissors_start, hw_scissors_end;
drm_savage_state_t state;
/* after emitting a wait cmd Savage3D needs 63 nops before next DMA */
unsigned int waiting;
/* config/hardware-dependent function pointers */
int (*wait_fifo)(struct drm_savage_private *dev_priv, unsigned int n);
int (*wait_evnt)(struct drm_savage_private *dev_priv, uint16_t e);
/* Err, there is a macro wait_event in include/linux/wait.h.
* Avoid unwanted macro expansion. */
void (*emit_clip_rect)(struct drm_savage_private *dev_priv,
const drm_clip_rect_t *pbox);
void (*dma_flush)(struct drm_savage_private *dev_priv);
} drm_savage_private_t;
/* ioctls */
extern int savage_bci_cmdbuf(DRM_IOCTL_ARGS);
extern int savage_bci_buffers(DRM_IOCTL_ARGS);
/* BCI functions */
extern uint16_t savage_bci_emit_event(drm_savage_private_t *dev_priv,
unsigned int flags);
extern void savage_freelist_put(drm_device_t *dev, drm_buf_t *buf);
extern void savage_dma_reset(drm_savage_private_t *dev_priv);
extern void savage_dma_wait(drm_savage_private_t *dev_priv, unsigned int page);
extern uint32_t *savage_dma_alloc(drm_savage_private_t *dev_priv,
unsigned int n);
extern int savage_driver_load(drm_device_t *dev, unsigned long chipset);
extern int savage_driver_firstopen(drm_device_t *dev);
extern void savage_driver_lastclose(drm_device_t *dev);
extern int savage_driver_unload(drm_device_t *dev);
extern int savage_do_cleanup_bci(drm_device_t *dev);
extern void savage_reclaim_buffers(drm_device_t *dev, DRMFILE filp);
/* state functions */
extern void savage_emit_clip_rect_s3d(drm_savage_private_t *dev_priv,
const drm_clip_rect_t *pbox);
extern void savage_emit_clip_rect_s4(drm_savage_private_t *dev_priv,
const drm_clip_rect_t *pbox);
#define SAVAGE_FB_SIZE_S3 0x01000000 /* 16MB */
#define SAVAGE_FB_SIZE_S4 0x02000000 /* 32MB */
#define SAVAGE_MMIO_SIZE 0x00080000 /* 512kB */
#define SAVAGE_APERTURE_OFFSET 0x02000000 /* 32MB */
#define SAVAGE_APERTURE_SIZE 0x05000000 /* 5 tiled surfaces, 16MB each */
#define SAVAGE_BCI_OFFSET 0x00010000 /* offset of the BCI region
* inside the MMIO region */
#define SAVAGE_BCI_FIFO_SIZE 32 /* number of entries in on-chip
* BCI FIFO */
/*
* MMIO registers
*/
#define SAVAGE_STATUS_WORD0 0x48C00
#define SAVAGE_STATUS_WORD1 0x48C04
#define SAVAGE_ALT_STATUS_WORD0 0x48C60
#define SAVAGE_FIFO_USED_MASK_S3D 0x0001ffff
#define SAVAGE_FIFO_USED_MASK_S4 0x001fffff
/* Copied from savage_bci.h in the 2D driver with some renaming. */
/* Bitmap descriptors */
#define SAVAGE_BD_STRIDE_SHIFT 0
#define SAVAGE_BD_BPP_SHIFT 16
#define SAVAGE_BD_TILE_SHIFT 24
#define SAVAGE_BD_BW_DISABLE (1<<28)
/* common: */
#define SAVAGE_BD_TILE_LINEAR 0
/* savage4, MX, IX, 3D */
#define SAVAGE_BD_TILE_16BPP 2
#define SAVAGE_BD_TILE_32BPP 3
/* twister, prosavage, DDR, supersavage, 2000 */
#define SAVAGE_BD_TILE_DEST 1
#define SAVAGE_BD_TILE_TEXTURE 2
/* GBD - BCI enable */
/* savage4, MX, IX, 3D */
#define SAVAGE_GBD_BCI_ENABLE 8
/* twister, prosavage, DDR, supersavage, 2000 */
#define SAVAGE_GBD_BCI_ENABLE_TWISTER 0
#define SAVAGE_GBD_BIG_ENDIAN 4
#define SAVAGE_GBD_LITTLE_ENDIAN 0
#define SAVAGE_GBD_64 1
/* Global Bitmap Descriptor */
#define SAVAGE_BCI_GLB_BD_LOW 0x8168
#define SAVAGE_BCI_GLB_BD_HIGH 0x816C
/*
* BCI registers
*/
/* Savage4/Twister/ProSavage 3D registers */
#define SAVAGE_DRAWLOCALCTRL_S4 0x1e
#define SAVAGE_TEXPALADDR_S4 0x1f
#define SAVAGE_TEXCTRL0_S4 0x20
#define SAVAGE_TEXCTRL1_S4 0x21
#define SAVAGE_TEXADDR0_S4 0x22
#define SAVAGE_TEXADDR1_S4 0x23
#define SAVAGE_TEXBLEND0_S4 0x24
#define SAVAGE_TEXBLEND1_S4 0x25
#define SAVAGE_TEXXPRCLR_S4 0x26 /* never used */
#define SAVAGE_TEXDESCR_S4 0x27
#define SAVAGE_FOGTABLE_S4 0x28
#define SAVAGE_FOGCTRL_S4 0x30
#define SAVAGE_STENCILCTRL_S4 0x31
#define SAVAGE_ZBUFCTRL_S4 0x32
#define SAVAGE_ZBUFOFF_S4 0x33
#define SAVAGE_DESTCTRL_S4 0x34
#define SAVAGE_DRAWCTRL0_S4 0x35
#define SAVAGE_DRAWCTRL1_S4 0x36
#define SAVAGE_ZWATERMARK_S4 0x37
#define SAVAGE_DESTTEXRWWATERMARK_S4 0x38
#define SAVAGE_TEXBLENDCOLOR_S4 0x39
/* Savage3D/MX/IX 3D registers */
#define SAVAGE_TEXPALADDR_S3D 0x18
#define SAVAGE_TEXXPRCLR_S3D 0x19 /* never used */
#define SAVAGE_TEXADDR_S3D 0x1A
#define SAVAGE_TEXDESCR_S3D 0x1B
#define SAVAGE_TEXCTRL_S3D 0x1C
#define SAVAGE_FOGTABLE_S3D 0x20
#define SAVAGE_FOGCTRL_S3D 0x30
#define SAVAGE_DRAWCTRL_S3D 0x31
#define SAVAGE_ZBUFCTRL_S3D 0x32
#define SAVAGE_ZBUFOFF_S3D 0x33
#define SAVAGE_DESTCTRL_S3D 0x34
#define SAVAGE_SCSTART_S3D 0x35
#define SAVAGE_SCEND_S3D 0x36
#define SAVAGE_ZWATERMARK_S3D 0x37
#define SAVAGE_DESTTEXRWWATERMARK_S3D 0x38
/* common stuff */
#define SAVAGE_VERTBUFADDR 0x3e
#define SAVAGE_BITPLANEWTMASK 0xd7
#define SAVAGE_DMABUFADDR 0x51
/* texture enable bits (needed for tex addr checking) */
#define SAVAGE_TEXCTRL_TEXEN_MASK 0x00010000 /* S3D */
#define SAVAGE_TEXDESCR_TEX0EN_MASK 0x02000000 /* S4 */
#define SAVAGE_TEXDESCR_TEX1EN_MASK 0x04000000 /* S4 */
/* Global fields in Savage4/Twister/ProSavage 3D registers:
*
* All texture registers and DrawLocalCtrl are local. All other
* registers are global. */
/* Global fields in Savage3D/MX/IX 3D registers:
*
* All texture registers are local. DrawCtrl and ZBufCtrl are
* partially local. All other registers are global.
*
* DrawCtrl global fields: cullMode, alphaTestCmpFunc, alphaTestEn, alphaRefVal
* ZBufCtrl global fields: zCmpFunc, zBufEn
*/
#define SAVAGE_DRAWCTRL_S3D_GLOBAL 0x03f3c00c
#define SAVAGE_ZBUFCTRL_S3D_GLOBAL 0x00000027
/* Masks for scissor bits (drawCtrl[01] on s4, scissorStart/End on s3d)
*/
#define SAVAGE_SCISSOR_MASK_S4 0x00fff7ff
#define SAVAGE_SCISSOR_MASK_S3D 0x07ff07ff
/*
* BCI commands
*/
#define BCI_CMD_NOP 0x40000000
#define BCI_CMD_RECT 0x48000000
#define BCI_CMD_RECT_XP 0x01000000
#define BCI_CMD_RECT_YP 0x02000000
#define BCI_CMD_SCANLINE 0x50000000
#define BCI_CMD_LINE 0x5C000000
#define BCI_CMD_LINE_LAST_PIXEL 0x58000000
#define BCI_CMD_BYTE_TEXT 0x63000000
#define BCI_CMD_NT_BYTE_TEXT 0x67000000
#define BCI_CMD_BIT_TEXT 0x6C000000
#define BCI_CMD_GET_ROP(cmd) (((cmd) >> 16) & 0xFF)
#define BCI_CMD_SET_ROP(cmd, rop) ((cmd) |= ((rop & 0xFF) << 16))
#define BCI_CMD_SEND_COLOR 0x00008000
#define BCI_CMD_CLIP_NONE 0x00000000
#define BCI_CMD_CLIP_CURRENT 0x00002000
#define BCI_CMD_CLIP_LR 0x00004000
#define BCI_CMD_CLIP_NEW 0x00006000
#define BCI_CMD_DEST_GBD 0x00000000
#define BCI_CMD_DEST_PBD 0x00000800
#define BCI_CMD_DEST_PBD_NEW 0x00000C00
#define BCI_CMD_DEST_SBD 0x00001000
#define BCI_CMD_DEST_SBD_NEW 0x00001400
#define BCI_CMD_SRC_TRANSPARENT 0x00000200
#define BCI_CMD_SRC_SOLID 0x00000000
#define BCI_CMD_SRC_GBD 0x00000020
#define BCI_CMD_SRC_COLOR 0x00000040
#define BCI_CMD_SRC_MONO 0x00000060
#define BCI_CMD_SRC_PBD_COLOR 0x00000080
#define BCI_CMD_SRC_PBD_MONO 0x000000A0
#define BCI_CMD_SRC_PBD_COLOR_NEW 0x000000C0
#define BCI_CMD_SRC_PBD_MONO_NEW 0x000000E0
#define BCI_CMD_SRC_SBD_COLOR 0x00000100
#define BCI_CMD_SRC_SBD_MONO 0x00000120
#define BCI_CMD_SRC_SBD_COLOR_NEW 0x00000140
#define BCI_CMD_SRC_SBD_MONO_NEW 0x00000160
#define BCI_CMD_PAT_TRANSPARENT 0x00000010
#define BCI_CMD_PAT_NONE 0x00000000
#define BCI_CMD_PAT_COLOR 0x00000002
#define BCI_CMD_PAT_MONO 0x00000003
#define BCI_CMD_PAT_PBD_COLOR 0x00000004
#define BCI_CMD_PAT_PBD_MONO 0x00000005
#define BCI_CMD_PAT_PBD_COLOR_NEW 0x00000006
#define BCI_CMD_PAT_PBD_MONO_NEW 0x00000007
#define BCI_CMD_PAT_SBD_COLOR 0x00000008
#define BCI_CMD_PAT_SBD_MONO 0x00000009
#define BCI_CMD_PAT_SBD_COLOR_NEW 0x0000000A
#define BCI_CMD_PAT_SBD_MONO_NEW 0x0000000B
#define BCI_BD_BW_DISABLE 0x10000000
#define BCI_BD_TILE_MASK 0x03000000
#define BCI_BD_TILE_NONE 0x00000000
#define BCI_BD_TILE_16 0x02000000
#define BCI_BD_TILE_32 0x03000000
#define BCI_BD_GET_BPP(bd) (((bd) >> 16) & 0xFF)
#define BCI_BD_SET_BPP(bd, bpp) ((bd) |= (((bpp) & 0xFF) << 16))
#define BCI_BD_GET_STRIDE(bd) ((bd) & 0xFFFF)
#define BCI_BD_SET_STRIDE(bd, st) ((bd) |= ((st) & 0xFFFF))
#define BCI_CMD_SET_REGISTER 0x96000000
#define BCI_CMD_WAIT 0xC0000000
#define BCI_CMD_WAIT_3D 0x00010000
#define BCI_CMD_WAIT_2D 0x00020000
#define BCI_CMD_UPDATE_EVENT_TAG 0x98000000
#define BCI_CMD_DRAW_PRIM 0x80000000
#define BCI_CMD_DRAW_INDEXED_PRIM 0x88000000
#define BCI_CMD_DRAW_CONT 0x01000000
#define BCI_CMD_DRAW_TRILIST 0x00000000
#define BCI_CMD_DRAW_TRISTRIP 0x02000000
#define BCI_CMD_DRAW_TRIFAN 0x04000000
#define BCI_CMD_DRAW_SKIPFLAGS 0x000000ff
#define BCI_CMD_DRAW_NO_Z 0x00000001
#define BCI_CMD_DRAW_NO_W 0x00000002
#define BCI_CMD_DRAW_NO_CD 0x00000004
#define BCI_CMD_DRAW_NO_CS 0x00000008
#define BCI_CMD_DRAW_NO_U0 0x00000010
#define BCI_CMD_DRAW_NO_V0 0x00000020
#define BCI_CMD_DRAW_NO_UV0 0x00000030
#define BCI_CMD_DRAW_NO_U1 0x00000040
#define BCI_CMD_DRAW_NO_V1 0x00000080
#define BCI_CMD_DRAW_NO_UV1 0x000000c0
#define BCI_CMD_DMA 0xa8000000
#define BCI_W_H(w, h) ((((h) << 16) | (w)) & 0x0FFF0FFF)
#define BCI_X_Y(x, y) ((((y) << 16) | (x)) & 0x0FFF0FFF)
#define BCI_X_W(x, y) ((((w) << 16) | (x)) & 0x0FFF0FFF)
#define BCI_CLIP_LR(l, r) ((((r) << 16) | (l)) & 0x0FFF0FFF)
#define BCI_CLIP_TL(t, l) ((((t) << 16) | (l)) & 0x0FFF0FFF)
#define BCI_CLIP_BR(b, r) ((((b) << 16) | (r)) & 0x0FFF0FFF)
#define BCI_LINE_X_Y(x, y) (((y) << 16) | ((x) & 0xFFFF))
#define BCI_LINE_STEPS(diag, axi) (((axi) << 16) | ((diag) & 0xFFFF))
#define BCI_LINE_MISC(maj, ym, xp, yp, err) \
(((maj) & 0x1FFF) | \
((ym) ? 1<<13 : 0) | \
((xp) ? 1<<14 : 0) | \
((yp) ? 1<<15 : 0) | \
((err) << 16))
/*
* common commands
*/
#define BCI_SET_REGISTERS( first, n ) \
BCI_WRITE(BCI_CMD_SET_REGISTER | \
((uint32_t)(n) & 0xff) << 16 | \
((uint32_t)(first) & 0xffff))
#define DMA_SET_REGISTERS( first, n ) \
DMA_WRITE(BCI_CMD_SET_REGISTER | \
((uint32_t)(n) & 0xff) << 16 | \
((uint32_t)(first) & 0xffff))
#define BCI_DRAW_PRIMITIVE(n, type, skip) \
BCI_WRITE(BCI_CMD_DRAW_PRIM | (type) | (skip) | \
((n) << 16))
#define DMA_DRAW_PRIMITIVE(n, type, skip) \
DMA_WRITE(BCI_CMD_DRAW_PRIM | (type) | (skip) | \
((n) << 16))
#define BCI_DRAW_INDICES_S3D(n, type, i0) \
BCI_WRITE(BCI_CMD_DRAW_INDEXED_PRIM | (type) | \
((n) << 16) | (i0))
#define BCI_DRAW_INDICES_S4(n, type, skip) \
BCI_WRITE(BCI_CMD_DRAW_INDEXED_PRIM | (type) | \
(skip) | ((n) << 16))
#define BCI_DMA(n) \
BCI_WRITE(BCI_CMD_DMA | (((n) >> 1) - 1))
/*
* access to MMIO
*/
#define SAVAGE_READ(reg) DRM_READ32( dev_priv->mmio, (reg) )
#define SAVAGE_WRITE(reg) DRM_WRITE32( dev_priv->mmio, (reg) )
/*
* access to the burst command interface (BCI)
*/
#define SAVAGE_BCI_DEBUG 1
#define BCI_LOCALS volatile uint32_t *bci_ptr;
#define BEGIN_BCI( n ) do { \
dev_priv->wait_fifo(dev_priv, (n)); \
bci_ptr = dev_priv->bci_ptr; \
} while(0)
#define BCI_WRITE( val ) *bci_ptr++ = (uint32_t)(val)
/*
* command DMA support
*/
#define SAVAGE_DMA_DEBUG 1
#define DMA_LOCALS uint32_t *dma_ptr;
#define BEGIN_DMA( n ) do { \
unsigned int cur = dev_priv->current_dma_page; \
unsigned int rest = SAVAGE_DMA_PAGE_SIZE - \
dev_priv->dma_pages[cur].used; \
if ((n) > rest) { \
dma_ptr = savage_dma_alloc(dev_priv, (n)); \
} else { /* fast path for small allocations */ \
dma_ptr = (uint32_t *)dev_priv->cmd_dma->handle + \
cur * SAVAGE_DMA_PAGE_SIZE + \
dev_priv->dma_pages[cur].used; \
if (dev_priv->dma_pages[cur].used == 0) \
savage_dma_wait(dev_priv, cur); \
dev_priv->dma_pages[cur].used += (n); \
} \
} while(0)
#define DMA_WRITE( val ) *dma_ptr++ = (uint32_t)(val)
#define DMA_COPY(src, n) do { \
memcpy(dma_ptr, (src), (n)*4); \
dma_ptr += n; \
} while(0)
#if SAVAGE_DMA_DEBUG
#define DMA_COMMIT() do { \
unsigned int cur = dev_priv->current_dma_page; \
uint32_t *expected = (uint32_t *)dev_priv->cmd_dma->handle + \
cur * SAVAGE_DMA_PAGE_SIZE + \
dev_priv->dma_pages[cur].used; \
if (dma_ptr != expected) { \
DRM_ERROR("DMA allocation and use don't match: " \
"%p != %p\n", expected, dma_ptr); \
savage_dma_reset(dev_priv); \
} \
} while(0)
#else
#define DMA_COMMIT() do {/* nothing */} while(0)
#endif
#define DMA_FLUSH() dev_priv->dma_flush(dev_priv)
/* Buffer aging via event tag
*/
#define UPDATE_EVENT_COUNTER( ) do { \
if (dev_priv->status_ptr) { \
uint16_t count; \
/* coordinate with Xserver */ \
count = dev_priv->status_ptr[1023]; \
if (count < dev_priv->event_counter) \
dev_priv->event_wrap++; \
dev_priv->event_counter = count; \
} \
} while(0)
#define SET_AGE( age, e, w ) do { \
(age)->event = e; \
(age)->wrap = w; \
} while(0)
#define TEST_AGE( age, e, w ) \
( (age)->wrap < (w) || ( (age)->wrap == (w) && (age)->event <= (e) ) )
#endif /* __SAVAGE_DRV_H__ */

File diff suppressed because it is too large Load Diff

72
sys/dev/pci/drm/sis_drm.h Normal file
View File

@ -0,0 +1,72 @@
/* sis_drv.h -- Private header for sis driver -*- linux-c -*- */
/*-
* Copyright 2005 Eric Anholt
* 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 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
#include <sys/cdefs.h>
/*
__FBSDID("$FreeBSD: src/sys/dev/drm/sis_drm.h,v 1.6 2005/11/28 23:13:55 anholt Exp $");
*/
#ifndef __SIS_DRM_H__
#define __SIS_DRM_H__
/* SiS specific ioctls */
#define NOT_USED_0_3
#define DRM_SIS_FB_ALLOC 0x04
#define DRM_SIS_FB_FREE 0x05
#define NOT_USED_6_12
#define DRM_SIS_AGP_INIT 0x13
#define DRM_SIS_AGP_ALLOC 0x14
#define DRM_SIS_AGP_FREE 0x15
#define DRM_SIS_FB_INIT 0x16
#define DRM_IOCTL_SIS_FB_ALLOC DRM_IOWR(DRM_COMMAND_BASE + DRM_SIS_FB_ALLOC, drm_sis_mem_t)
#define DRM_IOCTL_SIS_FB_FREE DRM_IOW( DRM_COMMAND_BASE + DRM_SIS_FB_FREE, drm_sis_mem_t)
#define DRM_IOCTL_SIS_AGP_INIT DRM_IOWR(DRM_COMMAND_BASE + DRM_SIS_AGP_INIT, drm_sis_agp_t)
#define DRM_IOCTL_SIS_AGP_ALLOC DRM_IOWR(DRM_COMMAND_BASE + DRM_SIS_AGP_ALLOC, drm_sis_mem_t)
#define DRM_IOCTL_SIS_AGP_FREE DRM_IOW( DRM_COMMAND_BASE + DRM_SIS_AGP_FREE, drm_sis_mem_t)
#define DRM_IOCTL_SIS_FB_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_SIS_FB_INIT, drm_sis_fb_t)
/*
#define DRM_IOCTL_SIS_FLIP DRM_IOW( 0x48, drm_sis_flip_t)
#define DRM_IOCTL_SIS_FLIP_INIT DRM_IO( 0x49)
#define DRM_IOCTL_SIS_FLIP_FINAL DRM_IO( 0x50)
*/
typedef struct {
int context;
unsigned int offset;
unsigned int size;
unsigned long free;
} drm_sis_mem_t;
typedef struct {
unsigned int offset, size;
} drm_sis_agp_t;
typedef struct {
unsigned int offset, size;
} drm_sis_fb_t;
#endif /* __SIS_DRM_H__ */

126
sys/dev/pci/drm/sis_drv.c Normal file
View File

@ -0,0 +1,126 @@
/* sis.c -- sis driver -*- linux-c -*-
*/
/*-
* 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.
*
*/
#include <sys/cdefs.h>
/*
__FBSDID("$FreeBSD: src/sys/dev/drm/sis_drv.c,v 1.7 2005/12/20 22:44:36 jhb Exp $");
*/
#include "drmP.h"
#include "sis_drm.h"
#include "sis_drv.h"
#include "drm_pciids.h"
/* drv_PCI_IDs comes from drm_pciids.h, generated from drm_pciids.txt. */
static drm_pci_id_list_t sis_pciidlist[] = {
sis_PCI_IDS
};
static void sis_configure(drm_device_t *dev)
{
dev->driver.buf_priv_size = 1; /* No dev_priv */
dev->driver.context_ctor = sis_init_context;
dev->driver.context_dtor = sis_final_context;
dev->driver.ioctls = sis_ioctls;
dev->driver.max_ioctl = sis_max_ioctl;
dev->driver.name = DRIVER_NAME;
dev->driver.desc = DRIVER_DESC;
dev->driver.date = DRIVER_DATE;
dev->driver.major = DRIVER_MAJOR;
dev->driver.minor = DRIVER_MINOR;
dev->driver.patchlevel = DRIVER_PATCHLEVEL;
dev->driver.use_agp = 1;
dev->driver.use_mtrr = 1;
}
#ifdef __FreeBSD__
static int
sis_probe(device_t dev)
{
return drm_probe(dev, sis_pciidlist);
}
static int
sis_attach(device_t nbdev)
{
drm_device_t *dev = device_get_softc(nbdev);
bzero(dev, sizeof(drm_device_t));
sis_configure(dev);
return drm_attach(nbdev, sis_pciidlist);
}
static device_method_t sis_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, sis_probe),
DEVMETHOD(device_attach, sis_attach),
DEVMETHOD(device_detach, drm_detach),
{ 0, 0 }
};
static driver_t sis_driver = {
"drm",
sis_methods,
sizeof(drm_device_t)
};
extern devclass_t drm_devclass;
#if __FreeBSD_version >= 700010
DRIVER_MODULE(sisdrm, vgapci, sis_driver, drm_devclass, 0, 0);
#else
DRIVER_MODULE(sisdrm, pci, sis_driver, drm_devclass, 0, 0);
#endif
MODULE_DEPEND(sisdrm, drm, 1, 1, 1);
#elif defined(__NetBSD__) || defined(__OpenBSD__)
static int
sisdrm_probe(struct device *parent, struct cfdata *match, void *aux)
{
struct pci_attach_args *pa = aux;
return drm_probe(pa, sis_pciidlist);
}
static void
sisdrm_attach(struct device *parent, struct device *self, void *aux)
{
struct pci_attach_args *pa = aux;
drm_device_t *dev = (drm_device_t *)self;
sis_configure(dev);
return drm_attach(self, pa, sis_pciidlist);
}
CFATTACH_DECL(sisdrm, sizeof(drm_device_t), sisdrm_probe, sisdrm_attach,
drm_detach, drm_activate);
#endif

60
sys/dev/pci/drm/sis_drv.h Normal file
View File

@ -0,0 +1,60 @@
/* sis_drv.h -- Private header for sis driver -*- linux-c -*- */
/*-
* 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.
*
*/
#include <sys/cdefs.h>
/*
__FBSDID("$FreeBSD: src/sys/dev/drm/sis_drv.h,v 1.4 2005/11/28 23:13:55 anholt Exp $");
*/
#ifndef _SIS_DRV_H_
#define _SIS_DRV_H_
/* General customization:
*/
#define DRIVER_AUTHOR "SIS"
#define DRIVER_NAME "sis"
#define DRIVER_DESC "SIS 300/630/540"
#define DRIVER_DATE "20030826"
#define DRIVER_MAJOR 1
#define DRIVER_MINOR 1
#define DRIVER_PATCHLEVEL 0
#include "sis_ds.h"
typedef struct drm_sis_private {
memHeap_t *AGPHeap;
memHeap_t *FBHeap;
} drm_sis_private_t;
extern int sis_init_context(drm_device_t * dev, int context);
extern int sis_final_context(drm_device_t * dev, int context);
extern drm_ioctl_desc_t sis_ioctls[];
extern int sis_max_ioctl;
#endif

304
sys/dev/pci/drm/sis_ds.c Normal file
View File

@ -0,0 +1,304 @@
/* sis_ds.c -- Private header for Direct Rendering Manager -*- linux-c -*-
* Created: Mon Jan 4 10:05:05 1999 by sclin@sis.com.tw
*
* Copyright 2000 Silicon Integrated Systems Corp, Inc., HsinChu, Taiwan.
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* Authors:
* Sung-Ching Lin <sclin@sis.com.tw>
*
*/
#include <sys/cdefs.h>
/*
__FBSDID("$FreeBSD: src/sys/dev/drm/sis_ds.c,v 1.5 2006/04/09 20:45:45 anholt Exp $");
*/
#include "drmP.h"
#include "drm.h"
#include "sis_ds.h"
/* Set Data Structure, not check repeated value
* temporarily used
*/
set_t *setInit(void)
{
int i;
set_t *set;
set = (set_t *) drm_alloc(sizeof(set_t), DRM_MEM_DRIVER);
if (set != NULL) {
for (i = 0; i < SET_SIZE; i++) {
set->list[i].free_next = i + 1;
set->list[i].alloc_next = -1;
}
set->list[SET_SIZE - 1].free_next = -1;
set->free = 0;
set->alloc = -1;
set->trace = -1;
}
return set;
}
int setAdd(set_t * set, ITEM_TYPE item)
{
int sfree = set->free;
if (sfree != -1) {
set->list[sfree].val = item;
set->free = set->list[sfree].free_next;
} else {
return 0;
}
set->list[sfree].alloc_next = set->alloc;
set->alloc = sfree;
set->list[sfree].free_next = -1;
return 1;
}
int setDel(set_t * set, ITEM_TYPE item)
{
int alloc = set->alloc;
int prev = -1;
while (alloc != -1) {
if (set->list[alloc].val == item) {
if (prev != -1)
set->list[prev].alloc_next =
set->list[alloc].alloc_next;
else
set->alloc = set->list[alloc].alloc_next;
break;
}
prev = alloc;
alloc = set->list[alloc].alloc_next;
}
if (alloc == -1)
return 0;
set->list[alloc].free_next = set->free;
set->free = alloc;
set->list[alloc].alloc_next = -1;
return 1;
}
/* setFirst -> setAdd -> setNext is wrong */
int setFirst(set_t * set, ITEM_TYPE * item)
{
if (set->alloc == -1)
return 0;
*item = set->list[set->alloc].val;
set->trace = set->list[set->alloc].alloc_next;
return 1;
}
int setNext(set_t * set, ITEM_TYPE * item)
{
if (set->trace == -1)
return 0;
*item = set->list[set->trace].val;
set->trace = set->list[set->trace].alloc_next;
return 1;
}
int setDestroy(set_t * set)
{
drm_free(set, sizeof(set_t), DRM_MEM_DRIVER);
return 1;
}
/*
* GLX Hardware Device Driver common code
* Copyright (C) 1999 Wittawat Yamwong
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* WITTAWAT YAMWONG, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#define ISFREE(bptr) ((bptr)->free)
memHeap_t *mmInit(int ofs, int size)
{
PMemBlock blocks;
if (size <= 0)
return NULL;
blocks = (TMemBlock *) drm_calloc(1, sizeof(TMemBlock), DRM_MEM_DRIVER);
if (blocks != NULL) {
blocks->ofs = ofs;
blocks->size = size;
blocks->free = 1;
return (memHeap_t *) blocks;
} else
return NULL;
}
/* Checks if a pointer 'b' is part of the heap 'heap' */
int mmBlockInHeap(memHeap_t * heap, PMemBlock b)
{
TMemBlock *p;
if (heap == NULL || b == NULL)
return 0;
p = heap;
while (p != NULL && p != b) {
p = p->next;
}
if (p == b)
return 1;
else
return 0;
}
static TMemBlock *SliceBlock(TMemBlock * p,
int startofs, int size,
int reserved, int alignment)
{
TMemBlock *newblock;
/* break left */
if (startofs > p->ofs) {
newblock = (TMemBlock *) drm_calloc(1, sizeof(TMemBlock),
DRM_MEM_DRIVER);
newblock->ofs = startofs;
newblock->size = p->size - (startofs - p->ofs);
newblock->free = 1;
newblock->next = p->next;
p->size -= newblock->size;
p->next = newblock;
p = newblock;
}
/* break right */
if (size < p->size) {
newblock = (TMemBlock *) drm_calloc(1, sizeof(TMemBlock),
DRM_MEM_DRIVER);
newblock->ofs = startofs + size;
newblock->size = p->size - size;
newblock->free = 1;
newblock->next = p->next;
p->size = size;
p->next = newblock;
}
/* p = middle block */
p->align = alignment;
p->free = 0;
p->reserved = reserved;
return p;
}
PMemBlock mmAllocMem(memHeap_t * heap, int size, int align2, int startSearch)
{
int mask, startofs, endofs;
TMemBlock *p;
if (heap == NULL || align2 < 0 || size <= 0)
return NULL;
mask = (1 << align2) - 1;
startofs = 0;
p = (TMemBlock *) heap;
while (p != NULL) {
if (ISFREE(p)) {
startofs = (p->ofs + mask) & ~mask;
if (startofs < startSearch) {
startofs = startSearch;
}
endofs = startofs + size;
if (endofs <= (p->ofs + p->size))
break;
}
p = p->next;
}
if (p == NULL)
return NULL;
p = SliceBlock(p, startofs, size, 0, mask + 1);
p->heap = heap;
return p;
}
static __inline__ int Join2Blocks(TMemBlock * p)
{
if (p->free && p->next && p->next->free) {
TMemBlock *q = p->next;
p->size += q->size;
p->next = q->next;
drm_free(q, sizeof(TMemBlock), DRM_MEM_DRIVER);
return 1;
}
return 0;
}
int mmFreeMem(PMemBlock b)
{
TMemBlock *p, *prev;
if (b == NULL)
return 0;
if (b->heap == NULL)
return -1;
p = b->heap;
prev = NULL;
while (p != NULL && p != b) {
prev = p;
p = p->next;
}
if (p == NULL || p->free || p->reserved)
return -1;
p->free = 1;
Join2Blocks(p);
if (prev)
Join2Blocks(prev);
return 0;
}

151
sys/dev/pci/drm/sis_ds.h Normal file
View File

@ -0,0 +1,151 @@
/* sis_ds.h -- Private header for Direct Rendering Manager -*- linux-c -*-
* Created: Mon Jan 4 10:05:05 1999 by sclin@sis.com.tw
*/
/*-
* Copyright 2000 Silicon Integrated Systems Corp, Inc., HsinChu, Taiwan.
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* Authors:
* Sung-Ching Lin <sclin@sis.com.tw>
*
*/
#include <sys/cdefs.h>
/*
__FBSDID("$FreeBSD: src/sys/dev/drm/sis_ds.h,v 1.6 2006/04/09 20:45:45 anholt Exp $");
*/
#ifndef __SIS_DS_H__
#define __SIS_DS_H__
/* Set Data Structure */
#define SET_SIZE 5000
typedef unsigned long ITEM_TYPE;
typedef struct {
ITEM_TYPE val;
int alloc_next, free_next;
} list_item_t;
typedef struct {
int alloc;
int free;
int trace;
list_item_t list[SET_SIZE];
} set_t;
set_t *setInit(void);
int setAdd(set_t * set, ITEM_TYPE item);
int setDel(set_t * set, ITEM_TYPE item);
int setFirst(set_t * set, ITEM_TYPE * item);
int setNext(set_t * set, ITEM_TYPE * item);
int setDestroy(set_t * set);
/*
* GLX Hardware Device Driver common code
* Copyright (C) 1999 Wittawat Yamwong
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* WITTAWAT YAMWONG, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
struct mem_block_t {
struct mem_block_t *next;
struct mem_block_t *heap;
int ofs, size;
int align;
unsigned int free:1;
unsigned int reserved:1;
};
typedef struct mem_block_t TMemBlock;
typedef struct mem_block_t *PMemBlock;
/* a heap is just the first block in a chain */
typedef struct mem_block_t memHeap_t;
static __inline__ int mmBlockSize(PMemBlock b)
{
return b->size;
}
static __inline__ int mmOffset(PMemBlock b)
{
return b->ofs;
}
static __inline__ void mmMarkReserved(PMemBlock b)
{
b->reserved = 1;
}
/*
* input: total size in bytes
* return: a heap pointer if OK, NULL if error
*/
memHeap_t *mmInit(int ofs, int size);
/*
* Allocate 'size' bytes with 2^align2 bytes alignment,
* restrict the search to free memory after 'startSearch'
* depth and back buffers should be in different 4mb banks
* to get better page hits if possible
* input: size = size of block
* align2 = 2^align2 bytes alignment
* startSearch = linear offset from start of heap to begin search
* return: pointer to the allocated block, 0 if error
*/
PMemBlock mmAllocMem(memHeap_t * heap, int size, int align2, int startSearch);
/*
* Returns 1 if the block 'b' is part of the heap 'heap'
*/
int mmBlockInHeap(PMemBlock heap, PMemBlock b);
/*
* Free block starts at offset
* input: pointer to a block
* return: 0 if OK, -1 if error
*/
int mmFreeMem(PMemBlock b);
/* For debuging purpose. */
void mmDumpMemInfo(memHeap_t * mmInit);
#endif /* __SIS_DS_H__ */

423
sys/dev/pci/drm/sis_mm.c Normal file
View File

@ -0,0 +1,423 @@
/* sis_mm.c -- Private header for Direct Rendering Manager -*- linux-c -*-
* Created: Mon Jan 4 10:05:05 1999 by sclin@sis.com.tw
*
* Copyright 2000 Silicon Integrated Systems Corp, Inc., HsinChu, Taiwan.
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* Authors:
* Sung-Ching Lin <sclin@sis.com.tw>
*
*/
#include <sys/cdefs.h>
/*
__FBSDID("$FreeBSD: src/sys/dev/drm/sis_mm.c,v 1.9 2006/04/09 20:45:45 anholt Exp $");
*/
#if defined(__linux__) && defined(CONFIG_FB_SIS)
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
#include <video/sisfb.h>
#else
#include <linux/sisfb.h>
#endif
#endif
#include "drmP.h"
#include "sis_drm.h"
#include "sis_drv.h"
#include "sis_ds.h"
#define MAX_CONTEXT 100
#define VIDEO_TYPE 0
#define AGP_TYPE 1
typedef struct {
int used;
int context;
set_t *sets[2]; /* 0 for video, 1 for AGP */
} sis_context_t;
static sis_context_t global_ppriv[MAX_CONTEXT];
static int add_alloc_set(int context, int type, unsigned int val)
{
int i, retval = 0;
for (i = 0; i < MAX_CONTEXT; i++) {
if (global_ppriv[i].used && global_ppriv[i].context == context) {
retval = setAdd(global_ppriv[i].sets[type], val);
break;
}
}
return retval;
}
static int del_alloc_set(int context, int type, unsigned int val)
{
int i, retval = 0;
for (i = 0; i < MAX_CONTEXT; i++) {
if (global_ppriv[i].used && global_ppriv[i].context == context) {
retval = setDel(global_ppriv[i].sets[type], val);
break;
}
}
return retval;
}
/* fb management via fb device */
#if defined(__linux__) && defined(CONFIG_FB_SIS)
static int sis_fb_init(DRM_IOCTL_ARGS)
{
return 0;
}
static int sis_fb_alloc(DRM_IOCTL_ARGS)
{
drm_sis_mem_t fb;
struct sis_memreq req;
drm_sis_mem_t __user *argp = (drm_sis_mem_t __user *)data;
int retval = 0;
DRM_COPY_FROM_USER_IOCTL(fb, argp, sizeof(fb));
req.size = fb.size;
sis_malloc(&req);
if (req.offset) {
/* TODO */
fb.offset = req.offset;
fb.free = req.offset;
if (!add_alloc_set(fb.context, VIDEO_TYPE, fb.free)) {
DRM_DEBUG("adding to allocation set fails\n");
sis_free(req.offset);
retval = DRM_ERR(EINVAL);
}
} else {
fb.offset = 0;
fb.size = 0;
fb.free = 0;
}
DRM_COPY_TO_USER_IOCTL(argp, fb, sizeof(fb));
DRM_DEBUG("alloc fb, size = %d, offset = %ld\n", fb.size, req.offset);
return retval;
}
static int sis_fb_free(DRM_IOCTL_ARGS)
{
drm_sis_mem_t fb;
int retval = 0;
DRM_COPY_FROM_USER_IOCTL(fb, (drm_sis_mem_t __user *) data, sizeof(fb));
if (!fb.free)
return DRM_ERR(EINVAL);
if (!del_alloc_set(fb.context, VIDEO_TYPE, fb.free))
retval = DRM_ERR(EINVAL);
sis_free(fb.free);
DRM_DEBUG("free fb, offset = 0x%lx\n", fb.free);
return retval;
}
#else
/* Called by the X Server to initialize the FB heap. Allocations will fail
* unless this is called. Offset is the beginning of the heap from the
* framebuffer offset (MaxXFBMem in XFree86).
*
* Memory layout according to Thomas Winischofer:
* |------------------|DDDDDDDDDDDDDDDDDDDDDDDDDDDDD|HHHH|CCCCCCCCCCC|
*
* X driver/sisfb HW- Command-
* framebuffer memory DRI heap Cursor queue
*/
static int sis_fb_init(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_sis_private_t *dev_priv = dev->dev_private;
drm_sis_fb_t fb;
DRM_COPY_FROM_USER_IOCTL(fb, (drm_sis_fb_t __user *) data, sizeof(fb));
if (dev_priv == NULL) {
dev->dev_private = drm_calloc(1, sizeof(drm_sis_private_t),
DRM_MEM_DRIVER);
dev_priv = dev->dev_private;
if (dev_priv == NULL)
return ENOMEM;
}
if (dev_priv->FBHeap != NULL)
return DRM_ERR(EINVAL);
dev_priv->FBHeap = mmInit(fb.offset, fb.size);
DRM_DEBUG("offset = %u, size = %u", fb.offset, fb.size);
return 0;
}
static int sis_fb_alloc(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_sis_private_t *dev_priv = dev->dev_private;
drm_sis_mem_t __user *argp = (drm_sis_mem_t __user *)data;
drm_sis_mem_t fb;
PMemBlock block;
int retval = 0;
if (dev_priv == NULL || dev_priv->FBHeap == NULL)
return DRM_ERR(EINVAL);
DRM_COPY_FROM_USER_IOCTL(fb, argp, sizeof(fb));
block = mmAllocMem(dev_priv->FBHeap, fb.size, 0, 0);
if (block) {
/* TODO */
fb.offset = block->ofs;
fb.free = (unsigned long)block;
if (!add_alloc_set(fb.context, VIDEO_TYPE, fb.free)) {
DRM_DEBUG("adding to allocation set fails\n");
mmFreeMem((PMemBlock) fb.free);
retval = DRM_ERR(EINVAL);
}
} else {
fb.offset = 0;
fb.size = 0;
fb.free = 0;
}
DRM_COPY_TO_USER_IOCTL(argp, fb, sizeof(fb));
DRM_DEBUG("alloc fb, size = %d, offset = %d\n", fb.size, fb.offset);
return retval;
}
static int sis_fb_free(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_sis_private_t *dev_priv = dev->dev_private;
drm_sis_mem_t fb;
if (dev_priv == NULL || dev_priv->FBHeap == NULL)
return DRM_ERR(EINVAL);
DRM_COPY_FROM_USER_IOCTL(fb, (drm_sis_mem_t __user *) data, sizeof(fb));
if (!mmBlockInHeap(dev_priv->FBHeap, (PMemBlock) fb.free))
return DRM_ERR(EINVAL);
if (!del_alloc_set(fb.context, VIDEO_TYPE, fb.free))
return DRM_ERR(EINVAL);
mmFreeMem((PMemBlock) fb.free);
DRM_DEBUG("free fb, free = 0x%lx\n", fb.free);
return 0;
}
#endif
/* agp memory management */
static int sis_ioctl_agp_init(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_sis_private_t *dev_priv = dev->dev_private;
drm_sis_agp_t agp;
if (dev_priv == NULL) {
dev->dev_private = drm_calloc(1, sizeof(drm_sis_private_t),
DRM_MEM_DRIVER);
dev_priv = dev->dev_private;
if (dev_priv == NULL)
return ENOMEM;
}
if (dev_priv->AGPHeap != NULL)
return DRM_ERR(EINVAL);
DRM_COPY_FROM_USER_IOCTL(agp, (drm_sis_agp_t __user *) data,
sizeof(agp));
dev_priv->AGPHeap = mmInit(agp.offset, agp.size);
DRM_DEBUG("offset = %u, size = %u", agp.offset, agp.size);
return 0;
}
static int sis_ioctl_agp_alloc(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_sis_private_t *dev_priv = dev->dev_private;
drm_sis_mem_t __user *argp = (drm_sis_mem_t __user *)data;
drm_sis_mem_t agp;
PMemBlock block;
int retval = 0;
if (dev_priv == NULL || dev_priv->AGPHeap == NULL)
return DRM_ERR(EINVAL);
DRM_COPY_FROM_USER_IOCTL(agp, argp, sizeof(agp));
block = mmAllocMem(dev_priv->AGPHeap, agp.size, 0, 0);
if (block) {
/* TODO */
agp.offset = block->ofs;
agp.free = (unsigned long)block;
if (!add_alloc_set(agp.context, AGP_TYPE, agp.free)) {
DRM_DEBUG("adding to allocation set fails\n");
mmFreeMem((PMemBlock) agp.free);
retval = -1;
}
} else {
agp.offset = 0;
agp.size = 0;
agp.free = 0;
}
DRM_COPY_TO_USER_IOCTL(argp, agp, sizeof(agp));
DRM_DEBUG("alloc agp, size = %d, offset = %d\n", agp.size, agp.offset);
return retval;
}
static int sis_ioctl_agp_free(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_sis_private_t *dev_priv = dev->dev_private;
drm_sis_mem_t agp;
if (dev_priv == NULL || dev_priv->AGPHeap == NULL)
return DRM_ERR(EINVAL);
DRM_COPY_FROM_USER_IOCTL(agp, (drm_sis_mem_t __user *) data,
sizeof(agp));
if (!mmBlockInHeap(dev_priv->AGPHeap, (PMemBlock) agp.free))
return DRM_ERR(EINVAL);
mmFreeMem((PMemBlock) agp.free);
if (!del_alloc_set(agp.context, AGP_TYPE, agp.free))
return DRM_ERR(EINVAL);
DRM_DEBUG("free agp, free = 0x%lx\n", agp.free);
return 0;
}
int sis_init_context(struct drm_device *dev, int context)
{
int i;
for (i = 0; i < MAX_CONTEXT; i++) {
if (global_ppriv[i].used &&
(global_ppriv[i].context == context))
break;
}
if (i >= MAX_CONTEXT) {
for (i = 0; i < MAX_CONTEXT; i++) {
if (!global_ppriv[i].used) {
global_ppriv[i].context = context;
global_ppriv[i].used = 1;
global_ppriv[i].sets[0] = setInit();
global_ppriv[i].sets[1] = setInit();
DRM_DEBUG("init allocation set, socket=%d, "
"context = %d\n", i, context);
break;
}
}
if ((i >= MAX_CONTEXT) || (global_ppriv[i].sets[0] == NULL) ||
(global_ppriv[i].sets[1] == NULL)) {
return 0;
}
}
return 1;
}
int sis_final_context(struct drm_device *dev, int context)
{
int i;
for (i = 0; i < MAX_CONTEXT; i++) {
if (global_ppriv[i].used &&
(global_ppriv[i].context == context))
break;
}
if (i < MAX_CONTEXT) {
set_t *set;
ITEM_TYPE item;
int retval;
DRM_DEBUG("find socket %d, context = %d\n", i, context);
/* Video Memory */
set = global_ppriv[i].sets[0];
retval = setFirst(set, &item);
while (retval) {
DRM_DEBUG("free video memory 0x%lx\n", item);
#if defined(__linux__) && defined(CONFIG_FB_SIS)
sis_free(item);
#else
mmFreeMem((PMemBlock) item);
#endif
retval = setNext(set, &item);
}
setDestroy(set);
/* AGP Memory */
set = global_ppriv[i].sets[1];
retval = setFirst(set, &item);
while (retval) {
DRM_DEBUG("free agp memory 0x%lx\n", item);
mmFreeMem((PMemBlock) item);
retval = setNext(set, &item);
}
setDestroy(set);
global_ppriv[i].used = 0;
}
return 1;
}
drm_ioctl_desc_t sis_ioctls[] = {
[DRM_IOCTL_NR(DRM_SIS_FB_ALLOC)] = {sis_fb_alloc, DRM_AUTH},
[DRM_IOCTL_NR(DRM_SIS_FB_FREE)] = {sis_fb_free, DRM_AUTH},
[DRM_IOCTL_NR(DRM_SIS_AGP_INIT)] = {sis_ioctl_agp_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
[DRM_IOCTL_NR(DRM_SIS_AGP_ALLOC)] = {sis_ioctl_agp_alloc, DRM_AUTH},
[DRM_IOCTL_NR(DRM_SIS_AGP_FREE)] = {sis_ioctl_agp_free, DRM_AUTH},
[DRM_IOCTL_NR(DRM_SIS_FB_INIT)] = {sis_fb_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}
};
int sis_max_ioctl = DRM_ARRAY_SIZE(sis_ioctls);

127
sys/dev/pci/drm/tdfx_drv.c Normal file
View File

@ -0,0 +1,127 @@
/* tdfx_drv.c -- tdfx driver -*- linux-c -*-
* Created: Thu Oct 7 10:38:32 1999 by faith@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>
* Daryll Strauss <daryll@valinux.com>
* Gareth Hughes <gareth@valinux.com>
*
*/
#include <sys/cdefs.h>
/*
__FBSDID("$FreeBSD: src/sys/dev/drm/tdfx_drv.c,v 1.10 2005/12/20 22:44:36 jhb Exp $");
*/
#include "tdfx_drv.h"
#include "drmP.h"
#include "drm_pciids.h"
/* drv_PCI_IDs comes from drm_pciids.h, generated from drm_pciids.txt. */
static drm_pci_id_list_t tdfx_pciidlist[] = {
tdfx_PCI_IDS
};
static void tdfx_configure(drm_device_t *dev)
{
dev->driver.buf_priv_size = 1; /* No dev_priv */
dev->driver.max_ioctl = 0;
dev->driver.name = DRIVER_NAME;
dev->driver.desc = DRIVER_DESC;
dev->driver.date = DRIVER_DATE;
dev->driver.major = DRIVER_MAJOR;
dev->driver.minor = DRIVER_MINOR;
dev->driver.patchlevel = DRIVER_PATCHLEVEL;
dev->driver.use_mtrr = 1;
}
#ifdef __FreeBSD__
static int
tdfx_probe(device_t dev)
{
return drm_probe(dev, tdfx_pciidlist);
}
static int
tdfx_attach(device_t nbdev)
{
drm_device_t *dev = device_get_softc(nbdev);
bzero(dev, sizeof(drm_device_t));
tdfx_configure(dev);
return drm_attach(nbdev, tdfx_pciidlist);
}
static device_method_t tdfx_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, tdfx_probe),
DEVMETHOD(device_attach, tdfx_attach),
DEVMETHOD(device_detach, drm_detach),
{ 0, 0 }
};
static driver_t tdfx_driver = {
"drm",
tdfx_methods,
sizeof(drm_device_t)
};
extern devclass_t drm_devclass;
#if __FreeBSD_version >= 700010
DRIVER_MODULE(tdfx, vgapci, tdfx_driver, drm_devclass, 0, 0);
#else
DRIVER_MODULE(tdfx, pci, tdfx_driver, drm_devclass, 0, 0);
#endif
MODULE_DEPEND(tdfx, drm, 1, 1, 1);
#elif defined(__NetBSD__) || defined(__OpenBSD__)
static int
tdfxdrm_probe(struct device *parent, struct cfdata *match, void *aux)
{
struct pci_attach_args *pa = aux;
return drm_probe(pa, tdfx_pciidlist);
}
static void
tdfxdrm_attach(struct device *parent, struct device *self, void *aux)
{
struct pci_attach_args *pa = aux;
drm_device_t *dev = (drm_device_t *)self;
tdfx_configure(dev);
return drm_attach(self, pa, tdfx_pciidlist);
}
CFATTACH_DECL(tdfxdrm, sizeof(drm_device_t), tdfxdrm_probe, tdfxdrm_attach,
drm_detach, drm_activate);
#endif

View File

@ -0,0 +1,52 @@
/* tdfx.h -- 3dfx DRM template customization -*- linux-c -*-
* Created: Wed Feb 14 12:32:32 2001 by gareth@valinux.com
*/
/*-
* 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:
* Gareth Hughes <gareth@valinux.com>
*/
#include <sys/cdefs.h>
/*
__FBSDID("$FreeBSD: src/sys/dev/drm/tdfx_drv.h,v 1.2 2005/11/28 23:13:55 anholt Exp $");
*/
#ifndef __TDFX_H__
#define __TDFX_H__
/* General customization:
*/
#define DRIVER_AUTHOR "VA Linux Systems Inc."
#define DRIVER_NAME "tdfx"
#define DRIVER_DESC "3dfx Banshee/Voodoo3+"
#define DRIVER_DATE "20010216"
#define DRIVER_MAJOR 1
#define DRIVER_MINOR 0
#define DRIVER_PATCHLEVEL 0
#endif

View File

@ -1,4 +1,4 @@
# $NetBSD: files.pci,v 1.278 2007/03/20 05:50:35 garbled Exp $
# $NetBSD: files.pci,v 1.279 2007/03/20 18:05:31 drochner Exp $
#
# Config file and device description for machine-independent PCI code.
# Included by ports that need it. Requires that the SCSI files be
@ -862,3 +862,58 @@ attach mskc at pci
device msk: ether, ifnet, arp, mii
attach msk at mskc
file dev/pci/if_msk.c mskc | msk
device i915drm: drmbase
attach i915drm at drm
file dev/pci/drm/i915_drv.c i915drm
file dev/pci/drm/i915_dma.c i915drm
file dev/pci/drm/i915_irq.c i915drm
file dev/pci/drm/i915_mem.c i915drm
device mach64drm: drmbase
attach mach64drm at drm
file dev/pci/drm/mach64_dma.c mach64drm
file dev/pci/drm/mach64_drv.c mach64drm
file dev/pci/drm/mach64_irq.c mach64drm
file dev/pci/drm/mach64_state.c mach64drm
device mgadrm: drmbase
attach mgadrm at drm
file dev/pci/drm/mga_dma.c mgadrm
file dev/pci/drm/mga_drv.c mgadrm
file dev/pci/drm/mga_irq.c mgadrm
file dev/pci/drm/mga_state.c mgadrm
file dev/pci/drm/mga_warp.c mgadrm
device r128drm: drmbase
attach r128drm at drm
file dev/pci/drm/ati_pcigart.c r128drm | radeondrm
file dev/pci/drm/r128_cce.c r128drm
file dev/pci/drm/r128_drv.c r128drm
file dev/pci/drm/r128_irq.c r128drm
file dev/pci/drm/r128_state.c r128drm
device radeondrm: drmbase
attach radeondrm at drm
file dev/pci/drm/r300_cmdbuf.c radeondrm
file dev/pci/drm/radeon_cp.c radeondrm
file dev/pci/drm/radeon_drv.c radeondrm
file dev/pci/drm/radeon_irq.c radeondrm
file dev/pci/drm/radeon_mem.c radeondrm
file dev/pci/drm/radeon_state.c radeondrm
device savagedrm: drmbase
attach savagedrm at drm
file dev/pci/drm/savage_bci.c savagedrm
file dev/pci/drm/savage_drv.c savagedrm
file dev/pci/drm/savage_state.c savagedrm
device sisdrm: drmbase
attach sisdrm at drm
file dev/pci/drm/sis_drv.c sisdrm
file dev/pci/drm/sis_ds.c sisdrm
file dev/pci/drm/sis_mm.c sisdrm
device tdfxdrm: drmbase
attach tdfxdrm at drm
file dev/pci/drm/tdfx_drv.c tdfxdrm

View File

@ -1,4 +1,4 @@
/* $NetBSD: vga_pci.c,v 1.31 2007/03/04 06:02:26 christos Exp $ */
/* $NetBSD: vga_pci.c,v 1.32 2007/03/20 18:05:31 drochner Exp $ */
/*
* Copyright (c) 1995, 1996 Carnegie-Mellon University.
@ -28,7 +28,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: vga_pci.c,v 1.31 2007/03/04 06:02:26 christos Exp $");
__KERNEL_RCSID(0, "$NetBSD: vga_pci.c,v 1.32 2007/03/20 18:05:31 drochner Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -214,6 +214,8 @@ vga_pci_attach(struct device *parent, struct device *self, void *aux)
vga_common_attach(sc, pa->pa_iot, pa->pa_memt, WSDISPLAY_TYPE_PCIVGA,
vga_pci_lookup_quirks(pa), &vga_pci_funcs);
config_found_ia(self, "drm", aux, vga_drm_print);
}
int
@ -225,6 +227,15 @@ vga_pci_cnattach(bus_space_tag_t iot, bus_space_tag_t memt,
return (vga_cnattach(iot, memt, WSDISPLAY_TYPE_PCIVGA, 0));
}
int
vga_drm_print(void *aux, const char *pnp)
{
if (pnp)
aprint_normal("direct rendering for %s", pnp);
return (UNSUPP);
}
static int
vga_pci_ioctl(void *v, u_long cmd, void *data, int flag, struct lwp *l)
{

View File

@ -1,4 +1,4 @@
/* $NetBSD: vga_pcivar.h,v 1.4 2005/12/11 12:22:51 christos Exp $ */
/* $NetBSD: vga_pcivar.h,v 1.5 2007/03/20 18:05:31 drochner Exp $ */
/*
* Copyright (c) 1995, 1996 Carnegie-Mellon University.
@ -35,3 +35,5 @@
int vga_pci_cnattach(bus_space_tag_t, bus_space_tag_t,
pci_chipset_tag_t, int, int, int);
int vga_drm_print(void *aux, const char *pnp);