![Robin Murphy](/assets/img/avatar_default.png)
With our DMA ops enabled for PCI devices, we should avoid allocating IOVAs which a host bridge might misinterpret as peer-to-peer DMA and lead to faults, corruption or other badness. To be safe, punch out holes for all of the relevant host bridge's windows when initialising a DMA domain for a PCI device. CC: Marek Szyprowski <m.szyprowski@samsung.com> CC: Inki Dae <inki.dae@samsung.com> Reported-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> Signed-off-by: Robin Murphy <robin.murphy@arm.com> Signed-off-by: Will Deacon <will.deacon@arm.com>
157 lines
3.5 KiB
C
157 lines
3.5 KiB
C
/* exynos_drm_iommu.h
|
|
*
|
|
* Copyright (c) 2012 Samsung Electronics Co., Ltd.
|
|
* Authoer: Inki Dae <inki.dae@samsung.com>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License as published by the
|
|
* Free Software Foundation; either version 2 of the License, or (at your
|
|
* option) any later version.
|
|
*/
|
|
|
|
#ifndef _EXYNOS_DRM_IOMMU_H_
|
|
#define _EXYNOS_DRM_IOMMU_H_
|
|
|
|
#define EXYNOS_DEV_ADDR_START 0x20000000
|
|
#define EXYNOS_DEV_ADDR_SIZE 0x40000000
|
|
|
|
#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, NULL);
|
|
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);
|
|
|
|
int drm_iommu_attach_device(struct drm_device *drm_dev,
|
|
struct device *subdrv_dev);
|
|
|
|
void drm_iommu_detach_device(struct drm_device *dev_dev,
|
|
struct device *subdrv_dev);
|
|
|
|
static inline bool is_drm_iommu_supported(struct drm_device *drm_dev)
|
|
{
|
|
struct exynos_drm_private *priv = drm_dev->dev_private;
|
|
|
|
return priv->mapping ? true : false;
|
|
}
|
|
|
|
#else
|
|
|
|
static inline int drm_create_iommu_mapping(struct drm_device *drm_dev)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static inline void drm_release_iommu_mapping(struct drm_device *drm_dev)
|
|
{
|
|
}
|
|
|
|
static inline int drm_iommu_attach_device(struct drm_device *drm_dev,
|
|
struct device *subdrv_dev)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static inline void drm_iommu_detach_device(struct drm_device *drm_dev,
|
|
struct device *subdrv_dev)
|
|
{
|
|
}
|
|
|
|
static inline bool is_drm_iommu_supported(struct drm_device *drm_dev)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
#endif
|
|
#endif
|