* Re: [PATCH v3 1/4] dt-bindings: iio: adc: mediatek,mt6359-auxadc: add mt6323 PMIC AUXADC
From: Conor Dooley @ 2026-06-16 15:41 UTC (permalink / raw)
To: rva333
Cc: Jonathan Cameron, David Lechner, Nuno Sá, Andy Shevchenko,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
AngeloGioacchino Del Regno, Lee Jones, linux-iio, devicetree,
linux-kernel, linux-arm-kernel, linux-mediatek, Ben Grisdale
In-Reply-To: <20260616-mt6323-adc-v3-1-1c27c588185d@protonmail.com>
[-- Attachment #1: Type: text/plain, Size: 864 bytes --]
On Tue, Jun 16, 2026 at 05:15:39PM +0300, Roman Vivchar via B4 Relay wrote:
> From: Roman Vivchar <rva333@protonmail.com>
>
> The MediaTek mt6323 PMIC includes an AUXADC used for battery voltage,
> temperature, and other internal measurements. The IP block is not
> register-compatible with mt6359
Cut this sentence here, whether or not it uses the same driver may
differ per OS.
Acked-by: Conor Dooley <conor.dooley@microchip.com>
pw-bot: not-applicable
>
> Add the devicetree binding documentation and the associated header file
> defining the ADC channel constants.
>
> Also change the description to 'MT6350 series and similar' because
> the binding already includes more than mt635x series PMICs.
>
> Finally, add the MAINTAINERS entry for the header with ADC constants.
>
> Signed-off-by: Roman Vivchar <rva333@protonmail.com>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply
* Re: [PATCH 3/9] firmware: imx: ele: Add API functions for OCOTP fuse access
From: Frank Li @ 2026-06-16 15:36 UTC (permalink / raw)
To: Frieder Schrempf
Cc: Srinivas Kandagatla, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Frank Li, Sascha Hauer, Pengutronix Kernel Team,
Fabio Estevam, Shawn Guo, devicetree, imx, linux-arm-kernel,
linux-kernel, Frieder Schrempf
In-Reply-To: <20260616-upstreaming-next-20260609-imx-ocotp-ele-v1-3-cb7f3698c3e6@kontron.de>
On Tue, Jun 16, 2026 at 01:52:18PM +0200, Frieder Schrempf wrote:
> From: Frieder Schrempf <frieder.schrempf@kontron.de>
>
> The ELE S400 API provides read and write access to the OCOTP fuse
> registers. This adds the necessary API functions imx_se_read_fuse()
> and imx_se_write_fuse() to be used by other drivers such as the
> OCOTP S400 NVMEM driver.
>
> This is ported from the downstream vendor kernel.
>
> Signed-off-by: Frieder Schrempf <frieder.schrempf@kontron.de>
> ---
> drivers/firmware/imx/ele_base_msg.c | 122 ++++++++++++++++++++++++++++++++++++
> drivers/firmware/imx/ele_base_msg.h | 6 ++
> include/linux/firmware/imx/se_api.h | 3 +
> 3 files changed, 131 insertions(+)
>
...
> +++ b/include/linux/firmware/imx/se_api.h
> @@ -11,4 +11,7 @@
> #define SOC_ID_OF_IMX8ULP 0x084d
> #define SOC_ID_OF_IMX93 0x9300
>
> +int imx_se_read_fuse(void *se_if_data, uint16_t fuse_id, u32 *value);
> +int imx_se_write_fuse(void *se_if_data, uint16_t fuse_id, u32 value);
> +
This API should implement in fuse drivers. Other consume should use standard
fuse API to get value. If put here, it may bypass fuse driver.
Frank
> #endif /* __SE_API_H__ */
>
> --
> 2.54.0
>
>
^ permalink raw reply
* Re: [PATCH v6 1/7] dt-bindings: mfd: mt6397: Add MT6392 PMIC
From: Conor Dooley @ 2026-06-16 15:35 UTC (permalink / raw)
To: Luca Leonardo Scorcia
Cc: linux-mediatek, Fabien Parent, Val Packett, Dmitry Torokhov,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Sen Chu,
Sean Wang, Macpaul Lin, Lee Jones, Matthias Brugger,
AngeloGioacchino Del Regno, Linus Walleij, Julien Massot,
Louis-Alexis Eyraud, Akari Tsuyukusa, Chen Zhong, linux-input,
devicetree, linux-kernel, linux-pm, linux-arm-kernel, linux-gpio
In-Reply-To: <CAORyz2+4EquYcUHEnoq0N_p7vCmDpPONEhVrmAfO1eX_RNMYbQ@mail.gmail.com>
[-- Attachment #1: Type: text/plain, Size: 1046 bytes --]
On Mon, Jun 15, 2026 at 07:09:39PM +0200, Luca Leonardo Scorcia wrote:
> Hi,
> yes, sorry about that, series v6 has been superseded by v7 (I replied
> to the thread and marked it as archived in patchwork, please let me
> know if I have to do something else to mark it as obsolete).
> Sashiko was correct, the regulators node is required for this device.
I have no idea what regulator node you're referring to here or what
patchwork. Please don't delete context when you reply.
If it's the devicetree patchwork I don't you need to do anything.
> Sashiko also has suggestions for v7, a few pre existing issues and a
> few nits here and there but some are actual improvements. One bit that
> caught my eye is the use of the modeset register in the
> mt6392_ldo_get_mode function. I have to double check that with the
> data sheet and the android kernel sources. Not sure if I can do that
> before next week though.
>
> Is there any way I can trigger a Sashiko review before sending patches
> to the ML?
I don't know sorry.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply
* Re: [PATCH v7 9/9] arm64: dts: mediatek: Add MediaTek MT6392 PMIC dtsi
From: Luca Leonardo Scorcia @ 2026-06-16 15:32 UTC (permalink / raw)
To: Rob Herring
Cc: linux-mediatek, Val Packett, Dmitry Torokhov, Krzysztof Kozlowski,
Conor Dooley, Sen Chu, Sean Wang, Macpaul Lin, Lee Jones,
Matthias Brugger, AngeloGioacchino Del Regno, Liam Girdwood,
Mark Brown, Linus Walleij, Louis-Alexis Eyraud, Julien Massot,
Fabien Parent, Akari Tsuyukusa, Chen Zhong, linux-input,
devicetree, linux-kernel, linux-pm, linux-arm-kernel, linux-gpio
In-Reply-To: <20260616133918.GA2335264-robh@kernel.org>
> > arch/arm64/boot/dts/mediatek/mt6392.dtsi | 75 ++++++++++++++++++++++++
>
> Nothing is using this so it is a dead file that doesn't get tested.
Hi, it's not referenced as the dtsi inclusion was removed in the
original patch from 2019 for an easier merging of support for mt8516
pumpkin boards [1][2].
If you prefer in the next revision I can add another patch to readd it
to the existing pumpkin board.
I am working on a few boards with MT8167 (Xiaomi Mi Smart Clock,
Lenovo Smart Clock 2, Sony Playstation Classic) that reference it and
these have been used to test it locally too.
[1] https://lore.kernel.org/linux-mediatek/20190323211612.860-25-fparent@baylibre.com/
[2] https://lore.kernel.org/linux-mediatek/20200229170401.1287324-2-fparent@baylibre.com/
Thank you
Luca
^ permalink raw reply
* Re: [PATCH RFC v8 01/24] mm: Introduce kpkeys
From: David Hildenbrand (Arm) @ 2026-06-16 15:32 UTC (permalink / raw)
To: Kevin Brodsky, Linus Walleij
Cc: linux-hardening, Andrew Morton, Andy Lutomirski, Catalin Marinas,
Dave Hansen, Ira Weiny, Jann Horn, Jeff Xu, Joey Gouly, Kees Cook,
Marc Zyngier, Mark Brown, Matthew Wilcox, Maxwell Bland,
Mike Rapoport (IBM), Peter Zijlstra, Pierre Langlois,
Quentin Perret, Rick Edgecombe, Ryan Roberts, Vlastimil Babka,
Will Deacon, Yang Shi, Yeoreum Yun, linux-arm-kernel, linux-mm,
x86, Lorenzo Stoakes, Thomas Gleixner
In-Reply-To: <b4eb4ea8-f4d6-4be2-81b1-4a8a46abe94e@arm.com>
>>> +static __always_inline u64 kpkeys_set_context(int ctx)
>> Should ctx be unsigned here? I'm nor sure what a negativ context
>> would mean.
>> kpkeys_set_context(unsigned int ctx)
>
> That's a good point, now that we say "context" and not "level" an enum
> would be a better representation. I would directly use:
>
> u64 kpkeys_set_context(enum kpkeys_ctx ctx);
>
> ... unless we really need another layer of abstraction.
Using an enum will also make it easier to just automatically update MIN and MAX
values. Although, arguably, you can just assume that MIN will always be 0.
enum kpkey_ctx {
KPKEY_CTX_DEFAULT = 0,
KPKEY_CTX_COUNT,
};
Then, just reject anything < 0 or >= KPKEY_CTX_COUNT.
--
Cheers,
David
^ permalink raw reply
* [PATCH v7 3/3] PCI: rockchip: drive at 2.5 GT/s, error other speeds
From: Geraldo Nascimento @ 2026-06-16 15:26 UTC (permalink / raw)
To: Shawn Lin, Dragan Simic
Cc: linux-rockchip, Lorenzo Pieralisi, Krzysztof Wilczyński,
Manivannan Sadhasivam, Rob Herring, Bjorn Helgaas, linux-pci,
linux-arm-kernel, linux-kernel, Geraldo Nascimento
In-Reply-To: <cover.1781622998.git.geraldogabriel@gmail.com>
Configure the core to be driven at 2.5 GT/s Link Speed and ignore
any other speed with a warning. Also drop the 5.0 GT/s Link Speed
defines from Rockchip PCIe header.
The reason is that Shawn Lin from Rockchip has reiterated that there
may be danger of "catastrophic failure" in using their PCIe with
5.0 GT/s speeds.
While Rockchip has done so informally without issuing a proper errata,
and the particulars are thus unknown, this may cause data loss or
worse.
This change is corroborated by RK3399 official datasheet [1], which
states maximum link speed for this platform is 2.5 GT/s.
[1] https://opensource.rock-chips.com/images/d/d7/Rockchip_RK3399_Datasheet_V2.1-20200323.pdf
Fixes: 956cd99b35a8 ("PCI: rockchip: Separate common code from RC driver")
Link: https://lore.kernel.org/all/ffd05070-9879-4468-94e3-b88968b4c21b@rock-chips.com/
Cc: stable@vger.kernel.org
Reported-by: Dragan Simic <dsimic@manjaro.org>
Reported-by: Shawn Lin <shawn.lin@rock-chips.com>
Signed-off-by: Geraldo Nascimento <geraldogabriel@gmail.com>
---
drivers/pci/controller/pcie-rockchip.c | 14 ++++++--------
drivers/pci/controller/pcie-rockchip.h | 3 ---
2 files changed, 6 insertions(+), 11 deletions(-)
diff --git a/drivers/pci/controller/pcie-rockchip.c b/drivers/pci/controller/pcie-rockchip.c
index 0f88da3788054..456dcfd676ed7 100644
--- a/drivers/pci/controller/pcie-rockchip.c
+++ b/drivers/pci/controller/pcie-rockchip.c
@@ -66,8 +66,10 @@ int rockchip_pcie_parse_dt(struct rockchip_pcie *rockchip)
}
rockchip->link_gen = of_pci_get_max_link_speed(node);
- if (rockchip->link_gen < 0 || rockchip->link_gen > 2)
- rockchip->link_gen = 2;
+ if (rockchip->link_gen < 0 || rockchip->link_gen >= 2) {
+ rockchip->link_gen = 1;
+ dev_warn(dev, "invalid max-link-speed, limited to 2.5 GT/s\n");
+ }
for (i = 0; i < ROCKCHIP_NUM_PM_RSTS; i++)
rockchip->pm_rsts[i].id = rockchip_pci_pm_rsts[i];
@@ -147,12 +149,8 @@ int rockchip_pcie_init_port(struct rockchip_pcie *rockchip)
goto err_exit_phy;
}
- if (rockchip->link_gen == 2)
- rockchip_pcie_write(rockchip, PCIE_CLIENT_GEN_SEL_2,
- PCIE_CLIENT_CONFIG);
- else
- rockchip_pcie_write(rockchip, PCIE_CLIENT_GEN_SEL_1,
- PCIE_CLIENT_CONFIG);
+ rockchip_pcie_write(rockchip, PCIE_CLIENT_GEN_SEL_1,
+ PCIE_CLIENT_CONFIG);
regs = PCIE_CLIENT_ARI_ENABLE |
PCIE_CLIENT_CONF_LANE_NUM(rockchip->lanes);
diff --git a/drivers/pci/controller/pcie-rockchip.h b/drivers/pci/controller/pcie-rockchip.h
index 3e82a69b9c006..b5da15601b585 100644
--- a/drivers/pci/controller/pcie-rockchip.h
+++ b/drivers/pci/controller/pcie-rockchip.h
@@ -42,7 +42,6 @@
#define PCIE_CLIENT_MODE_RC HWORD_SET_BIT(0x0040)
#define PCIE_CLIENT_MODE_EP HWORD_CLR_BIT(0x0040)
#define PCIE_CLIENT_GEN_SEL_1 HWORD_CLR_BIT(0x0080)
-#define PCIE_CLIENT_GEN_SEL_2 HWORD_SET_BIT(0x0080)
#define PCIE_CLIENT_LEGACY_INT_CTRL (PCIE_CLIENT_BASE + 0x0c)
#define PCIE_CLIENT_INT_IN_ASSERT HWORD_SET_BIT(0x0002)
#define PCIE_CLIENT_INT_IN_DEASSERT HWORD_CLR_BIT(0x0002)
@@ -197,8 +196,6 @@
(((x) & PCIE_CORE_PL_CONF_LS_MASK) == PCIE_CORE_PL_CONF_LS_READY)
#define PCIE_LINK_UP(x) \
(((x) & PCIE_CLIENT_LINK_STATUS_MASK) == PCIE_CLIENT_LINK_STATUS_UP)
-#define PCIE_LINK_IS_GEN2(x) \
- (((x) & PCIE_CORE_PL_CONF_SPEED_MASK) == PCIE_CORE_PL_CONF_SPEED_5G)
#define RC_REGION_0_ADDR_TRANS_H 0x00000000
#define RC_REGION_0_ADDR_TRANS_L 0x00000000
--
2.54.0
^ permalink raw reply related
* [PATCH v7 2/3] PCI: rockchip-host: do not attempt 5.0 GT/s retraining
From: Geraldo Nascimento @ 2026-06-16 15:25 UTC (permalink / raw)
To: Shawn Lin, Dragan Simic
Cc: linux-rockchip, Lorenzo Pieralisi, Krzysztof Wilczyński,
Manivannan Sadhasivam, Rob Herring, Bjorn Helgaas, linux-pci,
linux-arm-kernel, linux-kernel, Geraldo Nascimento
In-Reply-To: <cover.1781622998.git.geraldogabriel@gmail.com>
Drop the 5.0 GT/s Link Speed retraining from Rockchip PCIe Root
Complex Mode Operation, so called host driver.
The reason is that Shawn Lin from Rockchip has reiterated that there
may be danger of "catastrophic failure" in using their PCIe with
5.0GT/s speeds.
While Rockchip has done so informally without issuing a proper errata,
and the particulars are thus unknown, this may cause data loss or
worse.
This change is corroborated by RK3399 official datasheet [1], which
states maximum link speed for this platform is 2.5 GT/s.
[1] https://opensource.rock-chips.com/images/d/d7/Rockchip_RK3399_Datasheet_V2.1-20200323.pdf
Link: https://lore.kernel.org/all/ffd05070-9879-4468-94e3-b88968b4c21b@rock-chips.com/
Cc: stable@vger.kernel.org
Reported-by: Dragan Simic <dsimic@manjaro.org>
Reported-by: Shawn Lin <shawn.lin@rock-chips.com>
Signed-off-by: Geraldo Nascimento <geraldogabriel@gmail.com>
---
drivers/pci/controller/pcie-rockchip-host.c | 20 --------------------
1 file changed, 20 deletions(-)
diff --git a/drivers/pci/controller/pcie-rockchip-host.c b/drivers/pci/controller/pcie-rockchip-host.c
index ee1822ca01db3..1374a2c92b563 100644
--- a/drivers/pci/controller/pcie-rockchip-host.c
+++ b/drivers/pci/controller/pcie-rockchip-host.c
@@ -328,26 +328,6 @@ static int rockchip_pcie_host_init_port(struct rockchip_pcie *rockchip)
goto err_power_off_phy;
}
- if (rockchip->link_gen == 2) {
- /*
- * Enable retrain for gen2. This should be configured only after
- * gen1 finished.
- */
- status = rockchip_pcie_read(rockchip, PCIE_RC_CONFIG_CR + PCI_EXP_LNKCTL2);
- status &= ~PCI_EXP_LNKCTL2_TLS;
- status |= PCI_EXP_LNKCTL2_TLS_5_0GT;
- rockchip_pcie_write(rockchip, status, PCIE_RC_CONFIG_CR + PCI_EXP_LNKCTL2);
- status = rockchip_pcie_read(rockchip, PCIE_RC_CONFIG_CR + PCI_EXP_LNKCTL);
- status |= PCI_EXP_LNKCTL_RL;
- rockchip_pcie_write(rockchip, status, PCIE_RC_CONFIG_CR + PCI_EXP_LNKCTL);
-
- err = readl_poll_timeout(rockchip->apb_base + PCIE_CORE_CTRL,
- status, PCIE_LINK_IS_GEN2(status), 20,
- 500 * USEC_PER_MSEC);
- if (err)
- dev_dbg(dev, "PCIe link training gen2 timeout, fall back to gen1!\n");
- }
-
/* Check the final link width from negotiated lane counter from MGMT */
status = rockchip_pcie_read(rockchip, PCIE_CORE_CTRL);
status = 0x1 << ((status & PCIE_CORE_PL_CONF_LANE_MASK) >>
--
2.54.0
^ permalink raw reply related
* [PATCH v7 1/3] PCI: rockchip-ep: do not attempt 5.0 GT/s retraining
From: Geraldo Nascimento @ 2026-06-16 15:25 UTC (permalink / raw)
To: Shawn Lin, Dragan Simic
Cc: linux-rockchip, Lorenzo Pieralisi, Krzysztof Wilczyński,
Manivannan Sadhasivam, Rob Herring, Bjorn Helgaas, linux-pci,
linux-arm-kernel, linux-kernel, Geraldo Nascimento
In-Reply-To: <cover.1781622998.git.geraldogabriel@gmail.com>
Drop the 5.0 GT/s Link Speed retraining code block from Rockchip PCIe
EP driver. The reason is that Shawn Lin from Rockchip has reiterated
that there may be danger of "catastrophic failure" in using their PCIe
with 5.0 GT/s speeds.
While Rockchip has done so informally without issuing a proper errata,
and the particulars are thus unknown, this may cause data loss or
worse.
This change is corroborated by RK3399 official datasheet [1], which
states maximum link speed for this platform is 2.5 GT/s.
[1] https://opensource.rock-chips.com/images/d/d7/Rockchip_RK3399_Datasheet_V2.1-20200323.pdf
Link: https://lore.kernel.org/all/ffd05070-9879-4468-94e3-b88968b4c21b@rock-chips.com/
Cc: stable@vger.kernel.org
Reported-by: Dragan Simic <dsimic@manjaro.org>
Reported-by: Shawn Lin <shawn.lin@rock-chips.com>
Signed-off-by: Geraldo Nascimento <geraldogabriel@gmail.com>
---
drivers/pci/controller/pcie-rockchip-ep.c | 13 -------------
1 file changed, 13 deletions(-)
diff --git a/drivers/pci/controller/pcie-rockchip-ep.c b/drivers/pci/controller/pcie-rockchip-ep.c
index 799461335762e..9ebc227a1ef84 100644
--- a/drivers/pci/controller/pcie-rockchip-ep.c
+++ b/drivers/pci/controller/pcie-rockchip-ep.c
@@ -553,19 +553,6 @@ static void rockchip_pcie_ep_link_training(struct work_struct *work)
if (ret)
goto again;
- /*
- * Check the current speed: if gen2 speed was requested and we are not
- * at gen2 speed yet, retrain again for gen2.
- */
- val = rockchip_pcie_read(rockchip, PCIE_CORE_CTRL);
- if (!PCIE_LINK_IS_GEN2(val) && rockchip->link_gen == 2) {
- /* Enable retrain for gen2 */
- rockchip_pcie_ep_retrain_link(rockchip);
- readl_poll_timeout(rockchip->apb_base + PCIE_CORE_CTRL,
- val, PCIE_LINK_IS_GEN2(val), 50,
- LINK_TRAIN_TIMEOUT);
- }
-
/* Check again that the link is up */
if (!rockchip_pcie_ep_link_up(rockchip))
goto again;
--
2.54.0
^ permalink raw reply related
* [PATCH v7 0/3] PCI: rockchip: 5.0 GT/s speed discouraged by Rockchip
From: Geraldo Nascimento @ 2026-06-16 15:24 UTC (permalink / raw)
To: Shawn Lin, Dragan Simic
Cc: linux-rockchip, Lorenzo Pieralisi, Krzysztof Wilczyński,
Manivannan Sadhasivam, Rob Herring, Bjorn Helgaas, linux-pci,
linux-arm-kernel, linux-kernel, Geraldo Nascimento
Dragan Simic already had warned me of potential issues with 5.0 GT/s
speed operation in Rockchip PCIe. However, in recent interactions
with Shawn Lin from Rockchip it came to my attention there's grave
danger in the unknown errata regarding 5.0 GT/s operational speed
of their PCIe core, including data loss.
Drop all code related to 5.0 GT/s operational speed from this driver.
Endpoint Mode driver was not tested.
Changes in v7:
- In pcie-rockchip.c (PATCH 3) drop unreachable code
- Link to v6: https://lore.kernel.org/all/cover.1781207474.git.geraldogabriel@gmail.com/T/
Changes in v6:
- Squashed patches 3 & 4 together as suggested by Mani
- More formal warning message as suggested by Dragan
- Set the 2.5 GT/s bit regardless of if link-speed is set to 2
- Link to v5: https://lore.kernel.org/all/cover.1772239598.git.geraldogabriel@gmail.com/T/
Changes in v5:
- Changed commit order to not break builds and adjusted copy pasted
commit message. (thanks Charalampos!)
- Reintroduced behavior to force 2.5 GT/s in case there's something
non-default in the DT. (thanks Dragan!)
- Link to v4: https://lore.kernel.org/linux-rockchip/cover.1772169998.git.geraldogabriel@gmail.com/T/
Changes in v4:
- Incorporate suggestion by Bjorn and refined by Dragan to drop the
"catastrophic" code
- Link to v3: https://lore.kernel.org/linux-rockchip/cover.1772057799.git.geraldogabriel@gmail.com/T/
Changes in v3:
- Clarify warning message even though Rockchip won't disclose details
- Drop DT changes as they were applied as subset by Heiko
- Link to v2: https://lore.kernel.org/all/cover.1763415705.git.geraldogabriel@gmail.com/T/
Changes in v2:
- hard limit to 2.5 GT/s, not just warn
- add Reported-by: and Reviewed-by: Dragan Simic
- remove redundant declaration of max-link-speed from helios64 dts
- fix Link: of helios64 patch
- simplify RC mode comment
- Link to v1: https://lore.kernel.org/all/aRhR79u5BPtRRFw3@geday/T/
Geraldo Nascimento (3):
PCI: rockchip-ep: do not attempt 5.0 GT/s retraining
PCI: rockchip-host: do not attempt 5.0 GT/s retraining
PCI: rockchip: drive at 2.5 GT/s, error other speeds
drivers/pci/controller/pcie-rockchip-ep.c | 13 -------------
drivers/pci/controller/pcie-rockchip-host.c | 20 --------------------
drivers/pci/controller/pcie-rockchip.c | 14 ++++++--------
drivers/pci/controller/pcie-rockchip.h | 3 ---
4 files changed, 6 insertions(+), 44 deletions(-)
--
2.54.0
^ permalink raw reply
* Re: [PATCH net 4/4] net: ti: icssg: Fix XSK zero copy TX during application wakeup
From: Jakub Kicinski @ 2026-06-16 15:19 UTC (permalink / raw)
To: Meghana Malladi
Cc: diogo.ivo, haokexin, vadim.fedorenko, devnexen, horms,
jacob.e.keller, sdf, john.fastabend, hawk, daniel, ast, pabeni,
edumazet, davem, andrew+netdev, bpf, linux-kernel, netdev,
linux-arm-kernel, srk, Vignesh Raghavendra, Roger Quadros,
danishanwar
In-Reply-To: <ed0bc332-0196-4613-8066-9b94f8ed0013@ti.com>
On Tue, 16 Jun 2026 16:41:00 +0530 Meghana Malladi wrote:
> On 6/16/26 04:51, Jakub Kicinski wrote:
> > On Fri, 12 Jun 2026 00:27:44 +0530 Meghana Malladi wrote:
> >> @@ -169,9 +169,6 @@ static int emac_xsk_xmit_zc(struct prueth_emac *emac,
> >>
> >> num_tx++;
> >> }
> >> -
> >> - xsk_tx_release(tx_chn->xsk_pool);
> >> - return num_tx;
> >
> > Why are you deleting this?
> >
>
> xsk_sendmsg() also calls this without an rcu-lock when transmitting the
> packets if the xmit was successful, so I was assuming it is not required
> and I removed this.
I think you still need it. Besides, seems like a separate cleanup.
> >> void prueth_xmit_free(struct prueth_tx_chn *tx_chn,
> >> @@ -279,9 +276,6 @@ int emac_tx_complete_packets(struct prueth_emac *emac, int chn,
> >> num_tx++;
> >> }
> >>
> >> - if (!num_tx)
> >> - return 0;
> >
> > Does something prevent us from running all this code if budget is 0?
> > If budget is 0 we can complete normal Tx with skbs but we must
> > not touch any AF-XDP related state.
>
> Can you elaborate more, I couldn't interpret your comment here
netpoll may call napi from any context, including from IRQ.
It uses budget of 0 to indicate that it's trying to only reap tx
completions, without doing any Rx or XDP work. XDPs can't be called
from IRQ context.
> >> netif_txq = netdev_get_tx_queue(ndev, chn);
> >> netdev_tx_completed_queue(netif_txq, num_tx, total_bytes);
> >>
> >> @@ -306,7 +300,9 @@ int emac_tx_complete_packets(struct prueth_emac *emac, int chn,
> >>
> >> netif_txq = netdev_get_tx_queue(ndev, chn);
> >> txq_trans_cond_update(netif_txq);
> >
> > This looks misplaced, now we will hit it even if we didn't complete
> > or submit any Tx.
>
> This code needs to be hit for packet transmission in zero copy mode.
> emac_xsk_xmit_zc() submits the packets to the DMA in NAPI context,
> when application wakes up the driver and triggers NAPI. Once DMA
> transfer is done, irq gets triggered NAPI gets called which will handle
> the tx packet completion + submit next Tx batch packets to the DMA.
>
> if (tx_chn->xsk_pool) -> check ensure this hits and runs for zero copy
> only. Also above check (!num_tx) returns early during the application
> wakeup (where budget is zero), hence it is removed.
I'm commenting on txq_trans_cond_update(), you're calling it
effectively on every NAPI call when XSK is bound, whether
Tx is making progress or not.
^ permalink raw reply
* Re: [PATCH RFC v8 01/24] mm: Introduce kpkeys
From: David Hildenbrand (Arm) @ 2026-06-16 15:19 UTC (permalink / raw)
To: Kevin Brodsky, linux-hardening
Cc: Andrew Morton, Andy Lutomirski, Catalin Marinas, Dave Hansen,
Ira Weiny, Jann Horn, Jeff Xu, Joey Gouly, Kees Cook,
Linus Walleij, Marc Zyngier, Mark Brown, Matthew Wilcox,
Maxwell Bland, Mike Rapoport (IBM), Peter Zijlstra,
Pierre Langlois, Quentin Perret, Rick Edgecombe, Ryan Roberts,
Vlastimil Babka, Will Deacon, Yang Shi, Yeoreum Yun,
linux-arm-kernel, linux-mm, x86, Lorenzo Stoakes, Thomas Gleixner
In-Reply-To: <20260526-kpkeys-v8-1-eaaacdacc67c@arm.com>
On 5/26/26 13:15, Kevin Brodsky wrote:
> kpkeys is a simple framework to enable the use of protection keys
> (pkeys) to harden the kernel itself. This patch introduces the basic
> API in <linux/kpkeys.h>: a couple of functions to set and restore
> the pkey register and macros to define guard objects.
>
> kpkeys introduces a new concept on top of pkeys: the kpkeys context.
> Each context is associated to a set of permissions for the pkeys
> managed by the kpkeys framework. kpkeys_set_context(ctx) sets those
> permissions according to ctx, and returns the original pkey
> register, to be later restored by kpkeys_restore_pkey_reg(). To
> start with, only KPKEYS_CTX_DEFAULT is available, which is meant to
> grant RW access to KPKEYS_PKEY_DEFAULT (i.e. all memory since this
> is the only available pkey for now).
>
> Because each architecture implementing pkeys uses a different
> representation for the pkey register, and may reserve certain pkeys
> for specific uses, support for kpkeys must be explicitly indicated
> by selecting ARCH_HAS_KPKEYS and defining the following functions in
> <asm/kpkeys.h>, in addition to the macros provided in
> <asm-generic/kpkeys.h>:
>
> - arch_kpkeys_set_context()
> - arch_kpkeys_restore_pkey_reg()
Looking at this, and wondering about "why do we get registers involved in this
API" I would probably have an interface like:
arch_kpkeys_enter_context()
arch_kpkeys_leave_context()
Whereby you return a "struct kpkeys_state" or sth like that.
You could either let the architecture define what's in the state, or
alternatively store some generic data in there as well.
struct kpkeys_state {
bool entered_context;
struct arch_pkey_state arch;
};
Maybe the "entered_context" or however you would want to call it could avoid the
KPKEYS_PKEY_REG_INVAL (which confuses me ;) )?
But the KPKEYS_PKEY_REG_INVAL usage confuses me. I understand the
KPKEYS_GUARD_COND + kpkeys_restore_pkey_reg() one, but not the one where
arch_kpkeys_set_context() would return that value.
>
> Signed-off-by: Kevin Brodsky <kevin.brodsky@arm.com>
> ---
> include/asm-generic/kpkeys.h | 17 ++++++
> include/linux/kpkeys.h | 122 +++++++++++++++++++++++++++++++++++++++++++
> mm/Kconfig | 2 +
> 3 files changed, 141 insertions(+)
>
> diff --git a/include/asm-generic/kpkeys.h b/include/asm-generic/kpkeys.h
> new file mode 100644
> index 000000000000..ab819f157d6a
> --- /dev/null
> +++ b/include/asm-generic/kpkeys.h
> @@ -0,0 +1,17 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +#ifndef __ASM_GENERIC_KPKEYS_H
> +#define __ASM_GENERIC_KPKEYS_H
> +
> +#ifndef KPKEYS_PKEY_DEFAULT
> +#define KPKEYS_PKEY_DEFAULT 0
> +#endif
Do we currently expect an architecture to overwrite this? How does this interact
with KPKEYS_CTX_DEFAULT?
Nobody in this patch uses it, so maybe it should be added where actually needed.
> +
> +/*
> + * Represents a pkey register value that cannot be used, typically disabling
> + * access to all keys.
> + */
> +#ifndef KPKEYS_PKEY_REG_INVAL
> +#define KPKEYS_PKEY_REG_INVAL 0
> +#endif
> +
> +#endif /* __ASM_GENERIC_KPKEYS_H */
> diff --git a/include/linux/kpkeys.h b/include/linux/kpkeys.h
> new file mode 100644
> index 000000000000..0ce0db80b4ee
> --- /dev/null
> +++ b/include/linux/kpkeys.h
> @@ -0,0 +1,122 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +#ifndef _LINUX_KPKEYS_H
> +#define _LINUX_KPKEYS_H
> +
> +#include <linux/bug.h>
> +#include <linux/cleanup.h>
> +
> +#define KPKEYS_CTX_DEFAULT 0
Agreed with enum.
> +
> +#define KPKEYS_CTX_MIN KPKEYS_CTX_DEFAULT
> +#define KPKEYS_CTX_MAX KPKEYS_CTX_DEFAULT
> +
> +/*
> + * ... is used to discard extra arguments - this allows users of this macro
> + * to have set_arg default to void.
> + */
> +#define __KPKEYS_GUARD(name, set_context, restore_pkey_reg, set_arg, ...) \
> + __DEFINE_CLASS_IS_CONDITIONAL(name, false); \
> + DEFINE_CLASS(name, u64, \
> + restore_pkey_reg, set_context, set_arg); \
> + static inline void *class_##name##_lock_ptr(u64 *_T) \
> + { return _T; }
> +
> +/**
> + * KPKEYS_GUARD_NOOP() - define a guard type that does nothing
> + * @name: the name of the guard type
> + * @cond_arg: an argument specification (optional)
> + *
> + * Define a guard type that does nothing, useful to match a real guard type
> + * that is defined under an #ifdef. @cond_arg may optionally be passed to match
> + * a guard defined using KPKEYS_GUARD_COND().
> + */
> +#define KPKEYS_GUARD_NOOP(name, ...) \
> + __KPKEYS_GUARD(name, 0, (void)_T, ##__VA_ARGS__, void)
> +
> +#ifdef CONFIG_ARCH_HAS_KPKEYS
> +
> +#include <asm/kpkeys.h>
> +
> +/**
> + * KPKEYS_GUARD_COND() - define a guard type that conditionally switches to
> + * a given kpkeys context
> + * @name: the name of the guard type
> + * @ctx: the kpkeys context to switch to
> + * @cond: an expression that is evaluated as condition
> + * @cond_arg: an argument specification for the condition (optional)
> + *
> + * Define a guard type that switches to @ctx if @cond evaluates to true,
> + * and does nothing otherwise. @cond_arg may be specified to give access to a
> + * caller-defined argument to @cond.
> + */
> +#define KPKEYS_GUARD_COND(name, ctx, cond, ...) \
> + __KPKEYS_GUARD(name, \
> + (cond) ? kpkeys_set_context(ctx) \
> + : KPKEYS_PKEY_REG_INVAL, \
> + kpkeys_restore_pkey_reg(_T), \
> + ##__VA_ARGS__, void)
> +
> +/**
> + * KPKEYS_GUARD() - define a guard type that switches to a given kpkeys context
> + * if kpkeys are enabled
> + * @name: the name of the guard type
> + * @ctx: the kpkeys context to switch to
> + *
> + * Define a guard type that switches to @ctx if the system supports kpkeys.
> + */
> +#define KPKEYS_GUARD(name, ctx) \
> + KPKEYS_GUARD_COND(name, ctx, kpkeys_enabled())
> +
> +/**
> + * kpkeys_set_context() - switch kpkeys context
> + * @ctx: the context to switch to
> + *
> + * Switches to specified kpkeys context. @ctx must be a compile-time
> + * constant. The arch-specific pkey register will be updated accordingly, and
> + * the original value returned.
Are these arch details and registers relevant? Ideally, we'd keep it very simple
here ...
> + *
> + * Return: the original pkey register value if the register was written to, or
> + * KPKEYS_PKEY_REG_INVAL otherwise (no write to the register was
> + * required).
... and here. Not sure if any caller cares about these details. Again, with some
abstract state we could maybe handle that internally.
"Return: the pkey state to pass to kpkeys_restore_pkey_reg" (or however that
function will be called)
> + */
> +static __always_inline u64 kpkeys_set_context(int ctx)
> +{
> + BUILD_BUG_ON_MSG(!__builtin_constant_p(ctx),
> + "kpkeys_set_context() only takes constant values");
> + BUILD_BUG_ON_MSG(ctx < KPKEYS_CTX_MIN || ctx > KPKEYS_CTX_MAX,
> + "Invalid value passed to kpkeys_set_context()");
> +
> + return arch_kpkeys_set_context(ctx);
> +}
> +
> +/**
> + * kpkeys_restore_pkey_reg() - restores a pkey register value
> + * @pkey_reg: the pkey register value to restore
> + *
> + * This function is meant to be passed the value returned by
> + * kpkeys_set_context(), in order to restore the pkey register to its original
> + * value (thus restoring the original kpkeys context).
> + */
> +static __always_inline void kpkeys_restore_pkey_reg(u64 pkey_reg)
> +{
> + if (pkey_reg != KPKEYS_PKEY_REG_INVAL)
> + arch_kpkeys_restore_pkey_reg(pkey_reg);
> +}
> +
> +static inline bool kpkeys_enabled(void)
Is the enabled vs. supported intentional?
> +{
> + return arch_supports_kpkeys();
> +}
> +
--
Cheers,
David
^ permalink raw reply
* [PATCH] memory: atmel-ebi: unwind SMC clock on probe failures
From: Pengpeng Hou @ 2026-06-16 15:17 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: Nicolas Ferre, Alexandre Belloni, Claudiu Beznea, linux-kernel,
linux-arm-kernel, Pengpeng Hou
atmel_ebi_probe() obtains the SMC clock with of_clk_get() and enables it
before several later validation and child setup steps. Those later
failures currently return directly, leaving the non-managed SMC clock
enabled and referenced.
Route the post-enable failures through common cleanup labels, put the SMC
clock on enable failure, and depopulate any partially created children if
the final child population fails.
Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
---
drivers/memory/atmel-ebi.c | 28 +++++++++++++++++++++-------
1 file changed, 21 insertions(+), 7 deletions(-)
diff --git a/drivers/memory/atmel-ebi.c b/drivers/memory/atmel-ebi.c
index 1e8e8aba2542..f331eed362c5 100644
--- a/drivers/memory/atmel-ebi.c
+++ b/drivers/memory/atmel-ebi.c
@@ -562,7 +562,7 @@ static int atmel_ebi_probe(struct platform_device *pdev)
}
ret = clk_prepare_enable(ebi->smc.clk);
if (ret)
- return ret;
+ goto err_put_smc_clk;
/*
* The sama5d3 does not provide an EBICSA register and thus does need
@@ -572,14 +572,16 @@ static int atmel_ebi_probe(struct platform_device *pdev)
ebi->regmap =
syscon_regmap_lookup_by_phandle(np,
ebi->caps->regmap_name);
- if (IS_ERR(ebi->regmap))
- return PTR_ERR(ebi->regmap);
+ if (IS_ERR(ebi->regmap)) {
+ ret = PTR_ERR(ebi->regmap);
+ goto err_disable_smc_clk;
+ }
}
ret = of_property_read_u32(np, "#address-cells", &val);
if (ret) {
dev_err(dev, "missing #address-cells property\n");
- return ret;
+ goto err_disable_smc_clk;
}
reg_cells = val;
@@ -587,7 +589,7 @@ static int atmel_ebi_probe(struct platform_device *pdev)
ret = of_property_read_u32(np, "#size-cells", &val);
if (ret) {
dev_err(dev, "missing #address-cells property\n");
- return ret;
+ goto err_disable_smc_clk;
}
reg_cells += val;
@@ -603,11 +605,23 @@ static int atmel_ebi_probe(struct platform_device *pdev)
ret = atmel_ebi_dev_disable(ebi, child);
if (ret)
- return ret;
+ goto err_disable_smc_clk;
}
}
- return of_platform_populate(np, NULL, NULL, dev);
+ ret = of_platform_populate(np, NULL, NULL, dev);
+ if (ret) {
+ of_platform_depopulate(dev);
+ goto err_disable_smc_clk;
+ }
+
+ return 0;
+
+err_disable_smc_clk:
+ clk_disable_unprepare(ebi->smc.clk);
+err_put_smc_clk:
+ clk_put(ebi->smc.clk);
+ return ret;
}
static __maybe_unused int atmel_ebi_resume(struct device *dev)
--
2.43.0
^ permalink raw reply related
* [PATCH] bus: stm32_rifsc: clean up debugfs file with device state
From: Pengpeng Hou @ 2026-06-16 15:16 UTC (permalink / raw)
To: Gatien Chevallier
Cc: Maxime Coquelin, Alexandre Torgue, linux-stm32, linux-arm-kernel,
linux-kernel, Pengpeng Hou
stm32_rifsc_register_debugfs() creates a debugfs file whose private data
is devm-allocated RIFSC debug state. If a later probe step fails, or if
the device is removed, that debugfs file can outlive the private data it
dereferences.
Keep the created dentry and register a devm cleanup action so the file is
removed before the RIFSC state is released.
Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
---
drivers/bus/stm32_rifsc.c | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)
diff --git a/drivers/bus/stm32_rifsc.c b/drivers/bus/stm32_rifsc.c
index 19d10379dcef..3877198e6eb9 100644
--- a/drivers/bus/stm32_rifsc.c
+++ b/drivers/bus/stm32_rifsc.c
@@ -602,11 +602,17 @@ static int stm32_rifsc_conf_dump_show(struct seq_file *s, void *data)
}
DEFINE_SHOW_ATTRIBUTE(stm32_rifsc_conf_dump);
+static void stm32_rifsc_remove_debugfs(void *data)
+{
+ debugfs_remove(data);
+}
+
static int stm32_rifsc_register_debugfs(struct stm32_firewall_controller *rifsc_controller,
u32 nb_risup, u32 nb_rimu, u32 nb_risal)
{
struct rifsc_dbg_private *rifsc_priv;
struct dentry *root = NULL;
+ struct dentry *file;
rifsc_priv = devm_kzalloc(rifsc_controller->dev, sizeof(*rifsc_priv), GFP_KERNEL);
if (!rifsc_priv)
@@ -625,9 +631,13 @@ static int stm32_rifsc_register_debugfs(struct stm32_firewall_controller *rifsc_
if (IS_ERR(root))
return PTR_ERR(root);
- debugfs_create_file("rifsc", 0444, root, rifsc_priv, &stm32_rifsc_conf_dump_fops);
+ file = debugfs_create_file("rifsc", 0444, root, rifsc_priv,
+ &stm32_rifsc_conf_dump_fops);
+ if (IS_ERR(file))
+ return PTR_ERR(file);
- return 0;
+ return devm_add_action_or_reset(rifsc_controller->dev,
+ stm32_rifsc_remove_debugfs, file);
}
#endif /* defined(CONFIG_DEBUG_FS) */
--
2.43.0
^ permalink raw reply related
* [PATCH] soc: mediatek: mtk-svs: clean up debugfs entries
From: Pengpeng Hou @ 2026-06-16 15:14 UTC (permalink / raw)
To: Matthias Brugger
Cc: AngeloGioacchino Del Regno, linux-kernel, linux-arm-kernel,
linux-mediatek, Pengpeng Hou
svs_create_debug_cmds() publishes debugfs files whose private data points
at the SVS platform and bank state, but neither partial debugfs creation
failures nor device teardown remove the tree before that state is
released.
Remove the debugfs tree on partial creation failures and register a devm
action so successful probes remove the tree before devm-managed SVS state
is freed.
Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
---
drivers/soc/mediatek/mtk-svs.c | 19 +++++++++++++++----
1 file changed, 15 insertions(+), 4 deletions(-)
diff --git a/drivers/soc/mediatek/mtk-svs.c b/drivers/soc/mediatek/mtk-svs.c
index 99edecb204f2..2caab6a89698 100644
--- a/drivers/soc/mediatek/mtk-svs.c
+++ b/drivers/soc/mediatek/mtk-svs.c
@@ -172,6 +172,11 @@ static DEFINE_SPINLOCK(svs_lock);
}
#define svs_dentry_data(name) {__stringify(name), &svs_##name##_debug_fops}
+
+static void svs_remove_debug_cmds(void *data)
+{
+ debugfs_remove_recursive(data);
+}
#endif
/**
@@ -887,7 +892,7 @@ static int svs_create_debug_cmds(struct svs_platform *svsp)
if (IS_ERR(file_entry)) {
dev_err(svsp->dev, "cannot create %s/%s: %ld\n",
d, svs_entries[i].name, PTR_ERR(file_entry));
- return PTR_ERR(file_entry);
+ goto err_remove_debugfs;
}
}
@@ -901,7 +906,8 @@ static int svs_create_debug_cmds(struct svs_platform *svsp)
if (IS_ERR(svsb_dir)) {
dev_err(svsp->dev, "cannot create %s/%s: %ld\n",
d, svsb->name, PTR_ERR(svsb_dir));
- return PTR_ERR(svsb_dir);
+ file_entry = svsb_dir;
+ goto err_remove_debugfs;
}
for (i = 0; i < ARRAY_SIZE(svsb_entries); i++) {
@@ -912,12 +918,17 @@ static int svs_create_debug_cmds(struct svs_platform *svsp)
dev_err(svsp->dev, "no %s/%s/%s?: %ld\n",
d, svsb->name, svsb_entries[i].name,
PTR_ERR(file_entry));
- return PTR_ERR(file_entry);
+ goto err_remove_debugfs;
}
}
}
- return 0;
+ return devm_add_action_or_reset(svsp->dev, svs_remove_debug_cmds,
+ svs_dir);
+
+err_remove_debugfs:
+ debugfs_remove_recursive(svs_dir);
+ return PTR_ERR(file_entry);
}
#endif /* CONFIG_DEBUG_FS */
--
2.43.0
^ permalink raw reply related
* Re: [PATCH v7 3/9] regulator: dt-bindings: Add MediaTek MT6392 PMIC
From: Rob Herring @ 2026-06-16 13:50 UTC (permalink / raw)
To: Luca Leonardo Scorcia
Cc: linux-mediatek, Dmitry Torokhov, Krzysztof Kozlowski,
Conor Dooley, Sen Chu, Sean Wang, Macpaul Lin, Lee Jones,
Matthias Brugger, AngeloGioacchino Del Regno, Liam Girdwood,
Mark Brown, Linus Walleij, Val Packett, Julien Massot,
Louis-Alexis Eyraud, Fabien Parent, Akari Tsuyukusa, Chen Zhong,
linux-input, devicetree, linux-kernel, linux-pm, linux-arm-kernel,
linux-gpio
In-Reply-To: <20260615071836.362883-4-l.scorcia@gmail.com>
On Mon, Jun 15, 2026 at 09:16:09AM +0200, Luca Leonardo Scorcia wrote:
> Add bindings for the regulators found in the MediaTek MT6392 PMIC,
> usually found in board designs using the MediaTek MT8516/MT8167 SoCs.
>
> Signed-off-by: Luca Leonardo Scorcia <l.scorcia@gmail.com>
> ---
> .../regulator/mediatek,mt6392-regulator.yaml | 234 ++++++++++++++++++
> .../regulator/mediatek,mt6392-regulator.h | 24 ++
> 2 files changed, 258 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/regulator/mediatek,mt6392-regulator.yaml
> create mode 100644 include/dt-bindings/regulator/mediatek,mt6392-regulator.h
>
> diff --git a/Documentation/devicetree/bindings/regulator/mediatek,mt6392-regulator.yaml b/Documentation/devicetree/bindings/regulator/mediatek,mt6392-regulator.yaml
> new file mode 100644
> index 000000000000..197041df4ba1
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/regulator/mediatek,mt6392-regulator.yaml
> @@ -0,0 +1,234 @@
> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/regulator/mediatek,mt6392-regulator.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: MediaTek MT6392 regulator
> +
> +maintainers:
> + - Luca Leonardo Scorcia <l.scorcia@gmail.com>
> +
> +description:
> + MT6392 is a power management system chip containing three buck converters and
> + 23 LDOs. All voltage regulators provided by the PMIC are described as
> + sub-nodes of this node.
> +
> +properties:
> + compatible:
> + items:
> + - const: mediatek,mt6392-regulator
> +
> + vproc-supply:
> + description: Supply for buck regulator vproc
> + vcore-supply:
> + description: Supply for buck regulator vcore
> + vsys-supply:
> + description: Supply for buck regulator vsys
> + avddldo-supply:
> + description: |
Don't need '|' if no formatting to preserve. Elsewhere too.
> + Supply for AVDD LDOs (vm, vio18, vcn18, vcamd, vcamio). According to the data sheet
> + this is an internal supply derived from vsys.
> + ldo1-supply:
> + description: Supply for LDOs group 1 (vaud28, vxo22, vaud22, vadc18, vcama, vrtc)
> + ldo2-supply:
> + description: Supply for LDOs group 2 (vcn35, vio28, vmc, vmch, vefuse, vdig18)
> + ldo3-supply:
> + description: Supply for LDOs group 3 (vusb, vemc3v3, vcamaf, vgp1, vgp2, vm25)
> +
> +patternProperties:
> + "^v(core|proc|sys)$":
> + description: Buck regulators
> + type: object
> + $ref: regulator.yaml#
> + properties:
> + regulator-allowed-modes:
> + description: |
> + BUCK regulators can set regulator-initial-mode and regulator-allowed-modes to
> + values specified in dt-bindings/regulator/mediatek,mt6392-regulator.h
> + items:
> + enum: [0, 1]
minItems: 1
maxItems: 2
? Because if there are only 2 modes, can't have more entries than that,
right? Though wouldn't 2 entries be the same as no property present
because I would assume the default is all modes. I shouldn't have to
assume though.
> + unevaluatedProperties: false
Place this after $ref. Easier to read than after indented blocks.
> +
> + "^v(adc18|camio|cn18|io18|xo22|m25|aud28|io28|rtc|usb)$":
> + description: LDOs with fixed output and mode setting
> + type: object
> + $ref: regulator.yaml#
> + properties:
> + regulator-allowed-modes:
> + description: |
> + LDO regulators can set regulator-initial-mode and regulator-allowed-modes to
> + values specified in dt-bindings/regulator/mediatek,mt6392-regulator.h
> + items:
> + enum: [0, 1]
> + unevaluatedProperties: false
> +
> + "^v(cama|dig18)$":
> + description: LDOs with fixed output without mode setting
> + type: object
> + $ref: regulator.yaml#
> + unevaluatedProperties: false
> +
> + "^v(aud22|camaf|camd|cn35|efuse|emc3v3|gp1|gp2|m|mc|mch)$":
> + description: LDOs with adjustable output
> + type: object
> + $ref: regulator.yaml#
> + properties:
> + regulator-allowed-modes: false
> + unevaluatedProperties: false
> +
> +required:
> + - compatible
> +
> +additionalProperties: false
> +
> +examples:
> + - |
> + #include <dt-bindings/interrupt-controller/arm-gic.h>
> +
> + regulators {
> + compatible = "mediatek,mt6392-regulator";
Drop the example. Put 1 complete example in the MFD schema rather than
incomplete examples.
Rob
^ permalink raw reply
* Re: [PATCH v2] net: macb: add TX stall timeout callback to recover from lost TSTART write
From: Théo Lebrun @ 2026-06-16 15:07 UTC (permalink / raw)
To: Andrea della Porta, netdev, Nicolas Ferre, Claudiu Beznea,
Andrew Lunn, David S . Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, linux-kernel, linux-arm-kernel, linux-rpi-kernel,
Nicolai Buchwitz
Cc: Lukasz Raczylo, Steffen Jaeckel
In-Reply-To: <468f480454a314303bac6a54780b153f689f2267.1781598350.git.andrea.porta@suse.com>
Hello Andrea,
On Tue Jun 16, 2026 at 3:23 PM CEST, Andrea della Porta wrote:
> From: Lukasz Raczylo <lukasz@raczylo.com>
>
> The MACB found in the Raspberry Pi RP1 suffers from sporadic stalls on
> the TX queue.
> While the exact root cause is not yet fully understood, it is likely
> related to a hardware issue where a TSTART write to the NCR register
> is missed, preventing the transmission from being kicked off.
>
> Implement a timeout callback to handle TX queue stalls, triggering the
> existing restart mechanism to recover.
>
> Link: https://lore.kernel.org/all/20260514215459.36109-1-lukasz@raczylo.com/
> Fixes: dc110d1b23564 ("net: cadence: macb: Add support for Raspberry Pi RP1 ethernet controller")
> Signed-off-by: Lukasz Raczylo <lukasz@raczylo.com>
> Co-developed-by: Steffen Jaeckel <sjaeckel@suse.de>
> Signed-off-by: Steffen Jaeckel <sjaeckel@suse.de>
> Co-developed-by: Andrea della Porta <andrea.porta@suse.com>
> Signed-off-by: Andrea della Porta <andrea.porta@suse.com>
Thanks for this V2.
Reviewed-by: Théo Lebrun <theo.lebrun@bootlin.com>
Any news from the Raspberry Pi community about this bug investigation?
Thanks,
--
Théo Lebrun, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
^ permalink raw reply
* Re: [PATCH v8 09/12] iommu/arm-smmu-v3: Implement pm_runtime & system sleep ops
From: Daniel Mentz @ 2026-06-16 15:07 UTC (permalink / raw)
To: Pranjal Shrivastava
Cc: Mostafa Saleh, iommu, Will Deacon, Joerg Roedel, Robin Murphy,
Jason Gunthorpe, Nicolin Chen, Ashish Mhetre, linux-arm-kernel
In-Reply-To: <ajBWGSs6RrkRTcSY@google.com>
On Mon, Jun 15, 2026 at 12:44 PM Pranjal Shrivastava <praan@google.com> wrote:
>
> On Mon, Jun 15, 2026 at 06:20:27PM +0000, Mostafa Saleh wrote:
> > On Mon, Jun 01, 2026 at 09:59:06PM +0000, Pranjal Shrivastava wrote:
> > > Implement pm_runtime and system sleep ops for arm-smmu-v3.
> > > + /* Clear any flags from the previous life */
I'm wondering if this comment can be improved. You are clearing a very
specific flag, not just any random one. How about "Resume command
queue insertion by clearing STOP_FLAG"?
> > > + atomic_andnot(CMDQ_PROD_STOP_FLAG, &smmu->cmdq.owner_prod);
> > > + atomic_andnot(CMDQ_PROD_STOP_FLAG, &smmu->cmdq.q.llq.atomic.prod);
> >
> > Should not that be done from the suspend call?
>
> I'm not sure if I understand? We're just clearing the flag here?
> We set the flag in suspend to close the gate and clear it in resume
> to re-open it. Clearing it at the end of suspend would be wrong as it
> would allow new submissions while the SMMU is off..
^ permalink raw reply
* Re: [PATCH net-next v7 2/2] net: ti: icssg-prueth: Add ethtool ops for Frame Preemption MAC Merge
From: Jakub Kicinski @ 2026-06-16 15:07 UTC (permalink / raw)
To: Meghana Malladi
Cc: elfring, haokexin, vadim.fedorenko, devnexen, horms,
jacob.e.keller, arnd, basharath, afd, parvathi, vladimir.oltean,
rogerq, danishanwar, pabeni, edumazet, davem, andrew+netdev,
linux-arm-kernel, netdev, linux-kernel, srk, vigneshr
In-Reply-To: <d0123269-b1e8-4fba-94b0-b94d3d9a5405@ti.com>
On Tue, 16 Jun 2026 18:24:22 +0530 Meghana Malladi wrote:
> >> Could the firmware-register lookup table used by emac_get_stat_by_name()
> >> be separated from the ethtool -S string table, so the new preemption
> >> counters feed get_mm_stats without also showing up under ethtool -S?
> >
> > This -- not sure about the other complaints but this one looks legit.
>
> I agree that this is legit, but right now there is no other place holder
> other than pa stats to put the mac merge firmware counters. I believe
> the effort needs to go in re-structuring the hardware and firmware stats
> implementation to address this issue.
icssg_all_miig_stats has a true / false that looks like it's supposed
to serve the same purpose? Maybe I don't understand what you're trying
to say
^ permalink raw reply
* [PATCH v9 9/9] perf test: Add Arm CoreSight callchain test
From: Leo Yan @ 2026-06-16 14:51 UTC (permalink / raw)
To: Arnaldo Carvalho de Melo, John Garry, Will Deacon, James Clark,
Mike Leach, Suzuki K Poulose, Namhyung Kim, Mark Rutland,
Alexander Shishkin, Jiri Olsa, Ian Rogers, Adrian Hunter,
Al Grant, Paschalis Mpeis, Amir Ayupov
Cc: linux-arm-kernel, coresight, linux-perf-users, Leo Yan
In-Reply-To: <20260616-b4-arm_cs_callchain_support_v1-v9-0-f8fad931c413@arm.com>
Add a CoreSight shell test for synthesized callchains.
The test uses the new callchain workload to generate trace and decodes
it with synthesis callchain. It then verifies that the instruction
samples show the expected callchain push and pop.
Use control FIFOs so tracing starts only around the workload, which
keeps the trace data small. The test is limited to with the cs_etm
event available and root permission.
After:
perf test 138 -vvv
138: CoreSight synthesized callchain:
---- start ----
test child forked, pid 35581
Callchain flow matched:
l1=4642868 l2=4642880 l3=4642895 l4=4642919 l5=4670494 l6=4670500 l7=4670520
---- end(0) ----
138: CoreSight synthesized callchain : Ok
Assisted-by: Codex:GPT-5.5
Signed-off-by: Leo Yan <leo.yan@arm.com>
---
tools/perf/Documentation/perf-test.txt | 6 +-
tools/perf/tests/builtin-test.c | 1 +
tools/perf/tests/shell/coresight/callchain.sh | 172 ++++++++++++++++++++++++++
tools/perf/tests/tests.h | 1 +
tools/perf/tests/workloads/Build | 2 +
tools/perf/tests/workloads/callchain.c | 33 +++++
6 files changed, 213 insertions(+), 2 deletions(-)
diff --git a/tools/perf/Documentation/perf-test.txt b/tools/perf/Documentation/perf-test.txt
index 81c8525f594680d814f80e6f88bcce8d867bb350..859df74e62efc4b1e80da13ae8e053356f68ae54 100644
--- a/tools/perf/Documentation/perf-test.txt
+++ b/tools/perf/Documentation/perf-test.txt
@@ -57,7 +57,8 @@ OPTIONS
--workload=::
Run a built-in workload, to list them use '--list-workloads', current
ones include: noploop, thloop, leafloop, sqrtloop, brstack, datasym,
- context_switch_loop, deterministic, named_threads and landlock.
+ context_switch_loop, deterministic, named_threads, landlock and
+ callchain.
Used with the shell script regression tests.
@@ -69,7 +70,8 @@ OPTIONS
'named_threads' accepts the number of threads and the number of loops to
do in each thread.
- The datasym, landlock and deterministic workloads don't accept any.
+ The datasym, landlock, deterministic and callchain workloads don't accept
+ any.
--list-workloads::
List the available workloads to use with -w/--workload.
diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c
index 7e75f590f225e3284980829707ca8d916c98cada..1d1f38127e05429a27f31beda814f2b5f5a75089 100644
--- a/tools/perf/tests/builtin-test.c
+++ b/tools/perf/tests/builtin-test.c
@@ -168,6 +168,7 @@ static struct test_workload *workloads[] = {
&workload__jitdump,
&workload__context_switch_loop,
&workload__deterministic,
+ &workload__callchain,
#ifdef HAVE_RUST_SUPPORT
&workload__code_with_type,
diff --git a/tools/perf/tests/shell/coresight/callchain.sh b/tools/perf/tests/shell/coresight/callchain.sh
new file mode 100755
index 0000000000000000000000000000000000000000..13cca7dc11184002e3ddc058c0d0ffa1c458c483
--- /dev/null
+++ b/tools/perf/tests/shell/coresight/callchain.sh
@@ -0,0 +1,172 @@
+#!/bin/bash
+# CoreSight synthesized callchain (exclusive)
+# SPDX-License-Identifier: GPL-2.0
+
+glb_err=1
+
+if ! tmpdir=$(mktemp -d /tmp/perf-cs-callchain-test.XXXXXX); then
+ echo "mktemp failed"
+ exit 1
+fi
+
+cleanup_files()
+{
+ rm -rf "$tmpdir"
+}
+
+trap cleanup_files EXIT
+trap 'cleanup_files; exit $glb_err' TERM INT
+
+skip_if_system_is_not_ready()
+{
+ perf list | grep -Pzq 'cs_etm//' || {
+ echo "[Skip] cs_etm event is not available" >&2
+ return 2
+ }
+
+ # Requires root for trace in kernel
+ [ "$(id -u)" = 0 ] || {
+ echo "[Skip] No root permission" >&2
+ return 2
+ }
+
+ return 0
+}
+
+record_trace()
+{
+ local data=$1
+ local script=$2
+
+ local cf="$tmpdir/ctl"
+ local af="$tmpdir/ack"
+
+ mkfifo "$cf" "$af"
+
+ perf record -o "$data" -e cs_etm// --per-thread -D -1 --control fifo:"$cf","$af" -- \
+ perf test --record-ctl fifo:"$cf","$af" -w callchain >/dev/null 2>&1 &&
+
+ # It is safe to use 'i3i' with a three-instruction interval, since the
+ # workload is compiled with -O0.
+ perf script --itrace=g16i3il64 -i "$data" > "$script"
+}
+
+callchain_regex_1()
+{
+ printf '%s' \
+'perf[[:space:]]+[0-9]+[[:space:]]+\[[0-9]+\][[:space:]]+([0-9.]+:[[:space:]]+)?[0-9]+ instructions:[[:space:]]*\n'\
+'[[:space:]]+[[:xdigit:]]+ callchain_foo\+0x[[:xdigit:]]+ \(.*/perf\)\n'\
+'[[:space:]]+[[:xdigit:]]+ callchain\+0x[[:xdigit:]]+ \(.*/perf\)\n'\
+'([[:space:]]+[[:xdigit:]]+ .*\n)*'
+}
+
+callchain_regex_2()
+{
+ printf '%s' \
+'perf[[:space:]]+[0-9]+[[:space:]]+\[[0-9]+\][[:space:]]+([0-9.]+:[[:space:]]+)?[0-9]+ instructions:[[:space:]]*\n'\
+'[[:space:]]+[[:xdigit:]]+ callchain_do_syscall\+0x[[:xdigit:]]+ \(.*/perf\)\n'\
+'[[:space:]]+[[:xdigit:]]+ callchain_foo\+0x[[:xdigit:]]+ \(.*/perf\)\n'\
+'[[:space:]]+[[:xdigit:]]+ callchain\+0x[[:xdigit:]]+ \(.*/perf\)\n'\
+'([[:space:]]+[[:xdigit:]]+ .*\n)*'
+}
+
+callchain_regex_3()
+{
+ printf '%s' \
+'perf[[:space:]]+[0-9]+[[:space:]]+\[[0-9]+\][[:space:]]+([0-9.]+:[[:space:]]+)?[0-9]+ instructions:[[:space:]]*\n'\
+'[[:space:]]+[[:xdigit:]]+ syscall(@plt)?\+0x[[:xdigit:]]+ \(.*\)\n'\
+'[[:space:]]+[[:xdigit:]]+ callchain_do_syscall\+0x[[:xdigit:]]+ \(.*/perf\)\n'\
+'[[:space:]]+[[:xdigit:]]+ callchain_foo\+0x[[:xdigit:]]+ \(.*/perf\)\n'\
+'[[:space:]]+[[:xdigit:]]+ callchain\+0x[[:xdigit:]]+ \(.*/perf\)\n'\
+'([[:space:]]+[[:xdigit:]]+ .*\n)*'
+}
+
+callchain_regex_4()
+{
+ printf '%s' \
+'perf[[:space:]]+[0-9]+[[:space:]]+\[[0-9]+\][[:space:]]+([0-9.]+:[[:space:]]+)?[0-9]+ instructions:[[:space:]]*\n'\
+'[[:space:]]+[[:xdigit:]]+ .*\+0x[[:xdigit:]]+ \(\[kernel\.kallsyms\]\)\n'\
+'[[:space:]]+[[:xdigit:]]+ syscall(@plt)?\+0x[[:xdigit:]]+ \(.*\)\n'\
+'[[:space:]]+[[:xdigit:]]+ callchain_do_syscall\+0x[[:xdigit:]]+ \(.*/perf\)\n'\
+'[[:space:]]+[[:xdigit:]]+ callchain_foo\+0x[[:xdigit:]]+ \(.*/perf\)\n'\
+'[[:space:]]+[[:xdigit:]]+ callchain\+0x[[:xdigit:]]+ \(.*/perf\)\n'\
+'([[:space:]]+[[:xdigit:]]+ .*\n)*'
+}
+
+find_after_line()
+{
+ local regex="$1"
+ local file="$2"
+ local start="$3"
+ local offset
+ local line
+
+ # Search in byte offset
+ offset=$(
+ tail -n +"$start" "$file" |
+ grep -Pzob -m1 "$regex" |
+ tr '\0' '\n' |
+ sed -n 's/^\([0-9][0-9]*\):.*/\1/p;q'
+ )
+
+ if [ -z "$offset" ]; then
+ echo "Failed to match regex after line $start" >&2
+ echo "Regex:" >&2
+ printf '%s\n' "$regex" >&2
+ echo "Context from line $start:" >&2
+ sed -n "${start},$((start + 100))p" "$file" >&2
+ return 1
+ fi
+
+ # Convert from offset to line
+ line=$(
+ tail -n +"$start" "$file" |
+ head -c "$offset" |
+ wc -l
+ )
+
+ echo "$((start + line))"
+}
+
+check_callchain_flow()
+{
+ local file="$1"
+ local l1 l2 l3 l4 l5 l6 l7
+
+ # Callchain push
+ l1=$(find_after_line "$(callchain_regex_1)" "$file" 1) || return 1
+ l2=$(find_after_line "$(callchain_regex_2)" "$file" "$((l1 + 1))") || return 1
+ l3=$(find_after_line "$(callchain_regex_3)" "$file" "$((l2 + 1))") || return 1
+ l4=$(find_after_line "$(callchain_regex_4)" "$file" "$((l3 + 1))") || return 1
+
+ # Callchain pop
+ l5=$(find_after_line "$(callchain_regex_3)" "$file" "$((l4 + 1))") || return 1
+ l6=$(find_after_line "$(callchain_regex_2)" "$file" "$((l5 + 1))") || return 1
+ l7=$(find_after_line "$(callchain_regex_1)" "$file" "$((l6 + 1))") || return 1
+
+ echo "Callchain flow matched:"
+ echo " l1=$l1 l2=$l2 l3=$l3 l4=$l4 l5=$l5 l6=$l6 l7=$l7"
+
+ return 0
+}
+
+run_test()
+{
+ local data=$tmpdir/perf.data
+ local script=$tmpdir/perf.script
+
+ if ! record_trace "$data" "$script"; then
+ echo "perf record/script failed"
+ return
+ fi
+
+ check_callchain_flow "$script" || return
+
+ glb_err=0
+}
+
+skip_if_system_is_not_ready || exit 2
+
+run_test
+
+exit $glb_err
diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h
index 7cedf05be544ad79a99e86d30dfa4f7b01ca0837..cee9e6b62dcc838c864bbe76efe3b638ed75b134 100644
--- a/tools/perf/tests/tests.h
+++ b/tools/perf/tests/tests.h
@@ -248,6 +248,7 @@ DECLARE_WORKLOAD(inlineloop);
DECLARE_WORKLOAD(jitdump);
DECLARE_WORKLOAD(context_switch_loop);
DECLARE_WORKLOAD(deterministic);
+DECLARE_WORKLOAD(callchain);
#ifdef HAVE_RUST_SUPPORT
DECLARE_WORKLOAD(code_with_type);
diff --git a/tools/perf/tests/workloads/Build b/tools/perf/tests/workloads/Build
index 7bb4b9829ba245740c8967e6bf3235614cdd55a3..048e371eb63e316453b6b46ebd0a02794c3d25d7 100644
--- a/tools/perf/tests/workloads/Build
+++ b/tools/perf/tests/workloads/Build
@@ -13,6 +13,7 @@ perf-test-y += inlineloop.o
perf-test-y += jitdump.o
perf-test-y += context_switch_loop.o
perf-test-y += deterministic.o
+perf-test-y += callchain.o
ifeq ($(CONFIG_RUST_SUPPORT),y)
perf-test-y += code_with_type.o
@@ -27,3 +28,4 @@ CFLAGS_traploop.o = -g -O0 -fno-inline -U_FORTIFY_SOURCE
CFLAGS_inlineloop.o = -g -O2
CFLAGS_deterministic.o = -g -O0 -fno-inline -U_FORTIFY_SOURCE
CFLAGS_named_threads.o = -g -O0 -fno-inline -U_FORTIFY_SOURCE
+CFLAGS_callchain.o = -g -O0 -fno-inline -U_FORTIFY_SOURCE
diff --git a/tools/perf/tests/workloads/callchain.c b/tools/perf/tests/workloads/callchain.c
new file mode 100644
index 0000000000000000000000000000000000000000..3951423d8115e9efb49af8ba2586001fc6f02761
--- /dev/null
+++ b/tools/perf/tests/workloads/callchain.c
@@ -0,0 +1,33 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/compiler.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+#include "../tests.h"
+
+/*
+ * Mark as noinline to establish the call chain, and avoid the static
+ * annotation to prevent LTO from renaming the functions.
+ */
+noinline void callchain_do_syscall(void);
+noinline void callchain_foo(void);
+noinline int callchain(int argc, const char **argv);
+
+noinline void callchain_do_syscall(void)
+{
+ syscall(SYS_getpid);
+}
+
+noinline void callchain_foo(void)
+{
+ callchain_do_syscall();
+}
+
+noinline int callchain(int argc __maybe_unused,
+ const char **argv __maybe_unused)
+{
+ callchain_foo();
+
+ return 0;
+}
+
+DEFINE_WORKLOAD(callchain);
--
2.34.1
^ permalink raw reply related
* [PATCH v9 8/9] perf cs-etm: Synthesize callchains for instruction samples
From: Leo Yan @ 2026-06-16 14:51 UTC (permalink / raw)
To: Arnaldo Carvalho de Melo, John Garry, Will Deacon, James Clark,
Mike Leach, Suzuki K Poulose, Namhyung Kim, Mark Rutland,
Alexander Shishkin, Jiri Olsa, Ian Rogers, Adrian Hunter,
Al Grant, Paschalis Mpeis, Amir Ayupov
Cc: linux-arm-kernel, coresight, linux-perf-users, Leo Yan, Leo Yan
In-Reply-To: <20260616-b4-arm_cs_callchain_support_v1-v9-0-f8fad931c413@arm.com>
From: Leo Yan <leo.yan@linaro.org>
CS ETM already records branches into the thread stack, but instruction
samples do not carry synthesized callchains. It misses to support the
callchain and no output with the itrace option 'g'.
Allocate a callchain buffer per queue and use thread_stack__sample()
when synthesizing instruction samples.
Advertise PERF_SAMPLE_CALLCHAIN on the synthetic instruction event.
Allocate one extra callchain entry than requested, as the first entry
is reserved for storing context information.
cs_etm__context() is introduced for handling context packet and update
the thread info and start kernel address for frontend decoding.
After:
perf script --itrace=g16l64i1i
callchain_test 6543 [002] 1 instructions:
ffff800080010c14 vectors+0x414 ([kernel.kallsyms])
aaaad6b60784 do_svc+0x1c (/home/kernel/leoy/test_cs_callchain/callchain_test)
aaaad6b60798 print+0xc (/home/kernel/leoy/test_cs_callchain/callchain_test)
aaaad6b607b0 foo+0xc (/home/kernel/leoy/test_cs_callchain/callchain_test)
aaaad6b607c8 main+0xc (/home/kernel/leoy/test_cs_callchain/callchain_test)
ffff9325225c __libc_start_call_main+0x7c (/usr/lib/aarch64-linux-gnu/libc.so.6)
ffff9325233c call_init+0x9c (inlined)
ffff9325233c __libc_start_main_impl+0x9c (inlined)
aaaad6b60670 _start+0x30 (/home/kernel/leoy/test_cs_callchain/callchain_test)
ffff800080012290 ret_to_user+0x120 ([kernel.kallsyms])
Signed-off-by: Leo Yan <leo.yan@linaro.org>
Reviewed-by: James Clark <james.clark@linaro.org>
Signed-off-by: Leo Yan <leo.yan@arm.com>
---
tools/perf/util/cs-etm.c | 83 +++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 78 insertions(+), 5 deletions(-)
diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c
index e18d2dec79431f7e4b26742d98cf074483c4a246..34489476681b8e46c7a0d9e20bff433f66962484 100644
--- a/tools/perf/util/cs-etm.c
+++ b/tools/perf/util/cs-etm.c
@@ -18,6 +18,7 @@
#include <stdlib.h>
#include "auxtrace.h"
+#include "callchain.h"
#include "color.h"
#include "cs-etm.h"
#include "cs-etm-decoder/cs-etm-decoder.h"
@@ -87,9 +88,11 @@ struct cs_etm_auxtrace {
struct cs_etm_traceid_queue {
u8 trace_chan_id;
u64 period_instructions;
+ u64 kernel_start;
union perf_event *event_buf;
unsigned int br_stack_sz;
struct branch_stack *last_branch;
+ struct ip_callchain *callchain;
struct cs_etm_packet *prev_packet;
struct cs_etm_packet *packet;
struct cs_etm_packet_queue packet_queue;
@@ -652,6 +655,15 @@ static int cs_etm__init_traceid_queue(struct cs_etm_queue *etmq,
tidq->br_stack_sz = etm->synth_opts.last_branch_sz;
}
+ if (etm->synth_opts.callchain) {
+ /* Add 1 to callchain_sz for callchain context */
+ tidq->callchain =
+ zalloc(struct_size(tidq->callchain, ips,
+ etm->synth_opts.callchain_sz + 1));
+ if (!tidq->callchain)
+ goto out_free;
+ }
+
tidq->event_buf = malloc(PERF_SAMPLE_MAX_SIZE);
if (!tidq->event_buf)
goto out_free;
@@ -659,6 +671,7 @@ static int cs_etm__init_traceid_queue(struct cs_etm_queue *etmq,
return 0;
out_free:
+ zfree(&tidq->callchain);
zfree(&tidq->last_branch);
zfree(&tidq->prev_packet);
zfree(&tidq->packet);
@@ -942,6 +955,7 @@ static void cs_etm__free_traceid_queues(struct cs_etm_queue *etmq)
thread__zput(tidq->frontend_thread);
thread__zput(tidq->decode_thread);
zfree(&tidq->event_buf);
+ zfree(&tidq->callchain);
zfree(&tidq->last_branch);
zfree(&tidq->prev_packet);
zfree(&tidq->packet);
@@ -1611,6 +1625,26 @@ static int cs_etm__synth_instruction_sample(struct cs_etm_queue *etmq,
sample.branch_stack = tidq->last_branch;
}
+ if (etm->synth_opts.callchain) {
+ if (tidq->kernel_start)
+ thread_stack__sample(tidq->frontend_thread,
+ tidq->packet->cpu,
+ tidq->callchain,
+ etm->synth_opts.callchain_sz + 1,
+ sample.ip, tidq->kernel_start);
+ else
+ /*
+ * Clear the callchain when the kernel start address is
+ * not available yet. The empty callchain can then be
+ * consumed by cs_etm__inject_event().
+ */
+ memset(tidq->callchain, 0,
+ struct_size(tidq->callchain, ips,
+ etm->synth_opts.callchain_sz + 1));
+
+ sample.callchain = tidq->callchain;
+ }
+
if (etm->synth_opts.inject) {
ret = cs_etm__inject_event(etm, event, &sample,
etm->instructions_sample_type);
@@ -1773,6 +1807,9 @@ static int cs_etm__synth_events(struct cs_etm_auxtrace *etm,
attr.branch_sample_type |= PERF_SAMPLE_BRANCH_HW_INDEX;
}
+ if (etm->synth_opts.callchain)
+ attr.sample_type |= PERF_SAMPLE_CALLCHAIN;
+
if (etm->synth_opts.instructions) {
attr.config = PERF_COUNT_HW_INSTRUCTIONS;
attr.sample_period = etm->synth_opts.period;
@@ -1904,6 +1941,34 @@ static int cs_etm__sample(struct cs_etm_queue *etmq,
return 0;
}
+static int cs_etm__context(struct cs_etm_queue *etmq,
+ struct cs_etm_traceid_queue *tidq)
+{
+ ocsd_ex_level el = tidq->packet->el;
+ struct machine *machine;
+ int ret;
+
+ machine = cs_etm__get_machine(etmq, el);
+ if (!machine) {
+ ret = -EINVAL;
+ goto err;
+ }
+
+ tidq->kernel_start = machine__kernel_start(machine);
+
+ ret = cs_etm__etmq_update_thread(etmq, el, tidq->packet->tid,
+ &tidq->frontend_thread);
+ if (ret)
+ goto err;
+
+ return 0;
+
+err:
+ thread__zput(tidq->frontend_thread);
+ tidq->kernel_start = 0;
+ return ret;
+}
+
static int cs_etm__exception(struct cs_etm_traceid_queue *tidq)
{
/*
@@ -2504,9 +2569,7 @@ static int cs_etm__process_traceid_queue(struct cs_etm_queue *etmq,
* tracing the kernel the context packet will be emitted
* between two ranges.
*/
- ret = cs_etm__etmq_update_thread(etmq, tidq->packet->el,
- tidq->packet->tid,
- &tidq->frontend_thread);
+ ret = cs_etm__context(etmq, tidq);
if (ret)
goto out;
break;
@@ -3530,6 +3593,14 @@ int cs_etm__process_auxtrace_info_full(union perf_event *event,
PERF_IP_FLAG_TRACE_BEGIN |
PERF_IP_FLAG_TRACE_END;
+ if (etm->synth_opts.callchain && !symbol_conf.use_callchain) {
+ symbol_conf.use_callchain = true;
+ if (callchain_register_param(&callchain_param) < 0) {
+ symbol_conf.use_callchain = false;
+ etm->synth_opts.callchain = false;
+ }
+ }
+
etm->session = session;
etm->num_cpu = num_cpu;
@@ -3581,9 +3652,11 @@ int cs_etm__process_auxtrace_info_full(union perf_event *event,
}
etm->use_thread_stack = etm->synth_opts.thread_stack ||
- etm->synth_opts.last_branch;
+ etm->synth_opts.last_branch ||
+ etm->synth_opts.callchain;
- etm->use_callchain = etm->synth_opts.thread_stack;
+ etm->use_callchain = etm->synth_opts.thread_stack ||
+ etm->synth_opts.callchain;
err = cs_etm__synth_events(etm, session);
if (err)
--
2.34.1
^ permalink raw reply related
* [PATCH v9 7/9] perf cs-etm: Support call indentation
From: Leo Yan @ 2026-06-16 14:51 UTC (permalink / raw)
To: Arnaldo Carvalho de Melo, John Garry, Will Deacon, James Clark,
Mike Leach, Suzuki K Poulose, Namhyung Kim, Mark Rutland,
Alexander Shishkin, Jiri Olsa, Ian Rogers, Adrian Hunter,
Al Grant, Paschalis Mpeis, Amir Ayupov
Cc: linux-arm-kernel, coresight, linux-perf-users, Leo Yan, Leo Yan
In-Reply-To: <20260616-b4-arm_cs_callchain_support_v1-v9-0-f8fad931c413@arm.com>
From: Leo Yan <leo.yan@linaro.org>
The perf script callindent is derived from call stack in thread context,
CS ETM ignores the requirement for callindent without pushing and poping
call stack.
Enable thread-stack when either itrace thread-stack support or last branch
entries are requested, allocate the branch stack storage accordingly, and
feed taken branches to thread_stack__event() whenever thread-stack state
is needed.
When callindent is requested, pass callstack=true to thread_stack__event()
so the common thread-stack code maintains call depth for branch samples.
Before:
perf script -F +callindent
callchain_test 6543 [002] 1 branches: main ffff93252258 __libc_start_call_main+0x78 (/usr/lib/aarch64-linux-gnu/libc.so.6)
callchain_test 6543 [002] 1 branches: foo aaaad6b607c4 main+0x8 (/home/kernel/leoy/test_cs_callchain/callchain_test)
callchain_test 6543 [002] 1 branches: print aaaad6b607ac foo+0x8 (/home/kernel/leoy/test_cs_callchain/callchain_test)
callchain_test 6543 [002] 1 branches: do_svc aaaad6b60794 print+0x8 (/home/kernel/leoy/test_cs_callchain/callchain_test)
callchain_test 6543 [002] 1 branches: vectors aaaad6b60780 do_svc+0x18 (/home/kernel/leoy/test_cs_callchain/callchain_test)
callchain_test 6543 [002] 1 branches: el0t_64_sync_handler ffff80008001159c el0t_64_sync+0x194 ([kernel.kallsyms])
callchain_test 6543 [002] 1 branches: el0_svc ffff800081829194 el0t_64_sync_handler+0x9c ([kernel.kallsyms])
callchain_test 6543 [002] 1 branches: lockdep_hardirqs_off ffff800081828794 el0_svc+0x24 ([kernel.kallsyms])
callchain_test 6543 [002] 1 branches: __this_cpu_preempt_check ffff80008182b348 lockdep_hardirqs_off+0xf0 ([kernel.kallsyms])
After:
callchain_test 6543 [002] 1 branches: main ffff93252258 __libc_start_call_main+0x78 (/usr/lib/aarch64-linux-gnu/libc.so.6)
callchain_test 6543 [002] 1 branches: foo aaaad6b607c4 main+0x8 (/home/kernel/leoy/test_cs_callchain/callchain_test)
callchain_test 6543 [002] 1 branches: print aaaad6b607ac foo+0x8 (/home/kernel/leoy/test_cs_callchain/callchain_test)
callchain_test 6543 [002] 1 branches: do_svc aaaad6b60794 print+0x8 (/home/kernel/leoy/test_cs_callchain/callchain_test)
callchain_test 6543 [002] 1 branches: vectors aaaad6b60780 do_svc+0x18 (/home/kernel/leoy/test_cs_callchain/callchain_test)
callchain_test 6543 [002] 1 branches: el0t_64_sync_handler ffff80008001159c el0t_64_sync+0x194 ([kernel.kallsyms])
callchain_test 6543 [002] 1 branches: el0_svc ffff800081829194 el0t_64_sync_handler+0x9c ([kernel.kallsyms])
callchain_test 6543 [002] 1 branches: lockdep_hardirqs_off ffff800081828794 el0_svc+0x24 ([kernel.kallsyms])
callchain_test 6543 [002] 1 branches: __this_cpu_preempt_check ffff80008182b348 lockdep_hardirqs_off+0xf0 ([kernel.kallsyms])
Signed-off-by: Leo Yan <leo.yan@linaro.org>
Reviewed-by: James Clark <james.clark@linaro.org>
Signed-off-by: Leo Yan <leo.yan@arm.com>
---
tools/perf/util/cs-etm.c | 20 +++++++++++++++-----
1 file changed, 15 insertions(+), 5 deletions(-)
diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c
index d41aad583a26fe9f2f74c52630bd01c2a5bbe0e4..e18d2dec79431f7e4b26742d98cf074483c4a246 100644
--- a/tools/perf/util/cs-etm.c
+++ b/tools/perf/util/cs-etm.c
@@ -67,6 +67,8 @@ struct cs_etm_auxtrace {
bool snapshot_mode;
bool data_queued;
bool has_virtual_ts; /* Virtual/Kernel timestamps in the trace. */
+ bool use_thread_stack;
+ bool use_callchain;
int num_cpu;
u64 latest_kernel_timestamp;
@@ -638,7 +640,7 @@ static int cs_etm__init_traceid_queue(struct cs_etm_queue *etmq,
if (!tidq->prev_packet)
goto out_free;
- if (etm->synth_opts.last_branch) {
+ if (etm->use_thread_stack) {
size_t sz = sizeof(struct branch_stack);
sz += etm->synth_opts.last_branch_sz *
@@ -1554,7 +1556,7 @@ static void cs_etm__add_stack_event(struct cs_etm_queue *etmq,
if (!cs_etm__packet_has_taken_branch(tidq->prev_packet))
return;
- if (etmq->etm->synth_opts.last_branch) {
+ if (etmq->etm->use_thread_stack) {
from = cs_etm__last_executed_instr(tidq->prev_packet);
to = cs_etm__first_executed_instr(tidq->packet);
@@ -1563,7 +1565,8 @@ static void cs_etm__add_stack_event(struct cs_etm_queue *etmq,
/* Enable callchain so thread stack entry can be allocated */
thread_stack__event(tidq->frontend_thread, tidq->prev_packet->cpu,
tidq->prev_packet->flags, from, to, size,
- etmq->buffer->buffer_nr + 1, false,
+ etmq->buffer->buffer_nr + 1,
+ etmq->etm->use_callchain,
tidq->br_stack_sz, 0);
} else {
thread_stack__set_trace_nr(tidq->frontend_thread,
@@ -1964,7 +1967,7 @@ static int cs_etm__flush(struct cs_etm_queue *etmq,
cs_etm__packet_swap(etm, tidq);
/* Reset last branches after flush the trace */
- if (etm->synth_opts.last_branch)
+ if (etm->use_thread_stack)
thread_stack__flush(tidq->frontend_thread);
return err;
@@ -2027,7 +2030,7 @@ static void cs_etm__flush_all_stack(struct cs_etm_queue *etmq)
{
enum cs_etm_pid_fmt pid_fmt = cs_etm__get_pid_fmt(etmq);
- if (!etmq->etm->synth_opts.last_branch)
+ if (!etmq->etm->use_thread_stack)
return;
switch (pid_fmt) {
@@ -3514,6 +3517,7 @@ int cs_etm__process_auxtrace_info_full(union perf_event *event,
itrace_synth_opts__set_default(&etm->synth_opts,
session->itrace_synth_opts->default_no_sample);
etm->synth_opts.callchain = false;
+ etm->synth_opts.thread_stack = session->itrace_synth_opts->thread_stack;
}
if (etm->synth_opts.calls)
@@ -3575,6 +3579,12 @@ int cs_etm__process_auxtrace_info_full(union perf_event *event,
etm->tc.cap_user_time_zero = tc->cap_user_time_zero;
etm->tc.cap_user_time_short = tc->cap_user_time_short;
}
+
+ etm->use_thread_stack = etm->synth_opts.thread_stack ||
+ etm->synth_opts.last_branch;
+
+ etm->use_callchain = etm->synth_opts.thread_stack;
+
err = cs_etm__synth_events(etm, session);
if (err)
goto err_free_queues;
--
2.34.1
^ permalink raw reply related
* [PATCH v9 6/9] perf cs-etm: Flush thread stacks after decoder reset
From: Leo Yan @ 2026-06-16 14:51 UTC (permalink / raw)
To: Arnaldo Carvalho de Melo, John Garry, Will Deacon, James Clark,
Mike Leach, Suzuki K Poulose, Namhyung Kim, Mark Rutland,
Alexander Shishkin, Jiri Olsa, Ian Rogers, Adrian Hunter,
Al Grant, Paschalis Mpeis, Amir Ayupov
Cc: linux-arm-kernel, coresight, linux-perf-users, Leo Yan
In-Reply-To: <20260616-b4-arm_cs_callchain_support_v1-v9-0-f8fad931c413@arm.com>
Perf resets the CoreSight decoder when moving to a new AUX trace buffer,
this causes trace discontinunity globally.
For callchain synthesis, keeping thread-stack state after decoder reset
can leave stale call/return history attached to threads that are decoded
later, producing incorrect synthesized callchains.
Flush all host thread stacks after a decoder reset. When virtualization
is present, flush the guest thread stacks as well.
Reviewed-by: James Clark <james.clark@linaro.org>
Signed-off-by: Leo Yan <leo.yan@arm.com>
---
tools/perf/util/cs-etm.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 45 insertions(+)
diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c
index 51b05a0bc1898128ad66d82bef6e09b5c853463c..d41aad583a26fe9f2f74c52630bd01c2a5bbe0e4 100644
--- a/tools/perf/util/cs-etm.c
+++ b/tools/perf/util/cs-etm.c
@@ -2006,6 +2006,45 @@ static int cs_etm__end_block(struct cs_etm_queue *etmq,
return 0;
}
+
+static int cs_etm__flush_stack_cb(struct thread *thread,
+ void *data __maybe_unused)
+{
+ thread_stack__flush(thread);
+ return 0;
+}
+
+static void cs_etm__flush_machine_stack(struct cs_etm_queue *etmq, pid_t pid)
+{
+ struct machine *machine;
+
+ machine = machines__find(&etmq->etm->session->machines, pid);
+ if (machine)
+ machine__for_each_thread(machine, cs_etm__flush_stack_cb, NULL);
+}
+
+static void cs_etm__flush_all_stack(struct cs_etm_queue *etmq)
+{
+ enum cs_etm_pid_fmt pid_fmt = cs_etm__get_pid_fmt(etmq);
+
+ if (!etmq->etm->synth_opts.last_branch)
+ return;
+
+ switch (pid_fmt) {
+ case CS_ETM_PIDFMT_CTXTID2:
+ /* Clear the guest stack if virtualization is supported */
+ cs_etm__flush_machine_stack(etmq, DEFAULT_GUEST_KERNEL_ID);
+ fallthrough;
+ case CS_ETM_PIDFMT_CTXTID:
+ cs_etm__flush_machine_stack(etmq, HOST_KERNEL_ID);
+ break;
+ case CS_ETM_PIDFMT_NONE:
+ default:
+ break;
+
+ }
+}
+
/*
* cs_etm__get_data_block: Fetch a block from the auxtrace_buffer queue
* if need be.
@@ -2028,6 +2067,12 @@ static int cs_etm__get_data_block(struct cs_etm_queue *etmq)
ret = cs_etm_decoder__reset(etmq->decoder);
if (ret)
return ret;
+
+ /*
+ * Since the decoder is reset, this causes a global trace
+ * discontinuity. Flush all thread stacks.
+ */
+ cs_etm__flush_all_stack(etmq);
}
return etmq->buf_len;
--
2.34.1
^ permalink raw reply related
* [PATCH v9 5/9] perf cs-etm: Use thread-stack for last branch entries
From: Leo Yan @ 2026-06-16 14:51 UTC (permalink / raw)
To: Arnaldo Carvalho de Melo, John Garry, Will Deacon, James Clark,
Mike Leach, Suzuki K Poulose, Namhyung Kim, Mark Rutland,
Alexander Shishkin, Jiri Olsa, Ian Rogers, Adrian Hunter,
Al Grant, Paschalis Mpeis, Amir Ayupov
Cc: linux-arm-kernel, coresight, linux-perf-users, Leo Yan
In-Reply-To: <20260616-b4-arm_cs_callchain_support_v1-v9-0-f8fad931c413@arm.com>
CS ETM maintains its own circular array for last branch entries, with
local helpers to update, copy and reset the branch stack. This
duplicates logic already provided by the common code.
Record taken branches with thread_stack__event() and synthesize
PERF_SAMPLE_BRANCH_STACK data with thread_stack__br_sample(). This
removes the private last_branch_rb buffer and its position tracking.
This also makes the branch history state belong to the thread rather
than the trace queue. That is a better fit for CoreSight traces where
a trace queue can effectively be CPU scoped, while call/return history
is per thread.
Keep the buffer number updated via thread_stack__set_trace_nr(), which
is used when exporting samples to Python scripts. Pass callstack=false
for now; synthesized callchains are added by a later patch.
The output should remain same, except that be->flags.predicted is no
longer set. Since CoreSight trace does not provide branch prediction
information, clearing the flag avoids confusion.
Reviewed-by: James Clark <james.clark@linaro.org>
Signed-off-by: Leo Yan <leo.yan@arm.com>
---
tools/perf/util/cs-etm.c | 163 +++++++++++++++--------------------------------
1 file changed, 50 insertions(+), 113 deletions(-)
diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c
index 6827ef8871a8fc092500b93a8284d5d162558357..51b05a0bc1898128ad66d82bef6e09b5c853463c 100644
--- a/tools/perf/util/cs-etm.c
+++ b/tools/perf/util/cs-etm.c
@@ -85,10 +85,9 @@ struct cs_etm_auxtrace {
struct cs_etm_traceid_queue {
u8 trace_chan_id;
u64 period_instructions;
- size_t last_branch_pos;
union perf_event *event_buf;
+ unsigned int br_stack_sz;
struct branch_stack *last_branch;
- struct branch_stack *last_branch_rb;
struct cs_etm_packet *prev_packet;
struct cs_etm_packet *packet;
struct cs_etm_packet_queue packet_queue;
@@ -647,9 +646,8 @@ static int cs_etm__init_traceid_queue(struct cs_etm_queue *etmq,
tidq->last_branch = zalloc(sz);
if (!tidq->last_branch)
goto out_free;
- tidq->last_branch_rb = zalloc(sz);
- if (!tidq->last_branch_rb)
- goto out_free;
+
+ tidq->br_stack_sz = etm->synth_opts.last_branch_sz;
}
tidq->event_buf = malloc(PERF_SAMPLE_MAX_SIZE);
@@ -659,7 +657,6 @@ static int cs_etm__init_traceid_queue(struct cs_etm_queue *etmq,
return 0;
out_free:
- zfree(&tidq->last_branch_rb);
zfree(&tidq->last_branch);
zfree(&tidq->prev_packet);
zfree(&tidq->packet);
@@ -944,7 +941,6 @@ static void cs_etm__free_traceid_queues(struct cs_etm_queue *etmq)
thread__zput(tidq->decode_thread);
zfree(&tidq->event_buf);
zfree(&tidq->last_branch);
- zfree(&tidq->last_branch_rb);
zfree(&tidq->prev_packet);
zfree(&tidq->packet);
zfree(&tidq);
@@ -1304,57 +1300,6 @@ static int cs_etm__queue_first_cs_timestamp(struct cs_etm_auxtrace *etm,
return ret;
}
-static inline
-void cs_etm__copy_last_branch_rb(struct cs_etm_queue *etmq,
- struct cs_etm_traceid_queue *tidq)
-{
- struct branch_stack *bs_src = tidq->last_branch_rb;
- struct branch_stack *bs_dst = tidq->last_branch;
- size_t nr = 0;
-
- /*
- * Set the number of records before early exit: ->nr is used to
- * determine how many branches to copy from ->entries.
- */
- bs_dst->nr = bs_src->nr;
-
- /*
- * Early exit when there is nothing to copy.
- */
- if (!bs_src->nr)
- return;
-
- /*
- * As bs_src->entries is a circular buffer, we need to copy from it in
- * two steps. First, copy the branches from the most recently inserted
- * branch ->last_branch_pos until the end of bs_src->entries buffer.
- */
- nr = etmq->etm->synth_opts.last_branch_sz - tidq->last_branch_pos;
- memcpy(&bs_dst->entries[0],
- &bs_src->entries[tidq->last_branch_pos],
- sizeof(struct branch_entry) * nr);
-
- /*
- * If we wrapped around at least once, the branches from the beginning
- * of the bs_src->entries buffer and until the ->last_branch_pos element
- * are older valid branches: copy them over. The total number of
- * branches copied over will be equal to the number of branches asked by
- * the user in last_branch_sz.
- */
- if (bs_src->nr >= etmq->etm->synth_opts.last_branch_sz) {
- memcpy(&bs_dst->entries[nr],
- &bs_src->entries[0],
- sizeof(struct branch_entry) * tidq->last_branch_pos);
- }
-}
-
-static inline
-void cs_etm__reset_last_branch_rb(struct cs_etm_traceid_queue *tidq)
-{
- tidq->last_branch_pos = 0;
- tidq->last_branch_rb->nr = 0;
-}
-
static inline int cs_etm__t32_instr_size(struct cs_etm_queue *etmq,
struct cs_etm_traceid_queue *tidq,
struct cs_etm_packet *packet, u64 addr)
@@ -1424,38 +1369,6 @@ static inline u64 cs_etm__instr_addr(struct cs_etm_queue *etmq,
return addr;
}
-static void cs_etm__update_last_branch_rb(struct cs_etm_queue *etmq,
- struct cs_etm_traceid_queue *tidq)
-{
- struct branch_stack *bs = tidq->last_branch_rb;
- struct branch_entry *be;
-
- /*
- * The branches are recorded in a circular buffer in reverse
- * chronological order: we start recording from the last element of the
- * buffer down. After writing the first element of the stack, move the
- * insert position back to the end of the buffer.
- */
- if (!tidq->last_branch_pos)
- tidq->last_branch_pos = etmq->etm->synth_opts.last_branch_sz;
-
- tidq->last_branch_pos -= 1;
-
- be = &bs->entries[tidq->last_branch_pos];
- be->from = cs_etm__last_executed_instr(tidq->prev_packet);
- be->to = cs_etm__first_executed_instr(tidq->packet);
- /* No support for mispredict */
- be->flags.mispred = 0;
- be->flags.predicted = 1;
-
- /*
- * Increment bs->nr until reaching the number of last branches asked by
- * the user on the command line.
- */
- if (bs->nr < etmq->etm->synth_opts.last_branch_sz)
- bs->nr += 1;
-}
-
static int cs_etm__inject_event(struct cs_etm_auxtrace *etm, union perf_event *event,
struct perf_sample *sample, u64 type)
{
@@ -1619,6 +1532,46 @@ static inline u64 cs_etm__resolve_sample_time(struct cs_etm_queue *etmq,
return etm->latest_kernel_timestamp;
}
+static bool cs_etm__packet_has_taken_branch(struct cs_etm_packet *packet)
+{
+ if (packet->sample_type == CS_ETM_RANGE &&
+ packet->last_instr_taken_branch)
+ return true;
+
+ return false;
+}
+
+static void cs_etm__add_stack_event(struct cs_etm_queue *etmq,
+ struct cs_etm_traceid_queue *tidq)
+{
+ struct cs_etm_auxtrace *etm = etmq->etm;
+ u64 from, to;
+ int size;
+
+ if (!etm->synth_opts.branches && !etm->synth_opts.instructions)
+ return;
+
+ if (!cs_etm__packet_has_taken_branch(tidq->prev_packet))
+ return;
+
+ if (etmq->etm->synth_opts.last_branch) {
+ from = cs_etm__last_executed_instr(tidq->prev_packet);
+ to = cs_etm__first_executed_instr(tidq->packet);
+
+ size = cs_etm__instr_size(etmq, tidq, tidq->prev_packet, from);
+
+ /* Enable callchain so thread stack entry can be allocated */
+ thread_stack__event(tidq->frontend_thread, tidq->prev_packet->cpu,
+ tidq->prev_packet->flags, from, to, size,
+ etmq->buffer->buffer_nr + 1, false,
+ tidq->br_stack_sz, 0);
+ } else {
+ thread_stack__set_trace_nr(tidq->frontend_thread,
+ tidq->prev_packet->cpu,
+ etmq->buffer->buffer_nr + 1);
+ }
+}
+
static int cs_etm__synth_instruction_sample(struct cs_etm_queue *etmq,
struct cs_etm_traceid_queue *tidq,
struct cs_etm_packet *packet,
@@ -1649,8 +1602,11 @@ static int cs_etm__synth_instruction_sample(struct cs_etm_queue *etmq,
cs_etm__copy_insn(etmq, tidq, packet, &sample);
- if (etm->synth_opts.last_branch)
+ if (etm->synth_opts.last_branch) {
+ thread_stack__br_sample(tidq->frontend_thread, tidq->packet->cpu,
+ tidq->last_branch, tidq->br_stack_sz);
sample.branch_stack = tidq->last_branch;
+ }
if (etm->synth_opts.inject) {
ret = cs_etm__inject_event(etm, event, &sample,
@@ -1841,14 +1797,7 @@ static int cs_etm__sample(struct cs_etm_queue *etmq,
tidq->period_instructions += tidq->packet->instr_count;
- /*
- * Record a branch when the last instruction in
- * PREV_PACKET is a branch.
- */
- if (etm->synth_opts.last_branch &&
- tidq->prev_packet->sample_type == CS_ETM_RANGE &&
- tidq->prev_packet->last_instr_taken_branch)
- cs_etm__update_last_branch_rb(etmq, tidq);
+ cs_etm__add_stack_event(etmq, tidq);
if (etm->synth_opts.instructions &&
tidq->period_instructions >= etm->instructions_sample_period) {
@@ -1907,10 +1856,6 @@ static int cs_etm__sample(struct cs_etm_queue *etmq,
u64 offset = etm->instructions_sample_period - instrs_prev;
u64 addr;
- /* Prepare last branches for instruction sample */
- if (etm->synth_opts.last_branch)
- cs_etm__copy_last_branch_rb(etmq, tidq);
-
while (tidq->period_instructions >=
etm->instructions_sample_period) {
/*
@@ -1941,8 +1886,7 @@ static int cs_etm__sample(struct cs_etm_queue *etmq,
generate_sample = true;
/* Generate sample for branch taken packet */
- if (tidq->prev_packet->sample_type == CS_ETM_RANGE &&
- tidq->prev_packet->last_instr_taken_branch)
+ if (cs_etm__packet_has_taken_branch(tidq->prev_packet))
generate_sample = true;
if (generate_sample) {
@@ -1990,10 +1934,6 @@ static int cs_etm__flush(struct cs_etm_queue *etmq,
etmq->etm->synth_opts.instructions &&
tidq->prev_packet->sample_type == CS_ETM_RANGE) {
u64 addr;
-
- /* Prepare last branches for instruction sample */
- cs_etm__copy_last_branch_rb(etmq, tidq);
-
/*
* Generate a last branch event for the branches left in the
* circular buffer at the end of the trace.
@@ -2025,7 +1965,7 @@ static int cs_etm__flush(struct cs_etm_queue *etmq,
/* Reset last branches after flush the trace */
if (etm->synth_opts.last_branch)
- cs_etm__reset_last_branch_rb(tidq);
+ thread_stack__flush(tidq->frontend_thread);
return err;
}
@@ -2049,9 +1989,6 @@ static int cs_etm__end_block(struct cs_etm_queue *etmq,
tidq->prev_packet->sample_type == CS_ETM_RANGE) {
u64 addr;
- /* Prepare last branches for instruction sample */
- cs_etm__copy_last_branch_rb(etmq, tidq);
-
/*
* Use the address of the end of the last reported execution
* range.
--
2.34.1
^ permalink raw reply related
* [PATCH v9 4/9] perf cs-etm: Refactor instruction size handling
From: Leo Yan @ 2026-06-16 14:51 UTC (permalink / raw)
To: Arnaldo Carvalho de Melo, John Garry, Will Deacon, James Clark,
Mike Leach, Suzuki K Poulose, Namhyung Kim, Mark Rutland,
Alexander Shishkin, Jiri Olsa, Ian Rogers, Adrian Hunter,
Al Grant, Paschalis Mpeis, Amir Ayupov
Cc: linux-arm-kernel, coresight, linux-perf-users, Leo Yan, Leo Yan
In-Reply-To: <20260616-b4-arm_cs_callchain_support_v1-v9-0-f8fad931c413@arm.com>
From: Leo Yan <leo.yan@linaro.org>
This patch introduces a new function cs_etm__instr_size() to calculate
the instruction size based on ISA type and instruction address.
Given the trace data can be MB and most likely that will be A64/A32 on
a lot of platforms, cs_etm__instr_addr() keeps a single ISA type check
for A64/A32 and executes an optimized calculation (addr + offset * 4).
Signed-off-by: Leo Yan <leo.yan@linaro.org>
Reviewed-by: James Clark <james.clark@linaro.org>
Signed-off-by: Leo Yan <leo.yan@arm.com>
---
tools/perf/util/cs-etm.c | 43 ++++++++++++++++++++++---------------------
1 file changed, 22 insertions(+), 21 deletions(-)
diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c
index e2c3d2efb5982136abf9295159acab04271897a0..6827ef8871a8fc092500b93a8284d5d162558357 100644
--- a/tools/perf/util/cs-etm.c
+++ b/tools/perf/util/cs-etm.c
@@ -1371,6 +1371,18 @@ static inline int cs_etm__t32_instr_size(struct cs_etm_queue *etmq,
return ((instrBytes[1] & 0xF8) >= 0xE8) ? 4 : 2;
}
+static inline int cs_etm__instr_size(struct cs_etm_queue *etmq,
+ struct cs_etm_traceid_queue *tidq,
+ struct cs_etm_packet *packet,
+ u64 addr)
+{
+ if (packet->isa == CS_ETM_ISA_T32)
+ return cs_etm__t32_instr_size(etmq, tidq, packet, addr);
+
+ /* Otherwise, 4-byte instruction size for A32/A64 */
+ return 4;
+}
+
static inline u64 cs_etm__first_executed_instr(struct cs_etm_packet *packet)
{
/*
@@ -1399,19 +1411,17 @@ static inline u64 cs_etm__instr_addr(struct cs_etm_queue *etmq,
struct cs_etm_packet *packet,
u64 offset)
{
- if (packet->isa == CS_ETM_ISA_T32) {
- u64 addr = packet->start_addr;
+ u64 addr = packet->start_addr;
- while (offset) {
- addr += cs_etm__t32_instr_size(etmq, tidq, packet,
- addr);
- offset--;
- }
- return addr;
- }
+ /* 4-byte instruction size for A32/A64 */
+ if (packet->isa == CS_ETM_ISA_A64 || packet->isa == CS_ETM_ISA_A32)
+ return addr + offset * 4;
- /* Assume a 4 byte instruction size (A32/A64) */
- return packet->start_addr + offset * 4;
+ while (offset) {
+ addr += cs_etm__instr_size(etmq, tidq, packet, addr);
+ offset--;
+ }
+ return addr;
}
static void cs_etm__update_last_branch_rb(struct cs_etm_queue *etmq,
@@ -1581,16 +1591,7 @@ static void cs_etm__copy_insn(struct cs_etm_queue *etmq,
return;
}
- /*
- * T32 instruction size might be 32-bit or 16-bit, decide by calling
- * cs_etm__t32_instr_size().
- */
- if (packet->isa == CS_ETM_ISA_T32)
- sample->insn_len = cs_etm__t32_instr_size(etmq, tidq, packet,
- sample->ip);
- /* Otherwise, A64 and A32 instruction size are always 32-bit. */
- else
- sample->insn_len = 4;
+ sample->insn_len = cs_etm__instr_size(etmq, tidq, packet, sample->ip);
cs_etm__frontend_mem_access(etmq, tidq, packet, sample->ip,
sample->insn_len, (void *)sample->insn);
--
2.34.1
^ permalink raw reply related
* [PATCH v9 3/9] perf cs-etm: Decode ETE exception packets
From: Leo Yan @ 2026-06-16 14:51 UTC (permalink / raw)
To: Arnaldo Carvalho de Melo, John Garry, Will Deacon, James Clark,
Mike Leach, Suzuki K Poulose, Namhyung Kim, Mark Rutland,
Alexander Shishkin, Jiri Olsa, Ian Rogers, Adrian Hunter,
Al Grant, Paschalis Mpeis, Amir Ayupov
Cc: linux-arm-kernel, coresight, linux-perf-users, Leo Yan
In-Reply-To: <20260616-b4-arm_cs_callchain_support_v1-v9-0-f8fad931c413@arm.com>
ETE shares the same packet format as ETMv4, but exception decoding
handled ETMv4 packets only. As a result, ETE exception packets were
not classified.
Recognize the ETE magic for exception number decoding.
Reviewed-by: James Clark <james.clark@linaro.org>
Signed-off-by: Leo Yan <leo.yan@arm.com>
---
tools/perf/util/cs-etm.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c
index 42de2d82fd728bcc719adcab80670efa9859762f..e2c3d2efb5982136abf9295159acab04271897a0 100644
--- a/tools/perf/util/cs-etm.c
+++ b/tools/perf/util/cs-etm.c
@@ -2181,7 +2181,7 @@ static bool cs_etm__is_syscall(struct cs_etm_queue *etmq,
* HVC cases; need to check if it's SVC instruction based on
* packet address.
*/
- if (magic == __perf_cs_etmv4_magic) {
+ if (magic == __perf_cs_etmv4_magic || magic == __perf_cs_ete_magic) {
if (packet->exception_number == CS_ETMV4_EXC_CALL &&
cs_etm__is_svc_instr(etmq, tidq, prev_packet,
prev_packet->end_addr))
@@ -2204,7 +2204,7 @@ static bool cs_etm__is_async_exception(struct cs_etm_traceid_queue *tidq,
packet->exception_number == CS_ETMV3_EXC_FIQ)
return true;
- if (magic == __perf_cs_etmv4_magic)
+ if (magic == __perf_cs_etmv4_magic || magic == __perf_cs_ete_magic)
if (packet->exception_number == CS_ETMV4_EXC_RESET ||
packet->exception_number == CS_ETMV4_EXC_DEBUG_HALT ||
packet->exception_number == CS_ETMV4_EXC_SYSTEM_ERROR ||
@@ -2234,7 +2234,7 @@ static bool cs_etm__is_sync_exception(struct cs_etm_queue *etmq,
packet->exception_number == CS_ETMV3_EXC_GENERIC)
return true;
- if (magic == __perf_cs_etmv4_magic) {
+ if (magic == __perf_cs_etmv4_magic || magic == __perf_cs_ete_magic) {
if (packet->exception_number == CS_ETMV4_EXC_TRAP ||
packet->exception_number == CS_ETMV4_EXC_ALIGNMENT ||
packet->exception_number == CS_ETMV4_EXC_INST_FAULT ||
--
2.34.1
^ 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