Re: [PATCH RFC 2/2] interconnect: qcom: add msm8974 driver

From: Bjorn Andersson
Date: Wed Sep 04 2019 - 01:40:02 EST


On Mon 02 Sep 14:19 PDT 2019, Brian Masney wrote:

> Add driver for the Qualcomm MSM8974 interconnect providers that support
> setting system bandwidth requirements between various network-on-chip
> fabrics.
>
> I marked this as a PATCH RFC since I'm not able to write to all of the
> master IDs with qcom_icc_rpm_smd_send(). I included tables below that
> shows which of the 20 master IDs that I'm able to activate with
> qcom_icc_rpm_smd_send() [1] and the remaining 37 where
> qcom_icc_rpm_smd_send() fails with -ENXIO [2].
>
> The device tree snippets that I'm using is in patch 1 of this series,
> however the relevant interconnect properties for the mdp5 are:
>
> interconnects = <&mmssnoc MNOC_MAS_GRAPHICS_3D &bimc BIMC_SLV_EBI_CH0>,
> <&ocmemnoc OCMEM_VNOC_MAS_GFX3D &ocmemnoc OCMEM_SLV_OCMEM>;
> interconnect-names = "mdp0-mem", "mdp1-mem";
>
> The two interconnects have the following paths:
>
> - mdp0-mem
> - mas_graphics_3d
> - mnoc_to_bimc
> - bimc_to_mnoc
> - slv_ebi_ch0
>
> - mdp1-mem
> - mas_v_ocmem_gfx3d
> - ocmem_vnoc_to_onoc
> - ocmem_noc_to_ocmem_vnoc
> - slv_ocmem
>
> ocmem_noc_to_ocmem_vnoc is the only one that is successfully activated
> and the remaining fail in these two paths.
>
> With this interconnect driver, I am able to remove a clock hack that I
> had in place that set the speed of MDSS_AXI_CLK high and I'm able to use
> kmscube. However, I do see a clock warning on system startup [3].
>
> The display doesn't work for me with the downstream MSM sources so I may
> have to get that working to debug this some more unless anyone has any
> suggestions. I verified that the downstream msm8974 sources are using
> rpm smd to setup the interconnects for the msm bus:
> https://github.com/AICP/kernel_lge_hammerhead/blob/n7.1/arch/arm/mach-msm/msm_bus/msm_bus_rpm_smd.c#L153
> The only difference I noticed is that that upstream uses a 32 bit field
> for the 'value' field in drivers/interconnect/qcom/smd-rpm.c for
> qcom_icc_rpm_smd_send(), and downstream uses a 64 bit value instead.
> Changing that upstream doesn't make a difference.
>
> Downstream msm8974 msm bus code:
> https://github.com/AICP/kernel_lge_hammerhead/blob/n7.1/arch/arm/mach-msm/msm_bus/msm_bus_board_8974.c
>
> [1] Master IDs that I'm able to activate with qcom_icc_rpm_smd_send():
>
> HW ID Name
> -------------------------------
> 3 mas_mss_proc
> 18 slv_tcsr
> 21 slv_crypto_1_cfg
> 22 slv_imem_cfg
> 25 slv_boot_rom
> 29 slv_mpm
> 33 cnoc_to_snoc
> 34 slv_cnoc_onoc_cfg
> 35 slv_cnoc_mnoc_mmss_cfg
> 36 slv_cnoc_mnoc_cfg
> 37 slv_pnoc_cfg
> 38 slv_snoc_mpu_cfg
> 39 slv_snoc_cfg
> 40 slv_ebi1_dll_cfg
> 41 slv_phy_apu_cfg
> 42 slv_ebi1_phy_cfg
> 43 slv_rpm
> 44 slv_service_cnoc
> 52 mnoc_to_bimc
> 54 slv_display_cfg
>
> [2] Master IDs where qcom_icc_rpm_smd_send() fails with -ENXIO. The
> -ENXIO error comes from qcom_smd_rpm_callback() in
> https://elixir.bootlin.com/linux/latest/source/drivers/soc/qcom/smd-rpm.c#L179
>
> HW ID Name
> -------------------------------
> 1 mas_ampss_m0
> 2 mas_ampss_m1
> 4 bimc_to_mnoc
> 5 bimc_to_snoc
> 6 slv_ebi_ch0
> 7 slv_ampss_l2
> 8 mas_rpm_inst
> 9 mas_rpm_data
> 10 mas_rpm_sys
> 11 mas_dehr
> 12 mas_qdss_dap
> 13 mas_spdm
> 14 mas_tic
> 15 slv_clk_ctl
> 16 slv_cnoc_mss
> 17 slv_security
> 19 slv_tlmm
> 20 slv_crypto_0_cfg
> 23 slv_message_ram
> 24 slv_bimc_cfg
> 26 slv_pmic_arb
> 27 slv_spdm_wrapper
> 28 slv_dehr_cfg
> 30 slv_qdss_cfg
> 31 slv_rbcpr_cfg
> 32 slv_rbcpr_qdss_apu_cfg
> 45 mas_graphics_3d
> 46 mas_jpeg
> 47 mas_mdp_port0
> 48 mas_video_p0
> 49 mas_video_p1
> 50 mas_vfe
> 51 mnoc_to_cnoc
> 53 slv_camera_cfg
> 55 slv_ocmem_cfg
> 56 slv_cpr_cfg
> 57 slv_cpr_xpu_cfg
>
> [3] Clock warning on system startup:
>
> WARNING: CPU: 3 PID: 26 at drivers/clk/qcom/clk-rcg2.c:121 update_config+0xe8/0xf0
> gfx3d_clk_src: rcg didn't update its configuration.
> Modules linked in: msm qcom_spmi_vadc qcom_vadc_common pm8941_pwrkey qcom_spmi_iadc msm_vibrator brcmfmac qnoc_msm8974 icc_core inv_mpu6050_i2c(+) inv_mpu6050 brcmutil cfg80211 bq24190_charger tsl2772 rmi_i2c rmi_core icc_smd_rpm usb_f_rndis dm_mod
> CPU: 3 PID: 26 Comm: kworker/3:0 Not tainted 5.3.0-rc4-next-20190816-00021-gd27e1e778708-dirty #148
> Hardware name: Generic DT based system
> Workqueue: events deferred_probe_work_func
> [<c0312328>] (unwind_backtrace) from [<c030d618>] (show_stack+0x10/0x14)
> [<c030d618>] (show_stack) from [<c0a8f8e4>] (dump_stack+0x78/0x8c)
> [<c0a8f8e4>] (dump_stack) from [<c0321b64>] (__warn.part.0+0xb8/0xd4)
> [<c0321b64>] (__warn.part.0) from [<c0321be8>] (warn_slowpath_fmt+0x68/0x94)
> [<c0321be8>] (warn_slowpath_fmt) from [<c07262cc>] (update_config+0xe8/0xf0)
> [<c07262cc>] (update_config) from [<c071d1cc>] (clk_change_rate+0x9c/0x594)
> [<c071d1cc>] (clk_change_rate) from [<c071d850>] (clk_core_set_rate_nolock+0x18c/0x1d4)
> [<c071d850>] (clk_core_set_rate_nolock) from [<c071d8c8>] (clk_set_rate+0x30/0x88)
> [<c071d8c8>] (clk_set_rate) from [<bf16edf8>] (msm_gpu_pm_resume+0x104/0x168 [msm])
> [<bf16edf8>] (msm_gpu_pm_resume [msm]) from [<c07d7c50>] (genpd_runtime_resume+0x9c/0x2a4)
> [<c07d7c50>] (genpd_runtime_resume) from [<c07cd344>] (__rpm_callback+0x74/0x12c)
> [<c07cd344>] (__rpm_callback) from [<c07cd41c>] (rpm_callback+0x20/0x80)
> [<c07cd41c>] (rpm_callback) from [<c07ccf98>] (rpm_resume+0x640/0x814)
> [<c07ccf98>] (rpm_resume) from [<c07cd1bc>] (__pm_runtime_resume+0x50/0x68)
> [<c07cd1bc>] (__pm_runtime_resume) from [<bf11e498>] (adreno_load_gpu+0x50/0x154 [msm])
> [<bf11e498>] (adreno_load_gpu [msm]) from [<bf1690d4>] (msm_open+0x80/0x94 [msm])
> [<bf1690d4>] (msm_open [msm]) from [<c078b32c>] (drm_file_alloc+0x138/0x1f0)
> [<c078b32c>] (drm_file_alloc) from [<c07aebdc>] (drm_client_init+0xa8/0x124)
> [<c07aebdc>] (drm_client_init) from [<c0789700>] (drm_fb_helper_init.part.0+0x30/0x3c)
> [<c0789700>] (drm_fb_helper_init.part.0) from [<bf1740fc>] (msm_fbdev_init+0x4c/0xb4 [msm])
> [<bf1740fc>] (msm_fbdev_init [msm]) from [<bf169c90>] (msm_drm_bind+0x5d4/0x654 [msm])
> [<bf169c90>] (msm_drm_bind [msm]) from [<c07b98b0>] (try_to_bring_up_master+0x1f8/0x2b4)
> [<c07b98b0>] (try_to_bring_up_master) from [<c07b9a1c>] (__component_add+0xb0/0x174)
> [<c07b9a1c>] (__component_add) from [<c07c29e8>] (platform_drv_probe+0x48/0x98)
> [<c07c29e8>] (platform_drv_probe) from [<c07c0578>] (really_probe+0x24c/0x480)
> [<c07c0578>] (really_probe) from [<c07c09a0>] (driver_probe_device+0xa0/0x1f8)
> [<c07c09a0>] (driver_probe_device) from [<c07be5ec>] (bus_for_each_drv+0x84/0xd0)
> [<c07be5ec>] (bus_for_each_drv) from [<c07c028c>] (__device_attach+0xe0/0x178)
> [<c07c028c>] (__device_attach) from [<c07bf3c4>] (bus_probe_device+0x84/0x8c)
> [<c07bf3c4>] (bus_probe_device) from [<c07bf91c>] (deferred_probe_work_func+0x84/0xc4)
> [<c07bf91c>] (deferred_probe_work_func) from [<c033d2a8>] (process_one_work+0x1dc/0x538)
> [<c033d2a8>] (process_one_work) from [<c033ebf8>] (worker_thread+0x44/0x508)
> [<c033ebf8>] (worker_thread) from [<c0343370>] (kthread+0x120/0x150)
> [<c0343370>] (kthread) from [<c03010e8>] (ret_from_fork+0x14/0x2c)

I haven't checked the docs, but we see pretty much the same problem on
subsequent platforms if things are now powered properly. And there's a
OXILI gdsc (power domain) which is fed by pm8841_s4 corner, according to
the downstream DT.

[..]
> diff --git a/drivers/interconnect/qcom/msm8974.c b/drivers/interconnect/qcom/msm8974.c
[..]
> +DEFINE_QNODE(mas_ampss_m0, MSM8974_BIMC_MAS_AMPSS_M0, 8, 0, -1);
> +DEFINE_QNODE(mas_ampss_m1, MSM8974_BIMC_MAS_AMPSS_M1, 8, 0, -1);
> +DEFINE_QNODE(mas_mss_proc, MSM8974_BIMC_MAS_MSS_PROC, 8, 1, -1);
> +DEFINE_QNODE(bimc_to_mnoc, MSM8974_BIMC_TO_MNOC, 8, 2, -1,
> + MSM8974_BIMC_SLV_EBI_CH0);

None of these looks excessive, so please ignore the 80-char rule to
improve readability.

> +DEFINE_QNODE(bimc_to_snoc, MSM8974_BIMC_TO_SNOC, 8, 3, 2,
> + MSM8974_SNOC_TO_BIMC, MSM8974_BIMC_SLV_EBI_CH0,
> + MSM8974_BIMC_MAS_AMPSS_M0);
> +DEFINE_QNODE(slv_ebi_ch0, MSM8974_BIMC_SLV_EBI_CH0, 8, -1, 0);
> +DEFINE_QNODE(slv_ampss_l2, MSM8974_BIMC_SLV_AMPSS_L2, 8, -1, 1);
> +
[..]
> +static int qnoc_probe(struct platform_device *pdev)
> +{
> + struct device *dev = &pdev->dev;
> + const struct qcom_icc_desc *desc;
> + struct icc_onecell_data *data;
> + struct icc_provider *provider;
> + struct qcom_icc_node **qnodes;
> + struct qcom_icc_provider *qp;
> + struct icc_node *node;
> + size_t num_nodes, i;
> + int ret;
> +
> + /* wait for the RPM proxy */
> + if (!qcom_icc_rpm_smd_available())
> + return -EPROBE_DEFER;
> +
> + desc = of_device_get_match_data(dev);
> + if (!desc)
> + return -EINVAL;
> +
> + qnodes = desc->nodes;
> + num_nodes = desc->num_nodes;
> +
> + qp = devm_kzalloc(dev, sizeof(*qp), GFP_KERNEL);
> + if (!qp)
> + return -ENOMEM;
> +
> + data = devm_kcalloc(dev, num_nodes, sizeof(*node), GFP_KERNEL);
> + if (!data)
> + return -ENOMEM;
> +
> + qp->bus_clks = devm_kmemdup(dev, bus_clocks, sizeof(bus_clocks),
> + GFP_KERNEL);
> + if (!qp->bus_clks)
> + return -ENOMEM;
> +
> + qp->num_clks = ARRAY_SIZE(bus_clocks);
> + ret = devm_clk_bulk_get(dev, qp->num_clks, qp->bus_clks);
> + if (ret)
> + return ret;
> +
> + ret = clk_bulk_prepare_enable(qp->num_clks, qp->bus_clks);

We should be able to turn these off when there are no active/enabled
paths passing by this particular bus. But let's postpone that problem.

> + if (ret)
> + return ret;
> +
> + provider = &qp->provider;
> + INIT_LIST_HEAD(&provider->nodes);
> + provider->dev = dev;
> + provider->set = qcom_icc_set;
> + provider->aggregate = qcom_icc_aggregate;
> + provider->xlate = of_icc_xlate_onecell;
> + provider->data = data;
> +
> + ret = icc_provider_add(provider);
> + if (ret) {
> + dev_err(dev, "error adding interconnect provider: %d\n", ret);
> + clk_bulk_disable_unprepare(qp->num_clks, qp->bus_clks);

Flip the order of clk_bulk_disable_unprepare() and icc_provider_del() in
the error path, inject a new label for the clk diable and replace this
with a goto err_disable_clks;

> + return ret;
> + }
> +
> + for (i = 0; i < num_nodes; i++) {
> + size_t j;
> +
> + node = icc_node_create(qnodes[i]->id);
> + if (IS_ERR(node)) {
> + ret = PTR_ERR(node);
> + goto err;
> + }
> +
> + node->name = qnodes[i]->name;
> + node->data = qnodes[i];
> + icc_node_add(node, provider);
> +
> + dev_dbg(dev, "registered node %s\n", node->name);
> +
> + /* populate links */
> + for (j = 0; j < qnodes[i]->num_links; j++)
> + icc_link_create(node, qnodes[i]->links[j]);
> +
> + data->nodes[i] = node;
> + }
> + data->num_nodes = num_nodes;
> +
> + platform_set_drvdata(pdev, qp);
> +
> + return 0;
> +err:
> + list_for_each_entry(node, &provider->nodes, node_list) {
> + icc_node_del(node);
> + icc_node_destroy(node->id);
> + }
> + clk_bulk_disable_unprepare(qp->num_clks, qp->bus_clks);
> + icc_provider_del(provider);
> +
> + return ret;
> +}
> +
> +static int qnoc_remove(struct platform_device *pdev)
> +{
> + struct qcom_icc_provider *qp = platform_get_drvdata(pdev);
> + struct icc_provider *provider = &qp->provider;
> + struct icc_node *n;
> +
> + list_for_each_entry(n, &provider->nodes, node_list) {
> + icc_node_del(n);
> + icc_node_destroy(n->id);
> + }
> + clk_bulk_disable_unprepare(qp->num_clks, qp->bus_clks);
> +
> + return icc_provider_del(provider);

It's nice when remove unrolls probe, so please flip the order of clk
disable and provider_del.

Regards,
Bjorn

> +}
> +
> +static const struct of_device_id msm8974_noc_of_match[] = {
> + { .compatible = "qcom,msm8974-bimc", .data = &msm8974_bimc},
> + { .compatible = "qcom,msm8974-cnoc", .data = &msm8974_cnoc},
> + { .compatible = "qcom,msm8974-mmssnoc", .data = &msm8974_mnoc},
> + { .compatible = "qcom,msm8974-ocmemnoc", .data = &msm8974_onoc},
> + { .compatible = "qcom,msm8974-pnoc", .data = &msm8974_pnoc},
> + { .compatible = "qcom,msm8974-snoc", .data = &msm8974_snoc},
> + { },
> +};
> +MODULE_DEVICE_TABLE(of, msm8974_noc_of_match);
> +
> +static struct platform_driver msm8974_noc_driver = {
> + .probe = qnoc_probe,
> + .remove = qnoc_remove,
> + .driver = {
> + .name = "qnoc-msm8974",
> + .of_match_table = msm8974_noc_of_match,
> + },
> +};
> +module_platform_driver(msm8974_noc_driver);
> +MODULE_DESCRIPTION("Qualcomm MSM8974 NoC driver");
> +MODULE_AUTHOR("Brian Masney <masneyb@xxxxxxxxxxxxx>");
> +MODULE_LICENSE("GPL v2");
> --
> 2.21.0
>