* Re: [PATCH net] net: airoha: Add retry mechanism to airoha_qdma_set_trtcm_param()
From: Lorenzo Bianconi @ 2026-06-11 10:01 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni
Cc: linux-arm-kernel, linux-mediatek, netdev, Brown Huang, Leto Liu
In-Reply-To: <20260608-airoha_qdma_set_trtcm_param-retry-fix-v1-1-f07704f0d8c5@kernel.org>
[-- Attachment #1: Type: text/plain, Size: 2663 bytes --]
> From: Brown Huang <brown.huang@airoha.com>
>
> CPU accesses QDMA via the bus. When multiple modules are using the bus
> simultaneously, CPU access to QDMA may encounter bus timeouts and fails,
> resulting in QDMA configuration failures and potentially causing packet
> transmission issues. In order to mitigate the issue, introduce a retry
> mechanism to airoha_qdma_set_trtcm_param routine in order to ensure the
> configuration is correctly applied to the hardware.
>
> Fixes: ef1ca9271313b ("net: airoha: Add sched HTB offload support")
> Signed-off-by: Brown Huang <brown.huang@airoha.com>
> Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
> ---
> drivers/net/ethernet/airoha/airoha_eth.c | 21 +++++++++++++++------
> 1 file changed, 15 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c
> index eab6a98d62b9..aaf7d8c8ccd3 100644
> --- a/drivers/net/ethernet/airoha/airoha_eth.c
> +++ b/drivers/net/ethernet/airoha/airoha_eth.c
> @@ -2493,14 +2493,23 @@ static int airoha_qdma_set_trtcm_param(struct airoha_qdma *qdma, int channel,
> FIELD_PREP(TRTCM_METER_GROUP_MASK, group) |
> FIELD_PREP(TRTCM_PARAM_INDEX_MASK, idx) |
> FIELD_PREP(TRTCM_PARAM_RATE_TYPE_MASK, mode);
> + int i;
>
> - airoha_qdma_wr(qdma, REG_TRTCM_DATA_LOW(addr), val);
> - airoha_qdma_wr(qdma, REG_TRTCM_CFG_PARAM(addr), config);
> + for (i = 0; i < 100; i++) {
> + u32 data;
>
> - return read_poll_timeout(airoha_qdma_rr, val,
> - val & TRTCM_PARAM_RW_DONE_MASK,
> - USEC_PER_MSEC, 10 * USEC_PER_MSEC, true,
> - qdma, REG_TRTCM_CFG_PARAM(addr));
> + airoha_qdma_wr(qdma, REG_TRTCM_DATA_LOW(addr), val);
> + wmb();
> + airoha_qdma_wr(qdma, REG_TRTCM_CFG_PARAM(addr), config);
> + if (airoha_qdma_get_trtcm_param(qdma, channel, addr, param,
> + mode, &data, NULL))
> + continue;
> +
> + if (data == val)
> + break;
> + }
> +
> + return i == 100 ? -EBUSY : 0;
> }
>
> static int airoha_qdma_set_trtcm_config(struct airoha_qdma *qdma, int channel,
>
> ---
> base-commit: 4aacf509e537a711fa71bca9f234e5eb6968850e
> change-id: 20260605-airoha_qdma_set_trtcm_param-retry-fix-a9d2956b9b2f
>
> Best regards,
> --
> Lorenzo Bianconi <lorenzo@kernel.org>
I think the issue reported by sashiko in [0] is valid and it needs to be
addressed in v2, but since I am not the original author of the patch, I will
let Brown or Leto comment on it.
Regards,
Lorenzo
[0] https://sashiko.dev/#/patchset/20260608-airoha_qdma_set_trtcm_param-retry-fix-v1-1-f07704f0d8c5%40kernel.org
>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply
* Re: [PATCH 2/3] remoteproc: abort subdev stop sequence on first failure
From: Stephan Gerhold @ 2026-06-11 9:54 UTC (permalink / raw)
To: Mukesh Ojha
Cc: Bjorn Andersson, Mathieu Poirier, Matthias Brugger,
AngeloGioacchino Del Regno, linux-arm-msm, linux-remoteproc,
linux-kernel, linux-arm-kernel, linux-mediatek
In-Reply-To: <20260611094851.dkg63rqztsv2pre7@hu-mojha-hyd.qualcomm.com>
On Thu, Jun 11, 2026 at 03:18:51PM +0530, Mukesh Ojha wrote:
> On Tue, Jun 09, 2026 at 01:43:17PM +0200, Stephan Gerhold wrote:
> > On Tue, Jun 09, 2026 at 03:52:52PM +0530, Mukesh Ojha wrote:
> > > If a subdevice fails to stop, it indicates broken communication with the
> > > DSP. Continuing to stop further subdevices against an unresponsive
> > > remote processor could close rpmsg devices that could remove the memory
> > > mapping from HLOS and in case if remote processor touches those memory
> > > can result in SMMU fault.
> > >
> > > Change rproc_stop_subdevices() to return int and abort on the first
> > > failing subdev. Propagate the error through rproc_stop() and
> > > __rproc_detach() so callers are aware the teardown did not complete
> > > cleanly.
> > >
> > > Signed-off-by: Mukesh Ojha <mukesh.ojha@oss.qualcomm.com>
> >
> > But what would callers do about this? If you abort the teardown sequence
> > half-way through you now have an inconsistent half-stopped state that
> > neither a new call to stop() nor a new call to start() could recover
> > from. That doesn't sound much better than the SMMU fault. Or am I
> > missing something here?
>
> SMMU fault result in device crash while other is non-functional remote
> processor. From Linux side, we do not know the state of remote processor
> when the timeout happens..cleaning the subdevices can result in the
> debug data being lost for hung remote processor.
>
Ok, but how do we go from here? Do we expect that the system would have
some userspace monitoring daemon that would collect the debug data and
then reboot the device to make the remoteproc work again?
With these changes, I don't see how you would start the remoteproc again
without fully rebooting the board. Calling start()/stop() on the
subdevices again would lead to crashes because some of them are in
started state and some of them are in stopped state and we don't even
know which one is in which state.
Thanks,
Stephan
^ permalink raw reply
* Re: [PATCH 0/2] gpio: fix sleeping-in-atomic in shared-proxy; restore meson non-sleeping
From: Bartosz Golaszewski @ 2026-06-11 9:53 UTC (permalink / raw)
To: Viacheslav Bocharov
Cc: Linus Walleij, Neil Armstrong, Kevin Hilman, Jerome Brunet,
Martin Blumenstingl, Marek Szyprowski, Robin Murphy,
Diederik de Haas, linux-gpio, linux-arm-kernel, linux-amlogic,
linux-kernel
In-Reply-To: <20260610153329.937833-1-v@baodeep.com>
On Wed, Jun 10, 2026 at 5:41 PM Viacheslav Bocharov <v@baodeep.com> wrote:
>
> gpio-shared-proxy chooses its descriptor lock (mutex vs spinlock) from
> the underlying chip's can_sleep, but under that lock it calls config and
> direction ops that reach sleeping pinctrl paths. On a controller with
> non-sleeping MMIO value ops the lock is a spinlock, so a sleeping call
> runs from atomic context:
>
Why am I seeing three versions of this in my inbox? Which one should I review?
Bartosz
^ permalink raw reply
* Re: [PATCH net-next v3 0/3] Add standard stats for HSR/PRP
From: MD Danish Anwar @ 2026-06-11 9:51 UTC (permalink / raw)
To: Simon Horman
Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Jonathan Corbet, Shuah Khan, Roger Quadros, Andrew Lunn,
Jacob Keller, Meghana Malladi, David Carlier, Vadim Fedorenko,
Kevin Hao, Himanshu Mittal, Hangbin Liu, Markus Elfring,
Fernando Fernandez Mancera, Jan Vaclav, netdev, linux-doc,
linux-kernel, linux-arm-kernel, Felix Maurer, Luka Gejak
In-Reply-To: <20260610184737.GO3920875@horms.kernel.org>
Hi Simon,
On 11/06/26 12:17 am, Simon Horman wrote:
> On Mon, Jun 08, 2026 at 03:39:27PM +0530, MD Danish Anwar wrote:
>> Add standard stats for HSR / PRP. This series was initially adding HSR/PRP
>> related stats for ICSSG driver. Based on maintainers' comments on v2 I am
>> now adding support to dump standard stats for HSR/PRP.
>>
>> The drivers which support offload can populate these standard stats.
>>
>> This series only implements offloaded stats. For software-only interfaces
>> Felix Maurer had said he will do it later [1]
>>
>> v2 https://lore.kernel.org/all/20260514075605.850674-1-danishanwar@ti.com/
>> [1] https://lore.kernel.org/all/ag87pBZfOyccPZTc@thinkpad/
>>
>> Cc: Jakub Kicinski <kuba@kernel.org>
>> Cc: Felix Maurer <fmaurer@redhat.com>
>> Cc: Luka Gejak <luka.gejak@linux.dev>
>
> Hi MD,
>
> There is AI-generated review of this patch-set available on both
> https://sashiko.dev and https://netdev-ai.bots.linux.dev/sashiko/
> I would appreciate it if you could look over that with a view
> to addressing any issues that directly affect this patch-set.
I did look at the AI-generated reviews. The review on Patch 1/3 and 3/3
seems like a real issue to me which I have fixed. The reviews on patch
2/2 is not related to the series.
I have posted v4 with this fix
https://lore.kernel.org/all/20260611095035.852370-1-danishanwar@ti.com/
--
Thanks and Regards,
Danish
^ permalink raw reply
* [PATCH net-next v4 3/3] net: ti: icssg: Add HSR offload statistics support
From: MD Danish Anwar @ 2026-06-11 9:50 UTC (permalink / raw)
To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Jonathan Corbet, Shuah Khan, MD Danish Anwar,
Roger Quadros, Andrew Lunn, Meghana Malladi, Jacob Keller,
David Carlier, Vadim Fedorenko, Kevin Hao, Markus Elfring,
Hangbin Liu, Fernando Fernandez Mancera, Jan Vaclav
Cc: netdev, linux-doc, linux-kernel, linux-arm-kernel
In-Reply-To: <20260611095035.852370-1-danishanwar@ti.com>
Add support for exposing ICSSG HSR statistics through two interfaces:
ethtool and the standard RTM_GETSTATS / IFLA_STATS_LINK_XSTATS path.
Add a standard_stats flag to struct icssg_pa_stats and extend
icssg_all_pa_stats[] with 10 new entries:
Firmware-specific HSR counters (standard_stats=false, ethtool only):
- FW_HSR_FWD_CHECK_FAIL_DROP
- FW_HSR_HE_CHECK_FAIL_DROP
- FW_HSR_SKIP_HOST_DUP_DISCARD
IEC 62439-3 LRE counters (standard_stats=true, excluded from ethtool):
- FW_LRE_CNT_UNIQUE_RX, FW_LRE_CNT_DUPLICATE_RX, FW_LRE_CNT_MULTIPLE_RX
- FW_LRE_CNT_RX, FW_LRE_CNT_TX, FW_LRE_CNT_OWN_RX
- FW_LRE_CNT_ERRWRONGLAN
The ethtool get_strings/get_ethtool_stats callbacks skip entries with
standard_stats=true so they do not appear as ethtool counters.
ICSSG_NUM_PA_STANDARD_STATS is introduced and accounted for in
ICSSG_NUM_ETHTOOL_STATS so the sset count stays accurate.
ICSSG_NUM_PA_STATS is updated from 32 to 42.
Implement ndo_has_offload_stats() and ndo_get_offload_stats() in
emac_netdev_ops to expose the IEC 62439-3 LRE counters via the HSR
stack's RTM_GETSTATS / IFLA_STATS_LINK_XSTATS interface. The HSR stack
calls these NDOs on slave A; the callback reads PA stat registers for
both ports (MAC0 = port A, MAC1 = port B) from the shared prueth
instance and fills struct hsr_lre_stats. Port C counters are not
available in ICSSG hardware and remain at ~0ULL.
Export emac_update_hardware_stats() and emac_get_stat_by_name() as
GPL symbols so they can be called from icssg_prueth.c. Also change
emac_get_stat_by_name() return type from int to u64 and make it return
~0ULL on an unknown stat name instead of -EINVAL, consistent with the
hsr_lre_stats sentinel convention.
Add FW_HSR_FWD_CHECK_FAIL_DROP and FW_HSR_HE_CHECK_FAIL_DROP to the
rx_dropped sum in ndo_get_stats64, as these represent frames discarded
by the HSR forwarding logic.
Signed-off-by: MD Danish Anwar <danishanwar@ti.com>
---
.../ethernet/ti/icssg_prueth.rst | 19 ++++
drivers/net/ethernet/ti/icssg/icssg_common.c | 7 +-
drivers/net/ethernet/ti/icssg/icssg_ethtool.c | 10 +-
drivers/net/ethernet/ti/icssg/icssg_prueth.c | 92 +++++++++++++++++++
drivers/net/ethernet/ti/icssg/icssg_prueth.h | 10 +-
drivers/net/ethernet/ti/icssg/icssg_stats.c | 6 +-
drivers/net/ethernet/ti/icssg/icssg_stats.h | 85 +++++++++--------
.../net/ethernet/ti/icssg/icssg_switch_map.h | 10 ++
8 files changed, 193 insertions(+), 46 deletions(-)
diff --git a/Documentation/networking/device_drivers/ethernet/ti/icssg_prueth.rst b/Documentation/networking/device_drivers/ethernet/ti/icssg_prueth.rst
index da21ddf431bbc..faa1fc18a6737 100644
--- a/Documentation/networking/device_drivers/ethernet/ti/icssg_prueth.rst
+++ b/Documentation/networking/device_drivers/ethernet/ti/icssg_prueth.rst
@@ -54,3 +54,22 @@ These statistics are as follows,
- ``FW_HOST_TX_PKT_CNT``: Number of valid packets copied by RTU0 to Tx queues
- ``FW_HOST_EGRESS_Q_PRE_OVERFLOW``: Host Egress Q (Pre-emptible) Overflow Counter
- ``FW_HOST_EGRESS_Q_EXP_OVERFLOW``: Host Egress Q (Pre-emptible) Overflow Counter
+ - ``FW_HSR_FWD_CHECK_FAIL_DROP``: Packets dropped on the HSR forwarding path due to failed checks
+ - ``FW_HSR_HE_CHECK_FAIL_DROP``: Packets dropped on the host egress path due to failed checks
+ - ``FW_HSR_SKIP_HOST_DUP_DISCARD``: Frames for which the host duplicate discard check was skipped
+
+HSR/LRE Standard Statistics
+============================
+
+When the ICSSG operates in HSR offload mode the driver exposes the IEC 62439-3
+LRE counters through the standard netlink stats interface.
+
+The following per-port (port A and port B) LRE counters are reported:
+
+ - ``lreCntTx``: Number of HSR/PRP tagged frames sent
+ - ``lreCntRx``: Number of HSR/PRP tagged frames received
+ - ``lreCntUnique``: Number of frames received with no duplicate detected
+ - ``lreCntDuplicate``: Number of frames received for which exactly one duplicate was detected
+ - ``lreCntMultiple``: Number of frames received for which more than one duplicate was detected
+ - ``lreCntOwnRx``: Number of HSR/PRP tagged frames received whose source MAC matches the node's own address
+ - ``lreCntErrWrongLan``: Number of frames received with a wrong LAN identifier (PRP only)
diff --git a/drivers/net/ethernet/ti/icssg/icssg_common.c b/drivers/net/ethernet/ti/icssg/icssg_common.c
index a28a608f9bf4b..1fcb031949535 100644
--- a/drivers/net/ethernet/ti/icssg/icssg_common.c
+++ b/drivers/net/ethernet/ti/icssg/icssg_common.c
@@ -1643,7 +1643,12 @@ void icssg_ndo_get_stats64(struct net_device *ndev,
emac_get_stat_by_name(emac, "FW_INF_DROP_TAGGED") +
emac_get_stat_by_name(emac, "FW_INF_DROP_PRIOTAGGED") +
emac_get_stat_by_name(emac, "FW_INF_DROP_NOTAG") +
- emac_get_stat_by_name(emac, "FW_INF_DROP_NOTMEMBER");
+ emac_get_stat_by_name(emac,
+ "FW_INF_DROP_NOTMEMBER") +
+ emac_get_stat_by_name(emac,
+ "FW_HSR_FWD_CHECK_FAIL_DROP") +
+ emac_get_stat_by_name(emac,
+ "FW_HSR_HE_CHECK_FAIL_DROP");
stats->tx_errors = ndev->stats.tx_errors;
stats->tx_dropped = ndev->stats.tx_dropped +
emac_get_stat_by_name(emac, "FW_RTU_PKT_DROP") +
diff --git a/drivers/net/ethernet/ti/icssg/icssg_ethtool.c b/drivers/net/ethernet/ti/icssg/icssg_ethtool.c
index b715af21d23ac..7a99c99aab1e8 100644
--- a/drivers/net/ethernet/ti/icssg/icssg_ethtool.c
+++ b/drivers/net/ethernet/ti/icssg/icssg_ethtool.c
@@ -74,7 +74,9 @@ static int emac_get_sset_count(struct net_device *ndev, int stringset)
if (emac->prueth->pa_stats)
return ICSSG_NUM_ETHTOOL_STATS;
else
- return ICSSG_NUM_ETHTOOL_STATS - ICSSG_NUM_PA_STATS;
+ return ICSSG_NUM_ETHTOOL_STATS -
+ (ICSSG_NUM_PA_STATS -
+ ICSSG_NUM_PA_STANDARD_STATS);
default:
return -EOPNOTSUPP;
}
@@ -93,7 +95,8 @@ static void emac_get_strings(struct net_device *ndev, u32 stringset, u8 *data)
ethtool_puts(&p, icssg_all_miig_stats[i].name);
if (emac->prueth->pa_stats)
for (i = 0; i < ARRAY_SIZE(icssg_all_pa_stats); i++)
- ethtool_puts(&p, icssg_all_pa_stats[i].name);
+ if (!icssg_all_pa_stats[i].standard_stats)
+ ethtool_puts(&p, icssg_all_pa_stats[i].name);
break;
default:
break;
@@ -114,7 +117,8 @@ static void emac_get_ethtool_stats(struct net_device *ndev,
if (emac->prueth->pa_stats)
for (i = 0; i < ARRAY_SIZE(icssg_all_pa_stats); i++)
- *(data++) = emac->pa_stats[i];
+ if (!icssg_all_pa_stats[i].standard_stats)
+ *(data++) = emac->pa_stats[i];
}
static int emac_get_ts_info(struct net_device *ndev,
diff --git a/drivers/net/ethernet/ti/icssg/icssg_prueth.c b/drivers/net/ethernet/ti/icssg/icssg_prueth.c
index 591be5c8056b4..6df5bb2582928 100644
--- a/drivers/net/ethernet/ti/icssg/icssg_prueth.c
+++ b/drivers/net/ethernet/ti/icssg/icssg_prueth.c
@@ -14,6 +14,7 @@
#include <linux/etherdevice.h>
#include <linux/genalloc.h>
#include <linux/if_hsr.h>
+#include <linux/if_link.h>
#include <linux/if_vlan.h>
#include <linux/interrupt.h>
#include <linux/io-64-nonatomic-hi-lo.h>
@@ -1633,6 +1634,95 @@ int prueth_xsk_wakeup(struct net_device *ndev, u32 qid, u32 flags)
return 0;
}
+/**
+ * prueth_ndo_get_offload_stats - Fill standard LRE counters from ICSSG.
+ * @attr_id: Stats attribute ID; only IFLA_OFFLOAD_XSTATS_LRE_STATS is handled.
+ * @dev: Slave net_device (port A) whose offload stats are requested.
+ * @sp: Output pointer; cast to struct hsr_lre_stats *.
+ *
+ * Called by the HSR stack via ndo_get_offload_stats on the slave A device.
+ * Fetches the per-port PA stat register snapshots for port A and port B,
+ * and fills the IEC-62439-3 per-port LRE counters. Port C (interlink)
+ * counters are not available in ICSSG hardware and remain at ~0ULL.
+ *
+ * Return: 0 on success, -EOPNOTSUPP if the device does not support
+ * HSR offload statistics for the requested attribute.
+ */
+static int prueth_ndo_get_offload_stats(int attr_id,
+ const struct net_device *dev,
+ void *sp)
+{
+ struct prueth_emac *emac = netdev_priv(dev);
+ struct prueth *prueth = emac->prueth;
+ struct hsr_lre_stats *stats = sp;
+ struct prueth_emac *emac0;
+ struct prueth_emac *emac1;
+
+ if (attr_id != IFLA_OFFLOAD_XSTATS_LRE_STATS)
+ return -EOPNOTSUPP;
+
+ if (!prueth->is_hsr_offload_mode)
+ return -EOPNOTSUPP;
+
+ /* Current emac is SlaveA. Other emac is SlaveB */
+ emac0 = emac;
+ emac1 = prueth->emac[1 - prueth_emac_slice(emac)];
+
+ if (!prueth->pa_stats)
+ return -EOPNOTSUPP;
+
+ /* Initialise all fields to ~0ULL ("unsupported"); only port A and B
+ * counters are filled — port C and aggregate counters are not
+ * available in ICSSG hardware.
+ */
+ memset(stats, 0xff, sizeof(*stats));
+
+ emac_update_hardware_stats(emac0);
+ stats->cnt_tx_a =
+ emac_get_stat_by_name(emac0, "FW_LRE_CNT_TX");
+ stats->cnt_rx_a =
+ emac_get_stat_by_name(emac0, "FW_LRE_CNT_RX");
+ stats->cnt_unique_a =
+ emac_get_stat_by_name(emac0, "FW_LRE_CNT_UNIQUE_RX");
+ stats->cnt_duplicate_a =
+ emac_get_stat_by_name(emac0, "FW_LRE_CNT_DUPLICATE_RX");
+ stats->cnt_multi_a =
+ emac_get_stat_by_name(emac0, "FW_LRE_CNT_MULTIPLE_RX");
+ stats->cnt_own_rx_a =
+ emac_get_stat_by_name(emac0, "FW_LRE_CNT_OWN_RX");
+ /* lreCntErrWrongLan is PRP only */
+ stats->cnt_err_wrong_lan_a =
+ emac_get_stat_by_name(emac0, "FW_LRE_CNT_ERRWRONGLAN");
+
+ emac_update_hardware_stats(emac1);
+ stats->cnt_tx_b =
+ emac_get_stat_by_name(emac1, "FW_LRE_CNT_TX");
+ stats->cnt_rx_b =
+ emac_get_stat_by_name(emac1, "FW_LRE_CNT_RX");
+ stats->cnt_unique_b =
+ emac_get_stat_by_name(emac1, "FW_LRE_CNT_UNIQUE_RX");
+ stats->cnt_duplicate_b =
+ emac_get_stat_by_name(emac1, "FW_LRE_CNT_DUPLICATE_RX");
+ stats->cnt_multi_b =
+ emac_get_stat_by_name(emac1, "FW_LRE_CNT_MULTIPLE_RX");
+ stats->cnt_own_rx_b =
+ emac_get_stat_by_name(emac1, "FW_LRE_CNT_OWN_RX");
+ stats->cnt_err_wrong_lan_b =
+ emac_get_stat_by_name(emac1, "FW_LRE_CNT_ERRWRONGLAN");
+
+ return 0;
+}
+
+static bool prueth_ndo_has_offload_stats(const struct net_device *dev,
+ int attr_id)
+{
+ struct prueth_emac *emac = netdev_priv(dev);
+ struct prueth *prueth = emac->prueth;
+
+ return attr_id == IFLA_OFFLOAD_XSTATS_LRE_STATS &&
+ prueth->is_hsr_offload_mode && prueth->pa_stats;
+}
+
static const struct net_device_ops emac_netdev_ops = {
.ndo_open = emac_ndo_open,
.ndo_stop = emac_ndo_stop,
@@ -1652,6 +1742,8 @@ static const struct net_device_ops emac_netdev_ops = {
.ndo_hwtstamp_get = icssg_ndo_get_ts_config,
.ndo_hwtstamp_set = icssg_ndo_set_ts_config,
.ndo_xsk_wakeup = prueth_xsk_wakeup,
+ .ndo_has_offload_stats = prueth_ndo_has_offload_stats,
+ .ndo_get_offload_stats = prueth_ndo_get_offload_stats,
};
static int prueth_netdev_init(struct prueth *prueth,
diff --git a/drivers/net/ethernet/ti/icssg/icssg_prueth.h b/drivers/net/ethernet/ti/icssg/icssg_prueth.h
index df93d15c5b786..d6c221e897924 100644
--- a/drivers/net/ethernet/ti/icssg/icssg_prueth.h
+++ b/drivers/net/ethernet/ti/icssg/icssg_prueth.h
@@ -57,12 +57,14 @@
#define ICSSG_MAX_RFLOWS 8 /* per slice */
-#define ICSSG_NUM_PA_STATS 32
+#define ICSSG_NUM_PA_STATS 42
#define ICSSG_NUM_MIIG_STATS 60
/* Number of ICSSG related stats */
#define ICSSG_NUM_STATS (ICSSG_NUM_MIIG_STATS + ICSSG_NUM_PA_STATS)
-#define ICSSG_NUM_STANDARD_STATS 31
-#define ICSSG_NUM_ETHTOOL_STATS (ICSSG_NUM_STATS - ICSSG_NUM_STANDARD_STATS)
+#define ICSSG_NUM_STANDARD_STATS 31
+#define ICSSG_NUM_PA_STANDARD_STATS 7
+#define ICSSG_NUM_ETHTOOL_STATS (ICSSG_NUM_STATS - ICSSG_NUM_STANDARD_STATS - \
+ ICSSG_NUM_PA_STANDARD_STATS)
#define IEP_DEFAULT_CYCLE_TIME_NS 1000000 /* 1 ms */
@@ -458,7 +460,7 @@ int emac_fdb_flow_id_updated(struct prueth_emac *emac);
void icssg_stats_work_handler(struct work_struct *work);
void emac_update_hardware_stats(struct prueth_emac *emac);
-int emac_get_stat_by_name(struct prueth_emac *emac, char *stat_name);
+u64 emac_get_stat_by_name(struct prueth_emac *emac, char *stat_name);
/* Common functions */
void prueth_cleanup_rx_chns(struct prueth_emac *emac,
diff --git a/drivers/net/ethernet/ti/icssg/icssg_stats.c b/drivers/net/ethernet/ti/icssg/icssg_stats.c
index 7159baa0155cf..9950d0ba899fa 100644
--- a/drivers/net/ethernet/ti/icssg/icssg_stats.c
+++ b/drivers/net/ethernet/ti/icssg/icssg_stats.c
@@ -62,6 +62,7 @@ void emac_update_hardware_stats(struct prueth_emac *emac)
spin_unlock(&prueth->stats_lock);
}
+EXPORT_SYMBOL_GPL(emac_update_hardware_stats);
void icssg_stats_work_handler(struct work_struct *work)
{
@@ -74,7 +75,7 @@ void icssg_stats_work_handler(struct work_struct *work)
}
EXPORT_SYMBOL_GPL(icssg_stats_work_handler);
-int emac_get_stat_by_name(struct prueth_emac *emac, char *stat_name)
+u64 emac_get_stat_by_name(struct prueth_emac *emac, char *stat_name)
{
int i;
@@ -91,5 +92,6 @@ int emac_get_stat_by_name(struct prueth_emac *emac, char *stat_name)
}
netdev_err(emac->ndev, "Invalid stats %s\n", stat_name);
- return -EINVAL;
+ return ~0ULL;
}
+EXPORT_SYMBOL_GPL(emac_get_stat_by_name);
diff --git a/drivers/net/ethernet/ti/icssg/icssg_stats.h b/drivers/net/ethernet/ti/icssg/icssg_stats.h
index 6f4400d8a0f61..373debfb815cc 100644
--- a/drivers/net/ethernet/ti/icssg/icssg_stats.h
+++ b/drivers/net/ethernet/ti/icssg/icssg_stats.h
@@ -157,50 +157,63 @@ static const struct icssg_miig_stats icssg_all_miig_stats[] = {
static_assert(ARRAY_SIZE(icssg_all_miig_stats) == ICSSG_NUM_MIIG_STATS);
-#define ICSSG_PA_STATS(field) \
-{ \
- #field, \
- field, \
+#define ICSSG_PA_STATS(field, stats_type) \
+{ \
+ #field, \
+ field, \
+ stats_type \
}
struct icssg_pa_stats {
char name[ETH_GSTRING_LEN];
u32 offset;
+ bool standard_stats;
};
static const struct icssg_pa_stats icssg_all_pa_stats[] = {
- ICSSG_PA_STATS(FW_RTU_PKT_DROP),
- ICSSG_PA_STATS(FW_Q0_OVERFLOW),
- ICSSG_PA_STATS(FW_Q1_OVERFLOW),
- ICSSG_PA_STATS(FW_Q2_OVERFLOW),
- ICSSG_PA_STATS(FW_Q3_OVERFLOW),
- ICSSG_PA_STATS(FW_Q4_OVERFLOW),
- ICSSG_PA_STATS(FW_Q5_OVERFLOW),
- ICSSG_PA_STATS(FW_Q6_OVERFLOW),
- ICSSG_PA_STATS(FW_Q7_OVERFLOW),
- ICSSG_PA_STATS(FW_DROPPED_PKT),
- ICSSG_PA_STATS(FW_RX_ERROR),
- ICSSG_PA_STATS(FW_RX_DS_INVALID),
- ICSSG_PA_STATS(FW_TX_DROPPED_PACKET),
- ICSSG_PA_STATS(FW_TX_TS_DROPPED_PACKET),
- ICSSG_PA_STATS(FW_INF_PORT_DISABLED),
- ICSSG_PA_STATS(FW_INF_SAV),
- ICSSG_PA_STATS(FW_INF_SA_DL),
- ICSSG_PA_STATS(FW_INF_PORT_BLOCKED),
- ICSSG_PA_STATS(FW_INF_DROP_TAGGED),
- ICSSG_PA_STATS(FW_INF_DROP_PRIOTAGGED),
- ICSSG_PA_STATS(FW_INF_DROP_NOTAG),
- ICSSG_PA_STATS(FW_INF_DROP_NOTMEMBER),
- ICSSG_PA_STATS(FW_RX_EOF_SHORT_FRMERR),
- ICSSG_PA_STATS(FW_RX_B0_DROP_EARLY_EOF),
- ICSSG_PA_STATS(FW_TX_JUMBO_FRM_CUTOFF),
- ICSSG_PA_STATS(FW_RX_EXP_FRAG_Q_DROP),
- ICSSG_PA_STATS(FW_RX_FIFO_OVERRUN),
- ICSSG_PA_STATS(FW_CUT_THR_PKT),
- ICSSG_PA_STATS(FW_HOST_RX_PKT_CNT),
- ICSSG_PA_STATS(FW_HOST_TX_PKT_CNT),
- ICSSG_PA_STATS(FW_HOST_EGRESS_Q_PRE_OVERFLOW),
- ICSSG_PA_STATS(FW_HOST_EGRESS_Q_EXP_OVERFLOW),
+ /* Firmware-specific stats: exposed via ethtool -S only */
+ ICSSG_PA_STATS(FW_RTU_PKT_DROP, false),
+ ICSSG_PA_STATS(FW_Q0_OVERFLOW, false),
+ ICSSG_PA_STATS(FW_Q1_OVERFLOW, false),
+ ICSSG_PA_STATS(FW_Q2_OVERFLOW, false),
+ ICSSG_PA_STATS(FW_Q3_OVERFLOW, false),
+ ICSSG_PA_STATS(FW_Q4_OVERFLOW, false),
+ ICSSG_PA_STATS(FW_Q5_OVERFLOW, false),
+ ICSSG_PA_STATS(FW_Q6_OVERFLOW, false),
+ ICSSG_PA_STATS(FW_Q7_OVERFLOW, false),
+ ICSSG_PA_STATS(FW_DROPPED_PKT, false),
+ ICSSG_PA_STATS(FW_RX_ERROR, false),
+ ICSSG_PA_STATS(FW_RX_DS_INVALID, false),
+ ICSSG_PA_STATS(FW_TX_DROPPED_PACKET, false),
+ ICSSG_PA_STATS(FW_TX_TS_DROPPED_PACKET, false),
+ ICSSG_PA_STATS(FW_INF_PORT_DISABLED, false),
+ ICSSG_PA_STATS(FW_INF_SAV, false),
+ ICSSG_PA_STATS(FW_INF_SA_DL, false),
+ ICSSG_PA_STATS(FW_INF_PORT_BLOCKED, false),
+ ICSSG_PA_STATS(FW_INF_DROP_TAGGED, false),
+ ICSSG_PA_STATS(FW_INF_DROP_PRIOTAGGED, false),
+ ICSSG_PA_STATS(FW_INF_DROP_NOTAG, false),
+ ICSSG_PA_STATS(FW_INF_DROP_NOTMEMBER, false),
+ ICSSG_PA_STATS(FW_RX_EOF_SHORT_FRMERR, false),
+ ICSSG_PA_STATS(FW_RX_B0_DROP_EARLY_EOF, false),
+ ICSSG_PA_STATS(FW_TX_JUMBO_FRM_CUTOFF, false),
+ ICSSG_PA_STATS(FW_RX_EXP_FRAG_Q_DROP, false),
+ ICSSG_PA_STATS(FW_RX_FIFO_OVERRUN, false),
+ ICSSG_PA_STATS(FW_CUT_THR_PKT, false),
+ ICSSG_PA_STATS(FW_HOST_RX_PKT_CNT, false),
+ ICSSG_PA_STATS(FW_HOST_TX_PKT_CNT, false),
+ ICSSG_PA_STATS(FW_HOST_EGRESS_Q_PRE_OVERFLOW, false),
+ ICSSG_PA_STATS(FW_HOST_EGRESS_Q_EXP_OVERFLOW, false),
+ ICSSG_PA_STATS(FW_HSR_FWD_CHECK_FAIL_DROP, false),
+ ICSSG_PA_STATS(FW_HSR_HE_CHECK_FAIL_DROP, false),
+ ICSSG_PA_STATS(FW_HSR_SKIP_HOST_DUP_DISCARD, false),
+ ICSSG_PA_STATS(FW_LRE_CNT_UNIQUE_RX, true),
+ ICSSG_PA_STATS(FW_LRE_CNT_DUPLICATE_RX, true),
+ ICSSG_PA_STATS(FW_LRE_CNT_MULTIPLE_RX, true),
+ ICSSG_PA_STATS(FW_LRE_CNT_RX, true),
+ ICSSG_PA_STATS(FW_LRE_CNT_TX, true),
+ ICSSG_PA_STATS(FW_LRE_CNT_OWN_RX, true),
+ ICSSG_PA_STATS(FW_LRE_CNT_ERRWRONGLAN, true),
};
static_assert(ARRAY_SIZE(icssg_all_pa_stats) == ICSSG_NUM_PA_STATS);
diff --git a/drivers/net/ethernet/ti/icssg/icssg_switch_map.h b/drivers/net/ethernet/ti/icssg/icssg_switch_map.h
index 7e053b8af3ece..556facb33e0ce 100644
--- a/drivers/net/ethernet/ti/icssg/icssg_switch_map.h
+++ b/drivers/net/ethernet/ti/icssg/icssg_switch_map.h
@@ -266,5 +266,15 @@
#define FW_HOST_TX_PKT_CNT 0x0250
#define FW_HOST_EGRESS_Q_PRE_OVERFLOW 0x0258
#define FW_HOST_EGRESS_Q_EXP_OVERFLOW 0x0260
+#define FW_HSR_FWD_CHECK_FAIL_DROP 0x0500
+#define FW_HSR_HE_CHECK_FAIL_DROP 0x0508
+#define FW_HSR_SKIP_HOST_DUP_DISCARD 0x0510
+#define FW_LRE_CNT_UNIQUE_RX 0x0518
+#define FW_LRE_CNT_DUPLICATE_RX 0x0520
+#define FW_LRE_CNT_MULTIPLE_RX 0x0528
+#define FW_LRE_CNT_RX 0x0530
+#define FW_LRE_CNT_TX 0x0538
+#define FW_LRE_CNT_OWN_RX 0x0540
+#define FW_LRE_CNT_ERRWRONGLAN 0x0548
#endif /* __NET_TI_ICSSG_SWITCH_MAP_H */
--
2.34.1
^ permalink raw reply related
* [PATCH net-next v4 2/3] net: ti: icssg: Add static_assert to guard stat array counts
From: MD Danish Anwar @ 2026-06-11 9:50 UTC (permalink / raw)
To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Jonathan Corbet, Shuah Khan, MD Danish Anwar,
Roger Quadros, Andrew Lunn, Meghana Malladi, Jacob Keller,
David Carlier, Vadim Fedorenko, Kevin Hao, Markus Elfring,
Hangbin Liu, Fernando Fernandez Mancera, Jan Vaclav
Cc: netdev, linux-doc, linux-kernel, linux-arm-kernel
In-Reply-To: <20260611095035.852370-1-danishanwar@ti.com>
Place static_assert() immediately after each of icssg_all_miig_stats[]
and icssg_all_pa_stats[] in icssg_stats.h to verify at build time that
ICSSG_NUM_MIIG_STATS and ICSSG_NUM_PA_STATS stay in sync with the
actual array sizes. This turns a silent miscount into a build error
should either the constant or the array be updated independently.
Signed-off-by: MD Danish Anwar <danishanwar@ti.com>
---
drivers/net/ethernet/ti/icssg/icssg_stats.h | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/net/ethernet/ti/icssg/icssg_stats.h b/drivers/net/ethernet/ti/icssg/icssg_stats.h
index 5ec0b38e0c67d..6f4400d8a0f61 100644
--- a/drivers/net/ethernet/ti/icssg/icssg_stats.h
+++ b/drivers/net/ethernet/ti/icssg/icssg_stats.h
@@ -155,6 +155,8 @@ static const struct icssg_miig_stats icssg_all_miig_stats[] = {
ICSSG_MIIG_STATS(tx_bytes, true),
};
+static_assert(ARRAY_SIZE(icssg_all_miig_stats) == ICSSG_NUM_MIIG_STATS);
+
#define ICSSG_PA_STATS(field) \
{ \
#field, \
@@ -201,4 +203,6 @@ static const struct icssg_pa_stats icssg_all_pa_stats[] = {
ICSSG_PA_STATS(FW_HOST_EGRESS_Q_EXP_OVERFLOW),
};
+static_assert(ARRAY_SIZE(icssg_all_pa_stats) == ICSSG_NUM_PA_STATS);
+
#endif /* __NET_TI_ICSSG_STATS_H */
--
2.34.1
^ permalink raw reply related
* [PATCH net-next v4 0/3] Add standard stats for HSR/PRP
From: MD Danish Anwar @ 2026-06-11 9:50 UTC (permalink / raw)
To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Jonathan Corbet, Shuah Khan, MD Danish Anwar,
Roger Quadros, Andrew Lunn, Meghana Malladi, Jacob Keller,
David Carlier, Vadim Fedorenko, Kevin Hao, Markus Elfring,
Hangbin Liu, Fernando Fernandez Mancera, Jan Vaclav
Cc: netdev, linux-doc, linux-kernel, linux-arm-kernel, Felix Maurer,
Luka Gejak
Add standard stats for HSR / PRP. This series was initially adding HSR/PRP
related stats for ICSSG driver. Based on maintainers' comments on v2 I am
now adding support to dump standard stats for HSR/PRP.
The drivers which support offload can populate these standard stats.
This series only implements offloaded stats. For software-only interfaces
Felix Maurer had said he will do it later [1]
v3 - v4:
*) Address AI review comments on Patch 1/3 and Patch 3/3. AI review comments
on patch 2/3 were not relevant to this series.
v3 https://lore.kernel.org/all/20260608100930.210149-1-danishanwar@ti.com/
v2 https://lore.kernel.org/all/20260514075605.850674-1-danishanwar@ti.com/
[1] https://lore.kernel.org/all/ag87pBZfOyccPZTc@thinkpad/
Cc: Jakub Kicinski <kuba@kernel.org>
Cc: Felix Maurer <fmaurer@redhat.com>
Cc: Luka Gejak <luka.gejak@linux.dev>
MD Danish Anwar (3):
net: hsr: Add standard LRE stats via RTM_GETSTATS /
IFLA_STATS_LINK_XSTATS
net: ti: icssg: Add static_assert to guard stat array counts
net: ti: icssg: Add HSR offload statistics support
.../ethernet/ti/icssg_prueth.rst | 19 +++
drivers/net/ethernet/ti/icssg/icssg_common.c | 7 +-
drivers/net/ethernet/ti/icssg/icssg_ethtool.c | 10 +-
drivers/net/ethernet/ti/icssg/icssg_prueth.c | 92 +++++++++++++
drivers/net/ethernet/ti/icssg/icssg_prueth.h | 10 +-
drivers/net/ethernet/ti/icssg/icssg_stats.c | 6 +-
drivers/net/ethernet/ti/icssg/icssg_stats.h | 89 +++++++-----
.../net/ethernet/ti/icssg/icssg_switch_map.h | 10 ++
include/linux/if_hsr.h | 48 +++++++
include/uapi/linux/hsr_netlink.h | 56 ++++++++
include/uapi/linux/if_link.h | 2 +
net/hsr/hsr_netlink.c | 130 ++++++++++++++++--
tools/include/uapi/linux/if_link.h | 2 +
13 files changed, 427 insertions(+), 54 deletions(-)
base-commit: 0068940907d33217ae01217f84910a5cde606c17
--
2.34.1
^ permalink raw reply
* [PATCH net-next v4 1/3] net: hsr: Add standard LRE stats via RTM_GETSTATS / IFLA_STATS_LINK_XSTATS
From: MD Danish Anwar @ 2026-06-11 9:50 UTC (permalink / raw)
To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Jonathan Corbet, Shuah Khan, MD Danish Anwar,
Roger Quadros, Andrew Lunn, Meghana Malladi, Jacob Keller,
David Carlier, Vadim Fedorenko, Kevin Hao, Markus Elfring,
Hangbin Liu, Fernando Fernandez Mancera, Jan Vaclav
Cc: netdev, linux-doc, linux-kernel, linux-arm-kernel
In-Reply-To: <20260611095035.852370-1-danishanwar@ti.com>
Per the IEC-62439-3 specification the Link Redundancy Entity (LRE)
maintains a well-defined set of counters applicable to both software
and offloaded HSR/PRP implementations. Define these counters as
individual netlink attributes inside a LINK_XSTATS_TYPE_HSR nest,
following the approach used by bridge and bond with IFLA_STATS_LINK_XSTATS.
The full IEC-62439-3 MIB counter set is represented, with per-port (A,
B, C) granularity where applicable:
lreCntTx{A,B,C} - sent HSR/PRP tagged frames per port
lreCntRx{A,B,C} - received HSR/PRP tagged frames per port
lreCntErrWrongLan{A,B,C} - received frames with wrong LAN ID (PRP)
lreCntErrors{A,B,C} - received frames with errors per port
lreCntUnique{A,B,C} - frames received without duplicate
lreCntDuplicate{A,B,C} - frames received with exactly one duplicate
lreCntMulti{A,B,C} - frames received with more than one duplicate
lreCntOwnRx{A,B} - own-address frames received (HSR only)
Each counter is encoded as its own HSR_XSTATS_* u64 netlink attribute.
Unsupported counters are initialised to ~0ULL by the kernel and omitted
from the netlink reply; user-space must treat an absent attribute as
"not available".
The UAPI attribute enum (HSR_XSTATS_*) is added to hsr_netlink.h.
LINK_XSTATS_TYPE_HSR is added to the LINK_XSTATS_TYPE_* enum in both
include/uapi/linux/if_link.h and tools/include/uapi/linux/if_link.h.
A kernel-internal struct hsr_lre_stats (in linux/if_hsr.h) is provided
for offload drivers to fill via ndo_get_offload_stats. Unsupported
fields must be left at the ~0ULL value initialised by the HSR layer
before calling the NDO.
The HSR stack calls ndo_get_offload_stats on slave A to collect offload
counters.
Signed-off-by: MD Danish Anwar <danishanwar@ti.com>
---
include/linux/if_hsr.h | 48 +++++++++++
include/uapi/linux/hsr_netlink.h | 56 +++++++++++++
include/uapi/linux/if_link.h | 2 +
net/hsr/hsr_netlink.c | 130 +++++++++++++++++++++++++++--
tools/include/uapi/linux/if_link.h | 2 +
5 files changed, 230 insertions(+), 8 deletions(-)
diff --git a/include/linux/if_hsr.h b/include/linux/if_hsr.h
index f4cf2dd36d193..b8c20f0906194 100644
--- a/include/linux/if_hsr.h
+++ b/include/linux/if_hsr.h
@@ -38,6 +38,54 @@ struct hsr_tag {
#define HSR_HLEN 6
+/**
+ * struct hsr_lre_stats - Kernel-internal IEC-62439-3 LRE counter set.
+ *
+ * This is the buffer type written by ndo_get_offload_stats() when called
+ * with attr_id == IFLA_STATS_LINK_XSTATS on an HSR slave device. Each
+ * field maps to one HSR_XSTATS_* netlink attribute. Fields that the
+ * offload driver does not support must be left at the initialised value of
+ * ~0ULL; the HSR layer will skip those when building the netlink reply.
+ *
+ * Per-port suffix: _a = port A (slave 1 / LAN-A),
+ * _b = port B (slave 2 / LAN-B),
+ * _c = interlink / application interface.
+ *
+ * @cnt_tx_a: lreCntTxA - sent HSR/PRP tagged frames on port A.
+ * @cnt_tx_b: lreCntTxB - sent HSR/PRP tagged frames on port B.
+ * @cnt_tx_c: lreCntTxC - sent HSR/PRP tagged frames on port C.
+ * @cnt_rx_a: lreCntRxA - received HSR/PRP tagged frames on port A.
+ * @cnt_rx_b: lreCntRxB - received HSR/PRP tagged frames on port B.
+ * @cnt_rx_c: lreCntRxC - received HSR/PRP tagged frames on port C.
+ * @cnt_err_wrong_lan_a: lreCntErrWrongLanA - wrong LAN ID frames on port A.
+ * @cnt_err_wrong_lan_b: lreCntErrWrongLanB - wrong LAN ID frames on port B.
+ * @cnt_err_wrong_lan_c: lreCntErrWrongLanC - wrong LAN ID frames on port C.
+ * @cnt_errors_a: lreCntErrorsA - received frames with errors on port A.
+ * @cnt_errors_b: lreCntErrorsB - received frames with errors on port B.
+ * @cnt_errors_c: lreCntErrorsC - received frames with errors on port C.
+ * @cnt_unique_a: lreCntUniqueA - frames received without duplicate on port A.
+ * @cnt_unique_b: lreCntUniqueB - frames received without duplicate on port B.
+ * @cnt_unique_c: lreCntUniqueC - frames received without duplicate on port C.
+ * @cnt_duplicate_a: lreCntDuplicateA - frames with one duplicate on port A.
+ * @cnt_duplicate_b: lreCntDuplicateB - frames with one duplicate on port B.
+ * @cnt_duplicate_c: lreCntDuplicateC - frames with one duplicate on port C.
+ * @cnt_multi_a: lreCntMultiA - frames with more than one duplicate on port A.
+ * @cnt_multi_b: lreCntMultiB - frames with more than one duplicate on port B.
+ * @cnt_multi_c: lreCntMultiC - frames with more than one duplicate on port C.
+ * @cnt_own_rx_a: lreCntOwnRxA - own-address frames received on port A.
+ * @cnt_own_rx_b: lreCntOwnRxB - own-address frames received on port B.
+ */
+struct hsr_lre_stats {
+ u64 cnt_tx_a, cnt_tx_b, cnt_tx_c;
+ u64 cnt_rx_a, cnt_rx_b, cnt_rx_c;
+ u64 cnt_err_wrong_lan_a, cnt_err_wrong_lan_b, cnt_err_wrong_lan_c;
+ u64 cnt_errors_a, cnt_errors_b, cnt_errors_c;
+ u64 cnt_unique_a, cnt_unique_b, cnt_unique_c;
+ u64 cnt_duplicate_a, cnt_duplicate_b, cnt_duplicate_c;
+ u64 cnt_multi_a, cnt_multi_b, cnt_multi_c;
+ u64 cnt_own_rx_a, cnt_own_rx_b;
+};
+
#if IS_ENABLED(CONFIG_HSR)
extern bool is_hsr_master(struct net_device *dev);
extern int hsr_get_version(struct net_device *dev, enum hsr_version *ver);
diff --git a/include/uapi/linux/hsr_netlink.h b/include/uapi/linux/hsr_netlink.h
index d540ea9bbef4b..c414a2bb93b79 100644
--- a/include/uapi/linux/hsr_netlink.h
+++ b/include/uapi/linux/hsr_netlink.h
@@ -48,4 +48,60 @@ enum {
};
#define HSR_C_MAX (__HSR_C_MAX - 1)
+/* HSR/PRP LRE extended statistics attributes.
+ * Reported inside LINK_XSTATS_TYPE_HSR (RTM_GETSTATS / ip stats show).
+ * Counter definitions follow IEC-62439-3 MIB naming.
+ *
+ * All counters are __u64. Unsupported counters are omitted from the
+ * netlink reply; user-space must treat an absent attribute as "not available".
+ *
+ * Per-port suffix: _A = port A (slave 1), _B = port B (slave 2),
+ * _C = interlink / application interface.
+ */
+enum {
+ /* Sent HSR/PRP tagged frames per port */
+ HSR_XSTATS_CNT_TX_A = 1,
+ HSR_XSTATS_CNT_TX_B,
+ HSR_XSTATS_CNT_TX_C,
+
+ /* Received HSR/PRP tagged frames per port */
+ HSR_XSTATS_CNT_RX_A,
+ HSR_XSTATS_CNT_RX_B,
+ HSR_XSTATS_CNT_RX_C,
+
+ /* Received frames with wrong LAN ID (PRP only) per port */
+ HSR_XSTATS_CNT_ERR_WRONG_LAN_A,
+ HSR_XSTATS_CNT_ERR_WRONG_LAN_B,
+ HSR_XSTATS_CNT_ERR_WRONG_LAN_C,
+
+ /* Received frames with errors per port */
+ HSR_XSTATS_CNT_ERRORS_A,
+ HSR_XSTATS_CNT_ERRORS_B,
+ HSR_XSTATS_CNT_ERRORS_C,
+
+ /* Frames received with no duplicate per port */
+ HSR_XSTATS_CNT_UNIQUE_A,
+ HSR_XSTATS_CNT_UNIQUE_B,
+ HSR_XSTATS_CNT_UNIQUE_C,
+
+ /* Frames received with exactly one duplicate per port */
+ HSR_XSTATS_CNT_DUPLICATE_A,
+ HSR_XSTATS_CNT_DUPLICATE_B,
+ HSR_XSTATS_CNT_DUPLICATE_C,
+
+ /* Frames received with more than one duplicate per port */
+ HSR_XSTATS_CNT_MULTI_A,
+ HSR_XSTATS_CNT_MULTI_B,
+ HSR_XSTATS_CNT_MULTI_C,
+
+ /* Frames received matching this node's own address (HSR only) */
+ HSR_XSTATS_CNT_OWN_RX_A,
+ HSR_XSTATS_CNT_OWN_RX_B,
+
+ HSR_XSTATS_PAD,
+ __HSR_XSTATS_MAX,
+};
+
+#define HSR_XSTATS_MAX (__HSR_XSTATS_MAX - 1)
+
#endif /* __UAPI_HSR_NETLINK_H */
diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h
index 79ce4bc24cba6..11458f683624a 100644
--- a/include/uapi/linux/if_link.h
+++ b/include/uapi/linux/if_link.h
@@ -1905,6 +1905,7 @@ enum {
LINK_XSTATS_TYPE_UNSPEC,
LINK_XSTATS_TYPE_BRIDGE,
LINK_XSTATS_TYPE_BOND,
+ LINK_XSTATS_TYPE_HSR,
__LINK_XSTATS_TYPE_MAX
};
#define LINK_XSTATS_TYPE_MAX (__LINK_XSTATS_TYPE_MAX - 1)
@@ -1915,6 +1916,7 @@ enum {
IFLA_OFFLOAD_XSTATS_CPU_HIT, /* struct rtnl_link_stats64 */
IFLA_OFFLOAD_XSTATS_HW_S_INFO, /* HW stats info. A nest */
IFLA_OFFLOAD_XSTATS_L3_STATS, /* struct rtnl_hw_stats64 */
+ IFLA_OFFLOAD_XSTATS_LRE_STATS, /* struct hsr_lre_stats */
__IFLA_OFFLOAD_XSTATS_MAX
};
#define IFLA_OFFLOAD_XSTATS_MAX (__IFLA_OFFLOAD_XSTATS_MAX - 1)
diff --git a/net/hsr/hsr_netlink.c b/net/hsr/hsr_netlink.c
index db0b0af7a6920..31aedf7460a47 100644
--- a/net/hsr/hsr_netlink.c
+++ b/net/hsr/hsr_netlink.c
@@ -11,6 +11,8 @@
#include <linux/kernel.h>
#include <net/rtnetlink.h>
#include <net/genetlink.h>
+#include <uapi/linux/if_link.h>
+#include <uapi/linux/hsr_netlink.h>
#include "hsr_main.h"
#include "hsr_device.h"
#include "hsr_framereg.h"
@@ -189,15 +191,127 @@ static int hsr_fill_info(struct sk_buff *skb, const struct net_device *dev)
return -EMSGSIZE;
}
+/*
+ * Number of real HSR_XSTATS_* u64 counter attributes.
+ * Real counters run from HSR_XSTATS_CNT_TX_A(1) through
+ * HSR_XSTATS_CNT_OWN_RX_B(25); HSR_XSTATS_PAD is not a counter.
+ */
+#define HSR_XSTATS_CNT_ATTRS (HSR_XSTATS_PAD - 1)
+
+static size_t hsr_get_linkxstats_size(const struct net_device *dev, int attr)
+{
+ if (attr != IFLA_STATS_LINK_XSTATS)
+ return 0;
+
+ /* Nest header (LINK_XSTATS_TYPE_HSR) + one u64 nla per counter */
+ return nla_total_size(0) +
+ HSR_XSTATS_CNT_ATTRS * nla_total_size_64bit(sizeof(u64));
+}
+
+/* Put a u64 counter attribute; skip if value is ~0ULL (unsupported). */
+static int hsr_put_stat(struct sk_buff *skb, int attr_id, u64 val)
+{
+ if (val == ~0ULL)
+ return 0;
+ return nla_put_u64_64bit(skb, attr_id, val, HSR_XSTATS_PAD);
+}
+
+static int hsr_fill_linkxstats(struct sk_buff *skb,
+ const struct net_device *dev,
+ int *prividx, int attr)
+{
+ struct hsr_priv *hsr = netdev_priv(dev);
+ struct hsr_lre_stats stats;
+ int s_prividx = *prividx;
+ struct hsr_port *port;
+ struct nlattr *nest;
+ int err;
+
+ if (attr != IFLA_STATS_LINK_XSTATS)
+ return 0;
+
+ *prividx = 0;
+
+ nest = nla_nest_start_noflag(skb, LINK_XSTATS_TYPE_HSR);
+ if (!nest)
+ return -EMSGSIZE;
+
+ /* Initialise all counters to ~0ULL ("unsupported") */
+ memset(&stats, 0xff, sizeof(stats));
+
+ /* Ask the offload driver (if any) via ndo_get_offload_stats on slave A.
+ * Use IFLA_OFFLOAD_XSTATS_LRE_STATS, which is the correct identifier
+ * from enum ifla_offload_xstats that these NDOs expect.
+ */
+ port = hsr_port_get_hsr(hsr, HSR_PT_SLAVE_A);
+ if (port) {
+ const struct net_device_ops *ops = port->dev->netdev_ops;
+
+ if (ops->ndo_has_offload_stats &&
+ ops->ndo_has_offload_stats(port->dev,
+ IFLA_OFFLOAD_XSTATS_LRE_STATS) &&
+ ops->ndo_get_offload_stats) {
+ err = ops->ndo_get_offload_stats(IFLA_OFFLOAD_XSTATS_LRE_STATS,
+ port->dev, &stats);
+ if (err && err != -EOPNOTSUPP) {
+ nla_nest_cancel(skb, nest);
+ return err;
+ }
+ }
+ }
+
+#define PUT_STAT(attr, field) \
+ do { \
+ if (HSR_XSTATS_##attr < s_prividx) \
+ break; \
+ if (hsr_put_stat(skb, HSR_XSTATS_##attr, stats.field)) { \
+ *prividx = HSR_XSTATS_##attr; \
+ nla_nest_end(skb, nest); \
+ return -EMSGSIZE; \
+ } \
+ } while (0)
+
+ PUT_STAT(CNT_TX_A, cnt_tx_a);
+ PUT_STAT(CNT_TX_B, cnt_tx_b);
+ PUT_STAT(CNT_TX_C, cnt_tx_c);
+ PUT_STAT(CNT_RX_A, cnt_rx_a);
+ PUT_STAT(CNT_RX_B, cnt_rx_b);
+ PUT_STAT(CNT_RX_C, cnt_rx_c);
+ PUT_STAT(CNT_ERR_WRONG_LAN_A, cnt_err_wrong_lan_a);
+ PUT_STAT(CNT_ERR_WRONG_LAN_B, cnt_err_wrong_lan_b);
+ PUT_STAT(CNT_ERR_WRONG_LAN_C, cnt_err_wrong_lan_c);
+ PUT_STAT(CNT_ERRORS_A, cnt_errors_a);
+ PUT_STAT(CNT_ERRORS_B, cnt_errors_b);
+ PUT_STAT(CNT_ERRORS_C, cnt_errors_c);
+ PUT_STAT(CNT_UNIQUE_A, cnt_unique_a);
+ PUT_STAT(CNT_UNIQUE_B, cnt_unique_b);
+ PUT_STAT(CNT_UNIQUE_C, cnt_unique_c);
+ PUT_STAT(CNT_DUPLICATE_A, cnt_duplicate_a);
+ PUT_STAT(CNT_DUPLICATE_B, cnt_duplicate_b);
+ PUT_STAT(CNT_DUPLICATE_C, cnt_duplicate_c);
+ PUT_STAT(CNT_MULTI_A, cnt_multi_a);
+ PUT_STAT(CNT_MULTI_B, cnt_multi_b);
+ PUT_STAT(CNT_MULTI_C, cnt_multi_c);
+ PUT_STAT(CNT_OWN_RX_A, cnt_own_rx_a);
+ PUT_STAT(CNT_OWN_RX_B, cnt_own_rx_b);
+
+#undef PUT_STAT
+
+ nla_nest_end(skb, nest);
+ return 0;
+}
+
static struct rtnl_link_ops hsr_link_ops __read_mostly = {
- .kind = "hsr",
- .maxtype = IFLA_HSR_MAX,
- .policy = hsr_policy,
- .priv_size = sizeof(struct hsr_priv),
- .setup = hsr_dev_setup,
- .newlink = hsr_newlink,
- .dellink = hsr_dellink,
- .fill_info = hsr_fill_info,
+ .kind = "hsr",
+ .maxtype = IFLA_HSR_MAX,
+ .policy = hsr_policy,
+ .priv_size = sizeof(struct hsr_priv),
+ .setup = hsr_dev_setup,
+ .newlink = hsr_newlink,
+ .dellink = hsr_dellink,
+ .fill_info = hsr_fill_info,
+ .get_linkxstats_size = hsr_get_linkxstats_size,
+ .fill_linkxstats = hsr_fill_linkxstats,
};
/* attribute policy */
diff --git a/tools/include/uapi/linux/if_link.h b/tools/include/uapi/linux/if_link.h
index 7e46ca4cd31bb..ed4e6d53ccbab 100644
--- a/tools/include/uapi/linux/if_link.h
+++ b/tools/include/uapi/linux/if_link.h
@@ -1844,6 +1844,7 @@ enum {
LINK_XSTATS_TYPE_UNSPEC,
LINK_XSTATS_TYPE_BRIDGE,
LINK_XSTATS_TYPE_BOND,
+ LINK_XSTATS_TYPE_HSR,
__LINK_XSTATS_TYPE_MAX
};
#define LINK_XSTATS_TYPE_MAX (__LINK_XSTATS_TYPE_MAX - 1)
@@ -1854,6 +1855,7 @@ enum {
IFLA_OFFLOAD_XSTATS_CPU_HIT, /* struct rtnl_link_stats64 */
IFLA_OFFLOAD_XSTATS_HW_S_INFO, /* HW stats info. A nest */
IFLA_OFFLOAD_XSTATS_L3_STATS, /* struct rtnl_hw_stats64 */
+ IFLA_OFFLOAD_XSTATS_LRE_STATS, /* struct hsr_lre_stats */
__IFLA_OFFLOAD_XSTATS_MAX
};
#define IFLA_OFFLOAD_XSTATS_MAX (__IFLA_OFFLOAD_XSTATS_MAX - 1)
--
2.34.1
^ permalink raw reply related
* Re: [PATCH v7 01/30] drm/fb-helper: Remove unused local variable in hotplug_event()
From: Maxime Ripard @ 2026-06-11 9:49 UTC (permalink / raw)
To: Cristian Ciocaltea
Cc: dri-devel, kernel, linux-arm-kernel, linux-kernel, linux-rockchip,
Andrzej Hajda, Andy Yan, Daniel Stone, Dave Stevenson,
David Airlie, Heiko Stübner, Jernej Skrabec, Jonas Karlman,
Laurent Pinchart, Luca Ceresoli, Maarten Lankhorst, Maxime Ripard,
Maíra Canal, Neil Armstrong, Raspberry Pi Kernel Maintenance,
Robert Foss, Sandy Huang, Simona Vetter, Thomas Zimmermann
In-Reply-To: <20260602-dw-hdmi-qp-scramb-v7-1-445eb54ee1ed@collabora.com>
On Tue, 2 Jun 2026 01:44:01 +0300, Cristian Ciocaltea wrote:
> Remove the 'err' local variable in drm_fb_helper_hotplug_event() which
> only stores a return value that is never used beyond the immediate
> return statement. This simplifies the code without behavior changes.
>
> Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
>
> [ ... ]
Acked-by: Maxime Ripard <mripard@kernel.org>
Thanks!
Maxime
^ permalink raw reply
* Re: [PATCH 2/3] remoteproc: abort subdev stop sequence on first failure
From: Mukesh Ojha @ 2026-06-11 9:48 UTC (permalink / raw)
To: Stephan Gerhold
Cc: Bjorn Andersson, Mathieu Poirier, Matthias Brugger,
AngeloGioacchino Del Regno, linux-arm-msm, linux-remoteproc,
linux-kernel, linux-arm-kernel, linux-mediatek
In-Reply-To: <aif8VS0pLYurFEho@linaro.org>
On Tue, Jun 09, 2026 at 01:43:17PM +0200, Stephan Gerhold wrote:
> On Tue, Jun 09, 2026 at 03:52:52PM +0530, Mukesh Ojha wrote:
> > If a subdevice fails to stop, it indicates broken communication with the
> > DSP. Continuing to stop further subdevices against an unresponsive
> > remote processor could close rpmsg devices that could remove the memory
> > mapping from HLOS and in case if remote processor touches those memory
> > can result in SMMU fault.
> >
> > Change rproc_stop_subdevices() to return int and abort on the first
> > failing subdev. Propagate the error through rproc_stop() and
> > __rproc_detach() so callers are aware the teardown did not complete
> > cleanly.
> >
> > Signed-off-by: Mukesh Ojha <mukesh.ojha@oss.qualcomm.com>
>
> But what would callers do about this? If you abort the teardown sequence
> half-way through you now have an inconsistent half-stopped state that
> neither a new call to stop() nor a new call to start() could recover
> from. That doesn't sound much better than the SMMU fault. Or am I
> missing something here?
SMMU fault result in device crash while other is non-functional remote
processor. From Linux side, we do not know the state of remote processor
when the timeout happens..cleaning the subdevices can result in the
debug data being lost for hung remote processor.
>
> I would expect that we should either be able to tolerate the SMMU faults
> with the resets involved in the remoteproc stop/start sequence, or that
> DMA gets cancelled by the remoteproc stop sequence, before the buffers
> are unmapped. Perhaps the order of our stop sequence is just wrong? Can
> we unmap the buffers in the subdev unprepare() callback?
IMO, Sequence of subdevice is fine
glink-> sysmon-> ssr start
ssr -> sysmon-> glink stop
glink subdevice gets cleared due to which this issue happens.., it will
not help as we are ignoring the timeout.
> Thanks,
> Stephan
--
-Mukesh Ojha
^ permalink raw reply
* Re: [PATCH 1/3] arm64: dts: renesas: r8a77965-salvator-x: Enable GPU support
From: Niklas Söderlund @ 2026-06-11 9:47 UTC (permalink / raw)
To: Marek Vasut
Cc: linux-arm-kernel, Conor Dooley, David Airlie, Frank Binns,
Geert Uytterhoeven, Krzysztof Kozlowski, Maarten Lankhorst,
Magnus Damm, Matt Coster, Maxime Ripard, Rob Herring,
Simona Vetter, Thomas Zimmermann, devicetree, dri-devel,
linux-renesas-soc
In-Reply-To: <20260611005952.146825-1-marek.vasut+renesas@mailbox.org>
Hi Marek,
Thanks for your work.
On 2026-06-11 02:57:29 +0200, Marek Vasut wrote:
> Enable GPU on Salvator-X with R-Car M3-N.
>
> Signed-off-by: Marek Vasut <marek.vasut+renesas@mailbox.org>
For the whole series,
Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
> ---
> Cc: Conor Dooley <conor+dt@kernel.org>
> Cc: David Airlie <airlied@gmail.com>
> Cc: Frank Binns <frank.binns@imgtec.com>
> Cc: Geert Uytterhoeven <geert+renesas@glider.be>
> Cc: Krzysztof Kozlowski <krzk+dt@kernel.org>
> Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
> Cc: Magnus Damm <magnus.damm@gmail.com>
> Cc: Matt Coster <matt.coster@imgtec.com>
> Cc: Maxime Ripard <mripard@kernel.org>
> Cc: "Niklas Söderlund" <niklas.soderlund@ragnatech.se>
> Cc: Rob Herring <robh@kernel.org>
> Cc: Simona Vetter <simona@ffwll.ch>
> Cc: Thomas Zimmermann <tzimmermann@suse.de>
> Cc: devicetree@vger.kernel.org
> Cc: dri-devel@lists.freedesktop.org
> Cc: linux-renesas-soc@vger.kernel.org
> ---
> arch/arm64/boot/dts/renesas/r8a77965-salvator-x.dts | 4 ++++
> 1 file changed, 4 insertions(+)
>
> diff --git a/arch/arm64/boot/dts/renesas/r8a77965-salvator-x.dts b/arch/arm64/boot/dts/renesas/r8a77965-salvator-x.dts
> index f84c64ed4df7b..af8cfdccd2103 100644
> --- a/arch/arm64/boot/dts/renesas/r8a77965-salvator-x.dts
> +++ b/arch/arm64/boot/dts/renesas/r8a77965-salvator-x.dts
> @@ -30,3 +30,7 @@ &du {
> clock-names = "du.0", "du.1", "du.3",
> "dclkin.0", "dclkin.1", "dclkin.3";
> };
> +
> +&gpu {
> + status = "okay";
> +};
> --
> 2.53.0
>
--
Kind Regards,
Niklas Söderlund
^ permalink raw reply
* Re: [PATCH v2 1/7] KVM: arm64: Support FFA_NOTIFICATION_BITMAP_CREATE in host handler
From: Sebastian Ene @ 2026-06-11 9:46 UTC (permalink / raw)
To: Vincent Donnefort
Cc: catalin.marinas, maz, oupton, will, joey.gouly, korneld, kvmarm,
linux-arm-kernel, linux-kernel, android-kvm, mrigendra.chaubey,
perlarsen, suzuki.poulose, yuzenghui
In-Reply-To: <aiklq5QvztNk8FZR@google.com>
On Wed, Jun 10, 2026 at 09:51:55AM +0100, Vincent Donnefort wrote:
> Hi Seb,
>
> On Mon, Jun 08, 2026 at 04:55:43PM +0000, Sebastian Ene wrote:
> > Allow FF-A notification bitmap creation messages to be forwarded to
> > Trustzone from the host and introduce a helper to check for SBZ
> > register fields.
> >
> > Signed-off-by: Sebastian Ene <sebastianene@google.com>
> > ---
> > arch/arm64/kvm/hyp/nvhe/ffa.c | 36 ++++++++++++++++++++++++++++++++++-
> > 1 file changed, 35 insertions(+), 1 deletion(-)
> >
> > diff --git a/arch/arm64/kvm/hyp/nvhe/ffa.c b/arch/arm64/kvm/hyp/nvhe/ffa.c
> > index 1af722771178..c20d45191085 100644
> > --- a/arch/arm64/kvm/hyp/nvhe/ffa.c
> > +++ b/arch/arm64/kvm/hyp/nvhe/ffa.c
> > @@ -71,6 +71,18 @@ static u32 hyp_ffa_version;
> > static bool has_version_negotiated;
> > static hyp_spinlock_t version_lock;
> >
> > +static bool ffa_check_unused_args_sbz(struct kvm_cpu_context *ctxt, int first_reg)
> > +{
> > + int reg;
> > +
> > + for (reg = first_reg; reg < 17; reg++) {
>
> The upper limit should probably be something like ARRAY_SIZE(ctx->regs.regs) - first_reg?
>
The upper limit is 17 since the smc64 uses x1-x17 as arguments and w0 as
a function identifier. ARRAY_SIZE(ctx->regs.regs) is 31
> > + if (cpu_reg(ctxt, reg))
> > + return true;
> > + }
> > +
> > + return false;
> > +}
> > +
> > static void ffa_to_smccc_error(struct arm_smccc_1_2_regs *res, u64 ffa_errno)
> > {
> > *res = (struct arm_smccc_1_2_regs) {
> > @@ -676,7 +688,6 @@ static bool ffa_call_supported(u64 func_id)
> > case FFA_MEM_DONATE:
> > case FFA_MEM_RETRIEVE_REQ:
> > /* Optional notification interfaces added in FF-A 1.1 */
> > - case FFA_NOTIFICATION_BITMAP_CREATE:
> > case FFA_NOTIFICATION_BITMAP_DESTROY:
> > case FFA_NOTIFICATION_BIND:
> > case FFA_NOTIFICATION_UNBIND:
> > @@ -862,6 +873,26 @@ static void do_ffa_part_get(struct arm_smccc_1_2_regs *res,
> > hyp_spin_unlock(&host_buffers.lock);
> > }
> >
> > +static void do_ffa_notif_bitmap_create(struct arm_smccc_1_2_regs *res,
> > + struct kvm_cpu_context *ctxt)
> > +{
> > + DECLARE_REG(u32, vmid, ctxt, 1);
> > + struct arm_smccc_1_2_regs *args;
> > +
> > + if (ffa_check_unused_args_sbz(ctxt, 3)) {
>
> Is that expected we start at 3 but only read 0 and 1?
>
That's what they are saying in the ffa doc (16.1
FFA_NOTIFICATION_BITMAP_CREATE). They use w2 to hold the number of
vcpus, that's why they start at 3.
> > + ffa_to_smccc_res(res, FFA_RET_INVALID_PARAMETERS);
> > + return;
> > + }
> > +
> > + if (vmid != HOST_FFA_ID) {
> > + ffa_to_smccc_res(res, FFA_RET_INVALID_PARAMETERS);
> > + return;
> > + }
> > +
> > + args = (void *)&ctxt->regs.regs[0];
> > + arm_smccc_1_2_smc(args, res);
>
> Should be hyp_smccc_1_2_smc()
>
Yes, replaced it with this.
> > +}
> > +
> > bool kvm_host_ffa_handler(struct kvm_cpu_context *host_ctxt, u32 func_id)
> > {
> > struct arm_smccc_1_2_regs res;
> > @@ -920,6 +951,9 @@ bool kvm_host_ffa_handler(struct kvm_cpu_context *host_ctxt, u32 func_id)
> > case FFA_PARTITION_INFO_GET:
> > do_ffa_part_get(&res, host_ctxt);
> > goto out_handled;
> > + case FFA_NOTIFICATION_BITMAP_CREATE:
> > + do_ffa_notif_bitmap_create(&res, host_ctxt);
> > + goto out_handled;
> > }
> >
> > if (ffa_call_supported(func_id))
> > --
> > 2.54.0.1064.gd145956f57-goog
> >
Thanks,
Sebastian
^ permalink raw reply
* [PATCH v2 1/2] dt-bindings: iio: adc: add Axiado AX3000/AX3005 SARADC
From: Petar Stepanovic @ 2026-06-11 9:37 UTC (permalink / raw)
To: Akhila Kavi, Prasad Bolisetty, Jonathan Cameron, David Lechner,
Nuno Sá, Andy Shevchenko, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Harshit Shah
Cc: linux-iio, devicetree, linux-arm-kernel, linux-kernel,
Petar Stepanovic, Conor Dooley
In-Reply-To: <20260611-axiado-ax3000-ax3005-saradc-v2-0-913c9de7c64c@axiado.com>
The Axiado AX3000 and AX3005 SoCs include a 10-bit SAR ADC controller.
AX3000 supports 16 input channels, while AX3005 supports 8 input
channels.
Document the compatible strings, register region, clock, reference
voltage supply, and IIO channel cells.
Signed-off-by: Petar Stepanovic <pstepanovic@axiado.com>
Acked-by: Conor Dooley <conor.dooley@microchip.com>
---
.../bindings/iio/adc/axiado,ax3000-saradc.yaml | 63 ++++++++++++++++++++++
MAINTAINERS | 7 +++
2 files changed, 70 insertions(+)
diff --git a/Documentation/devicetree/bindings/iio/adc/axiado,ax3000-saradc.yaml b/Documentation/devicetree/bindings/iio/adc/axiado,ax3000-saradc.yaml
new file mode 100644
index 000000000000..b910852aa56f
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/adc/axiado,ax3000-saradc.yaml
@@ -0,0 +1,63 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/adc/axiado,ax3000-saradc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Axiado AX3000/AX3005 Successive Approximation Register ADC
+
+description:
+ The Axiado AX3000/AX3005 SAR ADC is a 10-bit ADC with sixteen input
+ channels on AX3000 and eight input channels on AX3005.
+
+maintainers:
+ - Petar Stepanovic <pstepanovic@axiado.com>
+ - Akhila Kavi <akavi@axiado.com>
+ - Prasad Bolisetty <pbolisetty@axiado.com>
+
+properties:
+ compatible:
+ enum:
+ - axiado,ax3000-saradc
+ - axiado,ax3005-saradc
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ maxItems: 1
+
+ clock-names:
+ const: saradc
+
+ '#io-channel-cells':
+ const: 1
+
+ vref-supply:
+ description: Reference voltage regulator supplying the ADC
+
+required:
+ - compatible
+ - reg
+ - clocks
+ - clock-names
+ - '#io-channel-cells'
+ - vref-supply
+
+additionalProperties: false
+
+examples:
+ - |
+ soc {
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ adc@806a0000 {
+ compatible = "axiado,ax3000-saradc";
+ reg = <0x0 0x806a0000 0x0 0x400>;
+ clocks = <&pclk>;
+ clock-names = "saradc";
+ vref-supply = <&vref_reg>;
+ #io-channel-cells = <1>;
+ };
+ };
diff --git a/MAINTAINERS b/MAINTAINERS
index b2040011a386..932bba890780 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4312,6 +4312,13 @@ S: Orphan
F: Documentation/devicetree/bindings/sound/axentia,*
F: sound/soc/atmel/tse850-pcm5142.c
+AXIADO SARADC DRIVER
+M: Petar Stepanovic <pstepanovic@axiado.com>
+M: Akhila Kavi <akavi@axiado.com>
+M: Prasad Bolisetty <pbolisetty@axiado.com>
+S: Maintained
+F: Documentation/devicetree/bindings/iio/adc/axiado,ax3000-saradc.yaml
+
AXIS ARTPEC ARM64 SoC SUPPORT
M: Jesper Nilsson <jesper.nilsson@axis.com>
M: Lars Persson <lars.persson@axis.com>
--
2.34.1
^ permalink raw reply related
* [PATCH v2 2/2] iio: adc: add Axiado SARADC driver
From: Petar Stepanovic @ 2026-06-11 9:37 UTC (permalink / raw)
To: Akhila Kavi, Prasad Bolisetty, Jonathan Cameron, David Lechner,
Nuno Sá, Andy Shevchenko, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Harshit Shah
Cc: linux-iio, devicetree, linux-arm-kernel, linux-kernel,
Petar Stepanovic
In-Reply-To: <20260611-axiado-ax3000-ax3005-saradc-v2-0-913c9de7c64c@axiado.com>
Add support for the SARADC controller found on Axiado AX3000 and
AX3005 SoCs.
The driver supports single-shot voltage reads through the IIO
subsystem. The number of available input channels is selected from
the SoC match data, allowing AX3000 and AX3005 variants to use the
same driver.
Signed-off-by: Petar Stepanovic <pstepanovic@axiado.com>
---
MAINTAINERS | 1 +
drivers/iio/adc/Kconfig | 10 ++
drivers/iio/adc/Makefile | 1 +
drivers/iio/adc/axiado_saradc.c | 244 ++++++++++++++++++++++++++++++++++++++++
4 files changed, 256 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 932bba890780..e6dadfa65ee0 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4318,6 +4318,7 @@ M: Akhila Kavi <akavi@axiado.com>
M: Prasad Bolisetty <pbolisetty@axiado.com>
S: Maintained
F: Documentation/devicetree/bindings/iio/adc/axiado,ax3000-saradc.yaml
+F: drivers/iio/adc/axiado_saradc.c
AXIS ARTPEC ARM64 SoC SUPPORT
M: Jesper Nilsson <jesper.nilsson@axis.com>
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index a9dedbb8eb46..a9ba600a5f64 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -631,6 +631,16 @@ config AT91_SAMA5D2_ADC
To compile this driver as a module, choose M here: the module will be
called at91-sama5d2_adc.
+config AXIADO_SARADC
+ tristate "Axiado SARADC driver"
+ depends on ARCH_AXIADO || COMPILE_TEST
+ help
+ Say yes here to build support for the SARADC found in Axiado
+ SoCs.
+
+ To compile this driver as a module, choose M here: the module
+ will be called axiado_saradc.
+
config AXP20X_ADC
tristate "X-Powers AXP20X and AXP22X ADC driver"
depends on MFD_AXP20X
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
index 097357d146ba..96de0ce1d90a 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -54,6 +54,7 @@ obj-$(CONFIG_ADI_AXI_ADC) += adi-axi-adc.o
obj-$(CONFIG_ASPEED_ADC) += aspeed_adc.o
obj-$(CONFIG_AT91_ADC) += at91_adc.o
obj-$(CONFIG_AT91_SAMA5D2_ADC) += at91-sama5d2_adc.o
+obj-$(CONFIG_AXIADO_SARADC) += axiado_saradc.o
obj-$(CONFIG_AXP20X_ADC) += axp20x_adc.o
obj-$(CONFIG_AXP288_ADC) += axp288_adc.o
obj-$(CONFIG_BCM_IPROC_ADC) += bcm_iproc_adc.o
diff --git a/drivers/iio/adc/axiado_saradc.c b/drivers/iio/adc/axiado_saradc.c
new file mode 100644
index 000000000000..d2f4071c932c
--- /dev/null
+++ b/drivers/iio/adc/axiado_saradc.c
@@ -0,0 +1,244 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2021-2026 Axiado Corporation
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/clk.h>
+#include <linux/cleanup.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/regulator/consumer.h>
+
+#include <linux/iio/iio.h>
+
+/* Register offsets */
+#define AX_SARADC_GLOBAL_CTRL_REG 0x0004
+#define AX_SARADC_MANUAL_CTRL_REG 0x0008
+#define AX_SARADC_DOUT_REG 0x001C
+
+/* GLOBAL_CTRL register fields */
+#define AX_SARADC_GLOBAL_CTRL_CH_EN_MASK GENMASK(31, 16)
+#define AX_SARADC_GLOBAL_CTRL_SAMPLE_MASK GENMASK(6, 5)
+#define AX_SARADC_GLOBAL_CTRL_MODE_MASK GENMASK(4, 3)
+#define AX_SARADC_GLOBAL_CTRL_PD BIT(2)
+#define AX_SARADC_GLOBAL_CTRL_ENABLE BIT(0)
+
+/* GLOBAL_CTRL register values */
+#define AX_SARADC_GLOBAL_CTRL_SAMPLE_16 \
+ FIELD_PREP(AX_SARADC_GLOBAL_CTRL_SAMPLE_MASK, 0)
+
+#define AX_SARADC_GLOBAL_CTRL_MODE_MANUAL \
+ FIELD_PREP(AX_SARADC_GLOBAL_CTRL_MODE_MASK, 1)
+
+/* MANUAL_CTRL register fields */
+#define AX_SARADC_MANUAL_CTRL_ENABLE BIT(0)
+#define AX_SARADC_MANUAL_CTRL_CH_SEL_MASK GENMASK(4, 1)
+
+#define AX_SARADC_MANUAL_CTRL_EN(ch) \
+ (AX_SARADC_MANUAL_CTRL_ENABLE | \
+ FIELD_PREP(AX_SARADC_MANUAL_CTRL_CH_SEL_MASK, ch))
+
+#define AX_RESOLUTION_BITS 10
+#define AX_SARADC_CONV_CYCLES 13
+#define AX_SARADC_CONV_DELAY_MARGIN_US 10
+
+struct axiado_saradc {
+ void __iomem *regs;
+ struct clk *clk;
+ unsigned long clk_rate;
+ int vref_uV;
+ struct mutex lock; /* Serializes ADC conversions. */
+};
+
+static int axiado_saradc_conversion(struct axiado_saradc *info,
+ struct iio_chan_spec const *chan, int *val)
+{
+ unsigned long usecs;
+
+ guard(mutex)(&info->lock);
+
+ /* Select the channel to be used and trigger conversion */
+ writel(AX_SARADC_MANUAL_CTRL_EN(chan->channel),
+ info->regs + AX_SARADC_MANUAL_CTRL_REG);
+
+ /* Hardware requires 13 conversion cycles at clk_rate */
+ usecs = DIV_ROUND_UP(AX_SARADC_CONV_CYCLES * USEC_PER_SEC,
+ info->clk_rate);
+ fsleep(usecs + AX_SARADC_CONV_DELAY_MARGIN_US);
+
+ *val = readl(info->regs + AX_SARADC_DOUT_REG) &
+ GENMASK(AX_RESOLUTION_BITS - 1, 0);
+
+ /* Stop manual conversion */
+ writel(0, info->regs + AX_SARADC_MANUAL_CTRL_REG);
+
+ return 0;
+}
+
+static int axiado_saradc_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int *val,
+ int *val2, long mask)
+{
+ struct axiado_saradc *info = iio_priv(indio_dev);
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ ret = axiado_saradc_conversion(info, chan, val);
+ return ret ? ret : IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ *val = info->vref_uV / 1000;
+ *val2 = AX_RESOLUTION_BITS;
+ return IIO_VAL_FRACTIONAL_LOG2;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct iio_info axiado_saradc_iio_info = {
+ .read_raw = axiado_saradc_read_raw,
+};
+
+struct axiado_saradc_soc_data {
+ const char *name;
+ unsigned int num_channels;
+};
+
+static const struct axiado_saradc_soc_data ax3000_saradc_data = {
+ .name = "ax3000_saradc",
+ .num_channels = 16,
+};
+
+static const struct axiado_saradc_soc_data ax3005_saradc_data = {
+ .name = "ax3005_saradc",
+ .num_channels = 8,
+};
+
+#define AX_SARADC_CH(_index, _id) \
+ { \
+ .type = IIO_VOLTAGE, \
+ .indexed = 1, \
+ .channel = (_index), \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
+ .datasheet_name = (_id), \
+ }
+
+static const struct iio_chan_spec axiado_saradc_iio_channels[] = {
+ AX_SARADC_CH(0, "adc0"), AX_SARADC_CH(1, "adc1"),
+ AX_SARADC_CH(2, "adc2"), AX_SARADC_CH(3, "adc3"),
+ AX_SARADC_CH(4, "adc4"), AX_SARADC_CH(5, "adc5"),
+ AX_SARADC_CH(6, "adc6"), AX_SARADC_CH(7, "adc7"),
+ AX_SARADC_CH(8, "adc8"), AX_SARADC_CH(9, "adc9"),
+ AX_SARADC_CH(10, "adc10"), AX_SARADC_CH(11, "adc11"),
+ AX_SARADC_CH(12, "adc12"), AX_SARADC_CH(13, "adc13"),
+ AX_SARADC_CH(14, "adc14"), AX_SARADC_CH(15, "adc15"),
+};
+
+static void axiado_saradc_disable(void *data)
+{
+ struct axiado_saradc *info = data;
+
+ writel(AX_SARADC_GLOBAL_CTRL_PD,
+ info->regs + AX_SARADC_GLOBAL_CTRL_REG);
+}
+
+static int axiado_saradc_probe(struct platform_device *pdev)
+{
+ const struct axiado_saradc_soc_data *soc_data;
+ struct device *dev = &pdev->dev;
+ struct axiado_saradc *info;
+ struct iio_dev *indio_dev;
+ u32 regval;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*info));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ info = iio_priv(indio_dev);
+
+ info->regs = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(info->regs))
+ return PTR_ERR(info->regs);
+
+ info->clk = devm_clk_get_enabled(dev, NULL);
+ if (IS_ERR(info->clk))
+ return PTR_ERR(info->clk);
+
+ info->clk_rate = clk_get_rate(info->clk);
+ if (!info->clk_rate)
+ return dev_err_probe(dev, -EINVAL, "invalid clock rate\n");
+
+ info->vref_uV = devm_regulator_get_enable_read_voltage(dev, "vref");
+ if (info->vref_uV < 0)
+ return dev_err_probe(dev, info->vref_uV,
+ "failed to get vref voltage\n");
+
+ soc_data = device_get_match_data(dev);
+ if (!soc_data)
+ return dev_err_probe(dev, -EINVAL, "failed to get match data\n");
+
+ ret = devm_mutex_init(dev, &info->lock);
+ if (ret)
+ return ret;
+
+ regval = FIELD_PREP(AX_SARADC_GLOBAL_CTRL_CH_EN_MASK,
+ GENMASK(soc_data->num_channels - 1, 0)) |
+ AX_SARADC_GLOBAL_CTRL_SAMPLE_16 |
+ AX_SARADC_GLOBAL_CTRL_MODE_MANUAL |
+ AX_SARADC_GLOBAL_CTRL_ENABLE;
+
+ writel(AX_SARADC_GLOBAL_CTRL_PD,
+ info->regs + AX_SARADC_GLOBAL_CTRL_REG);
+ writel(regval, info->regs + AX_SARADC_GLOBAL_CTRL_REG);
+
+ ret = devm_add_action_or_reset(dev, axiado_saradc_disable, info);
+ if (ret)
+ return ret;
+
+ indio_dev->name = soc_data->name;
+ indio_dev->info = &axiado_saradc_iio_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = axiado_saradc_iio_channels;
+ indio_dev->num_channels = soc_data->num_channels;
+
+ return devm_iio_device_register(dev, indio_dev);
+}
+
+static const struct of_device_id axiado_saradc_match[] = {
+ {
+ .compatible = "axiado,ax3000-saradc",
+ .data = &ax3000_saradc_data,
+ },
+ {
+ .compatible = "axiado,ax3005-saradc",
+ .data = &ax3005_saradc_data,
+ },
+ { }
+};
+MODULE_DEVICE_TABLE(of, axiado_saradc_match);
+
+static struct platform_driver axiado_saradc_driver = {
+ .driver = {
+ .name = "axiado-saradc",
+ .of_match_table = axiado_saradc_match,
+ },
+ .probe = axiado_saradc_probe,
+};
+
+module_platform_driver(axiado_saradc_driver);
+
+MODULE_AUTHOR("AXIADO CORPORATION");
+MODULE_DESCRIPTION("AXIADO SARADC driver");
+MODULE_LICENSE("GPL");
--
2.34.1
^ permalink raw reply related
* [PATCH v2 0/2] iio: adc: Add Axiado SARADC driver
From: Petar Stepanovic @ 2026-06-11 9:37 UTC (permalink / raw)
To: Akhila Kavi, Prasad Bolisetty, Jonathan Cameron, David Lechner,
Nuno Sá, Andy Shevchenko, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Harshit Shah
Cc: linux-iio, devicetree, linux-arm-kernel, linux-kernel,
Petar Stepanovic, Conor Dooley
This series adds support for the SAR ADC controller found on Axiado
AX3000 and AX3005 SoCs.
A new driver is needed because this SAR ADC controller is a SoC-specific
hardware block used on Axiado SoCs. It has its own register layout,
channel enable handling, conversion control, and data readout sequence,
and it does not match any existing upstream IIO ADC driver.
AX3000 provides sixteen input channels, while AX3005 provides eight
input channels. The driver uses SoC match data to select the number of
available channels for each compatible.
The driver supports single-shot voltage reads through the IIO subsystem
and uses the reference voltage regulator for scale calculation.
The datasheet is not publicly available. Public high-level product
information is available at:
https://axiado.com/products/#AX3080
The register definitions and programming sequence used by this driver
are based on Axiado internal SoC documentation.
Signed-off-by: Petar Stepanovic <pstepanovic@axiado.com>
---
Changes in v2:
- Fixed the devicetree example node name to use the generic ADC node name.
- Removed the explicit `depends on OF` from Kconfig.
- Cleaned up and reordered header includes.
- Added missing includes for `bits.h`, `clk.h`, `cleanup.h`, and `err.h`.
- Removed unused `linux/kernel.h` include.
- Renamed register offset macros to use the `_REG` suffix.
- Renamed register bitfield macros to include the register name prefix.
- Added separate macros for `GLOBAL_CTRL` and `MANUAL_CTRL` register
fields and values.
- Replaced `iowrite32()` / `ioread32()` with `writel()` / `readl()`.
- Moved ADC conversion locking into `axiado_saradc_conversion()` using
`guard(mutex)`.
- Replaced `usleep_range()` with `fsleep()`.
- Renamed `vref_uv` to `vref_uV`.
- Added SoC-specific device names in `axiado_saradc_soc_data`.
- Used the fixed SoC-specific name for `indio_dev->name`.
- Removed unused buffered scan configuration from IIO channels.
- Added a managed cleanup action to disable the SARADC hardware on driver
unbind or probe failure.
- Switched to a local `struct device *dev` helper in probe.
- Used `devm_mutex_init()` for mutex initialization.
- Simplified error handling by using `dev_err_probe()`.
- Updated probe variable declarations to follow reverse Christmas tree
order.
- Fixed the `of_device_id` terminator style.
- Replaced `KBUILD_MODNAME` with a fixed driver name string.
- Link to v1: https://lore.kernel.org/r/20260528-axiado-ax3000-ax3005-saradc-v1-0-345dd5f6608a@axiado.com
---
Petar Stepanovic (2):
dt-bindings: iio: adc: add Axiado AX3000/AX3005 SARADC
iio: adc: add Axiado SARADC driver
.../bindings/iio/adc/axiado,ax3000-saradc.yaml | 63 ++++++
MAINTAINERS | 8 +
drivers/iio/adc/Kconfig | 10 +
drivers/iio/adc/Makefile | 1 +
drivers/iio/adc/axiado_saradc.c | 244 +++++++++++++++++++++
5 files changed, 326 insertions(+)
---
base-commit: 51f0c0b8545b23963afd5d43a8f56ee05bfa54da
change-id: 20260508-axiado-ax3000-ax3005-saradc-151aed5d25da
Best regards,
--
Petar Stepanovic <pstepanovic@axiado.com>
^ permalink raw reply
* Re: [PATCH v2 05/16] usb: hub: Associate port@ fwnode with USB port device
From: Bartosz Golaszewski @ 2026-06-11 9:35 UTC (permalink / raw)
To: Andy Shevchenko
Cc: Greg Kroah-Hartman, Daniel Scally, Heikki Krogerus, Sakari Ailus,
Rafael J. Wysocki, Danilo Krummrich, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
AngeloGioacchino Del Regno, Alan Stern, linux-acpi, driver-core,
linux-pm, linux-usb, devicetree, linux-mediatek, linux-arm-kernel,
linux-kernel, Manivannan Sadhasivam, Chen-Yu Tsai
In-Reply-To: <aipz2zMFcdnZYTxS@ashevche-desk.local>
On Thu, Jun 11, 2026 at 10:37 AM Andy Shevchenko
<andriy.shevchenko@linux.intel.com> wrote:
>
> On Thu, Jun 11, 2026 at 04:20:58AM -0400, Bartosz Golaszewski wrote:
> > On Wed, 10 Jun 2026 16:16:12 +0200, Andy Shevchenko
> > <andriy.shevchenko@linux.intel.com> said:
> > > On Wed, Jun 10, 2026 at 04:40:39PM +0800, Chen-Yu Tsai wrote:
> > >> When a USB hub port is connected to a connector in a firmware node
> > >> graph, the port itself has a node in the graph.
> > >>
> > >> Associate the port's firmware node with the USB port's device,
> > >> usb_port::dev. This is used in later changes for the M.2 slot power
> > >> sequencing provider to match against the requesting port.
> > >
> > > Okay, would this affect ACPI-based systems? if so, how?
> > > Can you elaborate on that, please?
> >
> > Is it possible that there's an ACPI device node associated with the port like
> > on some DT systems? I don't think so and there should be no impact IMO but I
> > also don't know enough about ACPI.
>
> The API is agnostic. There is a possibility to have software nodes associated
> with the port. I think the best is to be sure that ACPI-aware people who are
> experts in USB will check this (Heikki?).
>
Even if there is a software node - it shouldn't really matter. It will
just be assigned to the port device.
Bart
> Also note Sashiko complain on reference count leakage.
>
> --
> With Best Regards,
> Andy Shevchenko
>
>
^ permalink raw reply
* Re: [PATCH v2 3/7] KVM: arm64: Support FFA_NOTIFICATION_BIND in host handler
From: Sebastian Ene @ 2026-06-11 9:30 UTC (permalink / raw)
To: Vincent Donnefort
Cc: catalin.marinas, maz, oupton, will, joey.gouly, korneld, kvmarm,
linux-arm-kernel, linux-kernel, android-kvm, mrigendra.chaubey,
perlarsen, suzuki.poulose, yuzenghui
In-Reply-To: <aikobxnyWj_G2iPT@google.com>
On Wed, Jun 10, 2026 at 10:03:43AM +0100, Vincent Donnefort wrote:
> On Mon, Jun 08, 2026 at 04:55:45PM +0000, Sebastian Ene wrote:
> > Verify the arguments of the FF-A notification bind call and forward the
> > message to Trustzone.
> >
> > Signed-off-by: Sebastian Ene <sebastianene@google.com>
> > ---
> > arch/arm64/kvm/hyp/nvhe/ffa.c | 32 +++++++++++++++++++++++++++++++-
> > 1 file changed, 31 insertions(+), 1 deletion(-)
> >
> > diff --git a/arch/arm64/kvm/hyp/nvhe/ffa.c b/arch/arm64/kvm/hyp/nvhe/ffa.c
> > index 91e89d889c44..eedb01955a45 100644
> > --- a/arch/arm64/kvm/hyp/nvhe/ffa.c
> > +++ b/arch/arm64/kvm/hyp/nvhe/ffa.c
> > @@ -42,6 +42,8 @@
> > */
> > #define HOST_FFA_ID 0
> >
> > +#define FFA_NOTIF_SENDER_ENDP_MASK GENMASK(31, 16)
>
> Could we move the MASK definitions form arm_ffa to include/linux/arm_ffa.h?
>
I wanted to keep it here since it is not used anywhere else other than
this file.
> > +
> > /*
> > * A buffer to hold the maximum descriptor size we can see from the host,
> > * which is required when the SPMD returns a fragmented FFA_MEM_RETRIEVE_RESP
> > @@ -688,7 +690,6 @@ static bool ffa_call_supported(u64 func_id)
> > case FFA_MEM_DONATE:
> > case FFA_MEM_RETRIEVE_REQ:
> > /* Optional notification interfaces added in FF-A 1.1 */
> > - case FFA_NOTIFICATION_BIND:
> > case FFA_NOTIFICATION_UNBIND:
> > case FFA_NOTIFICATION_SET:
> > case FFA_NOTIFICATION_GET:
> > @@ -912,6 +913,32 @@ static void do_ffa_notif_bitmap_destroy(struct arm_smccc_1_2_regs *res,
> > arm_smccc_1_2_smc(args, res);
> > }
> >
> > +static void do_ffa_notif_bind(struct arm_smccc_1_2_regs *res,
> > + struct kvm_cpu_context *ctxt)
> > +{
> > + DECLARE_REG(u32, endp_id, ctxt, 1);
> > + DECLARE_REG(u32, flags, ctxt, 2);
> > + struct arm_smccc_1_2_regs *args;
> > +
> > + if (ffa_check_unused_args_sbz(ctxt, 5)) {
> > + ffa_to_smccc_res(res, FFA_RET_INVALID_PARAMETERS);
> > + return;
> > + }
> > +
> > + if (FIELD_GET(FFA_NOTIF_SENDER_ENDP_MASK, endp_id) != HOST_FFA_ID) {
> > + ffa_to_smccc_res(res, FFA_RET_INVALID_PARAMETERS);
> > + return;
> > + }
> > +
> > + if (flags & GENMASK(31, 1)) {
> > + ffa_to_smccc_res(res, FFA_RET_INVALID_PARAMETERS);
> > + return;
> > + }
>
> if (flags > 1) ?
>
sure, I can replace it with this.
> > +
> > + args = (void *)&ctxt->regs.regs[0];
> > + arm_smccc_1_2_smc(args, res);
>
> And of course just like all the other functions, it should use
> the hyp_ prefix.
>
Added this.
> > +}
> > +
> > bool kvm_host_ffa_handler(struct kvm_cpu_context *host_ctxt, u32 func_id)
> > {
> > struct arm_smccc_1_2_regs res;
> > @@ -976,6 +1003,9 @@ bool kvm_host_ffa_handler(struct kvm_cpu_context *host_ctxt, u32 func_id)
> > case FFA_NOTIFICATION_BITMAP_DESTROY:
> > do_ffa_notif_bitmap_destroy(&res, host_ctxt);
> > goto out_handled;
> > + case FFA_NOTIFICATION_BIND:
> > + do_ffa_notif_bind(&res, host_ctxt);
> > + goto out_handled;
> > }
> >
> > if (ffa_call_supported(func_id))
> > --
> > 2.54.0.1064.gd145956f57-goog
> >
Thanks,
Sebastian
^ permalink raw reply
* Re: [PATCH 0/2] gpio: fix sleeping-in-atomic in shared-proxy; restore meson non-sleeping
From: Viacheslav @ 2026-06-11 9:27 UTC (permalink / raw)
To: Marek Szyprowski, Linus Walleij, Bartosz Golaszewski
Cc: Neil Armstrong, Kevin Hilman, Jerome Brunet, Martin Blumenstingl,
Robin Murphy, Diederik de Haas, linux-gpio, linux-arm-kernel,
linux-amlogic, linux-kernel, linux-rockchip, Heiko Stuebner
In-Reply-To: <184d315b-a0a1-4792-8a40-1b4967025916@samsung.com>
Hi, Marek!
11.06.2026 11:26, Marek Szyprowski wrote:
> Hi Viachesla,
>
> On 10.06.2026 17:32, Viacheslav Bocharov wrote:
>
> Tested-by: Marek Szyprowski <m.szyprowski@samsung.com>
>
Thanks for testing.
> This probably also affects the similar changes in Rockchip GPIO driver done
> by the following commits:
> 20cf2aed89ac ("gpio: rockchip: mark the GPIO controller as sleeping")
> 7ca497be0016 ("gpio: rockchip: Stop calling pinctrl for set_direction")
>
Yeah, we also need to revert can_sleep=true on rockchip and amlogic-a4
(d6df4abe95a4).
Best regards
--
Viacheslav Bocharov
Shenzhen JetHome Technology Co., Ltd.
^ permalink raw reply
* [PATCH] media: raspberrypi: cfe: Enable video capture on CSI2_CH1
From: Tomi Valkeinen @ 2026-06-11 9:15 UTC (permalink / raw)
To: Raspberry Pi Kernel Maintenance, Mauro Carvalho Chehab,
Florian Fainelli, Broadcom internal kernel review list,
Dave Stevenson, Naushir Patuck
Cc: Sakari Ailus, linux-media, linux-rpi-kernel, linux-arm-kernel,
linux-kernel, Tomi Valkeinen
The upstreamed CFE driver did not enable video capture on the second
DMA channel, only metadata capture, to imitate the downstream
Raspberry Pi kernel.
Let's drop this limitation and also support video streams.
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
---
drivers/media/platform/raspberrypi/rp1-cfe/cfe.c | 8 +-------
1 file changed, 1 insertion(+), 7 deletions(-)
diff --git a/drivers/media/platform/raspberrypi/rp1-cfe/cfe.c b/drivers/media/platform/raspberrypi/rp1-cfe/cfe.c
index 8375ed3e97b9..40eef608504d 100644
--- a/drivers/media/platform/raspberrypi/rp1-cfe/cfe.c
+++ b/drivers/media/platform/raspberrypi/rp1-cfe/cfe.c
@@ -130,15 +130,9 @@ static const struct node_description node_desc[NUM_NODES] = {
.pad_flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT,
.link_pad = CSI2_PAD_FIRST_SOURCE + 0
},
- /*
- * At the moment the main userspace component (libcamera) doesn't
- * support metadata with video nodes that support both video and
- * metadata. So for the time being this node is set to only support
- * V4L2_CAP_META_CAPTURE.
- */
[CSI2_CH1] = {
.name = "csi2-ch1",
- .caps = V4L2_CAP_META_CAPTURE,
+ .caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_META_CAPTURE,
.pad_flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT,
.link_pad = CSI2_PAD_FIRST_SOURCE + 1
},
---
base-commit: 06cb687a5132fcffe624c0070576ab852ac6b568
change-id: 20260611-cfe-ch1-video-0116fb7151ba
Best regards,
--
Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
^ permalink raw reply related
* [PATCH v3 2/2] spi: ma35d1-qspi: Add Nuvoton MA35D1 QSPI controller support
From: Chi-Wen Weng @ 2026-06-11 9:12 UTC (permalink / raw)
To: broonie, robh, krzk+dt, conor+dt
Cc: linux-arm-kernel, linux-spi, devicetree, linux-kernel, cwweng,
cwweng.linux
In-Reply-To: <20260611091246.2070485-1-cwweng.linux@gmail.com>
From: Chi-Wen Weng <cwweng@nuvoton.com>
Add SPI controller driver support for the Nuvoton MA35D1 Quad SPI
controller.
The controller supports standard SPI transfers and spi-mem operations
for SPI memory devices such as SPI NOR and SPI NAND flashes. The driver
supports single, dual and quad I/O modes and uses a conservative
word-by-word PIO transfer path for the initial upstream version.
The driver also handles controller reset, clock divider programming,
chip-select control, transfer mode setup and spi-mem command/address/
dummy/data phases.
Signed-off-by: Chi-Wen Weng <cwweng@nuvoton.com>
---
drivers/spi/Kconfig | 10 +
drivers/spi/Makefile | 1 +
drivers/spi/spi-ma35d1-qspi.c | 633 ++++++++++++++++++++++++++++++++++
3 files changed, 644 insertions(+)
create mode 100644 drivers/spi/spi-ma35d1-qspi.c
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index b563f49e2197..8b8297ee3f2e 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -694,6 +694,16 @@ config SPI_LJCA
This driver can also be built as a module. If so, the module
will be called spi-ljca.
+config SPI_MA35D1_QSPI
+ tristate "Nuvoton MA35D1 QSPI controller"
+ depends on ARCH_MA35 || COMPILE_TEST
+ help
+ This enables support for the Quad SPI controller found in
+ Nuvoton MA35D1 SoCs.
+
+ The controller supports SPI memory devices such as SPI NOR and
+ SPI NAND flashes in single, dual and quad I/O modes.
+
config SPI_MESON_SPICC
tristate "Amlogic Meson SPICC controller"
depends on COMMON_CLK
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 9d36190a9884..c5bb0efd108c 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -85,6 +85,7 @@ obj-$(CONFIG_SPI_LOONGSON_CORE) += spi-loongson-core.o
obj-$(CONFIG_SPI_LOONGSON_PCI) += spi-loongson-pci.o
obj-$(CONFIG_SPI_LOONGSON_PLATFORM) += spi-loongson-plat.o
obj-$(CONFIG_SPI_LP8841_RTC) += spi-lp8841-rtc.o
+obj-$(CONFIG_SPI_MA35D1_QSPI) += spi-ma35d1-qspi.o
obj-$(CONFIG_SPI_MESON_SPICC) += spi-meson-spicc.o
obj-$(CONFIG_SPI_MESON_SPIFC) += spi-meson-spifc.o
obj-$(CONFIG_SPI_MICROCHIP_CORE_QSPI) += spi-microchip-core-qspi.o
diff --git a/drivers/spi/spi-ma35d1-qspi.c b/drivers/spi/spi-ma35d1-qspi.c
new file mode 100644
index 000000000000..d3e687b6a06d
--- /dev/null
+++ b/drivers/spi/spi-ma35d1-qspi.c
@@ -0,0 +1,633 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+//
+// Nuvoton MA35D1 QSPI controller driver
+//
+// Copyright (c) 2026 Nuvoton Technology Corp.
+// Author: Chi-Wen Weng <cwweng@nuvoton.com>
+
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/spi-mem.h>
+
+/* Register offset definitions */
+#define NUVOTON_QSPI_CTL_OFFSET 0x00 /* Control Register, RW */
+#define NUVOTON_QSPI_CLKDIV_OFFSET 0x04 /* Clock Divider Register, RW */
+#define NUVOTON_QSPI_SSCTL_OFFSET 0x08 /* Slave Select Register, RW */
+#define NUVOTON_QSPI_FIFOCTL_OFFSET 0x10 /* FIFO Control Register, RW */
+#define NUVOTON_QSPI_STATUS_OFFSET 0x14 /* Status Register, RW */
+#define NUVOTON_QSPI_TX_OFFSET 0x20 /* Data Transmit Register, WO */
+#define NUVOTON_QSPI_RX_OFFSET 0x30 /* Data Receive Register, RO */
+
+/* QSPI Control Register bit masks */
+#define NUVOTON_QSPI_CTL_QUADIOEN_MASK BIT(22) /* Quad I/O Mode Enable */
+#define NUVOTON_QSPI_CTL_DUALIOEN_MASK BIT(21) /* Dual I/O Mode Enable */
+#define NUVOTON_QSPI_CTL_DATDIR_MASK BIT(20) /* Data Port Direction Control */
+#define NUVOTON_QSPI_CTL_REORDER_MASK BIT(19) /* Byte Reorder Function Enable */
+#define NUVOTON_QSPI_CTL_LSB_MASK BIT(13) /* Send LSB First */
+#define NUVOTON_QSPI_CTL_DWIDTH_MASK GENMASK(12, 8) /* Data Width */
+#define NUVOTON_QSPI_CTL_SUSPITV_MASK GENMASK(7, 4) /* Suspend Interval */
+#define NUVOTON_QSPI_CTL_CLKPOL_MASK BIT(3) /* Clock Polarity */
+#define NUVOTON_QSPI_CTL_TXNEG_MASK BIT(2) /* Transmit on Negative Edge */
+#define NUVOTON_QSPI_CTL_RXNEG_MASK BIT(1) /* Receive on Negative Edge */
+#define NUVOTON_QSPI_CTL_SPIEN_MASK BIT(0) /* QSPI Transfer Control Enable */
+
+/* QSPI Clock Divider Register bit masks */
+#define NUVOTON_QSPI_CLKDIV_MASK GENMASK(8, 0) /* Clock Divider */
+
+/* QSPI Slave Select Control Register bit masks */
+#define NUVOTON_QSPI_SSCTL_SS1_MASK BIT(1) /* Slave Selection 1 Control */
+#define NUVOTON_QSPI_SSCTL_SS0_MASK BIT(0) /* Slave Selection 0 Control */
+
+/* QSPI FIFO Control Register bit masks */
+#define NUVOTON_QSPI_FIFOCTL_TXRST_MASK BIT(1) /* Transmit Reset */
+#define NUVOTON_QSPI_FIFOCTL_RXRST_MASK BIT(0) /* Receive Reset */
+
+/* QSPI Status Register bit masks */
+#define NUVOTON_QSPI_STATUS_TXRXRST_MASK BIT(23) /* TX or RX Reset Status */
+#define NUVOTON_QSPI_STATUS_TXFULL_MASK BIT(17) /* Transmit FIFO Full */
+#define NUVOTON_QSPI_STATUS_SPIENSTS_MASK BIT(15) /* QSPI Enable Status */
+#define NUVOTON_QSPI_STATUS_RXEMPTY_MASK BIT(8) /* Receive FIFO Empty */
+#define NUVOTON_QSPI_STATUS_BUSY_MASK BIT(0) /* Busy Status */
+
+#define NUVOTON_QSPI_DEFAULT_NUM_CS 2
+#define NUVOTON_QSPI_DEFAULT_BPW 8
+#define NUVOTON_QSPI_TIMEOUT_US 10000
+
+struct nuvoton_qspi {
+ void __iomem *regs;
+ struct clk *clk;
+ struct device *dev;
+ u32 speed_hz;
+ u8 bits_per_word;
+};
+
+static u32 nuvoton_qspi_read(struct nuvoton_qspi *qspi, u32 reg)
+{
+ return readl(qspi->regs + reg);
+}
+
+static void nuvoton_qspi_write(struct nuvoton_qspi *qspi, u32 val, u32 reg)
+{
+ writel(val, qspi->regs + reg);
+}
+
+static void nuvoton_qspi_update_bits(struct nuvoton_qspi *qspi, u32 reg,
+ u32 mask, u32 val)
+{
+ u32 tmp;
+
+ tmp = nuvoton_qspi_read(qspi, reg);
+ tmp &= ~mask;
+ tmp |= val & mask;
+ nuvoton_qspi_write(qspi, tmp, reg);
+}
+
+static int nuvoton_qspi_wait_ready(struct nuvoton_qspi *qspi)
+{
+ u32 val;
+
+ return readl_poll_timeout(qspi->regs + NUVOTON_QSPI_STATUS_OFFSET,
+ val,
+ !(val & NUVOTON_QSPI_STATUS_BUSY_MASK),
+ 0, NUVOTON_QSPI_TIMEOUT_US);
+}
+
+static int nuvoton_qspi_reset_fifo(struct nuvoton_qspi *qspi)
+{
+ u32 val;
+
+ val = nuvoton_qspi_read(qspi, NUVOTON_QSPI_FIFOCTL_OFFSET);
+ val |= NUVOTON_QSPI_FIFOCTL_TXRST_MASK |
+ NUVOTON_QSPI_FIFOCTL_RXRST_MASK;
+ nuvoton_qspi_write(qspi, val, NUVOTON_QSPI_FIFOCTL_OFFSET);
+
+ /*
+ * Give the controller a short time to latch the FIFO reset request
+ * before polling the reset status bit.
+ */
+ udelay(1);
+
+ return readl_poll_timeout_atomic(qspi->regs + NUVOTON_QSPI_STATUS_OFFSET,
+ val,
+ !(val & NUVOTON_QSPI_STATUS_TXRXRST_MASK),
+ 1, NUVOTON_QSPI_TIMEOUT_US);
+}
+
+static int nuvoton_qspi_set_speed(struct nuvoton_qspi *qspi, u32 speed_hz)
+{
+ unsigned long clk_rate;
+ u32 div;
+
+ if (!speed_hz)
+ return -EINVAL;
+
+ if (qspi->speed_hz == speed_hz)
+ return 0;
+
+ clk_rate = clk_get_rate(qspi->clk);
+ if (!clk_rate) {
+ dev_err(qspi->dev, "failed to get clock rate\n");
+ return -EINVAL;
+ }
+
+ div = DIV_ROUND_UP(clk_rate, speed_hz) - 1;
+ if (div > FIELD_MAX(NUVOTON_QSPI_CLKDIV_MASK)) {
+ dev_err(qspi->dev, "unsupported SPI clock %u Hz\n", speed_hz);
+ return -EINVAL;
+ }
+
+ nuvoton_qspi_write(qspi, FIELD_PREP(NUVOTON_QSPI_CLKDIV_MASK, div),
+ NUVOTON_QSPI_CLKDIV_OFFSET);
+ qspi->speed_hz = speed_hz;
+
+ return 0;
+}
+
+static int nuvoton_qspi_set_bits_per_word(struct nuvoton_qspi *qspi, u8 bpw)
+{
+ u32 val;
+
+ if (bpw != 8 && bpw != 16 && bpw != 32)
+ return -EINVAL;
+
+ if (bpw == 32)
+ val = NUVOTON_QSPI_CTL_REORDER_MASK;
+ else
+ val = FIELD_PREP(NUVOTON_QSPI_CTL_DWIDTH_MASK, bpw);
+
+ nuvoton_qspi_update_bits(qspi, NUVOTON_QSPI_CTL_OFFSET,
+ NUVOTON_QSPI_CTL_DWIDTH_MASK |
+ NUVOTON_QSPI_CTL_REORDER_MASK, val);
+ qspi->bits_per_word = bpw;
+
+ return 0;
+}
+
+static int nuvoton_qspi_setup_transfer(struct spi_device *spi,
+ u32 speed_hz, u8 bpw)
+{
+ struct nuvoton_qspi *qspi = spi_controller_get_devdata(spi->controller);
+ u32 mode = spi->mode & SPI_MODE_X_MASK;
+ u32 ctl = 0;
+ int ret;
+
+ if (!speed_hz)
+ speed_hz = spi->max_speed_hz;
+
+ if (!bpw)
+ bpw = NUVOTON_QSPI_DEFAULT_BPW;
+
+ ret = nuvoton_qspi_set_speed(qspi, speed_hz);
+ if (ret)
+ return ret;
+
+ ret = nuvoton_qspi_set_bits_per_word(qspi, bpw);
+ if (ret)
+ return ret;
+
+ if (mode == SPI_MODE_0 || mode == SPI_MODE_3)
+ ctl |= NUVOTON_QSPI_CTL_TXNEG_MASK;
+ else
+ ctl |= NUVOTON_QSPI_CTL_RXNEG_MASK;
+
+ if (spi->mode & SPI_CPOL)
+ ctl |= NUVOTON_QSPI_CTL_CLKPOL_MASK;
+
+ if (spi->mode & SPI_LSB_FIRST)
+ ctl |= NUVOTON_QSPI_CTL_LSB_MASK;
+
+ nuvoton_qspi_update_bits(qspi, NUVOTON_QSPI_CTL_OFFSET,
+ NUVOTON_QSPI_CTL_TXNEG_MASK |
+ NUVOTON_QSPI_CTL_RXNEG_MASK |
+ NUVOTON_QSPI_CTL_CLKPOL_MASK |
+ NUVOTON_QSPI_CTL_LSB_MASK, ctl);
+
+ return 0;
+}
+
+static void nuvoton_qspi_set_bus_width(struct nuvoton_qspi *qspi,
+ unsigned int buswidth,
+ enum spi_mem_data_dir dir)
+{
+ u32 ctl = 0;
+
+ if (buswidth == 4)
+ ctl |= NUVOTON_QSPI_CTL_QUADIOEN_MASK;
+ else if (buswidth == 2)
+ ctl |= NUVOTON_QSPI_CTL_DUALIOEN_MASK;
+
+ if (buswidth > 1 && dir == SPI_MEM_DATA_OUT)
+ ctl |= NUVOTON_QSPI_CTL_DATDIR_MASK;
+
+ nuvoton_qspi_update_bits(qspi, NUVOTON_QSPI_CTL_OFFSET,
+ NUVOTON_QSPI_CTL_QUADIOEN_MASK |
+ NUVOTON_QSPI_CTL_DUALIOEN_MASK |
+ NUVOTON_QSPI_CTL_DATDIR_MASK, ctl);
+}
+
+static u32 nuvoton_qspi_tx_word(const void *txbuf, unsigned int idx, u8 bpw)
+{
+ if (!txbuf)
+ return 0;
+
+ if (bpw <= 8)
+ return ((const u8 *)txbuf)[idx];
+ if (bpw <= 16)
+ return ((const u16 *)txbuf)[idx];
+
+ return ((const u32 *)txbuf)[idx];
+}
+
+static void nuvoton_qspi_rx_word(void *rxbuf, unsigned int idx, u32 val, u8 bpw)
+{
+ if (!rxbuf)
+ return;
+
+ if (bpw <= 8)
+ ((u8 *)rxbuf)[idx] = val;
+ else if (bpw <= 16)
+ ((u16 *)rxbuf)[idx] = val;
+ else
+ ((u32 *)rxbuf)[idx] = val;
+}
+
+static int nuvoton_qspi_wait_tx_not_full(struct nuvoton_qspi *qspi)
+{
+ u32 val;
+
+ return readl_poll_timeout_atomic(qspi->regs + NUVOTON_QSPI_STATUS_OFFSET,
+ val,
+ !(val & NUVOTON_QSPI_STATUS_TXFULL_MASK),
+ 0, NUVOTON_QSPI_TIMEOUT_US);
+}
+
+static int nuvoton_qspi_wait_rx_not_empty(struct nuvoton_qspi *qspi)
+{
+ u32 val;
+
+ return readl_poll_timeout_atomic(qspi->regs + NUVOTON_QSPI_STATUS_OFFSET,
+ val,
+ !(val & NUVOTON_QSPI_STATUS_RXEMPTY_MASK),
+ 0, NUVOTON_QSPI_TIMEOUT_US);
+}
+
+static int nuvoton_qspi_txrx(struct nuvoton_qspi *qspi, const void *txbuf,
+ void *rxbuf, unsigned int len)
+{
+ unsigned int bytes_per_word = DIV_ROUND_UP(qspi->bits_per_word, 8);
+ unsigned int words;
+ u32 val;
+ int ret;
+ int i;
+
+ if (!len)
+ return 0;
+
+ if (len % bytes_per_word)
+ return -EINVAL;
+
+ words = len / bytes_per_word;
+
+ ret = nuvoton_qspi_reset_fifo(qspi);
+ if (ret) {
+ dev_err(qspi->dev, "FIFO reset timed out\n");
+ return ret;
+ }
+
+ /*
+ * Use conservative word-by-word PIO access. This keeps the initial driver
+ * simple and avoids relying on FIFO threshold interrupts or DMA support.
+ *
+ * The MA35D1 QSPI controller pushes one RX FIFO entry for each TX word in
+ * single, dual-output and quad-output modes. Drain RX after every TX word
+ * and discard the value for TX-only transfers to avoid RX FIFO overflow.
+ */
+ for (i = 0; i < words; i++) {
+ ret = nuvoton_qspi_wait_tx_not_full(qspi);
+ if (ret) {
+ dev_err(qspi->dev, "TX FIFO full timeout\n");
+ return ret;
+ }
+
+ nuvoton_qspi_write(qspi, nuvoton_qspi_tx_word(txbuf, i,
+ qspi->bits_per_word),
+ NUVOTON_QSPI_TX_OFFSET);
+
+ ret = nuvoton_qspi_wait_rx_not_empty(qspi);
+ if (ret) {
+ dev_err(qspi->dev, "RX FIFO empty timeout\n");
+ return ret;
+ }
+
+ val = nuvoton_qspi_read(qspi, NUVOTON_QSPI_RX_OFFSET);
+ if (rxbuf)
+ nuvoton_qspi_rx_word(rxbuf, i, val, qspi->bits_per_word);
+ }
+
+ ret = nuvoton_qspi_wait_ready(qspi);
+ if (ret)
+ dev_err(qspi->dev, "controller busy timeout\n");
+
+ return ret;
+}
+
+static int nuvoton_qspi_hw_init(struct nuvoton_qspi *qspi)
+{
+ u32 val;
+ int ret;
+
+ ret = nuvoton_qspi_set_bits_per_word(qspi, NUVOTON_QSPI_DEFAULT_BPW);
+ if (ret)
+ return ret;
+
+ nuvoton_qspi_update_bits(qspi, NUVOTON_QSPI_CTL_OFFSET,
+ NUVOTON_QSPI_CTL_SUSPITV_MASK |
+ NUVOTON_QSPI_CTL_TXNEG_MASK |
+ NUVOTON_QSPI_CTL_RXNEG_MASK |
+ NUVOTON_QSPI_CTL_CLKPOL_MASK |
+ NUVOTON_QSPI_CTL_LSB_MASK,
+ NUVOTON_QSPI_CTL_TXNEG_MASK);
+
+ val = nuvoton_qspi_read(qspi, NUVOTON_QSPI_CTL_OFFSET);
+ nuvoton_qspi_write(qspi, val | NUVOTON_QSPI_CTL_SPIEN_MASK,
+ NUVOTON_QSPI_CTL_OFFSET);
+
+ ret = readl_poll_timeout(qspi->regs + NUVOTON_QSPI_STATUS_OFFSET, val,
+ (val & NUVOTON_QSPI_STATUS_SPIENSTS_MASK),
+ 1, NUVOTON_QSPI_TIMEOUT_US);
+ if (ret) {
+ dev_err(qspi->dev, "failed to enable controller\n");
+ return ret;
+ }
+
+ ret = nuvoton_qspi_reset_fifo(qspi);
+ if (ret)
+ dev_err(qspi->dev, "FIFO reset timed out\n");
+
+ return ret;
+}
+
+static bool nuvoton_qspi_mem_supports_op(struct spi_mem *mem,
+ const struct spi_mem_op *op)
+{
+ if (!spi_mem_default_supports_op(mem, op))
+ return false;
+
+ if (op->cmd.buswidth > 4 || op->addr.buswidth > 4 ||
+ op->dummy.buswidth > 4 || op->data.buswidth > 4)
+ return false;
+
+ if (op->cmd.nbytes != 1)
+ return false;
+
+ if (op->addr.nbytes > 4)
+ return false;
+
+ return true;
+}
+
+static void nuvoton_qspi_set_cs_level(struct nuvoton_qspi *qspi,
+ unsigned int cs, bool assert)
+{
+ u32 mask;
+ u32 val;
+
+ switch (cs) {
+ case 0:
+ mask = NUVOTON_QSPI_SSCTL_SS0_MASK;
+ break;
+ case 1:
+ mask = NUVOTON_QSPI_SSCTL_SS1_MASK;
+ break;
+ default:
+ dev_warn(qspi->dev, "invalid chip select %u\n", cs);
+ return;
+ }
+
+ val = nuvoton_qspi_read(qspi, NUVOTON_QSPI_SSCTL_OFFSET);
+
+ if (assert)
+ val |= mask;
+ else
+ val &= ~mask;
+
+ nuvoton_qspi_write(qspi, val, NUVOTON_QSPI_SSCTL_OFFSET);
+}
+
+static void nuvoton_qspi_set_cs(struct spi_device *spi, bool enable)
+{
+ struct nuvoton_qspi *qspi = spi_controller_get_devdata(spi->controller);
+
+ nuvoton_qspi_set_cs_level(qspi, spi_get_chipselect(spi, 0), enable);
+}
+
+static void nuvoton_qspi_mem_set_cs(struct spi_device *spi, bool enable)
+{
+ struct nuvoton_qspi *qspi = spi_controller_get_devdata(spi->controller);
+ bool assert = enable;
+
+ if (spi->mode & SPI_CS_HIGH)
+ assert = !assert;
+
+ nuvoton_qspi_set_cs_level(qspi, spi_get_chipselect(spi, 0), assert);
+}
+
+static int nuvoton_qspi_mem_exec_op(struct spi_mem *mem,
+ const struct spi_mem_op *op)
+{
+ struct spi_device *spi = mem->spi;
+ struct nuvoton_qspi *qspi = spi_controller_get_devdata(spi->controller);
+ u8 opcode = op->cmd.opcode;
+ u8 addr[4];
+ int ret;
+ int i;
+
+ ret = nuvoton_qspi_setup_transfer(spi, op->max_freq, NUVOTON_QSPI_DEFAULT_BPW);
+ if (ret)
+ return ret;
+
+ nuvoton_qspi_mem_set_cs(spi, true);
+
+ nuvoton_qspi_set_bus_width(qspi, op->cmd.buswidth, SPI_MEM_DATA_OUT);
+ ret = nuvoton_qspi_txrx(qspi, &opcode, NULL, 1);
+ if (ret)
+ goto out_deassert_cs;
+
+ if (op->addr.nbytes) {
+ for (i = 0; i < op->addr.nbytes; i++)
+ addr[i] = op->addr.val >> (8 * (op->addr.nbytes - i - 1));
+
+ nuvoton_qspi_set_bus_width(qspi, op->addr.buswidth,
+ SPI_MEM_DATA_OUT);
+ ret = nuvoton_qspi_txrx(qspi, addr, NULL, op->addr.nbytes);
+ if (ret)
+ goto out_deassert_cs;
+ }
+
+ if (op->dummy.nbytes) {
+ nuvoton_qspi_set_bus_width(qspi, op->dummy.buswidth,
+ SPI_MEM_DATA_IN);
+ ret = nuvoton_qspi_txrx(qspi, NULL, NULL, op->dummy.nbytes);
+ if (ret)
+ goto out_deassert_cs;
+ }
+
+ if (op->data.nbytes) {
+ nuvoton_qspi_set_bus_width(qspi, op->data.buswidth,
+ op->data.dir);
+ ret = nuvoton_qspi_txrx(qspi,
+ op->data.dir == SPI_MEM_DATA_OUT ?
+ op->data.buf.out : NULL,
+ op->data.dir == SPI_MEM_DATA_IN ?
+ op->data.buf.in : NULL,
+ op->data.nbytes);
+ }
+
+out_deassert_cs:
+ nuvoton_qspi_set_bus_width(qspi, 1, SPI_MEM_DATA_IN);
+ nuvoton_qspi_mem_set_cs(spi, false);
+
+ return ret;
+}
+
+static const struct spi_controller_mem_ops nuvoton_qspi_mem_ops = {
+ .supports_op = nuvoton_qspi_mem_supports_op,
+ .exec_op = nuvoton_qspi_mem_exec_op,
+};
+
+static const struct spi_controller_mem_caps nuvoton_qspi_mem_caps = {
+ .per_op_freq = true,
+};
+
+static int nuvoton_qspi_transfer_one(struct spi_controller *ctlr,
+ struct spi_device *spi,
+ struct spi_transfer *xfer)
+{
+ struct nuvoton_qspi *qspi = spi_controller_get_devdata(ctlr);
+ enum spi_mem_data_dir dir = SPI_MEM_DATA_IN;
+ unsigned int buswidth = 1;
+ int ret;
+
+ ret = nuvoton_qspi_setup_transfer(spi, xfer->speed_hz, xfer->bits_per_word);
+ if (ret)
+ return ret;
+
+ if (xfer->tx_buf && xfer->rx_buf) {
+ if (xfer->tx_nbits != SPI_NBITS_SINGLE ||
+ xfer->rx_nbits != SPI_NBITS_SINGLE)
+ return -EOPNOTSUPP;
+ }
+
+ if (xfer->tx_buf) {
+ dir = SPI_MEM_DATA_OUT;
+ if (xfer->tx_nbits == SPI_NBITS_QUAD)
+ buswidth = 4;
+ else if (xfer->tx_nbits == SPI_NBITS_DUAL)
+ buswidth = 2;
+ } else if (xfer->rx_buf) {
+ if (xfer->rx_nbits == SPI_NBITS_QUAD)
+ buswidth = 4;
+ else if (xfer->rx_nbits == SPI_NBITS_DUAL)
+ buswidth = 2;
+ }
+
+ nuvoton_qspi_set_bus_width(qspi, buswidth, dir);
+ ret = nuvoton_qspi_txrx(qspi, xfer->tx_buf, xfer->rx_buf, xfer->len);
+ nuvoton_qspi_set_bus_width(qspi, 1, SPI_MEM_DATA_IN);
+
+ return ret;
+}
+
+static int nuvoton_qspi_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct spi_controller *ctlr;
+ struct nuvoton_qspi *qspi;
+ struct reset_control *rst;
+ int ret;
+
+ ctlr = devm_spi_alloc_host(dev, sizeof(*qspi));
+ if (!ctlr)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, ctlr);
+
+ qspi = spi_controller_get_devdata(ctlr);
+ qspi->dev = dev;
+ qspi->bits_per_word = NUVOTON_QSPI_DEFAULT_BPW;
+
+ qspi->regs = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(qspi->regs))
+ return PTR_ERR(qspi->regs);
+
+ rst = devm_reset_control_get_exclusive(dev, NULL);
+ if (IS_ERR(rst))
+ return dev_err_probe(dev, PTR_ERR(rst),
+ "failed to get reset\n");
+
+ qspi->clk = devm_clk_get_enabled(dev, NULL);
+ if (IS_ERR(qspi->clk))
+ return dev_err_probe(dev, PTR_ERR(qspi->clk),
+ "failed to get and enable clock\n");
+
+ ret = reset_control_assert(rst);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to assert reset\n");
+
+ udelay(2);
+
+ ret = reset_control_deassert(rst);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to deassert reset\n");
+
+ ctlr->num_chipselect = NUVOTON_QSPI_DEFAULT_NUM_CS;
+ ctlr->mem_ops = &nuvoton_qspi_mem_ops;
+ ctlr->mem_caps = &nuvoton_qspi_mem_caps;
+ ctlr->set_cs = nuvoton_qspi_set_cs;
+ ctlr->transfer_one = nuvoton_qspi_transfer_one;
+ ctlr->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16) |
+ SPI_BPW_MASK(32);
+ ctlr->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST |
+ SPI_RX_DUAL | SPI_TX_DUAL |
+ SPI_RX_QUAD | SPI_TX_QUAD;
+ ctlr->dev.of_node = dev->of_node;
+
+ ret = nuvoton_qspi_hw_init(qspi);
+ if (ret)
+ return ret;
+
+ ret = devm_spi_register_controller(dev, ctlr);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "failed to register spi controller\n");
+
+ return 0;
+}
+
+static const struct of_device_id nuvoton_qspi_of_match[] = {
+ { .compatible = "nuvoton,ma35d1-qspi" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, nuvoton_qspi_of_match);
+
+static struct platform_driver nuvoton_qspi_driver = {
+ .driver = {
+ .name = "ma35d1-qspi",
+ .of_match_table = nuvoton_qspi_of_match,
+ },
+ .probe = nuvoton_qspi_probe,
+};
+module_platform_driver(nuvoton_qspi_driver);
+
+MODULE_DESCRIPTION("Nuvoton MA35D1 QSPI controller driver");
+MODULE_AUTHOR("Chi-Wen Weng <cwweng@nuvoton.com>");
+MODULE_LICENSE("GPL");
--
2.25.1
^ permalink raw reply related
* [PATCH v3 1/2] dt-bindings: spi: nuvoton,ma35d1-qspi: Add Nuvoton MA35D1 QSPI
From: Chi-Wen Weng @ 2026-06-11 9:12 UTC (permalink / raw)
To: broonie, robh, krzk+dt, conor+dt
Cc: linux-arm-kernel, linux-spi, devicetree, linux-kernel, cwweng,
cwweng.linux
In-Reply-To: <20260611091246.2070485-1-cwweng.linux@gmail.com>
From: Chi-Wen Weng <cwweng@nuvoton.com>
Add a devicetree binding for the Quad SPI controller found in
Nuvoton MA35D1 SoCs.
The controller supports SPI memory devices such as SPI NOR and SPI NAND
flashes. It has one register range, one clock input and one reset line,
and supports up to two chip selects.
Signed-off-by: Chi-Wen Weng <cwweng@nuvoton.com>
---
.../bindings/spi/nuvoton,ma35d1-qspi.yaml | 62 +++++++++++++++++++
1 file changed, 62 insertions(+)
create mode 100644 Documentation/devicetree/bindings/spi/nuvoton,ma35d1-qspi.yaml
diff --git a/Documentation/devicetree/bindings/spi/nuvoton,ma35d1-qspi.yaml b/Documentation/devicetree/bindings/spi/nuvoton,ma35d1-qspi.yaml
new file mode 100644
index 000000000000..d3b36e612eb0
--- /dev/null
+++ b/Documentation/devicetree/bindings/spi/nuvoton,ma35d1-qspi.yaml
@@ -0,0 +1,62 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/spi/nuvoton,ma35d1-qspi.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Nuvoton MA35D1 Quad SPI Controller
+
+maintainers:
+ - Chi-Wen Weng <cwweng@nuvoton.com>
+
+allOf:
+ - $ref: /schemas/spi/spi-controller.yaml#
+
+properties:
+ compatible:
+ const: nuvoton,ma35d1-qspi
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ clocks:
+ maxItems: 1
+
+ resets:
+ maxItems: 1
+
+ num-cs:
+ maximum: 2
+
+required:
+ - compatible
+ - reg
+ - clocks
+ - resets
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/clock/nuvoton,ma35d1-clk.h>
+ #include <dt-bindings/reset/nuvoton,ma35d1-reset.h>
+
+ soc {
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ spi@40680000 {
+ compatible = "nuvoton,ma35d1-qspi";
+ reg = <0 0x40680000 0 0x100>;
+ interrupts = <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clk QSPI0_GATE>;
+ resets = <&sys MA35D1_RESET_QSPI0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+ };
+
--
2.25.1
^ permalink raw reply related
* [PATCH v3 0/2] spi: ma35d1-qspi: Add Nuvoton MA35D1 QSPI controller
From: Chi-Wen Weng @ 2026-06-11 9:12 UTC (permalink / raw)
To: broonie, robh, krzk+dt, conor+dt
Cc: linux-arm-kernel, linux-spi, devicetree, linux-kernel, cwweng,
cwweng.linux
From: Chi-Wen Weng <cwweng@nuvoton.com>
Add devicetree binding and SPI controller driver support for the
Nuvoton MA35D1 Quad SPI controller.
The MA35D1 QSPI controller supports SPI memory devices such as SPI NOR
and SPI NAND flashes in single, dual and quad I/O modes. This initial
driver implements a conservative PIO-based transfer path and spi-mem
operation support.
Changes in v3:
- Fixed DCO mismatch by using a consistent author and Signed-off-by
address.
- Added spi_controller_mem_caps and set per_op_freq for spi-mem
operations.
- Added SPI_CS_HIGH to controller mode_bits.
- Added a short delay after requesting FIFO reset before polling reset
completion.
- Documented that the MA35D1 QSPI controller pushes one RX FIFO entry for
each TX word in single, dual-output and quad-output modes, so TX-only
transfers intentionally drain and discard RX data.
- Added missing linux/delay.h include for udelay().
- Cleaned up unused register bit definitions.
Changes in v2:
- Updated patch subject lines to match SPI subsystem style.
- Added commit message to the dt-bindings patch.
- Added ARCH_MA35 || COMPILE_TEST dependency to Kconfig.
- Expanded Kconfig help text.
- Converted the driver file header to // comments.
- Added reset control handling to the driver.
- Added resets property to the binding.
- Added num-cs constraint to the binding.
- Dropped the flash child node from the binding example.
- Used op->max_freq for spi-mem operations.
- Split low-level CS register handling from the SPI core .set_cs()
callback.
- Handled SPI_CS_HIGH explicitly for the spi-mem direct CS path.
- Fixed spi-mem opcode transfer to use a u8 buffer.
- Limited spi-mem command opcode length to one byte.
- Forced spi-mem operations to 8-bit word size.
- Avoided driving bidirectional data pins during dummy cycles.
- Drained RX FIFO during TX-only transfers.
- Rejected invalid chip-select numbers instead of mapping them to SS1.
- Rejected unsupported dual/quad full-duplex generic SPI transfers.
- Fixed checkpatch style issues.
Chi-Wen Weng (2):
dt-bindings: spi: nuvoton,ma35d1-qspi: Add Nuvoton MA35D1 QSPI
spi: ma35d1-qspi: Add Nuvoton MA35D1 QSPI controller support
.../bindings/spi/nuvoton,ma35d1-qspi.yaml | 62 ++
drivers/spi/Kconfig | 10 +
drivers/spi/Makefile | 1 +
drivers/spi/spi-ma35d1-qspi.c | 633 ++++++++++++++++++
4 files changed, 706 insertions(+)
create mode 100644 Documentation/devicetree/bindings/spi/nuvoton,ma35d1-qspi.yaml
create mode 100644 drivers/spi/spi-ma35d1-qspi.c
--
2.25.1
^ permalink raw reply
* Re: [PATCH v2 07/16] usb: hub: Power on connected M.2 E-key connectors
From: Bartosz Golaszewski @ 2026-06-11 9:11 UTC (permalink / raw)
To: Chen-Yu Tsai
Cc: Alan Stern, linux-acpi, driver-core, linux-pm, linux-usb,
devicetree, linux-mediatek, linux-arm-kernel, linux-kernel,
Manivannan Sadhasivam, Bartosz Golaszewski, Greg Kroah-Hartman,
Andy Shevchenko, Daniel Scally, Heikki Krogerus, Sakari Ailus,
Rafael J. Wysocki, Danilo Krummrich, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
AngeloGioacchino Del Regno
In-Reply-To: <20260610084053.2059858-8-wenst@chromium.org>
On Wed, 10 Jun 2026 10:40:41 +0200, Chen-Yu Tsai <wenst@chromium.org> said:
> The new M.2 E-key connector can have a USB connection. For the USB device
> on this connector to work, its power must be enabled and the W_DISABLE2#
> signal deasserted. The connector driver handles this and provides a
> toggle over the power sequencing API.
>
> This feature currently only supports a directly connected (no mux in
> between) M.2 E-key connector. Existing USB connector types are not
> covered. The USB A connector was recently added to the onboard devices
> driver. USB B connectors have historically been managed by the USB
> gadget or dual-role device controller drivers. USB C connectors are
> handled by TCPM drivers.
>
> The power sequencing API does not know whether a power sequence provider
> is not needed or not available yet, so we only request it for connectors
> that we know need it, which at this time is just the E-key connector.
>
> On the USB side, the port firmware node (if present) is tied to the
> usb_port device. This device is used to acquire the power sequencing
> descriptor. This allows the provider to tell the different ports on one
> hub apart.
>
> This feature is not implemented in the onboard USB devices driver. The
> power sequencing API expects the consumer device to make the request,
> but there is no device node to instantiate a platform device to tie
> the driver to. The connector is not a child node of the USB host or
> hub, and the graph connection is from a USB port to the connector.
> And the connector itself already has a driver.
>
> Power sequencing is not directly enabled in the connector driver as
> that would completely decouple the timing of it from the USB subsystem.
> It would not be possible for the USB subsystem to toggle the power
> for a power cycle or to disable the port.
>
> This change depends on another change to make the power sequencing
> framework bool instead of tristate. The USB core and hub driver are
> bool, so if the power sequencing framework is built as a module, the
> kernel will fail to link.
>
That bit needs to go away I suppose?
I see Andy has some suggestions but in general I like this approach much better
than adding the pwrseq_get_index() function. Thanks!
Bartosz
^ permalink raw reply
* Re: [PATCH v7 8/8] perf test: Add Arm CoreSight callchain test
From: James Clark @ 2026-06-11 9:11 UTC (permalink / raw)
To: Leo Yan
Cc: linux-arm-kernel, coresight, linux-perf-users,
Arnaldo Carvalho de Melo, John Garry, Will Deacon, Mike Leach,
Suzuki K Poulose, Namhyung Kim, Mark Rutland, Alexander Shishkin,
Jiri Olsa, Ian Rogers, Adrian Hunter, Al Grant, Paschalis Mpeis,
Amir Ayupov
In-Reply-To: <20260611-b4-arm_cs_callchain_support_v1-v7-8-1ba770c862ae@arm.com>
On 11/06/2026 8:57 am, Leo Yan wrote:
> Add a CoreSight shell test for synthesized callchains.
>
> The test uses the new callchain workload to generate trace and decodes
> it with synthesis callchain. It then verifies that the instruction
> samples show the expected callchain push and pop.
>
> Use control FIFOs so tracing starts only around the workload, which
> keeps the trace data small. The test is limited to arm64 systems with
> the cs_etm event available.
>
> After:
>
> perf test 136 -vvv
> 136: CoreSight synthesized callchain:
> --- start ---
> test child forked, pid 3539
> ---- end(0) ----
> 136: CoreSight synthesized callchain : Ok
>
> Assisted-by: Codex:GPT-5.5
> Signed-off-by: Leo Yan <leo.yan@arm.com>
> ---
> tools/perf/Documentation/perf-test.txt | 6 +-
> tools/perf/tests/builtin-test.c | 1 +
> tools/perf/tests/shell/coresight/callchain.sh | 168 ++++++++++++++++++++++++++
> tools/perf/tests/tests.h | 1 +
> tools/perf/tests/workloads/Build | 2 +
> tools/perf/tests/workloads/callchain.c | 24 ++++
Maybe "syscall" is a better name? There's not any difference between
this one and others like the deterministic one I added with regards to
the callchain.
> 6 files changed, 200 insertions(+), 2 deletions(-)
>
> diff --git a/tools/perf/Documentation/perf-test.txt b/tools/perf/Documentation/perf-test.txt
> index 81c8525f594680d814f80e6f88bcce8d867bb350..859df74e62efc4b1e80da13ae8e053356f68ae54 100644
> --- a/tools/perf/Documentation/perf-test.txt
> +++ b/tools/perf/Documentation/perf-test.txt
> @@ -57,7 +57,8 @@ OPTIONS
> --workload=::
> Run a built-in workload, to list them use '--list-workloads', current
> ones include: noploop, thloop, leafloop, sqrtloop, brstack, datasym,
> - context_switch_loop, deterministic, named_threads and landlock.
> + context_switch_loop, deterministic, named_threads, landlock and
> + callchain.
>
> Used with the shell script regression tests.
>
> @@ -69,7 +70,8 @@ OPTIONS
> 'named_threads' accepts the number of threads and the number of loops to
> do in each thread.
>
> - The datasym, landlock and deterministic workloads don't accept any.
> + The datasym, landlock, deterministic and callchain workloads don't accept
> + any.
>
> --list-workloads::
> List the available workloads to use with -w/--workload.
> diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c
> index afc06cec49546d29d86b94840c7021c5bf5c88e3..8994488cc206863ba77f7e7e5803e62f18e151ba 100644
> --- a/tools/perf/tests/builtin-test.c
> +++ b/tools/perf/tests/builtin-test.c
> @@ -166,6 +166,7 @@ static struct test_workload *workloads[] = {
> &workload__jitdump,
> &workload__context_switch_loop,
> &workload__deterministic,
> + &workload__callchain,
>
> #ifdef HAVE_RUST_SUPPORT
> &workload__code_with_type,
> diff --git a/tools/perf/tests/shell/coresight/callchain.sh b/tools/perf/tests/shell/coresight/callchain.sh
> new file mode 100755
> index 0000000000000000000000000000000000000000..e9f907f60e3a4574f13a9c651d541c675f07a4ad
> --- /dev/null
> +++ b/tools/perf/tests/shell/coresight/callchain.sh
> @@ -0,0 +1,168 @@
> +#!/bin/bash
> +# CoreSight synthesized callchain (exclusive)
> +# SPDX-License-Identifier: GPL-2.0
> +
> +glb_err=1
> +
> +if ! tmpdir=$(mktemp -d /tmp/perf-cs-callchain-test.XXXXXX); then
> + echo "mktemp failed"
> + exit 1
> +fi
> +
> +cleanup_files()
> +{
> + rm -rf "$tmpdir"
> +}
> +
> +trap cleanup_files EXIT
> +trap 'cleanup_files; exit $glb_err' TERM INT
> +
> +skip_if_system_is_not_ready()
> +{
> + [ "$(uname -m)" = "aarch64" ] || {
> + echo "Skip: arm64 only test" >&2
> + return 2
> + }
Minor nit, but for consistency with the other coresight tests we should
probably not check for arm64 and only check for cs_etm//.
> +
> + perf list | grep -Pzq 'cs_etm//' || {
> + echo "Skip: cs_etm event is not available" >&2
> + return 2
> + }
> +
> + return 0
> +}
> +
> +record_trace()
> +{
> + local data=$1
> + local script=$2
> +
> + local cf="$tmpdir/ctl"
> + local af="$tmpdir/ack"
> +
> + mkfifo "$cf" "$af"
> +
> + perf record -o "$data" -e cs_etm// --per-thread -D -1 --control fifo:"$cf","$af" -- \
> + perf test --record-ctl fifo:"$cf","$af" -w callchain >/dev/null 2>&1 &&
> +
> + # It is safe to use 'i3i' with a three-instruction interval, since the
> + # workload is compiled with -O0.
> + perf script --itrace=g16i3il64 -i "$data" > "$script"
> +}
> +
> +callchain_regex_1()
> +{
> + printf '%s' \
> +'perf[[:space:]]+[0-9]+[[:space:]]+\[[0-9]+\][[:space:]]+([0-9.]+:[[:space:]]+)?[0-9]+ instructions:[[:space:]]*\n'\
> +'[[:space:]]+[[:xdigit:]]+ foo\+0x[[:xdigit:]]+ \(.*/perf\)\n'\
> +'[[:space:]]+[[:xdigit:]]+ callchain\+0x[[:xdigit:]]+ \(.*/perf\)\n'\
> +'([[:space:]]+[[:xdigit:]]+ .*\n)*'
> +}
> +
> +callchain_regex_2()
> +{
> + printf '%s' \
> +'perf[[:space:]]+[0-9]+[[:space:]]+\[[0-9]+\][[:space:]]+([0-9.]+:[[:space:]]+)?[0-9]+ instructions:[[:space:]]*\n'\
> +'[[:space:]]+[[:xdigit:]]+ do_syscall\+0x[[:xdigit:]]+ \(.*/perf\)\n'\
> +'[[:space:]]+[[:xdigit:]]+ foo\+0x[[:xdigit:]]+ \(.*/perf\)\n'\
> +'[[:space:]]+[[:xdigit:]]+ callchain\+0x[[:xdigit:]]+ \(.*/perf\)\n'\
> +'([[:space:]]+[[:xdigit:]]+ .*\n)*'
> +}
> +
> +callchain_regex_3()
> +{
> + printf '%s' \
> +'perf[[:space:]]+[0-9]+[[:space:]]+\[[0-9]+\][[:space:]]+([0-9.]+:[[:space:]]+)?[0-9]+ instructions:[[:space:]]*\n'\
> +'[[:space:]]+[[:xdigit:]]+ syscall(@plt)?\+0x[[:xdigit:]]+ \(.*\)\n'\
> +'[[:space:]]+[[:xdigit:]]+ do_syscall\+0x[[:xdigit:]]+ \(.*/perf\)\n'\
> +'[[:space:]]+[[:xdigit:]]+ foo\+0x[[:xdigit:]]+ \(.*/perf\)\n'\
> +'[[:space:]]+[[:xdigit:]]+ callchain\+0x[[:xdigit:]]+ \(.*/perf\)\n'\
> +'([[:space:]]+[[:xdigit:]]+ .*\n)*'
> +}
> +
> +callchain_regex_4()
> +{
> + printf '%s' \
> +'perf[[:space:]]+[0-9]+[[:space:]]+\[[0-9]+\][[:space:]]+([0-9.]+:[[:space:]]+)?[0-9]+ instructions:[[:space:]]*\n'\
> +'[[:space:]]+[[:xdigit:]]+ .*\+0x[[:xdigit:]]+ \(\[kernel\.kallsyms\]\)\n'\
> +'[[:space:]]+[[:xdigit:]]+ syscall(@plt)?\+0x[[:xdigit:]]+ \(.*\)\n'\
> +'[[:space:]]+[[:xdigit:]]+ do_syscall\+0x[[:xdigit:]]+ \(.*/perf\)\n'\
> +'[[:space:]]+[[:xdigit:]]+ foo\+0x[[:xdigit:]]+ \(.*/perf\)\n'\
> +'[[:space:]]+[[:xdigit:]]+ callchain\+0x[[:xdigit:]]+ \(.*/perf\)\n'\
> +'([[:space:]]+[[:xdigit:]]+ .*\n)*'
> +}
> +
> +find_after_line()
> +{
> + local regex="$1"
> + local file="$2"
> + local start="$3"
> + local offset
> + local line
> +
> + # Search in byte offset
> + offset=$(
> + tail -n +"$start" "$file" |
> + grep -Pzob -m1 "$regex" |
> + tr '\0' '\n' |
> + sed -n 's/^\([0-9][0-9]*\):.*/\1/p;q'
> + )
> +
> + if [ -z "$offset" ]; then
> + echo "Failed to match regex after line $start" >&2
> + echo "Regex:" >&2
> + printf '%s\n' "$regex" >&2
> + echo "Context from line $start:" >&2
> + sed -n "${start},$((start + 100))p" "$file" >&2
> + return 1
> + fi
> +
> + # Conver from offset to line
> + line=$(
> + tail -n +"$start" "$file" |
> + head -c "$offset" |
> + wc -l
> + )
> +
> + echo "$((start + line))"
> +}
> +
> +check_callchain_flow()
> +{
> + local file="$1"
> + local l1 l2 l3 l4 l5 l6 l7
> +
> + # Callchain push
> + l1=$(find_after_line "$(callchain_regex_1)" "$file" 1) || return 1
> + l2=$(find_after_line "$(callchain_regex_2)" "$file" "$((l1 + 1))") || return 1
> + l3=$(find_after_line "$(callchain_regex_3)" "$file" "$((l2 + 1))") || return 1
> + l4=$(find_after_line "$(callchain_regex_4)" "$file" "$((l3 + 1))") || return 1
> +
> + # Callchain pop
> + l5=$(find_after_line "$(callchain_regex_3)" "$file" "$((l4 + 1))") || return 1
> + l6=$(find_after_line "$(callchain_regex_2)" "$file" "$((l5 + 1))") || return 1
> + l7=$(find_after_line "$(callchain_regex_1)" "$file" "$((l6 + 1))") || return 1
> +
In tests/shell/coresight/callchain.sh line 144:
l7=$(find_after_line "$(callchain_regex_1)" "$file" "$((l6 + 1))") ||
return 1
^-- SC2034 (warning): l7 appears unused. Verify use (or export
if used externally).
> + return 0
> +}
> +
> +run_test()
> +{
> + local data=$tmpdir/perf.data
> + local script=$tmpdir/perf.script
> +
> + if ! record_trace "$data" "$script"; then
> + echo "$name: perf record/script failed"
In tests/shell/coresight/callchain.sh line 155:
echo "$name: perf record/script failed"
^---^ SC2154 (warning): name is referenced but
not assigned.
> + return
> + fi
> +
> + check_callchain_flow "$script" || return
> +
> + glb_err=0
> +}
> +
> +skip_if_system_is_not_ready || exit 2
> +
> +run_test
> +
> +exit $glb_err
> diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h
> index 7cedf05be544ad79a99e86d30dfa4f7b01ca0837..cee9e6b62dcc838c864bbe76efe3b638ed75b134 100644
> --- a/tools/perf/tests/tests.h
> +++ b/tools/perf/tests/tests.h
> @@ -248,6 +248,7 @@ DECLARE_WORKLOAD(inlineloop);
> DECLARE_WORKLOAD(jitdump);
> DECLARE_WORKLOAD(context_switch_loop);
> DECLARE_WORKLOAD(deterministic);
> +DECLARE_WORKLOAD(callchain);
>
> #ifdef HAVE_RUST_SUPPORT
> DECLARE_WORKLOAD(code_with_type);
> diff --git a/tools/perf/tests/workloads/Build b/tools/perf/tests/workloads/Build
> index 75b377934a0e62b9ac1fec245520ea0978ac957e..dfdf9a2720b22f67a3d7b53d0ed14e0654059c8f 100644
> --- a/tools/perf/tests/workloads/Build
> +++ b/tools/perf/tests/workloads/Build
> @@ -13,6 +13,7 @@ perf-test-y += inlineloop.o
> perf-test-y += jitdump.o
> perf-test-y += context_switch_loop.o
> perf-test-y += deterministic.o
> +perf-test-y += callchain.o
>
> ifeq ($(CONFIG_RUST_SUPPORT),y)
> perf-test-y += code_with_type.o
> @@ -26,3 +27,4 @@ CFLAGS_datasym.o = -g -O0 -fno-inline -U_FORTIFY_SOURCE
> CFLAGS_traploop.o = -g -O0 -fno-inline -U_FORTIFY_SOURCE
> CFLAGS_inlineloop.o = -g -O2
> CFLAGS_deterministic.o = -g -O0 -fno-inline -U_FORTIFY_SOURCE
> +CFLAGS_callchain.o = -g -O0 -fno-inline -U_FORTIFY_SOURCE
> diff --git a/tools/perf/tests/workloads/callchain.c b/tools/perf/tests/workloads/callchain.c
> new file mode 100644
> index 0000000000000000000000000000000000000000..a7eca77277496eec2f47d6f1a646552c298a533f
> --- /dev/null
> +++ b/tools/perf/tests/workloads/callchain.c
> @@ -0,0 +1,24 @@
> +// SPDX-License-Identifier: GPL-2.0
> +#include <linux/compiler.h>
> +#include <sys/syscall.h>
> +#include <unistd.h>
> +#include "../tests.h"
> +
> +static void do_syscall(void)
> +{
> + syscall(SYS_getpid);
> +}
> +
> +static void foo(void)
According to Sashiko on my other review, even with -O0 these symbols can
be renamed when built with LTO. As you are looking for matches on
function names, you should probably make them global and with unique
prefixes and leave a comment. At least I did that wherever I was
matching on a function name, and only used static for ones that weren't
matched. Would be a good habit to the pattern gets copy pasted to other
workloads and tests.
> +{
> + do_syscall();
> +}
> +
> +static int callchain(int argc __maybe_unused, const char **argv __maybe_unused)
> +{
> + foo();
> +
> + return 0;
> +}
> +
> +DEFINE_WORKLOAD(callchain);
>
^ permalink raw reply
* Re: [PATCH v1 1/3] dt-bindings: arm: fsl: add Variscite DART-MX8M-MINI Boards
From: Krzysztof Kozlowski @ 2026-06-11 9:06 UTC (permalink / raw)
To: Stefano Radaelli
Cc: linux-kernel, devicetree, imx, linux-arm-kernel, pierluigi.p,
Stefano Radaelli, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Frank Li, Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam,
Shawn Guo, Daniel Baluta, Dario Binacchi, Josua Mayer,
Maud Spierings, Alexander Stein, Ernest Van Hoecke,
Francesco Dolcini, Hugo Villeneuve
In-Reply-To: <a3355082aec3454f671b44e1f9a78000d2733470.1781024557.git.stefano.r@variscite.com>
On Wed, Jun 10, 2026 at 10:58:53AM +0200, Stefano Radaelli wrote:
> From: Stefano Radaelli <stefano.r@variscite.com>
>
> Add DT compatible strings for Variscite DART-MX8MM SoM and Variscite
> development carrier Board.
>
> Signed-off-by: Stefano Radaelli <stefano.r@variscite.com>
> ---
> Documentation/devicetree/bindings/arm/fsl.yaml | 6 ++++++
> 1 file changed, 6 insertions(+)
Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
Best regards,
Krzysztof
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox