/*
*/
/*
* Copyright (c) 2009, 2013, 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, distribute, sublicense,
* 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.
*
* Authors:
* Eric Anholt <eric@anholt.net>
*
*/
#include "drmP.h"
#include <vm/seg_kmem.h>
/** @file drm_gem.c
*
* This file provides some of the base ioctls and library routines for
* the graphics memory manager implemented by each device driver.
*
* Because various devices have different requirements in terms of
* synchronization and migration strategies, implementing that is left up to
* the driver, and all that the general API provides should be generic --
* the CPU mean we'll likely hook those out to driver-specific calls. However,
*
* The goal was to have swap-backed object allocation managed through
* struct file. However, file descriptors as handles to a struct file have
* two major failings:
* - Process limits prevent more than 1024 or so being used at a time by
* default.
* - Inability to allocate high fds will aggravate the X Server's select()
* handling, and likely that of many GL client applications as well.
*
* This led to a plan of using our own integer IDs (called handles, following
* DRM terminology) to mimic fds, and implement the fd syscalls we need as
* ioctls. The objects themselves will still include the struct file so
* that we can transition to fds if the required kernel infrastructure shows
* up at a later date, and as our interface with shmfs for memory allocation.
*/
/*
* We make up offsets for buffer objects so we can recognize them at
* mmap time.
*/
/* memory pool is used for all platforms now */
/**
* Initialize the GEM device fields
*/
int
{
return 0;
}
void
/* LINTED */
{
}
static void
{
if (HAS_MEM_POOL(gen)) {
} else {
}
}
0xff000U, /* dma_attr_addr_lo */
0xffffffffU, /* dma_attr_addr_hi */
0xffffffffU, /* dma_attr_count_max */
4096, /* dma_attr_align */
0x1fffU, /* dma_attr_burstsizes */
1, /* dma_attr_minxfer */
0xffffffffU, /* dma_attr_maxxfer */
0xffffffffU, /* dma_attr_seg */
1, /* dma_attr_sgllen, variable */
4, /* dma_attr_granular */
DDI_DMA_FLAGERR, /* dma_attr_flags */
};
};
static int
{
int i, n;
acc_attr = &old_acc_attr;
dma_attr = &old_dma_attr;
DRM_ERROR("ddi_dma_alloc_handle failed");
goto err1;
}
DRM_ERROR("ddi_dma_mem_alloc failed");
goto err2;
}
!= DDI_DMA_MAPPED) {
DRM_ERROR("ddi_dma_addr_bind_handle failed");
goto err3;
}
DRM_DEBUG("pfnarray == NULL");
goto err4;
}
for (n = 0, i = 1; ; i++) {
paddr < cookie_end;
if (n >= real_pgcnt)
return (0);
}
if (i >= cookie_cnt)
break;
}
err4:
err3:
err2:
err1:
return (-1);
}
/* Alloc GEM object by memory pool */
static int
{
int ret;
DRM_ERROR("Failed to allocate pfnarray ");
return (-1);
}
if (ret) {
DRM_ERROR("Failed to alloc pages from memory pool");
return (-1);
}
return (0);
}
static int
{
if (HAS_MEM_POOL(gen)) {
if (gen >= 60)
else
if (ret)
return (-1);
} else {
if (ret)
return (-1);
}
DRM_ERROR("obj %p map incorrect 0x%lx != 0x%lx",
udelay(150);
if (num++ < 5)
goto alloc_again;
else
return (-1);
}
return (0);
}
/*
* Initialize an already allocate GEM object of the specified size with
* shmfs backing store.
*/
int
{
int ret;
if (size == 0) {
DRM_DEBUG("size == 0");
return (-1);
}
if (ret)
return (-1);
DRM_DEBUG("map == NULL");
goto err5;
}
map->umem_cookie =
DRM_DEBUG("umem_cookie == NULL");
goto err6;
}
DRM_DEBUG("drm_map_handle failed");
goto err7;
}
if (MDB_TRACK_ENABLE) {
}
return (0);
err7:
err6:
err5:
return (-1);
}
/**
* Initialize an already allocated GEM object of the specified size with
* no GEM provided backing store. Instead the caller is responsible for
* backing the object and handling it.
*/
{
return 0;
}
/**
* Allocate a GEM object of the specified size with shmfs backing store
*/
struct drm_gem_object *
{
if (!obj)
goto free;
return NULL;
}
goto fput;
}
return obj;
fput:
/* Object_init mangles the global counters - readjust them. */
free:
return NULL;
}
/**
* Removes the mapping from handle to filp for this object.
*/
int
{
/* This is gross. The idr system doesn't let us try a delete and
* return an error code. It just spews if you fail at deleting.
* So, we have to grab a lock around finding the object and then
* doing the delete on it and dropping the refcount, or the user
* could race us to double-decrement the refcount and cause a
* use-after-free later. Given the frequency of our handle lookups,
* we may want to use ida for number allocation and a hash table
* for the pointers, anyway.
*/
/* Check if we currently have a reference on the object */
return -EINVAL;
}
/* Release reference and decrement refcount. */
return 0;
}
/**
* Create a handle for this object. This adds a handle reference
* to the object, which includes a regular reference count. Callers
* will likely want to dereference the object afterwards.
*/
int
struct drm_gem_object *obj,
{
int ret;
/*
* Get the user-visible handle using idr.
*/
/* ensure there is space available to allocate a handle */
return -ENOMEM;
/* do the allocation under our spinlock */
goto again;
if (ret != 0)
return ret;
if (ret) {
return ret;
}
}
return 0;
}
/** Returns a reference to the object named by the handle. */
struct drm_gem_object *
/* LINTED */
{
/* Check if we currently have a reference on the object */
return NULL;
}
return obj;
}
/**
* Releases the handle to an mm object.
*/
int
/* LINTED */
{
int ret;
return -ENODEV;
return ret;
}
/**
* Create a global name for an object, returning the name.
*
* Note that the name does not hold a reference; when the object
* is freed, the name goes away.
*/
int
/* LINTED */
{
int ret;
return -ENODEV;
return -ENOENT;
goto err;
}
goto again;
if (ret != 0)
goto err;
/* Allocate a reference for the name table. */
} else {
ret = 0;
}
err:
return ret;
}
/**
* Open an object using the global name, returning a handle and the size.
*
* This handle (of course) holds a reference to the object, so the object
* will not go away until the handle is deleted.
*/
int
/* LINTED */
{
int ret;
return -ENODEV;
if (obj)
if (!obj)
return -ENOENT;
if (ret)
return ret;
return 0;
}
/**
* Called at device open time, sets up the structure for handling refcounting
* of mm objects.
*/
void
/* LINTED */
{
}
/**
* Called at device close to release the file's
* handle references on objects.
*/
static int
/* LINTED */
{
return 0;
}
/**
* Called at close time when the filp is going away.
*
* Releases any remaining references on objects by this filp.
*/
void
/* LINTED E_FUNC_ARG_UNUSED */
{
}
}
void
{
if (MDB_TRACK_ENABLE) {
}
}
} else {
}
}
/**
* Called after the last reference to the object has been lost.
*
* Frees the object
*/
void
{
/* LINTED */
// BUG_ON(!mutex_is_locked(&dev->struct_mutex));
}
/* LINTED E_FUNC_ARG_UNUSED */
{
BUG_ON(1);
}
/**
* Called after the last handle to the object has been closed
*
* Removes any name for the object. Note that this must be
* called before drm_gem_object_free or we'll be touching
* freed memory
*/
void
{
/* Remove any name for this object */
/*
* The object name held a reference to this object, drop
* that now.
*
* This cannot be the last reference, since the handle holds one too.
*/
} else
}
int
{
return -ENOMEM;
}
return 0;
}
void
{
}
void
{
}
void
{
DRM_DEBUG("already freed, don't free more than once!");
}
}
}
void
{
}
}