[PATCH v1] perf/hx_arm_ni: Support uncore ARM NI-700 PMU

Krzysztof Kozlowski krzysztof.kozlowski at linaro.org
Tue Jan 30 00:43:09 PST 2024


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 at shingroup.cn>
> ---
> 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 at shingroup.cn>
> +
> +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 at 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




More information about the linux-arm-kernel mailing list