WARNING: THIS SITE IS A MIRROR OF GITHUB.COM / IT CANNOT LOGIN OR REGISTER ACCOUNTS / THE CONTENTS ARE PROVIDED AS-IS / THIS SITE ASSUMES NO RESPONSIBILITY FOR ANY DISPLAYED CONTENT OR LINKS / IF YOU FOUND SOMETHING MAY NOT GOOD FOR EVERYONE, CONTACT ADMIN AT ilovescratch@foxmail.com
Skip to content

Conversation

@retro98boy
Copy link
Contributor

@retro98boy retro98boy commented Nov 16, 2025

Description

The backported patch from Linux 6.18 allows loading QUP firmware under the Linux system.

LKML url:

https://lore.kernel.org/all/[email protected]/

The commit for each patch in the GitHub Linux repository:

torvalds/linux@9bc7130

torvalds/linux@b44a593

torvalds/linux@d4bf065

torvalds/linux@b645df7

torvalds/linux@99cf351

torvalds/linux@3f17073

By appending .patch to the end of these URLs, you get the patches in this PR. The qup i2c patch had some minor errors under the 6.12 kernel, and I have corrected them.

How Has This Been Tested?

use ./compile.sh BOARD=damo-cockpit8250 BRANCH=current RELEASE=noble to compile the image for my own QCS8250 device.

Before applying the patches:

root@damo-cockpit8250:~# dmesg | grep geni
[    0.142517] geni_se_qup 8c0000.geniqup: Adding to iommu group 1
[    0.143304] geni_i2c 884000.i2c: Bus frequency not specified, default to 100kHz.
[    0.143817] geni_se_qup 9c0000.geniqup: Adding to iommu group 2
[    0.145091] geni_se_qup ac0000.geniqup: Adding to iommu group 3
[    4.336172] geni_spi 988000.spi: Invalid proto 255
[   13.358430] qcom_geni_serial 998000.serial: Invalid FW loaded, proto: 255
[   13.422149] qcom_geni_serial 998000.serial: Invalid FW loaded, proto: 255
[   13.422213] qcom_geni_serial 998000.serial: Invalid FW loaded, proto: 255
[   15.874260] qcom_geni_serial 998000.serial: Invalid FW loaded, proto: 255
[   15.941918] qcom_geni_serial 998000.serial: Invalid FW loaded, proto: 255
[   15.942344] qcom_geni_serial 998000.serial: Invalid FW loaded, proto: 255
[   19.074146] qcom_geni_serial 998000.serial: Invalid FW loaded, proto: 255
[   19.142152] qcom_geni_serial 998000.serial: Invalid FW loaded, proto: 255
[   19.142343] qcom_geni_serial 998000.serial: Invalid FW loaded, proto: 255
[   21.570472] qcom_geni_serial 998000.serial: Invalid FW loaded, proto: 255
[   21.634173] qcom_geni_serial 998000.serial: Invalid FW loaded, proto: 255
[   21.634819] qcom_geni_serial 998000.serial: Invalid FW loaded, proto: 255
root@damo-cockpit8250:~#

After applying the patches:

root@damo-cockpit8250:~# dmesg | grep geni
[    0.142838] geni_se_qup 8c0000.geniqup: Adding to iommu group 1
[    0.143640] geni_i2c 884000.i2c: Bus frequency not specified, default to 100kHz.
[    0.144167] geni_se_qup 9c0000.geniqup: Adding to iommu group 2
[    0.145014] geni_se_qup ac0000.geniqup: Adding to iommu group 3
root@damo-cockpit8250:~#

It is worth noting that the qup firmware needs to be added to the initramfs.

For the mainline armbian/build source code, use ./compile.sh BOARD=xiaomi-elish BRANCH=current RELEASE=noble to ensure the kernel compiles successfully.

Why can't I build a complete xiaomi-elish image? Because the official mkbootimg in Noble seems to have a bug.For my own device, there is a temporary fix.

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • My changes generate no new warnings
  • Any dependent changes have been merged and published in downstream modules

Summary by CodeRabbit

  • New Features

    • I2C, SPI, and UART GENI serial engines now support automatic on-demand firmware loading for improved driver initialization.
  • Documentation

    • Added unified device tree binding schema for QUP peripheral common properties shared across I2C, SPI, and UART drivers.
  • Refactor

    • Standardized internal register macro naming and offset references throughout the GENI SE implementation for improved code consistency.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 16, 2025

Walkthrough

This patch series adds Qualcomm QUP SE firmware loading capability to the GENI driver subsystem. It includes devicetree binding updates, register macro refactoring in the core GENI-SE driver, new firmware loading infrastructure, and integration points in I2C, SPI, and UART drivers to dynamically load protocol-specific firmware at runtime when needed.

Changes

Cohort / File(s) Change Summary
Devicetree Bindings
Documentation/devicetree/bindings/soc/qcom/qcom,se-common-props.yaml, Documentation/devicetree/bindings/i2c/qcom,i2c-geni-qcom.yaml, Documentation/devicetree/bindings/serial/qcom,serial-geni-qcom.yaml, Documentation/devicetree/bindings/spi/qcom,spi-geni-qcom.yaml
Added new common properties schema for QUP peripherals defining qcom,enable-gsi-dma flag; updated I2C, Serial, and SPI binding schemas to reference the new common-props schema via allOf directives for property reusability.
Core GENI-SE Driver
drivers/soc/qcom/qcom-geni-se.c
Register macro refactoring: renamed SE_GENI-related defines (e.g., SE_GENI_INIT_CFG_REVISION, SE_GENI_CGC_CTRL) for consistency; updated hardware version access to use QUPV3_HW_VER_REG; adjusted DMA flag bit names (e.g., DMA_AHB_SLV_CFG_ONDMA_AHB_SLV_CLK_CGC_ON); updated copyright headers.
Firmware Loading Infrastructure
drivers/soc/qcom/qcom-geni-se.c, include/linux/soc/qcom/geni-se.h
Added comprehensive SE firmware loading support: introduced protocol-aware firmware discovery (geni_find_protocol_fw), dynamic transfer mode configuration (geni_configure_xfer_mode), interrupt/resource management, RAM programming, and firmware revision writing; exposed new public API geni_load_se_firmware() and helper structures (se_fw_hdr, protocol name mapping).
Protocol-Specific Driver Integration
drivers/i2c/busses/i2c-qcom-geni.c, drivers/spi/spi-geni-qcom.c, drivers/tty/serial/qcom_geni_serial.c
Added runtime firmware loading paths in I2C probe, SPI initialization, and UART setup functions; when protocol is marked invalid (GENI_SE_INVALID_PROTO), drivers invoke geni_load_se_firmware() with protocol-specific parameter; includes error handling with logging and resource cleanup on failure.

Sequence Diagram(s)

sequenceDiagram
    participant Driver as I2C/SPI/UART Driver
    participant Core as GENI-SE Core
    participant FW as Firmware Loader
    participant HW as Hardware (GENI SE)
    
    Driver->>Core: geni_load_se_firmware(se, protocol)
    Core->>FW: Request protocol-specific FW
    FW-->>Core: Return FW data
    Core->>Core: geni_find_protocol_fw (validate header, magic, version)
    Core->>Core: geni_configure_xfer_mode (set FIFO/GSI DMA)
    Core->>Core: geni_enable_interrupts (setup IRQs)
    Core->>HW: Program configuration registers
    Core->>HW: Write firmware to GENI SE RAM
    Core->>HW: geni_write_fw_revision (update firmware metadata)
    Core-->>Driver: Return success/error
    
    alt Success
        Driver->>Driver: Continue normal driver setup
    else Failure
        Driver->>Driver: Log error, cleanup resources
        Driver-->>Driver: Return error to probe/init
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Patch 0045 introduces substantial new firmware loading infrastructure with protocol validation, register programming, and memory management logic requiring careful verification of hardware interactions.
  • Register macro refactoring (Patch 0044) has cascading effects and must be verified for correctness across multiple usage sites.
  • Integration points (Patches 0046–0048) require verification that error paths properly clean up resources and that firmware loading is invoked at appropriate driver lifecycle points.
  • Devicetree binding changes (Patch 0043) need validation of schema correctness and proper schema referencing.

Areas requiring extra attention:

  • Firmware header validation and boundary checking logic in geni_find_protocol_fw
  • RAM programming and CGC/clock state management during firmware load
  • Error handling and resource cleanup paths in all protocol drivers
  • Register macro rename completeness and consistency across the codebase

Suggested reviewers

  • amazingfate
  • paolosabatino
  • rpardini
  • prahal
  • pyavitz

Poem

🐰 A firmware tale of GENI SE,
Where protocols dance wild and free,
I2C, SPI, and UART aligned,
With bindings bound and macros refined,
The QUP loads its code with glee!

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: adding support to load QUP SE Firmware via the Linux subsystem, which aligns with all six patches included in the PR.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions bot added size/large PR with 250 lines or more 11 Milestone: Fourth quarter release Needs review Seeking for review Hardware Hardware related like kernel, U-Boot, ... Patches Patches related to kernel, U-Boot, ... labels Nov 16, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between d30f8d0 and 8cb72aa.

📒 Files selected for processing (6)
  • patch/kernel/archive/sm8250-6.12/0043-dt-bindings-qcom-se-common-Add-QUP-Peripheral-specif.patch (1 hunks)
  • patch/kernel/archive/sm8250-6.12/0044-soc-qcom-geni-se-Cleanup-register-defines-and-update.patch (1 hunks)
  • patch/kernel/archive/sm8250-6.12/0045-soc-qcom-geni-se-Add-support-to-load-QUP-SE-Firmware.patch (1 hunks)
  • patch/kernel/archive/sm8250-6.12/0046-i2c-qcom-geni-Load-i2c-qup-Firmware-from-linux-side.patch (1 hunks)
  • patch/kernel/archive/sm8250-6.12/0047-spi-geni-qcom-Load-spi-qup-Firmware-from-linux-side.patch (1 hunks)
  • patch/kernel/archive/sm8250-6.12/0048-serial-qcom-geni-Load-UART-qup-Firmware-from-linux-s.patch (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: rpardini
Repo: armbian/build PR: 8044
File: patch/u-boot/v2025.04/cmd-fileenv-read-string-from-file-into-env.patch:73-75
Timestamp: 2025-03-31T22:20:41.849Z
Learning: When porting patches between U-Boot versions (like from 2025.01 to 2025.04), rpardini prefers to maintain patches as-is rather than introducing refactoring changes, even when potential improvements are identified. This approach prioritizes consistency and reduces the risk of introducing new issues.
Learnt from: EvilOlaf
Repo: armbian/build PR: 8428
File: config/boards/lckfb-taishanpi.csc:5-9
Timestamp: 2025-07-25T03:51:50.830Z
Learning: When reviewing PRs in the Armbian build system, U-Boot defconfig files and patches may be added as part of the PR changes but might not be visible in the current repository clone state during review. It's important to check the actual PR file changes directly via GitHub or the PR API to get the complete picture of what files are being added or modified.
Learnt from: rpardini
Repo: armbian/build PR: 8879
File: config/sources/families/uefi-x86.conf:0-0
Timestamp: 2025-11-06T15:36:04.682Z
Learning: As of PR #8879, the uefi-x86 family in the Armbian build system now includes kernel patches for the first time. The current and edge branches for uefi-x86 are specifically configured for Apple T2-based x86 machines, including T2-specific patches from the linux-t2 project and custom kernel configuration options for Apple hardware drivers.
Learnt from: rpardini
Repo: armbian/build PR: 8044
File: patch/u-boot/v2025.04/cmd-fileenv-read-string-from-file-into-env.patch:76-86
Timestamp: 2025-03-31T22:20:48.475Z
Learning: For the Armbian build project, maintaining consistency with existing patches across U-Boot versions (such as between 2025.01 and 2025.04) is prioritized over refactoring individual patches for code improvements.
Learnt from: EvilOlaf
Repo: armbian/build PR: 8428
File: config/boards/lckfb-taishanpi.csc:5-9
Timestamp: 2025-07-25T03:51:50.830Z
Learning: When reviewing PRs in the Armbian build system, U-Boot defconfig files and patches may be added as part of the PR changes but might not be visible in the current repository clone state during review. It's important to check the actual PR file changes directly via GitHub API (https://api.github.com/repos/armbian/build/pulls/{pr_number}/files) to get the complete picture of what files are being added or modified, especially for U-Boot patches that will be applied during the build process.
📚 Learning: 2025-03-31T22:20:41.849Z
Learnt from: rpardini
Repo: armbian/build PR: 8044
File: patch/u-boot/v2025.04/cmd-fileenv-read-string-from-file-into-env.patch:73-75
Timestamp: 2025-03-31T22:20:41.849Z
Learning: When porting patches between U-Boot versions (like from 2025.01 to 2025.04), rpardini prefers to maintain patches as-is rather than introducing refactoring changes, even when potential improvements are identified. This approach prioritizes consistency and reduces the risk of introducing new issues.

Applied to files:

  • patch/kernel/archive/sm8250-6.12/0047-spi-geni-qcom-Load-spi-qup-Firmware-from-linux-side.patch
  • patch/kernel/archive/sm8250-6.12/0044-soc-qcom-geni-se-Cleanup-register-defines-and-update.patch
  • patch/kernel/archive/sm8250-6.12/0048-serial-qcom-geni-Load-UART-qup-Firmware-from-linux-s.patch
🔇 Additional comments (8)
patch/kernel/archive/sm8250-6.12/0043-dt-bindings-qcom-se-common-Add-QUP-Peripheral-specif.patch (1)

30-95: QUP SE common DT schema and references look consistent and safe to backport

The new qcom,se-common-props.yaml schema and the added allOf references in the I2C, SPI, and serial GENI bindings are coherent: the file path matches the $ref URI, qcom,enable-gsi-dma is correctly modeled as a flag, and additionalProperties: true preserves compatibility with existing device trees. This is a straightforward, upstream‑style binding addition with no obvious 6.12 integration pitfalls.

patch/kernel/archive/sm8250-6.12/0044-soc-qcom-geni-se-Cleanup-register-defines-and-update.patch (1)

23-103: GENI SE macro renames are mechanical and align with later firmware work

The macro cleanup (QUP_HW_VER_REGQUPV3_HW_VER_REG, GENI_*SE_GENI_*, DMA_AHB_SLV_CFG_ONDMA_AHB_SLV_CLK_CGC_ON) is purely mechanical with identical offsets/bit positions, and all in‑file uses are updated (geni_se_get_qup_hw_version, geni_se_io_init). The removed macros were unused in this file, so they should not affect 6.12 builds. This matches what upstream did and looks safe as a base for the subsequent QUP SE firmware‑loading support.

patch/kernel/archive/sm8250-6.12/0047-spi-geni-qcom-Load-spi-qup-Firmware-from-linux-side.patch (1)

23-33: SPI GENI firmware-load path is consistent; just ensure series ordering

The new GENI_SE_INVALID_PROTO branch in spi_geni_init() correctly mirrors the I2C/UART pattern: on proto 255 it attempts geni_load_se_firmware(se, GENI_SE_SPI) and bails out via the existing out_pm cleanup on failure, while leaving behaviour for valid SPI and other invalid protos unchanged. This looks right for fixing the “Invalid FW loaded, proto: 255” case on SPI.

The only integration concern is series ordering: this file assumes that the patch adding GENI_SE_INVALID_PROTO, GENI_SE_SPI, and geni_load_se_firmware() (0045) is applied earlier in the sm8250‑6.12 patch stack so the symbols resolve.

patch/kernel/archive/sm8250-6.12/0046-i2c-qcom-geni-Load-i2c-qup-Firmware-from-linux-side.patch (1)

23-40: I2C GENI firmware loading and error paths look correct for probe-time use

The new GENI_SE_INVALID_PROTO handling in geni_i2c_probe() is wired cleanly: on invalid proto it attempts geni_load_se_firmware(&gi2c->se, GENI_SE_I2C) and, if that fails, logs via dev_err_probe(), turns off SE resources, disables core_clk, and returns the original error (including -EPROBE_DEFER). The existing non‑I2C proto path is preserved as an else if, with the same cleanup and -ENXIO as before. This matches the intended behaviour and should fix the “Invalid FW loaded” case without introducing leaks.

As with SPI, just ensure the common GENI SE firmware support patch providing GENI_SE_INVALID_PROTO and geni_load_se_firmware() is applied earlier in the sm8250‑6.12 patch sequence.

patch/kernel/archive/sm8250-6.12/0048-serial-qcom-geni-Load-UART-qup-Firmware-from-linux-s.patch (1)

23-36: UART GENI firmware-load handling is minimal and matches SPI/I2C patterns

The updated qcom_geni_serial_port_setup() now sensibly tries geni_load_se_firmware(&port->se, GENI_SE_UART) when geni_se_read_proto() returns GENI_SE_INVALID_PROTO, only falling back to the existing “Invalid FW loaded” -ENXIO path for other non‑UART proto values. Error handling on firmware load failure is straightforward (dev_err + return ret), which is appropriate here. This should eliminate the repeated “proto: 255” messages while keeping behaviour unchanged in all other cases.

As with the other drivers, this assumes the GENI SE firmware API and enum extensions are already present from the earlier patch in the series.

patch/kernel/archive/sm8250-6.12/0045-soc-qcom-geni-se-Add-support-to-load-QUP-SE-Firmware.patch (3)

44-103: Macro and header-format definitions look consistent with upstream GENI/QUP usage

The added protocol_name[], struct se_fw_hdr, MI_PBT* flags, FW/CLOCK/CGC register offsets, and geni_{set,clr}bits32() helpers are internally consistent and align with how they are used later in this patch. No issues spotted here, assuming the earlier patch in this series provides FW_REV_PROTOCOL_MSK and related register field definitions.

Please confirm that the full patch stack (especially the prior qcom-geni-se macro cleanup patch) is applied unmodified so that all new masks (e.g. FW_REV_PROTOCOL_MSK) are available and the driver still builds cleanly on 6.12.

Also applies to: 146-163


295-351: Firmware load sequence, clocks, and resource handling look correct

The transfer-mode configuration (geni_configure_xfer_mode()), interrupt enables (geni_enable_interrupts()), FW revision write, and the overall geni_load_se_fw() sequence (ICC set/enable, resources on, RAM programming, and cleanup via the out_resources_off/out_icc_disable labels) are coherent and appear balanced on both success and failure paths. No additional functional issues stand out here beyond the protocol comparison bug already noted.

Given this is a backport, please keep this function in sync with the upstream 6.18 version and confirm that, after fixing the serial_protocol comparison, it still behaves identically (or intentionally differs only where 6.12 requires it).

Also applies to: 361-494


508-557: Public firmware-loading API and enum extension are sound

geni_load_se_firmware() cleanly wraps property lookup, transfer-mode selection, firmware request, and delegation into geni_load_se_fw(), returning -EPROBE_DEFER when firmware is not yet present. The bounds check against ARRAY_SIZE(protocol_name) ensures safe indexing and prevents GENI_SE_INVALID_PROTO (255) from being used here, while the new enum value provides a clear sentinel for callers.

The new declaration in include/linux/soc/qcom/geni-se.h and the exported symbol match the implementation and intended use in the follow-on I2C/SPI/UART patches.

Please double-check that all new call sites in patches 0046–0048 only ever pass concrete protocol values (SPI/UART/I2C/I3C/SPI_SLAVE) and never GENI_SE_INVALID_PROTO, to keep the bounds and logging assumptions valid.

Also applies to: 574-587

Comment on lines +199 to +283
+static struct se_fw_hdr *geni_find_protocol_fw(struct device *dev, const struct firmware *fw,
+ enum geni_se_protocol_type protocol)
+{
+ const struct elf32_hdr *ehdr;
+ const struct elf32_phdr *phdrs;
+ const struct elf32_phdr *phdr;
+ struct se_fw_hdr *sefw;
+ u32 fw_end, cfg_idx_end, cfg_val_end;
+ u16 fw_size;
+ int i;
+
+ if (!fw || fw->size < sizeof(struct elf32_hdr))
+ return NULL;
+
+ ehdr = (const struct elf32_hdr *)fw->data;
+ phdrs = (const struct elf32_phdr *)(fw->data + ehdr->e_phoff);
+
+ /*
+ * The firmware is expected to have at least two program headers (segments).
+ * One for metadata and the other for the actual protocol-specific firmware.
+ */
+ if (ehdr->e_phnum < 2) {
+ dev_err(dev, "Invalid firmware: less than 2 program headers\n");
+ return NULL;
+ }
+
+ for (i = 0; i < ehdr->e_phnum; i++) {
+ phdr = &phdrs[i];
+
+ if (fw->size < phdr->p_offset + phdr->p_filesz) {
+ dev_err(dev, "Firmware size (%zu) < expected offset (%u) + size (%u)\n",
+ fw->size, phdr->p_offset, phdr->p_filesz);
+ return NULL;
+ }
+
+ if (phdr->p_type != PT_LOAD || !phdr->p_memsz)
+ continue;
+
+ if (MI_PBT_PAGE_MODE_VALUE(phdr->p_flags) != MI_PBT_NON_PAGED_SEGMENT ||
+ MI_PBT_SEGMENT_TYPE_VALUE(phdr->p_flags) == MI_PBT_HASH_SEGMENT ||
+ MI_PBT_ACCESS_TYPE_VALUE(phdr->p_flags) == MI_PBT_NOTUSED_SEGMENT ||
+ MI_PBT_ACCESS_TYPE_VALUE(phdr->p_flags) == MI_PBT_SHARED_SEGMENT)
+ continue;
+
+ if (phdr->p_filesz < sizeof(struct se_fw_hdr))
+ continue;
+
+ sefw = (struct se_fw_hdr *)(fw->data + phdr->p_offset);
+ fw_size = le16_to_cpu(sefw->fw_size_in_items);
+ fw_end = le16_to_cpu(sefw->fw_offset) + fw_size * sizeof(u32);
+ cfg_idx_end = le16_to_cpu(sefw->cfg_idx_offset) +
+ le16_to_cpu(sefw->cfg_size_in_items) * sizeof(u8);
+ cfg_val_end = le16_to_cpu(sefw->cfg_val_offset) +
+ le16_to_cpu(sefw->cfg_size_in_items) * sizeof(u32);
+
+ if (le32_to_cpu(sefw->magic) != SE_MAGIC_NUM || le32_to_cpu(sefw->version) != 1)
+ continue;
+
+ if (le32_to_cpu(sefw->serial_protocol) != protocol)
+ continue;
+
+ if (fw_size % 2 != 0) {
+ fw_size++;
+ sefw->fw_size_in_items = cpu_to_le16(fw_size);
+ }
+
+ if (fw_size >= MAX_GENI_CFG_RAMn_CNT) {
+ dev_err(dev,
+ "Firmware size (%u) exceeds max allowed RAMn count (%u)\n",
+ fw_size, MAX_GENI_CFG_RAMn_CNT);
+ continue;
+ }
+
+ if (fw_end > phdr->p_filesz || cfg_idx_end > phdr->p_filesz ||
+ cfg_val_end > phdr->p_filesz) {
+ dev_err(dev, "Truncated or corrupt SE FW segment found at index %d\n", i);
+ continue;
+ }
+
+ return sefw;
+ }
+
+ dev_err(dev, "Failed to get %s protocol firmware\n", protocol_name[protocol]);
+ return NULL;
+}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Wrong endianness helper on serial_protocol breaks firmware selection

In geni_find_protocol_fw(), serial_protocol is declared as __le16 in struct se_fw_hdr, but the comparison uses le32_to_cpu(sefw->serial_protocol). This:

  • Interprets a 16-bit field as 32-bit, reading into the next field (fw_version).
  • Makes it effectively impossible for the value to equal the requested enum geni_se_protocol_type, so the function will never find a matching firmware header and will always fall through to the “Failed to get … protocol firmware” path.

This is a functional blocker for firmware loading.

Apply this minimal fix (matches the field width and other call sites):

-        if (le32_to_cpu(sefw->serial_protocol) != protocol)
+        if (le16_to_cpu(sefw->serial_protocol) != protocol)
             continue;

Please rebuild and re-test QUP SE firmware loading after this change.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
+static struct se_fw_hdr *geni_find_protocol_fw(struct device *dev, const struct firmware *fw,
+ enum geni_se_protocol_type protocol)
+{
+ const struct elf32_hdr *ehdr;
+ const struct elf32_phdr *phdrs;
+ const struct elf32_phdr *phdr;
+ struct se_fw_hdr *sefw;
+ u32 fw_end, cfg_idx_end, cfg_val_end;
+ u16 fw_size;
+ int i;
+
+ if (!fw || fw->size < sizeof(struct elf32_hdr))
+ return NULL;
+
+ ehdr = (const struct elf32_hdr *)fw->data;
+ phdrs = (const struct elf32_phdr *)(fw->data + ehdr->e_phoff);
+
+ /*
+ * The firmware is expected to have at least two program headers (segments).
+ * One for metadata and the other for the actual protocol-specific firmware.
+ */
+ if (ehdr->e_phnum < 2) {
+ dev_err(dev, "Invalid firmware: less than 2 program headers\n");
+ return NULL;
+ }
+
+ for (i = 0; i < ehdr->e_phnum; i++) {
+ phdr = &phdrs[i];
+
+ if (fw->size < phdr->p_offset + phdr->p_filesz) {
+ dev_err(dev, "Firmware size (%zu) < expected offset (%u) + size (%u)\n",
+ fw->size, phdr->p_offset, phdr->p_filesz);
+ return NULL;
+ }
+
+ if (phdr->p_type != PT_LOAD || !phdr->p_memsz)
+ continue;
+
+ if (MI_PBT_PAGE_MODE_VALUE(phdr->p_flags) != MI_PBT_NON_PAGED_SEGMENT ||
+ MI_PBT_SEGMENT_TYPE_VALUE(phdr->p_flags) == MI_PBT_HASH_SEGMENT ||
+ MI_PBT_ACCESS_TYPE_VALUE(phdr->p_flags) == MI_PBT_NOTUSED_SEGMENT ||
+ MI_PBT_ACCESS_TYPE_VALUE(phdr->p_flags) == MI_PBT_SHARED_SEGMENT)
+ continue;
+
+ if (phdr->p_filesz < sizeof(struct se_fw_hdr))
+ continue;
+
+ sefw = (struct se_fw_hdr *)(fw->data + phdr->p_offset);
+ fw_size = le16_to_cpu(sefw->fw_size_in_items);
+ fw_end = le16_to_cpu(sefw->fw_offset) + fw_size * sizeof(u32);
+ cfg_idx_end = le16_to_cpu(sefw->cfg_idx_offset) +
+ le16_to_cpu(sefw->cfg_size_in_items) * sizeof(u8);
+ cfg_val_end = le16_to_cpu(sefw->cfg_val_offset) +
+ le16_to_cpu(sefw->cfg_size_in_items) * sizeof(u32);
+
+ if (le32_to_cpu(sefw->magic) != SE_MAGIC_NUM || le32_to_cpu(sefw->version) != 1)
+ continue;
+
+ if (le32_to_cpu(sefw->serial_protocol) != protocol)
+ continue;
+
+ if (fw_size % 2 != 0) {
+ fw_size++;
+ sefw->fw_size_in_items = cpu_to_le16(fw_size);
+ }
+
+ if (fw_size >= MAX_GENI_CFG_RAMn_CNT) {
+ dev_err(dev,
+ "Firmware size (%u) exceeds max allowed RAMn count (%u)\n",
+ fw_size, MAX_GENI_CFG_RAMn_CNT);
+ continue;
+ }
+
+ if (fw_end > phdr->p_filesz || cfg_idx_end > phdr->p_filesz ||
+ cfg_val_end > phdr->p_filesz) {
+ dev_err(dev, "Truncated or corrupt SE FW segment found at index %d\n", i);
+ continue;
+ }
+
+ return sefw;
+ }
+
+ dev_err(dev, "Failed to get %s protocol firmware\n", protocol_name[protocol]);
+ return NULL;
+}
static struct se_fw_hdr *geni_find_protocol_fw(struct device *dev, const struct firmware *fw,
enum geni_se_protocol_type protocol)
{
const struct elf32_hdr *ehdr;
const struct elf32_phdr *phdrs;
const struct elf32_phdr *phdr;
struct se_fw_hdr *sefw;
u32 fw_end, cfg_idx_end, cfg_val_end;
u16 fw_size;
int i;
if (!fw || fw->size < sizeof(struct elf32_hdr))
return NULL;
ehdr = (const struct elf32_hdr *)fw->data;
phdrs = (const struct elf32_phdr *)(fw->data + ehdr->e_phoff);
/*
* The firmware is expected to have at least two program headers (segments).
* One for metadata and the other for the actual protocol-specific firmware.
*/
if (ehdr->e_phnum < 2) {
dev_err(dev, "Invalid firmware: less than 2 program headers\n");
return NULL;
}
for (i = 0; i < ehdr->e_phnum; i++) {
phdr = &phdrs[i];
if (fw->size < phdr->p_offset + phdr->p_filesz) {
dev_err(dev, "Firmware size (%zu) < expected offset (%u) + size (%u)\n",
fw->size, phdr->p_offset, phdr->p_filesz);
return NULL;
}
if (phdr->p_type != PT_LOAD || !phdr->p_memsz)
continue;
if (MI_PBT_PAGE_MODE_VALUE(phdr->p_flags) != MI_PBT_NON_PAGED_SEGMENT ||
MI_PBT_SEGMENT_TYPE_VALUE(phdr->p_flags) == MI_PBT_HASH_SEGMENT ||
MI_PBT_ACCESS_TYPE_VALUE(phdr->p_flags) == MI_PBT_NOTUSED_SEGMENT ||
MI_PBT_ACCESS_TYPE_VALUE(phdr->p_flags) == MI_PBT_SHARED_SEGMENT)
continue;
if (phdr->p_filesz < sizeof(struct se_fw_hdr))
continue;
sefw = (struct se_fw_hdr *)(fw->data + phdr->p_offset);
fw_size = le16_to_cpu(sefw->fw_size_in_items);
fw_end = le16_to_cpu(sefw->fw_offset) + fw_size * sizeof(u32);
cfg_idx_end = le16_to_cpu(sefw->cfg_idx_offset) +
le16_to_cpu(sefw->cfg_size_in_items) * sizeof(u8);
cfg_val_end = le16_to_cpu(sefw->cfg_val_offset) +
le16_to_cpu(sefw->cfg_size_in_items) * sizeof(u32);
if (le32_to_cpu(sefw->magic) != SE_MAGIC_NUM || le32_to_cpu(sefw->version) != 1)
continue;
if (le16_to_cpu(sefw->serial_protocol) != protocol)
continue;
if (fw_size % 2 != 0) {
fw_size++;
sefw->fw_size_in_items = cpu_to_le16(fw_size);
}
if (fw_size >= MAX_GENI_CFG_RAMn_CNT) {
dev_err(dev,
"Firmware size (%u) exceeds max allowed RAMn count (%u)\n",
fw_size, MAX_GENI_CFG_RAMn_CNT);
continue;
}
if (fw_end > phdr->p_filesz || cfg_idx_end > phdr->p_filesz ||
cfg_val_end > phdr->p_filesz) {
dev_err(dev, "Truncated or corrupt SE FW segment found at index %d\n", i);
continue;
}
return sefw;
}
dev_err(dev, "Failed to get %s protocol firmware\n", protocol_name[protocol]);
return NULL;
}
🤖 Prompt for AI Agents
In
patch/kernel/archive/sm8250-6.12/0045-soc-qcom-geni-se-Add-support-to-load-QUP-SE-Firmware.patch
around lines 199-283, the code incorrectly uses
le32_to_cpu(sefw->serial_protocol) to compare a field declared as __le16,
causing reads to overflow into the next field and preventing any match; change
the comparison to use le16_to_cpu(sefw->serial_protocol) (matching other call
sites and the field width) so the 16-bit serial_protocol is interpreted
correctly and firmware selection can succeed.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (3)
patch/kernel/archive/sm8250-6.12/0046-i2c-qcom-geni-Load-i2c-qup-Firmware-from-linux-side.patch (1)

23-40: I2C GENI firmware-load branch is correct; ensure firmware is packaged appropriately

The new proto == GENI_SE_INVALID_PROTO branch in geni_i2c_probe() correctly tries geni_load_se_firmware(&gi2c->se, GENI_SE_I2C) and, on failure, uses dev_err_probe() and tears down the SE resources and core clock before returning, mirroring the existing invalid-proto error path preserved in the else if (proto != GENI_SE_I2C) block. This is logically sound and consistent with the SPI/UART changes.

From an Armbian integration standpoint, make sure the corresponding QUP SE firmware blobs are actually installed under /lib/firmware/updates/ and included in the initramfs for sm8250/QCS8250 targets; otherwise these new paths will still fail at probe despite the code changes. Using /lib/firmware/updates/ avoids conflicts with the firmware package while remaining first in the kernel firmware search order. Based on learnings.

patch/kernel/archive/sm8250-6.12/0045-soc-qcom-geni-se-Add-support-to-load-QUP-SE-Firmware.patch (2)

44-45: Keep protocol_name[] in lockstep with enum geni_se_protocol_type

The protocol_name[] table assumes that all valid protocol enum values are in the 0..GENI_SE_SPI_SLAVE range, with GENI_SE_INVALID_PROTO as an out-of-range sentinel. That’s a reasonable design, and geni_load_se_firmware() explicitly guards against protocol >= ARRAY_SIZE(protocol_name), so today it’s safe.

To make this future-proof, consider adding a small compile-time check tying the array size to the last “real” protocol enumerator so new protocols can’t be added without updating this table, e.g.:

 static const char * const protocol_name[] = { "None", "SPI", "UART", "I2C", "I3C", "SPI SLAVE" };
+
+/* Ensure protocol_name[] covers all valid protocol enums (excluding INVALID). */
+static_assert(ARRAY_SIZE(protocol_name) == GENI_SE_SPI_SLAVE + 1);

This keeps the mapping robust if more GENI_SE_* values are introduced later, without changing current behavior.

Based on learnings

Also applies to: 573-578


508-555: Firmware load entry point is well-structured; consider minor property handling tweaks

geni_load_se_firmware() is a clean public entry:

  • Validates protocol against protocol_name[] before indexing it.
  • Retrieves firmware-name from the wrapper device, where it’s naturally specified in DT.
  • Selects GPI DMA vs FIFO based on qcom,enable-gsi-dma, but correctly forces FIFO for UART where GSI is unsupported.
  • Maps request_firmware()’s -ENOENT to -EPROBE_DEFER, which is appropriate for Armbian’s “firmware must be in initramfs” expectation.
  • Logs clear error paths and emits a useful dev_dbg() on success.

Two optional refinements you might consider (not blockers):

  • Use device_property_read_bool() instead of of_property_read_bool() for "qcom,enable-gsi-dma" to also support possible ACPI-based platforms.
  • Add a newline to the "Invalid geni-se protocol: %d" dev_err format string for consistent log formatting.

These can be deferred; the current behavior is correct for the DT-based QUP use case you’re targeting.

Based on learnings

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between d30f8d0 and 8cb72aa.

📒 Files selected for processing (6)
  • patch/kernel/archive/sm8250-6.12/0043-dt-bindings-qcom-se-common-Add-QUP-Peripheral-specif.patch (1 hunks)
  • patch/kernel/archive/sm8250-6.12/0044-soc-qcom-geni-se-Cleanup-register-defines-and-update.patch (1 hunks)
  • patch/kernel/archive/sm8250-6.12/0045-soc-qcom-geni-se-Add-support-to-load-QUP-SE-Firmware.patch (1 hunks)
  • patch/kernel/archive/sm8250-6.12/0046-i2c-qcom-geni-Load-i2c-qup-Firmware-from-linux-side.patch (1 hunks)
  • patch/kernel/archive/sm8250-6.12/0047-spi-geni-qcom-Load-spi-qup-Firmware-from-linux-side.patch (1 hunks)
  • patch/kernel/archive/sm8250-6.12/0048-serial-qcom-geni-Load-UART-qup-Firmware-from-linux-s.patch (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: EvilOlaf
Repo: armbian/build PR: 8428
File: config/boards/lckfb-taishanpi.csc:5-9
Timestamp: 2025-07-25T03:51:50.830Z
Learning: When reviewing PRs in the Armbian build system, U-Boot defconfig files and patches may be added as part of the PR changes but might not be visible in the current repository clone state during review. It's important to check the actual PR file changes directly via GitHub or the PR API to get the complete picture of what files are being added or modified.
Learnt from: EvilOlaf
Repo: armbian/build PR: 8428
File: config/boards/lckfb-taishanpi.csc:5-9
Timestamp: 2025-07-25T03:51:50.830Z
Learning: When reviewing PRs in the Armbian build system, U-Boot defconfig files and patches may be added as part of the PR changes but might not be visible in the current repository clone state during review. It's important to check the actual PR file changes directly via GitHub API (https://api.github.com/repos/armbian/build/pulls/{pr_number}/files) to get the complete picture of what files are being added or modified, especially for U-Boot patches that will be applied during the build process.
Learnt from: rpardini
Repo: armbian/build PR: 8879
File: config/sources/families/uefi-x86.conf:0-0
Timestamp: 2025-11-06T15:36:04.682Z
Learning: As of PR #8879, the uefi-x86 family in the Armbian build system now includes kernel patches for the first time. The current and edge branches for uefi-x86 are specifically configured for Apple T2-based x86 machines, including T2-specific patches from the linux-t2 project and custom kernel configuration options for Apple hardware drivers.
Learnt from: rpardini
Repo: armbian/build PR: 8044
File: patch/u-boot/v2025.04/cmd-fileenv-read-string-from-file-into-env.patch:76-86
Timestamp: 2025-03-31T22:20:48.475Z
Learning: For the Armbian build project, maintaining consistency with existing patches across U-Boot versions (such as between 2025.01 and 2025.04) is prioritized over refactoring individual patches for code improvements.
Learnt from: rpardini
Repo: armbian/build PR: 8044
File: patch/u-boot/v2025.04/cmd-fileenv-read-string-from-file-into-env.patch:73-75
Timestamp: 2025-03-31T22:20:41.849Z
Learning: When porting patches between U-Boot versions (like from 2025.01 to 2025.04), rpardini prefers to maintain patches as-is rather than introducing refactoring changes, even when potential improvements are identified. This approach prioritizes consistency and reduces the risk of introducing new issues.
Learnt from: tabrisnet
Repo: armbian/build PR: 8661
File: lib/functions/compilation/armbian-kernel.sh:194-199
Timestamp: 2025-09-25T18:37:00.330Z
Learning: In PR armbian/build#8661, line 235 of lib/functions/compilation/armbian-kernel.sh already contains the corrected comment "BPF link support for netfilter hooks" for NETFILTER_BPF_LINK, not the misleading "BPF_SYSCALL" comment that was flagged during review.
Learnt from: tabrisnet
Repo: armbian/build PR: 8661
File: lib/functions/compilation/armbian-kernel.sh:194-199
Timestamp: 2025-09-25T18:37:00.330Z
Learning: In PR armbian/build#8661, line 235 of lib/functions/compilation/armbian-kernel.sh already contains the corrected comment "BPF link support for netfilter hooks" for NETFILTER_BPF_LINK, not the misleading "BPF_SYSCALL" comment that was flagged during review.
Learnt from: pyavitz
Repo: armbian/build PR: 8455
File: config/sources/families/sun50iw1.conf:19-24
Timestamp: 2025-08-03T15:21:20.148Z
Learning: In the Armbian build system, when copying firmware files during family_tweaks_s(), use /lib/firmware/updates/ instead of /lib/firmware/ to avoid conflicts with the Armbian firmware package. The /lib/firmware/updates directory takes precedence in Linux firmware loading hierarchy and is the proper location for user-installed firmware files.
Learnt from: pyavitz
Repo: armbian/build PR: 8481
File: config/kernel/linux-spacemit-edge.config:492-494
Timestamp: 2025-08-11T12:39:22.861Z
Learning: The SpacemiT platform requires esos.elf firmware to be embedded in the kernel image for boot. The Armbian build system handles this by copying esos.elf from $SRC/packages/blobs/riscv64/spacemit/ to ${kernel_work_dir}/firmware/ via the custom_kernel_config__spacemit_k1_firmware() function in config/sources/families/spacemit.conf, ensuring CONFIG_EXTRA_FIRMWARE="esos.elf" can successfully embed it during kernel build.
📚 Learning: 2025-03-31T22:20:41.849Z
Learnt from: rpardini
Repo: armbian/build PR: 8044
File: patch/u-boot/v2025.04/cmd-fileenv-read-string-from-file-into-env.patch:73-75
Timestamp: 2025-03-31T22:20:41.849Z
Learning: When porting patches between U-Boot versions (like from 2025.01 to 2025.04), rpardini prefers to maintain patches as-is rather than introducing refactoring changes, even when potential improvements are identified. This approach prioritizes consistency and reduces the risk of introducing new issues.

Applied to files:

  • patch/kernel/archive/sm8250-6.12/0048-serial-qcom-geni-Load-UART-qup-Firmware-from-linux-s.patch
  • patch/kernel/archive/sm8250-6.12/0044-soc-qcom-geni-se-Cleanup-register-defines-and-update.patch
🔇 Additional comments (7)
patch/kernel/archive/sm8250-6.12/0043-dt-bindings-qcom-se-common-Add-QUP-Peripheral-specif.patch (2)

36-38: Hooking common QUP schema into I2C/SPI/serial bindings looks correct

Adding /schemas/soc/qcom/qcom,se-common-props.yaml# to the allOf blocks for qcom,i2c-geni-qcom.yaml, qcom,serial-geni-qcom.yaml, and qcom,spi-geni-qcom.yaml follows the usual pattern for sharing peripheral-specific properties and only extends validation to include the new common props (e.g. qcom,enable-gsi-dma) without disturbing the existing controller semantics. This is a clean, upstream-style backport.

Also applies to: 48-50, 90-95


60-85: New qcom,se-common-props.yaml schema is minimal, correct, and non-intrusive

The new schema has matching $id/file path, standard $schema, a clear title/description, and maintainers. qcom,enable-gsi-dma is correctly modeled as a flag with a precise description, and additionalProperties: true ensures the fragment does not over-constrain consumers when composed via allOf. This should integrate cleanly with existing DT validation.

patch/kernel/archive/sm8250-6.12/0047-spi-geni-qcom-Load-spi-qup-Firmware-from-linux-side.patch (1)

23-33: SPI GENI firmware-load path on GENI_SE_INVALID_PROTO is consistent and safe

The added proto == GENI_SE_INVALID_PROTO branch correctly attempts geni_load_se_firmware(se, GENI_SE_SPI) and, on failure, logs the error and bails out via the existing out_pm cleanup path. For other unexpected protocol values, the prior proto != GENI_SE_SPI error handling remains unchanged. This preserves existing behaviour for valid SPI proto while enabling Linux-side firmware loading when the SE starts in the invalid state.

patch/kernel/archive/sm8250-6.12/0044-soc-qcom-geni-se-Cleanup-register-defines-and-update.patch (1)

22-103: GENI SE register macro cleanup preserves semantics and aligns naming with later patches

The macro changes keep all register offsets identical while standardizing names (QUP_HW_VER_REGQUPV3_HW_VER_REG, GENI_*SE_GENI_*) and removing apparently unused GP length / RX length defines. geni_se_get_qup_hw_version() and geni_se_io_init() are updated to use the new symbols, and the DMA_AHB_SLV_CFG_ONDMA_AHB_SLV_CLK_CGC_ON rename is correctly reflected in the bitmask write. This is a pure refactor with no functional change and matches the style expected for the subsequent firmware-loading support; keeping it as-is is preferable to avoid diverging from upstream. Based on learnings.

patch/kernel/archive/sm8250-6.12/0048-serial-qcom-geni-Load-UART-qup-Firmware-from-linux-s.patch (1)

25-35: UART GENI now correctly attempts firmware load when SE protocol is invalid

The new proto == GENI_SE_INVALID_PROTO branch in qcom_geni_serial_port_setup() cleanly reuses geni_load_se_firmware(&port->se, GENI_SE_UART) and returns the underlying error on failure, while preserving the existing "Invalid FW loaded, proto: %d" / -ENXIO handling for other unexpected protocol values. This should resolve the previous proto: 255 log spam when firmware is missing while keeping the failure mode unchanged if a wrong (non-UART) firmware is present.

patch/kernel/archive/sm8250-6.12/0045-soc-qcom-geni-se-Add-support-to-load-QUP-SE-Firmware.patch (2)

383-494: Resource / ICC sequencing in geni_load_se_fw() looks correct

The overall resource choreography in geni_load_se_fw() looks sound:

  • geni_icc_set_bw()geni_icc_enable()geni_se_resources_on() on the way in.
  • On all post-resources_on error paths you goto out_resources_off / out_icc_disable, guaranteeing geni_se_resources_off() is called only after a successful geni_se_resources_on(), and that geni_icc_disable() is paired with a successful geni_icc_enable().
  • The success path naturally falls through to the same cleanup labels, so ICC and SE resources are not left enabled after firmware programming finishes.
  • Firmware header bounds checks are reused via geni_find_protocol_fw(), and the CFG RAM and primitive-table programming are guarded by the header’s size fields.

From a correctness and leak perspective, this function is in good shape once geni_find_protocol_fw() is hardened as suggested above.


566-587: Header and API are correctly implemented across the patch series

Verification confirms all three call sites (0046, 0047, 0048 patches) correctly pass valid protocols to geni_load_se_firmware():

  • 0046-i2c: passes GENI_SE_I2C
  • 0047-spi: passes GENI_SE_SPI
  • 0048-serial: passes GENI_SE_UART

GENI_SE_INVALID_PROTO is used exclusively as a hardware state sentinel in conditional checks (if (proto == GENI_SE_INVALID_PROTO)), never passed to the function. The implementation meets all stated expectations.

Comment on lines +187 to +283
+/**
+ * geni_find_protocol_fw() - Locate and validate SE firmware for a protocol.
+ * @dev: Pointer to the device structure.
+ * @fw: Pointer to the firmware image.
+ * @protocol: Expected serial engine protocol type.
+ *
+ * Identifies the appropriate firmware image or configuration required for a
+ * specific communication protocol instance running on a Qualcomm GENI
+ * controller.
+ *
+ * Return: pointer to a valid 'struct se_fw_hdr' if found, or NULL otherwise.
+ */
+static struct se_fw_hdr *geni_find_protocol_fw(struct device *dev, const struct firmware *fw,
+ enum geni_se_protocol_type protocol)
+{
+ const struct elf32_hdr *ehdr;
+ const struct elf32_phdr *phdrs;
+ const struct elf32_phdr *phdr;
+ struct se_fw_hdr *sefw;
+ u32 fw_end, cfg_idx_end, cfg_val_end;
+ u16 fw_size;
+ int i;
+
+ if (!fw || fw->size < sizeof(struct elf32_hdr))
+ return NULL;
+
+ ehdr = (const struct elf32_hdr *)fw->data;
+ phdrs = (const struct elf32_phdr *)(fw->data + ehdr->e_phoff);
+
+ /*
+ * The firmware is expected to have at least two program headers (segments).
+ * One for metadata and the other for the actual protocol-specific firmware.
+ */
+ if (ehdr->e_phnum < 2) {
+ dev_err(dev, "Invalid firmware: less than 2 program headers\n");
+ return NULL;
+ }
+
+ for (i = 0; i < ehdr->e_phnum; i++) {
+ phdr = &phdrs[i];
+
+ if (fw->size < phdr->p_offset + phdr->p_filesz) {
+ dev_err(dev, "Firmware size (%zu) < expected offset (%u) + size (%u)\n",
+ fw->size, phdr->p_offset, phdr->p_filesz);
+ return NULL;
+ }
+
+ if (phdr->p_type != PT_LOAD || !phdr->p_memsz)
+ continue;
+
+ if (MI_PBT_PAGE_MODE_VALUE(phdr->p_flags) != MI_PBT_NON_PAGED_SEGMENT ||
+ MI_PBT_SEGMENT_TYPE_VALUE(phdr->p_flags) == MI_PBT_HASH_SEGMENT ||
+ MI_PBT_ACCESS_TYPE_VALUE(phdr->p_flags) == MI_PBT_NOTUSED_SEGMENT ||
+ MI_PBT_ACCESS_TYPE_VALUE(phdr->p_flags) == MI_PBT_SHARED_SEGMENT)
+ continue;
+
+ if (phdr->p_filesz < sizeof(struct se_fw_hdr))
+ continue;
+
+ sefw = (struct se_fw_hdr *)(fw->data + phdr->p_offset);
+ fw_size = le16_to_cpu(sefw->fw_size_in_items);
+ fw_end = le16_to_cpu(sefw->fw_offset) + fw_size * sizeof(u32);
+ cfg_idx_end = le16_to_cpu(sefw->cfg_idx_offset) +
+ le16_to_cpu(sefw->cfg_size_in_items) * sizeof(u8);
+ cfg_val_end = le16_to_cpu(sefw->cfg_val_offset) +
+ le16_to_cpu(sefw->cfg_size_in_items) * sizeof(u32);
+
+ if (le32_to_cpu(sefw->magic) != SE_MAGIC_NUM || le32_to_cpu(sefw->version) != 1)
+ continue;
+
+ if (le32_to_cpu(sefw->serial_protocol) != protocol)
+ continue;
+
+ if (fw_size % 2 != 0) {
+ fw_size++;
+ sefw->fw_size_in_items = cpu_to_le16(fw_size);
+ }
+
+ if (fw_size >= MAX_GENI_CFG_RAMn_CNT) {
+ dev_err(dev,
+ "Firmware size (%u) exceeds max allowed RAMn count (%u)\n",
+ fw_size, MAX_GENI_CFG_RAMn_CNT);
+ continue;
+ }
+
+ if (fw_end > phdr->p_filesz || cfg_idx_end > phdr->p_filesz ||
+ cfg_val_end > phdr->p_filesz) {
+ dev_err(dev, "Truncated or corrupt SE FW segment found at index %d\n", i);
+ continue;
+ }
+
+ return sefw;
+ }
+
+ dev_err(dev, "Failed to get %s protocol firmware\n", protocol_name[protocol]);
+ return NULL;
+}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Harden ELF program-header parsing and fix serial_protocol endianness helper

Two issues in geni_find_protocol_fw() are worth addressing:

  1. Potential out-of-bounds read on the program header table

You compute phdrs directly from ehdr->e_phoff and then index up to ehdr->e_phnum without checking that the header table actually fits into fw->data:

ehdr = (const struct elf32_hdr *)fw->data;
phdrs = (const struct elf32_phdr *)(fw->data + ehdr->e_phoff);

for (i = 0; i < ehdr->e_phnum; i++) {
    phdr = &phdrs[i];
    if (fw->size < phdr->p_offset + phdr->p_filesz) ...

If e_phoff or e_phnum are malicious or corrupt, phdrs[i] can point beyond the firmware buffer, and dereferencing phdr->p_offset / phdr->p_filesz becomes an OOB read in kernel space.

You can close this hole cheaply by validating the program header table before the loop, e.g.:

-	ehdr = (const struct elf32_hdr *)fw->data;
-	phdrs = (const struct elf32_phdr *)(fw->data + ehdr->e_phoff);
+	ehdr = (const struct elf32_hdr *)fw->data;
+
+	if (fw->size < ehdr->e_phoff +
+		       (size_t)ehdr->e_phnum * sizeof(*phdrs)) {
+		dev_err(dev, "Invalid firmware: truncated program header table\n");
+		return NULL;
+	}
+
+	phdrs = (const struct elf32_phdr *)(fw->data + ehdr->e_phoff);

(Exact types/casts can be tuned to match kernel style, but the core idea is to bound-check the table as a whole before touching any phdr fields.)

  1. Endianness helper for serial_protocol is mismatched to the field type

serial_protocol is declared as __le16 in struct se_fw_hdr, but the comparison uses le32_to_cpu():

struct se_fw_hdr {
	__le32 magic;
	__le32 version;
	__le32 core_version;
	__le16 serial_protocol;
	...
};

...

if (le32_to_cpu(sefw->serial_protocol) != protocol)
    continue;

This is type-inconsistent and will either trip sparse/type checking or at least be confusing. Using le16_to_cpu() matches the field width and keeps the code self-documenting:

-		if (le32_to_cpu(sefw->serial_protocol) != protocol)
+		if (le16_to_cpu(sefw->serial_protocol) != protocol)
 			continue;

Given this runs in the kernel on untrusted firmware blobs, I’d treat the program-header bounds check as a must-have before merging, even if the code otherwise mirrors upstream, and keep the endianness fix as a straightforward, low-risk correction.

Based on learnings

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
patch/kernel/archive/sm8250-6.12/0043-dt-bindings-qcom-se-common-Add-QUP-Peripheral-specif.patch (1)

55-85: New qcom,se-common-props.yaml schema is well-formed

The new schema has the expected structure (SPDX header, $id, $schema, title, description, maintainers, properties) and defines qcom,enable-gsi-dma as a boolean flag via /schemas/types.yaml#/definitions/flag, with a clear description of GSI vs FIFO mode. This should validate cleanly with dt-schema.

One minor point to double-check: additionalProperties: true at the common-schema level is permissive; this is fine as long as the top-level protocol bindings still enforce their own additionalProperties policy. If this matches upstream 6.18, I’d keep it as-is for backport consistency.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between d30f8d0 and 8cb72aa.

📒 Files selected for processing (6)
  • patch/kernel/archive/sm8250-6.12/0043-dt-bindings-qcom-se-common-Add-QUP-Peripheral-specif.patch (1 hunks)
  • patch/kernel/archive/sm8250-6.12/0044-soc-qcom-geni-se-Cleanup-register-defines-and-update.patch (1 hunks)
  • patch/kernel/archive/sm8250-6.12/0045-soc-qcom-geni-se-Add-support-to-load-QUP-SE-Firmware.patch (1 hunks)
  • patch/kernel/archive/sm8250-6.12/0046-i2c-qcom-geni-Load-i2c-qup-Firmware-from-linux-side.patch (1 hunks)
  • patch/kernel/archive/sm8250-6.12/0047-spi-geni-qcom-Load-spi-qup-Firmware-from-linux-side.patch (1 hunks)
  • patch/kernel/archive/sm8250-6.12/0048-serial-qcom-geni-Load-UART-qup-Firmware-from-linux-s.patch (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: EvilOlaf
Repo: armbian/build PR: 8428
File: config/boards/lckfb-taishanpi.csc:5-9
Timestamp: 2025-07-25T03:51:50.830Z
Learning: When reviewing PRs in the Armbian build system, U-Boot defconfig files and patches may be added as part of the PR changes but might not be visible in the current repository clone state during review. It's important to check the actual PR file changes directly via GitHub or the PR API to get the complete picture of what files are being added or modified.
Learnt from: EvilOlaf
Repo: armbian/build PR: 8428
File: config/boards/lckfb-taishanpi.csc:5-9
Timestamp: 2025-07-25T03:51:50.830Z
Learning: When reviewing PRs in the Armbian build system, U-Boot defconfig files and patches may be added as part of the PR changes but might not be visible in the current repository clone state during review. It's important to check the actual PR file changes directly via GitHub API (https://api.github.com/repos/armbian/build/pulls/{pr_number}/files) to get the complete picture of what files are being added or modified, especially for U-Boot patches that will be applied during the build process.
Learnt from: tabrisnet
Repo: armbian/build PR: 8661
File: lib/functions/compilation/armbian-kernel.sh:194-199
Timestamp: 2025-09-25T18:37:00.330Z
Learning: In PR armbian/build#8661, line 235 of lib/functions/compilation/armbian-kernel.sh already contains the corrected comment "BPF link support for netfilter hooks" for NETFILTER_BPF_LINK, not the misleading "BPF_SYSCALL" comment that was flagged during review.
Learnt from: tabrisnet
Repo: armbian/build PR: 8661
File: lib/functions/compilation/armbian-kernel.sh:194-199
Timestamp: 2025-09-25T18:37:00.330Z
Learning: In PR armbian/build#8661, line 235 of lib/functions/compilation/armbian-kernel.sh already contains the corrected comment "BPF link support for netfilter hooks" for NETFILTER_BPF_LINK, not the misleading "BPF_SYSCALL" comment that was flagged during review.
Learnt from: rpardini
Repo: armbian/build PR: 8879
File: config/sources/families/uefi-x86.conf:0-0
Timestamp: 2025-11-06T15:36:04.682Z
Learning: As of PR #8879, the uefi-x86 family in the Armbian build system now includes kernel patches for the first time. The current and edge branches for uefi-x86 are specifically configured for Apple T2-based x86 machines, including T2-specific patches from the linux-t2 project and custom kernel configuration options for Apple hardware drivers.
Learnt from: rpardini
Repo: armbian/build PR: 8044
File: patch/u-boot/v2025.04/cmd-fileenv-read-string-from-file-into-env.patch:76-86
Timestamp: 2025-03-31T22:20:48.475Z
Learning: For the Armbian build project, maintaining consistency with existing patches across U-Boot versions (such as between 2025.01 and 2025.04) is prioritized over refactoring individual patches for code improvements.
Learnt from: rpardini
Repo: armbian/build PR: 8044
File: patch/u-boot/v2025.04/cmd-fileenv-read-string-from-file-into-env.patch:73-75
Timestamp: 2025-03-31T22:20:41.849Z
Learning: When porting patches between U-Boot versions (like from 2025.01 to 2025.04), rpardini prefers to maintain patches as-is rather than introducing refactoring changes, even when potential improvements are identified. This approach prioritizes consistency and reduces the risk of introducing new issues.
📚 Learning: 2025-03-31T22:20:41.849Z
Learnt from: rpardini
Repo: armbian/build PR: 8044
File: patch/u-boot/v2025.04/cmd-fileenv-read-string-from-file-into-env.patch:73-75
Timestamp: 2025-03-31T22:20:41.849Z
Learning: When porting patches between U-Boot versions (like from 2025.01 to 2025.04), rpardini prefers to maintain patches as-is rather than introducing refactoring changes, even when potential improvements are identified. This approach prioritizes consistency and reduces the risk of introducing new issues.

Applied to files:

  • patch/kernel/archive/sm8250-6.12/0047-spi-geni-qcom-Load-spi-qup-Firmware-from-linux-side.patch
  • patch/kernel/archive/sm8250-6.12/0044-soc-qcom-geni-se-Cleanup-register-defines-and-update.patch
  • patch/kernel/archive/sm8250-6.12/0048-serial-qcom-geni-Load-UART-qup-Firmware-from-linux-s.patch
🔇 Additional comments (13)
patch/kernel/archive/sm8250-6.12/0043-dt-bindings-qcom-se-common-Add-QUP-Peripheral-specif.patch (4)

1-29: Patch metadata is consistent and upstream-aligned

Commit header, authorship, Link tag, and summary all look coherent and match an upstream-style dt-bindings patch. Nothing to change here from an Armbian backport perspective.


30-41: I2C GENI binding correctly references the new common schema

Adding - $ref: /schemas/soc/qcom/qcom,se-common-props.yaml# under allOf cleanly shares the new QUP SE properties with the I2C binding and matches standard dt-bindings patterns. No issues spotted.


43-51: Serial GENI binding integration looks correct

Extending the allOf list with the common QUP SE schema is consistent with the I2C change and keeps SERIAL bindings in sync for qcom,enable-gsi-dma. The placement and path are correct.


86-95: SPI GENI binding change is consistent with I2C/SERIAL

Including the new common props schema in the SPI binding’s allOf list keeps all three QUP peripherals aligned on shared properties. Path and placement look correct; no further changes needed.

patch/kernel/archive/sm8250-6.12/0044-soc-qcom-geni-se-Cleanup-register-defines-and-update.patch (6)

23-28: Copyright block update is consistent and non-invasive

SPDX remains unchanged and the switch to a C-style multi-line comment plus adding the Qualcomm Technologies copyright line is fine; no functional impact. This matches the typical upstream style for these drivers.

Based on learnings


71-76: DMA_AHB_SLV bit rename preserves semantics

Renaming DMA_AHB_SLV_CFG_ON to DMA_AHB_SLV_CLK_CGC_ON keeps the bit position (BIT(2)) unchanged and improves naming consistency with the other *_CLK_CGC_ON bits. No functional change.

Based on learnings


79-85: QUP HW version read still targets the same register

geni_se_get_qup_hw_version() now uses QUPV3_HW_VER_REG, which is still 0x4, so the read from wrapper->base + 0x4 is identical to the previous QUP_HW_VER_REG usage. No behavior change.

Based on learnings


88-103: IO init uses renamed CGC/CLK macros; behavior unchanged

geni_se_io_init() now uses SE_GENI_CGC_CTRL in place of GENI_CGC_CTRL and the updated DMA_AHB_SLV_CLK_CGC_ON name, but all register offsets and bit positions are preserved. The same clocks get enabled as before, which is important for the later firmware-loading patches; no regressions expected here.

Based on learnings


104-105: Patch footer looks standard

The git version footer (2.51.1) is normal for an exported upstream patch and doesn’t affect integration into Armbian’s patch system.

Based on learnings


36-52: Upstream patch verification confirmed safe; no repository-side verification needed

This patch originates from upstream Linux kernel (commit link: https://lore.kernel.org/r/[email protected]) and is already merged in the official kernel tree. The armbian/build repository does not contain kernel source code—it applies patches to source fetched during build. Repository-wide verification found no references to the removed macros (GENI_INIT_CFG_REVISION, GENI_S_INIT_CFG_REVISION, GENI_OUTPUT_CTRL, SE_GENI_M_GP_LENGTH, SE_GENI_S_GP_LENGTH, SE_DMA_RX_LEN_IN), confirming upstream maintainers have already ensured their safe removal. The macro renames and removals are safe to apply.

patch/kernel/archive/sm8250-6.12/0046-i2c-qcom-geni-Load-i2c-qup-Firmware-from-linux-side.patch (1)

24-39: I2C INVALID_PROTO handling and cleanup look correct

The new GENI_SE_INVALID_PROTO branch cleanly attempts firmware load, and on failure it logs, tears down SE resources, and disables the core clock before returning the error. The follow‑up else if (proto != GENI_SE_I2C) preserves the old invalid‑proto behavior, so overall control flow and cleanup remain sound and consistent with the SPI/UART changes in this series.

patch/kernel/archive/sm8250-6.12/0047-spi-geni-qcom-Load-spi-qup-Firmware-from-linux-side.patch (1)

23-35: SPI INVALID_PROTO handling is consistent with the new SE firmware API

The added GENI_SE_INVALID_PROTO branch cleanly integrates SPI with the new geni_load_se_firmware() path: on success it falls through to the normal flow; on failure it logs once and jumps to the existing out_pm cleanup path. The existing SPI‑slave and invalid‑proto checks (proto != GENI_SE_SPI) remain intact, so overall behavior and resource handling stay consistent.

patch/kernel/archive/sm8250-6.12/0048-serial-qcom-geni-Load-UART-qup-Firmware-from-linux-s.patch (1)

23-36: UART INVALID_PROTO handling integrates cleanly with SE firmware loading

The new GENI_SE_INVALID_PROTO path in qcom_geni_serial_port_setup() appropriately attempts a UART firmware load and, on failure, logs and returns the error to the caller. The existing proto != GENI_SE_UART case is preserved for genuinely wrong protocols. This is consistent with the SPI and I2C patches and should eliminate the previous "Invalid FW loaded, proto: 255" noise once firmware is available.

Comment on lines +33 to +39
#include <linux/acpi.h>
+#include <linux/bitfield.h>
#include <linux/clk.h>
+#include <linux/firmware.h>
#include <linux/slab.h>
#include <linux/dma-mapping.h>
#include <linux/io.h>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Add <linux/elf.h> include for ELF32 types

geni_find_protocol_fw() uses struct elf32_hdr and struct elf32_phdr (Line 202–Line 204), but this file only adds <linux/bitfield.h> and <linux/firmware.h> around Line 33–Line 37. Without including <linux/elf.h>, this will not compile.

Please add the missing include next to the other headers, e.g.:

 #include <linux/acpi.h>
 #include <linux/bitfield.h>
 #include <linux/clk.h>
 #include <linux/firmware.h>
+#include <linux/elf.h>
 #include <linux/slab.h>

Based on learnings.

Also applies to: 199-205

🤖 Prompt for AI Agents
In
patch/kernel/archive/sm8250-6.12/0045-soc-qcom-geni-se-Add-support-to-load-QUP-SE-Firmware.patch
around lines 33 to 39 (and also where similar headers appear around lines 199 to
205), the file uses struct elf32_hdr and struct elf32_phdr but does not include
<linux/elf.h>; add the missing include directive for <linux/elf.h> alongside the
other kernel header includes in both locations so the ELF32 types are defined
and the file compiles.

Comment on lines +64 to +76
+struct se_fw_hdr {
+ __le32 magic;
+ __le32 version;
+ __le32 core_version;
+ __le16 serial_protocol;
+ __le16 fw_version;
+ __le16 cfg_version;
+ __le16 fw_size_in_items;
+ __le16 fw_offset;
+ __le16 cfg_size_in_items;
+ __le16 cfg_idx_offset;
+ __le16 cfg_val_offset;
+};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Use the correct endianness helper for serial_protocol (__le16)

In struct se_fw_hdr (Line 64–Line 76), serial_protocol is declared as __le16, but in geni_find_protocol_fw() it’s compared using le32_to_cpu (Line 257):

if (le32_to_cpu(sefw->serial_protocol) != protocol)
    continue;

This reads 32 bits starting at serial_protocol (i.e., mixing in fw_version), so the comparison can fail even for valid firmware once fw_version becomes non‑zero.

This should use le16_to_cpu instead, matching the field type:

-       if (le32_to_cpu(sefw->serial_protocol) != protocol)
+       if (le16_to_cpu(sefw->serial_protocol) != protocol)
                continue;

Based on learnings.

Also applies to: 247-259

🤖 Prompt for AI Agents
In
patch/kernel/archive/sm8250-6.12/0045-soc-qcom-geni-se-Add-support-to-load-QUP-SE-Firmware.patch
around lines 64-76 and usages around 247-259, the struct field serial_protocol
is __le16 but the code compares it using le32_to_cpu (e.g. at line ~257), which
reads 32 bits and can corrupt the comparison; change the conversion to
le16_to_cpu for any comparison or reads of se_fw_hdr.serial_protocol (and
related places that treat it as 16-bit) so the correct 16-bit endianness helper
is used and the comparison uses the proper width.

Comment on lines +244 to +266
+ continue;
+
+ sefw = (struct se_fw_hdr *)(fw->data + phdr->p_offset);
+ fw_size = le16_to_cpu(sefw->fw_size_in_items);
+ fw_end = le16_to_cpu(sefw->fw_offset) + fw_size * sizeof(u32);
+ cfg_idx_end = le16_to_cpu(sefw->cfg_idx_offset) +
+ le16_to_cpu(sefw->cfg_size_in_items) * sizeof(u8);
+ cfg_val_end = le16_to_cpu(sefw->cfg_val_offset) +
+ le16_to_cpu(sefw->cfg_size_in_items) * sizeof(u32);
+
+ if (le32_to_cpu(sefw->magic) != SE_MAGIC_NUM || le32_to_cpu(sefw->version) != 1)
+ continue;
+
+ if (le32_to_cpu(sefw->serial_protocol) != protocol)
+ continue;
+
+ if (fw_size % 2 != 0) {
+ fw_size++;
+ sefw->fw_size_in_items = cpu_to_le16(fw_size);
+ }
+
+ if (fw_size >= MAX_GENI_CFG_RAMn_CNT) {
+ dev_err(dev,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Recompute fw_end after rounding fw_size_in_items to avoid overruns

geni_find_protocol_fw() computes fw_end based on the original fw_size_in_items:

fw_size = le16_to_cpu(sefw->fw_size_in_items);
fw_end = le16_to_cpu(sefw->fw_offset) + fw_size * sizeof(u32);
...
if (fw_size % 2 != 0) {
    fw_size++;
    sefw->fw_size_in_items = cpu_to_le16(fw_size);
}
...
if (fw_end > phdr->p_filesz || cfg_idx_end > phdr->p_filesz ||
    cfg_val_end > phdr->p_filesz)
    ...

Later, geni_load_se_fw() uses hdr->fw_size_in_items when copying to the SE RAM (Line 468–Line 470):

memcpy_toio(se->base + SE_GENI_CFG_RAMN, fw_data,
            le16_to_cpu(hdr->fw_size_in_items) * sizeof(u32));

If the original fw_size_in_items is odd and just fits within the ELF segment, rounding it up by one increases the copy length, but fw_end and its bounds check are not recomputed. This can make memcpy_toio() read beyond the validated portion of the segment.

Suggestion:

  • After adjusting fw_size to even, recompute fw_end and then perform the fw_end > phdr->p_filesz check using the updated size.

Example patch:

fw_size = le16_to_cpu(sefw->fw_size_in_items);
fw_end = le16_to_cpu(sefw->fw_offset) + fw_size * sizeof(u32);
...
if (fw_size % 2 != 0) {
    fw_size++;
    sefw->fw_size_in_items = cpu_to_le16(fw_size);
+   fw_end = le16_to_cpu(sefw->fw_offset) + fw_size * sizeof(u32);
}
...
- if (fw_end > phdr->p_filesz || cfg_idx_end > phdr->p_filesz ||
+ if (fw_end > phdr->p_filesz || cfg_idx_end > phdr->p_filesz ||
      cfg_val_end > phdr->p_filesz) {

This keeps the behavior while ensuring the bounds check matches the eventual copy size.

Based on learnings.

Also applies to: 468-470

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between d30f8d0 and 8cb72aa.

📒 Files selected for processing (6)
  • patch/kernel/archive/sm8250-6.12/0043-dt-bindings-qcom-se-common-Add-QUP-Peripheral-specif.patch (1 hunks)
  • patch/kernel/archive/sm8250-6.12/0044-soc-qcom-geni-se-Cleanup-register-defines-and-update.patch (1 hunks)
  • patch/kernel/archive/sm8250-6.12/0045-soc-qcom-geni-se-Add-support-to-load-QUP-SE-Firmware.patch (1 hunks)
  • patch/kernel/archive/sm8250-6.12/0046-i2c-qcom-geni-Load-i2c-qup-Firmware-from-linux-side.patch (1 hunks)
  • patch/kernel/archive/sm8250-6.12/0047-spi-geni-qcom-Load-spi-qup-Firmware-from-linux-side.patch (1 hunks)
  • patch/kernel/archive/sm8250-6.12/0048-serial-qcom-geni-Load-UART-qup-Firmware-from-linux-s.patch (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: EvilOlaf
Repo: armbian/build PR: 8428
File: config/boards/lckfb-taishanpi.csc:5-9
Timestamp: 2025-07-25T03:51:50.830Z
Learning: When reviewing PRs in the Armbian build system, U-Boot defconfig files and patches may be added as part of the PR changes but might not be visible in the current repository clone state during review. It's important to check the actual PR file changes directly via GitHub or the PR API to get the complete picture of what files are being added or modified.
Learnt from: EvilOlaf
Repo: armbian/build PR: 8428
File: config/boards/lckfb-taishanpi.csc:5-9
Timestamp: 2025-07-25T03:51:50.830Z
Learning: When reviewing PRs in the Armbian build system, U-Boot defconfig files and patches may be added as part of the PR changes but might not be visible in the current repository clone state during review. It's important to check the actual PR file changes directly via GitHub API (https://api.github.com/repos/armbian/build/pulls/{pr_number}/files) to get the complete picture of what files are being added or modified, especially for U-Boot patches that will be applied during the build process.
Learnt from: rpardini
Repo: armbian/build PR: 8879
File: config/sources/families/uefi-x86.conf:0-0
Timestamp: 2025-11-06T15:36:04.682Z
Learning: As of PR #8879, the uefi-x86 family in the Armbian build system now includes kernel patches for the first time. The current and edge branches for uefi-x86 are specifically configured for Apple T2-based x86 machines, including T2-specific patches from the linux-t2 project and custom kernel configuration options for Apple hardware drivers.
Learnt from: rpardini
Repo: armbian/build PR: 8044
File: patch/u-boot/v2025.04/cmd-fileenv-read-string-from-file-into-env.patch:73-75
Timestamp: 2025-03-31T22:20:41.849Z
Learning: When porting patches between U-Boot versions (like from 2025.01 to 2025.04), rpardini prefers to maintain patches as-is rather than introducing refactoring changes, even when potential improvements are identified. This approach prioritizes consistency and reduces the risk of introducing new issues.
Learnt from: rpardini
Repo: armbian/build PR: 8044
File: patch/u-boot/v2025.04/cmd-fileenv-read-string-from-file-into-env.patch:76-86
Timestamp: 2025-03-31T22:20:48.475Z
Learning: For the Armbian build project, maintaining consistency with existing patches across U-Boot versions (such as between 2025.01 and 2025.04) is prioritized over refactoring individual patches for code improvements.
Learnt from: tabrisnet
Repo: armbian/build PR: 8661
File: lib/functions/compilation/armbian-kernel.sh:194-199
Timestamp: 2025-09-25T18:37:00.330Z
Learning: In PR armbian/build#8661, line 235 of lib/functions/compilation/armbian-kernel.sh already contains the corrected comment "BPF link support for netfilter hooks" for NETFILTER_BPF_LINK, not the misleading "BPF_SYSCALL" comment that was flagged during review.
Learnt from: tabrisnet
Repo: armbian/build PR: 8661
File: lib/functions/compilation/armbian-kernel.sh:194-199
Timestamp: 2025-09-25T18:37:00.330Z
Learning: In PR armbian/build#8661, line 235 of lib/functions/compilation/armbian-kernel.sh already contains the corrected comment "BPF link support for netfilter hooks" for NETFILTER_BPF_LINK, not the misleading "BPF_SYSCALL" comment that was flagged during review.
📚 Learning: 2025-03-31T22:20:41.849Z
Learnt from: rpardini
Repo: armbian/build PR: 8044
File: patch/u-boot/v2025.04/cmd-fileenv-read-string-from-file-into-env.patch:73-75
Timestamp: 2025-03-31T22:20:41.849Z
Learning: When porting patches between U-Boot versions (like from 2025.01 to 2025.04), rpardini prefers to maintain patches as-is rather than introducing refactoring changes, even when potential improvements are identified. This approach prioritizes consistency and reduces the risk of introducing new issues.

Applied to files:

  • patch/kernel/archive/sm8250-6.12/0044-soc-qcom-geni-se-Cleanup-register-defines-and-update.patch
  • patch/kernel/archive/sm8250-6.12/0048-serial-qcom-geni-Load-UART-qup-Firmware-from-linux-s.patch
🔇 Additional comments (21)
patch/kernel/archive/sm8250-6.12/0043-dt-bindings-qcom-se-common-Add-QUP-Peripheral-specif.patch (8)

1-22: Upstream patch metadata is complete and well-formed.

The patch header includes all necessary git metadata: proper authorship, co-developer attribution, upstream review tag from Krzysztof Kozlowski (devicetree maintainer), maintainer sign-off from Bjorn Andersson, and a link to the LKML discussion. This confirms the patch has been properly reviewed upstream before backporting.


23-28: File change summary matches the described modifications.

The statistics correctly reflect the addition of a new common properties schema and updates to three existing binding files.


30-41: I2C binding schema reference added correctly.

The reference to the common properties schema is properly placed in the allOf section with correct YAML syntax and path structure.


42-50: Serial binding schema reference added correctly.

Consistent with the I2C binding update, the reference is properly formatted and positioned.


54-86: New common properties schema is well-structured and follows kernel conventions.

The YAML schema correctly defines the qcom,enable-gsi-dma property as a boolean flag to configure GPI DMA mode. The additionalProperties: true on line 85 is appropriate for a reusable schema that will be referenced by other binding files. The schema follows standard kernel devicetree binding documentation patterns with proper licensing, schema URIs, and clear descriptions.


87-97: SPI binding schema reference added correctly.

The update is consistent with the I2C and serial binding changes, completing the integration of the common properties schema across all three QUP peripheral types.


98-100: Git version signature present.

The patch footer is standard git format-patch output.


1-100: Patch is well-formed and should apply cleanly to 6.12.

This is a documentation-only change introducing a new QUP common properties schema and adding schema references to three existing device tree binding files. The binding files (qcom,i2c-geni-qcom.yaml, qcom,spi-geni-qcom.yaml, qcom,serial-geni-qcom.yaml) are properly structured to accept the new $ref additions.

The patch is part of a well-ordered series (0040–0048), has upstream Reviewed-by approval, and contains no syntax errors. No changes required.

patch/kernel/archive/sm8250-6.12/0044-soc-qcom-geni-se-Cleanup-register-defines-and-update.patch (6)

22-28: LGTM!

The copyright update correctly adds Qualcomm Technologies, Inc. while preserving the original Linux Foundation copyright. The format change to a block comment is consistent with kernel coding standards.


79-86: LGTM!

The update correctly applies the register rename from QUP_HW_VER_REG to QUPV3_HW_VER_REG. The function's public API is unchanged, maintaining backward compatibility for external callers.


88-103: LGTM!

All register and flag references in geni_se_io_init() are correctly updated to use the new naming convention. The function logic remains unchanged.


36-67: Request manual verification of macro removals in actual kernel build.

This repository contains patches only, not kernel source code. The ripgrep searches found no results because there is no kernel source tree to inspect—not because the macros are unused. I cannot verify whether GENI_OUTPUT_CTRL, SE_GENI_M_GP_LENGTH, SE_GENI_S_GP_LENGTH, and SE_DMA_RX_LEN_IN are referenced elsewhere in the actual 6.12 kernel tree.

Verify this patch applies cleanly and the kernel builds successfully with this backport to 6.12, as the safety of the macro removals cannot be determined from this patch archive alone.


71-75: DMA flag rename is correctly applied and consistent.

The patch properly updates both the macro definition (DMA_AHB_SLV_CFG_ONDMA_AHB_SLV_CLK_CGC_ON at line 74–75) and its usage in geni_se_io_init() (line 99–100). The new name accurately reflects that this is a clock gating control bit.


3-3: No action required — patch date and upstream source verified as legitimate.

The patch was posted to LKML on 2025-09-11 as part of the v7 QUP Serial Engine firmware loading series. The message ID (20250911043256.3523057) encodes the correct date, and the timing aligns with the Linux 6.18 development cycle (merge window mid-October, rc releases late October/November 2025). The patch originates from official upstream LKML and is legitimate.

patch/kernel/archive/sm8250-6.12/0047-spi-geni-qcom-Load-spi-qup-Firmware-from-linux-side.patch (1)

23-33: SPI: INVALID proto firmware-load path is consistent and correctly ordered

The new GENI_SE_INVALID_PROTO branch calls geni_load_se_firmware() before the existing proto != GENI_SE_SPI error, so normal SPI and SPI-slave paths are unchanged while INVALID now gets a chance to self-heal. Error propagation through ret and goto out_pm should preserve -EPROBE_DEFER and other errors as-is; just confirm that the out_pm epilogue in spi_geni_init() returns ret unchanged on this platform.

patch/kernel/archive/sm8250-6.12/0046-i2c-qcom-geni-Load-i2c-qup-Firmware-from-linux-side.patch (1)

23-40: I2C: INVALID proto recovery and error handling look correct; watch resource balance

The new GENI_SE_INVALID_PROTO case correctly mirrors the SPI/UART pattern: it attempts geni_load_se_firmware(&gi2c->se, GENI_SE_I2C) and uses dev_err_probe() so -EPROBE_DEFER is handled properly, then drops SE resources and core_clk on failure similar to the existing invalid-proto path.

One subtlety: geni_load_se_firmware() manages ICC paths and SE resources internally, while geni_i2c_probe() also calls geni_se_resources_off()/clk_disable_unprepare() on its own error path. This should be safe if those helpers are idempotent (as in upstream), but it's worth confirming in the 6.12 context that resource/clock enable/disable counts remain balanced after a failed firmware load.

patch/kernel/archive/sm8250-6.12/0048-serial-qcom-geni-Load-UART-qup-Firmware-from-linux-s.patch (1)

22-36: UART: INVALID proto firmware-load integration is aligned with I2C/SPI

The UART setup now attempts geni_load_se_firmware(&port->se, GENI_SE_UART) when proto == GENI_SE_INVALID_PROTO and falls back to the existing Invalid FW loaded error for other unexpected protocols. This matches the pattern used in the I2C/SPI drivers and correctly returns the underlying ret from the loader.

Please verify that callers of qcom_geni_serial_port_setup() are fine with seeing -EPROBE_DEFER when the UART firmware is not yet available (which is likely desired here so the port reprobes once the firmware is in place).

patch/kernel/archive/sm8250-6.12/0045-soc-qcom-geni-se-Add-support-to-load-QUP-SE-Firmware.patch (4)

44-118: Core GENI-SE data structures and register/macro additions look coherent

The new protocol_name[], struct se_fw_hdr, ELF-related constants, and QUPV3/GENI register/bitfield defines are internally consistent and match the usage later in the file (firmware header parsing, primitive table programming, clock/CGC control, IRQ setup). Placing GENI_SE_INVALID_PROTO = 255 at the end of enum geni_se_protocol_type also keeps existing numeric values stable while giving a sentinel for the new INVALID path.

Given these definitions are directly consumed by the new firmware loader and by the I2C/SPI/UART call sites, I don’t see any structural issues here for the 6.12 backport.


295-351: Transfer-mode and interrupt configuration helpers look consistent with GENI usage

geni_configure_xfer_mode() cleanly centralizes the FIFO/GPI-DMA/DMA register programming, and geni_enable_interrupts() sets up M/S and DMA IRQs in a way that matches the masks and register names you define earlier (M_COMMON_GENI_M_IRQ_EN, GENI_SE_DMA_*, etc.). This keeps the mode-specific SE/GSI/DMA wiring out of the protocol drivers and in one place.

No functional issues stand out here; just ensure that on 6.12 the SE/GSI event bits (DMA_RX_EVENT_EN, DMA_TX_EVENT_EN, GENI_M_EVENT_EN, GENI_S_EVENT_EN) and the new DMA IRQ bits still match the hardware/DT configuration for SM8250 as in the 6.18 baseline you’re backporting from.


383-494: Resource/clock/ICC lifecycle in geni_load_se_fw() is subtle but appears self-contained

geni_load_se_fw():

  • Locates the protocol-specific firmware with geni_find_protocol_fw().
  • Enables ICC bandwidth and paths, powers the SE on (geni_se_resources_on()), programs QUPV3/GENI clocks/CGC, writes the primitive table/CFG RAM, configures transfer mode, enables interrupts, writes FW revision, and finally toggles SCLK/HCLK and DMA/FIFO interfaces.
  • Always drops resources and ICC on exit via geni_se_resources_off() and geni_icc_disable().

Two things to keep in mind for the backport:

  1. Callers (I2C/SPI/UART) must not assume the SE or ICC remain enabled after geni_load_se_firmware() returns; they should treat it as a self-contained programming transaction and bring resources back up as needed for normal operation. From the snippets you’ve patched, this seems to be the intent, but it’s worth double-checking against the 6.12 versions of those drivers.

  2. On early failures before geni_se_resources_on() succeeds, the function returns directly without calling geni_icc_disable(), but that matches the typical GENI ICC usage pattern where only a successful geni_icc_enable() is paired with geni_icc_disable().

Given your dmesg results and successful bring‑up, the lifecycle looks sound; just ensure there are no remaining 6.12-only callers that expected resources_on() to keep the SE powered beyond this programming step.


508-555: Public API geni_load_se_firmware() and GENI_SE_INVALID_PROTO integration look good

The exported geni_load_se_firmware():

  • Validates the protocol against protocol_name[].
  • Reads a required firmware-name property from the wrapper device.
  • Optionally enables GSI DMA via qcom,enable-gsi-dma, but forces FIFO mode for UART.
  • Requests the firmware and maps -ENOENT to -EPROBE_DEFER so protocol drivers can reprobe once the blob is available.
  • Delegates the actual programming to geni_load_se_fw() and logs detailed errors.

The header update (GENI_SE_INVALID_PROTO = 255 and the prototype) lines up with how the I2C/SPI/UART drivers now trigger firmware loading when geni_se_read_proto() reports INVALID.

Given Armbian’s preference to track upstream patches closely, this public API shape looks appropriate for the 6.12 backport. The main thing to verify is that all SM8250 QUP wrapper nodes used here have the correct firmware-name property and that the corresponding firmware files are included in the initramfs, otherwise you’ll see persistent -EPROBE_DEFER and probe loops. Based on learnings.

Also applies to: 566-587

Comment on lines +187 to +283
+/**
+ * geni_find_protocol_fw() - Locate and validate SE firmware for a protocol.
+ * @dev: Pointer to the device structure.
+ * @fw: Pointer to the firmware image.
+ * @protocol: Expected serial engine protocol type.
+ *
+ * Identifies the appropriate firmware image or configuration required for a
+ * specific communication protocol instance running on a Qualcomm GENI
+ * controller.
+ *
+ * Return: pointer to a valid 'struct se_fw_hdr' if found, or NULL otherwise.
+ */
+static struct se_fw_hdr *geni_find_protocol_fw(struct device *dev, const struct firmware *fw,
+ enum geni_se_protocol_type protocol)
+{
+ const struct elf32_hdr *ehdr;
+ const struct elf32_phdr *phdrs;
+ const struct elf32_phdr *phdr;
+ struct se_fw_hdr *sefw;
+ u32 fw_end, cfg_idx_end, cfg_val_end;
+ u16 fw_size;
+ int i;
+
+ if (!fw || fw->size < sizeof(struct elf32_hdr))
+ return NULL;
+
+ ehdr = (const struct elf32_hdr *)fw->data;
+ phdrs = (const struct elf32_phdr *)(fw->data + ehdr->e_phoff);
+
+ /*
+ * The firmware is expected to have at least two program headers (segments).
+ * One for metadata and the other for the actual protocol-specific firmware.
+ */
+ if (ehdr->e_phnum < 2) {
+ dev_err(dev, "Invalid firmware: less than 2 program headers\n");
+ return NULL;
+ }
+
+ for (i = 0; i < ehdr->e_phnum; i++) {
+ phdr = &phdrs[i];
+
+ if (fw->size < phdr->p_offset + phdr->p_filesz) {
+ dev_err(dev, "Firmware size (%zu) < expected offset (%u) + size (%u)\n",
+ fw->size, phdr->p_offset, phdr->p_filesz);
+ return NULL;
+ }
+
+ if (phdr->p_type != PT_LOAD || !phdr->p_memsz)
+ continue;
+
+ if (MI_PBT_PAGE_MODE_VALUE(phdr->p_flags) != MI_PBT_NON_PAGED_SEGMENT ||
+ MI_PBT_SEGMENT_TYPE_VALUE(phdr->p_flags) == MI_PBT_HASH_SEGMENT ||
+ MI_PBT_ACCESS_TYPE_VALUE(phdr->p_flags) == MI_PBT_NOTUSED_SEGMENT ||
+ MI_PBT_ACCESS_TYPE_VALUE(phdr->p_flags) == MI_PBT_SHARED_SEGMENT)
+ continue;
+
+ if (phdr->p_filesz < sizeof(struct se_fw_hdr))
+ continue;
+
+ sefw = (struct se_fw_hdr *)(fw->data + phdr->p_offset);
+ fw_size = le16_to_cpu(sefw->fw_size_in_items);
+ fw_end = le16_to_cpu(sefw->fw_offset) + fw_size * sizeof(u32);
+ cfg_idx_end = le16_to_cpu(sefw->cfg_idx_offset) +
+ le16_to_cpu(sefw->cfg_size_in_items) * sizeof(u8);
+ cfg_val_end = le16_to_cpu(sefw->cfg_val_offset) +
+ le16_to_cpu(sefw->cfg_size_in_items) * sizeof(u32);
+
+ if (le32_to_cpu(sefw->magic) != SE_MAGIC_NUM || le32_to_cpu(sefw->version) != 1)
+ continue;
+
+ if (le32_to_cpu(sefw->serial_protocol) != protocol)
+ continue;
+
+ if (fw_size % 2 != 0) {
+ fw_size++;
+ sefw->fw_size_in_items = cpu_to_le16(fw_size);
+ }
+
+ if (fw_size >= MAX_GENI_CFG_RAMn_CNT) {
+ dev_err(dev,
+ "Firmware size (%u) exceeds max allowed RAMn count (%u)\n",
+ fw_size, MAX_GENI_CFG_RAMn_CNT);
+ continue;
+ }
+
+ if (fw_end > phdr->p_filesz || cfg_idx_end > phdr->p_filesz ||
+ cfg_val_end > phdr->p_filesz) {
+ dev_err(dev, "Truncated or corrupt SE FW segment found at index %d\n", i);
+ continue;
+ }
+
+ return sefw;
+ }
+
+ dev_err(dev, "Failed to get %s protocol firmware\n", protocol_name[protocol]);
+ return NULL;
+}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

Minor endianness bug and potential hardening opportunity in geni_find_protocol_fw()

geni_find_protocol_fw() does a good job of validating ELF segments and guarding against truncated SE firmware segments, but there are two points worth tightening:

  • The protocol compare currently uses le32_to_cpu(sefw->serial_protocol) even though serial_protocol is declared as __le16. On little‑endian ARM this happens to work, but it’s type‑mismatched and would break on big‑endian. Using le16_to_cpu() here is the correct and clearer choice:
-        if (le32_to_cpu(sefw->serial_protocol) != protocol)
+        if (le16_to_cpu(sefw->serial_protocol) != protocol)
             continue;
  • For extra robustness you might also want to add a bounds check that ehdr->e_phoff + e_phnum * sizeof(*phdrs) <= fw->size before computing phdrs, to avoid ever indexing past the firmware blob if a malformed image slips through. This is probably low‑risk given the firmware is Qualcomm‑supplied, so consider it optional, especially if you prefer to keep this patch identical to the upstream 6.18 version and instead carry hardening changes in a tiny follow‑up patch. Based on learnings.

I'll help you verify the review comment. Let me examine the patch file and the structure definitions to confirm the identified issues.

I need to examine the actual patch file in the repository to verify the specific issues. Let me search for it.

[/run_scripts]


🏁 Script executed:

#!/bin/bash
# Find and examine the patch file
find . -name "*0045-soc-qcom-geni-se*" -type f 2>/dev/null | head -5

Length of output: 98


[/run_scripts]


🏁 Script executed:

#!/bin/bash
# Extract lines around 187-283 and search for relevant structures
echo "=== Extracting lines 187-283 from patch ==="
sed -n '187,283p' ./patch/kernel/archive/sm8250-6.12/0045-soc-qcom-geni-se-Add-support-to-load-QUP-SE-Firmware.patch

echo -e "\n=== Searching for se_fw_hdr structure ==="
grep -n "se_fw_hdr" ./patch/kernel/archive/sm8250-6.12/0045-soc-qcom-geni-se-Add-support-to-load-QUP-SE-Firmware.patch | head -20

Length of output: 3719


[/run_scripts]


🏁 Script executed:

#!/bin/bash
# Extract the se_fw_hdr structure definition
echo "=== Extracting se_fw_hdr structure definition ==="
sed -n '47,85p' ./patch/kernel/archive/sm8250-6.12/0045-soc-qcom-geni-se-Add-support-to-load-QUP-SE-Firmware.patch

echo -e "\n=== Looking for bounds check before phdrs ==="
sed -n '210,230p' ./patch/kernel/archive/sm8250-6.12/0045-soc-qcom-geni-se-Add-support-to-load-QUP-SE-Firmware.patch

Length of output: 2086


Fix type mismatch in endianness conversion for serial_protocol field

The serial_protocol field is declared as __le16 in the se_fw_hdr structure (line ~70), but the code at line ~255 uses le32_to_cpu(sefw->serial_protocol). This type mismatch works by accident on little-endian ARM but will break on big-endian systems and reads from incorrect memory offsets. Change to le16_to_cpu():

-        if (le32_to_cpu(sefw->serial_protocol) != protocol)
+        if (le16_to_cpu(sefw->serial_protocol) != protocol)
             continue;

Additionally, consider adding a bounds check before computing phdrs at line ~215 to validate that ehdr->e_phoff + ehdr->e_phnum * sizeof(*phdrs) <= fw->size, though this is optional hardening since the firmware is Qualcomm-supplied.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
+/**
+ * geni_find_protocol_fw() - Locate and validate SE firmware for a protocol.
+ * @dev: Pointer to the device structure.
+ * @fw: Pointer to the firmware image.
+ * @protocol: Expected serial engine protocol type.
+ *
+ * Identifies the appropriate firmware image or configuration required for a
+ * specific communication protocol instance running on a Qualcomm GENI
+ * controller.
+ *
+ * Return: pointer to a valid 'struct se_fw_hdr' if found, or NULL otherwise.
+ */
+static struct se_fw_hdr *geni_find_protocol_fw(struct device *dev, const struct firmware *fw,
+ enum geni_se_protocol_type protocol)
+{
+ const struct elf32_hdr *ehdr;
+ const struct elf32_phdr *phdrs;
+ const struct elf32_phdr *phdr;
+ struct se_fw_hdr *sefw;
+ u32 fw_end, cfg_idx_end, cfg_val_end;
+ u16 fw_size;
+ int i;
+
+ if (!fw || fw->size < sizeof(struct elf32_hdr))
+ return NULL;
+
+ ehdr = (const struct elf32_hdr *)fw->data;
+ phdrs = (const struct elf32_phdr *)(fw->data + ehdr->e_phoff);
+
+ /*
+ * The firmware is expected to have at least two program headers (segments).
+ * One for metadata and the other for the actual protocol-specific firmware.
+ */
+ if (ehdr->e_phnum < 2) {
+ dev_err(dev, "Invalid firmware: less than 2 program headers\n");
+ return NULL;
+ }
+
+ for (i = 0; i < ehdr->e_phnum; i++) {
+ phdr = &phdrs[i];
+
+ if (fw->size < phdr->p_offset + phdr->p_filesz) {
+ dev_err(dev, "Firmware size (%zu) < expected offset (%u) + size (%u)\n",
+ fw->size, phdr->p_offset, phdr->p_filesz);
+ return NULL;
+ }
+
+ if (phdr->p_type != PT_LOAD || !phdr->p_memsz)
+ continue;
+
+ if (MI_PBT_PAGE_MODE_VALUE(phdr->p_flags) != MI_PBT_NON_PAGED_SEGMENT ||
+ MI_PBT_SEGMENT_TYPE_VALUE(phdr->p_flags) == MI_PBT_HASH_SEGMENT ||
+ MI_PBT_ACCESS_TYPE_VALUE(phdr->p_flags) == MI_PBT_NOTUSED_SEGMENT ||
+ MI_PBT_ACCESS_TYPE_VALUE(phdr->p_flags) == MI_PBT_SHARED_SEGMENT)
+ continue;
+
+ if (phdr->p_filesz < sizeof(struct se_fw_hdr))
+ continue;
+
+ sefw = (struct se_fw_hdr *)(fw->data + phdr->p_offset);
+ fw_size = le16_to_cpu(sefw->fw_size_in_items);
+ fw_end = le16_to_cpu(sefw->fw_offset) + fw_size * sizeof(u32);
+ cfg_idx_end = le16_to_cpu(sefw->cfg_idx_offset) +
+ le16_to_cpu(sefw->cfg_size_in_items) * sizeof(u8);
+ cfg_val_end = le16_to_cpu(sefw->cfg_val_offset) +
+ le16_to_cpu(sefw->cfg_size_in_items) * sizeof(u32);
+
+ if (le32_to_cpu(sefw->magic) != SE_MAGIC_NUM || le32_to_cpu(sefw->version) != 1)
+ continue;
+
+ if (le32_to_cpu(sefw->serial_protocol) != protocol)
+ continue;
+
+ if (fw_size % 2 != 0) {
+ fw_size++;
+ sefw->fw_size_in_items = cpu_to_le16(fw_size);
+ }
+
+ if (fw_size >= MAX_GENI_CFG_RAMn_CNT) {
+ dev_err(dev,
+ "Firmware size (%u) exceeds max allowed RAMn count (%u)\n",
+ fw_size, MAX_GENI_CFG_RAMn_CNT);
+ continue;
+ }
+
+ if (fw_end > phdr->p_filesz || cfg_idx_end > phdr->p_filesz ||
+ cfg_val_end > phdr->p_filesz) {
+ dev_err(dev, "Truncated or corrupt SE FW segment found at index %d\n", i);
+ continue;
+ }
+
+ return sefw;
+ }
+
+ dev_err(dev, "Failed to get %s protocol firmware\n", protocol_name[protocol]);
+ return NULL;
+}
/**
* geni_find_protocol_fw() - Locate and validate SE firmware for a protocol.
* @dev: Pointer to the device structure.
* @fw: Pointer to the firmware image.
* @protocol: Expected serial engine protocol type.
*
* Identifies the appropriate firmware image or configuration required for a
* specific communication protocol instance running on a Qualcomm GENI
* controller.
*
* Return: pointer to a valid 'struct se_fw_hdr' if found, or NULL otherwise.
*/
static struct se_fw_hdr *geni_find_protocol_fw(struct device *dev, const struct firmware *fw,
enum geni_se_protocol_type protocol)
{
const struct elf32_hdr *ehdr;
const struct elf32_phdr *phdrs;
const struct elf32_phdr *phdr;
struct se_fw_hdr *sefw;
u32 fw_end, cfg_idx_end, cfg_val_end;
u16 fw_size;
int i;
if (!fw || fw->size < sizeof(struct elf32_hdr))
return NULL;
ehdr = (const struct elf32_hdr *)fw->data;
phdrs = (const struct elf32_phdr *)(fw->data + ehdr->e_phoff);
/*
* The firmware is expected to have at least two program headers (segments).
* One for metadata and the other for the actual protocol-specific firmware.
*/
if (ehdr->e_phnum < 2) {
dev_err(dev, "Invalid firmware: less than 2 program headers\n");
return NULL;
}
for (i = 0; i < ehdr->e_phnum; i++) {
phdr = &phdrs[i];
if (fw->size < phdr->p_offset + phdr->p_filesz) {
dev_err(dev, "Firmware size (%zu) < expected offset (%u) + size (%u)\n",
fw->size, phdr->p_offset, phdr->p_filesz);
return NULL;
}
if (phdr->p_type != PT_LOAD || !phdr->p_memsz)
continue;
if (MI_PBT_PAGE_MODE_VALUE(phdr->p_flags) != MI_PBT_NON_PAGED_SEGMENT ||
MI_PBT_SEGMENT_TYPE_VALUE(phdr->p_flags) == MI_PBT_HASH_SEGMENT ||
MI_PBT_ACCESS_TYPE_VALUE(phdr->p_flags) == MI_PBT_NOTUSED_SEGMENT ||
MI_PBT_ACCESS_TYPE_VALUE(phdr->p_flags) == MI_PBT_SHARED_SEGMENT)
continue;
if (phdr->p_filesz < sizeof(struct se_fw_hdr))
continue;
sefw = (struct se_fw_hdr *)(fw->data + phdr->p_offset);
fw_size = le16_to_cpu(sefw->fw_size_in_items);
fw_end = le16_to_cpu(sefw->fw_offset) + fw_size * sizeof(u32);
cfg_idx_end = le16_to_cpu(sefw->cfg_idx_offset) +
le16_to_cpu(sefw->cfg_size_in_items) * sizeof(u8);
cfg_val_end = le16_to_cpu(sefw->cfg_val_offset) +
le16_to_cpu(sefw->cfg_size_in_items) * sizeof(u32);
if (le32_to_cpu(sefw->magic) != SE_MAGIC_NUM || le32_to_cpu(sefw->version) != 1)
continue;
if (le16_to_cpu(sefw->serial_protocol) != protocol)
continue;
if (fw_size % 2 != 0) {
fw_size++;
sefw->fw_size_in_items = cpu_to_le16(fw_size);
}
if (fw_size >= MAX_GENI_CFG_RAMn_CNT) {
dev_err(dev,
"Firmware size (%u) exceeds max allowed RAMn count (%u)\n",
fw_size, MAX_GENI_CFG_RAMn_CNT);
continue;
}
if (fw_end > phdr->p_filesz || cfg_idx_end > phdr->p_filesz ||
cfg_val_end > phdr->p_filesz) {
dev_err(dev, "Truncated or corrupt SE FW segment found at index %d\n", i);
continue;
}
return sefw;
}
dev_err(dev, "Failed to get %s protocol firmware\n", protocol_name[protocol]);
return NULL;
}

@github-actions github-actions bot added the Ready to merge Reviewed, tested and ready for merge label Nov 16, 2025
@github-actions
Copy link
Contributor

✅ This PR has been reviewed and approved — all set for merge!

@github-actions github-actions bot removed the Needs review Seeking for review label Nov 16, 2025
@igorpecovnik igorpecovnik merged commit 2ac1b4c into armbian:main Nov 17, 2025
1 check passed
@retro98boy retro98boy deleted the sm8250-current-qup-firmware branch November 17, 2025 08:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

11 Milestone: Fourth quarter release Hardware Hardware related like kernel, U-Boot, ... Patches Patches related to kernel, U-Boot, ... Ready to merge Reviewed, tested and ready for merge size/large PR with 250 lines or more

Development

Successfully merging this pull request may close these issues.

3 participants