drm/msm: Support different SMMU backends for address spaces
SDE and the GPU have different requirements for the SMMU backends - the SDE generates its own iova addresses and needs special support for DMA buffers and the GPU does its own IOMMU operations. Add a shim layer to aspace to break out the address generation and call the appropriate SMMU functions. There is probably consolidation that can be done, but for now this is the best way to deal with the two use cases. Change-Id: Ic0dedbadc6dc03504ef7dffded18ba09fb3ef291 Signed-off-by: Jordan Crouse <jcrouse@codeaurora.org>
This commit is contained in:
parent
1de066f014
commit
ffd2f3eb42
10 changed files with 264 additions and 84 deletions
|
@ -192,11 +192,21 @@ static void mdp4_preclose(struct msm_kms *kms, struct drm_file *file)
|
||||||
|
|
||||||
static void mdp4_destroy(struct msm_kms *kms)
|
static void mdp4_destroy(struct msm_kms *kms)
|
||||||
{
|
{
|
||||||
|
struct device *dev = mdp4_kms->dev->dev;
|
||||||
|
struct msm_gem_address_space *aspace = mdp4_kms->aspace;
|
||||||
|
|
||||||
struct mdp4_kms *mdp4_kms = to_mdp4_kms(to_mdp_kms(kms));
|
struct mdp4_kms *mdp4_kms = to_mdp4_kms(to_mdp_kms(kms));
|
||||||
if (mdp4_kms->blank_cursor_iova)
|
if (mdp4_kms->blank_cursor_iova)
|
||||||
msm_gem_put_iova(mdp4_kms->blank_cursor_bo, mdp4_kms->id);
|
msm_gem_put_iova(mdp4_kms->blank_cursor_bo, mdp4_kms->id);
|
||||||
if (mdp4_kms->blank_cursor_bo)
|
if (mdp4_kms->blank_cursor_bo)
|
||||||
drm_gem_object_unreference_unlocked(mdp4_kms->blank_cursor_bo);
|
drm_gem_object_unreference_unlocked(mdp4_kms->blank_cursor_bo);
|
||||||
|
|
||||||
|
if (aspace) {
|
||||||
|
aspace->mmu->funcs->detach(aspace->mmu,
|
||||||
|
iommu_ports, ARRAY_SIZE(iommu_ports));
|
||||||
|
msm_gem_address_space_destroy(aspace);
|
||||||
|
}
|
||||||
|
|
||||||
kfree(mdp4_kms);
|
kfree(mdp4_kms);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -416,7 +426,6 @@ struct msm_kms *mdp4_kms_init(struct drm_device *dev)
|
||||||
struct mdp4_platform_config *config = mdp4_get_config(pdev);
|
struct mdp4_platform_config *config = mdp4_get_config(pdev);
|
||||||
struct mdp4_kms *mdp4_kms;
|
struct mdp4_kms *mdp4_kms;
|
||||||
struct msm_kms *kms = NULL;
|
struct msm_kms *kms = NULL;
|
||||||
struct msm_mmu *mmu;
|
|
||||||
struct msm_gem_address_space *aspace;
|
struct msm_gem_address_space *aspace;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
@ -506,8 +515,15 @@ struct msm_kms *mdp4_kms_init(struct drm_device *dev)
|
||||||
mdelay(16);
|
mdelay(16);
|
||||||
|
|
||||||
if (config->iommu) {
|
if (config->iommu) {
|
||||||
|
struct msm_mmu *mmu = msm_iommu_new(&pdev->dev, config->iommu);
|
||||||
|
|
||||||
|
if (IS_ERR(mmu)) {
|
||||||
|
ret = PTR_ERR(mmu);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
aspace = msm_gem_address_space_create(&pdev->dev,
|
aspace = msm_gem_address_space_create(&pdev->dev,
|
||||||
config->iommu, "mdp4");
|
mmu, "mdp4", 0x1000, 0xffffffff);
|
||||||
if (IS_ERR(aspace)) {
|
if (IS_ERR(aspace)) {
|
||||||
ret = PTR_ERR(aspace);
|
ret = PTR_ERR(aspace);
|
||||||
goto fail;
|
goto fail;
|
||||||
|
@ -575,6 +591,7 @@ static struct mdp4_platform_config *mdp4_get_config(struct platform_device *dev)
|
||||||
/* TODO */
|
/* TODO */
|
||||||
config.max_clk = 266667000;
|
config.max_clk = 266667000;
|
||||||
config.iommu = iommu_domain_alloc(msm_iommu_get_bus(&dev->dev));
|
config.iommu = iommu_domain_alloc(msm_iommu_get_bus(&dev->dev));
|
||||||
|
|
||||||
#else
|
#else
|
||||||
if (cpu_is_apq8064())
|
if (cpu_is_apq8064())
|
||||||
config.max_clk = 266667000;
|
config.max_clk = 266667000;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2014, 2016, The Linux Foundation. All rights reserved.
|
* Copyright (c) 2014, 2016-2017 The Linux Foundation. All rights reserved.
|
||||||
* Copyright (C) 2013 Red Hat
|
* Copyright (C) 2013 Red Hat
|
||||||
* Author: Rob Clark <robdclark@gmail.com>
|
* Author: Rob Clark <robdclark@gmail.com>
|
||||||
*
|
*
|
||||||
|
@ -18,6 +18,7 @@
|
||||||
|
|
||||||
|
|
||||||
#include "msm_drv.h"
|
#include "msm_drv.h"
|
||||||
|
#include "msm_gem.h"
|
||||||
#include "msm_mmu.h"
|
#include "msm_mmu.h"
|
||||||
#include "mdp5_kms.h"
|
#include "mdp5_kms.h"
|
||||||
|
|
||||||
|
@ -130,13 +131,14 @@ static void mdp5_preclose(struct msm_kms *kms, struct drm_file *file)
|
||||||
static void mdp5_destroy(struct msm_kms *kms)
|
static void mdp5_destroy(struct msm_kms *kms)
|
||||||
{
|
{
|
||||||
struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
|
struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
|
||||||
struct msm_mmu *mmu = mdp5_kms->mmu;
|
struct msm_gem_address_space *aspace = mdp5_kms->aspace;
|
||||||
|
|
||||||
mdp5_irq_domain_fini(mdp5_kms);
|
mdp5_irq_domain_fini(mdp5_kms);
|
||||||
|
|
||||||
if (mmu) {
|
if (aspace) {
|
||||||
mmu->funcs->detach(mmu, iommu_ports, ARRAY_SIZE(iommu_ports));
|
aspace->mmu->funcs->detach(aspace->mmu,
|
||||||
mmu->funcs->destroy(mmu);
|
iommu_ports, ARRAY_SIZE(iommu_ports));
|
||||||
|
msm_gem_address_space_destroy(aspace);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mdp5_kms->ctlm)
|
if (mdp5_kms->ctlm)
|
||||||
|
@ -474,7 +476,7 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev)
|
||||||
struct mdp5_cfg *config;
|
struct mdp5_cfg *config;
|
||||||
struct mdp5_kms *mdp5_kms;
|
struct mdp5_kms *mdp5_kms;
|
||||||
struct msm_kms *kms = NULL;
|
struct msm_kms *kms = NULL;
|
||||||
struct msm_mmu *mmu;
|
struct msm_gem_address_space *aspace;
|
||||||
uint32_t major, minor;
|
uint32_t major, minor;
|
||||||
int i, ret;
|
int i, ret;
|
||||||
|
|
||||||
|
@ -595,30 +597,37 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev)
|
||||||
mdelay(16);
|
mdelay(16);
|
||||||
|
|
||||||
if (config->platform.iommu) {
|
if (config->platform.iommu) {
|
||||||
mmu = msm_smmu_new(&pdev->dev,
|
struct msm_mmu *mmu = msm_smmu_new(&pdev->dev,
|
||||||
MSM_SMMU_DOMAIN_UNSECURE);
|
MSM_SMMU_DOMAIN_UNSECURE);
|
||||||
if (IS_ERR(mmu)) {
|
if (IS_ERR(mmu)) {
|
||||||
ret = PTR_ERR(mmu);
|
ret = PTR_ERR(mmu);
|
||||||
dev_err(dev->dev, "failed to init iommu: %d\n", ret);
|
dev_err(dev->dev, "failed to init iommu: %d\n", ret);
|
||||||
iommu_domain_free(config->platform.iommu);
|
iommu_domain_free(config->platform.iommu);
|
||||||
|
}
|
||||||
|
|
||||||
|
aspace = msm_gem_smmu_address_space_create(&pdev->dev,
|
||||||
|
mmu, "mdp5");
|
||||||
|
if (IS_ERR(aspace)) {
|
||||||
|
ret = PTR_ERR(aspace);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = mmu->funcs->attach(mmu, iommu_ports,
|
mdp5_kms->aspace = aspace;
|
||||||
|
|
||||||
|
ret = aspace->mmu->funcs->attach(aspace->mmu, iommu_ports,
|
||||||
ARRAY_SIZE(iommu_ports));
|
ARRAY_SIZE(iommu_ports));
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(dev->dev, "failed to attach iommu: %d\n", ret);
|
dev_err(&pdev->dev, "failed to attach iommu: %d\n",
|
||||||
mmu->funcs->destroy(mmu);
|
ret);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
dev_info(dev->dev, "no iommu, fallback to phys "
|
dev_info(&pdev->dev,
|
||||||
"contig buffers for scanout\n");
|
"no iommu, fallback to phys contig buffers for scanout\n");
|
||||||
mmu = NULL;
|
aspace = NULL;
|
||||||
}
|
}
|
||||||
mdp5_kms->mmu = mmu;
|
|
||||||
|
|
||||||
mdp5_kms->id = msm_register_mmu(dev, mmu);
|
mdp5_kms->id = msm_register_address_space(dev, aspace);
|
||||||
if (mdp5_kms->id < 0) {
|
if (mdp5_kms->id < 0) {
|
||||||
ret = mdp5_kms->id;
|
ret = mdp5_kms->id;
|
||||||
dev_err(dev->dev, "failed to register mdp5 iommu: %d\n", ret);
|
dev_err(dev->dev, "failed to register mdp5 iommu: %d\n", ret);
|
||||||
|
|
|
@ -37,7 +37,7 @@ struct mdp5_kms {
|
||||||
|
|
||||||
/* mapper-id used to request GEM buffer mapped for scanout: */
|
/* mapper-id used to request GEM buffer mapped for scanout: */
|
||||||
int id;
|
int id;
|
||||||
struct msm_mmu *mmu;
|
struct msm_gem_address_space *aspace;
|
||||||
|
|
||||||
struct mdp5_smp *smp;
|
struct mdp5_smp *smp;
|
||||||
struct mdp5_ctl_manager *ctlm;
|
struct mdp5_ctl_manager *ctlm;
|
||||||
|
|
|
@ -368,31 +368,32 @@ void __msm_fence_worker(struct work_struct *work);
|
||||||
int msm_atomic_commit(struct drm_device *dev,
|
int msm_atomic_commit(struct drm_device *dev,
|
||||||
struct drm_atomic_state *state, bool async);
|
struct drm_atomic_state *state, bool async);
|
||||||
|
|
||||||
static inline int msm_register_mmu(struct drm_device *dev,
|
|
||||||
struct msm_mmu *mmu) {
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
static inline void msm_unregister_mmu(struct drm_device *dev,
|
|
||||||
struct msm_mmu *mmu) {
|
|
||||||
}
|
|
||||||
int msm_wait_fence(struct drm_device *dev, uint32_t fence,
|
int msm_wait_fence(struct drm_device *dev, uint32_t fence,
|
||||||
ktime_t *timeout, bool interruptible);
|
ktime_t *timeout, bool interruptible);
|
||||||
int msm_queue_fence_cb(struct drm_device *dev,
|
int msm_queue_fence_cb(struct drm_device *dev,
|
||||||
struct msm_fence_cb *cb, uint32_t fence);
|
struct msm_fence_cb *cb, uint32_t fence);
|
||||||
void msm_update_fence(struct drm_device *dev, uint32_t fence);
|
void msm_update_fence(struct drm_device *dev, uint32_t fence);
|
||||||
|
|
||||||
int msm_register_address_space(struct drm_device *dev,
|
int msm_register_address_space(struct drm_device *dev,
|
||||||
struct msm_gem_address_space *aspace);
|
struct msm_gem_address_space *aspace);
|
||||||
|
|
||||||
void msm_gem_unmap_vma(struct msm_gem_address_space *aspace,
|
void msm_gem_unmap_vma(struct msm_gem_address_space *aspace,
|
||||||
struct msm_gem_vma *vma, struct sg_table *sgt);
|
struct msm_gem_vma *vma, struct sg_table *sgt,
|
||||||
|
void *priv);
|
||||||
int msm_gem_map_vma(struct msm_gem_address_space *aspace,
|
int msm_gem_map_vma(struct msm_gem_address_space *aspace,
|
||||||
struct msm_gem_vma *vma, struct sg_table *sgt, int npages);
|
struct msm_gem_vma *vma, struct sg_table *sgt,
|
||||||
|
void *priv);
|
||||||
void msm_gem_address_space_destroy(struct msm_gem_address_space *aspace);
|
void msm_gem_address_space_destroy(struct msm_gem_address_space *aspace);
|
||||||
|
|
||||||
|
/* For GPU and legacy display */
|
||||||
struct msm_gem_address_space *
|
struct msm_gem_address_space *
|
||||||
msm_gem_address_space_create(struct device *dev, struct iommu_domain *domain,
|
msm_gem_address_space_create(struct device *dev, struct iommu_domain *domain,
|
||||||
const char *name);
|
const char *name);
|
||||||
|
|
||||||
|
/* For SDE display */
|
||||||
|
struct msm_gem_address_space *
|
||||||
|
msm_gem_smmu_address_space_create(struct device *dev, struct msm_mmu *mmu,
|
||||||
|
const char *name);
|
||||||
|
|
||||||
int msm_ioctl_gem_submit(struct drm_device *dev, void *data,
|
int msm_ioctl_gem_submit(struct drm_device *dev, void *data,
|
||||||
struct drm_file *file);
|
struct drm_file *file);
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,11 @@
|
||||||
#include "msm_gpu.h"
|
#include "msm_gpu.h"
|
||||||
#include "msm_mmu.h"
|
#include "msm_mmu.h"
|
||||||
|
|
||||||
|
static void *get_dmabuf_ptr(struct drm_gem_object *obj)
|
||||||
|
{
|
||||||
|
return (obj && obj->import_attach) ? obj->import_attach->dmabuf : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static dma_addr_t physaddr(struct drm_gem_object *obj)
|
static dma_addr_t physaddr(struct drm_gem_object *obj)
|
||||||
{
|
{
|
||||||
struct msm_gem_object *msm_obj = to_msm_bo(obj);
|
struct msm_gem_object *msm_obj = to_msm_bo(obj);
|
||||||
|
@ -279,8 +284,8 @@ put_iova(struct drm_gem_object *obj)
|
||||||
WARN_ON(!mutex_is_locked(&dev->struct_mutex));
|
WARN_ON(!mutex_is_locked(&dev->struct_mutex));
|
||||||
|
|
||||||
for (id = 0; id < ARRAY_SIZE(msm_obj->domain); id++) {
|
for (id = 0; id < ARRAY_SIZE(msm_obj->domain); id++) {
|
||||||
msm_gem_unmap_vma(priv->aspace[id],
|
msm_gem_unmap_vma(priv->aspace[id], &msm_obj->domain[id],
|
||||||
&msm_obj->domain[id], msm_obj->sgt);
|
msm_obj->sgt, get_dmabuf_ptr(obj));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -305,12 +310,11 @@ int msm_gem_get_iova_locked(struct drm_gem_object *obj, int id,
|
||||||
return PTR_ERR(pages);
|
return PTR_ERR(pages);
|
||||||
|
|
||||||
if (iommu_present(&platform_bus_type)) {
|
if (iommu_present(&platform_bus_type)) {
|
||||||
ret = msm_gem_map_vma(priv->aspace[id], &msm_obj->domain[id],
|
ret = msm_gem_map_vma(priv->aspace[id],
|
||||||
msm_obj->sgt, obj->size >> PAGE_SHIFT);
|
&msm_obj->domain[id], msm_obj->sgt,
|
||||||
} else {
|
get_dmabuf_ptr(obj));
|
||||||
WARN_ONCE(1, "physical address being used\n");
|
} else
|
||||||
msm_obj->domain[id].iova = physaddr(obj);
|
msm_obj->domain[id].iova = physaddr(obj);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ret)
|
if (!ret)
|
||||||
|
@ -485,7 +489,7 @@ 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 msm_drm_private *priv = obj->dev->dev_private;
|
struct msm_drm_private *priv = obj->dev->dev_private;
|
||||||
uint64_t off = drm_vma_node_start(&obj->vma_node);
|
uint64_t off = drm_vma_node_start(&obj->vma_node);
|
||||||
unsigned id;
|
int id;
|
||||||
|
|
||||||
WARN_ON(!mutex_is_locked(&dev->struct_mutex));
|
WARN_ON(!mutex_is_locked(&dev->struct_mutex));
|
||||||
seq_printf(m, "%08x: %c(r=%u,w=%u) %2d (%2d) %08llx %p\t",
|
seq_printf(m, "%08x: %c(r=%u,w=%u) %2d (%2d) %08llx %p\t",
|
||||||
|
@ -496,6 +500,8 @@ void msm_gem_describe(struct drm_gem_object *obj, struct seq_file *m)
|
||||||
|
|
||||||
for (id = 0; id < priv->num_aspaces; id++)
|
for (id = 0; id < priv->num_aspaces; id++)
|
||||||
seq_printf(m, " %08llx", msm_obj->domain[id].iova);
|
seq_printf(m, " %08llx", msm_obj->domain[id].iova);
|
||||||
|
|
||||||
|
seq_puts(m, "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void msm_gem_describe_objects(struct list_head *list, struct seq_file *m)
|
void msm_gem_describe_objects(struct list_head *list, struct seq_file *m)
|
||||||
|
@ -532,7 +538,8 @@ void msm_gem_free_object(struct drm_gem_object *obj)
|
||||||
|
|
||||||
if (obj->import_attach) {
|
if (obj->import_attach) {
|
||||||
if (msm_obj->vaddr)
|
if (msm_obj->vaddr)
|
||||||
dma_buf_vunmap(obj->import_attach->dmabuf, msm_obj->vaddr);
|
dma_buf_vunmap(obj->import_attach->dmabuf,
|
||||||
|
msm_obj->vaddr);
|
||||||
|
|
||||||
/* Don't drop the pages for imported dmabuf, as they are not
|
/* Don't drop the pages for imported dmabuf, as they are not
|
||||||
* ours, just free the array we allocated:
|
* ours, just free the array we allocated:
|
||||||
|
|
|
@ -24,16 +24,24 @@
|
||||||
/* Additional internal-use only BO flags: */
|
/* Additional internal-use only BO flags: */
|
||||||
#define MSM_BO_STOLEN 0x10000000 /* try to use stolen/splash memory */
|
#define MSM_BO_STOLEN 0x10000000 /* try to use stolen/splash memory */
|
||||||
|
|
||||||
|
struct msm_gem_aspace_ops {
|
||||||
|
int (*map)(struct msm_gem_address_space *, struct msm_gem_vma *,
|
||||||
|
struct sg_table *sgt, void *priv);
|
||||||
|
|
||||||
|
void (*unmap)(struct msm_gem_address_space *, struct msm_gem_vma *,
|
||||||
|
struct sg_table *sgt, void *priv);
|
||||||
|
|
||||||
|
void (*destroy)(struct msm_gem_address_space *);
|
||||||
|
};
|
||||||
|
|
||||||
struct msm_gem_address_space {
|
struct msm_gem_address_space {
|
||||||
const char *name;
|
const char *name;
|
||||||
/* NOTE: mm managed at the page level, size is in # of pages
|
|
||||||
* and position mm_node->start is in # of pages:
|
|
||||||
*/
|
|
||||||
struct drm_mm mm;
|
|
||||||
struct msm_mmu *mmu;
|
struct msm_mmu *mmu;
|
||||||
|
const struct msm_gem_aspace_ops *ops;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct msm_gem_vma {
|
struct msm_gem_vma {
|
||||||
|
/* Node used by the GPU address space, but not the SDE address space */
|
||||||
struct drm_mm_node node;
|
struct drm_mm_node node;
|
||||||
uint64_t iova;
|
uint64_t iova;
|
||||||
};
|
};
|
||||||
|
|
|
@ -19,9 +19,81 @@
|
||||||
#include "msm_gem.h"
|
#include "msm_gem.h"
|
||||||
#include "msm_mmu.h"
|
#include "msm_mmu.h"
|
||||||
|
|
||||||
void
|
/* SDE address space operations */
|
||||||
msm_gem_unmap_vma(struct msm_gem_address_space *aspace,
|
static void smmu_aspace_unmap_vma(struct msm_gem_address_space *aspace,
|
||||||
struct msm_gem_vma *vma, struct sg_table *sgt)
|
struct msm_gem_vma *vma, struct sg_table *sgt,
|
||||||
|
void *priv)
|
||||||
|
{
|
||||||
|
struct dma_buf *buf = priv;
|
||||||
|
|
||||||
|
if (buf)
|
||||||
|
aspace->mmu->funcs->unmap_dma_buf(aspace->mmu,
|
||||||
|
sgt, buf, DMA_BIDIRECTIONAL);
|
||||||
|
else
|
||||||
|
aspace->mmu->funcs->unmap_sg(aspace->mmu, sgt,
|
||||||
|
DMA_BIDIRECTIONAL);
|
||||||
|
|
||||||
|
vma->iova = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int smmu_aspace_map_vma(struct msm_gem_address_space *aspace,
|
||||||
|
struct msm_gem_vma *vma, struct sg_table *sgt,
|
||||||
|
void *priv)
|
||||||
|
{
|
||||||
|
struct dma_buf *buf = priv;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (buf)
|
||||||
|
ret = aspace->mmu->funcs->map_dma_buf(aspace->mmu, sgt, buf,
|
||||||
|
DMA_BIDIRECTIONAL);
|
||||||
|
else
|
||||||
|
ret = aspace->mmu->funcs->map_sg(aspace->mmu, sgt,
|
||||||
|
DMA_BIDIRECTIONAL);
|
||||||
|
|
||||||
|
if (!ret)
|
||||||
|
vma->iova = sg_dma_address(sgt->sgl);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct msm_gem_aspace_ops smmu_aspace_ops = {
|
||||||
|
.map = smmu_aspace_map_vma,
|
||||||
|
.unmap = smmu_aspace_unmap_vma,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct msm_gem_address_space *
|
||||||
|
msm_gem_smmu_address_space_create(struct device *dev, struct msm_mmu *mmu,
|
||||||
|
const char *name)
|
||||||
|
{
|
||||||
|
struct msm_gem_address_space *aspace;
|
||||||
|
|
||||||
|
if (!mmu)
|
||||||
|
return ERR_PTR(-EINVAL);
|
||||||
|
|
||||||
|
aspace = kzalloc(sizeof(*aspace), GFP_KERNEL);
|
||||||
|
if (!aspace)
|
||||||
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
|
aspace->name = name;
|
||||||
|
aspace->mmu = mmu;
|
||||||
|
aspace->ops = &smmu_aspace_ops;
|
||||||
|
|
||||||
|
return aspace;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* GPU address space operations */
|
||||||
|
struct msm_iommu_aspace {
|
||||||
|
struct msm_gem_address_space base;
|
||||||
|
struct drm_mm mm;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define to_iommu_aspace(aspace) \
|
||||||
|
((struct msm_iommu_aspace *) \
|
||||||
|
container_of(aspace, struct msm_iommu_aspace, base))
|
||||||
|
|
||||||
|
static void iommu_aspace_unmap_vma(struct msm_gem_address_space *aspace,
|
||||||
|
struct msm_gem_vma *vma, struct sg_table *sgt, void *priv)
|
||||||
{
|
{
|
||||||
if (!vma->iova)
|
if (!vma->iova)
|
||||||
return;
|
return;
|
||||||
|
@ -34,16 +106,22 @@ msm_gem_unmap_vma(struct msm_gem_address_space *aspace,
|
||||||
vma->iova = 0;
|
vma->iova = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
static int iommu_aspace_map_vma(struct msm_gem_address_space *aspace,
|
||||||
msm_gem_map_vma(struct msm_gem_address_space *aspace,
|
struct msm_gem_vma *vma, struct sg_table *sgt,
|
||||||
struct msm_gem_vma *vma, struct sg_table *sgt, int npages)
|
void *priv)
|
||||||
{
|
{
|
||||||
int ret;
|
struct msm_iommu_aspace *local = to_iommu_aspace(aspace);
|
||||||
|
size_t size = 0;
|
||||||
|
struct scatterlist *sg;
|
||||||
|
int ret = 0, i;
|
||||||
|
|
||||||
if (WARN_ON(drm_mm_node_allocated(&vma->node)))
|
if (WARN_ON(drm_mm_node_allocated(&vma->node)))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
ret = drm_mm_insert_node(&aspace->mm, &vma->node, npages,
|
for_each_sg(sgt->sgl, sg, sgt->nents, i)
|
||||||
|
size += sg->length + sg->offset;
|
||||||
|
|
||||||
|
ret = drm_mm_insert_node(&local->mm, &vma->node, size >> PAGE_SHIFT,
|
||||||
0, DRM_MM_SEARCH_DEFAULT);
|
0, DRM_MM_SEARCH_DEFAULT);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -51,36 +129,85 @@ msm_gem_map_vma(struct msm_gem_address_space *aspace,
|
||||||
vma->iova = vma->node.start << PAGE_SHIFT;
|
vma->iova = vma->node.start << PAGE_SHIFT;
|
||||||
|
|
||||||
if (aspace->mmu)
|
if (aspace->mmu)
|
||||||
ret = aspace->mmu->funcs->map(aspace->mmu, vma->iova, sgt,
|
ret = aspace->mmu->funcs->map(aspace->mmu, vma->iova,
|
||||||
IOMMU_READ | IOMMU_WRITE);
|
sgt, IOMMU_READ | IOMMU_WRITE);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
static void iommu_aspace_destroy(struct msm_gem_address_space *aspace)
|
||||||
msm_gem_address_space_destroy(struct msm_gem_address_space *aspace)
|
|
||||||
{
|
{
|
||||||
drm_mm_takedown(&aspace->mm);
|
struct msm_iommu_aspace *local = to_iommu_aspace(aspace);
|
||||||
if (aspace->mmu)
|
|
||||||
aspace->mmu->funcs->destroy(aspace->mmu);
|
drm_mm_takedown(&local->mm);
|
||||||
kfree(aspace);
|
aspace->mmu->funcs->destroy(aspace->mmu);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct msm_gem_aspace_ops msm_iommu_aspace_ops = {
|
||||||
|
.map = iommu_aspace_map_vma,
|
||||||
|
.unmap = iommu_aspace_unmap_vma,
|
||||||
|
.destroy = iommu_aspace_destroy,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct msm_gem_address_space *
|
||||||
|
msm_gem_address_space_new(struct msm_mmu *mmu, const char *name,
|
||||||
|
uint64_t start, uint64_t end)
|
||||||
|
{
|
||||||
|
struct msm_iommu_aspace *local;
|
||||||
|
|
||||||
|
if (!mmu)
|
||||||
|
return ERR_PTR(-EINVAL);
|
||||||
|
|
||||||
|
local = kzalloc(sizeof(*local), GFP_KERNEL);
|
||||||
|
if (!local)
|
||||||
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
|
drm_mm_init(&local->mm, (start >> PAGE_SHIFT),
|
||||||
|
(end >> PAGE_SHIFT) - 1);
|
||||||
|
|
||||||
|
local->base.name = name;
|
||||||
|
local->base.mmu = mmu;
|
||||||
|
local->base.ops = &msm_iommu_aspace_ops;
|
||||||
|
|
||||||
|
return &local->base;
|
||||||
|
}
|
||||||
|
|
||||||
|
int msm_gem_map_vma(struct msm_gem_address_space *aspace,
|
||||||
|
struct msm_gem_vma *vma, struct sg_table *sgt,
|
||||||
|
void *priv)
|
||||||
|
{
|
||||||
|
if (aspace && aspace->ops->map)
|
||||||
|
return aspace->ops->map(aspace, vma, sgt, priv);
|
||||||
|
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void msm_gem_unmap_vma(struct msm_gem_address_space *aspace,
|
||||||
|
struct msm_gem_vma *vma, struct sg_table *sgt, void *priv)
|
||||||
|
{
|
||||||
|
if (aspace && aspace->ops->unmap)
|
||||||
|
aspace->ops->unmap(aspace, vma, sgt, priv);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct msm_gem_address_space *
|
struct msm_gem_address_space *
|
||||||
msm_gem_address_space_create(struct device *dev, struct iommu_domain *domain,
|
msm_gem_address_space_create(struct device *dev, struct iommu_domain *domain,
|
||||||
const char *name)
|
const char *name)
|
||||||
{
|
{
|
||||||
struct msm_gem_address_space *aspace;
|
struct msm_mmu *mmu = msm_iommu_new(dev, domain);
|
||||||
|
|
||||||
aspace = kzalloc(sizeof(*aspace), GFP_KERNEL);
|
if (IS_ERR(mmu))
|
||||||
if (!aspace)
|
return (struct msm_gem_address_space *) mmu;
|
||||||
return ERR_PTR(-ENOMEM);
|
|
||||||
|
|
||||||
aspace->name = name;
|
return msm_gem_address_space_new(mmu, name,
|
||||||
aspace->mmu = msm_iommu_new(dev, domain);
|
domain->geometry.aperture_start,
|
||||||
|
domain->geometry.aperture_end);
|
||||||
drm_mm_init(&aspace->mm, (domain->geometry.aperture_start >> PAGE_SHIFT),
|
}
|
||||||
(domain->geometry.aperture_end >> PAGE_SHIFT) - 1);
|
|
||||||
|
void
|
||||||
return aspace;
|
msm_gem_address_space_destroy(struct msm_gem_address_space *aspace)
|
||||||
|
{
|
||||||
|
if (aspace && aspace->ops->destroy)
|
||||||
|
aspace->ops->destroy(aspace);
|
||||||
|
|
||||||
|
kfree(aspace);
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
#include <linux/iommu.h>
|
#include <linux/iommu.h>
|
||||||
|
|
||||||
struct msm_mmu;
|
struct msm_mmu;
|
||||||
struct msm_gpu;
|
|
||||||
|
|
||||||
enum msm_mmu_domain_type {
|
enum msm_mmu_domain_type {
|
||||||
MSM_SMMU_DOMAIN_UNSECURE,
|
MSM_SMMU_DOMAIN_UNSECURE,
|
||||||
|
@ -61,7 +60,6 @@ static inline void msm_mmu_init(struct msm_mmu *mmu, struct device *dev,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct msm_mmu *msm_iommu_new(struct device *dev, struct iommu_domain *domain);
|
struct msm_mmu *msm_iommu_new(struct device *dev, struct iommu_domain *domain);
|
||||||
struct msm_mmu *msm_gpummu_new(struct device *dev, struct msm_gpu *gpu);
|
|
||||||
struct msm_mmu *msm_smmu_new(struct device *dev,
|
struct msm_mmu *msm_smmu_new(struct device *dev,
|
||||||
enum msm_mmu_domain_type domain);
|
enum msm_mmu_domain_type domain);
|
||||||
|
|
||||||
|
|
|
@ -941,15 +941,15 @@ static int _sde_kms_mmu_destroy(struct sde_kms *sde_kms)
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = ARRAY_SIZE(sde_kms->mmu_id) - 1; i >= 0; i--) {
|
for (i = ARRAY_SIZE(sde_kms->mmu_id) - 1; i >= 0; i--) {
|
||||||
if (!sde_kms->mmu[i])
|
mmu = sde_kms->aspace[i]->mmu;
|
||||||
|
|
||||||
|
if (!mmu)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
mmu = sde_kms->mmu[i];
|
|
||||||
msm_unregister_mmu(sde_kms->dev, mmu);
|
|
||||||
mmu->funcs->detach(mmu, (const char **)iommu_ports,
|
mmu->funcs->detach(mmu, (const char **)iommu_ports,
|
||||||
ARRAY_SIZE(iommu_ports));
|
ARRAY_SIZE(iommu_ports));
|
||||||
mmu->funcs->destroy(mmu);
|
msm_gem_address_space_destroy(sde_kms->aspace[i]);
|
||||||
sde_kms->mmu[i] = 0;
|
|
||||||
sde_kms->mmu_id[i] = 0;
|
sde_kms->mmu_id[i] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -962,6 +962,8 @@ static int _sde_kms_mmu_init(struct sde_kms *sde_kms)
|
||||||
int i, ret;
|
int i, ret;
|
||||||
|
|
||||||
for (i = 0; i < MSM_SMMU_DOMAIN_MAX; i++) {
|
for (i = 0; i < MSM_SMMU_DOMAIN_MAX; i++) {
|
||||||
|
struct msm_gem_address_space *aspace;
|
||||||
|
|
||||||
mmu = msm_smmu_new(sde_kms->dev->dev, i);
|
mmu = msm_smmu_new(sde_kms->dev->dev, i);
|
||||||
if (IS_ERR(mmu)) {
|
if (IS_ERR(mmu)) {
|
||||||
/* MMU's can be optional depending on platform */
|
/* MMU's can be optional depending on platform */
|
||||||
|
@ -971,25 +973,35 @@ static int _sde_kms_mmu_init(struct sde_kms *sde_kms)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = mmu->funcs->attach(mmu, (const char **)iommu_ports,
|
aspace = msm_gem_smmu_address_space_create(sde_kms->dev->dev,
|
||||||
ARRAY_SIZE(iommu_ports));
|
mmu, "sde");
|
||||||
if (ret) {
|
if (IS_ERR(aspace)) {
|
||||||
SDE_ERROR("failed to attach iommu %d: %d\n", i, ret);
|
ret = PTR_ERR(aspace);
|
||||||
mmu->funcs->destroy(mmu);
|
mmu->funcs->destroy(mmu);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
sde_kms->mmu_id[i] = msm_register_mmu(sde_kms->dev, mmu);
|
sde_kms->aspace[i] = aspace;
|
||||||
|
|
||||||
|
ret = mmu->funcs->attach(mmu, (const char **)iommu_ports,
|
||||||
|
ARRAY_SIZE(iommu_ports));
|
||||||
|
if (ret) {
|
||||||
|
SDE_ERROR("failed to attach iommu %d: %d\n", i, ret);
|
||||||
|
msm_gem_address_space_destroy(aspace);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
sde_kms->mmu_id[i] = msm_register_address_space(sde_kms->dev,
|
||||||
|
aspace);
|
||||||
if (sde_kms->mmu_id[i] < 0) {
|
if (sde_kms->mmu_id[i] < 0) {
|
||||||
ret = sde_kms->mmu_id[i];
|
ret = sde_kms->mmu_id[i];
|
||||||
SDE_ERROR("failed to register sde iommu %d: %d\n",
|
SDE_ERROR("failed to register sde iommu %d: %d\n",
|
||||||
i, ret);
|
i, ret);
|
||||||
mmu->funcs->detach(mmu, (const char **)iommu_ports,
|
mmu->funcs->detach(mmu, (const char **)iommu_ports,
|
||||||
ARRAY_SIZE(iommu_ports));
|
ARRAY_SIZE(iommu_ports));
|
||||||
|
msm_gem_address_space_destroy(aspace);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
sde_kms->mmu[i] = mmu;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include "msm_drv.h"
|
#include "msm_drv.h"
|
||||||
#include "msm_kms.h"
|
#include "msm_kms.h"
|
||||||
#include "msm_mmu.h"
|
#include "msm_mmu.h"
|
||||||
|
#include "msm_gem.h"
|
||||||
#include "sde_dbg.h"
|
#include "sde_dbg.h"
|
||||||
#include "sde_hw_catalog.h"
|
#include "sde_hw_catalog.h"
|
||||||
#include "sde_hw_ctl.h"
|
#include "sde_hw_ctl.h"
|
||||||
|
@ -121,7 +122,7 @@ struct sde_kms {
|
||||||
int core_rev;
|
int core_rev;
|
||||||
struct sde_mdss_cfg *catalog;
|
struct sde_mdss_cfg *catalog;
|
||||||
|
|
||||||
struct msm_mmu *mmu[MSM_SMMU_DOMAIN_MAX];
|
struct msm_gem_address_space *aspace[MSM_SMMU_DOMAIN_MAX];
|
||||||
int mmu_id[MSM_SMMU_DOMAIN_MAX];
|
int mmu_id[MSM_SMMU_DOMAIN_MAX];
|
||||||
struct sde_power_client *core_client;
|
struct sde_power_client *core_client;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue