aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/exynos/exynos_drm_iommu.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/exynos/exynos_drm_iommu.c')
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_iommu.c212
1 files changed, 60 insertions, 152 deletions
diff --git a/drivers/gpu/drm/exynos/exynos_drm_iommu.c b/drivers/gpu/drm/exynos/exynos_drm_iommu.c
index f2ffa68..b0a8e1c 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_iommu.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_iommu.c
@@ -37,13 +37,13 @@
static DEFINE_MUTEX(iommu_mutex);
struct exynos_iommu_ops {
- int (*setup)(struct device *dev);
- void (*cleanup)(struct device *dev);
- int (*activate)(struct device *dev);
- void (*deactivate)(struct device *dev);
- dma_addr_t (*map)(struct device *dev, struct scatterlist *sg,
+ void *(*setup)(unsigned long s_iova, unsigned long size);
+ void (*cleanup)(void *in_vmm);
+ int (*activate)(void *in_vmm, struct device *dev);
+ void (*deactivate)(void *in_vmm, struct device *dev);
+ dma_addr_t (*map)(void *in_vmm, struct scatterlist *sg,
off_t offset, size_t size);
- void (*unmap)(struct device *dev, dma_addr_t iova);
+ void (*unmap)(void *in_vmm, dma_addr_t iova);
};
static const struct exynos_iommu_ops iommu_ops = {
@@ -55,74 +55,20 @@ static const struct exynos_iommu_ops iommu_ops = {
.unmap = iovmm_unmap
};
-static bool check_iommu_map_params(struct iommu_gem_map_params *params)
-{
- if (!params) {
- DRM_ERROR("params is null.\n");
- return false;
- }
-
- if (!params->dev || !params->drm_dev || !params->file) {
- DRM_ERROR("invalid params.\n");
- return false;
- }
-
- return true;
-}
-
-void exynos_drm_remove_iommu_list(struct list_head *iommu_list,
- void *gem_obj)
-{
- struct iommu_info_node *im, *t_im;
-
- list_for_each_entry_safe(im, t_im, iommu_list, list) {
- if (im->gem_obj == gem_obj) {
- list_del(&im->list);
- kfree(im);
- im = NULL;
- break;
- }
- }
-
-}
-
-dma_addr_t exynos_drm_iommu_map_gem(struct iommu_gem_map_params *params,
- struct list_head *iommu_list,
- unsigned int gem_handle,
- enum iommu_types type)
+dma_addr_t exynos_drm_iommu_map_gem(struct drm_device *drm_dev,
+ struct drm_gem_object *obj)
{
+ struct exynos_drm_gem_obj *exynos_gem_obj;
+ struct exynos_drm_gem_buf *buf;
struct sg_table *sgt;
- struct iommu_info_node *node;
- struct exynos_drm_gem_obj *obj;
- dma_addr_t dma_addr;
-
- if (!is_iommu_type_valid(type)) {
- DRM_ERROR("invalid iommu type.\n");
- return 0;
- }
-
- if (!check_iommu_map_params(params))
- return 0;
-
- /* get gem object from specific gem framework. */
- obj = exynos_drm_gem_get_obj(params->drm_dev, gem_handle,
- params->file);
- if (IS_ERR(obj))
- return 0;
+ dma_addr_t dev_addr;
mutex_lock(&iommu_mutex);
- /*
- * if this gem object had already been mapped to iommu then
- * return dma address mapped before this time.
- */
- if (obj->iommu_info.mapped & (1 << type)) {
- DRM_DEBUG_KMS("already mapped to iommu");
- mutex_unlock(&iommu_mutex);
- return obj->iommu_info.dma_addrs[type];
- }
+ exynos_gem_obj = to_exynos_gem_obj(obj);
- sgt = obj->buffer->sgt;
+ buf = exynos_gem_obj->buffer;
+ sgt = buf->sgt;
/*
* if not using iommu, just return base address to physical
@@ -132,102 +78,64 @@ dma_addr_t exynos_drm_iommu_map_gem(struct iommu_gem_map_params *params,
mutex_unlock(&iommu_mutex);
return sg_dma_address(&sgt->sgl[0]);
}
- mutex_unlock(&iommu_mutex);
/*
- * allocate device address space for this driver and then
- * map all pages contained in sg list to iommu table.
+ * if a gem buffer was already mapped with iommu table then
+ * just return dev_addr;
+ *
+ * Note: device address is unique to system globally.
*/
- dma_addr = iommu_ops.map(params->dev, sgt->sgl, (off_t)0,
- (size_t)obj->size);
- if (!dma_addr) {
+ if (buf->dev_addr) {
mutex_unlock(&iommu_mutex);
- return dma_addr;
+ return buf->dev_addr;
}
- mutex_lock(&iommu_mutex);
-
/*
- * check map flag bit and device address mapped to iommu.
- * this data would be used to avoid duplicated mapping.
- */
- obj->iommu_info.mapped |= (1 << type);
- obj->iommu_info.dma_addrs[type] = dma_addr;
- obj->iommu_info.devs[type] = params->dev;
- obj->iommu_info.iommu_lists[type] = iommu_list;
-
- params->gem_obj = obj;
-
- /*
- * this gem object is referenced by this driver so
- * the object refcount should be increased.
+ * allocate device address space for this driver and then
+ * map all pages contained in sg list to iommu table.
*/
- drm_gem_object_reference(&obj->base);
-
- node = kzalloc(sizeof(*node), GFP_KERNEL);
- if (!node) {
- DRM_ERROR("failed to allocate iommu node.\n");
- dma_addr = 0;
- goto err;
+ dev_addr = iommu_ops.map(exynos_gem_obj->vmm, sgt->sgl, (off_t)0,
+ (size_t)obj->size);
+ if (!dev_addr) {
+ mutex_unlock(&iommu_mutex);
+ return dev_addr;
}
- node->gem_obj = obj;
- node->dma_addr = dma_addr;
mutex_unlock(&iommu_mutex);
- list_add_tail(&node->list, iommu_list);
-
- return dma_addr;
-err:
- mutex_unlock(&iommu_mutex);
- iommu_ops.unmap(params->dev, dma_addr);
- return dma_addr;
+ return dev_addr;
}
-void exynos_drm_iommu_unmap_gem(struct iommu_gem_map_params *params,
- dma_addr_t dma_addr,
- enum iommu_types type)
+void exynos_drm_iommu_unmap_gem(struct drm_gem_object *obj)
{
- struct exynos_drm_gem_obj *obj;
-
- if (!iommu_ops.unmap)
- return;
+ struct exynos_drm_gem_obj *exynos_gem_obj;
+ struct exynos_drm_gem_buf *buf;
- if (!is_iommu_type_valid(type)) {
- DRM_ERROR("invalid iommu type.\n");
+ if (!iommu_ops.unmap || !obj)
return;
- }
- if (!check_iommu_map_params(params))
- return;
-
- if (!params->gem_obj)
- return;
+ exynos_gem_obj = to_exynos_gem_obj(obj);
+ buf = exynos_gem_obj->buffer;
- obj = (struct exynos_drm_gem_obj *)params->gem_obj;
+ /* workaround */
+ usleep_range(15000, 20000);
mutex_lock(&iommu_mutex);
- if (!(obj->iommu_info.mapped & (1 << type))) {
- DRM_DEBUG_KMS("not already mapped to iommu so just return\n");
+
+ if (!buf->dev_addr) {
mutex_unlock(&iommu_mutex);
+ DRM_DEBUG_KMS("not mapped with iommu table.\n");
return;
}
- /* uncheck map flag bit. */
- obj->iommu_info.mapped &= ~(1 << type);
- obj->iommu_info.dma_addrs[type] = 0;
- mutex_unlock(&iommu_mutex);
-
- iommu_ops.unmap(params->dev, dma_addr);
+ if (exynos_gem_obj->vmm)
+ iommu_ops.unmap(exynos_gem_obj->vmm, buf->dev_addr);
- /*
- * drop this gem object refcount to release allocated buffer
- * and resources.
- */
- drm_gem_object_unreference_unlocked(&obj->base);
+ buf->dev_addr = 0;
+ mutex_unlock(&iommu_mutex);
}
-dma_addr_t exynos_drm_iommu_map(struct device *dev, dma_addr_t paddr,
+dma_addr_t exynos_drm_iommu_map(void *in_vmm, dma_addr_t paddr,
size_t size)
{
struct sg_table *sgt;
@@ -244,13 +152,13 @@ dma_addr_t exynos_drm_iommu_map(struct device *dev, dma_addr_t paddr,
sgt = kzalloc(sizeof(struct sg_table) * npages, GFP_KERNEL);
if (!sgt) {
- dev_err(dev, "failed to allocate sg table.\n");
+ DRM_ERROR("failed to allocate sg table.\n");
return dma_addr;
}
ret = sg_alloc_table(sgt, npages, GFP_KERNEL);
if (ret < 0) {
- dev_err(dev, "failed to initialize sg table.\n");
+ DRM_ERROR("failed to initialize sg table.\n");
goto err;
}
@@ -270,9 +178,9 @@ dma_addr_t exynos_drm_iommu_map(struct device *dev, dma_addr_t paddr,
* allocate device address space for this driver and then
* map all pages contained in sg list to iommu table.
*/
- dma_addr = iommu_ops.map(dev, sgt->sgl, (off_t)0, (size_t)size);
+ dma_addr = iommu_ops.map(in_vmm, sgt->sgl, (off_t)0, (size_t)size);
if (!dma_addr)
- dev_err(dev, "failed to map cmdlist pool.\n");
+ DRM_ERROR("failed to map cmdlist pool.\n");
sg_free_table(sgt);
err:
@@ -283,45 +191,45 @@ err:
}
-void exynos_drm_iommu_unmap(struct device *dev, dma_addr_t dma_addr)
+void exynos_drm_iommu_unmap(void *in_vmm, dma_addr_t dma_addr)
{
if (iommu_ops.unmap)
- iommu_ops.unmap(dev, dma_addr);
+ iommu_ops.unmap(in_vmm, dma_addr);
}
-int exynos_drm_iommu_setup(struct device *dev)
+void *exynos_drm_iommu_setup(unsigned long s_iova, unsigned long size)
{
/*
* allocate device address space to this driver and add vmm object
* to s5p_iovmm_list. please know that each iommu will use
* 1GB as its own device address apace.
*
- * the device address space : 0x80000000 ~ 0xA0000000
+ * the device address space : s_iova ~ s_iova + size
*/
if (iommu_ops.setup)
- return iommu_ops.setup(dev);
+ return iommu_ops.setup(s_iova, size);
- return 0;
+ return ERR_PTR(-EINVAL);
}
-int exynos_drm_iommu_activate(struct device *dev)
+int exynos_drm_iommu_activate(void *in_vmm, struct device *dev)
{
if (iommu_ops.activate)
- return iovmm_activate(dev);
+ return iovmm_activate(in_vmm, dev);
return 0;
}
-void exynos_drm_iommu_deactivate(struct device *dev)
+void exynos_drm_iommu_deactivate(void *in_vmm, struct device *dev)
{
if (iommu_ops.deactivate)
- iommu_ops.deactivate(dev);
+ iommu_ops.deactivate(in_vmm, dev);
}
-void exynos_drm_iommu_cleanup(struct device *dev)
+void exynos_drm_iommu_cleanup(void *in_vmm)
{
if (iommu_ops.cleanup)
- iommu_ops.cleanup(dev);
+ iommu_ops.cleanup(in_vmm);
}
MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");