Creation of Cybook 2416 (actually Gen4) repository
This commit is contained in:
108
drivers/char/drm/Kconfig
Normal file
108
drivers/char/drm/Kconfig
Normal file
@@ -0,0 +1,108 @@
|
||||
#
|
||||
# Drm device configuration
|
||||
#
|
||||
# This driver provides support for the
|
||||
# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
|
||||
#
|
||||
config DRM
|
||||
tristate "Direct Rendering Manager (XFree86 4.1.0 and higher DRI support)"
|
||||
depends on (AGP || AGP=n) && PCI
|
||||
help
|
||||
Kernel-level support for the Direct Rendering Infrastructure (DRI)
|
||||
introduced in XFree86 4.0. If you say Y here, you need to select
|
||||
the module that's right for your graphics card from the list below.
|
||||
These modules provide support for synchronization, security, and
|
||||
DMA transfers. Please see <http://dri.sourceforge.net/> for more
|
||||
details. You should also select and configure AGP
|
||||
(/dev/agpgart) support.
|
||||
|
||||
config DRM_TDFX
|
||||
tristate "3dfx Banshee/Voodoo3+"
|
||||
depends on DRM && PCI
|
||||
help
|
||||
Choose this option if you have a 3dfx Banshee or Voodoo3 (or later),
|
||||
graphics card. If M is selected, the module will be called tdfx.
|
||||
|
||||
config DRM_R128
|
||||
tristate "ATI Rage 128"
|
||||
depends on DRM && PCI
|
||||
help
|
||||
Choose this option if you have an ATI Rage 128 graphics card. If M
|
||||
is selected, the module will be called r128. AGP support for
|
||||
this card is strongly suggested (unless you have a PCI version).
|
||||
|
||||
config DRM_RADEON
|
||||
tristate "ATI Radeon"
|
||||
depends on DRM && PCI
|
||||
help
|
||||
Choose this option if you have an ATI Radeon graphics card. There
|
||||
are both PCI and AGP versions. You don't need to choose this to
|
||||
run the Radeon in plain VGA mode.
|
||||
|
||||
If M is selected, the module will be called radeon.
|
||||
|
||||
config DRM_I810
|
||||
tristate "Intel I810"
|
||||
depends on DRM && AGP && AGP_INTEL
|
||||
help
|
||||
Choose this option if you have an Intel I810 graphics card. If M is
|
||||
selected, the module will be called i810. AGP support is required
|
||||
for this driver to work.
|
||||
|
||||
choice
|
||||
prompt "Intel 830M, 845G, 852GM, 855GM, 865G"
|
||||
depends on DRM && AGP && AGP_INTEL
|
||||
optional
|
||||
|
||||
config DRM_I830
|
||||
tristate "i830 driver"
|
||||
help
|
||||
Choose this option if you have a system that has Intel 830M, 845G,
|
||||
852GM, 855GM or 865G integrated graphics. If M is selected, the
|
||||
module will be called i830. AGP support is required for this driver
|
||||
to work. This driver is used by the older X releases X.org 6.7 and
|
||||
XFree86 4.3. If unsure, build this and i915 as modules and the X server
|
||||
will load the correct one.
|
||||
|
||||
config DRM_I915
|
||||
tristate "i915 driver"
|
||||
help
|
||||
Choose this option if you have a system that has Intel 830M, 845G,
|
||||
852GM, 855GM 865G or 915G integrated graphics. If M is selected, the
|
||||
module will be called i915. AGP support is required for this driver
|
||||
to work. This driver is used by the Intel driver in X.org 6.8 and
|
||||
XFree86 4.4 and above. If unsure, build this and i830 as modules and
|
||||
the X server will load the correct one.
|
||||
|
||||
endchoice
|
||||
|
||||
config DRM_MGA
|
||||
tristate "Matrox g200/g400"
|
||||
depends on DRM
|
||||
help
|
||||
Choose this option if you have a Matrox G200, G400 or G450 graphics
|
||||
card. If M is selected, the module will be called mga. AGP
|
||||
support is required for this driver to work.
|
||||
|
||||
config DRM_SIS
|
||||
tristate "SiS video cards"
|
||||
depends on DRM && AGP
|
||||
help
|
||||
Choose this option if you have a SiS 630 or compatible video
|
||||
chipset. If M is selected the module will be called sis. AGP
|
||||
support is required for this driver to work.
|
||||
|
||||
config DRM_VIA
|
||||
tristate "Via unichrome video cards"
|
||||
depends on DRM
|
||||
help
|
||||
Choose this option if you have a Via unichrome or compatible video
|
||||
chipset. If M is selected the module will be called via.
|
||||
|
||||
config DRM_SAVAGE
|
||||
tristate "Savage video cards"
|
||||
depends on DRM
|
||||
help
|
||||
Choose this option if you have a Savage3D/4/SuperSavage/Pro/Twister
|
||||
chipset. If M is selected the module will be called savage.
|
||||
|
||||
42
drivers/char/drm/Makefile
Normal file
42
drivers/char/drm/Makefile
Normal file
@@ -0,0 +1,42 @@
|
||||
#
|
||||
# Makefile for the drm device driver. This driver provides support for the
|
||||
# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
|
||||
|
||||
drm-objs := drm_auth.o drm_bufs.o drm_context.o drm_dma.o drm_drawable.o \
|
||||
drm_drv.o drm_fops.o drm_ioctl.o drm_irq.o \
|
||||
drm_lock.o drm_memory.o drm_proc.o drm_stub.o drm_vm.o \
|
||||
drm_agpsupport.o drm_scatter.o ati_pcigart.o drm_pci.o \
|
||||
drm_sysfs.o drm_hashtab.o drm_sman.o drm_mm.o
|
||||
|
||||
tdfx-objs := tdfx_drv.o
|
||||
r128-objs := r128_drv.o r128_cce.o r128_state.o r128_irq.o
|
||||
mga-objs := mga_drv.o mga_dma.o mga_state.o mga_warp.o mga_irq.o
|
||||
i810-objs := i810_drv.o i810_dma.o
|
||||
i830-objs := i830_drv.o i830_dma.o i830_irq.o
|
||||
i915-objs := i915_drv.o i915_dma.o i915_irq.o i915_mem.o
|
||||
radeon-objs := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o r300_cmdbuf.o
|
||||
sis-objs := sis_drv.o sis_mm.o
|
||||
savage-objs := savage_drv.o savage_bci.o savage_state.o
|
||||
via-objs := via_irq.o via_drv.o via_map.o via_mm.o via_dma.o via_verifier.o via_video.o via_dmablit.o
|
||||
|
||||
ifeq ($(CONFIG_COMPAT),y)
|
||||
drm-objs += drm_ioc32.o
|
||||
radeon-objs += radeon_ioc32.o
|
||||
mga-objs += mga_ioc32.o
|
||||
r128-objs += r128_ioc32.o
|
||||
i915-objs += i915_ioc32.o
|
||||
endif
|
||||
|
||||
obj-$(CONFIG_DRM) += drm.o
|
||||
obj-$(CONFIG_DRM_TDFX) += tdfx.o
|
||||
obj-$(CONFIG_DRM_R128) += r128.o
|
||||
obj-$(CONFIG_DRM_RADEON)+= radeon.o
|
||||
obj-$(CONFIG_DRM_MGA) += mga.o
|
||||
obj-$(CONFIG_DRM_I810) += i810.o
|
||||
obj-$(CONFIG_DRM_I830) += i830.o
|
||||
obj-$(CONFIG_DRM_I915) += i915.o
|
||||
obj-$(CONFIG_DRM_SIS) += sis.o
|
||||
obj-$(CONFIG_DRM_SAVAGE)+= savage.o
|
||||
obj-$(CONFIG_DRM_VIA) +=via.o
|
||||
|
||||
|
||||
46
drivers/char/drm/README.drm
Normal file
46
drivers/char/drm/README.drm
Normal file
@@ -0,0 +1,46 @@
|
||||
************************************************************
|
||||
* For the very latest on DRI development, please see: *
|
||||
* http://dri.sourceforge.net/ *
|
||||
************************************************************
|
||||
|
||||
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:
|
||||
|
||||
1. The DRM provides synchronized access to the graphics hardware via
|
||||
the use of an optimized two-tiered lock.
|
||||
|
||||
2. 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.
|
||||
|
||||
3. The DRM provides a generic DMA engine, complete with multiple
|
||||
queues and the ability to detect the need for an OpenGL context
|
||||
switch.
|
||||
|
||||
4. The DRM is extensible via the use of small device-specific modules
|
||||
that rely extensively on the API exported by the DRM module.
|
||||
|
||||
|
||||
Documentation on the DRI is available from:
|
||||
http://precisioninsight.com/piinsights.html
|
||||
|
||||
For specific information about kernel-level support, see:
|
||||
|
||||
The Direct Rendering Manager, Kernel Support for the Direct Rendering
|
||||
Infrastructure
|
||||
http://precisioninsight.com/dr/drm.html
|
||||
|
||||
Hardware Locking for the Direct Rendering Infrastructure
|
||||
http://precisioninsight.com/dr/locking.html
|
||||
|
||||
A Security Analysis of the Direct Rendering Infrastructure
|
||||
http://precisioninsight.com/dr/security.html
|
||||
|
||||
************************************************************
|
||||
* For the very latest on DRI development, please see: *
|
||||
* http://dri.sourceforge.net/ *
|
||||
************************************************************
|
||||
224
drivers/char/drm/ati_pcigart.c
Normal file
224
drivers/char/drm/ati_pcigart.c
Normal file
@@ -0,0 +1,224 @@
|
||||
/**
|
||||
* \file ati_pcigart.c
|
||||
* ATI PCI GART support
|
||||
*
|
||||
* \author Gareth Hughes <gareth@valinux.com>
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "drmP.h"
|
||||
|
||||
#if PAGE_SIZE == 65536
|
||||
# define ATI_PCIGART_TABLE_ORDER 0
|
||||
# define ATI_PCIGART_TABLE_PAGES (1 << 0)
|
||||
#elif PAGE_SIZE == 16384
|
||||
# define ATI_PCIGART_TABLE_ORDER 1
|
||||
# define ATI_PCIGART_TABLE_PAGES (1 << 1)
|
||||
#elif PAGE_SIZE == 8192
|
||||
# define ATI_PCIGART_TABLE_ORDER 2
|
||||
# define ATI_PCIGART_TABLE_PAGES (1 << 2)
|
||||
#elif PAGE_SIZE == 4096
|
||||
# define ATI_PCIGART_TABLE_ORDER 3
|
||||
# define ATI_PCIGART_TABLE_PAGES (1 << 3)
|
||||
#else
|
||||
# error - PAGE_SIZE not 64K, 16K, 8K or 4K
|
||||
#endif
|
||||
|
||||
# define ATI_MAX_PCIGART_PAGES 8192 /**< 32 MB aperture, 4K pages */
|
||||
# define ATI_PCIGART_PAGE_SIZE 4096 /**< PCI GART page size */
|
||||
|
||||
static void *drm_ati_alloc_pcigart_table(void)
|
||||
{
|
||||
unsigned long address;
|
||||
struct page *page;
|
||||
int i;
|
||||
DRM_DEBUG("%s\n", __FUNCTION__);
|
||||
|
||||
address = __get_free_pages(GFP_KERNEL | __GFP_COMP,
|
||||
ATI_PCIGART_TABLE_ORDER);
|
||||
if (address == 0UL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
page = virt_to_page(address);
|
||||
|
||||
for (i = 0; i < ATI_PCIGART_TABLE_PAGES; i++, page++)
|
||||
SetPageReserved(page);
|
||||
|
||||
DRM_DEBUG("%s: returning 0x%08lx\n", __FUNCTION__, address);
|
||||
return (void *)address;
|
||||
}
|
||||
|
||||
static void drm_ati_free_pcigart_table(void *address)
|
||||
{
|
||||
struct page *page;
|
||||
int i;
|
||||
DRM_DEBUG("%s\n", __FUNCTION__);
|
||||
|
||||
page = virt_to_page((unsigned long)address);
|
||||
|
||||
for (i = 0; i < ATI_PCIGART_TABLE_PAGES; i++, page++)
|
||||
ClearPageReserved(page);
|
||||
|
||||
free_pages((unsigned long)address, ATI_PCIGART_TABLE_ORDER);
|
||||
}
|
||||
|
||||
int drm_ati_pcigart_cleanup(drm_device_t *dev, drm_ati_pcigart_info *gart_info)
|
||||
{
|
||||
drm_sg_mem_t *entry = dev->sg;
|
||||
unsigned long pages;
|
||||
int i;
|
||||
|
||||
/* we need to support large memory configurations */
|
||||
if (!entry) {
|
||||
DRM_ERROR("no scatter/gather memory!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (gart_info->bus_addr) {
|
||||
if (gart_info->gart_table_location == DRM_ATI_GART_MAIN) {
|
||||
pci_unmap_single(dev->pdev, gart_info->bus_addr,
|
||||
ATI_PCIGART_TABLE_PAGES * PAGE_SIZE,
|
||||
PCI_DMA_TODEVICE);
|
||||
}
|
||||
|
||||
pages = (entry->pages <= ATI_MAX_PCIGART_PAGES)
|
||||
? entry->pages : ATI_MAX_PCIGART_PAGES;
|
||||
|
||||
for (i = 0; i < pages; i++) {
|
||||
if (!entry->busaddr[i])
|
||||
break;
|
||||
pci_unmap_single(dev->pdev, entry->busaddr[i],
|
||||
PAGE_SIZE, PCI_DMA_TODEVICE);
|
||||
}
|
||||
|
||||
if (gart_info->gart_table_location == DRM_ATI_GART_MAIN)
|
||||
gart_info->bus_addr = 0;
|
||||
}
|
||||
|
||||
if (gart_info->gart_table_location == DRM_ATI_GART_MAIN
|
||||
&& gart_info->addr) {
|
||||
drm_ati_free_pcigart_table(gart_info->addr);
|
||||
gart_info->addr = NULL;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(drm_ati_pcigart_cleanup);
|
||||
|
||||
int drm_ati_pcigart_init(drm_device_t *dev, drm_ati_pcigart_info *gart_info)
|
||||
{
|
||||
drm_sg_mem_t *entry = dev->sg;
|
||||
void *address = NULL;
|
||||
unsigned long pages;
|
||||
u32 *pci_gart, page_base, bus_address = 0;
|
||||
int i, j, ret = 0;
|
||||
|
||||
if (!entry) {
|
||||
DRM_ERROR("no scatter/gather memory!\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (gart_info->gart_table_location == DRM_ATI_GART_MAIN) {
|
||||
DRM_DEBUG("PCI: no table in VRAM: using normal RAM\n");
|
||||
|
||||
address = drm_ati_alloc_pcigart_table();
|
||||
if (!address) {
|
||||
DRM_ERROR("cannot allocate PCI GART page!\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!dev->pdev) {
|
||||
DRM_ERROR("PCI device unknown!\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
bus_address = pci_map_single(dev->pdev, address,
|
||||
ATI_PCIGART_TABLE_PAGES *
|
||||
PAGE_SIZE, PCI_DMA_TODEVICE);
|
||||
if (bus_address == 0) {
|
||||
DRM_ERROR("unable to map PCIGART pages!\n");
|
||||
drm_ati_free_pcigart_table(address);
|
||||
address = NULL;
|
||||
goto done;
|
||||
}
|
||||
} else {
|
||||
address = gart_info->addr;
|
||||
bus_address = gart_info->bus_addr;
|
||||
DRM_DEBUG("PCI: Gart Table: VRAM %08X mapped at %08lX\n",
|
||||
bus_address, (unsigned long)address);
|
||||
}
|
||||
|
||||
pci_gart = (u32 *) address;
|
||||
|
||||
pages = (entry->pages <= ATI_MAX_PCIGART_PAGES)
|
||||
? entry->pages : ATI_MAX_PCIGART_PAGES;
|
||||
|
||||
memset(pci_gart, 0, ATI_MAX_PCIGART_PAGES * sizeof(u32));
|
||||
|
||||
for (i = 0; i < pages; i++) {
|
||||
/* we need to support large memory configurations */
|
||||
entry->busaddr[i] = pci_map_single(dev->pdev,
|
||||
page_address(entry->
|
||||
pagelist[i]),
|
||||
PAGE_SIZE, PCI_DMA_TODEVICE);
|
||||
if (entry->busaddr[i] == 0) {
|
||||
DRM_ERROR("unable to map PCIGART pages!\n");
|
||||
drm_ati_pcigart_cleanup(dev, gart_info);
|
||||
address = NULL;
|
||||
bus_address = 0;
|
||||
goto done;
|
||||
}
|
||||
page_base = (u32) entry->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;
|
||||
}
|
||||
}
|
||||
|
||||
ret = 1;
|
||||
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
wbinvd();
|
||||
#else
|
||||
mb();
|
||||
#endif
|
||||
|
||||
done:
|
||||
gart_info->addr = address;
|
||||
gart_info->bus_addr = bus_address;
|
||||
return ret;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(drm_ati_pcigart_init);
|
||||
664
drivers/char/drm/drm.h
Normal file
664
drivers/char/drm/drm.h
Normal file
@@ -0,0 +1,664 @@
|
||||
/**
|
||||
* \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.
|
||||
*/
|
||||
|
||||
#ifndef _DRM_H_
|
||||
#define _DRM_H_
|
||||
|
||||
#if defined(__linux__)
|
||||
#if defined(__KERNEL__)
|
||||
#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(__NetBSD__) || defined(__OpenBSD__)
|
||||
#if defined(__FreeBSD__) && 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)
|
||||
#define DRM_MAJOR 226
|
||||
#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))
|
||||
|
||||
typedef unsigned int drm_handle_t;
|
||||
typedef unsigned int drm_context_t;
|
||||
typedef unsigned int drm_drawable_t;
|
||||
typedef unsigned int drm_magic_t;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Drawable information.
|
||||
*/
|
||||
typedef struct drm_drawable_info {
|
||||
unsigned int num_rects;
|
||||
drm_clip_rect_t *rects;
|
||||
} drm_drawable_info_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;
|
||||
|
||||
/**
|
||||
* 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 */
|
||||
size_t name_len; /**< Length of name buffer */
|
||||
char __user *name; /**< Name of driver */
|
||||
size_t date_len; /**< Length of date buffer */
|
||||
char __user *date; /**< User-space buffer to hold date */
|
||||
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 {
|
||||
size_t unique_len; /**< Length of unique */
|
||||
char __user *unique; /**< Unique name for driver instantiation */
|
||||
} drm_unique_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 */
|
||||
_DRM_PCI_BUFFER_RO = 0x10 /**< Map PCI DMA buffer read-only */
|
||||
} 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; /**< Entries in list */
|
||||
drm_buf_desc_t __user *list;
|
||||
} 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 */
|
||||
void __user *virtual; /**< Mmap'd area in user-virtual */
|
||||
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_UPDATE_DRAW ioctl argument type.
|
||||
*/
|
||||
typedef enum {
|
||||
DRM_DRAWABLE_CLIPRECTS,
|
||||
} drm_drawable_info_type_t;
|
||||
|
||||
typedef struct drm_update_draw {
|
||||
drm_drawable_t handle;
|
||||
unsigned int type;
|
||||
unsigned int num;
|
||||
unsigned long long data;
|
||||
} drm_update_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_NEXTONMISS = 0x10000000, /**< If missed, wait for next vblank */
|
||||
_DRM_VBLANK_SECONDARY = 0x20000000, /**< Secondary display controller */
|
||||
_DRM_VBLANK_SIGNAL = 0x40000000 /**< Send signal instead of blocking */
|
||||
} drm_vblank_seq_type_t;
|
||||
|
||||
#define _DRM_VBLANK_TYPES_MASK (_DRM_VBLANK_ABSOLUTE | _DRM_VBLANK_RELATIVE)
|
||||
#define _DRM_VBLANK_FLAGS_MASK (_DRM_VBLANK_SIGNAL | _DRM_VBLANK_SECONDARY | \
|
||||
_DRM_VBLANK_NEXTONMISS)
|
||||
|
||||
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;
|
||||
|
||||
/* 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;
|
||||
|
||||
#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)
|
||||
|
||||
#define DRM_IOCTL_UPDATE_DRAW DRM_IOW(0x3f, drm_update_draw_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
|
||||
1130
drivers/char/drm/drmP.h
Normal file
1130
drivers/char/drm/drmP.h
Normal file
File diff suppressed because it is too large
Load Diff
514
drivers/char/drm/drm_agpsupport.c
Normal file
514
drivers/char/drm/drm_agpsupport.c
Normal file
@@ -0,0 +1,514 @@
|
||||
/**
|
||||
* \file drm_agpsupport.c
|
||||
* DRM support for AGP/GART backend
|
||||
*
|
||||
* \author Rickard E. (Rik) Faith <faith@valinux.com>
|
||||
* \author Gareth Hughes <gareth@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.
|
||||
*/
|
||||
|
||||
#include "drmP.h"
|
||||
#include <linux/module.h>
|
||||
|
||||
#if __OS_HAS_AGP
|
||||
|
||||
/**
|
||||
* Get AGP information.
|
||||
*
|
||||
* \param inode device inode.
|
||||
* \param filp file pointer.
|
||||
* \param cmd command.
|
||||
* \param arg pointer to a (output) drm_agp_info structure.
|
||||
* \return zero on success or a negative number on failure.
|
||||
*
|
||||
* Verifies the AGP device has been initialized and acquired and fills in the
|
||||
* drm_agp_info structure with the information in drm_agp_head::agp_info.
|
||||
*/
|
||||
int drm_agp_info(drm_device_t * dev, drm_agp_info_t * info)
|
||||
{
|
||||
DRM_AGP_KERN *kern;
|
||||
|
||||
if (!dev->agp || !dev->agp->acquired)
|
||||
return -EINVAL;
|
||||
|
||||
kern = &dev->agp->agp_info;
|
||||
info->agp_version_major = kern->version.major;
|
||||
info->agp_version_minor = kern->version.minor;
|
||||
info->mode = kern->mode;
|
||||
info->aperture_base = kern->aper_base;
|
||||
info->aperture_size = kern->aper_size * 1024 * 1024;
|
||||
info->memory_allowed = kern->max_memory << PAGE_SHIFT;
|
||||
info->memory_used = kern->current_memory << PAGE_SHIFT;
|
||||
info->id_vendor = kern->device->vendor;
|
||||
info->id_device = kern->device->device;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(drm_agp_info);
|
||||
|
||||
int drm_agp_info_ioctl(struct inode *inode, struct file *filp,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
drm_file_t *priv = filp->private_data;
|
||||
drm_device_t *dev = priv->head->dev;
|
||||
drm_agp_info_t info;
|
||||
int err;
|
||||
|
||||
err = drm_agp_info(dev, &info);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (copy_to_user((drm_agp_info_t __user *) arg, &info, sizeof(info)))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Acquire the AGP device.
|
||||
*
|
||||
* \param dev DRM device that is to acquire AGP.
|
||||
* \return zero on success or a negative number on failure.
|
||||
*
|
||||
* Verifies the AGP device hasn't been acquired before and calls
|
||||
* \c agp_backend_acquire.
|
||||
*/
|
||||
int drm_agp_acquire(drm_device_t * dev)
|
||||
{
|
||||
if (!dev->agp)
|
||||
return -ENODEV;
|
||||
if (dev->agp->acquired)
|
||||
return -EBUSY;
|
||||
if (!(dev->agp->bridge = agp_backend_acquire(dev->pdev)))
|
||||
return -ENODEV;
|
||||
dev->agp->acquired = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(drm_agp_acquire);
|
||||
|
||||
/**
|
||||
* Acquire the AGP device (ioctl).
|
||||
*
|
||||
* \param inode device inode.
|
||||
* \param filp file pointer.
|
||||
* \param cmd command.
|
||||
* \param arg user argument.
|
||||
* \return zero on success or a negative number on failure.
|
||||
*
|
||||
* Verifies the AGP device hasn't been acquired before and calls
|
||||
* \c agp_backend_acquire.
|
||||
*/
|
||||
int drm_agp_acquire_ioctl(struct inode *inode, struct file *filp,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
drm_file_t *priv = filp->private_data;
|
||||
|
||||
return drm_agp_acquire((drm_device_t *) priv->head->dev);
|
||||
}
|
||||
|
||||
/**
|
||||
* Release the AGP device.
|
||||
*
|
||||
* \param dev DRM device that is to release AGP.
|
||||
* \return zero on success or a negative number on failure.
|
||||
*
|
||||
* Verifies the AGP device has been acquired and calls \c agp_backend_release.
|
||||
*/
|
||||
int drm_agp_release(drm_device_t * dev)
|
||||
{
|
||||
if (!dev->agp || !dev->agp->acquired)
|
||||
return -EINVAL;
|
||||
agp_backend_release(dev->agp->bridge);
|
||||
dev->agp->acquired = 0;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_agp_release);
|
||||
|
||||
int drm_agp_release_ioctl(struct inode *inode, struct file *filp,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
drm_file_t *priv = filp->private_data;
|
||||
drm_device_t *dev = priv->head->dev;
|
||||
|
||||
return drm_agp_release(dev);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable the AGP bus.
|
||||
*
|
||||
* \param dev DRM device that has previously acquired AGP.
|
||||
* \param mode Requested AGP mode.
|
||||
* \return zero on success or a negative number on failure.
|
||||
*
|
||||
* Verifies the AGP device has been acquired but not enabled, and calls
|
||||
* \c agp_enable.
|
||||
*/
|
||||
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->bridge, mode.mode);
|
||||
dev->agp->base = dev->agp->agp_info.aper_base;
|
||||
dev->agp->enabled = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(drm_agp_enable);
|
||||
|
||||
int drm_agp_enable_ioctl(struct inode *inode, struct file *filp,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
drm_file_t *priv = filp->private_data;
|
||||
drm_device_t *dev = priv->head->dev;
|
||||
drm_agp_mode_t mode;
|
||||
|
||||
if (copy_from_user(&mode, (drm_agp_mode_t __user *) arg, sizeof(mode)))
|
||||
return -EFAULT;
|
||||
|
||||
return drm_agp_enable(dev, mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate AGP memory.
|
||||
*
|
||||
* \param inode device inode.
|
||||
* \param filp file pointer.
|
||||
* \param cmd command.
|
||||
* \param arg pointer to a drm_agp_buffer structure.
|
||||
* \return zero on success or a negative number on failure.
|
||||
*
|
||||
* Verifies the AGP device is present and has been acquired, allocates the
|
||||
* memory via alloc_agp() and creates a drm_agp_mem entry for it.
|
||||
*/
|
||||
int drm_agp_alloc(drm_device_t *dev, drm_agp_buffer_t *request)
|
||||
{
|
||||
drm_agp_mem_t *entry;
|
||||
DRM_AGP_MEM *memory;
|
||||
unsigned long pages;
|
||||
u32 type;
|
||||
|
||||
if (!dev->agp || !dev->agp->acquired)
|
||||
return -EINVAL;
|
||||
if (!(entry = drm_alloc(sizeof(*entry), DRM_MEM_AGPLISTS)))
|
||||
return -ENOMEM;
|
||||
|
||||
memset(entry, 0, sizeof(*entry));
|
||||
|
||||
pages = (request->size + PAGE_SIZE - 1) / PAGE_SIZE;
|
||||
type = (u32) request->type;
|
||||
if (!(memory = drm_alloc_agp(dev, pages, type))) {
|
||||
drm_free(entry, sizeof(*entry), DRM_MEM_AGPLISTS);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
entry->handle = (unsigned long)memory->key + 1;
|
||||
entry->memory = memory;
|
||||
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;
|
||||
|
||||
request->handle = entry->handle;
|
||||
request->physical = memory->physical;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_agp_alloc);
|
||||
|
||||
int drm_agp_alloc_ioctl(struct inode *inode, struct file *filp,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
drm_file_t *priv = filp->private_data;
|
||||
drm_device_t *dev = priv->head->dev;
|
||||
drm_agp_buffer_t request;
|
||||
drm_agp_buffer_t __user *argp = (void __user *)arg;
|
||||
int err;
|
||||
|
||||
if (copy_from_user(&request, argp, sizeof(request)))
|
||||
return -EFAULT;
|
||||
|
||||
err = drm_agp_alloc(dev, &request);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (copy_to_user(argp, &request, sizeof(request))) {
|
||||
drm_agp_mem_t *entry = dev->agp->memory;
|
||||
|
||||
dev->agp->memory = entry->next;
|
||||
dev->agp->memory->prev = NULL;
|
||||
drm_free_agp(entry->memory, entry->pages);
|
||||
drm_free(entry, sizeof(*entry), DRM_MEM_AGPLISTS);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for the AGP memory entry associated with a handle.
|
||||
*
|
||||
* \param dev DRM device structure.
|
||||
* \param handle AGP memory handle.
|
||||
* \return pointer to the drm_agp_mem structure associated with \p handle.
|
||||
*
|
||||
* Walks through drm_agp_head::memory until finding a matching handle.
|
||||
*/
|
||||
static drm_agp_mem_t *drm_agp_lookup_entry(drm_device_t * dev,
|
||||
unsigned long handle)
|
||||
{
|
||||
drm_agp_mem_t *entry;
|
||||
|
||||
for (entry = dev->agp->memory; entry; entry = entry->next) {
|
||||
if (entry->handle == handle)
|
||||
return entry;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unbind AGP memory from the GATT (ioctl).
|
||||
*
|
||||
* \param inode device inode.
|
||||
* \param filp file pointer.
|
||||
* \param cmd command.
|
||||
* \param arg pointer to a drm_agp_binding structure.
|
||||
* \return zero on success or a negative number on failure.
|
||||
*
|
||||
* Verifies the AGP device is present and acquired, looks-up the AGP memory
|
||||
* entry and passes it to the unbind_agp() function.
|
||||
*/
|
||||
int drm_agp_unbind(drm_device_t *dev, drm_agp_binding_t *request)
|
||||
{
|
||||
drm_agp_mem_t *entry;
|
||||
int ret;
|
||||
|
||||
if (!dev->agp || !dev->agp->acquired)
|
||||
return -EINVAL;
|
||||
if (!(entry = drm_agp_lookup_entry(dev, request->handle)))
|
||||
return -EINVAL;
|
||||
if (!entry->bound)
|
||||
return -EINVAL;
|
||||
ret = drm_unbind_agp(entry->memory);
|
||||
if (ret == 0)
|
||||
entry->bound = 0;
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_agp_unbind);
|
||||
|
||||
int drm_agp_unbind_ioctl(struct inode *inode, struct file *filp,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
drm_file_t *priv = filp->private_data;
|
||||
drm_device_t *dev = priv->head->dev;
|
||||
drm_agp_binding_t request;
|
||||
|
||||
if (copy_from_user
|
||||
(&request, (drm_agp_binding_t __user *) arg, sizeof(request)))
|
||||
return -EFAULT;
|
||||
|
||||
return drm_agp_unbind(dev, &request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind AGP memory into the GATT (ioctl)
|
||||
*
|
||||
* \param inode device inode.
|
||||
* \param filp file pointer.
|
||||
* \param cmd command.
|
||||
* \param arg pointer to a drm_agp_binding structure.
|
||||
* \return zero on success or a negative number on failure.
|
||||
*
|
||||
* Verifies the AGP device is present and has been acquired and that no memory
|
||||
* is currently bound into the GATT. Looks-up the AGP memory entry and passes
|
||||
* it to bind_agp() function.
|
||||
*/
|
||||
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;
|
||||
if (!(entry = drm_agp_lookup_entry(dev, request->handle)))
|
||||
return -EINVAL;
|
||||
if (entry->bound)
|
||||
return -EINVAL;
|
||||
page = (request->offset + PAGE_SIZE - 1) / PAGE_SIZE;
|
||||
if ((retcode = drm_bind_agp(entry->memory, page)))
|
||||
return retcode;
|
||||
entry->bound = dev->agp->base + (page << PAGE_SHIFT);
|
||||
DRM_DEBUG("base = 0x%lx entry->bound = 0x%lx\n",
|
||||
dev->agp->base, entry->bound);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_agp_bind);
|
||||
|
||||
int drm_agp_bind_ioctl(struct inode *inode, struct file *filp,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
drm_file_t *priv = filp->private_data;
|
||||
drm_device_t *dev = priv->head->dev;
|
||||
drm_agp_binding_t request;
|
||||
|
||||
if (copy_from_user
|
||||
(&request, (drm_agp_binding_t __user *) arg, sizeof(request)))
|
||||
return -EFAULT;
|
||||
|
||||
return drm_agp_bind(dev, &request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Free AGP memory (ioctl).
|
||||
*
|
||||
* \param inode device inode.
|
||||
* \param filp file pointer.
|
||||
* \param cmd command.
|
||||
* \param arg pointer to a drm_agp_buffer structure.
|
||||
* \return zero on success or a negative number on failure.
|
||||
*
|
||||
* Verifies the AGP device is present and has been acquired and looks up the
|
||||
* AGP memory entry. If the memory it's currently bound, unbind it via
|
||||
* unbind_agp(). Frees it via free_agp() as well as the entry itself
|
||||
* and unlinks from the doubly linked list it's inserted in.
|
||||
*/
|
||||
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;
|
||||
if (!(entry = drm_agp_lookup_entry(dev, request->handle)))
|
||||
return -EINVAL;
|
||||
if (entry->bound)
|
||||
drm_unbind_agp(entry->memory);
|
||||
|
||||
if (entry->prev)
|
||||
entry->prev->next = entry->next;
|
||||
else
|
||||
dev->agp->memory = entry->next;
|
||||
|
||||
if (entry->next)
|
||||
entry->next->prev = entry->prev;
|
||||
|
||||
drm_free_agp(entry->memory, entry->pages);
|
||||
drm_free(entry, sizeof(*entry), DRM_MEM_AGPLISTS);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_agp_free);
|
||||
|
||||
int drm_agp_free_ioctl(struct inode *inode, struct file *filp,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
drm_file_t *priv = filp->private_data;
|
||||
drm_device_t *dev = priv->head->dev;
|
||||
drm_agp_buffer_t request;
|
||||
|
||||
if (copy_from_user
|
||||
(&request, (drm_agp_buffer_t __user *) arg, sizeof(request)))
|
||||
return -EFAULT;
|
||||
|
||||
return drm_agp_free(dev, &request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the AGP resources.
|
||||
*
|
||||
* \return pointer to a drm_agp_head structure.
|
||||
*
|
||||
* Gets the drm_agp_t structure which is made available by the agpgart module
|
||||
* via the inter_module_* functions. Creates and initializes a drm_agp_head
|
||||
* structure.
|
||||
*/
|
||||
drm_agp_head_t *drm_agp_init(drm_device_t * dev)
|
||||
{
|
||||
drm_agp_head_t *head = NULL;
|
||||
|
||||
if (!(head = drm_alloc(sizeof(*head), DRM_MEM_AGPLISTS)))
|
||||
return NULL;
|
||||
memset((void *)head, 0, sizeof(*head));
|
||||
head->bridge = agp_find_bridge(dev->pdev);
|
||||
if (!head->bridge) {
|
||||
if (!(head->bridge = agp_backend_acquire(dev->pdev))) {
|
||||
drm_free(head, sizeof(*head), DRM_MEM_AGPLISTS);
|
||||
return NULL;
|
||||
}
|
||||
agp_copy_info(head->bridge, &head->agp_info);
|
||||
agp_backend_release(head->bridge);
|
||||
} else {
|
||||
agp_copy_info(head->bridge, &head->agp_info);
|
||||
}
|
||||
if (head->agp_info.chipset == NOT_SUPPORTED) {
|
||||
drm_free(head, sizeof(*head), DRM_MEM_AGPLISTS);
|
||||
return NULL;
|
||||
}
|
||||
head->memory = NULL;
|
||||
head->cant_use_aperture = head->agp_info.cant_use_aperture;
|
||||
head->page_mask = head->agp_info.page_mask;
|
||||
|
||||
return head;
|
||||
}
|
||||
|
||||
/** Calls agp_allocate_memory() */
|
||||
DRM_AGP_MEM *drm_agp_allocate_memory(struct agp_bridge_data * bridge,
|
||||
size_t pages, u32 type)
|
||||
{
|
||||
return agp_allocate_memory(bridge, pages, type);
|
||||
}
|
||||
|
||||
/** Calls agp_free_memory() */
|
||||
int drm_agp_free_memory(DRM_AGP_MEM * handle)
|
||||
{
|
||||
if (!handle)
|
||||
return 0;
|
||||
agp_free_memory(handle);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** Calls agp_bind_memory() */
|
||||
int drm_agp_bind_memory(DRM_AGP_MEM * handle, off_t start)
|
||||
{
|
||||
if (!handle)
|
||||
return -EINVAL;
|
||||
return agp_bind_memory(handle, start);
|
||||
}
|
||||
|
||||
/** Calls agp_unbind_memory() */
|
||||
int drm_agp_unbind_memory(DRM_AGP_MEM * handle)
|
||||
{
|
||||
if (!handle)
|
||||
return -EINVAL;
|
||||
return agp_unbind_memory(handle);
|
||||
}
|
||||
|
||||
#endif /* __OS_HAS_AGP */
|
||||
198
drivers/char/drm/drm_auth.c
Normal file
198
drivers/char/drm/drm_auth.c
Normal file
@@ -0,0 +1,198 @@
|
||||
/**
|
||||
* \file drm_auth.c
|
||||
* IOCTLs for authentication
|
||||
*
|
||||
* \author Rickard E. (Rik) Faith <faith@valinux.com>
|
||||
* \author Gareth Hughes <gareth@valinux.com>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Created: Tue Feb 2 08:37:54 1999 by faith@valinux.com
|
||||
*
|
||||
* Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
|
||||
* Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "drmP.h"
|
||||
|
||||
/**
|
||||
* Find the file with the given magic number.
|
||||
*
|
||||
* \param dev DRM device.
|
||||
* \param magic magic number.
|
||||
*
|
||||
* Searches in drm_device::magiclist within all files with the same hash key
|
||||
* the one with matching magic number, while holding the drm_device::struct_mutex
|
||||
* lock.
|
||||
*/
|
||||
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;
|
||||
drm_hash_item_t *hash;
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
if (!drm_ht_find_item(&dev->magiclist, (unsigned long)magic, &hash)) {
|
||||
pt = drm_hash_entry(hash, drm_magic_entry_t, hash_item);
|
||||
retval = pt->priv;
|
||||
}
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a magic number.
|
||||
*
|
||||
* \param dev DRM device.
|
||||
* \param priv file private data.
|
||||
* \param magic magic number.
|
||||
*
|
||||
* Creates a drm_magic_entry structure and appends to the linked list
|
||||
* associated the magic number hash key in drm_device::magiclist, while holding
|
||||
* the drm_device::struct_mutex lock.
|
||||
*/
|
||||
static int drm_add_magic(drm_device_t * dev, drm_file_t * priv,
|
||||
drm_magic_t magic)
|
||||
{
|
||||
drm_magic_entry_t *entry;
|
||||
|
||||
DRM_DEBUG("%d\n", magic);
|
||||
|
||||
entry = drm_alloc(sizeof(*entry), DRM_MEM_MAGIC);
|
||||
if (!entry)
|
||||
return -ENOMEM;
|
||||
memset(entry, 0, sizeof(*entry));
|
||||
entry->priv = priv;
|
||||
|
||||
entry->hash_item.key = (unsigned long)magic;
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
drm_ht_insert_item(&dev->magiclist, &entry->hash_item);
|
||||
list_add_tail(&entry->head, &dev->magicfree);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a magic number.
|
||||
*
|
||||
* \param dev DRM device.
|
||||
* \param magic magic number.
|
||||
*
|
||||
* Searches and unlinks the entry in drm_device::magiclist with the magic
|
||||
* number hash key, while holding the drm_device::struct_mutex lock.
|
||||
*/
|
||||
static int drm_remove_magic(drm_device_t * dev, drm_magic_t magic)
|
||||
{
|
||||
drm_magic_entry_t *pt;
|
||||
drm_hash_item_t *hash;
|
||||
|
||||
DRM_DEBUG("%d\n", magic);
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
if (drm_ht_find_item(&dev->magiclist, (unsigned long)magic, &hash)) {
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return -EINVAL;
|
||||
}
|
||||
pt = drm_hash_entry(hash, drm_magic_entry_t, hash_item);
|
||||
drm_ht_remove_item(&dev->magiclist, hash);
|
||||
list_del(&pt->head);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
drm_free(pt, sizeof(*pt), DRM_MEM_MAGIC);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a unique magic number (ioctl).
|
||||
*
|
||||
* \param inode device inode.
|
||||
* \param filp file pointer.
|
||||
* \param cmd command.
|
||||
* \param arg pointer to a resulting drm_auth structure.
|
||||
* \return zero on success, or a negative number on failure.
|
||||
*
|
||||
* If there is a magic number in drm_file::magic then use it, otherwise
|
||||
* searches an unique non-zero magic number and add it associating it with \p
|
||||
* filp.
|
||||
*/
|
||||
int drm_getmagic(struct inode *inode, struct file *filp,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
static drm_magic_t sequence = 0;
|
||||
static DEFINE_SPINLOCK(lock);
|
||||
drm_file_t *priv = filp->private_data;
|
||||
drm_device_t *dev = priv->head->dev;
|
||||
drm_auth_t auth;
|
||||
|
||||
/* Find unique magic */
|
||||
if (priv->magic) {
|
||||
auth.magic = priv->magic;
|
||||
} else {
|
||||
do {
|
||||
spin_lock(&lock);
|
||||
if (!sequence)
|
||||
++sequence; /* reserve 0 */
|
||||
auth.magic = sequence++;
|
||||
spin_unlock(&lock);
|
||||
} while (drm_find_file(dev, auth.magic));
|
||||
priv->magic = auth.magic;
|
||||
drm_add_magic(dev, priv, auth.magic);
|
||||
}
|
||||
|
||||
DRM_DEBUG("%u\n", auth.magic);
|
||||
if (copy_to_user((drm_auth_t __user *) arg, &auth, sizeof(auth)))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Authenticate with a magic.
|
||||
*
|
||||
* \param inode device inode.
|
||||
* \param filp file pointer.
|
||||
* \param cmd command.
|
||||
* \param arg pointer to a drm_auth structure.
|
||||
* \return zero if authentication successed, or a negative number otherwise.
|
||||
*
|
||||
* Checks if \p filp is associated with the magic number passed in \arg.
|
||||
*/
|
||||
int drm_authmagic(struct inode *inode, struct file *filp,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
drm_file_t *priv = filp->private_data;
|
||||
drm_device_t *dev = priv->head->dev;
|
||||
drm_auth_t auth;
|
||||
drm_file_t *file;
|
||||
|
||||
if (copy_from_user(&auth, (drm_auth_t __user *) arg, sizeof(auth)))
|
||||
return -EFAULT;
|
||||
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 -EINVAL;
|
||||
}
|
||||
1606
drivers/char/drm/drm_bufs.c
Normal file
1606
drivers/char/drm/drm_bufs.c
Normal file
File diff suppressed because it is too large
Load Diff
594
drivers/char/drm/drm_context.c
Normal file
594
drivers/char/drm/drm_context.c
Normal file
@@ -0,0 +1,594 @@
|
||||
/**
|
||||
* \file drm_context.c
|
||||
* IOCTLs for generic contexts
|
||||
*
|
||||
* \author Rickard E. (Rik) Faith <faith@valinux.com>
|
||||
* \author Gareth Hughes <gareth@valinux.com>
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* ChangeLog:
|
||||
* 2001-11-16 Torsten Duwe <duwe@caldera.de>
|
||||
* added context constructor/destructor hooks,
|
||||
* needed by SiS driver's memory management.
|
||||
*/
|
||||
|
||||
#include "drmP.h"
|
||||
|
||||
/******************************************************************/
|
||||
/** \name Context bitmap support */
|
||||
/*@{*/
|
||||
|
||||
/**
|
||||
* Free a handle from the context bitmap.
|
||||
*
|
||||
* \param dev DRM device.
|
||||
* \param ctx_handle context handle.
|
||||
*
|
||||
* Clears the bit specified by \p ctx_handle in drm_device::ctx_bitmap and the entry
|
||||
* in drm_device::context_sareas, while holding the drm_device::struct_mutex
|
||||
* lock.
|
||||
*/
|
||||
void drm_ctxbitmap_free(drm_device_t * dev, int ctx_handle)
|
||||
{
|
||||
if (ctx_handle < 0)
|
||||
goto failed;
|
||||
if (!dev->ctx_bitmap)
|
||||
goto failed;
|
||||
|
||||
if (ctx_handle < DRM_MAX_CTXBITMAP) {
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
clear_bit(ctx_handle, dev->ctx_bitmap);
|
||||
dev->context_sareas[ctx_handle] = NULL;
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return;
|
||||
}
|
||||
failed:
|
||||
DRM_ERROR("Attempt to free invalid context handle: %d\n", ctx_handle);
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Context bitmap allocation.
|
||||
*
|
||||
* \param dev DRM device.
|
||||
* \return (non-negative) context handle on success or a negative number on failure.
|
||||
*
|
||||
* Find the first zero bit in drm_device::ctx_bitmap and (re)allocates
|
||||
* drm_device::context_sareas to accommodate the new entry while holding the
|
||||
* drm_device::struct_mutex lock.
|
||||
*/
|
||||
static int drm_ctxbitmap_next(drm_device_t * dev)
|
||||
{
|
||||
int bit;
|
||||
|
||||
if (!dev->ctx_bitmap)
|
||||
return -1;
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
bit = find_first_zero_bit(dev->ctx_bitmap, DRM_MAX_CTXBITMAP);
|
||||
if (bit < DRM_MAX_CTXBITMAP) {
|
||||
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) {
|
||||
drm_map_t **ctx_sareas;
|
||||
|
||||
ctx_sareas = drm_realloc(dev->context_sareas,
|
||||
(dev->max_context -
|
||||
1) *
|
||||
sizeof(*dev->
|
||||
context_sareas),
|
||||
dev->max_context *
|
||||
sizeof(*dev->
|
||||
context_sareas),
|
||||
DRM_MEM_MAPS);
|
||||
if (!ctx_sareas) {
|
||||
clear_bit(bit, dev->ctx_bitmap);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return -1;
|
||||
}
|
||||
dev->context_sareas = ctx_sareas;
|
||||
dev->context_sareas[bit] = NULL;
|
||||
} else {
|
||||
/* max_context == 1 at this point */
|
||||
dev->context_sareas =
|
||||
drm_alloc(dev->max_context *
|
||||
sizeof(*dev->context_sareas),
|
||||
DRM_MEM_MAPS);
|
||||
if (!dev->context_sareas) {
|
||||
clear_bit(bit, dev->ctx_bitmap);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return -1;
|
||||
}
|
||||
dev->context_sareas[bit] = NULL;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return bit;
|
||||
}
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Context bitmap initialization.
|
||||
*
|
||||
* \param dev DRM device.
|
||||
*
|
||||
* Allocates and initialize drm_device::ctx_bitmap and drm_device::context_sareas, while holding
|
||||
* the drm_device::struct_mutex lock.
|
||||
*/
|
||||
int drm_ctxbitmap_init(drm_device_t * dev)
|
||||
{
|
||||
int i;
|
||||
int temp;
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
dev->ctx_bitmap = (unsigned long *)drm_alloc(PAGE_SIZE,
|
||||
DRM_MEM_CTXBITMAP);
|
||||
if (dev->ctx_bitmap == NULL) {
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return -ENOMEM;
|
||||
}
|
||||
memset((void *)dev->ctx_bitmap, 0, PAGE_SIZE);
|
||||
dev->context_sareas = NULL;
|
||||
dev->max_context = -1;
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) {
|
||||
temp = drm_ctxbitmap_next(dev);
|
||||
DRM_DEBUG("drm_ctxbitmap_init : %d\n", temp);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Context bitmap cleanup.
|
||||
*
|
||||
* \param dev DRM device.
|
||||
*
|
||||
* Frees drm_device::ctx_bitmap and drm_device::context_sareas, while holding
|
||||
* the drm_device::struct_mutex lock.
|
||||
*/
|
||||
void drm_ctxbitmap_cleanup(drm_device_t * dev)
|
||||
{
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
if (dev->context_sareas)
|
||||
drm_free(dev->context_sareas,
|
||||
sizeof(*dev->context_sareas) *
|
||||
dev->max_context, DRM_MEM_MAPS);
|
||||
drm_free((void *)dev->ctx_bitmap, PAGE_SIZE, DRM_MEM_CTXBITMAP);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
}
|
||||
|
||||
/*@}*/
|
||||
|
||||
/******************************************************************/
|
||||
/** \name Per Context SAREA Support */
|
||||
/*@{*/
|
||||
|
||||
/**
|
||||
* Get per-context SAREA.
|
||||
*
|
||||
* \param inode device inode.
|
||||
* \param filp file pointer.
|
||||
* \param cmd command.
|
||||
* \param arg user argument pointing to a drm_ctx_priv_map structure.
|
||||
* \return zero on success or a negative number on failure.
|
||||
*
|
||||
* Gets the map from drm_device::context_sareas with the handle specified and
|
||||
* returns its handle.
|
||||
*/
|
||||
int drm_getsareactx(struct inode *inode, struct file *filp,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
drm_file_t *priv = filp->private_data;
|
||||
drm_device_t *dev = priv->head->dev;
|
||||
drm_ctx_priv_map_t __user *argp = (void __user *)arg;
|
||||
drm_ctx_priv_map_t request;
|
||||
drm_map_t *map;
|
||||
drm_map_list_t *_entry;
|
||||
|
||||
if (copy_from_user(&request, argp, sizeof(request)))
|
||||
return -EFAULT;
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
if (dev->max_context < 0
|
||||
|| request.ctx_id >= (unsigned)dev->max_context) {
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
map = dev->context_sareas[request.ctx_id];
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
request.handle = NULL;
|
||||
list_for_each_entry(_entry, &dev->maplist->head, head) {
|
||||
if (_entry->map == map) {
|
||||
request.handle =
|
||||
(void *)(unsigned long)_entry->user_token;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (request.handle == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
if (copy_to_user(argp, &request, sizeof(request)))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set per-context SAREA.
|
||||
*
|
||||
* \param inode device inode.
|
||||
* \param filp file pointer.
|
||||
* \param cmd command.
|
||||
* \param arg user argument pointing to a drm_ctx_priv_map structure.
|
||||
* \return zero on success or a negative number on failure.
|
||||
*
|
||||
* Searches the mapping specified in \p arg and update the entry in
|
||||
* drm_device::context_sareas with it.
|
||||
*/
|
||||
int drm_setsareactx(struct inode *inode, struct file *filp,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
drm_file_t *priv = filp->private_data;
|
||||
drm_device_t *dev = priv->head->dev;
|
||||
drm_ctx_priv_map_t request;
|
||||
drm_map_t *map = NULL;
|
||||
drm_map_list_t *r_list = NULL;
|
||||
struct list_head *list;
|
||||
|
||||
if (copy_from_user(&request,
|
||||
(drm_ctx_priv_map_t __user *) arg, sizeof(request)))
|
||||
return -EFAULT;
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
list_for_each(list, &dev->maplist->head) {
|
||||
r_list = list_entry(list, drm_map_list_t, head);
|
||||
if (r_list->map
|
||||
&& r_list->user_token == (unsigned long)request.handle)
|
||||
goto found;
|
||||
}
|
||||
bad:
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return -EINVAL;
|
||||
|
||||
found:
|
||||
map = r_list->map;
|
||||
if (!map)
|
||||
goto bad;
|
||||
if (dev->max_context < 0)
|
||||
goto bad;
|
||||
if (request.ctx_id >= (unsigned)dev->max_context)
|
||||
goto bad;
|
||||
dev->context_sareas[request.ctx_id] = map;
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*@}*/
|
||||
|
||||
/******************************************************************/
|
||||
/** \name The actual DRM context handling routines */
|
||||
/*@{*/
|
||||
|
||||
/**
|
||||
* Switch context.
|
||||
*
|
||||
* \param dev DRM device.
|
||||
* \param old old context handle.
|
||||
* \param new new context handle.
|
||||
* \return zero on success or a negative number on failure.
|
||||
*
|
||||
* Attempt to set drm_device::context_flag.
|
||||
*/
|
||||
static 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 -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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Complete context switch.
|
||||
*
|
||||
* \param dev DRM device.
|
||||
* \param new new context handle.
|
||||
* \return zero on success or a negative number on failure.
|
||||
*
|
||||
* Updates drm_device::last_context and drm_device::last_switch. Verifies the
|
||||
* hardware lock is held, clears the drm_device::context_flag and wakes up
|
||||
* drm_device::context_wait.
|
||||
*/
|
||||
static int drm_context_switch_complete(drm_device_t * dev, int new)
|
||||
{
|
||||
dev->last_context = new; /* PRE/POST: This is the _only_ writer. */
|
||||
dev->last_switch = jiffies;
|
||||
|
||||
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);
|
||||
wake_up(&dev->context_wait);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reserve contexts.
|
||||
*
|
||||
* \param inode device inode.
|
||||
* \param filp file pointer.
|
||||
* \param cmd command.
|
||||
* \param arg user argument pointing to a drm_ctx_res structure.
|
||||
* \return zero on success or a negative number on failure.
|
||||
*/
|
||||
int drm_resctx(struct inode *inode, struct file *filp,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
drm_ctx_res_t res;
|
||||
drm_ctx_t __user *argp = (void __user *)arg;
|
||||
drm_ctx_t ctx;
|
||||
int i;
|
||||
|
||||
if (copy_from_user(&res, argp, sizeof(res)))
|
||||
return -EFAULT;
|
||||
|
||||
if (res.count >= DRM_RESERVED_CONTEXTS) {
|
||||
memset(&ctx, 0, sizeof(ctx));
|
||||
for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) {
|
||||
ctx.handle = i;
|
||||
if (copy_to_user(&res.contexts[i], &ctx, sizeof(ctx)))
|
||||
return -EFAULT;
|
||||
}
|
||||
}
|
||||
res.count = DRM_RESERVED_CONTEXTS;
|
||||
|
||||
if (copy_to_user(argp, &res, sizeof(res)))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add context.
|
||||
*
|
||||
* \param inode device inode.
|
||||
* \param filp file pointer.
|
||||
* \param cmd command.
|
||||
* \param arg user argument pointing to a drm_ctx structure.
|
||||
* \return zero on success or a negative number on failure.
|
||||
*
|
||||
* Get a new handle for the context and copy to userspace.
|
||||
*/
|
||||
int drm_addctx(struct inode *inode, struct file *filp,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
drm_file_t *priv = filp->private_data;
|
||||
drm_device_t *dev = priv->head->dev;
|
||||
drm_ctx_list_t *ctx_entry;
|
||||
drm_ctx_t __user *argp = (void __user *)arg;
|
||||
drm_ctx_t ctx;
|
||||
|
||||
if (copy_from_user(&ctx, argp, sizeof(ctx)))
|
||||
return -EFAULT;
|
||||
|
||||
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 -ENOMEM;
|
||||
}
|
||||
|
||||
if (ctx.handle != DRM_KERNEL_CONTEXT) {
|
||||
if (dev->driver->context_ctor)
|
||||
if (!dev->driver->context_ctor(dev, ctx.handle)) {
|
||||
DRM_DEBUG("Running out of ctxs or memory.\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
ctx_entry = drm_alloc(sizeof(*ctx_entry), DRM_MEM_CTXLIST);
|
||||
if (!ctx_entry) {
|
||||
DRM_DEBUG("out of memory\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&ctx_entry->head);
|
||||
ctx_entry->handle = ctx.handle;
|
||||
ctx_entry->tag = priv;
|
||||
|
||||
mutex_lock(&dev->ctxlist_mutex);
|
||||
list_add(&ctx_entry->head, &dev->ctxlist->head);
|
||||
++dev->ctx_count;
|
||||
mutex_unlock(&dev->ctxlist_mutex);
|
||||
|
||||
if (copy_to_user(argp, &ctx, sizeof(ctx)))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int drm_modctx(struct inode *inode, struct file *filp,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
/* This does nothing */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get context.
|
||||
*
|
||||
* \param inode device inode.
|
||||
* \param filp file pointer.
|
||||
* \param cmd command.
|
||||
* \param arg user argument pointing to a drm_ctx structure.
|
||||
* \return zero on success or a negative number on failure.
|
||||
*/
|
||||
int drm_getctx(struct inode *inode, struct file *filp,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
drm_ctx_t __user *argp = (void __user *)arg;
|
||||
drm_ctx_t ctx;
|
||||
|
||||
if (copy_from_user(&ctx, argp, sizeof(ctx)))
|
||||
return -EFAULT;
|
||||
|
||||
/* This is 0, because we don't handle any context flags */
|
||||
ctx.flags = 0;
|
||||
|
||||
if (copy_to_user(argp, &ctx, sizeof(ctx)))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Switch context.
|
||||
*
|
||||
* \param inode device inode.
|
||||
* \param filp file pointer.
|
||||
* \param cmd command.
|
||||
* \param arg user argument pointing to a drm_ctx structure.
|
||||
* \return zero on success or a negative number on failure.
|
||||
*
|
||||
* Calls context_switch().
|
||||
*/
|
||||
int drm_switchctx(struct inode *inode, struct file *filp,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
drm_file_t *priv = filp->private_data;
|
||||
drm_device_t *dev = priv->head->dev;
|
||||
drm_ctx_t ctx;
|
||||
|
||||
if (copy_from_user(&ctx, (drm_ctx_t __user *) arg, sizeof(ctx)))
|
||||
return -EFAULT;
|
||||
|
||||
DRM_DEBUG("%d\n", ctx.handle);
|
||||
return drm_context_switch(dev, dev->last_context, ctx.handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* New context.
|
||||
*
|
||||
* \param inode device inode.
|
||||
* \param filp file pointer.
|
||||
* \param cmd command.
|
||||
* \param arg user argument pointing to a drm_ctx structure.
|
||||
* \return zero on success or a negative number on failure.
|
||||
*
|
||||
* Calls context_switch_complete().
|
||||
*/
|
||||
int drm_newctx(struct inode *inode, struct file *filp,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
drm_file_t *priv = filp->private_data;
|
||||
drm_device_t *dev = priv->head->dev;
|
||||
drm_ctx_t ctx;
|
||||
|
||||
if (copy_from_user(&ctx, (drm_ctx_t __user *) arg, sizeof(ctx)))
|
||||
return -EFAULT;
|
||||
|
||||
DRM_DEBUG("%d\n", ctx.handle);
|
||||
drm_context_switch_complete(dev, ctx.handle);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove context.
|
||||
*
|
||||
* \param inode device inode.
|
||||
* \param filp file pointer.
|
||||
* \param cmd command.
|
||||
* \param arg user argument pointing to a drm_ctx structure.
|
||||
* \return zero on success or a negative number on failure.
|
||||
*
|
||||
* If not the special kernel context, calls ctxbitmap_free() to free the specified context.
|
||||
*/
|
||||
int drm_rmctx(struct inode *inode, struct file *filp,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
drm_file_t *priv = filp->private_data;
|
||||
drm_device_t *dev = priv->head->dev;
|
||||
drm_ctx_t ctx;
|
||||
|
||||
if (copy_from_user(&ctx, (drm_ctx_t __user *) arg, sizeof(ctx)))
|
||||
return -EFAULT;
|
||||
|
||||
DRM_DEBUG("%d\n", ctx.handle);
|
||||
if (ctx.handle == DRM_KERNEL_CONTEXT + 1) {
|
||||
priv->remove_auth_on_close = 1;
|
||||
}
|
||||
if (ctx.handle != DRM_KERNEL_CONTEXT) {
|
||||
if (dev->driver->context_dtor)
|
||||
dev->driver->context_dtor(dev, ctx.handle);
|
||||
drm_ctxbitmap_free(dev, ctx.handle);
|
||||
}
|
||||
|
||||
mutex_lock(&dev->ctxlist_mutex);
|
||||
if (!list_empty(&dev->ctxlist->head)) {
|
||||
drm_ctx_list_t *pos, *n;
|
||||
|
||||
list_for_each_entry_safe(pos, n, &dev->ctxlist->head, head) {
|
||||
if (pos->handle == ctx.handle) {
|
||||
list_del(&pos->head);
|
||||
drm_free(pos, sizeof(*pos), DRM_MEM_CTXLIST);
|
||||
--dev->ctx_count;
|
||||
}
|
||||
}
|
||||
}
|
||||
mutex_unlock(&dev->ctxlist_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*@}*/
|
||||
34
drivers/char/drm/drm_core.h
Normal file
34
drivers/char/drm/drm_core.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2004 Jon Smirl <jonsmirl@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sub license,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the
|
||||
* next paragraph) shall be included in all copies or substantial portions
|
||||
* of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
|
||||
* VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#define CORE_AUTHOR "Gareth Hughes, Leif Delgass, José Fonseca, Jon Smirl"
|
||||
|
||||
#define CORE_NAME "drm"
|
||||
#define CORE_DESC "DRM shared core routines"
|
||||
#define CORE_DATE "20060810"
|
||||
|
||||
#define DRM_IF_MAJOR 1
|
||||
#define DRM_IF_MINOR 3
|
||||
|
||||
#define CORE_MAJOR 1
|
||||
#define CORE_MINOR 1
|
||||
#define CORE_PATCHLEVEL 0
|
||||
179
drivers/char/drm/drm_dma.c
Normal file
179
drivers/char/drm/drm_dma.c
Normal file
@@ -0,0 +1,179 @@
|
||||
/**
|
||||
* \file drm_dma.c
|
||||
* DMA IOCTL and function support
|
||||
*
|
||||
* \author Rickard E. (Rik) Faith <faith@valinux.com>
|
||||
* \author Gareth Hughes <gareth@valinux.com>
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "drmP.h"
|
||||
|
||||
/**
|
||||
* Initialize the DMA data.
|
||||
*
|
||||
* \param dev DRM device.
|
||||
* \return zero on success or a negative value on failure.
|
||||
*
|
||||
* Allocate and initialize a drm_device_dma structure.
|
||||
*/
|
||||
int drm_dma_setup(drm_device_t * dev)
|
||||
{
|
||||
int i;
|
||||
|
||||
dev->dma = drm_alloc(sizeof(*dev->dma), DRM_MEM_DRIVER);
|
||||
if (!dev->dma)
|
||||
return -ENOMEM;
|
||||
|
||||
memset(dev->dma, 0, sizeof(*dev->dma));
|
||||
|
||||
for (i = 0; i <= DRM_MAX_ORDER; i++)
|
||||
memset(&dev->dma->bufs[i], 0, sizeof(dev->dma->bufs[0]));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleanup the DMA resources.
|
||||
*
|
||||
* \param dev DRM device.
|
||||
*
|
||||
* Free all pages associated with DMA buffers, the buffers and pages lists, and
|
||||
* finally the the drm_device::dma structure itself.
|
||||
*/
|
||||
void drm_dma_takedown(drm_device_t * dev)
|
||||
{
|
||||
drm_device_dma_t *dma = dev->dma;
|
||||
int i, j;
|
||||
|
||||
if (!dma)
|
||||
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++) {
|
||||
if (dma->bufs[i].seglist[j]) {
|
||||
drm_pci_free(dev, dma->bufs[i].seglist[j]);
|
||||
}
|
||||
}
|
||||
drm_free(dma->bufs[i].seglist,
|
||||
dma->bufs[i].seg_count
|
||||
* sizeof(*dma->bufs[0].seglist), DRM_MEM_SEGS);
|
||||
}
|
||||
if (dma->bufs[i].buf_count) {
|
||||
for (j = 0; j < dma->bufs[i].buf_count; j++) {
|
||||
if (dma->bufs[i].buflist[j].dev_private) {
|
||||
drm_free(dma->bufs[i].buflist[j].
|
||||
dev_private,
|
||||
dma->bufs[i].buflist[j].
|
||||
dev_priv_size, DRM_MEM_BUFS);
|
||||
}
|
||||
}
|
||||
drm_free(dma->bufs[i].buflist,
|
||||
dma->bufs[i].buf_count *
|
||||
sizeof(*dma->bufs[0].buflist), DRM_MEM_BUFS);
|
||||
}
|
||||
}
|
||||
|
||||
if (dma->buflist) {
|
||||
drm_free(dma->buflist,
|
||||
dma->buf_count * sizeof(*dma->buflist), DRM_MEM_BUFS);
|
||||
}
|
||||
|
||||
if (dma->pagelist) {
|
||||
drm_free(dma->pagelist,
|
||||
dma->page_count * sizeof(*dma->pagelist),
|
||||
DRM_MEM_PAGES);
|
||||
}
|
||||
drm_free(dev->dma, sizeof(*dev->dma), DRM_MEM_DRIVER);
|
||||
dev->dma = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Free a buffer.
|
||||
*
|
||||
* \param dev DRM device.
|
||||
* \param buf buffer to free.
|
||||
*
|
||||
* Resets the fields of \p buf.
|
||||
*/
|
||||
void drm_free_buffer(drm_device_t * dev, drm_buf_t * buf)
|
||||
{
|
||||
if (!buf)
|
||||
return;
|
||||
|
||||
buf->waiting = 0;
|
||||
buf->pending = 0;
|
||||
buf->filp = NULL;
|
||||
buf->used = 0;
|
||||
|
||||
if (drm_core_check_feature(dev, DRIVER_DMA_QUEUE)
|
||||
&& waitqueue_active(&buf->dma_wait)) {
|
||||
wake_up_interruptible(&buf->dma_wait);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reclaim the buffers.
|
||||
*
|
||||
* \param filp file pointer.
|
||||
*
|
||||
* Frees each buffer associated with \p filp not already on the hardware.
|
||||
*/
|
||||
void drm_core_reclaim_buffers(drm_device_t * dev, struct file *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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(drm_core_reclaim_buffers);
|
||||
330
drivers/char/drm/drm_drawable.c
Normal file
330
drivers/char/drm/drm_drawable.c
Normal file
@@ -0,0 +1,330 @@
|
||||
/**
|
||||
* \file drm_drawable.c
|
||||
* IOCTLs for drawables
|
||||
*
|
||||
* \author Rickard E. (Rik) Faith <faith@valinux.com>
|
||||
* \author Gareth Hughes <gareth@valinux.com>
|
||||
* \author Michel Dänzer <michel@tungstengraphics.com>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Created: Tue Feb 2 08:37:54 1999 by faith@valinux.com
|
||||
*
|
||||
* Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
|
||||
* Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
|
||||
* Copyright 2006 Tungsten Graphics, Inc., Bismarck, North Dakota.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "drmP.h"
|
||||
|
||||
/**
|
||||
* Allocate drawable ID and memory to store information about it.
|
||||
*/
|
||||
int drm_adddraw(DRM_IOCTL_ARGS)
|
||||
{
|
||||
DRM_DEVICE;
|
||||
unsigned long irqflags;
|
||||
int i, j;
|
||||
u32 *bitfield = dev->drw_bitfield;
|
||||
unsigned int bitfield_length = dev->drw_bitfield_length;
|
||||
drm_drawable_info_t **info = dev->drw_info;
|
||||
unsigned int info_length = dev->drw_info_length;
|
||||
drm_draw_t draw;
|
||||
|
||||
for (i = 0, j = 0; i < bitfield_length; i++) {
|
||||
if (bitfield[i] == ~0)
|
||||
continue;
|
||||
|
||||
for (; j < 8 * sizeof(*bitfield); j++)
|
||||
if (!(bitfield[i] & (1 << j)))
|
||||
goto done;
|
||||
}
|
||||
done:
|
||||
|
||||
if (i == bitfield_length) {
|
||||
bitfield_length++;
|
||||
|
||||
bitfield = drm_alloc(bitfield_length * sizeof(*bitfield),
|
||||
DRM_MEM_BUFS);
|
||||
|
||||
if (!bitfield) {
|
||||
DRM_ERROR("Failed to allocate new drawable bitfield\n");
|
||||
return DRM_ERR(ENOMEM);
|
||||
}
|
||||
|
||||
if (8 * sizeof(*bitfield) * bitfield_length > info_length) {
|
||||
info_length += 8 * sizeof(*bitfield);
|
||||
|
||||
info = drm_alloc(info_length * sizeof(*info),
|
||||
DRM_MEM_BUFS);
|
||||
|
||||
if (!info) {
|
||||
DRM_ERROR("Failed to allocate new drawable info"
|
||||
" array\n");
|
||||
|
||||
drm_free(bitfield,
|
||||
bitfield_length * sizeof(*bitfield),
|
||||
DRM_MEM_BUFS);
|
||||
return DRM_ERR(ENOMEM);
|
||||
}
|
||||
}
|
||||
|
||||
bitfield[i] = 0;
|
||||
}
|
||||
|
||||
draw.handle = i * 8 * sizeof(*bitfield) + j + 1;
|
||||
DRM_DEBUG("%d\n", draw.handle);
|
||||
|
||||
spin_lock_irqsave(&dev->drw_lock, irqflags);
|
||||
|
||||
bitfield[i] |= 1 << j;
|
||||
info[draw.handle - 1] = NULL;
|
||||
|
||||
if (bitfield != dev->drw_bitfield) {
|
||||
memcpy(bitfield, dev->drw_bitfield, dev->drw_bitfield_length *
|
||||
sizeof(*bitfield));
|
||||
drm_free(dev->drw_bitfield, sizeof(*bitfield) *
|
||||
dev->drw_bitfield_length, DRM_MEM_BUFS);
|
||||
dev->drw_bitfield = bitfield;
|
||||
dev->drw_bitfield_length = bitfield_length;
|
||||
}
|
||||
|
||||
if (info != dev->drw_info) {
|
||||
memcpy(info, dev->drw_info, dev->drw_info_length *
|
||||
sizeof(*info));
|
||||
drm_free(dev->drw_info, sizeof(*info) * dev->drw_info_length,
|
||||
DRM_MEM_BUFS);
|
||||
dev->drw_info = info;
|
||||
dev->drw_info_length = info_length;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&dev->drw_lock, irqflags);
|
||||
|
||||
DRM_COPY_TO_USER_IOCTL((drm_draw_t __user *)data, draw, sizeof(draw));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Free drawable ID and memory to store information about it.
|
||||
*/
|
||||
int drm_rmdraw(DRM_IOCTL_ARGS)
|
||||
{
|
||||
DRM_DEVICE;
|
||||
drm_draw_t draw;
|
||||
int id, idx;
|
||||
unsigned int shift;
|
||||
unsigned long irqflags;
|
||||
u32 *bitfield = dev->drw_bitfield;
|
||||
unsigned int bitfield_length = dev->drw_bitfield_length;
|
||||
drm_drawable_info_t **info = dev->drw_info;
|
||||
unsigned int info_length = dev->drw_info_length;
|
||||
|
||||
DRM_COPY_FROM_USER_IOCTL(draw, (drm_draw_t __user *) data,
|
||||
sizeof(draw));
|
||||
|
||||
id = draw.handle - 1;
|
||||
idx = id / (8 * sizeof(*bitfield));
|
||||
shift = id % (8 * sizeof(*bitfield));
|
||||
|
||||
if (idx < 0 || idx >= bitfield_length ||
|
||||
!(bitfield[idx] & (1 << shift))) {
|
||||
DRM_DEBUG("No such drawable %d\n", draw.handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&dev->drw_lock, irqflags);
|
||||
|
||||
bitfield[idx] &= ~(1 << shift);
|
||||
|
||||
spin_unlock_irqrestore(&dev->drw_lock, irqflags);
|
||||
|
||||
if (info[id]) {
|
||||
drm_free(info[id]->rects, info[id]->num_rects *
|
||||
sizeof(drm_clip_rect_t), DRM_MEM_BUFS);
|
||||
drm_free(info[id], sizeof(**info), DRM_MEM_BUFS);
|
||||
}
|
||||
|
||||
/* Can we shrink the arrays? */
|
||||
if (idx == bitfield_length - 1) {
|
||||
while (idx >= 0 && !bitfield[idx])
|
||||
--idx;
|
||||
|
||||
bitfield_length = idx + 1;
|
||||
|
||||
if (idx != id / (8 * sizeof(*bitfield)))
|
||||
bitfield = drm_alloc(bitfield_length *
|
||||
sizeof(*bitfield), DRM_MEM_BUFS);
|
||||
|
||||
if (!bitfield && bitfield_length) {
|
||||
bitfield = dev->drw_bitfield;
|
||||
bitfield_length = dev->drw_bitfield_length;
|
||||
}
|
||||
}
|
||||
|
||||
if (bitfield != dev->drw_bitfield) {
|
||||
info_length = 8 * sizeof(*bitfield) * bitfield_length;
|
||||
|
||||
info = drm_alloc(info_length * sizeof(*info), DRM_MEM_BUFS);
|
||||
|
||||
if (!info && info_length) {
|
||||
info = dev->drw_info;
|
||||
info_length = dev->drw_info_length;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&dev->drw_lock, irqflags);
|
||||
|
||||
memcpy(bitfield, dev->drw_bitfield, bitfield_length *
|
||||
sizeof(*bitfield));
|
||||
drm_free(dev->drw_bitfield, sizeof(*bitfield) *
|
||||
dev->drw_bitfield_length, DRM_MEM_BUFS);
|
||||
dev->drw_bitfield = bitfield;
|
||||
dev->drw_bitfield_length = bitfield_length;
|
||||
|
||||
if (info != dev->drw_info) {
|
||||
memcpy(info, dev->drw_info, info_length *
|
||||
sizeof(*info));
|
||||
drm_free(dev->drw_info, sizeof(*info) *
|
||||
dev->drw_info_length, DRM_MEM_BUFS);
|
||||
dev->drw_info = info;
|
||||
dev->drw_info_length = info_length;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&dev->drw_lock, irqflags);
|
||||
}
|
||||
|
||||
DRM_DEBUG("%d\n", draw.handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int drm_update_drawable_info(DRM_IOCTL_ARGS) {
|
||||
DRM_DEVICE;
|
||||
drm_update_draw_t update;
|
||||
unsigned int id, idx, shift;
|
||||
u32 *bitfield = dev->drw_bitfield;
|
||||
unsigned long irqflags, bitfield_length = dev->drw_bitfield_length;
|
||||
drm_drawable_info_t *info;
|
||||
drm_clip_rect_t *rects;
|
||||
int err;
|
||||
|
||||
DRM_COPY_FROM_USER_IOCTL(update, (drm_update_draw_t __user *) data,
|
||||
sizeof(update));
|
||||
|
||||
id = update.handle - 1;
|
||||
idx = id / (8 * sizeof(*bitfield));
|
||||
shift = id % (8 * sizeof(*bitfield));
|
||||
|
||||
if (idx < 0 || idx >= bitfield_length ||
|
||||
!(bitfield[idx] & (1 << shift))) {
|
||||
DRM_ERROR("No such drawable %d\n", update.handle);
|
||||
return DRM_ERR(EINVAL);
|
||||
}
|
||||
|
||||
info = dev->drw_info[id];
|
||||
|
||||
if (!info) {
|
||||
info = drm_calloc(1, sizeof(drm_drawable_info_t), DRM_MEM_BUFS);
|
||||
|
||||
if (!info) {
|
||||
DRM_ERROR("Failed to allocate drawable info memory\n");
|
||||
return DRM_ERR(ENOMEM);
|
||||
}
|
||||
}
|
||||
|
||||
switch (update.type) {
|
||||
case DRM_DRAWABLE_CLIPRECTS:
|
||||
if (update.num != info->num_rects) {
|
||||
rects = drm_alloc(update.num * sizeof(drm_clip_rect_t),
|
||||
DRM_MEM_BUFS);
|
||||
} else
|
||||
rects = info->rects;
|
||||
|
||||
if (update.num && !rects) {
|
||||
DRM_ERROR("Failed to allocate cliprect memory\n");
|
||||
err = DRM_ERR(ENOMEM);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (update.num && DRM_COPY_FROM_USER(rects,
|
||||
(drm_clip_rect_t __user *)
|
||||
(unsigned long)update.data,
|
||||
update.num *
|
||||
sizeof(*rects))) {
|
||||
DRM_ERROR("Failed to copy cliprects from userspace\n");
|
||||
err = DRM_ERR(EFAULT);
|
||||
goto error;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&dev->drw_lock, irqflags);
|
||||
|
||||
if (rects != info->rects) {
|
||||
drm_free(info->rects, info->num_rects *
|
||||
sizeof(drm_clip_rect_t), DRM_MEM_BUFS);
|
||||
}
|
||||
|
||||
info->rects = rects;
|
||||
info->num_rects = update.num;
|
||||
dev->drw_info[id] = info;
|
||||
|
||||
spin_unlock_irqrestore(&dev->drw_lock, irqflags);
|
||||
|
||||
DRM_DEBUG("Updated %d cliprects for drawable %d\n",
|
||||
info->num_rects, id);
|
||||
break;
|
||||
default:
|
||||
DRM_ERROR("Invalid update type %d\n", update.type);
|
||||
return DRM_ERR(EINVAL);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
if (!dev->drw_info[id])
|
||||
drm_free(info, sizeof(*info), DRM_MEM_BUFS);
|
||||
else if (rects != dev->drw_info[id]->rects)
|
||||
drm_free(rects, update.num *
|
||||
sizeof(drm_clip_rect_t), DRM_MEM_BUFS);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* Caller must hold the drawable spinlock!
|
||||
*/
|
||||
drm_drawable_info_t *drm_get_drawable_info(drm_device_t *dev, drm_drawable_t id) {
|
||||
u32 *bitfield = dev->drw_bitfield;
|
||||
unsigned int idx, shift;
|
||||
|
||||
id--;
|
||||
idx = id / (8 * sizeof(*bitfield));
|
||||
shift = id % (8 * sizeof(*bitfield));
|
||||
|
||||
if (idx < 0 || idx >= dev->drw_bitfield_length ||
|
||||
!(bitfield[idx] & (1 << shift))) {
|
||||
DRM_DEBUG("No such drawable %d\n", id);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return dev->drw_info[id];
|
||||
}
|
||||
EXPORT_SYMBOL(drm_get_drawable_info);
|
||||
530
drivers/char/drm/drm_drv.c
Normal file
530
drivers/char/drm/drm_drv.c
Normal file
@@ -0,0 +1,530 @@
|
||||
/**
|
||||
* \file drm_drv.c
|
||||
* Generic driver template
|
||||
*
|
||||
* \author Rickard E. (Rik) Faith <faith@valinux.com>
|
||||
* \author Gareth Hughes <gareth@valinux.com>
|
||||
*
|
||||
* To use this template, you must at least define the following (samples
|
||||
* given for the MGA driver):
|
||||
*
|
||||
* \code
|
||||
* #define DRIVER_AUTHOR "VA Linux Systems, Inc."
|
||||
*
|
||||
* #define DRIVER_NAME "mga"
|
||||
* #define DRIVER_DESC "Matrox G200/G400"
|
||||
* #define DRIVER_DATE "20001127"
|
||||
*
|
||||
* #define DRIVER_IOCTL_COUNT DRM_ARRAY_SIZE( mga_ioctls )
|
||||
*
|
||||
* #define drm_x mga_##x
|
||||
* \endcode
|
||||
*/
|
||||
|
||||
/*
|
||||
* Created: Thu Nov 23 03:10:50 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.
|
||||
*/
|
||||
|
||||
#include "drmP.h"
|
||||
#include "drm_core.h"
|
||||
|
||||
static int drm_version(struct inode *inode, struct file *filp,
|
||||
unsigned int cmd, unsigned long arg);
|
||||
|
||||
/** Ioctl table */
|
||||
static drm_ioctl_desc_t drm_ioctls[] = {
|
||||
[DRM_IOCTL_NR(DRM_IOCTL_VERSION)] = {drm_version, 0},
|
||||
[DRM_IOCTL_NR(DRM_IOCTL_GET_UNIQUE)] = {drm_getunique, 0},
|
||||
[DRM_IOCTL_NR(DRM_IOCTL_GET_MAGIC)] = {drm_getmagic, 0},
|
||||
[DRM_IOCTL_NR(DRM_IOCTL_IRQ_BUSID)] = {drm_irq_by_busid, DRM_MASTER|DRM_ROOT_ONLY},
|
||||
[DRM_IOCTL_NR(DRM_IOCTL_GET_MAP)] = {drm_getmap, 0},
|
||||
[DRM_IOCTL_NR(DRM_IOCTL_GET_CLIENT)] = {drm_getclient, 0},
|
||||
[DRM_IOCTL_NR(DRM_IOCTL_GET_STATS)] = {drm_getstats, 0},
|
||||
[DRM_IOCTL_NR(DRM_IOCTL_SET_VERSION)] = {drm_setversion, DRM_MASTER|DRM_ROOT_ONLY},
|
||||
[DRM_IOCTL_NR(DRM_IOCTL_SET_UNIQUE)] = {drm_setunique, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
|
||||
[DRM_IOCTL_NR(DRM_IOCTL_BLOCK)] = {drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
|
||||
[DRM_IOCTL_NR(DRM_IOCTL_UNBLOCK)] = {drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
|
||||
[DRM_IOCTL_NR(DRM_IOCTL_AUTH_MAGIC)] = {drm_authmagic, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
|
||||
|
||||
[DRM_IOCTL_NR(DRM_IOCTL_ADD_MAP)] = {drm_addmap_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
|
||||
[DRM_IOCTL_NR(DRM_IOCTL_RM_MAP)] = {drm_rmmap_ioctl, DRM_AUTH},
|
||||
|
||||
[DRM_IOCTL_NR(DRM_IOCTL_SET_SAREA_CTX)] = {drm_setsareactx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
|
||||
[DRM_IOCTL_NR(DRM_IOCTL_GET_SAREA_CTX)] = {drm_getsareactx, DRM_AUTH},
|
||||
|
||||
[DRM_IOCTL_NR(DRM_IOCTL_ADD_CTX)] = {drm_addctx, DRM_AUTH|DRM_ROOT_ONLY},
|
||||
[DRM_IOCTL_NR(DRM_IOCTL_RM_CTX)] = {drm_rmctx, DRM_AUTH|DRM_ROOT_ONLY},
|
||||
[DRM_IOCTL_NR(DRM_IOCTL_MOD_CTX)] = {drm_modctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
|
||||
[DRM_IOCTL_NR(DRM_IOCTL_GET_CTX)] = {drm_getctx, DRM_AUTH},
|
||||
[DRM_IOCTL_NR(DRM_IOCTL_SWITCH_CTX)] = {drm_switchctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
|
||||
[DRM_IOCTL_NR(DRM_IOCTL_NEW_CTX)] = {drm_newctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
|
||||
[DRM_IOCTL_NR(DRM_IOCTL_RES_CTX)] = {drm_resctx, DRM_AUTH},
|
||||
|
||||
[DRM_IOCTL_NR(DRM_IOCTL_ADD_DRAW)] = {drm_adddraw, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
|
||||
[DRM_IOCTL_NR(DRM_IOCTL_RM_DRAW)] = {drm_rmdraw, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
|
||||
|
||||
[DRM_IOCTL_NR(DRM_IOCTL_LOCK)] = {drm_lock, DRM_AUTH},
|
||||
[DRM_IOCTL_NR(DRM_IOCTL_UNLOCK)] = {drm_unlock, DRM_AUTH},
|
||||
|
||||
[DRM_IOCTL_NR(DRM_IOCTL_FINISH)] = {drm_noop, DRM_AUTH},
|
||||
|
||||
[DRM_IOCTL_NR(DRM_IOCTL_ADD_BUFS)] = {drm_addbufs, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
|
||||
[DRM_IOCTL_NR(DRM_IOCTL_MARK_BUFS)] = {drm_markbufs, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
|
||||
[DRM_IOCTL_NR(DRM_IOCTL_INFO_BUFS)] = {drm_infobufs, DRM_AUTH},
|
||||
[DRM_IOCTL_NR(DRM_IOCTL_MAP_BUFS)] = {drm_mapbufs, DRM_AUTH},
|
||||
[DRM_IOCTL_NR(DRM_IOCTL_FREE_BUFS)] = {drm_freebufs, DRM_AUTH},
|
||||
/* The DRM_IOCTL_DMA ioctl should be defined by the driver. */
|
||||
[DRM_IOCTL_NR(DRM_IOCTL_DMA)] = {NULL, DRM_AUTH},
|
||||
|
||||
[DRM_IOCTL_NR(DRM_IOCTL_CONTROL)] = {drm_control, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
|
||||
|
||||
#if __OS_HAS_AGP
|
||||
[DRM_IOCTL_NR(DRM_IOCTL_AGP_ACQUIRE)] = {drm_agp_acquire_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
|
||||
[DRM_IOCTL_NR(DRM_IOCTL_AGP_RELEASE)] = {drm_agp_release_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
|
||||
[DRM_IOCTL_NR(DRM_IOCTL_AGP_ENABLE)] = {drm_agp_enable_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
|
||||
[DRM_IOCTL_NR(DRM_IOCTL_AGP_INFO)] = {drm_agp_info_ioctl, DRM_AUTH},
|
||||
[DRM_IOCTL_NR(DRM_IOCTL_AGP_ALLOC)] = {drm_agp_alloc_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
|
||||
[DRM_IOCTL_NR(DRM_IOCTL_AGP_FREE)] = {drm_agp_free_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
|
||||
[DRM_IOCTL_NR(DRM_IOCTL_AGP_BIND)] = {drm_agp_bind_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
|
||||
[DRM_IOCTL_NR(DRM_IOCTL_AGP_UNBIND)] = {drm_agp_unbind_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
|
||||
#endif
|
||||
|
||||
[DRM_IOCTL_NR(DRM_IOCTL_SG_ALLOC)] = {drm_sg_alloc, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
|
||||
[DRM_IOCTL_NR(DRM_IOCTL_SG_FREE)] = {drm_sg_free, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
|
||||
|
||||
[DRM_IOCTL_NR(DRM_IOCTL_WAIT_VBLANK)] = {drm_wait_vblank, 0},
|
||||
|
||||
[DRM_IOCTL_NR(DRM_IOCTL_UPDATE_DRAW)] = {drm_update_drawable_info, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
|
||||
};
|
||||
|
||||
#define DRIVER_IOCTL_COUNT ARRAY_SIZE( drm_ioctls )
|
||||
|
||||
/**
|
||||
* Take down the DRM device.
|
||||
*
|
||||
* \param dev DRM device structure.
|
||||
*
|
||||
* Frees every resource in \p dev.
|
||||
*
|
||||
* \sa drm_device
|
||||
*/
|
||||
int drm_lastclose(drm_device_t * dev)
|
||||
{
|
||||
drm_magic_entry_t *pt, *next;
|
||||
drm_map_list_t *r_list;
|
||||
drm_vma_entry_t *vma, *vma_next;
|
||||
int i;
|
||||
|
||||
DRM_DEBUG("\n");
|
||||
|
||||
if (dev->driver->lastclose)
|
||||
dev->driver->lastclose(dev);
|
||||
DRM_DEBUG("driver lastclose completed\n");
|
||||
|
||||
if (dev->unique) {
|
||||
drm_free(dev->unique, strlen(dev->unique) + 1, DRM_MEM_DRIVER);
|
||||
dev->unique = NULL;
|
||||
dev->unique_len = 0;
|
||||
}
|
||||
|
||||
if (dev->irq_enabled)
|
||||
drm_irq_uninstall(dev);
|
||||
|
||||
/* Free drawable information memory */
|
||||
for (i = 0; i < dev->drw_bitfield_length / sizeof(*dev->drw_bitfield);
|
||||
i++) {
|
||||
drm_drawable_info_t *info = drm_get_drawable_info(dev, i);
|
||||
|
||||
if (info) {
|
||||
drm_free(info->rects, info->num_rects *
|
||||
sizeof(drm_clip_rect_t), DRM_MEM_BUFS);
|
||||
drm_free(info, sizeof(*info), DRM_MEM_BUFS);
|
||||
}
|
||||
}
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
del_timer(&dev->timer);
|
||||
|
||||
/* Clear pid list */
|
||||
if (dev->magicfree.next) {
|
||||
list_for_each_entry_safe(pt, next, &dev->magicfree, head) {
|
||||
list_del(&pt->head);
|
||||
drm_ht_remove_item(&dev->magiclist, &pt->hash_item);
|
||||
drm_free(pt, sizeof(*pt), DRM_MEM_MAGIC);
|
||||
}
|
||||
drm_ht_remove(&dev->magiclist);
|
||||
}
|
||||
|
||||
/* Clear AGP information */
|
||||
if (drm_core_has_AGP(dev) && dev->agp) {
|
||||
drm_agp_mem_t *entry;
|
||||
drm_agp_mem_t *nexte;
|
||||
|
||||
/* Remove AGP resources, but leave dev->agp
|
||||
intact until drv_cleanup is called. */
|
||||
for (entry = dev->agp->memory; entry; entry = nexte) {
|
||||
nexte = entry->next;
|
||||
if (entry->bound)
|
||||
drm_unbind_agp(entry->memory);
|
||||
drm_free_agp(entry->memory, entry->pages);
|
||||
drm_free(entry, sizeof(*entry), DRM_MEM_AGPLISTS);
|
||||
}
|
||||
dev->agp->memory = NULL;
|
||||
|
||||
if (dev->agp->acquired)
|
||||
drm_agp_release(dev);
|
||||
|
||||
dev->agp->acquired = 0;
|
||||
dev->agp->enabled = 0;
|
||||
}
|
||||
if (drm_core_check_feature(dev, DRIVER_SG) && dev->sg) {
|
||||
drm_sg_cleanup(dev->sg);
|
||||
dev->sg = NULL;
|
||||
}
|
||||
|
||||
/* Clear vma list (only built for debugging) */
|
||||
if (dev->vmalist) {
|
||||
for (vma = dev->vmalist; vma; vma = vma_next) {
|
||||
vma_next = vma->next;
|
||||
drm_free(vma, sizeof(*vma), DRM_MEM_VMAS);
|
||||
}
|
||||
dev->vmalist = NULL;
|
||||
}
|
||||
|
||||
if (dev->maplist) {
|
||||
while (!list_empty(&dev->maplist->head)) {
|
||||
struct list_head *list = dev->maplist->head.next;
|
||||
r_list = list_entry(list, drm_map_list_t, head);
|
||||
drm_rmmap_locked(dev, r_list->map);
|
||||
}
|
||||
}
|
||||
|
||||
if (drm_core_check_feature(dev, DRIVER_DMA_QUEUE) && dev->queuelist) {
|
||||
for (i = 0; i < dev->queue_count; i++) {
|
||||
if (dev->queuelist[i]) {
|
||||
drm_free(dev->queuelist[i],
|
||||
sizeof(*dev->queuelist[0]),
|
||||
DRM_MEM_QUEUES);
|
||||
dev->queuelist[i] = NULL;
|
||||
}
|
||||
}
|
||||
drm_free(dev->queuelist,
|
||||
dev->queue_slots * sizeof(*dev->queuelist),
|
||||
DRM_MEM_QUEUES);
|
||||
dev->queuelist = NULL;
|
||||
}
|
||||
dev->queue_count = 0;
|
||||
|
||||
if (drm_core_check_feature(dev, DRIVER_HAVE_DMA))
|
||||
drm_dma_takedown(dev);
|
||||
|
||||
if (dev->lock.hw_lock) {
|
||||
dev->sigdata.lock = dev->lock.hw_lock = NULL; /* SHM removed */
|
||||
dev->lock.filp = NULL;
|
||||
wake_up_interruptible(&dev->lock.lock_queue);
|
||||
}
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
DRM_DEBUG("lastclose completed\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Module initialization. Called via init_module at module load time, or via
|
||||
* linux/init/main.c (this is not currently supported).
|
||||
*
|
||||
* \return zero on success or a negative number on failure.
|
||||
*
|
||||
* Initializes an array of drm_device structures, and attempts to
|
||||
* initialize all available devices, using consecutive minors, registering the
|
||||
* stubs and initializing the AGP device.
|
||||
*
|
||||
* Expands the \c DRIVER_PREINIT and \c DRIVER_POST_INIT macros before and
|
||||
* after the initialization for driver customization.
|
||||
*/
|
||||
int drm_init(struct drm_driver *driver)
|
||||
{
|
||||
struct pci_dev *pdev = NULL;
|
||||
struct pci_device_id *pid;
|
||||
int i;
|
||||
|
||||
DRM_DEBUG("\n");
|
||||
|
||||
drm_mem_init();
|
||||
|
||||
for (i = 0; driver->pci_driver.id_table[i].vendor != 0; i++) {
|
||||
pid = (struct pci_device_id *)&driver->pci_driver.id_table[i];
|
||||
|
||||
pdev = NULL;
|
||||
/* pass back in pdev to account for multiple identical cards */
|
||||
while ((pdev =
|
||||
pci_get_subsys(pid->vendor, pid->device, pid->subvendor,
|
||||
pid->subdevice, pdev)) != NULL) {
|
||||
/* stealth mode requires a manual probe */
|
||||
pci_dev_get(pdev);
|
||||
drm_get_dev(pdev, pid, driver);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(drm_init);
|
||||
|
||||
/**
|
||||
* Called via cleanup_module() at module unload time.
|
||||
*
|
||||
* Cleans up all DRM device, calling drm_lastclose().
|
||||
*
|
||||
* \sa drm_init
|
||||
*/
|
||||
static void drm_cleanup(drm_device_t * dev)
|
||||
{
|
||||
DRM_DEBUG("\n");
|
||||
|
||||
if (!dev) {
|
||||
DRM_ERROR("cleanup called no dev\n");
|
||||
return;
|
||||
}
|
||||
|
||||
drm_lastclose(dev);
|
||||
|
||||
if (dev->maplist) {
|
||||
drm_free(dev->maplist, sizeof(*dev->maplist), DRM_MEM_MAPS);
|
||||
dev->maplist = NULL;
|
||||
drm_ht_remove(&dev->map_hash);
|
||||
}
|
||||
|
||||
drm_ctxbitmap_cleanup(dev);
|
||||
|
||||
if (drm_core_has_MTRR(dev) && drm_core_has_AGP(dev) &&
|
||||
dev->agp && dev->agp->agp_mtrr >= 0) {
|
||||
int retval;
|
||||
retval = mtrr_del(dev->agp->agp_mtrr,
|
||||
dev->agp->agp_info.aper_base,
|
||||
dev->agp->agp_info.aper_size * 1024 * 1024);
|
||||
DRM_DEBUG("mtrr_del=%d\n", retval);
|
||||
}
|
||||
|
||||
if (drm_core_has_AGP(dev) && dev->agp) {
|
||||
drm_free(dev->agp, sizeof(*dev->agp), DRM_MEM_AGPLISTS);
|
||||
dev->agp = NULL;
|
||||
}
|
||||
|
||||
if (dev->driver->unload)
|
||||
dev->driver->unload(dev);
|
||||
|
||||
drm_put_head(&dev->primary);
|
||||
if (drm_put_dev(dev))
|
||||
DRM_ERROR("Cannot unload module\n");
|
||||
}
|
||||
|
||||
void drm_exit(struct drm_driver *driver)
|
||||
{
|
||||
int i;
|
||||
drm_device_t *dev = NULL;
|
||||
drm_head_t *head;
|
||||
|
||||
DRM_DEBUG("\n");
|
||||
|
||||
for (i = 0; i < drm_cards_limit; i++) {
|
||||
head = drm_heads[i];
|
||||
if (!head)
|
||||
continue;
|
||||
if (!head->dev)
|
||||
continue;
|
||||
if (head->dev->driver != driver)
|
||||
continue;
|
||||
dev = head->dev;
|
||||
if (dev) {
|
||||
/* release the pci driver */
|
||||
if (dev->pdev)
|
||||
pci_dev_put(dev->pdev);
|
||||
drm_cleanup(dev);
|
||||
}
|
||||
}
|
||||
DRM_INFO("Module unloaded\n");
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(drm_exit);
|
||||
|
||||
/** File operations structure */
|
||||
static const struct file_operations drm_stub_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = drm_stub_open
|
||||
};
|
||||
|
||||
static int __init drm_core_init(void)
|
||||
{
|
||||
int ret = -ENOMEM;
|
||||
|
||||
drm_cards_limit =
|
||||
(drm_cards_limit <
|
||||
DRM_MAX_MINOR + 1 ? drm_cards_limit : DRM_MAX_MINOR + 1);
|
||||
drm_heads =
|
||||
drm_calloc(drm_cards_limit, sizeof(*drm_heads), DRM_MEM_STUB);
|
||||
if (!drm_heads)
|
||||
goto err_p1;
|
||||
|
||||
if (register_chrdev(DRM_MAJOR, "drm", &drm_stub_fops))
|
||||
goto err_p1;
|
||||
|
||||
drm_class = drm_sysfs_create(THIS_MODULE, "drm");
|
||||
if (IS_ERR(drm_class)) {
|
||||
printk(KERN_ERR "DRM: Error creating drm class.\n");
|
||||
ret = PTR_ERR(drm_class);
|
||||
goto err_p2;
|
||||
}
|
||||
|
||||
drm_proc_root = proc_mkdir("dri", NULL);
|
||||
if (!drm_proc_root) {
|
||||
DRM_ERROR("Cannot create /proc/dri\n");
|
||||
ret = -1;
|
||||
goto err_p3;
|
||||
}
|
||||
|
||||
DRM_INFO("Initialized %s %d.%d.%d %s\n",
|
||||
CORE_NAME, CORE_MAJOR, CORE_MINOR, CORE_PATCHLEVEL, CORE_DATE);
|
||||
return 0;
|
||||
err_p3:
|
||||
drm_sysfs_destroy(drm_class);
|
||||
err_p2:
|
||||
unregister_chrdev(DRM_MAJOR, "drm");
|
||||
drm_free(drm_heads, sizeof(*drm_heads) * drm_cards_limit, DRM_MEM_STUB);
|
||||
err_p1:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit drm_core_exit(void)
|
||||
{
|
||||
remove_proc_entry("dri", NULL);
|
||||
drm_sysfs_destroy(drm_class);
|
||||
|
||||
unregister_chrdev(DRM_MAJOR, "drm");
|
||||
|
||||
drm_free(drm_heads, sizeof(*drm_heads) * drm_cards_limit, DRM_MEM_STUB);
|
||||
}
|
||||
|
||||
module_init(drm_core_init);
|
||||
module_exit(drm_core_exit);
|
||||
|
||||
/**
|
||||
* Get version information
|
||||
*
|
||||
* \param inode device inode.
|
||||
* \param filp file pointer.
|
||||
* \param cmd command.
|
||||
* \param arg user argument, pointing to a drm_version structure.
|
||||
* \return zero on success or negative number on failure.
|
||||
*
|
||||
* Fills in the version information in \p arg.
|
||||
*/
|
||||
static int drm_version(struct inode *inode, struct file *filp,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
drm_file_t *priv = filp->private_data;
|
||||
drm_device_t *dev = priv->head->dev;
|
||||
drm_version_t __user *argp = (void __user *)arg;
|
||||
drm_version_t version;
|
||||
int len;
|
||||
|
||||
if (copy_from_user(&version, argp, sizeof(version)))
|
||||
return -EFAULT;
|
||||
|
||||
version.version_major = dev->driver->major;
|
||||
version.version_minor = dev->driver->minor;
|
||||
version.version_patchlevel = dev->driver->patchlevel;
|
||||
DRM_COPY(version.name, dev->driver->name);
|
||||
DRM_COPY(version.date, dev->driver->date);
|
||||
DRM_COPY(version.desc, dev->driver->desc);
|
||||
|
||||
if (copy_to_user(argp, &version, sizeof(version)))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called whenever a process performs an ioctl on /dev/drm.
|
||||
*
|
||||
* \param inode device inode.
|
||||
* \param filp file pointer.
|
||||
* \param cmd command.
|
||||
* \param arg user argument.
|
||||
* \return zero on success or negative number on failure.
|
||||
*
|
||||
* Looks up the ioctl function in the ::ioctls table, checking for root
|
||||
* previleges if so required, and dispatches to the respective function.
|
||||
*/
|
||||
int drm_ioctl(struct inode *inode, struct file *filp,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
drm_file_t *priv = filp->private_data;
|
||||
drm_device_t *dev = priv->head->dev;
|
||||
drm_ioctl_desc_t *ioctl;
|
||||
drm_ioctl_t *func;
|
||||
unsigned int nr = DRM_IOCTL_NR(cmd);
|
||||
int retcode = -EINVAL;
|
||||
|
||||
atomic_inc(&dev->ioctl_count);
|
||||
atomic_inc(&dev->counts[_DRM_STAT_IOCTLS]);
|
||||
++priv->ioctl_count;
|
||||
|
||||
DRM_DEBUG("pid=%d, cmd=0x%02x, nr=0x%02x, dev 0x%lx, auth=%d\n",
|
||||
current->pid, cmd, nr,
|
||||
(long)old_encode_dev(priv->head->device),
|
||||
priv->authenticated);
|
||||
|
||||
if (nr < DRIVER_IOCTL_COUNT)
|
||||
ioctl = &drm_ioctls[nr];
|
||||
else if ((nr >= DRM_COMMAND_BASE)
|
||||
&& (nr < DRM_COMMAND_BASE + dev->driver->num_ioctls))
|
||||
ioctl = &dev->driver->ioctls[nr - DRM_COMMAND_BASE];
|
||||
else
|
||||
goto err_i1;
|
||||
|
||||
func = ioctl->func;
|
||||
/* is there a local override? */
|
||||
if ((nr == DRM_IOCTL_NR(DRM_IOCTL_DMA)) && dev->driver->dma_ioctl)
|
||||
func = dev->driver->dma_ioctl;
|
||||
|
||||
if (!func) {
|
||||
DRM_DEBUG("no function\n");
|
||||
retcode = -EINVAL;
|
||||
} else if (((ioctl->flags & DRM_ROOT_ONLY) && !capable(CAP_SYS_ADMIN)) ||
|
||||
((ioctl->flags & DRM_AUTH) && !priv->authenticated) ||
|
||||
((ioctl->flags & DRM_MASTER) && !priv->master)) {
|
||||
retcode = -EACCES;
|
||||
} else {
|
||||
retcode = func(inode, filp, cmd, arg);
|
||||
}
|
||||
|
||||
err_i1:
|
||||
atomic_dec(&dev->ioctl_count);
|
||||
if (retcode)
|
||||
DRM_DEBUG("ret = %x\n", retcode);
|
||||
return retcode;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(drm_ioctl);
|
||||
492
drivers/char/drm/drm_fops.c
Normal file
492
drivers/char/drm/drm_fops.c
Normal file
@@ -0,0 +1,492 @@
|
||||
/**
|
||||
* \file drm_fops.c
|
||||
* File operations for DRM
|
||||
*
|
||||
* \author Rickard E. (Rik) Faith <faith@valinux.com>
|
||||
* \author Daryll Strauss <daryll@valinux.com>
|
||||
* \author Gareth Hughes <gareth@valinux.com>
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "drmP.h"
|
||||
#include "drm_sarea.h"
|
||||
#include <linux/poll.h>
|
||||
|
||||
static int drm_open_helper(struct inode *inode, struct file *filp,
|
||||
drm_device_t * dev);
|
||||
|
||||
static int drm_setup(drm_device_t * dev)
|
||||
{
|
||||
drm_local_map_t *map;
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
if (dev->driver->firstopen) {
|
||||
ret = dev->driver->firstopen(dev);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
dev->magicfree.next = NULL;
|
||||
|
||||
/* prebuild the SAREA */
|
||||
i = drm_addmap(dev, 0, SAREA_MAX, _DRM_SHM, _DRM_CONTAINS_LOCK, &map);
|
||||
if (i != 0)
|
||||
return i;
|
||||
|
||||
atomic_set(&dev->ioctl_count, 0);
|
||||
atomic_set(&dev->vma_count, 0);
|
||||
dev->buf_use = 0;
|
||||
atomic_set(&dev->buf_alloc, 0);
|
||||
|
||||
if (drm_core_check_feature(dev, DRIVER_HAVE_DMA)) {
|
||||
i = drm_dma_setup(dev);
|
||||
if (i < 0)
|
||||
return i;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(dev->counts); i++)
|
||||
atomic_set(&dev->counts[i], 0);
|
||||
|
||||
drm_ht_create(&dev->magiclist, DRM_MAGIC_HASH_ORDER);
|
||||
INIT_LIST_HEAD(&dev->magicfree);
|
||||
|
||||
dev->ctxlist = drm_alloc(sizeof(*dev->ctxlist), DRM_MEM_CTXLIST);
|
||||
if (dev->ctxlist == NULL)
|
||||
return -ENOMEM;
|
||||
memset(dev->ctxlist, 0, sizeof(*dev->ctxlist));
|
||||
INIT_LIST_HEAD(&dev->ctxlist->head);
|
||||
|
||||
dev->vmalist = NULL;
|
||||
dev->sigdata.lock = dev->lock.hw_lock = NULL;
|
||||
init_waitqueue_head(&dev->lock.lock_queue);
|
||||
dev->queue_count = 0;
|
||||
dev->queue_reserved = 0;
|
||||
dev->queue_slots = 0;
|
||||
dev->queuelist = NULL;
|
||||
dev->irq_enabled = 0;
|
||||
dev->context_flag = 0;
|
||||
dev->interrupt_flag = 0;
|
||||
dev->dma_flag = 0;
|
||||
dev->last_context = 0;
|
||||
dev->last_switch = 0;
|
||||
dev->last_checked = 0;
|
||||
init_waitqueue_head(&dev->context_wait);
|
||||
dev->if_version = 0;
|
||||
|
||||
dev->ctx_start = 0;
|
||||
dev->lck_start = 0;
|
||||
|
||||
dev->buf_async = NULL;
|
||||
init_waitqueue_head(&dev->buf_readers);
|
||||
init_waitqueue_head(&dev->buf_writers);
|
||||
|
||||
DRM_DEBUG("\n");
|
||||
|
||||
/*
|
||||
* The kernel's context could be created here, but is now created
|
||||
* in drm_dma_enqueue. This is more resource-efficient for
|
||||
* hardware that does not do DMA, but may mean that
|
||||
* drm_select_queue fails between the time the interrupt is
|
||||
* initialized and the time the queues are initialized.
|
||||
*/
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Open file.
|
||||
*
|
||||
* \param inode device inode
|
||||
* \param filp file pointer.
|
||||
* \return zero on success or a negative number on failure.
|
||||
*
|
||||
* Searches the DRM device with the same minor number, calls open_helper(), and
|
||||
* increments the device open count. If the open count was previous at zero,
|
||||
* i.e., it's the first that the device is open, then calls setup().
|
||||
*/
|
||||
int drm_open(struct inode *inode, struct file *filp)
|
||||
{
|
||||
drm_device_t *dev = NULL;
|
||||
int minor = iminor(inode);
|
||||
int retcode = 0;
|
||||
|
||||
if (!((minor >= 0) && (minor < drm_cards_limit)))
|
||||
return -ENODEV;
|
||||
|
||||
if (!drm_heads[minor])
|
||||
return -ENODEV;
|
||||
|
||||
if (!(dev = drm_heads[minor]->dev))
|
||||
return -ENODEV;
|
||||
|
||||
retcode = drm_open_helper(inode, filp, dev);
|
||||
if (!retcode) {
|
||||
atomic_inc(&dev->counts[_DRM_STAT_OPENS]);
|
||||
spin_lock(&dev->count_lock);
|
||||
if (!dev->open_count++) {
|
||||
spin_unlock(&dev->count_lock);
|
||||
return drm_setup(dev);
|
||||
}
|
||||
spin_unlock(&dev->count_lock);
|
||||
}
|
||||
|
||||
return retcode;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_open);
|
||||
|
||||
/**
|
||||
* File \c open operation.
|
||||
*
|
||||
* \param inode device inode.
|
||||
* \param filp file pointer.
|
||||
*
|
||||
* Puts the dev->fops corresponding to the device minor number into
|
||||
* \p filp, call the \c open method, and restore the file operations.
|
||||
*/
|
||||
int drm_stub_open(struct inode *inode, struct file *filp)
|
||||
{
|
||||
drm_device_t *dev = NULL;
|
||||
int minor = iminor(inode);
|
||||
int err = -ENODEV;
|
||||
const struct file_operations *old_fops;
|
||||
|
||||
DRM_DEBUG("\n");
|
||||
|
||||
if (!((minor >= 0) && (minor < drm_cards_limit)))
|
||||
return -ENODEV;
|
||||
|
||||
if (!drm_heads[minor])
|
||||
return -ENODEV;
|
||||
|
||||
if (!(dev = drm_heads[minor]->dev))
|
||||
return -ENODEV;
|
||||
|
||||
old_fops = filp->f_op;
|
||||
filp->f_op = fops_get(&dev->driver->fops);
|
||||
if (filp->f_op->open && (err = filp->f_op->open(inode, filp))) {
|
||||
fops_put(filp->f_op);
|
||||
filp->f_op = fops_get(old_fops);
|
||||
}
|
||||
fops_put(old_fops);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether DRI will run on this CPU.
|
||||
*
|
||||
* \return non-zero if the DRI will run on this CPU, or zero otherwise.
|
||||
*/
|
||||
static int drm_cpu_valid(void)
|
||||
{
|
||||
#if defined(__i386__)
|
||||
if (boot_cpu_data.x86 == 3)
|
||||
return 0; /* No cmpxchg on a 386 */
|
||||
#endif
|
||||
#if defined(__sparc__) && !defined(__sparc_v9__)
|
||||
return 0; /* No cmpxchg before v9 sparc. */
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called whenever a process opens /dev/drm.
|
||||
*
|
||||
* \param inode device inode.
|
||||
* \param filp file pointer.
|
||||
* \param dev device.
|
||||
* \return zero on success or a negative number on failure.
|
||||
*
|
||||
* Creates and initializes a drm_file structure for the file private data in \p
|
||||
* filp and add it into the double linked list in \p dev.
|
||||
*/
|
||||
static int drm_open_helper(struct inode *inode, struct file *filp,
|
||||
drm_device_t * dev)
|
||||
{
|
||||
int minor = iminor(inode);
|
||||
drm_file_t *priv;
|
||||
int ret;
|
||||
|
||||
if (filp->f_flags & O_EXCL)
|
||||
return -EBUSY; /* No exclusive opens */
|
||||
if (!drm_cpu_valid())
|
||||
return -EINVAL;
|
||||
|
||||
DRM_DEBUG("pid = %d, minor = %d\n", current->pid, minor);
|
||||
|
||||
priv = drm_alloc(sizeof(*priv), DRM_MEM_FILES);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
memset(priv, 0, sizeof(*priv));
|
||||
filp->private_data = priv;
|
||||
priv->uid = current->euid;
|
||||
priv->pid = current->pid;
|
||||
priv->minor = minor;
|
||||
priv->head = drm_heads[minor];
|
||||
priv->ioctl_count = 0;
|
||||
/* for compatibility root is always authenticated */
|
||||
priv->authenticated = capable(CAP_SYS_ADMIN);
|
||||
priv->lock_count = 0;
|
||||
|
||||
if (dev->driver->open) {
|
||||
ret = dev->driver->open(dev, priv);
|
||||
if (ret < 0)
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
if (!dev->file_last) {
|
||||
priv->next = NULL;
|
||||
priv->prev = NULL;
|
||||
dev->file_first = priv;
|
||||
dev->file_last = priv;
|
||||
/* first opener automatically becomes master */
|
||||
priv->master = 1;
|
||||
} else {
|
||||
priv->next = NULL;
|
||||
priv->prev = dev->file_last;
|
||||
dev->file_last->next = priv;
|
||||
dev->file_last = priv;
|
||||
}
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
#ifdef __alpha__
|
||||
/*
|
||||
* Default the hose
|
||||
*/
|
||||
if (!dev->hose) {
|
||||
struct pci_dev *pci_dev;
|
||||
pci_dev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, NULL);
|
||||
if (pci_dev) {
|
||||
dev->hose = pci_dev->sysdata;
|
||||
pci_dev_put(pci_dev);
|
||||
}
|
||||
if (!dev->hose) {
|
||||
struct pci_bus *b = pci_bus_b(pci_root_buses.next);
|
||||
if (b)
|
||||
dev->hose = b->sysdata;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
out_free:
|
||||
drm_free(priv, sizeof(*priv), DRM_MEM_FILES);
|
||||
filp->private_data = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** No-op. */
|
||||
int drm_fasync(int fd, struct file *filp, int on)
|
||||
{
|
||||
drm_file_t *priv = filp->private_data;
|
||||
drm_device_t *dev = priv->head->dev;
|
||||
int retcode;
|
||||
|
||||
DRM_DEBUG("fd = %d, device = 0x%lx\n", fd,
|
||||
(long)old_encode_dev(priv->head->device));
|
||||
retcode = fasync_helper(fd, filp, on, &dev->buf_async);
|
||||
if (retcode < 0)
|
||||
return retcode;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_fasync);
|
||||
|
||||
/**
|
||||
* Release file.
|
||||
*
|
||||
* \param inode device inode
|
||||
* \param filp file pointer.
|
||||
* \return zero on success or a negative number on failure.
|
||||
*
|
||||
* If the hardware lock is held then free it, and take it again for the kernel
|
||||
* context since it's necessary to reclaim buffers. Unlink the file private
|
||||
* data from its list and free it. Decreases the open count and if it reaches
|
||||
* zero calls drm_lastclose().
|
||||
*/
|
||||
int drm_release(struct inode *inode, struct file *filp)
|
||||
{
|
||||
drm_file_t *priv = filp->private_data;
|
||||
drm_device_t *dev;
|
||||
int retcode = 0;
|
||||
|
||||
lock_kernel();
|
||||
dev = priv->head->dev;
|
||||
|
||||
DRM_DEBUG("open_count = %d\n", dev->open_count);
|
||||
|
||||
if (dev->driver->preclose)
|
||||
dev->driver->preclose(dev, filp);
|
||||
|
||||
/* ========================================================
|
||||
* Begin inline drm_release
|
||||
*/
|
||||
|
||||
DRM_DEBUG("pid = %d, device = 0x%lx, open_count = %d\n",
|
||||
current->pid, (long)old_encode_dev(priv->head->device),
|
||||
dev->open_count);
|
||||
|
||||
if (priv->lock_count && dev->lock.hw_lock &&
|
||||
_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) &&
|
||||
dev->lock.filp == filp) {
|
||||
DRM_DEBUG("File %p released, freeing lock for context %d\n",
|
||||
filp, _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
|
||||
|
||||
if (dev->driver->reclaim_buffers_locked)
|
||||
dev->driver->reclaim_buffers_locked(dev, filp);
|
||||
|
||||
drm_lock_free(dev, &dev->lock.hw_lock->lock,
|
||||
_DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
|
||||
|
||||
/* FIXME: may require heavy-handed reset of
|
||||
hardware at this point, possibly
|
||||
processed via a callback to the X
|
||||
server. */
|
||||
} else if (dev->driver->reclaim_buffers_locked && priv->lock_count
|
||||
&& dev->lock.hw_lock) {
|
||||
/* The lock is required to reclaim buffers */
|
||||
DECLARE_WAITQUEUE(entry, current);
|
||||
|
||||
add_wait_queue(&dev->lock.lock_queue, &entry);
|
||||
for (;;) {
|
||||
__set_current_state(TASK_INTERRUPTIBLE);
|
||||
if (!dev->lock.hw_lock) {
|
||||
/* Device has been unregistered */
|
||||
retcode = -EINTR;
|
||||
break;
|
||||
}
|
||||
if (drm_lock_take(&dev->lock.hw_lock->lock,
|
||||
DRM_KERNEL_CONTEXT)) {
|
||||
dev->lock.filp = filp;
|
||||
dev->lock.lock_time = jiffies;
|
||||
atomic_inc(&dev->counts[_DRM_STAT_LOCKS]);
|
||||
break; /* Got lock */
|
||||
}
|
||||
/* Contention */
|
||||
schedule();
|
||||
if (signal_pending(current)) {
|
||||
retcode = -ERESTARTSYS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
__set_current_state(TASK_RUNNING);
|
||||
remove_wait_queue(&dev->lock.lock_queue, &entry);
|
||||
if (!retcode) {
|
||||
dev->driver->reclaim_buffers_locked(dev, filp);
|
||||
drm_lock_free(dev, &dev->lock.hw_lock->lock,
|
||||
DRM_KERNEL_CONTEXT);
|
||||
}
|
||||
}
|
||||
|
||||
if (drm_core_check_feature(dev, DRIVER_HAVE_DMA) &&
|
||||
!dev->driver->reclaim_buffers_locked) {
|
||||
dev->driver->reclaim_buffers(dev, filp);
|
||||
}
|
||||
|
||||
drm_fasync(-1, filp, 0);
|
||||
|
||||
mutex_lock(&dev->ctxlist_mutex);
|
||||
if (dev->ctxlist && (!list_empty(&dev->ctxlist->head))) {
|
||||
drm_ctx_list_t *pos, *n;
|
||||
|
||||
list_for_each_entry_safe(pos, n, &dev->ctxlist->head, head) {
|
||||
if (pos->tag == priv &&
|
||||
pos->handle != DRM_KERNEL_CONTEXT) {
|
||||
if (dev->driver->context_dtor)
|
||||
dev->driver->context_dtor(dev,
|
||||
pos->handle);
|
||||
|
||||
drm_ctxbitmap_free(dev, pos->handle);
|
||||
|
||||
list_del(&pos->head);
|
||||
drm_free(pos, sizeof(*pos), DRM_MEM_CTXLIST);
|
||||
--dev->ctx_count;
|
||||
}
|
||||
}
|
||||
}
|
||||
mutex_unlock(&dev->ctxlist_mutex);
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
if (priv->remove_auth_on_close == 1) {
|
||||
drm_file_t *temp = dev->file_first;
|
||||
while (temp) {
|
||||
temp->authenticated = 0;
|
||||
temp = temp->next;
|
||||
}
|
||||
}
|
||||
if (priv->prev) {
|
||||
priv->prev->next = priv->next;
|
||||
} else {
|
||||
dev->file_first = priv->next;
|
||||
}
|
||||
if (priv->next) {
|
||||
priv->next->prev = priv->prev;
|
||||
} else {
|
||||
dev->file_last = priv->prev;
|
||||
}
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
if (dev->driver->postclose)
|
||||
dev->driver->postclose(dev, priv);
|
||||
drm_free(priv, sizeof(*priv), DRM_MEM_FILES);
|
||||
|
||||
/* ========================================================
|
||||
* End inline drm_release
|
||||
*/
|
||||
|
||||
atomic_inc(&dev->counts[_DRM_STAT_CLOSES]);
|
||||
spin_lock(&dev->count_lock);
|
||||
if (!--dev->open_count) {
|
||||
if (atomic_read(&dev->ioctl_count) || dev->blocked) {
|
||||
DRM_ERROR("Device busy: %d %d\n",
|
||||
atomic_read(&dev->ioctl_count), dev->blocked);
|
||||
spin_unlock(&dev->count_lock);
|
||||
unlock_kernel();
|
||||
return -EBUSY;
|
||||
}
|
||||
spin_unlock(&dev->count_lock);
|
||||
unlock_kernel();
|
||||
return drm_lastclose(dev);
|
||||
}
|
||||
spin_unlock(&dev->count_lock);
|
||||
|
||||
unlock_kernel();
|
||||
|
||||
return retcode;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_release);
|
||||
|
||||
/** No-op. */
|
||||
unsigned int drm_poll(struct file *filp, struct poll_table_struct *wait)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_poll);
|
||||
190
drivers/char/drm/drm_hashtab.c
Normal file
190
drivers/char/drm/drm_hashtab.c
Normal file
@@ -0,0 +1,190 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND. USA.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sub license, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the
|
||||
* next paragraph) shall be included in all copies or substantial portions
|
||||
* of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
* USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*
|
||||
**************************************************************************/
|
||||
/*
|
||||
* Simple open hash tab implementation.
|
||||
*
|
||||
* Authors:
|
||||
* Thomas Hellström <thomas-at-tungstengraphics-dot-com>
|
||||
*/
|
||||
|
||||
#include "drmP.h"
|
||||
#include "drm_hashtab.h"
|
||||
#include <linux/hash.h>
|
||||
|
||||
int drm_ht_create(drm_open_hash_t *ht, unsigned int order)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
ht->size = 1 << order;
|
||||
ht->order = order;
|
||||
ht->fill = 0;
|
||||
ht->table = vmalloc(ht->size*sizeof(*ht->table));
|
||||
if (!ht->table) {
|
||||
DRM_ERROR("Out of memory for hash table\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
for (i=0; i< ht->size; ++i) {
|
||||
INIT_HLIST_HEAD(&ht->table[i]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void drm_ht_verbose_list(drm_open_hash_t *ht, unsigned long key)
|
||||
{
|
||||
drm_hash_item_t *entry;
|
||||
struct hlist_head *h_list;
|
||||
struct hlist_node *list;
|
||||
unsigned int hashed_key;
|
||||
int count = 0;
|
||||
|
||||
hashed_key = hash_long(key, ht->order);
|
||||
DRM_DEBUG("Key is 0x%08lx, Hashed key is 0x%08x\n", key, hashed_key);
|
||||
h_list = &ht->table[hashed_key];
|
||||
hlist_for_each(list, h_list) {
|
||||
entry = hlist_entry(list, drm_hash_item_t, head);
|
||||
DRM_DEBUG("count %d, key: 0x%08lx\n", count++, entry->key);
|
||||
}
|
||||
}
|
||||
|
||||
static struct hlist_node *drm_ht_find_key(drm_open_hash_t *ht,
|
||||
unsigned long key)
|
||||
{
|
||||
drm_hash_item_t *entry;
|
||||
struct hlist_head *h_list;
|
||||
struct hlist_node *list;
|
||||
unsigned int hashed_key;
|
||||
|
||||
hashed_key = hash_long(key, ht->order);
|
||||
h_list = &ht->table[hashed_key];
|
||||
hlist_for_each(list, h_list) {
|
||||
entry = hlist_entry(list, drm_hash_item_t, head);
|
||||
if (entry->key == key)
|
||||
return list;
|
||||
if (entry->key > key)
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
int drm_ht_insert_item(drm_open_hash_t *ht, drm_hash_item_t *item)
|
||||
{
|
||||
drm_hash_item_t *entry;
|
||||
struct hlist_head *h_list;
|
||||
struct hlist_node *list, *parent;
|
||||
unsigned int hashed_key;
|
||||
unsigned long key = item->key;
|
||||
|
||||
hashed_key = hash_long(key, ht->order);
|
||||
h_list = &ht->table[hashed_key];
|
||||
parent = NULL;
|
||||
hlist_for_each(list, h_list) {
|
||||
entry = hlist_entry(list, drm_hash_item_t, head);
|
||||
if (entry->key == key)
|
||||
return -EINVAL;
|
||||
if (entry->key > key)
|
||||
break;
|
||||
parent = list;
|
||||
}
|
||||
if (parent) {
|
||||
hlist_add_after(parent, &item->head);
|
||||
} else {
|
||||
hlist_add_head(&item->head, h_list);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Just insert an item and return any "bits" bit key that hasn't been
|
||||
* used before.
|
||||
*/
|
||||
int drm_ht_just_insert_please(drm_open_hash_t *ht, drm_hash_item_t *item,
|
||||
unsigned long seed, int bits, int shift,
|
||||
unsigned long add)
|
||||
{
|
||||
int ret;
|
||||
unsigned long mask = (1 << bits) - 1;
|
||||
unsigned long first, unshifted_key;
|
||||
|
||||
unshifted_key = hash_long(seed, bits);
|
||||
first = unshifted_key;
|
||||
do {
|
||||
item->key = (unshifted_key << shift) + add;
|
||||
ret = drm_ht_insert_item(ht, item);
|
||||
if (ret)
|
||||
unshifted_key = (unshifted_key + 1) & mask;
|
||||
} while(ret && (unshifted_key != first));
|
||||
|
||||
if (ret) {
|
||||
DRM_ERROR("Available key bit space exhausted\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int drm_ht_find_item(drm_open_hash_t *ht, unsigned long key,
|
||||
drm_hash_item_t **item)
|
||||
{
|
||||
struct hlist_node *list;
|
||||
|
||||
list = drm_ht_find_key(ht, key);
|
||||
if (!list)
|
||||
return -EINVAL;
|
||||
|
||||
*item = hlist_entry(list, drm_hash_item_t, head);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int drm_ht_remove_key(drm_open_hash_t *ht, unsigned long key)
|
||||
{
|
||||
struct hlist_node *list;
|
||||
|
||||
list = drm_ht_find_key(ht, key);
|
||||
if (list) {
|
||||
hlist_del_init(list);
|
||||
ht->fill--;
|
||||
return 0;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int drm_ht_remove_item(drm_open_hash_t *ht, drm_hash_item_t *item)
|
||||
{
|
||||
hlist_del_init(&item->head);
|
||||
ht->fill--;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void drm_ht_remove(drm_open_hash_t *ht)
|
||||
{
|
||||
if (ht->table) {
|
||||
vfree(ht->table);
|
||||
ht->table = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
67
drivers/char/drm/drm_hashtab.h
Normal file
67
drivers/char/drm/drm_hashtab.h
Normal file
@@ -0,0 +1,67 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright 2006 Tungsten Graphics, Inc., Bismack, ND. USA.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sub license, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the
|
||||
* next paragraph) shall be included in all copies or substantial portions
|
||||
* of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
* USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*
|
||||
**************************************************************************/
|
||||
/*
|
||||
* Simple open hash tab implementation.
|
||||
*
|
||||
* Authors:
|
||||
* Thomas Hellström <thomas-at-tungstengraphics-dot-com>
|
||||
*/
|
||||
|
||||
#ifndef DRM_HASHTAB_H
|
||||
#define DRM_HASHTAB_H
|
||||
|
||||
#define drm_hash_entry(_ptr, _type, _member) container_of(_ptr, _type, _member)
|
||||
|
||||
typedef struct drm_hash_item{
|
||||
struct hlist_node head;
|
||||
unsigned long key;
|
||||
} drm_hash_item_t;
|
||||
|
||||
typedef struct drm_open_hash{
|
||||
unsigned int size;
|
||||
unsigned int order;
|
||||
unsigned int fill;
|
||||
struct hlist_head *table;
|
||||
} drm_open_hash_t;
|
||||
|
||||
|
||||
extern int drm_ht_create(drm_open_hash_t *ht, unsigned int order);
|
||||
extern int drm_ht_insert_item(drm_open_hash_t *ht, drm_hash_item_t *item);
|
||||
extern int drm_ht_just_insert_please(drm_open_hash_t *ht, drm_hash_item_t *item,
|
||||
unsigned long seed, int bits, int shift,
|
||||
unsigned long add);
|
||||
extern int drm_ht_find_item(drm_open_hash_t *ht, unsigned long key, drm_hash_item_t **item);
|
||||
|
||||
extern void drm_ht_verbose_list(drm_open_hash_t *ht, unsigned long key);
|
||||
extern int drm_ht_remove_key(drm_open_hash_t *ht, unsigned long key);
|
||||
extern int drm_ht_remove_item(drm_open_hash_t *ht, drm_hash_item_t *item);
|
||||
extern void drm_ht_remove(drm_open_hash_t *ht);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
1069
drivers/char/drm/drm_ioc32.c
Normal file
1069
drivers/char/drm/drm_ioc32.c
Normal file
File diff suppressed because it is too large
Load Diff
383
drivers/char/drm/drm_ioctl.c
Normal file
383
drivers/char/drm/drm_ioctl.c
Normal file
@@ -0,0 +1,383 @@
|
||||
/**
|
||||
* \file drm_ioctl.c
|
||||
* IOCTL processing for DRM
|
||||
*
|
||||
* \author Rickard E. (Rik) Faith <faith@valinux.com>
|
||||
* \author Gareth Hughes <gareth@valinux.com>
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "drmP.h"
|
||||
#include "drm_core.h"
|
||||
|
||||
#include "linux/pci.h"
|
||||
|
||||
/**
|
||||
* Get the bus id.
|
||||
*
|
||||
* \param inode device inode.
|
||||
* \param filp file pointer.
|
||||
* \param cmd command.
|
||||
* \param arg user argument, pointing to a drm_unique structure.
|
||||
* \return zero on success or a negative number on failure.
|
||||
*
|
||||
* Copies the bus id from drm_device::unique into user space.
|
||||
*/
|
||||
int drm_getunique(struct inode *inode, struct file *filp,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
drm_file_t *priv = filp->private_data;
|
||||
drm_device_t *dev = priv->head->dev;
|
||||
drm_unique_t __user *argp = (void __user *)arg;
|
||||
drm_unique_t u;
|
||||
|
||||
if (copy_from_user(&u, argp, sizeof(u)))
|
||||
return -EFAULT;
|
||||
if (u.unique_len >= dev->unique_len) {
|
||||
if (copy_to_user(u.unique, dev->unique, dev->unique_len))
|
||||
return -EFAULT;
|
||||
}
|
||||
u.unique_len = dev->unique_len;
|
||||
if (copy_to_user(argp, &u, sizeof(u)))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the bus id.
|
||||
*
|
||||
* \param inode device inode.
|
||||
* \param filp file pointer.
|
||||
* \param cmd command.
|
||||
* \param arg user argument, pointing to a drm_unique structure.
|
||||
* \return zero on success or a negative number on failure.
|
||||
*
|
||||
* Copies the bus id from userspace into drm_device::unique, and verifies that
|
||||
* it matches the device this DRM is attached to (EINVAL otherwise). Deprecated
|
||||
* in interface version 1.1 and will return EBUSY when setversion has requested
|
||||
* version 1.1 or greater.
|
||||
*/
|
||||
int drm_setunique(struct inode *inode, struct file *filp,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
drm_file_t *priv = filp->private_data;
|
||||
drm_device_t *dev = priv->head->dev;
|
||||
drm_unique_t u;
|
||||
int domain, bus, slot, func, ret;
|
||||
|
||||
if (dev->unique_len || dev->unique)
|
||||
return -EBUSY;
|
||||
|
||||
if (copy_from_user(&u, (drm_unique_t __user *) arg, sizeof(u)))
|
||||
return -EFAULT;
|
||||
|
||||
if (!u.unique_len || u.unique_len > 1024)
|
||||
return -EINVAL;
|
||||
|
||||
dev->unique_len = u.unique_len;
|
||||
dev->unique = drm_alloc(u.unique_len + 1, DRM_MEM_DRIVER);
|
||||
if (!dev->unique)
|
||||
return -ENOMEM;
|
||||
if (copy_from_user(dev->unique, u.unique, dev->unique_len))
|
||||
return -EFAULT;
|
||||
|
||||
dev->unique[dev->unique_len] = '\0';
|
||||
|
||||
dev->devname =
|
||||
drm_alloc(strlen(dev->driver->pci_driver.name) +
|
||||
strlen(dev->unique) + 2, DRM_MEM_DRIVER);
|
||||
if (!dev->devname)
|
||||
return -ENOMEM;
|
||||
|
||||
sprintf(dev->devname, "%s@%s", dev->driver->pci_driver.name,
|
||||
dev->unique);
|
||||
|
||||
/* Return error if the busid submitted doesn't match the device's actual
|
||||
* busid.
|
||||
*/
|
||||
ret = sscanf(dev->unique, "PCI:%d:%d:%d", &bus, &slot, &func);
|
||||
if (ret != 3)
|
||||
return DRM_ERR(EINVAL);
|
||||
domain = bus >> 8;
|
||||
bus &= 0xff;
|
||||
|
||||
if ((domain != drm_get_pci_domain(dev)) ||
|
||||
(bus != dev->pdev->bus->number) ||
|
||||
(slot != PCI_SLOT(dev->pdev->devfn)) ||
|
||||
(func != PCI_FUNC(dev->pdev->devfn)))
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int drm_set_busid(drm_device_t * dev)
|
||||
{
|
||||
int len;
|
||||
|
||||
if (dev->unique != NULL)
|
||||
return 0;
|
||||
|
||||
dev->unique_len = 40;
|
||||
dev->unique = drm_alloc(dev->unique_len + 1, DRM_MEM_DRIVER);
|
||||
if (dev->unique == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
len = snprintf(dev->unique, dev->unique_len, "pci:%04x:%02x:%02x.%d",
|
||||
drm_get_pci_domain(dev), dev->pdev->bus->number,
|
||||
PCI_SLOT(dev->pdev->devfn),
|
||||
PCI_FUNC(dev->pdev->devfn));
|
||||
|
||||
if (len > dev->unique_len)
|
||||
DRM_ERROR("Unique buffer overflowed\n");
|
||||
|
||||
dev->devname =
|
||||
drm_alloc(strlen(dev->driver->pci_driver.name) + dev->unique_len +
|
||||
2, DRM_MEM_DRIVER);
|
||||
if (dev->devname == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
sprintf(dev->devname, "%s@%s", dev->driver->pci_driver.name,
|
||||
dev->unique);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a mapping information.
|
||||
*
|
||||
* \param inode device inode.
|
||||
* \param filp file pointer.
|
||||
* \param cmd command.
|
||||
* \param arg user argument, pointing to a drm_map structure.
|
||||
*
|
||||
* \return zero on success or a negative number on failure.
|
||||
*
|
||||
* Searches for the mapping with the specified offset and copies its information
|
||||
* into userspace
|
||||
*/
|
||||
int drm_getmap(struct inode *inode, struct file *filp,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
drm_file_t *priv = filp->private_data;
|
||||
drm_device_t *dev = priv->head->dev;
|
||||
drm_map_t __user *argp = (void __user *)arg;
|
||||
drm_map_t map;
|
||||
drm_map_list_t *r_list = NULL;
|
||||
struct list_head *list;
|
||||
int idx;
|
||||
int i;
|
||||
|
||||
if (copy_from_user(&map, argp, sizeof(map)))
|
||||
return -EFAULT;
|
||||
idx = map.offset;
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
if (idx < 0) {
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
list_for_each(list, &dev->maplist->head) {
|
||||
if (i == idx) {
|
||||
r_list = list_entry(list, drm_map_list_t, head);
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if (!r_list || !r_list->map) {
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
map.offset = r_list->map->offset;
|
||||
map.size = r_list->map->size;
|
||||
map.type = r_list->map->type;
|
||||
map.flags = r_list->map->flags;
|
||||
map.handle = (void *)(unsigned long)r_list->user_token;
|
||||
map.mtrr = r_list->map->mtrr;
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
if (copy_to_user(argp, &map, sizeof(map)))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get client information.
|
||||
*
|
||||
* \param inode device inode.
|
||||
* \param filp file pointer.
|
||||
* \param cmd command.
|
||||
* \param arg user argument, pointing to a drm_client structure.
|
||||
*
|
||||
* \return zero on success or a negative number on failure.
|
||||
*
|
||||
* Searches for the client with the specified index and copies its information
|
||||
* into userspace
|
||||
*/
|
||||
int drm_getclient(struct inode *inode, struct file *filp,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
drm_file_t *priv = filp->private_data;
|
||||
drm_device_t *dev = priv->head->dev;
|
||||
drm_client_t __user *argp = (drm_client_t __user *)arg;
|
||||
drm_client_t client;
|
||||
drm_file_t *pt;
|
||||
int idx;
|
||||
int i;
|
||||
|
||||
if (copy_from_user(&client, argp, sizeof(client)))
|
||||
return -EFAULT;
|
||||
idx = client.idx;
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
for (i = 0, pt = dev->file_first; i < idx && pt; i++, pt = pt->next) ;
|
||||
|
||||
if (!pt) {
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return -EINVAL;
|
||||
}
|
||||
client.auth = pt->authenticated;
|
||||
client.pid = pt->pid;
|
||||
client.uid = pt->uid;
|
||||
client.magic = pt->magic;
|
||||
client.iocs = pt->ioctl_count;
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
if (copy_to_user(argp, &client, sizeof(client)))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get statistics information.
|
||||
*
|
||||
* \param inode device inode.
|
||||
* \param filp file pointer.
|
||||
* \param cmd command.
|
||||
* \param arg user argument, pointing to a drm_stats structure.
|
||||
*
|
||||
* \return zero on success or a negative number on failure.
|
||||
*/
|
||||
int drm_getstats(struct inode *inode, struct file *filp,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
drm_file_t *priv = filp->private_data;
|
||||
drm_device_t *dev = priv->head->dev;
|
||||
drm_stats_t stats;
|
||||
int i;
|
||||
|
||||
memset(&stats, 0, sizeof(stats));
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
|
||||
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;
|
||||
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
if (copy_to_user((drm_stats_t __user *) arg, &stats, sizeof(stats)))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setversion ioctl.
|
||||
*
|
||||
* \param inode device inode.
|
||||
* \param filp file pointer.
|
||||
* \param cmd command.
|
||||
* \param arg user argument, pointing to a drm_lock structure.
|
||||
* \return zero on success or negative number on failure.
|
||||
*
|
||||
* Sets the requested interface version
|
||||
*/
|
||||
int drm_setversion(DRM_IOCTL_ARGS)
|
||||
{
|
||||
DRM_DEVICE;
|
||||
drm_set_version_t sv;
|
||||
drm_set_version_t retv;
|
||||
int if_version;
|
||||
drm_set_version_t __user *argp = (void __user *)data;
|
||||
int ret;
|
||||
|
||||
if (copy_from_user(&sv, argp, sizeof(sv)))
|
||||
return -EFAULT;
|
||||
|
||||
retv.drm_di_major = DRM_IF_MAJOR;
|
||||
retv.drm_di_minor = DRM_IF_MINOR;
|
||||
retv.drm_dd_major = dev->driver->major;
|
||||
retv.drm_dd_minor = dev->driver->minor;
|
||||
|
||||
if (copy_to_user(argp, &retv, sizeof(retv)))
|
||||
return -EFAULT;
|
||||
|
||||
if (sv.drm_di_major != -1) {
|
||||
if (sv.drm_di_major != DRM_IF_MAJOR ||
|
||||
sv.drm_di_minor < 0 || sv.drm_di_minor > DRM_IF_MINOR)
|
||||
return -EINVAL;
|
||||
if_version = DRM_IF_VERSION(sv.drm_di_major, sv.drm_di_minor);
|
||||
dev->if_version = max(if_version, dev->if_version);
|
||||
if (sv.drm_di_minor >= 1) {
|
||||
/*
|
||||
* Version 1.1 includes tying of DRM to specific device
|
||||
*/
|
||||
ret = drm_set_busid(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (dev->driver->set_version)
|
||||
dev->driver->set_version(dev, &sv);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** No-op ioctl. */
|
||||
int drm_noop(struct inode *inode, struct file *filp, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
DRM_DEBUG("\n");
|
||||
return 0;
|
||||
}
|
||||
482
drivers/char/drm/drm_irq.c
Normal file
482
drivers/char/drm/drm_irq.c
Normal file
@@ -0,0 +1,482 @@
|
||||
/**
|
||||
* \file drm_irq.c
|
||||
* IRQ support
|
||||
*
|
||||
* \author Rickard E. (Rik) Faith <faith@valinux.com>
|
||||
* \author Gareth Hughes <gareth@valinux.com>
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "drmP.h"
|
||||
|
||||
#include <linux/interrupt.h> /* For task queue support */
|
||||
|
||||
/**
|
||||
* Get interrupt from bus id.
|
||||
*
|
||||
* \param inode device inode.
|
||||
* \param filp file pointer.
|
||||
* \param cmd command.
|
||||
* \param arg user argument, pointing to a drm_irq_busid structure.
|
||||
* \return zero on success or a negative number on failure.
|
||||
*
|
||||
* Finds the PCI device with the specified bus id and gets its IRQ number.
|
||||
* This IOCTL is deprecated, and will now return EINVAL for any busid not equal
|
||||
* to that of the device that this DRM instance attached to.
|
||||
*/
|
||||
int drm_irq_by_busid(struct inode *inode, struct file *filp,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
drm_file_t *priv = filp->private_data;
|
||||
drm_device_t *dev = priv->head->dev;
|
||||
drm_irq_busid_t __user *argp = (void __user *)arg;
|
||||
drm_irq_busid_t p;
|
||||
|
||||
if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
|
||||
return -EINVAL;
|
||||
|
||||
if (copy_from_user(&p, argp, sizeof(p)))
|
||||
return -EFAULT;
|
||||
|
||||
if ((p.busnum >> 8) != drm_get_pci_domain(dev) ||
|
||||
(p.busnum & 0xff) != dev->pdev->bus->number ||
|
||||
p.devnum != PCI_SLOT(dev->pdev->devfn) || p.funcnum != PCI_FUNC(dev->pdev->devfn))
|
||||
return -EINVAL;
|
||||
|
||||
p.irq = dev->irq;
|
||||
|
||||
DRM_DEBUG("%d:%d:%d => IRQ %d\n", p.busnum, p.devnum, p.funcnum, p.irq);
|
||||
if (copy_to_user(argp, &p, sizeof(p)))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Install IRQ handler.
|
||||
*
|
||||
* \param dev DRM device.
|
||||
* \param irq IRQ number.
|
||||
*
|
||||
* Initializes the IRQ related data, and setups drm_device::vbl_queue. Installs the handler, calling the driver
|
||||
* \c drm_driver_irq_preinstall() and \c drm_driver_irq_postinstall() functions
|
||||
* before and after the installation.
|
||||
*/
|
||||
static int drm_irq_install(drm_device_t * dev)
|
||||
{
|
||||
int ret;
|
||||
unsigned long sh_flags = 0;
|
||||
|
||||
if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
|
||||
return -EINVAL;
|
||||
|
||||
if (dev->irq == 0)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
|
||||
/* Driver must have been initialized */
|
||||
if (!dev->dev_private) {
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (dev->irq_enabled) {
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return -EBUSY;
|
||||
}
|
||||
dev->irq_enabled = 1;
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
DRM_DEBUG("%s: irq=%d\n", __FUNCTION__, dev->irq);
|
||||
|
||||
if (drm_core_check_feature(dev, DRIVER_IRQ_VBL)) {
|
||||
init_waitqueue_head(&dev->vbl_queue);
|
||||
|
||||
spin_lock_init(&dev->vbl_lock);
|
||||
|
||||
INIT_LIST_HEAD(&dev->vbl_sigs.head);
|
||||
INIT_LIST_HEAD(&dev->vbl_sigs2.head);
|
||||
|
||||
dev->vbl_pending = 0;
|
||||
}
|
||||
|
||||
/* Before installing handler */
|
||||
dev->driver->irq_preinstall(dev);
|
||||
|
||||
/* Install handler */
|
||||
if (drm_core_check_feature(dev, DRIVER_IRQ_SHARED))
|
||||
sh_flags = IRQF_SHARED;
|
||||
|
||||
ret = request_irq(dev->irq, dev->driver->irq_handler,
|
||||
sh_flags, dev->devname, dev);
|
||||
if (ret < 0) {
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
dev->irq_enabled = 0;
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* After installing handler */
|
||||
dev->driver->irq_postinstall(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uninstall the IRQ handler.
|
||||
*
|
||||
* \param dev DRM device.
|
||||
*
|
||||
* Calls the driver's \c drm_driver_irq_uninstall() function, and stops the irq.
|
||||
*/
|
||||
int drm_irq_uninstall(drm_device_t * dev)
|
||||
{
|
||||
int irq_enabled;
|
||||
|
||||
if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
irq_enabled = dev->irq_enabled;
|
||||
dev->irq_enabled = 0;
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
if (!irq_enabled)
|
||||
return -EINVAL;
|
||||
|
||||
DRM_DEBUG("%s: irq=%d\n", __FUNCTION__, dev->irq);
|
||||
|
||||
dev->driver->irq_uninstall(dev);
|
||||
|
||||
free_irq(dev->irq, dev);
|
||||
|
||||
dev->locked_tasklet_func = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(drm_irq_uninstall);
|
||||
|
||||
/**
|
||||
* IRQ control ioctl.
|
||||
*
|
||||
* \param inode device inode.
|
||||
* \param filp file pointer.
|
||||
* \param cmd command.
|
||||
* \param arg user argument, pointing to a drm_control structure.
|
||||
* \return zero on success or a negative number on failure.
|
||||
*
|
||||
* Calls irq_install() or irq_uninstall() according to \p arg.
|
||||
*/
|
||||
int drm_control(struct inode *inode, struct file *filp,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
drm_file_t *priv = filp->private_data;
|
||||
drm_device_t *dev = priv->head->dev;
|
||||
drm_control_t ctl;
|
||||
|
||||
/* if we haven't irq we fallback for compatibility reasons - this used to be a separate function in drm_dma.h */
|
||||
|
||||
if (copy_from_user(&ctl, (drm_control_t __user *) arg, sizeof(ctl)))
|
||||
return -EFAULT;
|
||||
|
||||
switch (ctl.func) {
|
||||
case DRM_INST_HANDLER:
|
||||
if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
|
||||
return 0;
|
||||
if (dev->if_version < DRM_IF_VERSION(1, 2) &&
|
||||
ctl.irq != dev->irq)
|
||||
return -EINVAL;
|
||||
return drm_irq_install(dev);
|
||||
case DRM_UNINST_HANDLER:
|
||||
if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
|
||||
return 0;
|
||||
return drm_irq_uninstall(dev);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for VBLANK.
|
||||
*
|
||||
* \param inode device inode.
|
||||
* \param filp file pointer.
|
||||
* \param cmd command.
|
||||
* \param data user argument, pointing to a drm_wait_vblank structure.
|
||||
* \return zero on success or a negative number on failure.
|
||||
*
|
||||
* Verifies the IRQ is installed.
|
||||
*
|
||||
* If a signal is requested checks if this task has already scheduled the same signal
|
||||
* for the same vblank sequence number - nothing to be done in
|
||||
* that case. If the number of tasks waiting for the interrupt exceeds 100 the
|
||||
* function fails. Otherwise adds a new entry to drm_device::vbl_sigs for this
|
||||
* task.
|
||||
*
|
||||
* If a signal is not requested, then calls vblank_wait().
|
||||
*/
|
||||
int drm_wait_vblank(DRM_IOCTL_ARGS)
|
||||
{
|
||||
drm_file_t *priv = filp->private_data;
|
||||
drm_device_t *dev = priv->head->dev;
|
||||
drm_wait_vblank_t __user *argp = (void __user *)data;
|
||||
drm_wait_vblank_t vblwait;
|
||||
struct timeval now;
|
||||
int ret = 0;
|
||||
unsigned int flags, seq;
|
||||
|
||||
if (!dev->irq)
|
||||
return -EINVAL;
|
||||
|
||||
if (copy_from_user(&vblwait, argp, sizeof(vblwait)))
|
||||
return -EFAULT;
|
||||
|
||||
if (vblwait.request.type &
|
||||
~(_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK)) {
|
||||
DRM_ERROR("Unsupported type value 0x%x, supported mask 0x%x\n",
|
||||
vblwait.request.type,
|
||||
(_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
flags = vblwait.request.type & _DRM_VBLANK_FLAGS_MASK;
|
||||
|
||||
if (!drm_core_check_feature(dev, (flags & _DRM_VBLANK_SECONDARY) ?
|
||||
DRIVER_IRQ_VBL2 : DRIVER_IRQ_VBL))
|
||||
return -EINVAL;
|
||||
|
||||
seq = atomic_read((flags & _DRM_VBLANK_SECONDARY) ? &dev->vbl_received2
|
||||
: &dev->vbl_received);
|
||||
|
||||
switch (vblwait.request.type & _DRM_VBLANK_TYPES_MASK) {
|
||||
case _DRM_VBLANK_RELATIVE:
|
||||
vblwait.request.sequence += seq;
|
||||
vblwait.request.type &= ~_DRM_VBLANK_RELATIVE;
|
||||
case _DRM_VBLANK_ABSOLUTE:
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ((flags & _DRM_VBLANK_NEXTONMISS) &&
|
||||
(seq - vblwait.request.sequence) <= (1<<23)) {
|
||||
vblwait.request.sequence = seq + 1;
|
||||
}
|
||||
|
||||
if (flags & _DRM_VBLANK_SIGNAL) {
|
||||
unsigned long irqflags;
|
||||
drm_vbl_sig_t *vbl_sigs = (flags & _DRM_VBLANK_SECONDARY)
|
||||
? &dev->vbl_sigs2 : &dev->vbl_sigs;
|
||||
drm_vbl_sig_t *vbl_sig;
|
||||
|
||||
spin_lock_irqsave(&dev->vbl_lock, irqflags);
|
||||
|
||||
/* Check if this task has already scheduled the same signal
|
||||
* for the same vblank sequence number; nothing to be done in
|
||||
* that case
|
||||
*/
|
||||
list_for_each_entry(vbl_sig, &vbl_sigs->head, head) {
|
||||
if (vbl_sig->sequence == vblwait.request.sequence
|
||||
&& vbl_sig->info.si_signo == vblwait.request.signal
|
||||
&& vbl_sig->task == current) {
|
||||
spin_unlock_irqrestore(&dev->vbl_lock,
|
||||
irqflags);
|
||||
vblwait.reply.sequence = seq;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
if (dev->vbl_pending >= 100) {
|
||||
spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
dev->vbl_pending++;
|
||||
|
||||
spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
|
||||
|
||||
if (!
|
||||
(vbl_sig =
|
||||
drm_alloc(sizeof(drm_vbl_sig_t), DRM_MEM_DRIVER))) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
memset((void *)vbl_sig, 0, sizeof(*vbl_sig));
|
||||
|
||||
vbl_sig->sequence = vblwait.request.sequence;
|
||||
vbl_sig->info.si_signo = vblwait.request.signal;
|
||||
vbl_sig->task = current;
|
||||
|
||||
spin_lock_irqsave(&dev->vbl_lock, irqflags);
|
||||
|
||||
list_add_tail((struct list_head *)vbl_sig, &vbl_sigs->head);
|
||||
|
||||
spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
|
||||
|
||||
vblwait.reply.sequence = seq;
|
||||
} else {
|
||||
if (flags & _DRM_VBLANK_SECONDARY) {
|
||||
if (dev->driver->vblank_wait2)
|
||||
ret = dev->driver->vblank_wait2(dev, &vblwait.request.sequence);
|
||||
} else if (dev->driver->vblank_wait)
|
||||
ret =
|
||||
dev->driver->vblank_wait(dev,
|
||||
&vblwait.request.sequence);
|
||||
|
||||
do_gettimeofday(&now);
|
||||
vblwait.reply.tval_sec = now.tv_sec;
|
||||
vblwait.reply.tval_usec = now.tv_usec;
|
||||
}
|
||||
|
||||
done:
|
||||
if (copy_to_user(argp, &vblwait, sizeof(vblwait)))
|
||||
return -EFAULT;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the VBLANK signals.
|
||||
*
|
||||
* \param dev DRM device.
|
||||
*
|
||||
* Sends a signal for each task in drm_device::vbl_sigs and empties the list.
|
||||
*
|
||||
* If a signal is not requested, then calls vblank_wait().
|
||||
*/
|
||||
void drm_vbl_send_signals(drm_device_t * dev)
|
||||
{
|
||||
unsigned long flags;
|
||||
int i;
|
||||
|
||||
spin_lock_irqsave(&dev->vbl_lock, flags);
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
struct list_head *list, *tmp;
|
||||
drm_vbl_sig_t *vbl_sig;
|
||||
drm_vbl_sig_t *vbl_sigs = i ? &dev->vbl_sigs2 : &dev->vbl_sigs;
|
||||
unsigned int vbl_seq = atomic_read(i ? &dev->vbl_received2 :
|
||||
&dev->vbl_received);
|
||||
|
||||
list_for_each_safe(list, tmp, &vbl_sigs->head) {
|
||||
vbl_sig = list_entry(list, drm_vbl_sig_t, head);
|
||||
if ((vbl_seq - vbl_sig->sequence) <= (1 << 23)) {
|
||||
vbl_sig->info.si_code = vbl_seq;
|
||||
send_sig_info(vbl_sig->info.si_signo,
|
||||
&vbl_sig->info, vbl_sig->task);
|
||||
|
||||
list_del(list);
|
||||
|
||||
drm_free(vbl_sig, sizeof(*vbl_sig),
|
||||
DRM_MEM_DRIVER);
|
||||
|
||||
dev->vbl_pending--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&dev->vbl_lock, flags);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(drm_vbl_send_signals);
|
||||
|
||||
/**
|
||||
* Tasklet wrapper function.
|
||||
*
|
||||
* \param data DRM device in disguise.
|
||||
*
|
||||
* Attempts to grab the HW lock and calls the driver callback on success. On
|
||||
* failure, leave the lock marked as contended so the callback can be called
|
||||
* from drm_unlock().
|
||||
*/
|
||||
static void drm_locked_tasklet_func(unsigned long data)
|
||||
{
|
||||
drm_device_t *dev = (drm_device_t*)data;
|
||||
unsigned long irqflags;
|
||||
|
||||
spin_lock_irqsave(&dev->tasklet_lock, irqflags);
|
||||
|
||||
if (!dev->locked_tasklet_func ||
|
||||
!drm_lock_take(&dev->lock.hw_lock->lock,
|
||||
DRM_KERNEL_CONTEXT)) {
|
||||
spin_unlock_irqrestore(&dev->tasklet_lock, irqflags);
|
||||
return;
|
||||
}
|
||||
|
||||
dev->lock.lock_time = jiffies;
|
||||
atomic_inc(&dev->counts[_DRM_STAT_LOCKS]);
|
||||
|
||||
dev->locked_tasklet_func(dev);
|
||||
|
||||
drm_lock_free(dev, &dev->lock.hw_lock->lock,
|
||||
DRM_KERNEL_CONTEXT);
|
||||
|
||||
dev->locked_tasklet_func = NULL;
|
||||
|
||||
spin_unlock_irqrestore(&dev->tasklet_lock, irqflags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule a tasklet to call back a driver hook with the HW lock held.
|
||||
*
|
||||
* \param dev DRM device.
|
||||
* \param func Driver callback.
|
||||
*
|
||||
* This is intended for triggering actions that require the HW lock from an
|
||||
* interrupt handler. The lock will be grabbed ASAP after the interrupt handler
|
||||
* completes. Note that the callback may be called from interrupt or process
|
||||
* context, it must not make any assumptions about this. Also, the HW lock will
|
||||
* be held with the kernel context or any client context.
|
||||
*/
|
||||
void drm_locked_tasklet(drm_device_t *dev, void (*func)(drm_device_t*))
|
||||
{
|
||||
unsigned long irqflags;
|
||||
static DECLARE_TASKLET(drm_tasklet, drm_locked_tasklet_func, 0);
|
||||
|
||||
if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ) ||
|
||||
test_bit(TASKLET_STATE_SCHED, &drm_tasklet.state))
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&dev->tasklet_lock, irqflags);
|
||||
|
||||
if (dev->locked_tasklet_func) {
|
||||
spin_unlock_irqrestore(&dev->tasklet_lock, irqflags);
|
||||
return;
|
||||
}
|
||||
|
||||
dev->locked_tasklet_func = func;
|
||||
|
||||
spin_unlock_irqrestore(&dev->tasklet_lock, irqflags);
|
||||
|
||||
drm_tasklet.data = (unsigned long)dev;
|
||||
|
||||
tasklet_hi_schedule(&drm_tasklet);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_locked_tasklet);
|
||||
324
drivers/char/drm/drm_lock.c
Normal file
324
drivers/char/drm/drm_lock.c
Normal file
@@ -0,0 +1,324 @@
|
||||
/**
|
||||
* \file drm_lock.c
|
||||
* IOCTLs for locking
|
||||
*
|
||||
* \author Rickard E. (Rik) Faith <faith@valinux.com>
|
||||
* \author Gareth Hughes <gareth@valinux.com>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Created: Tue Feb 2 08:37:54 1999 by faith@valinux.com
|
||||
*
|
||||
* Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
|
||||
* Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "drmP.h"
|
||||
|
||||
static int drm_lock_transfer(drm_device_t * dev,
|
||||
__volatile__ unsigned int *lock,
|
||||
unsigned int context);
|
||||
static int drm_notifier(void *priv);
|
||||
|
||||
/**
|
||||
* Lock ioctl.
|
||||
*
|
||||
* \param inode device inode.
|
||||
* \param filp file pointer.
|
||||
* \param cmd command.
|
||||
* \param arg user argument, pointing to a drm_lock structure.
|
||||
* \return zero on success or negative number on failure.
|
||||
*
|
||||
* Add the current task to the lock wait queue, and attempt to take to lock.
|
||||
*/
|
||||
int drm_lock(struct inode *inode, struct file *filp,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
drm_file_t *priv = filp->private_data;
|
||||
drm_device_t *dev = priv->head->dev;
|
||||
DECLARE_WAITQUEUE(entry, current);
|
||||
drm_lock_t lock;
|
||||
int ret = 0;
|
||||
|
||||
++priv->lock_count;
|
||||
|
||||
if (copy_from_user(&lock, (drm_lock_t __user *) arg, sizeof(lock)))
|
||||
return -EFAULT;
|
||||
|
||||
if (lock.context == DRM_KERNEL_CONTEXT) {
|
||||
DRM_ERROR("Process %d using kernel context %d\n",
|
||||
current->pid, lock.context);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
DRM_DEBUG("%d (pid %d) requests lock (0x%08x), flags = 0x%08x\n",
|
||||
lock.context, current->pid,
|
||||
dev->lock.hw_lock->lock, lock.flags);
|
||||
|
||||
if (drm_core_check_feature(dev, DRIVER_DMA_QUEUE))
|
||||
if (lock.context < 0)
|
||||
return -EINVAL;
|
||||
|
||||
add_wait_queue(&dev->lock.lock_queue, &entry);
|
||||
for (;;) {
|
||||
__set_current_state(TASK_INTERRUPTIBLE);
|
||||
if (!dev->lock.hw_lock) {
|
||||
/* Device has been unregistered */
|
||||
ret = -EINTR;
|
||||
break;
|
||||
}
|
||||
if (drm_lock_take(&dev->lock.hw_lock->lock, lock.context)) {
|
||||
dev->lock.filp = filp;
|
||||
dev->lock.lock_time = jiffies;
|
||||
atomic_inc(&dev->counts[_DRM_STAT_LOCKS]);
|
||||
break; /* Got lock */
|
||||
}
|
||||
|
||||
/* Contention */
|
||||
schedule();
|
||||
if (signal_pending(current)) {
|
||||
ret = -ERESTARTSYS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
__set_current_state(TASK_RUNNING);
|
||||
remove_wait_queue(&dev->lock.lock_queue, &entry);
|
||||
|
||||
DRM_DEBUG("%d %s\n", lock.context, ret ? "interrupted" : "has lock");
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
sigemptyset(&dev->sigmask);
|
||||
sigaddset(&dev->sigmask, SIGSTOP);
|
||||
sigaddset(&dev->sigmask, SIGTSTP);
|
||||
sigaddset(&dev->sigmask, SIGTTIN);
|
||||
sigaddset(&dev->sigmask, SIGTTOU);
|
||||
dev->sigdata.context = lock.context;
|
||||
dev->sigdata.lock = dev->lock.hw_lock;
|
||||
block_all_signals(drm_notifier, &dev->sigdata, &dev->sigmask);
|
||||
|
||||
if (dev->driver->dma_ready && (lock.flags & _DRM_LOCK_READY))
|
||||
dev->driver->dma_ready(dev);
|
||||
|
||||
if (dev->driver->dma_quiescent && (lock.flags & _DRM_LOCK_QUIESCENT)) {
|
||||
if (dev->driver->dma_quiescent(dev)) {
|
||||
DRM_DEBUG("%d waiting for DMA quiescent\n", lock.context);
|
||||
return DRM_ERR(EBUSY);
|
||||
}
|
||||
}
|
||||
|
||||
/* dev->driver->kernel_context_switch isn't used by any of the x86
|
||||
* drivers but is used by the Sparc driver.
|
||||
*/
|
||||
if (dev->driver->kernel_context_switch &&
|
||||
dev->last_context != lock.context) {
|
||||
dev->driver->kernel_context_switch(dev, dev->last_context,
|
||||
lock.context);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlock ioctl.
|
||||
*
|
||||
* \param inode device inode.
|
||||
* \param filp file pointer.
|
||||
* \param cmd command.
|
||||
* \param arg user argument, pointing to a drm_lock structure.
|
||||
* \return zero on success or negative number on failure.
|
||||
*
|
||||
* Transfer and free the lock.
|
||||
*/
|
||||
int drm_unlock(struct inode *inode, struct file *filp,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
drm_file_t *priv = filp->private_data;
|
||||
drm_device_t *dev = priv->head->dev;
|
||||
drm_lock_t lock;
|
||||
unsigned long irqflags;
|
||||
|
||||
if (copy_from_user(&lock, (drm_lock_t __user *) arg, sizeof(lock)))
|
||||
return -EFAULT;
|
||||
|
||||
if (lock.context == DRM_KERNEL_CONTEXT) {
|
||||
DRM_ERROR("Process %d using kernel context %d\n",
|
||||
current->pid, lock.context);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&dev->tasklet_lock, irqflags);
|
||||
|
||||
if (dev->locked_tasklet_func) {
|
||||
dev->locked_tasklet_func(dev);
|
||||
|
||||
dev->locked_tasklet_func = NULL;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&dev->tasklet_lock, irqflags);
|
||||
|
||||
atomic_inc(&dev->counts[_DRM_STAT_UNLOCKS]);
|
||||
|
||||
/* kernel_context_switch isn't used by any of the x86 drm
|
||||
* modules but is required by the Sparc driver.
|
||||
*/
|
||||
if (dev->driver->kernel_context_switch_unlock)
|
||||
dev->driver->kernel_context_switch_unlock(dev);
|
||||
else {
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
unblock_all_signals();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Take the heavyweight lock.
|
||||
*
|
||||
* \param lock lock pointer.
|
||||
* \param context locking context.
|
||||
* \return one if the lock is held, or zero otherwise.
|
||||
*
|
||||
* Attempt to mark the lock as held by the given context, via the \p cmpxchg instruction.
|
||||
*/
|
||||
int drm_lock_take(__volatile__ unsigned int *lock, unsigned int context)
|
||||
{
|
||||
unsigned int old, new, prev;
|
||||
|
||||
do {
|
||||
old = *lock;
|
||||
if (old & _DRM_LOCK_HELD)
|
||||
new = old | _DRM_LOCK_CONT;
|
||||
else
|
||||
new = context | _DRM_LOCK_HELD;
|
||||
prev = cmpxchg(lock, old, new);
|
||||
} while (prev != old);
|
||||
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.
|
||||
*
|
||||
* \param dev DRM device.
|
||||
* \param lock lock pointer.
|
||||
* \param context locking context.
|
||||
* \return always one.
|
||||
*
|
||||
* Resets the lock file pointer.
|
||||
* Marks the lock as held by the given context, via the \p cmpxchg instruction.
|
||||
*/
|
||||
static int drm_lock_transfer(drm_device_t * dev,
|
||||
__volatile__ unsigned int *lock,
|
||||
unsigned int context)
|
||||
{
|
||||
unsigned int old, new, prev;
|
||||
|
||||
dev->lock.filp = NULL;
|
||||
do {
|
||||
old = *lock;
|
||||
new = context | _DRM_LOCK_HELD;
|
||||
prev = cmpxchg(lock, old, new);
|
||||
} while (prev != old);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Free lock.
|
||||
*
|
||||
* \param dev DRM device.
|
||||
* \param lock lock.
|
||||
* \param context context.
|
||||
*
|
||||
* Resets the lock file pointer.
|
||||
* Marks the lock as not held, via the \p cmpxchg instruction. Wakes any task
|
||||
* waiting on the lock queue.
|
||||
*/
|
||||
int drm_lock_free(drm_device_t * dev,
|
||||
__volatile__ unsigned int *lock, unsigned int context)
|
||||
{
|
||||
unsigned int old, new, prev;
|
||||
|
||||
dev->lock.filp = NULL;
|
||||
do {
|
||||
old = *lock;
|
||||
new = 0;
|
||||
prev = cmpxchg(lock, old, new);
|
||||
} while (prev != old);
|
||||
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;
|
||||
}
|
||||
wake_up_interruptible(&dev->lock.lock_queue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* If we get here, it means that the process has called DRM_IOCTL_LOCK
|
||||
* without calling DRM_IOCTL_UNLOCK.
|
||||
*
|
||||
* If the lock is not held, then let the signal proceed as usual. If the lock
|
||||
* is held, then set the contended flag and keep the signal blocked.
|
||||
*
|
||||
* \param priv pointer to a drm_sigdata structure.
|
||||
* \return one if the signal should be delivered normally, or zero if the
|
||||
* signal should be blocked.
|
||||
*/
|
||||
static int drm_notifier(void *priv)
|
||||
{
|
||||
drm_sigdata_t *s = (drm_sigdata_t *) priv;
|
||||
unsigned int old, new, prev;
|
||||
|
||||
/* Allow signal delivery if lock isn't held */
|
||||
if (!s->lock || !_DRM_LOCK_IS_HELD(s->lock->lock)
|
||||
|| _DRM_LOCKING_CONTEXT(s->lock->lock) != s->context)
|
||||
return 1;
|
||||
|
||||
/* Otherwise, set flag to force call to
|
||||
drmUnlock */
|
||||
do {
|
||||
old = s->lock->lock;
|
||||
new = old | _DRM_LOCK_CONT;
|
||||
prev = cmpxchg(&s->lock->lock, old, new);
|
||||
} while (prev != old);
|
||||
return 0;
|
||||
}
|
||||
182
drivers/char/drm/drm_memory.c
Normal file
182
drivers/char/drm/drm_memory.c
Normal file
@@ -0,0 +1,182 @@
|
||||
/**
|
||||
* \file drm_memory.c
|
||||
* Memory management wrappers for DRM
|
||||
*
|
||||
* \author Rickard E. (Rik) Faith <faith@valinux.com>
|
||||
* \author Gareth Hughes <gareth@valinux.com>
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <linux/highmem.h>
|
||||
#include "drmP.h"
|
||||
|
||||
#ifdef DEBUG_MEMORY
|
||||
#include "drm_memory_debug.h"
|
||||
#else
|
||||
|
||||
/** No-op. */
|
||||
void drm_mem_init(void)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when "/proc/dri/%dev%/mem" is read.
|
||||
*
|
||||
* \param buf output buffer.
|
||||
* \param start start of output data.
|
||||
* \param offset requested start offset.
|
||||
* \param len requested number of bytes.
|
||||
* \param eof whether there is no more data to return.
|
||||
* \param data private data.
|
||||
* \return number of written bytes.
|
||||
*
|
||||
* No-op.
|
||||
*/
|
||||
int drm_mem_info(char *buf, char **start, off_t offset,
|
||||
int len, int *eof, void *data)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Wrapper around kmalloc() and kfree() */
|
||||
void *drm_realloc(void *oldpt, size_t oldsize, size_t size, int area)
|
||||
{
|
||||
void *pt;
|
||||
|
||||
if (!(pt = kmalloc(size, GFP_KERNEL)))
|
||||
return NULL;
|
||||
if (oldpt && oldsize) {
|
||||
memcpy(pt, oldpt, oldsize);
|
||||
kfree(oldpt);
|
||||
}
|
||||
return pt;
|
||||
}
|
||||
|
||||
#if __OS_HAS_AGP
|
||||
static void *agp_remap(unsigned long offset, unsigned long size,
|
||||
drm_device_t * dev)
|
||||
{
|
||||
unsigned long *phys_addr_map, i, num_pages =
|
||||
PAGE_ALIGN(size) / PAGE_SIZE;
|
||||
struct drm_agp_mem *agpmem;
|
||||
struct page **page_map;
|
||||
void *addr;
|
||||
|
||||
size = PAGE_ALIGN(size);
|
||||
|
||||
#ifdef __alpha__
|
||||
offset -= dev->hose->mem_space->start;
|
||||
#endif
|
||||
|
||||
for (agpmem = dev->agp->memory; agpmem; agpmem = agpmem->next)
|
||||
if (agpmem->bound <= offset
|
||||
&& (agpmem->bound + (agpmem->pages << PAGE_SHIFT)) >=
|
||||
(offset + size))
|
||||
break;
|
||||
if (!agpmem)
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* OK, we're mapping AGP space on a chipset/platform on which memory accesses by
|
||||
* the CPU do not get remapped by the GART. We fix this by using the kernel's
|
||||
* page-table instead (that's probably faster anyhow...).
|
||||
*/
|
||||
/* note: use vmalloc() because num_pages could be large... */
|
||||
page_map = vmalloc(num_pages * sizeof(struct page *));
|
||||
if (!page_map)
|
||||
return NULL;
|
||||
|
||||
phys_addr_map =
|
||||
agpmem->memory->memory + (offset - agpmem->bound) / PAGE_SIZE;
|
||||
for (i = 0; i < num_pages; ++i)
|
||||
page_map[i] = pfn_to_page(phys_addr_map[i] >> PAGE_SHIFT);
|
||||
addr = vmap(page_map, num_pages, VM_IOREMAP, PAGE_AGP);
|
||||
vfree(page_map);
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
/** Wrapper around agp_allocate_memory() */
|
||||
DRM_AGP_MEM *drm_alloc_agp(drm_device_t * dev, int pages, u32 type)
|
||||
{
|
||||
return drm_agp_allocate_memory(dev->agp->bridge, pages, type);
|
||||
}
|
||||
|
||||
/** Wrapper around agp_free_memory() */
|
||||
int drm_free_agp(DRM_AGP_MEM * handle, int pages)
|
||||
{
|
||||
return drm_agp_free_memory(handle) ? 0 : -EINVAL;
|
||||
}
|
||||
|
||||
/** Wrapper around agp_bind_memory() */
|
||||
int drm_bind_agp(DRM_AGP_MEM * handle, unsigned int start)
|
||||
{
|
||||
return drm_agp_bind_memory(handle, start);
|
||||
}
|
||||
|
||||
/** Wrapper around agp_unbind_memory() */
|
||||
int drm_unbind_agp(DRM_AGP_MEM * handle)
|
||||
{
|
||||
return drm_agp_unbind_memory(handle);
|
||||
}
|
||||
|
||||
#else /* __OS_HAS_AGP */
|
||||
static inline void *agp_remap(unsigned long offset, unsigned long size,
|
||||
drm_device_t * dev)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif /* agp */
|
||||
|
||||
#endif /* debug_memory */
|
||||
|
||||
void drm_core_ioremap(struct drm_map *map, struct drm_device *dev)
|
||||
{
|
||||
if (drm_core_has_AGP(dev) &&
|
||||
dev->agp && dev->agp->cant_use_aperture && map->type == _DRM_AGP)
|
||||
map->handle = agp_remap(map->offset, map->size, dev);
|
||||
else
|
||||
map->handle = ioremap(map->offset, map->size);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_core_ioremap);
|
||||
|
||||
void drm_core_ioremapfree(struct drm_map *map, struct drm_device *dev)
|
||||
{
|
||||
if (!map->handle || !map->size)
|
||||
return;
|
||||
|
||||
if (drm_core_has_AGP(dev) &&
|
||||
dev->agp && dev->agp->cant_use_aperture && map->type == _DRM_AGP)
|
||||
vunmap(map->handle);
|
||||
else
|
||||
iounmap(map->handle);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_core_ioremapfree);
|
||||
|
||||
61
drivers/char/drm/drm_memory.h
Normal file
61
drivers/char/drm/drm_memory.h
Normal file
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* \file drm_memory.h
|
||||
* Memory management wrappers for DRM
|
||||
*
|
||||
* \author Rickard E. (Rik) Faith <faith@valinux.com>
|
||||
* \author Gareth Hughes <gareth@valinux.com>
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <linux/highmem.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include "drmP.h"
|
||||
|
||||
/**
|
||||
* Cut down version of drm_memory_debug.h, which used to be called
|
||||
* drm_memory.h.
|
||||
*/
|
||||
|
||||
#if __OS_HAS_AGP
|
||||
|
||||
#include <linux/vmalloc.h>
|
||||
|
||||
#ifdef HAVE_PAGE_AGP
|
||||
#include <asm/agp.h>
|
||||
#else
|
||||
# ifdef __powerpc__
|
||||
# define PAGE_AGP __pgprot(_PAGE_KERNEL | _PAGE_NO_CACHE)
|
||||
# else
|
||||
# define PAGE_AGP PAGE_KERNEL
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#else /* __OS_HAS_AGP */
|
||||
|
||||
#endif
|
||||
309
drivers/char/drm/drm_memory_debug.h
Normal file
309
drivers/char/drm/drm_memory_debug.h
Normal file
@@ -0,0 +1,309 @@
|
||||
/**
|
||||
* \file drm_memory_debug.h
|
||||
* Memory management wrappers for DRM.
|
||||
*
|
||||
* \author Rickard E. (Rik) Faith <faith@valinux.com>
|
||||
* \author Gareth Hughes <gareth@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.
|
||||
*/
|
||||
|
||||
#include "drmP.h"
|
||||
|
||||
typedef struct drm_mem_stats {
|
||||
const char *name;
|
||||
int succeed_count;
|
||||
int free_count;
|
||||
int fail_count;
|
||||
unsigned long bytes_allocated;
|
||||
unsigned long bytes_freed;
|
||||
} drm_mem_stats_t;
|
||||
|
||||
static DEFINE_SPINLOCK(drm_mem_lock);
|
||||
static unsigned long drm_ram_available = 0; /* In pages */
|
||||
static unsigned long drm_ram_used = 0;
|
||||
static drm_mem_stats_t drm_mem_stats[] =
|
||||
{
|
||||
[DRM_MEM_DMA] = {"dmabufs"},
|
||||
[DRM_MEM_SAREA] = {"sareas"},
|
||||
[DRM_MEM_DRIVER] = {"driver"},
|
||||
[DRM_MEM_MAGIC] = {"magic"},
|
||||
[DRM_MEM_IOCTLS] = {"ioctltab"},
|
||||
[DRM_MEM_MAPS] = {"maplist"},
|
||||
[DRM_MEM_VMAS] = {"vmalist"},
|
||||
[DRM_MEM_BUFS] = {"buflist"},
|
||||
[DRM_MEM_SEGS] = {"seglist"},
|
||||
[DRM_MEM_PAGES] = {"pagelist"},
|
||||
[DRM_MEM_FILES] = {"files"},
|
||||
[DRM_MEM_QUEUES] = {"queues"},
|
||||
[DRM_MEM_CMDS] = {"commands"},
|
||||
[DRM_MEM_MAPPINGS] = {"mappings"},
|
||||
[DRM_MEM_BUFLISTS] = {"buflists"},
|
||||
[DRM_MEM_AGPLISTS] = {"agplist"},
|
||||
[DRM_MEM_SGLISTS] = {"sglist"},
|
||||
[DRM_MEM_TOTALAGP] = {"totalagp"},
|
||||
[DRM_MEM_BOUNDAGP] = {"boundagp"},
|
||||
[DRM_MEM_CTXBITMAP] = {"ctxbitmap"},
|
||||
[DRM_MEM_CTXLIST] = {"ctxlist"},
|
||||
[DRM_MEM_STUB] = {"stub"},
|
||||
{NULL, 0,} /* Last entry must be null */
|
||||
};
|
||||
|
||||
void drm_mem_init (void) {
|
||||
drm_mem_stats_t *mem;
|
||||
struct sysinfo si;
|
||||
|
||||
for (mem = drm_mem_stats; mem->name; ++mem) {
|
||||
mem->succeed_count = 0;
|
||||
mem->free_count = 0;
|
||||
mem->fail_count = 0;
|
||||
mem->bytes_allocated = 0;
|
||||
mem->bytes_freed = 0;
|
||||
}
|
||||
|
||||
si_meminfo(&si);
|
||||
drm_ram_available = si.totalram;
|
||||
drm_ram_used = 0;
|
||||
}
|
||||
|
||||
/* drm_mem_info is called whenever a process reads /dev/drm/mem. */
|
||||
|
||||
static int drm__mem_info (char *buf, char **start, off_t offset,
|
||||
int request, int *eof, void *data) {
|
||||
drm_mem_stats_t *pt;
|
||||
int len = 0;
|
||||
|
||||
if (offset > DRM_PROC_LIMIT) {
|
||||
*eof = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
*eof = 0;
|
||||
*start = &buf[offset];
|
||||
|
||||
DRM_PROC_PRINT(" total counts "
|
||||
" | outstanding \n");
|
||||
DRM_PROC_PRINT("type alloc freed fail bytes freed"
|
||||
" | allocs bytes\n\n");
|
||||
DRM_PROC_PRINT("%-9.9s %5d %5d %4d %10lu kB |\n",
|
||||
"system", 0, 0, 0,
|
||||
drm_ram_available << (PAGE_SHIFT - 10));
|
||||
DRM_PROC_PRINT("%-9.9s %5d %5d %4d %10lu kB |\n",
|
||||
"locked", 0, 0, 0, drm_ram_used >> 10);
|
||||
DRM_PROC_PRINT("\n");
|
||||
for (pt = drm_mem_stats; pt->name; pt++) {
|
||||
DRM_PROC_PRINT("%-9.9s %5d %5d %4d %10lu %10lu | %6d %10ld\n",
|
||||
pt->name,
|
||||
pt->succeed_count,
|
||||
pt->free_count,
|
||||
pt->fail_count,
|
||||
pt->bytes_allocated,
|
||||
pt->bytes_freed,
|
||||
pt->succeed_count - pt->free_count,
|
||||
(long)pt->bytes_allocated
|
||||
- (long)pt->bytes_freed);
|
||||
}
|
||||
|
||||
if (len > request + offset)
|
||||
return request;
|
||||
*eof = 1;
|
||||
return len - offset;
|
||||
}
|
||||
|
||||
int drm_mem_info (char *buf, char **start, off_t offset,
|
||||
int len, int *eof, void *data) {
|
||||
int ret;
|
||||
|
||||
spin_lock(&drm_mem_lock);
|
||||
ret = drm__mem_info (buf, start, offset, len, eof, data);
|
||||
spin_unlock(&drm_mem_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void *drm_alloc (size_t size, int area) {
|
||||
void *pt;
|
||||
|
||||
if (!size) {
|
||||
DRM_MEM_ERROR(area, "Allocating 0 bytes\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(pt = kmalloc(size, GFP_KERNEL))) {
|
||||
spin_lock(&drm_mem_lock);
|
||||
++drm_mem_stats[area].fail_count;
|
||||
spin_unlock(&drm_mem_lock);
|
||||
return NULL;
|
||||
}
|
||||
spin_lock(&drm_mem_lock);
|
||||
++drm_mem_stats[area].succeed_count;
|
||||
drm_mem_stats[area].bytes_allocated += size;
|
||||
spin_unlock(&drm_mem_lock);
|
||||
return pt;
|
||||
}
|
||||
|
||||
void *drm_calloc (size_t nmemb, size_t size, int area) {
|
||||
void *addr;
|
||||
|
||||
addr = drm_alloc (nmemb * size, area);
|
||||
if (addr != NULL)
|
||||
memset((void *)addr, 0, size * nmemb);
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
void *drm_realloc (void *oldpt, size_t oldsize, size_t size, int area) {
|
||||
void *pt;
|
||||
|
||||
if (!(pt = drm_alloc (size, area)))
|
||||
return NULL;
|
||||
if (oldpt && oldsize) {
|
||||
memcpy(pt, oldpt, oldsize);
|
||||
drm_free (oldpt, oldsize, area);
|
||||
}
|
||||
return pt;
|
||||
}
|
||||
|
||||
void drm_free (void *pt, size_t size, int area) {
|
||||
int alloc_count;
|
||||
int free_count;
|
||||
|
||||
if (!pt)
|
||||
DRM_MEM_ERROR(area, "Attempt to free NULL pointer\n");
|
||||
else
|
||||
kfree(pt);
|
||||
spin_lock(&drm_mem_lock);
|
||||
drm_mem_stats[area].bytes_freed += size;
|
||||
free_count = ++drm_mem_stats[area].free_count;
|
||||
alloc_count = drm_mem_stats[area].succeed_count;
|
||||
spin_unlock(&drm_mem_lock);
|
||||
if (free_count > alloc_count) {
|
||||
DRM_MEM_ERROR(area, "Excess frees: %d frees, %d allocs\n",
|
||||
free_count, alloc_count);
|
||||
}
|
||||
}
|
||||
|
||||
#if __OS_HAS_AGP
|
||||
|
||||
DRM_AGP_MEM *drm_alloc_agp (drm_device_t *dev, int pages, u32 type) {
|
||||
DRM_AGP_MEM *handle;
|
||||
|
||||
if (!pages) {
|
||||
DRM_MEM_ERROR(DRM_MEM_TOTALAGP, "Allocating 0 pages\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((handle = drm_agp_allocate_memory (pages, type))) {
|
||||
spin_lock(&drm_mem_lock);
|
||||
++drm_mem_stats[DRM_MEM_TOTALAGP].succeed_count;
|
||||
drm_mem_stats[DRM_MEM_TOTALAGP].bytes_allocated
|
||||
+= pages << PAGE_SHIFT;
|
||||
spin_unlock(&drm_mem_lock);
|
||||
return handle;
|
||||
}
|
||||
spin_lock(&drm_mem_lock);
|
||||
++drm_mem_stats[DRM_MEM_TOTALAGP].fail_count;
|
||||
spin_unlock(&drm_mem_lock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int drm_free_agp (DRM_AGP_MEM * handle, int pages) {
|
||||
int alloc_count;
|
||||
int free_count;
|
||||
int retval = -EINVAL;
|
||||
|
||||
if (!handle) {
|
||||
DRM_MEM_ERROR(DRM_MEM_TOTALAGP,
|
||||
"Attempt to free NULL AGP handle\n");
|
||||
return retval;
|
||||
}
|
||||
|
||||
if (drm_agp_free_memory (handle)) {
|
||||
spin_lock(&drm_mem_lock);
|
||||
free_count = ++drm_mem_stats[DRM_MEM_TOTALAGP].free_count;
|
||||
alloc_count = drm_mem_stats[DRM_MEM_TOTALAGP].succeed_count;
|
||||
drm_mem_stats[DRM_MEM_TOTALAGP].bytes_freed
|
||||
+= pages << PAGE_SHIFT;
|
||||
spin_unlock(&drm_mem_lock);
|
||||
if (free_count > alloc_count) {
|
||||
DRM_MEM_ERROR(DRM_MEM_TOTALAGP,
|
||||
"Excess frees: %d frees, %d allocs\n",
|
||||
free_count, alloc_count);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
int drm_bind_agp (DRM_AGP_MEM * handle, unsigned int start) {
|
||||
int retcode = -EINVAL;
|
||||
|
||||
if (!handle) {
|
||||
DRM_MEM_ERROR(DRM_MEM_BOUNDAGP,
|
||||
"Attempt to bind NULL AGP handle\n");
|
||||
return retcode;
|
||||
}
|
||||
|
||||
if (!(retcode = drm_agp_bind_memory (handle, start))) {
|
||||
spin_lock(&drm_mem_lock);
|
||||
++drm_mem_stats[DRM_MEM_BOUNDAGP].succeed_count;
|
||||
drm_mem_stats[DRM_MEM_BOUNDAGP].bytes_allocated
|
||||
+= handle->page_count << PAGE_SHIFT;
|
||||
spin_unlock(&drm_mem_lock);
|
||||
return retcode;
|
||||
}
|
||||
spin_lock(&drm_mem_lock);
|
||||
++drm_mem_stats[DRM_MEM_BOUNDAGP].fail_count;
|
||||
spin_unlock(&drm_mem_lock);
|
||||
return retcode;
|
||||
}
|
||||
|
||||
int drm_unbind_agp (DRM_AGP_MEM * handle) {
|
||||
int alloc_count;
|
||||
int free_count;
|
||||
int retcode = -EINVAL;
|
||||
|
||||
if (!handle) {
|
||||
DRM_MEM_ERROR(DRM_MEM_BOUNDAGP,
|
||||
"Attempt to unbind NULL AGP handle\n");
|
||||
return retcode;
|
||||
}
|
||||
|
||||
if ((retcode = drm_agp_unbind_memory (handle)))
|
||||
return retcode;
|
||||
spin_lock(&drm_mem_lock);
|
||||
free_count = ++drm_mem_stats[DRM_MEM_BOUNDAGP].free_count;
|
||||
alloc_count = drm_mem_stats[DRM_MEM_BOUNDAGP].succeed_count;
|
||||
drm_mem_stats[DRM_MEM_BOUNDAGP].bytes_freed
|
||||
+= handle->page_count << PAGE_SHIFT;
|
||||
spin_unlock(&drm_mem_lock);
|
||||
if (free_count > alloc_count) {
|
||||
DRM_MEM_ERROR(DRM_MEM_BOUNDAGP,
|
||||
"Excess frees: %d frees, %d allocs\n",
|
||||
free_count, alloc_count);
|
||||
}
|
||||
return retcode;
|
||||
}
|
||||
#endif
|
||||
298
drivers/char/drm/drm_mm.c
Normal file
298
drivers/char/drm/drm_mm.c
Normal file
@@ -0,0 +1,298 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sub license, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the
|
||||
* next paragraph) shall be included in all copies or substantial portions
|
||||
* of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
* USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*
|
||||
**************************************************************************/
|
||||
|
||||
/*
|
||||
* Generic simple memory manager implementation. Intended to be used as a base
|
||||
* class implementation for more advanced memory managers.
|
||||
*
|
||||
* Note that the algorithm used is quite simple and there might be substantial
|
||||
* performance gains if a smarter free list is implemented. Currently it is just an
|
||||
* unordered stack of free regions. This could easily be improved if an RB-tree
|
||||
* is used instead. At least if we expect heavy fragmentation.
|
||||
*
|
||||
* Aligned allocations can also see improvement.
|
||||
*
|
||||
* Authors:
|
||||
* Thomas Hellström <thomas-at-tungstengraphics-dot-com>
|
||||
*/
|
||||
|
||||
#include "drmP.h"
|
||||
#include <linux/slab.h>
|
||||
|
||||
unsigned long drm_mm_tail_space(drm_mm_t *mm)
|
||||
{
|
||||
struct list_head *tail_node;
|
||||
drm_mm_node_t *entry;
|
||||
|
||||
tail_node = mm->ml_entry.prev;
|
||||
entry = list_entry(tail_node, drm_mm_node_t, ml_entry);
|
||||
if (!entry->free)
|
||||
return 0;
|
||||
|
||||
return entry->size;
|
||||
}
|
||||
|
||||
int drm_mm_remove_space_from_tail(drm_mm_t *mm, unsigned long size)
|
||||
{
|
||||
struct list_head *tail_node;
|
||||
drm_mm_node_t *entry;
|
||||
|
||||
tail_node = mm->ml_entry.prev;
|
||||
entry = list_entry(tail_node, drm_mm_node_t, ml_entry);
|
||||
if (!entry->free)
|
||||
return -ENOMEM;
|
||||
|
||||
if (entry->size <= size)
|
||||
return -ENOMEM;
|
||||
|
||||
entry->size -= size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int drm_mm_create_tail_node(drm_mm_t *mm,
|
||||
unsigned long start,
|
||||
unsigned long size)
|
||||
{
|
||||
drm_mm_node_t *child;
|
||||
|
||||
child = (drm_mm_node_t *)
|
||||
drm_alloc(sizeof(*child), DRM_MEM_MM);
|
||||
if (!child)
|
||||
return -ENOMEM;
|
||||
|
||||
child->free = 1;
|
||||
child->size = size;
|
||||
child->start = start;
|
||||
child->mm = mm;
|
||||
|
||||
list_add_tail(&child->ml_entry, &mm->ml_entry);
|
||||
list_add_tail(&child->fl_entry, &mm->fl_entry);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int drm_mm_add_space_to_tail(drm_mm_t *mm, unsigned long size)
|
||||
{
|
||||
struct list_head *tail_node;
|
||||
drm_mm_node_t *entry;
|
||||
|
||||
tail_node = mm->ml_entry.prev;
|
||||
entry = list_entry(tail_node, drm_mm_node_t, ml_entry);
|
||||
if (!entry->free) {
|
||||
return drm_mm_create_tail_node(mm, entry->start + entry->size, size);
|
||||
}
|
||||
entry->size += size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static drm_mm_node_t *drm_mm_split_at_start(drm_mm_node_t *parent,
|
||||
unsigned long size)
|
||||
{
|
||||
drm_mm_node_t *child;
|
||||
|
||||
child = (drm_mm_node_t *)
|
||||
drm_alloc(sizeof(*child), DRM_MEM_MM);
|
||||
if (!child)
|
||||
return NULL;
|
||||
|
||||
INIT_LIST_HEAD(&child->fl_entry);
|
||||
|
||||
child->free = 0;
|
||||
child->size = size;
|
||||
child->start = parent->start;
|
||||
child->mm = parent->mm;
|
||||
|
||||
list_add_tail(&child->ml_entry, &parent->ml_entry);
|
||||
INIT_LIST_HEAD(&child->fl_entry);
|
||||
|
||||
parent->size -= size;
|
||||
parent->start += size;
|
||||
return child;
|
||||
}
|
||||
|
||||
|
||||
|
||||
drm_mm_node_t *drm_mm_get_block(drm_mm_node_t * parent,
|
||||
unsigned long size, unsigned alignment)
|
||||
{
|
||||
|
||||
drm_mm_node_t *align_splitoff = NULL;
|
||||
drm_mm_node_t *child;
|
||||
unsigned tmp = 0;
|
||||
|
||||
if (alignment)
|
||||
tmp = parent->start % alignment;
|
||||
|
||||
if (tmp) {
|
||||
align_splitoff = drm_mm_split_at_start(parent, alignment - tmp);
|
||||
if (!align_splitoff)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (parent->size == size) {
|
||||
list_del_init(&parent->fl_entry);
|
||||
parent->free = 0;
|
||||
return parent;
|
||||
} else {
|
||||
child = drm_mm_split_at_start(parent, size);
|
||||
}
|
||||
|
||||
if (align_splitoff)
|
||||
drm_mm_put_block(align_splitoff);
|
||||
|
||||
return child;
|
||||
}
|
||||
|
||||
/*
|
||||
* Put a block. Merge with the previous and / or next block if they are free.
|
||||
* Otherwise add to the free stack.
|
||||
*/
|
||||
|
||||
void drm_mm_put_block(drm_mm_node_t * cur)
|
||||
{
|
||||
|
||||
drm_mm_t *mm = cur->mm;
|
||||
struct list_head *cur_head = &cur->ml_entry;
|
||||
struct list_head *root_head = &mm->ml_entry;
|
||||
drm_mm_node_t *prev_node = NULL;
|
||||
drm_mm_node_t *next_node;
|
||||
|
||||
int merged = 0;
|
||||
|
||||
if (cur_head->prev != root_head) {
|
||||
prev_node = list_entry(cur_head->prev, drm_mm_node_t, ml_entry);
|
||||
if (prev_node->free) {
|
||||
prev_node->size += cur->size;
|
||||
merged = 1;
|
||||
}
|
||||
}
|
||||
if (cur_head->next != root_head) {
|
||||
next_node = list_entry(cur_head->next, drm_mm_node_t, ml_entry);
|
||||
if (next_node->free) {
|
||||
if (merged) {
|
||||
prev_node->size += next_node->size;
|
||||
list_del(&next_node->ml_entry);
|
||||
list_del(&next_node->fl_entry);
|
||||
drm_free(next_node, sizeof(*next_node),
|
||||
DRM_MEM_MM);
|
||||
} else {
|
||||
next_node->size += cur->size;
|
||||
next_node->start = cur->start;
|
||||
merged = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!merged) {
|
||||
cur->free = 1;
|
||||
list_add(&cur->fl_entry, &mm->fl_entry);
|
||||
} else {
|
||||
list_del(&cur->ml_entry);
|
||||
drm_free(cur, sizeof(*cur), DRM_MEM_MM);
|
||||
}
|
||||
}
|
||||
|
||||
drm_mm_node_t *drm_mm_search_free(const drm_mm_t * mm,
|
||||
unsigned long size,
|
||||
unsigned alignment, int best_match)
|
||||
{
|
||||
struct list_head *list;
|
||||
const struct list_head *free_stack = &mm->fl_entry;
|
||||
drm_mm_node_t *entry;
|
||||
drm_mm_node_t *best;
|
||||
unsigned long best_size;
|
||||
unsigned wasted;
|
||||
|
||||
best = NULL;
|
||||
best_size = ~0UL;
|
||||
|
||||
list_for_each(list, free_stack) {
|
||||
entry = list_entry(list, drm_mm_node_t, fl_entry);
|
||||
wasted = 0;
|
||||
|
||||
if (entry->size < size)
|
||||
continue;
|
||||
|
||||
if (alignment) {
|
||||
register unsigned tmp = entry->start % alignment;
|
||||
if (tmp)
|
||||
wasted += alignment - tmp;
|
||||
}
|
||||
|
||||
|
||||
if (entry->size >= size + wasted) {
|
||||
if (!best_match)
|
||||
return entry;
|
||||
if (size < best_size) {
|
||||
best = entry;
|
||||
best_size = entry->size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return best;
|
||||
}
|
||||
|
||||
int drm_mm_clean(drm_mm_t * mm)
|
||||
{
|
||||
struct list_head *head = &mm->ml_entry;
|
||||
|
||||
return (head->next->next == head);
|
||||
}
|
||||
|
||||
int drm_mm_init(drm_mm_t * mm, unsigned long start, unsigned long size)
|
||||
{
|
||||
INIT_LIST_HEAD(&mm->ml_entry);
|
||||
INIT_LIST_HEAD(&mm->fl_entry);
|
||||
|
||||
return drm_mm_create_tail_node(mm, start, size);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(drm_mm_init);
|
||||
|
||||
void drm_mm_takedown(drm_mm_t * mm)
|
||||
{
|
||||
struct list_head *bnode = mm->fl_entry.next;
|
||||
drm_mm_node_t *entry;
|
||||
|
||||
entry = list_entry(bnode, drm_mm_node_t, fl_entry);
|
||||
|
||||
if (entry->ml_entry.next != &mm->ml_entry ||
|
||||
entry->fl_entry.next != &mm->fl_entry) {
|
||||
DRM_ERROR("Memory manager not clean. Delaying takedown\n");
|
||||
return;
|
||||
}
|
||||
|
||||
list_del(&entry->fl_entry);
|
||||
list_del(&entry->ml_entry);
|
||||
|
||||
drm_free(entry, sizeof(*entry), DRM_MEM_MM);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(drm_mm_takedown);
|
||||
147
drivers/char/drm/drm_os_linux.h
Normal file
147
drivers/char/drm/drm_os_linux.h
Normal file
@@ -0,0 +1,147 @@
|
||||
/**
|
||||
* \file drm_os_linux.h
|
||||
* OS abstraction macros.
|
||||
*/
|
||||
|
||||
#include <linux/interrupt.h> /* For task queue support */
|
||||
#include <linux/delay.h>
|
||||
|
||||
/** File pointer type */
|
||||
#define DRMFILE struct file *
|
||||
/** Ioctl arguments */
|
||||
#define DRM_IOCTL_ARGS struct inode *inode, struct file *filp, unsigned int cmd, unsigned long data
|
||||
#define DRM_ERR(d) -(d)
|
||||
/** Current process ID */
|
||||
#define DRM_CURRENTPID current->pid
|
||||
#define DRM_SUSER(p) capable(CAP_SYS_ADMIN)
|
||||
#define DRM_UDELAY(d) udelay(d)
|
||||
/** Read a byte from a MMIO region */
|
||||
#define DRM_READ8(map, offset) readb(((void __iomem *)(map)->handle) + (offset))
|
||||
/** Read a word from a MMIO region */
|
||||
#define DRM_READ16(map, offset) readw(((void __iomem *)(map)->handle) + (offset))
|
||||
/** Read a dword from a MMIO region */
|
||||
#define DRM_READ32(map, offset) readl(((void __iomem *)(map)->handle) + (offset))
|
||||
/** Write a byte into a MMIO region */
|
||||
#define DRM_WRITE8(map, offset, val) writeb(val, ((void __iomem *)(map)->handle) + (offset))
|
||||
/** Write a word into a MMIO region */
|
||||
#define DRM_WRITE16(map, offset, val) writew(val, ((void __iomem *)(map)->handle) + (offset))
|
||||
/** Write a dword into a MMIO region */
|
||||
#define DRM_WRITE32(map, offset, val) writel(val, ((void __iomem *)(map)->handle) + (offset))
|
||||
/** Read memory barrier */
|
||||
#define DRM_READMEMORYBARRIER() rmb()
|
||||
/** Write memory barrier */
|
||||
#define DRM_WRITEMEMORYBARRIER() wmb()
|
||||
/** Read/write memory barrier */
|
||||
#define DRM_MEMORYBARRIER() mb()
|
||||
/** DRM device local declaration */
|
||||
#define DRM_DEVICE drm_file_t *priv = filp->private_data; \
|
||||
drm_device_t *dev = priv->head->dev
|
||||
|
||||
/** IRQ handler arguments and return type and values */
|
||||
#define DRM_IRQ_ARGS int irq, void *arg
|
||||
|
||||
/** AGP types */
|
||||
#if __OS_HAS_AGP
|
||||
#define DRM_AGP_MEM struct agp_memory
|
||||
#define DRM_AGP_KERN struct agp_kern_info
|
||||
#else
|
||||
/* define some dummy types for non AGP supporting kernels */
|
||||
struct no_agp_kern {
|
||||
unsigned long aper_base;
|
||||
unsigned long aper_size;
|
||||
};
|
||||
#define DRM_AGP_MEM int
|
||||
#define DRM_AGP_KERN struct no_agp_kern
|
||||
#endif
|
||||
|
||||
#if !(__OS_HAS_MTRR)
|
||||
static __inline__ int mtrr_add(unsigned long base, unsigned long size,
|
||||
unsigned int type, char increment)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static __inline__ int mtrr_del(int reg, unsigned long base, unsigned long size)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
#define MTRR_TYPE_WRCOMB 1
|
||||
|
||||
#endif
|
||||
|
||||
/** Task queue handler arguments */
|
||||
#define DRM_TASKQUEUE_ARGS void *arg
|
||||
|
||||
/** For data going into the kernel through the ioctl argument */
|
||||
#define DRM_COPY_FROM_USER_IOCTL(arg1, arg2, arg3) \
|
||||
if ( copy_from_user(&arg1, arg2, arg3) ) \
|
||||
return -EFAULT
|
||||
/** For data going from the kernel through the ioctl argument */
|
||||
#define DRM_COPY_TO_USER_IOCTL(arg1, arg2, arg3) \
|
||||
if ( copy_to_user(arg1, &arg2, arg3) ) \
|
||||
return -EFAULT
|
||||
/** Other copying of data to kernel space */
|
||||
#define DRM_COPY_FROM_USER(arg1, arg2, arg3) \
|
||||
copy_from_user(arg1, arg2, arg3)
|
||||
/** Other copying of data from kernel space */
|
||||
#define DRM_COPY_TO_USER(arg1, arg2, arg3) \
|
||||
copy_to_user(arg1, arg2, arg3)
|
||||
/* Macros for copyfrom user, but checking readability only once */
|
||||
#define DRM_VERIFYAREA_READ( uaddr, size ) \
|
||||
(access_ok( VERIFY_READ, uaddr, size ) ? 0 : -EFAULT)
|
||||
#define DRM_COPY_FROM_USER_UNCHECKED(arg1, arg2, arg3) \
|
||||
__copy_from_user(arg1, arg2, arg3)
|
||||
#define DRM_COPY_TO_USER_UNCHECKED(arg1, arg2, arg3) \
|
||||
__copy_to_user(arg1, arg2, arg3)
|
||||
#define DRM_GET_USER_UNCHECKED(val, uaddr) \
|
||||
__get_user(val, uaddr)
|
||||
|
||||
#define DRM_GET_PRIV_WITH_RETURN(_priv, _filp) _priv = _filp->private_data
|
||||
|
||||
/**
|
||||
* Get the pointer to the SAREA.
|
||||
*
|
||||
* Searches the SAREA on the mapping lists and points drm_device::sarea to it.
|
||||
*/
|
||||
#define DRM_GETSAREA() \
|
||||
do { \
|
||||
drm_map_list_t *entry; \
|
||||
list_for_each_entry( entry, &dev->maplist->head, head ) { \
|
||||
if ( entry->map && \
|
||||
entry->map->type == _DRM_SHM && \
|
||||
(entry->map->flags & _DRM_CONTAINS_LOCK) ) { \
|
||||
dev_priv->sarea = entry->map; \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define DRM_HZ HZ
|
||||
|
||||
#define DRM_WAIT_ON( ret, queue, timeout, condition ) \
|
||||
do { \
|
||||
DECLARE_WAITQUEUE(entry, current); \
|
||||
unsigned long end = jiffies + (timeout); \
|
||||
add_wait_queue(&(queue), &entry); \
|
||||
\
|
||||
for (;;) { \
|
||||
__set_current_state(TASK_INTERRUPTIBLE); \
|
||||
if (condition) \
|
||||
break; \
|
||||
if (time_after_eq(jiffies, end)) { \
|
||||
ret = -EBUSY; \
|
||||
break; \
|
||||
} \
|
||||
schedule_timeout((HZ/100 > 1) ? HZ/100 : 1); \
|
||||
if (signal_pending(current)) { \
|
||||
ret = -EINTR; \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
__set_current_state(TASK_RUNNING); \
|
||||
remove_wait_queue(&(queue), &entry); \
|
||||
} while (0)
|
||||
|
||||
#define DRM_WAKEUP( queue ) wake_up_interruptible( queue )
|
||||
#define DRM_INIT_WAITQUEUE( queue ) init_waitqueue_head( queue )
|
||||
183
drivers/char/drm/drm_pci.c
Normal file
183
drivers/char/drm/drm_pci.c
Normal file
@@ -0,0 +1,183 @@
|
||||
/* drm_pci.h -- PCI DMA memory management wrappers for DRM -*- linux-c -*- */
|
||||
/**
|
||||
* \file drm_pci.c
|
||||
* \brief Functions and ioctls to manage PCI memory
|
||||
*
|
||||
* \warning These interfaces aren't stable yet.
|
||||
*
|
||||
* \todo Implement the remaining ioctl's for the PCI pools.
|
||||
* \todo The wrappers here are so thin that they would be better off inlined..
|
||||
*
|
||||
* \author Jose Fonseca <jrfonseca@tungstengraphics.com>
|
||||
* \author Leif Delgass <ldelgass@retinalburn.net>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2003 Jos<6F>Fonseca.
|
||||
* Copyright 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
|
||||
* AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <linux/pci.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include "drmP.h"
|
||||
|
||||
/**********************************************************************/
|
||||
/** \name PCI memory */
|
||||
/*@{*/
|
||||
|
||||
/**
|
||||
* \brief Allocate a PCI consistent memory block, for DMA.
|
||||
*/
|
||||
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;
|
||||
#if 1
|
||||
unsigned long addr;
|
||||
size_t sz;
|
||||
#endif
|
||||
#ifdef DRM_DEBUG_MEMORY
|
||||
int area = DRM_MEM_DMA;
|
||||
|
||||
spin_lock(&drm_mem_lock);
|
||||
if ((drm_ram_used >> PAGE_SHIFT)
|
||||
> (DRM_RAM_PERCENT * drm_ram_available) / 100) {
|
||||
spin_unlock(&drm_mem_lock);
|
||||
return 0;
|
||||
}
|
||||
spin_unlock(&drm_mem_lock);
|
||||
#endif
|
||||
|
||||
/* pci_alloc_consistent only guarantees alignment to the smallest
|
||||
* PAGE_SIZE order which is greater than or equal to the requested size.
|
||||
* Return NULL here for now to make sure nobody tries for larger alignment
|
||||
*/
|
||||
if (align > size)
|
||||
return NULL;
|
||||
|
||||
if (pci_set_dma_mask(dev->pdev, maxaddr) != 0) {
|
||||
DRM_ERROR("Setting pci dma mask failed\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dmah = kmalloc(sizeof(drm_dma_handle_t), GFP_KERNEL);
|
||||
if (!dmah)
|
||||
return NULL;
|
||||
|
||||
dmah->size = size;
|
||||
dmah->vaddr = dma_alloc_coherent(&dev->pdev->dev, size, &dmah->busaddr, GFP_KERNEL | __GFP_COMP);
|
||||
|
||||
#ifdef DRM_DEBUG_MEMORY
|
||||
if (dmah->vaddr == NULL) {
|
||||
spin_lock(&drm_mem_lock);
|
||||
++drm_mem_stats[area].fail_count;
|
||||
spin_unlock(&drm_mem_lock);
|
||||
kfree(dmah);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
spin_lock(&drm_mem_lock);
|
||||
++drm_mem_stats[area].succeed_count;
|
||||
drm_mem_stats[area].bytes_allocated += size;
|
||||
drm_ram_used += size;
|
||||
spin_unlock(&drm_mem_lock);
|
||||
#else
|
||||
if (dmah->vaddr == NULL) {
|
||||
kfree(dmah);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
memset(dmah->vaddr, 0, size);
|
||||
|
||||
/* XXX - Is virt_to_page() legal for consistent mem? */
|
||||
/* Reserve */
|
||||
for (addr = (unsigned long)dmah->vaddr, sz = size;
|
||||
sz > 0; addr += PAGE_SIZE, sz -= PAGE_SIZE) {
|
||||
SetPageReserved(virt_to_page(addr));
|
||||
}
|
||||
|
||||
return dmah;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(drm_pci_alloc);
|
||||
|
||||
/**
|
||||
* \brief Free a PCI consistent memory block without freeing its descriptor.
|
||||
*
|
||||
* This function is for internal use in the Linux-specific DRM core code.
|
||||
*/
|
||||
void __drm_pci_free(drm_device_t * dev, drm_dma_handle_t * dmah)
|
||||
{
|
||||
#if 1
|
||||
unsigned long addr;
|
||||
size_t sz;
|
||||
#endif
|
||||
#ifdef DRM_DEBUG_MEMORY
|
||||
int area = DRM_MEM_DMA;
|
||||
int alloc_count;
|
||||
int free_count;
|
||||
#endif
|
||||
|
||||
if (!dmah->vaddr) {
|
||||
#ifdef DRM_DEBUG_MEMORY
|
||||
DRM_MEM_ERROR(area, "Attempt to free address 0\n");
|
||||
#endif
|
||||
} else {
|
||||
/* XXX - Is virt_to_page() legal for consistent mem? */
|
||||
/* Unreserve */
|
||||
for (addr = (unsigned long)dmah->vaddr, sz = dmah->size;
|
||||
sz > 0; addr += PAGE_SIZE, sz -= PAGE_SIZE) {
|
||||
ClearPageReserved(virt_to_page(addr));
|
||||
}
|
||||
dma_free_coherent(&dev->pdev->dev, dmah->size, dmah->vaddr,
|
||||
dmah->busaddr);
|
||||
}
|
||||
|
||||
#ifdef DRM_DEBUG_MEMORY
|
||||
spin_lock(&drm_mem_lock);
|
||||
free_count = ++drm_mem_stats[area].free_count;
|
||||
alloc_count = drm_mem_stats[area].succeed_count;
|
||||
drm_mem_stats[area].bytes_freed += size;
|
||||
drm_ram_used -= size;
|
||||
spin_unlock(&drm_mem_lock);
|
||||
if (free_count > alloc_count) {
|
||||
DRM_MEM_ERROR(area,
|
||||
"Excess frees: %d frees, %d allocs\n",
|
||||
free_count, alloc_count);
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Free a PCI consistent memory block
|
||||
*/
|
||||
void drm_pci_free(drm_device_t * dev, drm_dma_handle_t * dmah)
|
||||
{
|
||||
__drm_pci_free(dev, dmah);
|
||||
kfree(dmah);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(drm_pci_free);
|
||||
|
||||
/*@}*/
|
||||
300
drivers/char/drm/drm_pciids.h
Normal file
300
drivers/char/drm/drm_pciids.h
Normal file
@@ -0,0 +1,300 @@
|
||||
/*
|
||||
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, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY}, \
|
||||
{0x1002, 0x3152, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x3154, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x3E50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x3E54, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x4136, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS100|RADEON_IS_IGP}, \
|
||||
{0x1002, 0x4137, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|RADEON_IS_IGP}, \
|
||||
{0x1002, 0x4144, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
|
||||
{0x1002, 0x4145, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
|
||||
{0x1002, 0x4146, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
|
||||
{0x1002, 0x4147, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
|
||||
{0x1002, 0x4148, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \
|
||||
{0x1002, 0x4149, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \
|
||||
{0x1002, 0x414A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \
|
||||
{0x1002, 0x414B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \
|
||||
{0x1002, 0x4150, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \
|
||||
{0x1002, 0x4151, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \
|
||||
{0x1002, 0x4152, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \
|
||||
{0x1002, 0x4153, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \
|
||||
{0x1002, 0x4154, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \
|
||||
{0x1002, 0x4155, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \
|
||||
{0x1002, 0x4156, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \
|
||||
{0x1002, 0x4237, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|RADEON_IS_IGP}, \
|
||||
{0x1002, 0x4242, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
|
||||
{0x1002, 0x4243, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
|
||||
{0x1002, 0x4336, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS100|RADEON_IS_IGP|RADEON_IS_MOBILITY}, \
|
||||
{0x1002, 0x4337, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|RADEON_IS_IGP|RADEON_IS_MOBILITY}, \
|
||||
{0x1002, 0x4437, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|RADEON_IS_IGP|RADEON_IS_MOBILITY}, \
|
||||
{0x1002, 0x4966, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250}, \
|
||||
{0x1002, 0x4967, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250}, \
|
||||
{0x1002, 0x4A48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x4A49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x4A4A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x4A4B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x4A4C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x4A4D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x4A4E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x4A4F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x4A50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x4A54, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x4B49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x4B4A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x4B4B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x4B4C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x4C57, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV200|RADEON_IS_MOBILITY}, \
|
||||
{0x1002, 0x4C58, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV200|RADEON_IS_MOBILITY}, \
|
||||
{0x1002, 0x4C59, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100|RADEON_IS_MOBILITY}, \
|
||||
{0x1002, 0x4C5A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100|RADEON_IS_MOBILITY}, \
|
||||
{0x1002, 0x4C64, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250|RADEON_IS_MOBILITY}, \
|
||||
{0x1002, 0x4C66, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250|RADEON_IS_MOBILITY}, \
|
||||
{0x1002, 0x4C67, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250|RADEON_IS_MOBILITY}, \
|
||||
{0x1002, 0x4E44, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
|
||||
{0x1002, 0x4E45, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
|
||||
{0x1002, 0x4E46, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
|
||||
{0x1002, 0x4E47, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
|
||||
{0x1002, 0x4E48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \
|
||||
{0x1002, 0x4E49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \
|
||||
{0x1002, 0x4E4A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \
|
||||
{0x1002, 0x4E4B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \
|
||||
{0x1002, 0x4E50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|RADEON_IS_MOBILITY}, \
|
||||
{0x1002, 0x4E51, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|RADEON_IS_MOBILITY}, \
|
||||
{0x1002, 0x4E52, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|RADEON_IS_MOBILITY}, \
|
||||
{0x1002, 0x4E53, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|RADEON_IS_MOBILITY}, \
|
||||
{0x1002, 0x4E54, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|RADEON_IS_MOBILITY}, \
|
||||
{0x1002, 0x4E56, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|RADEON_IS_MOBILITY}, \
|
||||
{0x1002, 0x5144, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|RADEON_SINGLE_CRTC}, \
|
||||
{0x1002, 0x5145, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|RADEON_SINGLE_CRTC}, \
|
||||
{0x1002, 0x5146, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|RADEON_SINGLE_CRTC}, \
|
||||
{0x1002, 0x5147, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|RADEON_SINGLE_CRTC}, \
|
||||
{0x1002, 0x5148, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
|
||||
{0x1002, 0x514C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
|
||||
{0x1002, 0x514D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
|
||||
{0x1002, 0x5157, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV200}, \
|
||||
{0x1002, 0x5158, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV200}, \
|
||||
{0x1002, 0x5159, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100}, \
|
||||
{0x1002, 0x515A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100}, \
|
||||
{0x1002, 0x515E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100}, \
|
||||
{0x1002, 0x5460, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY}, \
|
||||
{0x1002, 0x5462, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY}, \
|
||||
{0x1002, 0x5464, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY}, \
|
||||
{0x1002, 0x5548, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5549, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x554A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x554B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x554C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x554D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x554E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x554F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5550, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5551, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5552, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5554, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x564A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x564B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x564F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5652, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5653, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5834, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|RADEON_IS_IGP}, \
|
||||
{0x1002, 0x5835, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|RADEON_IS_IGP|RADEON_IS_MOBILITY}, \
|
||||
{0x1002, 0x5960, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
|
||||
{0x1002, 0x5961, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
|
||||
{0x1002, 0x5962, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
|
||||
{0x1002, 0x5964, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
|
||||
{0x1002, 0x5965, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
|
||||
{0x1002, 0x5969, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100}, \
|
||||
{0x1002, 0x5b60, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5b62, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5b63, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5b64, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5b65, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5c61, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280|RADEON_IS_MOBILITY}, \
|
||||
{0x1002, 0x5c63, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280|RADEON_IS_MOBILITY}, \
|
||||
{0x1002, 0x5d48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5d49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5d4a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5d4c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5d4d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5d4e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5d4f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5d50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5d52, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5d57, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5e48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5e4a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5e4b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5e4c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5e4d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x5e4f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x7834, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|RADEON_IS_IGP|RADEON_NEW_MEMMAP}, \
|
||||
{0x1002, 0x7835, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
|
||||
{0, 0, 0}
|
||||
|
||||
#define r128_PCI_IDS \
|
||||
{0x1002, 0x4c45, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x1002, 0x4c46, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x1002, 0x4d46, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x1002, 0x4d4c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x1002, 0x5041, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x1002, 0x5042, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x1002, 0x5043, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x1002, 0x5044, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x1002, 0x5045, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x1002, 0x5046, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x1002, 0x5047, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x1002, 0x5048, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x1002, 0x5049, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x1002, 0x504A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x1002, 0x504B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x1002, 0x504C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x1002, 0x504D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x1002, 0x504E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x1002, 0x504F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x1002, 0x5050, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x1002, 0x5051, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x1002, 0x5052, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x1002, 0x5053, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x1002, 0x5054, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x1002, 0x5055, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x1002, 0x5056, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x1002, 0x5057, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x1002, 0x5058, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x1002, 0x5245, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x1002, 0x5246, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x1002, 0x5247, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x1002, 0x524b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x1002, 0x524c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x1002, 0x534d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x1002, 0x5446, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x1002, 0x544C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x1002, 0x5452, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0, 0, 0}
|
||||
|
||||
#define mga_PCI_IDS \
|
||||
{0x102b, 0x0520, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MGA_CARD_TYPE_G200}, \
|
||||
{0x102b, 0x0521, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MGA_CARD_TYPE_G200}, \
|
||||
{0x102b, 0x0525, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MGA_CARD_TYPE_G400}, \
|
||||
{0x102b, 0x2527, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MGA_CARD_TYPE_G550}, \
|
||||
{0, 0, 0}
|
||||
|
||||
#define mach64_PCI_IDS \
|
||||
{0x1002, 0x4749, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x1002, 0x4750, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x1002, 0x4751, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x1002, 0x4742, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x1002, 0x4744, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x1002, 0x4c49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x1002, 0x4c50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x1002, 0x4c51, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x1002, 0x4c42, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x1002, 0x4c44, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x1002, 0x474c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x1002, 0x474f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x1002, 0x4752, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x1002, 0x4753, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x1002, 0x474d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x1002, 0x474e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x1002, 0x4c52, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x1002, 0x4c53, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x1002, 0x4c4d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x1002, 0x4c4e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0, 0, 0}
|
||||
|
||||
#define sisdrv_PCI_IDS \
|
||||
{0x1039, 0x0300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x1039, 0x5300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x1039, 0x6300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x1039, 0x6330, PCI_ANY_ID, PCI_ANY_ID, 0, 0, SIS_CHIP_315}, \
|
||||
{0x1039, 0x7300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0, 0, 0}
|
||||
|
||||
#define tdfx_PCI_IDS \
|
||||
{0x121a, 0x0003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x121a, 0x0004, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x121a, 0x0005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x121a, 0x0007, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x121a, 0x0009, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x121a, 0x000b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0, 0, 0}
|
||||
|
||||
#define viadrv_PCI_IDS \
|
||||
{0x1106, 0x3022, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x1106, 0x3118, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VIA_PRO_GROUP_A}, \
|
||||
{0x1106, 0x3122, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x1106, 0x7204, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x1106, 0x7205, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x1106, 0x3108, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x1106, 0x3304, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x1106, 0x3157, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x1106, 0x3344, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x1106, 0x3343, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x1106, 0x3230, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VIA_DX9_0}, \
|
||||
{0, 0, 0}
|
||||
|
||||
#define i810_PCI_IDS \
|
||||
{0x8086, 0x7121, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x8086, 0x7123, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x8086, 0x7125, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x8086, 0x1132, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0, 0, 0}
|
||||
|
||||
#define i830_PCI_IDS \
|
||||
{0x8086, 0x3577, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x8086, 0x2562, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x8086, 0x3582, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x8086, 0x2572, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0, 0, 0}
|
||||
|
||||
#define gamma_PCI_IDS \
|
||||
{0x3d3d, 0x0008, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0, 0, 0}
|
||||
|
||||
#define savage_PCI_IDS \
|
||||
{0x5333, 0x8a20, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_SAVAGE3D}, \
|
||||
{0x5333, 0x8a21, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_SAVAGE3D}, \
|
||||
{0x5333, 0x8a22, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_SAVAGE4}, \
|
||||
{0x5333, 0x8a23, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_SAVAGE4}, \
|
||||
{0x5333, 0x8c10, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_SAVAGE_MX}, \
|
||||
{0x5333, 0x8c11, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_SAVAGE_MX}, \
|
||||
{0x5333, 0x8c12, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_SAVAGE_MX}, \
|
||||
{0x5333, 0x8c13, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_SAVAGE_MX}, \
|
||||
{0x5333, 0x8c22, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_SUPERSAVAGE}, \
|
||||
{0x5333, 0x8c24, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_SUPERSAVAGE}, \
|
||||
{0x5333, 0x8c26, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_SUPERSAVAGE}, \
|
||||
{0x5333, 0x8c2a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_SUPERSAVAGE}, \
|
||||
{0x5333, 0x8c2b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_SUPERSAVAGE}, \
|
||||
{0x5333, 0x8c2c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_SUPERSAVAGE}, \
|
||||
{0x5333, 0x8c2d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_SUPERSAVAGE}, \
|
||||
{0x5333, 0x8c2e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_SUPERSAVAGE}, \
|
||||
{0x5333, 0x8c2f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_SUPERSAVAGE}, \
|
||||
{0x5333, 0x8a25, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_PROSAVAGE}, \
|
||||
{0x5333, 0x8a26, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_PROSAVAGE}, \
|
||||
{0x5333, 0x8d01, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_TWISTER}, \
|
||||
{0x5333, 0x8d02, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_TWISTER}, \
|
||||
{0x5333, 0x8d03, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_PROSAVAGEDDR}, \
|
||||
{0x5333, 0x8d04, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_PROSAVAGEDDR}, \
|
||||
{0, 0, 0}
|
||||
|
||||
#define ffb_PCI_IDS \
|
||||
{0, 0, 0}
|
||||
|
||||
#define i915_PCI_IDS \
|
||||
{0x8086, 0x3577, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x8086, 0x2562, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x8086, 0x3582, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x8086, 0x2572, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x8086, 0x2582, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x8086, 0x2592, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x8086, 0x2772, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x8086, 0x27a2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x8086, 0x2972, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x8086, 0x2982, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x8086, 0x2992, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0x8086, 0x29a2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
|
||||
{0, 0, 0}
|
||||
|
||||
548
drivers/char/drm/drm_proc.c
Normal file
548
drivers/char/drm/drm_proc.c
Normal file
@@ -0,0 +1,548 @@
|
||||
/**
|
||||
* \file drm_proc.c
|
||||
* /proc support for DRM
|
||||
*
|
||||
* \author Rickard E. (Rik) Faith <faith@valinux.com>
|
||||
* \author Gareth Hughes <gareth@valinux.com>
|
||||
*
|
||||
* \par Acknowledgements:
|
||||
* Matthew J Sottek <matthew.j.sottek@intel.com> sent in a patch to fix
|
||||
* the problem with the proc files not outputting all their information.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Created: Mon Jan 11 09:48:47 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.
|
||||
*/
|
||||
|
||||
#include "drmP.h"
|
||||
|
||||
static int drm_name_info(char *buf, char **start, off_t offset,
|
||||
int request, int *eof, void *data);
|
||||
static int drm_vm_info(char *buf, char **start, off_t offset,
|
||||
int request, int *eof, void *data);
|
||||
static int drm_clients_info(char *buf, char **start, off_t offset,
|
||||
int request, int *eof, void *data);
|
||||
static int drm_queues_info(char *buf, char **start, off_t offset,
|
||||
int request, int *eof, void *data);
|
||||
static int drm_bufs_info(char *buf, char **start, off_t offset,
|
||||
int request, int *eof, void *data);
|
||||
#if DRM_DEBUG_CODE
|
||||
static int drm_vma_info(char *buf, char **start, off_t offset,
|
||||
int request, int *eof, void *data);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Proc file list.
|
||||
*/
|
||||
static struct drm_proc_list {
|
||||
const char *name; /**< file name */
|
||||
int (*f) (char *, char **, off_t, int, int *, void *); /**< proc callback*/
|
||||
} drm_proc_list[] = {
|
||||
{"name", drm_name_info},
|
||||
{"mem", drm_mem_info},
|
||||
{"vm", drm_vm_info},
|
||||
{"clients", drm_clients_info},
|
||||
{"queues", drm_queues_info},
|
||||
{"bufs", drm_bufs_info},
|
||||
#if DRM_DEBUG_CODE
|
||||
{"vma", drm_vma_info},
|
||||
#endif
|
||||
};
|
||||
|
||||
#define DRM_PROC_ENTRIES (sizeof(drm_proc_list)/sizeof(drm_proc_list[0]))
|
||||
|
||||
/**
|
||||
* Initialize the DRI proc filesystem for a device.
|
||||
*
|
||||
* \param dev DRM device.
|
||||
* \param minor device minor number.
|
||||
* \param root DRI proc dir entry.
|
||||
* \param dev_root resulting DRI device proc dir entry.
|
||||
* \return root entry pointer on success, or NULL on failure.
|
||||
*
|
||||
* Create the DRI proc root entry "/proc/dri", the device proc root entry
|
||||
* "/proc/dri/%minor%/", and each entry in proc_list as
|
||||
* "/proc/dri/%minor%/%name%".
|
||||
*/
|
||||
int drm_proc_init(drm_device_t * dev, int minor,
|
||||
struct proc_dir_entry *root, struct proc_dir_entry **dev_root)
|
||||
{
|
||||
struct proc_dir_entry *ent;
|
||||
int i, j;
|
||||
char name[64];
|
||||
|
||||
sprintf(name, "%d", minor);
|
||||
*dev_root = proc_mkdir(name, root);
|
||||
if (!*dev_root) {
|
||||
DRM_ERROR("Cannot create /proc/dri/%s\n", name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < DRM_PROC_ENTRIES; i++) {
|
||||
ent = create_proc_entry(drm_proc_list[i].name,
|
||||
S_IFREG | S_IRUGO, *dev_root);
|
||||
if (!ent) {
|
||||
DRM_ERROR("Cannot create /proc/dri/%s/%s\n",
|
||||
name, drm_proc_list[i].name);
|
||||
for (j = 0; j < i; j++)
|
||||
remove_proc_entry(drm_proc_list[i].name,
|
||||
*dev_root);
|
||||
remove_proc_entry(name, root);
|
||||
return -1;
|
||||
}
|
||||
ent->read_proc = drm_proc_list[i].f;
|
||||
ent->data = dev;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleanup the proc filesystem resources.
|
||||
*
|
||||
* \param minor device minor number.
|
||||
* \param root DRI proc dir entry.
|
||||
* \param dev_root DRI device proc dir entry.
|
||||
* \return always zero.
|
||||
*
|
||||
* Remove all proc entries created by proc_init().
|
||||
*/
|
||||
int drm_proc_cleanup(int minor, struct proc_dir_entry *root,
|
||||
struct proc_dir_entry *dev_root)
|
||||
{
|
||||
int i;
|
||||
char name[64];
|
||||
|
||||
if (!root || !dev_root)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < DRM_PROC_ENTRIES; i++)
|
||||
remove_proc_entry(drm_proc_list[i].name, dev_root);
|
||||
sprintf(name, "%d", minor);
|
||||
remove_proc_entry(name, root);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when "/proc/dri/.../name" is read.
|
||||
*
|
||||
* \param buf output buffer.
|
||||
* \param start start of output data.
|
||||
* \param offset requested start offset.
|
||||
* \param request requested number of bytes.
|
||||
* \param eof whether there is no more data to return.
|
||||
* \param data private data.
|
||||
* \return number of written bytes.
|
||||
*
|
||||
* Prints the device name together with the bus id if available.
|
||||
*/
|
||||
static int drm_name_info(char *buf, char **start, off_t offset, int request,
|
||||
int *eof, void *data)
|
||||
{
|
||||
drm_device_t *dev = (drm_device_t *) data;
|
||||
int len = 0;
|
||||
|
||||
if (offset > DRM_PROC_LIMIT) {
|
||||
*eof = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
*start = &buf[offset];
|
||||
*eof = 0;
|
||||
|
||||
if (dev->unique) {
|
||||
DRM_PROC_PRINT("%s %s %s\n",
|
||||
dev->driver->pci_driver.name,
|
||||
pci_name(dev->pdev), dev->unique);
|
||||
} else {
|
||||
DRM_PROC_PRINT("%s %s\n", dev->driver->pci_driver.name,
|
||||
pci_name(dev->pdev));
|
||||
}
|
||||
|
||||
if (len > request + offset)
|
||||
return request;
|
||||
*eof = 1;
|
||||
return len - offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when "/proc/dri/.../vm" is read.
|
||||
*
|
||||
* \param buf output buffer.
|
||||
* \param start start of output data.
|
||||
* \param offset requested start offset.
|
||||
* \param request requested number of bytes.
|
||||
* \param eof whether there is no more data to return.
|
||||
* \param data private data.
|
||||
* \return number of written bytes.
|
||||
*
|
||||
* Prints information about all mappings in drm_device::maplist.
|
||||
*/
|
||||
static int drm__vm_info(char *buf, char **start, off_t offset, int request,
|
||||
int *eof, void *data)
|
||||
{
|
||||
drm_device_t *dev = (drm_device_t *) data;
|
||||
int len = 0;
|
||||
drm_map_t *map;
|
||||
drm_map_list_t *r_list;
|
||||
struct list_head *list;
|
||||
|
||||
/* Hardcoded from _DRM_FRAME_BUFFER,
|
||||
_DRM_REGISTERS, _DRM_SHM, _DRM_AGP, and
|
||||
_DRM_SCATTER_GATHER and _DRM_CONSISTENT */
|
||||
const char *types[] = { "FB", "REG", "SHM", "AGP", "SG", "PCI" };
|
||||
const char *type;
|
||||
int i;
|
||||
|
||||
if (offset > DRM_PROC_LIMIT) {
|
||||
*eof = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
*start = &buf[offset];
|
||||
*eof = 0;
|
||||
|
||||
DRM_PROC_PRINT("slot offset size type flags "
|
||||
"address mtrr\n\n");
|
||||
i = 0;
|
||||
if (dev->maplist != NULL)
|
||||
list_for_each(list, &dev->maplist->head) {
|
||||
r_list = list_entry(list, drm_map_list_t, head);
|
||||
map = r_list->map;
|
||||
if (!map)
|
||||
continue;
|
||||
if (map->type < 0 || map->type > 5)
|
||||
type = "??";
|
||||
else
|
||||
type = types[map->type];
|
||||
DRM_PROC_PRINT("%4d 0x%08lx 0x%08lx %4.4s 0x%02x 0x%08x ",
|
||||
i,
|
||||
map->offset,
|
||||
map->size, type, map->flags, r_list->user_token);
|
||||
if (map->mtrr < 0) {
|
||||
DRM_PROC_PRINT("none\n");
|
||||
} else {
|
||||
DRM_PROC_PRINT("%4d\n", map->mtrr);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
if (len > request + offset)
|
||||
return request;
|
||||
*eof = 1;
|
||||
return len - offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simply calls _vm_info() while holding the drm_device::struct_mutex lock.
|
||||
*/
|
||||
static int drm_vm_info(char *buf, char **start, off_t offset, int request,
|
||||
int *eof, void *data)
|
||||
{
|
||||
drm_device_t *dev = (drm_device_t *) data;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
ret = drm__vm_info(buf, start, offset, request, eof, data);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when "/proc/dri/.../queues" is read.
|
||||
*
|
||||
* \param buf output buffer.
|
||||
* \param start start of output data.
|
||||
* \param offset requested start offset.
|
||||
* \param request requested number of bytes.
|
||||
* \param eof whether there is no more data to return.
|
||||
* \param data private data.
|
||||
* \return number of written bytes.
|
||||
*/
|
||||
static int drm__queues_info(char *buf, char **start, off_t offset,
|
||||
int request, int *eof, void *data)
|
||||
{
|
||||
drm_device_t *dev = (drm_device_t *) data;
|
||||
int len = 0;
|
||||
int i;
|
||||
drm_queue_t *q;
|
||||
|
||||
if (offset > DRM_PROC_LIMIT) {
|
||||
*eof = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
*start = &buf[offset];
|
||||
*eof = 0;
|
||||
|
||||
DRM_PROC_PRINT(" ctx/flags use fin"
|
||||
" blk/rw/rwf wait flushed queued"
|
||||
" locks\n\n");
|
||||
for (i = 0; i < dev->queue_count; i++) {
|
||||
q = dev->queuelist[i];
|
||||
atomic_inc(&q->use_count);
|
||||
DRM_PROC_PRINT_RET(atomic_dec(&q->use_count),
|
||||
"%5d/0x%03x %5d %5d"
|
||||
" %5d/%c%c/%c%c%c %5Zd\n",
|
||||
i,
|
||||
q->flags,
|
||||
atomic_read(&q->use_count),
|
||||
atomic_read(&q->finalization),
|
||||
atomic_read(&q->block_count),
|
||||
atomic_read(&q->block_read) ? 'r' : '-',
|
||||
atomic_read(&q->block_write) ? 'w' : '-',
|
||||
waitqueue_active(&q->read_queue) ? 'r' : '-',
|
||||
waitqueue_active(&q->
|
||||
write_queue) ? 'w' : '-',
|
||||
waitqueue_active(&q->
|
||||
flush_queue) ? 'f' : '-',
|
||||
DRM_BUFCOUNT(&q->waitlist));
|
||||
atomic_dec(&q->use_count);
|
||||
}
|
||||
|
||||
if (len > request + offset)
|
||||
return request;
|
||||
*eof = 1;
|
||||
return len - offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simply calls _queues_info() while holding the drm_device::struct_mutex lock.
|
||||
*/
|
||||
static int drm_queues_info(char *buf, char **start, off_t offset, int request,
|
||||
int *eof, void *data)
|
||||
{
|
||||
drm_device_t *dev = (drm_device_t *) data;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
ret = drm__queues_info(buf, start, offset, request, eof, data);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when "/proc/dri/.../bufs" is read.
|
||||
*
|
||||
* \param buf output buffer.
|
||||
* \param start start of output data.
|
||||
* \param offset requested start offset.
|
||||
* \param request requested number of bytes.
|
||||
* \param eof whether there is no more data to return.
|
||||
* \param data private data.
|
||||
* \return number of written bytes.
|
||||
*/
|
||||
static int drm__bufs_info(char *buf, char **start, off_t offset, int request,
|
||||
int *eof, void *data)
|
||||
{
|
||||
drm_device_t *dev = (drm_device_t *) data;
|
||||
int len = 0;
|
||||
drm_device_dma_t *dma = dev->dma;
|
||||
int i;
|
||||
|
||||
if (!dma || offset > DRM_PROC_LIMIT) {
|
||||
*eof = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
*start = &buf[offset];
|
||||
*eof = 0;
|
||||
|
||||
DRM_PROC_PRINT(" o size count free segs pages kB\n\n");
|
||||
for (i = 0; i <= DRM_MAX_ORDER; i++) {
|
||||
if (dma->bufs[i].buf_count)
|
||||
DRM_PROC_PRINT("%2d %8d %5d %5d %5d %5d %5ld\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_PROC_PRINT("\n");
|
||||
for (i = 0; i < dma->buf_count; i++) {
|
||||
if (i && !(i % 32))
|
||||
DRM_PROC_PRINT("\n");
|
||||
DRM_PROC_PRINT(" %d", dma->buflist[i]->list);
|
||||
}
|
||||
DRM_PROC_PRINT("\n");
|
||||
|
||||
if (len > request + offset)
|
||||
return request;
|
||||
*eof = 1;
|
||||
return len - offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simply calls _bufs_info() while holding the drm_device::struct_mutex lock.
|
||||
*/
|
||||
static int drm_bufs_info(char *buf, char **start, off_t offset, int request,
|
||||
int *eof, void *data)
|
||||
{
|
||||
drm_device_t *dev = (drm_device_t *) data;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
ret = drm__bufs_info(buf, start, offset, request, eof, data);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when "/proc/dri/.../clients" is read.
|
||||
*
|
||||
* \param buf output buffer.
|
||||
* \param start start of output data.
|
||||
* \param offset requested start offset.
|
||||
* \param request requested number of bytes.
|
||||
* \param eof whether there is no more data to return.
|
||||
* \param data private data.
|
||||
* \return number of written bytes.
|
||||
*/
|
||||
static int drm__clients_info(char *buf, char **start, off_t offset,
|
||||
int request, int *eof, void *data)
|
||||
{
|
||||
drm_device_t *dev = (drm_device_t *) data;
|
||||
int len = 0;
|
||||
drm_file_t *priv;
|
||||
|
||||
if (offset > DRM_PROC_LIMIT) {
|
||||
*eof = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
*start = &buf[offset];
|
||||
*eof = 0;
|
||||
|
||||
DRM_PROC_PRINT("a dev pid uid magic ioctls\n\n");
|
||||
for (priv = dev->file_first; priv; priv = priv->next) {
|
||||
DRM_PROC_PRINT("%c %3d %5d %5d %10u %10lu\n",
|
||||
priv->authenticated ? 'y' : 'n',
|
||||
priv->minor,
|
||||
priv->pid,
|
||||
priv->uid, priv->magic, priv->ioctl_count);
|
||||
}
|
||||
|
||||
if (len > request + offset)
|
||||
return request;
|
||||
*eof = 1;
|
||||
return len - offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simply calls _clients_info() while holding the drm_device::struct_mutex lock.
|
||||
*/
|
||||
static int drm_clients_info(char *buf, char **start, off_t offset,
|
||||
int request, int *eof, void *data)
|
||||
{
|
||||
drm_device_t *dev = (drm_device_t *) data;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
ret = drm__clients_info(buf, start, offset, request, eof, data);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if DRM_DEBUG_CODE
|
||||
|
||||
static int drm__vma_info(char *buf, char **start, off_t offset, int request,
|
||||
int *eof, void *data)
|
||||
{
|
||||
drm_device_t *dev = (drm_device_t *) data;
|
||||
int len = 0;
|
||||
drm_vma_entry_t *pt;
|
||||
struct vm_area_struct *vma;
|
||||
#if defined(__i386__)
|
||||
unsigned int pgprot;
|
||||
#endif
|
||||
|
||||
if (offset > DRM_PROC_LIMIT) {
|
||||
*eof = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
*start = &buf[offset];
|
||||
*eof = 0;
|
||||
|
||||
DRM_PROC_PRINT("vma use count: %d, high_memory = %p, 0x%08lx\n",
|
||||
atomic_read(&dev->vma_count),
|
||||
high_memory, virt_to_phys(high_memory));
|
||||
for (pt = dev->vmalist; pt; pt = pt->next) {
|
||||
if (!(vma = pt->vma))
|
||||
continue;
|
||||
DRM_PROC_PRINT("\n%5d 0x%08lx-0x%08lx %c%c%c%c%c%c 0x%08lx000",
|
||||
pt->pid,
|
||||
vma->vm_start,
|
||||
vma->vm_end,
|
||||
vma->vm_flags & VM_READ ? 'r' : '-',
|
||||
vma->vm_flags & VM_WRITE ? 'w' : '-',
|
||||
vma->vm_flags & VM_EXEC ? 'x' : '-',
|
||||
vma->vm_flags & VM_MAYSHARE ? 's' : 'p',
|
||||
vma->vm_flags & VM_LOCKED ? 'l' : '-',
|
||||
vma->vm_flags & VM_IO ? 'i' : '-',
|
||||
vma->vm_pgoff);
|
||||
|
||||
#if defined(__i386__)
|
||||
pgprot = pgprot_val(vma->vm_page_prot);
|
||||
DRM_PROC_PRINT(" %c%c%c%c%c%c%c%c%c",
|
||||
pgprot & _PAGE_PRESENT ? 'p' : '-',
|
||||
pgprot & _PAGE_RW ? 'w' : 'r',
|
||||
pgprot & _PAGE_USER ? 'u' : 's',
|
||||
pgprot & _PAGE_PWT ? 't' : 'b',
|
||||
pgprot & _PAGE_PCD ? 'u' : 'c',
|
||||
pgprot & _PAGE_ACCESSED ? 'a' : '-',
|
||||
pgprot & _PAGE_DIRTY ? 'd' : '-',
|
||||
pgprot & _PAGE_PSE ? 'm' : 'k',
|
||||
pgprot & _PAGE_GLOBAL ? 'g' : 'l');
|
||||
#endif
|
||||
DRM_PROC_PRINT("\n");
|
||||
}
|
||||
|
||||
if (len > request + offset)
|
||||
return request;
|
||||
*eof = 1;
|
||||
return len - offset;
|
||||
}
|
||||
|
||||
static int drm_vma_info(char *buf, char **start, off_t offset, int request,
|
||||
int *eof, void *data)
|
||||
{
|
||||
drm_device_t *dev = (drm_device_t *) data;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
ret = drm__vma_info(buf, start, offset, request, eof, data);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
78
drivers/char/drm/drm_sarea.h
Normal file
78
drivers/char/drm/drm_sarea.h
Normal file
@@ -0,0 +1,78 @@
|
||||
/**
|
||||
* \file drm_sarea.h
|
||||
* \brief SAREA definitions
|
||||
*
|
||||
* \author Michel Dänzer <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.
|
||||
*/
|
||||
|
||||
#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_ */
|
||||
228
drivers/char/drm/drm_scatter.c
Normal file
228
drivers/char/drm/drm_scatter.c
Normal file
@@ -0,0 +1,228 @@
|
||||
/**
|
||||
* \file drm_scatter.c
|
||||
* IOCTLs to manage scatter/gather memory
|
||||
*
|
||||
* \author Gareth Hughes <gareth@valinux.com>
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <linux/vmalloc.h>
|
||||
#include "drmP.h"
|
||||
|
||||
#define DEBUG_SCATTER 0
|
||||
|
||||
void drm_sg_cleanup(drm_sg_mem_t * entry)
|
||||
{
|
||||
struct page *page;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < entry->pages; i++) {
|
||||
page = entry->pagelist[i];
|
||||
if (page)
|
||||
ClearPageReserved(page);
|
||||
}
|
||||
|
||||
vfree(entry->virtual);
|
||||
|
||||
drm_free(entry->busaddr,
|
||||
entry->pages * sizeof(*entry->busaddr), DRM_MEM_PAGES);
|
||||
drm_free(entry->pagelist,
|
||||
entry->pages * sizeof(*entry->pagelist), DRM_MEM_PAGES);
|
||||
drm_free(entry, sizeof(*entry), DRM_MEM_SGLISTS);
|
||||
}
|
||||
|
||||
#ifdef _LP64
|
||||
# define ScatterHandle(x) (unsigned int)((x >> 32) + (x & ((1L << 32) - 1)))
|
||||
#else
|
||||
# define ScatterHandle(x) (unsigned int)(x)
|
||||
#endif
|
||||
|
||||
int drm_sg_alloc(struct inode *inode, struct file *filp,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
drm_file_t *priv = filp->private_data;
|
||||
drm_device_t *dev = priv->head->dev;
|
||||
drm_scatter_gather_t __user *argp = (void __user *)arg;
|
||||
drm_scatter_gather_t request;
|
||||
drm_sg_mem_t *entry;
|
||||
unsigned long pages, i, j;
|
||||
|
||||
DRM_DEBUG("%s\n", __FUNCTION__);
|
||||
|
||||
if (!drm_core_check_feature(dev, DRIVER_SG))
|
||||
return -EINVAL;
|
||||
|
||||
if (dev->sg)
|
||||
return -EINVAL;
|
||||
|
||||
if (copy_from_user(&request, argp, sizeof(request)))
|
||||
return -EFAULT;
|
||||
|
||||
entry = drm_alloc(sizeof(*entry), DRM_MEM_SGLISTS);
|
||||
if (!entry)
|
||||
return -ENOMEM;
|
||||
|
||||
memset(entry, 0, sizeof(*entry));
|
||||
|
||||
pages = (request.size + PAGE_SIZE - 1) / PAGE_SIZE;
|
||||
DRM_DEBUG("sg size=%ld pages=%ld\n", request.size, pages);
|
||||
|
||||
entry->pages = pages;
|
||||
entry->pagelist = drm_alloc(pages * sizeof(*entry->pagelist),
|
||||
DRM_MEM_PAGES);
|
||||
if (!entry->pagelist) {
|
||||
drm_free(entry, sizeof(*entry), DRM_MEM_SGLISTS);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
memset(entry->pagelist, 0, pages * sizeof(*entry->pagelist));
|
||||
|
||||
entry->busaddr = drm_alloc(pages * sizeof(*entry->busaddr),
|
||||
DRM_MEM_PAGES);
|
||||
if (!entry->busaddr) {
|
||||
drm_free(entry->pagelist,
|
||||
entry->pages * sizeof(*entry->pagelist),
|
||||
DRM_MEM_PAGES);
|
||||
drm_free(entry, sizeof(*entry), DRM_MEM_SGLISTS);
|
||||
return -ENOMEM;
|
||||
}
|
||||
memset((void *)entry->busaddr, 0, pages * sizeof(*entry->busaddr));
|
||||
|
||||
entry->virtual = vmalloc_32(pages << PAGE_SHIFT);
|
||||
if (!entry->virtual) {
|
||||
drm_free(entry->busaddr,
|
||||
entry->pages * sizeof(*entry->busaddr), DRM_MEM_PAGES);
|
||||
drm_free(entry->pagelist,
|
||||
entry->pages * sizeof(*entry->pagelist),
|
||||
DRM_MEM_PAGES);
|
||||
drm_free(entry, sizeof(*entry), DRM_MEM_SGLISTS);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* This also forces the mapping of COW pages, so our page list
|
||||
* will be valid. Please don't remove it...
|
||||
*/
|
||||
memset(entry->virtual, 0, pages << PAGE_SHIFT);
|
||||
|
||||
entry->handle = ScatterHandle((unsigned long)entry->virtual);
|
||||
|
||||
DRM_DEBUG("sg alloc handle = %08lx\n", entry->handle);
|
||||
DRM_DEBUG("sg alloc virtual = %p\n", entry->virtual);
|
||||
|
||||
for (i = (unsigned long)entry->virtual, j = 0; j < pages;
|
||||
i += PAGE_SIZE, j++) {
|
||||
entry->pagelist[j] = vmalloc_to_page((void *)i);
|
||||
if (!entry->pagelist[j])
|
||||
goto failed;
|
||||
SetPageReserved(entry->pagelist[j]);
|
||||
}
|
||||
|
||||
request.handle = entry->handle;
|
||||
|
||||
if (copy_to_user(argp, &request, sizeof(request))) {
|
||||
drm_sg_cleanup(entry);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
dev->sg = entry;
|
||||
|
||||
#if DEBUG_SCATTER
|
||||
/* Verify that each page points to its virtual address, and vice
|
||||
* versa.
|
||||
*/
|
||||
{
|
||||
int error = 0;
|
||||
|
||||
for (i = 0; i < pages; i++) {
|
||||
unsigned long *tmp;
|
||||
|
||||
tmp = page_address(entry->pagelist[i]);
|
||||
for (j = 0;
|
||||
j < PAGE_SIZE / sizeof(unsigned long);
|
||||
j++, tmp++) {
|
||||
*tmp = 0xcafebabe;
|
||||
}
|
||||
tmp = (unsigned long *)((u8 *) entry->virtual +
|
||||
(PAGE_SIZE * i));
|
||||
for (j = 0;
|
||||
j < PAGE_SIZE / sizeof(unsigned long);
|
||||
j++, tmp++) {
|
||||
if (*tmp != 0xcafebabe && error == 0) {
|
||||
error = 1;
|
||||
DRM_ERROR("Scatter allocation error, "
|
||||
"pagelist does not match "
|
||||
"virtual mapping\n");
|
||||
}
|
||||
}
|
||||
tmp = page_address(entry->pagelist[i]);
|
||||
for (j = 0;
|
||||
j < PAGE_SIZE / sizeof(unsigned long);
|
||||
j++, tmp++) {
|
||||
*tmp = 0;
|
||||
}
|
||||
}
|
||||
if (error == 0)
|
||||
DRM_ERROR("Scatter allocation matches pagelist\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
||||
failed:
|
||||
drm_sg_cleanup(entry);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
int drm_sg_free(struct inode *inode, struct file *filp,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
drm_file_t *priv = filp->private_data;
|
||||
drm_device_t *dev = priv->head->dev;
|
||||
drm_scatter_gather_t request;
|
||||
drm_sg_mem_t *entry;
|
||||
|
||||
if (!drm_core_check_feature(dev, DRIVER_SG))
|
||||
return -EINVAL;
|
||||
|
||||
if (copy_from_user(&request,
|
||||
(drm_scatter_gather_t __user *) arg,
|
||||
sizeof(request)))
|
||||
return -EFAULT;
|
||||
|
||||
entry = dev->sg;
|
||||
dev->sg = NULL;
|
||||
|
||||
if (!entry || entry->handle != request.handle)
|
||||
return -EINVAL;
|
||||
|
||||
DRM_DEBUG("sg free virtual = %p\n", entry->virtual);
|
||||
|
||||
drm_sg_cleanup(entry);
|
||||
|
||||
return 0;
|
||||
}
|
||||
352
drivers/char/drm/drm_sman.c
Normal file
352
drivers/char/drm/drm_sman.c
Normal file
@@ -0,0 +1,352 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright 2006 Tungsten Graphics, Inc., Bismarck., ND., USA.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sub license, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
* USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the
|
||||
* next paragraph) shall be included in all copies or substantial portions
|
||||
* of the Software.
|
||||
*
|
||||
*
|
||||
**************************************************************************/
|
||||
/*
|
||||
* Simple memory manager interface that keeps track on allocate regions on a
|
||||
* per "owner" basis. All regions associated with an "owner" can be released
|
||||
* with a simple call. Typically if the "owner" exists. The owner is any
|
||||
* "unsigned long" identifier. Can typically be a pointer to a file private
|
||||
* struct or a context identifier.
|
||||
*
|
||||
* Authors:
|
||||
* Thomas Hellström <thomas-at-tungstengraphics-dot-com>
|
||||
*/
|
||||
|
||||
#include "drm_sman.h"
|
||||
|
||||
typedef struct drm_owner_item {
|
||||
drm_hash_item_t owner_hash;
|
||||
struct list_head sman_list;
|
||||
struct list_head mem_blocks;
|
||||
} drm_owner_item_t;
|
||||
|
||||
void drm_sman_takedown(drm_sman_t * sman)
|
||||
{
|
||||
drm_ht_remove(&sman->user_hash_tab);
|
||||
drm_ht_remove(&sman->owner_hash_tab);
|
||||
if (sman->mm)
|
||||
drm_free(sman->mm, sman->num_managers * sizeof(*sman->mm),
|
||||
DRM_MEM_MM);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(drm_sman_takedown);
|
||||
|
||||
int
|
||||
drm_sman_init(drm_sman_t * sman, unsigned int num_managers,
|
||||
unsigned int user_order, unsigned int owner_order)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
sman->mm = (drm_sman_mm_t *) drm_calloc(num_managers, sizeof(*sman->mm),
|
||||
DRM_MEM_MM);
|
||||
if (!sman->mm) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
sman->num_managers = num_managers;
|
||||
INIT_LIST_HEAD(&sman->owner_items);
|
||||
ret = drm_ht_create(&sman->owner_hash_tab, owner_order);
|
||||
if (ret)
|
||||
goto out1;
|
||||
ret = drm_ht_create(&sman->user_hash_tab, user_order);
|
||||
if (!ret)
|
||||
goto out;
|
||||
|
||||
drm_ht_remove(&sman->owner_hash_tab);
|
||||
out1:
|
||||
drm_free(sman->mm, num_managers * sizeof(*sman->mm), DRM_MEM_MM);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(drm_sman_init);
|
||||
|
||||
static void *drm_sman_mm_allocate(void *private, unsigned long size,
|
||||
unsigned alignment)
|
||||
{
|
||||
drm_mm_t *mm = (drm_mm_t *) private;
|
||||
drm_mm_node_t *tmp;
|
||||
|
||||
tmp = drm_mm_search_free(mm, size, alignment, 1);
|
||||
if (!tmp) {
|
||||
return NULL;
|
||||
}
|
||||
tmp = drm_mm_get_block(tmp, size, alignment);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
static void drm_sman_mm_free(void *private, void *ref)
|
||||
{
|
||||
drm_mm_node_t *node = (drm_mm_node_t *) ref;
|
||||
|
||||
drm_mm_put_block(node);
|
||||
}
|
||||
|
||||
static void drm_sman_mm_destroy(void *private)
|
||||
{
|
||||
drm_mm_t *mm = (drm_mm_t *) private;
|
||||
drm_mm_takedown(mm);
|
||||
drm_free(mm, sizeof(*mm), DRM_MEM_MM);
|
||||
}
|
||||
|
||||
static unsigned long drm_sman_mm_offset(void *private, void *ref)
|
||||
{
|
||||
drm_mm_node_t *node = (drm_mm_node_t *) ref;
|
||||
return node->start;
|
||||
}
|
||||
|
||||
int
|
||||
drm_sman_set_range(drm_sman_t * sman, unsigned int manager,
|
||||
unsigned long start, unsigned long size)
|
||||
{
|
||||
drm_sman_mm_t *sman_mm;
|
||||
drm_mm_t *mm;
|
||||
int ret;
|
||||
|
||||
BUG_ON(manager >= sman->num_managers);
|
||||
|
||||
sman_mm = &sman->mm[manager];
|
||||
mm = drm_calloc(1, sizeof(*mm), DRM_MEM_MM);
|
||||
if (!mm) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
sman_mm->private = mm;
|
||||
ret = drm_mm_init(mm, start, size);
|
||||
|
||||
if (ret) {
|
||||
drm_free(mm, sizeof(*mm), DRM_MEM_MM);
|
||||
return ret;
|
||||
}
|
||||
|
||||
sman_mm->allocate = drm_sman_mm_allocate;
|
||||
sman_mm->free = drm_sman_mm_free;
|
||||
sman_mm->destroy = drm_sman_mm_destroy;
|
||||
sman_mm->offset = drm_sman_mm_offset;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(drm_sman_set_range);
|
||||
|
||||
int
|
||||
drm_sman_set_manager(drm_sman_t * sman, unsigned int manager,
|
||||
drm_sman_mm_t * allocator)
|
||||
{
|
||||
BUG_ON(manager >= sman->num_managers);
|
||||
sman->mm[manager] = *allocator;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_sman_set_manager);
|
||||
|
||||
static drm_owner_item_t *drm_sman_get_owner_item(drm_sman_t * sman,
|
||||
unsigned long owner)
|
||||
{
|
||||
int ret;
|
||||
drm_hash_item_t *owner_hash_item;
|
||||
drm_owner_item_t *owner_item;
|
||||
|
||||
ret = drm_ht_find_item(&sman->owner_hash_tab, owner, &owner_hash_item);
|
||||
if (!ret) {
|
||||
return drm_hash_entry(owner_hash_item, drm_owner_item_t,
|
||||
owner_hash);
|
||||
}
|
||||
|
||||
owner_item = drm_calloc(1, sizeof(*owner_item), DRM_MEM_MM);
|
||||
if (!owner_item)
|
||||
goto out;
|
||||
|
||||
INIT_LIST_HEAD(&owner_item->mem_blocks);
|
||||
owner_item->owner_hash.key = owner;
|
||||
if (drm_ht_insert_item(&sman->owner_hash_tab, &owner_item->owner_hash))
|
||||
goto out1;
|
||||
|
||||
list_add_tail(&owner_item->sman_list, &sman->owner_items);
|
||||
return owner_item;
|
||||
|
||||
out1:
|
||||
drm_free(owner_item, sizeof(*owner_item), DRM_MEM_MM);
|
||||
out:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
drm_memblock_item_t *drm_sman_alloc(drm_sman_t *sman, unsigned int manager,
|
||||
unsigned long size, unsigned alignment,
|
||||
unsigned long owner)
|
||||
{
|
||||
void *tmp;
|
||||
drm_sman_mm_t *sman_mm;
|
||||
drm_owner_item_t *owner_item;
|
||||
drm_memblock_item_t *memblock;
|
||||
|
||||
BUG_ON(manager >= sman->num_managers);
|
||||
|
||||
sman_mm = &sman->mm[manager];
|
||||
tmp = sman_mm->allocate(sman_mm->private, size, alignment);
|
||||
|
||||
if (!tmp) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memblock = drm_calloc(1, sizeof(*memblock), DRM_MEM_MM);
|
||||
|
||||
if (!memblock)
|
||||
goto out;
|
||||
|
||||
memblock->mm_info = tmp;
|
||||
memblock->mm = sman_mm;
|
||||
memblock->sman = sman;
|
||||
|
||||
if (drm_ht_just_insert_please
|
||||
(&sman->user_hash_tab, &memblock->user_hash,
|
||||
(unsigned long)memblock, 32, 0, 0))
|
||||
goto out1;
|
||||
|
||||
owner_item = drm_sman_get_owner_item(sman, owner);
|
||||
if (!owner_item)
|
||||
goto out2;
|
||||
|
||||
list_add_tail(&memblock->owner_list, &owner_item->mem_blocks);
|
||||
|
||||
return memblock;
|
||||
|
||||
out2:
|
||||
drm_ht_remove_item(&sman->user_hash_tab, &memblock->user_hash);
|
||||
out1:
|
||||
drm_free(memblock, sizeof(*memblock), DRM_MEM_MM);
|
||||
out:
|
||||
sman_mm->free(sman_mm->private, tmp);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(drm_sman_alloc);
|
||||
|
||||
static void drm_sman_free(drm_memblock_item_t *item)
|
||||
{
|
||||
drm_sman_t *sman = item->sman;
|
||||
|
||||
list_del(&item->owner_list);
|
||||
drm_ht_remove_item(&sman->user_hash_tab, &item->user_hash);
|
||||
item->mm->free(item->mm->private, item->mm_info);
|
||||
drm_free(item, sizeof(*item), DRM_MEM_MM);
|
||||
}
|
||||
|
||||
int drm_sman_free_key(drm_sman_t *sman, unsigned int key)
|
||||
{
|
||||
drm_hash_item_t *hash_item;
|
||||
drm_memblock_item_t *memblock_item;
|
||||
|
||||
if (drm_ht_find_item(&sman->user_hash_tab, key, &hash_item))
|
||||
return -EINVAL;
|
||||
|
||||
memblock_item = drm_hash_entry(hash_item, drm_memblock_item_t, user_hash);
|
||||
drm_sman_free(memblock_item);
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(drm_sman_free_key);
|
||||
|
||||
static void drm_sman_remove_owner(drm_sman_t *sman,
|
||||
drm_owner_item_t *owner_item)
|
||||
{
|
||||
list_del(&owner_item->sman_list);
|
||||
drm_ht_remove_item(&sman->owner_hash_tab, &owner_item->owner_hash);
|
||||
drm_free(owner_item, sizeof(*owner_item), DRM_MEM_MM);
|
||||
}
|
||||
|
||||
int drm_sman_owner_clean(drm_sman_t *sman, unsigned long owner)
|
||||
{
|
||||
|
||||
drm_hash_item_t *hash_item;
|
||||
drm_owner_item_t *owner_item;
|
||||
|
||||
if (drm_ht_find_item(&sman->owner_hash_tab, owner, &hash_item)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
owner_item = drm_hash_entry(hash_item, drm_owner_item_t, owner_hash);
|
||||
if (owner_item->mem_blocks.next == &owner_item->mem_blocks) {
|
||||
drm_sman_remove_owner(sman, owner_item);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(drm_sman_owner_clean);
|
||||
|
||||
static void drm_sman_do_owner_cleanup(drm_sman_t *sman,
|
||||
drm_owner_item_t *owner_item)
|
||||
{
|
||||
drm_memblock_item_t *entry, *next;
|
||||
|
||||
list_for_each_entry_safe(entry, next, &owner_item->mem_blocks,
|
||||
owner_list) {
|
||||
drm_sman_free(entry);
|
||||
}
|
||||
drm_sman_remove_owner(sman, owner_item);
|
||||
}
|
||||
|
||||
void drm_sman_owner_cleanup(drm_sman_t *sman, unsigned long owner)
|
||||
{
|
||||
|
||||
drm_hash_item_t *hash_item;
|
||||
drm_owner_item_t *owner_item;
|
||||
|
||||
if (drm_ht_find_item(&sman->owner_hash_tab, owner, &hash_item)) {
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
owner_item = drm_hash_entry(hash_item, drm_owner_item_t, owner_hash);
|
||||
drm_sman_do_owner_cleanup(sman, owner_item);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(drm_sman_owner_cleanup);
|
||||
|
||||
void drm_sman_cleanup(drm_sman_t *sman)
|
||||
{
|
||||
drm_owner_item_t *entry, *next;
|
||||
unsigned int i;
|
||||
drm_sman_mm_t *sman_mm;
|
||||
|
||||
list_for_each_entry_safe(entry, next, &sman->owner_items, sman_list) {
|
||||
drm_sman_do_owner_cleanup(sman, entry);
|
||||
}
|
||||
if (sman->mm) {
|
||||
for (i = 0; i < sman->num_managers; ++i) {
|
||||
sman_mm = &sman->mm[i];
|
||||
if (sman_mm->private) {
|
||||
sman_mm->destroy(sman_mm->private);
|
||||
sman_mm->private = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(drm_sman_cleanup);
|
||||
176
drivers/char/drm/drm_sman.h
Normal file
176
drivers/char/drm/drm_sman.h
Normal file
@@ -0,0 +1,176 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sub license, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the
|
||||
* next paragraph) shall be included in all copies or substantial portions
|
||||
* of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
* USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*
|
||||
**************************************************************************/
|
||||
/*
|
||||
* Simple memory MANager interface that keeps track on allocate regions on a
|
||||
* per "owner" basis. All regions associated with an "owner" can be released
|
||||
* with a simple call. Typically if the "owner" exists. The owner is any
|
||||
* "unsigned long" identifier. Can typically be a pointer to a file private
|
||||
* struct or a context identifier.
|
||||
*
|
||||
* Authors:
|
||||
* Thomas Hellström <thomas-at-tungstengraphics-dot-com>
|
||||
*/
|
||||
|
||||
#ifndef DRM_SMAN_H
|
||||
#define DRM_SMAN_H
|
||||
|
||||
#include "drmP.h"
|
||||
#include "drm_hashtab.h"
|
||||
|
||||
/*
|
||||
* A class that is an abstration of a simple memory allocator.
|
||||
* The sman implementation provides a default such allocator
|
||||
* using the drm_mm.c implementation. But the user can replace it.
|
||||
* See the SiS implementation, which may use the SiS FB kernel module
|
||||
* for memory management.
|
||||
*/
|
||||
|
||||
typedef struct drm_sman_mm {
|
||||
/* private info. If allocated, needs to be destroyed by the destroy
|
||||
function */
|
||||
void *private;
|
||||
|
||||
/* Allocate a memory block with given size and alignment.
|
||||
Return an opaque reference to the memory block */
|
||||
|
||||
void *(*allocate) (void *private, unsigned long size,
|
||||
unsigned alignment);
|
||||
|
||||
/* Free a memory block. "ref" is the opaque reference that we got from
|
||||
the "alloc" function */
|
||||
|
||||
void (*free) (void *private, void *ref);
|
||||
|
||||
/* Free all resources associated with this allocator */
|
||||
|
||||
void (*destroy) (void *private);
|
||||
|
||||
/* Return a memory offset from the opaque reference returned from the
|
||||
"alloc" function */
|
||||
|
||||
unsigned long (*offset) (void *private, void *ref);
|
||||
} drm_sman_mm_t;
|
||||
|
||||
typedef struct drm_memblock_item {
|
||||
struct list_head owner_list;
|
||||
drm_hash_item_t user_hash;
|
||||
void *mm_info;
|
||||
drm_sman_mm_t *mm;
|
||||
struct drm_sman *sman;
|
||||
} drm_memblock_item_t;
|
||||
|
||||
typedef struct drm_sman {
|
||||
drm_sman_mm_t *mm;
|
||||
int num_managers;
|
||||
drm_open_hash_t owner_hash_tab;
|
||||
drm_open_hash_t user_hash_tab;
|
||||
struct list_head owner_items;
|
||||
} drm_sman_t;
|
||||
|
||||
/*
|
||||
* Take down a memory manager. This function should only be called after a
|
||||
* successful init and after a call to drm_sman_cleanup.
|
||||
*/
|
||||
|
||||
extern void drm_sman_takedown(drm_sman_t * sman);
|
||||
|
||||
/*
|
||||
* Allocate structures for a manager.
|
||||
* num_managers are the number of memory pools to manage. (VRAM, AGP, ....)
|
||||
* user_order is the log2 of the number of buckets in the user hash table.
|
||||
* set this to approximately log2 of the max number of memory regions
|
||||
* that will be allocated for _all_ pools together.
|
||||
* owner_order is the log2 of the number of buckets in the owner hash table.
|
||||
* set this to approximately log2 of
|
||||
* the number of client file connections that will
|
||||
* be using the manager.
|
||||
*
|
||||
*/
|
||||
|
||||
extern int drm_sman_init(drm_sman_t * sman, unsigned int num_managers,
|
||||
unsigned int user_order, unsigned int owner_order);
|
||||
|
||||
/*
|
||||
* Initialize a drm_mm.c allocator. Should be called only once for each
|
||||
* manager unless a customized allogator is used.
|
||||
*/
|
||||
|
||||
extern int drm_sman_set_range(drm_sman_t * sman, unsigned int manager,
|
||||
unsigned long start, unsigned long size);
|
||||
|
||||
/*
|
||||
* Initialize a customized allocator for one of the managers.
|
||||
* (See the SiS module). The object pointed to by "allocator" is copied,
|
||||
* so it can be destroyed after this call.
|
||||
*/
|
||||
|
||||
extern int drm_sman_set_manager(drm_sman_t * sman, unsigned int mananger,
|
||||
drm_sman_mm_t * allocator);
|
||||
|
||||
/*
|
||||
* Allocate a memory block. Aligment is not implemented yet.
|
||||
*/
|
||||
|
||||
extern drm_memblock_item_t *drm_sman_alloc(drm_sman_t * sman,
|
||||
unsigned int manager,
|
||||
unsigned long size,
|
||||
unsigned alignment,
|
||||
unsigned long owner);
|
||||
/*
|
||||
* Free a memory block identified by its user hash key.
|
||||
*/
|
||||
|
||||
extern int drm_sman_free_key(drm_sman_t * sman, unsigned int key);
|
||||
|
||||
/*
|
||||
* returns 1 iff there are no stale memory blocks associated with this owner.
|
||||
* Typically called to determine if we need to idle the hardware and call
|
||||
* drm_sman_owner_cleanup. If there are no stale memory blocks, it removes all
|
||||
* resources associated with owner.
|
||||
*/
|
||||
|
||||
extern int drm_sman_owner_clean(drm_sman_t * sman, unsigned long owner);
|
||||
|
||||
/*
|
||||
* Frees all stale memory blocks associated with this owner. Note that this
|
||||
* requires that the hardware is finished with all blocks, so the graphics engine
|
||||
* should be idled before this call is made. This function also frees
|
||||
* any resources associated with "owner" and should be called when owner
|
||||
* is not going to be referenced anymore.
|
||||
*/
|
||||
|
||||
extern void drm_sman_owner_cleanup(drm_sman_t * sman, unsigned long owner);
|
||||
|
||||
/*
|
||||
* Frees all stale memory blocks associated with the memory manager.
|
||||
* See idling above.
|
||||
*/
|
||||
|
||||
extern void drm_sman_cleanup(drm_sman_t * sman);
|
||||
|
||||
#endif
|
||||
290
drivers/char/drm/drm_stub.c
Normal file
290
drivers/char/drm/drm_stub.c
Normal file
@@ -0,0 +1,290 @@
|
||||
/**
|
||||
* \file drm_stub.h
|
||||
* Stub support
|
||||
*
|
||||
* \author Rickard E. (Rik) Faith <faith@valinux.com>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Created: Fri Jan 19 10:48:35 2001 by faith@acm.org
|
||||
*
|
||||
* Copyright 2001 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 <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include "drmP.h"
|
||||
#include "drm_core.h"
|
||||
|
||||
unsigned int drm_cards_limit = 16; /* Enough for one machine */
|
||||
unsigned int drm_debug = 0; /* 1 to enable debug output */
|
||||
EXPORT_SYMBOL(drm_debug);
|
||||
|
||||
MODULE_AUTHOR(CORE_AUTHOR);
|
||||
MODULE_DESCRIPTION(CORE_DESC);
|
||||
MODULE_LICENSE("GPL and additional rights");
|
||||
MODULE_PARM_DESC(cards_limit, "Maximum number of graphics cards");
|
||||
MODULE_PARM_DESC(debug, "Enable debug output");
|
||||
|
||||
module_param_named(cards_limit, drm_cards_limit, int, 0444);
|
||||
module_param_named(debug, drm_debug, int, 0600);
|
||||
|
||||
drm_head_t **drm_heads;
|
||||
struct class *drm_class;
|
||||
struct proc_dir_entry *drm_proc_root;
|
||||
|
||||
static int drm_fill_in_dev(drm_device_t * dev, struct pci_dev *pdev,
|
||||
const struct pci_device_id *ent,
|
||||
struct drm_driver *driver)
|
||||
{
|
||||
int retcode;
|
||||
|
||||
spin_lock_init(&dev->count_lock);
|
||||
spin_lock_init(&dev->drw_lock);
|
||||
spin_lock_init(&dev->tasklet_lock);
|
||||
init_timer(&dev->timer);
|
||||
mutex_init(&dev->struct_mutex);
|
||||
mutex_init(&dev->ctxlist_mutex);
|
||||
|
||||
dev->pdev = pdev;
|
||||
dev->pci_device = pdev->device;
|
||||
dev->pci_vendor = pdev->vendor;
|
||||
|
||||
#ifdef __alpha__
|
||||
dev->hose = pdev->sysdata;
|
||||
#endif
|
||||
dev->irq = pdev->irq;
|
||||
|
||||
dev->maplist = drm_calloc(1, sizeof(*dev->maplist), DRM_MEM_MAPS);
|
||||
if (dev->maplist == NULL)
|
||||
return -ENOMEM;
|
||||
INIT_LIST_HEAD(&dev->maplist->head);
|
||||
if (drm_ht_create(&dev->map_hash, 12)) {
|
||||
drm_free(dev->maplist, sizeof(*dev->maplist), DRM_MEM_MAPS);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* the DRM has 6 basic counters */
|
||||
dev->counters = 6;
|
||||
dev->types[0] = _DRM_STAT_LOCK;
|
||||
dev->types[1] = _DRM_STAT_OPENS;
|
||||
dev->types[2] = _DRM_STAT_CLOSES;
|
||||
dev->types[3] = _DRM_STAT_IOCTLS;
|
||||
dev->types[4] = _DRM_STAT_LOCKS;
|
||||
dev->types[5] = _DRM_STAT_UNLOCKS;
|
||||
|
||||
dev->driver = driver;
|
||||
|
||||
if (dev->driver->load)
|
||||
if ((retcode = dev->driver->load(dev, ent->driver_data)))
|
||||
goto error_out_unreg;
|
||||
|
||||
if (drm_core_has_AGP(dev)) {
|
||||
if (drm_device_is_agp(dev))
|
||||
dev->agp = drm_agp_init(dev);
|
||||
if (drm_core_check_feature(dev, DRIVER_REQUIRE_AGP)
|
||||
&& (dev->agp == NULL)) {
|
||||
DRM_ERROR("Cannot initialize the agpgart module.\n");
|
||||
retcode = -EINVAL;
|
||||
goto error_out_unreg;
|
||||
}
|
||||
if (drm_core_has_MTRR(dev)) {
|
||||
if (dev->agp)
|
||||
dev->agp->agp_mtrr =
|
||||
mtrr_add(dev->agp->agp_info.aper_base,
|
||||
dev->agp->agp_info.aper_size *
|
||||
1024 * 1024, MTRR_TYPE_WRCOMB, 1);
|
||||
}
|
||||
}
|
||||
|
||||
retcode = drm_ctxbitmap_init(dev);
|
||||
if (retcode) {
|
||||
DRM_ERROR("Cannot allocate memory for context bitmap.\n");
|
||||
goto error_out_unreg;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error_out_unreg:
|
||||
drm_lastclose(dev);
|
||||
return retcode;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get a secondary minor number.
|
||||
*
|
||||
* \param dev device data structure
|
||||
* \param sec-minor structure to hold the assigned minor
|
||||
* \return negative number on failure.
|
||||
*
|
||||
* Search an empty entry and initialize it to the given parameters, and
|
||||
* create the proc init entry via proc_init(). This routines assigns
|
||||
* minor numbers to secondary heads of multi-headed cards
|
||||
*/
|
||||
static int drm_get_head(drm_device_t * dev, drm_head_t * head)
|
||||
{
|
||||
drm_head_t **heads = drm_heads;
|
||||
int ret;
|
||||
int minor;
|
||||
|
||||
DRM_DEBUG("\n");
|
||||
|
||||
for (minor = 0; minor < drm_cards_limit; minor++, heads++) {
|
||||
if (!*heads) {
|
||||
|
||||
*head = (drm_head_t) {
|
||||
.dev = dev,.device =
|
||||
MKDEV(DRM_MAJOR, minor),.minor = minor,};
|
||||
|
||||
if ((ret =
|
||||
drm_proc_init(dev, minor, drm_proc_root,
|
||||
&head->dev_root))) {
|
||||
printk(KERN_ERR
|
||||
"DRM: Failed to initialize /proc/dri.\n");
|
||||
goto err_g1;
|
||||
}
|
||||
|
||||
head->dev_class = drm_sysfs_device_add(drm_class, head);
|
||||
if (IS_ERR(head->dev_class)) {
|
||||
printk(KERN_ERR
|
||||
"DRM: Error sysfs_device_add.\n");
|
||||
ret = PTR_ERR(head->dev_class);
|
||||
goto err_g2;
|
||||
}
|
||||
*heads = head;
|
||||
|
||||
DRM_DEBUG("new minor assigned %d\n", minor);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
DRM_ERROR("out of minors\n");
|
||||
return -ENOMEM;
|
||||
err_g2:
|
||||
drm_proc_cleanup(minor, drm_proc_root, head->dev_root);
|
||||
err_g1:
|
||||
*head = (drm_head_t) {
|
||||
.dev = NULL};
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register.
|
||||
*
|
||||
* \param pdev - PCI device structure
|
||||
* \param ent entry from the PCI ID table with device type flags
|
||||
* \return zero on success or a negative number on failure.
|
||||
*
|
||||
* Attempt to gets inter module "drm" information. If we are first
|
||||
* then register the character device and inter module information.
|
||||
* Try and register, if we fail to register, backout previous work.
|
||||
*/
|
||||
int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
|
||||
struct drm_driver *driver)
|
||||
{
|
||||
drm_device_t *dev;
|
||||
int ret;
|
||||
|
||||
DRM_DEBUG("\n");
|
||||
|
||||
dev = drm_calloc(1, sizeof(*dev), DRM_MEM_STUB);
|
||||
if (!dev)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = pci_enable_device(pdev);
|
||||
if (ret)
|
||||
goto err_g1;
|
||||
|
||||
if ((ret = drm_fill_in_dev(dev, pdev, ent, driver))) {
|
||||
printk(KERN_ERR "DRM: Fill_in_dev failed.\n");
|
||||
goto err_g2;
|
||||
}
|
||||
if ((ret = drm_get_head(dev, &dev->primary)))
|
||||
goto err_g2;
|
||||
|
||||
DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n",
|
||||
driver->name, driver->major, driver->minor, driver->patchlevel,
|
||||
driver->date, dev->primary.minor);
|
||||
|
||||
return 0;
|
||||
|
||||
err_g2:
|
||||
pci_disable_device(pdev);
|
||||
err_g1:
|
||||
drm_free(dev, sizeof(*dev), DRM_MEM_STUB);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Put a device minor number.
|
||||
*
|
||||
* \param dev device data structure
|
||||
* \return always zero
|
||||
*
|
||||
* Cleans up the proc resources. If it is the last minor then release the foreign
|
||||
* "drm" data, otherwise unregisters the "drm" data, frees the dev list and
|
||||
* unregisters the character device.
|
||||
*/
|
||||
int drm_put_dev(drm_device_t * dev)
|
||||
{
|
||||
DRM_DEBUG("release primary %s\n", dev->driver->pci_driver.name);
|
||||
|
||||
if (dev->unique) {
|
||||
drm_free(dev->unique, strlen(dev->unique) + 1, DRM_MEM_DRIVER);
|
||||
dev->unique = NULL;
|
||||
dev->unique_len = 0;
|
||||
}
|
||||
if (dev->devname) {
|
||||
drm_free(dev->devname, strlen(dev->devname) + 1,
|
||||
DRM_MEM_DRIVER);
|
||||
dev->devname = NULL;
|
||||
}
|
||||
drm_free(dev, sizeof(*dev), DRM_MEM_STUB);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Put a secondary minor number.
|
||||
*
|
||||
* \param sec_minor - structure to be released
|
||||
* \return always zero
|
||||
*
|
||||
* Cleans up the proc resources. Not legal for this to be the
|
||||
* last minor released.
|
||||
*
|
||||
*/
|
||||
int drm_put_head(drm_head_t * head)
|
||||
{
|
||||
int minor = head->minor;
|
||||
|
||||
DRM_DEBUG("release secondary minor %d\n", minor);
|
||||
|
||||
drm_proc_cleanup(minor, drm_proc_root, head->dev_root);
|
||||
drm_sysfs_device_remove(head->dev_class);
|
||||
|
||||
*head = (drm_head_t) {.dev = NULL};
|
||||
|
||||
drm_heads[minor] = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
156
drivers/char/drm/drm_sysfs.c
Normal file
156
drivers/char/drm/drm_sysfs.c
Normal file
@@ -0,0 +1,156 @@
|
||||
|
||||
/*
|
||||
* drm_sysfs.c - Modifications to drm_sysfs_class.c to support
|
||||
* extra sysfs attribute from DRM. Normal drm_sysfs_class
|
||||
* does not allow adding attributes.
|
||||
*
|
||||
* Copyright (c) 2004 Jon Smirl <jonsmirl@gmail.com>
|
||||
* Copyright (c) 2003-2004 Greg Kroah-Hartman <greg@kroah.com>
|
||||
* Copyright (c) 2003-2004 IBM Corp.
|
||||
*
|
||||
* This file is released under the GPLv2
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/kdev_t.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
#include "drm_core.h"
|
||||
#include "drmP.h"
|
||||
|
||||
/* Display the version of drm_core. This doesn't work right in current design */
|
||||
static ssize_t version_show(struct class *dev, char *buf)
|
||||
{
|
||||
return sprintf(buf, "%s %d.%d.%d %s\n", CORE_NAME, CORE_MAJOR,
|
||||
CORE_MINOR, CORE_PATCHLEVEL, CORE_DATE);
|
||||
}
|
||||
|
||||
static CLASS_ATTR(version, S_IRUGO, version_show, NULL);
|
||||
|
||||
/**
|
||||
* drm_sysfs_create - create a struct drm_sysfs_class structure
|
||||
* @owner: pointer to the module that is to "own" this struct drm_sysfs_class
|
||||
* @name: pointer to a string for the name of this class.
|
||||
*
|
||||
* This is used to create a struct drm_sysfs_class pointer that can then be used
|
||||
* in calls to drm_sysfs_device_add().
|
||||
*
|
||||
* Note, the pointer created here is to be destroyed when finished by making a
|
||||
* call to drm_sysfs_destroy().
|
||||
*/
|
||||
struct class *drm_sysfs_create(struct module *owner, char *name)
|
||||
{
|
||||
struct class *class;
|
||||
int err;
|
||||
|
||||
class = class_create(owner, name);
|
||||
if (IS_ERR(class)) {
|
||||
err = PTR_ERR(class);
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
err = class_create_file(class, &class_attr_version);
|
||||
if (err)
|
||||
goto err_out_class;
|
||||
|
||||
return class;
|
||||
|
||||
err_out_class:
|
||||
class_destroy(class);
|
||||
err_out:
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_sysfs_destroy - destroys a struct drm_sysfs_class structure
|
||||
* @cs: pointer to the struct drm_sysfs_class that is to be destroyed
|
||||
*
|
||||
* Note, the pointer to be destroyed must have been created with a call to
|
||||
* drm_sysfs_create().
|
||||
*/
|
||||
void drm_sysfs_destroy(struct class *class)
|
||||
{
|
||||
if ((class == NULL) || (IS_ERR(class)))
|
||||
return;
|
||||
|
||||
class_remove_file(class, &class_attr_version);
|
||||
class_destroy(class);
|
||||
}
|
||||
|
||||
static ssize_t show_dri(struct class_device *class_device, char *buf)
|
||||
{
|
||||
drm_device_t * dev = ((drm_head_t *)class_get_devdata(class_device))->dev;
|
||||
if (dev->driver->dri_library_name)
|
||||
return dev->driver->dri_library_name(dev, buf);
|
||||
return snprintf(buf, PAGE_SIZE, "%s\n", dev->driver->pci_driver.name);
|
||||
}
|
||||
|
||||
static struct class_device_attribute class_device_attrs[] = {
|
||||
__ATTR(dri_library_name, S_IRUGO, show_dri, NULL),
|
||||
};
|
||||
|
||||
/**
|
||||
* drm_sysfs_device_add - adds a class device to sysfs for a character driver
|
||||
* @cs: pointer to the struct class that this device should be registered to.
|
||||
* @dev: the dev_t for the device to be added.
|
||||
* @device: a pointer to a struct device that is assiociated with this class device.
|
||||
* @fmt: string for the class device's name
|
||||
*
|
||||
* A struct class_device will be created in sysfs, registered to the specified
|
||||
* class. A "dev" file will be created, showing the dev_t for the device. The
|
||||
* pointer to the struct class_device will be returned from the call. Any further
|
||||
* sysfs files that might be required can be created using this pointer.
|
||||
* Note: the struct class passed to this function must have previously been
|
||||
* created with a call to drm_sysfs_create().
|
||||
*/
|
||||
struct class_device *drm_sysfs_device_add(struct class *cs, drm_head_t *head)
|
||||
{
|
||||
struct class_device *class_dev;
|
||||
int i, j, err;
|
||||
|
||||
class_dev = class_device_create(cs, NULL,
|
||||
MKDEV(DRM_MAJOR, head->minor),
|
||||
&(head->dev->pdev)->dev,
|
||||
"card%d", head->minor);
|
||||
if (IS_ERR(class_dev)) {
|
||||
err = PTR_ERR(class_dev);
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
class_set_devdata(class_dev, head);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++) {
|
||||
err = class_device_create_file(class_dev,
|
||||
&class_device_attrs[i]);
|
||||
if (err)
|
||||
goto err_out_files;
|
||||
}
|
||||
|
||||
return class_dev;
|
||||
|
||||
err_out_files:
|
||||
if (i > 0)
|
||||
for (j = 0; j < i; j++)
|
||||
class_device_remove_file(class_dev,
|
||||
&class_device_attrs[i]);
|
||||
class_device_unregister(class_dev);
|
||||
err_out:
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_sysfs_device_remove - removes a class device that was created with drm_sysfs_device_add()
|
||||
* @dev: the dev_t of the device that was previously registered.
|
||||
*
|
||||
* This call unregisters and cleans up a class device that was created with a
|
||||
* call to drm_sysfs_device_add()
|
||||
*/
|
||||
void drm_sysfs_device_remove(struct class_device *class_dev)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++)
|
||||
class_device_remove_file(class_dev, &class_device_attrs[i]);
|
||||
class_device_unregister(class_dev);
|
||||
}
|
||||
666
drivers/char/drm/drm_vm.c
Normal file
666
drivers/char/drm/drm_vm.c
Normal file
@@ -0,0 +1,666 @@
|
||||
/**
|
||||
* \file drm_vm.c
|
||||
* Memory mapping for DRM
|
||||
*
|
||||
* \author Rickard E. (Rik) Faith <faith@valinux.com>
|
||||
* \author Gareth Hughes <gareth@valinux.com>
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "drmP.h"
|
||||
#if defined(__ia64__)
|
||||
#include <linux/efi.h>
|
||||
#endif
|
||||
|
||||
static void drm_vm_open(struct vm_area_struct *vma);
|
||||
static void drm_vm_close(struct vm_area_struct *vma);
|
||||
|
||||
/**
|
||||
* \c nopage method for AGP virtual memory.
|
||||
*
|
||||
* \param vma virtual memory area.
|
||||
* \param address access address.
|
||||
* \return pointer to the page structure.
|
||||
*
|
||||
* Find the right map and if it's AGP memory find the real physical page to
|
||||
* map, get the page, increment the use count and return it.
|
||||
*/
|
||||
#if __OS_HAS_AGP
|
||||
static __inline__ struct page *drm_do_vm_nopage(struct vm_area_struct *vma,
|
||||
unsigned long address)
|
||||
{
|
||||
drm_file_t *priv = vma->vm_file->private_data;
|
||||
drm_device_t *dev = priv->head->dev;
|
||||
drm_map_t *map = NULL;
|
||||
drm_map_list_t *r_list;
|
||||
drm_hash_item_t *hash;
|
||||
|
||||
/*
|
||||
* Find the right map
|
||||
*/
|
||||
if (!drm_core_has_AGP(dev))
|
||||
goto vm_nopage_error;
|
||||
|
||||
if (!dev->agp || !dev->agp->cant_use_aperture)
|
||||
goto vm_nopage_error;
|
||||
|
||||
if (drm_ht_find_item(&dev->map_hash, vma->vm_pgoff, &hash))
|
||||
goto vm_nopage_error;
|
||||
|
||||
r_list = drm_hash_entry(hash, drm_map_list_t, hash);
|
||||
map = r_list->map;
|
||||
|
||||
if (map && map->type == _DRM_AGP) {
|
||||
unsigned long offset = address - vma->vm_start;
|
||||
unsigned long baddr = map->offset + offset;
|
||||
struct drm_agp_mem *agpmem;
|
||||
struct page *page;
|
||||
|
||||
#ifdef __alpha__
|
||||
/*
|
||||
* Adjust to a bus-relative address
|
||||
*/
|
||||
baddr -= dev->hose->mem_space->start;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* It's AGP memory - find the real physical page to map
|
||||
*/
|
||||
for (agpmem = dev->agp->memory; agpmem; agpmem = agpmem->next) {
|
||||
if (agpmem->bound <= baddr &&
|
||||
agpmem->bound + agpmem->pages * PAGE_SIZE > baddr)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!agpmem)
|
||||
goto vm_nopage_error;
|
||||
|
||||
/*
|
||||
* Get the page, inc the use count, and return it
|
||||
*/
|
||||
offset = (baddr - agpmem->bound) >> PAGE_SHIFT;
|
||||
page = virt_to_page(__va(agpmem->memory->memory[offset]));
|
||||
get_page(page);
|
||||
|
||||
DRM_DEBUG
|
||||
("baddr = 0x%lx page = 0x%p, offset = 0x%lx, count=%d\n",
|
||||
baddr, __va(agpmem->memory->memory[offset]), offset,
|
||||
page_count(page));
|
||||
|
||||
return page;
|
||||
}
|
||||
vm_nopage_error:
|
||||
return NOPAGE_SIGBUS; /* Disallow mremap */
|
||||
}
|
||||
#else /* __OS_HAS_AGP */
|
||||
static __inline__ struct page *drm_do_vm_nopage(struct vm_area_struct *vma,
|
||||
unsigned long address)
|
||||
{
|
||||
return NOPAGE_SIGBUS;
|
||||
}
|
||||
#endif /* __OS_HAS_AGP */
|
||||
|
||||
/**
|
||||
* \c nopage method for shared virtual memory.
|
||||
*
|
||||
* \param vma virtual memory area.
|
||||
* \param address access address.
|
||||
* \return pointer to the page structure.
|
||||
*
|
||||
* Get the the mapping, find the real physical page to map, get the page, and
|
||||
* return it.
|
||||
*/
|
||||
static __inline__ struct page *drm_do_vm_shm_nopage(struct vm_area_struct *vma,
|
||||
unsigned long address)
|
||||
{
|
||||
drm_map_t *map = (drm_map_t *) vma->vm_private_data;
|
||||
unsigned long offset;
|
||||
unsigned long i;
|
||||
struct page *page;
|
||||
|
||||
if (address > vma->vm_end)
|
||||
return NOPAGE_SIGBUS; /* Disallow mremap */
|
||||
if (!map)
|
||||
return NOPAGE_SIGBUS; /* Nothing allocated */
|
||||
|
||||
offset = address - vma->vm_start;
|
||||
i = (unsigned long)map->handle + offset;
|
||||
page = (map->type == _DRM_CONSISTENT) ?
|
||||
virt_to_page((void *)i) : vmalloc_to_page((void *)i);
|
||||
if (!page)
|
||||
return NOPAGE_SIGBUS;
|
||||
get_page(page);
|
||||
|
||||
DRM_DEBUG("shm_nopage 0x%lx\n", address);
|
||||
return page;
|
||||
}
|
||||
|
||||
/**
|
||||
* \c close method for shared virtual memory.
|
||||
*
|
||||
* \param vma virtual memory area.
|
||||
*
|
||||
* Deletes map information if we are the last
|
||||
* person to close a mapping and it's not in the global maplist.
|
||||
*/
|
||||
static void drm_vm_shm_close(struct vm_area_struct *vma)
|
||||
{
|
||||
drm_file_t *priv = vma->vm_file->private_data;
|
||||
drm_device_t *dev = priv->head->dev;
|
||||
drm_vma_entry_t *pt, *prev, *next;
|
||||
drm_map_t *map;
|
||||
drm_map_list_t *r_list;
|
||||
struct list_head *list;
|
||||
int found_maps = 0;
|
||||
|
||||
DRM_DEBUG("0x%08lx,0x%08lx\n",
|
||||
vma->vm_start, vma->vm_end - vma->vm_start);
|
||||
atomic_dec(&dev->vma_count);
|
||||
|
||||
map = vma->vm_private_data;
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
for (pt = dev->vmalist, prev = NULL; pt; pt = next) {
|
||||
next = pt->next;
|
||||
if (pt->vma->vm_private_data == map)
|
||||
found_maps++;
|
||||
if (pt->vma == vma) {
|
||||
if (prev) {
|
||||
prev->next = pt->next;
|
||||
} else {
|
||||
dev->vmalist = pt->next;
|
||||
}
|
||||
drm_free(pt, sizeof(*pt), DRM_MEM_VMAS);
|
||||
} else {
|
||||
prev = pt;
|
||||
}
|
||||
}
|
||||
/* We were the only map that was found */
|
||||
if (found_maps == 1 && map->flags & _DRM_REMOVABLE) {
|
||||
/* Check to see if we are in the maplist, if we are not, then
|
||||
* we delete this mappings information.
|
||||
*/
|
||||
found_maps = 0;
|
||||
list = &dev->maplist->head;
|
||||
list_for_each(list, &dev->maplist->head) {
|
||||
r_list = list_entry(list, drm_map_list_t, head);
|
||||
if (r_list->map == map)
|
||||
found_maps++;
|
||||
}
|
||||
|
||||
if (!found_maps) {
|
||||
drm_dma_handle_t dmah;
|
||||
|
||||
switch (map->type) {
|
||||
case _DRM_REGISTERS:
|
||||
case _DRM_FRAME_BUFFER:
|
||||
if (drm_core_has_MTRR(dev) && map->mtrr >= 0) {
|
||||
int retcode;
|
||||
retcode = mtrr_del(map->mtrr,
|
||||
map->offset,
|
||||
map->size);
|
||||
DRM_DEBUG("mtrr_del = %d\n", retcode);
|
||||
}
|
||||
iounmap(map->handle);
|
||||
break;
|
||||
case _DRM_SHM:
|
||||
vfree(map->handle);
|
||||
break;
|
||||
case _DRM_AGP:
|
||||
case _DRM_SCATTER_GATHER:
|
||||
break;
|
||||
case _DRM_CONSISTENT:
|
||||
dmah.vaddr = map->handle;
|
||||
dmah.busaddr = map->offset;
|
||||
dmah.size = map->size;
|
||||
__drm_pci_free(dev, &dmah);
|
||||
break;
|
||||
}
|
||||
drm_free(map, sizeof(*map), DRM_MEM_MAPS);
|
||||
}
|
||||
}
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
}
|
||||
|
||||
/**
|
||||
* \c nopage method for DMA virtual memory.
|
||||
*
|
||||
* \param vma virtual memory area.
|
||||
* \param address access address.
|
||||
* \return pointer to the page structure.
|
||||
*
|
||||
* Determine the page number from the page offset and get it from drm_device_dma::pagelist.
|
||||
*/
|
||||
static __inline__ struct page *drm_do_vm_dma_nopage(struct vm_area_struct *vma,
|
||||
unsigned long address)
|
||||
{
|
||||
drm_file_t *priv = vma->vm_file->private_data;
|
||||
drm_device_t *dev = priv->head->dev;
|
||||
drm_device_dma_t *dma = dev->dma;
|
||||
unsigned long offset;
|
||||
unsigned long page_nr;
|
||||
struct page *page;
|
||||
|
||||
if (!dma)
|
||||
return NOPAGE_SIGBUS; /* Error */
|
||||
if (address > vma->vm_end)
|
||||
return NOPAGE_SIGBUS; /* Disallow mremap */
|
||||
if (!dma->pagelist)
|
||||
return NOPAGE_SIGBUS; /* Nothing allocated */
|
||||
|
||||
offset = address - vma->vm_start; /* vm_[pg]off[set] should be 0 */
|
||||
page_nr = offset >> PAGE_SHIFT;
|
||||
page = virt_to_page((dma->pagelist[page_nr] + (offset & (~PAGE_MASK))));
|
||||
|
||||
get_page(page);
|
||||
|
||||
DRM_DEBUG("dma_nopage 0x%lx (page %lu)\n", address, page_nr);
|
||||
return page;
|
||||
}
|
||||
|
||||
/**
|
||||
* \c nopage method for scatter-gather virtual memory.
|
||||
*
|
||||
* \param vma virtual memory area.
|
||||
* \param address access address.
|
||||
* \return pointer to the page structure.
|
||||
*
|
||||
* Determine the map offset from the page offset and get it from drm_sg_mem::pagelist.
|
||||
*/
|
||||
static __inline__ struct page *drm_do_vm_sg_nopage(struct vm_area_struct *vma,
|
||||
unsigned long address)
|
||||
{
|
||||
drm_map_t *map = (drm_map_t *) vma->vm_private_data;
|
||||
drm_file_t *priv = vma->vm_file->private_data;
|
||||
drm_device_t *dev = priv->head->dev;
|
||||
drm_sg_mem_t *entry = dev->sg;
|
||||
unsigned long offset;
|
||||
unsigned long map_offset;
|
||||
unsigned long page_offset;
|
||||
struct page *page;
|
||||
|
||||
if (!entry)
|
||||
return NOPAGE_SIGBUS; /* Error */
|
||||
if (address > vma->vm_end)
|
||||
return NOPAGE_SIGBUS; /* Disallow mremap */
|
||||
if (!entry->pagelist)
|
||||
return NOPAGE_SIGBUS; /* Nothing allocated */
|
||||
|
||||
offset = address - vma->vm_start;
|
||||
map_offset = map->offset - (unsigned long)dev->sg->virtual;
|
||||
page_offset = (offset >> PAGE_SHIFT) + (map_offset >> PAGE_SHIFT);
|
||||
page = entry->pagelist[page_offset];
|
||||
get_page(page);
|
||||
|
||||
return page;
|
||||
}
|
||||
|
||||
static struct page *drm_vm_nopage(struct vm_area_struct *vma,
|
||||
unsigned long address, int *type)
|
||||
{
|
||||
if (type)
|
||||
*type = VM_FAULT_MINOR;
|
||||
return drm_do_vm_nopage(vma, address);
|
||||
}
|
||||
|
||||
static struct page *drm_vm_shm_nopage(struct vm_area_struct *vma,
|
||||
unsigned long address, int *type)
|
||||
{
|
||||
if (type)
|
||||
*type = VM_FAULT_MINOR;
|
||||
return drm_do_vm_shm_nopage(vma, address);
|
||||
}
|
||||
|
||||
static struct page *drm_vm_dma_nopage(struct vm_area_struct *vma,
|
||||
unsigned long address, int *type)
|
||||
{
|
||||
if (type)
|
||||
*type = VM_FAULT_MINOR;
|
||||
return drm_do_vm_dma_nopage(vma, address);
|
||||
}
|
||||
|
||||
static struct page *drm_vm_sg_nopage(struct vm_area_struct *vma,
|
||||
unsigned long address, int *type)
|
||||
{
|
||||
if (type)
|
||||
*type = VM_FAULT_MINOR;
|
||||
return drm_do_vm_sg_nopage(vma, address);
|
||||
}
|
||||
|
||||
/** AGP virtual memory operations */
|
||||
static struct vm_operations_struct drm_vm_ops = {
|
||||
.nopage = drm_vm_nopage,
|
||||
.open = drm_vm_open,
|
||||
.close = drm_vm_close,
|
||||
};
|
||||
|
||||
/** Shared virtual memory operations */
|
||||
static struct vm_operations_struct drm_vm_shm_ops = {
|
||||
.nopage = drm_vm_shm_nopage,
|
||||
.open = drm_vm_open,
|
||||
.close = drm_vm_shm_close,
|
||||
};
|
||||
|
||||
/** DMA virtual memory operations */
|
||||
static struct vm_operations_struct drm_vm_dma_ops = {
|
||||
.nopage = drm_vm_dma_nopage,
|
||||
.open = drm_vm_open,
|
||||
.close = drm_vm_close,
|
||||
};
|
||||
|
||||
/** Scatter-gather virtual memory operations */
|
||||
static struct vm_operations_struct drm_vm_sg_ops = {
|
||||
.nopage = drm_vm_sg_nopage,
|
||||
.open = drm_vm_open,
|
||||
.close = drm_vm_close,
|
||||
};
|
||||
|
||||
/**
|
||||
* \c open method for shared virtual memory.
|
||||
*
|
||||
* \param vma virtual memory area.
|
||||
*
|
||||
* Create a new drm_vma_entry structure as the \p vma private data entry and
|
||||
* add it to drm_device::vmalist.
|
||||
*/
|
||||
static void drm_vm_open(struct vm_area_struct *vma)
|
||||
{
|
||||
drm_file_t *priv = vma->vm_file->private_data;
|
||||
drm_device_t *dev = priv->head->dev;
|
||||
drm_vma_entry_t *vma_entry;
|
||||
|
||||
DRM_DEBUG("0x%08lx,0x%08lx\n",
|
||||
vma->vm_start, vma->vm_end - vma->vm_start);
|
||||
atomic_inc(&dev->vma_count);
|
||||
|
||||
vma_entry = drm_alloc(sizeof(*vma_entry), DRM_MEM_VMAS);
|
||||
if (vma_entry) {
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
vma_entry->vma = vma;
|
||||
vma_entry->next = dev->vmalist;
|
||||
vma_entry->pid = current->pid;
|
||||
dev->vmalist = vma_entry;
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \c close method for all virtual memory types.
|
||||
*
|
||||
* \param vma virtual memory area.
|
||||
*
|
||||
* Search the \p vma private data entry in drm_device::vmalist, unlink it, and
|
||||
* free it.
|
||||
*/
|
||||
static void drm_vm_close(struct vm_area_struct *vma)
|
||||
{
|
||||
drm_file_t *priv = vma->vm_file->private_data;
|
||||
drm_device_t *dev = priv->head->dev;
|
||||
drm_vma_entry_t *pt, *prev;
|
||||
|
||||
DRM_DEBUG("0x%08lx,0x%08lx\n",
|
||||
vma->vm_start, vma->vm_end - vma->vm_start);
|
||||
atomic_dec(&dev->vma_count);
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
for (pt = dev->vmalist, prev = NULL; pt; prev = pt, pt = pt->next) {
|
||||
if (pt->vma == vma) {
|
||||
if (prev) {
|
||||
prev->next = pt->next;
|
||||
} else {
|
||||
dev->vmalist = pt->next;
|
||||
}
|
||||
drm_free(pt, sizeof(*pt), DRM_MEM_VMAS);
|
||||
break;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
}
|
||||
|
||||
/**
|
||||
* mmap DMA memory.
|
||||
*
|
||||
* \param filp file pointer.
|
||||
* \param vma virtual memory area.
|
||||
* \return zero on success or a negative number on failure.
|
||||
*
|
||||
* Sets the virtual memory area operations structure to vm_dma_ops, the file
|
||||
* pointer, and calls vm_open().
|
||||
*/
|
||||
static int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma)
|
||||
{
|
||||
drm_file_t *priv = filp->private_data;
|
||||
drm_device_t *dev;
|
||||
drm_device_dma_t *dma;
|
||||
unsigned long length = vma->vm_end - vma->vm_start;
|
||||
|
||||
lock_kernel();
|
||||
dev = priv->head->dev;
|
||||
dma = dev->dma;
|
||||
DRM_DEBUG("start = 0x%lx, end = 0x%lx, page offset = 0x%lx\n",
|
||||
vma->vm_start, vma->vm_end, vma->vm_pgoff);
|
||||
|
||||
/* Length must match exact page count */
|
||||
if (!dma || (length >> PAGE_SHIFT) != dma->page_count) {
|
||||
unlock_kernel();
|
||||
return -EINVAL;
|
||||
}
|
||||
unlock_kernel();
|
||||
|
||||
if (!capable(CAP_SYS_ADMIN) &&
|
||||
(dma->flags & _DRM_DMA_USE_PCI_RO)) {
|
||||
vma->vm_flags &= ~(VM_WRITE | VM_MAYWRITE);
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
pgprot_val(vma->vm_page_prot) &= ~_PAGE_RW;
|
||||
#else
|
||||
/* Ye gads this is ugly. With more thought
|
||||
we could move this up higher and use
|
||||
`protection_map' instead. */
|
||||
vma->vm_page_prot =
|
||||
__pgprot(pte_val
|
||||
(pte_wrprotect
|
||||
(__pte(pgprot_val(vma->vm_page_prot)))));
|
||||
#endif
|
||||
}
|
||||
|
||||
vma->vm_ops = &drm_vm_dma_ops;
|
||||
|
||||
vma->vm_flags |= VM_RESERVED; /* Don't swap */
|
||||
|
||||
vma->vm_file = filp; /* Needed for drm_vm_open() */
|
||||
drm_vm_open(vma);
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned long drm_core_get_map_ofs(drm_map_t * map)
|
||||
{
|
||||
return map->offset;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(drm_core_get_map_ofs);
|
||||
|
||||
unsigned long drm_core_get_reg_ofs(struct drm_device *dev)
|
||||
{
|
||||
#ifdef __alpha__
|
||||
return dev->hose->dense_mem_base - dev->hose->mem_space->start;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(drm_core_get_reg_ofs);
|
||||
|
||||
/**
|
||||
* mmap DMA memory.
|
||||
*
|
||||
* \param filp file pointer.
|
||||
* \param vma virtual memory area.
|
||||
* \return zero on success or a negative number on failure.
|
||||
*
|
||||
* If the virtual memory area has no offset associated with it then it's a DMA
|
||||
* area, so calls mmap_dma(). Otherwise searches the map in drm_device::maplist,
|
||||
* checks that the restricted flag is not set, sets the virtual memory operations
|
||||
* according to the mapping type and remaps the pages. Finally sets the file
|
||||
* pointer and calls vm_open().
|
||||
*/
|
||||
int drm_mmap(struct file *filp, struct vm_area_struct *vma)
|
||||
{
|
||||
drm_file_t *priv = filp->private_data;
|
||||
drm_device_t *dev = priv->head->dev;
|
||||
drm_map_t *map = NULL;
|
||||
unsigned long offset = 0;
|
||||
drm_hash_item_t *hash;
|
||||
|
||||
DRM_DEBUG("start = 0x%lx, end = 0x%lx, page offset = 0x%lx\n",
|
||||
vma->vm_start, vma->vm_end, vma->vm_pgoff);
|
||||
|
||||
if (!priv->authenticated)
|
||||
return -EACCES;
|
||||
|
||||
/* We check for "dma". On Apple's UniNorth, it's valid to have
|
||||
* the AGP mapped at physical address 0
|
||||
* --BenH.
|
||||
*/
|
||||
if (!vma->vm_pgoff
|
||||
#if __OS_HAS_AGP
|
||||
&& (!dev->agp
|
||||
|| dev->agp->agp_info.device->vendor != PCI_VENDOR_ID_APPLE)
|
||||
#endif
|
||||
)
|
||||
return drm_mmap_dma(filp, vma);
|
||||
|
||||
if (drm_ht_find_item(&dev->map_hash, vma->vm_pgoff, &hash)) {
|
||||
DRM_ERROR("Could not find map\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
map = drm_hash_entry(hash, drm_map_list_t, hash)->map;
|
||||
if (!map || ((map->flags & _DRM_RESTRICTED) && !capable(CAP_SYS_ADMIN)))
|
||||
return -EPERM;
|
||||
|
||||
/* Check for valid size. */
|
||||
if (map->size != vma->vm_end - vma->vm_start)
|
||||
return -EINVAL;
|
||||
|
||||
if (!capable(CAP_SYS_ADMIN) && (map->flags & _DRM_READ_ONLY)) {
|
||||
vma->vm_flags &= ~(VM_WRITE | VM_MAYWRITE);
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
pgprot_val(vma->vm_page_prot) &= ~_PAGE_RW;
|
||||
#else
|
||||
/* Ye gads this is ugly. With more thought
|
||||
we could move this up higher and use
|
||||
`protection_map' instead. */
|
||||
vma->vm_page_prot =
|
||||
__pgprot(pte_val
|
||||
(pte_wrprotect
|
||||
(__pte(pgprot_val(vma->vm_page_prot)))));
|
||||
#endif
|
||||
}
|
||||
|
||||
switch (map->type) {
|
||||
case _DRM_AGP:
|
||||
if (drm_core_has_AGP(dev) && dev->agp->cant_use_aperture) {
|
||||
/*
|
||||
* On some platforms we can't talk to bus dma address from the CPU, so for
|
||||
* memory of type DRM_AGP, we'll deal with sorting out the real physical
|
||||
* pages and mappings in nopage()
|
||||
*/
|
||||
#if defined(__powerpc__)
|
||||
pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE;
|
||||
#endif
|
||||
vma->vm_ops = &drm_vm_ops;
|
||||
break;
|
||||
}
|
||||
/* fall through to _DRM_FRAME_BUFFER... */
|
||||
case _DRM_FRAME_BUFFER:
|
||||
case _DRM_REGISTERS:
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
if (boot_cpu_data.x86 > 3 && map->type != _DRM_AGP) {
|
||||
pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
|
||||
pgprot_val(vma->vm_page_prot) &= ~_PAGE_PWT;
|
||||
}
|
||||
#elif defined(__powerpc__)
|
||||
pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE;
|
||||
if (map->type == _DRM_REGISTERS)
|
||||
pgprot_val(vma->vm_page_prot) |= _PAGE_GUARDED;
|
||||
#endif
|
||||
vma->vm_flags |= VM_IO; /* not in core dump */
|
||||
#if defined(__ia64__)
|
||||
if (efi_range_is_wc(vma->vm_start, vma->vm_end - vma->vm_start))
|
||||
vma->vm_page_prot =
|
||||
pgprot_writecombine(vma->vm_page_prot);
|
||||
else
|
||||
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
|
||||
#endif
|
||||
offset = dev->driver->get_reg_ofs(dev);
|
||||
#ifdef __sparc__
|
||||
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
|
||||
if (io_remap_pfn_range(vma, vma->vm_start,
|
||||
(map->offset + offset) >> PAGE_SHIFT,
|
||||
vma->vm_end - vma->vm_start,
|
||||
vma->vm_page_prot))
|
||||
#else
|
||||
if (io_remap_pfn_range(vma, vma->vm_start,
|
||||
(map->offset + offset) >> PAGE_SHIFT,
|
||||
vma->vm_end - vma->vm_start,
|
||||
vma->vm_page_prot))
|
||||
#endif
|
||||
return -EAGAIN;
|
||||
DRM_DEBUG(" Type = %d; start = 0x%lx, end = 0x%lx,"
|
||||
" offset = 0x%lx\n",
|
||||
map->type,
|
||||
vma->vm_start, vma->vm_end, map->offset + offset);
|
||||
vma->vm_ops = &drm_vm_ops;
|
||||
break;
|
||||
case _DRM_SHM:
|
||||
case _DRM_CONSISTENT:
|
||||
/* Consistent memory is really like shared memory. It's only
|
||||
* allocate in a different way */
|
||||
vma->vm_ops = &drm_vm_shm_ops;
|
||||
vma->vm_private_data = (void *)map;
|
||||
/* Don't let this area swap. Change when
|
||||
DRM_KERNEL advisory is supported. */
|
||||
vma->vm_flags |= VM_RESERVED;
|
||||
break;
|
||||
case _DRM_SCATTER_GATHER:
|
||||
vma->vm_ops = &drm_vm_sg_ops;
|
||||
vma->vm_private_data = (void *)map;
|
||||
vma->vm_flags |= VM_RESERVED;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL; /* This should never happen. */
|
||||
}
|
||||
vma->vm_flags |= VM_RESERVED; /* Don't swap */
|
||||
|
||||
vma->vm_file = filp; /* Needed for drm_vm_open() */
|
||||
drm_vm_open(vma);
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(drm_mmap);
|
||||
1405
drivers/char/drm/i810_dma.c
Normal file
1405
drivers/char/drm/i810_dma.c
Normal file
File diff suppressed because it is too large
Load Diff
286
drivers/char/drm/i810_drm.h
Normal file
286
drivers/char/drm/i810_drm.h
Normal file
@@ -0,0 +1,286 @@
|
||||
#ifndef _I810_DRM_H_
|
||||
#define _I810_DRM_H_
|
||||
|
||||
/* WARNING: These defines must be the same as what the Xserver uses.
|
||||
* if you change them, you must change the defines in the Xserver.
|
||||
*/
|
||||
|
||||
#ifndef _I810_DEFINES_
|
||||
#define _I810_DEFINES_
|
||||
|
||||
#define I810_DMA_BUF_ORDER 12
|
||||
#define I810_DMA_BUF_SZ (1<<I810_DMA_BUF_ORDER)
|
||||
#define I810_DMA_BUF_NR 256
|
||||
#define I810_NR_SAREA_CLIPRECTS 8
|
||||
|
||||
/* Each region is a minimum of 64k, and there are at most 64 of them.
|
||||
*/
|
||||
#define I810_NR_TEX_REGIONS 64
|
||||
#define I810_LOG_MIN_TEX_REGION_SIZE 16
|
||||
#endif
|
||||
|
||||
#define I810_UPLOAD_TEX0IMAGE 0x1 /* handled clientside */
|
||||
#define I810_UPLOAD_TEX1IMAGE 0x2 /* handled clientside */
|
||||
#define I810_UPLOAD_CTX 0x4
|
||||
#define I810_UPLOAD_BUFFERS 0x8
|
||||
#define I810_UPLOAD_TEX0 0x10
|
||||
#define I810_UPLOAD_TEX1 0x20
|
||||
#define I810_UPLOAD_CLIPRECTS 0x40
|
||||
|
||||
/* Indices into buf.Setup where various bits of state are mirrored per
|
||||
* context and per buffer. These can be fired at the card as a unit,
|
||||
* or in a piecewise fashion as required.
|
||||
*/
|
||||
|
||||
/* Destbuffer state
|
||||
* - backbuffer linear offset and pitch -- invarient in the current dri
|
||||
* - zbuffer linear offset and pitch -- also invarient
|
||||
* - drawing origin in back and depth buffers.
|
||||
*
|
||||
* Keep the depth/back buffer state here to accommodate private buffers
|
||||
* in the future.
|
||||
*/
|
||||
#define I810_DESTREG_DI0 0 /* CMD_OP_DESTBUFFER_INFO (2 dwords) */
|
||||
#define I810_DESTREG_DI1 1
|
||||
#define I810_DESTREG_DV0 2 /* GFX_OP_DESTBUFFER_VARS (2 dwords) */
|
||||
#define I810_DESTREG_DV1 3
|
||||
#define I810_DESTREG_DR0 4 /* GFX_OP_DRAWRECT_INFO (4 dwords) */
|
||||
#define I810_DESTREG_DR1 5
|
||||
#define I810_DESTREG_DR2 6
|
||||
#define I810_DESTREG_DR3 7
|
||||
#define I810_DESTREG_DR4 8
|
||||
#define I810_DEST_SETUP_SIZE 10
|
||||
|
||||
/* Context state
|
||||
*/
|
||||
#define I810_CTXREG_CF0 0 /* GFX_OP_COLOR_FACTOR */
|
||||
#define I810_CTXREG_CF1 1
|
||||
#define I810_CTXREG_ST0 2 /* GFX_OP_STIPPLE */
|
||||
#define I810_CTXREG_ST1 3
|
||||
#define I810_CTXREG_VF 4 /* GFX_OP_VERTEX_FMT */
|
||||
#define I810_CTXREG_MT 5 /* GFX_OP_MAP_TEXELS */
|
||||
#define I810_CTXREG_MC0 6 /* GFX_OP_MAP_COLOR_STAGES - stage 0 */
|
||||
#define I810_CTXREG_MC1 7 /* GFX_OP_MAP_COLOR_STAGES - stage 1 */
|
||||
#define I810_CTXREG_MC2 8 /* GFX_OP_MAP_COLOR_STAGES - stage 2 */
|
||||
#define I810_CTXREG_MA0 9 /* GFX_OP_MAP_ALPHA_STAGES - stage 0 */
|
||||
#define I810_CTXREG_MA1 10 /* GFX_OP_MAP_ALPHA_STAGES - stage 1 */
|
||||
#define I810_CTXREG_MA2 11 /* GFX_OP_MAP_ALPHA_STAGES - stage 2 */
|
||||
#define I810_CTXREG_SDM 12 /* GFX_OP_SRC_DEST_MONO */
|
||||
#define I810_CTXREG_FOG 13 /* GFX_OP_FOG_COLOR */
|
||||
#define I810_CTXREG_B1 14 /* GFX_OP_BOOL_1 */
|
||||
#define I810_CTXREG_B2 15 /* GFX_OP_BOOL_2 */
|
||||
#define I810_CTXREG_LCS 16 /* GFX_OP_LINEWIDTH_CULL_SHADE_MODE */
|
||||
#define I810_CTXREG_PV 17 /* GFX_OP_PV_RULE -- Invarient! */
|
||||
#define I810_CTXREG_ZA 18 /* GFX_OP_ZBIAS_ALPHAFUNC */
|
||||
#define I810_CTXREG_AA 19 /* GFX_OP_ANTIALIAS */
|
||||
#define I810_CTX_SETUP_SIZE 20
|
||||
|
||||
/* Texture state (per tex unit)
|
||||
*/
|
||||
#define I810_TEXREG_MI0 0 /* GFX_OP_MAP_INFO (4 dwords) */
|
||||
#define I810_TEXREG_MI1 1
|
||||
#define I810_TEXREG_MI2 2
|
||||
#define I810_TEXREG_MI3 3
|
||||
#define I810_TEXREG_MF 4 /* GFX_OP_MAP_FILTER */
|
||||
#define I810_TEXREG_MLC 5 /* GFX_OP_MAP_LOD_CTL */
|
||||
#define I810_TEXREG_MLL 6 /* GFX_OP_MAP_LOD_LIMITS */
|
||||
#define I810_TEXREG_MCS 7 /* GFX_OP_MAP_COORD_SETS ??? */
|
||||
#define I810_TEX_SETUP_SIZE 8
|
||||
|
||||
/* Flags for clear ioctl
|
||||
*/
|
||||
#define I810_FRONT 0x1
|
||||
#define I810_BACK 0x2
|
||||
#define I810_DEPTH 0x4
|
||||
|
||||
typedef enum _drm_i810_init_func {
|
||||
I810_INIT_DMA = 0x01,
|
||||
I810_CLEANUP_DMA = 0x02,
|
||||
I810_INIT_DMA_1_4 = 0x03
|
||||
} drm_i810_init_func_t;
|
||||
|
||||
/* This is the init structure after v1.2 */
|
||||
typedef struct _drm_i810_init {
|
||||
drm_i810_init_func_t func;
|
||||
#if CONFIG_XFREE86_VERSION < XFREE86_VERSION(4,1,0,0)
|
||||
int ring_map_idx;
|
||||
int buffer_map_idx;
|
||||
#else
|
||||
unsigned int mmio_offset;
|
||||
unsigned int buffers_offset;
|
||||
#endif
|
||||
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 overlay_offset;
|
||||
unsigned int overlay_physical;
|
||||
unsigned int w;
|
||||
unsigned int h;
|
||||
unsigned int pitch;
|
||||
unsigned int pitch_bits;
|
||||
} drm_i810_init_t;
|
||||
|
||||
/* This is the init structure prior to v1.2 */
|
||||
typedef struct _drm_i810_pre12_init {
|
||||
drm_i810_init_func_t func;
|
||||
unsigned int mmio_offset;
|
||||
unsigned int buffers_offset;
|
||||
int sarea_priv_offset;
|
||||
unsigned int ring_start;
|
||||
unsigned int ring_end;
|
||||
unsigned int ring_size;
|
||||
unsigned int front_offset;
|
||||
unsigned int back_offset;
|
||||
unsigned int depth_offset;
|
||||
unsigned int w;
|
||||
unsigned int h;
|
||||
unsigned int pitch;
|
||||
unsigned int pitch_bits;
|
||||
} drm_i810_pre12_init_t;
|
||||
|
||||
/* Warning: If you change the SAREA structure you must change the Xserver
|
||||
* structure as well */
|
||||
|
||||
typedef struct _drm_i810_tex_region {
|
||||
unsigned char next, prev; /* indices to form a circular LRU */
|
||||
unsigned char in_use; /* owned by a client, or free? */
|
||||
int age; /* tracked by clients to update local LRU's */
|
||||
} drm_i810_tex_region_t;
|
||||
|
||||
typedef struct _drm_i810_sarea {
|
||||
unsigned int ContextState[I810_CTX_SETUP_SIZE];
|
||||
unsigned int BufferState[I810_DEST_SETUP_SIZE];
|
||||
unsigned int TexState[2][I810_TEX_SETUP_SIZE];
|
||||
unsigned int dirty;
|
||||
|
||||
unsigned int nbox;
|
||||
drm_clip_rect_t boxes[I810_NR_SAREA_CLIPRECTS];
|
||||
|
||||
/* Maintain an LRU of contiguous regions of texture space. If
|
||||
* you think you own a region of texture memory, and it has an
|
||||
* age different to the one you set, then you are mistaken and
|
||||
* it has been stolen by another client. If global texAge
|
||||
* hasn't changed, there is no need to walk the list.
|
||||
*
|
||||
* These regions can be used as a proxy for the fine-grained
|
||||
* texture information of other clients - by maintaining them
|
||||
* in the same lru which is used to age their own textures,
|
||||
* clients have an approximate lru for the whole of global
|
||||
* texture space, and can make informed decisions as to which
|
||||
* areas to kick out. There is no need to choose whether to
|
||||
* kick out your own texture or someone else's - simply eject
|
||||
* them all in LRU order.
|
||||
*/
|
||||
|
||||
drm_i810_tex_region_t texList[I810_NR_TEX_REGIONS + 1];
|
||||
/* Last elt is sentinal */
|
||||
int texAge; /* last time texture was uploaded */
|
||||
int last_enqueue; /* last time a buffer was enqueued */
|
||||
int last_dispatch; /* age of the most recently dispatched buffer */
|
||||
int last_quiescent; /* */
|
||||
int ctxOwner; /* last context to upload state */
|
||||
|
||||
int vertex_prim;
|
||||
|
||||
int pf_enabled; /* is pageflipping allowed? */
|
||||
int pf_active;
|
||||
int pf_current_page; /* which buffer is being displayed? */
|
||||
} drm_i810_sarea_t;
|
||||
|
||||
/* WARNING: If you change any of these defines, make sure to change the
|
||||
* defines in the Xserver file (xf86drmMga.h)
|
||||
*/
|
||||
|
||||
/* i810 specific ioctls
|
||||
* The device specific ioctl range is 0x40 to 0x79.
|
||||
*/
|
||||
#define DRM_I810_INIT 0x00
|
||||
#define DRM_I810_VERTEX 0x01
|
||||
#define DRM_I810_CLEAR 0x02
|
||||
#define DRM_I810_FLUSH 0x03
|
||||
#define DRM_I810_GETAGE 0x04
|
||||
#define DRM_I810_GETBUF 0x05
|
||||
#define DRM_I810_SWAP 0x06
|
||||
#define DRM_I810_COPY 0x07
|
||||
#define DRM_I810_DOCOPY 0x08
|
||||
#define DRM_I810_OV0INFO 0x09
|
||||
#define DRM_I810_FSTATUS 0x0a
|
||||
#define DRM_I810_OV0FLIP 0x0b
|
||||
#define DRM_I810_MC 0x0c
|
||||
#define DRM_I810_RSTATUS 0x0d
|
||||
#define DRM_I810_FLIP 0x0e
|
||||
|
||||
#define DRM_IOCTL_I810_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_I810_INIT, drm_i810_init_t)
|
||||
#define DRM_IOCTL_I810_VERTEX DRM_IOW( DRM_COMMAND_BASE + DRM_I810_VERTEX, drm_i810_vertex_t)
|
||||
#define DRM_IOCTL_I810_CLEAR DRM_IOW( DRM_COMMAND_BASE + DRM_I810_CLEAR, drm_i810_clear_t)
|
||||
#define DRM_IOCTL_I810_FLUSH DRM_IO( DRM_COMMAND_BASE + DRM_I810_FLUSH)
|
||||
#define DRM_IOCTL_I810_GETAGE DRM_IO( DRM_COMMAND_BASE + DRM_I810_GETAGE)
|
||||
#define DRM_IOCTL_I810_GETBUF DRM_IOWR(DRM_COMMAND_BASE + DRM_I810_GETBUF, drm_i810_dma_t)
|
||||
#define DRM_IOCTL_I810_SWAP DRM_IO( DRM_COMMAND_BASE + DRM_I810_SWAP)
|
||||
#define DRM_IOCTL_I810_COPY DRM_IOW( DRM_COMMAND_BASE + DRM_I810_COPY, drm_i810_copy_t)
|
||||
#define DRM_IOCTL_I810_DOCOPY DRM_IO( DRM_COMMAND_BASE + DRM_I810_DOCOPY)
|
||||
#define DRM_IOCTL_I810_OV0INFO DRM_IOR( DRM_COMMAND_BASE + DRM_I810_OV0INFO, drm_i810_overlay_t)
|
||||
#define DRM_IOCTL_I810_FSTATUS DRM_IO ( DRM_COMMAND_BASE + DRM_I810_FSTATUS)
|
||||
#define DRM_IOCTL_I810_OV0FLIP DRM_IO ( DRM_COMMAND_BASE + DRM_I810_OV0FLIP)
|
||||
#define DRM_IOCTL_I810_MC DRM_IOW( DRM_COMMAND_BASE + DRM_I810_MC, drm_i810_mc_t)
|
||||
#define DRM_IOCTL_I810_RSTATUS DRM_IO ( DRM_COMMAND_BASE + DRM_I810_RSTATUS)
|
||||
#define DRM_IOCTL_I810_FLIP DRM_IO ( DRM_COMMAND_BASE + DRM_I810_FLIP)
|
||||
|
||||
typedef struct _drm_i810_clear {
|
||||
int clear_color;
|
||||
int clear_depth;
|
||||
int flags;
|
||||
} drm_i810_clear_t;
|
||||
|
||||
/* These may be placeholders if we have more cliprects than
|
||||
* I810_NR_SAREA_CLIPRECTS. In that case, the client sets discard to
|
||||
* false, indicating that the buffer will be dispatched again with a
|
||||
* new set of cliprects.
|
||||
*/
|
||||
typedef struct _drm_i810_vertex {
|
||||
int idx; /* buffer index */
|
||||
int used; /* nr bytes in use */
|
||||
int discard; /* client is finished with the buffer? */
|
||||
} drm_i810_vertex_t;
|
||||
|
||||
typedef struct _drm_i810_copy_t {
|
||||
int idx; /* buffer index */
|
||||
int used; /* nr bytes in use */
|
||||
void *address; /* Address to copy from */
|
||||
} drm_i810_copy_t;
|
||||
|
||||
#define PR_TRIANGLES (0x0<<18)
|
||||
#define PR_TRISTRIP_0 (0x1<<18)
|
||||
#define PR_TRISTRIP_1 (0x2<<18)
|
||||
#define PR_TRIFAN (0x3<<18)
|
||||
#define PR_POLYGON (0x4<<18)
|
||||
#define PR_LINES (0x5<<18)
|
||||
#define PR_LINESTRIP (0x6<<18)
|
||||
#define PR_RECTS (0x7<<18)
|
||||
#define PR_MASK (0x7<<18)
|
||||
|
||||
typedef struct drm_i810_dma {
|
||||
void *virtual;
|
||||
int request_idx;
|
||||
int request_size;
|
||||
int granted;
|
||||
} drm_i810_dma_t;
|
||||
|
||||
typedef struct _drm_i810_overlay_t {
|
||||
unsigned int offset; /* Address of the Overlay Regs */
|
||||
unsigned int physical;
|
||||
} drm_i810_overlay_t;
|
||||
|
||||
typedef struct _drm_i810_mc {
|
||||
int idx; /* buffer index */
|
||||
int used; /* nr bytes in use */
|
||||
int num_blocks; /* number of GFXBlocks */
|
||||
int *length; /* List of lengths for GFXBlocks (FUTURE) */
|
||||
unsigned int last_render; /* Last Render Request */
|
||||
} drm_i810_mc_t;
|
||||
|
||||
#endif /* _I810_DRM_H_ */
|
||||
97
drivers/char/drm/i810_drv.c
Normal file
97
drivers/char/drm/i810_drv.c
Normal file
@@ -0,0 +1,97 @@
|
||||
/* i810_drv.c -- I810 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>
|
||||
* Jeff Hartmann <jhartmann@valinux.com>
|
||||
* Gareth Hughes <gareth@valinux.com>
|
||||
*/
|
||||
|
||||
#include "drmP.h"
|
||||
#include "drm.h"
|
||||
#include "i810_drm.h"
|
||||
#include "i810_drv.h"
|
||||
|
||||
#include "drm_pciids.h"
|
||||
|
||||
static struct pci_device_id pciidlist[] = {
|
||||
i810_PCI_IDS
|
||||
};
|
||||
|
||||
static struct drm_driver driver = {
|
||||
.driver_features =
|
||||
DRIVER_USE_AGP | DRIVER_REQUIRE_AGP | DRIVER_USE_MTRR |
|
||||
DRIVER_HAVE_DMA | DRIVER_DMA_QUEUE,
|
||||
.dev_priv_size = sizeof(drm_i810_buf_priv_t),
|
||||
.load = i810_driver_load,
|
||||
.lastclose = i810_driver_lastclose,
|
||||
.preclose = i810_driver_preclose,
|
||||
.device_is_agp = i810_driver_device_is_agp,
|
||||
.reclaim_buffers_locked = i810_driver_reclaim_buffers_locked,
|
||||
.dma_quiescent = i810_driver_dma_quiescent,
|
||||
.get_map_ofs = drm_core_get_map_ofs,
|
||||
.get_reg_ofs = drm_core_get_reg_ofs,
|
||||
.ioctls = i810_ioctls,
|
||||
.fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = drm_open,
|
||||
.release = drm_release,
|
||||
.ioctl = drm_ioctl,
|
||||
.mmap = drm_mmap,
|
||||
.poll = drm_poll,
|
||||
.fasync = drm_fasync,
|
||||
},
|
||||
|
||||
.pci_driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.id_table = pciidlist,
|
||||
},
|
||||
|
||||
.name = DRIVER_NAME,
|
||||
.desc = DRIVER_DESC,
|
||||
.date = DRIVER_DATE,
|
||||
.major = DRIVER_MAJOR,
|
||||
.minor = DRIVER_MINOR,
|
||||
.patchlevel = DRIVER_PATCHLEVEL,
|
||||
};
|
||||
|
||||
static int __init i810_init(void)
|
||||
{
|
||||
driver.num_ioctls = i810_max_ioctl;
|
||||
return drm_init(&driver);
|
||||
}
|
||||
|
||||
static void __exit i810_exit(void)
|
||||
{
|
||||
drm_exit(&driver);
|
||||
}
|
||||
|
||||
module_init(i810_init);
|
||||
module_exit(i810_exit);
|
||||
|
||||
MODULE_AUTHOR(DRIVER_AUTHOR);
|
||||
MODULE_DESCRIPTION(DRIVER_DESC);
|
||||
MODULE_LICENSE("GPL and additional rights");
|
||||
241
drivers/char/drm/i810_drv.h
Normal file
241
drivers/char/drm/i810_drv.h
Normal file
@@ -0,0 +1,241 @@
|
||||
/* i810_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
|
||||
* PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors: Rickard E. (Rik) Faith <faith@valinux.com>
|
||||
* Jeff Hartmann <jhartmann@valinux.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _I810_DRV_H_
|
||||
#define _I810_DRV_H_
|
||||
|
||||
/* General customization:
|
||||
*/
|
||||
|
||||
#define DRIVER_AUTHOR "VA Linux Systems Inc."
|
||||
|
||||
#define DRIVER_NAME "i810"
|
||||
#define DRIVER_DESC "Intel i810"
|
||||
#define DRIVER_DATE "20030605"
|
||||
|
||||
/* Interface history
|
||||
*
|
||||
* 1.1 - XFree86 4.1
|
||||
* 1.2 - XvMC interfaces
|
||||
* - XFree86 4.2
|
||||
* 1.2.1 - Disable copying code (leave stub ioctls for backwards compatibility)
|
||||
* - Remove requirement for interrupt (leave stubs again)
|
||||
* 1.3 - Add page flipping.
|
||||
* 1.4 - fix DRM interface
|
||||
*/
|
||||
#define DRIVER_MAJOR 1
|
||||
#define DRIVER_MINOR 4
|
||||
#define DRIVER_PATCHLEVEL 0
|
||||
|
||||
typedef struct drm_i810_buf_priv {
|
||||
u32 *in_use;
|
||||
int my_use_idx;
|
||||
int currently_mapped;
|
||||
void *virtual;
|
||||
void *kernel_virtual;
|
||||
drm_local_map_t map;
|
||||
} drm_i810_buf_priv_t;
|
||||
|
||||
typedef struct _drm_i810_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_i810_ring_buffer_t;
|
||||
|
||||
typedef struct drm_i810_private {
|
||||
drm_map_t *sarea_map;
|
||||
drm_map_t *mmio_map;
|
||||
|
||||
drm_i810_sarea_t *sarea_priv;
|
||||
drm_i810_ring_buffer_t ring;
|
||||
|
||||
void *hw_status_page;
|
||||
unsigned long counter;
|
||||
|
||||
dma_addr_t dma_status_page;
|
||||
|
||||
drm_buf_t *mmap_buffer;
|
||||
|
||||
u32 front_di1, back_di1, zi1;
|
||||
|
||||
int back_offset;
|
||||
int depth_offset;
|
||||
int overlay_offset;
|
||||
int overlay_physical;
|
||||
int w, h;
|
||||
int pitch;
|
||||
int back_pitch;
|
||||
int depth_pitch;
|
||||
|
||||
int do_boxes;
|
||||
int dma_used;
|
||||
|
||||
int current_page;
|
||||
int page_flipping;
|
||||
|
||||
wait_queue_head_t irq_queue;
|
||||
atomic_t irq_received;
|
||||
atomic_t irq_emitted;
|
||||
|
||||
int front_offset;
|
||||
} drm_i810_private_t;
|
||||
|
||||
/* i810_dma.c */
|
||||
extern int i810_driver_dma_quiescent(drm_device_t * dev);
|
||||
extern void i810_driver_reclaim_buffers_locked(drm_device_t * dev,
|
||||
struct file *filp);
|
||||
extern int i810_driver_load(struct drm_device *, unsigned long flags);
|
||||
extern void i810_driver_lastclose(drm_device_t * dev);
|
||||
extern void i810_driver_preclose(drm_device_t * dev, DRMFILE filp);
|
||||
extern void i810_driver_reclaim_buffers_locked(drm_device_t * dev,
|
||||
struct file *filp);
|
||||
extern int i810_driver_device_is_agp(drm_device_t * dev);
|
||||
|
||||
extern drm_ioctl_desc_t i810_ioctls[];
|
||||
extern int i810_max_ioctl;
|
||||
|
||||
#define I810_BASE(reg) ((unsigned long) \
|
||||
dev_priv->mmio_map->handle)
|
||||
#define I810_ADDR(reg) (I810_BASE(reg) + reg)
|
||||
#define I810_DEREF(reg) *(__volatile__ int *)I810_ADDR(reg)
|
||||
#define I810_READ(reg) I810_DEREF(reg)
|
||||
#define I810_WRITE(reg,val) do { I810_DEREF(reg) = val; } while (0)
|
||||
#define I810_DEREF16(reg) *(__volatile__ u16 *)I810_ADDR(reg)
|
||||
#define I810_READ16(reg) I810_DEREF16(reg)
|
||||
#define I810_WRITE16(reg,val) do { I810_DEREF16(reg) = val; } while (0)
|
||||
|
||||
#define I810_VERBOSE 0
|
||||
#define RING_LOCALS unsigned int outring, ringmask; \
|
||||
volatile char *virt;
|
||||
|
||||
#define BEGIN_LP_RING(n) do { \
|
||||
if (I810_VERBOSE) \
|
||||
DRM_DEBUG("BEGIN_LP_RING(%d) in %s\n", n, __FUNCTION__); \
|
||||
if (dev_priv->ring.space < n*4) \
|
||||
i810_wait_ring(dev, n*4); \
|
||||
dev_priv->ring.space -= n*4; \
|
||||
outring = dev_priv->ring.tail; \
|
||||
ringmask = dev_priv->ring.tail_mask; \
|
||||
virt = dev_priv->ring.virtual_start; \
|
||||
} while (0)
|
||||
|
||||
#define ADVANCE_LP_RING() do { \
|
||||
if (I810_VERBOSE) DRM_DEBUG("ADVANCE_LP_RING\n"); \
|
||||
dev_priv->ring.tail = outring; \
|
||||
I810_WRITE(LP_RING + RING_TAIL, outring); \
|
||||
} while(0)
|
||||
|
||||
#define OUT_RING(n) do { \
|
||||
if (I810_VERBOSE) DRM_DEBUG(" OUT_RING %x\n", (int)(n)); \
|
||||
*(volatile unsigned int *)(virt + outring) = n; \
|
||||
outring += 4; \
|
||||
outring &= ringmask; \
|
||||
} while (0)
|
||||
|
||||
#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 I810REG_HWSTAM 0x02098
|
||||
#define I810REG_INT_IDENTITY_R 0x020a4
|
||||
#define I810REG_INT_MASK_R 0x020a8
|
||||
#define I810REG_INT_ENABLE_R 0x020a0
|
||||
|
||||
#define LP_RING 0x2030
|
||||
#define HP_RING 0x2040
|
||||
#define RING_TAIL 0x00
|
||||
#define TAIL_ADDR 0x000FFFF8
|
||||
#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 0x00FFFFF8
|
||||
#define RING_LEN 0x0C
|
||||
#define RING_NR_PAGES 0x000FF000
|
||||
#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_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)|0x2)
|
||||
#define GFX_OP_DESTBUFFER_VARS ((0x3<<29)|(0x1d<<24)|(0x85<<16)|0x0)
|
||||
#define GFX_OP_DRAWRECT_INFO ((0x3<<29)|(0x1d<<24)|(0x80<<16)|(0x3))
|
||||
#define GFX_OP_PRIMITIVE ((0x3<<29)|(0x1f<<24))
|
||||
|
||||
#define CMD_OP_Z_BUFFER_INFO ((0x0<<29)|(0x16<<23))
|
||||
#define CMD_OP_DESTBUFFER_INFO ((0x0<<29)|(0x15<<23))
|
||||
#define CMD_OP_FRONTBUFFER_INFO ((0x0<<29)|(0x14<<23))
|
||||
#define CMD_OP_WAIT_FOR_EVENT ((0x0<<29)|(0x03<<23))
|
||||
|
||||
#define BR00_BITBLT_CLIENT 0x40000000
|
||||
#define BR00_OP_COLOR_BLT 0x10000000
|
||||
#define BR00_OP_SRC_COPY_BLT 0x10C00000
|
||||
#define BR13_SOLID_PATTERN 0x80000000
|
||||
|
||||
#define WAIT_FOR_PLANE_A_SCANLINES (1<<1)
|
||||
#define WAIT_FOR_PLANE_A_FLIP (1<<2)
|
||||
#define WAIT_FOR_VBLANK (1<<3)
|
||||
|
||||
#endif
|
||||
1600
drivers/char/drm/i830_dma.c
Normal file
1600
drivers/char/drm/i830_dma.c
Normal file
File diff suppressed because it is too large
Load Diff
342
drivers/char/drm/i830_drm.h
Normal file
342
drivers/char/drm/i830_drm.h
Normal file
@@ -0,0 +1,342 @@
|
||||
#ifndef _I830_DRM_H_
|
||||
#define _I830_DRM_H_
|
||||
|
||||
/* WARNING: These defines must be the same as what the Xserver uses.
|
||||
* if you change them, you must change the defines in the Xserver.
|
||||
*
|
||||
* KW: Actually, you can't ever change them because doing so would
|
||||
* break backwards compatibility.
|
||||
*/
|
||||
|
||||
#ifndef _I830_DEFINES_
|
||||
#define _I830_DEFINES_
|
||||
|
||||
#define I830_DMA_BUF_ORDER 12
|
||||
#define I830_DMA_BUF_SZ (1<<I830_DMA_BUF_ORDER)
|
||||
#define I830_DMA_BUF_NR 256
|
||||
#define I830_NR_SAREA_CLIPRECTS 8
|
||||
|
||||
/* Each region is a minimum of 64k, and there are at most 64 of them.
|
||||
*/
|
||||
#define I830_NR_TEX_REGIONS 64
|
||||
#define I830_LOG_MIN_TEX_REGION_SIZE 16
|
||||
|
||||
/* KW: These aren't correct but someone set them to two and then
|
||||
* released the module. Now we can't change them as doing so would
|
||||
* break backwards compatibility.
|
||||
*/
|
||||
#define I830_TEXTURE_COUNT 2
|
||||
#define I830_TEXBLEND_COUNT I830_TEXTURE_COUNT
|
||||
|
||||
#define I830_TEXBLEND_SIZE 12 /* (4 args + op) * 2 + COLOR_FACTOR */
|
||||
|
||||
#define I830_UPLOAD_CTX 0x1
|
||||
#define I830_UPLOAD_BUFFERS 0x2
|
||||
#define I830_UPLOAD_CLIPRECTS 0x4
|
||||
#define I830_UPLOAD_TEX0_IMAGE 0x100 /* handled clientside */
|
||||
#define I830_UPLOAD_TEX0_CUBE 0x200 /* handled clientside */
|
||||
#define I830_UPLOAD_TEX1_IMAGE 0x400 /* handled clientside */
|
||||
#define I830_UPLOAD_TEX1_CUBE 0x800 /* handled clientside */
|
||||
#define I830_UPLOAD_TEX2_IMAGE 0x1000 /* handled clientside */
|
||||
#define I830_UPLOAD_TEX2_CUBE 0x2000 /* handled clientside */
|
||||
#define I830_UPLOAD_TEX3_IMAGE 0x4000 /* handled clientside */
|
||||
#define I830_UPLOAD_TEX3_CUBE 0x8000 /* handled clientside */
|
||||
#define I830_UPLOAD_TEX_N_IMAGE(n) (0x100 << (n * 2))
|
||||
#define I830_UPLOAD_TEX_N_CUBE(n) (0x200 << (n * 2))
|
||||
#define I830_UPLOAD_TEXIMAGE_MASK 0xff00
|
||||
#define I830_UPLOAD_TEX0 0x10000
|
||||
#define I830_UPLOAD_TEX1 0x20000
|
||||
#define I830_UPLOAD_TEX2 0x40000
|
||||
#define I830_UPLOAD_TEX3 0x80000
|
||||
#define I830_UPLOAD_TEX_N(n) (0x10000 << (n))
|
||||
#define I830_UPLOAD_TEX_MASK 0xf0000
|
||||
#define I830_UPLOAD_TEXBLEND0 0x100000
|
||||
#define I830_UPLOAD_TEXBLEND1 0x200000
|
||||
#define I830_UPLOAD_TEXBLEND2 0x400000
|
||||
#define I830_UPLOAD_TEXBLEND3 0x800000
|
||||
#define I830_UPLOAD_TEXBLEND_N(n) (0x100000 << (n))
|
||||
#define I830_UPLOAD_TEXBLEND_MASK 0xf00000
|
||||
#define I830_UPLOAD_TEX_PALETTE_N(n) (0x1000000 << (n))
|
||||
#define I830_UPLOAD_TEX_PALETTE_SHARED 0x4000000
|
||||
#define I830_UPLOAD_STIPPLE 0x8000000
|
||||
|
||||
/* Indices into buf.Setup where various bits of state are mirrored per
|
||||
* context and per buffer. These can be fired at the card as a unit,
|
||||
* or in a piecewise fashion as required.
|
||||
*/
|
||||
|
||||
/* Destbuffer state
|
||||
* - backbuffer linear offset and pitch -- invarient in the current dri
|
||||
* - zbuffer linear offset and pitch -- also invarient
|
||||
* - drawing origin in back and depth buffers.
|
||||
*
|
||||
* Keep the depth/back buffer state here to accommodate private buffers
|
||||
* in the future.
|
||||
*/
|
||||
|
||||
#define I830_DESTREG_CBUFADDR 0
|
||||
#define I830_DESTREG_DBUFADDR 1
|
||||
#define I830_DESTREG_DV0 2
|
||||
#define I830_DESTREG_DV1 3
|
||||
#define I830_DESTREG_SENABLE 4
|
||||
#define I830_DESTREG_SR0 5
|
||||
#define I830_DESTREG_SR1 6
|
||||
#define I830_DESTREG_SR2 7
|
||||
#define I830_DESTREG_DR0 8
|
||||
#define I830_DESTREG_DR1 9
|
||||
#define I830_DESTREG_DR2 10
|
||||
#define I830_DESTREG_DR3 11
|
||||
#define I830_DESTREG_DR4 12
|
||||
#define I830_DEST_SETUP_SIZE 13
|
||||
|
||||
/* Context state
|
||||
*/
|
||||
#define I830_CTXREG_STATE1 0
|
||||
#define I830_CTXREG_STATE2 1
|
||||
#define I830_CTXREG_STATE3 2
|
||||
#define I830_CTXREG_STATE4 3
|
||||
#define I830_CTXREG_STATE5 4
|
||||
#define I830_CTXREG_IALPHAB 5
|
||||
#define I830_CTXREG_STENCILTST 6
|
||||
#define I830_CTXREG_ENABLES_1 7
|
||||
#define I830_CTXREG_ENABLES_2 8
|
||||
#define I830_CTXREG_AA 9
|
||||
#define I830_CTXREG_FOGCOLOR 10
|
||||
#define I830_CTXREG_BLENDCOLR0 11
|
||||
#define I830_CTXREG_BLENDCOLR 12 /* Dword 1 of 2 dword command */
|
||||
#define I830_CTXREG_VF 13
|
||||
#define I830_CTXREG_VF2 14
|
||||
#define I830_CTXREG_MCSB0 15
|
||||
#define I830_CTXREG_MCSB1 16
|
||||
#define I830_CTX_SETUP_SIZE 17
|
||||
|
||||
/* 1.3: Stipple state
|
||||
*/
|
||||
#define I830_STPREG_ST0 0
|
||||
#define I830_STPREG_ST1 1
|
||||
#define I830_STP_SETUP_SIZE 2
|
||||
|
||||
/* Texture state (per tex unit)
|
||||
*/
|
||||
|
||||
#define I830_TEXREG_MI0 0 /* GFX_OP_MAP_INFO (6 dwords) */
|
||||
#define I830_TEXREG_MI1 1
|
||||
#define I830_TEXREG_MI2 2
|
||||
#define I830_TEXREG_MI3 3
|
||||
#define I830_TEXREG_MI4 4
|
||||
#define I830_TEXREG_MI5 5
|
||||
#define I830_TEXREG_MF 6 /* GFX_OP_MAP_FILTER */
|
||||
#define I830_TEXREG_MLC 7 /* GFX_OP_MAP_LOD_CTL */
|
||||
#define I830_TEXREG_MLL 8 /* GFX_OP_MAP_LOD_LIMITS */
|
||||
#define I830_TEXREG_MCS 9 /* GFX_OP_MAP_COORD_SETS */
|
||||
#define I830_TEX_SETUP_SIZE 10
|
||||
|
||||
#define I830_TEXREG_TM0LI 0 /* load immediate 2 texture map n */
|
||||
#define I830_TEXREG_TM0S0 1
|
||||
#define I830_TEXREG_TM0S1 2
|
||||
#define I830_TEXREG_TM0S2 3
|
||||
#define I830_TEXREG_TM0S3 4
|
||||
#define I830_TEXREG_TM0S4 5
|
||||
#define I830_TEXREG_NOP0 6 /* noop */
|
||||
#define I830_TEXREG_NOP1 7 /* noop */
|
||||
#define I830_TEXREG_NOP2 8 /* noop */
|
||||
#define __I830_TEXREG_MCS 9 /* GFX_OP_MAP_COORD_SETS -- shared */
|
||||
#define __I830_TEX_SETUP_SIZE 10
|
||||
|
||||
#define I830_FRONT 0x1
|
||||
#define I830_BACK 0x2
|
||||
#define I830_DEPTH 0x4
|
||||
|
||||
#endif /* _I830_DEFINES_ */
|
||||
|
||||
typedef struct _drm_i830_init {
|
||||
enum {
|
||||
I830_INIT_DMA = 0x01,
|
||||
I830_CLEANUP_DMA = 0x02
|
||||
} func;
|
||||
unsigned int mmio_offset;
|
||||
unsigned int buffers_offset;
|
||||
int sarea_priv_offset;
|
||||
unsigned int ring_start;
|
||||
unsigned int ring_end;
|
||||
unsigned int ring_size;
|
||||
unsigned int front_offset;
|
||||
unsigned int back_offset;
|
||||
unsigned int depth_offset;
|
||||
unsigned int w;
|
||||
unsigned int h;
|
||||
unsigned int pitch;
|
||||
unsigned int pitch_bits;
|
||||
unsigned int back_pitch;
|
||||
unsigned int depth_pitch;
|
||||
unsigned int cpp;
|
||||
} drm_i830_init_t;
|
||||
|
||||
/* Warning: If you change the SAREA structure you must change the Xserver
|
||||
* structure as well */
|
||||
|
||||
typedef struct _drm_i830_tex_region {
|
||||
unsigned char next, prev; /* indices to form a circular LRU */
|
||||
unsigned char in_use; /* owned by a client, or free? */
|
||||
int age; /* tracked by clients to update local LRU's */
|
||||
} drm_i830_tex_region_t;
|
||||
|
||||
typedef struct _drm_i830_sarea {
|
||||
unsigned int ContextState[I830_CTX_SETUP_SIZE];
|
||||
unsigned int BufferState[I830_DEST_SETUP_SIZE];
|
||||
unsigned int TexState[I830_TEXTURE_COUNT][I830_TEX_SETUP_SIZE];
|
||||
unsigned int TexBlendState[I830_TEXBLEND_COUNT][I830_TEXBLEND_SIZE];
|
||||
unsigned int TexBlendStateWordsUsed[I830_TEXBLEND_COUNT];
|
||||
unsigned int Palette[2][256];
|
||||
unsigned int dirty;
|
||||
|
||||
unsigned int nbox;
|
||||
drm_clip_rect_t boxes[I830_NR_SAREA_CLIPRECTS];
|
||||
|
||||
/* Maintain an LRU of contiguous regions of texture space. If
|
||||
* you think you own a region of texture memory, and it has an
|
||||
* age different to the one you set, then you are mistaken and
|
||||
* it has been stolen by another client. If global texAge
|
||||
* hasn't changed, there is no need to walk the list.
|
||||
*
|
||||
* These regions can be used as a proxy for the fine-grained
|
||||
* texture information of other clients - by maintaining them
|
||||
* in the same lru which is used to age their own textures,
|
||||
* clients have an approximate lru for the whole of global
|
||||
* texture space, and can make informed decisions as to which
|
||||
* areas to kick out. There is no need to choose whether to
|
||||
* kick out your own texture or someone else's - simply eject
|
||||
* them all in LRU order.
|
||||
*/
|
||||
|
||||
drm_i830_tex_region_t texList[I830_NR_TEX_REGIONS + 1];
|
||||
/* Last elt is sentinal */
|
||||
int texAge; /* last time texture was uploaded */
|
||||
int last_enqueue; /* last time a buffer was enqueued */
|
||||
int last_dispatch; /* age of the most recently dispatched buffer */
|
||||
int last_quiescent; /* */
|
||||
int ctxOwner; /* last context to upload state */
|
||||
|
||||
int vertex_prim;
|
||||
|
||||
int pf_enabled; /* is pageflipping allowed? */
|
||||
int pf_active;
|
||||
int pf_current_page; /* which buffer is being displayed? */
|
||||
|
||||
int perf_boxes; /* performance boxes to be displayed */
|
||||
|
||||
/* Here's the state for texunits 2,3:
|
||||
*/
|
||||
unsigned int TexState2[I830_TEX_SETUP_SIZE];
|
||||
unsigned int TexBlendState2[I830_TEXBLEND_SIZE];
|
||||
unsigned int TexBlendStateWordsUsed2;
|
||||
|
||||
unsigned int TexState3[I830_TEX_SETUP_SIZE];
|
||||
unsigned int TexBlendState3[I830_TEXBLEND_SIZE];
|
||||
unsigned int TexBlendStateWordsUsed3;
|
||||
|
||||
unsigned int StippleState[I830_STP_SETUP_SIZE];
|
||||
} drm_i830_sarea_t;
|
||||
|
||||
/* Flags for perf_boxes
|
||||
*/
|
||||
#define I830_BOX_RING_EMPTY 0x1 /* populated by kernel */
|
||||
#define I830_BOX_FLIP 0x2 /* populated by kernel */
|
||||
#define I830_BOX_WAIT 0x4 /* populated by kernel & client */
|
||||
#define I830_BOX_TEXTURE_LOAD 0x8 /* populated by kernel */
|
||||
#define I830_BOX_LOST_CONTEXT 0x10 /* populated by client */
|
||||
|
||||
/* I830 specific ioctls
|
||||
* The device specific ioctl range is 0x40 to 0x79.
|
||||
*/
|
||||
#define DRM_I830_INIT 0x00
|
||||
#define DRM_I830_VERTEX 0x01
|
||||
#define DRM_I830_CLEAR 0x02
|
||||
#define DRM_I830_FLUSH 0x03
|
||||
#define DRM_I830_GETAGE 0x04
|
||||
#define DRM_I830_GETBUF 0x05
|
||||
#define DRM_I830_SWAP 0x06
|
||||
#define DRM_I830_COPY 0x07
|
||||
#define DRM_I830_DOCOPY 0x08
|
||||
#define DRM_I830_FLIP 0x09
|
||||
#define DRM_I830_IRQ_EMIT 0x0a
|
||||
#define DRM_I830_IRQ_WAIT 0x0b
|
||||
#define DRM_I830_GETPARAM 0x0c
|
||||
#define DRM_I830_SETPARAM 0x0d
|
||||
|
||||
#define DRM_IOCTL_I830_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_IOCTL_I830_INIT, drm_i830_init_t)
|
||||
#define DRM_IOCTL_I830_VERTEX DRM_IOW( DRM_COMMAND_BASE + DRM_IOCTL_I830_VERTEX, drm_i830_vertex_t)
|
||||
#define DRM_IOCTL_I830_CLEAR DRM_IOW( DRM_COMMAND_BASE + DRM_IOCTL_I830_CLEAR, drm_i830_clear_t)
|
||||
#define DRM_IOCTL_I830_FLUSH DRM_IO ( DRM_COMMAND_BASE + DRM_IOCTL_I830_FLUSH)
|
||||
#define DRM_IOCTL_I830_GETAGE DRM_IO ( DRM_COMMAND_BASE + DRM_IOCTL_I830_GETAGE)
|
||||
#define DRM_IOCTL_I830_GETBUF DRM_IOWR(DRM_COMMAND_BASE + DRM_IOCTL_I830_GETBUF, drm_i830_dma_t)
|
||||
#define DRM_IOCTL_I830_SWAP DRM_IO ( DRM_COMMAND_BASE + DRM_IOCTL_I830_SWAP)
|
||||
#define DRM_IOCTL_I830_COPY DRM_IOW( DRM_COMMAND_BASE + DRM_IOCTL_I830_COPY, drm_i830_copy_t)
|
||||
#define DRM_IOCTL_I830_DOCOPY DRM_IO ( DRM_COMMAND_BASE + DRM_IOCTL_I830_DOCOPY)
|
||||
#define DRM_IOCTL_I830_FLIP DRM_IO ( DRM_COMMAND_BASE + DRM_IOCTL_I830_FLIP)
|
||||
#define DRM_IOCTL_I830_IRQ_EMIT DRM_IOWR(DRM_COMMAND_BASE + DRM_IOCTL_I830_IRQ_EMIT, drm_i830_irq_emit_t)
|
||||
#define DRM_IOCTL_I830_IRQ_WAIT DRM_IOW( DRM_COMMAND_BASE + DRM_IOCTL_I830_IRQ_WAIT, drm_i830_irq_wait_t)
|
||||
#define DRM_IOCTL_I830_GETPARAM DRM_IOWR(DRM_COMMAND_BASE + DRM_IOCTL_I830_GETPARAM, drm_i830_getparam_t)
|
||||
#define DRM_IOCTL_I830_SETPARAM DRM_IOWR(DRM_COMMAND_BASE + DRM_IOCTL_I830_SETPARAM, drm_i830_setparam_t)
|
||||
|
||||
typedef struct _drm_i830_clear {
|
||||
int clear_color;
|
||||
int clear_depth;
|
||||
int flags;
|
||||
unsigned int clear_colormask;
|
||||
unsigned int clear_depthmask;
|
||||
} drm_i830_clear_t;
|
||||
|
||||
/* These may be placeholders if we have more cliprects than
|
||||
* I830_NR_SAREA_CLIPRECTS. In that case, the client sets discard to
|
||||
* false, indicating that the buffer will be dispatched again with a
|
||||
* new set of cliprects.
|
||||
*/
|
||||
typedef struct _drm_i830_vertex {
|
||||
int idx; /* buffer index */
|
||||
int used; /* nr bytes in use */
|
||||
int discard; /* client is finished with the buffer? */
|
||||
} drm_i830_vertex_t;
|
||||
|
||||
typedef struct _drm_i830_copy_t {
|
||||
int idx; /* buffer index */
|
||||
int used; /* nr bytes in use */
|
||||
void __user *address; /* Address to copy from */
|
||||
} drm_i830_copy_t;
|
||||
|
||||
typedef struct drm_i830_dma {
|
||||
void __user *virtual;
|
||||
int request_idx;
|
||||
int request_size;
|
||||
int granted;
|
||||
} drm_i830_dma_t;
|
||||
|
||||
/* 1.3: Userspace can request & wait on irq's:
|
||||
*/
|
||||
typedef struct drm_i830_irq_emit {
|
||||
int __user *irq_seq;
|
||||
} drm_i830_irq_emit_t;
|
||||
|
||||
typedef struct drm_i830_irq_wait {
|
||||
int irq_seq;
|
||||
} drm_i830_irq_wait_t;
|
||||
|
||||
/* 1.3: New ioctl to query kernel params:
|
||||
*/
|
||||
#define I830_PARAM_IRQ_ACTIVE 1
|
||||
|
||||
typedef struct drm_i830_getparam {
|
||||
int param;
|
||||
int __user *value;
|
||||
} drm_i830_getparam_t;
|
||||
|
||||
/* 1.3: New ioctl to set kernel params:
|
||||
*/
|
||||
#define I830_SETPARAM_USE_MI_BATCHBUFFER_START 1
|
||||
|
||||
typedef struct drm_i830_setparam {
|
||||
int param;
|
||||
int value;
|
||||
} drm_i830_setparam_t;
|
||||
|
||||
#endif /* _I830_DRM_H_ */
|
||||
108
drivers/char/drm/i830_drv.c
Normal file
108
drivers/char/drm/i830_drv.c
Normal file
@@ -0,0 +1,108 @@
|
||||
/* i830_drv.c -- I810 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>
|
||||
* Jeff Hartmann <jhartmann@valinux.com>
|
||||
* Gareth Hughes <gareth@valinux.com>
|
||||
* Abraham vd Merwe <abraham@2d3d.co.za>
|
||||
* Keith Whitwell <keith@tungstengraphics.com>
|
||||
*/
|
||||
|
||||
#include "drmP.h"
|
||||
#include "drm.h"
|
||||
#include "i830_drm.h"
|
||||
#include "i830_drv.h"
|
||||
|
||||
#include "drm_pciids.h"
|
||||
|
||||
static struct pci_device_id pciidlist[] = {
|
||||
i830_PCI_IDS
|
||||
};
|
||||
|
||||
static struct drm_driver driver = {
|
||||
.driver_features =
|
||||
DRIVER_USE_AGP | DRIVER_REQUIRE_AGP | DRIVER_USE_MTRR |
|
||||
DRIVER_HAVE_DMA | DRIVER_DMA_QUEUE,
|
||||
#if USE_IRQS
|
||||
.driver_features |= DRIVER_HAVE_IRQ | DRIVER_SHARED_IRQ,
|
||||
#endif
|
||||
.dev_priv_size = sizeof(drm_i830_buf_priv_t),
|
||||
.load = i830_driver_load,
|
||||
.lastclose = i830_driver_lastclose,
|
||||
.preclose = i830_driver_preclose,
|
||||
.device_is_agp = i830_driver_device_is_agp,
|
||||
.reclaim_buffers_locked = i830_driver_reclaim_buffers_locked,
|
||||
.dma_quiescent = i830_driver_dma_quiescent,
|
||||
.get_map_ofs = drm_core_get_map_ofs,
|
||||
.get_reg_ofs = drm_core_get_reg_ofs,
|
||||
#if USE_IRQS
|
||||
.irq_preinstall = i830_driver_irq_preinstall,
|
||||
.irq_postinstall = i830_driver_irq_postinstall,
|
||||
.irq_uninstall = i830_driver_irq_uninstall,
|
||||
.irq_handler = i830_driver_irq_handler,
|
||||
#endif
|
||||
.ioctls = i830_ioctls,
|
||||
.fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = drm_open,
|
||||
.release = drm_release,
|
||||
.ioctl = drm_ioctl,
|
||||
.mmap = drm_mmap,
|
||||
.poll = drm_poll,
|
||||
.fasync = drm_fasync,
|
||||
},
|
||||
|
||||
.pci_driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.id_table = pciidlist,
|
||||
},
|
||||
|
||||
.name = DRIVER_NAME,
|
||||
.desc = DRIVER_DESC,
|
||||
.date = DRIVER_DATE,
|
||||
.major = DRIVER_MAJOR,
|
||||
.minor = DRIVER_MINOR,
|
||||
.patchlevel = DRIVER_PATCHLEVEL,
|
||||
};
|
||||
|
||||
static int __init i830_init(void)
|
||||
{
|
||||
driver.num_ioctls = i830_max_ioctl;
|
||||
return drm_init(&driver);
|
||||
}
|
||||
|
||||
static void __exit i830_exit(void)
|
||||
{
|
||||
drm_exit(&driver);
|
||||
}
|
||||
|
||||
module_init(i830_init);
|
||||
module_exit(i830_exit);
|
||||
|
||||
MODULE_AUTHOR(DRIVER_AUTHOR);
|
||||
MODULE_DESCRIPTION(DRIVER_DESC);
|
||||
MODULE_LICENSE("GPL and additional rights");
|
||||
292
drivers/char/drm/i830_drv.h
Normal file
292
drivers/char/drm/i830_drv.h
Normal file
@@ -0,0 +1,292 @@
|
||||
/* i830_drv.h -- Private header for the I830 driver -*- linux-c -*-
|
||||
* Created: Mon Dec 13 01:50:01 1999 by jhartmann@precisioninsight.com
|
||||
*
|
||||
* Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
|
||||
* Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors: Rickard E. (Rik) Faith <faith@valinux.com>
|
||||
* Jeff Hartmann <jhartmann@valinux.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _I830_DRV_H_
|
||||
#define _I830_DRV_H_
|
||||
|
||||
/* General customization:
|
||||
*/
|
||||
|
||||
#define DRIVER_AUTHOR "VA Linux Systems Inc."
|
||||
|
||||
#define DRIVER_NAME "i830"
|
||||
#define DRIVER_DESC "Intel 830M"
|
||||
#define DRIVER_DATE "20021108"
|
||||
|
||||
/* Interface history:
|
||||
*
|
||||
* 1.1: Original.
|
||||
* 1.2: ?
|
||||
* 1.3: New irq emit/wait ioctls.
|
||||
* New pageflip ioctl.
|
||||
* New getparam ioctl.
|
||||
* State for texunits 3&4 in sarea.
|
||||
* New (alternative) layout for texture state.
|
||||
*/
|
||||
#define DRIVER_MAJOR 1
|
||||
#define DRIVER_MINOR 3
|
||||
#define DRIVER_PATCHLEVEL 2
|
||||
|
||||
/* Driver will work either way: IRQ's save cpu time when waiting for
|
||||
* the card, but are subject to subtle interactions between bios,
|
||||
* hardware and the driver.
|
||||
*/
|
||||
/* XXX: Add vblank support? */
|
||||
#define USE_IRQS 0
|
||||
|
||||
typedef struct drm_i830_buf_priv {
|
||||
u32 *in_use;
|
||||
int my_use_idx;
|
||||
int currently_mapped;
|
||||
void __user *virtual;
|
||||
void *kernel_virtual;
|
||||
drm_local_map_t map;
|
||||
} drm_i830_buf_priv_t;
|
||||
|
||||
typedef struct _drm_i830_ring_buffer {
|
||||
int tail_mask;
|
||||
unsigned long Start;
|
||||
unsigned long End;
|
||||
unsigned long Size;
|
||||
u8 *virtual_start;
|
||||
int head;
|
||||
int tail;
|
||||
int space;
|
||||
drm_local_map_t map;
|
||||
} drm_i830_ring_buffer_t;
|
||||
|
||||
typedef struct drm_i830_private {
|
||||
drm_map_t *sarea_map;
|
||||
drm_map_t *mmio_map;
|
||||
|
||||
drm_i830_sarea_t *sarea_priv;
|
||||
drm_i830_ring_buffer_t ring;
|
||||
|
||||
void *hw_status_page;
|
||||
unsigned long counter;
|
||||
|
||||
dma_addr_t dma_status_page;
|
||||
|
||||
drm_buf_t *mmap_buffer;
|
||||
|
||||
u32 front_di1, back_di1, zi1;
|
||||
|
||||
int back_offset;
|
||||
int depth_offset;
|
||||
int front_offset;
|
||||
int w, h;
|
||||
int pitch;
|
||||
int back_pitch;
|
||||
int depth_pitch;
|
||||
unsigned int cpp;
|
||||
|
||||
int do_boxes;
|
||||
int dma_used;
|
||||
|
||||
int current_page;
|
||||
int page_flipping;
|
||||
|
||||
wait_queue_head_t irq_queue;
|
||||
atomic_t irq_received;
|
||||
atomic_t irq_emitted;
|
||||
|
||||
int use_mi_batchbuffer_start;
|
||||
|
||||
} drm_i830_private_t;
|
||||
|
||||
extern drm_ioctl_desc_t i830_ioctls[];
|
||||
extern int i830_max_ioctl;
|
||||
|
||||
/* i830_irq.c */
|
||||
extern int i830_irq_emit(struct inode *inode, struct file *filp,
|
||||
unsigned int cmd, unsigned long arg);
|
||||
extern int i830_irq_wait(struct inode *inode, struct file *filp,
|
||||
unsigned int cmd, unsigned long arg);
|
||||
|
||||
extern irqreturn_t i830_driver_irq_handler(DRM_IRQ_ARGS);
|
||||
extern void i830_driver_irq_preinstall(drm_device_t * dev);
|
||||
extern void i830_driver_irq_postinstall(drm_device_t * dev);
|
||||
extern void i830_driver_irq_uninstall(drm_device_t * dev);
|
||||
extern int i830_driver_load(struct drm_device *, unsigned long flags);
|
||||
extern void i830_driver_preclose(drm_device_t * dev, DRMFILE filp);
|
||||
extern void i830_driver_lastclose(drm_device_t * dev);
|
||||
extern void i830_driver_reclaim_buffers_locked(drm_device_t * dev,
|
||||
struct file *filp);
|
||||
extern int i830_driver_dma_quiescent(drm_device_t * dev);
|
||||
extern int i830_driver_device_is_agp(drm_device_t * dev);
|
||||
|
||||
#define I830_READ(reg) DRM_READ32(dev_priv->mmio_map, reg)
|
||||
#define I830_WRITE(reg,val) DRM_WRITE32(dev_priv->mmio_map, reg, val)
|
||||
#define I830_READ16(reg) DRM_READ16(dev_priv->mmio_map, reg)
|
||||
#define I830_WRITE16(reg,val) DRM_WRITE16(dev_priv->mmio_map, reg, val)
|
||||
|
||||
#define I830_VERBOSE 0
|
||||
|
||||
#define RING_LOCALS unsigned int outring, ringmask, outcount; \
|
||||
volatile char *virt;
|
||||
|
||||
#define BEGIN_LP_RING(n) do { \
|
||||
if (I830_VERBOSE) \
|
||||
printk("BEGIN_LP_RING(%d) in %s\n", \
|
||||
n, __FUNCTION__); \
|
||||
if (dev_priv->ring.space < n*4) \
|
||||
i830_wait_ring(dev, n*4, __FUNCTION__); \
|
||||
outcount = 0; \
|
||||
outring = dev_priv->ring.tail; \
|
||||
ringmask = dev_priv->ring.tail_mask; \
|
||||
virt = dev_priv->ring.virtual_start; \
|
||||
} while (0)
|
||||
|
||||
#define OUT_RING(n) do { \
|
||||
if (I830_VERBOSE) printk(" OUT_RING %x\n", (int)(n)); \
|
||||
*(volatile unsigned int *)(virt + outring) = n; \
|
||||
outcount++; \
|
||||
outring += 4; \
|
||||
outring &= ringmask; \
|
||||
} while (0)
|
||||
|
||||
#define ADVANCE_LP_RING() do { \
|
||||
if (I830_VERBOSE) printk("ADVANCE_LP_RING %x\n", outring); \
|
||||
dev_priv->ring.tail = outring; \
|
||||
dev_priv->ring.space -= outcount * 4; \
|
||||
I830_WRITE(LP_RING + RING_TAIL, outring); \
|
||||
} while(0)
|
||||
|
||||
extern int i830_wait_ring(drm_device_t * dev, int n, const char *caller);
|
||||
|
||||
#define GFX_OP_USER_INTERRUPT ((0<<29)|(2<<23))
|
||||
#define GFX_OP_BREAKPOINT_INTERRUPT ((0<<29)|(1<<23))
|
||||
#define CMD_REPORT_HEAD (7<<23)
|
||||
#define CMD_STORE_DWORD_IDX ((0x21<<23) | 0x1)
|
||||
#define CMD_OP_BATCH_BUFFER ((0x0<<29)|(0x30<<23)|0x1)
|
||||
|
||||
#define STATE3D_LOAD_STATE_IMMEDIATE_2 ((0x3<<29)|(0x1d<<24)|(0x03<<16))
|
||||
#define LOAD_TEXTURE_MAP0 (1<<11)
|
||||
|
||||
#define INST_PARSER_CLIENT 0x00000000
|
||||
#define INST_OP_FLUSH 0x02000000
|
||||
#define INST_FLUSH_MAP_CACHE 0x00000001
|
||||
|
||||
#define BB1_START_ADDR_MASK (~0x7)
|
||||
#define BB1_PROTECTED (1<<0)
|
||||
#define BB1_UNPROTECTED (0<<0)
|
||||
#define BB2_END_ADDR_MASK (~0x7)
|
||||
|
||||
#define I830REG_HWSTAM 0x02098
|
||||
#define I830REG_INT_IDENTITY_R 0x020a4
|
||||
#define I830REG_INT_MASK_R 0x020a8
|
||||
#define I830REG_INT_ENABLE_R 0x020a0
|
||||
|
||||
#define I830_IRQ_RESERVED ((1<<13)|(3<<2))
|
||||
|
||||
#define LP_RING 0x2030
|
||||
#define HP_RING 0x2040
|
||||
#define RING_TAIL 0x00
|
||||
#define TAIL_ADDR 0x001FFFF8
|
||||
#define RING_HEAD 0x04
|
||||
#define HEAD_WRAP_COUNT 0xFFE00000
|
||||
#define HEAD_WRAP_ONE 0x00200000
|
||||
#define HEAD_ADDR 0x001FFFFC
|
||||
#define RING_START 0x08
|
||||
#define START_ADDR 0x0xFFFFF000
|
||||
#define RING_LEN 0x0C
|
||||
#define RING_NR_PAGES 0x001FF000
|
||||
#define RING_REPORT_MASK 0x00000006
|
||||
#define RING_REPORT_64K 0x00000002
|
||||
#define RING_REPORT_128K 0x00000004
|
||||
#define RING_NO_REPORT 0x00000000
|
||||
#define RING_VALID_MASK 0x00000001
|
||||
#define RING_VALID 0x00000001
|
||||
#define RING_INVALID 0x00000000
|
||||
|
||||
#define GFX_OP_SCISSOR ((0x3<<29)|(0x1c<<24)|(0x10<<19))
|
||||
#define SC_UPDATE_SCISSOR (0x1<<1)
|
||||
#define SC_ENABLE_MASK (0x1<<0)
|
||||
#define SC_ENABLE (0x1<<0)
|
||||
|
||||
#define GFX_OP_SCISSOR_INFO ((0x3<<29)|(0x1d<<24)|(0x81<<16)|(0x1))
|
||||
#define SCI_YMIN_MASK (0xffff<<16)
|
||||
#define SCI_XMIN_MASK (0xffff<<0)
|
||||
#define SCI_YMAX_MASK (0xffff<<16)
|
||||
#define SCI_XMAX_MASK (0xffff<<0)
|
||||
|
||||
#define GFX_OP_SCISSOR_ENABLE ((0x3<<29)|(0x1c<<24)|(0x10<<19))
|
||||
#define GFX_OP_SCISSOR_RECT ((0x3<<29)|(0x1d<<24)|(0x81<<16)|1)
|
||||
#define GFX_OP_COLOR_FACTOR ((0x3<<29)|(0x1d<<24)|(0x1<<16)|0x0)
|
||||
#define GFX_OP_STIPPLE ((0x3<<29)|(0x1d<<24)|(0x83<<16))
|
||||
#define GFX_OP_MAP_INFO ((0x3<<29)|(0x1d<<24)|0x4)
|
||||
#define GFX_OP_DESTBUFFER_VARS ((0x3<<29)|(0x1d<<24)|(0x85<<16)|0x0)
|
||||
#define GFX_OP_DRAWRECT_INFO ((0x3<<29)|(0x1d<<24)|(0x80<<16)|(0x3))
|
||||
#define GFX_OP_PRIMITIVE ((0x3<<29)|(0x1f<<24))
|
||||
|
||||
#define CMD_OP_DESTBUFFER_INFO ((0x3<<29)|(0x1d<<24)|(0x8e<<16)|1)
|
||||
|
||||
#define CMD_OP_DISPLAYBUFFER_INFO ((0x0<<29)|(0x14<<23)|2)
|
||||
#define ASYNC_FLIP (1<<22)
|
||||
|
||||
#define CMD_3D (0x3<<29)
|
||||
#define STATE3D_CONST_BLEND_COLOR_CMD (CMD_3D|(0x1d<<24)|(0x88<<16))
|
||||
#define STATE3D_MAP_COORD_SETBIND_CMD (CMD_3D|(0x1d<<24)|(0x02<<16))
|
||||
|
||||
#define BR00_BITBLT_CLIENT 0x40000000
|
||||
#define BR00_OP_COLOR_BLT 0x10000000
|
||||
#define BR00_OP_SRC_COPY_BLT 0x10C00000
|
||||
#define BR13_SOLID_PATTERN 0x80000000
|
||||
|
||||
#define BUF_3D_ID_COLOR_BACK (0x3<<24)
|
||||
#define BUF_3D_ID_DEPTH (0x7<<24)
|
||||
#define BUF_3D_USE_FENCE (1<<23)
|
||||
#define BUF_3D_PITCH(x) (((x)/4)<<2)
|
||||
|
||||
#define CMD_OP_MAP_PALETTE_LOAD ((3<<29)|(0x1d<<24)|(0x82<<16)|255)
|
||||
#define MAP_PALETTE_NUM(x) ((x<<8) & (1<<8))
|
||||
#define MAP_PALETTE_BOTH (1<<11)
|
||||
|
||||
#define XY_COLOR_BLT_CMD ((2<<29)|(0x50<<22)|0x4)
|
||||
#define XY_COLOR_BLT_WRITE_ALPHA (1<<21)
|
||||
#define XY_COLOR_BLT_WRITE_RGB (1<<20)
|
||||
|
||||
#define XY_SRC_COPY_BLT_CMD ((2<<29)|(0x53<<22)|6)
|
||||
#define XY_SRC_COPY_BLT_WRITE_ALPHA (1<<21)
|
||||
#define XY_SRC_COPY_BLT_WRITE_RGB (1<<20)
|
||||
|
||||
#define MI_BATCH_BUFFER ((0x30<<23)|1)
|
||||
#define MI_BATCH_BUFFER_START (0x31<<23)
|
||||
#define MI_BATCH_BUFFER_END (0xA<<23)
|
||||
#define MI_BATCH_NON_SECURE (1)
|
||||
|
||||
#define MI_WAIT_FOR_EVENT ((0x3<<23))
|
||||
#define MI_WAIT_FOR_PLANE_A_FLIP (1<<2)
|
||||
#define MI_WAIT_FOR_PLANE_A_SCANLINES (1<<1)
|
||||
|
||||
#define MI_LOAD_SCAN_LINES_INCL ((0x12<<23))
|
||||
|
||||
#endif
|
||||
198
drivers/char/drm/i830_irq.c
Normal file
198
drivers/char/drm/i830_irq.c
Normal file
@@ -0,0 +1,198 @@
|
||||
/* i830_dma.c -- DMA support for the I830 -*- linux-c -*-
|
||||
*
|
||||
* Copyright 2002 Tungsten Graphics, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors: Keith Whitwell <keith@tungstengraphics.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#include "drmP.h"
|
||||
#include "drm.h"
|
||||
#include "i830_drm.h"
|
||||
#include "i830_drv.h"
|
||||
#include <linux/interrupt.h> /* For task queue support */
|
||||
#include <linux/delay.h>
|
||||
|
||||
irqreturn_t i830_driver_irq_handler(DRM_IRQ_ARGS)
|
||||
{
|
||||
drm_device_t *dev = (drm_device_t *) arg;
|
||||
drm_i830_private_t *dev_priv = (drm_i830_private_t *) dev->dev_private;
|
||||
u16 temp;
|
||||
|
||||
temp = I830_READ16(I830REG_INT_IDENTITY_R);
|
||||
DRM_DEBUG("%x\n", temp);
|
||||
|
||||
if (!(temp & 2))
|
||||
return IRQ_NONE;
|
||||
|
||||
I830_WRITE16(I830REG_INT_IDENTITY_R, temp);
|
||||
|
||||
atomic_inc(&dev_priv->irq_received);
|
||||
wake_up_interruptible(&dev_priv->irq_queue);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int i830_emit_irq(drm_device_t * dev)
|
||||
{
|
||||
drm_i830_private_t *dev_priv = dev->dev_private;
|
||||
RING_LOCALS;
|
||||
|
||||
DRM_DEBUG("%s\n", __FUNCTION__);
|
||||
|
||||
atomic_inc(&dev_priv->irq_emitted);
|
||||
|
||||
BEGIN_LP_RING(2);
|
||||
OUT_RING(0);
|
||||
OUT_RING(GFX_OP_USER_INTERRUPT);
|
||||
ADVANCE_LP_RING();
|
||||
|
||||
return atomic_read(&dev_priv->irq_emitted);
|
||||
}
|
||||
|
||||
static int i830_wait_irq(drm_device_t * dev, int irq_nr)
|
||||
{
|
||||
drm_i830_private_t *dev_priv = (drm_i830_private_t *) dev->dev_private;
|
||||
DECLARE_WAITQUEUE(entry, current);
|
||||
unsigned long end = jiffies + HZ * 3;
|
||||
int ret = 0;
|
||||
|
||||
DRM_DEBUG("%s\n", __FUNCTION__);
|
||||
|
||||
if (atomic_read(&dev_priv->irq_received) >= irq_nr)
|
||||
return 0;
|
||||
|
||||
dev_priv->sarea_priv->perf_boxes |= I830_BOX_WAIT;
|
||||
|
||||
add_wait_queue(&dev_priv->irq_queue, &entry);
|
||||
|
||||
for (;;) {
|
||||
__set_current_state(TASK_INTERRUPTIBLE);
|
||||
if (atomic_read(&dev_priv->irq_received) >= irq_nr)
|
||||
break;
|
||||
if ((signed)(end - jiffies) <= 0) {
|
||||
DRM_ERROR("timeout iir %x imr %x ier %x hwstam %x\n",
|
||||
I830_READ16(I830REG_INT_IDENTITY_R),
|
||||
I830_READ16(I830REG_INT_MASK_R),
|
||||
I830_READ16(I830REG_INT_ENABLE_R),
|
||||
I830_READ16(I830REG_HWSTAM));
|
||||
|
||||
ret = -EBUSY; /* Lockup? Missed irq? */
|
||||
break;
|
||||
}
|
||||
schedule_timeout(HZ * 3);
|
||||
if (signal_pending(current)) {
|
||||
ret = -EINTR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
__set_current_state(TASK_RUNNING);
|
||||
remove_wait_queue(&dev_priv->irq_queue, &entry);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Needs the lock as it touches the ring.
|
||||
*/
|
||||
int i830_irq_emit(struct inode *inode, struct file *filp, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
drm_file_t *priv = filp->private_data;
|
||||
drm_device_t *dev = priv->head->dev;
|
||||
drm_i830_private_t *dev_priv = dev->dev_private;
|
||||
drm_i830_irq_emit_t emit;
|
||||
int result;
|
||||
|
||||
LOCK_TEST_WITH_RETURN(dev, filp);
|
||||
|
||||
if (!dev_priv) {
|
||||
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (copy_from_user
|
||||
(&emit, (drm_i830_irq_emit_t __user *) arg, sizeof(emit)))
|
||||
return -EFAULT;
|
||||
|
||||
result = i830_emit_irq(dev);
|
||||
|
||||
if (copy_to_user(emit.irq_seq, &result, sizeof(int))) {
|
||||
DRM_ERROR("copy_to_user\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Doesn't need the hardware lock.
|
||||
*/
|
||||
int i830_irq_wait(struct inode *inode, struct file *filp, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
drm_file_t *priv = filp->private_data;
|
||||
drm_device_t *dev = priv->head->dev;
|
||||
drm_i830_private_t *dev_priv = dev->dev_private;
|
||||
drm_i830_irq_wait_t irqwait;
|
||||
|
||||
if (!dev_priv) {
|
||||
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (copy_from_user(&irqwait, (drm_i830_irq_wait_t __user *) arg,
|
||||
sizeof(irqwait)))
|
||||
return -EFAULT;
|
||||
|
||||
return i830_wait_irq(dev, irqwait.irq_seq);
|
||||
}
|
||||
|
||||
/* drm_dma.h hooks
|
||||
*/
|
||||
void i830_driver_irq_preinstall(drm_device_t * dev)
|
||||
{
|
||||
drm_i830_private_t *dev_priv = (drm_i830_private_t *) dev->dev_private;
|
||||
|
||||
I830_WRITE16(I830REG_HWSTAM, 0xffff);
|
||||
I830_WRITE16(I830REG_INT_MASK_R, 0x0);
|
||||
I830_WRITE16(I830REG_INT_ENABLE_R, 0x0);
|
||||
atomic_set(&dev_priv->irq_received, 0);
|
||||
atomic_set(&dev_priv->irq_emitted, 0);
|
||||
init_waitqueue_head(&dev_priv->irq_queue);
|
||||
}
|
||||
|
||||
void i830_driver_irq_postinstall(drm_device_t * dev)
|
||||
{
|
||||
drm_i830_private_t *dev_priv = (drm_i830_private_t *) dev->dev_private;
|
||||
|
||||
I830_WRITE16(I830REG_INT_ENABLE_R, 0x2);
|
||||
}
|
||||
|
||||
void i830_driver_irq_uninstall(drm_device_t * dev)
|
||||
{
|
||||
drm_i830_private_t *dev_priv = (drm_i830_private_t *) dev->dev_private;
|
||||
if (!dev_priv)
|
||||
return;
|
||||
|
||||
I830_WRITE16(I830REG_INT_MASK_R, 0xffff);
|
||||
I830_WRITE16(I830REG_INT_ENABLE_R, 0x0);
|
||||
}
|
||||
805
drivers/char/drm/i915_dma.c
Normal file
805
drivers/char/drm/i915_dma.c
Normal file
@@ -0,0 +1,805 @@
|
||||
/* 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 "drmP.h"
|
||||
#include "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->cpp = init->cpp;
|
||||
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 = DRM_ERR(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 DRM_ERR(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_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;
|
||||
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 },
|
||||
[DRM_IOCTL_NR(DRM_I915_VBLANK_SWAP)] = {i915_vblank_swap, 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;
|
||||
}
|
||||
265
drivers/char/drm/i915_drm.h
Normal file
265
drivers/char/drm/i915_drm.h
Normal file
@@ -0,0 +1,265 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _I915_DRM_H_
|
||||
#define _I915_DRM_H_
|
||||
|
||||
/* Please note that modifications to all structs defined here are
|
||||
* subject to backwards-compatibility constraints.
|
||||
*/
|
||||
|
||||
#include "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;
|
||||
|
||||
int pipeA_x;
|
||||
int pipeA_y;
|
||||
int pipeA_w;
|
||||
int pipeA_h;
|
||||
int pipeB_x;
|
||||
int pipeB_y;
|
||||
int pipeB_w;
|
||||
int pipeB_h;
|
||||
} 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_I915_VBLANK_SWAP 0x0f
|
||||
|
||||
#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)
|
||||
#define DRM_IOCTL_I915_VBLANK_SWAP DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_VBLANK_SWAP, drm_i915_vblank_swap_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;
|
||||
|
||||
/* Schedule buffer swap at given vertical blank:
|
||||
*/
|
||||
typedef struct drm_i915_vblank_swap {
|
||||
drm_drawable_t drawable;
|
||||
drm_vblank_seq_type_t seqtype;
|
||||
unsigned int sequence;
|
||||
} drm_i915_vblank_swap_t;
|
||||
|
||||
#endif /* _I915_DRM_H_ */
|
||||
105
drivers/char/drm/i915_drv.c
Normal file
105
drivers/char/drm/i915_drv.c
Normal file
@@ -0,0 +1,105 @@
|
||||
/* i915_drv.c -- i830,i845,i855,i865,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 "drmP.h"
|
||||
#include "drm.h"
|
||||
#include "i915_drm.h"
|
||||
#include "i915_drv.h"
|
||||
|
||||
#include "drm_pciids.h"
|
||||
|
||||
static struct pci_device_id pciidlist[] = {
|
||||
i915_PCI_IDS
|
||||
};
|
||||
|
||||
static struct drm_driver driver = {
|
||||
/* don't use mtrr's here, the Xserver or user space app should
|
||||
* deal with them for intel hardware.
|
||||
*/
|
||||
.driver_features =
|
||||
DRIVER_USE_AGP | DRIVER_REQUIRE_AGP | /* DRIVER_USE_MTRR |*/
|
||||
DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL |
|
||||
DRIVER_IRQ_VBL2,
|
||||
.load = i915_driver_load,
|
||||
.lastclose = i915_driver_lastclose,
|
||||
.preclose = i915_driver_preclose,
|
||||
.device_is_agp = i915_driver_device_is_agp,
|
||||
.vblank_wait = i915_driver_vblank_wait,
|
||||
.vblank_wait2 = i915_driver_vblank_wait2,
|
||||
.irq_preinstall = i915_driver_irq_preinstall,
|
||||
.irq_postinstall = i915_driver_irq_postinstall,
|
||||
.irq_uninstall = i915_driver_irq_uninstall,
|
||||
.irq_handler = i915_driver_irq_handler,
|
||||
.reclaim_buffers = drm_core_reclaim_buffers,
|
||||
.get_map_ofs = drm_core_get_map_ofs,
|
||||
.get_reg_ofs = drm_core_get_reg_ofs,
|
||||
.ioctls = i915_ioctls,
|
||||
.fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = drm_open,
|
||||
.release = drm_release,
|
||||
.ioctl = drm_ioctl,
|
||||
.mmap = drm_mmap,
|
||||
.poll = drm_poll,
|
||||
.fasync = drm_fasync,
|
||||
#ifdef CONFIG_COMPAT
|
||||
.compat_ioctl = i915_compat_ioctl,
|
||||
#endif
|
||||
},
|
||||
|
||||
.pci_driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.id_table = pciidlist,
|
||||
},
|
||||
|
||||
.name = DRIVER_NAME,
|
||||
.desc = DRIVER_DESC,
|
||||
.date = DRIVER_DATE,
|
||||
.major = DRIVER_MAJOR,
|
||||
.minor = DRIVER_MINOR,
|
||||
.patchlevel = DRIVER_PATCHLEVEL,
|
||||
};
|
||||
|
||||
static int __init i915_init(void)
|
||||
{
|
||||
driver.num_ioctls = i915_max_ioctl;
|
||||
return drm_init(&driver);
|
||||
}
|
||||
|
||||
static void __exit i915_exit(void)
|
||||
{
|
||||
drm_exit(&driver);
|
||||
}
|
||||
|
||||
module_init(i915_init);
|
||||
module_exit(i915_exit);
|
||||
|
||||
MODULE_AUTHOR(DRIVER_AUTHOR);
|
||||
MODULE_DESCRIPTION(DRIVER_DESC);
|
||||
MODULE_LICENSE("GPL and additional rights");
|
||||
297
drivers/char/drm/i915_drv.h
Normal file
297
drivers/char/drm/i915_drv.h
Normal file
@@ -0,0 +1,297 @@
|
||||
/* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#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
|
||||
* 1.6: - New ioctl for scheduling buffer swaps on vertical blank
|
||||
* - Support vertical blank on secondary display pipe
|
||||
*/
|
||||
#define DRIVER_MAJOR 1
|
||||
#define DRIVER_MINOR 6
|
||||
#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_vbl_swap {
|
||||
struct list_head head;
|
||||
drm_drawable_t drw_id;
|
||||
unsigned int pipe;
|
||||
unsigned int sequence;
|
||||
} drm_i915_vbl_swap_t;
|
||||
|
||||
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;
|
||||
|
||||
unsigned int cpp;
|
||||
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;
|
||||
|
||||
spinlock_t swaps_lock;
|
||||
drm_i915_vbl_swap_t vbl_swaps;
|
||||
unsigned int swaps_pending;
|
||||
} 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 int i915_driver_vblank_wait2(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);
|
||||
extern int i915_vblank_swap(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 XY_SRC_COPY_BLT_CMD ((2<<29)|(0x53<<22)|6)
|
||||
#define XY_SRC_COPY_BLT_WRITE_ALPHA (1<<21)
|
||||
#define XY_SRC_COPY_BLT_WRITE_RGB (1<<20)
|
||||
|
||||
#define MI_BATCH_BUFFER ((0x30<<23)|1)
|
||||
#define MI_BATCH_BUFFER_START (0x31<<23)
|
||||
#define MI_BATCH_BUFFER_END (0xA<<23)
|
||||
#define MI_BATCH_NON_SECURE (1)
|
||||
|
||||
#define MI_WAIT_FOR_EVENT ((0x3<<23))
|
||||
#define MI_WAIT_FOR_PLANE_A_FLIP (1<<2)
|
||||
#define MI_WAIT_FOR_PLANE_A_SCANLINES (1<<1)
|
||||
|
||||
#define MI_LOAD_SCAN_LINES_INCL ((0x12<<23))
|
||||
|
||||
#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
|
||||
222
drivers/char/drm/i915_ioc32.c
Normal file
222
drivers/char/drm/i915_ioc32.c
Normal file
@@ -0,0 +1,222 @@
|
||||
/**
|
||||
* \file i915_ioc32.c
|
||||
*
|
||||
* 32-bit ioctl compatibility routines for the i915 DRM.
|
||||
*
|
||||
* \author Alan Hourihane <alanh@fairlite.demon.co.uk>
|
||||
*
|
||||
*
|
||||
* Copyright (C) Paul Mackerras 2005
|
||||
* Copyright (C) Alan Hourihane 2005
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
#include <linux/compat.h>
|
||||
|
||||
#include "drmP.h"
|
||||
#include "drm.h"
|
||||
#include "i915_drm.h"
|
||||
|
||||
typedef struct _drm_i915_batchbuffer32 {
|
||||
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? */
|
||||
u32 cliprects; /* pointer to userspace cliprects */
|
||||
} drm_i915_batchbuffer32_t;
|
||||
|
||||
static int compat_i915_batchbuffer(struct file *file, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
drm_i915_batchbuffer32_t batchbuffer32;
|
||||
drm_i915_batchbuffer_t __user *batchbuffer;
|
||||
|
||||
if (copy_from_user
|
||||
(&batchbuffer32, (void __user *)arg, sizeof(batchbuffer32)))
|
||||
return -EFAULT;
|
||||
|
||||
batchbuffer = compat_alloc_user_space(sizeof(*batchbuffer));
|
||||
if (!access_ok(VERIFY_WRITE, batchbuffer, sizeof(*batchbuffer))
|
||||
|| __put_user(batchbuffer32.start, &batchbuffer->start)
|
||||
|| __put_user(batchbuffer32.used, &batchbuffer->used)
|
||||
|| __put_user(batchbuffer32.DR1, &batchbuffer->DR1)
|
||||
|| __put_user(batchbuffer32.DR4, &batchbuffer->DR4)
|
||||
|| __put_user(batchbuffer32.num_cliprects,
|
||||
&batchbuffer->num_cliprects)
|
||||
|| __put_user((int __user *)(unsigned long)batchbuffer32.cliprects,
|
||||
&batchbuffer->cliprects))
|
||||
return -EFAULT;
|
||||
|
||||
return drm_ioctl(file->f_path.dentry->d_inode, file,
|
||||
DRM_IOCTL_I915_BATCHBUFFER,
|
||||
(unsigned long)batchbuffer);
|
||||
}
|
||||
|
||||
typedef struct _drm_i915_cmdbuffer32 {
|
||||
u32 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? */
|
||||
u32 cliprects; /* pointer to userspace cliprects */
|
||||
} drm_i915_cmdbuffer32_t;
|
||||
|
||||
static int compat_i915_cmdbuffer(struct file *file, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
drm_i915_cmdbuffer32_t cmdbuffer32;
|
||||
drm_i915_cmdbuffer_t __user *cmdbuffer;
|
||||
|
||||
if (copy_from_user
|
||||
(&cmdbuffer32, (void __user *)arg, sizeof(cmdbuffer32)))
|
||||
return -EFAULT;
|
||||
|
||||
cmdbuffer = compat_alloc_user_space(sizeof(*cmdbuffer));
|
||||
if (!access_ok(VERIFY_WRITE, cmdbuffer, sizeof(*cmdbuffer))
|
||||
|| __put_user((int __user *)(unsigned long)cmdbuffer32.buf,
|
||||
&cmdbuffer->buf)
|
||||
|| __put_user(cmdbuffer32.sz, &cmdbuffer->sz)
|
||||
|| __put_user(cmdbuffer32.DR1, &cmdbuffer->DR1)
|
||||
|| __put_user(cmdbuffer32.DR4, &cmdbuffer->DR4)
|
||||
|| __put_user(cmdbuffer32.num_cliprects, &cmdbuffer->num_cliprects)
|
||||
|| __put_user((int __user *)(unsigned long)cmdbuffer32.cliprects,
|
||||
&cmdbuffer->cliprects))
|
||||
return -EFAULT;
|
||||
|
||||
return drm_ioctl(file->f_path.dentry->d_inode, file,
|
||||
DRM_IOCTL_I915_CMDBUFFER, (unsigned long)cmdbuffer);
|
||||
}
|
||||
|
||||
typedef struct drm_i915_irq_emit32 {
|
||||
u32 irq_seq;
|
||||
} drm_i915_irq_emit32_t;
|
||||
|
||||
static int compat_i915_irq_emit(struct file *file, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
drm_i915_irq_emit32_t req32;
|
||||
drm_i915_irq_emit_t __user *request;
|
||||
|
||||
if (copy_from_user(&req32, (void __user *)arg, sizeof(req32)))
|
||||
return -EFAULT;
|
||||
|
||||
request = compat_alloc_user_space(sizeof(*request));
|
||||
if (!access_ok(VERIFY_WRITE, request, sizeof(*request))
|
||||
|| __put_user((int __user *)(unsigned long)req32.irq_seq,
|
||||
&request->irq_seq))
|
||||
return -EFAULT;
|
||||
|
||||
return drm_ioctl(file->f_path.dentry->d_inode, file,
|
||||
DRM_IOCTL_I915_IRQ_EMIT, (unsigned long)request);
|
||||
}
|
||||
typedef struct drm_i915_getparam32 {
|
||||
int param;
|
||||
u32 value;
|
||||
} drm_i915_getparam32_t;
|
||||
|
||||
static int compat_i915_getparam(struct file *file, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
drm_i915_getparam32_t req32;
|
||||
drm_i915_getparam_t __user *request;
|
||||
|
||||
if (copy_from_user(&req32, (void __user *)arg, sizeof(req32)))
|
||||
return -EFAULT;
|
||||
|
||||
request = compat_alloc_user_space(sizeof(*request));
|
||||
if (!access_ok(VERIFY_WRITE, request, sizeof(*request))
|
||||
|| __put_user(req32.param, &request->param)
|
||||
|| __put_user((void __user *)(unsigned long)req32.value,
|
||||
&request->value))
|
||||
return -EFAULT;
|
||||
|
||||
return drm_ioctl(file->f_path.dentry->d_inode, file,
|
||||
DRM_IOCTL_I915_GETPARAM, (unsigned long)request);
|
||||
}
|
||||
|
||||
typedef struct drm_i915_mem_alloc32 {
|
||||
int region;
|
||||
int alignment;
|
||||
int size;
|
||||
u32 region_offset; /* offset from start of fb or agp */
|
||||
} drm_i915_mem_alloc32_t;
|
||||
|
||||
static int compat_i915_alloc(struct file *file, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
drm_i915_mem_alloc32_t req32;
|
||||
drm_i915_mem_alloc_t __user *request;
|
||||
|
||||
if (copy_from_user(&req32, (void __user *)arg, sizeof(req32)))
|
||||
return -EFAULT;
|
||||
|
||||
request = compat_alloc_user_space(sizeof(*request));
|
||||
if (!access_ok(VERIFY_WRITE, request, sizeof(*request))
|
||||
|| __put_user(req32.region, &request->region)
|
||||
|| __put_user(req32.alignment, &request->alignment)
|
||||
|| __put_user(req32.size, &request->size)
|
||||
|| __put_user((void __user *)(unsigned long)req32.region_offset,
|
||||
&request->region_offset))
|
||||
return -EFAULT;
|
||||
|
||||
return drm_ioctl(file->f_path.dentry->d_inode, file,
|
||||
DRM_IOCTL_I915_ALLOC, (unsigned long)request);
|
||||
}
|
||||
|
||||
drm_ioctl_compat_t *i915_compat_ioctls[] = {
|
||||
[DRM_I915_BATCHBUFFER] = compat_i915_batchbuffer,
|
||||
[DRM_I915_CMDBUFFER] = compat_i915_cmdbuffer,
|
||||
[DRM_I915_GETPARAM] = compat_i915_getparam,
|
||||
[DRM_I915_IRQ_EMIT] = compat_i915_irq_emit,
|
||||
[DRM_I915_ALLOC] = compat_i915_alloc
|
||||
};
|
||||
|
||||
/**
|
||||
* Called whenever a 32-bit process running under a 64-bit kernel
|
||||
* performs an ioctl on /dev/dri/card<n>.
|
||||
*
|
||||
* \param filp file pointer.
|
||||
* \param cmd command.
|
||||
* \param arg user argument.
|
||||
* \return zero on success or negative number on failure.
|
||||
*/
|
||||
long i915_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
unsigned int nr = DRM_IOCTL_NR(cmd);
|
||||
drm_ioctl_compat_t *fn = NULL;
|
||||
int ret;
|
||||
|
||||
if (nr < DRM_COMMAND_BASE)
|
||||
return drm_compat_ioctl(filp, cmd, arg);
|
||||
|
||||
if (nr < DRM_COMMAND_BASE + DRM_ARRAY_SIZE(i915_compat_ioctls))
|
||||
fn = i915_compat_ioctls[nr - DRM_COMMAND_BASE];
|
||||
|
||||
lock_kernel(); /* XXX for now */
|
||||
if (fn != NULL)
|
||||
ret = (*fn) (filp, cmd, arg);
|
||||
else
|
||||
ret = drm_ioctl(filp->f_path.dentry->d_inode, filp, cmd, arg);
|
||||
unlock_kernel();
|
||||
|
||||
return ret;
|
||||
}
|
||||
609
drivers/char/drm/i915_irq.c
Normal file
609
drivers/char/drm/i915_irq.c
Normal file
@@ -0,0 +1,609 @@
|
||||
/* 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 "drmP.h"
|
||||
#include "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)
|
||||
|
||||
/**
|
||||
* Emit blits for scheduled buffer swaps.
|
||||
*
|
||||
* This function will be called with the HW lock held.
|
||||
*/
|
||||
static void i915_vblank_tasklet(drm_device_t *dev)
|
||||
{
|
||||
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
|
||||
unsigned long irqflags;
|
||||
struct list_head *list, *tmp, hits, *hit;
|
||||
int nhits, nrects, slice[2], upper[2], lower[2], i;
|
||||
unsigned counter[2] = { atomic_read(&dev->vbl_received),
|
||||
atomic_read(&dev->vbl_received2) };
|
||||
drm_drawable_info_t *drw;
|
||||
drm_i915_sarea_t *sarea_priv = dev_priv->sarea_priv;
|
||||
u32 cpp = dev_priv->cpp;
|
||||
u32 cmd = (cpp == 4) ? (XY_SRC_COPY_BLT_CMD |
|
||||
XY_SRC_COPY_BLT_WRITE_ALPHA |
|
||||
XY_SRC_COPY_BLT_WRITE_RGB)
|
||||
: XY_SRC_COPY_BLT_CMD;
|
||||
u32 pitchropcpp = (sarea_priv->pitch * cpp) | (0xcc << 16) |
|
||||
(cpp << 23) | (1 << 24);
|
||||
RING_LOCALS;
|
||||
|
||||
DRM_DEBUG("\n");
|
||||
|
||||
INIT_LIST_HEAD(&hits);
|
||||
|
||||
nhits = nrects = 0;
|
||||
|
||||
spin_lock_irqsave(&dev_priv->swaps_lock, irqflags);
|
||||
|
||||
/* Find buffer swaps scheduled for this vertical blank */
|
||||
list_for_each_safe(list, tmp, &dev_priv->vbl_swaps.head) {
|
||||
drm_i915_vbl_swap_t *vbl_swap =
|
||||
list_entry(list, drm_i915_vbl_swap_t, head);
|
||||
|
||||
if ((counter[vbl_swap->pipe] - vbl_swap->sequence) > (1<<23))
|
||||
continue;
|
||||
|
||||
list_del(list);
|
||||
dev_priv->swaps_pending--;
|
||||
|
||||
spin_unlock(&dev_priv->swaps_lock);
|
||||
spin_lock(&dev->drw_lock);
|
||||
|
||||
drw = drm_get_drawable_info(dev, vbl_swap->drw_id);
|
||||
|
||||
if (!drw) {
|
||||
spin_unlock(&dev->drw_lock);
|
||||
drm_free(vbl_swap, sizeof(*vbl_swap), DRM_MEM_DRIVER);
|
||||
spin_lock(&dev_priv->swaps_lock);
|
||||
continue;
|
||||
}
|
||||
|
||||
list_for_each(hit, &hits) {
|
||||
drm_i915_vbl_swap_t *swap_cmp =
|
||||
list_entry(hit, drm_i915_vbl_swap_t, head);
|
||||
drm_drawable_info_t *drw_cmp =
|
||||
drm_get_drawable_info(dev, swap_cmp->drw_id);
|
||||
|
||||
if (drw_cmp &&
|
||||
drw_cmp->rects[0].y1 > drw->rects[0].y1) {
|
||||
list_add_tail(list, hit);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock(&dev->drw_lock);
|
||||
|
||||
/* List of hits was empty, or we reached the end of it */
|
||||
if (hit == &hits)
|
||||
list_add_tail(list, hits.prev);
|
||||
|
||||
nhits++;
|
||||
|
||||
spin_lock(&dev_priv->swaps_lock);
|
||||
}
|
||||
|
||||
if (nhits == 0) {
|
||||
spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);
|
||||
return;
|
||||
}
|
||||
|
||||
spin_unlock(&dev_priv->swaps_lock);
|
||||
|
||||
i915_kernel_lost_context(dev);
|
||||
|
||||
BEGIN_LP_RING(6);
|
||||
|
||||
OUT_RING(GFX_OP_DRAWRECT_INFO);
|
||||
OUT_RING(0);
|
||||
OUT_RING(0);
|
||||
OUT_RING(sarea_priv->width | sarea_priv->height << 16);
|
||||
OUT_RING(sarea_priv->width | sarea_priv->height << 16);
|
||||
OUT_RING(0);
|
||||
|
||||
ADVANCE_LP_RING();
|
||||
|
||||
sarea_priv->ctxOwner = DRM_KERNEL_CONTEXT;
|
||||
|
||||
upper[0] = upper[1] = 0;
|
||||
slice[0] = max(sarea_priv->pipeA_h / nhits, 1);
|
||||
slice[1] = max(sarea_priv->pipeB_h / nhits, 1);
|
||||
lower[0] = sarea_priv->pipeA_y + slice[0];
|
||||
lower[1] = sarea_priv->pipeB_y + slice[0];
|
||||
|
||||
spin_lock(&dev->drw_lock);
|
||||
|
||||
/* Emit blits for buffer swaps, partitioning both outputs into as many
|
||||
* slices as there are buffer swaps scheduled in order to avoid tearing
|
||||
* (based on the assumption that a single buffer swap would always
|
||||
* complete before scanout starts).
|
||||
*/
|
||||
for (i = 0; i++ < nhits;
|
||||
upper[0] = lower[0], lower[0] += slice[0],
|
||||
upper[1] = lower[1], lower[1] += slice[1]) {
|
||||
if (i == nhits)
|
||||
lower[0] = lower[1] = sarea_priv->height;
|
||||
|
||||
list_for_each(hit, &hits) {
|
||||
drm_i915_vbl_swap_t *swap_hit =
|
||||
list_entry(hit, drm_i915_vbl_swap_t, head);
|
||||
drm_clip_rect_t *rect;
|
||||
int num_rects, pipe;
|
||||
unsigned short top, bottom;
|
||||
|
||||
drw = drm_get_drawable_info(dev, swap_hit->drw_id);
|
||||
|
||||
if (!drw)
|
||||
continue;
|
||||
|
||||
rect = drw->rects;
|
||||
pipe = swap_hit->pipe;
|
||||
top = upper[pipe];
|
||||
bottom = lower[pipe];
|
||||
|
||||
for (num_rects = drw->num_rects; num_rects--; rect++) {
|
||||
int y1 = max(rect->y1, top);
|
||||
int y2 = min(rect->y2, bottom);
|
||||
|
||||
if (y1 >= y2)
|
||||
continue;
|
||||
|
||||
BEGIN_LP_RING(8);
|
||||
|
||||
OUT_RING(cmd);
|
||||
OUT_RING(pitchropcpp);
|
||||
OUT_RING((y1 << 16) | rect->x1);
|
||||
OUT_RING((y2 << 16) | rect->x2);
|
||||
OUT_RING(sarea_priv->front_offset);
|
||||
OUT_RING((y1 << 16) | rect->x1);
|
||||
OUT_RING(pitchropcpp & 0xffff);
|
||||
OUT_RING(sarea_priv->back_offset);
|
||||
|
||||
ADVANCE_LP_RING();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&dev->drw_lock, irqflags);
|
||||
|
||||
list_for_each_safe(hit, tmp, &hits) {
|
||||
drm_i915_vbl_swap_t *swap_hit =
|
||||
list_entry(hit, drm_i915_vbl_swap_t, head);
|
||||
|
||||
list_del(hit);
|
||||
|
||||
drm_free(swap_hit, sizeof(*swap_hit), DRM_MEM_DRIVER);
|
||||
}
|
||||
}
|
||||
|
||||
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__, 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)) {
|
||||
int vblank_pipe = dev_priv->vblank_pipe;
|
||||
|
||||
if ((vblank_pipe &
|
||||
(DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B))
|
||||
== (DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B)) {
|
||||
if (temp & VSYNC_PIPEA_FLAG)
|
||||
atomic_inc(&dev->vbl_received);
|
||||
if (temp & VSYNC_PIPEB_FLAG)
|
||||
atomic_inc(&dev->vbl_received2);
|
||||
} else if (((temp & VSYNC_PIPEA_FLAG) &&
|
||||
(vblank_pipe & DRM_I915_VBLANK_PIPE_A)) ||
|
||||
((temp & VSYNC_PIPEB_FLAG) &&
|
||||
(vblank_pipe & DRM_I915_VBLANK_PIPE_B)))
|
||||
atomic_inc(&dev->vbl_received);
|
||||
|
||||
DRM_WAKEUP(&dev->vbl_queue);
|
||||
drm_vbl_send_signals(dev);
|
||||
|
||||
if (dev_priv->swaps_pending > 0)
|
||||
drm_locked_tasklet(dev, i915_vblank_tasklet);
|
||||
}
|
||||
|
||||
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,
|
||||
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__,
|
||||
READ_BREADCRUMB(dev_priv), (int)dev_priv->counter);
|
||||
}
|
||||
|
||||
dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int i915_driver_vblank_do_wait(drm_device_t *dev, unsigned int *sequence,
|
||||
atomic_t *counter)
|
||||
{
|
||||
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(counter))
|
||||
- *sequence) <= (1<<23)));
|
||||
|
||||
*sequence = cur_vblank;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int i915_driver_vblank_wait(drm_device_t *dev, unsigned int *sequence)
|
||||
{
|
||||
return i915_driver_vblank_do_wait(dev, sequence, &dev->vbl_received);
|
||||
}
|
||||
|
||||
int i915_driver_vblank_wait2(drm_device_t *dev, unsigned int *sequence)
|
||||
{
|
||||
return i915_driver_vblank_do_wait(dev, sequence, &dev->vbl_received2);
|
||||
}
|
||||
|
||||
/* 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 void 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;
|
||||
|
||||
I915_WRITE16(I915REG_INT_ENABLE_R, USER_INT_FLAG | flag);
|
||||
}
|
||||
|
||||
/* 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));
|
||||
|
||||
if (pipe.pipe & ~(DRM_I915_VBLANK_PIPE_A|DRM_I915_VBLANK_PIPE_B)) {
|
||||
DRM_ERROR("%s called with invalid pipe 0x%x\n",
|
||||
__FUNCTION__, pipe.pipe);
|
||||
return DRM_ERR(EINVAL);
|
||||
}
|
||||
|
||||
dev_priv->vblank_pipe = pipe.pipe;
|
||||
|
||||
i915_enable_interrupt (dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule buffer swap at given vertical blank.
|
||||
*/
|
||||
int i915_vblank_swap(DRM_IOCTL_ARGS)
|
||||
{
|
||||
DRM_DEVICE;
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
drm_i915_vblank_swap_t swap;
|
||||
drm_i915_vbl_swap_t *vbl_swap;
|
||||
unsigned int pipe, seqtype, curseq;
|
||||
unsigned long irqflags;
|
||||
struct list_head *list;
|
||||
|
||||
if (!dev_priv) {
|
||||
DRM_ERROR("%s called with no initialization\n", __func__);
|
||||
return DRM_ERR(EINVAL);
|
||||
}
|
||||
|
||||
if (dev_priv->sarea_priv->rotation) {
|
||||
DRM_DEBUG("Rotation not supported\n");
|
||||
return DRM_ERR(EINVAL);
|
||||
}
|
||||
|
||||
DRM_COPY_FROM_USER_IOCTL(swap, (drm_i915_vblank_swap_t __user *) data,
|
||||
sizeof(swap));
|
||||
|
||||
if (swap.seqtype & ~(_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE |
|
||||
_DRM_VBLANK_SECONDARY | _DRM_VBLANK_NEXTONMISS)) {
|
||||
DRM_ERROR("Invalid sequence type 0x%x\n", swap.seqtype);
|
||||
return DRM_ERR(EINVAL);
|
||||
}
|
||||
|
||||
pipe = (swap.seqtype & _DRM_VBLANK_SECONDARY) ? 1 : 0;
|
||||
|
||||
seqtype = swap.seqtype & (_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE);
|
||||
|
||||
if (!(dev_priv->vblank_pipe & (1 << pipe))) {
|
||||
DRM_ERROR("Invalid pipe %d\n", pipe);
|
||||
return DRM_ERR(EINVAL);
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&dev->drw_lock, irqflags);
|
||||
|
||||
if (!drm_get_drawable_info(dev, swap.drawable)) {
|
||||
spin_unlock_irqrestore(&dev->drw_lock, irqflags);
|
||||
DRM_DEBUG("Invalid drawable ID %d\n", swap.drawable);
|
||||
return DRM_ERR(EINVAL);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&dev->drw_lock, irqflags);
|
||||
|
||||
curseq = atomic_read(pipe ? &dev->vbl_received2 : &dev->vbl_received);
|
||||
|
||||
if (seqtype == _DRM_VBLANK_RELATIVE)
|
||||
swap.sequence += curseq;
|
||||
|
||||
if ((curseq - swap.sequence) <= (1<<23)) {
|
||||
if (swap.seqtype & _DRM_VBLANK_NEXTONMISS) {
|
||||
swap.sequence = curseq + 1;
|
||||
} else {
|
||||
DRM_DEBUG("Missed target sequence\n");
|
||||
return DRM_ERR(EINVAL);
|
||||
}
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&dev_priv->swaps_lock, irqflags);
|
||||
|
||||
list_for_each(list, &dev_priv->vbl_swaps.head) {
|
||||
vbl_swap = list_entry(list, drm_i915_vbl_swap_t, head);
|
||||
|
||||
if (vbl_swap->drw_id == swap.drawable &&
|
||||
vbl_swap->pipe == pipe &&
|
||||
vbl_swap->sequence == swap.sequence) {
|
||||
spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);
|
||||
DRM_DEBUG("Already scheduled\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);
|
||||
|
||||
if (dev_priv->swaps_pending >= 100) {
|
||||
DRM_DEBUG("Too many swaps queued\n");
|
||||
return DRM_ERR(EBUSY);
|
||||
}
|
||||
|
||||
vbl_swap = drm_calloc(1, sizeof(vbl_swap), DRM_MEM_DRIVER);
|
||||
|
||||
if (!vbl_swap) {
|
||||
DRM_ERROR("Failed to allocate memory to queue swap\n");
|
||||
return DRM_ERR(ENOMEM);
|
||||
}
|
||||
|
||||
DRM_DEBUG("\n");
|
||||
|
||||
vbl_swap->drw_id = swap.drawable;
|
||||
vbl_swap->pipe = pipe;
|
||||
vbl_swap->sequence = swap.sequence;
|
||||
|
||||
spin_lock_irqsave(&dev_priv->swaps_lock, irqflags);
|
||||
|
||||
list_add_tail((struct list_head *)vbl_swap, &dev_priv->vbl_swaps.head);
|
||||
dev_priv->swaps_pending++;
|
||||
|
||||
spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);
|
||||
|
||||
DRM_COPY_TO_USER_IOCTL((drm_i915_vblank_swap_t __user *) data, swap,
|
||||
sizeof(swap));
|
||||
|
||||
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;
|
||||
|
||||
dev_priv->swaps_lock = SPIN_LOCK_UNLOCKED;
|
||||
INIT_LIST_HEAD(&dev_priv->vbl_swaps.head);
|
||||
dev_priv->swaps_pending = 0;
|
||||
|
||||
if (!dev_priv->vblank_pipe)
|
||||
dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A;
|
||||
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);
|
||||
}
|
||||
398
drivers/char/drm/i915_mem.c
Normal file
398
drivers/char/drm/i915_mem.c
Normal file
@@ -0,0 +1,398 @@
|
||||
/* 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 "drmP.h"
|
||||
#include "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;
|
||||
}
|
||||
|
||||
1179
drivers/char/drm/mga_dma.c
Normal file
1179
drivers/char/drm/mga_dma.c
Normal file
File diff suppressed because it is too large
Load Diff
417
drivers/char/drm/mga_drm.h
Normal file
417
drivers/char/drm/mga_drm.h
Normal file
@@ -0,0 +1,417 @@
|
||||
/* 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>
|
||||
*/
|
||||
|
||||
#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
|
||||
141
drivers/char/drm/mga_drv.c
Normal file
141
drivers/char/drm/mga_drv.c
Normal file
@@ -0,0 +1,141 @@
|
||||
/* 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 "drmP.h"
|
||||
#include "drm.h"
|
||||
#include "mga_drm.h"
|
||||
#include "mga_drv.h"
|
||||
|
||||
#include "drm_pciids.h"
|
||||
|
||||
static int mga_driver_device_is_agp(drm_device_t * dev);
|
||||
|
||||
static struct pci_device_id pciidlist[] = {
|
||||
mga_PCI_IDS
|
||||
};
|
||||
|
||||
static struct drm_driver driver = {
|
||||
.driver_features =
|
||||
DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA |
|
||||
DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED |
|
||||
DRIVER_IRQ_VBL,
|
||||
.dev_priv_size = sizeof(drm_mga_buf_priv_t),
|
||||
.load = mga_driver_load,
|
||||
.unload = mga_driver_unload,
|
||||
.lastclose = mga_driver_lastclose,
|
||||
.dma_quiescent = mga_driver_dma_quiescent,
|
||||
.device_is_agp = mga_driver_device_is_agp,
|
||||
.vblank_wait = mga_driver_vblank_wait,
|
||||
.irq_preinstall = mga_driver_irq_preinstall,
|
||||
.irq_postinstall = mga_driver_irq_postinstall,
|
||||
.irq_uninstall = mga_driver_irq_uninstall,
|
||||
.irq_handler = mga_driver_irq_handler,
|
||||
.reclaim_buffers = drm_core_reclaim_buffers,
|
||||
.get_map_ofs = drm_core_get_map_ofs,
|
||||
.get_reg_ofs = drm_core_get_reg_ofs,
|
||||
.ioctls = mga_ioctls,
|
||||
.dma_ioctl = mga_dma_buffers,
|
||||
.fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = drm_open,
|
||||
.release = drm_release,
|
||||
.ioctl = drm_ioctl,
|
||||
.mmap = drm_mmap,
|
||||
.poll = drm_poll,
|
||||
.fasync = drm_fasync,
|
||||
#ifdef CONFIG_COMPAT
|
||||
.compat_ioctl = mga_compat_ioctl,
|
||||
#endif
|
||||
},
|
||||
.pci_driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.id_table = pciidlist,
|
||||
},
|
||||
|
||||
.name = DRIVER_NAME,
|
||||
.desc = DRIVER_DESC,
|
||||
.date = DRIVER_DATE,
|
||||
.major = DRIVER_MAJOR,
|
||||
.minor = DRIVER_MINOR,
|
||||
.patchlevel = DRIVER_PATCHLEVEL,
|
||||
};
|
||||
|
||||
static int __init mga_init(void)
|
||||
{
|
||||
driver.num_ioctls = mga_max_ioctl;
|
||||
return drm_init(&driver);
|
||||
}
|
||||
|
||||
static void __exit mga_exit(void)
|
||||
{
|
||||
drm_exit(&driver);
|
||||
}
|
||||
|
||||
module_init(mga_init);
|
||||
module_exit(mga_exit);
|
||||
|
||||
MODULE_AUTHOR(DRIVER_AUTHOR);
|
||||
MODULE_DESCRIPTION(DRIVER_DESC);
|
||||
MODULE_LICENSE("GPL and additional rights");
|
||||
|
||||
/**
|
||||
* 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 2 is returned.
|
||||
*/
|
||||
static int mga_driver_device_is_agp(drm_device_t * dev)
|
||||
{
|
||||
const struct pci_dev *const pdev = dev->pdev;
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
if ((pdev->device == 0x0525) && pdev->bus->self
|
||||
&& (pdev->bus->self->vendor == 0x3388)
|
||||
&& (pdev->bus->self->device == 0x0021)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 2;
|
||||
}
|
||||
683
drivers/char/drm/mga_drv.h
Normal file
683
drivers/char/drm/mga_drv.h
Normal file
@@ -0,0 +1,683 @@
|
||||
/* 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>
|
||||
*/
|
||||
|
||||
#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 "20051102"
|
||||
|
||||
#define DRIVER_MAJOR 3
|
||||
#define DRIVER_MINOR 2
|
||||
#define DRIVER_PATCHLEVEL 1
|
||||
|
||||
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
|
||||
231
drivers/char/drm/mga_ioc32.c
Normal file
231
drivers/char/drm/mga_ioc32.c
Normal file
@@ -0,0 +1,231 @@
|
||||
/**
|
||||
* \file mga_ioc32.c
|
||||
*
|
||||
* 32-bit ioctl compatibility routines for the MGA DRM.
|
||||
*
|
||||
* \author Dave Airlie <airlied@linux.ie> with code from patches by Egbert Eich
|
||||
*
|
||||
*
|
||||
* Copyright (C) Paul Mackerras 2005
|
||||
* Copyright (C) Egbert Eich 2003,2004
|
||||
* Copyright (C) Dave Airlie 2005
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
#include <linux/compat.h>
|
||||
|
||||
#include "drmP.h"
|
||||
#include "drm.h"
|
||||
#include "mga_drm.h"
|
||||
|
||||
typedef struct drm32_mga_init {
|
||||
int func;
|
||||
u32 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];
|
||||
u32 fb_offset;
|
||||
u32 mmio_offset;
|
||||
u32 status_offset;
|
||||
u32 warp_offset;
|
||||
u32 primary_offset;
|
||||
u32 buffers_offset;
|
||||
} drm_mga_init32_t;
|
||||
|
||||
static int compat_mga_init(struct file *file, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
drm_mga_init32_t init32;
|
||||
drm_mga_init_t __user *init;
|
||||
int err = 0, i;
|
||||
|
||||
if (copy_from_user(&init32, (void __user *)arg, sizeof(init32)))
|
||||
return -EFAULT;
|
||||
|
||||
init = compat_alloc_user_space(sizeof(*init));
|
||||
if (!access_ok(VERIFY_WRITE, init, sizeof(*init))
|
||||
|| __put_user(init32.func, &init->func)
|
||||
|| __put_user(init32.sarea_priv_offset, &init->sarea_priv_offset)
|
||||
|| __put_user(init32.chipset, &init->chipset)
|
||||
|| __put_user(init32.sgram, &init->sgram)
|
||||
|| __put_user(init32.maccess, &init->maccess)
|
||||
|| __put_user(init32.fb_cpp, &init->fb_cpp)
|
||||
|| __put_user(init32.front_offset, &init->front_offset)
|
||||
|| __put_user(init32.front_pitch, &init->front_pitch)
|
||||
|| __put_user(init32.back_offset, &init->back_offset)
|
||||
|| __put_user(init32.back_pitch, &init->back_pitch)
|
||||
|| __put_user(init32.depth_cpp, &init->depth_cpp)
|
||||
|| __put_user(init32.depth_offset, &init->depth_offset)
|
||||
|| __put_user(init32.depth_pitch, &init->depth_pitch)
|
||||
|| __put_user(init32.fb_offset, &init->fb_offset)
|
||||
|| __put_user(init32.mmio_offset, &init->mmio_offset)
|
||||
|| __put_user(init32.status_offset, &init->status_offset)
|
||||
|| __put_user(init32.warp_offset, &init->warp_offset)
|
||||
|| __put_user(init32.primary_offset, &init->primary_offset)
|
||||
|| __put_user(init32.buffers_offset, &init->buffers_offset))
|
||||
return -EFAULT;
|
||||
|
||||
for (i = 0; i < MGA_NR_TEX_HEAPS; i++) {
|
||||
err |=
|
||||
__put_user(init32.texture_offset[i],
|
||||
&init->texture_offset[i]);
|
||||
err |=
|
||||
__put_user(init32.texture_size[i], &init->texture_size[i]);
|
||||
}
|
||||
if (err)
|
||||
return -EFAULT;
|
||||
|
||||
return drm_ioctl(file->f_path.dentry->d_inode, file,
|
||||
DRM_IOCTL_MGA_INIT, (unsigned long)init);
|
||||
}
|
||||
|
||||
typedef struct drm_mga_getparam32 {
|
||||
int param;
|
||||
u32 value;
|
||||
} drm_mga_getparam32_t;
|
||||
|
||||
static int compat_mga_getparam(struct file *file, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
drm_mga_getparam32_t getparam32;
|
||||
drm_mga_getparam_t __user *getparam;
|
||||
|
||||
if (copy_from_user(&getparam32, (void __user *)arg, sizeof(getparam32)))
|
||||
return -EFAULT;
|
||||
|
||||
getparam = compat_alloc_user_space(sizeof(*getparam));
|
||||
if (!access_ok(VERIFY_WRITE, getparam, sizeof(*getparam))
|
||||
|| __put_user(getparam32.param, &getparam->param)
|
||||
|| __put_user((void __user *)(unsigned long)getparam32.value,
|
||||
&getparam->value))
|
||||
return -EFAULT;
|
||||
|
||||
return drm_ioctl(file->f_path.dentry->d_inode, file,
|
||||
DRM_IOCTL_MGA_GETPARAM, (unsigned long)getparam);
|
||||
}
|
||||
|
||||
typedef struct drm_mga_drm_bootstrap32 {
|
||||
u32 texture_handle;
|
||||
u32 texture_size;
|
||||
u32 primary_size;
|
||||
u32 secondary_bin_count;
|
||||
u32 secondary_bin_size;
|
||||
u32 agp_mode;
|
||||
u8 agp_size;
|
||||
} drm_mga_dma_bootstrap32_t;
|
||||
|
||||
static int compat_mga_dma_bootstrap(struct file *file, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
drm_mga_dma_bootstrap32_t dma_bootstrap32;
|
||||
drm_mga_dma_bootstrap_t __user *dma_bootstrap;
|
||||
int err;
|
||||
|
||||
if (copy_from_user(&dma_bootstrap32, (void __user *)arg,
|
||||
sizeof(dma_bootstrap32)))
|
||||
return -EFAULT;
|
||||
|
||||
dma_bootstrap = compat_alloc_user_space(sizeof(*dma_bootstrap));
|
||||
if (!access_ok(VERIFY_WRITE, dma_bootstrap, sizeof(*dma_bootstrap))
|
||||
|| __put_user(dma_bootstrap32.texture_handle,
|
||||
&dma_bootstrap->texture_handle)
|
||||
|| __put_user(dma_bootstrap32.texture_size,
|
||||
&dma_bootstrap->texture_size)
|
||||
|| __put_user(dma_bootstrap32.primary_size,
|
||||
&dma_bootstrap->primary_size)
|
||||
|| __put_user(dma_bootstrap32.secondary_bin_count,
|
||||
&dma_bootstrap->secondary_bin_count)
|
||||
|| __put_user(dma_bootstrap32.secondary_bin_size,
|
||||
&dma_bootstrap->secondary_bin_size)
|
||||
|| __put_user(dma_bootstrap32.agp_mode, &dma_bootstrap->agp_mode)
|
||||
|| __put_user(dma_bootstrap32.agp_size, &dma_bootstrap->agp_size))
|
||||
return -EFAULT;
|
||||
|
||||
err = drm_ioctl(file->f_path.dentry->d_inode, file,
|
||||
DRM_IOCTL_MGA_DMA_BOOTSTRAP,
|
||||
(unsigned long)dma_bootstrap);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (__get_user(dma_bootstrap32.texture_handle,
|
||||
&dma_bootstrap->texture_handle)
|
||||
|| __get_user(dma_bootstrap32.texture_size,
|
||||
&dma_bootstrap->texture_size)
|
||||
|| __get_user(dma_bootstrap32.primary_size,
|
||||
&dma_bootstrap->primary_size)
|
||||
|| __get_user(dma_bootstrap32.secondary_bin_count,
|
||||
&dma_bootstrap->secondary_bin_count)
|
||||
|| __get_user(dma_bootstrap32.secondary_bin_size,
|
||||
&dma_bootstrap->secondary_bin_size)
|
||||
|| __get_user(dma_bootstrap32.agp_mode, &dma_bootstrap->agp_mode)
|
||||
|| __get_user(dma_bootstrap32.agp_size, &dma_bootstrap->agp_size))
|
||||
return -EFAULT;
|
||||
|
||||
if (copy_to_user((void __user *)arg, &dma_bootstrap32,
|
||||
sizeof(dma_bootstrap32)))
|
||||
return -EFAULT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
drm_ioctl_compat_t *mga_compat_ioctls[] = {
|
||||
[DRM_MGA_INIT] = compat_mga_init,
|
||||
[DRM_MGA_GETPARAM] = compat_mga_getparam,
|
||||
[DRM_MGA_DMA_BOOTSTRAP] = compat_mga_dma_bootstrap,
|
||||
};
|
||||
|
||||
/**
|
||||
* Called whenever a 32-bit process running under a 64-bit kernel
|
||||
* performs an ioctl on /dev/dri/card<n>.
|
||||
*
|
||||
* \param filp file pointer.
|
||||
* \param cmd command.
|
||||
* \param arg user argument.
|
||||
* \return zero on success or negative number on failure.
|
||||
*/
|
||||
long mga_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
unsigned int nr = DRM_IOCTL_NR(cmd);
|
||||
drm_ioctl_compat_t *fn = NULL;
|
||||
int ret;
|
||||
|
||||
if (nr < DRM_COMMAND_BASE)
|
||||
return drm_compat_ioctl(filp, cmd, arg);
|
||||
|
||||
if (nr < DRM_COMMAND_BASE + DRM_ARRAY_SIZE(mga_compat_ioctls))
|
||||
fn = mga_compat_ioctls[nr - DRM_COMMAND_BASE];
|
||||
|
||||
lock_kernel(); /* XXX for now */
|
||||
if (fn != NULL)
|
||||
ret = (*fn) (filp, cmd, arg);
|
||||
else
|
||||
ret = drm_ioctl(filp->f_path.dentry->d_inode, filp, cmd, arg);
|
||||
unlock_kernel();
|
||||
|
||||
return ret;
|
||||
}
|
||||
148
drivers/char/drm/mga_irq.c
Normal file
148
drivers/char/drm/mga_irq.c
Normal file
@@ -0,0 +1,148 @@
|
||||
/* 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 "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;
|
||||
}
|
||||
1145
drivers/char/drm/mga_state.c
Normal file
1145
drivers/char/drm/mga_state.c
Normal file
File diff suppressed because it is too large
Load Diff
11645
drivers/char/drm/mga_ucode.h
Normal file
11645
drivers/char/drm/mga_ucode.h
Normal file
File diff suppressed because it is too large
Load Diff
193
drivers/char/drm/mga_warp.c
Normal file
193
drivers/char/drm/mga_warp.c
Normal file
@@ -0,0 +1,193 @@
|
||||
/* 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 "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:
|
||||
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;
|
||||
}
|
||||
950
drivers/char/drm/r128_cce.c
Normal file
950
drivers/char/drm/r128_cce.c
Normal file
@@ -0,0 +1,950 @@
|
||||
/* 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 "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;
|
||||
}
|
||||
344
drivers/char/drm/r128_drm.h
Normal file
344
drivers/char/drm/r128_drm.h
Normal file
@@ -0,0 +1,344 @@
|
||||
/* 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>
|
||||
*/
|
||||
|
||||
#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
|
||||
103
drivers/char/drm/r128_drv.c
Normal file
103
drivers/char/drm/r128_drv.c
Normal file
@@ -0,0 +1,103 @@
|
||||
/* 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 "drmP.h"
|
||||
#include "drm.h"
|
||||
#include "r128_drm.h"
|
||||
#include "r128_drv.h"
|
||||
|
||||
#include "drm_pciids.h"
|
||||
|
||||
static struct pci_device_id pciidlist[] = {
|
||||
r128_PCI_IDS
|
||||
};
|
||||
|
||||
static struct drm_driver driver = {
|
||||
.driver_features =
|
||||
DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_SG |
|
||||
DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED |
|
||||
DRIVER_IRQ_VBL,
|
||||
.dev_priv_size = sizeof(drm_r128_buf_priv_t),
|
||||
.preclose = r128_driver_preclose,
|
||||
.lastclose = r128_driver_lastclose,
|
||||
.vblank_wait = r128_driver_vblank_wait,
|
||||
.irq_preinstall = r128_driver_irq_preinstall,
|
||||
.irq_postinstall = r128_driver_irq_postinstall,
|
||||
.irq_uninstall = r128_driver_irq_uninstall,
|
||||
.irq_handler = r128_driver_irq_handler,
|
||||
.reclaim_buffers = drm_core_reclaim_buffers,
|
||||
.get_map_ofs = drm_core_get_map_ofs,
|
||||
.get_reg_ofs = drm_core_get_reg_ofs,
|
||||
.ioctls = r128_ioctls,
|
||||
.dma_ioctl = r128_cce_buffers,
|
||||
.fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = drm_open,
|
||||
.release = drm_release,
|
||||
.ioctl = drm_ioctl,
|
||||
.mmap = drm_mmap,
|
||||
.poll = drm_poll,
|
||||
.fasync = drm_fasync,
|
||||
#ifdef CONFIG_COMPAT
|
||||
.compat_ioctl = r128_compat_ioctl,
|
||||
#endif
|
||||
},
|
||||
|
||||
.pci_driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.id_table = pciidlist,
|
||||
},
|
||||
|
||||
.name = DRIVER_NAME,
|
||||
.desc = DRIVER_DESC,
|
||||
.date = DRIVER_DATE,
|
||||
.major = DRIVER_MAJOR,
|
||||
.minor = DRIVER_MINOR,
|
||||
.patchlevel = DRIVER_PATCHLEVEL,
|
||||
};
|
||||
|
||||
static int __init r128_init(void)
|
||||
{
|
||||
driver.num_ioctls = r128_max_ioctl;
|
||||
return drm_init(&driver);
|
||||
}
|
||||
|
||||
static void __exit r128_exit(void)
|
||||
{
|
||||
drm_exit(&driver);
|
||||
}
|
||||
|
||||
module_init(r128_init);
|
||||
module_exit(r128_exit);
|
||||
|
||||
MODULE_AUTHOR(DRIVER_AUTHOR);
|
||||
MODULE_DESCRIPTION(DRIVER_DESC);
|
||||
MODULE_LICENSE("GPL and additional rights");
|
||||
520
drivers/char/drm/r128_drv.h
Normal file
520
drivers/char/drm/r128_drv.h
Normal file
@@ -0,0 +1,520 @@
|
||||
/* 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<>zer <daenzerm@student.ethz.ch>
|
||||
*/
|
||||
|
||||
#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__ */
|
||||
221
drivers/char/drm/r128_ioc32.c
Normal file
221
drivers/char/drm/r128_ioc32.c
Normal file
@@ -0,0 +1,221 @@
|
||||
/**
|
||||
* \file r128_ioc32.c
|
||||
*
|
||||
* 32-bit ioctl compatibility routines for the R128 DRM.
|
||||
*
|
||||
* \author Dave Airlie <airlied@linux.ie> with code from patches by Egbert Eich
|
||||
*
|
||||
* Copyright (C) Paul Mackerras 2005
|
||||
* Copyright (C) Egbert Eich 2003,2004
|
||||
* Copyright (C) Dave Airlie 2005
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
#include <linux/compat.h>
|
||||
|
||||
#include "drmP.h"
|
||||
#include "drm.h"
|
||||
#include "r128_drm.h"
|
||||
|
||||
typedef struct drm_r128_init32 {
|
||||
int func;
|
||||
unsigned int sarea_priv_offset;
|
||||
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;
|
||||
|
||||
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;
|
||||
} drm_r128_init32_t;
|
||||
|
||||
static int compat_r128_init(struct file *file, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
drm_r128_init32_t init32;
|
||||
drm_r128_init_t __user *init;
|
||||
|
||||
if (copy_from_user(&init32, (void __user *)arg, sizeof(init32)))
|
||||
return -EFAULT;
|
||||
|
||||
init = compat_alloc_user_space(sizeof(*init));
|
||||
if (!access_ok(VERIFY_WRITE, init, sizeof(*init))
|
||||
|| __put_user(init32.func, &init->func)
|
||||
|| __put_user(init32.sarea_priv_offset, &init->sarea_priv_offset)
|
||||
|| __put_user(init32.is_pci, &init->is_pci)
|
||||
|| __put_user(init32.cce_mode, &init->cce_mode)
|
||||
|| __put_user(init32.cce_secure, &init->cce_secure)
|
||||
|| __put_user(init32.ring_size, &init->ring_size)
|
||||
|| __put_user(init32.usec_timeout, &init->usec_timeout)
|
||||
|| __put_user(init32.fb_bpp, &init->fb_bpp)
|
||||
|| __put_user(init32.front_offset, &init->front_offset)
|
||||
|| __put_user(init32.front_pitch, &init->front_pitch)
|
||||
|| __put_user(init32.back_offset, &init->back_offset)
|
||||
|| __put_user(init32.back_pitch, &init->back_pitch)
|
||||
|| __put_user(init32.depth_bpp, &init->depth_bpp)
|
||||
|| __put_user(init32.depth_offset, &init->depth_offset)
|
||||
|| __put_user(init32.depth_pitch, &init->depth_pitch)
|
||||
|| __put_user(init32.span_offset, &init->span_offset)
|
||||
|| __put_user(init32.fb_offset, &init->fb_offset)
|
||||
|| __put_user(init32.mmio_offset, &init->mmio_offset)
|
||||
|| __put_user(init32.ring_offset, &init->ring_offset)
|
||||
|| __put_user(init32.ring_rptr_offset, &init->ring_rptr_offset)
|
||||
|| __put_user(init32.buffers_offset, &init->buffers_offset)
|
||||
|| __put_user(init32.agp_textures_offset,
|
||||
&init->agp_textures_offset))
|
||||
return -EFAULT;
|
||||
|
||||
return drm_ioctl(file->f_path.dentry->d_inode, file,
|
||||
DRM_IOCTL_R128_INIT, (unsigned long)init);
|
||||
}
|
||||
|
||||
typedef struct drm_r128_depth32 {
|
||||
int func;
|
||||
int n;
|
||||
u32 x;
|
||||
u32 y;
|
||||
u32 buffer;
|
||||
u32 mask;
|
||||
} drm_r128_depth32_t;
|
||||
|
||||
static int compat_r128_depth(struct file *file, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
drm_r128_depth32_t depth32;
|
||||
drm_r128_depth_t __user *depth;
|
||||
|
||||
if (copy_from_user(&depth32, (void __user *)arg, sizeof(depth32)))
|
||||
return -EFAULT;
|
||||
|
||||
depth = compat_alloc_user_space(sizeof(*depth));
|
||||
if (!access_ok(VERIFY_WRITE, depth, sizeof(*depth))
|
||||
|| __put_user(depth32.func, &depth->func)
|
||||
|| __put_user(depth32.n, &depth->n)
|
||||
|| __put_user((int __user *)(unsigned long)depth32.x, &depth->x)
|
||||
|| __put_user((int __user *)(unsigned long)depth32.y, &depth->y)
|
||||
|| __put_user((unsigned int __user *)(unsigned long)depth32.buffer,
|
||||
&depth->buffer)
|
||||
|| __put_user((unsigned char __user *)(unsigned long)depth32.mask,
|
||||
&depth->mask))
|
||||
return -EFAULT;
|
||||
|
||||
return drm_ioctl(file->f_path.dentry->d_inode, file,
|
||||
DRM_IOCTL_R128_DEPTH, (unsigned long)depth);
|
||||
|
||||
}
|
||||
|
||||
typedef struct drm_r128_stipple32 {
|
||||
u32 mask;
|
||||
} drm_r128_stipple32_t;
|
||||
|
||||
static int compat_r128_stipple(struct file *file, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
drm_r128_stipple32_t stipple32;
|
||||
drm_r128_stipple_t __user *stipple;
|
||||
|
||||
if (copy_from_user(&stipple32, (void __user *)arg, sizeof(stipple32)))
|
||||
return -EFAULT;
|
||||
|
||||
stipple = compat_alloc_user_space(sizeof(*stipple));
|
||||
if (!access_ok(VERIFY_WRITE, stipple, sizeof(*stipple))
|
||||
|| __put_user((unsigned int __user *)(unsigned long)stipple32.mask,
|
||||
&stipple->mask))
|
||||
return -EFAULT;
|
||||
|
||||
return drm_ioctl(file->f_path.dentry->d_inode, file,
|
||||
DRM_IOCTL_R128_STIPPLE, (unsigned long)stipple);
|
||||
}
|
||||
|
||||
typedef struct drm_r128_getparam32 {
|
||||
int param;
|
||||
u32 value;
|
||||
} drm_r128_getparam32_t;
|
||||
|
||||
static int compat_r128_getparam(struct file *file, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
drm_r128_getparam32_t getparam32;
|
||||
drm_r128_getparam_t __user *getparam;
|
||||
|
||||
if (copy_from_user(&getparam32, (void __user *)arg, sizeof(getparam32)))
|
||||
return -EFAULT;
|
||||
|
||||
getparam = compat_alloc_user_space(sizeof(*getparam));
|
||||
if (!access_ok(VERIFY_WRITE, getparam, sizeof(*getparam))
|
||||
|| __put_user(getparam32.param, &getparam->param)
|
||||
|| __put_user((void __user *)(unsigned long)getparam32.value,
|
||||
&getparam->value))
|
||||
return -EFAULT;
|
||||
|
||||
return drm_ioctl(file->f_path.dentry->d_inode, file,
|
||||
DRM_IOCTL_R128_GETPARAM, (unsigned long)getparam);
|
||||
}
|
||||
|
||||
drm_ioctl_compat_t *r128_compat_ioctls[] = {
|
||||
[DRM_R128_INIT] = compat_r128_init,
|
||||
[DRM_R128_DEPTH] = compat_r128_depth,
|
||||
[DRM_R128_STIPPLE] = compat_r128_stipple,
|
||||
[DRM_R128_GETPARAM] = compat_r128_getparam,
|
||||
};
|
||||
|
||||
/**
|
||||
* Called whenever a 32-bit process running under a 64-bit kernel
|
||||
* performs an ioctl on /dev/dri/card<n>.
|
||||
*
|
||||
* \param filp file pointer.
|
||||
* \param cmd command.
|
||||
* \param arg user argument.
|
||||
* \return zero on success or negative number on failure.
|
||||
*/
|
||||
long r128_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
unsigned int nr = DRM_IOCTL_NR(cmd);
|
||||
drm_ioctl_compat_t *fn = NULL;
|
||||
int ret;
|
||||
|
||||
if (nr < DRM_COMMAND_BASE)
|
||||
return drm_compat_ioctl(filp, cmd, arg);
|
||||
|
||||
if (nr < DRM_COMMAND_BASE + DRM_ARRAY_SIZE(r128_compat_ioctls))
|
||||
fn = r128_compat_ioctls[nr - DRM_COMMAND_BASE];
|
||||
|
||||
lock_kernel(); /* XXX for now */
|
||||
if (fn != NULL)
|
||||
ret = (*fn) (filp, cmd, arg);
|
||||
else
|
||||
ret = drm_ioctl(filp->f_path.dentry->d_inode, filp, cmd, arg);
|
||||
unlock_kernel();
|
||||
|
||||
return ret;
|
||||
}
|
||||
101
drivers/char/drm/r128_irq.c
Normal file
101
drivers/char/drm/r128_irq.c
Normal file
@@ -0,0 +1,101 @@
|
||||
/* 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 "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);
|
||||
}
|
||||
1713
drivers/char/drm/r128_state.c
Normal file
1713
drivers/char/drm/r128_state.c
Normal file
File diff suppressed because it is too large
Load Diff
954
drivers/char/drm/r300_cmdbuf.c
Normal file
954
drivers/char/drm/r300_cmdbuf.c
Normal file
@@ -0,0 +1,954 @@
|
||||
/* 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 "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;
|
||||
}
|
||||
|
||||
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 (!radeon_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 (!radeon_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 (!radeon_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 = !radeon_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 = !radeon_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_indx_buffer(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[1] & 0x8000ffff) != 0x80000810) {
|
||||
DRM_ERROR("Invalid indx_buffer reg address %08X\n", cmd[1]);
|
||||
return DRM_ERR(EINVAL);
|
||||
}
|
||||
ret = !radeon_check_offset(dev_priv, cmd[2]);
|
||||
if (ret) {
|
||||
DRM_ERROR("Invalid indx_buffer offset is %08X\n", cmd[2]);
|
||||
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_INDX_BUFFER: /* DRAW_INDX_2 without INDX_BUFFER seems to lock up the gpu */
|
||||
return r300_emit_indx_buffer(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_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(u64) + 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(u64);
|
||||
cmdbuf->bufsz -= sizeof(u64);
|
||||
|
||||
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;
|
||||
}
|
||||
1435
drivers/char/drm/r300_reg.h
Normal file
1435
drivers/char/drm/r300_reg.h
Normal file
File diff suppressed because it is too large
Load Diff
2249
drivers/char/drm/radeon_cp.c
Normal file
2249
drivers/char/drm/radeon_cp.c
Normal file
File diff suppressed because it is too large
Load Diff
723
drivers/char/drm/radeon_drm.h
Normal file
723
drivers/char/drm/radeon_drm.h
Normal file
@@ -0,0 +1,723 @@
|
||||
/* 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>
|
||||
*/
|
||||
|
||||
#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;
|
||||
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;
|
||||
unsigned long mmio_offset;
|
||||
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
|
||||
125
drivers/char/drm/radeon_drv.c
Normal file
125
drivers/char/drm/radeon_drv.c
Normal file
@@ -0,0 +1,125 @@
|
||||
/**
|
||||
* \file radeon_drv.c
|
||||
* ATI Radeon driver
|
||||
*
|
||||
* \author Gareth Hughes <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.
|
||||
*/
|
||||
|
||||
#include "drmP.h"
|
||||
#include "drm.h"
|
||||
#include "radeon_drm.h"
|
||||
#include "radeon_drv.h"
|
||||
|
||||
#include "drm_pciids.h"
|
||||
|
||||
int radeon_no_wb;
|
||||
|
||||
MODULE_PARM_DESC(no_wb, "Disable AGP writeback for scratch registers\n");
|
||||
module_param_named(no_wb, radeon_no_wb, int, 0444);
|
||||
|
||||
static int dri_library_name(struct drm_device *dev, char *buf)
|
||||
{
|
||||
drm_radeon_private_t *dev_priv = dev->dev_private;
|
||||
int family = dev_priv->flags & RADEON_FAMILY_MASK;
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%s\n",
|
||||
(family < CHIP_R200) ? "radeon" :
|
||||
((family < CHIP_R300) ? "r200" :
|
||||
"r300"));
|
||||
}
|
||||
|
||||
static struct pci_device_id pciidlist[] = {
|
||||
radeon_PCI_IDS
|
||||
};
|
||||
|
||||
static struct drm_driver driver = {
|
||||
.driver_features =
|
||||
DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_SG |
|
||||
DRIVER_HAVE_IRQ | DRIVER_HAVE_DMA | DRIVER_IRQ_SHARED |
|
||||
DRIVER_IRQ_VBL,
|
||||
.dev_priv_size = sizeof(drm_radeon_buf_priv_t),
|
||||
.load = radeon_driver_load,
|
||||
.firstopen = radeon_driver_firstopen,
|
||||
.open = radeon_driver_open,
|
||||
.preclose = radeon_driver_preclose,
|
||||
.postclose = radeon_driver_postclose,
|
||||
.lastclose = radeon_driver_lastclose,
|
||||
.unload = radeon_driver_unload,
|
||||
.vblank_wait = radeon_driver_vblank_wait,
|
||||
.dri_library_name = dri_library_name,
|
||||
.irq_preinstall = radeon_driver_irq_preinstall,
|
||||
.irq_postinstall = radeon_driver_irq_postinstall,
|
||||
.irq_uninstall = radeon_driver_irq_uninstall,
|
||||
.irq_handler = radeon_driver_irq_handler,
|
||||
.reclaim_buffers = drm_core_reclaim_buffers,
|
||||
.get_map_ofs = drm_core_get_map_ofs,
|
||||
.get_reg_ofs = drm_core_get_reg_ofs,
|
||||
.ioctls = radeon_ioctls,
|
||||
.dma_ioctl = radeon_cp_buffers,
|
||||
.fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = drm_open,
|
||||
.release = drm_release,
|
||||
.ioctl = drm_ioctl,
|
||||
.mmap = drm_mmap,
|
||||
.poll = drm_poll,
|
||||
.fasync = drm_fasync,
|
||||
#ifdef CONFIG_COMPAT
|
||||
.compat_ioctl = radeon_compat_ioctl,
|
||||
#endif
|
||||
},
|
||||
|
||||
.pci_driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.id_table = pciidlist,
|
||||
},
|
||||
|
||||
.name = DRIVER_NAME,
|
||||
.desc = DRIVER_DESC,
|
||||
.date = DRIVER_DATE,
|
||||
.major = DRIVER_MAJOR,
|
||||
.minor = DRIVER_MINOR,
|
||||
.patchlevel = DRIVER_PATCHLEVEL,
|
||||
};
|
||||
|
||||
static int __init radeon_init(void)
|
||||
{
|
||||
driver.num_ioctls = radeon_max_ioctl;
|
||||
return drm_init(&driver);
|
||||
}
|
||||
|
||||
static void __exit radeon_exit(void)
|
||||
{
|
||||
drm_exit(&driver);
|
||||
}
|
||||
|
||||
module_init(radeon_init);
|
||||
module_exit(radeon_exit);
|
||||
|
||||
MODULE_AUTHOR(DRIVER_AUTHOR);
|
||||
MODULE_DESCRIPTION(DRIVER_DESC);
|
||||
MODULE_LICENSE("GPL and additional rights");
|
||||
1157
drivers/char/drm/radeon_drv.h
Normal file
1157
drivers/char/drm/radeon_drv.h
Normal file
File diff suppressed because it is too large
Load Diff
393
drivers/char/drm/radeon_ioc32.c
Normal file
393
drivers/char/drm/radeon_ioc32.c
Normal file
@@ -0,0 +1,393 @@
|
||||
/**
|
||||
* \file radeon_ioc32.c
|
||||
*
|
||||
* 32-bit ioctl compatibility routines for the Radeon DRM.
|
||||
*
|
||||
* \author Paul Mackerras <paulus@samba.org>
|
||||
*
|
||||
* Copyright (C) Paul Mackerras 2005
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
#include <linux/compat.h>
|
||||
|
||||
#include "drmP.h"
|
||||
#include "drm.h"
|
||||
#include "radeon_drm.h"
|
||||
#include "radeon_drv.h"
|
||||
|
||||
typedef struct drm_radeon_init32 {
|
||||
int func;
|
||||
u32 sarea_priv_offset;
|
||||
int is_pci;
|
||||
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;
|
||||
|
||||
u32 fb_offset;
|
||||
u32 mmio_offset;
|
||||
u32 ring_offset;
|
||||
u32 ring_rptr_offset;
|
||||
u32 buffers_offset;
|
||||
u32 gart_textures_offset;
|
||||
} drm_radeon_init32_t;
|
||||
|
||||
static int compat_radeon_cp_init(struct file *file, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
drm_radeon_init32_t init32;
|
||||
drm_radeon_init_t __user *init;
|
||||
|
||||
if (copy_from_user(&init32, (void __user *)arg, sizeof(init32)))
|
||||
return -EFAULT;
|
||||
|
||||
init = compat_alloc_user_space(sizeof(*init));
|
||||
if (!access_ok(VERIFY_WRITE, init, sizeof(*init))
|
||||
|| __put_user(init32.func, &init->func)
|
||||
|| __put_user(init32.sarea_priv_offset, &init->sarea_priv_offset)
|
||||
|| __put_user(init32.is_pci, &init->is_pci)
|
||||
|| __put_user(init32.cp_mode, &init->cp_mode)
|
||||
|| __put_user(init32.gart_size, &init->gart_size)
|
||||
|| __put_user(init32.ring_size, &init->ring_size)
|
||||
|| __put_user(init32.usec_timeout, &init->usec_timeout)
|
||||
|| __put_user(init32.fb_bpp, &init->fb_bpp)
|
||||
|| __put_user(init32.front_offset, &init->front_offset)
|
||||
|| __put_user(init32.front_pitch, &init->front_pitch)
|
||||
|| __put_user(init32.back_offset, &init->back_offset)
|
||||
|| __put_user(init32.back_pitch, &init->back_pitch)
|
||||
|| __put_user(init32.depth_bpp, &init->depth_bpp)
|
||||
|| __put_user(init32.depth_offset, &init->depth_offset)
|
||||
|| __put_user(init32.depth_pitch, &init->depth_pitch)
|
||||
|| __put_user(init32.fb_offset, &init->fb_offset)
|
||||
|| __put_user(init32.mmio_offset, &init->mmio_offset)
|
||||
|| __put_user(init32.ring_offset, &init->ring_offset)
|
||||
|| __put_user(init32.ring_rptr_offset, &init->ring_rptr_offset)
|
||||
|| __put_user(init32.buffers_offset, &init->buffers_offset)
|
||||
|| __put_user(init32.gart_textures_offset,
|
||||
&init->gart_textures_offset))
|
||||
return -EFAULT;
|
||||
|
||||
return drm_ioctl(file->f_path.dentry->d_inode, file,
|
||||
DRM_IOCTL_RADEON_CP_INIT, (unsigned long)init);
|
||||
}
|
||||
|
||||
typedef struct drm_radeon_clear32 {
|
||||
unsigned int flags;
|
||||
unsigned int clear_color;
|
||||
unsigned int clear_depth;
|
||||
unsigned int color_mask;
|
||||
unsigned int depth_mask; /* misnamed field: should be stencil */
|
||||
u32 depth_boxes;
|
||||
} drm_radeon_clear32_t;
|
||||
|
||||
static int compat_radeon_cp_clear(struct file *file, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
drm_radeon_clear32_t clr32;
|
||||
drm_radeon_clear_t __user *clr;
|
||||
|
||||
if (copy_from_user(&clr32, (void __user *)arg, sizeof(clr32)))
|
||||
return -EFAULT;
|
||||
|
||||
clr = compat_alloc_user_space(sizeof(*clr));
|
||||
if (!access_ok(VERIFY_WRITE, clr, sizeof(*clr))
|
||||
|| __put_user(clr32.flags, &clr->flags)
|
||||
|| __put_user(clr32.clear_color, &clr->clear_color)
|
||||
|| __put_user(clr32.clear_depth, &clr->clear_depth)
|
||||
|| __put_user(clr32.color_mask, &clr->color_mask)
|
||||
|| __put_user(clr32.depth_mask, &clr->depth_mask)
|
||||
|| __put_user((void __user *)(unsigned long)clr32.depth_boxes,
|
||||
&clr->depth_boxes))
|
||||
return -EFAULT;
|
||||
|
||||
return drm_ioctl(file->f_path.dentry->d_inode, file,
|
||||
DRM_IOCTL_RADEON_CLEAR, (unsigned long)clr);
|
||||
}
|
||||
|
||||
typedef struct drm_radeon_stipple32 {
|
||||
u32 mask;
|
||||
} drm_radeon_stipple32_t;
|
||||
|
||||
static int compat_radeon_cp_stipple(struct file *file, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
drm_radeon_stipple32_t __user *argp = (void __user *)arg;
|
||||
drm_radeon_stipple_t __user *request;
|
||||
u32 mask;
|
||||
|
||||
if (get_user(mask, &argp->mask))
|
||||
return -EFAULT;
|
||||
|
||||
request = compat_alloc_user_space(sizeof(*request));
|
||||
if (!access_ok(VERIFY_WRITE, request, sizeof(*request))
|
||||
|| __put_user((unsigned int __user *)(unsigned long)mask,
|
||||
&request->mask))
|
||||
return -EFAULT;
|
||||
|
||||
return drm_ioctl(file->f_path.dentry->d_inode, file,
|
||||
DRM_IOCTL_RADEON_STIPPLE, (unsigned long)request);
|
||||
}
|
||||
|
||||
typedef struct drm_radeon_tex_image32 {
|
||||
unsigned int x, y; /* Blit coordinates */
|
||||
unsigned int width, height;
|
||||
u32 data;
|
||||
} drm_radeon_tex_image32_t;
|
||||
|
||||
typedef struct drm_radeon_texture32 {
|
||||
unsigned int offset;
|
||||
int pitch;
|
||||
int format;
|
||||
int width; /* Texture image coordinates */
|
||||
int height;
|
||||
u32 image;
|
||||
} drm_radeon_texture32_t;
|
||||
|
||||
static int compat_radeon_cp_texture(struct file *file, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
drm_radeon_texture32_t req32;
|
||||
drm_radeon_texture_t __user *request;
|
||||
drm_radeon_tex_image32_t img32;
|
||||
drm_radeon_tex_image_t __user *image;
|
||||
|
||||
if (copy_from_user(&req32, (void __user *)arg, sizeof(req32)))
|
||||
return -EFAULT;
|
||||
if (req32.image == 0)
|
||||
return -EINVAL;
|
||||
if (copy_from_user(&img32, (void __user *)(unsigned long)req32.image,
|
||||
sizeof(img32)))
|
||||
return -EFAULT;
|
||||
|
||||
request = compat_alloc_user_space(sizeof(*request) + sizeof(*image));
|
||||
if (!access_ok(VERIFY_WRITE, request,
|
||||
sizeof(*request) + sizeof(*image)))
|
||||
return -EFAULT;
|
||||
image = (drm_radeon_tex_image_t __user *) (request + 1);
|
||||
|
||||
if (__put_user(req32.offset, &request->offset)
|
||||
|| __put_user(req32.pitch, &request->pitch)
|
||||
|| __put_user(req32.format, &request->format)
|
||||
|| __put_user(req32.width, &request->width)
|
||||
|| __put_user(req32.height, &request->height)
|
||||
|| __put_user(image, &request->image)
|
||||
|| __put_user(img32.x, &image->x)
|
||||
|| __put_user(img32.y, &image->y)
|
||||
|| __put_user(img32.width, &image->width)
|
||||
|| __put_user(img32.height, &image->height)
|
||||
|| __put_user((const void __user *)(unsigned long)img32.data,
|
||||
&image->data))
|
||||
return -EFAULT;
|
||||
|
||||
return drm_ioctl(file->f_path.dentry->d_inode, file,
|
||||
DRM_IOCTL_RADEON_TEXTURE, (unsigned long)request);
|
||||
}
|
||||
|
||||
typedef struct drm_radeon_vertex2_32 {
|
||||
int idx; /* Index of vertex buffer */
|
||||
int discard; /* Client finished with buffer? */
|
||||
int nr_states;
|
||||
u32 state;
|
||||
int nr_prims;
|
||||
u32 prim;
|
||||
} drm_radeon_vertex2_32_t;
|
||||
|
||||
static int compat_radeon_cp_vertex2(struct file *file, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
drm_radeon_vertex2_32_t req32;
|
||||
drm_radeon_vertex2_t __user *request;
|
||||
|
||||
if (copy_from_user(&req32, (void __user *)arg, sizeof(req32)))
|
||||
return -EFAULT;
|
||||
|
||||
request = compat_alloc_user_space(sizeof(*request));
|
||||
if (!access_ok(VERIFY_WRITE, request, sizeof(*request))
|
||||
|| __put_user(req32.idx, &request->idx)
|
||||
|| __put_user(req32.discard, &request->discard)
|
||||
|| __put_user(req32.nr_states, &request->nr_states)
|
||||
|| __put_user((void __user *)(unsigned long)req32.state,
|
||||
&request->state)
|
||||
|| __put_user(req32.nr_prims, &request->nr_prims)
|
||||
|| __put_user((void __user *)(unsigned long)req32.prim,
|
||||
&request->prim))
|
||||
return -EFAULT;
|
||||
|
||||
return drm_ioctl(file->f_path.dentry->d_inode, file,
|
||||
DRM_IOCTL_RADEON_VERTEX2, (unsigned long)request);
|
||||
}
|
||||
|
||||
typedef struct drm_radeon_cmd_buffer32 {
|
||||
int bufsz;
|
||||
u32 buf;
|
||||
int nbox;
|
||||
u32 boxes;
|
||||
} drm_radeon_cmd_buffer32_t;
|
||||
|
||||
static int compat_radeon_cp_cmdbuf(struct file *file, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
drm_radeon_cmd_buffer32_t req32;
|
||||
drm_radeon_cmd_buffer_t __user *request;
|
||||
|
||||
if (copy_from_user(&req32, (void __user *)arg, sizeof(req32)))
|
||||
return -EFAULT;
|
||||
|
||||
request = compat_alloc_user_space(sizeof(*request));
|
||||
if (!access_ok(VERIFY_WRITE, request, sizeof(*request))
|
||||
|| __put_user(req32.bufsz, &request->bufsz)
|
||||
|| __put_user((void __user *)(unsigned long)req32.buf,
|
||||
&request->buf)
|
||||
|| __put_user(req32.nbox, &request->nbox)
|
||||
|| __put_user((void __user *)(unsigned long)req32.boxes,
|
||||
&request->boxes))
|
||||
return -EFAULT;
|
||||
|
||||
return drm_ioctl(file->f_path.dentry->d_inode, file,
|
||||
DRM_IOCTL_RADEON_CMDBUF, (unsigned long)request);
|
||||
}
|
||||
|
||||
typedef struct drm_radeon_getparam32 {
|
||||
int param;
|
||||
u32 value;
|
||||
} drm_radeon_getparam32_t;
|
||||
|
||||
static int compat_radeon_cp_getparam(struct file *file, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
drm_radeon_getparam32_t req32;
|
||||
drm_radeon_getparam_t __user *request;
|
||||
|
||||
if (copy_from_user(&req32, (void __user *)arg, sizeof(req32)))
|
||||
return -EFAULT;
|
||||
|
||||
request = compat_alloc_user_space(sizeof(*request));
|
||||
if (!access_ok(VERIFY_WRITE, request, sizeof(*request))
|
||||
|| __put_user(req32.param, &request->param)
|
||||
|| __put_user((void __user *)(unsigned long)req32.value,
|
||||
&request->value))
|
||||
return -EFAULT;
|
||||
|
||||
return drm_ioctl(file->f_path.dentry->d_inode, file,
|
||||
DRM_IOCTL_RADEON_GETPARAM, (unsigned long)request);
|
||||
}
|
||||
|
||||
typedef struct drm_radeon_mem_alloc32 {
|
||||
int region;
|
||||
int alignment;
|
||||
int size;
|
||||
u32 region_offset; /* offset from start of fb or GART */
|
||||
} drm_radeon_mem_alloc32_t;
|
||||
|
||||
static int compat_radeon_mem_alloc(struct file *file, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
drm_radeon_mem_alloc32_t req32;
|
||||
drm_radeon_mem_alloc_t __user *request;
|
||||
|
||||
if (copy_from_user(&req32, (void __user *)arg, sizeof(req32)))
|
||||
return -EFAULT;
|
||||
|
||||
request = compat_alloc_user_space(sizeof(*request));
|
||||
if (!access_ok(VERIFY_WRITE, request, sizeof(*request))
|
||||
|| __put_user(req32.region, &request->region)
|
||||
|| __put_user(req32.alignment, &request->alignment)
|
||||
|| __put_user(req32.size, &request->size)
|
||||
|| __put_user((int __user *)(unsigned long)req32.region_offset,
|
||||
&request->region_offset))
|
||||
return -EFAULT;
|
||||
|
||||
return drm_ioctl(file->f_path.dentry->d_inode, file,
|
||||
DRM_IOCTL_RADEON_ALLOC, (unsigned long)request);
|
||||
}
|
||||
|
||||
typedef struct drm_radeon_irq_emit32 {
|
||||
u32 irq_seq;
|
||||
} drm_radeon_irq_emit32_t;
|
||||
|
||||
static int compat_radeon_irq_emit(struct file *file, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
drm_radeon_irq_emit32_t req32;
|
||||
drm_radeon_irq_emit_t __user *request;
|
||||
|
||||
if (copy_from_user(&req32, (void __user *)arg, sizeof(req32)))
|
||||
return -EFAULT;
|
||||
|
||||
request = compat_alloc_user_space(sizeof(*request));
|
||||
if (!access_ok(VERIFY_WRITE, request, sizeof(*request))
|
||||
|| __put_user((int __user *)(unsigned long)req32.irq_seq,
|
||||
&request->irq_seq))
|
||||
return -EFAULT;
|
||||
|
||||
return drm_ioctl(file->f_path.dentry->d_inode, file,
|
||||
DRM_IOCTL_RADEON_IRQ_EMIT, (unsigned long)request);
|
||||
}
|
||||
|
||||
drm_ioctl_compat_t *radeon_compat_ioctls[] = {
|
||||
[DRM_RADEON_CP_INIT] = compat_radeon_cp_init,
|
||||
[DRM_RADEON_CLEAR] = compat_radeon_cp_clear,
|
||||
[DRM_RADEON_STIPPLE] = compat_radeon_cp_stipple,
|
||||
[DRM_RADEON_TEXTURE] = compat_radeon_cp_texture,
|
||||
[DRM_RADEON_VERTEX2] = compat_radeon_cp_vertex2,
|
||||
[DRM_RADEON_CMDBUF] = compat_radeon_cp_cmdbuf,
|
||||
[DRM_RADEON_GETPARAM] = compat_radeon_cp_getparam,
|
||||
[DRM_RADEON_ALLOC] = compat_radeon_mem_alloc,
|
||||
[DRM_RADEON_IRQ_EMIT] = compat_radeon_irq_emit,
|
||||
};
|
||||
|
||||
/**
|
||||
* Called whenever a 32-bit process running under a 64-bit kernel
|
||||
* performs an ioctl on /dev/dri/card<n>.
|
||||
*
|
||||
* \param filp file pointer.
|
||||
* \param cmd command.
|
||||
* \param arg user argument.
|
||||
* \return zero on success or negative number on failure.
|
||||
*/
|
||||
long radeon_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
unsigned int nr = DRM_IOCTL_NR(cmd);
|
||||
drm_ioctl_compat_t *fn = NULL;
|
||||
int ret;
|
||||
|
||||
if (nr < DRM_COMMAND_BASE)
|
||||
return drm_compat_ioctl(filp, cmd, arg);
|
||||
|
||||
if (nr < DRM_COMMAND_BASE + DRM_ARRAY_SIZE(radeon_compat_ioctls))
|
||||
fn = radeon_compat_ioctls[nr - DRM_COMMAND_BASE];
|
||||
|
||||
lock_kernel(); /* XXX for now */
|
||||
if (fn != NULL)
|
||||
ret = (*fn) (filp, cmd, arg);
|
||||
else
|
||||
ret = drm_ioctl(filp->f_path.dentry->d_inode, filp, cmd, arg);
|
||||
unlock_kernel();
|
||||
|
||||
return ret;
|
||||
}
|
||||
244
drivers/char/drm/radeon_irq.c
Normal file
244
drivers/char/drm/radeon_irq.c
Normal file
@@ -0,0 +1,244 @@
|
||||
/* 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<>zer <michel@daenzer.net>
|
||||
*/
|
||||
|
||||
#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);
|
||||
}
|
||||
314
drivers/char/drm/radeon_mem.c
Normal file
314
drivers/char/drm/radeon_mem.c
Normal file
@@ -0,0 +1,314 @@
|
||||
/* 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 "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);
|
||||
}
|
||||
3245
drivers/char/drm/radeon_state.c
Normal file
3245
drivers/char/drm/radeon_state.c
Normal file
File diff suppressed because it is too large
Load Diff
1111
drivers/char/drm/savage_bci.c
Normal file
1111
drivers/char/drm/savage_bci.c
Normal file
File diff suppressed because it is too large
Load Diff
210
drivers/char/drm/savage_drm.h
Normal file
210
drivers/char/drm/savage_drm.h
Normal file
@@ -0,0 +1,210 @@
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
#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
|
||||
88
drivers/char/drm/savage_drv.c
Normal file
88
drivers/char/drm/savage_drv.c
Normal file
@@ -0,0 +1,88 @@
|
||||
/* savage_drv.c -- Savage driver for Linux
|
||||
*
|
||||
* 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 "drmP.h"
|
||||
#include "savage_drm.h"
|
||||
#include "savage_drv.h"
|
||||
|
||||
#include "drm_pciids.h"
|
||||
|
||||
static struct pci_device_id pciidlist[] = {
|
||||
savage_PCI_IDS
|
||||
};
|
||||
|
||||
static struct drm_driver driver = {
|
||||
.driver_features =
|
||||
DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_HAVE_DMA | DRIVER_PCI_DMA,
|
||||
.dev_priv_size = sizeof(drm_savage_buf_priv_t),
|
||||
.load = savage_driver_load,
|
||||
.firstopen = savage_driver_firstopen,
|
||||
.lastclose = savage_driver_lastclose,
|
||||
.unload = savage_driver_unload,
|
||||
.reclaim_buffers = savage_reclaim_buffers,
|
||||
.get_map_ofs = drm_core_get_map_ofs,
|
||||
.get_reg_ofs = drm_core_get_reg_ofs,
|
||||
.ioctls = savage_ioctls,
|
||||
.dma_ioctl = savage_bci_buffers,
|
||||
.fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = drm_open,
|
||||
.release = drm_release,
|
||||
.ioctl = drm_ioctl,
|
||||
.mmap = drm_mmap,
|
||||
.poll = drm_poll,
|
||||
.fasync = drm_fasync,
|
||||
},
|
||||
|
||||
.pci_driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.id_table = pciidlist,
|
||||
},
|
||||
|
||||
.name = DRIVER_NAME,
|
||||
.desc = DRIVER_DESC,
|
||||
.date = DRIVER_DATE,
|
||||
.major = DRIVER_MAJOR,
|
||||
.minor = DRIVER_MINOR,
|
||||
.patchlevel = DRIVER_PATCHLEVEL,
|
||||
};
|
||||
|
||||
static int __init savage_init(void)
|
||||
{
|
||||
driver.num_ioctls = savage_max_ioctl;
|
||||
return drm_init(&driver);
|
||||
}
|
||||
|
||||
static void __exit savage_exit(void)
|
||||
{
|
||||
drm_exit(&driver);
|
||||
}
|
||||
|
||||
module_init(savage_init);
|
||||
module_exit(savage_exit);
|
||||
|
||||
MODULE_AUTHOR(DRIVER_AUTHOR);
|
||||
MODULE_DESCRIPTION(DRIVER_DESC);
|
||||
MODULE_LICENSE("GPL and additional rights");
|
||||
574
drivers/char/drm/savage_drv.h
Normal file
574
drivers/char/drm/savage_drv.h
Normal file
@@ -0,0 +1,574 @@
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
#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 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__ */
|
||||
1165
drivers/char/drm/savage_state.c
Normal file
1165
drivers/char/drm/savage_state.c
Normal file
File diff suppressed because it is too large
Load Diff
67
drivers/char/drm/sis_drm.h
Normal file
67
drivers/char/drm/sis_drm.h
Normal file
@@ -0,0 +1,67 @@
|
||||
/* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#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__ */
|
||||
117
drivers/char/drm/sis_drv.c
Normal file
117
drivers/char/drm/sis_drv.c
Normal file
@@ -0,0 +1,117 @@
|
||||
/* 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 "drmP.h"
|
||||
#include "sis_drm.h"
|
||||
#include "sis_drv.h"
|
||||
|
||||
#include "drm_pciids.h"
|
||||
|
||||
static struct pci_device_id pciidlist[] = {
|
||||
sisdrv_PCI_IDS
|
||||
};
|
||||
|
||||
static int sis_driver_load(drm_device_t *dev, unsigned long chipset)
|
||||
{
|
||||
drm_sis_private_t *dev_priv;
|
||||
int ret;
|
||||
|
||||
dev_priv = drm_calloc(1, sizeof(drm_sis_private_t), DRM_MEM_DRIVER);
|
||||
if (dev_priv == NULL)
|
||||
return DRM_ERR(ENOMEM);
|
||||
|
||||
dev->dev_private = (void *)dev_priv;
|
||||
dev_priv->chipset = chipset;
|
||||
ret = drm_sman_init(&dev_priv->sman, 2, 12, 8);
|
||||
if (ret) {
|
||||
drm_free(dev_priv, sizeof(dev_priv), DRM_MEM_DRIVER);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sis_driver_unload(drm_device_t *dev)
|
||||
{
|
||||
drm_sis_private_t *dev_priv = dev->dev_private;
|
||||
|
||||
drm_sman_takedown(&dev_priv->sman);
|
||||
drm_free(dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct drm_driver driver = {
|
||||
.driver_features = DRIVER_USE_AGP | DRIVER_USE_MTRR,
|
||||
.load = sis_driver_load,
|
||||
.unload = sis_driver_unload,
|
||||
.context_dtor = NULL,
|
||||
.dma_quiescent = sis_idle,
|
||||
.reclaim_buffers = NULL,
|
||||
.reclaim_buffers_locked = sis_reclaim_buffers_locked,
|
||||
.lastclose = sis_lastclose,
|
||||
.get_map_ofs = drm_core_get_map_ofs,
|
||||
.get_reg_ofs = drm_core_get_reg_ofs,
|
||||
.ioctls = sis_ioctls,
|
||||
.fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = drm_open,
|
||||
.release = drm_release,
|
||||
.ioctl = drm_ioctl,
|
||||
.mmap = drm_mmap,
|
||||
.poll = drm_poll,
|
||||
.fasync = drm_fasync,
|
||||
},
|
||||
.pci_driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.id_table = pciidlist,
|
||||
},
|
||||
|
||||
.name = DRIVER_NAME,
|
||||
.desc = DRIVER_DESC,
|
||||
.date = DRIVER_DATE,
|
||||
.major = DRIVER_MAJOR,
|
||||
.minor = DRIVER_MINOR,
|
||||
.patchlevel = DRIVER_PATCHLEVEL,
|
||||
};
|
||||
|
||||
static int __init sis_init(void)
|
||||
{
|
||||
driver.num_ioctls = sis_max_ioctl;
|
||||
return drm_init(&driver);
|
||||
}
|
||||
|
||||
static void __exit sis_exit(void)
|
||||
{
|
||||
drm_exit(&driver);
|
||||
}
|
||||
|
||||
module_init(sis_init);
|
||||
module_exit(sis_exit);
|
||||
|
||||
MODULE_AUTHOR(DRIVER_AUTHOR);
|
||||
MODULE_DESCRIPTION(DRIVER_DESC);
|
||||
MODULE_LICENSE("GPL and additional rights");
|
||||
71
drivers/char/drm/sis_drv.h
Normal file
71
drivers/char/drm/sis_drv.h
Normal file
@@ -0,0 +1,71 @@
|
||||
/* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _SIS_DRV_H_
|
||||
#define _SIS_DRV_H_
|
||||
|
||||
/* General customization:
|
||||
*/
|
||||
|
||||
#define DRIVER_AUTHOR "SIS, Tungsten Graphics"
|
||||
#define DRIVER_NAME "sis"
|
||||
#define DRIVER_DESC "SIS 300/630/540"
|
||||
#define DRIVER_DATE "20060704"
|
||||
#define DRIVER_MAJOR 1
|
||||
#define DRIVER_MINOR 2
|
||||
#define DRIVER_PATCHLEVEL 1
|
||||
|
||||
enum sis_family {
|
||||
SIS_OTHER = 0,
|
||||
SIS_CHIP_315 = 1,
|
||||
};
|
||||
|
||||
#include "drm_sman.h"
|
||||
|
||||
#define SIS_BASE (dev_priv->mmio)
|
||||
#define SIS_READ(reg) DRM_READ32(SIS_BASE, reg);
|
||||
#define SIS_WRITE(reg, val) DRM_WRITE32(SIS_BASE, reg, val);
|
||||
|
||||
typedef struct drm_sis_private {
|
||||
drm_local_map_t *mmio;
|
||||
unsigned int idle_fault;
|
||||
drm_sman_t sman;
|
||||
unsigned int chipset;
|
||||
int vram_initialized;
|
||||
int agp_initialized;
|
||||
unsigned long vram_offset;
|
||||
unsigned long agp_offset;
|
||||
} drm_sis_private_t;
|
||||
|
||||
extern int sis_idle(drm_device_t *dev);
|
||||
extern void sis_reclaim_buffers_locked(drm_device_t *dev, struct file *filp);
|
||||
extern void sis_lastclose(drm_device_t *dev);
|
||||
|
||||
extern drm_ioctl_desc_t sis_ioctls[];
|
||||
extern int sis_max_ioctl;
|
||||
|
||||
#endif
|
||||
348
drivers/char/drm/sis_mm.c
Normal file
348
drivers/char/drm/sis_mm.c
Normal file
@@ -0,0 +1,348 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sub license, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the
|
||||
* next paragraph) shall be included in all copies or substantial portions
|
||||
* of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
* USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*
|
||||
**************************************************************************/
|
||||
|
||||
/*
|
||||
* Authors:
|
||||
* Thomas Hellström <thomas-at-tungstengraphics-dot-com>
|
||||
*/
|
||||
|
||||
#include "drmP.h"
|
||||
#include "sis_drm.h"
|
||||
#include "sis_drv.h"
|
||||
|
||||
#include <video/sisfb.h>
|
||||
|
||||
#define VIDEO_TYPE 0
|
||||
#define AGP_TYPE 1
|
||||
|
||||
|
||||
#if defined(CONFIG_FB_SIS)
|
||||
/* fb management via fb device */
|
||||
|
||||
#define SIS_MM_ALIGN_SHIFT 0
|
||||
#define SIS_MM_ALIGN_MASK 0
|
||||
|
||||
static void *sis_sman_mm_allocate(void *private, unsigned long size,
|
||||
unsigned alignment)
|
||||
{
|
||||
struct sis_memreq req;
|
||||
|
||||
req.size = size;
|
||||
sis_malloc(&req);
|
||||
if (req.size == 0)
|
||||
return NULL;
|
||||
else
|
||||
return (void *)~req.offset;
|
||||
}
|
||||
|
||||
static void sis_sman_mm_free(void *private, void *ref)
|
||||
{
|
||||
sis_free(~((unsigned long)ref));
|
||||
}
|
||||
|
||||
static void sis_sman_mm_destroy(void *private)
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
static unsigned long sis_sman_mm_offset(void *private, void *ref)
|
||||
{
|
||||
return ~((unsigned long)ref);
|
||||
}
|
||||
|
||||
#else /* CONFIG_FB_SIS */
|
||||
|
||||
#define SIS_MM_ALIGN_SHIFT 4
|
||||
#define SIS_MM_ALIGN_MASK ( (1 << SIS_MM_ALIGN_SHIFT) - 1)
|
||||
|
||||
#endif /* CONFIG_FB_SIS */
|
||||
|
||||
static int sis_fb_init(DRM_IOCTL_ARGS)
|
||||
{
|
||||
DRM_DEVICE;
|
||||
drm_sis_private_t *dev_priv = dev->dev_private;
|
||||
drm_sis_fb_t fb;
|
||||
int ret;
|
||||
|
||||
DRM_COPY_FROM_USER_IOCTL(fb, (drm_sis_fb_t __user *) data, sizeof(fb));
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
#if defined(CONFIG_FB_SIS)
|
||||
{
|
||||
drm_sman_mm_t sman_mm;
|
||||
sman_mm.private = (void *)0xFFFFFFFF;
|
||||
sman_mm.allocate = sis_sman_mm_allocate;
|
||||
sman_mm.free = sis_sman_mm_free;
|
||||
sman_mm.destroy = sis_sman_mm_destroy;
|
||||
sman_mm.offset = sis_sman_mm_offset;
|
||||
ret =
|
||||
drm_sman_set_manager(&dev_priv->sman, VIDEO_TYPE, &sman_mm);
|
||||
}
|
||||
#else
|
||||
ret = drm_sman_set_range(&dev_priv->sman, VIDEO_TYPE, 0,
|
||||
fb.size >> SIS_MM_ALIGN_SHIFT);
|
||||
#endif
|
||||
|
||||
if (ret) {
|
||||
DRM_ERROR("VRAM memory manager initialisation error\n");
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
dev_priv->vram_initialized = 1;
|
||||
dev_priv->vram_offset = fb.offset;
|
||||
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
DRM_DEBUG("offset = %u, size = %u", fb.offset, fb.size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sis_drm_alloc(drm_device_t * dev, drm_file_t * priv,
|
||||
unsigned long data, int pool)
|
||||
{
|
||||
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 mem;
|
||||
int retval = 0;
|
||||
drm_memblock_item_t *item;
|
||||
|
||||
DRM_COPY_FROM_USER_IOCTL(mem, argp, sizeof(mem));
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
|
||||
if (0 == ((pool == 0) ? dev_priv->vram_initialized :
|
||||
dev_priv->agp_initialized)) {
|
||||
DRM_ERROR
|
||||
("Attempt to allocate from uninitialized memory manager.\n");
|
||||
return DRM_ERR(EINVAL);
|
||||
}
|
||||
|
||||
mem.size = (mem.size + SIS_MM_ALIGN_MASK) >> SIS_MM_ALIGN_SHIFT;
|
||||
item = drm_sman_alloc(&dev_priv->sman, pool, mem.size, 0,
|
||||
(unsigned long)priv);
|
||||
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
if (item) {
|
||||
mem.offset = ((pool == 0) ?
|
||||
dev_priv->vram_offset : dev_priv->agp_offset) +
|
||||
(item->mm->
|
||||
offset(item->mm, item->mm_info) << SIS_MM_ALIGN_SHIFT);
|
||||
mem.free = item->user_hash.key;
|
||||
mem.size = mem.size << SIS_MM_ALIGN_SHIFT;
|
||||
} else {
|
||||
mem.offset = 0;
|
||||
mem.size = 0;
|
||||
mem.free = 0;
|
||||
retval = DRM_ERR(ENOMEM);
|
||||
}
|
||||
|
||||
DRM_COPY_TO_USER_IOCTL(argp, mem, sizeof(mem));
|
||||
|
||||
DRM_DEBUG("alloc %d, size = %d, offset = %d\n", pool, mem.size,
|
||||
mem.offset);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int sis_drm_free(DRM_IOCTL_ARGS)
|
||||
{
|
||||
DRM_DEVICE;
|
||||
drm_sis_private_t *dev_priv = dev->dev_private;
|
||||
drm_sis_mem_t mem;
|
||||
int ret;
|
||||
|
||||
DRM_COPY_FROM_USER_IOCTL(mem, (drm_sis_mem_t __user *) data,
|
||||
sizeof(mem));
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
ret = drm_sman_free_key(&dev_priv->sman, mem.free);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
DRM_DEBUG("free = 0x%lx\n", mem.free);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sis_fb_alloc(DRM_IOCTL_ARGS)
|
||||
{
|
||||
DRM_DEVICE;
|
||||
return sis_drm_alloc(dev, priv, data, VIDEO_TYPE);
|
||||
}
|
||||
|
||||
static int sis_ioctl_agp_init(DRM_IOCTL_ARGS)
|
||||
{
|
||||
DRM_DEVICE;
|
||||
drm_sis_private_t *dev_priv = dev->dev_private;
|
||||
drm_sis_agp_t agp;
|
||||
int ret;
|
||||
dev_priv = dev->dev_private;
|
||||
|
||||
DRM_COPY_FROM_USER_IOCTL(agp, (drm_sis_agp_t __user *) data,
|
||||
sizeof(agp));
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
ret = drm_sman_set_range(&dev_priv->sman, AGP_TYPE, 0,
|
||||
agp.size >> SIS_MM_ALIGN_SHIFT);
|
||||
|
||||
if (ret) {
|
||||
DRM_ERROR("AGP memory manager initialisation error\n");
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
dev_priv->agp_initialized = 1;
|
||||
dev_priv->agp_offset = agp.offset;
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
DRM_DEBUG("offset = %u, size = %u", agp.offset, agp.size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sis_ioctl_agp_alloc(DRM_IOCTL_ARGS)
|
||||
{
|
||||
DRM_DEVICE;
|
||||
|
||||
return sis_drm_alloc(dev, priv, data, AGP_TYPE);
|
||||
}
|
||||
|
||||
static drm_local_map_t *sis_reg_init(drm_device_t *dev)
|
||||
{
|
||||
drm_map_list_t *entry;
|
||||
drm_local_map_t *map;
|
||||
|
||||
list_for_each_entry(entry, &dev->maplist->head, head) {
|
||||
map = entry->map;
|
||||
if (!map)
|
||||
continue;
|
||||
if (map->type == _DRM_REGISTERS) {
|
||||
return map;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int sis_idle(drm_device_t *dev)
|
||||
{
|
||||
drm_sis_private_t *dev_priv = dev->dev_private;
|
||||
uint32_t idle_reg;
|
||||
unsigned long end;
|
||||
int i;
|
||||
|
||||
if (dev_priv->idle_fault)
|
||||
return 0;
|
||||
|
||||
if (dev_priv->mmio == NULL) {
|
||||
dev_priv->mmio = sis_reg_init(dev);
|
||||
if (dev_priv->mmio == NULL) {
|
||||
DRM_ERROR("Could not find register map.\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Implement a device switch here if needed
|
||||
*/
|
||||
|
||||
if (dev_priv->chipset != SIS_CHIP_315)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Timeout after 3 seconds. We cannot use DRM_WAIT_ON here
|
||||
* because its polling frequency is too low.
|
||||
*/
|
||||
|
||||
end = jiffies + (DRM_HZ * 3);
|
||||
|
||||
for (i=0; i<4; ++i) {
|
||||
do {
|
||||
idle_reg = SIS_READ(0x85cc);
|
||||
} while ( !time_after_eq(jiffies, end) &&
|
||||
((idle_reg & 0x80000000) != 0x80000000));
|
||||
}
|
||||
|
||||
if (time_after_eq(jiffies, end)) {
|
||||
DRM_ERROR("Graphics engine idle timeout. "
|
||||
"Disabling idle check\n");
|
||||
dev_priv->idle_fault = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* The caller never sees an error code. It gets trapped
|
||||
* in libdrm.
|
||||
*/
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void sis_lastclose(struct drm_device *dev)
|
||||
{
|
||||
drm_sis_private_t *dev_priv = dev->dev_private;
|
||||
|
||||
if (!dev_priv)
|
||||
return;
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
drm_sman_cleanup(&dev_priv->sman);
|
||||
dev_priv->vram_initialized = 0;
|
||||
dev_priv->agp_initialized = 0;
|
||||
dev_priv->mmio = NULL;
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
}
|
||||
|
||||
void sis_reclaim_buffers_locked(drm_device_t * dev, struct file *filp)
|
||||
{
|
||||
drm_sis_private_t *dev_priv = dev->dev_private;
|
||||
drm_file_t *priv = filp->private_data;
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
if (drm_sman_owner_clean(&dev_priv->sman, (unsigned long)priv)) {
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
if (dev->driver->dma_quiescent) {
|
||||
dev->driver->dma_quiescent(dev);
|
||||
}
|
||||
|
||||
drm_sman_owner_cleanup(&dev_priv->sman, (unsigned long)priv);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
drm_ioctl_desc_t sis_ioctls[] = {
|
||||
[DRM_IOCTL_NR(DRM_SIS_FB_ALLOC)] = {sis_fb_alloc, DRM_AUTH},
|
||||
[DRM_IOCTL_NR(DRM_SIS_FB_FREE)] = {sis_drm_free, DRM_AUTH},
|
||||
[DRM_IOCTL_NR(DRM_SIS_AGP_INIT)] =
|
||||
{sis_ioctl_agp_init, DRM_AUTH | DRM_MASTER | DRM_ROOT_ONLY},
|
||||
[DRM_IOCTL_NR(DRM_SIS_AGP_ALLOC)] = {sis_ioctl_agp_alloc, DRM_AUTH},
|
||||
[DRM_IOCTL_NR(DRM_SIS_AGP_FREE)] = {sis_drm_free, DRM_AUTH},
|
||||
[DRM_IOCTL_NR(DRM_SIS_FB_INIT)] =
|
||||
{sis_fb_init, DRM_AUTH | DRM_MASTER | DRM_ROOT_ONLY}
|
||||
};
|
||||
|
||||
int sis_max_ioctl = DRM_ARRAY_SIZE(sis_ioctls);
|
||||
84
drivers/char/drm/tdfx_drv.c
Normal file
84
drivers/char/drm/tdfx_drv.c
Normal file
@@ -0,0 +1,84 @@
|
||||
/* 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 "drmP.h"
|
||||
#include "tdfx_drv.h"
|
||||
|
||||
#include "drm_pciids.h"
|
||||
|
||||
static struct pci_device_id pciidlist[] = {
|
||||
tdfx_PCI_IDS
|
||||
};
|
||||
|
||||
static struct drm_driver driver = {
|
||||
.driver_features = DRIVER_USE_MTRR,
|
||||
.reclaim_buffers = drm_core_reclaim_buffers,
|
||||
.get_map_ofs = drm_core_get_map_ofs,
|
||||
.get_reg_ofs = drm_core_get_reg_ofs,
|
||||
.fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = drm_open,
|
||||
.release = drm_release,
|
||||
.ioctl = drm_ioctl,
|
||||
.mmap = drm_mmap,
|
||||
.poll = drm_poll,
|
||||
.fasync = drm_fasync,
|
||||
},
|
||||
.pci_driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.id_table = pciidlist,
|
||||
},
|
||||
|
||||
.name = DRIVER_NAME,
|
||||
.desc = DRIVER_DESC,
|
||||
.date = DRIVER_DATE,
|
||||
.major = DRIVER_MAJOR,
|
||||
.minor = DRIVER_MINOR,
|
||||
.patchlevel = DRIVER_PATCHLEVEL,
|
||||
};
|
||||
|
||||
static int __init tdfx_init(void)
|
||||
{
|
||||
return drm_init(&driver);
|
||||
}
|
||||
|
||||
static void __exit tdfx_exit(void)
|
||||
{
|
||||
drm_exit(&driver);
|
||||
}
|
||||
|
||||
module_init(tdfx_init);
|
||||
module_exit(tdfx_exit);
|
||||
|
||||
MODULE_AUTHOR(DRIVER_AUTHOR);
|
||||
MODULE_DESCRIPTION(DRIVER_DESC);
|
||||
MODULE_LICENSE("GPL and additional rights");
|
||||
47
drivers/char/drm/tdfx_drv.h
Normal file
47
drivers/char/drm/tdfx_drv.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/* 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>
|
||||
*/
|
||||
|
||||
#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
|
||||
1650
drivers/char/drm/via_3d_reg.h
Normal file
1650
drivers/char/drm/via_3d_reg.h
Normal file
File diff suppressed because it is too large
Load Diff
751
drivers/char/drm/via_dma.c
Normal file
751
drivers/char/drm/via_dma.c
Normal file
@@ -0,0 +1,751 @@
|
||||
/* via_dma.c -- DMA support for the VIA Unichrome/Pro
|
||||
*
|
||||
* Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Copyright 2004 Digeo, Inc., Palo Alto, CA, U.S.A.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Copyright 2004 The Unichrome project.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sub license,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the
|
||||
* next paragraph) shall be included in all copies or substantial portions
|
||||
* of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
* USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors:
|
||||
* Tungsten Graphics,
|
||||
* Erdi Chen,
|
||||
* Thomas Hellstrom.
|
||||
*/
|
||||
|
||||
#include "drmP.h"
|
||||
#include "drm.h"
|
||||
#include "via_drm.h"
|
||||
#include "via_drv.h"
|
||||
#include "via_3d_reg.h"
|
||||
|
||||
#define CMDBUF_ALIGNMENT_SIZE (0x100)
|
||||
#define CMDBUF_ALIGNMENT_MASK (0x0ff)
|
||||
|
||||
/* defines for VIA 3D registers */
|
||||
#define VIA_REG_STATUS 0x400
|
||||
#define VIA_REG_TRANSET 0x43C
|
||||
#define VIA_REG_TRANSPACE 0x440
|
||||
|
||||
/* VIA_REG_STATUS(0x400): Engine Status */
|
||||
#define VIA_CMD_RGTR_BUSY 0x00000080 /* Command Regulator is busy */
|
||||
#define VIA_2D_ENG_BUSY 0x00000001 /* 2D Engine is busy */
|
||||
#define VIA_3D_ENG_BUSY 0x00000002 /* 3D Engine is busy */
|
||||
#define VIA_VR_QUEUE_BUSY 0x00020000 /* Virtual Queue is busy */
|
||||
|
||||
#define SetReg2DAGP(nReg, nData) { \
|
||||
*((uint32_t *)(vb)) = ((nReg) >> 2) | HALCYON_HEADER1; \
|
||||
*((uint32_t *)(vb) + 1) = (nData); \
|
||||
vb = ((uint32_t *)vb) + 2; \
|
||||
dev_priv->dma_low +=8; \
|
||||
}
|
||||
|
||||
#define via_flush_write_combine() DRM_MEMORYBARRIER()
|
||||
|
||||
#define VIA_OUT_RING_QW(w1,w2) \
|
||||
*vb++ = (w1); \
|
||||
*vb++ = (w2); \
|
||||
dev_priv->dma_low += 8;
|
||||
|
||||
static void via_cmdbuf_start(drm_via_private_t * dev_priv);
|
||||
static void via_cmdbuf_pause(drm_via_private_t * dev_priv);
|
||||
static void via_cmdbuf_reset(drm_via_private_t * dev_priv);
|
||||
static void via_cmdbuf_rewind(drm_via_private_t * dev_priv);
|
||||
static int via_wait_idle(drm_via_private_t * dev_priv);
|
||||
static void via_pad_cache(drm_via_private_t * dev_priv, int qwords);
|
||||
|
||||
/*
|
||||
* Free space in command buffer.
|
||||
*/
|
||||
|
||||
static uint32_t via_cmdbuf_space(drm_via_private_t * dev_priv)
|
||||
{
|
||||
uint32_t agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr;
|
||||
uint32_t hw_addr = *(dev_priv->hw_addr_ptr) - agp_base;
|
||||
|
||||
return ((hw_addr <= dev_priv->dma_low) ?
|
||||
(dev_priv->dma_high + hw_addr - dev_priv->dma_low) :
|
||||
(hw_addr - dev_priv->dma_low));
|
||||
}
|
||||
|
||||
/*
|
||||
* How much does the command regulator lag behind?
|
||||
*/
|
||||
|
||||
static uint32_t via_cmdbuf_lag(drm_via_private_t * dev_priv)
|
||||
{
|
||||
uint32_t agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr;
|
||||
uint32_t hw_addr = *(dev_priv->hw_addr_ptr) - agp_base;
|
||||
|
||||
return ((hw_addr <= dev_priv->dma_low) ?
|
||||
(dev_priv->dma_low - hw_addr) :
|
||||
(dev_priv->dma_wrap + dev_priv->dma_low - hw_addr));
|
||||
}
|
||||
|
||||
/*
|
||||
* Check that the given size fits in the buffer, otherwise wait.
|
||||
*/
|
||||
|
||||
static inline int
|
||||
via_cmdbuf_wait(drm_via_private_t * dev_priv, unsigned int size)
|
||||
{
|
||||
uint32_t agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr;
|
||||
uint32_t cur_addr, hw_addr, next_addr;
|
||||
volatile uint32_t *hw_addr_ptr;
|
||||
uint32_t count;
|
||||
hw_addr_ptr = dev_priv->hw_addr_ptr;
|
||||
cur_addr = dev_priv->dma_low;
|
||||
next_addr = cur_addr + size + 512 * 1024;
|
||||
count = 1000000;
|
||||
do {
|
||||
hw_addr = *hw_addr_ptr - agp_base;
|
||||
if (count-- == 0) {
|
||||
DRM_ERROR
|
||||
("via_cmdbuf_wait timed out hw %x cur_addr %x next_addr %x\n",
|
||||
hw_addr, cur_addr, next_addr);
|
||||
return -1;
|
||||
}
|
||||
} while ((cur_addr < hw_addr) && (next_addr >= hw_addr));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks whether buffer head has reach the end. Rewind the ring buffer
|
||||
* when necessary.
|
||||
*
|
||||
* Returns virtual pointer to ring buffer.
|
||||
*/
|
||||
|
||||
static inline uint32_t *via_check_dma(drm_via_private_t * dev_priv,
|
||||
unsigned int size)
|
||||
{
|
||||
if ((dev_priv->dma_low + size + 4 * CMDBUF_ALIGNMENT_SIZE) >
|
||||
dev_priv->dma_high) {
|
||||
via_cmdbuf_rewind(dev_priv);
|
||||
}
|
||||
if (via_cmdbuf_wait(dev_priv, size) != 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (uint32_t *) (dev_priv->dma_ptr + dev_priv->dma_low);
|
||||
}
|
||||
|
||||
int via_dma_cleanup(drm_device_t * dev)
|
||||
{
|
||||
if (dev->dev_private) {
|
||||
drm_via_private_t *dev_priv =
|
||||
(drm_via_private_t *) dev->dev_private;
|
||||
|
||||
if (dev_priv->ring.virtual_start) {
|
||||
via_cmdbuf_reset(dev_priv);
|
||||
|
||||
drm_core_ioremapfree(&dev_priv->ring.map, dev);
|
||||
dev_priv->ring.virtual_start = NULL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int via_initialize(drm_device_t * dev,
|
||||
drm_via_private_t * dev_priv,
|
||||
drm_via_dma_init_t * init)
|
||||
{
|
||||
if (!dev_priv || !dev_priv->mmio) {
|
||||
DRM_ERROR("via_dma_init called before via_map_init\n");
|
||||
return DRM_ERR(EFAULT);
|
||||
}
|
||||
|
||||
if (dev_priv->ring.virtual_start != NULL) {
|
||||
DRM_ERROR("%s called again without calling cleanup\n",
|
||||
__FUNCTION__);
|
||||
return DRM_ERR(EFAULT);
|
||||
}
|
||||
|
||||
if (!dev->agp || !dev->agp->base) {
|
||||
DRM_ERROR("%s called with no agp memory available\n",
|
||||
__FUNCTION__);
|
||||
return DRM_ERR(EFAULT);
|
||||
}
|
||||
|
||||
if (dev_priv->chipset == VIA_DX9_0) {
|
||||
DRM_ERROR("AGP DMA is not supported on this chip\n");
|
||||
return DRM_ERR(EINVAL);
|
||||
}
|
||||
|
||||
dev_priv->ring.map.offset = dev->agp->base + init->offset;
|
||||
dev_priv->ring.map.size = init->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) {
|
||||
via_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->dma_ptr = dev_priv->ring.virtual_start;
|
||||
dev_priv->dma_low = 0;
|
||||
dev_priv->dma_high = init->size;
|
||||
dev_priv->dma_wrap = init->size;
|
||||
dev_priv->dma_offset = init->offset;
|
||||
dev_priv->last_pause_ptr = NULL;
|
||||
dev_priv->hw_addr_ptr =
|
||||
(volatile uint32_t *)((char *)dev_priv->mmio->handle +
|
||||
init->reg_pause_addr);
|
||||
|
||||
via_cmdbuf_start(dev_priv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int via_dma_init(DRM_IOCTL_ARGS)
|
||||
{
|
||||
DRM_DEVICE;
|
||||
drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
|
||||
drm_via_dma_init_t init;
|
||||
int retcode = 0;
|
||||
|
||||
DRM_COPY_FROM_USER_IOCTL(init, (drm_via_dma_init_t __user *) data,
|
||||
sizeof(init));
|
||||
|
||||
switch (init.func) {
|
||||
case VIA_INIT_DMA:
|
||||
if (!DRM_SUSER(DRM_CURPROC))
|
||||
retcode = DRM_ERR(EPERM);
|
||||
else
|
||||
retcode = via_initialize(dev, dev_priv, &init);
|
||||
break;
|
||||
case VIA_CLEANUP_DMA:
|
||||
if (!DRM_SUSER(DRM_CURPROC))
|
||||
retcode = DRM_ERR(EPERM);
|
||||
else
|
||||
retcode = via_dma_cleanup(dev);
|
||||
break;
|
||||
case VIA_DMA_INITIALIZED:
|
||||
retcode = (dev_priv->ring.virtual_start != NULL) ?
|
||||
0 : DRM_ERR(EFAULT);
|
||||
break;
|
||||
default:
|
||||
retcode = DRM_ERR(EINVAL);
|
||||
break;
|
||||
}
|
||||
|
||||
return retcode;
|
||||
}
|
||||
|
||||
static int via_dispatch_cmdbuffer(drm_device_t * dev, drm_via_cmdbuffer_t * cmd)
|
||||
{
|
||||
drm_via_private_t *dev_priv;
|
||||
uint32_t *vb;
|
||||
int ret;
|
||||
|
||||
dev_priv = (drm_via_private_t *) dev->dev_private;
|
||||
|
||||
if (dev_priv->ring.virtual_start == NULL) {
|
||||
DRM_ERROR("%s called without initializing AGP ring buffer.\n",
|
||||
__FUNCTION__);
|
||||
return DRM_ERR(EFAULT);
|
||||
}
|
||||
|
||||
if (cmd->size > VIA_PCI_BUF_SIZE) {
|
||||
return DRM_ERR(ENOMEM);
|
||||
}
|
||||
|
||||
if (DRM_COPY_FROM_USER(dev_priv->pci_buf, cmd->buf, cmd->size))
|
||||
return DRM_ERR(EFAULT);
|
||||
|
||||
/*
|
||||
* Running this function on AGP memory is dead slow. Therefore
|
||||
* we run it on a temporary cacheable system memory buffer and
|
||||
* copy it to AGP memory when ready.
|
||||
*/
|
||||
|
||||
if ((ret =
|
||||
via_verify_command_stream((uint32_t *) dev_priv->pci_buf,
|
||||
cmd->size, dev, 1))) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
vb = via_check_dma(dev_priv, (cmd->size < 0x100) ? 0x102 : cmd->size);
|
||||
if (vb == NULL) {
|
||||
return DRM_ERR(EAGAIN);
|
||||
}
|
||||
|
||||
memcpy(vb, dev_priv->pci_buf, cmd->size);
|
||||
|
||||
dev_priv->dma_low += cmd->size;
|
||||
|
||||
/*
|
||||
* Small submissions somehow stalls the CPU. (AGP cache effects?)
|
||||
* pad to greater size.
|
||||
*/
|
||||
|
||||
if (cmd->size < 0x100)
|
||||
via_pad_cache(dev_priv, (0x100 - cmd->size) >> 3);
|
||||
via_cmdbuf_pause(dev_priv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int via_driver_dma_quiescent(drm_device_t * dev)
|
||||
{
|
||||
drm_via_private_t *dev_priv = dev->dev_private;
|
||||
|
||||
if (!via_wait_idle(dev_priv)) {
|
||||
return DRM_ERR(EBUSY);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int via_flush_ioctl(DRM_IOCTL_ARGS)
|
||||
{
|
||||
DRM_DEVICE;
|
||||
|
||||
LOCK_TEST_WITH_RETURN(dev, filp);
|
||||
|
||||
return via_driver_dma_quiescent(dev);
|
||||
}
|
||||
|
||||
static int via_cmdbuffer(DRM_IOCTL_ARGS)
|
||||
{
|
||||
DRM_DEVICE;
|
||||
drm_via_cmdbuffer_t cmdbuf;
|
||||
int ret;
|
||||
|
||||
LOCK_TEST_WITH_RETURN(dev, filp);
|
||||
|
||||
DRM_COPY_FROM_USER_IOCTL(cmdbuf, (drm_via_cmdbuffer_t __user *) data,
|
||||
sizeof(cmdbuf));
|
||||
|
||||
DRM_DEBUG("via cmdbuffer, buf %p size %lu\n", cmdbuf.buf, cmdbuf.size);
|
||||
|
||||
ret = via_dispatch_cmdbuffer(dev, &cmdbuf);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int via_dispatch_pci_cmdbuffer(drm_device_t * dev,
|
||||
drm_via_cmdbuffer_t * cmd)
|
||||
{
|
||||
drm_via_private_t *dev_priv = dev->dev_private;
|
||||
int ret;
|
||||
|
||||
if (cmd->size > VIA_PCI_BUF_SIZE) {
|
||||
return DRM_ERR(ENOMEM);
|
||||
}
|
||||
if (DRM_COPY_FROM_USER(dev_priv->pci_buf, cmd->buf, cmd->size))
|
||||
return DRM_ERR(EFAULT);
|
||||
|
||||
if ((ret =
|
||||
via_verify_command_stream((uint32_t *) dev_priv->pci_buf,
|
||||
cmd->size, dev, 0))) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret =
|
||||
via_parse_command_stream(dev, (const uint32_t *)dev_priv->pci_buf,
|
||||
cmd->size);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int via_pci_cmdbuffer(DRM_IOCTL_ARGS)
|
||||
{
|
||||
DRM_DEVICE;
|
||||
drm_via_cmdbuffer_t cmdbuf;
|
||||
int ret;
|
||||
|
||||
LOCK_TEST_WITH_RETURN(dev, filp);
|
||||
|
||||
DRM_COPY_FROM_USER_IOCTL(cmdbuf, (drm_via_cmdbuffer_t __user *) data,
|
||||
sizeof(cmdbuf));
|
||||
|
||||
DRM_DEBUG("via_pci_cmdbuffer, buf %p size %lu\n", cmdbuf.buf,
|
||||
cmdbuf.size);
|
||||
|
||||
ret = via_dispatch_pci_cmdbuffer(dev, &cmdbuf);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline uint32_t *via_align_buffer(drm_via_private_t * dev_priv,
|
||||
uint32_t * vb, int qw_count)
|
||||
{
|
||||
for (; qw_count > 0; --qw_count) {
|
||||
VIA_OUT_RING_QW(HC_DUMMY, HC_DUMMY);
|
||||
}
|
||||
return vb;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is used internally by ring buffer mangement code.
|
||||
*
|
||||
* Returns virtual pointer to ring buffer.
|
||||
*/
|
||||
static inline uint32_t *via_get_dma(drm_via_private_t * dev_priv)
|
||||
{
|
||||
return (uint32_t *) (dev_priv->dma_ptr + dev_priv->dma_low);
|
||||
}
|
||||
|
||||
/*
|
||||
* Hooks a segment of data into the tail of the ring-buffer by
|
||||
* modifying the pause address stored in the buffer itself. If
|
||||
* the regulator has already paused, restart it.
|
||||
*/
|
||||
static int via_hook_segment(drm_via_private_t * dev_priv,
|
||||
uint32_t pause_addr_hi, uint32_t pause_addr_lo,
|
||||
int no_pci_fire)
|
||||
{
|
||||
int paused, count;
|
||||
volatile uint32_t *paused_at = dev_priv->last_pause_ptr;
|
||||
|
||||
via_flush_write_combine();
|
||||
while (!*(via_get_dma(dev_priv) - 1)) ;
|
||||
*dev_priv->last_pause_ptr = pause_addr_lo;
|
||||
via_flush_write_combine();
|
||||
|
||||
/*
|
||||
* The below statement is inserted to really force the flush.
|
||||
* Not sure it is needed.
|
||||
*/
|
||||
|
||||
while (!*dev_priv->last_pause_ptr) ;
|
||||
dev_priv->last_pause_ptr = via_get_dma(dev_priv) - 1;
|
||||
while (!*dev_priv->last_pause_ptr) ;
|
||||
|
||||
paused = 0;
|
||||
count = 20;
|
||||
|
||||
while (!(paused = (VIA_READ(0x41c) & 0x80000000)) && count--) ;
|
||||
if ((count <= 8) && (count >= 0)) {
|
||||
uint32_t rgtr, ptr;
|
||||
rgtr = *(dev_priv->hw_addr_ptr);
|
||||
ptr = ((volatile char *)dev_priv->last_pause_ptr -
|
||||
dev_priv->dma_ptr) + dev_priv->dma_offset +
|
||||
(uint32_t) dev_priv->agpAddr + 4 - CMDBUF_ALIGNMENT_SIZE;
|
||||
if (rgtr <= ptr) {
|
||||
DRM_ERROR
|
||||
("Command regulator\npaused at count %d, address %x, "
|
||||
"while current pause address is %x.\n"
|
||||
"Please mail this message to "
|
||||
"<unichrome-devel@lists.sourceforge.net>\n", count,
|
||||
rgtr, ptr);
|
||||
}
|
||||
}
|
||||
|
||||
if (paused && !no_pci_fire) {
|
||||
uint32_t rgtr, ptr;
|
||||
uint32_t ptr_low;
|
||||
|
||||
count = 1000000;
|
||||
while ((VIA_READ(VIA_REG_STATUS) & VIA_CMD_RGTR_BUSY)
|
||||
&& count--) ;
|
||||
|
||||
rgtr = *(dev_priv->hw_addr_ptr);
|
||||
ptr = ((volatile char *)paused_at - dev_priv->dma_ptr) +
|
||||
dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr + 4;
|
||||
|
||||
ptr_low = (ptr > 3 * CMDBUF_ALIGNMENT_SIZE) ?
|
||||
ptr - 3 * CMDBUF_ALIGNMENT_SIZE : 0;
|
||||
if (rgtr <= ptr && rgtr >= ptr_low) {
|
||||
VIA_WRITE(VIA_REG_TRANSET, (HC_ParaType_PreCR << 16));
|
||||
VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_hi);
|
||||
VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_lo);
|
||||
VIA_READ(VIA_REG_TRANSPACE);
|
||||
}
|
||||
}
|
||||
return paused;
|
||||
}
|
||||
|
||||
static int via_wait_idle(drm_via_private_t * dev_priv)
|
||||
{
|
||||
int count = 10000000;
|
||||
while (count-- && (VIA_READ(VIA_REG_STATUS) &
|
||||
(VIA_CMD_RGTR_BUSY | VIA_2D_ENG_BUSY |
|
||||
VIA_3D_ENG_BUSY))) ;
|
||||
return count;
|
||||
}
|
||||
|
||||
static uint32_t *via_align_cmd(drm_via_private_t * dev_priv, uint32_t cmd_type,
|
||||
uint32_t addr, uint32_t * cmd_addr_hi,
|
||||
uint32_t * cmd_addr_lo, int skip_wait)
|
||||
{
|
||||
uint32_t agp_base;
|
||||
uint32_t cmd_addr, addr_lo, addr_hi;
|
||||
uint32_t *vb;
|
||||
uint32_t qw_pad_count;
|
||||
|
||||
if (!skip_wait)
|
||||
via_cmdbuf_wait(dev_priv, 2 * CMDBUF_ALIGNMENT_SIZE);
|
||||
|
||||
vb = via_get_dma(dev_priv);
|
||||
VIA_OUT_RING_QW(HC_HEADER2 | ((VIA_REG_TRANSET >> 2) << 12) |
|
||||
(VIA_REG_TRANSPACE >> 2), HC_ParaType_PreCR << 16);
|
||||
agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr;
|
||||
qw_pad_count = (CMDBUF_ALIGNMENT_SIZE >> 3) -
|
||||
((dev_priv->dma_low & CMDBUF_ALIGNMENT_MASK) >> 3);
|
||||
|
||||
cmd_addr = (addr) ? addr :
|
||||
agp_base + dev_priv->dma_low - 8 + (qw_pad_count << 3);
|
||||
addr_lo = ((HC_SubA_HAGPBpL << 24) | (cmd_type & HC_HAGPBpID_MASK) |
|
||||
(cmd_addr & HC_HAGPBpL_MASK));
|
||||
addr_hi = ((HC_SubA_HAGPBpH << 24) | (cmd_addr >> 24));
|
||||
|
||||
vb = via_align_buffer(dev_priv, vb, qw_pad_count - 1);
|
||||
VIA_OUT_RING_QW(*cmd_addr_hi = addr_hi, *cmd_addr_lo = addr_lo);
|
||||
return vb;
|
||||
}
|
||||
|
||||
static void via_cmdbuf_start(drm_via_private_t * dev_priv)
|
||||
{
|
||||
uint32_t pause_addr_lo, pause_addr_hi;
|
||||
uint32_t start_addr, start_addr_lo;
|
||||
uint32_t end_addr, end_addr_lo;
|
||||
uint32_t command;
|
||||
uint32_t agp_base;
|
||||
|
||||
dev_priv->dma_low = 0;
|
||||
|
||||
agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr;
|
||||
start_addr = agp_base;
|
||||
end_addr = agp_base + dev_priv->dma_high;
|
||||
|
||||
start_addr_lo = ((HC_SubA_HAGPBstL << 24) | (start_addr & 0xFFFFFF));
|
||||
end_addr_lo = ((HC_SubA_HAGPBendL << 24) | (end_addr & 0xFFFFFF));
|
||||
command = ((HC_SubA_HAGPCMNT << 24) | (start_addr >> 24) |
|
||||
((end_addr & 0xff000000) >> 16));
|
||||
|
||||
dev_priv->last_pause_ptr =
|
||||
via_align_cmd(dev_priv, HC_HAGPBpID_PAUSE, 0,
|
||||
&pause_addr_hi, &pause_addr_lo, 1) - 1;
|
||||
|
||||
via_flush_write_combine();
|
||||
while (!*dev_priv->last_pause_ptr) ;
|
||||
|
||||
VIA_WRITE(VIA_REG_TRANSET, (HC_ParaType_PreCR << 16));
|
||||
VIA_WRITE(VIA_REG_TRANSPACE, command);
|
||||
VIA_WRITE(VIA_REG_TRANSPACE, start_addr_lo);
|
||||
VIA_WRITE(VIA_REG_TRANSPACE, end_addr_lo);
|
||||
|
||||
VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_hi);
|
||||
VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_lo);
|
||||
DRM_WRITEMEMORYBARRIER();
|
||||
VIA_WRITE(VIA_REG_TRANSPACE, command | HC_HAGPCMNT_MASK);
|
||||
VIA_READ(VIA_REG_TRANSPACE);
|
||||
}
|
||||
|
||||
static void via_pad_cache(drm_via_private_t * dev_priv, int qwords)
|
||||
{
|
||||
uint32_t *vb;
|
||||
|
||||
via_cmdbuf_wait(dev_priv, qwords + 2);
|
||||
vb = via_get_dma(dev_priv);
|
||||
VIA_OUT_RING_QW(HC_HEADER2, HC_ParaType_NotTex << 16);
|
||||
via_align_buffer(dev_priv, vb, qwords);
|
||||
}
|
||||
|
||||
static inline void via_dummy_bitblt(drm_via_private_t * dev_priv)
|
||||
{
|
||||
uint32_t *vb = via_get_dma(dev_priv);
|
||||
SetReg2DAGP(0x0C, (0 | (0 << 16)));
|
||||
SetReg2DAGP(0x10, 0 | (0 << 16));
|
||||
SetReg2DAGP(0x0, 0x1 | 0x2000 | 0xAA000000);
|
||||
}
|
||||
|
||||
static void via_cmdbuf_jump(drm_via_private_t * dev_priv)
|
||||
{
|
||||
uint32_t agp_base;
|
||||
uint32_t pause_addr_lo, pause_addr_hi;
|
||||
uint32_t jump_addr_lo, jump_addr_hi;
|
||||
volatile uint32_t *last_pause_ptr;
|
||||
uint32_t dma_low_save1, dma_low_save2;
|
||||
|
||||
agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr;
|
||||
via_align_cmd(dev_priv, HC_HAGPBpID_JUMP, 0, &jump_addr_hi,
|
||||
&jump_addr_lo, 0);
|
||||
|
||||
dev_priv->dma_wrap = dev_priv->dma_low;
|
||||
|
||||
/*
|
||||
* Wrap command buffer to the beginning.
|
||||
*/
|
||||
|
||||
dev_priv->dma_low = 0;
|
||||
if (via_cmdbuf_wait(dev_priv, CMDBUF_ALIGNMENT_SIZE) != 0) {
|
||||
DRM_ERROR("via_cmdbuf_jump failed\n");
|
||||
}
|
||||
|
||||
via_dummy_bitblt(dev_priv);
|
||||
via_dummy_bitblt(dev_priv);
|
||||
|
||||
last_pause_ptr =
|
||||
via_align_cmd(dev_priv, HC_HAGPBpID_PAUSE, 0, &pause_addr_hi,
|
||||
&pause_addr_lo, 0) - 1;
|
||||
via_align_cmd(dev_priv, HC_HAGPBpID_PAUSE, 0, &pause_addr_hi,
|
||||
&pause_addr_lo, 0);
|
||||
|
||||
*last_pause_ptr = pause_addr_lo;
|
||||
dma_low_save1 = dev_priv->dma_low;
|
||||
|
||||
/*
|
||||
* Now, set a trap that will pause the regulator if it tries to rerun the old
|
||||
* command buffer. (Which may happen if via_hook_segment detecs a command regulator pause
|
||||
* and reissues the jump command over PCI, while the regulator has already taken the jump
|
||||
* and actually paused at the current buffer end).
|
||||
* There appears to be no other way to detect this condition, since the hw_addr_pointer
|
||||
* does not seem to get updated immediately when a jump occurs.
|
||||
*/
|
||||
|
||||
last_pause_ptr =
|
||||
via_align_cmd(dev_priv, HC_HAGPBpID_PAUSE, 0, &pause_addr_hi,
|
||||
&pause_addr_lo, 0) - 1;
|
||||
via_align_cmd(dev_priv, HC_HAGPBpID_PAUSE, 0, &pause_addr_hi,
|
||||
&pause_addr_lo, 0);
|
||||
*last_pause_ptr = pause_addr_lo;
|
||||
|
||||
dma_low_save2 = dev_priv->dma_low;
|
||||
dev_priv->dma_low = dma_low_save1;
|
||||
via_hook_segment(dev_priv, jump_addr_hi, jump_addr_lo, 0);
|
||||
dev_priv->dma_low = dma_low_save2;
|
||||
via_hook_segment(dev_priv, pause_addr_hi, pause_addr_lo, 0);
|
||||
}
|
||||
|
||||
static void via_cmdbuf_rewind(drm_via_private_t * dev_priv)
|
||||
{
|
||||
via_cmdbuf_jump(dev_priv);
|
||||
}
|
||||
|
||||
static void via_cmdbuf_flush(drm_via_private_t * dev_priv, uint32_t cmd_type)
|
||||
{
|
||||
uint32_t pause_addr_lo, pause_addr_hi;
|
||||
|
||||
via_align_cmd(dev_priv, cmd_type, 0, &pause_addr_hi, &pause_addr_lo, 0);
|
||||
via_hook_segment(dev_priv, pause_addr_hi, pause_addr_lo, 0);
|
||||
}
|
||||
|
||||
static void via_cmdbuf_pause(drm_via_private_t * dev_priv)
|
||||
{
|
||||
via_cmdbuf_flush(dev_priv, HC_HAGPBpID_PAUSE);
|
||||
}
|
||||
|
||||
static void via_cmdbuf_reset(drm_via_private_t * dev_priv)
|
||||
{
|
||||
via_cmdbuf_flush(dev_priv, HC_HAGPBpID_STOP);
|
||||
via_wait_idle(dev_priv);
|
||||
}
|
||||
|
||||
/*
|
||||
* User interface to the space and lag functions.
|
||||
*/
|
||||
|
||||
static int via_cmdbuf_size(DRM_IOCTL_ARGS)
|
||||
{
|
||||
DRM_DEVICE;
|
||||
drm_via_cmdbuf_size_t d_siz;
|
||||
int ret = 0;
|
||||
uint32_t tmp_size, count;
|
||||
drm_via_private_t *dev_priv;
|
||||
|
||||
DRM_DEBUG("via cmdbuf_size\n");
|
||||
LOCK_TEST_WITH_RETURN(dev, filp);
|
||||
|
||||
dev_priv = (drm_via_private_t *) dev->dev_private;
|
||||
|
||||
if (dev_priv->ring.virtual_start == NULL) {
|
||||
DRM_ERROR("%s called without initializing AGP ring buffer.\n",
|
||||
__FUNCTION__);
|
||||
return DRM_ERR(EFAULT);
|
||||
}
|
||||
|
||||
DRM_COPY_FROM_USER_IOCTL(d_siz, (drm_via_cmdbuf_size_t __user *) data,
|
||||
sizeof(d_siz));
|
||||
|
||||
count = 1000000;
|
||||
tmp_size = d_siz.size;
|
||||
switch (d_siz.func) {
|
||||
case VIA_CMDBUF_SPACE:
|
||||
while (((tmp_size = via_cmdbuf_space(dev_priv)) < d_siz.size)
|
||||
&& count--) {
|
||||
if (!d_siz.wait) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!count) {
|
||||
DRM_ERROR("VIA_CMDBUF_SPACE timed out.\n");
|
||||
ret = DRM_ERR(EAGAIN);
|
||||
}
|
||||
break;
|
||||
case VIA_CMDBUF_LAG:
|
||||
while (((tmp_size = via_cmdbuf_lag(dev_priv)) > d_siz.size)
|
||||
&& count--) {
|
||||
if (!d_siz.wait) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!count) {
|
||||
DRM_ERROR("VIA_CMDBUF_LAG timed out.\n");
|
||||
ret = DRM_ERR(EAGAIN);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ret = DRM_ERR(EFAULT);
|
||||
}
|
||||
d_siz.size = tmp_size;
|
||||
|
||||
DRM_COPY_TO_USER_IOCTL((drm_via_cmdbuf_size_t __user *) data, d_siz,
|
||||
sizeof(d_siz));
|
||||
return ret;
|
||||
}
|
||||
|
||||
drm_ioctl_desc_t via_ioctls[] = {
|
||||
[DRM_IOCTL_NR(DRM_VIA_ALLOCMEM)] = {via_mem_alloc, DRM_AUTH},
|
||||
[DRM_IOCTL_NR(DRM_VIA_FREEMEM)] = {via_mem_free, DRM_AUTH},
|
||||
[DRM_IOCTL_NR(DRM_VIA_AGP_INIT)] = {via_agp_init, DRM_AUTH|DRM_MASTER},
|
||||
[DRM_IOCTL_NR(DRM_VIA_FB_INIT)] = {via_fb_init, DRM_AUTH|DRM_MASTER},
|
||||
[DRM_IOCTL_NR(DRM_VIA_MAP_INIT)] = {via_map_init, DRM_AUTH|DRM_MASTER},
|
||||
[DRM_IOCTL_NR(DRM_VIA_DEC_FUTEX)] = {via_decoder_futex, DRM_AUTH},
|
||||
[DRM_IOCTL_NR(DRM_VIA_DMA_INIT)] = {via_dma_init, DRM_AUTH},
|
||||
[DRM_IOCTL_NR(DRM_VIA_CMDBUFFER)] = {via_cmdbuffer, DRM_AUTH},
|
||||
[DRM_IOCTL_NR(DRM_VIA_FLUSH)] = {via_flush_ioctl, DRM_AUTH},
|
||||
[DRM_IOCTL_NR(DRM_VIA_PCICMD)] = {via_pci_cmdbuffer, DRM_AUTH},
|
||||
[DRM_IOCTL_NR(DRM_VIA_CMDBUF_SIZE)] = {via_cmdbuf_size, DRM_AUTH},
|
||||
[DRM_IOCTL_NR(DRM_VIA_WAIT_IRQ)] = {via_wait_irq, DRM_AUTH},
|
||||
[DRM_IOCTL_NR(DRM_VIA_DMA_BLIT)] = {via_dma_blit, DRM_AUTH},
|
||||
[DRM_IOCTL_NR(DRM_VIA_BLIT_SYNC)] = {via_dma_blit_sync, DRM_AUTH}
|
||||
};
|
||||
|
||||
int via_max_ioctl = DRM_ARRAY_SIZE(via_ioctls);
|
||||
825
drivers/char/drm/via_dmablit.c
Normal file
825
drivers/char/drm/via_dmablit.c
Normal file
@@ -0,0 +1,825 @@
|
||||
/* via_dmablit.c -- PCI DMA BitBlt support for the VIA Unichrome/Pro
|
||||
*
|
||||
* Copyright (C) 2005 Thomas Hellstrom, All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sub license,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the
|
||||
* next paragraph) shall be included in all copies or substantial portions
|
||||
* of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
* USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors:
|
||||
* Thomas Hellstrom.
|
||||
* Partially based on code obtained from Digeo Inc.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Unmaps the DMA mappings.
|
||||
* FIXME: Is this a NoOp on x86? Also
|
||||
* FIXME: What happens if this one is called and a pending blit has previously done
|
||||
* the same DMA mappings?
|
||||
*/
|
||||
|
||||
#include "drmP.h"
|
||||
#include "via_drm.h"
|
||||
#include "via_drv.h"
|
||||
#include "via_dmablit.h"
|
||||
|
||||
#include <linux/pagemap.h>
|
||||
|
||||
#define VIA_PGDN(x) (((unsigned long)(x)) & PAGE_MASK)
|
||||
#define VIA_PGOFF(x) (((unsigned long)(x)) & ~PAGE_MASK)
|
||||
#define VIA_PFN(x) ((unsigned long)(x) >> PAGE_SHIFT)
|
||||
|
||||
typedef struct _drm_via_descriptor {
|
||||
uint32_t mem_addr;
|
||||
uint32_t dev_addr;
|
||||
uint32_t size;
|
||||
uint32_t next;
|
||||
} drm_via_descriptor_t;
|
||||
|
||||
|
||||
/*
|
||||
* Unmap a DMA mapping.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
static void
|
||||
via_unmap_blit_from_device(struct pci_dev *pdev, drm_via_sg_info_t *vsg)
|
||||
{
|
||||
int num_desc = vsg->num_desc;
|
||||
unsigned cur_descriptor_page = num_desc / vsg->descriptors_per_page;
|
||||
unsigned descriptor_this_page = num_desc % vsg->descriptors_per_page;
|
||||
drm_via_descriptor_t *desc_ptr = vsg->desc_pages[cur_descriptor_page] +
|
||||
descriptor_this_page;
|
||||
dma_addr_t next = vsg->chain_start;
|
||||
|
||||
while(num_desc--) {
|
||||
if (descriptor_this_page-- == 0) {
|
||||
cur_descriptor_page--;
|
||||
descriptor_this_page = vsg->descriptors_per_page - 1;
|
||||
desc_ptr = vsg->desc_pages[cur_descriptor_page] +
|
||||
descriptor_this_page;
|
||||
}
|
||||
dma_unmap_single(&pdev->dev, next, sizeof(*desc_ptr), DMA_TO_DEVICE);
|
||||
dma_unmap_page(&pdev->dev, desc_ptr->mem_addr, desc_ptr->size, vsg->direction);
|
||||
next = (dma_addr_t) desc_ptr->next;
|
||||
desc_ptr--;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If mode = 0, count how many descriptors are needed.
|
||||
* If mode = 1, Map the DMA pages for the device, put together and map also the descriptors.
|
||||
* Descriptors are run in reverse order by the hardware because we are not allowed to update the
|
||||
* 'next' field without syncing calls when the descriptor is already mapped.
|
||||
*/
|
||||
|
||||
static void
|
||||
via_map_blit_for_device(struct pci_dev *pdev,
|
||||
const drm_via_dmablit_t *xfer,
|
||||
drm_via_sg_info_t *vsg,
|
||||
int mode)
|
||||
{
|
||||
unsigned cur_descriptor_page = 0;
|
||||
unsigned num_descriptors_this_page = 0;
|
||||
unsigned char *mem_addr = xfer->mem_addr;
|
||||
unsigned char *cur_mem;
|
||||
unsigned char *first_addr = (unsigned char *)VIA_PGDN(mem_addr);
|
||||
uint32_t fb_addr = xfer->fb_addr;
|
||||
uint32_t cur_fb;
|
||||
unsigned long line_len;
|
||||
unsigned remaining_len;
|
||||
int num_desc = 0;
|
||||
int cur_line;
|
||||
dma_addr_t next = 0 | VIA_DMA_DPR_EC;
|
||||
drm_via_descriptor_t *desc_ptr = NULL;
|
||||
|
||||
if (mode == 1)
|
||||
desc_ptr = vsg->desc_pages[cur_descriptor_page];
|
||||
|
||||
for (cur_line = 0; cur_line < xfer->num_lines; ++cur_line) {
|
||||
|
||||
line_len = xfer->line_length;
|
||||
cur_fb = fb_addr;
|
||||
cur_mem = mem_addr;
|
||||
|
||||
while (line_len > 0) {
|
||||
|
||||
remaining_len = min(PAGE_SIZE-VIA_PGOFF(cur_mem), line_len);
|
||||
line_len -= remaining_len;
|
||||
|
||||
if (mode == 1) {
|
||||
desc_ptr->mem_addr =
|
||||
dma_map_page(&pdev->dev,
|
||||
vsg->pages[VIA_PFN(cur_mem) -
|
||||
VIA_PFN(first_addr)],
|
||||
VIA_PGOFF(cur_mem), remaining_len,
|
||||
vsg->direction);
|
||||
desc_ptr->dev_addr = cur_fb;
|
||||
|
||||
desc_ptr->size = remaining_len;
|
||||
desc_ptr->next = (uint32_t) next;
|
||||
next = dma_map_single(&pdev->dev, desc_ptr, sizeof(*desc_ptr),
|
||||
DMA_TO_DEVICE);
|
||||
desc_ptr++;
|
||||
if (++num_descriptors_this_page >= vsg->descriptors_per_page) {
|
||||
num_descriptors_this_page = 0;
|
||||
desc_ptr = vsg->desc_pages[++cur_descriptor_page];
|
||||
}
|
||||
}
|
||||
|
||||
num_desc++;
|
||||
cur_mem += remaining_len;
|
||||
cur_fb += remaining_len;
|
||||
}
|
||||
|
||||
mem_addr += xfer->mem_stride;
|
||||
fb_addr += xfer->fb_stride;
|
||||
}
|
||||
|
||||
if (mode == 1) {
|
||||
vsg->chain_start = next;
|
||||
vsg->state = dr_via_device_mapped;
|
||||
}
|
||||
vsg->num_desc = num_desc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Function that frees up all resources for a blit. It is usable even if the
|
||||
* blit info has only been partially built as long as the status enum is consistent
|
||||
* with the actual status of the used resources.
|
||||
*/
|
||||
|
||||
|
||||
static void
|
||||
via_free_sg_info(struct pci_dev *pdev, drm_via_sg_info_t *vsg)
|
||||
{
|
||||
struct page *page;
|
||||
int i;
|
||||
|
||||
switch(vsg->state) {
|
||||
case dr_via_device_mapped:
|
||||
via_unmap_blit_from_device(pdev, vsg);
|
||||
case dr_via_desc_pages_alloc:
|
||||
for (i=0; i<vsg->num_desc_pages; ++i) {
|
||||
if (vsg->desc_pages[i] != NULL)
|
||||
free_page((unsigned long)vsg->desc_pages[i]);
|
||||
}
|
||||
kfree(vsg->desc_pages);
|
||||
case dr_via_pages_locked:
|
||||
for (i=0; i<vsg->num_pages; ++i) {
|
||||
if ( NULL != (page = vsg->pages[i])) {
|
||||
if (! PageReserved(page) && (DMA_FROM_DEVICE == vsg->direction))
|
||||
SetPageDirty(page);
|
||||
page_cache_release(page);
|
||||
}
|
||||
}
|
||||
case dr_via_pages_alloc:
|
||||
vfree(vsg->pages);
|
||||
default:
|
||||
vsg->state = dr_via_sg_init;
|
||||
}
|
||||
if (vsg->bounce_buffer) {
|
||||
vfree(vsg->bounce_buffer);
|
||||
vsg->bounce_buffer = NULL;
|
||||
}
|
||||
vsg->free_on_sequence = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fire a blit engine.
|
||||
*/
|
||||
|
||||
static void
|
||||
via_fire_dmablit(drm_device_t *dev, drm_via_sg_info_t *vsg, int engine)
|
||||
{
|
||||
drm_via_private_t *dev_priv = (drm_via_private_t *)dev->dev_private;
|
||||
|
||||
VIA_WRITE(VIA_PCI_DMA_MAR0 + engine*0x10, 0);
|
||||
VIA_WRITE(VIA_PCI_DMA_DAR0 + engine*0x10, 0);
|
||||
VIA_WRITE(VIA_PCI_DMA_CSR0 + engine*0x04, VIA_DMA_CSR_DD | VIA_DMA_CSR_TD |
|
||||
VIA_DMA_CSR_DE);
|
||||
VIA_WRITE(VIA_PCI_DMA_MR0 + engine*0x04, VIA_DMA_MR_CM | VIA_DMA_MR_TDIE);
|
||||
VIA_WRITE(VIA_PCI_DMA_BCR0 + engine*0x10, 0);
|
||||
VIA_WRITE(VIA_PCI_DMA_DPR0 + engine*0x10, vsg->chain_start);
|
||||
DRM_WRITEMEMORYBARRIER();
|
||||
VIA_WRITE(VIA_PCI_DMA_CSR0 + engine*0x04, VIA_DMA_CSR_DE | VIA_DMA_CSR_TS);
|
||||
VIA_READ(VIA_PCI_DMA_CSR0 + engine*0x04);
|
||||
}
|
||||
|
||||
/*
|
||||
* Obtain a page pointer array and lock all pages into system memory. A segmentation violation will
|
||||
* occur here if the calling user does not have access to the submitted address.
|
||||
*/
|
||||
|
||||
static int
|
||||
via_lock_all_dma_pages(drm_via_sg_info_t *vsg, drm_via_dmablit_t *xfer)
|
||||
{
|
||||
int ret;
|
||||
unsigned long first_pfn = VIA_PFN(xfer->mem_addr);
|
||||
vsg->num_pages = VIA_PFN(xfer->mem_addr + (xfer->num_lines * xfer->mem_stride -1)) -
|
||||
first_pfn + 1;
|
||||
|
||||
if (NULL == (vsg->pages = vmalloc(sizeof(struct page *) * vsg->num_pages)))
|
||||
return DRM_ERR(ENOMEM);
|
||||
memset(vsg->pages, 0, sizeof(struct page *) * vsg->num_pages);
|
||||
down_read(¤t->mm->mmap_sem);
|
||||
ret = get_user_pages(current, current->mm,
|
||||
(unsigned long)xfer->mem_addr,
|
||||
vsg->num_pages,
|
||||
(vsg->direction == DMA_FROM_DEVICE),
|
||||
0, vsg->pages, NULL);
|
||||
|
||||
up_read(¤t->mm->mmap_sem);
|
||||
if (ret != vsg->num_pages) {
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
vsg->state = dr_via_pages_locked;
|
||||
return DRM_ERR(EINVAL);
|
||||
}
|
||||
vsg->state = dr_via_pages_locked;
|
||||
DRM_DEBUG("DMA pages locked\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate DMA capable memory for the blit descriptor chain, and an array that keeps track of the
|
||||
* pages we allocate. We don't want to use kmalloc for the descriptor chain because it may be
|
||||
* quite large for some blits, and pages don't need to be contingous.
|
||||
*/
|
||||
|
||||
static int
|
||||
via_alloc_desc_pages(drm_via_sg_info_t *vsg)
|
||||
{
|
||||
int i;
|
||||
|
||||
vsg->descriptors_per_page = PAGE_SIZE / sizeof( drm_via_descriptor_t);
|
||||
vsg->num_desc_pages = (vsg->num_desc + vsg->descriptors_per_page - 1) /
|
||||
vsg->descriptors_per_page;
|
||||
|
||||
if (NULL == (vsg->desc_pages = kmalloc(sizeof(void *) * vsg->num_desc_pages, GFP_KERNEL)))
|
||||
return DRM_ERR(ENOMEM);
|
||||
|
||||
memset(vsg->desc_pages, 0, sizeof(void *) * vsg->num_desc_pages);
|
||||
vsg->state = dr_via_desc_pages_alloc;
|
||||
for (i=0; i<vsg->num_desc_pages; ++i) {
|
||||
if (NULL == (vsg->desc_pages[i] =
|
||||
(drm_via_descriptor_t *) __get_free_page(GFP_KERNEL)))
|
||||
return DRM_ERR(ENOMEM);
|
||||
}
|
||||
DRM_DEBUG("Allocated %d pages for %d descriptors.\n", vsg->num_desc_pages,
|
||||
vsg->num_desc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
via_abort_dmablit(drm_device_t *dev, int engine)
|
||||
{
|
||||
drm_via_private_t *dev_priv = (drm_via_private_t *)dev->dev_private;
|
||||
|
||||
VIA_WRITE(VIA_PCI_DMA_CSR0 + engine*0x04, VIA_DMA_CSR_TA);
|
||||
}
|
||||
|
||||
static void
|
||||
via_dmablit_engine_off(drm_device_t *dev, int engine)
|
||||
{
|
||||
drm_via_private_t *dev_priv = (drm_via_private_t *)dev->dev_private;
|
||||
|
||||
VIA_WRITE(VIA_PCI_DMA_CSR0 + engine*0x04, VIA_DMA_CSR_TD | VIA_DMA_CSR_DD);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* The dmablit part of the IRQ handler. Trying to do only reasonably fast things here.
|
||||
* The rest, like unmapping and freeing memory for done blits is done in a separate workqueue
|
||||
* task. Basically the task of the interrupt handler is to submit a new blit to the engine, while
|
||||
* the workqueue task takes care of processing associated with the old blit.
|
||||
*/
|
||||
|
||||
void
|
||||
via_dmablit_handler(drm_device_t *dev, int engine, int from_irq)
|
||||
{
|
||||
drm_via_private_t *dev_priv = (drm_via_private_t *)dev->dev_private;
|
||||
drm_via_blitq_t *blitq = dev_priv->blit_queues + engine;
|
||||
int cur;
|
||||
int done_transfer;
|
||||
unsigned long irqsave=0;
|
||||
uint32_t status = 0;
|
||||
|
||||
DRM_DEBUG("DMA blit handler called. engine = %d, from_irq = %d, blitq = 0x%lx\n",
|
||||
engine, from_irq, (unsigned long) blitq);
|
||||
|
||||
if (from_irq) {
|
||||
spin_lock(&blitq->blit_lock);
|
||||
} else {
|
||||
spin_lock_irqsave(&blitq->blit_lock, irqsave);
|
||||
}
|
||||
|
||||
done_transfer = blitq->is_active &&
|
||||
(( status = VIA_READ(VIA_PCI_DMA_CSR0 + engine*0x04)) & VIA_DMA_CSR_TD);
|
||||
done_transfer = done_transfer || ( blitq->aborting && !(status & VIA_DMA_CSR_DE));
|
||||
|
||||
cur = blitq->cur;
|
||||
if (done_transfer) {
|
||||
|
||||
blitq->blits[cur]->aborted = blitq->aborting;
|
||||
blitq->done_blit_handle++;
|
||||
DRM_WAKEUP(blitq->blit_queue + cur);
|
||||
|
||||
cur++;
|
||||
if (cur >= VIA_NUM_BLIT_SLOTS)
|
||||
cur = 0;
|
||||
blitq->cur = cur;
|
||||
|
||||
/*
|
||||
* Clear transfer done flag.
|
||||
*/
|
||||
|
||||
VIA_WRITE(VIA_PCI_DMA_CSR0 + engine*0x04, VIA_DMA_CSR_TD);
|
||||
|
||||
blitq->is_active = 0;
|
||||
blitq->aborting = 0;
|
||||
schedule_work(&blitq->wq);
|
||||
|
||||
} else if (blitq->is_active && time_after_eq(jiffies, blitq->end)) {
|
||||
|
||||
/*
|
||||
* Abort transfer after one second.
|
||||
*/
|
||||
|
||||
via_abort_dmablit(dev, engine);
|
||||
blitq->aborting = 1;
|
||||
blitq->end = jiffies + DRM_HZ;
|
||||
}
|
||||
|
||||
if (!blitq->is_active) {
|
||||
if (blitq->num_outstanding) {
|
||||
via_fire_dmablit(dev, blitq->blits[cur], engine);
|
||||
blitq->is_active = 1;
|
||||
blitq->cur = cur;
|
||||
blitq->num_outstanding--;
|
||||
blitq->end = jiffies + DRM_HZ;
|
||||
if (!timer_pending(&blitq->poll_timer))
|
||||
mod_timer(&blitq->poll_timer, jiffies + 1);
|
||||
} else {
|
||||
if (timer_pending(&blitq->poll_timer)) {
|
||||
del_timer(&blitq->poll_timer);
|
||||
}
|
||||
via_dmablit_engine_off(dev, engine);
|
||||
}
|
||||
}
|
||||
|
||||
if (from_irq) {
|
||||
spin_unlock(&blitq->blit_lock);
|
||||
} else {
|
||||
spin_unlock_irqrestore(&blitq->blit_lock, irqsave);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Check whether this blit is still active, performing necessary locking.
|
||||
*/
|
||||
|
||||
static int
|
||||
via_dmablit_active(drm_via_blitq_t *blitq, int engine, uint32_t handle, wait_queue_head_t **queue)
|
||||
{
|
||||
unsigned long irqsave;
|
||||
uint32_t slot;
|
||||
int active;
|
||||
|
||||
spin_lock_irqsave(&blitq->blit_lock, irqsave);
|
||||
|
||||
/*
|
||||
* Allow for handle wraparounds.
|
||||
*/
|
||||
|
||||
active = ((blitq->done_blit_handle - handle) > (1 << 23)) &&
|
||||
((blitq->cur_blit_handle - handle) <= (1 << 23));
|
||||
|
||||
if (queue && active) {
|
||||
slot = handle - blitq->done_blit_handle + blitq->cur -1;
|
||||
if (slot >= VIA_NUM_BLIT_SLOTS) {
|
||||
slot -= VIA_NUM_BLIT_SLOTS;
|
||||
}
|
||||
*queue = blitq->blit_queue + slot;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&blitq->blit_lock, irqsave);
|
||||
|
||||
return active;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sync. Wait for at least three seconds for the blit to be performed.
|
||||
*/
|
||||
|
||||
static int
|
||||
via_dmablit_sync(drm_device_t *dev, uint32_t handle, int engine)
|
||||
{
|
||||
|
||||
drm_via_private_t *dev_priv = (drm_via_private_t *)dev->dev_private;
|
||||
drm_via_blitq_t *blitq = dev_priv->blit_queues + engine;
|
||||
wait_queue_head_t *queue;
|
||||
int ret = 0;
|
||||
|
||||
if (via_dmablit_active(blitq, engine, handle, &queue)) {
|
||||
DRM_WAIT_ON(ret, *queue, 3 * DRM_HZ,
|
||||
!via_dmablit_active(blitq, engine, handle, NULL));
|
||||
}
|
||||
DRM_DEBUG("DMA blit sync handle 0x%x engine %d returned %d\n",
|
||||
handle, engine, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* A timer that regularly polls the blit engine in cases where we don't have interrupts:
|
||||
* a) Broken hardware (typically those that don't have any video capture facility).
|
||||
* b) Blit abort. The hardware doesn't send an interrupt when a blit is aborted.
|
||||
* The timer and hardware IRQ's can and do work in parallel. If the hardware has
|
||||
* irqs, it will shorten the latency somewhat.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
static void
|
||||
via_dmablit_timer(unsigned long data)
|
||||
{
|
||||
drm_via_blitq_t *blitq = (drm_via_blitq_t *) data;
|
||||
drm_device_t *dev = blitq->dev;
|
||||
int engine = (int)
|
||||
(blitq - ((drm_via_private_t *)dev->dev_private)->blit_queues);
|
||||
|
||||
DRM_DEBUG("Polling timer called for engine %d, jiffies %lu\n", engine,
|
||||
(unsigned long) jiffies);
|
||||
|
||||
via_dmablit_handler(dev, engine, 0);
|
||||
|
||||
if (!timer_pending(&blitq->poll_timer)) {
|
||||
mod_timer(&blitq->poll_timer, jiffies + 1);
|
||||
|
||||
/*
|
||||
* Rerun handler to delete timer if engines are off, and
|
||||
* to shorten abort latency. This is a little nasty.
|
||||
*/
|
||||
|
||||
via_dmablit_handler(dev, engine, 0);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Workqueue task that frees data and mappings associated with a blit.
|
||||
* Also wakes up waiting processes. Each of these tasks handles one
|
||||
* blit engine only and may not be called on each interrupt.
|
||||
*/
|
||||
|
||||
|
||||
static void
|
||||
via_dmablit_workqueue(struct work_struct *work)
|
||||
{
|
||||
drm_via_blitq_t *blitq = container_of(work, drm_via_blitq_t, wq);
|
||||
drm_device_t *dev = blitq->dev;
|
||||
unsigned long irqsave;
|
||||
drm_via_sg_info_t *cur_sg;
|
||||
int cur_released;
|
||||
|
||||
|
||||
DRM_DEBUG("Workqueue task called for blit engine %ld\n",(unsigned long)
|
||||
(blitq - ((drm_via_private_t *)dev->dev_private)->blit_queues));
|
||||
|
||||
spin_lock_irqsave(&blitq->blit_lock, irqsave);
|
||||
|
||||
while(blitq->serviced != blitq->cur) {
|
||||
|
||||
cur_released = blitq->serviced++;
|
||||
|
||||
DRM_DEBUG("Releasing blit slot %d\n", cur_released);
|
||||
|
||||
if (blitq->serviced >= VIA_NUM_BLIT_SLOTS)
|
||||
blitq->serviced = 0;
|
||||
|
||||
cur_sg = blitq->blits[cur_released];
|
||||
blitq->num_free++;
|
||||
|
||||
spin_unlock_irqrestore(&blitq->blit_lock, irqsave);
|
||||
|
||||
DRM_WAKEUP(&blitq->busy_queue);
|
||||
|
||||
via_free_sg_info(dev->pdev, cur_sg);
|
||||
kfree(cur_sg);
|
||||
|
||||
spin_lock_irqsave(&blitq->blit_lock, irqsave);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&blitq->blit_lock, irqsave);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Init all blit engines. Currently we use two, but some hardware have 4.
|
||||
*/
|
||||
|
||||
|
||||
void
|
||||
via_init_dmablit(drm_device_t *dev)
|
||||
{
|
||||
int i,j;
|
||||
drm_via_private_t *dev_priv = (drm_via_private_t *)dev->dev_private;
|
||||
drm_via_blitq_t *blitq;
|
||||
|
||||
pci_set_master(dev->pdev);
|
||||
|
||||
for (i=0; i< VIA_NUM_BLIT_ENGINES; ++i) {
|
||||
blitq = dev_priv->blit_queues + i;
|
||||
blitq->dev = dev;
|
||||
blitq->cur_blit_handle = 0;
|
||||
blitq->done_blit_handle = 0;
|
||||
blitq->head = 0;
|
||||
blitq->cur = 0;
|
||||
blitq->serviced = 0;
|
||||
blitq->num_free = VIA_NUM_BLIT_SLOTS;
|
||||
blitq->num_outstanding = 0;
|
||||
blitq->is_active = 0;
|
||||
blitq->aborting = 0;
|
||||
spin_lock_init(&blitq->blit_lock);
|
||||
for (j=0; j<VIA_NUM_BLIT_SLOTS; ++j) {
|
||||
DRM_INIT_WAITQUEUE(blitq->blit_queue + j);
|
||||
}
|
||||
DRM_INIT_WAITQUEUE(&blitq->busy_queue);
|
||||
INIT_WORK(&blitq->wq, via_dmablit_workqueue);
|
||||
setup_timer(&blitq->poll_timer, via_dmablit_timer,
|
||||
(unsigned long)blitq);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Build all info and do all mappings required for a blit.
|
||||
*/
|
||||
|
||||
|
||||
static int
|
||||
via_build_sg_info(drm_device_t *dev, drm_via_sg_info_t *vsg, drm_via_dmablit_t *xfer)
|
||||
{
|
||||
int draw = xfer->to_fb;
|
||||
int ret = 0;
|
||||
|
||||
vsg->direction = (draw) ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
|
||||
vsg->bounce_buffer = NULL;
|
||||
|
||||
vsg->state = dr_via_sg_init;
|
||||
|
||||
if (xfer->num_lines <= 0 || xfer->line_length <= 0) {
|
||||
DRM_ERROR("Zero size bitblt.\n");
|
||||
return DRM_ERR(EINVAL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Below check is a driver limitation, not a hardware one. We
|
||||
* don't want to lock unused pages, and don't want to incoporate the
|
||||
* extra logic of avoiding them. Make sure there are no.
|
||||
* (Not a big limitation anyway.)
|
||||
*/
|
||||
|
||||
if ((xfer->mem_stride - xfer->line_length) >= PAGE_SIZE) {
|
||||
DRM_ERROR("Too large system memory stride. Stride: %d, "
|
||||
"Length: %d\n", xfer->mem_stride, xfer->line_length);
|
||||
return DRM_ERR(EINVAL);
|
||||
}
|
||||
|
||||
if ((xfer->mem_stride == xfer->line_length) &&
|
||||
(xfer->fb_stride == xfer->line_length)) {
|
||||
xfer->mem_stride *= xfer->num_lines;
|
||||
xfer->line_length = xfer->mem_stride;
|
||||
xfer->fb_stride = xfer->mem_stride;
|
||||
xfer->num_lines = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Don't lock an arbitrary large number of pages, since that causes a
|
||||
* DOS security hole.
|
||||
*/
|
||||
|
||||
if (xfer->num_lines > 2048 || (xfer->num_lines*xfer->mem_stride > (2048*2048*4))) {
|
||||
DRM_ERROR("Too large PCI DMA bitblt.\n");
|
||||
return DRM_ERR(EINVAL);
|
||||
}
|
||||
|
||||
/*
|
||||
* we allow a negative fb stride to allow flipping of images in
|
||||
* transfer.
|
||||
*/
|
||||
|
||||
if (xfer->mem_stride < xfer->line_length ||
|
||||
abs(xfer->fb_stride) < xfer->line_length) {
|
||||
DRM_ERROR("Invalid frame-buffer / memory stride.\n");
|
||||
return DRM_ERR(EINVAL);
|
||||
}
|
||||
|
||||
/*
|
||||
* A hardware bug seems to be worked around if system memory addresses start on
|
||||
* 16 byte boundaries. This seems a bit restrictive however. VIA is contacted
|
||||
* about this. Meanwhile, impose the following restrictions:
|
||||
*/
|
||||
|
||||
#ifdef VIA_BUGFREE
|
||||
if ((((unsigned long)xfer->mem_addr & 3) != ((unsigned long)xfer->fb_addr & 3)) ||
|
||||
((xfer->num_lines > 1) && ((xfer->mem_stride & 3) != (xfer->fb_stride & 3)))) {
|
||||
DRM_ERROR("Invalid DRM bitblt alignment.\n");
|
||||
return DRM_ERR(EINVAL);
|
||||
}
|
||||
#else
|
||||
if ((((unsigned long)xfer->mem_addr & 15) ||
|
||||
((unsigned long)xfer->fb_addr & 3)) ||
|
||||
((xfer->num_lines > 1) &&
|
||||
((xfer->mem_stride & 15) || (xfer->fb_stride & 3)))) {
|
||||
DRM_ERROR("Invalid DRM bitblt alignment.\n");
|
||||
return DRM_ERR(EINVAL);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (0 != (ret = via_lock_all_dma_pages(vsg, xfer))) {
|
||||
DRM_ERROR("Could not lock DMA pages.\n");
|
||||
via_free_sg_info(dev->pdev, vsg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
via_map_blit_for_device(dev->pdev, xfer, vsg, 0);
|
||||
if (0 != (ret = via_alloc_desc_pages(vsg))) {
|
||||
DRM_ERROR("Could not allocate DMA descriptor pages.\n");
|
||||
via_free_sg_info(dev->pdev, vsg);
|
||||
return ret;
|
||||
}
|
||||
via_map_blit_for_device(dev->pdev, xfer, vsg, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Reserve one free slot in the blit queue. Will wait for one second for one
|
||||
* to become available. Otherwise -EBUSY is returned.
|
||||
*/
|
||||
|
||||
static int
|
||||
via_dmablit_grab_slot(drm_via_blitq_t *blitq, int engine)
|
||||
{
|
||||
int ret=0;
|
||||
unsigned long irqsave;
|
||||
|
||||
DRM_DEBUG("Num free is %d\n", blitq->num_free);
|
||||
spin_lock_irqsave(&blitq->blit_lock, irqsave);
|
||||
while(blitq->num_free == 0) {
|
||||
spin_unlock_irqrestore(&blitq->blit_lock, irqsave);
|
||||
|
||||
DRM_WAIT_ON(ret, blitq->busy_queue, DRM_HZ, blitq->num_free > 0);
|
||||
if (ret) {
|
||||
return (DRM_ERR(EINTR) == ret) ? DRM_ERR(EAGAIN) : ret;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&blitq->blit_lock, irqsave);
|
||||
}
|
||||
|
||||
blitq->num_free--;
|
||||
spin_unlock_irqrestore(&blitq->blit_lock, irqsave);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Hand back a free slot if we changed our mind.
|
||||
*/
|
||||
|
||||
static void
|
||||
via_dmablit_release_slot(drm_via_blitq_t *blitq)
|
||||
{
|
||||
unsigned long irqsave;
|
||||
|
||||
spin_lock_irqsave(&blitq->blit_lock, irqsave);
|
||||
blitq->num_free++;
|
||||
spin_unlock_irqrestore(&blitq->blit_lock, irqsave);
|
||||
DRM_WAKEUP( &blitq->busy_queue );
|
||||
}
|
||||
|
||||
/*
|
||||
* Grab a free slot. Build blit info and queue a blit.
|
||||
*/
|
||||
|
||||
|
||||
static int
|
||||
via_dmablit(drm_device_t *dev, drm_via_dmablit_t *xfer)
|
||||
{
|
||||
drm_via_private_t *dev_priv = (drm_via_private_t *)dev->dev_private;
|
||||
drm_via_sg_info_t *vsg;
|
||||
drm_via_blitq_t *blitq;
|
||||
int ret;
|
||||
int engine;
|
||||
unsigned long irqsave;
|
||||
|
||||
if (dev_priv == NULL) {
|
||||
DRM_ERROR("Called without initialization.\n");
|
||||
return DRM_ERR(EINVAL);
|
||||
}
|
||||
|
||||
engine = (xfer->to_fb) ? 0 : 1;
|
||||
blitq = dev_priv->blit_queues + engine;
|
||||
if (0 != (ret = via_dmablit_grab_slot(blitq, engine))) {
|
||||
return ret;
|
||||
}
|
||||
if (NULL == (vsg = kmalloc(sizeof(*vsg), GFP_KERNEL))) {
|
||||
via_dmablit_release_slot(blitq);
|
||||
return DRM_ERR(ENOMEM);
|
||||
}
|
||||
if (0 != (ret = via_build_sg_info(dev, vsg, xfer))) {
|
||||
via_dmablit_release_slot(blitq);
|
||||
kfree(vsg);
|
||||
return ret;
|
||||
}
|
||||
spin_lock_irqsave(&blitq->blit_lock, irqsave);
|
||||
|
||||
blitq->blits[blitq->head++] = vsg;
|
||||
if (blitq->head >= VIA_NUM_BLIT_SLOTS)
|
||||
blitq->head = 0;
|
||||
blitq->num_outstanding++;
|
||||
xfer->sync.sync_handle = ++blitq->cur_blit_handle;
|
||||
|
||||
spin_unlock_irqrestore(&blitq->blit_lock, irqsave);
|
||||
xfer->sync.engine = engine;
|
||||
|
||||
via_dmablit_handler(dev, engine, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sync on a previously submitted blit. Note that the X server use signals extensively, and
|
||||
* that there is a very big probability that this IOCTL will be interrupted by a signal. In that
|
||||
* case it returns with -EAGAIN for the signal to be delivered.
|
||||
* The caller should then reissue the IOCTL. This is similar to what is being done for drmGetLock().
|
||||
*/
|
||||
|
||||
int
|
||||
via_dma_blit_sync( DRM_IOCTL_ARGS )
|
||||
{
|
||||
drm_via_blitsync_t sync;
|
||||
int err;
|
||||
DRM_DEVICE;
|
||||
|
||||
DRM_COPY_FROM_USER_IOCTL(sync, (drm_via_blitsync_t *)data, sizeof(sync));
|
||||
|
||||
if (sync.engine >= VIA_NUM_BLIT_ENGINES)
|
||||
return DRM_ERR(EINVAL);
|
||||
|
||||
err = via_dmablit_sync(dev, sync.sync_handle, sync.engine);
|
||||
|
||||
if (DRM_ERR(EINTR) == err)
|
||||
err = DRM_ERR(EAGAIN);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Queue a blit and hand back a handle to be used for sync. This IOCTL may be interrupted by a signal
|
||||
* while waiting for a free slot in the blit queue. In that case it returns with -EAGAIN and should
|
||||
* be reissued. See the above IOCTL code.
|
||||
*/
|
||||
|
||||
int
|
||||
via_dma_blit( DRM_IOCTL_ARGS )
|
||||
{
|
||||
drm_via_dmablit_t xfer;
|
||||
int err;
|
||||
DRM_DEVICE;
|
||||
|
||||
DRM_COPY_FROM_USER_IOCTL(xfer, (drm_via_dmablit_t __user *)data, sizeof(xfer));
|
||||
|
||||
err = via_dmablit(dev, &xfer);
|
||||
|
||||
DRM_COPY_TO_USER_IOCTL((void __user *)data, xfer, sizeof(xfer));
|
||||
|
||||
return err;
|
||||
}
|
||||
140
drivers/char/drm/via_dmablit.h
Normal file
140
drivers/char/drm/via_dmablit.h
Normal file
@@ -0,0 +1,140 @@
|
||||
/* via_dmablit.h -- PCI DMA BitBlt support for the VIA Unichrome/Pro
|
||||
*
|
||||
* Copyright 2005 Thomas Hellstrom.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sub license,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the
|
||||
* next paragraph) shall be included in all copies or substantial portions
|
||||
* of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
* USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors:
|
||||
* Thomas Hellstrom.
|
||||
* Register info from Digeo Inc.
|
||||
*/
|
||||
|
||||
#ifndef _VIA_DMABLIT_H
|
||||
#define _VIA_DMABLIT_H
|
||||
|
||||
#include <linux/dma-mapping.h>
|
||||
|
||||
#define VIA_NUM_BLIT_ENGINES 2
|
||||
#define VIA_NUM_BLIT_SLOTS 8
|
||||
|
||||
struct _drm_via_descriptor;
|
||||
|
||||
typedef struct _drm_via_sg_info {
|
||||
struct page **pages;
|
||||
unsigned long num_pages;
|
||||
struct _drm_via_descriptor **desc_pages;
|
||||
int num_desc_pages;
|
||||
int num_desc;
|
||||
enum dma_data_direction direction;
|
||||
unsigned char *bounce_buffer;
|
||||
dma_addr_t chain_start;
|
||||
uint32_t free_on_sequence;
|
||||
unsigned int descriptors_per_page;
|
||||
int aborted;
|
||||
enum {
|
||||
dr_via_device_mapped,
|
||||
dr_via_desc_pages_alloc,
|
||||
dr_via_pages_locked,
|
||||
dr_via_pages_alloc,
|
||||
dr_via_sg_init
|
||||
} state;
|
||||
} drm_via_sg_info_t;
|
||||
|
||||
typedef struct _drm_via_blitq {
|
||||
drm_device_t *dev;
|
||||
uint32_t cur_blit_handle;
|
||||
uint32_t done_blit_handle;
|
||||
unsigned serviced;
|
||||
unsigned head;
|
||||
unsigned cur;
|
||||
unsigned num_free;
|
||||
unsigned num_outstanding;
|
||||
unsigned long end;
|
||||
int aborting;
|
||||
int is_active;
|
||||
drm_via_sg_info_t *blits[VIA_NUM_BLIT_SLOTS];
|
||||
spinlock_t blit_lock;
|
||||
wait_queue_head_t blit_queue[VIA_NUM_BLIT_SLOTS];
|
||||
wait_queue_head_t busy_queue;
|
||||
struct work_struct wq;
|
||||
struct timer_list poll_timer;
|
||||
} drm_via_blitq_t;
|
||||
|
||||
|
||||
/*
|
||||
* PCI DMA Registers
|
||||
* Channels 2 & 3 don't seem to be implemented in hardware.
|
||||
*/
|
||||
|
||||
#define VIA_PCI_DMA_MAR0 0xE40 /* Memory Address Register of Channel 0 */
|
||||
#define VIA_PCI_DMA_DAR0 0xE44 /* Device Address Register of Channel 0 */
|
||||
#define VIA_PCI_DMA_BCR0 0xE48 /* Byte Count Register of Channel 0 */
|
||||
#define VIA_PCI_DMA_DPR0 0xE4C /* Descriptor Pointer Register of Channel 0 */
|
||||
|
||||
#define VIA_PCI_DMA_MAR1 0xE50 /* Memory Address Register of Channel 1 */
|
||||
#define VIA_PCI_DMA_DAR1 0xE54 /* Device Address Register of Channel 1 */
|
||||
#define VIA_PCI_DMA_BCR1 0xE58 /* Byte Count Register of Channel 1 */
|
||||
#define VIA_PCI_DMA_DPR1 0xE5C /* Descriptor Pointer Register of Channel 1 */
|
||||
|
||||
#define VIA_PCI_DMA_MAR2 0xE60 /* Memory Address Register of Channel 2 */
|
||||
#define VIA_PCI_DMA_DAR2 0xE64 /* Device Address Register of Channel 2 */
|
||||
#define VIA_PCI_DMA_BCR2 0xE68 /* Byte Count Register of Channel 2 */
|
||||
#define VIA_PCI_DMA_DPR2 0xE6C /* Descriptor Pointer Register of Channel 2 */
|
||||
|
||||
#define VIA_PCI_DMA_MAR3 0xE70 /* Memory Address Register of Channel 3 */
|
||||
#define VIA_PCI_DMA_DAR3 0xE74 /* Device Address Register of Channel 3 */
|
||||
#define VIA_PCI_DMA_BCR3 0xE78 /* Byte Count Register of Channel 3 */
|
||||
#define VIA_PCI_DMA_DPR3 0xE7C /* Descriptor Pointer Register of Channel 3 */
|
||||
|
||||
#define VIA_PCI_DMA_MR0 0xE80 /* Mode Register of Channel 0 */
|
||||
#define VIA_PCI_DMA_MR1 0xE84 /* Mode Register of Channel 1 */
|
||||
#define VIA_PCI_DMA_MR2 0xE88 /* Mode Register of Channel 2 */
|
||||
#define VIA_PCI_DMA_MR3 0xE8C /* Mode Register of Channel 3 */
|
||||
|
||||
#define VIA_PCI_DMA_CSR0 0xE90 /* Command/Status Register of Channel 0 */
|
||||
#define VIA_PCI_DMA_CSR1 0xE94 /* Command/Status Register of Channel 1 */
|
||||
#define VIA_PCI_DMA_CSR2 0xE98 /* Command/Status Register of Channel 2 */
|
||||
#define VIA_PCI_DMA_CSR3 0xE9C /* Command/Status Register of Channel 3 */
|
||||
|
||||
#define VIA_PCI_DMA_PTR 0xEA0 /* Priority Type Register */
|
||||
|
||||
/* Define for DMA engine */
|
||||
/* DPR */
|
||||
#define VIA_DMA_DPR_EC (1<<1) /* end of chain */
|
||||
#define VIA_DMA_DPR_DDIE (1<<2) /* descriptor done interrupt enable */
|
||||
#define VIA_DMA_DPR_DT (1<<3) /* direction of transfer (RO) */
|
||||
|
||||
/* MR */
|
||||
#define VIA_DMA_MR_CM (1<<0) /* chaining mode */
|
||||
#define VIA_DMA_MR_TDIE (1<<1) /* transfer done interrupt enable */
|
||||
#define VIA_DMA_MR_HENDMACMD (1<<7) /* ? */
|
||||
|
||||
/* CSR */
|
||||
#define VIA_DMA_CSR_DE (1<<0) /* DMA enable */
|
||||
#define VIA_DMA_CSR_TS (1<<1) /* transfer start */
|
||||
#define VIA_DMA_CSR_TA (1<<2) /* transfer abort */
|
||||
#define VIA_DMA_CSR_TD (1<<3) /* transfer done */
|
||||
#define VIA_DMA_CSR_DD (1<<4) /* descriptor done */
|
||||
#define VIA_DMA_DPR_EC (1<<1) /* end of chain */
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
275
drivers/char/drm/via_drm.h
Normal file
275
drivers/char/drm/via_drm.h
Normal file
@@ -0,0 +1,275 @@
|
||||
/*
|
||||
* Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
|
||||
* Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sub license,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the
|
||||
* next paragraph) shall be included in all copies or substantial portions
|
||||
* of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
|
||||
* VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef _VIA_DRM_H_
|
||||
#define _VIA_DRM_H_
|
||||
|
||||
/* WARNING: These defines must be the same as what the Xserver uses.
|
||||
* if you change them, you must change the defines in the Xserver.
|
||||
*/
|
||||
|
||||
#ifndef _VIA_DEFINES_
|
||||
#define _VIA_DEFINES_
|
||||
|
||||
#ifndef __KERNEL__
|
||||
#include "via_drmclient.h"
|
||||
#endif
|
||||
|
||||
#define VIA_NR_SAREA_CLIPRECTS 8
|
||||
#define VIA_NR_XVMC_PORTS 10
|
||||
#define VIA_NR_XVMC_LOCKS 5
|
||||
#define VIA_MAX_CACHELINE_SIZE 64
|
||||
#define XVMCLOCKPTR(saPriv,lockNo) \
|
||||
((volatile drm_hw_lock_t *)(((((unsigned long) (saPriv)->XvMCLockArea) + \
|
||||
(VIA_MAX_CACHELINE_SIZE - 1)) & \
|
||||
~(VIA_MAX_CACHELINE_SIZE - 1)) + \
|
||||
VIA_MAX_CACHELINE_SIZE*(lockNo)))
|
||||
|
||||
/* Each region is a minimum of 64k, and there are at most 64 of them.
|
||||
*/
|
||||
#define VIA_NR_TEX_REGIONS 64
|
||||
#define VIA_LOG_MIN_TEX_REGION_SIZE 16
|
||||
#endif
|
||||
|
||||
#define VIA_UPLOAD_TEX0IMAGE 0x1 /* handled clientside */
|
||||
#define VIA_UPLOAD_TEX1IMAGE 0x2 /* handled clientside */
|
||||
#define VIA_UPLOAD_CTX 0x4
|
||||
#define VIA_UPLOAD_BUFFERS 0x8
|
||||
#define VIA_UPLOAD_TEX0 0x10
|
||||
#define VIA_UPLOAD_TEX1 0x20
|
||||
#define VIA_UPLOAD_CLIPRECTS 0x40
|
||||
#define VIA_UPLOAD_ALL 0xff
|
||||
|
||||
/* VIA specific ioctls */
|
||||
#define DRM_VIA_ALLOCMEM 0x00
|
||||
#define DRM_VIA_FREEMEM 0x01
|
||||
#define DRM_VIA_AGP_INIT 0x02
|
||||
#define DRM_VIA_FB_INIT 0x03
|
||||
#define DRM_VIA_MAP_INIT 0x04
|
||||
#define DRM_VIA_DEC_FUTEX 0x05
|
||||
#define NOT_USED
|
||||
#define DRM_VIA_DMA_INIT 0x07
|
||||
#define DRM_VIA_CMDBUFFER 0x08
|
||||
#define DRM_VIA_FLUSH 0x09
|
||||
#define DRM_VIA_PCICMD 0x0a
|
||||
#define DRM_VIA_CMDBUF_SIZE 0x0b
|
||||
#define NOT_USED
|
||||
#define DRM_VIA_WAIT_IRQ 0x0d
|
||||
#define DRM_VIA_DMA_BLIT 0x0e
|
||||
#define DRM_VIA_BLIT_SYNC 0x0f
|
||||
|
||||
#define DRM_IOCTL_VIA_ALLOCMEM DRM_IOWR(DRM_COMMAND_BASE + DRM_VIA_ALLOCMEM, drm_via_mem_t)
|
||||
#define DRM_IOCTL_VIA_FREEMEM DRM_IOW( DRM_COMMAND_BASE + DRM_VIA_FREEMEM, drm_via_mem_t)
|
||||
#define DRM_IOCTL_VIA_AGP_INIT DRM_IOWR(DRM_COMMAND_BASE + DRM_VIA_AGP_INIT, drm_via_agp_t)
|
||||
#define DRM_IOCTL_VIA_FB_INIT DRM_IOWR(DRM_COMMAND_BASE + DRM_VIA_FB_INIT, drm_via_fb_t)
|
||||
#define DRM_IOCTL_VIA_MAP_INIT DRM_IOWR(DRM_COMMAND_BASE + DRM_VIA_MAP_INIT, drm_via_init_t)
|
||||
#define DRM_IOCTL_VIA_DEC_FUTEX DRM_IOW( DRM_COMMAND_BASE + DRM_VIA_DEC_FUTEX, drm_via_futex_t)
|
||||
#define DRM_IOCTL_VIA_DMA_INIT DRM_IOWR(DRM_COMMAND_BASE + DRM_VIA_DMA_INIT, drm_via_dma_init_t)
|
||||
#define DRM_IOCTL_VIA_CMDBUFFER DRM_IOW( DRM_COMMAND_BASE + DRM_VIA_CMDBUFFER, drm_via_cmdbuffer_t)
|
||||
#define DRM_IOCTL_VIA_FLUSH DRM_IO( DRM_COMMAND_BASE + DRM_VIA_FLUSH)
|
||||
#define DRM_IOCTL_VIA_PCICMD DRM_IOW( DRM_COMMAND_BASE + DRM_VIA_PCICMD, drm_via_cmdbuffer_t)
|
||||
#define DRM_IOCTL_VIA_CMDBUF_SIZE DRM_IOWR( DRM_COMMAND_BASE + DRM_VIA_CMDBUF_SIZE, \
|
||||
drm_via_cmdbuf_size_t)
|
||||
#define DRM_IOCTL_VIA_WAIT_IRQ DRM_IOWR( DRM_COMMAND_BASE + DRM_VIA_WAIT_IRQ, drm_via_irqwait_t)
|
||||
#define DRM_IOCTL_VIA_DMA_BLIT DRM_IOW(DRM_COMMAND_BASE + DRM_VIA_DMA_BLIT, drm_via_dmablit_t)
|
||||
#define DRM_IOCTL_VIA_BLIT_SYNC DRM_IOW(DRM_COMMAND_BASE + DRM_VIA_BLIT_SYNC, drm_via_blitsync_t)
|
||||
|
||||
/* Indices into buf.Setup where various bits of state are mirrored per
|
||||
* context and per buffer. These can be fired at the card as a unit,
|
||||
* or in a piecewise fashion as required.
|
||||
*/
|
||||
|
||||
#define VIA_TEX_SETUP_SIZE 8
|
||||
|
||||
/* Flags for clear ioctl
|
||||
*/
|
||||
#define VIA_FRONT 0x1
|
||||
#define VIA_BACK 0x2
|
||||
#define VIA_DEPTH 0x4
|
||||
#define VIA_STENCIL 0x8
|
||||
#define VIA_MEM_VIDEO 0 /* matches drm constant */
|
||||
#define VIA_MEM_AGP 1 /* matches drm constant */
|
||||
#define VIA_MEM_SYSTEM 2
|
||||
#define VIA_MEM_MIXED 3
|
||||
#define VIA_MEM_UNKNOWN 4
|
||||
|
||||
typedef struct {
|
||||
uint32_t offset;
|
||||
uint32_t size;
|
||||
} drm_via_agp_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t offset;
|
||||
uint32_t size;
|
||||
} drm_via_fb_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t context;
|
||||
uint32_t type;
|
||||
uint32_t size;
|
||||
unsigned long index;
|
||||
unsigned long offset;
|
||||
} drm_via_mem_t;
|
||||
|
||||
typedef struct _drm_via_init {
|
||||
enum {
|
||||
VIA_INIT_MAP = 0x01,
|
||||
VIA_CLEANUP_MAP = 0x02
|
||||
} func;
|
||||
|
||||
unsigned long sarea_priv_offset;
|
||||
unsigned long fb_offset;
|
||||
unsigned long mmio_offset;
|
||||
unsigned long agpAddr;
|
||||
} drm_via_init_t;
|
||||
|
||||
typedef struct _drm_via_futex {
|
||||
enum {
|
||||
VIA_FUTEX_WAIT = 0x00,
|
||||
VIA_FUTEX_WAKE = 0X01
|
||||
} func;
|
||||
uint32_t ms;
|
||||
uint32_t lock;
|
||||
uint32_t val;
|
||||
} drm_via_futex_t;
|
||||
|
||||
typedef struct _drm_via_dma_init {
|
||||
enum {
|
||||
VIA_INIT_DMA = 0x01,
|
||||
VIA_CLEANUP_DMA = 0x02,
|
||||
VIA_DMA_INITIALIZED = 0x03
|
||||
} func;
|
||||
|
||||
unsigned long offset;
|
||||
unsigned long size;
|
||||
unsigned long reg_pause_addr;
|
||||
} drm_via_dma_init_t;
|
||||
|
||||
typedef struct _drm_via_cmdbuffer {
|
||||
char __user *buf;
|
||||
unsigned long size;
|
||||
} drm_via_cmdbuffer_t;
|
||||
|
||||
/* Warning: If you change the SAREA structure you must change the Xserver
|
||||
* structure as well */
|
||||
|
||||
typedef struct _drm_via_tex_region {
|
||||
unsigned char next, prev; /* indices to form a circular LRU */
|
||||
unsigned char inUse; /* owned by a client, or free? */
|
||||
int age; /* tracked by clients to update local LRU's */
|
||||
} drm_via_tex_region_t;
|
||||
|
||||
typedef struct _drm_via_sarea {
|
||||
unsigned int dirty;
|
||||
unsigned int nbox;
|
||||
drm_clip_rect_t boxes[VIA_NR_SAREA_CLIPRECTS];
|
||||
drm_via_tex_region_t texList[VIA_NR_TEX_REGIONS + 1];
|
||||
int texAge; /* last time texture was uploaded */
|
||||
int ctxOwner; /* last context to upload state */
|
||||
int vertexPrim;
|
||||
|
||||
/*
|
||||
* Below is for XvMC.
|
||||
* We want the lock integers alone on, and aligned to, a cache line.
|
||||
* Therefore this somewhat strange construct.
|
||||
*/
|
||||
|
||||
char XvMCLockArea[VIA_MAX_CACHELINE_SIZE * (VIA_NR_XVMC_LOCKS + 1)];
|
||||
|
||||
unsigned int XvMCDisplaying[VIA_NR_XVMC_PORTS];
|
||||
unsigned int XvMCSubPicOn[VIA_NR_XVMC_PORTS];
|
||||
unsigned int XvMCCtxNoGrabbed; /* Last context to hold decoder */
|
||||
|
||||
/* Used by the 3d driver only at this point, for pageflipping:
|
||||
*/
|
||||
unsigned int pfCurrentOffset;
|
||||
} drm_via_sarea_t;
|
||||
|
||||
typedef struct _drm_via_cmdbuf_size {
|
||||
enum {
|
||||
VIA_CMDBUF_SPACE = 0x01,
|
||||
VIA_CMDBUF_LAG = 0x02
|
||||
} func;
|
||||
int wait;
|
||||
uint32_t size;
|
||||
} drm_via_cmdbuf_size_t;
|
||||
|
||||
typedef enum {
|
||||
VIA_IRQ_ABSOLUTE = 0x0,
|
||||
VIA_IRQ_RELATIVE = 0x1,
|
||||
VIA_IRQ_SIGNAL = 0x10000000,
|
||||
VIA_IRQ_FORCE_SEQUENCE = 0x20000000
|
||||
} via_irq_seq_type_t;
|
||||
|
||||
#define VIA_IRQ_FLAGS_MASK 0xF0000000
|
||||
|
||||
enum drm_via_irqs {
|
||||
drm_via_irq_hqv0 = 0,
|
||||
drm_via_irq_hqv1,
|
||||
drm_via_irq_dma0_dd,
|
||||
drm_via_irq_dma0_td,
|
||||
drm_via_irq_dma1_dd,
|
||||
drm_via_irq_dma1_td,
|
||||
drm_via_irq_num
|
||||
};
|
||||
|
||||
struct drm_via_wait_irq_request {
|
||||
unsigned irq;
|
||||
via_irq_seq_type_t type;
|
||||
uint32_t sequence;
|
||||
uint32_t signal;
|
||||
};
|
||||
|
||||
typedef union drm_via_irqwait {
|
||||
struct drm_via_wait_irq_request request;
|
||||
struct drm_wait_vblank_reply reply;
|
||||
} drm_via_irqwait_t;
|
||||
|
||||
typedef struct drm_via_blitsync {
|
||||
uint32_t sync_handle;
|
||||
unsigned engine;
|
||||
} drm_via_blitsync_t;
|
||||
|
||||
/* - * Below,"flags" is currently unused but will be used for possible future
|
||||
* extensions like kernel space bounce buffers for bad alignments and
|
||||
* blit engine busy-wait polling for better latency in the absence of
|
||||
* interrupts.
|
||||
*/
|
||||
|
||||
typedef struct drm_via_dmablit {
|
||||
uint32_t num_lines;
|
||||
uint32_t line_length;
|
||||
|
||||
uint32_t fb_addr;
|
||||
uint32_t fb_stride;
|
||||
|
||||
unsigned char *mem_addr;
|
||||
uint32_t mem_stride;
|
||||
|
||||
uint32_t flags;
|
||||
int to_fb;
|
||||
|
||||
drm_via_blitsync_t sync;
|
||||
} drm_via_dmablit_t;
|
||||
|
||||
#endif /* _VIA_DRM_H_ */
|
||||
99
drivers/char/drm/via_drv.c
Normal file
99
drivers/char/drm/via_drv.c
Normal file
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
|
||||
* Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sub license,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the
|
||||
* next paragraph) shall be included in all copies or substantial portions
|
||||
* of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
|
||||
* VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "drmP.h"
|
||||
#include "via_drm.h"
|
||||
#include "via_drv.h"
|
||||
|
||||
#include "drm_pciids.h"
|
||||
|
||||
static int dri_library_name(struct drm_device *dev, char *buf)
|
||||
{
|
||||
return snprintf(buf, PAGE_SIZE, "unichrome");
|
||||
}
|
||||
|
||||
static struct pci_device_id pciidlist[] = {
|
||||
viadrv_PCI_IDS
|
||||
};
|
||||
|
||||
static struct drm_driver driver = {
|
||||
.driver_features =
|
||||
DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_HAVE_IRQ |
|
||||
DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL,
|
||||
.load = via_driver_load,
|
||||
.unload = via_driver_unload,
|
||||
.context_dtor = via_final_context,
|
||||
.vblank_wait = via_driver_vblank_wait,
|
||||
.irq_preinstall = via_driver_irq_preinstall,
|
||||
.irq_postinstall = via_driver_irq_postinstall,
|
||||
.irq_uninstall = via_driver_irq_uninstall,
|
||||
.irq_handler = via_driver_irq_handler,
|
||||
.dma_quiescent = via_driver_dma_quiescent,
|
||||
.dri_library_name = dri_library_name,
|
||||
.reclaim_buffers = drm_core_reclaim_buffers,
|
||||
.reclaim_buffers_locked = via_reclaim_buffers_locked,
|
||||
.lastclose = via_lastclose,
|
||||
.get_map_ofs = drm_core_get_map_ofs,
|
||||
.get_reg_ofs = drm_core_get_reg_ofs,
|
||||
.ioctls = via_ioctls,
|
||||
.fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = drm_open,
|
||||
.release = drm_release,
|
||||
.ioctl = drm_ioctl,
|
||||
.mmap = drm_mmap,
|
||||
.poll = drm_poll,
|
||||
.fasync = drm_fasync,
|
||||
},
|
||||
.pci_driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.id_table = pciidlist,
|
||||
},
|
||||
|
||||
.name = DRIVER_NAME,
|
||||
.desc = DRIVER_DESC,
|
||||
.date = DRIVER_DATE,
|
||||
.major = DRIVER_MAJOR,
|
||||
.minor = DRIVER_MINOR,
|
||||
.patchlevel = DRIVER_PATCHLEVEL,
|
||||
};
|
||||
|
||||
static int __init via_init(void)
|
||||
{
|
||||
driver.num_ioctls = via_max_ioctl;
|
||||
via_init_command_verifier();
|
||||
return drm_init(&driver);
|
||||
}
|
||||
|
||||
static void __exit via_exit(void)
|
||||
{
|
||||
drm_exit(&driver);
|
||||
}
|
||||
|
||||
module_init(via_init);
|
||||
module_exit(via_exit);
|
||||
|
||||
MODULE_AUTHOR(DRIVER_AUTHOR);
|
||||
MODULE_DESCRIPTION(DRIVER_DESC);
|
||||
MODULE_LICENSE("GPL and additional rights");
|
||||
152
drivers/char/drm/via_drv.h
Normal file
152
drivers/char/drm/via_drv.h
Normal file
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
|
||||
* Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sub license,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the
|
||||
* next paragraph) shall be included in all copies or substantial portions
|
||||
* of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
|
||||
* VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef _VIA_DRV_H_
|
||||
#define _VIA_DRV_H_
|
||||
|
||||
#include "drm_sman.h"
|
||||
#define DRIVER_AUTHOR "Various"
|
||||
|
||||
#define DRIVER_NAME "via"
|
||||
#define DRIVER_DESC "VIA Unichrome / Pro"
|
||||
#define DRIVER_DATE "20061227"
|
||||
|
||||
#define DRIVER_MAJOR 2
|
||||
#define DRIVER_MINOR 11
|
||||
#define DRIVER_PATCHLEVEL 0
|
||||
|
||||
#include "via_verifier.h"
|
||||
|
||||
#include "via_dmablit.h"
|
||||
|
||||
#define VIA_PCI_BUF_SIZE 60000
|
||||
#define VIA_FIRE_BUF_SIZE 1024
|
||||
#define VIA_NUM_IRQS 4
|
||||
|
||||
typedef struct drm_via_ring_buffer {
|
||||
drm_local_map_t map;
|
||||
char *virtual_start;
|
||||
} drm_via_ring_buffer_t;
|
||||
|
||||
typedef uint32_t maskarray_t[5];
|
||||
|
||||
typedef struct drm_via_irq {
|
||||
atomic_t irq_received;
|
||||
uint32_t pending_mask;
|
||||
uint32_t enable_mask;
|
||||
wait_queue_head_t irq_queue;
|
||||
} drm_via_irq_t;
|
||||
|
||||
typedef struct drm_via_private {
|
||||
drm_via_sarea_t *sarea_priv;
|
||||
drm_local_map_t *sarea;
|
||||
drm_local_map_t *fb;
|
||||
drm_local_map_t *mmio;
|
||||
unsigned long agpAddr;
|
||||
wait_queue_head_t decoder_queue[VIA_NR_XVMC_LOCKS];
|
||||
char *dma_ptr;
|
||||
unsigned int dma_low;
|
||||
unsigned int dma_high;
|
||||
unsigned int dma_offset;
|
||||
uint32_t dma_wrap;
|
||||
volatile uint32_t *last_pause_ptr;
|
||||
volatile uint32_t *hw_addr_ptr;
|
||||
drm_via_ring_buffer_t ring;
|
||||
struct timeval last_vblank;
|
||||
int last_vblank_valid;
|
||||
unsigned usec_per_vblank;
|
||||
drm_via_state_t hc_state;
|
||||
char pci_buf[VIA_PCI_BUF_SIZE];
|
||||
const uint32_t *fire_offsets[VIA_FIRE_BUF_SIZE];
|
||||
uint32_t num_fire_offsets;
|
||||
int chipset;
|
||||
drm_via_irq_t via_irqs[VIA_NUM_IRQS];
|
||||
unsigned num_irqs;
|
||||
maskarray_t *irq_masks;
|
||||
uint32_t irq_enable_mask;
|
||||
uint32_t irq_pending_mask;
|
||||
int *irq_map;
|
||||
unsigned int idle_fault;
|
||||
drm_sman_t sman;
|
||||
int vram_initialized;
|
||||
int agp_initialized;
|
||||
unsigned long vram_offset;
|
||||
unsigned long agp_offset;
|
||||
drm_via_blitq_t blit_queues[VIA_NUM_BLIT_ENGINES];
|
||||
} drm_via_private_t;
|
||||
|
||||
enum via_family {
|
||||
VIA_OTHER = 0, /* Baseline */
|
||||
VIA_PRO_GROUP_A, /* Another video engine and DMA commands */
|
||||
VIA_DX9_0 /* Same video as pro_group_a, but 3D is unsupported */
|
||||
};
|
||||
|
||||
/* VIA MMIO register access */
|
||||
#define VIA_BASE ((dev_priv->mmio))
|
||||
|
||||
#define VIA_READ(reg) DRM_READ32(VIA_BASE, reg)
|
||||
#define VIA_WRITE(reg,val) DRM_WRITE32(VIA_BASE, reg, val)
|
||||
#define VIA_READ8(reg) DRM_READ8(VIA_BASE, reg)
|
||||
#define VIA_WRITE8(reg,val) DRM_WRITE8(VIA_BASE, reg, val)
|
||||
|
||||
extern drm_ioctl_desc_t via_ioctls[];
|
||||
extern int via_max_ioctl;
|
||||
|
||||
extern int via_fb_init(DRM_IOCTL_ARGS);
|
||||
extern int via_mem_alloc(DRM_IOCTL_ARGS);
|
||||
extern int via_mem_free(DRM_IOCTL_ARGS);
|
||||
extern int via_agp_init(DRM_IOCTL_ARGS);
|
||||
extern int via_map_init(DRM_IOCTL_ARGS);
|
||||
extern int via_decoder_futex(DRM_IOCTL_ARGS);
|
||||
extern int via_wait_irq(DRM_IOCTL_ARGS);
|
||||
extern int via_dma_blit_sync( DRM_IOCTL_ARGS );
|
||||
extern int via_dma_blit( DRM_IOCTL_ARGS );
|
||||
|
||||
extern int via_driver_load(drm_device_t *dev, unsigned long chipset);
|
||||
extern int via_driver_unload(drm_device_t *dev);
|
||||
|
||||
extern int via_init_context(drm_device_t * dev, int context);
|
||||
extern int via_final_context(drm_device_t * dev, int context);
|
||||
|
||||
extern int via_do_cleanup_map(drm_device_t * dev);
|
||||
extern int via_driver_vblank_wait(drm_device_t * dev, unsigned int *sequence);
|
||||
|
||||
extern irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS);
|
||||
extern void via_driver_irq_preinstall(drm_device_t * dev);
|
||||
extern void via_driver_irq_postinstall(drm_device_t * dev);
|
||||
extern void via_driver_irq_uninstall(drm_device_t * dev);
|
||||
|
||||
extern int via_dma_cleanup(drm_device_t * dev);
|
||||
extern void via_init_command_verifier(void);
|
||||
extern int via_driver_dma_quiescent(drm_device_t * dev);
|
||||
extern void via_init_futex(drm_via_private_t * dev_priv);
|
||||
extern void via_cleanup_futex(drm_via_private_t * dev_priv);
|
||||
extern void via_release_futex(drm_via_private_t * dev_priv, int context);
|
||||
|
||||
extern void via_reclaim_buffers_locked(drm_device_t *dev, struct file *filp);
|
||||
extern void via_lastclose(drm_device_t *dev);
|
||||
|
||||
extern void via_dmablit_handler(drm_device_t *dev, int engine, int from_irq);
|
||||
extern void via_init_dmablit(drm_device_t *dev);
|
||||
|
||||
#endif
|
||||
384
drivers/char/drm/via_irq.c
Normal file
384
drivers/char/drm/via_irq.c
Normal file
@@ -0,0 +1,384 @@
|
||||
/* via_irq.c
|
||||
*
|
||||
* Copyright 2004 BEAM Ltd.
|
||||
* Copyright 2002 Tungsten Graphics, Inc.
|
||||
* Copyright 2005 Thomas Hellstrom.
|
||||
* 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
|
||||
* BEAM LTD, TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors:
|
||||
* Terry Barnaby <terry1@beam.ltd.uk>
|
||||
* Keith Whitwell <keith@tungstengraphics.com>
|
||||
* Thomas Hellstrom <unichrome@shipmail.org>
|
||||
*
|
||||
* This code provides standard DRM access to the Via Unichrome / Pro Vertical blank
|
||||
* interrupt, as well as an infrastructure to handle other interrupts of the chip.
|
||||
* The refresh rate is also calculated for video playback sync purposes.
|
||||
*/
|
||||
|
||||
#include "drmP.h"
|
||||
#include "drm.h"
|
||||
#include "via_drm.h"
|
||||
#include "via_drv.h"
|
||||
|
||||
#define VIA_REG_INTERRUPT 0x200
|
||||
|
||||
/* VIA_REG_INTERRUPT */
|
||||
#define VIA_IRQ_GLOBAL (1 << 31)
|
||||
#define VIA_IRQ_VBLANK_ENABLE (1 << 19)
|
||||
#define VIA_IRQ_VBLANK_PENDING (1 << 3)
|
||||
#define VIA_IRQ_HQV0_ENABLE (1 << 11)
|
||||
#define VIA_IRQ_HQV1_ENABLE (1 << 25)
|
||||
#define VIA_IRQ_HQV0_PENDING (1 << 9)
|
||||
#define VIA_IRQ_HQV1_PENDING (1 << 10)
|
||||
#define VIA_IRQ_DMA0_DD_ENABLE (1 << 20)
|
||||
#define VIA_IRQ_DMA0_TD_ENABLE (1 << 21)
|
||||
#define VIA_IRQ_DMA1_DD_ENABLE (1 << 22)
|
||||
#define VIA_IRQ_DMA1_TD_ENABLE (1 << 23)
|
||||
#define VIA_IRQ_DMA0_DD_PENDING (1 << 4)
|
||||
#define VIA_IRQ_DMA0_TD_PENDING (1 << 5)
|
||||
#define VIA_IRQ_DMA1_DD_PENDING (1 << 6)
|
||||
#define VIA_IRQ_DMA1_TD_PENDING (1 << 7)
|
||||
|
||||
|
||||
/*
|
||||
* Device-specific IRQs go here. This type might need to be extended with
|
||||
* the register if there are multiple IRQ control registers.
|
||||
* Currently we activate the HQV interrupts of Unichrome Pro group A.
|
||||
*/
|
||||
|
||||
static maskarray_t via_pro_group_a_irqs[] = {
|
||||
{VIA_IRQ_HQV0_ENABLE, VIA_IRQ_HQV0_PENDING, 0x000003D0, 0x00008010,
|
||||
0x00000000},
|
||||
{VIA_IRQ_HQV1_ENABLE, VIA_IRQ_HQV1_PENDING, 0x000013D0, 0x00008010,
|
||||
0x00000000},
|
||||
{VIA_IRQ_DMA0_TD_ENABLE, VIA_IRQ_DMA0_TD_PENDING, VIA_PCI_DMA_CSR0,
|
||||
VIA_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008},
|
||||
{VIA_IRQ_DMA1_TD_ENABLE, VIA_IRQ_DMA1_TD_PENDING, VIA_PCI_DMA_CSR1,
|
||||
VIA_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008},
|
||||
};
|
||||
static int via_num_pro_group_a =
|
||||
sizeof(via_pro_group_a_irqs) / sizeof(maskarray_t);
|
||||
static int via_irqmap_pro_group_a[] = {0, 1, -1, 2, -1, 3};
|
||||
|
||||
static maskarray_t via_unichrome_irqs[] = {
|
||||
{VIA_IRQ_DMA0_TD_ENABLE, VIA_IRQ_DMA0_TD_PENDING, VIA_PCI_DMA_CSR0,
|
||||
VIA_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008},
|
||||
{VIA_IRQ_DMA1_TD_ENABLE, VIA_IRQ_DMA1_TD_PENDING, VIA_PCI_DMA_CSR1,
|
||||
VIA_DMA_CSR_TA | VIA_DMA_CSR_TD, 0x00000008}
|
||||
};
|
||||
static int via_num_unichrome = sizeof(via_unichrome_irqs) / sizeof(maskarray_t);
|
||||
static int via_irqmap_unichrome[] = {-1, -1, -1, 0, -1, 1};
|
||||
|
||||
static unsigned time_diff(struct timeval *now, struct timeval *then)
|
||||
{
|
||||
return (now->tv_usec >= then->tv_usec) ?
|
||||
now->tv_usec - then->tv_usec :
|
||||
1000000 - (then->tv_usec - now->tv_usec);
|
||||
}
|
||||
|
||||
irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS)
|
||||
{
|
||||
drm_device_t *dev = (drm_device_t *) arg;
|
||||
drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
|
||||
u32 status;
|
||||
int handled = 0;
|
||||
struct timeval cur_vblank;
|
||||
drm_via_irq_t *cur_irq = dev_priv->via_irqs;
|
||||
int i;
|
||||
|
||||
status = VIA_READ(VIA_REG_INTERRUPT);
|
||||
if (status & VIA_IRQ_VBLANK_PENDING) {
|
||||
atomic_inc(&dev->vbl_received);
|
||||
if (!(atomic_read(&dev->vbl_received) & 0x0F)) {
|
||||
do_gettimeofday(&cur_vblank);
|
||||
if (dev_priv->last_vblank_valid) {
|
||||
dev_priv->usec_per_vblank =
|
||||
time_diff(&cur_vblank,
|
||||
&dev_priv->last_vblank) >> 4;
|
||||
}
|
||||
dev_priv->last_vblank = cur_vblank;
|
||||
dev_priv->last_vblank_valid = 1;
|
||||
}
|
||||
if (!(atomic_read(&dev->vbl_received) & 0xFF)) {
|
||||
DRM_DEBUG("US per vblank is: %u\n",
|
||||
dev_priv->usec_per_vblank);
|
||||
}
|
||||
DRM_WAKEUP(&dev->vbl_queue);
|
||||
drm_vbl_send_signals(dev);
|
||||
handled = 1;
|
||||
}
|
||||
|
||||
for (i = 0; i < dev_priv->num_irqs; ++i) {
|
||||
if (status & cur_irq->pending_mask) {
|
||||
atomic_inc(&cur_irq->irq_received);
|
||||
DRM_WAKEUP(&cur_irq->irq_queue);
|
||||
handled = 1;
|
||||
if (dev_priv->irq_map[drm_via_irq_dma0_td] == i) {
|
||||
via_dmablit_handler(dev, 0, 1);
|
||||
} else if (dev_priv->irq_map[drm_via_irq_dma1_td] == i) {
|
||||
via_dmablit_handler(dev, 1, 1);
|
||||
}
|
||||
}
|
||||
cur_irq++;
|
||||
}
|
||||
|
||||
/* Acknowlege interrupts */
|
||||
VIA_WRITE(VIA_REG_INTERRUPT, status);
|
||||
|
||||
if (handled)
|
||||
return IRQ_HANDLED;
|
||||
else
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
static __inline__ void viadrv_acknowledge_irqs(drm_via_private_t * dev_priv)
|
||||
{
|
||||
u32 status;
|
||||
|
||||
if (dev_priv) {
|
||||
/* Acknowlege interrupts */
|
||||
status = VIA_READ(VIA_REG_INTERRUPT);
|
||||
VIA_WRITE(VIA_REG_INTERRUPT, status |
|
||||
dev_priv->irq_pending_mask);
|
||||
}
|
||||
}
|
||||
|
||||
int via_driver_vblank_wait(drm_device_t * dev, unsigned int *sequence)
|
||||
{
|
||||
drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
|
||||
unsigned int cur_vblank;
|
||||
int ret = 0;
|
||||
|
||||
DRM_DEBUG("viadrv_vblank_wait\n");
|
||||
if (!dev_priv) {
|
||||
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
viadrv_acknowledge_irqs(dev_priv);
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
static int
|
||||
via_driver_irq_wait(drm_device_t * dev, unsigned int irq, int force_sequence,
|
||||
unsigned int *sequence)
|
||||
{
|
||||
drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
|
||||
unsigned int cur_irq_sequence;
|
||||
drm_via_irq_t *cur_irq;
|
||||
int ret = 0;
|
||||
maskarray_t *masks;
|
||||
int real_irq;
|
||||
|
||||
DRM_DEBUG("%s\n", __FUNCTION__);
|
||||
|
||||
if (!dev_priv) {
|
||||
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
|
||||
return DRM_ERR(EINVAL);
|
||||
}
|
||||
|
||||
if (irq >= drm_via_irq_num) {
|
||||
DRM_ERROR("%s Trying to wait on unknown irq %d\n", __FUNCTION__,
|
||||
irq);
|
||||
return DRM_ERR(EINVAL);
|
||||
}
|
||||
|
||||
real_irq = dev_priv->irq_map[irq];
|
||||
|
||||
if (real_irq < 0) {
|
||||
DRM_ERROR("%s Video IRQ %d not available on this hardware.\n",
|
||||
__FUNCTION__, irq);
|
||||
return DRM_ERR(EINVAL);
|
||||
}
|
||||
|
||||
masks = dev_priv->irq_masks;
|
||||
cur_irq = dev_priv->via_irqs + real_irq;
|
||||
|
||||
if (masks[real_irq][2] && !force_sequence) {
|
||||
DRM_WAIT_ON(ret, cur_irq->irq_queue, 3 * DRM_HZ,
|
||||
((VIA_READ(masks[irq][2]) & masks[irq][3]) ==
|
||||
masks[irq][4]));
|
||||
cur_irq_sequence = atomic_read(&cur_irq->irq_received);
|
||||
} else {
|
||||
DRM_WAIT_ON(ret, cur_irq->irq_queue, 3 * DRM_HZ,
|
||||
(((cur_irq_sequence =
|
||||
atomic_read(&cur_irq->irq_received)) -
|
||||
*sequence) <= (1 << 23)));
|
||||
}
|
||||
*sequence = cur_irq_sequence;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* drm_dma.h hooks
|
||||
*/
|
||||
|
||||
void via_driver_irq_preinstall(drm_device_t * dev)
|
||||
{
|
||||
drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
|
||||
u32 status;
|
||||
drm_via_irq_t *cur_irq;
|
||||
int i;
|
||||
|
||||
DRM_DEBUG("driver_irq_preinstall: dev_priv: %p\n", dev_priv);
|
||||
if (dev_priv) {
|
||||
cur_irq = dev_priv->via_irqs;
|
||||
|
||||
dev_priv->irq_enable_mask = VIA_IRQ_VBLANK_ENABLE;
|
||||
dev_priv->irq_pending_mask = VIA_IRQ_VBLANK_PENDING;
|
||||
|
||||
if (dev_priv->chipset == VIA_PRO_GROUP_A ||
|
||||
dev_priv->chipset == VIA_DX9_0) {
|
||||
dev_priv->irq_masks = via_pro_group_a_irqs;
|
||||
dev_priv->num_irqs = via_num_pro_group_a;
|
||||
dev_priv->irq_map = via_irqmap_pro_group_a;
|
||||
} else {
|
||||
dev_priv->irq_masks = via_unichrome_irqs;
|
||||
dev_priv->num_irqs = via_num_unichrome;
|
||||
dev_priv->irq_map = via_irqmap_unichrome;
|
||||
}
|
||||
|
||||
for (i = 0; i < dev_priv->num_irqs; ++i) {
|
||||
atomic_set(&cur_irq->irq_received, 0);
|
||||
cur_irq->enable_mask = dev_priv->irq_masks[i][0];
|
||||
cur_irq->pending_mask = dev_priv->irq_masks[i][1];
|
||||
DRM_INIT_WAITQUEUE(&cur_irq->irq_queue);
|
||||
dev_priv->irq_enable_mask |= cur_irq->enable_mask;
|
||||
dev_priv->irq_pending_mask |= cur_irq->pending_mask;
|
||||
cur_irq++;
|
||||
|
||||
DRM_DEBUG("Initializing IRQ %d\n", i);
|
||||
}
|
||||
|
||||
dev_priv->last_vblank_valid = 0;
|
||||
|
||||
/* Clear VSync interrupt regs */
|
||||
status = VIA_READ(VIA_REG_INTERRUPT);
|
||||
VIA_WRITE(VIA_REG_INTERRUPT, status &
|
||||
~(dev_priv->irq_enable_mask));
|
||||
|
||||
/* Clear bits if they're already high */
|
||||
viadrv_acknowledge_irqs(dev_priv);
|
||||
}
|
||||
}
|
||||
|
||||
void via_driver_irq_postinstall(drm_device_t * dev)
|
||||
{
|
||||
drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
|
||||
u32 status;
|
||||
|
||||
DRM_DEBUG("via_driver_irq_postinstall\n");
|
||||
if (dev_priv) {
|
||||
status = VIA_READ(VIA_REG_INTERRUPT);
|
||||
VIA_WRITE(VIA_REG_INTERRUPT, status | VIA_IRQ_GLOBAL
|
||||
| dev_priv->irq_enable_mask);
|
||||
|
||||
/* Some magic, oh for some data sheets ! */
|
||||
|
||||
VIA_WRITE8(0x83d4, 0x11);
|
||||
VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) | 0x30);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void via_driver_irq_uninstall(drm_device_t * dev)
|
||||
{
|
||||
drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
|
||||
u32 status;
|
||||
|
||||
DRM_DEBUG("driver_irq_uninstall)\n");
|
||||
if (dev_priv) {
|
||||
|
||||
/* Some more magic, oh for some data sheets ! */
|
||||
|
||||
VIA_WRITE8(0x83d4, 0x11);
|
||||
VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) & ~0x30);
|
||||
|
||||
status = VIA_READ(VIA_REG_INTERRUPT);
|
||||
VIA_WRITE(VIA_REG_INTERRUPT, status &
|
||||
~(VIA_IRQ_VBLANK_ENABLE | dev_priv->irq_enable_mask));
|
||||
}
|
||||
}
|
||||
|
||||
int via_wait_irq(DRM_IOCTL_ARGS)
|
||||
{
|
||||
DRM_DEVICE;
|
||||
drm_via_irqwait_t __user *argp = (void __user *)data;
|
||||
drm_via_irqwait_t irqwait;
|
||||
struct timeval now;
|
||||
int ret = 0;
|
||||
drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
|
||||
drm_via_irq_t *cur_irq = dev_priv->via_irqs;
|
||||
int force_sequence;
|
||||
|
||||
if (!dev->irq)
|
||||
return DRM_ERR(EINVAL);
|
||||
|
||||
DRM_COPY_FROM_USER_IOCTL(irqwait, argp, sizeof(irqwait));
|
||||
if (irqwait.request.irq >= dev_priv->num_irqs) {
|
||||
DRM_ERROR("%s Trying to wait on unknown irq %d\n", __FUNCTION__,
|
||||
irqwait.request.irq);
|
||||
return DRM_ERR(EINVAL);
|
||||
}
|
||||
|
||||
cur_irq += irqwait.request.irq;
|
||||
|
||||
switch (irqwait.request.type & ~VIA_IRQ_FLAGS_MASK) {
|
||||
case VIA_IRQ_RELATIVE:
|
||||
irqwait.request.sequence += atomic_read(&cur_irq->irq_received);
|
||||
irqwait.request.type &= ~_DRM_VBLANK_RELATIVE;
|
||||
case VIA_IRQ_ABSOLUTE:
|
||||
break;
|
||||
default:
|
||||
return DRM_ERR(EINVAL);
|
||||
}
|
||||
|
||||
if (irqwait.request.type & VIA_IRQ_SIGNAL) {
|
||||
DRM_ERROR("%s Signals on Via IRQs not implemented yet.\n",
|
||||
__FUNCTION__);
|
||||
return DRM_ERR(EINVAL);
|
||||
}
|
||||
|
||||
force_sequence = (irqwait.request.type & VIA_IRQ_FORCE_SEQUENCE);
|
||||
|
||||
ret = via_driver_irq_wait(dev, irqwait.request.irq, force_sequence,
|
||||
&irqwait.request.sequence);
|
||||
do_gettimeofday(&now);
|
||||
irqwait.reply.tval_sec = now.tv_sec;
|
||||
irqwait.reply.tval_usec = now.tv_usec;
|
||||
|
||||
DRM_COPY_TO_USER_IOCTL(argp, irqwait, sizeof(irqwait));
|
||||
|
||||
return ret;
|
||||
}
|
||||
128
drivers/char/drm/via_map.c
Normal file
128
drivers/char/drm/via_map.c
Normal file
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
|
||||
* Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sub license,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the
|
||||
* next paragraph) shall be included in all copies or substantial portions
|
||||
* of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
|
||||
* VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "drmP.h"
|
||||
#include "via_drm.h"
|
||||
#include "via_drv.h"
|
||||
|
||||
static int via_do_init_map(drm_device_t * dev, drm_via_init_t * init)
|
||||
{
|
||||
drm_via_private_t *dev_priv = dev->dev_private;
|
||||
|
||||
DRM_DEBUG("%s\n", __FUNCTION__);
|
||||
|
||||
DRM_GETSAREA();
|
||||
if (!dev_priv->sarea) {
|
||||
DRM_ERROR("could not find sarea!\n");
|
||||
dev->dev_private = (void *)dev_priv;
|
||||
via_do_cleanup_map(dev);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dev_priv->fb = drm_core_findmap(dev, init->fb_offset);
|
||||
if (!dev_priv->fb) {
|
||||
DRM_ERROR("could not find framebuffer!\n");
|
||||
dev->dev_private = (void *)dev_priv;
|
||||
via_do_cleanup_map(dev);
|
||||
return -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;
|
||||
via_do_cleanup_map(dev);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dev_priv->sarea_priv =
|
||||
(drm_via_sarea_t *) ((u8 *) dev_priv->sarea->handle +
|
||||
init->sarea_priv_offset);
|
||||
|
||||
dev_priv->agpAddr = init->agpAddr;
|
||||
|
||||
via_init_futex(dev_priv);
|
||||
|
||||
via_init_dmablit(dev);
|
||||
|
||||
dev->dev_private = (void *)dev_priv;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int via_do_cleanup_map(drm_device_t * dev)
|
||||
{
|
||||
via_dma_cleanup(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int via_map_init(DRM_IOCTL_ARGS)
|
||||
{
|
||||
DRM_DEVICE;
|
||||
drm_via_init_t init;
|
||||
|
||||
DRM_DEBUG("%s\n", __FUNCTION__);
|
||||
|
||||
DRM_COPY_FROM_USER_IOCTL(init, (drm_via_init_t __user *) data,
|
||||
sizeof(init));
|
||||
|
||||
switch (init.func) {
|
||||
case VIA_INIT_MAP:
|
||||
return via_do_init_map(dev, &init);
|
||||
case VIA_CLEANUP_MAP:
|
||||
return via_do_cleanup_map(dev);
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int via_driver_load(drm_device_t *dev, unsigned long chipset)
|
||||
{
|
||||
drm_via_private_t *dev_priv;
|
||||
int ret = 0;
|
||||
|
||||
dev_priv = drm_calloc(1, sizeof(drm_via_private_t), DRM_MEM_DRIVER);
|
||||
if (dev_priv == NULL)
|
||||
return DRM_ERR(ENOMEM);
|
||||
|
||||
dev->dev_private = (void *)dev_priv;
|
||||
|
||||
dev_priv->chipset = chipset;
|
||||
|
||||
ret = drm_sman_init(&dev_priv->sman, 2, 12, 8);
|
||||
if (ret) {
|
||||
drm_free(dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int via_driver_unload(drm_device_t *dev)
|
||||
{
|
||||
drm_via_private_t *dev_priv = dev->dev_private;
|
||||
|
||||
drm_sman_takedown(&dev_priv->sman);
|
||||
|
||||
drm_free(dev_priv, sizeof(drm_via_private_t), DRM_MEM_DRIVER);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
209
drivers/char/drm/via_mm.c
Normal file
209
drivers/char/drm/via_mm.c
Normal file
@@ -0,0 +1,209 @@
|
||||
/*
|
||||
* Copyright 2006 Tungsten Graphics Inc., Bismarck, ND., USA.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sub license,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the
|
||||
* next paragraph) shall be included in all copies or substantial portions
|
||||
* of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
/*
|
||||
* Authors: Thomas Hellström <thomas-at-tungstengraphics-dot-com>
|
||||
*/
|
||||
|
||||
#include "drmP.h"
|
||||
#include "via_drm.h"
|
||||
#include "via_drv.h"
|
||||
#include "drm_sman.h"
|
||||
|
||||
#define VIA_MM_ALIGN_SHIFT 4
|
||||
#define VIA_MM_ALIGN_MASK ( (1 << VIA_MM_ALIGN_SHIFT) - 1)
|
||||
|
||||
int via_agp_init(DRM_IOCTL_ARGS)
|
||||
{
|
||||
DRM_DEVICE;
|
||||
drm_via_agp_t agp;
|
||||
drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
|
||||
int ret;
|
||||
|
||||
DRM_COPY_FROM_USER_IOCTL(agp, (drm_via_agp_t __user *) data,
|
||||
sizeof(agp));
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
ret = drm_sman_set_range(&dev_priv->sman, VIA_MEM_AGP, 0,
|
||||
agp.size >> VIA_MM_ALIGN_SHIFT);
|
||||
|
||||
if (ret) {
|
||||
DRM_ERROR("AGP memory manager initialisation error\n");
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
dev_priv->agp_initialized = 1;
|
||||
dev_priv->agp_offset = agp.offset;
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
DRM_DEBUG("offset = %u, size = %u", agp.offset, agp.size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int via_fb_init(DRM_IOCTL_ARGS)
|
||||
{
|
||||
DRM_DEVICE;
|
||||
drm_via_fb_t fb;
|
||||
drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
|
||||
int ret;
|
||||
|
||||
DRM_COPY_FROM_USER_IOCTL(fb, (drm_via_fb_t __user *) data, sizeof(fb));
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
ret = drm_sman_set_range(&dev_priv->sman, VIA_MEM_VIDEO, 0,
|
||||
fb.size >> VIA_MM_ALIGN_SHIFT);
|
||||
|
||||
if (ret) {
|
||||
DRM_ERROR("VRAM memory manager initialisation error\n");
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
dev_priv->vram_initialized = 1;
|
||||
dev_priv->vram_offset = fb.offset;
|
||||
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
DRM_DEBUG("offset = %u, size = %u", fb.offset, fb.size);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int via_final_context(struct drm_device *dev, int context)
|
||||
{
|
||||
drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
|
||||
|
||||
via_release_futex(dev_priv, context);
|
||||
|
||||
/* Linux specific until context tracking code gets ported to BSD */
|
||||
/* Last context, perform cleanup */
|
||||
if (dev->ctx_count == 1 && dev->dev_private) {
|
||||
DRM_DEBUG("Last Context\n");
|
||||
if (dev->irq)
|
||||
drm_irq_uninstall(dev);
|
||||
via_cleanup_futex(dev_priv);
|
||||
via_do_cleanup_map(dev);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void via_lastclose(struct drm_device *dev)
|
||||
{
|
||||
drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
|
||||
|
||||
if (!dev_priv)
|
||||
return;
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
drm_sman_cleanup(&dev_priv->sman);
|
||||
dev_priv->vram_initialized = 0;
|
||||
dev_priv->agp_initialized = 0;
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
}
|
||||
|
||||
int via_mem_alloc(DRM_IOCTL_ARGS)
|
||||
{
|
||||
DRM_DEVICE;
|
||||
|
||||
drm_via_mem_t mem;
|
||||
int retval = 0;
|
||||
drm_memblock_item_t *item;
|
||||
drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
|
||||
unsigned long tmpSize;
|
||||
|
||||
DRM_COPY_FROM_USER_IOCTL(mem, (drm_via_mem_t __user *) data,
|
||||
sizeof(mem));
|
||||
|
||||
if (mem.type > VIA_MEM_AGP) {
|
||||
DRM_ERROR("Unknown memory type allocation\n");
|
||||
return DRM_ERR(EINVAL);
|
||||
}
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
if (0 == ((mem.type == VIA_MEM_VIDEO) ? dev_priv->vram_initialized :
|
||||
dev_priv->agp_initialized)) {
|
||||
DRM_ERROR
|
||||
("Attempt to allocate from uninitialized memory manager.\n");
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return DRM_ERR(EINVAL);
|
||||
}
|
||||
|
||||
tmpSize = (mem.size + VIA_MM_ALIGN_MASK) >> VIA_MM_ALIGN_SHIFT;
|
||||
item = drm_sman_alloc(&dev_priv->sman, mem.type, tmpSize, 0,
|
||||
(unsigned long)priv);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
if (item) {
|
||||
mem.offset = ((mem.type == VIA_MEM_VIDEO) ?
|
||||
dev_priv->vram_offset : dev_priv->agp_offset) +
|
||||
(item->mm->
|
||||
offset(item->mm, item->mm_info) << VIA_MM_ALIGN_SHIFT);
|
||||
mem.index = item->user_hash.key;
|
||||
} else {
|
||||
mem.offset = 0;
|
||||
mem.size = 0;
|
||||
mem.index = 0;
|
||||
DRM_DEBUG("Video memory allocation failed\n");
|
||||
retval = DRM_ERR(ENOMEM);
|
||||
}
|
||||
DRM_COPY_TO_USER_IOCTL((drm_via_mem_t __user *) data, mem, sizeof(mem));
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
int via_mem_free(DRM_IOCTL_ARGS)
|
||||
{
|
||||
DRM_DEVICE;
|
||||
drm_via_private_t *dev_priv = dev->dev_private;
|
||||
drm_via_mem_t mem;
|
||||
int ret;
|
||||
|
||||
DRM_COPY_FROM_USER_IOCTL(mem, (drm_via_mem_t __user *) data,
|
||||
sizeof(mem));
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
ret = drm_sman_free_key(&dev_priv->sman, mem.index);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
DRM_DEBUG("free = 0x%lx\n", mem.index);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void via_reclaim_buffers_locked(drm_device_t * dev, struct file *filp)
|
||||
{
|
||||
drm_via_private_t *dev_priv = dev->dev_private;
|
||||
drm_file_t *priv = filp->private_data;
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
if (drm_sman_owner_clean(&dev_priv->sman, (unsigned long)priv)) {
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
if (dev->driver->dma_quiescent) {
|
||||
dev->driver->dma_quiescent(dev);
|
||||
}
|
||||
|
||||
drm_sman_owner_cleanup(&dev_priv->sman, (unsigned long)priv);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return;
|
||||
}
|
||||
40
drivers/char/drm/via_mm.h
Normal file
40
drivers/char/drm/via_mm.h
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
|
||||
* Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sub license,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the
|
||||
* next paragraph) shall be included in all copies or substantial portions
|
||||
* of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
|
||||
* VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef _via_drm_mm_h_
|
||||
#define _via_drm_mm_h_
|
||||
|
||||
typedef struct {
|
||||
unsigned int context;
|
||||
unsigned int size;
|
||||
unsigned long offset;
|
||||
unsigned long free;
|
||||
} drm_via_mm_t;
|
||||
|
||||
typedef struct {
|
||||
unsigned int size;
|
||||
unsigned long handle;
|
||||
void *virtual;
|
||||
} drm_via_dma_t;
|
||||
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user