Commit 4b85f7f5 authored by Rob Clark's avatar Rob Clark
Browse files

drm/msm: support for an arbitrary number of address spaces



It means we have to do a list traversal where we once had an index into
a table.  But the list will normally have one or two entries.

Signed-off-by: default avatarRob Clark <robdclark@gmail.com>
parent f4839bd5
Loading
Loading
Loading
Loading
+96 −42
Original line number Original line Diff line number Diff line
@@ -283,21 +283,59 @@ uint64_t msm_gem_mmap_offset(struct drm_gem_object *obj)
	return offset;
	return offset;
}
}


static struct msm_gem_vma *add_vma(struct drm_gem_object *obj,
		struct msm_gem_address_space *aspace)
{
	struct msm_gem_object *msm_obj = to_msm_bo(obj);
	struct msm_gem_vma *vma;

	vma = kzalloc(sizeof(*vma), GFP_KERNEL);
	if (!vma)
		return ERR_PTR(-ENOMEM);

	vma->aspace = aspace;

	list_add_tail(&vma->list, &msm_obj->vmas);

	return vma;
}

static struct msm_gem_vma *lookup_vma(struct drm_gem_object *obj,
		struct msm_gem_address_space *aspace)
{
	struct msm_gem_object *msm_obj = to_msm_bo(obj);
	struct msm_gem_vma *vma;

	WARN_ON(!mutex_is_locked(&obj->dev->struct_mutex));

	list_for_each_entry(vma, &msm_obj->vmas, list) {
		if (vma->aspace == aspace)
			return vma;
	}

	return NULL;
}

static void del_vma(struct msm_gem_vma *vma)
{
	if (!vma)
		return;

	list_del(&vma->list);
	kfree(vma);
}

static void
static void
put_iova(struct drm_gem_object *obj)
put_iova(struct drm_gem_object *obj)
{
{
	struct drm_device *dev = obj->dev;
	struct msm_drm_private *priv = obj->dev->dev_private;
	struct msm_gem_object *msm_obj = to_msm_bo(obj);
	struct msm_gem_object *msm_obj = to_msm_bo(obj);
	int id;
	struct msm_gem_vma *vma, *tmp;


	WARN_ON(!mutex_is_locked(&dev->struct_mutex));
	WARN_ON(!mutex_is_locked(&obj->dev->struct_mutex));


	for (id = 0; id < ARRAY_SIZE(msm_obj->domain); id++) {
	list_for_each_entry_safe(vma, tmp, &msm_obj->vmas, list) {
		if (!priv->aspace[id])
		msm_gem_unmap_vma(vma->aspace, vma, msm_obj->sgt);
			continue;
		del_vma(vma);
		msm_gem_unmap_vma(priv->aspace[id],
				&msm_obj->domain[id], msm_obj->sgt);
	}
	}
}
}


@@ -312,24 +350,37 @@ int msm_gem_get_iova_locked(struct drm_gem_object *obj,
		struct msm_gem_address_space *aspace, uint64_t *iova)
		struct msm_gem_address_space *aspace, uint64_t *iova)
{
{
	struct msm_gem_object *msm_obj = to_msm_bo(obj);
	struct msm_gem_object *msm_obj = to_msm_bo(obj);
	int id = aspace ? aspace->id : 0;
	struct msm_gem_vma *vma;
	int ret = 0;
	int ret = 0;


	WARN_ON(!mutex_is_locked(&obj->dev->struct_mutex));
	WARN_ON(!mutex_is_locked(&obj->dev->struct_mutex));


	if (!msm_obj->domain[id].iova) {
	vma = lookup_vma(obj, aspace);
		struct msm_drm_private *priv = obj->dev->dev_private;
		struct page **pages = get_pages(obj);


		if (IS_ERR(pages))
	if (!vma) {
			return PTR_ERR(pages);
		struct page **pages;

		vma = add_vma(obj, aspace);
		if (IS_ERR(vma))
			return PTR_ERR(vma);

		pages = get_pages(obj);
		if (IS_ERR(pages)) {
			ret = PTR_ERR(pages);
			goto fail;
		}


		ret = msm_gem_map_vma(priv->aspace[id], &msm_obj->domain[id],
		ret = msm_gem_map_vma(aspace, vma, msm_obj->sgt,
				msm_obj->sgt, obj->size >> PAGE_SHIFT);
				obj->size >> PAGE_SHIFT);
		if (ret)
			goto fail;
	}
	}


	if (!ret)
	*iova = vma->iova;
		*iova = msm_obj->domain[id].iova;
	return 0;

fail:
	del_vma(vma);


	return ret;
	return ret;
}
}
@@ -338,22 +389,12 @@ int msm_gem_get_iova_locked(struct drm_gem_object *obj,
int msm_gem_get_iova(struct drm_gem_object *obj,
int msm_gem_get_iova(struct drm_gem_object *obj,
		struct msm_gem_address_space *aspace, uint64_t *iova)
		struct msm_gem_address_space *aspace, uint64_t *iova)
{
{
	struct msm_gem_object *msm_obj = to_msm_bo(obj);
	int id = aspace ? aspace->id : 0;
	int ret;
	int ret;


	/* this is safe right now because we don't unmap until the
	 * bo is deleted:
	 */
	if (msm_obj->domain[id].iova) {
		might_lock(&obj->dev->struct_mutex);
		*iova = msm_obj->domain[id].iova;
		return 0;
	}

	mutex_lock(&obj->dev->struct_mutex);
	mutex_lock(&obj->dev->struct_mutex);
	ret = msm_gem_get_iova_locked(obj, aspace, iova);
	ret = msm_gem_get_iova_locked(obj, aspace, iova);
	mutex_unlock(&obj->dev->struct_mutex);
	mutex_unlock(&obj->dev->struct_mutex);

	return ret;
	return ret;
}
}


@@ -363,10 +404,14 @@ int msm_gem_get_iova(struct drm_gem_object *obj,
uint64_t msm_gem_iova(struct drm_gem_object *obj,
uint64_t msm_gem_iova(struct drm_gem_object *obj,
		struct msm_gem_address_space *aspace)
		struct msm_gem_address_space *aspace)
{
{
	struct msm_gem_object *msm_obj = to_msm_bo(obj);
	struct msm_gem_vma *vma;
	int id = aspace ? aspace->id : 0;

	WARN_ON(!msm_obj->domain[id].iova);
	mutex_lock(&obj->dev->struct_mutex);
	return msm_obj->domain[id].iova;
	vma = lookup_vma(obj, aspace);
	mutex_unlock(&obj->dev->struct_mutex);
	WARN_ON(!vma);

	return vma ? vma->iova : 0;
}
}


void msm_gem_put_iova(struct drm_gem_object *obj,
void msm_gem_put_iova(struct drm_gem_object *obj,
@@ -624,11 +669,10 @@ void msm_gem_describe(struct drm_gem_object *obj, struct seq_file *m)
	struct msm_gem_object *msm_obj = to_msm_bo(obj);
	struct msm_gem_object *msm_obj = to_msm_bo(obj);
	struct reservation_object *robj = msm_obj->resv;
	struct reservation_object *robj = msm_obj->resv;
	struct reservation_object_list *fobj;
	struct reservation_object_list *fobj;
	struct msm_drm_private *priv = obj->dev->dev_private;
	struct dma_fence *fence;
	struct dma_fence *fence;
	struct msm_gem_vma *vma;
	uint64_t off = drm_vma_node_start(&obj->vma_node);
	uint64_t off = drm_vma_node_start(&obj->vma_node);
	const char *madv;
	const char *madv;
	unsigned id;


	WARN_ON(!mutex_is_locked(&obj->dev->struct_mutex));
	WARN_ON(!mutex_is_locked(&obj->dev->struct_mutex));


@@ -650,8 +694,9 @@ void msm_gem_describe(struct drm_gem_object *obj, struct seq_file *m)
			obj->name, kref_read(&obj->refcount),
			obj->name, kref_read(&obj->refcount),
			off, msm_obj->vaddr);
			off, msm_obj->vaddr);


	for (id = 0; id < priv->num_aspaces; id++)
	/* FIXME: we need to print the address space here too */
		seq_printf(m, " %08llx", msm_obj->domain[id].iova);
	list_for_each_entry(vma, &msm_obj->vmas, list)
		seq_printf(m, " %08llx", vma->iova);


	seq_printf(m, " %zu%s\n", obj->size, madv);
	seq_printf(m, " %zu%s\n", obj->size, madv);


@@ -790,6 +835,8 @@ static int msm_gem_new_impl(struct drm_device *dev,
	}
	}


	INIT_LIST_HEAD(&msm_obj->submit_entry);
	INIT_LIST_HEAD(&msm_obj->submit_entry);
	INIT_LIST_HEAD(&msm_obj->vmas);

	list_add_tail(&msm_obj->mm_list, &priv->inactive_list);
	list_add_tail(&msm_obj->mm_list, &priv->inactive_list);


	*obj = &msm_obj->base;
	*obj = &msm_obj->base;
@@ -828,19 +875,26 @@ struct drm_gem_object *msm_gem_new(struct drm_device *dev,
		goto fail;
		goto fail;


	if (use_vram) {
	if (use_vram) {
		struct msm_gem_object *msm_obj = to_msm_bo(obj);
		struct msm_gem_vma *vma;
		struct page **pages;
		struct page **pages;


		msm_obj->vram_node = &msm_obj->domain[0].node;
		vma = add_vma(obj, NULL);
		if (IS_ERR(vma)) {
			ret = PTR_ERR(vma);
			goto fail;
		}

		to_msm_bo(obj)->vram_node = &vma->node;

		drm_gem_private_object_init(dev, obj, size);
		drm_gem_private_object_init(dev, obj, size);


		msm_obj->pages = get_pages(obj);
		pages = get_pages(obj);
		pages = get_pages(obj);
		if (IS_ERR(pages)) {
		if (IS_ERR(pages)) {
			ret = PTR_ERR(pages);
			ret = PTR_ERR(pages);
			goto fail;
			goto fail;
		}
		}
		msm_obj->domain[0].iova = physaddr(obj);

		vma->iova = physaddr(obj);
	} else {
	} else {
		ret = drm_gem_object_init(dev, obj, size);
		ret = drm_gem_object_init(dev, obj, size);
		if (ret)
		if (ret)
+3 −1
Original line number Original line Diff line number Diff line
@@ -39,6 +39,8 @@ struct msm_gem_address_space {
struct msm_gem_vma {
struct msm_gem_vma {
	struct drm_mm_node node;
	struct drm_mm_node node;
	uint64_t iova;
	uint64_t iova;
	struct msm_gem_address_space *aspace;
	struct list_head list;    /* node in msm_gem_object::vmas */
};
};


struct msm_gem_object {
struct msm_gem_object {
@@ -78,7 +80,7 @@ struct msm_gem_object {
	struct sg_table *sgt;
	struct sg_table *sgt;
	void *vaddr;
	void *vaddr;


	struct msm_gem_vma domain[NUM_DOMAINS];
	struct list_head vmas;    /* list of msm_gem_vma */


	/* normally (resv == &_resv) except for imported bo's */
	/* normally (resv == &_resv) except for imported bo's */
	struct reservation_object *resv;
	struct reservation_object *resv;