Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH RFC net-next 02/10] net: stmmac: rename dev_id to userver
From: Russell King (Oracle) @ 2026-04-10  8:39 UTC (permalink / raw)
  To: Jitendra Vegiraju
  Cc: Andrew Lunn, Alexandre Torgue, Andrew Lunn, Chen-Yu Tsai,
	David S. Miller, Eric Dumazet, Jakub Kicinski, linux-arm-kernel,
	linux-stm32, linux-sunxi, netdev, Paolo Abeni, Samuel Holland
In-Reply-To: <CAMdnO-+TK65AxjTsDd017Mhop+VC3Xf8jtfaTXYpE6wBNZOt4g@mail.gmail.com>

On Thu, Apr 09, 2026 at 04:07:42PM -0700, Jitendra Vegiraju wrote:
> Hi Russell,
> 
> On Wed, Apr 8, 2026 at 2:27 AM Russell King (Oracle)
> <rmk+kernel@armlinux.org.uk> wrote:
> >
> > The Synopsys Databook and several implementation TRMs identify bits
> > 15:8 of the version register in dwmac v3.xx and v4.xx as "userver".
> > We even print its value with "User ID". Rather than using "dev_id",
> > use "userver" instead.
> >
> > Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
> > ---
> >  drivers/net/ethernet/stmicro/stmmac/hwif.c | 18 +++++++++---------
> >  1 file changed, 9 insertions(+), 9 deletions(-)
> >
> > diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.c b/drivers/net/ethernet/stmicro/stmmac/hwif.c
> > index 3774af66db48..830ff816ab4f 100644
> > --- a/drivers/net/ethernet/stmicro/stmmac/hwif.c
> > +++ b/drivers/net/ethernet/stmicro/stmmac/hwif.c
> > @@ -15,7 +15,7 @@
> >
> >  struct stmmac_version {
> >         u8 snpsver;
> > -       u8 dev_id;
> > +       u8 userver;
> >  };
> From the XGMAC databook that I have access to bits(15:8) identify the
> DEVID field of MAC_version register.
> The userver field is from bits(23:16) of the same register. This is a
> customer defined field (configured with coreConsultant).
> Currently stmmac doesn't care about bits(23:16).

Thanks for the additional information.

I don't have any XGMAC documentation, but this indicates that it differs
between XGMAC and previous cores - GMAC and GMAC4 cores, 15:8 are
documented as userver, and 31:16 are marked as reserved.

Note that the dev_info() also prints 15:8 as "User ID" not "Device ID".

To confirm, is the XGMAC version register at offset 0x20 ? Later GMAC
cores moved it to 0x110.

-- 
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 80Mbps down 10Mbps up. Decent connectivity at last!


^ permalink raw reply

* Re: [PATCH v2 8/8] arm64: dts: qcom: eliza: Add support for MM clock controllers
From: Bryan O'Donoghue @ 2026-04-10  8:26 UTC (permalink / raw)
  To: Taniya Das, Bjorn Andersson, Michael Turquette, Stephen Boyd,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio,
	Maxime Coquelin, Alexandre Torgue
  Cc: Ajit Pandey, Imran Shaik, Jagadeesh Kona, linux-arm-msm,
	linux-clk, devicetree, linux-kernel, linux-stm32,
	linux-arm-kernel
In-Reply-To: <328b388c-438e-4f91-9384-0dad903355a5@oss.qualcomm.com>

On 10/04/2026 04:55, Taniya Das wrote:
>> Why do these two controllers have no power-domains ?
> Bryan, on Eliza the videocc and camcc are connected on CX and MXA.

Shouldn't you at least have:

power-domains = <&rpmhpd RPMHPD_CX> ?

And even

power-domains = <&rpmhpd RPMHPD_MX>,
                 <&rpmhpd RPMHPD_CX>;
power-domain-names = "mx",
                      "cx";

Konrad's suggestion to me was that MXA should have a vote in my CSIPHY 
series I think he and Jagadeesh discussed it but I'm not sure if they 
_concluded_ what was the right thing to do.

Right now I'm representing the dependency. MXA is always on ... and 
there's nothing to do voting for it @ MX ?

---
bod


^ permalink raw reply

* RE: [PATCH v6 06/10] clk: realtek: Add support for mux clock
From: Yu-Chun Lin [林祐君] @ 2026-04-10  8:24 UTC (permalink / raw)
  To: Brian Masney
  Cc: mturquette@baylibre.com, sboyd@kernel.org, robh@kernel.org,
	krzk+dt@kernel.org, conor+dt@kernel.org, p.zabel@pengutronix.de,
	Edgar Lee [李承諭], afaerber@suse.com,
	Jyan Chou [周芷安], devicetree@vger.kernel.org,
	linux-clk@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org,
	linux-realtek-soc@lists.infradead.org,
	James Tai [戴志峰],
	CY_Huang[黃鉦晏],
	Stanley Chang[昌育德]
In-Reply-To: <ac_UkRiqWb6fSc1I@redhat.com>

Hi Brian,

> Hi Yu-Chun and Cheng-Yu,
> 
> On Thu, Apr 02, 2026 at 03:39:53PM +0800, Yu-Chun Lin wrote:
> > From: Cheng-Yu Lee <cylee12@realtek.com>
> >
> > Add a simple regmap-based clk_ops implementation for Realtek mux clocks.
> >
> > The implementation supports parent selection and rate determination
> > through regmap-backed register access.
> >
> > Signed-off-by: Cheng-Yu Lee <cylee12@realtek.com>
> > Co-developed-by: Yu-Chun Lin <eleanor.lin@realtek.com>
> > Signed-off-by: Yu-Chun Lin <eleanor.lin@realtek.com>
> > ---
> > Changes in v6:
> > - Add the headers used in c file to follow the "Include What You Use"
> principle.
> > ---
> >  drivers/clk/realtek/Makefile         |  1 +
> >  drivers/clk/realtek/clk-regmap-mux.c | 48
> > ++++++++++++++++++++++++++++  drivers/clk/realtek/clk-regmap-mux.h |
> > 43 +++++++++++++++++++++++++
> >  3 files changed, 92 insertions(+)
> >  create mode 100644 drivers/clk/realtek/clk-regmap-mux.c
> >  create mode 100644 drivers/clk/realtek/clk-regmap-mux.h
> >
> > diff --git a/drivers/clk/realtek/Makefile
> > b/drivers/clk/realtek/Makefile index 74375f8127ac..f90dc57fcfdb 100644
> > --- a/drivers/clk/realtek/Makefile
> > +++ b/drivers/clk/realtek/Makefile
> > @@ -5,4 +5,5 @@ clk-rtk-y += common.o
> >
> >  clk-rtk-y += clk-pll.o
> >  clk-rtk-y += clk-regmap-gate.o
> > +clk-rtk-y += clk-regmap-mux.o
> >  clk-rtk-y += freq_table.o
> > diff --git a/drivers/clk/realtek/clk-regmap-mux.c
> > b/drivers/clk/realtek/clk-regmap-mux.c
> > new file mode 100644
> > index 000000000000..068b056d61f0
> > --- /dev/null
> > +++ b/drivers/clk/realtek/clk-regmap-mux.c
> > @@ -0,0 +1,48 @@
> > +// SPDX-License-Identifier: GPL-2.0-only
> > +/*
> > + * Copyright (C) 2017 Realtek Semiconductor Corporation
> > + * Author: Cheng-Yu Lee <cylee12@realtek.com>  */
> > +
> > +#include <linux/regmap.h>
> > +#include <linux/clk-provider.h>
> 
> Sort the includes.
> 

Ack.

> > +#include "clk-regmap-mux.h"
> > +
> > +static u8 clk_regmap_mux_get_parent(struct clk_hw *hw) {
> > +     struct clk_regmap_mux *clkm = to_clk_regmap_mux(hw);
> > +     int num_parents = clk_hw_get_num_parents(hw);
> > +     u32 val;
> > +     int ret;
> > +
> > +     ret = regmap_read(clkm->clkr.regmap, clkm->mux_ofs, &val);
> > +     if (ret)
> > +             return 0;
> 
> This is another case where it'd be nice to get the get_parent declaration fixed.
> Stephen recently linked to some work of his from 2022 here.
> 
> https://lore.kernel.org/linux-clk/177431305509.5403.15386021337517970667
> @lazor/
> 
> There's nothing for you to do right now.
> 
> > +
> > +     val = val >> clkm->shift & clkm->mask;
> 
> I know there's the order of operations, however for clarity I would just include
> some () here to make it clear the expected order.

Ack.

> > +
> > +     if (val >= num_parents)
> 
> Remove newline before if.

Ack.

> 
> > +             return 0;
> > +
> > +     return val;
> 
> Or you could just use a ternary operator:
> 
> return val >= num_parents ? 0 : val;
> 

Ack.

> > +}
> > +
> > +static int clk_regmap_mux_set_parent(struct clk_hw *hw, u8 index) {
> > +     struct clk_regmap_mux *clkm = to_clk_regmap_mux(hw);
> > +
> > +     return regmap_update_bits(clkm->clkr.regmap, clkm->mux_ofs,
> > +                               clkm->mask << clkm->shift, index <<
> > +clkm->shift); }
> > +
> > +const struct clk_ops rtk_clk_regmap_mux_ops = {
> > +     .set_parent = clk_regmap_mux_set_parent,
> > +     .get_parent = clk_regmap_mux_get_parent,
> > +     .determine_rate = __clk_mux_determine_rate, };
> > +EXPORT_SYMBOL_NS_GPL(rtk_clk_regmap_mux_ops, "REALTEK_CLK");
> > +
> > +const struct clk_ops rtk_clk_regmap_mux_ro_ops = {
> > +     .get_parent = clk_regmap_mux_get_parent, };
> > +EXPORT_SYMBOL_NS_GPL(rtk_clk_regmap_mux_ro_ops, "REALTEK_CLK");
> 
> rtk_clk_regmap_mux_ro_ops is exported, however the declaration is not
> actually declared in any header files.
> 
> Brian

Since it is currently unused, I will drop the 'rtk_clk_regmap_mux_ro_ops'
implementation.

Best Regards,
Yu-Chun.

^ permalink raw reply

* Re: [PATCH v6 05/10] clk: realtek: Add support for gate clock
From: Yu-Chun Lin @ 2026-04-10  8:19 UTC (permalink / raw)
  To: bmasney
  Cc: afaerber, conor+dt, cy.huang, cylee12, devicetree, eleanor.lin,
	james.tai, jyanchou, krzk+dt, linux-arm-kernel, linux-clk,
	linux-kernel, linux-realtek-soc, mturquette, p.zabel, robh, sboyd,
	stanley_chang
In-Reply-To: <ac_RcGSpVBpt3S7C@redhat.com>

Hi Brian,

> Hi Cheng-Yu,
> 
> On Thu, Apr 02, 2026 at 03:39:52PM +0800, Yu-Chun Lin wrote:
> > From: Cheng-Yu Lee <cylee12@realtek.com>
> > 
> > Introduce clk_regmap_gate_ops supporting enable, disable, is_enabled, and
> > disable_unused for standard regmap gate clocks.
>
> disable_unused is not implemented below.
>

Will remove it from commit message.

> > 
> > Add clk_regmap_gate_ro_ops as a read-only variant exposing only is_enabled.
> > 
> > Signed-off-by: Cheng-Yu Lee <cylee12@realtek.com>
> > Co-developed-by: Yu-Chun Lin <eleanor.lin@realtek.com>
> > Signed-off-by: Yu-Chun Lin <eleanor.lin@realtek.com>
> > ---
> > Changes in v6:
> > - Add the headers used in c file to follow the "Include What You Use" principle.
> > ---
> >  drivers/clk/realtek/Makefile          |  2 +
> >  drivers/clk/realtek/clk-regmap-gate.c | 69 +++++++++++++++++++++++++++
> >  drivers/clk/realtek/clk-regmap-gate.h | 65 +++++++++++++++++++++++++
> >  3 files changed, 136 insertions(+)
> >  create mode 100644 drivers/clk/realtek/clk-regmap-gate.c
> >  create mode 100644 drivers/clk/realtek/clk-regmap-gate.h
> > 
> > diff --git a/drivers/clk/realtek/Makefile b/drivers/clk/realtek/Makefile
> > index a89ad77993e9..74375f8127ac 100644
> > --- a/drivers/clk/realtek/Makefile
> > +++ b/drivers/clk/realtek/Makefile
> > @@ -2,5 +2,7 @@
> >  obj-$(CONFIG_RTK_CLK_COMMON) += clk-rtk.o
> >  
> >  clk-rtk-y += common.o
> > +
> >  clk-rtk-y += clk-pll.o
> > +clk-rtk-y += clk-regmap-gate.o
> >  clk-rtk-y += freq_table.o
> > diff --git a/drivers/clk/realtek/clk-regmap-gate.c b/drivers/clk/realtek/clk-regmap-gate.c
> > new file mode 100644
> > index 000000000000..8738d6c6f8dd
> > --- /dev/null
> > +++ b/drivers/clk/realtek/clk-regmap-gate.c
> > @@ -0,0 +1,69 @@
> > +// SPDX-License-Identifier: GPL-2.0-only
> > +/*
> > + * Copyright (C) 2017 Realtek Semiconductor Corporation
> > + * Author: Cheng-Yu Lee <cylee12@realtek.com>
> > + */
> > +
> > +#include <linux/regmap.h>
> > +#include <linux/bits.h>
> > +#include "clk-regmap-gate.h"
> > +#include <linux/clk-provider.h>
>
> linux/clk-provider.h needs to be included before clk-regmap-gate.h.
>

Ack.

> Also Sashiko reports that linux/export.h should also be included.
https://sashiko.dev/#/patchset/20260402073957.2742459-1-eleanor.lin%40realtek.com
> 
> Brian

Ack.

Best Regards,
Yu-Chun.


^ permalink raw reply

* Re: [PATCH net 1/1] net: stmmac: Update default_an_inband before passing value to phylink_config
From: KhaiWenTan @ 2026-04-10  7:53 UTC (permalink / raw)
  To: linux
  Cc: alexandre.torgue, andrew+netdev, davem, edumazet, hong.aun.looi,
	khai.wen.tan, khai.wen.tan, kuba, linux-arm-kernel, linux-kernel,
	linux-stm32, maxime.chevallier, mcoquelin.stm32, netdev,
	ovidiu.panait.rb, pabeni, vladimir.oltean, yoong.siang.song
In-Reply-To: <adirrTJujEsrsK4F@shell.armlinux.org.uk>

Hi Russell,

Thanks for the review. I will address the comments in v2.


^ permalink raw reply

* Re: [PATCH v6 04/10] clk: realtek: Add support for phase locked loops (PLLs)
From: Yu-Chun Lin @ 2026-04-10  7:53 UTC (permalink / raw)
  To: bmasney
  Cc: afaerber, conor+dt, cy.huang, cylee12, devicetree, eleanor.lin,
	james.tai, jyanchou, krzk+dt, linux-arm-kernel, linux-clk,
	linux-kernel, linux-realtek-soc, mturquette, p.zabel, robh, sboyd,
	stanley_chang
In-Reply-To: <ac_SX1UJRqiBH2iM@redhat.com>

Hi Brian,

> Hi Cheng-Yu and Yu-Chun,
>
> On Thu, Apr 02, 2026 at 03:39:51PM +0800, Yu-Chun Lin wrote:
> > From: Cheng-Yu Lee <cylee12@realtek.com>
> >
> > Provide a full set of PLL operations for programmable PLLs and a read-only
> > variant for fixed or hardware-managed PLLs.
> >
> > Signed-off-by: Cheng-Yu Lee <cylee12@realtek.com>
> > Co-developed-by: Yu-Chun Lin <eleanor.lin@realtek.com>
> > Signed-off-by: Yu-Chun Lin <eleanor.lin@realtek.com>
> > ---
> > +static int clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
> > +			    unsigned long parent_rate)
> > +{
> > +	struct clk_pll *clkp = to_clk_pll(hw);
> > +	const struct freq_table *fv;
> > +	int ret;
> > +
> > +	fv = ftbl_find_by_rate(clkp->freq_tbl, rate);
> > +	if (!fv || fv->rate != rate)
> > +		return -EINVAL;
> > +
> > +	if (clkp->seq_pre_set_freq) {
> > +		ret = regmap_multi_reg_write(clkp->clkr.regmap, clkp->seq_pre_set_freq,
> > +					     clkp->num_seq_pre_set_freq);
> > +		if (ret)
> > +			return ret;
> > +	}
> > +
> > +	ret = regmap_update_bits(clkp->clkr.regmap, clkp->freq_reg,
> > +				 clkp->freq_mask, fv->val);
> > +	if (ret)
> > +		return ret;
> > +
> > +	if (clkp->seq_post_set_freq) {
> > +		ret = regmap_multi_reg_write(clkp->clkr.regmap, clkp->seq_post_set_freq,
> > +					     clkp->num_seq_post_set_freq);
> > +		if (ret)
> > +			return ret;
> > +	}
> > +
> > +	if (is_power_on(clkp)) {
> > +		ret = wait_freq_ready(clkp);
>
> I should have checked Sashiko before I hit send on my last review.
> https://sashiko.dev/#/patchset/20260402073957.2742459-1-eleanor.lin%40realtek.com
>
> It suggested the following:
>
>    In the Common Clock Framework, .set_rate executes under the prepare_lock
>    mutex, while .enable and .disable execute under the enable_lock spinlock.
>
>    Could an interleaved clk_pll_enable() corrupt the hardware state by running
>    its seq_power_on sequence concurrently with these multi-step register
>    updates?
>
>    There also appears to be a potential race condition later in this function:
>
>        if (is_power_on(clkp)) {
>            ret = wait_freq_ready(clkp);
>            ...
>        }
>    
>    If .disable() powers off the PLL right before wait_freq_ready() is called,
>    will wait_freq_ready() poll a disabled PLL and erroneously return
>    -ETIMEDOUT? Is a private spinlock needed to serialize these operations?
>
> Brian
>

Agreed, I will add a private spinlock here.

Best Regards,
Yu-Chun


^ permalink raw reply

* Re: [PATCH net 1/1] net: stmmac: Update default_an_inband before passing value to phylink_config
From: Russell King (Oracle) @ 2026-04-10  7:50 UTC (permalink / raw)
  To: KhaiWenTan
  Cc: andrew+netdev, davem, edumazet, kuba, pabeni, mcoquelin.stm32,
	alexandre.torgue, maxime.chevallier, ovidiu.panait.rb,
	vladimir.oltean, netdev, linux-stm32, linux-arm-kernel,
	linux-kernel, yoong.siang.song, hong.aun.looi, khai.wen.tan
In-Reply-To: <20260410020735.327590-1-khai.wen.tan@linux.intel.com>

On Fri, Apr 10, 2026 at 10:07:35AM +0800, KhaiWenTan wrote:
> get_interfaces() will update both the plat->phy_interfaces and
> mdio_bus_data->default_an_inband based on reading a SERDES register.
> 
> Therefore, we moved the priv->plat->get_interfaces() to be executed
> first before assigning mdio_bus_data->default_an_inband to
> config->default_an_inband to ensure default_an_inband is in correct
> value during PHY setup.
> 
> Fixes: ca732e990fc8 ("net: stmmac: add get_interfaces() platform method")
> Signed-off-by: KhaiWenTan <khai.wen.tan@linux.intel.com>

Patch looks good, but the blamed commit is wrong.

d3836052fe09 ("net: stmmac: intel: convert speed_mode_2500() to get_interfaces()")

introduced the problem.

The commit message could also do with mentioning that dwmac-intel
regressed result of that commit.

-- 
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 80Mbps down 10Mbps up. Decent connectivity at last!


^ permalink raw reply

* Re: [PATCH v2 3/8] dt-bindings: clock: qcom: Add support for CAMCC for Eliza
From: Krzysztof Kozlowski @ 2026-04-10  7:47 UTC (permalink / raw)
  To: Taniya Das
  Cc: Bjorn Andersson, Michael Turquette, Stephen Boyd, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio, Maxime Coquelin,
	Alexandre Torgue, Ajit Pandey, Imran Shaik, Jagadeesh Kona,
	linux-arm-msm, linux-clk, devicetree, linux-kernel, linux-stm32,
	linux-arm-kernel
In-Reply-To: <20260409-eliza_mm_cc_v2-v2-3-bc0c6dd77bc5@oss.qualcomm.com>

On Thu, Apr 09, 2026 at 11:40:44PM +0530, Taniya Das wrote:
> Update the compatible and the bindings for CAMCC support on Eliza SoC.

I do not see any update here. Also, no improvements after v1 comments.

Best regards,
Krzysztof



^ permalink raw reply

* Re: [PATCH v13 10/17] drm/bridge: analogix_dp: Pass struct drm_atomic_state* for analogix_dp_bridge_mode_set()
From: Luca Ceresoli @ 2026-04-10  7:45 UTC (permalink / raw)
  To: Damon Ding, andrzej.hajda, neil.armstrong, rfoss,
	maarten.lankhorst, mripard, tzimmermann, airlied, simona,
	victor.liu, Frank.Li, shawnguo, s.hauer, inki.dae, sw0312.kim,
	kyungmin.park, krzk, jingoohan1, p.zabel, hjc, heiko, andy.yan
  Cc: Laurent.pinchart, jonas, jernej.skrabec, kernel, festevam,
	alim.akhtar, dmitry.baryshkov, nicolas.frattaroli, dianders,
	m.szyprowski, linux-kernel, dri-devel, imx, linux-arm-kernel,
	linux-samsung-soc, linux-rockchip
In-Reply-To: <20260409065301.446670-11-damon.ding@rock-chips.com>

On Thu Apr 9, 2026 at 8:52 AM CEST, Damon Ding wrote:
> To avoid using &analogix_dp_device.connector for compatibility
> with the bridge connector framework, get &drm_connector from
> &drm_atomic_state instead.
>
> Signed-off-by: Damon Ding <damon.ding@rock-chips.com>

Reviewed-by: Luca Ceresoli <luca.ceresoli@bootlin.com>

--
Luca Ceresoli, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com


^ permalink raw reply

* Re: [PATCH v2 8/8] arm64: dts: qcom: eliza: Add support for MM clock controllers
From: Krzysztof Kozlowski @ 2026-04-10  7:44 UTC (permalink / raw)
  To: Taniya Das
  Cc: Bjorn Andersson, Michael Turquette, Stephen Boyd, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio, Maxime Coquelin,
	Alexandre Torgue, Ajit Pandey, Imran Shaik, Jagadeesh Kona,
	linux-arm-msm, linux-clk, devicetree, linux-kernel, linux-stm32,
	linux-arm-kernel
In-Reply-To: <20260409-eliza_mm_cc_v2-v2-8-bc0c6dd77bc5@oss.qualcomm.com>

On Thu, Apr 09, 2026 at 11:40:49PM +0530, Taniya Das wrote:
> Add the device nodes for the multimedia clock controllers (cambistmclkcc,
> camcc, videocc, gpucc) for Qualcomm Eliza SoC.
> 
> Signed-off-by: Taniya Das <taniya.das@oss.qualcomm.com>
> ---
>  arch/arm64/boot/dts/qcom/eliza.dtsi | 54 +++++++++++++++++++++++++++++++++++++
>  1 file changed, 54 insertions(+)

Note that this patch and drivers parches were likely not tested.

Please mark patches you wish others to test as RFT.

Best regards,
Krzysztof



^ permalink raw reply

* RE: [PATCH v6 04/10] clk: realtek: Add support for phase locked loops (PLLs)
From: Yu-Chun Lin [林祐君] @ 2026-04-10  7:43 UTC (permalink / raw)
  To: Brian Masney
  Cc: mturquette@baylibre.com, sboyd@kernel.org, robh@kernel.org,
	krzk+dt@kernel.org, conor+dt@kernel.org, p.zabel@pengutronix.de,
	Edgar Lee [李承諭], afaerber@suse.com,
	Jyan Chou [周芷安], devicetree@vger.kernel.org,
	linux-clk@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org,
	linux-realtek-soc@lists.infradead.org,
	James Tai [戴志峰],
	CY_Huang[黃鉦晏],
	Stanley Chang[昌育德]
In-Reply-To: <ac_QBGY8VxcvuVlY@redhat.com>

Hi Brian,

> Hi Cheng-Yu,
> 
> On Thu, Apr 02, 2026 at 03:39:51PM +0800, Yu-Chun Lin wrote:
> > From: Cheng-Yu Lee <cylee12@realtek.com>
> >
> > Provide a full set of PLL operations for programmable PLLs and a
> > read-only variant for fixed or hardware-managed PLLs.
> >
> > Signed-off-by: Cheng-Yu Lee <cylee12@realtek.com>
> > Co-developed-by: Yu-Chun Lin <eleanor.lin@realtek.com>
> > Signed-off-by: Yu-Chun Lin <eleanor.lin@realtek.com>
> > ---
> > Changes in v6:
> > - Add the headers used in c file to follow the "Include What You Use"
> principle.
> > - Move to_clk_pll() from clk-pll.h to clk-pll.c to limit its scope.
> > ---
> >  drivers/clk/realtek/Makefile     |   2 +
> >  drivers/clk/realtek/clk-pll.c    | 164
> +++++++++++++++++++++++++++++++
> >  drivers/clk/realtek/clk-pll.h    |  42 ++++++++
> >  drivers/clk/realtek/freq_table.c |  36 +++++++
> > drivers/clk/realtek/freq_table.h |  21 ++++
> >  5 files changed, 265 insertions(+)
> >  create mode 100644 drivers/clk/realtek/clk-pll.c  create mode 100644
> > drivers/clk/realtek/clk-pll.h  create mode 100644
> > drivers/clk/realtek/freq_table.c  create mode 100644
> > drivers/clk/realtek/freq_table.h
> >
> > diff --git a/drivers/clk/realtek/Makefile
> > b/drivers/clk/realtek/Makefile index 377ec776ee47..a89ad77993e9 100644
> > --- a/drivers/clk/realtek/Makefile
> > +++ b/drivers/clk/realtek/Makefile
> > @@ -2,3 +2,5 @@
> >  obj-$(CONFIG_RTK_CLK_COMMON) += clk-rtk.o
> >
> >  clk-rtk-y += common.o
> > +clk-rtk-y += clk-pll.o
> > +clk-rtk-y += freq_table.o
> > diff --git a/drivers/clk/realtek/clk-pll.c
> > b/drivers/clk/realtek/clk-pll.c new file mode 100644 index
> > 000000000000..44730b22a94c
> > --- /dev/null
> > +++ b/drivers/clk/realtek/clk-pll.c
> > @@ -0,0 +1,164 @@
> > +// SPDX-License-Identifier: GPL-2.0-only
> > +/*
> > + * Copyright (C) 2024 Realtek Semiconductor Corporation
> > + * Author: Cheng-Yu Lee <cylee12@realtek.com>  */
> > +
> > +#include <linux/regmap.h>
> > +#include "clk-pll.h"
> > +
> > +#define TIMEOUT 2000
> > +
> > +static inline struct clk_pll *to_clk_pll(struct clk_hw *hw) {
> > +     struct clk_regmap *clkr = to_clk_regmap(hw);
> > +
> > +     return container_of(clkr, struct clk_pll, clkr); }
> > +
> > +static int wait_freq_ready(struct clk_pll *clkp) {
> > +     u32 pollval;
> > +
> > +     if (!clkp->freq_ready_valid)
> > +             return 0;
> > +
> > +     return regmap_read_poll_timeout_atomic(clkp->clkr.regmap,
> clkp->freq_ready_reg, pollval,
> > +                                             (pollval &
> clkp->freq_ready_mask)
> > +                                             ==
> clkp->freq_ready_val,
> > + 0, TIMEOUT);
> 
> I would put the "(pollval & clkp->freq_ready_mask) == clkp->freq_ready_val"
> on the same line to improve readability. You can go out to 100 characters.
> 
> Also should the delay be greater than 0 to avoid tons of constant retries?
> 

Since aligning with the open parenthesis would exceed the 100-character limit,
I will use an extra tab for the continuation line.

Also, I have increased the delay_us parameter to 1 to avoid constant retries.

The code will look like this:

	return regmap_read_poll_timeout_atomic(clkp->clkr.regmap, clkp->freq_ready_reg, pollval,
		(pollval & clkp->freq_ready_mask) == clkp->freq_ready_val, 1, TIMEOUT);

> > +}
> > +
> > +static bool is_power_on(struct clk_pll *clkp) {
> > +     u32 val;
> > +
> > +     if (!clkp->power_reg)
> > +             return true;
> > +
> > +     if (regmap_read(clkp->clkr.regmap, clkp->power_reg, &val))
> > +             return true;
> 
> Is the intention if there is an error, then it marks it as success?
> 

Returning true here is a conservative design choice. When reading the power
status fails, returning true prevents unconditionally turning off the clock.
> > +
> > +     return (val & clkp->power_mask) == clkp->power_val_on; }
> > +
> > +static void clk_pll_disable(struct clk_hw *hw) {
> > +     struct clk_pll *clkp = to_clk_pll(hw);
> > +
> > +     if (!clkp->seq_power_off)
> > +             return;
> > +
> > +     regmap_multi_reg_write(clkp->clkr.regmap, clkp->seq_power_off,
> > +                            clkp->num_seq_power_off); }
> > +
> > +static int clk_pll_is_enabled(struct clk_hw *hw) {
> > +     struct clk_pll *clkp = to_clk_pll(hw);
> > +
> > +     return is_power_on(clkp);
> > +}
> > +
> > +static int clk_pll_determine_rate(struct clk_hw *hw,
> > +                               struct clk_rate_request *req) {
> > +     struct clk_pll *clkp = to_clk_pll(hw);
> > +     const struct freq_table *ftblv = NULL;
> > +
> > +     ftblv = ftbl_find_by_rate(clkp->freq_tbl, req->rate);
> > +     if (!ftblv)
> > +             return -EINVAL;
> > +
> > +     req->rate = ftblv->rate;
> > +     return 0;
> 
> Add newline before return.
> 

Ack.

> > +}
> > +
> > +static unsigned long clk_pll_recalc_rate(struct clk_hw *hw,
> > +                                      unsigned long parent_rate) {
> > +     struct clk_pll *clkp = to_clk_pll(hw);
> > +     const struct freq_table *fv;
> > +     u32 freq_val;
> > +
> > +     if (regmap_read(clkp->clkr.regmap, clkp->freq_reg, &freq_val))
> > +             return 0;
> > +
> > +     freq_val &= clkp->freq_mask;
> > +
> > +     fv = ftbl_find_by_val_with_mask(clkp->freq_tbl, clkp->freq_mask,
> > +                                     freq_val);
> > +     return fv ? fv->rate : 0;
> 
> Add newline before return.
> 

Ack.

> > +}
> > +

(snip)

> > index 000000000000..272a10e75a54
> > --- /dev/null
> > +++ b/drivers/clk/realtek/freq_table.c
> > @@ -0,0 +1,36 @@
> > +// SPDX-License-Identifier: GPL-2.0-only
> > +
> > +#include <linux/bitops.h>
> > +#include "freq_table.h"
> > +
> > +const struct freq_table *ftbl_find_by_rate(const struct freq_table *ftbl,
> > +                                        unsigned long rate) {
> > +     unsigned long best_rate = 0;
> > +     const struct freq_table *best = NULL;
> 
> Put variables in reverse Christmas tree order.

Ack

> 
> > +
> > +     for (; !IS_FREQ_TABLE_END(ftbl); ftbl++) {
> > +             if (ftbl->rate == rate)
> > +                     return ftbl;
> > +
> > +             if (ftbl->rate > rate)
> > +                     continue;
> > +
> > +             if (ftbl->rate > best_rate) {
> > +                     best_rate = ftbl->rate;
> > +                     best = ftbl;
> > +             }
> > +     }
> > +
> > +     return best;
> > +}
> > +
> > +const struct freq_table *
> > +ftbl_find_by_val_with_mask(const struct freq_table *ftbl, u32 mask,
> > +u32 value) {
> > +     for (; !IS_FREQ_TABLE_END(ftbl); ftbl++) {
> > +             if ((ftbl->val & mask) == (value & mask))
> > +                     return ftbl;
> > +     }
> > +     return NULL;
> > +};
> > diff --git a/drivers/clk/realtek/freq_table.h
> > b/drivers/clk/realtek/freq_table.h
> > new file mode 100644
> > index 000000000000..6d9116651105
> > --- /dev/null
> > +++ b/drivers/clk/realtek/freq_table.h
> > @@ -0,0 +1,21 @@
> > +/* SPDX-License-Identifier: GPL-2.0-only */
> > +
> > +struct freq_table {
> > +     u32 val;
> > +     unsigned long rate;
> > +};
> > +
> > +/* ofs check */
> > +#define CLK_OFS_INVALID        -1
> > +#define CLK_OFS_IS_VALID(_ofs) ((_ofs) != CLK_OFS_INVALID)
> 
> Is this used anywhere?

I will drop them.

Best Regards,
Yu-Chun

> 
> Brian

^ permalink raw reply

* [PATCH v2 5/5] coresight: etm3x: fix inconsistencies with sysfs configration
From: Yeoreum Yun @ 2026-04-10  7:43 UTC (permalink / raw)
  To: coresight, linux-arm-kernel, linux-kernel
  Cc: suzuki.poulose, mike.leach, james.clark, alexander.shishkin,
	leo.yan, Yeoreum Yun
In-Reply-To: <20260410074310.2693385-1-yeoreum.yun@arm.com>

The current ETM3x configuration via sysfs can lead to the following
inconsistencies:

  - If a configuration is modified via sysfs while a perf session is
    active, the running configuration may differ between before
    a sched-out and after a subsequent sched-in.

To resolve these inconsistencies, the configuration should be separated into:

  - active_config, which is applied configuration for the current session
  - config, which stores the settings configured via sysfs.

and apply configuration after taking a mode.

Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
---
 drivers/hwtracing/coresight/coresight-etm.h   |  2 ++
 .../coresight/coresight-etm3x-core.c          | 20 ++++++++++++-------
 2 files changed, 15 insertions(+), 7 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-etm.h b/drivers/hwtracing/coresight/coresight-etm.h
index 6fda26039db8..9ed5e2361be1 100644
--- a/drivers/hwtracing/coresight/coresight-etm.h
+++ b/drivers/hwtracing/coresight/coresight-etm.h
@@ -241,6 +241,7 @@ struct etm_config {
  * @boot_enable:true if we should start tracing at boot time.
  * @os_unlock:	true if access to management registers is allowed.
  * @traceid:	value of the current ID for this component.
+ * @active_config:	structure holding current running configuration parameters.
  * @config:	structure holding configuration parameters.
  */
 struct etm_drvdata {
@@ -256,6 +257,7 @@ struct etm_drvdata {
 	bool				boot_enable;
 	bool				os_unlock;
 	u32				traceid;
+	struct etm_config		active_config;
 	struct etm_config		config;
 };
 
diff --git a/drivers/hwtracing/coresight/coresight-etm3x-core.c b/drivers/hwtracing/coresight/coresight-etm3x-core.c
index b7e977defb1c..0afe2275aa27 100644
--- a/drivers/hwtracing/coresight/coresight-etm3x-core.c
+++ b/drivers/hwtracing/coresight/coresight-etm3x-core.c
@@ -308,7 +308,7 @@ void etm_config_trace_mode(struct etm_config *config)
 static int etm_parse_event_config(struct etm_drvdata *drvdata,
 				  struct perf_event *event)
 {
-	struct etm_config *config = &drvdata->config;
+	struct etm_config *config = &drvdata->active_config;
 	struct perf_event_attr *attr = &event->attr;
 	u8 ts_level;
 
@@ -368,7 +368,7 @@ static int etm_enable_hw(struct etm_drvdata *drvdata)
 	int i, rc;
 	u32 etmcr;
 	const struct etm_caps *caps = &drvdata->caps;
-	struct etm_config *config = &drvdata->config;
+	struct etm_config *config = &drvdata->active_config;
 	struct coresight_device *csdev = drvdata->csdev;
 
 	CS_UNLOCK(drvdata->csa.base);
@@ -442,24 +442,30 @@ static int etm_enable_hw(struct etm_drvdata *drvdata)
 
 struct etm_enable_arg {
 	struct etm_drvdata *drvdata;
+	u32 traceid;
 	int rc;
 };
 
 static void etm_enable_sysfs_smp_call(void *info)
 {
 	struct etm_enable_arg *arg = info;
+	struct etm_drvdata *drvdata;
 	struct coresight_device *csdev;
 
 	if (WARN_ON(!arg))
 		return;
 
-	csdev = arg->drvdata->csdev;
+	drvdata = arg->drvdata;
+	csdev = drvdata->csdev;
 	if (!coresight_take_mode(csdev, CS_MODE_SYSFS)) {
 		/* Someone is already using the tracer */
 		arg->rc = -EBUSY;
 		return;
 	}
 
+	drvdata->active_config = drvdata->config;
+	drvdata->traceid = arg->traceid;
+
 	arg->rc = etm_enable_hw(arg->drvdata);
 
 	/* The tracer didn't start */
@@ -514,14 +520,13 @@ static int etm_enable_sysfs(struct coresight_device *csdev, struct coresight_pat
 
 	spin_lock(&drvdata->spinlock);
 
-	drvdata->traceid = path->trace_id;
-
 	/*
 	 * Configure the ETM only if the CPU is online.  If it isn't online
 	 * hw configuration will take place on the local CPU during bring up.
 	 */
 	if (cpu_online(drvdata->cpu)) {
 		arg.drvdata = drvdata;
+		arg.traceid = path->trace_id;
 		ret = smp_call_function_single(drvdata->cpu,
 					       etm_enable_sysfs_smp_call, &arg, 1);
 		if (!ret)
@@ -564,7 +569,7 @@ static int etm_enable(struct coresight_device *csdev, struct perf_event *event,
 static void etm_disable_hw(struct etm_drvdata *drvdata)
 {
 	int i;
-	struct etm_config *config = &drvdata->config;
+	struct etm_config *config = &drvdata->active_config;
 	struct coresight_device *csdev = drvdata->csdev;
 
 	CS_UNLOCK(drvdata->csa.base);
@@ -882,7 +887,8 @@ static int etm_probe(struct amba_device *adev, const struct amba_id *id)
 	if (etm_arch_supported(drvdata->arch) == false)
 		return -EINVAL;
 
-	etm_set_default(&drvdata->config);
+	etm_set_default(&drvdata->active_config);
+	drvdata->config = drvdata->active_config;
 
 	pdata = coresight_get_platform_data(dev);
 	if (IS_ERR(pdata))
-- 
LEVI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}



^ permalink raw reply related

* [PATCH v2 1/5] coresight: etm4x: introduce struct etm4_caps
From: Yeoreum Yun @ 2026-04-10  7:43 UTC (permalink / raw)
  To: coresight, linux-arm-kernel, linux-kernel
  Cc: suzuki.poulose, mike.leach, james.clark, alexander.shishkin,
	leo.yan, Yeoreum Yun
In-Reply-To: <20260410074310.2693385-1-yeoreum.yun@arm.com>

introduce struct etm4_caps to describe ETMv4 capabilities
and move capabilities information into it.

Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
---
 .../coresight/coresight-etm4x-core.c          | 234 +++++++++---------
 .../coresight/coresight-etm4x-sysfs.c         | 185 ++++++++------
 drivers/hwtracing/coresight/coresight-etm4x.h | 175 ++++++-------
 3 files changed, 327 insertions(+), 267 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c
index d565a73f0042..6443f3717b37 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x-core.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c
@@ -88,8 +88,9 @@ static int etm4_probe_cpu(unsigned int cpu);
  */
 static bool etm4x_sspcicrn_present(struct etmv4_drvdata *drvdata, int n)
 {
-	return (n < drvdata->nr_ss_cmp) &&
-	       drvdata->nr_pe &&
+	const struct etmv4_caps *caps = &drvdata->caps;
+
+	return (n < caps->nr_ss_cmp) && caps->nr_pe &&
 	       (drvdata->config.ss_status[n] & TRCSSCSRn_PC);
 }
 
@@ -160,17 +161,20 @@ static void ete_sysreg_write(u64 val, u32 offset, bool _relaxed, bool _64bit)
 static void etm_detect_os_lock(struct etmv4_drvdata *drvdata,
 			       struct csdev_access *csa)
 {
+	struct etmv4_caps *caps = &drvdata->caps;
 	u32 oslsr = etm4x_relaxed_read32(csa, TRCOSLSR);
 
-	drvdata->os_lock_model = ETM_OSLSR_OSLM(oslsr);
+	caps->os_lock_model = ETM_OSLSR_OSLM(oslsr);
 }
 
 static void etm_write_os_lock(struct etmv4_drvdata *drvdata,
 			      struct csdev_access *csa, u32 val)
 {
+	const struct etmv4_caps *caps = &drvdata->caps;
+
 	val = !!val;
 
-	switch (drvdata->os_lock_model) {
+	switch (caps->os_lock_model) {
 	case ETM_OSLOCK_PRESENT:
 		etm4x_relaxed_write32(csa, val, TRCOSLAR);
 		break;
@@ -179,7 +183,7 @@ static void etm_write_os_lock(struct etmv4_drvdata *drvdata,
 		break;
 	default:
 		pr_warn_once("CPU%d: Unsupported Trace OSLock model: %x\n",
-			     smp_processor_id(), drvdata->os_lock_model);
+			     smp_processor_id(), caps->os_lock_model);
 		fallthrough;
 	case ETM_OSLOCK_NI:
 		return;
@@ -494,6 +498,7 @@ static int etm4_enable_trace_unit(struct etmv4_drvdata *drvdata)
 static int etm4_enable_hw(struct etmv4_drvdata *drvdata)
 {
 	int i, rc;
+	const struct etmv4_caps *caps = &drvdata->caps;
 	struct etmv4_config *config = &drvdata->config;
 	struct coresight_device *csdev = drvdata->csdev;
 	struct device *etm_dev = &csdev->dev;
@@ -525,14 +530,14 @@ static int etm4_enable_hw(struct etmv4_drvdata *drvdata)
 	if (etm4x_wait_status(csa, TRCSTATR_IDLE_BIT, 1))
 		dev_err(etm_dev,
 			"timeout while waiting for Idle Trace Status\n");
-	if (drvdata->nr_pe)
+	if (caps->nr_pe)
 		etm4x_relaxed_write32(csa, config->pe_sel, TRCPROCSELR);
 	etm4x_relaxed_write32(csa, config->cfg, TRCCONFIGR);
 	/* nothing specific implemented */
 	etm4x_relaxed_write32(csa, 0x0, TRCAUXCTLR);
 	etm4x_relaxed_write32(csa, config->eventctrl0, TRCEVENTCTL0R);
 	etm4x_relaxed_write32(csa, config->eventctrl1, TRCEVENTCTL1R);
-	if (drvdata->stallctl)
+	if (caps->stallctl)
 		etm4x_relaxed_write32(csa, config->stall_ctrl, TRCSTALLCTLR);
 	etm4x_relaxed_write32(csa, config->ts_ctrl, TRCTSCTLR);
 	etm4x_relaxed_write32(csa, config->syncfreq, TRCSYNCPR);
@@ -542,17 +547,17 @@ static int etm4_enable_hw(struct etmv4_drvdata *drvdata)
 	etm4x_relaxed_write32(csa, config->vinst_ctrl, TRCVICTLR);
 	etm4x_relaxed_write32(csa, config->viiectlr, TRCVIIECTLR);
 	etm4x_relaxed_write32(csa, config->vissctlr, TRCVISSCTLR);
-	if (drvdata->nr_pe_cmp)
+	if (caps->nr_pe_cmp)
 		etm4x_relaxed_write32(csa, config->vipcssctlr, TRCVIPCSSCTLR);
-	for (i = 0; i < drvdata->nrseqstate - 1; i++)
+	for (i = 0; i < caps->nrseqstate - 1; i++)
 		etm4x_relaxed_write32(csa, config->seq_ctrl[i], TRCSEQEVRn(i));
-	if (drvdata->nrseqstate) {
+	if (caps->nrseqstate) {
 		etm4x_relaxed_write32(csa, config->seq_rst, TRCSEQRSTEVR);
 		etm4x_relaxed_write32(csa, config->seq_state, TRCSEQSTR);
 	}
-	if (drvdata->numextinsel)
+	if (caps->numextinsel)
 		etm4x_relaxed_write32(csa, config->ext_inp, TRCEXTINSELR);
-	for (i = 0; i < drvdata->nr_cntr; i++) {
+	for (i = 0; i < caps->nr_cntr; i++) {
 		etm4x_relaxed_write32(csa, config->cntrldvr[i], TRCCNTRLDVRn(i));
 		etm4x_relaxed_write32(csa, config->cntr_ctrl[i], TRCCNTCTLRn(i));
 		etm4x_relaxed_write32(csa, config->cntr_val[i], TRCCNTVRn(i));
@@ -562,10 +567,10 @@ static int etm4_enable_hw(struct etmv4_drvdata *drvdata)
 	 * Resource selector pair 0 is always implemented and reserved.  As
 	 * such start at 2.
 	 */
-	for (i = 2; i < drvdata->nr_resource * 2; i++)
+	for (i = 2; i < caps->nr_resource * 2; i++)
 		etm4x_relaxed_write32(csa, config->res_ctrl[i], TRCRSCTLRn(i));
 
-	for (i = 0; i < drvdata->nr_ss_cmp; i++) {
+	for (i = 0; i < caps->nr_ss_cmp; i++) {
 		/* always clear status bit on restart if using single-shot */
 		if (config->ss_ctrl[i] || config->ss_pe_cmp[i])
 			config->ss_status[i] &= ~TRCSSCSRn_STATUS;
@@ -574,23 +579,23 @@ static int etm4_enable_hw(struct etmv4_drvdata *drvdata)
 		if (etm4x_sspcicrn_present(drvdata, i))
 			etm4x_relaxed_write32(csa, config->ss_pe_cmp[i], TRCSSPCICRn(i));
 	}
-	for (i = 0; i < drvdata->nr_addr_cmp * 2; i++) {
+	for (i = 0; i < caps->nr_addr_cmp * 2; i++) {
 		etm4x_relaxed_write64(csa, config->addr_val[i], TRCACVRn(i));
 		etm4x_relaxed_write64(csa, config->addr_acc[i], TRCACATRn(i));
 	}
-	for (i = 0; i < drvdata->numcidc; i++)
+	for (i = 0; i < caps->numcidc; i++)
 		etm4x_relaxed_write64(csa, config->ctxid_pid[i], TRCCIDCVRn(i));
 	etm4x_relaxed_write32(csa, config->ctxid_mask0, TRCCIDCCTLR0);
-	if (drvdata->numcidc > 4)
+	if (caps->numcidc > 4)
 		etm4x_relaxed_write32(csa, config->ctxid_mask1, TRCCIDCCTLR1);
 
-	for (i = 0; i < drvdata->numvmidc; i++)
+	for (i = 0; i < caps->numvmidc; i++)
 		etm4x_relaxed_write64(csa, config->vmid_val[i], TRCVMIDCVRn(i));
 	etm4x_relaxed_write32(csa, config->vmid_mask0, TRCVMIDCCTLR0);
-	if (drvdata->numvmidc > 4)
+	if (caps->numvmidc > 4)
 		etm4x_relaxed_write32(csa, config->vmid_mask1, TRCVMIDCCTLR1);
 
-	if (!drvdata->skip_power_up) {
+	if (!caps->skip_power_up) {
 		u32 trcpdcr = etm4x_relaxed_read32(csa, TRCPDCR);
 
 		/*
@@ -666,19 +671,20 @@ static int etm4_config_timestamp_event(struct etmv4_drvdata *drvdata,
 {
 	int ctridx;
 	int rselector;
+	const struct etmv4_caps *caps = &drvdata->caps;
 	struct etmv4_config *config = &drvdata->config;
 
 	/* No point in trying if we don't have at least one counter */
-	if (!drvdata->nr_cntr)
+	if (!caps->nr_cntr)
 		return -EINVAL;
 
 	/* Find a counter that hasn't been initialised */
-	for (ctridx = 0; ctridx < drvdata->nr_cntr; ctridx++)
+	for (ctridx = 0; ctridx < caps->nr_cntr; ctridx++)
 		if (config->cntr_val[ctridx] == 0)
 			break;
 
 	/* All the counters have been configured already, bail out */
-	if (ctridx == drvdata->nr_cntr) {
+	if (ctridx == caps->nr_cntr) {
 		pr_debug("%s: no available counter found\n", __func__);
 		return -ENOSPC;
 	}
@@ -694,11 +700,11 @@ static int etm4_config_timestamp_event(struct etmv4_drvdata *drvdata,
 	 * ETMIDR4 gives the number of resource selector _pairs_, hence multiply
 	 * by 2.
 	 */
-	for (rselector = 2; rselector < drvdata->nr_resource * 2; rselector++)
+	for (rselector = 2; rselector < caps->nr_resource * 2; rselector++)
 		if (!config->res_ctrl[rselector])
 			break;
 
-	if (rselector == drvdata->nr_resource * 2) {
+	if (rselector == caps->nr_resource * 2) {
 		pr_debug("%s: no available resource selector found\n",
 			 __func__);
 		return -ENOSPC;
@@ -749,6 +755,7 @@ static int etm4_parse_event_config(struct coresight_device *csdev,
 {
 	int ret = 0;
 	struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+	const struct etmv4_caps *caps = &drvdata->caps;
 	struct etmv4_config *config = &drvdata->config;
 	struct perf_event_attr max_timestamp = {
 		.ATTR_CFG_FLD_timestamp_CFG = U64_MAX,
@@ -788,8 +795,8 @@ static int etm4_parse_event_config(struct coresight_device *csdev,
 		cc_threshold = ATTR_CFG_GET_FLD(attr, cc_threshold);
 		if (!cc_threshold)
 			cc_threshold = ETM_CYC_THRESHOLD_DEFAULT;
-		if (cc_threshold < drvdata->ccitmin)
-			cc_threshold = drvdata->ccitmin;
+		if (cc_threshold < caps->ccitmin)
+			cc_threshold = caps->ccitmin;
 		config->ccctlr = cc_threshold;
 	}
 
@@ -837,7 +844,7 @@ static int etm4_parse_event_config(struct coresight_device *csdev,
 	}
 
 	/* return stack - enable if selected and supported */
-	if (ATTR_CFG_GET_FLD(attr, retstack) && drvdata->retstack)
+	if (ATTR_CFG_GET_FLD(attr, retstack) && caps->retstack)
 		/* bit[12], Return stack enable bit */
 		config->cfg |= TRCCONFIGR_RS;
 
@@ -853,7 +860,7 @@ static int etm4_parse_event_config(struct coresight_device *csdev,
 
 	/* branch broadcast - enable if selected and supported */
 	if (ATTR_CFG_GET_FLD(attr, branch_broadcast)) {
-		if (!drvdata->trcbb) {
+		if (!caps->trcbb) {
 			/*
 			 * Missing BB support could cause silent decode errors
 			 * so fail to open if it's not supported.
@@ -1028,6 +1035,7 @@ static void etm4_disable_trace_unit(struct etmv4_drvdata *drvdata)
 static void etm4_disable_hw(struct etmv4_drvdata *drvdata)
 {
 	u32 control;
+	const struct etmv4_caps *caps = &drvdata->caps;
 	struct etmv4_config *config = &drvdata->config;
 	struct coresight_device *csdev = drvdata->csdev;
 	struct csdev_access *csa = &csdev->access;
@@ -1036,7 +1044,7 @@ static void etm4_disable_hw(struct etmv4_drvdata *drvdata)
 	etm4_cs_unlock(drvdata, csa);
 	etm4_disable_arch_specific(drvdata);
 
-	if (!drvdata->skip_power_up) {
+	if (!caps->skip_power_up) {
 		/* power can be removed from the trace unit now */
 		control = etm4x_relaxed_read32(csa, TRCPDCR);
 		control &= ~TRCPDCR_PU;
@@ -1046,13 +1054,13 @@ static void etm4_disable_hw(struct etmv4_drvdata *drvdata)
 	etm4_disable_trace_unit(drvdata);
 
 	/* read the status of the single shot comparators */
-	for (i = 0; i < drvdata->nr_ss_cmp; i++) {
+	for (i = 0; i < caps->nr_ss_cmp; i++) {
 		config->ss_status[i] =
 			etm4x_relaxed_read32(csa, TRCSSCSRn(i));
 	}
 
 	/* read back the current counter values */
-	for (i = 0; i < drvdata->nr_cntr; i++) {
+	for (i = 0; i < caps->nr_cntr; i++) {
 		config->cntr_val[i] =
 			etm4x_relaxed_read32(csa, TRCCNTVRn(i));
 	}
@@ -1350,7 +1358,7 @@ static struct midr_range etm_wrong_ccitmin_cpus[] = {
 	{},
 };
 
-static void etm4_fixup_wrong_ccitmin(struct etmv4_drvdata *drvdata)
+static void etm4_fixup_wrong_ccitmin(struct etmv4_caps *caps)
 {
 	/*
 	 * Erratum affected cpus will read 256 as the minimum
@@ -1360,8 +1368,8 @@ static void etm4_fixup_wrong_ccitmin(struct etmv4_drvdata *drvdata)
 	 * this problem.
 	 */
 	if (is_midr_in_range_list(etm_wrong_ccitmin_cpus)) {
-		if (drvdata->ccitmin == 256)
-			drvdata->ccitmin = 4;
+		if (caps->ccitmin == 256)
+			caps->ccitmin = 4;
 	}
 }
 
@@ -1374,11 +1382,13 @@ static void etm4_init_arch_data(void *info)
 	u32 etmidr5;
 	struct etm4_init_arg *init_arg = info;
 	struct etmv4_drvdata *drvdata;
+	struct etmv4_caps *caps;
 	struct csdev_access *csa;
 	struct device *dev = init_arg->dev;
 	int i;
 
 	drvdata = dev_get_drvdata(init_arg->dev);
+	caps = &drvdata->caps;
 	csa = init_arg->csa;
 
 	/*
@@ -1391,7 +1401,7 @@ static void etm4_init_arch_data(void *info)
 
 	if (!csa->io_mem ||
 	    fwnode_property_present(dev_fwnode(dev), "qcom,skip-power-up"))
-		drvdata->skip_power_up = true;
+		caps->skip_power_up = true;
 
 	/* Detect the support for OS Lock before we actually use it */
 	etm_detect_os_lock(drvdata, csa);
@@ -1406,71 +1416,71 @@ static void etm4_init_arch_data(void *info)
 	etmidr0 = etm4x_relaxed_read32(csa, TRCIDR0);
 
 	/* INSTP0, bits[2:1] P0 tracing support field */
-	drvdata->instrp0 = !!(FIELD_GET(TRCIDR0_INSTP0_MASK, etmidr0) == 0b11);
+	caps->instrp0 = !!(FIELD_GET(TRCIDR0_INSTP0_MASK, etmidr0) == 0b11);
 	/* TRCBB, bit[5] Branch broadcast tracing support bit */
-	drvdata->trcbb = !!(etmidr0 & TRCIDR0_TRCBB);
+	caps->trcbb = !!(etmidr0 & TRCIDR0_TRCBB);
 	/* TRCCOND, bit[6] Conditional instruction tracing support bit */
-	drvdata->trccond = !!(etmidr0 & TRCIDR0_TRCCOND);
+	caps->trccond = !!(etmidr0 & TRCIDR0_TRCCOND);
 	/* TRCCCI, bit[7] Cycle counting instruction bit */
-	drvdata->trccci = !!(etmidr0 & TRCIDR0_TRCCCI);
+	caps->trccci = !!(etmidr0 & TRCIDR0_TRCCCI);
 	/* RETSTACK, bit[9] Return stack bit */
-	drvdata->retstack = !!(etmidr0 & TRCIDR0_RETSTACK);
+	caps->retstack = !!(etmidr0 & TRCIDR0_RETSTACK);
 	/* NUMEVENT, bits[11:10] Number of events field */
-	drvdata->nr_event = FIELD_GET(TRCIDR0_NUMEVENT_MASK, etmidr0);
+	caps->nr_event = FIELD_GET(TRCIDR0_NUMEVENT_MASK, etmidr0);
 	/* QSUPP, bits[16:15] Q element support field */
-	drvdata->q_support = FIELD_GET(TRCIDR0_QSUPP_MASK, etmidr0);
-	if (drvdata->q_support)
-		drvdata->q_filt = !!(etmidr0 & TRCIDR0_QFILT);
+	caps->q_support = FIELD_GET(TRCIDR0_QSUPP_MASK, etmidr0);
+	if (caps->q_support)
+		caps->q_filt = !!(etmidr0 & TRCIDR0_QFILT);
 	/* TSSIZE, bits[28:24] Global timestamp size field */
-	drvdata->ts_size = FIELD_GET(TRCIDR0_TSSIZE_MASK, etmidr0);
+	caps->ts_size = FIELD_GET(TRCIDR0_TSSIZE_MASK, etmidr0);
 
 	/* maximum size of resources */
 	etmidr2 = etm4x_relaxed_read32(csa, TRCIDR2);
 	/* CIDSIZE, bits[9:5] Indicates the Context ID size */
-	drvdata->ctxid_size = FIELD_GET(TRCIDR2_CIDSIZE_MASK, etmidr2);
+	caps->ctxid_size = FIELD_GET(TRCIDR2_CIDSIZE_MASK, etmidr2);
 	/* VMIDSIZE, bits[14:10] Indicates the VMID size */
-	drvdata->vmid_size = FIELD_GET(TRCIDR2_VMIDSIZE_MASK, etmidr2);
+	caps->vmid_size = FIELD_GET(TRCIDR2_VMIDSIZE_MASK, etmidr2);
 	/* CCSIZE, bits[28:25] size of the cycle counter in bits minus 12 */
-	drvdata->ccsize = FIELD_GET(TRCIDR2_CCSIZE_MASK, etmidr2);
+	caps->ccsize = FIELD_GET(TRCIDR2_CCSIZE_MASK, etmidr2);
 
 	etmidr3 = etm4x_relaxed_read32(csa, TRCIDR3);
 	/* CCITMIN, bits[11:0] minimum threshold value that can be programmed */
-	drvdata->ccitmin = FIELD_GET(TRCIDR3_CCITMIN_MASK, etmidr3);
-	etm4_fixup_wrong_ccitmin(drvdata);
+	caps->ccitmin = FIELD_GET(TRCIDR3_CCITMIN_MASK, etmidr3);
+	etm4_fixup_wrong_ccitmin(caps);
 
 	/* EXLEVEL_S, bits[19:16] Secure state instruction tracing */
-	drvdata->s_ex_level = FIELD_GET(TRCIDR3_EXLEVEL_S_MASK, etmidr3);
-	drvdata->config.s_ex_level = drvdata->s_ex_level;
+	caps->s_ex_level = FIELD_GET(TRCIDR3_EXLEVEL_S_MASK, etmidr3);
+	drvdata->config.s_ex_level = caps->s_ex_level;
 	/* EXLEVEL_NS, bits[23:20] Non-secure state instruction tracing */
-	drvdata->ns_ex_level = FIELD_GET(TRCIDR3_EXLEVEL_NS_MASK, etmidr3);
+	caps->ns_ex_level = FIELD_GET(TRCIDR3_EXLEVEL_NS_MASK, etmidr3);
 	/*
 	 * TRCERR, bit[24] whether a trace unit can trace a
 	 * system error exception.
 	 */
-	drvdata->trc_error = !!(etmidr3 & TRCIDR3_TRCERR);
+	caps->trc_error = !!(etmidr3 & TRCIDR3_TRCERR);
 	/* SYNCPR, bit[25] implementation has a fixed synchronization period? */
-	drvdata->syncpr = !!(etmidr3 & TRCIDR3_SYNCPR);
+	caps->syncpr = !!(etmidr3 & TRCIDR3_SYNCPR);
 	/* STALLCTL, bit[26] is stall control implemented? */
-	drvdata->stallctl = !!(etmidr3 & TRCIDR3_STALLCTL);
+	caps->stallctl = !!(etmidr3 & TRCIDR3_STALLCTL);
 	/* SYSSTALL, bit[27] implementation can support stall control? */
-	drvdata->sysstall = !!(etmidr3 & TRCIDR3_SYSSTALL);
+	caps->sysstall = !!(etmidr3 & TRCIDR3_SYSSTALL);
 	/*
 	 * NUMPROC - the number of PEs available for tracing, 5bits
 	 *         = TRCIDR3.bits[13:12]bits[30:28]
 	 *  bits[4:3] = TRCIDR3.bits[13:12] (since etm-v4.2, otherwise RES0)
 	 *  bits[3:0] = TRCIDR3.bits[30:28]
 	 */
-	drvdata->nr_pe =  (FIELD_GET(TRCIDR3_NUMPROC_HI_MASK, etmidr3) << 3) |
-			   FIELD_GET(TRCIDR3_NUMPROC_LO_MASK, etmidr3);
+	caps->nr_pe = (FIELD_GET(TRCIDR3_NUMPROC_HI_MASK, etmidr3) << 3) |
+			       FIELD_GET(TRCIDR3_NUMPROC_LO_MASK, etmidr3);
 	/* NOOVERFLOW, bit[31] is trace overflow prevention supported */
-	drvdata->nooverflow = !!(etmidr3 & TRCIDR3_NOOVERFLOW);
+	caps->nooverflow = !!(etmidr3 & TRCIDR3_NOOVERFLOW);
 
 	/* number of resources trace unit supports */
 	etmidr4 = etm4x_relaxed_read32(csa, TRCIDR4);
 	/* NUMACPAIRS, bits[0:3] number of addr comparator pairs for tracing */
-	drvdata->nr_addr_cmp = FIELD_GET(TRCIDR4_NUMACPAIRS_MASK, etmidr4);
+	caps->nr_addr_cmp = FIELD_GET(TRCIDR4_NUMACPAIRS_MASK, etmidr4);
 	/* NUMPC, bits[15:12] number of PE comparator inputs for tracing */
-	drvdata->nr_pe_cmp = FIELD_GET(TRCIDR4_NUMPC_MASK, etmidr4);
+	caps->nr_pe_cmp = FIELD_GET(TRCIDR4_NUMPC_MASK, etmidr4);
 	/*
 	 * NUMRSPAIR, bits[19:16]
 	 * The number of resource pairs conveyed by the HW starts at 0, i.e a
@@ -1481,41 +1491,41 @@ static void etm4_init_arch_data(void *info)
 	 * the default TRUE and FALSE resource selectors are omitted.
 	 * Otherwise for values 0x1 and above the number is N + 1 as per v4.2.
 	 */
-	drvdata->nr_resource = FIELD_GET(TRCIDR4_NUMRSPAIR_MASK, etmidr4);
-	if ((drvdata->arch < ETM_ARCH_V4_3) || (drvdata->nr_resource > 0))
-		drvdata->nr_resource += 1;
+	caps->nr_resource = FIELD_GET(TRCIDR4_NUMRSPAIR_MASK, etmidr4);
+	if ((drvdata->arch < ETM_ARCH_V4_3) || (caps->nr_resource > 0))
+		caps->nr_resource += 1;
 	/*
 	 * NUMSSCC, bits[23:20] the number of single-shot
 	 * comparator control for tracing. Read any status regs as these
 	 * also contain RO capability data.
 	 */
-	drvdata->nr_ss_cmp = FIELD_GET(TRCIDR4_NUMSSCC_MASK, etmidr4);
-	for (i = 0; i < drvdata->nr_ss_cmp; i++) {
+	caps->nr_ss_cmp = FIELD_GET(TRCIDR4_NUMSSCC_MASK, etmidr4);
+	for (i = 0; i < caps->nr_ss_cmp; i++) {
 		drvdata->config.ss_status[i] =
 			etm4x_relaxed_read32(csa, TRCSSCSRn(i));
 	}
 	/* NUMCIDC, bits[27:24] number of Context ID comparators for tracing */
-	drvdata->numcidc = FIELD_GET(TRCIDR4_NUMCIDC_MASK, etmidr4);
+	caps->numcidc = FIELD_GET(TRCIDR4_NUMCIDC_MASK, etmidr4);
 	/* NUMVMIDC, bits[31:28] number of VMID comparators for tracing */
-	drvdata->numvmidc = FIELD_GET(TRCIDR4_NUMVMIDC_MASK, etmidr4);
+	caps->numvmidc = FIELD_GET(TRCIDR4_NUMVMIDC_MASK, etmidr4);
 
 	etmidr5 = etm4x_relaxed_read32(csa, TRCIDR5);
 	/* NUMEXTIN, bits[8:0] number of external inputs implemented */
-	drvdata->nr_ext_inp = FIELD_GET(TRCIDR5_NUMEXTIN_MASK, etmidr5);
-	drvdata->numextinsel = FIELD_GET(TRCIDR5_NUMEXTINSEL_MASK, etmidr5);
+	caps->nr_ext_inp = FIELD_GET(TRCIDR5_NUMEXTIN_MASK, etmidr5);
+	caps->numextinsel = FIELD_GET(TRCIDR5_NUMEXTINSEL_MASK, etmidr5);
 	/* TRACEIDSIZE, bits[21:16] indicates the trace ID width */
-	drvdata->trcid_size = FIELD_GET(TRCIDR5_TRACEIDSIZE_MASK, etmidr5);
+	caps->trcid_size = FIELD_GET(TRCIDR5_TRACEIDSIZE_MASK, etmidr5);
 	/* ATBTRIG, bit[22] implementation can support ATB triggers? */
-	drvdata->atbtrig = !!(etmidr5 & TRCIDR5_ATBTRIG);
+	caps->atbtrig = !!(etmidr5 & TRCIDR5_ATBTRIG);
 	/*
 	 * LPOVERRIDE, bit[23] implementation supports
 	 * low-power state override
 	 */
-	drvdata->lpoverride = (etmidr5 & TRCIDR5_LPOVERRIDE) && (!drvdata->skip_power_up);
+	caps->lpoverride = (etmidr5 & TRCIDR5_LPOVERRIDE) && (!caps->skip_power_up);
 	/* NUMSEQSTATE, bits[27:25] number of sequencer states implemented */
-	drvdata->nrseqstate = FIELD_GET(TRCIDR5_NUMSEQSTATE_MASK, etmidr5);
+	caps->nrseqstate = FIELD_GET(TRCIDR5_NUMSEQSTATE_MASK, etmidr5);
 	/* NUMCNTR, bits[30:28] number of counters available for tracing */
-	drvdata->nr_cntr = FIELD_GET(TRCIDR5_NUMCNTR_MASK, etmidr5);
+	caps->nr_cntr = FIELD_GET(TRCIDR5_NUMCNTR_MASK, etmidr5);
 
 	coresight_clear_self_claim_tag_unlocked(csa);
 	etm4_cs_lock(drvdata, csa);
@@ -1691,7 +1701,7 @@ static int etm4_get_next_comparator(struct etmv4_drvdata *drvdata, u32 type)
 	 * nr_addr_cmp holds the number of comparator _pair_, so time 2
 	 * for the total number of comparators.
 	 */
-	nr_comparator = drvdata->nr_addr_cmp * 2;
+	nr_comparator = drvdata->caps.nr_addr_cmp * 2;
 
 	/* Go through the tally of comparators looking for a free one. */
 	while (index < nr_comparator) {
@@ -1869,6 +1879,7 @@ static int etm4_dying_cpu(unsigned int cpu)
 static int __etm4_cpu_save(struct etmv4_drvdata *drvdata)
 {
 	int i, ret = 0;
+	const struct etmv4_caps *caps = &drvdata->caps;
 	struct etmv4_save_state *state;
 	struct coresight_device *csdev = drvdata->csdev;
 	struct csdev_access *csa;
@@ -1905,57 +1916,57 @@ static int __etm4_cpu_save(struct etmv4_drvdata *drvdata)
 
 	state = drvdata->save_state;
 
-	if (drvdata->nr_pe)
+	if (caps->nr_pe)
 		state->trcprocselr = etm4x_read32(csa, TRCPROCSELR);
 	state->trcconfigr = etm4x_read32(csa, TRCCONFIGR);
 	state->trcauxctlr = etm4x_read32(csa, TRCAUXCTLR);
 	state->trceventctl0r = etm4x_read32(csa, TRCEVENTCTL0R);
 	state->trceventctl1r = etm4x_read32(csa, TRCEVENTCTL1R);
-	if (drvdata->stallctl)
+	if (caps->stallctl)
 		state->trcstallctlr = etm4x_read32(csa, TRCSTALLCTLR);
 	state->trctsctlr = etm4x_read32(csa, TRCTSCTLR);
 	state->trcsyncpr = etm4x_read32(csa, TRCSYNCPR);
 	state->trcccctlr = etm4x_read32(csa, TRCCCCTLR);
 	state->trcbbctlr = etm4x_read32(csa, TRCBBCTLR);
 	state->trctraceidr = etm4x_read32(csa, TRCTRACEIDR);
-	if (drvdata->q_filt)
+	if (caps->q_filt)
 		state->trcqctlr = etm4x_read32(csa, TRCQCTLR);
 
 	state->trcvictlr = etm4x_read32(csa, TRCVICTLR);
 	state->trcviiectlr = etm4x_read32(csa, TRCVIIECTLR);
 	state->trcvissctlr = etm4x_read32(csa, TRCVISSCTLR);
-	if (drvdata->nr_pe_cmp)
+	if (caps->nr_pe_cmp)
 		state->trcvipcssctlr = etm4x_read32(csa, TRCVIPCSSCTLR);
 
-	for (i = 0; i < drvdata->nrseqstate - 1; i++)
+	for (i = 0; i < caps->nrseqstate - 1; i++)
 		state->trcseqevr[i] = etm4x_read32(csa, TRCSEQEVRn(i));
 
-	if (drvdata->nrseqstate) {
+	if (caps->nrseqstate) {
 		state->trcseqrstevr = etm4x_read32(csa, TRCSEQRSTEVR);
 		state->trcseqstr = etm4x_read32(csa, TRCSEQSTR);
 	}
 
-	if (drvdata->numextinsel)
+	if (caps->numextinsel)
 		state->trcextinselr = etm4x_read32(csa, TRCEXTINSELR);
 
-	for (i = 0; i < drvdata->nr_cntr; i++) {
+	for (i = 0; i < caps->nr_cntr; i++) {
 		state->trccntrldvr[i] = etm4x_read32(csa, TRCCNTRLDVRn(i));
 		state->trccntctlr[i] = etm4x_read32(csa, TRCCNTCTLRn(i));
 		state->trccntvr[i] = etm4x_read32(csa, TRCCNTVRn(i));
 	}
 
 	/* Resource selector pair 0 is reserved */
-	for (i = 2; i < drvdata->nr_resource * 2; i++)
+	for (i = 2; i < caps->nr_resource * 2; i++)
 		state->trcrsctlr[i] = etm4x_read32(csa, TRCRSCTLRn(i));
 
-	for (i = 0; i < drvdata->nr_ss_cmp; i++) {
+	for (i = 0; i < caps->nr_ss_cmp; i++) {
 		state->trcssccr[i] = etm4x_read32(csa, TRCSSCCRn(i));
 		state->trcsscsr[i] = etm4x_read32(csa, TRCSSCSRn(i));
 		if (etm4x_sspcicrn_present(drvdata, i))
 			state->trcsspcicr[i] = etm4x_read32(csa, TRCSSPCICRn(i));
 	}
 
-	for (i = 0; i < drvdata->nr_addr_cmp * 2; i++) {
+	for (i = 0; i < caps->nr_addr_cmp * 2; i++) {
 		state->trcacvr[i] = etm4x_read64(csa, TRCACVRn(i));
 		state->trcacatr[i] = etm4x_read64(csa, TRCACATRn(i));
 	}
@@ -1967,23 +1978,23 @@ static int __etm4_cpu_save(struct etmv4_drvdata *drvdata)
 	 * unit") of ARM IHI 0064D.
 	 */
 
-	for (i = 0; i < drvdata->numcidc; i++)
+	for (i = 0; i < caps->numcidc; i++)
 		state->trccidcvr[i] = etm4x_read64(csa, TRCCIDCVRn(i));
 
-	for (i = 0; i < drvdata->numvmidc; i++)
+	for (i = 0; i < caps->numvmidc; i++)
 		state->trcvmidcvr[i] = etm4x_read64(csa, TRCVMIDCVRn(i));
 
 	state->trccidcctlr0 = etm4x_read32(csa, TRCCIDCCTLR0);
-	if (drvdata->numcidc > 4)
+	if (caps->numcidc > 4)
 		state->trccidcctlr1 = etm4x_read32(csa, TRCCIDCCTLR1);
 
 	state->trcvmidcctlr0 = etm4x_read32(csa, TRCVMIDCCTLR0);
-	if (drvdata->numvmidc > 4)
+	if (caps->numvmidc > 4)
 		state->trcvmidcctlr0 = etm4x_read32(csa, TRCVMIDCCTLR1);
 
 	state->trcclaimset = etm4x_read32(csa, TRCCLAIMCLR);
 
-	if (!drvdata->skip_power_up)
+	if (!caps->skip_power_up)
 		state->trcpdcr = etm4x_read32(csa, TRCPDCR);
 
 	/* wait for TRCSTATR.IDLE to go up */
@@ -2000,7 +2011,7 @@ static int __etm4_cpu_save(struct etmv4_drvdata *drvdata)
 	 * potentially save power on systems that respect the TRCPDCR_PU
 	 * despite requesting software to save/restore state.
 	 */
-	if (!drvdata->skip_power_up)
+	if (!caps->skip_power_up)
 		etm4x_relaxed_write32(csa, (state->trcpdcr & ~TRCPDCR_PU),
 				      TRCPDCR);
 out:
@@ -2027,6 +2038,7 @@ static int etm4_cpu_save(struct etmv4_drvdata *drvdata)
 static void __etm4_cpu_restore(struct etmv4_drvdata *drvdata)
 {
 	int i;
+	const struct etmv4_caps *caps = &drvdata->caps;
 	struct etmv4_save_state *state = drvdata->save_state;
 	struct csdev_access *csa = &drvdata->csdev->access;
 
@@ -2036,77 +2048,77 @@ static void __etm4_cpu_restore(struct etmv4_drvdata *drvdata)
 	etm4_cs_unlock(drvdata, csa);
 	etm4x_relaxed_write32(csa, state->trcclaimset, TRCCLAIMSET);
 
-	if (drvdata->nr_pe)
+	if (caps->nr_pe)
 		etm4x_relaxed_write32(csa, state->trcprocselr, TRCPROCSELR);
 	etm4x_relaxed_write32(csa, state->trcconfigr, TRCCONFIGR);
 	etm4x_relaxed_write32(csa, state->trcauxctlr, TRCAUXCTLR);
 	etm4x_relaxed_write32(csa, state->trceventctl0r, TRCEVENTCTL0R);
 	etm4x_relaxed_write32(csa, state->trceventctl1r, TRCEVENTCTL1R);
-	if (drvdata->stallctl)
+	if (caps->stallctl)
 		etm4x_relaxed_write32(csa, state->trcstallctlr, TRCSTALLCTLR);
 	etm4x_relaxed_write32(csa, state->trctsctlr, TRCTSCTLR);
 	etm4x_relaxed_write32(csa, state->trcsyncpr, TRCSYNCPR);
 	etm4x_relaxed_write32(csa, state->trcccctlr, TRCCCCTLR);
 	etm4x_relaxed_write32(csa, state->trcbbctlr, TRCBBCTLR);
 	etm4x_relaxed_write32(csa, state->trctraceidr, TRCTRACEIDR);
-	if (drvdata->q_filt)
+	if (caps->q_filt)
 		etm4x_relaxed_write32(csa, state->trcqctlr, TRCQCTLR);
 
 	etm4x_relaxed_write32(csa, state->trcvictlr, TRCVICTLR);
 	etm4x_relaxed_write32(csa, state->trcviiectlr, TRCVIIECTLR);
 	etm4x_relaxed_write32(csa, state->trcvissctlr, TRCVISSCTLR);
-	if (drvdata->nr_pe_cmp)
+	if (caps->nr_pe_cmp)
 		etm4x_relaxed_write32(csa, state->trcvipcssctlr, TRCVIPCSSCTLR);
 
-	for (i = 0; i < drvdata->nrseqstate - 1; i++)
+	for (i = 0; i < caps->nrseqstate - 1; i++)
 		etm4x_relaxed_write32(csa, state->trcseqevr[i], TRCSEQEVRn(i));
 
-	if (drvdata->nrseqstate) {
+	if (caps->nrseqstate) {
 		etm4x_relaxed_write32(csa, state->trcseqrstevr, TRCSEQRSTEVR);
 		etm4x_relaxed_write32(csa, state->trcseqstr, TRCSEQSTR);
 	}
-	if (drvdata->numextinsel)
+	if (caps->numextinsel)
 		etm4x_relaxed_write32(csa, state->trcextinselr, TRCEXTINSELR);
 
-	for (i = 0; i < drvdata->nr_cntr; i++) {
+	for (i = 0; i < caps->nr_cntr; i++) {
 		etm4x_relaxed_write32(csa, state->trccntrldvr[i], TRCCNTRLDVRn(i));
 		etm4x_relaxed_write32(csa, state->trccntctlr[i], TRCCNTCTLRn(i));
 		etm4x_relaxed_write32(csa, state->trccntvr[i], TRCCNTVRn(i));
 	}
 
 	/* Resource selector pair 0 is reserved */
-	for (i = 2; i < drvdata->nr_resource * 2; i++)
+	for (i = 2; i < caps->nr_resource * 2; i++)
 		etm4x_relaxed_write32(csa, state->trcrsctlr[i], TRCRSCTLRn(i));
 
-	for (i = 0; i < drvdata->nr_ss_cmp; i++) {
+	for (i = 0; i < caps->nr_ss_cmp; i++) {
 		etm4x_relaxed_write32(csa, state->trcssccr[i], TRCSSCCRn(i));
 		etm4x_relaxed_write32(csa, state->trcsscsr[i], TRCSSCSRn(i));
 		if (etm4x_sspcicrn_present(drvdata, i))
 			etm4x_relaxed_write32(csa, state->trcsspcicr[i], TRCSSPCICRn(i));
 	}
 
-	for (i = 0; i < drvdata->nr_addr_cmp * 2; i++) {
+	for (i = 0; i < caps->nr_addr_cmp * 2; i++) {
 		etm4x_relaxed_write64(csa, state->trcacvr[i], TRCACVRn(i));
 		etm4x_relaxed_write64(csa, state->trcacatr[i], TRCACATRn(i));
 	}
 
-	for (i = 0; i < drvdata->numcidc; i++)
+	for (i = 0; i < caps->numcidc; i++)
 		etm4x_relaxed_write64(csa, state->trccidcvr[i], TRCCIDCVRn(i));
 
-	for (i = 0; i < drvdata->numvmidc; i++)
+	for (i = 0; i < caps->numvmidc; i++)
 		etm4x_relaxed_write64(csa, state->trcvmidcvr[i], TRCVMIDCVRn(i));
 
 	etm4x_relaxed_write32(csa, state->trccidcctlr0, TRCCIDCCTLR0);
-	if (drvdata->numcidc > 4)
+	if (caps->numcidc > 4)
 		etm4x_relaxed_write32(csa, state->trccidcctlr1, TRCCIDCCTLR1);
 
 	etm4x_relaxed_write32(csa, state->trcvmidcctlr0, TRCVMIDCCTLR0);
-	if (drvdata->numvmidc > 4)
+	if (caps->numvmidc > 4)
 		etm4x_relaxed_write32(csa, state->trcvmidcctlr0, TRCVMIDCCTLR1);
 
 	etm4x_relaxed_write32(csa, state->trcclaimset, TRCCLAIMSET);
 
-	if (!drvdata->skip_power_up)
+	if (!caps->skip_power_up)
 		etm4x_relaxed_write32(csa, state->trcpdcr, TRCPDCR);
 
 	/*
diff --git a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
index e9eeea6240d5..3d5f343130bd 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
@@ -62,8 +62,9 @@ static ssize_t nr_pe_cmp_show(struct device *dev,
 {
 	unsigned long val;
 	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	const struct etmv4_caps *caps = &drvdata->caps;
 
-	val = drvdata->nr_pe_cmp;
+	val = caps->nr_pe_cmp;
 	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
 }
 static DEVICE_ATTR_RO(nr_pe_cmp);
@@ -74,8 +75,9 @@ static ssize_t nr_addr_cmp_show(struct device *dev,
 {
 	unsigned long val;
 	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	const struct etmv4_caps *caps = &drvdata->caps;
 
-	val = drvdata->nr_addr_cmp;
+	val = caps->nr_addr_cmp;
 	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
 }
 static DEVICE_ATTR_RO(nr_addr_cmp);
@@ -86,8 +88,9 @@ static ssize_t nr_cntr_show(struct device *dev,
 {
 	unsigned long val;
 	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	const struct etmv4_caps *caps = &drvdata->caps;
 
-	val = drvdata->nr_cntr;
+	val = caps->nr_cntr;
 	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
 }
 static DEVICE_ATTR_RO(nr_cntr);
@@ -98,8 +101,9 @@ static ssize_t nr_ext_inp_show(struct device *dev,
 {
 	unsigned long val;
 	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	const struct etmv4_caps *caps = &drvdata->caps;
 
-	val = drvdata->nr_ext_inp;
+	val = caps->nr_ext_inp;
 	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
 }
 static DEVICE_ATTR_RO(nr_ext_inp);
@@ -110,8 +114,9 @@ static ssize_t numcidc_show(struct device *dev,
 {
 	unsigned long val;
 	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	const struct etmv4_caps *caps = &drvdata->caps;
 
-	val = drvdata->numcidc;
+	val = caps->numcidc;
 	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
 }
 static DEVICE_ATTR_RO(numcidc);
@@ -122,8 +127,9 @@ static ssize_t numvmidc_show(struct device *dev,
 {
 	unsigned long val;
 	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	const struct etmv4_caps *caps = &drvdata->caps;
 
-	val = drvdata->numvmidc;
+	val = caps->numvmidc;
 	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
 }
 static DEVICE_ATTR_RO(numvmidc);
@@ -134,8 +140,9 @@ static ssize_t nrseqstate_show(struct device *dev,
 {
 	unsigned long val;
 	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	const struct etmv4_caps *caps = &drvdata->caps;
 
-	val = drvdata->nrseqstate;
+	val = caps->nrseqstate;
 	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
 }
 static DEVICE_ATTR_RO(nrseqstate);
@@ -146,8 +153,9 @@ static ssize_t nr_resource_show(struct device *dev,
 {
 	unsigned long val;
 	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	const struct etmv4_caps *caps = &drvdata->caps;
 
-	val = drvdata->nr_resource;
+	val = caps->nr_resource;
 	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
 }
 static DEVICE_ATTR_RO(nr_resource);
@@ -158,8 +166,9 @@ static ssize_t nr_ss_cmp_show(struct device *dev,
 {
 	unsigned long val;
 	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	const struct etmv4_caps *caps = &drvdata->caps;
 
-	val = drvdata->nr_ss_cmp;
+	val = caps->nr_ss_cmp;
 	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
 }
 static DEVICE_ATTR_RO(nr_ss_cmp);
@@ -171,6 +180,7 @@ static ssize_t reset_store(struct device *dev,
 	int i;
 	unsigned long val;
 	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	const struct etmv4_caps *caps = &drvdata->caps;
 	struct etmv4_config *config = &drvdata->config;
 
 	if (kstrtoul(buf, 16, &val))
@@ -200,7 +210,7 @@ static ssize_t reset_store(struct device *dev,
 	config->stall_ctrl = 0x0;
 
 	/* Reset trace synchronization period  to 2^8 = 256 bytes*/
-	if (drvdata->syncpr == false)
+	if (caps->syncpr == false)
 		config->syncfreq = 0x8;
 
 	/*
@@ -209,7 +219,7 @@ static ssize_t reset_store(struct device *dev,
 	 * each trace run.
 	 */
 	config->vinst_ctrl = FIELD_PREP(TRCVICTLR_EVENT_MASK, 0x01);
-	if (drvdata->nr_addr_cmp > 0) {
+	if (caps->nr_addr_cmp > 0) {
 		config->mode |= ETM_MODE_VIEWINST_STARTSTOP;
 		/* SSSTATUS, bit[9] */
 		config->vinst_ctrl |= TRCVICTLR_SSSTATUS;
@@ -223,7 +233,7 @@ static ssize_t reset_store(struct device *dev,
 	config->vipcssctlr = 0x0;
 
 	/* Disable seq events */
-	for (i = 0; i < drvdata->nrseqstate-1; i++)
+	for (i = 0; i < caps->nrseqstate-1; i++)
 		config->seq_ctrl[i] = 0x0;
 	config->seq_rst = 0x0;
 	config->seq_state = 0x0;
@@ -232,38 +242,38 @@ static ssize_t reset_store(struct device *dev,
 	config->ext_inp = 0x0;
 
 	config->cntr_idx = 0x0;
-	for (i = 0; i < drvdata->nr_cntr; i++) {
+	for (i = 0; i < caps->nr_cntr; i++) {
 		config->cntrldvr[i] = 0x0;
 		config->cntr_ctrl[i] = 0x0;
 		config->cntr_val[i] = 0x0;
 	}
 
 	config->res_idx = 0x0;
-	for (i = 2; i < 2 * drvdata->nr_resource; i++)
+	for (i = 2; i < 2 * caps->nr_resource; i++)
 		config->res_ctrl[i] = 0x0;
 
 	config->ss_idx = 0x0;
-	for (i = 0; i < drvdata->nr_ss_cmp; i++) {
+	for (i = 0; i < caps->nr_ss_cmp; i++) {
 		config->ss_ctrl[i] = 0x0;
 		config->ss_pe_cmp[i] = 0x0;
 	}
 
 	config->addr_idx = 0x0;
-	for (i = 0; i < drvdata->nr_addr_cmp * 2; i++) {
+	for (i = 0; i < caps->nr_addr_cmp * 2; i++) {
 		config->addr_val[i] = 0x0;
 		config->addr_acc[i] = 0x0;
 		config->addr_type[i] = ETM_ADDR_TYPE_NONE;
 	}
 
 	config->ctxid_idx = 0x0;
-	for (i = 0; i < drvdata->numcidc; i++)
+	for (i = 0; i < caps->numcidc; i++)
 		config->ctxid_pid[i] = 0x0;
 
 	config->ctxid_mask0 = 0x0;
 	config->ctxid_mask1 = 0x0;
 
 	config->vmid_idx = 0x0;
-	for (i = 0; i < drvdata->numvmidc; i++)
+	for (i = 0; i < caps->numvmidc; i++)
 		config->vmid_val[i] = 0x0;
 	config->vmid_mask0 = 0x0;
 	config->vmid_mask1 = 0x0;
@@ -297,6 +307,7 @@ static ssize_t mode_store(struct device *dev,
 {
 	unsigned long val, mode;
 	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	const struct etmv4_caps *caps = &drvdata->caps;
 	struct etmv4_config *config = &drvdata->config;
 
 	if (kstrtoul(buf, 16, &val))
@@ -305,7 +316,7 @@ static ssize_t mode_store(struct device *dev,
 	raw_spin_lock(&drvdata->spinlock);
 	config->mode = val & ETMv4_MODE_ALL;
 
-	if (drvdata->instrp0 == true) {
+	if (caps->instrp0 == true) {
 		/* start by clearing instruction P0 field */
 		config->cfg  &= ~TRCCONFIGR_INSTP0_LOAD_STORE;
 		if (config->mode & ETM_MODE_LOAD)
@@ -323,45 +334,45 @@ static ssize_t mode_store(struct device *dev,
 	}
 
 	/* bit[3], Branch broadcast mode */
-	if ((config->mode & ETM_MODE_BB) && (drvdata->trcbb == true))
+	if ((config->mode & ETM_MODE_BB) && (caps->trcbb == true))
 		config->cfg |= TRCCONFIGR_BB;
 	else
 		config->cfg &= ~TRCCONFIGR_BB;
 
 	/* bit[4], Cycle counting instruction trace bit */
 	if ((config->mode & ETMv4_MODE_CYCACC) &&
-		(drvdata->trccci == true))
+		(caps->trccci == true))
 		config->cfg |= TRCCONFIGR_CCI;
 	else
 		config->cfg &= ~TRCCONFIGR_CCI;
 
 	/* bit[6], Context ID tracing bit */
-	if ((config->mode & ETMv4_MODE_CTXID) && (drvdata->ctxid_size))
+	if ((config->mode & ETMv4_MODE_CTXID) && (caps->ctxid_size))
 		config->cfg |= TRCCONFIGR_CID;
 	else
 		config->cfg &= ~TRCCONFIGR_CID;
 
-	if ((config->mode & ETM_MODE_VMID) && (drvdata->vmid_size))
+	if ((config->mode & ETM_MODE_VMID) && (caps->vmid_size))
 		config->cfg |= TRCCONFIGR_VMID;
 	else
 		config->cfg &= ~TRCCONFIGR_VMID;
 
 	/* bits[10:8], Conditional instruction tracing bit */
 	mode = ETM_MODE_COND(config->mode);
-	if (drvdata->trccond == true) {
+	if (caps->trccond == true) {
 		config->cfg &= ~TRCCONFIGR_COND_MASK;
 		config->cfg |= mode << __bf_shf(TRCCONFIGR_COND_MASK);
 	}
 
 	/* bit[11], Global timestamp tracing bit */
-	if ((config->mode & ETMv4_MODE_TIMESTAMP) && (drvdata->ts_size))
+	if ((config->mode & ETMv4_MODE_TIMESTAMP) && (caps->ts_size))
 		config->cfg |= TRCCONFIGR_TS;
 	else
 		config->cfg &= ~TRCCONFIGR_TS;
 
 	/* bit[12], Return stack enable bit */
 	if ((config->mode & ETM_MODE_RETURNSTACK) &&
-					(drvdata->retstack == true))
+					(caps->retstack == true))
 		config->cfg |= TRCCONFIGR_RS;
 	else
 		config->cfg &= ~TRCCONFIGR_RS;
@@ -375,31 +386,31 @@ static ssize_t mode_store(struct device *dev,
 	 * Always set the low bit for any requested mode. Valid combos are
 	 * 0b00, 0b01 and 0b11.
 	 */
-	if (mode && drvdata->q_support)
+	if (mode && caps->q_support)
 		config->cfg |= TRCCONFIGR_QE_W_COUNTS;
 	/*
 	 * if supported, Q elements with and without instruction
 	 * counts are enabled
 	 */
-	if ((mode & BIT(1)) && (drvdata->q_support & BIT(1)))
+	if ((mode & BIT(1)) && (caps->q_support & BIT(1)))
 		config->cfg |= TRCCONFIGR_QE_WO_COUNTS;
 
 	/* bit[11], AMBA Trace Bus (ATB) trigger enable bit */
 	if ((config->mode & ETM_MODE_ATB_TRIGGER) &&
-	    (drvdata->atbtrig == true))
+	    (caps->atbtrig == true))
 		config->eventctrl1 |= TRCEVENTCTL1R_ATB;
 	else
 		config->eventctrl1 &= ~TRCEVENTCTL1R_ATB;
 
 	/* bit[12], Low-power state behavior override bit */
 	if ((config->mode & ETM_MODE_LPOVERRIDE) &&
-	    (drvdata->lpoverride == true))
+	    (caps->lpoverride == true))
 		config->eventctrl1 |= TRCEVENTCTL1R_LPOVERRIDE;
 	else
 		config->eventctrl1 &= ~TRCEVENTCTL1R_LPOVERRIDE;
 
 	/* bit[8], Instruction stall bit */
-	if ((config->mode & ETM_MODE_ISTALL_EN) && (drvdata->stallctl == true))
+	if ((config->mode & ETM_MODE_ISTALL_EN) && (caps->stallctl == true))
 		config->stall_ctrl |= TRCSTALLCTLR_ISTALL;
 	else
 		config->stall_ctrl &= ~TRCSTALLCTLR_ISTALL;
@@ -412,7 +423,7 @@ static ssize_t mode_store(struct device *dev,
 
 	/* bit[13], Trace overflow prevention bit */
 	if ((config->mode & ETM_MODE_NOOVERFLOW) &&
-		(drvdata->nooverflow == true))
+		(caps->nooverflow == true))
 		config->stall_ctrl |= TRCSTALLCTLR_NOOVERFLOW;
 	else
 		config->stall_ctrl &= ~TRCSTALLCTLR_NOOVERFLOW;
@@ -431,7 +442,7 @@ static ssize_t mode_store(struct device *dev,
 
 	/* bit[11], Whether a trace unit must trace a system error exception */
 	if ((config->mode & ETM_MODE_TRACE_ERR) &&
-		(drvdata->trc_error == true))
+		(caps->trc_error == true))
 		config->vinst_ctrl |= TRCVICTLR_TRCERR;
 	else
 		config->vinst_ctrl &= ~TRCVICTLR_TRCERR;
@@ -463,13 +474,14 @@ static ssize_t pe_store(struct device *dev,
 {
 	unsigned long val;
 	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	const struct etmv4_caps *caps = &drvdata->caps;
 	struct etmv4_config *config = &drvdata->config;
 
 	if (kstrtoul(buf, 16, &val))
 		return -EINVAL;
 
 	raw_spin_lock(&drvdata->spinlock);
-	if (val > drvdata->nr_pe) {
+	if (val > caps->nr_pe) {
 		raw_spin_unlock(&drvdata->spinlock);
 		return -EINVAL;
 	}
@@ -498,13 +510,14 @@ static ssize_t event_store(struct device *dev,
 {
 	unsigned long val;
 	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	const struct etmv4_caps *caps = &drvdata->caps;
 	struct etmv4_config *config = &drvdata->config;
 
 	if (kstrtoul(buf, 16, &val))
 		return -EINVAL;
 
 	raw_spin_lock(&drvdata->spinlock);
-	switch (drvdata->nr_event) {
+	switch (caps->nr_event) {
 	case 0x0:
 		/* EVENT0, bits[7:0] */
 		config->eventctrl0 = val & 0xFF;
@@ -547,6 +560,7 @@ static ssize_t event_instren_store(struct device *dev,
 {
 	unsigned long val;
 	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	const struct etmv4_caps *caps = &drvdata->caps;
 	struct etmv4_config *config = &drvdata->config;
 
 	if (kstrtoul(buf, 16, &val))
@@ -555,7 +569,7 @@ static ssize_t event_instren_store(struct device *dev,
 	raw_spin_lock(&drvdata->spinlock);
 	/* start by clearing all instruction event enable bits */
 	config->eventctrl1 &= ~TRCEVENTCTL1R_INSTEN_MASK;
-	switch (drvdata->nr_event) {
+	switch (caps->nr_event) {
 	case 0x0:
 		/* generate Event element for event 1 */
 		config->eventctrl1 |= val & TRCEVENTCTL1R_INSTEN_1;
@@ -603,11 +617,12 @@ static ssize_t event_ts_store(struct device *dev,
 {
 	unsigned long val;
 	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	const struct etmv4_caps *caps = &drvdata->caps;
 	struct etmv4_config *config = &drvdata->config;
 
 	if (kstrtoul(buf, 16, &val))
 		return -EINVAL;
-	if (!drvdata->ts_size)
+	if (!caps->ts_size)
 		return -EINVAL;
 
 	config->ts_ctrl = val & ETMv4_EVENT_MASK;
@@ -633,11 +648,12 @@ static ssize_t syncfreq_store(struct device *dev,
 {
 	unsigned long val;
 	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	const struct etmv4_caps *caps = &drvdata->caps;
 	struct etmv4_config *config = &drvdata->config;
 
 	if (kstrtoul(buf, 16, &val))
 		return -EINVAL;
-	if (drvdata->syncpr == true)
+	if (caps->syncpr == true)
 		return -EINVAL;
 
 	config->syncfreq = val & ETMv4_SYNC_MASK;
@@ -663,6 +679,7 @@ static ssize_t cyc_threshold_store(struct device *dev,
 {
 	unsigned long val;
 	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	const struct etmv4_caps *caps = &drvdata->caps;
 	struct etmv4_config *config = &drvdata->config;
 
 	if (kstrtoul(buf, 16, &val))
@@ -670,7 +687,7 @@ static ssize_t cyc_threshold_store(struct device *dev,
 
 	/* mask off max threshold before checking min value */
 	val &= ETM_CYC_THRESHOLD_MASK;
-	if (val < drvdata->ccitmin)
+	if (val < caps->ccitmin)
 		return -EINVAL;
 
 	config->ccctlr = val;
@@ -696,13 +713,14 @@ static ssize_t bb_ctrl_store(struct device *dev,
 {
 	unsigned long val;
 	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	const struct etmv4_caps *caps = &drvdata->caps;
 	struct etmv4_config *config = &drvdata->config;
 
 	if (kstrtoul(buf, 16, &val))
 		return -EINVAL;
-	if (drvdata->trcbb == false)
+	if (caps->trcbb == false)
 		return -EINVAL;
-	if (!drvdata->nr_addr_cmp)
+	if (!caps->nr_addr_cmp)
 		return -EINVAL;
 
 	/*
@@ -768,6 +786,7 @@ static ssize_t s_exlevel_vinst_store(struct device *dev,
 {
 	unsigned long val;
 	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	const struct etmv4_caps *caps = &drvdata->caps;
 	struct etmv4_config *config = &drvdata->config;
 
 	if (kstrtoul(buf, 16, &val))
@@ -777,7 +796,7 @@ static ssize_t s_exlevel_vinst_store(struct device *dev,
 	/* clear all EXLEVEL_S bits  */
 	config->vinst_ctrl &= ~TRCVICTLR_EXLEVEL_S_MASK;
 	/* enable instruction tracing for corresponding exception level */
-	val &= drvdata->s_ex_level;
+	val &= caps->s_ex_level;
 	config->vinst_ctrl |= val << __bf_shf(TRCVICTLR_EXLEVEL_S_MASK);
 	raw_spin_unlock(&drvdata->spinlock);
 	return size;
@@ -803,6 +822,7 @@ static ssize_t ns_exlevel_vinst_store(struct device *dev,
 {
 	unsigned long val;
 	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	const struct etmv4_caps *caps = &drvdata->caps;
 	struct etmv4_config *config = &drvdata->config;
 
 	if (kstrtoul(buf, 16, &val))
@@ -812,7 +832,7 @@ static ssize_t ns_exlevel_vinst_store(struct device *dev,
 	/* clear EXLEVEL_NS bits  */
 	config->vinst_ctrl &= ~TRCVICTLR_EXLEVEL_NS_MASK;
 	/* enable instruction tracing for corresponding exception level */
-	val &= drvdata->ns_ex_level;
+	val &= caps->ns_ex_level;
 	config->vinst_ctrl |= val << __bf_shf(TRCVICTLR_EXLEVEL_NS_MASK);
 	raw_spin_unlock(&drvdata->spinlock);
 	return size;
@@ -837,11 +857,12 @@ static ssize_t addr_idx_store(struct device *dev,
 {
 	unsigned long val;
 	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	const struct etmv4_caps *caps = &drvdata->caps;
 	struct etmv4_config *config = &drvdata->config;
 
 	if (kstrtoul(buf, 16, &val))
 		return -EINVAL;
-	if (val >= drvdata->nr_addr_cmp * 2)
+	if (val >= caps->nr_addr_cmp * 2)
 		return -EINVAL;
 
 	/*
@@ -1060,6 +1081,7 @@ static ssize_t addr_start_store(struct device *dev,
 	u8 idx;
 	unsigned long val;
 	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	const struct etmv4_caps *caps = &drvdata->caps;
 	struct etmv4_config *config = &drvdata->config;
 
 	if (kstrtoul(buf, 16, &val))
@@ -1067,7 +1089,7 @@ static ssize_t addr_start_store(struct device *dev,
 
 	raw_spin_lock(&drvdata->spinlock);
 	idx = config->addr_idx;
-	if (!drvdata->nr_addr_cmp) {
+	if (!caps->nr_addr_cmp) {
 		raw_spin_unlock(&drvdata->spinlock);
 		return -EINVAL;
 	}
@@ -1115,6 +1137,7 @@ static ssize_t addr_stop_store(struct device *dev,
 	u8 idx;
 	unsigned long val;
 	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	const struct etmv4_caps *caps = &drvdata->caps;
 	struct etmv4_config *config = &drvdata->config;
 
 	if (kstrtoul(buf, 16, &val))
@@ -1122,7 +1145,7 @@ static ssize_t addr_stop_store(struct device *dev,
 
 	raw_spin_lock(&drvdata->spinlock);
 	idx = config->addr_idx;
-	if (!drvdata->nr_addr_cmp) {
+	if (!caps->nr_addr_cmp) {
 		raw_spin_unlock(&drvdata->spinlock);
 		return -EINVAL;
 	}
@@ -1167,6 +1190,7 @@ static ssize_t addr_ctxtype_store(struct device *dev,
 	u8 idx;
 	char str[10] = "";
 	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	const struct etmv4_caps *caps = &drvdata->caps;
 	struct etmv4_config *config = &drvdata->config;
 
 	if (strlen(buf) >= 10)
@@ -1181,13 +1205,13 @@ static ssize_t addr_ctxtype_store(struct device *dev,
 		config->addr_acc[idx] &= ~TRCACATRn_CONTEXTTYPE_MASK;
 	else if (!strcmp(str, "ctxid")) {
 		/* 0b01 The trace unit performs a Context ID */
-		if (drvdata->numcidc) {
+		if (caps->numcidc) {
 			config->addr_acc[idx] |= TRCACATRn_CONTEXTTYPE_CTXID;
 			config->addr_acc[idx] &= ~TRCACATRn_CONTEXTTYPE_VMID;
 		}
 	} else if (!strcmp(str, "vmid")) {
 		/* 0b10 The trace unit performs a VMID */
-		if (drvdata->numvmidc) {
+		if (caps->numvmidc) {
 			config->addr_acc[idx] &= ~TRCACATRn_CONTEXTTYPE_CTXID;
 			config->addr_acc[idx] |= TRCACATRn_CONTEXTTYPE_VMID;
 		}
@@ -1196,9 +1220,9 @@ static ssize_t addr_ctxtype_store(struct device *dev,
 		 * 0b11 The trace unit performs a Context ID
 		 * comparison and a VMID
 		 */
-		if (drvdata->numcidc)
+		if (caps->numcidc)
 			config->addr_acc[idx] |= TRCACATRn_CONTEXTTYPE_CTXID;
-		if (drvdata->numvmidc)
+		if (caps->numvmidc)
 			config->addr_acc[idx] |= TRCACATRn_CONTEXTTYPE_VMID;
 	}
 	raw_spin_unlock(&drvdata->spinlock);
@@ -1230,14 +1254,15 @@ static ssize_t addr_context_store(struct device *dev,
 	u8 idx;
 	unsigned long val;
 	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	const struct etmv4_caps *caps = &drvdata->caps;
 	struct etmv4_config *config = &drvdata->config;
 
 	if (kstrtoul(buf, 16, &val))
 		return -EINVAL;
-	if ((drvdata->numcidc <= 1) && (drvdata->numvmidc <= 1))
+	if ((caps->numcidc <= 1) && (caps->numvmidc <= 1))
 		return -EINVAL;
-	if (val >=  (drvdata->numcidc >= drvdata->numvmidc ?
-		     drvdata->numcidc : drvdata->numvmidc))
+	if (val >=  (caps->numcidc >= caps->numvmidc ?
+		     caps->numcidc : caps->numvmidc))
 		return -EINVAL;
 
 	raw_spin_lock(&drvdata->spinlock);
@@ -1348,9 +1373,10 @@ static ssize_t vinst_pe_cmp_start_stop_show(struct device *dev,
 {
 	unsigned long val;
 	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	const struct etmv4_caps *caps = &drvdata->caps;
 	struct etmv4_config *config = &drvdata->config;
 
-	if (!drvdata->nr_pe_cmp)
+	if (!caps->nr_pe_cmp)
 		return -EINVAL;
 	val = config->vipcssctlr;
 	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
@@ -1361,11 +1387,12 @@ static ssize_t vinst_pe_cmp_start_stop_store(struct device *dev,
 {
 	unsigned long val;
 	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	const struct etmv4_caps *caps = &drvdata->caps;
 	struct etmv4_config *config = &drvdata->config;
 
 	if (kstrtoul(buf, 16, &val))
 		return -EINVAL;
-	if (!drvdata->nr_pe_cmp)
+	if (!caps->nr_pe_cmp)
 		return -EINVAL;
 
 	raw_spin_lock(&drvdata->spinlock);
@@ -1393,11 +1420,12 @@ static ssize_t seq_idx_store(struct device *dev,
 {
 	unsigned long val;
 	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	const struct etmv4_caps *caps = &drvdata->caps;
 	struct etmv4_config *config = &drvdata->config;
 
 	if (kstrtoul(buf, 16, &val))
 		return -EINVAL;
-	if (val >= drvdata->nrseqstate - 1)
+	if (val >= caps->nrseqstate - 1)
 		return -EINVAL;
 
 	/*
@@ -1429,11 +1457,12 @@ static ssize_t seq_state_store(struct device *dev,
 {
 	unsigned long val;
 	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	const struct etmv4_caps *caps = &drvdata->caps;
 	struct etmv4_config *config = &drvdata->config;
 
 	if (kstrtoul(buf, 16, &val))
 		return -EINVAL;
-	if (val >= drvdata->nrseqstate)
+	if (val >= caps->nrseqstate)
 		return -EINVAL;
 
 	config->seq_state = val;
@@ -1496,11 +1525,12 @@ static ssize_t seq_reset_event_store(struct device *dev,
 {
 	unsigned long val;
 	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	const struct etmv4_caps *caps = &drvdata->caps;
 	struct etmv4_config *config = &drvdata->config;
 
 	if (kstrtoul(buf, 16, &val))
 		return -EINVAL;
-	if (!(drvdata->nrseqstate))
+	if (!(caps->nrseqstate))
 		return -EINVAL;
 
 	config->seq_rst = val & ETMv4_EVENT_MASK;
@@ -1526,11 +1556,12 @@ static ssize_t cntr_idx_store(struct device *dev,
 {
 	unsigned long val;
 	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	const struct etmv4_caps *caps = &drvdata->caps;
 	struct etmv4_config *config = &drvdata->config;
 
 	if (kstrtoul(buf, 16, &val))
 		return -EINVAL;
-	if (val >= drvdata->nr_cntr)
+	if (val >= caps->nr_cntr)
 		return -EINVAL;
 
 	/*
@@ -1674,6 +1705,7 @@ static ssize_t res_idx_store(struct device *dev,
 {
 	unsigned long val;
 	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	const struct etmv4_caps *caps = &drvdata->caps;
 	struct etmv4_config *config = &drvdata->config;
 
 	if (kstrtoul(buf, 16, &val))
@@ -1682,7 +1714,7 @@ static ssize_t res_idx_store(struct device *dev,
 	 * Resource selector pair 0 is always implemented and reserved,
 	 * namely an idx with 0 and 1 is illegal.
 	 */
-	if ((val < 2) || (val >= 2 * drvdata->nr_resource))
+	if ((val < 2) || (val >= 2 * caps->nr_resource))
 		return -EINVAL;
 
 	/*
@@ -1756,11 +1788,12 @@ static ssize_t sshot_idx_store(struct device *dev,
 {
 	unsigned long val;
 	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	const struct etmv4_caps *caps = &drvdata->caps;
 	struct etmv4_config *config = &drvdata->config;
 
 	if (kstrtoul(buf, 16, &val))
 		return -EINVAL;
-	if (val >= drvdata->nr_ss_cmp)
+	if (val >= caps->nr_ss_cmp)
 		return -EINVAL;
 
 	raw_spin_lock(&drvdata->spinlock);
@@ -1874,11 +1907,12 @@ static ssize_t ctxid_idx_store(struct device *dev,
 {
 	unsigned long val;
 	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	const struct etmv4_caps *caps = &drvdata->caps;
 	struct etmv4_config *config = &drvdata->config;
 
 	if (kstrtoul(buf, 16, &val))
 		return -EINVAL;
-	if (val >= drvdata->numcidc)
+	if (val >= caps->numcidc)
 		return -EINVAL;
 
 	/*
@@ -1922,6 +1956,7 @@ static ssize_t ctxid_pid_store(struct device *dev,
 	u8 idx;
 	unsigned long pid;
 	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	const struct etmv4_caps *caps = &drvdata->caps;
 	struct etmv4_config *config = &drvdata->config;
 
 	/*
@@ -1941,7 +1976,7 @@ static ssize_t ctxid_pid_store(struct device *dev,
 	 * ctxid comparator is implemented and ctxid is greater than 0 bits
 	 * in length
 	 */
-	if (!drvdata->ctxid_size || !drvdata->numcidc)
+	if (!caps->ctxid_size || !caps->numcidc)
 		return -EINVAL;
 	if (kstrtoul(buf, 16, &pid))
 		return -EINVAL;
@@ -1983,6 +2018,7 @@ static ssize_t ctxid_masks_store(struct device *dev,
 	u8 i, j, maskbyte;
 	unsigned long val1, val2, mask;
 	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	const struct etmv4_caps *caps = &drvdata->caps;
 	struct etmv4_config *config = &drvdata->config;
 	int nr_inputs;
 
@@ -1998,11 +2034,11 @@ static ssize_t ctxid_masks_store(struct device *dev,
 	 * ctxid comparator is implemented and ctxid is greater than 0 bits
 	 * in length
 	 */
-	if (!drvdata->ctxid_size || !drvdata->numcidc)
+	if (!caps->ctxid_size || !caps->numcidc)
 		return -EINVAL;
 	/* one mask if <= 4 comparators, two for up to 8 */
 	nr_inputs = sscanf(buf, "%lx %lx", &val1, &val2);
-	if ((drvdata->numcidc > 4) && (nr_inputs != 2))
+	if ((caps->numcidc > 4) && (nr_inputs != 2))
 		return -EINVAL;
 
 	raw_spin_lock(&drvdata->spinlock);
@@ -2010,7 +2046,7 @@ static ssize_t ctxid_masks_store(struct device *dev,
 	 * each byte[0..3] controls mask value applied to ctxid
 	 * comparator[0..3]
 	 */
-	switch (drvdata->numcidc) {
+	switch (caps->numcidc) {
 	case 0x1:
 		/* COMP0, bits[7:0] */
 		config->ctxid_mask0 = val1 & 0xFF;
@@ -2057,7 +2093,7 @@ static ssize_t ctxid_masks_store(struct device *dev,
 	 * of ctxid comparator0 value (corresponding to byte 0) register.
 	 */
 	mask = config->ctxid_mask0;
-	for (i = 0; i < drvdata->numcidc; i++) {
+	for (i = 0; i < caps->numcidc; i++) {
 		/* mask value of corresponding ctxid comparator */
 		maskbyte = mask & ETMv4_EVENT_MASK;
 		/*
@@ -2100,11 +2136,12 @@ static ssize_t vmid_idx_store(struct device *dev,
 {
 	unsigned long val;
 	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	const struct etmv4_caps *caps = &drvdata->caps;
 	struct etmv4_config *config = &drvdata->config;
 
 	if (kstrtoul(buf, 16, &val))
 		return -EINVAL;
-	if (val >= drvdata->numvmidc)
+	if (val >= caps->numvmidc)
 		return -EINVAL;
 
 	/*
@@ -2145,6 +2182,7 @@ static ssize_t vmid_val_store(struct device *dev,
 {
 	unsigned long val;
 	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	const struct etmv4_caps *caps = &drvdata->caps;
 	struct etmv4_config *config = &drvdata->config;
 
 	/*
@@ -2158,7 +2196,7 @@ static ssize_t vmid_val_store(struct device *dev,
 	 * only implemented when vmid tracing is enabled, i.e. at least one
 	 * vmid comparator is implemented and at least 8 bit vmid size
 	 */
-	if (!drvdata->vmid_size || !drvdata->numvmidc)
+	if (!caps->vmid_size || !caps->numvmidc)
 		return -EINVAL;
 	if (kstrtoul(buf, 16, &val))
 		return -EINVAL;
@@ -2198,6 +2236,7 @@ static ssize_t vmid_masks_store(struct device *dev,
 	u8 i, j, maskbyte;
 	unsigned long val1, val2, mask;
 	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	const struct etmv4_caps *caps = &drvdata->caps;
 	struct etmv4_config *config = &drvdata->config;
 	int nr_inputs;
 
@@ -2212,11 +2251,11 @@ static ssize_t vmid_masks_store(struct device *dev,
 	 * only implemented when vmid tracing is enabled, i.e. at least one
 	 * vmid comparator is implemented and at least 8 bit vmid size
 	 */
-	if (!drvdata->vmid_size || !drvdata->numvmidc)
+	if (!caps->vmid_size || !caps->numvmidc)
 		return -EINVAL;
 	/* one mask if <= 4 comparators, two for up to 8 */
 	nr_inputs = sscanf(buf, "%lx %lx", &val1, &val2);
-	if ((drvdata->numvmidc > 4) && (nr_inputs != 2))
+	if ((caps->numvmidc > 4) && (nr_inputs != 2))
 		return -EINVAL;
 
 	raw_spin_lock(&drvdata->spinlock);
@@ -2225,7 +2264,7 @@ static ssize_t vmid_masks_store(struct device *dev,
 	 * each byte[0..3] controls mask value applied to vmid
 	 * comparator[0..3]
 	 */
-	switch (drvdata->numvmidc) {
+	switch (caps->numvmidc) {
 	case 0x1:
 		/* COMP0, bits[7:0] */
 		config->vmid_mask0 = val1 & 0xFF;
@@ -2273,7 +2312,7 @@ static ssize_t vmid_masks_store(struct device *dev,
 	 * of vmid comparator0 value (corresponding to byte 0) register.
 	 */
 	mask = config->vmid_mask0;
-	for (i = 0; i < drvdata->numvmidc; i++) {
+	for (i = 0; i < caps->numvmidc; i++) {
 		/* mask value of corresponding vmid comparator */
 		maskbyte = mask & ETMv4_EVENT_MASK;
 		/*
diff --git a/drivers/hwtracing/coresight/coresight-etm4x.h b/drivers/hwtracing/coresight/coresight-etm4x.h
index 89d81ce4e04e..3e20561672dc 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x.h
+++ b/drivers/hwtracing/coresight/coresight-etm4x.h
@@ -812,6 +812,94 @@ enum etm_impdef_type {
 	ETM4_IMPDEF_FEATURE_MAX,
 };
 
+/**
+ * struct etmv4_caps - specifics ETM capabilities
+ * @nr_pe:	The number of processing entity available for tracing.
+ * @nr_pe_cmp:	The number of processing entity comparator inputs that are
+ *		available for tracing.
+ * @nr_addr_cmp:Number of pairs of address comparators available
+ *		as found in ETMIDR4 0-3.
+ * @nr_cntr:    Number of counters as found in ETMIDR5 bit 28-30.
+ * @nr_ext_inp: Number of external input.
+ * @numcidc:	Number of contextID comparators.
+ * @numvmidc:	Number of VMID comparators.
+ * @nrseqstate: The number of sequencer states that are implemented.
+ * @nr_event:	Indicates how many events the trace unit support.
+ * @nr_resource:The number of resource selection pairs available for tracing.
+ * @nr_ss_cmp:	Number of single-shot comparator controls that are available.
+ * @trcid_size: Indicates the trace ID width.
+ * @ts_size:	Global timestamp size field.
+ * @ctxid_size:	Size of the context ID field to consider.
+ * @vmid_size:	Size of the VM ID comparator to consider.
+ * @ccsize:	Indicates the size of the cycle counter in bits.
+ * @ccitmin:	minimum value that can be programmed in
+ * @s_ex_level:	In secure state, indicates whether instruction tracing is
+ *		supported for the corresponding Exception level.
+ * @ns_ex_level:In non-secure state, indicates whether instruction tracing is
+ *		supported for the corresponding Exception level.
+ * @q_support:	Q element support characteristics.
+ * @os_lock_model: OSLock model.
+ * @instrp0:	Tracing of load and store instructions
+ *		as P0 elements is supported.
+ * @q_filt:	Q element filtering support, if Q elements are supported.
+ * @trcbb:	Indicates if the trace unit supports branch broadcast tracing.
+ * @trccond:	If the trace unit supports conditional
+ *		instruction tracing.
+ * @retstack:	Indicates if the implementation supports a return stack.
+ * @trccci:	Indicates if the trace unit supports cycle counting
+ *		for instruction.
+ * @trc_error:	Whether a trace unit can trace a system
+ *		error exception.
+ * @syncpr:	Indicates if an implementation has a fixed
+ *		synchronization period.
+ * @stallctl:	If functionality that prevents trace unit buffer overflows
+ *		is available.
+ * @sysstall:	Does the system support stall control of the PE?
+ * @nooverflow:	Indicate if overflow prevention is supported.
+ * @atbtrig:	If the implementation can support ATB triggers
+ * @lpoverride:	If the implementation can support low-power state over.
+ * @skip_power_up: Indicates if an implementation can skip powering up
+ *		   the trace unit.
+ */
+struct etmv4_caps {
+	u8	nr_pe;
+	u8	nr_pe_cmp;
+	u8	nr_addr_cmp;
+	u8	nr_cntr;
+	u8	nr_ext_inp;
+	u8	numcidc;
+	u8	numextinsel;
+	u8	numvmidc;
+	u8	nrseqstate;
+	u8	nr_event;
+	u8	nr_resource;
+	u8	nr_ss_cmp;
+	u8	trcid_size;
+	u8	ts_size;
+	u8	ctxid_size;
+	u8	vmid_size;
+	u8	ccsize;
+	u16	ccitmin;
+	u8	s_ex_level;
+	u8	ns_ex_level;
+	u8	q_support;
+	u8	os_lock_model;
+	bool	instrp0 : 1;
+	bool	q_filt : 1;
+	bool	trcbb : 1;
+	bool	trccond : 1;
+	bool	retstack : 1;
+	bool	trccci : 1;
+	bool	trc_error : 1;
+	bool	syncpr : 1;
+	bool	stallctl : 1;
+	bool	sysstall : 1;
+	bool	nooverflow : 1;
+	bool	atbtrig : 1;
+	bool	lpoverride : 1;
+	bool	skip_power_up : 1;
+};
+
 /**
  * struct etmv4_config - configuration information related to an ETMv4
  * @mode:	Controls various modes supported by this ETM.
@@ -819,8 +907,8 @@ enum etm_impdef_type {
  * @cfg:	Controls the tracing options.
  * @eventctrl0: Controls the tracing of arbitrary events.
  * @eventctrl1: Controls the behavior of the events that @event_ctrl0 selects.
- * @stallctl:	If functionality that prevents trace unit buffer overflows
- *		is available.
+ * @stall_ctrl:	Enables trace unit functionality that prevents trace
+ *		unit buffer overflows.
  * @ts_ctrl:	Controls the insertion of global timestamps in the
  *		trace streams.
  * @syncfreq:	Controls how often trace synchronization requests occur.
@@ -971,61 +1059,17 @@ struct etmv4_save_state {
  * @mode:	This tracer's mode, i.e sysFS, Perf or disabled.
  * @cpu:        The cpu this component is affined to.
  * @arch:       ETM architecture version.
- * @nr_pe:	The number of processing entity available for tracing.
- * @nr_pe_cmp:	The number of processing entity comparator inputs that are
- *		available for tracing.
- * @nr_addr_cmp:Number of pairs of address comparators available
- *		as found in ETMIDR4 0-3.
- * @nr_cntr:    Number of counters as found in ETMIDR5 bit 28-30.
- * @nr_ext_inp: Number of external input.
- * @numcidc:	Number of contextID comparators.
- * @numvmidc:	Number of VMID comparators.
- * @nrseqstate: The number of sequencer states that are implemented.
- * @nr_event:	Indicates how many events the trace unit support.
- * @nr_resource:The number of resource selection pairs available for tracing.
- * @nr_ss_cmp:	Number of single-shot comparator controls that are available.
+ * @caps:	ETM capabilities.
  * @trcid:	value of the current ID for this component.
- * @trcid_size: Indicates the trace ID width.
- * @ts_size:	Global timestamp size field.
- * @ctxid_size:	Size of the context ID field to consider.
- * @vmid_size:	Size of the VM ID comparator to consider.
- * @ccsize:	Indicates the size of the cycle counter in bits.
- * @ccitmin:	minimum value that can be programmed in
- * @s_ex_level:	In secure state, indicates whether instruction tracing is
- *		supported for the corresponding Exception level.
- * @ns_ex_level:In non-secure state, indicates whether instruction tracing is
- *		supported for the corresponding Exception level.
  * @sticky_enable: true if ETM base configuration has been done.
  * @boot_enable:True if we should start tracing at boot time.
  * @os_unlock:  True if access to management registers is allowed.
- * @instrp0:	Tracing of load and store instructions
- *		as P0 elements is supported.
- * @q_filt:	Q element filtering support, if Q elements are supported.
- * @trcbb:	Indicates if the trace unit supports branch broadcast tracing.
- * @trccond:	If the trace unit supports conditional
- *		instruction tracing.
- * @retstack:	Indicates if the implementation supports a return stack.
- * @trccci:	Indicates if the trace unit supports cycle counting
- *		for instruction.
- * @q_support:	Q element support characteristics.
- * @trc_error:	Whether a trace unit can trace a system
- *		error exception.
- * @syncpr:	Indicates if an implementation has a fixed
- *		synchronization period.
- * @stall_ctrl:	Enables trace unit functionality that prevents trace
- *		unit buffer overflows.
- * @sysstall:	Does the system support stall control of the PE?
- * @nooverflow:	Indicate if overflow prevention is supported.
- * @atbtrig:	If the implementation can support ATB triggers
- * @lpoverride:	If the implementation can support low-power state over.
  * @trfcr:	If the CPU supports FEAT_TRF, value of the TRFCR_ELx that
  *		allows tracing at all ELs. We don't want to compute this
  *		at runtime, due to the additional setting of TRFCR_CX when
  *		in EL2. Otherwise, 0.
  * @config:	structure holding configuration parameters.
  * @save_state:	State to be preserved across power loss
- * @skip_power_up: Indicates if an implementation can skip powering up
- *		   the trace unit.
  * @paused:	Indicates if the trace unit is paused.
  * @arch_features: Bitmap of arch features of etmv4 devices.
  */
@@ -1037,46 +1081,11 @@ struct etmv4_drvdata {
 	raw_spinlock_t			spinlock;
 	int				cpu;
 	u8				arch;
-	u8				nr_pe;
-	u8				nr_pe_cmp;
-	u8				nr_addr_cmp;
-	u8				nr_cntr;
-	u8				nr_ext_inp;
-	u8				numcidc;
-	u8				numextinsel;
-	u8				numvmidc;
-	u8				nrseqstate;
-	u8				nr_event;
-	u8				nr_resource;
-	u8				nr_ss_cmp;
+	struct etmv4_caps 		caps;
 	u8				trcid;
-	u8				trcid_size;
-	u8				ts_size;
-	u8				ctxid_size;
-	u8				vmid_size;
-	u8				ccsize;
-	u16				ccitmin;
-	u8				s_ex_level;
-	u8				ns_ex_level;
-	u8				q_support;
-	u8				os_lock_model;
 	bool				sticky_enable : 1;
 	bool				boot_enable : 1;
 	bool				os_unlock : 1;
-	bool				instrp0 : 1;
-	bool				q_filt : 1;
-	bool				trcbb : 1;
-	bool				trccond : 1;
-	bool				retstack : 1;
-	bool				trccci : 1;
-	bool				trc_error : 1;
-	bool				syncpr : 1;
-	bool				stallctl : 1;
-	bool				sysstall : 1;
-	bool				nooverflow : 1;
-	bool				atbtrig : 1;
-	bool				lpoverride : 1;
-	bool				skip_power_up : 1;
 	bool				paused : 1;
 	u64				trfcr;
 	struct etmv4_config		config;
-- 
LEVI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}



^ permalink raw reply related

* [PATCH v2 4/5] coresight: etm3x: introduce struct etm_caps
From: Yeoreum Yun @ 2026-04-10  7:43 UTC (permalink / raw)
  To: coresight, linux-arm-kernel, linux-kernel
  Cc: suzuki.poulose, mike.leach, james.clark, alexander.shishkin,
	leo.yan, Yeoreum Yun
In-Reply-To: <20260410074310.2693385-1-yeoreum.yun@arm.com>

Introduce struct etm_caps to describe ETMv3 capabilities
and move capabilities information into it.

Since drvdata->etmccr and drvdata->etmccer are used to check
whether it supports fifofull logic and timestamping,
remove etmccr and etmccer field from drvdata and add relevant fields
in etm_caps structure.

Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
---
 drivers/hwtracing/coresight/coresight-etm.h   | 40 +++++++++++--------
 .../coresight/coresight-etm3x-core.c          | 33 ++++++++-------
 .../coresight/coresight-etm3x-sysfs.c         | 14 ++++---
 3 files changed, 52 insertions(+), 35 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-etm.h b/drivers/hwtracing/coresight/coresight-etm.h
index 1d753cca2943..6fda26039db8 100644
--- a/drivers/hwtracing/coresight/coresight-etm.h
+++ b/drivers/hwtracing/coresight/coresight-etm.h
@@ -140,6 +140,28 @@
 				 ETM_ADD_COMP_0		|	\
 				 ETM_EVENT_NOT_A)
 
+/**
+ * struct etmv4_caps - specifics ETM capabilities
+ * @port_size:	port size as reported by ETMCR bit 4-6 and 21.
+ * @nr_addr_cmp:Number of pairs of address comparators as found in ETMCCR.
+ * @nr_cntr:	Number of counters as found in ETMCCR bit 13-15.
+ * @nr_ext_inp:	Number of external input as found in ETMCCR bit 17-19.
+ * @nr_ext_out:	Number of external output as found in ETMCCR bit 20-22.
+ * @nr_ctxid_cmp: Number of contextID comparators as found in ETMCCR bit 24-25.
+ * @fifofull: FIFOFULL logic is present.
+ * @timestamp: Timestamping is implemented.
+ */
+struct etm_caps {
+	int	port_size;
+	u8	nr_addr_cmp;
+	u8	nr_cntr;
+	u8	nr_ext_inp;
+	u8	nr_ext_out;
+	u8	nr_ctxid_cmp;
+	bool	fifofull : 1;
+	bool	timestamp : 1;
+};
+
 /**
  * struct etm_config - configuration information related to an ETM
  * @mode:	controls various modes supported by this ETM/PTM.
@@ -212,19 +234,12 @@ struct etm_config {
  * @csdev:	component vitals needed by the framework.
  * @spinlock:	only one at a time pls.
  * @cpu:	the cpu this component is affined to.
- * @port_size:	port size as reported by ETMCR bit 4-6 and 21.
  * @arch:	ETM/PTM version number.
+ * @caps:	ETM capabilities.
  * @use_cpu14:	true if management registers need to be accessed via CP14.
  * @sticky_enable: true if ETM base configuration has been done.
  * @boot_enable:true if we should start tracing at boot time.
  * @os_unlock:	true if access to management registers is allowed.
- * @nr_addr_cmp:Number of pairs of address comparators as found in ETMCCR.
- * @nr_cntr:	Number of counters as found in ETMCCR bit 13-15.
- * @nr_ext_inp:	Number of external input as found in ETMCCR bit 17-19.
- * @nr_ext_out:	Number of external output as found in ETMCCR bit 20-22.
- * @nr_ctxid_cmp: Number of contextID comparators as found in ETMCCR bit 24-25.
- * @etmccr:	value of register ETMCCR.
- * @etmccer:	value of register ETMCCER.
  * @traceid:	value of the current ID for this component.
  * @config:	structure holding configuration parameters.
  */
@@ -234,19 +249,12 @@ struct etm_drvdata {
 	struct coresight_device		*csdev;
 	spinlock_t			spinlock;
 	int				cpu;
-	int				port_size;
 	u8				arch;
+	struct etm_caps			caps;
 	bool				use_cp14;
 	bool				sticky_enable;
 	bool				boot_enable;
 	bool				os_unlock;
-	u8				nr_addr_cmp;
-	u8				nr_cntr;
-	u8				nr_ext_inp;
-	u8				nr_ext_out;
-	u8				nr_ctxid_cmp;
-	u32				etmccr;
-	u32				etmccer;
 	u32				traceid;
 	struct etm_config		config;
 };
diff --git a/drivers/hwtracing/coresight/coresight-etm3x-core.c b/drivers/hwtracing/coresight/coresight-etm3x-core.c
index a547a6d2e0bd..b7e977defb1c 100644
--- a/drivers/hwtracing/coresight/coresight-etm3x-core.c
+++ b/drivers/hwtracing/coresight/coresight-etm3x-core.c
@@ -367,6 +367,7 @@ static int etm_enable_hw(struct etm_drvdata *drvdata)
 {
 	int i, rc;
 	u32 etmcr;
+	const struct etm_caps *caps = &drvdata->caps;
 	struct etm_config *config = &drvdata->config;
 	struct coresight_device *csdev = drvdata->csdev;
 
@@ -388,7 +389,7 @@ static int etm_enable_hw(struct etm_drvdata *drvdata)
 	etmcr = etm_readl(drvdata, ETMCR);
 	/* Clear setting from a previous run if need be */
 	etmcr &= ~ETM3X_SUPPORTED_OPTIONS;
-	etmcr |= drvdata->port_size;
+	etmcr |= caps->port_size;
 	etmcr |= ETMCR_ETM_EN;
 	etm_writel(drvdata, config->ctrl | etmcr, ETMCR);
 	etm_writel(drvdata, config->trigger_event, ETMTRIGGER);
@@ -396,11 +397,11 @@ static int etm_enable_hw(struct etm_drvdata *drvdata)
 	etm_writel(drvdata, config->enable_event, ETMTEEVR);
 	etm_writel(drvdata, config->enable_ctrl1, ETMTECR1);
 	etm_writel(drvdata, config->fifofull_level, ETMFFLR);
-	for (i = 0; i < drvdata->nr_addr_cmp; i++) {
+	for (i = 0; i < caps->nr_addr_cmp; i++) {
 		etm_writel(drvdata, config->addr_val[i], ETMACVRn(i));
 		etm_writel(drvdata, config->addr_acctype[i], ETMACTRn(i));
 	}
-	for (i = 0; i < drvdata->nr_cntr; i++) {
+	for (i = 0; i < caps->nr_cntr; i++) {
 		etm_writel(drvdata, config->cntr_rld_val[i], ETMCNTRLDVRn(i));
 		etm_writel(drvdata, config->cntr_event[i], ETMCNTENRn(i));
 		etm_writel(drvdata, config->cntr_rld_event[i],
@@ -414,9 +415,9 @@ static int etm_enable_hw(struct etm_drvdata *drvdata)
 	etm_writel(drvdata, config->seq_32_event, ETMSQ32EVR);
 	etm_writel(drvdata, config->seq_13_event, ETMSQ13EVR);
 	etm_writel(drvdata, config->seq_curr_state, ETMSQR);
-	for (i = 0; i < drvdata->nr_ext_out; i++)
+	for (i = 0; i < caps->nr_ext_out; i++)
 		etm_writel(drvdata, ETM_DEFAULT_EVENT_VAL, ETMEXTOUTEVRn(i));
-	for (i = 0; i < drvdata->nr_ctxid_cmp; i++)
+	for (i = 0; i < caps->nr_ctxid_cmp; i++)
 		etm_writel(drvdata, config->ctxid_pid[i], ETMCIDCVRn(i));
 	etm_writel(drvdata, config->ctxid_mask, ETMCIDCMR);
 	etm_writel(drvdata, config->sync_freq, ETMSYNCFR);
@@ -572,7 +573,7 @@ static void etm_disable_hw(struct etm_drvdata *drvdata)
 	/* Read back sequencer and counters for post trace analysis */
 	config->seq_curr_state = (etm_readl(drvdata, ETMSQR) & ETM_SQR_MASK);
 
-	for (i = 0; i < drvdata->nr_cntr; i++)
+	for (i = 0; i < caps->nr_cntr; i++)
 		config->cntr_val[i] = etm_readl(drvdata, ETMCNTVRn(i));
 
 	etm_set_pwrdwn(drvdata);
@@ -754,7 +755,9 @@ static void etm_init_arch_data(void *info)
 {
 	u32 etmidr;
 	u32 etmccr;
+	u32 etmccer;
 	struct etm_drvdata *drvdata = info;
+	struct etm_caps *caps = &drvdata->caps;
 
 	/* Make sure all registers are accessible */
 	etm_os_unlock(drvdata);
@@ -779,16 +782,18 @@ static void etm_init_arch_data(void *info)
 	/* Find all capabilities */
 	etmidr = etm_readl(drvdata, ETMIDR);
 	drvdata->arch = BMVAL(etmidr, 4, 11);
-	drvdata->port_size = etm_readl(drvdata, ETMCR) & PORT_SIZE_MASK;
+	caps->port_size = etm_readl(drvdata, ETMCR) & PORT_SIZE_MASK;
+
+	etmccer = etm_readl(drvdata, ETMCCER);
+	caps->timestamp = !!(drvdata->etmccer & ETMCCER_TIMESTAMP);
 
-	drvdata->etmccer = etm_readl(drvdata, ETMCCER);
 	etmccr = etm_readl(drvdata, ETMCCR);
-	drvdata->etmccr = etmccr;
-	drvdata->nr_addr_cmp = BMVAL(etmccr, 0, 3) * 2;
-	drvdata->nr_cntr = BMVAL(etmccr, 13, 15);
-	drvdata->nr_ext_inp = BMVAL(etmccr, 17, 19);
-	drvdata->nr_ext_out = BMVAL(etmccr, 20, 22);
-	drvdata->nr_ctxid_cmp = BMVAL(etmccr, 24, 25);
+	caps->fifofull = !!(drvdata->etmccr & ETMCCR_FIFOFULL);
+	caps->nr_addr_cmp = BMVAL(etmccr, 0, 3) * 2;
+	caps->nr_cntr = BMVAL(etmccr, 13, 15);
+	caps->nr_ext_inp = BMVAL(etmccr, 17, 19);
+	caps->nr_ext_out = BMVAL(etmccr, 20, 22);
+	caps->nr_ctxid_cmp = BMVAL(etmccr, 24, 25);
 
 	coresight_clear_self_claim_tag_unlocked(&drvdata->csa);
 	etm_set_pwrdwn(drvdata);
diff --git a/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c b/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c
index 762109307b86..0d8dac29d055 100644
--- a/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c
+++ b/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c
@@ -111,6 +111,7 @@ static ssize_t mode_store(struct device *dev,
 	int ret;
 	unsigned long val;
 	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	const struct etm_caps *caps = &drvdata->caps;
 	struct etm_config *config = &drvdata->config;
 
 	ret = kstrtoul(buf, 16, &val);
@@ -131,7 +132,7 @@ static ssize_t mode_store(struct device *dev,
 		config->ctrl &= ~ETMCR_CYC_ACC;
 
 	if (config->mode & ETM_MODE_STALL) {
-		if (!(drvdata->etmccr & ETMCCR_FIFOFULL)) {
+		if (!caps->fifofull) {
 			dev_warn(dev, "stall mode not supported\n");
 			ret = -EINVAL;
 			goto err_unlock;
@@ -141,7 +142,7 @@ static ssize_t mode_store(struct device *dev,
 		config->ctrl &= ~ETMCR_STALL_MODE;
 
 	if (config->mode & ETM_MODE_TIMESTAMP) {
-		if (!(drvdata->etmccer & ETMCCER_TIMESTAMP)) {
+		if (!caps->timestamp) {
 			dev_warn(dev, "timestamp not supported\n");
 			ret = -EINVAL;
 			goto err_unlock;
@@ -286,13 +287,14 @@ static ssize_t addr_idx_store(struct device *dev,
 	int ret;
 	unsigned long val;
 	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	const struct etm_caps *caps = &drvdata->caps;
 	struct etm_config *config = &drvdata->config;
 
 	ret = kstrtoul(buf, 16, &val);
 	if (ret)
 		return ret;
 
-	if (val >= drvdata->nr_addr_cmp)
+	if (val >= caps->nr_addr_cmp)
 		return -EINVAL;
 
 	/*
@@ -589,13 +591,14 @@ static ssize_t cntr_idx_store(struct device *dev,
 	int ret;
 	unsigned long val;
 	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	const struct etm_caps *caps = &drvdata->caps;
 	struct etm_config *config = &drvdata->config;
 
 	ret = kstrtoul(buf, 16, &val);
 	if (ret)
 		return ret;
 
-	if (val >= drvdata->nr_cntr)
+	if (val >= caps->nr_cntr)
 		return -EINVAL;
 	/*
 	 * Use spinlock to ensure index doesn't change while it gets
@@ -999,13 +1002,14 @@ static ssize_t ctxid_idx_store(struct device *dev,
 	int ret;
 	unsigned long val;
 	struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	const struct etm_caps *caps = &drvdata->caps;
 	struct etm_config *config = &drvdata->config;
 
 	ret = kstrtoul(buf, 16, &val);
 	if (ret)
 		return ret;
 
-	if (val >= drvdata->nr_ctxid_cmp)
+	if (val >= caps->nr_ctxid_cmp)
 		return -EINVAL;
 
 	/*
-- 
LEVI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}



^ permalink raw reply related

* [PATCH v2 3/5] coresight: etm4x: fix inconsistencies with sysfs configration
From: Yeoreum Yun @ 2026-04-10  7:43 UTC (permalink / raw)
  To: coresight, linux-arm-kernel, linux-kernel
  Cc: suzuki.poulose, mike.leach, james.clark, alexander.shishkin,
	leo.yan, Yeoreum Yun
In-Reply-To: <20260410074310.2693385-1-yeoreum.yun@arm.com>

The current ETM4x configuration via sysfs can lead to the following
inconsistencies:

  - If a configuration is modified via sysfs while a perf session is
    active, the running configuration may differ between before
    a sched-out and after a subsequent sched-in.

  - If a perf session and sysfs session tries to enable concurrently,
    configuration from configfs could be corrupted.

  - There is chance to corrupt drvdata->config if perf session tries
    to enabled among handling cscfg_csdev_disable_active_config()
    in etm4_disable_sysfs().

To resolve these inconsistencies, the configuration should be separated into:

  - active_config, which is applied configuration for the current session
  - config, which stores the settings configured via sysfs.

and apply configuration from configfs after taking a mode.

Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
---
 .../hwtracing/coresight/coresight-etm4x-cfg.c |  2 +-
 .../coresight/coresight-etm4x-core.c          | 74 ++++++++++++-------
 drivers/hwtracing/coresight/coresight-etm4x.h |  2 +
 3 files changed, 49 insertions(+), 29 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-etm4x-cfg.c b/drivers/hwtracing/coresight/coresight-etm4x-cfg.c
index d14d7c8a23e5..0553771d04e7 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x-cfg.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x-cfg.c
@@ -47,7 +47,7 @@ static int etm4_cfg_map_reg_offset(struct etmv4_drvdata *drvdata,
 				   struct cscfg_regval_csdev *reg_csdev, u32 offset)
 {
 	int err = -EINVAL, idx;
-	struct etmv4_config *drvcfg = &drvdata->config;
+	struct etmv4_config *drvcfg = &drvdata->active_config;
 	u32 off_mask;
 
 	if (((offset >= TRCEVENTCTL0R) && (offset <= TRCVIPCSSCTLR)) ||
diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c
index b7abb171f523..c7b4a0b85106 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x-core.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c
@@ -245,6 +245,9 @@ void etm4_release_trace_id(struct etmv4_drvdata *drvdata)
 
 struct etm4_enable_arg {
 	struct etmv4_drvdata *drvdata;
+	unsigned long cfg_hash;
+	int preset;
+	u8 trace_id;
 	int rc;
 };
 
@@ -270,10 +273,11 @@ static void etm4x_prohibit_trace(struct etmv4_drvdata *drvdata)
 static u64 etm4x_get_kern_user_filter(struct etmv4_drvdata *drvdata)
 {
 	u64 trfcr = drvdata->trfcr;
+	struct etmv4_config *config = &drvdata->active_config;
 
-	if (drvdata->config.mode & ETM_MODE_EXCL_KERN)
+	if (config->mode & ETM_MODE_EXCL_KERN)
 		trfcr &= ~TRFCR_EL1_ExTRE;
-	if (drvdata->config.mode & ETM_MODE_EXCL_USER)
+	if (config->mode & ETM_MODE_EXCL_USER)
 		trfcr &= ~TRFCR_EL1_E0TRE;
 
 	return trfcr;
@@ -281,7 +285,7 @@ static u64 etm4x_get_kern_user_filter(struct etmv4_drvdata *drvdata)
 
 /*
  * etm4x_allow_trace - Allow CPU tracing in the respective ELs,
- * as configured by the drvdata->config.mode for the current
+ * as configured by the drvdata->active_config.mode for the current
  * session. Even though we have TRCVICTLR bits to filter the
  * trace in the ELs, it doesn't prevent the ETM from generating
  * a packet (e.g, TraceInfo) that might contain the addresses from
@@ -292,12 +296,13 @@ static u64 etm4x_get_kern_user_filter(struct etmv4_drvdata *drvdata)
 static void etm4x_allow_trace(struct etmv4_drvdata *drvdata)
 {
 	u64 trfcr, guest_trfcr;
+	struct etmv4_config *config = &drvdata->active_config;
 
 	/* If the CPU doesn't support FEAT_TRF, nothing to do */
 	if (!drvdata->trfcr)
 		return;
 
-	if (drvdata->config.mode & ETM_MODE_EXCL_HOST)
+	if (config->mode & ETM_MODE_EXCL_HOST)
 		trfcr = drvdata->trfcr & ~(TRFCR_EL1_ExTRE | TRFCR_EL1_E0TRE);
 	else
 		trfcr = etm4x_get_kern_user_filter(drvdata);
@@ -305,7 +310,7 @@ static void etm4x_allow_trace(struct etmv4_drvdata *drvdata)
 	write_trfcr(trfcr);
 
 	/* Set filters for guests and pass to KVM */
-	if (drvdata->config.mode & ETM_MODE_EXCL_GUEST)
+	if (config->mode & ETM_MODE_EXCL_GUEST)
 		guest_trfcr = drvdata->trfcr & ~(TRFCR_EL1_ExTRE | TRFCR_EL1_E0TRE);
 	else
 		guest_trfcr = etm4x_get_kern_user_filter(drvdata);
@@ -499,7 +504,7 @@ static int etm4_enable_hw(struct etmv4_drvdata *drvdata)
 {
 	int i, rc;
 	const struct etmv4_caps *caps = &drvdata->caps;
-	struct etmv4_config *config = &drvdata->config;
+	struct etmv4_config *config = &drvdata->active_config;
 	struct coresight_device *csdev = drvdata->csdev;
 	struct device *etm_dev = &csdev->dev;
 	struct csdev_access *csa = &csdev->access;
@@ -616,19 +621,36 @@ static int etm4_enable_hw(struct etmv4_drvdata *drvdata)
 static void etm4_enable_sysfs_smp_call(void *info)
 {
 	struct etm4_enable_arg *arg = info;
+	struct etmv4_drvdata *drvdata;
 	struct coresight_device *csdev;
 
 	if (WARN_ON(!arg))
 		return;
 
-	csdev = arg->drvdata->csdev;
+	drvdata = arg->drvdata;
+	csdev = drvdata->csdev;
 	if (!coresight_take_mode(csdev, CS_MODE_SYSFS)) {
 		/* Someone is already using the tracer */
 		arg->rc = -EBUSY;
 		return;
 	}
 
-	arg->rc = etm4_enable_hw(arg->drvdata);
+	drvdata->active_config = drvdata->config;
+
+	if (arg->cfg_hash) {
+		arg->rc = cscfg_csdev_enable_active_config(csdev,
+							   arg->cfg_hash,
+							   arg->preset);
+		if (arg->rc)
+			return;
+	}
+
+	drvdata->trcid = arg->trace_id;
+
+	/* Tracer will never be paused in sysfs mode */
+	drvdata->paused = false;
+
+	arg->rc = etm4_enable_hw(drvdata);
 
 	/* The tracer didn't start */
 	if (arg->rc)
@@ -670,7 +692,7 @@ static int etm4_config_timestamp_event(struct etmv4_drvdata *drvdata,
 	int ctridx;
 	int rselector;
 	const struct etmv4_caps *caps = &drvdata->caps;
-	struct etmv4_config *config = &drvdata->config;
+	struct etmv4_config *config = &drvdata->active_config;
 
 	/* No point in trying if we don't have at least one counter */
 	if (!caps->nr_cntr)
@@ -754,7 +776,7 @@ static int etm4_parse_event_config(struct coresight_device *csdev,
 	int ret = 0;
 	struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
 	const struct etmv4_caps *caps = &drvdata->caps;
-	struct etmv4_config *config = &drvdata->config;
+	struct etmv4_config *config = &drvdata->active_config;
 	struct perf_event_attr max_timestamp = {
 		.ATTR_CFG_FLD_timestamp_CFG = U64_MAX,
 	};
@@ -916,24 +938,18 @@ static int etm4_enable_sysfs(struct coresight_device *csdev, struct coresight_pa
 
 	/* enable any config activated by configfs */
 	cscfg_config_sysfs_get_active_cfg(&cfg_hash, &preset);
-	if (cfg_hash) {
-		ret = cscfg_csdev_enable_active_config(csdev, cfg_hash, preset);
-		if (ret)
-			return ret;
-	}
 
 	raw_spin_lock(&drvdata->spinlock);
 
-	drvdata->trcid = path->trace_id;
-
-	/* Tracer will never be paused in sysfs mode */
-	drvdata->paused = false;
-
 	/*
 	 * Executing etm4_enable_hw on the cpu whose ETM is being enabled
 	 * ensures that register writes occur when cpu is powered.
 	 */
 	arg.drvdata = drvdata;
+	arg.cfg_hash = cfg_hash;
+	arg.preset = preset;
+	arg.trace_id = path->trace_id;
+
 	ret = smp_call_function_single(drvdata->cpu,
 				       etm4_enable_sysfs_smp_call, &arg, 1);
 	if (!ret)
@@ -1034,7 +1050,7 @@ static void etm4_disable_hw(struct etmv4_drvdata *drvdata)
 {
 	u32 control;
 	const struct etmv4_caps *caps = &drvdata->caps;
-	struct etmv4_config *config = &drvdata->config;
+	struct etmv4_config *config = &drvdata->active_config;
 	struct coresight_device *csdev = drvdata->csdev;
 	struct csdev_access *csa = &csdev->access;
 	int i;
@@ -1070,6 +1086,8 @@ static void etm4_disable_sysfs_smp_call(void *info)
 
 	etm4_disable_hw(drvdata);
 
+	cscfg_csdev_disable_active_config(drvdata->csdev);
+
 	coresight_set_mode(drvdata->csdev, CS_MODE_DISABLED);
 }
 
@@ -1130,9 +1148,6 @@ static void etm4_disable_sysfs(struct coresight_device *csdev)
 				 drvdata, 1);
 
 	raw_spin_unlock(&drvdata->spinlock);
-
-	cscfg_csdev_disable_active_config(csdev);
-
 	cpus_read_unlock();
 
 	/*
@@ -1375,6 +1390,7 @@ static void etm4_init_arch_data(void *info)
 	struct etm4_init_arg *init_arg = info;
 	struct etmv4_drvdata *drvdata;
 	struct etmv4_caps *caps;
+	struct etmv4_config *config;
 	struct csdev_access *csa;
 	struct device *dev = init_arg->dev;
 	int i;
@@ -1382,6 +1398,7 @@ static void etm4_init_arch_data(void *info)
 	drvdata = dev_get_drvdata(init_arg->dev);
 	caps = &drvdata->caps;
 	csa = init_arg->csa;
+	config = &drvdata->active_config;
 
 	/*
 	 * If we are unable to detect the access mechanism,
@@ -1442,7 +1459,7 @@ static void etm4_init_arch_data(void *info)
 
 	/* EXLEVEL_S, bits[19:16] Secure state instruction tracing */
 	caps->s_ex_level = FIELD_GET(TRCIDR3_EXLEVEL_S_MASK, etmidr3);
-	drvdata->config.s_ex_level = caps->s_ex_level;
+	config->s_ex_level = caps->s_ex_level;
 	/* EXLEVEL_NS, bits[23:20] Non-secure state instruction tracing */
 	caps->ns_ex_level = FIELD_GET(TRCIDR3_EXLEVEL_NS_MASK, etmidr3);
 	/*
@@ -1687,7 +1704,7 @@ static void etm4_set_default(struct etmv4_config *config)
 static int etm4_get_next_comparator(struct etmv4_drvdata *drvdata, u32 type)
 {
 	int nr_comparator, index = 0;
-	struct etmv4_config *config = &drvdata->config;
+	struct etmv4_config *config = &drvdata->active_config;
 
 	/*
 	 * nr_addr_cmp holds the number of comparator _pair_, so time 2
@@ -1728,7 +1745,7 @@ static int etm4_set_event_filters(struct etmv4_drvdata *drvdata,
 {
 	int i, comparator, ret = 0;
 	u64 address;
-	struct etmv4_config *config = &drvdata->config;
+	struct etmv4_config *config = &drvdata->active_config;
 	struct etm_filters *filters = event->hw.addr_filters;
 
 	if (!filters)
@@ -2250,7 +2267,8 @@ static int etm4_add_coresight_dev(struct etm4_init_arg *init_arg)
 	if (!desc.name)
 		return -ENOMEM;
 
-	etm4_set_default(&drvdata->config);
+	etm4_set_default(&drvdata->active_config);
+	drvdata->config = drvdata->active_config;
 
 	pdata = coresight_get_platform_data(dev);
 	if (IS_ERR(pdata))
diff --git a/drivers/hwtracing/coresight/coresight-etm4x.h b/drivers/hwtracing/coresight/coresight-etm4x.h
index 57508d301327..33a4f68dd0cb 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x.h
+++ b/drivers/hwtracing/coresight/coresight-etm4x.h
@@ -1069,6 +1069,7 @@ struct etmv4_save_state {
  *		allows tracing at all ELs. We don't want to compute this
  *		at runtime, due to the additional setting of TRFCR_CX when
  *		in EL2. Otherwise, 0.
+ * @active_config:	structure holding current applied configuration parameters.
  * @config:	structure holding configuration parameters.
  * @save_state:	State to be preserved across power loss
  * @paused:	Indicates if the trace unit is paused.
@@ -1089,6 +1090,7 @@ struct etmv4_drvdata {
 	bool				os_unlock : 1;
 	bool				paused : 1;
 	u64				trfcr;
+	struct etmv4_config		active_config;
 	struct etmv4_config		config;
 	struct etmv4_save_state		*save_state;
 	DECLARE_BITMAP(arch_features, ETM4_IMPDEF_FEATURE_MAX);
-- 
LEVI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}



^ permalink raw reply related

* [PATCH v2 2/5] coresight: etm4x: exclude ss_status from drvdata->config
From: Yeoreum Yun @ 2026-04-10  7:43 UTC (permalink / raw)
  To: coresight, linux-arm-kernel, linux-kernel
  Cc: suzuki.poulose, mike.leach, james.clark, alexander.shishkin,
	leo.yan, Yeoreum Yun
In-Reply-To: <20260410074310.2693385-1-yeoreum.yun@arm.com>

The purpose of TRCSSCSRn register is to show status of
the corresponding Single-shot Comparator Control and input supports.
That means writable field's purpose for reset or restore from idle status
not for configuration.

Therefore, exclude ss_status from drvdata->config, move it to etm4x_caps.
This includes remove TRCSSCRn from configurable item and
remove saving in etm4_disable_hw().

Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
---
 .../hwtracing/coresight/coresight-etm4x-cfg.c  |  1 -
 .../hwtracing/coresight/coresight-etm4x-core.c | 18 +++++-------------
 .../coresight/coresight-etm4x-sysfs.c          |  7 ++-----
 drivers/hwtracing/coresight/coresight-etm4x.h  |  3 ++-
 4 files changed, 9 insertions(+), 20 deletions(-)

diff --git a/drivers/hwtracing/coresight/coresight-etm4x-cfg.c b/drivers/hwtracing/coresight/coresight-etm4x-cfg.c
index c302072b293a..d14d7c8a23e5 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x-cfg.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x-cfg.c
@@ -86,7 +86,6 @@ static int etm4_cfg_map_reg_offset(struct etmv4_drvdata *drvdata,
 		off_mask =  (offset & GENMASK(11, 5));
 		do {
 			CHECKREGIDX(TRCSSCCRn(0), ss_ctrl, idx, off_mask);
-			CHECKREGIDX(TRCSSCSRn(0), ss_status, idx, off_mask);
 			CHECKREGIDX(TRCSSPCICRn(0), ss_pe_cmp, idx, off_mask);
 		} while (0);
 	} else if ((offset >= TRCCIDCVRn(0)) && (offset <= TRCVMIDCVRn(7))) {
diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c
index 6443f3717b37..b7abb171f523 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x-core.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c
@@ -91,7 +91,7 @@ static bool etm4x_sspcicrn_present(struct etmv4_drvdata *drvdata, int n)
 	const struct etmv4_caps *caps = &drvdata->caps;
 
 	return (n < caps->nr_ss_cmp) && caps->nr_pe &&
-	       (drvdata->config.ss_status[n] & TRCSSCSRn_PC);
+	       (caps->ss_status[n] & TRCSSCSRn_PC);
 }
 
 u64 etm4x_sysreg_read(u32 offset, bool _relaxed, bool _64bit)
@@ -571,11 +571,9 @@ static int etm4_enable_hw(struct etmv4_drvdata *drvdata)
 		etm4x_relaxed_write32(csa, config->res_ctrl[i], TRCRSCTLRn(i));
 
 	for (i = 0; i < caps->nr_ss_cmp; i++) {
-		/* always clear status bit on restart if using single-shot */
-		if (config->ss_ctrl[i] || config->ss_pe_cmp[i])
-			config->ss_status[i] &= ~TRCSSCSRn_STATUS;
 		etm4x_relaxed_write32(csa, config->ss_ctrl[i], TRCSSCCRn(i));
-		etm4x_relaxed_write32(csa, config->ss_status[i], TRCSSCSRn(i));
+		/* always clear status bit on restart if using single-shot */
+		etm4x_relaxed_write32(csa, caps->ss_status[i], TRCSSCSRn(i));
 		if (etm4x_sspcicrn_present(drvdata, i))
 			etm4x_relaxed_write32(csa, config->ss_pe_cmp[i], TRCSSPCICRn(i));
 	}
@@ -1053,12 +1051,6 @@ static void etm4_disable_hw(struct etmv4_drvdata *drvdata)
 
 	etm4_disable_trace_unit(drvdata);
 
-	/* read the status of the single shot comparators */
-	for (i = 0; i < caps->nr_ss_cmp; i++) {
-		config->ss_status[i] =
-			etm4x_relaxed_read32(csa, TRCSSCSRn(i));
-	}
-
 	/* read back the current counter values */
 	for (i = 0; i < caps->nr_cntr; i++) {
 		config->cntr_val[i] =
@@ -1501,8 +1493,8 @@ static void etm4_init_arch_data(void *info)
 	 */
 	caps->nr_ss_cmp = FIELD_GET(TRCIDR4_NUMSSCC_MASK, etmidr4);
 	for (i = 0; i < caps->nr_ss_cmp; i++) {
-		drvdata->config.ss_status[i] =
-			etm4x_relaxed_read32(csa, TRCSSCSRn(i));
+		caps->ss_status[i] = etm4x_relaxed_read32(csa, TRCSSCSRn(i));
+		caps->ss_status[i] &= ~(TRCSSCSRn_STATUS | TRCSSCSRn_PENDING);
 	}
 	/* NUMCIDC, bits[27:24] number of Context ID comparators for tracing */
 	caps->numcidc = FIELD_GET(TRCIDR4_NUMCIDC_MASK, etmidr4);
diff --git a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
index 3d5f343130bd..c794fc9de5b6 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
@@ -1832,8 +1832,6 @@ static ssize_t sshot_ctrl_store(struct device *dev,
 	raw_spin_lock(&drvdata->spinlock);
 	idx = config->ss_idx;
 	config->ss_ctrl[idx] = FIELD_PREP(TRCSSCCRn_SAC_ARC_RST_MASK, val);
-	/* must clear bit 31 in related status register on programming */
-	config->ss_status[idx] &= ~TRCSSCSRn_STATUS;
 	raw_spin_unlock(&drvdata->spinlock);
 	return size;
 }
@@ -1844,10 +1842,11 @@ static ssize_t sshot_status_show(struct device *dev,
 {
 	unsigned long val;
 	struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+	const struct etmv4_caps *caps = &drvdata->caps;
 	struct etmv4_config *config = &drvdata->config;
 
 	raw_spin_lock(&drvdata->spinlock);
-	val = config->ss_status[config->ss_idx];
+	val = caps->ss_status[config->ss_idx];
 	raw_spin_unlock(&drvdata->spinlock);
 	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
 }
@@ -1882,8 +1881,6 @@ static ssize_t sshot_pe_ctrl_store(struct device *dev,
 	raw_spin_lock(&drvdata->spinlock);
 	idx = config->ss_idx;
 	config->ss_pe_cmp[idx] = FIELD_PREP(TRCSSPCICRn_PC_MASK, val);
-	/* must clear bit 31 in related status register on programming */
-	config->ss_status[idx] &= ~TRCSSCSRn_STATUS;
 	raw_spin_unlock(&drvdata->spinlock);
 	return size;
 }
diff --git a/drivers/hwtracing/coresight/coresight-etm4x.h b/drivers/hwtracing/coresight/coresight-etm4x.h
index 3e20561672dc..57508d301327 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x.h
+++ b/drivers/hwtracing/coresight/coresight-etm4x.h
@@ -213,6 +213,7 @@
 #define TRCACATRn_EXLEVEL_MASK			GENMASK(14, 8)
 
 #define TRCSSCSRn_STATUS			BIT(31)
+#define TRCSSCSRn_PENDING			BIT(30)
 #define TRCSSCCRn_SAC_ARC_RST_MASK		GENMASK(24, 0)
 
 #define TRCSSPCICRn_PC_MASK			GENMASK(7, 0)
@@ -898,6 +899,7 @@ struct etmv4_caps {
 	bool	atbtrig : 1;
 	bool	lpoverride : 1;
 	bool	skip_power_up : 1;
+	u32	ss_status[ETM_MAX_SS_CMP];
 };
 
 /**
@@ -976,7 +978,6 @@ struct etmv4_config {
 	u32				res_ctrl[ETM_MAX_RES_SEL]; /* TRCRSCTLRn */
 	u8				ss_idx;
 	u32				ss_ctrl[ETM_MAX_SS_CMP];
-	u32				ss_status[ETM_MAX_SS_CMP];
 	u32				ss_pe_cmp[ETM_MAX_SS_CMP];
 	u8				addr_idx;
 	u64				addr_val[ETM_MAX_SINGLE_ADDR_CMP];
-- 
LEVI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}



^ permalink raw reply related

* [PATCH v2 0/5] fix inconsistencies with sysfs configuration in etmX
From: Yeoreum Yun @ 2026-04-10  7:43 UTC (permalink / raw)
  To: coresight, linux-arm-kernel, linux-kernel
  Cc: suzuki.poulose, mike.leach, james.clark, alexander.shishkin,
	leo.yan, Yeoreum Yun

The current ETMx configuration via sysfs can lead to the following
inconsistencies:

  - If a configuration is modified via sysfs while a perf session is
    active, the running configuration may differ between before
    a sched-out and after a subsequent sched-in.

  - If a perf session and sysfs session tries to enable concurrently,
    configuration from configfs could be corrupted (etm4).

  - There is chance to corrupt drvdata->config if perf session tries
    to enabled among handling cscfg_csdev_disable_active_config()
    in etm4_disable_sysfs() (etm4).

To resolve these inconsistencies, the configuration should be separated into:

  - active_config, which is applied configuration for the current session
  - config, which stores the settings configured via sysfs.

and apply configuration from configfs after taking a mode.


This patch based on v7.0-rc7


Patch History
=============

from v1 to v2
  - rebased to v7.0-rc7.
  - introduce etmX_caps structure to save etmX's capabilities.
  - remove ss_status from etmv4_config.
  - modify active_config after taking a mode (perf/sysfs).
  - https://lore.kernel.org/all/20260317181705.2456271-1-yeoreum.yun@arm.com/

Yeoreum Yun (5):
  coresight: etm4x: introduce struct etm4_caps
  coresight: etm4x: exclude ss_status from drvdata->config
  coresight: etm4x: fix inconsistencies with sysfs configration
  coresight: etm3x: introduce struct etm_caps
  coresight: etm3x: fix inconsistencies with sysfs configration

 drivers/hwtracing/coresight/coresight-etm.h   |  42 ++-
 .../coresight/coresight-etm3x-core.c          |  53 +--
 .../coresight/coresight-etm3x-sysfs.c         |  14 +-
 .../hwtracing/coresight/coresight-etm4x-cfg.c |   3 +-
 .../coresight/coresight-etm4x-core.c          | 322 ++++++++++--------
 .../coresight/coresight-etm4x-sysfs.c         | 192 ++++++-----
 drivers/hwtracing/coresight/coresight-etm4x.h | 180 +++++-----
 7 files changed, 450 insertions(+), 356 deletions(-)


base-commit: 591cd656a1bf5ea94a222af5ef2ee76df029c1d2
--
LEVI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}



^ permalink raw reply

* Re: [PATCH v13 11/17] drm/bridge: analogix_dp: Apply drm_bridge_connector helper
From: Luca Ceresoli @ 2026-04-10  7:41 UTC (permalink / raw)
  To: Damon Ding, andrzej.hajda, neil.armstrong, rfoss,
	maarten.lankhorst, mripard, tzimmermann, airlied, simona,
	victor.liu, Frank.Li, shawnguo, s.hauer, inki.dae, sw0312.kim,
	kyungmin.park, krzk, jingoohan1, p.zabel, hjc, heiko, andy.yan
  Cc: Laurent.pinchart, jonas, jernej.skrabec, kernel, festevam,
	alim.akhtar, dmitry.baryshkov, nicolas.frattaroli, dianders,
	m.szyprowski, linux-kernel, dri-devel, imx, linux-arm-kernel,
	linux-samsung-soc, linux-rockchip
In-Reply-To: <20260409065301.446670-12-damon.ding@rock-chips.com>

Hello Damon,

On Thu Apr 9, 2026 at 8:52 AM CEST, Damon Ding wrote:
> Initialize bridge_connector for both Rockchip and Exynos encoder sides.
> Then, make DRM_BRIDGE_ATTACH_NO_CONNECTOR mandatory for Analogix bridge
> side, as the private &drm_connector is no longer created.
>
> The previous &drm_connector_funcs and &drm_connector_helper_funcs APIs
> are replaced by the corresponding &drm_bridge_funcs APIs:
>
> analogix_dp_atomic_check() -> analogix_dp_bridge_atomic_check()
> analogix_dp_detect()       -> analogix_dp_bridge_detect()
> analogix_dp_get_modes()    -> analogix_dp_bridge_get_modes()
>                               analogix_dp_bridge_edid_read()
>
> Additionally, the compatibilities of Analogix DP bridge based on whether
> the next bridge is a 'panel'. If it is, OP_MODES and OP_DETECT are
> supported; If not (the next bridge is a 'monitor' or a bridge chip),
> OP_EDID and OP_DETECT are supported.
>
> The devm_drm_bridge_add() is placed in analogix_dp_bind() instead of
> analogix_dp_probe(), because the type of next bridge (the panel, monitor
> or bridge chip) can only be determined after the probe process has fully
> completed.
>
> Signed-off-by: Damon Ding <damon.ding@rock-chips.com>
> Tested-by: Marek Szyprowski <m.szyprowski@samsung.com>
> Tested-by: Heiko Stuebner <heiko@sntech.de> # rk3588

I noticed two issues, sorry I haven't catched them before...

> @@ -1580,7 +1533,8 @@ EXPORT_SYMBOL_GPL(analogix_dp_unbind);
>
>  int analogix_dp_start_crc(struct drm_connector *connector)
>  {
> -	struct analogix_dp_device *dp = to_dp(connector);
> +	struct analogix_dp_device *dp;
> +	struct drm_bridge *bridge;
>
>  	if (!connector->state->crtc) {
>  		DRM_ERROR("Connector %s doesn't currently have a CRTC.\n",
> @@ -1588,13 +1542,26 @@ int analogix_dp_start_crc(struct drm_connector *connector)
>  		return -EINVAL;
>  	}
>
> +	bridge = drm_bridge_chain_get_first_bridge(connector->encoder);
> +	if (bridge->type != DRM_MODE_CONNECTOR_eDP)
> +		return -EINVAL;
> +
> +	dp = to_dp(bridge);
> +
>  	return drm_dp_start_crc(&dp->aux, connector->state->crtc);
>  }

drm_bridge_chain_get_first_bridge() takes a reference, you must call
drm_bridge_put(bridge) before returning. Given there are two return paths I
suggest:

-	struct drm_bridge *bridge;

-	bridge = drm_bridge_chain_get_first_bridge(connector->encoder);
+	struct drm_bridge *bridge __free(drm_bridge_put) =
+		drm_bridge_chain_get_first_bridge(connector->encoder);

>  EXPORT_SYMBOL_GPL(analogix_dp_start_crc);
>
>  int analogix_dp_stop_crc(struct drm_connector *connector)
>  {
> -	struct analogix_dp_device *dp = to_dp(connector);
> +	struct analogix_dp_device *dp;
> +	struct drm_bridge *bridge;
> +
> +	bridge = drm_bridge_chain_get_first_bridge(connector->encoder);
> +	if (bridge->type != DRM_MODE_CONNECTOR_eDP)
> +		return -EINVAL;
> +
> +	dp = to_dp(bridge);
>
>  	return drm_dp_stop_crc(&dp->aux);
>  }

Same here:

-	struct drm_bridge *bridge;

-	bridge = drm_bridge_chain_get_first_bridge(connector->encoder);
+	struct drm_bridge *bridge __free(drm-bridge_put) =
+		drm_bridge_chain_get_first_bridge(connector->encoder);

With the above two changes you can add to v14:

+Reviewed-by: Luca Ceresoli <luca.ceresoli@bootlin.com>

Luca

--
Luca Ceresoli, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com


^ permalink raw reply

* RE: [PATCH v2 4/7] iommu/arm-smmu-v3: Mark ATC invalidate timeouts via lockless bitmap
From: Tian, Kevin @ 2026-04-10  7:39 UTC (permalink / raw)
  To: Jason Gunthorpe, Nicolin Chen
  Cc: Samiullah Khawaja, will@kernel.org, robin.murphy@arm.com,
	joro@8bytes.org, bhelgaas@google.com, rafael@kernel.org,
	lenb@kernel.org, praan@google.com, baolu.lu@linux.intel.com,
	xueshuai@linux.alibaba.com, linux-arm-kernel@lists.infradead.org,
	iommu@lists.linux.dev, linux-kernel@vger.kernel.org,
	linux-acpi@vger.kernel.org, linux-pci@vger.kernel.org,
	Vikram Sethi
In-Reply-To: <20260323235105.GV7340@nvidia.com>

> From: Jason Gunthorpe <jgg@nvidia.com>
> Sent: Tuesday, March 24, 2026 7:51 AM
> 
> On Wed, Mar 18, 2026 at 08:12:04PM -0700, Nicolin Chen wrote:
> > > > VT-d is able to find out the SID of the device for which the device TLB
> > > > invalidation timed-out occured by using the SID reported in the
> > > > "Invalidation Queue Error Record Register" (VT-d Specs 11.4.9.9).
> > >
> > > yes. but when there are multiple submissions (each with a wait descriptor)
> > > fetched/handled by the hw and then an invalidation timeout comes, all
> > > pending wait descriptors will be aborted (not just the one corresponding
> > > to the timeout). In this case all affected submitters need to re-try.
> >
> > This sounds similar to SMMU then.
> 
> Not entirely.. smmu HW stops processing at a SYNC and waits for
> everything pending to complete, then goes on forward. If there is a HW
> reported ATC timeout then it is contained to the SYNC that followed
> the ATC invalidation. The errored sync is skipped and whatever follows
> continues forward, so it doesn't contaminate future work.
> 
> VT-d's wait descriptor with fence FN=1 sounds identical???

yes

> 
> I guess if FN=0 then things start to become indeterminate what the
> wait actually waits for..
> 

Currently we use FN=0, so all pending works before head pointer will be
re-submitted. It has a larger impact compared to FN=1 when a timeout
happens, but allows more parallel work in hardware at other times.


^ permalink raw reply

* Re: [PATCH] pinctrl: mediatek: moore: implement gpio_chip::get_direction()
From: Linus Walleij @ 2026-04-10  7:37 UTC (permalink / raw)
  To: Bartosz Golaszewski
  Cc: Frank Wunderlich, Sean Wang, Matthias Brugger,
	AngeloGioacchino Del Regno, Bartosz Golaszewski, linux-mediatek,
	linux-gpio, linux-kernel, linux-arm-kernel
In-Reply-To: <20260410070935.9540-1-bartosz.golaszewski@oss.qualcomm.com>

On Fri, Apr 10, 2026 at 9:09 AM Bartosz Golaszewski
<bartosz.golaszewski@oss.qualcomm.com> wrote:

> If the gpio_chip::get_direction() callback is not implemented by the GPIO
> controller driver, GPIOLIB emits a warning.
>
> Implement get_direction() for the GPIO part of pinctrl-moore.
>
> Fixes: 471e998c0e31 ("gpiolib: remove redundant callback check")
> Fixes: e623c4303ed1 ("gpiolib: sanitize the return value of gpio_chip::get_direction()")
> Reported-by: Frank Wunderlich <linux@fw-web.de>
> Closes: https://lore.kernel.org/all/20260409132724.126258-1-linux@fw-web.de/
> Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>

LGTM, but it would have to go into v7.1-rc1 right now due to timing,
then from there to stable.

Yours,
Linus Walleij


^ permalink raw reply

* Re: [PATCH net-next v3 00/12] net: airoha: Support multiple net_devices connected to the same GDM port
From: Lorenzo Bianconi @ 2026-04-10  7:37 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Paolo Abeni,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Christian Marangi,
	Benjamin Larsson, linux-arm-kernel, linux-mediatek, netdev,
	devicetree, Xuegang Lu
In-Reply-To: <20260409195950.74e4bc97@kernel.org>

[-- Attachment #1: Type: text/plain, Size: 672 bytes --]

> On Mon, 06 Apr 2026 12:34:05 +0200 Lorenzo Bianconi wrote:
> > EN7581 or AN7583 SoCs support connecting multiple external SerDes (e.g.
> > Ethernet or USB SerDes) to GDM3 or GDM4 ports via a hw arbiter that
> > manages the traffic in a TDM manner. As a result multiple net_devices can
> > connect to the same GDM{3,4} port and there is a theoretical "1:n"
> > relation between GDM ports and net_devices.
> 
> Looks like this driver uses page pool.
> If you're sharing the same page pool across multiple netdevs
> it must not be linked to a netdev.

are you referring to slow.netdev pointer? If so, this is not set in airoha_eth
driver.

Regards,
Lorenzo

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply

* [PATCH v6 3/4] perf report: Update document for SIMD flags
From: Leo Yan @ 2026-04-10  7:37 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo, Namhyung Kim, Jiri Olsa, Ian Rogers,
	Adrian Hunter, James Clark, Mark Rutland
  Cc: Arnaldo Carvalho de Melo, linux-perf-users, linux-arm-kernel,
	Leo Yan
In-Reply-To: <20260410-perf_support_arm_spev1-3-v6-0-3c6f2dfe2cd3@arm.com>

Update SIMD architecture and predicate flags.

Reviewed-by: James Clark <james.clark@linaro.org>
Reviewed-by: Ian Rogers <irogers@google.com>
Signed-off-by: Leo Yan <leo.yan@arm.com>
---
 tools/perf/Documentation/perf-report.txt | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt
index 52f316628e43ac9851ecaa85f706e22c26294649..22f87eaa3279653836eaaa07a358c14f2e0afa75 100644
--- a/tools/perf/Documentation/perf-report.txt
+++ b/tools/perf/Documentation/perf-report.txt
@@ -136,7 +136,10 @@ OPTIONS
 	- addr: (Full) virtual address of the sampled instruction
 	- retire_lat: On X86, this reports pipeline stall of this instruction compared
 	  to the previous instruction in cycles. And currently supported only on X86
-	- simd: Flags describing a SIMD operation. "e" for empty Arm SVE predicate. "p" for partial Arm SVE predicate
+	- simd: Flags describing a SIMD operation. The architecture type can be Arm's
+	  ASE (Advanced SIMD extension), SVE, SME. It provides an extra tag for
+	  predicate: "e" for empty predicate, "p" for partial predicate, "d" for
+	  predicate disabled, and "f" for full predicate.
 	- type: Data type of sample memory access.
 	- typeoff: Offset in the data type of sample memory access.
 	- symoff: Offset in the symbol.

-- 
2.34.1



^ permalink raw reply related

* [PATCH v6 4/4] perf arm_spe: Improve SIMD flags setting
From: Leo Yan @ 2026-04-10  7:37 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo, Namhyung Kim, Jiri Olsa, Ian Rogers,
	Adrian Hunter, James Clark, Mark Rutland
  Cc: Arnaldo Carvalho de Melo, linux-perf-users, linux-arm-kernel,
	Leo Yan
In-Reply-To: <20260410-perf_support_arm_spev1-3-v6-0-3c6f2dfe2cd3@arm.com>

Fill in ASE and SME operations for the SIMD arch field.

Also set the predicate flags for SVE and SME, but differences between
them: SME does not have a predicate flag, so the setting is based on
events. SVE provides a predicate flag to indicate whether the predicate
is disabled, which allows it to be distinguished into four cases: full
predicates, empty predicates, fully predicated, and disabled predicates.

After:

    perf report -s +simd
    ...
    0.06%     0.06%  sve-test  sve-test               [.] setz                                        [p] SVE
    0.06%     0.06%  sve-test  [kernel.kallsyms]      [k] do_raw_spin_lock
    0.06%     0.06%  sve-test  sve-test               [.] getz                                        [p] SVE
    0.06%     0.06%  sve-test  [kernel.kallsyms]      [k] timekeeping_advance
    0.06%     0.06%  sve-test  sve-test               [.] getz                                        [d] SVE
    0.06%     0.06%  sve-test  [kernel.kallsyms]      [k] update_load_avg
    0.06%     0.06%  sve-test  sve-test               [.] getz                                        [e] SVE
    0.05%     0.05%  sve-test  sve-test               [.] setz                                        [e] SVE
    0.05%     0.05%  sve-test  [kernel.kallsyms]      [k] update_curr
    0.05%     0.05%  sve-test  sve-test               [.] setz                                        [d] SVE
    0.05%     0.05%  sve-test  [kernel.kallsyms]      [k] do_raw_spin_unlock
    0.05%     0.05%  sve-test  [kernel.kallsyms]      [k] timekeeping_update_from_shadow.constprop.0
    0.05%     0.05%  sve-test  sve-test               [.] getz                                        [f] SVE
    0.05%     0.05%  sve-test  sve-test               [.] setz                                        [f] SVE

Reviewed-by: James Clark <james.clark@linaro.org>
Reviewed-by: Ian Rogers <irogers@google.com>
Signed-off-by: Leo Yan <leo.yan@arm.com>
---
 tools/perf/util/arm-spe.c | 26 ++++++++++++++++++++------
 1 file changed, 20 insertions(+), 6 deletions(-)

diff --git a/tools/perf/util/arm-spe.c b/tools/perf/util/arm-spe.c
index 70dd9bee47c755f19a51b80c6df3499180de9540..e5835042acdf7685f95e19665cd45f97ed868275 100644
--- a/tools/perf/util/arm-spe.c
+++ b/tools/perf/util/arm-spe.c
@@ -353,12 +353,26 @@ static struct simd_flags arm_spe__synth_simd_flags(const struct arm_spe_record *
 
 	if (record->op & ARM_SPE_OP_SVE)
 		simd_flags.arch |= SIMD_OP_FLAGS_ARCH_SVE;
-
-	if (record->type & ARM_SPE_SVE_PARTIAL_PRED)
-		simd_flags.pred |= SIMD_OP_FLAGS_PRED_PARTIAL;
-
-	if (record->type & ARM_SPE_SVE_EMPTY_PRED)
-		simd_flags.pred |= SIMD_OP_FLAGS_PRED_EMPTY;
+	else if (record->op & ARM_SPE_OP_SME)
+		simd_flags.arch |= SIMD_OP_FLAGS_ARCH_SME;
+	else if (record->op & (ARM_SPE_OP_ASE | ARM_SPE_OP_SIMD_FP))
+		simd_flags.arch |= SIMD_OP_FLAGS_ARCH_ASE;
+
+	if (record->op & ARM_SPE_OP_SVE) {
+		if (!(record->op & ARM_SPE_OP_PRED))
+			simd_flags.pred = SIMD_OP_FLAGS_PRED_DISABLED;
+		else if (record->type & ARM_SPE_SVE_PARTIAL_PRED)
+			simd_flags.pred = SIMD_OP_FLAGS_PRED_PARTIAL;
+		else if (record->type & ARM_SPE_SVE_EMPTY_PRED)
+			simd_flags.pred = SIMD_OP_FLAGS_PRED_EMPTY;
+		else
+			simd_flags.pred = SIMD_OP_FLAGS_PRED_FULL;
+	} else {
+		if (record->type & ARM_SPE_SVE_PARTIAL_PRED)
+			simd_flags.pred = SIMD_OP_FLAGS_PRED_PARTIAL;
+		else if (record->type & ARM_SPE_SVE_EMPTY_PRED)
+			simd_flags.pred = SIMD_OP_FLAGS_PRED_EMPTY;
+	}
 
 	return simd_flags;
 }

-- 
2.34.1



^ permalink raw reply related

* [PATCH v6 2/4] perf sort: Sort disabled and full predicated flags
From: Leo Yan @ 2026-04-10  7:36 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo, Namhyung Kim, Jiri Olsa, Ian Rogers,
	Adrian Hunter, James Clark, Mark Rutland
  Cc: Arnaldo Carvalho de Melo, linux-perf-users, linux-arm-kernel,
	Leo Yan
In-Reply-To: <20260410-perf_support_arm_spev1-3-v6-0-3c6f2dfe2cd3@arm.com>

According to the Arm ARM (ARM DDI 0487, L.a), section D18.2.6
"Events packet", apart from the empty predicate and partial
predicates, an SVE or SME operation can be predicate-disabled
or full predicated.

To provide complete results, introduce two predicate types for
these cases.

Reviewed-by: James Clark <james.clark@linaro.org>
Reviewed-by: Ian Rogers <irogers@google.com>
Signed-off-by: Leo Yan <leo.yan@arm.com>
---
 tools/perf/util/sample.h | 13 +++++++++----
 tools/perf/util/sort.c   | 15 ++++++++++-----
 2 files changed, 19 insertions(+), 9 deletions(-)

diff --git a/tools/perf/util/sample.h b/tools/perf/util/sample.h
index 0e5ee7e0fb94f2d36c35df15de7c4ea00547a6c2..ca0c407c4423a4bc0b8098c657238b50ff5a3a17 100644
--- a/tools/perf/util/sample.h
+++ b/tools/perf/util/sample.h
@@ -72,8 +72,8 @@ struct aux_sample {
 
 struct simd_flags {
 	u8	arch:  2,	/* architecture (isa) */
-		pred:  2,	/* predication */
-		resv:  4;	/* reserved */
+		pred:  3,	/* predication */
+		resv:  3;	/* reserved */
 };
 
 /* simd architecture flags */
@@ -85,8 +85,13 @@ enum simd_op_flags {
 };
 
 /* simd predicate flags */
-#define SIMD_OP_FLAGS_PRED_PARTIAL	0x01	/* partial predicate */
-#define SIMD_OP_FLAGS_PRED_EMPTY	0x02	/* empty predicate */
+enum simd_pred_flags {
+	SIMD_OP_FLAGS_PRED_NONE = 0x0,	/* Not available */
+	SIMD_OP_FLAGS_PRED_PARTIAL,	/* partial predicate */
+	SIMD_OP_FLAGS_PRED_EMPTY,	/* empty predicate */
+	SIMD_OP_FLAGS_PRED_FULL,	/* full predicate */
+	SIMD_OP_FLAGS_PRED_DISABLED,	/* disabled predicate */
+};
 
 /**
  * struct perf_sample
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index 7198eb3ae560cdac762a7d233d19bd6c70903d39..0020089cb13c7858ba04579568b1bdbc32909c63 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -209,18 +209,23 @@ static int hist_entry__simd_snprintf(struct hist_entry *he, char *bf,
 				     size_t size, unsigned int width __maybe_unused)
 {
 	const char *name;
+	const char *pred_str = ".";
 
 	if (!he->simd_flags.arch)
 		return repsep_snprintf(bf, size, "");
 
 	name = hist_entry__get_simd_name(&he->simd_flags);
 
-	if (he->simd_flags.pred & SIMD_OP_FLAGS_PRED_EMPTY)
-		return repsep_snprintf(bf, size, "[e] %s", name);
-	else if (he->simd_flags.pred & SIMD_OP_FLAGS_PRED_PARTIAL)
-		return repsep_snprintf(bf, size, "[p] %s", name);
+	if (he->simd_flags.pred == SIMD_OP_FLAGS_PRED_EMPTY)
+		pred_str = "e";
+	else if (he->simd_flags.pred == SIMD_OP_FLAGS_PRED_PARTIAL)
+		pred_str = "p";
+	else if (he->simd_flags.pred == SIMD_OP_FLAGS_PRED_DISABLED)
+		pred_str = "d";
+	else if (he->simd_flags.pred == SIMD_OP_FLAGS_PRED_FULL)
+		pred_str = "f";
 
-	return repsep_snprintf(bf, size, "[.] %s", name);
+	return repsep_snprintf(bf, size, "[%s] %s", pred_str, name);
 }
 
 static struct sort_entry sort_simd = {

-- 
2.34.1



^ permalink raw reply related

* [PATCH v6 1/4] perf sort: Support sort ASE and SME
From: Leo Yan @ 2026-04-10  7:36 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo, Namhyung Kim, Jiri Olsa, Ian Rogers,
	Adrian Hunter, James Clark, Mark Rutland
  Cc: Arnaldo Carvalho de Melo, linux-perf-users, linux-arm-kernel,
	Leo Yan
In-Reply-To: <20260410-perf_support_arm_spev1-3-v6-0-3c6f2dfe2cd3@arm.com>

Support sort Advance SIMD extension (ASE) and SME.

Reviewed-by: James Clark <james.clark@linaro.org>
Reviewed-by: Ian Rogers <irogers@google.com>
Signed-off-by: Leo Yan <leo.yan@arm.com>
---
 tools/perf/util/sample.h | 12 +++++++++---
 tools/perf/util/sort.c   |  6 +++++-
 2 files changed, 14 insertions(+), 4 deletions(-)

diff --git a/tools/perf/util/sample.h b/tools/perf/util/sample.h
index 3d27a0daef8fb2d72ffa8510923857e73130dd40..0e5ee7e0fb94f2d36c35df15de7c4ea00547a6c2 100644
--- a/tools/perf/util/sample.h
+++ b/tools/perf/util/sample.h
@@ -71,12 +71,18 @@ struct aux_sample {
 };
 
 struct simd_flags {
-	u8	arch:1,	/* architecture (isa) */
-		pred:2;	/* predication */
+	u8	arch:  2,	/* architecture (isa) */
+		pred:  2,	/* predication */
+		resv:  4;	/* reserved */
 };
 
 /* simd architecture flags */
-#define SIMD_OP_FLAGS_ARCH_SVE		0x01	/* ARM SVE */
+enum simd_op_flags {
+	SIMD_OP_FLAGS_ARCH_NONE = 0x0,	/* No SIMD operation */
+	SIMD_OP_FLAGS_ARCH_SVE,		/* Arm SVE */
+	SIMD_OP_FLAGS_ARCH_SME,		/* Arm SME */
+	SIMD_OP_FLAGS_ARCH_ASE,		/* Arm Advanced SIMD */
+};
 
 /* simd predicate flags */
 #define SIMD_OP_FLAGS_PRED_PARTIAL	0x01	/* partial predicate */
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index 6ce684d68bd61edba2df16806d8a8f18132617db..7198eb3ae560cdac762a7d233d19bd6c70903d39 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -195,8 +195,12 @@ static const char *hist_entry__get_simd_name(struct simd_flags *simd_flags)
 {
 	u64 arch = simd_flags->arch;
 
-	if (arch & SIMD_OP_FLAGS_ARCH_SVE)
+	if (arch == SIMD_OP_FLAGS_ARCH_SVE)
 		return "SVE";
+	else if (arch == SIMD_OP_FLAGS_ARCH_SME)
+		return "SME";
+	else if (arch == SIMD_OP_FLAGS_ARCH_ASE)
+		return "ASE";
 	else
 		return "n/a";
 }

-- 
2.34.1



^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox