checkpoint: gtt binding written.
parent
2140e102f9
commit
5af87acbc2
|
@ -1038,6 +1038,10 @@ extern void drm_free_pages(unsigned long address, int order, int area);
|
||||||
extern DRM_AGP_MEM *drm_alloc_agp(struct drm_device *dev, int pages, u32 type);
|
extern DRM_AGP_MEM *drm_alloc_agp(struct drm_device *dev, int pages, u32 type);
|
||||||
extern int drm_free_agp(DRM_AGP_MEM * handle, int pages);
|
extern int drm_free_agp(DRM_AGP_MEM * handle, int pages);
|
||||||
extern int drm_bind_agp(DRM_AGP_MEM * handle, unsigned int start);
|
extern int drm_bind_agp(DRM_AGP_MEM * handle, unsigned int start);
|
||||||
|
extern DRM_AGP_MEM *drm_agp_bind_pages(struct drm_device *dev,
|
||||||
|
struct page **pages,
|
||||||
|
unsigned long num_pages,
|
||||||
|
uint32_t gtt_offset);
|
||||||
extern int drm_unbind_agp(DRM_AGP_MEM * handle);
|
extern int drm_unbind_agp(DRM_AGP_MEM * handle);
|
||||||
|
|
||||||
extern void drm_free_memctl(size_t size);
|
extern void drm_free_memctl(size_t size);
|
||||||
|
@ -1301,11 +1305,14 @@ static inline struct drm_memrange *drm_get_mm(struct drm_memrange_node *block)
|
||||||
return block->mm;
|
return block->mm;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Memory manager (drm_mm.c) */
|
/* Graphics Execution Manager library functions (drm_gem.c) */
|
||||||
void drm_gem_object_reference(struct drm_device *dev,
|
void drm_gem_object_reference(struct drm_device *dev,
|
||||||
struct drm_gem_object *obj);
|
struct drm_gem_object *obj);
|
||||||
void drm_gem_object_unreference(struct drm_device *dev,
|
void drm_gem_object_unreference(struct drm_device *dev,
|
||||||
struct drm_gem_object *obj);
|
struct drm_gem_object *obj);
|
||||||
|
struct drm_gem_object *
|
||||||
|
drm_gem_object_lookup(struct drm_device *dev, struct drm_file *filp,
|
||||||
|
int handle);
|
||||||
int drm_gem_alloc_ioctl(struct drm_device *dev, void *data,
|
int drm_gem_alloc_ioctl(struct drm_device *dev, void *data,
|
||||||
struct drm_file *file_priv);
|
struct drm_file *file_priv);
|
||||||
int drm_gem_unreference_ioctl(struct drm_device *dev, void *data,
|
int drm_gem_unreference_ioctl(struct drm_device *dev, void *data,
|
||||||
|
|
|
@ -484,6 +484,53 @@ int drm_agp_unbind_memory(DRM_AGP_MEM * handle)
|
||||||
return agp_unbind_memory(handle);
|
return agp_unbind_memory(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Binds a collection of pages into AGP memory at the given offset, returning
|
||||||
|
* the AGP memory structure containing them.
|
||||||
|
*
|
||||||
|
* No reference is held on the pages during this time -- it is up to the
|
||||||
|
* caller to handle that.
|
||||||
|
*/
|
||||||
|
DRM_AGP_MEM *
|
||||||
|
drm_agp_bind_pages(struct drm_device *dev,
|
||||||
|
struct page **pages,
|
||||||
|
unsigned long num_pages,
|
||||||
|
uint32_t gtt_offset)
|
||||||
|
{
|
||||||
|
struct page **cur_page, **last_page = pages + num_pages;
|
||||||
|
DRM_AGP_MEM *mem;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
DRM_DEBUG("drm_agp_populate_ttm\n");
|
||||||
|
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,11)
|
||||||
|
mem = drm_agp_allocate_memory(num_pages, AGP_USER_MEMORY);
|
||||||
|
#else
|
||||||
|
mem = drm_agp_allocate_memory(dev->agp->bridge, num_pages,
|
||||||
|
AGP_USER_MEMORY);
|
||||||
|
#endif
|
||||||
|
if (mem == NULL) {
|
||||||
|
DRM_ERROR("Failed to allocate memory for %ld pages\n",
|
||||||
|
num_pages);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
mem->page_count = 0;
|
||||||
|
for (cur_page = pages; cur_page < last_page; ++cur_page) {
|
||||||
|
struct page *page = *cur_page;
|
||||||
|
|
||||||
|
mem->memory[mem->page_count++] =
|
||||||
|
phys_to_gart(page_to_phys(page));
|
||||||
|
}
|
||||||
|
|
||||||
|
mem->is_flushed = TRUE;
|
||||||
|
ret = drm_agp_bind_memory(mem, gtt_offset);
|
||||||
|
if (ret != 0) {
|
||||||
|
agp_free_memory(mem);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return mem;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -127,7 +127,7 @@ drm_gem_handle_delete(struct drm_device *dev, struct drm_file *filp,
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns a reference to the object named by the handle. */
|
/** Returns a reference to the object named by the handle. */
|
||||||
static struct drm_gem_object *
|
struct drm_gem_object *
|
||||||
drm_gem_object_lookup(struct drm_device *dev, struct drm_file *filp,
|
drm_gem_object_lookup(struct drm_device *dev, struct drm_file *filp,
|
||||||
int handle)
|
int handle)
|
||||||
{
|
{
|
||||||
|
@ -358,6 +358,9 @@ drm_gem_object_reference(struct drm_device *dev, struct drm_gem_object *obj)
|
||||||
void
|
void
|
||||||
drm_gem_object_unreference(struct drm_device *dev, struct drm_gem_object *obj)
|
drm_gem_object_unreference(struct drm_device *dev, struct drm_gem_object *obj)
|
||||||
{
|
{
|
||||||
|
if (obj == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
spin_lock(&obj->lock);
|
spin_lock(&obj->lock);
|
||||||
obj->refcount--;
|
obj->refcount--;
|
||||||
spin_unlock(&obj->lock);
|
spin_unlock(&obj->lock);
|
||||||
|
|
|
@ -49,9 +49,120 @@ i915_gem_init_ioctl(struct drm_device *dev, void *data,
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
i915_gem_evict_object(struct drm_device *dev, struct drm_gem_object *obj)
|
i915_gem_object_free_page_list(struct drm_device *dev,
|
||||||
|
struct drm_gem_object *obj)
|
||||||
{
|
{
|
||||||
|
struct drm_i915_gem_object *obj_priv = obj->driver_private;
|
||||||
|
int page_count = obj->size / PAGE_SIZE;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (obj_priv->page_list == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Count how many we had successfully allocated, since release_pages()
|
||||||
|
* doesn't like NULLs.
|
||||||
|
*/
|
||||||
|
for (i = 0; i < obj->size / PAGE_SIZE; i++) {
|
||||||
|
if (obj_priv->page_list[i] == NULL)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
release_pages(obj_priv->page_list, i, 0);
|
||||||
|
|
||||||
|
drm_free(obj_priv->page_list,
|
||||||
|
page_count * sizeof(struct page *),
|
||||||
|
DRM_MEM_DRIVER);
|
||||||
|
obj_priv->page_list = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unbinds an object from the GTT aperture.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
i915_gem_object_unbind(struct drm_device *dev, struct drm_gem_object *obj)
|
||||||
|
{
|
||||||
|
struct drm_i915_gem_object *obj_priv = obj->driver_private;
|
||||||
|
|
||||||
|
if (obj_priv->agp_mem != NULL) {
|
||||||
|
drm_unbind_agp(obj_priv->agp_mem);
|
||||||
|
drm_free_agp(obj_priv->agp_mem, obj->size / PAGE_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
i915_gem_object_free_page_list(dev, obj);
|
||||||
|
|
||||||
|
drm_memrange_put_block(obj_priv->gtt_space);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds free space in the GTT aperture and binds the object there.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
i915_gem_object_bind_to_gtt(struct drm_device *dev, struct drm_gem_object *obj)
|
||||||
|
{
|
||||||
|
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||||
|
struct drm_i915_gem_object *obj_priv = obj->driver_private;
|
||||||
|
struct drm_memrange_node *free_space;
|
||||||
|
int page_count, i;
|
||||||
|
|
||||||
|
free_space = drm_memrange_search_free(&dev_priv->mm.gtt_space,
|
||||||
|
obj->size,
|
||||||
|
PAGE_SIZE, 0);
|
||||||
|
|
||||||
|
obj_priv->gtt_space = drm_memrange_get_block(free_space,
|
||||||
|
obj->size,
|
||||||
|
PAGE_SIZE);
|
||||||
|
|
||||||
|
/* Get the list of pages out of our struct file. They'll be pinned
|
||||||
|
* at this point until we release them.
|
||||||
|
*/
|
||||||
|
page_count = obj->size / PAGE_SIZE;
|
||||||
|
BUG_ON(obj_priv->page_list != NULL);
|
||||||
|
obj_priv->page_list = drm_calloc(page_count, sizeof(struct page *),
|
||||||
|
DRM_MEM_DRIVER);
|
||||||
|
for (i = 0; i < page_count; i++) {
|
||||||
|
obj_priv->page_list[i] =
|
||||||
|
find_or_create_page(obj->filp->f_mapping, i, GFP_HIGHUSER);
|
||||||
|
|
||||||
|
if (obj_priv->page_list[i] == NULL) {
|
||||||
|
i915_gem_object_free_page_list(dev, obj);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create an AGP memory structure pointing at our pages, and bind it
|
||||||
|
* into the GTT.
|
||||||
|
*/
|
||||||
|
obj_priv->agp_mem = drm_agp_bind_pages(dev,
|
||||||
|
obj_priv->page_list,
|
||||||
|
page_count,
|
||||||
|
obj_priv->gtt_offset);
|
||||||
|
if (obj_priv->agp_mem == NULL) {
|
||||||
|
i915_gem_object_free_page_list(dev, obj);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
i915_gem_reloc_and_validate_object(struct drm_device *dev,
|
||||||
|
struct drm_file *file_priv,
|
||||||
|
struct drm_i915_gem_validate_entry *entry,
|
||||||
|
struct drm_gem_object *obj)
|
||||||
|
{
|
||||||
|
struct drm_i915_gem_reloc *relocs;
|
||||||
|
struct drm_i915_gem_object *obj_priv = obj->driver_private;
|
||||||
|
|
||||||
|
/* Walk the list of relocations and perform them if necessary. */
|
||||||
|
/* XXX */
|
||||||
|
|
||||||
|
/* Choose the GTT offset for our buffer and put it there. */
|
||||||
|
if (obj_priv->gtt_space == NULL) {
|
||||||
|
i915_gem_object_bind_to_gtt(dev, obj);
|
||||||
|
if (obj_priv->gtt_space == NULL)
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -62,7 +173,7 @@ evict_callback(struct drm_memrange_node *node, void *data)
|
||||||
struct drm_i915_gem_object *obj_priv = obj->driver_private;
|
struct drm_i915_gem_object *obj_priv = obj->driver_private;
|
||||||
|
|
||||||
if (obj_priv->pin_count == 0)
|
if (obj_priv->pin_count == 0)
|
||||||
i915_gem_evict_object(dev, obj);
|
i915_gem_object_unbind(dev, obj);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -74,6 +185,7 @@ i915_gem_execbuffer(struct drm_device *dev, void *data,
|
||||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||||
struct drm_i915_gem_execbuffer *args = data;
|
struct drm_i915_gem_execbuffer *args = data;
|
||||||
struct drm_i915_gem_validate_entry *validate_list;
|
struct drm_i915_gem_validate_entry *validate_list;
|
||||||
|
struct drm_gem_object **object_list;
|
||||||
int ret, i;
|
int ret, i;
|
||||||
RING_LOCALS;
|
RING_LOCALS;
|
||||||
|
|
||||||
|
@ -90,34 +202,64 @@ i915_gem_execbuffer(struct drm_device *dev, void *data,
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
/* Evict everything so we have space for sure. */
|
/* Evict everything so we have space for sure. */
|
||||||
drm_memrange_for_each(&dev_priv->mm.gtt_space, evict_callback);
|
drm_memrange_for_each(&dev_priv->mm.gtt_space, evict_callback, dev);
|
||||||
|
|
||||||
/* Copy in the validate list from userland */
|
/* Copy in the validate list from userland */
|
||||||
validate_list = drm_calloc(sizeof(*validate_list), args->buffer_count,
|
validate_list = drm_calloc(sizeof(*validate_list), args->buffer_count,
|
||||||
DRM_MEM_DRIVER);
|
DRM_MEM_DRIVER);
|
||||||
|
object_list = drm_calloc(sizeof(*object_list), args->buffer_count,
|
||||||
|
DRM_MEM_DRIVER);
|
||||||
|
if (validate_list == NULL || object_list == NULL) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
ret = copy_from_user(validate_list,
|
ret = copy_from_user(validate_list,
|
||||||
(struct drm_i915_relocation_entry __user*)
|
(struct drm_i915_relocation_entry __user*)
|
||||||
args->buffers,
|
args->buffers,
|
||||||
sizeof(*validate_list) * args->buffer_count);
|
sizeof(*validate_list) * args->buffer_count);
|
||||||
if (ret != 0) {
|
if (ret != 0)
|
||||||
drm_free(validate_list,
|
goto err;
|
||||||
sizeof(*validate_list) * args->buffer_count,
|
|
||||||
DRM_MEM_DRIVER);
|
/* Look up object handles and perform the relocations */
|
||||||
return ret;
|
for (i = 0; i < args->buffer_count; i++) {
|
||||||
|
object_list[i] = drm_gem_object_lookup(dev, file_priv,
|
||||||
|
validate_list[i].buffer_handle);
|
||||||
|
if (object_list[i] == NULL) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Perform the relocations */
|
i915_gem_reloc_and_validate_object(dev, file_priv,
|
||||||
for (i = 0; i < args->buffer_count; i++) {
|
&validate_list[i],
|
||||||
intel_gem_reloc_and_validate_buffer(dev, &validate_list[i]);
|
object_list[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Exec the batchbuffer */
|
/* Exec the batchbuffer */
|
||||||
|
|
||||||
|
/* Copy the new buffer offsets back to the user's validate list. */
|
||||||
|
for (i = 0; i < args->buffer_count; i++) {
|
||||||
|
struct drm_i915_gem_object *obj_priv =
|
||||||
|
object_list[i]->driver_private;
|
||||||
|
|
||||||
|
validate_list[i].buffer_offset = obj_priv->gtt_offset;
|
||||||
|
}
|
||||||
|
ret = copy_to_user(validate_list,
|
||||||
|
(struct drm_i915_relocation_entry __user*)
|
||||||
|
args->buffers,
|
||||||
|
sizeof(*validate_list) * args->buffer_count);
|
||||||
|
|
||||||
|
/* Clean up and return */
|
||||||
|
err:
|
||||||
|
if (object_list != NULL) {
|
||||||
|
for (i = 0; i < args->buffer_count; i++)
|
||||||
|
drm_gem_object_unreference(dev, object_list[i]);
|
||||||
|
}
|
||||||
|
drm_free(object_list, sizeof(*object_list) * args->buffer_count,
|
||||||
|
DRM_MEM_DRIVER);
|
||||||
drm_free(validate_list, sizeof(*validate_list) * args->buffer_count,
|
drm_free(validate_list, sizeof(*validate_list) * args->buffer_count,
|
||||||
DRM_MEM_DRIVER);
|
DRM_MEM_DRIVER);
|
||||||
|
|
||||||
return 0;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int i915_gem_init_object(struct drm_device *dev, struct drm_gem_object *obj)
|
int i915_gem_init_object(struct drm_device *dev, struct drm_gem_object *obj)
|
||||||
|
|
|
@ -256,7 +256,19 @@ enum intel_chip_family {
|
||||||
|
|
||||||
/** driver private structure attached to each drm_gem_object */
|
/** driver private structure attached to each drm_gem_object */
|
||||||
struct drm_i915_gem_object {
|
struct drm_i915_gem_object {
|
||||||
/** Current offset of the object in GTT space, if any. */
|
/** Current space allocated to this object in the GTT, if any. */
|
||||||
|
struct drm_memrange_node *gtt_space;
|
||||||
|
|
||||||
|
/** AGP memory structure for our GTT binding. */
|
||||||
|
DRM_AGP_MEM *agp_mem;
|
||||||
|
|
||||||
|
struct page **page_list;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Current offset of the object in GTT space.
|
||||||
|
*
|
||||||
|
* This is the same as gtt_space->start
|
||||||
|
*/
|
||||||
uint32_t gtt_offset;
|
uint32_t gtt_offset;
|
||||||
|
|
||||||
/** Boolean whether this object has a valid gtt offset. */
|
/** Boolean whether this object has a valid gtt offset. */
|
||||||
|
|
Loading…
Reference in New Issue