Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [RFC PATCH] mmc: host: sdhci-iproc: implement the .hw_reset callback
From: Meagan Lloyd @ 2026-03-27 22:21 UTC (permalink / raw)
  To: rjui
  Cc: sbranden, linux-arm-kernel, meaganlloyd, tgopinath, adrian.hunter,
	linux-mmc

Implement the .hw_reset callback so that the eMMC can be reset as needed
given cap-mmc-hw-reset is set in the devicetree and the functionality is
enabled on the eMMC.

Signed-off-by: Meagan Lloyd <meaganlloyd@linux.microsoft.com>
---

SDHCI_POWER_CONTROL[4] (SD Host Controller Standard) has been repurposed
on my Broadcomm processor to be eMMC hardware reset
(SDIO*_eMMCSDXC_CTRL[12], HRESET).

Can you confirm this repurposed bit is consistent across the Broadcomm
iProc processors and thus the .hw_reset callback can be uniformly
applied in this driver?

---
 drivers/mmc/host/sdhci-iproc.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/drivers/mmc/host/sdhci-iproc.c b/drivers/mmc/host/sdhci-iproc.c
index 35ef5c5f51467..9018ed7fe2e66 100644
--- a/drivers/mmc/host/sdhci-iproc.c
+++ b/drivers/mmc/host/sdhci-iproc.c
@@ -181,12 +181,26 @@ static unsigned int sdhci_iproc_bcm2711_get_min_clock(struct sdhci_host *host)
 	return 200000;
 }
 
+static void sdhci_iproc_hw_reset(struct sdhci_host *host)
+{
+	u8 val = sdhci_readb(host, SDHCI_POWER_CONTROL);
+
+	/* Trigger reset and hold for at least 1us (eMMC spec requirement) */
+	sdhci_writeb(host, val | BIT(4), SDHCI_POWER_CONTROL);
+	usleep_range(2, 10);
+
+	/* Release from reset and wait for at least 200us (eMMC spec requirement) */
+	sdhci_writeb(host, val & ~BIT(4), SDHCI_POWER_CONTROL);
+	usleep_range(250, 300);
+}
+
 static const struct sdhci_ops sdhci_iproc_ops = {
 	.set_clock = sdhci_set_clock,
 	.get_max_clock = sdhci_iproc_get_max_clock,
 	.set_bus_width = sdhci_set_bus_width,
 	.reset = sdhci_reset,
 	.set_uhs_signaling = sdhci_set_uhs_signaling,
+	.hw_reset = sdhci_iproc_hw_reset,
 };
 
 static const struct sdhci_ops sdhci_iproc_32only_ops = {
@@ -201,6 +215,7 @@ static const struct sdhci_ops sdhci_iproc_32only_ops = {
 	.set_bus_width = sdhci_set_bus_width,
 	.reset = sdhci_reset,
 	.set_uhs_signaling = sdhci_set_uhs_signaling,
+	.hw_reset = sdhci_iproc_hw_reset,
 };
 
 static const struct sdhci_pltfm_data sdhci_iproc_cygnus_pltfm_data = {
@@ -283,6 +298,7 @@ static const struct sdhci_ops sdhci_iproc_bcm2711_ops = {
 	.set_bus_width = sdhci_set_bus_width,
 	.reset = sdhci_reset,
 	.set_uhs_signaling = sdhci_set_uhs_signaling,
+	.hw_reset = sdhci_iproc_hw_reset,
 };
 
 static const struct sdhci_pltfm_data sdhci_bcm2711_pltfm_data = {
-- 
2.49.0



^ permalink raw reply related

* Re: [PATCH] media: rockchip: Disable VIDEO_ROCKCHIP_VDEC when compile testing for Hexagon
From: Nathan Chancellor @ 2026-03-27 22:11 UTC (permalink / raw)
  To: Nicolas Dufresne
  Cc: Detlev Casanova, Ezequiel Garcia, Mauro Carvalho Chehab,
	Heiko Stuebner, Brian Cain, Nick Desaulniers, Bill Wendling,
	Justin Stitt, linux-media, linux-rockchip, linux-arm-kernel,
	linux-kernel, linux-hexagon, llvm
In-Reply-To: <1a618af9b6c311e8fe5db64ff6fb7c1872c7b2b6.camel@ndufresne.ca>

On Thu, Mar 19, 2026 at 04:08:29PM -0400, Nicolas Dufresne wrote:
> I haven't heard back about the port to plain bitwriter. I guess I have to pick
> this patch, but I really don't want to have to maintain too many of these hacks.
> Anyone else with an opinion on the topic ? Or a better idea how this can be
> workaround differently ?

I ended up retesting this recently after I saw Denis posted a bitwriter
series and it turns out that Arnd's commit 446c6a25a449 ("media: rkvdec:
reduce excessive stack usage in assemble_hw_pps()") is enough to avoid
this issue, so you can disregard this change.

Cheers,
Nathan


^ permalink raw reply

* [PATCH] media: aspeed: fix missing of_reserved_mem_device_release() on probe failure
From: David Carlier @ 2026-03-27 22:08 UTC (permalink / raw)
  To: eajames, mchehab
  Cc: joel, andrew, hverkuil, linux-media, openbmc, linux-arm-kernel,
	linux-aspeed, linux-kernel, David Carlier

aspeed_video_init() calls of_reserved_mem_device_init() to associate
reserved memory regions with the device. When aspeed_video_setup_video()
subsequently fails in aspeed_video_probe(), the error path frees the
JPEG buffer and unprepares the clocks but does not release the reserved
memory association, leaking the rmem_assigned_device entry on the global
list.

The normal remove path already calls of_reserved_mem_device_release()
correctly; only the probe error path was missing it.

Add the missing of_reserved_mem_device_release() call to the
aspeed_video_setup_video() failure cleanup.

Fixes: d2b4387f3bdf ("media: aspeed: Add Aspeed Video Engine driver")
Signed-off-by: David Carlier <devnexen@gmail.com>
---
 drivers/media/platform/aspeed/aspeed-video.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platform/aspeed/aspeed-video.c
index 41cb96f60110..a292275f6b7b 100644
--- a/drivers/media/platform/aspeed/aspeed-video.c
+++ b/drivers/media/platform/aspeed/aspeed-video.c
@@ -2343,6 +2343,7 @@ static int aspeed_video_probe(struct platform_device *pdev)
 	rc = aspeed_video_setup_video(video);
 	if (rc) {
 		aspeed_video_free_buf(video, &video->jpeg);
+		of_reserved_mem_device_release(&pdev->dev);
 		clk_unprepare(video->vclk);
 		clk_unprepare(video->eclk);
 		return rc;
-- 
2.53.0



^ permalink raw reply related

* [PATCH] mailbox: Fix NULL message support in mbox_send_message()
From: jassisinghbrar @ 2026-03-27 22:00 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: dianders, shawn.guo, maz, andersson, tglx, joonwonkang,
	Jassi Brar

From: Jassi Brar <jassisinghbrar@gmail.com>

The active_req field serves double duty as both the "is a TX in
flight" flag (NULL means idle) and the storage for the in-flight
message pointer. When a client sends NULL via mbox_send_message(),
active_req is set to NULL, which the framework misinterprets as
"no active request". This breaks the TX state machine by:

 - tx_tick() short-circuits on (!mssg), skipping the tx_done
   callback and the tx_complete completion
 - txdone_hrtimer() skips the channel entirely since active_req
   is NULL, so poll-based TX-done detection never fires.

Fix this by introducing a MBOX_NO_MSG sentinel value that means
"no active request," freeing NULL to be valid message data. The
sentinel is defined in the subsystem-internal mailbox.h so that
controller drivers within drivers/mailbox/ can reference it, but
it is not exposed to clients outside the subsystem.

Fifteen in-tree callers send NULL (doorbell-style IPCs on Qualcomm,
Tegra, TI, Xilinx, i.MX, SCMI, and PCC platforms). All were
audited for regression:

 - Most already work around the bug via knows_txdone=true with a
   manual mbox_client_txdone() call, making the framework's
   tracking irrelevant. These are unaffected.

 - Poll-based callers (Xilinx zynqmp/r5) are strictly better off:
   the poll timer now correctly detects NULL-active channels
   instead of silently skipping them.

 - irq-qcom-mpm.c was a pre-existing bug -- the only Qualcomm
   caller that omitted the knows_txdone + mbox_client_txdone()
   pattern. Fixed in a companion commit ("irqchip/qcom-mpm: Fix
   missing mailbox TX done acknowledgment").

 - No caller sets both a tx_done callback and sends NULL, nor
   combines tx_block=true with NULL sends, so the newly reachable
   callback/completion paths are never exercised.

Also update tegra-hsp's flush callback, which directly inspects
active_req to wait for the channel to drain: the old "!= NULL"
check becomes "!= MBOX_NO_MSG", otherwise flush spins until
timeout since the sentinel is non-NULL.

The only tradeoff is that 'MBOX_NO_MSG' can not be used as a message
by clients.

Reported-by: Joonwon Kang <joonwonkang@google.com>
Reviewed-by: Douglas Anderson <dianders@chromium.org>
Signed-off-by: Jassi Brar <jassisinghbrar@gmail.com>
---
 drivers/mailbox/mailbox.c   | 15 ++++++++-------
 drivers/mailbox/mailbox.h   |  3 +++
 drivers/mailbox/tegra-hsp.c |  2 +-
 3 files changed, 12 insertions(+), 8 deletions(-)

diff --git a/drivers/mailbox/mailbox.c b/drivers/mailbox/mailbox.c
index 617ba505691d..9622369cab66 100644
--- a/drivers/mailbox/mailbox.c
+++ b/drivers/mailbox/mailbox.c
@@ -52,7 +52,7 @@ static void msg_submit(struct mbox_chan *chan)
 	int err = -EBUSY;
 
 	scoped_guard(spinlock_irqsave, &chan->lock) {
-		if (!chan->msg_count || chan->active_req)
+		if (!chan->msg_count || chan->active_req != MBOX_NO_MSG)
 			break;
 
 		count = chan->msg_count;
@@ -87,13 +87,13 @@ static void tx_tick(struct mbox_chan *chan, int r)
 
 	scoped_guard(spinlock_irqsave, &chan->lock) {
 		mssg = chan->active_req;
-		chan->active_req = NULL;
+		chan->active_req = MBOX_NO_MSG;
 	}
 
 	/* Submit next message */
 	msg_submit(chan);
 
-	if (!mssg)
+	if (mssg == MBOX_NO_MSG)
 		return;
 
 	/* Notify the client */
@@ -114,7 +114,7 @@ static enum hrtimer_restart txdone_hrtimer(struct hrtimer *hrtimer)
 	for (i = 0; i < mbox->num_chans; i++) {
 		struct mbox_chan *chan = &mbox->chans[i];
 
-		if (chan->active_req && chan->cl) {
+		if (chan->active_req != MBOX_NO_MSG && chan->cl) {
 			txdone = chan->mbox->ops->last_tx_done(chan);
 			if (txdone)
 				tx_tick(chan, 0);
@@ -246,7 +246,7 @@ int mbox_send_message(struct mbox_chan *chan, void *mssg)
 {
 	int t;
 
-	if (!chan || !chan->cl)
+	if (!chan || !chan->cl || mssg == MBOX_NO_MSG)
 		return -EINVAL;
 
 	t = add_to_rbuf(chan, mssg);
@@ -319,7 +319,7 @@ static int __mbox_bind_client(struct mbox_chan *chan, struct mbox_client *cl)
 	scoped_guard(spinlock_irqsave, &chan->lock) {
 		chan->msg_free = 0;
 		chan->msg_count = 0;
-		chan->active_req = NULL;
+		chan->active_req = MBOX_NO_MSG;
 		chan->cl = cl;
 		init_completion(&chan->tx_complete);
 
@@ -477,7 +477,7 @@ void mbox_free_channel(struct mbox_chan *chan)
 	/* The queued TX requests are simply aborted, no callbacks are made */
 	scoped_guard(spinlock_irqsave, &chan->lock) {
 		chan->cl = NULL;
-		chan->active_req = NULL;
+		chan->active_req = MBOX_NO_MSG;
 		if (chan->txdone_method == TXDONE_BY_ACK)
 			chan->txdone_method = TXDONE_BY_POLL;
 	}
@@ -532,6 +532,7 @@ int mbox_controller_register(struct mbox_controller *mbox)
 
 		chan->cl = NULL;
 		chan->mbox = mbox;
+		chan->active_req = MBOX_NO_MSG;
 		chan->txdone_method = txdone;
 		spin_lock_init(&chan->lock);
 	}
diff --git a/drivers/mailbox/mailbox.h b/drivers/mailbox/mailbox.h
index e1ec4efab693..c77dd6fc5b8a 100644
--- a/drivers/mailbox/mailbox.h
+++ b/drivers/mailbox/mailbox.h
@@ -5,6 +5,9 @@
 
 #include <linux/bits.h>
 
+/* Sentinel value distinguishing "no active request" from "NULL message data" */
+#define MBOX_NO_MSG	((void *)-1)
+
 #define TXDONE_BY_IRQ	BIT(0) /* controller has remote RTR irq */
 #define TXDONE_BY_POLL	BIT(1) /* controller can read status of last TX */
 #define TXDONE_BY_ACK	BIT(2) /* S/W ACK received by Client ticks the TX */
diff --git a/drivers/mailbox/tegra-hsp.c b/drivers/mailbox/tegra-hsp.c
index ed9a0bb2bcd8..7991e8dba579 100644
--- a/drivers/mailbox/tegra-hsp.c
+++ b/drivers/mailbox/tegra-hsp.c
@@ -497,7 +497,7 @@ static int tegra_hsp_mailbox_flush(struct mbox_chan *chan,
 			mbox_chan_txdone(chan, 0);
 
 			/* Wait until channel is empty */
-			if (chan->active_req != NULL)
+			if (chan->active_req != MBOX_NO_MSG)
 				continue;
 
 			return 0;
-- 
2.52.0



^ permalink raw reply related

* [PATCH v5 6/7] arm64: dts: imx8mp-evk: add board-level mux for CAN2 and MICFIL
From: Frank Li @ 2026-03-27 21:34 UTC (permalink / raw)
  To: Peter Rosin, Linus Walleij, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Rafał Miłecki, Sascha Hauer,
	Pengutronix Kernel Team, Fabio Estevam
  Cc: linux-kernel, linux-gpio, devicetree, imx, linux-arm-kernel,
	Haibo Chen, Frank Li, Ahmad Fatoum
In-Reply-To: <20260327-pinctrl-mux-v5-0-d4aec9d62c62@nxp.com>

The board integrates an on-board mux to route shared signals to either
CAN2 or PDM (MICFIL). The mux is controlled by a GPIO.

Add a pinctrl-based multiplexer node to describe this routing and ensure
proper probe ordering of the dependent devices.

Previously, MICFIL operation implicitly depended on the default level of
PCA6416 GPIO3. After adding the pinctrl-multiplexer, make the dependency
explicit.

Reviewed-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
change in v3 - v4
- none
change in v2
- update commit message to show why need update PDM MICIFL.
---
 arch/arm64/boot/dts/freescale/imx8mp-evk.dts | 23 +++++++++++++++++++++--
 1 file changed, 21 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/boot/dts/freescale/imx8mp-evk.dts b/arch/arm64/boot/dts/freescale/imx8mp-evk.dts
index b256be710ea1281465f5cecc7a3b979f2c068e43..1341ee27239fd41a26117adc9023524ce50420a7 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-evk.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mp-evk.dts
@@ -50,6 +50,25 @@ status {
 		};
 	};
 
+	can_mux: mux-controller-0 {
+		compatible = "gpio-mux";
+		#mux-control-cells = <0>;
+		#mux-state-cells = <1>;
+		mux-gpios = <&pca6416 3 GPIO_ACTIVE_HIGH>;
+	};
+
+	can_mux_pinctrl: pinctrl-gpiomux {
+		compatible = "pinctrl-multiplexer";
+
+		can_fun: can-grp {
+			mux-states = <&can_mux 1>;
+		};
+
+		pdm_fun: pdm-grp {
+			mux-states = <&can_mux 0>;
+		};
+	};
+
 	memory@40000000 {
 		device_type = "memory";
 		reg = <0x0 0x40000000 0 0xc0000000>,
@@ -446,7 +465,7 @@ &flexcan1 {
 
 &flexcan2 {
 	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_flexcan2>;
+	pinctrl-0 = <&pinctrl_flexcan2>, <&can_fun>;
 	phys = <&flexcan_phy 1>;
 	status = "disabled";/* can2 pin conflict with pdm */
 };
@@ -712,7 +731,7 @@ &lcdif3 {
 &micfil {
 	#sound-dai-cells = <0>;
 	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_pdm>;
+	pinctrl-0 = <&pinctrl_pdm>, <&pdm_fun>;
 	assigned-clocks = <&clk IMX8MP_CLK_PDM>;
 	assigned-clock-parents = <&clk IMX8MP_AUDIO_PLL1_OUT>;
 	assigned-clock-rates = <196608000>;

-- 
2.43.0



^ permalink raw reply related

* [PATCH v5 5/7] pinctrl: add generic board-level pinctrl driver using mux framework
From: Frank Li @ 2026-03-27 21:34 UTC (permalink / raw)
  To: Peter Rosin, Linus Walleij, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Rafał Miłecki, Sascha Hauer,
	Pengutronix Kernel Team, Fabio Estevam
  Cc: linux-kernel, linux-gpio, devicetree, imx, linux-arm-kernel,
	Haibo Chen, Frank Li
In-Reply-To: <20260327-pinctrl-mux-v5-0-d4aec9d62c62@nxp.com>

Many boards use on-board mux chips (often controlled by GPIOs from an I2C
expander) to switch shared signals between peripherals.

Add a generic pinctrl driver built on top of the mux framework to
centralize mux handling and avoid probe ordering issues. Keep board-level
routing out of individual drivers and supports boot-time only mux
selection.

Ensure correct probe ordering, especially when the GPIO expander is probed
later.

Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
chagne in v4:
- use new pinctrl_generic_pins_to_map()

change in v3:
- use pinctrl_generic_pins_function_dt_node_to_map() and
pinctrl_utils_free_map().

change in v2:
- fix copywrite by add nxp
- fix if (!*map) check
- add release_mux to call mux_state_deselect()
---
 drivers/pinctrl/Kconfig               |   9 ++
 drivers/pinctrl/Makefile              |   1 +
 drivers/pinctrl/pinctrl-generic-mux.c | 197 ++++++++++++++++++++++++++++++++++
 3 files changed, 207 insertions(+)

diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index afecd9407f5354f5b92223f8cd80d2f7a08f8e7d..b6d4755e67510786c34f890c5e7a3fcf0adf45e4 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -274,6 +274,15 @@ config PINCTRL_GEMINI
 	select GENERIC_PINCONF
 	select MFD_SYSCON
 
+config PINCTRL_GENERIC_MUX
+	tristate "Generic Pinctrl driver by using multiplexer"
+	depends on MULTIPLEXER
+	select PINMUX
+	select GENERIC_PINCTRL
+	help
+          Generic pinctrl driver by MULTIPLEXER framework to control on
+          board pin selection.
+
 config PINCTRL_INGENIC
 	bool "Pinctrl driver for the Ingenic JZ47xx SoCs"
 	default MACH_INGENIC
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index f7d5d5f76d0c8becc0aa1d77c68b6ced924ea264..fcd1703440d24579636e8ddb6cbd83a0a982dfb7 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -29,6 +29,7 @@ obj-$(CONFIG_PINCTRL_EQUILIBRIUM)   += pinctrl-equilibrium.o
 obj-$(CONFIG_PINCTRL_EP93XX)	+= pinctrl-ep93xx.o
 obj-$(CONFIG_PINCTRL_EYEQ5)	+= pinctrl-eyeq5.o
 obj-$(CONFIG_PINCTRL_GEMINI)	+= pinctrl-gemini.o
+obj-$(CONFIG_PINCTRL_GENERIC_MUX) += pinctrl-generic-mux.o
 obj-$(CONFIG_PINCTRL_INGENIC)	+= pinctrl-ingenic.o
 obj-$(CONFIG_PINCTRL_K210)	+= pinctrl-k210.o
 obj-$(CONFIG_PINCTRL_K230)	+= pinctrl-k230.o
diff --git a/drivers/pinctrl/pinctrl-generic-mux.c b/drivers/pinctrl/pinctrl-generic-mux.c
new file mode 100644
index 0000000000000000000000000000000000000000..add3179f40a65d16e71b63442d62504ab1013540
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-generic-mux.c
@@ -0,0 +1,197 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Generic Pin Control Driver for Board-Level Mux Chips
+ * Copyright 2026 NXP
+ */
+
+#include <linux/cleanup.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/mutex.h>
+#include <linux/mux/consumer.h>
+#include <linux/platform_device.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/slab.h>
+
+#include "core.h"
+#include "pinconf.h"
+#include "pinmux.h"
+#include "pinctrl-utils.h"
+
+struct mux_pin_function {
+	struct mux_state *mux_state;
+};
+
+struct mux_pinctrl {
+	struct device *dev;
+	struct pinctrl_dev *pctl;
+
+	/* mutex protect [pinctrl|pinmux]_generic functions */
+	struct mutex lock;
+	int cur_select;
+};
+
+static int
+mux_pinmux_dt_node_to_map(struct pinctrl_dev *pctldev,
+			  struct device_node *np_config,
+			  struct pinctrl_map **maps, unsigned int *num_maps)
+{
+	unsigned int num_reserved_maps = 0;
+	struct mux_pin_function *function;
+	const char **group_names;
+	int ret;
+
+	function = devm_kzalloc(pctldev->dev, sizeof(*function), GFP_KERNEL);
+	if (!function)
+		return -ENOMEM;
+
+	group_names = devm_kcalloc(pctldev->dev, 1, sizeof(*group_names), GFP_KERNEL);
+	if (!group_names)
+		return -ENOMEM;
+
+	function->mux_state = devm_mux_state_get_from_np(pctldev->dev, NULL, np_config);
+	if (IS_ERR(function->mux_state))
+		return PTR_ERR(function->mux_state);
+
+	ret = pinctrl_generic_to_map(pctldev, np_config, np_config, maps,
+				     num_maps, &num_reserved_maps, group_names,
+				     0, &np_config->name, NULL, 0);
+
+	if (ret)
+		return ret;
+
+	ret = pinmux_generic_add_function(pctldev, np_config->name, group_names,
+					  1, function);
+	if (ret < 0) {
+		pinctrl_utils_free_map(pctldev, *maps, *num_maps);
+		return ret;
+	}
+
+	return 0;
+}
+
+static const struct pinctrl_ops mux_pinctrl_ops = {
+	.get_groups_count = pinctrl_generic_get_group_count,
+	.get_group_name = pinctrl_generic_get_group_name,
+	.get_group_pins = pinctrl_generic_get_group_pins,
+	.dt_node_to_map = mux_pinmux_dt_node_to_map,
+	.dt_free_map = pinctrl_utils_free_map,
+};
+
+static int mux_pinmux_set_mux(struct pinctrl_dev *pctldev,
+			      unsigned int func_selector,
+			      unsigned int group_selector)
+{
+	struct mux_pinctrl *mpctl = pinctrl_dev_get_drvdata(pctldev);
+	const struct function_desc *function;
+	struct mux_pin_function *func;
+	int ret;
+
+	guard(mutex)(&mpctl->lock);
+
+	function = pinmux_generic_get_function(pctldev, func_selector);
+	func = function->data;
+
+	if (mpctl->cur_select == func_selector)
+		return 0;
+
+	if (mpctl->cur_select >= 0 && mpctl->cur_select != func_selector)
+		return -EINVAL;
+
+	ret = mux_state_select(func->mux_state);
+	if (ret)
+		return ret;
+
+	mpctl->cur_select = func_selector;
+
+	return 0;
+}
+
+static void mux_pinmux_release_mux(struct pinctrl_dev *pctldev,
+				   unsigned int func_selector,
+				   unsigned int group_selector)
+{
+	struct mux_pinctrl *mpctl = pinctrl_dev_get_drvdata(pctldev);
+	const struct function_desc *function;
+	struct mux_pin_function *func;
+
+	guard(mutex)(&mpctl->lock);
+
+	function = pinmux_generic_get_function(pctldev, func_selector);
+	func = function->data;
+
+	mux_state_deselect(func->mux_state);
+
+	mpctl->cur_select = -1;
+}
+
+static const struct pinmux_ops mux_pinmux_ops = {
+	.get_functions_count = pinmux_generic_get_function_count,
+	.get_function_name = pinmux_generic_get_function_name,
+	.get_function_groups = pinmux_generic_get_function_groups,
+	.set_mux = mux_pinmux_set_mux,
+	.release_mux = mux_pinmux_release_mux,
+};
+
+static int mux_pinctrl_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct mux_pinctrl *mpctl;
+	struct pinctrl_desc *pctl_desc;
+	int ret;
+
+	mpctl = devm_kzalloc(dev, sizeof(*mpctl), GFP_KERNEL);
+	if (!mpctl)
+		return -ENOMEM;
+
+	mpctl->dev = dev;
+	mpctl->cur_select = -1;
+
+	platform_set_drvdata(pdev, mpctl);
+
+	pctl_desc = devm_kzalloc(dev, sizeof(*pctl_desc), GFP_KERNEL);
+	if (!pctl_desc)
+		return -ENOMEM;
+
+	ret = devm_mutex_init(dev, &mpctl->lock);
+	if (ret)
+		return ret;
+
+	pctl_desc->name = dev_name(dev);
+	pctl_desc->owner = THIS_MODULE;
+	pctl_desc->pctlops = &mux_pinctrl_ops;
+	pctl_desc->pmxops = &mux_pinmux_ops;
+
+	ret = devm_pinctrl_register_and_init(dev, pctl_desc, mpctl,
+					     &mpctl->pctl);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to register pinctrl.\n");
+
+	ret = pinctrl_enable(mpctl->pctl);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to enable pinctrl.\n");
+
+	return 0;
+}
+
+static const struct of_device_id mux_pinctrl_of_match[] = {
+	{ .compatible = "pinctrl-multiplexer" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, mux_pinctrl_of_match);
+
+static struct platform_driver mux_pinctrl_driver = {
+	.driver = {
+		.name = "generic-pinctrl-mux",
+		.of_match_table = mux_pinctrl_of_match,
+	},
+	.probe = mux_pinctrl_probe,
+};
+module_platform_driver(mux_pinctrl_driver);
+
+MODULE_AUTHOR("Frank Li <Frank.Li@nxp.com>");
+MODULE_DESCRIPTION("Generic Pin Control Driver for Board-Level Mux Chips");
+MODULE_LICENSE("GPL");
+

-- 
2.43.0



^ permalink raw reply related

* [PATCH v5 7/7] arm64: dts: imx8mp-evk: add flexcan2 overlay file
From: Frank Li @ 2026-03-27 21:34 UTC (permalink / raw)
  To: Peter Rosin, Linus Walleij, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Rafał Miłecki, Sascha Hauer,
	Pengutronix Kernel Team, Fabio Estevam
  Cc: linux-kernel, linux-gpio, devicetree, imx, linux-arm-kernel,
	Haibo Chen, Frank Li
In-Reply-To: <20260327-pinctrl-mux-v5-0-d4aec9d62c62@nxp.com>

Add flexcan2 overlay file, which enable flexcan2 node and disable micfil
node.

Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
change in v3-v4
- none
---
 arch/arm64/boot/dts/freescale/Makefile                 |  4 ++++
 arch/arm64/boot/dts/freescale/imx8mp-evk-flexcan2.dtso | 15 +++++++++++++++
 2 files changed, 19 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile
index 700bab4d3e6001fe6cf460fcb09cfe57acc77e36..bd377191a68a6167d5f9a65184d19c789a4223ee 100644
--- a/arch/arm64/boot/dts/freescale/Makefile
+++ b/arch/arm64/boot/dts/freescale/Makefile
@@ -233,6 +233,10 @@ dtb-$(CONFIG_ARCH_MXC) += imx8mp-dhcom-pdk3.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mp-dhcom-picoitx.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mp-edm-g-wb.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mp-evk.dtb
+
+imx8mp-evk-flexcan2-dtbs += imx8mp-evk.dtb imx8mp-evk-flexcan2.dtbo
+dtb-$(CONFIG_ARCH_MXC) += imx8mp-evk-flexcan2.dtb
+
 dtb-$(CONFIG_ARCH_MXC) += imx8mp-frdm.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mp-hummingboard-mate.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mp-hummingboard-pro.dtb
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-evk-flexcan2.dtso b/arch/arm64/boot/dts/freescale/imx8mp-evk-flexcan2.dtso
new file mode 100644
index 0000000000000000000000000000000000000000..f7d2674c45f72353a20300300e98c8a1eba4a2a6
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx8mp-evk-flexcan2.dtso
@@ -0,0 +1,15 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2026 NXP
+ */
+
+/dts-v1/;
+/plugin/;
+
+&flexcan2 {
+        status = "okay"; /* can2 pin conflict with pdm */
+};
+
+&micfil {
+        status = "disabled";
+};

-- 
2.43.0



^ permalink raw reply related

* [PATCH v5 3/7] pinctrl: extract pinctrl_generic_to_map() from pinctrl_generic_pins_function_dt_node_to_map()
From: Frank Li @ 2026-03-27 21:34 UTC (permalink / raw)
  To: Peter Rosin, Linus Walleij, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Rafał Miłecki, Sascha Hauer,
	Pengutronix Kernel Team, Fabio Estevam
  Cc: linux-kernel, linux-gpio, devicetree, imx, linux-arm-kernel,
	Haibo Chen, Frank Li, Conor Dooley
In-Reply-To: <20260327-pinctrl-mux-v5-0-d4aec9d62c62@nxp.com>

Refactor pinctrl_generic_pins_function_dt_subnode_to_map() by separating DT
parsing logic from map creation. Introduce a new helper
pinctrl_generic_to_map() to handle mapping to kernel data structures, while
keeping DT property parsing in the subnode function.

Improve code structure and enables easier reuse for platforms using
different DT properties (e.g. pinmux) without modifying the
dt_node_to_map-style callback API. Avoid unnecessary coupling to
pinctrl_generic_pins_function_dt_node_to_map(), which provides
functionality not needed when the phandle target is unambiguous.

Maximize code reuse and provide a cleaner extension point for future
pinctrl drivers.

Suggested-by: Conor Dooley <conor.dooley@microchip.com>
Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
change in v5
- add npins in pinctrl_generic_to_map();
- remove below line in pinctrl_generic_to_map();
pins = devm_kcalloc(dev, npins, sizeof(*pins), GFP_KERNEL);

change in v4
- new patch
---
 drivers/pinctrl/pinconf.h         | 18 ++++++++
 drivers/pinctrl/pinctrl-generic.c | 94 +++++++++++++++++++++++----------------
 2 files changed, 73 insertions(+), 39 deletions(-)

diff --git a/drivers/pinctrl/pinconf.h b/drivers/pinctrl/pinconf.h
index 2880adef476e68950ffdd540ea42cdee6a16ec27..67044dff61e4c2b2ccc0c10524b442d17f3ec42f 100644
--- a/drivers/pinctrl/pinconf.h
+++ b/drivers/pinctrl/pinconf.h
@@ -166,6 +166,13 @@ int pinctrl_generic_pins_function_dt_node_to_map(struct pinctrl_dev *pctldev,
 						 struct device_node *np,
 						 struct pinctrl_map **maps,
 						 unsigned int *num_maps);
+
+int pinctrl_generic_to_map(struct pinctrl_dev *pctldev, struct device_node *parent,
+			   struct device_node *np, struct pinctrl_map **maps,
+			   unsigned int *num_maps, unsigned int *num_reserved_maps,
+			   const char **group_name, unsigned int ngroups,
+			   const char **functions, unsigned int *pins,
+			   unsigned int npins);
 #else
 static inline int
 pinctrl_generic_pins_function_dt_node_to_map(struct pinctrl_dev *pctldev,
@@ -175,4 +182,15 @@ pinctrl_generic_pins_function_dt_node_to_map(struct pinctrl_dev *pctldev,
 {
 	return -ENOTSUPP;
 }
+
+static inline int
+pinctrl_generic_to_map(struct pinctrl_dev *pctldev, struct device_node *parent,
+		       struct device_node *np, struct pinctrl_map **maps,
+		       unsigned int *num_maps, unsigned int *num_reserved_maps,
+		       const char **group_name, unsigned int ngroups,
+		       const char **functions, unsigned int *pins,
+		       void *function_data)
+{
+	return -ENOTSUPP;
+}
 #endif
diff --git a/drivers/pinctrl/pinctrl-generic.c b/drivers/pinctrl/pinctrl-generic.c
index efb39c6a670331775855efdc8566102b5c6202ef..76670aef62da47ede2901f5af6199dcd2896d894 100644
--- a/drivers/pinctrl/pinctrl-generic.c
+++ b/drivers/pinctrl/pinctrl-generic.c
@@ -17,29 +17,18 @@
 #include "pinctrl-utils.h"
 #include "pinmux.h"
 
-static int pinctrl_generic_pins_function_dt_subnode_to_map(struct pinctrl_dev *pctldev,
-							   struct device_node *parent,
-							   struct device_node *np,
-							   struct pinctrl_map **maps,
-							   unsigned int *num_maps,
-							   unsigned int *num_reserved_maps,
-							   const char **group_names,
-							   unsigned int ngroups)
+int pinctrl_generic_to_map(struct pinctrl_dev *pctldev, struct device_node *parent,
+			   struct device_node *np, struct pinctrl_map **maps,
+			   unsigned int *num_maps, unsigned int *num_reserved_maps,
+			   const char **group_names, unsigned int ngroups,
+			   const char **functions, unsigned int *pins,
+			   unsigned int npins)
 {
 	struct device *dev = pctldev->dev;
-	const char **functions;
+	unsigned int num_configs;
 	const char *group_name;
 	unsigned long *configs;
-	unsigned int num_configs, pin, *pins;
-	int npins, ret, reserve = 1;
-
-	npins = of_property_count_u32_elems(np, "pins");
-
-	if (npins < 1) {
-		dev_err(dev, "invalid pinctrl group %pOFn.%pOFn %d\n",
-			parent, np, npins);
-		return npins;
-	}
+	int ret, reserve = 1;
 
 	group_name = devm_kasprintf(dev, GFP_KERNEL, "%pOFn.%pOFn", parent, np);
 	if (!group_name)
@@ -47,26 +36,6 @@ static int pinctrl_generic_pins_function_dt_subnode_to_map(struct pinctrl_dev *p
 
 	group_names[ngroups] = group_name;
 
-	pins = devm_kcalloc(dev, npins, sizeof(*pins), GFP_KERNEL);
-	if (!pins)
-		return -ENOMEM;
-
-	functions = devm_kcalloc(dev, npins, sizeof(*functions), GFP_KERNEL);
-	if (!functions)
-		return -ENOMEM;
-
-	for (int i = 0; i < npins; i++) {
-		ret = of_property_read_u32_index(np, "pins", i, &pin);
-		if (ret)
-			return ret;
-
-		pins[i] = pin;
-
-		ret = of_property_read_string(np, "function", &functions[i]);
-		if (ret)
-			return ret;
-	}
-
 	ret = pinctrl_utils_reserve_map(pctldev, maps, num_reserved_maps, num_maps, reserve);
 	if (ret)
 		return ret;
@@ -103,6 +72,53 @@ static int pinctrl_generic_pins_function_dt_subnode_to_map(struct pinctrl_dev *p
 	return 0;
 };
 
+static int pinctrl_generic_pins_function_dt_subnode_to_map(struct pinctrl_dev *pctldev,
+							   struct device_node *parent,
+							   struct device_node *np,
+							   struct pinctrl_map **maps,
+							   unsigned int *num_maps,
+							   unsigned int *num_reserved_maps,
+							   const char **group_names,
+							   unsigned int ngroups)
+{
+	struct device *dev = pctldev->dev;
+	unsigned int pin, *pins;
+	const char **functions;
+	int npins, ret;
+
+	npins = of_property_count_u32_elems(np, "pins");
+
+	if (npins < 1) {
+		dev_err(dev, "invalid pinctrl group %pOFn.%pOFn %d\n",
+			parent, np, npins);
+		return npins;
+	}
+
+	pins = devm_kcalloc(dev, npins, sizeof(*pins), GFP_KERNEL);
+	if (!pins)
+		return -ENOMEM;
+
+	functions = devm_kcalloc(dev, npins, sizeof(*functions), GFP_KERNEL);
+	if (!functions)
+		return -ENOMEM;
+
+	for (int i = 0; i < npins; i++) {
+		ret = of_property_read_u32_index(np, "pins", i, &pin);
+		if (ret)
+			return ret;
+
+		pins[i] = pin;
+
+		ret = of_property_read_string(np, "function", &functions[i]);
+		if (ret)
+			return ret;
+	}
+
+	return pinctrl_generic_to_map(pctldev, parent, np, maps, num_maps,
+				      num_reserved_maps, group_names, ngroups,
+				      functions, pins, npins);
+}
+
 /*
  * For platforms that do not define groups or functions in the driver, but
  * instead use the devicetree to describe them. This function will, unlike

-- 
2.43.0



^ permalink raw reply related

* [PATCH v5 4/7] pinctrl: add optional .release_mux() callback
From: Frank Li @ 2026-03-27 21:34 UTC (permalink / raw)
  To: Peter Rosin, Linus Walleij, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Rafał Miłecki, Sascha Hauer,
	Pengutronix Kernel Team, Fabio Estevam
  Cc: linux-kernel, linux-gpio, devicetree, imx, linux-arm-kernel,
	Haibo Chen, Frank Li
In-Reply-To: <20260327-pinctrl-mux-v5-0-d4aec9d62c62@nxp.com>

Add an optional .release_mux() callback to struct pinmux_ops.

Some drivers acquire additional resources in .set_mux(), such as software
locks. These resources may need to be released when the mux function is no
longer active. Introducing a dedicated .release_mux() callback allows
drivers to clean up such resources.

The callback is optional and does not affect existing drivers.

Commit 2243a87d90b42 ("pinctrl: avoid duplicated calling
enable_pinmux_setting for a pin") removed the .disable() callback
to resolve two issues:

  1. desc->mux_usecount increasing monotonically
  2. Hardware glitches caused by repeated .disable()/.enable() calls

Adding .release_mux() does not reintroduce those problems. The callback is
intended only for releasing driver-side resources (e.g. locks) and must not
modify hardware registers.

Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
change in v4
- none

change in v3
- Add judgement about 2243a87d90b42 ("pinctrl: avoid duplicated calling
enable_pinmux_setting for a pin") in commit message.
---
 drivers/pinctrl/pinmux.c       | 5 +++++
 include/linux/pinctrl/pinmux.h | 5 +++++
 2 files changed, 10 insertions(+)

diff --git a/drivers/pinctrl/pinmux.c b/drivers/pinctrl/pinmux.c
index 3a8dd184ba3d670e01a890427e19af59b65eb813..c705bc182266c596c4e6c820f5e3ffcadbbb2838 100644
--- a/drivers/pinctrl/pinmux.c
+++ b/drivers/pinctrl/pinmux.c
@@ -517,6 +517,7 @@ void pinmux_disable_setting(const struct pinctrl_setting *setting)
 {
 	struct pinctrl_dev *pctldev = setting->pctldev;
 	const struct pinctrl_ops *pctlops = pctldev->desc->pctlops;
+	const struct pinmux_ops *ops = pctldev->desc->pmxops;
 	int ret = 0;
 	const unsigned int *pins = NULL;
 	unsigned int num_pins = 0;
@@ -563,6 +564,10 @@ void pinmux_disable_setting(const struct pinctrl_setting *setting)
 				 pins[i], desc->name, gname);
 		}
 	}
+
+	if (ops->release_mux)
+		ops->release_mux(pctldev, setting->data.mux.func,
+				 setting->data.mux.group);
 }
 
 #ifdef CONFIG_DEBUG_FS
diff --git a/include/linux/pinctrl/pinmux.h b/include/linux/pinctrl/pinmux.h
index 094bbe2fd6fd5ea3c5fdf5b6d6d9a7639700b50b..77664937eeb273eef440988c4cf833dbc6f10758 100644
--- a/include/linux/pinctrl/pinmux.h
+++ b/include/linux/pinctrl/pinmux.h
@@ -51,6 +51,8 @@ struct pinctrl_gpio_range;
  *	are handled by the pinmux subsystem. The @func_selector selects a
  *	certain function whereas @group_selector selects a certain set of pins
  *	to be used. On simple controllers the latter argument may be ignored
+ * @release_mux: Release software resources acquired by @set_mux. This callback
+ *	must not change hardware state to avoid glitches when switching mux.
  * @gpio_request_enable: requests and enables GPIO on a certain pin.
  *	Implement this only if you can mux every pin individually as GPIO. The
  *	affected GPIO range is passed along with an offset(pin number) into that
@@ -80,6 +82,9 @@ struct pinmux_ops {
 				  unsigned int selector);
 	int (*set_mux) (struct pinctrl_dev *pctldev, unsigned int func_selector,
 			unsigned int group_selector);
+	void (*release_mux) (struct pinctrl_dev *pctldev,
+			     unsigned int func_selector,
+			     unsigned int group_selector);
 	int (*gpio_request_enable) (struct pinctrl_dev *pctldev,
 				    struct pinctrl_gpio_range *range,
 				    unsigned int offset);

-- 
2.43.0



^ permalink raw reply related

* [PATCH v5 2/7] dt-bindings: pinctrl: Add generic pinctrl for board-level mux chips
From: Frank Li @ 2026-03-27 21:33 UTC (permalink / raw)
  To: Peter Rosin, Linus Walleij, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Rafał Miłecki, Sascha Hauer,
	Pengutronix Kernel Team, Fabio Estevam
  Cc: linux-kernel, linux-gpio, devicetree, imx, linux-arm-kernel,
	Haibo Chen, Frank Li
In-Reply-To: <20260327-pinctrl-mux-v5-0-d4aec9d62c62@nxp.com>

Add a generic pinctrl binding for board-level pinmux chips that are
controlled through the multiplexer subsystem.

On some boards, especially development boards, external mux chips are used
to switch SoC signals between different peripherals (e.g. MMC and UART).
The mux select lines are often driven by a GPIO expander over I2C,
as illustrated below:

	┌──────┐      ┌─────┐
	│ SOC  │      │     │    ┌───────┐
	│      │      │     │───►│ MMC   │
	│      │      │ MUX │    └───────┘
	│      ├─────►│     │    ┌───────┐
	│      │      │     │───►│ UART  │
	│      │      └─────┘    └───────┘
	│      │         ▲
	│      │    ┌────┴──────────────┐
	│ I2C  ├───►│ GPIO Expander     │
	└──────┘    └───────────────────┘

Traditionally, gpio-hog is used to configure the onboard mux at boot.
However, the GPIO expander may probe later than consumer devices such as
MMC. As a result, the MUX might not be configured when the peripheral
driver probes, leading to initialization failures or data transfer errors.

Introduce a generic pinctrl binding that models the board-level MUX as a
pin control provider and builds proper device links between the MUX, its
GPIO controller, and peripheral devices. This ensures correct probe
ordering and reliable mux configuration.

The implementation leverages the standard multiplexer subsystem, which
provides broad support for onboard mux controllers and avoids the need for
per-driver custom MUX handling.

Allow pinctrl-* pattern as node name because this pinctrl device have not
reg property.

Reviewed-by: Linus Walleij <linusw@kernel.org>
Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
Change in v4
- add Linus Walleij's review by tags

change in v3:
- collect rob's reviewed-by tag.

change in v2:
 - change descriptions for device, not for driver
 - add missed additionalProperties: false
---
 .../bindings/pinctrl/pinctrl-multiplexer.yaml      | 57 ++++++++++++++++++++++
 .../devicetree/bindings/pinctrl/pinctrl.yaml       |  2 +-
 2 files changed, 58 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-multiplexer.yaml b/Documentation/devicetree/bindings/pinctrl/pinctrl-multiplexer.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..2b0385ed879b70b24ca9c39b098c3840d08d7482
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-multiplexer.yaml
@@ -0,0 +1,57 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pinctrl/pinctrl-multiplexer.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Generic pinctrl device for on-board MUX Chips
+
+maintainers:
+  - Frank Li <Frank.Li@nxp.com>
+
+description:
+  Generic pinctrl device for on-board MUX Chips, which switch SoC signals
+  between different peripherals (e.g. MMC and UART).
+
+  The MUX select lines are often driven by a I2C GPIO expander.
+
+properties:
+  compatible:
+    const: pinctrl-multiplexer
+
+patternProperties:
+  '-grp$':
+    type: object
+    additionalProperties: false
+    properties:
+      mux-states:
+        maxItems: 1
+
+    required:
+      - mux-states
+
+required:
+  - compatible
+
+allOf:
+  - $ref: pinctrl.yaml#
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    pinctrl-mux {
+        compatible = "pinctrl-multiplexer";
+
+        uart-grp {
+            mux-states = <&mux 0>;
+        };
+
+        spi-grp {
+            mux-states = <&mux 1>;
+        };
+
+        i2c-grp {
+            mux-states = <&mux 2>;
+        };
+    };
diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/pinctrl.yaml
index 290438826c507ec6725f486d18cf686aa7c35e67..20176bf3074757de30f208e69b968a6bd6125273 100644
--- a/Documentation/devicetree/bindings/pinctrl/pinctrl.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/pinctrl.yaml
@@ -27,7 +27,7 @@ description: |
 
 properties:
   $nodename:
-    pattern: "^(pinctrl|pinmux)(@[0-9a-f]+)?$"
+    pattern: "^(pinctrl|pinmux)(@[0-9a-f]+|-[a-z0-9]+)?$"
 
   "#pinctrl-cells":
     description: >

-- 
2.43.0



^ permalink raw reply related

* [PATCH v5 1/7] mux: add devm_mux_control_get_from_np() to get mux from child node
From: Frank Li @ 2026-03-27 21:33 UTC (permalink / raw)
  To: Peter Rosin, Linus Walleij, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Rafał Miłecki, Sascha Hauer,
	Pengutronix Kernel Team, Fabio Estevam
  Cc: linux-kernel, linux-gpio, devicetree, imx, linux-arm-kernel,
	Haibo Chen, Frank Li
In-Reply-To: <20260327-pinctrl-mux-v5-0-d4aec9d62c62@nxp.com>

Add new API devm_mux_control_get_from_np() to retrieve a mux control from
a specified child device node.

Make devm_mux_control_get() call devm_mux_control_get_from_np() with a NULL
node parameter, which defaults to using the device's own of_node.

Support the following DT schema:

pinctrl@0 {
    uart-func {
            mux-state = <&mux_chip 0>;
    };

    spi-func {
            mux-state = <&mux_chip 1>;
    };
};

Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
change from v1 to v4
- none
---
 drivers/mux/core.c           | 40 ++++++++++++++++++++++++----------------
 include/linux/mux/consumer.h | 16 ++++++++++++----
 2 files changed, 36 insertions(+), 20 deletions(-)

diff --git a/drivers/mux/core.c b/drivers/mux/core.c
index a3840fe0995fe0125432d34edd8ab0f2cd1a6e9a..bdd959389b4ee1b0b8a7367fadf2c148c8f2f0b1 100644
--- a/drivers/mux/core.c
+++ b/drivers/mux/core.c
@@ -522,13 +522,15 @@ static struct mux_chip *of_find_mux_chip_by_node(struct device_node *np)
  * @mux_name: The name identifying the mux-control.
  * @state: Pointer to where the requested state is returned, or NULL when
  *         the required multiplexer states are handled by other means.
+ * @node: the device nodes, use dev->of_node if it is NULL.
  *
  * Return: A pointer to the mux-control, or an ERR_PTR with a negative errno.
  */
 static struct mux_control *mux_get(struct device *dev, const char *mux_name,
-				   unsigned int *state)
+				   unsigned int *state,
+				   struct device_node *node)
 {
-	struct device_node *np = dev->of_node;
+	struct device_node *np = node ? node : dev->of_node;
 	struct of_phandle_args args;
 	struct mux_chip *mux_chip;
 	unsigned int controller;
@@ -617,7 +619,7 @@ static struct mux_control *mux_get(struct device *dev, const char *mux_name,
  */
 struct mux_control *mux_control_get(struct device *dev, const char *mux_name)
 {
-	return mux_get(dev, mux_name, NULL);
+	return mux_get(dev, mux_name, NULL, NULL);
 }
 EXPORT_SYMBOL_GPL(mux_control_get);
 
@@ -641,15 +643,17 @@ static void devm_mux_control_release(struct device *dev, void *res)
 }
 
 /**
- * devm_mux_control_get() - Get the mux-control for a device, with resource
- *			    management.
+ * devm_mux_control_get_from_np() - Get the mux-control for a device, with
+ *				    resource management.
  * @dev: The device that needs a mux-control.
  * @mux_name: The name identifying the mux-control.
+ * @np: the device nodes, use dev->of_node if it is NULL.
  *
  * Return: Pointer to the mux-control, or an ERR_PTR with a negative errno.
  */
-struct mux_control *devm_mux_control_get(struct device *dev,
-					 const char *mux_name)
+struct mux_control *
+devm_mux_control_get_from_np(struct device *dev, const char *mux_name,
+			     struct device_node *np)
 {
 	struct mux_control **ptr, *mux;
 
@@ -668,16 +672,18 @@ struct mux_control *devm_mux_control_get(struct device *dev,
 
 	return mux;
 }
-EXPORT_SYMBOL_GPL(devm_mux_control_get);
+EXPORT_SYMBOL_GPL(devm_mux_control_get_from_np);
 
 /*
  * mux_state_get() - Get the mux-state for a device.
  * @dev: The device that needs a mux-state.
  * @mux_name: The name identifying the mux-state.
+ * @np: the device nodes, use dev->of_node if it is NULL.
  *
  * Return: A pointer to the mux-state, or an ERR_PTR with a negative errno.
  */
-static struct mux_state *mux_state_get(struct device *dev, const char *mux_name)
+static struct mux_state *
+mux_state_get(struct device *dev, const char *mux_name, struct device_node *np)
 {
 	struct mux_state *mstate;
 
@@ -685,7 +691,7 @@ static struct mux_state *mux_state_get(struct device *dev, const char *mux_name)
 	if (!mstate)
 		return ERR_PTR(-ENOMEM);
 
-	mstate->mux = mux_get(dev, mux_name, &mstate->state);
+	mstate->mux = mux_get(dev, mux_name, &mstate->state, np);
 	if (IS_ERR(mstate->mux)) {
 		int err = PTR_ERR(mstate->mux);
 
@@ -716,15 +722,17 @@ static void devm_mux_state_release(struct device *dev, void *res)
 }
 
 /**
- * devm_mux_state_get() - Get the mux-state for a device, with resource
- *			  management.
+ * devm_mux_state_get_from_np() - Get the mux-state for a device, with resource
+ *				  management.
  * @dev: The device that needs a mux-control.
  * @mux_name: The name identifying the mux-control.
+ * @np: the device nodes, use dev->of_node if it is NULL.
  *
  * Return: Pointer to the mux-state, or an ERR_PTR with a negative errno.
  */
-struct mux_state *devm_mux_state_get(struct device *dev,
-				     const char *mux_name)
+struct mux_state *
+devm_mux_state_get_from_np(struct device *dev, const char *mux_name,
+			   struct device_node *np)
 {
 	struct mux_state **ptr, *mstate;
 
@@ -732,7 +740,7 @@ struct mux_state *devm_mux_state_get(struct device *dev,
 	if (!ptr)
 		return ERR_PTR(-ENOMEM);
 
-	mstate = mux_state_get(dev, mux_name);
+	mstate = mux_state_get(dev, mux_name, np);
 	if (IS_ERR(mstate)) {
 		devres_free(ptr);
 		return mstate;
@@ -743,7 +751,7 @@ struct mux_state *devm_mux_state_get(struct device *dev,
 
 	return mstate;
 }
-EXPORT_SYMBOL_GPL(devm_mux_state_get);
+EXPORT_SYMBOL_GPL(devm_mux_state_get_from_np);
 
 /*
  * Using subsys_initcall instead of module_init here to try to ensure - for
diff --git a/include/linux/mux/consumer.h b/include/linux/mux/consumer.h
index 2e25c838f8312532040441ee618424b76378aad7..6300e091035323dd6158d52a55a109d43ef120aa 100644
--- a/include/linux/mux/consumer.h
+++ b/include/linux/mux/consumer.h
@@ -56,9 +56,17 @@ int mux_state_deselect(struct mux_state *mstate);
 struct mux_control *mux_control_get(struct device *dev, const char *mux_name);
 void mux_control_put(struct mux_control *mux);
 
-struct mux_control *devm_mux_control_get(struct device *dev,
-					 const char *mux_name);
-struct mux_state *devm_mux_state_get(struct device *dev,
-				     const char *mux_name);
+struct mux_control *
+devm_mux_control_get_from_np(struct device *dev, const char *mux_name,
+			     struct device_node *np);
+
+#define devm_mux_control_get(dev, mux_name)		\
+	devm_mux_control_get_from_np(dev, mux_name, NULL)
+
+struct mux_state *
+devm_mux_state_get_from_np(struct device *dev, const char *mux_name,
+			   struct device_node *np);
+#define devm_mux_state_get(dev, mux_name)		\
+	devm_mux_state_get_from_np(dev, mux_name, NULL)
 
 #endif /* _LINUX_MUX_CONSUMER_H */

-- 
2.43.0



^ permalink raw reply related

* [PATCH v5 0/7] pinctrl: Add generic pinctrl for board-level mux chips
From: Frank Li @ 2026-03-27 21:33 UTC (permalink / raw)
  To: Peter Rosin, Linus Walleij, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Rafał Miłecki, Sascha Hauer,
	Pengutronix Kernel Team, Fabio Estevam
  Cc: linux-kernel, linux-gpio, devicetree, imx, linux-arm-kernel,
	Haibo Chen, Frank Li, Conor Dooley, Ahmad Fatoum

Add a generic pinctrl binding for board-level pinmux chips that are
controlled through the multiplexer subsystem.

On some boards, especially development boards, external mux chips are used
to switch SoC signals between different peripherals (e.g. MMC and UART).
The mux select lines are often driven by a GPIO expander over I2C,
as illustrated below:

        ┌──────┐      ┌─────┐
        │ SOC  │      │     │    ┌───────┐
        │      │      │     │───►│ MMC   │
        │      │      │ MUX │    └───────┘
        │      ├─────►│     │    ┌───────┐
        │      │      │     │───►│ UART  │
        │      │      └─────┘    └───────┘
        │      │         ▲
        │      │    ┌────┴──────────────┐
        │ I2C  ├───►│ GPIO Expander     │
        └──────┘    └───────────────────┘

Traditionally, gpio-hog is used to configure the onboard mux at boot.
However, the GPIO expander may probe later than consumer devices such as
MMC. As a result, the MUX might not be configured when the peripheral
driver probes, leading to initialization failures or data transfer errors.

Introduce a generic pinctrl binding that models the board-level MUX as a
pin control provider and builds proper device links between the MUX, its
GPIO controller, and peripheral devices. This ensures correct probe
ordering and reliable mux configuration.

The implementation leverages the standard multiplexer subsystem, which
provides broad support for onboard mux controllers and avoids the need for
per-driver custom MUX handling

Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
Changes in v5:
- add npins to pinctrl_generic_to_map()
- remove pins = kmalloc() in pinctrl_generic_to_map().
- Link to v4: https://lore.kernel.org/r/20260325-pinctrl-mux-v4-0-043c2c82e623@nxp.com

Changes in v4:
- use Conor Dooley suggest to extract funciton pinctrl_generic_pins_to_map()
- Link to v3: https://lore.kernel.org/r/20260311-pinctrl-mux-v3-0-236b1c17bf9b@nxp.com

Changes in v3:
- collect rob's review tag for binding
- extend and use pinctrl_generic_pins_function_dt_node_to_map()
- add judgement about
commit 2243a87d90b42eb38bc281957df3e57c712b5e56
"pinctrl: avoid duplicated calling enable_pinmux_setting for a pin"

which call pinmux_disable_setting() before pinmux_enable_setting() when
switch state. It is actually what wanted. Previous remove .disable() to
avoid hardware glitch when switch state.

New .release_mux() call intent just release software resource, like lock,
don't touch hardware register. No glitch involve. Comments already added

Linus Walleij:
  I hope this answer all of your questions. If I missed, let me know

- Link to v2: https://lore.kernel.org/r/20260225-pinctrl-mux-v2-0-1436a25fa454@nxp.com

Changes in v2:
- Add release_mux callback,
  test insmod/rmmod, mux_state_(de)select() called.
- Link to v1: https://lore.kernel.org/r/20260219-pinctrl-mux-v1-0-678d21637788@nxp.com

---
Frank Li (7):
      mux: add devm_mux_control_get_from_np() to get mux from child node
      dt-bindings: pinctrl: Add generic pinctrl for board-level mux chips
      pinctrl: extract pinctrl_generic_to_map() from pinctrl_generic_pins_function_dt_node_to_map()
      pinctrl: add optional .release_mux() callback
      pinctrl: add generic board-level pinctrl driver using mux framework
      arm64: dts: imx8mp-evk: add board-level mux for CAN2 and MICFIL
      arm64: dts: imx8mp-evk: add flexcan2 overlay file

 .../bindings/pinctrl/pinctrl-multiplexer.yaml      |  57 ++++++
 .../devicetree/bindings/pinctrl/pinctrl.yaml       |   2 +-
 arch/arm64/boot/dts/freescale/Makefile             |   4 +
 .../boot/dts/freescale/imx8mp-evk-flexcan2.dtso    |  15 ++
 arch/arm64/boot/dts/freescale/imx8mp-evk.dts       |  23 ++-
 drivers/mux/core.c                                 |  40 +++--
 drivers/pinctrl/Kconfig                            |   9 +
 drivers/pinctrl/Makefile                           |   1 +
 drivers/pinctrl/pinconf.h                          |  18 ++
 drivers/pinctrl/pinctrl-generic-mux.c              | 197 +++++++++++++++++++++
 drivers/pinctrl/pinctrl-generic.c                  |  94 ++++++----
 drivers/pinctrl/pinmux.c                           |   5 +
 include/linux/mux/consumer.h                       |  16 +-
 include/linux/pinctrl/pinmux.h                     |   5 +
 14 files changed, 424 insertions(+), 62 deletions(-)
---
base-commit: ff76d257e86235eb07ef33db8644a517c48d1c3f
change-id: 20260213-pinctrl-mux-df9c5b661540

Best regards,
--
Frank Li <Frank.Li@nxp.com>



^ permalink raw reply

* Re: [PATCH v5 00/12] scsi: ufs: Add TX Equalization support for UFS 5.0
From: Martin K. Petersen @ 2026-03-27 21:25 UTC (permalink / raw)
  To: Can Guo
  Cc: avri.altman, bvanassche, beanhuo, peter.wang, martin.petersen,
	mani, linux-scsi, Matthias Brugger, AngeloGioacchino Del Regno,
	open list:ARM/Mediatek SoC support:Keyword:mediatek,
	moderated list:ARM/Mediatek SoC support:Keyword:mediatek,
	moderated list:ARM/Mediatek SoC support:Keyword:mediatek
In-Reply-To: <20260325152154.1604082-1-can.guo@oss.qualcomm.com>


Can,

> The UFS v5.0 and UFSHCI v5.0 standards have published, introducing
> support for HS-G6 (46.6 Gbps per lane) through the new UniPro V3.0
> interconnect layer and M-PHY V6.0 physical layer specifications. To
> achieve reliable operation at these higher speeds, UniPro V3.0
> introduces TX Equalization and Pre-Coding mechanisms that are
> essential for signal integrity.

Applied to 7.1/scsi-staging, thanks!

-- 
Martin K. Petersen


^ permalink raw reply

* Re: [PATCH v1 0/2] perf build: Remove libunwind support
From: Arnaldo Carvalho de Melo @ 2026-03-27 21:08 UTC (permalink / raw)
  To: Ian Rogers
  Cc: Namhyung Kim, 9erthalion6, adrian.hunter, alex,
	alexander.shishkin, andrew.jones, aou, atrajeev, blakejones,
	ctshao, dapeng1.mi, howardchu95, james.clark, john.g.garry, jolsa,
	leo.yan, libunwind-devel, linux-arm-kernel, linux-kernel,
	linux-perf-users, linux-riscv, mingo, palmer, peterz, pjw,
	shimin.guo, tglozar, tmricht, will, amadio, yuzhuo
In-Reply-To: <CAP-5=fXmBpqP86FT85sA_BZYRnzwbZ5joYLogCqON6fjXCkRHQ@mail.gmail.com>

On Fri, Mar 27, 2026 at 01:37:20PM -0700, Ian Rogers wrote:
> On Fri, Mar 27, 2026 at 1:07 PM Arnaldo Carvalho de Melo
> <acme@kernel.org> wrote:
> >
> > On Thu, Mar 26, 2026 at 03:51:19PM -0700, Namhyung Kim wrote:
> > > On Sat, Mar 21, 2026 at 04:42:18PM -0700, Ian Rogers wrote:
> > > > libunwind support exists for "--call-graph dwarf", however, libunwind
> > > > support has been opt-in rather than opt-out since Linux v6.13 as libdw
> > > > is preferred - commit 13e17c9ff49119aa ("perf build: Make libunwind
> > > > opt-in rather than opt-out"). A problem with the libdw support was
> > > > that it was slow, an issue fixed in Linux v7.0 in commit 6b2658b3f36a
> > > > ("perf unwind-libdw: Don't discard loaded ELF/DWARF after every
> > > > unwind"). As such libunwind support is now unnecessary.
> > > >
> > > > The patch series:
> > > > https://lore.kernel.org/lkml/20260305221927.3237145-1-irogers@google.com/
> > > > looked to make the libunwind support in perf similar to the libdw
> > > > support, allow cross-architecture unwinding, etc. This was motivated
> > > > by the perf regs conventions being altered by the addition of x86 APX
> > > > support:
> > > > https://lore.kernel.org/lkml/20260209072047.2180332-1-dapeng1.mi@linux.intel.com/
> > > > It is necessary to translate the library's notion of registers to the
> > > > perf register convention so that the stack unwinding state can be
> > > > initialized. On this series it was stated that removing libunwind
> > > > support from perf should be an option, rather than updating support:
> > > > https://lore.kernel.org/lkml/abxs-2rozL1tBEO1@google.com/
> > > > This was also what motivated making libunwind opt-in rather than
> > > > opt-out.
> >
> > > > Given that 7 minor releases have happened with libunwind "deprecated"
> > > > by making it opt-in, let's remove the libunwind support. There doesn't
> > > > appear to be any disagreement to this on the mailing list.
> >
> > > I'm not sure if we want to remove it now.  I think we need more time to
> > > verify libdw unwinding is stable and fast enough.  Also maybe we can
> > > add build- or run-time warning when people try to use libunwind.
> >
> > We have:
> >
> > acme@x1:~/git/perf-tools$ perf -vv | grep LIBU
> >              libunwind: [ OFF ]  # HAVE_LIBUNWIND_SUPPORT ( tip: Deprecated, use LIBUNWIND=1 and install libunwind-dev[el] to build with it )
> > acme@x1:~/git/perf-tools$
> >
> > acme@x1:~/git/perf-tools$ perf check feature libunwind && echo perf built with libunwind
> >              libunwind: [ OFF ]  # HAVE_LIBUNWIND_SUPPORT ( tip: Deprecated, use LIBUNWIND=1 and install libunwind-dev[el] to build with it )
> > acme@x1:~/git/perf-tools$
> >
> > Building with both, as Ian mentioned ends up with:
> >
> >   LD      /tmp/build/perf-tools/util/perf-util-in.o
> > ld: /tmp/build/perf-tools/util/unwind-libunwind.o: in function `unwind__get_entries':
> > unwind-libunwind.c:(.text+0x2a0): multiple definition of `unwind__get_entries'; /tmp/build/perf-tools/util/unwind-libdw.o:unwind-libdw.c:(.text+0x940): first defined here
> > make[4]: *** [/home/acme/git/perf-tools/tools/build/Makefile.build:164: /tmp/build/perf-tools/util/perf-util-in.o] Error 123
> > make[3]: *** [/home/acme/git/perf-tools/tools/build/Makefile.build:158: util] Error 2
> > make[2]: *** [Makefile.perf:797: /tmp/build/perf-tools/perf-util-in.o] Error 2
> > make[1]: *** [Makefile.perf:289: sub-make] Error 2
> > make: *** [Makefile:119: install-bin] Error 2
> > make: Leaving directory '/home/acme/git/perf-tools/tools/perf'
> > ⬢ [acme@toolbx perf-tools]$
> >
> > So what Namhyung is suggesting is to disable libdw when libunwind is
> > asked for?
> >
> > I.e.
> >
> > alias m='rm -rf ~/libexec/perf-core/ ; make LIBUNWIND=1 NO_LIBDW=1 -k O=/tmp/build/$(basename $PWD)/ -C tools/perf install-bin && perf test "import python" && cat /tmp/build/$(basename $PWD)/feature/test-all.make.output' ; export PYTHONPATH=/tmp/build/$(basename $PWD)/python
> >
> > Which builds and ends up linking with both:
> >
> > ⬢ [acme@toolbx perf-tools]$ ldd ~/bin/perf | egrep unwind\|dw
> >         libunwind-x86_64.so.8 => /lib64/libunwind-x86_64.so.8 (0x00007fbf430b6000)
> >         libunwind.so.8 => /lib64/libunwind.so.8 (0x00007fbf4309b000)
> >         libdw.so.1 => /lib64/libdw.so.1 (0x00007fbf38570000)
> > ⬢ [acme@toolbx perf-tools]$
> >
> > I.e. that NO_LIBDW isn't really disabling linking with it, just some
> > features based on it, likely.
> >
> > Hum, we also have NO_LIBDW_DWARF_UNWIND, which probably is what we want
> > here... nope:
> >
> > ⬢ [acme@toolbx perf-tools]$ alias m='rm -rf ~/libexec/perf-core/ ; make LIBUNWIND=1 NO_LIBDW_DWARF_UNWIND=1 -k O=/tmp/build/$(basename $PWD)/ -C tools/perf install-bin && perf test "import python" && cat /tmp/build/$(basename $PWD)/feature/test-all.make.output' ; export PYTHONPATH=/tmp/build/$(basename $PWD)/python
> > ⬢ [acme@toolbx perf-tools]$ m
> > rm: cannot remove '/home/acme/libexec/perf-core/scripts/python/Perf-Trace-Util/lib/Perf/Trace/__pycache__/Core.cpython-314.pyc': Permission denied
> > make: Entering directory '/home/acme/git/perf-tools/tools/perf'
> >   BUILD:   Doing 'make -j12' parallel build
> > Warning: Kernel ABI header differences:
> >   diff -u tools/arch/x86/include/uapi/asm/svm.h arch/x86/include/uapi/asm/svm.h
> >
> > Auto-detecting system features:
> > ...                                   libdw: [ on  ]
> > ...                                   glibc: [ on  ]
> > ...                                  libelf: [ on  ]
> > ...                                 libnuma: [ on  ]
> > ...                  numa_num_possible_cpus: [ on  ]
> > ...                               libpython: [ on  ]
> > ...                             libcapstone: [ on  ]
> > ...                               llvm-perf: [ on  ]
> > ...                                    zlib: [ on  ]
> > ...                                    lzma: [ on  ]
> > ...                                     bpf: [ on  ]
> > ...                                  libaio: [ on  ]
> > ...                                 libzstd: [ on  ]
> > ...                              libopenssl: [ on  ]
> > ...                                    rust: [ on  ]
> >
> >   INSTALL libsubcmd_headers
> >   INSTALL libperf_headers
> >   INSTALL libapi_headers
> >   INSTALL libsymbol_headers
> >   INSTALL libbpf_headers
> >   LD      /tmp/build/perf-tools/util/perf-util-in.o
> > ld: /tmp/build/perf-tools/util/unwind-libunwind.o: in function `unwind__get_entries':
> > unwind-libunwind.c:(.text+0x2a0): multiple definition of `unwind__get_entries'; /tmp/build/perf-tools/util/unwind-libdw.o:unwind-libdw.c:(.text+0x940): first defined here
> > make[4]: *** [/home/acme/git/perf-tools/tools/build/Makefile.build:164: /tmp/build/perf-tools/util/perf-util-in.o] Error 123
> > make[3]: *** [/home/acme/git/perf-tools/tools/build/Makefile.build:158: util] Error 2
> > make[2]: *** [Makefile.perf:797: /tmp/build/perf-tools/perf-util-in.o] Error 2
> > make[2]: *** Waiting for unfinished jobs....
> > make[1]: *** [Makefile.perf:289: sub-make] Error 2
> > make: *** [Makefile:119: install-bin] Error 2
> > make: Leaving directory '/home/acme/git/perf-tools/tools/perf'
> > ⬢ [acme@toolbx perf-tools]$
> >
> > I expected NO_LIBDW_DWARF_UNWIND=1 would resolve this case, and maybe it
> > should?
> >
> > Or maybe it did it in the past as by now it is just a comment:
> >
> > ⬢ [acme@toolbx perf-tools]$ git grep NO_LIBDW_DWARF_UNWIND
> > tools/perf/Makefile.perf:# Define NO_LIBDW_DWARF_UNWIND if you do not want libdw support
> > ⬢ [acme@toolbx perf-tools]$
> >
> > Its from:
> >
> > # Define NO_LIBDW_DWARF_UNWIND if you do not want libdw support
> > # for dwarf backtrace post unwind.
> >
> > As we need libdw for 'perf probe', etc, so being able to disable it just
> > for DWARF backtrace is what we need here to make them mutually
> > exclusive, i.e. the default is for building with libdw for backtraces,
> > but if the user asks for LIBUNWIND=1, then a warning that libdw won't be
> > used for DWARF backtraces and select NO_LIBDW_DWARF_UNWIND?
> >
> > We could then have a regression test that builds perf with one, does
> > some backtraces, then with the other, then compare? This would be
> > followup work, if somebody has the cycles, but making them mutually
> > exclusive should be doable with not that much work?
> >
> > This is an area that is tricky and since we _already_ have two
> > implementations, the good thing for regression testing would be the
> > compare their results until libunwind becomes completely rotten and
> > unusable?
> 
> My series:
> https://lore.kernel.org/lkml/20260305221927.3237145-1-irogers@google.com/
> makes libdw and libunwind supported together:
> https://lore.kernel.org/lkml/20260305221927.3237145-2-irogers@google.com/
> """
> This commit refactors the DWARF unwind post-processing to be
> configurable at runtime via the .perfconfig file option
> 'unwind.style', or using the argument '--unwind-style' in the commands
> 'perf report', 'perf script' and 'perf inject', in a similar manner to
> the addr2line or the disassembler style.
> """
> That series cleans up several other issues, which is why I think it is
> worth landing while we wait for libdw to become stable.

Cool, I'll try and review/test it this weekend.

Thanks for pointint it out!

- Arnaldo


^ permalink raw reply

* Re: [PATCH v3 3/4] irqchip/ast2700-intc: Add KUnit tests for route resolution
From: kernel test robot @ 2026-03-27 20:58 UTC (permalink / raw)
  To: Ryan Chen, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Joel Stanley, Andrew Jeffery, Paul Walmsley, Palmer Dabbelt,
	Albert Ou, Alexandre Ghiti, Thomas Gleixner
  Cc: oe-kbuild-all, linux-kernel, devicetree, linux-arm-kernel,
	linux-aspeed, linux-riscv, Ryan Chen
In-Reply-To: <20260326-irqchip-v3-3-366739f57acf@aspeedtech.com>

Hi Ryan,

kernel test robot noticed the following build warnings:

[auto build test WARNING on 6de23f81a5e08be8fbf5e8d7e9febc72a5b5f27f]

url:    https://github.com/intel-lab-lkp/linux/commits/Ryan-Chen/dt-bindings-interrupt-controller-Describe-AST2700-A2-hardware-instead-of-A0/20260327-190127
base:   6de23f81a5e08be8fbf5e8d7e9febc72a5b5f27f
patch link:    https://lore.kernel.org/r/20260326-irqchip-v3-3-366739f57acf%40aspeedtech.com
patch subject: [PATCH v3 3/4] irqchip/ast2700-intc: Add KUnit tests for route resolution
config: arm-allyesconfig (https://download.01.org/0day-ci/archive/20260328/202603280415.xv0eHt8u-lkp@intel.com/config)
compiler: arm-linux-gnueabi-gcc (GCC) 15.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260328/202603280415.xv0eHt8u-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202603280415.xv0eHt8u-lkp@intel.com/

All warnings (new ones prefixed by >>):

   drivers/irqchip/irq-ast2700-intc0-test.c: In function 'aspeed_intc0_resolve_route_c1i1o1mc0i2o1':
>> drivers/irqchip/irq-ast2700-intc0-test.c:351:1: warning: the frame size of 1296 bytes is larger than 1280 bytes [-Wframe-larger-than=]
     351 | }
         | ^
   drivers/irqchip/irq-ast2700-intc0-test.c: In function 'aspeed_intc0_resolve_route_c1i2o2mc0i1o1':
   drivers/irqchip/irq-ast2700-intc0-test.c:292:1: warning: the frame size of 1296 bytes is larger than 1280 bytes [-Wframe-larger-than=]
     292 | }
         | ^


vim +351 drivers/irqchip/irq-ast2700-intc0-test.c

   293	
   294	static void aspeed_intc0_resolve_route_c1i1o1mc0i2o1(struct kunit *test)
   295	{
   296		struct device_node intc0_node = {
   297			.fwnode = { .ops = &intc0_fwnode_ops },
   298		};
   299		struct aspeed_intc_interrupt_range c1ranges[] = {
   300			{
   301				.start = 0,
   302				.count = 1,
   303				.upstream = {
   304					.fwnode = &intc0_node.fwnode,
   305					.param_count = 1,
   306					.param = { 510 }
   307				}
   308			},
   309		};
   310		static const u32 c1outs[] = { 0 };
   311		struct aspeed_intc_interrupt_range resolved;
   312		struct aspeed_intc_interrupt_range intc0_ranges[] = {
   313			{
   314				.start = 192,
   315				.count = 1,
   316				.upstream = {
   317					.fwnode = NULL,
   318					.param_count = 0,
   319					.param = {0},
   320				}
   321			},
   322			{
   323				.start = 208,
   324				.count = 1,
   325				.upstream = {
   326					.fwnode = NULL,
   327					.param_count = 0,
   328					.param = {0},
   329				}
   330			}
   331		};
   332		struct aspeed_intc0 intc0 = {
   333			.ranges = {
   334				.ranges = intc0_ranges,
   335				.nranges = ARRAY_SIZE(intc0_ranges),
   336			}
   337		};
   338		const struct irq_domain c0domain = {
   339			.host_data = &intc0,
   340			.fwnode = &intc0_node.fwnode
   341		};
   342		int rc;
   343	
   344		rc = aspeed_intc0_resolve_route(&c0domain, ARRAY_SIZE(c1outs), c1outs,
   345						ARRAY_SIZE(c1ranges), c1ranges,
   346						&resolved);
   347		KUNIT_EXPECT_EQ(test, rc, 0);
   348		KUNIT_EXPECT_EQ(test, resolved.start, 0);
   349		KUNIT_EXPECT_EQ(test, resolved.count, 1);
   350		KUNIT_EXPECT_EQ(test, resolved.upstream.param[0], 510);
 > 351	}
   352	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


^ permalink raw reply

* Re: [PATCH v1 1/3] arm64: mm: Fix rodata=full block mapping support for realm guests
From: Yang Shi @ 2026-03-27 20:49 UTC (permalink / raw)
  To: Ryan Roberts, Catalin Marinas, Will Deacon,
	David Hildenbrand (Arm), Dev Jain, Suzuki K Poulose, Jinjiang Tu,
	Kevin Brodsky
  Cc: linux-arm-kernel, linux-kernel, stable
In-Reply-To: <47d033cc-33dd-4fb2-9e8a-bc5762db6b6a@arm.com>



On 3/25/26 10:29 AM, Ryan Roberts wrote:
> On 23/03/2026 21:34, Yang Shi wrote:
>>
>> On 3/23/26 6:03 AM, Ryan Roberts wrote:
>>> Commit a166563e7ec37 ("arm64: mm: support large block mapping when
>>> rodata=full") enabled the linear map to be mapped by block/cont while
>>> still allowing granular permission changes on BBML2_NOABORT systems by
>>> lazily splitting the live mappings. This mechanism was intended to be
>>> usable by realm guests since they need to dynamically share dma buffers
>>> with the host by "decrypting" them - which for Arm CCA, means marking
>>> them as shared in the page tables.
>>>
>>> However, it turns out that the mechanism was failing for realm guests
>>> because realms need to share their dma buffers (via
>>> __set_memory_enc_dec()) much earlier during boot than
>>> split_kernel_leaf_mapping() was able to handle. The report linked below
>>> showed that GIC's ITS was one such user. But during the investigation I
>>> found other callsites that could not meet the
>>> split_kernel_leaf_mapping() constraints.
>>>
>>> The problem is that we block map the linear map based on the boot CPU
>>> supporting BBML2_NOABORT, then check that all the other CPUs support it
>>> too when finalizing the caps. If they don't, then we stop_machine() and
>>> split to ptes. For safety, split_kernel_leaf_mapping() previously
>>> wouldn't permit splitting until after the caps were finalized. That
>>> ensured that if any secondary cpus were running that didn't support
>>> BBML2_NOABORT, we wouldn't risk breaking them.
>>>
>>> I've fix this problem by reducing the black-out window where we refuse
>>> to split; there are now 2 windows. The first is from T0 until the page
>>> allocator is inititialized. Splitting allocates memory for the page
>>> allocator so it must be in use. The second covers the period between
>>> starting to online the secondary cpus until the system caps are
>>> finalized (this is a very small window).
>>>
>>> All of the problematic callers are calling __set_memory_enc_dec() before
>>> the secondary cpus come online, so this solves the problem. However, one
>>> of these callers, swiotlb_update_mem_attributes(), was trying to split
>>> before the page allocator was initialized. So I have moved this call
>>> from arch_mm_preinit() to mem_init(), which solves the ordering issue.
>>>
>>> I've added warnings and return an error if any attempt is made to split
>>> in the black-out windows.
>>>
>>> Note there are other issues which prevent booting all the way to user
>>> space, which will be fixed in subsequent patches.
>> Hi Ryan,
>>
>> Thanks for putting everything to together to have the patches so quickly. It
>> basically looks good to me. However, I'm thinking about whether we should have
>> split_kernel_leaf_mapping() call for different memory allocators in different
>> stages. If buddy has been initialized, it can call page allocator, otherwise,
>> for example, in early boot stage, it can call memblock allocator. So
>> split_kernel_leaf_mapping() should be able to be called anytime and we don't
>> have to rely on the boot order of subsystems.
> I considered that, but ultimately we would just be adding dead code. I've added
> a warning that will catch this usage. So I'd prefer to leave it as is for now
> and only add this functionality if we identify a need.

OK, fine to me. I don't have strong preference for either.

Thanks,
Yang

>
> Thanks,
> Ryan
>
>
>> Thanks,
>> Yang
>>



^ permalink raw reply

* Re: [PATCH v1 2/3] arm64: mm: Handle invalid large leaf mappings correctly
From: Yang Shi @ 2026-03-27 20:46 UTC (permalink / raw)
  To: Ryan Roberts, Catalin Marinas, Will Deacon,
	David Hildenbrand (Arm), Dev Jain, Suzuki K Poulose, Jinjiang Tu,
	Kevin Brodsky
  Cc: linux-arm-kernel, linux-kernel, stable
In-Reply-To: <eea4f7f1-c929-453b-adca-606ba6e4ec69@arm.com>



On 3/25/26 10:37 AM, Ryan Roberts wrote:
> On 24/03/2026 18:20, Yang Shi wrote:
>>
>> On 3/23/26 6:03 AM, Ryan Roberts wrote:
>>> It has been possible for a long time to mark ptes in the linear map as
>>> invalid. This is done for secretmem, kfence, realm dma memory un/share,
>>> and others, by simply clearing the PTE_VALID bit. But until commit
>>> a166563e7ec37 ("arm64: mm: support large block mapping when
>>> rodata=full") large leaf mappings were never made invalid in this way.
>>>
>>> It turns out various parts of the code base are not equipped to handle
>>> invalid large leaf mappings (in the way they are currently encoded) and
>>> I've observed a kernel panic while booting a realm guest on a
>>> BBML2_NOABORT system as a result:
>>>
>>> [   15.432706] software IO TLB: Memory encryption is active and system is
>>> using DMA bounce buffers
>>> [   15.476896] Unable to handle kernel paging request at virtual address
>>> ffff000019600000
>>> [   15.513762] Mem abort info:
>>> [   15.527245]   ESR = 0x0000000096000046
>>> [   15.548553]   EC = 0x25: DABT (current EL), IL = 32 bits
>>> [   15.572146]   SET = 0, FnV = 0
>>> [   15.592141]   EA = 0, S1PTW = 0
>>> [   15.612694]   FSC = 0x06: level 2 translation fault
>>> [   15.640644] Data abort info:
>>> [   15.661983]   ISV = 0, ISS = 0x00000046, ISS2 = 0x00000000
>>> [   15.694875]   CM = 0, WnR = 1, TnD = 0, TagAccess = 0
>>> [   15.723740]   GCS = 0, Overlay = 0, DirtyBit = 0, Xs = 0
>>> [   15.755776] swapper pgtable: 4k pages, 48-bit VAs, pgdp=0000000081f3f000
>>> [   15.800410] [ffff000019600000] pgd=0000000000000000, p4d=180000009ffff403,
>>> pud=180000009fffe403, pmd=00e8000199600704
>>> [   15.855046] Internal error: Oops: 0000000096000046 [#1]  SMP
>>> [   15.886394] Modules linked in:
>>> [   15.900029] CPU: 0 UID: 0 PID: 1 Comm: swapper/0 Not tainted 7.0.0-rc4-
>>> dirty #4 PREEMPT
>>> [   15.935258] Hardware name: linux,dummy-virt (DT)
>>> [   15.955612] pstate: 21400005 (nzCv daif +PAN -UAO -TCO +DIT -SSBS BTYPE=--)
>>> [   15.986009] pc : __pi_memcpy_generic+0x128/0x22c
>>> [   16.006163] lr : swiotlb_bounce+0xf4/0x158
>>> [   16.024145] sp : ffff80008000b8f0
>>> [   16.038896] x29: ffff80008000b8f0 x28: 0000000000000000 x27: 0000000000000000
>>> [   16.069953] x26: ffffb3976d261ba8 x25: 0000000000000000 x24: ffff000019600000
>>> [   16.100876] x23: 0000000000000001 x22: ffff0000043430d0 x21: 0000000000007ff0
>>> [   16.131946] x20: 0000000084570010 x19: 0000000000000000 x18: ffff00001ffe3fcc
>>> [   16.163073] x17: 0000000000000000 x16: 00000000003fffff x15: 646e612065766974
>>> [   16.194131] x14: 0000000000000000 x13: 0000000000000000 x12: 0000000000000000
>>> [   16.225059] x11: 0000000000000000 x10: 0000000000000010 x9 : 0000000000000018
>>> [   16.256113] x8 : 0000000000000018 x7 : 0000000000000000 x6 : 0000000000000000
>>> [   16.287203] x5 : ffff000019607ff0 x4 : ffff000004578000 x3 : ffff000019600000
>>> [   16.318145] x2 : 0000000000007ff0 x1 : ffff000004570010 x0 : ffff000019600000
>>> [   16.349071] Call trace:
>>> [   16.360143]  __pi_memcpy_generic+0x128/0x22c (P)
>>> [   16.380310]  swiotlb_tbl_map_single+0x154/0x2b4
>>> [   16.400282]  swiotlb_map+0x5c/0x228
>>> [   16.415984]  dma_map_phys+0x244/0x2b8
>>> [   16.432199]  dma_map_page_attrs+0x44/0x58
>>> [   16.449782]  virtqueue_map_page_attrs+0x38/0x44
>>> [   16.469596]  virtqueue_map_single_attrs+0xc0/0x130
>>> [   16.490509]  virtnet_rq_alloc.isra.0+0xa4/0x1fc
>>> [   16.510355]  try_fill_recv+0x2a4/0x584
>>> [   16.526989]  virtnet_open+0xd4/0x238
>>> [   16.542775]  __dev_open+0x110/0x24c
>>> [   16.558280]  __dev_change_flags+0x194/0x20c
>>> [   16.576879]  netif_change_flags+0x24/0x6c
>>> [   16.594489]  dev_change_flags+0x48/0x7c
>>> [   16.611462]  ip_auto_config+0x258/0x1114
>>> [   16.628727]  do_one_initcall+0x80/0x1c8
>>> [   16.645590]  kernel_init_freeable+0x208/0x2f0
>>> [   16.664917]  kernel_init+0x24/0x1e0
>>> [   16.680295]  ret_from_fork+0x10/0x20
>>> [   16.696369] Code: 927cec03 cb0e0021 8b0e0042 a9411c26 (a900340c)
>>> [   16.723106] ---[ end trace 0000000000000000 ]---
>>> [   16.752866] Kernel panic - not syncing: Attempted to kill init!
>>> exitcode=0x0000000b
>>> [   16.792556] Kernel Offset: 0x3396ea200000 from 0xffff800080000000
>>> [   16.818966] PHYS_OFFSET: 0xfff1000080000000
>>> [   16.837237] CPU features: 0x0000000,00060005,13e38581,957e772f
>>> [   16.862904] Memory Limit: none
>>> [   16.876526] ---[ end Kernel panic - not syncing: Attempted to kill init!
>>> exitcode=0x0000000b ]---
>>>
>>> This panic occurs because the swiotlb memory was previously shared to
>>> the host (__set_memory_enc_dec()), which involves transitioning the
>>> (large) leaf mappings to invalid, sharing to the host, then marking the
>>> mappings valid again. But pageattr_p[mu]d_entry() would only update the
>>> entry if it is a section mapping, since otherwise it concluded it must
>>> be a table entry so shouldn't be modified. But p[mu]d_sect() only
>>> returns true if the entry is valid. So the result was that the large
>>> leaf entry was made invalid in the first pass then ignored in the second
>>> pass. It remains invalid until the above code tries to access it and
>>> blows up.
>> Good catch. I recall I met this problem when I worked on a very early PoC of
>> large block mapping patch. It took a total different approach than
>> BBML2_NOABORT. I didn't run into that problem when I implemented BBML2_NOABORT
>> because nobody actually changed valid/invalid attribute on large block mapping
>> granule so I forgot it. But I definitely missed realm usecase.
>>
>>> The simple fix would be to update pageattr_pmd_entry() to use
>>> !pmd_table() instead of pmd_sect(). That would solve this problem.
>> Yes, I agree.
>>
>>> But the ptdump code also suffers from a similar issue. It checks
>>> pmd_leaf() and doesn't call into the arch-specific note_page() machinery
>>> if it returns false. As a result of this, ptdump wasn't even able to
>>> show the invalid large leaf mappings; it looked like they were valid
>>> which made this super fun to debug. the ptdump code is core-mm and
>>> pmd_table() is arm64-specific so we can't use the same trick to solve
>>> that.
>> I don't quite get why we need to show invalid mappings in ptdump? IIUC ptdump is
>> not supposed to show invalid mappings even though they are transient.
> Let's say we have 8M of PMD mappings, then we want to mark 2M in the middle of
> that as invalid. Prior to my fix, ptdump would show the full 8M as still being
> valid after making the middle 2M invalid. This happened because the note_page()
> call for the 2M invalid part was suppressed, but there was also no ptdump_hole()
> call since the PMD entry is not none. After my fix, we call note_page() for the
> non-none but invalid pmd and now the "F" is correctly displayed for that portion.

I see your point now. Yes, pmd_entry() will return 0 because pmd_leaf() 
returns false in this case. But the page table walk still continues 
since the later "pmd_leaf(*pmd) || !pmd_present(*pmd)" returns true 
because it is not present either. So the invalid entry will be 
mistakenly covered in a valid range.

It may be better to show the user visible ptdump change in the commit log.

Thanks,
Yang
>
> Thanks,
> Ryan
>
>
>
>> Thanks,
>> Yang
>>
>>
>>> But we already support the concept of "present-invalid" for user space
>>> entries. And even better, pmd_leaf() will return true for a leaf mapping
>>> that is marked present-invalid. So let's just use that encoding for
>>> present-invalid kernel mappings too. Then we can use pmd_leaf() where we
>>> previously used pmd_sect() and everything is magically fixed.
>>>
>>> Additionally, from inspection kernel_page_present() was broken in a
>>> similar way, so I'm also updating that to use pmd_leaf().
>>>
>>> I haven't spotted any other issues of this shape but plan to do a follow
>>> up patch to remove pmd_sect() and pud_sect() in favour of the more
>>> sophisticated pmd_leaf()/pud_leaf() which are core-mm APIs and will
>>> simplify arm64 code a bit.
>>>
>>> Fixes: a166563e7ec37 ("arm64: mm: support large block mapping when rodata=full")
>>> Cc: stable@vger.kernel.org
>>> Signed-off-by: Ryan Roberts <ryan.roberts@arm.com>
>>> ---
>>>    arch/arm64/mm/pageattr.c | 50 ++++++++++++++++++++++------------------
>>>    1 file changed, 28 insertions(+), 22 deletions(-)
>>>
>>> diff --git a/arch/arm64/mm/pageattr.c b/arch/arm64/mm/pageattr.c
>>> index 358d1dc9a576f..87dfe4c82fa92 100644
>>> --- a/arch/arm64/mm/pageattr.c
>>> +++ b/arch/arm64/mm/pageattr.c
>>> @@ -25,6 +25,11 @@ static ptdesc_t set_pageattr_masks(ptdesc_t val, struct
>>> mm_walk *walk)
>>>    {
>>>        struct page_change_data *masks = walk->private;
>>>    +    /*
>>> +     * Some users clear and set bits which alias eachother (e.g. PTE_NG and
>>> +     * PTE_PRESENT_INVALID). It is therefore important that we always clear
>>> +     * first then set.
>>> +     */
>>>        val &= ~(pgprot_val(masks->clear_mask));
>>>        val |= (pgprot_val(masks->set_mask));
>>>    @@ -36,7 +41,7 @@ static int pageattr_pud_entry(pud_t *pud, unsigned long addr,
>>>    {
>>>        pud_t val = pudp_get(pud);
>>>    -    if (pud_sect(val)) {
>>> +    if (pud_leaf(val)) {
>>>            if (WARN_ON_ONCE((next - addr) != PUD_SIZE))
>>>                return -EINVAL;
>>>            val = __pud(set_pageattr_masks(pud_val(val), walk));
>>> @@ -52,7 +57,7 @@ static int pageattr_pmd_entry(pmd_t *pmd, unsigned long addr,
>>>    {
>>>        pmd_t val = pmdp_get(pmd);
>>>    -    if (pmd_sect(val)) {
>>> +    if (pmd_leaf(val)) {
>>>            if (WARN_ON_ONCE((next - addr) != PMD_SIZE))
>>>                return -EINVAL;
>>>            val = __pmd(set_pageattr_masks(pmd_val(val), walk));
>>> @@ -132,11 +137,12 @@ static int __change_memory_common(unsigned long start,
>>> unsigned long size,
>>>        ret = update_range_prot(start, size, set_mask, clear_mask);
>>>          /*
>>> -     * If the memory is being made valid without changing any other bits
>>> -     * then a TLBI isn't required as a non-valid entry cannot be cached in
>>> -     * the TLB.
>>> +     * If the memory is being switched from present-invalid to valid without
>>> +     * changing any other bits then a TLBI isn't required as a non-valid
>>> +     * entry cannot be cached in the TLB.
>>>         */
>>> -    if (pgprot_val(set_mask) != PTE_VALID || pgprot_val(clear_mask))
>>> +    if (pgprot_val(set_mask) != (PTE_MAYBE_NG | PTE_VALID) ||
>>> +        pgprot_val(clear_mask) != PTE_PRESENT_INVALID)
>>>            flush_tlb_kernel_range(start, start + size);
>>>        return ret;
>>>    }
>>> @@ -237,18 +243,18 @@ int set_memory_valid(unsigned long addr, int numpages,
>>> int enable)
>>>    {
>>>        if (enable)
>>>            return __change_memory_common(addr, PAGE_SIZE * numpages,
>>> -                    __pgprot(PTE_VALID),
>>> -                    __pgprot(0));
>>> +                    __pgprot(PTE_MAYBE_NG | PTE_VALID),
>>> +                    __pgprot(PTE_PRESENT_INVALID));
>>>        else
>>>            return __change_memory_common(addr, PAGE_SIZE * numpages,
>>> -                    __pgprot(0),
>>> -                    __pgprot(PTE_VALID));
>>> +                    __pgprot(PTE_PRESENT_INVALID),
>>> +                    __pgprot(PTE_MAYBE_NG | PTE_VALID));
>>>    }
>>>      int set_direct_map_invalid_noflush(struct page *page)
>>>    {
>>> -    pgprot_t clear_mask = __pgprot(PTE_VALID);
>>> -    pgprot_t set_mask = __pgprot(0);
>>> +    pgprot_t clear_mask = __pgprot(PTE_MAYBE_NG | PTE_VALID);
>>> +    pgprot_t set_mask = __pgprot(PTE_PRESENT_INVALID);
>>>          if (!can_set_direct_map())
>>>            return 0;
>>> @@ -259,8 +265,8 @@ int set_direct_map_invalid_noflush(struct page *page)
>>>      int set_direct_map_default_noflush(struct page *page)
>>>    {
>>> -    pgprot_t set_mask = __pgprot(PTE_VALID | PTE_WRITE);
>>> -    pgprot_t clear_mask = __pgprot(PTE_RDONLY);
>>> +    pgprot_t set_mask = __pgprot(PTE_MAYBE_NG | PTE_VALID | PTE_WRITE);
>>> +    pgprot_t clear_mask = __pgprot(PTE_PRESENT_INVALID | PTE_RDONLY);
>>>          if (!can_set_direct_map())
>>>            return 0;
>>> @@ -296,8 +302,8 @@ static int __set_memory_enc_dec(unsigned long addr,
>>>         * entries or Synchronous External Aborts caused by RIPAS_EMPTY
>>>         */
>>>        ret = __change_memory_common(addr, PAGE_SIZE * numpages,
>>> -                     __pgprot(set_prot),
>>> -                     __pgprot(clear_prot | PTE_VALID));
>>> +                     __pgprot(set_prot | PTE_PRESENT_INVALID),
>>> +                     __pgprot(clear_prot | PTE_MAYBE_NG | PTE_VALID));
>>>          if (ret)
>>>            return ret;
>>> @@ -311,8 +317,8 @@ static int __set_memory_enc_dec(unsigned long addr,
>>>            return ret;
>>>          return __change_memory_common(addr, PAGE_SIZE * numpages,
>>> -                      __pgprot(PTE_VALID),
>>> -                      __pgprot(0));
>>> +                      __pgprot(PTE_MAYBE_NG | PTE_VALID),
>>> +                      __pgprot(PTE_PRESENT_INVALID));
>>>    }
>>>      static int realm_set_memory_encrypted(unsigned long addr, int numpages)
>>> @@ -404,15 +410,15 @@ bool kernel_page_present(struct page *page)
>>>        pud = READ_ONCE(*pudp);
>>>        if (pud_none(pud))
>>>            return false;
>>> -    if (pud_sect(pud))
>>> -        return true;
>>> +    if (pud_leaf(pud))
>>> +        return pud_valid(pud);
>>>          pmdp = pmd_offset(pudp, addr);
>>>        pmd = READ_ONCE(*pmdp);
>>>        if (pmd_none(pmd))
>>>            return false;
>>> -    if (pmd_sect(pmd))
>>> -        return true;
>>> +    if (pmd_leaf(pmd))
>>> +        return pmd_valid(pmd);
>>>          ptep = pte_offset_kernel(pmdp, addr);
>>>        return pte_valid(__ptep_get(ptep));



^ permalink raw reply

* ✅ PASS: Test report for for-kernelci (7.0.0-rc5, upstream-arm-next, 8d9c78aa)
From: cki-project @ 2026-03-27 20:43 UTC (permalink / raw)
  To: will, catalin.marinas, linux-arm-kernel

Hi, we tested your kernel and here are the results:

    Overall result: PASSED
             Merge: OK
           Compile: OK
              Test: OK

Tested-by: CKI Project <cki-project@redhat.com>

Kernel information:
    Commit message: Merge remote-tracking branch 'will/for-next/perf' into for-kernelci

You can find all the details about the test run at
    https://datawarehouse.cki-project.org/kcidb/checkouts/redhat:2414225370


If you find a failure unrelated to your changes, please ask the test maintainer to review it.
This will prevent the failures from being incorrectly reported in the future.

Please reply to this email if you have any questions about the tests that we
ran or if you have any suggestions on how to make future tests more effective.

        ,-.   ,-.
       ( C ) ( K )  Continuous
        `-',-.`-'   Kernel
          ( I )     Integration
           `-'
______________________________________________________________________________



^ permalink raw reply

* Re: [PATCH v1 0/2] perf build: Remove libunwind support
From: Ian Rogers @ 2026-03-27 20:41 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Namhyung Kim, 9erthalion6, adrian.hunter, alex,
	alexander.shishkin, andrew.jones, aou, atrajeev, blakejones,
	ctshao, dapeng1.mi, howardchu95, james.clark, john.g.garry, jolsa,
	leo.yan, libunwind-devel, linux-arm-kernel, linux-kernel,
	linux-perf-users, linux-riscv, mingo, palmer, peterz, pjw,
	shimin.guo, tglozar, tmricht, will, amadio, yuzhuo
In-Reply-To: <CAP-5=fXmBpqP86FT85sA_BZYRnzwbZ5joYLogCqON6fjXCkRHQ@mail.gmail.com>

On Fri, Mar 27, 2026 at 1:37 PM Ian Rogers <irogers@google.com> wrote:
>
> On Fri, Mar 27, 2026 at 1:07 PM Arnaldo Carvalho de Melo
> <acme@kernel.org> wrote:
> >
> > On Thu, Mar 26, 2026 at 03:51:19PM -0700, Namhyung Kim wrote:
> > > On Sat, Mar 21, 2026 at 04:42:18PM -0700, Ian Rogers wrote:
> > > > libunwind support exists for "--call-graph dwarf", however, libunwind
> > > > support has been opt-in rather than opt-out since Linux v6.13 as libdw
> > > > is preferred - commit 13e17c9ff49119aa ("perf build: Make libunwind
> > > > opt-in rather than opt-out"). A problem with the libdw support was
> > > > that it was slow, an issue fixed in Linux v7.0 in commit 6b2658b3f36a
> > > > ("perf unwind-libdw: Don't discard loaded ELF/DWARF after every
> > > > unwind"). As such libunwind support is now unnecessary.
> > > >
> > > > The patch series:
> > > > https://lore.kernel.org/lkml/20260305221927.3237145-1-irogers@google.com/
> > > > looked to make the libunwind support in perf similar to the libdw
> > > > support, allow cross-architecture unwinding, etc. This was motivated
> > > > by the perf regs conventions being altered by the addition of x86 APX
> > > > support:
> > > > https://lore.kernel.org/lkml/20260209072047.2180332-1-dapeng1.mi@linux.intel.com/
> > > > It is necessary to translate the library's notion of registers to the
> > > > perf register convention so that the stack unwinding state can be
> > > > initialized. On this series it was stated that removing libunwind
> > > > support from perf should be an option, rather than updating support:
> > > > https://lore.kernel.org/lkml/abxs-2rozL1tBEO1@google.com/
> > > > This was also what motivated making libunwind opt-in rather than
> > > > opt-out.
> >
> > > > Given that 7 minor releases have happened with libunwind "deprecated"
> > > > by making it opt-in, let's remove the libunwind support. There doesn't
> > > > appear to be any disagreement to this on the mailing list.
> >
> > > I'm not sure if we want to remove it now.  I think we need more time to
> > > verify libdw unwinding is stable and fast enough.  Also maybe we can
> > > add build- or run-time warning when people try to use libunwind.
> >
> > We have:
> >
> > acme@x1:~/git/perf-tools$ perf -vv | grep LIBU
> >              libunwind: [ OFF ]  # HAVE_LIBUNWIND_SUPPORT ( tip: Deprecated, use LIBUNWIND=1 and install libunwind-dev[el] to build with it )
> > acme@x1:~/git/perf-tools$
> >
> > acme@x1:~/git/perf-tools$ perf check feature libunwind && echo perf built with libunwind
> >              libunwind: [ OFF ]  # HAVE_LIBUNWIND_SUPPORT ( tip: Deprecated, use LIBUNWIND=1 and install libunwind-dev[el] to build with it )
> > acme@x1:~/git/perf-tools$
> >
> > Building with both, as Ian mentioned ends up with:
> >
> >   LD      /tmp/build/perf-tools/util/perf-util-in.o
> > ld: /tmp/build/perf-tools/util/unwind-libunwind.o: in function `unwind__get_entries':
> > unwind-libunwind.c:(.text+0x2a0): multiple definition of `unwind__get_entries'; /tmp/build/perf-tools/util/unwind-libdw.o:unwind-libdw.c:(.text+0x940): first defined here
> > make[4]: *** [/home/acme/git/perf-tools/tools/build/Makefile.build:164: /tmp/build/perf-tools/util/perf-util-in.o] Error 123
> > make[3]: *** [/home/acme/git/perf-tools/tools/build/Makefile.build:158: util] Error 2
> > make[2]: *** [Makefile.perf:797: /tmp/build/perf-tools/perf-util-in.o] Error 2
> > make[1]: *** [Makefile.perf:289: sub-make] Error 2
> > make: *** [Makefile:119: install-bin] Error 2
> > make: Leaving directory '/home/acme/git/perf-tools/tools/perf'
> > ⬢ [acme@toolbx perf-tools]$
> >
> > So what Namhyung is suggesting is to disable libdw when libunwind is
> > asked for?
> >
> > I.e.
> >
> > alias m='rm -rf ~/libexec/perf-core/ ; make LIBUNWIND=1 NO_LIBDW=1 -k O=/tmp/build/$(basename $PWD)/ -C tools/perf install-bin && perf test "import python" && cat /tmp/build/$(basename $PWD)/feature/test-all.make.output' ; export PYTHONPATH=/tmp/build/$(basename $PWD)/python
> >
> > Which builds and ends up linking with both:
> >
> > ⬢ [acme@toolbx perf-tools]$ ldd ~/bin/perf | egrep unwind\|dw
> >         libunwind-x86_64.so.8 => /lib64/libunwind-x86_64.so.8 (0x00007fbf430b6000)
> >         libunwind.so.8 => /lib64/libunwind.so.8 (0x00007fbf4309b000)
> >         libdw.so.1 => /lib64/libdw.so.1 (0x00007fbf38570000)
> > ⬢ [acme@toolbx perf-tools]$
> >
> > I.e. that NO_LIBDW isn't really disabling linking with it, just some
> > features based on it, likely.
> >
> > Hum, we also have NO_LIBDW_DWARF_UNWIND, which probably is what we want
> > here... nope:
> >
> > ⬢ [acme@toolbx perf-tools]$ alias m='rm -rf ~/libexec/perf-core/ ; make LIBUNWIND=1 NO_LIBDW_DWARF_UNWIND=1 -k O=/tmp/build/$(basename $PWD)/ -C tools/perf install-bin && perf test "import python" && cat /tmp/build/$(basename $PWD)/feature/test-all.make.output' ; export PYTHONPATH=/tmp/build/$(basename $PWD)/python
> > ⬢ [acme@toolbx perf-tools]$ m
> > rm: cannot remove '/home/acme/libexec/perf-core/scripts/python/Perf-Trace-Util/lib/Perf/Trace/__pycache__/Core.cpython-314.pyc': Permission denied
> > make: Entering directory '/home/acme/git/perf-tools/tools/perf'
> >   BUILD:   Doing 'make -j12' parallel build
> > Warning: Kernel ABI header differences:
> >   diff -u tools/arch/x86/include/uapi/asm/svm.h arch/x86/include/uapi/asm/svm.h
> >
> > Auto-detecting system features:
> > ...                                   libdw: [ on  ]
> > ...                                   glibc: [ on  ]
> > ...                                  libelf: [ on  ]
> > ...                                 libnuma: [ on  ]
> > ...                  numa_num_possible_cpus: [ on  ]
> > ...                               libpython: [ on  ]
> > ...                             libcapstone: [ on  ]
> > ...                               llvm-perf: [ on  ]
> > ...                                    zlib: [ on  ]
> > ...                                    lzma: [ on  ]
> > ...                                     bpf: [ on  ]
> > ...                                  libaio: [ on  ]
> > ...                                 libzstd: [ on  ]
> > ...                              libopenssl: [ on  ]
> > ...                                    rust: [ on  ]
> >
> >   INSTALL libsubcmd_headers
> >   INSTALL libperf_headers
> >   INSTALL libapi_headers
> >   INSTALL libsymbol_headers
> >   INSTALL libbpf_headers
> >   LD      /tmp/build/perf-tools/util/perf-util-in.o
> > ld: /tmp/build/perf-tools/util/unwind-libunwind.o: in function `unwind__get_entries':
> > unwind-libunwind.c:(.text+0x2a0): multiple definition of `unwind__get_entries'; /tmp/build/perf-tools/util/unwind-libdw.o:unwind-libdw.c:(.text+0x940): first defined here
> > make[4]: *** [/home/acme/git/perf-tools/tools/build/Makefile.build:164: /tmp/build/perf-tools/util/perf-util-in.o] Error 123
> > make[3]: *** [/home/acme/git/perf-tools/tools/build/Makefile.build:158: util] Error 2
> > make[2]: *** [Makefile.perf:797: /tmp/build/perf-tools/perf-util-in.o] Error 2
> > make[2]: *** Waiting for unfinished jobs....
> > make[1]: *** [Makefile.perf:289: sub-make] Error 2
> > make: *** [Makefile:119: install-bin] Error 2
> > make: Leaving directory '/home/acme/git/perf-tools/tools/perf'
> > ⬢ [acme@toolbx perf-tools]$
> >
> > I expected NO_LIBDW_DWARF_UNWIND=1 would resolve this case, and maybe it
> > should?
> >
> > Or maybe it did it in the past as by now it is just a comment:
> >
> > ⬢ [acme@toolbx perf-tools]$ git grep NO_LIBDW_DWARF_UNWIND
> > tools/perf/Makefile.perf:# Define NO_LIBDW_DWARF_UNWIND if you do not want libdw support
> > ⬢ [acme@toolbx perf-tools]$
> >
> > Its from:
> >
> > # Define NO_LIBDW_DWARF_UNWIND if you do not want libdw support
> > # for dwarf backtrace post unwind.
> >
> > As we need libdw for 'perf probe', etc, so being able to disable it just
> > for DWARF backtrace is what we need here to make them mutually
> > exclusive, i.e. the default is for building with libdw for backtraces,
> > but if the user asks for LIBUNWIND=1, then a warning that libdw won't be
> > used for DWARF backtraces and select NO_LIBDW_DWARF_UNWIND?
> >
> > We could then have a regression test that builds perf with one, does
> > some backtraces, then with the other, then compare? This would be
> > followup work, if somebody has the cycles, but making them mutually
> > exclusive should be doable with not that much work?
> >
> > This is an area that is tricky and since we _already_ have two
> > implementations, the good thing for regression testing would be the
> > compare their results until libunwind becomes completely rotten and
> > unusable?
>
> My series:
> https://lore.kernel.org/lkml/20260305221927.3237145-1-irogers@google.com/
> makes libdw and libunwind supported together:
> https://lore.kernel.org/lkml/20260305221927.3237145-2-irogers@google.com/
> """
> This commit refactors the DWARF unwind post-processing to be
> configurable at runtime via the .perfconfig file option
> 'unwind.style', or using the argument '--unwind-style' in the commands
> 'perf report', 'perf script' and 'perf inject', in a similar manner to
> the addr2line or the disassembler style.
> """
> That series cleans up several other issues, which is why I think it is
> worth landing while we wait for libdw to become stable.

Fwiw, fixing cross-platform MIPS libunwind support (my series does
this) goes someway to address problems with perf raised here:
https://github.com/koute/not-perf

Thanks,
Ian

> Thanks,
> Ian
>
> > - Arnaldo


^ permalink raw reply

* Re: [PATCH v2] ASoC: dt-bindings: mediatek,mt8173-rt5650-rt5514: convert to DT schema
From: Mark Brown @ 2026-03-27 17:21 UTC (permalink / raw)
  To: lgirdwood, Khushal Chitturi
  Cc: robh, krzk+dt, conor+dt, matthias.bgg, angelogioacchino.delregno,
	koro.chen, linux-sound, devicetree, linux-kernel,
	linux-arm-kernel, linux-mediatek
In-Reply-To: <20260327134649.31376-1-khushalchitturi@gmail.com>

On Fri, 27 Mar 2026 19:16:49 +0530, Khushal Chitturi wrote:
> ASoC: dt-bindings: mediatek,mt8173-rt5650-rt5514: convert to DT schema

Applied to

   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-7.1

Thanks!

[1/1] ASoC: dt-bindings: mediatek,mt8173-rt5650-rt5514: convert to DT schema
      https://git.kernel.org/broonie/sound/c/472d77bdc511

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark



^ permalink raw reply

* Re: [PATCH v1 0/2] perf build: Remove libunwind support
From: Ian Rogers @ 2026-03-27 20:37 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Namhyung Kim, 9erthalion6, adrian.hunter, alex,
	alexander.shishkin, andrew.jones, aou, atrajeev, blakejones,
	ctshao, dapeng1.mi, howardchu95, james.clark, john.g.garry, jolsa,
	leo.yan, libunwind-devel, linux-arm-kernel, linux-kernel,
	linux-perf-users, linux-riscv, mingo, palmer, peterz, pjw,
	shimin.guo, tglozar, tmricht, will, amadio, yuzhuo
In-Reply-To: <acbjjwc-WCk1CwtF@x1>

On Fri, Mar 27, 2026 at 1:07 PM Arnaldo Carvalho de Melo
<acme@kernel.org> wrote:
>
> On Thu, Mar 26, 2026 at 03:51:19PM -0700, Namhyung Kim wrote:
> > On Sat, Mar 21, 2026 at 04:42:18PM -0700, Ian Rogers wrote:
> > > libunwind support exists for "--call-graph dwarf", however, libunwind
> > > support has been opt-in rather than opt-out since Linux v6.13 as libdw
> > > is preferred - commit 13e17c9ff49119aa ("perf build: Make libunwind
> > > opt-in rather than opt-out"). A problem with the libdw support was
> > > that it was slow, an issue fixed in Linux v7.0 in commit 6b2658b3f36a
> > > ("perf unwind-libdw: Don't discard loaded ELF/DWARF after every
> > > unwind"). As such libunwind support is now unnecessary.
> > >
> > > The patch series:
> > > https://lore.kernel.org/lkml/20260305221927.3237145-1-irogers@google.com/
> > > looked to make the libunwind support in perf similar to the libdw
> > > support, allow cross-architecture unwinding, etc. This was motivated
> > > by the perf regs conventions being altered by the addition of x86 APX
> > > support:
> > > https://lore.kernel.org/lkml/20260209072047.2180332-1-dapeng1.mi@linux.intel.com/
> > > It is necessary to translate the library's notion of registers to the
> > > perf register convention so that the stack unwinding state can be
> > > initialized. On this series it was stated that removing libunwind
> > > support from perf should be an option, rather than updating support:
> > > https://lore.kernel.org/lkml/abxs-2rozL1tBEO1@google.com/
> > > This was also what motivated making libunwind opt-in rather than
> > > opt-out.
>
> > > Given that 7 minor releases have happened with libunwind "deprecated"
> > > by making it opt-in, let's remove the libunwind support. There doesn't
> > > appear to be any disagreement to this on the mailing list.
>
> > I'm not sure if we want to remove it now.  I think we need more time to
> > verify libdw unwinding is stable and fast enough.  Also maybe we can
> > add build- or run-time warning when people try to use libunwind.
>
> We have:
>
> acme@x1:~/git/perf-tools$ perf -vv | grep LIBU
>              libunwind: [ OFF ]  # HAVE_LIBUNWIND_SUPPORT ( tip: Deprecated, use LIBUNWIND=1 and install libunwind-dev[el] to build with it )
> acme@x1:~/git/perf-tools$
>
> acme@x1:~/git/perf-tools$ perf check feature libunwind && echo perf built with libunwind
>              libunwind: [ OFF ]  # HAVE_LIBUNWIND_SUPPORT ( tip: Deprecated, use LIBUNWIND=1 and install libunwind-dev[el] to build with it )
> acme@x1:~/git/perf-tools$
>
> Building with both, as Ian mentioned ends up with:
>
>   LD      /tmp/build/perf-tools/util/perf-util-in.o
> ld: /tmp/build/perf-tools/util/unwind-libunwind.o: in function `unwind__get_entries':
> unwind-libunwind.c:(.text+0x2a0): multiple definition of `unwind__get_entries'; /tmp/build/perf-tools/util/unwind-libdw.o:unwind-libdw.c:(.text+0x940): first defined here
> make[4]: *** [/home/acme/git/perf-tools/tools/build/Makefile.build:164: /tmp/build/perf-tools/util/perf-util-in.o] Error 123
> make[3]: *** [/home/acme/git/perf-tools/tools/build/Makefile.build:158: util] Error 2
> make[2]: *** [Makefile.perf:797: /tmp/build/perf-tools/perf-util-in.o] Error 2
> make[1]: *** [Makefile.perf:289: sub-make] Error 2
> make: *** [Makefile:119: install-bin] Error 2
> make: Leaving directory '/home/acme/git/perf-tools/tools/perf'
> ⬢ [acme@toolbx perf-tools]$
>
> So what Namhyung is suggesting is to disable libdw when libunwind is
> asked for?
>
> I.e.
>
> alias m='rm -rf ~/libexec/perf-core/ ; make LIBUNWIND=1 NO_LIBDW=1 -k O=/tmp/build/$(basename $PWD)/ -C tools/perf install-bin && perf test "import python" && cat /tmp/build/$(basename $PWD)/feature/test-all.make.output' ; export PYTHONPATH=/tmp/build/$(basename $PWD)/python
>
> Which builds and ends up linking with both:
>
> ⬢ [acme@toolbx perf-tools]$ ldd ~/bin/perf | egrep unwind\|dw
>         libunwind-x86_64.so.8 => /lib64/libunwind-x86_64.so.8 (0x00007fbf430b6000)
>         libunwind.so.8 => /lib64/libunwind.so.8 (0x00007fbf4309b000)
>         libdw.so.1 => /lib64/libdw.so.1 (0x00007fbf38570000)
> ⬢ [acme@toolbx perf-tools]$
>
> I.e. that NO_LIBDW isn't really disabling linking with it, just some
> features based on it, likely.
>
> Hum, we also have NO_LIBDW_DWARF_UNWIND, which probably is what we want
> here... nope:
>
> ⬢ [acme@toolbx perf-tools]$ alias m='rm -rf ~/libexec/perf-core/ ; make LIBUNWIND=1 NO_LIBDW_DWARF_UNWIND=1 -k O=/tmp/build/$(basename $PWD)/ -C tools/perf install-bin && perf test "import python" && cat /tmp/build/$(basename $PWD)/feature/test-all.make.output' ; export PYTHONPATH=/tmp/build/$(basename $PWD)/python
> ⬢ [acme@toolbx perf-tools]$ m
> rm: cannot remove '/home/acme/libexec/perf-core/scripts/python/Perf-Trace-Util/lib/Perf/Trace/__pycache__/Core.cpython-314.pyc': Permission denied
> make: Entering directory '/home/acme/git/perf-tools/tools/perf'
>   BUILD:   Doing 'make -j12' parallel build
> Warning: Kernel ABI header differences:
>   diff -u tools/arch/x86/include/uapi/asm/svm.h arch/x86/include/uapi/asm/svm.h
>
> Auto-detecting system features:
> ...                                   libdw: [ on  ]
> ...                                   glibc: [ on  ]
> ...                                  libelf: [ on  ]
> ...                                 libnuma: [ on  ]
> ...                  numa_num_possible_cpus: [ on  ]
> ...                               libpython: [ on  ]
> ...                             libcapstone: [ on  ]
> ...                               llvm-perf: [ on  ]
> ...                                    zlib: [ on  ]
> ...                                    lzma: [ on  ]
> ...                                     bpf: [ on  ]
> ...                                  libaio: [ on  ]
> ...                                 libzstd: [ on  ]
> ...                              libopenssl: [ on  ]
> ...                                    rust: [ on  ]
>
>   INSTALL libsubcmd_headers
>   INSTALL libperf_headers
>   INSTALL libapi_headers
>   INSTALL libsymbol_headers
>   INSTALL libbpf_headers
>   LD      /tmp/build/perf-tools/util/perf-util-in.o
> ld: /tmp/build/perf-tools/util/unwind-libunwind.o: in function `unwind__get_entries':
> unwind-libunwind.c:(.text+0x2a0): multiple definition of `unwind__get_entries'; /tmp/build/perf-tools/util/unwind-libdw.o:unwind-libdw.c:(.text+0x940): first defined here
> make[4]: *** [/home/acme/git/perf-tools/tools/build/Makefile.build:164: /tmp/build/perf-tools/util/perf-util-in.o] Error 123
> make[3]: *** [/home/acme/git/perf-tools/tools/build/Makefile.build:158: util] Error 2
> make[2]: *** [Makefile.perf:797: /tmp/build/perf-tools/perf-util-in.o] Error 2
> make[2]: *** Waiting for unfinished jobs....
> make[1]: *** [Makefile.perf:289: sub-make] Error 2
> make: *** [Makefile:119: install-bin] Error 2
> make: Leaving directory '/home/acme/git/perf-tools/tools/perf'
> ⬢ [acme@toolbx perf-tools]$
>
> I expected NO_LIBDW_DWARF_UNWIND=1 would resolve this case, and maybe it
> should?
>
> Or maybe it did it in the past as by now it is just a comment:
>
> ⬢ [acme@toolbx perf-tools]$ git grep NO_LIBDW_DWARF_UNWIND
> tools/perf/Makefile.perf:# Define NO_LIBDW_DWARF_UNWIND if you do not want libdw support
> ⬢ [acme@toolbx perf-tools]$
>
> Its from:
>
> # Define NO_LIBDW_DWARF_UNWIND if you do not want libdw support
> # for dwarf backtrace post unwind.
>
> As we need libdw for 'perf probe', etc, so being able to disable it just
> for DWARF backtrace is what we need here to make them mutually
> exclusive, i.e. the default is for building with libdw for backtraces,
> but if the user asks for LIBUNWIND=1, then a warning that libdw won't be
> used for DWARF backtraces and select NO_LIBDW_DWARF_UNWIND?
>
> We could then have a regression test that builds perf with one, does
> some backtraces, then with the other, then compare? This would be
> followup work, if somebody has the cycles, but making them mutually
> exclusive should be doable with not that much work?
>
> This is an area that is tricky and since we _already_ have two
> implementations, the good thing for regression testing would be the
> compare their results until libunwind becomes completely rotten and
> unusable?

My series:
https://lore.kernel.org/lkml/20260305221927.3237145-1-irogers@google.com/
makes libdw and libunwind supported together:
https://lore.kernel.org/lkml/20260305221927.3237145-2-irogers@google.com/
"""
This commit refactors the DWARF unwind post-processing to be
configurable at runtime via the .perfconfig file option
'unwind.style', or using the argument '--unwind-style' in the commands
'perf report', 'perf script' and 'perf inject', in a similar manner to
the addr2line or the disassembler style.
"""
That series cleans up several other issues, which is why I think it is
worth landing while we wait for libdw to become stable.

Thanks,
Ian

> - Arnaldo


^ permalink raw reply

* Re: [PATCH v1 1/1] scsi: ufs: rockchip: Drop unused include
From: Martin K. Petersen @ 2026-03-27 20:28 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Shawn Lin, linux-scsi, linux-arm-kernel, linux-rockchip,
	linux-kernel, James E.J. Bottomley, Martin K. Petersen,
	Heiko Stuebner
In-Reply-To: <20260320215606.3236516-1-andriy.shevchenko@linux.intel.com>


Andy,

> This driver includes the legacy header <linux/gpio.h> but does
> not use any symbols from it. Drop the inclusion.

Applied to 7.1/scsi-staging, thanks!

-- 
Martin K. Petersen


^ permalink raw reply

* Re: [PATCH] mailbox: Fix NULL message support in mbox_send_message()
From: Doug Anderson @ 2026-03-27 20:24 UTC (permalink / raw)
  To: jassisinghbrar
  Cc: linux-kernel, linux-arm-kernel, shawn.guo, maz, stable, andersson,
	tglx, joonwonkang
In-Reply-To: <20260322171752.608486-1-jassisinghbrar@gmail.com>

Jassi,

On Sun, Mar 22, 2026 at 10:18 AM <jassisinghbrar@gmail.com> wrote:
>
> From: Jassi Brar <jassisinghbrar@gmail.com>
>
> The active_req field serves double duty as both the "is a TX in
> flight" flag (NULL means idle) and the storage for the in-flight
> message pointer. When a client sends NULL via mbox_send_message(),
> active_req is set to NULL, which the framework misinterprets as
> "no active request". This breaks the TX state machine by:
>
>  - tx_tick() short-circuits on (!mssg), skipping the tx_done
>    callback and the tx_complete completion
>  - txdone_hrtimer() skips the channel entirely since active_req
>    is NULL, so poll-based TX-done detection never fires.
>
> Fix this by introducing a MBOX_NO_MSG sentinel value that means
> "no active request," freeing NULL to be valid message data. The
> sentinel is defined in the subsystem-internal mailbox.h so that
> controller drivers within drivers/mailbox/ can reference it, but
> it is not exposed to clients outside the subsystem.
>
> Fifteen in-tree callers send NULL (doorbell-style IPCs on Qualcomm,
> Tegra, TI, Xilinx, i.MX, SCMI, and PCC platforms). All were
> audited for regression:
>
>  - Most already work around the bug via knows_txdone=true with a
>    manual mbox_client_txdone() call, making the framework's
>    tracking irrelevant. These are unaffected.
>
>  - Poll-based callers (Xilinx zynqmp/r5) are strictly better off:
>    the poll timer now correctly detects NULL-active channels
>    instead of silently skipping them.
>
>  - irq-qcom-mpm.c was a pre-existing bug -- the only Qualcomm
>    caller that omitted the knows_txdone + mbox_client_txdone()
>    pattern. Fixed in a companion commit ("irqchip/qcom-mpm: Fix
>    missing mailbox TX done acknowledgment").
>
>  - No caller sets both a tx_done callback and sends NULL, nor
>    combines tx_block=true with NULL sends, so the newly reachable
>    callback/completion paths are never exercised.
>
> Also update tegra-hsp's flush callback, which directly inspects
> active_req to wait for the channel to drain: the old "!= NULL"
> check becomes "!= MBOX_NO_MSG", otherwise flush spins until
> timeout since the sentinel is non-NULL.
>
> The only tradeoff is that 'MBOX_NO_MSG' can not be used as a message
> by clients.
>
> Signed-off-by: Jassi Brar <jassisinghbrar@gmail.com>
> ---
>  drivers/mailbox/mailbox.c   | 13 +++++++------
>  drivers/mailbox/mailbox.h   |  3 +++
>  drivers/mailbox/tegra-hsp.c |  2 +-
>  3 files changed, 11 insertions(+), 7 deletions(-)

This looks reasonable to me. I have one nit, though. Can you please
add a snippet to the beginning of mbox_send_message() that looks like:

if (mssg == MBOX_NO_MSG)
  return -EINVAL

I just want to ensure a client doesn't decide to simulate the
old/weird behavior by sending this sentinel value. ;-)

Other than that:

Reviewed-by: Douglas Anderson <dianders@chromium.org>


-Doug


^ permalink raw reply

* Re: [PATCH v6 phy-next 09/28] scsi: ufs: exynos: stop poking into struct phy guts
From: Peter Griffin @ 2026-03-27 20:23 UTC (permalink / raw)
  To: Vladimir Oltean
  Cc: linux-phy, Vinod Koul, Neil Armstrong, dri-devel, freedreno,
	linux-arm-kernel, linux-arm-msm, linux-can, linux-gpio, linux-ide,
	linux-kernel, linux-media, linux-pci, linux-renesas-soc,
	linux-riscv, linux-rockchip, linux-samsung-soc, linux-scsi,
	linux-sunxi, linux-tegra, linux-usb, netdev, spacemit,
	UNGLinuxDriver, Bart Van Assche, Alim Akhtar,
	James E.J. Bottomley, Martin K. Petersen, Krzysztof Kozlowski,
	Chanho Park
In-Reply-To: <20260327184706.1600329-10-vladimir.oltean@nxp.com>

On Fri, 27 Mar 2026 at 18:48, Vladimir Oltean <vladimir.oltean@nxp.com> wrote:
>
> The Exynos host controller driver is clearly a PHY consumer (gets the
> ufs->phy using devm_phy_get()), but pokes into the guts of struct phy
> to get the generic_phy->power_count.
>
> The UFS core (specifically ufshcd_link_startup()) may call the variant
> operation exynos_ufs_pre_link() -> exynos_ufs_phy_init() multiple times
> if the link startup fails and needs to be retried.
>
> However ufs-exynos shouldn't be doing what it's doing, i.e. looking at
> the generic_phy->power_count, because in the general sense of the API, a
> single Generic PHY may have multiple consumers. If ufs-exynos looks at
> generic_phy->power_count, there's no guarantee that this ufs-exynos
> instance is the one who previously bumped that power count. So it may be
> powering down the PHY on behalf of another consumer.
>
> The correct way in which this should be handled is ufs-exynos should
> *remember* whether it has initialized and powered up the PHY before, and
> power it down during link retries. Not rely on the power_count (which,
> btw, on the writer side is modified under &phy->mutex, but on the reader
> side is accessed unlocked). This is a discouraged pattern even if here
> it doesn't cause functional problems.
>
> Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
> Reviewed-by: Bart Van Assche <bvanassche@acm.org>
> Acked-by: Alim Akhtar <alim.akhtar@samsung.com>
> Tested-by: Alim Akhtar <alim.akhtar@samsung.com>
> ---

Reviewed-by: Peter Griffin <peter.griffin@linaro.org>

> Cc: Alim Akhtar <alim.akhtar@samsung.com>
> Cc: Peter Griffin <peter.griffin@linaro.org>
> Cc: "James E.J. Bottomley" <James.Bottomley@HansenPartnership.com>
> Cc: "Martin K. Petersen" <martin.petersen@oracle.com>
> Cc: Krzysztof Kozlowski <krzk@kernel.org>
> Cc: Chanho Park <chanho61.park@samsung.com>
>
> v5->v6: collect tags from Alim Akhtar
> v4->v5: collect tag, add "scsi: " prefix to commit title
> v3->v4: none
> v2->v3:
> - add Cc Chanho Park, author of commit 3d73b200f989 ("scsi: ufs:
>   ufs-exynos: Change ufs phy control sequence")
> v1->v2:
> - add better ufs->phy_powered_on handling in exynos_ufs_exit(),
>   exynos_ufs_suspend() and exynos_ufs_resume() which ensures we won't
>   enter a phy->power_count underrun condition
> ---
>  drivers/ufs/host/ufs-exynos.c | 24 ++++++++++++++++++++----
>  drivers/ufs/host/ufs-exynos.h |  1 +
>  2 files changed, 21 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/ufs/host/ufs-exynos.c b/drivers/ufs/host/ufs-exynos.c
> index 76fee3a79c77..274e53833571 100644
> --- a/drivers/ufs/host/ufs-exynos.c
> +++ b/drivers/ufs/host/ufs-exynos.c
> @@ -963,9 +963,10 @@ static int exynos_ufs_phy_init(struct exynos_ufs *ufs)
>
>         phy_set_bus_width(generic_phy, ufs->avail_ln_rx);
>
> -       if (generic_phy->power_count) {
> +       if (ufs->phy_powered_on) {
>                 phy_power_off(generic_phy);
>                 phy_exit(generic_phy);
> +               ufs->phy_powered_on = false;
>         }
>
>         ret = phy_init(generic_phy);
> @@ -979,6 +980,8 @@ static int exynos_ufs_phy_init(struct exynos_ufs *ufs)
>         if (ret)
>                 goto out_exit_phy;
>
> +       ufs->phy_powered_on = true;
> +
>         return 0;
>
>  out_exit_phy:
> @@ -1527,6 +1530,9 @@ static void exynos_ufs_exit(struct ufs_hba *hba)
>  {
>         struct exynos_ufs *ufs = ufshcd_get_variant(hba);
>
> +       if (!ufs->phy_powered_on)
> +               return;
> +
>         phy_power_off(ufs->phy);
>         phy_exit(ufs->phy);
>  }
> @@ -1728,8 +1734,10 @@ static int exynos_ufs_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op,
>         if (ufs->drv_data->suspend)
>                 ufs->drv_data->suspend(ufs);
>
> -       if (!ufshcd_is_link_active(hba))
> +       if (!ufshcd_is_link_active(hba) && ufs->phy_powered_on) {
>                 phy_power_off(ufs->phy);
> +               ufs->phy_powered_on = false;
> +       }
>
>         return 0;
>  }
> @@ -1737,9 +1745,17 @@ static int exynos_ufs_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op,
>  static int exynos_ufs_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)
>  {
>         struct exynos_ufs *ufs = ufshcd_get_variant(hba);
> +       int err;
>
> -       if (!ufshcd_is_link_active(hba))
> -               phy_power_on(ufs->phy);
> +       if (!ufshcd_is_link_active(hba) && !ufs->phy_powered_on) {
> +               err = phy_power_on(ufs->phy);
> +               if (err) {
> +                       dev_err(hba->dev, "Failed to power on PHY: %pe\n",
> +                               ERR_PTR(err));
> +               } else {
> +                       ufs->phy_powered_on = true;
> +               }
> +       }
>
>         exynos_ufs_config_smu(ufs);
>         exynos_ufs_fmp_resume(hba);
> diff --git a/drivers/ufs/host/ufs-exynos.h b/drivers/ufs/host/ufs-exynos.h
> index abe7e472759e..683b9150e2ba 100644
> --- a/drivers/ufs/host/ufs-exynos.h
> +++ b/drivers/ufs/host/ufs-exynos.h
> @@ -227,6 +227,7 @@ struct exynos_ufs {
>         int avail_ln_rx;
>         int avail_ln_tx;
>         int rx_sel_idx;
> +       bool phy_powered_on;
>         struct ufs_pa_layer_attr dev_req_params;
>         struct ufs_phy_time_cfg t_cfg;
>         ktime_t entry_hibern8_t;
> --
> 2.43.0
>


^ permalink raw reply

* Re: [PATCH v6 phy-next 11/28] scsi: ufs: qcom: include missing <linux/interrupt.h>
From: Martin K. Petersen @ 2026-03-27 20:20 UTC (permalink / raw)
  To: Vladimir Oltean
  Cc: linux-phy, Vinod Koul, Neil Armstrong, dri-devel, freedreno,
	linux-arm-kernel, linux-arm-msm, linux-can, linux-gpio, linux-ide,
	linux-kernel, linux-media, linux-pci, linux-renesas-soc,
	linux-riscv, linux-rockchip, linux-samsung-soc, linux-scsi,
	linux-sunxi, linux-tegra, linux-usb, netdev, spacemit,
	UNGLinuxDriver, Manivannan Sadhasivam, James E.J. Bottomley,
	Martin K. Petersen
In-Reply-To: <20260327184706.1600329-12-vladimir.oltean@nxp.com>


Vladimir,

> The point is that <linux/phy/phy.h> will stop providing
> <linux/regulator/consumer.h>, and this would break the transitive
> include chain on armv7.

Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com>

-- 
Martin K. Petersen


^ permalink raw reply


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