i915_dma.c revision d02310705313ee2fcefee164a4b26d1fa85e9d22
/* BEGIN CSTYLED */
/* 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,
* 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.
* 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.
*
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include "drmP.h"
#include "drm.h"
#include "i915_drm.h"
#include "i915_drv.h"
/* 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.
*/
/*ARGSUSED*/
{
int i;
for (i = 0; i < 100000; i++) {
return 0;
i = 0;
if (acthd != last_acthd)
i = 0;
last_acthd = acthd;
DRM_UDELAY(10);
}
return (EBUSY);
}
{
/* Program Hardware Status Page */
if (!dmah) {
DRM_ERROR("Can not allocate hardware status page\n");
return -ENOMEM;
}
DRM_DEBUG("Enabled hardware status page\n");
return 0;
}
{
if (!I915_NEED_GFX_HWS(dev)) {
if (dev_priv->status_page_dmah) {
/* Need to rewrite hardware status page */
}
} else {
if (dev_priv->status_gfx_addr) {
dev_priv->status_gfx_addr = 0;
}
}
}
/**
* Validate the cached ring tail value
*
* If the X server writes to the ring and DRM doesn't
* reload the head and tail pointers, it will end up writing
* data to the wrong place in the ring, causing havoc.
*/
{
DRM_ERROR("%s:%d head sw %x, hw %x. tail sw %x hw %x\n",
}
}
#endif
{
}
{
/* 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)
(void) drm_irq_uninstall(dev);
}
return 0;
}
{
DRM_GETSAREA();
DRM_ERROR("can not find sarea!\n");
(void) i915_dma_cleanup(dev);
return (EINVAL);
}
/*
* mmio_map will be destoried after DMA clean up. We should not
* access mmio_map in suspend or resume process.
*/
(void) i915_dma_cleanup(dev);
DRM_ERROR("can not find mmio map!\n");
return (EINVAL);
}
if (init->sarea_priv_offset)
else {
/* No sarea_priv for you! */
}
(void) i915_dma_cleanup(dev);
DRM_ERROR("can not ioremap virtual address for"
" ring buffer\n");
return (ENOMEM);
}
}
if (dev_priv->sarea_priv)
/* We are using separate values as placeholders for mechanisms for
* private backbuffer/depthbuffer usage.
*/
/* Allow hardware batchbuffers unless told otherwise.
*/
/* Init HWS */
if (!I915_NEED_GFX_HWS(dev)) {
(void) i915_init_hardware_status(dev);
}
/* Enable vblank on pipe A for older X servers
*/
#ifdef I915_HAVE_BUFFER
#endif
return 0;
}
{
DRM_DEBUG("i915_dma_resume\n");
DRM_ERROR("can not find sarea!\n");
return (EINVAL);
}
DRM_ERROR("can not ioremap virtual address for"
" ring buffer\n");
return (ENOMEM);
}
/* Program Hardware Status Page */
if (!dev_priv->hw_status_page) {
DRM_ERROR("Can not find hardware status page\n");
return (EINVAL);
}
if (!I915_NEED_GFX_HWS(dev))
else
DRM_DEBUG("Enabled hardware status page\n");
return 0;
}
/*ARGSUSED*/
static int i915_dma_init(DRM_IOCTL_ARGS)
{
int retcode = 0;
case I915_INIT_DMA:
break;
case I915_CLEANUP_DMA:
break;
case I915_RESUME_DMA:
break;
default:
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)
{
case 0x0:
case 0x0:
return 1; /* MI_NOOP */
case 0x4:
return 1; /* MI_FLUSH */
default:
return 0; /* disallow everything else */
}
#ifndef __SUNPRO_C
break;
#endif
case 0x1:
return 0; /* reserved */
case 0x2:
case 0x3:
return 1;
case 0x1c:
return 1;
case 0x1d:
case 0x3:
case 0x4:
default:
}
case 0x1e:
else
return 1;
case 0x1f:
if ((cmd & 0xffff) == 0)
return 0; /* unknown length, too hard */
else
else
return 2; /* indirect sequential */
default:
return 0;
}
default:
return 0;
}
#ifndef __SUNPRO_C
return 0;
#endif
}
static int validate_cmd(int cmd)
{
/* printk("validate_cmd( %x ): %d\n", cmd, ret); */
return ret;
}
{
int i;
return (EINVAL);
for (i = 0; i < dwords;) {
return (EINVAL);
return (EINVAL);
while (++i, --sz) {
sizeof(cmd))) {
return (EINVAL);
}
}
}
if (dwords & 1)
OUT_RING(0);
return 0;
}
{
return (EFAULT);
}
DRM_ERROR("Bad box %d,%d..%d,%d\n",
return (EINVAL);
}
BEGIN_LP_RING(4);
} else {
BEGIN_LP_RING(6);
OUT_RING(0);
}
return 0;
}
/* XXX: Emitting the counter should really be moved to part of the IRQ
* emit. For now, do it in both places:
*/
{
DRM_DEBUG("Breadcrumb counter wrapped around\n");
}
if (dev_priv->sarea_priv)
BEGIN_LP_RING(4);
OUT_RING(0);
}
{
BEGIN_LP_RING(4);
OUT_RING(0);
OUT_RING(0);
OUT_RING(0);
}
{
#ifdef I915_HAVE_FENCE
#endif
DRM_ERROR("alignment");
return (EINVAL);
}
for (i = 0; i < count; i++) {
if (i < nbox) {
if (ret)
return ret;
}
if (ret)
return ret;
}
#ifdef I915_HAVE_FENCE
#endif
return 0;
}
{
int i = 0, count;
DRM_ERROR("alignment");
return (EINVAL);
}
for (i = 0; i < count; i++) {
if (i < nbox) {
if (ret)
return ret;
}
BEGIN_LP_RING(4);
OUT_RING(0);
} else {
BEGIN_LP_RING(2);
} else {
}
}
}
return 0;
}
{
/* Calculate display base offset */
switch (next_page) {
default:
case 0:
break;
case 1:
break;
case 2:
break;
}
if (plane == 0) {
} else {
}
BEGIN_LP_RING(4);
}
{
int i;
DRM_DEBUG("planes=0x%x pfCurrentPage=%d\n",
for (i = 0; i < 2; i++)
if (planes & (1 << i))
#ifdef I915_HAVE_FENCE
#endif
}
{
int ret;
if (ret)
{
DRM_ERROR ("not quiescent head %08x tail %08x space %08x\n",
}
return ret;
}
/*ARGSUSED*/
static int i915_flush_ioctl(DRM_IOCTL_ARGS)
{
return i915_quiescent(dev);
}
/*ARGSUSED*/
static int i915_batchbuffer(DRM_IOCTL_ARGS)
{
int ret;
if (!dev_priv->allow_batchbuffer) {
DRM_ERROR("Batchbuffer ioctl disabled\n");
return (EINVAL);
}
(void *) data, sizeof (batchbuffer32_t));
} else
sizeof(batch));
DRM_DEBUG("i915 batchbuffer, start %x used %d cliprects %d, counter %d\n",
/*
if (batch.num_cliprects && DRM_VERIFYAREA_READ(batch.cliprects,
batch.num_cliprects *
sizeof(drm_clip_rect_t)))
return (EFAULT);
*/
return ret;
}
/*ARGSUSED*/
static int i915_cmdbuffer(DRM_IOCTL_ARGS)
{
int ret;
sizeof (drm_i915_cmdbuffer32_t));
} else
sizeof(cmdbuf));
DRM_DEBUG("i915 cmdbuffer, buf %p sz %d cliprects %d\n",
/*
if (cmdbuf.num_cliprects &&
DRM_VERIFYAREA_READ(cmdbuf.cliprects,
cmdbuf.num_cliprects *
sizeof(drm_clip_rect_t))) {
DRM_ERROR("Fault accessing cliprects\n");
return (EFAULT);
}
*/
if (ret) {
DRM_ERROR("i915_dispatch_cmdbuffer failed\n");
return ret;
}
return 0;
}
{
DRM_DEBUG("i915_do_cleanup_pageflip\n");
for (i = 0, planes = 0; i < 2; i++)
planes |= 1 << i;
}
if (planes)
}
/*ARGSUSED*/
static int i915_flip_bufs(DRM_IOCTL_ARGS)
{
sizeof(param));
DRM_DEBUG("i915_flip_bufs\n");
/* This is really planes */
DRM_ERROR("Invalid planes 0x%x, only <= 0x3 is valid\n",
return -EINVAL;
}
return 0;
}
/*ARGSUSED*/
static int i915_getparam(DRM_IOCTL_ARGS)
{
int value;
if (!dev_priv) {
return (EINVAL);
}
sizeof (drm_i915_getparam32_t));
} else
case I915_PARAM_IRQ_ACTIVE:
break;
break;
case I915_PARAM_LAST_DISPATCH:
break;
case I915_PARAM_CHIPSET_ID:
break;
default:
return (EINVAL);
}
DRM_ERROR("i915_getparam failed\n");
return (EFAULT);
}
return 0;
}
/*ARGSUSED*/
static int i915_setparam(DRM_IOCTL_ARGS)
{
if (!dev_priv) {
return (EINVAL);
}
sizeof(param));
break;
break;
break;
default:
return (EINVAL);
}
return 0;
}
/*ARGSUSED*/
static int i915_set_status_page(DRM_IOCTL_ARGS)
{
if (!I915_NEED_GFX_HWS(dev))
return (EINVAL);
if (!dev_priv) {
return (EINVAL);
}
sizeof(hws));
DRM_DEBUG("set status page: i915_set_status_page: mapoffset 0x%llx\n",
(void) i915_dma_cleanup(dev);
dev_priv->status_gfx_addr = 0;
DRM_ERROR("can not ioremap virtual address for"
" G33 hw status page\n");
return (ENOMEM);
}
DRM_DEBUG("load hws 0x2080 with gfx mem 0x%x\n",
return 0;
}
/*ARGSUSED*/
{
struct drm_i915_private *dev_priv;
int ret = 0;
/* i915 has 4 more counters */
return ENOMEM;
return ret;
}
{
return 0;
}
{
/* agp off can use this to get called before dev_priv */
if (!dev_priv)
return;
#ifdef I915_HAVE_BUFFER
}
#endif
DRM_GETSAREA();
if (dev_priv->sarea_priv)
#if defined(I915_HAVE_BUFFER)
}
}
#endif
(void) i915_dma_cleanup(dev);
}
{
if (dev->dev_private) {
}
}
drm_ioctl_desc_t 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.
*/
/*ARGSUSED*/
{
return 1;
}
/*ARGSUSED*/
{
#ifdef I915_HAVE_BUFFER
#endif
return 0;
}