1ba37b7caSFelix Fietkau // SPDX-License-Identifier: GPL-2.0-only 2ba37b7caSFelix Fietkau /* Copyright (C) 2020 Felix Fietkau <nbd@nbd.name> */ 3ba37b7caSFelix Fietkau 4ba37b7caSFelix Fietkau #include <linux/kernel.h> 5ba37b7caSFelix Fietkau #include <linux/io.h> 6c5d66587SIlya Lipnitskiy #include <linux/iopoll.h> 7ba37b7caSFelix Fietkau #include <linux/etherdevice.h> 8ba37b7caSFelix Fietkau #include <linux/platform_device.h> 933fc42deSFelix Fietkau #include <linux/if_ether.h> 1033fc42deSFelix Fietkau #include <linux/if_vlan.h> 115f36ca1bSFelix Fietkau #include <net/dst_metadata.h> 1233fc42deSFelix Fietkau #include <net/dsa.h> 13c4f033d9SFelix Fietkau #include "mtk_eth_soc.h" 14ba37b7caSFelix Fietkau #include "mtk_ppe.h" 15ba37b7caSFelix Fietkau #include "mtk_ppe_regs.h" 16ba37b7caSFelix Fietkau 17c4f033d9SFelix Fietkau static DEFINE_SPINLOCK(ppe_lock); 18c4f033d9SFelix Fietkau 1933fc42deSFelix Fietkau static const struct rhashtable_params mtk_flow_l2_ht_params = { 2033fc42deSFelix Fietkau .head_offset = offsetof(struct mtk_flow_entry, l2_node), 2133fc42deSFelix Fietkau .key_offset = offsetof(struct mtk_flow_entry, data.bridge), 2233fc42deSFelix Fietkau .key_len = offsetof(struct mtk_foe_bridge, key_end), 2333fc42deSFelix Fietkau .automatic_shrinking = true, 2433fc42deSFelix Fietkau }; 2533fc42deSFelix Fietkau 26ba37b7caSFelix Fietkau static void ppe_w32(struct mtk_ppe *ppe, u32 reg, u32 val) 27ba37b7caSFelix Fietkau { 28ba37b7caSFelix Fietkau writel(val, ppe->base + reg); 29ba37b7caSFelix Fietkau } 30ba37b7caSFelix Fietkau 31ba37b7caSFelix Fietkau static u32 ppe_r32(struct mtk_ppe *ppe, u32 reg) 32ba37b7caSFelix Fietkau { 33ba37b7caSFelix Fietkau return readl(ppe->base + reg); 34ba37b7caSFelix Fietkau } 35ba37b7caSFelix Fietkau 36ba37b7caSFelix Fietkau static u32 ppe_m32(struct mtk_ppe *ppe, u32 reg, u32 mask, u32 set) 37ba37b7caSFelix Fietkau { 38ba37b7caSFelix Fietkau u32 val; 39ba37b7caSFelix Fietkau 40ba37b7caSFelix Fietkau val = ppe_r32(ppe, reg); 41ba37b7caSFelix Fietkau val &= ~mask; 42ba37b7caSFelix Fietkau val |= set; 43ba37b7caSFelix Fietkau ppe_w32(ppe, reg, val); 44ba37b7caSFelix Fietkau 45ba37b7caSFelix Fietkau return val; 46ba37b7caSFelix Fietkau } 47ba37b7caSFelix Fietkau 48ba37b7caSFelix Fietkau static u32 ppe_set(struct mtk_ppe *ppe, u32 reg, u32 val) 49ba37b7caSFelix Fietkau { 50ba37b7caSFelix Fietkau return ppe_m32(ppe, reg, 0, val); 51ba37b7caSFelix Fietkau } 52ba37b7caSFelix Fietkau 53ba37b7caSFelix Fietkau static u32 ppe_clear(struct mtk_ppe *ppe, u32 reg, u32 val) 54ba37b7caSFelix Fietkau { 55ba37b7caSFelix Fietkau return ppe_m32(ppe, reg, val, 0); 56ba37b7caSFelix Fietkau } 57ba37b7caSFelix Fietkau 58c4f033d9SFelix Fietkau static u32 mtk_eth_timestamp(struct mtk_eth *eth) 59c4f033d9SFelix Fietkau { 6003a3180eSLorenzo Bianconi return mtk_r32(eth, 0x0010) & mtk_get_ib1_ts_mask(eth); 61c4f033d9SFelix Fietkau } 62c4f033d9SFelix Fietkau 63ba37b7caSFelix Fietkau static int mtk_ppe_wait_busy(struct mtk_ppe *ppe) 64ba37b7caSFelix Fietkau { 65c5d66587SIlya Lipnitskiy int ret; 66c5d66587SIlya Lipnitskiy u32 val; 67ba37b7caSFelix Fietkau 68c5d66587SIlya Lipnitskiy ret = readl_poll_timeout(ppe->base + MTK_PPE_GLO_CFG, val, 69c5d66587SIlya Lipnitskiy !(val & MTK_PPE_GLO_CFG_BUSY), 70c5d66587SIlya Lipnitskiy 20, MTK_PPE_WAIT_TIMEOUT_US); 71ba37b7caSFelix Fietkau 72c5d66587SIlya Lipnitskiy if (ret) 73ba37b7caSFelix Fietkau dev_err(ppe->dev, "PPE table busy"); 74ba37b7caSFelix Fietkau 75c5d66587SIlya Lipnitskiy return ret; 76ba37b7caSFelix Fietkau } 77ba37b7caSFelix Fietkau 783fbe4d8cSDaniel Golle static int mtk_ppe_mib_wait_busy(struct mtk_ppe *ppe) 793fbe4d8cSDaniel Golle { 803fbe4d8cSDaniel Golle int ret; 813fbe4d8cSDaniel Golle u32 val; 823fbe4d8cSDaniel Golle 833fbe4d8cSDaniel Golle ret = readl_poll_timeout(ppe->base + MTK_PPE_MIB_SER_CR, val, 843fbe4d8cSDaniel Golle !(val & MTK_PPE_MIB_SER_CR_ST), 853fbe4d8cSDaniel Golle 20, MTK_PPE_WAIT_TIMEOUT_US); 863fbe4d8cSDaniel Golle 873fbe4d8cSDaniel Golle if (ret) 883fbe4d8cSDaniel Golle dev_err(ppe->dev, "MIB table busy"); 893fbe4d8cSDaniel Golle 903fbe4d8cSDaniel Golle return ret; 913fbe4d8cSDaniel Golle } 923fbe4d8cSDaniel Golle 933fbe4d8cSDaniel Golle static int mtk_mib_entry_read(struct mtk_ppe *ppe, u16 index, u64 *bytes, u64 *packets) 943fbe4d8cSDaniel Golle { 953fbe4d8cSDaniel Golle u32 byte_cnt_low, byte_cnt_high, pkt_cnt_low, pkt_cnt_high; 963fbe4d8cSDaniel Golle u32 val, cnt_r0, cnt_r1, cnt_r2; 973fbe4d8cSDaniel Golle int ret; 983fbe4d8cSDaniel Golle 993fbe4d8cSDaniel Golle val = FIELD_PREP(MTK_PPE_MIB_SER_CR_ADDR, index) | MTK_PPE_MIB_SER_CR_ST; 1003fbe4d8cSDaniel Golle ppe_w32(ppe, MTK_PPE_MIB_SER_CR, val); 1013fbe4d8cSDaniel Golle 1023fbe4d8cSDaniel Golle ret = mtk_ppe_mib_wait_busy(ppe); 1033fbe4d8cSDaniel Golle if (ret) 1043fbe4d8cSDaniel Golle return ret; 1053fbe4d8cSDaniel Golle 1063fbe4d8cSDaniel Golle cnt_r0 = readl(ppe->base + MTK_PPE_MIB_SER_R0); 1073fbe4d8cSDaniel Golle cnt_r1 = readl(ppe->base + MTK_PPE_MIB_SER_R1); 1083fbe4d8cSDaniel Golle cnt_r2 = readl(ppe->base + MTK_PPE_MIB_SER_R2); 1093fbe4d8cSDaniel Golle 1103fbe4d8cSDaniel Golle byte_cnt_low = FIELD_GET(MTK_PPE_MIB_SER_R0_BYTE_CNT_LOW, cnt_r0); 1113fbe4d8cSDaniel Golle byte_cnt_high = FIELD_GET(MTK_PPE_MIB_SER_R1_BYTE_CNT_HIGH, cnt_r1); 1123fbe4d8cSDaniel Golle pkt_cnt_low = FIELD_GET(MTK_PPE_MIB_SER_R1_PKT_CNT_LOW, cnt_r1); 1133fbe4d8cSDaniel Golle pkt_cnt_high = FIELD_GET(MTK_PPE_MIB_SER_R2_PKT_CNT_HIGH, cnt_r2); 1143fbe4d8cSDaniel Golle *bytes = ((u64)byte_cnt_high << 32) | byte_cnt_low; 1153fbe4d8cSDaniel Golle *packets = (pkt_cnt_high << 16) | pkt_cnt_low; 1163fbe4d8cSDaniel Golle 1173fbe4d8cSDaniel Golle return 0; 1183fbe4d8cSDaniel Golle } 1193fbe4d8cSDaniel Golle 120ba37b7caSFelix Fietkau static void mtk_ppe_cache_clear(struct mtk_ppe *ppe) 121ba37b7caSFelix Fietkau { 122ba37b7caSFelix Fietkau ppe_set(ppe, MTK_PPE_CACHE_CTL, MTK_PPE_CACHE_CTL_CLEAR); 123ba37b7caSFelix Fietkau ppe_clear(ppe, MTK_PPE_CACHE_CTL, MTK_PPE_CACHE_CTL_CLEAR); 124ba37b7caSFelix Fietkau } 125ba37b7caSFelix Fietkau 126ba37b7caSFelix Fietkau static void mtk_ppe_cache_enable(struct mtk_ppe *ppe, bool enable) 127ba37b7caSFelix Fietkau { 128ba37b7caSFelix Fietkau mtk_ppe_cache_clear(ppe); 129ba37b7caSFelix Fietkau 130ba37b7caSFelix Fietkau ppe_m32(ppe, MTK_PPE_CACHE_CTL, MTK_PPE_CACHE_CTL_EN, 131ba37b7caSFelix Fietkau enable * MTK_PPE_CACHE_CTL_EN); 132ba37b7caSFelix Fietkau } 133ba37b7caSFelix Fietkau 134ba2fc48cSLorenzo Bianconi static u32 mtk_ppe_hash_entry(struct mtk_eth *eth, struct mtk_foe_entry *e) 135ba37b7caSFelix Fietkau { 136ba37b7caSFelix Fietkau u32 hv1, hv2, hv3; 137ba37b7caSFelix Fietkau u32 hash; 138ba37b7caSFelix Fietkau 13903a3180eSLorenzo Bianconi switch (mtk_get_ib1_pkt_type(eth, e->ib1)) { 140ba37b7caSFelix Fietkau case MTK_PPE_PKT_TYPE_IPV4_ROUTE: 141ba37b7caSFelix Fietkau case MTK_PPE_PKT_TYPE_IPV4_HNAPT: 142ba37b7caSFelix Fietkau hv1 = e->ipv4.orig.ports; 143ba37b7caSFelix Fietkau hv2 = e->ipv4.orig.dest_ip; 144ba37b7caSFelix Fietkau hv3 = e->ipv4.orig.src_ip; 145ba37b7caSFelix Fietkau break; 146ba37b7caSFelix Fietkau case MTK_PPE_PKT_TYPE_IPV6_ROUTE_3T: 147ba37b7caSFelix Fietkau case MTK_PPE_PKT_TYPE_IPV6_ROUTE_5T: 148ba37b7caSFelix Fietkau hv1 = e->ipv6.src_ip[3] ^ e->ipv6.dest_ip[3]; 149ba37b7caSFelix Fietkau hv1 ^= e->ipv6.ports; 150ba37b7caSFelix Fietkau 151ba37b7caSFelix Fietkau hv2 = e->ipv6.src_ip[2] ^ e->ipv6.dest_ip[2]; 152ba37b7caSFelix Fietkau hv2 ^= e->ipv6.dest_ip[0]; 153ba37b7caSFelix Fietkau 154ba37b7caSFelix Fietkau hv3 = e->ipv6.src_ip[1] ^ e->ipv6.dest_ip[1]; 155ba37b7caSFelix Fietkau hv3 ^= e->ipv6.src_ip[0]; 156ba37b7caSFelix Fietkau break; 157ba37b7caSFelix Fietkau case MTK_PPE_PKT_TYPE_IPV4_DSLITE: 158ba37b7caSFelix Fietkau case MTK_PPE_PKT_TYPE_IPV6_6RD: 159ba37b7caSFelix Fietkau default: 160ba37b7caSFelix Fietkau WARN_ON_ONCE(1); 161ba37b7caSFelix Fietkau return MTK_PPE_HASH_MASK; 162ba37b7caSFelix Fietkau } 163ba37b7caSFelix Fietkau 164ba37b7caSFelix Fietkau hash = (hv1 & hv2) | ((~hv1) & hv3); 165ba37b7caSFelix Fietkau hash = (hash >> 24) | ((hash & 0xffffff) << 8); 166ba37b7caSFelix Fietkau hash ^= hv1 ^ hv2 ^ hv3; 167ba37b7caSFelix Fietkau hash ^= hash >> 16; 168ba2fc48cSLorenzo Bianconi hash <<= (ffs(eth->soc->hash_offset) - 1); 169ba37b7caSFelix Fietkau hash &= MTK_PPE_ENTRIES - 1; 170ba37b7caSFelix Fietkau 171ba37b7caSFelix Fietkau return hash; 172ba37b7caSFelix Fietkau } 173ba37b7caSFelix Fietkau 174ba37b7caSFelix Fietkau static inline struct mtk_foe_mac_info * 17503a3180eSLorenzo Bianconi mtk_foe_entry_l2(struct mtk_eth *eth, struct mtk_foe_entry *entry) 176ba37b7caSFelix Fietkau { 17703a3180eSLorenzo Bianconi int type = mtk_get_ib1_pkt_type(eth, entry->ib1); 178ba37b7caSFelix Fietkau 17933fc42deSFelix Fietkau if (type == MTK_PPE_PKT_TYPE_BRIDGE) 18033fc42deSFelix Fietkau return &entry->bridge.l2; 18133fc42deSFelix Fietkau 182ba37b7caSFelix Fietkau if (type >= MTK_PPE_PKT_TYPE_IPV4_DSLITE) 183ba37b7caSFelix Fietkau return &entry->ipv6.l2; 184ba37b7caSFelix Fietkau 185ba37b7caSFelix Fietkau return &entry->ipv4.l2; 186ba37b7caSFelix Fietkau } 187ba37b7caSFelix Fietkau 188ba37b7caSFelix Fietkau static inline u32 * 18903a3180eSLorenzo Bianconi mtk_foe_entry_ib2(struct mtk_eth *eth, struct mtk_foe_entry *entry) 190ba37b7caSFelix Fietkau { 19103a3180eSLorenzo Bianconi int type = mtk_get_ib1_pkt_type(eth, entry->ib1); 192ba37b7caSFelix Fietkau 19333fc42deSFelix Fietkau if (type == MTK_PPE_PKT_TYPE_BRIDGE) 19433fc42deSFelix Fietkau return &entry->bridge.ib2; 19533fc42deSFelix Fietkau 196ba37b7caSFelix Fietkau if (type >= MTK_PPE_PKT_TYPE_IPV4_DSLITE) 197ba37b7caSFelix Fietkau return &entry->ipv6.ib2; 198ba37b7caSFelix Fietkau 199ba37b7caSFelix Fietkau return &entry->ipv4.ib2; 200ba37b7caSFelix Fietkau } 201ba37b7caSFelix Fietkau 20203a3180eSLorenzo Bianconi int mtk_foe_entry_prepare(struct mtk_eth *eth, struct mtk_foe_entry *entry, 20303a3180eSLorenzo Bianconi int type, int l4proto, u8 pse_port, u8 *src_mac, 20403a3180eSLorenzo Bianconi u8 *dest_mac) 205ba37b7caSFelix Fietkau { 206ba37b7caSFelix Fietkau struct mtk_foe_mac_info *l2; 207ba37b7caSFelix Fietkau u32 ports_pad, val; 208ba37b7caSFelix Fietkau 209ba37b7caSFelix Fietkau memset(entry, 0, sizeof(*entry)); 210ba37b7caSFelix Fietkau 21103a3180eSLorenzo Bianconi if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { 21203a3180eSLorenzo Bianconi val = FIELD_PREP(MTK_FOE_IB1_STATE, MTK_FOE_STATE_BIND) | 21303a3180eSLorenzo Bianconi FIELD_PREP(MTK_FOE_IB1_PACKET_TYPE_V2, type) | 21403a3180eSLorenzo Bianconi FIELD_PREP(MTK_FOE_IB1_UDP, l4proto == IPPROTO_UDP) | 21503a3180eSLorenzo Bianconi MTK_FOE_IB1_BIND_CACHE_V2 | MTK_FOE_IB1_BIND_TTL_V2; 21603a3180eSLorenzo Bianconi entry->ib1 = val; 21703a3180eSLorenzo Bianconi 21803a3180eSLorenzo Bianconi val = FIELD_PREP(MTK_FOE_IB2_DEST_PORT_V2, pse_port) | 21903a3180eSLorenzo Bianconi FIELD_PREP(MTK_FOE_IB2_PORT_AG_V2, 0xf); 22003a3180eSLorenzo Bianconi } else { 22171ba8e48SFelix Fietkau int port_mg = eth->soc->offload_version > 1 ? 0 : 0x3f; 22271ba8e48SFelix Fietkau 223ba37b7caSFelix Fietkau val = FIELD_PREP(MTK_FOE_IB1_STATE, MTK_FOE_STATE_BIND) | 224ba37b7caSFelix Fietkau FIELD_PREP(MTK_FOE_IB1_PACKET_TYPE, type) | 225ba37b7caSFelix Fietkau FIELD_PREP(MTK_FOE_IB1_UDP, l4proto == IPPROTO_UDP) | 22603a3180eSLorenzo Bianconi MTK_FOE_IB1_BIND_CACHE | MTK_FOE_IB1_BIND_TTL; 227ba37b7caSFelix Fietkau entry->ib1 = val; 228ba37b7caSFelix Fietkau 22903a3180eSLorenzo Bianconi val = FIELD_PREP(MTK_FOE_IB2_DEST_PORT, pse_port) | 23071ba8e48SFelix Fietkau FIELD_PREP(MTK_FOE_IB2_PORT_MG, port_mg) | 23103a3180eSLorenzo Bianconi FIELD_PREP(MTK_FOE_IB2_PORT_AG, 0x1f); 23203a3180eSLorenzo Bianconi } 233ba37b7caSFelix Fietkau 234ba37b7caSFelix Fietkau if (is_multicast_ether_addr(dest_mac)) 23503a3180eSLorenzo Bianconi val |= mtk_get_ib2_multicast_mask(eth); 236ba37b7caSFelix Fietkau 237ba37b7caSFelix Fietkau ports_pad = 0xa5a5a500 | (l4proto & 0xff); 238ba37b7caSFelix Fietkau if (type == MTK_PPE_PKT_TYPE_IPV4_ROUTE) 239ba37b7caSFelix Fietkau entry->ipv4.orig.ports = ports_pad; 240ba37b7caSFelix Fietkau if (type == MTK_PPE_PKT_TYPE_IPV6_ROUTE_3T) 241ba37b7caSFelix Fietkau entry->ipv6.ports = ports_pad; 242ba37b7caSFelix Fietkau 24333fc42deSFelix Fietkau if (type == MTK_PPE_PKT_TYPE_BRIDGE) { 24433fc42deSFelix Fietkau ether_addr_copy(entry->bridge.src_mac, src_mac); 24533fc42deSFelix Fietkau ether_addr_copy(entry->bridge.dest_mac, dest_mac); 24633fc42deSFelix Fietkau entry->bridge.ib2 = val; 24733fc42deSFelix Fietkau l2 = &entry->bridge.l2; 24833fc42deSFelix Fietkau } else if (type >= MTK_PPE_PKT_TYPE_IPV4_DSLITE) { 249ba37b7caSFelix Fietkau entry->ipv6.ib2 = val; 250ba37b7caSFelix Fietkau l2 = &entry->ipv6.l2; 251ba37b7caSFelix Fietkau } else { 252ba37b7caSFelix Fietkau entry->ipv4.ib2 = val; 253ba37b7caSFelix Fietkau l2 = &entry->ipv4.l2; 254ba37b7caSFelix Fietkau } 255ba37b7caSFelix Fietkau 256ba37b7caSFelix Fietkau l2->dest_mac_hi = get_unaligned_be32(dest_mac); 257ba37b7caSFelix Fietkau l2->dest_mac_lo = get_unaligned_be16(dest_mac + 4); 258ba37b7caSFelix Fietkau l2->src_mac_hi = get_unaligned_be32(src_mac); 259ba37b7caSFelix Fietkau l2->src_mac_lo = get_unaligned_be16(src_mac + 4); 260ba37b7caSFelix Fietkau 261ba37b7caSFelix Fietkau if (type >= MTK_PPE_PKT_TYPE_IPV6_ROUTE_3T) 262ba37b7caSFelix Fietkau l2->etype = ETH_P_IPV6; 263ba37b7caSFelix Fietkau else 264ba37b7caSFelix Fietkau l2->etype = ETH_P_IP; 265ba37b7caSFelix Fietkau 266ba37b7caSFelix Fietkau return 0; 267ba37b7caSFelix Fietkau } 268ba37b7caSFelix Fietkau 26903a3180eSLorenzo Bianconi int mtk_foe_entry_set_pse_port(struct mtk_eth *eth, 27003a3180eSLorenzo Bianconi struct mtk_foe_entry *entry, u8 port) 271ba37b7caSFelix Fietkau { 27203a3180eSLorenzo Bianconi u32 *ib2 = mtk_foe_entry_ib2(eth, entry); 27303a3180eSLorenzo Bianconi u32 val = *ib2; 274ba37b7caSFelix Fietkau 27503a3180eSLorenzo Bianconi if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { 27603a3180eSLorenzo Bianconi val &= ~MTK_FOE_IB2_DEST_PORT_V2; 27703a3180eSLorenzo Bianconi val |= FIELD_PREP(MTK_FOE_IB2_DEST_PORT_V2, port); 27803a3180eSLorenzo Bianconi } else { 279ba37b7caSFelix Fietkau val &= ~MTK_FOE_IB2_DEST_PORT; 280ba37b7caSFelix Fietkau val |= FIELD_PREP(MTK_FOE_IB2_DEST_PORT, port); 28103a3180eSLorenzo Bianconi } 282ba37b7caSFelix Fietkau *ib2 = val; 283ba37b7caSFelix Fietkau 284ba37b7caSFelix Fietkau return 0; 285ba37b7caSFelix Fietkau } 286ba37b7caSFelix Fietkau 28703a3180eSLorenzo Bianconi int mtk_foe_entry_set_ipv4_tuple(struct mtk_eth *eth, 28803a3180eSLorenzo Bianconi struct mtk_foe_entry *entry, bool egress, 289ba37b7caSFelix Fietkau __be32 src_addr, __be16 src_port, 290ba37b7caSFelix Fietkau __be32 dest_addr, __be16 dest_port) 291ba37b7caSFelix Fietkau { 29203a3180eSLorenzo Bianconi int type = mtk_get_ib1_pkt_type(eth, entry->ib1); 293ba37b7caSFelix Fietkau struct mtk_ipv4_tuple *t; 294ba37b7caSFelix Fietkau 295ba37b7caSFelix Fietkau switch (type) { 296ba37b7caSFelix Fietkau case MTK_PPE_PKT_TYPE_IPV4_HNAPT: 297ba37b7caSFelix Fietkau if (egress) { 298ba37b7caSFelix Fietkau t = &entry->ipv4.new; 299ba37b7caSFelix Fietkau break; 300ba37b7caSFelix Fietkau } 301ba37b7caSFelix Fietkau fallthrough; 302ba37b7caSFelix Fietkau case MTK_PPE_PKT_TYPE_IPV4_DSLITE: 303ba37b7caSFelix Fietkau case MTK_PPE_PKT_TYPE_IPV4_ROUTE: 304ba37b7caSFelix Fietkau t = &entry->ipv4.orig; 305ba37b7caSFelix Fietkau break; 306ba37b7caSFelix Fietkau case MTK_PPE_PKT_TYPE_IPV6_6RD: 307ba37b7caSFelix Fietkau entry->ipv6_6rd.tunnel_src_ip = be32_to_cpu(src_addr); 308ba37b7caSFelix Fietkau entry->ipv6_6rd.tunnel_dest_ip = be32_to_cpu(dest_addr); 309ba37b7caSFelix Fietkau return 0; 310ba37b7caSFelix Fietkau default: 311ba37b7caSFelix Fietkau WARN_ON_ONCE(1); 312ba37b7caSFelix Fietkau return -EINVAL; 313ba37b7caSFelix Fietkau } 314ba37b7caSFelix Fietkau 315ba37b7caSFelix Fietkau t->src_ip = be32_to_cpu(src_addr); 316ba37b7caSFelix Fietkau t->dest_ip = be32_to_cpu(dest_addr); 317ba37b7caSFelix Fietkau 318ba37b7caSFelix Fietkau if (type == MTK_PPE_PKT_TYPE_IPV4_ROUTE) 319ba37b7caSFelix Fietkau return 0; 320ba37b7caSFelix Fietkau 321ba37b7caSFelix Fietkau t->src_port = be16_to_cpu(src_port); 322ba37b7caSFelix Fietkau t->dest_port = be16_to_cpu(dest_port); 323ba37b7caSFelix Fietkau 324ba37b7caSFelix Fietkau return 0; 325ba37b7caSFelix Fietkau } 326ba37b7caSFelix Fietkau 32703a3180eSLorenzo Bianconi int mtk_foe_entry_set_ipv6_tuple(struct mtk_eth *eth, 32803a3180eSLorenzo Bianconi struct mtk_foe_entry *entry, 329ba37b7caSFelix Fietkau __be32 *src_addr, __be16 src_port, 330ba37b7caSFelix Fietkau __be32 *dest_addr, __be16 dest_port) 331ba37b7caSFelix Fietkau { 33203a3180eSLorenzo Bianconi int type = mtk_get_ib1_pkt_type(eth, entry->ib1); 333ba37b7caSFelix Fietkau u32 *src, *dest; 334ba37b7caSFelix Fietkau int i; 335ba37b7caSFelix Fietkau 336ba37b7caSFelix Fietkau switch (type) { 337ba37b7caSFelix Fietkau case MTK_PPE_PKT_TYPE_IPV4_DSLITE: 338ba37b7caSFelix Fietkau src = entry->dslite.tunnel_src_ip; 339ba37b7caSFelix Fietkau dest = entry->dslite.tunnel_dest_ip; 340ba37b7caSFelix Fietkau break; 341ba37b7caSFelix Fietkau case MTK_PPE_PKT_TYPE_IPV6_ROUTE_5T: 342ba37b7caSFelix Fietkau case MTK_PPE_PKT_TYPE_IPV6_6RD: 343ba37b7caSFelix Fietkau entry->ipv6.src_port = be16_to_cpu(src_port); 344ba37b7caSFelix Fietkau entry->ipv6.dest_port = be16_to_cpu(dest_port); 345ba37b7caSFelix Fietkau fallthrough; 346ba37b7caSFelix Fietkau case MTK_PPE_PKT_TYPE_IPV6_ROUTE_3T: 347ba37b7caSFelix Fietkau src = entry->ipv6.src_ip; 348ba37b7caSFelix Fietkau dest = entry->ipv6.dest_ip; 349ba37b7caSFelix Fietkau break; 350ba37b7caSFelix Fietkau default: 351ba37b7caSFelix Fietkau WARN_ON_ONCE(1); 352ba37b7caSFelix Fietkau return -EINVAL; 3533b2c32f9SQiheng Lin } 354ba37b7caSFelix Fietkau 355ba37b7caSFelix Fietkau for (i = 0; i < 4; i++) 356ba37b7caSFelix Fietkau src[i] = be32_to_cpu(src_addr[i]); 357ba37b7caSFelix Fietkau for (i = 0; i < 4; i++) 358ba37b7caSFelix Fietkau dest[i] = be32_to_cpu(dest_addr[i]); 359ba37b7caSFelix Fietkau 360ba37b7caSFelix Fietkau return 0; 361ba37b7caSFelix Fietkau } 362ba37b7caSFelix Fietkau 36303a3180eSLorenzo Bianconi int mtk_foe_entry_set_dsa(struct mtk_eth *eth, struct mtk_foe_entry *entry, 36403a3180eSLorenzo Bianconi int port) 365ba37b7caSFelix Fietkau { 36603a3180eSLorenzo Bianconi struct mtk_foe_mac_info *l2 = mtk_foe_entry_l2(eth, entry); 367ba37b7caSFelix Fietkau 368ba37b7caSFelix Fietkau l2->etype = BIT(port); 369ba37b7caSFelix Fietkau 37003a3180eSLorenzo Bianconi if (!(entry->ib1 & mtk_get_ib1_vlan_layer_mask(eth))) 37103a3180eSLorenzo Bianconi entry->ib1 |= mtk_prep_ib1_vlan_layer(eth, 1); 372ba37b7caSFelix Fietkau else 373ba37b7caSFelix Fietkau l2->etype |= BIT(8); 374ba37b7caSFelix Fietkau 37503a3180eSLorenzo Bianconi entry->ib1 &= ~mtk_get_ib1_vlan_tag_mask(eth); 376ba37b7caSFelix Fietkau 377ba37b7caSFelix Fietkau return 0; 378ba37b7caSFelix Fietkau } 379ba37b7caSFelix Fietkau 38003a3180eSLorenzo Bianconi int mtk_foe_entry_set_vlan(struct mtk_eth *eth, struct mtk_foe_entry *entry, 38103a3180eSLorenzo Bianconi int vid) 382ba37b7caSFelix Fietkau { 38303a3180eSLorenzo Bianconi struct mtk_foe_mac_info *l2 = mtk_foe_entry_l2(eth, entry); 384ba37b7caSFelix Fietkau 385fb7da771SDaniel Golle switch (mtk_get_ib1_vlan_layer(eth, entry->ib1)) { 386ba37b7caSFelix Fietkau case 0: 38703a3180eSLorenzo Bianconi entry->ib1 |= mtk_get_ib1_vlan_tag_mask(eth) | 38803a3180eSLorenzo Bianconi mtk_prep_ib1_vlan_layer(eth, 1); 389ba37b7caSFelix Fietkau l2->vlan1 = vid; 390ba37b7caSFelix Fietkau return 0; 391ba37b7caSFelix Fietkau case 1: 39203a3180eSLorenzo Bianconi if (!(entry->ib1 & mtk_get_ib1_vlan_tag_mask(eth))) { 393ba37b7caSFelix Fietkau l2->vlan1 = vid; 394ba37b7caSFelix Fietkau l2->etype |= BIT(8); 395ba37b7caSFelix Fietkau } else { 396ba37b7caSFelix Fietkau l2->vlan2 = vid; 39703a3180eSLorenzo Bianconi entry->ib1 += mtk_prep_ib1_vlan_layer(eth, 1); 398ba37b7caSFelix Fietkau } 399ba37b7caSFelix Fietkau return 0; 400ba37b7caSFelix Fietkau default: 401ba37b7caSFelix Fietkau return -ENOSPC; 402ba37b7caSFelix Fietkau } 403ba37b7caSFelix Fietkau } 404ba37b7caSFelix Fietkau 40503a3180eSLorenzo Bianconi int mtk_foe_entry_set_pppoe(struct mtk_eth *eth, struct mtk_foe_entry *entry, 40603a3180eSLorenzo Bianconi int sid) 407ba37b7caSFelix Fietkau { 40803a3180eSLorenzo Bianconi struct mtk_foe_mac_info *l2 = mtk_foe_entry_l2(eth, entry); 409ba37b7caSFelix Fietkau 41003a3180eSLorenzo Bianconi if (!(entry->ib1 & mtk_get_ib1_vlan_layer_mask(eth)) || 41103a3180eSLorenzo Bianconi (entry->ib1 & mtk_get_ib1_vlan_tag_mask(eth))) 412ba37b7caSFelix Fietkau l2->etype = ETH_P_PPP_SES; 413ba37b7caSFelix Fietkau 41403a3180eSLorenzo Bianconi entry->ib1 |= mtk_get_ib1_ppoe_mask(eth); 415ba37b7caSFelix Fietkau l2->pppoe_id = sid; 416ba37b7caSFelix Fietkau 417ba37b7caSFelix Fietkau return 0; 418ba37b7caSFelix Fietkau } 419ba37b7caSFelix Fietkau 42003a3180eSLorenzo Bianconi int mtk_foe_entry_set_wdma(struct mtk_eth *eth, struct mtk_foe_entry *entry, 42103a3180eSLorenzo Bianconi int wdma_idx, int txq, int bss, int wcid) 422a333215eSFelix Fietkau { 42303a3180eSLorenzo Bianconi struct mtk_foe_mac_info *l2 = mtk_foe_entry_l2(eth, entry); 42403a3180eSLorenzo Bianconi u32 *ib2 = mtk_foe_entry_ib2(eth, entry); 425a333215eSFelix Fietkau 42603a3180eSLorenzo Bianconi if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { 42703a3180eSLorenzo Bianconi *ib2 &= ~MTK_FOE_IB2_PORT_MG_V2; 42803a3180eSLorenzo Bianconi *ib2 |= FIELD_PREP(MTK_FOE_IB2_RX_IDX, txq) | 42903a3180eSLorenzo Bianconi MTK_FOE_IB2_WDMA_WINFO_V2; 43003a3180eSLorenzo Bianconi l2->winfo = FIELD_PREP(MTK_FOE_WINFO_WCID, wcid) | 43103a3180eSLorenzo Bianconi FIELD_PREP(MTK_FOE_WINFO_BSS, bss); 43203a3180eSLorenzo Bianconi } else { 433a333215eSFelix Fietkau *ib2 &= ~MTK_FOE_IB2_PORT_MG; 434a333215eSFelix Fietkau *ib2 |= MTK_FOE_IB2_WDMA_WINFO; 435a333215eSFelix Fietkau if (wdma_idx) 436a333215eSFelix Fietkau *ib2 |= MTK_FOE_IB2_WDMA_DEVIDX; 437a333215eSFelix Fietkau l2->vlan2 = FIELD_PREP(MTK_FOE_VLAN2_WINFO_BSS, bss) | 438a333215eSFelix Fietkau FIELD_PREP(MTK_FOE_VLAN2_WINFO_WCID, wcid) | 439a333215eSFelix Fietkau FIELD_PREP(MTK_FOE_VLAN2_WINFO_RING, txq); 44003a3180eSLorenzo Bianconi } 441a333215eSFelix Fietkau 442a333215eSFelix Fietkau return 0; 443a333215eSFelix Fietkau } 444a333215eSFelix Fietkau 4458bd8dcc5SFelix Fietkau int mtk_foe_entry_set_queue(struct mtk_eth *eth, struct mtk_foe_entry *entry, 4468bd8dcc5SFelix Fietkau unsigned int queue) 4478bd8dcc5SFelix Fietkau { 4488bd8dcc5SFelix Fietkau u32 *ib2 = mtk_foe_entry_ib2(eth, entry); 4498bd8dcc5SFelix Fietkau 4508bd8dcc5SFelix Fietkau if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { 4518bd8dcc5SFelix Fietkau *ib2 &= ~MTK_FOE_IB2_QID_V2; 4528bd8dcc5SFelix Fietkau *ib2 |= FIELD_PREP(MTK_FOE_IB2_QID_V2, queue); 4538bd8dcc5SFelix Fietkau *ib2 |= MTK_FOE_IB2_PSE_QOS_V2; 4548bd8dcc5SFelix Fietkau } else { 4558bd8dcc5SFelix Fietkau *ib2 &= ~MTK_FOE_IB2_QID; 4568bd8dcc5SFelix Fietkau *ib2 |= FIELD_PREP(MTK_FOE_IB2_QID, queue); 4578bd8dcc5SFelix Fietkau *ib2 |= MTK_FOE_IB2_PSE_QOS; 4588bd8dcc5SFelix Fietkau } 4598bd8dcc5SFelix Fietkau 4608bd8dcc5SFelix Fietkau return 0; 4618bd8dcc5SFelix Fietkau } 4628bd8dcc5SFelix Fietkau 463c4f033d9SFelix Fietkau static bool 46403a3180eSLorenzo Bianconi mtk_flow_entry_match(struct mtk_eth *eth, struct mtk_flow_entry *entry, 46503a3180eSLorenzo Bianconi struct mtk_foe_entry *data) 466c4f033d9SFelix Fietkau { 467c4f033d9SFelix Fietkau int type, len; 468c4f033d9SFelix Fietkau 469c4f033d9SFelix Fietkau if ((data->ib1 ^ entry->data.ib1) & MTK_FOE_IB1_UDP) 470c4f033d9SFelix Fietkau return false; 471c4f033d9SFelix Fietkau 47203a3180eSLorenzo Bianconi type = mtk_get_ib1_pkt_type(eth, entry->data.ib1); 473c4f033d9SFelix Fietkau if (type > MTK_PPE_PKT_TYPE_IPV4_DSLITE) 474c4f033d9SFelix Fietkau len = offsetof(struct mtk_foe_entry, ipv6._rsv); 475c4f033d9SFelix Fietkau else 476c4f033d9SFelix Fietkau len = offsetof(struct mtk_foe_entry, ipv4.ib2); 477c4f033d9SFelix Fietkau 478c4f033d9SFelix Fietkau return !memcmp(&entry->data.data, &data->data, len - 4); 479c4f033d9SFelix Fietkau } 480c4f033d9SFelix Fietkau 481c4f033d9SFelix Fietkau static void 48233fc42deSFelix Fietkau __mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) 48333fc42deSFelix Fietkau { 48433fc42deSFelix Fietkau struct hlist_head *head; 48533fc42deSFelix Fietkau struct hlist_node *tmp; 48633fc42deSFelix Fietkau 48733fc42deSFelix Fietkau if (entry->type == MTK_FLOW_TYPE_L2) { 48833fc42deSFelix Fietkau rhashtable_remove_fast(&ppe->l2_flows, &entry->l2_node, 48933fc42deSFelix Fietkau mtk_flow_l2_ht_params); 49033fc42deSFelix Fietkau 49133fc42deSFelix Fietkau head = &entry->l2_flows; 49233fc42deSFelix Fietkau hlist_for_each_entry_safe(entry, tmp, head, l2_data.list) 49333fc42deSFelix Fietkau __mtk_foe_entry_clear(ppe, entry); 49433fc42deSFelix Fietkau return; 49533fc42deSFelix Fietkau } 49633fc42deSFelix Fietkau 49733fc42deSFelix Fietkau hlist_del_init(&entry->list); 49833fc42deSFelix Fietkau if (entry->hash != 0xffff) { 4999d8cb4c0SLorenzo Bianconi struct mtk_foe_entry *hwe = mtk_foe_get_entry(ppe, entry->hash); 5009d8cb4c0SLorenzo Bianconi 5019d8cb4c0SLorenzo Bianconi hwe->ib1 &= ~MTK_FOE_IB1_STATE; 502e52f7c1dSJakub Kicinski hwe->ib1 |= FIELD_PREP(MTK_FOE_IB1_STATE, MTK_FOE_STATE_INVALID); 50333fc42deSFelix Fietkau dma_wmb(); 50492453132SFelix Fietkau mtk_ppe_cache_clear(ppe); 50579548b79SJakub Kicinski 5063fbe4d8cSDaniel Golle if (ppe->accounting) { 5073fbe4d8cSDaniel Golle struct mtk_foe_accounting *acct; 5083fbe4d8cSDaniel Golle 5093fbe4d8cSDaniel Golle acct = ppe->acct_table + entry->hash * sizeof(*acct); 5103fbe4d8cSDaniel Golle acct->packets = 0; 5113fbe4d8cSDaniel Golle acct->bytes = 0; 5123fbe4d8cSDaniel Golle } 51333fc42deSFelix Fietkau } 51433fc42deSFelix Fietkau entry->hash = 0xffff; 51533fc42deSFelix Fietkau 51633fc42deSFelix Fietkau if (entry->type != MTK_FLOW_TYPE_L2_SUBFLOW) 51733fc42deSFelix Fietkau return; 51833fc42deSFelix Fietkau 51933fc42deSFelix Fietkau hlist_del_init(&entry->l2_data.list); 52033fc42deSFelix Fietkau kfree(entry); 52133fc42deSFelix Fietkau } 52233fc42deSFelix Fietkau 52333fc42deSFelix Fietkau static int __mtk_foe_entry_idle_time(struct mtk_ppe *ppe, u32 ib1) 52433fc42deSFelix Fietkau { 52503a3180eSLorenzo Bianconi u32 ib1_ts_mask = mtk_get_ib1_ts_mask(ppe->eth); 52603a3180eSLorenzo Bianconi u16 now = mtk_eth_timestamp(ppe->eth); 52703a3180eSLorenzo Bianconi u16 timestamp = ib1 & ib1_ts_mask; 52833fc42deSFelix Fietkau 52933fc42deSFelix Fietkau if (timestamp > now) 53003a3180eSLorenzo Bianconi return ib1_ts_mask + 1 - timestamp + now; 53133fc42deSFelix Fietkau else 53233fc42deSFelix Fietkau return now - timestamp; 53333fc42deSFelix Fietkau } 53433fc42deSFelix Fietkau 53533fc42deSFelix Fietkau static void 53633fc42deSFelix Fietkau mtk_flow_entry_update_l2(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) 53733fc42deSFelix Fietkau { 53803a3180eSLorenzo Bianconi u32 ib1_ts_mask = mtk_get_ib1_ts_mask(ppe->eth); 53933fc42deSFelix Fietkau struct mtk_flow_entry *cur; 54033fc42deSFelix Fietkau struct mtk_foe_entry *hwe; 54133fc42deSFelix Fietkau struct hlist_node *tmp; 54233fc42deSFelix Fietkau int idle; 54333fc42deSFelix Fietkau 54433fc42deSFelix Fietkau idle = __mtk_foe_entry_idle_time(ppe, entry->data.ib1); 54533fc42deSFelix Fietkau hlist_for_each_entry_safe(cur, tmp, &entry->l2_flows, l2_data.list) { 54633fc42deSFelix Fietkau int cur_idle; 54733fc42deSFelix Fietkau u32 ib1; 54833fc42deSFelix Fietkau 5499d8cb4c0SLorenzo Bianconi hwe = mtk_foe_get_entry(ppe, cur->hash); 55033fc42deSFelix Fietkau ib1 = READ_ONCE(hwe->ib1); 55133fc42deSFelix Fietkau 55233fc42deSFelix Fietkau if (FIELD_GET(MTK_FOE_IB1_STATE, ib1) != MTK_FOE_STATE_BIND) { 55333fc42deSFelix Fietkau cur->hash = 0xffff; 55433fc42deSFelix Fietkau __mtk_foe_entry_clear(ppe, cur); 55533fc42deSFelix Fietkau continue; 55633fc42deSFelix Fietkau } 55733fc42deSFelix Fietkau 55833fc42deSFelix Fietkau cur_idle = __mtk_foe_entry_idle_time(ppe, ib1); 55933fc42deSFelix Fietkau if (cur_idle >= idle) 56033fc42deSFelix Fietkau continue; 56133fc42deSFelix Fietkau 56233fc42deSFelix Fietkau idle = cur_idle; 56303a3180eSLorenzo Bianconi entry->data.ib1 &= ~ib1_ts_mask; 56403a3180eSLorenzo Bianconi entry->data.ib1 |= hwe->ib1 & ib1_ts_mask; 56533fc42deSFelix Fietkau } 56633fc42deSFelix Fietkau } 56733fc42deSFelix Fietkau 56833fc42deSFelix Fietkau static void 569c4f033d9SFelix Fietkau mtk_flow_entry_update(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) 570ba37b7caSFelix Fietkau { 5719d8cb4c0SLorenzo Bianconi struct mtk_foe_entry foe = {}; 572ba37b7caSFelix Fietkau struct mtk_foe_entry *hwe; 573ba37b7caSFelix Fietkau 574c4f033d9SFelix Fietkau spin_lock_bh(&ppe_lock); 57533fc42deSFelix Fietkau 57633fc42deSFelix Fietkau if (entry->type == MTK_FLOW_TYPE_L2) { 57733fc42deSFelix Fietkau mtk_flow_entry_update_l2(ppe, entry); 57833fc42deSFelix Fietkau goto out; 57933fc42deSFelix Fietkau } 58033fc42deSFelix Fietkau 581c4f033d9SFelix Fietkau if (entry->hash == 0xffff) 582c4f033d9SFelix Fietkau goto out; 583c4f033d9SFelix Fietkau 5849d8cb4c0SLorenzo Bianconi hwe = mtk_foe_get_entry(ppe, entry->hash); 5859d8cb4c0SLorenzo Bianconi memcpy(&foe, hwe, ppe->eth->soc->foe_entry_size); 58603a3180eSLorenzo Bianconi if (!mtk_flow_entry_match(ppe->eth, entry, &foe)) { 587c4f033d9SFelix Fietkau entry->hash = 0xffff; 588c4f033d9SFelix Fietkau goto out; 589c4f033d9SFelix Fietkau } 590c4f033d9SFelix Fietkau 591c4f033d9SFelix Fietkau entry->data.ib1 = foe.ib1; 592c4f033d9SFelix Fietkau 593c4f033d9SFelix Fietkau out: 594c4f033d9SFelix Fietkau spin_unlock_bh(&ppe_lock); 595c4f033d9SFelix Fietkau } 596c4f033d9SFelix Fietkau 597c4f033d9SFelix Fietkau static void 598c4f033d9SFelix Fietkau __mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_foe_entry *entry, 599c4f033d9SFelix Fietkau u16 hash) 600c4f033d9SFelix Fietkau { 60103a3180eSLorenzo Bianconi struct mtk_eth *eth = ppe->eth; 60203a3180eSLorenzo Bianconi u16 timestamp = mtk_eth_timestamp(eth); 603c4f033d9SFelix Fietkau struct mtk_foe_entry *hwe; 604c4f033d9SFelix Fietkau 60503a3180eSLorenzo Bianconi if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { 60603a3180eSLorenzo Bianconi entry->ib1 &= ~MTK_FOE_IB1_BIND_TIMESTAMP_V2; 60703a3180eSLorenzo Bianconi entry->ib1 |= FIELD_PREP(MTK_FOE_IB1_BIND_TIMESTAMP_V2, 60803a3180eSLorenzo Bianconi timestamp); 60903a3180eSLorenzo Bianconi } else { 610ba37b7caSFelix Fietkau entry->ib1 &= ~MTK_FOE_IB1_BIND_TIMESTAMP; 61103a3180eSLorenzo Bianconi entry->ib1 |= FIELD_PREP(MTK_FOE_IB1_BIND_TIMESTAMP, 61203a3180eSLorenzo Bianconi timestamp); 61303a3180eSLorenzo Bianconi } 614ba37b7caSFelix Fietkau 6159d8cb4c0SLorenzo Bianconi hwe = mtk_foe_get_entry(ppe, hash); 616454b20e1SDaniel Golle memcpy(&hwe->data, &entry->data, eth->soc->foe_entry_size - sizeof(hwe->ib1)); 617ba37b7caSFelix Fietkau wmb(); 618ba37b7caSFelix Fietkau hwe->ib1 = entry->ib1; 619ba37b7caSFelix Fietkau 6203fbe4d8cSDaniel Golle if (ppe->accounting) 6213fbe4d8cSDaniel Golle *mtk_foe_entry_ib2(eth, hwe) |= MTK_FOE_IB2_MIB_CNT; 6223fbe4d8cSDaniel Golle 623ba37b7caSFelix Fietkau dma_wmb(); 624ba37b7caSFelix Fietkau 625ba37b7caSFelix Fietkau mtk_ppe_cache_clear(ppe); 626ba37b7caSFelix Fietkau } 627ba37b7caSFelix Fietkau 628c4f033d9SFelix Fietkau void mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) 629c4f033d9SFelix Fietkau { 630c4f033d9SFelix Fietkau spin_lock_bh(&ppe_lock); 63133fc42deSFelix Fietkau __mtk_foe_entry_clear(ppe, entry); 632c4f033d9SFelix Fietkau spin_unlock_bh(&ppe_lock); 633c4f033d9SFelix Fietkau } 634c4f033d9SFelix Fietkau 63533fc42deSFelix Fietkau static int 63633fc42deSFelix Fietkau mtk_foe_entry_commit_l2(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) 63733fc42deSFelix Fietkau { 638*e2853114SFelix Fietkau struct mtk_flow_entry *prev; 639*e2853114SFelix Fietkau 64033fc42deSFelix Fietkau entry->type = MTK_FLOW_TYPE_L2; 64133fc42deSFelix Fietkau 642*e2853114SFelix Fietkau prev = rhashtable_lookup_get_insert_fast(&ppe->l2_flows, &entry->l2_node, 64333fc42deSFelix Fietkau mtk_flow_l2_ht_params); 644*e2853114SFelix Fietkau if (likely(!prev)) 645*e2853114SFelix Fietkau return 0; 646*e2853114SFelix Fietkau 647*e2853114SFelix Fietkau if (IS_ERR(prev)) 648*e2853114SFelix Fietkau return PTR_ERR(prev); 649*e2853114SFelix Fietkau 650*e2853114SFelix Fietkau return rhashtable_replace_fast(&ppe->l2_flows, &prev->l2_node, 651*e2853114SFelix Fietkau &entry->l2_node, mtk_flow_l2_ht_params); 65233fc42deSFelix Fietkau } 65333fc42deSFelix Fietkau 654c4f033d9SFelix Fietkau int mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) 655c4f033d9SFelix Fietkau { 656ba2fc48cSLorenzo Bianconi const struct mtk_soc_data *soc = ppe->eth->soc; 65703a3180eSLorenzo Bianconi int type = mtk_get_ib1_pkt_type(ppe->eth, entry->data.ib1); 65833fc42deSFelix Fietkau u32 hash; 659c4f033d9SFelix Fietkau 66033fc42deSFelix Fietkau if (type == MTK_PPE_PKT_TYPE_BRIDGE) 66133fc42deSFelix Fietkau return mtk_foe_entry_commit_l2(ppe, entry); 66233fc42deSFelix Fietkau 663ba2fc48cSLorenzo Bianconi hash = mtk_ppe_hash_entry(ppe->eth, &entry->data); 664c4f033d9SFelix Fietkau entry->hash = 0xffff; 665c4f033d9SFelix Fietkau spin_lock_bh(&ppe_lock); 666ba2fc48cSLorenzo Bianconi hlist_add_head(&entry->list, &ppe->foe_flow[hash / soc->hash_offset]); 667c4f033d9SFelix Fietkau spin_unlock_bh(&ppe_lock); 668c4f033d9SFelix Fietkau 669c4f033d9SFelix Fietkau return 0; 670c4f033d9SFelix Fietkau } 671c4f033d9SFelix Fietkau 67233fc42deSFelix Fietkau static void 67333fc42deSFelix Fietkau mtk_foe_entry_commit_subflow(struct mtk_ppe *ppe, struct mtk_flow_entry *entry, 67433fc42deSFelix Fietkau u16 hash) 67533fc42deSFelix Fietkau { 676ba2fc48cSLorenzo Bianconi const struct mtk_soc_data *soc = ppe->eth->soc; 67733fc42deSFelix Fietkau struct mtk_flow_entry *flow_info; 6789d8cb4c0SLorenzo Bianconi struct mtk_foe_entry foe = {}, *hwe; 67933fc42deSFelix Fietkau struct mtk_foe_mac_info *l2; 68003a3180eSLorenzo Bianconi u32 ib1_mask = mtk_get_ib1_pkt_type_mask(ppe->eth) | MTK_FOE_IB1_UDP; 68133fc42deSFelix Fietkau int type; 68233fc42deSFelix Fietkau 683f3eceaedSKees Cook flow_info = kzalloc(sizeof(*flow_info), GFP_ATOMIC); 68433fc42deSFelix Fietkau if (!flow_info) 68533fc42deSFelix Fietkau return; 68633fc42deSFelix Fietkau 68733fc42deSFelix Fietkau flow_info->l2_data.base_flow = entry; 68833fc42deSFelix Fietkau flow_info->type = MTK_FLOW_TYPE_L2_SUBFLOW; 68933fc42deSFelix Fietkau flow_info->hash = hash; 690ba2fc48cSLorenzo Bianconi hlist_add_head(&flow_info->list, 691ba2fc48cSLorenzo Bianconi &ppe->foe_flow[hash / soc->hash_offset]); 69233fc42deSFelix Fietkau hlist_add_head(&flow_info->l2_data.list, &entry->l2_flows); 69333fc42deSFelix Fietkau 6949d8cb4c0SLorenzo Bianconi hwe = mtk_foe_get_entry(ppe, hash); 6959d8cb4c0SLorenzo Bianconi memcpy(&foe, hwe, soc->foe_entry_size); 69633fc42deSFelix Fietkau foe.ib1 &= ib1_mask; 69733fc42deSFelix Fietkau foe.ib1 |= entry->data.ib1 & ~ib1_mask; 69833fc42deSFelix Fietkau 69903a3180eSLorenzo Bianconi l2 = mtk_foe_entry_l2(ppe->eth, &foe); 70033fc42deSFelix Fietkau memcpy(l2, &entry->data.bridge.l2, sizeof(*l2)); 70133fc42deSFelix Fietkau 70203a3180eSLorenzo Bianconi type = mtk_get_ib1_pkt_type(ppe->eth, foe.ib1); 70333fc42deSFelix Fietkau if (type == MTK_PPE_PKT_TYPE_IPV4_HNAPT) 70433fc42deSFelix Fietkau memcpy(&foe.ipv4.new, &foe.ipv4.orig, sizeof(foe.ipv4.new)); 70533fc42deSFelix Fietkau else if (type >= MTK_PPE_PKT_TYPE_IPV6_ROUTE_3T && l2->etype == ETH_P_IP) 70633fc42deSFelix Fietkau l2->etype = ETH_P_IPV6; 70733fc42deSFelix Fietkau 70803a3180eSLorenzo Bianconi *mtk_foe_entry_ib2(ppe->eth, &foe) = entry->data.bridge.ib2; 70933fc42deSFelix Fietkau 71033fc42deSFelix Fietkau __mtk_foe_entry_commit(ppe, &foe, hash); 71133fc42deSFelix Fietkau } 71233fc42deSFelix Fietkau 713c4f033d9SFelix Fietkau void __mtk_ppe_check_skb(struct mtk_ppe *ppe, struct sk_buff *skb, u16 hash) 714c4f033d9SFelix Fietkau { 715ba2fc48cSLorenzo Bianconi const struct mtk_soc_data *soc = ppe->eth->soc; 716ba2fc48cSLorenzo Bianconi struct hlist_head *head = &ppe->foe_flow[hash / soc->hash_offset]; 7179d8cb4c0SLorenzo Bianconi struct mtk_foe_entry *hwe = mtk_foe_get_entry(ppe, hash); 71833fc42deSFelix Fietkau struct mtk_flow_entry *entry; 71933fc42deSFelix Fietkau struct mtk_foe_bridge key = {}; 72017a5f6a7SDan Carpenter struct hlist_node *n; 72133fc42deSFelix Fietkau struct ethhdr *eh; 722c4f033d9SFelix Fietkau bool found = false; 72333fc42deSFelix Fietkau u8 *tag; 724c4f033d9SFelix Fietkau 725c4f033d9SFelix Fietkau spin_lock_bh(&ppe_lock); 72633fc42deSFelix Fietkau 72733fc42deSFelix Fietkau if (FIELD_GET(MTK_FOE_IB1_STATE, hwe->ib1) == MTK_FOE_STATE_BIND) 72833fc42deSFelix Fietkau goto out; 72933fc42deSFelix Fietkau 73017a5f6a7SDan Carpenter hlist_for_each_entry_safe(entry, n, head, list) { 73133fc42deSFelix Fietkau if (entry->type == MTK_FLOW_TYPE_L2_SUBFLOW) { 73233fc42deSFelix Fietkau if (unlikely(FIELD_GET(MTK_FOE_IB1_STATE, hwe->ib1) == 73333fc42deSFelix Fietkau MTK_FOE_STATE_BIND)) 73433fc42deSFelix Fietkau continue; 73533fc42deSFelix Fietkau 73633fc42deSFelix Fietkau entry->hash = 0xffff; 73733fc42deSFelix Fietkau __mtk_foe_entry_clear(ppe, entry); 73833fc42deSFelix Fietkau continue; 73933fc42deSFelix Fietkau } 74033fc42deSFelix Fietkau 74103a3180eSLorenzo Bianconi if (found || !mtk_flow_entry_match(ppe->eth, entry, hwe)) { 742c4f033d9SFelix Fietkau if (entry->hash != 0xffff) 743c4f033d9SFelix Fietkau entry->hash = 0xffff; 744c4f033d9SFelix Fietkau continue; 745c4f033d9SFelix Fietkau } 746c4f033d9SFelix Fietkau 747c4f033d9SFelix Fietkau entry->hash = hash; 748c4f033d9SFelix Fietkau __mtk_foe_entry_commit(ppe, &entry->data, hash); 749c4f033d9SFelix Fietkau found = true; 750c4f033d9SFelix Fietkau } 75133fc42deSFelix Fietkau 75233fc42deSFelix Fietkau if (found) 75333fc42deSFelix Fietkau goto out; 75433fc42deSFelix Fietkau 75533fc42deSFelix Fietkau eh = eth_hdr(skb); 75633fc42deSFelix Fietkau ether_addr_copy(key.dest_mac, eh->h_dest); 75733fc42deSFelix Fietkau ether_addr_copy(key.src_mac, eh->h_source); 75833fc42deSFelix Fietkau tag = skb->data - 2; 75933fc42deSFelix Fietkau key.vlan = 0; 76033fc42deSFelix Fietkau switch (skb->protocol) { 76133fc42deSFelix Fietkau #if IS_ENABLED(CONFIG_NET_DSA) 76233fc42deSFelix Fietkau case htons(ETH_P_XDSA): 76333fc42deSFelix Fietkau if (!netdev_uses_dsa(skb->dev) || 76433fc42deSFelix Fietkau skb->dev->dsa_ptr->tag_ops->proto != DSA_TAG_PROTO_MTK) 76533fc42deSFelix Fietkau goto out; 76633fc42deSFelix Fietkau 7675f36ca1bSFelix Fietkau if (!skb_metadata_dst(skb)) 76833fc42deSFelix Fietkau tag += 4; 7695f36ca1bSFelix Fietkau 77033fc42deSFelix Fietkau if (get_unaligned_be16(tag) != ETH_P_8021Q) 77133fc42deSFelix Fietkau break; 77233fc42deSFelix Fietkau 77333fc42deSFelix Fietkau fallthrough; 77433fc42deSFelix Fietkau #endif 77533fc42deSFelix Fietkau case htons(ETH_P_8021Q): 77633fc42deSFelix Fietkau key.vlan = get_unaligned_be16(tag + 2) & VLAN_VID_MASK; 77733fc42deSFelix Fietkau break; 77833fc42deSFelix Fietkau default: 77933fc42deSFelix Fietkau break; 78033fc42deSFelix Fietkau } 78133fc42deSFelix Fietkau 78233fc42deSFelix Fietkau entry = rhashtable_lookup_fast(&ppe->l2_flows, &key, mtk_flow_l2_ht_params); 78333fc42deSFelix Fietkau if (!entry) 78433fc42deSFelix Fietkau goto out; 78533fc42deSFelix Fietkau 78633fc42deSFelix Fietkau mtk_foe_entry_commit_subflow(ppe, entry, hash); 78733fc42deSFelix Fietkau 78833fc42deSFelix Fietkau out: 789c4f033d9SFelix Fietkau spin_unlock_bh(&ppe_lock); 790c4f033d9SFelix Fietkau } 791c4f033d9SFelix Fietkau 792c4f033d9SFelix Fietkau int mtk_foe_entry_idle_time(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) 793c4f033d9SFelix Fietkau { 794c4f033d9SFelix Fietkau mtk_flow_entry_update(ppe, entry); 795c4f033d9SFelix Fietkau 79633fc42deSFelix Fietkau return __mtk_foe_entry_idle_time(ppe, entry->data.ib1); 797c4f033d9SFelix Fietkau } 798c4f033d9SFelix Fietkau 79906127504SLorenzo Bianconi int mtk_ppe_prepare_reset(struct mtk_ppe *ppe) 80006127504SLorenzo Bianconi { 80106127504SLorenzo Bianconi if (!ppe) 80206127504SLorenzo Bianconi return -EINVAL; 80306127504SLorenzo Bianconi 80406127504SLorenzo Bianconi /* disable KA */ 80506127504SLorenzo Bianconi ppe_clear(ppe, MTK_PPE_TB_CFG, MTK_PPE_TB_CFG_KEEPALIVE); 80606127504SLorenzo Bianconi ppe_clear(ppe, MTK_PPE_BIND_LMT1, MTK_PPE_NTU_KEEPALIVE); 80706127504SLorenzo Bianconi ppe_w32(ppe, MTK_PPE_KEEPALIVE, 0); 80806127504SLorenzo Bianconi usleep_range(10000, 11000); 80906127504SLorenzo Bianconi 81006127504SLorenzo Bianconi /* set KA timer to maximum */ 81106127504SLorenzo Bianconi ppe_set(ppe, MTK_PPE_BIND_LMT1, MTK_PPE_NTU_KEEPALIVE); 81206127504SLorenzo Bianconi ppe_w32(ppe, MTK_PPE_KEEPALIVE, 0xffffffff); 81306127504SLorenzo Bianconi 81406127504SLorenzo Bianconi /* set KA tick select */ 81506127504SLorenzo Bianconi ppe_set(ppe, MTK_PPE_TB_CFG, MTK_PPE_TB_TICK_SEL); 81606127504SLorenzo Bianconi ppe_set(ppe, MTK_PPE_TB_CFG, MTK_PPE_TB_CFG_KEEPALIVE); 81706127504SLorenzo Bianconi usleep_range(10000, 11000); 81806127504SLorenzo Bianconi 81906127504SLorenzo Bianconi /* disable scan mode */ 82006127504SLorenzo Bianconi ppe_clear(ppe, MTK_PPE_TB_CFG, MTK_PPE_TB_CFG_SCAN_MODE); 82106127504SLorenzo Bianconi usleep_range(10000, 11000); 82206127504SLorenzo Bianconi 82306127504SLorenzo Bianconi return mtk_ppe_wait_busy(ppe); 82406127504SLorenzo Bianconi } 82506127504SLorenzo Bianconi 8263fbe4d8cSDaniel Golle struct mtk_foe_accounting *mtk_foe_entry_get_mib(struct mtk_ppe *ppe, u32 index, 8273fbe4d8cSDaniel Golle struct mtk_foe_accounting *diff) 828ba37b7caSFelix Fietkau { 8293fbe4d8cSDaniel Golle struct mtk_foe_accounting *acct; 8303fbe4d8cSDaniel Golle int size = sizeof(struct mtk_foe_accounting); 8313fbe4d8cSDaniel Golle u64 bytes, packets; 8323fbe4d8cSDaniel Golle 8333fbe4d8cSDaniel Golle if (!ppe->accounting) 8343fbe4d8cSDaniel Golle return NULL; 8353fbe4d8cSDaniel Golle 8363fbe4d8cSDaniel Golle if (mtk_mib_entry_read(ppe, index, &bytes, &packets)) 8373fbe4d8cSDaniel Golle return NULL; 8383fbe4d8cSDaniel Golle 8393fbe4d8cSDaniel Golle acct = ppe->acct_table + index * size; 8403fbe4d8cSDaniel Golle 8413fbe4d8cSDaniel Golle acct->bytes += bytes; 8423fbe4d8cSDaniel Golle acct->packets += packets; 8433fbe4d8cSDaniel Golle 8443fbe4d8cSDaniel Golle if (diff) { 8453fbe4d8cSDaniel Golle diff->bytes = bytes; 8463fbe4d8cSDaniel Golle diff->packets = packets; 8473fbe4d8cSDaniel Golle } 8483fbe4d8cSDaniel Golle 8493fbe4d8cSDaniel Golle return acct; 8503fbe4d8cSDaniel Golle } 8513fbe4d8cSDaniel Golle 8523fbe4d8cSDaniel Golle struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base, int index) 8533fbe4d8cSDaniel Golle { 8543fbe4d8cSDaniel Golle bool accounting = eth->soc->has_accounting; 855ba2fc48cSLorenzo Bianconi const struct mtk_soc_data *soc = eth->soc; 8563fbe4d8cSDaniel Golle struct mtk_foe_accounting *acct; 857c4f033d9SFelix Fietkau struct device *dev = eth->dev; 8583fbe4d8cSDaniel Golle struct mtk_mib_entry *mib; 8591ccc723bSFelix Fietkau struct mtk_ppe *ppe; 860ba2fc48cSLorenzo Bianconi u32 foe_flow_size; 8619d8cb4c0SLorenzo Bianconi void *foe; 8621ccc723bSFelix Fietkau 8631ccc723bSFelix Fietkau ppe = devm_kzalloc(dev, sizeof(*ppe), GFP_KERNEL); 8641ccc723bSFelix Fietkau if (!ppe) 8651ccc723bSFelix Fietkau return NULL; 866ba37b7caSFelix Fietkau 86733fc42deSFelix Fietkau rhashtable_init(&ppe->l2_flows, &mtk_flow_l2_ht_params); 86833fc42deSFelix Fietkau 869ba37b7caSFelix Fietkau /* need to allocate a separate device, since it PPE DMA access is 870ba37b7caSFelix Fietkau * not coherent. 871ba37b7caSFelix Fietkau */ 872ba37b7caSFelix Fietkau ppe->base = base; 873c4f033d9SFelix Fietkau ppe->eth = eth; 874ba37b7caSFelix Fietkau ppe->dev = dev; 8753fbe4d8cSDaniel Golle ppe->version = eth->soc->offload_version; 8763fbe4d8cSDaniel Golle ppe->accounting = accounting; 877ba37b7caSFelix Fietkau 8789d8cb4c0SLorenzo Bianconi foe = dmam_alloc_coherent(ppe->dev, 8799d8cb4c0SLorenzo Bianconi MTK_PPE_ENTRIES * soc->foe_entry_size, 880ba37b7caSFelix Fietkau &ppe->foe_phys, GFP_KERNEL); 881ba37b7caSFelix Fietkau if (!foe) 882603ea5e7SYan Cangang goto err_free_l2_flows; 883ba37b7caSFelix Fietkau 884ba37b7caSFelix Fietkau ppe->foe_table = foe; 885ba37b7caSFelix Fietkau 886ba2fc48cSLorenzo Bianconi foe_flow_size = (MTK_PPE_ENTRIES / soc->hash_offset) * 887ba2fc48cSLorenzo Bianconi sizeof(*ppe->foe_flow); 888ba2fc48cSLorenzo Bianconi ppe->foe_flow = devm_kzalloc(dev, foe_flow_size, GFP_KERNEL); 889ba2fc48cSLorenzo Bianconi if (!ppe->foe_flow) 890603ea5e7SYan Cangang goto err_free_l2_flows; 891ba2fc48cSLorenzo Bianconi 8923fbe4d8cSDaniel Golle if (accounting) { 8933fbe4d8cSDaniel Golle mib = dmam_alloc_coherent(ppe->dev, MTK_PPE_ENTRIES * sizeof(*mib), 8943fbe4d8cSDaniel Golle &ppe->mib_phys, GFP_KERNEL); 8953fbe4d8cSDaniel Golle if (!mib) 8963fbe4d8cSDaniel Golle return NULL; 8973fbe4d8cSDaniel Golle 8983fbe4d8cSDaniel Golle ppe->mib_table = mib; 8993fbe4d8cSDaniel Golle 9003fbe4d8cSDaniel Golle acct = devm_kzalloc(dev, MTK_PPE_ENTRIES * sizeof(*acct), 9013fbe4d8cSDaniel Golle GFP_KERNEL); 9023fbe4d8cSDaniel Golle 9033fbe4d8cSDaniel Golle if (!acct) 9043fbe4d8cSDaniel Golle return NULL; 9053fbe4d8cSDaniel Golle 9063fbe4d8cSDaniel Golle ppe->acct_table = acct; 9073fbe4d8cSDaniel Golle } 9083fbe4d8cSDaniel Golle 9094ff1a3fcSLorenzo Bianconi mtk_ppe_debugfs_init(ppe, index); 910ba37b7caSFelix Fietkau 9111ccc723bSFelix Fietkau return ppe; 912603ea5e7SYan Cangang 913603ea5e7SYan Cangang err_free_l2_flows: 914603ea5e7SYan Cangang rhashtable_destroy(&ppe->l2_flows); 915603ea5e7SYan Cangang return NULL; 916603ea5e7SYan Cangang } 917603ea5e7SYan Cangang 918603ea5e7SYan Cangang void mtk_ppe_deinit(struct mtk_eth *eth) 919603ea5e7SYan Cangang { 920603ea5e7SYan Cangang int i; 921603ea5e7SYan Cangang 922603ea5e7SYan Cangang for (i = 0; i < ARRAY_SIZE(eth->ppe); i++) { 923603ea5e7SYan Cangang if (!eth->ppe[i]) 924603ea5e7SYan Cangang return; 925603ea5e7SYan Cangang rhashtable_destroy(ð->ppe[i]->l2_flows); 926603ea5e7SYan Cangang } 927ba37b7caSFelix Fietkau } 928ba37b7caSFelix Fietkau 929ba37b7caSFelix Fietkau static void mtk_ppe_init_foe_table(struct mtk_ppe *ppe) 930ba37b7caSFelix Fietkau { 931ba37b7caSFelix Fietkau static const u8 skip[] = { 12, 25, 38, 51, 76, 89, 102 }; 932ba37b7caSFelix Fietkau int i, k; 933ba37b7caSFelix Fietkau 9349d8cb4c0SLorenzo Bianconi memset(ppe->foe_table, 0, 9359d8cb4c0SLorenzo Bianconi MTK_PPE_ENTRIES * ppe->eth->soc->foe_entry_size); 936ba37b7caSFelix Fietkau 937ba37b7caSFelix Fietkau if (!IS_ENABLED(CONFIG_SOC_MT7621)) 938ba37b7caSFelix Fietkau return; 939ba37b7caSFelix Fietkau 940ba37b7caSFelix Fietkau /* skip all entries that cross the 1024 byte boundary */ 9419d8cb4c0SLorenzo Bianconi for (i = 0; i < MTK_PPE_ENTRIES; i += 128) { 9429d8cb4c0SLorenzo Bianconi for (k = 0; k < ARRAY_SIZE(skip); k++) { 9439d8cb4c0SLorenzo Bianconi struct mtk_foe_entry *hwe; 9449d8cb4c0SLorenzo Bianconi 9459d8cb4c0SLorenzo Bianconi hwe = mtk_foe_get_entry(ppe, i + skip[k]); 9469d8cb4c0SLorenzo Bianconi hwe->ib1 |= MTK_FOE_IB1_STATIC; 9479d8cb4c0SLorenzo Bianconi } 9489d8cb4c0SLorenzo Bianconi } 949ba37b7caSFelix Fietkau } 950ba37b7caSFelix Fietkau 9514ff1a3fcSLorenzo Bianconi void mtk_ppe_start(struct mtk_ppe *ppe) 952ba37b7caSFelix Fietkau { 953ba37b7caSFelix Fietkau u32 val; 954ba37b7caSFelix Fietkau 9554ff1a3fcSLorenzo Bianconi if (!ppe) 9564ff1a3fcSLorenzo Bianconi return; 9574ff1a3fcSLorenzo Bianconi 958ba37b7caSFelix Fietkau mtk_ppe_init_foe_table(ppe); 959ba37b7caSFelix Fietkau ppe_w32(ppe, MTK_PPE_TB_BASE, ppe->foe_phys); 960ba37b7caSFelix Fietkau 961ba37b7caSFelix Fietkau val = MTK_PPE_TB_CFG_ENTRY_80B | 962ba37b7caSFelix Fietkau MTK_PPE_TB_CFG_AGE_NON_L4 | 963ba37b7caSFelix Fietkau MTK_PPE_TB_CFG_AGE_UNBIND | 964ba37b7caSFelix Fietkau MTK_PPE_TB_CFG_AGE_TCP | 965ba37b7caSFelix Fietkau MTK_PPE_TB_CFG_AGE_UDP | 966ba37b7caSFelix Fietkau MTK_PPE_TB_CFG_AGE_TCP_FIN | 967ba37b7caSFelix Fietkau FIELD_PREP(MTK_PPE_TB_CFG_SEARCH_MISS, 968ba37b7caSFelix Fietkau MTK_PPE_SEARCH_MISS_ACTION_FORWARD_BUILD) | 969ba37b7caSFelix Fietkau FIELD_PREP(MTK_PPE_TB_CFG_KEEPALIVE, 970ba37b7caSFelix Fietkau MTK_PPE_KEEPALIVE_DISABLE) | 971ba37b7caSFelix Fietkau FIELD_PREP(MTK_PPE_TB_CFG_HASH_MODE, 1) | 972ba37b7caSFelix Fietkau FIELD_PREP(MTK_PPE_TB_CFG_SCAN_MODE, 973ba37b7caSFelix Fietkau MTK_PPE_SCAN_MODE_KEEPALIVE_AGE) | 974ba37b7caSFelix Fietkau FIELD_PREP(MTK_PPE_TB_CFG_ENTRY_NUM, 975ba37b7caSFelix Fietkau MTK_PPE_ENTRIES_SHIFT); 97603a3180eSLorenzo Bianconi if (MTK_HAS_CAPS(ppe->eth->soc->caps, MTK_NETSYS_V2)) 97703a3180eSLorenzo Bianconi val |= MTK_PPE_TB_CFG_INFO_SEL; 978ba37b7caSFelix Fietkau ppe_w32(ppe, MTK_PPE_TB_CFG, val); 979ba37b7caSFelix Fietkau 980ba37b7caSFelix Fietkau ppe_w32(ppe, MTK_PPE_IP_PROTO_CHK, 981ba37b7caSFelix Fietkau MTK_PPE_IP_PROTO_CHK_IPV4 | MTK_PPE_IP_PROTO_CHK_IPV6); 982ba37b7caSFelix Fietkau 983ba37b7caSFelix Fietkau mtk_ppe_cache_enable(ppe, true); 984ba37b7caSFelix Fietkau 98503a3180eSLorenzo Bianconi val = MTK_PPE_FLOW_CFG_IP6_3T_ROUTE | 986ba37b7caSFelix Fietkau MTK_PPE_FLOW_CFG_IP6_5T_ROUTE | 987ba37b7caSFelix Fietkau MTK_PPE_FLOW_CFG_IP6_6RD | 988ba37b7caSFelix Fietkau MTK_PPE_FLOW_CFG_IP4_NAT | 989ba37b7caSFelix Fietkau MTK_PPE_FLOW_CFG_IP4_NAPT | 990ba37b7caSFelix Fietkau MTK_PPE_FLOW_CFG_IP4_DSLITE | 991ba37b7caSFelix Fietkau MTK_PPE_FLOW_CFG_IP4_NAT_FRAG; 99203a3180eSLorenzo Bianconi if (MTK_HAS_CAPS(ppe->eth->soc->caps, MTK_NETSYS_V2)) 99303a3180eSLorenzo Bianconi val |= MTK_PPE_MD_TOAP_BYP_CRSN0 | 99403a3180eSLorenzo Bianconi MTK_PPE_MD_TOAP_BYP_CRSN1 | 99503a3180eSLorenzo Bianconi MTK_PPE_MD_TOAP_BYP_CRSN2 | 99603a3180eSLorenzo Bianconi MTK_PPE_FLOW_CFG_IP4_HASH_GRE_KEY; 99703a3180eSLorenzo Bianconi else 99803a3180eSLorenzo Bianconi val |= MTK_PPE_FLOW_CFG_IP4_TCP_FRAG | 99903a3180eSLorenzo Bianconi MTK_PPE_FLOW_CFG_IP4_UDP_FRAG; 1000ba37b7caSFelix Fietkau ppe_w32(ppe, MTK_PPE_FLOW_CFG, val); 1001ba37b7caSFelix Fietkau 1002ba37b7caSFelix Fietkau val = FIELD_PREP(MTK_PPE_UNBIND_AGE_MIN_PACKETS, 1000) | 1003ba37b7caSFelix Fietkau FIELD_PREP(MTK_PPE_UNBIND_AGE_DELTA, 3); 1004ba37b7caSFelix Fietkau ppe_w32(ppe, MTK_PPE_UNBIND_AGE, val); 1005ba37b7caSFelix Fietkau 1006ba37b7caSFelix Fietkau val = FIELD_PREP(MTK_PPE_BIND_AGE0_DELTA_UDP, 12) | 1007ba37b7caSFelix Fietkau FIELD_PREP(MTK_PPE_BIND_AGE0_DELTA_NON_L4, 1); 1008ba37b7caSFelix Fietkau ppe_w32(ppe, MTK_PPE_BIND_AGE0, val); 1009ba37b7caSFelix Fietkau 1010ba37b7caSFelix Fietkau val = FIELD_PREP(MTK_PPE_BIND_AGE1_DELTA_TCP_FIN, 1) | 1011ba37b7caSFelix Fietkau FIELD_PREP(MTK_PPE_BIND_AGE1_DELTA_TCP, 7); 1012ba37b7caSFelix Fietkau ppe_w32(ppe, MTK_PPE_BIND_AGE1, val); 1013ba37b7caSFelix Fietkau 1014ba37b7caSFelix Fietkau val = MTK_PPE_BIND_LIMIT0_QUARTER | MTK_PPE_BIND_LIMIT0_HALF; 1015ba37b7caSFelix Fietkau ppe_w32(ppe, MTK_PPE_BIND_LIMIT0, val); 1016ba37b7caSFelix Fietkau 1017ba37b7caSFelix Fietkau val = MTK_PPE_BIND_LIMIT1_FULL | 1018ba37b7caSFelix Fietkau FIELD_PREP(MTK_PPE_BIND_LIMIT1_NON_L4, 1); 1019ba37b7caSFelix Fietkau ppe_w32(ppe, MTK_PPE_BIND_LIMIT1, val); 1020ba37b7caSFelix Fietkau 1021ba37b7caSFelix Fietkau val = FIELD_PREP(MTK_PPE_BIND_RATE_BIND, 30) | 1022ba37b7caSFelix Fietkau FIELD_PREP(MTK_PPE_BIND_RATE_PREBIND, 1); 1023ba37b7caSFelix Fietkau ppe_w32(ppe, MTK_PPE_BIND_RATE, val); 1024ba37b7caSFelix Fietkau 1025ba37b7caSFelix Fietkau /* enable PPE */ 1026ba37b7caSFelix Fietkau val = MTK_PPE_GLO_CFG_EN | 1027ba37b7caSFelix Fietkau MTK_PPE_GLO_CFG_IP4_L4_CS_DROP | 1028ba37b7caSFelix Fietkau MTK_PPE_GLO_CFG_IP4_CS_DROP | 1029ba37b7caSFelix Fietkau MTK_PPE_GLO_CFG_FLOW_DROP_UPDATE; 1030ba37b7caSFelix Fietkau ppe_w32(ppe, MTK_PPE_GLO_CFG, val); 1031ba37b7caSFelix Fietkau 1032ba37b7caSFelix Fietkau ppe_w32(ppe, MTK_PPE_DEFAULT_CPU_PORT, 0); 103303a3180eSLorenzo Bianconi 103403a3180eSLorenzo Bianconi if (MTK_HAS_CAPS(ppe->eth->soc->caps, MTK_NETSYS_V2)) { 103503a3180eSLorenzo Bianconi ppe_w32(ppe, MTK_PPE_DEFAULT_CPU_PORT1, 0xcb777); 103603a3180eSLorenzo Bianconi ppe_w32(ppe, MTK_PPE_SBW_CTRL, 0x7f); 103703a3180eSLorenzo Bianconi } 10383fbe4d8cSDaniel Golle 10393fbe4d8cSDaniel Golle if (ppe->accounting && ppe->mib_phys) { 10403fbe4d8cSDaniel Golle ppe_w32(ppe, MTK_PPE_MIB_TB_BASE, ppe->mib_phys); 10413fbe4d8cSDaniel Golle ppe_m32(ppe, MTK_PPE_MIB_CFG, MTK_PPE_MIB_CFG_EN, 10423fbe4d8cSDaniel Golle MTK_PPE_MIB_CFG_EN); 10433fbe4d8cSDaniel Golle ppe_m32(ppe, MTK_PPE_MIB_CFG, MTK_PPE_MIB_CFG_RD_CLR, 10443fbe4d8cSDaniel Golle MTK_PPE_MIB_CFG_RD_CLR); 10453fbe4d8cSDaniel Golle ppe_m32(ppe, MTK_PPE_MIB_CACHE_CTL, MTK_PPE_MIB_CACHE_CTL_EN, 10463fbe4d8cSDaniel Golle MTK_PPE_MIB_CFG_RD_CLR); 10473fbe4d8cSDaniel Golle } 1048ba37b7caSFelix Fietkau } 1049ba37b7caSFelix Fietkau 1050ba37b7caSFelix Fietkau int mtk_ppe_stop(struct mtk_ppe *ppe) 1051ba37b7caSFelix Fietkau { 1052ba37b7caSFelix Fietkau u32 val; 1053ba37b7caSFelix Fietkau int i; 1054ba37b7caSFelix Fietkau 10554ff1a3fcSLorenzo Bianconi if (!ppe) 10564ff1a3fcSLorenzo Bianconi return 0; 10574ff1a3fcSLorenzo Bianconi 10589d8cb4c0SLorenzo Bianconi for (i = 0; i < MTK_PPE_ENTRIES; i++) { 10599d8cb4c0SLorenzo Bianconi struct mtk_foe_entry *hwe = mtk_foe_get_entry(ppe, i); 10609d8cb4c0SLorenzo Bianconi 10619d8cb4c0SLorenzo Bianconi hwe->ib1 = FIELD_PREP(MTK_FOE_IB1_STATE, 1062ba37b7caSFelix Fietkau MTK_FOE_STATE_INVALID); 10639d8cb4c0SLorenzo Bianconi } 1064ba37b7caSFelix Fietkau 1065ba37b7caSFelix Fietkau mtk_ppe_cache_enable(ppe, false); 1066ba37b7caSFelix Fietkau 1067ba37b7caSFelix Fietkau /* disable offload engine */ 1068ba37b7caSFelix Fietkau ppe_clear(ppe, MTK_PPE_GLO_CFG, MTK_PPE_GLO_CFG_EN); 1069ba37b7caSFelix Fietkau ppe_w32(ppe, MTK_PPE_FLOW_CFG, 0); 1070ba37b7caSFelix Fietkau 1071ba37b7caSFelix Fietkau /* disable aging */ 1072ba37b7caSFelix Fietkau val = MTK_PPE_TB_CFG_AGE_NON_L4 | 1073ba37b7caSFelix Fietkau MTK_PPE_TB_CFG_AGE_UNBIND | 1074ba37b7caSFelix Fietkau MTK_PPE_TB_CFG_AGE_TCP | 1075ba37b7caSFelix Fietkau MTK_PPE_TB_CFG_AGE_UDP | 1076ba37b7caSFelix Fietkau MTK_PPE_TB_CFG_AGE_TCP_FIN; 1077ba37b7caSFelix Fietkau ppe_clear(ppe, MTK_PPE_TB_CFG, val); 1078ba37b7caSFelix Fietkau 1079ba37b7caSFelix Fietkau return mtk_ppe_wait_busy(ppe); 1080ba37b7caSFelix Fietkau } 1081