* Re: [PATCH v6 10/10] rust: module: update MAINTAINERS to cover module.rs
From: Gary Guo @ 2026-06-25 14:39 UTC (permalink / raw)
To: Alvin Sun, Miguel Ojeda, Boqun Feng, Gary Guo,
Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
Trevor Gross, Danilo Krummrich, Luis Chamberlain, Petr Pavlu,
Daniel Gomez, Sami Tolvanen, Aaron Tomlin, Greg Kroah-Hartman,
Rafael J. Wysocki, David Airlie, Simona Vetter, Daniel Almeida,
Arnd Bergmann, Brendan Higgins, David Gow, Rae Moar, Breno Leitao,
Jens Axboe, Dave Ertman, Leon Romanovsky, Igor Korotin,
FUJITA Tomonori, Bjorn Helgaas, Krzysztof Wilczyński,
Arve Hjønnevåg, Todd Kjos, Christian Brauner,
Carlos Llamas
Cc: rust-for-linux, linux-modules, driver-core, dri-devel, nova-gpu,
linux-kselftest, kunit-dev, linux-block, linux-kernel, netdev,
linux-pci
In-Reply-To: <20260624-fix-fops-owner-v6-10-5295e333cb3e@linux.dev>
On Wed Jun 24, 2026 at 4:00 PM BST, Alvin Sun wrote:
> Module types now live in `rust/kernel/module.rs` alongside
> `rust/kernel/module_param.rs`. Update the MODULE SUPPORT file pattern
> from `rust/kernel/module_param.rs` to `rust/kernel/module*.rs` so both
> files are covered.
>
> Assisted-by: opencode:glm-5.2
Did you actually use a LLM for this patch even? :)
> Link: https://lore.kernel.org/rust-for-linux/8ea21b29-9baf-4926-a16f-7d21c5a1a1b8@suse.com
> Signed-off-by: Alvin Sun <alvin.sun@linux.dev>
This patch should probably be squashed into the actual move, i.e. patch 1.
Best,
Gary
> ---
> MAINTAINERS | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index e035a3be797c4..74733de3e41ee 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -17984,7 +17984,7 @@ F: include/linux/module*.h
> F: kernel/module/
> F: lib/test_kmod.c
> F: lib/tests/module/
> -F: rust/kernel/module_param.rs
> +F: rust/kernel/module*.rs
> F: rust/macros/module.rs
> F: scripts/module*
> F: tools/testing/selftests/kmod/
^ permalink raw reply
* Re: [PATCH v6 01/10] rust: module: move module types into `module.rs`
From: Gary Guo @ 2026-06-25 14:37 UTC (permalink / raw)
To: Alvin Sun, Miguel Ojeda, Boqun Feng, Gary Guo,
Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
Trevor Gross, Danilo Krummrich, Luis Chamberlain, Petr Pavlu,
Daniel Gomez, Sami Tolvanen, Aaron Tomlin, Greg Kroah-Hartman,
Rafael J. Wysocki, David Airlie, Simona Vetter, Daniel Almeida,
Arnd Bergmann, Brendan Higgins, David Gow, Rae Moar, Breno Leitao,
Jens Axboe, Dave Ertman, Leon Romanovsky, Igor Korotin,
FUJITA Tomonori, Bjorn Helgaas, Krzysztof Wilczyński,
Arve Hjønnevåg, Todd Kjos, Christian Brauner,
Carlos Llamas
Cc: rust-for-linux, linux-modules, driver-core, dri-devel, nova-gpu,
linux-kselftest, kunit-dev, linux-block, linux-kernel, netdev,
linux-pci
In-Reply-To: <20260624-fix-fops-owner-v6-1-5295e333cb3e@linux.dev>
On Wed Jun 24, 2026 at 4:00 PM BST, Alvin Sun wrote:
> Move `Module`, `InPlaceModule`, `ModuleMetadata` and `ThisModule` from
> `lib.rs` into a new `rust/kernel/module.rs`. Re-export them from `lib.rs`
> to avoid tree-wide changes.
>
> Switch six bus driver registrations from `module.0` to the public
> `ThisModule::as_ptr()` accessor, since the field is no longer visible
> outside the new `module` submodule.
>
> No functional change.
>
> Assisted-by: opencode:glm-5.2
> Acked-by: Danilo Krummrich <dakr@kernel.org>
> Signed-off-by: Alvin Sun <alvin.sun@linux.dev>
Suggested-by: Gary Guo <gary@garyguo.net>
Link: https://lore.kernel.org/all/DJFIQPLOVO4T.1K8T0VZM30LDA@garyguo.net/
Reviewed-by: Gary Guo <gary@garyguo.net>
> ---
> rust/kernel/auxiliary.rs | 2 +-
> rust/kernel/i2c.rs | 2 +-
> rust/kernel/lib.rs | 75 +++++-------------------------------------------
> rust/kernel/module.rs | 71 +++++++++++++++++++++++++++++++++++++++++++++
> rust/kernel/net/phy.rs | 6 +++-
> rust/kernel/pci.rs | 2 +-
> rust/kernel/platform.rs | 2 +-
> rust/kernel/usb.rs | 2 +-
> 8 files changed, 88 insertions(+), 74 deletions(-)
^ permalink raw reply
* Re: [PATCH] block: partitions: Use seq_buf_putc() in cmdline_partition()
From: Andy Shevchenko @ 2026-06-25 14:27 UTC (permalink / raw)
To: Markus Elfring
Cc: linux-block, Jens Axboe, Josh Law, Kees Cook,
Woradorn Laodhanadhaworn, LKML, kernel-janitors
In-Reply-To: <7de415a7-457d-4dd2-aebb-8e179fa0bbcd@web.de>
On Thu, Jun 25, 2026 at 02:18:49PM +0200, Markus Elfring wrote:
...
> >> cmdline_parts_set(parts, disk_size, state);
> >> cmdline_parts_verifier(1, state);
> >
> >> -
> >> - seq_buf_puts(&state->pp_buf, "\n");
> >> -
> >> + seq_buf_putc(&state->pp_buf, '\n');
> >
> > Why did you remove blank lines?
> >
> >> return 1;
> I imagine that this source code place can become a bit more succinct.
>
> See also:
> efi_partition()
> https://elixir.bootlin.com/linux/v7.1.1/source/block/partitions/efi.c#L694-L756
>
> Do you insist to preserve two blank lines here?
Yes.
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply
* Re: [PATCH 2/6] remoteproc: qcom: Add M0 BTSS secure PIL driver
From: George Moussalem @ 2026-06-25 14:24 UTC (permalink / raw)
To: Philipp Zabel, Jens Axboe, Ulf Hansson, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Johannes Berg, Jeff Johnson,
Bartosz Golaszewski, Marcel Holtmann, Luiz Augusto von Dentz,
Balakrishna Godavarthi, Rocky Liao, Saravana Kannan, Andrew Lunn,
Heiner Kallweit, Russell King, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Bjorn Andersson,
Konrad Dybcio, Mathieu Poirier
Cc: linux-block, linux-kernel, linux-mmc, devicetree, linux-wireless,
ath10k, linux-arm-msm, linux-bluetooth, netdev, linux-remoteproc
In-Reply-To: <439f76c3fcafdfb91cca426fcae17ef776776eab.camel@pengutronix.de>
Thanks, that was quick!
On 6/25/26 18:18, Philipp Zabel wrote:
> On Do, 2026-06-25 at 18:10 +0400, George Moussalem via B4 Relay wrote:
>> From: George Moussalem <george.moussalem@outlook.com>
>>
>> Add support to bring up the M0 core of the bluetooth subsystem found in
>> the IPQ5018 SoC.
>>
>> The signed firmware loaded is authenticated by TrustZone. If successful,
>> the M0 core boots the firmware and the peripheral is taken out of reset
>> using a Secure Channel Manager call to TrustZone.
>>
>> Signed-off-by: George Moussalem <george.moussalem@outlook.com>
>> ---
>> drivers/remoteproc/Kconfig | 12 ++
>> drivers/remoteproc/Makefile | 1 +
>> drivers/remoteproc/qcom_m0_btss_pil.c | 261 ++++++++++++++++++++++++++++++++++
>> 3 files changed, 274 insertions(+)
>>
> [...]
>> diff --git a/drivers/remoteproc/qcom_m0_btss_pil.c b/drivers/remoteproc/qcom_m0_btss_pil.c
>> new file mode 100644
>> index 000000000000..7168e270e4d4
>> --- /dev/null
>> +++ b/drivers/remoteproc/qcom_m0_btss_pil.c
>> @@ -0,0 +1,261 @@
>> +// SPDX-License-Identifier: GPL-2.0-only
>> +/*
>> + * Copyright (c) 2026 The Linux Foundation. All rights reserved.
>> + */
>> +
>> +#include <linux/clk.h>
>> +#include <linux/delay.h>
>> +#include <linux/elf.h>
>> +#include <linux/firmware/qcom/qcom_scm.h>
>> +#include <linux/io.h>
>> +#include <linux/kernel.h>
>> +#include <linux/of_reserved_mem.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/reset.h>
>> +#include <linux/soc/qcom/mdt_loader.h>
>> +
>> +#include "qcom_common.h"
>> +
>> +#define BTSS_PAS_ID 0xc
>> +
>> +struct m0_btss {
>> + struct device *dev;
>> + phys_addr_t mem_phys;
>> + phys_addr_t mem_reloc;
>> + void __iomem *mem_region;
>> + size_t mem_size;
>> + struct reset_control *btss_reset;
>
> Why is this stored here? It doesn't seem to be used.
will remove it and use devm_reset_control_get_exclusive_deasserted as
suggested below.
>
> [...]
>> +static int m0_btss_pil_probe(struct platform_device *pdev)
>> +{
>> + // struct reset_control *btss_reset;
>
> It looks like this shouldn't be commented out.
>
>> + struct device *dev = &pdev->dev;
>> + const char *fw_name = NULL;
>> + struct m0_btss *desc;
>> + struct clk *lpo_clk;
>> + struct rproc *rproc;
>> + int ret;
>> +
>> + ret = of_property_read_string(dev->of_node, "firmware-name",
>> + &fw_name);
>> + if (ret < 0)
>> + return ret;
>> +
>> + rproc = devm_rproc_alloc(dev, "m0btss", &m0_btss_ops,
>> + fw_name, sizeof(*desc));
>> + if (!rproc) {
>> + dev_err(dev, "failed to allocate rproc\n");
>> + return -ENOMEM;
>> + }
>> +
>> + desc = rproc->priv;
>> + desc->dev = dev;
>> +
>> + ret = m0_btss_alloc_memory_region(desc);
>> + if (ret)
>> + return ret;
>> +
>> + lpo_clk = devm_clk_get_enabled(dev, "btss_lpo_clk");
>> + if (IS_ERR(lpo_clk))
>> + return dev_err_probe(dev, PTR_ERR(lpo_clk),
>> + "Failed to get lpo clock\n");
>> +
>> + desc->btss_reset = devm_reset_control_get(dev, "btss_reset");
>
> Please use devm_reset_control_get_exclusive() directly.
>
>> + if (IS_ERR_OR_NULL(desc->btss_reset))
>> + return dev_err_probe(dev, PTR_ERR(desc->btss_reset),
>> + "unable to acquire btss_reset\n");
>> +
>> + ret = reset_control_deassert(desc->btss_reset);
>> + if (ret)
>> + return dev_err_probe(rproc->dev.parent, ret,
>> + "Failed to deassert reset\n");
>
> Shouldn't this be asserted on remove? Otherwise after an unbind/bind
> cycle probe will enable the clock with reset already deasserted.
> That may or may not be problematic.
>
> Consider using devm_reset_control_get_exclusive_deasserted().
>
>
> regards
> Philipp
Regards,
George
^ permalink raw reply
* Re: [PATCH 2/6] remoteproc: qcom: Add M0 BTSS secure PIL driver
From: Philipp Zabel @ 2026-06-25 14:18 UTC (permalink / raw)
To: george.moussalem, Jens Axboe, Ulf Hansson, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Johannes Berg, Jeff Johnson,
Bartosz Golaszewski, Marcel Holtmann, Luiz Augusto von Dentz,
Balakrishna Godavarthi, Rocky Liao, Saravana Kannan, Andrew Lunn,
Heiner Kallweit, Russell King, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Bjorn Andersson,
Konrad Dybcio, Mathieu Poirier
Cc: linux-block, linux-kernel, linux-mmc, devicetree, linux-wireless,
ath10k, linux-arm-msm, linux-bluetooth, netdev, linux-remoteproc
In-Reply-To: <20260625-ipq5018-bluetooth-v1-2-d999be0e04f7@outlook.com>
On Do, 2026-06-25 at 18:10 +0400, George Moussalem via B4 Relay wrote:
> From: George Moussalem <george.moussalem@outlook.com>
>
> Add support to bring up the M0 core of the bluetooth subsystem found in
> the IPQ5018 SoC.
>
> The signed firmware loaded is authenticated by TrustZone. If successful,
> the M0 core boots the firmware and the peripheral is taken out of reset
> using a Secure Channel Manager call to TrustZone.
>
> Signed-off-by: George Moussalem <george.moussalem@outlook.com>
> ---
> drivers/remoteproc/Kconfig | 12 ++
> drivers/remoteproc/Makefile | 1 +
> drivers/remoteproc/qcom_m0_btss_pil.c | 261 ++++++++++++++++++++++++++++++++++
> 3 files changed, 274 insertions(+)
>
[...]
> diff --git a/drivers/remoteproc/qcom_m0_btss_pil.c b/drivers/remoteproc/qcom_m0_btss_pil.c
> new file mode 100644
> index 000000000000..7168e270e4d4
> --- /dev/null
> +++ b/drivers/remoteproc/qcom_m0_btss_pil.c
> @@ -0,0 +1,261 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (c) 2026 The Linux Foundation. All rights reserved.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +#include <linux/elf.h>
> +#include <linux/firmware/qcom/qcom_scm.h>
> +#include <linux/io.h>
> +#include <linux/kernel.h>
> +#include <linux/of_reserved_mem.h>
> +#include <linux/platform_device.h>
> +#include <linux/reset.h>
> +#include <linux/soc/qcom/mdt_loader.h>
> +
> +#include "qcom_common.h"
> +
> +#define BTSS_PAS_ID 0xc
> +
> +struct m0_btss {
> + struct device *dev;
> + phys_addr_t mem_phys;
> + phys_addr_t mem_reloc;
> + void __iomem *mem_region;
> + size_t mem_size;
> + struct reset_control *btss_reset;
Why is this stored here? It doesn't seem to be used.
[...]
> +static int m0_btss_pil_probe(struct platform_device *pdev)
> +{
> + // struct reset_control *btss_reset;
It looks like this shouldn't be commented out.
> + struct device *dev = &pdev->dev;
> + const char *fw_name = NULL;
> + struct m0_btss *desc;
> + struct clk *lpo_clk;
> + struct rproc *rproc;
> + int ret;
> +
> + ret = of_property_read_string(dev->of_node, "firmware-name",
> + &fw_name);
> + if (ret < 0)
> + return ret;
> +
> + rproc = devm_rproc_alloc(dev, "m0btss", &m0_btss_ops,
> + fw_name, sizeof(*desc));
> + if (!rproc) {
> + dev_err(dev, "failed to allocate rproc\n");
> + return -ENOMEM;
> + }
> +
> + desc = rproc->priv;
> + desc->dev = dev;
> +
> + ret = m0_btss_alloc_memory_region(desc);
> + if (ret)
> + return ret;
> +
> + lpo_clk = devm_clk_get_enabled(dev, "btss_lpo_clk");
> + if (IS_ERR(lpo_clk))
> + return dev_err_probe(dev, PTR_ERR(lpo_clk),
> + "Failed to get lpo clock\n");
> +
> + desc->btss_reset = devm_reset_control_get(dev, "btss_reset");
Please use devm_reset_control_get_exclusive() directly.
> + if (IS_ERR_OR_NULL(desc->btss_reset))
> + return dev_err_probe(dev, PTR_ERR(desc->btss_reset),
> + "unable to acquire btss_reset\n");
> +
> + ret = reset_control_deassert(desc->btss_reset);
> + if (ret)
> + return dev_err_probe(rproc->dev.parent, ret,
> + "Failed to deassert reset\n");
Shouldn't this be asserted on remove? Otherwise after an unbind/bind
cycle probe will enable the clock with reset already deasserted.
That may or may not be problematic.
Consider using devm_reset_control_get_exclusive_deasserted().
regards
Philipp
^ permalink raw reply
* [PATCH 6/6] arm64: dts: qcom: ipq5018: add nodes required for Bluetooth support
From: George Moussalem via B4 Relay @ 2026-06-25 14:10 UTC (permalink / raw)
To: Jens Axboe, Ulf Hansson, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Johannes Berg, Jeff Johnson, Bartosz Golaszewski,
Marcel Holtmann, Luiz Augusto von Dentz, Balakrishna Godavarthi,
Rocky Liao, Saravana Kannan, Andrew Lunn, Heiner Kallweit,
Russell King, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman, Bjorn Andersson, Konrad Dybcio,
Mathieu Poirier, Philipp Zabel
Cc: linux-block, linux-kernel, linux-mmc, devicetree, linux-wireless,
ath10k, linux-arm-msm, linux-bluetooth, netdev, linux-remoteproc,
George Moussalem
In-Reply-To: <20260625-ipq5018-bluetooth-v1-0-d999be0e04f7@outlook.com>
From: George Moussalem <george.moussalem@outlook.com>
Add nodes for the M0 remoteproc, reserved memory carveout, and Bluetooth
to bring up the M0 core and enable the Bluetooth Subsystem.
Signed-off-by: George Moussalem <george.moussalem@outlook.com>
---
arch/arm64/boot/dts/qcom/ipq5018.dtsi | 34 +++++++++++++++++++++++++++++++++-
1 file changed, 33 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/boot/dts/qcom/ipq5018.dtsi b/arch/arm64/boot/dts/qcom/ipq5018.dtsi
index 6f8004a22a1f..4fdf20c87b0a 100644
--- a/arch/arm64/boot/dts/qcom/ipq5018.dtsi
+++ b/arch/arm64/boot/dts/qcom/ipq5018.dtsi
@@ -17,6 +17,17 @@ / {
#address-cells = <2>;
#size-cells = <2>;
+ bluetooth: bluetooth {
+ compatible = "qcom,ipq5018-bt";
+
+ qcom,ipc = <&apcs_glb 8 23>;
+ interrupts = <GIC_SPI 162 IRQ_TYPE_EDGE_RISING>;
+
+ qcom,rproc = <&m0_btss>;
+
+ status = "disabled";
+ };
+
clocks {
gephy_rx_clk: gephy-rx-clk {
compatible = "fixed-clock";
@@ -131,11 +142,31 @@ psci {
method = "smc";
};
+ m0_btss: remoteproc {
+ compatible = "qcom,ipq5018-btss-pil";
+
+ firmware-name = "qca/bt_fw_patch.mbn";
+
+ clocks = <&gcc GCC_BTSS_LPO_CLK>;
+ clock-names = "btss_lpo_clk";
+ resets = <&gcc GCC_BTSS_BCR>;
+ reset-names = "btss_reset";
+
+ memory-region = <&btss_region>;
+
+ status = "disabled";
+ };
+
reserved-memory {
#address-cells = <2>;
#size-cells = <2>;
ranges;
+ btss_region: bluetooth@7000000 {
+ reg = <0x0 0x07000000 0x0 0x58000>;
+ no-map;
+ };
+
bootloader@4a800000 {
reg = <0x0 0x4a800000 0x0 0x200000>;
no-map;
@@ -647,7 +678,8 @@ watchdog: watchdog@b017000 {
apcs_glb: mailbox@b111000 {
compatible = "qcom,ipq5018-apcs-apps-global",
- "qcom,ipq6018-apcs-apps-global";
+ "qcom,ipq6018-apcs-apps-global",
+ "syscon";
reg = <0x0b111000 0x1000>;
#clock-cells = <1>;
clocks = <&a53pll>, <&xo_board_clk>, <&gcc GPLL0>;
--
2.53.0
^ permalink raw reply related
* [PATCH 5/6] Bluetooth: Introduce Qualcomm IPQ5018 IPC based HCI driver
From: George Moussalem via B4 Relay @ 2026-06-25 14:10 UTC (permalink / raw)
To: Jens Axboe, Ulf Hansson, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Johannes Berg, Jeff Johnson, Bartosz Golaszewski,
Marcel Holtmann, Luiz Augusto von Dentz, Balakrishna Godavarthi,
Rocky Liao, Saravana Kannan, Andrew Lunn, Heiner Kallweit,
Russell King, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman, Bjorn Andersson, Konrad Dybcio,
Mathieu Poirier, Philipp Zabel
Cc: linux-block, linux-kernel, linux-mmc, devicetree, linux-wireless,
ath10k, linux-arm-msm, linux-bluetooth, netdev, linux-remoteproc,
George Moussalem
In-Reply-To: <20260625-ipq5018-bluetooth-v1-0-d999be0e04f7@outlook.com>
From: George Moussalem <george.moussalem@outlook.com>
Add driver support for the Qualcomm IPQ5018 bluetooth chip.
The firmware runs on the M0 co-processor.
The host and the M0 core use a shared memory carveout for transport
using ring buffers. This driver implements the transport layer between
the HCI core and the Bluetooth subsystem running on the M0 core.
Notifications of host and M0 core events are triggered by an IPC
register BIT and an interrupt line respectfully.
Signed-off-by: George Moussalem <george.moussalem@outlook.com>
---
drivers/bluetooth/Kconfig | 11 +
drivers/bluetooth/Makefile | 1 +
drivers/bluetooth/btqcomipc.c | 939 ++++++++++++++++++++++++++++++++++++++++++
3 files changed, 951 insertions(+)
diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig
index 4e8c24d757e9..6b8bed6a6ffd 100644
--- a/drivers/bluetooth/Kconfig
+++ b/drivers/bluetooth/Kconfig
@@ -413,6 +413,17 @@ config BT_MTKUART
Say Y here to compile support for MediaTek Bluetooth UART devices
into the kernel or say M to compile it as module (btmtkuart).
+config BT_QCOMIPC
+ tristate "Qualcomm IPQ5018 IPC based HCI support"
+ select BT_QCA
+ help
+ Qualcomm IPQ5018 IPC based HCI driver.
+ This driver is used to bridge HCI data onto shared memory between
+ the host and the M0 BTSS core.
+
+ Say Y here to compile support for HCI over Qualcomm IPC into the
+ kernel or say M to compile as a module.
+
config BT_QCOMSMD
tristate "Qualcomm SMD based HCI support"
depends on RPMSG || (COMPILE_TEST && RPMSG=n)
diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile
index e6b1c1180d1d..05f19047bed0 100644
--- a/drivers/bluetooth/Makefile
+++ b/drivers/bluetooth/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_BT_MRVL) += btmrvl.o
obj-$(CONFIG_BT_MRVL_SDIO) += btmrvl_sdio.o
obj-$(CONFIG_BT_MTKSDIO) += btmtksdio.o
obj-$(CONFIG_BT_MTKUART) += btmtkuart.o
+obj-$(CONFIG_BT_QCOMIPC) += btqcomipc.o
obj-$(CONFIG_BT_QCOMSMD) += btqcomsmd.o
obj-$(CONFIG_BT_BCM) += btbcm.o
obj-$(CONFIG_BT_RTL) += btrtl.o
diff --git a/drivers/bluetooth/btqcomipc.c b/drivers/bluetooth/btqcomipc.c
new file mode 100644
index 000000000000..662a75b6c4a9
--- /dev/null
+++ b/drivers/bluetooth/btqcomipc.c
@@ -0,0 +1,939 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2020 The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/bits.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/firmware/qcom/qcom_scm.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_reserved_mem.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/remoteproc.h>
+#include <linux/skbuff.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/workqueue.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+
+#include "btqca.h"
+
+/** Message header format.
+ *
+ * ----------------------------------------------------------------
+ * BitPos | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 - 0 |
+ * ---------------------------------------------------------------
+ * Field | long_msg |ACK | RFU | pkt_type | cmd |
+ * ----------------------------------------------------------------
+ *
+ * - long_msg : If set, indicates that the payload is larger than the
+ * IPC_MSG_PLD_SZ. The payload instead contains a pointer to the
+ * long message buffer in the shared BTSS memory space.
+ *
+ * - ACK : Set if sending ACK if required by sending acknowledegement
+ * to sender i.e. send an ack IPC interrupt if set.
+ *
+ * - RFU : Reserved for future use.
+ *
+ * - pkt_type : IPC Packet Type
+ *
+ * - cmd : Contains unique command ID
+ */
+
+#define IPC_MSG_HDR_SZ 4
+#define IPC_MSG_PLD_SZ 40
+#define IPC_TOTAL_MSG_SZ (IPC_MSG_HDR_SZ + IPC_MSG_PLD_SZ)
+
+/* Message Header */
+#define IPC_HDR_LONG_MSG BIT(15)
+#define IPC_HDR_REQ_ACK BIT(14)
+#define IPC_HDR_PKT_TYPE_MASK GENMASK(9, 8)
+#define IPC_HDR_PKT_TYPE_CUST 0
+#define IPC_HDR_PKT_TYPE_HCI 1
+#define IPC_HDR_PKT_TYPE_AUDIO 2
+#define IPC_HDR_PKT_TYPE_RFU 3
+#define IPC_HDR_CMD_MASK GENMASK(7, 0)
+
+#define IPC_CMD_STOP 1
+#define IPC_CMD_SWITCH_TO_UART 2
+#define IPC_CMD_PREPARE_DUMP 3
+#define IPC_CMD_COLLECT_DUMP 4
+#define IPC_CMD_START 5
+
+#define IPC_TX_QSIZE 32
+
+#define TO_APPS_ADDR(a) (desc->mem_region + (int)(uintptr_t)a)
+#define TO_BT_ADDR(a) (a - desc->mem_region)
+#define IPC_LBUF_SZ(w, x, y, z) (((TO_BT_ADDR((void *)w) + w->x) - w->y) / w->z)
+
+#define GET_NO_OF_BLOCKS(a, b) ((a + b - 1) / b)
+
+#define GET_RX_INDEX_FROM_BUF(x, y) ((x - desc->rx_ctxt->lring_buf) / y)
+
+#define GET_TX_INDEX_FROM_BUF(x, y) ((x - desc->tx_ctxt->lring_buf) / y)
+
+#define IS_RX_MEM_NON_CONTIGIOUS(buf, len, sz) \
+ ((buf + len) > (desc->rx_ctxt->lring_buf + \
+ (sz * desc->rx_ctxt->lmsg_buf_cnt)))
+
+#define POWER_CONTROL_DELAY_MS 50
+
+#define BTSS_PAS_ID 0xc
+
+struct long_msg_info {
+ __le16 smsg_free_cnt;
+ __le16 lmsg_free_cnt;
+ u8 ridx;
+ u8 widx;
+} __packed;
+
+struct ipc_aux_ptr {
+ __le32 len;
+ __le32 buf;
+} __packed;
+
+struct ring_buffer {
+ __le16 msg_hdr;
+ __le16 len;
+ union {
+ u8 smsg_data[IPC_MSG_PLD_SZ];
+ __le32 lmsg_data;
+ } payload;
+} __packed;
+
+struct ring_buffer_info {
+ __le32 rbuf;
+ u8 ring_buf_cnt;
+ u8 ridx;
+ u8 widx;
+ u8 tidx;
+ __le32 next;
+} __packed;
+
+struct context_info {
+ __le16 total_size;
+ u8 lmsg_buf_cnt;
+ u8 smsg_buf_cnt;
+ struct ring_buffer_info sring_buf_info;
+ __le32 sring_buf;
+ __le32 lring_buf;
+ __le32 reserved;
+} __packed;
+
+struct qcom_btss {
+ struct device *dev;
+ struct rproc *rproc;
+ struct hci_dev *hdev;
+
+ struct regmap *regmap;
+ u32 offset;
+ u32 bit;
+ int irq;
+
+ void *mem_region;
+ phys_addr_t mem_phys;
+ phys_addr_t mem_reloc;
+ size_t mem_size;
+
+ struct sk_buff_head tx_q;
+ struct workqueue_struct *wq;
+ struct work_struct work;
+ wait_queue_head_t wait_q;
+ spinlock_t lock;
+
+ struct context_info *tx_ctxt;
+ struct context_info *rx_ctxt;
+ struct long_msg_info lmsg_ctxt;
+
+ bool running;
+};
+
+static void btqcomipc_update_stats(struct hci_dev *hdev, struct sk_buff *skb);
+
+static void *btss_alloc_lmsg(struct qcom_btss *desc, u32 len,
+ struct ipc_aux_ptr *aux_ptr, bool *is_lbuf_full)
+{
+ struct device *dev = desc->dev;
+ u8 idx, blks, blks_consumed;
+ void *ret_ptr;
+ u32 lsz;
+
+ if (desc->tx_ctxt->lring_buf == 0) {
+ dev_err(dev, "no long message buffer initialized\n");
+ return ERR_PTR(-ENODEV);
+ }
+
+ lsz = IPC_LBUF_SZ(desc->tx_ctxt, total_size, lring_buf, lmsg_buf_cnt);
+ blks = GET_NO_OF_BLOCKS(len, lsz);
+
+ if (!desc->lmsg_ctxt.lmsg_free_cnt ||
+ (blks > desc->lmsg_ctxt.lmsg_free_cnt))
+ return ERR_PTR(-EAGAIN);
+
+ idx = desc->lmsg_ctxt.widx;
+
+ if ((desc->lmsg_ctxt.widx + blks) > desc->tx_ctxt->lmsg_buf_cnt) {
+ blks_consumed = desc->tx_ctxt->lmsg_buf_cnt - idx;
+ aux_ptr->len = len - (blks_consumed * lsz);
+ aux_ptr->buf = desc->tx_ctxt->lring_buf;
+ }
+
+ desc->lmsg_ctxt.widx = (desc->lmsg_ctxt.widx + blks) %
+ desc->tx_ctxt->lmsg_buf_cnt;
+
+ desc->lmsg_ctxt.lmsg_free_cnt -= blks;
+
+ if (desc->lmsg_ctxt.lmsg_free_cnt <=
+ ((desc->tx_ctxt->lmsg_buf_cnt * 20) / 100))
+ *is_lbuf_full = true;
+
+ ret_ptr = TO_APPS_ADDR(desc->tx_ctxt->lring_buf) + (idx * lsz);
+
+ return ret_ptr;
+}
+
+static struct ring_buffer_info *btss_get_tx_rbuf(struct qcom_btss *desc,
+ bool *is_sbuf_full)
+{
+ u8 idx;
+ struct ring_buffer_info *rinfo;
+
+ for (rinfo = &(desc->tx_ctxt->sring_buf_info); rinfo != NULL;
+ rinfo = (struct ring_buffer_info *)(uintptr_t)(rinfo->next)) {
+ idx = (rinfo->widx + 1) % (desc->tx_ctxt->smsg_buf_cnt);
+
+ if (idx != rinfo->tidx) {
+ desc->lmsg_ctxt.smsg_free_cnt--;
+
+ if (desc->lmsg_ctxt.smsg_free_cnt <=
+ ((desc->tx_ctxt->smsg_buf_cnt * 20) / 100))
+ *is_sbuf_full = true;
+
+ return rinfo;
+ }
+ }
+
+ return ERR_PTR(-EAGAIN);
+}
+
+static int btss_send(struct qcom_btss *desc, u16 msg_hdr,
+ struct sk_buff *skb)
+{
+ struct hci_dev *hdev = desc->hdev;
+ struct ring_buffer_info *rinfo;
+ struct ipc_aux_ptr aux_ptr;
+ struct ring_buffer *rbuf;
+ bool is_lbuf_full = false;
+ bool is_sbuf_full = false;
+ u16 hdr = msg_hdr;
+ void *ptr_buf;
+ u32 len;
+
+ /* Account for HCI packet type as it's not included in the skb payload */
+ len = skb->len + 1;
+ memset(&aux_ptr, 0, sizeof(struct ipc_aux_ptr));
+
+ if (len > IPC_MSG_PLD_SZ) {
+ hdr |= IPC_HDR_LONG_MSG;
+
+ ptr_buf = btss_alloc_lmsg(desc, len,
+ &aux_ptr, &is_lbuf_full);
+ if (IS_ERR(ptr_buf)) {
+ bt_dev_err(hdev, "long msg buf full");
+ hdev->stat.err_tx++;
+ return PTR_ERR(ptr_buf);
+ }
+ }
+
+ rinfo = btss_get_tx_rbuf(desc, &is_sbuf_full);
+ if (IS_ERR(rinfo)) {
+ bt_dev_err(hdev, "short msg buf full");
+ hdev->stat.err_tx++;
+ return PTR_ERR(rinfo);
+ }
+
+ rbuf = &((struct ring_buffer *)(TO_APPS_ADDR(rinfo->rbuf)))[rinfo->widx];
+
+ if (len > IPC_MSG_PLD_SZ)
+ rbuf->payload.lmsg_data = cpu_to_le32(TO_BT_ADDR(ptr_buf));
+ else
+ ptr_buf = rbuf->payload.smsg_data;
+
+ /* if it's a short message, the aux len and buf are NULL */
+ memcpy_toio(ptr_buf, &hci_skb_pkt_type(skb), 1);
+ memcpy_toio((u8 *)ptr_buf + 1, skb->data, skb->len - aux_ptr.len);
+ if (aux_ptr.buf) {
+ memcpy_toio(TO_APPS_ADDR(aux_ptr.buf),
+ (skb->data + (skb->len - aux_ptr.len)), aux_ptr.len);
+ }
+
+ if (is_sbuf_full || is_lbuf_full)
+ hdr |= IPC_HDR_REQ_ACK;
+
+ rbuf->msg_hdr = cpu_to_le16(hdr);
+ rbuf->len = cpu_to_le16(len);
+
+ rinfo->widx = (rinfo->widx + 1) % desc->tx_ctxt->smsg_buf_cnt;
+
+ regmap_set_bits(desc->regmap, desc->offset, BIT(desc->bit));
+
+ return 0;
+}
+
+static void btss_process_tx_queue(struct qcom_btss *desc)
+{
+ struct sk_buff *skb;
+ u16 hdr;
+ int ret;
+
+ while ((skb = skb_dequeue(&desc->tx_q))) {
+ hdr = FIELD_PREP(IPC_HDR_PKT_TYPE_MASK, IPC_HDR_PKT_TYPE_HCI);
+
+ ret = btss_send(desc, hdr, skb);
+ if (ret) {
+ bt_dev_err(desc->hdev, "Failed to send message");
+ skb_queue_head(&desc->tx_q, skb);
+ break;
+ }
+
+ btqcomipc_update_stats(desc->hdev, skb);
+ kfree_skb(skb);
+ }
+}
+
+static void btss_free_lmsg(struct qcom_btss *desc, u32 lmsg, u16 len)
+{
+ u8 idx;
+ u8 blks;
+ u32 lsz = IPC_LBUF_SZ(desc->tx_ctxt, total_size, lring_buf,
+ lmsg_buf_cnt);
+
+ idx = GET_TX_INDEX_FROM_BUF(lmsg, lsz);
+
+ if (idx != desc->lmsg_ctxt.ridx)
+ return;
+
+ blks = GET_NO_OF_BLOCKS(len, lsz);
+
+ desc->lmsg_ctxt.ridx = (desc->lmsg_ctxt.ridx + blks) %
+ desc->tx_ctxt->lmsg_buf_cnt;
+
+ desc->lmsg_ctxt.lmsg_free_cnt += blks;
+}
+
+static int btss_send_ctrl(struct qcom_btss *desc, u16 msg_hdr)
+{
+ struct ring_buffer_info *rinfo;
+ struct ring_buffer *rbuf;
+
+ rinfo = btss_get_tx_rbuf(desc, NULL);
+ if (IS_ERR(rinfo))
+ return PTR_ERR(rinfo);
+
+ rbuf = &((struct ring_buffer *)TO_APPS_ADDR(rinfo->rbuf))[rinfo->widx];
+ rbuf->msg_hdr = cpu_to_le16(msg_hdr);
+ rbuf->len = 0;
+
+ rinfo->widx = (rinfo->widx + 1) % desc->tx_ctxt->smsg_buf_cnt;
+
+ regmap_set_bits(desc->regmap, desc->offset, BIT(desc->bit));
+
+ return 0;
+}
+
+static void btss_recv_cust_frame(struct qcom_btss *desc, u8 cmd)
+{
+ u16 msg_hdr = 0;
+ int ret;
+
+ msg_hdr |= cmd;
+
+ switch (cmd) {
+ case IPC_CMD_STOP:
+ bt_dev_info(desc->hdev, "BTSS stopped, gracefully stopping APSS IPC");
+ break;
+ case IPC_CMD_START:
+ desc->tx_ctxt = (struct context_info *)((void *)desc->rx_ctxt +
+ le16_to_cpu(desc->rx_ctxt->total_size));
+ desc->lmsg_ctxt.widx = 0;
+ desc->lmsg_ctxt.ridx = 0;
+ desc->lmsg_ctxt.smsg_free_cnt = desc->tx_ctxt->smsg_buf_cnt;
+ desc->lmsg_ctxt.lmsg_free_cnt = desc->tx_ctxt->lmsg_buf_cnt;
+ WRITE_ONCE(desc->running, true);
+ wake_up(&desc->wait_q);
+
+ bt_dev_info(desc->hdev, "BTSS started, initializing APSS BT IPC");
+ return;
+ default:
+ bt_dev_err(desc->hdev, "Unsupported CMD ID: %u", cmd);
+ return;
+ }
+
+ if (unlikely(!READ_ONCE(desc->running))) {
+ bt_dev_err(desc->hdev, "BTSS not initialized, no message sent");
+ return;
+ }
+
+ WRITE_ONCE(desc->running, false);
+
+ ret = btss_send_ctrl(desc, msg_hdr);
+ if (ret)
+ bt_dev_err(desc->hdev, "Failed to send control message");
+}
+
+static inline int btss_recv_hci_frame(struct qcom_btss *desc, const u8 *data, size_t len)
+{
+ unsigned char pkt_type;
+ struct sk_buff *skb;
+ size_t pkt_len;
+
+ if (len < 1)
+ return -EPROTO;
+
+ pkt_type = data[0];
+
+ switch (pkt_type) {
+ case HCI_EVENT_PKT:
+ {
+ if (len < HCI_EVENT_HDR_SIZE)
+ return -EILSEQ;
+ struct hci_event_hdr *hdr = (struct hci_event_hdr *)(data + 1);
+
+ pkt_len = HCI_EVENT_HDR_SIZE + hdr->plen;
+ break;
+ }
+ case HCI_COMMAND_PKT: {
+ if (len < HCI_COMMAND_HDR_SIZE)
+ return -EILSEQ;
+ struct hci_command_hdr *hdr = (struct hci_command_hdr *)(data + 1);
+
+ pkt_len = HCI_COMMAND_HDR_SIZE + le16_to_cpu(hdr->plen);
+ break;
+ }
+ case HCI_ACLDATA_PKT:
+ {
+ if (len < HCI_ACL_HDR_SIZE)
+ return -EILSEQ;
+ struct hci_acl_hdr *hdr = (struct hci_acl_hdr *)(data + 1);
+
+ pkt_len = HCI_ACL_HDR_SIZE + le16_to_cpu(hdr->dlen);
+ break;
+ }
+ case HCI_SCODATA_PKT:
+ {
+ if (len < HCI_SCO_HDR_SIZE)
+ return -EILSEQ;
+ struct hci_sco_hdr *hdr = (struct hci_sco_hdr *)(data + 1);
+
+ pkt_len = HCI_SCO_HDR_SIZE + hdr->dlen;
+ break;
+ }
+ default:
+ return -EPROTO;
+ }
+
+ if (pkt_len > len)
+ return -EINVAL;
+
+ skb = bt_skb_alloc(pkt_len, GFP_ATOMIC);
+ if (!skb) {
+ desc->hdev->stat.err_rx++;
+ return -ENOMEM;
+ }
+
+ skb->dev = (void *)desc->hdev;
+ hci_skb_pkt_type(skb) = pkt_type;
+ skb_put_data(skb, data + 1, pkt_len);
+
+ hci_recv_frame(desc->hdev, skb);
+ desc->hdev->stat.byte_rx += pkt_len;
+
+ return 0;
+}
+
+static inline int btss_process_rx(struct qcom_btss *desc,
+ struct ring_buffer_info *rinfo,
+ bool *ack, u8 *rx_count)
+{
+ u8 ridx, lbuf_idx, blks_consumed, pkt_type, cmd;
+ struct ipc_aux_ptr aux_ptr;
+ struct ring_buffer *rbuf;
+ uint8_t *rxbuf = NULL;
+ unsigned char *buf;
+ u32 lsz;
+ int ret;
+
+ ridx = rinfo->ridx;
+
+ while (ridx != rinfo->widx) {
+ memset(&aux_ptr, 0, sizeof(struct ipc_aux_ptr));
+
+ rbuf = &((struct ring_buffer *)(TO_APPS_ADDR(rinfo->rbuf)))[ridx];
+
+ if (rbuf->msg_hdr & IPC_HDR_LONG_MSG) {
+ rxbuf = TO_APPS_ADDR(rbuf->payload.lmsg_data);
+ lsz = IPC_LBUF_SZ(desc->rx_ctxt, total_size, lring_buf,
+ lmsg_buf_cnt);
+
+ if (IS_RX_MEM_NON_CONTIGIOUS(rbuf->payload.lmsg_data,
+ rbuf->len, lsz)) {
+ lbuf_idx = GET_RX_INDEX_FROM_BUF(
+ rbuf->payload.lmsg_data, lsz);
+
+ blks_consumed = desc->rx_ctxt->lmsg_buf_cnt -
+ lbuf_idx;
+ aux_ptr.len = rbuf->len - (blks_consumed * lsz);
+ aux_ptr.buf = desc->rx_ctxt->lring_buf;
+ }
+ } else {
+ rxbuf = rbuf->payload.smsg_data;
+ }
+
+ *ack = (rbuf->msg_hdr & IPC_HDR_REQ_ACK);
+
+ pkt_type = FIELD_GET(IPC_HDR_PKT_TYPE_MASK, rbuf->msg_hdr);
+
+ switch (pkt_type) {
+ case IPC_HDR_PKT_TYPE_HCI:
+ buf = kmalloc(rbuf->len, GFP_ATOMIC);
+ if (!buf) {
+ rinfo->ridx = ridx;
+ return -ENOMEM;
+ }
+
+ memcpy_fromio(buf, rxbuf, rbuf->len - aux_ptr.len);
+
+ if (aux_ptr.buf)
+ memcpy_fromio(buf + (rbuf->len - aux_ptr.len),
+ TO_APPS_ADDR(aux_ptr.buf), aux_ptr.len);
+
+ ret = btss_recv_hci_frame(desc, buf, rbuf->len);
+ if (ret)
+ bt_dev_err(desc->hdev, "Failed to process HCI frame: %d", ret);
+ kfree(buf);
+ break;
+ case IPC_HDR_PKT_TYPE_CUST:
+ cmd = FIELD_GET(IPC_HDR_CMD_MASK, rbuf->msg_hdr);
+ btss_recv_cust_frame(desc, cmd);
+ break;
+ default:
+ break;
+ }
+
+ ridx = (ridx + 1) % rinfo->ring_buf_cnt;
+
+ if (rx_count)
+ (*rx_count)++;
+
+ rinfo->ridx = ridx;
+ }
+
+ return 0;
+}
+
+static void btss_process_ack(struct qcom_btss *desc)
+{
+ struct ring_buffer_info *rinfo;
+ struct ring_buffer *rbuf;
+ u8 tidx;
+
+ for (rinfo = &desc->tx_ctxt->sring_buf_info; rinfo != NULL;
+ rinfo = (struct ring_buffer_info *)(uintptr_t)(rinfo->next)) {
+ tidx = rinfo->tidx;
+ rbuf = (struct ring_buffer *)TO_APPS_ADDR(rinfo->rbuf);
+
+ while (tidx != rinfo->ridx) {
+ if (rbuf[tidx].msg_hdr & IPC_HDR_LONG_MSG) {
+ btss_free_lmsg(desc,
+ rbuf[tidx].payload.lmsg_data,
+ rbuf[tidx].len);
+ }
+
+ tidx = (tidx + 1) % desc->tx_ctxt->smsg_buf_cnt;
+ desc->lmsg_ctxt.smsg_free_cnt++;
+ }
+
+ rinfo->tidx = tidx;
+
+ btss_process_tx_queue(desc);
+ }
+}
+
+static void btss_worker(struct work_struct *work)
+{
+ struct qcom_btss *desc = container_of(work, struct qcom_btss, work);
+ struct ring_buffer_info *rinfo;
+ bool ack = false;
+ u32 offset;
+ int ret;
+
+ if (desc->rproc->state != RPROC_RUNNING)
+ return;
+
+ spin_lock(&desc->lock);
+
+ if (unlikely(!READ_ONCE(desc->running))) {
+ // FW sets offset of RX context info at start of memory region upon boot
+ offset = readl(desc->mem_region);
+ dev_dbg(desc->dev, "offset after M0 boot: 0x%08x\n", offset);
+ desc->rx_ctxt = (struct context_info *)(desc->mem_region + offset);
+ } else {
+ btss_process_ack(desc);
+ }
+
+ for (rinfo = &(desc->rx_ctxt->sring_buf_info);
+ rinfo != NULL;
+ rinfo = (struct ring_buffer_info *)(uintptr_t)(rinfo->next)) {
+ ret = btss_process_rx(desc, rinfo, &ack,
+ &desc->rx_ctxt->smsg_buf_cnt);
+ if (ret) {
+ bt_dev_err(desc->hdev, "Failed to process peer msgs: %d", ret);
+ goto spin_unlock;
+ }
+ }
+
+ if (ack)
+ regmap_set_bits(desc->regmap, desc->offset, BIT(desc->bit));
+
+spin_unlock:
+ spin_unlock(&desc->lock);
+}
+
+static irqreturn_t btss_irq_handler(int irq, void *data)
+{
+ struct qcom_btss *desc = data;
+
+ queue_work(desc->wq, &desc->work);
+
+ return IRQ_HANDLED;
+}
+
+static int btss_init(struct qcom_btss *desc)
+{
+ struct device *dev = desc->dev;
+ int ret;
+
+ init_waitqueue_head(&desc->wait_q);
+ spin_lock_init(&desc->lock);
+ skb_queue_head_init(&desc->tx_q);
+
+ desc->wq = create_singlethread_workqueue("btss_wq");
+ if (!desc->wq) {
+ dev_err(dev, "Failed to initialize workqueue\n");
+ return -EAGAIN;
+ }
+
+ INIT_WORK(&desc->work, btss_worker);
+
+ ret = devm_request_threaded_irq(dev, desc->irq, NULL, btss_irq_handler,
+ IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+ "btss_irq", desc);
+
+ if (ret)
+ dev_err(dev, "error registering irq[%d] ret = %d\n",
+ desc->irq, ret);
+
+ return ret;
+}
+
+static void btqcomipc_update_stats(struct hci_dev *hdev, struct sk_buff *skb)
+{
+ u8 pkt_type = hci_skb_pkt_type(skb);
+
+ hdev->stat.byte_tx += skb->len;
+ switch (pkt_type) {
+ case HCI_COMMAND_PKT:
+ hdev->stat.cmd_tx++;
+ break;
+ case HCI_ACLDATA_PKT:
+ hdev->stat.acl_tx++;
+ break;
+ case HCI_SCODATA_PKT:
+ hdev->stat.sco_tx++;
+ break;
+ default:
+ break;
+ }
+}
+
+static int btqcomipc_open(struct hci_dev *hdev)
+{
+ struct qcom_btss *desc = hci_get_drvdata(hdev);
+
+ int ret;
+
+ ret = btss_init(desc);
+ if (ret) {
+ bt_dev_err(hdev, "Failed initializing BTSS: %d", ret);
+ return ret;
+ }
+
+ /* wait 2 seconds for filesystem to become available */
+ msleep(2000);
+
+ /* Boot M0 firmware */
+ ret = rproc_boot(desc->rproc);
+ if (ret) {
+ bt_dev_err(hdev, "Failed to boot M0 processor: %d", ret);
+ return ret;
+ }
+
+ msleep(POWER_CONTROL_DELAY_MS);
+ ret = wait_event_timeout(desc->wait_q, READ_ONCE(desc->running),
+ msecs_to_jiffies(1000));
+
+ if (!ret) {
+ bt_dev_err(hdev, "Timeout waiting for BTSS start");
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static int btqcomipc_close(struct hci_dev *hdev)
+{
+ struct qcom_btss *desc = hci_get_drvdata(hdev);
+
+ rproc_shutdown(desc->rproc);
+ msleep(POWER_CONTROL_DELAY_MS);
+
+ return 0;
+}
+
+static int btqcomipc_shutdown(struct hci_dev *hdev)
+{
+ struct qcom_btss *desc = hci_get_drvdata(hdev);
+
+ WRITE_ONCE(desc->running, false);
+ if (desc->wq != NULL) {
+ disable_irq(desc->irq);
+ flush_workqueue(desc->wq);
+ devm_free_irq(desc->dev, desc->irq, desc);
+ skb_queue_purge(&desc->tx_q);
+ destroy_workqueue(desc->wq);
+ desc->wq = NULL;
+ }
+
+ return 0;
+}
+
+static int btqcomipc_setup(struct hci_dev *hdev)
+{
+ struct qca_btsoc_version ver;
+ int ret;
+
+ /*
+ * Enable controller to do both LE scan and BR/EDR inquiry
+ * simultaneously.
+ */
+ hci_set_quirk(hdev, HCI_QUIRK_SIMULTANEOUS_DISCOVERY);
+
+ /*
+ * Enable NON_PERSISTENT_SETUP QUIRK to ensure to execute
+ * setup for every hci up.
+ */
+ hci_set_quirk(hdev, HCI_QUIRK_NON_PERSISTENT_SETUP);
+ ret = qca_read_soc_version(hdev, &ver, QCA_IPQ5018);
+ if (ret)
+ return -EINVAL;
+
+ ret = qca_uart_setup(hdev, 0, QCA_IPQ5018, ver, NULL);
+ if (ret) {
+ bt_dev_err(hdev, "Failed to setup UART: %d\n", ret);
+ return ret;
+ }
+
+ bt_dev_info(hdev, "QCA Build Info: %s", hdev->fw_info);
+
+ /* Obtain and set BD address from NVMEM cell */
+ hci_set_quirk(hdev, HCI_QUIRK_USE_BDADDR_NVMEM);
+ hci_set_quirk(hdev, HCI_QUIRK_BDADDR_NVMEM_BE);
+
+ return 0;
+}
+
+static int btqcomipc_send(struct hci_dev *hdev, struct sk_buff *skb)
+{
+ u16 hdr = FIELD_PREP(IPC_HDR_PKT_TYPE_MASK, IPC_HDR_PKT_TYPE_HCI);
+ struct qcom_btss *desc = hci_get_drvdata(hdev);
+ int ret;
+
+ if (unlikely(!READ_ONCE(desc->running))) {
+ bt_dev_err(hdev, "BTSS not initialized, failed to send message");
+ ret = -ENODEV;
+ goto free_skb;
+ }
+
+ ret = btss_send(desc, hdr, skb);
+ if (ret) {
+ if (ret == -EAGAIN) {
+ if (skb_queue_len(&desc->tx_q) >= IPC_TX_QSIZE) {
+ bt_dev_err(hdev, "TX queue full, dropping message");
+ hdev->stat.err_tx++;
+ ret = -ENOBUFS;
+ } else {
+ skb_queue_tail(&desc->tx_q, skb);
+ return 0;
+ }
+ } else {
+ bt_dev_err(hdev, "Failed to send message: %d", ret);
+ hdev->stat.err_tx++;
+ }
+ }
+
+ btqcomipc_update_stats(desc->hdev, skb);
+
+free_skb:
+ kfree_skb(skb);
+
+ return ret;
+}
+
+static int btqcomipc_flush(struct hci_dev *hdev)
+{
+ struct qcom_btss *desc = hci_get_drvdata(hdev);
+
+ skb_queue_purge(&desc->tx_q);
+ return 0;
+}
+
+static int btqcomipc_alloc_memory_region(struct qcom_btss *desc)
+{
+ struct device *dev = desc->dev;
+ struct resource res;
+ int ret;
+
+ /* lookup reserved-memory region of the remoteproc node */
+ ret = of_reserved_mem_region_to_resource(desc->rproc->dev.parent->of_node, 0, &res);
+ if (ret) {
+ dev_err(dev, "unable to acquire memory-region resource\n");
+ return ret;
+ }
+
+ desc->mem_phys = res.start;
+ desc->mem_reloc = res.start;
+ desc->mem_size = resource_size(&res);
+ desc->mem_region = devm_ioremap(dev, desc->mem_phys, desc->mem_size);
+ if (!desc->mem_region) {
+ dev_err(dev, "unable to map memory region: %pR\n", &res);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static void btqcomipc_rproc_put(void *data)
+{
+ struct rproc *rproc = data;
+
+ rproc_put(rproc);
+}
+
+static int btqcomipc_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct qcom_btss *desc;
+ phandle rproc_phandle;
+ struct hci_dev *hdev;
+ unsigned int args[2];
+ int ret;
+
+ desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
+ if (!desc)
+ return -ENOMEM;
+
+ desc->dev = dev;
+
+ if (of_property_read_u32(dev->of_node, "qcom,rproc", &rproc_phandle))
+ return dev_err_probe(dev, -ENOENT, "Failed to get remoteproc handle\n");
+
+ desc->rproc = rproc_get_by_phandle(rproc_phandle);
+ if (!desc->rproc)
+ return dev_err_probe(dev, -EPROBE_DEFER, "Failed to get remoteproc\n");
+
+ devm_add_action_or_reset(dev, btqcomipc_rproc_put, desc->rproc);
+
+ ret = btqcomipc_alloc_memory_region(desc);
+ if (ret)
+ return ret;
+
+ desc->regmap = syscon_regmap_lookup_by_phandle_args(dev->of_node, "qcom,ipc", 2, args);
+ if (IS_ERR(desc->regmap))
+ return PTR_ERR(desc->regmap);
+
+ desc->offset = args[0];
+ desc->bit = args[1];
+
+ desc->irq = platform_get_irq(pdev, 0);
+ if (desc->irq < 0)
+ return dev_err_probe(dev, desc->irq, "Failed to acquire IRQ\n");
+
+ hdev = hci_alloc_dev();
+ if (!hdev)
+ return -ENOMEM;
+
+ hci_set_drvdata(hdev, desc);
+ desc->hdev = hdev;
+ SET_HCIDEV_DEV(hdev, &pdev->dev);
+ hdev->bus = HCI_IPC;
+
+ hdev->open = btqcomipc_open;
+ hdev->close = btqcomipc_close;
+ hdev->shutdown = btqcomipc_shutdown;
+ hdev->setup = btqcomipc_setup;
+ hdev->send = btqcomipc_send;
+ hdev->flush = btqcomipc_flush;
+ hdev->set_bdaddr = qca_set_bdaddr;
+
+ ret = hci_register_dev(hdev);
+ if (ret < 0) {
+ hci_free_dev(hdev);
+ return dev_err_probe(dev, -EBUSY, "Failed to register hdev\n");
+ }
+
+ platform_set_drvdata(pdev, desc);
+
+ return 0;
+}
+
+static void btqcomipc_remove(struct platform_device *pdev)
+{
+ struct qcom_btss *desc = platform_get_drvdata(pdev);
+
+ if (!desc || !desc->hdev)
+ return;
+
+ hci_unregister_dev(desc->hdev);
+ hci_free_dev(desc->hdev);
+}
+
+static const struct of_device_id btqcomipc_of_match[] = {
+ { .compatible = "qcom,ipq5018-bt" },
+ { /* sentinel */},
+};
+MODULE_DEVICE_TABLE(of, btqcomipc_of_match);
+
+static struct platform_driver btqcomipc_driver = {
+ .probe = btqcomipc_probe,
+ .remove = btqcomipc_remove,
+ .driver = {
+ .name = "btqcomipc",
+ .of_match_table = btqcomipc_of_match,
+ },
+};
+
+module_platform_driver(btqcomipc_driver);
+
+MODULE_DESCRIPTION("Qualcomm Bluetooth IPC Driver");
+MODULE_LICENSE("GPL");
--
2.53.0
^ permalink raw reply related
* [PATCH 4/6] dt-bindings: net: bluetooth: Document Qualcomm IPQ5018 Bluetooth controller
From: George Moussalem via B4 Relay @ 2026-06-25 14:10 UTC (permalink / raw)
To: Jens Axboe, Ulf Hansson, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Johannes Berg, Jeff Johnson, Bartosz Golaszewski,
Marcel Holtmann, Luiz Augusto von Dentz, Balakrishna Godavarthi,
Rocky Liao, Saravana Kannan, Andrew Lunn, Heiner Kallweit,
Russell King, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman, Bjorn Andersson, Konrad Dybcio,
Mathieu Poirier, Philipp Zabel
Cc: linux-block, linux-kernel, linux-mmc, devicetree, linux-wireless,
ath10k, linux-arm-msm, linux-bluetooth, netdev, linux-remoteproc,
George Moussalem
In-Reply-To: <20260625-ipq5018-bluetooth-v1-0-d999be0e04f7@outlook.com>
From: George Moussalem <george.moussalem@outlook.com>
Document the Qualcomm IPQ5018 Bluetooth controller.
Signed-off-by: George Moussalem <george.moussalem@outlook.com>
---
.../bindings/net/bluetooth/qcom,ipq5018-bt.yaml | 63 ++++++++++++++++++++++
1 file changed, 63 insertions(+)
diff --git a/Documentation/devicetree/bindings/net/bluetooth/qcom,ipq5018-bt.yaml b/Documentation/devicetree/bindings/net/bluetooth/qcom,ipq5018-bt.yaml
new file mode 100644
index 000000000000..afd33f851858
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/bluetooth/qcom,ipq5018-bt.yaml
@@ -0,0 +1,63 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/net/bluetooth/qcom,ipq5018-bt.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm IPQ5018 Bluetooth
+
+maintainers:
+ - George Moussalem <george.moussalem@outlook.com>
+
+properties:
+ compatible:
+ enum:
+ - qcom,ipq5018-bt
+
+ interrupts:
+ items:
+ - description:
+ Interrupt line from the M0 Bluetooth Subsystem to the host processor
+ to notify it of events such as re
+
+ qcom,ipc:
+ $ref: /schemas/types.yaml#/definitions/phandle-array
+ items:
+ - items:
+ - description: phandle to a syscon node representing the APCS registers
+ - description: u32 representing offset to the register within the syscon
+ - description: u32 representing the ipc bit within the register
+ description: |
+ These entries specify the outgoing IPC bit used for signaling the remote
+ M0 BTSS core of a host event or for sending an ACK if the remote processor
+ expects it.
+
+ qcom,rproc:
+ $ref: /schemas/types.yaml#/definitions/phandle
+ description:
+ Phandle to the remote processor node representing the M0 BTSS core.
+
+required:
+ - compatible
+ - interrupts
+ - qcom,ipc
+ - qcom,rproc
+
+allOf:
+ - $ref: bluetooth-controller.yaml#
+ - $ref: qcom,bluetooth-common.yaml
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+ bluetooth: bluetooth {
+ compatible = "qcom,ipq5018-bt";
+
+ qcom,ipc = <&apcs_glb 8 23>;
+ interrupts = <GIC_SPI 162 IRQ_TYPE_EDGE_RISING>;
+
+ qcom,rproc = <&m0_btss>;
+ };
--
2.53.0
^ permalink raw reply related
* [PATCH 2/6] remoteproc: qcom: Add M0 BTSS secure PIL driver
From: George Moussalem via B4 Relay @ 2026-06-25 14:10 UTC (permalink / raw)
To: Jens Axboe, Ulf Hansson, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Johannes Berg, Jeff Johnson, Bartosz Golaszewski,
Marcel Holtmann, Luiz Augusto von Dentz, Balakrishna Godavarthi,
Rocky Liao, Saravana Kannan, Andrew Lunn, Heiner Kallweit,
Russell King, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman, Bjorn Andersson, Konrad Dybcio,
Mathieu Poirier, Philipp Zabel
Cc: linux-block, linux-kernel, linux-mmc, devicetree, linux-wireless,
ath10k, linux-arm-msm, linux-bluetooth, netdev, linux-remoteproc,
George Moussalem
In-Reply-To: <20260625-ipq5018-bluetooth-v1-0-d999be0e04f7@outlook.com>
From: George Moussalem <george.moussalem@outlook.com>
Add support to bring up the M0 core of the bluetooth subsystem found in
the IPQ5018 SoC.
The signed firmware loaded is authenticated by TrustZone. If successful,
the M0 core boots the firmware and the peripheral is taken out of reset
using a Secure Channel Manager call to TrustZone.
Signed-off-by: George Moussalem <george.moussalem@outlook.com>
---
drivers/remoteproc/Kconfig | 12 ++
drivers/remoteproc/Makefile | 1 +
drivers/remoteproc/qcom_m0_btss_pil.c | 261 ++++++++++++++++++++++++++++++++++
3 files changed, 274 insertions(+)
diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
index c521c744e7db..6b52f78f1427 100644
--- a/drivers/remoteproc/Kconfig
+++ b/drivers/remoteproc/Kconfig
@@ -163,6 +163,18 @@ config PRU_REMOTEPROC
processors on various TI SoCs. It's safe to say N here if you're
not interested in the PRU or if you are unsure.
+config QCOM_M0_BTSS_PIL
+ tristate "Qualcomm M0 BTSS Peripheral Image Loader"
+ depends on OF && ARCH_QCOM
+ select QCOM_MDT_LOADER
+ select QCOM_RPROC_COMMON
+ select QCOM_SCM
+ help
+ Say y here to support the Secure Peripheral Imager Loader for the
+ Qualcomm Bluetooth Subsystem running on the M0 remote processor found
+ in the IPQ5018 SoC. The M0 core is started and stopped using a
+ Secure Channel Manager call to TrustZone.
+
config QCOM_PIL_INFO
tristate
diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile
index 1c7598b8475d..df80faf8d0df 100644
--- a/drivers/remoteproc/Makefile
+++ b/drivers/remoteproc/Makefile
@@ -21,6 +21,7 @@ obj-$(CONFIG_DA8XX_REMOTEPROC) += da8xx_remoteproc.o
obj-$(CONFIG_KEYSTONE_REMOTEPROC) += keystone_remoteproc.o
obj-$(CONFIG_MESON_MX_AO_ARC_REMOTEPROC)+= meson_mx_ao_arc.o
obj-$(CONFIG_PRU_REMOTEPROC) += pru_rproc.o
+obj-$(CONFIG_QCOM_M0_BTSS_PIL) += qcom_m0_btss_pil.o
obj-$(CONFIG_QCOM_PIL_INFO) += qcom_pil_info.o
obj-$(CONFIG_QCOM_RPROC_COMMON) += qcom_common.o
obj-$(CONFIG_QCOM_Q6V5_COMMON) += qcom_q6v5.o
diff --git a/drivers/remoteproc/qcom_m0_btss_pil.c b/drivers/remoteproc/qcom_m0_btss_pil.c
new file mode 100644
index 000000000000..7168e270e4d4
--- /dev/null
+++ b/drivers/remoteproc/qcom_m0_btss_pil.c
@@ -0,0 +1,261 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2026 The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/elf.h>
+#include <linux/firmware/qcom/qcom_scm.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/of_reserved_mem.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+#include <linux/soc/qcom/mdt_loader.h>
+
+#include "qcom_common.h"
+
+#define BTSS_PAS_ID 0xc
+
+struct m0_btss {
+ struct device *dev;
+ phys_addr_t mem_phys;
+ phys_addr_t mem_reloc;
+ void __iomem *mem_region;
+ size_t mem_size;
+ struct reset_control *btss_reset;
+};
+
+static int m0_btss_start(struct rproc *rproc)
+{
+ int ret;
+
+ if (!qcom_scm_pas_supported(BTSS_PAS_ID)) {
+ dev_err(rproc->dev.parent,
+ "PAS is not available for peripheral: 0x%x\n",
+ BTSS_PAS_ID);
+ return -ENODEV;
+ }
+
+ ret = qcom_scm_pas_auth_and_reset(BTSS_PAS_ID);
+ if (ret) {
+ dev_err(rproc->dev.parent, "Failed to start rproc: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int m0_btss_stop(struct rproc *rproc)
+{
+ int ret;
+
+ if (rproc->state == RPROC_RUNNING || rproc->state == RPROC_CRASHED) {
+ ret = qcom_scm_pas_shutdown(BTSS_PAS_ID);
+ if (ret) {
+ dev_err(rproc->dev.parent, "Failed to stop rproc: %d\n",
+ ret);
+ return ret;
+ }
+
+ dev_info(rproc->dev.parent, "Successfully stopped rproc\n");
+ }
+
+ return 0;
+}
+
+static int m0_btss_load(struct rproc *rproc, const struct firmware *fw)
+{
+ struct m0_btss *desc = rproc->priv;
+ const struct elf32_phdr *phdrs;
+ const struct firmware *seg_fw;
+ const struct elf32_phdr *phdr;
+ const struct elf32_hdr *ehdr;
+ void __iomem *metadata;
+ size_t metadata_size;
+ int i, ret;
+
+ ehdr = (const struct elf32_hdr *)fw->data;
+ phdrs = (const struct elf32_phdr *)(ehdr + 1);
+
+ ret = request_firmware(&fw, rproc->firmware, rproc->dev.parent);
+ if (ret) {
+ dev_err(rproc->dev.parent, "Failed to request firmware: %d\n",
+ ret);
+ return ret;
+ }
+
+ metadata = qcom_mdt_read_metadata(fw, &metadata_size, rproc->firmware,
+ rproc->dev.parent);
+ if (IS_ERR(metadata)) {
+ ret = PTR_ERR(metadata);
+ dev_err(rproc->dev.parent,
+ "Failed to read firmware metadata: %d\n", ret);
+ goto release_fw;
+ }
+
+ ret = qcom_scm_pas_init_image(BTSS_PAS_ID, metadata,
+ metadata_size, NULL);
+ if (ret) {
+ dev_err(rproc->dev.parent, "PAS init image failed: %d\n", ret);
+ goto free_metadata;
+ }
+
+ for (i = 0; i < ehdr->e_phnum; i++) {
+ char *seg_name __free(kfree) = kstrdup(rproc->firmware,
+ GFP_KERNEL);
+ if (!seg_name)
+ return -ENOMEM;
+
+ phdr = &phdrs[i];
+
+ /* Only process valid loadable data segments */
+ if (phdr->p_type != PT_LOAD || !phdr->p_memsz)
+ continue;
+
+ if (phdr->p_vaddr + phdr->p_filesz > desc->mem_size) {
+ dev_err(rproc->dev.parent,
+ "Segment data exceeds the reserved memory area!\n");
+ goto free_metadata;
+ }
+
+ /* Check if firmware is split across multiple segment files */
+ if (phdr->p_offset > fw->size ||
+ phdr->p_offset + phdr->p_filesz > fw->size) {
+ sprintf(seg_name + strlen(seg_name) - 3, "b%02d", i);
+ ret = request_firmware(&seg_fw, seg_name,
+ rproc->dev.parent);
+ if (ret) {
+ dev_err(rproc->dev.parent,
+ "Could not find split segment binary: %s\n",
+ seg_name);
+ goto free_metadata;
+ }
+
+ /*
+ * Use the virtual instead of the physical address as
+ * the offset
+ */
+ memcpy_toio(desc->mem_region + phdr->p_vaddr,
+ seg_fw->data, phdr->p_filesz);
+
+ release_firmware(seg_fw);
+ } else {
+ memcpy_toio(desc->mem_region + phdr->p_vaddr,
+ fw->data + phdr->p_offset, phdr->p_filesz);
+ }
+ }
+
+ return 0;
+
+free_metadata:
+ kfree(metadata);
+release_fw:
+ release_firmware(fw);
+ return ret;
+}
+
+static const struct rproc_ops m0_btss_ops = {
+ .start = m0_btss_start,
+ .stop = m0_btss_stop,
+ .load = m0_btss_load,
+ .get_boot_addr = rproc_elf_get_boot_addr,
+};
+
+static int m0_btss_alloc_memory_region(struct m0_btss *desc)
+{
+ struct device *dev = desc->dev;
+ struct resource res;
+ int ret;
+
+ ret = of_reserved_mem_region_to_resource(dev->of_node, 0, &res);
+ if (ret) {
+ dev_err(dev, "unable to acquire memory-region resource\n");
+ return ret;
+ }
+
+ desc->mem_phys = res.start;
+ desc->mem_reloc = res.start;
+ desc->mem_size = resource_size(&res);
+ desc->mem_region = devm_ioremap(dev, desc->mem_phys, desc->mem_size);
+ if (!desc->mem_region) {
+ dev_err(dev, "unable to map memory region: %pR\n", &res);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static int m0_btss_pil_probe(struct platform_device *pdev)
+{
+ // struct reset_control *btss_reset;
+ struct device *dev = &pdev->dev;
+ const char *fw_name = NULL;
+ struct m0_btss *desc;
+ struct clk *lpo_clk;
+ struct rproc *rproc;
+ int ret;
+
+ ret = of_property_read_string(dev->of_node, "firmware-name",
+ &fw_name);
+ if (ret < 0)
+ return ret;
+
+ rproc = devm_rproc_alloc(dev, "m0btss", &m0_btss_ops,
+ fw_name, sizeof(*desc));
+ if (!rproc) {
+ dev_err(dev, "failed to allocate rproc\n");
+ return -ENOMEM;
+ }
+
+ desc = rproc->priv;
+ desc->dev = dev;
+
+ ret = m0_btss_alloc_memory_region(desc);
+ if (ret)
+ return ret;
+
+ lpo_clk = devm_clk_get_enabled(dev, "btss_lpo_clk");
+ if (IS_ERR(lpo_clk))
+ return dev_err_probe(dev, PTR_ERR(lpo_clk),
+ "Failed to get lpo clock\n");
+
+ desc->btss_reset = devm_reset_control_get(dev, "btss_reset");
+ if (IS_ERR_OR_NULL(desc->btss_reset))
+ return dev_err_probe(dev, PTR_ERR(desc->btss_reset),
+ "unable to acquire btss_reset\n");
+
+ ret = reset_control_deassert(desc->btss_reset);
+ if (ret)
+ return dev_err_probe(rproc->dev.parent, ret,
+ "Failed to deassert reset\n");
+
+ rproc->auto_boot = false;
+ ret = devm_rproc_add(dev, rproc);
+ if (ret)
+ return ret;
+
+ platform_set_drvdata(pdev, rproc);
+
+ return 0;
+}
+
+static const struct of_device_id m0_btss_of_match[] = {
+ { .compatible = "qcom,ipq5018-btss-pil" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, m0_btss_of_match);
+
+static struct platform_driver m0_btss_pil_driver = {
+ .probe = m0_btss_pil_probe,
+ .driver = {
+ .name = "qcom-m0-btss-pil",
+ .of_match_table = m0_btss_of_match,
+ },
+};
+
+module_platform_driver(m0_btss_pil_driver);
+
+MODULE_DESCRIPTION("Qualcomm M0 Bluetooth Subsystem Peripheral Image Loader");
+MODULE_LICENSE("GPL");
--
2.53.0
^ permalink raw reply related
* [PATCH 3/6] Bluetooth: btqca: Add IPQ5018 support
From: George Moussalem via B4 Relay @ 2026-06-25 14:10 UTC (permalink / raw)
To: Jens Axboe, Ulf Hansson, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Johannes Berg, Jeff Johnson, Bartosz Golaszewski,
Marcel Holtmann, Luiz Augusto von Dentz, Balakrishna Godavarthi,
Rocky Liao, Saravana Kannan, Andrew Lunn, Heiner Kallweit,
Russell King, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman, Bjorn Andersson, Konrad Dybcio,
Mathieu Poirier, Philipp Zabel
Cc: linux-block, linux-kernel, linux-mmc, devicetree, linux-wireless,
ath10k, linux-arm-msm, linux-bluetooth, netdev, linux-remoteproc,
George Moussalem
In-Reply-To: <20260625-ipq5018-bluetooth-v1-0-d999be0e04f7@outlook.com>
From: George Moussalem <george.moussalem@outlook.com>
Add the IPQ5018 SoC type and support for loading its firmware.
The firmware tested has been taken from GPL sources of various router
boards. Firmware files needed are:
- qca/bt_fw_patch.mbn
- qca/mpnv10.bin
Signed-off-by: George Moussalem <george.moussalem@outlook.com>
---
drivers/bluetooth/btqca.c | 16 ++++++++++++++++
drivers/bluetooth/btqca.h | 3 +++
2 files changed, 19 insertions(+)
diff --git a/drivers/bluetooth/btqca.c b/drivers/bluetooth/btqca.c
index 04ebe290bc78..e136e91976cf 100644
--- a/drivers/bluetooth/btqca.c
+++ b/drivers/bluetooth/btqca.c
@@ -380,6 +380,9 @@ static int qca_tlv_check_data(struct hci_dev *hdev,
break;
case TLV_TYPE_NVM:
+ if (soc_type == QCA_IPQ5018)
+ break;
+
if (fw_size < sizeof(struct tlv_type_hdr))
return -EINVAL;
@@ -794,6 +797,9 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
else
rom_ver = ((soc_ver & 0x00000f00) >> 0x04) | (soc_ver & 0x0000000f);
+ if (soc_type == QCA_IPQ5018)
+ goto download_nvm;
+
if (soc_type == QCA_WCN6750)
qca_send_patch_config_cmd(hdev);
@@ -881,6 +887,7 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
if (soc_type == QCA_QCA2066 || soc_type == QCA_WCN7850)
qca_read_fw_board_id(hdev, &boardid);
+download_nvm:
/* Download NVM configuration */
config.type = TLV_TYPE_NVM;
if (firmware_name) {
@@ -939,6 +946,10 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
qca_get_nvm_name_by_board(config.fwname, sizeof(config.fwname),
"hmtnv", soc_type, ver, rom_ver, boardid);
break;
+ case QCA_IPQ5018:
+ snprintf(config.fwname, sizeof(config.fwname),
+ "qca/mpnv%02x.bin", rom_ver);
+ break;
default:
snprintf(config.fwname, sizeof(config.fwname),
"qca/nvm_%08x.bin", soc_ver);
@@ -958,6 +969,9 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
return err;
}
+ if (soc_type == QCA_IPQ5018)
+ msleep(NVM_READY_DELAY_MS);
+
switch (soc_type) {
case QCA_QCA2066:
case QCA_QCA6390:
@@ -965,6 +979,7 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
case QCA_WCN6750:
case QCA_WCN6855:
case QCA_WCN7850:
+ case QCA_IPQ5018:
err = qca_disable_soc_logging(hdev);
if (err < 0)
return err;
@@ -1001,6 +1016,7 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
case QCA_WCN6750:
case QCA_WCN6855:
case QCA_WCN7850:
+ case QCA_IPQ5018:
/* get fw build info */
err = qca_read_fw_build_info(hdev);
if (err < 0)
diff --git a/drivers/bluetooth/btqca.h b/drivers/bluetooth/btqca.h
index 8f3c1b1c77b3..343cd62d1137 100644
--- a/drivers/bluetooth/btqca.h
+++ b/drivers/bluetooth/btqca.h
@@ -54,6 +54,8 @@
#define QCA_HSP_GF_SOC_ID 0x1200
#define QCA_HSP_GF_SOC_MASK 0x0000ff00
+#define NVM_READY_DELAY_MS 1500
+
enum qca_baudrate {
QCA_BAUDRATE_115200 = 0,
QCA_BAUDRATE_57600,
@@ -158,6 +160,7 @@ enum qca_btsoc_type {
QCA_WCN6750,
QCA_WCN6855,
QCA_WCN7850,
+ QCA_IPQ5018,
};
#if IS_ENABLED(CONFIG_BT_QCA)
--
2.53.0
^ permalink raw reply related
* [PATCH 1/6] dt-bindings: remoteproc: document M0 Bluetooth Subsystem secure PIL
From: George Moussalem via B4 Relay @ 2026-06-25 14:10 UTC (permalink / raw)
To: Jens Axboe, Ulf Hansson, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Johannes Berg, Jeff Johnson, Bartosz Golaszewski,
Marcel Holtmann, Luiz Augusto von Dentz, Balakrishna Godavarthi,
Rocky Liao, Saravana Kannan, Andrew Lunn, Heiner Kallweit,
Russell King, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman, Bjorn Andersson, Konrad Dybcio,
Mathieu Poirier, Philipp Zabel
Cc: linux-block, linux-kernel, linux-mmc, devicetree, linux-wireless,
ath10k, linux-arm-msm, linux-bluetooth, netdev, linux-remoteproc,
George Moussalem
In-Reply-To: <20260625-ipq5018-bluetooth-v1-0-d999be0e04f7@outlook.com>
From: George Moussalem <george.moussalem@outlook.com>
Document the M0 Bluetooth Subsystem remote processor core found in the
Qualcomm IPQ5018 SoC. Firmware loaded is authenticated via TrustZone.
The firmware running on the M0 core provides bluetooth functionality.
Signed-off-by: George Moussalem <george.moussalem@outlook.com>
---
.../bindings/remoteproc/qcom,m0-btss-pil.yaml | 72 ++++++++++++++++++++++
1 file changed, 72 insertions(+)
diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,m0-btss-pil.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,m0-btss-pil.yaml
new file mode 100644
index 000000000000..397bb6815d71
--- /dev/null
+++ b/Documentation/devicetree/bindings/remoteproc/qcom,m0-btss-pil.yaml
@@ -0,0 +1,72 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/remoteproc/qcom,m0-btss-pil.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm M0 BTSS Peripheral Image Loader
+
+maintainers:
+ - George Moussalem <george.moussalem@outlook.com>
+
+description:
+ Qualcomm M0 BTSS Peripheral Secure Image Loader loads firmware and powers up
+ the M0 BTSS remote processor core on the Qualcomm IPQ5018 SoC.
+
+properties:
+ compatible:
+ enum:
+ - qcom,ipq5018-btss-pil
+
+ firmware-name:
+ maxItems: 1
+ description: Firmware name for the M0 Bluetooth Subsystem core
+
+ clocks:
+ items:
+ - description: M0 BTSS low power oscillator clock
+
+ clock-names:
+ items:
+ - const: btss_lpo_clk
+
+ memory-region:
+ items:
+ - description: M0 BTSS reserved memory carveout
+
+ resets:
+ items:
+ - description: M0 BTSS reset
+
+ reset-names:
+ items:
+ - const: btss_reset
+
+required:
+ - compatible
+ - firmware-name
+ - clocks
+ - clock-names
+ - resets
+ - reset-names
+ - memory-region
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/qcom,gcc-ipq5018.h>
+ #include <dt-bindings/reset/qcom,gcc-ipq5018.h>
+
+ remoteproc {
+ compatible = "qcom,ipq5018-btss-pil";
+
+ firmware-name = "qca/bt_fw_patch.mbn";
+
+ clocks = <&gcc GCC_BTSS_LPO_CLK>;
+ clock-names = "btss_lpo_clk";
+ resets = <&gcc GCC_BTSS_BCR>;
+ reset-names = "btss_reset";
+
+ memory-region = <&btss_region>;
+ };
--
2.53.0
^ permalink raw reply related
* [PATCH 0/6] Add support for IPQ5018 Bluetooth
From: George Moussalem via B4 Relay @ 2026-06-25 14:10 UTC (permalink / raw)
To: Jens Axboe, Ulf Hansson, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Johannes Berg, Jeff Johnson, Bartosz Golaszewski,
Marcel Holtmann, Luiz Augusto von Dentz, Balakrishna Godavarthi,
Rocky Liao, Saravana Kannan, Andrew Lunn, Heiner Kallweit,
Russell King, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman, Bjorn Andersson, Konrad Dybcio,
Mathieu Poirier, Philipp Zabel
Cc: linux-block, linux-kernel, linux-mmc, devicetree, linux-wireless,
ath10k, linux-arm-msm, linux-bluetooth, netdev, linux-remoteproc,
George Moussalem
Hello,
This patch series introduces Bluetooth support for IPQ5018.
Bluetooth firmware on the IPQ5018 platform runs on the M0 co-processor.
The firmware is loaded by the host into a dedicated reserved memory
carveout and authenticated by TrustZone. A Secure Channel Manager (SCM)
call safely brings the peripheral core out of reset.
A shared memory ring buffer topology handles runtime data frame
transport between the host APSS and the M0 core. An outgoing APCS IPC
bit and an incoming GIC interrupt handle host/guest signaling.
This series has been tested and verified on various IPQ5018 router
boards utilizing firmware extracted from GPL distributions, using both
mdt and mbn file formats.
[ 14.781511] Bluetooth: hci0: QCA Product ID :0x00000016
[ 14.781583] Bluetooth: hci0: QCA SOC Version :0x20180100
[ 14.785926] Bluetooth: hci0: QCA ROM Version :0x00000100
[ 14.791546] Bluetooth: hci0: QCA Patch Version:0x00003ded
[ 14.796698] Bluetooth: hci0: QCA controller version 0x01000100
[ 14.802217] Bluetooth: hci0: QCA Downloading qca/mpnv10.bin
[ 16.393850] Bluetooth: hci0: QCA Build Info: BTFW.MAPLE.1.0.0-00102-MPL_ROM_PATCHZ-1
Best regards,
George Moussalem
Signed-off-by: George Moussalem <george.moussalem@outlook.com>
---
George Moussalem (6):
dt-bindings: remoteproc: document M0 Bluetooth Subsystem secure PIL
remoteproc: qcom: Add M0 BTSS secure PIL driver
Bluetooth: btqca: Add IPQ5018 support
dt-bindings: net: bluetooth: Document Qualcomm IPQ5018 Bluetooth controller
Bluetooth: Introduce Qualcomm IPQ5018 IPC based HCI driver
arm64: dts: qcom: ipq5018: add nodes required for Bluetooth support
.../bindings/net/bluetooth/qcom,ipq5018-bt.yaml | 63 ++
.../bindings/remoteproc/qcom,m0-btss-pil.yaml | 72 ++
arch/arm64/boot/dts/qcom/ipq5018.dtsi | 34 +-
drivers/bluetooth/Kconfig | 11 +
drivers/bluetooth/Makefile | 1 +
drivers/bluetooth/btqca.c | 16 +
drivers/bluetooth/btqca.h | 3 +
drivers/bluetooth/btqcomipc.c | 939 +++++++++++++++++++++
drivers/remoteproc/Kconfig | 12 +
drivers/remoteproc/Makefile | 1 +
drivers/remoteproc/qcom_m0_btss_pil.c | 261 ++++++
11 files changed, 1412 insertions(+), 1 deletion(-)
---
base-commit: 4d1ab324fcb7d20df5a071edb0304461846fdc12
change-id: 20260625-ipq5018-bluetooth-06ff66c9d753
prerequisite-message-id: <20260612-block-as-nvmem-v5-0-95e0b30fff90@oss.qualcomm.com>
prerequisite-patch-id: 6ce8686c1683f468d86b4502f5ec9d19c392a382
prerequisite-patch-id: e362f7fcbacff716b7ef720e6780786a7d88c013
prerequisite-patch-id: 9168930e40551e842c8171d5433a6f39ad4b78a4
prerequisite-patch-id: 64fecfbd1e085d7d2ab0ae23295ca34ec8e14c5e
prerequisite-patch-id: 566804aaa690ee9aa285d0fd75fd16d94fbadebf
prerequisite-patch-id: dc18bec338f54b3051f4523f9d1d3c0566a20ccd
prerequisite-patch-id: b6b3eb46429936ab49423d295433daf47981db0f
prerequisite-patch-id: 75caa99e3bbcdf41b6462b9f5f703bea1d4a65fa
prerequisite-patch-id: 35e9968f482f78ca233eb0306d9c5fdbff093175
Best regards,
--
George Moussalem <george.moussalem@outlook.com>
^ permalink raw reply
* Re: [PATCH v18 4/8] rust: page: convert to `Ownable`
From: Gary Guo @ 2026-06-25 13:32 UTC (permalink / raw)
To: Andreas Hindborg, Danilo Krummrich, Lorenzo Stoakes,
Vlastimil Babka, Liam R. Howlett, Uladzislau Rezki, Miguel Ojeda,
Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin,
Alice Ryhl, Trevor Gross, Daniel Almeida, Tamir Duberstein,
Alexandre Courbot, Onur Özkan, Lyude Paul,
Greg Kroah-Hartman, Arve Hjønnevåg, Todd Kjos,
Christian Brauner, Carlos Llamas, Rafael J. Wysocki, Dave Ertman,
Ira Weiny, Leon Romanovsky, Paul Moore, Serge Hallyn,
David Airlie, Simona Vetter, Alexander Viro, Jan Kara,
Igor Korotin, Viresh Kumar, Nishanth Menon, Stephen Boyd,
Bjorn Helgaas, Krzysztof Wilczyński, Pavel Tikhomirov,
Michal Wilczynski
Cc: Philipp Stanner, rust-for-linux, linux-kernel, linux-mm,
driver-core, linux-block, linux-security-module, dri-devel,
linux-fsdevel, linux-pm, linux-pci, linux-pwm, Asahi Lina
In-Reply-To: <20260625-unique-ref-v18-4-4e06b5896d47@kernel.org>
On Thu Jun 25, 2026 at 11:15 AM BST, Andreas Hindborg wrote:
> From: Asahi Lina <lina@asahilina.net>
>
> This allows Page references to be returned as borrowed references,
> without necessarily owning the struct page.
>
> Remove `BorrowedPage` and update users to use `Owned<Page>`.
>
> Signed-off-by: Asahi Lina <lina@asahilina.net>
> [ Andreas: Fix formatting and add a safety comment, update users. ]
> Signed-off-by: Andreas Hindborg <a.hindborg@kernel.org>
Nice to see `BorrowedPage` going away.
Reviewed-by: Gary Guo <gary@garyguo.net>
> ---
> drivers/android/binder/page_range.rs | 10 +--
> rust/kernel/alloc/allocator.rs | 19 +++---
> rust/kernel/alloc/allocator/iter.rs | 6 +-
> rust/kernel/page.rs | 122 +++++++++--------------------------
> 4 files changed, 46 insertions(+), 111 deletions(-)
^ permalink raw reply
* Re: [PATCH v18 3/8] rust: implement `ForeignOwnable` for `Owned`
From: Gary Guo @ 2026-06-25 13:29 UTC (permalink / raw)
To: Andreas Hindborg, Danilo Krummrich, Lorenzo Stoakes,
Vlastimil Babka, Liam R. Howlett, Uladzislau Rezki, Miguel Ojeda,
Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin,
Alice Ryhl, Trevor Gross, Daniel Almeida, Tamir Duberstein,
Alexandre Courbot, Onur Özkan, Lyude Paul,
Greg Kroah-Hartman, Arve Hjønnevåg, Todd Kjos,
Christian Brauner, Carlos Llamas, Rafael J. Wysocki, Dave Ertman,
Ira Weiny, Leon Romanovsky, Paul Moore, Serge Hallyn,
David Airlie, Simona Vetter, Alexander Viro, Jan Kara,
Igor Korotin, Viresh Kumar, Nishanth Menon, Stephen Boyd,
Bjorn Helgaas, Krzysztof Wilczyński, Pavel Tikhomirov,
Michal Wilczynski
Cc: Philipp Stanner, rust-for-linux, linux-kernel, linux-mm,
driver-core, linux-block, linux-security-module, dri-devel,
linux-fsdevel, linux-pm, linux-pci, linux-pwm
In-Reply-To: <20260625-unique-ref-v18-3-4e06b5896d47@kernel.org>
On Thu Jun 25, 2026 at 11:15 AM BST, Andreas Hindborg wrote:
> Implement `ForeignOwnable` for `Owned<T>`. This allows use of `Owned<T>` in
> places such as the `XArray`.
>
> Note that `T` does not need to implement `ForeignOwnable` for `Owned<T>` to
> implement `ForeignOwnable`.
>
> Signed-off-by: Andreas Hindborg <a.hindborg@kernel.org>
> ---
> rust/kernel/owned.rs | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 53 insertions(+)
>
> diff --git a/rust/kernel/owned.rs b/rust/kernel/owned.rs
> index 7fe9ec3e55126..9c92d4a83cc1b 100644
> --- a/rust/kernel/owned.rs
> +++ b/rust/kernel/owned.rs
> @@ -15,6 +15,8 @@
> ptr::NonNull, //
> };
>
> +use kernel::types::ForeignOwnable;
> +
> /// Types that specify their own way of performing allocation and destruction. Typically, this trait
> /// is implemented on types from the C side.
> ///
> @@ -186,3 +188,54 @@ fn drop(&mut self) {
> unsafe { T::release(self.ptr) };
> }
> }
> +
> +// SAFETY: We derive the pointer to `T` from a valid `T`, so the returned
> +// pointer satisfy alignment requirements of `T`.
> +unsafe impl<T: Ownable> ForeignOwnable for Owned<T> {
> + const FOREIGN_ALIGN: usize = core::mem::align_of::<T>();
> +
> + type Borrowed<'a>
> + = &'a T
> + where
> + Self: 'a;
> + type BorrowedMut<'a>
> + = Pin<&'a mut T>
> + where
> + Self: 'a;
> +
> + #[inline]
> + fn into_foreign(self) -> *mut kernel::ffi::c_void {
> + let ptr = self.ptr.as_ptr().cast();
> + core::mem::forget(self);
> + ptr
I think the pattern in `into_raw` is better:
ManuallyDrop::new(self).ptr.as_ptr().cast()
Or perhaps this can just use `Self::into_raw(self).as_ptr().cast()`.
> + }
> +
> + #[inline]
> + unsafe fn from_foreign(ptr: *mut kernel::ffi::c_void) -> Self {
> + // INVARIANT: By the function safety contract, `ptr` was returned by `into_foreign`, which
> + // gave up exclusive ownership of a valid, pinned `T`; we retake that ownership here.
> + Self {
> + // SAFETY: By function safety contract, `ptr` came from
> + // `into_foreign` and cannot be null.
> + ptr: unsafe { NonNull::new_unchecked(ptr.cast()) },
> + }
> + }
Same here, could be using `Self::from_raw`.
However, the current code looks correct to me regardless, so:
Reviewed-by: Gary Guo <gary@garyguo.net>
Best,
Gary
> +
> + #[inline]
> + unsafe fn borrow<'a>(ptr: *mut kernel::ffi::c_void) -> Self::Borrowed<'a> {
> + // SAFETY: By function safety requirements, `ptr` is valid for use as a
> + // reference for `'a`.
> + unsafe { &*ptr.cast() }
> + }
> +
> + #[inline]
> + unsafe fn borrow_mut<'a>(ptr: *mut kernel::ffi::c_void) -> Self::BorrowedMut<'a> {
> + // SAFETY: By function safety requirements, `ptr` is valid for use as a
> + // unique reference for `'a`.
> + let inner = unsafe { &mut *ptr.cast() };
> +
> + // SAFETY: We never move out of inner, and we do not hand out mutable
> + // references when `T: !Unpin`.
> + unsafe { Pin::new_unchecked(inner) }
> + }
> +}
^ permalink raw reply
* Re: [PATCH] block: partitions: Use seq_buf_putc() in cmdline_partition()
From: Markus Elfring @ 2026-06-25 12:18 UTC (permalink / raw)
To: Andy Shevchenko, linux-block
Cc: Jens Axboe, Josh Law, Kees Cook, Woradorn Laodhanadhaworn, LKML,
kernel-janitors
In-Reply-To: <ajzkRM_RFKBpp0i5@ashevche-desk.local>
>
>> cmdline_parts_set(parts, disk_size, state);
>> cmdline_parts_verifier(1, state);
>
>> -
>> - seq_buf_puts(&state->pp_buf, "\n");
>> -
>> + seq_buf_putc(&state->pp_buf, '\n');
>
> Why did you remove blank lines?
>
>> return 1;
I imagine that this source code place can become a bit more succinct.
See also:
efi_partition()
https://elixir.bootlin.com/linux/v7.1.1/source/block/partitions/efi.c#L694-L756
Do you insist to preserve two blank lines here?
Regards,
Markus
^ permalink raw reply
* [GIT PULL] block fixes for 7.2-rc1
From: Jens Axboe @ 2026-06-25 12:12 UTC (permalink / raw)
To: Linus Torvalds; +Cc: linux-block@vger.kernel.org
Hi Linus,
A set of changes queued up after the initial merge window PR, and fixes
etc that came in during the merge window. This pull request contains:
- blk-cgroup locking rework and fixes: fix a use-after-free in
__blkcg_rstat_flush(), defer freeing policy data until after an RCU
grace period, defer the blkcg css_put until the blkg is unlinked from
the queue, and a series unwinding the queue_lock nesting under RCU /
blkcg->lock across the lookup, create, associate and destroy paths.
- NVMe fixes via Keith:
- Fix a crash and memory leak during invalid cdev teardown, and
related cdev cleanups (Maurizio, John)
- nvmet fixes: handle TCP_CLOSING in the tcp state_change
handler, reject short AUTH_RECEIVE buffers, handle inline data
with a nonzero offset in rdma, fix an sq refcount leak, and
allocate ana_state with the port
(Maurizio, Michael, Bryam, Wentao, Rosen)
- nvme-fc fix to not cancel requests on an IO target before it is
initialized (Mohamed)
- nvme-apple fix to prevent shared tags across queues on Apple A11
(Nick)
- Various smaller fixes and cleanups (John)
- MD fixes via Yu Kuai:
- raid1/raid10 fixes for writes_pending and barrier reference
leaks on write and discard failures, plus REQ_NOWAIT handling
fixes (Abd-Alrhman)
- raid5 discard accounting and validation, and a batch of fixes
for stripe batch races (Yu Kuai, Chen)
- Protect raid1 head_position during read balancing (Chen)
- block bio-integrity fixes: correct an error injection static key
decrement, fix GFP flag confusion in bio_integrity_alloc_buf(), and
handle REQ_OP_ZONE_APPEND in __bio_integrity_action() (Christoph)
- Fixes for bio_iov_iter_bounce_write(): revert the iov_iter after a
short copy, and respect the iov_iter nofault flag (Qu)
- Invalidate the cached plug timestamp after a task switch, and clear
PF_BLOCK_TS in copy_process() (Usama)
- Fix the IORING_URING_CMD_REISSUE flags check in blkdev_uring_cmd()
(Yitang)
- Remove a redundant plug in __submit_bio() (Wen)
- Don't warn when reclassifying a busy socket lock in nbd (Deepanshu)
Please pull!
The following changes since commit 6b5a2b7d9bc156e505f09e698d85d6a1547c1206:
Merge tag 'trace-tools-v7.2' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace (2026-06-16 17:50:34 +0530)
are available in the Git repository at:
https://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux.git tags/block-7.2-20260625
for you to fetch changes up to a1c8bdbbd72564cebb0d02948c1ed57b80b2e773:
block: handle REQ_OP_ZONE_APPEND in __bio_integrity_action (2026-06-24 06:53:25 -0600)
----------------------------------------------------------------
Abd-Alrhman Masalkhi (6):
md/raid1: fix writes_pending and barrier reference leaks on write failures
md/raid10: fix writes_pending leak on write request failures
md/raid10: fix writes_pending and barrier reference leaks on discard failures
md/raid1: simplify raid1_write_request() error handling
md/raid1: honor REQ_NOWAIT when waiting for behind writes
md/raid1: free r1_bio when REQ_NOWAIT is set and read would block on retry
Bryam Vargas (1):
nvmet-rdma: handle inline data with a nonzero offset
Cen Zhang (1):
block, bfq: protect async queue reset with blkcg locks
Chen Cheng (4):
md/raid1: protect head_position for read balance
md/raid5: let stripe batch bm_seq comparison wrap-safe
md/raid5: use stripe state snapshot in break_stripe_batch_list()
md/raid5: avoid R5_Overlap races while breaking stripe batches
Christoph Hellwig (3):
block: fix incorrect error injection static key decrement
block: fix GFP_ flags confusion in bio_integrity_alloc_buf
block: handle REQ_OP_ZONE_APPEND in __bio_integrity_action
Deepanshu Kartikey (1):
nbd: don't warn when reclassifying a busy socket lock
Jens Axboe (2):
Merge tag 'nvme-7.2-2026-06-23' of git://git.infradead.org/nvme into block-7.2
Merge branch 'md-7.2' of https://git.kernel.org/pub/scm/linux/kernel/git/mdraid/linux into block-7.2
John Garry (3):
nvme: quieten sparse warning in valid LBA size check
nvme: make some sysfs diagnostic structures static
nvme: make nvme_add_ns{_head}_cdev return void
Maurizio Lombardi (2):
nvme: fix crash and memory leak during invalid cdev teardown
nvmet-tcp: handle TCP_CLOSING state in nvmet_tcp_state_change
Michael Bommarito (1):
nvmet-auth: reject short AUTH_RECEIVE buffers
Michal Koutný (1):
blk-cgroup: fix UAF in __blkcg_rstat_flush()
Mohamed Khalfella (1):
nvme-fc: Do not cancel requests in io target before it is initialized
Nick Chan (1):
nvme-apple: Prevent shared tags across queues on Apple A11
Qu Wenruo (2):
block: revert the iov_iter after a short copy in bio_iov_iter_bounce_write()
block: respect iov_iter::nofault flag in bio_iov_iter_bounce_write()
Rosen Penev (1):
nvme: target: allocate ana_state with port
Usama Arif (2):
kernel/fork: clear PF_BLOCK_TS in copy_process()
block: invalidate cached plug timestamp after task switch
Wen Xiong (1):
block: Remove redundant plug in __submit_bio()
Wentao Liang (1):
nvmet: fix refcount leak in nvmet_sq_create()
Yitang Yang (1):
block: fix IORING_URING_CMD_REISSUE flags check in blkdev_uring_cmd
Yu Kuai (11):
md/raid5: account discard IO
md/raid5: validate discard support at request time
md/raid5: always convert llbitmap bits for discard
blk-cgroup: protect iterating blkgs with blkcg->lock in blkcg_print_stat()
blk-cgroup: delay freeing policy data after rcu grace period
blk-cgroup: don't nest queue_lock under rcu in blkcg_print_blkgs()
blk-cgroup: don't nest queue_lock under rcu in blkg_lookup_create()
blk-cgroup: don't nest queue_lock under rcu in bio_associate_blkg()
blk-cgroup: don't nest queue_lock under blkcg->lock in blkcg_destroy_blkgs()
mm/page_io: don't nest queue_lock under rcu in bio_associate_blkg_from_page()
block, bfq: don't grab queue_lock to initialize bfq
Zizhi Wo (1):
blk-cgroup: defer blkcg css_put until blkg is unlinked from queue
block/bfq-cgroup.c | 30 ++++-
block/bfq-iosched.c | 8 +-
block/bio-integrity-auto.c | 2 +-
block/bio-integrity-fs.c | 4 +-
block/bio-integrity.c | 9 +-
block/bio.c | 21 +++-
block/blk-cgroup-rwstat.c | 15 ++-
block/blk-cgroup.c | 196 +++++++++++++++++++--------------
block/blk-cgroup.h | 8 +-
block/blk-core.c | 7 --
block/blk-iocost.c | 22 +++-
block/blk-iolatency.c | 10 +-
block/blk-throttle.c | 13 ++-
block/error-injection.c | 4 +-
block/ioctl.c | 2 +-
drivers/block/nbd.c | 2 +-
drivers/md/md-bitmap.c | 9 +-
drivers/md/md-bitmap.h | 2 +-
drivers/md/md-llbitmap.c | 13 ++-
drivers/md/md.c | 2 +-
drivers/md/raid1.c | 99 ++++++++++-------
drivers/md/raid10.c | 28 +++--
drivers/md/raid5.c | 131 +++++++++++++---------
drivers/md/raid5.h | 1 +
drivers/nvme/host/apple.c | 12 +-
drivers/nvme/host/core.c | 45 +++++---
drivers/nvme/host/fc.c | 7 +-
drivers/nvme/host/multipath.c | 24 ++--
drivers/nvme/host/nvme.h | 5 +-
drivers/nvme/host/sysfs.c | 6 +-
drivers/nvme/target/configfs.c | 9 +-
drivers/nvme/target/core.c | 2 +-
drivers/nvme/target/fabrics-cmd-auth.c | 26 ++++-
drivers/nvme/target/nvmet.h | 2 +-
drivers/nvme/target/rdma.c | 18 +--
drivers/nvme/target/tcp.c | 1 +
include/linux/bio-integrity.h | 2 +-
include/linux/blkdev.h | 16 +--
kernel/fork.c | 1 +
kernel/sched/core.c | 12 +-
mm/page_io.c | 7 +-
41 files changed, 518 insertions(+), 315 deletions(-)
--
Jens Axboe
^ permalink raw reply
* Re: [PATCH v2] scsi: bsg: read io_uring command fields once
From: Jens Axboe @ 2026-06-25 12:06 UTC (permalink / raw)
To: Yang Xiuwei, James E . J . Bottomley, Martin K . Petersen
Cc: Rahul Chandelkar, FUJITA Tomonori, linux-scsi, linux-block,
io-uring, Bart Van Assche, Caleb Sander Mateos
In-Reply-To: <20260626020000.0000000-1-yangxiuwei@kylinos.cn>
On 6/24/26 9:25 PM, Yang Xiuwei wrote:
> Hi James, Martin,
>
> Friendly ping on v2 ? anything else needed before pick-up?
It'll fix the issue, but it also just applies READ_ONCE() everywhere.
Which is fine, but most of them don't really matter. For example, yes
you could race on the timeout if the application is being stupid or
silly, but it doesn't matter one bit. Similarly with a bunch of others.
I'll leave that up to the SCSI folks to decide how they want to do it.
--
Jens Axboe
^ permalink raw reply
* Re: [PATCH v3 5/5] block: validate user space vectors during extraction
From: Christoph Hellwig @ 2026-06-25 11:57 UTC (permalink / raw)
To: Keith Busch
Cc: linux-block, linux-fsdevel, dm-devel, hch, axboe, brauner, djwong,
viro, Keith Busch, stable
In-Reply-To: <20260624170905.3972095-6-kbusch@meta.com>
Looks good:
Reviewed-by: Christoph Hellwig <hch@lst.de>
^ permalink raw reply
* Re: [PATCH v3 4/5] zloop: set dma_alignment from the backing files for direct I/O
From: Christoph Hellwig @ 2026-06-25 11:57 UTC (permalink / raw)
To: Keith Busch
Cc: linux-block, linux-fsdevel, dm-devel, hch, axboe, brauner, djwong,
viro, Keith Busch
In-Reply-To: <20260624170905.3972095-5-kbusch@meta.com>
Looks good:
Reviewed-by: Christoph Hellwig <hch@lst.de>
^ permalink raw reply
* Re: [PATCH v3 3/5] loop: set dma_alignment from the backing file for direct I/O
From: Christoph Hellwig @ 2026-06-25 11:57 UTC (permalink / raw)
To: Keith Busch
Cc: linux-block, linux-fsdevel, dm-devel, hch, axboe, brauner, djwong,
viro, Keith Busch
In-Reply-To: <20260624170905.3972095-4-kbusch@meta.com>
Looks good:
Reviewed-by: Christoph Hellwig <hch@lst.de>
^ permalink raw reply
* Re: [PATCH v3 1/5] block: use blkdev_iov_iter_get_pages status for errors
From: Christoph Hellwig @ 2026-06-25 11:56 UTC (permalink / raw)
To: Keith Busch
Cc: linux-block, linux-fsdevel, dm-devel, hch, axboe, brauner, djwong,
viro, Keith Busch
In-Reply-To: <20260624170905.3972095-2-kbusch@meta.com>
Looks good:
Reviewed-by: Christoph Hellwig <hch@lst.de>
^ permalink raw reply
* Re: [PATCH blktests] block/044: basic block error injection sanity test
From: Christoph Hellwig @ 2026-06-25 11:54 UTC (permalink / raw)
To: Shin'ichiro Kawasaki; +Cc: Christoph Hellwig, linux-block
In-Reply-To: <ajzJiWqsQc2EgR3I@shinmob>
On Thu, Jun 25, 2026 at 03:36:19PM +0900, Shin'ichiro Kawasaki wrote:
> Hi Christoph, thanks for the patch. I ran the test case with block/for-next
> kernel branch tip and confirmed that it is working as expected.
>
> Please find my comments in line. FYI, I atttach the patch which reflects my
> comments. If you are fine with the changes, please let me know so that I can
> fold in the change and apply this patch.
> > +# SPDX-License-Identifier: GPL-2.0
>
> Nit: Majority of the blktests test cases have GPL-3.0+. If you do not mind,
> I suggest GPL-3.0+.
Well a mix of licenses is obviously bad, although I hate the GPL 3 with
passion.
> I suggest to add the line below.
>
> _have_kernel_option BLK_ERROR_INJECTION
>
> This way, we can confirm the kernel has the required changes and
> the dependent feature is enabled.
Sounds good, although this assumes we actually have /proc/config.gz?
Otherwise the changes looks fine.
^ permalink raw reply
* Re: [PATCH] block: avoid potential deadlock on zone revalidation failure
From: Christoph Hellwig @ 2026-06-25 11:52 UTC (permalink / raw)
To: Damien Le Moal; +Cc: Jens Axboe, linux-block, Christoph Hellwig
In-Reply-To: <20260625062824.2013244-1-dlemoal@kernel.org>
On Thu, Jun 25, 2026 at 03:28:24PM +0900, Damien Le Moal wrote:
[very long lockdep trace]
> + /*
> + * We may already have a zone write plug workqueue as this function may
> + * be called after disk_free_zone_resources(), which does not destroy
> + * the workqueue (the zone write plugs workqueue is destroyed at
> + * disk_release() time).
> + */
> + if (!disk->zone_wplugs_wq) {
Can't we just allocate this at add_disk time instead of the magic NULL
check here to mirror the freeing side?
^ permalink raw reply
* Re: [PATCH v3 1/7] list: Add mutable iterator variants
From: Jani Nikula @ 2026-06-25 11:00 UTC (permalink / raw)
To: Kaitao Cheng, David Laight, Christian König,
David Hildenbrand (Arm), Alexei Starovoitov
Cc: Andrew Morton, David Hildenbrand, Jens Axboe, Tejun Heo,
Alexander Viro, Christian Brauner, Daniel Borkmann,
Andrii Nakryiko, Johannes Weiner, Peter Zijlstra, Ingo Molnar,
Arnaldo Carvalho de Melo, Namhyung Kim, Thomas Gleixner,
Juri Lelli, Vincent Guittot, Paul Moore, Andy Shevchenko,
Paul E. McKenney, Shakeel Butt, David Howells, Simona Vetter,
Randy Dunlap, Luca Ceresoli, Philipp Stanner, linux-block,
linux-kernel, cgroups, linux-ntfs-dev, linux-fsdevel, io-uring,
audit, bpf, netdev, dri-devel, linux-perf-users,
linux-trace-kernel, kexec, live-patching, linux-modules,
linux-crypto, linux-pm, rcu, sched-ext, linux-mm, virtualization,
damon, llvm, Kaitao Cheng, Muchun Song
In-Reply-To: <0ed6b5c3-e955-46e2-9fc6-075a0dfd1c4f@linux.dev>
On Thu, 25 Jun 2026, Kaitao Cheng <kaitao.cheng@linux.dev> wrote:
> 在 2026/6/24 22:23, David Laight 写道:
>> On Wed, 24 Jun 2026 15:23:47 +0200
>> Christian König <christian.koenig@amd.com> wrote:
>>> On 6/24/26 15:14, Kaitao Cheng wrote:
>>>> 在 2026/6/22 16:42, David Laight 写道:
>>>>> On Mon, 22 Jun 2026 12:05:31 +0800
>>>>> Kaitao Cheng <kaitao.cheng@linux.dev> wrote:
>>>>>
>>>>>> From: Kaitao Cheng <chengkaitao@kylinos.cn>
>>>>>>
>>>>>> The list_for_each*_safe() helpers are used when the loop body may
>>>>>> remove the current entry. Their API exposes the temporary cursor at
>>>>>> every call site, even though most users only need it for the iterator
>>>>>> implementation and never reference it in the loop body.
>>>>>>
>>>>>> Add *_mutable() variants for list and hlist iteration. The new helpers
>>>>>> support both forms: callers may keep passing an explicit temporary cursor
>>>>>> when they need to inspect or reset it, or omit it and let the helper use
>>>>>> a unique internal cursor.
>>>>>
>>>>> I'm not really sure 'mutable' means anything either.
>>>>> It is possible to make it valid for the loop body (or even other threads)
>>>>> to delete arbitrary list items - but that needs significant extra overheads.
>>>>>
>>>>> It might be worth doing something that doesn't need the extra variable,
>>>>> but there is little point doing all the churn just to rename things.
>>>>>
>>>>>>
>>>>>> This makes call sites that only mutate the list through the current entry
>>>>>> less noisy, while keeping the existing *_safe() helpers available for
>>>>>> compatibility.
>>>>>>
>>>>>> Signed-off-by: Kaitao Cheng <chengkaitao@kylinos.cn>
>>>>>> ---
>>>>>> include/linux/list.h | 269 +++++++++++++++++++++++++++++++++++++------
>>>>>> 1 file changed, 231 insertions(+), 38 deletions(-)
>>>>>>
>>>>>> diff --git a/include/linux/list.h b/include/linux/list.h
>>>>>> index 09d979976b3b..1081def7cea9 100644
>>>>>> --- a/include/linux/list.h
>>>>>> +++ b/include/linux/list.h
>>>>>> @@ -7,6 +7,7 @@
>>>>>> #include <linux/stddef.h>
>>>>>> #include <linux/poison.h>
>>>>>> #include <linux/const.h>
>>>>>> +#include <linux/args.h>
>>>>>>
>>>>>> #include <asm/barrier.h>
>>>>>>
>>>>>> @@ -763,28 +764,72 @@ static inline void list_splice_tail_init(struct list_head *list,
>>>>>> #define list_for_each_prev(pos, head) \
>>>>>> for (pos = (head)->prev; !list_is_head(pos, (head)); pos = pos->prev)
>>>>>>
>>>>>> -/**
>>>>>> - * list_for_each_safe - iterate over a list safe against removal of list entry
>>>>>> - * @pos: the &struct list_head to use as a loop cursor.
>>>>>> - * @n: another &struct list_head to use as temporary storage
>>>>>> - * @head: the head for your list.
>>>>>> +/*
>>>>>> + * list_for_each_safe is an old interface, use list_for_each_mutable instead.
>>>>>> */
>>>>>> #define list_for_each_safe(pos, n, head) \
>>>>>> for (pos = (head)->next, n = pos->next; \
>>>>>> !list_is_head(pos, (head)); \
>>>>>> pos = n, n = pos->next)
>>>>>>
>>>>>> +#define __list_for_each_mutable_internal(pos, tmp, head) \
>>>>>> + for (typeof(pos) tmp = (pos = (head)->next)->next; \
>>>>>
>>>>> Use auto
>>>>>
>>>>>> + !list_is_head(pos, (head)); \
>>>>>> + pos = tmp, tmp = pos->next)
>>>>>> +
>>>>>> +#define __list_for_each_mutable1(pos, head) \
>>>>>> + __list_for_each_mutable_internal(pos, __UNIQUE_ID(next), head)
>>>>>> +
>>>>>> +#define __list_for_each_mutable2(pos, next, head) \
>>>>>> + list_for_each_safe(pos, next, head)
>>>>>> +
>>>>>> /**
>>>>>> - * list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry
>>>>>> + * list_for_each_mutable - iterate over a list safe against entry removal
>>>>>> * @pos: the &struct list_head to use as a loop cursor.
>>>>>> - * @n: another &struct list_head to use as temporary storage
>>>>>> - * @head: the head for your list.
>>>>>> + * @...: either (head) or (next, head)
>>>>>> + *
>>>>>> + * next: another &struct list_head to use as optional temporary storage.
>>>>>> + * The temporary cursor is internal unless explicitly supplied by
>>>>>> + * the caller.
>>>>>> + * head: the head for your list.
>>>>>> + */
>>>>>> +#define list_for_each_mutable(pos, ...) \
>>>>>> + CONCATENATE(__list_for_each_mutable, COUNT_ARGS(__VA_ARGS__)) \
>>>>>> + (pos, __VA_ARGS__)
>>>>>
>>>>> The variable argument count logic really just slows down compilation.
>>>>> Maybe there aren't enough copies of this code to make that significant.
>>>>> But just because you can do it doesn't mean it is a gooD idea.
>>>>> I'm also not sure it really adds anything to the readability.
>>>>>
>>>>> And, it you are going to make the middle argument optional there is
>>>>> no need to change the macro name.
>>>>
>>>> Christian König and Jani Nikula also disagree with the variadic-argument
>>>> implementation approach. If we abandon that method, it means we will
>>>> inevitably need to add some new macros. If mutable is not a good name,
>>>> suggestions for better alternatives would be welcome; coming up with a
>>>> suitable name is indeed rather tricky.
>>>
>>> I don't think you need to add a new macro for the specific use case that people want to modify the next element of the iteration.
>>>
>>> If I remember your numbers correctly that is a really corner case and keeping using the existing *_safe() macros for that sounds perfectly fine to me.
>>
>> IIRC currently you have a choice of either:
>> define Item that can't be deleted
>> list_for_each() The current item.
>> list_for_each_safe() The next item.
>> There is also likely to be code that updates the variables to allow
>> for other scenarios.
>>
>> Note that if increase a reference count and release a lock then list_for_each()
>> is likely safer than list_for_each_safe() :-)
>>
>> list.h has 9 variants of the 'safe' loop.
>> The bloat of another 9 is getting excessive.
>>
>> It has to be said that this is one of my least favourite type of list...
>
> Hi Christian König, David Laight, Jani Nikula, David Hildenbrand,
> Andy Shevchenko, Alexei Starovoitov
>
> For ease of discussion, I need to summarize the currently possible
> approaches and briefly describe their respective pros and cons,
> using the list_for_each_entry* interfaces as examples.
>
> 1. Add list_for_each_entry_mutable, while keeping list_for_each_entry
> and list_for_each_entry_safe unchanged. list_for_each_entry_mutable
> would be used specifically for safe deletion scenarios that do not
> need to expose the temporary cursor externally. The code can refer to
> the v1 version.
>
> Pros: Does not depend on immediate per-subsystem adaptation and can be
> merged directly.
> Cons: Requires adding a whole set of mutable interfaces, which makes the
> code somewhat redundant.
Seems fine, and the original _safe naming is ambiguous anyway.
> 2. Directly optimize away the temporary cursor in list_for_each_entry_safe
> and define it inside the loop instead, changing the interface from four
> arguments to three.
>
> Pros: Does not add redundant interfaces.
> Cons: (1) Users need to manually update special cases that use the
> traversal variable of list_for_each_entry_safe, the new
> list_for_each_entry_safe would no longer apply there and would
> need to be open-coded.
> (2) Because the macro arguments changes, all list_for_each_entry_safe
> callers would need to be modified and merged together, making it
> difficult to merge such a large amount of code at once.
This won't fly because there are literally thousands of
list_for_each_entry_safe() users.
> 3. Use a variadic macro approach to optimize list_for_each_entry_safe,
> so that it supports both three and four arguments.
>
> Pros: (1) Does not add redundant interfaces.
> (2) Does not depend on immediate per-subsystem adaptation and can
> be merged directly.
> Cons: (1) Increases compile time.
> (2) Makes the interface harder for users to use.
Basically I'm against any variadic macro tricks where the optional
argument is not the last argument. That's just way too surprising, and
goes against common practice in just about all other languages.
> 4. Optimize list_for_each_entry by defining the temporary cursor internally,
> making it compatible with the functionality of list_for_each_entry_safe.
> The code can refer to the v2 version.
>
> Pros: (1) Does not add redundant interfaces.
> (2) The number of externally visible arguments of list_for_each_entry
> remains unchanged, still three.
> Cons: (1) list_for_each_entry and list_for_each_entry_safe would be merged
> into one, and list_for_each_entry_safe would gradually be deprecated.
> (2) Users need to manually update special cases that use the traversal
> variable of list_for_each_entry, the new list_for_each_entry would no
> longer apply there and would need to be open-coded. There are 15 such
> cases in total.
This sounds good to me, though I take it there's some code size increase
and/or performance penalty?
Maybe the 15 cases are questionable anyway?
> 5. Use a variadic macro approach to optimize list_for_each_entry, so that
> it supports both three and four arguments.
>
> Pros: (1) Does not add redundant interfaces.
> (2) Does not depend on immediate per-subsystem adaptation and can be
> merged directly.
> Cons: (1) Increases compile time.
> (2) list_for_each_entry and list_for_each_entry_safe would be merged
> into one, and list_for_each_entry_safe would gradually be deprecated.
Please don't do the macro tricks.
> 6. Make no changes, keep the current logic unchanged, and close the current
> email discussion.
I like hiding the temporary stuff when possible.
BR,
Jani.
--
Jani Nikula, Intel
^ permalink raw reply
* Re: [PATCH net v3 1/2] iov_iter: export iov_iter_restore
From: Christian Brauner @ 2026-06-25 10:43 UTC (permalink / raw)
To: Octavian Purdila
Cc: netdev, Alexander Viro, Andrew Morton, Arseniy Krasnov,
David S. Miller, Eric Dumazet, Eugenio Pérez, Jakub Kicinski,
Jason Wang, kvm, linux-block, linux-fsdevel, linux-kernel,
Michael S. Tsirkin, Paolo Abeni, Simon Horman, Stefan Hajnoczi,
Stefano Garzarella, virtualization, Xuan Zhuo, Jens Axboe
In-Reply-To: <20260622222757.2130402-2-tavip@google.com>
> Export iov_iter_restore so that it can be used by modules.
>
> This is needed by the virtio vsock transport (which can be built as a
> module) to restore the msg_iter state when transmission fails.
>
> Acked-by: Stefano Garzarella <sgarzare@redhat.com>
> Signed-off-by: Octavian Purdila <tavip@google.com>
>
> diff --git a/lib/iov_iter.c b/lib/iov_iter.c
> index 273919b16161..f5df63961fb2 100644
> --- a/lib/iov_iter.c
> +++ b/lib/iov_iter.c
> @@ -1491,6 +1491,7 @@ void iov_iter_restore(struct iov_iter *i, struct iov_iter_state *state)
> i->__iov -= state->nr_segs - i->nr_segs;
> i->nr_segs = state->nr_segs;
> }
> +EXPORT_SYMBOL_GPL(iov_iter_restore);
At least only export it for the module that really needs it. For
example, see:
EXPORT_SYMBOL_FOR_MODULES(__kernel_write, "autofs4");
--
Christian Brauner <brauner@kernel.org>
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox