* Re: [BUG] wifi: rtw88: Hard system freeze on RTL8821CE when power_save is enabled (LPS/ASPM conflict)
From: LB F @ 2026-04-26 23:17 UTC (permalink / raw)
To: Bitterblue Smith
Cc: Ping-Ke Shih, linux-wireless@vger.kernel.org,
linux-kernel@vger.kernel.org
In-Reply-To: <faa215f1-ac2c-4072-9603-4baca1d5e07b@gmail.com>
Hi Bitterblue,
I am writing to report preliminary testing results for your RTL8821CE
RX descriptor validation patch (addressing Bugzilla 221286). I have
successfully applied the patch to the out-of-tree rtw88 driver.
System Environment:
OS: openSUSE Tumbleweed-Slowroll
Kernel: 6.19.12-1-default (x86_64)
Hardware: HP Notebook 15-ay027ur (SKU: P3S95EA#ACB, Board: 81F0)
Wi-Fi Module: Realtek RTL8821CE (PCIe)
Firmware loaded: Firmware version 24.11.0, H2C version 12
Driver: Out-of-tree rtw88 (manually patched rx.c, pci.c, pci_old.c,
sdio.c, usb.c)
Note on Patch Baseline: This testing was conducted with the new RX
descriptor validation patch applied on top of the previous patches
we've discussed:
Quirks to disable PCI ASPM and deep LPS for this HP model.
NULL check for chip->edcca_th.
The diagnostic hex dump patch for unused phy status pages.
Testing Methodology: To intentionally trigger the hardware bug, I
performed the following stress tests:
Sustained high-throughput RX load (continuously downloading a 145MB
file to /dev/null at maximum bandwidth).
Toggling PCIe ASPM and interface power saving (iw dev wlp19s0 set
power_save on) under active network load.
Rapid software de-authentication and re-association via NetworkManager.
ACPI Power state transitions: Suspend to RAM (S3) and Suspend to Disk
(S4/Hibernation) while actively connected.
Results: Previously, resuming from S3/S4 or shifting ASPM states under
load would consistently trigger a hard system freeze or kernel panic
within minutes. With your patch applied, the system remained
completely stable across all test phases. The driver handled all power
state transitions and sustained network loads without any issues.
Log Analysis: A detailed review of dmesg and journalctl shows no
mac80211 warnings, no rtw_8821ce initialization errors, and no memory
corruption traces. Notably, the pr_err_once trap for the corrupted
descriptor (drv_info_sz != PHY_STATUS_SIZE or length mismatches) was
not triggered during these artificial tests. This suggests the
hardware did not emit a corrupted frame during this specific session.
However, the system's ability to survive heavy S3/S4 transitions
without crashing is a massive improvement.
Next Steps: Given the intermittent nature of the bug, I will use the
machine for standard daily workloads over the next several days
(longitudinal testing). If the pr_err_once trap is triggered or if any
instability occurs, I will immediately provide the logs. If the system
remains perfectly stable for a week, I will report back to confirm the
fix is solid.
Thank you for your time and for providing this patch.
Best regards, Oleksandr Havrylov
^ permalink raw reply
* Re: [BUG] wifi: rtw88: Hard system freeze on RTL8821CE when power_save is enabled (LPS/ASPM conflict)
From: LB F @ 2026-04-27 0:26 UTC (permalink / raw)
To: Bitterblue Smith
Cc: Ping-Ke Shih, linux-wireless@vger.kernel.org,
linux-kernel@vger.kernel.org
In-Reply-To: <CALdGYqQ+Syz+6weTChA=aXe=DBZSi1c0-7OYhJgkj7ahpR4EUA@mail.gmail.com>
Hi Bitterblue and Panagiotis,
A quick follow-up to my preliminary report from earlier today.
After ensuring the new module containing the `drv_info_sz` validation
patch was properly loaded via DKMS, I ran a much more aggressive
stress test suite. During a test where I rapidly toggled power saving
(`iw dev wlp19s0 set power_save on/off`) while concurrently
downloading a 10GB file, the hardware bug finally triggered.
The resulting logs revealed a fascinating edge case about the
corruption pattern:
1. The hardware emitted a corrupted RX DMA burst.
2. Interestingly, the `pr_err_once("drv_info_sz %d\n", ...)` trap from
your new patch did NOT trigger. This indicates that the corrupted
descriptor happened to have a `drv_info_sz` that exactly matched 24
(`PHY_STATUS_SIZE`) (or 0) purely by coincidence, bypassing the
validation check.
3. Because the descriptor bypassed the length check, the driver
considered it valid and handed it over to the mac80211 stack via NAPI.
The mac80211 stack immediately choked on the corrupted frame structure
and threw a WARNING.
4. About 1.3 seconds later, the subsequent garbage in the hardware
burst reached the PHY status processing logic, where Panagiotis's
patch stepped in.
Here is the exact kernel trace proving this sequence:
[ 1080.394531] WARNING: net/mac80211/rx.c:896 at
ieee80211_rx_list+0x8bd/0xf10 [mac80211], CPU#3: irq/51-rtw_pci/519
[ 1080.394802] CPU: 3 UID: 0 PID: 519 Comm: irq/51-rtw_pci Tainted: G
IOE 6.19.12-1-default #1
[ 1080.394814] RIP: 0010:ieee80211_rx_list+0x8bd/0xf10 [mac80211]
[ 1080.394921] Call Trace:
[ 1080.394924] <IRQ>
[ 1080.394941] ieee80211_rx_napi+0x55/0xe0 [mac80211]
[ 1080.395025] rtw_pci_rx_napi+0x269/0x360 [rtw_pci]
[ 1080.395038] rtw_pci_napi_poll+0x5b/0x110 [rtw_pci]
[ 1080.395044] __napi_poll+0x30/0x1e0
[ 1080.395050] net_rx_action+0x2ec/0x380
[ 1080.395063] handle_softirqs+0xcd/0x270
[ 1080.395068] do_softirq.part.0+0x3b/0x60
[ 1080.395073] </IRQ>
...
[ 1081.708220] rtw_8821ce 0000:13:00.0: unused phy status page (10)
Crucially, because Panagiotis's patch (`if (!edcca_th) return;`) was
active, the system cleanly dropped the PHY status garbage at [
1081.708220 ] instead of hitting the NULL pointer dereference.
The system survived perfectly. No Kernel Panic occurred, and the
driver recovered instantly and continued the 10GB download without
dropping the connection.
Conclusion:
This proves that checking `drv_info_sz` is an excellent primary
defense, but it is not 100% bulletproof because random hardware
garbage can coincidentally have a "valid" length. Panagiotis's NULL
check patch remains an absolutely vital secondary layer of defense
that safely neutralizes the garbage that inevitably slips past the
length validation.
Together, these two patches create a remarkably robust shield against
this hardware defect. The system is incredibly stable now.
Thank you both for your brilliant work on this!
Best regards,
Oleksandr Havrylov
^ permalink raw reply
* RE: [PATCH rtw-next] wifi: rtlwifi: rtl8821ae: Fix C2H bit location in RX descriptor
From: Ping-Ke Shih @ 2026-04-27 2:16 UTC (permalink / raw)
To: Bitterblue Smith, linux-wireless@vger.kernel.org
In-Reply-To: <04da7398-cedb-425a-a810-5772ab10139d@gmail.com>
Bitterblue Smith <rtl8821cerfe2@gmail.com> wrote:
> Bit 28 of double word 2 in the RX descriptor indicates if the packet is
> a normal 802.11 frame, or a message from the wifi firmware to the
> driver (Card 2 Host).
>
> Commit f5678bfe1cdc ("rtlwifi: rtl8821ae: Replace local bit manipulation
> macros") mistakenly made the driver look for this bit in double word 1,
> causing packet loss and Bluetooth coexistence problems.
The mistake in the commit is
#define GET_RX_STATUS_DESC_RPT_SEL(__pdesc) \
- LE_BITS_TO_4BYTE(__pdesc+8, 28, 1)
+ le32_get_bits(*((__le32 *)(__pdesc + 4)), BIT(28))
>
> Fixes: f5678bfe1cdc ("rtlwifi: rtl8821ae: Replace local bit manipulation macros")
> Cc: <stable@vger.kernel.org>
> Signed-off-by: Bitterblue Smith <rtl8821cerfe2@gmail.com>
Acked-by: Ping-Ke Shih <pkshih@realtek.com>
^ permalink raw reply
* RE: [PATCH rtw-next] wifi: rtl8xxxu: Detect the maximum supported channel width
From: Ping-Ke Shih @ 2026-04-27 2:50 UTC (permalink / raw)
To: Bitterblue Smith, linux-wireless@vger.kernel.org
Cc: Jes Sorensen, art1310@proton.me
In-Reply-To: <092f18cd-f3a6-4e3b-b0de-1cb23615e86b@gmail.com>
Bitterblue Smith <rtl8821cerfe2@gmail.com> wrote:
> Some devices malfunction when connected to a network with 40 MHz channel
> width, because they don't support that.
>
> RTL8188FU, RTL8192FU, and RTL8710BU (RTL8188GU) have a way to signal
> this (and some other capabilities) to the driver. Get this information
> from the hardware and advertise 40 MHz support only when the hardware
> can handle it. We assume the other chips can always handle it.
>
> RTL8710BU needs a different way to retrieve this information, which will
> be implemented some other time.
>
> Fixes: dbf9b7bb0edf ("wifi: rtl8xxxu: Enable 40 MHz width by default")
> Cc: stable@vger.kernel.org
> Closes: https://bugzilla.kernel.org/show_bug.cgi?id=221394
> Signed-off-by: Bitterblue Smith <rtl8821cerfe2@gmail.com>
Reviewed-by: Ping-Ke Shih <pkshih@realtek.com>
^ permalink raw reply
* [PATCH 0/3] wifi: mt76: remove mediatek,mtd-eeprom
From: Rosen Penev @ 2026-04-27 3:44 UTC (permalink / raw)
To: devicetree
Cc: Felix Fietkau, Lorenzo Bianconi, Ryder Lee, Shayne Chen,
Sean Wang, Johannes Berg, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno,
Thomas Bogendoerfer, open list:MEDIATEK MT76 WIRELESS LAN DRIVER,
open list:ARM/Mediatek SoC support,
moderated list:ARM/Mediatek SoC support,
moderated list:ARM/Mediatek SoC support, open list:MIPS
mediatek,mtd-eeprom predates nvmem which is used everywhere to grab
eeprom and mac-address data from MTD devices.
Transition the one place to nvmem and remove the binding to discourage
use.
Rosen Penev (3):
MIPS: dts: ralink: gardena_smart_gateway_mt7688: use nvmem for EEPROM
dt-bindings: net: wireless: mt76: remove mediatek,mtd-eeprom
wifi: mt76: remove mt76_get_of_data_from_mtd
.../bindings/net/wireless/mediatek,mt76.yaml | 19 +---
.../ralink/gardena_smart_gateway_mt7688.dts | 17 +++-
drivers/net/wireless/mediatek/mt76/eeprom.c | 87 -------------------
drivers/net/wireless/mediatek/mt76/mt76.h | 1 -
.../wireless/mediatek/mt76/mt7915/eeprom.c | 4 -
5 files changed, 17 insertions(+), 111 deletions(-)
--
2.54.0
^ permalink raw reply
* [PATCH 1/3] MIPS: dts: ralink: gardena_smart_gateway_mt7688: use nvmem for EEPROM
From: Rosen Penev @ 2026-04-27 3:44 UTC (permalink / raw)
To: devicetree
Cc: Felix Fietkau, Lorenzo Bianconi, Ryder Lee, Shayne Chen,
Sean Wang, Johannes Berg, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno,
Thomas Bogendoerfer, open list:MEDIATEK MT76 WIRELESS LAN DRIVER,
open list:ARM/Mediatek SoC support,
moderated list:ARM/Mediatek SoC support,
moderated list:ARM/Mediatek SoC support, open list:MIPS
In-Reply-To: <20260427034427.881389-1-rosenp@gmail.com>
mediatek,mtd-eeprom is a deprecated binding for extracting data on MTD
devices which has been replaced by NVMEM.
The latter is already in wide use with mt76. As this is the only user,
transition to NVMEM.
Signed-off-by: Rosen Penev <rosenp@gmail.com>
---
.../dts/ralink/gardena_smart_gateway_mt7688.dts | 17 +++++++++++++++--
1 file changed, 15 insertions(+), 2 deletions(-)
diff --git a/arch/mips/boot/dts/ralink/gardena_smart_gateway_mt7688.dts b/arch/mips/boot/dts/ralink/gardena_smart_gateway_mt7688.dts
index 0bfb1dde9764..a8a8efbaf527 100644
--- a/arch/mips/boot/dts/ralink/gardena_smart_gateway_mt7688.dts
+++ b/arch/mips/boot/dts/ralink/gardena_smart_gateway_mt7688.dts
@@ -155,10 +155,20 @@ partition@b0000 {
reg = <0xb0000 0x10000>;
};
- factory: partition@c0000 {
+ partition@c0000 {
label = "factory";
reg = <0xc0000 0x10000>;
read-only;
+
+ nvmem-layout {
+ compatible = "fixed-layout";
+ #address-cells = <1>;
+ #nvmem-cell-cells = <1>;
+
+ eeprom_factory_0: eeprom@0 {
+ reg = <0x0 0x400>;
+ };
+ };
};
};
};
@@ -201,5 +211,8 @@ &watchdog {
&wmac {
status = "okay";
- mediatek,mtd-eeprom = <&factory 0x0000>;
+
+ nvmem-cells = <&eeprom_factory_0>;
+ nvmem-cell-names = "eeprom"
+
};
--
2.54.0
^ permalink raw reply related
* [PATCH 2/3] dt-bindings: net: wireless: mt76: remove mediatek,mtd-eeprom
From: Rosen Penev @ 2026-04-27 3:44 UTC (permalink / raw)
To: devicetree
Cc: Felix Fietkau, Lorenzo Bianconi, Ryder Lee, Shayne Chen,
Sean Wang, Johannes Berg, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno,
Thomas Bogendoerfer, open list:MEDIATEK MT76 WIRELESS LAN DRIVER,
open list:ARM/Mediatek SoC support,
moderated list:ARM/Mediatek SoC support,
moderated list:ARM/Mediatek SoC support, open list:MIPS
In-Reply-To: <20260427034427.881389-1-rosenp@gmail.com>
mediatek,mtd-eeprom is a widely unused binding that predates and has
been replaced by NVMEM. As there are no users, remove it.
Signed-off-by: Rosen Penev <rosenp@gmail.com>
---
.../bindings/net/wireless/mediatek,mt76.yaml | 19 ++-----------------
1 file changed, 2 insertions(+), 17 deletions(-)
diff --git a/Documentation/devicetree/bindings/net/wireless/mediatek,mt76.yaml b/Documentation/devicetree/bindings/net/wireless/mediatek,mt76.yaml
index ae6b97cdc44b..482c22cd6627 100644
--- a/Documentation/devicetree/bindings/net/wireless/mediatek,mt76.yaml
+++ b/Documentation/devicetree/bindings/net/wireless/mediatek,mt76.yaml
@@ -87,21 +87,6 @@ properties:
description:
EEPROM data embedded as array.
- mediatek,mtd-eeprom:
- $ref: /schemas/types.yaml#/definitions/phandle-array
- items:
- - items:
- - description: phandle to MTD partition
- - description: offset containing EEPROM data
- description:
- Phandle to a MTD partition + offset containing EEPROM data
- deprecated: true
-
- big-endian:
- $ref: /schemas/types.yaml#/definitions/flag
- description:
- Specify if the radio eeprom partition is written in big-endian
-
mediatek,eeprom-merge-otp:
type: boolean
description:
@@ -314,8 +299,8 @@ examples:
compatible = "mediatek,mt76";
reg = <0x0000 0 0 0 0>;
ieee80211-freq-limit = <5000000 6000000>;
- mediatek,mtd-eeprom = <&factory 0x8000>;
- big-endian;
+ nvmem-cells = <&eeprom>;
+ nvmem-cell-names = "eeprom";
led {
led-sources = <2>;
--
2.54.0
^ permalink raw reply related
* [PATCH 3/3] wifi: mt76: remove mt76_get_of_data_from_mtd
From: Rosen Penev @ 2026-04-27 3:44 UTC (permalink / raw)
To: devicetree
Cc: Felix Fietkau, Lorenzo Bianconi, Ryder Lee, Shayne Chen,
Sean Wang, Johannes Berg, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno,
Thomas Bogendoerfer, open list:MEDIATEK MT76 WIRELESS LAN DRIVER,
open list:ARM/Mediatek SoC support,
moderated list:ARM/Mediatek SoC support,
moderated list:ARM/Mediatek SoC support, open list:MIPS
In-Reply-To: <20260427034427.881389-1-rosenp@gmail.com>
mt76_get_of_data_from_mtd has been replaced by
mt76_get_of_data_from_nvmem in all usages.
Remove it to prevent people from using the deprecated
mediatek,mtd-eeprom binding.
Signed-off-by: Rosen Penev <rosenp@gmail.com>
---
drivers/net/wireless/mediatek/mt76/eeprom.c | 87 -------------------
drivers/net/wireless/mediatek/mt76/mt76.h | 1 -
.../wireless/mediatek/mt76/mt7915/eeprom.c | 4 -
3 files changed, 92 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/eeprom.c b/drivers/net/wireless/mediatek/mt76/eeprom.c
index afdb73661866..092804323d81 100644
--- a/drivers/net/wireless/mediatek/mt76/eeprom.c
+++ b/drivers/net/wireless/mediatek/mt76/eeprom.c
@@ -35,89 +35,6 @@ static int mt76_get_of_eeprom_data(struct mt76_dev *dev, void *eep, int len)
return 0;
}
-int mt76_get_of_data_from_mtd(struct mt76_dev *dev, void *eep, int offset, int len)
-{
-#ifdef CONFIG_MTD
- struct device_node *np = dev->dev->of_node;
- struct mtd_info *mtd;
- const __be32 *list;
- const char *part;
- phandle phandle;
- size_t retlen;
- int size;
- int ret;
-
- list = of_get_property(np, "mediatek,mtd-eeprom", &size);
- if (!list)
- return -ENOENT;
-
- phandle = be32_to_cpup(list++);
- if (!phandle)
- return -ENOENT;
-
- np = of_find_node_by_phandle(phandle);
- if (!np)
- return -EINVAL;
-
- part = of_get_property(np, "label", NULL);
- if (!part)
- part = np->name;
-
- mtd = get_mtd_device_nm(part);
- if (IS_ERR(mtd)) {
- ret = PTR_ERR(mtd);
- goto out_put_node;
- }
-
- if (size <= sizeof(*list)) {
- ret = -EINVAL;
- goto out_put_node;
- }
-
- offset += be32_to_cpup(list);
- ret = mtd_read(mtd, offset, len, &retlen, eep);
- put_mtd_device(mtd);
- if (mtd_is_bitflip(ret))
- ret = 0;
- if (ret) {
- dev_err(dev->dev, "reading EEPROM from mtd %s failed: %i\n",
- part, ret);
- goto out_put_node;
- }
-
- if (retlen < len) {
- ret = -EINVAL;
- goto out_put_node;
- }
-
- if (of_property_read_bool(dev->dev->of_node, "big-endian")) {
- u8 *data = (u8 *)eep;
- int i;
-
- /* convert eeprom data in Little Endian */
- for (i = 0; i < round_down(len, 2); i += 2)
- put_unaligned_le16(get_unaligned_be16(&data[i]),
- &data[i]);
- }
-
-#ifdef CONFIG_NL80211_TESTMODE
- dev->test_mtd.name = devm_kstrdup(dev->dev, part, GFP_KERNEL);
- if (!dev->test_mtd.name) {
- ret = -ENOMEM;
- goto out_put_node;
- }
- dev->test_mtd.offset = offset;
-#endif
-
-out_put_node:
- of_node_put(np);
- return ret;
-#else
- return -ENOENT;
-#endif
-}
-EXPORT_SYMBOL_GPL(mt76_get_of_data_from_mtd);
-
int mt76_get_of_data_from_nvmem(struct mt76_dev *dev, void *eep,
const char *cell_name, int len)
{
@@ -163,10 +80,6 @@ static int mt76_get_of_eeprom(struct mt76_dev *dev, void *eep, int len)
if (!ret)
return 0;
- ret = mt76_get_of_data_from_mtd(dev, eep, 0, len);
- if (!ret)
- return 0;
-
return mt76_get_of_data_from_nvmem(dev, eep, "eeprom", len);
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h
index 527bef97e122..f447ecac664d 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76.h
@@ -1339,7 +1339,6 @@ void mt76_seq_puts_array(struct seq_file *file, const char *str,
int mt76_eeprom_init(struct mt76_dev *dev, int len);
int mt76_eeprom_override(struct mt76_phy *phy);
-int mt76_get_of_data_from_mtd(struct mt76_dev *dev, void *eep, int offset, int len);
int mt76_get_of_data_from_nvmem(struct mt76_dev *dev, void *eep,
const char *cell_name, int len);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c
index eb92cbf1a284..c24e1276700b 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c
@@ -29,10 +29,6 @@ static int mt7915_eeprom_load_precal(struct mt7915_dev *dev)
offs = is_mt7915(&dev->mt76) ? MT_EE_PRECAL : MT_EE_PRECAL_V2;
- ret = mt76_get_of_data_from_mtd(mdev, dev->cal, offs, size);
- if (!ret)
- return ret;
-
ret = mt76_get_of_data_from_nvmem(mdev, dev->cal, "precal", size);
if (!ret)
return ret;
--
2.54.0
^ permalink raw reply related
* [PATCH] wifi: wfx: handle EPROBE_DEFER with of_get_mac_address
From: Rosen Penev @ 2026-04-27 5:16 UTC (permalink / raw)
To: linux-wireless; +Cc: Jérôme Pouiller, open list
In case nvmem gets used and is not ready in time for probe of wfx,
EPROBE_DEFER gets called. Return it so that a proper MAC address can be
specified in such a case.
Signed-off-by: Rosen Penev <rosenp@gmail.com>
---
drivers/net/wireless/silabs/wfx/main.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/net/wireless/silabs/wfx/main.c b/drivers/net/wireless/silabs/wfx/main.c
index dda36e41eed1..dc40a9bd986d 100644
--- a/drivers/net/wireless/silabs/wfx/main.c
+++ b/drivers/net/wireless/silabs/wfx/main.c
@@ -445,6 +445,8 @@ int wfx_probe(struct wfx_dev *wdev)
for (i = 0; i < ARRAY_SIZE(wdev->addresses); i++) {
eth_zero_addr(wdev->addresses[i].addr);
err = of_get_mac_address(wdev->dev->of_node, wdev->addresses[i].addr);
+ if (err == -EPROBE_DEFER)
+ goto irq_unsubscribe;
if (!err)
wdev->addresses[i].addr[ETH_ALEN - 1] += i;
else
--
2.54.0
^ permalink raw reply related
* [PATCH wireless-next] wifi: rt2x00: check for of_get_mac_address error
From: Rosen Penev @ 2026-04-27 5:16 UTC (permalink / raw)
To: linux-wireless; +Cc: Stanislaw Gruszka, open list
is_valid_ether_addr is already a check of of_get_mac_address, in which
case it returns an error if false. Just set a random MAC on all errors
except for EPROBE_DEFER.
Signed-off-by: Rosen Penev <rosenp@gmail.com>
---
drivers/net/wireless/ralink/rt2x00/rt2x00dev.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
index 2d778ea5f1b5..51b836343f07 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
@@ -991,7 +991,7 @@ int rt2x00lib_set_mac_address(struct rt2x00_dev *rt2x00dev, u8 *eeprom_mac_addr)
if (ret == -EPROBE_DEFER)
return ret;
- if (!is_valid_ether_addr(eeprom_mac_addr)) {
+ if (ret) {
eth_random_addr(eeprom_mac_addr);
rt2x00_eeprom_dbg(rt2x00dev, "MAC: %pM\n", eeprom_mac_addr);
}
--
2.54.0
^ permalink raw reply related
* [PATCH wireless-next] wifi: mt76: fix of_get_mac_address error handling
From: Rosen Penev @ 2026-04-27 5:17 UTC (permalink / raw)
To: linux-wireless
Cc: Felix Fietkau, Lorenzo Bianconi, Ryder Lee, Shayne Chen,
Sean Wang, Matthias Brugger, AngeloGioacchino Del Regno,
open list:ARM/Mediatek SoC support,
moderated list:ARM/Mediatek SoC support,
moderated list:ARM/Mediatek SoC support
Check return value instead of is_valid_ether_addr. The latter is handled
by the former.
Signed-off-by: Rosen Penev <rosenp@gmail.com>
---
drivers/net/wireless/mediatek/mt76/eeprom.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/wireless/mediatek/mt76/eeprom.c b/drivers/net/wireless/mediatek/mt76/eeprom.c
index 93d91264687f..0f6ccf6ed53d 100644
--- a/drivers/net/wireless/mediatek/mt76/eeprom.c
+++ b/drivers/net/wireless/mediatek/mt76/eeprom.c
@@ -93,7 +93,7 @@ mt76_eeprom_override(struct mt76_phy *phy)
if (err == -EPROBE_DEFER)
return err;
- if (!is_valid_ether_addr(phy->macaddr)) {
+ if (err) {
eth_random_addr(phy->macaddr);
dev_info(dev->dev,
"Invalid MAC address, using random address %pM\n",
--
2.54.0
^ permalink raw reply related
* [PATCH ath-current] wifi: ath12k: fix peer_id usage in normal RX path
From: Baochen Qiang @ 2026-04-27 5:51 UTC (permalink / raw)
To: Jeff Johnson; +Cc: linux-wireless, ath12k, linux-kernel, Baochen Qiang
ath12k_dp_rx_deliver_msdu() currently uses hal_rx_desc_data::peer_id
parsed from mpdu_start descriptor to do peer lookup. However In an A-MSDU
aggregation scenario, hardware only populates mpdu_start descriptor for
the first sub-msdu, but not the following ones. In that case peer_id could
be invalid, leading to peer lookup failure:
ath12k_wifi7_pci 0000:06:00.0: rx skb 00000000c391c041 len 1532 peer (null) 0 ucast sn 0 eht320 rate_idx 12 vht_nss 2 freq 6105 band 3 flag 0x40d1a fcs-err 0 mic-err 0 amsdu-more 0
As a result pubsta is NULL and parts of ieee80211_rx_status structure are
left uninitialized, which may cause unexpected behavior.
Fix it by switching the normal RX path to use ath12k_skb_rxcb::peer_id
which is parsed from REO ring's rx_mpdu_desc and is always valid.
hal_rx_desc_data::peer_id is still used in
ath12k_wifi7_dp_rx_frag_h_mpdu(), which is safe since A-MSDU
aggregation does not occur for fragmented frames. Similarly,
ath12k_skb_rxcb::peer_id may be overwritten by hal_rx_desc_data::peer_id
in ath12k_wifi7_dp_rx_h_mpdu(), which only handles non-aggregated
multicast/broadcast traffic.
Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.1.c5-00302-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.115823.3
Fixes: 11157e0910fd ("wifi: ath12k: Use ath12k_dp_peer in per packet Tx & Rx paths")
Signed-off-by: Baochen Qiang <baochen.qiang@oss.qualcomm.com>
---
drivers/net/wireless/ath/ath12k/dp_rx.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c
index 25557dea5826..b108ccd0f637 100644
--- a/drivers/net/wireless/ath/ath12k/dp_rx.c
+++ b/drivers/net/wireless/ath/ath12k/dp_rx.c
@@ -1340,7 +1340,7 @@ void ath12k_dp_rx_deliver_msdu(struct ath12k_pdev_dp *dp_pdev, struct napi_struc
bool is_mcbc = rxcb->is_mcbc;
bool is_eapol = rxcb->is_eapol;
- peer = ath12k_dp_peer_find_by_peerid(dp_pdev, rx_info->peer_id);
+ peer = ath12k_dp_peer_find_by_peerid(dp_pdev, rxcb->peer_id);
pubsta = peer ? peer->sta : NULL;
---
base-commit: 7aa24d964a04648b547197c22364e2b76aec096e
change-id: 20260416-ath12k-fix-peer-id-source-140c23f17d8a
Best regards,
--
Baochen Qiang <baochen.qiang@oss.qualcomm.com>
^ permalink raw reply related
* Re: [PATCH wireless-next] wifi: mt76: fix of_get_mac_address error handling
From: Lorenzo Bianconi @ 2026-04-27 7:00 UTC (permalink / raw)
To: Rosen Penev
Cc: linux-wireless, Felix Fietkau, Ryder Lee, Shayne Chen, Sean Wang,
Matthias Brugger, AngeloGioacchino Del Regno,
open list:ARM/Mediatek SoC support,
moderated list:ARM/Mediatek SoC support,
moderated list:ARM/Mediatek SoC support
In-Reply-To: <20260427051746.954704-1-rosenp@gmail.com>
[-- Attachment #1: Type: text/plain, Size: 894 bytes --]
> Check return value instead of is_valid_ether_addr. The latter is handled
> by the former.
>
> Signed-off-by: Rosen Penev <rosenp@gmail.com>
Acked-by: Lorenzo Bianconi <lorenzo@kernel.org>
> ---
> drivers/net/wireless/mediatek/mt76/eeprom.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/net/wireless/mediatek/mt76/eeprom.c b/drivers/net/wireless/mediatek/mt76/eeprom.c
> index 93d91264687f..0f6ccf6ed53d 100644
> --- a/drivers/net/wireless/mediatek/mt76/eeprom.c
> +++ b/drivers/net/wireless/mediatek/mt76/eeprom.c
> @@ -93,7 +93,7 @@ mt76_eeprom_override(struct mt76_phy *phy)
> if (err == -EPROBE_DEFER)
> return err;
>
> - if (!is_valid_ether_addr(phy->macaddr)) {
> + if (err) {
> eth_random_addr(phy->macaddr);
> dev_info(dev->dev,
> "Invalid MAC address, using random address %pM\n",
> --
> 2.54.0
>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply
* [PATCH] wifi: ath: Unify user-visible "Qualcomm" name
From: Krzysztof Kozlowski @ 2026-04-27 7:00 UTC (permalink / raw)
To: Jeff Johnson, linux-wireless, ath11k, linux-kernel, ath12k
Cc: =Bjorn Andersson, Konrad Dybcio, linux-arm-msm,
Krzysztof Kozlowski
Various names for Qualcomm as a company are used in user-visible config
options: QCOM, Qualcomm and Qualcomm Technologies. Switch to unified
"Qualcomm" so it will be easier for users to identify the options when
for example running menuconfig.
Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
---
And "Qualcomm Technologies" has even variations over the tree:
Qualcomm Technologies
Qualcomm Technologies Inc.
Qualcomm Technologies, Inc.
I am doing this tree wide:
https://lore.kernel.org/all/?q=f%3Akrzysztof+s%3A%22Unify+user-visible%22+s%3AQualcomm
---
drivers/net/wireless/ath/ath11k/Kconfig | 2 +-
drivers/net/wireless/ath/ath12k/Kconfig | 6 +++---
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/net/wireless/ath/ath11k/Kconfig b/drivers/net/wireless/ath/ath11k/Kconfig
index 385513cfdc30..122726f84492 100644
--- a/drivers/net/wireless/ath/ath11k/Kconfig
+++ b/drivers/net/wireless/ath/ath11k/Kconfig
@@ -1,6 +1,6 @@
# SPDX-License-Identifier: BSD-3-Clause-Clear
config ATH11K
- tristate "Qualcomm Technologies 802.11ax chipset support"
+ tristate "Qualcomm 802.11ax chipset support"
depends on MAC80211 && HAS_DMA
select ATH_COMMON
select QCOM_QMI_HELPERS
diff --git a/drivers/net/wireless/ath/ath12k/Kconfig b/drivers/net/wireless/ath/ath12k/Kconfig
index d39c075758bd..4a2b240f967a 100644
--- a/drivers/net/wireless/ath/ath12k/Kconfig
+++ b/drivers/net/wireless/ath/ath12k/Kconfig
@@ -1,6 +1,6 @@
# SPDX-License-Identifier: BSD-3-Clause-Clear
config ATH12K
- tristate "Qualcomm Technologies Wi-Fi 7 support (ath12k)"
+ tristate "Qualcomm Wi-Fi 7 support (ath12k)"
depends on MAC80211 && HAS_DMA && PCI
select QCOM_QMI_HELPERS
select MHI_BUS
@@ -15,7 +15,7 @@ config ATH12K
If you choose to build a module, it'll be called ath12k.
config ATH12K_AHB
- bool "QTI ath12k AHB support"
+ bool "Qualcomm ath12k AHB support"
depends on ATH12K && REMOTEPROC
select QCOM_MDT_LOADER
select QCOM_SCM
@@ -33,7 +33,7 @@ config ATH12K_DEBUG
you want optimal performance choose N.
config ATH12K_DEBUGFS
- bool "QTI ath12k debugfs support"
+ bool "Qualcomm ath12k debugfs support"
depends on ATH12K && MAC80211_DEBUGFS
help
Enable ath12k debugfs support
--
2.51.0
^ permalink raw reply related
* Re: [PATCH] wifi: ath12k: fix use-after-free of arvif in assign_vif_chanctx()
From: James Kim @ 2026-04-27 7:26 UTC (permalink / raw)
To: jjohnson
Cc: quic_srirrama, quic_ramess, kvalo, stable, linux-wireless, ath12k,
linux-kernel
In-Reply-To: <20260310024305.555408-1-james010kim@gmail.com>
Hi,
Just a gentle ping on this patch “wifi: ath12k: fix use-after-free of
arvif in assign_vif_chanctx()” (submitted on March 10, 2026).
It is a small, self-contained bug fix with a Fixes: tag, and the patch
still shows up as “New” in linux-wireless patchwork.
Please let me know if any changes are needed or if there is a better
way to route this fix.
Thanks,
James
On Tue, Mar 10, 2026 at 11:45 AM James Kim <james010kim@gmail.com> wrote:
>
> In ath12k_mac_op_assign_vif_chanctx(), arvif is obtained from
> ath12k_mac_assign_link_vif() and then passed to
> ath12k_mac_assign_vif_to_vdev(). Inside that function, when the
> target radio (ar) differs from arvif->ar (multi-radio configuration),
> the old arvif is freed via ath12k_mac_unassign_link_vif() -> kfree()
> and a new one is allocated internally. However, only the ar pointer
> is returned to the caller — the caller's arvif still points to the
> freed memory.
>
> The caller then continues to dereference this stale arvif pointer
> at multiple locations (arvif->vdev_id, arvif->punct_bitmap,
> arvif->is_started, etc.), resulting in a use-after-free.
>
> Fix this by re-fetching arvif from ahvif->link[link_id] after
> ath12k_mac_assign_vif_to_vdev() returns, since the link pointer
> is always updated when a new arvif is assigned.
>
> Fixes: 477cabfdb776 ("wifi: ath12k: modify link arvif creation and removal for MLO")
> Cc: stable@vger.kernel.org
> Signed-off-by: James Kim <james010kim@gmail.com>
> ---
> drivers/net/wireless/ath/ath12k/mac.c | 11 +++++++++++
> 1 file changed, 11 insertions(+)
>
> diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
> index b253d1e3f405..ee44a8b59e9b 100644
> --- a/drivers/net/wireless/ath/ath12k/mac.c
> +++ b/drivers/net/wireless/ath/ath12k/mac.c
> @@ -12069,6 +12069,17 @@ ath12k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw,
> return -EINVAL;
> }
>
> + /* ath12k_mac_assign_vif_to_vdev() may free and reassign arvif
> + * internally when switching radios (ar != arvif->ar). Refresh
> + * arvif from ahvif->link[].
> + */
> + arvif = wiphy_dereference(hw->wiphy, ahvif->link[link_id]);
> + if (!arvif) {
> + ath12k_hw_warn(ah, "failed to get arvif for link %u after vdev assignment",
> + link_id);
> + return -ENOENT;
> + }
> +
> ab = ar->ab;
>
> ath12k_dbg(ab, ATH12K_DBG_MAC,
> --
> 2.43.0
>
^ permalink raw reply
* Re: [PATCH wireless-next] wifi: rt2x00: check for of_get_mac_address error
From: Stanislaw Gruszka @ 2026-04-27 7:32 UTC (permalink / raw)
To: Rosen Penev; +Cc: linux-wireless, open list
In-Reply-To: <20260427051652.954059-1-rosenp@gmail.com>
On Sun, Apr 26, 2026 at 10:16:52PM -0700, Rosen Penev wrote:
> is_valid_ether_addr is already a check of of_get_mac_address, in which
> case it returns an error if false. Just set a random MAC on all errors
> except for EPROBE_DEFER.
>
> Signed-off-by: Rosen Penev <rosenp@gmail.com>
Acked-by: Stanislaw Gruszka <stf_xl@wp.pl>
> ---
> drivers/net/wireless/ralink/rt2x00/rt2x00dev.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
> index 2d778ea5f1b5..51b836343f07 100644
> --- a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
> +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
> @@ -991,7 +991,7 @@ int rt2x00lib_set_mac_address(struct rt2x00_dev *rt2x00dev, u8 *eeprom_mac_addr)
> if (ret == -EPROBE_DEFER)
> return ret;
>
> - if (!is_valid_ether_addr(eeprom_mac_addr)) {
> + if (ret) {
> eth_random_addr(eeprom_mac_addr);
> rt2x00_eeprom_dbg(rt2x00dev, "MAC: %pM\n", eeprom_mac_addr);
> }
> --
> 2.54.0
>
^ permalink raw reply
* Re: [PATCH] wifi: wfx: handle EPROBE_DEFER with of_get_mac_address
From: Jérôme Pouiller @ 2026-04-27 7:49 UTC (permalink / raw)
To: linux-wireless@vger.kernel.org, Rosen Penev; +Cc: open list
In-Reply-To: <20260427051604.953450-1-rosenp@gmail.com>
Hello Rosen,
On Monday 27 April 2026 07:16:04 Central European Summer Time Rosen Penev wrote:
>
> In case nvmem gets used and is not ready in time for probe of wfx,
> EPROBE_DEFER gets called. Return it so that a proper MAC address can be
> specified in such a case.
>
> Signed-off-by: Rosen Penev <rosenp@gmail.com>
> ---
> drivers/net/wireless/silabs/wfx/main.c | 2 ++
> 1 file changed, 2 insertions(+)
>
> diff --git a/drivers/net/wireless/silabs/wfx/main.c b/drivers/net/wireless/silabs/wfx/main.c
> index dda36e41eed1..dc40a9bd986d 100644
> --- a/drivers/net/wireless/silabs/wfx/main.c
> +++ b/drivers/net/wireless/silabs/wfx/main.c
> @@ -445,6 +445,8 @@ int wfx_probe(struct wfx_dev *wdev)
> for (i = 0; i < ARRAY_SIZE(wdev->addresses); i++) {
> eth_zero_addr(wdev->addresses[i].addr);
> err = of_get_mac_address(wdev->dev->of_node, wdev->addresses[i].addr);
> + if (err == -EPROBE_DEFER)
> + goto irq_unsubscribe;
> if (!err)
> wdev->addresses[i].addr[ETH_ALEN - 1] += i;
> else
I assume this patch works when WF200 is connected on SPI with reset GPIO
configured. However, for SDIO and without gpio reset, we can't run the
device initialisation twice.
I believe the check has to happen before the call to wfx_init_device().
To check it works as expected, can you also test your patch without the
reset-gpio attribute?
--
Jérôme Pouiller
^ permalink raw reply
* Re: [PATCH 1/9] bitfield: add FIELD_GET_SIGNED()
From: Johannes Berg @ 2026-04-27 8:29 UTC (permalink / raw)
To: Yury Norov
Cc: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
H. Peter Anvin, Andy Lutomirski, Peter Zijlstra, Jonathan Cameron,
David Lechner, Nuno Sá, Andy Shevchenko, Ping-Ke Shih,
Richard Cochran, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Alexandre Belloni, Yury Norov,
Rasmus Villemoes, Hans de Goede, Linus Walleij, Sakari Ailus,
Salah Triki, Achim Gratz, Ben Collins, linux-kernel, linux-iio,
linux-wireless, netdev, linux-rtc
In-Reply-To: <aeub59FBHbCy-KKP@yury>
On Fri, 2026-04-24 at 12:35 -0400, Yury Norov wrote:
> > I (personally) tend to prefer the "__MAKE_OP" versions (*_get_bits()
> > etc.), in particular because WiFi and firmware interfaces deal a lot
> > with fixed endian fields.
>
> I don't like that __MAKE_OP magic because whatever it generates is not
> greppable. And because we disable strict type checks for kernel, but
> this API claims to typecheck the parameters for the user. So, the
> following compiles well:
>
> u64 val = 0;
> ret = le16_get_bits(val, GENMASK(15, 10));
>
> I don't like autogeneration in general. We generate, for example,
> be32_get_bits(), but never use it.
That's a lot of "I don't like", but whatever.
> We don't even know the level of the bloat.
These are static inlines so there's no binary cost, and given that
you're complaining about them being generated you can't really *also*
complain about too much code...
> > Any chance it'd be simple to generate u32_get_bits_signed() etc.? Could
> > be especially useful for le32_get_bits_signed() for example, to have the
> > endian conversion built-in unlike FIELD_GET_SIGNED().
>
> Maybe this:
>
> FIELD_GET_SIGNED(mask, le32_to_cpu(reg))
Awful. "I don't like". But we rarely deal with bit-packed signed values
anyway.
johannes
^ permalink raw reply
* Re: [PATCH] wifi: rsi: fix kthread lifetime race between self-exit and external-stop
From: Jeongjun Park @ 2026-04-27 9:37 UTC (permalink / raw)
To: Hillf Danton
Cc: Johannes Berg, Kalle Valo, linux-wireless, linux-kernel,
syzbot+5de83f57cd8531f55596, syzkaller-bugs, stable
In-Reply-To: <20260423041500.2020-1-hdanton@sina.com>
Hi Hillf,
Hillf Danton <hdanton@sina.com> wrote:
>
> On Thu, 23 Apr 2026 02:38:46 +0900 Jeongjun Park wrote:
> > RSI driver use both self-exit(kthread_complete_and_exit) and external-stop
> > (kthread_stop) when killing a kthread. Generally, kthread_stop() is called
> > first, and in this case, no particular issues occur.
> >
> > However, in rare instances where kthread_complete_and_exit() is called
> > first and then kthread_stop() is called, a UAF occurs because the kthread
> > object, which has already exited and been freed, is accessed again.
> >
> Alternatively the race could be described with the regular diagram to better
> understand the uaf.
>
> rsi_kill_thread() rsi_tx_scheduler_thread()
> --- ---
> atomic_inc(&handle->thread_done); // set the done flag
> rsi_set_event(&handle->event);
>
> do {
> something;
> } while (atomic_read(&common->tx_thread.thread_done) == 0);
> // exit after done
> kthread_complete_and_exit(&common->tx_thread.completion, 0);
>
> kthread_stop(handle->task); // uaf
>
I did not include the race scenario diagram separately to keep the
description brief. Apart from that, Hillf's diagram itself is accurate.
Regards,
Jeongjun Park
^ permalink raw reply
* Re: [PATCH 1/9] bitfield: add FIELD_GET_SIGNED()
From: David Laight @ 2026-04-27 9:42 UTC (permalink / raw)
To: Johannes Berg
Cc: Yury Norov, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
Dave Hansen, x86
In-Reply-To: <dc1b12e74b3f487eb531bf7def806f10d9a18b5e.camel@sipsolutions.net>
On Mon, 27 Apr 2026 10:29:21 +0200
Johannes Berg <johannes@sipsolutions.net> wrote:
> On Fri, 2026-04-24 at 12:35 -0400, Yury Norov wrote:
> > > I (personally) tend to prefer the "__MAKE_OP" versions (*_get_bits()
> > > etc.), in particular because WiFi and firmware interfaces deal a lot
> > > with fixed endian fields.
> >
> > I don't like that __MAKE_OP magic because whatever it generates is not
> > greppable. And because we disable strict type checks for kernel, but
> > this API claims to typecheck the parameters for the user. So, the
> > following compiles well:
> >
> > u64 val = 0;
> > ret = le16_get_bits(val, GENMASK(15, 10));
> >
> > I don't like autogeneration in general. We generate, for example,
> > be32_get_bits(), but never use it.
>
> That's a lot of "I don't like", but whatever.
>
>
> > We don't even know the level of the bloat.
>
> These are static inlines so there's no binary cost, and given that
> you're complaining about them being generated you can't really *also*
> complain about too much code...
There is a measurable compile-time cost for processing the definitions
of static inlines even when they aren't used.
While processing the definitions of #defines is cheap, processing the
expansions can be measurable. Particularly when expansions get nested
as often happens when GENMASK() is used as an argument to FIELD_xxx().
Even trivial #defines can affect compile times.
The 'size' check in READ_ONCE() (etc) costs about 1%.
(1% may not sound much, but find 10 of them and it becomes significant.)
I suspect a lot of that is adding the extra external function to hold
the error message.
David
>
> > > Any chance it'd be simple to generate u32_get_bits_signed() etc.? Could
> > > be especially useful for le32_get_bits_signed() for example, to have the
> > > endian conversion built-in unlike FIELD_GET_SIGNED().
> >
> > Maybe this:
> >
> > FIELD_GET_SIGNED(mask, le32_to_cpu(reg))
>
> Awful. "I don't like". But we rarely deal with bit-packed signed values
> anyway.
>
> johannes
>
^ permalink raw reply
* Re: [PATCH] iw: Makefile: support out-of-tree builds
From: Johannes Berg @ 2026-04-27 9:43 UTC (permalink / raw)
To: Maxin John, linux-wireless
In-Reply-To: <20260423113154.1070521-1-maxin.john@gmail.com>
On Thu, 2026-04-23 at 14:31 +0300, Maxin John wrote:
> Enable out-of-tree builds without modifying the source tree.
> Out-of-tree builds are required by build frameworks such as OpenEmbedded.
You should probably say how this is intended to be used, clearly not in
the O= way that the kernel has, for example.
> +SRCDIR := $(dir $(lastword $(MAKEFILE_LIST)))
That doesn't work if there's whitespace anywhere along the path.
> +CPPFLAGS += -I$(SRCDIR)
> +CPPFLAGS += -I.
The "-I." seems questionable since you evidently intend to have "."
*not* be the source dir?
Overall it might be simpler to actually do it with the kernel-style O=
so you just need to change all the outputs, rather than all the inputs?
johannes
^ permalink raw reply
* [PATCH v4 00/15] firmware: qcom: Add OP-TEE PAS service support
From: Sumit Garg @ 2026-04-27 9:55 UTC (permalink / raw)
To: andersson, konradybcio
Cc: linux-arm-msm, devicetree, dri-devel, freedreno, linux-media,
netdev, linux-wireless, ath12k, linux-remoteproc, robh, krzk+dt,
conor+dt, robin.clark, sean, akhilpo, lumag, abhinav.kumar,
jesszhan0024, marijn.suijten, airlied, simona, vikash.garodia,
dikshita.agarwal, bod, mchehab, elder, andrew+netdev, davem,
edumazet, kuba, pabeni, jjohnson, mathieu.poirier,
trilokkumar.soni, mukesh.ojha, pavan.kondeti, jorge.ramirez,
tonyh, vignesh.viswanathan, srinivas.kandagatla, amirreza.zarrabi,
jens.wiklander, op-tee, apurupa, skare, linux-kernel, Sumit Garg
From: Sumit Garg <sumit.garg@oss.qualcomm.com>
Qcom platforms has the legacy of using non-standard SCM calls
splintered over the various kernel drivers. These SCM calls aren't
compliant with the standard SMC calling conventions which is a
prerequisite to enable migration to the FF-A specifications from Arm.
OP-TEE as an alternative trusted OS to Qualcomm TEE (QTEE) can't
support these non-standard SCM calls. And even for newer architectures
using S-EL2 with Hafnium support, QTEE won't be able to support SCM
calls either with FF-A requirements coming in. And with both OP-TEE
and QTEE drivers well integrated in the TEE subsystem, it makes further
sense to reuse the TEE bus client drivers infrastructure.
The added benefit of TEE bus infrastructure is that there is support
for discoverable/enumerable services. With that client drivers don't
have to manually invoke a special SCM call to know the service status.
So enable the generic Peripheral Authentication Service (PAS) provided
by the firmware. It acts as the common layer with different TZ
backends plugged in whether it's an SCM implementation or a proper
TEE bus based PAS service implementation.
The TEE PAS service ABI is designed to be extensible with additional API
as PTA_QCOM_PAS_CAPABILITIES. This allows to accommodate any future
extensions of the PAS service needed while still maintaining backwards
compatibility.
Currently OP-TEE support is being added to provide the backend PAS
service implementation which can be found as part of this PR [1].
This implementation has been tested on Kodiak/RB3Gen2 board with lemans
EVK board being the next target. In addition to that WIN/IPQ targets
planning to use OP-TEE will use this service too. Surely the backwards
compatibility is maintained and tested for SCM backend.
Note that kernel PAS service support while running in EL2 is at parity
among OP-TEE vs QTEE. Especially the media (venus/iris) support depends
on proper IOMMU support being worked out on the PAS client end.
Patch summary:
- Patch #1: adds Kodiak EL2 overlay since boot stack with TF-A/OP-TEE
only allow UEFI and Linux to boot in EL2.
- Patch #2: adds generic PAS service.
- Patch #3: migrates SCM backend to generic PAS service.
- Patch #4: adds TEE/OP-TEE backend for generic PAS service.
- Patch #5-#13: migrates all client drivers to generic PAS service.
- Patch #14: drops legacy PAS SCM exported APIs.
The patch-set is based on v7.1-rc1 tag and can be found in git tree here
[2].
Merge strategy:
It is expected due to APIs dependency, the entire patch-set to go via
the Qcom tree. All other subsystem maintainers, it will be great if I
can get acks for the corresponding subsystem patches.
[1] https://github.com/OP-TEE/optee_os/pull/7721
[2] https://git.kernel.org/pub/scm/linux/kernel/git/sumit.garg/linux.git/log/?h=qcom-pas-v4
---
Changes in v4:
- Incorporate misc. comments on patch #4.
- Picked up an ack for patch #10.
- Clarify in cover letter about state of media support.
Changes in v3:
- Incorporated some style and misc. comments for patch #2, #3 and #4.
- Add QCOM_PAS Kconfig dependency for various subsystems.
- Switch from pseudo TA to proper TA invoke commands.
Changes in v2:
- Fixed kernel doc warnings.
- Polish commit message and comments for patch #2.
- Pass proper PAS ID in set_remote_state API for media firmware drivers.
- Added Maintainer entry and dropped MODULE_AUTHOR.
Mukesh Ojha (1):
arm64: dts: qcom: kodiak: Add EL2 overlay
Sumit Garg (14):
firmware: qcom: Add a generic PAS service
firmware: qcom_scm: Migrate to generic PAS service
firmware: qcom: Add a PAS TEE service
remoteproc: qcom_q6v5_pas: Switch over to generic PAS TZ APIs
remoteproc: qcom_q6v5_mss: Switch to generic PAS TZ APIs
soc: qcom: mdtloader: Switch to generic PAS TZ APIs
remoteproc: qcom_wcnss: Switch to generic PAS TZ APIs
remoteproc: qcom: Select QCOM_PAS generic service
drm/msm: Switch to generic PAS TZ APIs
media: qcom: Switch to generic PAS TZ APIs
net: ipa: Switch to generic PAS TZ APIs
wifi: ath12k: Switch to generic PAS TZ APIs
firmware: qcom_scm: Remove SCM PAS wrappers
MAINTAINERS: Add maintainer entry for Qualcomm PAS TZ service
MAINTAINERS | 9 +
arch/arm64/boot/dts/qcom/Makefile | 2 +
arch/arm64/boot/dts/qcom/kodiak-el2.dtso | 35 ++
drivers/firmware/qcom/Kconfig | 19 +
drivers/firmware/qcom/Makefile | 2 +
drivers/firmware/qcom/qcom_pas.c | 288 +++++++++++
drivers/firmware/qcom/qcom_pas.h | 50 ++
drivers/firmware/qcom/qcom_pas_tee.c | 479 ++++++++++++++++++
drivers/firmware/qcom/qcom_scm.c | 302 ++++-------
drivers/gpu/drm/msm/Kconfig | 1 +
drivers/gpu/drm/msm/adreno/a5xx_gpu.c | 4 +-
drivers/gpu/drm/msm/adreno/adreno_gpu.c | 11 +-
drivers/media/platform/qcom/iris/Kconfig | 25 +-
.../media/platform/qcom/iris/iris_firmware.c | 9 +-
drivers/media/platform/qcom/venus/Kconfig | 1 +
drivers/media/platform/qcom/venus/firmware.c | 11 +-
drivers/net/ipa/Kconfig | 2 +-
drivers/net/ipa/ipa_main.c | 13 +-
drivers/net/wireless/ath/ath12k/Kconfig | 2 +-
drivers/net/wireless/ath/ath12k/ahb.c | 8 +-
drivers/remoteproc/Kconfig | 1 +
drivers/remoteproc/qcom_q6v5_mss.c | 5 +-
drivers/remoteproc/qcom_q6v5_pas.c | 51 +-
drivers/remoteproc/qcom_wcnss.c | 12 +-
drivers/soc/qcom/mdt_loader.c | 12 +-
include/linux/firmware/qcom/qcom_pas.h | 43 ++
include/linux/firmware/qcom/qcom_scm.h | 29 --
include/linux/soc/qcom/mdt_loader.h | 6 +-
28 files changed, 1115 insertions(+), 317 deletions(-)
create mode 100644 arch/arm64/boot/dts/qcom/kodiak-el2.dtso
create mode 100644 drivers/firmware/qcom/qcom_pas.c
create mode 100644 drivers/firmware/qcom/qcom_pas.h
create mode 100644 drivers/firmware/qcom/qcom_pas_tee.c
create mode 100644 include/linux/firmware/qcom/qcom_pas.h
--
2.51.0
^ permalink raw reply
* [PATCH v4 01/15] arm64: dts: qcom: kodiak: Add EL2 overlay
From: Sumit Garg @ 2026-04-27 9:55 UTC (permalink / raw)
To: andersson, konradybcio
Cc: linux-arm-msm, devicetree, dri-devel, freedreno, linux-media,
netdev, linux-wireless, ath12k, linux-remoteproc, robh, krzk+dt,
conor+dt, robin.clark, sean, akhilpo, lumag, abhinav.kumar,
jesszhan0024, marijn.suijten, airlied, simona, vikash.garodia,
dikshita.agarwal, bod, mchehab, elder, andrew+netdev, davem,
edumazet, kuba, pabeni, jjohnson, mathieu.poirier,
trilokkumar.soni, mukesh.ojha, pavan.kondeti, jorge.ramirez,
tonyh, vignesh.viswanathan, srinivas.kandagatla, amirreza.zarrabi,
jens.wiklander, op-tee, apurupa, skare, linux-kernel, Sumit Garg
In-Reply-To: <20260427095603.1157963-1-sumit.garg@kernel.org>
From: Mukesh Ojha <mukesh.ojha@oss.qualcomm.com>
All the existing variants Kodiak boards are using Gunyah hypervisor
which means that, so far, Linux-based OS could only boot in EL1 on those
devices. However, it is possible for us to boot Linux at EL2 on these
devices [1].
When running under Gunyah, the remote processor firmware IOMMU
streams are controlled by Gunyah. However, without Gunyah, the IOMMU is
managed by the consumer of this DeviceTree. Therefore, describe the
firmware streams for each remote processor.
Add a EL2-specific DT overlay and apply it to Kodiak IOT variant
devices to create -el2.dtb for each of them alongside "normal" dtb.
[1]
https://docs.qualcomm.com/bundle/publicresource/topics/80-70020-4/boot-developer-touchpoints.html#uefi
Signed-off-by: Mukesh Ojha <mukesh.ojha@oss.qualcomm.com>
[SG: watchdog fixup]
Signed-off-by: Sumit Garg <sumit.garg@oss.qualcomm.com>
---
arch/arm64/boot/dts/qcom/Makefile | 2 ++
arch/arm64/boot/dts/qcom/kodiak-el2.dtso | 35 ++++++++++++++++++++++++
2 files changed, 37 insertions(+)
create mode 100644 arch/arm64/boot/dts/qcom/kodiak-el2.dtso
diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile
index 4ba8e7306419..28123cdc9de2 100644
--- a/arch/arm64/boot/dts/qcom/Makefile
+++ b/arch/arm64/boot/dts/qcom/Makefile
@@ -170,6 +170,8 @@ qcs615-ride-el2-dtbs := qcs615-ride.dtb talos-el2.dtbo
dtb-$(CONFIG_ARCH_QCOM) += qcs615-ride-el2.dtb
dtb-$(CONFIG_ARCH_QCOM) += qcs6490-radxa-dragon-q6a.dtb
dtb-$(CONFIG_ARCH_QCOM) += qcs6490-rb3gen2.dtb
+qcs6490-rb3gen2-el2-dtbs := qcs6490-rb3gen2.dtb kodiak-el2.dtbo
+dtb-$(CONFIG_ARCH_QCOM) += qcs6490-rb3gen2-el2.dtb
qcs6490-rb3gen2-vision-mezzanine-dtbs := qcs6490-rb3gen2.dtb qcs6490-rb3gen2-vision-mezzanine.dtbo
qcs6490-rb3gen2-industrial-mezzanine-dtbs := qcs6490-rb3gen2.dtb qcs6490-rb3gen2-industrial-mezzanine.dtbo
diff --git a/arch/arm64/boot/dts/qcom/kodiak-el2.dtso b/arch/arm64/boot/dts/qcom/kodiak-el2.dtso
new file mode 100644
index 000000000000..0b3a69a0d765
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/kodiak-el2.dtso
@@ -0,0 +1,35 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ *
+ * Kodiak specific modifications required to boot in EL2.
+ */
+
+
+/dts-v1/;
+/plugin/;
+
+&gpu_zap_shader {
+ status = "disabled";
+};
+
+&remoteproc_adsp {
+ iommus = <&apps_smmu 0x1800 0x0>;
+};
+
+&remoteproc_cdsp {
+ iommus = <&apps_smmu 0x11a0 0x0400>;
+};
+
+&remoteproc_wpss {
+ iommus = <&apps_smmu 0x1c03 0x1>,
+ <&apps_smmu 0x1c83 0x1>;
+};
+
+&venus {
+ status = "disabled";
+};
+
+&watchdog {
+ status = "okay";
+};
--
2.51.0
^ permalink raw reply related
* [PATCH v4 02/15] firmware: qcom: Add a generic PAS service
From: Sumit Garg @ 2026-04-27 9:55 UTC (permalink / raw)
To: andersson, konradybcio
Cc: linux-arm-msm, devicetree, dri-devel, freedreno, linux-media,
netdev, linux-wireless, ath12k, linux-remoteproc, robh, krzk+dt,
conor+dt, robin.clark, sean, akhilpo, lumag, abhinav.kumar,
jesszhan0024, marijn.suijten, airlied, simona, vikash.garodia,
dikshita.agarwal, bod, mchehab, elder, andrew+netdev, davem,
edumazet, kuba, pabeni, jjohnson, mathieu.poirier,
trilokkumar.soni, mukesh.ojha, pavan.kondeti, jorge.ramirez,
tonyh, vignesh.viswanathan, srinivas.kandagatla, amirreza.zarrabi,
jens.wiklander, op-tee, apurupa, skare, linux-kernel, Sumit Garg
In-Reply-To: <20260427095603.1157963-1-sumit.garg@kernel.org>
From: Sumit Garg <sumit.garg@oss.qualcomm.com>
Qcom platforms has the legacy of using non-standard SCM calls
splintered over the various kernel drivers. These SCM calls aren't
compliant with the standard SMC calling conventions which is a
prerequisite to enable migration to the FF-A specifications from Arm.
OP-TEE as an alternative trusted OS to Qualcomm TEE (QTEE) can't
support these non-standard SCM calls. And even for newer architectures
using S-EL2 with Hafnium support, QTEE won't be able to support SCM
calls either with FF-A requirements coming in. And with both OP-TEE
and QTEE drivers well integrated in the TEE subsystem, it makes further
sense to reuse the TEE bus client drivers infrastructure.
The added benefit of TEE bus infrastructure is that there is support
for discoverable/enumerable services. With that client drivers don't
have to manually invoke a special SCM call to know the service status.
So enable the generic Peripheral Authentication Service (PAS) provided
by the firmware. It acts as the common layer with different TZ
backends plugged in whether it's an SCM implementation or a proper
TEE bus based PAS service implementation.
Signed-off-by: Sumit Garg <sumit.garg@oss.qualcomm.com>
---
drivers/firmware/qcom/Kconfig | 8 +
drivers/firmware/qcom/Makefile | 1 +
drivers/firmware/qcom/qcom_pas.c | 288 +++++++++++++++++++++++++
drivers/firmware/qcom/qcom_pas.h | 50 +++++
include/linux/firmware/qcom/qcom_pas.h | 43 ++++
5 files changed, 390 insertions(+)
create mode 100644 drivers/firmware/qcom/qcom_pas.c
create mode 100644 drivers/firmware/qcom/qcom_pas.h
create mode 100644 include/linux/firmware/qcom/qcom_pas.h
diff --git a/drivers/firmware/qcom/Kconfig b/drivers/firmware/qcom/Kconfig
index b477d54b495a..8653639d06db 100644
--- a/drivers/firmware/qcom/Kconfig
+++ b/drivers/firmware/qcom/Kconfig
@@ -6,6 +6,14 @@
menu "Qualcomm firmware drivers"
+config QCOM_PAS
+ tristate
+ help
+ Enable the generic Peripheral Authentication Service (PAS) provided
+ by the firmware. It acts as the common layer with different TZ
+ backends plugged in whether it's an SCM implementation or a proper
+ TEE bus based PAS service implementation.
+
config QCOM_SCM
select QCOM_TZMEM
tristate
diff --git a/drivers/firmware/qcom/Makefile b/drivers/firmware/qcom/Makefile
index 0be40a1abc13..dc5ab45f906a 100644
--- a/drivers/firmware/qcom/Makefile
+++ b/drivers/firmware/qcom/Makefile
@@ -8,3 +8,4 @@ qcom-scm-objs += qcom_scm.o qcom_scm-smc.o qcom_scm-legacy.o
obj-$(CONFIG_QCOM_TZMEM) += qcom_tzmem.o
obj-$(CONFIG_QCOM_QSEECOM) += qcom_qseecom.o
obj-$(CONFIG_QCOM_QSEECOM_UEFISECAPP) += qcom_qseecom_uefisecapp.o
+obj-$(CONFIG_QCOM_PAS) += qcom_pas.o
diff --git a/drivers/firmware/qcom/qcom_pas.c b/drivers/firmware/qcom/qcom_pas.c
new file mode 100644
index 000000000000..caf7fff33e5c
--- /dev/null
+++ b/drivers/firmware/qcom/qcom_pas.c
@@ -0,0 +1,288 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#include <linux/device/devres.h>
+#include <linux/firmware/qcom/qcom_pas.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include "qcom_pas.h"
+
+static struct qcom_pas_ops *ops_ptr;
+
+/**
+ * devm_qcom_pas_context_alloc() - Allocate peripheral authentication service
+ * context for a given peripheral
+ *
+ * PAS context is device-resource managed, so the caller does not need
+ * to worry about freeing the context memory.
+ *
+ * @dev: PAS firmware device
+ * @pas_id: peripheral authentication service id
+ * @mem_phys: Subsystem reserve memory start address
+ * @mem_size: Subsystem reserve memory size
+ *
+ * Return: The new PAS context, or ERR_PTR() on failure.
+ */
+struct qcom_pas_context *devm_qcom_pas_context_alloc(struct device *dev,
+ u32 pas_id,
+ phys_addr_t mem_phys,
+ size_t mem_size)
+{
+ struct qcom_pas_context *ctx;
+
+ ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return ERR_PTR(-ENOMEM);
+
+ ctx->dev = dev;
+ ctx->pas_id = pas_id;
+ ctx->mem_phys = mem_phys;
+ ctx->mem_size = mem_size;
+
+ return ctx;
+}
+EXPORT_SYMBOL_GPL(devm_qcom_pas_context_alloc);
+
+/**
+ * qcom_pas_init_image() - Initialize peripheral authentication service state
+ * machine for a given peripheral, using the metadata
+ * @pas_id: peripheral authentication service id
+ * @metadata: pointer to memory containing ELF header, program header table
+ * and optional blob of data used for authenticating the metadata
+ * and the rest of the firmware
+ * @size: size of the metadata
+ * @ctx: optional pas context
+ *
+ * Return: 0 on success.
+ *
+ * Upon successful return, the PAS metadata context (@ctx) will be used to
+ * track the metadata allocation, this needs to be released by invoking
+ * qcom_pas_metadata_release() by the caller.
+ */
+int qcom_pas_init_image(u32 pas_id, const void *metadata, size_t size,
+ struct qcom_pas_context *ctx)
+{
+ if (!ops_ptr)
+ return -ENODEV;
+
+ return ops_ptr->init_image(ops_ptr->dev, pas_id, metadata, size, ctx);
+}
+EXPORT_SYMBOL_GPL(qcom_pas_init_image);
+
+/**
+ * qcom_pas_metadata_release() - release metadata context
+ * @ctx: pas context
+ */
+void qcom_pas_metadata_release(struct qcom_pas_context *ctx)
+{
+ if (!ctx || !ctx->ptr || !ops_ptr)
+ return;
+
+ ops_ptr->metadata_release(ops_ptr->dev, ctx);
+}
+EXPORT_SYMBOL_GPL(qcom_pas_metadata_release);
+
+/**
+ * qcom_pas_mem_setup() - Prepare the memory related to a given peripheral
+ * for firmware loading
+ * @pas_id: peripheral authentication service id
+ * @addr: start address of memory area to prepare
+ * @size: size of the memory area to prepare
+ *
+ * Return: 0 on success.
+ */
+int qcom_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size)
+{
+ if (!ops_ptr)
+ return -ENODEV;
+
+ return ops_ptr->mem_setup(ops_ptr->dev, pas_id, addr, size);
+}
+EXPORT_SYMBOL_GPL(qcom_pas_mem_setup);
+
+/**
+ * qcom_pas_get_rsc_table() - Retrieve the resource table in passed output buffer
+ * for a given peripheral.
+ *
+ * Qualcomm remote processor may rely on both static and dynamic resources for
+ * its functionality. Static resources typically refer to memory-mapped
+ * addresses required by the subsystem and are often embedded within the
+ * firmware binary and dynamic resources, such as shared memory in DDR etc.,
+ * are determined at runtime during the boot process.
+ *
+ * On Qualcomm Technologies devices, it's possible that static resources are
+ * not embedded in the firmware binary and instead are provided by TrustZone.
+ * However, dynamic resources are always expected to come from TrustZone. This
+ * indicates that for Qualcomm devices, all resources (static and dynamic) will
+ * be provided by TrustZone PAS service.
+ *
+ * If the remote processor firmware binary does contain static resources, they
+ * should be passed in input_rt. These will be forwarded to TrustZone for
+ * authentication. TrustZone will then append the dynamic resources and return
+ * the complete resource table in output_rt_tzm.
+ *
+ * If the remote processor firmware binary does not include a resource table,
+ * the caller of this function should set input_rt as NULL and input_rt_size
+ * as zero respectively.
+ *
+ * More about documentation on resource table data structures can be found in
+ * include/linux/remoteproc.h
+ *
+ * @ctx: PAS context
+ * @pas_id: peripheral authentication service id
+ * @input_rt: resource table buffer which is present in firmware binary
+ * @input_rt_size: size of the resource table present in firmware binary
+ * @output_rt_size: TrustZone expects caller should pass worst case size for
+ * the output_rt_tzm.
+ *
+ * Return:
+ * On success, returns a pointer to the allocated buffer containing the final
+ * resource table and output_rt_size will have actual resource table size from
+ * TrustZone. The caller is responsible for freeing the buffer. On failure,
+ * returns ERR_PTR(-errno).
+ */
+struct resource_table *qcom_pas_get_rsc_table(struct qcom_pas_context *ctx,
+ void *input_rt,
+ size_t input_rt_size,
+ size_t *output_rt_size)
+{
+ if (!ctx)
+ return ERR_PTR(-EINVAL);
+ if (!ops_ptr)
+ return ERR_PTR(-ENODEV);
+
+ return ops_ptr->get_rsc_table(ops_ptr->dev, ctx, input_rt,
+ input_rt_size, output_rt_size);
+}
+EXPORT_SYMBOL_GPL(qcom_pas_get_rsc_table);
+
+/**
+ * qcom_pas_auth_and_reset() - Authenticate the given peripheral firmware
+ * and reset the remote processor
+ * @pas_id: peripheral authentication service id
+ *
+ * Return: 0 on success.
+ */
+int qcom_pas_auth_and_reset(u32 pas_id)
+{
+ if (!ops_ptr)
+ return -ENODEV;
+
+ return ops_ptr->auth_and_reset(ops_ptr->dev, pas_id);
+}
+EXPORT_SYMBOL_GPL(qcom_pas_auth_and_reset);
+
+/**
+ * qcom_pas_prepare_and_auth_reset() - Prepare, authenticate, and reset the
+ * remote processor
+ *
+ * @ctx: Context saved during call to qcom_scm_pas_context_init()
+ *
+ * This function performs the necessary steps to prepare a PAS subsystem,
+ * authenticate it using the provided metadata, and initiate a reset sequence.
+ *
+ * It should be used when Linux is in control setting up the IOMMU hardware
+ * for remote subsystem during secure firmware loading processes. The
+ * preparation step sets up a shmbridge over the firmware memory before
+ * TrustZone accesses the firmware memory region for authentication. The
+ * authentication step verifies the integrity and authenticity of the firmware
+ * or configuration using secure metadata. Finally, the reset step ensures the
+ * subsystem starts in a clean and sane state.
+ *
+ * Return: 0 on success, negative errno on failure.
+ */
+int qcom_pas_prepare_and_auth_reset(struct qcom_pas_context *ctx)
+{
+ if (!ctx)
+ return -EINVAL;
+ if (!ops_ptr)
+ return -ENODEV;
+
+ return ops_ptr->prepare_and_auth_reset(ops_ptr->dev, ctx);
+}
+EXPORT_SYMBOL_GPL(qcom_pas_prepare_and_auth_reset);
+
+/**
+ * qcom_pas_set_remote_state() - Set the remote processor state
+ * @state: peripheral state
+ * @pas_id: peripheral authentication service id
+ *
+ * Return: 0 on success.
+ */
+int qcom_pas_set_remote_state(u32 state, u32 pas_id)
+{
+ if (!ops_ptr)
+ return -ENODEV;
+
+ return ops_ptr->set_remote_state(ops_ptr->dev, state, pas_id);
+}
+EXPORT_SYMBOL_GPL(qcom_pas_set_remote_state);
+
+/**
+ * qcom_pas_shutdown() - Shut down the remote processor
+ * @pas_id: peripheral authentication service id
+ *
+ * Return: 0 on success.
+ */
+int qcom_pas_shutdown(u32 pas_id)
+{
+ if (!ops_ptr)
+ return -ENODEV;
+
+ return ops_ptr->shutdown(ops_ptr->dev, pas_id);
+}
+EXPORT_SYMBOL_GPL(qcom_pas_shutdown);
+
+/**
+ * qcom_pas_supported() - Check if the peripheral authentication service is
+ * available for the given peripheral
+ * @pas_id: peripheral authentication service id
+ *
+ * Return: true if PAS is supported for this peripheral, otherwise false.
+ */
+bool qcom_pas_supported(u32 pas_id)
+{
+ if (!ops_ptr)
+ return false;
+
+ return ops_ptr->supported(ops_ptr->dev, pas_id);
+}
+EXPORT_SYMBOL_GPL(qcom_pas_supported);
+
+bool qcom_pas_is_available(void)
+{
+ /*
+ * The barrier for ops_ptr is intended to synchronize the data stores
+ * for the ops data structure when client drivers are in parallel
+ * checking for PAS service availability.
+ *
+ * Once the PAS backend becomes available, it is allowed for multiple
+ * threads to enter TZ for parallel bringup of co-processors during
+ * boot.
+ */
+ return !!smp_load_acquire(&ops_ptr);
+}
+EXPORT_SYMBOL_GPL(qcom_pas_is_available);
+
+void qcom_pas_ops_register(struct qcom_pas_ops *ops)
+{
+ if (!qcom_pas_is_available())
+ /* Paired with smp_load_acquire() in qcom_pas_is_available() */
+ smp_store_release(&ops_ptr, ops);
+ else
+ pr_err("qcom_pas: ops already registered\n");
+}
+EXPORT_SYMBOL_GPL(qcom_pas_ops_register);
+
+void qcom_pas_ops_unregister(void)
+{
+ /* Paired with smp_load_acquire() in qcom_pas_is_available() */
+ smp_store_release(&ops_ptr, NULL);
+}
+EXPORT_SYMBOL_GPL(qcom_pas_ops_unregister);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Qualcomm common TZ PAS driver");
diff --git a/drivers/firmware/qcom/qcom_pas.h b/drivers/firmware/qcom/qcom_pas.h
new file mode 100644
index 000000000000..8643e2760602
--- /dev/null
+++ b/drivers/firmware/qcom/qcom_pas.h
@@ -0,0 +1,50 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#ifndef __QCOM_PAS_INT_H
+#define __QCOM_PAS_INT_H
+
+struct device;
+
+/**
+ * struct qcom_pas_ops - Qcom Peripheral Authentication Service (PAS) ops
+ * @drv_name: PAS driver name.
+ * @dev: PAS device pointer.
+ * @supported: Peripheral supported callback.
+ * @init_image: Peripheral image initialization callback.
+ * @mem_setup: Peripheral memory setup callback.
+ * @get_rsc_table: Peripheral get resource table callback.
+ * @prepare_and_auth_reset: Peripheral prepare firmware authentication and
+ * reset callback.
+ * @auth_and_reset: Peripheral firmware authentication and reset
+ * callback.
+ * @set_remote_state: Peripheral set remote state callback.
+ * @shutdown: Peripheral shutdown callback.
+ * @metadata_release: Image metadata release callback.
+ */
+struct qcom_pas_ops {
+ const char *drv_name;
+ struct device *dev;
+ bool (*supported)(struct device *dev, u32 pas_id);
+ int (*init_image)(struct device *dev, u32 pas_id, const void *metadata,
+ size_t size, struct qcom_pas_context *ctx);
+ int (*mem_setup)(struct device *dev, u32 pas_id, phys_addr_t addr,
+ phys_addr_t size);
+ void *(*get_rsc_table)(struct device *dev, struct qcom_pas_context *ctx,
+ void *input_rt, size_t input_rt_size,
+ size_t *output_rt_size);
+ int (*prepare_and_auth_reset)(struct device *dev,
+ struct qcom_pas_context *ctx);
+ int (*auth_and_reset)(struct device *dev, u32 pas_id);
+ int (*set_remote_state)(struct device *dev, u32 state, u32 pas_id);
+ int (*shutdown)(struct device *dev, u32 pas_id);
+ void (*metadata_release)(struct device *dev,
+ struct qcom_pas_context *ctx);
+};
+
+void qcom_pas_ops_register(struct qcom_pas_ops *ops);
+void qcom_pas_ops_unregister(void);
+
+#endif /* __QCOM_PAS_INT_H */
diff --git a/include/linux/firmware/qcom/qcom_pas.h b/include/linux/firmware/qcom/qcom_pas.h
new file mode 100644
index 000000000000..65b1c9564458
--- /dev/null
+++ b/include/linux/firmware/qcom/qcom_pas.h
@@ -0,0 +1,43 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2010-2015, 2018-2019 The Linux Foundation. All rights reserved.
+ * Copyright (C) 2015 Linaro Ltd.
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#ifndef __QCOM_PAS_H
+#define __QCOM_PAS_H
+
+#include <linux/err.h>
+#include <linux/types.h>
+
+struct qcom_pas_context {
+ struct device *dev;
+ u32 pas_id;
+ phys_addr_t mem_phys;
+ size_t mem_size;
+ void *ptr;
+ dma_addr_t phys;
+ ssize_t size;
+ bool use_tzmem;
+};
+
+bool qcom_pas_is_available(void);
+struct qcom_pas_context *devm_qcom_pas_context_alloc(struct device *dev,
+ u32 pas_id,
+ phys_addr_t mem_phys,
+ size_t mem_size);
+int qcom_pas_init_image(u32 pas_id, const void *metadata, size_t size,
+ struct qcom_pas_context *ctx);
+struct resource_table *qcom_pas_get_rsc_table(struct qcom_pas_context *ctx,
+ void *input_rt, size_t input_rt_size,
+ size_t *output_rt_size);
+int qcom_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size);
+int qcom_pas_auth_and_reset(u32 pas_id);
+int qcom_pas_prepare_and_auth_reset(struct qcom_pas_context *ctx);
+int qcom_pas_set_remote_state(u32 state, u32 pas_id);
+int qcom_pas_shutdown(u32 pas_id);
+bool qcom_pas_supported(u32 pas_id);
+void qcom_pas_metadata_release(struct qcom_pas_context *ctx);
+
+#endif /* __QCOM_PAS_H */
--
2.51.0
^ permalink raw reply related
* [PATCH v4 03/15] firmware: qcom_scm: Migrate to generic PAS service
From: Sumit Garg @ 2026-04-27 9:55 UTC (permalink / raw)
To: andersson, konradybcio
Cc: linux-arm-msm, devicetree, dri-devel, freedreno, linux-media,
netdev, linux-wireless, ath12k, linux-remoteproc, robh, krzk+dt,
conor+dt, robin.clark, sean, akhilpo, lumag, abhinav.kumar,
jesszhan0024, marijn.suijten, airlied, simona, vikash.garodia,
dikshita.agarwal, bod, mchehab, elder, andrew+netdev, davem,
edumazet, kuba, pabeni, jjohnson, mathieu.poirier,
trilokkumar.soni, mukesh.ojha, pavan.kondeti, jorge.ramirez,
tonyh, vignesh.viswanathan, srinivas.kandagatla, amirreza.zarrabi,
jens.wiklander, op-tee, apurupa, skare, linux-kernel, Sumit Garg
In-Reply-To: <20260427095603.1157963-1-sumit.garg@kernel.org>
From: Sumit Garg <sumit.garg@oss.qualcomm.com>
With the availability of generic PAS service, let's add SCM calls as
a backend to keep supporting legacy QTEE interfaces. The exported
qcom_scm* wrappers will get dropped once all the client drivers get
migrated as part of future patches.
Signed-off-by: Sumit Garg <sumit.garg@oss.qualcomm.com>
---
drivers/firmware/qcom/Kconfig | 1 +
drivers/firmware/qcom/qcom_scm.c | 335 ++++++++++++++-----------------
2 files changed, 155 insertions(+), 181 deletions(-)
diff --git a/drivers/firmware/qcom/Kconfig b/drivers/firmware/qcom/Kconfig
index 8653639d06db..9a12ae2b639d 100644
--- a/drivers/firmware/qcom/Kconfig
+++ b/drivers/firmware/qcom/Kconfig
@@ -15,6 +15,7 @@ config QCOM_PAS
TEE bus based PAS service implementation.
config QCOM_SCM
+ select QCOM_PAS
select QCOM_TZMEM
tristate
diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c
index 9b06a69d3a6d..d87a962e93da 100644
--- a/drivers/firmware/qcom/qcom_scm.c
+++ b/drivers/firmware/qcom/qcom_scm.c
@@ -13,6 +13,7 @@
#include <linux/dma-mapping.h>
#include <linux/err.h>
#include <linux/export.h>
+#include <linux/firmware/qcom/qcom_pas.h>
#include <linux/firmware/qcom/qcom_scm.h>
#include <linux/firmware/qcom/qcom_tzmem.h>
#include <linux/init.h>
@@ -33,6 +34,7 @@
#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include "qcom_pas.h"
#include "qcom_scm.h"
#include "qcom_tzmem.h"
@@ -479,25 +481,6 @@ void qcom_scm_cpu_power_down(u32 flags)
}
EXPORT_SYMBOL_GPL(qcom_scm_cpu_power_down);
-int qcom_scm_set_remote_state(u32 state, u32 id)
-{
- struct qcom_scm_desc desc = {
- .svc = QCOM_SCM_SVC_BOOT,
- .cmd = QCOM_SCM_BOOT_SET_REMOTE_STATE,
- .arginfo = QCOM_SCM_ARGS(2),
- .args[0] = state,
- .args[1] = id,
- .owner = ARM_SMCCC_OWNER_SIP,
- };
- struct qcom_scm_res res;
- int ret;
-
- ret = qcom_scm_call(__scm->dev, &desc, &res);
-
- return ret ? : res.result[0];
-}
-EXPORT_SYMBOL_GPL(qcom_scm_set_remote_state);
-
static int qcom_scm_disable_sdi(void)
{
int ret;
@@ -570,26 +553,12 @@ static void qcom_scm_set_download_mode(u32 dload_mode)
dev_err(__scm->dev, "failed to set download mode: %d\n", ret);
}
-/**
- * devm_qcom_scm_pas_context_alloc() - Allocate peripheral authentication service
- * context for a given peripheral
- *
- * PAS context is device-resource managed, so the caller does not need
- * to worry about freeing the context memory.
- *
- * @dev: PAS firmware device
- * @pas_id: peripheral authentication service id
- * @mem_phys: Subsystem reserve memory start address
- * @mem_size: Subsystem reserve memory size
- *
- * Returns: The new PAS context, or ERR_PTR() on failure.
- */
struct qcom_scm_pas_context *devm_qcom_scm_pas_context_alloc(struct device *dev,
u32 pas_id,
phys_addr_t mem_phys,
size_t mem_size)
{
- struct qcom_scm_pas_context *ctx;
+ struct qcom_pas_context *ctx;
ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
@@ -600,11 +569,12 @@ struct qcom_scm_pas_context *devm_qcom_scm_pas_context_alloc(struct device *dev,
ctx->mem_phys = mem_phys;
ctx->mem_size = mem_size;
- return ctx;
+ return (struct qcom_scm_pas_context *)ctx;
}
EXPORT_SYMBOL_GPL(devm_qcom_scm_pas_context_alloc);
-static int __qcom_scm_pas_init_image(u32 pas_id, dma_addr_t mdata_phys,
+static int __qcom_scm_pas_init_image(struct device *dev, u32 pas_id,
+ dma_addr_t mdata_phys,
struct qcom_scm_res *res)
{
struct qcom_scm_desc desc = {
@@ -626,7 +596,7 @@ static int __qcom_scm_pas_init_image(u32 pas_id, dma_addr_t mdata_phys,
desc.args[1] = mdata_phys;
- ret = qcom_scm_call(__scm->dev, &desc, res);
+ ret = qcom_scm_call(dev, &desc, res);
qcom_scm_bw_disable();
disable_clk:
@@ -635,7 +605,8 @@ static int __qcom_scm_pas_init_image(u32 pas_id, dma_addr_t mdata_phys,
return ret;
}
-static int qcom_scm_pas_prep_and_init_image(struct qcom_scm_pas_context *ctx,
+static int qcom_scm_pas_prep_and_init_image(struct device *dev,
+ struct qcom_pas_context *ctx,
const void *metadata, size_t size)
{
struct qcom_scm_res res;
@@ -650,7 +621,7 @@ static int qcom_scm_pas_prep_and_init_image(struct qcom_scm_pas_context *ctx,
memcpy(mdata_buf, metadata, size);
mdata_phys = qcom_tzmem_to_phys(mdata_buf);
- ret = __qcom_scm_pas_init_image(ctx->pas_id, mdata_phys, &res);
+ ret = __qcom_scm_pas_init_image(dev, ctx->pas_id, mdata_phys, &res);
if (ret < 0)
qcom_tzmem_free(mdata_buf);
else
@@ -659,25 +630,9 @@ static int qcom_scm_pas_prep_and_init_image(struct qcom_scm_pas_context *ctx,
return ret ? : res.result[0];
}
-/**
- * qcom_scm_pas_init_image() - Initialize peripheral authentication service
- * state machine for a given peripheral, using the
- * metadata
- * @pas_id: peripheral authentication service id
- * @metadata: pointer to memory containing ELF header, program header table
- * and optional blob of data used for authenticating the metadata
- * and the rest of the firmware
- * @size: size of the metadata
- * @ctx: optional pas context
- *
- * Return: 0 on success.
- *
- * Upon successful return, the PAS metadata context (@ctx) will be used to
- * track the metadata allocation, this needs to be released by invoking
- * qcom_scm_pas_metadata_release() by the caller.
- */
-int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size,
- struct qcom_scm_pas_context *ctx)
+static int __qcom_scm_pas_init_image2(struct device *dev, u32 pas_id,
+ const void *metadata, size_t size,
+ struct qcom_pas_context *ctx)
{
struct qcom_scm_res res;
dma_addr_t mdata_phys;
@@ -685,7 +640,7 @@ int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size,
int ret;
if (ctx && ctx->use_tzmem)
- return qcom_scm_pas_prep_and_init_image(ctx, metadata, size);
+ return qcom_scm_pas_prep_and_init_image(dev, ctx, metadata, size);
/*
* During the scm call memory protection will be enabled for the meta
@@ -699,16 +654,15 @@ int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size,
* If we pass a buffer that is already part of an SHM Bridge to this
* call, it will fail.
*/
- mdata_buf = dma_alloc_coherent(__scm->dev, size, &mdata_phys,
- GFP_KERNEL);
+ mdata_buf = dma_alloc_coherent(dev, size, &mdata_phys, GFP_KERNEL);
if (!mdata_buf)
return -ENOMEM;
memcpy(mdata_buf, metadata, size);
- ret = __qcom_scm_pas_init_image(pas_id, mdata_phys, &res);
+ ret = __qcom_scm_pas_init_image(dev, pas_id, mdata_phys, &res);
if (ret < 0 || !ctx) {
- dma_free_coherent(__scm->dev, size, mdata_buf, mdata_phys);
+ dma_free_coherent(dev, size, mdata_buf, mdata_phys);
} else if (ctx) {
ctx->ptr = mdata_buf;
ctx->phys = mdata_phys;
@@ -717,36 +671,35 @@ int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size,
return ret ? : res.result[0];
}
-EXPORT_SYMBOL_GPL(qcom_scm_pas_init_image);
-/**
- * qcom_scm_pas_metadata_release() - release metadata context
- * @ctx: pas context
- */
-void qcom_scm_pas_metadata_release(struct qcom_scm_pas_context *ctx)
+int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size,
+ struct qcom_scm_pas_context *ctx)
{
- if (!ctx->ptr)
- return;
+ return __qcom_scm_pas_init_image2(__scm->dev, pas_id, metadata, size,
+ (struct qcom_pas_context *)ctx);
+}
+EXPORT_SYMBOL_GPL(qcom_scm_pas_init_image);
+static void __qcom_scm_pas_metadata_release(struct device *dev,
+ struct qcom_pas_context *ctx)
+{
if (ctx->use_tzmem)
qcom_tzmem_free(ctx->ptr);
else
- dma_free_coherent(__scm->dev, ctx->size, ctx->ptr, ctx->phys);
+ dma_free_coherent(dev, ctx->size, ctx->ptr, ctx->phys);
ctx->ptr = NULL;
}
+
+void qcom_scm_pas_metadata_release(struct qcom_scm_pas_context *ctx)
+{
+ __qcom_scm_pas_metadata_release(__scm->dev,
+ (struct qcom_pas_context *)ctx);
+}
EXPORT_SYMBOL_GPL(qcom_scm_pas_metadata_release);
-/**
- * qcom_scm_pas_mem_setup() - Prepare the memory related to a given peripheral
- * for firmware loading
- * @pas_id: peripheral authentication service id
- * @addr: start address of memory area to prepare
- * @size: size of the memory area to prepare
- *
- * Returns 0 on success.
- */
-int qcom_scm_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size)
+static int __qcom_scm_pas_mem_setup(struct device *dev, u32 pas_id,
+ phys_addr_t addr, phys_addr_t size)
{
int ret;
struct qcom_scm_desc desc = {
@@ -768,7 +721,7 @@ int qcom_scm_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size)
if (ret)
goto disable_clk;
- ret = qcom_scm_call(__scm->dev, &desc, &res);
+ ret = qcom_scm_call(dev, &desc, &res);
qcom_scm_bw_disable();
disable_clk:
@@ -776,9 +729,15 @@ int qcom_scm_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size)
return ret ? : res.result[0];
}
+
+int qcom_scm_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size)
+{
+ return __qcom_scm_pas_mem_setup(__scm->dev, pas_id, addr, size);
+}
EXPORT_SYMBOL_GPL(qcom_scm_pas_mem_setup);
-static void *__qcom_scm_pas_get_rsc_table(u32 pas_id, void *input_rt_tzm,
+static void *__qcom_scm_pas_get_rsc_table(struct device *dev, u32 pas_id,
+ void *input_rt_tzm,
size_t input_rt_size,
size_t *output_rt_size)
{
@@ -813,7 +772,7 @@ static void *__qcom_scm_pas_get_rsc_table(u32 pas_id, void *input_rt_tzm,
* with output_rt_tzm buffer with res.result[2] size however, It should not
* be of unresonable size.
*/
- ret = qcom_scm_call(__scm->dev, &desc, &res);
+ ret = qcom_scm_call(dev, &desc, &res);
if (!ret && res.result[2] > SZ_1G) {
ret = -E2BIG;
goto free_output_rt;
@@ -830,51 +789,11 @@ static void *__qcom_scm_pas_get_rsc_table(u32 pas_id, void *input_rt_tzm,
return ret ? ERR_PTR(ret) : output_rt_tzm;
}
-/**
- * qcom_scm_pas_get_rsc_table() - Retrieve the resource table in passed output buffer
- * for a given peripheral.
- *
- * Qualcomm remote processor may rely on both static and dynamic resources for
- * its functionality. Static resources typically refer to memory-mapped addresses
- * required by the subsystem and are often embedded within the firmware binary
- * and dynamic resources, such as shared memory in DDR etc., are determined at
- * runtime during the boot process.
- *
- * On Qualcomm Technologies devices, it's possible that static resources are not
- * embedded in the firmware binary and instead are provided by TrustZone However,
- * dynamic resources are always expected to come from TrustZone. This indicates
- * that for Qualcomm devices, all resources (static and dynamic) will be provided
- * by TrustZone via the SMC call.
- *
- * If the remote processor firmware binary does contain static resources, they
- * should be passed in input_rt. These will be forwarded to TrustZone for
- * authentication. TrustZone will then append the dynamic resources and return
- * the complete resource table in output_rt_tzm.
- *
- * If the remote processor firmware binary does not include a resource table,
- * the caller of this function should set input_rt as NULL and input_rt_size
- * as zero respectively.
- *
- * More about documentation on resource table data structures can be found in
- * include/linux/remoteproc.h
- *
- * @ctx: PAS context
- * @pas_id: peripheral authentication service id
- * @input_rt: resource table buffer which is present in firmware binary
- * @input_rt_size: size of the resource table present in firmware binary
- * @output_rt_size: TrustZone expects caller should pass worst case size for
- * the output_rt_tzm.
- *
- * Return:
- * On success, returns a pointer to the allocated buffer containing the final
- * resource table and output_rt_size will have actual resource table size from
- * TrustZone. The caller is responsible for freeing the buffer. On failure,
- * returns ERR_PTR(-errno).
- */
-struct resource_table *qcom_scm_pas_get_rsc_table(struct qcom_scm_pas_context *ctx,
- void *input_rt,
- size_t input_rt_size,
- size_t *output_rt_size)
+static void *__qcom_scm_pas_get_rsc_table2(struct device *dev,
+ struct qcom_pas_context *ctx,
+ void *input_rt,
+ size_t input_rt_size,
+ size_t *output_rt_size)
{
struct resource_table empty_rsc = {};
size_t size = SZ_16K;
@@ -909,11 +828,12 @@ struct resource_table *qcom_scm_pas_get_rsc_table(struct qcom_scm_pas_context *c
memcpy(input_rt_tzm, input_rt, input_rt_size);
- output_rt_tzm = __qcom_scm_pas_get_rsc_table(ctx->pas_id, input_rt_tzm,
+ output_rt_tzm = __qcom_scm_pas_get_rsc_table(dev, ctx->pas_id,
+ input_rt_tzm,
input_rt_size, &size);
if (PTR_ERR(output_rt_tzm) == -EOVERFLOW)
/* Try again with the size requested by the TZ */
- output_rt_tzm = __qcom_scm_pas_get_rsc_table(ctx->pas_id,
+ output_rt_tzm = __qcom_scm_pas_get_rsc_table(dev, ctx->pas_id,
input_rt_tzm,
input_rt_size,
&size);
@@ -943,16 +863,20 @@ struct resource_table *qcom_scm_pas_get_rsc_table(struct qcom_scm_pas_context *c
return ret ? ERR_PTR(ret) : tbl_ptr;
}
+
+struct resource_table *qcom_scm_pas_get_rsc_table(struct qcom_scm_pas_context *ctx,
+ void *input_rt,
+ size_t input_rt_size,
+ size_t *output_rt_size)
+{
+ return __qcom_scm_pas_get_rsc_table2(__scm->dev,
+ (struct qcom_pas_context *)ctx,
+ input_rt, input_rt_size,
+ output_rt_size);
+}
EXPORT_SYMBOL_GPL(qcom_scm_pas_get_rsc_table);
-/**
- * qcom_scm_pas_auth_and_reset() - Authenticate the given peripheral firmware
- * and reset the remote processor
- * @pas_id: peripheral authentication service id
- *
- * Return 0 on success.
- */
-int qcom_scm_pas_auth_and_reset(u32 pas_id)
+static int __qcom_scm_pas_auth_and_reset(struct device *dev, u32 pas_id)
{
int ret;
struct qcom_scm_desc desc = {
@@ -972,7 +896,7 @@ int qcom_scm_pas_auth_and_reset(u32 pas_id)
if (ret)
goto disable_clk;
- ret = qcom_scm_call(__scm->dev, &desc, &res);
+ ret = qcom_scm_call(dev, &desc, &res);
qcom_scm_bw_disable();
disable_clk:
@@ -980,28 +904,15 @@ int qcom_scm_pas_auth_and_reset(u32 pas_id)
return ret ? : res.result[0];
}
+
+int qcom_scm_pas_auth_and_reset(u32 pas_id)
+{
+ return __qcom_scm_pas_auth_and_reset(__scm->dev, pas_id);
+}
EXPORT_SYMBOL_GPL(qcom_scm_pas_auth_and_reset);
-/**
- * qcom_scm_pas_prepare_and_auth_reset() - Prepare, authenticate, and reset the
- * remote processor
- *
- * @ctx: Context saved during call to qcom_scm_pas_context_init()
- *
- * This function performs the necessary steps to prepare a PAS subsystem,
- * authenticate it using the provided metadata, and initiate a reset sequence.
- *
- * It should be used when Linux is in control setting up the IOMMU hardware
- * for remote subsystem during secure firmware loading processes. The preparation
- * step sets up a shmbridge over the firmware memory before TrustZone accesses the
- * firmware memory region for authentication. The authentication step verifies
- * the integrity and authenticity of the firmware or configuration using secure
- * metadata. Finally, the reset step ensures the subsystem starts in a clean and
- * sane state.
- *
- * Return: 0 on success, negative errno on failure.
- */
-int qcom_scm_pas_prepare_and_auth_reset(struct qcom_scm_pas_context *ctx)
+static int __qcom_scm_pas_prepare_and_auth_reset(struct device *dev,
+ struct qcom_pas_context *ctx)
{
u64 handle;
int ret;
@@ -1012,7 +923,7 @@ int qcom_scm_pas_prepare_and_auth_reset(struct qcom_scm_pas_context *ctx)
* memory region and then invokes a call to TrustZone to authenticate.
*/
if (!ctx->use_tzmem)
- return qcom_scm_pas_auth_and_reset(ctx->pas_id);
+ return __qcom_scm_pas_auth_and_reset(dev, ctx->pas_id);
/*
* When Linux runs @ EL2 Linux must create the shmbridge itself and then
@@ -1022,20 +933,45 @@ int qcom_scm_pas_prepare_and_auth_reset(struct qcom_scm_pas_context *ctx)
if (ret)
return ret;
- ret = qcom_scm_pas_auth_and_reset(ctx->pas_id);
+ ret = __qcom_scm_pas_auth_and_reset(dev, ctx->pas_id);
qcom_tzmem_shm_bridge_delete(handle);
return ret;
}
+
+int qcom_scm_pas_prepare_and_auth_reset(struct qcom_scm_pas_context *ctx)
+{
+ return __qcom_scm_pas_prepare_and_auth_reset(__scm->dev,
+ (struct qcom_pas_context *)ctx);
+}
EXPORT_SYMBOL_GPL(qcom_scm_pas_prepare_and_auth_reset);
-/**
- * qcom_scm_pas_shutdown() - Shut down the remote processor
- * @pas_id: peripheral authentication service id
- *
- * Returns 0 on success.
- */
-int qcom_scm_pas_shutdown(u32 pas_id)
+static int __qcom_scm_pas_set_remote_state(struct device *dev, u32 state,
+ u32 pas_id)
+{
+ struct qcom_scm_desc desc = {
+ .svc = QCOM_SCM_SVC_BOOT,
+ .cmd = QCOM_SCM_BOOT_SET_REMOTE_STATE,
+ .arginfo = QCOM_SCM_ARGS(2),
+ .args[0] = state,
+ .args[1] = pas_id,
+ .owner = ARM_SMCCC_OWNER_SIP,
+ };
+ struct qcom_scm_res res;
+ int ret;
+
+ ret = qcom_scm_call(dev, &desc, &res);
+
+ return ret ? : res.result[0];
+}
+
+int qcom_scm_set_remote_state(u32 state, u32 id)
+{
+ return __qcom_scm_pas_set_remote_state(__scm->dev, state, id);
+}
+EXPORT_SYMBOL_GPL(qcom_scm_set_remote_state);
+
+static int __qcom_scm_pas_shutdown(struct device *dev, u32 pas_id)
{
int ret;
struct qcom_scm_desc desc = {
@@ -1055,7 +991,7 @@ int qcom_scm_pas_shutdown(u32 pas_id)
if (ret)
goto disable_clk;
- ret = qcom_scm_call(__scm->dev, &desc, &res);
+ ret = qcom_scm_call(dev, &desc, &res);
qcom_scm_bw_disable();
disable_clk:
@@ -1063,16 +999,14 @@ int qcom_scm_pas_shutdown(u32 pas_id)
return ret ? : res.result[0];
}
+
+int qcom_scm_pas_shutdown(u32 pas_id)
+{
+ return __qcom_scm_pas_shutdown(__scm->dev, pas_id);
+}
EXPORT_SYMBOL_GPL(qcom_scm_pas_shutdown);
-/**
- * qcom_scm_pas_supported() - Check if the peripheral authentication service is
- * available for the given peripherial
- * @pas_id: peripheral authentication service id
- *
- * Returns true if PAS is supported for this peripheral, otherwise false.
- */
-bool qcom_scm_pas_supported(u32 pas_id)
+static bool __qcom_scm_pas_supported(struct device *dev, u32 pas_id)
{
int ret;
struct qcom_scm_desc desc = {
@@ -1084,16 +1018,49 @@ bool qcom_scm_pas_supported(u32 pas_id)
};
struct qcom_scm_res res;
- if (!__qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_PIL,
+ if (!__qcom_scm_is_call_available(dev, QCOM_SCM_SVC_PIL,
QCOM_SCM_PIL_PAS_IS_SUPPORTED))
return false;
- ret = qcom_scm_call(__scm->dev, &desc, &res);
+ ret = qcom_scm_call(dev, &desc, &res);
return ret ? false : !!res.result[0];
}
+
+bool qcom_scm_pas_supported(u32 pas_id)
+{
+ return __qcom_scm_pas_supported(__scm->dev, pas_id);
+}
EXPORT_SYMBOL_GPL(qcom_scm_pas_supported);
+static struct qcom_pas_ops qcom_pas_ops_scm = {
+ .drv_name = "qcom_scm",
+ .supported = __qcom_scm_pas_supported,
+ .init_image = __qcom_scm_pas_init_image2,
+ .mem_setup = __qcom_scm_pas_mem_setup,
+ .get_rsc_table = __qcom_scm_pas_get_rsc_table2,
+ .auth_and_reset = __qcom_scm_pas_auth_and_reset,
+ .prepare_and_auth_reset = __qcom_scm_pas_prepare_and_auth_reset,
+ .set_remote_state = __qcom_scm_pas_set_remote_state,
+ .shutdown = __qcom_scm_pas_shutdown,
+ .metadata_release = __qcom_scm_pas_metadata_release,
+};
+
+/**
+ * qcom_scm_is_pas_available() - Check if the peripheral authentication service
+ * is available via SCM or not
+ *
+ * Returns true if PAS is available, otherwise false.
+ */
+static bool qcom_scm_is_pas_available(void)
+{
+ if (!__qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_PIL,
+ QCOM_SCM_PIL_PAS_AUTH_AND_RESET))
+ return false;
+
+ return true;
+}
+
static int __qcom_scm_pas_mss_reset(struct device *dev, bool reset)
{
struct qcom_scm_desc desc = {
@@ -2836,6 +2803,11 @@ static int qcom_scm_probe(struct platform_device *pdev)
__get_convention();
+ if (qcom_scm_is_pas_available()) {
+ qcom_pas_ops_scm.dev = scm->dev;
+ qcom_pas_ops_register(&qcom_pas_ops_scm);
+ }
+
/*
* If "download mode" is requested, from this point on warmboot
* will cause the boot stages to enter download mode, unless
@@ -2875,6 +2847,7 @@ static void qcom_scm_shutdown(struct platform_device *pdev)
{
/* Clean shutdown, disable download mode to allow normal restart */
qcom_scm_set_download_mode(QCOM_DLOAD_NODUMP);
+ qcom_pas_ops_unregister();
}
static const struct of_device_id qcom_scm_dt_match[] = {
--
2.51.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox