/* BEGIN CSTYLED */
/* i915_dma.c -- DMA support for the I915 -*- linux-c -*-
*/
/*
* Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
* Copyright (c) 2009, Intel Corporation.
* 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 add 0x%lx read GEM HWS 0x%x\n",dev_priv->hw_status_page, READ_HWSP(dev_priv, 0x20));
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;
}
}
}
{
}
{
/* 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);
}
#ifdef I915_HAVE_GEM
if (I915_NEED_GFX_HWS(dev))
#endif
return 0;
}
{
DRM_GETSAREA();
DRM_ERROR("can not find sarea!\n");
(void) i915_dma_cleanup(dev);
return (EINVAL);
}
(void) i915_dma_cleanup(dev);
DRM_ERROR("Client tried to initialize ringbuffer in "
"GEM mode\n");
return -EINVAL;
}
(void) i915_dma_cleanup(dev);
DRM_ERROR("can not ioremap virtual address for"
" ring buffer\n");
return (ENOMEM);
}
}
dev_priv->current_page = 0;
/* Allow hardware batchbuffers unless told otherwise.
*/
return 0;
}
{
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*/
{
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.
*/
{
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
}
{
/* printk("validate_cmd( %x ): %d\n", cmd, ret); */
return ret;
}
{
int i;
DRM_ERROR(" emit cmds invalid arg");
return (EINVAL);
}
for (i = 0; i < dwords;) {
DRM_ERROR("emit cmds failed to get cmd from user");
return (EINVAL);
}
DRM_ERROR("emit cmds invalid");
return (EINVAL);
}
while (++i, --sz) {
sizeof(cmd))) {
DRM_ERROR("emit cmds failed get cmds");
return (EINVAL);
}
}
}
if (dwords & 1)
OUT_RING(0);
return 0;
}
{
DRM_ERROR("emit box failed to copy from user");
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:
*/
{
if (dev_priv->sarea_priv)
BEGIN_LP_RING(4);
OUT_RING(0);
}
{
DRM_ERROR("alignment");
return (EINVAL);
}
for (i = 0; i < count; i++) {
if (i < nbox) {
if (ret)
return ret;
}
if (ret)
return ret;
}
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;
}
{
if (!dev_priv->sarea_priv)
return -EINVAL;
DRM_DEBUG("planes=0x%x pfCurrentPage=%d\n",
BEGIN_LP_RING(2);
OUT_RING(0);
BEGIN_LP_RING(6);
OUT_RING(0);
if (dev_priv->current_page == 0) {
} else {
dev_priv->current_page = 0;
}
OUT_RING(0);
BEGIN_LP_RING(2);
OUT_RING(0);
BEGIN_LP_RING(4);
OUT_RING(0);
return 0;
}
{
int ret;
if (ret)
{
DRM_ERROR ("not quiescent head %08x tail %08x space %08x\n",
}
return ret;
}
/*ARGSUSED*/
{
int ret;
return ret;
}
/*ARGSUSED*/
{
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*/
{
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;
}
/*ARGSUSED*/
{
int ret;
sizeof(param));
DRM_DEBUG("i915_flip_bufs\n");
return ret;
}
/*ARGSUSED*/
{
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;
case I915_PARAM_HAS_GEM:
break;
default:
return (EINVAL);
}
DRM_ERROR("i915_getparam failed\n");
return (EFAULT);
}
return 0;
}
/*ARGSUSED*/
{
if (!dev_priv) {
return (EINVAL);
}
sizeof(param));
break;
break;
break;
default:
return (EINVAL);
}
return 0;
}
/*ARGSUSED*/
{
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*/
{
/* i915 has 4 more counters */
return ENOMEM;
DRM_DEBUG("i915_driverload mmio %p mmio_map->dev_addr %x", dev_priv->mmio_map, dev_priv->mmio_map->dev_addr);
#if defined(__i386)
#else
} else {
}
#endif /* __i386 */
#if defined(__i386)
#else
#endif
{
}
#ifdef I915_HAVE_GEM
#endif
if (!I915_NEED_GFX_HWS(dev)) {
if(ret)
return ret;
}
if (ret) {
(void) i915_driver_unload(dev);
return ret;
}
return ret;
}
{
return 0;
}
/*ARGSUSED*/
{
DRM_DEBUG("\n");
i915_file_priv = (struct drm_i915_file_private *)
if (!i915_file_priv)
return -ENOMEM;
return 0;
}
{
/* agp off can use this to get called before dev_priv */
if (!dev_priv)
return;
#ifdef I915_HAVE_GEM
#endif
DRM_GETSAREA();
(void) i915_dma_cleanup(dev);
}
{
}
/*ARGSUSED*/
{
}
#ifdef I915_HAVE_GEM
{i915_gem_create_ioctl, 0},
{i915_gem_pread_ioctl, 0},
{i915_gem_pwrite_ioctl, 0},
{i915_gem_mmap_ioctl, 0},
{i915_gem_sw_finish_ioctl, 0},
{i915_gem_set_tiling, 0},
{i915_gem_get_tiling, 0},
#endif
};
/**
* 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;
}