summaryrefslogtreecommitdiff
path: root/drivers/gpu
diff options
context:
space:
mode:
authorJordan Crouse <jcrouse@codeaurora.org>2017-04-07 15:01:41 -0600
committerJordan Crouse <jcrouse@codeaurora.org>2017-04-26 12:08:07 -0600
commit4e061d8b6002fbb9c124a89f4952cebda0f0450d (patch)
treeadae0f84275392b51ca3fb27093e62fd70d0cd15 /drivers/gpu
parent1576b22ae914d60cd762fd6ef6e47012cb544820 (diff)
drm/msm: Refactor GPU IOMMU
Very soon we will be adding support for secure domains and so a bit of refactoring is needed the GPU IOMMU code: * Add support for directly probing the context bank device at create instead of at attach. This makes it a little bit easier to directly associate a mmu device with a specific context bank. * Specify the domain type at create time. Add a new domain type MSM_DOMAIN_USER to associate the user domain with the gfx3d_user context bank. Also add MSM_DOMAIN_DEFAULT with no context bank for legacy devices (read MDP4) with only one context bank to attach to the parent device. Adding a domain type saves us from having to create N entry points for each domain type. Note that dynamic domains stay with their own initalization function. This is because dynamic domains are cloned from the parent domain so the semantics are too different to try to smash into the generic functions. Change-Id: Ic0dedbad41692e776cddc72cda653ae637f9ec77 Signed-off-by: Jordan Crouse <jcrouse@codeaurora.org>
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c10
-rw-r--r--drivers/gpu/drm/msm/msm_drv.h2
-rw-r--r--drivers/gpu/drm/msm/msm_gem_vma.c4
-rw-r--r--drivers/gpu/drm/msm/msm_gpu.c2
-rw-r--r--drivers/gpu/drm/msm/msm_iommu.c178
-rw-r--r--drivers/gpu/drm/msm/msm_mmu.h13
6 files changed, 125 insertions, 84 deletions
diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c
index b6cddee0cf34..d089ba600de8 100644
--- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c
+++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c
@@ -515,15 +515,11 @@ struct msm_kms *mdp4_kms_init(struct drm_device *dev)
mdelay(16);
if (config->iommu) {
- struct msm_mmu *mmu = msm_iommu_new(&pdev->dev, config->iommu);
-
- if (IS_ERR(mmu)) {
- ret = PTR_ERR(mmu);
- goto fail;
- }
+ config->iommu->geometry.aperture_start = 0x1000;
+ config->iommu->geometry.aperture_end = 0xffffffff;
aspace = msm_gem_address_space_create(&pdev->dev,
- mmu, "mdp4", 0x1000, 0xffffffff);
+ config->iommu, MSM_IOMMU_DOMAIN_DEFAULT, "mdp4");
if (IS_ERR(aspace)) {
ret = PTR_ERR(aspace);
goto fail;
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index 943d73fa544d..d934819d1f1c 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -412,7 +412,7 @@ void msm_gem_address_space_put(struct msm_gem_address_space *aspace);
/* For GPU and legacy display */
struct msm_gem_address_space *
msm_gem_address_space_create(struct device *dev, struct iommu_domain *domain,
- const char *name);
+ int type, const char *name);
struct msm_gem_address_space *
msm_gem_address_space_create_instance(struct msm_mmu *parent, const char *name,
uint64_t start, uint64_t end);
diff --git a/drivers/gpu/drm/msm/msm_gem_vma.c b/drivers/gpu/drm/msm/msm_gem_vma.c
index 1f912ebff683..47f7436854fb 100644
--- a/drivers/gpu/drm/msm/msm_gem_vma.c
+++ b/drivers/gpu/drm/msm/msm_gem_vma.c
@@ -147,9 +147,9 @@ msm_gem_smmu_address_space_create(struct device *dev, struct msm_mmu *mmu,
struct msm_gem_address_space *
msm_gem_address_space_create(struct device *dev, struct iommu_domain *domain,
- const char *name)
+ int type, const char *name)
{
- struct msm_mmu *mmu = msm_iommu_new(dev, domain);
+ struct msm_mmu *mmu = msm_iommu_new(dev, type, domain);
if (IS_ERR(mmu))
return (struct msm_gem_address_space *) mmu;
diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c
index 5a505a8bf328..cbc37dcce1d0 100644
--- a/drivers/gpu/drm/msm/msm_gpu.c
+++ b/drivers/gpu/drm/msm/msm_gpu.c
@@ -837,7 +837,7 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev,
dev_info(drm->dev, "%s: using IOMMU\n", name);
gpu->aspace = msm_gem_address_space_create(&pdev->dev,
- iommu, "gpu");
+ iommu, MSM_IOMMU_DOMAIN_USER, "gpu");
if (IS_ERR(gpu->aspace)) {
ret = PTR_ERR(gpu->aspace);
dev_err(drm->dev, "failed to init iommu: %d\n", ret);
diff --git a/drivers/gpu/drm/msm/msm_iommu.c b/drivers/gpu/drm/msm/msm_iommu.c
index e465c737aab5..38b5cd6d45df 100644
--- a/drivers/gpu/drm/msm/msm_iommu.c
+++ b/drivers/gpu/drm/msm/msm_iommu.c
@@ -27,23 +27,41 @@ static int msm_fault_handler(struct iommu_domain *iommu, struct device *dev,
return 0;
}
+static void enable_iommu_clocks(struct msm_iommu *iommu)
+{
+ int i;
+
+ for (i = 0; i < iommu->nr_clocks; i++) {
+ if (iommu->clocks[i])
+ clk_prepare_enable(iommu->clocks[i]);
+ }
+}
+
+static void disable_iommu_clocks(struct msm_iommu *iommu)
+{
+ int i;
+
+ for (i = 0; i < iommu->nr_clocks; i++) {
+ if (iommu->clocks[i])
+ clk_disable_unprepare(iommu->clocks[i]);
+ }
+}
+
/*
* Get and enable the IOMMU clocks so that we can make
* sure they stay on the entire duration so that we can
* safely change the pagetable from the GPU
*/
-static void _get_iommu_clocks(struct msm_mmu *mmu, struct platform_device *pdev)
+static void get_iommu_clocks(struct msm_iommu *iommu, struct device *dev)
{
- struct msm_iommu *iommu = to_msm_iommu(mmu);
- struct device *dev;
struct property *prop;
const char *name;
int i = 0;
- if (WARN_ON(!pdev))
+ if (iommu->nr_clocks) {
+ enable_iommu_clocks(iommu);
return;
-
- dev = &pdev->dev;
+ }
iommu->nr_clocks =
of_property_count_strings(dev->of_node, "clock-names");
@@ -61,79 +79,40 @@ static void _get_iommu_clocks(struct msm_mmu *mmu, struct platform_device *pdev)
break;
iommu->clocks[i] = clk_get(dev, name);
- if (iommu->clocks[i])
- clk_prepare_enable(iommu->clocks[i]);
-
i++;
}
+
+ enable_iommu_clocks(iommu);
}
-static int _attach_iommu_device(struct msm_mmu *mmu,
- struct iommu_domain *domain, const char **names, int cnt)
+static int msm_iommu_attach(struct msm_mmu *mmu, const char **names,
+ int cnt)
{
- int i;
-
- /* See if there is a iommus member in the current device. If not, look
- * for the names and see if there is one in there.
- */
-
- if (of_find_property(mmu->dev->of_node, "iommus", NULL))
- return iommu_attach_device(domain, mmu->dev);
-
- /* Look through the list of names for a target */
- for (i = 0; i < cnt; i++) {
- struct device_node *node =
- of_find_node_by_name(mmu->dev->of_node, names[i]);
-
- if (!node)
- continue;
-
- if (of_find_property(node, "iommus", NULL)) {
- struct platform_device *pdev;
-
- /* Get the platform device for the node */
- of_platform_populate(node->parent, NULL, NULL,
- mmu->dev);
-
- pdev = of_find_device_by_node(node);
-
- if (!pdev)
- continue;
-
- _get_iommu_clocks(mmu,
- of_find_device_by_node(node->parent));
-
- mmu->dev = &pdev->dev;
-
- return iommu_attach_device(domain, mmu->dev);
- }
- }
+ struct msm_iommu *iommu = to_msm_iommu(mmu);
- dev_err(mmu->dev, "Couldn't find a IOMMU device\n");
- return -ENODEV;
+ return iommu_attach_device(iommu->domain, mmu->dev);
}
-static int msm_iommu_attach(struct msm_mmu *mmu, const char **names, int cnt)
+static int msm_iommu_attach_user(struct msm_mmu *mmu, const char **names,
+ int cnt)
{
struct msm_iommu *iommu = to_msm_iommu(mmu);
- int val = 1, ret;
+ int ret, val = 1;
/* Hope springs eternal */
- iommu->allow_dynamic = true;
+ iommu->allow_dynamic = !iommu_domain_set_attr(iommu->domain,
+ DOMAIN_ATTR_ENABLE_TTBR1, &val) ? true : false;
- /* per-instance pagetables need TTBR1 support in the IOMMU driver */
- ret = iommu_domain_set_attr(iommu->domain,
- DOMAIN_ATTR_ENABLE_TTBR1, &val);
- if (ret)
- iommu->allow_dynamic = false;
+ get_iommu_clocks(iommu, mmu->dev->parent);
/* Mark the GPU as I/O coherent if it is supported */
iommu->is_coherent = of_dma_is_coherent(mmu->dev->of_node);
- /* Attach the device to the domain */
- ret = _attach_iommu_device(mmu, iommu->domain, names, cnt);
- if (ret)
+ ret = iommu_attach_device(iommu->domain, mmu->dev);
+ if (ret) {
+ disable_iommu_clocks(iommu);
return ret;
+ }
/*
* Get the context bank for the base domain; this will be shared with
@@ -179,14 +158,10 @@ static int msm_iommu_attach_dynamic(struct msm_mmu *mmu, const char **names,
static void msm_iommu_detach(struct msm_mmu *mmu)
{
struct msm_iommu *iommu = to_msm_iommu(mmu);
- int i;
iommu_detach_device(iommu->domain, mmu->dev);
- for (i = 0; i < iommu->nr_clocks; i++) {
- if (iommu->clocks[i])
- clk_disable(iommu->clocks[i]);
- }
+ disable_iommu_clocks(iommu);
}
static void msm_iommu_detach_dynamic(struct msm_mmu *mmu)
@@ -249,7 +224,30 @@ static void msm_iommu_destroy(struct msm_mmu *mmu)
kfree(iommu);
}
-static const struct msm_mmu_funcs funcs = {
+static struct device *find_context_bank(const char *name)
+{
+ struct device_node *node = of_find_node_by_name(NULL, name);
+ struct platform_device *pdev, *parent;
+
+ if (!node)
+ return ERR_PTR(-ENODEV);
+
+ if (!of_find_property(node, "iommus", NULL))
+ return ERR_PTR(-ENODEV);
+
+ /* Get the parent device */
+ parent = of_find_device_by_node(node->parent);
+
+ /* Populate the sub nodes */
+ of_platform_populate(parent->dev.of_node, NULL, NULL, &parent->dev);
+
+ /* Get the context bank device */
+ pdev = of_find_device_by_node(node);
+
+ return pdev ? &pdev->dev : ERR_PTR(-ENODEV);
+}
+
+static const struct msm_mmu_funcs default_funcs = {
.attach = msm_iommu_attach,
.detach = msm_iommu_detach,
.map = msm_iommu_map,
@@ -257,6 +255,14 @@ static const struct msm_mmu_funcs funcs = {
.destroy = msm_iommu_destroy,
};
+static const struct msm_mmu_funcs user_funcs = {
+ .attach = msm_iommu_attach_user,
+ .detach = msm_iommu_detach,
+ .map = msm_iommu_map,
+ .unmap = msm_iommu_unmap,
+ .destroy = msm_iommu_destroy,
+};
+
static const struct msm_mmu_funcs dynamic_funcs = {
.attach = msm_iommu_attach_dynamic,
.detach = msm_iommu_detach_dynamic,
@@ -265,8 +271,22 @@ static const struct msm_mmu_funcs dynamic_funcs = {
.destroy = msm_iommu_destroy,
};
-struct msm_mmu *_msm_iommu_new(struct device *dev, struct iommu_domain *domain,
- const struct msm_mmu_funcs *funcs)
+static const struct {
+ const char *cbname;
+ const struct msm_mmu_funcs *funcs;
+} msm_iommu_domains[] = {
+ [MSM_IOMMU_DOMAIN_DEFAULT] = {
+ .cbname = NULL,
+ .funcs = &default_funcs,
+ },
+ [MSM_IOMMU_DOMAIN_USER] = {
+ .cbname = "gfx3d_user",
+ .funcs = &user_funcs,
+ },
+};
+
+static struct msm_mmu *iommu_create(struct device *dev,
+ struct iommu_domain *domain, const struct msm_mmu_funcs *funcs)
{
struct msm_iommu *iommu;
@@ -280,9 +300,23 @@ struct msm_mmu *_msm_iommu_new(struct device *dev, struct iommu_domain *domain,
return &iommu->base;
}
-struct msm_mmu *msm_iommu_new(struct device *dev, struct iommu_domain *domain)
+
+struct msm_mmu *msm_iommu_new(struct device *parent,
+ enum msm_iommu_domain_type type, struct iommu_domain *domain)
{
- return _msm_iommu_new(dev, domain, &funcs);
+ struct device *dev = parent;
+
+ if (type >= ARRAY_SIZE(msm_iommu_domains) ||
+ !msm_iommu_domains[type].funcs)
+ return ERR_PTR(-ENODEV);
+
+ if (msm_iommu_domains[type].cbname) {
+ dev = find_context_bank(msm_iommu_domains[type].cbname);
+ if (IS_ERR(dev))
+ return ERR_CAST(dev);
+ }
+
+ return iommu_create(dev, domain, msm_iommu_domains[type].funcs);
}
/*
@@ -307,7 +341,7 @@ struct msm_mmu *msm_iommu_new_dynamic(struct msm_mmu *base)
if (!domain)
return ERR_PTR(-ENODEV);
- mmu = _msm_iommu_new(base->dev, domain, &dynamic_funcs);
+ mmu = iommu_create(base->dev, domain, &dynamic_funcs);
if (IS_ERR(mmu)) {
if (domain)
diff --git a/drivers/gpu/drm/msm/msm_mmu.h b/drivers/gpu/drm/msm/msm_mmu.h
index 2cbe5c7c7bf9..0292a9ae1d33 100644
--- a/drivers/gpu/drm/msm/msm_mmu.h
+++ b/drivers/gpu/drm/msm/msm_mmu.h
@@ -30,6 +30,11 @@ enum msm_mmu_domain_type {
MSM_SMMU_DOMAIN_MAX,
};
+enum msm_iommu_domain_type {
+ MSM_IOMMU_DOMAIN_DEFAULT,
+ MSM_IOMMU_DOMAIN_USER,
+};
+
struct msm_mmu_funcs {
int (*attach)(struct msm_mmu *mmu, const char **names, int cnt);
void (*detach)(struct msm_mmu *mmu);
@@ -52,9 +57,15 @@ static inline void msm_mmu_init(struct msm_mmu *mmu, struct device *dev,
mmu->funcs = funcs;
}
-struct msm_mmu *msm_iommu_new(struct device *dev, struct iommu_domain *domain);
+/* Create a new SDE mmu device */
struct msm_mmu *msm_smmu_new(struct device *dev,
enum msm_mmu_domain_type domain);
+
+/* Create a new legacy MDP4 or GPU mmu device */
+struct msm_mmu *msm_iommu_new(struct device *parent,
+ enum msm_iommu_domain_type type, struct iommu_domain *domain);
+
+/* Create a new dynamic domain for GPU */
struct msm_mmu *msm_iommu_new_dynamic(struct msm_mmu *orig);
#endif /* __MSM_MMU_H__ */