Re: [PATCH v1] perf/hx_arm_ni: Support uncore ARM NI-700 PMU
From: Krzysztof Kozlowski
Date: Tue Jan 30 2024 - 03:44:02 EST
On 30/01/2024 09:17, JiaLong.Yang wrote:
> This code is based on uncore PMUs arm_smmuv3_pmu and arm-cmn.
> One ni-700 can have many clock domains. Each of them has only one PMU.
> Here one PMU corresponds to one 'struct ni_pmu' instance.
> PMU name will be ni_pmu_N_M, which N means different NI-700s and M means
> different PMU in one NI-700. If only one NI-700 found in NI-700, name will
> be ni_pmu_N.
> Node interface event name will be xxni_N_eventname, such as asni_0_rdreq_any.
> There are many kinds of type of nodes in one clock domain. Also means that
> there are many kinds of that in one PMU. So we distinguish them by xxni string.
> Besides, maybe there are many nodes have same type. So we have number N in
> event name.
> By ni_pmu_0_0/asni_0_rdreq_any/, we can pinpoint accurate bus traffic.
> Example1: perf stat -a -e ni_pmu_0_0/asni_0_rdreq_any/,ni_pmu_0_0/cycles/
> EXample2: perf stat -a -e ni_pmu_0_0/asni,id=0,event=0x0/
>
> Signed-off-by: JiaLong.Yang <jialong.yang@xxxxxxxxxxxx>
> ---
> If I should send Doc*/bindings/perf/*.yaml seperately?
Checkpatch tells you that, doesn't it?
Please run scripts/checkpatch.pl and fix reported warnings. Some
warnings can be ignored, but the code here looks like it needs a fix.
Feel free to get in touch if the warning is not clear.
>
> .../bindings/perf/hx,c2000-arm-ni.yaml | 58 +
> .../devicetree/bindings/vendor-prefixes.yaml | 2 +
> MAINTAINERS | 6 +
> drivers/perf/Kconfig | 10 +
> drivers/perf/Makefile | 1 +
> drivers/perf/hx_arm_ni.c | 1308 +++++++++++++++++
> 6 files changed, 1385 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/perf/hx,c2000-arm-ni.yaml
> create mode 100644 drivers/perf/hx_arm_ni.c
>
> diff --git a/Documentation/devicetree/bindings/perf/hx,c2000-arm-ni.yaml b/Documentation/devicetree/bindings/perf/hx,c2000-arm-ni.yaml
> new file mode 100644
> index 000000000000..1b145ecbfa83
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/perf/hx,c2000-arm-ni.yaml
> @@ -0,0 +1,58 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/perf/hx,c2000-arm-ni.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: HX-C2000 NI (Network-on_chip Interconnect) Performance Monitors
> +
> +maintainers:
> + - Jialong Yang <jialong.yang@xxxxxxxxxxxx>
> +
> +properties:
> + compatible:
> + enum:
> + - hx,c2000-arm-ni
> +
> + reg:
> + items:
> + - description: Physical address of the base (PERIPHBASE) and
> + size of the whole NI configuration address space.
> +
> + interrupts:
> + minItems: 1
Why?
> + items:
> + - description: Overflow interrupt for clock domain 0
> + - description: Overflow interrupt for clock domain 1
> + - description: Overflow interrupt for clock domain 2
> + description: Generally, one interrupt line for one PMU. But this also
> + support one interrupt line for a NI if merged.
> +
> +required:
> + - compatible
> + - reg
> + - interrupts
> +
> +if:
> + properties:
> + compatible:
> + contains:
> + const: hx,c2000-arm-ni
Drop entire if. What is the point of it?
> +then:
> + required:
> + - pccs-id
> +
> +additionalProperties: false
> +
> +examples:
> + - |
> + #include <dt-bindings/interrupt-controller/arm-gic.h>
> + #include <dt-bindings/interrupt-controller/irq.h>
> +
> + ni-pmu@23ff0000 {
Node names should be generic. See also an explanation and list of
examples (not exhaustive) in DT specification:
https://devicetree-specification.readthedocs.io/en/latest/chapter2-devicetree-basics.html#generic-names-recommendation
> + compatible = "hx,c2000-arm-ni";
> + #address-cells = <1>;
> + #size-cells = <1>;
Broken indentation.....
(...)
> + ni_pmu->dev = dev;
> + ni_pmu->ni = ni;
> + ni->ni_pmus[cd_idx] = ni_pmu;
> + }
> +
> + devm_kfree(dev, cd_arrays);
> +
> + pr_info("End discovering hardware registers.");
That's rather useless print. First entire driver must use dev_*. Second,
drop it, no need for end-of-function prints.
> +
> + return 0;
> +}
> +
> +static int ni_pmu_probe(struct platform_device *pdev)
> +{
> + int ret, cd_num, idx, irq_num, irq_idx;
> + void __iomem *periphbase;
> + struct global_ni *ni;
> + struct device *dev = &pdev->dev;
> + char *name;
> + static int id;
> + struct ni_pmu *ni_pmu;
> +
> + BUILD_BUG_ON(sizeof(long) == 4);
I am sorry, but what?
> + BUILD_BUG_ON(sizeof(struct ni_hw_perf_event) >
> + offsetof(struct hw_perf_event, target));
> +#define NI_PMU_REG_MAP_SIZE 0xE08
> + BUILD_BUG_ON(sizeof(struct ni_pmu_reg_map) != NI_PMU_REG_MAP_SIZE);
> +
> + pr_info("Begin probing.");
NAK, drop. Drop all silly entrance/exit messages. EVERYWHERE.
> +
> + periphbase = devm_platform_ioremap_resource(pdev, 0);
> +
Drop blank line
> + if (IS_ERR(periphbase)) {
> + pr_err("%s: ioremap error.", __func__);
dev_err and you need to print something useful, like error code. Or use
return dev_err_probe
> + return PTR_ERR(periphbase);
> + }
> +
> + cd_num = ni_child_number_total(periphbase, periphbase, NI_CD);
> + pr_info("%d clock domains found in NI-700.", cd_num);
Really, what's with all this printing?
> +
> + /* Each clock domain contains one PMU. So cd_num == pmu_num. */
> + ni = devm_kzalloc(dev,
> + struct_size(ni, ni_pmus, cd_num),
> + GFP_KERNEL);
> + if (!ni)
> + return -ENOMEM;
> +
> + ni->cd_num = cd_num;
> + ni->base = periphbase;
> + ni->dev = dev;
> + ni->on_cpu = raw_smp_processor_id();
> + platform_set_drvdata(pdev, ni);
> +
> + ret = ni_discovery(ni);
> + if (ret) {
> + pr_err("%s: discovery error.", __func__);
> + return ret;
> + }
> +
> + irq_num = platform_irq_count(pdev);
> + /* Support that one NI with one irq or one clock domain with one irq. */
> + if (irq_num < 0 || (irq_num != 1 && irq_num != ni->cd_num)) {
> + pr_err("Error in irq number: %d.", irq_num);
> + return -EINVAL;
> + }
> +
> + if (irq_num != cd_num) {
> + pr_warn("Only one IRQ found for all PMU.");
> + ret = ni_pmu_irq_setup(ni->ni_pmus[0], 0);
> + if (ret)
> + return ret;
> + }
> +
> + ni->irq_num = irq_num;
> +
> + for (idx = 0, irq_idx = 0; idx < ni->pmu_num; idx++) {
> + ni_pmu = ni->ni_pmus[idx];
> + ret = ni_pmu_init_attr_groups(ni_pmu);
> + if (ret)
> + return ret;
> +
> + if (irq_num == cd_num) {
> + ret = ni_pmu_irq_setup(ni_pmu, irq_idx++);
> + if (ret)
> + return ret;
> + }
> +
> + ni_pmu_reset(ni_pmu);
> +
> + ni_pmu->pmu = (struct pmu) {
> + .module = THIS_MODULE,
> + .task_ctx_nr = perf_invalid_context,
> + .pmu_enable = ni_pmu_enable,
> + .pmu_disable = ni_pmu_disable,
> + .event_init = ni_pmu_event_init,
> + .add = ni_pmu_event_add,
> + .del = ni_pmu_event_del,
> + .start = ni_pmu_event_start,
> + .stop = ni_pmu_event_stop,
> + .read = ni_pmu_event_read,
> + .attr_groups = ni_pmu->pmu.attr_groups,
> + .capabilities = PERF_PMU_CAP_NO_EXCLUDE | PERF_PMU_CAP_NO_INTERRUPT,
> + };
> +
> +#ifdef CONFIG_PPC_HX_C2000
> + if (of_property_read_u32(pdev->dev.of_node, "pccs-id", &id))
> + pr_warn("No found pccs_id in dts ni pmu node.");
> +#endif
> + if (cd_num > 1)
> + name = devm_kasprintf(dev, GFP_KERNEL, "ni_pmu_%d_%d", id++, idx);
> + else
> + name = devm_kasprintf(dev, GFP_KERNEL, "ni_pmu_%d", id++);
> +
> + ret = perf_pmu_register(&ni_pmu->pmu, name, -1);
> + if (ret) {
> + pr_err("Error %d_%d registering PMU", id - 1, idx);
> + return ret;
> + }
> + }
> +
> + ret = cpuhp_state_add_instance_nocalls(ni_hp_state,
> + &ni->node);
> + if (ret)
> + return ret;
> + pr_info("End probing.");
No, drop.
> +
> + return 0;
> +}
> +
> +static int ni_pmu_remove(struct platform_device *pdev)
> +{
> + struct global_ni *ni = platform_get_drvdata(pdev);
> + int idx;
> +
> + for (idx = 0; idx < ni->pmu_num; idx++)
> + perf_pmu_unregister(&ni->ni_pmus[idx]->pmu);
> +
> + cpuhp_remove_multi_state(ni_hp_state);
> + return 0;
> +}
> +
> +static const struct of_device_id ni_pmu_of_match[] = {
> + { .compatible = "hx,c2000-arm-ni" },
> + {},
> +};
> +
> +static struct platform_driver ni_pmu_driver = {
> + .driver = {
> + .name = "ni-pmu",
> + .of_match_table = of_match_ptr(ni_pmu_of_match),
Drop of_match_ptr. Leads to warnings.
..
> +
> +module_init(ni_pmu_init);
> +module_exit(ni_pmu_exit);
> +/* PLATFORM END */
Useless comment. Please clean your code from debugging or useless markers.
Best regards,
Krzysztof