summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDeepak Kumar <quic_dkumar@quicinc.com>2023-02-03 13:57:41 +0530
committerGerrit - the friendly Code Review server <code-review@localhost>2023-03-29 04:48:51 -0700
commit2537486de05624a6bd98147c7b49e78be417b6ec (patch)
tree3cfb9f26c2301317fe4f8727411f3173014bf317
parenta4c67fa57fc6747b44a9b43faad1ec34a4e15f01 (diff)
downloadgraphics-2537486de05624a6bd98147c7b49e78be417b6ec.tar.gz
msm: kgsl: Move kgsl MMU and CBs to a component device
Currently, there is no dependency between kgsl driver probe and smmu driver probe, this results in issues in case smmu driver probe is not done before kgsl driver probe. To ensure kgsl driver probe/bind happens only post smmu driver probe, add kgsl MMU and CBs as a component device. As CB nodes contain "iommus" property, fw_devlink ensures that CBs are probed only after corresponding supplier (smmu driver) probe is done. Adding CBs as a component device ensures master bind (adreno_bind) is called only once all components are probed. So adding CBs as component device ensures kgsl probe/bind are done only post smmu driver probe. Change-Id: I369c406128dc7f5c8904792f5979b3d0692ced5a Signed-off-by: Deepak Kumar <quic_dkumar@quicinc.com>
-rw-r--r--adreno.c76
-rw-r--r--kgsl.c11
-rw-r--r--kgsl_gmu_core.c2
-rw-r--r--kgsl_gmu_core.h2
-rw-r--r--kgsl_iommu.c33
-rw-r--r--kgsl_mmu.c118
-rw-r--r--kgsl_mmu.h12
7 files changed, 161 insertions, 93 deletions
diff --git a/adreno.c b/adreno.c
index 86717a9..d132cbe 100644
--- a/adreno.c
+++ b/adreno.c
@@ -1195,10 +1195,12 @@ static void adreno_setup_device(struct adreno_device *adreno_dev)
adreno_dev->gpucore->uche_gmem_alignment);
}
-static const struct of_device_id adreno_gmu_match[] = {
+static const struct of_device_id adreno_component_match[] = {
{ .compatible = "qcom,gen7-gmu" },
{ .compatible = "qcom,gpu-gmu" },
{ .compatible = "qcom,gpu-rgmu" },
+ { .compatible = "qcom,kgsl-smmu-v2" },
+ { .compatible = "qcom,smmu-kgsl-cb" },
{},
};
@@ -1242,18 +1244,6 @@ int adreno_device_probe(struct platform_device *pdev,
goto err;
/*
- * Bind the GMU components (if applicable) before doing the KGSL
- * platform probe
- */
- if (of_find_matching_node(dev->of_node, adreno_gmu_match)) {
- status = component_bind_all(dev, NULL);
- if (status) {
- kgsl_bus_close(device);
- return status;
- }
- }
-
- /*
* The SMMU APIs use unsigned long for virtual addresses which means
* that we cannot use 64 bit virtual addresses on a 32 bit kernel even
* though the hardware and the rest of the KGSL driver supports it.
@@ -1298,6 +1288,11 @@ int adreno_device_probe(struct platform_device *pdev,
if (!IS_ERR_OR_NULL(adreno_dev->gpuhtw_llc_slice))
kgsl_mmu_set_feature(device, KGSL_MMU_LLCC_ENABLE);
+ /* Bind the components before doing the KGSL platform probe. */
+ status = component_bind_all(dev, NULL);
+ if (status)
+ goto err;
+
status = kgsl_request_irq(pdev, "kgsl_3d0_irq", adreno_irq_handler, device);
if (status < 0)
goto err;
@@ -1382,8 +1377,7 @@ int adreno_device_probe(struct platform_device *pdev,
err:
device->pdev = NULL;
- if (of_find_matching_node(dev->of_node, adreno_gmu_match))
- component_unbind_all(dev, NULL);
+ component_unbind_all(dev, NULL);
kgsl_bus_close(device);
@@ -1457,8 +1451,7 @@ static void adreno_unbind(struct device *dev)
kgsl_device_platform_remove(device);
- if (of_find_matching_node(dev->of_node, adreno_gmu_match))
- component_unbind_all(dev, NULL);
+ component_unbind_all(dev, NULL);
kgsl_bus_close(device);
@@ -3394,43 +3387,40 @@ static void _release_of(struct device *dev, void *data)
of_node_put(data);
}
-static void adreno_add_gmu_components(struct device *dev,
+static void adreno_add_components(struct device *dev,
struct component_match **match)
{
struct device_node *node;
- node = of_find_matching_node(NULL, adreno_gmu_match);
- if (!node)
- return;
+ /*
+ * Add kgsl-smmu, context banks and gmu as components, if supported.
+ * Master bind (adreno_bind) will be called only once all added
+ * components are available.
+ */
+ for_each_matching_node(node, adreno_component_match) {
+ if (!of_device_is_available(node))
+ continue;
- if (!of_device_is_available(node)) {
- of_node_put(node);
- return;
+ component_match_add_release(dev, match, _release_of, _compare_of, node);
}
-
- component_match_add_release(dev, match, _release_of,
- _compare_of, node);
}
static int adreno_probe(struct platform_device *pdev)
{
struct component_match *match = NULL;
- adreno_add_gmu_components(&pdev->dev, &match);
+ adreno_add_components(&pdev->dev, &match);
- if (match)
- return component_master_add_with_match(&pdev->dev,
- &adreno_ops, match);
- else
- return adreno_bind(&pdev->dev);
+ if (!match)
+ return -ENODEV;
+
+ return component_master_add_with_match(&pdev->dev,
+ &adreno_ops, match);
}
static int adreno_remove(struct platform_device *pdev)
{
- if (of_find_matching_node(NULL, adreno_gmu_match))
- component_master_del(&pdev->dev, &adreno_ops);
- else
- adreno_unbind(&pdev->dev);
+ component_master_del(&pdev->dev, &adreno_ops);
return 0;
}
@@ -3652,10 +3642,19 @@ static int __init kgsl_3d_init(void)
if (ret)
return ret;
+ ret = kgsl_mmu_init();
+ if (ret) {
+ kgsl_core_exit();
+ return ret;
+ }
+
gmu_core_register();
ret = platform_driver_register(&adreno_platform_driver);
- if (ret)
+ if (ret) {
+ gmu_core_unregister();
+ kgsl_mmu_exit();
kgsl_core_exit();
+ }
return ret;
}
@@ -3664,6 +3663,7 @@ static void __exit kgsl_3d_exit(void)
{
platform_driver_unregister(&adreno_platform_driver);
gmu_core_unregister();
+ kgsl_mmu_exit();
kgsl_core_exit();
}
diff --git a/kgsl.c b/kgsl.c
index 3ce0e54..173018e 100644
--- a/kgsl.c
+++ b/kgsl.c
@@ -5067,11 +5067,6 @@ int kgsl_device_platform_probe(struct kgsl_device *device)
sched_set_fifo(device->events_worker->task);
- /* This can return -EPROBE_DEFER */
- status = kgsl_mmu_probe(device);
- if (status != 0)
- goto error_pwrctrl_close;
-
status = kgsl_reclaim_init();
if (status)
goto error_pwrctrl_close;
@@ -5124,12 +5119,6 @@ void kgsl_device_platform_remove(struct kgsl_device *device)
kgsl_device_events_remove(device);
- kgsl_mmu_close(device);
-
- /*
- * This needs to come after the MMU close so we can be sure all the
- * pagetables have been freed
- */
kgsl_free_globals(device);
kgsl_pwrctrl_close(device);
diff --git a/kgsl_gmu_core.c b/kgsl_gmu_core.c
index aa3c157..8dac6cc 100644
--- a/kgsl_gmu_core.c
+++ b/kgsl_gmu_core.c
@@ -34,7 +34,7 @@ void __init gmu_core_register(void)
of_node_put(node);
}
-void __exit gmu_core_unregister(void)
+void gmu_core_unregister(void)
{
const struct of_device_id *match;
struct device_node *node;
diff --git a/kgsl_gmu_core.h b/kgsl_gmu_core.h
index 7770e6e..2ef3ed0 100644
--- a/kgsl_gmu_core.h
+++ b/kgsl_gmu_core.h
@@ -263,7 +263,7 @@ extern struct platform_driver gen7_hwsched_driver;
/* GMU core functions */
void __init gmu_core_register(void);
-void __exit gmu_core_unregister(void);
+void gmu_core_unregister(void);
bool gmu_core_gpmu_isenabled(struct kgsl_device *device);
bool gmu_core_scales_bandwidth(struct kgsl_device *device);
diff --git a/kgsl_iommu.c b/kgsl_iommu.c
index adf3398..23fee14 100644
--- a/kgsl_iommu.c
+++ b/kgsl_iommu.c
@@ -1219,7 +1219,7 @@ int kgsl_set_smmu_aperture(struct kgsl_device *device,
ret = qcom_scm_kgsl_set_smmu_aperture(context->cb_num);
if (ret)
- dev_err(device->dev, "Unable to set the SMMU aperture: %d. The aperture needs to be set to use per-process pagetables\n",
+ dev_err(&device->pdev->dev, "Unable to set the SMMU aperture: %d. The aperture needs to be set to use per-process pagetables\n",
ret);
return ret;
@@ -1238,7 +1238,7 @@ static int set_smmu_lpac_aperture(struct kgsl_device *device,
ret = qcom_scm_kgsl_set_smmu_lpac_aperture(context->cb_num);
if (ret)
- dev_err(device->dev, "Unable to set the LPAC SMMU aperture: %d. The aperture needs to be set to use per-process pagetables\n",
+ dev_err(&device->pdev->dev, "Unable to set the LPAC SMMU aperture: %d. The aperture needs to be set to use per-process pagetables\n",
ret);
return ret;
@@ -1479,9 +1479,6 @@ static void kgsl_iommu_close(struct kgsl_mmu *mmu)
kgsl_guard_page = NULL;
}
- of_platform_depopulate(&iommu->pdev->dev);
- platform_device_put(iommu->pdev);
-
kmem_cache_destroy(addr_entry_cache);
addr_entry_cache = NULL;
}
@@ -2136,6 +2133,7 @@ static int kgsl_iommu_setup_context(struct kgsl_mmu *mmu,
{
struct device_node *node = of_find_node_by_name(parent, name);
struct platform_device *pdev;
+ struct kgsl_device *device = KGSL_MMU_DEVICE(mmu);
int ret;
if (!node)
@@ -2150,7 +2148,7 @@ static int kgsl_iommu_setup_context(struct kgsl_mmu *mmu,
context->cb_num = -1;
context->name = name;
- context->kgsldev = KGSL_MMU_DEVICE(mmu);
+ context->kgsldev = device;
context->pdev = pdev;
ratelimit_default_init(&context->ratelimit);
@@ -2181,7 +2179,7 @@ static int kgsl_iommu_setup_context(struct kgsl_mmu *mmu,
if (context->cb_num >= 0)
return 0;
- dev_err(KGSL_MMU_DEVICE(mmu)->dev, "Couldn't get the context bank for %s: %d\n",
+ dev_err(&device->pdev->dev, "Couldn't get the context bank for %s: %d\n",
context->name, context->cb_num);
iommu_detach_device(context->domain, &context->pdev->dev);
@@ -2306,7 +2304,7 @@ static int iommu_probe_secure_context(struct kgsl_device *device,
ret = qcom_iommu_set_secure_vmid(context->domain, secure_vmid);
if (ret) {
- dev_err(device->dev, "Unable to set the secure VMID: %d\n", ret);
+ dev_err(&device->pdev->dev, "Unable to set the secure VMID: %d\n", ret);
iommu_domain_free(context->domain);
context->domain = NULL;
@@ -2382,20 +2380,15 @@ static void kgsl_iommu_check_config(struct kgsl_mmu *mmu,
of_node_put(node);
}
-int kgsl_iommu_probe(struct kgsl_device *device)
+int kgsl_iommu_bind(struct kgsl_device *device, struct platform_device *pdev)
{
u32 val[2];
int ret, i;
struct kgsl_iommu *iommu = KGSL_IOMMU(device);
- struct platform_device *pdev;
struct kgsl_mmu *mmu = &device->mmu;
- struct device_node *node;
+ struct device_node *node = pdev->dev.of_node;
struct kgsl_global_memdesc *md;
- node = of_find_compatible_node(NULL, NULL, "qcom,kgsl-smmu-v2");
- if (!node)
- return -ENODEV;
-
/* Create a kmem cache for the pagetable address objects */
if (!addr_entry_cache) {
addr_entry_cache = KMEM_CACHE(kgsl_iommu_addr_entry, 0);
@@ -2407,7 +2400,7 @@ int kgsl_iommu_probe(struct kgsl_device *device)
ret = of_property_read_u32_array(node, "reg", val, 2);
if (ret) {
- dev_err(device->dev,
+ dev_err(&device->pdev->dev,
"%pOF: Unable to read KGSL IOMMU register range\n",
node);
goto err;
@@ -2420,14 +2413,12 @@ int kgsl_iommu_probe(struct kgsl_device *device)
goto err;
}
- pdev = of_find_device_by_node(node);
iommu->pdev = pdev;
iommu->num_clks = 0;
iommu->clks = devm_kcalloc(&pdev->dev, ARRAY_SIZE(kgsl_iommu_clocks),
sizeof(*iommu->clks), GFP_KERNEL);
if (!iommu->clks) {
- platform_device_put(pdev);
ret = -ENOMEM;
goto err;
}
@@ -2451,9 +2442,6 @@ int kgsl_iommu_probe(struct kgsl_device *device)
mmu->type = KGSL_MMU_TYPE_IOMMU;
mmu->mmu_ops = &kgsl_iommu_ops;
- /* Fill out the rest of the devices in the node */
- of_platform_populate(node, NULL, NULL, &pdev->dev);
-
/* Peek at the phandle to set up configuration */
kgsl_iommu_check_config(mmu, node);
@@ -2461,13 +2449,11 @@ int kgsl_iommu_probe(struct kgsl_device *device)
ret = iommu_probe_user_context(device, node);
if (ret) {
of_platform_depopulate(&pdev->dev);
- platform_device_put(pdev);
goto err;
}
/* Probe the secure pagetable (this is optional) */
iommu_probe_secure_context(device, node);
- of_node_put(node);
/* Map any globals that might have been created early */
list_for_each_entry(md, &device->globals, node) {
@@ -2515,7 +2501,6 @@ err:
kmem_cache_destroy(addr_entry_cache);
addr_entry_cache = NULL;
- of_node_put(node);
return ret;
}
diff --git a/kgsl_mmu.c b/kgsl_mmu.c
index ac97d5e..8992d72 100644
--- a/kgsl_mmu.c
+++ b/kgsl_mmu.c
@@ -1,9 +1,11 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2002,2007-2021, The Linux Foundation. All rights reserved.
- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved.
*/
+#include <linux/component.h>
+#include <linux/of_platform.h>
#include <linux/slab.h>
#include "kgsl_device.h"
@@ -499,14 +501,6 @@ void kgsl_mmu_map_global(struct kgsl_device *device,
mmu->mmu_ops->mmu_map_global(mmu, memdesc, padding);
}
-void kgsl_mmu_close(struct kgsl_device *device)
-{
- struct kgsl_mmu *mmu = &(device->mmu);
-
- if (MMU_OP_VALID(mmu, mmu_close))
- mmu->mmu_ops->mmu_close(mmu);
-}
-
int kgsl_mmu_pagetable_get_context_bank(struct kgsl_pagetable *pagetable,
struct kgsl_context *context)
{
@@ -610,16 +604,28 @@ static struct kgsl_mmu_ops kgsl_nommu_ops = {
.mmu_getpagetable = nommu_getpagetable,
};
-int kgsl_mmu_probe(struct kgsl_device *device)
+static int kgsl_mmu_cb_bind(struct device *dev, struct device *master, void *data)
+{
+ return 0;
+}
+
+static void kgsl_mmu_cb_unbind(struct device *dev, struct device *master,
+ void *data)
+{
+}
+
+static int kgsl_mmu_bind(struct device *dev, struct device *master, void *data)
{
+ struct kgsl_device *device = dev_get_drvdata(master);
struct kgsl_mmu *mmu = &device->mmu;
int ret;
/*
- * Try to probe for the IOMMU and if it doesn't exist for some reason
+ * Try to bind the IOMMU and if it doesn't exist for some reason
* go for the NOMMU option instead
*/
- ret = kgsl_iommu_probe(device);
+ ret = kgsl_iommu_bind(device, to_platform_device(dev));
+
if (!ret || ret == -EPROBE_DEFER)
return ret;
@@ -627,3 +633,91 @@ int kgsl_mmu_probe(struct kgsl_device *device)
mmu->type = KGSL_MMU_TYPE_NONE;
return 0;
}
+
+static void kgsl_mmu_unbind(struct device *dev, struct device *master,
+ void *data)
+{
+ struct kgsl_device *device = dev_get_drvdata(master);
+ struct kgsl_mmu *mmu = &device->mmu;
+
+ if (MMU_OP_VALID(mmu, mmu_close))
+ mmu->mmu_ops->mmu_close(mmu);
+}
+
+static const struct component_ops kgsl_mmu_cb_component_ops = {
+ .bind = kgsl_mmu_cb_bind,
+ .unbind = kgsl_mmu_cb_unbind,
+};
+
+static const struct component_ops kgsl_mmu_component_ops = {
+ .bind = kgsl_mmu_bind,
+ .unbind = kgsl_mmu_unbind,
+};
+
+static int kgsl_mmu_dev_probe(struct platform_device *pdev)
+{
+ /*
+ * Add kgsl-smmu and context bank as a component device to establish
+ * correct probe order with smmu driver.
+ *
+ * As context bank node in DT contains "iommus" property. fw_devlink
+ * ensures that context bank is probed only after corresponding
+ * supplier (smmu driver) probe is done.
+ *
+ * Adding context bank as a component device ensures master bind
+ * (adreno_bind) is called only once component (kgsl-smmu and context
+ * banks) probe is done thus ensuring correct probe order with smmu
+ * driver.
+ *
+ * kgsl-smmu also need to be a component because we need kgsl-smmu
+ * device info in order to initialize the context banks.
+ */
+ if (of_device_is_compatible(pdev->dev.of_node,
+ "qcom,smmu-kgsl-cb")) {
+ return component_add(&pdev->dev, &kgsl_mmu_cb_component_ops);
+ }
+
+ /* Fill out the rest of the devices in the node */
+ of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
+
+ return component_add(&pdev->dev, &kgsl_mmu_component_ops);
+}
+
+static int kgsl_mmu_dev_remove(struct platform_device *pdev)
+{
+ if (of_device_is_compatible(pdev->dev.of_node,
+ "qcom,smmu-kgsl-cb")) {
+ component_del(&pdev->dev, &kgsl_mmu_cb_component_ops);
+ return 0;
+ }
+
+ component_del(&pdev->dev, &kgsl_mmu_component_ops);
+
+ of_platform_depopulate(&pdev->dev);
+ return 0;
+}
+
+static const struct of_device_id mmu_match_table[] = {
+ { .compatible = "qcom,kgsl-smmu-v2" },
+ { .compatible = "qcom,smmu-kgsl-cb" },
+ {},
+};
+
+static struct platform_driver kgsl_mmu_driver = {
+ .probe = kgsl_mmu_dev_probe,
+ .remove = kgsl_mmu_dev_remove,
+ .driver = {
+ .name = "kgsl-iommu",
+ .of_match_table = mmu_match_table,
+ }
+};
+
+int __init kgsl_mmu_init(void)
+{
+ return platform_driver_register(&kgsl_mmu_driver);
+}
+
+void kgsl_mmu_exit(void)
+{
+ platform_driver_unregister(&kgsl_mmu_driver);
+}
diff --git a/kgsl_mmu.h b/kgsl_mmu.h
index a1c9c1e..01be7c6 100644
--- a/kgsl_mmu.h
+++ b/kgsl_mmu.h
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2002,2007-2021, The Linux Foundation. All rights reserved.
- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef __KGSL_MMU_H
#define __KGSL_MMU_H
@@ -203,7 +203,9 @@ struct kgsl_mmu {
#define KGSL_IOMMU(d) (&((d)->mmu.iommu))
-int kgsl_mmu_probe(struct kgsl_device *device);
+int __init kgsl_mmu_init(void);
+void kgsl_mmu_exit(void);
+
int kgsl_mmu_start(struct kgsl_device *device);
void kgsl_print_global_pt_entries(struct seq_file *s);
@@ -233,8 +235,6 @@ int kgsl_mmu_find_region(struct kgsl_pagetable *pagetable,
uint64_t region_start, uint64_t region_end,
uint64_t *gpuaddr, uint64_t size, unsigned int align);
-void kgsl_mmu_close(struct kgsl_device *device);
-
uint64_t kgsl_mmu_find_svm_region(struct kgsl_pagetable *pagetable,
uint64_t start, uint64_t end, uint64_t size,
uint64_t alignment);
@@ -418,9 +418,9 @@ void kgsl_mmu_pagetable_init(struct kgsl_mmu *mmu,
void kgsl_mmu_pagetable_add(struct kgsl_mmu *mmu, struct kgsl_pagetable *pagetable);
#if IS_ENABLED(CONFIG_ARM_SMMU)
-int kgsl_iommu_probe(struct kgsl_device *device);
+int kgsl_iommu_bind(struct kgsl_device *device, struct platform_device *pdev);
#else
-static inline int kgsl_iommu_probe(struct kgsl_device *device)
+static inline int kgsl_iommu_bind(struct kgsl_device *device, struct platform_device *pdev)
{
return -ENODEV;
}