airoha: backport upstream patch for Flow Offload support for AN7581
Backpot upstream patch for Flow Offload support for AN7581 and refresh all affected patch. To correctly work a dedicated firmware is needed to use the dedicated Network Coprocessor (NPU). This also introduce good cleanup and moves the driver in a dedicated Airoha directory. While currently not totally usable (due to lack of firmware blob) this is needed to backport support for external PHY/SFP support. Refresh all affected patch. Tested-by: Aleksander Jan Bajkowski <olek2@wp.pl> # tested on Quantum W1700k Tested-by: Andrew LaMarche <andrewjlamarche@gmail.com> Link: https://github.com/openwrt/openwrt/pull/18166 Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
This commit is contained in:
parent
afea8bda0d
commit
ad2077165b
18 changed files with 12118 additions and 24 deletions
|
@ -231,7 +231,8 @@ CONFIG_NET_FLOW_LIMIT=y
|
|||
# CONFIG_NET_MEDIATEK_SOC is not set
|
||||
CONFIG_NET_SELFTESTS=y
|
||||
# CONFIG_NET_VENDOR_3COM is not set
|
||||
CONFIG_NET_VENDOR_MEDIATEK=y
|
||||
CONFIG_NET_VENDOR_AIROHA=y
|
||||
# CONFIG_NET_VENDOR_MEDIATEK is not set
|
||||
CONFIG_NLS=y
|
||||
CONFIG_NO_HZ_COMMON=y
|
||||
CONFIG_NO_HZ_IDLE=y
|
||||
|
|
|
@ -23,8 +23,6 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
|||
drivers/net/ethernet/mediatek/airoha_eth.c | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/drivers/net/ethernet/mediatek/airoha_eth.c b/drivers/net/ethernet/mediatek/airoha_eth.c
|
||||
index 415d784de741..09f448f29124 100644
|
||||
--- a/drivers/net/ethernet/mediatek/airoha_eth.c
|
||||
+++ b/drivers/net/ethernet/mediatek/airoha_eth.c
|
||||
@@ -266,11 +266,11 @@
|
||||
|
@ -41,6 +39,3 @@ index 415d784de741..09f448f29124 100644
|
|||
#define GDM4_SPORT_OFF2_MASK GENMASK(19, 16)
|
||||
#define GDM4_SPORT_OFF1_MASK GENMASK(15, 12)
|
||||
#define GDM4_SPORT_OFF0_MASK GENMASK(11, 8)
|
||||
--
|
||||
2.48.1
|
||||
|
||||
|
|
|
@ -22,11 +22,9 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
|||
drivers/net/ethernet/mediatek/airoha_eth.c | 10 +++++-----
|
||||
1 file changed, 5 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/drivers/net/ethernet/mediatek/airoha_eth.c b/drivers/net/ethernet/mediatek/airoha_eth.c
|
||||
index 09f448f29124..aa5f220ddbcf 100644
|
||||
--- a/drivers/net/ethernet/mediatek/airoha_eth.c
|
||||
+++ b/drivers/net/ethernet/mediatek/airoha_eth.c
|
||||
@@ -2556,11 +2556,10 @@ static u16 airoha_dev_select_queue(struct net_device *dev, struct sk_buff *skb,
|
||||
@@ -2549,11 +2549,10 @@ static u16 airoha_dev_select_queue(struc
|
||||
static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,
|
||||
struct net_device *dev)
|
||||
{
|
||||
|
@ -39,7 +37,7 @@ index 09f448f29124..aa5f220ddbcf 100644
|
|||
struct netdev_queue *txq;
|
||||
struct airoha_queue *q;
|
||||
void *data = skb->data;
|
||||
@@ -2583,8 +2582,9 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,
|
||||
@@ -2576,8 +2575,9 @@ static netdev_tx_t airoha_dev_xmit(struc
|
||||
if (skb_cow_head(skb, 0))
|
||||
goto error;
|
||||
|
||||
|
@ -51,7 +49,7 @@ index 09f448f29124..aa5f220ddbcf 100644
|
|||
|
||||
tcp_hdr(skb)->check = (__force __sum16)csum;
|
||||
msg0 |= FIELD_PREP(QDMA_ETH_TXMSG_TSO_MASK, 1);
|
||||
@@ -2613,7 +2613,7 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,
|
||||
@@ -2606,7 +2606,7 @@ static netdev_tx_t airoha_dev_xmit(struc
|
||||
for (i = 0; i < nr_frags; i++) {
|
||||
struct airoha_qdma_desc *desc = &q->desc[index];
|
||||
struct airoha_queue_entry *e = &q->entry[index];
|
||||
|
@ -60,6 +58,3 @@ index 09f448f29124..aa5f220ddbcf 100644
|
|||
dma_addr_t addr;
|
||||
u32 val;
|
||||
|
||||
--
|
||||
2.48.1
|
||||
|
||||
|
|
|
@ -14,11 +14,9 @@ Signed-off-by: Andrew Lunn <andrew@lunn.ch>
|
|||
drivers/net/ethernet/mediatek/airoha_eth.c | 10 +++++++++-
|
||||
1 file changed, 9 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/drivers/net/ethernet/mediatek/airoha_eth.c b/drivers/net/ethernet/mediatek/airoha_eth.c
|
||||
index 21d6eed8aece..f463a505f5ba 100644
|
||||
--- a/drivers/net/ethernet/mediatek/airoha_eth.c
|
||||
+++ b/drivers/net/ethernet/mediatek/airoha_eth.c
|
||||
@@ -2342,7 +2342,7 @@ static int airoha_dev_stop(struct net_device *dev)
|
||||
@@ -2469,7 +2469,7 @@ static int airoha_dev_stop(struct net_de
|
||||
{
|
||||
struct airoha_gdm_port *port = netdev_priv(dev);
|
||||
struct airoha_qdma *qdma = port->qdma;
|
||||
|
@ -27,7 +25,7 @@ index 21d6eed8aece..f463a505f5ba 100644
|
|||
|
||||
netif_tx_disable(dev);
|
||||
err = airoha_set_gdm_ports(qdma->eth, false);
|
||||
@@ -2353,6 +2353,14 @@ static int airoha_dev_stop(struct net_device *dev)
|
||||
@@ -2480,6 +2480,14 @@ static int airoha_dev_stop(struct net_de
|
||||
GLOBAL_CFG_TX_DMA_EN_MASK |
|
||||
GLOBAL_CFG_RX_DMA_EN_MASK);
|
||||
|
||||
|
@ -42,6 +40,3 @@ index 21d6eed8aece..f463a505f5ba 100644
|
|||
return 0;
|
||||
}
|
||||
|
||||
--
|
||||
2.48.1
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,538 @@
|
|||
From b38f4ff0ceacd6ce8d333a8dc90f405a040968d3 Mon Sep 17 00:00:00 2001
|
||||
From: Lorenzo Bianconi <lorenzo@kernel.org>
|
||||
Date: Fri, 28 Feb 2025 11:54:10 +0100
|
||||
Subject: [PATCH 02/15] net: airoha: Move definitions in airoha_eth.h
|
||||
|
||||
Move common airoha_eth definitions in airoha_eth.h in order to reuse
|
||||
them for Packet Processor Engine (PPE) codebase.
|
||||
PPE module is used to enable support for flowtable hw offloading in
|
||||
airoha_eth driver.
|
||||
|
||||
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
|
||||
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||
---
|
||||
drivers/net/ethernet/airoha/airoha_eth.c | 240 +---------------------
|
||||
drivers/net/ethernet/airoha/airoha_eth.h | 251 +++++++++++++++++++++++
|
||||
2 files changed, 252 insertions(+), 239 deletions(-)
|
||||
create mode 100644 drivers/net/ethernet/airoha/airoha_eth.h
|
||||
|
||||
--- a/drivers/net/ethernet/airoha/airoha_eth.c
|
||||
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
|
||||
@@ -3,14 +3,9 @@
|
||||
* Copyright (c) 2024 AIROHA Inc
|
||||
* Author: Lorenzo Bianconi <lorenzo@kernel.org>
|
||||
*/
|
||||
-#include <linux/etherdevice.h>
|
||||
-#include <linux/iopoll.h>
|
||||
-#include <linux/kernel.h>
|
||||
-#include <linux/netdevice.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_net.h>
|
||||
#include <linux/platform_device.h>
|
||||
-#include <linux/reset.h>
|
||||
#include <linux/tcp.h>
|
||||
#include <linux/u64_stats_sync.h>
|
||||
#include <net/dsa.h>
|
||||
@@ -18,35 +13,7 @@
|
||||
#include <net/pkt_cls.h>
|
||||
#include <uapi/linux/ppp_defs.h>
|
||||
|
||||
-#define AIROHA_MAX_NUM_GDM_PORTS 1
|
||||
-#define AIROHA_MAX_NUM_QDMA 2
|
||||
-#define AIROHA_MAX_NUM_RSTS 3
|
||||
-#define AIROHA_MAX_NUM_XSI_RSTS 5
|
||||
-#define AIROHA_MAX_MTU 2000
|
||||
-#define AIROHA_MAX_PACKET_SIZE 2048
|
||||
-#define AIROHA_NUM_QOS_CHANNELS 4
|
||||
-#define AIROHA_NUM_QOS_QUEUES 8
|
||||
-#define AIROHA_NUM_TX_RING 32
|
||||
-#define AIROHA_NUM_RX_RING 32
|
||||
-#define AIROHA_NUM_NETDEV_TX_RINGS (AIROHA_NUM_TX_RING + \
|
||||
- AIROHA_NUM_QOS_CHANNELS)
|
||||
-#define AIROHA_FE_MC_MAX_VLAN_TABLE 64
|
||||
-#define AIROHA_FE_MC_MAX_VLAN_PORT 16
|
||||
-#define AIROHA_NUM_TX_IRQ 2
|
||||
-#define HW_DSCP_NUM 2048
|
||||
-#define IRQ_QUEUE_LEN(_n) ((_n) ? 1024 : 2048)
|
||||
-#define TX_DSCP_NUM 1024
|
||||
-#define RX_DSCP_NUM(_n) \
|
||||
- ((_n) == 2 ? 128 : \
|
||||
- (_n) == 11 ? 128 : \
|
||||
- (_n) == 15 ? 128 : \
|
||||
- (_n) == 0 ? 1024 : 16)
|
||||
-
|
||||
-#define PSE_RSV_PAGES 128
|
||||
-#define PSE_QUEUE_RSV_PAGES 64
|
||||
-
|
||||
-#define QDMA_METER_IDX(_n) ((_n) & 0xff)
|
||||
-#define QDMA_METER_GROUP(_n) (((_n) >> 8) & 0x3)
|
||||
+#include "airoha_eth.h"
|
||||
|
||||
/* FE */
|
||||
#define PSE_BASE 0x0100
|
||||
@@ -706,211 +673,6 @@ struct airoha_qdma_fwd_desc {
|
||||
__le32 rsv1;
|
||||
};
|
||||
|
||||
-enum {
|
||||
- QDMA_INT_REG_IDX0,
|
||||
- QDMA_INT_REG_IDX1,
|
||||
- QDMA_INT_REG_IDX2,
|
||||
- QDMA_INT_REG_IDX3,
|
||||
- QDMA_INT_REG_IDX4,
|
||||
- QDMA_INT_REG_MAX
|
||||
-};
|
||||
-
|
||||
-enum {
|
||||
- XSI_PCIE0_PORT,
|
||||
- XSI_PCIE1_PORT,
|
||||
- XSI_USB_PORT,
|
||||
- XSI_AE_PORT,
|
||||
- XSI_ETH_PORT,
|
||||
-};
|
||||
-
|
||||
-enum {
|
||||
- XSI_PCIE0_VIP_PORT_MASK = BIT(22),
|
||||
- XSI_PCIE1_VIP_PORT_MASK = BIT(23),
|
||||
- XSI_USB_VIP_PORT_MASK = BIT(25),
|
||||
- XSI_ETH_VIP_PORT_MASK = BIT(24),
|
||||
-};
|
||||
-
|
||||
-enum {
|
||||
- DEV_STATE_INITIALIZED,
|
||||
-};
|
||||
-
|
||||
-enum {
|
||||
- CDM_CRSN_QSEL_Q1 = 1,
|
||||
- CDM_CRSN_QSEL_Q5 = 5,
|
||||
- CDM_CRSN_QSEL_Q6 = 6,
|
||||
- CDM_CRSN_QSEL_Q15 = 15,
|
||||
-};
|
||||
-
|
||||
-enum {
|
||||
- CRSN_08 = 0x8,
|
||||
- CRSN_21 = 0x15, /* KA */
|
||||
- CRSN_22 = 0x16, /* hit bind and force route to CPU */
|
||||
- CRSN_24 = 0x18,
|
||||
- CRSN_25 = 0x19,
|
||||
-};
|
||||
-
|
||||
-enum {
|
||||
- FE_PSE_PORT_CDM1,
|
||||
- FE_PSE_PORT_GDM1,
|
||||
- FE_PSE_PORT_GDM2,
|
||||
- FE_PSE_PORT_GDM3,
|
||||
- FE_PSE_PORT_PPE1,
|
||||
- FE_PSE_PORT_CDM2,
|
||||
- FE_PSE_PORT_CDM3,
|
||||
- FE_PSE_PORT_CDM4,
|
||||
- FE_PSE_PORT_PPE2,
|
||||
- FE_PSE_PORT_GDM4,
|
||||
- FE_PSE_PORT_CDM5,
|
||||
- FE_PSE_PORT_DROP = 0xf,
|
||||
-};
|
||||
-
|
||||
-enum tx_sched_mode {
|
||||
- TC_SCH_WRR8,
|
||||
- TC_SCH_SP,
|
||||
- TC_SCH_WRR7,
|
||||
- TC_SCH_WRR6,
|
||||
- TC_SCH_WRR5,
|
||||
- TC_SCH_WRR4,
|
||||
- TC_SCH_WRR3,
|
||||
- TC_SCH_WRR2,
|
||||
-};
|
||||
-
|
||||
-enum trtcm_param_type {
|
||||
- TRTCM_MISC_MODE, /* meter_en, pps_mode, tick_sel */
|
||||
- TRTCM_TOKEN_RATE_MODE,
|
||||
- TRTCM_BUCKETSIZE_SHIFT_MODE,
|
||||
- TRTCM_BUCKET_COUNTER_MODE,
|
||||
-};
|
||||
-
|
||||
-enum trtcm_mode_type {
|
||||
- TRTCM_COMMIT_MODE,
|
||||
- TRTCM_PEAK_MODE,
|
||||
-};
|
||||
-
|
||||
-enum trtcm_param {
|
||||
- TRTCM_TICK_SEL = BIT(0),
|
||||
- TRTCM_PKT_MODE = BIT(1),
|
||||
- TRTCM_METER_MODE = BIT(2),
|
||||
-};
|
||||
-
|
||||
-#define MIN_TOKEN_SIZE 4096
|
||||
-#define MAX_TOKEN_SIZE_OFFSET 17
|
||||
-#define TRTCM_TOKEN_RATE_MASK GENMASK(23, 6)
|
||||
-#define TRTCM_TOKEN_RATE_FRACTION_MASK GENMASK(5, 0)
|
||||
-
|
||||
-struct airoha_queue_entry {
|
||||
- union {
|
||||
- void *buf;
|
||||
- struct sk_buff *skb;
|
||||
- };
|
||||
- dma_addr_t dma_addr;
|
||||
- u16 dma_len;
|
||||
-};
|
||||
-
|
||||
-struct airoha_queue {
|
||||
- struct airoha_qdma *qdma;
|
||||
-
|
||||
- /* protect concurrent queue accesses */
|
||||
- spinlock_t lock;
|
||||
- struct airoha_queue_entry *entry;
|
||||
- struct airoha_qdma_desc *desc;
|
||||
- u16 head;
|
||||
- u16 tail;
|
||||
-
|
||||
- int queued;
|
||||
- int ndesc;
|
||||
- int free_thr;
|
||||
- int buf_size;
|
||||
-
|
||||
- struct napi_struct napi;
|
||||
- struct page_pool *page_pool;
|
||||
-};
|
||||
-
|
||||
-struct airoha_tx_irq_queue {
|
||||
- struct airoha_qdma *qdma;
|
||||
-
|
||||
- struct napi_struct napi;
|
||||
-
|
||||
- int size;
|
||||
- u32 *q;
|
||||
-};
|
||||
-
|
||||
-struct airoha_hw_stats {
|
||||
- /* protect concurrent hw_stats accesses */
|
||||
- spinlock_t lock;
|
||||
- struct u64_stats_sync syncp;
|
||||
-
|
||||
- /* get_stats64 */
|
||||
- u64 rx_ok_pkts;
|
||||
- u64 tx_ok_pkts;
|
||||
- u64 rx_ok_bytes;
|
||||
- u64 tx_ok_bytes;
|
||||
- u64 rx_multicast;
|
||||
- u64 rx_errors;
|
||||
- u64 rx_drops;
|
||||
- u64 tx_drops;
|
||||
- u64 rx_crc_error;
|
||||
- u64 rx_over_errors;
|
||||
- /* ethtool stats */
|
||||
- u64 tx_broadcast;
|
||||
- u64 tx_multicast;
|
||||
- u64 tx_len[7];
|
||||
- u64 rx_broadcast;
|
||||
- u64 rx_fragment;
|
||||
- u64 rx_jabber;
|
||||
- u64 rx_len[7];
|
||||
-};
|
||||
-
|
||||
-struct airoha_qdma {
|
||||
- struct airoha_eth *eth;
|
||||
- void __iomem *regs;
|
||||
-
|
||||
- /* protect concurrent irqmask accesses */
|
||||
- spinlock_t irq_lock;
|
||||
- u32 irqmask[QDMA_INT_REG_MAX];
|
||||
- int irq;
|
||||
-
|
||||
- struct airoha_tx_irq_queue q_tx_irq[AIROHA_NUM_TX_IRQ];
|
||||
-
|
||||
- struct airoha_queue q_tx[AIROHA_NUM_TX_RING];
|
||||
- struct airoha_queue q_rx[AIROHA_NUM_RX_RING];
|
||||
-
|
||||
- /* descriptor and packet buffers for qdma hw forward */
|
||||
- struct {
|
||||
- void *desc;
|
||||
- void *q;
|
||||
- } hfwd;
|
||||
-};
|
||||
-
|
||||
-struct airoha_gdm_port {
|
||||
- struct airoha_qdma *qdma;
|
||||
- struct net_device *dev;
|
||||
- int id;
|
||||
-
|
||||
- struct airoha_hw_stats stats;
|
||||
-
|
||||
- DECLARE_BITMAP(qos_sq_bmap, AIROHA_NUM_QOS_CHANNELS);
|
||||
-
|
||||
- /* qos stats counters */
|
||||
- u64 cpu_tx_packets;
|
||||
- u64 fwd_tx_packets;
|
||||
-};
|
||||
-
|
||||
-struct airoha_eth {
|
||||
- struct device *dev;
|
||||
-
|
||||
- unsigned long state;
|
||||
- void __iomem *fe_regs;
|
||||
-
|
||||
- struct reset_control_bulk_data rsts[AIROHA_MAX_NUM_RSTS];
|
||||
- struct reset_control_bulk_data xsi_rsts[AIROHA_MAX_NUM_XSI_RSTS];
|
||||
-
|
||||
- struct net_device *napi_dev;
|
||||
-
|
||||
- struct airoha_qdma qdma[AIROHA_MAX_NUM_QDMA];
|
||||
- struct airoha_gdm_port *ports[AIROHA_MAX_NUM_GDM_PORTS];
|
||||
-};
|
||||
-
|
||||
static u32 airoha_rr(void __iomem *base, u32 offset)
|
||||
{
|
||||
return readl(base + offset);
|
||||
--- /dev/null
|
||||
+++ b/drivers/net/ethernet/airoha/airoha_eth.h
|
||||
@@ -0,0 +1,251 @@
|
||||
+/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
+/*
|
||||
+ * Copyright (c) 2024 AIROHA Inc
|
||||
+ * Author: Lorenzo Bianconi <lorenzo@kernel.org>
|
||||
+ */
|
||||
+
|
||||
+#ifndef AIROHA_ETH_H
|
||||
+#define AIROHA_ETH_H
|
||||
+
|
||||
+#include <linux/etherdevice.h>
|
||||
+#include <linux/iopoll.h>
|
||||
+#include <linux/kernel.h>
|
||||
+#include <linux/netdevice.h>
|
||||
+#include <linux/reset.h>
|
||||
+
|
||||
+#define AIROHA_MAX_NUM_GDM_PORTS 1
|
||||
+#define AIROHA_MAX_NUM_QDMA 2
|
||||
+#define AIROHA_MAX_NUM_RSTS 3
|
||||
+#define AIROHA_MAX_NUM_XSI_RSTS 5
|
||||
+#define AIROHA_MAX_MTU 2000
|
||||
+#define AIROHA_MAX_PACKET_SIZE 2048
|
||||
+#define AIROHA_NUM_QOS_CHANNELS 4
|
||||
+#define AIROHA_NUM_QOS_QUEUES 8
|
||||
+#define AIROHA_NUM_TX_RING 32
|
||||
+#define AIROHA_NUM_RX_RING 32
|
||||
+#define AIROHA_NUM_NETDEV_TX_RINGS (AIROHA_NUM_TX_RING + \
|
||||
+ AIROHA_NUM_QOS_CHANNELS)
|
||||
+#define AIROHA_FE_MC_MAX_VLAN_TABLE 64
|
||||
+#define AIROHA_FE_MC_MAX_VLAN_PORT 16
|
||||
+#define AIROHA_NUM_TX_IRQ 2
|
||||
+#define HW_DSCP_NUM 2048
|
||||
+#define IRQ_QUEUE_LEN(_n) ((_n) ? 1024 : 2048)
|
||||
+#define TX_DSCP_NUM 1024
|
||||
+#define RX_DSCP_NUM(_n) \
|
||||
+ ((_n) == 2 ? 128 : \
|
||||
+ (_n) == 11 ? 128 : \
|
||||
+ (_n) == 15 ? 128 : \
|
||||
+ (_n) == 0 ? 1024 : 16)
|
||||
+
|
||||
+#define PSE_RSV_PAGES 128
|
||||
+#define PSE_QUEUE_RSV_PAGES 64
|
||||
+
|
||||
+#define QDMA_METER_IDX(_n) ((_n) & 0xff)
|
||||
+#define QDMA_METER_GROUP(_n) (((_n) >> 8) & 0x3)
|
||||
+
|
||||
+enum {
|
||||
+ QDMA_INT_REG_IDX0,
|
||||
+ QDMA_INT_REG_IDX1,
|
||||
+ QDMA_INT_REG_IDX2,
|
||||
+ QDMA_INT_REG_IDX3,
|
||||
+ QDMA_INT_REG_IDX4,
|
||||
+ QDMA_INT_REG_MAX
|
||||
+};
|
||||
+
|
||||
+enum {
|
||||
+ XSI_PCIE0_PORT,
|
||||
+ XSI_PCIE1_PORT,
|
||||
+ XSI_USB_PORT,
|
||||
+ XSI_AE_PORT,
|
||||
+ XSI_ETH_PORT,
|
||||
+};
|
||||
+
|
||||
+enum {
|
||||
+ XSI_PCIE0_VIP_PORT_MASK = BIT(22),
|
||||
+ XSI_PCIE1_VIP_PORT_MASK = BIT(23),
|
||||
+ XSI_USB_VIP_PORT_MASK = BIT(25),
|
||||
+ XSI_ETH_VIP_PORT_MASK = BIT(24),
|
||||
+};
|
||||
+
|
||||
+enum {
|
||||
+ DEV_STATE_INITIALIZED,
|
||||
+};
|
||||
+
|
||||
+enum {
|
||||
+ CDM_CRSN_QSEL_Q1 = 1,
|
||||
+ CDM_CRSN_QSEL_Q5 = 5,
|
||||
+ CDM_CRSN_QSEL_Q6 = 6,
|
||||
+ CDM_CRSN_QSEL_Q15 = 15,
|
||||
+};
|
||||
+
|
||||
+enum {
|
||||
+ CRSN_08 = 0x8,
|
||||
+ CRSN_21 = 0x15, /* KA */
|
||||
+ CRSN_22 = 0x16, /* hit bind and force route to CPU */
|
||||
+ CRSN_24 = 0x18,
|
||||
+ CRSN_25 = 0x19,
|
||||
+};
|
||||
+
|
||||
+enum {
|
||||
+ FE_PSE_PORT_CDM1,
|
||||
+ FE_PSE_PORT_GDM1,
|
||||
+ FE_PSE_PORT_GDM2,
|
||||
+ FE_PSE_PORT_GDM3,
|
||||
+ FE_PSE_PORT_PPE1,
|
||||
+ FE_PSE_PORT_CDM2,
|
||||
+ FE_PSE_PORT_CDM3,
|
||||
+ FE_PSE_PORT_CDM4,
|
||||
+ FE_PSE_PORT_PPE2,
|
||||
+ FE_PSE_PORT_GDM4,
|
||||
+ FE_PSE_PORT_CDM5,
|
||||
+ FE_PSE_PORT_DROP = 0xf,
|
||||
+};
|
||||
+
|
||||
+enum tx_sched_mode {
|
||||
+ TC_SCH_WRR8,
|
||||
+ TC_SCH_SP,
|
||||
+ TC_SCH_WRR7,
|
||||
+ TC_SCH_WRR6,
|
||||
+ TC_SCH_WRR5,
|
||||
+ TC_SCH_WRR4,
|
||||
+ TC_SCH_WRR3,
|
||||
+ TC_SCH_WRR2,
|
||||
+};
|
||||
+
|
||||
+enum trtcm_param_type {
|
||||
+ TRTCM_MISC_MODE, /* meter_en, pps_mode, tick_sel */
|
||||
+ TRTCM_TOKEN_RATE_MODE,
|
||||
+ TRTCM_BUCKETSIZE_SHIFT_MODE,
|
||||
+ TRTCM_BUCKET_COUNTER_MODE,
|
||||
+};
|
||||
+
|
||||
+enum trtcm_mode_type {
|
||||
+ TRTCM_COMMIT_MODE,
|
||||
+ TRTCM_PEAK_MODE,
|
||||
+};
|
||||
+
|
||||
+enum trtcm_param {
|
||||
+ TRTCM_TICK_SEL = BIT(0),
|
||||
+ TRTCM_PKT_MODE = BIT(1),
|
||||
+ TRTCM_METER_MODE = BIT(2),
|
||||
+};
|
||||
+
|
||||
+#define MIN_TOKEN_SIZE 4096
|
||||
+#define MAX_TOKEN_SIZE_OFFSET 17
|
||||
+#define TRTCM_TOKEN_RATE_MASK GENMASK(23, 6)
|
||||
+#define TRTCM_TOKEN_RATE_FRACTION_MASK GENMASK(5, 0)
|
||||
+
|
||||
+struct airoha_queue_entry {
|
||||
+ union {
|
||||
+ void *buf;
|
||||
+ struct sk_buff *skb;
|
||||
+ };
|
||||
+ dma_addr_t dma_addr;
|
||||
+ u16 dma_len;
|
||||
+};
|
||||
+
|
||||
+struct airoha_queue {
|
||||
+ struct airoha_qdma *qdma;
|
||||
+
|
||||
+ /* protect concurrent queue accesses */
|
||||
+ spinlock_t lock;
|
||||
+ struct airoha_queue_entry *entry;
|
||||
+ struct airoha_qdma_desc *desc;
|
||||
+ u16 head;
|
||||
+ u16 tail;
|
||||
+
|
||||
+ int queued;
|
||||
+ int ndesc;
|
||||
+ int free_thr;
|
||||
+ int buf_size;
|
||||
+
|
||||
+ struct napi_struct napi;
|
||||
+ struct page_pool *page_pool;
|
||||
+};
|
||||
+
|
||||
+struct airoha_tx_irq_queue {
|
||||
+ struct airoha_qdma *qdma;
|
||||
+
|
||||
+ struct napi_struct napi;
|
||||
+
|
||||
+ int size;
|
||||
+ u32 *q;
|
||||
+};
|
||||
+
|
||||
+struct airoha_hw_stats {
|
||||
+ /* protect concurrent hw_stats accesses */
|
||||
+ spinlock_t lock;
|
||||
+ struct u64_stats_sync syncp;
|
||||
+
|
||||
+ /* get_stats64 */
|
||||
+ u64 rx_ok_pkts;
|
||||
+ u64 tx_ok_pkts;
|
||||
+ u64 rx_ok_bytes;
|
||||
+ u64 tx_ok_bytes;
|
||||
+ u64 rx_multicast;
|
||||
+ u64 rx_errors;
|
||||
+ u64 rx_drops;
|
||||
+ u64 tx_drops;
|
||||
+ u64 rx_crc_error;
|
||||
+ u64 rx_over_errors;
|
||||
+ /* ethtool stats */
|
||||
+ u64 tx_broadcast;
|
||||
+ u64 tx_multicast;
|
||||
+ u64 tx_len[7];
|
||||
+ u64 rx_broadcast;
|
||||
+ u64 rx_fragment;
|
||||
+ u64 rx_jabber;
|
||||
+ u64 rx_len[7];
|
||||
+};
|
||||
+
|
||||
+struct airoha_qdma {
|
||||
+ struct airoha_eth *eth;
|
||||
+ void __iomem *regs;
|
||||
+
|
||||
+ /* protect concurrent irqmask accesses */
|
||||
+ spinlock_t irq_lock;
|
||||
+ u32 irqmask[QDMA_INT_REG_MAX];
|
||||
+ int irq;
|
||||
+
|
||||
+ struct airoha_tx_irq_queue q_tx_irq[AIROHA_NUM_TX_IRQ];
|
||||
+
|
||||
+ struct airoha_queue q_tx[AIROHA_NUM_TX_RING];
|
||||
+ struct airoha_queue q_rx[AIROHA_NUM_RX_RING];
|
||||
+
|
||||
+ /* descriptor and packet buffers for qdma hw forward */
|
||||
+ struct {
|
||||
+ void *desc;
|
||||
+ void *q;
|
||||
+ } hfwd;
|
||||
+};
|
||||
+
|
||||
+struct airoha_gdm_port {
|
||||
+ struct airoha_qdma *qdma;
|
||||
+ struct net_device *dev;
|
||||
+ int id;
|
||||
+
|
||||
+ struct airoha_hw_stats stats;
|
||||
+
|
||||
+ DECLARE_BITMAP(qos_sq_bmap, AIROHA_NUM_QOS_CHANNELS);
|
||||
+
|
||||
+ /* qos stats counters */
|
||||
+ u64 cpu_tx_packets;
|
||||
+ u64 fwd_tx_packets;
|
||||
+};
|
||||
+
|
||||
+struct airoha_eth {
|
||||
+ struct device *dev;
|
||||
+
|
||||
+ unsigned long state;
|
||||
+ void __iomem *fe_regs;
|
||||
+
|
||||
+ struct reset_control_bulk_data rsts[AIROHA_MAX_NUM_RSTS];
|
||||
+ struct reset_control_bulk_data xsi_rsts[AIROHA_MAX_NUM_XSI_RSTS];
|
||||
+
|
||||
+ struct net_device *napi_dev;
|
||||
+
|
||||
+ struct airoha_qdma qdma[AIROHA_MAX_NUM_QDMA];
|
||||
+ struct airoha_gdm_port *ports[AIROHA_MAX_NUM_GDM_PORTS];
|
||||
+};
|
||||
+
|
||||
+#endif /* AIROHA_ETH_H */
|
|
@ -0,0 +1,101 @@
|
|||
From e0758a8694fbaffdc72940774db295585e951119 Mon Sep 17 00:00:00 2001
|
||||
From: Lorenzo Bianconi <lorenzo@kernel.org>
|
||||
Date: Fri, 28 Feb 2025 11:54:11 +0100
|
||||
Subject: [PATCH 03/15] net: airoha: Move reg/write utility routines in
|
||||
airoha_eth.h
|
||||
|
||||
This is a preliminary patch to introduce flowtable hw offloading
|
||||
support for airoha_eth driver.
|
||||
|
||||
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
|
||||
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||
---
|
||||
drivers/net/ethernet/airoha/airoha_eth.c | 28 +++---------------------
|
||||
drivers/net/ethernet/airoha/airoha_eth.h | 26 ++++++++++++++++++++++
|
||||
2 files changed, 29 insertions(+), 25 deletions(-)
|
||||
|
||||
--- a/drivers/net/ethernet/airoha/airoha_eth.c
|
||||
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
|
||||
@@ -673,17 +673,17 @@ struct airoha_qdma_fwd_desc {
|
||||
__le32 rsv1;
|
||||
};
|
||||
|
||||
-static u32 airoha_rr(void __iomem *base, u32 offset)
|
||||
+u32 airoha_rr(void __iomem *base, u32 offset)
|
||||
{
|
||||
return readl(base + offset);
|
||||
}
|
||||
|
||||
-static void airoha_wr(void __iomem *base, u32 offset, u32 val)
|
||||
+void airoha_wr(void __iomem *base, u32 offset, u32 val)
|
||||
{
|
||||
writel(val, base + offset);
|
||||
}
|
||||
|
||||
-static u32 airoha_rmw(void __iomem *base, u32 offset, u32 mask, u32 val)
|
||||
+u32 airoha_rmw(void __iomem *base, u32 offset, u32 mask, u32 val)
|
||||
{
|
||||
val |= (airoha_rr(base, offset) & ~mask);
|
||||
airoha_wr(base, offset, val);
|
||||
@@ -691,28 +691,6 @@ static u32 airoha_rmw(void __iomem *base
|
||||
return val;
|
||||
}
|
||||
|
||||
-#define airoha_fe_rr(eth, offset) \
|
||||
- airoha_rr((eth)->fe_regs, (offset))
|
||||
-#define airoha_fe_wr(eth, offset, val) \
|
||||
- airoha_wr((eth)->fe_regs, (offset), (val))
|
||||
-#define airoha_fe_rmw(eth, offset, mask, val) \
|
||||
- airoha_rmw((eth)->fe_regs, (offset), (mask), (val))
|
||||
-#define airoha_fe_set(eth, offset, val) \
|
||||
- airoha_rmw((eth)->fe_regs, (offset), 0, (val))
|
||||
-#define airoha_fe_clear(eth, offset, val) \
|
||||
- airoha_rmw((eth)->fe_regs, (offset), (val), 0)
|
||||
-
|
||||
-#define airoha_qdma_rr(qdma, offset) \
|
||||
- airoha_rr((qdma)->regs, (offset))
|
||||
-#define airoha_qdma_wr(qdma, offset, val) \
|
||||
- airoha_wr((qdma)->regs, (offset), (val))
|
||||
-#define airoha_qdma_rmw(qdma, offset, mask, val) \
|
||||
- airoha_rmw((qdma)->regs, (offset), (mask), (val))
|
||||
-#define airoha_qdma_set(qdma, offset, val) \
|
||||
- airoha_rmw((qdma)->regs, (offset), 0, (val))
|
||||
-#define airoha_qdma_clear(qdma, offset, val) \
|
||||
- airoha_rmw((qdma)->regs, (offset), (val), 0)
|
||||
-
|
||||
static void airoha_qdma_set_irqmask(struct airoha_qdma *qdma, int index,
|
||||
u32 clear, u32 set)
|
||||
{
|
||||
--- a/drivers/net/ethernet/airoha/airoha_eth.h
|
||||
+++ b/drivers/net/ethernet/airoha/airoha_eth.h
|
||||
@@ -248,4 +248,30 @@ struct airoha_eth {
|
||||
struct airoha_gdm_port *ports[AIROHA_MAX_NUM_GDM_PORTS];
|
||||
};
|
||||
|
||||
+u32 airoha_rr(void __iomem *base, u32 offset);
|
||||
+void airoha_wr(void __iomem *base, u32 offset, u32 val);
|
||||
+u32 airoha_rmw(void __iomem *base, u32 offset, u32 mask, u32 val);
|
||||
+
|
||||
+#define airoha_fe_rr(eth, offset) \
|
||||
+ airoha_rr((eth)->fe_regs, (offset))
|
||||
+#define airoha_fe_wr(eth, offset, val) \
|
||||
+ airoha_wr((eth)->fe_regs, (offset), (val))
|
||||
+#define airoha_fe_rmw(eth, offset, mask, val) \
|
||||
+ airoha_rmw((eth)->fe_regs, (offset), (mask), (val))
|
||||
+#define airoha_fe_set(eth, offset, val) \
|
||||
+ airoha_rmw((eth)->fe_regs, (offset), 0, (val))
|
||||
+#define airoha_fe_clear(eth, offset, val) \
|
||||
+ airoha_rmw((eth)->fe_regs, (offset), (val), 0)
|
||||
+
|
||||
+#define airoha_qdma_rr(qdma, offset) \
|
||||
+ airoha_rr((qdma)->regs, (offset))
|
||||
+#define airoha_qdma_wr(qdma, offset, val) \
|
||||
+ airoha_wr((qdma)->regs, (offset), (val))
|
||||
+#define airoha_qdma_rmw(qdma, offset, mask, val) \
|
||||
+ airoha_rmw((qdma)->regs, (offset), (mask), (val))
|
||||
+#define airoha_qdma_set(qdma, offset, val) \
|
||||
+ airoha_rmw((qdma)->regs, (offset), 0, (val))
|
||||
+#define airoha_qdma_clear(qdma, offset, val) \
|
||||
+ airoha_rmw((qdma)->regs, (offset), (val), 0)
|
||||
+
|
||||
#endif /* AIROHA_ETH_H */
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,287 @@
|
|||
From af3cf757d5c99011b9b94ea8d78aeaccc0153fdc Mon Sep 17 00:00:00 2001
|
||||
From: Lorenzo Bianconi <lorenzo@kernel.org>
|
||||
Date: Fri, 28 Feb 2025 11:54:13 +0100
|
||||
Subject: [PATCH 05/15] net: airoha: Move DSA tag in DMA descriptor
|
||||
|
||||
Packet Processor Engine (PPE) module reads DSA tags from the DMA descriptor
|
||||
and requires untagged DSA packets to properly parse them. Move DSA tag
|
||||
in the DMA descriptor on TX side and read DSA tag from DMA descriptor
|
||||
on RX side. In order to avoid skb reallocation, store tag in skb_dst on
|
||||
RX side.
|
||||
This is a preliminary patch to enable netfilter flowtable hw offloading
|
||||
on EN7581 SoC.
|
||||
|
||||
Tested-by: Sayantan Nandy <sayantan.nandy@airoha.com>
|
||||
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
|
||||
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||
---
|
||||
drivers/net/ethernet/airoha/airoha_eth.c | 125 ++++++++++++++++++++--
|
||||
drivers/net/ethernet/airoha/airoha_eth.h | 7 ++
|
||||
drivers/net/ethernet/airoha/airoha_regs.h | 2 +
|
||||
3 files changed, 128 insertions(+), 6 deletions(-)
|
||||
|
||||
--- a/drivers/net/ethernet/airoha/airoha_eth.c
|
||||
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <linux/tcp.h>
|
||||
#include <linux/u64_stats_sync.h>
|
||||
#include <net/dsa.h>
|
||||
+#include <net/dst_metadata.h>
|
||||
#include <net/page_pool/helpers.h>
|
||||
#include <net/pkt_cls.h>
|
||||
#include <uapi/linux/ppp_defs.h>
|
||||
@@ -656,6 +657,7 @@ static int airoha_qdma_rx_process(struct
|
||||
struct airoha_qdma_desc *desc = &q->desc[q->tail];
|
||||
dma_addr_t dma_addr = le32_to_cpu(desc->addr);
|
||||
u32 desc_ctrl = le32_to_cpu(desc->ctrl);
|
||||
+ struct airoha_gdm_port *port;
|
||||
struct sk_buff *skb;
|
||||
int len, p;
|
||||
|
||||
@@ -683,6 +685,7 @@ static int airoha_qdma_rx_process(struct
|
||||
continue;
|
||||
}
|
||||
|
||||
+ port = eth->ports[p];
|
||||
skb = napi_build_skb(e->buf, q->buf_size);
|
||||
if (!skb) {
|
||||
page_pool_put_full_page(q->page_pool,
|
||||
@@ -694,10 +697,26 @@ static int airoha_qdma_rx_process(struct
|
||||
skb_reserve(skb, 2);
|
||||
__skb_put(skb, len);
|
||||
skb_mark_for_recycle(skb);
|
||||
- skb->dev = eth->ports[p]->dev;
|
||||
+ skb->dev = port->dev;
|
||||
skb->protocol = eth_type_trans(skb, skb->dev);
|
||||
skb->ip_summed = CHECKSUM_UNNECESSARY;
|
||||
skb_record_rx_queue(skb, qid);
|
||||
+
|
||||
+ if (netdev_uses_dsa(port->dev)) {
|
||||
+ /* 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 sptag = FIELD_GET(QDMA_ETH_RXMSG_SPTAG,
|
||||
+ le32_to_cpu(desc->msg0));
|
||||
+
|
||||
+ if (sptag < ARRAY_SIZE(port->dsa_meta) &&
|
||||
+ port->dsa_meta[sptag])
|
||||
+ skb_dst_set_noref(skb,
|
||||
+ &port->dsa_meta[sptag]->dst);
|
||||
+ }
|
||||
+
|
||||
napi_gro_receive(&q->napi, skb);
|
||||
|
||||
done++;
|
||||
@@ -1637,25 +1656,76 @@ static u16 airoha_dev_select_queue(struc
|
||||
return queue < dev->num_tx_queues ? queue : 0;
|
||||
}
|
||||
|
||||
+static u32 airoha_get_dsa_tag(struct sk_buff *skb, struct net_device *dev)
|
||||
+{
|
||||
+#if IS_ENABLED(CONFIG_NET_DSA)
|
||||
+ struct ethhdr *ehdr;
|
||||
+ struct dsa_port *dp;
|
||||
+ u8 xmit_tpid;
|
||||
+ u16 tag;
|
||||
+
|
||||
+ if (!netdev_uses_dsa(dev))
|
||||
+ return 0;
|
||||
+
|
||||
+ dp = dev->dsa_ptr;
|
||||
+ if (IS_ERR(dp))
|
||||
+ return 0;
|
||||
+
|
||||
+ if (dp->tag_ops->proto != DSA_TAG_PROTO_MTK)
|
||||
+ return 0;
|
||||
+
|
||||
+ if (skb_cow_head(skb, 0))
|
||||
+ return 0;
|
||||
+
|
||||
+ ehdr = (struct ethhdr *)skb->data;
|
||||
+ tag = be16_to_cpu(ehdr->h_proto);
|
||||
+ xmit_tpid = tag >> 8;
|
||||
+
|
||||
+ switch (xmit_tpid) {
|
||||
+ case MTK_HDR_XMIT_TAGGED_TPID_8100:
|
||||
+ ehdr->h_proto = cpu_to_be16(ETH_P_8021Q);
|
||||
+ tag &= ~(MTK_HDR_XMIT_TAGGED_TPID_8100 << 8);
|
||||
+ break;
|
||||
+ case MTK_HDR_XMIT_TAGGED_TPID_88A8:
|
||||
+ ehdr->h_proto = cpu_to_be16(ETH_P_8021AD);
|
||||
+ tag &= ~(MTK_HDR_XMIT_TAGGED_TPID_88A8 << 8);
|
||||
+ break;
|
||||
+ default:
|
||||
+ /* PPE module requires untagged DSA packets to work properly,
|
||||
+ * so move DSA tag to DMA descriptor.
|
||||
+ */
|
||||
+ memmove(skb->data + MTK_HDR_LEN, skb->data, 2 * ETH_ALEN);
|
||||
+ __skb_pull(skb, MTK_HDR_LEN);
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ return tag;
|
||||
+#else
|
||||
+ return 0;
|
||||
+#endif
|
||||
+}
|
||||
+
|
||||
static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,
|
||||
struct net_device *dev)
|
||||
{
|
||||
struct airoha_gdm_port *port = netdev_priv(dev);
|
||||
- u32 nr_frags = 1 + skb_shinfo(skb)->nr_frags;
|
||||
- u32 msg0, msg1, len = skb_headlen(skb);
|
||||
struct airoha_qdma *qdma = port->qdma;
|
||||
+ u32 nr_frags, tag, msg0, msg1, len;
|
||||
struct netdev_queue *txq;
|
||||
struct airoha_queue *q;
|
||||
- void *data = skb->data;
|
||||
+ void *data;
|
||||
int i, qid;
|
||||
u16 index;
|
||||
u8 fport;
|
||||
|
||||
qid = skb_get_queue_mapping(skb) % ARRAY_SIZE(qdma->q_tx);
|
||||
+ tag = airoha_get_dsa_tag(skb, dev);
|
||||
+
|
||||
msg0 = FIELD_PREP(QDMA_ETH_TXMSG_CHAN_MASK,
|
||||
qid / AIROHA_NUM_QOS_QUEUES) |
|
||||
FIELD_PREP(QDMA_ETH_TXMSG_QUEUE_MASK,
|
||||
- qid % AIROHA_NUM_QOS_QUEUES);
|
||||
+ qid % AIROHA_NUM_QOS_QUEUES) |
|
||||
+ FIELD_PREP(QDMA_ETH_TXMSG_SP_TAG_MASK, tag);
|
||||
if (skb->ip_summed == CHECKSUM_PARTIAL)
|
||||
msg0 |= FIELD_PREP(QDMA_ETH_TXMSG_TCO_MASK, 1) |
|
||||
FIELD_PREP(QDMA_ETH_TXMSG_UCO_MASK, 1) |
|
||||
@@ -1686,6 +1756,8 @@ static netdev_tx_t airoha_dev_xmit(struc
|
||||
spin_lock_bh(&q->lock);
|
||||
|
||||
txq = netdev_get_tx_queue(dev, qid);
|
||||
+ nr_frags = 1 + skb_shinfo(skb)->nr_frags;
|
||||
+
|
||||
if (q->queued + nr_frags > q->ndesc) {
|
||||
/* not enough space in the queue */
|
||||
netif_tx_stop_queue(txq);
|
||||
@@ -1693,7 +1765,10 @@ static netdev_tx_t airoha_dev_xmit(struc
|
||||
return NETDEV_TX_BUSY;
|
||||
}
|
||||
|
||||
+ len = skb_headlen(skb);
|
||||
+ data = skb->data;
|
||||
index = q->head;
|
||||
+
|
||||
for (i = 0; i < nr_frags; i++) {
|
||||
struct airoha_qdma_desc *desc = &q->desc[index];
|
||||
struct airoha_queue_entry *e = &q->entry[index];
|
||||
@@ -2224,6 +2299,37 @@ static const struct ethtool_ops airoha_e
|
||||
.get_rmon_stats = airoha_ethtool_get_rmon_stats,
|
||||
};
|
||||
|
||||
+static int airoha_metadata_dst_alloc(struct airoha_gdm_port *port)
|
||||
+{
|
||||
+ int i;
|
||||
+
|
||||
+ for (i = 0; i < ARRAY_SIZE(port->dsa_meta); i++) {
|
||||
+ struct metadata_dst *md_dst;
|
||||
+
|
||||
+ md_dst = metadata_dst_alloc(0, METADATA_HW_PORT_MUX,
|
||||
+ GFP_KERNEL);
|
||||
+ if (!md_dst)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ md_dst->u.port_info.port_id = i;
|
||||
+ port->dsa_meta[i] = md_dst;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void airoha_metadata_dst_free(struct airoha_gdm_port *port)
|
||||
+{
|
||||
+ int i;
|
||||
+
|
||||
+ for (i = 0; i < ARRAY_SIZE(port->dsa_meta); i++) {
|
||||
+ if (!port->dsa_meta[i])
|
||||
+ continue;
|
||||
+
|
||||
+ metadata_dst_free(port->dsa_meta[i]);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
static int airoha_alloc_gdm_port(struct airoha_eth *eth, struct device_node *np)
|
||||
{
|
||||
const __be32 *id_ptr = of_get_property(np, "reg", NULL);
|
||||
@@ -2296,6 +2402,10 @@ static int airoha_alloc_gdm_port(struct
|
||||
port->id = id;
|
||||
eth->ports[index] = port;
|
||||
|
||||
+ err = airoha_metadata_dst_alloc(port);
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+
|
||||
return register_netdev(dev);
|
||||
}
|
||||
|
||||
@@ -2388,8 +2498,10 @@ error_hw_cleanup:
|
||||
for (i = 0; i < ARRAY_SIZE(eth->ports); i++) {
|
||||
struct airoha_gdm_port *port = eth->ports[i];
|
||||
|
||||
- if (port && port->dev->reg_state == NETREG_REGISTERED)
|
||||
+ if (port && port->dev->reg_state == NETREG_REGISTERED) {
|
||||
unregister_netdev(port->dev);
|
||||
+ airoha_metadata_dst_free(port);
|
||||
+ }
|
||||
}
|
||||
free_netdev(eth->napi_dev);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
@@ -2415,6 +2527,7 @@ static void airoha_remove(struct platfor
|
||||
|
||||
airoha_dev_stop(port->dev);
|
||||
unregister_netdev(port->dev);
|
||||
+ airoha_metadata_dst_free(port);
|
||||
}
|
||||
free_netdev(eth->napi_dev);
|
||||
|
||||
--- a/drivers/net/ethernet/airoha/airoha_eth.h
|
||||
+++ b/drivers/net/ethernet/airoha/airoha_eth.h
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
#define AIROHA_MAX_NUM_GDM_PORTS 1
|
||||
#define AIROHA_MAX_NUM_QDMA 2
|
||||
+#define AIROHA_MAX_DSA_PORTS 7
|
||||
#define AIROHA_MAX_NUM_RSTS 3
|
||||
#define AIROHA_MAX_NUM_XSI_RSTS 5
|
||||
#define AIROHA_MAX_MTU 2000
|
||||
@@ -43,6 +44,10 @@
|
||||
#define QDMA_METER_IDX(_n) ((_n) & 0xff)
|
||||
#define QDMA_METER_GROUP(_n) (((_n) >> 8) & 0x3)
|
||||
|
||||
+#define MTK_HDR_LEN 4
|
||||
+#define MTK_HDR_XMIT_TAGGED_TPID_8100 1
|
||||
+#define MTK_HDR_XMIT_TAGGED_TPID_88A8 2
|
||||
+
|
||||
enum {
|
||||
QDMA_INT_REG_IDX0,
|
||||
QDMA_INT_REG_IDX1,
|
||||
@@ -231,6 +236,8 @@ struct airoha_gdm_port {
|
||||
/* qos stats counters */
|
||||
u64 cpu_tx_packets;
|
||||
u64 fwd_tx_packets;
|
||||
+
|
||||
+ struct metadata_dst *dsa_meta[AIROHA_MAX_DSA_PORTS];
|
||||
};
|
||||
|
||||
struct airoha_eth {
|
||||
--- a/drivers/net/ethernet/airoha/airoha_regs.h
|
||||
+++ b/drivers/net/ethernet/airoha/airoha_regs.h
|
||||
@@ -624,6 +624,8 @@
|
||||
#define QDMA_ETH_TXMSG_ACNT_G1_MASK GENMASK(10, 6) /* 0x1f do not count */
|
||||
#define QDMA_ETH_TXMSG_ACNT_G0_MASK GENMASK(5, 0) /* 0x3f do not count */
|
||||
|
||||
+/* RX MSG0 */
|
||||
+#define QDMA_ETH_RXMSG_SPTAG GENMASK(21, 14)
|
||||
/* RX MSG1 */
|
||||
#define QDMA_ETH_RXMSG_DEI_MASK BIT(31)
|
||||
#define QDMA_ETH_RXMSG_IP6_MASK BIT(30)
|
|
@ -0,0 +1,46 @@
|
|||
From ab667db1e6014634c6607ebdddc16c1b8394a935 Mon Sep 17 00:00:00 2001
|
||||
From: Lorenzo Bianconi <lorenzo@kernel.org>
|
||||
Date: Fri, 28 Feb 2025 11:54:14 +0100
|
||||
Subject: [PATCH 06/15] net: dsa: mt7530: Enable Rx sptag for EN7581 SoC
|
||||
|
||||
Packet Processor Engine (PPE) module used for hw acceleration on EN7581
|
||||
mac block, in order to properly parse packets, requires DSA untagged
|
||||
packets on TX side and read DSA tag from DMA descriptor on RX side.
|
||||
For this reason, enable RX Special Tag (SPTAG) for EN7581 SoC.
|
||||
This is a preliminary patch to enable netfilter flowtable hw offloading
|
||||
on EN7581 SoC.
|
||||
|
||||
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
|
||||
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||
---
|
||||
drivers/net/dsa/mt7530.c | 5 +++++
|
||||
drivers/net/dsa/mt7530.h | 4 ++++
|
||||
2 files changed, 9 insertions(+)
|
||||
|
||||
--- a/drivers/net/dsa/mt7530.c
|
||||
+++ b/drivers/net/dsa/mt7530.c
|
||||
@@ -2585,6 +2585,11 @@ mt7531_setup_common(struct dsa_switch *d
|
||||
/* Allow mirroring frames received on the local port (monitor port). */
|
||||
mt7530_set(priv, MT753X_AGC, LOCAL_EN);
|
||||
|
||||
+ /* Enable Special Tag for rx frames */
|
||||
+ if (priv->id == ID_EN7581)
|
||||
+ mt7530_write(priv, MT753X_CPORT_SPTAG_CFG,
|
||||
+ CPORT_SW2FE_STAG_EN | CPORT_FE2SW_STAG_EN);
|
||||
+
|
||||
/* Flush the FDB table */
|
||||
ret = mt7530_fdb_cmd(priv, MT7530_FDB_FLUSH, NULL);
|
||||
if (ret < 0)
|
||||
--- a/drivers/net/dsa/mt7530.h
|
||||
+++ b/drivers/net/dsa/mt7530.h
|
||||
@@ -615,6 +615,10 @@ enum mt7531_xtal_fsel {
|
||||
#define MT7531_GPIO12_RG_RXD3_MASK GENMASK(19, 16)
|
||||
#define MT7531_EXT_P_MDIO_12 (2 << 16)
|
||||
|
||||
+#define MT753X_CPORT_SPTAG_CFG 0x7c10
|
||||
+#define CPORT_SW2FE_STAG_EN BIT(1)
|
||||
+#define CPORT_FE2SW_STAG_EN BIT(0)
|
||||
+
|
||||
/* Registers for LED GPIO control (MT7530 only)
|
||||
* All registers follow this pattern:
|
||||
* [ 2: 0] port 0
|
|
@ -0,0 +1,144 @@
|
|||
From 80369686737fe07c233a1152da0b84372dabdcd6 Mon Sep 17 00:00:00 2001
|
||||
From: Lorenzo Bianconi <lorenzo@kernel.org>
|
||||
Date: Fri, 28 Feb 2025 11:54:15 +0100
|
||||
Subject: [PATCH 07/15] net: airoha: Enable support for multiple net_devices
|
||||
|
||||
In the current codebase airoha_eth driver supports just a single
|
||||
net_device connected to the Packet Switch Engine (PSE) lan port (GDM1).
|
||||
As shown in commit 23020f049327 ("net: airoha: Introduce ethernet
|
||||
support for EN7581 SoC"), PSE can switch packets between four GDM ports.
|
||||
Enable the capability to create a net_device for each GDM port of the
|
||||
PSE module. Moreover, since the QDMA blocks can be shared between
|
||||
net_devices, do not stop TX/RX DMA in airoha_dev_stop() if there are
|
||||
active net_devices for this QDMA block.
|
||||
This is a preliminary patch to enable flowtable hw offloading for EN7581
|
||||
SoC.
|
||||
|
||||
Co-developed-by: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
|
||||
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||
---
|
||||
drivers/net/ethernet/airoha/airoha_eth.c | 35 ++++++++++++++----------
|
||||
drivers/net/ethernet/airoha/airoha_eth.h | 4 ++-
|
||||
2 files changed, 24 insertions(+), 15 deletions(-)
|
||||
|
||||
--- a/drivers/net/ethernet/airoha/airoha_eth.c
|
||||
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
|
||||
@@ -1563,6 +1563,7 @@ static int airoha_dev_open(struct net_de
|
||||
airoha_qdma_set(qdma, REG_QDMA_GLOBAL_CFG,
|
||||
GLOBAL_CFG_TX_DMA_EN_MASK |
|
||||
GLOBAL_CFG_RX_DMA_EN_MASK);
|
||||
+ atomic_inc(&qdma->users);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1578,16 +1579,20 @@ static int airoha_dev_stop(struct net_de
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
- airoha_qdma_clear(qdma, REG_QDMA_GLOBAL_CFG,
|
||||
- GLOBAL_CFG_TX_DMA_EN_MASK |
|
||||
- GLOBAL_CFG_RX_DMA_EN_MASK);
|
||||
+ for (i = 0; i < ARRAY_SIZE(qdma->q_tx); i++)
|
||||
+ netdev_tx_reset_subqueue(dev, i);
|
||||
|
||||
- for (i = 0; i < ARRAY_SIZE(qdma->q_tx); i++) {
|
||||
- if (!qdma->q_tx[i].ndesc)
|
||||
- continue;
|
||||
+ if (atomic_dec_and_test(&qdma->users)) {
|
||||
+ airoha_qdma_clear(qdma, REG_QDMA_GLOBAL_CFG,
|
||||
+ GLOBAL_CFG_TX_DMA_EN_MASK |
|
||||
+ GLOBAL_CFG_RX_DMA_EN_MASK);
|
||||
+
|
||||
+ for (i = 0; i < ARRAY_SIZE(qdma->q_tx); i++) {
|
||||
+ if (!qdma->q_tx[i].ndesc)
|
||||
+ continue;
|
||||
|
||||
- airoha_qdma_cleanup_tx_queue(&qdma->q_tx[i]);
|
||||
- netdev_tx_reset_subqueue(dev, i);
|
||||
+ airoha_qdma_cleanup_tx_queue(&qdma->q_tx[i]);
|
||||
+ }
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -2330,13 +2335,14 @@ static void airoha_metadata_dst_free(str
|
||||
}
|
||||
}
|
||||
|
||||
-static int airoha_alloc_gdm_port(struct airoha_eth *eth, struct device_node *np)
|
||||
+static int airoha_alloc_gdm_port(struct airoha_eth *eth,
|
||||
+ struct device_node *np, int index)
|
||||
{
|
||||
const __be32 *id_ptr = of_get_property(np, "reg", NULL);
|
||||
struct airoha_gdm_port *port;
|
||||
struct airoha_qdma *qdma;
|
||||
struct net_device *dev;
|
||||
- int err, index;
|
||||
+ int err, p;
|
||||
u32 id;
|
||||
|
||||
if (!id_ptr) {
|
||||
@@ -2345,14 +2351,14 @@ static int airoha_alloc_gdm_port(struct
|
||||
}
|
||||
|
||||
id = be32_to_cpup(id_ptr);
|
||||
- index = id - 1;
|
||||
+ p = id - 1;
|
||||
|
||||
if (!id || id > ARRAY_SIZE(eth->ports)) {
|
||||
dev_err(eth->dev, "invalid gdm port id: %d\n", id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
- if (eth->ports[index]) {
|
||||
+ if (eth->ports[p]) {
|
||||
dev_err(eth->dev, "duplicate gdm port id: %d\n", id);
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -2400,7 +2406,7 @@ static int airoha_alloc_gdm_port(struct
|
||||
port->qdma = qdma;
|
||||
port->dev = dev;
|
||||
port->id = id;
|
||||
- eth->ports[index] = port;
|
||||
+ eth->ports[p] = port;
|
||||
|
||||
err = airoha_metadata_dst_alloc(port);
|
||||
if (err)
|
||||
@@ -2472,6 +2478,7 @@ static int airoha_probe(struct platform_
|
||||
for (i = 0; i < ARRAY_SIZE(eth->qdma); i++)
|
||||
airoha_qdma_start_napi(ð->qdma[i]);
|
||||
|
||||
+ i = 0;
|
||||
for_each_child_of_node(pdev->dev.of_node, np) {
|
||||
if (!of_device_is_compatible(np, "airoha,eth-mac"))
|
||||
continue;
|
||||
@@ -2479,7 +2486,7 @@ static int airoha_probe(struct platform_
|
||||
if (!of_device_is_available(np))
|
||||
continue;
|
||||
|
||||
- err = airoha_alloc_gdm_port(eth, np);
|
||||
+ err = airoha_alloc_gdm_port(eth, np, i++);
|
||||
if (err) {
|
||||
of_node_put(np);
|
||||
goto error_napi_stop;
|
||||
--- a/drivers/net/ethernet/airoha/airoha_eth.h
|
||||
+++ b/drivers/net/ethernet/airoha/airoha_eth.h
|
||||
@@ -13,7 +13,7 @@
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/reset.h>
|
||||
|
||||
-#define AIROHA_MAX_NUM_GDM_PORTS 1
|
||||
+#define AIROHA_MAX_NUM_GDM_PORTS 4
|
||||
#define AIROHA_MAX_NUM_QDMA 2
|
||||
#define AIROHA_MAX_DSA_PORTS 7
|
||||
#define AIROHA_MAX_NUM_RSTS 3
|
||||
@@ -212,6 +212,8 @@ struct airoha_qdma {
|
||||
u32 irqmask[QDMA_INT_REG_MAX];
|
||||
int irq;
|
||||
|
||||
+ atomic_t users;
|
||||
+
|
||||
struct airoha_tx_irq_queue q_tx_irq[AIROHA_NUM_TX_IRQ];
|
||||
|
||||
struct airoha_queue q_tx[AIROHA_NUM_TX_RING];
|
|
@ -0,0 +1,77 @@
|
|||
From 67fde5d58cd43d129a979e918ec9cd5d2e2fbcfb Mon Sep 17 00:00:00 2001
|
||||
From: Lorenzo Bianconi <lorenzo@kernel.org>
|
||||
Date: Fri, 28 Feb 2025 11:54:16 +0100
|
||||
Subject: [PATCH 08/15] net: airoha: Move REG_GDM_FWD_CFG() initialization in
|
||||
airoha_dev_init()
|
||||
|
||||
Move REG_GDM_FWD_CFG() register initialization in airoha_dev_init
|
||||
routine. Moreover, always send traffic PPE module in order to be
|
||||
processed by hw accelerator.
|
||||
This is a preliminary patch to enable netfilter flowtable hw offloading
|
||||
on EN7581 SoC.
|
||||
|
||||
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
|
||||
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||
---
|
||||
drivers/net/ethernet/airoha/airoha_eth.c | 14 ++++----------
|
||||
1 file changed, 4 insertions(+), 10 deletions(-)
|
||||
|
||||
--- a/drivers/net/ethernet/airoha/airoha_eth.c
|
||||
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
|
||||
@@ -107,25 +107,20 @@ static void airoha_set_gdm_port_fwd_cfg(
|
||||
|
||||
static int airoha_set_gdm_port(struct airoha_eth *eth, int port, bool enable)
|
||||
{
|
||||
- u32 val = enable ? FE_PSE_PORT_PPE1 : FE_PSE_PORT_DROP;
|
||||
- u32 vip_port, cfg_addr;
|
||||
+ u32 vip_port;
|
||||
|
||||
switch (port) {
|
||||
case XSI_PCIE0_PORT:
|
||||
vip_port = XSI_PCIE0_VIP_PORT_MASK;
|
||||
- cfg_addr = REG_GDM_FWD_CFG(3);
|
||||
break;
|
||||
case XSI_PCIE1_PORT:
|
||||
vip_port = XSI_PCIE1_VIP_PORT_MASK;
|
||||
- cfg_addr = REG_GDM_FWD_CFG(3);
|
||||
break;
|
||||
case XSI_USB_PORT:
|
||||
vip_port = XSI_USB_VIP_PORT_MASK;
|
||||
- cfg_addr = REG_GDM_FWD_CFG(4);
|
||||
break;
|
||||
case XSI_ETH_PORT:
|
||||
vip_port = XSI_ETH_VIP_PORT_MASK;
|
||||
- cfg_addr = REG_GDM_FWD_CFG(4);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
@@ -139,8 +134,6 @@ static int airoha_set_gdm_port(struct ai
|
||||
airoha_fe_clear(eth, REG_FE_IFC_PORT_EN, vip_port);
|
||||
}
|
||||
|
||||
- airoha_set_gdm_port_fwd_cfg(eth, cfg_addr, val);
|
||||
-
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -177,8 +170,6 @@ static void airoha_fe_maccr_init(struct
|
||||
airoha_fe_set(eth, REG_GDM_FWD_CFG(p),
|
||||
GDM_TCP_CKSUM | GDM_UDP_CKSUM | GDM_IP4_CKSUM |
|
||||
GDM_DROP_CRC_ERR);
|
||||
- airoha_set_gdm_port_fwd_cfg(eth, REG_GDM_FWD_CFG(p),
|
||||
- FE_PSE_PORT_CDM1);
|
||||
airoha_fe_rmw(eth, REG_GDM_LEN_CFG(p),
|
||||
GDM_SHORT_LEN_MASK | GDM_LONG_LEN_MASK,
|
||||
FIELD_PREP(GDM_SHORT_LEN_MASK, 60) |
|
||||
@@ -1615,8 +1606,11 @@ static int airoha_dev_set_macaddr(struct
|
||||
static int airoha_dev_init(struct net_device *dev)
|
||||
{
|
||||
struct airoha_gdm_port *port = netdev_priv(dev);
|
||||
+ struct airoha_eth *eth = port->qdma->eth;
|
||||
|
||||
airoha_set_macaddr(port, dev->dev_addr);
|
||||
+ airoha_set_gdm_port_fwd_cfg(eth, REG_GDM_FWD_CFG(port->id),
|
||||
+ FE_PSE_PORT_PPE1);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,120 @@
|
|||
From c28b8375f6d02ef3b5e8c51234cc3f6d47d9fb7f Mon Sep 17 00:00:00 2001
|
||||
From: Lorenzo Bianconi <lorenzo@kernel.org>
|
||||
Date: Fri, 28 Feb 2025 11:54:17 +0100
|
||||
Subject: [PATCH 09/15] net: airoha: Rename airoha_set_gdm_port_fwd_cfg() in
|
||||
airoha_set_vip_for_gdm_port()
|
||||
|
||||
Rename airoha_set_gdm_port() in airoha_set_vip_for_gdm_port().
|
||||
Get rid of airoha_set_gdm_ports routine.
|
||||
|
||||
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
|
||||
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||
---
|
||||
drivers/net/ethernet/airoha/airoha_eth.c | 49 ++++++------------------
|
||||
drivers/net/ethernet/airoha/airoha_eth.h | 8 ----
|
||||
2 files changed, 11 insertions(+), 46 deletions(-)
|
||||
|
||||
--- a/drivers/net/ethernet/airoha/airoha_eth.c
|
||||
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
|
||||
@@ -105,25 +105,23 @@ static void airoha_set_gdm_port_fwd_cfg(
|
||||
FIELD_PREP(GDM_UCFQ_MASK, val));
|
||||
}
|
||||
|
||||
-static int airoha_set_gdm_port(struct airoha_eth *eth, int port, bool enable)
|
||||
+static int airoha_set_vip_for_gdm_port(struct airoha_gdm_port *port,
|
||||
+ bool enable)
|
||||
{
|
||||
+ struct airoha_eth *eth = port->qdma->eth;
|
||||
u32 vip_port;
|
||||
|
||||
- switch (port) {
|
||||
- case XSI_PCIE0_PORT:
|
||||
+ switch (port->id) {
|
||||
+ case 3:
|
||||
+ /* FIXME: handle XSI_PCIE1_PORT */
|
||||
vip_port = XSI_PCIE0_VIP_PORT_MASK;
|
||||
break;
|
||||
- case XSI_PCIE1_PORT:
|
||||
- vip_port = XSI_PCIE1_VIP_PORT_MASK;
|
||||
- break;
|
||||
- case XSI_USB_PORT:
|
||||
- vip_port = XSI_USB_VIP_PORT_MASK;
|
||||
- break;
|
||||
- case XSI_ETH_PORT:
|
||||
+ case 4:
|
||||
+ /* FIXME: handle XSI_USB_PORT */
|
||||
vip_port = XSI_ETH_VIP_PORT_MASK;
|
||||
break;
|
||||
default:
|
||||
- return -EINVAL;
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
if (enable) {
|
||||
@@ -137,31 +135,6 @@ static int airoha_set_gdm_port(struct ai
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static int airoha_set_gdm_ports(struct airoha_eth *eth, bool enable)
|
||||
-{
|
||||
- const int port_list[] = {
|
||||
- XSI_PCIE0_PORT,
|
||||
- XSI_PCIE1_PORT,
|
||||
- XSI_USB_PORT,
|
||||
- XSI_ETH_PORT
|
||||
- };
|
||||
- int i, err;
|
||||
-
|
||||
- for (i = 0; i < ARRAY_SIZE(port_list); i++) {
|
||||
- err = airoha_set_gdm_port(eth, port_list[i], enable);
|
||||
- if (err)
|
||||
- goto error;
|
||||
- }
|
||||
-
|
||||
- return 0;
|
||||
-
|
||||
-error:
|
||||
- for (i--; i >= 0; i--)
|
||||
- airoha_set_gdm_port(eth, port_list[i], false);
|
||||
-
|
||||
- return err;
|
||||
-}
|
||||
-
|
||||
static void airoha_fe_maccr_init(struct airoha_eth *eth)
|
||||
{
|
||||
int p;
|
||||
@@ -1540,7 +1513,7 @@ static int airoha_dev_open(struct net_de
|
||||
int err;
|
||||
|
||||
netif_tx_start_all_queues(dev);
|
||||
- err = airoha_set_gdm_ports(qdma->eth, true);
|
||||
+ err = airoha_set_vip_for_gdm_port(port, true);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@@ -1566,7 +1539,7 @@ static int airoha_dev_stop(struct net_de
|
||||
int i, err;
|
||||
|
||||
netif_tx_disable(dev);
|
||||
- err = airoha_set_gdm_ports(qdma->eth, false);
|
||||
+ err = airoha_set_vip_for_gdm_port(port, false);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
--- a/drivers/net/ethernet/airoha/airoha_eth.h
|
||||
+++ b/drivers/net/ethernet/airoha/airoha_eth.h
|
||||
@@ -58,14 +58,6 @@ enum {
|
||||
};
|
||||
|
||||
enum {
|
||||
- XSI_PCIE0_PORT,
|
||||
- XSI_PCIE1_PORT,
|
||||
- XSI_USB_PORT,
|
||||
- XSI_AE_PORT,
|
||||
- XSI_ETH_PORT,
|
||||
-};
|
||||
-
|
||||
-enum {
|
||||
XSI_PCIE0_VIP_PORT_MASK = BIT(22),
|
||||
XSI_PCIE1_VIP_PORT_MASK = BIT(23),
|
||||
XSI_USB_VIP_PORT_MASK = BIT(25),
|
|
@ -0,0 +1,627 @@
|
|||
From 23290c7bc190def4e1ca61610992d9b7c32e33f3 Mon Sep 17 00:00:00 2001
|
||||
From: Lorenzo Bianconi <lorenzo@kernel.org>
|
||||
Date: Fri, 28 Feb 2025 11:54:20 +0100
|
||||
Subject: [PATCH 12/15] net: airoha: Introduce Airoha NPU support
|
||||
|
||||
Packet Processor Engine (PPE) module available on EN7581 SoC populates
|
||||
the PPE table with 5-tuples flower rules learned from traffic forwarded
|
||||
between the GDM ports connected to the Packet Switch Engine (PSE) module.
|
||||
The airoha_eth driver can enable hw acceleration of learned 5-tuples
|
||||
rules if the user configure them in netfilter flowtable (netfilter
|
||||
flowtable support will be added with subsequent patches).
|
||||
airoha_eth driver configures and collects data from the PPE module via a
|
||||
Network Processor Unit (NPU) RISC-V module available on the EN7581 SoC.
|
||||
Introduce basic support for Airoha NPU module.
|
||||
|
||||
Tested-by: Sayantan Nandy <sayantan.nandy@airoha.com>
|
||||
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
|
||||
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||
---
|
||||
drivers/net/ethernet/airoha/Kconfig | 9 +
|
||||
drivers/net/ethernet/airoha/Makefile | 1 +
|
||||
drivers/net/ethernet/airoha/airoha_eth.h | 2 +
|
||||
drivers/net/ethernet/airoha/airoha_npu.c | 520 +++++++++++++++++++++++
|
||||
drivers/net/ethernet/airoha/airoha_npu.h | 34 ++
|
||||
5 files changed, 566 insertions(+)
|
||||
create mode 100644 drivers/net/ethernet/airoha/airoha_npu.c
|
||||
create mode 100644 drivers/net/ethernet/airoha/airoha_npu.h
|
||||
|
||||
--- a/drivers/net/ethernet/airoha/Kconfig
|
||||
+++ b/drivers/net/ethernet/airoha/Kconfig
|
||||
@@ -7,9 +7,18 @@ config NET_VENDOR_AIROHA
|
||||
|
||||
if NET_VENDOR_AIROHA
|
||||
|
||||
+config NET_AIROHA_NPU
|
||||
+ tristate "Airoha NPU support"
|
||||
+ select WANT_DEV_COREDUMP
|
||||
+ select REGMAP_MMIO
|
||||
+ help
|
||||
+ This driver supports Airoha Network Processor (NPU) available
|
||||
+ on the Airoha Soc family.
|
||||
+
|
||||
config NET_AIROHA
|
||||
tristate "Airoha SoC Gigabit Ethernet support"
|
||||
depends on NET_DSA || !NET_DSA
|
||||
+ select NET_AIROHA_NPU
|
||||
select PAGE_POOL
|
||||
help
|
||||
This driver supports the gigabit ethernet MACs in the
|
||||
--- a/drivers/net/ethernet/airoha/Makefile
|
||||
+++ b/drivers/net/ethernet/airoha/Makefile
|
||||
@@ -4,3 +4,4 @@
|
||||
#
|
||||
|
||||
obj-$(CONFIG_NET_AIROHA) += airoha_eth.o
|
||||
+obj-$(CONFIG_NET_AIROHA_NPU) += airoha_npu.o
|
||||
--- a/drivers/net/ethernet/airoha/airoha_eth.h
|
||||
+++ b/drivers/net/ethernet/airoha/airoha_eth.h
|
||||
@@ -240,6 +240,8 @@ struct airoha_eth {
|
||||
unsigned long state;
|
||||
void __iomem *fe_regs;
|
||||
|
||||
+ struct airoha_npu __rcu *npu;
|
||||
+
|
||||
struct reset_control_bulk_data rsts[AIROHA_MAX_NUM_RSTS];
|
||||
struct reset_control_bulk_data xsi_rsts[AIROHA_MAX_NUM_XSI_RSTS];
|
||||
|
||||
--- /dev/null
|
||||
+++ b/drivers/net/ethernet/airoha/airoha_npu.c
|
||||
@@ -0,0 +1,520 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0-only
|
||||
+/*
|
||||
+ * Copyright (c) 2025 AIROHA Inc
|
||||
+ * Author: Lorenzo Bianconi <lorenzo@kernel.org>
|
||||
+ */
|
||||
+
|
||||
+#include <linux/devcoredump.h>
|
||||
+#include <linux/firmware.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/of_net.h>
|
||||
+#include <linux/of_platform.h>
|
||||
+#include <linux/of_reserved_mem.h>
|
||||
+#include <linux/regmap.h>
|
||||
+
|
||||
+#include "airoha_npu.h"
|
||||
+
|
||||
+#define NPU_EN7581_FIRMWARE_DATA "airoha/en7581_npu_data.bin"
|
||||
+#define NPU_EN7581_FIRMWARE_RV32 "airoha/en7581_npu_rv32.bin"
|
||||
+#define NPU_EN7581_FIRMWARE_RV32_MAX_SIZE 0x200000
|
||||
+#define NPU_EN7581_FIRMWARE_DATA_MAX_SIZE 0x10000
|
||||
+#define NPU_DUMP_SIZE 512
|
||||
+
|
||||
+#define REG_NPU_LOCAL_SRAM 0x0
|
||||
+
|
||||
+#define NPU_PC_BASE_ADDR 0x305000
|
||||
+#define REG_PC_DBG(_n) (0x305000 + ((_n) * 0x100))
|
||||
+
|
||||
+#define NPU_CLUSTER_BASE_ADDR 0x306000
|
||||
+
|
||||
+#define REG_CR_BOOT_TRIGGER (NPU_CLUSTER_BASE_ADDR + 0x000)
|
||||
+#define REG_CR_BOOT_CONFIG (NPU_CLUSTER_BASE_ADDR + 0x004)
|
||||
+#define REG_CR_BOOT_BASE(_n) (NPU_CLUSTER_BASE_ADDR + 0x020 + ((_n) << 2))
|
||||
+
|
||||
+#define NPU_MBOX_BASE_ADDR 0x30c000
|
||||
+
|
||||
+#define REG_CR_MBOX_INT_STATUS (NPU_MBOX_BASE_ADDR + 0x000)
|
||||
+#define MBOX_INT_STATUS_MASK BIT(8)
|
||||
+
|
||||
+#define REG_CR_MBOX_INT_MASK(_n) (NPU_MBOX_BASE_ADDR + 0x004 + ((_n) << 2))
|
||||
+#define REG_CR_MBQ0_CTRL(_n) (NPU_MBOX_BASE_ADDR + 0x030 + ((_n) << 2))
|
||||
+#define REG_CR_MBQ8_CTRL(_n) (NPU_MBOX_BASE_ADDR + 0x0b0 + ((_n) << 2))
|
||||
+#define REG_CR_NPU_MIB(_n) (NPU_MBOX_BASE_ADDR + 0x140 + ((_n) << 2))
|
||||
+
|
||||
+#define NPU_TIMER_BASE_ADDR 0x310100
|
||||
+#define REG_WDT_TIMER_CTRL(_n) (NPU_TIMER_BASE_ADDR + ((_n) * 0x100))
|
||||
+#define WDT_EN_MASK BIT(25)
|
||||
+#define WDT_INTR_MASK BIT(21)
|
||||
+
|
||||
+enum {
|
||||
+ NPU_OP_SET = 1,
|
||||
+ NPU_OP_SET_NO_WAIT,
|
||||
+ NPU_OP_GET,
|
||||
+ NPU_OP_GET_NO_WAIT,
|
||||
+};
|
||||
+
|
||||
+enum {
|
||||
+ NPU_FUNC_WIFI,
|
||||
+ NPU_FUNC_TUNNEL,
|
||||
+ NPU_FUNC_NOTIFY,
|
||||
+ NPU_FUNC_DBA,
|
||||
+ NPU_FUNC_TR471,
|
||||
+ NPU_FUNC_PPE,
|
||||
+};
|
||||
+
|
||||
+enum {
|
||||
+ NPU_MBOX_ERROR,
|
||||
+ NPU_MBOX_SUCCESS,
|
||||
+};
|
||||
+
|
||||
+enum {
|
||||
+ PPE_FUNC_SET_WAIT,
|
||||
+ PPE_FUNC_SET_WAIT_HWNAT_INIT,
|
||||
+ PPE_FUNC_SET_WAIT_HWNAT_DEINIT,
|
||||
+ PPE_FUNC_SET_WAIT_API,
|
||||
+};
|
||||
+
|
||||
+enum {
|
||||
+ PPE2_SRAM_SET_ENTRY,
|
||||
+ PPE_SRAM_SET_ENTRY,
|
||||
+ PPE_SRAM_SET_VAL,
|
||||
+ PPE_SRAM_RESET_VAL,
|
||||
+};
|
||||
+
|
||||
+enum {
|
||||
+ QDMA_WAN_ETHER = 1,
|
||||
+ QDMA_WAN_PON_XDSL,
|
||||
+};
|
||||
+
|
||||
+#define MBOX_MSG_FUNC_ID GENMASK(14, 11)
|
||||
+#define MBOX_MSG_STATIC_BUF BIT(5)
|
||||
+#define MBOX_MSG_STATUS GENMASK(4, 2)
|
||||
+#define MBOX_MSG_DONE BIT(1)
|
||||
+#define MBOX_MSG_WAIT_RSP BIT(0)
|
||||
+
|
||||
+#define PPE_TYPE_L2B_IPV4 2
|
||||
+#define PPE_TYPE_L2B_IPV4_IPV6 3
|
||||
+
|
||||
+struct ppe_mbox_data {
|
||||
+ u32 func_type;
|
||||
+ u32 func_id;
|
||||
+ union {
|
||||
+ struct {
|
||||
+ u8 cds;
|
||||
+ u8 xpon_hal_api;
|
||||
+ u8 wan_xsi;
|
||||
+ u8 ct_joyme4;
|
||||
+ int ppe_type;
|
||||
+ int wan_mode;
|
||||
+ int wan_sel;
|
||||
+ } init_info;
|
||||
+ struct {
|
||||
+ int func_id;
|
||||
+ u32 size;
|
||||
+ u32 data;
|
||||
+ } set_info;
|
||||
+ };
|
||||
+};
|
||||
+
|
||||
+static int airoha_npu_send_msg(struct airoha_npu *npu, int func_id,
|
||||
+ void *p, int size)
|
||||
+{
|
||||
+ u16 core = 0; /* FIXME */
|
||||
+ u32 val, offset = core << 4;
|
||||
+ dma_addr_t dma_addr;
|
||||
+ void *addr;
|
||||
+ int ret;
|
||||
+
|
||||
+ addr = kmemdup(p, size, GFP_ATOMIC);
|
||||
+ if (!addr)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ dma_addr = dma_map_single(npu->dev, addr, size, DMA_TO_DEVICE);
|
||||
+ ret = dma_mapping_error(npu->dev, dma_addr);
|
||||
+ if (ret)
|
||||
+ goto out;
|
||||
+
|
||||
+ spin_lock_bh(&npu->cores[core].lock);
|
||||
+
|
||||
+ regmap_write(npu->regmap, REG_CR_MBQ0_CTRL(0) + offset, dma_addr);
|
||||
+ regmap_write(npu->regmap, REG_CR_MBQ0_CTRL(1) + offset, size);
|
||||
+ regmap_read(npu->regmap, REG_CR_MBQ0_CTRL(2) + offset, &val);
|
||||
+ regmap_write(npu->regmap, REG_CR_MBQ0_CTRL(2) + offset, val + 1);
|
||||
+ val = FIELD_PREP(MBOX_MSG_FUNC_ID, func_id) | MBOX_MSG_WAIT_RSP;
|
||||
+ regmap_write(npu->regmap, REG_CR_MBQ0_CTRL(3) + offset, val);
|
||||
+
|
||||
+ ret = regmap_read_poll_timeout_atomic(npu->regmap,
|
||||
+ REG_CR_MBQ0_CTRL(3) + offset,
|
||||
+ val, (val & MBOX_MSG_DONE),
|
||||
+ 100, 100 * MSEC_PER_SEC);
|
||||
+ if (!ret && FIELD_GET(MBOX_MSG_STATUS, val) != NPU_MBOX_SUCCESS)
|
||||
+ ret = -EINVAL;
|
||||
+
|
||||
+ spin_unlock_bh(&npu->cores[core].lock);
|
||||
+
|
||||
+ dma_unmap_single(npu->dev, dma_addr, size, DMA_TO_DEVICE);
|
||||
+out:
|
||||
+ kfree(addr);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int airoha_npu_run_firmware(struct device *dev, void __iomem *base,
|
||||
+ struct reserved_mem *rmem)
|
||||
+{
|
||||
+ const struct firmware *fw;
|
||||
+ void __iomem *addr;
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = request_firmware(&fw, NPU_EN7581_FIRMWARE_RV32, dev);
|
||||
+ if (ret)
|
||||
+ return ret == -ENOENT ? -EPROBE_DEFER : ret;
|
||||
+
|
||||
+ if (fw->size > NPU_EN7581_FIRMWARE_RV32_MAX_SIZE) {
|
||||
+ dev_err(dev, "%s: fw size too overlimit (%zu)\n",
|
||||
+ NPU_EN7581_FIRMWARE_RV32, fw->size);
|
||||
+ ret = -E2BIG;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ addr = devm_ioremap(dev, rmem->base, rmem->size);
|
||||
+ if (!addr) {
|
||||
+ ret = -ENOMEM;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ memcpy_toio(addr, fw->data, fw->size);
|
||||
+ release_firmware(fw);
|
||||
+
|
||||
+ ret = request_firmware(&fw, NPU_EN7581_FIRMWARE_DATA, dev);
|
||||
+ if (ret)
|
||||
+ return ret == -ENOENT ? -EPROBE_DEFER : ret;
|
||||
+
|
||||
+ if (fw->size > NPU_EN7581_FIRMWARE_DATA_MAX_SIZE) {
|
||||
+ dev_err(dev, "%s: fw size too overlimit (%zu)\n",
|
||||
+ NPU_EN7581_FIRMWARE_DATA, fw->size);
|
||||
+ ret = -E2BIG;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ memcpy_toio(base + REG_NPU_LOCAL_SRAM, fw->data, fw->size);
|
||||
+out:
|
||||
+ release_firmware(fw);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static irqreturn_t airoha_npu_mbox_handler(int irq, void *npu_instance)
|
||||
+{
|
||||
+ struct airoha_npu *npu = npu_instance;
|
||||
+
|
||||
+ /* clear mbox interrupt status */
|
||||
+ regmap_write(npu->regmap, REG_CR_MBOX_INT_STATUS,
|
||||
+ MBOX_INT_STATUS_MASK);
|
||||
+
|
||||
+ /* acknowledge npu */
|
||||
+ regmap_update_bits(npu->regmap, REG_CR_MBQ8_CTRL(3),
|
||||
+ MBOX_MSG_STATUS | MBOX_MSG_DONE, MBOX_MSG_DONE);
|
||||
+
|
||||
+ return IRQ_HANDLED;
|
||||
+}
|
||||
+
|
||||
+static void airoha_npu_wdt_work(struct work_struct *work)
|
||||
+{
|
||||
+ struct airoha_npu_core *core;
|
||||
+ struct airoha_npu *npu;
|
||||
+ void *dump;
|
||||
+ u32 val[3];
|
||||
+ int c;
|
||||
+
|
||||
+ core = container_of(work, struct airoha_npu_core, wdt_work);
|
||||
+ npu = core->npu;
|
||||
+
|
||||
+ dump = vzalloc(NPU_DUMP_SIZE);
|
||||
+ if (!dump)
|
||||
+ return;
|
||||
+
|
||||
+ c = core - &npu->cores[0];
|
||||
+ regmap_bulk_read(npu->regmap, REG_PC_DBG(c), val, ARRAY_SIZE(val));
|
||||
+ snprintf(dump, NPU_DUMP_SIZE, "PC: %08x SP: %08x LR: %08x\n",
|
||||
+ val[0], val[1], val[2]);
|
||||
+
|
||||
+ dev_coredumpv(npu->dev, dump, NPU_DUMP_SIZE, GFP_KERNEL);
|
||||
+}
|
||||
+
|
||||
+static irqreturn_t airoha_npu_wdt_handler(int irq, void *core_instance)
|
||||
+{
|
||||
+ struct airoha_npu_core *core = core_instance;
|
||||
+ struct airoha_npu *npu = core->npu;
|
||||
+ int c = core - &npu->cores[0];
|
||||
+ u32 val;
|
||||
+
|
||||
+ regmap_set_bits(npu->regmap, REG_WDT_TIMER_CTRL(c), WDT_INTR_MASK);
|
||||
+ if (!regmap_read(npu->regmap, REG_WDT_TIMER_CTRL(c), &val) &&
|
||||
+ FIELD_GET(WDT_EN_MASK, val))
|
||||
+ schedule_work(&core->wdt_work);
|
||||
+
|
||||
+ return IRQ_HANDLED;
|
||||
+}
|
||||
+
|
||||
+static int airoha_npu_ppe_init(struct airoha_npu *npu)
|
||||
+{
|
||||
+ struct ppe_mbox_data ppe_data = {
|
||||
+ .func_type = NPU_OP_SET,
|
||||
+ .func_id = PPE_FUNC_SET_WAIT_HWNAT_INIT,
|
||||
+ .init_info = {
|
||||
+ .ppe_type = PPE_TYPE_L2B_IPV4_IPV6,
|
||||
+ .wan_mode = QDMA_WAN_ETHER,
|
||||
+ },
|
||||
+ };
|
||||
+
|
||||
+ return airoha_npu_send_msg(npu, NPU_FUNC_PPE, &ppe_data,
|
||||
+ sizeof(struct ppe_mbox_data));
|
||||
+}
|
||||
+
|
||||
+static int airoha_npu_ppe_deinit(struct airoha_npu *npu)
|
||||
+{
|
||||
+ struct ppe_mbox_data ppe_data = {
|
||||
+ .func_type = NPU_OP_SET,
|
||||
+ .func_id = PPE_FUNC_SET_WAIT_HWNAT_DEINIT,
|
||||
+ };
|
||||
+
|
||||
+ return airoha_npu_send_msg(npu, NPU_FUNC_PPE, &ppe_data,
|
||||
+ sizeof(struct ppe_mbox_data));
|
||||
+}
|
||||
+
|
||||
+static int airoha_npu_ppe_flush_sram_entries(struct airoha_npu *npu,
|
||||
+ dma_addr_t foe_addr,
|
||||
+ int sram_num_entries)
|
||||
+{
|
||||
+ struct ppe_mbox_data ppe_data = {
|
||||
+ .func_type = NPU_OP_SET,
|
||||
+ .func_id = PPE_FUNC_SET_WAIT_API,
|
||||
+ .set_info = {
|
||||
+ .func_id = PPE_SRAM_RESET_VAL,
|
||||
+ .data = foe_addr,
|
||||
+ .size = sram_num_entries,
|
||||
+ },
|
||||
+ };
|
||||
+
|
||||
+ return airoha_npu_send_msg(npu, NPU_FUNC_PPE, &ppe_data,
|
||||
+ sizeof(struct ppe_mbox_data));
|
||||
+}
|
||||
+
|
||||
+static int airoha_npu_foe_commit_entry(struct airoha_npu *npu,
|
||||
+ dma_addr_t foe_addr,
|
||||
+ u32 entry_size, u32 hash, bool ppe2)
|
||||
+{
|
||||
+ struct ppe_mbox_data ppe_data = {
|
||||
+ .func_type = NPU_OP_SET,
|
||||
+ .func_id = PPE_FUNC_SET_WAIT_API,
|
||||
+ .set_info = {
|
||||
+ .data = foe_addr,
|
||||
+ .size = entry_size,
|
||||
+ },
|
||||
+ };
|
||||
+ int err;
|
||||
+
|
||||
+ ppe_data.set_info.func_id = ppe2 ? PPE2_SRAM_SET_ENTRY
|
||||
+ : PPE_SRAM_SET_ENTRY;
|
||||
+
|
||||
+ err = airoha_npu_send_msg(npu, NPU_FUNC_PPE, &ppe_data,
|
||||
+ sizeof(struct ppe_mbox_data));
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+
|
||||
+ ppe_data.set_info.func_id = PPE_SRAM_SET_VAL;
|
||||
+ ppe_data.set_info.data = hash;
|
||||
+ ppe_data.set_info.size = sizeof(u32);
|
||||
+
|
||||
+ return airoha_npu_send_msg(npu, NPU_FUNC_PPE, &ppe_data,
|
||||
+ sizeof(struct ppe_mbox_data));
|
||||
+}
|
||||
+
|
||||
+struct airoha_npu *airoha_npu_get(struct device *dev)
|
||||
+{
|
||||
+ struct platform_device *pdev;
|
||||
+ struct device_node *np;
|
||||
+ struct airoha_npu *npu;
|
||||
+
|
||||
+ np = of_parse_phandle(dev->of_node, "airoha,npu", 0);
|
||||
+ if (!np)
|
||||
+ return ERR_PTR(-ENODEV);
|
||||
+
|
||||
+ pdev = of_find_device_by_node(np);
|
||||
+ of_node_put(np);
|
||||
+
|
||||
+ if (!pdev) {
|
||||
+ dev_err(dev, "cannot find device node %s\n", np->name);
|
||||
+ return ERR_PTR(-ENODEV);
|
||||
+ }
|
||||
+
|
||||
+ if (!try_module_get(THIS_MODULE)) {
|
||||
+ dev_err(dev, "failed to get the device driver module\n");
|
||||
+ npu = ERR_PTR(-ENODEV);
|
||||
+ goto error_pdev_put;
|
||||
+ }
|
||||
+
|
||||
+ npu = platform_get_drvdata(pdev);
|
||||
+ if (!npu) {
|
||||
+ npu = ERR_PTR(-ENODEV);
|
||||
+ goto error_module_put;
|
||||
+ }
|
||||
+
|
||||
+ if (!device_link_add(dev, &pdev->dev, DL_FLAG_AUTOREMOVE_SUPPLIER)) {
|
||||
+ dev_err(&pdev->dev,
|
||||
+ "failed to create device link to consumer %s\n",
|
||||
+ dev_name(dev));
|
||||
+ npu = ERR_PTR(-EINVAL);
|
||||
+ goto error_module_put;
|
||||
+ }
|
||||
+
|
||||
+ return npu;
|
||||
+
|
||||
+error_module_put:
|
||||
+ module_put(THIS_MODULE);
|
||||
+error_pdev_put:
|
||||
+ platform_device_put(pdev);
|
||||
+
|
||||
+ return npu;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(airoha_npu_get);
|
||||
+
|
||||
+void airoha_npu_put(struct airoha_npu *npu)
|
||||
+{
|
||||
+ module_put(THIS_MODULE);
|
||||
+ put_device(npu->dev);
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(airoha_npu_put);
|
||||
+
|
||||
+static const struct of_device_id of_airoha_npu_match[] = {
|
||||
+ { .compatible = "airoha,en7581-npu" },
|
||||
+ { /* sentinel */ }
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, of_airoha_npu_match);
|
||||
+
|
||||
+static const struct regmap_config regmap_config = {
|
||||
+ .name = "npu",
|
||||
+ .reg_bits = 32,
|
||||
+ .val_bits = 32,
|
||||
+ .reg_stride = 4,
|
||||
+ .disable_locking = true,
|
||||
+};
|
||||
+
|
||||
+static int airoha_npu_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct device *dev = &pdev->dev;
|
||||
+ struct reserved_mem *rmem;
|
||||
+ struct airoha_npu *npu;
|
||||
+ struct device_node *np;
|
||||
+ void __iomem *base;
|
||||
+ int i, irq, err;
|
||||
+
|
||||
+ base = devm_platform_ioremap_resource(pdev, 0);
|
||||
+ if (IS_ERR(base))
|
||||
+ return PTR_ERR(base);
|
||||
+
|
||||
+ npu = devm_kzalloc(dev, sizeof(*npu), GFP_KERNEL);
|
||||
+ if (!npu)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ npu->dev = dev;
|
||||
+ npu->ops.ppe_init = airoha_npu_ppe_init;
|
||||
+ npu->ops.ppe_deinit = airoha_npu_ppe_deinit;
|
||||
+ npu->ops.ppe_flush_sram_entries = airoha_npu_ppe_flush_sram_entries;
|
||||
+ npu->ops.ppe_foe_commit_entry = airoha_npu_foe_commit_entry;
|
||||
+
|
||||
+ npu->regmap = devm_regmap_init_mmio(dev, base, ®map_config);
|
||||
+ if (IS_ERR(npu->regmap))
|
||||
+ return PTR_ERR(npu->regmap);
|
||||
+
|
||||
+ np = of_parse_phandle(dev->of_node, "memory-region", 0);
|
||||
+ if (!np)
|
||||
+ return -ENODEV;
|
||||
+
|
||||
+ rmem = of_reserved_mem_lookup(np);
|
||||
+ of_node_put(np);
|
||||
+
|
||||
+ if (!rmem)
|
||||
+ return -ENODEV;
|
||||
+
|
||||
+ irq = platform_get_irq(pdev, 0);
|
||||
+ if (irq < 0)
|
||||
+ return irq;
|
||||
+
|
||||
+ err = devm_request_irq(dev, irq, airoha_npu_mbox_handler,
|
||||
+ IRQF_SHARED, "airoha-npu-mbox", npu);
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+
|
||||
+ for (i = 0; i < ARRAY_SIZE(npu->cores); i++) {
|
||||
+ struct airoha_npu_core *core = &npu->cores[i];
|
||||
+
|
||||
+ spin_lock_init(&core->lock);
|
||||
+ core->npu = npu;
|
||||
+
|
||||
+ irq = platform_get_irq(pdev, i + 1);
|
||||
+ if (irq < 0)
|
||||
+ return irq;
|
||||
+
|
||||
+ err = devm_request_irq(dev, irq, airoha_npu_wdt_handler,
|
||||
+ IRQF_SHARED, "airoha-npu-wdt", core);
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+
|
||||
+ INIT_WORK(&core->wdt_work, airoha_npu_wdt_work);
|
||||
+ }
|
||||
+
|
||||
+ err = dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+
|
||||
+ err = airoha_npu_run_firmware(dev, base, rmem);
|
||||
+ if (err)
|
||||
+ return dev_err_probe(dev, err, "failed to run npu firmware\n");
|
||||
+
|
||||
+ regmap_write(npu->regmap, REG_CR_NPU_MIB(10),
|
||||
+ rmem->base + NPU_EN7581_FIRMWARE_RV32_MAX_SIZE);
|
||||
+ regmap_write(npu->regmap, REG_CR_NPU_MIB(11), 0x40000); /* SRAM 256K */
|
||||
+ regmap_write(npu->regmap, REG_CR_NPU_MIB(12), 0);
|
||||
+ regmap_write(npu->regmap, REG_CR_NPU_MIB(21), 1);
|
||||
+ msleep(100);
|
||||
+
|
||||
+ /* setting booting address */
|
||||
+ for (i = 0; i < NPU_NUM_CORES; i++)
|
||||
+ regmap_write(npu->regmap, REG_CR_BOOT_BASE(i), rmem->base);
|
||||
+ usleep_range(1000, 2000);
|
||||
+
|
||||
+ /* enable NPU cores */
|
||||
+ /* do not start core3 since it is used for WiFi offloading */
|
||||
+ regmap_write(npu->regmap, REG_CR_BOOT_CONFIG, 0xf7);
|
||||
+ regmap_write(npu->regmap, REG_CR_BOOT_TRIGGER, 0x1);
|
||||
+ msleep(100);
|
||||
+
|
||||
+ platform_set_drvdata(pdev, npu);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void airoha_npu_remove(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct airoha_npu *npu = platform_get_drvdata(pdev);
|
||||
+ int i;
|
||||
+
|
||||
+ for (i = 0; i < ARRAY_SIZE(npu->cores); i++)
|
||||
+ cancel_work_sync(&npu->cores[i].wdt_work);
|
||||
+}
|
||||
+
|
||||
+static struct platform_driver airoha_npu_driver = {
|
||||
+ .probe = airoha_npu_probe,
|
||||
+ .remove_new = airoha_npu_remove,
|
||||
+ .driver = {
|
||||
+ .name = "airoha-npu",
|
||||
+ .of_match_table = of_airoha_npu_match,
|
||||
+ },
|
||||
+};
|
||||
+module_platform_driver(airoha_npu_driver);
|
||||
+
|
||||
+MODULE_LICENSE("GPL");
|
||||
+MODULE_AUTHOR("Lorenzo Bianconi <lorenzo@kernel.org>");
|
||||
+MODULE_DESCRIPTION("Airoha Network Processor Unit driver");
|
||||
--- /dev/null
|
||||
+++ b/drivers/net/ethernet/airoha/airoha_npu.h
|
||||
@@ -0,0 +1,34 @@
|
||||
+/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
+/*
|
||||
+ * Copyright (c) 2025 AIROHA Inc
|
||||
+ * Author: Lorenzo Bianconi <lorenzo@kernel.org>
|
||||
+ */
|
||||
+
|
||||
+#define NPU_NUM_CORES 8
|
||||
+
|
||||
+struct airoha_npu {
|
||||
+ struct device *dev;
|
||||
+ struct regmap *regmap;
|
||||
+
|
||||
+ struct airoha_npu_core {
|
||||
+ struct airoha_npu *npu;
|
||||
+ /* protect concurrent npu memory accesses */
|
||||
+ spinlock_t lock;
|
||||
+ struct work_struct wdt_work;
|
||||
+ } cores[NPU_NUM_CORES];
|
||||
+
|
||||
+ struct {
|
||||
+ int (*ppe_init)(struct airoha_npu *npu);
|
||||
+ int (*ppe_deinit)(struct airoha_npu *npu);
|
||||
+ int (*ppe_flush_sram_entries)(struct airoha_npu *npu,
|
||||
+ dma_addr_t foe_addr,
|
||||
+ int sram_num_entries);
|
||||
+ int (*ppe_foe_commit_entry)(struct airoha_npu *npu,
|
||||
+ dma_addr_t foe_addr,
|
||||
+ u32 entry_size, u32 hash,
|
||||
+ bool ppe2);
|
||||
+ } ops;
|
||||
+};
|
||||
+
|
||||
+struct airoha_npu *airoha_npu_get(struct device *dev);
|
||||
+void airoha_npu_put(struct airoha_npu *npu);
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,210 @@
|
|||
From 9cd451d414f6e29f507a216fb3b19fa68c011f8c Mon Sep 17 00:00:00 2001
|
||||
From: Lorenzo Bianconi <lorenzo@kernel.org>
|
||||
Date: Fri, 28 Feb 2025 11:54:22 +0100
|
||||
Subject: [PATCH 14/15] net: airoha: Add loopback support for GDM2
|
||||
|
||||
Enable hw redirection for traffic received on GDM2 port to GDM{3,4}.
|
||||
This is required to apply Qdisc offloading (HTB or ETS) for traffic to
|
||||
and from GDM{3,4} port.
|
||||
|
||||
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
|
||||
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||
---
|
||||
drivers/net/ethernet/airoha/airoha_eth.c | 71 ++++++++++++++++++++++-
|
||||
drivers/net/ethernet/airoha/airoha_eth.h | 7 +++
|
||||
drivers/net/ethernet/airoha/airoha_ppe.c | 12 ++--
|
||||
drivers/net/ethernet/airoha/airoha_regs.h | 29 +++++++++
|
||||
4 files changed, 111 insertions(+), 8 deletions(-)
|
||||
|
||||
--- a/drivers/net/ethernet/airoha/airoha_eth.c
|
||||
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
|
||||
@@ -1589,14 +1589,81 @@ static int airoha_dev_set_macaddr(struct
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static void airhoha_set_gdm2_loopback(struct airoha_gdm_port *port)
|
||||
+{
|
||||
+ u32 pse_port = port->id == 3 ? FE_PSE_PORT_GDM3 : FE_PSE_PORT_GDM4;
|
||||
+ struct airoha_eth *eth = port->qdma->eth;
|
||||
+ u32 chan = port->id == 3 ? 4 : 0;
|
||||
+
|
||||
+ /* Forward the traffic to the proper GDM port */
|
||||
+ airoha_set_gdm_port_fwd_cfg(eth, REG_GDM_FWD_CFG(2), pse_port);
|
||||
+ airoha_fe_clear(eth, REG_GDM_FWD_CFG(2), GDM_STRIP_CRC);
|
||||
+
|
||||
+ /* Enable GDM2 loopback */
|
||||
+ airoha_fe_wr(eth, REG_GDM_TXCHN_EN(2), 0xffffffff);
|
||||
+ airoha_fe_wr(eth, REG_GDM_RXCHN_EN(2), 0xffff);
|
||||
+ airoha_fe_rmw(eth, REG_GDM_LPBK_CFG(2),
|
||||
+ LPBK_CHAN_MASK | LPBK_MODE_MASK | LPBK_EN_MASK,
|
||||
+ FIELD_PREP(LPBK_CHAN_MASK, chan) | LPBK_EN_MASK);
|
||||
+ airoha_fe_rmw(eth, REG_GDM_LEN_CFG(2),
|
||||
+ GDM_SHORT_LEN_MASK | GDM_LONG_LEN_MASK,
|
||||
+ FIELD_PREP(GDM_SHORT_LEN_MASK, 60) |
|
||||
+ FIELD_PREP(GDM_LONG_LEN_MASK, AIROHA_MAX_MTU));
|
||||
+
|
||||
+ /* Disable VIP and IFC for GDM2 */
|
||||
+ airoha_fe_clear(eth, REG_FE_VIP_PORT_EN, BIT(2));
|
||||
+ airoha_fe_clear(eth, REG_FE_IFC_PORT_EN, BIT(2));
|
||||
+
|
||||
+ if (port->id == 3) {
|
||||
+ /* FIXME: handle XSI_PCE1_PORT */
|
||||
+ airoha_fe_wr(eth, REG_PPE_DFT_CPORT0(0), 0x5500);
|
||||
+ airoha_fe_rmw(eth, REG_FE_WAN_PORT,
|
||||
+ WAN1_EN_MASK | WAN1_MASK | WAN0_MASK,
|
||||
+ FIELD_PREP(WAN0_MASK, HSGMII_LAN_PCIE0_SRCPORT));
|
||||
+ airoha_fe_rmw(eth,
|
||||
+ REG_SP_DFT_CPORT(HSGMII_LAN_PCIE0_SRCPORT >> 3),
|
||||
+ SP_CPORT_PCIE0_MASK,
|
||||
+ FIELD_PREP(SP_CPORT_PCIE0_MASK,
|
||||
+ FE_PSE_PORT_CDM2));
|
||||
+ } else {
|
||||
+ /* FIXME: handle XSI_USB_PORT */
|
||||
+ airoha_fe_rmw(eth, REG_SRC_PORT_FC_MAP6,
|
||||
+ FC_ID_OF_SRC_PORT24_MASK,
|
||||
+ FIELD_PREP(FC_ID_OF_SRC_PORT24_MASK, 2));
|
||||
+ airoha_fe_rmw(eth, REG_FE_WAN_PORT,
|
||||
+ WAN1_EN_MASK | WAN1_MASK | WAN0_MASK,
|
||||
+ FIELD_PREP(WAN0_MASK, HSGMII_LAN_ETH_SRCPORT));
|
||||
+ airoha_fe_rmw(eth,
|
||||
+ REG_SP_DFT_CPORT(HSGMII_LAN_ETH_SRCPORT >> 3),
|
||||
+ SP_CPORT_ETH_MASK,
|
||||
+ FIELD_PREP(SP_CPORT_ETH_MASK, FE_PSE_PORT_CDM2));
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
static int airoha_dev_init(struct net_device *dev)
|
||||
{
|
||||
struct airoha_gdm_port *port = netdev_priv(dev);
|
||||
struct airoha_eth *eth = port->qdma->eth;
|
||||
+ u32 pse_port;
|
||||
|
||||
airoha_set_macaddr(port, dev->dev_addr);
|
||||
- airoha_set_gdm_port_fwd_cfg(eth, REG_GDM_FWD_CFG(port->id),
|
||||
- FE_PSE_PORT_PPE1);
|
||||
+
|
||||
+ switch (port->id) {
|
||||
+ case 3:
|
||||
+ case 4:
|
||||
+ /* If GDM2 is active we can't enable loopback */
|
||||
+ if (!eth->ports[1])
|
||||
+ airhoha_set_gdm2_loopback(port);
|
||||
+ fallthrough;
|
||||
+ case 2:
|
||||
+ pse_port = FE_PSE_PORT_PPE2;
|
||||
+ break;
|
||||
+ default:
|
||||
+ pse_port = FE_PSE_PORT_PPE1;
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ airoha_set_gdm_port_fwd_cfg(eth, REG_GDM_FWD_CFG(port->id), pse_port);
|
||||
|
||||
return 0;
|
||||
}
|
||||
--- a/drivers/net/ethernet/airoha/airoha_eth.h
|
||||
+++ b/drivers/net/ethernet/airoha/airoha_eth.h
|
||||
@@ -68,6 +68,13 @@ enum {
|
||||
};
|
||||
|
||||
enum {
|
||||
+ HSGMII_LAN_PCIE0_SRCPORT = 0x16,
|
||||
+ HSGMII_LAN_PCIE1_SRCPORT,
|
||||
+ HSGMII_LAN_ETH_SRCPORT,
|
||||
+ HSGMII_LAN_USB_SRCPORT,
|
||||
+};
|
||||
+
|
||||
+enum {
|
||||
XSI_PCIE0_VIP_PORT_MASK = BIT(22),
|
||||
XSI_PCIE1_VIP_PORT_MASK = BIT(23),
|
||||
XSI_USB_VIP_PORT_MASK = BIT(25),
|
||||
--- a/drivers/net/ethernet/airoha/airoha_ppe.c
|
||||
+++ b/drivers/net/ethernet/airoha/airoha_ppe.c
|
||||
@@ -216,7 +216,8 @@ static int airoha_ppe_foe_entry_prepare(
|
||||
AIROHA_FOE_IB1_BIND_TTL;
|
||||
hwe->ib1 = val;
|
||||
|
||||
- val = FIELD_PREP(AIROHA_FOE_IB2_PORT_AG, 0x1f);
|
||||
+ val = FIELD_PREP(AIROHA_FOE_IB2_PORT_AG, 0x1f) |
|
||||
+ AIROHA_FOE_IB2_PSE_QOS;
|
||||
if (dsa_port >= 0)
|
||||
val |= FIELD_PREP(AIROHA_FOE_IB2_NBQ, dsa_port);
|
||||
|
||||
@@ -224,14 +225,13 @@ static int airoha_ppe_foe_entry_prepare(
|
||||
struct airoha_gdm_port *port = netdev_priv(dev);
|
||||
u8 pse_port;
|
||||
|
||||
- pse_port = port->id == 4 ? FE_PSE_PORT_GDM4 : port->id;
|
||||
+ if (dsa_port >= 0)
|
||||
+ pse_port = port->id == 4 ? FE_PSE_PORT_GDM4 : port->id;
|
||||
+ else
|
||||
+ pse_port = 2; /* uplink relies on GDM2 loopback */
|
||||
val |= FIELD_PREP(AIROHA_FOE_IB2_PSE_PORT, pse_port);
|
||||
}
|
||||
|
||||
- /* FIXME: implement QoS support setting pse_port to 2 (loopback)
|
||||
- * for uplink and setting qos bit in ib2
|
||||
- */
|
||||
-
|
||||
if (is_multicast_ether_addr(data->eth.h_dest))
|
||||
val |= AIROHA_FOE_IB2_MULTICAST;
|
||||
|
||||
--- a/drivers/net/ethernet/airoha/airoha_regs.h
|
||||
+++ b/drivers/net/ethernet/airoha/airoha_regs.h
|
||||
@@ -38,6 +38,12 @@
|
||||
#define FE_RST_CORE_MASK BIT(0)
|
||||
|
||||
#define REG_FE_FOE_TS 0x0010
|
||||
+
|
||||
+#define REG_FE_WAN_PORT 0x0024
|
||||
+#define WAN1_EN_MASK BIT(16)
|
||||
+#define WAN1_MASK GENMASK(12, 8)
|
||||
+#define WAN0_MASK GENMASK(4, 0)
|
||||
+
|
||||
#define REG_FE_WAN_MAC_H 0x0030
|
||||
#define REG_FE_LAN_MAC_H 0x0040
|
||||
|
||||
@@ -126,6 +132,7 @@
|
||||
#define GDM_IP4_CKSUM BIT(22)
|
||||
#define GDM_TCP_CKSUM BIT(21)
|
||||
#define GDM_UDP_CKSUM BIT(20)
|
||||
+#define GDM_STRIP_CRC BIT(16)
|
||||
#define GDM_UCFQ_MASK GENMASK(15, 12)
|
||||
#define GDM_BCFQ_MASK GENMASK(11, 8)
|
||||
#define GDM_MCFQ_MASK GENMASK(7, 4)
|
||||
@@ -139,6 +146,16 @@
|
||||
#define GDM_SHORT_LEN_MASK GENMASK(13, 0)
|
||||
#define GDM_LONG_LEN_MASK GENMASK(29, 16)
|
||||
|
||||
+#define REG_GDM_LPBK_CFG(_n) (GDM_BASE(_n) + 0x1c)
|
||||
+#define LPBK_GAP_MASK GENMASK(31, 24)
|
||||
+#define LPBK_LEN_MASK GENMASK(23, 10)
|
||||
+#define LPBK_CHAN_MASK GENMASK(8, 4)
|
||||
+#define LPBK_MODE_MASK GENMASK(3, 1)
|
||||
+#define LPBK_EN_MASK BIT(0)
|
||||
+
|
||||
+#define REG_GDM_TXCHN_EN(_n) (GDM_BASE(_n) + 0x24)
|
||||
+#define REG_GDM_RXCHN_EN(_n) (GDM_BASE(_n) + 0x28)
|
||||
+
|
||||
#define REG_FE_CPORT_CFG (GDM1_BASE + 0x40)
|
||||
#define FE_CPORT_PAD BIT(26)
|
||||
#define FE_CPORT_PORT_XFC_MASK BIT(25)
|
||||
@@ -351,6 +368,18 @@
|
||||
|
||||
#define REG_MC_VLAN_DATA 0x2108
|
||||
|
||||
+#define REG_SP_DFT_CPORT(_n) (0x20e0 + ((_n) << 2))
|
||||
+#define SP_CPORT_PCIE1_MASK GENMASK(31, 28)
|
||||
+#define SP_CPORT_PCIE0_MASK GENMASK(27, 24)
|
||||
+#define SP_CPORT_USB_MASK GENMASK(7, 4)
|
||||
+#define SP_CPORT_ETH_MASK GENMASK(7, 4)
|
||||
+
|
||||
+#define REG_SRC_PORT_FC_MAP6 0x2298
|
||||
+#define FC_ID_OF_SRC_PORT27_MASK GENMASK(28, 24)
|
||||
+#define FC_ID_OF_SRC_PORT26_MASK GENMASK(20, 16)
|
||||
+#define FC_ID_OF_SRC_PORT25_MASK GENMASK(12, 8)
|
||||
+#define FC_ID_OF_SRC_PORT24_MASK GENMASK(4, 0)
|
||||
+
|
||||
#define REG_CDM5_RX_OQ1_DROP_CNT 0x29d4
|
||||
|
||||
/* QDMA */
|
|
@ -0,0 +1,291 @@
|
|||
From 3fe15c640f3808c3faf235553c67c867d1389e5c Mon Sep 17 00:00:00 2001
|
||||
From: Lorenzo Bianconi <lorenzo@kernel.org>
|
||||
Date: Fri, 28 Feb 2025 11:54:23 +0100
|
||||
Subject: [PATCH 15/15] net: airoha: Introduce PPE debugfs support
|
||||
|
||||
Similar to PPE support for Mediatek devices, introduce PPE debugfs
|
||||
in order to dump binded and unbinded flows.
|
||||
|
||||
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
|
||||
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
|
||||
---
|
||||
drivers/net/ethernet/airoha/Makefile | 1 +
|
||||
drivers/net/ethernet/airoha/airoha_eth.h | 14 ++
|
||||
drivers/net/ethernet/airoha/airoha_ppe.c | 17 +-
|
||||
.../net/ethernet/airoha/airoha_ppe_debugfs.c | 181 ++++++++++++++++++
|
||||
4 files changed, 209 insertions(+), 4 deletions(-)
|
||||
create mode 100644 drivers/net/ethernet/airoha/airoha_ppe_debugfs.c
|
||||
|
||||
--- a/drivers/net/ethernet/airoha/Makefile
|
||||
+++ b/drivers/net/ethernet/airoha/Makefile
|
||||
@@ -5,4 +5,5 @@
|
||||
|
||||
obj-$(CONFIG_NET_AIROHA) += airoha-eth.o
|
||||
airoha-eth-y := airoha_eth.o airoha_ppe.o
|
||||
+airoha-eth-$(CONFIG_DEBUG_FS) += airoha_ppe_debugfs.o
|
||||
obj-$(CONFIG_NET_AIROHA_NPU) += airoha_npu.o
|
||||
--- a/drivers/net/ethernet/airoha/airoha_eth.h
|
||||
+++ b/drivers/net/ethernet/airoha/airoha_eth.h
|
||||
@@ -7,6 +7,7 @@
|
||||
#ifndef AIROHA_ETH_H
|
||||
#define AIROHA_ETH_H
|
||||
|
||||
+#include <linux/debugfs.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/kernel.h>
|
||||
@@ -480,6 +481,8 @@ struct airoha_ppe {
|
||||
|
||||
struct hlist_head *foe_flow;
|
||||
u16 foe_check_time[PPE_NUM_ENTRIES];
|
||||
+
|
||||
+ struct dentry *debugfs_dir;
|
||||
};
|
||||
|
||||
struct airoha_eth {
|
||||
@@ -533,5 +536,16 @@ int airoha_ppe_setup_tc_block_cb(enum tc
|
||||
void *cb_priv);
|
||||
int airoha_ppe_init(struct airoha_eth *eth);
|
||||
void airoha_ppe_deinit(struct airoha_eth *eth);
|
||||
+struct airoha_foe_entry *airoha_ppe_foe_get_entry(struct airoha_ppe *ppe,
|
||||
+ u32 hash);
|
||||
+
|
||||
+#if CONFIG_DEBUG_FS
|
||||
+int airoha_ppe_debugfs_init(struct airoha_ppe *ppe);
|
||||
+#else
|
||||
+static inline int airoha_ppe_debugfs_init(struct airoha_ppe *ppe)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+#endif
|
||||
|
||||
#endif /* AIROHA_ETH_H */
|
||||
--- a/drivers/net/ethernet/airoha/airoha_ppe.c
|
||||
+++ b/drivers/net/ethernet/airoha/airoha_ppe.c
|
||||
@@ -390,8 +390,8 @@ static u32 airoha_ppe_foe_get_entry_hash
|
||||
return hash;
|
||||
}
|
||||
|
||||
-static struct airoha_foe_entry *
|
||||
-airoha_ppe_foe_get_entry(struct airoha_ppe *ppe, u32 hash)
|
||||
+struct airoha_foe_entry *airoha_ppe_foe_get_entry(struct airoha_ppe *ppe,
|
||||
+ u32 hash)
|
||||
{
|
||||
if (hash < PPE_SRAM_NUM_ENTRIES) {
|
||||
u32 *hwe = ppe->foe + hash * sizeof(struct airoha_foe_entry);
|
||||
@@ -861,7 +861,7 @@ void airoha_ppe_check_skb(struct airoha_
|
||||
int airoha_ppe_init(struct airoha_eth *eth)
|
||||
{
|
||||
struct airoha_ppe *ppe;
|
||||
- int foe_size;
|
||||
+ int foe_size, err;
|
||||
|
||||
ppe = devm_kzalloc(eth->dev, sizeof(*ppe), GFP_KERNEL);
|
||||
if (!ppe)
|
||||
@@ -882,7 +882,15 @@ int airoha_ppe_init(struct airoha_eth *e
|
||||
if (!ppe->foe_flow)
|
||||
return -ENOMEM;
|
||||
|
||||
- return rhashtable_init(ð->flow_table, &airoha_flow_table_params);
|
||||
+ err = rhashtable_init(ð->flow_table, &airoha_flow_table_params);
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+
|
||||
+ err = airoha_ppe_debugfs_init(ppe);
|
||||
+ if (err)
|
||||
+ rhashtable_destroy(ð->flow_table);
|
||||
+
|
||||
+ return err;
|
||||
}
|
||||
|
||||
void airoha_ppe_deinit(struct airoha_eth *eth)
|
||||
@@ -898,4 +906,5 @@ void airoha_ppe_deinit(struct airoha_eth
|
||||
rcu_read_unlock();
|
||||
|
||||
rhashtable_destroy(ð->flow_table);
|
||||
+ debugfs_remove(eth->ppe->debugfs_dir);
|
||||
}
|
||||
--- /dev/null
|
||||
+++ b/drivers/net/ethernet/airoha/airoha_ppe_debugfs.c
|
||||
@@ -0,0 +1,181 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0-only
|
||||
+/*
|
||||
+ * Copyright (c) 2025 AIROHA Inc
|
||||
+ * Author: Lorenzo Bianconi <lorenzo@kernel.org>
|
||||
+ */
|
||||
+
|
||||
+#include "airoha_eth.h"
|
||||
+
|
||||
+static void airoha_debugfs_ppe_print_tuple(struct seq_file *m,
|
||||
+ void *src_addr, void *dest_addr,
|
||||
+ u16 *src_port, u16 *dest_port,
|
||||
+ bool ipv6)
|
||||
+{
|
||||
+ __be32 n_addr[IPV6_ADDR_WORDS];
|
||||
+
|
||||
+ if (ipv6) {
|
||||
+ ipv6_addr_cpu_to_be32(n_addr, src_addr);
|
||||
+ seq_printf(m, "%pI6", n_addr);
|
||||
+ } else {
|
||||
+ seq_printf(m, "%pI4h", src_addr);
|
||||
+ }
|
||||
+ if (src_port)
|
||||
+ seq_printf(m, ":%d", *src_port);
|
||||
+
|
||||
+ seq_puts(m, "->");
|
||||
+
|
||||
+ if (ipv6) {
|
||||
+ ipv6_addr_cpu_to_be32(n_addr, dest_addr);
|
||||
+ seq_printf(m, "%pI6", n_addr);
|
||||
+ } else {
|
||||
+ seq_printf(m, "%pI4h", dest_addr);
|
||||
+ }
|
||||
+ if (dest_port)
|
||||
+ seq_printf(m, ":%d", *dest_port);
|
||||
+}
|
||||
+
|
||||
+static int airoha_ppe_debugfs_foe_show(struct seq_file *m, void *private,
|
||||
+ bool bind)
|
||||
+{
|
||||
+ static const char *const ppe_type_str[] = {
|
||||
+ [PPE_PKT_TYPE_IPV4_HNAPT] = "IPv4 5T",
|
||||
+ [PPE_PKT_TYPE_IPV4_ROUTE] = "IPv4 3T",
|
||||
+ [PPE_PKT_TYPE_BRIDGE] = "L2B",
|
||||
+ [PPE_PKT_TYPE_IPV4_DSLITE] = "DS-LITE",
|
||||
+ [PPE_PKT_TYPE_IPV6_ROUTE_3T] = "IPv6 3T",
|
||||
+ [PPE_PKT_TYPE_IPV6_ROUTE_5T] = "IPv6 5T",
|
||||
+ [PPE_PKT_TYPE_IPV6_6RD] = "6RD",
|
||||
+ };
|
||||
+ static const char *const ppe_state_str[] = {
|
||||
+ [AIROHA_FOE_STATE_INVALID] = "INV",
|
||||
+ [AIROHA_FOE_STATE_UNBIND] = "UNB",
|
||||
+ [AIROHA_FOE_STATE_BIND] = "BND",
|
||||
+ [AIROHA_FOE_STATE_FIN] = "FIN",
|
||||
+ };
|
||||
+ struct airoha_ppe *ppe = m->private;
|
||||
+ int i;
|
||||
+
|
||||
+ for (i = 0; i < PPE_NUM_ENTRIES; i++) {
|
||||
+ const char *state_str, *type_str = "UNKNOWN";
|
||||
+ void *src_addr = NULL, *dest_addr = NULL;
|
||||
+ u16 *src_port = NULL, *dest_port = NULL;
|
||||
+ struct airoha_foe_mac_info_common *l2;
|
||||
+ unsigned char h_source[ETH_ALEN] = {};
|
||||
+ unsigned char h_dest[ETH_ALEN];
|
||||
+ struct airoha_foe_entry *hwe;
|
||||
+ u32 type, state, ib2, data;
|
||||
+ bool ipv6 = false;
|
||||
+
|
||||
+ hwe = airoha_ppe_foe_get_entry(ppe, i);
|
||||
+ if (!hwe)
|
||||
+ continue;
|
||||
+
|
||||
+ state = FIELD_GET(AIROHA_FOE_IB1_BIND_STATE, hwe->ib1);
|
||||
+ if (!state)
|
||||
+ continue;
|
||||
+
|
||||
+ if (bind && state != AIROHA_FOE_STATE_BIND)
|
||||
+ continue;
|
||||
+
|
||||
+ state_str = ppe_state_str[state % ARRAY_SIZE(ppe_state_str)];
|
||||
+ type = FIELD_GET(AIROHA_FOE_IB1_BIND_PACKET_TYPE, hwe->ib1);
|
||||
+ if (type < ARRAY_SIZE(ppe_type_str) && ppe_type_str[type])
|
||||
+ type_str = ppe_type_str[type];
|
||||
+
|
||||
+ seq_printf(m, "%05x %s %7s", i, state_str, type_str);
|
||||
+
|
||||
+ switch (type) {
|
||||
+ case PPE_PKT_TYPE_IPV4_HNAPT:
|
||||
+ case PPE_PKT_TYPE_IPV4_DSLITE:
|
||||
+ src_port = &hwe->ipv4.orig_tuple.src_port;
|
||||
+ dest_port = &hwe->ipv4.orig_tuple.dest_port;
|
||||
+ fallthrough;
|
||||
+ case PPE_PKT_TYPE_IPV4_ROUTE:
|
||||
+ src_addr = &hwe->ipv4.orig_tuple.src_ip;
|
||||
+ dest_addr = &hwe->ipv4.orig_tuple.dest_ip;
|
||||
+ break;
|
||||
+ case PPE_PKT_TYPE_IPV6_ROUTE_5T:
|
||||
+ src_port = &hwe->ipv6.src_port;
|
||||
+ dest_port = &hwe->ipv6.dest_port;
|
||||
+ fallthrough;
|
||||
+ case PPE_PKT_TYPE_IPV6_ROUTE_3T:
|
||||
+ case PPE_PKT_TYPE_IPV6_6RD:
|
||||
+ src_addr = &hwe->ipv6.src_ip;
|
||||
+ dest_addr = &hwe->ipv6.dest_ip;
|
||||
+ ipv6 = true;
|
||||
+ break;
|
||||
+ default:
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ if (src_addr && dest_addr) {
|
||||
+ seq_puts(m, " orig=");
|
||||
+ airoha_debugfs_ppe_print_tuple(m, src_addr, dest_addr,
|
||||
+ src_port, dest_port, ipv6);
|
||||
+ }
|
||||
+
|
||||
+ switch (type) {
|
||||
+ case PPE_PKT_TYPE_IPV4_HNAPT:
|
||||
+ case PPE_PKT_TYPE_IPV4_DSLITE:
|
||||
+ src_port = &hwe->ipv4.new_tuple.src_port;
|
||||
+ dest_port = &hwe->ipv4.new_tuple.dest_port;
|
||||
+ fallthrough;
|
||||
+ case PPE_PKT_TYPE_IPV4_ROUTE:
|
||||
+ src_addr = &hwe->ipv4.new_tuple.src_ip;
|
||||
+ dest_addr = &hwe->ipv4.new_tuple.dest_ip;
|
||||
+ seq_puts(m, " new=");
|
||||
+ airoha_debugfs_ppe_print_tuple(m, src_addr, dest_addr,
|
||||
+ src_port, dest_port,
|
||||
+ ipv6);
|
||||
+ break;
|
||||
+ default:
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ if (type >= PPE_PKT_TYPE_IPV6_ROUTE_3T) {
|
||||
+ data = hwe->ipv6.data;
|
||||
+ ib2 = hwe->ipv6.ib2;
|
||||
+ l2 = &hwe->ipv6.l2;
|
||||
+ } else {
|
||||
+ data = hwe->ipv4.data;
|
||||
+ ib2 = hwe->ipv4.ib2;
|
||||
+ l2 = &hwe->ipv4.l2.common;
|
||||
+ *((__be16 *)&h_source[4]) =
|
||||
+ cpu_to_be16(hwe->ipv4.l2.src_mac_lo);
|
||||
+ }
|
||||
+
|
||||
+ *((__be32 *)h_dest) = cpu_to_be32(l2->dest_mac_hi);
|
||||
+ *((__be16 *)&h_dest[4]) = cpu_to_be16(l2->dest_mac_lo);
|
||||
+ *((__be32 *)h_source) = cpu_to_be32(l2->src_mac_hi);
|
||||
+
|
||||
+ seq_printf(m, " eth=%pM->%pM etype=%04x data=%08x"
|
||||
+ " vlan=%d,%d ib1=%08x ib2=%08x\n",
|
||||
+ h_source, h_dest, l2->etype, data,
|
||||
+ l2->vlan1, l2->vlan2, hwe->ib1, ib2);
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int airoha_ppe_debugfs_foe_all_show(struct seq_file *m, void *private)
|
||||
+{
|
||||
+ return airoha_ppe_debugfs_foe_show(m, private, false);
|
||||
+}
|
||||
+DEFINE_SHOW_ATTRIBUTE(airoha_ppe_debugfs_foe_all);
|
||||
+
|
||||
+static int airoha_ppe_debugfs_foe_bind_show(struct seq_file *m, void *private)
|
||||
+{
|
||||
+ return airoha_ppe_debugfs_foe_show(m, private, true);
|
||||
+}
|
||||
+DEFINE_SHOW_ATTRIBUTE(airoha_ppe_debugfs_foe_bind);
|
||||
+
|
||||
+int airoha_ppe_debugfs_init(struct airoha_ppe *ppe)
|
||||
+{
|
||||
+ ppe->debugfs_dir = debugfs_create_dir("ppe", NULL);
|
||||
+ debugfs_create_file("entries", 0444, ppe->debugfs_dir, ppe,
|
||||
+ &airoha_ppe_debugfs_foe_all_fops);
|
||||
+ debugfs_create_file("bind", 0444, ppe->debugfs_dir, ppe,
|
||||
+ &airoha_ppe_debugfs_foe_bind_fops);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
|
@ -84,9 +84,9 @@ change-id: 20250107-airoha-ets-fix-chan-e35ccac76d64
|
|||
|
||||
Best regards,
|
||||
|
||||
--- a/drivers/net/ethernet/mediatek/airoha_eth.c
|
||||
+++ b/drivers/net/ethernet/mediatek/airoha_eth.c
|
||||
@@ -2846,11 +2846,14 @@ static int airoha_qdma_get_tx_ets_stats(
|
||||
--- a/drivers/net/ethernet/airoha/airoha_eth.c
|
||||
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
|
||||
@@ -2064,11 +2064,14 @@ static int airoha_qdma_get_tx_ets_stats(
|
||||
static int airoha_tc_setup_qdisc_ets(struct airoha_gdm_port *port,
|
||||
struct tc_ets_qopt_offload *opt)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue