* [PATCH 7/8] net: mv643xx: use platform_device_set_fwnode()
From: Bartosz Golaszewski @ 2026-07-20 9:24 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich,
Madhavan Srinivasan, Michael Ellerman, Nicholas Piggin,
Christophe Leroy (CS GROUP), Andi Shyti, Joerg Roedel (AMD),
Will Deacon, Robin Murphy, Andy Shevchenko, Doug Berger,
Florian Fainelli, Broadcom internal kernel review list,
Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Ulf Hansson, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, Lee Jones,
Sebastian Hesselbarth, Srinivas Kandagatla
Cc: brgl, driver-core, linuxppc-dev, linux-kernel, linux-i2c, iommu,
netdev, linux-pm, imx, linux-arm-kernel, mfd, linux-arm-msm,
linux-sound, Bartosz Golaszewski
In-Reply-To: <20260720-pdev-set-fwnode-instead-of-of-node-v1-0-2dee93f42c54@oss.qualcomm.com>
Prefer the higher-level platform_device_set_fwnode() over the
OF-specific platform_device_set_of_node() for dynamically allocated
platform devices.
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
---
drivers/net/ethernet/marvell/mv643xx_eth.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/marvell/mv643xx_eth.c b/drivers/net/ethernet/marvell/mv643xx_eth.c
index 9caa1e47c174c9d7a161b7f2e2ee12a829b813d4..2f2d6cce8d852b9ec3ab42678a04a7915d1f00cc 100644
--- a/drivers/net/ethernet/marvell/mv643xx_eth.c
+++ b/drivers/net/ethernet/marvell/mv643xx_eth.c
@@ -2780,7 +2780,7 @@ static int mv643xx_eth_shared_of_add_port(struct platform_device *pdev,
goto put_err;
}
ppdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
- platform_device_set_of_node(ppdev, pnp);
+ platform_device_set_fwnode(ppdev, of_fwnode_handle(pnp));
ret = platform_device_add_resources(ppdev, &res, 1);
if (ret)
--
2.47.3
^ permalink raw reply related
* [PATCH 8/8] slimbus: qcom-ngd-ctrl: use platform_device_set_fwnode()
From: Bartosz Golaszewski @ 2026-07-20 9:24 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich,
Madhavan Srinivasan, Michael Ellerman, Nicholas Piggin,
Christophe Leroy (CS GROUP), Andi Shyti, Joerg Roedel (AMD),
Will Deacon, Robin Murphy, Andy Shevchenko, Doug Berger,
Florian Fainelli, Broadcom internal kernel review list,
Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Ulf Hansson, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, Lee Jones,
Sebastian Hesselbarth, Srinivas Kandagatla
Cc: brgl, driver-core, linuxppc-dev, linux-kernel, linux-i2c, iommu,
netdev, linux-pm, imx, linux-arm-kernel, mfd, linux-arm-msm,
linux-sound, Bartosz Golaszewski
In-Reply-To: <20260720-pdev-set-fwnode-instead-of-of-node-v1-0-2dee93f42c54@oss.qualcomm.com>
Prefer the higher-level platform_device_set_fwnode() over the
OF-specific platform_device_set_of_node() for dynamically allocated
platform devices.
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
---
drivers/slimbus/qcom-ngd-ctrl.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/slimbus/qcom-ngd-ctrl.c b/drivers/slimbus/qcom-ngd-ctrl.c
index 934c44c5bc1a92fae98f52bccd12ed849379dca8..bf077f47c9ddd484c11f98b47d2d8d4daf78dcb7 100644
--- a/drivers/slimbus/qcom-ngd-ctrl.c
+++ b/drivers/slimbus/qcom-ngd-ctrl.c
@@ -1538,7 +1538,7 @@ static int of_qcom_slim_ngd_register(struct device *parent,
kfree(ngd);
return ret;
}
- platform_device_set_of_node(ngd->pdev, node);
+ platform_device_set_fwnode(ngd->pdev, of_fwnode_handle(node));
ctrl->ngd = ngd;
ret = platform_device_add(ngd->pdev);
--
2.47.3
^ permalink raw reply related
* Re: [kvm-unit-tests PATCH v2 0/6] powerpc improvements
From: Thomas Huth @ 2026-07-20 9:30 UTC (permalink / raw)
To: Chinmay Rath
Cc: npiggin, harshpb, lvivier, linuxppc-dev, kvm, andrew.jones, sbhat
In-Reply-To: <20260719130027.2347519-1-rathc@linux.ibm.com>
On 19/07/2026 15.00, Chinmay Rath wrote:
> This series aims to add a couple of new powerpc tests and improve the
> powerpc build structure.
>
> This is originally Nick's work. The last version (v10) of which can be seen here :
> https://lore.kernel.org/linuxppc-dev/20240612052322.218726-1-npiggin@gmail.com/
> Couple of patches from the series are already merged.
>
> Since it has been 2 years since this series was posted, I originally
> posted this as a RFC. This v1 series has changes accomodating the review comments
> received in the RFC :
> https://lore.kernel.org/kvm/20260602064806.3101025-1-rathc@linux.ibm.com/
> v1:
> https://lore.kernel.org/kvm/20260708105122.1177210-1-rathc@linux.ibm.com/
>
> I have rebased the patches to the upstream state.
> For the patches which did not require any changes in the existing upstream code,
> I have retained the "Reviewed-by"s and "Acked-by" (patch 3,5 & 6) from
> Nick's series. I have also added Andrew's "Reviewed-by" received on
> patch 2 in the RFC. Nick had originally introduced powernv tests as well.
> Removed it for now since it was causing CI failure in the current upstream.
>
> Link to Gitlab tree with patches :
> https://gitlab.com/rathc/kvm-unit-tests/-/tree/ppc64
> Link to Gitlab pipeline :
> https://gitlab.com/rathc/kvm-unit-tests/-/pipelines/2688519679
>
> Change log from RFC to v1:
> 1. Patch 2: Added Andrew's "Reviewed-by".
> 2. Patch 4: Removed usage of gitlab-ci group to run test - Thomas
> It would be nice to make use of the gitlab-ci group, but doing the
> change of all archs would make sense in a separate series. I look
> forward to doing that.
> 3. Patch 6: Removed addition of panic test in gitlab-ci group - Thomas
>
> There was a discussion on the build failing in Travis CI with Clang, in the
> RFC, which I have addressed there.
>
> Change log from v1 to v2:
> Patch 4: Addressed all comments by Thomas :
> 1. Removed extra blank line.
> 2. Removed accel=kvm test from gitlab-ci.
> 3. smp = 2 preserved in atmoics test.
Thanks, looks fine now, so I pushed it to the repository.
Thomas
^ permalink raw reply
* Re: [PATCH 2/8] i2c: pxa-pci: use platform_device_set_fwnode()
From: Wolfram Sang @ 2026-07-20 9:41 UTC (permalink / raw)
To: Bartosz Golaszewski
Cc: Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich,
Madhavan Srinivasan, Michael Ellerman, Nicholas Piggin,
Christophe Leroy (CS GROUP), Andi Shyti, Joerg Roedel (AMD),
Will Deacon, Robin Murphy, Andy Shevchenko, Doug Berger,
Florian Fainelli, Broadcom internal kernel review list,
Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Ulf Hansson, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, Lee Jones,
Sebastian Hesselbarth, Srinivas Kandagatla, brgl, driver-core,
linuxppc-dev, linux-kernel, linux-i2c, iommu, netdev, linux-pm,
imx, linux-arm-kernel, mfd, linux-arm-msm, linux-sound
In-Reply-To: <20260720-pdev-set-fwnode-instead-of-of-node-v1-2-2dee93f42c54@oss.qualcomm.com>
On Mon, Jul 20, 2026 at 11:24:49AM +0200, Bartosz Golaszewski wrote:
> Prefer the higher-level platform_device_set_fwnode() over the
> OF-specific platform_device_set_of_node() for dynamically allocated
> platform devices.
>
> Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Fine with me.
Reviewed-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
Note that we still need Andi's ack.
^ permalink raw reply
* [PATCH 0/4] ASoC: fsl: expose individual DAIs per ASRC/EASRC conversion pair/context
From: shengjiu.wang @ 2026-07-20 9:54 UTC (permalink / raw)
To: lgirdwood, broonie, robh, krzk+dt, conor+dt, Frank.Li, s.hauer,
kernel, festevam, shawnguo, linux-sound, devicetree, imx,
linux-arm-kernel, linux-kernel, shengjiu.wang, Xiubo.Lee,
nicoleotsuka, perex, tiwai, linuxppc-dev
Cc: Shengjiu Wang
From: Shengjiu Wang <shengjiu.wang@nxp.com>
The i.MX ASRC and EASRC hardware each support multiple independent
conversion pairs or contexts, but both drivers previously registered
only a single DAI with generic stream names. This prevented individual
pairs or contexts from being routed to separate audio paths at the same
time.
This series updates the DT bindings and drivers to expose one DAI per
conversion unit:
- fsl,imx-asrc: add a ports container (port@0/1/2 for pairs A/B/C)
alongside the deprecated single port property
- fsl,easrc: add a ports container (port@0/1/2/3 for contexts A/B/C/D)
- fsl_asrc: register three DAIs (paira/pairb/pairc); pair A keeps the
original stream names for backward compatibility
- fsl_easrc: register four DAIs (ctxa/ctxb/ctxc/ctxd); context A keeps
the original stream names for backward compatibility
Shengjiu Wang (4):
dt-bindings: sound: fsl,imx-asrc: update port binding to support
multiple pairs
dt-bindings: sound: fsl,easrc: add ports binding for multiple contexts
ASoC: fsl_asrc: expose individual DAIs per conversion pair
ASoC: fsl_easrc: expose individual DAIs per conversion context
.../devicetree/bindings/sound/fsl,easrc.yaml | 79 ++++++++++++
.../bindings/sound/fsl,imx-asrc.yaml | 78 ++++++++++++
sound/soc/fsl/fsl_asrc.c | 89 ++++++++++----
sound/soc/fsl/fsl_easrc.c | 112 ++++++++++++++----
4 files changed, 318 insertions(+), 40 deletions(-)
--
2.34.1
^ permalink raw reply
* [PATCH 1/4] dt-bindings: sound: fsl,imx-asrc: update port binding to support multiple pairs
From: shengjiu.wang @ 2026-07-20 9:54 UTC (permalink / raw)
To: lgirdwood, broonie, robh, krzk+dt, conor+dt, Frank.Li, s.hauer,
kernel, festevam, shawnguo, linux-sound, devicetree, imx,
linux-arm-kernel, linux-kernel, shengjiu.wang, Xiubo.Lee,
nicoleotsuka, perex, tiwai, linuxppc-dev
Cc: Shengjiu Wang
In-Reply-To: <20260720095450.1618747-1-shengjiu.wang@oss.nxp.com>
From: Shengjiu Wang <shengjiu.wang@nxp.com>
The i.MX ASRC hardware supports up to three conversion pairs (A, B, C).
The existing binding exposed only a single generic audio-graph port,
which cannot represent the individual pair endpoints.
Add a ports container that enumerates three named sub-ports:
port@0 -- pair A
port@1 -- pair B
port@2 -- pair C
Each sub-port references audio-graph-port.yaml as before.
For backwards compatibility, keep the old single port property but mark
it deprecated. A schema constraint (not: required: [port, ports]) ensures
that both forms cannot be used at the same time. Update the examples to
show both the new ports form and the deprecated port form.
No existing upstream DTS file for fsl,imx-asrc uses the previously
documented single 'port' node, so this change does not break any
in-tree device tree.
Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
---
.../bindings/sound/fsl,imx-asrc.yaml | 78 +++++++++++++++++++
1 file changed, 78 insertions(+)
diff --git a/Documentation/devicetree/bindings/sound/fsl,imx-asrc.yaml b/Documentation/devicetree/bindings/sound/fsl,imx-asrc.yaml
index 608defc93c1e..18d252722aa8 100644
--- a/Documentation/devicetree/bindings/sound/fsl,imx-asrc.yaml
+++ b/Documentation/devicetree/bindings/sound/fsl,imx-asrc.yaml
@@ -78,9 +78,29 @@ properties:
power-domains:
maxItems: 1
+ ports:
+ $ref: /schemas/graph.yaml#/properties/ports
+ properties:
+ port@0:
+ $ref: audio-graph-port.yaml#
+ unevaluatedProperties: false
+ description: port for pair A
+
+ port@1:
+ $ref: audio-graph-port.yaml#
+ unevaluatedProperties: false
+ description: port for pair B
+
+ port@2:
+ $ref: audio-graph-port.yaml#
+ unevaluatedProperties: false
+ description: port for pair C
+
port:
$ref: audio-graph-port.yaml#
unevaluatedProperties: false
+ deprecated: true
+ description: deprecated, use ports instead
fsl,asrc-rate:
$ref: /schemas/types.yaml#/definitions/uint32
@@ -125,6 +145,10 @@ required:
- fsl,asrc-width
allOf:
+ - not:
+ required:
+ - port
+ - ports
- $ref: dai-common.yaml#
- if:
properties:
@@ -188,3 +212,57 @@ examples:
};
};
};
+
+ - |
+ #include <dt-bindings/interrupt-controller/irq.h>
+ #include <dt-bindings/clock/imx6qdl-clock.h>
+ asrc1: asrc@2034000 {
+ compatible = "fsl,imx53-asrc";
+ reg = <0x02034000 0x4000>;
+ interrupts = <0 50 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clks IMX6QDL_CLK_ASRC_IPG>,
+ <&clks IMX6QDL_CLK_ASRC_MEM>, <&clks 0>,
+ <&clks 0>, <&clks 0>, <&clks 0>, <&clks 0>,
+ <&clks 0>, <&clks 0>, <&clks 0>, <&clks 0>,
+ <&clks 0>, <&clks 0>, <&clks 0>, <&clks 0>,
+ <&clks IMX6QDL_CLK_ASRC>, <&clks 0>, <&clks 0>,
+ <&clks IMX6QDL_CLK_SPBA>;
+ clock-names = "mem", "ipg", "asrck_0",
+ "asrck_1", "asrck_2", "asrck_3", "asrck_4",
+ "asrck_5", "asrck_6", "asrck_7", "asrck_8",
+ "asrck_9", "asrck_a", "asrck_b", "asrck_c",
+ "asrck_d", "asrck_e", "asrck_f", "spba";
+ dmas = <&sdma 17 23 1>, <&sdma 18 23 1>, <&sdma 19 23 1>,
+ <&sdma 20 23 1>, <&sdma 21 23 1>, <&sdma 22 23 1>;
+ dma-names = "rxa", "rxb", "rxc",
+ "txa", "txb", "txc";
+ fsl,asrc-rate = <48000>;
+ fsl,asrc-width = <16>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ playback-only;
+ asrc1_endpoint0: endpoint {
+ remote-endpoint = <&fe00_ep>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+ capture-only;
+ asrc1_endpoint1: endpoint {
+ };
+ };
+
+ port@2 {
+ reg = <2>;
+ capture-only;
+ asrc1_endpoint2: endpoint {
+ };
+ };
+ };
+ };
--
2.34.1
^ permalink raw reply related
* [PATCH 2/4] dt-bindings: sound: fsl,easrc: add ports binding for multiple contexts
From: shengjiu.wang @ 2026-07-20 9:54 UTC (permalink / raw)
To: lgirdwood, broonie, robh, krzk+dt, conor+dt, Frank.Li, s.hauer,
kernel, festevam, shawnguo, linux-sound, devicetree, imx,
linux-arm-kernel, linux-kernel, shengjiu.wang, Xiubo.Lee,
nicoleotsuka, perex, tiwai, linuxppc-dev
Cc: Shengjiu Wang
In-Reply-To: <20260720095450.1618747-1-shengjiu.wang@oss.nxp.com>
From: Shengjiu Wang <shengjiu.wang@nxp.com>
The i.MX EASRC hardware supports up to four conversion contexts
(A, B, C, D). Add a ports container property to the binding to allow
each context to be represented as an individual audio-graph port:
port@0 -- context A
port@1 -- context B
port@2 -- context C
port@3 -- context D
Each sub-port references audio-graph-port.yaml and follows the standard
audio-graph binding conventions.
Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
---
.../devicetree/bindings/sound/fsl,easrc.yaml | 79 +++++++++++++++++++
1 file changed, 79 insertions(+)
diff --git a/Documentation/devicetree/bindings/sound/fsl,easrc.yaml b/Documentation/devicetree/bindings/sound/fsl,easrc.yaml
index d5727f8bfb0b..0f579870110d 100644
--- a/Documentation/devicetree/bindings/sound/fsl,easrc.yaml
+++ b/Documentation/devicetree/bindings/sound/fsl,easrc.yaml
@@ -55,6 +55,29 @@ properties:
- const: imx/easrc/easrc-imx8mn.bin
description: The coefficient table for the filters
+ ports:
+ $ref: /schemas/graph.yaml#/properties/ports
+ properties:
+ port@0:
+ $ref: audio-graph-port.yaml#
+ unevaluatedProperties: false
+ description: port for context A
+
+ port@1:
+ $ref: audio-graph-port.yaml#
+ unevaluatedProperties: false
+ description: port for context B
+
+ port@2:
+ $ref: audio-graph-port.yaml#
+ unevaluatedProperties: false
+ description: port for context C
+
+ port@3:
+ $ref: audio-graph-port.yaml#
+ unevaluatedProperties: false
+ description: port for context D
+
fsl,asrc-rate:
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 8000
@@ -107,3 +130,59 @@ examples:
fsl,asrc-rate = <8000>;
fsl,asrc-format = <2>;
};
+
+ - |
+ #include <dt-bindings/clock/imx8mn-clock.h>
+
+ easrc1: easrc@300c0000 {
+ compatible = "fsl,imx8mn-easrc";
+ reg = <0x300c0000 0x10000>;
+ interrupts = <0x0 122 0x4>;
+ clocks = <&clk IMX8MN_CLK_ASRC_ROOT>;
+ clock-names = "mem";
+ dmas = <&sdma2 16 23 0> , <&sdma2 17 23 0>,
+ <&sdma2 18 23 0> , <&sdma2 19 23 0>,
+ <&sdma2 20 23 0> , <&sdma2 21 23 0>,
+ <&sdma2 22 23 0> , <&sdma2 23 23 0>;
+ dma-names = "ctx0_rx", "ctx0_tx",
+ "ctx1_rx", "ctx1_tx",
+ "ctx2_rx", "ctx2_tx",
+ "ctx3_rx", "ctx3_tx";
+ firmware-name = "imx/easrc/easrc-imx8mn.bin";
+ fsl,asrc-rate = <8000>;
+ fsl,asrc-format = <2>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ playback-only;
+ easrc1_endpoint0: endpoint {
+ remote-endpoint = <&fe00_ep>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+ capture-only;
+ easrc1_endpoint1: endpoint {
+ };
+ };
+
+ port@2 {
+ reg = <2>;
+ capture-only;
+ easrc1_endpoint2: endpoint {
+ };
+ };
+
+ port@3 {
+ reg = <3>;
+ capture-only;
+ easrc1_endpoint3: endpoint {
+ };
+ };
+ };
+ };
--
2.34.1
^ permalink raw reply related
* [PATCH 3/4] ASoC: fsl_asrc: expose individual DAIs per conversion pair
From: shengjiu.wang @ 2026-07-20 9:54 UTC (permalink / raw)
To: lgirdwood, broonie, robh, krzk+dt, conor+dt, Frank.Li, s.hauer,
kernel, festevam, shawnguo, linux-sound, devicetree, imx,
linux-arm-kernel, linux-kernel, shengjiu.wang, Xiubo.Lee,
nicoleotsuka, perex, tiwai, linuxppc-dev
Cc: Shengjiu Wang
In-Reply-To: <20260720095450.1618747-1-shengjiu.wang@oss.nxp.com>
From: Shengjiu Wang <shengjiu.wang@nxp.com>
The i.MX ASRC hardware supports three independent conversion pairs
(A, B, C). The driver previously registered a single DAI with generic
stream names "ASRC-Playback" and "ASRC-Capture", which prevents
individual pairs from being routed to separate audio paths simultaneously.
Replace the single fsl_asrc_dai instance with an array of three DAI
drivers, one per pair:
paira -- ASRC-Playback / ASRC-Capture (backward compatible)
pairb -- ASRCB-Playback / ASRCB-Capture
pairc -- ASRCC-Playback / ASRCC-Capture
Pair A retains the original generic stream names to preserve backward
compatibility with existing machine drivers and board configurations.
Each DAI retains the same channel, rate and format capabilities as the
original. Update the devm_snd_soc_register_component() call to register
all three DAIs.
Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
---
sound/soc/fsl/fsl_asrc.c | 89 +++++++++++++++++++++++++++++++---------
1 file changed, 69 insertions(+), 20 deletions(-)
diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c
index 0b28bcfa47fe..f83d6cdc6412 100644
--- a/sound/soc/fsl/fsl_asrc.c
+++ b/sound/soc/fsl/fsl_asrc.c
@@ -803,27 +803,76 @@ static const struct snd_soc_dai_ops fsl_asrc_dai_ops = {
SNDRV_PCM_FMTBIT_S16_LE | \
SNDRV_PCM_FMTBIT_S24_3LE)
-static struct snd_soc_dai_driver fsl_asrc_dai = {
- .playback = {
- .stream_name = "ASRC-Playback",
- .channels_min = 1,
- .channels_max = 10,
- .rate_min = 5512,
- .rate_max = 192000,
- .rates = SNDRV_PCM_RATE_KNOT,
- .formats = FSL_ASRC_FORMATS |
- SNDRV_PCM_FMTBIT_S8,
+static struct snd_soc_dai_driver fsl_asrc_dai[] = {
+ {
+ .name = "paira",
+ .playback = {
+ .stream_name = "ASRC-Playback",
+ .channels_min = 1,
+ .channels_max = 10,
+ .rate_min = 5512,
+ .rate_max = 192000,
+ .rates = SNDRV_PCM_RATE_KNOT,
+ .formats = FSL_ASRC_FORMATS |
+ SNDRV_PCM_FMTBIT_S8,
+ },
+ .capture = {
+ .stream_name = "ASRC-Capture",
+ .channels_min = 1,
+ .channels_max = 10,
+ .rate_min = 5512,
+ .rate_max = 192000,
+ .rates = SNDRV_PCM_RATE_KNOT,
+ .formats = FSL_ASRC_FORMATS,
+ },
+ .ops = &fsl_asrc_dai_ops,
+ },
+ {
+ .name = "pairb",
+ .playback = {
+ .stream_name = "ASRCB-Playback",
+ .channels_min = 1,
+ .channels_max = 10,
+ .rate_min = 5512,
+ .rate_max = 192000,
+ .rates = SNDRV_PCM_RATE_KNOT,
+ .formats = FSL_ASRC_FORMATS |
+ SNDRV_PCM_FMTBIT_S8,
+ },
+ .capture = {
+ .stream_name = "ASRCB-Capture",
+ .channels_min = 1,
+ .channels_max = 10,
+ .rate_min = 5512,
+ .rate_max = 192000,
+ .rates = SNDRV_PCM_RATE_KNOT,
+ .formats = FSL_ASRC_FORMATS,
+ },
+ .ops = &fsl_asrc_dai_ops,
},
- .capture = {
- .stream_name = "ASRC-Capture",
- .channels_min = 1,
- .channels_max = 10,
- .rate_min = 5512,
- .rate_max = 192000,
- .rates = SNDRV_PCM_RATE_KNOT,
- .formats = FSL_ASRC_FORMATS,
+ {
+ .name = "pairc",
+ .playback = {
+ .stream_name = "ASRCC-Playback",
+ .channels_min = 1,
+ .channels_max = 10,
+ .rate_min = 5512,
+ .rate_max = 192000,
+ .rates = SNDRV_PCM_RATE_KNOT,
+ .formats = FSL_ASRC_FORMATS |
+ SNDRV_PCM_FMTBIT_S8,
+ },
+ .capture = {
+ .stream_name = "ASRCC-Capture",
+ .channels_min = 1,
+ .channels_max = 10,
+ .rate_min = 5512,
+ .rate_max = 192000,
+ .rates = SNDRV_PCM_RATE_KNOT,
+ .formats = FSL_ASRC_FORMATS,
+ },
+ .ops = &fsl_asrc_dai_ops,
},
- .ops = &fsl_asrc_dai_ops,
};
static bool fsl_asrc_readable_reg(struct device *dev, unsigned int reg)
@@ -1404,7 +1453,7 @@ static int fsl_asrc_probe(struct platform_device *pdev)
goto err_pm_get_sync;
ret = devm_snd_soc_register_component(&pdev->dev, &fsl_asrc_component,
- &fsl_asrc_dai, 1);
+ fsl_asrc_dai, ARRAY_SIZE(fsl_asrc_dai));
if (ret) {
dev_err(&pdev->dev, "failed to register ASoC DAI\n");
goto err_pm_get_sync;
--
2.34.1
^ permalink raw reply related
* [PATCH 4/4] ASoC: fsl_easrc: expose individual DAIs per conversion context
From: shengjiu.wang @ 2026-07-20 9:54 UTC (permalink / raw)
To: lgirdwood, broonie, robh, krzk+dt, conor+dt, Frank.Li, s.hauer,
kernel, festevam, shawnguo, linux-sound, devicetree, imx,
linux-arm-kernel, linux-kernel, shengjiu.wang, Xiubo.Lee,
nicoleotsuka, perex, tiwai, linuxppc-dev
Cc: Shengjiu Wang
In-Reply-To: <20260720095450.1618747-1-shengjiu.wang@oss.nxp.com>
From: Shengjiu Wang <shengjiu.wang@nxp.com>
The i.MX EASRC hardware supports four independent conversion contexts
(A, B, C, D). The driver previously registered a single DAI with generic
stream names "ASRC-Playback" and "ASRC-Capture", which prevents
individual contexts from being routed to separate audio paths
simultaneously.
Replace the single fsl_easrc_dai instance with an array of four DAI
drivers, one per context:
ctxa -- ASRC-Playback / ASRC-Capture (backward compatible)
ctxb -- ASRCB-Playback / ASRCB-Capture
ctxc -- ASRCC-Playback / ASRCC-Capture
ctxd -- ASRCD-Playback / ASRCD-Capture
Context A retains the original generic stream names to preserve backward
compatibility with existing machine drivers and board configurations.
Each DAI retains the same channel, rate and format capabilities as the
original, including IEC958 subframe support on the capture side. Update
the devm_snd_soc_register_component() call to register all four DAIs.
Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
---
sound/soc/fsl/fsl_easrc.c | 112 +++++++++++++++++++++++++++++++-------
1 file changed, 92 insertions(+), 20 deletions(-)
diff --git a/sound/soc/fsl/fsl_easrc.c b/sound/soc/fsl/fsl_easrc.c
index edfd943197a0..3c5303d9b9cf 100644
--- a/sound/soc/fsl/fsl_easrc.c
+++ b/sound/soc/fsl/fsl_easrc.c
@@ -1600,27 +1600,99 @@ static const struct snd_soc_dai_ops fsl_easrc_dai_ops = {
.hw_free = fsl_easrc_hw_free,
};
-static struct snd_soc_dai_driver fsl_easrc_dai = {
- .playback = {
- .stream_name = "ASRC-Playback",
- .channels_min = 1,
- .channels_max = 32,
- .rate_min = 8000,
- .rate_max = 768000,
- .rates = SNDRV_PCM_RATE_KNOT,
- .formats = FSL_EASRC_FORMATS,
+static struct snd_soc_dai_driver fsl_easrc_dai[] = {
+ {
+ .name = "ctxa",
+ .playback = {
+ .stream_name = "ASRC-Playback",
+ .channels_min = 1,
+ .channels_max = 32,
+ .rate_min = 8000,
+ .rate_max = 768000,
+ .rates = SNDRV_PCM_RATE_KNOT,
+ .formats = FSL_EASRC_FORMATS,
+ },
+ .capture = {
+ .stream_name = "ASRC-Capture",
+ .channels_min = 1,
+ .channels_max = 32,
+ .rate_min = 8000,
+ .rate_max = 768000,
+ .rates = SNDRV_PCM_RATE_KNOT,
+ .formats = FSL_EASRC_FORMATS |
+ SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE,
+ },
+ .ops = &fsl_easrc_dai_ops,
},
- .capture = {
- .stream_name = "ASRC-Capture",
- .channels_min = 1,
- .channels_max = 32,
- .rate_min = 8000,
- .rate_max = 768000,
- .rates = SNDRV_PCM_RATE_KNOT,
- .formats = FSL_EASRC_FORMATS |
- SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE,
+ {
+ .name = "ctxb",
+ .playback = {
+ .stream_name = "ASRCB-Playback",
+ .channels_min = 1,
+ .channels_max = 32,
+ .rate_min = 8000,
+ .rate_max = 768000,
+ .rates = SNDRV_PCM_RATE_KNOT,
+ .formats = FSL_EASRC_FORMATS,
+ },
+ .capture = {
+ .stream_name = "ASRCB-Capture",
+ .channels_min = 1,
+ .channels_max = 32,
+ .rate_min = 8000,
+ .rate_max = 768000,
+ .rates = SNDRV_PCM_RATE_KNOT,
+ .formats = FSL_EASRC_FORMATS |
+ SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE,
+ },
+ .ops = &fsl_easrc_dai_ops,
+ },
+ {
+ .name = "ctxc",
+ .playback = {
+ .stream_name = "ASRCC-Playback",
+ .channels_min = 1,
+ .channels_max = 32,
+ .rate_min = 8000,
+ .rate_max = 768000,
+ .rates = SNDRV_PCM_RATE_KNOT,
+ .formats = FSL_EASRC_FORMATS,
+ },
+ .capture = {
+ .stream_name = "ASRCC-Capture",
+ .channels_min = 1,
+ .channels_max = 32,
+ .rate_min = 8000,
+ .rate_max = 768000,
+ .rates = SNDRV_PCM_RATE_KNOT,
+ .formats = FSL_EASRC_FORMATS |
+ SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE,
+ },
+ .ops = &fsl_easrc_dai_ops,
+ },
+ {
+ .name = "ctxd",
+ .playback = {
+ .stream_name = "ASRCD-Playback",
+ .channels_min = 1,
+ .channels_max = 32,
+ .rate_min = 8000,
+ .rate_max = 768000,
+ .rates = SNDRV_PCM_RATE_KNOT,
+ .formats = FSL_EASRC_FORMATS,
+ },
+ .capture = {
+ .stream_name = "ASRCD-Capture",
+ .channels_min = 1,
+ .channels_max = 32,
+ .rate_min = 8000,
+ .rate_max = 768000,
+ .rates = SNDRV_PCM_RATE_KNOT,
+ .formats = FSL_EASRC_FORMATS |
+ SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE,
+ },
+ .ops = &fsl_easrc_dai_ops,
},
- .ops = &fsl_easrc_dai_ops,
};
static const struct snd_soc_component_driver fsl_easrc_component = {
@@ -2245,7 +2317,7 @@ static int fsl_easrc_probe(struct platform_device *pdev)
regcache_cache_only(easrc->regmap, true);
ret = devm_snd_soc_register_component(dev, &fsl_easrc_component,
- &fsl_easrc_dai, 1);
+ fsl_easrc_dai, ARRAY_SIZE(fsl_easrc_dai));
if (ret) {
dev_err(dev, "failed to register ASoC DAI\n");
goto err_pm_disable;
--
2.34.1
^ permalink raw reply related
* [PATCH 0/7] soc: Remove redundant error messages on IRQ request failure
From: Pan Chuang @ 2026-07-20 9:59 UTC (permalink / raw)
To: Roy Pledge, Christophe Leroy (CS GROUP), Linus Walleij,
Imre Kaloz, Matthias Brugger, AngeloGioacchino Del Regno,
Bjorn Andersson, Konrad Dybcio, Thierry Reding, Jonathan Hunter,
Nishanth Menon, Santosh Shilimkar, Michal Simek, Shashank Balaji,
Gary Guo, Sumit Gupta, Rahul Bukte, Bruno Sobreira França,
Pan Chuang, Prasanna Kumar T S M, Marco Crivellari,
Jay Buddhabhatti, open list:DPAA2 DATAPATH I/O (DPIO) DRIVER,
open list:FREESCALE SOC DRIVERS,
moderated list:FREESCALE SOC DRIVERS,
moderated list:ARM/Mediatek SoC support,
open list:ARM/QUALCOMM MAILING LIST,
open list:TEGRA ARCHITECTURE SUPPORT
Commit 55b48e23f5c4 ("genirq/devres: Add error handling in
devm_request_*_irq()") added automatic error logging to
devm_request_threaded_irq() and devm_request_any_context_irq()
via the new devm_request_result() helper, which prints device
name, IRQ number, handler functions, and error code on failure.
Since devm_request_irq() is a static inline wrapper around
devm_request_threaded_irq(), it also benefits from this
automatic logging.
Remove the now-redundant dev_err() and dev_err_probe() calls
in soc drivers that follow these devm_request_*_irq()
functions, as the core now provides more detailed diagnostic
information on failure.
Pan Chuang (7):
soc: fsl: dpio: Remove redundant dev_err()
soc: ixp4xx: Remove redundant dev_err()
soc: mediatek: mtk-svs: Remove redundant dev_err_probe()
soc: qcom: Remove redundant dev_err()
soc/tegra: cbb: Remove redundant dev_err()
soc: ti: wkup_m3_ipc: Remove redundant dev_err()
soc: xilinx: Remove redundant dev_err()
drivers/soc/fsl/dpio/dpio-driver.c | 6 +-----
drivers/soc/ixp4xx/ixp4xx-qmgr.c | 10 ++--------
drivers/soc/mediatek/mtk-svs.c | 4 +---
drivers/soc/qcom/qcom_aoss.c | 4 +---
drivers/soc/qcom/smp2p.c | 4 +---
drivers/soc/qcom/smsm.c | 4 +---
drivers/soc/tegra/cbb/tegra194-cbb.c | 9 ++-------
drivers/soc/ti/wkup_m3_ipc.c | 4 +---
drivers/soc/xilinx/zynqmp_power.c | 5 +----
9 files changed, 11 insertions(+), 39 deletions(-)
--
2.34.1
^ permalink raw reply
* [PATCH 1/7] soc: fsl: dpio: Remove redundant dev_err()
From: Pan Chuang @ 2026-07-20 9:59 UTC (permalink / raw)
To: Roy Pledge, Christophe Leroy (CS GROUP),
open list:DPAA2 DATAPATH I/O (DPIO) DRIVER,
open list:FREESCALE SOC DRIVERS,
moderated list:FREESCALE SOC DRIVERS
Cc: Pan Chuang
In-Reply-To: <20260720095920.542801-1-panchuang@vivo.com>
Since commit 55b48e23f5c4 ("genirq/devres: Add error handling in
devm_request_*_irq()"), devm_request_irq() automatically logs
detailed error messages on failure. Remove the now-redundant
driver-specific dev_err() calls.
Signed-off-by: Pan Chuang <panchuang@vivo.com>
---
drivers/soc/fsl/dpio/dpio-driver.c | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)
diff --git a/drivers/soc/fsl/dpio/dpio-driver.c b/drivers/soc/fsl/dpio/dpio-driver.c
index 9e3fddd8f5a9..d5198ffc4455 100644
--- a/drivers/soc/fsl/dpio/dpio-driver.c
+++ b/drivers/soc/fsl/dpio/dpio-driver.c
@@ -102,12 +102,8 @@ static int register_dpio_irq_handlers(struct fsl_mc_device *dpio_dev, int cpu)
0,
dev_name(&dpio_dev->dev),
&dpio_dev->dev);
- if (error < 0) {
- dev_err(&dpio_dev->dev,
- "devm_request_irq() failed: %d\n",
- error);
+ if (error < 0)
return error;
- }
/* set the affinity hint */
if (irq_set_affinity_hint(irq->virq, cpumask_of(cpu)))
--
2.34.1
^ permalink raw reply related
* [PATCH v3 net-next 1/6] ibmvnic: Move long delayed work on system_dfl_long_wq
From: Marco Crivellari @ 2026-07-20 10:08 UTC (permalink / raw)
To: linux-kernel, netdev
Cc: Tejun Heo, Lai Jiangshan, Frederic Weisbecker,
Sebastian Andrzej Siewior, Marco Crivellari, Michal Hocko,
Andrew Lunn, David S . Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Haren Myneni, Rick Lindsley, Nick Child,
Madhavan Srinivasan, Michael Ellerman, Nicholas Piggin,
Christophe Leroy (CS GROUP), linuxppc-dev
In-Reply-To: <20260720100902.155605-1-marco.crivellari@suse.com>
Currently the code enqueue work items using {queue|mod}_delayed_work(),
using system_long_wq. This workqueue should be used when long works are
expected and it is a per-cpu workqueue.
The function(s) end up calling __queue_delayed_work(), which set a global
timer that could fire anywhere, enqueuing the work where the timer fired.
Unbound works could benefit from scheduler task placement, to optimize
performance and power consumption. Long work shouldn't stick to a single
CPU.
Recently, a new unbound workqueue specific for long running work has
been added:
c116737e972e ("workqueue: Add system_dfl_long_wq for long unbound works")
Since the workqueue work doesn't rely on per-cpu variables, there is no
obvious reason that justify the use of a per-cpu workqueue. So change
system_long_wq with system_dfl_long_wq so that the work may benefit from
scheduler task placement.
Cc: Haren Myneni <haren@linux.ibm.com>
Cc: Rick Lindsley <ricklind@linux.ibm.com>
Cc: Nick Child <nnac123@linux.ibm.com>
Cc: Madhavan Srinivasan <maddy@linux.ibm.com>
Cc: Michael Ellerman <mpe@ellerman.id.au>
Cc: Nicholas Piggin <npiggin@gmail.com>
Cc: Christophe Leroy (CS GROUP) <chleroy@kernel.org>
Cc: linuxppc-dev@lists.ozlabs.org
Signed-off-by: Marco Crivellari <marco.crivellari@suse.com>
---
drivers/net/ethernet/ibm/ibmvnic.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c
index 5a510eed335e..d4c284c8ef43 100644
--- a/drivers/net/ethernet/ibm/ibmvnic.c
+++ b/drivers/net/ethernet/ibm/ibmvnic.c
@@ -3229,7 +3229,7 @@ static void __ibmvnic_reset(struct work_struct *work)
if (adapter->state == VNIC_PROBING &&
!wait_for_completion_timeout(&adapter->probe_done, timeout)) {
dev_err(dev, "Reset thread timed out on probe");
- queue_delayed_work(system_long_wq,
+ queue_delayed_work(system_dfl_long_wq,
&adapter->ibmvnic_delayed_reset,
IBMVNIC_RESET_DELAY);
return;
@@ -3267,7 +3267,7 @@ static void __ibmvnic_reset(struct work_struct *work)
spin_lock(&adapter->rwi_lock);
if (!list_empty(&adapter->rwi_list)) {
if (test_and_set_bit_lock(0, &adapter->resetting)) {
- queue_delayed_work(system_long_wq,
+ queue_delayed_work(system_dfl_long_wq,
&adapter->ibmvnic_delayed_reset,
IBMVNIC_RESET_DELAY);
} else {
@@ -3454,7 +3454,7 @@ static int ibmvnic_reset(struct ibmvnic_adapter *adapter,
list_add_tail(&rwi->list, &adapter->rwi_list);
netdev_dbg(adapter->netdev, "Scheduling reset (reason %s)\n",
reset_reason_to_string(reason));
- queue_work(system_long_wq, &adapter->ibmvnic_reset);
+ queue_work(system_dfl_long_wq, &adapter->ibmvnic_reset);
ret = 0;
err:
--
2.54.0
^ permalink raw reply related
* Re: [PATCH] powerpc/irq: Fix missing r2 clobber in PCREL inline assembly
From: Segher Boessenkool @ 2026-07-20 10:25 UTC (permalink / raw)
To: Saket Kumar Bhaskar
Cc: linux-kernel, linuxppc-dev, maddy, mpe, npiggin, chleroy,
hbathini, venkat88, yeswanth
In-Reply-To: <dc021f42afa10396052499cbeda1772e30b7ca64.1784530547.git.skb99@linux.ibm.com>
Hi!
On Mon, Jul 20, 2026 at 12:43:47PM +0530, Saket Kumar Bhaskar wrote:
> In CONFIG_PPC_KERNEL_PCREL mode, r2 is no longer reserved for the TOC
> pointer and is available as a caller-saved register [0].
Just like on many more ABIs. Yeah. It's the first that PowerPC Linux
supports though :-)
> Both call_do_irq() and call_do_softirq() use inline assembly to call
> functions with stack switching, but fail to list r2 in their clobber
> lists. This causes the compiler to assume r2 is preserved across these
> calls, leading to register corruption when the called functions
> (__do_irq and __do_softirq) clobber r2.
Yeah.
> index a0e8b998c9b5..26df38bdd334 100644
> --- a/arch/powerpc/kernel/irq.c
> +++ b/arch/powerpc/kernel/irq.c
> @@ -218,7 +218,12 @@ static __always_inline void call_do_softirq(const void *sp)
> [callee] "i" (__do_softirq)
> : // Clobbers
> "lr", "xer", "ctr", "memory", "cr0", "cr1", "cr5", "cr6",
> - "cr7", "r0", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10",
> + "cr7", "r0",
> + /* r2 is clobbered in PCREL mode */
"Note that r2 may be clobbered in the call, when using the ELF V2 ABI"?
PCREL has nothing to do with it. Well, not directly :-) And the
clobber list does not specify registers that definitely *are* clobbered,
but registers that *may be* clobbered, instead :-) Registers that *are*
clobbered are in the output list (and given a name there so that the new
value can be accessed, etc.)
> +#ifdef CONFIG_PPC_KERNEL_PCREL
> + "r2",
> +#endif
> + "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10",
> "r11", "r12"
> );
> }
> @@ -276,7 +281,12 @@ static __always_inline void call_do_irq(struct pt_regs *regs, void *sp)
> [callee] "i" (__do_irq)
> : // Clobbers
> "lr", "xer", "ctr", "memory", "cr0", "cr1", "cr5", "cr6",
> - "cr7", "r0", "r4", "r5", "r6", "r7", "r8", "r9", "r10",
> + "cr7", "r0",
> + /* r2 is clobbered in PCREL mode */
> +#ifdef CONFIG_PPC_KERNEL_PCREL
> + "r2",
> +#endif
> + "r4", "r5", "r6", "r7", "r8", "r9", "r10",
> "r11", "r12"
> );
> }
Segher
^ permalink raw reply
* Re: [PATCH 2/3] sched: Convert paravirt_steal to new static key APIs
From: Jürgen Groß @ 2026-07-20 10:35 UTC (permalink / raw)
To: Hongyan Xia, mingo@redhat.com, peterz@infradead.org,
juri.lelli@redhat.com, vincent.guittot@linaro.org,
dietmar.eggemann@arm.com, rostedt@goodmis.org, bsegall@google.com,
mgorman@suse.de, vschneid@redhat.com, kprateek.nayak@amd.com,
Ajay Kaher, Alexey Makhalov, Broadcom internal kernel review list,
Catalin Marinas, Will Deacon, Huacai Chen, WANG Xuerui,
Madhavan Srinivasan, Michael Ellerman, Nicholas Piggin,
Christophe Leroy (CS GROUP), Paul Walmsley, Palmer Dabbelt,
Albert Ou, Alexandre Ghiti, Thomas Gleixner, Borislav Petkov,
Dave Hansen, x86@kernel.org, H. Peter Anvin, Paolo Bonzini,
Vitaly Kuznetsov, Stefano Stabellini, Oleksandr Tyshchenko
Cc: Jiazi Li, linux-kernel@vger.kernel.org,
virtualization@lists.linux.dev,
linux-arm-kernel@lists.infradead.org, loongarch@lists.linux.dev,
linuxppc-dev@lists.ozlabs.org, linux-riscv@lists.infradead.org,
kvm@vger.kernel.org, xen-devel@lists.xenproject.org
In-Reply-To: <773bbd8fcd5ef2ebfe1c64303c7a71a56368de69.1784538478.git.hongyan.xia@transsion.com>
[-- Attachment #1.1.1: Type: text/plain, Size: 375 bytes --]
On 20.07.26 11:38, Hongyan Xia wrote:
> From: Hongyan Xia <hongyan.xia@transsion.com>
>
> paravirt_steal_rq_enabled and paravirt_steal_enabled use raw static_key
> APIs which are now deprecated. Use the new API instead.
>
> No functional change.
>
> Signed-off-by: Hongyan Xia <hongyan.xia@transsion.com>
Acked-by: Juergen Gross <jgross@suse.com>
Juergen
[-- Attachment #1.1.2: OpenPGP public key --]
[-- Type: application/pgp-keys, Size: 3743 bytes --]
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 495 bytes --]
^ permalink raw reply
* [PATCH V2 1/6] powerpc/perf: Add HTM PMU driver to expose Hardware Trace Macro data
From: Athira Rajeev @ 2026-07-20 10:44 UTC (permalink / raw)
To: linuxppc-dev, maddy
Cc: linux-perf-users, atrajeev, hbathini, tejas05, venkat88, tshah,
usha.r2
In-Reply-To: <20260720104447.11843-1-atrajeev@linux.ibm.com>
The H_HTM hypervisor call (hcall) provides an interface to the Hardware
Trace Macro (HTM) function on POWER systems. HTM captures hardware-level
trace data for a specific node/chip/core target within a logical partition.
Add a new "htm" Performance Monitoring Unit (PMU) that exposes HTM control
via the standard perf interface. The event configuration is a 28-bit value
packed into the perf config field:
bits 0-3: htm_type (HTM_CORE=2, HTM_NEST=1)
bits 4-11: nodeindex
bits 12-19: nodalchipindex
bits 20-27: coreindexonchip
PMU lifecycle:
add/del: Issue H_HTM_OP_CONFIGURE / H_HTM_OP_DECONFIGURE to reserve
and release the hardware trace resource.
start/stop: Issue H_HTM_OP_START / H_HTM_OP_STOP to control tracing.
HTM traces at node/chip/core scope continuously for the
duration of the event. Context-switch-triggered start/stop
callbacks (PERF_EF_RELOAD / PERF_EF_UPDATE) are ignored to
keep tracing uninterrupted. Explicit ioctl(ENABLE/DISABLE)
and event deletion do control the hardware.
State tracking uses event->pmu_private (HTM_TRACING_ACTIVE/INACTIVE) as
the source of information, with event->hw.state kept in sync as
a hint for the perf core. This avoids conflicts with infrastructure
writes to event->hw.state.
The H_HTM hcall may return H_BUSY (transient, retried up to MAX_RETRIES)
or H_LONG_BUSY_* (long delay required, not retried to avoid deadlocks in
atomic contexts).
After this patch the PMU is visible under sysfs:
# ls /sys/bus/event_source/devices/ |grep htm
htm
# ls /sys/bus/event_source/devices/htm/
events format perf_event_mux_interval_ms power subsystem type uevent
Signed-off-by: Athira Rajeev <atrajeev@linux.ibm.com>
---
Changes in V2:
- Replaced direct H_HTM_OP_CONFIGURE/DECONFIGURE calls in htm_event_add()
and htm_event_del() with separate htm_event_init() and destroy paths.
State tracking is now via event->pmu_private (HTM_TRACING_ACTIVE /
HTM_TRACING_INACTIVE) as the authoritative source, with event->hw.state
kept in sync as a hint for the perf core, avoiding conflicts with
infrastructure writes to event->hw.state.
- Context-switch callbacks (PERF_EF_RELOAD / PERF_EF_UPDATE) are now
explicitly ignored in htm_event_start()/stop() to keep tracing
uninterrupted across task switches; previously these paths were absent.
- H_BUSY retry loop is capped at MAX_RETRIES; H_LONG_BUSY_* is not
retried in atomic context to avoid deadlocks (was unconditionally
retried in V1).
arch/powerpc/perf/Makefile | 2 +-
arch/powerpc/perf/htm-perf.c | 379 +++++++++++++++++++++++++++++++++++
2 files changed, 380 insertions(+), 1 deletion(-)
create mode 100644 arch/powerpc/perf/htm-perf.c
diff --git a/arch/powerpc/perf/Makefile b/arch/powerpc/perf/Makefile
index 78dd7e25219e..26ef30c0693c 100644
--- a/arch/powerpc/perf/Makefile
+++ b/arch/powerpc/perf/Makefile
@@ -14,7 +14,7 @@ obj-$(CONFIG_PPC_POWERNV) += imc-pmu.o
obj-$(CONFIG_FSL_EMB_PERF_EVENT) += core-fsl-emb.o
obj-$(CONFIG_FSL_EMB_PERF_EVENT_E500) += e500-pmu.o e6500-pmu.o
-obj-$(CONFIG_HV_PERF_CTRS) += hv-24x7.o hv-gpci.o hv-common.o vpa-dtl.o
+obj-$(CONFIG_HV_PERF_CTRS) += hv-24x7.o hv-gpci.o hv-common.o vpa-dtl.o htm-perf.o
obj-$(CONFIG_VPA_PMU) += vpa-pmu.o
diff --git a/arch/powerpc/perf/htm-perf.c b/arch/powerpc/perf/htm-perf.c
new file mode 100644
index 000000000000..abecc9bb58dc
--- /dev/null
+++ b/arch/powerpc/perf/htm-perf.c
@@ -0,0 +1,379 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Perf interface to expose HTM Trace data.
+ *
+ * Copyright (C) 2026 Athira Rajeev, IBM Corporation
+ */
+
+#define pr_fmt(fmt) "htm: " fmt
+
+#include <asm/dtl.h>
+#include <linux/perf_event.h>
+#include <asm/plpar_wrappers.h>
+#include <asm/firmware.h>
+
+#define EVENT(_name, _code) enum{_name = _code}
+#define MAX_RETRIES 100
+
+EVENT(HTM_CORE, 0x2);
+EVENT(HTM_NEST, 0x1);
+
+GENERIC_EVENT_ATTR(htm_core, HTM_CORE);
+GENERIC_EVENT_ATTR(htm_nest, HTM_NEST);
+
+PMU_FORMAT_ATTR(event, "config:0-27");
+PMU_FORMAT_ATTR(htm_type, "config:0-3");
+PMU_FORMAT_ATTR(nodeindex, "config:4-11");
+PMU_FORMAT_ATTR(nodalchipindex, "config:12-19");
+PMU_FORMAT_ATTR(coreindexonchip, "config:20-27");
+
+static struct attribute *events_attr[] = {
+ GENERIC_EVENT_PTR(HTM_NEST),
+ GENERIC_EVENT_PTR(HTM_CORE),
+ NULL
+};
+
+static struct attribute_group event_group = {
+ .name = "events",
+ .attrs = events_attr,
+};
+
+static struct attribute *format_attrs[] = {
+ &format_attr_event.attr,
+ &format_attr_htm_type.attr,
+ &format_attr_nodeindex.attr,
+ &format_attr_nodalchipindex.attr,
+ &format_attr_coreindexonchip.attr,
+ NULL,
+};
+
+static const struct attribute_group format_group = {
+ .name = "format",
+ .attrs = format_attrs,
+};
+
+static const struct attribute_group *attr_groups[] = {
+ &format_group,
+ &event_group,
+ NULL,
+};
+
+static u64 htmflags = H_HTM_FLAGS_NOWRAP;
+
+struct htm_config {
+ u32 htmtype;
+ u32 nodeindex;
+ u32 nodalchipindex;
+ u32 coreindexonchip;
+};
+
+/*
+ * Per-event private state. Allocated in htm_event_init(), freed via the
+ * event->destroy callback (reset_htm_active()).
+ *
+ * cfg stores the HTM target identity parsed from event->attr.config.
+ * tracing_active tracks whether H_HTM_OP_START has been successfully issued
+ * for this event. It is the source of information used by
+ * htm_event_start() and htm_event_stop() to make hcall decisions.
+ * event->hw.state is kept in sync for the perf core only.
+ */
+struct htm_target_id {
+ struct htm_config cfg;
+ int tracing_active; /* HTM_TRACING_ACTIVE / HTM_TRACING_INACTIVE */
+};
+
+/* Helper to parse the 28-bit event config into distinct fields */
+static inline void parse_htm_config(u64 config, struct htm_config *cfg)
+{
+ cfg->htmtype = config & 0xf;
+ cfg->nodeindex = (config >> 4) & 0xff;
+ cfg->nodalchipindex = (config >> 12) & 0xff;
+ cfg->coreindexonchip = (config >> 20) & 0xff;
+}
+
+/*
+ * Check the return code for H_HTM hcall.
+ * Return 1 if either H_PARTIAL or H_SUCCESS is returned.
+ * Return 0 if H_NOT_AVAILABLE.
+ * Return exact negative error codes for expected issues.
+ */
+static ssize_t htm_return_check(int rc)
+{
+ switch (rc) {
+ case H_SUCCESS:
+ case H_PARTIAL:
+ return 1;
+ case H_NOT_AVAILABLE:
+ return 0;
+ case H_BUSY:
+ /* Transient busy: retry loop will spin up to MAX_RETRIES */
+ return -EBUSY;
+ case H_LONG_BUSY_ORDER_1_MSEC:
+ case H_LONG_BUSY_ORDER_10_MSEC:
+ case H_LONG_BUSY_ORDER_100_MSEC:
+ case H_LONG_BUSY_ORDER_1_SEC:
+ case H_LONG_BUSY_ORDER_10_SEC:
+ case H_LONG_BUSY_ORDER_100_SEC:
+ /*
+ * Hypervisor requests a long delay before retry (1ms-100s).
+ * Spinning in a kernel retry loop for this duration risks
+ * deadlocks in atomic contexts. Return -EAGAIN so callers
+ * exit immediately; the operation will fail and userspace
+ * can retry the perf_event_open() call.
+ * Note: all retry loops check ret == -EBUSY only, so
+ * -EAGAIN exits without retrying, this is intentional.
+ */
+ return -EAGAIN;
+ case H_PARAMETER:
+ case H_P2:
+ case H_P3:
+ case H_P4:
+ case H_P5:
+ case H_P6:
+ return -EINVAL;
+ case H_STATE:
+ return -EIO;
+ case H_AUTHORITY:
+ return -EPERM;
+ default:
+ /* Prevent silent fallthrough mapping of unhandled errors to 1 */
+ return -EIO;
+ }
+}
+
+/*
+ * HTM_TRACING_ACTIVE/INACTIVE: values for htm_target_id.tracing_active.
+ * Tracks whether H_HTM_OP_START has been successfully issued.
+ * HTM traces at node/chip/core scope, not per-task. Once started,
+ * context-switch-triggered stop/start (PERF_EF_UPDATE / PERF_EF_RELOAD)
+ * must not stop/restart the hardware. Only explicit API calls
+ * (ioctl DISABLE/ENABLE) and event_del should control the hcall.
+ */
+#define HTM_TRACING_ACTIVE 1
+#define HTM_TRACING_INACTIVE 0
+
+static void reset_htm_active(struct perf_event *event)
+{
+ kfree(event->pmu_private);
+ event->pmu_private = NULL;
+}
+
+static int htm_event_init(struct perf_event *event)
+{
+ u64 config = event->attr.config;
+ struct htm_config cfg;
+
+ if (event->attr.inherit)
+ return -EOPNOTSUPP;
+
+ if (event->attr.type != event->pmu->type)
+ return -ENOENT;
+
+ if (!perfmon_capable())
+ return -EACCES;
+
+ if (!is_sampling_event(event))
+ return -EOPNOTSUPP;
+
+ if (has_branch_stack(event))
+ return -EOPNOTSUPP;
+
+ parse_htm_config(config, &cfg);
+ switch (cfg.htmtype) {
+ case HTM_CORE:
+ case HTM_NEST:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* Allocate per-event private state; freed via event->destroy */
+ event->pmu_private = kzalloc(sizeof(struct htm_target_id), GFP_KERNEL);
+ if (!event->pmu_private)
+ return -ENOMEM;
+
+ ((struct htm_target_id *)event->pmu_private)->cfg = cfg;
+ event->destroy = reset_htm_active;
+ return 0;
+}
+
+static void htm_event_start(struct perf_event *event, int flags)
+{
+ int rc, ret, retries = 0;
+ struct htm_config cfg;
+ struct htm_target_id *target = event->pmu_private;
+
+ /*
+ * Ignore context-switch re-enables. The perf core passes
+ * PERF_EF_RELOAD on context-switch-in. HTM tracing is
+ * continuous at hardware level, no hcall needed.
+ */
+ if (flags & PERF_EF_RELOAD)
+ return;
+
+ /* Already tracing, don't issue a second start hcall */
+ if (target->tracing_active == HTM_TRACING_ACTIVE)
+ return;
+
+ cfg = target->cfg;
+
+ /* Only retry on transient H_BUSY; H_LONG_BUSY_* (-EAGAIN) exits immediately */
+ do {
+ rc = htm_hcall_wrapper(htmflags, cfg.nodeindex, cfg.nodalchipindex,
+ cfg.coreindexonchip, cfg.htmtype,
+ H_HTM_OP_START, 0, 0, 0);
+ ret = htm_return_check(rc);
+ } while (ret == -EBUSY && ++retries < MAX_RETRIES);
+
+ if (ret > 0) {
+ target->tracing_active = HTM_TRACING_ACTIVE;
+ event->hw.state &= ~PERF_HES_STOPPED;
+ }
+}
+
+static void htm_event_stop(struct perf_event *event, int flags)
+{
+ int rc, ret, retries = 0;
+ struct htm_config cfg;
+ struct htm_target_id *target = event->pmu_private;
+
+ /*
+ * Ignore context-switch-out stops. The perf core passes
+ * PERF_EF_UPDATE on context-switch-out. Do not stop the hcall.
+ */
+ if (flags & PERF_EF_UPDATE)
+ return;
+
+ /* Not tracing, nothing to stop */
+ if (target->tracing_active == HTM_TRACING_INACTIVE)
+ return;
+
+ cfg = target->cfg;
+
+ /* Only retry on transient H_BUSY; H_LONG_BUSY_* (-EAGAIN) exits immediately */
+ do {
+ rc = htm_hcall_wrapper(htmflags, cfg.nodeindex, cfg.nodalchipindex,
+ cfg.coreindexonchip, cfg.htmtype,
+ H_HTM_OP_STOP, 0, 0, 0);
+ ret = htm_return_check(rc);
+ } while (ret == -EBUSY && ++retries < MAX_RETRIES);
+
+ /*
+ * Only mark stopped if the hcall succeeded. If the stop failed
+ * (e.g. -EAGAIN on long-busy), leave tracing_active as ACTIVE so
+ * that htm_event_del will retry the stop hcall rather than
+ * skipping it and leaving the hypervisor permanently configured.
+ */
+ if (ret > 0) {
+ target->tracing_active = HTM_TRACING_INACTIVE;
+ event->hw.state |= PERF_HES_STOPPED;
+ }
+}
+
+static int htm_event_add(struct perf_event *event, int flags)
+{
+ int rc, ret, retries = 0;
+ unsigned long param1 = -1, param2 = -1;
+ struct htm_target_id *target = event->pmu_private;
+ struct htm_config cfg = target->cfg;
+
+ /* Configure the hardware, only retry on transient H_BUSY */
+ do {
+ rc = htm_hcall_wrapper(htmflags, cfg.nodeindex, cfg.nodalchipindex,
+ cfg.coreindexonchip, cfg.htmtype,
+ H_HTM_OP_CONFIGURE, param1, param2, 0);
+ ret = htm_return_check(rc);
+ } while (ret == -EBUSY && ++retries < MAX_RETRIES);
+
+ if (ret <= 0)
+ return (ret == 0) ? -ENODEV : ret;
+
+ /*
+ * htm_event_init() allocated event->pmu_private (struct htm_target_id)
+ * and set event->destroy = reset_htm_active to free it on teardown.
+ * Initialise the tracing state and hw.state before calling start.
+ */
+ target->tracing_active = HTM_TRACING_INACTIVE;
+ event->hw.state = PERF_HES_STOPPED;
+
+ /*
+ * Start tracing via the .start callback so the standard
+ * PERF_EF_START / ioctl(ENABLE) path is honoured.
+ */
+ if (flags & PERF_EF_START) {
+ htm_event_start(event, 0); /* flags=0: not a context switch */
+ if (target->tracing_active == HTM_TRACING_INACTIVE) {
+ /* Start failed, deconfigure to avoid resource leak */
+ retries = 0;
+ do {
+ rc = htm_hcall_wrapper(htmflags, cfg.nodeindex,
+ cfg.nodalchipindex, cfg.coreindexonchip,
+ cfg.htmtype, H_HTM_OP_DECONFIGURE, 0, 0, 0);
+ ret = htm_return_check(rc);
+ } while (ret == -EBUSY && ++retries < MAX_RETRIES);
+ return -EIO;
+ }
+ }
+
+ return 0;
+}
+
+static void htm_event_del(struct perf_event *event, int flags)
+{
+ int rc, ret, retries = 0;
+ struct htm_target_id *target = event->pmu_private;
+ struct htm_config cfg = target->cfg;
+
+ /* Stop tracing, flags=0 so htm_event_stop issues the hcall */
+ htm_event_stop(event, 0);
+
+ /* Deconfigure */
+ do {
+ rc = htm_hcall_wrapper(htmflags, cfg.nodeindex, cfg.nodalchipindex,
+ cfg.coreindexonchip, cfg.htmtype,
+ H_HTM_OP_DECONFIGURE, 0, 0, 0);
+ ret = htm_return_check(rc);
+ } while (ret == -EBUSY && ++retries < MAX_RETRIES);
+
+ /* pmu_private freed by event->destroy = reset_htm_active */
+}
+
+static void htm_event_read(struct perf_event *event)
+{
+}
+
+static struct pmu htm_pmu = {
+ .task_ctx_nr = perf_invalid_context,
+ .name = "htm",
+ .attr_groups = attr_groups,
+ .event_init = htm_event_init,
+ .add = htm_event_add,
+ .del = htm_event_del,
+ .read = htm_event_read,
+ .start = htm_event_start,
+ .stop = htm_event_stop,
+ .capabilities = PERF_PMU_CAP_NO_EXCLUDE | PERF_PMU_CAP_EXCLUSIVE,
+};
+
+static int htm_init(void)
+{
+ int r;
+
+ if (!firmware_has_feature(FW_FEATURE_LPAR)) {
+ pr_debug("Only supported on LPAR platforms running under a Hypervisor\n");
+ return -ENODEV;
+ }
+
+ if (is_kvm_guest()) {
+ pr_debug("Only supported for L1 host system\n");
+ return -ENODEV;
+ }
+
+ r = perf_pmu_register(&htm_pmu, htm_pmu.name, -1);
+ if (r)
+ return r;
+
+ return 0;
+}
+
+device_initcall(htm_init);
--
2.43.0
^ permalink raw reply related
* [PATCH V2 0/6] powerpc/perf: Add HTM PMU driver and perf AUX support
From: Athira Rajeev @ 2026-07-20 10:44 UTC (permalink / raw)
To: linuxppc-dev, maddy
Cc: linux-perf-users, atrajeev, hbathini, tejas05, venkat88, tshah,
usha.r2
Overview:
The Hardware Trace Macro (HTM) on POWER systems provides hardware-level
bus-trace data for a specific node/chip/core target within a logical
partition. It is accessed via the H_HTM hypervisor call and traces
continuously at node, chip, or core scope independent of task scheduling.
This series adds a new "htm" PMU driver under arch/powerpc/perf/ that
exposes HTM trace collection via the standard perf interface using the
perf AUX buffer infrastructure, together with ABI and RST documentation.
Patch overview:
Patch 1 introduces the core HTM PMU driver (htm-perf.c). The event
configuration encodes the trace target as a 28-bit value in
perf_event_attr.config:
bits 0-3: htm_type (HTM_CORE=2, HTM_NEST=1)
bits 4-11: nodeindex
bits 12-19: nodalchipindex
bits 20-27: coreindexonchip
The PMU lifecycle maps to H_HTM_OP_CONFIGURE/DECONFIGURE at add/del time
and H_HTM_OP_START/STOP at start/stop time. Context-switch callbacks
(PERF_EF_RELOAD / PERF_EF_UPDATE) are intentionally ignored because HTM
traces the hardware scope, not individual tasks. Tracing state is kept
in event->pmu_private (HTM_TRACING_ACTIVE / HTM_TRACING_INACTIVE) as the
authoritative source, with event->hw.state kept in sync as a hint for the
perf core.
Patch 2 adds duplicate-reservation protection. When 'perf record -a' is
used, perf opens system-wide events on all CPUs in parallel. Without
driver-side tracking, concurrent opens for the same HTM target (node,
chip, core, type) can race and issue duplicate H_HTM_OP_CONFIGURE flows.
A global reserved-targets list is added; htm_event_init() rejects any
open that matches an already-reserved tuple, while different targets can
still be opened simultaneously on different CPUs.
Patch 3 adds AUX ring-buffer support so that high-volume trace data can
be streamed into a perf AUX buffer. The driver opts into
PERF_PMU_CAP_AUX_NO_SG | PERF_PMU_CAP_AUX_PREFER_LARGE to request
physically contiguous allocations, which H_HTM_OP_DUMP_DATA requires.
A page-by-page physical-continuity scan is performed before each dump to
detect and bound any fragmentation gaps, preventing silent memory
corruption. event->count is set to 1 when data is present and 0 when
the stream is exhausted; the perf tool uses this as a drain signal to
decide whether another read pass is needed before closing the event.
Patch 4 adds system memory configuration capture. After writing trace
data to the AUX buffer, htm_event_read() calls H_HTM_OP_DUMP_SYSMEM_CONF
and emits the returned physical-to-logical address mapping records as
PERF_SAMPLE_RAW data. Keeping trace data in the AUX stream and memory
configuration in raw samples allows each to be decoded independently in
userspace.
Patch 5 adds ABI documentation for the sysfs entries under
/sys/bus/event_source/devices/htm/, covering the format attribute
(config bit layout) and the events attribute group.
Patch 6 extends Documentation/arch/powerpc/htm.rst with a new section
on the perf interface: event syntax, required options, the two output
files (htm.bin.nX.pX.cX and translation.nX.pX.cX), and how to pass
them to htmdecode for trace decoding.
Usage example:
Collect HTM trace data from two simultaneous chip targets:
# perf record -m,256 \
-e htm/nodalchipindex=2,nodeindex=0,htm_type=1,cpu=8/ \
-e htm/nodalchipindex=1,nodeindex=0,htm_type=1,cpu=9/ \
-a -- sleep 10
# perf report
Output files written by perf report:
htm.bin.n0.p2.c0 raw HTM bus-trace, chip 2
htm.bin.n0.p1.c0 raw HTM bus-trace, chip 1
translation.n0.p2.c0 memory config records, chip 2
translation.n0.p1.c0 memory config records, chip 1
The htm.bin.* files can then be decoded with htmdecoder to produce
trace output.
Testing:
Tested on POWER10 with two simultaneous HTM targets. Both htm.bin.*
and translation.* files are produced correctly.
# perf record -C 9 -m,256 \
-e htm/nodalchipindex=2,nodeindex=0,htm_type=1/ sleep 3
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 256.277 MB perf.data ]
Athira Rajeev (6):
powerpc/perf: Add HTM PMU driver to expose Hardware Trace Macro data
powerpc/perf: Reject duplicate HTM target reservations
powerpc/perf: Add AUX buffer management to capture HTM trace data
powerpc/perf: Capture the HTM memory configuration as part of perf
data
docs: ABI: sysfs-bus-event_source-devices-htm: Document sysfs event
format entries for htm pmu
powerpc/perf/htm: Add documentation for Hardware Trace Macro PMU
.../sysfs-bus-event_source-devices-htm | 21 +
Documentation/arch/powerpc/htm.rst | 137 +++-
arch/powerpc/perf/Makefile | 2 +-
arch/powerpc/perf/htm-perf.c | 749 ++++++++++++++++++
4 files changed, 905 insertions(+), 4 deletions(-)
create mode 100644 Documentation/ABI/testing/sysfs-bus-event_source-devices-htm
create mode 100644 arch/powerpc/perf/htm-perf.c
--
2.43.0
^ permalink raw reply
* [PATCH V2 2/6] powerpc/perf: Reject duplicate HTM target reservations
From: Athira Rajeev @ 2026-07-20 10:44 UTC (permalink / raw)
To: linuxppc-dev, maddy
Cc: linux-perf-users, atrajeev, hbathini, tejas05, venkat88, tshah,
usha.r2
In-Reply-To: <20260720104447.11843-1-atrajeev@linux.ibm.com>
HTM tracing is controlled through hypervisor calls and operates on a
system-scoped target identified by HTM type, node index, chip index,
and core index. When userspace opens a system-wide event such as via
'perf record -a', perf may initialize matching events on multiple CPUs
in parallel.
Without driver-side target tracking, concurrent event initialization for
the same HTM target can race and issue duplicate configure/start flows
for an identical tracing scope. This can lead to conflicts in the
underlying H_HTM operations.
Track reserved HTM targets globally and reject duplicate reservations
for the same target. The reservation is created during
htm_event_init() and released through the event destroy path. This
prevents concurrent duplicate opens while still allowing different HTM
targets to be used simultaneously on different CPUs.
Extend the existing per-event htm_target_id structure with a list node,
and use the stored htm_config in pmu_private for target comparison.
A cpumask-based approach was considered but not used: cpumask restricts
which CPUs an event may be opened on, but HTM operates on a hardware
target (node/chip/core) that is independent of the CPU opening the
event. A user may open an HTM event for a specific node/chip/core target
from any CPU in the system, not just CPUs that belong to that node. A
cpumask would therefore either over-restrict valid opens or require a
per-target mask that mirrors the target list anyway. The approach in
this patch handles the real constraint: the same hardware target cannot
be configured twice, regardless of which CPU does the event open.
Signed-off-by: Athira Rajeev <atrajeev@linux.ibm.com>
---
Changes in V2:
- New patch. V1 did not protect against concurrent duplicate opens of
the same HTM target when 'perf record -a' initialises system-wide
events in parallel on all CPUs.
- Adds a global reserved-targets list. htm_event_init() rejects any
open whose (node, chip, core, type) tuple is already reserved; the
reservation is released through the event destroy path.
- Different targets can still be opened simultaneously on different CPUs.
arch/powerpc/perf/htm-perf.c | 42 ++++++++++++++++++++++++++++++++----
1 file changed, 38 insertions(+), 4 deletions(-)
diff --git a/arch/powerpc/perf/htm-perf.c b/arch/powerpc/perf/htm-perf.c
index abecc9bb58dc..01c6bd2104cf 100644
--- a/arch/powerpc/perf/htm-perf.c
+++ b/arch/powerpc/perf/htm-perf.c
@@ -77,9 +77,13 @@ struct htm_config {
* htm_event_start() and htm_event_stop() to make hcall decisions.
* event->hw.state is kept in sync for the perf core only.
*/
+static LIST_HEAD(htm_active_targets_list);
+static DEFINE_MUTEX(htm_targets_lock);
+
struct htm_target_id {
struct htm_config cfg;
int tracing_active; /* HTM_TRACING_ACTIVE / HTM_TRACING_INACTIVE */
+ struct list_head list;
};
/* Helper to parse the 28-bit event config into distinct fields */
@@ -154,7 +158,17 @@ static ssize_t htm_return_check(int rc)
static void reset_htm_active(struct perf_event *event)
{
- kfree(event->pmu_private);
+ struct htm_target_id *target = event->pmu_private;
+
+ if (!target)
+ return;
+
+ mutex_lock(&htm_targets_lock);
+ if (!list_empty(&target->list))
+ list_del(&target->list);
+ mutex_unlock(&htm_targets_lock);
+
+ kfree(target);
event->pmu_private = NULL;
}
@@ -162,6 +176,7 @@ static int htm_event_init(struct perf_event *event)
{
u64 config = event->attr.config;
struct htm_config cfg;
+ struct htm_target_id *target, *tmp;
if (event->attr.inherit)
return -EOPNOTSUPP;
@@ -188,11 +203,30 @@ static int htm_event_init(struct perf_event *event)
}
/* Allocate per-event private state; freed via event->destroy */
- event->pmu_private = kzalloc(sizeof(struct htm_target_id), GFP_KERNEL);
- if (!event->pmu_private)
+ target = kzalloc(sizeof(*target), GFP_KERNEL);
+ if (!target)
return -ENOMEM;
- ((struct htm_target_id *)event->pmu_private)->cfg = cfg;
+ target->cfg = cfg;
+ target->tracing_active = HTM_TRACING_INACTIVE;
+ INIT_LIST_HEAD(&target->list);
+
+ mutex_lock(&htm_targets_lock);
+ list_for_each_entry(tmp, &htm_active_targets_list, list) {
+ if (tmp->cfg.htmtype == cfg.htmtype &&
+ tmp->cfg.nodeindex == cfg.nodeindex &&
+ tmp->cfg.nodalchipindex == cfg.nodalchipindex &&
+ tmp->cfg.coreindexonchip == cfg.coreindexonchip) {
+ mutex_unlock(&htm_targets_lock);
+ kfree(target);
+ return -EBUSY;
+ }
+ }
+
+ list_add_tail(&target->list, &htm_active_targets_list);
+ mutex_unlock(&htm_targets_lock);
+
+ event->pmu_private = target;
event->destroy = reset_htm_active;
return 0;
}
--
2.43.0
^ permalink raw reply related
* [PATCH V2 3/6] powerpc/perf: Add AUX buffer management to capture HTM trace data
From: Athira Rajeev @ 2026-07-20 10:44 UTC (permalink / raw)
To: linuxppc-dev, maddy
Cc: linux-perf-users, atrajeev, hbathini, tejas05, venkat88, tshah,
usha.r2
In-Reply-To: <20260720104447.11843-1-atrajeev@linux.ibm.com>
Implement support for auxiliary (AUX) ring buffers in the HTM PMU driver.
This enables high-volume trace data to be streamed directly into a perf
AUX buffer for deferred post-processing by the perf tool.
Introduce the PMU data structures htm_pmu_buf and htm_pmu_ctx, and
implement the core lifecycle hooks:
htm_setup_aux(): Allocates per-CPU context and records the AUX buffer
base, head, and size for the active trace window.
htm_free_aux(): Releases the PMU-private tracking allocations.
The perf core AUX allocator (rb_alloc_aux) may return a page array with
physical fragmentation gaps. H_HTM_OP_DUMP_DATA operates on raw physical
addresses and requires a strictly contiguous region; crossing a gap would
cause silent memory corruption.
To prevent this, opt into PERF_PMU_CAP_AUX_NO_SG | PERF_PMU_CAP_AUX_PREFER_LARGE
to request large, physically contiguous allocations, and perform a
page-by-page physical continuity scan in htm_event_read() before each
H_HTM_OP_DUMP_DATA call. The scan verifies that
virt_to_phys(page[n]) + PAGE_SIZE == virt_to_phys(page[n+1]) and
breaks the loop on the first discontinuity, ensuring the dump to the
verified safe window.
Update htm_event_read() to set event->count to 1 when data is present
in the buffer and 0 when the stream is exhausted. This binary flag is
used by the perf tool drain hook to decide whether another read pass is
needed before closing the event. It does not represent an instruction
or cycle count; the actual trace records are decoded in userspace.
HTM target identity and tracing state are kept in event->pmu_private
(htm_target_id). AUX-private state holds only buffer metadata and
dump progress; htm_target_id.tracing_active remains the source for
tracing state.
Signed-off-by: Athira Rajeev <atrajeev@linux.ibm.com>
---
Changes in V2:
- Opted into PERF_PMU_CAP_AUX_NO_SG | PERF_PMU_CAP_AUX_PREFER_LARGE to
request physically contiguous allocations, which H_HTM_OP_DUMP_DATA
requires. V1 didn't handle no contiguity requirement.
- Added a page-by-page physical-continuity scan in htm_event_read()
before every H_HTM_OP_DUMP_DATA call. The scan verifies that
virt_to_phys(page[n]) + PAGE_SIZE == virt_to_phys(page[n+1]) and
stops at the first gap, bounding the dump to a verified safe window.
V1 had no such guard and could silently corrupt memory across gaps.
- event->count is now set to 1 when trace data is present and 0 when
the stream is exhausted. The perf tool uses this as a drain signal.
V1 relied on a separate arch_record__collect_final_data callback loop
with explicit evlist__enable cycling; this version doesn't need
explicit evlist__enable
arch/powerpc/perf/htm-perf.c | 216 ++++++++++++++++++++++++++++++++++-
1 file changed, 215 insertions(+), 1 deletion(-)
diff --git a/arch/powerpc/perf/htm-perf.c b/arch/powerpc/perf/htm-perf.c
index 01c6bd2104cf..edfca63e1e9b 100644
--- a/arch/powerpc/perf/htm-perf.c
+++ b/arch/powerpc/perf/htm-perf.c
@@ -95,6 +95,23 @@ static inline void parse_htm_config(u64 config, struct htm_config *cfg)
cfg->coreindexonchip = (config >> 20) & 0xff;
}
+struct htm_pmu_buf {
+ int nr_pages;
+ bool snapshot;
+ void *base;
+ void **pages;
+ u64 head;
+ u64 size;
+ int collect_htm_trace;
+ u64 trace_records;
+};
+
+struct htm_pmu_ctx {
+ struct perf_output_handle handle;
+};
+
+static DEFINE_PER_CPU(struct htm_pmu_ctx, htm_pmu_ctx);
+
/*
* Check the return code for H_HTM hcall.
* Return 1 if either H_PARTIAL or H_SUCCESS is returned.
@@ -372,8 +389,202 @@ static void htm_event_del(struct perf_event *event, int flags)
/* pmu_private freed by event->destroy = reset_htm_active */
}
+static int htm_dump_sample_data(struct perf_event *event)
+{
+ struct htm_pmu_ctx *htm_ctx = this_cpu_ptr(&htm_pmu_ctx);
+ struct htm_target_id *target = event->pmu_private;
+ struct htm_pmu_buf *aux_buf;
+ struct htm_config cfg = target->cfg;
+ u64 chunk_size, dump_offset, page_index, page_offset;
+ u64 max_contiguous_bytes, expected_phys, scan_index, actual_phys;
+ u64 hypervisor_target_phys;
+ void *target_page_virt;
+ int ret = 0, retries = 0;
+ long rc;
+
+ /* Start AUX transaction session framework */
+ aux_buf = perf_aux_output_begin(&htm_ctx->handle, event);
+ if (!aux_buf)
+ return 0;
+
+ if (!aux_buf->collect_htm_trace) {
+ perf_aux_output_end(&htm_ctx->handle, 0);
+ return 0;
+ }
+
+ if (target->tracing_active == HTM_TRACING_ACTIVE) {
+ htm_event_stop(event, 0);
+ if (target->tracing_active == HTM_TRACING_ACTIVE) {
+ perf_aux_output_end(&htm_ctx->handle, 0);
+ return -EAGAIN;
+ }
+ }
+
+ /* Derive the exact target destination point directly out of active ring pointers */
+ dump_offset = htm_ctx->handle.head & (aux_buf->size - 1);
+ page_index = dump_offset >> PAGE_SHIFT;
+ page_offset = dump_offset & (PAGE_SIZE - 1);
+
+ /*
+ * Assess constraints regarding space remaining across the mapping
+ * context boundary
+ */
+ chunk_size = htm_ctx->handle.size;
+ chunk_size &= PAGE_MASK;
+
+ if (chunk_size > (aux_buf->size - dump_offset))
+ chunk_size = aux_buf->size - dump_offset;
+
+ /*
+ * HTM driver uses these capabilities:
+ * PERF_PMU_CAP_AUX_NO_SG | PERF_PMU_CAP_AUX_PREFER_LARGE
+ * the core perf ring-buffer allocator (rb_alloc_aux) tries to allocate
+ * physically contiguous page block. If not available, it tries to allocate
+ * largest possible contiguous block.
+ *
+ * Example: If we ask perf for 1024 pages (64MB), the kernel executes a loop
+ * inside rb_alloc_aux() to fulfill that request using the buddy allocator. it
+ * always tries to grab the largest possible contiguous block of memory it can
+ * find first, then takes the next largest, and repeats until request is
+ * completely filled. Here while writing to aux buffer, to eliminate any
+ * virtual or physical boundary overruns, check for the page boundary.
+ *
+ * Dynamically scan forward page-by-page from our active page_index to
+ * calculate the absolute boundary limit of this current physically
+ * contiguous block chunk. Prevents hypervisor macro overruns across
+ * asymmetrical fragmentation gaps.
+ */
+ max_contiguous_bytes = PAGE_SIZE - page_offset;
+ scan_index = page_index + 1;
+ expected_phys = (u64)virt_to_phys(aux_buf->pages[page_index]) + PAGE_SIZE;
+
+ while (scan_index < aux_buf->nr_pages && max_contiguous_bytes < chunk_size) {
+ actual_phys = (u64)virt_to_phys(aux_buf->pages[scan_index]);
+
+ if (actual_phys != expected_phys)
+ break; /* Intersected a fragmentation boundary block link! */
+
+ max_contiguous_bytes += PAGE_SIZE;
+ expected_phys += PAGE_SIZE;
+ scan_index++;
+ }
+
+ /* Bound transfer length tightly within the validated contiguous window */
+ if (chunk_size > max_contiguous_bytes)
+ chunk_size = max_contiguous_bytes;
+
+ if (!chunk_size) {
+ aux_buf->collect_htm_trace = 0;
+ perf_aux_output_end(&htm_ctx->handle, 0);
+ return 0;
+ }
+
+ /*
+ * Compute the precise base target address using
+ * localized page offset rules
+ */
+ target_page_virt = aux_buf->pages[page_index];
+ hypervisor_target_phys = (u64)virt_to_phys(target_page_virt) + page_offset;
+
+ do {
+ /*
+ * Invoke H_HTM call with:
+ * - operation as htm dump (H_HTM_OP_DUMP_DATA)
+ * - last three values are address, size and offset
+ */
+ rc = htm_hcall_wrapper(htmflags, cfg.nodeindex, cfg.nodalchipindex,
+ cfg.coreindexonchip, cfg.htmtype, H_HTM_OP_DUMP_DATA,
+ hypervisor_target_phys, chunk_size, aux_buf->head);
+ ret = htm_return_check(rc);
+ } while (ret == -EBUSY && ++retries < MAX_RETRIES);
+
+ if (ret > 0) {
+ aux_buf->head += chunk_size;
+ aux_buf->trace_records++;
+ perf_aux_output_end(&htm_ctx->handle, chunk_size);
+ return ret;
+ }
+
+ aux_buf->collect_htm_trace = 0;
+ perf_aux_output_end(&htm_ctx->handle, 0);
+ return ret;
+}
+
static void htm_event_read(struct perf_event *event)
{
+ int ret;
+
+ /*
+ * Update event->count as a binary indicator:
+ * 1 if data was dumped into the
+ * AUX buffer, 0 otherwise. Actual trace record
+ * decoding is left to userspace.
+ */
+ ret = htm_dump_sample_data(event);
+ if (ret <= 0)
+ local64_set(&event->count, 0);
+ else
+ local64_set(&event->count, 1);
+}
+
+/*
+ * Set up pmu-private data structures for an AUX area
+ * **pages contains the aux buffer allocated for this event
+ * for the corresponding cpu. rb_alloc_aux uses "alloc_pages_node"
+ * and returns pointer to each page address.
+ * PMU capabilities: PERF_PMU_CAP_AUX_NO_SG | PERF_PMU_CAP_AUX_PREFER_LARGE
+ * to try get closest possible physically contiguous page blocks.
+ *
+ * The aux private data structure ie, "struct htm_pmu_buf" mainly
+ * saves
+ * - buf->base: aux buffer base address
+ * - buf->head: offset from base address where data will be written to.
+ * - buf->size: Size of allocated memory
+ */
+static void *htm_setup_aux(struct perf_event *event, void **pages,
+ int nr_pages, bool snapshot)
+{
+ int cpu = event->cpu;
+ struct htm_pmu_buf *buf;
+
+ if (!nr_pages)
+ return NULL;
+
+ if (cpu == -1)
+ cpu = raw_smp_processor_id();
+
+ buf = kzalloc_node(sizeof(*buf), GFP_KERNEL, cpu_to_node(cpu));
+ if (!buf)
+ return NULL;
+
+ buf->nr_pages = nr_pages;
+ buf->snapshot = snapshot;
+ buf->size = (u64)nr_pages << PAGE_SHIFT;
+ buf->pages = pages;
+
+ buf->base = pages[0];
+ if (!buf->base) {
+ kfree(buf);
+ return NULL;
+ }
+
+ buf->collect_htm_trace = 1;
+ buf->trace_records = 0;
+ buf->head = 0;
+ return buf;
+}
+
+/*
+ * free pmu-private AUX data structures
+ */
+static void htm_free_aux(void *aux)
+{
+ struct htm_pmu_buf *buf = aux;
+
+ if (!buf)
+ return;
+
+ kfree(buf);
}
static struct pmu htm_pmu = {
@@ -386,7 +597,10 @@ static struct pmu htm_pmu = {
.read = htm_event_read,
.start = htm_event_start,
.stop = htm_event_stop,
- .capabilities = PERF_PMU_CAP_NO_EXCLUDE | PERF_PMU_CAP_EXCLUSIVE,
+ .setup_aux = htm_setup_aux,
+ .free_aux = htm_free_aux,
+ .capabilities = PERF_PMU_CAP_NO_EXCLUDE | PERF_PMU_CAP_EXCLUSIVE
+ | PERF_PMU_CAP_AUX_NO_SG | PERF_PMU_CAP_AUX_PREFER_LARGE,
};
static int htm_init(void)
--
2.43.0
^ permalink raw reply related
* [PATCH V2 4/6] powerpc/perf: Capture the HTM memory configuration as part of perf data
From: Athira Rajeev @ 2026-07-20 10:44 UTC (permalink / raw)
To: linuxppc-dev, maddy
Cc: linux-perf-users, atrajeev, hbathini, tejas05, venkat88, tshah,
usha.r2
In-Reply-To: <20260720104447.11843-1-atrajeev@linux.ibm.com>
The H_HTM hypervisor call can also return the system memory
configuration, which describes the physical to logical real address
mapping for logical partitions.
After dumping HTM trace data into the AUX buffer, capture the
corresponding HTM system memory configuration records and emit them as
raw perf sample data for userspace parsing.
Add AUX-private tracking for a hypervisor memory-configuration dump
buffer, a stable emit buffer, and iterator state. Once AUX trace dumping
completes, htm_event_read() switches to H_HTM_OP_DUMP_SYSMEM_CONF and
iterates over the returned records until the configuration stream is
exhausted.
Trace payload continues to be written to the AUX buffer, while memory
configuration records are emitted as raw perf samples. This keeps the
AUX stream focused on trace data and allows the configuration records to
be decoded separately in userspace.
Keep HTM tracing state in event->pmu_private via htm_target_id. AUX
private state is used only for dump progress and staging buffers.
Signed-off-by: Athira Rajeev <atrajeev@linux.ibm.com>
---
Changes in V2:
- Memory configuration records are now emitted as PERF_SAMPLE_RAW
samples directly by htm_event_read() after the AUX trace dump
completes, using H_HTM_OP_DUMP_SYSMEM_CONF. V1 embedded the
configuration data inside the AUX buffer itself and used two
PERF_SAMPLE_RAW boundary markers (start/end) to delimit it.
- The two-marker boundary scheme is removed. There is no longer any
interleaving of memory configuration data inside the AUX stream;
the AUX buffer carries only bus-trace data.
- Separate AUX-private fields for a hypervisor dump buffer, a stable
emit buffer, and iterator state are introduced to manage the
multi-call SYSMEM_CONF dump loop.
- Tracing state remains in event->pmu_private (htm_target_id); AUX
private state is used only for dump progress and staging buffers,
consistent with the restructuring in patches 1 and 3.
arch/powerpc/perf/htm-perf.c | 124 ++++++++++++++++++++++++++++++++++-
1 file changed, 123 insertions(+), 1 deletion(-)
diff --git a/arch/powerpc/perf/htm-perf.c b/arch/powerpc/perf/htm-perf.c
index edfca63e1e9b..7e6a67485800 100644
--- a/arch/powerpc/perf/htm-perf.c
+++ b/arch/powerpc/perf/htm-perf.c
@@ -104,6 +104,10 @@ struct htm_pmu_buf {
u64 size;
int collect_htm_trace;
u64 trace_records;
+ void *htm_mem_buf; /* Staging bounce area allocated node-locally */
+ void *emit_buf; /* Stable buffer for perf raw sample emission */
+ u64 mem_start; /* Hypervisor offset state iterator tracker */
+ int collect_htm_mem; /* State flag tracking whether memory logging is ongoing */
};
struct htm_pmu_ctx {
@@ -173,6 +177,99 @@ static ssize_t htm_return_check(int rc)
#define HTM_TRACING_ACTIVE 1
#define HTM_TRACING_INACTIVE 0
+#define HTM_MEM_MAX_ENTRIES 2013U
+#define HTM_MEM_BUF_SIZE (32 + HTM_MEM_MAX_ENTRIES * 32)
+
+static int htm_collect_memory_config(struct perf_event *event,
+ struct htm_pmu_buf *aux_buf)
+{
+ struct perf_sample_data data;
+ struct perf_raw_record raw;
+ struct pt_regs regs;
+ u8 *htm_mem_buf = aux_buf->htm_mem_buf;
+ __be64 *num_entries;
+ u64 next_start;
+ u64 to_copy;
+ void *emit_buf = aux_buf->emit_buf;
+ long rc;
+ int ret = 0;
+ int retries;
+ int emitted = 0;
+
+ /*
+ * htm_mem_buf is the hcall memory buffer target reused each iteration.
+ * emit_buf is a preallocated stable buffer used for perf raw
+ * sample emission, so raw.frag.data remains valid during
+ * perf_event_overflow().
+ * Size: 32-byte header + HTM_MEM_MAX_ENTRIES * 32-byte entries.
+ */
+ while (true) {
+ retries = 0;
+ do {
+ rc = htm_hcall_wrapper(htmflags, 0, 0, 0,
+ 0, H_HTM_OP_DUMP_SYSMEM_CONF,
+ virt_to_phys(aux_buf->htm_mem_buf),
+ HTM_MEM_BUF_SIZE, aux_buf->mem_start);
+ ret = htm_return_check(rc);
+ } while (ret == -EBUSY && ++retries < MAX_RETRIES);
+
+ /* H_NOT_AVAILABLE or error: no more data */
+ if (ret <= 0) {
+ aux_buf->collect_htm_mem = 0;
+ break;
+ }
+
+ /*
+ * Read next iterator value from the hcall response BEFORE
+ * emitting, but only commit it to mem_start after a
+ * successful writing of raw data/
+ */
+ next_start = be64_to_cpu(*((__be64 *)(htm_mem_buf + 0x8)));
+
+ /*
+ * The hcall was given HTM_MEM_BUF_SIZE bytes of buffer space,
+ * so num_entries is already bounded to HTM_MEM_MAX_ENTRIES.
+ * The response is a complete hcall data:
+ * [32-byte header][num_entries * 32-byte entries]
+ * Userspace can validate and parse it directly.
+ */
+ num_entries = (__be64 *)(htm_mem_buf + 0x10);
+ to_copy = 32 + (be64_to_cpu(*num_entries) * 32);
+ if (WARN_ON_ONCE(to_copy > HTM_MEM_BUF_SIZE)) {
+ ret = -EIO;
+ aux_buf->collect_htm_mem = 0;
+ break;
+ }
+
+ memcpy(emit_buf, aux_buf->htm_mem_buf, to_copy);
+
+ perf_sample_data_init(&data, 0, event->hw.last_period);
+ memset(&raw, 0, sizeof(raw));
+ raw.frag.data = emit_buf;
+ raw.frag.size = to_copy;
+ perf_sample_save_raw_data(&data, event, &raw);
+
+ if (perf_event_overflow(event, &data, ®s)) {
+ ret = 0;
+ break;
+ }
+
+ /* Record written: advance next read iterator */
+ aux_buf->mem_start = next_start;
+ emitted = 1;
+
+ if (!next_start) {
+ aux_buf->collect_htm_mem = 0;
+ break;
+ }
+ }
+
+ if (emitted)
+ return 1;
+
+ return ret;
+}
+
static void reset_htm_active(struct perf_event *event)
{
struct htm_target_id *target = event->pmu_private;
@@ -407,7 +504,7 @@ static int htm_dump_sample_data(struct perf_event *event)
if (!aux_buf)
return 0;
- if (!aux_buf->collect_htm_trace) {
+ if (!aux_buf->collect_htm_trace && !aux_buf->collect_htm_mem) {
perf_aux_output_end(&htm_ctx->handle, 0);
return 0;
}
@@ -420,6 +517,11 @@ static int htm_dump_sample_data(struct perf_event *event)
}
}
+ if (!aux_buf->collect_htm_trace) {
+ ret = htm_collect_memory_config(event, aux_buf);
+ goto out;
+ }
+
/* Derive the exact target destination point directly out of active ring pointers */
dump_offset = htm_ctx->handle.head & (aux_buf->size - 1);
page_index = dump_offset >> PAGE_SHIFT;
@@ -506,6 +608,8 @@ static int htm_dump_sample_data(struct perf_event *event)
}
aux_buf->collect_htm_trace = 0;
+ ret = htm_collect_memory_config(event, aux_buf);
+out:
perf_aux_output_end(&htm_ctx->handle, 0);
return ret;
}
@@ -568,7 +672,23 @@ static void *htm_setup_aux(struct perf_event *event, void **pages,
return NULL;
}
+ buf->htm_mem_buf = kmalloc_node(PAGE_SIZE, GFP_KERNEL, cpu_to_node(cpu));
+ if (!buf->htm_mem_buf) {
+ kfree(buf);
+ return NULL;
+ }
+
+ buf->emit_buf = kmalloc_node(HTM_MEM_BUF_SIZE, GFP_KERNEL,
+ cpu_to_node(cpu));
+ if (!buf->emit_buf) {
+ kfree(buf->htm_mem_buf);
+ kfree(buf);
+ return NULL;
+ }
+
buf->collect_htm_trace = 1;
+ buf->collect_htm_mem = 1;
+ buf->mem_start = 0;
buf->trace_records = 0;
buf->head = 0;
return buf;
@@ -584,6 +704,8 @@ static void htm_free_aux(void *aux)
if (!buf)
return;
+ kfree(buf->emit_buf);
+ kfree(buf->htm_mem_buf);
kfree(buf);
}
--
2.43.0
^ permalink raw reply related
* [PATCH V2 5/6] docs: ABI: sysfs-bus-event_source-devices-htm: Document sysfs event format entries for htm pmu
From: Athira Rajeev @ 2026-07-20 10:44 UTC (permalink / raw)
To: linuxppc-dev, maddy
Cc: linux-perf-users, atrajeev, hbathini, tejas05, venkat88, tshah,
usha.r2
In-Reply-To: <20260720104447.11843-1-atrajeev@linux.ibm.com>
Add ABI documentation for the sysfs entries exposed by the "htm" PMU
under /sys/bus/event_source/devices/htm/.
Document the format attribute group, which describes the bit layout of
perf_event_attr.config accepted by the htm PMU:
htm_type config bits 0-3 (HTM_CORE=2, HTM_NEST=1)
nodeindex config bits 4-11
nodalchipindex config bits 12-19
coreindexonchip config bits 20-27
Document the events attribute group, which lists the named events
available on the PMU. Users can pass these names directly to perf:
# perf record -e htm/nodalchipindex=2,nodeindex=0,htm_type=1/ ...
Signed-off-by: Athira Rajeev <atrajeev@linux.ibm.com>
---
Changes in V2:
- Updated the bit-range descriptions to match the V2 config layout:
htm_type is bits 0-3 (was listed inconsistently in V1), nodeindex
is bits 4-11, nodalchipindex is bits 12-19, coreindexonchip is
bits 20-27.
- Added documentation for the events/ sysfs group which lists named
events users can pass directly to perf (e.g.
htm/nodalchipindex=2,nodeindex=0,htm_type=1/). This group was not
documented in V1.
- Patch is now 5/6 instead of 4/5.
.../sysfs-bus-event_source-devices-htm | 21 +++++++++++++++++++
1 file changed, 21 insertions(+)
create mode 100644 Documentation/ABI/testing/sysfs-bus-event_source-devices-htm
diff --git a/Documentation/ABI/testing/sysfs-bus-event_source-devices-htm b/Documentation/ABI/testing/sysfs-bus-event_source-devices-htm
new file mode 100644
index 000000000000..784ba7c31b89
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-bus-event_source-devices-htm
@@ -0,0 +1,21 @@
+What: /sys/bus/event_source/devices/htm/format
+Date: June 2026
+Contact: Linux on PowerPC Developer List <linuxppc-dev at lists.ozlabs.org>
+Description: Read-only. Attribute group to describe the magic bits
+ that go into perf_event_attr.config for a particular pmu.
+ (See ABI/testing/sysfs-bus-event_source-devices-format).
+
+ Each attribute under this group defines a bit range of the
+ perf_event_attr.config. Supported attribute are listed
+ below::
+
+ event = "config:0-27" - event ID
+
+What: /sys/bus/event_source/devices/htm/events
+Date: June 2026
+Contact: Linux on PowerPC Developer List <linuxppc-dev at lists.ozlabs.org>
+Description: (RO) Attribute group to describe performance monitoring events
+ for the Hardware Trace Macro (HTM) trace. Each attribute in
+ this group describes a single performance monitoring event
+ supported by htm pmu. The name of the file is the name of
+ the event (See ABI/testing/sysfs-bus-event_source-devices-events).
--
2.43.0
^ permalink raw reply related
* [PATCH V2 6/6] powerpc/perf/htm: Add documentation for Hardware Trace Macro PMU
From: Athira Rajeev @ 2026-07-20 10:44 UTC (permalink / raw)
To: linuxppc-dev, maddy
Cc: linux-perf-users, atrajeev, hbathini, tejas05, venkat88, tshah,
usha.r2
In-Reply-To: <20260720104447.11843-1-atrajeev@linux.ibm.com>
Extend Documentation/arch/powerpc/htm.rst with a new section covering
the HTM perf PMU interface.
The added documentation covers:
- How to open HTM events using perf record, including the event
syntax (nodalchipindex, nodeindex, htm_type, cpu=N) and the
required AUX buffer size (-m,256).
- The two output files produced by perf report:
htm.bin.nX.pX.cX raw bus-trace AUX data
translation.nX.pX.cX memory-configuration records
- How to pass the output files to htmdecode for trace decoding.
- Notes on system-wide collection (-a) vs CPU-pinned collection
(-C N) and the one-event-per-target PMU restriction.
The existing debugfs interface documentation is retained unchanged.
A brief cross-reference is added at the top to point readers to the
new perf interface section.
Signed-off-by: Athira Rajeev <atrajeev@linux.ibm.com>
---
Changes in V2:
- Updated the usage with more examples
- Patch is now 6/6 instead of 5/5.
Documentation/arch/powerpc/htm.rst | 137 ++++++++++++++++++++++++++++-
1 file changed, 134 insertions(+), 3 deletions(-)
diff --git a/Documentation/arch/powerpc/htm.rst b/Documentation/arch/powerpc/htm.rst
index fcb4eb6306b1..d574fd2225ea 100644
--- a/Documentation/arch/powerpc/htm.rst
+++ b/Documentation/arch/powerpc/htm.rst
@@ -18,9 +18,10 @@ H_HTM is used as an interface for executing Hardware Trace Macro (HTM)
functions, including setup, configuration, control and dumping of the HTM data.
For using HTM, it is required to setup HTM buffers and HTM operations can
be controlled using the H_HTM hcall. The hcall can be invoked for any core/chip
-of the system from within a partition itself. To use this feature, a debugfs
-folder called "htmdump" is present under /sys/kernel/debug/powerpc.
+of the system from within a partition itself.
+To use this feature, a debugfs folder called "htmdump" is present under
+/sys/kernel/debug/powerpc. Another interface is via perf.
HTM debugfs example usage
=========================
@@ -94,7 +95,137 @@ This trace file will contain the relevant instruction traces
collected during the workload execution. And can be used as
input file for trace decoders to understand data.
-Benefits of using HTM debugfs interface
+HTM perf interface usage
+========================
+
+The HTM (Hardware Trace Macro) perf interface enables collection and analysis
+of hardware trace data from PowerPC systems. This interface allows users to
+capture detailed execution traces for performance analysis and debugging.
+
+Event Configuration
+-------------------
+
+Use ``perf record`` with the htm PMU event. The event is configured using
+named parameters that specify the target hardware location and trace type:
+
+.. list-table::
+ :header-rows: 1
+ :widths: 25 75
+
+ * - Parameter
+ - Description
+ * - htm_type
+ - Type of HTM trace to collect (bits 0-3)
+ * - nodeindex
+ - Node index in the system topology (bits 4-11)
+ * - nodalchipindex
+ - Chip index within the specified node (bits 12-19)
+ * - coreindexonchip
+ - Core index on the specified chip (bits 20-27)
+
+- event: "config:0-27"
+- htm_type: "config:0-3"
+- nodeindex: "config:4-11"
+- nodalchipindex: "config:12-19"
+- coreindexonchip: "config:20-27"
+
+1) nodeindex, nodalchipindex, coreindexonchip: this specifies
+ which partition to configure the HTM for.
+2) htmtype: specifies the type of HTM.
+
+Event Syntax
+------------
+
+The event configuration uses named parameters::
+
+ htm/nodeindex=N,nodalchipindex=C,coreindexonchip=R,htm_type=T/
+
+To open the event on a specific cpu can be specified using::
+
+ htm/nodeindex=N,nodalchipindex=C,coreindexonchip=R,htm_type=T,cpu=x/
+
+Where:
+
+- N = node index
+- C = chip index within the node
+- R = core index on the chip
+- T = HTM type
+- x = CPU number
+
+Basic Usage Example
+-------------------
+
+To collect HTM trace data for a specific chip:
+
+.. code-block:: sh
+
+ # perf record -C 1 -e htm/nodalchipindex=2,nodeindex=0,htm_type=1/ <workload>
+
+In this example:
+
+- ``-C 1``: Collect on CPU 1
+- ``nodeindex=0``: Target node 0
+- ``nodalchipindex=2``: Target chip 2 within node 0
+- ``htm_type=1``: HTM trace type 1
+
+.. code-block:: sh
+
+ # perf record -m,256 -e htm/coreindexonchip=6,nodalchipindex=0,nodeindex=0,htm_type=2,cpu=16/ -a sleep 1
+
+In this example:
+
+- ``cpu=16``: Collect on CPU 16
+- ``nodeindex=0``: Target node 0
+- ``nodalchipindex=0``: Target chip 0 within node 0
+- ``coreindexonchip=6``: Target code 6
+- ``htm_type=2``: HTM trace type 2
+- ``-m,256``: specifies number of mmap pages
+
+Running trace collection for multiple targets:
+
+.. code-block:: sh
+
+ # perf record -m,256 -e htm/nodalchipindex=2,nodeindex=0,htm_type=1,cpu=8/ -e htm/nodalchipindex=1,nodeindex=0,htm_type=1,cpu=9/ -a sleep 1
+
+
+In this example, trace is collected for two events on different target chips
+
+Output Files
+------------
+
+After running ``perf record``, the following files are generated:
+
+.. code-block:: sh
+
+ # ls htm.bin.*
+ htm.bin.n0.p2.c0 htm.bin.n1.p3.c0 # Binary trace files
+
+ # ls translation.*
+ translation.n0.p2.c0 translation.n1.p3.c0 # Memory configuration files
+
+These files contain:
+
+- **htm.bin.*** - Raw HTM trace data in binary format
+- **translation.*** - Memory address translation information for decoding
+
+Complete Workflow Example
+--------------------------
+
+Here's a complete example of collecting and analyzing HTM traces:
+
+.. code-block:: sh
+
+ # Step 1: Collect trace data
+ perf record -C 1 -e htm/nodalchipindex=2,nodeindex=0,htm_type=1/ sleep 5
+
+ # Step 2: Verify output files
+ perf report -D
+
+ ls htm.bin.* # Binary trace files
+ ls translation.* # Memory configuration files
+ ls perf.data # Perf data file
+
+Benefits of using HTM interface
=======================================
It is now possible to collect traces for a particular core/chip
--
2.43.0
^ permalink raw reply related
* [PATCH 2/3] sched: Convert paravirt_steal to new static key APIs
From: Hongyan Xia @ 2026-07-20 9:38 UTC (permalink / raw)
To: mingo@redhat.com, peterz@infradead.org, juri.lelli@redhat.com,
vincent.guittot@linaro.org, dietmar.eggemann@arm.com,
rostedt@goodmis.org, bsegall@google.com, mgorman@suse.de,
vschneid@redhat.com, kprateek.nayak@amd.com, Juergen Gross,
Ajay Kaher, Alexey Makhalov, Broadcom internal kernel review list,
Catalin Marinas, Will Deacon, Huacai Chen, WANG Xuerui,
Madhavan Srinivasan, Michael Ellerman, Nicholas Piggin,
Christophe Leroy (CS GROUP), Paul Walmsley, Palmer Dabbelt,
Albert Ou, Alexandre Ghiti, Thomas Gleixner, Borislav Petkov,
Dave Hansen, x86@kernel.org, H. Peter Anvin, Paolo Bonzini,
Vitaly Kuznetsov, Stefano Stabellini, Oleksandr Tyshchenko
Cc: Jiazi Li, linux-kernel@vger.kernel.org,
virtualization@lists.linux.dev,
linux-arm-kernel@lists.infradead.org, loongarch@lists.linux.dev,
linuxppc-dev@lists.ozlabs.org, linux-riscv@lists.infradead.org,
kvm@vger.kernel.org, xen-devel@lists.xenproject.org
In-Reply-To: <cover.1784538478.git.hongyan.xia@transsion.com>
From: Hongyan Xia <hongyan.xia@transsion.com>
paravirt_steal_rq_enabled and paravirt_steal_enabled use raw static_key
APIs which are now deprecated. Use the new API instead.
No functional change.
Signed-off-by: Hongyan Xia <hongyan.xia@transsion.com>
---
arch/arm64/kernel/paravirt.c | 4 ++--
arch/loongarch/kernel/paravirt.c | 4 ++--
arch/powerpc/platforms/pseries/setup.c | 4 ++--
arch/riscv/kernel/paravirt.c | 4 ++--
arch/x86/kernel/cpu/vmware.c | 4 ++--
arch/x86/kernel/kvm.c | 4 ++--
drivers/xen/time.c | 4 ++--
include/linux/sched/cputime.h | 6 +++---
kernel/sched/core.c | 4 ++--
kernel/sched/cputime.c | 4 ++--
10 files changed, 21 insertions(+), 21 deletions(-)
diff --git a/arch/arm64/kernel/paravirt.c b/arch/arm64/kernel/paravirt.c
index 572efb96b23f..30bf61d031eb 100644
--- a/arch/arm64/kernel/paravirt.c
+++ b/arch/arm64/kernel/paravirt.c
@@ -157,9 +157,9 @@ int __init pv_time_init(void)
static_call_update(pv_steal_clock, para_steal_clock);
- static_key_slow_inc(¶virt_steal_enabled);
+ static_branch_inc(¶virt_steal_enabled);
if (steal_acc)
- static_key_slow_inc(¶virt_steal_rq_enabled);
+ static_branch_inc(¶virt_steal_rq_enabled);
pr_info("using stolen time PV\n");
diff --git a/arch/loongarch/kernel/paravirt.c b/arch/loongarch/kernel/paravirt.c
index 10821cce554c..e8965a3f8082 100644
--- a/arch/loongarch/kernel/paravirt.c
+++ b/arch/loongarch/kernel/paravirt.c
@@ -308,10 +308,10 @@ int __init pv_time_init(void)
static_call_update(pv_steal_clock, paravt_steal_clock);
- static_key_slow_inc(¶virt_steal_enabled);
+ static_branch_inc(¶virt_steal_enabled);
#ifdef CONFIG_PARAVIRT_TIME_ACCOUNTING
if (steal_acc)
- static_key_slow_inc(¶virt_steal_rq_enabled);
+ static_branch_inc(¶virt_steal_rq_enabled);
#endif
if (static_key_enabled(&virt_preempt_key))
diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c
index 1223dc961242..8dcbc4bb7025 100644
--- a/arch/powerpc/platforms/pseries/setup.c
+++ b/arch/powerpc/platforms/pseries/setup.c
@@ -852,9 +852,9 @@ static void __init pSeries_setup_arch(void)
static_branch_enable(&shared_processor);
pv_spinlocks_init();
#ifdef CONFIG_PARAVIRT_TIME_ACCOUNTING
- static_key_slow_inc(¶virt_steal_enabled);
+ static_branch_inc(¶virt_steal_enabled);
if (steal_acc)
- static_key_slow_inc(¶virt_steal_rq_enabled);
+ static_branch_inc(¶virt_steal_rq_enabled);
#endif
}
diff --git a/arch/riscv/kernel/paravirt.c b/arch/riscv/kernel/paravirt.c
index 5f56be79cd06..9c13a6f1ea2a 100644
--- a/arch/riscv/kernel/paravirt.c
+++ b/arch/riscv/kernel/paravirt.c
@@ -116,9 +116,9 @@ int __init pv_time_init(void)
static_call_update(pv_steal_clock, pv_time_steal_clock);
- static_key_slow_inc(¶virt_steal_enabled);
+ static_branch_inc(¶virt_steal_enabled);
if (steal_acc)
- static_key_slow_inc(¶virt_steal_rq_enabled);
+ static_branch_inc(¶virt_steal_rq_enabled);
pr_info("Computing paravirt steal-time\n");
diff --git a/arch/x86/kernel/cpu/vmware.c b/arch/x86/kernel/cpu/vmware.c
index 34b73573b108..f7ab9e7902cf 100644
--- a/arch/x86/kernel/cpu/vmware.c
+++ b/arch/x86/kernel/cpu/vmware.c
@@ -328,9 +328,9 @@ static int vmware_cpu_down_prepare(unsigned int cpu)
static __init int activate_jump_labels(void)
{
if (has_steal_clock) {
- static_key_slow_inc(¶virt_steal_enabled);
+ static_branch_inc(¶virt_steal_enabled);
if (steal_acc)
- static_key_slow_inc(¶virt_steal_rq_enabled);
+ static_branch_inc(¶virt_steal_rq_enabled);
}
return 0;
diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c
index dcef84da304b..d3dcd64f22c2 100644
--- a/arch/x86/kernel/kvm.c
+++ b/arch/x86/kernel/kvm.c
@@ -1052,9 +1052,9 @@ const __initconst struct hypervisor_x86 x86_hyper_kvm = {
static __init int activate_jump_labels(void)
{
if (has_steal_clock) {
- static_key_slow_inc(¶virt_steal_enabled);
+ static_branch_inc(¶virt_steal_enabled);
if (steal_acc)
- static_key_slow_inc(¶virt_steal_rq_enabled);
+ static_branch_inc(¶virt_steal_rq_enabled);
}
return 0;
diff --git a/drivers/xen/time.c b/drivers/xen/time.c
index a2be0a4d45b0..a02d48a2aa68 100644
--- a/drivers/xen/time.c
+++ b/drivers/xen/time.c
@@ -169,7 +169,7 @@ void __init xen_time_setup_guest(void)
static_call_update(pv_steal_clock, xen_steal_clock);
- static_key_slow_inc(¶virt_steal_enabled);
+ static_branch_inc(¶virt_steal_enabled);
if (xen_runstate_remote)
- static_key_slow_inc(¶virt_steal_rq_enabled);
+ static_branch_inc(¶virt_steal_rq_enabled);
}
diff --git a/include/linux/sched/cputime.h b/include/linux/sched/cputime.h
index e90efaf6d26e..694126411dfe 100644
--- a/include/linux/sched/cputime.h
+++ b/include/linux/sched/cputime.h
@@ -182,9 +182,9 @@ extern unsigned long long
task_sched_runtime(struct task_struct *task);
#ifdef CONFIG_PARAVIRT
-struct static_key;
-extern struct static_key paravirt_steal_enabled;
-extern struct static_key paravirt_steal_rq_enabled;
+#include <linux/jump_label.h>
+DECLARE_STATIC_KEY_FALSE(paravirt_steal_enabled);
+DECLARE_STATIC_KEY_FALSE(paravirt_steal_rq_enabled);
#ifdef CONFIG_HAVE_PV_STEAL_CLOCK_GEN
u64 dummy_steal_clock(int cpu);
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 96226707c2f6..786975d4ca1e 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -795,7 +795,7 @@ struct rq *_task_rq_lock(struct task_struct *p, struct rq_flags *rf)
/* Use CONFIG_PARAVIRT as this will avoid more #ifdef in arch code. */
#ifdef CONFIG_PARAVIRT
-struct static_key paravirt_steal_rq_enabled;
+DEFINE_STATIC_KEY_FALSE(paravirt_steal_rq_enabled);
#endif
static void update_rq_clock_task(struct rq *rq, s64 delta)
@@ -834,7 +834,7 @@ static void update_rq_clock_task(struct rq *rq, s64 delta)
}
#endif
#ifdef CONFIG_PARAVIRT_TIME_ACCOUNTING
- if (static_key_false((¶virt_steal_rq_enabled))) {
+ if (static_branch_unlikely(¶virt_steal_rq_enabled)) {
u64 prev_steal;
steal = prev_steal = paravirt_steal_clock(cpu_of(rq));
diff --git a/kernel/sched/cputime.c b/kernel/sched/cputime.c
index 06bddaa738e5..f16970ca81d0 100644
--- a/kernel/sched/cputime.c
+++ b/kernel/sched/cputime.c
@@ -255,7 +255,7 @@ void __account_forceidle_time(struct task_struct *p, u64 delta)
* occasion account more time than the calling functions think elapsed.
*/
#ifdef CONFIG_PARAVIRT
-struct static_key paravirt_steal_enabled;
+DEFINE_STATIC_KEY_FALSE(paravirt_steal_enabled);
#ifdef CONFIG_HAVE_PV_STEAL_CLOCK_GEN
static u64 native_steal_clock(int cpu)
@@ -270,7 +270,7 @@ DEFINE_STATIC_CALL(pv_steal_clock, native_steal_clock);
static __always_inline u64 steal_account_process_time(u64 maxtime)
{
#ifdef CONFIG_PARAVIRT
- if (static_key_false(¶virt_steal_enabled)) {
+ if (static_branch_unlikely(¶virt_steal_enabled)) {
u64 steal;
steal = paravirt_steal_clock(smp_processor_id());
--
2.47.3
^ permalink raw reply related
* [PATCH V2 1/6] tools/perf: Move powerpc VPA-DTL auxtrace init into a separate file
From: Athira Rajeev @ 2026-07-20 10:52 UTC (permalink / raw)
To: acme, jolsa, adrian.hunter, maddy, irogers, namhyung
Cc: linux-perf-users, linuxppc-dev, atrajeev, hbathini, tejas05,
tshah, venkat88, usha.r2
In-Reply-To: <20260720105218.14277-1-atrajeev@linux.ibm.com>
The powerpc auxtrace dispatch lives entirely in
arch/powerpc/util/auxtrace.c. As new PMUs such as HTM are added, this
file would grow to contain the recording logic for all of them.
Factor out the VPA-DTL recording initializer into its own file,
arch/powerpc/util/vpa-dtl.c, and reduce auxtrace.c to a thin dispatch
layer. auxtrace_record__init() now detects the PMU by name and calls
the appropriate per-PMU init function:
- vpa_dtl_recording_init() for VPA-DTL events (unchanged behaviour)
- Further PMU entries will follow in subsequent patches
This makes room in auxtrace_record__init() for the HTM recording path
added in the next patch without growing a single monolithic file.
Signed-off-by: Athira Rajeev <atrajeev@linux.ibm.com>
---
Changes in V2:
- Renamed the destination file from arch/powerpc/util/vpa-dtl.c (same
name, unchanged) but the subject and commit message are reworded to
clearly state that the goal is to make auxtrace_record__init() a thin
per-PMU dispatcher, not merely to "allow multiple PMUs to use auxtrace".
- Handle failure from memory allocation
- Included stdlib and limits.h
- No functional change to the VPA-DTL path itself.
- Patch is now 1/6 instead of 1/9.
tools/perf/arch/powerpc/util/Build | 1 +
tools/perf/arch/powerpc/util/auxtrace.c | 84 +++-------------------
tools/perf/arch/powerpc/util/vpa-dtl.c | 95 +++++++++++++++++++++++++
tools/perf/util/powerpc-vpadtl.h | 1 +
4 files changed, 105 insertions(+), 76 deletions(-)
create mode 100644 tools/perf/arch/powerpc/util/vpa-dtl.c
diff --git a/tools/perf/arch/powerpc/util/Build b/tools/perf/arch/powerpc/util/Build
index ae928050e07a..7819c8f5af2d 100644
--- a/tools/perf/arch/powerpc/util/Build
+++ b/tools/perf/arch/powerpc/util/Build
@@ -7,3 +7,4 @@ perf-util-y += evsel.o
perf-util-$(CONFIG_LIBDW) += skip-callchain-idx.o
perf-util-y += auxtrace.o
+perf-util-y += vpa-dtl.o
diff --git a/tools/perf/arch/powerpc/util/auxtrace.c b/tools/perf/arch/powerpc/util/auxtrace.c
index 4600a1661b4f..e04a0bd61755 100644
--- a/tools/perf/arch/powerpc/util/auxtrace.c
+++ b/tools/perf/arch/powerpc/util/auxtrace.c
@@ -13,63 +13,12 @@
#include "../../util/auxtrace.h"
#include "../../util/powerpc-vpadtl.h"
#include "../../util/record.h"
-#include <internal/lib.h> // page_size
-
-#define KiB(x) ((x) * 1024)
-
-static int
-powerpc_vpadtl_recording_options(struct auxtrace_record *ar __maybe_unused,
- struct evlist *evlist __maybe_unused,
- struct record_opts *opts)
-{
- opts->full_auxtrace = true;
-
- /*
- * Set auxtrace_mmap_pages to minimum
- * two pages
- */
- if (!opts->auxtrace_mmap_pages) {
- opts->auxtrace_mmap_pages = KiB(128) / page_size;
- if (opts->mmap_pages == UINT_MAX)
- opts->mmap_pages = KiB(256) / page_size;
- }
-
- return 0;
-}
-
-static size_t powerpc_vpadtl_info_priv_size(struct auxtrace_record *itr __maybe_unused,
- struct evlist *evlist __maybe_unused)
-{
- return VPADTL_AUXTRACE_PRIV_SIZE;
-}
-
-static int
-powerpc_vpadtl_info_fill(struct auxtrace_record *itr __maybe_unused,
- struct perf_session *session __maybe_unused,
- struct perf_record_auxtrace_info *auxtrace_info,
- size_t priv_size __maybe_unused)
-{
- auxtrace_info->type = PERF_AUXTRACE_VPA_DTL;
-
- return 0;
-}
-
-static void powerpc_vpadtl_free(struct auxtrace_record *itr)
-{
- free(itr);
-}
-
-static u64 powerpc_vpadtl_reference(struct auxtrace_record *itr __maybe_unused)
-{
- return 0;
-}
struct auxtrace_record *auxtrace_record__init(struct evlist *evlist,
int *err)
{
- struct auxtrace_record *aux;
struct evsel *pos;
- int found = 0;
+ struct evsel *vpa_dtl_evsel = NULL;
/*
* Set err value to zero here. Any fail later
@@ -78,33 +27,16 @@ struct auxtrace_record *auxtrace_record__init(struct evlist *evlist,
*err = 0;
evlist__for_each_entry(evlist, pos) {
- if (strstarts(pos->name, "vpa_dtl")) {
- found = 1;
+ if (pos->name && strstarts(pos->name, "vpa_dtl")) {
pos->needs_auxtrace_mmap = true;
- break;
+ /* Remember the first matching VPA DTL event */
+ if (!vpa_dtl_evsel)
+ vpa_dtl_evsel = pos;
}
}
- if (!found)
- return NULL;
-
- /*
- * To obtain the auxtrace buffer file descriptor, the auxtrace event
- * must come first.
- */
- evlist__to_front(pos->evlist, pos);
-
- aux = zalloc(sizeof(*aux));
- if (aux == NULL) {
- pr_debug("aux record is NULL\n");
- *err = -ENOMEM;
- return NULL;
- }
+ if (vpa_dtl_evsel)
+ return vpa_dtl_recording_init(vpa_dtl_evsel, err);
- aux->recording_options = powerpc_vpadtl_recording_options;
- aux->info_priv_size = powerpc_vpadtl_info_priv_size;
- aux->info_fill = powerpc_vpadtl_info_fill;
- aux->free = powerpc_vpadtl_free;
- aux->reference = powerpc_vpadtl_reference;
- return aux;
+ return NULL;
}
diff --git a/tools/perf/arch/powerpc/util/vpa-dtl.c b/tools/perf/arch/powerpc/util/vpa-dtl.c
new file mode 100644
index 000000000000..fde388d87477
--- /dev/null
+++ b/tools/perf/arch/powerpc/util/vpa-dtl.c
@@ -0,0 +1,95 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * VPA DTL AUX tracing support
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <limits.h>
+#include "../../util/cpumap.h"
+#include "../../util/evsel.h"
+#include "../../util/evlist.h"
+#include "../../util/session.h"
+#include "../../util/util.h"
+#include "../../util/debug.h"
+#include "../../util/auxtrace.h"
+#include "../../util/powerpc-vpadtl.h"
+#include "../../util/record.h"
+#include <internal/lib.h> // page_size
+
+#define KiB(x) ((x) * 1024)
+
+static int
+powerpc_vpadtl_recording_options(struct auxtrace_record *ar __maybe_unused,
+ struct evlist *evlist __maybe_unused,
+ struct record_opts *opts)
+{
+ opts->full_auxtrace = true;
+
+ /*
+ * Set auxtrace_mmap_pages to minimum
+ * two pages
+ */
+ if (!opts->auxtrace_mmap_pages) {
+ opts->auxtrace_mmap_pages = KiB(128) / page_size;
+ if (opts->mmap_pages == UINT_MAX)
+ opts->mmap_pages = KiB(256) / page_size;
+ }
+
+ return 0;
+}
+
+static size_t powerpc_vpadtl_info_priv_size(struct auxtrace_record *itr __maybe_unused,
+ struct evlist *evlist __maybe_unused)
+{
+ return VPADTL_AUXTRACE_PRIV_SIZE;
+}
+
+static int
+powerpc_vpadtl_info_fill(struct auxtrace_record *itr __maybe_unused,
+ struct perf_session *session __maybe_unused,
+ struct perf_record_auxtrace_info *auxtrace_info,
+ size_t priv_size __maybe_unused)
+{
+ auxtrace_info->type = PERF_AUXTRACE_VPA_DTL;
+
+ return 0;
+}
+
+static void powerpc_vpadtl_free(struct auxtrace_record *itr)
+{
+ free(itr);
+}
+
+static u64 powerpc_vpadtl_reference(struct auxtrace_record *itr __maybe_unused)
+{
+ return 0;
+}
+
+struct auxtrace_record *vpa_dtl_recording_init(struct evsel *pos, int *err)
+{
+ struct auxtrace_record *aux;
+
+ /*
+ * To obtain the auxtrace buffer file descriptor, the auxtrace event
+ * must come first.
+ */
+ evlist__to_front(pos->evlist, pos);
+
+ aux = zalloc(sizeof(*aux));
+ if (aux == NULL) {
+ pr_debug("aux record allocation failed (-ENOMEM)\n");
+ *err = -ENOMEM;
+ return NULL;
+ }
+
+ aux->recording_options = powerpc_vpadtl_recording_options;
+ aux->info_priv_size = powerpc_vpadtl_info_priv_size;
+ aux->info_fill = powerpc_vpadtl_info_fill;
+ aux->free = powerpc_vpadtl_free;
+ aux->reference = powerpc_vpadtl_reference;
+ return aux;
+}
diff --git a/tools/perf/util/powerpc-vpadtl.h b/tools/perf/util/powerpc-vpadtl.h
index ca809660b9bb..41e09b17a353 100644
--- a/tools/perf/util/powerpc-vpadtl.h
+++ b/tools/perf/util/powerpc-vpadtl.h
@@ -20,4 +20,5 @@ struct perf_pmu;
int powerpc_vpadtl_process_auxtrace_info(union perf_event *event,
struct perf_session *session);
+struct auxtrace_record *vpa_dtl_recording_init(struct evsel *pos, int *err);
#endif
--
2.43.0
^ permalink raw reply related
* [PATCH V2 0/6] tools/perf: Add powerpc HTM auxtrace support
From: Athira Rajeev @ 2026-07-20 10:52 UTC (permalink / raw)
To: acme, jolsa, adrian.hunter, maddy, irogers, namhyung
Cc: linux-perf-users, linuxppc-dev, atrajeev, hbathini, tejas05,
tshah, venkat88, usha.r2
Overview:
This series adds perf tool support for capturing and processing Hardware
Trace Macro (HTM) trace data on POWER systems. HTM exposes raw bus-trace
data via the H_HTM hypervisor call. The kernel-side HTM PMU driver
(submitted separately) streams this data into perf AUX buffers and emits
memory configuration as PERF_SAMPLE_RAW records.
This series wires up the record and report sides in the perf tool so that
'perf record' collects HTM data and 'perf report' writes the trace and
memory configuration to files ready for post-processing with htmdecoder.
Patch overview:
Patch 1 refactors the existing powerpc auxtrace dispatch. All VPA-DTL
recording logic is moved from arch/powerpc/util/auxtrace.c into its own
file, arch/powerpc/util/vpa-dtl.c, leaving auxtrace_record__init() as a
thin per-PMU dispatcher. This is a prerequisite for adding the HTM
recording path cleanly.
Patch 2 adds the HTM recording path (arch/powerpc/util/htm.c and
util/powerpc-htm.h). htm_recording_init() sets up the auxtrace_record
callbacks. htm_info_fill() stores the PMU type and a (cpu, attr.config)
pair for each htm evsel into the PERF_RECORD_AUXTRACE_INFO priv[] area.
The decode side reads these back to map each AUX buffer to its
(node, chip, core) target using event->auxtrace.cpu. PERF_SAMPLE_RAW is
also enabled here so that memory configuration records are captured
alongside the AUX stream.
Patch 3 adds a generic weak arch_perf_record__need_read() hook in
builtin-record.c. When the hook returns non-zero, perf record performs
an extra mmap-read pass before disabling events. The drain loop runs
until the hook returns 0 or no forward progress is made, then the events
are disabled and closed normally.
Patch 4 implements arch_perf_record__need_read() for powerpc. It reads
event->count for all open htm evsels via perf_evsel__read() and
accumulates the values. The kernel driver sets this count to 1 while
data is staged in its internal buffers and to 0 once the stream is
exhausted. A non-zero total causes the recording loop to perform another
read pass.
Patch 5 adds PERF_AUXTRACE_POWERPC_HTM to the auxtrace_type enum and
wires the dispatch in perf_event__process_auxtrace_info(). It also
amends htm_info_fill() to set auxtrace_info->type now that the constant
is available.
Patch 6 adds the full HTM decode path in util/powerpc-htm.c.
powerpc_htm_process_auxtrace_info() reads the (cpu, config) pairs from
priv[] and builds a cpu_configs[] lookup table. As each
PERF_RECORD_AUXTRACE event arrives, process_auxtrace_event() maps it to
the correct target and writes the data to htm.bin.nX.pX.cX immediately.
PERF_RECORD_SAMPLE RAW records are written to translation.nX.pX.cX by
process_event(). Per-run first-write tracking (htm_target_seen) ensures
O_TRUNC on the first write and O_APPEND on subsequent writes.
Patches not included in V2:
Three patches present in V1 are intentionally dropped from this series
and will be submitted as a follow-on once the core infrastructure gets
integrated:
- htmdecode integration: V1 patch 6 invoked the external htmdecode
tool via fork/exec after writing htm.bin.* to decode the raw
bus-trace data in-process. This is deferred because the interface
between perf and an external decode tool needs more discussion.
- Physical-to-logical address mapping: V1 patch 7 read the current
partition ID and parsed the translation.*
- Synthetic sample generation: V1 patches 8 and 9 created a
PERF_TYPE_SYNTH event named "htm", injected synthetic perf samples
Usage example:
Collect HTM trace data from a single chip target:
# perf record -C 9 -m,256 \
-e htm/nodalchipindex=2,nodeindex=0,htm_type=1/ sleep 3
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 256.277 MB perf.data ]
# perf report
Output files written by perf report:
htm.bin.n0.p2.c0 raw HTM bus-trace data
translation.n0.p2.c0 memory configuration records
Multiple targets can be collected simultaneously:
# perf record -m,256 \
-e htm/nodalchipindex=2,nodeindex=0,htm_type=1,cpu=8/ \
-e htm/nodalchipindex=1,nodeindex=0,htm_type=1,cpu=9/ \
-a sleep 10
Testing:
Tested on POWER10. Both htm.bin.* and translation.* files are produced
correctly for single and dual target collection.
Note: Link to kernel patches:
https://lore.kernel.org/linuxppc-dev/20260720104447.11843-1-atrajeev@linux.ibm.com/T/#t
Athira Rajeev (6):
tools/perf: Move powerpc VPA-DTL auxtrace init into a separate file
tools/perf: Add AUXTRACE recording support for powerpc HTM
tools/perf: Add arch hook to drain remaining data before event close
tools/perf: Add powerpc callback support for
arch_perf_record__need_read
tools/perf: Add powerpc HTM auxtrace event processing support
tools/perf: Add perf tool support for processing powerpc HTM AUXTRACE
records
tools/perf/arch/powerpc/util/Build | 2 +
tools/perf/arch/powerpc/util/auxtrace.c | 93 +-----
tools/perf/arch/powerpc/util/evsel.c | 69 ++++
tools/perf/arch/powerpc/util/htm.c | 169 ++++++++++
tools/perf/arch/powerpc/util/vpa-dtl.c | 95 ++++++
tools/perf/builtin-record.c | 45 +++
tools/perf/util/Build | 1 +
tools/perf/util/auxtrace.c | 4 +
tools/perf/util/auxtrace.h | 1 +
tools/perf/util/powerpc-htm.c | 415 ++++++++++++++++++++++++
tools/perf/util/powerpc-htm.h | 43 +++
tools/perf/util/powerpc-vpadtl.h | 1 +
tools/perf/util/record.h | 3 +
13 files changed, 865 insertions(+), 76 deletions(-)
create mode 100644 tools/perf/arch/powerpc/util/htm.c
create mode 100644 tools/perf/arch/powerpc/util/vpa-dtl.c
create mode 100644 tools/perf/util/powerpc-htm.c
create mode 100644 tools/perf/util/powerpc-htm.h
--
2.43.0
^ permalink raw reply
* [PATCH V2 2/6] tools/perf: Add AUXTRACE recording support for powerpc HTM
From: Athira Rajeev @ 2026-07-20 10:52 UTC (permalink / raw)
To: acme, jolsa, adrian.hunter, maddy, irogers, namhyung
Cc: linux-perf-users, linuxppc-dev, atrajeev, hbathini, tejas05,
tshah, venkat88, usha.r2
In-Reply-To: <20260720105218.14277-1-atrajeev@linux.ibm.com>
Add powerpc perf tool support for the HTM PMU AUXTRACE recording path.
Introduce htm_recording_init() and the associated auxtrace callbacks so
perf record can create PERF_RECORD_AUXTRACE records for HTM data.
htm_info_fill() stores the PMU type, number of HTM evsels, and a
(cpu, attr.config) pair for each evsel into PERF_RECORD_AUXTRACE_INFO
priv[]. The decode side reads these back to map each AUX buffer
(identified by event->auxtrace.cpu) to the correct (node, chip, core)
target when writing htm.bin.* output files.
Update auxtrace_record__init() to detect HTM events and dispatch to the
HTM-specific recording initializer.
Signed-off-by: Athira Rajeev <atrajeev@linux.ibm.com>
---
Changes in V2:
- htm_info_fill() now stores a (cpu, attr.config) pair for every HTM
evsel into PERF_RECORD_AUXTRACE_INFO priv[]. V1 stored only the PMU
type and a single config value; there was no per-CPU mapping.
- The priv[] layout is formalised in util/powerpc-htm.h with enum
constants POWERPC_HTM_PMU_TYPE, POWERPC_HTM_NUM_EVENTS, and
POWERPC_HTM_EVENT_DATA and the helper macros HTM_AUXTRACE_PRIV_FIXED
and HTM_AUXTRACE_PRIV_SIZE(n). V1 used bare numeric offsets.
- PERF_SAMPLE_RAW is enabled in the recording options so that memory
configuration records emitted by the kernel driver are captured
alongside the AUX stream. V1 added this in a later patch.
- PERF_AUXTRACE_POWERPC_HTM type constant is set in htm_info_fill()
(wired up in patch 5 once the enum is defined).
- Patch is now 2/6 instead of 2/9.
tools/perf/arch/powerpc/util/Build | 1 +
tools/perf/arch/powerpc/util/auxtrace.c | 9 ++
tools/perf/arch/powerpc/util/htm.c | 169 ++++++++++++++++++++++++
tools/perf/util/powerpc-htm.h | 43 ++++++
4 files changed, 222 insertions(+)
create mode 100644 tools/perf/arch/powerpc/util/htm.c
create mode 100644 tools/perf/util/powerpc-htm.h
diff --git a/tools/perf/arch/powerpc/util/Build b/tools/perf/arch/powerpc/util/Build
index 7819c8f5af2d..297152591046 100644
--- a/tools/perf/arch/powerpc/util/Build
+++ b/tools/perf/arch/powerpc/util/Build
@@ -8,3 +8,4 @@ perf-util-$(CONFIG_LIBDW) += skip-callchain-idx.o
perf-util-y += auxtrace.o
perf-util-y += vpa-dtl.o
+perf-util-y += htm.o
diff --git a/tools/perf/arch/powerpc/util/auxtrace.c b/tools/perf/arch/powerpc/util/auxtrace.c
index e04a0bd61755..fd9215e8d3f2 100644
--- a/tools/perf/arch/powerpc/util/auxtrace.c
+++ b/tools/perf/arch/powerpc/util/auxtrace.c
@@ -12,6 +12,7 @@
#include "../../util/debug.h"
#include "../../util/auxtrace.h"
#include "../../util/powerpc-vpadtl.h"
+#include "../../util/powerpc-htm.h"
#include "../../util/record.h"
struct auxtrace_record *auxtrace_record__init(struct evlist *evlist,
@@ -19,6 +20,7 @@ struct auxtrace_record *auxtrace_record__init(struct evlist *evlist,
{
struct evsel *pos;
struct evsel *vpa_dtl_evsel = NULL;
+ struct evsel *htm_evsel = NULL;
/*
* Set err value to zero here. Any fail later
@@ -32,11 +34,18 @@ struct auxtrace_record *auxtrace_record__init(struct evlist *evlist,
/* Remember the first matching VPA DTL event */
if (!vpa_dtl_evsel)
vpa_dtl_evsel = pos;
+ } else if (pos->name && strstarts(pos->name, "htm")) {
+ pos->needs_auxtrace_mmap = true;
+ /* Remember the first matching HTM event */
+ if (!htm_evsel)
+ htm_evsel = pos;
}
}
if (vpa_dtl_evsel)
return vpa_dtl_recording_init(vpa_dtl_evsel, err);
+ else if (htm_evsel)
+ return htm_recording_init(htm_evsel, err);
return NULL;
}
diff --git a/tools/perf/arch/powerpc/util/htm.c b/tools/perf/arch/powerpc/util/htm.c
new file mode 100644
index 000000000000..07b496e4be2f
--- /dev/null
+++ b/tools/perf/arch/powerpc/util/htm.c
@@ -0,0 +1,169 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * HTM AUX tracing support
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <stdlib.h>
+#include <limits.h>
+#include "../../util/evsel.h"
+#include "../../util/evlist.h"
+#include "../../util/session.h"
+#include "../../util/debug.h"
+#include "../../util/auxtrace.h"
+#include "../../util/powerpc-htm.h"
+#include "../../util/record.h"
+#include <internal/lib.h> /* page_size */
+#include <errno.h>
+
+#define KiB(x) ((x) * 1024)
+
+struct htm_recording {
+ struct auxtrace_record itr;
+ struct evsel *evsel;
+};
+
+static int
+htm_recording_options(struct auxtrace_record *itr __maybe_unused,
+ struct evlist *evlist,
+ struct record_opts *opts)
+{
+ struct evsel *pos;
+
+ opts->full_auxtrace = true;
+
+ if (!opts->auxtrace_mmap_pages) {
+ opts->auxtrace_mmap_pages = KiB(128) / page_size;
+ if (opts->mmap_pages == UINT_MAX)
+ opts->mmap_pages = KiB(256) / page_size;
+ }
+
+ evlist__for_each_entry(evlist, pos) {
+ if (!pos->name || !strstarts(pos->name, "htm"))
+ continue;
+ pos->core.attr.aux_watermark =
+ opts->auxtrace_mmap_pages * (size_t)page_size;
+ pos->core.attr.freq = 0;
+ pos->core.attr.sample_type |= PERF_SAMPLE_RAW;
+ pos->needs_auxtrace_mmap = true;
+ }
+
+ return 0;
+}
+
+/* Count htm evsels in the evlist */
+static int htm_nr_events(struct evlist *evlist)
+{
+ struct evsel *pos;
+ int n = 0;
+
+ evlist__for_each_entry(evlist, pos) {
+ if (pos->name && strstarts(pos->name, "htm"))
+ n++;
+ }
+ return n;
+}
+
+static size_t htm_info_priv_size(struct auxtrace_record *itr __maybe_unused,
+ struct evlist *evlist)
+{
+ return HTM_AUXTRACE_PRIV_SIZE(htm_nr_events(evlist));
+}
+
+/*
+ * Fill the PERF_RECORD_AUXTRACE_INFO private data with:
+ * priv[POWERPC_HTM_PMU_TYPE] = pmu->type of the first htm evsel
+ * priv[POWERPC_HTM_NUM_EVENTS] = number of htm evsels
+ * priv[POWERPC_HTM_EVENT_DATA + n*2] = CPU for nth htm evsel
+ * priv[POWERPC_HTM_EVENT_DATA + n*2 + 1] = attr.config for nth htm evsel
+ *
+ * The CPU is the first CPU in the evsel's cpu map; for events opened with
+ * cpu=N there is exactly one CPU. The decode side uses event->auxtrace.cpu
+ * to look up the matching config and derive (node, chip, core) for the
+ * output file name.
+ */
+static int
+htm_info_fill(struct auxtrace_record *itr,
+ struct perf_session *session,
+ struct perf_record_auxtrace_info *auxtrace_info,
+ size_t priv_size)
+{
+ struct htm_recording *htm_r = container_of(itr, struct htm_recording, itr);
+ struct evlist *evlist = session->evlist;
+ struct evsel *pos;
+ int n = 0;
+ int expected_n = htm_nr_events(evlist);
+
+ if (priv_size != HTM_AUXTRACE_PRIV_SIZE(expected_n))
+ return -EINVAL;
+
+ // To set: auxtrace_info->type
+ auxtrace_info->priv[POWERPC_HTM_PMU_TYPE] = htm_r->evsel->core.attr.type;
+ auxtrace_info->priv[POWERPC_HTM_NUM_EVENTS] = expected_n;
+
+ evlist__for_each_entry(evlist, pos) {
+ struct perf_cpu_map *cpus;
+ int cpu;
+
+ if (!pos->name || !strstarts(pos->name, "htm"))
+ continue;
+
+ /*
+ * Get the CPU this evsel is pinned to. For events opened
+ * with cpu=N, evsel__cpus() returns a single-entry map {N}
+ * at record time (not during replay).
+ */
+ cpus = evsel__cpus(pos);
+ if (cpus && perf_cpu_map__nr(cpus) > 0)
+ cpu = perf_cpu_map__cpu(cpus, 0).cpu;
+ else
+ cpu = -1;
+
+ auxtrace_info->priv[POWERPC_HTM_EVENT_DATA + n * 2] = cpu;
+ auxtrace_info->priv[POWERPC_HTM_EVENT_DATA + n * 2 + 1] =
+ pos->core.attr.config;
+ n++;
+ }
+
+ return 0;
+}
+
+static u64 htm_reference(struct auxtrace_record *itr __maybe_unused)
+{
+ return 0;
+}
+
+static void htm_free(struct auxtrace_record *itr)
+{
+ struct htm_recording *htm_r = container_of(itr, struct htm_recording, itr);
+
+ free(htm_r);
+}
+
+struct auxtrace_record *htm_recording_init(struct evsel *pos, int *err)
+{
+ struct htm_recording *htm_r;
+
+ /*
+ * To obtain the auxtrace buffer file descriptor, the auxtrace event
+ * must come first.
+ */
+ evlist__to_front(pos->evlist, pos);
+
+ htm_r = zalloc(sizeof(*htm_r));
+ if (!htm_r) {
+ pr_debug("htm_recording allocation failed (-ENOMEM)\n");
+ *err = -ENOMEM;
+ return NULL;
+ }
+
+ htm_r->evsel = pos;
+ htm_r->itr.recording_options = htm_recording_options;
+ htm_r->itr.info_priv_size = htm_info_priv_size;
+ htm_r->itr.info_fill = htm_info_fill;
+ htm_r->itr.free = htm_free;
+ htm_r->itr.reference = htm_reference;
+ return &htm_r->itr;
+}
diff --git a/tools/perf/util/powerpc-htm.h b/tools/perf/util/powerpc-htm.h
new file mode 100644
index 000000000000..18e39417d556
--- /dev/null
+++ b/tools/perf/util/powerpc-htm.h
@@ -0,0 +1,43 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __POWERPC_HTM_H
+#define __POWERPC_HTM_H
+
+#include <linux/types.h>
+
+/*
+ * Layout of the private data in PERF_RECORD_AUXTRACE_INFO for HTM.
+ *
+ * priv[POWERPC_HTM_PMU_TYPE] = htm PMU type ID (pmu->type from kernel)
+ * priv[POWERPC_HTM_NUM_EVENTS] = number of htm evsels recorded (N)
+ *
+ * Followed by N pairs (2 u64 each):
+ * priv[POWERPC_HTM_EVENT_DATA + n*2 + 0] = CPU number for nth htm evsel
+ * priv[POWERPC_HTM_EVENT_DATA + n*2 + 1] = attr.config for nth htm evsel
+ *
+ * Total priv entries: POWERPC_HTM_EVENT_DATA + N * 2
+ */
+enum {
+ POWERPC_HTM_PMU_TYPE = 0,
+ POWERPC_HTM_NUM_EVENTS,
+ POWERPC_HTM_EVENT_DATA, /* variable-length: 2 u64 per event */
+};
+
+/* Fixed header size (everything before the per-event data) */
+#define HTM_AUXTRACE_PRIV_FIXED (POWERPC_HTM_EVENT_DATA * sizeof(u64))
+
+/* Total priv size for N htm evsels */
+#define HTM_AUXTRACE_PRIV_SIZE(n) \
+ (HTM_AUXTRACE_PRIV_FIXED + (n) * 2 * sizeof(u64))
+
+struct evsel;
+struct evlist;
+union perf_event;
+struct perf_session;
+struct auxtrace_record;
+
+struct auxtrace_record *htm_recording_init(struct evsel *pos, int *err);
+
+int powerpc_htm_process_auxtrace_info(union perf_event *event,
+ struct perf_session *session);
+
+#endif /* __POWERPC_HTM_H */
--
2.43.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox