diff options
author | qctecmdr <qctecmdr@localhost> | 2023-03-30 00:48:15 -0700 |
---|---|---|
committer | Gerrit - the friendly Code Review server <code-review@localhost> | 2023-03-30 00:48:15 -0700 |
commit | 8fa442b60b2c40b57e44d43663f315dc76371ade (patch) | |
tree | f278faf3200f5de41430b1f5cd26b0fb07f51499 | |
parent | 05b08019ea160fa9f18c3b5a1f612cac4a3d0015 (diff) | |
parent | 2537486de05624a6bd98147c7b49e78be417b6ec (diff) | |
download | graphics-8fa442b60b2c40b57e44d43663f315dc76371ade.tar.gz |
Merge "msm: kgsl: Move kgsl MMU and CBs to a component device"
-rw-r--r-- | adreno.c | 76 | ||||
-rw-r--r-- | kgsl.c | 11 | ||||
-rw-r--r-- | kgsl_gmu_core.c | 2 | ||||
-rw-r--r-- | kgsl_gmu_core.h | 2 | ||||
-rw-r--r-- | kgsl_iommu.c | 33 | ||||
-rw-r--r-- | kgsl_mmu.c | 118 | ||||
-rw-r--r-- | kgsl_mmu.h | 12 |
7 files changed, 161 insertions, 93 deletions
@@ -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(); } @@ -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; } @@ -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); +} @@ -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; } |