* [PULL] PCI: meson: Fix PERST# timing by asserting reset before LTSSM enable
From: gowtham @ 2026-06-14 4:26 UTC (permalink / raw)
To: yue.wang, lpieralisi, kwilczynski, mani
Cc: robh, bhelgaas, neil.armstrong, khilman, jbrunet,
martin.blumenstingl, linux-pci, linux-amlogic, linux-arm-kernel,
linux-kernel
The following changes since commit
bb532bfaf7919c7c98caab81864e9ce2646e11e3:
Linux 7.0.11 (2026-06-01 17:54:55 +0200)
are available in the Git repository at:
https://github.com/GowthamKudupudi/linux.git
tags/meson-pcie-warm-reset-linux-7.0.y
for you to fetch changes up to 852811b11795ee389ea6a953ed0db69b76722469:
PCI: meson: Fix PERST# timing by asserting reset before LTSSM enable
(2026-06-14 09:41:01 +0530)
----------------------------------------------------------------
PCI: meson: Fix PERST# timing by asserting reset before LTSSM enable
On warm reboot, the PCIe controller's LTSSM starts link training
immediately if PERST# is already deasserted from the previous boot.
The driver then pulses PERST# for only 500us, which is too short to
properly reset the endpoint device that has already started training.
Fix by moving the PERST# assert/deassert pulse BEFORE enabling LTSSM,
so the endpoint gets a clean reset cycle before link training begins.
This was found on Amlogic G12B (A311D) with NVMe on an M.2 slot.
Cold boot worked because POR held PERST# low; warm reboot did not.
The fix was confirmed on a Banana Pi CM4 with Waveshare IO base board.
----------------------------------------------------------------
Gowtham Kudupudi (1):
PCI: meson: Fix PERST# timing by asserting reset before LTSSM
enable
drivers/pci/controller/dwc/pci-meson.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
^ permalink raw reply
* Re: [RFC PATCH net-next 0/7] net: airoha: add EN7581 SOE ESP packet offload
From: Jihong Min @ 2026-06-14 4:18 UTC (permalink / raw)
To: netdev, Lorenzo Bianconi
Cc: David S . Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Andrew Lunn, Simon Horman, Herbert Xu, Steffen Klassert,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, devicetree,
Matthias Brugger, AngeloGioacchino Del Regno, linux-arm-kernel,
linux-mediatek, Christian Marangi, Felix Fietkau, linux-kernel
In-Reply-To: <20260614040032.1567994-1-hurryman2212@gmail.com>
On 6/14/26 13:00, Jihong Min wrote:
> Add Secure Offload Engine (SOE) support for the Airoha EN7581 Ethernet
> driver. SOE provides inline ESP packet offload for native ESP and NAT-T
> traffic, with the Ethernet/QDMA path used to submit packets to the SOE
> block and the PPE path used to bind eligible ESP flows. NETIF_F_GSO_ESP
> and NETIF_F_HW_ESP_TX_CSUM are intentionally left out for now and will be
> revisited separately for feasibility.
>
> This is posted as RFC because the code was originally developed and tested
> against an OpenWrt 6.18 Airoha tree, not against the current upstream
> net-next driver. The original OpenWrt commit used as the source for this
> RFC is available at:
> https://github.com/hurryman2212/OpenW1700k-test/commit/7c1b5e662f7790b3d23ed143beadc1dcbf6d15f7
>
> The SOE part is intentionally linked into the airoha Ethernet module
> instead of being exposed as an independent crypto or platform driver. The
> user-visible ESP offload control is a netdev capability: xfrmdev_ops and
> NETIF_F_HW_ESP live on the target netdev, and the feature can be controlled
> through the usual netdev feature path. SOE also shares the FE/QDMA/PPE
> datapath, private queues, DSA conduit handling and netdev lifetime owned by
> airoha_eth.
>
> Patch 1 adds xdo_dev_packet_xmit() because the existing XFRM packet
> offload transmit path does not provide a hook for hardware whose ESP engine
> is reached through device-specific packet forwarding. SOE needs to consume
> the skb, add a hardware hop descriptor, steer it to a private QDMA path and
> return the final transmit status. Drivers that do not implement the
> optional callback keep the existing XFRM output behavior.
>
> Jihong Min (7):
> xfrm: allow packet offload drivers to own transmit
> dt-bindings: net: airoha: add EN7581 SOE
> arm64: dts: airoha: add EN7581 SOE node
> net: airoha: add SOE registers and driver state
> net: airoha: add QDMA support for SOE packets
> net: airoha: add PPE support for SOE flows
> net: airoha: add SOE XFRM packet offload support
>
> .../bindings/net/airoha,en7581-soe.yaml | 48 +
> MAINTAINERS | 1 +
> arch/arm64/boot/dts/airoha/en7581.dtsi | 6 +
> drivers/net/ethernet/airoha/Kconfig | 13 +
> drivers/net/ethernet/airoha/Makefile | 1 +
> drivers/net/ethernet/airoha/airoha_eth.c | 668 +++++-
> drivers/net/ethernet/airoha/airoha_eth.h | 40 +
> drivers/net/ethernet/airoha/airoha_ppe.c | 606 +++++-
> drivers/net/ethernet/airoha/airoha_regs.h | 16 +
> drivers/net/ethernet/airoha/airoha_soe.c | 1896 +++++++++++++++++
> drivers/net/ethernet/airoha/airoha_soe.h | 126 ++
> include/linux/netdevice.h | 8 +
> include/linux/soc/airoha/airoha_offload.h | 5 +
> net/xfrm/xfrm_output.c | 11 +
> 14 files changed, 3342 insertions(+), 103 deletions(-)
> create mode 100644 Documentation/devicetree/bindings/net/airoha,en7581-soe.yaml
> create mode 100644 drivers/net/ethernet/airoha/airoha_soe.c
> create mode 100644 drivers/net/ethernet/airoha/airoha_soe.h
>
I noticed, after posting this RFC, that I forgot to include the
following trailer while preparing the latest patch series:
Assisted-by: Codex:gpt-5.5
These patches were written and tested with AI assistance, although I've
reviewed the resulting code and test results. I'll include the trailer
properly in future revisions or submissions. Sorry.
Sincerely,
Jihong Min
^ permalink raw reply
* [RFC PATCH net-next 5/7] net: airoha: add QDMA support for SOE packets
From: Jihong Min @ 2026-06-14 4:00 UTC (permalink / raw)
To: netdev, Lorenzo Bianconi
Cc: David S . Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Andrew Lunn, Simon Horman, Herbert Xu, Steffen Klassert,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, devicetree,
Matthias Brugger, AngeloGioacchino Del Regno, linux-arm-kernel,
linux-mediatek, Christian Marangi, Felix Fietkau, linux-kernel,
Jihong Min
In-Reply-To: <20260614040032.1567994-1-hurryman2212@gmail.com>
Add QDMA RX/TX plumbing for SOE packets, including the SOE RX ring,
coherent RX slots, SOE completion decoding, and the private QDMA submit
helper used by the SOE provider. Wire the Ethernet netdev feature and
lifetime hooks through the SOE stubs.
Signed-off-by: Jihong Min <hurryman2212@gmail.com>
---
drivers/net/ethernet/airoha/airoha_eth.c | 668 ++++++++++++++++++++---
1 file changed, 591 insertions(+), 77 deletions(-)
diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c
index 5f1a118875fb..42fd30c12ed7 100644
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
@@ -6,6 +6,7 @@
#include <linux/of.h>
#include <linux/of_net.h>
#include <linux/of_reserved_mem.h>
+#include <linux/moduleparam.h>
#include <linux/platform_device.h>
#include <linux/tcp.h>
#include <linux/u64_stats_sync.h>
@@ -16,6 +17,67 @@
#include "airoha_regs.h"
#include "airoha_eth.h"
+#include "airoha_soe.h"
+
+/* QDMA1 uses a different RX IRQ bank layout than QDMA0 on EN7581. */
+#define AIROHA_QDMA_WAN_RX_IRQ0_BANK_PIN_MASK 0x0000839f
+#define AIROHA_QDMA_WAN_RX_IRQ1_BANK_PIN_MASK 0x7f800400
+#define AIROHA_QDMA_WAN_RX_IRQ2_BANK_PIN_MASK 0x00000000
+#define AIROHA_QDMA_WAN_RX_IRQ3_BANK_PIN_MASK 0x00000040
+
+static unsigned int airoha_qdma0_rx_irq_bank_mask[AIROHA_MAX_NUM_IRQ_BANKS] = {
+ RX_IRQ0_BANK_PIN_MASK,
+ RX_IRQ1_BANK_PIN_MASK,
+ RX_IRQ2_BANK_PIN_MASK,
+ RX_IRQ3_BANK_PIN_MASK,
+};
+
+static unsigned int airoha_qdma1_rx_irq_bank_mask[AIROHA_MAX_NUM_IRQ_BANKS] = {
+ AIROHA_QDMA_WAN_RX_IRQ0_BANK_PIN_MASK,
+ AIROHA_QDMA_WAN_RX_IRQ1_BANK_PIN_MASK,
+ AIROHA_QDMA_WAN_RX_IRQ2_BANK_PIN_MASK,
+ AIROHA_QDMA_WAN_RX_IRQ3_BANK_PIN_MASK,
+};
+
+#if IS_REACHABLE(CONFIG_NET_AIROHA_SOE)
+#define AIROHA_SOE_RX_RING 10
+#define AIROHA_SOE_RX_ALLOC_NDESC 2048
+#define AIROHA_SOE_RX_NDESC_DEFAULT 512
+#define AIROHA_SOE_RX_BUF_SIZE 4096
+#define AIROHA_SOE_RX_BUF_SIZE_MIN 128
+#define AIROHA_SOE_RX_BUF_SIZE_MAX 16384
+#define AIROHA_SOE_DECRYPT_FOE_REASON_MASK \
+ (BIT(PPE_CPU_REASON_UN_HIT) | BIT(PPE_CPU_REASON_HIT_UNBIND) | \
+ BIT(PPE_CPU_REASON_HIT_UNBIND_RATE_REACHED))
+
+static int airoha_soe_rx_poll_desc_budget = AIROHA_SOE_RX_NDESC_DEFAULT;
+static int airoha_soe_rx_max_frame_descs = 128;
+static int airoha_soe_probe_rx_ndesc = AIROHA_SOE_RX_NDESC_DEFAULT;
+static int airoha_soe_probe_rx_buf_size = AIROHA_SOE_RX_BUF_SIZE;
+static bool airoha_soe_probe_rx_coherent = true;
+static int airoha_soe_probe_rx_scatter = 1;
+
+module_param_named(soe_rx_poll_desc_budget, airoha_soe_rx_poll_desc_budget, int,
+ 0600);
+MODULE_PARM_DESC(soe_rx_poll_desc_budget,
+ "Maximum SOE RX descriptors consumed per poll");
+module_param_named(soe_rx_max_frame_descs, airoha_soe_rx_max_frame_descs, int,
+ 0600);
+MODULE_PARM_DESC(soe_rx_max_frame_descs,
+ "Maximum descriptors per SOE RX frame before dropping the chain");
+module_param_named(soe_probe_rx_ndesc, airoha_soe_probe_rx_ndesc, int, 0600);
+MODULE_PARM_DESC(soe_probe_rx_ndesc, "SOE RX descriptor count");
+module_param_named(soe_probe_rx_buf_size, airoha_soe_probe_rx_buf_size, int,
+ 0600);
+MODULE_PARM_DESC(soe_probe_rx_buf_size, "SOE RX buffer size");
+module_param_named(soe_probe_rx_coherent, airoha_soe_probe_rx_coherent, bool,
+ 0600);
+MODULE_PARM_DESC(soe_probe_rx_coherent, "Use coherent SOE RX buffers");
+module_param_named(soe_probe_rx_scatter, airoha_soe_probe_rx_scatter, int,
+ 0600);
+MODULE_PARM_DESC(soe_probe_rx_scatter,
+ "SOE RX scatter mode: 0 disabled, 1 enabled");
+#endif
u32 airoha_rr(void __iomem *base, u32 offset)
{
@@ -71,6 +133,100 @@ static void airoha_qdma_irq_disable(struct airoha_irq_bank *irq_bank,
airoha_qdma_set_irqmask(irq_bank, index, mask, 0);
}
+static unsigned int *airoha_qdma_rx_irq_bank_masks(struct airoha_qdma *qdma)
+{
+ struct airoha_eth *eth = qdma->eth;
+ int id = qdma - ð->qdma[0];
+
+ return id ? airoha_qdma1_rx_irq_bank_mask :
+ airoha_qdma0_rx_irq_bank_mask;
+}
+
+static u32 airoha_qdma_rx_irq_bank_mask(struct airoha_qdma *qdma, int bank)
+{
+ unsigned int *masks = airoha_qdma_rx_irq_bank_masks(qdma);
+
+ if (bank < 0 || bank >= AIROHA_MAX_NUM_IRQ_BANKS)
+ return 0;
+
+ return READ_ONCE(masks[bank]);
+}
+
+#if IS_REACHABLE(CONFIG_NET_AIROHA_SOE)
+static u32 airoha_qdma_rx_irq_all_bank_mask(struct airoha_qdma *qdma)
+{
+ u32 mask = 0;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(qdma->irq_banks); i++)
+ mask |= airoha_qdma_rx_irq_bank_mask(qdma, i);
+
+ return mask;
+}
+#endif
+
+static void airoha_qdma_apply_rx_irq_bank_masks(struct airoha_qdma *qdma)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(qdma->irq_banks); i++) {
+ struct airoha_irq_bank *irq_bank = &qdma->irq_banks[i];
+ u32 mask = airoha_qdma_rx_irq_bank_mask(qdma, i);
+
+ airoha_qdma_set_irqmask(irq_bank, QDMA_INT_REG_IDX0,
+ RX_COHERENT_LOW_INT_MASK,
+ INT_RX0_MASK(mask));
+ airoha_qdma_set_irqmask(irq_bank, QDMA_INT_REG_IDX1,
+ RX_NO_CPU_DSCP_LOW_INT_MASK |
+ RX_DONE_LOW_INT_MASK,
+ INT_RX1_MASK(mask));
+ airoha_qdma_set_irqmask(irq_bank, QDMA_INT_REG_IDX2,
+ RX_NO_CPU_DSCP_HIGH_INT_MASK |
+ RX_DONE_HIGH_INT_MASK,
+ INT_RX2_MASK(mask));
+ airoha_qdma_set_irqmask(irq_bank, QDMA_INT_REG_IDX3,
+ RX_COHERENT_HIGH_INT_MASK,
+ INT_RX3_MASK(mask));
+ }
+}
+
+static void airoha_qdma_set_rx_done_irq(struct airoha_qdma *qdma, int qid,
+ bool enable)
+{
+ int i, intr_reg;
+ u32 mask;
+
+ intr_reg = qid < RX_DONE_HIGH_OFFSET ? QDMA_INT_REG_IDX1 :
+ QDMA_INT_REG_IDX2;
+ mask = BIT(qid % RX_DONE_HIGH_OFFSET);
+
+ for (i = 0; i < ARRAY_SIZE(qdma->irq_banks); i++) {
+ if (!(BIT(qid) & airoha_qdma_rx_irq_bank_mask(qdma, i)))
+ continue;
+
+ if (enable)
+ airoha_qdma_irq_enable(&qdma->irq_banks[i], intr_reg,
+ mask);
+ else
+ airoha_qdma_irq_disable(&qdma->irq_banks[i], intr_reg,
+ mask);
+ }
+
+#if IS_REACHABLE(CONFIG_NET_AIROHA_SOE)
+ if (qid != AIROHA_SOE_RX_RING)
+ return;
+
+ if (BIT(qid) & airoha_qdma_rx_irq_all_bank_mask(qdma))
+ return;
+
+ /* SOE RX10 may not be covered by the shared bank mask; use bank 0. */
+ if (enable)
+ airoha_qdma_irq_enable(&qdma->irq_banks[0], intr_reg, mask);
+ else
+ airoha_qdma_irq_disable(&qdma->irq_banks[0], intr_reg, mask);
+#endif
+}
+
static int airoha_set_macaddr(struct airoha_gdm_dev *dev, const u8 *addr)
{
u8 ref_addr[ETH_ALEN] __aligned(2);
@@ -532,6 +688,11 @@ static int airoha_fe_init(struct airoha_eth *eth)
airoha_fe_wr(eth, REG_FE_CDM1_OQ_MAP2, BIT(4));
airoha_fe_wr(eth, REG_FE_CDM1_OQ_MAP3, BIT(28));
+ /* SOE/TDMA output depends on PSE shared-buffer flow control instead
+ * of leaving port-local sharing disabled.
+ */
+ airoha_fe_clear(eth, REG_PSE_FC_CFG, PSE_TDMA_SHARE_BUF_DIS_MASK);
+
airoha_fe_vip_setup(eth);
airoha_fe_pse_ports_init(eth);
@@ -597,20 +758,29 @@ static int airoha_qdma_fill_rx_queue(struct airoha_queue *q)
int offset;
u32 val;
- page = page_pool_dev_alloc_frag(q->page_pool, &offset,
- q->buf_size);
- if (!page)
- break;
+ if (q->rx_coherent) {
+ /* Coherent slots avoid page_pool recycling for SOE frames. */
+ offset = q->head * q->buf_size;
+ e->buf = q->rx_coherent_buf + offset;
+ e->dma_addr = q->rx_coherent_dma + offset;
+ e->dma_len = q->buf_size;
+ } else {
+ page = page_pool_dev_alloc_frag(q->page_pool, &offset,
+ q->buf_size);
+ if (!page)
+ break;
+
+ offset += AIROHA_RX_HEADROOM;
+ e->buf = page_address(page) + offset;
+ e->dma_addr = page_pool_get_dma_addr(page) + offset;
+ e->dma_len =
+ SKB_WITH_OVERHEAD(AIROHA_RX_LEN(q->buf_size));
+ }
q->head = (q->head + 1) % q->ndesc;
q->queued++;
nframes++;
- offset += AIROHA_RX_HEADROOM;
- e->buf = page_address(page) + offset;
- e->dma_addr = page_pool_get_dma_addr(page) + offset;
- e->dma_len = SKB_WITH_OVERHEAD(AIROHA_RX_LEN(q->buf_size));
-
val = FIELD_PREP(QDMA_DESC_LEN_MASK, e->dma_len);
WRITE_ONCE(desc->ctrl, cpu_to_le32(val));
WRITE_ONCE(desc->addr, cpu_to_le32(e->dma_addr));
@@ -652,92 +822,210 @@ airoha_qdma_get_gdm_dev(struct airoha_eth *eth, struct airoha_qdma_desc *desc)
return port->devs[d] ? port->devs[d] : ERR_PTR(-ENODEV);
}
+#if IS_REACHABLE(CONFIG_NET_AIROHA_SOE)
+static bool airoha_qdma_rx_is_soe(u32 msg0)
+{
+ u32 hop_flags = FIELD_GET(QDMA_ETH_RXMSG_HOP_FLAGS_MASK, msg0);
+
+ return hop_flags >= 3 && hop_flags <= 7;
+}
+#endif
+
static int airoha_qdma_rx_process(struct airoha_queue *q, int budget)
{
- enum dma_data_direction dir = page_pool_get_dma_dir(q->page_pool);
+ enum dma_data_direction dir;
struct airoha_qdma *qdma = q->qdma;
struct airoha_eth *eth = qdma->eth;
int qid = q - &qdma->q_rx[0];
+ int desc_budget = q->ndesc;
+ int desc_done = 0;
int done = 0;
- while (done < budget) {
+ dir = q->rx_coherent ? DMA_FROM_DEVICE :
+ page_pool_get_dma_dir(q->page_pool);
+
+#if IS_REACHABLE(CONFIG_NET_AIROHA_SOE)
+ if (airoha_soe_rx_poll_desc_budget > 0)
+ desc_budget = min(airoha_soe_rx_poll_desc_budget, q->ndesc);
+#endif
+
+ while (q->queued > 0 && done < budget && desc_done < desc_budget) {
struct airoha_queue_entry *e = &q->entry[q->tail];
struct airoha_qdma_desc *desc = &q->desc[q->tail];
- u32 hash, reason, msg1, desc_ctrl;
- struct airoha_gdm_dev *dev;
+ u32 hash, reason, msg0, msg1, msg2, desc_ctrl;
+#if IS_REACHABLE(CONFIG_NET_AIROHA_SOE)
+ /* Scattered SOE completions only tag the first descriptor. */
+ bool partial_soe = q->skb && !q->skb->dev;
+#endif
+ struct airoha_gdm_dev *dev = NULL;
+ struct net_device *rx_dev = NULL;
struct net_device *netdev;
+ bool soe_pkt = false;
int data_len, len;
- struct page *page;
+ struct page *page = NULL;
desc_ctrl = le32_to_cpu(READ_ONCE(desc->ctrl));
if (!(desc_ctrl & QDMA_DESC_DONE_MASK))
break;
dma_rmb();
+ desc_done++;
q->tail = (q->tail + 1) % q->ndesc;
q->queued--;
- dma_sync_single_for_cpu(eth->dev, e->dma_addr, e->dma_len,
- dir);
+ if (!q->rx_coherent)
+ dma_sync_single_for_cpu(eth->dev, e->dma_addr,
+ e->dma_len, dir);
+
+ if (!q->rx_coherent)
+ page = virt_to_head_page(e->buf);
+
+ if (q->rx_drop_chain) {
+ if (!FIELD_GET(QDMA_DESC_MORE_MASK, desc_ctrl)) {
+ q->rx_drop_chain = false;
+ q->rx_frame_descs = 0;
+ done++;
+ }
+ if (!q->rx_coherent)
+ page_pool_put_full_page(q->page_pool, page,
+ true);
+ continue;
+ }
- page = virt_to_head_page(e->buf);
len = FIELD_GET(QDMA_DESC_LEN_MASK, desc_ctrl);
- data_len = q->skb ? AIROHA_RX_LEN(q->buf_size) : e->dma_len;
+ data_len = q->skb && !q->rx_coherent ?
+ AIROHA_RX_LEN(q->buf_size) :
+ e->dma_len;
if (!len || data_len < len)
goto free_frag;
- dev = airoha_qdma_get_gdm_dev(eth, desc);
- if (IS_ERR(dev))
- goto free_frag;
+ msg0 = le32_to_cpu(READ_ONCE(desc->msg0));
+ msg1 = le32_to_cpu(READ_ONCE(desc->msg1));
+ msg2 = le32_to_cpu(READ_ONCE(desc->msg2));
+#if IS_REACHABLE(CONFIG_NET_AIROHA_SOE)
+ soe_pkt = partial_soe || airoha_qdma_rx_is_soe(msg0);
+#endif
+ if (!soe_pkt) {
+ dev = airoha_qdma_get_gdm_dev(eth, desc);
+ if (IS_ERR(dev))
+ goto free_frag;
+ netdev = netdev_from_priv(dev);
+ rx_dev = netdev;
+ }
- netdev = netdev_from_priv(dev);
if (!q->skb) { /* first buffer */
- q->skb = napi_build_skb(e->buf - AIROHA_RX_HEADROOM,
- q->buf_size);
+ if (q->rx_coherent) {
+ q->skb = napi_alloc_skb(&q->napi, len);
+ if (q->skb)
+ skb_put_data(q->skb, e->buf, len);
+ } else {
+ void *buf = e->buf - AIROHA_RX_HEADROOM;
+
+ q->skb = napi_build_skb(buf, q->buf_size);
+ }
if (!q->skb)
goto free_frag;
- skb_reserve(q->skb, AIROHA_RX_HEADROOM);
- __skb_put(q->skb, len);
- skb_mark_for_recycle(q->skb);
- q->skb->dev = netdev;
- q->skb->protocol = eth_type_trans(q->skb, netdev);
- q->skb->ip_summed = CHECKSUM_UNNECESSARY;
+ q->rx_drop_chain = false;
+ q->rx_frame_descs = 1;
+ if (!q->rx_coherent) {
+ skb_reserve(q->skb, AIROHA_RX_HEADROOM);
+ __skb_put(q->skb, len);
+ skb_mark_for_recycle(q->skb);
+ }
+ q->skb->dev = soe_pkt ? NULL : netdev;
+ q->skb->ip_summed = soe_pkt ? CHECKSUM_NONE :
+ CHECKSUM_UNNECESSARY;
skb_record_rx_queue(q->skb, qid);
+ if (soe_pkt) {
+ q->soe_rx_msg0 = msg0;
+ q->soe_rx_msg2 = msg2;
+ }
+ if (!soe_pkt)
+ q->skb->protocol = eth_type_trans(q->skb,
+ netdev);
} else { /* scattered frame */
- struct skb_shared_info *shinfo = skb_shinfo(q->skb);
- int nr_frags = shinfo->nr_frags;
-
- if (nr_frags >= ARRAY_SIZE(shinfo->frags))
+#if IS_REACHABLE(CONFIG_NET_AIROHA_SOE)
+ if (soe_pkt && airoha_soe_rx_max_frame_descs > 0 &&
+ q->rx_frame_descs >=
+ airoha_soe_rx_max_frame_descs) {
+ q->rx_drop_chain =
+ FIELD_GET(QDMA_DESC_MORE_MASK, desc_ctrl);
goto free_frag;
-
- skb_add_rx_frag(q->skb, nr_frags, page,
- e->buf - page_address(page), len,
- q->buf_size);
+ }
+#endif
+ q->rx_frame_descs++;
+ if (q->rx_coherent) {
+ if (skb_tailroom(q->skb) < len) {
+ unsigned int needed;
+
+ needed = len - skb_tailroom(q->skb);
+ if (pskb_expand_head(q->skb, 0, needed,
+ GFP_ATOMIC))
+ goto free_frag;
+ }
+ skb_put_data(q->skb, e->buf, len);
+ } else {
+ struct skb_shared_info *shinfo =
+ skb_shinfo(q->skb);
+ int nr_frags = shinfo->nr_frags;
+
+ if (nr_frags >= ARRAY_SIZE(shinfo->frags))
+ goto free_frag;
+
+ skb_add_rx_frag(q->skb, nr_frags, page,
+ e->buf - page_address(page),
+ len, q->buf_size);
+ }
}
if (FIELD_GET(QDMA_DESC_MORE_MASK, desc_ctrl))
continue;
+ q->rx_drop_chain = false;
+ q->rx_frame_descs = 0;
+#if IS_REACHABLE(CONFIG_NET_AIROHA_SOE)
+ if (soe_pkt) {
+ u32 hop_flags = FIELD_GET(QDMA_ETH_RXMSG_HOP_FLAGS_MASK,
+ q->soe_rx_msg0);
+ u32 sa_index = FIELD_GET(QDMA_ETH_RXMSG_SW_UDF_MASK,
+ q->soe_rx_msg2);
+
+ done++;
+ if (!airoha_soe_rx_skb(eth->soe, q->skb, sa_index,
+ hop_flags))
+ dev_kfree_skb(q->skb);
+ q->skb = NULL;
+ continue;
+ }
+#endif
+
if (netdev_uses_dsa(netdev)) {
struct airoha_gdm_port *port = dev->port;
+ struct dsa_port *cpu_dp = netdev->dsa_ptr;
+ u32 sptag = FIELD_GET(QDMA_ETH_RXMSG_SPTAG, msg0);
/* PPE module requires untagged packets to work
* properly and it provides DSA port index via the
* DMA descriptor. Report DSA tag to the DSA stack
* via skb dst info.
*/
- u32 msg0 = le32_to_cpu(READ_ONCE(desc->msg0));
- u32 sptag = FIELD_GET(QDMA_ETH_RXMSG_SPTAG, msg0);
-
if (sptag < ARRAY_SIZE(port->dsa_meta) &&
port->dsa_meta[sptag])
skb_dst_set_noref(q->skb,
&port->dsa_meta[sptag]->dst);
+
+ if (cpu_dp && cpu_dp->ds) {
+ struct dsa_port *dp =
+ dsa_to_port(cpu_dp->ds, sptag);
+
+ if (dp && dsa_port_is_user(dp) &&
+ dp->cpu_dp == cpu_dp && dp->user)
+ rx_dev = dp->user;
+ }
}
- msg1 = le32_to_cpu(READ_ONCE(desc->msg1));
hash = FIELD_GET(AIROHA_RXD4_FOE_ENTRY, msg1);
if (hash != AIROHA_RXD4_FOE_ENTRY)
skb_set_hash(q->skb, jhash_1word(hash, 0),
@@ -749,18 +1037,54 @@ static int airoha_qdma_rx_process(struct airoha_queue *q, int budget)
false);
done++;
+#if IS_REACHABLE(CONFIG_NET_AIROHA_SOE)
+ /* Native ESP/NAT-T packets enter through the normal RX path
+ * first. If they match an inbound packet-offload SA, consume
+ * the encrypted skb here and resubmit it to SOE before GRO
+ * takes ownership of the packet. SOE decrypts the original
+ * ESP/NAT-T packet; after GRO or the normal RX stack processes
+ * the skb, it is no longer a suitable hardware decrypt
+ * candidate. Keep the RX FOE hash/reason so the decrypt
+ * completion can later bind the PPE flow after egress is known.
+ */
+ if (hash != AIROHA_RXD4_FOE_ENTRY) {
+ bool foe_valid = false;
+
+ if (reason < 32)
+ foe_valid = AIROHA_SOE_DECRYPT_FOE_REASON_MASK &
+ BIT(reason);
+ if (airoha_soe_rx_plain_skb(dev, q->skb, rx_dev, hash,
+ reason, foe_valid)) {
+ q->skb = NULL;
+ continue;
+ }
+ } else if (airoha_soe_rx_plain_skb(dev, q->skb, rx_dev, hash,
+ reason, false)) {
+ q->skb = NULL;
+ continue;
+ }
+#endif
napi_gro_receive(&q->napi, q->skb);
q->skb = NULL;
continue;
free_frag:
+ q->rx_drop_chain = !!FIELD_GET(QDMA_DESC_MORE_MASK, desc_ctrl);
+ q->rx_frame_descs = 0;
+ done++;
if (q->skb) {
dev_kfree_skb(q->skb);
q->skb = NULL;
}
- page_pool_put_full_page(q->page_pool, page, true);
+ if (!q->rx_coherent)
+ page_pool_put_full_page(q->page_pool, page, true);
}
airoha_qdma_fill_rx_queue(q);
+#if IS_REACHABLE(CONFIG_NET_AIROHA_SOE)
+ if (desc_done && !done)
+ return 1;
+#endif
+
return done;
}
@@ -776,17 +1100,9 @@ static int airoha_qdma_rx_napi_poll(struct napi_struct *napi, int budget)
if (done < budget && napi_complete(napi)) {
struct airoha_qdma *qdma = q->qdma;
- int i, qid = q - &qdma->q_rx[0];
- int intr_reg = qid < RX_DONE_HIGH_OFFSET ? QDMA_INT_REG_IDX1
- : QDMA_INT_REG_IDX2;
-
- for (i = 0; i < ARRAY_SIZE(qdma->irq_banks); i++) {
- if (!(BIT(qid) & RX_IRQ_BANK_PIN_MASK(i)))
- continue;
+ int qid = q - &qdma->q_rx[0];
- airoha_qdma_irq_enable(&qdma->irq_banks[i], intr_reg,
- BIT(qid % RX_DONE_HIGH_OFFSET));
- }
+ airoha_qdma_set_rx_done_irq(qdma, qid, true);
}
return done;
@@ -795,7 +1111,7 @@ static int airoha_qdma_rx_napi_poll(struct napi_struct *napi, int budget)
static int airoha_qdma_init_rx_queue(struct airoha_queue *q,
struct airoha_qdma *qdma, int ndesc)
{
- const struct page_pool_params pp_params = {
+ struct page_pool_params pp_params = {
.order = 0,
.pool_size = 256,
.flags = PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV,
@@ -809,8 +1125,21 @@ static int airoha_qdma_init_rx_queue(struct airoha_queue *q,
int qid = q - &qdma->q_rx[0], thr;
dma_addr_t dma_addr;
+#if IS_REACHABLE(CONFIG_NET_AIROHA_SOE)
+ if (qid == AIROHA_SOE_RX_RING) {
+ ndesc = max(ndesc, AIROHA_SOE_RX_ALLOC_NDESC);
+ if (airoha_soe_probe_rx_ndesc > 0)
+ ndesc = clamp(airoha_soe_probe_rx_ndesc, 1,
+ AIROHA_SOE_RX_ALLOC_NDESC);
+ }
+#endif
+
q->buf_size = PAGE_SIZE / 2;
q->qdma = qdma;
+#if IS_REACHABLE(CONFIG_NET_AIROHA_SOE)
+ if (qid == AIROHA_SOE_RX_RING)
+ q->rx_coherent = airoha_soe_probe_rx_coherent;
+#endif
q->entry = devm_kzalloc(eth->dev, ndesc * sizeof(*q->entry),
GFP_KERNEL);
@@ -821,19 +1150,45 @@ static int airoha_qdma_init_rx_queue(struct airoha_queue *q,
&dma_addr, GFP_KERNEL);
if (!q->desc)
return -ENOMEM;
+ q->desc_dma = dma_addr;
- q->page_pool = page_pool_create(&pp_params);
- if (IS_ERR(q->page_pool)) {
- int err = PTR_ERR(q->page_pool);
+ if (!q->rx_coherent) {
+ q->page_pool = page_pool_create(&pp_params);
+ if (IS_ERR(q->page_pool)) {
+ int err = PTR_ERR(q->page_pool);
- q->page_pool = NULL;
- return err;
+ q->page_pool = NULL;
+ return err;
+ }
+ }
+
+#if IS_REACHABLE(CONFIG_NET_AIROHA_SOE)
+ if (qid == AIROHA_SOE_RX_RING) {
+ size_t buf_size;
+ int max_buf_size;
+
+ q->rx_alloc_ndesc = ndesc;
+ max_buf_size = q->rx_coherent ? AIROHA_SOE_RX_BUF_SIZE_MAX :
+ AIROHA_SOE_RX_BUF_SIZE;
+ q->buf_size = clamp(airoha_soe_probe_rx_buf_size,
+ AIROHA_SOE_RX_BUF_SIZE_MIN, max_buf_size);
+ if (q->rx_coherent) {
+ buf_size = q->buf_size * ndesc;
+ q->rx_coherent_buf =
+ dmam_alloc_coherent(eth->dev, buf_size,
+ &q->rx_coherent_dma,
+ GFP_KERNEL);
+ if (!q->rx_coherent_buf)
+ return -ENOMEM;
+ q->rx_coherent_buf_size = buf_size;
+ }
}
+#endif
q->ndesc = ndesc;
netif_napi_add(eth->napi_dev, &q->napi, airoha_qdma_rx_napi_poll);
- airoha_qdma_wr(qdma, REG_RX_RING_BASE(qid), dma_addr);
+ airoha_qdma_wr(qdma, REG_RX_RING_BASE(qid), q->desc_dma);
airoha_qdma_rmw(qdma, REG_RX_RING_SIZE(qid),
RX_RING_SIZE_MASK,
FIELD_PREP(RX_RING_SIZE_MASK, ndesc));
@@ -843,7 +1198,14 @@ static int airoha_qdma_init_rx_queue(struct airoha_queue *q,
FIELD_PREP(RX_RING_THR_MASK, thr));
airoha_qdma_rmw(qdma, REG_RX_DMA_IDX(qid), RX_RING_DMA_IDX_MASK,
FIELD_PREP(RX_RING_DMA_IDX_MASK, q->head));
- airoha_qdma_set(qdma, REG_RX_SCATTER_CFG(qid), RX_RING_SG_EN_MASK);
+#if IS_REACHABLE(CONFIG_NET_AIROHA_SOE)
+ if (qid == AIROHA_SOE_RX_RING && !airoha_soe_probe_rx_scatter)
+ airoha_qdma_clear(qdma, REG_RX_SCATTER_CFG(qid),
+ RX_RING_SG_EN_MASK);
+ else
+#endif
+ airoha_qdma_set(qdma, REG_RX_SCATTER_CFG(qid),
+ RX_RING_SG_EN_MASK);
airoha_qdma_fill_rx_queue(q);
@@ -859,11 +1221,14 @@ static void airoha_qdma_cleanup_rx_queue(struct airoha_queue *q)
while (q->queued) {
struct airoha_queue_entry *e = &q->entry[q->tail];
struct airoha_qdma_desc *desc = &q->desc[q->tail];
- struct page *page = virt_to_head_page(e->buf);
- dma_sync_single_for_cpu(eth->dev, e->dma_addr, e->dma_len,
- page_pool_get_dma_dir(q->page_pool));
- page_pool_put_full_page(q->page_pool, page, false);
+ if (!q->rx_coherent) {
+ struct page *page = virt_to_head_page(e->buf);
+
+ dma_sync_single_for_cpu(eth->dev, e->dma_addr, e->dma_len,
+ page_pool_get_dma_dir(q->page_pool));
+ page_pool_put_full_page(q->page_pool, page, false);
+ }
/* Reset DMA descriptor */
WRITE_ONCE(desc->ctrl, 0);
WRITE_ONCE(desc->addr, 0);
@@ -1045,8 +1410,24 @@ static int airoha_qdma_tx_napi_poll(struct napi_struct *napi, int budget)
airoha_qdma_rmw(qdma, REG_IRQ_CLEAR_LEN(id),
IRQ_CLEAR_LEN_MASK, 0x80);
airoha_qdma_rmw(qdma, REG_IRQ_CLEAR_LEN(id),
- IRQ_CLEAR_LEN_MASK, (done & 0x7f));
+ IRQ_CLEAR_LEN_MASK,
+ (done & 0x7f));
+ }
+
+#if IS_REACHABLE(CONFIG_NET_AIROHA_SOE)
+ if (done && airoha_soe_has_pending_rx(eth->soe)) {
+ int i;
+
+ /* SOE decrypt completions can lag behind TX cleanup IRQs. */
+ for (i = 0; i < ARRAY_SIZE(eth->qdma); i++) {
+ struct airoha_queue *rxq =
+ ð->qdma[i].q_rx[AIROHA_SOE_RX_RING];
+
+ if (rxq->ndesc)
+ napi_schedule(&rxq->napi);
+ }
}
+#endif
if (done < budget && napi_complete(napi))
airoha_qdma_irq_enable(&qdma->irq_banks[0], QDMA_INT_REG_IDX0,
@@ -1346,16 +1727,11 @@ static int airoha_qdma_hw_init(struct airoha_qdma *qdma)
for (i = 0; i < ARRAY_SIZE(qdma->irq_banks); i++) {
/* clear pending irqs */
airoha_qdma_wr(qdma, REG_INT_STATUS(i), 0xffffffff);
- /* setup rx irqs */
- airoha_qdma_irq_enable(&qdma->irq_banks[i], QDMA_INT_REG_IDX0,
- INT_RX0_MASK(RX_IRQ_BANK_PIN_MASK(i)));
- airoha_qdma_irq_enable(&qdma->irq_banks[i], QDMA_INT_REG_IDX1,
- INT_RX1_MASK(RX_IRQ_BANK_PIN_MASK(i)));
- airoha_qdma_irq_enable(&qdma->irq_banks[i], QDMA_INT_REG_IDX2,
- INT_RX2_MASK(RX_IRQ_BANK_PIN_MASK(i)));
- airoha_qdma_irq_enable(&qdma->irq_banks[i], QDMA_INT_REG_IDX3,
- INT_RX3_MASK(RX_IRQ_BANK_PIN_MASK(i)));
}
+ airoha_qdma_apply_rx_irq_bank_masks(qdma);
+#if IS_REACHABLE(CONFIG_NET_AIROHA_SOE)
+ airoha_qdma_set_rx_done_irq(qdma, AIROHA_SOE_RX_RING, true);
+#endif
/* setup tx irqs */
airoha_qdma_irq_enable(&qdma->irq_banks[0], QDMA_INT_REG_IDX0,
TX_COHERENT_LOW_INT_MASK | INT_TX_MASK);
@@ -2176,6 +2552,110 @@ int airoha_get_fe_port(struct airoha_gdm_dev *dev)
}
}
+#if IS_REACHABLE(CONFIG_NET_AIROHA_SOE)
+int airoha_qdma_xmit_skb(struct airoha_gdm_dev *dev, struct sk_buff *skb,
+ u32 msg0, u32 msg1, u32 msg2)
+{
+ struct net_device *netdev = netdev_from_priv(dev);
+ struct airoha_qdma *qdma = dev->qdma;
+ u32 nr_frags, len;
+ struct airoha_queue_entry *e;
+ struct netdev_queue *txq;
+ struct airoha_queue *q;
+ LIST_HEAD(tx_list);
+ int i = 0, qid;
+ void *data;
+ u16 index;
+
+ qid = airoha_qdma_get_txq(qdma, skb_get_queue_mapping(skb));
+ q = &qdma->q_tx[qid];
+ if (WARN_ON_ONCE(!q->ndesc))
+ return -ENODEV;
+
+ spin_lock_bh(&q->lock);
+
+ txq = skb_get_tx_queue(netdev, skb);
+ nr_frags = 1 + skb_shinfo(skb)->nr_frags;
+ if (q->queued + nr_frags >= q->ndesc) {
+ netif_tx_stop_queue(txq);
+ q->txq_stopped = true;
+ spin_unlock_bh(&q->lock);
+ return -EBUSY;
+ }
+
+ len = skb_headlen(skb);
+ data = skb->data;
+
+ e = list_first_entry(&q->tx_list, struct airoha_queue_entry, list);
+ index = e - q->entry;
+
+ while (true) {
+ struct airoha_qdma_desc *desc = &q->desc[index];
+ skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+ dma_addr_t addr;
+ u32 val;
+
+ addr = dma_map_single(netdev->dev.parent, data, len,
+ DMA_TO_DEVICE);
+ if (unlikely(dma_mapping_error(netdev->dev.parent, addr)))
+ goto error_unmap;
+
+ list_move_tail(&e->list, &tx_list);
+ e->skb = i == nr_frags - 1 ? skb : NULL;
+ e->dma_addr = addr;
+ e->dma_len = len;
+
+ e = list_first_entry(&q->tx_list, struct airoha_queue_entry,
+ list);
+ index = e - q->entry;
+
+ val = FIELD_PREP(QDMA_DESC_LEN_MASK, len);
+ if (i < nr_frags - 1)
+ val |= FIELD_PREP(QDMA_DESC_MORE_MASK, 1);
+ WRITE_ONCE(desc->ctrl, cpu_to_le32(val));
+ WRITE_ONCE(desc->addr, cpu_to_le32(addr));
+ val = FIELD_PREP(QDMA_DESC_NEXT_ID_MASK, index);
+ WRITE_ONCE(desc->data, cpu_to_le32(val));
+ WRITE_ONCE(desc->msg0, cpu_to_le32(msg0));
+ WRITE_ONCE(desc->msg1, cpu_to_le32(msg1));
+ WRITE_ONCE(desc->msg2, cpu_to_le32(msg2));
+
+ if (++i == nr_frags)
+ break;
+
+ data = skb_frag_address(frag);
+ len = skb_frag_size(frag);
+ }
+ q->queued += i;
+
+ skb_tx_timestamp(skb);
+ netdev_tx_sent_queue(txq, skb->len);
+ if (q->ndesc - q->queued < q->free_thr) {
+ netif_tx_stop_queue(txq);
+ q->txq_stopped = true;
+ }
+
+ /* SOE submits do not run in the regular ndo_start_xmit batching path. */
+ airoha_qdma_rmw(qdma, REG_TX_CPU_IDX(qid), TX_RING_CPU_IDX_MASK,
+ FIELD_PREP(TX_RING_CPU_IDX_MASK, index));
+
+ spin_unlock_bh(&q->lock);
+
+ return 0;
+
+error_unmap:
+ list_for_each_entry(e, &tx_list, list) {
+ dma_unmap_single(netdev->dev.parent, e->dma_addr, e->dma_len,
+ DMA_TO_DEVICE);
+ e->dma_addr = 0;
+ }
+ list_splice(&tx_list, &q->tx_list);
+ spin_unlock_bh(&q->lock);
+
+ return -ENOMEM;
+}
+#endif
+
static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,
struct net_device *netdev)
{
@@ -2185,6 +2665,7 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,
struct airoha_queue_entry *e;
struct netdev_queue *txq;
struct airoha_queue *q;
+ bool soe_decrypt_skb = false;
LIST_HEAD(tx_list);
int i = 0, qid;
void *data;
@@ -2223,6 +2704,11 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,
FIELD_PREP(QDMA_ETH_TXMSG_FPORT_MASK, fport) |
FIELD_PREP(QDMA_ETH_TXMSG_METER_MASK, 0x7f);
+#if IS_REACHABLE(CONFIG_NET_AIROHA_SOE)
+ if (dev->eth->ppe)
+ soe_decrypt_skb = airoha_ppe_soe_skb_marked(skb);
+#endif
+
q = &qdma->q_tx[qid];
if (WARN_ON_ONCE(!q->ndesc))
goto error;
@@ -2293,13 +2779,24 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,
q->txq_stopped = true;
}
- if (netif_xmit_stopped(txq) || !netdev_xmit_more())
+ if (netif_xmit_stopped(txq) || !netdev_xmit_more() ||
+ soe_decrypt_skb)
airoha_qdma_rmw(qdma, REG_TX_CPU_IDX(qid),
TX_RING_CPU_IDX_MASK,
FIELD_PREP(TX_RING_CPU_IDX_MASK, index));
spin_unlock_bh(&q->lock);
+ /* SOE decrypt flow binding needs the final egress netdev and QDMA
+ * descriptor context. The SOE RX path marks only candidate packets; bind
+ * only after the current plaintext packet has been queued and kicked so
+ * the newly bound decrypt entry cannot race the CPU-transmitted packet.
+ */
+#if IS_REACHABLE(CONFIG_NET_AIROHA_SOE)
+ if (soe_decrypt_skb)
+ airoha_ppe_soe_xmit_skb(&dev->eth->ppe->dev, skb, netdev);
+#endif
+
return NETDEV_TX_OK;
error_unmap:
@@ -3096,6 +3593,12 @@ static int airoha_dev_tc_setup(struct net_device *dev,
}
}
+static int airoha_dev_set_features(struct net_device *netdev,
+ netdev_features_t features)
+{
+ return airoha_soe_set_features(netdev, features);
+}
+
static const struct net_device_ops airoha_netdev_ops = {
.ndo_init = airoha_dev_init,
.ndo_open = airoha_dev_open,
@@ -3105,6 +3608,7 @@ static const struct net_device_ops airoha_netdev_ops = {
.ndo_start_xmit = airoha_dev_xmit,
.ndo_get_stats64 = airoha_dev_get_stats64,
.ndo_set_mac_address = airoha_dev_set_macaddr,
+ .ndo_set_features = airoha_dev_set_features,
.ndo_setup_tc = airoha_dev_tc_setup,
};
@@ -3230,6 +3734,7 @@ static int airoha_alloc_gdm_device(struct airoha_eth *eth,
dev->eth = eth;
dev->nbq = nbq;
port->devs[index] = dev;
+ airoha_soe_build_netdev(netdev, airoha_qdma_xmit_skb);
return 0;
}
@@ -3409,10 +3914,14 @@ static int airoha_probe(struct platform_device *pdev)
strscpy(eth->napi_dev->name, "qdma_eth", sizeof(eth->napi_dev->name));
platform_set_drvdata(pdev, eth);
- err = airoha_hw_init(pdev, eth);
+ err = airoha_soe_init(eth);
if (err)
goto error_netdev_free;
+ err = airoha_hw_init(pdev, eth);
+ if (err)
+ goto error_soe_deinit;
+
for (i = 0; i < ARRAY_SIZE(eth->qdma); i++)
airoha_qdma_start_napi(ð->qdma[i]);
@@ -3457,11 +3966,14 @@ static int airoha_probe(struct platform_device *pdev)
netdev = netdev_from_priv(dev);
if (netdev->reg_state == NETREG_REGISTERED)
unregister_netdev(netdev);
+ airoha_soe_teardown_netdev(netdev);
of_node_put(netdev->dev.of_node);
}
airoha_metadata_dst_free(port);
}
airoha_hw_cleanup(eth);
+error_soe_deinit:
+ airoha_soe_deinit(eth);
error_netdev_free:
free_netdev(eth->napi_dev);
platform_set_drvdata(pdev, NULL);
@@ -3492,12 +4004,14 @@ static void airoha_remove(struct platform_device *pdev)
continue;
netdev = netdev_from_priv(dev);
+ airoha_soe_teardown_netdev(netdev);
unregister_netdev(netdev);
of_node_put(netdev->dev.of_node);
}
airoha_metadata_dst_free(port);
}
airoha_hw_cleanup(eth);
+ airoha_soe_deinit(eth);
free_netdev(eth->napi_dev);
platform_set_drvdata(pdev, NULL);
--
2.53.0
^ permalink raw reply related
* [RFC PATCH net-next 4/7] net: airoha: add SOE registers and driver state
From: Jihong Min @ 2026-06-14 4:00 UTC (permalink / raw)
To: netdev, Lorenzo Bianconi
Cc: David S . Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Andrew Lunn, Simon Horman, Herbert Xu, Steffen Klassert,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, devicetree,
Matthias Brugger, AngeloGioacchino Del Regno, linux-arm-kernel,
linux-mediatek, Christian Marangi, Felix Fietkau, linux-kernel,
Jihong Min
In-Reply-To: <20260614040032.1567994-1-hurryman2212@gmail.com>
Add the FE/PPE/QDMA register definitions and shared driver state needed
by the Secure Offload Engine. Add a small SOE-facing header with stubs so
later Ethernet and PPE changes remain buildable until the provider is
enabled.
Signed-off-by: Jihong Min <hurryman2212@gmail.com>
---
drivers/net/ethernet/airoha/airoha_eth.h | 40 +++++++
drivers/net/ethernet/airoha/airoha_regs.h | 16 +++
drivers/net/ethernet/airoha/airoha_soe.h | 126 ++++++++++++++++++++++
3 files changed, 182 insertions(+)
create mode 100644 drivers/net/ethernet/airoha/airoha_soe.h
diff --git a/drivers/net/ethernet/airoha/airoha_eth.h b/drivers/net/ethernet/airoha/airoha_eth.h
index 46b1c31939de..c5f09aedd7e7 100644
--- a/drivers/net/ethernet/airoha/airoha_eth.h
+++ b/drivers/net/ethernet/airoha/airoha_eth.h
@@ -16,6 +16,8 @@
#include <linux/soc/airoha/airoha_offload.h>
#include <net/dsa.h>
+struct airoha_soe;
+
#define AIROHA_MAX_NUM_GDM_PORTS 4
#define AIROHA_MAX_NUM_GDM_DEVS 2
#define AIROHA_MAX_NUM_QDMA 2
@@ -189,18 +191,31 @@ struct airoha_queue {
spinlock_t lock;
struct airoha_queue_entry *entry;
struct airoha_qdma_desc *desc;
+ /* Preserved for RX ring reprogramming; dmam_alloc_coherent() owns it. */
+ dma_addr_t desc_dma;
u16 head;
u16 tail;
int queued;
int ndesc;
+ /* SOE RX rings may use coherent slots instead of page_pool fragments. */
+ int rx_alloc_ndesc;
int free_thr;
int buf_size;
bool txq_stopped;
+ bool rx_coherent;
+ bool rx_drop_chain;
+ void *rx_coherent_buf;
+ dma_addr_t rx_coherent_dma;
+ size_t rx_coherent_buf_size;
struct napi_struct napi;
struct page_pool *page_pool;
struct sk_buff *skb;
+ /* First SOE descriptor metadata is kept while a scattered frame is built. */
+ int rx_frame_descs;
+ u32 soe_rx_msg0;
+ u32 soe_rx_msg2;
struct list_head tx_list;
};
@@ -434,6 +449,16 @@ struct airoha_foe_stats64 {
u64 packets;
};
+struct airoha_ppe_soe_meta {
+ unsigned long expires;
+ u32 key_hash;
+ u16 foe_hash;
+ u8 valid;
+ u8 sa_index;
+ u8 hop;
+ u8 seen;
+};
+
struct airoha_flow_data {
struct ethhdr eth;
@@ -552,6 +577,11 @@ struct airoha_gdm_dev {
u32 flags;
int nbq;
+ /* Prevent toggling NETIF_F_HW_ESP while programmed SAs still exist. */
+ atomic_t soe_xfrm_state_count;
+ /* Private SOE submit path into this GDM's active QDMA instance. */
+ int (*soe_xmit_skb)(struct airoha_gdm_dev *dev, struct sk_buff *skb,
+ u32 msg0, u32 msg1, u32 msg2);
struct airoha_hw_stats stats;
};
@@ -581,6 +611,7 @@ struct airoha_ppe {
struct hlist_head *foe_flow;
u16 *foe_check_time;
+ struct airoha_ppe_soe_meta *soe_meta;
struct airoha_foe_stats *foe_stats;
dma_addr_t foe_stats_dma;
@@ -621,6 +652,7 @@ struct airoha_eth {
struct airoha_qdma qdma[AIROHA_MAX_NUM_QDMA];
struct airoha_gdm_port *ports[AIROHA_MAX_NUM_GDM_PORTS];
+ struct airoha_soe *soe;
};
u32 airoha_rr(void __iomem *base, u32 offset);
@@ -676,6 +708,14 @@ static inline bool airoha_is_7583(struct airoha_eth *eth)
int airoha_get_fe_port(struct airoha_gdm_dev *dev);
bool airoha_is_valid_gdm_dev(struct airoha_eth *eth,
struct airoha_gdm_dev *dev);
+int airoha_qdma_xmit_skb(struct airoha_gdm_dev *dev, struct sk_buff *skb,
+ u32 msg0, u32 msg1, u32 msg2);
+void airoha_ppe_soe_mark_skb(struct airoha_ppe_dev *dev, struct sk_buff *skb,
+ u16 hash, u8 sa_index, u8 hop);
+bool airoha_ppe_soe_skb_marked(struct sk_buff *skb);
+void airoha_ppe_soe_xmit_skb(struct airoha_ppe_dev *dev, struct sk_buff *skb,
+ struct net_device *netdev);
+void airoha_ppe_soe_flush_sa(struct airoha_ppe *ppe, u8 sa_index);
void airoha_ppe_set_cpu_port(struct airoha_gdm_dev *dev, u8 ppe_id, u8 fport);
bool airoha_ppe_is_enabled(struct airoha_eth *eth, int index);
diff --git a/drivers/net/ethernet/airoha/airoha_regs.h b/drivers/net/ethernet/airoha/airoha_regs.h
index 436f3c8779c1..27e158d0fa4b 100644
--- a/drivers/net/ethernet/airoha/airoha_regs.h
+++ b/drivers/net/ethernet/airoha/airoha_regs.h
@@ -82,6 +82,10 @@
#define PSE_SHARE_USED_MTHD_MASK GENMASK(31, 16)
#define PSE_SHARE_USED_HTHD_MASK GENMASK(15, 0)
+/* TDMA/SOE port 7 needs shared-buffer flow control enabled in the PSE. */
+#define REG_PSE_FC_CFG 0x0098
+#define PSE_TDMA_SHARE_BUF_DIS_MASK BIT(23)
+
#define REG_GDM_MISC_CFG 0x0148
#define GDM2_RDM_ACK_WAIT_PREF_MASK BIT(9)
#define GDM2_CHN_VLD_MODE_MASK BIT(5)
@@ -252,6 +256,8 @@
#define PPE_GLO_CFG_EN_MASK BIT(0)
#define REG_PPE_PPE_FLOW_CFG(_n) (((_n) ? PPE2_BASE : PPE1_BASE) + 0x204)
+#define PPE_FLOW_CFG_IP6_IPSEC_MASK BIT(28)
+#define PPE_FLOW_CFG_IP4_IPSEC_MASK BIT(27)
#define PPE_FLOW_CFG_IP6_HASH_GRE_KEY_MASK BIT(20)
#define PPE_FLOW_CFG_IP4_HASH_GRE_KEY_MASK BIT(19)
#define PPE_FLOW_CFG_IP4_HASH_FLOW_LABEL_MASK BIT(18)
@@ -851,6 +857,8 @@
#define QDMA_DESC_NEXT_ID_MASK GENMASK(15, 0)
/* TX MSG0 */
#define QDMA_ETH_TXMSG_MIC_IDX_MASK BIT(30)
+/* SOE submit metadata: msg0 carries SA index, msg1 selects port 7 OQ8/OQ9. */
+#define QDMA_ETH_TXMSG_SOE_SA_MASK GENMASK(29, 24)
#define QDMA_ETH_TXMSG_SP_TAG_MASK GENMASK(29, 14)
#define QDMA_ETH_TXMSG_ICO_MASK BIT(13)
#define QDMA_ETH_TXMSG_UCO_MASK BIT(12)
@@ -873,6 +881,11 @@
/* RX MSG0 */
#define QDMA_ETH_RXMSG_SPTAG GENMASK(21, 14)
+/* SOE completion metadata can use the full 16-bit SP tag word. */
+#define QDMA_ETH_RXMSG_SPTAG_FULL GENMASK(29, 14)
+/* SOE completion metadata returned by the QDMA RX descriptor. */
+#define QDMA_ETH_RXMSG_SOE_MASK BIT(10)
+#define QDMA_ETH_RXMSG_HOP_FLAGS_MASK GENMASK(2, 0)
/* RX MSG1 */
#define QDMA_ETH_RXMSG_DEI_MASK BIT(31)
#define QDMA_ETH_RXMSG_IP6_MASK BIT(30)
@@ -883,6 +896,9 @@
#define QDMA_ETH_RXMSG_SPORT_MASK GENMASK(25, 21)
#define QDMA_ETH_RXMSG_CRSN_MASK GENMASK(20, 16)
#define QDMA_ETH_RXMSG_PPE_ENTRY_MASK GENMASK(15, 0)
+/* RX MSG2 */
+/* SW_UDF carries the SA index for SOE completion frames. */
+#define QDMA_ETH_RXMSG_SW_UDF_MASK GENMASK(31, 24)
struct airoha_qdma_desc {
__le32 rsv;
diff --git a/drivers/net/ethernet/airoha/airoha_soe.h b/drivers/net/ethernet/airoha/airoha_soe.h
new file mode 100644
index 000000000000..0bde2e9c6b5b
--- /dev/null
+++ b/drivers/net/ethernet/airoha/airoha_soe.h
@@ -0,0 +1,126 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Ethernet-facing declarations for the Airoha Secure Offload Engine (SOE)
+ * packet offload provider.
+ *
+ * airoha_eth owns SOE lifetime and calls these helpers to expose xfrm
+ * ESP/NAT-T offload on its netdevs. When CONFIG_NET_AIROHA_SOE is disabled,
+ * the stubs keep the Ethernet driver buildable without SOE support.
+ */
+
+#ifndef AIROHA_SOE_H
+#define AIROHA_SOE_H
+
+#include <linux/bitops.h>
+#include <linux/errno.h>
+#include <linux/kconfig.h>
+#include <linux/netdev_features.h>
+#include <linux/types.h>
+
+struct airoha_soe;
+struct airoha_soe_sa;
+struct airoha_eth;
+struct airoha_gdm_dev;
+struct device;
+struct dst_entry;
+struct net_device;
+struct netlink_ext_ack;
+struct sk_buff;
+struct xfrm_state;
+
+#define AIROHA_SOE_FEATURE_ESP BIT(0)
+
+typedef int (*airoha_soe_xmit_skb_t)(struct airoha_gdm_dev *dev,
+ struct sk_buff *skb, u32 msg0, u32 msg1,
+ u32 msg2);
+
+#if IS_ENABLED(CONFIG_NET_AIROHA_SOE)
+int airoha_soe_init(struct airoha_eth *eth);
+void airoha_soe_deinit(struct airoha_eth *eth);
+bool airoha_soe_available(struct airoha_soe *soe);
+u32 airoha_soe_features(struct airoha_soe *soe);
+void airoha_soe_build_netdev(struct net_device *dev,
+ airoha_soe_xmit_skb_t xmit_skb);
+void airoha_soe_teardown_netdev(struct net_device *dev);
+int airoha_soe_set_features(struct net_device *dev,
+ netdev_features_t features);
+bool airoha_soe_rx_skb(struct airoha_soe *soe, struct sk_buff *skb,
+ unsigned int sa_index, u32 hop_flags);
+bool airoha_soe_rx_plain_skb(struct airoha_gdm_dev *dev,
+ struct sk_buff *skb, struct net_device *rx_dev,
+ u16 foe_hash, u32 foe_reason, bool foe_valid);
+bool airoha_soe_has_pending_rx(struct airoha_soe *soe);
+int airoha_soe_xfrm_ppe_info(const struct dst_entry *dst, u8 *sa_index,
+ u8 *hop);
+int airoha_soe_xmit(struct airoha_soe_sa *sa, struct airoha_gdm_dev *dev,
+ struct sk_buff *skb, struct xfrm_state *x);
+#else
+static inline int airoha_soe_init(struct airoha_eth *eth)
+{
+ return 0;
+}
+
+static inline void airoha_soe_deinit(struct airoha_eth *eth)
+{
+}
+
+static inline bool airoha_soe_available(struct airoha_soe *soe)
+{
+ return false;
+}
+
+static inline u32 airoha_soe_features(struct airoha_soe *soe)
+{
+ return 0;
+}
+
+static inline void airoha_soe_build_netdev(struct net_device *dev,
+ airoha_soe_xmit_skb_t xmit_skb)
+{
+}
+
+static inline void airoha_soe_teardown_netdev(struct net_device *dev)
+{
+}
+
+static inline int airoha_soe_set_features(struct net_device *dev,
+ netdev_features_t features)
+{
+ return 0;
+}
+
+static inline bool airoha_soe_rx_skb(struct airoha_soe *soe,
+ struct sk_buff *skb,
+ unsigned int sa_index, u32 hop_flags)
+{
+ return false;
+}
+
+static inline bool airoha_soe_rx_plain_skb(struct airoha_gdm_dev *dev,
+ struct sk_buff *skb,
+ struct net_device *rx_dev,
+ u16 foe_hash, u32 foe_reason,
+ bool foe_valid)
+{
+ return false;
+}
+
+static inline bool airoha_soe_has_pending_rx(struct airoha_soe *soe)
+{
+ return false;
+}
+
+static inline int airoha_soe_xfrm_ppe_info(const struct dst_entry *dst,
+ u8 *sa_index, u8 *hop)
+{
+ return -EOPNOTSUPP;
+}
+
+static inline int airoha_soe_xmit(struct airoha_soe_sa *sa,
+ struct airoha_gdm_dev *dev,
+ struct sk_buff *skb, struct xfrm_state *x)
+{
+ return -EOPNOTSUPP;
+}
+#endif
+
+#endif /* AIROHA_SOE_H */
--
2.53.0
^ permalink raw reply related
* [RFC PATCH net-next 3/7] arm64: dts: airoha: add EN7581 SOE node
From: Jihong Min @ 2026-06-14 4:00 UTC (permalink / raw)
To: netdev, Lorenzo Bianconi
Cc: David S . Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Andrew Lunn, Simon Horman, Herbert Xu, Steffen Klassert,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, devicetree,
Matthias Brugger, AngeloGioacchino Del Regno, linux-arm-kernel,
linux-mediatek, Christian Marangi, Felix Fietkau, linux-kernel,
Jihong Min
In-Reply-To: <20260614040032.1567994-1-hurryman2212@gmail.com>
Describe the EN7581 SOE register window and interrupt so the Ethernet driver can discover and initialize the packet offload engine.
Signed-off-by: Jihong Min <hurryman2212@gmail.com>
---
arch/arm64/boot/dts/airoha/en7581.dtsi | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/arch/arm64/boot/dts/airoha/en7581.dtsi b/arch/arm64/boot/dts/airoha/en7581.dtsi
index ff6908a76e8e..a3c1033d2437 100644
--- a/arch/arm64/boot/dts/airoha/en7581.dtsi
+++ b/arch/arm64/boot/dts/airoha/en7581.dtsi
@@ -347,6 +347,12 @@ i2c1: i2c@1fbf8100 {
status = "disabled";
};
+ soe: soe@1fbfa000 {
+ compatible = "airoha,en7581-soe";
+ reg = <0x0 0x1fbfa000 0x0 0x268>;
+ interrupts = <GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
eth: ethernet@1fb50000 {
compatible = "airoha,en7581-eth";
reg = <0 0x1fb50000 0 0x2600>,
--
2.53.0
^ permalink raw reply related
* [RFC PATCH net-next 2/7] dt-bindings: net: airoha: add EN7581 SOE
From: Jihong Min @ 2026-06-14 4:00 UTC (permalink / raw)
To: netdev, Lorenzo Bianconi
Cc: David S . Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Andrew Lunn, Simon Horman, Herbert Xu, Steffen Klassert,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, devicetree,
Matthias Brugger, AngeloGioacchino Del Regno, linux-arm-kernel,
linux-mediatek, Christian Marangi, Felix Fietkau, linux-kernel,
Jihong Min
In-Reply-To: <20260614040032.1567994-1-hurryman2212@gmail.com>
Document the EN7581 Secure Offload Engine register window used by the Ethernet driver for ESP packet offload, and add the new binding to the Airoha Ethernet MAINTAINERS entry.
Signed-off-by: Jihong Min <hurryman2212@gmail.com>
---
.../bindings/net/airoha,en7581-soe.yaml | 48 +++++++++++++++++++
MAINTAINERS | 1 +
2 files changed, 49 insertions(+)
create mode 100644 Documentation/devicetree/bindings/net/airoha,en7581-soe.yaml
diff --git a/Documentation/devicetree/bindings/net/airoha,en7581-soe.yaml b/Documentation/devicetree/bindings/net/airoha,en7581-soe.yaml
new file mode 100644
index 000000000000..24aecafecc70
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/airoha,en7581-soe.yaml
@@ -0,0 +1,48 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/net/airoha,en7581-soe.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Airoha EN7581 Secure Offload Engine
+
+maintainers:
+ - Lorenzo Bianconi <lorenzo@kernel.org>
+
+description:
+ The Secure Offload Engine provides inline ESP packet offload resources used
+ by the Airoha Ethernet controller.
+
+properties:
+ compatible:
+ const: airoha,en7581-soe
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+required:
+ - compatible
+ - reg
+ - interrupts
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/interrupt-controller/irq.h>
+
+ soc {
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ soe@1fbfa000 {
+ compatible = "airoha,en7581-soe";
+ reg = <0 0x1fbfa000 0 0x268>;
+ interrupts = <GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>;
+ };
+ };
+...
diff --git a/MAINTAINERS b/MAINTAINERS
index cc1dde0c9067..7c338e670572 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -757,6 +757,7 @@ L: linux-mediatek@lists.infradead.org (moderated for non-subscribers)
L: netdev@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/net/airoha,en7581-eth.yaml
+F: Documentation/devicetree/bindings/net/airoha,en7581-soe.yaml
F: drivers/net/ethernet/airoha/
AIROHA PCIE PHY DRIVER
--
2.53.0
^ permalink raw reply related
* [RFC PATCH net-next 1/7] xfrm: allow packet offload drivers to own transmit
From: Jihong Min @ 2026-06-14 4:00 UTC (permalink / raw)
To: netdev, Lorenzo Bianconi
Cc: David S . Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Andrew Lunn, Simon Horman, Herbert Xu, Steffen Klassert,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, devicetree,
Matthias Brugger, AngeloGioacchino Del Regno, linux-arm-kernel,
linux-mediatek, Christian Marangi, Felix Fietkau, linux-kernel,
Jihong Min
In-Reply-To: <20260614040032.1567994-1-hurryman2212@gmail.com>
Packet offload drivers can currently program state and validate whether an skb can be offloaded, but they cannot take ownership of a packet that needs driver-specific TX preparation before the regular XFRM output path continues.
Add an optional xdo_dev_packet_xmit() callback. Drivers that implement it consume the skb and return the final TX status; all other drivers keep the existing XFRM output path.
Signed-off-by: Jihong Min <hurryman2212@gmail.com>
---
include/linux/netdevice.h | 8 ++++++++
net/xfrm/xfrm_output.c | 11 +++++++++++
2 files changed, 19 insertions(+)
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 7f4f0837c09f..1552eb81ddf0 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1048,6 +1048,14 @@ struct xfrmdev_ops {
int (*xdo_dev_policy_add) (struct xfrm_policy *x, struct netlink_ext_ack *extack);
void (*xdo_dev_policy_delete) (struct xfrm_policy *x);
void (*xdo_dev_policy_free) (struct xfrm_policy *x);
+ /* Optional packet-offload TX path for devices that need
+ * driver-specific transmit preparation instead of continuing through
+ * the regular XFRM output path, such as adding offload metadata or
+ * steering the packet to a private transmit queue. The driver consumes
+ * skb and returns the final transmit status.
+ */
+ int (*xdo_dev_packet_xmit)(struct sk_buff *skb,
+ struct xfrm_state *x);
};
#endif
diff --git a/net/xfrm/xfrm_output.c b/net/xfrm/xfrm_output.c
index cc35c2fcbbe0..9f11559b0221 100644
--- a/net/xfrm/xfrm_output.c
+++ b/net/xfrm/xfrm_output.c
@@ -770,6 +770,17 @@ int xfrm_output(struct sock *sk, struct sk_buff *skb)
}
if (x->xso.type == XFRM_DEV_OFFLOAD_PACKET) {
+#ifdef CONFIG_XFRM_OFFLOAD
+ const struct xfrmdev_ops *ops;
+#endif
+
+#ifdef CONFIG_XFRM_OFFLOAD
+ ops = x->xso.dev->xfrmdev_ops;
+ /* Callback validates, consumes skb and returns final TX status. */
+ if (ops && ops->xdo_dev_packet_xmit)
+ return ops->xdo_dev_packet_xmit(skb, x);
+#endif
+
if (!xfrm_dev_offload_ok(skb, x)) {
XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTERROR);
kfree_skb(skb);
--
2.53.0
^ permalink raw reply related
* [RFC PATCH net-next 0/7] net: airoha: add EN7581 SOE ESP packet offload
From: Jihong Min @ 2026-06-14 4:00 UTC (permalink / raw)
To: netdev, Lorenzo Bianconi
Cc: David S . Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Andrew Lunn, Simon Horman, Herbert Xu, Steffen Klassert,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, devicetree,
Matthias Brugger, AngeloGioacchino Del Regno, linux-arm-kernel,
linux-mediatek, Christian Marangi, Felix Fietkau, linux-kernel,
Jihong Min
Add Secure Offload Engine (SOE) support for the Airoha EN7581 Ethernet
driver. SOE provides inline ESP packet offload for native ESP and NAT-T
traffic, with the Ethernet/QDMA path used to submit packets to the SOE
block and the PPE path used to bind eligible ESP flows. NETIF_F_GSO_ESP
and NETIF_F_HW_ESP_TX_CSUM are intentionally left out for now and will be
revisited separately for feasibility.
This is posted as RFC because the code was originally developed and tested
against an OpenWrt 6.18 Airoha tree, not against the current upstream
net-next driver. The original OpenWrt commit used as the source for this
RFC is available at:
https://github.com/hurryman2212/OpenW1700k-test/commit/7c1b5e662f7790b3d23ed143beadc1dcbf6d15f7
The SOE part is intentionally linked into the airoha Ethernet module
instead of being exposed as an independent crypto or platform driver. The
user-visible ESP offload control is a netdev capability: xfrmdev_ops and
NETIF_F_HW_ESP live on the target netdev, and the feature can be controlled
through the usual netdev feature path. SOE also shares the FE/QDMA/PPE
datapath, private queues, DSA conduit handling and netdev lifetime owned by
airoha_eth.
Patch 1 adds xdo_dev_packet_xmit() because the existing XFRM packet
offload transmit path does not provide a hook for hardware whose ESP engine
is reached through device-specific packet forwarding. SOE needs to consume
the skb, add a hardware hop descriptor, steer it to a private QDMA path and
return the final transmit status. Drivers that do not implement the
optional callback keep the existing XFRM output behavior.
Jihong Min (7):
xfrm: allow packet offload drivers to own transmit
dt-bindings: net: airoha: add EN7581 SOE
arm64: dts: airoha: add EN7581 SOE node
net: airoha: add SOE registers and driver state
net: airoha: add QDMA support for SOE packets
net: airoha: add PPE support for SOE flows
net: airoha: add SOE XFRM packet offload support
.../bindings/net/airoha,en7581-soe.yaml | 48 +
MAINTAINERS | 1 +
arch/arm64/boot/dts/airoha/en7581.dtsi | 6 +
drivers/net/ethernet/airoha/Kconfig | 13 +
drivers/net/ethernet/airoha/Makefile | 1 +
drivers/net/ethernet/airoha/airoha_eth.c | 668 +++++-
drivers/net/ethernet/airoha/airoha_eth.h | 40 +
drivers/net/ethernet/airoha/airoha_ppe.c | 606 +++++-
drivers/net/ethernet/airoha/airoha_regs.h | 16 +
drivers/net/ethernet/airoha/airoha_soe.c | 1896 +++++++++++++++++
drivers/net/ethernet/airoha/airoha_soe.h | 126 ++
include/linux/netdevice.h | 8 +
include/linux/soc/airoha/airoha_offload.h | 5 +
net/xfrm/xfrm_output.c | 11 +
14 files changed, 3342 insertions(+), 103 deletions(-)
create mode 100644 Documentation/devicetree/bindings/net/airoha,en7581-soe.yaml
create mode 100644 drivers/net/ethernet/airoha/airoha_soe.c
create mode 100644 drivers/net/ethernet/airoha/airoha_soe.h
--
2.53.0
^ permalink raw reply
* [PATCH] PCI: meson: Fix PERST# timing by asserting reset before LTSSM enable
From: Gowtham Kudupudi @ 2026-06-14 1:56 UTC (permalink / raw)
To: yue.wang, lpieralisi, kwilczynski, mani
Cc: robh, bhelgaas, neil.armstrong, khilman, jbrunet,
martin.blumenstingl, linux-pci, linux-amlogic, linux-arm-kernel,
linux-kernel, Gowtham Kudupudi
On warm reboot, the PCIe controller's LTSSM starts link training
immediately if PERST# is already deasserted from the previous boot.
The driver then pulses PERST# for only 500us, which is too short to
properly reset the endpoint device that has already started training.
Fix by moving the PERST# assert/deassert pulse BEFORE enabling LTSSM,
so the endpoint gets a clean reset cycle before link training begins.
This was found on Amlogic G12B (A311D) with NVMe on an M.2 slot.
Cold boot worked because POR held PERST# low; warm reboot did not.
The fix was confirmed on a Banana Pi CM4 with Waveshare IO base board.
Signed-off-by: Gowtham Kudupudi <gowtham@ferryfair.com>
---
drivers/pci/controller/dwc/pci-meson.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/pci/controller/dwc/pci-meson.c b/drivers/pci/controller/dwc/pci-meson.c
index 5f8e2f4b3c12..3a7e9f1d5b8c 100644
--- a/drivers/pci/controller/dwc/pci-meson.c
+++ b/drivers/pci/controller/dwc/pci-meson.c
@@ -310,8 +310,8 @@ static int meson_pcie_start_link(struct dw_pcie *pci)
{
struct meson_pcie *mp = to_meson_pcie(pci);
+ meson_pcie_assert_reset(mp);
meson_pcie_ltssm_enable(mp);
- meson_pcie_assert_reset(mp);
return 0;
}
--
2.49.0
^ permalink raw reply related
* Re: [RFC PATCH] ARM: move reserve_lp[012] handling into affected machines
From: Ethan Nelson-Moore @ 2026-06-14 2:20 UTC (permalink / raw)
To: linux-arm-kernel, linux-kernel
Cc: Russell King, Andrew Morton, Jiri Bohac, Linus Walleij,
Arnd Bergmann
In-Reply-To: <20260511011504.77760-1-enelsonmoore@gmail.com>
On Sun, May 10, 2026 at 6:15 PM Ethan Nelson-Moore
<enelsonmoore@gmail.com> wrote:
> arch/arm/kernel/setup.c contains code to reserve lp0/1/2 I/O ports for
> machines that can't possibly have these ports. This code is only used
> by netwinder and footbridge, and is small enough that it can just be
> moved into these machines. Do so to make the setup code more generic
> and the machine code more self-contained.
>
> This patch is an RFC because I'm not sure if using .init_early is
> actually necessary. I did it to match the place the original code was
> called as closely as possible. Can anyone weigh in on this?
Hi, everyone,
Gentle ping (+ cc Arnd, LinusW) - anyone have any thoughts on this?
I meant rpc and footbridge in the commit message - I'll fix it in a
future revision.
Ethan
^ permalink raw reply
* Re: [PATCH] ARM: remove references to removed CONFIG_CPU_ARM92x_CPU_IDLE options
From: Ethan Nelson-Moore @ 2026-06-14 2:06 UTC (permalink / raw)
To: Linus Walleij
Cc: linux-arm-kernel, Nathan Chancellor, Kees Cook, Russell King
In-Reply-To: <CAD++jLnD2EU=YfABb1ySRtgeOPVzQKH3iMjZtj2AsW+RK8M6mQ@mail.gmail.com>
On Thu, Jun 11, 2026 at 5:38 AM Linus Walleij <linusw@kernel.org> wrote:
> Please put this patch into Russell's patch tracker.
Here:
https://www.arm.linux.org.uk/developer/patches/viewpatch.php?id=9478/1
Ethan
^ permalink raw reply
* Re: [PATCH] ARM: disable broken eBPF JIT on the Risc PC
From: Ethan Nelson-Moore @ 2026-06-14 1:50 UTC (permalink / raw)
To: Linus Walleij
Cc: linux-arm-kernel, linux-kernel, stable, Russell King,
Russell King (Oracle), Arnd Bergmann, Kees Cook,
Nathan Chancellor, Thomas Weissschuh, Peter Zijlstra,
Shubham Bansal, David S. Miller
In-Reply-To: <CAD++jL=0qYGoygUwGEXQL7C_ROnC7kfpRv8RA+H5tNWwYu+pQA@mail.gmail.com>
On Mon, May 25, 2026 at 1:18 AM Linus Walleij <linusw@kernel.org> wrote:
> Looks correct to me.
> Reviewed-by: Linus Walleij <linusw@kernel.org>
>
> Please put this into Russell's patch tracker!
Done!
https://www.arm.linux.org.uk/developer/patches/viewpatch.php?id=9477/1
^ permalink raw reply
* [PATCH v2] Input: apple_z2 - bound the device-reported finger count
From: Bryam Vargas via B4 Relay @ 2026-06-14 1:22 UTC (permalink / raw)
To: Sasha Finkelstein, Dmitry Torokhov
Cc: linux-kernel, Janne Grunau, linux-arm-kernel, linux-input,
Sven Peter, asahi, Neal Gompa
From: Bryam Vargas <hexlabsecurity@proton.me>
apple_z2_parse_touches() takes the finger count from the touch
controller's report and loops over that many fixed-size finger records
without ever checking the count against the length of the report:
nfingers = msg[APPLE_Z2_NUM_FINGERS_OFFSET];
fingers = (struct apple_z2_finger *)(msg + APPLE_Z2_FINGERS_OFFSET);
for (i = 0; i < nfingers; i++)
/* read fingers[i] ... */
msg points into the fixed 4000-byte z2->rx_buf and nfingers is a single
device-supplied byte, so it can be as large as 255. A malicious,
malfunctioning or counterfeit controller (or an interposer on the SPI
bus) can report a large finger count in a short packet, making the loop
read up to 255 * sizeof(struct apple_z2_finger) bytes starting 24 bytes
into msg -- far past the 4000-byte buffer. This is a controller-driven
heap out-of-bounds read, and the finger fields that are read (position,
pressure, touch and tool dimensions) are forwarded to userspace as input
events, leaking adjacent kernel memory.
Bound the device-reported count to the number of finger records the
report actually carries.
Reported-by: sashiko-bot@kernel.org
Closes: https://lore.kernel.org/all/20260613215358.329921F000E9@smtp.kernel.org/
Fixes: 471a92f8a21a ("Input: apple_z2 - add a driver for Apple Z2 touchscreens")
Cc: stable@vger.kernel.org
Signed-off-by: Bryam Vargas <hexlabsecurity@proton.me>
---
Changes since v1 [1]:
- Keep the early-return at NUM_FINGERS_OFFSET instead of moving it to
FINGERS_OFFSET, so a short zero-finger ("all lifted") report still
reaches input_mt_sync_frame()/input_sync() and does not leave touches
stuck on the screen (caught by the sashiko-bot review of v1 [2]). A
packet too short to hold even one finger record clamps nfingers to 0
instead of being dropped.
[1] https://lore.kernel.org/all/20260613-b4-disp-f0148c89-v1-1-868a48b2a187@proton.me/
[2] https://lore.kernel.org/all/20260614000725.6B8D11F000E9@smtp.kernel.org/
Reachable on every touch interrupt once the controller is booted
(apple_z2_irq -> apple_z2_read_packet -> apple_z2_parse_touches).
nfingers is bounded here by the message length; the message length is in
turn bounded by the companion "Input: apple_z2 - bound the device-reported
packet length" change (in flight), which caps the device-reported pkt_len
to the 4000-byte receive buffer. The two together close the device-driven
out-of-bounds accesses in apple_z2_parse_touches() / apple_z2_read_packet().
Verified with a faithful in-kernel KASAN litmus (the verbatim 4000-byte
buffer, the struct apple_z2_finger layout and the parse loop),
CONFIG_KASAN=y on x86_64:
Arm A, nfingers = 255 in a short packet (msg_len 19):
BUG: KASAN: slab-out-of-bounds in apple_z2_parse_touches
Read of size 2 ... 1 bytes to the right of allocated 4000-byte region
... cache kmalloc-4k of size 4096
Arm B, with this patch: a zero-finger report (msg_len 19) reaches the
sync; a 255-finger claim is clamped to what the packet holds; clean.
Arm C, benign device (3 fingers): clean
AddressSanitizer (x86_64 and i386): heap-buffer-overflow READ, both ABIs.
Reproducer and full logs available on request.
---
drivers/input/touchscreen/apple_z2.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/drivers/input/touchscreen/apple_z2.c b/drivers/input/touchscreen/apple_z2.c
index 271ababf0ad5..39ade83ef0de 100644
--- a/drivers/input/touchscreen/apple_z2.c
+++ b/drivers/input/touchscreen/apple_z2.c
@@ -92,6 +92,12 @@ static void apple_z2_parse_touches(struct apple_z2 *z2,
return;
nfingers = msg[APPLE_Z2_NUM_FINGERS_OFFSET];
fingers = (struct apple_z2_finger *)(msg + APPLE_Z2_FINGERS_OFFSET);
+ /* a malicious controller can claim more fingers than the packet holds */
+ if (msg_len < APPLE_Z2_FINGERS_OFFSET)
+ nfingers = 0;
+ else
+ nfingers = min_t(int, nfingers,
+ (msg_len - APPLE_Z2_FINGERS_OFFSET) / sizeof(*fingers));
for (i = 0; i < nfingers; i++) {
slot = input_mt_get_slot_by_key(z2->input_dev, fingers[i].finger);
if (slot < 0) {
---
base-commit: 8e65320d91cdc3b241d4b94855c88459b91abf66
change-id: 20260613-b4-disp-4ebcbd68-ed8a28672ccc
Best regards,
--
Bryam Vargas <hexlabsecurity@proton.me>
^ permalink raw reply related
* Re: [PATCH v2 3/7] net: wwan: t9xx: Add control DMA interface
From: Jakub Kicinski @ 2026-06-14 0:30 UTC (permalink / raw)
To: Jack Wu via B4 Relay
Cc: jackbb_wu, Loic Poulain, Sergey Ryazanov, Johannes Berg,
Andrew Lunn, David S. Miller, Eric Dumazet, Paolo Abeni,
Wen-Zhi Huang, Shi-Wei Yeh, Minano Tseng, Matthias Brugger,
AngeloGioacchino Del Regno, Simon Horman, Jonathan Corbet,
Shuah Khan, linux-kernel, netdev, linux-arm-kernel,
linux-mediatek, linux-doc
In-Reply-To: <20260610-t9xx_driver_v1-v2-3-c65addf23b3f@compal.com>
On Wed, 10 Jun 2026 18:41:06 +0800 Jack Wu via B4 Relay wrote:
> From: Jack Wu <jackbb_wu@compal.com>
>
> Cross Layer Direct Memory Access(CLDMA) is the hardware
> interface used by the control plane and designated to
> translate data between the host and the device. It supports
> 8 hardware queues for the device AP and modem respectively.
Transient build warnings:
+../drivers/net/wwan/t9xx/pcie/mtk_pci_drv_m9xx.c:52:30: warning: symbol 'mtk_dev_cfg_0900' was not declared. Should it be static?
+../drivers/net/wwan/t9xx/pcie/mtk_ctrl_cfg_m9xx.c:19:22: warning: symbol 'mtk_ctrl_info_m9xx' was not declared. Should it be static?
+../drivers/net/wwan/t9xx/pcie/mtk_cldma_drv_m9xx.c:33:22: warning: symbol 'mtk_cldma_regs_m9xx' was not declared. Should it be static?
+../drivers/net/wwan/t9xx/pcie/mtk_cldma_drv_m9xx.c:166:22: warning: symbol 'cldma_drv_ops_m9xx' was not declared. Should it be static?
please also see all the AI code comments at:
https://sashiko.dev/#/patchset/20260610-t9xx_driver_v1-v2-3-c65addf23b3f@compal.com
--
pw-bot: cr
^ permalink raw reply
* Re: [PATCH] ASoC: Match DT helper types
From: Mark Brown @ 2026-06-14 0:00 UTC (permalink / raw)
To: Rob Herring (Arm)
Cc: Liam Girdwood, Jaroslav Kysela, Takashi Iwai, Peter Ujfalusi,
Heiko Stuebner, linux-sound, linux-kernel, linux-arm-kernel,
linux-rockchip
In-Reply-To: <20260612214904.1882991-1-robh@kernel.org>
[-- Attachment #1: Type: text/plain, Size: 1188 bytes --]
On Fri, Jun 12, 2026 at 04:49:02PM -0500, Rob Herring (Arm) wrote:
> The affected ASoC drivers read properties whose bindings use boolean
> flags, normal uint32 cells, or phandle-style arrays. Using helpers for
> a different encoding makes those accesses disagree with the binding.
> Use helpers that match the documented encoding and keep the existing
> driver storage by copying through temporary values where needed.
This feels like it would be easier to deal with as separate commits for
each issue...
> --- a/sound/soc/rockchip/rockchip_pdm.c
> +++ b/sound/soc/rockchip/rockchip_pdm.c
> @@ -546,8 +546,7 @@ static int rockchip_pdm_path_parse(struct rk_pdm_dev *pdm, struct device_node *n
> unsigned int path[PDM_PATH_MAX];
> int cnt = 0, ret = 0, i = 0, val = 0, msk = 0;
>
> - cnt = of_count_phandle_with_args(node, "rockchip,path-map",
> - NULL);
> + cnt = of_property_count_u32_elems(node, "rockchip,path-map");
> if (cnt != PDM_PATH_MAX)
> return cnt;
The error codes reported by these two functions for missing properties
differ (-ENOENT vs -EINVAL) and the caller of this function has a
specific check for -ENOENT which allows it.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply
* [PATCH] Input: apple_z2 - bound the device-reported finger count
From: Bryam Vargas via B4 Relay @ 2026-06-13 23:57 UTC (permalink / raw)
To: Sasha Finkelstein, Dmitry Torokhov
Cc: linux-arm-kernel, linux-kernel, Janne Grunau, asahi, linux-input,
Neal Gompa, Sven Peter
From: Bryam Vargas <hexlabsecurity@proton.me>
apple_z2_parse_touches() takes the finger count from the touch
controller's report and loops over that many fixed-size finger records
without ever checking the count against the length of the report:
nfingers = msg[APPLE_Z2_NUM_FINGERS_OFFSET];
fingers = (struct apple_z2_finger *)(msg + APPLE_Z2_FINGERS_OFFSET);
for (i = 0; i < nfingers; i++)
/* read fingers[i] ... */
msg points into the fixed 4000-byte z2->rx_buf and nfingers is a single
device-supplied byte, so it can be as large as 255. A malicious,
malfunctioning or counterfeit controller (or an interposer on the SPI
bus) can report a large finger count in a short packet, making the loop
read up to 255 * sizeof(struct apple_z2_finger) bytes starting 24 bytes
into msg -- far past the 4000-byte buffer. This is a controller-driven
heap out-of-bounds read, and the finger fields that are read (position,
pressure, touch and tool dimensions) are forwarded to userspace as input
events, leaking adjacent kernel memory.
Bound the device-reported count to the number of finger records the
report actually carries.
Reported-by: sashiko-bot@kernel.org
Closes: https://lore.kernel.org/all/20260613215358.329921F000E9@smtp.kernel.org/
Fixes: 471a92f8a21a ("Input: apple_z2 - add a driver for Apple Z2 touchscreens")
Cc: stable@vger.kernel.org
Signed-off-by: Bryam Vargas <hexlabsecurity@proton.me>
---
Reachable on every touch interrupt once the controller is booted
(apple_z2_irq -> apple_z2_read_packet -> apple_z2_parse_touches).
nfingers is a different device field from the packet length handled by
the in-flight "Input: apple_z2 - bound the device-reported packet length"
patch, so the two are orthogonal: that one bounds the spi_read() length
(rx_buf[1..2]); this one bounds the per-report finger count (msg[16]).
The early-return is tightened from NUM_FINGERS_OFFSET (16) to
FINGERS_OFFSET (24) so the subtraction below cannot underflow; since
msg_len == pkt_len - 5 and pkt_len is rounded to a multiple of four, the
only reachable lengths the tighter guard now drops are 19 and 23, both of
which are too short to hold even the finger-array header.
Verified with a faithful in-kernel KASAN litmus (the verbatim 4000-byte
buffer, the struct apple_z2_finger layout and the parse loop),
CONFIG_KASAN=y on x86_64:
Arm A, nfingers = 255 in a short packet (msg_len 19):
BUG: KASAN: slab-out-of-bounds in apple_z2_parse_touches
Read of size 2 ... 1 bytes to the right of allocated 4000-byte region
... cache kmalloc-4k of size 4096
Arm B, with this patch (count clamped to what the packet holds): clean
Arm C, benign device (3 fingers): clean
AddressSanitizer (x86_64 and i386): heap-buffer-overflow READ, both ABIs.
Reproducer and full logs available on request.
---
drivers/input/touchscreen/apple_z2.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/drivers/input/touchscreen/apple_z2.c b/drivers/input/touchscreen/apple_z2.c
index 271ababf0ad5..61f353553e7c 100644
--- a/drivers/input/touchscreen/apple_z2.c
+++ b/drivers/input/touchscreen/apple_z2.c
@@ -88,10 +88,13 @@ static void apple_z2_parse_touches(struct apple_z2 *z2,
int slot_valid;
struct apple_z2_finger *fingers;
- if (msg_len <= APPLE_Z2_NUM_FINGERS_OFFSET)
+ if (msg_len <= APPLE_Z2_FINGERS_OFFSET)
return;
nfingers = msg[APPLE_Z2_NUM_FINGERS_OFFSET];
fingers = (struct apple_z2_finger *)(msg + APPLE_Z2_FINGERS_OFFSET);
+ /* a malicious controller can claim more fingers than the packet holds */
+ nfingers = min_t(int, nfingers,
+ (msg_len - APPLE_Z2_FINGERS_OFFSET) / sizeof(*fingers));
for (i = 0; i < nfingers; i++) {
slot = input_mt_get_slot_by_key(z2->input_dev, fingers[i].finger);
if (slot < 0) {
---
base-commit: 8e65320d91cdc3b241d4b94855c88459b91abf66
change-id: 20260613-b4-disp-f0148c89-dfafdfb84b3f
Best regards,
--
Bryam Vargas <hexlabsecurity@proton.me>
^ permalink raw reply related
* [PATCH] net: airoha: Fix MODULE_LICENSE to match SPDX GPL-2.0-only identifier
From: Wayen.Yan @ 2026-06-13 23:52 UTC (permalink / raw)
To: netdev
Cc: lorenzo, horms, pabeni, kuba, edumazet, andrew+netdev,
angelogioacchino.delregno, matthias.bgg, linux-arm-kernel,
linux-mediatek
Both airoha_eth.c and airoha_npu.c declare SPDX-License-Identifier:
GPL-2.0-only but use MODULE_LICENSE("GPL"), which the kernel module
loader interprets as GPL-2.0+ (any GPL version). This mismatch causes
license compliance tools (FOSSology, ScanCode, etc.) to misidentify
the effective license as more permissive than intended.
Replace MODULE_LICENSE("GPL") with MODULE_LICENSE("GPL v2") to
align with the GPL-2.0-only SPDX identifier. Per include/linux/module.h,
"GPL v2" maps to GPL-2.0-only, matching the source files' declared
license.
Fixes: 23020f049327 ("net: airoha: Introduce ethernet support for EN7581 SoC")
Signed-off-by: Wayen <win847@gmail.com>
---
drivers/net/ethernet/airoha/airoha_eth.c | 2 +-
drivers/net/ethernet/airoha/airoha_npu.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c
index 31cdb11cd7..960727957e 100644
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
@@ -3333,6 +3333,6 @@ static struct platform_driver airoha_driver = {
};
module_platform_driver(airoha_driver);
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Lorenzo Bianconi <lorenzo@kernel.org>");
MODULE_DESCRIPTION("Ethernet driver for Airoha SoC");
diff --git a/drivers/net/ethernet/airoha/airoha_npu.c b/drivers/net/ethernet/airoha/airoha_npu.c
index 17dbdc8325..870d61fdd9 100644
--- a/drivers/net/ethernet/airoha/airoha_npu.c
+++ b/drivers/net/ethernet/airoha/airoha_npu.c
@@ -826,6 +826,6 @@ MODULE_FIRMWARE(NPU_EN7581_7996_FIRMWARE_DATA);
MODULE_FIRMWARE(NPU_EN7581_7996_FIRMWARE_RV32);
MODULE_FIRMWARE(NPU_AN7583_FIRMWARE_DATA);
MODULE_FIRMWARE(NPU_AN7583_FIRMWARE_RV32);
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Lorenzo Bianconi <lorenzo@kernel.org>");
MODULE_DESCRIPTION("Airoha Network Processor Unit driver");
--
2.51.0
^ permalink raw reply related
* [PATCH] net: airoha: Remove dead MT7996 NPU firmware declarations
From: Wayen.Yan @ 2026-06-13 23:40 UTC (permalink / raw)
To: netdev
Cc: lorenzo, horms, pabeni, kuba, edumazet, andrew+netdev,
angelogioacchino.delregno, matthias.bgg, linux-arm-kernel,
linux-mediatek
Remove the NPU_EN7581_7996_FIRMWARE_DATA/RV32 #define macros and
their corresponding MODULE_FIRMWARE() declarations. Neither the
en7581_npu_soc_data nor the an7583_npu_soc_data references these
firmware names, and no firmware loading path in the driver ever
requests them. The only references are the #define lines themselves
and the MODULE_FIRMWARE() declarations below.
Keeping dead MODULE_FIRMWARE entries causes modprobe/udev to attempt
pre-loading non-existent firmware files, generating kernel log noise
and misleading distributors about which firmware files to package.
Fixes: 23290c7bc190 ("net: airoha: Introduce Airoha NPU support")
Signed-off-by: Wayen <win847@gmail.com>
---
drivers/net/ethernet/airoha/airoha_npu.c | 4 ----
1 file changed, 4 deletions(-)
diff --git a/drivers/net/ethernet/airoha/airoha_npu.c b/drivers/net/ethernet/airoha/airoha_npu.c
index 17dbdc8325..93095f3894 100644
--- a/drivers/net/ethernet/airoha/airoha_npu.c
+++ b/drivers/net/ethernet/airoha/airoha_npu.c
@@ -16,8 +16,6 @@
#define NPU_EN7581_FIRMWARE_DATA "airoha/en7581_npu_data.bin"
#define NPU_EN7581_FIRMWARE_RV32 "airoha/en7581_npu_rv32.bin"
-#define NPU_EN7581_7996_FIRMWARE_DATA "airoha/en7581_MT7996_npu_data.bin"
-#define NPU_EN7581_7996_FIRMWARE_RV32 "airoha/en7581_MT7996_npu_rv32.bin"
#define NPU_AN7583_FIRMWARE_DATA "airoha/an7583_npu_data.bin"
#define NPU_AN7583_FIRMWARE_RV32 "airoha/an7583_npu_rv32.bin"
#define NPU_EN7581_FIRMWARE_RV32_MAX_SIZE 0x200000
@@ -822,8 +820,6 @@ module_platform_driver(airoha_npu_driver);
MODULE_FIRMWARE(NPU_EN7581_FIRMWARE_DATA);
MODULE_FIRMWARE(NPU_EN7581_FIRMWARE_RV32);
-MODULE_FIRMWARE(NPU_EN7581_7996_FIRMWARE_DATA);
-MODULE_FIRMWARE(NPU_EN7581_7996_FIRMWARE_RV32);
MODULE_FIRMWARE(NPU_AN7583_FIRMWARE_DATA);
MODULE_FIRMWARE(NPU_AN7583_FIRMWARE_RV32);
MODULE_LICENSE("GPL");
--
2.51.0
^ permalink raw reply related
* [PATCH] net: airoha: Fix skb->priority underflow in airoha_dev_select_queue()
From: Wayen.Yan @ 2026-06-13 23:30 UTC (permalink / raw)
To: netdev
Cc: lorenzo, horms, pabeni, kuba, edumazet, andrew+netdev,
angelogioacchino.delregno, matthias.bgg, linux-arm-kernel,
linux-mediatek
In airoha_dev_select_queue(), the expression:
queue = (skb->priority - 1) % AIROHA_NUM_QOS_QUEUES;
implicitly converts to unsigned arithmetic: when skb->priority is 0
(the default for unclassified traffic), (0u - 1u) wraps to UINT_MAX,
and UINT_MAX % 8 = 7, routing default best-effort packets to the
highest-priority QoS queue. This causes QoS inversion where the
majority of traffic on a PON gateway starves actual high-priority
flows (VoIP, gaming, etc.).
Fix by guarding the subtraction: when priority is 0, map to queue 0
(lowest priority), otherwise apply the original (priority - 1) % 8
mapping.
Fixes: 2b288b81560b ("net: airoha: Introduce ndo_select_queue callback")
Signed-off-by: Wayen <win847@gmail.com>
---
drivers/net/ethernet/airoha/airoha_eth.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c
index 31cdb11cd7..d476ef83c3 100644
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
@@ -1933,7 +1933,7 @@ static u16 airoha_dev_select_queue(struct net_device *dev, struct sk_buff *skb,
*/
channel = netdev_uses_dsa(dev) ? skb_get_queue_mapping(skb) : port->id;
channel = channel % AIROHA_NUM_QOS_CHANNELS;
- queue = (skb->priority - 1) % AIROHA_NUM_QOS_QUEUES; /* QoS queue */
+ queue = skb->priority ? (skb->priority - 1) % AIROHA_NUM_QOS_QUEUES : 0;
queue = channel * AIROHA_NUM_QOS_QUEUES + queue;
return queue < dev->num_tx_queues ? queue : 0;
--
2.51.0
^ permalink raw reply related
* Re: [GIT PULL] clk: samsung: drivers for v7.2
From: Stephen Boyd @ 2026-06-13 23:12 UTC (permalink / raw)
To: Krzysztof Kozlowski, Michael Turquette
Cc: Krzysztof Kozlowski, Chanwoo Choi, linux-clk, Sylwester Nawrocki,
Alim Akhtar, Peter Griffin, linux-arm-kernel, linux-samsung-soc,
linux-kernel
In-Reply-To: <20260604164729.83284-2-krzk@kernel.org>
Quoting Krzysztof Kozlowski (2026-06-04 09:47:25)
> Hi Stephen and Michael,
>
> Notable change outside of this pull: Peter Griffin was added as co-maintainer
> to Samsung SoC and Samsung SoC clocks. See also commit 20550601bf4 in
> linux-next and
> https://lore.kernel.org/all/178015858043.36212.8088079079471293822.b4-ty@b4/
>
> Best regards,
> Krzysztof
>
>
> The following changes since commit 254f49634ee16a731174d2ae34bc50bd5f45e731:
>
> Linux 7.1-rc1 (2026-04-26 14:19:00 -0700)
>
> are available in the Git repository at:
>
> https://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux.git tags/samsung-clk-7.2
>
> for you to fetch changes up to e11560b050ce867bd7d3ccea138231db54e2250a:
>
> clk: samsung: exynos990: Fix PERIC0/1 USI clock types (2026-05-30 18:50:36 +0200)
>
> ----------------------------------------------------------------
Thanks. Pulled into clk-next
^ permalink raw reply
* Re: [PATCH net 0/2] net/stmmac: Fixes for maximum TX/RX queues to use by driver
From: patchwork-bot+netdevbpf @ 2026-06-13 23:10 UTC (permalink / raw)
To: Jakub Raczynski
Cc: netdev, andrew+netdev, davem, edumazet, kuba, pabeni,
mcoquelin.stm32, alexandre.torgue, linux-kernel, linux-arm-kernel,
k.domagalski, k.tegowski
In-Reply-To: <20260611113358.3379518-1-j.raczynski@samsung.com>
Hello:
This series was applied to netdev/net-next.git (main)
by Jakub Kicinski <kuba@kernel.org>:
On Thu, 11 Jun 2026 13:33:56 +0200 you wrote:
> When contributing other changes preparing functions for new XGMAC hardware
> https://lore.kernel.org/netdev/20260601162537.553512-1-j.raczynski@samsung.com/
> there have been reports by Sashiko AI review about pre-existing issues
> in the code. These problems are non-insignificant and are 'net' material fixes,
> rather than net-next features.
> One issue in this patchset was reported by Sashiko AI, while other
> technically part of new patchset, but is reasonable related fix.
> All of issues are wrong DTS configuration, but kernel needs to handle it.
>
> [...]
Here is the summary with links:
- [net,1/2] net/stmmac: Apply TBS config only to used queues
https://git.kernel.org/netdev/net-next/c/8b10877d9d6c
- [net,2/2] net/stmmac: Apply MTL_MAX queue limit if config missing
https://git.kernel.org/netdev/net-next/c/8a7bca6de6de
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply
* [PATCH] ARM: mm: correct CONFIG_ARM_LPAE macro name in comment
From: Ethan Nelson-Moore @ 2026-06-13 23:01 UTC (permalink / raw)
To: Kees Cook, Ethan Nelson-Moore, linux-arm-kernel; +Cc: Russell King
A comment in arch/arm/mm/pgd.c incorrectly refers to CONFIG_LPAE
instead of CONFIG_ARM_LPAE. Correct it.
Discovered while searching for CONFIG_* symbols referenced in code but
not defined in any Kconfig file.
Signed-off-by: Ethan Nelson-Moore <enelsonmoore@gmail.com>
---
arch/arm/mm/pgd.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm/mm/pgd.c b/arch/arm/mm/pgd.c
index 447945836c3f..7c56279bc5bd 100644
--- a/arch/arm/mm/pgd.c
+++ b/arch/arm/mm/pgd.c
@@ -78,7 +78,7 @@ pgd_t *pgd_alloc(struct mm_struct *mm)
* sizeof(pmd_t));
clean_dcache_area(new_pmd, PTRS_PER_PMD * sizeof(pmd_t));
#endif /* CONFIG_KASAN */
-#endif /* CONFIG_LPAE */
+#endif /* CONFIG_ARM_LPAE */
if (!vectors_high()) {
/*
--
2.43.0
^ permalink raw reply related
* Re: [PATCH v2] net: airoha: Fix debugfs new-tuple display for IPv4 ROUTE entries
From: patchwork-bot+netdevbpf @ 2026-06-13 23:00 UTC (permalink / raw)
To: Wayen.Yan
Cc: netdev, lorenzo, horms, pabeni, kuba, edumazet, andrew+netdev,
angelogioacchino.delregno, matthias.bgg, linux-arm-kernel,
linux-mediatek
In-Reply-To: <6a2be54b.ef98c1b2.3c3224.2ed8@mx.google.com>
Hello:
This patch was applied to netdev/net.git (main)
by Jakub Kicinski <kuba@kernel.org>:
On Fri, 12 Jun 2026 07:09:56 +0800 you wrote:
> In airoha_ppe_debugfs_foe_show(), the second switch statement falls
> through from PPE_PKT_TYPE_IPV4_HNAPT/DSLITE to PPE_PKT_TYPE_IPV4_ROUTE,
> accessing hwe->ipv4.new_tuple for all three types. However, IPv4 ROUTE
> (3-tuple) entries do not contain a valid new_tuple — this field is only
> meaningful for NATted flows (HNAPT/DSLITE). For ROUTE entries, the
> memory at the new_tuple offset holds routing information, not NAT data,
> so displaying "new=" produces garbage output.
>
> [...]
Here is the summary with links:
- [v2] net: airoha: Fix debugfs new-tuple display for IPv4 ROUTE entries
https://git.kernel.org/netdev/net/c/1c3a77471afb
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply
* Re: [PATCH] net: airoha: Fix register index for Tx-fwd counter configuration
From: patchwork-bot+netdevbpf @ 2026-06-13 23:00 UTC (permalink / raw)
To: Wayen.Yan; +Cc: netdev, lorenzo, linux-arm-kernel, linux-mediatek
In-Reply-To: <6a2b40e7.4dd82583.3a5c46.e566@mx.google.com>
Hello:
This patch was applied to netdev/net.git (main)
by Jakub Kicinski <kuba@kernel.org>:
On Fri, 12 Jun 2026 07:09:13 +0800 you wrote:
> In airoha_qdma_init_qos_stats(), the Tx-fwd counter configuration
> register uses the same index (i << 1) as the Tx-cpu counter, which
> overwrites the Tx-cpu configuration. The Tx-fwd counter value register
> correctly uses (i << 1) + 1, so the configuration register should use
> the same index.
>
> Fix the REG_CNTR_CFG index from (i << 1) to ((i << 1) + 1) so that
> the Tx-fwd counter is properly configured instead of clobbering the
> Tx-cpu counter config.
>
> [...]
Here is the summary with links:
- net: airoha: Fix register index for Tx-fwd counter configuration
https://git.kernel.org/netdev/net/c/1402ecccf563
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply
* Re: [GIT PULL] Qualcomm clock updates for v7.2
From: Stephen Boyd @ 2026-06-13 22:55 UTC (permalink / raw)
To: Bjorn Andersson, linux-clk
Cc: linux-arm-msm, linux-arm-kernel, Vivek Aknurwar, Luca Weiss,
Jagadeesh Kona, Krzysztof Kozlowski, Luo Jie, Bartosz Golaszewski,
Kathiravan Thirumoorthy, Alexander Koskovich, Biswapriyo Nath,
Konrad Dybcio, Phillip Varney
In-Reply-To: <20260612224825.852551-1-andersson@kernel.org>
Quoting Bjorn Andersson (2026-06-12 15:48:25)
>
> The following changes since commit 254f49634ee16a731174d2ae34bc50bd5f45e731:
>
> Linux 7.1-rc1 (2026-04-26 14:19:00 -0700)
>
> are available in the Git repository at:
>
> https://git.kernel.org/pub/scm/linux/kernel/git/qcom/linux.git tags/qcom-clk-for-7.2
>
> for you to fetch changes up to e108373c54fbc844b7f541c6fd7ecb31772afd3c:
>
> clk: qcom: regmap-phy-mux: Rework the implementation (2026-06-08 09:17:24 -0500)
>
> ----------------------------------------------------------------
Thanks. Pulled into clk-next
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox