Merge branch 'exynos-drm-next' of git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos into drm-next
This pull request adds to the rework patch series for IOMMU integration to support ARM64bit architecture with DMA-IOMMU glue code. With this patch series, Exynos DRM works well on Exynos5433 SoC with IOMMU enabled. * 'exynos-drm-next' of git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos: drm/exynos: iommu: add support for ARM64 specific code for IOMMU glue drm/exynos: iommu: move ARM specific code to exynos_drm_iommu.h drm/exynos: iommu: remove unused entries from exynos_drm_private strcuture drm/exynos: iommu: add a check if all sub-devices have iommu controller drm/exynos: iommu: move dma_params configuration code to separate functions
This commit is contained in:
commit
f82c137222
@ -11,7 +11,7 @@ if DRM_EXYNOS
|
||||
|
||||
config DRM_EXYNOS_IOMMU
|
||||
bool
|
||||
depends on EXYNOS_IOMMU && ARM_DMA_USE_IOMMU
|
||||
depends on EXYNOS_IOMMU
|
||||
default y
|
||||
|
||||
comment "CRTCs"
|
||||
|
@ -159,12 +159,7 @@ static int exynos_drm_load(struct drm_device *dev, unsigned long flags)
|
||||
DRM_INFO("Exynos DRM: using %s device for DMA mapping operations\n",
|
||||
dev_name(private->dma_dev));
|
||||
|
||||
/*
|
||||
* create mapping to manage iommu table and set a pointer to iommu
|
||||
* mapping structure to iommu_mapping of private data.
|
||||
* also this iommu_mapping can be used to check if iommu is supported
|
||||
* or not.
|
||||
*/
|
||||
/* create common IOMMU mapping for all devices attached to Exynos DRM */
|
||||
ret = drm_create_iommu_mapping(dev);
|
||||
if (ret < 0) {
|
||||
DRM_ERROR("failed to create iommu mapping.\n");
|
||||
|
@ -224,8 +224,6 @@ struct exynos_drm_private {
|
||||
struct drm_property *plane_zpos_property;
|
||||
|
||||
struct device *dma_dev;
|
||||
unsigned long da_start;
|
||||
unsigned long da_space_size;
|
||||
void *mapping;
|
||||
|
||||
unsigned int pipe;
|
||||
|
@ -14,13 +14,27 @@
|
||||
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/iommu.h>
|
||||
#include <linux/kref.h>
|
||||
|
||||
#include <asm/dma-iommu.h>
|
||||
|
||||
#include "exynos_drm_drv.h"
|
||||
#include "exynos_drm_iommu.h"
|
||||
|
||||
static inline int configure_dma_max_seg_size(struct device *dev)
|
||||
{
|
||||
if (!dev->dma_parms)
|
||||
dev->dma_parms = kzalloc(sizeof(*dev->dma_parms), GFP_KERNEL);
|
||||
if (!dev->dma_parms)
|
||||
return -ENOMEM;
|
||||
|
||||
dma_set_max_seg_size(dev, DMA_BIT_MASK(32));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void clear_dma_max_seg_size(struct device *dev)
|
||||
{
|
||||
kfree(dev->dma_parms);
|
||||
dev->dma_parms = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* drm_create_iommu_mapping - create a mapping structure
|
||||
*
|
||||
@ -28,38 +42,22 @@
|
||||
*/
|
||||
int drm_create_iommu_mapping(struct drm_device *drm_dev)
|
||||
{
|
||||
struct dma_iommu_mapping *mapping = NULL;
|
||||
struct exynos_drm_private *priv = drm_dev->dev_private;
|
||||
|
||||
if (!priv->da_start)
|
||||
priv->da_start = EXYNOS_DEV_ADDR_START;
|
||||
if (!priv->da_space_size)
|
||||
priv->da_space_size = EXYNOS_DEV_ADDR_SIZE;
|
||||
|
||||
mapping = arm_iommu_create_mapping(&platform_bus_type, priv->da_start,
|
||||
priv->da_space_size);
|
||||
|
||||
if (IS_ERR(mapping))
|
||||
return PTR_ERR(mapping);
|
||||
|
||||
priv->mapping = mapping;
|
||||
|
||||
return 0;
|
||||
return __exynos_iommu_create_mapping(priv, EXYNOS_DEV_ADDR_START,
|
||||
EXYNOS_DEV_ADDR_SIZE);
|
||||
}
|
||||
|
||||
/*
|
||||
* drm_release_iommu_mapping - release iommu mapping structure
|
||||
*
|
||||
* @drm_dev: DRM device
|
||||
*
|
||||
* if mapping->kref becomes 0 then all things related to iommu mapping
|
||||
* will be released
|
||||
*/
|
||||
void drm_release_iommu_mapping(struct drm_device *drm_dev)
|
||||
{
|
||||
struct exynos_drm_private *priv = drm_dev->dev_private;
|
||||
|
||||
arm_iommu_release_mapping(priv->mapping);
|
||||
__exynos_iommu_release_mapping(priv);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -77,26 +75,20 @@ int drm_iommu_attach_device(struct drm_device *drm_dev,
|
||||
struct exynos_drm_private *priv = drm_dev->dev_private;
|
||||
int ret;
|
||||
|
||||
if (!priv->mapping)
|
||||
return 0;
|
||||
|
||||
subdrv_dev->dma_parms = devm_kzalloc(subdrv_dev,
|
||||
sizeof(*subdrv_dev->dma_parms),
|
||||
GFP_KERNEL);
|
||||
if (!subdrv_dev->dma_parms)
|
||||
return -ENOMEM;
|
||||
|
||||
dma_set_max_seg_size(subdrv_dev, 0xffffffffu);
|
||||
|
||||
if (subdrv_dev->archdata.mapping)
|
||||
arm_iommu_detach_device(subdrv_dev);
|
||||
|
||||
ret = arm_iommu_attach_device(subdrv_dev, priv->mapping);
|
||||
if (ret < 0) {
|
||||
DRM_DEBUG_KMS("failed iommu attach.\n");
|
||||
return ret;
|
||||
if (get_dma_ops(priv->dma_dev) != get_dma_ops(subdrv_dev)) {
|
||||
DRM_ERROR("Device %s lacks support for IOMMU\n",
|
||||
dev_name(subdrv_dev));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = configure_dma_max_seg_size(subdrv_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = __exynos_iommu_attach(priv, subdrv_dev);
|
||||
if (ret)
|
||||
clear_dma_max_seg_size(subdrv_dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -113,10 +105,7 @@ void drm_iommu_detach_device(struct drm_device *drm_dev,
|
||||
struct device *subdrv_dev)
|
||||
{
|
||||
struct exynos_drm_private *priv = drm_dev->dev_private;
|
||||
struct dma_iommu_mapping *mapping = priv->mapping;
|
||||
|
||||
if (!mapping || !mapping->domain)
|
||||
return;
|
||||
|
||||
arm_iommu_detach_device(subdrv_dev);
|
||||
__exynos_iommu_detach(priv, subdrv_dev);
|
||||
clear_dma_max_seg_size(subdrv_dev);
|
||||
}
|
||||
|
@ -17,6 +17,97 @@
|
||||
|
||||
#ifdef CONFIG_DRM_EXYNOS_IOMMU
|
||||
|
||||
#if defined(CONFIG_ARM_DMA_USE_IOMMU)
|
||||
#include <asm/dma-iommu.h>
|
||||
|
||||
static inline int __exynos_iommu_create_mapping(struct exynos_drm_private *priv,
|
||||
unsigned long start, unsigned long size)
|
||||
{
|
||||
priv->mapping = arm_iommu_create_mapping(&platform_bus_type, start,
|
||||
size);
|
||||
return IS_ERR(priv->mapping);
|
||||
}
|
||||
|
||||
static inline void
|
||||
__exynos_iommu_release_mapping(struct exynos_drm_private *priv)
|
||||
{
|
||||
arm_iommu_release_mapping(priv->mapping);
|
||||
}
|
||||
|
||||
static inline int __exynos_iommu_attach(struct exynos_drm_private *priv,
|
||||
struct device *dev)
|
||||
{
|
||||
if (dev->archdata.mapping)
|
||||
arm_iommu_detach_device(dev);
|
||||
|
||||
return arm_iommu_attach_device(dev, priv->mapping);
|
||||
}
|
||||
|
||||
static inline void __exynos_iommu_detach(struct exynos_drm_private *priv,
|
||||
struct device *dev)
|
||||
{
|
||||
arm_iommu_detach_device(dev);
|
||||
}
|
||||
|
||||
#elif defined(CONFIG_IOMMU_DMA)
|
||||
#include <linux/dma-iommu.h>
|
||||
|
||||
static inline int __exynos_iommu_create_mapping(struct exynos_drm_private *priv,
|
||||
unsigned long start, unsigned long size)
|
||||
{
|
||||
struct iommu_domain *domain;
|
||||
int ret;
|
||||
|
||||
domain = iommu_domain_alloc(priv->dma_dev->bus);
|
||||
if (!domain)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = iommu_get_dma_cookie(domain);
|
||||
if (ret)
|
||||
goto free_domain;
|
||||
|
||||
ret = iommu_dma_init_domain(domain, start, size);
|
||||
if (ret)
|
||||
goto put_cookie;
|
||||
|
||||
priv->mapping = domain;
|
||||
return 0;
|
||||
|
||||
put_cookie:
|
||||
iommu_put_dma_cookie(domain);
|
||||
free_domain:
|
||||
iommu_domain_free(domain);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void __exynos_iommu_release_mapping(struct exynos_drm_private *priv)
|
||||
{
|
||||
struct iommu_domain *domain = priv->mapping;
|
||||
|
||||
iommu_put_dma_cookie(domain);
|
||||
iommu_domain_free(domain);
|
||||
priv->mapping = NULL;
|
||||
}
|
||||
|
||||
static inline int __exynos_iommu_attach(struct exynos_drm_private *priv,
|
||||
struct device *dev)
|
||||
{
|
||||
struct iommu_domain *domain = priv->mapping;
|
||||
|
||||
return iommu_attach_device(domain, dev);
|
||||
}
|
||||
|
||||
static inline void __exynos_iommu_detach(struct exynos_drm_private *priv,
|
||||
struct device *dev)
|
||||
{
|
||||
struct iommu_domain *domain = priv->mapping;
|
||||
|
||||
iommu_detach_device(domain, dev);
|
||||
}
|
||||
#else
|
||||
#error Unsupported architecture and IOMMU/DMA-mapping glue code
|
||||
#endif
|
||||
|
||||
int drm_create_iommu_mapping(struct drm_device *drm_dev);
|
||||
|
||||
void drm_release_iommu_mapping(struct drm_device *drm_dev);
|
||||
|
Loading…
Reference in New Issue
Block a user