diff options
author | Linux Build Service Account <lnxbuild@localhost> | 2023-04-17 00:40:54 -0700 |
---|---|---|
committer | Linux Build Service Account <lnxbuild@localhost> | 2023-04-17 00:40:54 -0700 |
commit | 9499430bb5c6a97c9b10a06d6b16601f2bb20a45 (patch) | |
tree | 181dd9582339766dec60a19f3322dd69d7d2a3bc | |
parent | 30dda9aa57a7222190fc0a35a0f35b0c2ec42a99 (diff) | |
parent | 8fa442b60b2c40b57e44d43663f315dc76371ade (diff) | |
download | graphics-9499430bb5c6a97c9b10a06d6b16601f2bb20a45.tar.gz |
Merge 8fa442b60b2c40b57e44d43663f315dc76371ade on remote branch
Change-Id: I1a7803126bbf0104c6f4d1f5b6c8a3acb124642f
-rw-r--r-- | adreno-gpulist.h | 7 | ||||
-rw-r--r-- | adreno.c | 76 | ||||
-rw-r--r-- | adreno_a6xx.h | 15 | ||||
-rw-r--r-- | adreno_a6xx_hwsched_hfi.c | 25 | ||||
-rw-r--r-- | adreno_a6xx_hwsched_hfi.h | 7 | ||||
-rw-r--r-- | adreno_a6xx_perfcounter.c | 22 | ||||
-rw-r--r-- | adreno_dispatch.c | 9 | ||||
-rw-r--r-- | adreno_gen7.c | 5 | ||||
-rw-r--r-- | adreno_gen7.h | 9 | ||||
-rw-r--r-- | adreno_gen7_gmu.c | 4 | ||||
-rw-r--r-- | adreno_gen7_hwsched.c | 4 | ||||
-rw-r--r-- | adreno_gen7_hwsched_hfi.c | 38 | ||||
-rw-r--r-- | adreno_gen7_hwsched_hfi.h | 16 | ||||
-rw-r--r-- | adreno_gen7_perfcounter.c | 27 | ||||
-rw-r--r-- | adreno_gen7_rpmh.c | 29 | ||||
-rw-r--r-- | adreno_hwsched.c | 6 | ||||
-rw-r--r-- | config/gki_khajedisp.conf | 14 | ||||
-rw-r--r-- | kgsl.c | 14 | ||||
-rw-r--r-- | kgsl_device.h | 4 | ||||
-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 |
24 files changed, 340 insertions, 158 deletions
diff --git a/adreno-gpulist.h b/adreno-gpulist.h index 96b8e70..8897f11 100644 --- a/adreno-gpulist.h +++ b/adreno-gpulist.h @@ -2139,7 +2139,7 @@ static const struct adreno_gen7_core adreno_gpu_core_gen7_2_0 = { ADRENO_LPAC | ADRENO_BCL | ADRENO_L3_VOTE | ADRENO_PREEMPTION | ADRENO_DMS, .gpudev = &adreno_gen7_hwsched_gpudev.base, - .perfcounters = &adreno_gen7_2_0_perfcounters, + .perfcounters = &adreno_gen7_hwsched_perfcounters, .uche_gmem_alignment = SZ_16M, .gmem_size = 3 * SZ_1M, .bus_width = 32, @@ -2175,7 +2175,7 @@ static const struct adreno_gen7_core adreno_gpu_core_gen7_2_1 = { ADRENO_BCL | ADRENO_L3_VOTE | ADRENO_ACD | ADRENO_PREEMPTION | ADRENO_DMS, .gpudev = &adreno_gen7_hwsched_gpudev.base, - .perfcounters = &adreno_gen7_2_0_perfcounters, + .perfcounters = &adreno_gen7_hwsched_perfcounters, .uche_gmem_alignment = SZ_16M, .gmem_size = 3 * SZ_1M, .bus_width = 32, @@ -2300,7 +2300,7 @@ static const struct adreno_gen7_core adreno_gpu_core_gen7_9_0 = { ADRENO_CONTENT_PROTECTION | ADRENO_LPAC | ADRENO_IFPC | ADRENO_L3_VOTE | ADRENO_BCL | ADRENO_ACD | ADRENO_DMS | ADRENO_HW_FENCE, .gpudev = &adreno_gen7_9_0_hwsched_gpudev.base, - .perfcounters = &adreno_gen7_2_0_perfcounters, + .perfcounters = &adreno_gen7_hwsched_perfcounters, .uche_gmem_alignment = SZ_16M, .gmem_size = 3 * SZ_1M, .bus_width = 32, @@ -2320,6 +2320,7 @@ static const struct adreno_gen7_core adreno_gpu_core_gen7_9_0 = { .gmu_hub_clk_freq = 200000000, .gen7_snapshot_block_list = &gen7_9_0_snapshot_block_list, .bcl_data = 1, + .acv_perfmode_vote = BIT(2), }; static const struct kgsl_regmap_list a663_hwcg_regs[] = { @@ -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/adreno_a6xx.h b/adreno_a6xx.h index 52a384d..a00f389 100644 --- a/adreno_a6xx.h +++ b/adreno_a6xx.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2017-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 _ADRENO_A6XX_H_ @@ -352,19 +352,6 @@ void a6xx_spin_idle_debug(struct adreno_device *adreno_dev, const char *str); /** - * a6xx_counter_enable - Configure a performance counter for a countable - * @adreno_dev - Adreno device to configure - * @group - Desired performance counter group - * @counter - Desired performance counter in the group - * @countable - Desired countable - * - * Physically set up a counter within a group with the desired countable - * Return 0 on success else error code - */ -int a6xx_counter_enable(struct adreno_device *adreno_dev, - const struct adreno_perfcount_group *group, - unsigned int counter, unsigned int countable); -/** * a6xx_perfcounter_update - Update the IFPC perfcounter list * @adreno_dev: An Adreno GPU handle * @reg: Perfcounter reg struct to add/remove to the list diff --git a/adreno_a6xx_hwsched_hfi.c b/adreno_a6xx_hwsched_hfi.c index 829f869..85d375b 100644 --- a/adreno_a6xx_hwsched_hfi.c +++ b/adreno_a6xx_hwsched_hfi.c @@ -1387,17 +1387,12 @@ int a6xx_hwsched_cp_init(struct adreno_device *adreno_dev) int a6xx_hwsched_counter_inline_enable(struct adreno_device *adreno_dev, const struct adreno_perfcount_group *group, - unsigned int counter, unsigned int countable) + u32 counter, u32 countable) { struct kgsl_device *device = KGSL_DEVICE(adreno_dev); struct adreno_perfcount_register *reg = &group->regs[counter]; - u32 cmds[A6XX_PERF_COUNTER_ENABLE_DWORDS + 1]; + u32 val, cmds[A6XX_PERF_COUNTER_ENABLE_DWORDS + 1]; int ret; - char str[64]; - - if (!(device->state == KGSL_STATE_ACTIVE)) - return a6xx_counter_enable(adreno_dev, group, counter, - countable); if (group->flags & ADRENO_PERFCOUNTER_GROUP_RESTORE) a6xx_perfcounter_update(adreno_dev, reg, false); @@ -1409,13 +1404,21 @@ int a6xx_hwsched_counter_inline_enable(struct adreno_device *adreno_dev, cmds[2] = cp_type4_packet(reg->select, 1); cmds[3] = countable; - snprintf(str, sizeof(str), "Perfcounter %s/%u/%u start via commands failed\n", - group->name, counter, countable); + ret = a6xx_hfi_send_cmd_async(adreno_dev, cmds); + if (ret) + goto err; - ret = submit_raw_cmds(adreno_dev, cmds, str); - if (!ret) + /* Wait till the register is programmed with the countable */ + ret = kgsl_regmap_read_poll_timeout(&device->regmap, reg->select, val, + val == countable, 100, ADRENO_IDLE_TIMEOUT); + if (!ret) { reg->value = 0; + return ret; + } +err: + dev_err(device->dev, "Perfcounter %s/%u/%u start via commands failed\n", + group->name, counter, countable); return ret; } diff --git a/adreno_a6xx_hwsched_hfi.h b/adreno_a6xx_hwsched_hfi.h index 6c1063e..995bb63 100644 --- a/adreno_a6xx_hwsched_hfi.h +++ b/adreno_a6xx_hwsched_hfi.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2020-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 _ADRENO_A6XX_HWSCHED_HFI_H_ @@ -91,13 +91,12 @@ int a6xx_hwsched_cp_init(struct adreno_device *adreno_dev); * @counter - Desired performance counter in the group * @countable - Desired countable * - * Function is used for adreno cores * Physically set up a counter within a group with the desired countable - * Return 0 on success else error code + * Return 0 on success or negative error on failure. */ int a6xx_hwsched_counter_inline_enable(struct adreno_device *adreno_dev, const struct adreno_perfcount_group *group, - unsigned int counter, unsigned int countable); + u32 counter, u32 countable); /** * a6xx_hfi_send_cmd_async - Send an hfi packet diff --git a/adreno_a6xx_perfcounter.c b/adreno_a6xx_perfcounter.c index 7da9291..7d07cfc 100644 --- a/adreno_a6xx_perfcounter.c +++ b/adreno_a6xx_perfcounter.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2020-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 "adreno.h" @@ -72,9 +72,9 @@ static u64 a6xx_counter_read_norestore(struct adreno_device *adreno_dev, return ((((u64) hi) << 32) | lo) + reg->value; } -int a6xx_counter_enable(struct adreno_device *adreno_dev, +static int a6xx_counter_enable(struct adreno_device *adreno_dev, const struct adreno_perfcount_group *group, - unsigned int counter, unsigned int countable) + u32 counter, u32 countable) { struct kgsl_device *device = KGSL_DEVICE(adreno_dev); struct adreno_perfcount_register *reg = &group->regs[counter]; @@ -91,6 +91,16 @@ int a6xx_counter_enable(struct adreno_device *adreno_dev, return ret; } +static int a6xx_hwsched_counter_enable(struct adreno_device *adreno_dev, + const struct adreno_perfcount_group *group, + u32 counter, u32 countable) +{ + if (!(KGSL_DEVICE(adreno_dev)->state == KGSL_STATE_ACTIVE)) + return a6xx_counter_enable(adreno_dev, group, counter, countable); + + return a6xx_hwsched_counter_inline_enable(adreno_dev, group, counter, countable); +} + static int a6xx_counter_inline_enable(struct adreno_device *adreno_dev, const struct adreno_perfcount_group *group, unsigned int counter, unsigned int countable) @@ -941,7 +951,7 @@ static const struct adreno_perfcount_group a6xx_hwsched_perfcounter_groups a6xx_counter_enable, a6xx_counter_read, a6xx_counter_load), A6XX_REGULAR_PERFCOUNTER_GROUP(PC, pc), A6XX_REGULAR_PERFCOUNTER_GROUP(VFD, vfd), - A6XX_PERFCOUNTER_GROUP(HLSQ, hlsq, a6xx_hwsched_counter_inline_enable, + A6XX_PERFCOUNTER_GROUP(HLSQ, hlsq, a6xx_hwsched_counter_enable, a6xx_counter_read, a6xx_counter_load), A6XX_REGULAR_PERFCOUNTER_GROUP(VPC, vpc), A6XX_REGULAR_PERFCOUNTER_GROUP(CCU, ccu), @@ -950,9 +960,9 @@ static const struct adreno_perfcount_group a6xx_hwsched_perfcounter_groups A6XX_REGULAR_PERFCOUNTER_GROUP(RAS, ras), A6XX_REGULAR_PERFCOUNTER_GROUP(LRZ, lrz), A6XX_REGULAR_PERFCOUNTER_GROUP(UCHE, uche), - A6XX_PERFCOUNTER_GROUP(TP, tp, a6xx_hwsched_counter_inline_enable, + A6XX_PERFCOUNTER_GROUP(TP, tp, a6xx_hwsched_counter_enable, a6xx_counter_read, a6xx_counter_load), - A6XX_PERFCOUNTER_GROUP(SP, sp, a6xx_hwsched_counter_inline_enable, + A6XX_PERFCOUNTER_GROUP(SP, sp, a6xx_hwsched_counter_enable, a6xx_counter_read, a6xx_counter_load), A6XX_REGULAR_PERFCOUNTER_GROUP(RB, rb), A6XX_REGULAR_PERFCOUNTER_GROUP(VSC, vsc), diff --git a/adreno_dispatch.c b/adreno_dispatch.c index b52d4a9..bdf5598 100644 --- a/adreno_dispatch.c +++ b/adreno_dispatch.c @@ -1577,13 +1577,15 @@ static void adreno_fault_header(struct kgsl_device *device, const char *type = fault & ADRENO_GMU_FAULT ? "gmu" : "gpu"; if (!gx_on) { - if (drawobj != NULL) + if (drawobj != NULL) { pr_fault(device, drawobj, "%s fault ctx %u ctx_type %s ts %u and GX is OFF\n", type, drawobj->context->id, kgsl_context_type(drawctxt->type), drawobj->timestamp); - else + pr_fault(device, drawobj, "cmdline: %s\n", + drawctxt->base.proc_priv->cmdline); + } else dev_err(device->dev, "RB[%d] : %s fault and GX is OFF\n", id, type); @@ -1616,6 +1618,9 @@ static void adreno_fault_header(struct kgsl_device *device, drawobj->timestamp, status, rptr, wptr, ib1base, ib1sz, ib2base, ib2sz); + pr_fault(device, drawobj, "cmdline: %s\n", + drawctxt->base.proc_priv->cmdline); + if (rb != NULL) pr_fault(device, drawobj, "%s fault rb %d rb sw r/w %4.4x/%4.4x\n", diff --git a/adreno_gen7.c b/adreno_gen7.c index 82f29ee..4a94c1e 100644 --- a/adreno_gen7.c +++ b/adreno_gen7.c @@ -1441,6 +1441,11 @@ int gen7_probe_common(struct platform_device *pdev, debugfs_create_file("acd_calibrate", 0644, device->d_debugfs, device, &acd_cal_fops); gen7_coresight_init(adreno_dev); + + /* Dump additional AQE 16KB data on top of default 96KB(48(BR)+48(BV)) */ + device->snapshot_ctxt_record_size = ADRENO_FEATURE(adreno_dev, ADRENO_AQE) ? + 112 * SZ_1K : 96 * SZ_1K; + return 0; } diff --git a/adreno_gen7.h b/adreno_gen7.h index 445b9b6..be69d83 100644 --- a/adreno_gen7.h +++ b/adreno_gen7.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 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 _ADRENO_GEN7_H_ @@ -23,7 +23,7 @@ struct gen7_snapshot_block_list; extern const struct adreno_power_ops gen7_gmu_power_ops; extern const struct adreno_power_ops gen7_hwsched_power_ops; extern const struct adreno_perfcounters adreno_gen7_perfcounters; -extern const struct adreno_perfcounters adreno_gen7_2_0_perfcounters; +extern const struct adreno_perfcounters adreno_gen7_hwsched_perfcounters; struct gen7_gpudev { struct adreno_gpudev base; @@ -118,6 +118,8 @@ struct adreno_gen7_core { u32 preempt_level; /** @qos_value: GPU qos value to set for each RB. */ const u32 *qos_value; + /** @acv_perfmode_vote: ACV vote for GPU perfmode */ + u32 acv_perfmode_vote; }; /** @@ -191,6 +193,9 @@ struct gen7_cp_smmu_info { /* Size of the CP_INIT pm4 stream in dwords */ #define GEN7_CP_INIT_DWORDS 10 +/* Size of the perf counter enable pm4 stream in dwords */ +#define GEN7_PERF_COUNTER_ENABLE_DWORDS 3 + #define GEN7_INT_MASK \ ((1 << GEN7_INT_AHBERROR) | \ (1 << GEN7_INT_ATBASYNCFIFOOVERFLOW) | \ diff --git a/adreno_gen7_gmu.c b/adreno_gen7_gmu.c index 1b93f7d..6c19dc5 100644 --- a/adreno_gen7_gmu.c +++ b/adreno_gen7_gmu.c @@ -2153,7 +2153,9 @@ static int gen7_gmu_bus_set(struct adreno_device *adreno_dev, int buslevel, struct kgsl_pwrctrl *pwr = &device->pwrctrl; int ret = 0; - kgsl_icc_set_tag(pwr, buslevel); + /* Target gen7_9_0 votes for perfmode through ACV. Skip icc path for same */ + if (!adreno_is_gen7_9_0(adreno_dev)) + kgsl_icc_set_tag(pwr, buslevel); if (buslevel == pwr->cur_buslevel) buslevel = INVALID_DCVS_IDX; diff --git a/adreno_gen7_hwsched.c b/adreno_gen7_hwsched.c index 666b395..1dc9e05 100644 --- a/adreno_gen7_hwsched.c +++ b/adreno_gen7_hwsched.c @@ -1199,7 +1199,9 @@ static int gen7_hwsched_bus_set(struct adreno_device *adreno_dev, int buslevel, struct kgsl_pwrctrl *pwr = &device->pwrctrl; int ret = 0; - kgsl_icc_set_tag(pwr, buslevel); + /* Target gen7_9_0 votes for perfmode through ACV. Skip icc path for same */ + if (!adreno_is_gen7_9_0(adreno_dev)) + kgsl_icc_set_tag(pwr, buslevel); if (buslevel == pwr->cur_buslevel) buslevel = INVALID_DCVS_IDX; diff --git a/adreno_gen7_hwsched_hfi.c b/adreno_gen7_hwsched_hfi.c index d2e8e0e..c0d4b8f 100644 --- a/adreno_gen7_hwsched_hfi.c +++ b/adreno_gen7_hwsched_hfi.c @@ -3157,3 +3157,41 @@ void gen7_hwsched_context_destroy(struct adreno_device *adreno_dev, if (drawctxt->gmu_hw_fence_queue.gmuaddr) gen7_free_gmu_block(to_gen7_gmu(adreno_dev), &drawctxt->gmu_hw_fence_queue); } + +int gen7_hwsched_counter_inline_enable(struct adreno_device *adreno_dev, + const struct adreno_perfcount_group *group, + u32 counter, u32 countable) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + struct adreno_perfcount_register *reg = &group->regs[counter]; + u32 val, cmds[GEN7_PERF_COUNTER_ENABLE_DWORDS + 1]; + int ret; + + if (group->flags & ADRENO_PERFCOUNTER_GROUP_RESTORE) + gen7_perfcounter_update(adreno_dev, reg, false, + FIELD_PREP(GENMASK(13, 12), PIPE_NONE)); + + cmds[0] = CREATE_MSG_HDR(H2F_MSG_ISSUE_CMD_RAW, + (GEN7_PERF_COUNTER_ENABLE_DWORDS + 1) << 2, HFI_MSG_CMD); + + cmds[1] = cp_type7_packet(CP_WAIT_FOR_IDLE, 0); + cmds[2] = cp_type4_packet(reg->select, 1); + cmds[3] = countable; + + ret = gen7_hfi_send_cmd_async(adreno_dev, cmds); + if (ret) + goto err; + + /* Wait till the register is programmed with the countable */ + ret = kgsl_regmap_read_poll_timeout(&device->regmap, reg->select, val, + val == countable, 100, ADRENO_IDLE_TIMEOUT); + if (!ret) { + reg->value = 0; + return ret; + } + +err: + dev_err(device->dev, "Perfcounter %s/%u/%u start via commands failed\n", + group->name, counter, countable); + return ret; +} diff --git a/adreno_gen7_hwsched_hfi.h b/adreno_gen7_hwsched_hfi.h index 85751f4..6154a75 100644 --- a/adreno_gen7_hwsched_hfi.h +++ b/adreno_gen7_hwsched_hfi.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 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 _ADRENO_GEN7_HWSCHED_HFI_H_ @@ -90,6 +90,20 @@ void gen7_hwsched_hfi_stop(struct adreno_device *adreno_dev); int gen7_hwsched_cp_init(struct adreno_device *adreno_dev); /** + * gen7_hwsched_counter_inline_enable - Configure a performance counter for a countable + * @adreno_dev - Adreno device to configure + * @group - Desired performance counter group + * @counter - Desired performance counter in the group + * @countable - Desired countable + * + * Physically set up a counter within a group with the desired countable + * Return 0 on success or negative error on failure. + */ +int gen7_hwsched_counter_inline_enable(struct adreno_device *adreno_dev, + const struct adreno_perfcount_group *group, + u32 counter, u32 countable); + +/** * gen7_hfi_send_cmd_async - Send an hfi packet * @adreno_dev: Pointer to adreno device structure * @data: Data to be sent in the hfi packet diff --git a/adreno_gen7_perfcounter.c b/adreno_gen7_perfcounter.c index 2120c2c..74a7799 100644 --- a/adreno_gen7_perfcounter.c +++ b/adreno_gen7_perfcounter.c @@ -1,11 +1,12 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 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 "adreno.h" #include "adreno_gen7.h" +#include "adreno_gen7_hwsched_hfi.h" #include "adreno_perfcounter.h" #include "adreno_pm4types.h" #include "kgsl_device.h" @@ -100,6 +101,16 @@ static int gen7_counter_enable(struct adreno_device *adreno_dev, return ret; } +static int gen7_hwsched_counter_enable(struct adreno_device *adreno_dev, + const struct adreno_perfcount_group *group, + u32 counter, u32 countable) +{ + if (!(KGSL_DEVICE(adreno_dev)->state == KGSL_STATE_ACTIVE)) + return gen7_counter_enable(adreno_dev, group, counter, countable); + + return gen7_hwsched_counter_inline_enable(adreno_dev, group, counter, countable); +} + static u64 gen7_counter_read(struct adreno_device *adreno_dev, const struct adreno_perfcount_group *group, unsigned int counter) @@ -939,13 +950,13 @@ static struct adreno_perfcount_register gen7_perfcounters_alwayson[] = { GEN7_BV_PERFCOUNTER_GROUP(offset, name, \ gen7_counter_enable, gen7_counter_read) -static const struct adreno_perfcount_group gen7_2_0_perfcounter_groups +static const struct adreno_perfcount_group gen7_hwsched_perfcounter_groups [KGSL_PERFCOUNTER_GROUP_MAX] = { GEN7_REGULAR_PERFCOUNTER_GROUP(CP, cp), GEN7_PERFCOUNTER_GROUP_FLAGS(gen7, RBBM, rbbm, 0, gen7_counter_enable, gen7_counter_read), GEN7_REGULAR_PERFCOUNTER_GROUP(PC, pc), - GEN7_REGULAR_PERFCOUNTER_GROUP(VFD, vfd), + GEN7_PERFCOUNTER_GROUP(VFD, vfd, gen7_hwsched_counter_enable, gen7_counter_read), GEN7_PERFCOUNTER_GROUP(HLSQ, hlsq, gen7_counter_br_enable, gen7_counter_read), GEN7_REGULAR_PERFCOUNTER_GROUP(VPC, vpc), GEN7_REGULAR_PERFCOUNTER_GROUP(CCU, ccu), @@ -954,8 +965,8 @@ static const struct adreno_perfcount_group gen7_2_0_perfcounter_groups GEN7_PERFCOUNTER_GROUP(RAS, ras, gen7_counter_br_enable, gen7_counter_read), GEN7_PERFCOUNTER_GROUP(LRZ, lrz, gen7_counter_br_enable, gen7_counter_read), GEN7_REGULAR_PERFCOUNTER_GROUP(UCHE, gen7_2_0_uche), - GEN7_REGULAR_PERFCOUNTER_GROUP(TP, tp), - GEN7_REGULAR_PERFCOUNTER_GROUP(SP, sp), + GEN7_PERFCOUNTER_GROUP(TP, tp, gen7_hwsched_counter_enable, gen7_counter_read), + GEN7_PERFCOUNTER_GROUP(SP, sp, gen7_hwsched_counter_enable, gen7_counter_read), GEN7_REGULAR_PERFCOUNTER_GROUP(RB, rb), GEN7_REGULAR_PERFCOUNTER_GROUP(VSC, vsc), GEN7_PERFCOUNTER_GROUP_FLAGS(gen7, VBIF, gbif, 0, @@ -1038,7 +1049,7 @@ const struct adreno_perfcounters adreno_gen7_perfcounters = { ARRAY_SIZE(gen7_perfcounter_groups), }; -const struct adreno_perfcounters adreno_gen7_2_0_perfcounters = { - gen7_2_0_perfcounter_groups, - ARRAY_SIZE(gen7_2_0_perfcounter_groups), +const struct adreno_perfcounters adreno_gen7_hwsched_perfcounters = { + gen7_hwsched_perfcounter_groups, + ARRAY_SIZE(gen7_hwsched_perfcounter_groups), }; diff --git a/adreno_gen7_rpmh.c b/adreno_gen7_rpmh.c index 0c196ec..fd7c2fc 100644 --- a/adreno_gen7_rpmh.c +++ b/adreno_gen7_rpmh.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 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/types.h> @@ -118,8 +118,8 @@ static int setup_volt_dependency_tbl(u32 *votes, } /* Generate a set of bandwidth votes for the list of BCMs */ -static void tcs_cmd_data(struct bcm *bcms, int count, u32 ab, u32 ib, - u32 *data) +static void tcs_cmd_data(struct bcm *bcms, int count, + u32 ab, u32 ib, u32 *data, u32 perfmode_vote, bool set_perfmode) { int i; @@ -135,7 +135,8 @@ static void tcs_cmd_data(struct bcm *bcms, int count, u32 ab, u32 ib, if (!ab && !ib) data[i] = BCM_TCS_CMD(commit, false, 0x0, 0x0); else - data[i] = BCM_TCS_CMD(commit, true, 0x0, 0x8); + data[i] = BCM_TCS_CMD(commit, true, 0x0, + set_perfmode ? perfmode_vote : 0x0); continue; } @@ -193,9 +194,10 @@ static void free_rpmh_bw_votes(struct rpmh_bw_votes *votes) /* Build the votes table from the specified bandwidth levels */ static struct rpmh_bw_votes *build_rpmh_bw_votes(struct bcm *bcms, - int bcm_count, u32 *levels, int levels_count) + int bcm_count, u32 *levels, int levels_count, u32 perfmode_vote, u32 perfmode_lvl) { struct rpmh_bw_votes *votes; + bool set_perfmode; int i; votes = kzalloc(sizeof(*votes), GFP_KERNEL); @@ -243,7 +245,9 @@ static struct rpmh_bw_votes *build_rpmh_bw_votes(struct bcm *bcms, return ERR_PTR(-ENOMEM); } - tcs_cmd_data(bcms, bcm_count, levels[i], levels[i], votes->cmds[i]); + set_perfmode = (i >= perfmode_lvl) ? true : false; + tcs_cmd_data(bcms, bcm_count, levels[i], levels[i], votes->cmds[i], + perfmode_vote, set_perfmode); } return votes; @@ -455,18 +459,27 @@ static void build_bw_table_cmd(struct hfi_bwtable_cmd *cmd, cmd->cnoc_cmd_data[i][j] = (u32) cnoc->cmds[i][j]; } +#define GEN7_9_0_DDR_NOM_IDX 6 + static int build_bw_table(struct adreno_device *adreno_dev) { struct gen7_gmu_device *gmu = to_gen7_gmu(adreno_dev); + const struct adreno_gen7_core *gen7_core = to_gen7_core(adreno_dev); struct kgsl_device *device = KGSL_DEVICE(adreno_dev); struct kgsl_pwrctrl *pwr = &device->pwrctrl; struct rpmh_bw_votes *ddr, *cnoc = NULL; + u32 perfmode_vote = gen7_core->acv_perfmode_vote; + u32 perfmode_lvl = adreno_is_gen7_9_0(adreno_dev) ? GEN7_9_0_DDR_NOM_IDX : 1; u32 *cnoc_table; u32 count; int ret; + /* If perfmode vote is not defined, use default value as 0x8 */ + if (!perfmode_vote) + perfmode_vote = BIT(3); + ddr = build_rpmh_bw_votes(gen7_ddr_bcms, ARRAY_SIZE(gen7_ddr_bcms), - pwr->ddr_table, pwr->ddr_table_count); + pwr->ddr_table, pwr->ddr_table_count, perfmode_vote, perfmode_lvl); if (IS_ERR(ddr)) return PTR_ERR(ddr); @@ -475,7 +488,7 @@ static int build_bw_table(struct adreno_device *adreno_dev) if (count > 0) cnoc = build_rpmh_bw_votes(gen7_cnoc_bcms, - ARRAY_SIZE(gen7_cnoc_bcms), cnoc_table, count); + ARRAY_SIZE(gen7_cnoc_bcms), cnoc_table, count, 0, 0); kfree(cnoc_table); diff --git a/adreno_hwsched.c b/adreno_hwsched.c index a03f2db..cae6a3c 100644 --- a/adreno_hwsched.c +++ b/adreno_hwsched.c @@ -1506,6 +1506,9 @@ static void do_fault_header_lpac(struct adreno_device *adreno_dev, drawobj_lpac->context->gmu_dispatch_queue, lpac_rptr, lpac_wptr, lpac_ib1base, lpac_ib1sz, lpac_ib2base, lpac_ib2sz); + pr_context(device, drawobj_lpac->context, "lpac cmdline: %s\n", + drawctxt_lpac->base.proc_priv->cmdline); + trace_adreno_gpu_fault(drawobj_lpac->context->id, drawobj_lpac->timestamp, status, lpac_rptr, lpac_wptr, lpac_ib1base, lpac_ib1sz, lpac_ib2base, lpac_ib2sz, adreno_get_level(drawobj_lpac->context)); @@ -1541,6 +1544,9 @@ static void do_fault_header(struct adreno_device *adreno_dev, drawobj->context->gmu_dispatch_queue, rptr, wptr, ib1base, ib1sz, ib2base, ib2sz); + pr_context(device, drawobj->context, "cmdline: %s\n", + drawctxt->base.proc_priv->cmdline); + trace_adreno_gpu_fault(drawobj->context->id, drawobj->timestamp, status, rptr, wptr, ib1base, ib1sz, ib2base, ib2sz, adreno_get_level(drawobj->context)); diff --git a/config/gki_khajedisp.conf b/config/gki_khajedisp.conf index bc1590c..ddc889c 100644 --- a/config/gki_khajedisp.conf +++ b/config/gki_khajedisp.conf @@ -1,15 +1,21 @@ CONFIG_DEVFREQ_GOV_QCOM_ADRENO_TZ = y CONFIG_DEVFREQ_GOV_QCOM_GPUBW_MON = y CONFIG_QCOM_KGSL_IDLE_TIMEOUT = 80 -CONFIG_QCOM_KGSL_SORT_POOL = y CONFIG_QCOM_KGSL_CONTEXT_DEBUG = y -CONFIG_QCOM_KGSL_IOCOHERENCY_DEFAULT = y CONFIG_QCOM_ADRENO_DEFAULT_GOVERNOR = \"msm-adreno-tz\" +ifneq ($(CONFIG_SHMEM),) + CONFIG_QCOM_KGSL_USE_SHMEM = y + CONFIG_QCOM_KGSL_PROCESS_RECLAIM = y +endif + ccflags-y += -DCONFIG_DEVFREQ_GOV_QCOM_ADRENO_TZ=1 \ -DCONFIG_DEVFREQ_GOV_QCOM_GPUBW_MON=1 \ -DCONFIG_QCOM_KGSL_IDLE_TIMEOUT=80 \ - -DCONFIG_QCOM_KGSL_SORT_POOL=1 \ -DCONFIG_QCOM_KGSL_CONTEXT_DEBUG=1 \ - -DCONFIG_QCOM_KGSL_IOCOHERENCY_DEFAULT=0 \ -DCONFIG_QCOM_ADRENO_DEFAULT_GOVERNOR=\"msm-adreno-tz\" + +ifneq ($(CONFIG_SHMEM),) + ccflags-y += -DCONFIG_QCOM_KGSL_USE_SHMEM=1 \ + -DCONFIG_QCOM_KGSL_PROCESS_RECLAIM=1 +endif @@ -24,6 +24,7 @@ #include <linux/qcom_dma_heap.h> #include <linux/security.h> #include <linux/sort.h> +#include <linux/string_helpers.h> #include <soc/qcom/of_common.h> #include <soc/qcom/secure_buffer.h> #include <soc/qcom/boot_stats.h> @@ -949,6 +950,7 @@ static void kgsl_destroy_process_private(struct kref *kref) write_unlock(&kgsl_driver.proclist_lock); mutex_unlock(&kgsl_driver.process_mutex); + kfree(private->cmdline); put_pid(private->pid); idr_destroy(&private->mem_idr); idr_destroy(&private->syncsource_idr); @@ -1167,6 +1169,7 @@ static struct kgsl_process_private *kgsl_process_private_new( private->fd_count = 1; private->pid = cur_pid; get_task_comm(private->comm, current->group_leader); + private->cmdline = kstrdup_quotable_cmdline(current, GFP_KERNEL); spin_lock_init(&private->mem_lock); spin_lock_init(&private->syncsource_lock); @@ -5064,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; @@ -5121,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_device.h b/kgsl_device.h index 9980f73..6b7464f 100644 --- a/kgsl_device.h +++ b/kgsl_device.h @@ -528,6 +528,10 @@ struct kgsl_process_private { * @private_mutex: Mutex lock to protect kgsl_process_private */ struct mutex private_mutex; + /** + * @cmdline: Cmdline string of the process + */ + char *cmdline; }; struct kgsl_device_private { 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; } |