summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorqctecmdr <qctecmdr@localhost>2023-03-30 00:48:15 -0700
committerGerrit - the friendly Code Review server <code-review@localhost>2023-03-30 00:48:15 -0700
commit8fa442b60b2c40b57e44d43663f315dc76371ade (patch)
treef278faf3200f5de41430b1f5cd26b0fb07f51499
parent05b08019ea160fa9f18c3b5a1f612cac4a3d0015 (diff)
parent2537486de05624a6bd98147c7b49e78be417b6ec (diff)
downloadgraphics-8fa442b60b2c40b57e44d43663f315dc76371ade.tar.gz
Merge "msm: kgsl: Move kgsl MMU and CBs to a component device"
-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;
}