Resguardo inicial

This commit is contained in:
lastdragon
2026-09-06 12:53:21 -06:00
parent 662efe3c2a
commit ad2088d178
94853 changed files with 43200404 additions and 0 deletions
@@ -0,0 +1,37 @@
# SPDX-License-Identifier: GPL-2.0-only
config NET_VENDOR_MEDIATEK
bool "MediaTek devices"
depends on ARCH_MEDIATEK || ARCH_AIROHA || SOC_MT7621 || SOC_MT7620 || COMPILE_TEST
help
If you have a Mediatek SoC with ethernet, say Y.
if NET_VENDOR_MEDIATEK
config NET_MEDIATEK_SOC_WED
depends on ARCH_MEDIATEK || COMPILE_TEST
def_bool NET_MEDIATEK_SOC != n
config NET_MEDIATEK_SOC
tristate "MediaTek SoC Gigabit Ethernet support"
depends on NET_DSA || !NET_DSA
select PINCTRL
select PHYLINK
select DIMLIB
select GENERIC_ALLOCATOR
select PAGE_POOL
select PAGE_POOL_STATS
select PCS_MTK_LYNXI
select REGMAP_MMIO
help
This driver supports the gigabit ethernet MACs in the
MediaTek SoC family.
config NET_MEDIATEK_STAR_EMAC
tristate "MediaTek STAR Ethernet MAC support"
select PHYLIB
select REGMAP_MMIO
help
This driver supports the ethernet MAC IP first used on
MediaTek MT85** SoCs.
endif #NET_VENDOR_MEDIATEK
@@ -0,0 +1,13 @@
# SPDX-License-Identifier: GPL-2.0-only
#
# Makefile for the Mediatek SoCs built-in ethernet macs
#
obj-$(CONFIG_NET_MEDIATEK_SOC) += mtk_eth.o
mtk_eth-y := mtk_eth_soc.o mtk_eth_path.o mtk_ppe.o mtk_ppe_debugfs.o mtk_ppe_offload.o
mtk_eth-$(CONFIG_NET_MEDIATEK_SOC_WED) += mtk_wed.o mtk_wed_mcu.o mtk_wed_wo.o
ifdef CONFIG_DEBUG_FS
mtk_eth-$(CONFIG_NET_MEDIATEK_SOC_WED) += mtk_wed_debugfs.o
endif
obj-$(CONFIG_NET_MEDIATEK_SOC_WED) += mtk_wed_ops.o
obj-$(CONFIG_NET_MEDIATEK_STAR_EMAC) += mtk_star_emac.o
@@ -0,0 +1,330 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2018-2019 MediaTek Inc.
/* A library for configuring path from GMAC/GDM to target PHY
*
* Author: Sean Wang <sean.wang@mediatek.com>
*
*/
#include <linux/phy.h>
#include <linux/regmap.h>
#include "mtk_eth_soc.h"
struct mtk_eth_muxc {
const char *name;
u64 cap_bit;
int (*set_path)(struct mtk_eth *eth, u64 path);
};
static const char *mtk_eth_path_name(u64 path)
{
switch (path) {
case MTK_ETH_PATH_GMAC1_RGMII:
return "gmac1_rgmii";
case MTK_ETH_PATH_GMAC1_TRGMII:
return "gmac1_trgmii";
case MTK_ETH_PATH_GMAC1_SGMII:
return "gmac1_sgmii";
case MTK_ETH_PATH_GMAC2_RGMII:
return "gmac2_rgmii";
case MTK_ETH_PATH_GMAC2_SGMII:
return "gmac2_sgmii";
case MTK_ETH_PATH_GMAC2_2P5GPHY:
return "gmac2_2p5gphy";
case MTK_ETH_PATH_GMAC2_GEPHY:
return "gmac2_gephy";
case MTK_ETH_PATH_GDM1_ESW:
return "gdm1_esw";
default:
return "unknown path";
}
}
static int set_mux_gdm1_to_gmac1_esw(struct mtk_eth *eth, u64 path)
{
bool updated = true;
u32 mask, set, reg;
switch (path) {
case MTK_ETH_PATH_GMAC1_SGMII:
mask = ~(u32)MTK_MUX_TO_ESW;
set = 0;
break;
case MTK_ETH_PATH_GDM1_ESW:
mask = ~(u32)MTK_MUX_TO_ESW;
set = MTK_MUX_TO_ESW;
break;
default:
updated = false;
break;
}
if (mtk_is_netsys_v3_or_greater(eth))
reg = MTK_MAC_MISC_V3;
else
reg = MTK_MAC_MISC;
if (updated)
mtk_m32(eth, mask, set, reg);
dev_dbg(eth->dev, "path %s in %s updated = %d\n",
mtk_eth_path_name(path), __func__, updated);
return 0;
}
static int set_mux_gmac2_gmac0_to_gephy(struct mtk_eth *eth, u64 path)
{
unsigned int val = 0;
bool updated = true;
switch (path) {
case MTK_ETH_PATH_GMAC2_GEPHY:
val = ~(u32)GEPHY_MAC_SEL;
break;
default:
updated = false;
break;
}
if (updated)
regmap_update_bits(eth->infra, INFRA_MISC2, GEPHY_MAC_SEL, val);
dev_dbg(eth->dev, "path %s in %s updated = %d\n",
mtk_eth_path_name(path), __func__, updated);
return 0;
}
static int set_mux_u3_gmac2_to_qphy(struct mtk_eth *eth, u64 path)
{
unsigned int val = 0, mask = 0, reg = 0;
bool updated = true;
switch (path) {
case MTK_ETH_PATH_GMAC2_SGMII:
if (MTK_HAS_CAPS(eth->soc->caps, MTK_U3_COPHY_V2)) {
reg = USB_PHY_SWITCH_REG;
val = SGMII_QPHY_SEL;
mask = QPHY_SEL_MASK;
} else {
reg = INFRA_MISC2;
val = CO_QPHY_SEL;
mask = val;
}
break;
default:
updated = false;
break;
}
if (updated)
regmap_update_bits(eth->infra, reg, mask, val);
dev_dbg(eth->dev, "path %s in %s updated = %d\n",
mtk_eth_path_name(path), __func__, updated);
return 0;
}
static int set_mux_gmac2_to_2p5gphy(struct mtk_eth *eth, u64 path)
{
int ret;
if (path == MTK_ETH_PATH_GMAC2_2P5GPHY) {
ret = regmap_clear_bits(eth->ethsys, ETHSYS_SYSCFG0,
SYSCFG0_SGMII_GMAC2_V2);
if (ret)
return ret;
/* Setup mux to 2p5g PHY */
ret = regmap_clear_bits(eth->infra, TOP_MISC_NETSYS_PCS_MUX,
MUX_G2_USXGMII_SEL);
if (ret)
return ret;
dev_dbg(eth->dev, "path %s in %s updated\n",
mtk_eth_path_name(path), __func__);
}
return 0;
}
static int set_mux_gmac1_gmac2_to_sgmii_rgmii(struct mtk_eth *eth, u64 path)
{
unsigned int val = 0;
bool updated = true;
switch (path) {
case MTK_ETH_PATH_GMAC1_SGMII:
val = SYSCFG0_SGMII_GMAC1;
break;
case MTK_ETH_PATH_GMAC2_SGMII:
val = SYSCFG0_SGMII_GMAC2;
break;
case MTK_ETH_PATH_GMAC1_RGMII:
case MTK_ETH_PATH_GMAC2_RGMII:
regmap_read(eth->ethsys, ETHSYS_SYSCFG0, &val);
val &= SYSCFG0_SGMII_MASK;
if ((path == MTK_GMAC1_RGMII && val == SYSCFG0_SGMII_GMAC1) ||
(path == MTK_GMAC2_RGMII && val == SYSCFG0_SGMII_GMAC2))
val = 0;
else
updated = false;
break;
default:
updated = false;
break;
}
if (updated)
regmap_update_bits(eth->ethsys, ETHSYS_SYSCFG0,
SYSCFG0_SGMII_MASK, val);
dev_dbg(eth->dev, "path %s in %s updated = %d\n",
mtk_eth_path_name(path), __func__, updated);
return 0;
}
static int set_mux_gmac12_to_gephy_sgmii(struct mtk_eth *eth, u64 path)
{
unsigned int val = 0;
bool updated = true;
regmap_read(eth->ethsys, ETHSYS_SYSCFG0, &val);
switch (path) {
case MTK_ETH_PATH_GMAC1_SGMII:
val |= SYSCFG0_SGMII_GMAC1_V2;
break;
case MTK_ETH_PATH_GMAC2_GEPHY:
val &= ~(u32)SYSCFG0_SGMII_GMAC2_V2;
break;
case MTK_ETH_PATH_GMAC2_SGMII:
val |= SYSCFG0_SGMII_GMAC2_V2;
break;
default:
updated = false;
}
if (updated)
regmap_update_bits(eth->ethsys, ETHSYS_SYSCFG0,
SYSCFG0_SGMII_MASK, val);
dev_dbg(eth->dev, "path %s in %s updated = %d\n",
mtk_eth_path_name(path), __func__, updated);
return 0;
}
static const struct mtk_eth_muxc mtk_eth_muxc[] = {
{
.name = "mux_gdm1_to_gmac1_esw",
.cap_bit = MTK_ETH_MUX_GDM1_TO_GMAC1_ESW,
.set_path = set_mux_gdm1_to_gmac1_esw,
}, {
.name = "mux_gmac2_gmac0_to_gephy",
.cap_bit = MTK_ETH_MUX_GMAC2_GMAC0_TO_GEPHY,
.set_path = set_mux_gmac2_gmac0_to_gephy,
}, {
.name = "mux_u3_gmac2_to_qphy",
.cap_bit = MTK_ETH_MUX_U3_GMAC2_TO_QPHY,
.set_path = set_mux_u3_gmac2_to_qphy,
}, {
.name = "mux_gmac2_to_2p5gphy",
.cap_bit = MTK_ETH_MUX_GMAC2_TO_2P5GPHY,
.set_path = set_mux_gmac2_to_2p5gphy,
}, {
.name = "mux_gmac1_gmac2_to_sgmii_rgmii",
.cap_bit = MTK_ETH_MUX_GMAC1_GMAC2_TO_SGMII_RGMII,
.set_path = set_mux_gmac1_gmac2_to_sgmii_rgmii,
}, {
.name = "mux_gmac12_to_gephy_sgmii",
.cap_bit = MTK_ETH_MUX_GMAC12_TO_GEPHY_SGMII,
.set_path = set_mux_gmac12_to_gephy_sgmii,
},
};
static int mtk_eth_mux_setup(struct mtk_eth *eth, u64 path)
{
int i, err = 0;
if (!MTK_HAS_CAPS(eth->soc->caps, path)) {
dev_err(eth->dev, "path %s isn't support on the SoC\n",
mtk_eth_path_name(path));
return -EINVAL;
}
if (!MTK_HAS_CAPS(eth->soc->caps, MTK_MUX))
return 0;
/* Setup MUX in path fabric */
for (i = 0; i < ARRAY_SIZE(mtk_eth_muxc); i++) {
if (MTK_HAS_CAPS(eth->soc->caps, mtk_eth_muxc[i].cap_bit)) {
err = mtk_eth_muxc[i].set_path(eth, path);
if (err)
goto out;
} else {
dev_dbg(eth->dev, "mux %s isn't present on the SoC\n",
mtk_eth_muxc[i].name);
}
}
out:
return err;
}
int mtk_gmac_sgmii_path_setup(struct mtk_eth *eth, int mac_id)
{
u64 path;
path = (mac_id == 0) ? MTK_ETH_PATH_GMAC1_SGMII :
MTK_ETH_PATH_GMAC2_SGMII;
/* Setup proper MUXes along the path */
return mtk_eth_mux_setup(eth, path);
}
int mtk_gmac_2p5gphy_path_setup(struct mtk_eth *eth, int mac_id)
{
u64 path = 0;
if (mac_id == MTK_GMAC2_ID)
path = MTK_ETH_PATH_GMAC2_2P5GPHY;
if (!path)
return -EINVAL;
/* Setup proper MUXes along the path */
return mtk_eth_mux_setup(eth, path);
}
int mtk_gmac_gephy_path_setup(struct mtk_eth *eth, int mac_id)
{
u64 path = 0;
if (mac_id == 1)
path = MTK_ETH_PATH_GMAC2_GEPHY;
if (!path)
return -EINVAL;
/* Setup proper MUXes along the path */
return mtk_eth_mux_setup(eth, path);
}
int mtk_gmac_rgmii_path_setup(struct mtk_eth *eth, int mac_id)
{
u64 path;
path = (mac_id == 0) ? MTK_ETH_PATH_GMAC1_RGMII :
MTK_ETH_PATH_GMAC2_RGMII;
/* Setup proper MUXes along the path */
return mtk_eth_mux_setup(eth, path);
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,407 @@
// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (C) 2020 Felix Fietkau <nbd@nbd.name> */
#ifndef __MTK_PPE_H
#define __MTK_PPE_H
#include <linux/kernel.h>
#include <linux/bitfield.h>
#include <linux/rhashtable.h>
#define MTK_PPE_ENTRIES_SHIFT 4
#define MTK_PPE_ENTRIES (1024 << MTK_PPE_ENTRIES_SHIFT)
#define MTK_PPE_HASH_MASK (MTK_PPE_ENTRIES - 1)
#define MTK_PPE_WAIT_TIMEOUT_US 1000000
#define MTK_FOE_IB1_UNBIND_TIMESTAMP GENMASK(7, 0)
#define MTK_FOE_IB1_UNBIND_PACKETS GENMASK(23, 8)
#define MTK_FOE_IB1_UNBIND_PREBIND BIT(24)
#define MTK_FOE_IB1_BIND_TIMESTAMP GENMASK(14, 0)
#define MTK_FOE_IB1_BIND_KEEPALIVE BIT(15)
#define MTK_FOE_IB1_BIND_VLAN_LAYER GENMASK(18, 16)
#define MTK_FOE_IB1_BIND_PPPOE BIT(19)
#define MTK_FOE_IB1_BIND_VLAN_TAG BIT(20)
#define MTK_FOE_IB1_BIND_PKT_SAMPLE BIT(21)
#define MTK_FOE_IB1_BIND_CACHE BIT(22)
#define MTK_FOE_IB1_BIND_TUNNEL_DECAP BIT(23)
#define MTK_FOE_IB1_BIND_TTL BIT(24)
#define MTK_FOE_IB1_PACKET_TYPE GENMASK(27, 25)
#define MTK_FOE_IB1_STATE GENMASK(29, 28)
#define MTK_FOE_IB1_UDP BIT(30)
#define MTK_FOE_IB1_STATIC BIT(31)
/* CONFIG_MEDIATEK_NETSYS_V2 */
#define MTK_FOE_IB1_BIND_TIMESTAMP_V2 GENMASK(7, 0)
#define MTK_FOE_IB1_BIND_VLAN_LAYER_V2 GENMASK(16, 14)
#define MTK_FOE_IB1_BIND_PPPOE_V2 BIT(17)
#define MTK_FOE_IB1_BIND_VLAN_TAG_V2 BIT(18)
#define MTK_FOE_IB1_BIND_CACHE_V2 BIT(20)
#define MTK_FOE_IB1_BIND_TTL_V2 BIT(22)
#define MTK_FOE_IB1_PACKET_TYPE_V2 GENMASK(27, 23)
enum {
MTK_PPE_PKT_TYPE_IPV4_HNAPT = 0,
MTK_PPE_PKT_TYPE_IPV4_ROUTE = 1,
MTK_PPE_PKT_TYPE_BRIDGE = 2,
MTK_PPE_PKT_TYPE_IPV4_DSLITE = 3,
MTK_PPE_PKT_TYPE_IPV6_ROUTE_3T = 4,
MTK_PPE_PKT_TYPE_IPV6_ROUTE_5T = 5,
MTK_PPE_PKT_TYPE_IPV6_6RD = 7,
};
#define MTK_FOE_IB2_QID GENMASK(3, 0)
#define MTK_FOE_IB2_PSE_QOS BIT(4)
#define MTK_FOE_IB2_DEST_PORT GENMASK(7, 5)
#define MTK_FOE_IB2_MULTICAST BIT(8)
#define MTK_FOE_IB2_MIB_CNT BIT(10)
#define MTK_FOE_IB2_WDMA_QID2 GENMASK(13, 12)
#define MTK_FOE_IB2_MIB_CNT_V2 BIT(15)
#define MTK_FOE_IB2_WDMA_DEVIDX BIT(16)
#define MTK_FOE_IB2_WDMA_WINFO BIT(17)
#define MTK_FOE_IB2_PORT_MG GENMASK(17, 12)
#define MTK_FOE_IB2_RX_IDX GENMASK(18, 17)
#define MTK_FOE_IB2_PORT_AG GENMASK(23, 18)
#define MTK_FOE_IB2_DSCP GENMASK(31, 24)
/* CONFIG_MEDIATEK_NETSYS_V2 */
#define MTK_FOE_IB2_QID_V2 GENMASK(6, 0)
#define MTK_FOE_IB2_PORT_MG_V2 BIT(7)
#define MTK_FOE_IB2_PSE_QOS_V2 BIT(8)
#define MTK_FOE_IB2_DEST_PORT_V2 GENMASK(12, 9)
#define MTK_FOE_IB2_MULTICAST_V2 BIT(13)
#define MTK_FOE_IB2_WDMA_WINFO_V2 BIT(19)
#define MTK_FOE_IB2_PORT_AG_V2 GENMASK(23, 20)
#define MTK_FOE_VLAN2_WINFO_BSS GENMASK(5, 0)
#define MTK_FOE_VLAN2_WINFO_WCID GENMASK(13, 6)
#define MTK_FOE_VLAN2_WINFO_RING GENMASK(15, 14)
#define MTK_FOE_WINFO_BSS GENMASK(5, 0)
#define MTK_FOE_WINFO_WCID GENMASK(15, 6)
#define MTK_FOE_WINFO_BSS_V3 GENMASK(23, 16)
#define MTK_FOE_WINFO_WCID_V3 GENMASK(15, 0)
#define MTK_FOE_WINFO_AMSDU_USR_INFO GENMASK(15, 0)
#define MTK_FOE_WINFO_AMSDU_TID GENMASK(19, 16)
#define MTK_FOE_WINFO_AMSDU_IS_FIXEDRATE BIT(20)
#define MTK_FOE_WINFO_AMSDU_IS_PRIOR BIT(21)
#define MTK_FOE_WINFO_AMSDU_IS_SP BIT(22)
#define MTK_FOE_WINFO_AMSDU_HF BIT(23)
#define MTK_FOE_WINFO_AMSDU_EN BIT(24)
enum {
MTK_FOE_STATE_INVALID,
MTK_FOE_STATE_UNBIND,
MTK_FOE_STATE_BIND,
MTK_FOE_STATE_FIN
};
struct mtk_foe_mac_info {
u16 vlan1;
u16 etype;
u32 dest_mac_hi;
u16 vlan2;
u16 dest_mac_lo;
u32 src_mac_hi;
u16 pppoe_id;
u16 src_mac_lo;
/* netsys_v2 */
u16 minfo;
u16 winfo;
/* netsys_v3 */
u32 w3info;
u32 amsdu;
};
/* software-only entry type */
struct mtk_foe_bridge {
u8 dest_mac[ETH_ALEN];
u8 src_mac[ETH_ALEN];
u16 vlan;
struct {} key_end;
u32 ib2;
struct mtk_foe_mac_info l2;
};
struct mtk_ipv4_tuple {
u32 src_ip;
u32 dest_ip;
union {
struct {
u16 dest_port;
u16 src_port;
};
struct {
u8 protocol;
u8 _pad[3]; /* fill with 0xa5a5a5 */
};
u32 ports;
};
};
struct mtk_foe_ipv4 {
struct mtk_ipv4_tuple orig;
u32 ib2;
struct mtk_ipv4_tuple new;
u16 timestamp;
u16 _rsv0[3];
u32 udf_tsid;
struct mtk_foe_mac_info l2;
};
struct mtk_foe_ipv4_dslite {
struct mtk_ipv4_tuple ip4;
u32 tunnel_src_ip[4];
u32 tunnel_dest_ip[4];
u8 flow_label[3];
u8 priority;
u32 udf_tsid;
u32 ib2;
struct mtk_foe_mac_info l2;
};
struct mtk_foe_ipv6 {
u32 src_ip[4];
u32 dest_ip[4];
union {
struct {
u8 protocol;
u8 _pad[3]; /* fill with 0xa5a5a5 */
}; /* 3-tuple */
struct {
u16 dest_port;
u16 src_port;
}; /* 5-tuple */
u32 ports;
};
u32 _rsv[3];
u32 udf;
u32 ib2;
struct mtk_foe_mac_info l2;
};
struct mtk_foe_ipv6_6rd {
u32 src_ip[4];
u32 dest_ip[4];
u16 dest_port;
u16 src_port;
u32 tunnel_src_ip;
u32 tunnel_dest_ip;
u16 hdr_csum;
u8 dscp;
u8 ttl;
u8 flag;
u8 pad;
u8 per_flow_6rd_id;
u8 pad2;
u32 ib2;
struct mtk_foe_mac_info l2;
};
#define MTK_FOE_ENTRY_V1_SIZE 80
#define MTK_FOE_ENTRY_V2_SIZE 96
#define MTK_FOE_ENTRY_V3_SIZE 128
struct mtk_foe_entry {
u32 ib1;
union {
struct mtk_foe_bridge bridge;
struct mtk_foe_ipv4 ipv4;
struct mtk_foe_ipv4_dslite dslite;
struct mtk_foe_ipv6 ipv6;
struct mtk_foe_ipv6_6rd ipv6_6rd;
u32 data[31];
};
};
enum {
MTK_PPE_CPU_REASON_TTL_EXCEEDED = 0x02,
MTK_PPE_CPU_REASON_OPTION_HEADER = 0x03,
MTK_PPE_CPU_REASON_NO_FLOW = 0x07,
MTK_PPE_CPU_REASON_IPV4_FRAG = 0x08,
MTK_PPE_CPU_REASON_IPV4_DSLITE_FRAG = 0x09,
MTK_PPE_CPU_REASON_IPV4_DSLITE_NO_TCP_UDP = 0x0a,
MTK_PPE_CPU_REASON_IPV6_6RD_NO_TCP_UDP = 0x0b,
MTK_PPE_CPU_REASON_TCP_FIN_SYN_RST = 0x0c,
MTK_PPE_CPU_REASON_UN_HIT = 0x0d,
MTK_PPE_CPU_REASON_HIT_UNBIND = 0x0e,
MTK_PPE_CPU_REASON_HIT_UNBIND_RATE_REACHED = 0x0f,
MTK_PPE_CPU_REASON_HIT_BIND_TCP_FIN = 0x10,
MTK_PPE_CPU_REASON_HIT_TTL_1 = 0x11,
MTK_PPE_CPU_REASON_HIT_BIND_VLAN_VIOLATION = 0x12,
MTK_PPE_CPU_REASON_KEEPALIVE_UC_OLD_HDR = 0x13,
MTK_PPE_CPU_REASON_KEEPALIVE_MC_NEW_HDR = 0x14,
MTK_PPE_CPU_REASON_KEEPALIVE_DUP_OLD_HDR = 0x15,
MTK_PPE_CPU_REASON_HIT_BIND_FORCE_CPU = 0x16,
MTK_PPE_CPU_REASON_TUNNEL_OPTION_HEADER = 0x17,
MTK_PPE_CPU_REASON_MULTICAST_TO_CPU = 0x18,
MTK_PPE_CPU_REASON_MULTICAST_TO_GMAC1_CPU = 0x19,
MTK_PPE_CPU_REASON_HIT_PRE_BIND = 0x1a,
MTK_PPE_CPU_REASON_PACKET_SAMPLING = 0x1b,
MTK_PPE_CPU_REASON_EXCEED_MTU = 0x1c,
MTK_PPE_CPU_REASON_PPE_BYPASS = 0x1e,
MTK_PPE_CPU_REASON_INVALID = 0x1f,
};
enum {
MTK_FLOW_TYPE_L4,
MTK_FLOW_TYPE_L2,
MTK_FLOW_TYPE_L2_SUBFLOW,
};
struct mtk_flow_entry {
union {
struct hlist_node list;
struct {
struct rhash_head l2_node;
struct hlist_head l2_flows;
};
};
u8 type;
s8 wed_index;
u8 ppe_index;
u16 hash;
union {
struct mtk_foe_entry data;
struct {
struct mtk_flow_entry *base_flow;
struct hlist_node list;
} l2_data;
};
struct rhash_head node;
unsigned long cookie;
};
struct mtk_mib_entry {
u32 byt_cnt_l;
u16 byt_cnt_h;
u32 pkt_cnt_l;
u8 pkt_cnt_h;
u8 _rsv0;
u32 _rsv1;
} __packed;
struct mtk_foe_accounting {
u64 bytes;
u64 packets;
};
struct mtk_ppe {
struct mtk_eth *eth;
struct device *dev;
void __iomem *base;
int version;
char dirname[5];
bool accounting;
void *foe_table;
dma_addr_t foe_phys;
struct mtk_mib_entry *mib_table;
dma_addr_t mib_phys;
u16 foe_check_time[MTK_PPE_ENTRIES];
struct hlist_head *foe_flow;
struct rhashtable l2_flows;
void *acct_table;
};
struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base, int index);
void mtk_ppe_deinit(struct mtk_eth *eth);
void mtk_ppe_update_mtu(struct mtk_ppe *ppe, int mtu);
void mtk_ppe_start(struct mtk_ppe *ppe);
int mtk_ppe_stop(struct mtk_ppe *ppe);
int mtk_ppe_prepare_reset(struct mtk_ppe *ppe);
void __mtk_ppe_check_skb(struct mtk_ppe *ppe, struct sk_buff *skb, u16 hash);
static inline void
mtk_ppe_check_skb(struct mtk_ppe *ppe, struct sk_buff *skb, u16 hash)
{
u16 now, diff;
if (!ppe)
return;
if (hash > MTK_PPE_HASH_MASK)
return;
now = (u16)jiffies;
diff = now - ppe->foe_check_time[hash];
if (diff < HZ / 10)
return;
ppe->foe_check_time[hash] = now;
__mtk_ppe_check_skb(ppe, skb, hash);
}
int mtk_foe_entry_prepare(struct mtk_eth *eth, struct mtk_foe_entry *entry,
int type, int l4proto, u8 pse_port, u8 *src_mac,
u8 *dest_mac);
int mtk_foe_entry_set_pse_port(struct mtk_eth *eth,
struct mtk_foe_entry *entry, u8 port);
int mtk_foe_entry_set_ipv4_tuple(struct mtk_eth *eth,
struct mtk_foe_entry *entry, bool orig,
__be32 src_addr, __be16 src_port,
__be32 dest_addr, __be16 dest_port);
int mtk_foe_entry_set_ipv6_tuple(struct mtk_eth *eth,
struct mtk_foe_entry *entry,
__be32 *src_addr, __be16 src_port,
__be32 *dest_addr, __be16 dest_port);
int mtk_foe_entry_set_dsa(struct mtk_eth *eth, struct mtk_foe_entry *entry,
int port);
int mtk_foe_entry_set_vlan(struct mtk_eth *eth, struct mtk_foe_entry *entry,
int vid);
int mtk_foe_entry_set_pppoe(struct mtk_eth *eth, struct mtk_foe_entry *entry,
int sid);
int mtk_foe_entry_set_wdma(struct mtk_eth *eth, struct mtk_foe_entry *entry,
int wdma_idx, int txq, int bss, int wcid,
bool amsdu_en);
int mtk_foe_entry_set_queue(struct mtk_eth *eth, struct mtk_foe_entry *entry,
unsigned int queue);
int mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_flow_entry *entry);
void mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry);
int mtk_foe_entry_idle_time(struct mtk_ppe *ppe, struct mtk_flow_entry *entry);
int mtk_ppe_debugfs_init(struct mtk_ppe *ppe, int index);
struct mtk_foe_accounting *mtk_foe_entry_get_mib(struct mtk_ppe *ppe, u32 index,
struct mtk_foe_accounting *diff);
#endif
@@ -0,0 +1,195 @@
// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (C) 2020 Felix Fietkau <nbd@nbd.name> */
#include <linux/kernel.h>
#include <linux/debugfs.h>
#include <net/ipv6.h>
#include "mtk_eth_soc.h"
struct mtk_flow_addr_info
{
void *src, *dest;
u16 *src_port, *dest_port;
bool ipv6;
};
static const char *mtk_foe_entry_state_str(int state)
{
static const char * const state_str[] = {
[MTK_FOE_STATE_INVALID] = "INV",
[MTK_FOE_STATE_UNBIND] = "UNB",
[MTK_FOE_STATE_BIND] = "BND",
[MTK_FOE_STATE_FIN] = "FIN",
};
if (state >= ARRAY_SIZE(state_str) || !state_str[state])
return "UNK";
return state_str[state];
}
static const char *mtk_foe_pkt_type_str(int type)
{
static const char * const type_str[] = {
[MTK_PPE_PKT_TYPE_IPV4_HNAPT] = "IPv4 5T",
[MTK_PPE_PKT_TYPE_IPV4_ROUTE] = "IPv4 3T",
[MTK_PPE_PKT_TYPE_IPV4_DSLITE] = "DS-LITE",
[MTK_PPE_PKT_TYPE_IPV6_ROUTE_3T] = "IPv6 3T",
[MTK_PPE_PKT_TYPE_IPV6_ROUTE_5T] = "IPv6 5T",
[MTK_PPE_PKT_TYPE_IPV6_6RD] = "6RD",
};
if (type >= ARRAY_SIZE(type_str) || !type_str[type])
return "UNKNOWN";
return type_str[type];
}
static void
mtk_print_addr(struct seq_file *m, u32 *addr, bool ipv6)
{
__be32 n_addr[IPV6_ADDR_WORDS];
if (!ipv6) {
seq_printf(m, "%pI4h", addr);
return;
}
ipv6_addr_cpu_to_be32(n_addr, addr);
seq_printf(m, "%pI6", n_addr);
}
static void
mtk_print_addr_info(struct seq_file *m, struct mtk_flow_addr_info *ai)
{
mtk_print_addr(m, ai->src, ai->ipv6);
if (ai->src_port)
seq_printf(m, ":%d", *ai->src_port);
seq_printf(m, "->");
mtk_print_addr(m, ai->dest, ai->ipv6);
if (ai->dest_port)
seq_printf(m, ":%d", *ai->dest_port);
}
static int
mtk_ppe_debugfs_foe_show(struct seq_file *m, void *private, bool bind)
{
struct mtk_ppe *ppe = m->private;
int i;
for (i = 0; i < MTK_PPE_ENTRIES; i++) {
struct mtk_foe_entry *entry = mtk_foe_get_entry(ppe, i);
struct mtk_foe_mac_info *l2;
struct mtk_flow_addr_info ai = {};
struct mtk_foe_accounting *acct;
unsigned char h_source[ETH_ALEN];
unsigned char h_dest[ETH_ALEN];
int type, state;
u32 ib2;
state = FIELD_GET(MTK_FOE_IB1_STATE, entry->ib1);
if (!state)
continue;
if (bind && state != MTK_FOE_STATE_BIND)
continue;
acct = mtk_foe_entry_get_mib(ppe, i, NULL);
type = mtk_get_ib1_pkt_type(ppe->eth, entry->ib1);
seq_printf(m, "%05x %s %7s", i,
mtk_foe_entry_state_str(state),
mtk_foe_pkt_type_str(type));
switch (type) {
case MTK_PPE_PKT_TYPE_IPV4_HNAPT:
case MTK_PPE_PKT_TYPE_IPV4_DSLITE:
ai.src_port = &entry->ipv4.orig.src_port;
ai.dest_port = &entry->ipv4.orig.dest_port;
fallthrough;
case MTK_PPE_PKT_TYPE_IPV4_ROUTE:
ai.src = &entry->ipv4.orig.src_ip;
ai.dest = &entry->ipv4.orig.dest_ip;
break;
case MTK_PPE_PKT_TYPE_IPV6_ROUTE_5T:
ai.src_port = &entry->ipv6.src_port;
ai.dest_port = &entry->ipv6.dest_port;
fallthrough;
case MTK_PPE_PKT_TYPE_IPV6_ROUTE_3T:
case MTK_PPE_PKT_TYPE_IPV6_6RD:
ai.src = &entry->ipv6.src_ip;
ai.dest = &entry->ipv6.dest_ip;
ai.ipv6 = true;
break;
}
seq_printf(m, " orig=");
mtk_print_addr_info(m, &ai);
switch (type) {
case MTK_PPE_PKT_TYPE_IPV4_HNAPT:
case MTK_PPE_PKT_TYPE_IPV4_DSLITE:
ai.src_port = &entry->ipv4.new.src_port;
ai.dest_port = &entry->ipv4.new.dest_port;
fallthrough;
case MTK_PPE_PKT_TYPE_IPV4_ROUTE:
ai.src = &entry->ipv4.new.src_ip;
ai.dest = &entry->ipv4.new.dest_ip;
seq_printf(m, " new=");
mtk_print_addr_info(m, &ai);
break;
}
if (type >= MTK_PPE_PKT_TYPE_IPV4_DSLITE) {
l2 = &entry->ipv6.l2;
ib2 = entry->ipv6.ib2;
} else {
l2 = &entry->ipv4.l2;
ib2 = entry->ipv4.ib2;
}
*((__be32 *)h_source) = htonl(l2->src_mac_hi);
*((__be16 *)&h_source[4]) = htons(l2->src_mac_lo);
*((__be32 *)h_dest) = htonl(l2->dest_mac_hi);
*((__be16 *)&h_dest[4]) = htons(l2->dest_mac_lo);
seq_printf(m, " eth=%pM->%pM etype=%04x"
" vlan=%d,%d ib1=%08x ib2=%08x"
" packets=%llu bytes=%llu\n",
h_source, h_dest, ntohs(l2->etype),
l2->vlan1, l2->vlan2, entry->ib1, ib2,
acct ? acct->packets : 0, acct ? acct->bytes : 0);
}
return 0;
}
static int
mtk_ppe_debugfs_foe_all_show(struct seq_file *m, void *private)
{
return mtk_ppe_debugfs_foe_show(m, private, false);
}
DEFINE_SHOW_ATTRIBUTE(mtk_ppe_debugfs_foe_all);
static int
mtk_ppe_debugfs_foe_bind_show(struct seq_file *m, void *private)
{
return mtk_ppe_debugfs_foe_show(m, private, true);
}
DEFINE_SHOW_ATTRIBUTE(mtk_ppe_debugfs_foe_bind);
int mtk_ppe_debugfs_init(struct mtk_ppe *ppe, int index)
{
struct dentry *root;
snprintf(ppe->dirname, sizeof(ppe->dirname), "ppe%d", index);
root = debugfs_create_dir(ppe->dirname, NULL);
debugfs_create_file("entries", S_IRUGO, root, ppe, &mtk_ppe_debugfs_foe_all_fops);
debugfs_create_file("bind", S_IRUGO, root, ppe, &mtk_ppe_debugfs_foe_bind_fops);
return 0;
}
@@ -0,0 +1,677 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2020 Felix Fietkau <nbd@nbd.name>
*/
#include <linux/if_ether.h>
#include <linux/rhashtable.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <net/flow_offload.h>
#include <net/pkt_cls.h>
#include <net/dsa.h>
#include "mtk_eth_soc.h"
#include "mtk_wed.h"
struct mtk_flow_data {
struct ethhdr eth;
union {
struct {
__be32 src_addr;
__be32 dst_addr;
} v4;
struct {
struct in6_addr src_addr;
struct in6_addr dst_addr;
} v6;
};
__be16 src_port;
__be16 dst_port;
u16 vlan_in;
struct {
struct {
u16 id;
__be16 proto;
} vlans[2];
u8 num;
} vlan;
struct {
u16 sid;
u8 num;
} pppoe;
};
static const struct rhashtable_params mtk_flow_ht_params = {
.head_offset = offsetof(struct mtk_flow_entry, node),
.key_offset = offsetof(struct mtk_flow_entry, cookie),
.key_len = sizeof(unsigned long),
.automatic_shrinking = true,
};
static int
mtk_flow_set_ipv4_addr(struct mtk_eth *eth, struct mtk_foe_entry *foe,
struct mtk_flow_data *data, bool egress)
{
return mtk_foe_entry_set_ipv4_tuple(eth, foe, egress,
data->v4.src_addr, data->src_port,
data->v4.dst_addr, data->dst_port);
}
static int
mtk_flow_set_ipv6_addr(struct mtk_eth *eth, struct mtk_foe_entry *foe,
struct mtk_flow_data *data)
{
return mtk_foe_entry_set_ipv6_tuple(eth, foe,
data->v6.src_addr.s6_addr32, data->src_port,
data->v6.dst_addr.s6_addr32, data->dst_port);
}
static void
mtk_flow_offload_mangle_eth(const struct flow_action_entry *act, void *eth)
{
void *dest = eth + act->mangle.offset;
const void *src = &act->mangle.val;
if (act->mangle.offset > 8)
return;
if (act->mangle.mask == 0xffff) {
src += 2;
dest += 2;
}
memcpy(dest, src, act->mangle.mask ? 2 : 4);
}
static int
mtk_flow_get_wdma_info(struct net_device *dev, const u8 *addr, struct mtk_wdma_info *info)
{
struct net_device_path_stack stack;
struct net_device_path *path;
int err;
if (!dev)
return -ENODEV;
if (!IS_ENABLED(CONFIG_NET_MEDIATEK_SOC_WED))
return -1;
rcu_read_lock();
err = dev_fill_forward_path(dev, addr, &stack);
rcu_read_unlock();
if (err)
return err;
path = &stack.path[stack.num_paths - 1];
if (path->type != DEV_PATH_MTK_WDMA)
return -1;
info->wdma_idx = path->mtk_wdma.wdma_idx;
info->queue = path->mtk_wdma.queue;
info->bss = path->mtk_wdma.bss;
info->wcid = path->mtk_wdma.wcid;
info->amsdu = path->mtk_wdma.amsdu;
return 0;
}
static int
mtk_flow_mangle_ports(const struct flow_action_entry *act,
struct mtk_flow_data *data)
{
u32 val = ntohl(act->mangle.val);
switch (act->mangle.offset) {
case 0:
if (act->mangle.mask == ~htonl(0xffff))
data->dst_port = cpu_to_be16(val);
else
data->src_port = cpu_to_be16(val >> 16);
break;
case 2:
data->dst_port = cpu_to_be16(val);
break;
default:
return -EINVAL;
}
return 0;
}
static int
mtk_flow_mangle_ipv4(const struct flow_action_entry *act,
struct mtk_flow_data *data)
{
__be32 *dest;
switch (act->mangle.offset) {
case offsetof(struct iphdr, saddr):
dest = &data->v4.src_addr;
break;
case offsetof(struct iphdr, daddr):
dest = &data->v4.dst_addr;
break;
default:
return -EINVAL;
}
memcpy(dest, &act->mangle.val, sizeof(u32));
return 0;
}
static int
mtk_flow_get_dsa_port(struct net_device **dev)
{
#if IS_ENABLED(CONFIG_NET_DSA)
struct dsa_port *dp;
dp = dsa_port_from_netdev(*dev);
if (IS_ERR(dp))
return -ENODEV;
if (dp->cpu_dp->tag_ops->proto != DSA_TAG_PROTO_MTK)
return -ENODEV;
*dev = dsa_port_to_conduit(dp);
return dp->index;
#else
return -ENODEV;
#endif
}
static int
mtk_flow_set_output_device(struct mtk_eth *eth, struct mtk_foe_entry *foe,
struct net_device *dev, const u8 *dest_mac,
int *wed_index)
{
struct mtk_wdma_info info = {};
int pse_port, dsa_port, queue;
if (mtk_flow_get_wdma_info(dev, dest_mac, &info) == 0) {
mtk_foe_entry_set_wdma(eth, foe, info.wdma_idx, info.queue,
info.bss, info.wcid, info.amsdu);
if (mtk_is_netsys_v2_or_greater(eth)) {
switch (info.wdma_idx) {
case 0:
pse_port = PSE_WDMA0_PORT;
break;
case 1:
pse_port = PSE_WDMA1_PORT;
break;
case 2:
pse_port = PSE_WDMA2_PORT;
break;
default:
return -EINVAL;
}
} else {
pse_port = 3;
}
*wed_index = info.wdma_idx;
goto out;
}
dsa_port = mtk_flow_get_dsa_port(&dev);
if (dev == eth->netdev[0])
pse_port = PSE_GDM1_PORT;
else if (dev == eth->netdev[1])
pse_port = PSE_GDM2_PORT;
else if (dev == eth->netdev[2])
pse_port = PSE_GDM3_PORT;
else
return -EOPNOTSUPP;
if (dsa_port >= 0) {
mtk_foe_entry_set_dsa(eth, foe, dsa_port);
queue = 3 + dsa_port;
} else {
queue = pse_port - 1;
}
mtk_foe_entry_set_queue(eth, foe, queue);
out:
mtk_foe_entry_set_pse_port(eth, foe, pse_port);
return 0;
}
static bool
mtk_flow_is_valid_idev(const struct mtk_eth *eth, const struct net_device *idev)
{
size_t i;
if (!idev)
return false;
for (i = 0; i < ARRAY_SIZE(eth->netdev); i++) {
if (!eth->netdev[i])
continue;
if (idev->netdev_ops == eth->netdev[i]->netdev_ops)
return true;
}
return false;
}
static int
mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f,
int ppe_index)
{
struct flow_rule *rule = flow_cls_offload_flow_rule(f);
struct net_device *idev = NULL, *odev = NULL;
struct flow_action_entry *act;
struct mtk_flow_data data = {};
struct mtk_foe_entry foe;
struct mtk_flow_entry *entry;
int offload_type = 0;
int wed_index = -1;
u16 addr_type = 0;
u8 l4proto = 0;
int err = 0;
int i;
if (rhashtable_lookup(&eth->flow_table, &f->cookie, mtk_flow_ht_params))
return -EEXIST;
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_META)) {
struct flow_match_meta match;
flow_rule_match_meta(rule, &match);
if (mtk_is_netsys_v2_or_greater(eth)) {
idev = __dev_get_by_index(&init_net, match.key->ingress_ifindex);
if (mtk_flow_is_valid_idev(eth, idev)) {
struct mtk_mac *mac = netdev_priv(idev);
if (WARN_ON(mac->ppe_idx >= eth->soc->ppe_num))
return -EINVAL;
ppe_index = mac->ppe_idx;
}
}
} else {
return -EOPNOTSUPP;
}
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_CONTROL)) {
struct flow_match_control match;
flow_rule_match_control(rule, &match);
addr_type = match.key->addr_type;
if (flow_rule_has_control_flags(match.mask->flags,
f->common.extack))
return -EOPNOTSUPP;
} else {
return -EOPNOTSUPP;
}
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_BASIC)) {
struct flow_match_basic match;
flow_rule_match_basic(rule, &match);
l4proto = match.key->ip_proto;
} else {
return -EOPNOTSUPP;
}
switch (addr_type) {
case 0:
offload_type = MTK_PPE_PKT_TYPE_BRIDGE;
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
struct flow_match_eth_addrs match;
flow_rule_match_eth_addrs(rule, &match);
memcpy(data.eth.h_dest, match.key->dst, ETH_ALEN);
memcpy(data.eth.h_source, match.key->src, ETH_ALEN);
} else {
return -EOPNOTSUPP;
}
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_VLAN)) {
struct flow_match_vlan match;
flow_rule_match_vlan(rule, &match);
if (match.key->vlan_tpid != cpu_to_be16(ETH_P_8021Q))
return -EOPNOTSUPP;
data.vlan_in = match.key->vlan_id;
}
break;
case FLOW_DISSECTOR_KEY_IPV4_ADDRS:
offload_type = MTK_PPE_PKT_TYPE_IPV4_HNAPT;
break;
case FLOW_DISSECTOR_KEY_IPV6_ADDRS:
offload_type = MTK_PPE_PKT_TYPE_IPV6_ROUTE_5T;
break;
default:
return -EOPNOTSUPP;
}
flow_action_for_each(i, act, &rule->action) {
switch (act->id) {
case FLOW_ACTION_MANGLE:
if (offload_type == MTK_PPE_PKT_TYPE_BRIDGE)
return -EOPNOTSUPP;
if (act->mangle.htype == FLOW_ACT_MANGLE_HDR_TYPE_ETH)
mtk_flow_offload_mangle_eth(act, &data.eth);
break;
case FLOW_ACTION_REDIRECT:
odev = act->dev;
break;
case FLOW_ACTION_CSUM:
break;
case FLOW_ACTION_VLAN_PUSH:
if (data.vlan.num + data.pppoe.num == 2 ||
act->vlan.proto != htons(ETH_P_8021Q))
return -EOPNOTSUPP;
data.vlan.vlans[data.vlan.num].id = act->vlan.vid;
data.vlan.vlans[data.vlan.num].proto = act->vlan.proto;
data.vlan.num++;
break;
case FLOW_ACTION_VLAN_POP:
break;
case FLOW_ACTION_PPPOE_PUSH:
if (data.pppoe.num == 1 ||
data.vlan.num == 2)
return -EOPNOTSUPP;
data.pppoe.sid = act->pppoe.sid;
data.pppoe.num++;
break;
default:
return -EOPNOTSUPP;
}
}
if (!is_valid_ether_addr(data.eth.h_source) ||
!is_valid_ether_addr(data.eth.h_dest))
return -EINVAL;
err = mtk_foe_entry_prepare(eth, &foe, offload_type, l4proto, 0,
data.eth.h_source, data.eth.h_dest);
if (err)
return err;
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_PORTS)) {
struct flow_match_ports ports;
if (offload_type == MTK_PPE_PKT_TYPE_BRIDGE)
return -EOPNOTSUPP;
flow_rule_match_ports(rule, &ports);
data.src_port = ports.key->src;
data.dst_port = ports.key->dst;
} else if (offload_type != MTK_PPE_PKT_TYPE_BRIDGE) {
return -EOPNOTSUPP;
}
if (addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS) {
struct flow_match_ipv4_addrs addrs;
flow_rule_match_ipv4_addrs(rule, &addrs);
data.v4.src_addr = addrs.key->src;
data.v4.dst_addr = addrs.key->dst;
mtk_flow_set_ipv4_addr(eth, &foe, &data, false);
}
if (addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS) {
struct flow_match_ipv6_addrs addrs;
flow_rule_match_ipv6_addrs(rule, &addrs);
data.v6.src_addr = addrs.key->src;
data.v6.dst_addr = addrs.key->dst;
mtk_flow_set_ipv6_addr(eth, &foe, &data);
}
flow_action_for_each(i, act, &rule->action) {
if (act->id != FLOW_ACTION_MANGLE)
continue;
if (offload_type == MTK_PPE_PKT_TYPE_BRIDGE)
return -EOPNOTSUPP;
switch (act->mangle.htype) {
case FLOW_ACT_MANGLE_HDR_TYPE_TCP:
case FLOW_ACT_MANGLE_HDR_TYPE_UDP:
err = mtk_flow_mangle_ports(act, &data);
break;
case FLOW_ACT_MANGLE_HDR_TYPE_IP4:
err = mtk_flow_mangle_ipv4(act, &data);
break;
case FLOW_ACT_MANGLE_HDR_TYPE_ETH:
/* handled earlier */
break;
default:
return -EOPNOTSUPP;
}
if (err)
return err;
}
if (addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS) {
err = mtk_flow_set_ipv4_addr(eth, &foe, &data, true);
if (err)
return err;
}
if (offload_type == MTK_PPE_PKT_TYPE_BRIDGE)
foe.bridge.vlan = data.vlan_in;
for (i = 0; i < data.vlan.num; i++)
mtk_foe_entry_set_vlan(eth, &foe, data.vlan.vlans[i].id);
if (data.pppoe.num == 1)
mtk_foe_entry_set_pppoe(eth, &foe, data.pppoe.sid);
err = mtk_flow_set_output_device(eth, &foe, odev, data.eth.h_dest,
&wed_index);
if (err)
return err;
if (wed_index >= 0 && (err = mtk_wed_flow_add(wed_index)) < 0)
return err;
entry = kzalloc_obj(*entry);
if (!entry)
return -ENOMEM;
entry->cookie = f->cookie;
memcpy(&entry->data, &foe, sizeof(entry->data));
entry->wed_index = wed_index;
entry->ppe_index = ppe_index;
err = mtk_foe_entry_commit(eth->ppe[entry->ppe_index], entry);
if (err < 0)
goto free;
err = rhashtable_insert_fast(&eth->flow_table, &entry->node,
mtk_flow_ht_params);
if (err < 0)
goto clear;
return 0;
clear:
mtk_foe_entry_clear(eth->ppe[entry->ppe_index], entry);
free:
kfree(entry);
if (wed_index >= 0)
mtk_wed_flow_remove(wed_index);
return err;
}
static int
mtk_flow_offload_destroy(struct mtk_eth *eth, struct flow_cls_offload *f)
{
struct mtk_flow_entry *entry;
entry = rhashtable_lookup(&eth->flow_table, &f->cookie,
mtk_flow_ht_params);
if (!entry)
return -ENOENT;
mtk_foe_entry_clear(eth->ppe[entry->ppe_index], entry);
rhashtable_remove_fast(&eth->flow_table, &entry->node,
mtk_flow_ht_params);
if (entry->wed_index >= 0)
mtk_wed_flow_remove(entry->wed_index);
kfree(entry);
return 0;
}
static int
mtk_flow_offload_stats(struct mtk_eth *eth, struct flow_cls_offload *f)
{
struct mtk_flow_entry *entry;
struct mtk_foe_accounting diff;
u32 idle;
entry = rhashtable_lookup(&eth->flow_table, &f->cookie,
mtk_flow_ht_params);
if (!entry)
return -ENOENT;
idle = mtk_foe_entry_idle_time(eth->ppe[entry->ppe_index], entry);
f->stats.lastused = jiffies - idle * HZ;
if (entry->hash != 0xFFFF &&
mtk_foe_entry_get_mib(eth->ppe[entry->ppe_index], entry->hash,
&diff)) {
f->stats.pkts += diff.packets;
f->stats.bytes += diff.bytes;
}
return 0;
}
static DEFINE_MUTEX(mtk_flow_offload_mutex);
int mtk_flow_offload_cmd(struct mtk_eth *eth, struct flow_cls_offload *cls,
int ppe_index)
{
int err;
mutex_lock(&mtk_flow_offload_mutex);
switch (cls->command) {
case FLOW_CLS_REPLACE:
err = mtk_flow_offload_replace(eth, cls, ppe_index);
break;
case FLOW_CLS_DESTROY:
err = mtk_flow_offload_destroy(eth, cls);
break;
case FLOW_CLS_STATS:
err = mtk_flow_offload_stats(eth, cls);
break;
default:
err = -EOPNOTSUPP;
break;
}
mutex_unlock(&mtk_flow_offload_mutex);
return err;
}
static int
mtk_eth_setup_tc_block_cb(enum tc_setup_type type, void *type_data, void *cb_priv)
{
struct flow_cls_offload *cls = type_data;
struct net_device *dev = cb_priv;
struct mtk_mac *mac;
struct mtk_eth *eth;
mac = netdev_priv(dev);
eth = mac->hw;
if (!tc_can_offload(dev))
return -EOPNOTSUPP;
if (type != TC_SETUP_CLSFLOWER)
return -EOPNOTSUPP;
return mtk_flow_offload_cmd(eth, cls, 0);
}
static int
mtk_eth_setup_tc_block(struct net_device *dev, struct flow_block_offload *f)
{
struct mtk_mac *mac = netdev_priv(dev);
struct mtk_eth *eth = mac->hw;
static LIST_HEAD(block_cb_list);
struct flow_block_cb *block_cb;
flow_setup_cb_t *cb;
if (!eth->soc->offload_version)
return -EOPNOTSUPP;
if (f->binder_type != FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
return -EOPNOTSUPP;
cb = mtk_eth_setup_tc_block_cb;
f->driver_block_list = &block_cb_list;
switch (f->command) {
case FLOW_BLOCK_BIND:
block_cb = flow_block_cb_lookup(f->block, cb, dev);
if (block_cb) {
flow_block_cb_incref(block_cb);
return 0;
}
block_cb = flow_block_cb_alloc(cb, dev, dev, NULL);
if (IS_ERR(block_cb))
return PTR_ERR(block_cb);
flow_block_cb_incref(block_cb);
flow_block_cb_add(block_cb, f);
list_add_tail(&block_cb->driver_list, &block_cb_list);
return 0;
case FLOW_BLOCK_UNBIND:
block_cb = flow_block_cb_lookup(f->block, cb, dev);
if (!block_cb)
return -ENOENT;
if (!flow_block_cb_decref(block_cb)) {
flow_block_cb_remove(block_cb, f);
list_del(&block_cb->driver_list);
}
return 0;
default:
return -EOPNOTSUPP;
}
}
int mtk_eth_setup_tc(struct net_device *dev, enum tc_setup_type type,
void *type_data)
{
switch (type) {
case TC_SETUP_BLOCK:
case TC_SETUP_FT:
return mtk_eth_setup_tc_block(dev, type_data);
default:
return -EOPNOTSUPP;
}
}
int mtk_eth_offload_init(struct mtk_eth *eth, u8 id)
{
if (!eth->ppe[id] || !eth->ppe[id]->foe_table)
return 0;
return rhashtable_init(&eth->flow_table, &mtk_flow_ht_params);
}
@@ -0,0 +1,174 @@
// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (C) 2020 Felix Fietkau <nbd@nbd.name> */
#ifndef __MTK_PPE_REGS_H
#define __MTK_PPE_REGS_H
#define MTK_PPE_GLO_CFG 0x200
#define MTK_PPE_GLO_CFG_EN BIT(0)
#define MTK_PPE_GLO_CFG_TSID_EN BIT(1)
#define MTK_PPE_GLO_CFG_IP4_L4_CS_DROP BIT(2)
#define MTK_PPE_GLO_CFG_IP4_CS_DROP BIT(3)
#define MTK_PPE_GLO_CFG_TTL0_DROP BIT(4)
#define MTK_PPE_GLO_CFG_PPE_BSWAP BIT(5)
#define MTK_PPE_GLO_CFG_PSE_HASH_OFS BIT(6)
#define MTK_PPE_GLO_CFG_MCAST_TB_EN BIT(7)
#define MTK_PPE_GLO_CFG_FLOW_DROP_KA BIT(8)
#define MTK_PPE_GLO_CFG_FLOW_DROP_UPDATE BIT(9)
#define MTK_PPE_GLO_CFG_UDP_LITE_EN BIT(10)
#define MTK_PPE_GLO_CFG_UDP_LEN_DROP BIT(11)
#define MTK_PPE_GLO_CFG_MCAST_ENTRIES GNEMASK(13, 12)
#define MTK_PPE_GLO_CFG_BUSY BIT(31)
#define MTK_PPE_FLOW_CFG 0x204
#define MTK_PPE_MD_TOAP_BYP_CRSN0 BIT(1)
#define MTK_PPE_MD_TOAP_BYP_CRSN1 BIT(2)
#define MTK_PPE_MD_TOAP_BYP_CRSN2 BIT(3)
#define MTK_PPE_FLOW_CFG_IP4_TCP_FRAG BIT(6)
#define MTK_PPE_FLOW_CFG_IP4_UDP_FRAG BIT(7)
#define MTK_PPE_FLOW_CFG_IP6_3T_ROUTE BIT(8)
#define MTK_PPE_FLOW_CFG_IP6_5T_ROUTE BIT(9)
#define MTK_PPE_FLOW_CFG_IP6_6RD BIT(10)
#define MTK_PPE_FLOW_CFG_IP4_NAT BIT(12)
#define MTK_PPE_FLOW_CFG_IP4_NAPT BIT(13)
#define MTK_PPE_FLOW_CFG_IP4_DSLITE BIT(14)
#define MTK_PPE_FLOW_CFG_L2_BRIDGE BIT(15)
#define MTK_PPE_FLOW_CFG_IP_PROTO_BLACKLIST BIT(16)
#define MTK_PPE_FLOW_CFG_IP4_NAT_FRAG BIT(17)
#define MTK_PPE_FLOW_CFG_IP4_HASH_FLOW_LABEL BIT(18)
#define MTK_PPE_FLOW_CFG_IP4_HASH_GRE_KEY BIT(19)
#define MTK_PPE_FLOW_CFG_IP6_HASH_GRE_KEY BIT(20)
#define MTK_PPE_IP_PROTO_CHK 0x208
#define MTK_PPE_IP_PROTO_CHK_IPV4 GENMASK(15, 0)
#define MTK_PPE_IP_PROTO_CHK_IPV6 GENMASK(31, 16)
#define MTK_PPE_TB_CFG 0x21c
#define MTK_PPE_TB_CFG_ENTRY_NUM GENMASK(2, 0)
#define MTK_PPE_TB_CFG_ENTRY_80B BIT(3)
#define MTK_PPE_TB_CFG_SEARCH_MISS GENMASK(5, 4)
#define MTK_PPE_TB_CFG_AGE_PREBIND BIT(6)
#define MTK_PPE_TB_CFG_AGE_NON_L4 BIT(7)
#define MTK_PPE_TB_CFG_AGE_UNBIND BIT(8)
#define MTK_PPE_TB_CFG_AGE_TCP BIT(9)
#define MTK_PPE_TB_CFG_AGE_UDP BIT(10)
#define MTK_PPE_TB_CFG_AGE_TCP_FIN BIT(11)
#define MTK_PPE_TB_CFG_KEEPALIVE GENMASK(13, 12)
#define MTK_PPE_TB_CFG_HASH_MODE GENMASK(15, 14)
#define MTK_PPE_TB_CFG_SCAN_MODE GENMASK(17, 16)
#define MTK_PPE_TB_CFG_HASH_DEBUG GENMASK(19, 18)
#define MTK_PPE_TB_CFG_INFO_SEL BIT(20)
#define MTK_PPE_TB_TICK_SEL BIT(24)
#define MTK_PPE_BIND_LMT1 0x230
#define MTK_PPE_NTU_KEEPALIVE GENMASK(23, 16)
#define MTK_PPE_KEEPALIVE 0x234
enum {
MTK_PPE_SCAN_MODE_DISABLED,
MTK_PPE_SCAN_MODE_CHECK_AGE,
MTK_PPE_SCAN_MODE_KEEPALIVE_AGE,
};
enum {
MTK_PPE_KEEPALIVE_DISABLE,
MTK_PPE_KEEPALIVE_UNICAST_CPU,
MTK_PPE_KEEPALIVE_DUP_CPU = 3,
};
enum {
MTK_PPE_SEARCH_MISS_ACTION_DROP,
MTK_PPE_SEARCH_MISS_ACTION_FORWARD = 2,
MTK_PPE_SEARCH_MISS_ACTION_FORWARD_BUILD = 3,
};
#define MTK_PPE_TB_BASE 0x220
#define MTK_PPE_TB_USED 0x224
#define MTK_PPE_TB_USED_NUM GENMASK(13, 0)
#define MTK_PPE_BIND_RATE 0x228
#define MTK_PPE_BIND_RATE_BIND GENMASK(15, 0)
#define MTK_PPE_BIND_RATE_PREBIND GENMASK(31, 16)
#define MTK_PPE_BIND_LIMIT0 0x22c
#define MTK_PPE_BIND_LIMIT0_QUARTER GENMASK(13, 0)
#define MTK_PPE_BIND_LIMIT0_HALF GENMASK(29, 16)
#define MTK_PPE_BIND_LIMIT1 0x230
#define MTK_PPE_BIND_LIMIT1_FULL GENMASK(13, 0)
#define MTK_PPE_BIND_LIMIT1_NON_L4 GENMASK(23, 16)
#define MTK_PPE_KEEPALIVE 0x234
#define MTK_PPE_KEEPALIVE_TIME GENMASK(15, 0)
#define MTK_PPE_KEEPALIVE_TIME_TCP GENMASK(23, 16)
#define MTK_PPE_KEEPALIVE_TIME_UDP GENMASK(31, 24)
#define MTK_PPE_UNBIND_AGE 0x238
#define MTK_PPE_UNBIND_AGE_MIN_PACKETS GENMASK(31, 16)
#define MTK_PPE_UNBIND_AGE_DELTA GENMASK(7, 0)
#define MTK_PPE_BIND_AGE0 0x23c
#define MTK_PPE_BIND_AGE0_DELTA_NON_L4 GENMASK(30, 16)
#define MTK_PPE_BIND_AGE0_DELTA_UDP GENMASK(14, 0)
#define MTK_PPE_BIND_AGE1 0x240
#define MTK_PPE_BIND_AGE1_DELTA_TCP_FIN GENMASK(30, 16)
#define MTK_PPE_BIND_AGE1_DELTA_TCP GENMASK(14, 0)
#define MTK_PPE_HASH_SEED 0x244
#define MTK_PPE_DEFAULT_CPU_PORT 0x248
#define MTK_PPE_DEFAULT_CPU_PORT_MASK(_n) (GENMASK(2, 0) << ((_n) * 4))
#define MTK_PPE_DEFAULT_CPU_PORT1 0x24c
#define MTK_PPE_MTU_DROP 0x308
#define MTK_PPE_VLAN_MTU0 0x30c
#define MTK_PPE_VLAN_MTU0_NONE GENMASK(13, 0)
#define MTK_PPE_VLAN_MTU0_1TAG GENMASK(29, 16)
#define MTK_PPE_VLAN_MTU1 0x310
#define MTK_PPE_VLAN_MTU1_2TAG GENMASK(13, 0)
#define MTK_PPE_VLAN_MTU1_3TAG GENMASK(29, 16)
#define MTK_PPE_VPM_TPID 0x318
#define MTK_PPE_CACHE_CTL 0x320
#define MTK_PPE_CACHE_CTL_EN BIT(0)
#define MTK_PPE_CACHE_CTL_LOCK_CLR BIT(4)
#define MTK_PPE_CACHE_CTL_REQ BIT(8)
#define MTK_PPE_CACHE_CTL_CLEAR BIT(9)
#define MTK_PPE_CACHE_CTL_CMD GENMASK(13, 12)
#define MTK_PPE_MIB_CFG 0x334
#define MTK_PPE_MIB_CFG_EN BIT(0)
#define MTK_PPE_MIB_CFG_RD_CLR BIT(1)
#define MTK_PPE_MIB_TB_BASE 0x338
#define MTK_PPE_MIB_SER_CR 0x33C
#define MTK_PPE_MIB_SER_CR_ST BIT(16)
#define MTK_PPE_MIB_SER_CR_ADDR GENMASK(13, 0)
#define MTK_PPE_MIB_SER_R0 0x340
#define MTK_PPE_MIB_SER_R0_BYTE_CNT_LOW GENMASK(31, 0)
#define MTK_PPE_MIB_SER_R1 0x344
#define MTK_PPE_MIB_SER_R1_PKT_CNT_LOW GENMASK(31, 16)
#define MTK_PPE_MIB_SER_R1_BYTE_CNT_HIGH GENMASK(15, 0)
#define MTK_PPE_MIB_SER_R2 0x348
#define MTK_PPE_MIB_SER_R2_PKT_CNT_HIGH GENMASK(23, 0)
#define MTK_PPE_MIB_SER_R3 0x34c
#define MTK_PPE_MIB_CACHE_CTL 0x350
#define MTK_PPE_MIB_CACHE_CTL_EN BIT(0)
#define MTK_PPE_MIB_CACHE_CTL_FLUSH BIT(2)
#define MTK_PPE_SBW_CTRL 0x374
#endif
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,226 @@
// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (C) 2021 Felix Fietkau <nbd@nbd.name> */
#ifndef __MTK_WED_PRIV_H
#define __MTK_WED_PRIV_H
#include <linux/soc/mediatek/mtk_wed.h>
#include <linux/debugfs.h>
#include <linux/regmap.h>
#include <linux/netdevice.h>
#include "mtk_wed_regs.h"
struct mtk_eth;
struct mtk_wed_wo;
struct mtk_wed_soc_data {
struct {
u32 tx_bm_tkid;
u32 wpdma_rx_ring[MTK_WED_RX_QUEUES];
u32 reset_idx_tx_mask;
u32 reset_idx_rx_mask;
} regmap;
u32 tx_ring_desc_size;
u32 wdma_desc_size;
};
struct mtk_wed_amsdu {
void *txd;
dma_addr_t txd_phy;
};
struct mtk_wed_hw {
const struct mtk_wed_soc_data *soc;
struct device_node *node;
struct mtk_eth *eth;
struct regmap *regs;
struct regmap *hifsys;
struct device *dev;
void __iomem *wdma;
phys_addr_t wdma_phy;
struct regmap *mirror;
struct dentry *debugfs_dir;
struct mtk_wed_device *wed_dev;
struct mtk_wed_wo *wed_wo;
struct mtk_wed_amsdu *wed_amsdu;
u32 pcie_base;
u32 debugfs_reg;
u32 num_flows;
u8 version;
char dirname[5];
int irq;
int index;
};
struct mtk_wdma_info {
u8 wdma_idx;
u8 queue;
u16 wcid;
u8 bss;
u8 amsdu;
};
#ifdef CONFIG_NET_MEDIATEK_SOC_WED
static inline bool mtk_wed_is_v1(struct mtk_wed_hw *hw)
{
return hw->version == 1;
}
static inline bool mtk_wed_is_v2(struct mtk_wed_hw *hw)
{
return hw->version == 2;
}
static inline bool mtk_wed_is_v3(struct mtk_wed_hw *hw)
{
return hw->version == 3;
}
static inline bool mtk_wed_is_v3_or_greater(struct mtk_wed_hw *hw)
{
return hw->version > 2;
}
static inline void
wed_w32(struct mtk_wed_device *dev, u32 reg, u32 val)
{
regmap_write(dev->hw->regs, reg, val);
}
static inline u32
wed_r32(struct mtk_wed_device *dev, u32 reg)
{
unsigned int val;
regmap_read(dev->hw->regs, reg, &val);
return val;
}
static inline void
wdma_w32(struct mtk_wed_device *dev, u32 reg, u32 val)
{
writel(val, dev->hw->wdma + reg);
}
static inline u32
wdma_r32(struct mtk_wed_device *dev, u32 reg)
{
return readl(dev->hw->wdma + reg);
}
static inline u32
wpdma_tx_r32(struct mtk_wed_device *dev, int ring, u32 reg)
{
if (!dev->tx_ring[ring].wpdma)
return 0;
return readl(dev->tx_ring[ring].wpdma + reg);
}
static inline void
wpdma_tx_w32(struct mtk_wed_device *dev, int ring, u32 reg, u32 val)
{
if (!dev->tx_ring[ring].wpdma)
return;
writel(val, dev->tx_ring[ring].wpdma + reg);
}
static inline u32
wpdma_rx_r32(struct mtk_wed_device *dev, int ring, u32 reg)
{
if (!dev->rx_ring[ring].wpdma)
return 0;
return readl(dev->rx_ring[ring].wpdma + reg);
}
static inline void
wpdma_rx_w32(struct mtk_wed_device *dev, int ring, u32 reg, u32 val)
{
if (!dev->rx_ring[ring].wpdma)
return;
writel(val, dev->rx_ring[ring].wpdma + reg);
}
static inline u32
wpdma_txfree_r32(struct mtk_wed_device *dev, u32 reg)
{
if (!dev->txfree_ring.wpdma)
return 0;
return readl(dev->txfree_ring.wpdma + reg);
}
static inline void
wpdma_txfree_w32(struct mtk_wed_device *dev, u32 reg, u32 val)
{
if (!dev->txfree_ring.wpdma)
return;
writel(val, dev->txfree_ring.wpdma + reg);
}
static inline u32 mtk_wed_get_pcie_base(struct mtk_wed_device *dev)
{
if (!mtk_wed_is_v3_or_greater(dev->hw))
return MTK_WED_PCIE_BASE;
switch (dev->hw->index) {
case 1:
return MTK_WED_PCIE_BASE1;
case 2:
return MTK_WED_PCIE_BASE2;
default:
return MTK_WED_PCIE_BASE0;
}
}
void mtk_wed_add_hw(struct device_node *np, struct mtk_eth *eth,
void __iomem *wdma, phys_addr_t wdma_phy,
int index);
void mtk_wed_exit(void);
int mtk_wed_flow_add(int index);
void mtk_wed_flow_remove(int index);
void mtk_wed_fe_reset(void);
void mtk_wed_fe_reset_complete(void);
#else
static inline void
mtk_wed_add_hw(struct device_node *np, struct mtk_eth *eth,
void __iomem *wdma, phys_addr_t wdma_phy,
int index)
{
}
static inline void
mtk_wed_exit(void)
{
}
static inline int mtk_wed_flow_add(int index)
{
return -EINVAL;
}
static inline void mtk_wed_flow_remove(int index)
{
}
static inline void mtk_wed_fe_reset(void)
{
}
static inline void mtk_wed_fe_reset_complete(void)
{
}
#endif
#ifdef CONFIG_DEBUG_FS
void mtk_wed_hw_add_debugfs(struct mtk_wed_hw *hw);
#else
static inline void mtk_wed_hw_add_debugfs(struct mtk_wed_hw *hw)
{
}
#endif
#endif
@@ -0,0 +1,637 @@
// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (C) 2021 Felix Fietkau <nbd@nbd.name> */
#include <linux/seq_file.h>
#include <linux/soc/mediatek/mtk_wed.h>
#include "mtk_wed.h"
#include "mtk_wed_regs.h"
struct reg_dump {
const char *name;
u16 offset;
u8 type;
u8 base;
u32 mask;
};
enum {
DUMP_TYPE_STRING,
DUMP_TYPE_WED,
DUMP_TYPE_WDMA,
DUMP_TYPE_WPDMA_TX,
DUMP_TYPE_WPDMA_TXFREE,
DUMP_TYPE_WPDMA_RX,
DUMP_TYPE_WED_RRO,
};
#define DUMP_STR(_str) { _str, 0, DUMP_TYPE_STRING }
#define DUMP_REG(_reg, ...) { #_reg, MTK_##_reg, __VA_ARGS__ }
#define DUMP_REG_MASK(_reg, _mask) \
{ #_mask, MTK_##_reg, DUMP_TYPE_WED, 0, MTK_##_mask }
#define DUMP_RING(_prefix, _base, ...) \
{ _prefix " BASE", _base, __VA_ARGS__ }, \
{ _prefix " CNT", _base + 0x4, __VA_ARGS__ }, \
{ _prefix " CIDX", _base + 0x8, __VA_ARGS__ }, \
{ _prefix " DIDX", _base + 0xc, __VA_ARGS__ }
#define DUMP_WED(_reg) DUMP_REG(_reg, DUMP_TYPE_WED)
#define DUMP_WED_MASK(_reg, _mask) DUMP_REG_MASK(_reg, _mask)
#define DUMP_WED_RING(_base) DUMP_RING(#_base, MTK_##_base, DUMP_TYPE_WED)
#define DUMP_WDMA(_reg) DUMP_REG(_reg, DUMP_TYPE_WDMA)
#define DUMP_WDMA_RING(_base) DUMP_RING(#_base, MTK_##_base, DUMP_TYPE_WDMA)
#define DUMP_WPDMA_TX_RING(_n) DUMP_RING("WPDMA_TX" #_n, 0, DUMP_TYPE_WPDMA_TX, _n)
#define DUMP_WPDMA_TXFREE_RING DUMP_RING("WPDMA_RX1", 0, DUMP_TYPE_WPDMA_TXFREE)
#define DUMP_WPDMA_RX_RING(_n) DUMP_RING("WPDMA_RX" #_n, 0, DUMP_TYPE_WPDMA_RX, _n)
#define DUMP_WED_RRO_RING(_base)DUMP_RING("WED_RRO_MIOD", MTK_##_base, DUMP_TYPE_WED_RRO)
#define DUMP_WED_RRO_FDBK(_base)DUMP_RING("WED_RRO_FDBK", MTK_##_base, DUMP_TYPE_WED_RRO)
static void
print_reg_val(struct seq_file *s, const char *name, u32 val)
{
seq_printf(s, "%-32s %08x\n", name, val);
}
static void
dump_wed_regs(struct seq_file *s, struct mtk_wed_device *dev,
const struct reg_dump *regs, int n_regs)
{
const struct reg_dump *cur;
u32 val;
for (cur = regs; cur < &regs[n_regs]; cur++) {
switch (cur->type) {
case DUMP_TYPE_STRING:
seq_printf(s, "%s======== %s:\n",
cur > regs ? "\n" : "",
cur->name);
continue;
case DUMP_TYPE_WED_RRO:
case DUMP_TYPE_WED:
val = wed_r32(dev, cur->offset);
break;
case DUMP_TYPE_WDMA:
val = wdma_r32(dev, cur->offset);
break;
case DUMP_TYPE_WPDMA_TX:
val = wpdma_tx_r32(dev, cur->base, cur->offset);
break;
case DUMP_TYPE_WPDMA_TXFREE:
val = wpdma_txfree_r32(dev, cur->offset);
break;
case DUMP_TYPE_WPDMA_RX:
val = wpdma_rx_r32(dev, cur->base, cur->offset);
break;
}
print_reg_val(s, cur->name, val);
}
}
static int
wed_txinfo_show(struct seq_file *s, void *data)
{
static const struct reg_dump regs[] = {
DUMP_STR("WED TX"),
DUMP_WED(WED_TX_MIB(0)),
DUMP_WED_RING(WED_RING_TX(0)),
DUMP_WED(WED_TX_MIB(1)),
DUMP_WED_RING(WED_RING_TX(1)),
DUMP_STR("WPDMA TX"),
DUMP_WED(WED_WPDMA_TX_MIB(0)),
DUMP_WED_RING(WED_WPDMA_RING_TX(0)),
DUMP_WED(WED_WPDMA_TX_COHERENT_MIB(0)),
DUMP_WED(WED_WPDMA_TX_MIB(1)),
DUMP_WED_RING(WED_WPDMA_RING_TX(1)),
DUMP_WED(WED_WPDMA_TX_COHERENT_MIB(1)),
DUMP_STR("WPDMA TX"),
DUMP_WPDMA_TX_RING(0),
DUMP_WPDMA_TX_RING(1),
DUMP_STR("WED WDMA RX"),
DUMP_WED(WED_WDMA_RX_MIB(0)),
DUMP_WED_RING(WED_WDMA_RING_RX(0)),
DUMP_WED(WED_WDMA_RX_THRES(0)),
DUMP_WED(WED_WDMA_RX_RECYCLE_MIB(0)),
DUMP_WED(WED_WDMA_RX_PROCESSED_MIB(0)),
DUMP_WED(WED_WDMA_RX_MIB(1)),
DUMP_WED_RING(WED_WDMA_RING_RX(1)),
DUMP_WED(WED_WDMA_RX_THRES(1)),
DUMP_WED(WED_WDMA_RX_RECYCLE_MIB(1)),
DUMP_WED(WED_WDMA_RX_PROCESSED_MIB(1)),
DUMP_STR("WDMA RX"),
DUMP_WDMA(WDMA_GLO_CFG),
DUMP_WDMA_RING(WDMA_RING_RX(0)),
DUMP_WDMA_RING(WDMA_RING_RX(1)),
DUMP_STR("WED TX FREE"),
DUMP_WED(WED_RX_MIB(0)),
DUMP_WED_RING(WED_RING_RX(0)),
DUMP_WED(WED_WPDMA_RX_COHERENT_MIB(0)),
DUMP_WED(WED_RX_MIB(1)),
DUMP_WED_RING(WED_RING_RX(1)),
DUMP_WED(WED_WPDMA_RX_COHERENT_MIB(1)),
DUMP_STR("WED WPDMA TX FREE"),
DUMP_WED_RING(WED_WPDMA_RING_RX(0)),
DUMP_WED_RING(WED_WPDMA_RING_RX(1)),
};
struct mtk_wed_hw *hw = s->private;
struct mtk_wed_device *dev = hw->wed_dev;
if (dev)
dump_wed_regs(s, dev, regs, ARRAY_SIZE(regs));
return 0;
}
DEFINE_SHOW_ATTRIBUTE(wed_txinfo);
static int
wed_rxinfo_show(struct seq_file *s, void *data)
{
static const struct reg_dump regs_common[] = {
DUMP_STR("WPDMA RX"),
DUMP_WPDMA_RX_RING(0),
DUMP_WPDMA_RX_RING(1),
DUMP_STR("WPDMA RX"),
DUMP_WED(WED_WPDMA_RX_D_MIB(0)),
DUMP_WED_RING(WED_WPDMA_RING_RX_DATA(0)),
DUMP_WED(WED_WPDMA_RX_D_PROCESSED_MIB(0)),
DUMP_WED(WED_WPDMA_RX_D_MIB(1)),
DUMP_WED_RING(WED_WPDMA_RING_RX_DATA(1)),
DUMP_WED(WED_WPDMA_RX_D_PROCESSED_MIB(1)),
DUMP_WED(WED_WPDMA_RX_D_COHERENT_MIB),
DUMP_STR("WED RX"),
DUMP_WED_RING(WED_RING_RX_DATA(0)),
DUMP_WED_RING(WED_RING_RX_DATA(1)),
DUMP_STR("WED WO RRO"),
DUMP_WED_RRO_RING(WED_RROQM_MIOD_CTRL0),
DUMP_WED(WED_RROQM_MID_MIB),
DUMP_WED(WED_RROQM_MOD_MIB),
DUMP_WED(WED_RROQM_MOD_COHERENT_MIB),
DUMP_WED_RRO_FDBK(WED_RROQM_FDBK_CTRL0),
DUMP_WED(WED_RROQM_FDBK_IND_MIB),
DUMP_WED(WED_RROQM_FDBK_ENQ_MIB),
DUMP_WED(WED_RROQM_FDBK_ANC_MIB),
DUMP_WED(WED_RROQM_FDBK_ANC2H_MIB),
DUMP_STR("WED WDMA TX"),
DUMP_WED(WED_WDMA_TX_MIB),
DUMP_WED_RING(WED_WDMA_RING_TX),
DUMP_STR("WDMA TX"),
DUMP_WDMA(WDMA_GLO_CFG),
DUMP_WDMA_RING(WDMA_RING_TX(0)),
DUMP_WDMA_RING(WDMA_RING_TX(1)),
DUMP_STR("WED RX BM"),
DUMP_WED(WED_RX_BM_BASE),
DUMP_WED(WED_RX_BM_RX_DMAD),
DUMP_WED(WED_RX_BM_PTR),
DUMP_WED(WED_RX_BM_TKID_MIB),
DUMP_WED(WED_RX_BM_BLEN),
DUMP_WED(WED_RX_BM_STS),
DUMP_WED(WED_RX_BM_INTF2),
DUMP_WED(WED_RX_BM_INTF),
DUMP_WED(WED_RX_BM_ERR_STS),
};
static const struct reg_dump regs_wed_v2[] = {
DUMP_STR("WED Route QM"),
DUMP_WED(WED_RTQM_R2H_MIB(0)),
DUMP_WED(WED_RTQM_R2Q_MIB(0)),
DUMP_WED(WED_RTQM_Q2H_MIB(0)),
DUMP_WED(WED_RTQM_R2H_MIB(1)),
DUMP_WED(WED_RTQM_R2Q_MIB(1)),
DUMP_WED(WED_RTQM_Q2H_MIB(1)),
DUMP_WED(WED_RTQM_Q2N_MIB),
DUMP_WED(WED_RTQM_Q2B_MIB),
DUMP_WED(WED_RTQM_PFDBK_MIB),
};
static const struct reg_dump regs_wed_v3[] = {
DUMP_STR("WED RX RRO DATA"),
DUMP_WED_RING(WED_RRO_RX_D_RX(0)),
DUMP_WED_RING(WED_RRO_RX_D_RX(1)),
DUMP_STR("WED RX MSDU PAGE"),
DUMP_WED_RING(WED_RRO_MSDU_PG_CTRL0(0)),
DUMP_WED_RING(WED_RRO_MSDU_PG_CTRL0(1)),
DUMP_WED_RING(WED_RRO_MSDU_PG_CTRL0(2)),
DUMP_STR("WED RX IND CMD"),
DUMP_WED(WED_IND_CMD_RX_CTRL1),
DUMP_WED_MASK(WED_IND_CMD_RX_CTRL2, WED_IND_CMD_MAX_CNT),
DUMP_WED_MASK(WED_IND_CMD_RX_CTRL0, WED_IND_CMD_PROC_IDX),
DUMP_WED_MASK(RRO_IND_CMD_SIGNATURE, RRO_IND_CMD_DMA_IDX),
DUMP_WED_MASK(WED_IND_CMD_RX_CTRL0, WED_IND_CMD_MAGIC_CNT),
DUMP_WED_MASK(RRO_IND_CMD_SIGNATURE, RRO_IND_CMD_MAGIC_CNT),
DUMP_WED_MASK(WED_IND_CMD_RX_CTRL0,
WED_IND_CMD_PREFETCH_FREE_CNT),
DUMP_WED_MASK(WED_RRO_CFG1, WED_RRO_CFG1_PARTICL_SE_ID),
DUMP_STR("WED ADDR ELEM"),
DUMP_WED(WED_ADDR_ELEM_CFG0),
DUMP_WED_MASK(WED_ADDR_ELEM_CFG1,
WED_ADDR_ELEM_PREFETCH_FREE_CNT),
DUMP_STR("WED Route QM"),
DUMP_WED(WED_RTQM_ENQ_I2Q_DMAD_CNT),
DUMP_WED(WED_RTQM_ENQ_I2N_DMAD_CNT),
DUMP_WED(WED_RTQM_ENQ_I2Q_PKT_CNT),
DUMP_WED(WED_RTQM_ENQ_I2N_PKT_CNT),
DUMP_WED(WED_RTQM_ENQ_USED_ENTRY_CNT),
DUMP_WED(WED_RTQM_ENQ_ERR_CNT),
DUMP_WED(WED_RTQM_DEQ_DMAD_CNT),
DUMP_WED(WED_RTQM_DEQ_Q2I_DMAD_CNT),
DUMP_WED(WED_RTQM_DEQ_PKT_CNT),
DUMP_WED(WED_RTQM_DEQ_Q2I_PKT_CNT),
DUMP_WED(WED_RTQM_DEQ_USED_PFDBK_CNT),
DUMP_WED(WED_RTQM_DEQ_ERR_CNT),
};
struct mtk_wed_hw *hw = s->private;
struct mtk_wed_device *dev = hw->wed_dev;
if (dev) {
dump_wed_regs(s, dev, regs_common, ARRAY_SIZE(regs_common));
if (mtk_wed_is_v2(hw))
dump_wed_regs(s, dev,
regs_wed_v2, ARRAY_SIZE(regs_wed_v2));
else
dump_wed_regs(s, dev,
regs_wed_v3, ARRAY_SIZE(regs_wed_v3));
}
return 0;
}
DEFINE_SHOW_ATTRIBUTE(wed_rxinfo);
static int
wed_amsdu_show(struct seq_file *s, void *data)
{
static const struct reg_dump regs[] = {
DUMP_STR("WED AMDSU INFO"),
DUMP_WED(WED_MON_AMSDU_FIFO_DMAD),
DUMP_STR("WED AMDSU ENG0 INFO"),
DUMP_WED(WED_MON_AMSDU_ENG_DMAD(0)),
DUMP_WED(WED_MON_AMSDU_ENG_QFPL(0)),
DUMP_WED(WED_MON_AMSDU_ENG_QENI(0)),
DUMP_WED(WED_MON_AMSDU_ENG_QENO(0)),
DUMP_WED(WED_MON_AMSDU_ENG_MERG(0)),
DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT8(0),
WED_AMSDU_ENG_MAX_PL_CNT),
DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT8(0),
WED_AMSDU_ENG_MAX_QGPP_CNT),
DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(0),
WED_AMSDU_ENG_CUR_ENTRY),
DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(0),
WED_AMSDU_ENG_MAX_BUF_MERGED),
DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(0),
WED_AMSDU_ENG_MAX_MSDU_MERGED),
DUMP_STR("WED AMDSU ENG1 INFO"),
DUMP_WED(WED_MON_AMSDU_ENG_DMAD(1)),
DUMP_WED(WED_MON_AMSDU_ENG_QFPL(1)),
DUMP_WED(WED_MON_AMSDU_ENG_QENI(1)),
DUMP_WED(WED_MON_AMSDU_ENG_QENO(1)),
DUMP_WED(WED_MON_AMSDU_ENG_MERG(1)),
DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT8(1),
WED_AMSDU_ENG_MAX_PL_CNT),
DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT8(1),
WED_AMSDU_ENG_MAX_QGPP_CNT),
DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(1),
WED_AMSDU_ENG_CUR_ENTRY),
DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(1),
WED_AMSDU_ENG_MAX_BUF_MERGED),
DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(1),
WED_AMSDU_ENG_MAX_MSDU_MERGED),
DUMP_STR("WED AMDSU ENG2 INFO"),
DUMP_WED(WED_MON_AMSDU_ENG_DMAD(2)),
DUMP_WED(WED_MON_AMSDU_ENG_QFPL(2)),
DUMP_WED(WED_MON_AMSDU_ENG_QENI(2)),
DUMP_WED(WED_MON_AMSDU_ENG_QENO(2)),
DUMP_WED(WED_MON_AMSDU_ENG_MERG(2)),
DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT8(2),
WED_AMSDU_ENG_MAX_PL_CNT),
DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT8(2),
WED_AMSDU_ENG_MAX_QGPP_CNT),
DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(2),
WED_AMSDU_ENG_CUR_ENTRY),
DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(2),
WED_AMSDU_ENG_MAX_BUF_MERGED),
DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(2),
WED_AMSDU_ENG_MAX_MSDU_MERGED),
DUMP_STR("WED AMDSU ENG3 INFO"),
DUMP_WED(WED_MON_AMSDU_ENG_DMAD(3)),
DUMP_WED(WED_MON_AMSDU_ENG_QFPL(3)),
DUMP_WED(WED_MON_AMSDU_ENG_QENI(3)),
DUMP_WED(WED_MON_AMSDU_ENG_QENO(3)),
DUMP_WED(WED_MON_AMSDU_ENG_MERG(3)),
DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT8(3),
WED_AMSDU_ENG_MAX_PL_CNT),
DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT8(3),
WED_AMSDU_ENG_MAX_QGPP_CNT),
DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(3),
WED_AMSDU_ENG_CUR_ENTRY),
DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(3),
WED_AMSDU_ENG_MAX_BUF_MERGED),
DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(3),
WED_AMSDU_ENG_MAX_MSDU_MERGED),
DUMP_STR("WED AMDSU ENG4 INFO"),
DUMP_WED(WED_MON_AMSDU_ENG_DMAD(4)),
DUMP_WED(WED_MON_AMSDU_ENG_QFPL(4)),
DUMP_WED(WED_MON_AMSDU_ENG_QENI(4)),
DUMP_WED(WED_MON_AMSDU_ENG_QENO(4)),
DUMP_WED(WED_MON_AMSDU_ENG_MERG(4)),
DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT8(4),
WED_AMSDU_ENG_MAX_PL_CNT),
DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT8(4),
WED_AMSDU_ENG_MAX_QGPP_CNT),
DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(4),
WED_AMSDU_ENG_CUR_ENTRY),
DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(4),
WED_AMSDU_ENG_MAX_BUF_MERGED),
DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(4),
WED_AMSDU_ENG_MAX_MSDU_MERGED),
DUMP_STR("WED AMDSU ENG5 INFO"),
DUMP_WED(WED_MON_AMSDU_ENG_DMAD(5)),
DUMP_WED(WED_MON_AMSDU_ENG_QFPL(5)),
DUMP_WED(WED_MON_AMSDU_ENG_QENI(5)),
DUMP_WED(WED_MON_AMSDU_ENG_QENO(5)),
DUMP_WED(WED_MON_AMSDU_ENG_MERG(5)),
DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT8(5),
WED_AMSDU_ENG_MAX_PL_CNT),
DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT8(5),
WED_AMSDU_ENG_MAX_QGPP_CNT),
DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(5),
WED_AMSDU_ENG_CUR_ENTRY),
DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(5),
WED_AMSDU_ENG_MAX_BUF_MERGED),
DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(5),
WED_AMSDU_ENG_MAX_MSDU_MERGED),
DUMP_STR("WED AMDSU ENG6 INFO"),
DUMP_WED(WED_MON_AMSDU_ENG_DMAD(6)),
DUMP_WED(WED_MON_AMSDU_ENG_QFPL(6)),
DUMP_WED(WED_MON_AMSDU_ENG_QENI(6)),
DUMP_WED(WED_MON_AMSDU_ENG_QENO(6)),
DUMP_WED(WED_MON_AMSDU_ENG_MERG(6)),
DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT8(6),
WED_AMSDU_ENG_MAX_PL_CNT),
DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT8(6),
WED_AMSDU_ENG_MAX_QGPP_CNT),
DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(6),
WED_AMSDU_ENG_CUR_ENTRY),
DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(6),
WED_AMSDU_ENG_MAX_BUF_MERGED),
DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(6),
WED_AMSDU_ENG_MAX_MSDU_MERGED),
DUMP_STR("WED AMDSU ENG7 INFO"),
DUMP_WED(WED_MON_AMSDU_ENG_DMAD(7)),
DUMP_WED(WED_MON_AMSDU_ENG_QFPL(7)),
DUMP_WED(WED_MON_AMSDU_ENG_QENI(7)),
DUMP_WED(WED_MON_AMSDU_ENG_QENO(7)),
DUMP_WED(WED_MON_AMSDU_ENG_MERG(7)),
DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT8(7),
WED_AMSDU_ENG_MAX_PL_CNT),
DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT8(7),
WED_AMSDU_ENG_MAX_QGPP_CNT),
DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(7),
WED_AMSDU_ENG_CUR_ENTRY),
DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(7),
WED_AMSDU_ENG_MAX_BUF_MERGED),
DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(7),
WED_AMSDU_ENG_MAX_MSDU_MERGED),
DUMP_STR("WED AMDSU ENG8 INFO"),
DUMP_WED(WED_MON_AMSDU_ENG_DMAD(8)),
DUMP_WED(WED_MON_AMSDU_ENG_QFPL(8)),
DUMP_WED(WED_MON_AMSDU_ENG_QENI(8)),
DUMP_WED(WED_MON_AMSDU_ENG_QENO(8)),
DUMP_WED(WED_MON_AMSDU_ENG_MERG(8)),
DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT8(8),
WED_AMSDU_ENG_MAX_PL_CNT),
DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT8(8),
WED_AMSDU_ENG_MAX_QGPP_CNT),
DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(8),
WED_AMSDU_ENG_CUR_ENTRY),
DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(8),
WED_AMSDU_ENG_MAX_BUF_MERGED),
DUMP_WED_MASK(WED_MON_AMSDU_ENG_CNT9(8),
WED_AMSDU_ENG_MAX_MSDU_MERGED),
DUMP_STR("WED QMEM INFO"),
DUMP_WED_MASK(WED_MON_AMSDU_QMEM_CNT(0), WED_AMSDU_QMEM_FQ_CNT),
DUMP_WED_MASK(WED_MON_AMSDU_QMEM_CNT(0), WED_AMSDU_QMEM_SP_QCNT),
DUMP_WED_MASK(WED_MON_AMSDU_QMEM_CNT(1), WED_AMSDU_QMEM_TID0_QCNT),
DUMP_WED_MASK(WED_MON_AMSDU_QMEM_CNT(1), WED_AMSDU_QMEM_TID1_QCNT),
DUMP_WED_MASK(WED_MON_AMSDU_QMEM_CNT(2), WED_AMSDU_QMEM_TID2_QCNT),
DUMP_WED_MASK(WED_MON_AMSDU_QMEM_CNT(2), WED_AMSDU_QMEM_TID3_QCNT),
DUMP_WED_MASK(WED_MON_AMSDU_QMEM_CNT(3), WED_AMSDU_QMEM_TID4_QCNT),
DUMP_WED_MASK(WED_MON_AMSDU_QMEM_CNT(3), WED_AMSDU_QMEM_TID5_QCNT),
DUMP_WED_MASK(WED_MON_AMSDU_QMEM_CNT(4), WED_AMSDU_QMEM_TID6_QCNT),
DUMP_WED_MASK(WED_MON_AMSDU_QMEM_CNT(4), WED_AMSDU_QMEM_TID7_QCNT),
DUMP_STR("WED QMEM HEAD INFO"),
DUMP_WED_MASK(WED_MON_AMSDU_QMEM_PTR(0), WED_AMSDU_QMEM_FQ_HEAD),
DUMP_WED_MASK(WED_MON_AMSDU_QMEM_PTR(0), WED_AMSDU_QMEM_SP_QHEAD),
DUMP_WED_MASK(WED_MON_AMSDU_QMEM_PTR(1), WED_AMSDU_QMEM_TID0_QHEAD),
DUMP_WED_MASK(WED_MON_AMSDU_QMEM_PTR(1), WED_AMSDU_QMEM_TID1_QHEAD),
DUMP_WED_MASK(WED_MON_AMSDU_QMEM_PTR(2), WED_AMSDU_QMEM_TID2_QHEAD),
DUMP_WED_MASK(WED_MON_AMSDU_QMEM_PTR(2), WED_AMSDU_QMEM_TID3_QHEAD),
DUMP_WED_MASK(WED_MON_AMSDU_QMEM_PTR(3), WED_AMSDU_QMEM_TID4_QHEAD),
DUMP_WED_MASK(WED_MON_AMSDU_QMEM_PTR(3), WED_AMSDU_QMEM_TID5_QHEAD),
DUMP_WED_MASK(WED_MON_AMSDU_QMEM_PTR(4), WED_AMSDU_QMEM_TID6_QHEAD),
DUMP_WED_MASK(WED_MON_AMSDU_QMEM_PTR(4), WED_AMSDU_QMEM_TID7_QHEAD),
DUMP_STR("WED QMEM TAIL INFO"),
DUMP_WED_MASK(WED_MON_AMSDU_QMEM_PTR(5), WED_AMSDU_QMEM_FQ_TAIL),
DUMP_WED_MASK(WED_MON_AMSDU_QMEM_PTR(5), WED_AMSDU_QMEM_SP_QTAIL),
DUMP_WED_MASK(WED_MON_AMSDU_QMEM_PTR(6), WED_AMSDU_QMEM_TID0_QTAIL),
DUMP_WED_MASK(WED_MON_AMSDU_QMEM_PTR(6), WED_AMSDU_QMEM_TID1_QTAIL),
DUMP_WED_MASK(WED_MON_AMSDU_QMEM_PTR(7), WED_AMSDU_QMEM_TID2_QTAIL),
DUMP_WED_MASK(WED_MON_AMSDU_QMEM_PTR(7), WED_AMSDU_QMEM_TID3_QTAIL),
DUMP_WED_MASK(WED_MON_AMSDU_QMEM_PTR(8), WED_AMSDU_QMEM_TID4_QTAIL),
DUMP_WED_MASK(WED_MON_AMSDU_QMEM_PTR(8), WED_AMSDU_QMEM_TID5_QTAIL),
DUMP_WED_MASK(WED_MON_AMSDU_QMEM_PTR(9), WED_AMSDU_QMEM_TID6_QTAIL),
DUMP_WED_MASK(WED_MON_AMSDU_QMEM_PTR(9), WED_AMSDU_QMEM_TID7_QTAIL),
DUMP_STR("WED HIFTXD MSDU INFO"),
DUMP_WED(WED_MON_AMSDU_HIFTXD_FETCH_MSDU(1)),
DUMP_WED(WED_MON_AMSDU_HIFTXD_FETCH_MSDU(2)),
DUMP_WED(WED_MON_AMSDU_HIFTXD_FETCH_MSDU(3)),
DUMP_WED(WED_MON_AMSDU_HIFTXD_FETCH_MSDU(4)),
DUMP_WED(WED_MON_AMSDU_HIFTXD_FETCH_MSDU(5)),
DUMP_WED(WED_MON_AMSDU_HIFTXD_FETCH_MSDU(6)),
DUMP_WED(WED_MON_AMSDU_HIFTXD_FETCH_MSDU(7)),
DUMP_WED(WED_MON_AMSDU_HIFTXD_FETCH_MSDU(8)),
DUMP_WED(WED_MON_AMSDU_HIFTXD_FETCH_MSDU(9)),
DUMP_WED(WED_MON_AMSDU_HIFTXD_FETCH_MSDU(10)),
DUMP_WED(WED_MON_AMSDU_HIFTXD_FETCH_MSDU(11)),
DUMP_WED(WED_MON_AMSDU_HIFTXD_FETCH_MSDU(12)),
DUMP_WED(WED_MON_AMSDU_HIFTXD_FETCH_MSDU(13)),
};
struct mtk_wed_hw *hw = s->private;
struct mtk_wed_device *dev = hw->wed_dev;
if (dev)
dump_wed_regs(s, dev, regs, ARRAY_SIZE(regs));
return 0;
}
DEFINE_SHOW_ATTRIBUTE(wed_amsdu);
static int
wed_rtqm_show(struct seq_file *s, void *data)
{
static const struct reg_dump regs[] = {
DUMP_STR("WED Route QM IGRS0(N2H + Recycle)"),
DUMP_WED(WED_RTQM_IGRS0_I2HW_DMAD_CNT),
DUMP_WED(WED_RTQM_IGRS0_I2H_DMAD_CNT(0)),
DUMP_WED(WED_RTQM_IGRS0_I2H_DMAD_CNT(1)),
DUMP_WED(WED_RTQM_IGRS0_I2HW_PKT_CNT),
DUMP_WED(WED_RTQM_IGRS0_I2H_PKT_CNT(0)),
DUMP_WED(WED_RTQM_IGRS0_I2H_PKT_CNT(0)),
DUMP_WED(WED_RTQM_IGRS0_FDROP_CNT),
DUMP_STR("WED Route QM IGRS1(Legacy)"),
DUMP_WED(WED_RTQM_IGRS1_I2HW_DMAD_CNT),
DUMP_WED(WED_RTQM_IGRS1_I2H_DMAD_CNT(0)),
DUMP_WED(WED_RTQM_IGRS1_I2H_DMAD_CNT(1)),
DUMP_WED(WED_RTQM_IGRS1_I2HW_PKT_CNT),
DUMP_WED(WED_RTQM_IGRS1_I2H_PKT_CNT(0)),
DUMP_WED(WED_RTQM_IGRS1_I2H_PKT_CNT(1)),
DUMP_WED(WED_RTQM_IGRS1_FDROP_CNT),
DUMP_STR("WED Route QM IGRS2(RRO3.0)"),
DUMP_WED(WED_RTQM_IGRS2_I2HW_DMAD_CNT),
DUMP_WED(WED_RTQM_IGRS2_I2H_DMAD_CNT(0)),
DUMP_WED(WED_RTQM_IGRS2_I2H_DMAD_CNT(1)),
DUMP_WED(WED_RTQM_IGRS2_I2HW_PKT_CNT),
DUMP_WED(WED_RTQM_IGRS2_I2H_PKT_CNT(0)),
DUMP_WED(WED_RTQM_IGRS2_I2H_PKT_CNT(1)),
DUMP_WED(WED_RTQM_IGRS2_FDROP_CNT),
DUMP_STR("WED Route QM IGRS3(DEBUG)"),
DUMP_WED(WED_RTQM_IGRS2_I2HW_DMAD_CNT),
DUMP_WED(WED_RTQM_IGRS3_I2H_DMAD_CNT(0)),
DUMP_WED(WED_RTQM_IGRS3_I2H_DMAD_CNT(1)),
DUMP_WED(WED_RTQM_IGRS3_I2HW_PKT_CNT),
DUMP_WED(WED_RTQM_IGRS3_I2H_PKT_CNT(0)),
DUMP_WED(WED_RTQM_IGRS3_I2H_PKT_CNT(1)),
DUMP_WED(WED_RTQM_IGRS3_FDROP_CNT),
};
struct mtk_wed_hw *hw = s->private;
struct mtk_wed_device *dev = hw->wed_dev;
if (dev)
dump_wed_regs(s, dev, regs, ARRAY_SIZE(regs));
return 0;
}
DEFINE_SHOW_ATTRIBUTE(wed_rtqm);
static int
wed_rro_show(struct seq_file *s, void *data)
{
static const struct reg_dump regs[] = {
DUMP_STR("RRO/IND CMD CNT"),
DUMP_WED(WED_RX_IND_CMD_CNT(1)),
DUMP_WED(WED_RX_IND_CMD_CNT(2)),
DUMP_WED(WED_RX_IND_CMD_CNT(3)),
DUMP_WED(WED_RX_IND_CMD_CNT(4)),
DUMP_WED(WED_RX_IND_CMD_CNT(5)),
DUMP_WED(WED_RX_IND_CMD_CNT(6)),
DUMP_WED(WED_RX_IND_CMD_CNT(7)),
DUMP_WED(WED_RX_IND_CMD_CNT(8)),
DUMP_WED_MASK(WED_RX_IND_CMD_CNT(9),
WED_IND_CMD_MAGIC_CNT_FAIL_CNT),
DUMP_WED(WED_RX_ADDR_ELEM_CNT(0)),
DUMP_WED_MASK(WED_RX_ADDR_ELEM_CNT(1),
WED_ADDR_ELEM_SIG_FAIL_CNT),
DUMP_WED(WED_RX_MSDU_PG_CNT(1)),
DUMP_WED(WED_RX_MSDU_PG_CNT(2)),
DUMP_WED(WED_RX_MSDU_PG_CNT(3)),
DUMP_WED(WED_RX_MSDU_PG_CNT(4)),
DUMP_WED(WED_RX_MSDU_PG_CNT(5)),
DUMP_WED_MASK(WED_RX_PN_CHK_CNT,
WED_PN_CHK_FAIL_CNT),
};
struct mtk_wed_hw *hw = s->private;
struct mtk_wed_device *dev = hw->wed_dev;
if (dev)
dump_wed_regs(s, dev, regs, ARRAY_SIZE(regs));
return 0;
}
DEFINE_SHOW_ATTRIBUTE(wed_rro);
static int
mtk_wed_reg_set(void *data, u64 val)
{
struct mtk_wed_hw *hw = data;
regmap_write(hw->regs, hw->debugfs_reg, val);
return 0;
}
static int
mtk_wed_reg_get(void *data, u64 *val)
{
struct mtk_wed_hw *hw = data;
unsigned int regval;
int ret;
ret = regmap_read(hw->regs, hw->debugfs_reg, &regval);
if (ret)
return ret;
*val = regval;
return 0;
}
DEFINE_DEBUGFS_ATTRIBUTE(fops_regval, mtk_wed_reg_get, mtk_wed_reg_set,
"0x%08llx\n");
void mtk_wed_hw_add_debugfs(struct mtk_wed_hw *hw)
{
struct dentry *dir;
snprintf(hw->dirname, sizeof(hw->dirname), "wed%d", hw->index);
dir = debugfs_create_dir(hw->dirname, NULL);
hw->debugfs_dir = dir;
debugfs_create_u32("regidx", 0600, dir, &hw->debugfs_reg);
debugfs_create_file_unsafe("regval", 0600, dir, hw, &fops_regval);
debugfs_create_file_unsafe("txinfo", 0400, dir, hw, &wed_txinfo_fops);
if (!mtk_wed_is_v1(hw)) {
debugfs_create_file_unsafe("rxinfo", 0400, dir, hw,
&wed_rxinfo_fops);
if (mtk_wed_is_v3_or_greater(hw)) {
debugfs_create_file_unsafe("amsdu", 0400, dir, hw,
&wed_amsdu_fops);
debugfs_create_file_unsafe("rtqm", 0400, dir, hw,
&wed_rtqm_fops);
debugfs_create_file_unsafe("rro", 0400, dir, hw,
&wed_rro_fops);
}
}
}
@@ -0,0 +1,411 @@
// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (C) 2022 MediaTek Inc.
*
* Author: Lorenzo Bianconi <lorenzo@kernel.org>
* Sujuan Chen <sujuan.chen@mediatek.com>
*/
#include <linux/firmware.h>
#include <linux/of_address.h>
#include <linux/of_reserved_mem.h>
#include <linux/mfd/syscon.h>
#include <linux/soc/mediatek/mtk_wed.h>
#include <linux/unaligned.h>
#include "mtk_wed_regs.h"
#include "mtk_wed_wo.h"
#include "mtk_wed.h"
static struct mtk_wed_wo_memory_region mem_region[] = {
[MTK_WED_WO_REGION_EMI] = {
.name = "wo-emi",
},
[MTK_WED_WO_REGION_ILM] = {
.name = "wo-ilm",
},
[MTK_WED_WO_REGION_DATA] = {
.name = "wo-data",
.shared = true,
},
[MTK_WED_WO_REGION_BOOT] = {
.name = "wo-boot",
},
};
static u32 wo_r32(u32 reg)
{
return readl(mem_region[MTK_WED_WO_REGION_BOOT].addr + reg);
}
static void wo_w32(u32 reg, u32 val)
{
writel(val, mem_region[MTK_WED_WO_REGION_BOOT].addr + reg);
}
static struct sk_buff *
mtk_wed_mcu_msg_alloc(const void *data, int data_len)
{
int length = sizeof(struct mtk_wed_mcu_hdr) + data_len;
struct sk_buff *skb;
skb = alloc_skb(length, GFP_KERNEL);
if (!skb)
return NULL;
memset(skb->head, 0, length);
skb_reserve(skb, sizeof(struct mtk_wed_mcu_hdr));
if (data && data_len)
skb_put_data(skb, data, data_len);
return skb;
}
static struct sk_buff *
mtk_wed_mcu_get_response(struct mtk_wed_wo *wo, unsigned long expires)
{
if (!time_is_after_jiffies(expires))
return NULL;
wait_event_timeout(wo->mcu.wait, !skb_queue_empty(&wo->mcu.res_q),
expires - jiffies);
return skb_dequeue(&wo->mcu.res_q);
}
void mtk_wed_mcu_rx_event(struct mtk_wed_wo *wo, struct sk_buff *skb)
{
skb_queue_tail(&wo->mcu.res_q, skb);
wake_up(&wo->mcu.wait);
}
static void
mtk_wed_update_rx_stats(struct mtk_wed_device *wed, struct sk_buff *skb)
{
u32 count = get_unaligned_le32(skb->data);
struct mtk_wed_wo_rx_stats *stats;
int i;
if (!wed->wlan.update_wo_rx_stats)
return;
if (count * sizeof(*stats) > skb->len - sizeof(u32))
return;
stats = (struct mtk_wed_wo_rx_stats *)(skb->data + sizeof(u32));
for (i = 0 ; i < count ; i++)
wed->wlan.update_wo_rx_stats(wed, &stats[i]);
}
void mtk_wed_mcu_rx_unsolicited_event(struct mtk_wed_wo *wo,
struct sk_buff *skb)
{
struct mtk_wed_mcu_hdr *hdr = (struct mtk_wed_mcu_hdr *)skb->data;
skb_pull(skb, sizeof(*hdr));
switch (hdr->cmd) {
case MTK_WED_WO_EVT_LOG_DUMP:
dev_notice(wo->hw->dev, "%s\n", skb->data);
break;
case MTK_WED_WO_EVT_PROFILING: {
struct mtk_wed_wo_log_info *info = (void *)skb->data;
u32 count = skb->len / sizeof(*info);
int i;
for (i = 0 ; i < count ; i++)
dev_notice(wo->hw->dev,
"SN:%u latency: total=%u, rro:%u, mod:%u\n",
le32_to_cpu(info[i].sn),
le32_to_cpu(info[i].total),
le32_to_cpu(info[i].rro),
le32_to_cpu(info[i].mod));
break;
}
case MTK_WED_WO_EVT_RXCNT_INFO:
mtk_wed_update_rx_stats(wo->hw->wed_dev, skb);
break;
default:
break;
}
dev_kfree_skb(skb);
}
static int
mtk_wed_mcu_skb_send_msg(struct mtk_wed_wo *wo, struct sk_buff *skb,
int id, int cmd, u16 *wait_seq, bool wait_resp)
{
struct mtk_wed_mcu_hdr *hdr;
/* TODO: make it dynamic based on cmd */
wo->mcu.timeout = 20 * HZ;
hdr = (struct mtk_wed_mcu_hdr *)skb_push(skb, sizeof(*hdr));
hdr->cmd = cmd;
hdr->length = cpu_to_le16(skb->len);
if (wait_resp && wait_seq) {
u16 seq = ++wo->mcu.seq;
if (!seq)
seq = ++wo->mcu.seq;
*wait_seq = seq;
hdr->flag |= cpu_to_le16(MTK_WED_WARP_CMD_FLAG_NEED_RSP);
hdr->seq = cpu_to_le16(seq);
}
if (id == MTK_WED_MODULE_ID_WO)
hdr->flag |= cpu_to_le16(MTK_WED_WARP_CMD_FLAG_FROM_TO_WO);
return mtk_wed_wo_queue_tx_skb(wo, &wo->q_tx, skb);
}
static int
mtk_wed_mcu_parse_response(struct mtk_wed_wo *wo, struct sk_buff *skb,
int cmd, int seq)
{
struct mtk_wed_mcu_hdr *hdr;
if (!skb) {
dev_err(wo->hw->dev, "Message %08x (seq %d) timeout\n",
cmd, seq);
return -ETIMEDOUT;
}
hdr = (struct mtk_wed_mcu_hdr *)skb->data;
if (le16_to_cpu(hdr->seq) != seq)
return -EAGAIN;
skb_pull(skb, sizeof(*hdr));
switch (cmd) {
case MTK_WED_WO_CMD_RXCNT_INFO:
mtk_wed_update_rx_stats(wo->hw->wed_dev, skb);
break;
default:
break;
}
return 0;
}
int mtk_wed_mcu_send_msg(struct mtk_wed_wo *wo, int id, int cmd,
const void *data, int len, bool wait_resp)
{
unsigned long expires;
struct sk_buff *skb;
u16 seq;
int ret;
skb = mtk_wed_mcu_msg_alloc(data, len);
if (!skb)
return -ENOMEM;
mutex_lock(&wo->mcu.mutex);
ret = mtk_wed_mcu_skb_send_msg(wo, skb, id, cmd, &seq, wait_resp);
if (ret || !wait_resp)
goto unlock;
expires = jiffies + wo->mcu.timeout;
do {
skb = mtk_wed_mcu_get_response(wo, expires);
ret = mtk_wed_mcu_parse_response(wo, skb, cmd, seq);
dev_kfree_skb(skb);
} while (ret == -EAGAIN);
unlock:
mutex_unlock(&wo->mcu.mutex);
return ret;
}
int mtk_wed_mcu_msg_update(struct mtk_wed_device *dev, int id, void *data,
int len)
{
struct mtk_wed_wo *wo = dev->hw->wed_wo;
if (!mtk_wed_get_rx_capa(dev))
return 0;
if (WARN_ON(!wo))
return -ENODEV;
return mtk_wed_mcu_send_msg(wo, MTK_WED_MODULE_ID_WO, id, data, len,
true);
}
static int
mtk_wed_get_memory_region(struct mtk_wed_hw *hw, const char *name,
struct mtk_wed_wo_memory_region *region)
{
struct resource res;
int ret;
ret = of_reserved_mem_region_to_resource_byname(hw->node, name, &res);
if (ret)
return 0;
region->phy_addr = res.start;
region->size = resource_size(&res);
region->addr = devm_ioremap_resource(hw->dev, &res);
if (IS_ERR(region->addr))
return PTR_ERR(region->addr);
return 0;
}
static int
mtk_wed_mcu_run_firmware(struct mtk_wed_wo *wo, const struct firmware *fw)
{
const u8 *first_region_ptr, *region_ptr, *trailer_ptr, *ptr = fw->data;
const struct mtk_wed_fw_trailer *trailer;
const struct mtk_wed_fw_region *fw_region;
trailer_ptr = fw->data + fw->size - sizeof(*trailer);
trailer = (const struct mtk_wed_fw_trailer *)trailer_ptr;
region_ptr = trailer_ptr - trailer->num_region * sizeof(*fw_region);
first_region_ptr = region_ptr;
while (region_ptr < trailer_ptr) {
u32 length;
int i;
fw_region = (const struct mtk_wed_fw_region *)region_ptr;
length = le32_to_cpu(fw_region->len);
if (first_region_ptr < ptr + length)
goto next;
for (i = 0; i < ARRAY_SIZE(mem_region); i++) {
struct mtk_wed_wo_memory_region *region;
region = &mem_region[i];
if (region->phy_addr != le32_to_cpu(fw_region->addr))
continue;
if (region->size < length)
continue;
if (region->shared && region->consumed)
break;
if (!region->shared || !region->consumed) {
memcpy_toio(region->addr, ptr, length);
region->consumed = true;
break;
}
}
if (i == ARRAY_SIZE(mem_region))
return -EINVAL;
next:
region_ptr += sizeof(*fw_region);
ptr += length;
}
return 0;
}
static int
mtk_wed_mcu_load_firmware(struct mtk_wed_wo *wo)
{
const struct mtk_wed_fw_trailer *trailer;
const struct firmware *fw;
const char *fw_name;
u32 val, boot_cr;
int ret, i;
/* load firmware region metadata */
for (i = 0; i < ARRAY_SIZE(mem_region); i++) {
ret = mtk_wed_get_memory_region(wo->hw, mem_region[i].name, &mem_region[i]);
if (ret)
return ret;
}
/* set dummy cr */
wed_w32(wo->hw->wed_dev, MTK_WED_SCR0 + 4 * MTK_WED_DUMMY_CR_FWDL,
wo->hw->index + 1);
/* load firmware */
switch (wo->hw->version) {
case 2:
if (of_device_is_compatible(wo->hw->node,
"mediatek,mt7981-wed"))
fw_name = MT7981_FIRMWARE_WO;
else
fw_name = wo->hw->index ? MT7986_FIRMWARE_WO1
: MT7986_FIRMWARE_WO0;
break;
case 3:
fw_name = wo->hw->index ? MT7988_FIRMWARE_WO1
: MT7988_FIRMWARE_WO0;
break;
default:
return -EINVAL;
}
ret = request_firmware(&fw, fw_name, wo->hw->dev);
if (ret)
return ret;
trailer = (void *)(fw->data + fw->size -
sizeof(struct mtk_wed_fw_trailer));
dev_info(wo->hw->dev,
"MTK WED WO Firmware Version: %.10s, Build Time: %.15s\n",
trailer->fw_ver, trailer->build_date);
dev_info(wo->hw->dev, "MTK WED WO Chip ID %02x Region %d\n",
trailer->chip_id, trailer->num_region);
ret = mtk_wed_mcu_run_firmware(wo, fw);
if (ret)
goto out;
/* set the start address */
if (!mtk_wed_is_v3_or_greater(wo->hw) && wo->hw->index)
boot_cr = MTK_WO_MCU_CFG_LS_WA_BOOT_ADDR_ADDR;
else
boot_cr = MTK_WO_MCU_CFG_LS_WM_BOOT_ADDR_ADDR;
wo_w32(boot_cr, mem_region[MTK_WED_WO_REGION_EMI].phy_addr >> 16);
/* wo firmware reset */
wo_w32(MTK_WO_MCU_CFG_LS_WF_MCCR_CLR_ADDR, 0xc00);
val = wo_r32(MTK_WO_MCU_CFG_LS_WF_MCU_CFG_WM_WA_ADDR);
if (!mtk_wed_is_v3_or_greater(wo->hw) && wo->hw->index)
val |= MTK_WO_MCU_CFG_LS_WF_WM_WA_WA_CPU_RSTB_MASK;
else
val |= MTK_WO_MCU_CFG_LS_WF_WM_WA_WM_CPU_RSTB_MASK;
wo_w32(MTK_WO_MCU_CFG_LS_WF_MCU_CFG_WM_WA_ADDR, val);
out:
release_firmware(fw);
return ret;
}
static u32
mtk_wed_mcu_read_fw_dl(struct mtk_wed_wo *wo)
{
return wed_r32(wo->hw->wed_dev,
MTK_WED_SCR0 + 4 * MTK_WED_DUMMY_CR_FWDL);
}
int mtk_wed_mcu_init(struct mtk_wed_wo *wo)
{
u32 val;
int ret;
skb_queue_head_init(&wo->mcu.res_q);
init_waitqueue_head(&wo->mcu.wait);
mutex_init(&wo->mcu.mutex);
ret = mtk_wed_mcu_load_firmware(wo);
if (ret)
return ret;
return readx_poll_timeout(mtk_wed_mcu_read_fw_dl, wo, val, !val,
100, MTK_FW_DL_TIMEOUT);
}
MODULE_FIRMWARE(MT7981_FIRMWARE_WO);
MODULE_FIRMWARE(MT7986_FIRMWARE_WO0);
MODULE_FIRMWARE(MT7986_FIRMWARE_WO1);
MODULE_FIRMWARE(MT7988_FIRMWARE_WO0);
MODULE_FIRMWARE(MT7988_FIRMWARE_WO1);
@@ -0,0 +1,8 @@
// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (C) 2020 Felix Fietkau <nbd@nbd.name> */
#include <linux/kernel.h>
#include <linux/soc/mediatek/mtk_wed.h>
const struct mtk_wed_ops __rcu *mtk_soc_wed_ops;
EXPORT_SYMBOL_GPL(mtk_soc_wed_ops);
@@ -0,0 +1,815 @@
// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (C) 2020 Felix Fietkau <nbd@nbd.name> */
#ifndef __MTK_WED_REGS_H
#define __MTK_WED_REGS_H
#define MTK_WFDMA_DESC_CTRL_TO_HOST BIT(8)
#define MTK_WDMA_DESC_CTRL_LEN1 GENMASK(14, 0)
#define MTK_WDMA_DESC_CTRL_LEN1_V2 GENMASK(13, 0)
#define MTK_WDMA_DESC_CTRL_LAST_SEG1 BIT(15)
#define MTK_WDMA_DESC_CTRL_BURST BIT(16)
#define MTK_WDMA_DESC_CTRL_LEN0 GENMASK(29, 16)
#define MTK_WDMA_DESC_CTRL_LAST_SEG0 BIT(30)
#define MTK_WDMA_DESC_CTRL_DMA_DONE BIT(31)
#define MTK_WDMA_TXD0_DESC_INFO_DMA_DONE BIT(29)
#define MTK_WDMA_TXD1_DESC_INFO_DMA_DONE BIT(31)
struct mtk_wdma_desc {
__le32 buf0;
__le32 ctrl;
__le32 buf1;
__le32 info;
} __packed __aligned(4);
#define MTK_WED_REV_ID 0x004
#define MTK_WED_RESET 0x008
#define MTK_WED_RESET_TX_BM BIT(0)
#define MTK_WED_RESET_RX_BM BIT(1)
#define MTK_WED_RESET_RX_PG_BM BIT(2)
#define MTK_WED_RESET_RRO_RX_TO_PG BIT(3)
#define MTK_WED_RESET_TX_FREE_AGENT BIT(4)
#define MTK_WED_RESET_WPDMA_TX_DRV BIT(8)
#define MTK_WED_RESET_WPDMA_RX_DRV BIT(9)
#define MTK_WED_RESET_WPDMA_RX_D_DRV BIT(10)
#define MTK_WED_RESET_WPDMA_INT_AGENT BIT(11)
#define MTK_WED_RESET_WED_TX_DMA BIT(12)
#define MTK_WED_RESET_WED_RX_DMA BIT(13)
#define MTK_WED_RESET_WDMA_TX_DRV BIT(16)
#define MTK_WED_RESET_WDMA_RX_DRV BIT(17)
#define MTK_WED_RESET_WDMA_INT_AGENT BIT(19)
#define MTK_WED_RESET_RX_RRO_QM BIT(20)
#define MTK_WED_RESET_RX_ROUTE_QM BIT(21)
#define MTK_WED_RESET_TX_AMSDU BIT(22)
#define MTK_WED_RESET_WED BIT(31)
#define MTK_WED_CTRL 0x00c
#define MTK_WED_CTRL_WPDMA_INT_AGENT_EN BIT(0)
#define MTK_WED_CTRL_WPDMA_INT_AGENT_BUSY BIT(1)
#define MTK_WED_CTRL_WDMA_INT_AGENT_EN BIT(2)
#define MTK_WED_CTRL_WDMA_INT_AGENT_BUSY BIT(3)
#define MTK_WED_CTRL_WED_RX_IND_CMD_EN BIT(5)
#define MTK_WED_CTRL_WED_RX_PG_BM_EN BIT(6)
#define MTK_WED_CTRL_WED_RX_PG_BM_BUSY BIT(7)
#define MTK_WED_CTRL_WED_TX_BM_EN BIT(8)
#define MTK_WED_CTRL_WED_TX_BM_BUSY BIT(9)
#define MTK_WED_CTRL_WED_TX_FREE_AGENT_EN BIT(10)
#define MTK_WED_CTRL_WED_TX_FREE_AGENT_BUSY BIT(11)
#define MTK_WED_CTRL_WED_RX_BM_EN BIT(12)
#define MTK_WED_CTRL_WED_RX_BM_BUSY BIT(13)
#define MTK_WED_CTRL_RX_RRO_QM_EN BIT(14)
#define MTK_WED_CTRL_RX_RRO_QM_BUSY BIT(15)
#define MTK_WED_CTRL_RX_ROUTE_QM_EN BIT(16)
#define MTK_WED_CTRL_RX_ROUTE_QM_BUSY BIT(17)
#define MTK_WED_CTRL_TX_TKID_ALI_EN BIT(20)
#define MTK_WED_CTRL_TX_TKID_ALI_BUSY BIT(21)
#define MTK_WED_CTRL_TX_AMSDU_EN BIT(22)
#define MTK_WED_CTRL_TX_AMSDU_BUSY BIT(23)
#define MTK_WED_CTRL_FINAL_DIDX_READ BIT(24)
#define MTK_WED_CTRL_ETH_DMAD_FMT BIT(25)
#define MTK_WED_CTRL_MIB_READ_CLEAR BIT(28)
#define MTK_WED_CTRL_FLD_MIB_RD_CLR BIT(28)
#define MTK_WED_EXT_INT_STATUS 0x020
#define MTK_WED_EXT_INT_STATUS_TF_LEN_ERR BIT(0)
#define MTK_WED_EXT_INT_STATUS_TKID_WO_PYLD BIT(1)
#define MTK_WED_EXT_INT_STATUS_TKID_TITO_INVALID BIT(4)
#define MTK_WED_EXT_INT_STATUS_TX_FBUF_LO_TH BIT(8)
#define MTK_WED_EXT_INT_STATUS_TX_FBUF_HI_TH BIT(9)
#define MTK_WED_EXT_INT_STATUS_RX_FBUF_LO_TH BIT(10) /* wed v2 */
#define MTK_WED_EXT_INT_STATUS_RX_FBUF_HI_TH BIT(11) /* wed v2 */
#define MTK_WED_EXT_INT_STATUS_RX_DRV_R_RESP_ERR BIT(16)
#define MTK_WED_EXT_INT_STATUS_RX_DRV_W_RESP_ERR BIT(17)
#define MTK_WED_EXT_INT_STATUS_RX_DRV_COHERENT BIT(18)
#define MTK_WED_EXT_INT_STATUS_RX_DRV_INIT_WDMA_EN BIT(19)
#define MTK_WED_EXT_INT_STATUS_RX_DRV_BM_DMAD_COHERENT BIT(20)
#define MTK_WED_EXT_INT_STATUS_TX_DRV_R_RESP_ERR BIT(21)
#define MTK_WED_EXT_INT_STATUS_TX_DMA_R_RESP_ERR BIT(22)
#define MTK_WED_EXT_INT_STATUS_TX_DMA_W_RESP_ERR BIT(23)
#define MTK_WED_EXT_INT_STATUS_RX_DRV_DMA_RECYCLE BIT(24)
#define MTK_WED_EXT_INT_STATUS_RX_DRV_GET_BM_DMAD_SKIP BIT(25)
#define MTK_WED_EXT_INT_STATUS_WPDMA_RX_D_DRV_ERR BIT(26)
#define MTK_WED_EXT_INT_STATUS_WPDMA_MID_RDY BIT(27)
#define MTK_WED_EXT_INT_STATUS_ERROR_MASK (MTK_WED_EXT_INT_STATUS_TF_LEN_ERR | \
MTK_WED_EXT_INT_STATUS_TKID_WO_PYLD | \
MTK_WED_EXT_INT_STATUS_TKID_TITO_INVALID | \
MTK_WED_EXT_INT_STATUS_RX_DRV_R_RESP_ERR | \
MTK_WED_EXT_INT_STATUS_RX_DRV_W_RESP_ERR | \
MTK_WED_EXT_INT_STATUS_RX_DRV_INIT_WDMA_EN | \
MTK_WED_EXT_INT_STATUS_TX_DMA_R_RESP_ERR)
#define MTK_WED_EXT_INT_MASK 0x028
#define MTK_WED_EXT_INT_MASK1 0x02c
#define MTK_WED_EXT_INT_MASK2 0x030
#define MTK_WED_EXT_INT_MASK3 0x034
#define MTK_WED_STATUS 0x060
#define MTK_WED_STATUS_TX GENMASK(15, 8)
#define MTK_WED_WPDMA_STATUS 0x068
#define MTK_WED_WPDMA_STATUS_TX_DRV GENMASK(15, 8)
#define MTK_WED_TX_BM_CTRL 0x080
#define MTK_WED_TX_BM_CTRL_VLD_GRP_NUM GENMASK(6, 0)
#define MTK_WED_TX_BM_CTRL_RSV_GRP_NUM GENMASK(22, 16)
#define MTK_WED_TX_BM_CTRL_LEGACY_EN BIT(26)
#define MTK_WED_TX_TKID_CTRL_FREE_FORMAT BIT(27)
#define MTK_WED_TX_BM_CTRL_PAUSE BIT(28)
#define MTK_WED_TX_BM_BASE 0x084
#define MTK_WED_TX_BM_INIT_PTR 0x088
#define MTK_WED_TX_BM_SW_TAIL_IDX GENMASK(16, 0)
#define MTK_WED_TX_BM_INIT_SW_TAIL_IDX BIT(16)
#define MTK_WED_TX_BM_TKID_START GENMASK(15, 0)
#define MTK_WED_TX_BM_TKID_END GENMASK(31, 16)
#define MTK_WED_TX_BM_BUF_LEN 0x08c
#define MTK_WED_TX_BM_INTF 0x09c
#define MTK_WED_TX_BM_INTF_TKID GENMASK(15, 0)
#define MTK_WED_TX_BM_INTF_TKFIFO_FDEP GENMASK(23, 16)
#define MTK_WED_TX_BM_INTF_TKID_VALID BIT(28)
#define MTK_WED_TX_BM_INTF_TKID_READ BIT(29)
#define MTK_WED_TX_BM_DYN_THR 0x0a0
#define MTK_WED_TX_BM_DYN_THR_LO GENMASK(6, 0)
#define MTK_WED_TX_BM_DYN_THR_LO_V2 GENMASK(8, 0)
#define MTK_WED_TX_BM_DYN_THR_HI GENMASK(22, 16)
#define MTK_WED_TX_BM_DYN_THR_HI_V2 GENMASK(24, 16)
#define MTK_WED_TX_TKID_CTRL 0x0c0
#define MTK_WED_TX_TKID_CTRL_VLD_GRP_NUM GENMASK(6, 0)
#define MTK_WED_TX_TKID_CTRL_RSV_GRP_NUM GENMASK(22, 16)
#define MTK_WED_TX_TKID_CTRL_PAUSE BIT(28)
#define MTK_WED_TX_TKID_INTF 0x0dc
#define MTK_WED_TX_TKID_INTF_TKFIFO_FDEP GENMASK(25, 16)
#define MTK_WED_TX_TKID_CTRL_VLD_GRP_NUM_V3 GENMASK(7, 0)
#define MTK_WED_TX_TKID_CTRL_RSV_GRP_NUM_V3 GENMASK(23, 16)
#define MTK_WED_TX_TKID_DYN_THR 0x0e0
#define MTK_WED_TX_TKID_DYN_THR_LO GENMASK(6, 0)
#define MTK_WED_TX_TKID_DYN_THR_HI GENMASK(22, 16)
#define MTK_WED_TXP_DW0 0x120
#define MTK_WED_TXP_DW1 0x124
#define MTK_WED_WPDMA_WRITE_TXP GENMASK(31, 16)
#define MTK_WED_TXDP_CTRL 0x130
#define MTK_WED_TXDP_DW9_OVERWR BIT(9)
#define MTK_WED_RX_BM_TKID_MIB 0x1cc
#define MTK_WED_INT_STATUS 0x200
#define MTK_WED_INT_MASK 0x204
#define MTK_WED_GLO_CFG 0x208
#define MTK_WED_GLO_CFG_TX_DMA_EN BIT(0)
#define MTK_WED_GLO_CFG_TX_DMA_BUSY BIT(1)
#define MTK_WED_GLO_CFG_RX_DMA_EN BIT(2)
#define MTK_WED_GLO_CFG_RX_DMA_BUSY BIT(3)
#define MTK_WED_GLO_CFG_RX_BT_SIZE GENMASK(5, 4)
#define MTK_WED_GLO_CFG_TX_WB_DDONE BIT(6)
#define MTK_WED_GLO_CFG_BIG_ENDIAN BIT(7)
#define MTK_WED_GLO_CFG_DIS_BT_SIZE_ALIGN BIT(8)
#define MTK_WED_GLO_CFG_TX_BT_SIZE_LO BIT(9)
#define MTK_WED_GLO_CFG_MULTI_DMA_EN GENMASK(11, 10)
#define MTK_WED_GLO_CFG_FIFO_LITTLE_ENDIAN BIT(12)
#define MTK_WED_GLO_CFG_MI_DEPTH_RD GENMASK(21, 13)
#define MTK_WED_GLO_CFG_TX_BT_SIZE_HI GENMASK(23, 22)
#define MTK_WED_GLO_CFG_SW_RESET BIT(24)
#define MTK_WED_GLO_CFG_FIRST_TOKEN_ONLY BIT(26)
#define MTK_WED_GLO_CFG_OMIT_RX_INFO BIT(27)
#define MTK_WED_GLO_CFG_OMIT_TX_INFO BIT(28)
#define MTK_WED_GLO_CFG_BYTE_SWAP BIT(29)
#define MTK_WED_GLO_CFG_RX_2B_OFFSET BIT(31)
#define MTK_WED_RESET_IDX 0x20c
#define MTK_WED_RESET_WPDMA_IDX_RX GENMASK(31, 30)
#define MTK_WED_TX_MIB(_n) (0x2a0 + (_n) * 4)
#define MTK_WED_RX_MIB(_n) (0x2e0 + (_n) * 4)
#define MTK_WED_RING_TX(_n) (0x300 + (_n) * 0x10)
#define MTK_WED_RING_RX(_n) (0x400 + (_n) * 0x10)
#define MTK_WED_RING_RX_DATA(_n) (0x420 + (_n) * 0x10)
#define MTK_WED_SCR0 0x3c0
#define MTK_WED_RX1_CTRL2 0x418
#define MTK_WED_WPDMA_INT_TRIGGER 0x504
#define MTK_WED_WPDMA_INT_TRIGGER_RX_DONE BIT(1)
#define MTK_WED_WPDMA_INT_TRIGGER_TX_DONE GENMASK(5, 4)
#define MTK_WED_WPDMA_GLO_CFG 0x508
#define MTK_WED_WPDMA_GLO_CFG_TX_DRV_EN BIT(0)
#define MTK_WED_WPDMA_GLO_CFG_TX_DRV_BUSY BIT(1)
#define MTK_WED_WPDMA_GLO_CFG_RX_DRV_EN BIT(2)
#define MTK_WED_WPDMA_GLO_CFG_RX_DRV_BUSY BIT(3)
#define MTK_WED_WPDMA_GLO_CFG_RX_BT_SIZE GENMASK(5, 4)
#define MTK_WED_WPDMA_GLO_CFG_TX_WB_DDONE BIT(6)
#define MTK_WED_WPDMA_GLO_CFG_BIG_ENDIAN BIT(7)
#define MTK_WED_WPDMA_GLO_CFG_DIS_BT_SIZE_ALIGN BIT(8)
#define MTK_WED_WPDMA_GLO_CFG_TX_BT_SIZE_LO BIT(9)
#define MTK_WED_WPDMA_GLO_CFG_MULTI_DMA_EN GENMASK(11, 10)
#define MTK_WED_WPDMA_GLO_CFG_FIFO_LITTLE_ENDIAN BIT(12)
#define MTK_WED_WPDMA_GLO_CFG_MI_DEPTH_RD GENMASK(21, 13)
#define MTK_WED_WPDMA_GLO_CFG_TX_BT_SIZE_HI GENMASK(23, 22)
#define MTK_WED_WPDMA_GLO_CFG_SW_RESET BIT(24)
#define MTK_WED_WPDMA_GLO_CFG_FIRST_TOKEN_ONLY BIT(26)
#define MTK_WED_WPDMA_GLO_CFG_OMIT_RX_INFO BIT(27)
#define MTK_WED_WPDMA_GLO_CFG_OMIT_TX_INFO BIT(28)
#define MTK_WED_WPDMA_GLO_CFG_BYTE_SWAP BIT(29)
#define MTK_WED_WPDMA_GLO_CFG_RX_2B_OFFSET BIT(31)
/* CONFIG_MEDIATEK_NETSYS_V2 */
#define MTK_WED_WPDMA_GLO_CFG_RX_DRV_R0_PKT_PROC BIT(4)
#define MTK_WED_WPDMA_GLO_CFG_RX_DRV_R1_PKT_PROC BIT(5)
#define MTK_WED_WPDMA_GLO_CFG_RX_DRV_R0_CRX_SYNC BIT(6)
#define MTK_WED_WPDMA_GLO_CFG_RX_DRV_R1_CRX_SYNC BIT(7)
#define MTK_WED_WPDMA_GLO_CFG_RX_DRV_EVENT_PKT_FMT_VER GENMASK(15, 12)
#define MTK_WED_WPDMA_GLO_CFG_RX_DRV_UNS_VER_FORCE_4 BIT(18)
#define MTK_WED_WPDMA_GLO_CFG_RX_DRV_UNSUPPORT_FMT BIT(19)
#define MTK_WED_WPDMA_GLO_CFG_RX_DRV_EVENT_PKT_FMT_CHK BIT(20)
#define MTK_WED_WPDMA_GLO_CFG_RX_DDONE2_WR BIT(21)
#define MTK_WED_WPDMA_GLO_CFG_TX_TKID_KEEP BIT(24)
#define MTK_WED_WPDMA_GLO_CFG_TX_DDONE_CHK_LAST BIT(25)
#define MTK_WED_WPDMA_GLO_CFG_TX_DMAD_DW3_PREV BIT(28)
#define MTK_WED_WPDMA_GLO_CFG_TX_DDONE_CHK BIT(30)
#define MTK_WED_WPDMA_RESET_IDX 0x50c
#define MTK_WED_WPDMA_RESET_IDX_TX GENMASK(3, 0)
#define MTK_WED_WPDMA_RESET_IDX_RX GENMASK(17, 16)
#define MTK_WED_WPDMA_CTRL 0x518
#define MTK_WED_WPDMA_CTRL_SDL1_FIXED BIT(31)
#define MTK_WED_WPDMA_INT_CTRL 0x520
#define MTK_WED_WPDMA_INT_CTRL_SUBRT_ADV BIT(21)
#define MTK_WED_WPDMA_INT_CTRL_SIG_SRC BIT(22)
#define MTK_WED_WPDMA_INT_CTRL_SRC_SEL GENMASK(17, 16)
#define MTK_WED_WPDMA_INT_MASK 0x524
#define MTK_WED_WPDMA_INT_CTRL_TX 0x530
#define MTK_WED_WPDMA_INT_CTRL_TX0_DONE_EN BIT(0)
#define MTK_WED_WPDMA_INT_CTRL_TX0_DONE_CLR BIT(1)
#define MTK_WED_WPDMA_INT_CTRL_TX0_DONE_TRIG GENMASK(6, 2)
#define MTK_WED_WPDMA_INT_CTRL_TX1_DONE_EN BIT(8)
#define MTK_WED_WPDMA_INT_CTRL_TX1_DONE_CLR BIT(9)
#define MTK_WED_WPDMA_INT_CTRL_TX1_DONE_TRIG GENMASK(14, 10)
#define MTK_WED_WPDMA_INT_CTRL_RX 0x534
#define MTK_WED_WPDMA_INT_CTRL_RX0_EN BIT(0)
#define MTK_WED_WPDMA_INT_CTRL_RX0_CLR BIT(1)
#define MTK_WED_WPDMA_INT_CTRL_RX0_DONE_TRIG GENMASK(6, 2)
#define MTK_WED_WPDMA_INT_CTRL_RX1_EN BIT(8)
#define MTK_WED_WPDMA_INT_CTRL_RX1_CLR BIT(9)
#define MTK_WED_WPDMA_INT_CTRL_RX1_DONE_TRIG GENMASK(14, 10)
#define MTK_WED_WPDMA_INT_CTRL_TX_FREE 0x538
#define MTK_WED_WPDMA_INT_CTRL_TX_FREE_DONE_EN BIT(0)
#define MTK_WED_WPDMA_INT_CTRL_TX_FREE_DONE_CLR BIT(1)
#define MTK_WED_WPDMA_INT_CTRL_TX_FREE_DONE_TRIG GENMASK(6, 2)
#define MTK_WED_PCIE_CFG_BASE 0x560
#define MTK_WED_PCIE_CFG_BASE 0x560
#define MTK_WED_PCIE_CFG_INTM 0x564
#define MTK_WED_PCIE_CFG_MSIS 0x568
#define MTK_WED_PCIE_INT_TRIGGER 0x570
#define MTK_WED_PCIE_INT_TRIGGER_STATUS BIT(16)
#define MTK_WED_PCIE_INT_CTRL 0x57c
#define MTK_WED_PCIE_INT_CTRL_POLL_EN GENMASK(13, 12)
#define MTK_WED_PCIE_INT_CTRL_SRC_SEL GENMASK(17, 16)
#define MTK_WED_PCIE_INT_CTRL_MSK_EN_POLA BIT(20)
#define MTK_WED_PCIE_INT_CTRL_MSK_IRQ_FILTER BIT(21)
#define MTK_WED_WPDMA_CFG_BASE 0x580
#define MTK_WED_WPDMA_CFG_INT_MASK 0x584
#define MTK_WED_WPDMA_CFG_TX 0x588
#define MTK_WED_WPDMA_CFG_TX_FREE 0x58c
#define MTK_WED_WPDMA_TX_MIB(_n) (0x5a0 + (_n) * 4)
#define MTK_WED_WPDMA_TX_COHERENT_MIB(_n) (0x5d0 + (_n) * 4)
#define MTK_WED_WPDMA_RX_MIB(_n) (0x5e0 + (_n) * 4)
#define MTK_WED_WPDMA_RX_COHERENT_MIB(_n) (0x5f0 + (_n) * 4)
#define MTK_WED_WPDMA_RING_TX(_n) (0x600 + (_n) * 0x10)
#define MTK_WED_WPDMA_RING_RX(_n) (0x700 + (_n) * 0x10)
#define MTK_WED_WPDMA_RING_RX_DATA(_n) (0x730 + (_n) * 0x10)
#define MTK_WED_WPDMA_RX_D_GLO_CFG 0x75c
#define MTK_WED_WPDMA_RX_D_RX_DRV_EN BIT(0)
#define MTK_WED_WPDMA_RX_D_RX_DRV_BUSY BIT(1)
#define MTK_WED_WPDMA_RX_D_FSM_RETURN_IDLE BIT(3)
#define MTK_WED_WPDMA_RX_D_RST_INIT_COMPLETE BIT(4)
#define MTK_WED_WPDMA_RX_D_INIT_PHASE_RXEN_SEL GENMASK(11, 7)
#define MTK_WED_WPDMA_RX_D_RXD_READ_LEN GENMASK(31, 24)
#define MTK_WED_WPDMA_RX_D_RST_IDX 0x760
#define MTK_WED_WPDMA_RX_D_RST_CRX_IDX GENMASK(17, 16)
#define MTK_WED_WPDMA_RX_D_RST_DRV_IDX_ALL BIT(20)
#define MTK_WED_WPDMA_RX_D_RST_DRV_IDX GENMASK(25, 24)
#define MTK_WED_WPDMA_RX_GLO_CFG 0x76c
#define MTK_WED_WPDMA_RX_D_MIB(_n) (0x774 + (_n) * 4)
#define MTK_WED_WPDMA_RX_D_PROCESSED_MIB(_n) (0x784 + (_n) * 4)
#define MTK_WED_WPDMA_RX_D_COHERENT_MIB 0x78c
#define MTK_WED_WPDMA_RX_D_PREF_CFG 0x7b4
#define MTK_WED_WPDMA_RX_D_PREF_EN BIT(0)
#define MTK_WED_WPDMA_RX_D_PREF_BUSY BIT(1)
#define MTK_WED_WPDMA_RX_D_PREF_BURST_SIZE GENMASK(12, 8)
#define MTK_WED_WPDMA_RX_D_PREF_LOW_THRES GENMASK(21, 16)
#define MTK_WED_WPDMA_RX_D_PREF_RX0_SIDX 0x7b8
#define MTK_WED_WPDMA_RX_D_PREF_SIDX_IDX_CLR BIT(15)
#define MTK_WED_WPDMA_RX_D_PREF_RX1_SIDX 0x7bc
#define MTK_WED_WPDMA_RX_D_PREF_FIFO_CFG 0x7c0
#define MTK_WED_WPDMA_RX_D_PREF_FIFO_CFG_R0_CLR BIT(0)
#define MTK_WED_WPDMA_RX_D_PREF_FIFO_CFG_R1_CLR BIT(16)
#define MTK_WED_WDMA_RING_TX 0x800
#define MTK_WED_WDMA_TX_MIB 0x810
#define MTK_WED_WDMA_RING_RX(_n) (0x900 + (_n) * 0x10)
#define MTK_WED_WDMA_RX_THRES(_n) (0x940 + (_n) * 0x4)
#define MTK_WED_WDMA_RX_PREF_CFG 0x950
#define MTK_WED_WDMA_RX_PREF_EN BIT(0)
#define MTK_WED_WDMA_RX_PREF_BUSY BIT(1)
#define MTK_WED_WDMA_RX_PREF_BURST_SIZE GENMASK(12, 8)
#define MTK_WED_WDMA_RX_PREF_LOW_THRES GENMASK(21, 16)
#define MTK_WED_WDMA_RX_PREF_RX0_SIDX_CLR BIT(24)
#define MTK_WED_WDMA_RX_PREF_RX1_SIDX_CLR BIT(25)
#define MTK_WED_WDMA_RX_PREF_DDONE2_EN BIT(26)
#define MTK_WED_WDMA_RX_PREF_DDONE2_BUSY BIT(27)
#define MTK_WED_WDMA_RX_PREF_FIFO_CFG 0x95C
#define MTK_WED_WDMA_RX_PREF_FIFO_RX0_CLR BIT(0)
#define MTK_WED_WDMA_RX_PREF_FIFO_RX1_CLR BIT(16)
#define MTK_WED_WDMA_GLO_CFG 0xa04
#define MTK_WED_WDMA_GLO_CFG_TX_DRV_EN BIT(0)
#define MTK_WED_WDMA_GLO_CFG_TX_DDONE_CHK BIT(1)
#define MTK_WED_WDMA_GLO_CFG_RX_DRV_EN BIT(2)
#define MTK_WED_WDMA_GLO_CFG_RX_DRV_BUSY BIT(3)
#define MTK_WED_WDMA_GLO_CFG_BT_SIZE GENMASK(5, 4)
#define MTK_WED_WDMA_GLO_CFG_TX_WB_DDONE BIT(6)
#define MTK_WED_WDMA_GLO_CFG_RX_DIS_FSM_AUTO_IDLE BIT(13)
#define MTK_WED_WDMA_GLO_CFG_WCOMPLETE_SEL BIT(16)
#define MTK_WED_WDMA_GLO_CFG_INIT_PHASE_RXDMA_BYPASS BIT(17)
#define MTK_WED_WDMA_GLO_CFG_INIT_PHASE_BYPASS BIT(18)
#define MTK_WED_WDMA_GLO_CFG_FSM_RETURN_IDLE BIT(19)
#define MTK_WED_WDMA_GLO_CFG_WAIT_COHERENT BIT(20)
#define MTK_WED_WDMA_GLO_CFG_AXI_W_AFTER_AW BIT(21)
#define MTK_WED_WDMA_GLO_CFG_IDLE_DMAD_SUPPLY_SINGLE_W BIT(22)
#define MTK_WED_WDMA_GLO_CFG_IDLE_DMAD_SUPPLY BIT(23)
#define MTK_WED_WDMA_GLO_CFG_DYNAMIC_SKIP_DMAD_PREP BIT(24)
#define MTK_WED_WDMA_GLO_CFG_DYNAMIC_DMAD_RECYCLE BIT(25)
#define MTK_WED_WDMA_GLO_CFG_RST_INIT_COMPLETE BIT(26)
#define MTK_WED_WDMA_GLO_CFG_RXDRV_CLKGATE_BYPASS BIT(30)
#define MTK_WED_WDMA_RESET_IDX 0xa08
#define MTK_WED_WDMA_RESET_IDX_RX GENMASK(17, 16)
#define MTK_WED_WDMA_RESET_IDX_RX_ALL BIT(20)
#define MTK_WED_WDMA_RESET_IDX_DRV GENMASK(25, 24)
#define MTK_WED_WDMA_INT_CLR 0xa24
#define MTK_WED_WDMA_INT_CLR_RX_DONE GENMASK(17, 16)
#define MTK_WED_WDMA_INT_TRIGGER 0xa28
#define MTK_WED_WDMA_INT_TRIGGER_RX_DONE GENMASK(17, 16)
#define MTK_WED_WDMA_INT_CTRL 0xa2c
#define MTK_WED_WDMA_INT_POLL_PRD GENMASK(7, 0)
#define MTK_WED_WDMA_INT_CTRL_POLL_SRC_SEL GENMASK(17, 16)
#define MTK_WED_WDMA_CFG_BASE 0xaa0
#define MTK_WED_WDMA_OFFSET0 0xaa4
#define MTK_WED_WDMA_OFFSET1 0xaa8
#define MTK_WED_WDMA_OFST0_GLO_INTS GENMASK(15, 0)
#define MTK_WED_WDMA_OFST0_GLO_CFG GENMASK(31, 16)
#define MTK_WED_WDMA_OFST1_TX_CTRL GENMASK(15, 0)
#define MTK_WED_WDMA_OFST1_RX_CTRL GENMASK(31, 16)
#define MTK_WED_WDMA_RX_MIB(_n) (0xae0 + (_n) * 4)
#define MTK_WED_WDMA_RX_RECYCLE_MIB(_n) (0xae8 + (_n) * 4)
#define MTK_WED_WDMA_RX_PROCESSED_MIB(_n) (0xaf0 + (_n) * 4)
#define MTK_WED_RX_BM_RX_DMAD 0xd80
#define MTK_WED_RX_BM_RX_DMAD_SDL0 GENMASK(13, 0)
#define MTK_WED_RX_BM_BASE 0xd84
#define MTK_WED_RX_BM_INIT_PTR 0xd88
#define MTK_WED_RX_BM_SW_TAIL GENMASK(15, 0)
#define MTK_WED_RX_BM_INIT_SW_TAIL BIT(16)
#define MTK_WED_RX_PTR 0xd8c
#define MTK_WED_RX_BM_DYN_ALLOC_TH 0xdb4
#define MTK_WED_RX_BM_DYN_ALLOC_TH_H GENMASK(31, 16)
#define MTK_WED_RX_BM_DYN_ALLOC_TH_L GENMASK(15, 0)
#define MTK_WED_RING_OFS_BASE 0x00
#define MTK_WED_RING_OFS_COUNT 0x04
#define MTK_WED_RING_OFS_CPU_IDX 0x08
#define MTK_WED_RING_OFS_DMA_IDX 0x0c
#define MTK_WDMA_RING_TX(_n) (0x000 + (_n) * 0x10)
#define MTK_WDMA_RING_RX(_n) (0x100 + (_n) * 0x10)
#define MTK_WDMA_GLO_CFG 0x204
#define MTK_WDMA_GLO_CFG_TX_DMA_EN BIT(0)
#define MTK_WDMA_GLO_CFG_TX_DMA_BUSY BIT(1)
#define MTK_WDMA_GLO_CFG_RX_DMA_EN BIT(2)
#define MTK_WDMA_GLO_CFG_RX_DMA_BUSY BIT(3)
#define MTK_WDMA_GLO_CFG_RX_INFO3_PRERES BIT(26)
#define MTK_WDMA_GLO_CFG_RX_INFO2_PRERES BIT(27)
#define MTK_WDMA_GLO_CFG_RX_INFO1_PRERES BIT(28)
#define MTK_WDMA_RESET_IDX 0x208
#define MTK_WDMA_RESET_IDX_TX GENMASK(3, 0)
#define MTK_WDMA_RESET_IDX_RX GENMASK(17, 16)
#define MTK_WDMA_INT_STATUS 0x220
#define MTK_WDMA_INT_MASK 0x228
#define MTK_WDMA_INT_MASK_TX_DONE GENMASK(3, 0)
#define MTK_WDMA_INT_MASK_RX_DONE GENMASK(17, 16)
#define MTK_WDMA_INT_MASK_TX_DELAY BIT(28)
#define MTK_WDMA_INT_MASK_TX_COHERENT BIT(29)
#define MTK_WDMA_INT_MASK_RX_DELAY BIT(30)
#define MTK_WDMA_INT_MASK_RX_COHERENT BIT(31)
#define MTK_WDMA_XDMA_TX_FIFO_CFG 0x238
#define MTK_WDMA_XDMA_TX_FIFO_CFG_TX_PAR_FIFO_CLEAR BIT(0)
#define MTK_WDMA_XDMA_TX_FIFO_CFG_TX_CMD_FIFO_CLEAR BIT(4)
#define MTK_WDMA_XDMA_TX_FIFO_CFG_TX_DMAD_FIFO_CLEAR BIT(8)
#define MTK_WDMA_XDMA_TX_FIFO_CFG_TX_ARR_FIFO_CLEAR BIT(12)
#define MTK_WDMA_XDMA_RX_FIFO_CFG 0x23c
#define MTK_WDMA_XDMA_RX_FIFO_CFG_RX_PAR_FIFO_CLEAR BIT(0)
#define MTK_WDMA_XDMA_RX_FIFO_CFG_RX_CMD_FIFO_CLEAR BIT(4)
#define MTK_WDMA_XDMA_RX_FIFO_CFG_RX_DMAD_FIFO_CLEAR BIT(8)
#define MTK_WDMA_XDMA_RX_FIFO_CFG_RX_ARR_FIFO_CLEAR BIT(12)
#define MTK_WDMA_XDMA_RX_FIFO_CFG_RX_LEN_FIFO_CLEAR BIT(15)
#define MTK_WDMA_XDMA_RX_FIFO_CFG_RX_WID_FIFO_CLEAR BIT(18)
#define MTK_WDMA_XDMA_RX_FIFO_CFG_RX_BID_FIFO_CLEAR BIT(21)
#define MTK_WDMA_INT_GRP1 0x250
#define MTK_WDMA_INT_GRP2 0x254
#define MTK_WDMA_PREF_TX_CFG 0x2d0
#define MTK_WDMA_PREF_TX_CFG_PREF_EN BIT(0)
#define MTK_WDMA_PREF_TX_CFG_PREF_BUSY BIT(1)
#define MTK_WDMA_PREF_RX_CFG 0x2dc
#define MTK_WDMA_PREF_RX_CFG_PREF_EN BIT(0)
#define MTK_WDMA_PREF_RX_CFG_PREF_BUSY BIT(1)
#define MTK_WDMA_PREF_RX_FIFO_CFG 0x2e0
#define MTK_WDMA_PREF_RX_FIFO_CFG_RING0_CLEAR BIT(0)
#define MTK_WDMA_PREF_RX_FIFO_CFG_RING1_CLEAR BIT(16)
#define MTK_WDMA_PREF_TX_FIFO_CFG 0x2d4
#define MTK_WDMA_PREF_TX_FIFO_CFG_RING0_CLEAR BIT(0)
#define MTK_WDMA_PREF_TX_FIFO_CFG_RING1_CLEAR BIT(16)
#define MTK_WDMA_PREF_SIDX_CFG 0x2e4
#define MTK_WDMA_PREF_SIDX_CFG_TX_RING_CLEAR GENMASK(3, 0)
#define MTK_WDMA_PREF_SIDX_CFG_RX_RING_CLEAR GENMASK(5, 4)
#define MTK_WDMA_WRBK_TX_CFG 0x300
#define MTK_WDMA_WRBK_TX_CFG_WRBK_BUSY BIT(0)
#define MTK_WDMA_WRBK_TX_CFG_WRBK_EN BIT(30)
#define MTK_WDMA_WRBK_TX_FIFO_CFG(_n) (0x304 + (_n) * 0x4)
#define MTK_WDMA_WRBK_TX_FIFO_CFG_RING_CLEAR BIT(0)
#define MTK_WDMA_WRBK_RX_CFG 0x344
#define MTK_WDMA_WRBK_RX_CFG_WRBK_BUSY BIT(0)
#define MTK_WDMA_WRBK_RX_CFG_WRBK_EN BIT(30)
#define MTK_WDMA_WRBK_RX_FIFO_CFG(_n) (0x348 + (_n) * 0x4)
#define MTK_WDMA_WRBK_RX_FIFO_CFG_RING_CLEAR BIT(0)
#define MTK_WDMA_WRBK_SIDX_CFG 0x388
#define MTK_WDMA_WRBK_SIDX_CFG_TX_RING_CLEAR GENMASK(3, 0)
#define MTK_WDMA_WRBK_SIDX_CFG_RX_RING_CLEAR GENMASK(5, 4)
#define MTK_PCIE_MIRROR_MAP(n) ((n) ? 0x4 : 0x0)
#define MTK_PCIE_MIRROR_MAP_EN BIT(0)
#define MTK_PCIE_MIRROR_MAP_WED_ID BIT(1)
/* DMA channel mapping */
#define HIFSYS_DMA_AG_MAP 0x008
#define MTK_WED_RTQM_GLO_CFG 0xb00
#define MTK_WED_RTQM_BUSY BIT(1)
#define MTK_WED_RTQM_Q_RST BIT(2)
#define MTK_WED_RTQM_Q_DBG_BYPASS BIT(5)
#define MTK_WED_RTQM_TXDMAD_FPORT GENMASK(23, 20)
#define MTK_WED_RTQM_RST 0xb04
#define MTK_WED_RTQM_IGRS0_I2HW_DMAD_CNT 0xb1c
#define MTK_WED_RTQM_IGRS0_I2H_DMAD_CNT(_n) (0xb20 + (_n) * 0x4)
#define MTK_WED_RTQM_IGRS0_I2HW_PKT_CNT 0xb28
#define MTK_WED_RTQM_IGRS0_I2H_PKT_CNT(_n) (0xb2c + (_n) * 0x4)
#define MTK_WED_RTQM_IGRS0_FDROP_CNT 0xb34
#define MTK_WED_RTQM_IGRS1_I2HW_DMAD_CNT 0xb44
#define MTK_WED_RTQM_IGRS1_I2H_DMAD_CNT(_n) (0xb48 + (_n) * 0x4)
#define MTK_WED_RTQM_IGRS1_I2HW_PKT_CNT 0xb50
#define MTK_WED_RTQM_IGRS1_I2H_PKT_CNT(_n) (0xb54 + (_n) * 0x4)
#define MTK_WED_RTQM_IGRS1_FDROP_CNT 0xb5c
#define MTK_WED_RTQM_IGRS2_I2HW_DMAD_CNT 0xb6c
#define MTK_WED_RTQM_IGRS2_I2H_DMAD_CNT(_n) (0xb70 + (_n) * 0x4)
#define MTK_WED_RTQM_IGRS2_I2HW_PKT_CNT 0xb78
#define MTK_WED_RTQM_IGRS2_I2H_PKT_CNT(_n) (0xb7c + (_n) * 0x4)
#define MTK_WED_RTQM_IGRS2_FDROP_CNT 0xb84
#define MTK_WED_RTQM_IGRS3_I2HW_DMAD_CNT 0xb94
#define MTK_WED_RTQM_IGRS3_I2H_DMAD_CNT(_n) (0xb98 + (_n) * 0x4)
#define MTK_WED_RTQM_IGRS3_I2HW_PKT_CNT 0xba0
#define MTK_WED_RTQM_IGRS3_I2H_PKT_CNT(_n) (0xba4 + (_n) * 0x4)
#define MTK_WED_RTQM_IGRS3_FDROP_CNT 0xbac
#define MTK_WED_RTQM_R2H_MIB(_n) (0xb70 + (_n) * 0x4)
#define MTK_WED_RTQM_R2Q_MIB(_n) (0xb78 + (_n) * 0x4)
#define MTK_WED_RTQM_Q2N_MIB 0xb80
#define MTK_WED_RTQM_Q2H_MIB(_n) (0xb84 + (_n) * 0x4)
#define MTK_WED_RTQM_Q2B_MIB 0xb8c
#define MTK_WED_RTQM_PFDBK_MIB 0xb90
#define MTK_WED_RTQM_ENQ_CFG0 0xbb8
#define MTK_WED_RTQM_ENQ_CFG_TXDMAD_FPORT GENMASK(15, 12)
#define MTK_WED_RTQM_FDROP_MIB 0xb84
#define MTK_WED_RTQM_ENQ_I2Q_DMAD_CNT 0xbbc
#define MTK_WED_RTQM_ENQ_I2N_DMAD_CNT 0xbc0
#define MTK_WED_RTQM_ENQ_I2Q_PKT_CNT 0xbc4
#define MTK_WED_RTQM_ENQ_I2N_PKT_CNT 0xbc8
#define MTK_WED_RTQM_ENQ_USED_ENTRY_CNT 0xbcc
#define MTK_WED_RTQM_ENQ_ERR_CNT 0xbd0
#define MTK_WED_RTQM_DEQ_DMAD_CNT 0xbd8
#define MTK_WED_RTQM_DEQ_Q2I_DMAD_CNT 0xbdc
#define MTK_WED_RTQM_DEQ_PKT_CNT 0xbe0
#define MTK_WED_RTQM_DEQ_Q2I_PKT_CNT 0xbe4
#define MTK_WED_RTQM_DEQ_USED_PFDBK_CNT 0xbe8
#define MTK_WED_RTQM_DEQ_ERR_CNT 0xbec
#define MTK_WED_RROQM_GLO_CFG 0xc04
#define MTK_WED_RROQM_RST_IDX 0xc08
#define MTK_WED_RROQM_RST_IDX_MIOD BIT(0)
#define MTK_WED_RROQM_RST_IDX_FDBK BIT(4)
#define MTK_WED_RROQM_MIOD_CTRL0 0xc40
#define MTK_WED_RROQM_MIOD_CTRL1 0xc44
#define MTK_WED_RROQM_MIOD_CNT GENMASK(11, 0)
#define MTK_WED_RROQM_MIOD_CTRL2 0xc48
#define MTK_WED_RROQM_MIOD_CTRL3 0xc4c
#define MTK_WED_RROQM_FDBK_CTRL0 0xc50
#define MTK_WED_RROQM_FDBK_CTRL1 0xc54
#define MTK_WED_RROQM_FDBK_CNT GENMASK(11, 0)
#define MTK_WED_RROQM_FDBK_CTRL2 0xc58
#define MTK_WED_RROQ_BASE_L 0xc80
#define MTK_WED_RROQ_BASE_H 0xc84
#define MTK_WED_RROQM_MIOD_CFG 0xc8c
#define MTK_WED_RROQM_MIOD_MID_DW GENMASK(5, 0)
#define MTK_WED_RROQM_MIOD_MOD_DW GENMASK(13, 8)
#define MTK_WED_RROQM_MIOD_ENTRY_DW GENMASK(22, 16)
#define MTK_WED_RROQM_MID_MIB 0xcc0
#define MTK_WED_RROQM_MOD_MIB 0xcc4
#define MTK_WED_RROQM_MOD_COHERENT_MIB 0xcc8
#define MTK_WED_RROQM_FDBK_MIB 0xcd0
#define MTK_WED_RROQM_FDBK_COHERENT_MIB 0xcd4
#define MTK_WED_RROQM_FDBK_IND_MIB 0xce0
#define MTK_WED_RROQM_FDBK_ENQ_MIB 0xce4
#define MTK_WED_RROQM_FDBK_ANC_MIB 0xce8
#define MTK_WED_RROQM_FDBK_ANC2H_MIB 0xcec
#define MTK_WED_RX_BM_RX_DMAD 0xd80
#define MTK_WED_RX_BM_BASE 0xd84
#define MTK_WED_RX_BM_INIT_PTR 0xd88
#define MTK_WED_RX_BM_PTR 0xd8c
#define MTK_WED_RX_BM_PTR_HEAD GENMASK(32, 16)
#define MTK_WED_RX_BM_PTR_TAIL GENMASK(15, 0)
#define MTK_WED_RX_BM_BLEN 0xd90
#define MTK_WED_RX_BM_STS 0xd94
#define MTK_WED_RX_BM_INTF2 0xd98
#define MTK_WED_RX_BM_INTF 0xd9c
#define MTK_WED_RX_BM_ERR_STS 0xda8
#define MTK_RRO_IND_CMD_SIGNATURE 0xe00
#define MTK_RRO_IND_CMD_DMA_IDX GENMASK(11, 0)
#define MTK_RRO_IND_CMD_MAGIC_CNT GENMASK(30, 28)
#define MTK_WED_IND_CMD_RX_CTRL0 0xe04
#define MTK_WED_IND_CMD_PROC_IDX GENMASK(11, 0)
#define MTK_WED_IND_CMD_PREFETCH_FREE_CNT GENMASK(19, 16)
#define MTK_WED_IND_CMD_MAGIC_CNT GENMASK(30, 28)
#define MTK_WED_IND_CMD_RX_CTRL1 0xe08
#define MTK_WED_IND_CMD_RX_CTRL2 0xe0c
#define MTK_WED_IND_CMD_MAX_CNT GENMASK(11, 0)
#define MTK_WED_IND_CMD_BASE_M GENMASK(19, 16)
#define MTK_WED_RRO_CFG0 0xe10
#define MTK_WED_RRO_CFG1 0xe14
#define MTK_WED_RRO_CFG1_MAX_WIN_SZ GENMASK(31, 29)
#define MTK_WED_RRO_CFG1_ACK_SN_BASE_M GENMASK(19, 16)
#define MTK_WED_RRO_CFG1_PARTICL_SE_ID GENMASK(11, 0)
#define MTK_WED_ADDR_ELEM_CFG0 0xe18
#define MTK_WED_ADDR_ELEM_CFG1 0xe1c
#define MTK_WED_ADDR_ELEM_PREFETCH_FREE_CNT GENMASK(19, 16)
#define MTK_WED_ADDR_ELEM_TBL_CFG 0xe20
#define MTK_WED_ADDR_ELEM_TBL_OFFSET GENMASK(6, 0)
#define MTK_WED_ADDR_ELEM_TBL_RD_RDY BIT(28)
#define MTK_WED_ADDR_ELEM_TBL_WR_RDY BIT(29)
#define MTK_WED_ADDR_ELEM_TBL_RD BIT(30)
#define MTK_WED_ADDR_ELEM_TBL_WR BIT(31)
#define MTK_WED_RADDR_ELEM_TBL_WDATA 0xe24
#define MTK_WED_RADDR_ELEM_TBL_RDATA 0xe28
#define MTK_WED_PN_CHECK_CFG 0xe30
#define MTK_WED_PN_CHECK_SE_ID GENMASK(11, 0)
#define MTK_WED_PN_CHECK_RD_RDY BIT(28)
#define MTK_WED_PN_CHECK_WR_RDY BIT(29)
#define MTK_WED_PN_CHECK_RD BIT(30)
#define MTK_WED_PN_CHECK_WR BIT(31)
#define MTK_WED_PN_CHECK_WDATA_M 0xe38
#define MTK_WED_PN_CHECK_IS_FIRST BIT(17)
#define MTK_WED_RRO_MSDU_PG_RING_CFG(_n) (0xe44 + (_n) * 0x8)
#define MTK_WED_RRO_MSDU_PG_RING2_CFG 0xe58
#define MTK_WED_RRO_MSDU_PG_DRV_CLR BIT(26)
#define MTK_WED_RRO_MSDU_PG_DRV_EN BIT(31)
#define MTK_WED_RRO_MSDU_PG_CTRL0(_n) (0xe5c + (_n) * 0xc)
#define MTK_WED_RRO_MSDU_PG_CTRL1(_n) (0xe60 + (_n) * 0xc)
#define MTK_WED_RRO_MSDU_PG_CTRL2(_n) (0xe64 + (_n) * 0xc)
#define MTK_WED_RRO_RX_D_RX(_n) (0xe80 + (_n) * 0x10)
#define MTK_WED_RRO_RX_MAGIC_CNT BIT(13)
#define MTK_WED_RRO_RX_D_CFG(_n) (0xea0 + (_n) * 0x4)
#define MTK_WED_RRO_RX_D_DRV_CLR BIT(26)
#define MTK_WED_RRO_RX_D_DRV_EN BIT(31)
#define MTK_WED_RRO_PG_BM_RX_DMAM 0xeb0
#define MTK_WED_RRO_PG_BM_RX_SDL0 GENMASK(13, 0)
#define MTK_WED_RRO_PG_BM_BASE 0xeb4
#define MTK_WED_RRO_PG_BM_INIT_PTR 0xeb8
#define MTK_WED_RRO_PG_BM_SW_TAIL_IDX GENMASK(15, 0)
#define MTK_WED_RRO_PG_BM_INIT_SW_TAIL_IDX BIT(16)
#define MTK_WED_WPDMA_INT_CTRL_RRO_RX 0xeec
#define MTK_WED_WPDMA_INT_CTRL_RRO_RX0_EN BIT(0)
#define MTK_WED_WPDMA_INT_CTRL_RRO_RX0_CLR BIT(1)
#define MTK_WED_WPDMA_INT_CTRL_RRO_RX0_DONE_TRIG GENMASK(6, 2)
#define MTK_WED_WPDMA_INT_CTRL_RRO_RX1_EN BIT(8)
#define MTK_WED_WPDMA_INT_CTRL_RRO_RX1_CLR BIT(9)
#define MTK_WED_WPDMA_INT_CTRL_RRO_RX1_DONE_TRIG GENMASK(14, 10)
#define MTK_WED_WPDMA_INT_CTRL_RRO_MSDU_PG 0xef4
#define MTK_WED_WPDMA_INT_CTRL_RRO_PG0_EN BIT(0)
#define MTK_WED_WPDMA_INT_CTRL_RRO_PG0_CLR BIT(1)
#define MTK_WED_WPDMA_INT_CTRL_RRO_PG0_DONE_TRIG GENMASK(6, 2)
#define MTK_WED_WPDMA_INT_CTRL_RRO_PG1_EN BIT(8)
#define MTK_WED_WPDMA_INT_CTRL_RRO_PG1_CLR BIT(9)
#define MTK_WED_WPDMA_INT_CTRL_RRO_PG1_DONE_TRIG GENMASK(14, 10)
#define MTK_WED_WPDMA_INT_CTRL_RRO_PG2_EN BIT(16)
#define MTK_WED_WPDMA_INT_CTRL_RRO_PG2_CLR BIT(17)
#define MTK_WED_WPDMA_INT_CTRL_RRO_PG2_DONE_TRIG GENMASK(22, 18)
#define MTK_WED_RRO_RX_HW_STS 0xf00
#define MTK_WED_RX_IND_CMD_BUSY GENMASK(31, 0)
#define MTK_WED_RX_IND_CMD_CNT0 0xf20
#define MTK_WED_RX_IND_CMD_DBG_CNT_EN BIT(31)
#define MTK_WED_RX_IND_CMD_CNT(_n) (0xf20 + (_n) * 0x4)
#define MTK_WED_IND_CMD_MAGIC_CNT_FAIL_CNT GENMASK(15, 0)
#define MTK_WED_RX_ADDR_ELEM_CNT(_n) (0xf48 + (_n) * 0x4)
#define MTK_WED_ADDR_ELEM_SIG_FAIL_CNT GENMASK(15, 0)
#define MTK_WED_ADDR_ELEM_FIRST_SIG_FAIL_CNT GENMASK(31, 16)
#define MTK_WED_ADDR_ELEM_ACKSN_CNT GENMASK(27, 0)
#define MTK_WED_RX_MSDU_PG_CNT(_n) (0xf5c + (_n) * 0x4)
#define MTK_WED_RX_PN_CHK_CNT 0xf70
#define MTK_WED_PN_CHK_FAIL_CNT GENMASK(15, 0)
#define MTK_WED_WOCPU_VIEW_MIOD_BASE 0x8000
#define MTK_WED_PCIE_INT_MASK 0x0
#define MTK_WED_AMSDU_FIFO 0x1800
#define MTK_WED_AMSDU_IS_PRIOR0_RING BIT(10)
#define MTK_WED_AMSDU_STA_INFO 0x01810
#define MTK_WED_AMSDU_STA_INFO_DO_INIT BIT(0)
#define MTK_WED_AMSDU_STA_INFO_SET_INIT BIT(1)
#define MTK_WED_AMSDU_STA_INFO_INIT 0x01814
#define MTK_WED_AMSDU_STA_WTBL_HDRT_MODE BIT(0)
#define MTK_WED_AMSDU_STA_RMVL BIT(1)
#define MTK_WED_AMSDU_STA_MAX_AMSDU_LEN GENMASK(7, 2)
#define MTK_WED_AMSDU_STA_MAX_AMSDU_NUM GENMASK(11, 8)
#define MTK_WED_AMSDU_HIFTXD_BASE_L(_n) (0x1980 + (_n) * 0x4)
#define MTK_WED_AMSDU_PSE 0x1910
#define MTK_WED_AMSDU_PSE_RESET BIT(16)
#define MTK_WED_AMSDU_HIFTXD_CFG 0x1968
#define MTK_WED_AMSDU_HIFTXD_SRC GENMASK(16, 15)
#define MTK_WED_MON_AMSDU_FIFO_DMAD 0x1a34
#define MTK_WED_MON_AMSDU_ENG_DMAD(_n) (0x1a80 + (_n) * 0x50)
#define MTK_WED_MON_AMSDU_ENG_QFPL(_n) (0x1a84 + (_n) * 0x50)
#define MTK_WED_MON_AMSDU_ENG_QENI(_n) (0x1a88 + (_n) * 0x50)
#define MTK_WED_MON_AMSDU_ENG_QENO(_n) (0x1a8c + (_n) * 0x50)
#define MTK_WED_MON_AMSDU_ENG_MERG(_n) (0x1a90 + (_n) * 0x50)
#define MTK_WED_MON_AMSDU_ENG_CNT8(_n) (0x1a94 + (_n) * 0x50)
#define MTK_WED_AMSDU_ENG_MAX_QGPP_CNT GENMASK(10, 0)
#define MTK_WED_AMSDU_ENG_MAX_PL_CNT GENMASK(27, 16)
#define MTK_WED_MON_AMSDU_ENG_CNT9(_n) (0x1a98 + (_n) * 0x50)
#define MTK_WED_AMSDU_ENG_CUR_ENTRY GENMASK(10, 0)
#define MTK_WED_AMSDU_ENG_MAX_BUF_MERGED GENMASK(20, 16)
#define MTK_WED_AMSDU_ENG_MAX_MSDU_MERGED GENMASK(28, 24)
#define MTK_WED_MON_AMSDU_QMEM_STS1 0x1e04
#define MTK_WED_MON_AMSDU_QMEM_CNT(_n) (0x1e0c + (_n) * 0x4)
#define MTK_WED_AMSDU_QMEM_FQ_CNT GENMASK(27, 16)
#define MTK_WED_AMSDU_QMEM_SP_QCNT GENMASK(11, 0)
#define MTK_WED_AMSDU_QMEM_TID0_QCNT GENMASK(27, 16)
#define MTK_WED_AMSDU_QMEM_TID1_QCNT GENMASK(11, 0)
#define MTK_WED_AMSDU_QMEM_TID2_QCNT GENMASK(27, 16)
#define MTK_WED_AMSDU_QMEM_TID3_QCNT GENMASK(11, 0)
#define MTK_WED_AMSDU_QMEM_TID4_QCNT GENMASK(27, 16)
#define MTK_WED_AMSDU_QMEM_TID5_QCNT GENMASK(11, 0)
#define MTK_WED_AMSDU_QMEM_TID6_QCNT GENMASK(27, 16)
#define MTK_WED_AMSDU_QMEM_TID7_QCNT GENMASK(11, 0)
#define MTK_WED_MON_AMSDU_QMEM_PTR(_n) (0x1e20 + (_n) * 0x4)
#define MTK_WED_AMSDU_QMEM_FQ_HEAD GENMASK(27, 16)
#define MTK_WED_AMSDU_QMEM_SP_QHEAD GENMASK(11, 0)
#define MTK_WED_AMSDU_QMEM_TID0_QHEAD GENMASK(27, 16)
#define MTK_WED_AMSDU_QMEM_TID1_QHEAD GENMASK(11, 0)
#define MTK_WED_AMSDU_QMEM_TID2_QHEAD GENMASK(27, 16)
#define MTK_WED_AMSDU_QMEM_TID3_QHEAD GENMASK(11, 0)
#define MTK_WED_AMSDU_QMEM_TID4_QHEAD GENMASK(27, 16)
#define MTK_WED_AMSDU_QMEM_TID5_QHEAD GENMASK(11, 0)
#define MTK_WED_AMSDU_QMEM_TID6_QHEAD GENMASK(27, 16)
#define MTK_WED_AMSDU_QMEM_TID7_QHEAD GENMASK(11, 0)
#define MTK_WED_AMSDU_QMEM_FQ_TAIL GENMASK(27, 16)
#define MTK_WED_AMSDU_QMEM_SP_QTAIL GENMASK(11, 0)
#define MTK_WED_AMSDU_QMEM_TID0_QTAIL GENMASK(27, 16)
#define MTK_WED_AMSDU_QMEM_TID1_QTAIL GENMASK(11, 0)
#define MTK_WED_AMSDU_QMEM_TID2_QTAIL GENMASK(27, 16)
#define MTK_WED_AMSDU_QMEM_TID3_QTAIL GENMASK(11, 0)
#define MTK_WED_AMSDU_QMEM_TID4_QTAIL GENMASK(27, 16)
#define MTK_WED_AMSDU_QMEM_TID5_QTAIL GENMASK(11, 0)
#define MTK_WED_AMSDU_QMEM_TID6_QTAIL GENMASK(27, 16)
#define MTK_WED_AMSDU_QMEM_TID7_QTAIL GENMASK(11, 0)
#define MTK_WED_MON_AMSDU_HIFTXD_FETCH_MSDU(_n) (0x1ec4 + (_n) * 0x4)
#define MTK_WED_PCIE_BASE 0x11280000
#define MTK_WED_PCIE_BASE0 0x11300000
#define MTK_WED_PCIE_BASE1 0x11310000
#define MTK_WED_PCIE_BASE2 0x11290000
#endif
@@ -0,0 +1,491 @@
// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (C) 2022 MediaTek Inc.
*
* Author: Lorenzo Bianconi <lorenzo@kernel.org>
* Sujuan Chen <sujuan.chen@mediatek.com>
*/
#include <linux/kernel.h>
#include <linux/dma-mapping.h>
#include <linux/interrupt.h>
#include <linux/mfd/syscon.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/bitfield.h>
#include "mtk_wed.h"
#include "mtk_wed_regs.h"
#include "mtk_wed_wo.h"
static u32
mtk_wed_mmio_r32(struct mtk_wed_wo *wo, u32 reg)
{
u32 val;
if (regmap_read(wo->mmio.regs, reg, &val))
val = ~0;
return val;
}
static void
mtk_wed_mmio_w32(struct mtk_wed_wo *wo, u32 reg, u32 val)
{
regmap_write(wo->mmio.regs, reg, val);
}
static u32
mtk_wed_wo_get_isr(struct mtk_wed_wo *wo)
{
u32 val = mtk_wed_mmio_r32(wo, MTK_WED_WO_CCIF_RCHNUM);
return val & MTK_WED_WO_CCIF_RCHNUM_MASK;
}
static void
mtk_wed_wo_set_isr(struct mtk_wed_wo *wo, u32 mask)
{
mtk_wed_mmio_w32(wo, MTK_WED_WO_CCIF_IRQ0_MASK, mask);
}
static void
mtk_wed_wo_set_ack(struct mtk_wed_wo *wo, u32 mask)
{
mtk_wed_mmio_w32(wo, MTK_WED_WO_CCIF_ACK, mask);
}
static void
mtk_wed_wo_set_isr_mask(struct mtk_wed_wo *wo, u32 mask, u32 val, bool set)
{
unsigned long flags;
spin_lock_irqsave(&wo->mmio.lock, flags);
wo->mmio.irq_mask &= ~mask;
wo->mmio.irq_mask |= val;
if (set)
mtk_wed_wo_set_isr(wo, wo->mmio.irq_mask);
spin_unlock_irqrestore(&wo->mmio.lock, flags);
}
static void
mtk_wed_wo_irq_enable(struct mtk_wed_wo *wo, u32 mask)
{
mtk_wed_wo_set_isr_mask(wo, 0, mask, false);
tasklet_schedule(&wo->mmio.irq_tasklet);
}
static void
mtk_wed_wo_irq_disable(struct mtk_wed_wo *wo, u32 mask)
{
mtk_wed_wo_set_isr_mask(wo, mask, 0, true);
}
static void
mtk_wed_wo_kickout(struct mtk_wed_wo *wo)
{
mtk_wed_mmio_w32(wo, MTK_WED_WO_CCIF_BUSY, 1 << MTK_WED_WO_TXCH_NUM);
mtk_wed_mmio_w32(wo, MTK_WED_WO_CCIF_TCHNUM, MTK_WED_WO_TXCH_NUM);
}
static void
mtk_wed_wo_queue_kick(struct mtk_wed_wo *wo, struct mtk_wed_wo_queue *q,
u32 val)
{
wmb();
mtk_wed_mmio_w32(wo, q->regs.cpu_idx, val);
}
static void *
mtk_wed_wo_dequeue(struct mtk_wed_wo *wo, struct mtk_wed_wo_queue *q, u32 *len,
bool flush)
{
int buf_len = SKB_WITH_OVERHEAD(q->buf_size);
int index = (q->tail + 1) % q->n_desc;
struct mtk_wed_wo_queue_entry *entry;
struct mtk_wed_wo_queue_desc *desc;
void *buf;
if (!q->queued)
return NULL;
if (flush)
q->desc[index].ctrl |= cpu_to_le32(MTK_WED_WO_CTL_DMA_DONE);
else if (!(q->desc[index].ctrl & cpu_to_le32(MTK_WED_WO_CTL_DMA_DONE)))
return NULL;
q->tail = index;
q->queued--;
desc = &q->desc[index];
entry = &q->entry[index];
buf = entry->buf;
if (len)
*len = FIELD_GET(MTK_WED_WO_CTL_SD_LEN0,
le32_to_cpu(READ_ONCE(desc->ctrl)));
if (buf)
dma_unmap_single(wo->hw->dev, entry->addr, buf_len,
DMA_FROM_DEVICE);
entry->buf = NULL;
return buf;
}
static int
mtk_wed_wo_queue_refill(struct mtk_wed_wo *wo, struct mtk_wed_wo_queue *q,
bool rx)
{
enum dma_data_direction dir = rx ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
int n_buf = 0;
while (q->queued < q->n_desc) {
struct mtk_wed_wo_queue_entry *entry;
dma_addr_t addr;
void *buf;
buf = page_frag_alloc(&q->cache, q->buf_size,
GFP_ATOMIC | GFP_DMA32);
if (!buf)
break;
addr = dma_map_single(wo->hw->dev, buf, q->buf_size, dir);
if (unlikely(dma_mapping_error(wo->hw->dev, addr))) {
skb_free_frag(buf);
break;
}
q->head = (q->head + 1) % q->n_desc;
entry = &q->entry[q->head];
entry->addr = addr;
entry->len = q->buf_size;
q->entry[q->head].buf = buf;
if (rx) {
struct mtk_wed_wo_queue_desc *desc = &q->desc[q->head];
u32 ctrl = MTK_WED_WO_CTL_LAST_SEC0 |
FIELD_PREP(MTK_WED_WO_CTL_SD_LEN0,
entry->len);
WRITE_ONCE(desc->buf0, cpu_to_le32(addr));
WRITE_ONCE(desc->ctrl, cpu_to_le32(ctrl));
}
q->queued++;
n_buf++;
}
return n_buf;
}
static void
mtk_wed_wo_rx_complete(struct mtk_wed_wo *wo)
{
mtk_wed_wo_set_ack(wo, MTK_WED_WO_RXCH_INT_MASK);
mtk_wed_wo_irq_enable(wo, MTK_WED_WO_RXCH_INT_MASK);
}
static void
mtk_wed_wo_rx_run_queue(struct mtk_wed_wo *wo, struct mtk_wed_wo_queue *q)
{
for (;;) {
struct mtk_wed_mcu_hdr *hdr;
struct sk_buff *skb;
void *data;
u32 len;
data = mtk_wed_wo_dequeue(wo, q, &len, false);
if (!data)
break;
skb = build_skb(data, q->buf_size);
if (!skb) {
skb_free_frag(data);
continue;
}
__skb_put(skb, len);
if (mtk_wed_mcu_check_msg(wo, skb)) {
dev_kfree_skb(skb);
continue;
}
hdr = (struct mtk_wed_mcu_hdr *)skb->data;
if (hdr->flag & cpu_to_le16(MTK_WED_WARP_CMD_FLAG_RSP))
mtk_wed_mcu_rx_event(wo, skb);
else
mtk_wed_mcu_rx_unsolicited_event(wo, skb);
}
if (mtk_wed_wo_queue_refill(wo, q, true)) {
u32 index = (q->head - 1) % q->n_desc;
mtk_wed_wo_queue_kick(wo, q, index);
}
}
static irqreturn_t
mtk_wed_wo_irq_handler(int irq, void *data)
{
struct mtk_wed_wo *wo = data;
mtk_wed_wo_set_isr(wo, 0);
tasklet_schedule(&wo->mmio.irq_tasklet);
return IRQ_HANDLED;
}
static void mtk_wed_wo_irq_tasklet(struct tasklet_struct *t)
{
struct mtk_wed_wo *wo = from_tasklet(wo, t, mmio.irq_tasklet);
u32 intr, mask;
/* disable interrupts */
mtk_wed_wo_set_isr(wo, 0);
intr = mtk_wed_wo_get_isr(wo);
intr &= wo->mmio.irq_mask;
mask = intr & (MTK_WED_WO_RXCH_INT_MASK | MTK_WED_WO_EXCEPTION_INT_MASK);
mtk_wed_wo_irq_disable(wo, mask);
if (intr & MTK_WED_WO_RXCH_INT_MASK) {
mtk_wed_wo_rx_run_queue(wo, &wo->q_rx);
mtk_wed_wo_rx_complete(wo);
}
}
/* mtk wed wo hw queues */
static int
mtk_wed_wo_queue_alloc(struct mtk_wed_wo *wo, struct mtk_wed_wo_queue *q,
int n_desc, int buf_size, int index,
struct mtk_wed_wo_queue_regs *regs)
{
q->regs = *regs;
q->n_desc = n_desc;
q->buf_size = buf_size;
q->desc = dmam_alloc_coherent(wo->hw->dev, n_desc * sizeof(*q->desc),
&q->desc_dma, GFP_KERNEL);
if (!q->desc)
return -ENOMEM;
q->entry = devm_kzalloc(wo->hw->dev, n_desc * sizeof(*q->entry),
GFP_KERNEL);
if (!q->entry)
return -ENOMEM;
return 0;
}
static void
mtk_wed_wo_queue_free(struct mtk_wed_wo *wo, struct mtk_wed_wo_queue *q)
{
mtk_wed_mmio_w32(wo, q->regs.cpu_idx, 0);
dma_free_coherent(wo->hw->dev, q->n_desc * sizeof(*q->desc), q->desc,
q->desc_dma);
}
static void
mtk_wed_wo_queue_tx_clean(struct mtk_wed_wo *wo, struct mtk_wed_wo_queue *q)
{
int i;
for (i = 0; i < q->n_desc; i++) {
struct mtk_wed_wo_queue_entry *entry = &q->entry[i];
if (!entry->buf)
continue;
dma_unmap_single(wo->hw->dev, entry->addr, entry->len,
DMA_TO_DEVICE);
skb_free_frag(entry->buf);
entry->buf = NULL;
}
page_frag_cache_drain(&q->cache);
}
static void
mtk_wed_wo_queue_rx_clean(struct mtk_wed_wo *wo, struct mtk_wed_wo_queue *q)
{
for (;;) {
void *buf = mtk_wed_wo_dequeue(wo, q, NULL, true);
if (!buf)
break;
skb_free_frag(buf);
}
page_frag_cache_drain(&q->cache);
}
static void
mtk_wed_wo_queue_reset(struct mtk_wed_wo *wo, struct mtk_wed_wo_queue *q)
{
mtk_wed_mmio_w32(wo, q->regs.cpu_idx, 0);
mtk_wed_mmio_w32(wo, q->regs.desc_base, q->desc_dma);
mtk_wed_mmio_w32(wo, q->regs.ring_size, q->n_desc);
}
int mtk_wed_wo_queue_tx_skb(struct mtk_wed_wo *wo, struct mtk_wed_wo_queue *q,
struct sk_buff *skb)
{
struct mtk_wed_wo_queue_entry *entry;
struct mtk_wed_wo_queue_desc *desc;
int ret = 0, index;
u32 ctrl;
q->tail = mtk_wed_mmio_r32(wo, q->regs.dma_idx);
index = (q->head + 1) % q->n_desc;
if (q->tail == index) {
ret = -ENOMEM;
goto out;
}
entry = &q->entry[index];
if (skb->len > entry->len) {
ret = -ENOMEM;
goto out;
}
desc = &q->desc[index];
q->head = index;
dma_sync_single_for_cpu(wo->hw->dev, entry->addr, skb->len,
DMA_TO_DEVICE);
memcpy(entry->buf, skb->data, skb->len);
dma_sync_single_for_device(wo->hw->dev, entry->addr, skb->len,
DMA_TO_DEVICE);
ctrl = FIELD_PREP(MTK_WED_WO_CTL_SD_LEN0, skb->len) |
MTK_WED_WO_CTL_LAST_SEC0 | MTK_WED_WO_CTL_DMA_DONE;
WRITE_ONCE(desc->buf0, cpu_to_le32(entry->addr));
WRITE_ONCE(desc->ctrl, cpu_to_le32(ctrl));
mtk_wed_wo_queue_kick(wo, q, q->head);
mtk_wed_wo_kickout(wo);
out:
dev_kfree_skb(skb);
return ret;
}
static int
mtk_wed_wo_exception_init(struct mtk_wed_wo *wo)
{
return 0;
}
static int
mtk_wed_wo_hardware_init(struct mtk_wed_wo *wo)
{
struct mtk_wed_wo_queue_regs regs;
struct device_node *np;
int ret;
np = of_parse_phandle(wo->hw->node, "mediatek,wo-ccif", 0);
if (!np)
return -ENODEV;
wo->mmio.regs = syscon_regmap_lookup_by_phandle(np, NULL);
if (IS_ERR(wo->mmio.regs)) {
ret = PTR_ERR(wo->mmio.regs);
goto error_put;
}
wo->mmio.irq = irq_of_parse_and_map(np, 0);
wo->mmio.irq_mask = MTK_WED_WO_ALL_INT_MASK;
spin_lock_init(&wo->mmio.lock);
tasklet_setup(&wo->mmio.irq_tasklet, mtk_wed_wo_irq_tasklet);
ret = devm_request_irq(wo->hw->dev, wo->mmio.irq,
mtk_wed_wo_irq_handler, IRQF_TRIGGER_HIGH,
KBUILD_MODNAME, wo);
if (ret)
goto error;
regs.desc_base = MTK_WED_WO_CCIF_DUMMY1;
regs.ring_size = MTK_WED_WO_CCIF_DUMMY2;
regs.dma_idx = MTK_WED_WO_CCIF_SHADOW4;
regs.cpu_idx = MTK_WED_WO_CCIF_DUMMY3;
ret = mtk_wed_wo_queue_alloc(wo, &wo->q_tx, MTK_WED_WO_RING_SIZE,
MTK_WED_WO_CMD_LEN, MTK_WED_WO_TXCH_NUM,
&regs);
if (ret)
goto error;
mtk_wed_wo_queue_refill(wo, &wo->q_tx, false);
mtk_wed_wo_queue_reset(wo, &wo->q_tx);
regs.desc_base = MTK_WED_WO_CCIF_DUMMY5;
regs.ring_size = MTK_WED_WO_CCIF_DUMMY6;
regs.dma_idx = MTK_WED_WO_CCIF_SHADOW8;
regs.cpu_idx = MTK_WED_WO_CCIF_DUMMY7;
ret = mtk_wed_wo_queue_alloc(wo, &wo->q_rx, MTK_WED_WO_RING_SIZE,
MTK_WED_WO_CMD_LEN, MTK_WED_WO_RXCH_NUM,
&regs);
if (ret)
goto error;
mtk_wed_wo_queue_refill(wo, &wo->q_rx, true);
mtk_wed_wo_queue_reset(wo, &wo->q_rx);
/* rx queue irqmask */
mtk_wed_wo_set_isr(wo, wo->mmio.irq_mask);
return 0;
error:
devm_free_irq(wo->hw->dev, wo->mmio.irq, wo);
error_put:
of_node_put(np);
return ret;
}
static void
mtk_wed_wo_hw_deinit(struct mtk_wed_wo *wo)
{
/* disable interrupts */
mtk_wed_wo_set_isr(wo, 0);
tasklet_disable(&wo->mmio.irq_tasklet);
disable_irq(wo->mmio.irq);
devm_free_irq(wo->hw->dev, wo->mmio.irq, wo);
mtk_wed_wo_queue_tx_clean(wo, &wo->q_tx);
mtk_wed_wo_queue_rx_clean(wo, &wo->q_rx);
mtk_wed_wo_queue_free(wo, &wo->q_tx);
mtk_wed_wo_queue_free(wo, &wo->q_rx);
}
int mtk_wed_wo_init(struct mtk_wed_hw *hw)
{
struct mtk_wed_wo *wo;
int ret;
wo = devm_kzalloc(hw->dev, sizeof(*wo), GFP_KERNEL);
if (!wo)
return -ENOMEM;
hw->wed_wo = wo;
wo->hw = hw;
ret = mtk_wed_wo_hardware_init(wo);
if (ret)
return ret;
ret = mtk_wed_mcu_init(wo);
if (ret)
return ret;
return mtk_wed_wo_exception_init(wo);
}
void mtk_wed_wo_deinit(struct mtk_wed_hw *hw)
{
struct mtk_wed_wo *wo = hw->wed_wo;
mtk_wed_wo_hw_deinit(wo);
}
@@ -0,0 +1,283 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* Copyright (C) 2022 Lorenzo Bianconi <lorenzo@kernel.org> */
#ifndef __MTK_WED_WO_H
#define __MTK_WED_WO_H
#include <linux/skbuff.h>
#include <linux/netdevice.h>
struct mtk_wed_hw;
struct mtk_wed_mcu_hdr {
/* DW0 */
u8 version;
u8 cmd;
__le16 length;
/* DW1 */
__le16 seq;
__le16 flag;
/* DW2 */
__le32 status;
/* DW3 */
u8 rsv[20];
};
struct mtk_wed_wo_log_info {
__le32 sn;
__le32 total;
__le32 rro;
__le32 mod;
};
enum mtk_wed_wo_event {
MTK_WED_WO_EVT_LOG_DUMP = 0x1,
MTK_WED_WO_EVT_PROFILING = 0x2,
MTK_WED_WO_EVT_RXCNT_INFO = 0x3,
};
#define MTK_WED_MODULE_ID_WO 1
#define MTK_FW_DL_TIMEOUT 4000000 /* us */
#define MTK_WOCPU_TIMEOUT 2000000 /* us */
enum {
MTK_WED_WARP_CMD_FLAG_RSP = BIT(0),
MTK_WED_WARP_CMD_FLAG_NEED_RSP = BIT(1),
MTK_WED_WARP_CMD_FLAG_FROM_TO_WO = BIT(2),
};
#define MTK_WED_WO_CPU_MCUSYS_RESET_ADDR 0x15194050
#define MTK_WED_WO_CPU_WO0_MCUSYS_RESET_MASK 0x20
#define MTK_WED_WO_CPU_WO1_MCUSYS_RESET_MASK 0x1
enum {
MTK_WED_WO_REGION_EMI,
MTK_WED_WO_REGION_ILM,
MTK_WED_WO_REGION_DATA,
MTK_WED_WO_REGION_BOOT,
__MTK_WED_WO_REGION_MAX,
};
enum mtk_wed_wo_state {
MTK_WED_WO_STATE_UNDEFINED,
MTK_WED_WO_STATE_INIT,
MTK_WED_WO_STATE_ENABLE,
MTK_WED_WO_STATE_DISABLE,
MTK_WED_WO_STATE_HALT,
MTK_WED_WO_STATE_GATING,
MTK_WED_WO_STATE_SER_RESET,
MTK_WED_WO_STATE_WF_RESET,
};
enum mtk_wed_wo_done_state {
MTK_WED_WOIF_UNDEFINED,
MTK_WED_WOIF_DISABLE_DONE,
MTK_WED_WOIF_TRIGGER_ENABLE,
MTK_WED_WOIF_ENABLE_DONE,
MTK_WED_WOIF_TRIGGER_GATING,
MTK_WED_WOIF_GATING_DONE,
MTK_WED_WOIF_TRIGGER_HALT,
MTK_WED_WOIF_HALT_DONE,
};
enum mtk_wed_dummy_cr_idx {
MTK_WED_DUMMY_CR_FWDL,
MTK_WED_DUMMY_CR_WO_STATUS,
};
#define MT7981_FIRMWARE_WO "mediatek/mt7981_wo.bin"
#define MT7986_FIRMWARE_WO0 "mediatek/mt7986_wo_0.bin"
#define MT7986_FIRMWARE_WO1 "mediatek/mt7986_wo_1.bin"
#define MT7988_FIRMWARE_WO0 "mediatek/mt7988/mt7988_wo_0.bin"
#define MT7988_FIRMWARE_WO1 "mediatek/mt7988/mt7988_wo_1.bin"
#define MTK_WO_MCU_CFG_LS_BASE 0
#define MTK_WO_MCU_CFG_LS_HW_VER_ADDR (MTK_WO_MCU_CFG_LS_BASE + 0x000)
#define MTK_WO_MCU_CFG_LS_FW_VER_ADDR (MTK_WO_MCU_CFG_LS_BASE + 0x004)
#define MTK_WO_MCU_CFG_LS_CFG_DBG1_ADDR (MTK_WO_MCU_CFG_LS_BASE + 0x00c)
#define MTK_WO_MCU_CFG_LS_CFG_DBG2_ADDR (MTK_WO_MCU_CFG_LS_BASE + 0x010)
#define MTK_WO_MCU_CFG_LS_WF_MCCR_ADDR (MTK_WO_MCU_CFG_LS_BASE + 0x014)
#define MTK_WO_MCU_CFG_LS_WF_MCCR_SET_ADDR (MTK_WO_MCU_CFG_LS_BASE + 0x018)
#define MTK_WO_MCU_CFG_LS_WF_MCCR_CLR_ADDR (MTK_WO_MCU_CFG_LS_BASE + 0x01c)
#define MTK_WO_MCU_CFG_LS_WF_MCU_CFG_WM_WA_ADDR (MTK_WO_MCU_CFG_LS_BASE + 0x050)
#define MTK_WO_MCU_CFG_LS_WM_BOOT_ADDR_ADDR (MTK_WO_MCU_CFG_LS_BASE + 0x060)
#define MTK_WO_MCU_CFG_LS_WA_BOOT_ADDR_ADDR (MTK_WO_MCU_CFG_LS_BASE + 0x064)
#define MTK_WO_MCU_CFG_LS_WF_WM_WA_WM_CPU_RSTB_MASK BIT(5)
#define MTK_WO_MCU_CFG_LS_WF_WM_WA_WA_CPU_RSTB_MASK BIT(0)
#define MTK_WED_WO_RING_SIZE 256
#define MTK_WED_WO_CMD_LEN 1504
#define MTK_WED_WO_TXCH_NUM 0
#define MTK_WED_WO_RXCH_NUM 1
#define MTK_WED_WO_RXCH_WO_EXCEPTION 7
#define MTK_WED_WO_TXCH_INT_MASK BIT(0)
#define MTK_WED_WO_RXCH_INT_MASK BIT(1)
#define MTK_WED_WO_EXCEPTION_INT_MASK BIT(7)
#define MTK_WED_WO_ALL_INT_MASK (MTK_WED_WO_RXCH_INT_MASK | \
MTK_WED_WO_EXCEPTION_INT_MASK)
#define MTK_WED_WO_CCIF_BUSY 0x004
#define MTK_WED_WO_CCIF_START 0x008
#define MTK_WED_WO_CCIF_TCHNUM 0x00c
#define MTK_WED_WO_CCIF_RCHNUM 0x010
#define MTK_WED_WO_CCIF_RCHNUM_MASK GENMASK(7, 0)
#define MTK_WED_WO_CCIF_ACK 0x014
#define MTK_WED_WO_CCIF_IRQ0_MASK 0x018
#define MTK_WED_WO_CCIF_IRQ1_MASK 0x01c
#define MTK_WED_WO_CCIF_DUMMY1 0x020
#define MTK_WED_WO_CCIF_DUMMY2 0x024
#define MTK_WED_WO_CCIF_DUMMY3 0x028
#define MTK_WED_WO_CCIF_DUMMY4 0x02c
#define MTK_WED_WO_CCIF_SHADOW1 0x030
#define MTK_WED_WO_CCIF_SHADOW2 0x034
#define MTK_WED_WO_CCIF_SHADOW3 0x038
#define MTK_WED_WO_CCIF_SHADOW4 0x03c
#define MTK_WED_WO_CCIF_DUMMY5 0x050
#define MTK_WED_WO_CCIF_DUMMY6 0x054
#define MTK_WED_WO_CCIF_DUMMY7 0x058
#define MTK_WED_WO_CCIF_DUMMY8 0x05c
#define MTK_WED_WO_CCIF_SHADOW5 0x060
#define MTK_WED_WO_CCIF_SHADOW6 0x064
#define MTK_WED_WO_CCIF_SHADOW7 0x068
#define MTK_WED_WO_CCIF_SHADOW8 0x06c
#define MTK_WED_WO_CTL_SD_LEN1 GENMASK(13, 0)
#define MTK_WED_WO_CTL_LAST_SEC1 BIT(14)
#define MTK_WED_WO_CTL_BURST BIT(15)
#define MTK_WED_WO_CTL_SD_LEN0_SHIFT 16
#define MTK_WED_WO_CTL_SD_LEN0 GENMASK(29, 16)
#define MTK_WED_WO_CTL_LAST_SEC0 BIT(30)
#define MTK_WED_WO_CTL_DMA_DONE BIT(31)
#define MTK_WED_WO_INFO_WINFO GENMASK(15, 0)
struct mtk_wed_wo_memory_region {
const char *name;
void __iomem *addr;
phys_addr_t phy_addr;
u32 size;
bool shared:1;
bool consumed:1;
};
struct mtk_wed_fw_region {
__le32 decomp_crc;
__le32 decomp_len;
__le32 decomp_blk_sz;
u8 rsv0[4];
__le32 addr;
__le32 len;
u8 feature_set;
u8 rsv1[15];
} __packed;
struct mtk_wed_fw_trailer {
u8 chip_id;
u8 eco_code;
u8 num_region;
u8 format_ver;
u8 format_flag;
u8 rsv[2];
char fw_ver[10];
char build_date[15];
u32 crc;
};
struct mtk_wed_wo_queue_regs {
u32 desc_base;
u32 ring_size;
u32 cpu_idx;
u32 dma_idx;
};
struct mtk_wed_wo_queue_desc {
__le32 buf0;
__le32 ctrl;
__le32 buf1;
__le32 info;
__le32 reserved[4];
} __packed __aligned(32);
struct mtk_wed_wo_queue_entry {
dma_addr_t addr;
void *buf;
u32 len;
};
struct mtk_wed_wo_queue {
struct mtk_wed_wo_queue_regs regs;
struct page_frag_cache cache;
struct mtk_wed_wo_queue_desc *desc;
dma_addr_t desc_dma;
struct mtk_wed_wo_queue_entry *entry;
u16 head;
u16 tail;
int n_desc;
int queued;
int buf_size;
};
struct mtk_wed_wo {
struct mtk_wed_hw *hw;
struct mtk_wed_wo_queue q_tx;
struct mtk_wed_wo_queue q_rx;
struct {
struct mutex mutex;
int timeout;
u16 seq;
struct sk_buff_head res_q;
wait_queue_head_t wait;
} mcu;
struct {
struct regmap *regs;
spinlock_t lock;
struct tasklet_struct irq_tasklet;
int irq;
u32 irq_mask;
} mmio;
};
static inline int
mtk_wed_mcu_check_msg(struct mtk_wed_wo *wo, struct sk_buff *skb)
{
struct mtk_wed_mcu_hdr *hdr = (struct mtk_wed_mcu_hdr *)skb->data;
if (hdr->version)
return -EINVAL;
if (skb->len < sizeof(*hdr) || skb->len != le16_to_cpu(hdr->length))
return -EINVAL;
return 0;
}
void mtk_wed_mcu_rx_event(struct mtk_wed_wo *wo, struct sk_buff *skb);
void mtk_wed_mcu_rx_unsolicited_event(struct mtk_wed_wo *wo,
struct sk_buff *skb);
int mtk_wed_mcu_send_msg(struct mtk_wed_wo *wo, int id, int cmd,
const void *data, int len, bool wait_resp);
int mtk_wed_mcu_msg_update(struct mtk_wed_device *dev, int id, void *data,
int len);
int mtk_wed_mcu_init(struct mtk_wed_wo *wo);
int mtk_wed_wo_init(struct mtk_wed_hw *hw);
void mtk_wed_wo_deinit(struct mtk_wed_hw *hw);
int mtk_wed_wo_queue_tx_skb(struct mtk_wed_wo *dev, struct mtk_wed_wo_queue *q,
struct sk_buff *skb);
#endif /* __MTK_WED_WO_H */